blob: bcd12f106c90f85386c0e2d46b6b423d23ff5c68 [file] [log] [blame]
Eric Andersendf82f612001-06-28 07:46:40 +00001/* vi: set sw=4 ts=4: */
2/*
3 * ash shell port for busybox
4 *
5 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +00006 * The Regents of the University of California. All rights reserved.
Eric Andersencb57d552001-06-28 07:25:16 +00007 *
8 * This code is derived from software contributed to Berkeley by
9 * Kenneth Almquist.
10 *
Eric Andersendf82f612001-06-28 07:46:40 +000011 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
Eric Andersencb57d552001-06-28 07:25:16 +000015 *
Eric Andersendf82f612001-06-28 07:46:40 +000016 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
Eric Andersen2870d962001-07-02 17:27:21 +000025 * This version of ash is adapted from the source in Debian's ash 0.3.8-5
26 * package.
Eric Andersendf82f612001-06-28 07:46:40 +000027 *
Eric Andersen2870d962001-07-02 17:27:21 +000028 * Modified by Erik Andersen <andersee@debian.org> and
Eric Andersen7467c8d2001-07-12 20:26:32 +000029 * Vladimir Oleynik <dzo@simtreas.ru> to be used in busybox
Eric Andersen2870d962001-07-02 17:27:21 +000030 *
Eric Andersendf82f612001-06-28 07:46:40 +000031 *
32 * Original copyright notice is retained at the end of this file.
Eric Andersencb57d552001-06-28 07:25:16 +000033 */
34
Eric Andersen2870d962001-07-02 17:27:21 +000035
36/* These defines allow you to adjust the feature set to be compiled
37 * into the ash shell. As a rule, enabling these options will make
38 * ash get bigger... With all of these options off, ash adds about
Eric Andersen62483552001-07-10 06:09:16 +000039 * 60k to busybox on an x86 system.*/
Eric Andersen2870d962001-07-02 17:27:21 +000040
41
42/* Enable job control. This allows you to run jobs in the background,
43 * which is great when ash is being used as an interactive shell, but
Eric Andersen3102ac42001-07-06 04:26:23 +000044 * it completely useless for is all you are doing is running scripts.
Eric Andersen2870d962001-07-02 17:27:21 +000045 * This adds about 2.5k on an x86 system. */
Eric Andersen62483552001-07-10 06:09:16 +000046#undef JOBS
Eric Andersen2870d962001-07-02 17:27:21 +000047
48/* This enables alias support in ash. If you want to support things
49 * like "alias ls='ls -l'" with ash, enable this. This is only useful
50 * when ash is used as an intractive shell. This adds about 1.5k */
51#define ASH_ALIAS
52
53/* If you need ash to act as a full Posix shell, with full math
Eric Andersen74bcd162001-07-30 21:41:37 +000054 * support, enable this. This adds a bit over 2k an x86 system. */
Eric Andersen34506362001-08-02 05:02:46 +000055//#undef ASH_MATH_SUPPORT
Eric Andersen74bcd162001-07-30 21:41:37 +000056#define ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +000057
Eric Andersen2870d962001-07-02 17:27:21 +000058/* Getopts is used by shell procedures to parse positional parameters.
59 * You probably want to leave this disabled, and use the busybox getopt
60 * applet if you want to do this sort of thing. There are some scripts
61 * out there that use it, so it you need it, enable. Most people will
62 * leave this disabled. This adds 1k on an x86 system. */
63#undef ASH_GETOPTS
64
65/* This allows you to override shell builtins and use whatever is on
66 * the filesystem. This is most useful when ash is acting as a
Eric Andersen62483552001-07-10 06:09:16 +000067 * standalone shell. Adds about 272 bytes. */
Eric Andersen2870d962001-07-02 17:27:21 +000068#undef ASH_CMDCMD
69
Eric Andersen2870d962001-07-02 17:27:21 +000070
Eric Andersen3102ac42001-07-06 04:26:23 +000071/* Optimize size vs speed as size */
72#define ASH_OPTIMIZE_FOR_SIZE
73
Eric Andersen2870d962001-07-02 17:27:21 +000074/* Enable this to compile in extra debugging noise. When debugging is
75 * on, debugging info will be written to $HOME/trace and a quit signal
76 * will generate a core dump. */
77#undef DEBUG
78
Eric Andersen2870d962001-07-02 17:27:21 +000079/* These are here to work with glibc -- Don't change these... */
Eric Andersendf82f612001-06-28 07:46:40 +000080#undef FNMATCH_BROKEN
81#undef GLOB_BROKEN
Eric Andersencb57d552001-06-28 07:25:16 +000082
83#include <assert.h>
84#include <ctype.h>
85#include <dirent.h>
86#include <errno.h>
87#include <fcntl.h>
88#include <limits.h>
89#include <paths.h>
90#include <pwd.h>
91#include <setjmp.h>
92#include <signal.h>
93#include <stdarg.h>
Eric Andersencb57d552001-06-28 07:25:16 +000094#include <stdio.h>
95#include <stdlib.h>
96#include <string.h>
97#include <sysexits.h>
98#include <unistd.h>
99#include <sys/stat.h>
100#include <sys/cdefs.h>
101#include <sys/ioctl.h>
102#include <sys/param.h>
103#include <sys/resource.h>
104#include <sys/time.h>
105#include <sys/times.h>
106#include <sys/types.h>
107#include <sys/wait.h>
108
109
110#if !defined(FNMATCH_BROKEN)
111#include <fnmatch.h>
112#endif
113#if !defined(GLOB_BROKEN)
114#include <glob.h>
115#endif
116
Eric Andersen2870d962001-07-02 17:27:21 +0000117#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +0000118#include <termios.h>
Eric Andersencb57d552001-06-28 07:25:16 +0000119#endif
120
Eric Andersencb57d552001-06-28 07:25:16 +0000121#include "busybox.h"
Eric Andersen2870d962001-07-02 17:27:21 +0000122#include "cmdedit.h"
123
Eric Andersen2870d962001-07-02 17:27:21 +0000124/*
125 * This file was generated by the mksyntax program.
126 */
127
128/* Syntax classes */
129#define CWORD 0 /* character is nothing special */
130#define CNL 1 /* newline character */
131#define CBACK 2 /* a backslash character */
132#define CSQUOTE 3 /* single quote */
133#define CDQUOTE 4 /* double quote */
134#define CENDQUOTE 5 /* a terminating quote */
135#define CBQUOTE 6 /* backwards single quote */
136#define CVAR 7 /* a dollar sign */
137#define CENDVAR 8 /* a '}' character */
138#define CLP 9 /* a left paren in arithmetic */
139#define CRP 10 /* a right paren in arithmetic */
140#define CENDFILE 11 /* end of file */
141#define CCTL 12 /* like CWORD, except it must be escaped */
142#define CSPCL 13 /* these terminate a word */
143#define CIGN 14 /* character should be ignored */
144
145/* Syntax classes for is_ functions */
146#define ISDIGIT 01 /* a digit */
147#define ISUPPER 02 /* an upper case letter */
148#define ISLOWER 04 /* a lower case letter */
149#define ISUNDER 010 /* an underscore */
150#define ISSPECL 020 /* the name of a special parameter */
151
152#define SYNBASE 130
153#define PEOF -130
154
155#define PEOA -129
156
157#define TEOF 0
158#define TNL 1
159#define TSEMI 2
160#define TBACKGND 3
161#define TAND 4
162#define TOR 5
163#define TPIPE 6
164#define TLP 7
165#define TRP 8
166#define TENDCASE 9
167#define TENDBQUOTE 10
168#define TREDIR 11
169#define TWORD 12
170#define TASSIGN 13
171#define TNOT 14
172#define TCASE 15
173#define TDO 16
174#define TDONE 17
175#define TELIF 18
176#define TELSE 19
177#define TESAC 20
178#define TFI 21
179#define TFOR 22
180#define TIF 23
181#define TIN 24
182#define TTHEN 25
183#define TUNTIL 26
184#define TWHILE 27
185#define TBEGIN 28
186#define TEND 29
187
188
189#define BASESYNTAX (basesyntax + SYNBASE)
190#define DQSYNTAX (dqsyntax + SYNBASE)
191#define SQSYNTAX (sqsyntax + SYNBASE)
192#define ARISYNTAX (arisyntax + SYNBASE)
193
194/* control characters in argument strings */
195#define CTLESC '\201'
196#define CTLVAR '\202'
197#define CTLENDVAR '\203'
198#define CTLBACKQ '\204'
199#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
200/* CTLBACKQ | CTLQUOTE == '\205' */
201#define CTLARI '\206'
202#define CTLENDARI '\207'
203#define CTLQUOTEMARK '\210'
204
Eric Andersen62483552001-07-10 06:09:16 +0000205#define is_digit(c) ((c)>='0' && (c)<='9')
Eric Andersen2870d962001-07-02 17:27:21 +0000206#define is_alpha(c) (((c) < CTLESC || (c) > CTLENDARI) && isalpha((unsigned char) (c)))
207#define is_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalpha((unsigned char) (c))))
208#define is_in_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalnum((unsigned char) (c))))
209#define is_special(c) ((is_type+SYNBASE)[c] & (ISSPECL|ISDIGIT))
210#define digit_val(c) ((c) - '0')
Eric Andersencb57d552001-06-28 07:25:16 +0000211
212
213#define _DIAGASSERT(x)
214
Eric Andersen3102ac42001-07-06 04:26:23 +0000215
Eric Andersencb57d552001-06-28 07:25:16 +0000216
Eric Andersen2870d962001-07-02 17:27:21 +0000217#define S_DFL 1 /* default signal handling (SIG_DFL) */
218#define S_CATCH 2 /* signal is caught */
219#define S_IGN 3 /* signal is ignored (SIG_IGN) */
220#define S_HARD_IGN 4 /* signal is ignored permenantly */
221#define S_RESET 5 /* temporary - to reset a hard ignored sig */
Eric Andersencb57d552001-06-28 07:25:16 +0000222
223
Eric Andersen2870d962001-07-02 17:27:21 +0000224/* variable substitution byte (follows CTLVAR) */
225#define VSTYPE 0x0f /* type of variable substitution */
226#define VSNUL 0x10 /* colon--treat the empty string as unset */
227#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
Eric Andersencb57d552001-06-28 07:25:16 +0000228
Eric Andersen2870d962001-07-02 17:27:21 +0000229/* values of VSTYPE field */
230#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
231#define VSMINUS 0x2 /* ${var-text} */
232#define VSPLUS 0x3 /* ${var+text} */
233#define VSQUESTION 0x4 /* ${var?message} */
234#define VSASSIGN 0x5 /* ${var=text} */
235#define VSTRIMLEFT 0x6 /* ${var#pattern} */
236#define VSTRIMLEFTMAX 0x7 /* ${var##pattern} */
237#define VSTRIMRIGHT 0x8 /* ${var%pattern} */
238#define VSTRIMRIGHTMAX 0x9 /* ${var%%pattern} */
239#define VSLENGTH 0xa /* ${#var} */
Eric Andersencb57d552001-06-28 07:25:16 +0000240
Eric Andersen2870d962001-07-02 17:27:21 +0000241/* flags passed to redirect */
242#define REDIR_PUSH 01 /* save previous values of file descriptors */
Eric Andersen3102ac42001-07-06 04:26:23 +0000243#define REDIR_BACKQ 02 /* save the command output to pipe */
Eric Andersencb57d552001-06-28 07:25:16 +0000244
Eric Andersen2870d962001-07-02 17:27:21 +0000245/*
246 * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
247 * so we use _setjmp instead.
248 */
249
Eric Andersen62483552001-07-10 06:09:16 +0000250#if defined(BSD)
Eric Andersen2870d962001-07-02 17:27:21 +0000251#define setjmp(jmploc) _setjmp(jmploc)
252#define longjmp(jmploc, val) _longjmp(jmploc, val)
253#endif
254
255/*
256 * Most machines require the value returned from malloc to be aligned
257 * in some way. The following macro will get this right on many machines.
258 */
259
260#ifndef ALIGN
261union align {
262 int i;
263 char *cp;
264};
265
266#define ALIGN(nbytes) (((nbytes) + sizeof(union align) - 1) & ~(sizeof(union align) - 1))
267#endif
268
269#ifdef BB_LOCALE_SUPPORT
270#include <locale.h>
271static void change_lc_all(const char *value);
272static void change_lc_ctype(const char *value);
273#endif
274
275/*
276 * These macros allow the user to suspend the handling of interrupt signals
277 * over a period of time. This is similar to SIGHOLD to or sigblock, but
278 * much more efficient and portable. (But hacking the kernel is so much
279 * more fun than worrying about efficiency and portability. :-))
280 */
281
282static void onint (void);
283static volatile int suppressint;
284static volatile int intpending;
285
286#define INTOFF suppressint++
Eric Andersen3102ac42001-07-06 04:26:23 +0000287#ifndef ASH_OPTIMIZE_FOR_SIZE
Eric Andersen2870d962001-07-02 17:27:21 +0000288#define INTON { if (--suppressint == 0 && intpending) onint(); }
Eric Andersen3102ac42001-07-06 04:26:23 +0000289#define FORCEINTON {suppressint = 0; if (intpending) onint();}
Eric Andersen2870d962001-07-02 17:27:21 +0000290#else
291static void __inton (void);
Eric Andersen3102ac42001-07-06 04:26:23 +0000292static void forceinton (void);
Eric Andersen2870d962001-07-02 17:27:21 +0000293#define INTON __inton()
Eric Andersen3102ac42001-07-06 04:26:23 +0000294#define FORCEINTON forceinton()
Eric Andersen2870d962001-07-02 17:27:21 +0000295#endif
Eric Andersen3102ac42001-07-06 04:26:23 +0000296
Eric Andersen2870d962001-07-02 17:27:21 +0000297#define CLEAR_PENDING_INT intpending = 0
298#define int_pending() intpending
299
300
301typedef void *pointer;
302#ifndef NULL
303#define NULL (void *)0
304#endif
305
306static inline pointer ckmalloc (int sz) { return xmalloc(sz); }
307static inline pointer ckrealloc(void *p, int sz) { return xrealloc(p, sz); }
308static inline char * savestr (const char *s) { return xstrdup(s); }
309
310static pointer stalloc (int);
311static void stunalloc (pointer);
312static void ungrabstackstr (char *, char *);
313static char * growstackstr(void);
Eric Andersen3102ac42001-07-06 04:26:23 +0000314static char * makestrspace(size_t newlen);
Eric Andersen2870d962001-07-02 17:27:21 +0000315static char *sstrdup (const char *);
316
317/*
318 * Parse trees for commands are allocated in lifo order, so we use a stack
319 * to make this more efficient, and also to avoid all sorts of exception
320 * handling code to handle interrupts in the middle of a parse.
321 *
322 * The size 504 was chosen because the Ultrix malloc handles that size
323 * well.
324 */
325
326#define MINSIZE 504 /* minimum size of a block */
327
328
329struct stack_block {
330 struct stack_block *prev;
331 char space[MINSIZE];
332};
333
334static struct stack_block stackbase;
335static struct stack_block *stackp = &stackbase;
336static struct stackmark *markp;
337static char *stacknxt = stackbase.space;
338static int stacknleft = MINSIZE;
339
340
341#define equal(s1, s2) (strcmp(s1, s2) == 0)
342
343#define stackblock() stacknxt
344#define stackblocksize() stacknleft
345#define STARTSTACKSTR(p) p = stackblock(), sstrnleft = stackblocksize()
Eric Andersen3102ac42001-07-06 04:26:23 +0000346
Eric Andersen2870d962001-07-02 17:27:21 +0000347#define STPUTC(c, p) (--sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(), *p++ = (c)))
348#define CHECKSTRSPACE(n, p) { if (sstrnleft < n) p = makestrspace(n); }
Eric Andersen2870d962001-07-02 17:27:21 +0000349#define STACKSTRNUL(p) (sstrnleft == 0? (p = growstackstr(), *p = '\0') : (*p = '\0'))
Eric Andersen3102ac42001-07-06 04:26:23 +0000350
351
352#define USTPUTC(c, p) (--sstrnleft, *p++ = (c))
Eric Andersen2870d962001-07-02 17:27:21 +0000353#define STUNPUTC(p) (++sstrnleft, --p)
354#define STTOPC(p) p[-1]
355#define STADJUST(amount, p) (p += (amount), sstrnleft -= (amount))
356#define grabstackstr(p) stalloc(stackblocksize() - sstrnleft)
357
358#define ckfree(p) free((pointer)(p))
359
Eric Andersen2870d962001-07-02 17:27:21 +0000360
361#ifdef DEBUG
362#define TRACE(param) trace param
363static void trace (const char *, ...);
364static void trargs (char **);
365static void showtree (union node *);
366static void trputc (int);
367static void trputs (const char *);
368static void opentrace (void);
369#else
370#define TRACE(param)
371#endif
372
373#define NSEMI 0
374#define NCMD 1
375#define NPIPE 2
376#define NREDIR 3
377#define NBACKGND 4
378#define NSUBSHELL 5
379#define NAND 6
380#define NOR 7
381#define NIF 8
382#define NWHILE 9
383#define NUNTIL 10
384#define NFOR 11
385#define NCASE 12
386#define NCLIST 13
387#define NDEFUN 14
388#define NARG 15
389#define NTO 16
390#define NFROM 17
391#define NFROMTO 18
392#define NAPPEND 19
393#define NTOOV 20
394#define NTOFD 21
395#define NFROMFD 22
396#define NHERE 23
397#define NXHERE 24
398#define NNOT 25
399
400/*
401 * expandarg() flags
402 */
403#define EXP_FULL 0x1 /* perform word splitting & file globbing */
404#define EXP_TILDE 0x2 /* do normal tilde expansion */
405#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
406#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
407#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
408#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
409
410
411#define NOPTS 16
412
413static char optet_vals[NOPTS];
414
415static const char * const optlist[NOPTS] = {
416 "e" "errexit",
417 "f" "noglob",
418 "I" "ignoreeof",
419 "i" "interactive",
420 "m" "monitor",
421 "n" "noexec",
422 "s" "stdin",
423 "x" "xtrace",
424 "v" "verbose",
425 "V" "vi",
426 "E" "emacs",
427 "C" "noclobber",
428 "a" "allexport",
429 "b" "notify",
430 "u" "nounset",
431 "q" "quietprofile"
432};
433
434#define optent_name(optent) (optent+1)
435#define optent_letter(optent) optent[0]
436#define optent_val(optent) optet_vals[optent]
437
438#define eflag optent_val(0)
439#define fflag optent_val(1)
440#define Iflag optent_val(2)
441#define iflag optent_val(3)
442#define mflag optent_val(4)
443#define nflag optent_val(5)
444#define sflag optent_val(6)
445#define xflag optent_val(7)
446#define vflag optent_val(8)
447#define Vflag optent_val(9)
448#define Eflag optent_val(10)
449#define Cflag optent_val(11)
450#define aflag optent_val(12)
451#define bflag optent_val(13)
452#define uflag optent_val(14)
453#define qflag optent_val(15)
454
455
456/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
457#define FORK_FG 0
458#define FORK_BG 1
459#define FORK_NOJOB 2
460
461
462struct nbinary {
463 int type;
464 union node *ch1;
465 union node *ch2;
466};
467
468
469struct ncmd {
470 int type;
471 int backgnd;
472 union node *assign;
473 union node *args;
474 union node *redirect;
475};
476
477
478struct npipe {
479 int type;
480 int backgnd;
481 struct nodelist *cmdlist;
482};
483
484
485struct nredir {
486 int type;
487 union node *n;
488 union node *redirect;
489};
490
491
492struct nif {
493 int type;
494 union node *test;
495 union node *ifpart;
496 union node *elsepart;
497};
498
499
500struct nfor {
501 int type;
502 union node *args;
503 union node *body;
504 char *var;
505};
506
507
508struct ncase {
509 int type;
510 union node *expr;
511 union node *cases;
512};
513
514
515struct nclist {
516 int type;
517 union node *next;
518 union node *pattern;
519 union node *body;
520};
521
522
523struct narg {
524 int type;
525 union node *next;
526 char *text;
527 struct nodelist *backquote;
528};
529
530
531struct nfile {
532 int type;
533 union node *next;
534 int fd;
535 union node *fname;
536 char *expfname;
537};
538
539
540struct ndup {
541 int type;
542 union node *next;
543 int fd;
544 int dupfd;
545 union node *vname;
546};
547
548
549struct nhere {
550 int type;
551 union node *next;
552 int fd;
553 union node *doc;
554};
555
556
557struct nnot {
558 int type;
559 union node *com;
560};
561
562
563union node {
564 int type;
565 struct nbinary nbinary;
566 struct ncmd ncmd;
567 struct npipe npipe;
568 struct nredir nredir;
569 struct nif nif;
570 struct nfor nfor;
571 struct ncase ncase;
572 struct nclist nclist;
573 struct narg narg;
574 struct nfile nfile;
575 struct ndup ndup;
576 struct nhere nhere;
577 struct nnot nnot;
578};
579
580
581struct nodelist {
582 struct nodelist *next;
583 union node *n;
584};
585
586struct backcmd { /* result of evalbackcmd */
587 int fd; /* file descriptor to read from */
588 char *buf; /* buffer */
589 int nleft; /* number of chars in buffer */
590 struct job *jp; /* job structure for command */
591};
592
593struct cmdentry {
594 int cmdtype;
595 union param {
596 int index;
597 union node *func;
598 const struct builtincmd *cmd;
599 } u;
600};
601
602struct strlist {
603 struct strlist *next;
604 char *text;
605};
606
607
608struct arglist {
609 struct strlist *list;
610 struct strlist **lastp;
611};
612
613struct strpush {
614 struct strpush *prev; /* preceding string on stack */
615 char *prevstring;
616 int prevnleft;
617#ifdef ASH_ALIAS
618 struct alias *ap; /* if push was associated with an alias */
619#endif
620 char *string; /* remember the string since it may change */
621};
622
623struct parsefile {
624 struct parsefile *prev; /* preceding file on stack */
625 int linno; /* current line */
626 int fd; /* file descriptor (or -1 if string) */
627 int nleft; /* number of chars left in this line */
628 int lleft; /* number of chars left in this buffer */
629 char *nextc; /* next char in buffer */
630 char *buf; /* input buffer */
631 struct strpush *strpush; /* for pushing strings at this level */
632 struct strpush basestrpush; /* so pushing one is fast */
633};
634
635struct stackmark {
636 struct stack_block *stackp;
637 char *stacknxt;
638 int stacknleft;
639 struct stackmark *marknext;
640};
641
642struct shparam {
643 int nparam; /* # of positional parameters (without $0) */
644 unsigned char malloc; /* if parameter list dynamically allocated */
645 char **p; /* parameter list */
646 int optind; /* next parameter to be processed by getopts */
647 int optoff; /* used by getopts */
648};
649
Eric Andersen62483552001-07-10 06:09:16 +0000650/*
651 * When commands are first encountered, they are entered in a hash table.
652 * This ensures that a full path search will not have to be done for them
653 * on each invocation.
654 *
655 * We should investigate converting to a linear search, even though that
656 * would make the command name "hash" a misnomer.
657 */
658#define CMDTABLESIZE 31 /* should be prime */
659#define ARB 1 /* actual size determined at run time */
660
661
662
663struct tblentry {
664 struct tblentry *next; /* next entry in hash chain */
665 union param param; /* definition of builtin function */
666 short cmdtype; /* index identifying command */
667 char rehash; /* if set, cd done since entry created */
668 char cmdname[ARB]; /* name of command */
669};
670
671
672static struct tblentry *cmdtable[CMDTABLESIZE];
673static int builtinloc = -1; /* index in path of %builtin, or -1 */
674static int exerrno = 0; /* Last exec error */
675
676
677static void tryexec (char *, char **, char **);
678static void printentry (struct tblentry *, int);
679static void clearcmdentry (int);
680static struct tblentry *cmdlookup (const char *, int);
681static void delete_cmd_entry (void);
682static int path_change (const char *, int *);
683
684
Eric Andersen2870d962001-07-02 17:27:21 +0000685static void flushall (void);
Eric Andersen3102ac42001-07-06 04:26:23 +0000686static void out2fmt (const char *, ...)
687 __attribute__((__format__(__printf__,1,2)));
Eric Andersen2870d962001-07-02 17:27:21 +0000688static int xwrite (int, const char *, int);
Eric Andersen2870d962001-07-02 17:27:21 +0000689
Eric Andersen3102ac42001-07-06 04:26:23 +0000690static void outstr (const char *p, FILE *file) { fputs(p, file); }
691static void out1str(const char *p) { outstr(p, stdout); }
692static void out2str(const char *p) { outstr(p, stderr); }
Eric Andersen2870d962001-07-02 17:27:21 +0000693
Eric Andersen62483552001-07-10 06:09:16 +0000694#ifndef ASH_OPTIMIZE_FOR_SIZE
Eric Andersen3102ac42001-07-06 04:26:23 +0000695#define out2c(c) putc((c), stderr)
Eric Andersen62483552001-07-10 06:09:16 +0000696#else
697static void out2c(int c) { putc(c, stderr); }
698#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000699
700/* syntax table used when not in quotes */
701static const char basesyntax[257] = {
702 CENDFILE, CSPCL, CWORD, CCTL,
703 CCTL, CCTL, CCTL, CCTL,
704 CCTL, CCTL, CCTL, CWORD,
705 CWORD, CWORD, CWORD, CWORD,
706 CWORD, CWORD, CWORD, CWORD,
707 CWORD, CWORD, CWORD, CWORD,
708 CWORD, CWORD, CWORD, CWORD,
709 CWORD, CWORD, CWORD, CWORD,
710 CWORD, CWORD, CWORD, CWORD,
711 CWORD, CWORD, CWORD, CWORD,
712 CWORD, CWORD, CWORD, CWORD,
713 CWORD, CWORD, CWORD, CWORD,
714 CWORD, CWORD, CWORD, CWORD,
715 CWORD, CWORD, CWORD, CWORD,
716 CWORD, CWORD, CWORD, CWORD,
717 CWORD, CWORD, CWORD, CWORD,
718 CWORD, CWORD, CWORD, CWORD,
719 CWORD, CWORD, CWORD, CWORD,
720 CWORD, CWORD, CWORD, CWORD,
721 CWORD, CWORD, CWORD, CWORD,
722 CWORD, CWORD, CWORD, CWORD,
723 CWORD, CWORD, CWORD, CWORD,
724 CWORD, CWORD, CWORD, CWORD,
725 CWORD, CWORD, CWORD, CWORD,
726 CWORD, CWORD, CWORD, CWORD,
727 CWORD, CWORD, CWORD, CWORD,
728 CWORD, CWORD, CWORD, CWORD,
729 CWORD, CWORD, CWORD, CWORD,
730 CWORD, CWORD, CWORD, CWORD,
731 CWORD, CWORD, CWORD, CWORD,
732 CWORD, CWORD, CWORD, CWORD,
733 CWORD, CWORD, CWORD, CWORD,
734 CWORD, CWORD, CWORD, CWORD,
735 CWORD, CWORD, CWORD, CWORD,
736 CWORD, CWORD, CWORD, CSPCL,
737 CNL, CWORD, CWORD, CWORD,
738 CWORD, CWORD, CWORD, CWORD,
739 CWORD, CWORD, CWORD, CWORD,
740 CWORD, CWORD, CWORD, CWORD,
741 CWORD, CWORD, CWORD, CWORD,
742 CWORD, CWORD, CSPCL, CWORD,
743 CDQUOTE, CWORD, CVAR, CWORD,
744 CSPCL, CSQUOTE, CSPCL, CSPCL,
745 CWORD, CWORD, CWORD, CWORD,
746 CWORD, CWORD, CWORD, CWORD,
747 CWORD, CWORD, CWORD, CWORD,
748 CWORD, CWORD, CWORD, CWORD,
749 CWORD, CSPCL, CSPCL, CWORD,
750 CSPCL, CWORD, CWORD, CWORD,
751 CWORD, CWORD, CWORD, CWORD,
752 CWORD, CWORD, CWORD, CWORD,
753 CWORD, CWORD, CWORD, CWORD,
754 CWORD, CWORD, CWORD, CWORD,
755 CWORD, CWORD, CWORD, CWORD,
756 CWORD, CWORD, CWORD, CWORD,
757 CWORD, CWORD, CBACK, CWORD,
758 CWORD, CWORD, CBQUOTE, CWORD,
759 CWORD, CWORD, CWORD, CWORD,
760 CWORD, CWORD, CWORD, CWORD,
761 CWORD, CWORD, CWORD, CWORD,
762 CWORD, CWORD, CWORD, CWORD,
763 CWORD, CWORD, CWORD, CWORD,
764 CWORD, CWORD, CWORD, CWORD,
765 CWORD, CWORD, CSPCL, CENDVAR,
766 CWORD
767};
768
769/* syntax table used when in double quotes */
770static const char dqsyntax[257] = {
771 CENDFILE, CIGN, CWORD, CCTL,
772 CCTL, CCTL, CCTL, CCTL,
773 CCTL, CCTL, CCTL, CWORD,
774 CWORD, CWORD, CWORD, CWORD,
775 CWORD, CWORD, CWORD, CWORD,
776 CWORD, CWORD, CWORD, CWORD,
777 CWORD, CWORD, CWORD, CWORD,
778 CWORD, CWORD, CWORD, CWORD,
779 CWORD, CWORD, CWORD, CWORD,
780 CWORD, CWORD, CWORD, CWORD,
781 CWORD, CWORD, CWORD, CWORD,
782 CWORD, CWORD, CWORD, CWORD,
783 CWORD, CWORD, CWORD, CWORD,
784 CWORD, CWORD, CWORD, CWORD,
785 CWORD, CWORD, CWORD, CWORD,
786 CWORD, CWORD, CWORD, CWORD,
787 CWORD, CWORD, CWORD, CWORD,
788 CWORD, CWORD, CWORD, CWORD,
789 CWORD, CWORD, CWORD, CWORD,
790 CWORD, CWORD, CWORD, CWORD,
791 CWORD, CWORD, CWORD, CWORD,
792 CWORD, CWORD, CWORD, CWORD,
793 CWORD, CWORD, CWORD, CWORD,
794 CWORD, CWORD, CWORD, CWORD,
795 CWORD, CWORD, CWORD, CWORD,
796 CWORD, CWORD, CWORD, CWORD,
797 CWORD, CWORD, CWORD, CWORD,
798 CWORD, CWORD, CWORD, CWORD,
799 CWORD, CWORD, CWORD, CWORD,
800 CWORD, CWORD, CWORD, CWORD,
801 CWORD, CWORD, CWORD, CWORD,
802 CWORD, CWORD, CWORD, CWORD,
803 CWORD, CWORD, CWORD, CWORD,
804 CWORD, CWORD, CWORD, CWORD,
805 CWORD, CWORD, CWORD, CWORD,
806 CNL, CWORD, CWORD, CWORD,
807 CWORD, CWORD, CWORD, CWORD,
808 CWORD, CWORD, CWORD, CWORD,
809 CWORD, CWORD, CWORD, CWORD,
810 CWORD, CWORD, CWORD, CWORD,
811 CWORD, CWORD, CWORD, CCTL,
812 CENDQUOTE,CWORD, CVAR, CWORD,
813 CWORD, CWORD, CWORD, CWORD,
814 CCTL, CWORD, CWORD, CCTL,
815 CWORD, CCTL, CWORD, CWORD,
816 CWORD, CWORD, CWORD, CWORD,
817 CWORD, CWORD, CWORD, CWORD,
818 CCTL, CWORD, CWORD, CCTL,
819 CWORD, CCTL, CWORD, CWORD,
820 CWORD, CWORD, CWORD, CWORD,
821 CWORD, CWORD, CWORD, CWORD,
822 CWORD, CWORD, CWORD, CWORD,
823 CWORD, CWORD, CWORD, CWORD,
824 CWORD, CWORD, CWORD, CWORD,
825 CWORD, CWORD, CWORD, CWORD,
826 CWORD, CCTL, CBACK, CCTL,
827 CWORD, CWORD, CBQUOTE, CWORD,
828 CWORD, CWORD, CWORD, CWORD,
829 CWORD, CWORD, CWORD, CWORD,
830 CWORD, CWORD, CWORD, CWORD,
831 CWORD, CWORD, CWORD, CWORD,
832 CWORD, CWORD, CWORD, CWORD,
833 CWORD, CWORD, CWORD, CWORD,
834 CWORD, CWORD, CWORD, CENDVAR,
835 CCTL
836};
837
838/* syntax table used when in single quotes */
839static const char sqsyntax[257] = {
840 CENDFILE, CIGN, CWORD, CCTL,
841 CCTL, CCTL, CCTL, CCTL,
842 CCTL, CCTL, CCTL, CWORD,
843 CWORD, CWORD, CWORD, CWORD,
844 CWORD, CWORD, CWORD, CWORD,
845 CWORD, CWORD, CWORD, CWORD,
846 CWORD, CWORD, CWORD, CWORD,
847 CWORD, CWORD, CWORD, CWORD,
848 CWORD, CWORD, CWORD, CWORD,
849 CWORD, CWORD, CWORD, CWORD,
850 CWORD, CWORD, CWORD, CWORD,
851 CWORD, CWORD, CWORD, CWORD,
852 CWORD, CWORD, CWORD, CWORD,
853 CWORD, CWORD, CWORD, CWORD,
854 CWORD, CWORD, CWORD, CWORD,
855 CWORD, CWORD, CWORD, CWORD,
856 CWORD, CWORD, CWORD, CWORD,
857 CWORD, CWORD, CWORD, CWORD,
858 CWORD, CWORD, CWORD, CWORD,
859 CWORD, CWORD, CWORD, CWORD,
860 CWORD, CWORD, CWORD, CWORD,
861 CWORD, CWORD, CWORD, CWORD,
862 CWORD, CWORD, CWORD, CWORD,
863 CWORD, CWORD, CWORD, CWORD,
864 CWORD, CWORD, CWORD, CWORD,
865 CWORD, CWORD, CWORD, CWORD,
866 CWORD, CWORD, CWORD, CWORD,
867 CWORD, CWORD, CWORD, CWORD,
868 CWORD, CWORD, CWORD, CWORD,
869 CWORD, CWORD, CWORD, CWORD,
870 CWORD, CWORD, CWORD, CWORD,
871 CWORD, CWORD, CWORD, CWORD,
872 CWORD, CWORD, CWORD, CWORD,
873 CWORD, CWORD, CWORD, CWORD,
874 CWORD, CWORD, CWORD, CWORD,
875 CNL, CWORD, CWORD, CWORD,
876 CWORD, CWORD, CWORD, CWORD,
877 CWORD, CWORD, CWORD, CWORD,
878 CWORD, CWORD, CWORD, CWORD,
879 CWORD, CWORD, CWORD, CWORD,
880 CWORD, CWORD, CWORD, CCTL,
881 CWORD, CWORD, CWORD, CWORD,
882 CWORD, CENDQUOTE,CWORD, CWORD,
883 CCTL, CWORD, CWORD, CCTL,
884 CWORD, CCTL, CWORD, CWORD,
885 CWORD, CWORD, CWORD, CWORD,
886 CWORD, CWORD, CWORD, CWORD,
887 CCTL, CWORD, CWORD, CCTL,
888 CWORD, CCTL, CWORD, CWORD,
889 CWORD, CWORD, CWORD, CWORD,
890 CWORD, CWORD, CWORD, CWORD,
891 CWORD, CWORD, CWORD, CWORD,
892 CWORD, CWORD, CWORD, CWORD,
893 CWORD, CWORD, CWORD, CWORD,
894 CWORD, CWORD, CWORD, CWORD,
895 CWORD, CCTL, CCTL, CCTL,
896 CWORD, CWORD, CWORD, CWORD,
897 CWORD, CWORD, CWORD, CWORD,
898 CWORD, CWORD, CWORD, CWORD,
899 CWORD, CWORD, CWORD, CWORD,
900 CWORD, CWORD, CWORD, CWORD,
901 CWORD, CWORD, CWORD, CWORD,
902 CWORD, CWORD, CWORD, CWORD,
903 CWORD, CWORD, CWORD, CWORD,
904 CCTL
905};
906
907/* syntax table used when in arithmetic */
908static const char arisyntax[257] = {
909 CENDFILE, CIGN, CWORD, CCTL,
910 CCTL, CCTL, CCTL, CCTL,
911 CCTL, CCTL, CCTL, CWORD,
912 CWORD, CWORD, CWORD, CWORD,
913 CWORD, CWORD, CWORD, CWORD,
914 CWORD, CWORD, CWORD, CWORD,
915 CWORD, CWORD, CWORD, CWORD,
916 CWORD, CWORD, CWORD, CWORD,
917 CWORD, CWORD, CWORD, CWORD,
918 CWORD, CWORD, CWORD, CWORD,
919 CWORD, CWORD, CWORD, CWORD,
920 CWORD, CWORD, CWORD, CWORD,
921 CWORD, CWORD, CWORD, CWORD,
922 CWORD, CWORD, CWORD, CWORD,
923 CWORD, CWORD, CWORD, CWORD,
924 CWORD, CWORD, CWORD, CWORD,
925 CWORD, CWORD, CWORD, CWORD,
926 CWORD, CWORD, CWORD, CWORD,
927 CWORD, CWORD, CWORD, CWORD,
928 CWORD, CWORD, CWORD, CWORD,
929 CWORD, CWORD, CWORD, CWORD,
930 CWORD, CWORD, CWORD, CWORD,
931 CWORD, CWORD, CWORD, CWORD,
932 CWORD, CWORD, CWORD, CWORD,
933 CWORD, CWORD, CWORD, CWORD,
934 CWORD, CWORD, CWORD, CWORD,
935 CWORD, CWORD, CWORD, CWORD,
936 CWORD, CWORD, CWORD, CWORD,
937 CWORD, CWORD, CWORD, CWORD,
938 CWORD, CWORD, CWORD, CWORD,
939 CWORD, CWORD, CWORD, CWORD,
940 CWORD, CWORD, CWORD, CWORD,
941 CWORD, CWORD, CWORD, CWORD,
942 CWORD, CWORD, CWORD, CWORD,
943 CWORD, CWORD, CWORD, CWORD,
944 CNL, CWORD, CWORD, CWORD,
945 CWORD, CWORD, CWORD, CWORD,
946 CWORD, CWORD, CWORD, CWORD,
947 CWORD, CWORD, CWORD, CWORD,
948 CWORD, CWORD, CWORD, CWORD,
949 CWORD, CWORD, CWORD, CWORD,
950 CDQUOTE, CWORD, CVAR, CWORD,
951 CWORD, CSQUOTE, CLP, CRP,
952 CWORD, CWORD, CWORD, CWORD,
953 CWORD, CWORD, CWORD, CWORD,
954 CWORD, CWORD, CWORD, CWORD,
955 CWORD, CWORD, CWORD, CWORD,
956 CWORD, CWORD, CWORD, CWORD,
957 CWORD, CWORD, CWORD, CWORD,
958 CWORD, CWORD, CWORD, CWORD,
959 CWORD, CWORD, CWORD, CWORD,
960 CWORD, CWORD, CWORD, CWORD,
961 CWORD, CWORD, CWORD, CWORD,
962 CWORD, CWORD, CWORD, CWORD,
963 CWORD, CWORD, CWORD, CWORD,
964 CWORD, CWORD, CBACK, CWORD,
965 CWORD, CWORD, CBQUOTE, CWORD,
966 CWORD, CWORD, CWORD, CWORD,
967 CWORD, CWORD, CWORD, CWORD,
968 CWORD, CWORD, CWORD, CWORD,
969 CWORD, CWORD, CWORD, CWORD,
970 CWORD, CWORD, CWORD, CWORD,
971 CWORD, CWORD, CWORD, CWORD,
972 CWORD, CWORD, CWORD, CENDVAR,
973 CWORD
974};
975
976/* character classification table */
977static const char is_type[257] = {
978 0, 0, 0, 0,
979 0, 0, 0, 0,
980 0, 0, 0, 0,
981 0, 0, 0, 0,
982 0, 0, 0, 0,
983 0, 0, 0, 0,
984 0, 0, 0, 0,
985 0, 0, 0, 0,
986 0, 0, 0, 0,
987 0, 0, 0, 0,
988 0, 0, 0, 0,
989 0, 0, 0, 0,
990 0, 0, 0, 0,
991 0, 0, 0, 0,
992 0, 0, 0, 0,
993 0, 0, 0, 0,
994 0, 0, 0, 0,
995 0, 0, 0, 0,
996 0, 0, 0, 0,
997 0, 0, 0, 0,
998 0, 0, 0, 0,
999 0, 0, 0, 0,
1000 0, 0, 0, 0,
1001 0, 0, 0, 0,
1002 0, 0, 0, 0,
1003 0, 0, 0, 0,
1004 0, 0, 0, 0,
1005 0, 0, 0, 0,
1006 0, 0, 0, 0,
1007 0, 0, 0, 0,
1008 0, 0, 0, 0,
1009 0, 0, 0, 0,
1010 0, 0, 0, 0,
1011 0, 0, 0, 0,
1012 0, 0, 0, 0,
1013 0, 0, 0, 0,
1014 0, 0, 0, 0,
1015 0, 0, 0, 0,
1016 0, 0, 0, 0,
1017 0, 0, 0, 0,
1018 0, 0, 0, ISSPECL,
1019 0, ISSPECL, ISSPECL, 0,
1020 0, 0, 0, 0,
1021 ISSPECL, 0, 0, ISSPECL,
1022 0, 0, ISDIGIT, ISDIGIT,
1023 ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT,
1024 ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT,
1025 0, 0, 0, 0,
1026 0, ISSPECL, ISSPECL, ISUPPER,
1027 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
1028 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
1029 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
1030 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
1031 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
1032 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
1033 ISUPPER, 0, 0, 0,
1034 0, ISUNDER, 0, ISLOWER,
1035 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
1036 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
1037 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
1038 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
1039 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
1040 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
1041 ISLOWER, 0, 0, 0,
1042 0
1043};
1044
1045/* Array indicating which tokens mark the end of a list */
1046static const char tokendlist[] = {
1047 1,
1048 0,
1049 0,
1050 0,
1051 0,
1052 0,
1053 0,
1054 0,
1055 1,
1056 1,
1057 1,
1058 0,
1059 0,
1060 0,
1061 0,
1062 0,
1063 1,
1064 1,
1065 1,
1066 1,
1067 1,
1068 1,
1069 0,
1070 0,
1071 0,
1072 1,
1073 0,
1074 0,
1075 0,
1076 1,
1077};
1078
1079static const char *const tokname[] = {
1080 "end of file",
1081 "newline",
1082 "\";\"",
1083 "\"&\"",
1084 "\"&&\"",
1085 "\"||\"",
1086 "\"|\"",
1087 "\"(\"",
1088 "\")\"",
1089 "\";;\"",
1090 "\"`\"",
1091 "redirection",
1092 "word",
1093 "assignment",
1094 "\"!\"",
1095 "\"case\"",
1096 "\"do\"",
1097 "\"done\"",
1098 "\"elif\"",
1099 "\"else\"",
1100 "\"esac\"",
1101 "\"fi\"",
1102 "\"for\"",
1103 "\"if\"",
1104 "\"in\"",
1105 "\"then\"",
1106 "\"until\"",
1107 "\"while\"",
1108 "\"{\"",
1109 "\"}\"",
1110};
1111
1112#define KWDOFFSET 14
1113
1114static const char *const parsekwd[] = {
1115 "!",
1116 "case",
1117 "do",
1118 "done",
1119 "elif",
1120 "else",
1121 "esac",
1122 "fi",
1123 "for",
1124 "if",
1125 "in",
1126 "then",
1127 "until",
1128 "while",
1129 "{",
1130 "}"
1131};
1132
1133
1134static int plinno = 1; /* input line number */
1135
1136static int parselleft; /* copy of parsefile->lleft */
1137
1138static struct parsefile basepf; /* top level input file */
1139static char basebuf[BUFSIZ]; /* buffer for top level input file */
1140static struct parsefile *parsefile = &basepf; /* current input file */
1141
1142/*
1143 * NEOF is returned by parsecmd when it encounters an end of file. It
1144 * must be distinct from NULL, so we use the address of a variable that
1145 * happens to be handy.
1146 */
1147
1148static int tokpushback; /* last token pushed back */
1149#define NEOF ((union node *)&tokpushback)
1150static int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */
1151
1152
1153static void error (const char *, ...) __attribute__((__noreturn__));
1154static void exerror (int, const char *, ...) __attribute__((__noreturn__));
1155static void shellexec (char **, char **, const char *, int)
1156 __attribute__((noreturn));
1157static void exitshell (int) __attribute__((noreturn));
1158
1159static int goodname(const char *);
1160static void ignoresig (int);
1161static void onsig (int);
1162static void dotrap (void);
1163static int decode_signal (const char *, int);
1164
1165static void shprocvar(void);
1166static void deletefuncs(void);
1167static void setparam (char **);
1168static void freeparam (volatile struct shparam *);
1169
1170/* reasons for skipping commands (see comment on breakcmd routine) */
1171#define SKIPBREAK 1
1172#define SKIPCONT 2
1173#define SKIPFUNC 3
1174#define SKIPFILE 4
1175
1176/* values of cmdtype */
1177#define CMDUNKNOWN -1 /* no entry in table for command */
1178#define CMDNORMAL 0 /* command is an executable program */
1179#define CMDBUILTIN 1 /* command is a shell builtin */
1180#define CMDFUNCTION 2 /* command is a shell function */
1181
1182#define DO_ERR 1 /* find_command prints errors */
1183#define DO_ABS 2 /* find_command checks absolute paths */
1184#define DO_NOFUN 4 /* find_command ignores functions */
1185#define DO_BRUTE 8 /* find_command ignores hash table */
1186
1187/*
1188 * Shell variables.
1189 */
1190
1191/* flags */
1192#define VEXPORT 0x01 /* variable is exported */
1193#define VREADONLY 0x02 /* variable cannot be modified */
1194#define VSTRFIXED 0x04 /* variable struct is staticly allocated */
1195#define VTEXTFIXED 0x08 /* text is staticly allocated */
1196#define VSTACK 0x10 /* text is allocated on the stack */
1197#define VUNSET 0x20 /* the variable is not set */
1198#define VNOFUNC 0x40 /* don't call the callback function */
1199
1200
1201struct var {
1202 struct var *next; /* next entry in hash list */
1203 int flags; /* flags are defined above */
1204 char *text; /* name=value */
1205 void (*func) (const char *);
1206 /* function to be called when */
1207 /* the variable gets set/unset */
1208};
1209
1210struct localvar {
1211 struct localvar *next; /* next local variable in list */
1212 struct var *vp; /* the variable that was made local */
1213 int flags; /* saved flags */
1214 char *text; /* saved text */
1215};
1216
1217
Eric Andersen62483552001-07-10 06:09:16 +00001218#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00001219#define rmescapes(p) _rmescapes((p), 0)
1220static char *_rmescapes (char *, int);
1221#else
1222static void rmescapes (char *);
1223#endif
1224
1225static int casematch (union node *, const char *);
1226static void clearredir(void);
1227static void popstring(void);
1228static void readcmdfile (const char *);
1229
1230static int number (const char *);
1231static int is_number (const char *, int *num);
1232static char *single_quote (const char *);
1233static int nextopt (const char *);
1234
1235static void redirect (union node *, int);
1236static void popredir (void);
1237static int dup_as_newfd (int, int);
1238
1239static void changepath(const char *newval);
1240static void getoptsreset(const char *value);
1241
1242
1243static int parsenleft; /* copy of parsefile->nleft */
1244static char *parsenextc; /* copy of parsefile->nextc */
1245static int rootpid; /* pid of main shell */
1246static int rootshell; /* true if we aren't a child of the main shell */
1247
1248static const char spcstr[] = " ";
1249static const char snlfmt[] = "%s\n";
1250
1251static int sstrnleft;
1252static int herefd = -1;
1253
1254static struct localvar *localvars;
1255
1256static struct var vifs;
1257static struct var vmail;
1258static struct var vmpath;
1259static struct var vpath;
1260static struct var vps1;
1261static struct var vps2;
1262static struct var voptind;
1263#ifdef BB_LOCALE_SUPPORT
1264static struct var vlc_all;
1265static struct var vlc_ctype;
1266#endif
1267
1268struct varinit {
1269 struct var *var;
1270 int flags;
1271 const char *text;
1272 void (*func) (const char *);
1273};
1274
1275static const char defpathvar[] =
1276 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
1277#define defpath (defpathvar + 5)
1278
1279#ifdef IFS_BROKEN
1280static const char defifsvar[] = "IFS= \t\n";
1281#define defifs (defifsvar + 4)
1282#else
1283static const char defifs[] = " \t\n";
1284#endif
1285
1286static const struct varinit varinit[] = {
1287#ifdef IFS_BROKEN
1288 { &vifs, VSTRFIXED|VTEXTFIXED, defifsvar,
1289#else
1290 { &vifs, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS=",
1291#endif
1292 NULL },
1293 { &vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=",
1294 NULL },
1295 { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=",
1296 NULL },
1297 { &vpath, VSTRFIXED|VTEXTFIXED, defpathvar,
1298 changepath },
1299 /*
1300 * vps1 depends on uid
1301 */
1302 { &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ",
1303 NULL },
1304 { &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1",
1305 getoptsreset },
1306#ifdef BB_LOCALE_SUPPORT
1307 { &vlc_all, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL=",
1308 change_lc_all },
1309 { &vlc_ctype, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE=",
1310 change_lc_ctype },
1311#endif
1312 { NULL, 0, NULL,
1313 NULL }
1314};
1315
1316#define VTABSIZE 39
1317
1318static struct var *vartab[VTABSIZE];
1319
1320/*
1321 * The following macros access the values of the above variables.
1322 * They have to skip over the name. They return the null string
1323 * for unset variables.
1324 */
1325
1326#define ifsval() (vifs.text + 4)
1327#define ifsset() ((vifs.flags & VUNSET) == 0)
1328#define mailval() (vmail.text + 5)
1329#define mpathval() (vmpath.text + 9)
1330#define pathval() (vpath.text + 5)
1331#define ps1val() (vps1.text + 4)
1332#define ps2val() (vps2.text + 4)
1333#define optindval() (voptind.text + 7)
1334
1335#define mpathset() ((vmpath.flags & VUNSET) == 0)
1336
1337static void initvar (void);
1338static void setvar (const char *, const char *, int);
1339static void setvareq (char *, int);
1340static void listsetvar (struct strlist *);
Eric Andersen62483552001-07-10 06:09:16 +00001341static const char *lookupvar (const char *);
1342static const char *bltinlookup (const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001343static char **environment (void);
1344static int showvarscmd (int, char **);
1345static void mklocal (char *);
1346static void poplocalvars (void);
1347static int unsetvar (const char *);
1348static int varequal (const char *, const char *);
1349
1350
1351static char *arg0; /* value of $0 */
1352static struct shparam shellparam; /* current positional parameters */
1353static char **argptr; /* argument list for builtin commands */
1354static char *optionarg; /* set by nextopt (like getopt) */
1355static char *optptr; /* used by nextopt */
1356static char *minusc; /* argument to -c option */
1357
1358
1359#ifdef ASH_ALIAS
1360
1361#define ALIASINUSE 1
1362#define ALIASDEAD 2
1363
Eric Andersen3102ac42001-07-06 04:26:23 +00001364#define ATABSIZE 39
1365
Eric Andersen2870d962001-07-02 17:27:21 +00001366struct alias {
1367 struct alias *next;
1368 char *name;
1369 char *val;
1370 int flag;
1371};
1372
1373static struct alias *atab[ATABSIZE];
1374
1375static void setalias (char *, char *);
1376static struct alias **hashalias (const char *);
1377static struct alias *freealias (struct alias *);
1378static struct alias **__lookupalias (const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00001379
1380static void
1381setalias(name, val)
1382 char *name, *val;
1383{
1384 struct alias *ap, **app;
1385
1386 app = __lookupalias(name);
1387 ap = *app;
1388 INTOFF;
1389 if (ap) {
1390 if (!(ap->flag & ALIASINUSE)) {
1391 ckfree(ap->val);
1392 }
Eric Andersen2870d962001-07-02 17:27:21 +00001393 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00001394 ap->flag &= ~ALIASDEAD;
1395 } else {
1396 /* not found */
1397 ap = ckmalloc(sizeof (struct alias));
1398 ap->name = savestr(name);
1399 ap->val = savestr(val);
1400 ap->flag = 0;
1401 ap->next = 0;
1402 *app = ap;
1403 }
1404 INTON;
1405}
1406
1407static int
Eric Andersen2870d962001-07-02 17:27:21 +00001408unalias(char *name)
1409{
Eric Andersencb57d552001-06-28 07:25:16 +00001410 struct alias **app;
1411
1412 app = __lookupalias(name);
1413
1414 if (*app) {
1415 INTOFF;
1416 *app = freealias(*app);
1417 INTON;
1418 return (0);
1419 }
1420
1421 return (1);
1422}
1423
Eric Andersencb57d552001-06-28 07:25:16 +00001424static void
Eric Andersen2870d962001-07-02 17:27:21 +00001425rmaliases(void)
1426{
Eric Andersencb57d552001-06-28 07:25:16 +00001427 struct alias *ap, **app;
1428 int i;
1429
1430 INTOFF;
1431 for (i = 0; i < ATABSIZE; i++) {
1432 app = &atab[i];
1433 for (ap = *app; ap; ap = *app) {
1434 *app = freealias(*app);
1435 if (ap == *app) {
1436 app = &ap->next;
1437 }
1438 }
1439 }
1440 INTON;
1441}
1442
Eric Andersen2870d962001-07-02 17:27:21 +00001443static struct alias *
1444lookupalias(const char *name, int check)
Eric Andersencb57d552001-06-28 07:25:16 +00001445{
1446 struct alias *ap = *__lookupalias(name);
1447
1448 if (check && ap && (ap->flag & ALIASINUSE))
1449 return (NULL);
1450 return (ap);
1451}
1452
Eric Andersen2870d962001-07-02 17:27:21 +00001453static void
1454printalias(const struct alias *ap) {
1455 char *p;
1456
1457 p = single_quote(ap->val);
Eric Andersen62483552001-07-10 06:09:16 +00001458 printf("alias %s=%s\n", ap->name, p);
Eric Andersen2870d962001-07-02 17:27:21 +00001459 stunalloc(p);
1460}
1461
Eric Andersencb57d552001-06-28 07:25:16 +00001462
1463/*
1464 * TODO - sort output
1465 */
1466static int
Eric Andersen2870d962001-07-02 17:27:21 +00001467aliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001468{
1469 char *n, *v;
1470 int ret = 0;
1471 struct alias *ap;
1472
1473 if (argc == 1) {
1474 int i;
1475
1476 for (i = 0; i < ATABSIZE; i++)
1477 for (ap = atab[i]; ap; ap = ap->next) {
1478 printalias(ap);
1479 }
1480 return (0);
1481 }
1482 while ((n = *++argv) != NULL) {
1483 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
1484 if ((ap = *__lookupalias(n)) == NULL) {
Eric Andersen3102ac42001-07-06 04:26:23 +00001485 out2fmt("%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00001486 ret = 1;
1487 } else
1488 printalias(ap);
1489 }
1490 else {
1491 *v++ = '\0';
1492 setalias(n, v);
1493 }
1494 }
1495
1496 return (ret);
1497}
1498
1499static int
Eric Andersen2870d962001-07-02 17:27:21 +00001500unaliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001501{
1502 int i;
1503
1504 while ((i = nextopt("a")) != '\0') {
1505 if (i == 'a') {
1506 rmaliases();
1507 return (0);
1508 }
1509 }
1510 for (i = 0; *argptr; argptr++) {
1511 if (unalias(*argptr)) {
Eric Andersen3102ac42001-07-06 04:26:23 +00001512 out2fmt("%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00001513 i = 1;
1514 }
1515 }
1516
1517 return (i);
1518}
1519
1520static struct alias **
1521hashalias(p)
1522 const char *p;
1523 {
1524 unsigned int hashval;
1525
1526 hashval = *p << 4;
1527 while (*p)
1528 hashval+= *p++;
1529 return &atab[hashval % ATABSIZE];
1530}
1531
1532static struct alias *
1533freealias(struct alias *ap) {
1534 struct alias *next;
1535
1536 if (ap->flag & ALIASINUSE) {
1537 ap->flag |= ALIASDEAD;
1538 return ap;
1539 }
1540
1541 next = ap->next;
1542 ckfree(ap->name);
1543 ckfree(ap->val);
1544 ckfree(ap);
1545 return next;
1546}
1547
Eric Andersencb57d552001-06-28 07:25:16 +00001548
1549static struct alias **
1550__lookupalias(const char *name) {
1551 struct alias **app = hashalias(name);
1552
1553 for (; *app; app = &(*app)->next) {
1554 if (equal(name, (*app)->name)) {
1555 break;
1556 }
1557 }
1558
1559 return app;
1560}
Eric Andersen2870d962001-07-02 17:27:21 +00001561#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001562
1563#ifdef ASH_MATH_SUPPORT
Eric Andersen74bcd162001-07-30 21:41:37 +00001564/* The generated file arith.c has been replaced with a custom hand
1565 * written implementation written by Aaron Lehmann <aaronl@vitelus.com>.
1566 * This is now part of libbb, so that it can be used by all the shells
1567 * in busybox. */
Eric Andersen2870d962001-07-02 17:27:21 +00001568#define ARITH_NUM 257
1569#define ARITH_LPAREN 258
1570#define ARITH_RPAREN 259
1571#define ARITH_OR 260
1572#define ARITH_AND 261
1573#define ARITH_BOR 262
1574#define ARITH_BXOR 263
1575#define ARITH_BAND 264
1576#define ARITH_EQ 265
1577#define ARITH_NE 266
1578#define ARITH_LT 267
1579#define ARITH_GT 268
1580#define ARITH_GE 269
1581#define ARITH_LE 270
1582#define ARITH_LSHIFT 271
1583#define ARITH_RSHIFT 272
1584#define ARITH_ADD 273
1585#define ARITH_SUB 274
1586#define ARITH_MUL 275
1587#define ARITH_DIV 276
1588#define ARITH_REM 277
1589#define ARITH_UNARYMINUS 278
1590#define ARITH_UNARYPLUS 279
1591#define ARITH_NOT 280
1592#define ARITH_BNOT 281
1593
1594static void expari (int);
Eric Andersencb57d552001-06-28 07:25:16 +00001595#endif
1596
Eric Andersen2870d962001-07-02 17:27:21 +00001597static char *trap[NSIG]; /* trap handler commands */
1598static char sigmode[NSIG - 1]; /* current value of signal */
1599static char gotsig[NSIG - 1]; /* indicates specified signal received */
1600static int pendingsigs; /* indicates some signal received */
1601
Eric Andersencb57d552001-06-28 07:25:16 +00001602/*
1603 * This file was generated by the mkbuiltins program.
1604 */
1605
Eric Andersen2870d962001-07-02 17:27:21 +00001606#ifdef JOBS
1607static int bgcmd (int, char **);
1608static int fgcmd (int, char **);
1609static int killcmd (int, char **);
1610#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001611static int bltincmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001612static int cdcmd (int, char **);
1613static int breakcmd (int, char **);
1614#ifdef ASH_CMDCMD
1615static int commandcmd (int, char **);
1616#endif
1617static int dotcmd (int, char **);
1618static int evalcmd (int, char **);
1619static int execcmd (int, char **);
1620static int exitcmd (int, char **);
1621static int exportcmd (int, char **);
1622static int histcmd (int, char **);
1623static int hashcmd (int, char **);
Eric Andersen1c039232001-07-07 00:05:55 +00001624static int helpcmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001625static int jobscmd (int, char **);
1626static int localcmd (int, char **);
Eric Andersen3102ac42001-07-06 04:26:23 +00001627#ifndef BB_PWD
Eric Andersen2870d962001-07-02 17:27:21 +00001628static int pwdcmd (int, char **);
1629#endif
1630static int readcmd (int, char **);
1631static int returncmd (int, char **);
1632static int setcmd (int, char **);
1633static int setvarcmd (int, char **);
1634static int shiftcmd (int, char **);
1635static int trapcmd (int, char **);
1636static int umaskcmd (int, char **);
1637#ifdef ASH_ALIAS
1638static int aliascmd (int, char **);
1639static int unaliascmd (int, char **);
1640#endif
1641static int unsetcmd (int, char **);
1642static int waitcmd (int, char **);
1643static int ulimitcmd (int, char **);
1644static int timescmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001645#ifdef ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +00001646static int letcmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001647#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001648static int typecmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001649#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00001650static int getoptscmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001651#endif
1652
Eric Andersen2870d962001-07-02 17:27:21 +00001653#ifndef BB_TRUE_FALSE
Eric Andersen2870d962001-07-02 17:27:21 +00001654static int true_main (int, char **);
1655static int false_main (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001656#endif
1657
1658static void setpwd (const char *, int);
1659
1660
1661#define BUILTIN_NOSPEC "0"
1662#define BUILTIN_SPECIAL "1"
1663#define BUILTIN_REGULAR "2"
1664#define BUILTIN_ASSIGN "4"
1665#define BUILTIN_SPEC_ASSG "5"
1666#define BUILTIN_REG_ASSG "6"
1667
1668#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1669#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1670#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
1671
1672struct builtincmd {
1673 const char *name;
1674 int (*const builtinfunc) (int, char **);
1675 //unsigned flags;
1676};
1677
Eric Andersencb57d552001-06-28 07:25:16 +00001678
1679/* It is CRUCIAL that this listing be kept in ascii order, otherwise
1680 * the binary search in find_builtin() will stop working. If you value
1681 * your kneecaps, you'll be sure to *make sure* that any changes made
1682 * to this array result in the listing remaining in ascii order. You
1683 * have been warned.
1684 */
1685static const struct builtincmd builtincmds[] = {
Eric Andersen62483552001-07-10 06:09:16 +00001686 { BUILTIN_SPECIAL ".", dotcmd }, /* first, see declare DOTCMD */
Eric Andersen2870d962001-07-02 17:27:21 +00001687 { BUILTIN_SPECIAL ":", true_main },
1688#ifdef ASH_ALIAS
1689 { BUILTIN_REG_ASSG "alias", aliascmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001690#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001691#ifdef JOBS
1692 { BUILTIN_REGULAR "bg", bgcmd },
1693#endif
1694 { BUILTIN_SPECIAL "break", breakcmd },
Eric Andersen3102ac42001-07-06 04:26:23 +00001695 { BUILTIN_SPECIAL "builtin", bltincmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001696 { BUILTIN_REGULAR "cd", cdcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001697 { BUILTIN_NOSPEC "chdir", cdcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001698#ifdef ASH_CMDCMD
1699 { BUILTIN_REGULAR "command", commandcmd },
1700#endif
1701 { BUILTIN_SPECIAL "continue", breakcmd },
1702 { BUILTIN_SPECIAL "eval", evalcmd },
1703 { BUILTIN_SPECIAL "exec", execcmd },
1704 { BUILTIN_SPECIAL "exit", exitcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001705 { BUILTIN_SPEC_ASSG "export", exportcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001706 { BUILTIN_REGULAR "false", false_main },
Eric Andersen2870d962001-07-02 17:27:21 +00001707 { BUILTIN_REGULAR "fc", histcmd },
1708#ifdef JOBS
1709 { BUILTIN_REGULAR "fg", fgcmd },
1710#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001711#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00001712 { BUILTIN_REGULAR "getopts", getoptscmd },
1713#endif
1714 { BUILTIN_NOSPEC "hash", hashcmd },
Eric Andersen1c039232001-07-07 00:05:55 +00001715 { BUILTIN_NOSPEC "help", helpcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001716 { BUILTIN_REGULAR "jobs", jobscmd },
1717#ifdef JOBS
1718 { BUILTIN_REGULAR "kill", killcmd },
1719#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001720#ifdef ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +00001721 { BUILTIN_REGULAR "let", letcmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001722#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001723 { BUILTIN_ASSIGN "local", localcmd },
Eric Andersen3102ac42001-07-06 04:26:23 +00001724#ifndef BB_PWD
Eric Andersen2870d962001-07-02 17:27:21 +00001725 { BUILTIN_NOSPEC "pwd", pwdcmd },
1726#endif
1727 { BUILTIN_REGULAR "read", readcmd },
1728 { BUILTIN_SPEC_ASSG "readonly", exportcmd },
1729 { BUILTIN_SPECIAL "return", returncmd },
1730 { BUILTIN_SPECIAL "set", setcmd },
1731 { BUILTIN_NOSPEC "setvar", setvarcmd },
1732 { BUILTIN_SPECIAL "shift", shiftcmd },
1733 { BUILTIN_SPECIAL "times", timescmd },
1734 { BUILTIN_SPECIAL "trap", trapcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001735 { BUILTIN_REGULAR "true", true_main },
Eric Andersen2870d962001-07-02 17:27:21 +00001736 { BUILTIN_NOSPEC "type", typecmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001737 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1738 { BUILTIN_REGULAR "umask", umaskcmd },
1739#ifdef ASH_ALIAS
1740 { BUILTIN_REGULAR "unalias", unaliascmd },
1741#endif
1742 { BUILTIN_SPECIAL "unset", unsetcmd },
1743 { BUILTIN_REGULAR "wait", waitcmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001744};
1745#define NUMBUILTINS (sizeof (builtincmds) / sizeof (struct builtincmd) )
1746
Eric Andersen2870d962001-07-02 17:27:21 +00001747static const struct builtincmd *DOTCMD = &builtincmds[0];
1748static struct builtincmd *BLTINCMD;
1749static struct builtincmd *EXECCMD;
1750static struct builtincmd *EVALCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00001751
Eric Andersen2870d962001-07-02 17:27:21 +00001752/* states */
1753#define JOBSTOPPED 1 /* all procs are stopped */
1754#define JOBDONE 2 /* all procs are completed */
Eric Andersencb57d552001-06-28 07:25:16 +00001755
Eric Andersen2870d962001-07-02 17:27:21 +00001756/*
1757 * A job structure contains information about a job. A job is either a
1758 * single process or a set of processes contained in a pipeline. In the
1759 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1760 * array of pids.
1761 */
Eric Andersencb57d552001-06-28 07:25:16 +00001762
Eric Andersen2870d962001-07-02 17:27:21 +00001763struct procstat {
1764 pid_t pid; /* process id */
1765 int status; /* status flags (defined above) */
1766 char *cmd; /* text of command being run */
1767};
Eric Andersencb57d552001-06-28 07:25:16 +00001768
Eric Andersen2870d962001-07-02 17:27:21 +00001769
1770static int job_warning; /* user was warned about stopped jobs */
1771
1772#ifdef JOBS
1773static void setjobctl(int enable);
1774#else
1775#define setjobctl(on) /* do nothing */
Eric Andersencb57d552001-06-28 07:25:16 +00001776#endif
1777
Eric Andersen2870d962001-07-02 17:27:21 +00001778
1779struct job {
1780 struct procstat ps0; /* status of process */
1781 struct procstat *ps; /* status or processes when more than one */
1782 short nprocs; /* number of processes */
1783 short pgrp; /* process group of this job */
1784 char state; /* true if job is finished */
1785 char used; /* true if this entry is in used */
1786 char changed; /* true if status has changed */
1787#ifdef JOBS
1788 char jobctl; /* job running under job control */
1789#endif
1790};
1791
1792static struct job *jobtab; /* array of jobs */
1793static int njobs; /* size of array */
1794static int backgndpid = -1; /* pid of last background process */
1795#ifdef JOBS
1796static int initialpgrp; /* pgrp of shell on invocation */
1797static int curjob; /* current job */
1798static int jobctl;
1799#endif
1800static int intreceived;
1801
Eric Andersen62483552001-07-10 06:09:16 +00001802static struct job *makejob (const union node *, int);
1803static int forkshell (struct job *, const union node *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00001804static int waitforjob (struct job *);
1805
1806static int docd (char *, int);
1807static char *getcomponent (void);
1808static void updatepwd (const char *);
1809static void getpwd (void);
1810
1811static char *padvance (const char **, const char *);
1812
1813static char nullstr[1]; /* zero length string */
1814static char *curdir = nullstr; /* current working directory */
1815static char *cdcomppath;
1816
Eric Andersencb57d552001-06-28 07:25:16 +00001817static int
1818cdcmd(argc, argv)
1819 int argc;
1820 char **argv;
1821{
1822 const char *dest;
1823 const char *path;
1824 char *p;
1825 struct stat statb;
1826 int print = 0;
1827
1828 nextopt(nullstr);
1829 if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME")) == NULL)
1830 error("HOME not set");
1831 if (*dest == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00001832 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001833 if (dest[0] == '-' && dest[1] == '\0') {
1834 dest = bltinlookup("OLDPWD");
1835 if (!dest || !*dest) {
1836 dest = curdir;
1837 }
1838 print = 1;
1839 if (dest)
Eric Andersen2870d962001-07-02 17:27:21 +00001840 print = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00001841 else
Eric Andersen2870d962001-07-02 17:27:21 +00001842 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001843 }
1844 if (*dest == '/' || (path = bltinlookup("CDPATH")) == NULL)
1845 path = nullstr;
1846 while ((p = padvance(&path, dest)) != NULL) {
1847 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
1848 if (!print) {
1849 /*
1850 * XXX - rethink
1851 */
1852 if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
1853 p += 2;
1854 print = strcmp(p, dest);
1855 }
1856 if (docd(p, print) >= 0)
1857 return 0;
1858
1859 }
1860 }
1861 error("can't cd to %s", dest);
1862 /* NOTREACHED */
1863}
1864
1865
1866/*
1867 * Actually do the chdir. In an interactive shell, print the
1868 * directory name if "print" is nonzero.
1869 */
1870
1871static int
1872docd(dest, print)
1873 char *dest;
1874 int print;
1875{
1876 char *p;
1877 char *q;
1878 char *component;
1879 struct stat statb;
1880 int first;
1881 int badstat;
1882
1883 TRACE(("docd(\"%s\", %d) called\n", dest, print));
1884
1885 /*
1886 * Check each component of the path. If we find a symlink or
1887 * something we can't stat, clear curdir to force a getcwd()
1888 * next time we get the value of the current directory.
1889 */
1890 badstat = 0;
1891 cdcomppath = sstrdup(dest);
1892 STARTSTACKSTR(p);
1893 if (*dest == '/') {
1894 STPUTC('/', p);
1895 cdcomppath++;
1896 }
1897 first = 1;
1898 while ((q = getcomponent()) != NULL) {
1899 if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0'))
1900 continue;
1901 if (! first)
1902 STPUTC('/', p);
1903 first = 0;
1904 component = q;
1905 while (*q)
1906 STPUTC(*q++, p);
1907 if (equal(component, ".."))
1908 continue;
1909 STACKSTRNUL(p);
1910 if ((lstat(stackblock(), &statb) < 0)
1911 || (S_ISLNK(statb.st_mode))) {
1912 /* print = 1; */
1913 badstat = 1;
1914 break;
1915 }
1916 }
1917
1918 INTOFF;
1919 if (chdir(dest) < 0) {
1920 INTON;
1921 return -1;
1922 }
1923 updatepwd(badstat ? NULL : dest);
1924 INTON;
1925 if (print && iflag)
Eric Andersen62483552001-07-10 06:09:16 +00001926 printf(snlfmt, curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00001927 return 0;
1928}
1929
1930
1931/*
1932 * Get the next component of the path name pointed to by cdcomppath.
1933 * This routine overwrites the string pointed to by cdcomppath.
1934 */
1935
1936static char *
1937getcomponent() {
1938 char *p;
1939 char *start;
1940
1941 if ((p = cdcomppath) == NULL)
1942 return NULL;
1943 start = cdcomppath;
1944 while (*p != '/' && *p != '\0')
1945 p++;
1946 if (*p == '\0') {
1947 cdcomppath = NULL;
1948 } else {
1949 *p++ = '\0';
1950 cdcomppath = p;
1951 }
1952 return start;
1953}
1954
1955
1956
1957/*
1958 * Update curdir (the name of the current directory) in response to a
1959 * cd command. We also call hashcd to let the routines in exec.c know
1960 * that the current directory has changed.
1961 */
1962
Eric Andersen2870d962001-07-02 17:27:21 +00001963static void hashcd (void);
1964
Eric Andersencb57d552001-06-28 07:25:16 +00001965static void
Eric Andersen2870d962001-07-02 17:27:21 +00001966updatepwd(const char *dir)
1967{
Eric Andersencb57d552001-06-28 07:25:16 +00001968 char *new;
1969 char *p;
1970 size_t len;
1971
Eric Andersen2870d962001-07-02 17:27:21 +00001972 hashcd(); /* update command hash table */
Eric Andersencb57d552001-06-28 07:25:16 +00001973
1974 /*
1975 * If our argument is NULL, we don't know the current directory
1976 * any more because we traversed a symbolic link or something
1977 * we couldn't stat().
1978 */
1979 if (dir == NULL || curdir == nullstr) {
1980 setpwd(0, 1);
1981 return;
1982 }
1983 len = strlen(dir);
1984 cdcomppath = sstrdup(dir);
1985 STARTSTACKSTR(new);
1986 if (*dir != '/') {
1987 p = curdir;
1988 while (*p)
1989 STPUTC(*p++, new);
1990 if (p[-1] == '/')
1991 STUNPUTC(new);
1992 }
1993 while ((p = getcomponent()) != NULL) {
1994 if (equal(p, "..")) {
1995 while (new > stackblock() && (STUNPUTC(new), *new) != '/');
1996 } else if (*p != '\0' && ! equal(p, ".")) {
1997 STPUTC('/', new);
1998 while (*p)
1999 STPUTC(*p++, new);
2000 }
2001 }
2002 if (new == stackblock())
2003 STPUTC('/', new);
2004 STACKSTRNUL(new);
2005 setpwd(stackblock(), 1);
2006}
2007
2008
Eric Andersen3102ac42001-07-06 04:26:23 +00002009#ifndef BB_PWD
Eric Andersencb57d552001-06-28 07:25:16 +00002010static int
2011pwdcmd(argc, argv)
2012 int argc;
2013 char **argv;
2014{
Eric Andersen62483552001-07-10 06:09:16 +00002015 printf(snlfmt, curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00002016 return 0;
2017}
Eric Andersen2870d962001-07-02 17:27:21 +00002018#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002019
2020/*
2021 * Find out what the current directory is. If we already know the current
2022 * directory, this routine returns immediately.
2023 */
2024static void
Eric Andersen2870d962001-07-02 17:27:21 +00002025getpwd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00002026{
Eric Andersen2870d962001-07-02 17:27:21 +00002027 curdir = xgetcwd(0);
2028 if(curdir==0)
2029 curdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00002030}
2031
2032static void
2033setpwd(const char *val, int setold)
2034{
2035 if (setold) {
2036 setvar("OLDPWD", curdir, VEXPORT);
2037 }
2038 INTOFF;
2039 if (curdir != nullstr) {
2040 free(curdir);
2041 curdir = nullstr;
2042 }
2043 if (!val) {
2044 getpwd();
2045 } else {
2046 curdir = savestr(val);
2047 }
2048 INTON;
2049 setvar("PWD", curdir, VEXPORT);
2050}
2051
Eric Andersencb57d552001-06-28 07:25:16 +00002052/*
2053 * Errors and exceptions.
2054 */
2055
2056/*
2057 * Code to handle exceptions in C.
2058 */
2059
Eric Andersen2870d962001-07-02 17:27:21 +00002060/*
2061 * We enclose jmp_buf in a structure so that we can declare pointers to
2062 * jump locations. The global variable handler contains the location to
2063 * jump to when an exception occurs, and the global variable exception
2064 * contains a code identifying the exeception. To implement nested
2065 * exception handlers, the user should save the value of handler on entry
2066 * to an inner scope, set handler to point to a jmploc structure for the
2067 * inner scope, and restore handler on exit from the scope.
2068 */
2069
2070struct jmploc {
2071 jmp_buf loc;
2072};
2073
2074/* exceptions */
2075#define EXINT 0 /* SIGINT received */
2076#define EXERROR 1 /* a generic error */
2077#define EXSHELLPROC 2 /* execute a shell procedure */
2078#define EXEXEC 3 /* command execution failed */
2079
2080static struct jmploc *handler;
Eric Andersencb57d552001-06-28 07:25:16 +00002081static int exception;
Eric Andersencb57d552001-06-28 07:25:16 +00002082
Eric Andersen2870d962001-07-02 17:27:21 +00002083static void exverror (int, const char *, va_list)
Eric Andersencb57d552001-06-28 07:25:16 +00002084 __attribute__((__noreturn__));
2085
2086/*
2087 * Called to raise an exception. Since C doesn't include exceptions, we
2088 * just do a longjmp to the exception handler. The type of exception is
2089 * stored in the global variable "exception".
2090 */
2091
Eric Andersen2870d962001-07-02 17:27:21 +00002092static void exraise (int) __attribute__((__noreturn__));
2093
Eric Andersencb57d552001-06-28 07:25:16 +00002094static void
Eric Andersen2870d962001-07-02 17:27:21 +00002095exraise(int e)
Eric Andersencb57d552001-06-28 07:25:16 +00002096{
2097#ifdef DEBUG
2098 if (handler == NULL)
2099 abort();
2100#endif
Eric Andersen62483552001-07-10 06:09:16 +00002101 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00002102 exception = e;
2103 longjmp(handler->loc, 1);
2104}
2105
2106
2107/*
2108 * Called from trap.c when a SIGINT is received. (If the user specifies
2109 * that SIGINT is to be trapped or ignored using the trap builtin, then
2110 * this routine is not called.) Suppressint is nonzero when interrupts
2111 * are held using the INTOFF macro. The call to _exit is necessary because
2112 * there is a short period after a fork before the signal handlers are
2113 * set to the appropriate value for the child. (The test for iflag is
2114 * just defensive programming.)
2115 */
2116
2117static void
Eric Andersen2870d962001-07-02 17:27:21 +00002118onint(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00002119 sigset_t mysigset;
2120
2121 if (suppressint) {
2122 intpending++;
2123 return;
2124 }
2125 intpending = 0;
2126 sigemptyset(&mysigset);
2127 sigprocmask(SIG_SETMASK, &mysigset, NULL);
2128 if (rootshell && iflag)
2129 exraise(EXINT);
2130 else {
2131 signal(SIGINT, SIG_DFL);
2132 raise(SIGINT);
2133 }
2134 /* NOTREACHED */
2135}
2136
2137
Eric Andersen2870d962001-07-02 17:27:21 +00002138static char *commandname; /* currently executing command */
2139
Eric Andersencb57d552001-06-28 07:25:16 +00002140/*
2141 * Exverror is called to raise the error exception. If the first argument
2142 * is not NULL then error prints an error message using printf style
2143 * formatting. It then raises the error exception.
2144 */
2145static void
Eric Andersen2870d962001-07-02 17:27:21 +00002146exverror(int cond, const char *msg, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00002147{
2148 CLEAR_PENDING_INT;
2149 INTOFF;
2150
2151#ifdef DEBUG
2152 if (msg)
2153 TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
2154 else
2155 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2156#endif
2157 if (msg) {
2158 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +00002159 out2fmt("%s: ", commandname);
2160 vfprintf(stderr, msg, ap);
2161 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00002162 }
Eric Andersencb57d552001-06-28 07:25:16 +00002163 exraise(cond);
2164 /* NOTREACHED */
2165}
2166
2167
Eric Andersen74bcd162001-07-30 21:41:37 +00002168static void
Eric Andersencb57d552001-06-28 07:25:16 +00002169error(const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002170{
Eric Andersencb57d552001-06-28 07:25:16 +00002171 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002172 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002173 exverror(EXERROR, msg, ap);
2174 /* NOTREACHED */
2175 va_end(ap);
2176}
2177
2178
Eric Andersencb57d552001-06-28 07:25:16 +00002179static void
2180exerror(int cond, const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002181{
Eric Andersencb57d552001-06-28 07:25:16 +00002182 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002183 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002184 exverror(cond, msg, ap);
2185 /* NOTREACHED */
2186 va_end(ap);
2187}
2188
2189
2190
2191/*
2192 * Table of error messages.
2193 */
2194
2195struct errname {
Eric Andersen2870d962001-07-02 17:27:21 +00002196 short errcode; /* error number */
Eric Andersen62483552001-07-10 06:09:16 +00002197 char action; /* operation which encountered the error */
Eric Andersencb57d552001-06-28 07:25:16 +00002198};
2199
Eric Andersen2870d962001-07-02 17:27:21 +00002200/*
2201 * Types of operations (passed to the errmsg routine).
2202 */
2203
2204#define E_OPEN 01 /* opening a file */
2205#define E_CREAT 02 /* creating a file */
2206#define E_EXEC 04 /* executing a program */
Eric Andersencb57d552001-06-28 07:25:16 +00002207
2208#define ALL (E_OPEN|E_CREAT|E_EXEC)
2209
2210static const struct errname errormsg[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00002211 { EINTR, ALL },
2212 { EACCES, ALL },
2213 { EIO, ALL },
2214 { ENOENT, E_OPEN },
2215 { ENOENT, E_CREAT },
2216 { ENOENT, E_EXEC },
2217 { ENOTDIR, E_OPEN },
2218 { ENOTDIR, E_CREAT },
2219 { ENOTDIR, E_EXEC },
2220 { EISDIR, ALL },
2221 { EEXIST, E_CREAT },
2222#ifdef EMFILE
2223 { EMFILE, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002224#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002225 { ENFILE, ALL },
2226 { ENOSPC, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002227#ifdef EDQUOT
Eric Andersen2870d962001-07-02 17:27:21 +00002228 { EDQUOT, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002229#endif
2230#ifdef ENOSR
Eric Andersen2870d962001-07-02 17:27:21 +00002231 { ENOSR, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002232#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002233 { ENXIO, ALL },
2234 { EROFS, ALL },
2235 { ETXTBSY, ALL },
2236#ifdef EAGAIN
2237 { EAGAIN, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002238#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002239 { ENOMEM, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002240#ifdef ENOLINK
Eric Andersen2870d962001-07-02 17:27:21 +00002241 { ENOLINK, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002242#endif
2243#ifdef EMULTIHOP
Eric Andersen2870d962001-07-02 17:27:21 +00002244 { EMULTIHOP, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002245#endif
2246#ifdef ECOMM
Eric Andersen2870d962001-07-02 17:27:21 +00002247 { ECOMM, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002248#endif
2249#ifdef ESTALE
Eric Andersen2870d962001-07-02 17:27:21 +00002250 { ESTALE, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002251#endif
2252#ifdef ETIMEDOUT
Eric Andersen2870d962001-07-02 17:27:21 +00002253 { ETIMEDOUT, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002254#endif
2255#ifdef ELOOP
Eric Andersen2870d962001-07-02 17:27:21 +00002256 { ELOOP, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002257#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002258 { E2BIG, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002259#ifdef ELIBACC
Eric Andersen2870d962001-07-02 17:27:21 +00002260 { ELIBACC, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002261#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002262};
2263
Eric Andersen2870d962001-07-02 17:27:21 +00002264#define ERRNAME_SIZE (sizeof(errormsg)/sizeof(struct errname))
Eric Andersencb57d552001-06-28 07:25:16 +00002265
2266/*
2267 * Return a string describing an error. The returned string may be a
2268 * pointer to a static buffer that will be overwritten on the next call.
2269 * Action describes the operation that got the error.
2270 */
2271
2272static const char *
Eric Andersen2870d962001-07-02 17:27:21 +00002273errmsg(int e, int action)
Eric Andersencb57d552001-06-28 07:25:16 +00002274{
2275 struct errname const *ep;
2276 static char buf[12];
2277
Eric Andersen2870d962001-07-02 17:27:21 +00002278 for (ep = errormsg ; ep < errormsg+ERRNAME_SIZE; ep++) {
Eric Andersencb57d552001-06-28 07:25:16 +00002279 if (ep->errcode == e && (ep->action & action) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00002280 return strerror(e);
Eric Andersencb57d552001-06-28 07:25:16 +00002281 }
Eric Andersen2870d962001-07-02 17:27:21 +00002282
Eric Andersen3102ac42001-07-06 04:26:23 +00002283 snprintf(buf, sizeof buf, "error %d", e);
Eric Andersencb57d552001-06-28 07:25:16 +00002284 return buf;
2285}
2286
2287
Eric Andersen3102ac42001-07-06 04:26:23 +00002288#ifdef ASH_OPTIMIZE_FOR_SIZE
Eric Andersencb57d552001-06-28 07:25:16 +00002289static void
2290__inton() {
2291 if (--suppressint == 0 && intpending) {
2292 onint();
2293 }
2294}
Eric Andersen3102ac42001-07-06 04:26:23 +00002295static void forceinton (void) {
2296 suppressint = 0;
2297 if (intpending)
2298 onint();
2299}
Eric Andersencb57d552001-06-28 07:25:16 +00002300#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002301
2302/* flags in argument to evaltree */
Eric Andersen2870d962001-07-02 17:27:21 +00002303#define EV_EXIT 01 /* exit after evaluating tree */
2304#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2305#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00002306
Eric Andersen2870d962001-07-02 17:27:21 +00002307static int evalskip; /* set if we are skipping commands */
2308static int skipcount; /* number of levels to skip */
2309static int loopnest; /* current loop nesting level */
2310static int funcnest; /* depth of function calls */
Eric Andersencb57d552001-06-28 07:25:16 +00002311
2312
Eric Andersen2870d962001-07-02 17:27:21 +00002313static struct strlist *cmdenviron; /* environment for builtin command */
2314static int exitstatus; /* exit status of last command */
2315static int oexitstatus; /* saved exit status */
Eric Andersencb57d552001-06-28 07:25:16 +00002316
Eric Andersen62483552001-07-10 06:09:16 +00002317static void evalsubshell (const union node *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00002318static void expredir (union node *);
Eric Andersen2870d962001-07-02 17:27:21 +00002319static void prehash (union node *);
2320static void eprintlist (struct strlist *);
Eric Andersencb57d552001-06-28 07:25:16 +00002321
Eric Andersen2870d962001-07-02 17:27:21 +00002322static union node *parsecmd(int);
Eric Andersencb57d552001-06-28 07:25:16 +00002323/*
2324 * Called to reset things after an exception.
2325 */
2326
Eric Andersencb57d552001-06-28 07:25:16 +00002327/*
2328 * The eval commmand.
2329 */
Eric Andersen2870d962001-07-02 17:27:21 +00002330static void evalstring (char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00002331
2332static int
2333evalcmd(argc, argv)
2334 int argc;
2335 char **argv;
2336{
Eric Andersen2870d962001-07-02 17:27:21 +00002337 char *p;
2338 char *concat;
2339 char **ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002340
Eric Andersen2870d962001-07-02 17:27:21 +00002341 if (argc > 1) {
2342 p = argv[1];
2343 if (argc > 2) {
2344 STARTSTACKSTR(concat);
2345 ap = argv + 2;
2346 for (;;) {
2347 while (*p)
2348 STPUTC(*p++, concat);
2349 if ((p = *ap++) == NULL)
2350 break;
2351 STPUTC(' ', concat);
2352 }
2353 STPUTC('\0', concat);
2354 p = grabstackstr(concat);
2355 }
2356 evalstring(p, EV_TESTED);
2357 }
2358 return exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002359}
2360
Eric Andersencb57d552001-06-28 07:25:16 +00002361/*
2362 * Execute a command or commands contained in a string.
2363 */
2364
Eric Andersen2870d962001-07-02 17:27:21 +00002365static void evaltree (union node *, int);
2366static void setinputstring (char *);
2367static void popfile (void);
2368static void setstackmark(struct stackmark *mark);
2369static void popstackmark(struct stackmark *mark);
2370
2371
Eric Andersencb57d552001-06-28 07:25:16 +00002372static void
Eric Andersen2870d962001-07-02 17:27:21 +00002373evalstring(char *s, int flag)
2374{
Eric Andersencb57d552001-06-28 07:25:16 +00002375 union node *n;
2376 struct stackmark smark;
2377
2378 setstackmark(&smark);
2379 setinputstring(s);
2380 while ((n = parsecmd(0)) != NEOF) {
2381 evaltree(n, flag);
2382 popstackmark(&smark);
2383 }
2384 popfile();
2385 popstackmark(&smark);
2386}
2387
Eric Andersen2870d962001-07-02 17:27:21 +00002388static struct builtincmd *find_builtin (const char *);
Eric Andersen62483552001-07-10 06:09:16 +00002389static void expandarg (union node *, struct arglist *, int);
2390static void calcsize (const union node *);
2391static union node *copynode (const union node *);
2392
2393/*
2394 * Make a copy of a parse tree.
2395 */
2396
2397static int funcblocksize; /* size of structures in function */
2398static int funcstringsize; /* size of strings in node */
2399static pointer funcblock; /* block to allocate function from */
2400static char *funcstring; /* block to allocate strings from */
2401
2402
2403static inline union node *
2404copyfunc(union node *n)
2405{
2406 if (n == NULL)
2407 return NULL;
2408 funcblocksize = 0;
2409 funcstringsize = 0;
2410 calcsize(n);
2411 funcblock = ckmalloc(funcblocksize + funcstringsize);
2412 funcstring = (char *) funcblock + funcblocksize;
2413 return copynode(n);
2414}
2415
2416/*
2417 * Free a parse tree.
2418 */
Eric Andersencb57d552001-06-28 07:25:16 +00002419
2420static void
Eric Andersen62483552001-07-10 06:09:16 +00002421freefunc(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00002422{
Eric Andersen62483552001-07-10 06:09:16 +00002423 if (n)
2424 ckfree(n);
Eric Andersencb57d552001-06-28 07:25:16 +00002425}
2426
2427
Eric Andersen62483552001-07-10 06:09:16 +00002428/*
2429 * Add a new command entry, replacing any existing command entry for
2430 * the same name.
2431 */
2432
2433static inline void
2434addcmdentry(char *name, struct cmdentry *entry)
2435{
2436 struct tblentry *cmdp;
2437
2438 INTOFF;
2439 cmdp = cmdlookup(name, 1);
2440 if (cmdp->cmdtype == CMDFUNCTION) {
2441 freefunc(cmdp->param.func);
2442 }
2443 cmdp->cmdtype = entry->cmdtype;
2444 cmdp->param = entry->u;
2445 INTON;
2446}
2447
2448static inline void
2449evalloop(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002450{
2451 int status;
2452
2453 loopnest++;
2454 status = 0;
2455 for (;;) {
2456 evaltree(n->nbinary.ch1, EV_TESTED);
2457 if (evalskip) {
Eric Andersen2870d962001-07-02 17:27:21 +00002458skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002459 evalskip = 0;
2460 continue;
2461 }
2462 if (evalskip == SKIPBREAK && --skipcount <= 0)
2463 evalskip = 0;
2464 break;
2465 }
2466 if (n->type == NWHILE) {
2467 if (exitstatus != 0)
2468 break;
2469 } else {
2470 if (exitstatus == 0)
2471 break;
2472 }
2473 evaltree(n->nbinary.ch2, flags & EV_TESTED);
2474 status = exitstatus;
2475 if (evalskip)
2476 goto skipping;
2477 }
2478 loopnest--;
2479 exitstatus = status;
2480}
2481
Eric Andersencb57d552001-06-28 07:25:16 +00002482static void
Eric Andersen62483552001-07-10 06:09:16 +00002483evalfor(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002484{
2485 struct arglist arglist;
2486 union node *argp;
2487 struct strlist *sp;
2488 struct stackmark smark;
2489
2490 setstackmark(&smark);
2491 arglist.lastp = &arglist.list;
2492 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2493 oexitstatus = exitstatus;
2494 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2495 if (evalskip)
2496 goto out;
2497 }
2498 *arglist.lastp = NULL;
2499
2500 exitstatus = 0;
2501 loopnest++;
2502 for (sp = arglist.list ; sp ; sp = sp->next) {
2503 setvar(n->nfor.var, sp->text, 0);
2504 evaltree(n->nfor.body, flags & EV_TESTED);
2505 if (evalskip) {
2506 if (evalskip == SKIPCONT && --skipcount <= 0) {
2507 evalskip = 0;
2508 continue;
2509 }
2510 if (evalskip == SKIPBREAK && --skipcount <= 0)
2511 evalskip = 0;
2512 break;
2513 }
2514 }
2515 loopnest--;
2516out:
2517 popstackmark(&smark);
2518}
2519
Eric Andersen62483552001-07-10 06:09:16 +00002520static inline void
2521evalcase(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002522{
2523 union node *cp;
2524 union node *patp;
2525 struct arglist arglist;
2526 struct stackmark smark;
2527
2528 setstackmark(&smark);
2529 arglist.lastp = &arglist.list;
2530 oexitstatus = exitstatus;
2531 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2532 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2533 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2534 if (casematch(patp, arglist.list->text)) {
2535 if (evalskip == 0) {
2536 evaltree(cp->nclist.body, flags);
2537 }
2538 goto out;
2539 }
2540 }
2541 }
2542out:
2543 popstackmark(&smark);
2544}
2545
Eric Andersencb57d552001-06-28 07:25:16 +00002546/*
Eric Andersencb57d552001-06-28 07:25:16 +00002547 * Evaluate a pipeline. All the processes in the pipeline are children
2548 * of the process creating the pipeline. (This differs from some versions
2549 * of the shell, which make the last process in a pipeline the parent
2550 * of all the rest.)
2551 */
2552
Eric Andersen62483552001-07-10 06:09:16 +00002553static inline void
Eric Andersencb57d552001-06-28 07:25:16 +00002554evalpipe(n)
2555 union node *n;
2556{
2557 struct job *jp;
2558 struct nodelist *lp;
2559 int pipelen;
2560 int prevfd;
2561 int pip[2];
2562
2563 TRACE(("evalpipe(0x%lx) called\n", (long)n));
2564 pipelen = 0;
2565 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
2566 pipelen++;
2567 INTOFF;
2568 jp = makejob(n, pipelen);
2569 prevfd = -1;
2570 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
2571 prehash(lp->n);
2572 pip[1] = -1;
2573 if (lp->next) {
2574 if (pipe(pip) < 0) {
2575 close(prevfd);
2576 error("Pipe call failed");
2577 }
2578 }
2579 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
2580 INTON;
2581 if (prevfd > 0) {
2582 close(0);
2583 dup_as_newfd(prevfd, 0);
2584 close(prevfd);
2585 if (pip[0] == 0) {
2586 pip[0] = -1;
2587 }
2588 }
2589 if (pip[1] >= 0) {
2590 if (pip[0] >= 0) {
2591 close(pip[0]);
2592 }
2593 if (pip[1] != 1) {
2594 close(1);
2595 dup_as_newfd(pip[1], 1);
2596 close(pip[1]);
2597 }
2598 }
2599 evaltree(lp->n, EV_EXIT);
2600 }
2601 if (prevfd >= 0)
2602 close(prevfd);
2603 prevfd = pip[0];
2604 close(pip[1]);
2605 }
2606 INTON;
2607 if (n->npipe.backgnd == 0) {
2608 INTOFF;
2609 exitstatus = waitforjob(jp);
2610 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
2611 INTON;
2612 }
2613}
2614
Eric Andersen2870d962001-07-02 17:27:21 +00002615static void find_command (const char *, struct cmdentry *, int, const char *);
2616
2617static int
2618isassignment(const char *word) {
2619 if (!is_name(*word)) {
2620 return 0;
2621 }
2622 do {
2623 word++;
2624 } while (is_in_name(*word));
2625 return *word == '=';
2626}
2627
Eric Andersen62483552001-07-10 06:09:16 +00002628
Eric Andersencb57d552001-06-28 07:25:16 +00002629static void
Eric Andersen3102ac42001-07-06 04:26:23 +00002630evalcommand(union node *cmd, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002631{
2632 struct stackmark smark;
2633 union node *argp;
2634 struct arglist arglist;
2635 struct arglist varlist;
2636 char **argv;
2637 int argc;
2638 char **envp;
2639 struct strlist *sp;
2640 int mode;
Eric Andersencb57d552001-06-28 07:25:16 +00002641 struct cmdentry cmdentry;
2642 struct job *jp;
2643 char *volatile savecmdname;
2644 volatile struct shparam saveparam;
2645 struct localvar *volatile savelocalvars;
2646 volatile int e;
2647 char *lastarg;
2648 const char *path;
2649 const struct builtincmd *firstbltin;
2650 struct jmploc *volatile savehandler;
2651 struct jmploc jmploc;
2652#if __GNUC__
2653 /* Avoid longjmp clobbering */
2654 (void) &argv;
2655 (void) &argc;
2656 (void) &lastarg;
2657 (void) &flags;
2658#endif
2659
2660 /* First expand the arguments. */
2661 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
2662 setstackmark(&smark);
2663 arglist.lastp = &arglist.list;
2664 varlist.lastp = &varlist.list;
2665 arglist.list = 0;
2666 oexitstatus = exitstatus;
2667 exitstatus = 0;
2668 path = pathval();
2669 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
2670 expandarg(argp, &varlist, EXP_VARTILDE);
2671 }
2672 for (
2673 argp = cmd->ncmd.args; argp && !arglist.list;
2674 argp = argp->narg.next
2675 ) {
2676 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2677 }
2678 if (argp) {
2679 struct builtincmd *bcmd;
Eric Andersen62483552001-07-10 06:09:16 +00002680 int pseudovarflag;
Eric Andersencb57d552001-06-28 07:25:16 +00002681 bcmd = find_builtin(arglist.list->text);
Eric Andersen2870d962001-07-02 17:27:21 +00002682 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00002683 for (; argp; argp = argp->narg.next) {
2684 if (pseudovarflag && isassignment(argp->narg.text)) {
2685 expandarg(argp, &arglist, EXP_VARTILDE);
2686 continue;
2687 }
2688 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2689 }
2690 }
2691 *arglist.lastp = NULL;
2692 *varlist.lastp = NULL;
2693 expredir(cmd->ncmd.redirect);
2694 argc = 0;
2695 for (sp = arglist.list ; sp ; sp = sp->next)
2696 argc++;
2697 argv = stalloc(sizeof (char *) * (argc + 1));
2698
2699 for (sp = arglist.list ; sp ; sp = sp->next) {
2700 TRACE(("evalcommand arg: %s\n", sp->text));
2701 *argv++ = sp->text;
2702 }
2703 *argv = NULL;
2704 lastarg = NULL;
2705 if (iflag && funcnest == 0 && argc > 0)
2706 lastarg = argv[-1];
2707 argv -= argc;
2708
2709 /* Print the command if xflag is set. */
2710 if (xflag) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002711 out2c('+');
Eric Andersencb57d552001-06-28 07:25:16 +00002712 eprintlist(varlist.list);
2713 eprintlist(arglist.list);
Eric Andersen3102ac42001-07-06 04:26:23 +00002714 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00002715 }
2716
2717 /* Now locate the command. */
2718 if (argc == 0) {
2719 cmdentry.cmdtype = CMDBUILTIN;
2720 firstbltin = cmdentry.u.cmd = BLTINCMD;
2721 } else {
2722 const char *oldpath;
2723 int findflag = DO_ERR;
2724 int oldfindflag;
2725
2726 /*
2727 * Modify the command lookup path, if a PATH= assignment
2728 * is present
2729 */
2730 for (sp = varlist.list ; sp ; sp = sp->next)
2731 if (varequal(sp->text, defpathvar)) {
2732 path = sp->text + 5;
2733 findflag |= DO_BRUTE;
2734 }
2735 oldpath = path;
2736 oldfindflag = findflag;
2737 firstbltin = 0;
2738 for(;;) {
2739 find_command(argv[0], &cmdentry, findflag, path);
Eric Andersen2870d962001-07-02 17:27:21 +00002740 if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */
Eric Andersencb57d552001-06-28 07:25:16 +00002741 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002742 goto out;
2743 }
2744 /* implement bltin and command here */
2745 if (cmdentry.cmdtype != CMDBUILTIN) {
2746 break;
2747 }
2748 if (!firstbltin) {
2749 firstbltin = cmdentry.u.cmd;
2750 }
2751 if (cmdentry.u.cmd == BLTINCMD) {
2752 for(;;) {
2753 struct builtincmd *bcmd;
2754
2755 argv++;
2756 if (--argc == 0)
2757 goto found;
2758 if (!(bcmd = find_builtin(*argv))) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002759 out2fmt("%s: not found\n", *argv);
Eric Andersencb57d552001-06-28 07:25:16 +00002760 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002761 goto out;
2762 }
2763 cmdentry.u.cmd = bcmd;
2764 if (bcmd != BLTINCMD)
2765 break;
2766 }
2767 }
Eric Andersen2870d962001-07-02 17:27:21 +00002768 if (cmdentry.u.cmd == find_builtin("command")) {
Eric Andersencb57d552001-06-28 07:25:16 +00002769 argv++;
2770 if (--argc == 0) {
2771 goto found;
2772 }
2773 if (*argv[0] == '-') {
2774 if (!equal(argv[0], "-p")) {
2775 argv--;
2776 argc++;
2777 break;
2778 }
2779 argv++;
2780 if (--argc == 0) {
2781 goto found;
2782 }
2783 path = defpath;
2784 findflag |= DO_BRUTE;
2785 } else {
2786 path = oldpath;
2787 findflag = oldfindflag;
2788 }
2789 findflag |= DO_NOFUN;
2790 continue;
2791 }
2792found:
2793 break;
2794 }
2795 }
2796
2797 /* Fork off a child process if necessary. */
2798 if (cmd->ncmd.backgnd
2799 || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00002800 ) {
2801 jp = makejob(cmd, 1);
2802 mode = cmd->ncmd.backgnd;
Eric Andersencb57d552001-06-28 07:25:16 +00002803 if (forkshell(jp, cmd, mode) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00002804 goto parent; /* at end of routine */
Eric Andersencb57d552001-06-28 07:25:16 +00002805 flags |= EV_EXIT;
2806 }
2807
2808 /* This is the child process if a fork occurred. */
2809 /* Execute the command. */
2810 if (cmdentry.cmdtype == CMDFUNCTION) {
2811#ifdef DEBUG
2812 trputs("Shell function: "); trargs(argv);
2813#endif
2814 exitstatus = oexitstatus;
2815 redirect(cmd->ncmd.redirect, REDIR_PUSH);
2816 saveparam = shellparam;
2817 shellparam.malloc = 0;
2818 shellparam.nparam = argc - 1;
2819 shellparam.p = argv + 1;
2820 INTOFF;
2821 savelocalvars = localvars;
2822 localvars = NULL;
2823 INTON;
2824 if (setjmp(jmploc.loc)) {
2825 if (exception == EXSHELLPROC) {
2826 freeparam((volatile struct shparam *)
2827 &saveparam);
2828 } else {
2829 saveparam.optind = shellparam.optind;
2830 saveparam.optoff = shellparam.optoff;
2831 freeparam(&shellparam);
2832 shellparam = saveparam;
2833 }
2834 poplocalvars();
2835 localvars = savelocalvars;
2836 handler = savehandler;
2837 longjmp(handler->loc, 1);
2838 }
2839 savehandler = handler;
2840 handler = &jmploc;
2841 for (sp = varlist.list ; sp ; sp = sp->next)
2842 mklocal(sp->text);
2843 funcnest++;
2844 evaltree(cmdentry.u.func, flags & EV_TESTED);
2845 funcnest--;
2846 INTOFF;
2847 poplocalvars();
2848 localvars = savelocalvars;
2849 saveparam.optind = shellparam.optind;
2850 saveparam.optoff = shellparam.optoff;
2851 freeparam(&shellparam);
2852 shellparam = saveparam;
2853 handler = savehandler;
2854 popredir();
2855 INTON;
2856 if (evalskip == SKIPFUNC) {
2857 evalskip = 0;
2858 skipcount = 0;
2859 }
2860 if (flags & EV_EXIT)
2861 exitshell(exitstatus);
2862 } else if (cmdentry.cmdtype == CMDBUILTIN) {
2863#ifdef DEBUG
2864 trputs("builtin command: "); trargs(argv);
2865#endif
2866 mode = (cmdentry.u.cmd == EXECCMD)? 0 : REDIR_PUSH;
Eric Andersencb57d552001-06-28 07:25:16 +00002867 redirect(cmd->ncmd.redirect, mode);
2868 savecmdname = commandname;
Eric Andersen2870d962001-07-02 17:27:21 +00002869 if (IS_BUILTIN_SPECIAL(firstbltin)) {
Eric Andersencb57d552001-06-28 07:25:16 +00002870 listsetvar(varlist.list);
2871 } else {
2872 cmdenviron = varlist.list;
2873 }
2874 e = -1;
2875 if (setjmp(jmploc.loc)) {
2876 e = exception;
2877 exitstatus = (e == EXINT)? SIGINT+128 : 2;
2878 goto cmddone;
2879 }
2880 savehandler = handler;
2881 handler = &jmploc;
2882 commandname = argv[0];
2883 argptr = argv + 1;
Eric Andersen2870d962001-07-02 17:27:21 +00002884 optptr = NULL; /* initialize nextopt */
Eric Andersencb57d552001-06-28 07:25:16 +00002885 exitstatus = (*cmdentry.u.cmd->builtinfunc)(argc, argv);
2886 flushall();
2887cmddone:
Eric Andersencb57d552001-06-28 07:25:16 +00002888 cmdenviron = NULL;
2889 if (e != EXSHELLPROC) {
2890 commandname = savecmdname;
2891 if (flags & EV_EXIT)
2892 exitshell(exitstatus);
2893 }
2894 handler = savehandler;
2895 if (e != -1) {
2896 if ((e != EXERROR && e != EXEXEC)
2897 || cmdentry.u.cmd == BLTINCMD
2898 || cmdentry.u.cmd == DOTCMD
2899 || cmdentry.u.cmd == EVALCMD
2900 || cmdentry.u.cmd == EXECCMD)
2901 exraise(e);
2902 FORCEINTON;
2903 }
2904 if (cmdentry.u.cmd != EXECCMD)
2905 popredir();
Eric Andersencb57d552001-06-28 07:25:16 +00002906 } else {
2907#ifdef DEBUG
2908 trputs("normal command: "); trargs(argv);
2909#endif
2910 redirect(cmd->ncmd.redirect, 0);
2911 clearredir();
2912 for (sp = varlist.list ; sp ; sp = sp->next)
2913 setvareq(sp->text, VEXPORT|VSTACK);
2914 envp = environment();
2915 shellexec(argv, envp, path, cmdentry.u.index);
2916 }
2917 goto out;
2918
Eric Andersen2870d962001-07-02 17:27:21 +00002919parent: /* parent process gets here (if we forked) */
2920 if (mode == 0) { /* argument to fork */
Eric Andersencb57d552001-06-28 07:25:16 +00002921 INTOFF;
2922 exitstatus = waitforjob(jp);
2923 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00002924 }
2925
2926out:
2927 if (lastarg)
2928 setvar("_", lastarg, 0);
2929 popstackmark(&smark);
2930}
2931
Eric Andersen62483552001-07-10 06:09:16 +00002932/*
2933 * Evaluate a parse tree. The value is left in the global variable
2934 * exitstatus.
2935 */
2936static void
2937evaltree(n, flags)
2938 union node *n;
2939 int flags;
2940{
2941 int checkexit = 0;
2942 if (n == NULL) {
2943 TRACE(("evaltree(NULL) called\n"));
2944 goto out;
2945 }
2946 TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
2947 switch (n->type) {
2948 case NSEMI:
2949 evaltree(n->nbinary.ch1, flags & EV_TESTED);
2950 if (evalskip)
2951 goto out;
2952 evaltree(n->nbinary.ch2, flags);
2953 break;
2954 case NAND:
2955 evaltree(n->nbinary.ch1, EV_TESTED);
2956 if (evalskip || exitstatus != 0)
2957 goto out;
2958 evaltree(n->nbinary.ch2, flags);
2959 break;
2960 case NOR:
2961 evaltree(n->nbinary.ch1, EV_TESTED);
2962 if (evalskip || exitstatus == 0)
2963 goto out;
2964 evaltree(n->nbinary.ch2, flags);
2965 break;
2966 case NREDIR:
2967 expredir(n->nredir.redirect);
2968 redirect(n->nredir.redirect, REDIR_PUSH);
2969 evaltree(n->nredir.n, flags);
2970 popredir();
2971 break;
2972 case NSUBSHELL:
2973 evalsubshell(n, flags);
2974 break;
2975 case NBACKGND:
2976 evalsubshell(n, flags);
2977 break;
2978 case NIF: {
2979 evaltree(n->nif.test, EV_TESTED);
2980 if (evalskip)
2981 goto out;
2982 if (exitstatus == 0)
2983 evaltree(n->nif.ifpart, flags);
2984 else if (n->nif.elsepart)
2985 evaltree(n->nif.elsepart, flags);
2986 else
2987 exitstatus = 0;
2988 break;
2989 }
2990 case NWHILE:
2991 case NUNTIL:
2992 evalloop(n, flags);
2993 break;
2994 case NFOR:
2995 evalfor(n, flags);
2996 break;
2997 case NCASE:
2998 evalcase(n, flags);
2999 break;
3000 case NDEFUN: {
3001 struct builtincmd *bcmd;
3002 struct cmdentry entry;
3003 if (
3004 (bcmd = find_builtin(n->narg.text)) &&
3005 IS_BUILTIN_SPECIAL(bcmd)
3006 ) {
3007 out2fmt("%s is a special built-in\n", n->narg.text);
3008 exitstatus = 1;
3009 break;
3010 }
3011 entry.cmdtype = CMDFUNCTION;
3012 entry.u.func = copyfunc(n->narg.next);
3013 addcmdentry(n->narg.text, &entry);
3014 exitstatus = 0;
3015 break;
3016 }
3017 case NNOT:
3018 evaltree(n->nnot.com, EV_TESTED);
3019 exitstatus = !exitstatus;
3020 break;
Eric Andersencb57d552001-06-28 07:25:16 +00003021
Eric Andersen62483552001-07-10 06:09:16 +00003022 case NPIPE:
3023 evalpipe(n);
3024 checkexit = 1;
3025 break;
3026 case NCMD:
3027 evalcommand(n, flags);
3028 checkexit = 1;
3029 break;
3030#ifdef DEBUG
3031 default:
3032 printf("Node type = %d\n", n->type);
3033 break;
3034#endif
3035 }
3036out:
3037 if (pendingsigs)
3038 dotrap();
3039 if (
3040 flags & EV_EXIT ||
3041 (checkexit && eflag && exitstatus && !(flags & EV_TESTED))
3042 )
3043 exitshell(exitstatus);
3044}
3045
3046/*
3047 * Kick off a subshell to evaluate a tree.
3048 */
3049
3050static void
3051evalsubshell(const union node *n, int flags)
3052{
3053 struct job *jp;
3054 int backgnd = (n->type == NBACKGND);
3055
3056 expredir(n->nredir.redirect);
3057 jp = makejob(n, 1);
3058 if (forkshell(jp, n, backgnd) == 0) {
3059 if (backgnd)
3060 flags &=~ EV_TESTED;
3061 redirect(n->nredir.redirect, 0);
3062 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
3063 }
3064 if (! backgnd) {
3065 INTOFF;
3066 exitstatus = waitforjob(jp);
3067 INTON;
3068 }
3069}
3070
3071/*
3072 * Compute the names of the files in a redirection list.
3073 */
3074
3075static void fixredir(union node *n, const char *text, int err);
3076
3077static void
3078expredir(union node *n)
3079{
3080 union node *redir;
3081
3082 for (redir = n ; redir ; redir = redir->nfile.next) {
3083 struct arglist fn;
3084 fn.lastp = &fn.list;
3085 oexitstatus = exitstatus;
3086 switch (redir->type) {
3087 case NFROMTO:
3088 case NFROM:
3089 case NTO:
3090 case NAPPEND:
3091 case NTOOV:
3092 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3093 redir->nfile.expfname = fn.list->text;
3094 break;
3095 case NFROMFD:
3096 case NTOFD:
3097 if (redir->ndup.vname) {
3098 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3099 fixredir(redir, fn.list->text, 1);
3100 }
3101 break;
3102 }
3103 }
3104}
3105
3106
3107/*
3108 * Execute a command inside back quotes. If it's a builtin command, we
3109 * want to save its output in a block obtained from malloc. Otherwise
3110 * we fork off a subprocess and get the output of the command via a pipe.
3111 * Should be called with interrupts off.
3112 */
3113
3114static void
3115evalbackcmd(union node *n, struct backcmd *result)
3116{
3117 int pip[2];
3118 struct job *jp;
3119 struct stackmark smark; /* unnecessary */
3120
3121 setstackmark(&smark);
3122 result->fd = -1;
3123 result->buf = NULL;
3124 result->nleft = 0;
3125 result->jp = NULL;
3126 if (n == NULL) {
3127 exitstatus = 0;
3128 goto out;
3129 }
3130 exitstatus = 0;
3131 if (pipe(pip) < 0)
3132 error("Pipe call failed");
3133 jp = makejob(n, 1);
3134 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3135 FORCEINTON;
3136 close(pip[0]);
3137 if (pip[1] != 1) {
3138 close(1);
3139 dup_as_newfd(pip[1], 1);
3140 close(pip[1]);
3141 }
3142 eflag = 0;
3143 evaltree(n, EV_EXIT);
3144 }
3145 close(pip[1]);
3146 result->fd = pip[0];
3147 result->jp = jp;
3148out:
3149 popstackmark(&smark);
3150 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
3151 result->fd, result->buf, result->nleft, result->jp));
3152}
3153
3154
3155/*
3156 * Execute a simple command.
3157 */
Eric Andersencb57d552001-06-28 07:25:16 +00003158
3159/*
3160 * Search for a command. This is called before we fork so that the
3161 * location of the command will be available in the parent as well as
3162 * the child. The check for "goodname" is an overly conservative
3163 * check that the name will not be subject to expansion.
3164 */
3165
3166static void
3167prehash(n)
3168 union node *n;
3169{
3170 struct cmdentry entry;
3171
3172 if (n->type == NCMD && n->ncmd.args)
3173 if (goodname(n->ncmd.args->narg.text))
3174 find_command(n->ncmd.args->narg.text, &entry, 0,
3175 pathval());
3176}
3177
3178
Eric Andersencb57d552001-06-28 07:25:16 +00003179/*
3180 * Builtin commands. Builtin commands whose functions are closely
3181 * tied to evaluation are implemented here.
3182 */
3183
3184/*
3185 * No command given, or a bltin command with no arguments. Set the
3186 * specified variables.
3187 */
3188
3189int
3190bltincmd(argc, argv)
3191 int argc;
3192 char **argv;
3193{
3194 /*
3195 * Preserve exitstatus of a previous possible redirection
3196 * as POSIX mandates
3197 */
3198 return exitstatus;
3199}
3200
3201
3202/*
3203 * Handle break and continue commands. Break, continue, and return are
3204 * all handled by setting the evalskip flag. The evaluation routines
3205 * above all check this flag, and if it is set they start skipping
3206 * commands rather than executing them. The variable skipcount is
3207 * the number of loops to break/continue, or the number of function
3208 * levels to return. (The latter is always 1.) It should probably
3209 * be an error to break out of more loops than exist, but it isn't
3210 * in the standard shell so we don't make it one here.
3211 */
3212
3213static int
3214breakcmd(argc, argv)
3215 int argc;
3216 char **argv;
3217{
3218 int n = argc > 1 ? number(argv[1]) : 1;
3219
3220 if (n > loopnest)
3221 n = loopnest;
3222 if (n > 0) {
3223 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
3224 skipcount = n;
3225 }
3226 return 0;
3227}
3228
3229
3230/*
3231 * The return command.
3232 */
3233
3234static int
3235returncmd(argc, argv)
3236 int argc;
3237 char **argv;
3238{
3239 int ret = argc > 1 ? number(argv[1]) : oexitstatus;
3240
3241 if (funcnest) {
3242 evalskip = SKIPFUNC;
3243 skipcount = 1;
3244 return ret;
3245 }
3246 else {
3247 /* Do what ksh does; skip the rest of the file */
3248 evalskip = SKIPFILE;
3249 skipcount = 1;
3250 return ret;
3251 }
3252}
3253
3254
3255#ifndef BB_TRUE_FALSE
3256static int
3257false_main(argc, argv)
3258 int argc;
3259 char **argv;
3260{
3261 return 1;
3262}
3263
3264
3265static int
3266true_main(argc, argv)
3267 int argc;
3268 char **argv;
3269{
3270 return 0;
3271}
3272#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003273
3274/*
3275 * Controls whether the shell is interactive or not.
3276 */
3277
3278static void setsignal(int signo);
3279static void chkmail(int silent);
3280
3281
3282static void
3283setinteractive(int on)
3284{
3285 static int is_interactive;
Eric Andersen1c039232001-07-07 00:05:55 +00003286 static int do_banner=0;
Eric Andersen2870d962001-07-02 17:27:21 +00003287
3288 if (on == is_interactive)
3289 return;
3290 setsignal(SIGINT);
3291 setsignal(SIGQUIT);
3292 setsignal(SIGTERM);
3293 chkmail(1);
3294 is_interactive = on;
Eric Andersen1c039232001-07-07 00:05:55 +00003295 if (do_banner==0 && is_interactive) {
3296 /* Looks like they want an interactive shell */
3297 printf( "\n\n" BB_BANNER " Built-in shell (ash)\n");
3298 printf( "Enter 'help' for a list of built-in commands.\n\n");
3299 do_banner=1;
3300 }
Eric Andersen2870d962001-07-02 17:27:21 +00003301}
3302
3303static void
3304optschanged(void)
3305{
3306 setinteractive(iflag);
3307 setjobctl(mflag);
3308}
3309
Eric Andersencb57d552001-06-28 07:25:16 +00003310
3311static int
3312execcmd(argc, argv)
3313 int argc;
3314 char **argv;
3315{
3316 if (argc > 1) {
3317 struct strlist *sp;
3318
Eric Andersen2870d962001-07-02 17:27:21 +00003319 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003320 mflag = 0;
3321 optschanged();
3322 for (sp = cmdenviron; sp ; sp = sp->next)
3323 setvareq(sp->text, VEXPORT|VSTACK);
3324 shellexec(argv + 1, environment(), pathval(), 0);
3325 }
3326 return 0;
3327}
3328
3329static void
3330eprintlist(struct strlist *sp)
3331{
3332 for (; sp; sp = sp->next) {
Eric Andersen3102ac42001-07-06 04:26:23 +00003333 out2fmt(" %s",sp->text);
Eric Andersencb57d552001-06-28 07:25:16 +00003334 }
3335}
Eric Andersencb57d552001-06-28 07:25:16 +00003336
3337/*
3338 * Exec a program. Never returns. If you change this routine, you may
3339 * have to change the find_command routine as well.
3340 */
3341
Eric Andersen2870d962001-07-02 17:27:21 +00003342static const char *pathopt; /* set by padvance */
3343
Eric Andersencb57d552001-06-28 07:25:16 +00003344static void
3345shellexec(argv, envp, path, idx)
3346 char **argv, **envp;
3347 const char *path;
3348 int idx;
3349{
3350 char *cmdname;
3351 int e;
3352
3353 if (strchr(argv[0], '/') != NULL) {
3354 tryexec(argv[0], argv, envp);
3355 e = errno;
3356 } else {
3357 e = ENOENT;
3358 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3359 if (--idx < 0 && pathopt == NULL) {
3360 tryexec(cmdname, argv, envp);
3361 if (errno != ENOENT && errno != ENOTDIR)
3362 e = errno;
3363 }
3364 stunalloc(cmdname);
3365 }
3366 }
3367
3368 /* Map to POSIX errors */
3369 switch (e) {
3370 case EACCES:
3371 exerrno = 126;
3372 break;
3373 case ENOENT:
3374 exerrno = 127;
3375 break;
3376 default:
3377 exerrno = 2;
3378 break;
3379 }
3380 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3381 /* NOTREACHED */
3382}
3383
Eric Andersen2870d962001-07-02 17:27:21 +00003384/*
3385 * Clear traps on a fork.
3386 */
3387static void
3388clear_traps(void) {
3389 char **tp;
3390
3391 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
3392 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
3393 INTOFF;
3394 ckfree(*tp);
3395 *tp = NULL;
3396 if (tp != &trap[0])
3397 setsignal(tp - trap);
3398 INTON;
3399 }
3400 }
3401}
3402
3403
3404static void
3405initshellproc(void) {
3406
3407#ifdef ASH_ALIAS
3408 /* from alias.c: */
3409 {
3410 rmaliases();
3411 }
3412#endif
3413 /* from eval.c: */
3414 {
3415 exitstatus = 0;
3416 }
3417
3418 /* from exec.c: */
3419 {
3420 deletefuncs();
3421 }
3422
3423 /* from jobs.c: */
3424 {
3425 backgndpid = -1;
3426#ifdef JOBS
3427 jobctl = 0;
3428#endif
3429 }
3430
3431 /* from options.c: */
3432 {
3433 int i;
3434
3435 for (i = 0; i < NOPTS; i++)
3436 optent_val(i) = 0;
3437 optschanged();
3438
3439 }
3440
3441 /* from redir.c: */
3442 {
3443 clearredir();
3444 }
3445
3446 /* from trap.c: */
3447 {
3448 char *sm;
3449
3450 clear_traps();
3451 for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) {
3452 if (*sm == S_IGN)
3453 *sm = S_HARD_IGN;
3454 }
3455 }
3456
3457 /* from var.c: */
3458 {
3459 shprocvar();
3460 }
3461}
3462
3463static int preadbuffer(void);
3464static void pushfile (void);
Eric Andersen2870d962001-07-02 17:27:21 +00003465
3466/*
3467 * Read a character from the script, returning PEOF on end of file.
3468 * Nul characters in the input are silently discarded.
3469 */
3470
Eric Andersen3102ac42001-07-06 04:26:23 +00003471#ifndef ASH_OPTIMIZE_FOR_SIZE
Eric Andersen2870d962001-07-02 17:27:21 +00003472#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
3473static int
3474pgetc(void)
3475{
3476 return pgetc_macro();
3477}
3478#else
3479static int
3480pgetc_macro(void)
3481{
3482 return --parsenleft >= 0? *parsenextc++ : preadbuffer();
3483}
3484
3485static inline int
3486pgetc(void)
3487{
3488 return pgetc_macro();
3489}
3490#endif
3491
3492
3493/*
3494 * Undo the last call to pgetc. Only one character may be pushed back.
3495 * PEOF may be pushed back.
3496 */
3497
3498static void
3499pungetc() {
3500 parsenleft++;
3501 parsenextc--;
3502}
3503
3504
3505static void
3506popfile(void) {
3507 struct parsefile *pf = parsefile;
3508
3509 INTOFF;
3510 if (pf->fd >= 0)
3511 close(pf->fd);
3512 if (pf->buf)
3513 ckfree(pf->buf);
3514 while (pf->strpush)
3515 popstring();
3516 parsefile = pf->prev;
3517 ckfree(pf);
3518 parsenleft = parsefile->nleft;
3519 parselleft = parsefile->lleft;
3520 parsenextc = parsefile->nextc;
3521 plinno = parsefile->linno;
3522 INTON;
3523}
3524
3525
3526/*
3527 * Return to top level.
3528 */
3529
3530static void
3531popallfiles(void) {
3532 while (parsefile != &basepf)
3533 popfile();
3534}
3535
3536/*
3537 * Close the file(s) that the shell is reading commands from. Called
3538 * after a fork is done.
3539 */
3540
3541static void
3542closescript() {
3543 popallfiles();
3544 if (parsefile->fd > 0) {
3545 close(parsefile->fd);
3546 parsefile->fd = 0;
3547 }
3548}
3549
3550
3551/*
3552 * Like setinputfile, but takes an open file descriptor. Call this with
3553 * interrupts off.
3554 */
3555
3556static void
3557setinputfd(fd, push)
3558 int fd, push;
3559{
3560 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
3561 if (push) {
3562 pushfile();
3563 parsefile->buf = 0;
3564 } else {
3565 closescript();
3566 while (parsefile->strpush)
3567 popstring();
3568 }
3569 parsefile->fd = fd;
3570 if (parsefile->buf == NULL)
3571 parsefile->buf = ckmalloc(BUFSIZ);
3572 parselleft = parsenleft = 0;
3573 plinno = 1;
3574}
3575
3576
3577/*
3578 * Set the input to take input from a file. If push is set, push the
3579 * old input onto the stack first.
3580 */
3581
3582static void
3583setinputfile(const char *fname, int push)
3584{
3585 int fd;
3586 int myfileno2;
3587
3588 INTOFF;
3589 if ((fd = open(fname, O_RDONLY)) < 0)
3590 error("Can't open %s", fname);
3591 if (fd < 10) {
3592 myfileno2 = dup_as_newfd(fd, 10);
3593 close(fd);
3594 if (myfileno2 < 0)
3595 error("Out of file descriptors");
3596 fd = myfileno2;
3597 }
3598 setinputfd(fd, push);
3599 INTON;
3600}
3601
Eric Andersencb57d552001-06-28 07:25:16 +00003602
3603static void
Eric Andersen62483552001-07-10 06:09:16 +00003604tryexec(char *cmd, char **argv, char **envp)
3605{
Eric Andersencb57d552001-06-28 07:25:16 +00003606 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003607
Eric Andersen3102ac42001-07-06 04:26:23 +00003608#ifdef BB_FEATURE_SH_STANDALONE_SHELL
3609 char *name = cmd;
3610 char** argv_l=argv;
3611 int argc_l;
3612#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
3613 name = get_last_path_component(name);
3614#endif
3615 argv_l=envp;
3616 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
3617 putenv(*argv_l);
3618 argv_l=argv;
Eric Andersen62483552001-07-10 06:09:16 +00003619 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
Eric Andersen3102ac42001-07-06 04:26:23 +00003620 optind = 1;
3621 run_applet_by_name(name, argc_l, argv);
3622#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003623 execve(cmd, argv, envp);
Eric Andersencb57d552001-06-28 07:25:16 +00003624 e = errno;
3625 if (e == ENOEXEC) {
3626 INTOFF;
3627 initshellproc();
3628 setinputfile(cmd, 0);
3629 commandname = arg0 = savestr(argv[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00003630 setparam(argv + 1);
3631 exraise(EXSHELLPROC);
3632 }
3633 errno = e;
3634}
3635
Eric Andersen2870d962001-07-02 17:27:21 +00003636static char *commandtext (const union node *);
Eric Andersencb57d552001-06-28 07:25:16 +00003637
3638/*
3639 * Do a path search. The variable path (passed by reference) should be
3640 * set to the start of the path before the first call; padvance will update
3641 * this value as it proceeds. Successive calls to padvance will return
3642 * the possible path expansions in sequence. If an option (indicated by
3643 * a percent sign) appears in the path entry then the global variable
3644 * pathopt will be set to point to it; otherwise pathopt will be set to
3645 * NULL.
3646 */
3647
3648static const char *pathopt;
3649
Eric Andersen2870d962001-07-02 17:27:21 +00003650static void growstackblock(void);
3651
3652
Eric Andersencb57d552001-06-28 07:25:16 +00003653static char *
Eric Andersen2870d962001-07-02 17:27:21 +00003654padvance(const char **path, const char *name)
3655{
Eric Andersencb57d552001-06-28 07:25:16 +00003656 const char *p;
3657 char *q;
3658 const char *start;
3659 int len;
3660
3661 if (*path == NULL)
3662 return NULL;
3663 start = *path;
3664 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
Eric Andersen2870d962001-07-02 17:27:21 +00003665 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003666 while (stackblocksize() < len)
3667 growstackblock();
3668 q = stackblock();
3669 if (p != start) {
3670 memcpy(q, start, p - start);
3671 q += p - start;
3672 *q++ = '/';
3673 }
3674 strcpy(q, name);
3675 pathopt = NULL;
3676 if (*p == '%') {
3677 pathopt = ++p;
3678 while (*p && *p != ':') p++;
3679 }
3680 if (*p == ':')
3681 *path = p + 1;
3682 else
3683 *path = NULL;
3684 return stalloc(len);
3685}
3686
Eric Andersen62483552001-07-10 06:09:16 +00003687/*
3688 * Wrapper around strcmp for qsort/bsearch/...
3689 */
3690static int
3691pstrcmp(const void *a, const void *b)
3692{
3693 return strcmp((const char *) a, *(const char *const *) b);
3694}
3695
3696/*
3697 * Find a keyword is in a sorted array.
3698 */
3699
3700static const char *const *
3701findkwd(const char *s)
3702{
3703 return bsearch(s, parsekwd, sizeof(parsekwd) / sizeof(const char *),
3704 sizeof(const char *), pstrcmp);
3705}
Eric Andersencb57d552001-06-28 07:25:16 +00003706
3707
3708/*** Command hashing code ***/
3709
3710
3711static int
3712hashcmd(argc, argv)
3713 int argc;
3714 char **argv;
3715{
3716 struct tblentry **pp;
3717 struct tblentry *cmdp;
3718 int c;
3719 int verbose;
3720 struct cmdentry entry;
3721 char *name;
Eric Andersen62483552001-07-10 06:09:16 +00003722#ifdef ASH_ALIAS
3723 const struct alias *ap;
3724#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003725
3726 verbose = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003727 while ((c = nextopt("rvV")) != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00003728 if (c == 'r') {
3729 clearcmdentry(0);
3730 return 0;
Eric Andersen62483552001-07-10 06:09:16 +00003731 } else if (c == 'v' || c == 'V') {
3732 verbose = c;
Eric Andersencb57d552001-06-28 07:25:16 +00003733 }
3734 }
3735 if (*argptr == NULL) {
3736 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3737 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3738 if (cmdp->cmdtype != CMDBUILTIN) {
3739 printentry(cmdp, verbose);
3740 }
3741 }
3742 }
3743 return 0;
3744 }
3745 c = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003746 while ((name = *argptr++) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00003747 if ((cmdp = cmdlookup(name, 0)) != NULL
3748 && (cmdp->cmdtype == CMDNORMAL
3749 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3750 delete_cmd_entry();
Eric Andersen62483552001-07-10 06:09:16 +00003751#ifdef ASH_ALIAS
3752 /* Then look at the aliases */
3753 if ((ap = lookupalias(name, 0)) != NULL) {
3754 if (verbose=='v')
3755 printf("%s is an alias for %s\n", name, ap->val);
3756 else
3757 printalias(ap);
3758 continue;
3759 }
3760#endif
3761 /* First look at the keywords */
3762 if (findkwd(name)!=0) {
3763 if (verbose=='v')
3764 printf("%s is a shell keyword\n", name);
3765 else
3766 printf(snlfmt, name);
3767 continue;
3768 }
3769
Eric Andersencb57d552001-06-28 07:25:16 +00003770 find_command(name, &entry, DO_ERR, pathval());
3771 if (entry.cmdtype == CMDUNKNOWN) c = 1;
3772 else if (verbose) {
3773 cmdp = cmdlookup(name, 0);
Eric Andersen62483552001-07-10 06:09:16 +00003774 if (cmdp) printentry(cmdp, verbose=='v');
Eric Andersencb57d552001-06-28 07:25:16 +00003775 flushall();
3776 }
Eric Andersencb57d552001-06-28 07:25:16 +00003777 }
3778 return c;
3779}
3780
Eric Andersencb57d552001-06-28 07:25:16 +00003781static void
3782printentry(cmdp, verbose)
3783 struct tblentry *cmdp;
3784 int verbose;
3785 {
3786 int idx;
3787 const char *path;
3788 char *name;
3789
Eric Andersen62483552001-07-10 06:09:16 +00003790 printf("%s%s", cmdp->cmdname, (verbose ? " is " : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00003791 if (cmdp->cmdtype == CMDNORMAL) {
3792 idx = cmdp->param.index;
3793 path = pathval();
3794 do {
3795 name = padvance(&path, cmdp->cmdname);
3796 stunalloc(name);
3797 } while (--idx >= 0);
Eric Andersen62483552001-07-10 06:09:16 +00003798 if(verbose)
3799 out1str(name);
Eric Andersencb57d552001-06-28 07:25:16 +00003800 } else if (cmdp->cmdtype == CMDBUILTIN) {
Eric Andersen62483552001-07-10 06:09:16 +00003801 if(verbose)
3802 out1str("a shell builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00003803 } else if (cmdp->cmdtype == CMDFUNCTION) {
Eric Andersencb57d552001-06-28 07:25:16 +00003804 if (verbose) {
3805 INTOFF;
Eric Andersen62483552001-07-10 06:09:16 +00003806 out1str("a function\n");
Eric Andersencb57d552001-06-28 07:25:16 +00003807 name = commandtext(cmdp->param.func);
Eric Andersen62483552001-07-10 06:09:16 +00003808 printf("%s() {\n %s\n}", cmdp->cmdname, name);
Eric Andersencb57d552001-06-28 07:25:16 +00003809 ckfree(name);
3810 INTON;
3811 }
3812#ifdef DEBUG
3813 } else {
3814 error("internal error: cmdtype %d", cmdp->cmdtype);
3815#endif
3816 }
Eric Andersen62483552001-07-10 06:09:16 +00003817 printf(snlfmt, cmdp->rehash ? "*" : nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +00003818}
3819
3820
3821
Eric Andersen1c039232001-07-07 00:05:55 +00003822/*** List the available builtins ***/
3823
3824
3825static int helpcmd(int argc, char** argv)
3826{
3827 int col, i;
Eric Andersen1c039232001-07-07 00:05:55 +00003828
Eric Andersen62483552001-07-10 06:09:16 +00003829 printf("\nBuilt-in commands:\n-------------------\n");
3830 for (col=0, i=0; i < NUMBUILTINS; i++) {
3831 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3832 builtincmds[i].name+1);
Eric Andersen1c039232001-07-07 00:05:55 +00003833 if (col > 60) {
3834 printf("\n");
3835 col = 0;
3836 }
3837 }
3838#ifdef BB_FEATURE_SH_STANDALONE_SHELL
3839 {
Eric Andersen1c039232001-07-07 00:05:55 +00003840 extern const struct BB_applet applets[];
3841 extern const size_t NUM_APPLETS;
3842
Eric Andersen62483552001-07-10 06:09:16 +00003843 for (i=0; i < NUM_APPLETS; i++) {
3844
3845 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3846 applets[i].name);
Eric Andersen1c039232001-07-07 00:05:55 +00003847 if (col > 60) {
3848 printf("\n");
3849 col = 0;
3850 }
3851 }
3852 }
3853#endif
3854 printf("\n\n");
3855 return EXIT_SUCCESS;
3856}
3857
Eric Andersencb57d552001-06-28 07:25:16 +00003858/*
3859 * Resolve a command name. If you change this routine, you may have to
3860 * change the shellexec routine as well.
3861 */
3862
Eric Andersen2870d962001-07-02 17:27:21 +00003863static int prefix (const char *, const char *);
3864
Eric Andersencb57d552001-06-28 07:25:16 +00003865static void
Eric Andersen2870d962001-07-02 17:27:21 +00003866find_command(const char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003867{
3868 struct tblentry *cmdp;
3869 int idx;
3870 int prev;
3871 char *fullname;
3872 struct stat statb;
3873 int e;
3874 int bltin;
3875 int firstchange;
3876 int updatetbl;
Eric Andersen62483552001-07-10 06:09:16 +00003877 int regular;
Eric Andersencb57d552001-06-28 07:25:16 +00003878 struct builtincmd *bcmd;
3879
3880 /* If name contains a slash, don't use the hash table */
3881 if (strchr(name, '/') != NULL) {
3882 if (act & DO_ABS) {
3883 while (stat(name, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003884 if (errno != ENOENT && errno != ENOTDIR)
3885 e = errno;
3886 entry->cmdtype = CMDUNKNOWN;
3887 entry->u.index = -1;
3888 return;
3889 }
3890 entry->cmdtype = CMDNORMAL;
3891 entry->u.index = -1;
3892 return;
3893 }
3894 entry->cmdtype = CMDNORMAL;
3895 entry->u.index = 0;
3896 return;
3897 }
3898
3899 updatetbl = 1;
3900 if (act & DO_BRUTE) {
3901 firstchange = path_change(path, &bltin);
3902 } else {
3903 bltin = builtinloc;
3904 firstchange = 9999;
3905 }
3906
3907 /* If name is in the table, and not invalidated by cd, we're done */
3908 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
3909 if (cmdp->cmdtype == CMDFUNCTION) {
3910 if (act & DO_NOFUN) {
3911 updatetbl = 0;
3912 } else {
3913 goto success;
3914 }
3915 } else if (act & DO_BRUTE) {
3916 if ((cmdp->cmdtype == CMDNORMAL &&
3917 cmdp->param.index >= firstchange) ||
3918 (cmdp->cmdtype == CMDBUILTIN &&
3919 ((builtinloc < 0 && bltin >= 0) ?
3920 bltin : builtinloc) >= firstchange)) {
3921 /* need to recompute the entry */
3922 } else {
3923 goto success;
3924 }
3925 } else {
3926 goto success;
3927 }
3928 }
3929
3930 bcmd = find_builtin(name);
Eric Andersen2870d962001-07-02 17:27:21 +00003931 regular = bcmd && IS_BUILTIN_REGULAR(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00003932
3933 if (regular) {
3934 if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) {
Eric Andersen2870d962001-07-02 17:27:21 +00003935 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003936 }
3937 } else if (act & DO_BRUTE) {
3938 if (firstchange == 0) {
3939 updatetbl = 0;
3940 }
3941 }
3942
3943 /* If %builtin not in path, check for builtin next */
3944 if (regular || (bltin < 0 && bcmd)) {
3945builtin:
3946 if (!updatetbl) {
3947 entry->cmdtype = CMDBUILTIN;
3948 entry->u.cmd = bcmd;
3949 return;
3950 }
3951 INTOFF;
3952 cmdp = cmdlookup(name, 1);
3953 cmdp->cmdtype = CMDBUILTIN;
3954 cmdp->param.cmd = bcmd;
3955 INTON;
3956 goto success;
3957 }
3958
3959 /* We have to search path. */
Eric Andersen2870d962001-07-02 17:27:21 +00003960 prev = -1; /* where to start */
3961 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00003962 if (cmdp->cmdtype == CMDBUILTIN)
3963 prev = builtinloc;
3964 else
3965 prev = cmdp->param.index;
3966 }
3967
3968 e = ENOENT;
3969 idx = -1;
3970loop:
3971 while ((fullname = padvance(&path, name)) != NULL) {
3972 stunalloc(fullname);
3973 idx++;
3974 if (idx >= firstchange) {
3975 updatetbl = 0;
3976 }
3977 if (pathopt) {
3978 if (prefix("builtin", pathopt)) {
3979 if ((bcmd = find_builtin(name))) {
3980 goto builtin;
3981 }
3982 continue;
3983 } else if (!(act & DO_NOFUN) &&
3984 prefix("func", pathopt)) {
3985 /* handled below */
3986 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00003987 continue; /* ignore unimplemented options */
Eric Andersencb57d552001-06-28 07:25:16 +00003988 }
3989 }
3990 /* if rehash, don't redo absolute path names */
3991 if (fullname[0] == '/' && idx <= prev &&
3992 idx < firstchange) {
3993 if (idx < prev)
3994 continue;
3995 TRACE(("searchexec \"%s\": no change\n", name));
3996 goto success;
3997 }
3998 while (stat(fullname, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003999 if (errno != ENOENT && errno != ENOTDIR)
4000 e = errno;
4001 goto loop;
4002 }
Eric Andersen2870d962001-07-02 17:27:21 +00004003 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00004004 if (!S_ISREG(statb.st_mode))
4005 continue;
Eric Andersen2870d962001-07-02 17:27:21 +00004006 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00004007 stalloc(strlen(fullname) + 1);
4008 readcmdfile(fullname);
4009 if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
4010 error("%s not defined in %s", name, fullname);
4011 stunalloc(fullname);
4012 goto success;
4013 }
Eric Andersencb57d552001-06-28 07:25:16 +00004014 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
4015 /* If we aren't called with DO_BRUTE and cmdp is set, it must
4016 be a function and we're being called with DO_NOFUN */
4017 if (!updatetbl) {
4018 entry->cmdtype = CMDNORMAL;
4019 entry->u.index = idx;
4020 return;
4021 }
4022 INTOFF;
4023 cmdp = cmdlookup(name, 1);
4024 cmdp->cmdtype = CMDNORMAL;
4025 cmdp->param.index = idx;
4026 INTON;
4027 goto success;
4028 }
4029
4030 /* We failed. If there was an entry for this command, delete it */
4031 if (cmdp && updatetbl)
4032 delete_cmd_entry();
4033 if (act & DO_ERR)
Eric Andersen3102ac42001-07-06 04:26:23 +00004034 out2fmt("%s: %s\n", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00004035 entry->cmdtype = CMDUNKNOWN;
4036 return;
4037
4038success:
4039 cmdp->rehash = 0;
4040 entry->cmdtype = cmdp->cmdtype;
4041 entry->u = cmdp->param;
4042}
4043
4044
4045
4046/*
4047 * Search the table of builtin commands.
4048 */
4049
Eric Andersen2870d962001-07-02 17:27:21 +00004050static int
4051bstrcmp(const void *name, const void *b)
4052{
4053 return strcmp((const char *)name, (*(const char *const *) b)+1);
4054}
4055
4056static struct builtincmd *
4057find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00004058{
4059 struct builtincmd *bp;
4060
Eric Andersen2870d962001-07-02 17:27:21 +00004061 bp = bsearch(name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd),
4062 bstrcmp
Eric Andersencb57d552001-06-28 07:25:16 +00004063 );
4064 return bp;
4065}
4066
4067
4068/*
4069 * Called when a cd is done. Marks all commands so the next time they
4070 * are executed they will be rehashed.
4071 */
4072
4073static void
Eric Andersen2870d962001-07-02 17:27:21 +00004074hashcd(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00004075 struct tblentry **pp;
4076 struct tblentry *cmdp;
4077
4078 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4079 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4080 if (cmdp->cmdtype == CMDNORMAL
4081 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
4082 cmdp->rehash = 1;
4083 }
4084 }
4085}
4086
4087
4088
4089/*
4090 * Called before PATH is changed. The argument is the new value of PATH;
4091 * pathval() still returns the old value at this point. Called with
4092 * interrupts off.
4093 */
4094
4095static void
Eric Andersen2870d962001-07-02 17:27:21 +00004096changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00004097{
4098 int firstchange;
4099 int bltin;
4100
4101 firstchange = path_change(newval, &bltin);
4102 if (builtinloc < 0 && bltin >= 0)
Eric Andersen2870d962001-07-02 17:27:21 +00004103 builtinloc = bltin; /* zap builtins */
Eric Andersencb57d552001-06-28 07:25:16 +00004104 clearcmdentry(firstchange);
4105 builtinloc = bltin;
4106}
4107
4108
4109/*
4110 * Clear out command entries. The argument specifies the first entry in
4111 * PATH which has changed.
4112 */
4113
4114static void
4115clearcmdentry(firstchange)
4116 int firstchange;
4117{
4118 struct tblentry **tblp;
4119 struct tblentry **pp;
4120 struct tblentry *cmdp;
4121
4122 INTOFF;
4123 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4124 pp = tblp;
4125 while ((cmdp = *pp) != NULL) {
4126 if ((cmdp->cmdtype == CMDNORMAL &&
4127 cmdp->param.index >= firstchange)
4128 || (cmdp->cmdtype == CMDBUILTIN &&
4129 builtinloc >= firstchange)) {
4130 *pp = cmdp->next;
4131 ckfree(cmdp);
4132 } else {
4133 pp = &cmdp->next;
4134 }
4135 }
4136 }
4137 INTON;
4138}
4139
4140
4141/*
4142 * Delete all functions.
4143 */
4144
Eric Andersencb57d552001-06-28 07:25:16 +00004145static void
Eric Andersen2870d962001-07-02 17:27:21 +00004146deletefuncs(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00004147 struct tblentry **tblp;
4148 struct tblentry **pp;
4149 struct tblentry *cmdp;
4150
4151 INTOFF;
4152 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4153 pp = tblp;
4154 while ((cmdp = *pp) != NULL) {
4155 if (cmdp->cmdtype == CMDFUNCTION) {
4156 *pp = cmdp->next;
4157 freefunc(cmdp->param.func);
4158 ckfree(cmdp);
4159 } else {
4160 pp = &cmdp->next;
4161 }
4162 }
4163 }
4164 INTON;
4165}
4166
4167
4168
4169/*
4170 * Locate a command in the command hash table. If "add" is nonzero,
4171 * add the command to the table if it is not already present. The
4172 * variable "lastcmdentry" is set to point to the address of the link
4173 * pointing to the entry, so that delete_cmd_entry can delete the
4174 * entry.
4175 */
4176
Eric Andersen2870d962001-07-02 17:27:21 +00004177static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00004178
4179static struct tblentry *
Eric Andersen2870d962001-07-02 17:27:21 +00004180cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00004181{
4182 int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00004183 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00004184 struct tblentry *cmdp;
4185 struct tblentry **pp;
4186
4187 p = name;
4188 hashval = *p << 4;
4189 while (*p)
4190 hashval += *p++;
4191 hashval &= 0x7FFF;
4192 pp = &cmdtable[hashval % CMDTABLESIZE];
4193 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4194 if (equal(cmdp->cmdname, name))
4195 break;
4196 pp = &cmdp->next;
4197 }
4198 if (add && cmdp == NULL) {
4199 INTOFF;
4200 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4201 + strlen(name) + 1);
4202 cmdp->next = NULL;
4203 cmdp->cmdtype = CMDUNKNOWN;
4204 cmdp->rehash = 0;
4205 strcpy(cmdp->cmdname, name);
4206 INTON;
4207 }
4208 lastcmdentry = pp;
4209 return cmdp;
4210}
4211
4212/*
4213 * Delete the command entry returned on the last lookup.
4214 */
4215
4216static void
4217delete_cmd_entry() {
4218 struct tblentry *cmdp;
4219
4220 INTOFF;
4221 cmdp = *lastcmdentry;
4222 *lastcmdentry = cmdp->next;
4223 ckfree(cmdp);
4224 INTON;
4225}
4226
4227
4228
Eric Andersencb57d552001-06-28 07:25:16 +00004229
4230
Eric Andersen62483552001-07-10 06:09:16 +00004231static const short nodesize[26] = {
4232 ALIGN(sizeof (struct nbinary)),
4233 ALIGN(sizeof (struct ncmd)),
4234 ALIGN(sizeof (struct npipe)),
4235 ALIGN(sizeof (struct nredir)),
4236 ALIGN(sizeof (struct nredir)),
4237 ALIGN(sizeof (struct nredir)),
4238 ALIGN(sizeof (struct nbinary)),
4239 ALIGN(sizeof (struct nbinary)),
4240 ALIGN(sizeof (struct nif)),
4241 ALIGN(sizeof (struct nbinary)),
4242 ALIGN(sizeof (struct nbinary)),
4243 ALIGN(sizeof (struct nfor)),
4244 ALIGN(sizeof (struct ncase)),
4245 ALIGN(sizeof (struct nclist)),
4246 ALIGN(sizeof (struct narg)),
4247 ALIGN(sizeof (struct narg)),
4248 ALIGN(sizeof (struct nfile)),
4249 ALIGN(sizeof (struct nfile)),
4250 ALIGN(sizeof (struct nfile)),
4251 ALIGN(sizeof (struct nfile)),
4252 ALIGN(sizeof (struct nfile)),
4253 ALIGN(sizeof (struct ndup)),
4254 ALIGN(sizeof (struct ndup)),
4255 ALIGN(sizeof (struct nhere)),
4256 ALIGN(sizeof (struct nhere)),
4257 ALIGN(sizeof (struct nnot)),
4258};
Eric Andersencb57d552001-06-28 07:25:16 +00004259
Eric Andersencb57d552001-06-28 07:25:16 +00004260
4261
4262/*
4263 * Delete a function if it exists.
4264 */
4265
4266static void
Eric Andersen2870d962001-07-02 17:27:21 +00004267unsetfunc(char *name)
4268{
Eric Andersencb57d552001-06-28 07:25:16 +00004269 struct tblentry *cmdp;
4270
4271 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
4272 freefunc(cmdp->param.func);
4273 delete_cmd_entry();
4274 }
4275}
4276
Eric Andersen2870d962001-07-02 17:27:21 +00004277
4278/*
Eric Andersencb57d552001-06-28 07:25:16 +00004279 * Locate and print what a word is...
4280 */
4281
4282static int
Eric Andersen62483552001-07-10 06:09:16 +00004283typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004284{
4285 int i;
4286 int err = 0;
Eric Andersen62483552001-07-10 06:09:16 +00004287 char *argv_a[2];
4288
4289 argv_a[1] = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004290
4291 for (i = 1; i < argc; i++) {
Eric Andersen62483552001-07-10 06:09:16 +00004292 argv_a[0] = argv[i];
4293 argptr = argv_a;
4294 optptr = "v";
4295 err |= hashcmd(argc, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00004296 }
4297 return err;
4298}
4299
Eric Andersen2870d962001-07-02 17:27:21 +00004300#ifdef ASH_CMDCMD
Eric Andersencb57d552001-06-28 07:25:16 +00004301static int
4302commandcmd(argc, argv)
4303 int argc;
4304 char **argv;
4305{
4306 int c;
4307 int default_path = 0;
4308 int verify_only = 0;
4309 int verbose_verify_only = 0;
4310
4311 while ((c = nextopt("pvV")) != '\0')
4312 switch (c) {
4313 case 'p':
4314 default_path = 1;
4315 break;
4316 case 'v':
4317 verify_only = 1;
4318 break;
4319 case 'V':
4320 verbose_verify_only = 1;
4321 break;
Eric Andersencb57d552001-06-28 07:25:16 +00004322 }
4323
4324 if (default_path + verify_only + verbose_verify_only > 1 ||
4325 !*argptr) {
Eric Andersen62483552001-07-10 06:09:16 +00004326 out2str(
4327 "command [-p] command [arg ...]\n"
4328 "command {-v|-V} command\n");
Eric Andersencb57d552001-06-28 07:25:16 +00004329 return EX_USAGE;
4330 }
4331
Eric Andersencb57d552001-06-28 07:25:16 +00004332 if (verify_only || verbose_verify_only) {
Eric Andersen62483552001-07-10 06:09:16 +00004333 char *argv_a[2];
4334
4335 argv_a[1] = 0;
4336 argv_a[0] = *argptr;
4337 argptr = argv_a;
4338 optptr = verbose_verify_only ? "v" : "V"; /* reverse special */
4339 return hashcmd(argc, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00004340 }
Eric Andersencb57d552001-06-28 07:25:16 +00004341
4342 return 0;
4343}
Eric Andersen2870d962001-07-02 17:27:21 +00004344#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004345
4346static int
4347path_change(newval, bltin)
4348 const char *newval;
4349 int *bltin;
4350{
4351 const char *old, *new;
4352 int idx;
4353 int firstchange;
4354
4355 old = pathval();
4356 new = newval;
Eric Andersen2870d962001-07-02 17:27:21 +00004357 firstchange = 9999; /* assume no change */
Eric Andersencb57d552001-06-28 07:25:16 +00004358 idx = 0;
4359 *bltin = -1;
4360 for (;;) {
4361 if (*old != *new) {
4362 firstchange = idx;
4363 if ((*old == '\0' && *new == ':')
4364 || (*old == ':' && *new == '\0'))
4365 firstchange++;
Eric Andersen2870d962001-07-02 17:27:21 +00004366 old = new; /* ignore subsequent differences */
Eric Andersencb57d552001-06-28 07:25:16 +00004367 }
4368 if (*new == '\0')
4369 break;
4370 if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1))
4371 *bltin = idx;
4372 if (*new == ':') {
4373 idx++;
4374 }
4375 new++, old++;
4376 }
4377 if (builtinloc >= 0 && *bltin < 0)
4378 firstchange = 0;
4379 return firstchange;
4380}
Eric Andersencb57d552001-06-28 07:25:16 +00004381/*
4382 * Routines to expand arguments to commands. We have to deal with
4383 * backquotes, shell variables, and file metacharacters.
4384 */
4385/*
4386 * _rmescape() flags
4387 */
Eric Andersen2870d962001-07-02 17:27:21 +00004388#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4389#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Eric Andersencb57d552001-06-28 07:25:16 +00004390
4391/*
4392 * Structure specifying which parts of the string should be searched
4393 * for IFS characters.
4394 */
4395
4396struct ifsregion {
Eric Andersen2870d962001-07-02 17:27:21 +00004397 struct ifsregion *next; /* next region in list */
4398 int begoff; /* offset of start of region */
4399 int endoff; /* offset of end of region */
4400 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004401};
4402
4403
Eric Andersen2870d962001-07-02 17:27:21 +00004404static char *expdest; /* output of current string */
4405static struct nodelist *argbackq; /* list of back quote expressions */
4406static struct ifsregion ifsfirst; /* first struct in list of ifs regions */
4407static struct ifsregion *ifslastp; /* last struct in list */
4408static struct arglist exparg; /* holds expanded arg list */
Eric Andersencb57d552001-06-28 07:25:16 +00004409
Eric Andersen2870d962001-07-02 17:27:21 +00004410static void argstr (char *, int);
4411static char *exptilde (char *, int);
4412static void expbackq (union node *, int, int);
4413static int subevalvar (char *, char *, int, int, int, int, int);
Eric Andersen2870d962001-07-02 17:27:21 +00004414static int varisset (char *, int);
4415static void strtodest (const char *, const char *, int);
4416static void varvalue (char *, int, int);
4417static void recordregion (int, int, int);
4418static void removerecordregions (int);
4419static void ifsbreakup (char *, struct arglist *);
4420static void ifsfree (void);
4421static void expandmeta (struct strlist *, int);
Eric Andersen62483552001-07-10 06:09:16 +00004422#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00004423#define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB)
4424#if !defined(GLOB_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00004425static void addglob (const glob_t *);
Eric Andersencb57d552001-06-28 07:25:16 +00004426#endif
4427#endif
Eric Andersen62483552001-07-10 06:09:16 +00004428#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersen2870d962001-07-02 17:27:21 +00004429static void expmeta (char *, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004430#endif
Eric Andersen62483552001-07-10 06:09:16 +00004431#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersen2870d962001-07-02 17:27:21 +00004432static struct strlist *expsort (struct strlist *);
4433static struct strlist *msort (struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004434#endif
Eric Andersen2870d962001-07-02 17:27:21 +00004435static int patmatch (char *, char *, int);
Eric Andersen62483552001-07-10 06:09:16 +00004436#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00004437static int patmatch2 (char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004438#else
Eric Andersen2870d962001-07-02 17:27:21 +00004439static int pmatch (char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004440#define patmatch2 patmatch
4441#endif
Eric Andersen2870d962001-07-02 17:27:21 +00004442static char *cvtnum (int, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004443
4444/*
4445 * Expand shell variables and backquotes inside a here document.
4446 */
4447
Eric Andersen2870d962001-07-02 17:27:21 +00004448/* arg: the document, fd: where to write the expanded version */
Eric Andersen62483552001-07-10 06:09:16 +00004449static inline void
Eric Andersen2870d962001-07-02 17:27:21 +00004450expandhere(union node *arg, int fd)
4451{
Eric Andersencb57d552001-06-28 07:25:16 +00004452 herefd = fd;
4453 expandarg(arg, (struct arglist *)NULL, 0);
4454 xwrite(fd, stackblock(), expdest - stackblock());
4455}
4456
4457
4458/*
4459 * Perform variable substitution and command substitution on an argument,
4460 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4461 * perform splitting and file name expansion. When arglist is NULL, perform
4462 * here document expansion.
4463 */
4464
4465static void
4466expandarg(arg, arglist, flag)
4467 union node *arg;
4468 struct arglist *arglist;
4469 int flag;
4470{
4471 struct strlist *sp;
4472 char *p;
4473
4474 argbackq = arg->narg.backquote;
4475 STARTSTACKSTR(expdest);
4476 ifsfirst.next = NULL;
4477 ifslastp = NULL;
4478 argstr(arg->narg.text, flag);
4479 if (arglist == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00004480 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004481 }
4482 STPUTC('\0', expdest);
4483 p = grabstackstr(expdest);
4484 exparg.lastp = &exparg.list;
4485 /*
4486 * TODO - EXP_REDIR
4487 */
4488 if (flag & EXP_FULL) {
4489 ifsbreakup(p, &exparg);
4490 *exparg.lastp = NULL;
4491 exparg.lastp = &exparg.list;
4492 expandmeta(exparg.list, flag);
4493 } else {
4494 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4495 rmescapes(p);
4496 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4497 sp->text = p;
4498 *exparg.lastp = sp;
4499 exparg.lastp = &sp->next;
4500 }
4501 ifsfree();
4502 *exparg.lastp = NULL;
4503 if (exparg.list) {
4504 *arglist->lastp = exparg.list;
4505 arglist->lastp = exparg.lastp;
4506 }
4507}
4508
4509
Eric Andersen62483552001-07-10 06:09:16 +00004510/*
4511 * Expand a variable, and return a pointer to the next character in the
4512 * input string.
4513 */
4514
4515static inline char *
4516evalvar(p, flag)
4517 char *p;
4518 int flag;
4519{
4520 int subtype;
4521 int varflags;
4522 char *var;
4523 const char *val;
4524 int patloc;
4525 int c;
4526 int set;
4527 int special;
4528 int startloc;
4529 int varlen;
4530 int easy;
4531 int quotes = flag & (EXP_FULL | EXP_CASE);
4532
4533 varflags = *p++;
4534 subtype = varflags & VSTYPE;
4535 var = p;
4536 special = 0;
4537 if (! is_name(*p))
4538 special = 1;
4539 p = strchr(p, '=') + 1;
4540again: /* jump here after setting a variable with ${var=text} */
4541 if (special) {
4542 set = varisset(var, varflags & VSNUL);
4543 val = NULL;
4544 } else {
4545 val = lookupvar(var);
4546 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
4547 val = NULL;
4548 set = 0;
4549 } else
4550 set = 1;
4551 }
4552 varlen = 0;
4553 startloc = expdest - stackblock();
4554 if (set && subtype != VSPLUS) {
4555 /* insert the value of the variable */
4556 if (special) {
4557 varvalue(var, varflags & VSQUOTE, flag);
4558 if (subtype == VSLENGTH) {
4559 varlen = expdest - stackblock() - startloc;
4560 STADJUST(-varlen, expdest);
4561 }
4562 } else {
4563 if (subtype == VSLENGTH) {
4564 varlen = strlen(val);
4565 } else {
4566 strtodest(
4567 val,
4568 varflags & VSQUOTE ?
4569 DQSYNTAX : BASESYNTAX,
4570 quotes
4571 );
4572 }
4573 }
4574 }
4575
4576 if (subtype == VSPLUS)
4577 set = ! set;
4578
4579 easy = ((varflags & VSQUOTE) == 0 ||
4580 (*var == '@' && shellparam.nparam != 1));
4581
4582
4583 switch (subtype) {
4584 case VSLENGTH:
4585 expdest = cvtnum(varlen, expdest);
4586 goto record;
4587
4588 case VSNORMAL:
4589 if (!easy)
4590 break;
4591record:
4592 recordregion(startloc, expdest - stackblock(),
4593 varflags & VSQUOTE);
4594 break;
4595
4596 case VSPLUS:
4597 case VSMINUS:
4598 if (!set) {
4599 argstr(p, flag);
4600 break;
4601 }
4602 if (easy)
4603 goto record;
4604 break;
4605
4606 case VSTRIMLEFT:
4607 case VSTRIMLEFTMAX:
4608 case VSTRIMRIGHT:
4609 case VSTRIMRIGHTMAX:
4610 if (!set)
4611 break;
4612 /*
4613 * Terminate the string and start recording the pattern
4614 * right after it
4615 */
4616 STPUTC('\0', expdest);
4617 patloc = expdest - stackblock();
4618 if (subevalvar(p, NULL, patloc, subtype,
4619 startloc, varflags, quotes) == 0) {
4620 int amount = (expdest - stackblock() - patloc) + 1;
4621 STADJUST(-amount, expdest);
4622 }
4623 /* Remove any recorded regions beyond start of variable */
4624 removerecordregions(startloc);
4625 goto record;
4626
4627 case VSASSIGN:
4628 case VSQUESTION:
4629 if (!set) {
4630 if (subevalvar(p, var, 0, subtype, startloc,
4631 varflags, quotes)) {
4632 varflags &= ~VSNUL;
4633 /*
4634 * Remove any recorded regions beyond
4635 * start of variable
4636 */
4637 removerecordregions(startloc);
4638 goto again;
4639 }
4640 break;
4641 }
4642 if (easy)
4643 goto record;
4644 break;
4645
4646#ifdef DEBUG
4647 default:
4648 abort();
4649#endif
4650 }
4651
4652 if (subtype != VSNORMAL) { /* skip to end of alternative */
4653 int nesting = 1;
4654 for (;;) {
4655 if ((c = *p++) == CTLESC)
4656 p++;
4657 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
4658 if (set)
4659 argbackq = argbackq->next;
4660 } else if (c == CTLVAR) {
4661 if ((*p++ & VSTYPE) != VSNORMAL)
4662 nesting++;
4663 } else if (c == CTLENDVAR) {
4664 if (--nesting == 0)
4665 break;
4666 }
4667 }
4668 }
4669 return p;
4670}
4671
Eric Andersencb57d552001-06-28 07:25:16 +00004672
4673/*
4674 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4675 * characters to allow for further processing. Otherwise treat
4676 * $@ like $* since no splitting will be performed.
4677 */
4678
4679static void
4680argstr(p, flag)
4681 char *p;
4682 int flag;
4683{
4684 char c;
Eric Andersen2870d962001-07-02 17:27:21 +00004685 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
Eric Andersencb57d552001-06-28 07:25:16 +00004686 int firsteq = 1;
4687
4688 if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
4689 p = exptilde(p, flag);
4690 for (;;) {
4691 switch (c = *p++) {
4692 case '\0':
4693 case CTLENDVAR: /* ??? */
4694 goto breakloop;
4695 case CTLQUOTEMARK:
4696 /* "$@" syntax adherence hack */
4697 if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
4698 break;
4699 if ((flag & EXP_FULL) != 0)
4700 STPUTC(c, expdest);
4701 break;
4702 case CTLESC:
4703 if (quotes)
4704 STPUTC(c, expdest);
4705 c = *p++;
4706 STPUTC(c, expdest);
4707 break;
4708 case CTLVAR:
4709 p = evalvar(p, flag);
4710 break;
4711 case CTLBACKQ:
4712 case CTLBACKQ|CTLQUOTE:
4713 expbackq(argbackq->n, c & CTLQUOTE, flag);
4714 argbackq = argbackq->next;
4715 break;
4716#ifdef ASH_MATH_SUPPORT
4717 case CTLENDARI:
4718 expari(flag);
4719 break;
Eric Andersen2870d962001-07-02 17:27:21 +00004720#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004721 case ':':
4722 case '=':
4723 /*
4724 * sort of a hack - expand tildes in variable
4725 * assignments (after the first '=' and after ':'s).
4726 */
4727 STPUTC(c, expdest);
4728 if (flag & EXP_VARTILDE && *p == '~') {
4729 if (c == '=') {
4730 if (firsteq)
4731 firsteq = 0;
4732 else
4733 break;
4734 }
4735 p = exptilde(p, flag);
4736 }
4737 break;
4738 default:
4739 STPUTC(c, expdest);
4740 }
4741 }
4742breakloop:;
4743 return;
4744}
4745
4746static char *
4747exptilde(p, flag)
4748 char *p;
4749 int flag;
4750{
4751 char c, *startp = p;
4752 struct passwd *pw;
4753 const char *home;
4754 int quotes = flag & (EXP_FULL | EXP_CASE);
4755
4756 while ((c = *p) != '\0') {
4757 switch(c) {
4758 case CTLESC:
4759 return (startp);
4760 case CTLQUOTEMARK:
4761 return (startp);
4762 case ':':
4763 if (flag & EXP_VARTILDE)
4764 goto done;
4765 break;
4766 case '/':
4767 goto done;
4768 }
4769 p++;
4770 }
4771done:
4772 *p = '\0';
4773 if (*(startp+1) == '\0') {
4774 if ((home = lookupvar("HOME")) == NULL)
4775 goto lose;
4776 } else {
4777 if ((pw = getpwnam(startp+1)) == NULL)
4778 goto lose;
4779 home = pw->pw_dir;
4780 }
4781 if (*home == '\0')
4782 goto lose;
4783 *p = c;
4784 strtodest(home, SQSYNTAX, quotes);
4785 return (p);
4786lose:
4787 *p = c;
4788 return (startp);
4789}
4790
4791
Eric Andersen2870d962001-07-02 17:27:21 +00004792static void
4793removerecordregions(int endoff)
Eric Andersencb57d552001-06-28 07:25:16 +00004794{
4795 if (ifslastp == NULL)
4796 return;
4797
4798 if (ifsfirst.endoff > endoff) {
4799 while (ifsfirst.next != NULL) {
4800 struct ifsregion *ifsp;
4801 INTOFF;
4802 ifsp = ifsfirst.next->next;
4803 ckfree(ifsfirst.next);
4804 ifsfirst.next = ifsp;
4805 INTON;
4806 }
4807 if (ifsfirst.begoff > endoff)
4808 ifslastp = NULL;
4809 else {
4810 ifslastp = &ifsfirst;
4811 ifsfirst.endoff = endoff;
4812 }
4813 return;
4814 }
Eric Andersen2870d962001-07-02 17:27:21 +00004815
Eric Andersencb57d552001-06-28 07:25:16 +00004816 ifslastp = &ifsfirst;
4817 while (ifslastp->next && ifslastp->next->begoff < endoff)
4818 ifslastp=ifslastp->next;
4819 while (ifslastp->next != NULL) {
4820 struct ifsregion *ifsp;
4821 INTOFF;
4822 ifsp = ifslastp->next->next;
4823 ckfree(ifslastp->next);
4824 ifslastp->next = ifsp;
4825 INTON;
4826 }
4827 if (ifslastp->endoff > endoff)
4828 ifslastp->endoff = endoff;
4829}
4830
4831
4832#ifdef ASH_MATH_SUPPORT
4833/*
4834 * Expand arithmetic expression. Backup to start of expression,
4835 * evaluate, place result in (backed up) result, adjust string position.
4836 */
4837static void
Eric Andersen2870d962001-07-02 17:27:21 +00004838expari(int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004839{
4840 char *p, *start;
Eric Andersen34506362001-08-02 05:02:46 +00004841 int errcode;
Eric Andersencb57d552001-06-28 07:25:16 +00004842 int result;
4843 int begoff;
4844 int quotes = flag & (EXP_FULL | EXP_CASE);
4845 int quoted;
4846
Eric Andersen2870d962001-07-02 17:27:21 +00004847 /* ifsfree(); */
Eric Andersencb57d552001-06-28 07:25:16 +00004848
4849 /*
4850 * This routine is slightly over-complicated for
4851 * efficiency. First we make sure there is
4852 * enough space for the result, which may be bigger
4853 * than the expression if we add exponentation. Next we
4854 * scan backwards looking for the start of arithmetic. If the
4855 * next previous character is a CTLESC character, then we
4856 * have to rescan starting from the beginning since CTLESC
4857 * characters have to be processed left to right.
4858 */
4859 CHECKSTRSPACE(10, expdest);
4860 USTPUTC('\0', expdest);
4861 start = stackblock();
4862 p = expdest - 1;
4863 while (*p != CTLARI && p >= start)
4864 --p;
4865 if (*p != CTLARI)
4866 error("missing CTLARI (shouldn't happen)");
4867 if (p > start && *(p-1) == CTLESC)
4868 for (p = start; *p != CTLARI; p++)
4869 if (*p == CTLESC)
4870 p++;
4871
4872 if (p[1] == '"')
4873 quoted=1;
4874 else
4875 quoted=0;
4876 begoff = p - start;
4877 removerecordregions(begoff);
4878 if (quotes)
4879 rmescapes(p+2);
Eric Andersen34506362001-08-02 05:02:46 +00004880 result = arith(p+2, &errcode);
4881 if (errcode < 0) {
4882 if(errcode == -2)
4883 error("divide by zero");
4884 else
4885 error("syntax error: \"%s\"\n", p+2);
4886 }
Eric Andersen3102ac42001-07-06 04:26:23 +00004887 snprintf(p, 12, "%d", result);
Eric Andersencb57d552001-06-28 07:25:16 +00004888
4889 while (*p++)
4890 ;
4891
4892 if (quoted == 0)
4893 recordregion(begoff, p - 1 - start, 0);
4894 result = expdest - p + 1;
4895 STADJUST(-result, expdest);
4896}
Eric Andersen2870d962001-07-02 17:27:21 +00004897#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004898
4899/*
4900 * Expand stuff in backwards quotes.
4901 */
4902
4903static void
4904expbackq(cmd, quoted, flag)
4905 union node *cmd;
4906 int quoted;
4907 int flag;
4908{
4909 volatile struct backcmd in;
4910 int i;
4911 char buf[128];
4912 char *p;
4913 char *dest = expdest;
4914 volatile struct ifsregion saveifs;
4915 struct ifsregion *volatile savelastp;
4916 struct nodelist *volatile saveargbackq;
4917 char lastc;
4918 int startloc = dest - stackblock();
4919 char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
4920 volatile int saveherefd;
4921 int quotes = flag & (EXP_FULL | EXP_CASE);
4922 struct jmploc jmploc;
4923 struct jmploc *volatile savehandler;
4924 int ex;
4925
4926#if __GNUC__
4927 /* Avoid longjmp clobbering */
4928 (void) &dest;
4929 (void) &syntax;
4930#endif
4931
4932 in.fd = -1;
4933 in.buf = 0;
4934 in.jp = 0;
4935
4936 INTOFF;
4937 saveifs = ifsfirst;
4938 savelastp = ifslastp;
4939 saveargbackq = argbackq;
4940 saveherefd = herefd;
4941 herefd = -1;
4942 if ((ex = setjmp(jmploc.loc))) {
4943 goto err1;
4944 }
4945 savehandler = handler;
4946 handler = &jmploc;
4947 INTON;
4948 p = grabstackstr(dest);
4949 evalbackcmd(cmd, (struct backcmd *) &in);
4950 ungrabstackstr(p, dest);
4951err1:
4952 INTOFF;
4953 ifsfirst = saveifs;
4954 ifslastp = savelastp;
4955 argbackq = saveargbackq;
4956 herefd = saveherefd;
4957 if (ex) {
4958 goto err2;
4959 }
4960
4961 p = in.buf;
4962 lastc = '\0';
4963 for (;;) {
4964 if (--in.nleft < 0) {
4965 if (in.fd < 0)
4966 break;
Eric Andersen7467c8d2001-07-12 20:26:32 +00004967 i = safe_read(in.fd, buf, sizeof buf);
Eric Andersencb57d552001-06-28 07:25:16 +00004968 TRACE(("expbackq: read returns %d\n", i));
4969 if (i <= 0)
4970 break;
4971 p = buf;
4972 in.nleft = i - 1;
4973 }
4974 lastc = *p++;
4975 if (lastc != '\0') {
4976 if (quotes && syntax[(int)lastc] == CCTL)
4977 STPUTC(CTLESC, dest);
4978 STPUTC(lastc, dest);
4979 }
4980 }
4981
4982 /* Eat all trailing newlines */
4983 for (; dest > stackblock() && dest[-1] == '\n';)
4984 STUNPUTC(dest);
4985
4986err2:
4987 if (in.fd >= 0)
4988 close(in.fd);
4989 if (in.buf)
4990 ckfree(in.buf);
4991 if (in.jp)
4992 exitstatus = waitforjob(in.jp);
4993 handler = savehandler;
4994 if (ex) {
4995 longjmp(handler->loc, 1);
4996 }
4997 if (quoted == 0)
4998 recordregion(startloc, dest - stackblock(), 0);
4999 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
5000 (dest - stackblock()) - startloc,
5001 (dest - stackblock()) - startloc,
5002 stackblock() + startloc));
5003 expdest = dest;
5004 INTON;
5005}
5006
Eric Andersencb57d552001-06-28 07:25:16 +00005007static int
5008subevalvar(p, str, strloc, subtype, startloc, varflags, quotes)
5009 char *p;
5010 char *str;
5011 int strloc;
5012 int subtype;
5013 int startloc;
5014 int varflags;
5015 int quotes;
5016{
5017 char *startp;
5018 char *loc = NULL;
5019 char *q;
5020 int c = 0;
5021 int saveherefd = herefd;
5022 struct nodelist *saveargbackq = argbackq;
5023 int amount;
5024
5025 herefd = -1;
5026 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5027 STACKSTRNUL(expdest);
5028 herefd = saveherefd;
5029 argbackq = saveargbackq;
5030 startp = stackblock() + startloc;
5031 if (str == NULL)
5032 str = stackblock() + strloc;
5033
5034 switch (subtype) {
5035 case VSASSIGN:
5036 setvar(str, startp, 0);
5037 amount = startp - expdest;
5038 STADJUST(amount, expdest);
5039 varflags &= ~VSNUL;
5040 if (c != 0)
5041 *loc = c;
5042 return 1;
5043
5044 case VSQUESTION:
5045 if (*p != CTLENDVAR) {
Eric Andersen3102ac42001-07-06 04:26:23 +00005046 out2fmt(snlfmt, startp);
Eric Andersencb57d552001-06-28 07:25:16 +00005047 error((char *)NULL);
5048 }
5049 error("%.*s: parameter %snot set", p - str - 1,
5050 str, (varflags & VSNUL) ? "null or "
5051 : nullstr);
5052 /* NOTREACHED */
5053
5054 case VSTRIMLEFT:
5055 for (loc = startp; loc < str; loc++) {
5056 c = *loc;
5057 *loc = '\0';
5058 if (patmatch2(str, startp, quotes))
5059 goto recordleft;
5060 *loc = c;
5061 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00005062 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00005063 }
5064 return 0;
5065
5066 case VSTRIMLEFTMAX:
5067 for (loc = str - 1; loc >= startp;) {
5068 c = *loc;
5069 *loc = '\0';
5070 if (patmatch2(str, startp, quotes))
5071 goto recordleft;
5072 *loc = c;
5073 loc--;
5074 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
5075 for (q = startp; q < loc; q++)
5076 if (*q == CTLESC)
5077 q++;
5078 if (q > loc)
5079 loc--;
5080 }
5081 }
5082 return 0;
5083
5084 case VSTRIMRIGHT:
Eric Andersen2870d962001-07-02 17:27:21 +00005085 for (loc = str - 1; loc >= startp;) {
Eric Andersencb57d552001-06-28 07:25:16 +00005086 if (patmatch2(str, loc, quotes))
5087 goto recordright;
5088 loc--;
Eric Andersen2870d962001-07-02 17:27:21 +00005089 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
Eric Andersencb57d552001-06-28 07:25:16 +00005090 for (q = startp; q < loc; q++)
5091 if (*q == CTLESC)
5092 q++;
5093 if (q > loc)
5094 loc--;
5095 }
5096 }
5097 return 0;
5098
5099 case VSTRIMRIGHTMAX:
5100 for (loc = startp; loc < str - 1; loc++) {
5101 if (patmatch2(str, loc, quotes))
5102 goto recordright;
5103 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00005104 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00005105 }
5106 return 0;
5107
5108#ifdef DEBUG
5109 default:
5110 abort();
5111#endif
5112 }
5113
5114recordleft:
5115 *loc = c;
5116 amount = ((str - 1) - (loc - startp)) - expdest;
5117 STADJUST(amount, expdest);
5118 while (loc != str - 1)
5119 *startp++ = *loc++;
5120 return 1;
5121
5122recordright:
5123 amount = loc - expdest;
5124 STADJUST(amount, expdest);
5125 STPUTC('\0', expdest);
5126 STADJUST(-1, expdest);
5127 return 1;
5128}
5129
5130
5131/*
Eric Andersencb57d552001-06-28 07:25:16 +00005132 * Test whether a specialized variable is set.
5133 */
5134
5135static int
5136varisset(name, nulok)
5137 char *name;
5138 int nulok;
5139{
5140 if (*name == '!')
5141 return backgndpid != -1;
5142 else if (*name == '@' || *name == '*') {
5143 if (*shellparam.p == NULL)
5144 return 0;
5145
5146 if (nulok) {
5147 char **av;
5148
5149 for (av = shellparam.p; *av; av++)
5150 if (**av != '\0')
5151 return 1;
5152 return 0;
5153 }
5154 } else if (is_digit(*name)) {
5155 char *ap;
5156 int num = atoi(name);
5157
5158 if (num > shellparam.nparam)
5159 return 0;
5160
5161 if (num == 0)
5162 ap = arg0;
5163 else
5164 ap = shellparam.p[num - 1];
5165
5166 if (nulok && (ap == NULL || *ap == '\0'))
5167 return 0;
5168 }
5169 return 1;
5170}
5171
Eric Andersencb57d552001-06-28 07:25:16 +00005172/*
5173 * Put a string on the stack.
5174 */
5175
5176static void
5177strtodest(p, syntax, quotes)
5178 const char *p;
5179 const char *syntax;
5180 int quotes;
5181{
5182 while (*p) {
5183 if (quotes && syntax[(int) *p] == CCTL)
5184 STPUTC(CTLESC, expdest);
5185 STPUTC(*p++, expdest);
5186 }
5187}
5188
Eric Andersencb57d552001-06-28 07:25:16 +00005189/*
5190 * Add the value of a specialized variable to the stack string.
5191 */
5192
5193static void
5194varvalue(name, quoted, flags)
5195 char *name;
5196 int quoted;
5197 int flags;
5198{
5199 int num;
5200 char *p;
5201 int i;
5202 int sep;
5203 int sepq = 0;
5204 char **ap;
5205 char const *syntax;
5206 int allow_split = flags & EXP_FULL;
5207 int quotes = flags & (EXP_FULL | EXP_CASE);
5208
5209 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5210 switch (*name) {
5211 case '$':
5212 num = rootpid;
5213 goto numvar;
5214 case '?':
5215 num = oexitstatus;
5216 goto numvar;
5217 case '#':
5218 num = shellparam.nparam;
5219 goto numvar;
5220 case '!':
5221 num = backgndpid;
5222numvar:
5223 expdest = cvtnum(num, expdest);
5224 break;
5225 case '-':
5226 for (i = 0 ; i < NOPTS ; i++) {
Eric Andersen2870d962001-07-02 17:27:21 +00005227 if (optent_val(i))
5228 STPUTC(optent_letter(optlist[i]), expdest);
Eric Andersencb57d552001-06-28 07:25:16 +00005229 }
5230 break;
5231 case '@':
5232 if (allow_split && quoted) {
5233 sep = 1 << CHAR_BIT;
5234 goto param;
5235 }
5236 /* fall through */
5237 case '*':
5238 sep = ifsset() ? ifsval()[0] : ' ';
5239 if (quotes) {
5240 sepq = syntax[(int) sep] == CCTL;
5241 }
5242param:
5243 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
5244 strtodest(p, syntax, quotes);
5245 if (*ap && sep) {
5246 if (sepq)
5247 STPUTC(CTLESC, expdest);
5248 STPUTC(sep, expdest);
5249 }
5250 }
5251 break;
5252 case '0':
5253 strtodest(arg0, syntax, quotes);
5254 break;
5255 default:
5256 num = atoi(name);
5257 if (num > 0 && num <= shellparam.nparam) {
5258 strtodest(shellparam.p[num - 1], syntax, quotes);
5259 }
5260 break;
5261 }
5262}
5263
5264
Eric Andersencb57d552001-06-28 07:25:16 +00005265/*
5266 * Record the fact that we have to scan this region of the
5267 * string for IFS characters.
5268 */
5269
5270static void
5271recordregion(start, end, nulonly)
5272 int start;
5273 int end;
5274 int nulonly;
5275{
5276 struct ifsregion *ifsp;
5277
5278 if (ifslastp == NULL) {
5279 ifsp = &ifsfirst;
5280 } else {
5281 INTOFF;
5282 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
5283 ifsp->next = NULL;
5284 ifslastp->next = ifsp;
5285 INTON;
5286 }
5287 ifslastp = ifsp;
5288 ifslastp->begoff = start;
5289 ifslastp->endoff = end;
5290 ifslastp->nulonly = nulonly;
5291}
5292
5293
5294
5295/*
5296 * Break the argument string into pieces based upon IFS and add the
5297 * strings to the argument list. The regions of the string to be
5298 * searched for IFS characters have been stored by recordregion.
5299 */
5300static void
5301ifsbreakup(string, arglist)
5302 char *string;
5303 struct arglist *arglist;
5304 {
5305 struct ifsregion *ifsp;
5306 struct strlist *sp;
5307 char *start;
5308 char *p;
5309 char *q;
5310 const char *ifs, *realifs;
5311 int ifsspc;
5312 int nulonly;
5313
5314
5315 start = string;
5316 ifsspc = 0;
5317 nulonly = 0;
5318 realifs = ifsset() ? ifsval() : defifs;
5319 if (ifslastp != NULL) {
5320 ifsp = &ifsfirst;
5321 do {
5322 p = string + ifsp->begoff;
5323 nulonly = ifsp->nulonly;
5324 ifs = nulonly ? nullstr : realifs;
5325 ifsspc = 0;
5326 while (p < string + ifsp->endoff) {
5327 q = p;
5328 if (*p == CTLESC)
5329 p++;
5330 if (strchr(ifs, *p)) {
5331 if (!nulonly)
5332 ifsspc = (strchr(defifs, *p) != NULL);
5333 /* Ignore IFS whitespace at start */
5334 if (q == start && ifsspc) {
5335 p++;
5336 start = p;
5337 continue;
5338 }
5339 *q = '\0';
5340 sp = (struct strlist *)stalloc(sizeof *sp);
5341 sp->text = start;
5342 *arglist->lastp = sp;
5343 arglist->lastp = &sp->next;
5344 p++;
5345 if (!nulonly) {
5346 for (;;) {
5347 if (p >= string + ifsp->endoff) {
5348 break;
5349 }
5350 q = p;
5351 if (*p == CTLESC)
5352 p++;
5353 if (strchr(ifs, *p) == NULL ) {
5354 p = q;
5355 break;
5356 } else if (strchr(defifs, *p) == NULL) {
5357 if (ifsspc) {
5358 p++;
5359 ifsspc = 0;
5360 } else {
5361 p = q;
5362 break;
5363 }
5364 } else
5365 p++;
5366 }
5367 }
5368 start = p;
5369 } else
5370 p++;
5371 }
5372 } while ((ifsp = ifsp->next) != NULL);
5373 if (!(*start || (!ifsspc && start > string && nulonly))) {
5374 return;
5375 }
5376 }
5377
5378 sp = (struct strlist *)stalloc(sizeof *sp);
5379 sp->text = start;
5380 *arglist->lastp = sp;
5381 arglist->lastp = &sp->next;
5382}
5383
5384static void
5385ifsfree()
5386{
5387 while (ifsfirst.next != NULL) {
5388 struct ifsregion *ifsp;
5389 INTOFF;
5390 ifsp = ifsfirst.next->next;
5391 ckfree(ifsfirst.next);
5392 ifsfirst.next = ifsp;
5393 INTON;
5394 }
5395 ifslastp = NULL;
5396 ifsfirst.next = NULL;
5397}
5398
Eric Andersen2870d962001-07-02 17:27:21 +00005399/*
5400 * Add a file name to the list.
5401 */
Eric Andersencb57d552001-06-28 07:25:16 +00005402
Eric Andersen2870d962001-07-02 17:27:21 +00005403static void
5404addfname(const char *name)
5405{
5406 char *p;
5407 struct strlist *sp;
5408
5409 p = sstrdup(name);
5410 sp = (struct strlist *)stalloc(sizeof *sp);
5411 sp->text = p;
5412 *exparg.lastp = sp;
5413 exparg.lastp = &sp->next;
5414}
Eric Andersencb57d552001-06-28 07:25:16 +00005415
5416/*
5417 * Expand shell metacharacters. At this point, the only control characters
5418 * should be escapes. The results are stored in the list exparg.
5419 */
5420
Eric Andersen62483552001-07-10 06:09:16 +00005421#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00005422static void
5423expandmeta(str, flag)
5424 struct strlist *str;
5425 int flag;
5426{
5427 const char *p;
5428 glob_t pglob;
5429 /* TODO - EXP_REDIR */
5430
5431 while (str) {
5432 if (fflag)
5433 goto nometa;
5434 p = preglob(str->text);
5435 INTOFF;
Eric Andersen34506362001-08-02 05:02:46 +00005436 switch (glob(p, 0, 0, &pglob)) {
Eric Andersencb57d552001-06-28 07:25:16 +00005437 case 0:
Eric Andersen34506362001-08-02 05:02:46 +00005438 if(pglob.gl_pathv[1]==0 && !strcmp(p, pglob.gl_pathv[0]))
Eric Andersencb57d552001-06-28 07:25:16 +00005439 goto nometa2;
5440 addglob(&pglob);
5441 globfree(&pglob);
5442 INTON;
5443 break;
5444 case GLOB_NOMATCH:
5445nometa2:
5446 globfree(&pglob);
5447 INTON;
5448nometa:
5449 *exparg.lastp = str;
5450 rmescapes(str->text);
5451 exparg.lastp = &str->next;
5452 break;
Eric Andersen2870d962001-07-02 17:27:21 +00005453 default: /* GLOB_NOSPACE */
Eric Andersencb57d552001-06-28 07:25:16 +00005454 error("Out of space");
5455 }
5456 str = str->next;
5457 }
5458}
5459
5460
5461/*
5462 * Add the result of glob(3) to the list.
5463 */
5464
5465static void
5466addglob(pglob)
5467 const glob_t *pglob;
5468{
5469 char **p = pglob->gl_pathv;
5470
5471 do {
5472 addfname(*p);
5473 } while (*++p);
5474}
5475
5476
Eric Andersen2870d962001-07-02 17:27:21 +00005477#else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005478static char *expdir;
5479
5480
5481static void
5482expandmeta(str, flag)
5483 struct strlist *str;
5484 int flag;
5485{
5486 char *p;
5487 struct strlist **savelastp;
5488 struct strlist *sp;
5489 char c;
5490 /* TODO - EXP_REDIR */
5491
5492 while (str) {
5493 if (fflag)
5494 goto nometa;
5495 p = str->text;
Eric Andersen2870d962001-07-02 17:27:21 +00005496 for (;;) { /* fast check for meta chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005497 if ((c = *p++) == '\0')
5498 goto nometa;
5499 if (c == '*' || c == '?' || c == '[' || c == '!')
5500 break;
5501 }
5502 savelastp = exparg.lastp;
5503 INTOFF;
5504 if (expdir == NULL) {
5505 int i = strlen(str->text);
5506 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5507 }
5508
5509 expmeta(expdir, str->text);
5510 ckfree(expdir);
5511 expdir = NULL;
5512 INTON;
5513 if (exparg.lastp == savelastp) {
5514 /*
5515 * no matches
5516 */
5517nometa:
5518 *exparg.lastp = str;
5519 rmescapes(str->text);
5520 exparg.lastp = &str->next;
5521 } else {
5522 *exparg.lastp = NULL;
5523 *savelastp = sp = expsort(*savelastp);
5524 while (sp->next != NULL)
5525 sp = sp->next;
5526 exparg.lastp = &sp->next;
5527 }
5528 str = str->next;
5529 }
5530}
5531
5532
5533/*
5534 * Do metacharacter (i.e. *, ?, [...]) expansion.
5535 */
5536
5537static void
5538expmeta(enddir, name)
5539 char *enddir;
5540 char *name;
5541 {
5542 char *p;
5543 const char *cp;
5544 char *q;
5545 char *start;
5546 char *endname;
5547 int metaflag;
5548 struct stat statb;
5549 DIR *dirp;
5550 struct dirent *dp;
5551 int atend;
5552 int matchdot;
5553
5554 metaflag = 0;
5555 start = name;
5556 for (p = name ; ; p++) {
5557 if (*p == '*' || *p == '?')
5558 metaflag = 1;
5559 else if (*p == '[') {
5560 q = p + 1;
5561 if (*q == '!')
5562 q++;
5563 for (;;) {
5564 while (*q == CTLQUOTEMARK)
5565 q++;
5566 if (*q == CTLESC)
5567 q++;
5568 if (*q == '/' || *q == '\0')
5569 break;
5570 if (*++q == ']') {
5571 metaflag = 1;
5572 break;
5573 }
5574 }
Eric Andersen2870d962001-07-02 17:27:21 +00005575 } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) {
Eric Andersencb57d552001-06-28 07:25:16 +00005576 metaflag = 1;
5577 } else if (*p == '\0')
5578 break;
5579 else if (*p == CTLQUOTEMARK)
5580 continue;
5581 else if (*p == CTLESC)
5582 p++;
5583 if (*p == '/') {
5584 if (metaflag)
5585 break;
5586 start = p + 1;
5587 }
5588 }
Eric Andersen2870d962001-07-02 17:27:21 +00005589 if (metaflag == 0) { /* we've reached the end of the file name */
Eric Andersencb57d552001-06-28 07:25:16 +00005590 if (enddir != expdir)
5591 metaflag++;
5592 for (p = name ; ; p++) {
5593 if (*p == CTLQUOTEMARK)
5594 continue;
5595 if (*p == CTLESC)
5596 p++;
5597 *enddir++ = *p;
5598 if (*p == '\0')
5599 break;
5600 }
5601 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5602 addfname(expdir);
5603 return;
5604 }
5605 endname = p;
5606 if (start != name) {
5607 p = name;
5608 while (p < start) {
5609 while (*p == CTLQUOTEMARK)
5610 p++;
5611 if (*p == CTLESC)
5612 p++;
5613 *enddir++ = *p++;
5614 }
5615 }
5616 if (enddir == expdir) {
5617 cp = ".";
5618 } else if (enddir == expdir + 1 && *expdir == '/') {
5619 cp = "/";
5620 } else {
5621 cp = expdir;
5622 enddir[-1] = '\0';
5623 }
5624 if ((dirp = opendir(cp)) == NULL)
5625 return;
5626 if (enddir != expdir)
5627 enddir[-1] = '/';
5628 if (*endname == 0) {
5629 atend = 1;
5630 } else {
5631 atend = 0;
5632 *endname++ = '\0';
5633 }
5634 matchdot = 0;
5635 p = start;
5636 while (*p == CTLQUOTEMARK)
5637 p++;
5638 if (*p == CTLESC)
5639 p++;
5640 if (*p == '.')
5641 matchdot++;
5642 while (! int_pending() && (dp = readdir(dirp)) != NULL) {
5643 if (dp->d_name[0] == '.' && ! matchdot)
5644 continue;
5645 if (patmatch(start, dp->d_name, 0)) {
5646 if (atend) {
Eric Andersen2870d962001-07-02 17:27:21 +00005647 strcpy(enddir, dp->d_name);
Eric Andersencb57d552001-06-28 07:25:16 +00005648 addfname(expdir);
5649 } else {
5650 for (p = enddir, cp = dp->d_name;
5651 (*p++ = *cp++) != '\0';)
5652 continue;
5653 p[-1] = '/';
5654 expmeta(p, endname);
5655 }
5656 }
5657 }
5658 closedir(dirp);
5659 if (! atend)
5660 endname[-1] = '/';
5661}
Eric Andersen2870d962001-07-02 17:27:21 +00005662#endif /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005663
5664
Eric Andersencb57d552001-06-28 07:25:16 +00005665
Eric Andersen62483552001-07-10 06:09:16 +00005666#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersencb57d552001-06-28 07:25:16 +00005667/*
5668 * Sort the results of file name expansion. It calculates the number of
5669 * strings to sort and then calls msort (short for merge sort) to do the
5670 * work.
5671 */
5672
5673static struct strlist *
5674expsort(str)
5675 struct strlist *str;
5676 {
5677 int len;
5678 struct strlist *sp;
5679
5680 len = 0;
5681 for (sp = str ; sp ; sp = sp->next)
5682 len++;
5683 return msort(str, len);
5684}
5685
5686
5687static struct strlist *
5688msort(list, len)
5689 struct strlist *list;
5690 int len;
5691{
5692 struct strlist *p, *q = NULL;
5693 struct strlist **lpp;
5694 int half;
5695 int n;
5696
5697 if (len <= 1)
5698 return list;
5699 half = len >> 1;
5700 p = list;
5701 for (n = half ; --n >= 0 ; ) {
5702 q = p;
5703 p = p->next;
5704 }
Eric Andersen2870d962001-07-02 17:27:21 +00005705 q->next = NULL; /* terminate first half of list */
5706 q = msort(list, half); /* sort first half of list */
5707 p = msort(p, len - half); /* sort second half */
Eric Andersencb57d552001-06-28 07:25:16 +00005708 lpp = &list;
5709 for (;;) {
5710 if (strcmp(p->text, q->text) < 0) {
5711 *lpp = p;
5712 lpp = &p->next;
5713 if ((p = *lpp) == NULL) {
5714 *lpp = q;
5715 break;
5716 }
5717 } else {
5718 *lpp = q;
5719 lpp = &q->next;
5720 if ((q = *lpp) == NULL) {
5721 *lpp = p;
5722 break;
5723 }
5724 }
5725 }
5726 return list;
5727}
5728#endif
5729
5730
5731
5732/*
5733 * Returns true if the pattern matches the string.
5734 */
5735
Eric Andersen62483552001-07-10 06:09:16 +00005736#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00005737/* squoted: string might have quote chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005738static int
Eric Andersen2870d962001-07-02 17:27:21 +00005739patmatch(char *pattern, char *string, int squoted)
5740{
Eric Andersencb57d552001-06-28 07:25:16 +00005741 const char *p;
5742 char *q;
5743
5744 p = preglob(pattern);
5745 q = squoted ? _rmescapes(string, RMESCAPE_ALLOC) : string;
5746
5747 return !fnmatch(p, q, 0);
5748}
5749
5750
5751static int
Eric Andersen2870d962001-07-02 17:27:21 +00005752patmatch2(char *pattern, char *string, int squoted)
5753{
Eric Andersencb57d552001-06-28 07:25:16 +00005754 char *p;
5755 int res;
5756
5757 sstrnleft--;
5758 p = grabstackstr(expdest);
5759 res = patmatch(pattern, string, squoted);
5760 ungrabstackstr(p, expdest);
5761 return res;
5762}
5763#else
5764static int
Eric Andersen2870d962001-07-02 17:27:21 +00005765patmatch(char *pattern, char *string, int squoted) {
5766 return pmatch(pattern, string, squoted);
Eric Andersencb57d552001-06-28 07:25:16 +00005767}
5768
5769
5770static int
Eric Andersen2870d962001-07-02 17:27:21 +00005771pmatch(char *pattern, char *string, int squoted)
5772{
Eric Andersencb57d552001-06-28 07:25:16 +00005773 char *p, *q;
5774 char c;
5775
5776 p = pattern;
5777 q = string;
5778 for (;;) {
5779 switch (c = *p++) {
5780 case '\0':
5781 goto breakloop;
5782 case CTLESC:
5783 if (squoted && *q == CTLESC)
5784 q++;
5785 if (*q++ != *p++)
5786 return 0;
5787 break;
5788 case CTLQUOTEMARK:
5789 continue;
5790 case '?':
5791 if (squoted && *q == CTLESC)
5792 q++;
5793 if (*q++ == '\0')
5794 return 0;
5795 break;
5796 case '*':
5797 c = *p;
5798 while (c == CTLQUOTEMARK || c == '*')
5799 c = *++p;
5800 if (c != CTLESC && c != CTLQUOTEMARK &&
5801 c != '?' && c != '*' && c != '[') {
5802 while (*q != c) {
5803 if (squoted && *q == CTLESC &&
5804 q[1] == c)
5805 break;
5806 if (*q == '\0')
5807 return 0;
5808 if (squoted && *q == CTLESC)
5809 q++;
5810 q++;
5811 }
5812 }
5813 do {
5814 if (pmatch(p, q, squoted))
5815 return 1;
5816 if (squoted && *q == CTLESC)
5817 q++;
5818 } while (*q++ != '\0');
5819 return 0;
5820 case '[': {
5821 char *endp;
5822 int invert, found;
5823 char chr;
5824
5825 endp = p;
5826 if (*endp == '!')
5827 endp++;
5828 for (;;) {
5829 while (*endp == CTLQUOTEMARK)
5830 endp++;
5831 if (*endp == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00005832 goto dft; /* no matching ] */
Eric Andersencb57d552001-06-28 07:25:16 +00005833 if (*endp == CTLESC)
5834 endp++;
5835 if (*++endp == ']')
5836 break;
5837 }
5838 invert = 0;
5839 if (*p == '!') {
5840 invert++;
5841 p++;
5842 }
5843 found = 0;
5844 chr = *q++;
5845 if (squoted && chr == CTLESC)
5846 chr = *q++;
5847 if (chr == '\0')
5848 return 0;
5849 c = *p++;
5850 do {
5851 if (c == CTLQUOTEMARK)
5852 continue;
5853 if (c == CTLESC)
5854 c = *p++;
5855 if (*p == '-' && p[1] != ']') {
5856 p++;
5857 while (*p == CTLQUOTEMARK)
5858 p++;
5859 if (*p == CTLESC)
5860 p++;
5861 if (chr >= c && chr <= *p)
5862 found = 1;
5863 p++;
5864 } else {
5865 if (chr == c)
5866 found = 1;
5867 }
5868 } while ((c = *p++) != ']');
5869 if (found == invert)
5870 return 0;
5871 break;
5872 }
Eric Andersen2870d962001-07-02 17:27:21 +00005873dft: default:
Eric Andersencb57d552001-06-28 07:25:16 +00005874 if (squoted && *q == CTLESC)
5875 q++;
5876 if (*q++ != c)
5877 return 0;
5878 break;
5879 }
5880 }
5881breakloop:
5882 if (*q != '\0')
5883 return 0;
5884 return 1;
5885}
5886#endif
5887
5888
5889
5890/*
5891 * Remove any CTLESC characters from a string.
5892 */
5893
Eric Andersen62483552001-07-10 06:09:16 +00005894#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00005895static char *
Eric Andersen2870d962001-07-02 17:27:21 +00005896_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005897{
5898 char *p, *q, *r;
5899 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5900
5901 p = strpbrk(str, qchars);
5902 if (!p) {
5903 return str;
5904 }
5905 q = p;
5906 r = str;
5907 if (flag & RMESCAPE_ALLOC) {
5908 size_t len = p - str;
5909 q = r = stalloc(strlen(p) + len + 1);
5910 if (len > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00005911 memcpy(q, str, len);
5912 q += len;
Eric Andersencb57d552001-06-28 07:25:16 +00005913 }
5914 }
5915 while (*p) {
5916 if (*p == CTLQUOTEMARK) {
5917 p++;
5918 continue;
5919 }
5920 if (*p == CTLESC) {
5921 p++;
5922 if (flag & RMESCAPE_GLOB && *p != '/') {
5923 *q++ = '\\';
5924 }
5925 }
5926 *q++ = *p++;
5927 }
5928 *q = '\0';
5929 return r;
5930}
5931#else
5932static void
5933rmescapes(str)
5934 char *str;
5935{
5936 char *p, *q;
5937
5938 p = str;
5939 while (*p != CTLESC && *p != CTLQUOTEMARK) {
5940 if (*p++ == '\0')
5941 return;
5942 }
5943 q = p;
5944 while (*p) {
5945 if (*p == CTLQUOTEMARK) {
5946 p++;
5947 continue;
5948 }
5949 if (*p == CTLESC)
5950 p++;
5951 *q++ = *p++;
5952 }
5953 *q = '\0';
5954}
5955#endif
5956
5957
5958
5959/*
5960 * See if a pattern matches in a case statement.
5961 */
5962
5963static int
Eric Andersen2870d962001-07-02 17:27:21 +00005964casematch(union node *pattern, const char *val)
5965{
Eric Andersencb57d552001-06-28 07:25:16 +00005966 struct stackmark smark;
5967 int result;
5968 char *p;
5969
5970 setstackmark(&smark);
5971 argbackq = pattern->narg.backquote;
5972 STARTSTACKSTR(expdest);
5973 ifslastp = NULL;
5974 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5975 STPUTC('\0', expdest);
5976 p = grabstackstr(expdest);
Eric Andersen2870d962001-07-02 17:27:21 +00005977 result = patmatch(p, (char *)val, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00005978 popstackmark(&smark);
5979 return result;
5980}
5981
5982/*
5983 * Our own itoa().
5984 */
5985
5986static char *
5987cvtnum(num, buf)
5988 int num;
5989 char *buf;
5990 {
5991 int len;
5992
5993 CHECKSTRSPACE(32, buf);
5994 len = sprintf(buf, "%d", num);
5995 STADJUST(len, buf);
5996 return buf;
5997}
Eric Andersencb57d552001-06-28 07:25:16 +00005998/*
5999 * Editline and history functions (and glue).
6000 */
6001static int histcmd(argc, argv)
6002 int argc;
6003 char **argv;
6004{
6005 error("not compiled with history support");
6006 /* NOTREACHED */
6007}
6008
6009
Eric Andersencb57d552001-06-28 07:25:16 +00006010struct redirtab {
6011 struct redirtab *next;
Russ Dill4db35642001-07-26 05:58:40 +00006012 short renamed[10]; /* Current ash support only 0-9 descriptors */
Eric Andersen34506362001-08-02 05:02:46 +00006013 /* char on arm (and others) can't be negative */
Eric Andersencb57d552001-06-28 07:25:16 +00006014};
6015
Eric Andersen2870d962001-07-02 17:27:21 +00006016static struct redirtab *redirlist;
Eric Andersencb57d552001-06-28 07:25:16 +00006017
6018extern char **environ;
6019
6020
6021
6022/*
6023 * Initialization code.
6024 */
6025
6026static void
Eric Andersen2870d962001-07-02 17:27:21 +00006027init(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00006028
6029 /* from cd.c: */
6030 {
6031 setpwd(0, 0);
6032 }
6033
6034 /* from input.c: */
6035 {
6036 basepf.nextc = basepf.buf = basebuf;
6037 }
6038
Eric Andersencb57d552001-06-28 07:25:16 +00006039 /* from var.c: */
6040 {
6041 char **envp;
6042 char ppid[32];
6043
6044 initvar();
6045 for (envp = environ ; *envp ; envp++) {
6046 if (strchr(*envp, '=')) {
6047 setvareq(*envp, VEXPORT|VTEXTFIXED);
6048 }
6049 }
6050
Eric Andersen3102ac42001-07-06 04:26:23 +00006051 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
Eric Andersencb57d552001-06-28 07:25:16 +00006052 setvar("PPID", ppid, 0);
6053 }
6054}
6055
6056
6057
6058/*
6059 * This routine is called when an error or an interrupt occurs in an
6060 * interactive shell and control is returned to the main command loop.
6061 */
6062
Eric Andersen2870d962001-07-02 17:27:21 +00006063/* 1 == check for aliases, 2 == also check for assignments */
Eric Andersen7467c8d2001-07-12 20:26:32 +00006064static int checkalias; /* also used in no alias mode for check assignments */
Eric Andersen2870d962001-07-02 17:27:21 +00006065
Eric Andersencb57d552001-06-28 07:25:16 +00006066static void
Eric Andersen2870d962001-07-02 17:27:21 +00006067reset(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00006068
6069 /* from eval.c: */
6070 {
6071 evalskip = 0;
6072 loopnest = 0;
6073 funcnest = 0;
6074 }
6075
6076 /* from input.c: */
6077 {
6078 if (exception != EXSHELLPROC)
Eric Andersen2870d962001-07-02 17:27:21 +00006079 parselleft = parsenleft = 0; /* clear input buffer */
Eric Andersencb57d552001-06-28 07:25:16 +00006080 popallfiles();
6081 }
6082
6083 /* from parser.c: */
6084 {
6085 tokpushback = 0;
6086 checkkwd = 0;
6087 checkalias = 0;
6088 }
6089
6090 /* from redir.c: */
6091 {
6092 while (redirlist)
6093 popredir();
6094 }
6095
Eric Andersencb57d552001-06-28 07:25:16 +00006096}
6097
6098
6099
6100/*
Eric Andersencb57d552001-06-28 07:25:16 +00006101 * This file implements the input routines used by the parser.
6102 */
6103
6104#ifdef BB_FEATURE_COMMAND_EDITING
Eric Andersencb57d552001-06-28 07:25:16 +00006105static const char * cmdedit_prompt;
6106static inline void putprompt(const char *s) {
6107 cmdedit_prompt = s;
6108}
6109#else
6110static inline void putprompt(const char *s) {
6111 out2str(s);
6112}
6113#endif
6114
Eric Andersen2870d962001-07-02 17:27:21 +00006115#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
Eric Andersencb57d552001-06-28 07:25:16 +00006116
Eric Andersencb57d552001-06-28 07:25:16 +00006117
Eric Andersencb57d552001-06-28 07:25:16 +00006118
Eric Andersen2870d962001-07-02 17:27:21 +00006119/*
6120 * Same as pgetc(), but ignores PEOA.
6121 */
Eric Andersencb57d552001-06-28 07:25:16 +00006122
Eric Andersen2870d962001-07-02 17:27:21 +00006123#ifdef ASH_ALIAS
6124static int
6125pgetc2()
6126{
6127 int c;
6128 do {
6129 c = pgetc_macro();
6130 } while (c == PEOA);
6131 return c;
Eric Andersencb57d552001-06-28 07:25:16 +00006132}
Eric Andersen2870d962001-07-02 17:27:21 +00006133#else
6134static inline int pgetc2() { return pgetc_macro(); }
Eric Andersencb57d552001-06-28 07:25:16 +00006135#endif
6136
Eric Andersencb57d552001-06-28 07:25:16 +00006137/*
6138 * Read a line from the script.
6139 */
6140
Eric Andersen62483552001-07-10 06:09:16 +00006141static inline char *
Eric Andersen2870d962001-07-02 17:27:21 +00006142pfgets(char *line, int len)
Eric Andersencb57d552001-06-28 07:25:16 +00006143{
6144 char *p = line;
6145 int nleft = len;
6146 int c;
6147
6148 while (--nleft > 0) {
6149 c = pgetc2();
6150 if (c == PEOF) {
6151 if (p == line)
6152 return NULL;
6153 break;
6154 }
6155 *p++ = c;
6156 if (c == '\n')
6157 break;
6158 }
6159 *p = '\0';
6160 return line;
6161}
6162
Eric Andersen62483552001-07-10 06:09:16 +00006163static inline int
Eric Andersen2870d962001-07-02 17:27:21 +00006164preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006165{
6166 int nr;
6167 char *buf = parsefile->buf;
6168 parsenextc = buf;
6169
6170retry:
6171#ifdef BB_FEATURE_COMMAND_EDITING
6172 {
Eric Andersen34506362001-08-02 05:02:46 +00006173 if (!iflag || parsefile->fd)
Eric Andersen7467c8d2001-07-12 20:26:32 +00006174 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersen2870d962001-07-02 17:27:21 +00006175 else {
Eric Andersen044228d2001-07-17 01:12:36 +00006176 nr = cmdedit_read_input((char*)cmdedit_prompt, buf);
Eric Andersencb57d552001-06-28 07:25:16 +00006177 }
6178 }
6179#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00006180 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006181#endif
6182
6183 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006184 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6185 int flags = fcntl(0, F_GETFL, 0);
6186 if (flags >= 0 && flags & O_NONBLOCK) {
6187 flags &=~ O_NONBLOCK;
6188 if (fcntl(0, F_SETFL, flags) >= 0) {
6189 out2str("sh: turning off NDELAY mode\n");
6190 goto retry;
6191 }
6192 }
6193 }
6194 }
6195 return nr;
6196}
6197
Eric Andersen2870d962001-07-02 17:27:21 +00006198static void
6199popstring(void)
6200{
6201 struct strpush *sp = parsefile->strpush;
6202
6203 INTOFF;
6204#ifdef ASH_ALIAS
6205 if (sp->ap) {
6206 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6207 if (!checkalias) {
6208 checkalias = 1;
6209 }
6210 }
6211 if (sp->string != sp->ap->val) {
6212 ckfree(sp->string);
6213 }
6214
6215 sp->ap->flag &= ~ALIASINUSE;
6216 if (sp->ap->flag & ALIASDEAD) {
6217 unalias(sp->ap->name);
6218 }
6219 }
6220#endif
6221 parsenextc = sp->prevstring;
6222 parsenleft = sp->prevnleft;
6223/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6224 parsefile->strpush = sp->prev;
6225 if (sp != &(parsefile->basestrpush))
6226 ckfree(sp);
6227 INTON;
6228}
6229
6230
Eric Andersencb57d552001-06-28 07:25:16 +00006231/*
6232 * Refill the input buffer and return the next input character:
6233 *
6234 * 1) If a string was pushed back on the input, pop it;
6235 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6236 * from a string so we can't refill the buffer, return EOF.
6237 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6238 * 4) Process input up to the next newline, deleting nul characters.
6239 */
6240
6241static int
Eric Andersen2870d962001-07-02 17:27:21 +00006242preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006243{
6244 char *p, *q;
6245 int more;
6246 char savec;
6247
6248 while (parsefile->strpush) {
Eric Andersen2870d962001-07-02 17:27:21 +00006249#ifdef ASH_ALIAS
6250 if (parsenleft == -1 && parsefile->strpush->ap &&
6251 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00006252 return PEOA;
6253 }
Eric Andersen2870d962001-07-02 17:27:21 +00006254#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006255 popstring();
6256 if (--parsenleft >= 0)
6257 return (*parsenextc++);
6258 }
6259 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6260 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00006261 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00006262
6263again:
6264 if (parselleft <= 0) {
6265 if ((parselleft = preadfd()) <= 0) {
6266 parselleft = parsenleft = EOF_NLEFT;
6267 return PEOF;
6268 }
6269 }
6270
6271 q = p = parsenextc;
6272
6273 /* delete nul characters */
6274 for (more = 1; more;) {
6275 switch (*p) {
6276 case '\0':
Eric Andersen2870d962001-07-02 17:27:21 +00006277 p++; /* Skip nul */
Eric Andersencb57d552001-06-28 07:25:16 +00006278 goto check;
6279
6280
6281 case '\n':
6282 parsenleft = q - parsenextc;
6283 more = 0; /* Stop processing here */
6284 break;
6285 }
6286
6287 *q++ = *p++;
6288check:
6289 if (--parselleft <= 0 && more) {
6290 parsenleft = q - parsenextc - 1;
6291 if (parsenleft < 0)
6292 goto again;
6293 more = 0;
6294 }
6295 }
6296
6297 savec = *q;
6298 *q = '\0';
6299
6300 if (vflag) {
6301 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00006302 }
6303
6304 *q = savec;
6305
6306 return *parsenextc++;
6307}
6308
Eric Andersencb57d552001-06-28 07:25:16 +00006309
6310/*
6311 * Push a string back onto the input at this current parsefile level.
6312 * We handle aliases this way.
6313 */
6314static void
Eric Andersen2870d962001-07-02 17:27:21 +00006315pushstring(char *s, int len, void *ap)
6316{
Eric Andersencb57d552001-06-28 07:25:16 +00006317 struct strpush *sp;
6318
6319 INTOFF;
6320/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6321 if (parsefile->strpush) {
6322 sp = ckmalloc(sizeof (struct strpush));
6323 sp->prev = parsefile->strpush;
6324 parsefile->strpush = sp;
6325 } else
6326 sp = parsefile->strpush = &(parsefile->basestrpush);
6327 sp->prevstring = parsenextc;
6328 sp->prevnleft = parsenleft;
Eric Andersen2870d962001-07-02 17:27:21 +00006329#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00006330 sp->ap = (struct alias *)ap;
6331 if (ap) {
6332 ((struct alias *)ap)->flag |= ALIASINUSE;
6333 sp->string = s;
6334 }
Eric Andersen2870d962001-07-02 17:27:21 +00006335#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006336 parsenextc = s;
6337 parsenleft = len;
6338 INTON;
6339}
6340
Eric Andersencb57d552001-06-28 07:25:16 +00006341
Eric Andersencb57d552001-06-28 07:25:16 +00006342/*
6343 * Like setinputfile, but takes input from a string.
6344 */
6345
6346static void
Eric Andersen62483552001-07-10 06:09:16 +00006347setinputstring(char *string)
6348{
Eric Andersencb57d552001-06-28 07:25:16 +00006349 INTOFF;
6350 pushfile();
6351 parsenextc = string;
6352 parsenleft = strlen(string);
6353 parsefile->buf = NULL;
6354 plinno = 1;
6355 INTON;
6356}
6357
6358
6359
6360/*
6361 * To handle the "." command, a stack of input files is used. Pushfile
6362 * adds a new entry to the stack and popfile restores the previous level.
6363 */
6364
6365static void
Eric Andersen2870d962001-07-02 17:27:21 +00006366pushfile(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00006367 struct parsefile *pf;
6368
6369 parsefile->nleft = parsenleft;
6370 parsefile->lleft = parselleft;
6371 parsefile->nextc = parsenextc;
6372 parsefile->linno = plinno;
6373 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6374 pf->prev = parsefile;
6375 pf->fd = -1;
6376 pf->strpush = NULL;
6377 pf->basestrpush.prev = NULL;
6378 parsefile = pf;
6379}
6380
Eric Andersen2870d962001-07-02 17:27:21 +00006381#ifdef JOBS
6382static void restartjob (struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00006383#endif
Eric Andersen2870d962001-07-02 17:27:21 +00006384static void freejob (struct job *);
6385static struct job *getjob (const char *);
6386static int dowait (int, struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00006387static void waitonint(int);
6388
6389
Eric Andersen2870d962001-07-02 17:27:21 +00006390/*
6391 * We keep track of whether or not fd0 has been redirected. This is for
6392 * background commands, where we want to redirect fd0 to /dev/null only
6393 * if it hasn't already been redirected.
6394*/
6395static int fd0_redirected = 0;
6396
6397/* Return true if fd 0 has already been redirected at least once. */
6398static inline int
6399fd0_redirected_p () {
6400 return fd0_redirected != 0;
6401}
6402
Eric Andersen62483552001-07-10 06:09:16 +00006403static void dupredirect (const union node *, int, int fd1dup);
Eric Andersen2870d962001-07-02 17:27:21 +00006404
6405#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006406/*
6407 * Turn job control on and off.
6408 *
6409 * Note: This code assumes that the third arg to ioctl is a character
6410 * pointer, which is true on Berkeley systems but not System V. Since
6411 * System V doesn't have job control yet, this isn't a problem now.
6412 */
6413
Eric Andersen2870d962001-07-02 17:27:21 +00006414
Eric Andersencb57d552001-06-28 07:25:16 +00006415
6416static void setjobctl(int enable)
6417{
6418#ifdef OLD_TTY_DRIVER
6419 int ldisc;
6420#endif
6421
6422 if (enable == jobctl || rootshell == 0)
6423 return;
6424 if (enable) {
6425 do { /* while we are in the background */
6426#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006427 if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006428#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006429 initialpgrp = tcgetpgrp(2);
Eric Andersencb57d552001-06-28 07:25:16 +00006430 if (initialpgrp < 0) {
6431#endif
Eric Andersen8c145dc2001-07-10 16:57:09 +00006432 out2str("sh: can't access tty; job control turned off\n");
Eric Andersencb57d552001-06-28 07:25:16 +00006433 mflag = 0;
6434 return;
6435 }
6436 if (initialpgrp == -1)
6437 initialpgrp = getpgrp();
6438 else if (initialpgrp != getpgrp()) {
6439 killpg(initialpgrp, SIGTTIN);
6440 continue;
6441 }
6442 } while (0);
6443#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006444 if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
Eric Andersen8c145dc2001-07-10 16:57:09 +00006445 out2str("sh: need new tty driver to run job control; job control turned off\n");
Eric Andersencb57d552001-06-28 07:25:16 +00006446 mflag = 0;
6447 return;
6448 }
6449#endif
6450 setsignal(SIGTSTP);
6451 setsignal(SIGTTOU);
6452 setsignal(SIGTTIN);
6453 setpgid(0, rootpid);
6454#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006455 ioctl(2, TIOCSPGRP, (char *)&rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00006456#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006457 tcsetpgrp(2, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00006458#endif
Eric Andersen8c145dc2001-07-10 16:57:09 +00006459 } else { /* turning job control off */
Eric Andersencb57d552001-06-28 07:25:16 +00006460 setpgid(0, initialpgrp);
6461#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006462 ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006463#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006464 tcsetpgrp(2, initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006465#endif
6466 setsignal(SIGTSTP);
6467 setsignal(SIGTTOU);
6468 setsignal(SIGTTIN);
6469 }
6470 jobctl = enable;
6471}
6472#endif
6473
6474
Eric Andersen2870d962001-07-02 17:27:21 +00006475#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006476static int
6477killcmd(argc, argv)
6478 int argc;
6479 char **argv;
6480{
6481 int signo = -1;
6482 int list = 0;
6483 int i;
6484 pid_t pid;
6485 struct job *jp;
6486
6487 if (argc <= 1) {
6488usage:
6489 error(
6490"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6491"kill -l [exitstatus]"
6492 );
6493 }
6494
6495 if (*argv[1] == '-') {
6496 signo = decode_signal(argv[1] + 1, 1);
6497 if (signo < 0) {
6498 int c;
6499
6500 while ((c = nextopt("ls:")) != '\0')
6501 switch (c) {
6502 case 'l':
6503 list = 1;
6504 break;
6505 case 's':
6506 signo = decode_signal(optionarg, 1);
6507 if (signo < 0) {
6508 error(
6509 "invalid signal number or name: %s",
6510 optionarg
6511 );
6512 }
Eric Andersen2870d962001-07-02 17:27:21 +00006513 break;
Eric Andersencb57d552001-06-28 07:25:16 +00006514#ifdef DEBUG
6515 default:
6516 error(
6517 "nextopt returned character code 0%o", c);
6518#endif
6519 }
6520 } else
6521 argptr++;
6522 }
6523
6524 if (!list && signo < 0)
6525 signo = SIGTERM;
6526
6527 if ((signo < 0 || !*argptr) ^ list) {
6528 goto usage;
6529 }
6530
6531 if (list) {
Eric Andersen34506362001-08-02 05:02:46 +00006532 const char *name;
6533
Eric Andersencb57d552001-06-28 07:25:16 +00006534 if (!*argptr) {
6535 out1str("0\n");
6536 for (i = 1; i < NSIG; i++) {
Eric Andersen34506362001-08-02 05:02:46 +00006537 name = u_signal_names(0, &i, 1);
6538 if(name)
6539 printf(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006540 }
6541 return 0;
6542 }
Eric Andersen34506362001-08-02 05:02:46 +00006543 name = u_signal_names(*argptr, &signo, -1);
6544 if (name)
6545 printf(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006546 else
6547 error("invalid signal number or exit status: %s",
6548 *argptr);
6549 return 0;
6550 }
6551
6552 do {
6553 if (**argptr == '%') {
6554 jp = getjob(*argptr);
6555 if (jp->jobctl == 0)
6556 error("job %s not created under job control",
6557 *argptr);
6558 pid = -jp->ps[0].pid;
6559 } else
6560 pid = atoi(*argptr);
6561 if (kill(pid, signo) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00006562 error("%s: %m", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006563 } while (*++argptr);
6564
6565 return 0;
6566}
6567
6568static int
6569fgcmd(argc, argv)
6570 int argc;
6571 char **argv;
6572{
6573 struct job *jp;
6574 int pgrp;
6575 int status;
6576
6577 jp = getjob(argv[1]);
6578 if (jp->jobctl == 0)
6579 error("job not created under job control");
6580 pgrp = jp->ps[0].pid;
6581#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006582 ioctl(2, TIOCSPGRP, (char *)&pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006583#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006584 tcsetpgrp(2, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006585#endif
6586 restartjob(jp);
6587 INTOFF;
6588 status = waitforjob(jp);
6589 INTON;
6590 return status;
6591}
6592
6593
6594static int
6595bgcmd(argc, argv)
6596 int argc;
6597 char **argv;
6598{
6599 struct job *jp;
6600
6601 do {
6602 jp = getjob(*++argv);
6603 if (jp->jobctl == 0)
6604 error("job not created under job control");
6605 restartjob(jp);
6606 } while (--argc > 1);
6607 return 0;
6608}
6609
6610
6611static void
6612restartjob(jp)
6613 struct job *jp;
6614{
6615 struct procstat *ps;
6616 int i;
6617
6618 if (jp->state == JOBDONE)
6619 return;
6620 INTOFF;
6621 killpg(jp->ps[0].pid, SIGCONT);
6622 for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
6623 if (WIFSTOPPED(ps->status)) {
6624 ps->status = -1;
6625 jp->state = 0;
6626 }
6627 }
6628 INTON;
6629}
6630#endif
6631
Eric Andersen2870d962001-07-02 17:27:21 +00006632static void showjobs(int change);
6633
Eric Andersencb57d552001-06-28 07:25:16 +00006634
6635static int
6636jobscmd(argc, argv)
6637 int argc;
6638 char **argv;
6639{
6640 showjobs(0);
6641 return 0;
6642}
6643
6644
6645/*
6646 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6647 * statuses have changed since the last call to showjobs.
6648 *
6649 * If the shell is interrupted in the process of creating a job, the
6650 * result may be a job structure containing zero processes. Such structures
6651 * will be freed here.
6652 */
6653
6654static void
6655showjobs(change)
6656 int change;
6657{
6658 int jobno;
6659 int procno;
6660 int i;
6661 struct job *jp;
6662 struct procstat *ps;
6663 int col;
6664 char s[64];
6665
6666 TRACE(("showjobs(%d) called\n", change));
6667 while (dowait(0, (struct job *)NULL) > 0);
6668 for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
6669 if (! jp->used)
6670 continue;
6671 if (jp->nprocs == 0) {
6672 freejob(jp);
6673 continue;
6674 }
6675 if (change && ! jp->changed)
6676 continue;
6677 procno = jp->nprocs;
Eric Andersen2870d962001-07-02 17:27:21 +00006678 for (ps = jp->ps ; ; ps++) { /* for each process */
Eric Andersencb57d552001-06-28 07:25:16 +00006679 if (ps == jp->ps)
Eric Andersen3102ac42001-07-06 04:26:23 +00006680 snprintf(s, 64, "[%d] %ld ", jobno,
Eric Andersencb57d552001-06-28 07:25:16 +00006681 (long)ps->pid);
6682 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006683 snprintf(s, 64, " %ld ",
Eric Andersencb57d552001-06-28 07:25:16 +00006684 (long)ps->pid);
6685 out1str(s);
6686 col = strlen(s);
6687 s[0] = '\0';
6688 if (ps->status == -1) {
6689 /* don't print anything */
6690 } else if (WIFEXITED(ps->status)) {
Eric Andersen3102ac42001-07-06 04:26:23 +00006691 snprintf(s, 64, "Exit %d",
Eric Andersencb57d552001-06-28 07:25:16 +00006692 WEXITSTATUS(ps->status));
6693 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00006694#ifdef JOBS
6695 if (WIFSTOPPED(ps->status))
Eric Andersencb57d552001-06-28 07:25:16 +00006696 i = WSTOPSIG(ps->status);
6697 else /* WIFSIGNALED(ps->status) */
6698#endif
6699 i = WTERMSIG(ps->status);
6700 if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
Eric Andersen2870d962001-07-02 17:27:21 +00006701 strcpy(s, sys_siglist[i & 0x7F]);
Eric Andersencb57d552001-06-28 07:25:16 +00006702 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006703 snprintf(s, 64, "Signal %d", i & 0x7F);
Eric Andersencb57d552001-06-28 07:25:16 +00006704 if (WCOREDUMP(ps->status))
6705 strcat(s, " (core dumped)");
6706 }
6707 out1str(s);
6708 col += strlen(s);
Eric Andersen62483552001-07-10 06:09:16 +00006709 printf(
Eric Andersencb57d552001-06-28 07:25:16 +00006710 "%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ',
6711 ps->cmd
6712 );
6713 if (--procno <= 0)
6714 break;
6715 }
6716 jp->changed = 0;
6717 if (jp->state == JOBDONE) {
6718 freejob(jp);
6719 }
6720 }
6721}
6722
6723
6724/*
6725 * Mark a job structure as unused.
6726 */
6727
6728static void
Eric Andersen62483552001-07-10 06:09:16 +00006729freejob(struct job *jp)
6730{
6731 const struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006732 int i;
6733
6734 INTOFF;
6735 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6736 if (ps->cmd != nullstr)
6737 ckfree(ps->cmd);
6738 }
6739 if (jp->ps != &jp->ps0)
6740 ckfree(jp->ps);
6741 jp->used = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006742#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006743 if (curjob == jp - jobtab + 1)
6744 curjob = 0;
6745#endif
6746 INTON;
6747}
6748
6749
6750
6751static int
6752waitcmd(argc, argv)
6753 int argc;
6754 char **argv;
6755{
6756 struct job *job;
6757 int status, retval;
6758 struct job *jp;
6759
6760 if (--argc > 0) {
6761start:
6762 job = getjob(*++argv);
6763 } else {
6764 job = NULL;
6765 }
Eric Andersen2870d962001-07-02 17:27:21 +00006766 for (;;) { /* loop until process terminated or stopped */
Eric Andersencb57d552001-06-28 07:25:16 +00006767 if (job != NULL) {
6768 if (job->state) {
6769 status = job->ps[job->nprocs - 1].status;
6770 if (! iflag)
6771 freejob(job);
6772 if (--argc) {
6773 goto start;
6774 }
6775 if (WIFEXITED(status))
6776 retval = WEXITSTATUS(status);
Eric Andersen2870d962001-07-02 17:27:21 +00006777#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006778 else if (WIFSTOPPED(status))
6779 retval = WSTOPSIG(status) + 128;
6780#endif
6781 else {
6782 /* XXX: limits number of signals */
6783 retval = WTERMSIG(status) + 128;
6784 }
6785 return retval;
6786 }
6787 } else {
6788 for (jp = jobtab ; ; jp++) {
Eric Andersen2870d962001-07-02 17:27:21 +00006789 if (jp >= jobtab + njobs) { /* no running procs */
Eric Andersencb57d552001-06-28 07:25:16 +00006790 return 0;
6791 }
6792 if (jp->used && jp->state == 0)
6793 break;
6794 }
6795 }
6796 if (dowait(2, 0) < 0 && errno == EINTR) {
6797 return 129;
6798 }
6799 }
6800}
6801
6802
6803
6804/*
6805 * Convert a job name to a job structure.
6806 */
6807
6808static struct job *
Eric Andersen2870d962001-07-02 17:27:21 +00006809getjob(const char *name)
6810{
Eric Andersencb57d552001-06-28 07:25:16 +00006811 int jobno;
6812 struct job *jp;
6813 int pid;
6814 int i;
6815
6816 if (name == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00006817#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006818currentjob:
6819 if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
6820 error("No current job");
6821 return &jobtab[jobno - 1];
6822#else
6823 error("No current job");
6824#endif
6825 } else if (name[0] == '%') {
6826 if (is_digit(name[1])) {
6827 jobno = number(name + 1);
6828 if (jobno > 0 && jobno <= njobs
6829 && jobtab[jobno - 1].used != 0)
6830 return &jobtab[jobno - 1];
Eric Andersen2870d962001-07-02 17:27:21 +00006831#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006832 } else if (name[1] == '%' && name[2] == '\0') {
6833 goto currentjob;
6834#endif
6835 } else {
6836 struct job *found = NULL;
6837 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
6838 if (jp->used && jp->nprocs > 0
6839 && prefix(name + 1, jp->ps[0].cmd)) {
6840 if (found)
6841 error("%s: ambiguous", name);
6842 found = jp;
6843 }
6844 }
6845 if (found)
6846 return found;
6847 }
Eric Andersen2870d962001-07-02 17:27:21 +00006848 } else if (is_number(name, &pid)) {
Eric Andersencb57d552001-06-28 07:25:16 +00006849 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
6850 if (jp->used && jp->nprocs > 0
6851 && jp->ps[jp->nprocs - 1].pid == pid)
6852 return jp;
6853 }
6854 }
6855 error("No such job: %s", name);
6856 /* NOTREACHED */
6857}
6858
6859
6860
6861/*
6862 * Return a new job structure,
6863 */
6864
Eric Andersen2870d962001-07-02 17:27:21 +00006865static struct job *
Eric Andersen62483552001-07-10 06:09:16 +00006866makejob(const union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00006867{
6868 int i;
6869 struct job *jp;
6870
6871 for (i = njobs, jp = jobtab ; ; jp++) {
6872 if (--i < 0) {
6873 INTOFF;
6874 if (njobs == 0) {
6875 jobtab = ckmalloc(4 * sizeof jobtab[0]);
6876 } else {
6877 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
6878 memcpy(jp, jobtab, njobs * sizeof jp[0]);
6879 /* Relocate `ps' pointers */
6880 for (i = 0; i < njobs; i++)
6881 if (jp[i].ps == &jobtab[i].ps0)
6882 jp[i].ps = &jp[i].ps0;
6883 ckfree(jobtab);
6884 jobtab = jp;
6885 }
6886 jp = jobtab + njobs;
6887 for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
6888 INTON;
6889 break;
6890 }
6891 if (jp->used == 0)
6892 break;
6893 }
6894 INTOFF;
6895 jp->state = 0;
6896 jp->used = 1;
6897 jp->changed = 0;
6898 jp->nprocs = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006899#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006900 jp->jobctl = jobctl;
6901#endif
6902 if (nprocs > 1) {
6903 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
6904 } else {
6905 jp->ps = &jp->ps0;
6906 }
6907 INTON;
6908 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
6909 jp - jobtab + 1));
6910 return jp;
6911}
6912
6913
6914/*
6915 * Fork of a subshell. If we are doing job control, give the subshell its
6916 * own process group. Jp is a job structure that the job is to be added to.
6917 * N is the command that will be evaluated by the child. Both jp and n may
6918 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00006919 * FORK_FG - Fork off a foreground process.
6920 * FORK_BG - Fork off a background process.
6921 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
6922 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00006923 *
6924 * When job control is turned off, background processes have their standard
6925 * input redirected to /dev/null (except for the second and later processes
6926 * in a pipeline).
6927 */
6928
Eric Andersen2870d962001-07-02 17:27:21 +00006929
6930
Eric Andersencb57d552001-06-28 07:25:16 +00006931static int
Eric Andersen62483552001-07-10 06:09:16 +00006932forkshell(struct job *jp, const union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00006933{
6934 int pid;
Eric Andersen62483552001-07-10 06:09:16 +00006935#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006936 int pgrp;
Eric Andersen62483552001-07-10 06:09:16 +00006937#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006938 const char *devnull = _PATH_DEVNULL;
6939 const char *nullerr = "Can't open %s";
6940
6941 TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
6942 mode));
6943 INTOFF;
6944 pid = fork();
6945 if (pid == -1) {
6946 TRACE(("Fork failed, errno=%d\n", errno));
6947 INTON;
6948 error("Cannot fork");
6949 }
6950 if (pid == 0) {
6951 struct job *p;
6952 int wasroot;
6953 int i;
6954
6955 TRACE(("Child shell %d\n", getpid()));
6956 wasroot = rootshell;
6957 rootshell = 0;
6958 closescript();
6959 INTON;
6960 clear_traps();
Eric Andersen2870d962001-07-02 17:27:21 +00006961#ifdef JOBS
6962 jobctl = 0; /* do job control only in root shell */
Eric Andersencb57d552001-06-28 07:25:16 +00006963 if (wasroot && mode != FORK_NOJOB && mflag) {
6964 if (jp == NULL || jp->nprocs == 0)
6965 pgrp = getpid();
6966 else
6967 pgrp = jp->ps[0].pid;
6968 setpgid(0, pgrp);
6969 if (mode == FORK_FG) {
6970 /*** this causes superfluous TIOCSPGRPS ***/
6971#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006972 if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006973 error("TIOCSPGRP failed, errno=%d", errno);
6974#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006975 if (tcsetpgrp(2, pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006976 error("tcsetpgrp failed, errno=%d", errno);
6977#endif
6978 }
6979 setsignal(SIGTSTP);
6980 setsignal(SIGTTOU);
6981 } else if (mode == FORK_BG) {
6982 ignoresig(SIGINT);
6983 ignoresig(SIGQUIT);
6984 if ((jp == NULL || jp->nprocs == 0) &&
6985 ! fd0_redirected_p ()) {
6986 close(0);
6987 if (open(devnull, O_RDONLY) != 0)
6988 error(nullerr, devnull);
6989 }
6990 }
6991#else
6992 if (mode == FORK_BG) {
6993 ignoresig(SIGINT);
6994 ignoresig(SIGQUIT);
6995 if ((jp == NULL || jp->nprocs == 0) &&
6996 ! fd0_redirected_p ()) {
6997 close(0);
6998 if (open(devnull, O_RDONLY) != 0)
6999 error(nullerr, devnull);
7000 }
7001 }
7002#endif
7003 for (i = njobs, p = jobtab ; --i >= 0 ; p++)
7004 if (p->used)
7005 freejob(p);
7006 if (wasroot && iflag) {
7007 setsignal(SIGINT);
7008 setsignal(SIGQUIT);
7009 setsignal(SIGTERM);
7010 }
7011 return pid;
7012 }
Eric Andersen62483552001-07-10 06:09:16 +00007013#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007014 if (rootshell && mode != FORK_NOJOB && mflag) {
7015 if (jp == NULL || jp->nprocs == 0)
7016 pgrp = pid;
7017 else
7018 pgrp = jp->ps[0].pid;
7019 setpgid(pid, pgrp);
7020 }
Eric Andersen62483552001-07-10 06:09:16 +00007021#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007022 if (mode == FORK_BG)
Eric Andersen2870d962001-07-02 17:27:21 +00007023 backgndpid = pid; /* set $! */
Eric Andersencb57d552001-06-28 07:25:16 +00007024 if (jp) {
7025 struct procstat *ps = &jp->ps[jp->nprocs++];
7026 ps->pid = pid;
7027 ps->status = -1;
7028 ps->cmd = nullstr;
7029 if (iflag && rootshell && n)
7030 ps->cmd = commandtext(n);
7031 }
7032 INTON;
7033 TRACE(("In parent shell: child = %d\n", pid));
7034 return pid;
7035}
7036
7037
7038
7039/*
7040 * Wait for job to finish.
7041 *
7042 * Under job control we have the problem that while a child process is
7043 * running interrupts generated by the user are sent to the child but not
7044 * to the shell. This means that an infinite loop started by an inter-
7045 * active user may be hard to kill. With job control turned off, an
7046 * interactive user may place an interactive program inside a loop. If
7047 * the interactive program catches interrupts, the user doesn't want
7048 * these interrupts to also abort the loop. The approach we take here
7049 * is to have the shell ignore interrupt signals while waiting for a
7050 * forground process to terminate, and then send itself an interrupt
7051 * signal if the child process was terminated by an interrupt signal.
7052 * Unfortunately, some programs want to do a bit of cleanup and then
7053 * exit on interrupt; unless these processes terminate themselves by
7054 * sending a signal to themselves (instead of calling exit) they will
7055 * confuse this approach.
7056 */
7057
7058static int
Eric Andersen62483552001-07-10 06:09:16 +00007059waitforjob(struct job *jp)
7060{
Eric Andersen2870d962001-07-02 17:27:21 +00007061#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007062 int mypgrp = getpgrp();
7063#endif
7064 int status;
7065 int st;
7066 struct sigaction act, oact;
7067
7068 INTOFF;
7069 intreceived = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00007070#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007071 if (!jobctl) {
7072#else
7073 if (!iflag) {
7074#endif
7075 sigaction(SIGINT, 0, &act);
7076 act.sa_handler = waitonint;
7077 sigaction(SIGINT, &act, &oact);
7078 }
7079 TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
7080 while (jp->state == 0) {
7081 dowait(1, jp);
7082 }
Eric Andersen2870d962001-07-02 17:27:21 +00007083#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007084 if (!jobctl) {
7085#else
7086 if (!iflag) {
7087#endif
7088 sigaction(SIGINT, &oact, 0);
7089 if (intreceived && trap[SIGINT]) kill(getpid(), SIGINT);
7090 }
Eric Andersen2870d962001-07-02 17:27:21 +00007091#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007092 if (jp->jobctl) {
7093#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00007094 if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007095 error("TIOCSPGRP failed, errno=%d\n", errno);
7096#else
Eric Andersen3102ac42001-07-06 04:26:23 +00007097 if (tcsetpgrp(2, mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007098 error("tcsetpgrp failed, errno=%d\n", errno);
7099#endif
7100 }
7101 if (jp->state == JOBSTOPPED)
7102 curjob = jp - jobtab + 1;
7103#endif
7104 status = jp->ps[jp->nprocs - 1].status;
7105 /* convert to 8 bits */
7106 if (WIFEXITED(status))
7107 st = WEXITSTATUS(status);
Eric Andersen2870d962001-07-02 17:27:21 +00007108#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007109 else if (WIFSTOPPED(status))
7110 st = WSTOPSIG(status) + 128;
7111#endif
7112 else
7113 st = WTERMSIG(status) + 128;
Eric Andersen2870d962001-07-02 17:27:21 +00007114#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007115 if (jp->jobctl) {
7116 /*
7117 * This is truly gross.
7118 * If we're doing job control, then we did a TIOCSPGRP which
7119 * caused us (the shell) to no longer be in the controlling
7120 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7121 * intuit from the subprocess exit status whether a SIGINT
7122 * occured, and if so interrupt ourselves. Yuck. - mycroft
7123 */
7124 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
7125 raise(SIGINT);
7126 }
Eric Andersen2870d962001-07-02 17:27:21 +00007127 if (jp->state == JOBDONE)
7128
Eric Andersencb57d552001-06-28 07:25:16 +00007129#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007130 freejob(jp);
7131 INTON;
7132 return st;
7133}
7134
7135
7136
7137/*
7138 * Wait for a process to terminate.
7139 */
7140
Eric Andersen62483552001-07-10 06:09:16 +00007141/*
7142 * Do a wait system call. If job control is compiled in, we accept
7143 * stopped processes. If block is zero, we return a value of zero
7144 * rather than blocking.
7145 *
7146 * System V doesn't have a non-blocking wait system call. It does
7147 * have a SIGCLD signal that is sent to a process when one of it's
7148 * children dies. The obvious way to use SIGCLD would be to install
7149 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7150 * was received, and have waitproc bump another counter when it got
7151 * the status of a process. Waitproc would then know that a wait
7152 * system call would not block if the two counters were different.
7153 * This approach doesn't work because if a process has children that
7154 * have not been waited for, System V will send it a SIGCLD when it
7155 * installs a signal handler for SIGCLD. What this means is that when
7156 * a child exits, the shell will be sent SIGCLD signals continuously
7157 * until is runs out of stack space, unless it does a wait call before
7158 * restoring the signal handler. The code below takes advantage of
7159 * this (mis)feature by installing a signal handler for SIGCLD and
7160 * then checking to see whether it was called. If there are any
7161 * children to be waited for, it will be.
7162 *
7163 */
7164
7165static inline int
7166waitproc(int block, int *status)
7167{
7168 int flags;
7169
7170 flags = 0;
7171#ifdef JOBS
7172 if (jobctl)
7173 flags |= WUNTRACED;
7174#endif
7175 if (block == 0)
7176 flags |= WNOHANG;
7177 return wait3(status, flags, (struct rusage *)NULL);
7178}
7179
Eric Andersencb57d552001-06-28 07:25:16 +00007180static int
Eric Andersen62483552001-07-10 06:09:16 +00007181dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00007182{
7183 int pid;
7184 int status;
7185 struct procstat *sp;
7186 struct job *jp;
7187 struct job *thisjob;
7188 int done;
7189 int stopped;
7190 int core;
7191 int sig;
7192
7193 TRACE(("dowait(%d) called\n", block));
7194 do {
7195 pid = waitproc(block, &status);
7196 TRACE(("wait returns %d, status=%d\n", pid, status));
7197 } while (!(block & 2) && pid == -1 && errno == EINTR);
7198 if (pid <= 0)
7199 return pid;
7200 INTOFF;
7201 thisjob = NULL;
7202 for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
7203 if (jp->used) {
7204 done = 1;
7205 stopped = 1;
7206 for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
7207 if (sp->pid == -1)
7208 continue;
7209 if (sp->pid == pid) {
7210 TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
7211 sp->status = status;
7212 thisjob = jp;
7213 }
7214 if (sp->status == -1)
7215 stopped = 0;
7216 else if (WIFSTOPPED(sp->status))
7217 done = 0;
7218 }
Eric Andersen2870d962001-07-02 17:27:21 +00007219 if (stopped) { /* stopped or done */
Eric Andersencb57d552001-06-28 07:25:16 +00007220 int state = done? JOBDONE : JOBSTOPPED;
7221 if (jp->state != state) {
7222 TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
7223 jp->state = state;
Eric Andersen2870d962001-07-02 17:27:21 +00007224#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007225 if (done && curjob == jp - jobtab + 1)
Eric Andersen2870d962001-07-02 17:27:21 +00007226 curjob = 0; /* no current job */
Eric Andersencb57d552001-06-28 07:25:16 +00007227#endif
7228 }
7229 }
7230 }
7231 }
7232 INTON;
7233 if (! rootshell || ! iflag || (job && thisjob == job)) {
7234 core = WCOREDUMP(status);
Eric Andersen2870d962001-07-02 17:27:21 +00007235#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007236 if (WIFSTOPPED(status)) sig = WSTOPSIG(status);
7237 else
7238#endif
7239 if (WIFEXITED(status)) sig = 0;
7240 else sig = WTERMSIG(status);
7241
7242 if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
7243 if (thisjob != job)
Eric Andersen3102ac42001-07-06 04:26:23 +00007244 out2fmt("%d: ", pid);
Eric Andersen2870d962001-07-02 17:27:21 +00007245#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007246 if (sig == SIGTSTP && rootshell && iflag)
Eric Andersen3102ac42001-07-06 04:26:23 +00007247 out2fmt("%%%ld ",
Eric Andersencb57d552001-06-28 07:25:16 +00007248 (long)(job - jobtab + 1));
7249#endif
7250 if (sig < NSIG && sys_siglist[sig])
7251 out2str(sys_siglist[sig]);
7252 else
Eric Andersen3102ac42001-07-06 04:26:23 +00007253 out2fmt("Signal %d", sig);
Eric Andersencb57d552001-06-28 07:25:16 +00007254 if (core)
7255 out2str(" - core dumped");
7256 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00007257 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00007258 TRACE(("Not printing status: status=%d, sig=%d\n",
Eric Andersencb57d552001-06-28 07:25:16 +00007259 status, sig));
7260 }
7261 } else {
7262 TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
7263 if (thisjob)
7264 thisjob->changed = 1;
7265 }
7266 return pid;
7267}
7268
7269
7270
Eric Andersencb57d552001-06-28 07:25:16 +00007271
7272/*
7273 * return 1 if there are stopped jobs, otherwise 0
7274 */
Eric Andersencb57d552001-06-28 07:25:16 +00007275static int
Eric Andersen2870d962001-07-02 17:27:21 +00007276stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007277{
7278 int jobno;
7279 struct job *jp;
7280
7281 if (job_warning)
7282 return (0);
7283 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
7284 if (jp->used == 0)
7285 continue;
7286 if (jp->state == JOBSTOPPED) {
7287 out2str("You have stopped jobs.\n");
7288 job_warning = 2;
7289 return (1);
7290 }
7291 }
7292
7293 return (0);
7294}
7295
7296/*
7297 * Return a string identifying a command (to be printed by the
7298 * jobs command.
7299 */
7300
7301static char *cmdnextc;
7302static int cmdnleft;
Eric Andersen2870d962001-07-02 17:27:21 +00007303#define MAXCMDTEXT 200
Eric Andersencb57d552001-06-28 07:25:16 +00007304
Eric Andersen2870d962001-07-02 17:27:21 +00007305static void
7306cmdputs(const char *s)
7307{
7308 const char *p;
7309 char *q;
7310 char c;
7311 int subtype = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007312
Eric Andersen2870d962001-07-02 17:27:21 +00007313 if (cmdnleft <= 0)
7314 return;
7315 p = s;
7316 q = cmdnextc;
7317 while ((c = *p++) != '\0') {
7318 if (c == CTLESC)
7319 *q++ = *p++;
7320 else if (c == CTLVAR) {
7321 *q++ = '$';
7322 if (--cmdnleft > 0)
7323 *q++ = '{';
7324 subtype = *p++;
7325 } else if (c == '=' && subtype != 0) {
7326 *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
7327 subtype = 0;
7328 } else if (c == CTLENDVAR) {
7329 *q++ = '}';
7330 } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
7331 cmdnleft++; /* ignore it */
7332 else
7333 *q++ = c;
7334 if (--cmdnleft <= 0) {
7335 *q++ = '.';
7336 *q++ = '.';
7337 *q++ = '.';
7338 break;
7339 }
7340 }
7341 cmdnextc = q;
Eric Andersencb57d552001-06-28 07:25:16 +00007342}
7343
7344
7345static void
Eric Andersen2870d962001-07-02 17:27:21 +00007346cmdtxt(const union node *n)
7347{
Eric Andersencb57d552001-06-28 07:25:16 +00007348 union node *np;
7349 struct nodelist *lp;
7350 const char *p;
7351 int i;
7352 char s[2];
7353
7354 if (n == NULL)
7355 return;
7356 switch (n->type) {
7357 case NSEMI:
7358 cmdtxt(n->nbinary.ch1);
7359 cmdputs("; ");
7360 cmdtxt(n->nbinary.ch2);
7361 break;
7362 case NAND:
7363 cmdtxt(n->nbinary.ch1);
7364 cmdputs(" && ");
7365 cmdtxt(n->nbinary.ch2);
7366 break;
7367 case NOR:
7368 cmdtxt(n->nbinary.ch1);
7369 cmdputs(" || ");
7370 cmdtxt(n->nbinary.ch2);
7371 break;
7372 case NPIPE:
7373 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7374 cmdtxt(lp->n);
7375 if (lp->next)
7376 cmdputs(" | ");
7377 }
7378 break;
7379 case NSUBSHELL:
7380 cmdputs("(");
7381 cmdtxt(n->nredir.n);
7382 cmdputs(")");
7383 break;
7384 case NREDIR:
7385 case NBACKGND:
7386 cmdtxt(n->nredir.n);
7387 break;
7388 case NIF:
7389 cmdputs("if ");
7390 cmdtxt(n->nif.test);
7391 cmdputs("; then ");
7392 cmdtxt(n->nif.ifpart);
7393 cmdputs("...");
7394 break;
7395 case NWHILE:
7396 cmdputs("while ");
7397 goto until;
7398 case NUNTIL:
7399 cmdputs("until ");
7400until:
7401 cmdtxt(n->nbinary.ch1);
7402 cmdputs("; do ");
7403 cmdtxt(n->nbinary.ch2);
7404 cmdputs("; done");
7405 break;
7406 case NFOR:
7407 cmdputs("for ");
7408 cmdputs(n->nfor.var);
7409 cmdputs(" in ...");
7410 break;
7411 case NCASE:
7412 cmdputs("case ");
7413 cmdputs(n->ncase.expr->narg.text);
7414 cmdputs(" in ...");
7415 break;
7416 case NDEFUN:
7417 cmdputs(n->narg.text);
7418 cmdputs("() ...");
7419 break;
7420 case NCMD:
7421 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7422 cmdtxt(np);
7423 if (np->narg.next)
7424 cmdputs(spcstr);
7425 }
7426 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7427 cmdputs(spcstr);
7428 cmdtxt(np);
7429 }
7430 break;
7431 case NARG:
7432 cmdputs(n->narg.text);
7433 break;
7434 case NTO:
7435 p = ">"; i = 1; goto redir;
7436 case NAPPEND:
7437 p = ">>"; i = 1; goto redir;
7438 case NTOFD:
7439 p = ">&"; i = 1; goto redir;
7440 case NTOOV:
7441 p = ">|"; i = 1; goto redir;
7442 case NFROM:
7443 p = "<"; i = 0; goto redir;
7444 case NFROMFD:
7445 p = "<&"; i = 0; goto redir;
7446 case NFROMTO:
7447 p = "<>"; i = 0; goto redir;
7448redir:
7449 if (n->nfile.fd != i) {
7450 s[0] = n->nfile.fd + '0';
7451 s[1] = '\0';
7452 cmdputs(s);
7453 }
7454 cmdputs(p);
7455 if (n->type == NTOFD || n->type == NFROMFD) {
7456 s[0] = n->ndup.dupfd + '0';
7457 s[1] = '\0';
7458 cmdputs(s);
7459 } else {
7460 cmdtxt(n->nfile.fname);
7461 }
7462 break;
7463 case NHERE:
7464 case NXHERE:
7465 cmdputs("<<...");
7466 break;
7467 default:
7468 cmdputs("???");
7469 break;
7470 }
7471}
7472
7473
Eric Andersen2870d962001-07-02 17:27:21 +00007474static char *
7475commandtext(const union node *n)
7476{
7477 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007478
Eric Andersen2870d962001-07-02 17:27:21 +00007479 cmdnextc = name = ckmalloc(MAXCMDTEXT);
7480 cmdnleft = MAXCMDTEXT - 4;
7481 cmdtxt(n);
7482 *cmdnextc = '\0';
7483 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00007484}
7485
Eric Andersen2870d962001-07-02 17:27:21 +00007486
Eric Andersencb57d552001-06-28 07:25:16 +00007487static void waitonint(int sig) {
7488 intreceived = 1;
7489 return;
7490}
Eric Andersencb57d552001-06-28 07:25:16 +00007491/*
7492 * Routines to check for mail. (Perhaps make part of main.c?)
7493 */
7494
7495
7496#define MAXMBOXES 10
7497
7498
Eric Andersen2870d962001-07-02 17:27:21 +00007499static int nmboxes; /* number of mailboxes */
7500static time_t mailtime[MAXMBOXES]; /* times of mailboxes */
Eric Andersencb57d552001-06-28 07:25:16 +00007501
7502
7503
7504/*
7505 * Print appropriate message(s) if mail has arrived. If the argument is
7506 * nozero, then the value of MAIL has changed, so we just update the
7507 * values.
7508 */
7509
7510static void
Eric Andersen2870d962001-07-02 17:27:21 +00007511chkmail(int silent)
Eric Andersencb57d552001-06-28 07:25:16 +00007512{
7513 int i;
7514 const char *mpath;
7515 char *p;
7516 char *q;
7517 struct stackmark smark;
7518 struct stat statb;
7519
7520 if (silent)
7521 nmboxes = 10;
7522 if (nmboxes == 0)
7523 return;
7524 setstackmark(&smark);
7525 mpath = mpathset()? mpathval() : mailval();
7526 for (i = 0 ; i < nmboxes ; i++) {
7527 p = padvance(&mpath, nullstr);
7528 if (p == NULL)
7529 break;
7530 if (*p == '\0')
7531 continue;
7532 for (q = p ; *q ; q++);
7533#ifdef DEBUG
7534 if (q[-1] != '/')
7535 abort();
7536#endif
Eric Andersen2870d962001-07-02 17:27:21 +00007537 q[-1] = '\0'; /* delete trailing '/' */
Eric Andersencb57d552001-06-28 07:25:16 +00007538 if (stat(p, &statb) < 0)
7539 statb.st_size = 0;
7540 if (statb.st_size > mailtime[i] && ! silent) {
Eric Andersen3102ac42001-07-06 04:26:23 +00007541 out2fmt(snlfmt,
7542 pathopt? pathopt : "you have mail");
Eric Andersencb57d552001-06-28 07:25:16 +00007543 }
7544 mailtime[i] = statb.st_size;
Eric Andersencb57d552001-06-28 07:25:16 +00007545 }
7546 nmboxes = i;
7547 popstackmark(&smark);
7548}
Eric Andersencb57d552001-06-28 07:25:16 +00007549
7550#define PROFILE 0
7551
Eric Andersencb57d552001-06-28 07:25:16 +00007552#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007553static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007554extern int etext();
7555#endif
7556
Eric Andersen2870d962001-07-02 17:27:21 +00007557static void read_profile (const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007558static void cmdloop (int);
7559static void options (int);
Eric Andersen2870d962001-07-02 17:27:21 +00007560static void setoption (int, int);
7561static void procargs (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00007562
Eric Andersen2870d962001-07-02 17:27:21 +00007563
Eric Andersencb57d552001-06-28 07:25:16 +00007564/*
7565 * Main routine. We initialize things, parse the arguments, execute
7566 * profiles if we're a login shell, and then call cmdloop to execute
7567 * commands. The setjmp call sets up the location to jump to when an
7568 * exception occurs. When an exception occurs the variable "state"
7569 * is used to figure out how far we had gotten.
7570 */
7571
7572int
Matt Kraai2d91deb2001-08-01 17:21:35 +00007573ash_main(argc, argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007574 int argc;
7575 char **argv;
7576{
7577 struct jmploc jmploc;
7578 struct stackmark smark;
7579 volatile int state;
Eric Andersen62483552001-07-10 06:09:16 +00007580 const char *shinit;
Eric Andersencb57d552001-06-28 07:25:16 +00007581
Eric Andersencb57d552001-06-28 07:25:16 +00007582 BLTINCMD = find_builtin("builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00007583 EXECCMD = find_builtin("exec");
7584 EVALCMD = find_builtin("eval");
7585
Eric Andersen1c039232001-07-07 00:05:55 +00007586#ifndef BB_FEATURE_SH_FANCY_PROMPT
7587 unsetenv("PS1");
7588 unsetenv("PS2");
7589#endif
7590
Eric Andersencb57d552001-06-28 07:25:16 +00007591#if PROFILE
7592 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7593#endif
7594#if defined(linux) || defined(__GNU__)
7595 signal(SIGCHLD, SIG_DFL);
7596#endif
7597 state = 0;
7598 if (setjmp(jmploc.loc)) {
7599 INTOFF;
7600 /*
7601 * When a shell procedure is executed, we raise the
7602 * exception EXSHELLPROC to clean up before executing
7603 * the shell procedure.
7604 */
7605 switch (exception) {
7606 case EXSHELLPROC:
7607 rootpid = getpid();
7608 rootshell = 1;
7609 minusc = NULL;
7610 state = 3;
7611 break;
7612
7613 case EXEXEC:
7614 exitstatus = exerrno;
7615 break;
7616
7617 case EXERROR:
7618 exitstatus = 2;
7619 break;
7620
7621 default:
7622 break;
7623 }
7624
7625 if (exception != EXSHELLPROC) {
7626 if (state == 0 || iflag == 0 || ! rootshell)
7627 exitshell(exitstatus);
7628 }
7629 reset();
Eric Andersen2870d962001-07-02 17:27:21 +00007630 if (exception == EXINT) {
Eric Andersencb57d552001-06-28 07:25:16 +00007631 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00007632 }
7633 popstackmark(&smark);
Eric Andersen2870d962001-07-02 17:27:21 +00007634 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007635 if (state == 1)
7636 goto state1;
7637 else if (state == 2)
7638 goto state2;
7639 else if (state == 3)
7640 goto state3;
7641 else
7642 goto state4;
7643 }
7644 handler = &jmploc;
7645#ifdef DEBUG
7646 opentrace();
7647 trputs("Shell args: "); trargs(argv);
7648#endif
7649 rootpid = getpid();
7650 rootshell = 1;
7651 init();
7652 setstackmark(&smark);
7653 procargs(argc, argv);
7654 if (argv[0] && argv[0][0] == '-') {
7655 state = 1;
7656 read_profile("/etc/profile");
7657state1:
7658 state = 2;
7659 read_profile(".profile");
7660 }
7661state2:
7662 state = 3;
7663#ifndef linux
7664 if (getuid() == geteuid() && getgid() == getegid()) {
7665#endif
7666 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7667 state = 3;
7668 read_profile(shinit);
7669 }
7670#ifndef linux
7671 }
7672#endif
7673state3:
7674 state = 4;
7675 if (sflag == 0 || minusc) {
7676 static int sigs[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00007677 SIGINT, SIGQUIT, SIGHUP,
Eric Andersencb57d552001-06-28 07:25:16 +00007678#ifdef SIGTSTP
7679 SIGTSTP,
7680#endif
7681 SIGPIPE
7682 };
7683#define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0]))
7684 int i;
7685
7686 for (i = 0; i < SIGSSIZE; i++)
7687 setsignal(sigs[i]);
7688 }
7689
7690 if (minusc)
7691 evalstring(minusc, 0);
7692
7693 if (sflag || minusc == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00007694state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007695 cmdloop(1);
7696 }
7697#if PROFILE
7698 monitor(0);
7699#endif
7700 exitshell(exitstatus);
7701 /* NOTREACHED */
7702}
7703
7704
7705/*
7706 * Read and execute commands. "Top" is nonzero for the top level command
7707 * loop; it turns on prompting if the shell is interactive.
7708 */
7709
7710static void
Eric Andersen2870d962001-07-02 17:27:21 +00007711cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00007712{
7713 union node *n;
7714 struct stackmark smark;
7715 int inter;
7716 int numeof = 0;
7717
7718 TRACE(("cmdloop(%d) called\n", top));
7719 setstackmark(&smark);
7720 for (;;) {
7721 if (pendingsigs)
7722 dotrap();
7723 inter = 0;
7724 if (iflag && top) {
7725 inter++;
7726 showjobs(1);
7727 chkmail(0);
Eric Andersen3102ac42001-07-06 04:26:23 +00007728 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00007729 }
7730 n = parsecmd(inter);
7731 /* showtree(n); DEBUG */
7732 if (n == NEOF) {
7733 if (!top || numeof >= 50)
7734 break;
7735 if (!stoppedjobs()) {
7736 if (!Iflag)
7737 break;
7738 out2str("\nUse \"exit\" to leave shell.\n");
7739 }
7740 numeof++;
7741 } else if (n != NULL && nflag == 0) {
7742 job_warning = (job_warning == 2) ? 1 : 0;
7743 numeof = 0;
7744 evaltree(n, 0);
7745 }
7746 popstackmark(&smark);
7747 setstackmark(&smark);
7748 if (evalskip == SKIPFILE) {
7749 evalskip = 0;
7750 break;
7751 }
7752 }
7753 popstackmark(&smark);
7754}
7755
7756
7757
7758/*
7759 * Read /etc/profile or .profile. Return on error.
7760 */
7761
7762static void
7763read_profile(name)
7764 const char *name;
7765{
7766 int fd;
7767 int xflag_set = 0;
7768 int vflag_set = 0;
7769
7770 INTOFF;
7771 if ((fd = open(name, O_RDONLY)) >= 0)
7772 setinputfd(fd, 1);
7773 INTON;
7774 if (fd < 0)
7775 return;
7776 /* -q turns off -x and -v just when executing init files */
7777 if (qflag) {
7778 if (xflag)
7779 xflag = 0, xflag_set = 1;
7780 if (vflag)
7781 vflag = 0, vflag_set = 1;
7782 }
7783 cmdloop(0);
7784 if (qflag) {
7785 if (xflag_set)
7786 xflag = 1;
7787 if (vflag_set)
7788 vflag = 1;
7789 }
7790 popfile();
7791}
7792
7793
7794
7795/*
7796 * Read a file containing shell functions.
7797 */
7798
7799static void
Eric Andersen2870d962001-07-02 17:27:21 +00007800readcmdfile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00007801{
7802 int fd;
7803
7804 INTOFF;
7805 if ((fd = open(name, O_RDONLY)) >= 0)
7806 setinputfd(fd, 1);
7807 else
7808 error("Can't open %s", name);
7809 INTON;
7810 cmdloop(0);
7811 popfile();
7812}
7813
7814
7815
7816/*
7817 * Take commands from a file. To be compatable we should do a path
7818 * search for the file, which is necessary to find sub-commands.
7819 */
7820
7821
Eric Andersen62483552001-07-10 06:09:16 +00007822static inline char *
Eric Andersencb57d552001-06-28 07:25:16 +00007823find_dot_file(mybasename)
7824 char *mybasename;
7825{
7826 char *fullname;
7827 const char *path = pathval();
7828 struct stat statb;
7829
7830 /* don't try this for absolute or relative paths */
7831 if (strchr(mybasename, '/'))
7832 return mybasename;
7833
7834 while ((fullname = padvance(&path, mybasename)) != NULL) {
7835 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
7836 /*
7837 * Don't bother freeing here, since it will
7838 * be freed by the caller.
7839 */
7840 return fullname;
7841 }
7842 stunalloc(fullname);
7843 }
7844
7845 /* not found in the PATH */
7846 error("%s: not found", mybasename);
7847 /* NOTREACHED */
7848}
7849
7850static int
7851dotcmd(argc, argv)
7852 int argc;
7853 char **argv;
7854{
7855 struct strlist *sp;
7856 exitstatus = 0;
7857
7858 for (sp = cmdenviron; sp ; sp = sp->next)
7859 setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
7860
Eric Andersen2870d962001-07-02 17:27:21 +00007861 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00007862 char *fullname;
7863 struct stackmark smark;
7864
7865 setstackmark(&smark);
7866 fullname = find_dot_file(argv[1]);
7867 setinputfile(fullname, 1);
7868 commandname = fullname;
7869 cmdloop(0);
7870 popfile();
7871 popstackmark(&smark);
7872 }
7873 return exitstatus;
7874}
7875
7876
7877static int
7878exitcmd(argc, argv)
7879 int argc;
7880 char **argv;
7881{
7882 if (stoppedjobs())
7883 return 0;
7884 if (argc > 1)
7885 exitstatus = number(argv[1]);
7886 else
7887 exitstatus = oexitstatus;
7888 exitshell(exitstatus);
7889 /* NOTREACHED */
7890}
Eric Andersen62483552001-07-10 06:09:16 +00007891
Eric Andersen2870d962001-07-02 17:27:21 +00007892static pointer
7893stalloc(int nbytes)
Eric Andersencb57d552001-06-28 07:25:16 +00007894{
7895 char *p;
7896
7897 nbytes = ALIGN(nbytes);
7898 if (nbytes > stacknleft) {
7899 int blocksize;
7900 struct stack_block *sp;
7901
7902 blocksize = nbytes;
7903 if (blocksize < MINSIZE)
7904 blocksize = MINSIZE;
7905 INTOFF;
7906 sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
7907 sp->prev = stackp;
7908 stacknxt = sp->space;
7909 stacknleft = blocksize;
7910 stackp = sp;
7911 INTON;
7912 }
7913 p = stacknxt;
7914 stacknxt += nbytes;
7915 stacknleft -= nbytes;
7916 return p;
7917}
7918
7919
7920static void
Eric Andersen2870d962001-07-02 17:27:21 +00007921stunalloc(pointer p)
7922{
Eric Andersencb57d552001-06-28 07:25:16 +00007923#ifdef DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +00007924 if (p == NULL) { /*DEBUG */
Eric Andersencb57d552001-06-28 07:25:16 +00007925 write(2, "stunalloc\n", 10);
7926 abort();
7927 }
7928#endif
7929 if (!(stacknxt >= (char *)p && (char *)p >= stackp->space)) {
7930 p = stackp->space;
7931 }
7932 stacknleft += stacknxt - (char *)p;
7933 stacknxt = p;
7934}
7935
7936
Eric Andersencb57d552001-06-28 07:25:16 +00007937static void
Eric Andersen2870d962001-07-02 17:27:21 +00007938setstackmark(struct stackmark *mark)
7939{
Eric Andersencb57d552001-06-28 07:25:16 +00007940 mark->stackp = stackp;
7941 mark->stacknxt = stacknxt;
7942 mark->stacknleft = stacknleft;
7943 mark->marknext = markp;
7944 markp = mark;
7945}
7946
7947
7948static void
Eric Andersen2870d962001-07-02 17:27:21 +00007949popstackmark(struct stackmark *mark)
7950{
Eric Andersencb57d552001-06-28 07:25:16 +00007951 struct stack_block *sp;
7952
7953 INTOFF;
7954 markp = mark->marknext;
7955 while (stackp != mark->stackp) {
7956 sp = stackp;
7957 stackp = sp->prev;
7958 ckfree(sp);
7959 }
7960 stacknxt = mark->stacknxt;
7961 stacknleft = mark->stacknleft;
7962 INTON;
7963}
7964
7965
7966/*
7967 * When the parser reads in a string, it wants to stick the string on the
7968 * stack and only adjust the stack pointer when it knows how big the
7969 * string is. Stackblock (defined in stack.h) returns a pointer to a block
7970 * of space on top of the stack and stackblocklen returns the length of
7971 * this block. Growstackblock will grow this space by at least one byte,
7972 * possibly moving it (like realloc). Grabstackblock actually allocates the
7973 * part of the block that has been used.
7974 */
7975
7976static void
Eric Andersen2870d962001-07-02 17:27:21 +00007977growstackblock(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00007978 char *p;
7979 int newlen = ALIGN(stacknleft * 2 + 100);
7980 char *oldspace = stacknxt;
7981 int oldlen = stacknleft;
7982 struct stack_block *sp;
7983 struct stack_block *oldstackp;
7984
7985 if (stacknxt == stackp->space && stackp != &stackbase) {
7986 INTOFF;
7987 oldstackp = stackp;
7988 sp = stackp;
7989 stackp = sp->prev;
7990 sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen);
7991 sp->prev = stackp;
7992 stackp = sp;
7993 stacknxt = sp->space;
7994 stacknleft = newlen;
7995 {
7996 /* Stack marks pointing to the start of the old block
Eric Andersen2870d962001-07-02 17:27:21 +00007997 * must be relocated to point to the new block
Eric Andersencb57d552001-06-28 07:25:16 +00007998 */
7999 struct stackmark *xmark;
8000 xmark = markp;
8001 while (xmark != NULL && xmark->stackp == oldstackp) {
8002 xmark->stackp = stackp;
8003 xmark->stacknxt = stacknxt;
8004 xmark->stacknleft = stacknleft;
8005 xmark = xmark->marknext;
8006 }
8007 }
8008 INTON;
8009 } else {
8010 p = stalloc(newlen);
8011 memcpy(p, oldspace, oldlen);
Eric Andersen2870d962001-07-02 17:27:21 +00008012 stacknxt = p; /* free the space */
8013 stacknleft += newlen; /* we just allocated */
Eric Andersencb57d552001-06-28 07:25:16 +00008014 }
8015}
8016
8017
8018
Eric Andersen2870d962001-07-02 17:27:21 +00008019static inline void
8020grabstackblock(int len)
Eric Andersencb57d552001-06-28 07:25:16 +00008021{
8022 len = ALIGN(len);
8023 stacknxt += len;
8024 stacknleft -= len;
8025}
8026
8027
8028
8029/*
8030 * The following routines are somewhat easier to use that the above.
8031 * The user declares a variable of type STACKSTR, which may be declared
8032 * to be a register. The macro STARTSTACKSTR initializes things. Then
8033 * the user uses the macro STPUTC to add characters to the string. In
8034 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8035 * grown as necessary. When the user is done, she can just leave the
8036 * string there and refer to it using stackblock(). Or she can allocate
8037 * the space for it using grabstackstr(). If it is necessary to allow
8038 * someone else to use the stack temporarily and then continue to grow
8039 * the string, the user should use grabstack to allocate the space, and
8040 * then call ungrabstr(p) to return to the previous mode of operation.
8041 *
8042 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8043 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8044 * is space for at least one character.
8045 */
8046
8047
8048static char *
Eric Andersen2870d962001-07-02 17:27:21 +00008049growstackstr(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00008050 int len = stackblocksize();
8051 if (herefd >= 0 && len >= 1024) {
8052 xwrite(herefd, stackblock(), len);
8053 sstrnleft = len - 1;
8054 return stackblock();
8055 }
8056 growstackblock();
8057 sstrnleft = stackblocksize() - len - 1;
8058 return stackblock() + len;
8059}
8060
8061
8062/*
8063 * Called from CHECKSTRSPACE.
8064 */
8065
8066static char *
8067makestrspace(size_t newlen) {
8068 int len = stackblocksize() - sstrnleft;
8069 do {
8070 growstackblock();
8071 sstrnleft = stackblocksize() - len;
8072 } while (sstrnleft < newlen);
8073 return stackblock() + len;
8074}
8075
8076
8077
8078static void
Eric Andersen2870d962001-07-02 17:27:21 +00008079ungrabstackstr(char *s, char *p)
8080{
Eric Andersencb57d552001-06-28 07:25:16 +00008081 stacknleft += stacknxt - s;
8082 stacknxt = s;
8083 sstrnleft = stacknleft - (p - s);
8084}
Eric Andersencb57d552001-06-28 07:25:16 +00008085/*
8086 * Miscelaneous builtins.
8087 */
8088
8089
8090#undef rflag
8091
Eric Andersen62483552001-07-10 06:09:16 +00008092//#ifdef __GLIBC__
Eric Andersen2870d962001-07-02 17:27:21 +00008093static mode_t getmode(const void *, mode_t);
Eric Andersencb57d552001-06-28 07:25:16 +00008094static void *setmode(const char *);
Eric Andersen62483552001-07-10 06:09:16 +00008095//#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008096
8097#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersen62483552001-07-10 06:09:16 +00008098typedef long rlim_t;
Eric Andersencb57d552001-06-28 07:25:16 +00008099#endif
8100
8101
8102
8103/*
8104 * The read builtin. The -e option causes backslashes to escape the
8105 * following character.
8106 *
8107 * This uses unbuffered input, which may be avoidable in some cases.
8108 */
8109
8110static int
8111readcmd(argc, argv)
8112 int argc;
8113 char **argv;
8114{
8115 char **ap;
8116 int backslash;
8117 char c;
8118 int rflag;
8119 char *prompt;
8120 const char *ifs;
8121 char *p;
8122 int startword;
8123 int status;
8124 int i;
8125
8126 rflag = 0;
8127 prompt = NULL;
8128 while ((i = nextopt("p:r")) != '\0') {
8129 if (i == 'p')
8130 prompt = optionarg;
8131 else
8132 rflag = 1;
8133 }
8134 if (prompt && isatty(0)) {
8135 putprompt(prompt);
8136 flushall();
8137 }
8138 if (*(ap = argptr) == NULL)
8139 error("arg count");
8140 if ((ifs = bltinlookup("IFS")) == NULL)
8141 ifs = defifs;
8142 status = 0;
8143 startword = 1;
8144 backslash = 0;
8145 STARTSTACKSTR(p);
8146 for (;;) {
8147 if (read(0, &c, 1) != 1) {
8148 status = 1;
8149 break;
8150 }
8151 if (c == '\0')
8152 continue;
8153 if (backslash) {
8154 backslash = 0;
8155 if (c != '\n')
8156 STPUTC(c, p);
8157 continue;
8158 }
8159 if (!rflag && c == '\\') {
8160 backslash++;
8161 continue;
8162 }
8163 if (c == '\n')
8164 break;
8165 if (startword && *ifs == ' ' && strchr(ifs, c)) {
8166 continue;
8167 }
8168 startword = 0;
8169 if (backslash && c == '\\') {
8170 if (read(0, &c, 1) != 1) {
8171 status = 1;
8172 break;
8173 }
8174 STPUTC(c, p);
8175 } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
8176 STACKSTRNUL(p);
8177 setvar(*ap, stackblock(), 0);
8178 ap++;
8179 startword = 1;
8180 STARTSTACKSTR(p);
8181 } else {
8182 STPUTC(c, p);
8183 }
8184 }
8185 STACKSTRNUL(p);
8186 /* Remove trailing blanks */
8187 while (stackblock() <= --p && strchr(ifs, *p) != NULL)
8188 *p = '\0';
8189 setvar(*ap, stackblock(), 0);
8190 while (*++ap != NULL)
8191 setvar(*ap, nullstr, 0);
8192 return status;
8193}
8194
8195
8196
8197static int
8198umaskcmd(argc, argv)
8199 int argc;
8200 char **argv;
8201{
8202 char *ap;
8203 int mask;
8204 int i;
8205 int symbolic_mode = 0;
8206
Eric Andersen62483552001-07-10 06:09:16 +00008207 while (nextopt("S") != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00008208 symbolic_mode = 1;
8209 }
8210
8211 INTOFF;
8212 mask = umask(0);
8213 umask(mask);
8214 INTON;
8215
8216 if ((ap = *argptr) == NULL) {
8217 if (symbolic_mode) {
8218 char u[4], g[4], o[4];
8219
8220 i = 0;
8221 if ((mask & S_IRUSR) == 0)
8222 u[i++] = 'r';
8223 if ((mask & S_IWUSR) == 0)
8224 u[i++] = 'w';
8225 if ((mask & S_IXUSR) == 0)
8226 u[i++] = 'x';
8227 u[i] = '\0';
8228
8229 i = 0;
8230 if ((mask & S_IRGRP) == 0)
8231 g[i++] = 'r';
8232 if ((mask & S_IWGRP) == 0)
8233 g[i++] = 'w';
8234 if ((mask & S_IXGRP) == 0)
8235 g[i++] = 'x';
8236 g[i] = '\0';
8237
8238 i = 0;
8239 if ((mask & S_IROTH) == 0)
8240 o[i++] = 'r';
8241 if ((mask & S_IWOTH) == 0)
8242 o[i++] = 'w';
8243 if ((mask & S_IXOTH) == 0)
8244 o[i++] = 'x';
8245 o[i] = '\0';
8246
Eric Andersen62483552001-07-10 06:09:16 +00008247 printf("u=%s,g=%s,o=%s\n", u, g, o);
Eric Andersencb57d552001-06-28 07:25:16 +00008248 } else {
Eric Andersen62483552001-07-10 06:09:16 +00008249 printf("%.4o\n", mask);
Eric Andersencb57d552001-06-28 07:25:16 +00008250 }
8251 } else {
Eric Andersen62483552001-07-10 06:09:16 +00008252 if (is_digit((unsigned char)*ap)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008253 mask = 0;
8254 do {
8255 if (*ap >= '8' || *ap < '0')
8256 error("Illegal number: %s", argv[1]);
8257 mask = (mask << 3) + (*ap - '0');
8258 } while (*++ap != '\0');
8259 umask(mask);
8260 } else {
8261 void *set;
8262
8263 INTOFF;
8264 if ((set = setmode(ap)) != 0) {
8265 mask = getmode(set, ~mask & 0777);
8266 ckfree(set);
8267 }
8268 INTON;
8269 if (!set)
8270 error("Illegal mode: %s", ap);
8271
8272 umask(~mask & 0777);
8273 }
8274 }
8275 return 0;
8276}
8277
8278/*
8279 * ulimit builtin
8280 *
8281 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
8282 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
8283 * ash by J.T. Conklin.
8284 *
8285 * Public domain.
8286 */
8287
8288struct limits {
8289 const char *name;
Eric Andersen2870d962001-07-02 17:27:21 +00008290 int cmd;
8291 int factor; /* multiply by to get rlim_{cur,max} values */
8292 char option;
Eric Andersencb57d552001-06-28 07:25:16 +00008293};
8294
8295static const struct limits limits[] = {
8296#ifdef RLIMIT_CPU
Eric Andersen2870d962001-07-02 17:27:21 +00008297 { "time(seconds)", RLIMIT_CPU, 1, 't' },
Eric Andersencb57d552001-06-28 07:25:16 +00008298#endif
8299#ifdef RLIMIT_FSIZE
Eric Andersen2870d962001-07-02 17:27:21 +00008300 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
Eric Andersencb57d552001-06-28 07:25:16 +00008301#endif
8302#ifdef RLIMIT_DATA
Eric Andersen2870d962001-07-02 17:27:21 +00008303 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
Eric Andersencb57d552001-06-28 07:25:16 +00008304#endif
8305#ifdef RLIMIT_STACK
Eric Andersen2870d962001-07-02 17:27:21 +00008306 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
Eric Andersencb57d552001-06-28 07:25:16 +00008307#endif
8308#ifdef RLIMIT_CORE
Eric Andersen2870d962001-07-02 17:27:21 +00008309 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
Eric Andersencb57d552001-06-28 07:25:16 +00008310#endif
8311#ifdef RLIMIT_RSS
Eric Andersen2870d962001-07-02 17:27:21 +00008312 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
Eric Andersencb57d552001-06-28 07:25:16 +00008313#endif
8314#ifdef RLIMIT_MEMLOCK
Eric Andersen2870d962001-07-02 17:27:21 +00008315 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
Eric Andersencb57d552001-06-28 07:25:16 +00008316#endif
8317#ifdef RLIMIT_NPROC
Eric Andersen2870d962001-07-02 17:27:21 +00008318 { "process(processes)", RLIMIT_NPROC, 1, 'p' },
Eric Andersencb57d552001-06-28 07:25:16 +00008319#endif
8320#ifdef RLIMIT_NOFILE
Eric Andersen2870d962001-07-02 17:27:21 +00008321 { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
Eric Andersencb57d552001-06-28 07:25:16 +00008322#endif
8323#ifdef RLIMIT_VMEM
Eric Andersen2870d962001-07-02 17:27:21 +00008324 { "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' },
Eric Andersencb57d552001-06-28 07:25:16 +00008325#endif
8326#ifdef RLIMIT_SWAP
Eric Andersen2870d962001-07-02 17:27:21 +00008327 { "swap(kbytes)", RLIMIT_SWAP, 1024, 'w' },
Eric Andersencb57d552001-06-28 07:25:16 +00008328#endif
Eric Andersen2870d962001-07-02 17:27:21 +00008329 { (char *) 0, 0, 0, '\0' }
Eric Andersencb57d552001-06-28 07:25:16 +00008330};
8331
8332static int
8333ulimitcmd(argc, argv)
8334 int argc;
8335 char **argv;
8336{
Eric Andersen2870d962001-07-02 17:27:21 +00008337 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00008338 rlim_t val = 0;
8339 enum { SOFT = 0x1, HARD = 0x2 }
8340 how = SOFT | HARD;
Eric Andersen2870d962001-07-02 17:27:21 +00008341 const struct limits *l;
8342 int set, all = 0;
8343 int optc, what;
8344 struct rlimit limit;
Eric Andersencb57d552001-06-28 07:25:16 +00008345
8346 what = 'f';
8347 while ((optc = nextopt("HSatfdsmcnpl")) != '\0')
8348 switch (optc) {
8349 case 'H':
8350 how = HARD;
8351 break;
8352 case 'S':
8353 how = SOFT;
8354 break;
8355 case 'a':
8356 all = 1;
8357 break;
8358 default:
8359 what = optc;
8360 }
8361
8362 for (l = limits; l->name && l->option != what; l++)
8363 ;
8364 if (!l->name)
8365 error("internal error (%c)", what);
8366
8367 set = *argptr ? 1 : 0;
8368 if (set) {
8369 char *p = *argptr;
8370
8371 if (all || argptr[1])
8372 error("too many arguments");
8373 if (strcmp(p, "unlimited") == 0)
8374 val = RLIM_INFINITY;
8375 else {
8376 val = (rlim_t) 0;
8377
8378 while ((c = *p++) >= '0' && c <= '9')
8379 {
8380 val = (val * 10) + (long)(c - '0');
8381 if (val < (rlim_t) 0)
8382 break;
8383 }
8384 if (c)
8385 error("bad number");
8386 val *= l->factor;
8387 }
8388 }
8389 if (all) {
8390 for (l = limits; l->name; l++) {
8391 getrlimit(l->cmd, &limit);
8392 if (how & SOFT)
8393 val = limit.rlim_cur;
8394 else if (how & HARD)
8395 val = limit.rlim_max;
8396
Eric Andersen62483552001-07-10 06:09:16 +00008397 printf("%-20s ", l->name);
Eric Andersencb57d552001-06-28 07:25:16 +00008398 if (val == RLIM_INFINITY)
Eric Andersen62483552001-07-10 06:09:16 +00008399 printf("unlimited\n");
Eric Andersencb57d552001-06-28 07:25:16 +00008400 else
8401 {
8402 val /= l->factor;
Eric Andersen62483552001-07-10 06:09:16 +00008403 printf("%lld\n", (long long) val);
Eric Andersencb57d552001-06-28 07:25:16 +00008404 }
8405 }
8406 return 0;
8407 }
8408
8409 getrlimit(l->cmd, &limit);
8410 if (set) {
8411 if (how & HARD)
8412 limit.rlim_max = val;
8413 if (how & SOFT)
8414 limit.rlim_cur = val;
8415 if (setrlimit(l->cmd, &limit) < 0)
Eric Andersen2870d962001-07-02 17:27:21 +00008416 error("error setting limit (%m)");
Eric Andersencb57d552001-06-28 07:25:16 +00008417 } else {
8418 if (how & SOFT)
8419 val = limit.rlim_cur;
8420 else if (how & HARD)
8421 val = limit.rlim_max;
8422
8423 if (val == RLIM_INFINITY)
Eric Andersen62483552001-07-10 06:09:16 +00008424 printf("unlimited\n");
Eric Andersencb57d552001-06-28 07:25:16 +00008425 else
8426 {
8427 val /= l->factor;
Eric Andersen62483552001-07-10 06:09:16 +00008428 printf("%lld\n", (long long) val);
Eric Andersencb57d552001-06-28 07:25:16 +00008429 }
8430 }
8431 return 0;
8432}
Eric Andersencb57d552001-06-28 07:25:16 +00008433/*
8434 * prefix -- see if pfx is a prefix of string.
8435 */
8436
8437static int
Eric Andersen62483552001-07-10 06:09:16 +00008438prefix(char const *pfx, char const *string)
8439{
Eric Andersencb57d552001-06-28 07:25:16 +00008440 while (*pfx) {
8441 if (*pfx++ != *string++)
8442 return 0;
8443 }
8444 return 1;
8445}
8446
Eric Andersen2870d962001-07-02 17:27:21 +00008447/*
8448 * Return true if s is a string of digits, and save munber in intptr
8449 * nagative is bad
8450 */
8451
8452static int
8453is_number(const char *p, int *intptr)
8454{
8455 int ret = 0;
8456
8457 do {
8458 if (! is_digit(*p))
8459 return 0;
8460 ret *= 10;
8461 ret += digit_val(*p);
8462 p++;
8463 } while (*p != '\0');
8464
8465 *intptr = ret;
8466 return 1;
8467}
Eric Andersencb57d552001-06-28 07:25:16 +00008468
8469/*
8470 * Convert a string of digits to an integer, printing an error message on
8471 * failure.
8472 */
8473
8474static int
Eric Andersen2870d962001-07-02 17:27:21 +00008475number(const char *s)
8476{
8477 int i;
8478 if (! is_number(s, &i))
Eric Andersencb57d552001-06-28 07:25:16 +00008479 error("Illegal number: %s", s);
Eric Andersen2870d962001-07-02 17:27:21 +00008480 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00008481}
8482
Eric Andersencb57d552001-06-28 07:25:16 +00008483/*
8484 * Produce a possibly single quoted string suitable as input to the shell.
8485 * The return string is allocated on the stack.
8486 */
8487
8488static char *
8489single_quote(const char *s) {
8490 char *p;
8491
8492 STARTSTACKSTR(p);
8493
8494 do {
8495 char *q = p;
8496 size_t len1, len1p, len2, len2p;
8497
8498 len1 = strcspn(s, "'");
8499 len2 = strspn(s + len1, "'");
8500
8501 len1p = len1 ? len1 + 2 : len1;
8502 switch (len2) {
8503 case 0:
8504 len2p = 0;
8505 break;
8506 case 1:
8507 len2p = 2;
8508 break;
8509 default:
8510 len2p = len2 + 2;
8511 }
8512
8513 CHECKSTRSPACE(len1p + len2p + 1, p);
8514
8515 if (len1) {
8516 *p = '\'';
Eric Andersencb57d552001-06-28 07:25:16 +00008517 q = p + 1 + len1;
8518 memcpy(p + 1, s, len1);
Eric Andersencb57d552001-06-28 07:25:16 +00008519 *q++ = '\'';
8520 s += len1;
8521 }
8522
8523 switch (len2) {
8524 case 0:
8525 break;
8526 case 1:
8527 *q++ = '\\';
8528 *q = '\'';
8529 s++;
8530 break;
8531 default:
8532 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008533 q += 1 + len2;
8534 memcpy(q + 1, s, len2);
8535 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008536 s += len2;
8537 }
8538
8539 STADJUST(len1p + len2p, p);
8540 } while (*s);
8541
8542 USTPUTC(0, p);
8543
8544 return grabstackstr(p);
8545}
8546
8547/*
8548 * Like strdup but works with the ash stack.
8549 */
8550
8551static char *
8552sstrdup(const char *p)
8553{
8554 size_t len = strlen(p) + 1;
8555 return memcpy(stalloc(len), p, len);
8556}
8557
Eric Andersencb57d552001-06-28 07:25:16 +00008558
8559/*
Eric Andersencb57d552001-06-28 07:25:16 +00008560 * Routine for dealing with parsed shell commands.
8561 */
8562
8563
Eric Andersen62483552001-07-10 06:09:16 +00008564static void sizenodelist (const struct nodelist *);
8565static struct nodelist *copynodelist (const struct nodelist *);
8566static char *nodesavestr (const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00008567
8568static void
Eric Andersen62483552001-07-10 06:09:16 +00008569calcsize(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008570{
8571 if (n == NULL)
8572 return;
8573 funcblocksize += nodesize[n->type];
8574 switch (n->type) {
8575 case NSEMI:
8576 case NAND:
8577 case NOR:
8578 case NWHILE:
8579 case NUNTIL:
8580 calcsize(n->nbinary.ch2);
8581 calcsize(n->nbinary.ch1);
8582 break;
8583 case NCMD:
8584 calcsize(n->ncmd.redirect);
8585 calcsize(n->ncmd.args);
8586 calcsize(n->ncmd.assign);
8587 break;
8588 case NPIPE:
8589 sizenodelist(n->npipe.cmdlist);
8590 break;
8591 case NREDIR:
8592 case NBACKGND:
8593 case NSUBSHELL:
8594 calcsize(n->nredir.redirect);
8595 calcsize(n->nredir.n);
8596 break;
8597 case NIF:
8598 calcsize(n->nif.elsepart);
8599 calcsize(n->nif.ifpart);
8600 calcsize(n->nif.test);
8601 break;
8602 case NFOR:
8603 funcstringsize += strlen(n->nfor.var) + 1;
8604 calcsize(n->nfor.body);
8605 calcsize(n->nfor.args);
8606 break;
8607 case NCASE:
8608 calcsize(n->ncase.cases);
8609 calcsize(n->ncase.expr);
8610 break;
8611 case NCLIST:
8612 calcsize(n->nclist.body);
8613 calcsize(n->nclist.pattern);
8614 calcsize(n->nclist.next);
8615 break;
8616 case NDEFUN:
8617 case NARG:
8618 sizenodelist(n->narg.backquote);
8619 funcstringsize += strlen(n->narg.text) + 1;
8620 calcsize(n->narg.next);
8621 break;
8622 case NTO:
8623 case NFROM:
8624 case NFROMTO:
8625 case NAPPEND:
8626 case NTOOV:
8627 calcsize(n->nfile.fname);
8628 calcsize(n->nfile.next);
8629 break;
8630 case NTOFD:
8631 case NFROMFD:
8632 calcsize(n->ndup.vname);
8633 calcsize(n->ndup.next);
8634 break;
8635 case NHERE:
8636 case NXHERE:
8637 calcsize(n->nhere.doc);
8638 calcsize(n->nhere.next);
8639 break;
8640 case NNOT:
8641 calcsize(n->nnot.com);
8642 break;
8643 };
8644}
8645
Eric Andersencb57d552001-06-28 07:25:16 +00008646static void
Eric Andersen62483552001-07-10 06:09:16 +00008647sizenodelist(const struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008648{
8649 while (lp) {
8650 funcblocksize += ALIGN(sizeof(struct nodelist));
8651 calcsize(lp->n);
8652 lp = lp->next;
8653 }
8654}
8655
8656
Eric Andersencb57d552001-06-28 07:25:16 +00008657static union node *
Eric Andersen62483552001-07-10 06:09:16 +00008658copynode(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008659{
Eric Andersen62483552001-07-10 06:09:16 +00008660 union node *new;
Eric Andersencb57d552001-06-28 07:25:16 +00008661
8662 if (n == NULL)
8663 return NULL;
8664 new = funcblock;
8665 funcblock = (char *) funcblock + nodesize[n->type];
8666 switch (n->type) {
8667 case NSEMI:
8668 case NAND:
8669 case NOR:
8670 case NWHILE:
8671 case NUNTIL:
8672 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8673 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8674 break;
8675 case NCMD:
8676 new->ncmd.redirect = copynode(n->ncmd.redirect);
8677 new->ncmd.args = copynode(n->ncmd.args);
8678 new->ncmd.assign = copynode(n->ncmd.assign);
8679 new->ncmd.backgnd = n->ncmd.backgnd;
8680 break;
8681 case NPIPE:
8682 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8683 new->npipe.backgnd = n->npipe.backgnd;
8684 break;
8685 case NREDIR:
8686 case NBACKGND:
8687 case NSUBSHELL:
8688 new->nredir.redirect = copynode(n->nredir.redirect);
8689 new->nredir.n = copynode(n->nredir.n);
8690 break;
8691 case NIF:
8692 new->nif.elsepart = copynode(n->nif.elsepart);
8693 new->nif.ifpart = copynode(n->nif.ifpart);
8694 new->nif.test = copynode(n->nif.test);
8695 break;
8696 case NFOR:
8697 new->nfor.var = nodesavestr(n->nfor.var);
8698 new->nfor.body = copynode(n->nfor.body);
8699 new->nfor.args = copynode(n->nfor.args);
8700 break;
8701 case NCASE:
8702 new->ncase.cases = copynode(n->ncase.cases);
8703 new->ncase.expr = copynode(n->ncase.expr);
8704 break;
8705 case NCLIST:
8706 new->nclist.body = copynode(n->nclist.body);
8707 new->nclist.pattern = copynode(n->nclist.pattern);
8708 new->nclist.next = copynode(n->nclist.next);
8709 break;
8710 case NDEFUN:
8711 case NARG:
8712 new->narg.backquote = copynodelist(n->narg.backquote);
8713 new->narg.text = nodesavestr(n->narg.text);
8714 new->narg.next = copynode(n->narg.next);
8715 break;
8716 case NTO:
8717 case NFROM:
8718 case NFROMTO:
8719 case NAPPEND:
8720 case NTOOV:
8721 new->nfile.fname = copynode(n->nfile.fname);
8722 new->nfile.fd = n->nfile.fd;
8723 new->nfile.next = copynode(n->nfile.next);
8724 break;
8725 case NTOFD:
8726 case NFROMFD:
8727 new->ndup.vname = copynode(n->ndup.vname);
8728 new->ndup.dupfd = n->ndup.dupfd;
8729 new->ndup.fd = n->ndup.fd;
8730 new->ndup.next = copynode(n->ndup.next);
8731 break;
8732 case NHERE:
8733 case NXHERE:
8734 new->nhere.doc = copynode(n->nhere.doc);
8735 new->nhere.fd = n->nhere.fd;
8736 new->nhere.next = copynode(n->nhere.next);
8737 break;
8738 case NNOT:
8739 new->nnot.com = copynode(n->nnot.com);
8740 break;
8741 };
8742 new->type = n->type;
Eric Andersen62483552001-07-10 06:09:16 +00008743 return new;
Eric Andersencb57d552001-06-28 07:25:16 +00008744}
8745
8746
8747static struct nodelist *
Eric Andersen62483552001-07-10 06:09:16 +00008748copynodelist(const struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008749{
8750 struct nodelist *start;
8751 struct nodelist **lpp;
8752
8753 lpp = &start;
8754 while (lp) {
8755 *lpp = funcblock;
8756 funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist));
8757 (*lpp)->n = copynode(lp->n);
8758 lp = lp->next;
8759 lpp = &(*lpp)->next;
8760 }
8761 *lpp = NULL;
8762 return start;
8763}
8764
8765
Eric Andersencb57d552001-06-28 07:25:16 +00008766static char *
Eric Andersen62483552001-07-10 06:09:16 +00008767nodesavestr(const char *s)
Eric Andersencb57d552001-06-28 07:25:16 +00008768{
Eric Andersen62483552001-07-10 06:09:16 +00008769 const char *p = s;
8770 char *q = funcstring;
Eric Andersencb57d552001-06-28 07:25:16 +00008771 char *rtn = funcstring;
8772
8773 while ((*q++ = *p++) != '\0')
8774 continue;
8775 funcstring = q;
8776 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00008777}
8778
Eric Andersencb57d552001-06-28 07:25:16 +00008779#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00008780static int getopts (char *, char *, char **, int *, int *);
Eric Andersencb57d552001-06-28 07:25:16 +00008781#endif
8782
8783
8784/*
8785 * Process the shell command line arguments.
8786 */
8787
8788static void
8789procargs(argc, argv)
8790 int argc;
8791 char **argv;
8792{
8793 int i;
8794
8795 argptr = argv;
8796 if (argc > 0)
8797 argptr++;
8798 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00008799 optent_val(i) = 2;
Eric Andersencb57d552001-06-28 07:25:16 +00008800 options(1);
8801 if (*argptr == NULL && minusc == NULL)
8802 sflag = 1;
8803 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8804 iflag = 1;
8805 if (mflag == 2)
8806 mflag = iflag;
8807 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00008808 if (optent_val(i) == 2)
8809 optent_val(i) = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008810 arg0 = argv[0];
8811 if (sflag == 0 && minusc == NULL) {
8812 commandname = argv[0];
8813 arg0 = *argptr++;
8814 setinputfile(arg0, 0);
8815 commandname = arg0;
8816 }
8817 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8818 if (argptr && minusc && *argptr)
Eric Andersen2870d962001-07-02 17:27:21 +00008819 arg0 = *argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00008820
8821 shellparam.p = argptr;
8822 shellparam.optind = 1;
8823 shellparam.optoff = -1;
8824 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8825 while (*argptr) {
8826 shellparam.nparam++;
8827 argptr++;
8828 }
8829 optschanged();
8830}
8831
8832
Eric Andersencb57d552001-06-28 07:25:16 +00008833
8834/*
8835 * Process shell options. The global variable argptr contains a pointer
8836 * to the argument list; we advance it past the options.
8837 */
8838
Eric Andersen62483552001-07-10 06:09:16 +00008839static inline void
8840minus_o(const char *name, int val)
8841{
8842 int i;
8843
8844 if (name == NULL) {
8845 out1str("Current option settings\n");
8846 for (i = 0; i < NOPTS; i++)
8847 printf("%-16s%s\n", optent_name(optlist[i]),
8848 optent_val(i) ? "on" : "off");
8849 } else {
8850 for (i = 0; i < NOPTS; i++)
8851 if (equal(name, optent_name(optlist[i]))) {
8852 setoption(optent_letter(optlist[i]), val);
8853 return;
8854 }
8855 error("Illegal option -o %s", name);
8856 }
8857}
8858
8859
Eric Andersencb57d552001-06-28 07:25:16 +00008860static void
Eric Andersen62483552001-07-10 06:09:16 +00008861options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00008862{
8863 char *p;
8864 int val;
8865 int c;
8866
8867 if (cmdline)
8868 minusc = NULL;
8869 while ((p = *argptr) != NULL) {
8870 argptr++;
8871 if ((c = *p++) == '-') {
8872 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00008873 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8874 if (!cmdline) {
8875 /* "-" means turn off -x and -v */
8876 if (p[0] == '\0')
8877 xflag = vflag = 0;
8878 /* "--" means reset params */
8879 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00008880 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00008881 }
8882 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00008883 }
8884 } else if (c == '+') {
8885 val = 0;
8886 } else {
8887 argptr--;
8888 break;
8889 }
8890 while ((c = *p++) != '\0') {
8891 if (c == 'c' && cmdline) {
8892 char *q;
Eric Andersen2870d962001-07-02 17:27:21 +00008893#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */
Eric Andersencb57d552001-06-28 07:25:16 +00008894 if (*p == '\0')
8895#endif
8896 q = *argptr++;
8897 if (q == NULL || minusc != NULL)
8898 error("Bad -c option");
8899 minusc = q;
8900#ifdef NOHACK
8901 break;
8902#endif
8903 } else if (c == 'o') {
8904 minus_o(*argptr, val);
8905 if (*argptr)
8906 argptr++;
8907 } else {
8908 setoption(c, val);
8909 }
8910 }
8911 }
8912}
8913
Eric Andersencb57d552001-06-28 07:25:16 +00008914
8915static void
Eric Andersen2870d962001-07-02 17:27:21 +00008916setoption(int flag, int val)
8917{
Eric Andersencb57d552001-06-28 07:25:16 +00008918 int i;
8919
8920 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00008921 if (optent_letter(optlist[i]) == flag) {
8922 optent_val(i) = val;
Eric Andersencb57d552001-06-28 07:25:16 +00008923 if (val) {
8924 /* #%$ hack for ksh semantics */
8925 if (flag == 'V')
8926 Eflag = 0;
8927 else if (flag == 'E')
8928 Vflag = 0;
8929 }
8930 return;
8931 }
8932 error("Illegal option -%c", flag);
8933 /* NOTREACHED */
8934}
8935
8936
8937
Eric Andersencb57d552001-06-28 07:25:16 +00008938/*
8939 * Set the shell parameters.
8940 */
8941
8942static void
Eric Andersen2870d962001-07-02 17:27:21 +00008943setparam(char **argv)
8944{
Eric Andersencb57d552001-06-28 07:25:16 +00008945 char **newparam;
8946 char **ap;
8947 int nparam;
8948
8949 for (nparam = 0 ; argv[nparam] ; nparam++);
8950 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
8951 while (*argv) {
8952 *ap++ = savestr(*argv++);
8953 }
8954 *ap = NULL;
8955 freeparam(&shellparam);
8956 shellparam.malloc = 1;
8957 shellparam.nparam = nparam;
8958 shellparam.p = newparam;
8959 shellparam.optind = 1;
8960 shellparam.optoff = -1;
8961}
8962
8963
8964/*
8965 * Free the list of positional parameters.
8966 */
8967
8968static void
Eric Andersen2870d962001-07-02 17:27:21 +00008969freeparam(volatile struct shparam *param)
8970{
Eric Andersencb57d552001-06-28 07:25:16 +00008971 char **ap;
8972
8973 if (param->malloc) {
8974 for (ap = param->p ; *ap ; ap++)
8975 ckfree(*ap);
8976 ckfree(param->p);
8977 }
8978}
8979
8980
8981
8982/*
8983 * The shift builtin command.
8984 */
8985
8986static int
8987shiftcmd(argc, argv)
8988 int argc;
8989 char **argv;
8990{
8991 int n;
8992 char **ap1, **ap2;
8993
8994 n = 1;
8995 if (argc > 1)
8996 n = number(argv[1]);
8997 if (n > shellparam.nparam)
8998 error("can't shift that many");
8999 INTOFF;
9000 shellparam.nparam -= n;
9001 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
9002 if (shellparam.malloc)
9003 ckfree(*ap1);
9004 }
9005 ap2 = shellparam.p;
9006 while ((*ap2++ = *ap1++) != NULL);
9007 shellparam.optind = 1;
9008 shellparam.optoff = -1;
9009 INTON;
9010 return 0;
9011}
9012
9013
9014
9015/*
9016 * The set command builtin.
9017 */
9018
9019static int
9020setcmd(argc, argv)
9021 int argc;
9022 char **argv;
9023{
9024 if (argc == 1)
9025 return showvarscmd(argc, argv);
9026 INTOFF;
9027 options(0);
9028 optschanged();
9029 if (*argptr != NULL) {
9030 setparam(argptr);
9031 }
9032 INTON;
9033 return 0;
9034}
9035
9036
9037static void
Eric Andersen2870d962001-07-02 17:27:21 +00009038getoptsreset(const char *value)
Eric Andersencb57d552001-06-28 07:25:16 +00009039{
9040 shellparam.optind = number(value);
9041 shellparam.optoff = -1;
9042}
9043
Eric Andersen2870d962001-07-02 17:27:21 +00009044#ifdef BB_LOCALE_SUPPORT
9045static void change_lc_all(const char *value)
9046{
9047 if(value != 0 && *value != 0)
9048 setlocale(LC_ALL, value);
9049}
9050
9051static void change_lc_ctype(const char *value)
9052{
9053 if(value != 0 && *value != 0)
9054 setlocale(LC_CTYPE, value);
9055}
9056
9057#endif
9058
Eric Andersencb57d552001-06-28 07:25:16 +00009059#ifdef ASH_GETOPTS
9060/*
9061 * The getopts builtin. Shellparam.optnext points to the next argument
9062 * to be processed. Shellparam.optptr points to the next character to
9063 * be processed in the current argument. If shellparam.optnext is NULL,
9064 * then it's the first time getopts has been called.
9065 */
9066
9067static int
9068getoptscmd(argc, argv)
9069 int argc;
9070 char **argv;
9071{
9072 char **optbase;
9073
9074 if (argc < 3)
9075 error("Usage: getopts optstring var [arg]");
9076 else if (argc == 3) {
9077 optbase = shellparam.p;
9078 if (shellparam.optind > shellparam.nparam + 1) {
9079 shellparam.optind = 1;
9080 shellparam.optoff = -1;
9081 }
9082 }
9083 else {
9084 optbase = &argv[3];
9085 if (shellparam.optind > argc - 2) {
9086 shellparam.optind = 1;
9087 shellparam.optoff = -1;
9088 }
9089 }
9090
9091 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9092 &shellparam.optoff);
9093}
9094
9095/*
9096 * Safe version of setvar, returns 1 on success 0 on failure.
9097 */
9098
9099static int
9100setvarsafe(name, val, flags)
9101 const char *name, *val;
9102 int flags;
9103{
9104 struct jmploc jmploc;
9105 struct jmploc *volatile savehandler = handler;
9106 int err = 0;
9107#ifdef __GNUC__
9108 (void) &err;
9109#endif
9110
9111 if (setjmp(jmploc.loc))
9112 err = 1;
9113 else {
9114 handler = &jmploc;
9115 setvar(name, val, flags);
9116 }
9117 handler = savehandler;
9118 return err;
9119}
9120
9121static int
9122getopts(optstr, optvar, optfirst, myoptind, optoff)
9123 char *optstr;
9124 char *optvar;
9125 char **optfirst;
9126 int *myoptind;
9127 int *optoff;
9128{
9129 char *p, *q;
9130 char c = '?';
9131 int done = 0;
9132 int err = 0;
9133 char s[10];
9134 char **optnext = optfirst + *myoptind - 1;
9135
9136 if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
9137 strlen(*(optnext - 1)) < *optoff)
9138 p = NULL;
9139 else
9140 p = *(optnext - 1) + *optoff;
9141 if (p == NULL || *p == '\0') {
9142 /* Current word is done, advance */
9143 if (optnext == NULL)
9144 return 1;
9145 p = *optnext;
9146 if (p == NULL || *p != '-' || *++p == '\0') {
9147atend:
9148 *myoptind = optnext - optfirst + 1;
9149 p = NULL;
9150 done = 1;
9151 goto out;
9152 }
9153 optnext++;
Eric Andersen2870d962001-07-02 17:27:21 +00009154 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009155 goto atend;
9156 }
9157
9158 c = *p++;
9159 for (q = optstr; *q != c; ) {
9160 if (*q == '\0') {
9161 if (optstr[0] == ':') {
9162 s[0] = c;
9163 s[1] = '\0';
9164 err |= setvarsafe("OPTARG", s, 0);
9165 }
9166 else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009167 out2fmt("Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009168 (void) unsetvar("OPTARG");
9169 }
9170 c = '?';
9171 goto bad;
9172 }
9173 if (*++q == ':')
9174 q++;
9175 }
9176
9177 if (*++q == ':') {
9178 if (*p == '\0' && (p = *optnext) == NULL) {
9179 if (optstr[0] == ':') {
9180 s[0] = c;
9181 s[1] = '\0';
9182 err |= setvarsafe("OPTARG", s, 0);
9183 c = ':';
9184 }
9185 else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009186 out2fmt("No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009187 (void) unsetvar("OPTARG");
9188 c = '?';
9189 }
9190 goto bad;
9191 }
9192
9193 if (p == *optnext)
9194 optnext++;
9195 setvarsafe("OPTARG", p, 0);
9196 p = NULL;
9197 }
9198 else
9199 setvarsafe("OPTARG", "", 0);
9200 *myoptind = optnext - optfirst + 1;
9201 goto out;
9202
9203bad:
9204 *myoptind = 1;
9205 p = NULL;
9206out:
9207 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersen3102ac42001-07-06 04:26:23 +00009208 snprintf(s, sizeof(s), "%d", *myoptind);
Eric Andersencb57d552001-06-28 07:25:16 +00009209 err |= setvarsafe("OPTIND", s, VNOFUNC);
9210 s[0] = c;
9211 s[1] = '\0';
9212 err |= setvarsafe(optvar, s, 0);
9213 if (err) {
9214 *myoptind = 1;
9215 *optoff = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00009216 exraise(EXERROR);
9217 }
9218 return done;
9219}
Eric Andersen2870d962001-07-02 17:27:21 +00009220#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009221
9222/*
9223 * XXX - should get rid of. have all builtins use getopt(3). the
9224 * library getopt must have the BSD extension static variable "optreset"
9225 * otherwise it can't be used within the shell safely.
9226 *
9227 * Standard option processing (a la getopt) for builtin routines. The
9228 * only argument that is passed to nextopt is the option string; the
9229 * other arguments are unnecessary. It return the character, or '\0' on
9230 * end of input.
9231 */
9232
9233static int
Eric Andersen62483552001-07-10 06:09:16 +00009234nextopt(const char *optstring)
9235{
Eric Andersencb57d552001-06-28 07:25:16 +00009236 char *p;
9237 const char *q;
9238 char c;
9239
9240 if ((p = optptr) == NULL || *p == '\0') {
9241 p = *argptr;
9242 if (p == NULL || *p != '-' || *++p == '\0')
9243 return '\0';
9244 argptr++;
Eric Andersen2870d962001-07-02 17:27:21 +00009245 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009246 return '\0';
9247 }
9248 c = *p++;
9249 for (q = optstring ; *q != c ; ) {
9250 if (*q == '\0')
9251 error("Illegal option -%c", c);
9252 if (*++q == ':')
9253 q++;
9254 }
9255 if (*++q == ':') {
9256 if (*p == '\0' && (p = *argptr++) == NULL)
9257 error("No arg for -%c option", c);
9258 optionarg = p;
9259 p = NULL;
9260 }
9261 optptr = p;
9262 return c;
9263}
9264
Eric Andersencb57d552001-06-28 07:25:16 +00009265static void
9266flushall() {
Eric Andersencb57d552001-06-28 07:25:16 +00009267 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009268 fflush(stdout);
Eric Andersencb57d552001-06-28 07:25:16 +00009269 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009270}
9271
9272
9273static void
Eric Andersen3102ac42001-07-06 04:26:23 +00009274out2fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009275{
9276 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00009277 va_start(ap, fmt);
Eric Andersen3102ac42001-07-06 04:26:23 +00009278 vfprintf(stderr, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009279 va_end(ap);
9280}
9281
Eric Andersencb57d552001-06-28 07:25:16 +00009282/*
9283 * Version of write which resumes after a signal is caught.
9284 */
9285
9286static int
Eric Andersen2870d962001-07-02 17:27:21 +00009287xwrite(int fd, const char *buf, int nbytes)
9288{
Eric Andersencb57d552001-06-28 07:25:16 +00009289 int ntry;
9290 int i;
9291 int n;
9292
9293 n = nbytes;
9294 ntry = 0;
9295 for (;;) {
9296 i = write(fd, buf, n);
9297 if (i > 0) {
9298 if ((n -= i) <= 0)
9299 return nbytes;
9300 buf += i;
9301 ntry = 0;
9302 } else if (i == 0) {
9303 if (++ntry > 10)
9304 return nbytes - n;
9305 } else if (errno != EINTR) {
9306 return -1;
9307 }
9308 }
9309}
9310
9311
Eric Andersencb57d552001-06-28 07:25:16 +00009312/*
9313 * Shell command parser.
9314 */
9315
9316#define EOFMARKLEN 79
9317
9318
9319
9320struct heredoc {
Eric Andersen2870d962001-07-02 17:27:21 +00009321 struct heredoc *next; /* next here document in list */
9322 union node *here; /* redirection node */
9323 char *eofmark; /* string indicating end of input */
9324 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009325};
9326
Eric Andersen2870d962001-07-02 17:27:21 +00009327static struct heredoc *heredoclist; /* list of here documents to read */
9328static int parsebackquote; /* nonzero if we are inside backquotes */
9329static int doprompt; /* if set, prompt the user */
9330static int needprompt; /* true if interactive and at start of line */
9331static int lasttoken; /* last token read */
Eric Andersencb57d552001-06-28 07:25:16 +00009332
Eric Andersen2870d962001-07-02 17:27:21 +00009333static char *wordtext; /* text of last word returned by readtoken */
Eric Andersencb57d552001-06-28 07:25:16 +00009334
Eric Andersen2870d962001-07-02 17:27:21 +00009335static struct nodelist *backquotelist;
9336static union node *redirnode;
Eric Andersen044228d2001-07-17 01:12:36 +00009337static struct heredoc *heredoc;
Eric Andersen2870d962001-07-02 17:27:21 +00009338static int quoteflag; /* set if (part of) last token was quoted */
9339static int startlinno; /* line # where last token started */
Eric Andersencb57d552001-06-28 07:25:16 +00009340
9341
Eric Andersen2870d962001-07-02 17:27:21 +00009342static union node *list (int);
9343static union node *andor (void);
9344static union node *pipeline (void);
9345static union node *command (void);
9346static union node *simplecmd (void);
9347static void parsefname (void);
9348static void parseheredoc (void);
9349static int peektoken (void);
9350static int readtoken (void);
9351static int xxreadtoken (void);
9352static int readtoken1 (int, char const *, char *, int);
9353static int noexpand (char *);
9354static void synexpect (int) __attribute__((noreturn));
9355static void synerror (const char *) __attribute__((noreturn));
9356static void setprompt (int);
Eric Andersencb57d552001-06-28 07:25:16 +00009357
9358
9359/*
9360 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9361 * valid parse tree indicating a blank line.)
9362 */
9363
Eric Andersen2870d962001-07-02 17:27:21 +00009364static union node *
Eric Andersencb57d552001-06-28 07:25:16 +00009365parsecmd(int interact)
9366{
9367 int t;
9368
9369 tokpushback = 0;
9370 doprompt = interact;
9371 if (doprompt)
9372 setprompt(1);
9373 else
9374 setprompt(0);
9375 needprompt = 0;
9376 t = readtoken();
9377 if (t == TEOF)
9378 return NEOF;
9379 if (t == TNL)
9380 return NULL;
9381 tokpushback++;
9382 return list(1);
9383}
9384
9385
9386static union node *
9387list(nlflag)
9388 int nlflag;
9389{
9390 union node *n1, *n2, *n3;
9391 int tok;
9392
9393 checkkwd = 2;
9394 if (nlflag == 0 && tokendlist[peektoken()])
9395 return NULL;
9396 n1 = NULL;
9397 for (;;) {
9398 n2 = andor();
9399 tok = readtoken();
9400 if (tok == TBACKGND) {
9401 if (n2->type == NCMD || n2->type == NPIPE) {
9402 n2->ncmd.backgnd = 1;
9403 } else if (n2->type == NREDIR) {
9404 n2->type = NBACKGND;
9405 } else {
9406 n3 = (union node *)stalloc(sizeof (struct nredir));
9407 n3->type = NBACKGND;
9408 n3->nredir.n = n2;
9409 n3->nredir.redirect = NULL;
9410 n2 = n3;
9411 }
9412 }
9413 if (n1 == NULL) {
9414 n1 = n2;
9415 }
9416 else {
9417 n3 = (union node *)stalloc(sizeof (struct nbinary));
9418 n3->type = NSEMI;
9419 n3->nbinary.ch1 = n1;
9420 n3->nbinary.ch2 = n2;
9421 n1 = n3;
9422 }
9423 switch (tok) {
9424 case TBACKGND:
9425 case TSEMI:
9426 tok = readtoken();
9427 /* fall through */
9428 case TNL:
9429 if (tok == TNL) {
9430 parseheredoc();
9431 if (nlflag)
9432 return n1;
9433 } else {
9434 tokpushback++;
9435 }
9436 checkkwd = 2;
9437 if (tokendlist[peektoken()])
9438 return n1;
9439 break;
9440 case TEOF:
9441 if (heredoclist)
9442 parseheredoc();
9443 else
Eric Andersen2870d962001-07-02 17:27:21 +00009444 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009445 return n1;
9446 default:
9447 if (nlflag)
9448 synexpect(-1);
9449 tokpushback++;
9450 return n1;
9451 }
9452 }
9453}
9454
9455
9456
9457static union node *
9458andor() {
9459 union node *n1, *n2, *n3;
9460 int t;
9461
9462 checkkwd = 1;
9463 n1 = pipeline();
9464 for (;;) {
9465 if ((t = readtoken()) == TAND) {
9466 t = NAND;
9467 } else if (t == TOR) {
9468 t = NOR;
9469 } else {
9470 tokpushback++;
9471 return n1;
9472 }
9473 checkkwd = 2;
9474 n2 = pipeline();
9475 n3 = (union node *)stalloc(sizeof (struct nbinary));
9476 n3->type = t;
9477 n3->nbinary.ch1 = n1;
9478 n3->nbinary.ch2 = n2;
9479 n1 = n3;
9480 }
9481}
9482
9483
9484
9485static union node *
9486pipeline() {
9487 union node *n1, *n2, *pipenode;
9488 struct nodelist *lp, *prev;
9489 int negate;
9490
9491 negate = 0;
9492 TRACE(("pipeline: entered\n"));
9493 if (readtoken() == TNOT) {
9494 negate = !negate;
9495 checkkwd = 1;
9496 } else
9497 tokpushback++;
9498 n1 = command();
9499 if (readtoken() == TPIPE) {
9500 pipenode = (union node *)stalloc(sizeof (struct npipe));
9501 pipenode->type = NPIPE;
9502 pipenode->npipe.backgnd = 0;
9503 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9504 pipenode->npipe.cmdlist = lp;
9505 lp->n = n1;
9506 do {
9507 prev = lp;
9508 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9509 checkkwd = 2;
9510 lp->n = command();
9511 prev->next = lp;
9512 } while (readtoken() == TPIPE);
9513 lp->next = NULL;
9514 n1 = pipenode;
9515 }
9516 tokpushback++;
9517 if (negate) {
9518 n2 = (union node *)stalloc(sizeof (struct nnot));
9519 n2->type = NNOT;
9520 n2->nnot.com = n1;
9521 return n2;
9522 } else
9523 return n1;
9524}
9525
9526
9527
9528static union node *
9529command() {
9530 union node *n1, *n2;
9531 union node *ap, **app;
9532 union node *cp, **cpp;
9533 union node *redir, **rpp;
9534 int t;
9535
9536 redir = NULL;
9537 n1 = NULL;
9538 rpp = &redir;
9539
9540 switch (readtoken()) {
9541 case TIF:
9542 n1 = (union node *)stalloc(sizeof (struct nif));
9543 n1->type = NIF;
9544 n1->nif.test = list(0);
9545 if (readtoken() != TTHEN)
9546 synexpect(TTHEN);
9547 n1->nif.ifpart = list(0);
9548 n2 = n1;
9549 while (readtoken() == TELIF) {
9550 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9551 n2 = n2->nif.elsepart;
9552 n2->type = NIF;
9553 n2->nif.test = list(0);
9554 if (readtoken() != TTHEN)
9555 synexpect(TTHEN);
9556 n2->nif.ifpart = list(0);
9557 }
9558 if (lasttoken == TELSE)
9559 n2->nif.elsepart = list(0);
9560 else {
9561 n2->nif.elsepart = NULL;
9562 tokpushback++;
9563 }
9564 if (readtoken() != TFI)
9565 synexpect(TFI);
9566 checkkwd = 1;
9567 break;
9568 case TWHILE:
9569 case TUNTIL: {
9570 int got;
9571 n1 = (union node *)stalloc(sizeof (struct nbinary));
9572 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9573 n1->nbinary.ch1 = list(0);
9574 if ((got=readtoken()) != TDO) {
9575TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
9576 synexpect(TDO);
9577 }
9578 n1->nbinary.ch2 = list(0);
9579 if (readtoken() != TDONE)
9580 synexpect(TDONE);
9581 checkkwd = 1;
9582 break;
9583 }
9584 case TFOR:
9585 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9586 synerror("Bad for loop variable");
9587 n1 = (union node *)stalloc(sizeof (struct nfor));
9588 n1->type = NFOR;
9589 n1->nfor.var = wordtext;
9590 checkkwd = 1;
9591 if (readtoken() == TIN) {
9592 app = &ap;
9593 while (readtoken() == TWORD) {
9594 n2 = (union node *)stalloc(sizeof (struct narg));
9595 n2->type = NARG;
9596 n2->narg.text = wordtext;
9597 n2->narg.backquote = backquotelist;
9598 *app = n2;
9599 app = &n2->narg.next;
9600 }
9601 *app = NULL;
9602 n1->nfor.args = ap;
9603 if (lasttoken != TNL && lasttoken != TSEMI)
9604 synexpect(-1);
9605 } else {
9606 static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
9607 '@', '=', '\0'};
9608 n2 = (union node *)stalloc(sizeof (struct narg));
9609 n2->type = NARG;
9610 n2->narg.text = argvars;
9611 n2->narg.backquote = NULL;
9612 n2->narg.next = NULL;
9613 n1->nfor.args = n2;
9614 /*
9615 * Newline or semicolon here is optional (but note
9616 * that the original Bourne shell only allowed NL).
9617 */
9618 if (lasttoken != TNL && lasttoken != TSEMI)
9619 tokpushback++;
9620 }
9621 checkkwd = 2;
9622 if (readtoken() != TDO)
9623 synexpect(TDO);
9624 n1->nfor.body = list(0);
9625 if (readtoken() != TDONE)
9626 synexpect(TDONE);
9627 checkkwd = 1;
9628 break;
9629 case TCASE:
9630 n1 = (union node *)stalloc(sizeof (struct ncase));
9631 n1->type = NCASE;
9632 if (readtoken() != TWORD)
9633 synexpect(TWORD);
9634 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9635 n2->type = NARG;
9636 n2->narg.text = wordtext;
9637 n2->narg.backquote = backquotelist;
9638 n2->narg.next = NULL;
9639 do {
9640 checkkwd = 1;
9641 } while (readtoken() == TNL);
9642 if (lasttoken != TIN)
9643 synerror("expecting \"in\"");
9644 cpp = &n1->ncase.cases;
9645 checkkwd = 2, readtoken();
9646 do {
9647 if (lasttoken == TLP)
9648 readtoken();
9649 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9650 cp->type = NCLIST;
9651 app = &cp->nclist.pattern;
9652 for (;;) {
9653 *app = ap = (union node *)stalloc(sizeof (struct narg));
9654 ap->type = NARG;
9655 ap->narg.text = wordtext;
9656 ap->narg.backquote = backquotelist;
9657 if (checkkwd = 2, readtoken() != TPIPE)
9658 break;
9659 app = &ap->narg.next;
9660 readtoken();
9661 }
9662 ap->narg.next = NULL;
9663 if (lasttoken != TRP)
9664 synexpect(TRP);
9665 cp->nclist.body = list(0);
9666
9667 checkkwd = 2;
9668 if ((t = readtoken()) != TESAC) {
9669 if (t != TENDCASE)
9670 synexpect(TENDCASE);
9671 else
9672 checkkwd = 2, readtoken();
9673 }
9674 cpp = &cp->nclist.next;
9675 } while(lasttoken != TESAC);
9676 *cpp = NULL;
9677 checkkwd = 1;
9678 break;
9679 case TLP:
9680 n1 = (union node *)stalloc(sizeof (struct nredir));
9681 n1->type = NSUBSHELL;
9682 n1->nredir.n = list(0);
9683 n1->nredir.redirect = NULL;
9684 if (readtoken() != TRP)
9685 synexpect(TRP);
9686 checkkwd = 1;
9687 break;
9688 case TBEGIN:
9689 n1 = list(0);
9690 if (readtoken() != TEND)
9691 synexpect(TEND);
9692 checkkwd = 1;
9693 break;
9694 /* Handle an empty command like other simple commands. */
9695 case TSEMI:
9696 case TAND:
9697 case TOR:
9698 case TNL:
9699 case TEOF:
9700 case TRP:
9701 case TBACKGND:
9702 /*
9703 * An empty command before a ; doesn't make much sense, and
9704 * should certainly be disallowed in the case of `if ;'.
9705 */
9706 if (!redir)
9707 synexpect(-1);
9708 case TWORD:
9709 case TREDIR:
9710 tokpushback++;
9711 n1 = simplecmd();
9712 return n1;
9713 default:
9714 synexpect(-1);
9715 /* NOTREACHED */
9716 }
9717
9718 /* Now check for redirection which may follow command */
9719 while (readtoken() == TREDIR) {
9720 *rpp = n2 = redirnode;
9721 rpp = &n2->nfile.next;
9722 parsefname();
9723 }
9724 tokpushback++;
9725 *rpp = NULL;
9726 if (redir) {
9727 if (n1->type != NSUBSHELL) {
9728 n2 = (union node *)stalloc(sizeof (struct nredir));
9729 n2->type = NREDIR;
9730 n2->nredir.n = n1;
9731 n1 = n2;
9732 }
9733 n1->nredir.redirect = redir;
9734 }
9735
9736 return n1;
9737}
9738
9739
9740static union node *
9741simplecmd() {
9742 union node *args, **app;
9743 union node *n = NULL;
9744 union node *vars, **vpp;
9745 union node **rpp, *redir;
9746
9747 args = NULL;
9748 app = &args;
9749 vars = NULL;
9750 vpp = &vars;
9751 redir = NULL;
9752 rpp = &redir;
9753
9754 checkalias = 2;
9755 for (;;) {
9756 switch (readtoken()) {
9757 case TWORD:
9758 case TASSIGN:
9759 n = (union node *)stalloc(sizeof (struct narg));
9760 n->type = NARG;
9761 n->narg.text = wordtext;
9762 n->narg.backquote = backquotelist;
9763 if (lasttoken == TWORD) {
9764 *app = n;
9765 app = &n->narg.next;
9766 } else {
9767 *vpp = n;
9768 vpp = &n->narg.next;
9769 }
9770 break;
9771 case TREDIR:
9772 *rpp = n = redirnode;
9773 rpp = &n->nfile.next;
Eric Andersen2870d962001-07-02 17:27:21 +00009774 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +00009775 break;
9776 case TLP:
9777 if (
9778 args && app == &args->narg.next &&
9779 !vars && !redir
9780 ) {
9781 /* We have a function */
9782 if (readtoken() != TRP)
9783 synexpect(TRP);
Eric Andersencb57d552001-06-28 07:25:16 +00009784 n->type = NDEFUN;
9785 checkkwd = 2;
9786 n->narg.next = command();
9787 return n;
9788 }
9789 /* fall through */
9790 default:
9791 tokpushback++;
9792 goto out;
9793 }
9794 }
9795out:
9796 *app = NULL;
9797 *vpp = NULL;
9798 *rpp = NULL;
9799 n = (union node *)stalloc(sizeof (struct ncmd));
9800 n->type = NCMD;
9801 n->ncmd.backgnd = 0;
9802 n->ncmd.args = args;
9803 n->ncmd.assign = vars;
9804 n->ncmd.redirect = redir;
9805 return n;
9806}
9807
9808static union node *
Eric Andersen2870d962001-07-02 17:27:21 +00009809makename(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009810 union node *n;
9811
9812 n = (union node *)stalloc(sizeof (struct narg));
9813 n->type = NARG;
9814 n->narg.next = NULL;
9815 n->narg.text = wordtext;
9816 n->narg.backquote = backquotelist;
9817 return n;
9818}
9819
9820static void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +00009821{
Eric Andersencb57d552001-06-28 07:25:16 +00009822 TRACE(("Fix redir %s %d\n", text, err));
9823 if (!err)
9824 n->ndup.vname = NULL;
9825
9826 if (is_digit(text[0]) && text[1] == '\0')
9827 n->ndup.dupfd = digit_val(text[0]);
9828 else if (text[0] == '-' && text[1] == '\0')
9829 n->ndup.dupfd = -1;
9830 else {
9831
9832 if (err)
9833 synerror("Bad fd number");
9834 else
9835 n->ndup.vname = makename();
9836 }
9837}
9838
9839
9840static void
Eric Andersen2870d962001-07-02 17:27:21 +00009841parsefname(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009842 union node *n = redirnode;
9843
9844 if (readtoken() != TWORD)
9845 synexpect(-1);
9846 if (n->type == NHERE) {
9847 struct heredoc *here = heredoc;
9848 struct heredoc *p;
9849 int i;
9850
9851 if (quoteflag == 0)
9852 n->type = NXHERE;
9853 TRACE(("Here document %d\n", n->type));
9854 if (here->striptabs) {
9855 while (*wordtext == '\t')
9856 wordtext++;
9857 }
9858 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9859 synerror("Illegal eof marker for << redirection");
9860 rmescapes(wordtext);
9861 here->eofmark = wordtext;
9862 here->next = NULL;
9863 if (heredoclist == NULL)
9864 heredoclist = here;
9865 else {
9866 for (p = heredoclist ; p->next ; p = p->next);
9867 p->next = here;
9868 }
9869 } else if (n->type == NTOFD || n->type == NFROMFD) {
9870 fixredir(n, wordtext, 0);
9871 } else {
9872 n->nfile.fname = makename();
9873 }
9874}
9875
9876
9877/*
9878 * Input any here documents.
9879 */
9880
9881static void
9882parseheredoc() {
9883 struct heredoc *here;
9884 union node *n;
9885
9886 while (heredoclist) {
9887 here = heredoclist;
9888 heredoclist = here->next;
9889 if (needprompt) {
9890 setprompt(2);
9891 needprompt = 0;
9892 }
9893 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9894 here->eofmark, here->striptabs);
9895 n = (union node *)stalloc(sizeof (struct narg));
9896 n->narg.type = NARG;
9897 n->narg.next = NULL;
9898 n->narg.text = wordtext;
9899 n->narg.backquote = backquotelist;
9900 here->here->nhere.doc = n;
9901 }
9902}
9903
9904static int
9905peektoken() {
9906 int t;
9907
9908 t = readtoken();
9909 tokpushback++;
9910 return (t);
9911}
9912
9913static int
9914readtoken() {
9915 int t;
Eric Andersen7467c8d2001-07-12 20:26:32 +00009916
Eric Andersen2870d962001-07-02 17:27:21 +00009917#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00009918 int savecheckalias = checkalias;
Eric Andersen7467c8d2001-07-12 20:26:32 +00009919 int savecheckkwd = checkkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009920 struct alias *ap;
Eric Andersen2870d962001-07-02 17:27:21 +00009921#endif
9922
Eric Andersencb57d552001-06-28 07:25:16 +00009923#ifdef DEBUG
9924 int alreadyseen = tokpushback;
9925#endif
9926
Eric Andersen2870d962001-07-02 17:27:21 +00009927#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00009928top:
Eric Andersen2870d962001-07-02 17:27:21 +00009929#endif
9930
Eric Andersencb57d552001-06-28 07:25:16 +00009931 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +00009932
9933#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00009934 checkalias = savecheckalias;
Eric Andersen2870d962001-07-02 17:27:21 +00009935#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009936
9937 if (checkkwd) {
9938 /*
9939 * eat newlines
9940 */
9941 if (checkkwd == 2) {
9942 checkkwd = 0;
9943 while (t == TNL) {
9944 parseheredoc();
9945 t = xxreadtoken();
9946 }
9947 }
9948 checkkwd = 0;
9949 /*
9950 * check for keywords
9951 */
9952 if (t == TWORD && !quoteflag)
9953 {
9954 const char *const *pp;
9955
9956 if ((pp = findkwd(wordtext))) {
9957 lasttoken = t = pp - parsekwd + KWDOFFSET;
9958 TRACE(("keyword %s recognized\n", tokname[t]));
9959 goto out;
9960 }
9961 }
9962 }
9963
Eric Andersen7467c8d2001-07-12 20:26:32 +00009964
Eric Andersencb57d552001-06-28 07:25:16 +00009965 if (t != TWORD) {
9966 if (t != TREDIR) {
9967 checkalias = 0;
9968 }
9969 } else if (checkalias == 2 && isassignment(wordtext)) {
9970 lasttoken = t = TASSIGN;
Eric Andersen7467c8d2001-07-12 20:26:32 +00009971#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00009972 } else if (checkalias) {
9973 if (!quoteflag && (ap = lookupalias(wordtext, 1)) != NULL) {
9974 if (*ap->val) {
9975 pushstring(ap->val, strlen(ap->val), ap);
9976 }
9977 checkkwd = savecheckkwd;
9978 goto top;
9979 }
9980 checkalias = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00009981#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +00009982 }
Eric Andersencb57d552001-06-28 07:25:16 +00009983out:
9984#ifdef DEBUG
9985 if (!alreadyseen)
9986 TRACE(("token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : ""));
9987 else
9988 TRACE(("reread token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : ""));
9989#endif
9990 return (t);
9991}
9992
9993
9994/*
9995 * Read the next input token.
9996 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +00009997 * backquotes. We set quoteflag to true if any part of the word was
9998 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +00009999 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +000010000 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +000010001 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +000010002 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +000010003 *
10004 * [Change comment: here documents and internal procedures]
10005 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10006 * word parsing code into a separate routine. In this case, readtoken
10007 * doesn't need to have any internal procedures, but parseword does.
10008 * We could also make parseoperator in essence the main routine, and
10009 * have parseword (readtoken1?) handle both words and redirection.]
10010 */
10011
Eric Andersen2870d962001-07-02 17:27:21 +000010012#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010013
10014static int
10015xxreadtoken() {
10016 int c;
10017
10018 if (tokpushback) {
10019 tokpushback = 0;
10020 return lasttoken;
10021 }
10022 if (needprompt) {
10023 setprompt(2);
10024 needprompt = 0;
10025 }
10026 startlinno = plinno;
Eric Andersen2870d962001-07-02 17:27:21 +000010027 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010028 c = pgetc_macro();
10029 switch (c) {
10030 case ' ': case '\t':
Eric Andersen3102ac42001-07-06 04:26:23 +000010031#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010032 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010033#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010034 continue;
10035 case '#':
10036 while ((c = pgetc()) != '\n' && c != PEOF);
10037 pungetc();
10038 continue;
10039 case '\\':
10040 if (pgetc() == '\n') {
10041 startlinno = ++plinno;
10042 if (doprompt)
10043 setprompt(2);
10044 else
10045 setprompt(0);
10046 continue;
10047 }
10048 pungetc();
10049 goto breakloop;
10050 case '\n':
10051 plinno++;
10052 needprompt = doprompt;
10053 RETURN(TNL);
10054 case PEOF:
10055 RETURN(TEOF);
10056 case '&':
10057 if (pgetc() == '&')
10058 RETURN(TAND);
10059 pungetc();
10060 RETURN(TBACKGND);
10061 case '|':
10062 if (pgetc() == '|')
10063 RETURN(TOR);
10064 pungetc();
10065 RETURN(TPIPE);
10066 case ';':
10067 if (pgetc() == ';')
10068 RETURN(TENDCASE);
10069 pungetc();
10070 RETURN(TSEMI);
10071 case '(':
10072 RETURN(TLP);
10073 case ')':
10074 RETURN(TRP);
10075 default:
10076 goto breakloop;
10077 }
10078 }
10079breakloop:
10080 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10081#undef RETURN
10082}
10083
10084
10085
10086/*
10087 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10088 * is not NULL, read a here document. In the latter case, eofmark is the
10089 * word which marks the end of the document and striptabs is true if
10090 * leading tabs should be stripped from the document. The argument firstc
10091 * is the first character of the input token or document.
10092 *
10093 * Because C does not have internal subroutines, I have simulated them
10094 * using goto's to implement the subroutine linkage. The following macros
10095 * will run code that appears at the end of readtoken1.
10096 */
10097
Eric Andersen2870d962001-07-02 17:27:21 +000010098#define CHECKEND() {goto checkend; checkend_return:;}
10099#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10100#define PARSESUB() {goto parsesub; parsesub_return:;}
10101#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10102#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10103#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010104
10105static int
10106readtoken1(firstc, syntax, eofmark, striptabs)
10107 int firstc;
10108 char const *syntax;
10109 char *eofmark;
10110 int striptabs;
10111 {
10112 int c = firstc;
10113 char *out;
10114 int len;
10115 char line[EOFMARKLEN + 1];
10116 struct nodelist *bqlist;
10117 int quotef;
10118 int dblquote;
Eric Andersen2870d962001-07-02 17:27:21 +000010119 int varnest; /* levels of variables expansion */
10120 int arinest; /* levels of arithmetic expansion */
10121 int parenlevel; /* levels of parens in arithmetic */
10122 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +000010123 int oldstyle;
Eric Andersen2870d962001-07-02 17:27:21 +000010124 char const *prevsyntax; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010125#if __GNUC__
10126 /* Avoid longjmp clobbering */
10127 (void) &out;
10128 (void) &quotef;
10129 (void) &dblquote;
10130 (void) &varnest;
10131 (void) &arinest;
10132 (void) &parenlevel;
10133 (void) &dqvarnest;
10134 (void) &oldstyle;
10135 (void) &prevsyntax;
10136 (void) &syntax;
10137#endif
10138
10139 startlinno = plinno;
10140 dblquote = 0;
10141 if (syntax == DQSYNTAX)
10142 dblquote = 1;
10143 quotef = 0;
10144 bqlist = NULL;
10145 varnest = 0;
10146 arinest = 0;
10147 parenlevel = 0;
10148 dqvarnest = 0;
10149
10150 STARTSTACKSTR(out);
Eric Andersen2870d962001-07-02 17:27:21 +000010151 loop: { /* for each line, until end of word */
10152 CHECKEND(); /* set c to PEOF if at end of here document */
10153 for (;;) { /* until end of line or end of word */
10154 CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
Eric Andersencb57d552001-06-28 07:25:16 +000010155 switch(syntax[c]) {
Eric Andersen2870d962001-07-02 17:27:21 +000010156 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010157 if (syntax == BASESYNTAX)
Eric Andersen2870d962001-07-02 17:27:21 +000010158 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010159 USTPUTC(c, out);
10160 plinno++;
10161 if (doprompt)
10162 setprompt(2);
10163 else
10164 setprompt(0);
10165 c = pgetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010166 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010167 case CWORD:
10168 USTPUTC(c, out);
10169 break;
10170 case CCTL:
10171 if ((eofmark == NULL || dblquote) &&
10172 dqvarnest == 0)
10173 USTPUTC(CTLESC, out);
10174 USTPUTC(c, out);
10175 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010176 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010177 c = pgetc2();
10178 if (c == PEOF) {
10179 USTPUTC('\\', out);
10180 pungetc();
10181 } else if (c == '\n') {
10182 if (doprompt)
10183 setprompt(2);
10184 else
10185 setprompt(0);
10186 } else {
10187 if (dblquote && c != '\\' && c != '`' && c != '$'
10188 && (c != '"' || eofmark != NULL))
10189 USTPUTC('\\', out);
10190 if (SQSYNTAX[c] == CCTL)
10191 USTPUTC(CTLESC, out);
10192 else if (eofmark == NULL)
10193 USTPUTC(CTLQUOTEMARK, out);
10194 USTPUTC(c, out);
10195 quotef++;
10196 }
10197 break;
10198 case CSQUOTE:
10199 if (eofmark == NULL)
10200 USTPUTC(CTLQUOTEMARK, out);
10201 syntax = SQSYNTAX;
10202 break;
10203 case CDQUOTE:
10204 if (eofmark == NULL)
10205 USTPUTC(CTLQUOTEMARK, out);
10206 syntax = DQSYNTAX;
10207 dblquote = 1;
10208 break;
10209 case CENDQUOTE:
10210 if (eofmark != NULL && arinest == 0 &&
10211 varnest == 0) {
10212 USTPUTC(c, out);
10213 } else {
10214 if (arinest) {
10215 syntax = ARISYNTAX;
10216 dblquote = 0;
10217 } else if (eofmark == NULL &&
10218 dqvarnest == 0) {
10219 syntax = BASESYNTAX;
10220 dblquote = 0;
10221 }
10222 quotef++;
10223 }
10224 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010225 case CVAR: /* '$' */
10226 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010227 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010228 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010229 if (varnest > 0) {
10230 varnest--;
10231 if (dqvarnest > 0) {
10232 dqvarnest--;
10233 }
10234 USTPUTC(CTLENDVAR, out);
10235 } else {
10236 USTPUTC(c, out);
10237 }
10238 break;
10239#ifdef ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +000010240 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010241 parenlevel++;
10242 USTPUTC(c, out);
10243 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010244 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010245 if (parenlevel > 0) {
10246 USTPUTC(c, out);
10247 --parenlevel;
10248 } else {
10249 if (pgetc() == ')') {
10250 if (--arinest == 0) {
10251 USTPUTC(CTLENDARI, out);
10252 syntax = prevsyntax;
10253 if (syntax == DQSYNTAX)
10254 dblquote = 1;
10255 else
10256 dblquote = 0;
10257 } else
10258 USTPUTC(')', out);
10259 } else {
10260 /*
10261 * unbalanced parens
10262 * (don't 2nd guess - no error)
10263 */
10264 pungetc();
10265 USTPUTC(')', out);
10266 }
10267 }
10268 break;
10269#endif
Eric Andersen2870d962001-07-02 17:27:21 +000010270 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010271 PARSEBACKQOLD();
10272 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010273 case CENDFILE:
10274 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010275 case CIGN:
10276 break;
10277 default:
10278 if (varnest == 0)
Eric Andersen2870d962001-07-02 17:27:21 +000010279 goto endword; /* exit outer loop */
Eric Andersen3102ac42001-07-06 04:26:23 +000010280#ifdef ASH_ALIAS
10281 if (c != PEOA)
10282#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010283 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010284
Eric Andersencb57d552001-06-28 07:25:16 +000010285 }
10286 c = pgetc_macro();
10287 }
10288 }
10289endword:
10290 if (syntax == ARISYNTAX)
10291 synerror("Missing '))'");
10292 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10293 synerror("Unterminated quoted string");
10294 if (varnest != 0) {
10295 startlinno = plinno;
10296 synerror("Missing '}'");
10297 }
10298 USTPUTC('\0', out);
10299 len = out - stackblock();
10300 out = stackblock();
10301 if (eofmark == NULL) {
10302 if ((c == '>' || c == '<')
10303 && quotef == 0
10304 && len <= 2
10305 && (*out == '\0' || is_digit(*out))) {
10306 PARSEREDIR();
10307 return lasttoken = TREDIR;
10308 } else {
10309 pungetc();
10310 }
10311 }
10312 quoteflag = quotef;
10313 backquotelist = bqlist;
10314 grabstackblock(len);
10315 wordtext = out;
10316 return lasttoken = TWORD;
10317/* end of readtoken routine */
10318
10319
10320
10321/*
10322 * Check to see whether we are at the end of the here document. When this
10323 * is called, c is set to the first character of the next input line. If
10324 * we are at the end of the here document, this routine sets the c to PEOF.
10325 */
10326
10327checkend: {
10328 if (eofmark) {
Eric Andersen2870d962001-07-02 17:27:21 +000010329#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010330 if (c == PEOA) {
10331 c = pgetc2();
10332 }
Eric Andersen2870d962001-07-02 17:27:21 +000010333#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010334 if (striptabs) {
10335 while (c == '\t') {
10336 c = pgetc2();
10337 }
10338 }
10339 if (c == *eofmark) {
10340 if (pfgets(line, sizeof line) != NULL) {
10341 char *p, *q;
10342
10343 p = line;
10344 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10345 if (*p == '\n' && *q == '\0') {
10346 c = PEOF;
10347 plinno++;
10348 needprompt = doprompt;
10349 } else {
10350 pushstring(line, strlen(line), NULL);
10351 }
10352 }
10353 }
10354 }
10355 goto checkend_return;
10356}
10357
10358
10359/*
10360 * Parse a redirection operator. The variable "out" points to a string
10361 * specifying the fd to be redirected. The variable "c" contains the
10362 * first character of the redirection operator.
10363 */
10364
10365parseredir: {
10366 char fd = *out;
10367 union node *np;
10368
10369 np = (union node *)stalloc(sizeof (struct nfile));
10370 if (c == '>') {
10371 np->nfile.fd = 1;
10372 c = pgetc();
10373 if (c == '>')
10374 np->type = NAPPEND;
10375 else if (c == '&')
10376 np->type = NTOFD;
10377 else if (c == '|')
10378 np->type = NTOOV;
10379 else {
10380 np->type = NTO;
10381 pungetc();
10382 }
Eric Andersen2870d962001-07-02 17:27:21 +000010383 } else { /* c == '<' */
Eric Andersencb57d552001-06-28 07:25:16 +000010384 np->nfile.fd = 0;
10385 switch (c = pgetc()) {
10386 case '<':
10387 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10388 np = (union node *)stalloc(sizeof (struct nhere));
10389 np->nfile.fd = 0;
10390 }
10391 np->type = NHERE;
10392 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10393 heredoc->here = np;
10394 if ((c = pgetc()) == '-') {
10395 heredoc->striptabs = 1;
10396 } else {
10397 heredoc->striptabs = 0;
10398 pungetc();
10399 }
10400 break;
10401
10402 case '&':
10403 np->type = NFROMFD;
10404 break;
10405
10406 case '>':
10407 np->type = NFROMTO;
10408 break;
10409
10410 default:
10411 np->type = NFROM;
10412 pungetc();
10413 break;
10414 }
10415 }
10416 if (fd != '\0')
10417 np->nfile.fd = digit_val(fd);
10418 redirnode = np;
10419 goto parseredir_return;
10420}
10421
10422
10423/*
10424 * Parse a substitution. At this point, we have read the dollar sign
10425 * and nothing else.
10426 */
10427
10428parsesub: {
10429 int subtype;
10430 int typeloc;
10431 int flags;
10432 char *p;
10433 static const char types[] = "}-+?=";
10434
10435 c = pgetc();
10436 if (
10437 c <= PEOA ||
10438 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10439 ) {
10440 USTPUTC('$', out);
10441 pungetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010442 } else if (c == '(') { /* $(command) or $((arith)) */
Eric Andersencb57d552001-06-28 07:25:16 +000010443 if (pgetc() == '(') {
10444 PARSEARITH();
10445 } else {
10446 pungetc();
10447 PARSEBACKQNEW();
10448 }
10449 } else {
10450 USTPUTC(CTLVAR, out);
10451 typeloc = out - stackblock();
10452 USTPUTC(VSNORMAL, out);
10453 subtype = VSNORMAL;
10454 if (c == '{') {
10455 c = pgetc();
10456 if (c == '#') {
10457 if ((c = pgetc()) == '}')
10458 c = '#';
10459 else
10460 subtype = VSLENGTH;
10461 }
10462 else
10463 subtype = 0;
10464 }
10465 if (c > PEOA && is_name(c)) {
10466 do {
10467 STPUTC(c, out);
10468 c = pgetc();
10469 } while (c > PEOA && is_in_name(c));
10470 } else if (is_digit(c)) {
10471 do {
10472 USTPUTC(c, out);
10473 c = pgetc();
10474 } while (is_digit(c));
10475 }
10476 else if (is_special(c)) {
10477 USTPUTC(c, out);
10478 c = pgetc();
10479 }
10480 else
Eric Andersen2870d962001-07-02 17:27:21 +000010481badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010482
10483 STPUTC('=', out);
10484 flags = 0;
10485 if (subtype == 0) {
10486 switch (c) {
10487 case ':':
10488 flags = VSNUL;
10489 c = pgetc();
10490 /*FALLTHROUGH*/
10491 default:
10492 p = strchr(types, c);
10493 if (p == NULL)
10494 goto badsub;
10495 subtype = p - types + VSNORMAL;
10496 break;
10497 case '%':
10498 case '#':
10499 {
10500 int cc = c;
10501 subtype = c == '#' ? VSTRIMLEFT :
10502 VSTRIMRIGHT;
10503 c = pgetc();
10504 if (c == cc)
10505 subtype++;
10506 else
10507 pungetc();
10508 break;
10509 }
10510 }
10511 } else {
10512 pungetc();
10513 }
10514 if (dblquote || arinest)
10515 flags |= VSQUOTE;
10516 *(stackblock() + typeloc) = subtype | flags;
10517 if (subtype != VSNORMAL) {
10518 varnest++;
10519 if (dblquote) {
10520 dqvarnest++;
10521 }
10522 }
10523 }
10524 goto parsesub_return;
10525}
10526
10527
10528/*
10529 * Called to parse command substitutions. Newstyle is set if the command
10530 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10531 * list of commands (passed by reference), and savelen is the number of
10532 * characters on the top of the stack which must be preserved.
10533 */
10534
10535parsebackq: {
10536 struct nodelist **nlpp;
10537 int savepbq;
10538 union node *n;
10539 char *volatile str;
10540 struct jmploc jmploc;
10541 struct jmploc *volatile savehandler;
10542 int savelen;
10543 int saveprompt;
10544#ifdef __GNUC__
10545 (void) &saveprompt;
10546#endif
10547
10548 savepbq = parsebackquote;
10549 if (setjmp(jmploc.loc)) {
10550 if (str)
10551 ckfree(str);
10552 parsebackquote = 0;
10553 handler = savehandler;
10554 longjmp(handler->loc, 1);
10555 }
10556 INTOFF;
10557 str = NULL;
10558 savelen = out - stackblock();
10559 if (savelen > 0) {
10560 str = ckmalloc(savelen);
10561 memcpy(str, stackblock(), savelen);
10562 }
10563 savehandler = handler;
10564 handler = &jmploc;
10565 INTON;
Eric Andersen2870d962001-07-02 17:27:21 +000010566 if (oldstyle) {
10567 /* We must read until the closing backquote, giving special
10568 treatment to some slashes, and then push the string and
10569 reread it as input, interpreting it normally. */
10570 char *pout;
10571 int pc;
10572 int psavelen;
10573 char *pstr;
Eric Andersencb57d552001-06-28 07:25:16 +000010574
10575
Eric Andersen2870d962001-07-02 17:27:21 +000010576 STARTSTACKSTR(pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010577 for (;;) {
10578 if (needprompt) {
10579 setprompt(2);
10580 needprompt = 0;
10581 }
10582 switch (pc = pgetc()) {
10583 case '`':
10584 goto done;
10585
10586 case '\\':
Eric Andersen2870d962001-07-02 17:27:21 +000010587 if ((pc = pgetc()) == '\n') {
Eric Andersencb57d552001-06-28 07:25:16 +000010588 plinno++;
10589 if (doprompt)
10590 setprompt(2);
10591 else
10592 setprompt(0);
10593 /*
10594 * If eating a newline, avoid putting
10595 * the newline into the new character
10596 * stream (via the STPUTC after the
10597 * switch).
10598 */
10599 continue;
10600 }
Eric Andersen2870d962001-07-02 17:27:21 +000010601 if (pc != '\\' && pc != '`' && pc != '$'
10602 && (!dblquote || pc != '"'))
10603 STPUTC('\\', pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010604 if (pc > PEOA) {
10605 break;
10606 }
10607 /* fall through */
10608
10609 case PEOF:
Eric Andersen2870d962001-07-02 17:27:21 +000010610#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010611 case PEOA:
Eric Andersen2870d962001-07-02 17:27:21 +000010612#endif
10613 startlinno = plinno;
Eric Andersencb57d552001-06-28 07:25:16 +000010614 synerror("EOF in backquote substitution");
10615
10616 case '\n':
10617 plinno++;
10618 needprompt = doprompt;
10619 break;
10620
10621 default:
10622 break;
10623 }
10624 STPUTC(pc, pout);
Eric Andersen2870d962001-07-02 17:27:21 +000010625 }
Eric Andersencb57d552001-06-28 07:25:16 +000010626done:
Eric Andersen2870d962001-07-02 17:27:21 +000010627 STPUTC('\0', pout);
10628 psavelen = pout - stackblock();
10629 if (psavelen > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010630 pstr = grabstackstr(pout);
10631 setinputstring(pstr);
Eric Andersen2870d962001-07-02 17:27:21 +000010632 }
10633 }
Eric Andersencb57d552001-06-28 07:25:16 +000010634 nlpp = &bqlist;
10635 while (*nlpp)
10636 nlpp = &(*nlpp)->next;
10637 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10638 (*nlpp)->next = NULL;
10639 parsebackquote = oldstyle;
10640
10641 if (oldstyle) {
10642 saveprompt = doprompt;
10643 doprompt = 0;
10644 }
10645
10646 n = list(0);
10647
10648 if (oldstyle)
10649 doprompt = saveprompt;
10650 else {
10651 if (readtoken() != TRP)
10652 synexpect(TRP);
10653 }
10654
10655 (*nlpp)->n = n;
Eric Andersen2870d962001-07-02 17:27:21 +000010656 if (oldstyle) {
Eric Andersencb57d552001-06-28 07:25:16 +000010657 /*
10658 * Start reading from old file again, ignoring any pushed back
10659 * tokens left from the backquote parsing
10660 */
Eric Andersen2870d962001-07-02 17:27:21 +000010661 popfile();
Eric Andersencb57d552001-06-28 07:25:16 +000010662 tokpushback = 0;
10663 }
10664 while (stackblocksize() <= savelen)
10665 growstackblock();
10666 STARTSTACKSTR(out);
10667 if (str) {
10668 memcpy(out, str, savelen);
10669 STADJUST(savelen, out);
10670 INTOFF;
10671 ckfree(str);
10672 str = NULL;
10673 INTON;
10674 }
10675 parsebackquote = savepbq;
10676 handler = savehandler;
10677 if (arinest || dblquote)
10678 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10679 else
10680 USTPUTC(CTLBACKQ, out);
10681 if (oldstyle)
10682 goto parsebackq_oldreturn;
10683 else
10684 goto parsebackq_newreturn;
10685}
10686
10687/*
10688 * Parse an arithmetic expansion (indicate start of one and set state)
10689 */
10690parsearith: {
10691
10692 if (++arinest == 1) {
10693 prevsyntax = syntax;
10694 syntax = ARISYNTAX;
10695 USTPUTC(CTLARI, out);
10696 if (dblquote)
10697 USTPUTC('"',out);
10698 else
10699 USTPUTC(' ',out);
10700 } else {
10701 /*
10702 * we collapse embedded arithmetic expansion to
10703 * parenthesis, which should be equivalent
10704 */
10705 USTPUTC('(', out);
10706 }
10707 goto parsearith_return;
10708}
10709
10710} /* end of readtoken */
10711
10712
Eric Andersencb57d552001-06-28 07:25:16 +000010713/*
10714 * Returns true if the text contains nothing to expand (no dollar signs
10715 * or backquotes).
10716 */
10717
10718static int
10719noexpand(text)
10720 char *text;
10721 {
10722 char *p;
10723 char c;
10724
10725 p = text;
10726 while ((c = *p++) != '\0') {
10727 if (c == CTLQUOTEMARK)
10728 continue;
10729 if (c == CTLESC)
10730 p++;
10731 else if (BASESYNTAX[(int)c] == CCTL)
10732 return 0;
10733 }
10734 return 1;
10735}
10736
10737
10738/*
10739 * Return true if the argument is a legal variable name (a letter or
10740 * underscore followed by zero or more letters, underscores, and digits).
10741 */
10742
10743static int
Eric Andersen2870d962001-07-02 17:27:21 +000010744goodname(const char *name)
10745{
10746 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000010747
10748 p = name;
10749 if (! is_name(*p))
10750 return 0;
10751 while (*++p) {
10752 if (! is_in_name(*p))
10753 return 0;
10754 }
10755 return 1;
10756}
10757
10758
10759/*
10760 * Called when an unexpected token is read during the parse. The argument
10761 * is the token that is expected, or -1 if more than one type of token can
10762 * occur at this point.
10763 */
10764
10765static void
10766synexpect(token)
10767 int token;
10768{
10769 char msg[64];
10770
10771 if (token >= 0) {
Eric Andersen3102ac42001-07-06 04:26:23 +000010772 snprintf(msg, 64, "%s unexpected (expecting %s)",
Eric Andersencb57d552001-06-28 07:25:16 +000010773 tokname[lasttoken], tokname[token]);
10774 } else {
Eric Andersen3102ac42001-07-06 04:26:23 +000010775 snprintf(msg, 64, "%s unexpected", tokname[lasttoken]);
Eric Andersencb57d552001-06-28 07:25:16 +000010776 }
10777 synerror(msg);
10778 /* NOTREACHED */
10779}
10780
10781
10782static void
Eric Andersen2870d962001-07-02 17:27:21 +000010783synerror(const char *msg)
10784{
Eric Andersencb57d552001-06-28 07:25:16 +000010785 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +000010786 out2fmt("%s: %d: ", commandname, startlinno);
10787 out2fmt("Syntax error: %s\n", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000010788 error((char *)NULL);
10789 /* NOTREACHED */
10790}
10791
Eric Andersencb57d552001-06-28 07:25:16 +000010792
10793/*
10794 * called by editline -- any expansions to the prompt
10795 * should be added here.
10796 */
Eric Andersen2870d962001-07-02 17:27:21 +000010797static void
Eric Andersen62483552001-07-10 06:09:16 +000010798setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000010799{
Eric Andersen62483552001-07-10 06:09:16 +000010800 char *prompt;
10801 switch (whichprompt) {
10802 case 1:
10803 prompt = ps1val();
10804 break;
10805 case 2:
10806 prompt = ps2val();
10807 break;
10808 default: /* 0 */
10809 prompt = "";
10810 }
10811 putprompt(prompt);
Eric Andersencb57d552001-06-28 07:25:16 +000010812}
10813
Eric Andersencb57d552001-06-28 07:25:16 +000010814
Eric Andersencb57d552001-06-28 07:25:16 +000010815/*
10816 * Code for dealing with input/output redirection.
10817 */
10818
Eric Andersen2870d962001-07-02 17:27:21 +000010819#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000010820#ifndef PIPE_BUF
Eric Andersen2870d962001-07-02 17:27:21 +000010821# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000010822#else
10823# define PIPESIZE PIPE_BUF
10824#endif
10825
10826
Eric Andersen62483552001-07-10 06:09:16 +000010827/*
10828 * Open a file in noclobber mode.
10829 * The code was copied from bash.
10830 */
10831static inline int
10832noclobberopen(const char *fname)
10833{
10834 int r, fd;
10835 struct stat finfo, finfo2;
10836
10837 /*
10838 * If the file exists and is a regular file, return an error
10839 * immediately.
10840 */
10841 r = stat(fname, &finfo);
10842 if (r == 0 && S_ISREG(finfo.st_mode)) {
10843 errno = EEXIST;
10844 return -1;
10845 }
10846
10847 /*
10848 * If the file was not present (r != 0), make sure we open it
10849 * exclusively so that if it is created before we open it, our open
10850 * will fail. Make sure that we do not truncate an existing file.
10851 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10852 * file was not a regular file, we leave O_EXCL off.
10853 */
10854 if (r != 0)
10855 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10856 fd = open(fname, O_WRONLY|O_CREAT, 0666);
10857
10858 /* If the open failed, return the file descriptor right away. */
10859 if (fd < 0)
10860 return fd;
10861
10862 /*
10863 * OK, the open succeeded, but the file may have been changed from a
10864 * non-regular file to a regular file between the stat and the open.
10865 * We are assuming that the O_EXCL open handles the case where FILENAME
10866 * did not exist and is symlinked to an existing file between the stat
10867 * and open.
10868 */
10869
10870 /*
10871 * If we can open it and fstat the file descriptor, and neither check
10872 * revealed that it was a regular file, and the file has not been
10873 * replaced, return the file descriptor.
10874 */
10875 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10876 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
10877 return fd;
10878
10879 /* The file has been replaced. badness. */
10880 close(fd);
10881 errno = EEXIST;
10882 return -1;
10883}
Eric Andersencb57d552001-06-28 07:25:16 +000010884
10885/*
Eric Andersen62483552001-07-10 06:09:16 +000010886 * Handle here documents. Normally we fork off a process to write the
10887 * data to a pipe. If the document is short, we can stuff the data in
10888 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000010889 */
10890
Eric Andersen62483552001-07-10 06:09:16 +000010891static inline int
10892openhere(const union node *redir)
10893{
10894 int pip[2];
10895 int len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010896
Eric Andersen62483552001-07-10 06:09:16 +000010897 if (pipe(pip) < 0)
10898 error("Pipe call failed");
10899 if (redir->type == NHERE) {
10900 len = strlen(redir->nhere.doc->narg.text);
10901 if (len <= PIPESIZE) {
10902 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10903 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010904 }
Eric Andersencb57d552001-06-28 07:25:16 +000010905 }
Eric Andersen62483552001-07-10 06:09:16 +000010906 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
10907 close(pip[0]);
10908 signal(SIGINT, SIG_IGN);
10909 signal(SIGQUIT, SIG_IGN);
10910 signal(SIGHUP, SIG_IGN);
10911#ifdef SIGTSTP
10912 signal(SIGTSTP, SIG_IGN);
10913#endif
10914 signal(SIGPIPE, SIG_DFL);
10915 if (redir->type == NHERE)
10916 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10917 else
10918 expandhere(redir->nhere.doc, pip[1]);
10919 _exit(0);
10920 }
10921out:
10922 close(pip[1]);
10923 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000010924}
10925
10926
Eric Andersen62483552001-07-10 06:09:16 +000010927static inline int
10928openredirect(const union node *redir)
10929{
Eric Andersencb57d552001-06-28 07:25:16 +000010930 char *fname;
10931 int f;
10932
10933 switch (redir->nfile.type) {
10934 case NFROM:
10935 fname = redir->nfile.expfname;
10936 if ((f = open(fname, O_RDONLY)) < 0)
10937 goto eopen;
10938 break;
10939 case NFROMTO:
10940 fname = redir->nfile.expfname;
10941 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
10942 goto ecreate;
10943 break;
10944 case NTO:
10945 /* Take care of noclobber mode. */
10946 if (Cflag) {
10947 fname = redir->nfile.expfname;
10948 if ((f = noclobberopen(fname)) < 0)
10949 goto ecreate;
10950 break;
10951 }
10952 case NTOOV:
10953 fname = redir->nfile.expfname;
10954#ifdef O_CREAT
10955 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
10956 goto ecreate;
10957#else
10958 if ((f = creat(fname, 0666)) < 0)
10959 goto ecreate;
10960#endif
10961 break;
10962 case NAPPEND:
10963 fname = redir->nfile.expfname;
10964#ifdef O_APPEND
10965 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
10966 goto ecreate;
10967#else
10968 if ((f = open(fname, O_WRONLY)) < 0
10969 && (f = creat(fname, 0666)) < 0)
10970 goto ecreate;
10971 lseek(f, (off_t)0, 2);
10972#endif
10973 break;
10974 default:
10975#ifdef DEBUG
10976 abort();
10977#endif
10978 /* Fall through to eliminate warning. */
10979 case NTOFD:
10980 case NFROMFD:
10981 f = -1;
10982 break;
10983 case NHERE:
10984 case NXHERE:
10985 f = openhere(redir);
10986 break;
10987 }
10988
10989 return f;
10990ecreate:
10991 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
10992eopen:
10993 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
10994}
10995
10996
Eric Andersen62483552001-07-10 06:09:16 +000010997/*
10998 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
10999 * old file descriptors are stashed away so that the redirection can be
11000 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11001 * standard output, and the standard error if it becomes a duplicate of
11002 * stdout.
11003 */
11004
Eric Andersencb57d552001-06-28 07:25:16 +000011005static void
Eric Andersen62483552001-07-10 06:09:16 +000011006redirect(union node *redir, int flags)
11007{
11008 union node *n;
11009 struct redirtab *sv = NULL;
11010 int i;
11011 int fd;
11012 int newfd;
11013 int try;
11014 int fd1dup = flags & REDIR_BACKQ;; /* stdout `cmd` redir to pipe */
11015
11016 if (flags & REDIR_PUSH) {
11017 sv = ckmalloc(sizeof (struct redirtab));
11018 for (i = 0 ; i < 10 ; i++)
11019 sv->renamed[i] = EMPTY;
11020 sv->next = redirlist;
11021 redirlist = sv;
11022 }
11023 for (n = redir ; n ; n = n->nfile.next) {
11024 fd = n->nfile.fd;
11025 try = 0;
11026 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11027 n->ndup.dupfd == fd)
11028 continue; /* redirect from/to same file descriptor */
11029
11030 INTOFF;
11031 newfd = openredirect(n);
11032 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
11033 if (newfd == fd) {
11034 try++;
11035 } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
11036 switch (errno) {
11037 case EBADF:
11038 if (!try) {
11039 dupredirect(n, newfd, fd1dup);
11040 try++;
11041 break;
11042 }
11043 /* FALLTHROUGH*/
11044 default:
11045 if (newfd >= 0) {
11046 close(newfd);
11047 }
11048 INTON;
11049 error("%d: %m", fd);
11050 /* NOTREACHED */
11051 }
11052 }
11053 if (!try) {
11054 close(fd);
11055 if (flags & REDIR_PUSH) {
11056 sv->renamed[fd] = i;
11057 }
11058 }
11059 } else if (fd != newfd) {
11060 close(fd);
11061 }
11062 if (fd == 0)
11063 fd0_redirected++;
11064 if (!try)
11065 dupredirect(n, newfd, fd1dup);
11066 INTON;
11067 }
11068}
11069
11070
11071static void
11072dupredirect(const union node *redir, int f, int fd1dup)
Eric Andersen2870d962001-07-02 17:27:21 +000011073{
Eric Andersencb57d552001-06-28 07:25:16 +000011074 int fd = redir->nfile.fd;
11075
Eric Andersen62483552001-07-10 06:09:16 +000011076 if(fd==1)
11077 fd1dup = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011078 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Eric Andersen2870d962001-07-02 17:27:21 +000011079 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
Eric Andersen62483552001-07-10 06:09:16 +000011080 if (redir->ndup.dupfd!=1 || fd1dup!=1)
Eric Andersencb57d552001-06-28 07:25:16 +000011081 dup_as_newfd(redir->ndup.dupfd, fd);
11082 }
11083 return;
11084 }
11085
11086 if (f != fd) {
11087 dup_as_newfd(f, fd);
11088 close(f);
11089 }
11090 return;
11091}
11092
11093
Eric Andersencb57d552001-06-28 07:25:16 +000011094
Eric Andersencb57d552001-06-28 07:25:16 +000011095/*
11096 * Undo the effects of the last redirection.
11097 */
11098
11099static void
Eric Andersen2870d962001-07-02 17:27:21 +000011100popredir(void)
11101{
Eric Andersencb57d552001-06-28 07:25:16 +000011102 struct redirtab *rp = redirlist;
11103 int i;
11104
11105 INTOFF;
11106 for (i = 0 ; i < 10 ; i++) {
11107 if (rp->renamed[i] != EMPTY) {
Eric Andersen2870d962001-07-02 17:27:21 +000011108 if (i == 0)
11109 fd0_redirected--;
Eric Andersencb57d552001-06-28 07:25:16 +000011110 close(i);
11111 if (rp->renamed[i] >= 0) {
11112 dup_as_newfd(rp->renamed[i], i);
11113 close(rp->renamed[i]);
11114 }
Eric Andersencb57d552001-06-28 07:25:16 +000011115 }
11116 }
11117 redirlist = rp->next;
11118 ckfree(rp);
11119 INTON;
11120}
11121
11122/*
Eric Andersencb57d552001-06-28 07:25:16 +000011123 * Discard all saved file descriptors.
11124 */
11125
11126static void
Eric Andersen2870d962001-07-02 17:27:21 +000011127clearredir(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000011128 struct redirtab *rp;
11129 int i;
11130
11131 for (rp = redirlist ; rp ; rp = rp->next) {
11132 for (i = 0 ; i < 10 ; i++) {
11133 if (rp->renamed[i] >= 0) {
11134 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011135 }
11136 rp->renamed[i] = EMPTY;
11137 }
11138 }
Eric Andersencb57d552001-06-28 07:25:16 +000011139}
11140
11141
Eric Andersencb57d552001-06-28 07:25:16 +000011142/*
11143 * Copy a file descriptor to be >= to. Returns -1
11144 * if the source file descriptor is closed, EMPTY if there are no unused
11145 * file descriptors left.
11146 */
11147
11148static int
11149dup_as_newfd(from, to)
11150 int from;
11151 int to;
11152{
11153 int newfd;
11154
11155 newfd = fcntl(from, F_DUPFD, to);
11156 if (newfd < 0) {
11157 if (errno == EMFILE)
11158 return EMPTY;
11159 else
Eric Andersen2870d962001-07-02 17:27:21 +000011160 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011161 }
11162 return newfd;
11163}
11164
Eric Andersen2870d962001-07-02 17:27:21 +000011165/*#ifdef __weak_alias
Eric Andersencb57d552001-06-28 07:25:16 +000011166__weak_alias(getmode,_getmode)
11167__weak_alias(setmode,_setmode)
Eric Andersen2870d962001-07-02 17:27:21 +000011168#endif*/
Eric Andersencb57d552001-06-28 07:25:16 +000011169
Eric Andersen62483552001-07-10 06:09:16 +000011170#ifndef S_ISTXT
11171#if defined(__GLIBC__) && __GLIBC__ >= 2
Eric Andersencb57d552001-06-28 07:25:16 +000011172#define S_ISTXT __S_ISVTX
Eric Andersen62483552001-07-10 06:09:16 +000011173#else
11174#define S_ISTXT S_ISVTX
11175#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011176#endif
11177
Eric Andersen2870d962001-07-02 17:27:21 +000011178#define SET_LEN 6 /* initial # of bitcmd struct to malloc */
11179#define SET_LEN_INCR 4 /* # of bitcmd structs to add as needed */
Eric Andersencb57d552001-06-28 07:25:16 +000011180
11181typedef struct bitcmd {
Eric Andersen2870d962001-07-02 17:27:21 +000011182 char cmd;
11183 char cmd2;
11184 mode_t bits;
Eric Andersencb57d552001-06-28 07:25:16 +000011185} BITCMD;
11186
Eric Andersen2870d962001-07-02 17:27:21 +000011187#define CMD2_CLR 0x01
11188#define CMD2_SET 0x02
11189#define CMD2_GBITS 0x04
11190#define CMD2_OBITS 0x08
11191#define CMD2_UBITS 0x10
Eric Andersencb57d552001-06-28 07:25:16 +000011192
Eric Andersen2870d962001-07-02 17:27:21 +000011193static BITCMD *addcmd (BITCMD *, int, int, int, u_int);
11194static void compress_mode (BITCMD *);
Eric Andersencb57d552001-06-28 07:25:16 +000011195#ifdef SETMODE_DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +000011196static void dumpmode (BITCMD *);
Eric Andersencb57d552001-06-28 07:25:16 +000011197#endif
11198
11199/*
11200 * Given the old mode and an array of bitcmd structures, apply the operations
11201 * described in the bitcmd structures to the old mode, and return the new mode.
11202 * Note that there is no '=' command; a strict assignment is just a '-' (clear
11203 * bits) followed by a '+' (set bits).
11204 */
Eric Andersen2870d962001-07-02 17:27:21 +000011205static mode_t
Eric Andersencb57d552001-06-28 07:25:16 +000011206getmode(bbox, omode)
11207 const void *bbox;
11208 mode_t omode;
11209{
11210 const BITCMD *set;
11211 mode_t clrval, newmode, value;
11212
11213 _DIAGASSERT(bbox != NULL);
11214
11215 set = (const BITCMD *)bbox;
11216 newmode = omode;
11217 for (value = 0;; set++)
11218 switch(set->cmd) {
11219 /*
11220 * When copying the user, group or other bits around, we "know"
11221 * where the bits are in the mode so that we can do shifts to
11222 * copy them around. If we don't use shifts, it gets real
11223 * grundgy with lots of single bit checks and bit sets.
11224 */
11225 case 'u':
11226 value = (newmode & S_IRWXU) >> 6;
11227 goto common;
11228
11229 case 'g':
11230 value = (newmode & S_IRWXG) >> 3;
11231 goto common;
11232
11233 case 'o':
11234 value = newmode & S_IRWXO;
Eric Andersen2870d962001-07-02 17:27:21 +000011235common: if (set->cmd2 & CMD2_CLR) {
Eric Andersencb57d552001-06-28 07:25:16 +000011236 clrval =
11237 (set->cmd2 & CMD2_SET) ? S_IRWXO : value;
11238 if (set->cmd2 & CMD2_UBITS)
11239 newmode &= ~((clrval<<6) & set->bits);
11240 if (set->cmd2 & CMD2_GBITS)
11241 newmode &= ~((clrval<<3) & set->bits);
11242 if (set->cmd2 & CMD2_OBITS)
11243 newmode &= ~(clrval & set->bits);
11244 }
11245 if (set->cmd2 & CMD2_SET) {
11246 if (set->cmd2 & CMD2_UBITS)
11247 newmode |= (value<<6) & set->bits;
11248 if (set->cmd2 & CMD2_GBITS)
11249 newmode |= (value<<3) & set->bits;
11250 if (set->cmd2 & CMD2_OBITS)
11251 newmode |= value & set->bits;
11252 }
11253 break;
11254
11255 case '+':
11256 newmode |= set->bits;
11257 break;
11258
11259 case '-':
11260 newmode &= ~set->bits;
11261 break;
11262
11263 case 'X':
11264 if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
11265 newmode |= set->bits;
11266 break;
11267
11268 case '\0':
11269 default:
11270#ifdef SETMODE_DEBUG
11271 (void)printf("getmode:%04o -> %04o\n", omode, newmode);
11272#endif
11273 return (newmode);
11274 }
11275}
11276
Eric Andersen2870d962001-07-02 17:27:21 +000011277#define ADDCMD(a, b, c, d) do { \
11278 if (set >= endset) { \
11279 BITCMD *newset; \
11280 setlen += SET_LEN_INCR; \
11281 newset = realloc(saveset, sizeof(BITCMD) * setlen); \
11282 if (newset == NULL) { \
11283 free(saveset); \
11284 return (NULL); \
11285 } \
11286 set = newset + (set - saveset); \
11287 saveset = newset; \
11288 endset = newset + (setlen - 2); \
11289 } \
11290 set = addcmd(set, (a), (b), (c), (d)); \
Eric Andersencb57d552001-06-28 07:25:16 +000011291} while (/*CONSTCOND*/0)
11292
Eric Andersen2870d962001-07-02 17:27:21 +000011293#define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
Eric Andersencb57d552001-06-28 07:25:16 +000011294
11295static void *
11296setmode(p)
11297 const char *p;
11298{
11299 int perm, who;
11300 char op, *ep;
11301 BITCMD *set, *saveset, *endset;
11302 sigset_t mysigset, sigoset;
11303 mode_t mask;
Eric Andersen2870d962001-07-02 17:27:21 +000011304 int equalopdone = 0; /* pacify gcc */
Eric Andersencb57d552001-06-28 07:25:16 +000011305 int permXbits, setlen;
11306
11307 if (!*p)
11308 return (NULL);
11309
11310 /*
11311 * Get a copy of the mask for the permissions that are mask relative.
11312 * Flip the bits, we want what's not set. Since it's possible that
11313 * the caller is opening files inside a signal handler, protect them
11314 * as best we can.
11315 */
11316 sigfillset(&mysigset);
11317 (void)sigprocmask(SIG_BLOCK, &mysigset, &sigoset);
11318 (void)umask(mask = umask(0));
11319 mask = ~mask;
11320 (void)sigprocmask(SIG_SETMASK, &sigoset, NULL);
11321
11322 setlen = SET_LEN + 2;
Eric Andersen2870d962001-07-02 17:27:21 +000011323
Eric Andersencb57d552001-06-28 07:25:16 +000011324 if ((set = malloc((u_int)(sizeof(BITCMD) * setlen))) == NULL)
11325 return (NULL);
11326 saveset = set;
11327 endset = set + (setlen - 2);
11328
11329 /*
11330 * If an absolute number, get it and return; disallow non-octal digits
11331 * or illegal bits.
11332 */
Eric Andersen62483552001-07-10 06:09:16 +000011333 if (is_digit((unsigned char)*p)) {
Eric Andersencb57d552001-06-28 07:25:16 +000011334 perm = (mode_t)strtol(p, &ep, 8);
11335 if (*ep || perm & ~(STANDARD_BITS|S_ISTXT)) {
11336 free(saveset);
11337 return (NULL);
11338 }
11339 ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask);
11340 set->cmd = 0;
11341 return (saveset);
11342 }
11343
11344 /*
11345 * Build list of structures to set/clear/copy bits as described by
11346 * each clause of the symbolic mode.
11347 */
11348 for (;;) {
11349 /* First, find out which bits might be modified. */
11350 for (who = 0;; ++p) {
11351 switch (*p) {
11352 case 'a':
11353 who |= STANDARD_BITS;
11354 break;
11355 case 'u':
11356 who |= S_ISUID|S_IRWXU;
11357 break;
11358 case 'g':
11359 who |= S_ISGID|S_IRWXG;
11360 break;
11361 case 'o':
11362 who |= S_IRWXO;
11363 break;
11364 default:
11365 goto getop;
11366 }
11367 }
11368
Eric Andersen2870d962001-07-02 17:27:21 +000011369getop: if ((op = *p++) != '+' && op != '-' && op != '=') {
Eric Andersencb57d552001-06-28 07:25:16 +000011370 free(saveset);
11371 return (NULL);
11372 }
11373 if (op == '=')
11374 equalopdone = 0;
11375
11376 who &= ~S_ISTXT;
11377 for (perm = 0, permXbits = 0;; ++p) {
11378 switch (*p) {
11379 case 'r':
11380 perm |= S_IRUSR|S_IRGRP|S_IROTH;
11381 break;
11382 case 's':
11383 /*
Eric Andersen2870d962001-07-02 17:27:21 +000011384 * If specific bits where requested and
11385 * only "other" bits ignore set-id.
Eric Andersencb57d552001-06-28 07:25:16 +000011386 */
11387 if (who == 0 || (who & ~S_IRWXO))
11388 perm |= S_ISUID|S_ISGID;
11389 break;
11390 case 't':
11391 /*
Eric Andersen2870d962001-07-02 17:27:21 +000011392 * If specific bits where requested and
11393 * only "other" bits ignore set-id.
Eric Andersencb57d552001-06-28 07:25:16 +000011394 */
11395 if (who == 0 || (who & ~S_IRWXO)) {
11396 who |= S_ISTXT;
11397 perm |= S_ISTXT;
11398 }
11399 break;
11400 case 'w':
11401 perm |= S_IWUSR|S_IWGRP|S_IWOTH;
11402 break;
11403 case 'X':
11404 permXbits = S_IXUSR|S_IXGRP|S_IXOTH;
11405 break;
11406 case 'x':
11407 perm |= S_IXUSR|S_IXGRP|S_IXOTH;
11408 break;
11409 case 'u':
11410 case 'g':
11411 case 'o':
11412 /*
11413 * When ever we hit 'u', 'g', or 'o', we have
11414 * to flush out any partial mode that we have,
11415 * and then do the copying of the mode bits.
11416 */
11417 if (perm) {
11418 ADDCMD(op, who, perm, mask);
11419 perm = 0;
11420 }
11421 if (op == '=')
11422 equalopdone = 1;
11423 if (op == '+' && permXbits) {
11424 ADDCMD('X', who, permXbits, mask);
11425 permXbits = 0;
11426 }
11427 ADDCMD(*p, who, op, mask);
11428 break;
11429
11430 default:
11431 /*
11432 * Add any permissions that we haven't already
11433 * done.
11434 */
11435 if (perm || (op == '=' && !equalopdone)) {
11436 if (op == '=')
11437 equalopdone = 1;
11438 ADDCMD(op, who, perm, mask);
11439 perm = 0;
11440 }
11441 if (permXbits) {
11442 ADDCMD('X', who, permXbits, mask);
11443 permXbits = 0;
11444 }
11445 goto apply;
11446 }
11447 }
11448
Eric Andersen2870d962001-07-02 17:27:21 +000011449apply: if (!*p)
Eric Andersencb57d552001-06-28 07:25:16 +000011450 break;
11451 if (*p != ',')
11452 goto getop;
11453 ++p;
11454 }
11455 set->cmd = 0;
11456#ifdef SETMODE_DEBUG
11457 (void)printf("Before compress_mode()\n");
11458 dumpmode(saveset);
11459#endif
11460 compress_mode(saveset);
11461#ifdef SETMODE_DEBUG
11462 (void)printf("After compress_mode()\n");
11463 dumpmode(saveset);
11464#endif
11465 return (saveset);
11466}
11467
11468static BITCMD *
11469addcmd(set, op, who, oparg, mask)
11470 BITCMD *set;
11471 int oparg, who;
11472 int op;
11473 u_int mask;
11474{
11475
11476 _DIAGASSERT(set != NULL);
11477
11478 switch (op) {
11479 case '=':
11480 set->cmd = '-';
11481 set->bits = who ? who : STANDARD_BITS;
11482 set++;
11483
11484 op = '+';
11485 /* FALLTHROUGH */
11486 case '+':
11487 case '-':
11488 case 'X':
11489 set->cmd = op;
11490 set->bits = (who ? who : mask) & oparg;
11491 break;
11492
11493 case 'u':
11494 case 'g':
11495 case 'o':
11496 set->cmd = op;
11497 if (who) {
11498 set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) |
11499 ((who & S_IRGRP) ? CMD2_GBITS : 0) |
11500 ((who & S_IROTH) ? CMD2_OBITS : 0);
11501 set->bits = (mode_t)~0;
11502 } else {
11503 set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS;
11504 set->bits = mask;
11505 }
Eric Andersen2870d962001-07-02 17:27:21 +000011506
Eric Andersencb57d552001-06-28 07:25:16 +000011507 if (oparg == '+')
11508 set->cmd2 |= CMD2_SET;
11509 else if (oparg == '-')
11510 set->cmd2 |= CMD2_CLR;
11511 else if (oparg == '=')
11512 set->cmd2 |= CMD2_SET|CMD2_CLR;
11513 break;
11514 }
11515 return (set + 1);
11516}
11517
11518#ifdef SETMODE_DEBUG
11519static void
11520dumpmode(set)
11521 BITCMD *set;
11522{
11523
11524 _DIAGASSERT(set != NULL);
11525
11526 for (; set->cmd; ++set)
11527 (void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n",
11528 set->cmd, set->bits, set->cmd2 ? " cmd2:" : "",
11529 set->cmd2 & CMD2_CLR ? " CLR" : "",
11530 set->cmd2 & CMD2_SET ? " SET" : "",
11531 set->cmd2 & CMD2_UBITS ? " UBITS" : "",
11532 set->cmd2 & CMD2_GBITS ? " GBITS" : "",
11533 set->cmd2 & CMD2_OBITS ? " OBITS" : "");
11534}
11535#endif
11536
11537/*
11538 * Given an array of bitcmd structures, compress by compacting consecutive
11539 * '+', '-' and 'X' commands into at most 3 commands, one of each. The 'u',
Eric Andersen2870d962001-07-02 17:27:21 +000011540 * 'g' and 'o' commands continue to be separate. They could probably be
Eric Andersencb57d552001-06-28 07:25:16 +000011541 * compacted, but it's not worth the effort.
11542 */
11543static void
11544compress_mode(set)
11545 BITCMD *set;
11546{
11547 BITCMD *nset;
11548 int setbits, clrbits, Xbits, op;
11549
11550 _DIAGASSERT(set != NULL);
11551
11552 for (nset = set;;) {
11553 /* Copy over any 'u', 'g' and 'o' commands. */
11554 while ((op = nset->cmd) != '+' && op != '-' && op != 'X') {
11555 *set++ = *nset++;
11556 if (!op)
11557 return;
11558 }
11559
11560 for (setbits = clrbits = Xbits = 0;; nset++) {
11561 if ((op = nset->cmd) == '-') {
11562 clrbits |= nset->bits;
11563 setbits &= ~nset->bits;
11564 Xbits &= ~nset->bits;
11565 } else if (op == '+') {
11566 setbits |= nset->bits;
11567 clrbits &= ~nset->bits;
11568 Xbits &= ~nset->bits;
11569 } else if (op == 'X')
11570 Xbits |= nset->bits & ~setbits;
11571 else
11572 break;
11573 }
11574 if (clrbits) {
11575 set->cmd = '-';
11576 set->cmd2 = 0;
11577 set->bits = clrbits;
11578 set++;
11579 }
11580 if (setbits) {
11581 set->cmd = '+';
11582 set->cmd2 = 0;
11583 set->bits = setbits;
11584 set++;
11585 }
11586 if (Xbits) {
11587 set->cmd = 'X';
11588 set->cmd2 = 0;
11589 set->bits = Xbits;
11590 set++;
11591 }
11592 }
11593}
Eric Andersencb57d552001-06-28 07:25:16 +000011594#ifdef DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +000011595static void shtree (union node *, int, char *, FILE*);
11596static void shcmd (union node *, FILE *);
11597static void sharg (union node *, FILE *);
11598static void indent (int, char *, FILE *);
11599static void trstring (char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011600
11601
11602static void
11603showtree(n)
11604 union node *n;
11605{
11606 trputs("showtree called\n");
11607 shtree(n, 1, NULL, stdout);
11608}
11609
11610
11611static void
11612shtree(n, ind, pfx, fp)
11613 union node *n;
11614 int ind;
11615 char *pfx;
11616 FILE *fp;
11617{
11618 struct nodelist *lp;
11619 const char *s;
11620
11621 if (n == NULL)
11622 return;
11623
11624 indent(ind, pfx, fp);
11625 switch(n->type) {
11626 case NSEMI:
11627 s = "; ";
11628 goto binop;
11629 case NAND:
11630 s = " && ";
11631 goto binop;
11632 case NOR:
11633 s = " || ";
11634binop:
11635 shtree(n->nbinary.ch1, ind, NULL, fp);
11636 /* if (ind < 0) */
11637 fputs(s, fp);
11638 shtree(n->nbinary.ch2, ind, NULL, fp);
11639 break;
11640 case NCMD:
11641 shcmd(n, fp);
11642 if (ind >= 0)
11643 putc('\n', fp);
11644 break;
11645 case NPIPE:
11646 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11647 shcmd(lp->n, fp);
11648 if (lp->next)
11649 fputs(" | ", fp);
11650 }
11651 if (n->npipe.backgnd)
11652 fputs(" &", fp);
11653 if (ind >= 0)
11654 putc('\n', fp);
11655 break;
11656 default:
11657 fprintf(fp, "<node type %d>", n->type);
11658 if (ind >= 0)
11659 putc('\n', fp);
11660 break;
11661 }
11662}
11663
11664
11665
11666static void
11667shcmd(cmd, fp)
11668 union node *cmd;
11669 FILE *fp;
11670{
11671 union node *np;
11672 int first;
11673 const char *s;
11674 int dftfd;
11675
11676 first = 1;
11677 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11678 if (! first)
11679 putchar(' ');
11680 sharg(np, fp);
11681 first = 0;
11682 }
11683 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11684 if (! first)
11685 putchar(' ');
11686 switch (np->nfile.type) {
Eric Andersen2870d962001-07-02 17:27:21 +000011687 case NTO: s = ">"; dftfd = 1; break;
11688 case NAPPEND: s = ">>"; dftfd = 1; break;
11689 case NTOFD: s = ">&"; dftfd = 1; break;
11690 case NTOOV: s = ">|"; dftfd = 1; break;
11691 case NFROM: s = "<"; dftfd = 0; break;
11692 case NFROMFD: s = "<&"; dftfd = 0; break;
11693 case NFROMTO: s = "<>"; dftfd = 0; break;
11694 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011695 }
11696 if (np->nfile.fd != dftfd)
11697 fprintf(fp, "%d", np->nfile.fd);
11698 fputs(s, fp);
11699 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11700 fprintf(fp, "%d", np->ndup.dupfd);
11701 } else {
11702 sharg(np->nfile.fname, fp);
11703 }
11704 first = 0;
11705 }
11706}
11707
11708
11709
11710static void
11711sharg(arg, fp)
11712 union node *arg;
11713 FILE *fp;
11714 {
11715 char *p;
11716 struct nodelist *bqlist;
11717 int subtype;
11718
11719 if (arg->type != NARG) {
11720 printf("<node type %d>\n", arg->type);
11721 fflush(stdout);
11722 abort();
11723 }
11724 bqlist = arg->narg.backquote;
11725 for (p = arg->narg.text ; *p ; p++) {
11726 switch (*p) {
11727 case CTLESC:
11728 putc(*++p, fp);
11729 break;
11730 case CTLVAR:
11731 putc('$', fp);
11732 putc('{', fp);
11733 subtype = *++p;
11734 if (subtype == VSLENGTH)
11735 putc('#', fp);
11736
11737 while (*p != '=')
11738 putc(*p++, fp);
11739
11740 if (subtype & VSNUL)
11741 putc(':', fp);
11742
11743 switch (subtype & VSTYPE) {
11744 case VSNORMAL:
11745 putc('}', fp);
11746 break;
11747 case VSMINUS:
11748 putc('-', fp);
11749 break;
11750 case VSPLUS:
11751 putc('+', fp);
11752 break;
11753 case VSQUESTION:
11754 putc('?', fp);
11755 break;
11756 case VSASSIGN:
11757 putc('=', fp);
11758 break;
11759 case VSTRIMLEFT:
11760 putc('#', fp);
11761 break;
11762 case VSTRIMLEFTMAX:
11763 putc('#', fp);
11764 putc('#', fp);
11765 break;
11766 case VSTRIMRIGHT:
11767 putc('%', fp);
11768 break;
11769 case VSTRIMRIGHTMAX:
11770 putc('%', fp);
11771 putc('%', fp);
11772 break;
11773 case VSLENGTH:
11774 break;
11775 default:
11776 printf("<subtype %d>", subtype);
11777 }
11778 break;
11779 case CTLENDVAR:
11780 putc('}', fp);
11781 break;
11782 case CTLBACKQ:
11783 case CTLBACKQ|CTLQUOTE:
11784 putc('$', fp);
11785 putc('(', fp);
11786 shtree(bqlist->n, -1, NULL, fp);
11787 putc(')', fp);
11788 break;
11789 default:
11790 putc(*p, fp);
11791 break;
11792 }
11793 }
11794}
11795
11796
11797static void
11798indent(amount, pfx, fp)
11799 int amount;
11800 char *pfx;
11801 FILE *fp;
11802{
11803 int i;
11804
11805 for (i = 0 ; i < amount ; i++) {
11806 if (pfx && i == amount - 1)
11807 fputs(pfx, fp);
11808 putc('\t', fp);
11809 }
11810}
11811#endif
11812
11813
11814
11815/*
11816 * Debugging stuff.
11817 */
11818
11819
11820#ifdef DEBUG
11821FILE *tracefile;
11822
11823#if DEBUG == 2
11824static int debug = 1;
11825#else
11826static int debug = 0;
11827#endif
11828
11829
11830static void
11831trputc(c)
11832 int c;
11833{
11834 if (tracefile == NULL)
11835 return;
11836 putc(c, tracefile);
11837 if (c == '\n')
11838 fflush(tracefile);
11839}
11840
11841static void
11842trace(const char *fmt, ...)
11843{
11844 va_list va;
Eric Andersencb57d552001-06-28 07:25:16 +000011845 va_start(va, fmt);
Eric Andersencb57d552001-06-28 07:25:16 +000011846 if (tracefile != NULL) {
11847 (void) vfprintf(tracefile, fmt, va);
11848 if (strchr(fmt, '\n'))
11849 (void) fflush(tracefile);
11850 }
11851 va_end(va);
11852}
11853
11854
11855static void
11856trputs(s)
11857 const char *s;
11858{
11859 if (tracefile == NULL)
11860 return;
11861 fputs(s, tracefile);
11862 if (strchr(s, '\n'))
11863 fflush(tracefile);
11864}
11865
11866
11867static void
11868trstring(s)
11869 char *s;
11870{
11871 char *p;
11872 char c;
11873
11874 if (tracefile == NULL)
11875 return;
11876 putc('"', tracefile);
11877 for (p = s ; *p ; p++) {
11878 switch (*p) {
11879 case '\n': c = 'n'; goto backslash;
11880 case '\t': c = 't'; goto backslash;
11881 case '\r': c = 'r'; goto backslash;
11882 case '"': c = '"'; goto backslash;
11883 case '\\': c = '\\'; goto backslash;
11884 case CTLESC: c = 'e'; goto backslash;
11885 case CTLVAR: c = 'v'; goto backslash;
11886 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11887 case CTLBACKQ: c = 'q'; goto backslash;
11888 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
Eric Andersen2870d962001-07-02 17:27:21 +000011889backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011890 putc(c, tracefile);
11891 break;
11892 default:
11893 if (*p >= ' ' && *p <= '~')
11894 putc(*p, tracefile);
11895 else {
11896 putc('\\', tracefile);
11897 putc(*p >> 6 & 03, tracefile);
11898 putc(*p >> 3 & 07, tracefile);
11899 putc(*p & 07, tracefile);
11900 }
11901 break;
11902 }
11903 }
11904 putc('"', tracefile);
11905}
11906
11907
11908static void
11909trargs(ap)
11910 char **ap;
11911{
11912 if (tracefile == NULL)
11913 return;
11914 while (*ap) {
11915 trstring(*ap++);
11916 if (*ap)
11917 putc(' ', tracefile);
11918 else
11919 putc('\n', tracefile);
11920 }
11921 fflush(tracefile);
11922}
11923
11924
11925static void
11926opentrace() {
11927 char s[100];
11928#ifdef O_APPEND
11929 int flags;
11930#endif
11931
11932 if (!debug)
11933 return;
11934#ifdef not_this_way
11935 {
11936 char *p;
11937 if ((p = getenv("HOME")) == NULL) {
11938 if (geteuid() == 0)
11939 p = "/";
11940 else
11941 p = "/tmp";
11942 }
Eric Andersen2870d962001-07-02 17:27:21 +000011943 strcpy(s, p);
Eric Andersencb57d552001-06-28 07:25:16 +000011944 strcat(s, "/trace");
11945 }
11946#else
Eric Andersen2870d962001-07-02 17:27:21 +000011947 strcpy(s, "./trace");
Eric Andersencb57d552001-06-28 07:25:16 +000011948#endif /* not_this_way */
11949 if ((tracefile = fopen(s, "a")) == NULL) {
11950 fprintf(stderr, "Can't open %s\n", s);
11951 return;
11952 }
11953#ifdef O_APPEND
11954 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11955 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11956#endif
11957 fputs("\nTracing started.\n", tracefile);
11958 fflush(tracefile);
11959}
11960#endif /* DEBUG */
11961
11962
11963/*
Eric Andersencb57d552001-06-28 07:25:16 +000011964 * The trap builtin.
11965 */
11966
11967static int
11968trapcmd(argc, argv)
11969 int argc;
11970 char **argv;
11971{
11972 char *action;
11973 char **ap;
11974 int signo;
11975
11976 if (argc <= 1) {
11977 for (signo = 0 ; signo < NSIG ; signo++) {
11978 if (trap[signo] != NULL) {
11979 char *p;
Eric Andersen34506362001-08-02 05:02:46 +000011980 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011981
11982 p = single_quote(trap[signo]);
Eric Andersen34506362001-08-02 05:02:46 +000011983 sn = sys_siglist[signo];
11984 if(sn==NULL)
11985 sn = u_signal_names(0, &signo, 0);
11986 if(sn==NULL)
11987 sn = "???";
11988 printf("trap -- %s %s\n", p, sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011989 stunalloc(p);
11990 }
11991 }
11992 return 0;
11993 }
11994 ap = argv + 1;
11995 if (argc == 2)
11996 action = NULL;
11997 else
11998 action = *ap++;
11999 while (*ap) {
12000 if ((signo = decode_signal(*ap, 0)) < 0)
12001 error("%s: bad trap", *ap);
12002 INTOFF;
12003 if (action) {
12004 if (action[0] == '-' && action[1] == '\0')
12005 action = NULL;
12006 else
12007 action = savestr(action);
12008 }
12009 if (trap[signo])
12010 ckfree(trap[signo]);
12011 trap[signo] = action;
12012 if (signo != 0)
12013 setsignal(signo);
12014 INTON;
12015 ap++;
12016 }
12017 return 0;
12018}
12019
12020
12021
Eric Andersencb57d552001-06-28 07:25:16 +000012022
12023
12024
12025/*
12026 * Set the signal handler for the specified signal. The routine figures
12027 * out what it should be set to.
12028 */
12029
12030static void
Eric Andersen2870d962001-07-02 17:27:21 +000012031setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000012032{
12033 int action;
12034 char *t;
12035 struct sigaction act;
12036
12037 if ((t = trap[signo]) == NULL)
12038 action = S_DFL;
12039 else if (*t != '\0')
12040 action = S_CATCH;
12041 else
12042 action = S_IGN;
12043 if (rootshell && action == S_DFL) {
12044 switch (signo) {
12045 case SIGINT:
12046 if (iflag || minusc || sflag == 0)
12047 action = S_CATCH;
12048 break;
12049 case SIGQUIT:
12050#ifdef DEBUG
12051 {
Eric Andersencb57d552001-06-28 07:25:16 +000012052
12053 if (debug)
12054 break;
12055 }
12056#endif
12057 /* FALLTHROUGH */
12058 case SIGTERM:
12059 if (iflag)
12060 action = S_IGN;
12061 break;
Eric Andersen2870d962001-07-02 17:27:21 +000012062#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000012063 case SIGTSTP:
12064 case SIGTTOU:
12065 if (mflag)
12066 action = S_IGN;
12067 break;
12068#endif
12069 }
12070 }
12071
12072 t = &sigmode[signo - 1];
12073 if (*t == 0) {
12074 /*
12075 * current setting unknown
12076 */
12077 if (sigaction(signo, 0, &act) == -1) {
12078 /*
12079 * Pretend it worked; maybe we should give a warning
12080 * here, but other shells don't. We don't alter
12081 * sigmode, so that we retry every time.
12082 */
12083 return;
12084 }
12085 if (act.sa_handler == SIG_IGN) {
12086 if (mflag && (signo == SIGTSTP ||
12087 signo == SIGTTIN || signo == SIGTTOU)) {
Eric Andersen2870d962001-07-02 17:27:21 +000012088 *t = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000012089 } else
12090 *t = S_HARD_IGN;
12091 } else {
Eric Andersen2870d962001-07-02 17:27:21 +000012092 *t = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000012093 }
12094 }
12095 if (*t == S_HARD_IGN || *t == action)
12096 return;
12097 switch (action) {
12098 case S_CATCH:
12099 act.sa_handler = onsig;
12100 break;
12101 case S_IGN:
12102 act.sa_handler = SIG_IGN;
12103 break;
12104 default:
12105 act.sa_handler = SIG_DFL;
12106 }
12107 *t = action;
12108 act.sa_flags = 0;
12109 sigemptyset(&act.sa_mask);
12110 sigaction(signo, &act, 0);
12111}
12112
12113/*
12114 * Ignore a signal.
12115 */
12116
12117static void
12118ignoresig(signo)
12119 int signo;
12120{
12121 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
12122 signal(signo, SIG_IGN);
12123 }
12124 sigmode[signo - 1] = S_HARD_IGN;
12125}
12126
12127
Eric Andersencb57d552001-06-28 07:25:16 +000012128/*
12129 * Signal handler.
12130 */
12131
12132static void
Eric Andersen2870d962001-07-02 17:27:21 +000012133onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000012134{
12135 if (signo == SIGINT && trap[SIGINT] == NULL) {
12136 onint();
12137 return;
12138 }
12139 gotsig[signo - 1] = 1;
12140 pendingsigs++;
12141}
12142
12143
Eric Andersencb57d552001-06-28 07:25:16 +000012144/*
12145 * Called to execute a trap. Perhaps we should avoid entering new trap
12146 * handlers while we are executing a trap handler.
12147 */
12148
12149static void
Eric Andersen2870d962001-07-02 17:27:21 +000012150dotrap(void)
12151{
Eric Andersencb57d552001-06-28 07:25:16 +000012152 int i;
12153 int savestatus;
12154
12155 for (;;) {
12156 for (i = 1 ; ; i++) {
12157 if (gotsig[i - 1])
12158 break;
12159 if (i >= NSIG - 1)
12160 goto done;
12161 }
12162 gotsig[i - 1] = 0;
12163 savestatus=exitstatus;
12164 evalstring(trap[i], 0);
12165 exitstatus=savestatus;
12166 }
12167done:
12168 pendingsigs = 0;
12169}
12170
Eric Andersencb57d552001-06-28 07:25:16 +000012171/*
12172 * Called to exit the shell.
12173 */
12174
12175static void
Eric Andersen2870d962001-07-02 17:27:21 +000012176exitshell(int status)
Eric Andersencb57d552001-06-28 07:25:16 +000012177{
12178 struct jmploc loc1, loc2;
12179 char *p;
12180
12181 TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
12182 if (setjmp(loc1.loc)) {
12183 goto l1;
12184 }
12185 if (setjmp(loc2.loc)) {
12186 goto l2;
12187 }
12188 handler = &loc1;
12189 if ((p = trap[0]) != NULL && *p != '\0') {
12190 trap[0] = NULL;
12191 evalstring(p, 0);
12192 }
Eric Andersen2870d962001-07-02 17:27:21 +000012193l1: handler = &loc2; /* probably unnecessary */
Eric Andersencb57d552001-06-28 07:25:16 +000012194 flushall();
Eric Andersen2870d962001-07-02 17:27:21 +000012195#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000012196 setjobctl(0);
12197#endif
12198l2: _exit(status);
12199 /* NOTREACHED */
12200}
12201
12202static int decode_signal(const char *string, int minsig)
12203{
12204 int signo;
Eric Andersen34506362001-08-02 05:02:46 +000012205 const char *name = u_signal_names(string, &signo, minsig);
Eric Andersencb57d552001-06-28 07:25:16 +000012206
Eric Andersen34506362001-08-02 05:02:46 +000012207 return name ? signo : -1;
Eric Andersencb57d552001-06-28 07:25:16 +000012208}
Eric Andersen34506362001-08-02 05:02:46 +000012209
Eric Andersen2870d962001-07-02 17:27:21 +000012210static struct var **hashvar (const char *);
12211static void showvars (const char *, int, int);
12212static struct var **findvar (struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000012213
12214/*
12215 * Initialize the varable symbol tables and import the environment
12216 */
12217
Eric Andersencb57d552001-06-28 07:25:16 +000012218/*
12219 * This routine initializes the builtin variables. It is called when the
12220 * shell is initialized and again when a shell procedure is spawned.
12221 */
12222
12223static void
12224initvar() {
12225 const struct varinit *ip;
12226 struct var *vp;
12227 struct var **vpp;
12228
12229 for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
12230 if ((vp->flags & VEXPORT) == 0) {
12231 vpp = hashvar(ip->text);
12232 vp->next = *vpp;
12233 *vpp = vp;
12234 vp->text = strdup(ip->text);
12235 vp->flags = ip->flags;
12236 vp->func = ip->func;
12237 }
12238 }
12239 /*
12240 * PS1 depends on uid
12241 */
12242 if ((vps1.flags & VEXPORT) == 0) {
12243 vpp = hashvar("PS1=");
12244 vps1.next = *vpp;
12245 *vpp = &vps1;
12246 vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# ");
12247 vps1.flags = VSTRFIXED|VTEXTFIXED;
12248 }
12249}
12250
12251/*
12252 * Set the value of a variable. The flags argument is ored with the
12253 * flags of the variable. If val is NULL, the variable is unset.
12254 */
12255
12256static void
12257setvar(name, val, flags)
12258 const char *name, *val;
12259 int flags;
12260{
12261 const char *p;
12262 int len;
12263 int namelen;
12264 char *nameeq;
12265 int isbad;
12266 int vallen = 0;
12267
12268 isbad = 0;
12269 p = name;
12270 if (! is_name(*p))
12271 isbad = 1;
12272 p++;
12273 for (;;) {
12274 if (! is_in_name(*p)) {
12275 if (*p == '\0' || *p == '=')
12276 break;
12277 isbad = 1;
12278 }
12279 p++;
12280 }
12281 namelen = p - name;
12282 if (isbad)
12283 error("%.*s: bad variable name", namelen, name);
Eric Andersen2870d962001-07-02 17:27:21 +000012284 len = namelen + 2; /* 2 is space for '=' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +000012285 if (val == NULL) {
12286 flags |= VUNSET;
12287 } else {
12288 len += vallen = strlen(val);
12289 }
12290 INTOFF;
12291 nameeq = ckmalloc(len);
12292 memcpy(nameeq, name, namelen);
12293 nameeq[namelen] = '=';
12294 if (val) {
12295 memcpy(nameeq + namelen + 1, val, vallen + 1);
12296 } else {
12297 nameeq[namelen + 1] = '\0';
12298 }
12299 setvareq(nameeq, flags);
12300 INTON;
12301}
12302
12303
12304
12305/*
12306 * Same as setvar except that the variable and value are passed in
12307 * the first argument as name=value. Since the first argument will
12308 * be actually stored in the table, it should not be a string that
12309 * will go away.
12310 */
12311
12312static void
12313setvareq(s, flags)
12314 char *s;
12315 int flags;
12316{
12317 struct var *vp, **vpp;
12318
12319 vpp = hashvar(s);
12320 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
12321 if ((vp = *findvar(vpp, s))) {
12322 if (vp->flags & VREADONLY) {
12323 size_t len = strchr(s, '=') - s;
12324 error("%.*s: is read only", len, s);
12325 }
12326 INTOFF;
12327
12328 if (vp->func && (flags & VNOFUNC) == 0)
12329 (*vp->func)(strchr(s, '=') + 1);
12330
12331 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12332 ckfree(vp->text);
12333
12334 vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
12335 vp->flags |= flags;
12336 vp->text = s;
12337
12338 /*
12339 * We could roll this to a function, to handle it as
12340 * a regular variable function callback, but why bother?
12341 */
12342 if (iflag && (vp == &vmpath || (vp == &vmail && !mpathset())))
12343 chkmail(1);
12344 INTON;
12345 return;
12346 }
12347 /* not found */
12348 vp = ckmalloc(sizeof (*vp));
12349 vp->flags = flags;
12350 vp->text = s;
12351 vp->next = *vpp;
12352 vp->func = NULL;
12353 *vpp = vp;
12354}
12355
12356
12357
12358/*
12359 * Process a linked list of variable assignments.
12360 */
12361
12362static void
12363listsetvar(mylist)
12364 struct strlist *mylist;
12365 {
12366 struct strlist *lp;
12367
12368 INTOFF;
12369 for (lp = mylist ; lp ; lp = lp->next) {
12370 setvareq(savestr(lp->text), 0);
12371 }
12372 INTON;
12373}
12374
12375
12376
12377/*
12378 * Find the value of a variable. Returns NULL if not set.
12379 */
12380
Eric Andersen62483552001-07-10 06:09:16 +000012381static const char *
Eric Andersencb57d552001-06-28 07:25:16 +000012382lookupvar(name)
12383 const char *name;
12384 {
12385 struct var *v;
12386
12387 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
12388 return strchr(v->text, '=') + 1;
12389 }
12390 return NULL;
12391}
12392
12393
12394
12395/*
12396 * Search the environment of a builtin command.
12397 */
12398
Eric Andersen62483552001-07-10 06:09:16 +000012399static const char *
12400bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012401{
Eric Andersen62483552001-07-10 06:09:16 +000012402 const struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012403
12404 for (sp = cmdenviron ; sp ; sp = sp->next) {
12405 if (varequal(sp->text, name))
12406 return strchr(sp->text, '=') + 1;
12407 }
12408 return lookupvar(name);
12409}
12410
12411
12412
12413/*
12414 * Generate a list of exported variables. This routine is used to construct
12415 * the third argument to execve when executing a program.
12416 */
12417
12418static char **
12419environment() {
12420 int nenv;
12421 struct var **vpp;
12422 struct var *vp;
12423 char **env;
12424 char **ep;
12425
12426 nenv = 0;
12427 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12428 for (vp = *vpp ; vp ; vp = vp->next)
12429 if (vp->flags & VEXPORT)
12430 nenv++;
12431 }
12432 ep = env = stalloc((nenv + 1) * sizeof *env);
12433 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12434 for (vp = *vpp ; vp ; vp = vp->next)
12435 if (vp->flags & VEXPORT)
12436 *ep++ = vp->text;
12437 }
12438 *ep = NULL;
12439 return env;
12440}
12441
12442
12443/*
12444 * Called when a shell procedure is invoked to clear out nonexported
12445 * variables. It is also necessary to reallocate variables of with
12446 * VSTACK set since these are currently allocated on the stack.
12447 */
12448
Eric Andersencb57d552001-06-28 07:25:16 +000012449static void
Eric Andersen2870d962001-07-02 17:27:21 +000012450shprocvar(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000012451 struct var **vpp;
12452 struct var *vp, **prev;
12453
12454 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12455 for (prev = vpp ; (vp = *prev) != NULL ; ) {
12456 if ((vp->flags & VEXPORT) == 0) {
12457 *prev = vp->next;
12458 if ((vp->flags & VTEXTFIXED) == 0)
12459 ckfree(vp->text);
12460 if ((vp->flags & VSTRFIXED) == 0)
12461 ckfree(vp);
12462 } else {
12463 if (vp->flags & VSTACK) {
12464 vp->text = savestr(vp->text);
12465 vp->flags &=~ VSTACK;
12466 }
12467 prev = &vp->next;
12468 }
12469 }
12470 }
12471 initvar();
12472}
12473
12474
12475
12476/*
12477 * Command to list all variables which are set. Currently this command
12478 * is invoked from the set command when the set command is called without
12479 * any variables.
12480 */
12481
12482static int
12483showvarscmd(argc, argv)
12484 int argc;
12485 char **argv;
12486{
12487 showvars(nullstr, VUNSET, VUNSET);
12488 return 0;
12489}
12490
12491
12492
12493/*
12494 * The export and readonly commands.
12495 */
12496
12497static int
12498exportcmd(argc, argv)
12499 int argc;
12500 char **argv;
12501{
12502 struct var *vp;
12503 char *name;
12504 const char *p;
12505 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12506 int pflag;
12507
12508 listsetvar(cmdenviron);
12509 pflag = (nextopt("p") == 'p');
12510 if (argc > 1 && !pflag) {
12511 while ((name = *argptr++) != NULL) {
12512 if ((p = strchr(name, '=')) != NULL) {
12513 p++;
12514 } else {
12515 if ((vp = *findvar(hashvar(name), name))) {
12516 vp->flags |= flag;
12517 goto found;
12518 }
12519 }
12520 setvar(name, p, flag);
12521found:;
12522 }
12523 } else {
12524 showvars(argv[0], flag, 0);
12525 }
12526 return 0;
12527}
12528
Eric Andersen34506362001-08-02 05:02:46 +000012529
Eric Andersencb57d552001-06-28 07:25:16 +000012530/*
12531 * The "local" command.
12532 */
12533
Eric Andersen2870d962001-07-02 17:27:21 +000012534/* funcnest nonzero if we are currently evaluating a function */
12535
Eric Andersencb57d552001-06-28 07:25:16 +000012536static int
12537localcmd(argc, argv)
12538 int argc;
12539 char **argv;
12540{
12541 char *name;
12542
Eric Andersen2870d962001-07-02 17:27:21 +000012543 if (! funcnest)
Eric Andersencb57d552001-06-28 07:25:16 +000012544 error("Not in a function");
12545 while ((name = *argptr++) != NULL) {
12546 mklocal(name);
12547 }
12548 return 0;
12549}
12550
12551
12552/*
12553 * Make a variable a local variable. When a variable is made local, it's
12554 * value and flags are saved in a localvar structure. The saved values
12555 * will be restored when the shell function returns. We handle the name
12556 * "-" as a special case.
12557 */
12558
12559static void
12560mklocal(name)
12561 char *name;
12562 {
12563 struct localvar *lvp;
12564 struct var **vpp;
12565 struct var *vp;
12566
12567 INTOFF;
12568 lvp = ckmalloc(sizeof (struct localvar));
12569 if (name[0] == '-' && name[1] == '\0') {
12570 char *p;
Eric Andersen2870d962001-07-02 17:27:21 +000012571 p = ckmalloc(sizeof optet_vals);
12572 lvp->text = memcpy(p, optet_vals, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000012573 vp = NULL;
12574 } else {
12575 vpp = hashvar(name);
12576 vp = *findvar(vpp, name);
12577 if (vp == NULL) {
12578 if (strchr(name, '='))
12579 setvareq(savestr(name), VSTRFIXED);
12580 else
12581 setvar(name, NULL, VSTRFIXED);
Eric Andersen2870d962001-07-02 17:27:21 +000012582 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012583 lvp->text = NULL;
12584 lvp->flags = VUNSET;
12585 } else {
12586 lvp->text = vp->text;
12587 lvp->flags = vp->flags;
12588 vp->flags |= VSTRFIXED|VTEXTFIXED;
12589 if (strchr(name, '='))
12590 setvareq(savestr(name), 0);
12591 }
12592 }
12593 lvp->vp = vp;
12594 lvp->next = localvars;
12595 localvars = lvp;
12596 INTON;
12597}
12598
12599
12600/*
12601 * Called after a function returns.
12602 */
12603
12604static void
12605poplocalvars() {
12606 struct localvar *lvp;
12607 struct var *vp;
12608
12609 while ((lvp = localvars) != NULL) {
12610 localvars = lvp->next;
12611 vp = lvp->vp;
Eric Andersen2870d962001-07-02 17:27:21 +000012612 if (vp == NULL) { /* $- saved */
12613 memcpy(optet_vals, lvp->text, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000012614 ckfree(lvp->text);
12615 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12616 (void)unsetvar(vp->text);
12617 } else {
12618 if ((vp->flags & VTEXTFIXED) == 0)
12619 ckfree(vp->text);
12620 vp->flags = lvp->flags;
12621 vp->text = lvp->text;
12622 }
12623 ckfree(lvp);
12624 }
12625}
12626
12627
12628static int
12629setvarcmd(argc, argv)
12630 int argc;
12631 char **argv;
12632{
12633 if (argc <= 2)
12634 return unsetcmd(argc, argv);
12635 else if (argc == 3)
12636 setvar(argv[1], argv[2], 0);
12637 else
12638 error("List assignment not implemented");
12639 return 0;
12640}
12641
12642
12643/*
12644 * The unset builtin command. We unset the function before we unset the
12645 * variable to allow a function to be unset when there is a readonly variable
12646 * with the same name.
12647 */
12648
12649static int
12650unsetcmd(argc, argv)
12651 int argc;
12652 char **argv;
12653{
12654 char **ap;
12655 int i;
12656 int flg_func = 0;
12657 int flg_var = 0;
12658 int ret = 0;
12659
12660 while ((i = nextopt("vf")) != '\0') {
12661 if (i == 'f')
12662 flg_func = 1;
12663 else
12664 flg_var = 1;
12665 }
12666 if (flg_func == 0 && flg_var == 0)
12667 flg_var = 1;
12668
12669 for (ap = argptr; *ap ; ap++) {
12670 if (flg_func)
12671 unsetfunc(*ap);
12672 if (flg_var)
12673 ret |= unsetvar(*ap);
12674 }
12675 return ret;
12676}
12677
12678
12679/*
12680 * Unset the specified variable.
12681 */
12682
12683static int
Eric Andersen62483552001-07-10 06:09:16 +000012684unsetvar(const char *s)
12685{
Eric Andersencb57d552001-06-28 07:25:16 +000012686 struct var **vpp;
12687 struct var *vp;
12688
12689 vpp = findvar(hashvar(s), s);
12690 vp = *vpp;
12691 if (vp) {
12692 if (vp->flags & VREADONLY)
12693 return (1);
12694 INTOFF;
12695 if (*(strchr(vp->text, '=') + 1) != '\0')
12696 setvar(s, nullstr, 0);
12697 vp->flags &= ~VEXPORT;
12698 vp->flags |= VUNSET;
12699 if ((vp->flags & VSTRFIXED) == 0) {
12700 if ((vp->flags & VTEXTFIXED) == 0)
12701 ckfree(vp->text);
12702 *vpp = vp->next;
12703 ckfree(vp);
12704 }
12705 INTON;
12706 return (0);
12707 }
12708
12709 return (0);
12710}
12711
12712
12713
12714/*
12715 * Find the appropriate entry in the hash table from the name.
12716 */
12717
12718static struct var **
Eric Andersen62483552001-07-10 06:09:16 +000012719hashvar(const char *p)
12720{
Eric Andersencb57d552001-06-28 07:25:16 +000012721 unsigned int hashval;
12722
12723 hashval = ((unsigned char) *p) << 4;
12724 while (*p && *p != '=')
12725 hashval += (unsigned char) *p++;
12726 return &vartab[hashval % VTABSIZE];
12727}
12728
12729
12730
12731/*
12732 * Returns true if the two strings specify the same varable. The first
12733 * variable name is terminated by '='; the second may be terminated by
12734 * either '=' or '\0'.
12735 */
12736
12737static int
Eric Andersen62483552001-07-10 06:09:16 +000012738varequal(const char *p, const char *q)
12739{
Eric Andersencb57d552001-06-28 07:25:16 +000012740 while (*p == *q++) {
12741 if (*p++ == '=')
12742 return 1;
12743 }
12744 if (*p == '=' && *(q - 1) == '\0')
12745 return 1;
12746 return 0;
12747}
12748
12749static void
12750showvars(const char *myprefix, int mask, int xor)
12751{
12752 struct var **vpp;
12753 struct var *vp;
12754 const char *sep = myprefix == nullstr ? myprefix : spcstr;
12755
12756 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12757 for (vp = *vpp ; vp ; vp = vp->next) {
12758 if ((vp->flags & mask) ^ xor) {
12759 char *p;
12760 int len;
12761
12762 p = strchr(vp->text, '=') + 1;
12763 len = p - vp->text;
12764 p = single_quote(p);
12765
Eric Andersen62483552001-07-10 06:09:16 +000012766 printf("%s%s%.*s%s\n", myprefix, sep, len,
12767 vp->text, p);
Eric Andersencb57d552001-06-28 07:25:16 +000012768 stunalloc(p);
12769 }
12770 }
12771 }
12772}
12773
12774static struct var **
12775findvar(struct var **vpp, const char *name)
12776{
12777 for (; *vpp; vpp = &(*vpp)->next) {
12778 if (varequal((*vpp)->text, name)) {
12779 break;
12780 }
12781 }
12782 return vpp;
12783}
12784
12785/*
12786 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
12787 * This file contains code for the times builtin.
Eric Andersen34506362001-08-02 05:02:46 +000012788 * $Id: ash.c,v 1.17 2001/08/02 05:02:45 andersen Exp $
Eric Andersencb57d552001-06-28 07:25:16 +000012789 */
12790static int timescmd (int argc, char **argv)
12791{
12792 struct tms buf;
12793 long int clk_tck = sysconf(_SC_CLK_TCK);
12794
12795 times(&buf);
12796 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
12797 (int) (buf.tms_utime / clk_tck / 60),
12798 ((double) buf.tms_utime) / clk_tck,
12799 (int) (buf.tms_stime / clk_tck / 60),
12800 ((double) buf.tms_stime) / clk_tck,
12801 (int) (buf.tms_cutime / clk_tck / 60),
12802 ((double) buf.tms_cutime) / clk_tck,
12803 (int) (buf.tms_cstime / clk_tck / 60),
12804 ((double) buf.tms_cstime) / clk_tck);
12805 return 0;
12806}
12807
Eric Andersen74bcd162001-07-30 21:41:37 +000012808#ifdef ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012809/* The let builtin. */
12810int letcmd(int argc, char **argv)
Eric Andersen74bcd162001-07-30 21:41:37 +000012811{
Eric Andersen34506362001-08-02 05:02:46 +000012812 int errcode;
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012813 long result=0;
12814 if (argc == 2) {
12815 char *tmp, *expression, p[13];
12816 expression = strchr(argv[1], '=');
12817 if (!expression) {
Eric Andersen34506362001-08-02 05:02:46 +000012818 /* Cannot use 'error()' here, or the return code
12819 * will be incorrect */
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012820 out2fmt("sh: let: syntax error: \"%s\"\n", argv[1]);
12821 return 0;
Eric Andersen74bcd162001-07-30 21:41:37 +000012822 }
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012823 *expression = '\0';
12824 tmp = ++expression;
Eric Andersen34506362001-08-02 05:02:46 +000012825 result = arith(tmp, &errcode);
12826 if (errcode < 0) {
12827 /* Cannot use 'error()' here, or the return code
12828 * will be incorrect */
12829 out2fmt("sh: let: ");
12830 if(errcode == -2)
12831 out2fmt("divide by zero");
12832 else
12833 out2fmt("syntax error: \"%s=%s\"\n", argv[1], expression);
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012834 return 0;
12835 }
12836 snprintf(p, 12, "%ld", result);
12837 setvar(argv[1], savestr(p), 0);
12838 } else if (argc >= 3)
12839 synerror("invalid operand");
12840 return !result;
Eric Andersen74bcd162001-07-30 21:41:37 +000012841}
12842#endif
12843
12844
12845
Eric Andersendf82f612001-06-28 07:46:40 +000012846/*-
12847 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000012848 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000012849 *
12850 * This code is derived from software contributed to Berkeley by
12851 * Kenneth Almquist.
12852 *
12853 * Redistribution and use in source and binary forms, with or without
12854 * modification, are permitted provided that the following conditions
12855 * are met:
12856 * 1. Redistributions of source code must retain the above copyright
12857 * notice, this list of conditions and the following disclaimer.
12858 * 2. Redistributions in binary form must reproduce the above copyright
12859 * notice, this list of conditions and the following disclaimer in the
12860 * documentation and/or other materials provided with the distribution.
12861 *
Eric Andersen2870d962001-07-02 17:27:21 +000012862 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
12863 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000012864 *
12865 * 4. Neither the name of the University nor the names of its contributors
12866 * may be used to endorse or promote products derived from this software
12867 * without specific prior written permission.
12868 *
12869 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
12870 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
12871 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
12872 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
12873 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
12874 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
12875 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
12876 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
12877 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
12878 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
12879 * SUCH DAMAGE.
12880 */