blob: 09975198dbed1bcbfa2d84eb24e2f5410da7506d [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
Eric Andersen2870d962001-07-02 17:27:21 +000036/* Enable this to compile in extra debugging noise. When debugging is
37 * on, debugging info will be written to $HOME/trace and a quit signal
38 * will generate a core dump. */
39#undef DEBUG
40
Eric Andersen2870d962001-07-02 17:27:21 +000041/* These are here to work with glibc -- Don't change these... */
Eric Andersendf82f612001-06-28 07:46:40 +000042#undef FNMATCH_BROKEN
43#undef GLOB_BROKEN
Eric Andersen5bb16772001-09-06 18:00:41 +000044#define IFS_BROKEN
Eric Andersencb57d552001-06-28 07:25:16 +000045
46#include <assert.h>
Manuel Novoa III 16815d42001-08-10 19:36:07 +000047#include <stddef.h>
Eric Andersencb57d552001-06-28 07:25:16 +000048#include <ctype.h>
49#include <dirent.h>
50#include <errno.h>
51#include <fcntl.h>
52#include <limits.h>
53#include <paths.h>
Eric Andersencb57d552001-06-28 07:25:16 +000054#include <setjmp.h>
55#include <signal.h>
56#include <stdarg.h>
Eric Andersencb57d552001-06-28 07:25:16 +000057#include <stdio.h>
58#include <stdlib.h>
59#include <string.h>
60#include <sysexits.h>
61#include <unistd.h>
62#include <sys/stat.h>
63#include <sys/cdefs.h>
64#include <sys/ioctl.h>
65#include <sys/param.h>
66#include <sys/resource.h>
67#include <sys/time.h>
68#include <sys/times.h>
69#include <sys/types.h>
70#include <sys/wait.h>
Robert Grieblea1a63a2002-06-04 20:10:23 +000071#include "busybox.h"
Eric Andersen887ca792002-07-03 23:19:26 +000072#include "pwd_.h"
Eric Andersencb57d552001-06-28 07:25:16 +000073
74
75#if !defined(FNMATCH_BROKEN)
76#include <fnmatch.h>
77#endif
78#if !defined(GLOB_BROKEN)
79#include <glob.h>
80#endif
81
Eric Andersend35c5df2002-01-09 15:37:36 +000082#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +000083#include <termios.h>
Eric Andersencb57d552001-06-28 07:25:16 +000084#endif
85
Eric Andersen2870d962001-07-02 17:27:21 +000086#include "cmdedit.h"
87
Eric Andersen2870d962001-07-02 17:27:21 +000088/*
89 * This file was generated by the mksyntax program.
90 */
91
92/* Syntax classes */
93#define CWORD 0 /* character is nothing special */
94#define CNL 1 /* newline character */
95#define CBACK 2 /* a backslash character */
96#define CSQUOTE 3 /* single quote */
97#define CDQUOTE 4 /* double quote */
98#define CENDQUOTE 5 /* a terminating quote */
99#define CBQUOTE 6 /* backwards single quote */
100#define CVAR 7 /* a dollar sign */
101#define CENDVAR 8 /* a '}' character */
102#define CLP 9 /* a left paren in arithmetic */
103#define CRP 10 /* a right paren in arithmetic */
104#define CENDFILE 11 /* end of file */
105#define CCTL 12 /* like CWORD, except it must be escaped */
106#define CSPCL 13 /* these terminate a word */
107#define CIGN 14 /* character should be ignored */
108
Eric Andersen2870d962001-07-02 17:27:21 +0000109#define SYNBASE 130
110#define PEOF -130
111
112#define PEOA -129
113
114#define TEOF 0
115#define TNL 1
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000116#define TREDIR 2
117#define TWORD 3
118#define TASSIGN 4
119#define TSEMI 5
120#define TBACKGND 6
121#define TAND 7
122#define TOR 8
123#define TPIPE 9
124#define TLP 10
125#define TRP 11
126#define TENDCASE 12
127#define TENDBQUOTE 13
Eric Andersen2870d962001-07-02 17:27:21 +0000128#define TNOT 14
129#define TCASE 15
130#define TDO 16
131#define TDONE 17
132#define TELIF 18
133#define TELSE 19
134#define TESAC 20
135#define TFI 21
136#define TFOR 22
137#define TIF 23
138#define TIN 24
139#define TTHEN 25
140#define TUNTIL 26
141#define TWHILE 27
142#define TBEGIN 28
143#define TEND 29
144
145
Eric Andersen2870d962001-07-02 17:27:21 +0000146
147/* control characters in argument strings */
148#define CTLESC '\201'
149#define CTLVAR '\202'
150#define CTLENDVAR '\203'
151#define CTLBACKQ '\204'
152#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
153/* CTLBACKQ | CTLQUOTE == '\205' */
154#define CTLARI '\206'
155#define CTLENDARI '\207'
156#define CTLQUOTEMARK '\210'
157
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000158
Eric Andersen62483552001-07-10 06:09:16 +0000159#define is_digit(c) ((c)>='0' && (c)<='9')
Eric Andersen2870d962001-07-02 17:27:21 +0000160#define is_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalpha((unsigned char) (c))))
161#define is_in_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalnum((unsigned char) (c))))
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000162
163/*
164 * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
165 * (assuming ascii char codes, as the original implementation did)
166 */
167#define is_special(c) \
168 ( (((unsigned int)c) - 33 < 32) \
169 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
170
Eric Andersen2870d962001-07-02 17:27:21 +0000171#define digit_val(c) ((c) - '0')
Eric Andersencb57d552001-06-28 07:25:16 +0000172
173
Eric Andersen2870d962001-07-02 17:27:21 +0000174#define S_DFL 1 /* default signal handling (SIG_DFL) */
175#define S_CATCH 2 /* signal is caught */
176#define S_IGN 3 /* signal is ignored (SIG_IGN) */
177#define S_HARD_IGN 4 /* signal is ignored permenantly */
178#define S_RESET 5 /* temporary - to reset a hard ignored sig */
Eric Andersencb57d552001-06-28 07:25:16 +0000179
180
Eric Andersen2870d962001-07-02 17:27:21 +0000181/* variable substitution byte (follows CTLVAR) */
182#define VSTYPE 0x0f /* type of variable substitution */
183#define VSNUL 0x10 /* colon--treat the empty string as unset */
184#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
Eric Andersencb57d552001-06-28 07:25:16 +0000185
Eric Andersen2870d962001-07-02 17:27:21 +0000186/* values of VSTYPE field */
187#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
188#define VSMINUS 0x2 /* ${var-text} */
189#define VSPLUS 0x3 /* ${var+text} */
190#define VSQUESTION 0x4 /* ${var?message} */
191#define VSASSIGN 0x5 /* ${var=text} */
192#define VSTRIMLEFT 0x6 /* ${var#pattern} */
193#define VSTRIMLEFTMAX 0x7 /* ${var##pattern} */
194#define VSTRIMRIGHT 0x8 /* ${var%pattern} */
195#define VSTRIMRIGHTMAX 0x9 /* ${var%%pattern} */
196#define VSLENGTH 0xa /* ${#var} */
Eric Andersencb57d552001-06-28 07:25:16 +0000197
Eric Andersen2870d962001-07-02 17:27:21 +0000198/* flags passed to redirect */
199#define REDIR_PUSH 01 /* save previous values of file descriptors */
Eric Andersen3102ac42001-07-06 04:26:23 +0000200#define REDIR_BACKQ 02 /* save the command output to pipe */
Eric Andersencb57d552001-06-28 07:25:16 +0000201
Eric Andersen2870d962001-07-02 17:27:21 +0000202/*
203 * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
204 * so we use _setjmp instead.
205 */
206
Eric Andersen62483552001-07-10 06:09:16 +0000207#if defined(BSD)
Eric Andersen2870d962001-07-02 17:27:21 +0000208#define setjmp(jmploc) _setjmp(jmploc)
209#define longjmp(jmploc, val) _longjmp(jmploc, val)
210#endif
211
212/*
213 * Most machines require the value returned from malloc to be aligned
214 * in some way. The following macro will get this right on many machines.
215 */
216
217#ifndef ALIGN
218union align {
219 int i;
220 char *cp;
221};
222
223#define ALIGN(nbytes) (((nbytes) + sizeof(union align) - 1) & ~(sizeof(union align) - 1))
224#endif
225
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000226#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +0000227#include <locale.h>
228static void change_lc_all(const char *value);
229static void change_lc_ctype(const char *value);
230#endif
231
232/*
233 * These macros allow the user to suspend the handling of interrupt signals
234 * over a period of time. This is similar to SIGHOLD to or sigblock, but
235 * much more efficient and portable. (But hacking the kernel is so much
236 * more fun than worrying about efficiency and portability. :-))
237 */
238
239static void onint (void);
240static volatile int suppressint;
241static volatile int intpending;
242
243#define INTOFF suppressint++
Eric Andersend35c5df2002-01-09 15:37:36 +0000244#ifndef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Eric Andersen2870d962001-07-02 17:27:21 +0000245#define INTON { if (--suppressint == 0 && intpending) onint(); }
Eric Andersen3102ac42001-07-06 04:26:23 +0000246#define FORCEINTON {suppressint = 0; if (intpending) onint();}
Eric Andersen2870d962001-07-02 17:27:21 +0000247#else
248static void __inton (void);
Eric Andersen3102ac42001-07-06 04:26:23 +0000249static void forceinton (void);
Eric Andersen2870d962001-07-02 17:27:21 +0000250#define INTON __inton()
Eric Andersen3102ac42001-07-06 04:26:23 +0000251#define FORCEINTON forceinton()
Eric Andersen2870d962001-07-02 17:27:21 +0000252#endif
Eric Andersen3102ac42001-07-06 04:26:23 +0000253
Eric Andersen2870d962001-07-02 17:27:21 +0000254#define CLEAR_PENDING_INT intpending = 0
255#define int_pending() intpending
256
257
258typedef void *pointer;
259#ifndef NULL
260#define NULL (void *)0
261#endif
262
Eric Andersen2870d962001-07-02 17:27:21 +0000263static pointer stalloc (int);
264static void stunalloc (pointer);
265static void ungrabstackstr (char *, char *);
266static char * growstackstr(void);
Eric Andersen3102ac42001-07-06 04:26:23 +0000267static char * makestrspace(size_t newlen);
Eric Andersen2870d962001-07-02 17:27:21 +0000268static char *sstrdup (const char *);
269
270/*
271 * Parse trees for commands are allocated in lifo order, so we use a stack
272 * to make this more efficient, and also to avoid all sorts of exception
273 * handling code to handle interrupts in the middle of a parse.
274 *
275 * The size 504 was chosen because the Ultrix malloc handles that size
276 * well.
277 */
278
279#define MINSIZE 504 /* minimum size of a block */
280
281
282struct stack_block {
283 struct stack_block *prev;
284 char space[MINSIZE];
285};
286
287static struct stack_block stackbase;
288static struct stack_block *stackp = &stackbase;
289static struct stackmark *markp;
290static char *stacknxt = stackbase.space;
291static int stacknleft = MINSIZE;
292
293
294#define equal(s1, s2) (strcmp(s1, s2) == 0)
295
296#define stackblock() stacknxt
297#define stackblocksize() stacknleft
298#define STARTSTACKSTR(p) p = stackblock(), sstrnleft = stackblocksize()
Eric Andersen3102ac42001-07-06 04:26:23 +0000299
Eric Andersen2870d962001-07-02 17:27:21 +0000300#define STPUTC(c, p) (--sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(), *p++ = (c)))
301#define CHECKSTRSPACE(n, p) { if (sstrnleft < n) p = makestrspace(n); }
Eric Andersen2870d962001-07-02 17:27:21 +0000302#define STACKSTRNUL(p) (sstrnleft == 0? (p = growstackstr(), *p = '\0') : (*p = '\0'))
Eric Andersen3102ac42001-07-06 04:26:23 +0000303
304
305#define USTPUTC(c, p) (--sstrnleft, *p++ = (c))
Eric Andersen2870d962001-07-02 17:27:21 +0000306#define STUNPUTC(p) (++sstrnleft, --p)
307#define STTOPC(p) p[-1]
308#define STADJUST(amount, p) (p += (amount), sstrnleft -= (amount))
309#define grabstackstr(p) stalloc(stackblocksize() - sstrnleft)
310
Eric Andersen2870d962001-07-02 17:27:21 +0000311
Eric Andersen2870d962001-07-02 17:27:21 +0000312
313#ifdef DEBUG
314#define TRACE(param) trace param
Eric Andersen69a20f02001-10-31 10:40:37 +0000315typedef union node unode;
Eric Andersen2870d962001-07-02 17:27:21 +0000316static void trace (const char *, ...);
317static void trargs (char **);
Eric Andersen69a20f02001-10-31 10:40:37 +0000318static void showtree (unode *);
Eric Andersen2870d962001-07-02 17:27:21 +0000319static void trputc (int);
320static void trputs (const char *);
321static void opentrace (void);
322#else
323#define TRACE(param)
324#endif
325
326#define NSEMI 0
327#define NCMD 1
328#define NPIPE 2
329#define NREDIR 3
330#define NBACKGND 4
331#define NSUBSHELL 5
332#define NAND 6
333#define NOR 7
334#define NIF 8
335#define NWHILE 9
336#define NUNTIL 10
337#define NFOR 11
338#define NCASE 12
339#define NCLIST 13
340#define NDEFUN 14
341#define NARG 15
342#define NTO 16
343#define NFROM 17
344#define NFROMTO 18
345#define NAPPEND 19
346#define NTOOV 20
347#define NTOFD 21
348#define NFROMFD 22
349#define NHERE 23
350#define NXHERE 24
351#define NNOT 25
352
353/*
354 * expandarg() flags
355 */
356#define EXP_FULL 0x1 /* perform word splitting & file globbing */
357#define EXP_TILDE 0x2 /* do normal tilde expansion */
358#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
359#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
360#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
361#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
362
363
364#define NOPTS 16
365
366static char optet_vals[NOPTS];
367
368static const char * const optlist[NOPTS] = {
369 "e" "errexit",
370 "f" "noglob",
371 "I" "ignoreeof",
372 "i" "interactive",
373 "m" "monitor",
374 "n" "noexec",
375 "s" "stdin",
376 "x" "xtrace",
377 "v" "verbose",
378 "V" "vi",
379 "E" "emacs",
380 "C" "noclobber",
381 "a" "allexport",
382 "b" "notify",
383 "u" "nounset",
384 "q" "quietprofile"
385};
386
387#define optent_name(optent) (optent+1)
388#define optent_letter(optent) optent[0]
389#define optent_val(optent) optet_vals[optent]
390
391#define eflag optent_val(0)
392#define fflag optent_val(1)
393#define Iflag optent_val(2)
394#define iflag optent_val(3)
395#define mflag optent_val(4)
396#define nflag optent_val(5)
397#define sflag optent_val(6)
398#define xflag optent_val(7)
399#define vflag optent_val(8)
400#define Vflag optent_val(9)
401#define Eflag optent_val(10)
402#define Cflag optent_val(11)
403#define aflag optent_val(12)
404#define bflag optent_val(13)
405#define uflag optent_val(14)
406#define qflag optent_val(15)
407
408
409/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
410#define FORK_FG 0
411#define FORK_BG 1
412#define FORK_NOJOB 2
413
414
415struct nbinary {
416 int type;
417 union node *ch1;
418 union node *ch2;
419};
420
421
422struct ncmd {
423 int type;
424 int backgnd;
425 union node *assign;
426 union node *args;
427 union node *redirect;
428};
429
430
431struct npipe {
432 int type;
433 int backgnd;
434 struct nodelist *cmdlist;
435};
436
437
438struct nredir {
439 int type;
440 union node *n;
441 union node *redirect;
442};
443
444
445struct nif {
446 int type;
447 union node *test;
448 union node *ifpart;
449 union node *elsepart;
450};
451
452
453struct nfor {
454 int type;
455 union node *args;
456 union node *body;
457 char *var;
458};
459
460
461struct ncase {
462 int type;
463 union node *expr;
464 union node *cases;
465};
466
467
468struct nclist {
469 int type;
470 union node *next;
471 union node *pattern;
472 union node *body;
473};
474
475
476struct narg {
477 int type;
478 union node *next;
479 char *text;
480 struct nodelist *backquote;
481};
482
483
484struct nfile {
485 int type;
486 union node *next;
487 int fd;
488 union node *fname;
489 char *expfname;
490};
491
492
493struct ndup {
494 int type;
495 union node *next;
496 int fd;
497 int dupfd;
498 union node *vname;
499};
500
501
502struct nhere {
503 int type;
504 union node *next;
505 int fd;
506 union node *doc;
507};
508
509
510struct nnot {
511 int type;
512 union node *com;
513};
514
515
516union node {
517 int type;
518 struct nbinary nbinary;
519 struct ncmd ncmd;
520 struct npipe npipe;
521 struct nredir nredir;
522 struct nif nif;
523 struct nfor nfor;
524 struct ncase ncase;
525 struct nclist nclist;
526 struct narg narg;
527 struct nfile nfile;
528 struct ndup ndup;
529 struct nhere nhere;
530 struct nnot nnot;
531};
532
533
534struct nodelist {
535 struct nodelist *next;
536 union node *n;
537};
538
539struct backcmd { /* result of evalbackcmd */
540 int fd; /* file descriptor to read from */
541 char *buf; /* buffer */
542 int nleft; /* number of chars in buffer */
543 struct job *jp; /* job structure for command */
544};
545
546struct cmdentry {
547 int cmdtype;
548 union param {
549 int index;
550 union node *func;
551 const struct builtincmd *cmd;
552 } u;
553};
554
555struct strlist {
556 struct strlist *next;
557 char *text;
558};
559
560
561struct arglist {
562 struct strlist *list;
563 struct strlist **lastp;
564};
565
566struct strpush {
567 struct strpush *prev; /* preceding string on stack */
568 char *prevstring;
569 int prevnleft;
Eric Andersend35c5df2002-01-09 15:37:36 +0000570#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +0000571 struct alias *ap; /* if push was associated with an alias */
572#endif
573 char *string; /* remember the string since it may change */
574};
575
576struct parsefile {
577 struct parsefile *prev; /* preceding file on stack */
578 int linno; /* current line */
579 int fd; /* file descriptor (or -1 if string) */
580 int nleft; /* number of chars left in this line */
581 int lleft; /* number of chars left in this buffer */
582 char *nextc; /* next char in buffer */
583 char *buf; /* input buffer */
584 struct strpush *strpush; /* for pushing strings at this level */
585 struct strpush basestrpush; /* so pushing one is fast */
586};
587
588struct stackmark {
589 struct stack_block *stackp;
590 char *stacknxt;
591 int stacknleft;
592 struct stackmark *marknext;
593};
594
595struct shparam {
596 int nparam; /* # of positional parameters (without $0) */
597 unsigned char malloc; /* if parameter list dynamically allocated */
598 char **p; /* parameter list */
599 int optind; /* next parameter to be processed by getopts */
600 int optoff; /* used by getopts */
601};
602
Eric Andersen62483552001-07-10 06:09:16 +0000603/*
604 * When commands are first encountered, they are entered in a hash table.
605 * This ensures that a full path search will not have to be done for them
606 * on each invocation.
607 *
608 * We should investigate converting to a linear search, even though that
609 * would make the command name "hash" a misnomer.
610 */
611#define CMDTABLESIZE 31 /* should be prime */
612#define ARB 1 /* actual size determined at run time */
613
614
615
616struct tblentry {
617 struct tblentry *next; /* next entry in hash chain */
618 union param param; /* definition of builtin function */
619 short cmdtype; /* index identifying command */
620 char rehash; /* if set, cd done since entry created */
621 char cmdname[ARB]; /* name of command */
622};
623
624
625static struct tblentry *cmdtable[CMDTABLESIZE];
626static int builtinloc = -1; /* index in path of %builtin, or -1 */
627static int exerrno = 0; /* Last exec error */
628
629
630static void tryexec (char *, char **, char **);
631static void printentry (struct tblentry *, int);
632static void clearcmdentry (int);
633static struct tblentry *cmdlookup (const char *, int);
634static void delete_cmd_entry (void);
635static int path_change (const char *, int *);
636
637
Eric Andersen2870d962001-07-02 17:27:21 +0000638static void flushall (void);
Eric Andersen3102ac42001-07-06 04:26:23 +0000639static void out2fmt (const char *, ...)
640 __attribute__((__format__(__printf__,1,2)));
Eric Andersen2870d962001-07-02 17:27:21 +0000641static int xwrite (int, const char *, int);
Eric Andersen2870d962001-07-02 17:27:21 +0000642
Manuel Novoa III c639a352001-08-12 17:32:56 +0000643static inline void outstr (const char *p, FILE *file) { fputs(p, file); }
Eric Andersen3102ac42001-07-06 04:26:23 +0000644static void out1str(const char *p) { outstr(p, stdout); }
645static void out2str(const char *p) { outstr(p, stderr); }
Eric Andersen2870d962001-07-02 17:27:21 +0000646
Eric Andersend35c5df2002-01-09 15:37:36 +0000647#ifndef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Eric Andersen3102ac42001-07-06 04:26:23 +0000648#define out2c(c) putc((c), stderr)
Eric Andersen62483552001-07-10 06:09:16 +0000649#else
650static void out2c(int c) { putc(c, stderr); }
651#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000652
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000653
Eric Andersend35c5df2002-01-09 15:37:36 +0000654#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000655#define USE_SIT_FUNCTION
656#endif
657
658/* number syntax index */
659#define BASESYNTAX 0 /* not in quotes */
660#define DQSYNTAX 1 /* in double quotes */
661#define SQSYNTAX 2 /* in single quotes */
662#define ARISYNTAX 3 /* in arithmetic */
663
664static const char S_I_T[][4] = {
665 /* 0 */ { CSPCL, CIGN, CIGN, CIGN }, /* PEOA */
666 /* 1 */ { CSPCL, CWORD, CWORD, CWORD }, /* ' ' */
667 /* 2 */ { CNL, CNL, CNL, CNL }, /* \n */
668 /* 3 */ { CWORD, CCTL, CCTL, CWORD }, /* !*-/:=?[]~ */
669 /* 4 */ { CDQUOTE, CENDQUOTE, CWORD, CDQUOTE }, /* '"' */
670 /* 5 */ { CVAR, CVAR, CWORD, CVAR }, /* $ */
671 /* 6 */ { CSQUOTE, CWORD, CENDQUOTE, CSQUOTE }, /* "'" */
672 /* 7 */ { CSPCL, CWORD, CWORD, CLP }, /* ( */
673 /* 8 */ { CSPCL, CWORD, CWORD, CRP }, /* ) */
674 /* 9 */ { CBACK, CBACK, CCTL, CBACK }, /* \ */
675 /* 10 */ { CBQUOTE, CBQUOTE, CWORD, CBQUOTE }, /* ` */
676 /* 11 */ { CENDVAR, CENDVAR, CWORD, CENDVAR }, /* } */
677#ifndef USE_SIT_FUNCTION
678 /* 12 */ { CENDFILE, CENDFILE, CENDFILE, CENDFILE }, /* PEOF */
679 /* 13 */ { CWORD, CWORD, CWORD, CWORD }, /* 0-9A-Za-z */
680 /* 14 */ { CCTL, CCTL, CCTL, CCTL } /* CTLESC ... */
681#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000682};
683
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000684#ifdef USE_SIT_FUNCTION
685
686#define U_C(c) ((unsigned char)(c))
687
688static int SIT(int c, int syntax)
689{
690 static const char spec_symbls[]="\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
691 static const char syntax_index_table [] = {
692 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
693 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
694 3, 1, 3, 3, 9, 3,10, 1, /* "=>?[\\]`|" */
695 11,3 }; /* "}~" */
696 const char *s;
697 int indx;
698
699 if(c==PEOF) /* 2^8+2 */
700 return CENDFILE;
701 if(c==PEOA) /* 2^8+1 */
702 indx = 0;
703 else if(U_C(c)>=U_C(CTLESC) && U_C(c)<=U_C(CTLQUOTEMARK))
704 return CCTL;
705 else {
706 s = strchr(spec_symbls, c);
707 if(s==0)
708 return CWORD;
709 indx = syntax_index_table[(s-spec_symbls)];
710 }
711 return S_I_T[indx][syntax];
712}
713
714#else /* USE_SIT_FUNCTION */
715
716#define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
717
718#define CSPCL_CIGN_CIGN_CIGN 0
719#define CSPCL_CWORD_CWORD_CWORD 1
720#define CNL_CNL_CNL_CNL 2
721#define CWORD_CCTL_CCTL_CWORD 3
722#define CDQUOTE_CENDQUOTE_CWORD_CDQUOTE 4
723#define CVAR_CVAR_CWORD_CVAR 5
724#define CSQUOTE_CWORD_CENDQUOTE_CSQUOTE 6
725#define CSPCL_CWORD_CWORD_CLP 7
726#define CSPCL_CWORD_CWORD_CRP 8
727#define CBACK_CBACK_CCTL_CBACK 9
728#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
729#define CENDVAR_CENDVAR_CWORD_CENDVAR 11
730#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
731#define CWORD_CWORD_CWORD_CWORD 13
732#define CCTL_CCTL_CCTL_CCTL 14
733
734static const char syntax_index_table[258] = {
735 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
736 /* 0 -130 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
737 /* 1 -129 PEOA */ CSPCL_CIGN_CIGN_CIGN,
738 /* 2 -128 0xff */ CWORD_CWORD_CWORD_CWORD,
739 /* 3 -127 */ CCTL_CCTL_CCTL_CCTL, /* CTLQUOTEMARK */
740 /* 4 -126 */ CCTL_CCTL_CCTL_CCTL,
741 /* 5 -125 */ CCTL_CCTL_CCTL_CCTL,
742 /* 6 -124 */ CCTL_CCTL_CCTL_CCTL,
743 /* 7 -123 */ CCTL_CCTL_CCTL_CCTL,
744 /* 8 -122 */ CCTL_CCTL_CCTL_CCTL,
745 /* 9 -121 */ CCTL_CCTL_CCTL_CCTL,
746 /* 10 -120 */ CCTL_CCTL_CCTL_CCTL, /* CTLESC */
747 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
748 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
749 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
750 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
751 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
752 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
753 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
754 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
755 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
756 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
757 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
758 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
759 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
760 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
761 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
762 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
763 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
764 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
765 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
766 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
767 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
768 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
769 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
770 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
771 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
772 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
773 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
774 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
775 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
776 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
777 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
778 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
779 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
780 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
781 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
782 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
783 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
784 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
785 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
786 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
787 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
788 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
789 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
790 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
791 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
792 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
793 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
794 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
795 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
796 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
797 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
798 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
799 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
800 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
801 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
802 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
803 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
804 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
805 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
806 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
807 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
808 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
809 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
810 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
811 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
812 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
813 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
814 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
815 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
816 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
817 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
818 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
819 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
820 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
821 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
822 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
823 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
824 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
825 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
826 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
827 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
828 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
829 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
830 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
831 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
832 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
833 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
834 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
835 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
836 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
837 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
838 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
839 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
840 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
841 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
842 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
843 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
844 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
845 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
846 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
847 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
848 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
849 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
850 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
851 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
852 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
853 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
854 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
855 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
856 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
857 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
858 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
859 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
860 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
861 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
862 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
863 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
864 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
865 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
866 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
867 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
868 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
869 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
870 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
871 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
872 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
873 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
874 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
875 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
876 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
877 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
878 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
879 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
880 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
881 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
882 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
883 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
884 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
885 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
886 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
887 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
888 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
889 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
890 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
891 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
892 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
893 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
894 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
895 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
896 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
897 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
898 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
899 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
900 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CDQUOTE,
901 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
902 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
903 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
904 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
905 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CSQUOTE,
906 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
907 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
908 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
909 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
910 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
911 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
912 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
913 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
914 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
915 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
916 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
917 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
918 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
919 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
920 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
921 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
922 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
923 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
924 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
925 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
926 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
927 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
928 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
929 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
930 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
931 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
932 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
933 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
934 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
935 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
936 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
937 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
938 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
939 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
940 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
941 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
942 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
943 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
944 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
945 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
946 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
947 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
948 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
949 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
950 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
951 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
952 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
953 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
954 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
955 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
956 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
957 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
958 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
959 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
960 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
961 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
962 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
963 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
964 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
965 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
966 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
967 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
968 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
969 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
970 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
971 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
972 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
973 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
974 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
975 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
976 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
977 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
978 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
979 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
980 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
981 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
982 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
983 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
984 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
985 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
986 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
987 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
988 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
989 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
990 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
991 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
992 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
993 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
Eric Andersen2870d962001-07-02 17:27:21 +0000994};
995
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000996#endif /* USE_SIT_FUNCTION */
Eric Andersen2870d962001-07-02 17:27:21 +0000997
Eric Andersen2870d962001-07-02 17:27:21 +0000998
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000999/* first char is indicating which tokens mark the end of a list */
1000static const char *const tokname_array[] = {
1001 "\1end of file",
1002 "\0newline",
1003 "\0redirection",
1004 "\0word",
1005 "\0assignment",
1006 "\0;",
1007 "\0&",
1008 "\0&&",
1009 "\0||",
1010 "\0|",
1011 "\0(",
1012 "\1)",
1013 "\1;;",
1014 "\1`",
Eric Andersen2870d962001-07-02 17:27:21 +00001015#define KWDOFFSET 14
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001016 /* the following are keywords */
1017 "\0!",
1018 "\0case",
1019 "\1do",
1020 "\1done",
1021 "\1elif",
1022 "\1else",
1023 "\1esac",
1024 "\1fi",
1025 "\0for",
1026 "\0if",
1027 "\0in",
1028 "\1then",
1029 "\0until",
1030 "\0while",
1031 "\0{",
1032 "\1}",
Eric Andersen2870d962001-07-02 17:27:21 +00001033};
1034
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001035static const char *tokname(int tok)
1036{
1037 static char buf[16];
1038
1039 if(tok>=TSEMI)
1040 buf[0] = '"';
1041 sprintf(buf+(tok>=TSEMI), "%s%c",
1042 tokname_array[tok]+1, (tok>=TSEMI ? '"' : 0));
1043 return buf;
1044}
Eric Andersen2870d962001-07-02 17:27:21 +00001045
1046static int plinno = 1; /* input line number */
1047
1048static int parselleft; /* copy of parsefile->lleft */
1049
1050static struct parsefile basepf; /* top level input file */
1051static char basebuf[BUFSIZ]; /* buffer for top level input file */
1052static struct parsefile *parsefile = &basepf; /* current input file */
1053
1054/*
1055 * NEOF is returned by parsecmd when it encounters an end of file. It
1056 * must be distinct from NULL, so we use the address of a variable that
1057 * happens to be handy.
1058 */
1059
1060static int tokpushback; /* last token pushed back */
1061#define NEOF ((union node *)&tokpushback)
1062static int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */
1063
1064
1065static void error (const char *, ...) __attribute__((__noreturn__));
1066static void exerror (int, const char *, ...) __attribute__((__noreturn__));
1067static void shellexec (char **, char **, const char *, int)
1068 __attribute__((noreturn));
1069static void exitshell (int) __attribute__((noreturn));
1070
1071static int goodname(const char *);
1072static void ignoresig (int);
1073static void onsig (int);
1074static void dotrap (void);
1075static int decode_signal (const char *, int);
1076
1077static void shprocvar(void);
1078static void deletefuncs(void);
1079static void setparam (char **);
1080static void freeparam (volatile struct shparam *);
1081
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001082static void find_command (const char *, struct cmdentry *, int, const char *);
1083
1084static inline void hashcd (void);
1085
Eric Andersen2870d962001-07-02 17:27:21 +00001086/* reasons for skipping commands (see comment on breakcmd routine) */
1087#define SKIPBREAK 1
1088#define SKIPCONT 2
1089#define SKIPFUNC 3
1090#define SKIPFILE 4
1091
1092/* values of cmdtype */
1093#define CMDUNKNOWN -1 /* no entry in table for command */
1094#define CMDNORMAL 0 /* command is an executable program */
1095#define CMDBUILTIN 1 /* command is a shell builtin */
1096#define CMDFUNCTION 2 /* command is a shell function */
1097
1098#define DO_ERR 1 /* find_command prints errors */
1099#define DO_ABS 2 /* find_command checks absolute paths */
1100#define DO_NOFUN 4 /* find_command ignores functions */
1101#define DO_BRUTE 8 /* find_command ignores hash table */
1102
1103/*
1104 * Shell variables.
1105 */
1106
1107/* flags */
1108#define VEXPORT 0x01 /* variable is exported */
1109#define VREADONLY 0x02 /* variable cannot be modified */
1110#define VSTRFIXED 0x04 /* variable struct is staticly allocated */
1111#define VTEXTFIXED 0x08 /* text is staticly allocated */
1112#define VSTACK 0x10 /* text is allocated on the stack */
1113#define VUNSET 0x20 /* the variable is not set */
1114#define VNOFUNC 0x40 /* don't call the callback function */
1115
1116
1117struct var {
1118 struct var *next; /* next entry in hash list */
1119 int flags; /* flags are defined above */
1120 char *text; /* name=value */
1121 void (*func) (const char *);
1122 /* function to be called when */
1123 /* the variable gets set/unset */
1124};
1125
1126struct localvar {
1127 struct localvar *next; /* next local variable in list */
1128 struct var *vp; /* the variable that was made local */
1129 int flags; /* saved flags */
1130 char *text; /* saved text */
1131};
1132
1133
Eric Andersen62483552001-07-10 06:09:16 +00001134#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00001135#define rmescapes(p) _rmescapes((p), 0)
1136static char *_rmescapes (char *, int);
1137#else
1138static void rmescapes (char *);
1139#endif
1140
1141static int casematch (union node *, const char *);
1142static void clearredir(void);
1143static void popstring(void);
1144static void readcmdfile (const char *);
1145
1146static int number (const char *);
1147static int is_number (const char *, int *num);
1148static char *single_quote (const char *);
1149static int nextopt (const char *);
1150
1151static void redirect (union node *, int);
1152static void popredir (void);
1153static int dup_as_newfd (int, int);
1154
1155static void changepath(const char *newval);
1156static void getoptsreset(const char *value);
1157
1158
1159static int parsenleft; /* copy of parsefile->nleft */
1160static char *parsenextc; /* copy of parsefile->nextc */
1161static int rootpid; /* pid of main shell */
1162static int rootshell; /* true if we aren't a child of the main shell */
1163
1164static const char spcstr[] = " ";
1165static const char snlfmt[] = "%s\n";
1166
1167static int sstrnleft;
1168static int herefd = -1;
1169
1170static struct localvar *localvars;
1171
1172static struct var vifs;
1173static struct var vmail;
1174static struct var vmpath;
1175static struct var vpath;
1176static struct var vps1;
1177static struct var vps2;
1178static struct var voptind;
Eric Andersenbdfd0d72001-10-24 05:00:29 +00001179#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00001180static struct var vlc_all;
1181static struct var vlc_ctype;
1182#endif
1183
1184struct varinit {
1185 struct var *var;
1186 int flags;
1187 const char *text;
1188 void (*func) (const char *);
1189};
1190
1191static const char defpathvar[] =
1192 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
1193#define defpath (defpathvar + 5)
1194
1195#ifdef IFS_BROKEN
1196static const char defifsvar[] = "IFS= \t\n";
1197#define defifs (defifsvar + 4)
1198#else
1199static const char defifs[] = " \t\n";
1200#endif
1201
1202static const struct varinit varinit[] = {
1203#ifdef IFS_BROKEN
1204 { &vifs, VSTRFIXED|VTEXTFIXED, defifsvar,
1205#else
1206 { &vifs, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS=",
1207#endif
1208 NULL },
1209 { &vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=",
1210 NULL },
1211 { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=",
1212 NULL },
1213 { &vpath, VSTRFIXED|VTEXTFIXED, defpathvar,
1214 changepath },
Tim Riker497a8852002-04-13 05:37:10 +00001215#if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1216 { &vps1, VSTRFIXED|VTEXTFIXED, "PS1=\\w \\$ ",
1217 NULL },
1218#endif /* else vps1 depends on uid */
Eric Andersen2870d962001-07-02 17:27:21 +00001219 { &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ",
1220 NULL },
1221 { &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1",
1222 getoptsreset },
Eric Andersenbdfd0d72001-10-24 05:00:29 +00001223#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00001224 { &vlc_all, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL=",
1225 change_lc_all },
1226 { &vlc_ctype, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE=",
1227 change_lc_ctype },
1228#endif
1229 { NULL, 0, NULL,
1230 NULL }
1231};
1232
1233#define VTABSIZE 39
1234
1235static struct var *vartab[VTABSIZE];
1236
1237/*
1238 * The following macros access the values of the above variables.
1239 * They have to skip over the name. They return the null string
1240 * for unset variables.
1241 */
1242
1243#define ifsval() (vifs.text + 4)
1244#define ifsset() ((vifs.flags & VUNSET) == 0)
1245#define mailval() (vmail.text + 5)
1246#define mpathval() (vmpath.text + 9)
1247#define pathval() (vpath.text + 5)
1248#define ps1val() (vps1.text + 4)
1249#define ps2val() (vps2.text + 4)
1250#define optindval() (voptind.text + 7)
1251
1252#define mpathset() ((vmpath.flags & VUNSET) == 0)
1253
1254static void initvar (void);
1255static void setvar (const char *, const char *, int);
1256static void setvareq (char *, int);
1257static void listsetvar (struct strlist *);
Eric Andersen62483552001-07-10 06:09:16 +00001258static const char *lookupvar (const char *);
1259static const char *bltinlookup (const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001260static char **environment (void);
1261static int showvarscmd (int, char **);
1262static void mklocal (char *);
1263static void poplocalvars (void);
1264static int unsetvar (const char *);
1265static int varequal (const char *, const char *);
1266
1267
1268static char *arg0; /* value of $0 */
1269static struct shparam shellparam; /* current positional parameters */
1270static char **argptr; /* argument list for builtin commands */
1271static char *optionarg; /* set by nextopt (like getopt) */
1272static char *optptr; /* used by nextopt */
1273static char *minusc; /* argument to -c option */
1274
1275
Eric Andersend35c5df2002-01-09 15:37:36 +00001276#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00001277
1278#define ALIASINUSE 1
1279#define ALIASDEAD 2
1280
Eric Andersen3102ac42001-07-06 04:26:23 +00001281#define ATABSIZE 39
1282
Eric Andersen2870d962001-07-02 17:27:21 +00001283struct alias {
1284 struct alias *next;
1285 char *name;
1286 char *val;
1287 int flag;
1288};
1289
1290static struct alias *atab[ATABSIZE];
1291
1292static void setalias (char *, char *);
1293static struct alias **hashalias (const char *);
1294static struct alias *freealias (struct alias *);
1295static struct alias **__lookupalias (const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00001296
1297static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001298setalias(char *name, char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00001299{
1300 struct alias *ap, **app;
1301
1302 app = __lookupalias(name);
1303 ap = *app;
1304 INTOFF;
1305 if (ap) {
1306 if (!(ap->flag & ALIASINUSE)) {
Aaron Lehmann49c024a2002-08-02 06:39:47 +00001307 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00001308 }
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001309 ap->val = xstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00001310 ap->flag &= ~ALIASDEAD;
1311 } else {
1312 /* not found */
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001313 ap = xmalloc(sizeof (struct alias));
1314 ap->name = xstrdup(name);
1315 ap->val = xstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00001316 ap->flag = 0;
1317 ap->next = 0;
1318 *app = ap;
1319 }
1320 INTON;
1321}
1322
1323static int
Eric Andersen2870d962001-07-02 17:27:21 +00001324unalias(char *name)
1325{
Eric Andersencb57d552001-06-28 07:25:16 +00001326 struct alias **app;
1327
1328 app = __lookupalias(name);
1329
1330 if (*app) {
1331 INTOFF;
1332 *app = freealias(*app);
1333 INTON;
1334 return (0);
1335 }
1336
1337 return (1);
1338}
1339
Eric Andersencb57d552001-06-28 07:25:16 +00001340static void
Eric Andersen2870d962001-07-02 17:27:21 +00001341rmaliases(void)
1342{
Eric Andersencb57d552001-06-28 07:25:16 +00001343 struct alias *ap, **app;
1344 int i;
1345
1346 INTOFF;
1347 for (i = 0; i < ATABSIZE; i++) {
1348 app = &atab[i];
1349 for (ap = *app; ap; ap = *app) {
1350 *app = freealias(*app);
1351 if (ap == *app) {
1352 app = &ap->next;
1353 }
1354 }
1355 }
1356 INTON;
1357}
1358
Eric Andersen2870d962001-07-02 17:27:21 +00001359static void
1360printalias(const struct alias *ap) {
1361 char *p;
1362
1363 p = single_quote(ap->val);
Eric Andersen62483552001-07-10 06:09:16 +00001364 printf("alias %s=%s\n", ap->name, p);
Eric Andersen2870d962001-07-02 17:27:21 +00001365 stunalloc(p);
1366}
1367
Eric Andersencb57d552001-06-28 07:25:16 +00001368
1369/*
1370 * TODO - sort output
1371 */
1372static int
Eric Andersen2870d962001-07-02 17:27:21 +00001373aliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001374{
1375 char *n, *v;
1376 int ret = 0;
1377 struct alias *ap;
1378
1379 if (argc == 1) {
1380 int i;
1381
1382 for (i = 0; i < ATABSIZE; i++)
1383 for (ap = atab[i]; ap; ap = ap->next) {
1384 printalias(ap);
1385 }
1386 return (0);
1387 }
1388 while ((n = *++argv) != NULL) {
1389 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
1390 if ((ap = *__lookupalias(n)) == NULL) {
Eric Andersen3102ac42001-07-06 04:26:23 +00001391 out2fmt("%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00001392 ret = 1;
1393 } else
1394 printalias(ap);
1395 }
1396 else {
1397 *v++ = '\0';
1398 setalias(n, v);
1399 }
1400 }
1401
1402 return (ret);
1403}
1404
1405static int
Eric Andersen2870d962001-07-02 17:27:21 +00001406unaliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001407{
1408 int i;
1409
1410 while ((i = nextopt("a")) != '\0') {
1411 if (i == 'a') {
1412 rmaliases();
1413 return (0);
1414 }
1415 }
1416 for (i = 0; *argptr; argptr++) {
1417 if (unalias(*argptr)) {
Eric Andersen3102ac42001-07-06 04:26:23 +00001418 out2fmt("%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00001419 i = 1;
1420 }
1421 }
1422
1423 return (i);
1424}
1425
1426static struct alias **
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001427hashalias(const char *p)
1428{
Eric Andersencb57d552001-06-28 07:25:16 +00001429 unsigned int hashval;
1430
1431 hashval = *p << 4;
1432 while (*p)
1433 hashval+= *p++;
1434 return &atab[hashval % ATABSIZE];
1435}
1436
1437static struct alias *
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001438freealias(struct alias *ap)
1439{
Eric Andersencb57d552001-06-28 07:25:16 +00001440 struct alias *next;
1441
1442 if (ap->flag & ALIASINUSE) {
1443 ap->flag |= ALIASDEAD;
1444 return ap;
1445 }
1446
1447 next = ap->next;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00001448 free(ap->name);
1449 free(ap->val);
1450 free(ap);
Eric Andersencb57d552001-06-28 07:25:16 +00001451 return next;
1452}
1453
Eric Andersencb57d552001-06-28 07:25:16 +00001454
1455static struct alias **
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001456__lookupalias(const char *name)
1457{
Eric Andersencb57d552001-06-28 07:25:16 +00001458 struct alias **app = hashalias(name);
1459
1460 for (; *app; app = &(*app)->next) {
1461 if (equal(name, (*app)->name)) {
1462 break;
1463 }
1464 }
1465
1466 return app;
1467}
Eric Andersen2870d962001-07-02 17:27:21 +00001468#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001469
Eric Andersend35c5df2002-01-09 15:37:36 +00001470#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersen74bcd162001-07-30 21:41:37 +00001471/* The generated file arith.c has been replaced with a custom hand
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001472 * written implementation written by Aaron Lehmann <aaronl@vitelus.com>.
1473 * This is now part of libbb, so that it can be used by all the shells
Eric Andersen74bcd162001-07-30 21:41:37 +00001474 * in busybox. */
Eric Andersen2870d962001-07-02 17:27:21 +00001475static void expari (int);
Eric Andersencb57d552001-06-28 07:25:16 +00001476#endif
1477
Eric Andersen2870d962001-07-02 17:27:21 +00001478static char *trap[NSIG]; /* trap handler commands */
1479static char sigmode[NSIG - 1]; /* current value of signal */
1480static char gotsig[NSIG - 1]; /* indicates specified signal received */
1481static int pendingsigs; /* indicates some signal received */
1482
Eric Andersencb57d552001-06-28 07:25:16 +00001483/*
1484 * This file was generated by the mkbuiltins program.
1485 */
1486
Eric Andersend35c5df2002-01-09 15:37:36 +00001487#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen2870d962001-07-02 17:27:21 +00001488static int bgcmd (int, char **);
1489static int fgcmd (int, char **);
1490static int killcmd (int, char **);
1491#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001492static int bltincmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001493static int cdcmd (int, char **);
1494static int breakcmd (int, char **);
Eric Andersend35c5df2002-01-09 15:37:36 +00001495#ifdef CONFIG_ASH_CMDCMD
Eric Andersen2870d962001-07-02 17:27:21 +00001496static int commandcmd (int, char **);
1497#endif
1498static int dotcmd (int, char **);
1499static int evalcmd (int, char **);
1500static int execcmd (int, char **);
1501static int exitcmd (int, char **);
1502static int exportcmd (int, char **);
1503static int histcmd (int, char **);
1504static int hashcmd (int, char **);
Eric Andersen1c039232001-07-07 00:05:55 +00001505static int helpcmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001506static int jobscmd (int, char **);
1507static int localcmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001508static int pwdcmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001509static int readcmd (int, char **);
1510static int returncmd (int, char **);
1511static int setcmd (int, char **);
1512static int setvarcmd (int, char **);
1513static int shiftcmd (int, char **);
1514static int trapcmd (int, char **);
1515static int umaskcmd (int, char **);
Eric Andersend35c5df2002-01-09 15:37:36 +00001516#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00001517static int aliascmd (int, char **);
1518static int unaliascmd (int, char **);
1519#endif
1520static int unsetcmd (int, char **);
1521static int waitcmd (int, char **);
1522static int ulimitcmd (int, char **);
1523static int timescmd (int, char **);
Eric Andersend35c5df2002-01-09 15:37:36 +00001524#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +00001525static int letcmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001526#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001527static int typecmd (int, char **);
Eric Andersend35c5df2002-01-09 15:37:36 +00001528#ifdef CONFIG_ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00001529static int getoptscmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001530#endif
1531
Eric Andersen69a20f02001-10-31 10:40:37 +00001532#ifndef CONFIG_TRUE
Eric Andersen2870d962001-07-02 17:27:21 +00001533static int true_main (int, char **);
Eric Andersen69a20f02001-10-31 10:40:37 +00001534#endif
1535#ifndef CONFIG_FALSE
Eric Andersen2870d962001-07-02 17:27:21 +00001536static int false_main (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001537#endif
1538
1539static void setpwd (const char *, int);
1540
1541
1542#define BUILTIN_NOSPEC "0"
1543#define BUILTIN_SPECIAL "1"
1544#define BUILTIN_REGULAR "2"
1545#define BUILTIN_ASSIGN "4"
1546#define BUILTIN_SPEC_ASSG "5"
1547#define BUILTIN_REG_ASSG "6"
1548
1549#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1550#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1551#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
1552
1553struct builtincmd {
1554 const char *name;
1555 int (*const builtinfunc) (int, char **);
1556 //unsigned flags;
1557};
1558
Eric Andersencb57d552001-06-28 07:25:16 +00001559
1560/* It is CRUCIAL that this listing be kept in ascii order, otherwise
1561 * the binary search in find_builtin() will stop working. If you value
1562 * your kneecaps, you'll be sure to *make sure* that any changes made
1563 * to this array result in the listing remaining in ascii order. You
1564 * have been warned.
1565 */
1566static const struct builtincmd builtincmds[] = {
Eric Andersen62483552001-07-10 06:09:16 +00001567 { BUILTIN_SPECIAL ".", dotcmd }, /* first, see declare DOTCMD */
Eric Andersen2870d962001-07-02 17:27:21 +00001568 { BUILTIN_SPECIAL ":", true_main },
Eric Andersend35c5df2002-01-09 15:37:36 +00001569#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00001570 { BUILTIN_REG_ASSG "alias", aliascmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001571#endif
Eric Andersend35c5df2002-01-09 15:37:36 +00001572#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen2870d962001-07-02 17:27:21 +00001573 { BUILTIN_REGULAR "bg", bgcmd },
1574#endif
1575 { BUILTIN_SPECIAL "break", breakcmd },
Eric Andersen3102ac42001-07-06 04:26:23 +00001576 { BUILTIN_SPECIAL "builtin", bltincmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001577 { BUILTIN_REGULAR "cd", cdcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001578 { BUILTIN_NOSPEC "chdir", cdcmd },
Eric Andersend35c5df2002-01-09 15:37:36 +00001579#ifdef CONFIG_ASH_CMDCMD
Eric Andersen2870d962001-07-02 17:27:21 +00001580 { BUILTIN_REGULAR "command", commandcmd },
1581#endif
1582 { BUILTIN_SPECIAL "continue", breakcmd },
1583 { BUILTIN_SPECIAL "eval", evalcmd },
1584 { BUILTIN_SPECIAL "exec", execcmd },
1585 { BUILTIN_SPECIAL "exit", exitcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001586 { BUILTIN_SPEC_ASSG "export", exportcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001587 { BUILTIN_REGULAR "false", false_main },
Eric Andersen2870d962001-07-02 17:27:21 +00001588 { BUILTIN_REGULAR "fc", histcmd },
Eric Andersend35c5df2002-01-09 15:37:36 +00001589#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen2870d962001-07-02 17:27:21 +00001590 { BUILTIN_REGULAR "fg", fgcmd },
1591#endif
Eric Andersend35c5df2002-01-09 15:37:36 +00001592#ifdef CONFIG_ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00001593 { BUILTIN_REGULAR "getopts", getoptscmd },
1594#endif
1595 { BUILTIN_NOSPEC "hash", hashcmd },
Eric Andersen1c039232001-07-07 00:05:55 +00001596 { BUILTIN_NOSPEC "help", helpcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001597 { BUILTIN_REGULAR "jobs", jobscmd },
Eric Andersend35c5df2002-01-09 15:37:36 +00001598#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen2870d962001-07-02 17:27:21 +00001599 { BUILTIN_REGULAR "kill", killcmd },
1600#endif
Eric Andersend35c5df2002-01-09 15:37:36 +00001601#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +00001602 { BUILTIN_REGULAR "let", letcmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001603#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001604 { BUILTIN_ASSIGN "local", localcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001605 { BUILTIN_NOSPEC "pwd", pwdcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001606 { BUILTIN_REGULAR "read", readcmd },
1607 { BUILTIN_SPEC_ASSG "readonly", exportcmd },
1608 { BUILTIN_SPECIAL "return", returncmd },
1609 { BUILTIN_SPECIAL "set", setcmd },
1610 { BUILTIN_NOSPEC "setvar", setvarcmd },
1611 { BUILTIN_SPECIAL "shift", shiftcmd },
1612 { BUILTIN_SPECIAL "times", timescmd },
1613 { BUILTIN_SPECIAL "trap", trapcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001614 { BUILTIN_REGULAR "true", true_main },
Eric Andersen2870d962001-07-02 17:27:21 +00001615 { BUILTIN_NOSPEC "type", typecmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001616 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1617 { BUILTIN_REGULAR "umask", umaskcmd },
Eric Andersend35c5df2002-01-09 15:37:36 +00001618#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00001619 { BUILTIN_REGULAR "unalias", unaliascmd },
1620#endif
1621 { BUILTIN_SPECIAL "unset", unsetcmd },
1622 { BUILTIN_REGULAR "wait", waitcmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001623};
1624#define NUMBUILTINS (sizeof (builtincmds) / sizeof (struct builtincmd) )
1625
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001626#define DOTCMD &builtincmds[0]
Eric Andersen2870d962001-07-02 17:27:21 +00001627static struct builtincmd *BLTINCMD;
1628static struct builtincmd *EXECCMD;
1629static struct builtincmd *EVALCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00001630
Eric Andersen2870d962001-07-02 17:27:21 +00001631/* states */
Eric Andersend35c5df2002-01-09 15:37:36 +00001632#define CONFIG_ASH_JOB_CONTROLTOPPED 1 /* all procs are stopped */
Eric Andersen2870d962001-07-02 17:27:21 +00001633#define JOBDONE 2 /* all procs are completed */
Eric Andersencb57d552001-06-28 07:25:16 +00001634
Eric Andersen2870d962001-07-02 17:27:21 +00001635/*
1636 * A job structure contains information about a job. A job is either a
1637 * single process or a set of processes contained in a pipeline. In the
1638 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1639 * array of pids.
1640 */
Eric Andersencb57d552001-06-28 07:25:16 +00001641
Eric Andersen2870d962001-07-02 17:27:21 +00001642struct procstat {
1643 pid_t pid; /* process id */
1644 int status; /* status flags (defined above) */
1645 char *cmd; /* text of command being run */
1646};
Eric Andersencb57d552001-06-28 07:25:16 +00001647
Eric Andersen2870d962001-07-02 17:27:21 +00001648
1649static int job_warning; /* user was warned about stopped jobs */
1650
Eric Andersend35c5df2002-01-09 15:37:36 +00001651#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen2870d962001-07-02 17:27:21 +00001652static void setjobctl(int enable);
1653#else
1654#define setjobctl(on) /* do nothing */
Eric Andersencb57d552001-06-28 07:25:16 +00001655#endif
1656
Eric Andersen2870d962001-07-02 17:27:21 +00001657
1658struct job {
1659 struct procstat ps0; /* status of process */
1660 struct procstat *ps; /* status or processes when more than one */
1661 short nprocs; /* number of processes */
1662 short pgrp; /* process group of this job */
1663 char state; /* true if job is finished */
1664 char used; /* true if this entry is in used */
1665 char changed; /* true if status has changed */
Eric Andersend35c5df2002-01-09 15:37:36 +00001666#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen2870d962001-07-02 17:27:21 +00001667 char jobctl; /* job running under job control */
1668#endif
1669};
1670
1671static struct job *jobtab; /* array of jobs */
1672static int njobs; /* size of array */
1673static int backgndpid = -1; /* pid of last background process */
Eric Andersend35c5df2002-01-09 15:37:36 +00001674#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen2870d962001-07-02 17:27:21 +00001675static int initialpgrp; /* pgrp of shell on invocation */
1676static int curjob; /* current job */
1677static int jobctl;
1678#endif
1679static int intreceived;
1680
Eric Andersen62483552001-07-10 06:09:16 +00001681static struct job *makejob (const union node *, int);
1682static int forkshell (struct job *, const union node *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00001683static int waitforjob (struct job *);
1684
1685static int docd (char *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00001686static void getpwd (void);
1687
1688static char *padvance (const char **, const char *);
1689
1690static char nullstr[1]; /* zero length string */
1691static char *curdir = nullstr; /* current working directory */
Eric Andersen2870d962001-07-02 17:27:21 +00001692
Eric Andersencb57d552001-06-28 07:25:16 +00001693static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001694cdcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001695{
1696 const char *dest;
1697 const char *path;
1698 char *p;
1699 struct stat statb;
1700 int print = 0;
1701
1702 nextopt(nullstr);
1703 if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME")) == NULL)
1704 error("HOME not set");
1705 if (*dest == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00001706 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001707 if (dest[0] == '-' && dest[1] == '\0') {
1708 dest = bltinlookup("OLDPWD");
1709 if (!dest || !*dest) {
1710 dest = curdir;
1711 }
1712 print = 1;
1713 if (dest)
Eric Andersen2870d962001-07-02 17:27:21 +00001714 print = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00001715 else
Eric Andersen2870d962001-07-02 17:27:21 +00001716 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001717 }
1718 if (*dest == '/' || (path = bltinlookup("CDPATH")) == NULL)
1719 path = nullstr;
1720 while ((p = padvance(&path, dest)) != NULL) {
1721 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
1722 if (!print) {
1723 /*
1724 * XXX - rethink
1725 */
1726 if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
1727 p += 2;
1728 print = strcmp(p, dest);
1729 }
1730 if (docd(p, print) >= 0)
1731 return 0;
1732
1733 }
1734 }
1735 error("can't cd to %s", dest);
1736 /* NOTREACHED */
1737}
1738
1739
1740/*
1741 * Actually do the chdir. In an interactive shell, print the
1742 * directory name if "print" is nonzero.
1743 */
1744
1745static int
Eric Andersena3483db2001-10-24 08:01:06 +00001746docd(char *dest, int print)
Eric Andersencb57d552001-06-28 07:25:16 +00001747{
Eric Andersencb57d552001-06-28 07:25:16 +00001748 TRACE(("docd(\"%s\", %d) called\n", dest, print));
Eric Andersencb57d552001-06-28 07:25:16 +00001749 INTOFF;
1750 if (chdir(dest) < 0) {
1751 INTON;
1752 return -1;
1753 }
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001754 hashcd();
1755 /*
1756 * Update curdir (the name of the current directory) in response to a
1757 * cd command. We also call hashcd to let the routines in exec.c know
1758 * that the current directory has changed.
1759 */
1760 /* If dest is NULL, we don't know the current directory */
1761 if (dest == NULL || curdir == nullstr)
1762 setpwd(0, 1);
1763 else
1764 setpwd(dest, 1);
1765
Eric Andersencb57d552001-06-28 07:25:16 +00001766 INTON;
1767 if (print && iflag)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001768 puts(curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00001769 return 0;
1770}
1771
1772
Eric Andersencb57d552001-06-28 07:25:16 +00001773static int
Eric Andersena3483db2001-10-24 08:01:06 +00001774pwdcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001775{
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001776 puts(curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00001777 return 0;
1778}
Eric Andersencb57d552001-06-28 07:25:16 +00001779
Eric Andersena3483db2001-10-24 08:01:06 +00001780/* Ask system the current directory */
Eric Andersencb57d552001-06-28 07:25:16 +00001781static void
Eric Andersen2870d962001-07-02 17:27:21 +00001782getpwd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00001783{
Eric Andersen2870d962001-07-02 17:27:21 +00001784 curdir = xgetcwd(0);
1785 if(curdir==0)
1786 curdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00001787}
1788
1789static void
1790setpwd(const char *val, int setold)
1791{
Eric Andersena3483db2001-10-24 08:01:06 +00001792 char *cated = NULL;
1793
Eric Andersencb57d552001-06-28 07:25:16 +00001794 if (setold) {
1795 setvar("OLDPWD", curdir, VEXPORT);
1796 }
1797 INTOFF;
1798 if (curdir != nullstr) {
Eric Andersena3483db2001-10-24 08:01:06 +00001799 if(val!=NULL && *val != '/')
1800 val = cated = concat_path_file(curdir, val);
Eric Andersencb57d552001-06-28 07:25:16 +00001801 free(curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00001802 }
Eric Andersena3483db2001-10-24 08:01:06 +00001803 if (!val)
Eric Andersencb57d552001-06-28 07:25:16 +00001804 getpwd();
Eric Andersena3483db2001-10-24 08:01:06 +00001805 else
1806 curdir = simplify_path(val);
1807 free(cated);
Eric Andersencb57d552001-06-28 07:25:16 +00001808 INTON;
1809 setvar("PWD", curdir, VEXPORT);
1810}
1811
Eric Andersencb57d552001-06-28 07:25:16 +00001812/*
1813 * Errors and exceptions.
1814 */
1815
1816/*
1817 * Code to handle exceptions in C.
1818 */
1819
Eric Andersen2870d962001-07-02 17:27:21 +00001820/*
1821 * We enclose jmp_buf in a structure so that we can declare pointers to
1822 * jump locations. The global variable handler contains the location to
1823 * jump to when an exception occurs, and the global variable exception
1824 * contains a code identifying the exeception. To implement nested
1825 * exception handlers, the user should save the value of handler on entry
1826 * to an inner scope, set handler to point to a jmploc structure for the
1827 * inner scope, and restore handler on exit from the scope.
1828 */
1829
1830struct jmploc {
1831 jmp_buf loc;
1832};
1833
1834/* exceptions */
1835#define EXINT 0 /* SIGINT received */
1836#define EXERROR 1 /* a generic error */
1837#define EXSHELLPROC 2 /* execute a shell procedure */
1838#define EXEXEC 3 /* command execution failed */
1839
1840static struct jmploc *handler;
Eric Andersencb57d552001-06-28 07:25:16 +00001841static int exception;
Eric Andersencb57d552001-06-28 07:25:16 +00001842
Eric Andersen2870d962001-07-02 17:27:21 +00001843static void exverror (int, const char *, va_list)
Eric Andersencb57d552001-06-28 07:25:16 +00001844 __attribute__((__noreturn__));
1845
1846/*
1847 * Called to raise an exception. Since C doesn't include exceptions, we
1848 * just do a longjmp to the exception handler. The type of exception is
1849 * stored in the global variable "exception".
1850 */
1851
Eric Andersen2870d962001-07-02 17:27:21 +00001852static void exraise (int) __attribute__((__noreturn__));
1853
Eric Andersencb57d552001-06-28 07:25:16 +00001854static void
Eric Andersen2870d962001-07-02 17:27:21 +00001855exraise(int e)
Eric Andersencb57d552001-06-28 07:25:16 +00001856{
1857#ifdef DEBUG
1858 if (handler == NULL)
1859 abort();
1860#endif
Eric Andersen62483552001-07-10 06:09:16 +00001861 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00001862 exception = e;
1863 longjmp(handler->loc, 1);
1864}
1865
1866
1867/*
1868 * Called from trap.c when a SIGINT is received. (If the user specifies
1869 * that SIGINT is to be trapped or ignored using the trap builtin, then
1870 * this routine is not called.) Suppressint is nonzero when interrupts
1871 * are held using the INTOFF macro. The call to _exit is necessary because
1872 * there is a short period after a fork before the signal handlers are
1873 * set to the appropriate value for the child. (The test for iflag is
1874 * just defensive programming.)
1875 */
1876
1877static void
Eric Andersen2870d962001-07-02 17:27:21 +00001878onint(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00001879 sigset_t mysigset;
1880
1881 if (suppressint) {
1882 intpending++;
1883 return;
1884 }
1885 intpending = 0;
1886 sigemptyset(&mysigset);
1887 sigprocmask(SIG_SETMASK, &mysigset, NULL);
1888 if (rootshell && iflag)
1889 exraise(EXINT);
1890 else {
1891 signal(SIGINT, SIG_DFL);
1892 raise(SIGINT);
1893 }
1894 /* NOTREACHED */
1895}
1896
1897
Eric Andersen2870d962001-07-02 17:27:21 +00001898static char *commandname; /* currently executing command */
1899
Eric Andersencb57d552001-06-28 07:25:16 +00001900/*
1901 * Exverror is called to raise the error exception. If the first argument
1902 * is not NULL then error prints an error message using printf style
1903 * formatting. It then raises the error exception.
1904 */
1905static void
Eric Andersen2870d962001-07-02 17:27:21 +00001906exverror(int cond, const char *msg, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00001907{
1908 CLEAR_PENDING_INT;
1909 INTOFF;
1910
1911#ifdef DEBUG
1912 if (msg)
1913 TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
1914 else
1915 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
1916#endif
1917 if (msg) {
1918 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +00001919 out2fmt("%s: ", commandname);
1920 vfprintf(stderr, msg, ap);
1921 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00001922 }
Eric Andersencb57d552001-06-28 07:25:16 +00001923 exraise(cond);
1924 /* NOTREACHED */
1925}
1926
1927
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001928static void
Eric Andersencb57d552001-06-28 07:25:16 +00001929error(const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00001930{
Eric Andersencb57d552001-06-28 07:25:16 +00001931 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00001932 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00001933 exverror(EXERROR, msg, ap);
1934 /* NOTREACHED */
1935 va_end(ap);
1936}
1937
1938
Eric Andersencb57d552001-06-28 07:25:16 +00001939static void
1940exerror(int cond, const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00001941{
Eric Andersencb57d552001-06-28 07:25:16 +00001942 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00001943 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00001944 exverror(cond, msg, ap);
1945 /* NOTREACHED */
1946 va_end(ap);
1947}
1948
1949
1950
1951/*
1952 * Table of error messages.
1953 */
1954
1955struct errname {
Eric Andersen2870d962001-07-02 17:27:21 +00001956 short errcode; /* error number */
Aaron Lehmann43880332001-12-31 06:16:54 +00001957 short action; /* operation which encountered the error */
Eric Andersencb57d552001-06-28 07:25:16 +00001958};
1959
Eric Andersen2870d962001-07-02 17:27:21 +00001960/*
1961 * Types of operations (passed to the errmsg routine).
1962 */
1963
1964#define E_OPEN 01 /* opening a file */
1965#define E_CREAT 02 /* creating a file */
1966#define E_EXEC 04 /* executing a program */
Eric Andersencb57d552001-06-28 07:25:16 +00001967
1968#define ALL (E_OPEN|E_CREAT|E_EXEC)
1969
1970static const struct errname errormsg[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00001971 { EINTR, ALL },
1972 { EACCES, ALL },
1973 { EIO, ALL },
1974 { ENOENT, E_OPEN },
1975 { ENOENT, E_CREAT },
1976 { ENOENT, E_EXEC },
1977 { ENOTDIR, E_OPEN },
1978 { ENOTDIR, E_CREAT },
1979 { ENOTDIR, E_EXEC },
1980 { EISDIR, ALL },
1981 { EEXIST, E_CREAT },
1982#ifdef EMFILE
1983 { EMFILE, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00001984#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001985 { ENFILE, ALL },
1986 { ENOSPC, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00001987#ifdef EDQUOT
Eric Andersen2870d962001-07-02 17:27:21 +00001988 { EDQUOT, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00001989#endif
1990#ifdef ENOSR
Eric Andersen2870d962001-07-02 17:27:21 +00001991 { ENOSR, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00001992#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001993 { ENXIO, ALL },
1994 { EROFS, ALL },
1995 { ETXTBSY, ALL },
1996#ifdef EAGAIN
1997 { EAGAIN, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00001998#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001999 { ENOMEM, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002000#ifdef ENOLINK
Eric Andersen2870d962001-07-02 17:27:21 +00002001 { ENOLINK, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002002#endif
2003#ifdef EMULTIHOP
Eric Andersen2870d962001-07-02 17:27:21 +00002004 { EMULTIHOP, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002005#endif
2006#ifdef ECOMM
Eric Andersen2870d962001-07-02 17:27:21 +00002007 { ECOMM, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002008#endif
2009#ifdef ESTALE
Eric Andersen2870d962001-07-02 17:27:21 +00002010 { ESTALE, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002011#endif
2012#ifdef ETIMEDOUT
Eric Andersen2870d962001-07-02 17:27:21 +00002013 { ETIMEDOUT, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002014#endif
2015#ifdef ELOOP
Eric Andersen2870d962001-07-02 17:27:21 +00002016 { ELOOP, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002017#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002018 { E2BIG, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002019#ifdef ELIBACC
Eric Andersen2870d962001-07-02 17:27:21 +00002020 { ELIBACC, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002021#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002022};
2023
Eric Andersen2870d962001-07-02 17:27:21 +00002024#define ERRNAME_SIZE (sizeof(errormsg)/sizeof(struct errname))
Eric Andersencb57d552001-06-28 07:25:16 +00002025
2026/*
2027 * Return a string describing an error. The returned string may be a
2028 * pointer to a static buffer that will be overwritten on the next call.
2029 * Action describes the operation that got the error.
2030 */
2031
2032static const char *
Eric Andersen2870d962001-07-02 17:27:21 +00002033errmsg(int e, int action)
Eric Andersencb57d552001-06-28 07:25:16 +00002034{
2035 struct errname const *ep;
2036 static char buf[12];
2037
Eric Andersen2870d962001-07-02 17:27:21 +00002038 for (ep = errormsg ; ep < errormsg+ERRNAME_SIZE; ep++) {
Eric Andersencb57d552001-06-28 07:25:16 +00002039 if (ep->errcode == e && (ep->action & action) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00002040 return strerror(e);
Eric Andersencb57d552001-06-28 07:25:16 +00002041 }
Eric Andersen2870d962001-07-02 17:27:21 +00002042
Eric Andersen3102ac42001-07-06 04:26:23 +00002043 snprintf(buf, sizeof buf, "error %d", e);
Eric Andersencb57d552001-06-28 07:25:16 +00002044 return buf;
2045}
2046
2047
Eric Andersend35c5df2002-01-09 15:37:36 +00002048#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Eric Andersencb57d552001-06-28 07:25:16 +00002049static void
2050__inton() {
2051 if (--suppressint == 0 && intpending) {
2052 onint();
2053 }
2054}
Eric Andersen3102ac42001-07-06 04:26:23 +00002055static void forceinton (void) {
2056 suppressint = 0;
2057 if (intpending)
2058 onint();
2059}
Eric Andersencb57d552001-06-28 07:25:16 +00002060#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002061
2062/* flags in argument to evaltree */
Eric Andersen2870d962001-07-02 17:27:21 +00002063#define EV_EXIT 01 /* exit after evaluating tree */
2064#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2065#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00002066
Eric Andersen2870d962001-07-02 17:27:21 +00002067static int evalskip; /* set if we are skipping commands */
2068static int skipcount; /* number of levels to skip */
2069static int loopnest; /* current loop nesting level */
2070static int funcnest; /* depth of function calls */
Eric Andersencb57d552001-06-28 07:25:16 +00002071
2072
Eric Andersen2870d962001-07-02 17:27:21 +00002073static struct strlist *cmdenviron; /* environment for builtin command */
2074static int exitstatus; /* exit status of last command */
2075static int oexitstatus; /* saved exit status */
Eric Andersencb57d552001-06-28 07:25:16 +00002076
Eric Andersen62483552001-07-10 06:09:16 +00002077static void evalsubshell (const union node *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00002078static void expredir (union node *);
Eric Andersen2870d962001-07-02 17:27:21 +00002079static void eprintlist (struct strlist *);
Eric Andersencb57d552001-06-28 07:25:16 +00002080
Eric Andersen2870d962001-07-02 17:27:21 +00002081static union node *parsecmd(int);
Eric Andersencb57d552001-06-28 07:25:16 +00002082/*
2083 * Called to reset things after an exception.
2084 */
2085
Eric Andersencb57d552001-06-28 07:25:16 +00002086/*
2087 * The eval commmand.
2088 */
Eric Andersen2870d962001-07-02 17:27:21 +00002089static void evalstring (char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00002090
2091static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00002092evalcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002093{
Eric Andersen2870d962001-07-02 17:27:21 +00002094 char *p;
2095 char *concat;
2096 char **ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002097
Eric Andersen2870d962001-07-02 17:27:21 +00002098 if (argc > 1) {
2099 p = argv[1];
2100 if (argc > 2) {
2101 STARTSTACKSTR(concat);
2102 ap = argv + 2;
2103 for (;;) {
2104 while (*p)
2105 STPUTC(*p++, concat);
2106 if ((p = *ap++) == NULL)
2107 break;
2108 STPUTC(' ', concat);
2109 }
2110 STPUTC('\0', concat);
2111 p = grabstackstr(concat);
2112 }
2113 evalstring(p, EV_TESTED);
2114 }
2115 return exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002116}
2117
Eric Andersencb57d552001-06-28 07:25:16 +00002118/*
2119 * Execute a command or commands contained in a string.
2120 */
2121
Eric Andersen2870d962001-07-02 17:27:21 +00002122static void evaltree (union node *, int);
2123static void setinputstring (char *);
2124static void popfile (void);
2125static void setstackmark(struct stackmark *mark);
2126static void popstackmark(struct stackmark *mark);
2127
2128
Eric Andersencb57d552001-06-28 07:25:16 +00002129static void
Eric Andersen2870d962001-07-02 17:27:21 +00002130evalstring(char *s, int flag)
2131{
Eric Andersencb57d552001-06-28 07:25:16 +00002132 union node *n;
2133 struct stackmark smark;
2134
2135 setstackmark(&smark);
2136 setinputstring(s);
2137 while ((n = parsecmd(0)) != NEOF) {
2138 evaltree(n, flag);
2139 popstackmark(&smark);
2140 }
2141 popfile();
2142 popstackmark(&smark);
2143}
2144
Eric Andersen2870d962001-07-02 17:27:21 +00002145static struct builtincmd *find_builtin (const char *);
Eric Andersen62483552001-07-10 06:09:16 +00002146static void expandarg (union node *, struct arglist *, int);
2147static void calcsize (const union node *);
2148static union node *copynode (const union node *);
2149
2150/*
2151 * Make a copy of a parse tree.
2152 */
2153
2154static int funcblocksize; /* size of structures in function */
2155static int funcstringsize; /* size of strings in node */
2156static pointer funcblock; /* block to allocate function from */
2157static char *funcstring; /* block to allocate strings from */
2158
2159
2160static inline union node *
2161copyfunc(union node *n)
2162{
2163 if (n == NULL)
2164 return NULL;
2165 funcblocksize = 0;
2166 funcstringsize = 0;
2167 calcsize(n);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00002168 funcblock = xmalloc(funcblocksize + funcstringsize);
Eric Andersen62483552001-07-10 06:09:16 +00002169 funcstring = (char *) funcblock + funcblocksize;
2170 return copynode(n);
2171}
2172
2173/*
Eric Andersen62483552001-07-10 06:09:16 +00002174 * Add a new command entry, replacing any existing command entry for
2175 * the same name.
2176 */
2177
2178static inline void
2179addcmdentry(char *name, struct cmdentry *entry)
2180{
2181 struct tblentry *cmdp;
2182
2183 INTOFF;
2184 cmdp = cmdlookup(name, 1);
2185 if (cmdp->cmdtype == CMDFUNCTION) {
Aaron Lehmann49c024a2002-08-02 06:39:47 +00002186 free(cmdp->param.func);
Eric Andersen62483552001-07-10 06:09:16 +00002187 }
2188 cmdp->cmdtype = entry->cmdtype;
2189 cmdp->param = entry->u;
2190 INTON;
2191}
2192
2193static inline void
2194evalloop(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002195{
2196 int status;
2197
2198 loopnest++;
2199 status = 0;
2200 for (;;) {
2201 evaltree(n->nbinary.ch1, EV_TESTED);
2202 if (evalskip) {
Eric Andersen2870d962001-07-02 17:27:21 +00002203skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002204 evalskip = 0;
2205 continue;
2206 }
2207 if (evalskip == SKIPBREAK && --skipcount <= 0)
2208 evalskip = 0;
2209 break;
2210 }
2211 if (n->type == NWHILE) {
2212 if (exitstatus != 0)
2213 break;
2214 } else {
2215 if (exitstatus == 0)
2216 break;
2217 }
2218 evaltree(n->nbinary.ch2, flags & EV_TESTED);
2219 status = exitstatus;
2220 if (evalskip)
2221 goto skipping;
2222 }
2223 loopnest--;
2224 exitstatus = status;
2225}
2226
Eric Andersencb57d552001-06-28 07:25:16 +00002227static void
Eric Andersen62483552001-07-10 06:09:16 +00002228evalfor(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002229{
2230 struct arglist arglist;
2231 union node *argp;
2232 struct strlist *sp;
2233 struct stackmark smark;
2234
2235 setstackmark(&smark);
2236 arglist.lastp = &arglist.list;
2237 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2238 oexitstatus = exitstatus;
2239 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2240 if (evalskip)
2241 goto out;
2242 }
2243 *arglist.lastp = NULL;
2244
2245 exitstatus = 0;
2246 loopnest++;
2247 for (sp = arglist.list ; sp ; sp = sp->next) {
2248 setvar(n->nfor.var, sp->text, 0);
2249 evaltree(n->nfor.body, flags & EV_TESTED);
2250 if (evalskip) {
2251 if (evalskip == SKIPCONT && --skipcount <= 0) {
2252 evalskip = 0;
2253 continue;
2254 }
2255 if (evalskip == SKIPBREAK && --skipcount <= 0)
2256 evalskip = 0;
2257 break;
2258 }
2259 }
2260 loopnest--;
2261out:
2262 popstackmark(&smark);
2263}
2264
Eric Andersen62483552001-07-10 06:09:16 +00002265static inline void
2266evalcase(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002267{
2268 union node *cp;
2269 union node *patp;
2270 struct arglist arglist;
2271 struct stackmark smark;
2272
2273 setstackmark(&smark);
2274 arglist.lastp = &arglist.list;
2275 oexitstatus = exitstatus;
2276 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2277 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2278 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2279 if (casematch(patp, arglist.list->text)) {
2280 if (evalskip == 0) {
2281 evaltree(cp->nclist.body, flags);
2282 }
2283 goto out;
2284 }
2285 }
2286 }
2287out:
2288 popstackmark(&smark);
2289}
2290
Eric Andersencb57d552001-06-28 07:25:16 +00002291/*
Eric Andersencb57d552001-06-28 07:25:16 +00002292 * Evaluate a pipeline. All the processes in the pipeline are children
2293 * of the process creating the pipeline. (This differs from some versions
2294 * of the shell, which make the last process in a pipeline the parent
2295 * of all the rest.)
2296 */
2297
Eric Andersen74400cc2001-10-18 04:11:39 +00002298static inline void evalpipe(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00002299{
2300 struct job *jp;
2301 struct nodelist *lp;
2302 int pipelen;
2303 int prevfd;
2304 int pip[2];
2305
2306 TRACE(("evalpipe(0x%lx) called\n", (long)n));
2307 pipelen = 0;
2308 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
2309 pipelen++;
2310 INTOFF;
2311 jp = makejob(n, pipelen);
2312 prevfd = -1;
2313 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00002314 /*
2315 * Search for a command. This is called before we fork so that the
2316 * location of the command will be available in the parent as well as
2317 * the child. The check for "goodname" is an overly conservative
2318 * check that the name will not be subject to expansion.
2319 */
2320
2321 struct cmdentry entry;
2322 union node *lpn = lp->n;
2323 if (lpn->type == NCMD && lpn->ncmd.args && goodname(lpn->ncmd.args->narg.text))
2324 find_command(lpn->ncmd.args->narg.text, &entry, 0, pathval());
2325
Eric Andersencb57d552001-06-28 07:25:16 +00002326 pip[1] = -1;
2327 if (lp->next) {
2328 if (pipe(pip) < 0) {
2329 close(prevfd);
2330 error("Pipe call failed");
2331 }
2332 }
2333 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
2334 INTON;
2335 if (prevfd > 0) {
2336 close(0);
2337 dup_as_newfd(prevfd, 0);
2338 close(prevfd);
2339 if (pip[0] == 0) {
2340 pip[0] = -1;
2341 }
2342 }
2343 if (pip[1] >= 0) {
2344 if (pip[0] >= 0) {
2345 close(pip[0]);
2346 }
2347 if (pip[1] != 1) {
2348 close(1);
2349 dup_as_newfd(pip[1], 1);
2350 close(pip[1]);
2351 }
2352 }
2353 evaltree(lp->n, EV_EXIT);
2354 }
2355 if (prevfd >= 0)
2356 close(prevfd);
2357 prevfd = pip[0];
2358 close(pip[1]);
2359 }
2360 INTON;
2361 if (n->npipe.backgnd == 0) {
2362 INTOFF;
2363 exitstatus = waitforjob(jp);
2364 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
2365 INTON;
2366 }
2367}
2368
Eric Andersen2870d962001-07-02 17:27:21 +00002369static int
2370isassignment(const char *word) {
2371 if (!is_name(*word)) {
2372 return 0;
2373 }
2374 do {
2375 word++;
2376 } while (is_in_name(*word));
2377 return *word == '=';
2378}
2379
Eric Andersen62483552001-07-10 06:09:16 +00002380
Eric Andersencb57d552001-06-28 07:25:16 +00002381static void
Eric Andersen3102ac42001-07-06 04:26:23 +00002382evalcommand(union node *cmd, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002383{
2384 struct stackmark smark;
2385 union node *argp;
2386 struct arglist arglist;
2387 struct arglist varlist;
2388 char **argv;
2389 int argc;
2390 char **envp;
2391 struct strlist *sp;
2392 int mode;
Eric Andersencb57d552001-06-28 07:25:16 +00002393 struct cmdentry cmdentry;
2394 struct job *jp;
2395 char *volatile savecmdname;
2396 volatile struct shparam saveparam;
2397 struct localvar *volatile savelocalvars;
2398 volatile int e;
2399 char *lastarg;
2400 const char *path;
2401 const struct builtincmd *firstbltin;
2402 struct jmploc *volatile savehandler;
2403 struct jmploc jmploc;
2404#if __GNUC__
2405 /* Avoid longjmp clobbering */
2406 (void) &argv;
2407 (void) &argc;
2408 (void) &lastarg;
2409 (void) &flags;
2410#endif
2411
2412 /* First expand the arguments. */
2413 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
2414 setstackmark(&smark);
2415 arglist.lastp = &arglist.list;
2416 varlist.lastp = &varlist.list;
2417 arglist.list = 0;
2418 oexitstatus = exitstatus;
2419 exitstatus = 0;
2420 path = pathval();
2421 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
2422 expandarg(argp, &varlist, EXP_VARTILDE);
2423 }
2424 for (
2425 argp = cmd->ncmd.args; argp && !arglist.list;
2426 argp = argp->narg.next
2427 ) {
2428 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2429 }
2430 if (argp) {
2431 struct builtincmd *bcmd;
Eric Andersen62483552001-07-10 06:09:16 +00002432 int pseudovarflag;
Eric Andersencb57d552001-06-28 07:25:16 +00002433 bcmd = find_builtin(arglist.list->text);
Eric Andersen2870d962001-07-02 17:27:21 +00002434 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00002435 for (; argp; argp = argp->narg.next) {
2436 if (pseudovarflag && isassignment(argp->narg.text)) {
2437 expandarg(argp, &arglist, EXP_VARTILDE);
2438 continue;
2439 }
2440 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2441 }
2442 }
2443 *arglist.lastp = NULL;
2444 *varlist.lastp = NULL;
2445 expredir(cmd->ncmd.redirect);
2446 argc = 0;
2447 for (sp = arglist.list ; sp ; sp = sp->next)
2448 argc++;
2449 argv = stalloc(sizeof (char *) * (argc + 1));
2450
2451 for (sp = arglist.list ; sp ; sp = sp->next) {
2452 TRACE(("evalcommand arg: %s\n", sp->text));
2453 *argv++ = sp->text;
2454 }
2455 *argv = NULL;
2456 lastarg = NULL;
2457 if (iflag && funcnest == 0 && argc > 0)
2458 lastarg = argv[-1];
2459 argv -= argc;
2460
2461 /* Print the command if xflag is set. */
2462 if (xflag) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002463 out2c('+');
Eric Andersencb57d552001-06-28 07:25:16 +00002464 eprintlist(varlist.list);
2465 eprintlist(arglist.list);
Eric Andersen3102ac42001-07-06 04:26:23 +00002466 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00002467 }
2468
2469 /* Now locate the command. */
2470 if (argc == 0) {
2471 cmdentry.cmdtype = CMDBUILTIN;
2472 firstbltin = cmdentry.u.cmd = BLTINCMD;
2473 } else {
2474 const char *oldpath;
2475 int findflag = DO_ERR;
2476 int oldfindflag;
2477
2478 /*
2479 * Modify the command lookup path, if a PATH= assignment
2480 * is present
2481 */
2482 for (sp = varlist.list ; sp ; sp = sp->next)
2483 if (varequal(sp->text, defpathvar)) {
2484 path = sp->text + 5;
2485 findflag |= DO_BRUTE;
2486 }
2487 oldpath = path;
2488 oldfindflag = findflag;
2489 firstbltin = 0;
2490 for(;;) {
2491 find_command(argv[0], &cmdentry, findflag, path);
Eric Andersen2870d962001-07-02 17:27:21 +00002492 if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */
Eric Andersencb57d552001-06-28 07:25:16 +00002493 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002494 goto out;
2495 }
2496 /* implement bltin and command here */
2497 if (cmdentry.cmdtype != CMDBUILTIN) {
2498 break;
2499 }
2500 if (!firstbltin) {
2501 firstbltin = cmdentry.u.cmd;
2502 }
2503 if (cmdentry.u.cmd == BLTINCMD) {
2504 for(;;) {
2505 struct builtincmd *bcmd;
2506
2507 argv++;
2508 if (--argc == 0)
2509 goto found;
2510 if (!(bcmd = find_builtin(*argv))) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002511 out2fmt("%s: not found\n", *argv);
Eric Andersencb57d552001-06-28 07:25:16 +00002512 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002513 goto out;
2514 }
2515 cmdentry.u.cmd = bcmd;
2516 if (bcmd != BLTINCMD)
2517 break;
2518 }
2519 }
Eric Andersen2870d962001-07-02 17:27:21 +00002520 if (cmdentry.u.cmd == find_builtin("command")) {
Eric Andersencb57d552001-06-28 07:25:16 +00002521 argv++;
2522 if (--argc == 0) {
2523 goto found;
2524 }
2525 if (*argv[0] == '-') {
2526 if (!equal(argv[0], "-p")) {
2527 argv--;
2528 argc++;
2529 break;
2530 }
2531 argv++;
2532 if (--argc == 0) {
2533 goto found;
2534 }
2535 path = defpath;
2536 findflag |= DO_BRUTE;
2537 } else {
2538 path = oldpath;
2539 findflag = oldfindflag;
2540 }
2541 findflag |= DO_NOFUN;
2542 continue;
2543 }
2544found:
2545 break;
2546 }
2547 }
2548
2549 /* Fork off a child process if necessary. */
2550 if (cmd->ncmd.backgnd
2551 || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00002552 ) {
2553 jp = makejob(cmd, 1);
2554 mode = cmd->ncmd.backgnd;
Eric Andersencb57d552001-06-28 07:25:16 +00002555 if (forkshell(jp, cmd, mode) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00002556 goto parent; /* at end of routine */
Eric Andersencb57d552001-06-28 07:25:16 +00002557 flags |= EV_EXIT;
2558 }
2559
2560 /* This is the child process if a fork occurred. */
2561 /* Execute the command. */
2562 if (cmdentry.cmdtype == CMDFUNCTION) {
2563#ifdef DEBUG
2564 trputs("Shell function: "); trargs(argv);
2565#endif
2566 exitstatus = oexitstatus;
2567 redirect(cmd->ncmd.redirect, REDIR_PUSH);
2568 saveparam = shellparam;
2569 shellparam.malloc = 0;
2570 shellparam.nparam = argc - 1;
2571 shellparam.p = argv + 1;
2572 INTOFF;
2573 savelocalvars = localvars;
2574 localvars = NULL;
2575 INTON;
2576 if (setjmp(jmploc.loc)) {
2577 if (exception == EXSHELLPROC) {
2578 freeparam((volatile struct shparam *)
2579 &saveparam);
2580 } else {
2581 saveparam.optind = shellparam.optind;
2582 saveparam.optoff = shellparam.optoff;
2583 freeparam(&shellparam);
2584 shellparam = saveparam;
2585 }
2586 poplocalvars();
2587 localvars = savelocalvars;
2588 handler = savehandler;
2589 longjmp(handler->loc, 1);
2590 }
2591 savehandler = handler;
2592 handler = &jmploc;
2593 for (sp = varlist.list ; sp ; sp = sp->next)
2594 mklocal(sp->text);
2595 funcnest++;
2596 evaltree(cmdentry.u.func, flags & EV_TESTED);
2597 funcnest--;
2598 INTOFF;
2599 poplocalvars();
2600 localvars = savelocalvars;
2601 saveparam.optind = shellparam.optind;
2602 saveparam.optoff = shellparam.optoff;
2603 freeparam(&shellparam);
2604 shellparam = saveparam;
2605 handler = savehandler;
2606 popredir();
2607 INTON;
2608 if (evalskip == SKIPFUNC) {
2609 evalskip = 0;
2610 skipcount = 0;
2611 }
2612 if (flags & EV_EXIT)
2613 exitshell(exitstatus);
2614 } else if (cmdentry.cmdtype == CMDBUILTIN) {
2615#ifdef DEBUG
2616 trputs("builtin command: "); trargs(argv);
2617#endif
2618 mode = (cmdentry.u.cmd == EXECCMD)? 0 : REDIR_PUSH;
Eric Andersencb57d552001-06-28 07:25:16 +00002619 redirect(cmd->ncmd.redirect, mode);
2620 savecmdname = commandname;
Eric Andersen2870d962001-07-02 17:27:21 +00002621 if (IS_BUILTIN_SPECIAL(firstbltin)) {
Eric Andersencb57d552001-06-28 07:25:16 +00002622 listsetvar(varlist.list);
2623 } else {
2624 cmdenviron = varlist.list;
2625 }
2626 e = -1;
2627 if (setjmp(jmploc.loc)) {
2628 e = exception;
2629 exitstatus = (e == EXINT)? SIGINT+128 : 2;
2630 goto cmddone;
2631 }
2632 savehandler = handler;
2633 handler = &jmploc;
2634 commandname = argv[0];
2635 argptr = argv + 1;
Eric Andersen2870d962001-07-02 17:27:21 +00002636 optptr = NULL; /* initialize nextopt */
Eric Andersencb57d552001-06-28 07:25:16 +00002637 exitstatus = (*cmdentry.u.cmd->builtinfunc)(argc, argv);
2638 flushall();
2639cmddone:
Eric Andersencb57d552001-06-28 07:25:16 +00002640 cmdenviron = NULL;
2641 if (e != EXSHELLPROC) {
2642 commandname = savecmdname;
2643 if (flags & EV_EXIT)
2644 exitshell(exitstatus);
2645 }
2646 handler = savehandler;
2647 if (e != -1) {
2648 if ((e != EXERROR && e != EXEXEC)
2649 || cmdentry.u.cmd == BLTINCMD
2650 || cmdentry.u.cmd == DOTCMD
2651 || cmdentry.u.cmd == EVALCMD
2652 || cmdentry.u.cmd == EXECCMD)
2653 exraise(e);
2654 FORCEINTON;
2655 }
2656 if (cmdentry.u.cmd != EXECCMD)
2657 popredir();
Eric Andersencb57d552001-06-28 07:25:16 +00002658 } else {
2659#ifdef DEBUG
2660 trputs("normal command: "); trargs(argv);
2661#endif
2662 redirect(cmd->ncmd.redirect, 0);
2663 clearredir();
2664 for (sp = varlist.list ; sp ; sp = sp->next)
2665 setvareq(sp->text, VEXPORT|VSTACK);
2666 envp = environment();
2667 shellexec(argv, envp, path, cmdentry.u.index);
2668 }
2669 goto out;
2670
Eric Andersen2870d962001-07-02 17:27:21 +00002671parent: /* parent process gets here (if we forked) */
2672 if (mode == 0) { /* argument to fork */
Eric Andersencb57d552001-06-28 07:25:16 +00002673 INTOFF;
2674 exitstatus = waitforjob(jp);
2675 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00002676 }
2677
2678out:
2679 if (lastarg)
2680 setvar("_", lastarg, 0);
2681 popstackmark(&smark);
2682}
2683
Eric Andersen62483552001-07-10 06:09:16 +00002684/*
2685 * Evaluate a parse tree. The value is left in the global variable
2686 * exitstatus.
2687 */
2688static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00002689evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00002690{
2691 int checkexit = 0;
2692 if (n == NULL) {
2693 TRACE(("evaltree(NULL) called\n"));
2694 goto out;
2695 }
2696 TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
2697 switch (n->type) {
2698 case NSEMI:
2699 evaltree(n->nbinary.ch1, flags & EV_TESTED);
2700 if (evalskip)
2701 goto out;
2702 evaltree(n->nbinary.ch2, flags);
2703 break;
2704 case NAND:
2705 evaltree(n->nbinary.ch1, EV_TESTED);
2706 if (evalskip || exitstatus != 0)
2707 goto out;
2708 evaltree(n->nbinary.ch2, flags);
2709 break;
2710 case NOR:
2711 evaltree(n->nbinary.ch1, EV_TESTED);
2712 if (evalskip || exitstatus == 0)
2713 goto out;
2714 evaltree(n->nbinary.ch2, flags);
2715 break;
2716 case NREDIR:
2717 expredir(n->nredir.redirect);
2718 redirect(n->nredir.redirect, REDIR_PUSH);
2719 evaltree(n->nredir.n, flags);
2720 popredir();
2721 break;
2722 case NSUBSHELL:
2723 evalsubshell(n, flags);
2724 break;
2725 case NBACKGND:
2726 evalsubshell(n, flags);
2727 break;
2728 case NIF: {
2729 evaltree(n->nif.test, EV_TESTED);
2730 if (evalskip)
2731 goto out;
2732 if (exitstatus == 0)
2733 evaltree(n->nif.ifpart, flags);
2734 else if (n->nif.elsepart)
2735 evaltree(n->nif.elsepart, flags);
2736 else
2737 exitstatus = 0;
2738 break;
2739 }
2740 case NWHILE:
2741 case NUNTIL:
2742 evalloop(n, flags);
2743 break;
2744 case NFOR:
2745 evalfor(n, flags);
2746 break;
2747 case NCASE:
2748 evalcase(n, flags);
2749 break;
2750 case NDEFUN: {
2751 struct builtincmd *bcmd;
2752 struct cmdentry entry;
2753 if (
2754 (bcmd = find_builtin(n->narg.text)) &&
2755 IS_BUILTIN_SPECIAL(bcmd)
2756 ) {
2757 out2fmt("%s is a special built-in\n", n->narg.text);
2758 exitstatus = 1;
2759 break;
2760 }
2761 entry.cmdtype = CMDFUNCTION;
2762 entry.u.func = copyfunc(n->narg.next);
2763 addcmdentry(n->narg.text, &entry);
2764 exitstatus = 0;
2765 break;
2766 }
2767 case NNOT:
2768 evaltree(n->nnot.com, EV_TESTED);
2769 exitstatus = !exitstatus;
2770 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002771
Eric Andersen62483552001-07-10 06:09:16 +00002772 case NPIPE:
2773 evalpipe(n);
2774 checkexit = 1;
2775 break;
2776 case NCMD:
2777 evalcommand(n, flags);
2778 checkexit = 1;
2779 break;
2780#ifdef DEBUG
2781 default:
2782 printf("Node type = %d\n", n->type);
2783 break;
2784#endif
2785 }
2786out:
2787 if (pendingsigs)
2788 dotrap();
2789 if (
2790 flags & EV_EXIT ||
2791 (checkexit && eflag && exitstatus && !(flags & EV_TESTED))
2792 )
2793 exitshell(exitstatus);
2794}
2795
2796/*
2797 * Kick off a subshell to evaluate a tree.
2798 */
2799
2800static void
2801evalsubshell(const union node *n, int flags)
2802{
2803 struct job *jp;
2804 int backgnd = (n->type == NBACKGND);
2805
2806 expredir(n->nredir.redirect);
2807 jp = makejob(n, 1);
2808 if (forkshell(jp, n, backgnd) == 0) {
2809 if (backgnd)
2810 flags &=~ EV_TESTED;
2811 redirect(n->nredir.redirect, 0);
2812 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
2813 }
2814 if (! backgnd) {
2815 INTOFF;
2816 exitstatus = waitforjob(jp);
2817 INTON;
2818 }
2819}
2820
2821/*
2822 * Compute the names of the files in a redirection list.
2823 */
2824
2825static void fixredir(union node *n, const char *text, int err);
2826
2827static void
2828expredir(union node *n)
2829{
2830 union node *redir;
2831
2832 for (redir = n ; redir ; redir = redir->nfile.next) {
2833 struct arglist fn;
2834 fn.lastp = &fn.list;
2835 oexitstatus = exitstatus;
2836 switch (redir->type) {
2837 case NFROMTO:
2838 case NFROM:
2839 case NTO:
2840 case NAPPEND:
2841 case NTOOV:
2842 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
2843 redir->nfile.expfname = fn.list->text;
2844 break;
2845 case NFROMFD:
2846 case NTOFD:
2847 if (redir->ndup.vname) {
2848 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
2849 fixredir(redir, fn.list->text, 1);
2850 }
2851 break;
2852 }
2853 }
2854}
2855
2856
2857/*
2858 * Execute a command inside back quotes. If it's a builtin command, we
2859 * want to save its output in a block obtained from malloc. Otherwise
2860 * we fork off a subprocess and get the output of the command via a pipe.
2861 * Should be called with interrupts off.
2862 */
2863
2864static void
2865evalbackcmd(union node *n, struct backcmd *result)
2866{
2867 int pip[2];
2868 struct job *jp;
2869 struct stackmark smark; /* unnecessary */
2870
2871 setstackmark(&smark);
2872 result->fd = -1;
2873 result->buf = NULL;
2874 result->nleft = 0;
2875 result->jp = NULL;
2876 if (n == NULL) {
2877 exitstatus = 0;
2878 goto out;
2879 }
2880 exitstatus = 0;
2881 if (pipe(pip) < 0)
2882 error("Pipe call failed");
2883 jp = makejob(n, 1);
2884 if (forkshell(jp, n, FORK_NOJOB) == 0) {
2885 FORCEINTON;
2886 close(pip[0]);
2887 if (pip[1] != 1) {
2888 close(1);
2889 dup_as_newfd(pip[1], 1);
2890 close(pip[1]);
2891 }
2892 eflag = 0;
2893 evaltree(n, EV_EXIT);
2894 }
2895 close(pip[1]);
2896 result->fd = pip[0];
2897 result->jp = jp;
2898out:
2899 popstackmark(&smark);
2900 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
2901 result->fd, result->buf, result->nleft, result->jp));
2902}
2903
2904
2905/*
2906 * Execute a simple command.
2907 */
Eric Andersencb57d552001-06-28 07:25:16 +00002908
Eric Andersencb57d552001-06-28 07:25:16 +00002909
Eric Andersencb57d552001-06-28 07:25:16 +00002910/*
2911 * Builtin commands. Builtin commands whose functions are closely
2912 * tied to evaluation are implemented here.
2913 */
2914
2915/*
2916 * No command given, or a bltin command with no arguments. Set the
2917 * specified variables.
2918 */
2919
2920int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00002921bltincmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002922{
2923 /*
2924 * Preserve exitstatus of a previous possible redirection
2925 * as POSIX mandates
2926 */
2927 return exitstatus;
2928}
2929
2930
2931/*
2932 * Handle break and continue commands. Break, continue, and return are
2933 * all handled by setting the evalskip flag. The evaluation routines
2934 * above all check this flag, and if it is set they start skipping
2935 * commands rather than executing them. The variable skipcount is
2936 * the number of loops to break/continue, or the number of function
2937 * levels to return. (The latter is always 1.) It should probably
2938 * be an error to break out of more loops than exist, but it isn't
2939 * in the standard shell so we don't make it one here.
2940 */
2941
2942static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00002943breakcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002944{
2945 int n = argc > 1 ? number(argv[1]) : 1;
2946
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00002947 if (n <= 0)
2948 error("Illegal number: %s", argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00002949 if (n > loopnest)
2950 n = loopnest;
2951 if (n > 0) {
2952 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
2953 skipcount = n;
2954 }
2955 return 0;
2956}
2957
2958
2959/*
2960 * The return command.
2961 */
2962
2963static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00002964returncmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002965{
2966 int ret = argc > 1 ? number(argv[1]) : oexitstatus;
2967
2968 if (funcnest) {
2969 evalskip = SKIPFUNC;
2970 skipcount = 1;
2971 return ret;
2972 }
2973 else {
2974 /* Do what ksh does; skip the rest of the file */
2975 evalskip = SKIPFILE;
2976 skipcount = 1;
2977 return ret;
2978 }
2979}
2980
2981
Eric Andersen69a20f02001-10-31 10:40:37 +00002982#ifndef CONFIG_FALSE
Eric Andersencb57d552001-06-28 07:25:16 +00002983static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00002984false_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002985{
2986 return 1;
2987}
Eric Andersen69a20f02001-10-31 10:40:37 +00002988#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002989
Eric Andersen69a20f02001-10-31 10:40:37 +00002990#ifndef CONFIG_TRUE
Eric Andersencb57d552001-06-28 07:25:16 +00002991static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00002992true_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002993{
2994 return 0;
2995}
2996#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002997
2998/*
2999 * Controls whether the shell is interactive or not.
3000 */
3001
3002static void setsignal(int signo);
Eric Andersen2870d962001-07-02 17:27:21 +00003003
Eric Andersend35c5df2002-01-09 15:37:36 +00003004#ifdef CONFIG_ASH_MAIL
Eric Andersenec074692001-10-31 11:05:49 +00003005static void chkmail(int silent);
3006#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003007
3008static void
3009setinteractive(int on)
3010{
3011 static int is_interactive;
Eric Andersen1c039232001-07-07 00:05:55 +00003012 static int do_banner=0;
Eric Andersen2870d962001-07-02 17:27:21 +00003013
3014 if (on == is_interactive)
3015 return;
3016 setsignal(SIGINT);
3017 setsignal(SIGQUIT);
3018 setsignal(SIGTERM);
Eric Andersend35c5df2002-01-09 15:37:36 +00003019#ifdef CONFIG_ASH_MAIL
Eric Andersen2870d962001-07-02 17:27:21 +00003020 chkmail(1);
Eric Andersenec074692001-10-31 11:05:49 +00003021#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003022 is_interactive = on;
Eric Andersen1c039232001-07-07 00:05:55 +00003023 if (do_banner==0 && is_interactive) {
3024 /* Looks like they want an interactive shell */
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003025#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
Eric Andersen1c039232001-07-07 00:05:55 +00003026 printf( "\n\n" BB_BANNER " Built-in shell (ash)\n");
3027 printf( "Enter 'help' for a list of built-in commands.\n\n");
Eric Andersend63dee42001-10-19 00:22:23 +00003028#endif
Eric Andersen1c039232001-07-07 00:05:55 +00003029 do_banner=1;
3030 }
Eric Andersen2870d962001-07-02 17:27:21 +00003031}
3032
3033static void
3034optschanged(void)
3035{
3036 setinteractive(iflag);
3037 setjobctl(mflag);
3038}
3039
Eric Andersencb57d552001-06-28 07:25:16 +00003040
3041static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003042execcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003043{
3044 if (argc > 1) {
3045 struct strlist *sp;
3046
Eric Andersen2870d962001-07-02 17:27:21 +00003047 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003048 mflag = 0;
3049 optschanged();
3050 for (sp = cmdenviron; sp ; sp = sp->next)
3051 setvareq(sp->text, VEXPORT|VSTACK);
3052 shellexec(argv + 1, environment(), pathval(), 0);
3053 }
3054 return 0;
3055}
3056
3057static void
3058eprintlist(struct strlist *sp)
3059{
3060 for (; sp; sp = sp->next) {
Eric Andersen3102ac42001-07-06 04:26:23 +00003061 out2fmt(" %s",sp->text);
Eric Andersencb57d552001-06-28 07:25:16 +00003062 }
3063}
Eric Andersencb57d552001-06-28 07:25:16 +00003064
3065/*
3066 * Exec a program. Never returns. If you change this routine, you may
3067 * have to change the find_command routine as well.
3068 */
3069
Eric Andersen2870d962001-07-02 17:27:21 +00003070static const char *pathopt; /* set by padvance */
3071
Eric Andersencb57d552001-06-28 07:25:16 +00003072static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003073shellexec(char **argv, char **envp, const char *path, int idx)
Eric Andersencb57d552001-06-28 07:25:16 +00003074{
3075 char *cmdname;
3076 int e;
3077
3078 if (strchr(argv[0], '/') != NULL) {
3079 tryexec(argv[0], argv, envp);
3080 e = errno;
3081 } else {
3082 e = ENOENT;
3083 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3084 if (--idx < 0 && pathopt == NULL) {
3085 tryexec(cmdname, argv, envp);
3086 if (errno != ENOENT && errno != ENOTDIR)
3087 e = errno;
3088 }
3089 stunalloc(cmdname);
3090 }
3091 }
3092
3093 /* Map to POSIX errors */
3094 switch (e) {
3095 case EACCES:
3096 exerrno = 126;
3097 break;
3098 case ENOENT:
3099 exerrno = 127;
3100 break;
3101 default:
3102 exerrno = 2;
3103 break;
3104 }
3105 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3106 /* NOTREACHED */
3107}
3108
Eric Andersen2870d962001-07-02 17:27:21 +00003109/*
3110 * Clear traps on a fork.
3111 */
3112static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003113clear_traps(void)
3114{
Eric Andersen2870d962001-07-02 17:27:21 +00003115 char **tp;
3116
3117 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
3118 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
3119 INTOFF;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00003120 free(*tp);
Eric Andersen2870d962001-07-02 17:27:21 +00003121 *tp = NULL;
3122 if (tp != &trap[0])
3123 setsignal(tp - trap);
3124 INTON;
3125 }
3126 }
3127}
3128
3129
3130static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003131initshellproc(void)
3132{
Eric Andersen2870d962001-07-02 17:27:21 +00003133
Eric Andersend35c5df2002-01-09 15:37:36 +00003134#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00003135 /* from alias.c: */
3136 {
3137 rmaliases();
3138 }
3139#endif
3140 /* from eval.c: */
3141 {
3142 exitstatus = 0;
3143 }
3144
3145 /* from exec.c: */
3146 {
3147 deletefuncs();
3148 }
3149
3150 /* from jobs.c: */
3151 {
3152 backgndpid = -1;
Eric Andersend35c5df2002-01-09 15:37:36 +00003153#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen2870d962001-07-02 17:27:21 +00003154 jobctl = 0;
3155#endif
3156 }
3157
3158 /* from options.c: */
3159 {
3160 int i;
3161
3162 for (i = 0; i < NOPTS; i++)
3163 optent_val(i) = 0;
3164 optschanged();
3165
3166 }
3167
3168 /* from redir.c: */
3169 {
3170 clearredir();
3171 }
3172
3173 /* from trap.c: */
3174 {
3175 char *sm;
3176
3177 clear_traps();
3178 for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) {
3179 if (*sm == S_IGN)
3180 *sm = S_HARD_IGN;
3181 }
3182 }
3183
3184 /* from var.c: */
3185 {
3186 shprocvar();
3187 }
3188}
3189
3190static int preadbuffer(void);
3191static void pushfile (void);
Eric Andersen2870d962001-07-02 17:27:21 +00003192
3193/*
3194 * Read a character from the script, returning PEOF on end of file.
3195 * Nul characters in the input are silently discarded.
3196 */
3197
Eric Andersend35c5df2002-01-09 15:37:36 +00003198#ifndef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Eric Andersen2870d962001-07-02 17:27:21 +00003199#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
3200static int
3201pgetc(void)
3202{
3203 return pgetc_macro();
3204}
3205#else
3206static int
3207pgetc_macro(void)
3208{
3209 return --parsenleft >= 0? *parsenextc++ : preadbuffer();
3210}
3211
3212static inline int
3213pgetc(void)
3214{
3215 return pgetc_macro();
3216}
3217#endif
3218
3219
3220/*
3221 * Undo the last call to pgetc. Only one character may be pushed back.
3222 * PEOF may be pushed back.
3223 */
3224
Eric Andersen74400cc2001-10-18 04:11:39 +00003225static void pungetc(void)
3226{
Eric Andersen2870d962001-07-02 17:27:21 +00003227 parsenleft++;
3228 parsenextc--;
3229}
3230
3231
3232static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003233popfile(void)
3234{
Eric Andersen2870d962001-07-02 17:27:21 +00003235 struct parsefile *pf = parsefile;
3236
3237 INTOFF;
3238 if (pf->fd >= 0)
3239 close(pf->fd);
Aaron Lehmann49c024a2002-08-02 06:39:47 +00003240 free(pf->buf);
Eric Andersen2870d962001-07-02 17:27:21 +00003241 while (pf->strpush)
3242 popstring();
3243 parsefile = pf->prev;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00003244 free(pf);
Eric Andersen2870d962001-07-02 17:27:21 +00003245 parsenleft = parsefile->nleft;
3246 parselleft = parsefile->lleft;
3247 parsenextc = parsefile->nextc;
3248 plinno = parsefile->linno;
3249 INTON;
3250}
3251
3252
3253/*
3254 * Return to top level.
3255 */
3256
3257static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003258popallfiles(void)
3259{
Eric Andersen2870d962001-07-02 17:27:21 +00003260 while (parsefile != &basepf)
3261 popfile();
3262}
3263
3264/*
3265 * Close the file(s) that the shell is reading commands from. Called
3266 * after a fork is done.
3267 */
3268
Eric Andersen74400cc2001-10-18 04:11:39 +00003269static void closescript(void)
3270{
Eric Andersen2870d962001-07-02 17:27:21 +00003271 popallfiles();
3272 if (parsefile->fd > 0) {
3273 close(parsefile->fd);
3274 parsefile->fd = 0;
3275 }
3276}
3277
3278
3279/*
3280 * Like setinputfile, but takes an open file descriptor. Call this with
3281 * interrupts off.
3282 */
3283
Eric Andersen74400cc2001-10-18 04:11:39 +00003284static void setinputfd(int fd, int push)
Eric Andersen2870d962001-07-02 17:27:21 +00003285{
3286 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
3287 if (push) {
3288 pushfile();
3289 parsefile->buf = 0;
3290 } else {
3291 closescript();
3292 while (parsefile->strpush)
3293 popstring();
3294 }
3295 parsefile->fd = fd;
3296 if (parsefile->buf == NULL)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003297 parsefile->buf = xmalloc(BUFSIZ);
Eric Andersen2870d962001-07-02 17:27:21 +00003298 parselleft = parsenleft = 0;
3299 plinno = 1;
3300}
3301
3302
3303/*
3304 * Set the input to take input from a file. If push is set, push the
3305 * old input onto the stack first.
3306 */
3307
3308static void
3309setinputfile(const char *fname, int push)
3310{
3311 int fd;
3312 int myfileno2;
3313
3314 INTOFF;
3315 if ((fd = open(fname, O_RDONLY)) < 0)
3316 error("Can't open %s", fname);
3317 if (fd < 10) {
3318 myfileno2 = dup_as_newfd(fd, 10);
3319 close(fd);
3320 if (myfileno2 < 0)
3321 error("Out of file descriptors");
3322 fd = myfileno2;
3323 }
3324 setinputfd(fd, push);
3325 INTON;
3326}
3327
Eric Andersencb57d552001-06-28 07:25:16 +00003328
3329static void
Eric Andersen62483552001-07-10 06:09:16 +00003330tryexec(char *cmd, char **argv, char **envp)
3331{
Eric Andersencb57d552001-06-28 07:25:16 +00003332 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003333
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003334#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Eric Andersen3102ac42001-07-06 04:26:23 +00003335 char *name = cmd;
3336 char** argv_l=argv;
3337 int argc_l;
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003338#ifdef CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
Eric Andersen3102ac42001-07-06 04:26:23 +00003339 name = get_last_path_component(name);
3340#endif
3341 argv_l=envp;
3342 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
3343 putenv(*argv_l);
3344 argv_l=argv;
Eric Andersen62483552001-07-10 06:09:16 +00003345 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
Eric Andersen3102ac42001-07-06 04:26:23 +00003346 optind = 1;
3347 run_applet_by_name(name, argc_l, argv);
3348#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003349 execve(cmd, argv, envp);
Eric Andersencb57d552001-06-28 07:25:16 +00003350 e = errno;
3351 if (e == ENOEXEC) {
3352 INTOFF;
3353 initshellproc();
3354 setinputfile(cmd, 0);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003355 commandname = arg0 = xstrdup(argv[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00003356 setparam(argv + 1);
3357 exraise(EXSHELLPROC);
3358 }
3359 errno = e;
3360}
3361
Eric Andersen2870d962001-07-02 17:27:21 +00003362static char *commandtext (const union node *);
Eric Andersencb57d552001-06-28 07:25:16 +00003363
3364/*
3365 * Do a path search. The variable path (passed by reference) should be
3366 * set to the start of the path before the first call; padvance will update
3367 * this value as it proceeds. Successive calls to padvance will return
3368 * the possible path expansions in sequence. If an option (indicated by
3369 * a percent sign) appears in the path entry then the global variable
3370 * pathopt will be set to point to it; otherwise pathopt will be set to
3371 * NULL.
3372 */
3373
3374static const char *pathopt;
3375
Eric Andersen2870d962001-07-02 17:27:21 +00003376static void growstackblock(void);
3377
3378
Eric Andersencb57d552001-06-28 07:25:16 +00003379static char *
Eric Andersen2870d962001-07-02 17:27:21 +00003380padvance(const char **path, const char *name)
3381{
Eric Andersencb57d552001-06-28 07:25:16 +00003382 const char *p;
3383 char *q;
3384 const char *start;
3385 int len;
3386
3387 if (*path == NULL)
3388 return NULL;
3389 start = *path;
3390 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
Eric Andersen2870d962001-07-02 17:27:21 +00003391 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003392 while (stackblocksize() < len)
3393 growstackblock();
3394 q = stackblock();
3395 if (p != start) {
3396 memcpy(q, start, p - start);
3397 q += p - start;
3398 *q++ = '/';
3399 }
3400 strcpy(q, name);
3401 pathopt = NULL;
3402 if (*p == '%') {
3403 pathopt = ++p;
3404 while (*p && *p != ':') p++;
3405 }
3406 if (*p == ':')
3407 *path = p + 1;
3408 else
3409 *path = NULL;
3410 return stalloc(len);
3411}
3412
Eric Andersen62483552001-07-10 06:09:16 +00003413/*
3414 * Wrapper around strcmp for qsort/bsearch/...
3415 */
3416static int
3417pstrcmp(const void *a, const void *b)
3418{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003419 return strcmp((const char *) a, (*(const char *const *) b) + 1);
Eric Andersen62483552001-07-10 06:09:16 +00003420}
3421
3422/*
3423 * Find a keyword is in a sorted array.
3424 */
3425
3426static const char *const *
3427findkwd(const char *s)
3428{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003429 return bsearch(s, tokname_array + KWDOFFSET,
3430 (sizeof(tokname_array)/sizeof(const char *)) - KWDOFFSET,
3431 sizeof(const char *), pstrcmp);
Eric Andersen62483552001-07-10 06:09:16 +00003432}
Eric Andersencb57d552001-06-28 07:25:16 +00003433
3434
3435/*** Command hashing code ***/
3436
3437
3438static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003439hashcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003440{
3441 struct tblentry **pp;
3442 struct tblentry *cmdp;
3443 int c;
3444 int verbose;
3445 struct cmdentry entry;
3446 char *name;
Eric Andersend35c5df2002-01-09 15:37:36 +00003447#ifdef CONFIG_ASH_ALIAS
Eric Andersen62483552001-07-10 06:09:16 +00003448 const struct alias *ap;
3449#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003450
3451 verbose = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003452 while ((c = nextopt("rvV")) != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00003453 if (c == 'r') {
3454 clearcmdentry(0);
3455 return 0;
Eric Andersen62483552001-07-10 06:09:16 +00003456 } else if (c == 'v' || c == 'V') {
3457 verbose = c;
Eric Andersencb57d552001-06-28 07:25:16 +00003458 }
3459 }
3460 if (*argptr == NULL) {
3461 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3462 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3463 if (cmdp->cmdtype != CMDBUILTIN) {
3464 printentry(cmdp, verbose);
3465 }
3466 }
3467 }
3468 return 0;
3469 }
3470 c = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003471 while ((name = *argptr++) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00003472 if ((cmdp = cmdlookup(name, 0)) != NULL
3473 && (cmdp->cmdtype == CMDNORMAL
3474 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3475 delete_cmd_entry();
Eric Andersend35c5df2002-01-09 15:37:36 +00003476#ifdef CONFIG_ASH_ALIAS
Eric Andersen62483552001-07-10 06:09:16 +00003477 /* Then look at the aliases */
Eric Andersenec074692001-10-31 11:05:49 +00003478 if ((ap = *__lookupalias(name)) != NULL) {
Eric Andersen62483552001-07-10 06:09:16 +00003479 if (verbose=='v')
3480 printf("%s is an alias for %s\n", name, ap->val);
3481 else
3482 printalias(ap);
3483 continue;
3484 }
3485#endif
3486 /* First look at the keywords */
3487 if (findkwd(name)!=0) {
3488 if (verbose=='v')
3489 printf("%s is a shell keyword\n", name);
3490 else
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003491 puts(name);
Eric Andersen62483552001-07-10 06:09:16 +00003492 continue;
3493 }
3494
Eric Andersencb57d552001-06-28 07:25:16 +00003495 find_command(name, &entry, DO_ERR, pathval());
3496 if (entry.cmdtype == CMDUNKNOWN) c = 1;
3497 else if (verbose) {
3498 cmdp = cmdlookup(name, 0);
Eric Andersen62483552001-07-10 06:09:16 +00003499 if (cmdp) printentry(cmdp, verbose=='v');
Eric Andersencb57d552001-06-28 07:25:16 +00003500 flushall();
3501 }
Eric Andersencb57d552001-06-28 07:25:16 +00003502 }
3503 return c;
3504}
3505
Eric Andersencb57d552001-06-28 07:25:16 +00003506static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003507printentry(struct tblentry *cmdp, int verbose)
3508{
Eric Andersencb57d552001-06-28 07:25:16 +00003509 int idx;
3510 const char *path;
3511 char *name;
3512
Eric Andersen62483552001-07-10 06:09:16 +00003513 printf("%s%s", cmdp->cmdname, (verbose ? " is " : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00003514 if (cmdp->cmdtype == CMDNORMAL) {
3515 idx = cmdp->param.index;
3516 path = pathval();
3517 do {
3518 name = padvance(&path, cmdp->cmdname);
3519 stunalloc(name);
3520 } while (--idx >= 0);
Eric Andersen62483552001-07-10 06:09:16 +00003521 if(verbose)
3522 out1str(name);
Eric Andersencb57d552001-06-28 07:25:16 +00003523 } else if (cmdp->cmdtype == CMDBUILTIN) {
Eric Andersen62483552001-07-10 06:09:16 +00003524 if(verbose)
3525 out1str("a shell builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00003526 } else if (cmdp->cmdtype == CMDFUNCTION) {
Eric Andersencb57d552001-06-28 07:25:16 +00003527 if (verbose) {
3528 INTOFF;
Eric Andersen62483552001-07-10 06:09:16 +00003529 out1str("a function\n");
Eric Andersencb57d552001-06-28 07:25:16 +00003530 name = commandtext(cmdp->param.func);
Eric Andersen62483552001-07-10 06:09:16 +00003531 printf("%s() {\n %s\n}", cmdp->cmdname, name);
Aaron Lehmann49c024a2002-08-02 06:39:47 +00003532 free(name);
Eric Andersencb57d552001-06-28 07:25:16 +00003533 INTON;
3534 }
3535#ifdef DEBUG
3536 } else {
3537 error("internal error: cmdtype %d", cmdp->cmdtype);
3538#endif
3539 }
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003540 puts(cmdp->rehash ? "*" : nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +00003541}
3542
3543
3544
Eric Andersen1c039232001-07-07 00:05:55 +00003545/*** List the available builtins ***/
3546
3547
3548static int helpcmd(int argc, char** argv)
3549{
3550 int col, i;
Eric Andersen1c039232001-07-07 00:05:55 +00003551
Eric Andersen62483552001-07-10 06:09:16 +00003552 printf("\nBuilt-in commands:\n-------------------\n");
3553 for (col=0, i=0; i < NUMBUILTINS; i++) {
3554 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3555 builtincmds[i].name+1);
Eric Andersen1c039232001-07-07 00:05:55 +00003556 if (col > 60) {
3557 printf("\n");
3558 col = 0;
3559 }
3560 }
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003561#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Eric Andersen1c039232001-07-07 00:05:55 +00003562 {
Eric Andersen1c039232001-07-07 00:05:55 +00003563 extern const struct BB_applet applets[];
3564 extern const size_t NUM_APPLETS;
3565
Eric Andersen62483552001-07-10 06:09:16 +00003566 for (i=0; i < NUM_APPLETS; i++) {
3567
3568 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3569 applets[i].name);
Eric Andersen1c039232001-07-07 00:05:55 +00003570 if (col > 60) {
3571 printf("\n");
3572 col = 0;
3573 }
3574 }
3575 }
3576#endif
3577 printf("\n\n");
3578 return EXIT_SUCCESS;
3579}
3580
Eric Andersencb57d552001-06-28 07:25:16 +00003581/*
3582 * Resolve a command name. If you change this routine, you may have to
3583 * change the shellexec routine as well.
3584 */
3585
Eric Andersen2870d962001-07-02 17:27:21 +00003586static int prefix (const char *, const char *);
3587
Eric Andersencb57d552001-06-28 07:25:16 +00003588static void
Eric Andersen2870d962001-07-02 17:27:21 +00003589find_command(const char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003590{
3591 struct tblentry *cmdp;
3592 int idx;
3593 int prev;
3594 char *fullname;
3595 struct stat statb;
3596 int e;
3597 int bltin;
3598 int firstchange;
3599 int updatetbl;
Eric Andersen62483552001-07-10 06:09:16 +00003600 int regular;
Eric Andersencb57d552001-06-28 07:25:16 +00003601 struct builtincmd *bcmd;
3602
3603 /* If name contains a slash, don't use the hash table */
3604 if (strchr(name, '/') != NULL) {
3605 if (act & DO_ABS) {
3606 while (stat(name, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003607 if (errno != ENOENT && errno != ENOTDIR)
3608 e = errno;
3609 entry->cmdtype = CMDUNKNOWN;
3610 entry->u.index = -1;
3611 return;
3612 }
3613 entry->cmdtype = CMDNORMAL;
3614 entry->u.index = -1;
3615 return;
3616 }
3617 entry->cmdtype = CMDNORMAL;
3618 entry->u.index = 0;
3619 return;
3620 }
3621
3622 updatetbl = 1;
3623 if (act & DO_BRUTE) {
3624 firstchange = path_change(path, &bltin);
3625 } else {
3626 bltin = builtinloc;
3627 firstchange = 9999;
3628 }
3629
3630 /* If name is in the table, and not invalidated by cd, we're done */
3631 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
3632 if (cmdp->cmdtype == CMDFUNCTION) {
3633 if (act & DO_NOFUN) {
3634 updatetbl = 0;
3635 } else {
3636 goto success;
3637 }
3638 } else if (act & DO_BRUTE) {
3639 if ((cmdp->cmdtype == CMDNORMAL &&
3640 cmdp->param.index >= firstchange) ||
3641 (cmdp->cmdtype == CMDBUILTIN &&
3642 ((builtinloc < 0 && bltin >= 0) ?
3643 bltin : builtinloc) >= firstchange)) {
3644 /* need to recompute the entry */
3645 } else {
3646 goto success;
3647 }
3648 } else {
3649 goto success;
3650 }
3651 }
3652
3653 bcmd = find_builtin(name);
Eric Andersen2870d962001-07-02 17:27:21 +00003654 regular = bcmd && IS_BUILTIN_REGULAR(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00003655
3656 if (regular) {
3657 if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) {
Eric Andersen2870d962001-07-02 17:27:21 +00003658 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003659 }
3660 } else if (act & DO_BRUTE) {
3661 if (firstchange == 0) {
3662 updatetbl = 0;
3663 }
3664 }
3665
3666 /* If %builtin not in path, check for builtin next */
3667 if (regular || (bltin < 0 && bcmd)) {
3668builtin:
3669 if (!updatetbl) {
3670 entry->cmdtype = CMDBUILTIN;
3671 entry->u.cmd = bcmd;
3672 return;
3673 }
3674 INTOFF;
3675 cmdp = cmdlookup(name, 1);
3676 cmdp->cmdtype = CMDBUILTIN;
3677 cmdp->param.cmd = bcmd;
3678 INTON;
3679 goto success;
3680 }
3681
3682 /* We have to search path. */
Eric Andersen2870d962001-07-02 17:27:21 +00003683 prev = -1; /* where to start */
3684 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00003685 if (cmdp->cmdtype == CMDBUILTIN)
3686 prev = builtinloc;
3687 else
3688 prev = cmdp->param.index;
3689 }
3690
3691 e = ENOENT;
3692 idx = -1;
3693loop:
3694 while ((fullname = padvance(&path, name)) != NULL) {
3695 stunalloc(fullname);
3696 idx++;
3697 if (idx >= firstchange) {
3698 updatetbl = 0;
3699 }
3700 if (pathopt) {
3701 if (prefix("builtin", pathopt)) {
3702 if ((bcmd = find_builtin(name))) {
3703 goto builtin;
3704 }
3705 continue;
3706 } else if (!(act & DO_NOFUN) &&
3707 prefix("func", pathopt)) {
3708 /* handled below */
3709 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00003710 continue; /* ignore unimplemented options */
Eric Andersencb57d552001-06-28 07:25:16 +00003711 }
3712 }
3713 /* if rehash, don't redo absolute path names */
3714 if (fullname[0] == '/' && idx <= prev &&
3715 idx < firstchange) {
3716 if (idx < prev)
3717 continue;
3718 TRACE(("searchexec \"%s\": no change\n", name));
3719 goto success;
3720 }
3721 while (stat(fullname, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003722 if (errno != ENOENT && errno != ENOTDIR)
3723 e = errno;
3724 goto loop;
3725 }
Eric Andersen2870d962001-07-02 17:27:21 +00003726 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00003727 if (!S_ISREG(statb.st_mode))
3728 continue;
Eric Andersen2870d962001-07-02 17:27:21 +00003729 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00003730 stalloc(strlen(fullname) + 1);
3731 readcmdfile(fullname);
3732 if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
3733 error("%s not defined in %s", name, fullname);
3734 stunalloc(fullname);
3735 goto success;
3736 }
Eric Andersencb57d552001-06-28 07:25:16 +00003737 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
3738 /* If we aren't called with DO_BRUTE and cmdp is set, it must
3739 be a function and we're being called with DO_NOFUN */
3740 if (!updatetbl) {
3741 entry->cmdtype = CMDNORMAL;
3742 entry->u.index = idx;
3743 return;
3744 }
3745 INTOFF;
3746 cmdp = cmdlookup(name, 1);
3747 cmdp->cmdtype = CMDNORMAL;
3748 cmdp->param.index = idx;
3749 INTON;
3750 goto success;
3751 }
3752
3753 /* We failed. If there was an entry for this command, delete it */
3754 if (cmdp && updatetbl)
3755 delete_cmd_entry();
3756 if (act & DO_ERR)
Eric Andersen3102ac42001-07-06 04:26:23 +00003757 out2fmt("%s: %s\n", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00003758 entry->cmdtype = CMDUNKNOWN;
3759 return;
3760
3761success:
3762 cmdp->rehash = 0;
3763 entry->cmdtype = cmdp->cmdtype;
3764 entry->u = cmdp->param;
3765}
3766
3767
3768
3769/*
3770 * Search the table of builtin commands.
3771 */
3772
Eric Andersen2870d962001-07-02 17:27:21 +00003773static int
3774bstrcmp(const void *name, const void *b)
3775{
3776 return strcmp((const char *)name, (*(const char *const *) b)+1);
3777}
3778
3779static struct builtincmd *
3780find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00003781{
3782 struct builtincmd *bp;
3783
Eric Andersen2870d962001-07-02 17:27:21 +00003784 bp = bsearch(name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd),
3785 bstrcmp
Eric Andersencb57d552001-06-28 07:25:16 +00003786 );
3787 return bp;
3788}
3789
3790
3791/*
3792 * Called when a cd is done. Marks all commands so the next time they
3793 * are executed they will be rehashed.
3794 */
3795
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003796static inline void
3797hashcd(void)
3798{
Eric Andersencb57d552001-06-28 07:25:16 +00003799 struct tblentry **pp;
3800 struct tblentry *cmdp;
3801
3802 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3803 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3804 if (cmdp->cmdtype == CMDNORMAL
3805 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
3806 cmdp->rehash = 1;
3807 }
3808 }
3809}
3810
3811
3812
3813/*
3814 * Called before PATH is changed. The argument is the new value of PATH;
3815 * pathval() still returns the old value at this point. Called with
3816 * interrupts off.
3817 */
3818
3819static void
Eric Andersen2870d962001-07-02 17:27:21 +00003820changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00003821{
3822 int firstchange;
3823 int bltin;
3824
3825 firstchange = path_change(newval, &bltin);
3826 if (builtinloc < 0 && bltin >= 0)
Eric Andersen2870d962001-07-02 17:27:21 +00003827 builtinloc = bltin; /* zap builtins */
Eric Andersencb57d552001-06-28 07:25:16 +00003828 clearcmdentry(firstchange);
3829 builtinloc = bltin;
Eric Andersen1a923762002-06-06 12:07:28 +00003830 /* Ensure that getenv("PATH") stays current */
3831 setenv("PATH", newval, 1);
Eric Andersencb57d552001-06-28 07:25:16 +00003832}
3833
3834
3835/*
3836 * Clear out command entries. The argument specifies the first entry in
3837 * PATH which has changed.
3838 */
3839
3840static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003841clearcmdentry(int firstchange)
Eric Andersencb57d552001-06-28 07:25:16 +00003842{
3843 struct tblentry **tblp;
3844 struct tblentry **pp;
3845 struct tblentry *cmdp;
3846
3847 INTOFF;
3848 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
3849 pp = tblp;
3850 while ((cmdp = *pp) != NULL) {
3851 if ((cmdp->cmdtype == CMDNORMAL &&
3852 cmdp->param.index >= firstchange)
3853 || (cmdp->cmdtype == CMDBUILTIN &&
3854 builtinloc >= firstchange)) {
3855 *pp = cmdp->next;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00003856 free(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00003857 } else {
3858 pp = &cmdp->next;
3859 }
3860 }
3861 }
3862 INTON;
3863}
3864
3865
3866/*
3867 * Delete all functions.
3868 */
3869
Eric Andersencb57d552001-06-28 07:25:16 +00003870static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003871deletefuncs(void)
3872{
Eric Andersencb57d552001-06-28 07:25:16 +00003873 struct tblentry **tblp;
3874 struct tblentry **pp;
3875 struct tblentry *cmdp;
3876
3877 INTOFF;
3878 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
3879 pp = tblp;
3880 while ((cmdp = *pp) != NULL) {
3881 if (cmdp->cmdtype == CMDFUNCTION) {
3882 *pp = cmdp->next;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00003883 free(cmdp->param.func);
3884 free(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00003885 } else {
3886 pp = &cmdp->next;
3887 }
3888 }
3889 }
3890 INTON;
3891}
3892
3893
3894
3895/*
3896 * Locate a command in the command hash table. If "add" is nonzero,
3897 * add the command to the table if it is not already present. The
3898 * variable "lastcmdentry" is set to point to the address of the link
3899 * pointing to the entry, so that delete_cmd_entry can delete the
3900 * entry.
3901 */
3902
Eric Andersen2870d962001-07-02 17:27:21 +00003903static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00003904
3905static struct tblentry *
Eric Andersen2870d962001-07-02 17:27:21 +00003906cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00003907{
3908 int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00003909 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00003910 struct tblentry *cmdp;
3911 struct tblentry **pp;
3912
3913 p = name;
3914 hashval = *p << 4;
3915 while (*p)
3916 hashval += *p++;
3917 hashval &= 0x7FFF;
3918 pp = &cmdtable[hashval % CMDTABLESIZE];
3919 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3920 if (equal(cmdp->cmdname, name))
3921 break;
3922 pp = &cmdp->next;
3923 }
3924 if (add && cmdp == NULL) {
3925 INTOFF;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003926 cmdp = *pp = xmalloc(sizeof (struct tblentry) - ARB
Eric Andersencb57d552001-06-28 07:25:16 +00003927 + strlen(name) + 1);
3928 cmdp->next = NULL;
3929 cmdp->cmdtype = CMDUNKNOWN;
3930 cmdp->rehash = 0;
3931 strcpy(cmdp->cmdname, name);
3932 INTON;
3933 }
3934 lastcmdentry = pp;
3935 return cmdp;
3936}
3937
3938/*
3939 * Delete the command entry returned on the last lookup.
3940 */
3941
3942static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003943delete_cmd_entry()
3944{
Eric Andersencb57d552001-06-28 07:25:16 +00003945 struct tblentry *cmdp;
3946
3947 INTOFF;
3948 cmdp = *lastcmdentry;
3949 *lastcmdentry = cmdp->next;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00003950 free(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00003951 INTON;
3952}
3953
3954
3955
Eric Andersencb57d552001-06-28 07:25:16 +00003956
3957
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003958static const unsigned char nodesize[26] = {
Eric Andersen62483552001-07-10 06:09:16 +00003959 ALIGN(sizeof (struct nbinary)),
3960 ALIGN(sizeof (struct ncmd)),
3961 ALIGN(sizeof (struct npipe)),
3962 ALIGN(sizeof (struct nredir)),
3963 ALIGN(sizeof (struct nredir)),
3964 ALIGN(sizeof (struct nredir)),
3965 ALIGN(sizeof (struct nbinary)),
3966 ALIGN(sizeof (struct nbinary)),
3967 ALIGN(sizeof (struct nif)),
3968 ALIGN(sizeof (struct nbinary)),
3969 ALIGN(sizeof (struct nbinary)),
3970 ALIGN(sizeof (struct nfor)),
3971 ALIGN(sizeof (struct ncase)),
3972 ALIGN(sizeof (struct nclist)),
3973 ALIGN(sizeof (struct narg)),
3974 ALIGN(sizeof (struct narg)),
3975 ALIGN(sizeof (struct nfile)),
3976 ALIGN(sizeof (struct nfile)),
3977 ALIGN(sizeof (struct nfile)),
3978 ALIGN(sizeof (struct nfile)),
3979 ALIGN(sizeof (struct nfile)),
3980 ALIGN(sizeof (struct ndup)),
3981 ALIGN(sizeof (struct ndup)),
3982 ALIGN(sizeof (struct nhere)),
3983 ALIGN(sizeof (struct nhere)),
3984 ALIGN(sizeof (struct nnot)),
3985};
Eric Andersencb57d552001-06-28 07:25:16 +00003986
Eric Andersencb57d552001-06-28 07:25:16 +00003987
3988
3989/*
3990 * Delete a function if it exists.
3991 */
3992
3993static void
Eric Andersen2870d962001-07-02 17:27:21 +00003994unsetfunc(char *name)
3995{
Eric Andersencb57d552001-06-28 07:25:16 +00003996 struct tblentry *cmdp;
3997
3998 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
Aaron Lehmann49c024a2002-08-02 06:39:47 +00003999 free(cmdp->param.func);
Eric Andersencb57d552001-06-28 07:25:16 +00004000 delete_cmd_entry();
4001 }
4002}
4003
Eric Andersen2870d962001-07-02 17:27:21 +00004004
4005/*
Eric Andersencb57d552001-06-28 07:25:16 +00004006 * Locate and print what a word is...
4007 */
4008
4009static int
Eric Andersen62483552001-07-10 06:09:16 +00004010typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004011{
4012 int i;
4013 int err = 0;
Eric Andersen62483552001-07-10 06:09:16 +00004014 char *argv_a[2];
4015
4016 argv_a[1] = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004017
4018 for (i = 1; i < argc; i++) {
Eric Andersen62483552001-07-10 06:09:16 +00004019 argv_a[0] = argv[i];
4020 argptr = argv_a;
4021 optptr = "v";
4022 err |= hashcmd(argc, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00004023 }
4024 return err;
4025}
4026
Eric Andersend35c5df2002-01-09 15:37:36 +00004027#ifdef CONFIG_ASH_CMDCMD
Eric Andersencb57d552001-06-28 07:25:16 +00004028static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004029commandcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004030{
4031 int c;
4032 int default_path = 0;
4033 int verify_only = 0;
4034 int verbose_verify_only = 0;
4035
4036 while ((c = nextopt("pvV")) != '\0')
4037 switch (c) {
4038 case 'p':
4039 default_path = 1;
4040 break;
4041 case 'v':
4042 verify_only = 1;
4043 break;
4044 case 'V':
4045 verbose_verify_only = 1;
4046 break;
Eric Andersencb57d552001-06-28 07:25:16 +00004047 }
4048
4049 if (default_path + verify_only + verbose_verify_only > 1 ||
4050 !*argptr) {
Eric Andersen62483552001-07-10 06:09:16 +00004051 out2str(
4052 "command [-p] command [arg ...]\n"
4053 "command {-v|-V} command\n");
Eric Andersencb57d552001-06-28 07:25:16 +00004054 return EX_USAGE;
4055 }
4056
Eric Andersencb57d552001-06-28 07:25:16 +00004057 if (verify_only || verbose_verify_only) {
Eric Andersen62483552001-07-10 06:09:16 +00004058 char *argv_a[2];
4059
4060 argv_a[1] = 0;
4061 argv_a[0] = *argptr;
4062 argptr = argv_a;
4063 optptr = verbose_verify_only ? "v" : "V"; /* reverse special */
4064 return hashcmd(argc, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00004065 }
Eric Andersencb57d552001-06-28 07:25:16 +00004066
4067 return 0;
4068}
Eric Andersen2870d962001-07-02 17:27:21 +00004069#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004070
4071static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004072path_change(const char *newval, int *bltin)
Eric Andersencb57d552001-06-28 07:25:16 +00004073{
4074 const char *old, *new;
4075 int idx;
4076 int firstchange;
4077
4078 old = pathval();
4079 new = newval;
Eric Andersen2870d962001-07-02 17:27:21 +00004080 firstchange = 9999; /* assume no change */
Eric Andersencb57d552001-06-28 07:25:16 +00004081 idx = 0;
4082 *bltin = -1;
4083 for (;;) {
4084 if (*old != *new) {
4085 firstchange = idx;
4086 if ((*old == '\0' && *new == ':')
4087 || (*old == ':' && *new == '\0'))
4088 firstchange++;
Eric Andersen2870d962001-07-02 17:27:21 +00004089 old = new; /* ignore subsequent differences */
Eric Andersencb57d552001-06-28 07:25:16 +00004090 }
4091 if (*new == '\0')
4092 break;
4093 if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1))
4094 *bltin = idx;
4095 if (*new == ':') {
4096 idx++;
4097 }
4098 new++, old++;
4099 }
4100 if (builtinloc >= 0 && *bltin < 0)
4101 firstchange = 0;
4102 return firstchange;
4103}
Eric Andersencb57d552001-06-28 07:25:16 +00004104/*
4105 * Routines to expand arguments to commands. We have to deal with
4106 * backquotes, shell variables, and file metacharacters.
4107 */
4108/*
4109 * _rmescape() flags
4110 */
Eric Andersen2870d962001-07-02 17:27:21 +00004111#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4112#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Eric Andersencb57d552001-06-28 07:25:16 +00004113
4114/*
4115 * Structure specifying which parts of the string should be searched
4116 * for IFS characters.
4117 */
4118
4119struct ifsregion {
Eric Andersen2870d962001-07-02 17:27:21 +00004120 struct ifsregion *next; /* next region in list */
4121 int begoff; /* offset of start of region */
4122 int endoff; /* offset of end of region */
4123 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004124};
4125
4126
Eric Andersen2870d962001-07-02 17:27:21 +00004127static char *expdest; /* output of current string */
4128static struct nodelist *argbackq; /* list of back quote expressions */
4129static struct ifsregion ifsfirst; /* first struct in list of ifs regions */
4130static struct ifsregion *ifslastp; /* last struct in list */
4131static struct arglist exparg; /* holds expanded arg list */
Eric Andersencb57d552001-06-28 07:25:16 +00004132
Eric Andersen2870d962001-07-02 17:27:21 +00004133static void argstr (char *, int);
4134static char *exptilde (char *, int);
4135static void expbackq (union node *, int, int);
4136static int subevalvar (char *, char *, int, int, int, int, int);
Eric Andersen2870d962001-07-02 17:27:21 +00004137static int varisset (char *, int);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004138static void strtodest (const char *, int, int);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004139static inline void varvalue (char *, int, int);
Eric Andersen2870d962001-07-02 17:27:21 +00004140static void recordregion (int, int, int);
4141static void removerecordregions (int);
4142static void ifsbreakup (char *, struct arglist *);
4143static void ifsfree (void);
4144static void expandmeta (struct strlist *, int);
Eric Andersen62483552001-07-10 06:09:16 +00004145#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00004146#define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB)
4147#if !defined(GLOB_BROKEN)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004148static inline void addglob (const glob_t *);
Eric Andersencb57d552001-06-28 07:25:16 +00004149#endif
4150#endif
Eric Andersen62483552001-07-10 06:09:16 +00004151#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersen2870d962001-07-02 17:27:21 +00004152static void expmeta (char *, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004153#endif
Eric Andersen62483552001-07-10 06:09:16 +00004154#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersen2870d962001-07-02 17:27:21 +00004155static struct strlist *expsort (struct strlist *);
4156static struct strlist *msort (struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004157#endif
Eric Andersen2870d962001-07-02 17:27:21 +00004158static int patmatch (char *, char *, int);
Eric Andersen62483552001-07-10 06:09:16 +00004159#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00004160static int patmatch2 (char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004161#else
Eric Andersen2870d962001-07-02 17:27:21 +00004162static int pmatch (char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004163#define patmatch2 patmatch
4164#endif
Eric Andersen2870d962001-07-02 17:27:21 +00004165static char *cvtnum (int, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004166
4167/*
4168 * Expand shell variables and backquotes inside a here document.
4169 */
4170
Eric Andersen2870d962001-07-02 17:27:21 +00004171/* arg: the document, fd: where to write the expanded version */
Eric Andersen62483552001-07-10 06:09:16 +00004172static inline void
Eric Andersen2870d962001-07-02 17:27:21 +00004173expandhere(union node *arg, int fd)
4174{
Eric Andersencb57d552001-06-28 07:25:16 +00004175 herefd = fd;
4176 expandarg(arg, (struct arglist *)NULL, 0);
4177 xwrite(fd, stackblock(), expdest - stackblock());
4178}
4179
4180
4181/*
4182 * Perform variable substitution and command substitution on an argument,
4183 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4184 * perform splitting and file name expansion. When arglist is NULL, perform
4185 * here document expansion.
4186 */
4187
4188static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004189expandarg(union node *arg, struct arglist *arglist, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004190{
4191 struct strlist *sp;
4192 char *p;
4193
4194 argbackq = arg->narg.backquote;
4195 STARTSTACKSTR(expdest);
4196 ifsfirst.next = NULL;
4197 ifslastp = NULL;
4198 argstr(arg->narg.text, flag);
4199 if (arglist == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00004200 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004201 }
4202 STPUTC('\0', expdest);
4203 p = grabstackstr(expdest);
4204 exparg.lastp = &exparg.list;
4205 /*
4206 * TODO - EXP_REDIR
4207 */
4208 if (flag & EXP_FULL) {
4209 ifsbreakup(p, &exparg);
4210 *exparg.lastp = NULL;
4211 exparg.lastp = &exparg.list;
4212 expandmeta(exparg.list, flag);
4213 } else {
4214 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4215 rmescapes(p);
4216 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4217 sp->text = p;
4218 *exparg.lastp = sp;
4219 exparg.lastp = &sp->next;
4220 }
4221 ifsfree();
4222 *exparg.lastp = NULL;
4223 if (exparg.list) {
4224 *arglist->lastp = exparg.list;
4225 arglist->lastp = exparg.lastp;
4226 }
4227}
4228
4229
Eric Andersen62483552001-07-10 06:09:16 +00004230/*
4231 * Expand a variable, and return a pointer to the next character in the
4232 * input string.
4233 */
4234
Eric Andersen74400cc2001-10-18 04:11:39 +00004235static inline char * evalvar(char *p, int flag)
Eric Andersen62483552001-07-10 06:09:16 +00004236{
4237 int subtype;
4238 int varflags;
4239 char *var;
4240 const char *val;
4241 int patloc;
4242 int c;
4243 int set;
4244 int special;
4245 int startloc;
4246 int varlen;
4247 int easy;
4248 int quotes = flag & (EXP_FULL | EXP_CASE);
4249
4250 varflags = *p++;
4251 subtype = varflags & VSTYPE;
4252 var = p;
4253 special = 0;
4254 if (! is_name(*p))
4255 special = 1;
4256 p = strchr(p, '=') + 1;
4257again: /* jump here after setting a variable with ${var=text} */
4258 if (special) {
4259 set = varisset(var, varflags & VSNUL);
4260 val = NULL;
4261 } else {
4262 val = lookupvar(var);
4263 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
4264 val = NULL;
4265 set = 0;
4266 } else
4267 set = 1;
4268 }
4269 varlen = 0;
4270 startloc = expdest - stackblock();
4271 if (set && subtype != VSPLUS) {
4272 /* insert the value of the variable */
4273 if (special) {
4274 varvalue(var, varflags & VSQUOTE, flag);
4275 if (subtype == VSLENGTH) {
4276 varlen = expdest - stackblock() - startloc;
4277 STADJUST(-varlen, expdest);
4278 }
4279 } else {
4280 if (subtype == VSLENGTH) {
4281 varlen = strlen(val);
4282 } else {
4283 strtodest(
4284 val,
4285 varflags & VSQUOTE ?
4286 DQSYNTAX : BASESYNTAX,
4287 quotes
4288 );
4289 }
4290 }
4291 }
4292
4293 if (subtype == VSPLUS)
4294 set = ! set;
4295
4296 easy = ((varflags & VSQUOTE) == 0 ||
4297 (*var == '@' && shellparam.nparam != 1));
4298
4299
4300 switch (subtype) {
4301 case VSLENGTH:
4302 expdest = cvtnum(varlen, expdest);
4303 goto record;
4304
4305 case VSNORMAL:
4306 if (!easy)
4307 break;
4308record:
4309 recordregion(startloc, expdest - stackblock(),
4310 varflags & VSQUOTE);
4311 break;
4312
4313 case VSPLUS:
4314 case VSMINUS:
4315 if (!set) {
4316 argstr(p, flag);
4317 break;
4318 }
4319 if (easy)
4320 goto record;
4321 break;
4322
4323 case VSTRIMLEFT:
4324 case VSTRIMLEFTMAX:
4325 case VSTRIMRIGHT:
4326 case VSTRIMRIGHTMAX:
4327 if (!set)
4328 break;
4329 /*
4330 * Terminate the string and start recording the pattern
4331 * right after it
4332 */
4333 STPUTC('\0', expdest);
4334 patloc = expdest - stackblock();
4335 if (subevalvar(p, NULL, patloc, subtype,
4336 startloc, varflags, quotes) == 0) {
4337 int amount = (expdest - stackblock() - patloc) + 1;
4338 STADJUST(-amount, expdest);
4339 }
4340 /* Remove any recorded regions beyond start of variable */
4341 removerecordregions(startloc);
4342 goto record;
4343
4344 case VSASSIGN:
4345 case VSQUESTION:
4346 if (!set) {
4347 if (subevalvar(p, var, 0, subtype, startloc,
4348 varflags, quotes)) {
4349 varflags &= ~VSNUL;
4350 /*
4351 * Remove any recorded regions beyond
4352 * start of variable
4353 */
4354 removerecordregions(startloc);
4355 goto again;
4356 }
4357 break;
4358 }
4359 if (easy)
4360 goto record;
4361 break;
4362
4363#ifdef DEBUG
4364 default:
4365 abort();
4366#endif
4367 }
4368
4369 if (subtype != VSNORMAL) { /* skip to end of alternative */
4370 int nesting = 1;
4371 for (;;) {
4372 if ((c = *p++) == CTLESC)
4373 p++;
4374 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
4375 if (set)
4376 argbackq = argbackq->next;
4377 } else if (c == CTLVAR) {
4378 if ((*p++ & VSTYPE) != VSNORMAL)
4379 nesting++;
4380 } else if (c == CTLENDVAR) {
4381 if (--nesting == 0)
4382 break;
4383 }
4384 }
4385 }
4386 return p;
4387}
4388
Eric Andersencb57d552001-06-28 07:25:16 +00004389
4390/*
4391 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4392 * characters to allow for further processing. Otherwise treat
4393 * $@ like $* since no splitting will be performed.
4394 */
4395
4396static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004397argstr(char *p, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004398{
4399 char c;
Eric Andersen2870d962001-07-02 17:27:21 +00004400 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
Eric Andersencb57d552001-06-28 07:25:16 +00004401 int firsteq = 1;
4402
4403 if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
4404 p = exptilde(p, flag);
4405 for (;;) {
4406 switch (c = *p++) {
4407 case '\0':
4408 case CTLENDVAR: /* ??? */
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004409 return;
Eric Andersencb57d552001-06-28 07:25:16 +00004410 case CTLQUOTEMARK:
4411 /* "$@" syntax adherence hack */
4412 if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
4413 break;
4414 if ((flag & EXP_FULL) != 0)
4415 STPUTC(c, expdest);
4416 break;
4417 case CTLESC:
4418 if (quotes)
4419 STPUTC(c, expdest);
4420 c = *p++;
4421 STPUTC(c, expdest);
4422 break;
4423 case CTLVAR:
4424 p = evalvar(p, flag);
4425 break;
4426 case CTLBACKQ:
4427 case CTLBACKQ|CTLQUOTE:
4428 expbackq(argbackq->n, c & CTLQUOTE, flag);
4429 argbackq = argbackq->next;
4430 break;
Eric Andersend35c5df2002-01-09 15:37:36 +00004431#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +00004432 case CTLENDARI:
4433 expari(flag);
4434 break;
Eric Andersen2870d962001-07-02 17:27:21 +00004435#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004436 case ':':
4437 case '=':
4438 /*
4439 * sort of a hack - expand tildes in variable
4440 * assignments (after the first '=' and after ':'s).
4441 */
4442 STPUTC(c, expdest);
4443 if (flag & EXP_VARTILDE && *p == '~') {
4444 if (c == '=') {
4445 if (firsteq)
4446 firsteq = 0;
4447 else
4448 break;
4449 }
4450 p = exptilde(p, flag);
4451 }
4452 break;
4453 default:
4454 STPUTC(c, expdest);
4455 }
4456 }
Eric Andersencb57d552001-06-28 07:25:16 +00004457 return;
4458}
4459
4460static char *
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004461exptilde(char *p, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004462{
4463 char c, *startp = p;
4464 struct passwd *pw;
4465 const char *home;
4466 int quotes = flag & (EXP_FULL | EXP_CASE);
4467
4468 while ((c = *p) != '\0') {
4469 switch(c) {
4470 case CTLESC:
4471 return (startp);
4472 case CTLQUOTEMARK:
4473 return (startp);
4474 case ':':
4475 if (flag & EXP_VARTILDE)
4476 goto done;
4477 break;
4478 case '/':
4479 goto done;
4480 }
4481 p++;
4482 }
4483done:
4484 *p = '\0';
4485 if (*(startp+1) == '\0') {
4486 if ((home = lookupvar("HOME")) == NULL)
4487 goto lose;
4488 } else {
4489 if ((pw = getpwnam(startp+1)) == NULL)
4490 goto lose;
4491 home = pw->pw_dir;
4492 }
4493 if (*home == '\0')
4494 goto lose;
4495 *p = c;
4496 strtodest(home, SQSYNTAX, quotes);
4497 return (p);
4498lose:
4499 *p = c;
4500 return (startp);
4501}
4502
4503
Eric Andersen2870d962001-07-02 17:27:21 +00004504static void
4505removerecordregions(int endoff)
Eric Andersencb57d552001-06-28 07:25:16 +00004506{
4507 if (ifslastp == NULL)
4508 return;
4509
4510 if (ifsfirst.endoff > endoff) {
4511 while (ifsfirst.next != NULL) {
4512 struct ifsregion *ifsp;
4513 INTOFF;
4514 ifsp = ifsfirst.next->next;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00004515 free(ifsfirst.next);
Eric Andersencb57d552001-06-28 07:25:16 +00004516 ifsfirst.next = ifsp;
4517 INTON;
4518 }
4519 if (ifsfirst.begoff > endoff)
4520 ifslastp = NULL;
4521 else {
4522 ifslastp = &ifsfirst;
4523 ifsfirst.endoff = endoff;
4524 }
4525 return;
4526 }
Eric Andersen2870d962001-07-02 17:27:21 +00004527
Eric Andersencb57d552001-06-28 07:25:16 +00004528 ifslastp = &ifsfirst;
4529 while (ifslastp->next && ifslastp->next->begoff < endoff)
4530 ifslastp=ifslastp->next;
4531 while (ifslastp->next != NULL) {
4532 struct ifsregion *ifsp;
4533 INTOFF;
4534 ifsp = ifslastp->next->next;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00004535 free(ifslastp->next);
Eric Andersencb57d552001-06-28 07:25:16 +00004536 ifslastp->next = ifsp;
4537 INTON;
4538 }
4539 if (ifslastp->endoff > endoff)
4540 ifslastp->endoff = endoff;
4541}
4542
4543
Eric Andersend35c5df2002-01-09 15:37:36 +00004544#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +00004545/*
4546 * Expand arithmetic expression. Backup to start of expression,
4547 * evaluate, place result in (backed up) result, adjust string position.
4548 */
4549static void
Eric Andersen2870d962001-07-02 17:27:21 +00004550expari(int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004551{
4552 char *p, *start;
Eric Andersen34506362001-08-02 05:02:46 +00004553 int errcode;
Eric Andersencb57d552001-06-28 07:25:16 +00004554 int result;
4555 int begoff;
4556 int quotes = flag & (EXP_FULL | EXP_CASE);
4557 int quoted;
4558
Eric Andersen2870d962001-07-02 17:27:21 +00004559 /* ifsfree(); */
Eric Andersencb57d552001-06-28 07:25:16 +00004560
4561 /*
4562 * This routine is slightly over-complicated for
4563 * efficiency. First we make sure there is
4564 * enough space for the result, which may be bigger
4565 * than the expression if we add exponentation. Next we
4566 * scan backwards looking for the start of arithmetic. If the
4567 * next previous character is a CTLESC character, then we
4568 * have to rescan starting from the beginning since CTLESC
4569 * characters have to be processed left to right.
4570 */
4571 CHECKSTRSPACE(10, expdest);
4572 USTPUTC('\0', expdest);
4573 start = stackblock();
4574 p = expdest - 1;
4575 while (*p != CTLARI && p >= start)
4576 --p;
4577 if (*p != CTLARI)
4578 error("missing CTLARI (shouldn't happen)");
4579 if (p > start && *(p-1) == CTLESC)
4580 for (p = start; *p != CTLARI; p++)
4581 if (*p == CTLESC)
4582 p++;
4583
4584 if (p[1] == '"')
4585 quoted=1;
4586 else
4587 quoted=0;
4588 begoff = p - start;
4589 removerecordregions(begoff);
4590 if (quotes)
4591 rmescapes(p+2);
Eric Andersen34506362001-08-02 05:02:46 +00004592 result = arith(p+2, &errcode);
4593 if (errcode < 0) {
4594 if(errcode == -2)
4595 error("divide by zero");
4596 else
4597 error("syntax error: \"%s\"\n", p+2);
4598 }
Eric Andersen3102ac42001-07-06 04:26:23 +00004599 snprintf(p, 12, "%d", result);
Eric Andersencb57d552001-06-28 07:25:16 +00004600
4601 while (*p++)
4602 ;
4603
4604 if (quoted == 0)
4605 recordregion(begoff, p - 1 - start, 0);
4606 result = expdest - p + 1;
4607 STADJUST(-result, expdest);
4608}
Eric Andersen2870d962001-07-02 17:27:21 +00004609#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004610
4611/*
4612 * Expand stuff in backwards quotes.
4613 */
4614
4615static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004616expbackq(union node *cmd, int quoted, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004617{
4618 volatile struct backcmd in;
4619 int i;
4620 char buf[128];
4621 char *p;
4622 char *dest = expdest;
4623 volatile struct ifsregion saveifs;
4624 struct ifsregion *volatile savelastp;
4625 struct nodelist *volatile saveargbackq;
4626 char lastc;
4627 int startloc = dest - stackblock();
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004628 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +00004629 volatile int saveherefd;
4630 int quotes = flag & (EXP_FULL | EXP_CASE);
4631 struct jmploc jmploc;
4632 struct jmploc *volatile savehandler;
4633 int ex;
4634
4635#if __GNUC__
4636 /* Avoid longjmp clobbering */
4637 (void) &dest;
4638 (void) &syntax;
4639#endif
4640
4641 in.fd = -1;
4642 in.buf = 0;
4643 in.jp = 0;
4644
4645 INTOFF;
4646 saveifs = ifsfirst;
4647 savelastp = ifslastp;
4648 saveargbackq = argbackq;
4649 saveherefd = herefd;
4650 herefd = -1;
4651 if ((ex = setjmp(jmploc.loc))) {
4652 goto err1;
4653 }
4654 savehandler = handler;
4655 handler = &jmploc;
4656 INTON;
4657 p = grabstackstr(dest);
4658 evalbackcmd(cmd, (struct backcmd *) &in);
4659 ungrabstackstr(p, dest);
4660err1:
4661 INTOFF;
4662 ifsfirst = saveifs;
4663 ifslastp = savelastp;
4664 argbackq = saveargbackq;
4665 herefd = saveherefd;
4666 if (ex) {
4667 goto err2;
4668 }
4669
4670 p = in.buf;
4671 lastc = '\0';
4672 for (;;) {
4673 if (--in.nleft < 0) {
4674 if (in.fd < 0)
4675 break;
Eric Andersen7467c8d2001-07-12 20:26:32 +00004676 i = safe_read(in.fd, buf, sizeof buf);
Eric Andersencb57d552001-06-28 07:25:16 +00004677 TRACE(("expbackq: read returns %d\n", i));
4678 if (i <= 0)
4679 break;
4680 p = buf;
4681 in.nleft = i - 1;
4682 }
4683 lastc = *p++;
4684 if (lastc != '\0') {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004685 if (quotes && SIT(lastc, syntax) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +00004686 STPUTC(CTLESC, dest);
4687 STPUTC(lastc, dest);
4688 }
4689 }
4690
4691 /* Eat all trailing newlines */
4692 for (; dest > stackblock() && dest[-1] == '\n';)
4693 STUNPUTC(dest);
4694
4695err2:
4696 if (in.fd >= 0)
4697 close(in.fd);
Aaron Lehmann49c024a2002-08-02 06:39:47 +00004698 free(in.buf);
Eric Andersencb57d552001-06-28 07:25:16 +00004699 if (in.jp)
4700 exitstatus = waitforjob(in.jp);
4701 handler = savehandler;
4702 if (ex) {
4703 longjmp(handler->loc, 1);
4704 }
4705 if (quoted == 0)
4706 recordregion(startloc, dest - stackblock(), 0);
4707 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4708 (dest - stackblock()) - startloc,
4709 (dest - stackblock()) - startloc,
4710 stackblock() + startloc));
4711 expdest = dest;
4712 INTON;
4713}
4714
Eric Andersencb57d552001-06-28 07:25:16 +00004715static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004716subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
Eric Andersencb57d552001-06-28 07:25:16 +00004717{
4718 char *startp;
4719 char *loc = NULL;
4720 char *q;
4721 int c = 0;
4722 int saveherefd = herefd;
4723 struct nodelist *saveargbackq = argbackq;
4724 int amount;
4725
4726 herefd = -1;
4727 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
4728 STACKSTRNUL(expdest);
4729 herefd = saveherefd;
4730 argbackq = saveargbackq;
4731 startp = stackblock() + startloc;
4732 if (str == NULL)
4733 str = stackblock() + strloc;
4734
4735 switch (subtype) {
4736 case VSASSIGN:
4737 setvar(str, startp, 0);
4738 amount = startp - expdest;
4739 STADJUST(amount, expdest);
4740 varflags &= ~VSNUL;
4741 if (c != 0)
4742 *loc = c;
4743 return 1;
4744
4745 case VSQUESTION:
4746 if (*p != CTLENDVAR) {
Eric Andersen3102ac42001-07-06 04:26:23 +00004747 out2fmt(snlfmt, startp);
Eric Andersencb57d552001-06-28 07:25:16 +00004748 error((char *)NULL);
4749 }
4750 error("%.*s: parameter %snot set", p - str - 1,
4751 str, (varflags & VSNUL) ? "null or "
4752 : nullstr);
4753 /* NOTREACHED */
4754
4755 case VSTRIMLEFT:
4756 for (loc = startp; loc < str; loc++) {
4757 c = *loc;
4758 *loc = '\0';
4759 if (patmatch2(str, startp, quotes))
4760 goto recordleft;
4761 *loc = c;
4762 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00004763 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00004764 }
4765 return 0;
4766
4767 case VSTRIMLEFTMAX:
4768 for (loc = str - 1; loc >= startp;) {
4769 c = *loc;
4770 *loc = '\0';
4771 if (patmatch2(str, startp, quotes))
4772 goto recordleft;
4773 *loc = c;
4774 loc--;
4775 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
4776 for (q = startp; q < loc; q++)
4777 if (*q == CTLESC)
4778 q++;
4779 if (q > loc)
4780 loc--;
4781 }
4782 }
4783 return 0;
4784
4785 case VSTRIMRIGHT:
Eric Andersen2870d962001-07-02 17:27:21 +00004786 for (loc = str - 1; loc >= startp;) {
Eric Andersencb57d552001-06-28 07:25:16 +00004787 if (patmatch2(str, loc, quotes))
4788 goto recordright;
4789 loc--;
Eric Andersen2870d962001-07-02 17:27:21 +00004790 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
Eric Andersencb57d552001-06-28 07:25:16 +00004791 for (q = startp; q < loc; q++)
4792 if (*q == CTLESC)
4793 q++;
4794 if (q > loc)
4795 loc--;
4796 }
4797 }
4798 return 0;
4799
4800 case VSTRIMRIGHTMAX:
4801 for (loc = startp; loc < str - 1; loc++) {
4802 if (patmatch2(str, loc, quotes))
4803 goto recordright;
4804 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00004805 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00004806 }
4807 return 0;
4808
4809#ifdef DEBUG
4810 default:
4811 abort();
4812#endif
4813 }
4814
4815recordleft:
4816 *loc = c;
4817 amount = ((str - 1) - (loc - startp)) - expdest;
4818 STADJUST(amount, expdest);
4819 while (loc != str - 1)
4820 *startp++ = *loc++;
4821 return 1;
4822
4823recordright:
4824 amount = loc - expdest;
4825 STADJUST(amount, expdest);
4826 STPUTC('\0', expdest);
4827 STADJUST(-1, expdest);
4828 return 1;
4829}
4830
4831
4832/*
Eric Andersencb57d552001-06-28 07:25:16 +00004833 * Test whether a specialized variable is set.
4834 */
4835
4836static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004837varisset(char *name, int nulok)
Eric Andersencb57d552001-06-28 07:25:16 +00004838{
4839 if (*name == '!')
4840 return backgndpid != -1;
4841 else if (*name == '@' || *name == '*') {
4842 if (*shellparam.p == NULL)
4843 return 0;
4844
4845 if (nulok) {
4846 char **av;
4847
4848 for (av = shellparam.p; *av; av++)
4849 if (**av != '\0')
4850 return 1;
4851 return 0;
4852 }
4853 } else if (is_digit(*name)) {
4854 char *ap;
4855 int num = atoi(name);
4856
4857 if (num > shellparam.nparam)
4858 return 0;
4859
4860 if (num == 0)
4861 ap = arg0;
4862 else
4863 ap = shellparam.p[num - 1];
4864
4865 if (nulok && (ap == NULL || *ap == '\0'))
4866 return 0;
4867 }
4868 return 1;
4869}
4870
Eric Andersencb57d552001-06-28 07:25:16 +00004871/*
4872 * Put a string on the stack.
4873 */
4874
4875static void
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004876strtodest(const char *p, int syntax, int quotes)
Eric Andersencb57d552001-06-28 07:25:16 +00004877{
4878 while (*p) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004879 if (quotes && SIT(*p,syntax) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +00004880 STPUTC(CTLESC, expdest);
4881 STPUTC(*p++, expdest);
4882 }
4883}
4884
Eric Andersencb57d552001-06-28 07:25:16 +00004885/*
4886 * Add the value of a specialized variable to the stack string.
4887 */
4888
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004889static inline void
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004890varvalue(char *name, int quoted, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00004891{
4892 int num;
4893 char *p;
4894 int i;
4895 int sep;
4896 int sepq = 0;
4897 char **ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004898 int syntax;
Eric Andersencb57d552001-06-28 07:25:16 +00004899 int allow_split = flags & EXP_FULL;
4900 int quotes = flags & (EXP_FULL | EXP_CASE);
4901
4902 syntax = quoted ? DQSYNTAX : BASESYNTAX;
4903 switch (*name) {
4904 case '$':
4905 num = rootpid;
4906 goto numvar;
4907 case '?':
4908 num = oexitstatus;
4909 goto numvar;
4910 case '#':
4911 num = shellparam.nparam;
4912 goto numvar;
4913 case '!':
4914 num = backgndpid;
4915numvar:
4916 expdest = cvtnum(num, expdest);
4917 break;
4918 case '-':
4919 for (i = 0 ; i < NOPTS ; i++) {
Eric Andersen2870d962001-07-02 17:27:21 +00004920 if (optent_val(i))
4921 STPUTC(optent_letter(optlist[i]), expdest);
Eric Andersencb57d552001-06-28 07:25:16 +00004922 }
4923 break;
4924 case '@':
4925 if (allow_split && quoted) {
4926 sep = 1 << CHAR_BIT;
4927 goto param;
4928 }
4929 /* fall through */
4930 case '*':
4931 sep = ifsset() ? ifsval()[0] : ' ';
4932 if (quotes) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004933 sepq = SIT(sep,syntax) == CCTL;
Eric Andersencb57d552001-06-28 07:25:16 +00004934 }
4935param:
4936 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
4937 strtodest(p, syntax, quotes);
4938 if (*ap && sep) {
4939 if (sepq)
4940 STPUTC(CTLESC, expdest);
4941 STPUTC(sep, expdest);
4942 }
4943 }
4944 break;
4945 case '0':
4946 strtodest(arg0, syntax, quotes);
4947 break;
4948 default:
4949 num = atoi(name);
4950 if (num > 0 && num <= shellparam.nparam) {
4951 strtodest(shellparam.p[num - 1], syntax, quotes);
4952 }
4953 break;
4954 }
4955}
4956
4957
Eric Andersencb57d552001-06-28 07:25:16 +00004958/*
4959 * Record the fact that we have to scan this region of the
4960 * string for IFS characters.
4961 */
4962
4963static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004964recordregion(int start, int end, int nulonly)
Eric Andersencb57d552001-06-28 07:25:16 +00004965{
4966 struct ifsregion *ifsp;
4967
4968 if (ifslastp == NULL) {
4969 ifsp = &ifsfirst;
4970 } else {
4971 INTOFF;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004972 ifsp = (struct ifsregion *)xmalloc(sizeof (struct ifsregion));
Eric Andersencb57d552001-06-28 07:25:16 +00004973 ifsp->next = NULL;
4974 ifslastp->next = ifsp;
4975 INTON;
4976 }
4977 ifslastp = ifsp;
4978 ifslastp->begoff = start;
4979 ifslastp->endoff = end;
4980 ifslastp->nulonly = nulonly;
4981}
4982
4983
4984
4985/*
4986 * Break the argument string into pieces based upon IFS and add the
4987 * strings to the argument list. The regions of the string to be
4988 * searched for IFS characters have been stored by recordregion.
4989 */
4990static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004991ifsbreakup(char *string, struct arglist *arglist)
4992{
Eric Andersencb57d552001-06-28 07:25:16 +00004993 struct ifsregion *ifsp;
4994 struct strlist *sp;
4995 char *start;
4996 char *p;
4997 char *q;
4998 const char *ifs, *realifs;
4999 int ifsspc;
5000 int nulonly;
5001
5002
5003 start = string;
5004 ifsspc = 0;
5005 nulonly = 0;
5006 realifs = ifsset() ? ifsval() : defifs;
5007 if (ifslastp != NULL) {
5008 ifsp = &ifsfirst;
5009 do {
5010 p = string + ifsp->begoff;
5011 nulonly = ifsp->nulonly;
5012 ifs = nulonly ? nullstr : realifs;
5013 ifsspc = 0;
5014 while (p < string + ifsp->endoff) {
5015 q = p;
5016 if (*p == CTLESC)
5017 p++;
5018 if (strchr(ifs, *p)) {
5019 if (!nulonly)
5020 ifsspc = (strchr(defifs, *p) != NULL);
5021 /* Ignore IFS whitespace at start */
5022 if (q == start && ifsspc) {
5023 p++;
5024 start = p;
5025 continue;
5026 }
5027 *q = '\0';
5028 sp = (struct strlist *)stalloc(sizeof *sp);
5029 sp->text = start;
5030 *arglist->lastp = sp;
5031 arglist->lastp = &sp->next;
5032 p++;
5033 if (!nulonly) {
5034 for (;;) {
5035 if (p >= string + ifsp->endoff) {
5036 break;
5037 }
5038 q = p;
5039 if (*p == CTLESC)
5040 p++;
5041 if (strchr(ifs, *p) == NULL ) {
5042 p = q;
5043 break;
5044 } else if (strchr(defifs, *p) == NULL) {
5045 if (ifsspc) {
5046 p++;
5047 ifsspc = 0;
5048 } else {
5049 p = q;
5050 break;
5051 }
5052 } else
5053 p++;
5054 }
5055 }
5056 start = p;
5057 } else
5058 p++;
5059 }
5060 } while ((ifsp = ifsp->next) != NULL);
5061 if (!(*start || (!ifsspc && start > string && nulonly))) {
5062 return;
5063 }
5064 }
5065
5066 sp = (struct strlist *)stalloc(sizeof *sp);
5067 sp->text = start;
5068 *arglist->lastp = sp;
5069 arglist->lastp = &sp->next;
5070}
5071
5072static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005073ifsfree(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005074{
5075 while (ifsfirst.next != NULL) {
5076 struct ifsregion *ifsp;
5077 INTOFF;
5078 ifsp = ifsfirst.next->next;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00005079 free(ifsfirst.next);
Eric Andersencb57d552001-06-28 07:25:16 +00005080 ifsfirst.next = ifsp;
5081 INTON;
5082 }
5083 ifslastp = NULL;
5084 ifsfirst.next = NULL;
5085}
5086
Eric Andersen2870d962001-07-02 17:27:21 +00005087/*
5088 * Add a file name to the list.
5089 */
Eric Andersencb57d552001-06-28 07:25:16 +00005090
Eric Andersen2870d962001-07-02 17:27:21 +00005091static void
5092addfname(const char *name)
5093{
Eric Andersen2870d962001-07-02 17:27:21 +00005094 struct strlist *sp;
5095
Eric Andersen2870d962001-07-02 17:27:21 +00005096 sp = (struct strlist *)stalloc(sizeof *sp);
Aaron Lehmann95877b62001-12-31 06:00:57 +00005097 sp->text = sstrdup(name);
Eric Andersen2870d962001-07-02 17:27:21 +00005098 *exparg.lastp = sp;
5099 exparg.lastp = &sp->next;
5100}
Eric Andersencb57d552001-06-28 07:25:16 +00005101
5102/*
5103 * Expand shell metacharacters. At this point, the only control characters
5104 * should be escapes. The results are stored in the list exparg.
5105 */
5106
Eric Andersen62483552001-07-10 06:09:16 +00005107#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00005108static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005109expandmeta(struct strlist *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005110{
5111 const char *p;
5112 glob_t pglob;
5113 /* TODO - EXP_REDIR */
5114
5115 while (str) {
5116 if (fflag)
5117 goto nometa;
5118 p = preglob(str->text);
5119 INTOFF;
Eric Andersen34506362001-08-02 05:02:46 +00005120 switch (glob(p, 0, 0, &pglob)) {
Eric Andersencb57d552001-06-28 07:25:16 +00005121 case 0:
Eric Andersen34506362001-08-02 05:02:46 +00005122 if(pglob.gl_pathv[1]==0 && !strcmp(p, pglob.gl_pathv[0]))
Eric Andersencb57d552001-06-28 07:25:16 +00005123 goto nometa2;
5124 addglob(&pglob);
5125 globfree(&pglob);
5126 INTON;
5127 break;
5128 case GLOB_NOMATCH:
5129nometa2:
5130 globfree(&pglob);
5131 INTON;
5132nometa:
5133 *exparg.lastp = str;
5134 rmescapes(str->text);
5135 exparg.lastp = &str->next;
5136 break;
Eric Andersen2870d962001-07-02 17:27:21 +00005137 default: /* GLOB_NOSPACE */
Eric Andersencb57d552001-06-28 07:25:16 +00005138 error("Out of space");
5139 }
5140 str = str->next;
5141 }
5142}
5143
5144
5145/*
5146 * Add the result of glob(3) to the list.
5147 */
5148
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005149static inline void
5150addglob(const glob_t *pglob)
Eric Andersencb57d552001-06-28 07:25:16 +00005151{
5152 char **p = pglob->gl_pathv;
5153
5154 do {
5155 addfname(*p);
5156 } while (*++p);
5157}
5158
5159
Eric Andersen2870d962001-07-02 17:27:21 +00005160#else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005161static char *expdir;
5162
5163
5164static void
Eric Andersenceef50b2001-12-21 11:22:26 +00005165expandmeta(struct strlist *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005166{
5167 char *p;
5168 struct strlist **savelastp;
5169 struct strlist *sp;
5170 char c;
5171 /* TODO - EXP_REDIR */
5172
5173 while (str) {
5174 if (fflag)
5175 goto nometa;
5176 p = str->text;
Eric Andersen2870d962001-07-02 17:27:21 +00005177 for (;;) { /* fast check for meta chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005178 if ((c = *p++) == '\0')
5179 goto nometa;
5180 if (c == '*' || c == '?' || c == '[' || c == '!')
5181 break;
5182 }
5183 savelastp = exparg.lastp;
5184 INTOFF;
5185 if (expdir == NULL) {
5186 int i = strlen(str->text);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005187 expdir = xmalloc(i < 2048 ? 2048 : i); /* XXX */
Eric Andersencb57d552001-06-28 07:25:16 +00005188 }
5189
5190 expmeta(expdir, str->text);
Aaron Lehmann49c024a2002-08-02 06:39:47 +00005191 free(expdir);
Eric Andersencb57d552001-06-28 07:25:16 +00005192 expdir = NULL;
5193 INTON;
5194 if (exparg.lastp == savelastp) {
5195 /*
5196 * no matches
5197 */
5198nometa:
5199 *exparg.lastp = str;
5200 rmescapes(str->text);
5201 exparg.lastp = &str->next;
5202 } else {
5203 *exparg.lastp = NULL;
5204 *savelastp = sp = expsort(*savelastp);
5205 while (sp->next != NULL)
5206 sp = sp->next;
5207 exparg.lastp = &sp->next;
5208 }
5209 str = str->next;
5210 }
5211}
5212
5213
5214/*
5215 * Do metacharacter (i.e. *, ?, [...]) expansion.
5216 */
5217
5218static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005219expmeta(char *enddir, char *name)
5220{
Eric Andersencb57d552001-06-28 07:25:16 +00005221 char *p;
5222 const char *cp;
5223 char *q;
5224 char *start;
5225 char *endname;
5226 int metaflag;
5227 struct stat statb;
5228 DIR *dirp;
5229 struct dirent *dp;
5230 int atend;
5231 int matchdot;
5232
5233 metaflag = 0;
5234 start = name;
5235 for (p = name ; ; p++) {
5236 if (*p == '*' || *p == '?')
5237 metaflag = 1;
5238 else if (*p == '[') {
5239 q = p + 1;
5240 if (*q == '!')
5241 q++;
5242 for (;;) {
5243 while (*q == CTLQUOTEMARK)
5244 q++;
5245 if (*q == CTLESC)
5246 q++;
5247 if (*q == '/' || *q == '\0')
5248 break;
5249 if (*++q == ']') {
5250 metaflag = 1;
5251 break;
5252 }
5253 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005254 } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) {
Eric Andersencb57d552001-06-28 07:25:16 +00005255 metaflag = 1;
5256 } else if (*p == '\0')
5257 break;
5258 else if (*p == CTLQUOTEMARK)
5259 continue;
5260 else if (*p == CTLESC)
5261 p++;
5262 if (*p == '/') {
5263 if (metaflag)
5264 break;
5265 start = p + 1;
5266 }
5267 }
Eric Andersen2870d962001-07-02 17:27:21 +00005268 if (metaflag == 0) { /* we've reached the end of the file name */
Eric Andersencb57d552001-06-28 07:25:16 +00005269 if (enddir != expdir)
5270 metaflag++;
5271 for (p = name ; ; p++) {
5272 if (*p == CTLQUOTEMARK)
5273 continue;
5274 if (*p == CTLESC)
5275 p++;
5276 *enddir++ = *p;
5277 if (*p == '\0')
5278 break;
5279 }
5280 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5281 addfname(expdir);
5282 return;
5283 }
5284 endname = p;
5285 if (start != name) {
5286 p = name;
5287 while (p < start) {
5288 while (*p == CTLQUOTEMARK)
5289 p++;
5290 if (*p == CTLESC)
5291 p++;
5292 *enddir++ = *p++;
5293 }
5294 }
5295 if (enddir == expdir) {
5296 cp = ".";
5297 } else if (enddir == expdir + 1 && *expdir == '/') {
5298 cp = "/";
5299 } else {
5300 cp = expdir;
5301 enddir[-1] = '\0';
5302 }
5303 if ((dirp = opendir(cp)) == NULL)
5304 return;
5305 if (enddir != expdir)
5306 enddir[-1] = '/';
5307 if (*endname == 0) {
5308 atend = 1;
5309 } else {
5310 atend = 0;
5311 *endname++ = '\0';
5312 }
5313 matchdot = 0;
5314 p = start;
5315 while (*p == CTLQUOTEMARK)
5316 p++;
5317 if (*p == CTLESC)
5318 p++;
5319 if (*p == '.')
5320 matchdot++;
5321 while (! int_pending() && (dp = readdir(dirp)) != NULL) {
5322 if (dp->d_name[0] == '.' && ! matchdot)
5323 continue;
5324 if (patmatch(start, dp->d_name, 0)) {
5325 if (atend) {
Eric Andersen2870d962001-07-02 17:27:21 +00005326 strcpy(enddir, dp->d_name);
Eric Andersencb57d552001-06-28 07:25:16 +00005327 addfname(expdir);
5328 } else {
5329 for (p = enddir, cp = dp->d_name;
5330 (*p++ = *cp++) != '\0';)
5331 continue;
5332 p[-1] = '/';
5333 expmeta(p, endname);
5334 }
5335 }
5336 }
5337 closedir(dirp);
5338 if (! atend)
5339 endname[-1] = '/';
5340}
Eric Andersen2870d962001-07-02 17:27:21 +00005341#endif /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005342
5343
Eric Andersencb57d552001-06-28 07:25:16 +00005344
Eric Andersen62483552001-07-10 06:09:16 +00005345#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersencb57d552001-06-28 07:25:16 +00005346/*
5347 * Sort the results of file name expansion. It calculates the number of
5348 * strings to sort and then calls msort (short for merge sort) to do the
5349 * work.
5350 */
5351
5352static struct strlist *
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005353expsort(struct strlist *str)
5354{
Eric Andersencb57d552001-06-28 07:25:16 +00005355 int len;
5356 struct strlist *sp;
5357
5358 len = 0;
5359 for (sp = str ; sp ; sp = sp->next)
5360 len++;
5361 return msort(str, len);
5362}
5363
5364
5365static struct strlist *
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005366msort(struct strlist *list, int len)
Eric Andersencb57d552001-06-28 07:25:16 +00005367{
5368 struct strlist *p, *q = NULL;
5369 struct strlist **lpp;
5370 int half;
5371 int n;
5372
5373 if (len <= 1)
5374 return list;
5375 half = len >> 1;
5376 p = list;
5377 for (n = half ; --n >= 0 ; ) {
5378 q = p;
5379 p = p->next;
5380 }
Eric Andersen2870d962001-07-02 17:27:21 +00005381 q->next = NULL; /* terminate first half of list */
5382 q = msort(list, half); /* sort first half of list */
5383 p = msort(p, len - half); /* sort second half */
Eric Andersencb57d552001-06-28 07:25:16 +00005384 lpp = &list;
5385 for (;;) {
5386 if (strcmp(p->text, q->text) < 0) {
5387 *lpp = p;
5388 lpp = &p->next;
5389 if ((p = *lpp) == NULL) {
5390 *lpp = q;
5391 break;
5392 }
5393 } else {
5394 *lpp = q;
5395 lpp = &q->next;
5396 if ((q = *lpp) == NULL) {
5397 *lpp = p;
5398 break;
5399 }
5400 }
5401 }
5402 return list;
5403}
5404#endif
5405
5406
5407
5408/*
5409 * Returns true if the pattern matches the string.
5410 */
5411
Eric Andersen62483552001-07-10 06:09:16 +00005412#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00005413/* squoted: string might have quote chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005414static int
Eric Andersen2870d962001-07-02 17:27:21 +00005415patmatch(char *pattern, char *string, int squoted)
5416{
Eric Andersencb57d552001-06-28 07:25:16 +00005417 const char *p;
5418 char *q;
5419
5420 p = preglob(pattern);
5421 q = squoted ? _rmescapes(string, RMESCAPE_ALLOC) : string;
5422
5423 return !fnmatch(p, q, 0);
5424}
5425
5426
5427static int
Eric Andersen2870d962001-07-02 17:27:21 +00005428patmatch2(char *pattern, char *string, int squoted)
5429{
Eric Andersencb57d552001-06-28 07:25:16 +00005430 char *p;
5431 int res;
5432
5433 sstrnleft--;
5434 p = grabstackstr(expdest);
5435 res = patmatch(pattern, string, squoted);
5436 ungrabstackstr(p, expdest);
5437 return res;
5438}
5439#else
5440static int
Eric Andersen2870d962001-07-02 17:27:21 +00005441patmatch(char *pattern, char *string, int squoted) {
5442 return pmatch(pattern, string, squoted);
Eric Andersencb57d552001-06-28 07:25:16 +00005443}
5444
5445
5446static int
Eric Andersen2870d962001-07-02 17:27:21 +00005447pmatch(char *pattern, char *string, int squoted)
5448{
Eric Andersencb57d552001-06-28 07:25:16 +00005449 char *p, *q;
5450 char c;
5451
5452 p = pattern;
5453 q = string;
5454 for (;;) {
5455 switch (c = *p++) {
5456 case '\0':
5457 goto breakloop;
5458 case CTLESC:
5459 if (squoted && *q == CTLESC)
5460 q++;
5461 if (*q++ != *p++)
5462 return 0;
5463 break;
5464 case CTLQUOTEMARK:
5465 continue;
5466 case '?':
5467 if (squoted && *q == CTLESC)
5468 q++;
5469 if (*q++ == '\0')
5470 return 0;
5471 break;
5472 case '*':
5473 c = *p;
5474 while (c == CTLQUOTEMARK || c == '*')
5475 c = *++p;
5476 if (c != CTLESC && c != CTLQUOTEMARK &&
5477 c != '?' && c != '*' && c != '[') {
5478 while (*q != c) {
5479 if (squoted && *q == CTLESC &&
5480 q[1] == c)
5481 break;
5482 if (*q == '\0')
5483 return 0;
5484 if (squoted && *q == CTLESC)
5485 q++;
5486 q++;
5487 }
5488 }
5489 do {
5490 if (pmatch(p, q, squoted))
5491 return 1;
5492 if (squoted && *q == CTLESC)
5493 q++;
5494 } while (*q++ != '\0');
5495 return 0;
5496 case '[': {
5497 char *endp;
5498 int invert, found;
5499 char chr;
5500
5501 endp = p;
5502 if (*endp == '!')
5503 endp++;
5504 for (;;) {
5505 while (*endp == CTLQUOTEMARK)
5506 endp++;
5507 if (*endp == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00005508 goto dft; /* no matching ] */
Eric Andersencb57d552001-06-28 07:25:16 +00005509 if (*endp == CTLESC)
5510 endp++;
5511 if (*++endp == ']')
5512 break;
5513 }
5514 invert = 0;
5515 if (*p == '!') {
5516 invert++;
5517 p++;
5518 }
5519 found = 0;
5520 chr = *q++;
5521 if (squoted && chr == CTLESC)
5522 chr = *q++;
5523 if (chr == '\0')
5524 return 0;
5525 c = *p++;
5526 do {
5527 if (c == CTLQUOTEMARK)
5528 continue;
5529 if (c == CTLESC)
5530 c = *p++;
5531 if (*p == '-' && p[1] != ']') {
5532 p++;
5533 while (*p == CTLQUOTEMARK)
5534 p++;
5535 if (*p == CTLESC)
5536 p++;
5537 if (chr >= c && chr <= *p)
5538 found = 1;
5539 p++;
5540 } else {
5541 if (chr == c)
5542 found = 1;
5543 }
5544 } while ((c = *p++) != ']');
5545 if (found == invert)
5546 return 0;
5547 break;
5548 }
Eric Andersen2870d962001-07-02 17:27:21 +00005549dft: default:
Eric Andersencb57d552001-06-28 07:25:16 +00005550 if (squoted && *q == CTLESC)
5551 q++;
5552 if (*q++ != c)
5553 return 0;
5554 break;
5555 }
5556 }
5557breakloop:
5558 if (*q != '\0')
5559 return 0;
5560 return 1;
5561}
5562#endif
5563
5564
5565
5566/*
5567 * Remove any CTLESC characters from a string.
5568 */
5569
Eric Andersen62483552001-07-10 06:09:16 +00005570#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00005571static char *
Eric Andersen2870d962001-07-02 17:27:21 +00005572_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005573{
5574 char *p, *q, *r;
5575 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5576
5577 p = strpbrk(str, qchars);
5578 if (!p) {
5579 return str;
5580 }
5581 q = p;
5582 r = str;
5583 if (flag & RMESCAPE_ALLOC) {
5584 size_t len = p - str;
5585 q = r = stalloc(strlen(p) + len + 1);
5586 if (len > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00005587 memcpy(q, str, len);
5588 q += len;
Eric Andersencb57d552001-06-28 07:25:16 +00005589 }
5590 }
5591 while (*p) {
5592 if (*p == CTLQUOTEMARK) {
5593 p++;
5594 continue;
5595 }
5596 if (*p == CTLESC) {
5597 p++;
5598 if (flag & RMESCAPE_GLOB && *p != '/') {
5599 *q++ = '\\';
5600 }
5601 }
5602 *q++ = *p++;
5603 }
5604 *q = '\0';
5605 return r;
5606}
5607#else
5608static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005609rmescapes(char *str)
Eric Andersencb57d552001-06-28 07:25:16 +00005610{
5611 char *p, *q;
5612
5613 p = str;
5614 while (*p != CTLESC && *p != CTLQUOTEMARK) {
5615 if (*p++ == '\0')
5616 return;
5617 }
5618 q = p;
5619 while (*p) {
5620 if (*p == CTLQUOTEMARK) {
5621 p++;
5622 continue;
5623 }
5624 if (*p == CTLESC)
5625 p++;
5626 *q++ = *p++;
5627 }
5628 *q = '\0';
5629}
5630#endif
5631
5632
5633
5634/*
5635 * See if a pattern matches in a case statement.
5636 */
5637
5638static int
Eric Andersen2870d962001-07-02 17:27:21 +00005639casematch(union node *pattern, const char *val)
5640{
Eric Andersencb57d552001-06-28 07:25:16 +00005641 struct stackmark smark;
5642 int result;
5643 char *p;
5644
5645 setstackmark(&smark);
5646 argbackq = pattern->narg.backquote;
5647 STARTSTACKSTR(expdest);
5648 ifslastp = NULL;
5649 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5650 STPUTC('\0', expdest);
5651 p = grabstackstr(expdest);
Eric Andersen2870d962001-07-02 17:27:21 +00005652 result = patmatch(p, (char *)val, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00005653 popstackmark(&smark);
5654 return result;
5655}
5656
5657/*
5658 * Our own itoa().
5659 */
5660
5661static char *
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005662cvtnum(int num, char *buf)
5663{
Eric Andersencb57d552001-06-28 07:25:16 +00005664 int len;
5665
5666 CHECKSTRSPACE(32, buf);
5667 len = sprintf(buf, "%d", num);
5668 STADJUST(len, buf);
5669 return buf;
5670}
Eric Andersencb57d552001-06-28 07:25:16 +00005671/*
5672 * Editline and history functions (and glue).
5673 */
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005674static int histcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00005675{
5676 error("not compiled with history support");
5677 /* NOTREACHED */
5678}
5679
5680
Eric Andersencb57d552001-06-28 07:25:16 +00005681struct redirtab {
5682 struct redirtab *next;
Russ Dill4db35642001-07-26 05:58:40 +00005683 short renamed[10]; /* Current ash support only 0-9 descriptors */
Eric Andersen34506362001-08-02 05:02:46 +00005684 /* char on arm (and others) can't be negative */
Eric Andersencb57d552001-06-28 07:25:16 +00005685};
5686
Eric Andersen2870d962001-07-02 17:27:21 +00005687static struct redirtab *redirlist;
Eric Andersencb57d552001-06-28 07:25:16 +00005688
5689extern char **environ;
5690
5691
5692
5693/*
5694 * Initialization code.
5695 */
5696
5697static void
Eric Andersen2870d962001-07-02 17:27:21 +00005698init(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00005699
5700 /* from cd.c: */
5701 {
Eric Andersena3483db2001-10-24 08:01:06 +00005702 curdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00005703 setpwd(0, 0);
5704 }
5705
5706 /* from input.c: */
5707 {
5708 basepf.nextc = basepf.buf = basebuf;
5709 }
5710
Eric Andersencb57d552001-06-28 07:25:16 +00005711 /* from var.c: */
5712 {
5713 char **envp;
5714 char ppid[32];
5715
5716 initvar();
5717 for (envp = environ ; *envp ; envp++) {
5718 if (strchr(*envp, '=')) {
5719 setvareq(*envp, VEXPORT|VTEXTFIXED);
5720 }
5721 }
5722
Eric Andersen3102ac42001-07-06 04:26:23 +00005723 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
Eric Andersencb57d552001-06-28 07:25:16 +00005724 setvar("PPID", ppid, 0);
5725 }
5726}
5727
5728
5729
5730/*
5731 * This routine is called when an error or an interrupt occurs in an
5732 * interactive shell and control is returned to the main command loop.
5733 */
5734
Eric Andersen2870d962001-07-02 17:27:21 +00005735/* 1 == check for aliases, 2 == also check for assignments */
Eric Andersen7467c8d2001-07-12 20:26:32 +00005736static int checkalias; /* also used in no alias mode for check assignments */
Eric Andersen2870d962001-07-02 17:27:21 +00005737
Eric Andersencb57d552001-06-28 07:25:16 +00005738static void
Eric Andersen2870d962001-07-02 17:27:21 +00005739reset(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00005740
5741 /* from eval.c: */
5742 {
5743 evalskip = 0;
5744 loopnest = 0;
5745 funcnest = 0;
5746 }
5747
5748 /* from input.c: */
5749 {
5750 if (exception != EXSHELLPROC)
Eric Andersen2870d962001-07-02 17:27:21 +00005751 parselleft = parsenleft = 0; /* clear input buffer */
Eric Andersencb57d552001-06-28 07:25:16 +00005752 popallfiles();
5753 }
5754
5755 /* from parser.c: */
5756 {
5757 tokpushback = 0;
5758 checkkwd = 0;
5759 checkalias = 0;
5760 }
5761
5762 /* from redir.c: */
5763 {
5764 while (redirlist)
5765 popredir();
5766 }
5767
Eric Andersencb57d552001-06-28 07:25:16 +00005768}
5769
5770
5771
5772/*
Eric Andersencb57d552001-06-28 07:25:16 +00005773 * This file implements the input routines used by the parser.
5774 */
5775
Eric Andersenbdfd0d72001-10-24 05:00:29 +00005776#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersencb57d552001-06-28 07:25:16 +00005777static const char * cmdedit_prompt;
5778static inline void putprompt(const char *s) {
5779 cmdedit_prompt = s;
5780}
5781#else
5782static inline void putprompt(const char *s) {
5783 out2str(s);
5784}
5785#endif
5786
Eric Andersen2870d962001-07-02 17:27:21 +00005787#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
Eric Andersencb57d552001-06-28 07:25:16 +00005788
Eric Andersencb57d552001-06-28 07:25:16 +00005789
Eric Andersencb57d552001-06-28 07:25:16 +00005790
Eric Andersen2870d962001-07-02 17:27:21 +00005791/*
5792 * Same as pgetc(), but ignores PEOA.
5793 */
Eric Andersencb57d552001-06-28 07:25:16 +00005794
Eric Andersend35c5df2002-01-09 15:37:36 +00005795#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00005796static int
Eric Andersen74400cc2001-10-18 04:11:39 +00005797pgetc2(void)
Eric Andersen2870d962001-07-02 17:27:21 +00005798{
5799 int c;
5800 do {
5801 c = pgetc_macro();
5802 } while (c == PEOA);
5803 return c;
Eric Andersencb57d552001-06-28 07:25:16 +00005804}
Eric Andersen2870d962001-07-02 17:27:21 +00005805#else
Eric Andersend35c5df2002-01-09 15:37:36 +00005806static inline int pgetc2(void) { return pgetc_macro(); }
Eric Andersencb57d552001-06-28 07:25:16 +00005807#endif
5808
Eric Andersencb57d552001-06-28 07:25:16 +00005809/*
5810 * Read a line from the script.
5811 */
5812
Eric Andersen62483552001-07-10 06:09:16 +00005813static inline char *
Eric Andersen2870d962001-07-02 17:27:21 +00005814pfgets(char *line, int len)
Eric Andersencb57d552001-06-28 07:25:16 +00005815{
5816 char *p = line;
5817 int nleft = len;
5818 int c;
5819
5820 while (--nleft > 0) {
5821 c = pgetc2();
5822 if (c == PEOF) {
5823 if (p == line)
5824 return NULL;
5825 break;
5826 }
5827 *p++ = c;
5828 if (c == '\n')
5829 break;
5830 }
5831 *p = '\0';
5832 return line;
5833}
5834
Eric Andersen62483552001-07-10 06:09:16 +00005835static inline int
Eric Andersen2870d962001-07-02 17:27:21 +00005836preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005837{
5838 int nr;
5839 char *buf = parsefile->buf;
5840 parsenextc = buf;
5841
5842retry:
Eric Andersenbdfd0d72001-10-24 05:00:29 +00005843#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersencb57d552001-06-28 07:25:16 +00005844 {
Eric Andersen34506362001-08-02 05:02:46 +00005845 if (!iflag || parsefile->fd)
Eric Andersen7467c8d2001-07-12 20:26:32 +00005846 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersen2870d962001-07-02 17:27:21 +00005847 else {
Eric Andersen044228d2001-07-17 01:12:36 +00005848 nr = cmdedit_read_input((char*)cmdedit_prompt, buf);
Eric Andersencb57d552001-06-28 07:25:16 +00005849 }
5850 }
5851#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00005852 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00005853#endif
5854
5855 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00005856 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
5857 int flags = fcntl(0, F_GETFL, 0);
5858 if (flags >= 0 && flags & O_NONBLOCK) {
5859 flags &=~ O_NONBLOCK;
5860 if (fcntl(0, F_SETFL, flags) >= 0) {
5861 out2str("sh: turning off NDELAY mode\n");
5862 goto retry;
5863 }
5864 }
5865 }
5866 }
5867 return nr;
5868}
5869
Eric Andersen2870d962001-07-02 17:27:21 +00005870static void
5871popstring(void)
5872{
5873 struct strpush *sp = parsefile->strpush;
5874
5875 INTOFF;
Eric Andersend35c5df2002-01-09 15:37:36 +00005876#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00005877 if (sp->ap) {
5878 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
5879 if (!checkalias) {
5880 checkalias = 1;
5881 }
5882 }
5883 if (sp->string != sp->ap->val) {
Aaron Lehmann49c024a2002-08-02 06:39:47 +00005884 free(sp->string);
Eric Andersen2870d962001-07-02 17:27:21 +00005885 }
5886
5887 sp->ap->flag &= ~ALIASINUSE;
5888 if (sp->ap->flag & ALIASDEAD) {
5889 unalias(sp->ap->name);
5890 }
5891 }
5892#endif
5893 parsenextc = sp->prevstring;
5894 parsenleft = sp->prevnleft;
5895/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
5896 parsefile->strpush = sp->prev;
5897 if (sp != &(parsefile->basestrpush))
Aaron Lehmann49c024a2002-08-02 06:39:47 +00005898 free(sp);
Eric Andersen2870d962001-07-02 17:27:21 +00005899 INTON;
5900}
5901
5902
Eric Andersencb57d552001-06-28 07:25:16 +00005903/*
5904 * Refill the input buffer and return the next input character:
5905 *
5906 * 1) If a string was pushed back on the input, pop it;
5907 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
5908 * from a string so we can't refill the buffer, return EOF.
5909 * 3) If the is more stuff in this buffer, use it else call read to fill it.
5910 * 4) Process input up to the next newline, deleting nul characters.
5911 */
5912
5913static int
Eric Andersen2870d962001-07-02 17:27:21 +00005914preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005915{
5916 char *p, *q;
5917 int more;
5918 char savec;
5919
5920 while (parsefile->strpush) {
Eric Andersend35c5df2002-01-09 15:37:36 +00005921#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00005922 if (parsenleft == -1 && parsefile->strpush->ap &&
5923 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00005924 return PEOA;
5925 }
Eric Andersen2870d962001-07-02 17:27:21 +00005926#endif
Eric Andersencb57d552001-06-28 07:25:16 +00005927 popstring();
5928 if (--parsenleft >= 0)
5929 return (*parsenextc++);
5930 }
5931 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
5932 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00005933 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00005934
5935again:
5936 if (parselleft <= 0) {
5937 if ((parselleft = preadfd()) <= 0) {
5938 parselleft = parsenleft = EOF_NLEFT;
5939 return PEOF;
5940 }
5941 }
5942
5943 q = p = parsenextc;
5944
5945 /* delete nul characters */
5946 for (more = 1; more;) {
5947 switch (*p) {
5948 case '\0':
Eric Andersen2870d962001-07-02 17:27:21 +00005949 p++; /* Skip nul */
Eric Andersencb57d552001-06-28 07:25:16 +00005950 goto check;
5951
5952
5953 case '\n':
5954 parsenleft = q - parsenextc;
5955 more = 0; /* Stop processing here */
5956 break;
5957 }
5958
5959 *q++ = *p++;
5960check:
5961 if (--parselleft <= 0 && more) {
5962 parsenleft = q - parsenextc - 1;
5963 if (parsenleft < 0)
5964 goto again;
5965 more = 0;
5966 }
5967 }
5968
5969 savec = *q;
5970 *q = '\0';
5971
5972 if (vflag) {
5973 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00005974 }
5975
5976 *q = savec;
5977
5978 return *parsenextc++;
5979}
5980
Eric Andersencb57d552001-06-28 07:25:16 +00005981
5982/*
5983 * Push a string back onto the input at this current parsefile level.
5984 * We handle aliases this way.
5985 */
5986static void
Eric Andersen2870d962001-07-02 17:27:21 +00005987pushstring(char *s, int len, void *ap)
5988{
Eric Andersencb57d552001-06-28 07:25:16 +00005989 struct strpush *sp;
5990
5991 INTOFF;
5992/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
5993 if (parsefile->strpush) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005994 sp = xmalloc(sizeof (struct strpush));
Eric Andersencb57d552001-06-28 07:25:16 +00005995 sp->prev = parsefile->strpush;
5996 parsefile->strpush = sp;
5997 } else
5998 sp = parsefile->strpush = &(parsefile->basestrpush);
5999 sp->prevstring = parsenextc;
6000 sp->prevnleft = parsenleft;
Eric Andersend35c5df2002-01-09 15:37:36 +00006001#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00006002 sp->ap = (struct alias *)ap;
6003 if (ap) {
6004 ((struct alias *)ap)->flag |= ALIASINUSE;
6005 sp->string = s;
6006 }
Eric Andersen2870d962001-07-02 17:27:21 +00006007#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006008 parsenextc = s;
6009 parsenleft = len;
6010 INTON;
6011}
6012
Eric Andersencb57d552001-06-28 07:25:16 +00006013
Eric Andersencb57d552001-06-28 07:25:16 +00006014/*
6015 * Like setinputfile, but takes input from a string.
6016 */
6017
6018static void
Eric Andersen62483552001-07-10 06:09:16 +00006019setinputstring(char *string)
6020{
Eric Andersencb57d552001-06-28 07:25:16 +00006021 INTOFF;
6022 pushfile();
6023 parsenextc = string;
6024 parsenleft = strlen(string);
6025 parsefile->buf = NULL;
6026 plinno = 1;
6027 INTON;
6028}
6029
6030
6031
6032/*
6033 * To handle the "." command, a stack of input files is used. Pushfile
6034 * adds a new entry to the stack and popfile restores the previous level.
6035 */
6036
6037static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006038pushfile(void)
6039{
Eric Andersencb57d552001-06-28 07:25:16 +00006040 struct parsefile *pf;
6041
6042 parsefile->nleft = parsenleft;
6043 parsefile->lleft = parselleft;
6044 parsefile->nextc = parsenextc;
6045 parsefile->linno = plinno;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006046 pf = (struct parsefile *)xmalloc(sizeof (struct parsefile));
Eric Andersencb57d552001-06-28 07:25:16 +00006047 pf->prev = parsefile;
6048 pf->fd = -1;
6049 pf->strpush = NULL;
6050 pf->basestrpush.prev = NULL;
6051 parsefile = pf;
6052}
6053
Eric Andersend35c5df2002-01-09 15:37:36 +00006054#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen2870d962001-07-02 17:27:21 +00006055static void restartjob (struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00006056#endif
Eric Andersen2870d962001-07-02 17:27:21 +00006057static void freejob (struct job *);
6058static struct job *getjob (const char *);
6059static int dowait (int, struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00006060static void waitonint(int);
6061
6062
Eric Andersen2870d962001-07-02 17:27:21 +00006063/*
6064 * We keep track of whether or not fd0 has been redirected. This is for
6065 * background commands, where we want to redirect fd0 to /dev/null only
6066 * if it hasn't already been redirected.
6067*/
6068static int fd0_redirected = 0;
6069
6070/* Return true if fd 0 has already been redirected at least once. */
6071static inline int
Eric Andersen74400cc2001-10-18 04:11:39 +00006072fd0_redirected_p (void)
6073{
Eric Andersen2870d962001-07-02 17:27:21 +00006074 return fd0_redirected != 0;
6075}
6076
Eric Andersen62483552001-07-10 06:09:16 +00006077static void dupredirect (const union node *, int, int fd1dup);
Eric Andersen2870d962001-07-02 17:27:21 +00006078
Eric Andersend35c5df2002-01-09 15:37:36 +00006079#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006080/*
6081 * Turn job control on and off.
6082 *
6083 * Note: This code assumes that the third arg to ioctl is a character
6084 * pointer, which is true on Berkeley systems but not System V. Since
6085 * System V doesn't have job control yet, this isn't a problem now.
6086 */
6087
Eric Andersen2870d962001-07-02 17:27:21 +00006088
Eric Andersencb57d552001-06-28 07:25:16 +00006089
6090static void setjobctl(int enable)
6091{
6092#ifdef OLD_TTY_DRIVER
6093 int ldisc;
6094#endif
6095
6096 if (enable == jobctl || rootshell == 0)
6097 return;
6098 if (enable) {
6099 do { /* while we are in the background */
6100#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006101 if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006102#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006103 initialpgrp = tcgetpgrp(2);
Eric Andersencb57d552001-06-28 07:25:16 +00006104 if (initialpgrp < 0) {
6105#endif
Eric Andersen8c145dc2001-07-10 16:57:09 +00006106 out2str("sh: can't access tty; job control turned off\n");
Eric Andersencb57d552001-06-28 07:25:16 +00006107 mflag = 0;
6108 return;
6109 }
6110 if (initialpgrp == -1)
6111 initialpgrp = getpgrp();
6112 else if (initialpgrp != getpgrp()) {
6113 killpg(initialpgrp, SIGTTIN);
6114 continue;
6115 }
6116 } while (0);
6117#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006118 if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
Eric Andersen8c145dc2001-07-10 16:57:09 +00006119 out2str("sh: need new tty driver to run job control; job control turned off\n");
Eric Andersencb57d552001-06-28 07:25:16 +00006120 mflag = 0;
6121 return;
6122 }
6123#endif
6124 setsignal(SIGTSTP);
6125 setsignal(SIGTTOU);
6126 setsignal(SIGTTIN);
6127 setpgid(0, rootpid);
6128#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006129 ioctl(2, TIOCSPGRP, (char *)&rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00006130#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006131 tcsetpgrp(2, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00006132#endif
Eric Andersen8c145dc2001-07-10 16:57:09 +00006133 } else { /* turning job control off */
Eric Andersencb57d552001-06-28 07:25:16 +00006134 setpgid(0, initialpgrp);
6135#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006136 ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006137#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006138 tcsetpgrp(2, initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006139#endif
6140 setsignal(SIGTSTP);
6141 setsignal(SIGTTOU);
6142 setsignal(SIGTTIN);
6143 }
6144 jobctl = enable;
6145}
6146#endif
6147
6148
Eric Andersend35c5df2002-01-09 15:37:36 +00006149#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006150static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006151killcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006152{
6153 int signo = -1;
6154 int list = 0;
6155 int i;
6156 pid_t pid;
6157 struct job *jp;
6158
6159 if (argc <= 1) {
6160usage:
6161 error(
6162"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6163"kill -l [exitstatus]"
6164 );
6165 }
6166
6167 if (*argv[1] == '-') {
6168 signo = decode_signal(argv[1] + 1, 1);
6169 if (signo < 0) {
6170 int c;
6171
6172 while ((c = nextopt("ls:")) != '\0')
6173 switch (c) {
6174 case 'l':
6175 list = 1;
6176 break;
6177 case 's':
6178 signo = decode_signal(optionarg, 1);
6179 if (signo < 0) {
6180 error(
6181 "invalid signal number or name: %s",
6182 optionarg
6183 );
6184 }
Eric Andersen2870d962001-07-02 17:27:21 +00006185 break;
Eric Andersencb57d552001-06-28 07:25:16 +00006186#ifdef DEBUG
6187 default:
6188 error(
6189 "nextopt returned character code 0%o", c);
6190#endif
6191 }
6192 } else
6193 argptr++;
6194 }
6195
6196 if (!list && signo < 0)
6197 signo = SIGTERM;
6198
6199 if ((signo < 0 || !*argptr) ^ list) {
6200 goto usage;
6201 }
6202
6203 if (list) {
Eric Andersen34506362001-08-02 05:02:46 +00006204 const char *name;
6205
Eric Andersencb57d552001-06-28 07:25:16 +00006206 if (!*argptr) {
6207 out1str("0\n");
6208 for (i = 1; i < NSIG; i++) {
Eric Andersen34506362001-08-02 05:02:46 +00006209 name = u_signal_names(0, &i, 1);
6210 if(name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006211 puts(name);
Eric Andersencb57d552001-06-28 07:25:16 +00006212 }
6213 return 0;
6214 }
Eric Andersen34506362001-08-02 05:02:46 +00006215 name = u_signal_names(*argptr, &signo, -1);
6216 if (name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006217 puts(name);
Eric Andersencb57d552001-06-28 07:25:16 +00006218 else
6219 error("invalid signal number or exit status: %s",
6220 *argptr);
6221 return 0;
6222 }
6223
6224 do {
6225 if (**argptr == '%') {
6226 jp = getjob(*argptr);
6227 if (jp->jobctl == 0)
6228 error("job %s not created under job control",
6229 *argptr);
6230 pid = -jp->ps[0].pid;
6231 } else
6232 pid = atoi(*argptr);
6233 if (kill(pid, signo) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00006234 error("%s: %m", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006235 } while (*++argptr);
6236
6237 return 0;
6238}
6239
6240static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006241fgcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006242{
6243 struct job *jp;
6244 int pgrp;
6245 int status;
6246
6247 jp = getjob(argv[1]);
6248 if (jp->jobctl == 0)
6249 error("job not created under job control");
6250 pgrp = jp->ps[0].pid;
6251#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006252 ioctl(2, TIOCSPGRP, (char *)&pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006253#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006254 tcsetpgrp(2, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006255#endif
6256 restartjob(jp);
Eric Andersencb57d552001-06-28 07:25:16 +00006257 status = waitforjob(jp);
Eric Andersencb57d552001-06-28 07:25:16 +00006258 return status;
6259}
6260
6261
6262static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006263bgcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006264{
6265 struct job *jp;
6266
6267 do {
6268 jp = getjob(*++argv);
6269 if (jp->jobctl == 0)
6270 error("job not created under job control");
6271 restartjob(jp);
6272 } while (--argc > 1);
6273 return 0;
6274}
6275
6276
6277static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006278restartjob(struct job *jp)
Eric Andersencb57d552001-06-28 07:25:16 +00006279{
6280 struct procstat *ps;
6281 int i;
6282
6283 if (jp->state == JOBDONE)
6284 return;
6285 INTOFF;
6286 killpg(jp->ps[0].pid, SIGCONT);
6287 for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
6288 if (WIFSTOPPED(ps->status)) {
6289 ps->status = -1;
6290 jp->state = 0;
6291 }
6292 }
6293 INTON;
6294}
6295#endif
6296
Eric Andersen2870d962001-07-02 17:27:21 +00006297static void showjobs(int change);
6298
Eric Andersencb57d552001-06-28 07:25:16 +00006299
6300static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006301jobscmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006302{
6303 showjobs(0);
6304 return 0;
6305}
6306
6307
6308/*
6309 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6310 * statuses have changed since the last call to showjobs.
6311 *
6312 * If the shell is interrupted in the process of creating a job, the
6313 * result may be a job structure containing zero processes. Such structures
6314 * will be freed here.
6315 */
6316
6317static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006318showjobs(int change)
Eric Andersencb57d552001-06-28 07:25:16 +00006319{
6320 int jobno;
6321 int procno;
6322 int i;
6323 struct job *jp;
6324 struct procstat *ps;
6325 int col;
6326 char s[64];
6327
6328 TRACE(("showjobs(%d) called\n", change));
6329 while (dowait(0, (struct job *)NULL) > 0);
6330 for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
6331 if (! jp->used)
6332 continue;
6333 if (jp->nprocs == 0) {
6334 freejob(jp);
6335 continue;
6336 }
6337 if (change && ! jp->changed)
6338 continue;
6339 procno = jp->nprocs;
Eric Andersen2870d962001-07-02 17:27:21 +00006340 for (ps = jp->ps ; ; ps++) { /* for each process */
Eric Andersencb57d552001-06-28 07:25:16 +00006341 if (ps == jp->ps)
Eric Andersen3102ac42001-07-06 04:26:23 +00006342 snprintf(s, 64, "[%d] %ld ", jobno,
Eric Andersencb57d552001-06-28 07:25:16 +00006343 (long)ps->pid);
6344 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006345 snprintf(s, 64, " %ld ",
Eric Andersencb57d552001-06-28 07:25:16 +00006346 (long)ps->pid);
6347 out1str(s);
6348 col = strlen(s);
6349 s[0] = '\0';
6350 if (ps->status == -1) {
6351 /* don't print anything */
6352 } else if (WIFEXITED(ps->status)) {
Eric Andersen3102ac42001-07-06 04:26:23 +00006353 snprintf(s, 64, "Exit %d",
Eric Andersencb57d552001-06-28 07:25:16 +00006354 WEXITSTATUS(ps->status));
6355 } else {
Eric Andersend35c5df2002-01-09 15:37:36 +00006356#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen2870d962001-07-02 17:27:21 +00006357 if (WIFSTOPPED(ps->status))
Eric Andersencb57d552001-06-28 07:25:16 +00006358 i = WSTOPSIG(ps->status);
6359 else /* WIFSIGNALED(ps->status) */
6360#endif
6361 i = WTERMSIG(ps->status);
6362 if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
Eric Andersen2870d962001-07-02 17:27:21 +00006363 strcpy(s, sys_siglist[i & 0x7F]);
Eric Andersencb57d552001-06-28 07:25:16 +00006364 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006365 snprintf(s, 64, "Signal %d", i & 0x7F);
Eric Andersencb57d552001-06-28 07:25:16 +00006366 if (WCOREDUMP(ps->status))
6367 strcat(s, " (core dumped)");
6368 }
6369 out1str(s);
6370 col += strlen(s);
Eric Andersen62483552001-07-10 06:09:16 +00006371 printf(
Eric Andersencb57d552001-06-28 07:25:16 +00006372 "%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ',
6373 ps->cmd
6374 );
6375 if (--procno <= 0)
6376 break;
6377 }
6378 jp->changed = 0;
6379 if (jp->state == JOBDONE) {
6380 freejob(jp);
6381 }
6382 }
6383}
6384
6385
6386/*
6387 * Mark a job structure as unused.
6388 */
6389
6390static void
Eric Andersen62483552001-07-10 06:09:16 +00006391freejob(struct job *jp)
6392{
6393 const struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006394 int i;
6395
6396 INTOFF;
6397 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6398 if (ps->cmd != nullstr)
Aaron Lehmann49c024a2002-08-02 06:39:47 +00006399 free(ps->cmd);
Eric Andersencb57d552001-06-28 07:25:16 +00006400 }
6401 if (jp->ps != &jp->ps0)
Aaron Lehmann49c024a2002-08-02 06:39:47 +00006402 free(jp->ps);
Eric Andersencb57d552001-06-28 07:25:16 +00006403 jp->used = 0;
Eric Andersend35c5df2002-01-09 15:37:36 +00006404#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006405 if (curjob == jp - jobtab + 1)
6406 curjob = 0;
6407#endif
6408 INTON;
6409}
6410
6411
6412
6413static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006414waitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006415{
6416 struct job *job;
6417 int status, retval;
6418 struct job *jp;
6419
6420 if (--argc > 0) {
6421start:
6422 job = getjob(*++argv);
6423 } else {
6424 job = NULL;
6425 }
Eric Andersen2870d962001-07-02 17:27:21 +00006426 for (;;) { /* loop until process terminated or stopped */
Eric Andersencb57d552001-06-28 07:25:16 +00006427 if (job != NULL) {
6428 if (job->state) {
6429 status = job->ps[job->nprocs - 1].status;
6430 if (! iflag)
6431 freejob(job);
6432 if (--argc) {
6433 goto start;
6434 }
6435 if (WIFEXITED(status))
6436 retval = WEXITSTATUS(status);
Eric Andersend35c5df2002-01-09 15:37:36 +00006437#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006438 else if (WIFSTOPPED(status))
6439 retval = WSTOPSIG(status) + 128;
6440#endif
6441 else {
6442 /* XXX: limits number of signals */
6443 retval = WTERMSIG(status) + 128;
6444 }
6445 return retval;
6446 }
6447 } else {
6448 for (jp = jobtab ; ; jp++) {
Eric Andersen2870d962001-07-02 17:27:21 +00006449 if (jp >= jobtab + njobs) { /* no running procs */
Eric Andersencb57d552001-06-28 07:25:16 +00006450 return 0;
6451 }
6452 if (jp->used && jp->state == 0)
6453 break;
6454 }
6455 }
6456 if (dowait(2, 0) < 0 && errno == EINTR) {
6457 return 129;
6458 }
6459 }
6460}
6461
6462
6463
6464/*
6465 * Convert a job name to a job structure.
6466 */
6467
6468static struct job *
Eric Andersen2870d962001-07-02 17:27:21 +00006469getjob(const char *name)
6470{
Eric Andersencb57d552001-06-28 07:25:16 +00006471 int jobno;
6472 struct job *jp;
6473 int pid;
6474 int i;
6475
6476 if (name == NULL) {
Eric Andersend35c5df2002-01-09 15:37:36 +00006477#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006478currentjob:
6479 if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
6480 error("No current job");
6481 return &jobtab[jobno - 1];
6482#else
6483 error("No current job");
6484#endif
6485 } else if (name[0] == '%') {
6486 if (is_digit(name[1])) {
6487 jobno = number(name + 1);
6488 if (jobno > 0 && jobno <= njobs
6489 && jobtab[jobno - 1].used != 0)
6490 return &jobtab[jobno - 1];
Eric Andersend35c5df2002-01-09 15:37:36 +00006491#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006492 } else if (name[1] == '%' && name[2] == '\0') {
6493 goto currentjob;
6494#endif
6495 } else {
6496 struct job *found = NULL;
6497 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
6498 if (jp->used && jp->nprocs > 0
6499 && prefix(name + 1, jp->ps[0].cmd)) {
6500 if (found)
6501 error("%s: ambiguous", name);
6502 found = jp;
6503 }
6504 }
6505 if (found)
6506 return found;
6507 }
Eric Andersen2870d962001-07-02 17:27:21 +00006508 } else if (is_number(name, &pid)) {
Eric Andersencb57d552001-06-28 07:25:16 +00006509 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
6510 if (jp->used && jp->nprocs > 0
6511 && jp->ps[jp->nprocs - 1].pid == pid)
6512 return jp;
6513 }
6514 }
6515 error("No such job: %s", name);
6516 /* NOTREACHED */
6517}
6518
6519
6520
6521/*
6522 * Return a new job structure,
6523 */
6524
Eric Andersen2870d962001-07-02 17:27:21 +00006525static struct job *
Eric Andersen62483552001-07-10 06:09:16 +00006526makejob(const union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00006527{
6528 int i;
6529 struct job *jp;
6530
6531 for (i = njobs, jp = jobtab ; ; jp++) {
6532 if (--i < 0) {
6533 INTOFF;
6534 if (njobs == 0) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006535 jobtab = xmalloc(4 * sizeof jobtab[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00006536 } else {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006537 jp = xmalloc((njobs + 4) * sizeof jobtab[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00006538 memcpy(jp, jobtab, njobs * sizeof jp[0]);
6539 /* Relocate `ps' pointers */
6540 for (i = 0; i < njobs; i++)
6541 if (jp[i].ps == &jobtab[i].ps0)
6542 jp[i].ps = &jp[i].ps0;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00006543 free(jobtab);
Eric Andersencb57d552001-06-28 07:25:16 +00006544 jobtab = jp;
6545 }
6546 jp = jobtab + njobs;
6547 for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
6548 INTON;
6549 break;
6550 }
6551 if (jp->used == 0)
6552 break;
6553 }
6554 INTOFF;
6555 jp->state = 0;
6556 jp->used = 1;
6557 jp->changed = 0;
6558 jp->nprocs = 0;
Eric Andersend35c5df2002-01-09 15:37:36 +00006559#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006560 jp->jobctl = jobctl;
6561#endif
6562 if (nprocs > 1) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006563 jp->ps = xmalloc(nprocs * sizeof (struct procstat));
Eric Andersencb57d552001-06-28 07:25:16 +00006564 } else {
6565 jp->ps = &jp->ps0;
6566 }
6567 INTON;
6568 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
6569 jp - jobtab + 1));
6570 return jp;
6571}
6572
6573
6574/*
6575 * Fork of a subshell. If we are doing job control, give the subshell its
6576 * own process group. Jp is a job structure that the job is to be added to.
6577 * N is the command that will be evaluated by the child. Both jp and n may
6578 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00006579 * FORK_FG - Fork off a foreground process.
6580 * FORK_BG - Fork off a background process.
6581 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
6582 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00006583 *
6584 * When job control is turned off, background processes have their standard
6585 * input redirected to /dev/null (except for the second and later processes
6586 * in a pipeline).
6587 */
6588
Eric Andersen2870d962001-07-02 17:27:21 +00006589
6590
Eric Andersencb57d552001-06-28 07:25:16 +00006591static int
Eric Andersen62483552001-07-10 06:09:16 +00006592forkshell(struct job *jp, const union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00006593{
6594 int pid;
Eric Andersend35c5df2002-01-09 15:37:36 +00006595#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006596 int pgrp;
Eric Andersen62483552001-07-10 06:09:16 +00006597#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006598 const char *devnull = _PATH_DEVNULL;
6599 const char *nullerr = "Can't open %s";
6600
6601 TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
6602 mode));
6603 INTOFF;
Eric Andersen72f9a422001-10-28 05:12:20 +00006604#if !defined(__UCLIBC__) || defined(__UCLIBC_HAS_MMU__)
Eric Andersencb57d552001-06-28 07:25:16 +00006605 pid = fork();
Eric Andersen72f9a422001-10-28 05:12:20 +00006606#else
6607 pid = vfork();
6608#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006609 if (pid == -1) {
6610 TRACE(("Fork failed, errno=%d\n", errno));
6611 INTON;
6612 error("Cannot fork");
6613 }
6614 if (pid == 0) {
6615 struct job *p;
6616 int wasroot;
6617 int i;
6618
6619 TRACE(("Child shell %d\n", getpid()));
6620 wasroot = rootshell;
6621 rootshell = 0;
6622 closescript();
6623 INTON;
6624 clear_traps();
Eric Andersend35c5df2002-01-09 15:37:36 +00006625#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen2870d962001-07-02 17:27:21 +00006626 jobctl = 0; /* do job control only in root shell */
Eric Andersencb57d552001-06-28 07:25:16 +00006627 if (wasroot && mode != FORK_NOJOB && mflag) {
6628 if (jp == NULL || jp->nprocs == 0)
6629 pgrp = getpid();
6630 else
6631 pgrp = jp->ps[0].pid;
6632 setpgid(0, pgrp);
6633 if (mode == FORK_FG) {
6634 /*** this causes superfluous TIOCSPGRPS ***/
6635#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006636 if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006637 error("TIOCSPGRP failed, errno=%d", errno);
6638#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006639 if (tcsetpgrp(2, pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006640 error("tcsetpgrp failed, errno=%d", errno);
6641#endif
6642 }
6643 setsignal(SIGTSTP);
6644 setsignal(SIGTTOU);
6645 } else if (mode == FORK_BG) {
Eric Andersencb57d552001-06-28 07:25:16 +00006646#else
6647 if (mode == FORK_BG) {
Aaron Lehmann1a698662001-12-31 06:12:48 +00006648#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006649 ignoresig(SIGINT);
6650 ignoresig(SIGQUIT);
6651 if ((jp == NULL || jp->nprocs == 0) &&
6652 ! fd0_redirected_p ()) {
6653 close(0);
6654 if (open(devnull, O_RDONLY) != 0)
6655 error(nullerr, devnull);
6656 }
6657 }
Eric Andersencb57d552001-06-28 07:25:16 +00006658 for (i = njobs, p = jobtab ; --i >= 0 ; p++)
6659 if (p->used)
6660 freejob(p);
6661 if (wasroot && iflag) {
6662 setsignal(SIGINT);
6663 setsignal(SIGQUIT);
6664 setsignal(SIGTERM);
6665 }
6666 return pid;
6667 }
Eric Andersend35c5df2002-01-09 15:37:36 +00006668#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006669 if (rootshell && mode != FORK_NOJOB && mflag) {
6670 if (jp == NULL || jp->nprocs == 0)
6671 pgrp = pid;
6672 else
6673 pgrp = jp->ps[0].pid;
6674 setpgid(pid, pgrp);
6675 }
Eric Andersen62483552001-07-10 06:09:16 +00006676#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006677 if (mode == FORK_BG)
Eric Andersen2870d962001-07-02 17:27:21 +00006678 backgndpid = pid; /* set $! */
Eric Andersencb57d552001-06-28 07:25:16 +00006679 if (jp) {
6680 struct procstat *ps = &jp->ps[jp->nprocs++];
6681 ps->pid = pid;
6682 ps->status = -1;
6683 ps->cmd = nullstr;
6684 if (iflag && rootshell && n)
6685 ps->cmd = commandtext(n);
6686 }
6687 INTON;
6688 TRACE(("In parent shell: child = %d\n", pid));
6689 return pid;
6690}
6691
6692
6693
6694/*
6695 * Wait for job to finish.
6696 *
6697 * Under job control we have the problem that while a child process is
6698 * running interrupts generated by the user are sent to the child but not
6699 * to the shell. This means that an infinite loop started by an inter-
6700 * active user may be hard to kill. With job control turned off, an
6701 * interactive user may place an interactive program inside a loop. If
6702 * the interactive program catches interrupts, the user doesn't want
6703 * these interrupts to also abort the loop. The approach we take here
6704 * is to have the shell ignore interrupt signals while waiting for a
6705 * forground process to terminate, and then send itself an interrupt
6706 * signal if the child process was terminated by an interrupt signal.
6707 * Unfortunately, some programs want to do a bit of cleanup and then
6708 * exit on interrupt; unless these processes terminate themselves by
6709 * sending a signal to themselves (instead of calling exit) they will
6710 * confuse this approach.
6711 */
6712
6713static int
Eric Andersen62483552001-07-10 06:09:16 +00006714waitforjob(struct job *jp)
6715{
Eric Andersend35c5df2002-01-09 15:37:36 +00006716#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006717 int mypgrp = getpgrp();
6718#endif
6719 int status;
6720 int st;
6721 struct sigaction act, oact;
6722
6723 INTOFF;
6724 intreceived = 0;
Eric Andersend35c5df2002-01-09 15:37:36 +00006725#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006726 if (!jobctl) {
6727#else
6728 if (!iflag) {
6729#endif
6730 sigaction(SIGINT, 0, &act);
6731 act.sa_handler = waitonint;
6732 sigaction(SIGINT, &act, &oact);
6733 }
6734 TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
6735 while (jp->state == 0) {
6736 dowait(1, jp);
6737 }
Eric Andersend35c5df2002-01-09 15:37:36 +00006738#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006739 if (!jobctl) {
6740#else
6741 if (!iflag) {
6742#endif
6743 sigaction(SIGINT, &oact, 0);
Eric Andersen54c14d72002-04-24 23:14:06 +00006744 if (intreceived) kill(getpid(), SIGINT);
Eric Andersencb57d552001-06-28 07:25:16 +00006745 }
Eric Andersend35c5df2002-01-09 15:37:36 +00006746#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006747 if (jp->jobctl) {
6748#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006749 if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006750 error("TIOCSPGRP failed, errno=%d\n", errno);
6751#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006752 if (tcsetpgrp(2, mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006753 error("tcsetpgrp failed, errno=%d\n", errno);
6754#endif
6755 }
Eric Andersend35c5df2002-01-09 15:37:36 +00006756 if (jp->state == CONFIG_ASH_JOB_CONTROLTOPPED)
Eric Andersencb57d552001-06-28 07:25:16 +00006757 curjob = jp - jobtab + 1;
6758#endif
6759 status = jp->ps[jp->nprocs - 1].status;
6760 /* convert to 8 bits */
6761 if (WIFEXITED(status))
6762 st = WEXITSTATUS(status);
Eric Andersend35c5df2002-01-09 15:37:36 +00006763#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006764 else if (WIFSTOPPED(status))
6765 st = WSTOPSIG(status) + 128;
6766#endif
6767 else
6768 st = WTERMSIG(status) + 128;
Eric Andersend35c5df2002-01-09 15:37:36 +00006769#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006770 if (jp->jobctl) {
6771 /*
6772 * This is truly gross.
6773 * If we're doing job control, then we did a TIOCSPGRP which
6774 * caused us (the shell) to no longer be in the controlling
6775 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
6776 * intuit from the subprocess exit status whether a SIGINT
6777 * occured, and if so interrupt ourselves. Yuck. - mycroft
6778 */
6779 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
6780 raise(SIGINT);
6781 }
Eric Andersen2870d962001-07-02 17:27:21 +00006782 if (jp->state == JOBDONE)
6783
Eric Andersencb57d552001-06-28 07:25:16 +00006784#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006785 freejob(jp);
6786 INTON;
6787 return st;
6788}
6789
6790
6791
6792/*
6793 * Wait for a process to terminate.
6794 */
6795
Eric Andersen62483552001-07-10 06:09:16 +00006796/*
6797 * Do a wait system call. If job control is compiled in, we accept
6798 * stopped processes. If block is zero, we return a value of zero
6799 * rather than blocking.
6800 *
6801 * System V doesn't have a non-blocking wait system call. It does
6802 * have a SIGCLD signal that is sent to a process when one of it's
6803 * children dies. The obvious way to use SIGCLD would be to install
6804 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
6805 * was received, and have waitproc bump another counter when it got
6806 * the status of a process. Waitproc would then know that a wait
6807 * system call would not block if the two counters were different.
6808 * This approach doesn't work because if a process has children that
6809 * have not been waited for, System V will send it a SIGCLD when it
6810 * installs a signal handler for SIGCLD. What this means is that when
6811 * a child exits, the shell will be sent SIGCLD signals continuously
6812 * until is runs out of stack space, unless it does a wait call before
6813 * restoring the signal handler. The code below takes advantage of
6814 * this (mis)feature by installing a signal handler for SIGCLD and
6815 * then checking to see whether it was called. If there are any
6816 * children to be waited for, it will be.
6817 *
6818 */
6819
6820static inline int
6821waitproc(int block, int *status)
6822{
6823 int flags;
6824
6825 flags = 0;
Eric Andersend35c5df2002-01-09 15:37:36 +00006826#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen62483552001-07-10 06:09:16 +00006827 if (jobctl)
6828 flags |= WUNTRACED;
6829#endif
6830 if (block == 0)
6831 flags |= WNOHANG;
6832 return wait3(status, flags, (struct rusage *)NULL);
6833}
6834
Eric Andersencb57d552001-06-28 07:25:16 +00006835static int
Eric Andersen62483552001-07-10 06:09:16 +00006836dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00006837{
6838 int pid;
6839 int status;
6840 struct procstat *sp;
6841 struct job *jp;
6842 struct job *thisjob;
6843 int done;
6844 int stopped;
6845 int core;
6846 int sig;
6847
6848 TRACE(("dowait(%d) called\n", block));
6849 do {
6850 pid = waitproc(block, &status);
6851 TRACE(("wait returns %d, status=%d\n", pid, status));
6852 } while (!(block & 2) && pid == -1 && errno == EINTR);
6853 if (pid <= 0)
6854 return pid;
6855 INTOFF;
6856 thisjob = NULL;
6857 for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
6858 if (jp->used) {
6859 done = 1;
6860 stopped = 1;
6861 for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
6862 if (sp->pid == -1)
6863 continue;
6864 if (sp->pid == pid) {
6865 TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
6866 sp->status = status;
6867 thisjob = jp;
6868 }
6869 if (sp->status == -1)
6870 stopped = 0;
6871 else if (WIFSTOPPED(sp->status))
6872 done = 0;
6873 }
Eric Andersen2870d962001-07-02 17:27:21 +00006874 if (stopped) { /* stopped or done */
Eric Andersend35c5df2002-01-09 15:37:36 +00006875 int state = done? JOBDONE : CONFIG_ASH_JOB_CONTROLTOPPED;
Eric Andersencb57d552001-06-28 07:25:16 +00006876 if (jp->state != state) {
6877 TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
6878 jp->state = state;
Eric Andersend35c5df2002-01-09 15:37:36 +00006879#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006880 if (done && curjob == jp - jobtab + 1)
Eric Andersen2870d962001-07-02 17:27:21 +00006881 curjob = 0; /* no current job */
Eric Andersencb57d552001-06-28 07:25:16 +00006882#endif
6883 }
6884 }
6885 }
6886 }
6887 INTON;
6888 if (! rootshell || ! iflag || (job && thisjob == job)) {
6889 core = WCOREDUMP(status);
Eric Andersend35c5df2002-01-09 15:37:36 +00006890#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006891 if (WIFSTOPPED(status)) sig = WSTOPSIG(status);
6892 else
6893#endif
6894 if (WIFEXITED(status)) sig = 0;
6895 else sig = WTERMSIG(status);
6896
6897 if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
6898 if (thisjob != job)
Eric Andersen3102ac42001-07-06 04:26:23 +00006899 out2fmt("%d: ", pid);
Eric Andersend35c5df2002-01-09 15:37:36 +00006900#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006901 if (sig == SIGTSTP && rootshell && iflag)
Eric Andersen3102ac42001-07-06 04:26:23 +00006902 out2fmt("%%%ld ",
Eric Andersencb57d552001-06-28 07:25:16 +00006903 (long)(job - jobtab + 1));
6904#endif
6905 if (sig < NSIG && sys_siglist[sig])
6906 out2str(sys_siglist[sig]);
6907 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006908 out2fmt("Signal %d", sig);
Eric Andersencb57d552001-06-28 07:25:16 +00006909 if (core)
6910 out2str(" - core dumped");
6911 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00006912 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00006913 TRACE(("Not printing status: status=%d, sig=%d\n",
Eric Andersencb57d552001-06-28 07:25:16 +00006914 status, sig));
6915 }
6916 } else {
6917 TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
6918 if (thisjob)
6919 thisjob->changed = 1;
6920 }
6921 return pid;
6922}
6923
6924
6925
Eric Andersencb57d552001-06-28 07:25:16 +00006926
6927/*
6928 * return 1 if there are stopped jobs, otherwise 0
6929 */
Eric Andersencb57d552001-06-28 07:25:16 +00006930static int
Eric Andersen2870d962001-07-02 17:27:21 +00006931stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006932{
6933 int jobno;
6934 struct job *jp;
6935
6936 if (job_warning)
6937 return (0);
6938 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
6939 if (jp->used == 0)
6940 continue;
Eric Andersend35c5df2002-01-09 15:37:36 +00006941 if (jp->state == CONFIG_ASH_JOB_CONTROLTOPPED) {
Eric Andersencb57d552001-06-28 07:25:16 +00006942 out2str("You have stopped jobs.\n");
6943 job_warning = 2;
6944 return (1);
6945 }
6946 }
6947
6948 return (0);
6949}
6950
6951/*
6952 * Return a string identifying a command (to be printed by the
6953 * jobs command.
6954 */
6955
6956static char *cmdnextc;
6957static int cmdnleft;
Eric Andersen2870d962001-07-02 17:27:21 +00006958#define MAXCMDTEXT 200
Eric Andersencb57d552001-06-28 07:25:16 +00006959
Eric Andersen2870d962001-07-02 17:27:21 +00006960static void
6961cmdputs(const char *s)
6962{
6963 const char *p;
6964 char *q;
6965 char c;
6966 int subtype = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00006967
Eric Andersen2870d962001-07-02 17:27:21 +00006968 if (cmdnleft <= 0)
6969 return;
6970 p = s;
6971 q = cmdnextc;
6972 while ((c = *p++) != '\0') {
6973 if (c == CTLESC)
6974 *q++ = *p++;
6975 else if (c == CTLVAR) {
6976 *q++ = '$';
6977 if (--cmdnleft > 0)
6978 *q++ = '{';
6979 subtype = *p++;
6980 } else if (c == '=' && subtype != 0) {
6981 *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
6982 subtype = 0;
6983 } else if (c == CTLENDVAR) {
6984 *q++ = '}';
6985 } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
6986 cmdnleft++; /* ignore it */
6987 else
6988 *q++ = c;
6989 if (--cmdnleft <= 0) {
6990 *q++ = '.';
6991 *q++ = '.';
6992 *q++ = '.';
6993 break;
6994 }
6995 }
6996 cmdnextc = q;
Eric Andersencb57d552001-06-28 07:25:16 +00006997}
6998
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00006999#define CMDTXT_TABLE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007000#ifdef CMDTXT_TABLE
7001/*
7002 * To collect a lot of redundant code in cmdtxt() case statements, we
7003 * implement a mini language here. Each type of node struct has an
7004 * associated instruction sequence that operates on its members via
7005 * their offsets. The instruction are pack in unsigned chars with
7006 * format IIDDDDDE where the bits are
7007 * I : part of the instruction opcode, which are
7008 * 00 : member is a pointer to another node -- process it recursively
7009 * 40 : member is a pointer to a char string -- output it
7010 * 80 : output the string whose index is stored in the data field
7011 * CC : flag signaling that this case needs external processing
7012 * D : data - either the (shifted) index of a fixed string to output or
7013 * the actual offset of the member to operate on in the struct
7014 * (since we assume bit 0 is set, the offset is not shifted)
7015 * E : flag signaling end of instruction sequence
7016 *
7017 * WARNING: In order to handle larger offsets for 64bit archs, this code
7018 * assumes that no offset can be an odd number and stores the
7019 * end-of-instructions flag in bit 0.
7020 */
Eric Andersencb57d552001-06-28 07:25:16 +00007021
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007022#define CMDTXT_NOMORE 0x01 /* NOTE: no offset should be odd */
7023#define CMDTXT_CHARPTR 0x40
7024#define CMDTXT_STRING 0x80
7025#define CMDTXT_SPECIAL 0xC0
7026#define CMDTXT_OFFSETMASK 0x3E
7027
7028static const char * const cmdtxt_strings[] = {
7029 /* 0 1 2 3 4 5 6 7 */
7030 "; ", "(", ")", " && ", " || ", "if ", "; then ", "...",
7031 /* 8 9 10 11 12 13 */
7032 "while ", "; do ", "; done", "until ", "for ", " in ...",
7033 /* 14 15 16 17 */
7034 "case ", "???", "() ...", "<<..."
7035};
7036
7037static const char * const redir_strings[] = {
7038 ">", "<", "<>", ">>", ">|", ">&", "<&"
7039};
7040
7041static const unsigned char cmdtxt_ops[] = {
7042#define CMDTXT_NSEMI 0
7043 offsetof(union node, nbinary.ch1),
7044 0|CMDTXT_STRING,
7045 offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7046#define CMDTXT_NCMD (CMDTXT_NSEMI + 3)
7047#define CMDTXT_NPIPE (CMDTXT_NCMD)
7048#define CMDTXT_NCASE (CMDTXT_NCMD)
7049#define CMDTXT_NTO (CMDTXT_NCMD)
7050#define CMDTXT_NFROM (CMDTXT_NCMD)
7051#define CMDTXT_NFROMTO (CMDTXT_NCMD)
7052#define CMDTXT_NAPPEND (CMDTXT_NCMD)
7053#define CMDTXT_NTOOV (CMDTXT_NCMD)
7054#define CMDTXT_NTOFD (CMDTXT_NCMD)
7055#define CMDTXT_NFROMFD (CMDTXT_NCMD)
7056 CMDTXT_SPECIAL,
7057#define CMDTXT_NREDIR (CMDTXT_NPIPE + 1)
7058#define CMDTXT_NBACKGND (CMDTXT_NREDIR)
7059 offsetof(union node, nredir.n)|CMDTXT_NOMORE,
7060#define CMDTXT_NSUBSHELL (CMDTXT_NBACKGND + 1)
7061 (1*2)|CMDTXT_STRING,
7062 offsetof(union node, nredir.n),
7063 (2*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7064#define CMDTXT_NAND (CMDTXT_NSUBSHELL + 3)
7065 offsetof(union node, nbinary.ch1),
7066 (3*2)|CMDTXT_STRING,
7067 offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7068#define CMDTXT_NOR (CMDTXT_NAND + 3)
7069 offsetof(union node, nbinary.ch1),
7070 (4*2)|CMDTXT_STRING,
7071 offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7072#define CMDTXT_NIF (CMDTXT_NOR + 3)
7073 (5*2)|CMDTXT_STRING,
7074 offsetof(union node, nif.test),
7075 (6*2)|CMDTXT_STRING,
7076 offsetof(union node, nif.ifpart),
7077 (7*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7078#define CMDTXT_NWHILE (CMDTXT_NIF + 5)
7079 (8*2)|CMDTXT_STRING,
7080 offsetof(union node, nbinary.ch1),
7081 (9*2)|CMDTXT_STRING,
7082 offsetof(union node, nbinary.ch2),
7083 (10*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7084#define CMDTXT_NUNTIL (CMDTXT_NWHILE + 5)
7085 (11*2)|CMDTXT_STRING,
7086 offsetof(union node, nbinary.ch1),
7087 (9*2)|CMDTXT_STRING,
7088 offsetof(union node, nbinary.ch2),
7089 (10*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7090#define CMDTXT_NFOR (CMDTXT_NUNTIL + 5)
7091 (12*2)|CMDTXT_STRING,
7092 offsetof(union node, nfor.var)|CMDTXT_CHARPTR,
7093 (13*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7094#define CMDTXT_NCLIST (CMDTXT_NFOR + 3) /* TODO: IS THIS CORRECT??? */
7095#define CMDTXT_NNOT (CMDTXT_NCLIST) /* TODO: IS THIS CORRECT??? */
7096 (15*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7097#define CMDTXT_NDEFUN (CMDTXT_NCLIST + 1)
7098 offsetof(union node, narg.text)|CMDTXT_CHARPTR,
7099 (16*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7100#define CMDTXT_NARG (CMDTXT_NDEFUN + 2)
7101 offsetof(union node, narg.text)|CMDTXT_CHARPTR|CMDTXT_NOMORE,
7102#define CMDTXT_NHERE (CMDTXT_NARG + 1)
7103#define CMDTXT_NXHERE (CMDTXT_NHERE)
7104 (17*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7105};
7106
7107#if CMDTXT_NXHERE != 36
7108#error CMDTXT_NXHERE
7109#endif
7110
7111static const unsigned char cmdtxt_ops_index[26] = {
7112 CMDTXT_NSEMI,
7113 CMDTXT_NCMD,
7114 CMDTXT_NPIPE,
7115 CMDTXT_NREDIR,
7116 CMDTXT_NBACKGND,
7117 CMDTXT_NSUBSHELL,
7118 CMDTXT_NAND,
7119 CMDTXT_NOR,
7120 CMDTXT_NIF,
7121 CMDTXT_NWHILE,
7122 CMDTXT_NUNTIL,
7123 CMDTXT_NFOR,
7124 CMDTXT_NCASE,
7125 CMDTXT_NCLIST,
7126 CMDTXT_NDEFUN,
7127 CMDTXT_NARG,
7128 CMDTXT_NTO,
7129 CMDTXT_NFROM,
7130 CMDTXT_NFROMTO,
7131 CMDTXT_NAPPEND,
7132 CMDTXT_NTOOV,
7133 CMDTXT_NTOFD,
7134 CMDTXT_NFROMFD,
7135 CMDTXT_NHERE,
7136 CMDTXT_NXHERE,
7137 CMDTXT_NNOT,
7138};
7139
7140static void
7141cmdtxt(const union node *n)
7142{
7143 const char *p;
7144
7145 if (n == NULL)
7146 return;
7147
7148 p = cmdtxt_ops + (int) cmdtxt_ops_index[n->type];
7149 if ((*p & CMDTXT_SPECIAL) != CMDTXT_SPECIAL) { /* normal case */
7150 do {
7151 if (*p & CMDTXT_STRING) { /* output fixed string */
7152 cmdputs(cmdtxt_strings[((int)(*p & CMDTXT_OFFSETMASK) >> 1)]);
Manuel Novoa III c639a352001-08-12 17:32:56 +00007153 } else {
7154 const char *pf = ((const char *) n)
7155 + ((int)(*p & CMDTXT_OFFSETMASK));
7156 if (*p & CMDTXT_CHARPTR) { /* output dynamic string */
7157 cmdputs(*((const char **) pf));
7158 } else { /* output field */
7159 cmdtxt(*((const union node **) pf));
7160 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007161 }
7162 } while (!(*p++ & CMDTXT_NOMORE));
7163 } else if (n->type == NCMD) {
7164 union node *np;
7165 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7166 cmdtxt(np);
7167 if (np->narg.next)
7168 cmdputs(spcstr);
7169 }
7170 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7171 cmdputs(spcstr);
7172 cmdtxt(np);
7173 }
7174 } else if (n->type == NPIPE) {
7175 struct nodelist *lp;
7176 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7177 cmdtxt(lp->n);
7178 if (lp->next)
7179 cmdputs(" | ");
7180 }
7181 } else if (n->type == NCASE) {
7182 cmdputs(cmdtxt_strings[14]);
7183 cmdputs(n->ncase.expr->narg.text);
7184 cmdputs(cmdtxt_strings[13]);
7185 } else {
7186#if (NTO != 16) || (NFROM != 17) || (NFROMTO != 18) || (NAPPEND != 19) || (NTOOV != 20) || (NTOFD != 21) || (NFROMFD != 22)
7187#error Assumption violated regarding range and ordering of NTO ... NFROMFD!
7188#endif
7189 char s[2];
7190
7191#ifdef DEBUG
7192 assert((n->type >= NTO) && (n->type <= NFROMFD));
7193#endif
7194
7195 p = redir_strings[n->type - NTO];
7196 if (n->nfile.fd != ('>' == *p)) {
7197 s[0] = n->nfile.fd + '0';
7198 s[1] = '\0';
7199 cmdputs(s);
7200 }
7201 cmdputs(p);
7202 if (n->type >= NTOFD) {
7203 s[0] = n->ndup.dupfd + '0';
7204 s[1] = '\0';
7205 cmdputs(s);
7206 } else {
7207 cmdtxt(n->nfile.fname);
7208 }
7209 }
7210}
7211#else /* CMDTXT_TABLE */
Eric Andersencb57d552001-06-28 07:25:16 +00007212static void
Eric Andersen2870d962001-07-02 17:27:21 +00007213cmdtxt(const union node *n)
7214{
Eric Andersencb57d552001-06-28 07:25:16 +00007215 union node *np;
7216 struct nodelist *lp;
7217 const char *p;
7218 int i;
7219 char s[2];
7220
7221 if (n == NULL)
7222 return;
7223 switch (n->type) {
7224 case NSEMI:
7225 cmdtxt(n->nbinary.ch1);
7226 cmdputs("; ");
7227 cmdtxt(n->nbinary.ch2);
7228 break;
7229 case NAND:
7230 cmdtxt(n->nbinary.ch1);
7231 cmdputs(" && ");
7232 cmdtxt(n->nbinary.ch2);
7233 break;
7234 case NOR:
7235 cmdtxt(n->nbinary.ch1);
7236 cmdputs(" || ");
7237 cmdtxt(n->nbinary.ch2);
7238 break;
7239 case NPIPE:
7240 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7241 cmdtxt(lp->n);
7242 if (lp->next)
7243 cmdputs(" | ");
7244 }
7245 break;
7246 case NSUBSHELL:
7247 cmdputs("(");
7248 cmdtxt(n->nredir.n);
7249 cmdputs(")");
7250 break;
7251 case NREDIR:
7252 case NBACKGND:
7253 cmdtxt(n->nredir.n);
7254 break;
7255 case NIF:
7256 cmdputs("if ");
7257 cmdtxt(n->nif.test);
7258 cmdputs("; then ");
7259 cmdtxt(n->nif.ifpart);
7260 cmdputs("...");
7261 break;
7262 case NWHILE:
7263 cmdputs("while ");
7264 goto until;
7265 case NUNTIL:
7266 cmdputs("until ");
7267until:
7268 cmdtxt(n->nbinary.ch1);
7269 cmdputs("; do ");
7270 cmdtxt(n->nbinary.ch2);
7271 cmdputs("; done");
7272 break;
7273 case NFOR:
7274 cmdputs("for ");
7275 cmdputs(n->nfor.var);
7276 cmdputs(" in ...");
7277 break;
7278 case NCASE:
7279 cmdputs("case ");
7280 cmdputs(n->ncase.expr->narg.text);
7281 cmdputs(" in ...");
7282 break;
7283 case NDEFUN:
7284 cmdputs(n->narg.text);
7285 cmdputs("() ...");
7286 break;
7287 case NCMD:
7288 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7289 cmdtxt(np);
7290 if (np->narg.next)
7291 cmdputs(spcstr);
7292 }
7293 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7294 cmdputs(spcstr);
7295 cmdtxt(np);
7296 }
7297 break;
7298 case NARG:
7299 cmdputs(n->narg.text);
7300 break;
7301 case NTO:
7302 p = ">"; i = 1; goto redir;
7303 case NAPPEND:
7304 p = ">>"; i = 1; goto redir;
7305 case NTOFD:
7306 p = ">&"; i = 1; goto redir;
7307 case NTOOV:
7308 p = ">|"; i = 1; goto redir;
7309 case NFROM:
7310 p = "<"; i = 0; goto redir;
7311 case NFROMFD:
7312 p = "<&"; i = 0; goto redir;
7313 case NFROMTO:
7314 p = "<>"; i = 0; goto redir;
7315redir:
7316 if (n->nfile.fd != i) {
7317 s[0] = n->nfile.fd + '0';
7318 s[1] = '\0';
7319 cmdputs(s);
7320 }
7321 cmdputs(p);
7322 if (n->type == NTOFD || n->type == NFROMFD) {
7323 s[0] = n->ndup.dupfd + '0';
7324 s[1] = '\0';
7325 cmdputs(s);
7326 } else {
7327 cmdtxt(n->nfile.fname);
7328 }
7329 break;
7330 case NHERE:
7331 case NXHERE:
7332 cmdputs("<<...");
7333 break;
7334 default:
7335 cmdputs("???");
7336 break;
7337 }
7338}
Manuel Novoa III c639a352001-08-12 17:32:56 +00007339#endif /* CMDTXT_TABLE */
Eric Andersencb57d552001-06-28 07:25:16 +00007340
Eric Andersen2870d962001-07-02 17:27:21 +00007341static char *
7342commandtext(const union node *n)
7343{
7344 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007345
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007346 cmdnextc = name = xmalloc(MAXCMDTEXT);
Eric Andersen2870d962001-07-02 17:27:21 +00007347 cmdnleft = MAXCMDTEXT - 4;
7348 cmdtxt(n);
7349 *cmdnextc = '\0';
7350 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00007351}
7352
Eric Andersen2870d962001-07-02 17:27:21 +00007353
Eric Andersencb57d552001-06-28 07:25:16 +00007354static void waitonint(int sig) {
7355 intreceived = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00007356}
Eric Andersenec074692001-10-31 11:05:49 +00007357
Eric Andersend35c5df2002-01-09 15:37:36 +00007358#ifdef CONFIG_ASH_MAIL
Eric Andersenec074692001-10-31 11:05:49 +00007359
Eric Andersencb57d552001-06-28 07:25:16 +00007360/*
Eric Andersenec074692001-10-31 11:05:49 +00007361 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +00007362 */
7363
7364
7365#define MAXMBOXES 10
7366
7367
Eric Andersen2870d962001-07-02 17:27:21 +00007368static int nmboxes; /* number of mailboxes */
7369static time_t mailtime[MAXMBOXES]; /* times of mailboxes */
Eric Andersencb57d552001-06-28 07:25:16 +00007370
7371
7372
7373/*
7374 * Print appropriate message(s) if mail has arrived. If the argument is
7375 * nozero, then the value of MAIL has changed, so we just update the
7376 * values.
7377 */
7378
7379static void
Eric Andersen2870d962001-07-02 17:27:21 +00007380chkmail(int silent)
Eric Andersencb57d552001-06-28 07:25:16 +00007381{
7382 int i;
7383 const char *mpath;
7384 char *p;
7385 char *q;
7386 struct stackmark smark;
7387 struct stat statb;
7388
7389 if (silent)
7390 nmboxes = 10;
7391 if (nmboxes == 0)
7392 return;
7393 setstackmark(&smark);
7394 mpath = mpathset()? mpathval() : mailval();
7395 for (i = 0 ; i < nmboxes ; i++) {
7396 p = padvance(&mpath, nullstr);
7397 if (p == NULL)
7398 break;
7399 if (*p == '\0')
7400 continue;
7401 for (q = p ; *q ; q++);
7402#ifdef DEBUG
7403 if (q[-1] != '/')
7404 abort();
7405#endif
Eric Andersen2870d962001-07-02 17:27:21 +00007406 q[-1] = '\0'; /* delete trailing '/' */
Eric Andersencb57d552001-06-28 07:25:16 +00007407 if (stat(p, &statb) < 0)
7408 statb.st_size = 0;
7409 if (statb.st_size > mailtime[i] && ! silent) {
Eric Andersen3102ac42001-07-06 04:26:23 +00007410 out2fmt(snlfmt,
7411 pathopt? pathopt : "you have mail");
Eric Andersencb57d552001-06-28 07:25:16 +00007412 }
7413 mailtime[i] = statb.st_size;
Eric Andersencb57d552001-06-28 07:25:16 +00007414 }
7415 nmboxes = i;
7416 popstackmark(&smark);
7417}
Eric Andersencb57d552001-06-28 07:25:16 +00007418
Eric Andersend35c5df2002-01-09 15:37:36 +00007419#endif /* CONFIG_ASH_MAIL */
Eric Andersenec074692001-10-31 11:05:49 +00007420
Eric Andersencb57d552001-06-28 07:25:16 +00007421#define PROFILE 0
7422
Eric Andersencb57d552001-06-28 07:25:16 +00007423#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007424static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007425extern int etext();
7426#endif
7427
Robert Griebl64f70cc2002-05-14 23:22:06 +00007428static int isloginsh = 0;
7429
Eric Andersen2870d962001-07-02 17:27:21 +00007430static void read_profile (const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007431static void cmdloop (int);
7432static void options (int);
Eric Andersen2870d962001-07-02 17:27:21 +00007433static void setoption (int, int);
7434static void procargs (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00007435
Eric Andersen2870d962001-07-02 17:27:21 +00007436
Eric Andersencb57d552001-06-28 07:25:16 +00007437/*
7438 * Main routine. We initialize things, parse the arguments, execute
7439 * profiles if we're a login shell, and then call cmdloop to execute
7440 * commands. The setjmp call sets up the location to jump to when an
7441 * exception occurs. When an exception occurs the variable "state"
7442 * is used to figure out how far we had gotten.
7443 */
7444
7445int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007446ash_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007447{
7448 struct jmploc jmploc;
7449 struct stackmark smark;
7450 volatile int state;
Eric Andersen62483552001-07-10 06:09:16 +00007451 const char *shinit;
Eric Andersencb57d552001-06-28 07:25:16 +00007452
Eric Andersencb57d552001-06-28 07:25:16 +00007453 BLTINCMD = find_builtin("builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00007454 EXECCMD = find_builtin("exec");
7455 EVALCMD = find_builtin("eval");
7456
Eric Andersenbdfd0d72001-10-24 05:00:29 +00007457#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
Eric Andersen1c039232001-07-07 00:05:55 +00007458 unsetenv("PS1");
7459 unsetenv("PS2");
7460#endif
7461
Eric Andersencb57d552001-06-28 07:25:16 +00007462#if PROFILE
7463 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7464#endif
7465#if defined(linux) || defined(__GNU__)
7466 signal(SIGCHLD, SIG_DFL);
7467#endif
7468 state = 0;
7469 if (setjmp(jmploc.loc)) {
7470 INTOFF;
7471 /*
7472 * When a shell procedure is executed, we raise the
7473 * exception EXSHELLPROC to clean up before executing
7474 * the shell procedure.
7475 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007476 if (exception == EXSHELLPROC) {
Eric Andersencb57d552001-06-28 07:25:16 +00007477 rootpid = getpid();
7478 rootshell = 1;
7479 minusc = NULL;
7480 state = 3;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007481 } else {
7482 if (exception == EXEXEC) {
7483 exitstatus = exerrno;
7484 } else if (exception == EXERROR) {
7485 exitstatus = 2;
7486 }
Eric Andersencb57d552001-06-28 07:25:16 +00007487 if (state == 0 || iflag == 0 || ! rootshell)
7488 exitshell(exitstatus);
7489 }
7490 reset();
Eric Andersen2870d962001-07-02 17:27:21 +00007491 if (exception == EXINT) {
Eric Andersencb57d552001-06-28 07:25:16 +00007492 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00007493 }
7494 popstackmark(&smark);
Eric Andersen2870d962001-07-02 17:27:21 +00007495 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007496 if (state == 1)
7497 goto state1;
7498 else if (state == 2)
7499 goto state2;
7500 else if (state == 3)
7501 goto state3;
7502 else
7503 goto state4;
7504 }
7505 handler = &jmploc;
7506#ifdef DEBUG
7507 opentrace();
7508 trputs("Shell args: "); trargs(argv);
7509#endif
7510 rootpid = getpid();
7511 rootshell = 1;
7512 init();
7513 setstackmark(&smark);
7514 procargs(argc, argv);
Robert Griebl64f70cc2002-05-14 23:22:06 +00007515 if (argv[0] && argv[0][0] == '-')
7516 isloginsh = 1;
7517 if (isloginsh) {
Eric Andersencb57d552001-06-28 07:25:16 +00007518 state = 1;
7519 read_profile("/etc/profile");
7520state1:
7521 state = 2;
7522 read_profile(".profile");
7523 }
7524state2:
7525 state = 3;
7526#ifndef linux
7527 if (getuid() == geteuid() && getgid() == getegid()) {
7528#endif
7529 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7530 state = 3;
7531 read_profile(shinit);
7532 }
7533#ifndef linux
7534 }
7535#endif
7536state3:
7537 state = 4;
7538 if (sflag == 0 || minusc) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007539 static const char sigs[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00007540 SIGINT, SIGQUIT, SIGHUP,
Eric Andersencb57d552001-06-28 07:25:16 +00007541#ifdef SIGTSTP
7542 SIGTSTP,
7543#endif
7544 SIGPIPE
7545 };
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007546#define SIGSSIZE ((sizeof(sigs)/sizeof(sigs[0])) - 1) /* trailing nul */
Eric Andersencb57d552001-06-28 07:25:16 +00007547 int i;
7548
7549 for (i = 0; i < SIGSSIZE; i++)
7550 setsignal(sigs[i]);
7551 }
7552
7553 if (minusc)
7554 evalstring(minusc, 0);
7555
7556 if (sflag || minusc == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00007557state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007558 cmdloop(1);
7559 }
7560#if PROFILE
7561 monitor(0);
7562#endif
7563 exitshell(exitstatus);
7564 /* NOTREACHED */
7565}
7566
7567
7568/*
7569 * Read and execute commands. "Top" is nonzero for the top level command
7570 * loop; it turns on prompting if the shell is interactive.
7571 */
7572
7573static void
Eric Andersen2870d962001-07-02 17:27:21 +00007574cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00007575{
7576 union node *n;
7577 struct stackmark smark;
7578 int inter;
7579 int numeof = 0;
7580
7581 TRACE(("cmdloop(%d) called\n", top));
7582 setstackmark(&smark);
7583 for (;;) {
7584 if (pendingsigs)
7585 dotrap();
7586 inter = 0;
7587 if (iflag && top) {
7588 inter++;
7589 showjobs(1);
Eric Andersend35c5df2002-01-09 15:37:36 +00007590#ifdef CONFIG_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +00007591 chkmail(0);
Eric Andersenec074692001-10-31 11:05:49 +00007592#endif
Eric Andersen3102ac42001-07-06 04:26:23 +00007593 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00007594 }
7595 n = parsecmd(inter);
7596 /* showtree(n); DEBUG */
7597 if (n == NEOF) {
7598 if (!top || numeof >= 50)
7599 break;
7600 if (!stoppedjobs()) {
7601 if (!Iflag)
7602 break;
7603 out2str("\nUse \"exit\" to leave shell.\n");
7604 }
7605 numeof++;
7606 } else if (n != NULL && nflag == 0) {
7607 job_warning = (job_warning == 2) ? 1 : 0;
7608 numeof = 0;
7609 evaltree(n, 0);
7610 }
7611 popstackmark(&smark);
7612 setstackmark(&smark);
7613 if (evalskip == SKIPFILE) {
7614 evalskip = 0;
7615 break;
7616 }
7617 }
7618 popstackmark(&smark);
7619}
7620
7621
7622
7623/*
7624 * Read /etc/profile or .profile. Return on error.
7625 */
7626
7627static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007628read_profile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00007629{
7630 int fd;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007631 int xflag_save;
7632 int vflag_save;
Eric Andersencb57d552001-06-28 07:25:16 +00007633
7634 INTOFF;
7635 if ((fd = open(name, O_RDONLY)) >= 0)
7636 setinputfd(fd, 1);
7637 INTON;
7638 if (fd < 0)
7639 return;
7640 /* -q turns off -x and -v just when executing init files */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007641 /* Note: Might do a little redundant work, but reduces code size. */
7642 xflag_save = xflag;
7643 vflag_save = vflag;
Eric Andersencb57d552001-06-28 07:25:16 +00007644 if (qflag) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007645 vflag = xflag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007646 }
7647 cmdloop(0);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007648 xflag = xflag_save;
7649 vflag = vflag_save;
Eric Andersencb57d552001-06-28 07:25:16 +00007650 popfile();
7651}
7652
7653
7654
7655/*
7656 * Read a file containing shell functions.
7657 */
7658
7659static void
Eric Andersen2870d962001-07-02 17:27:21 +00007660readcmdfile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00007661{
7662 int fd;
7663
7664 INTOFF;
7665 if ((fd = open(name, O_RDONLY)) >= 0)
7666 setinputfd(fd, 1);
7667 else
7668 error("Can't open %s", name);
7669 INTON;
7670 cmdloop(0);
7671 popfile();
7672}
7673
7674
7675
7676/*
7677 * Take commands from a file. To be compatable we should do a path
7678 * search for the file, which is necessary to find sub-commands.
7679 */
7680
Eric Andersen62483552001-07-10 06:09:16 +00007681static inline char *
Eric Andersen74400cc2001-10-18 04:11:39 +00007682find_dot_file(char *mybasename)
Eric Andersencb57d552001-06-28 07:25:16 +00007683{
7684 char *fullname;
7685 const char *path = pathval();
7686 struct stat statb;
7687
7688 /* don't try this for absolute or relative paths */
7689 if (strchr(mybasename, '/'))
7690 return mybasename;
7691
7692 while ((fullname = padvance(&path, mybasename)) != NULL) {
7693 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
7694 /*
7695 * Don't bother freeing here, since it will
7696 * be freed by the caller.
7697 */
7698 return fullname;
7699 }
7700 stunalloc(fullname);
7701 }
7702
7703 /* not found in the PATH */
7704 error("%s: not found", mybasename);
7705 /* NOTREACHED */
7706}
7707
7708static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007709dotcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007710{
7711 struct strlist *sp;
Eric Andersen69a20f02001-10-31 10:40:37 +00007712 volatile struct shparam saveparam;
Eric Andersencb57d552001-06-28 07:25:16 +00007713 exitstatus = 0;
7714
7715 for (sp = cmdenviron; sp ; sp = sp->next)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007716 setvareq(xstrdup(sp->text), VSTRFIXED|VTEXTFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +00007717
Eric Andersen2870d962001-07-02 17:27:21 +00007718 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00007719 char *fullname;
7720 struct stackmark smark;
7721
7722 setstackmark(&smark);
7723 fullname = find_dot_file(argv[1]);
Eric Andersen69a20f02001-10-31 10:40:37 +00007724
7725 if (argc>2) {
7726 saveparam = shellparam;
7727 shellparam.malloc = 0;
7728 shellparam.nparam = argc - 2;
7729 shellparam.p = argv + 2;
7730 };
7731
Eric Andersencb57d552001-06-28 07:25:16 +00007732 setinputfile(fullname, 1);
7733 commandname = fullname;
7734 cmdloop(0);
7735 popfile();
Eric Andersen69a20f02001-10-31 10:40:37 +00007736
7737 if (argc>2) {
7738 freeparam(&shellparam);
7739 shellparam = saveparam;
7740 };
7741
Eric Andersencb57d552001-06-28 07:25:16 +00007742 popstackmark(&smark);
7743 }
7744 return exitstatus;
7745}
7746
7747
7748static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007749exitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007750{
7751 if (stoppedjobs())
7752 return 0;
7753 if (argc > 1)
7754 exitstatus = number(argv[1]);
7755 else
7756 exitstatus = oexitstatus;
7757 exitshell(exitstatus);
7758 /* NOTREACHED */
7759}
Eric Andersen62483552001-07-10 06:09:16 +00007760
Eric Andersen2870d962001-07-02 17:27:21 +00007761static pointer
7762stalloc(int nbytes)
Eric Andersencb57d552001-06-28 07:25:16 +00007763{
7764 char *p;
7765
7766 nbytes = ALIGN(nbytes);
7767 if (nbytes > stacknleft) {
7768 int blocksize;
7769 struct stack_block *sp;
7770
7771 blocksize = nbytes;
7772 if (blocksize < MINSIZE)
7773 blocksize = MINSIZE;
7774 INTOFF;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007775 sp = xmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
Eric Andersencb57d552001-06-28 07:25:16 +00007776 sp->prev = stackp;
7777 stacknxt = sp->space;
7778 stacknleft = blocksize;
7779 stackp = sp;
7780 INTON;
7781 }
7782 p = stacknxt;
7783 stacknxt += nbytes;
7784 stacknleft -= nbytes;
7785 return p;
7786}
7787
7788
7789static void
Eric Andersen2870d962001-07-02 17:27:21 +00007790stunalloc(pointer p)
7791{
Eric Andersencb57d552001-06-28 07:25:16 +00007792#ifdef DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +00007793 if (p == NULL) { /*DEBUG */
Eric Andersencb57d552001-06-28 07:25:16 +00007794 write(2, "stunalloc\n", 10);
7795 abort();
7796 }
7797#endif
7798 if (!(stacknxt >= (char *)p && (char *)p >= stackp->space)) {
7799 p = stackp->space;
7800 }
7801 stacknleft += stacknxt - (char *)p;
7802 stacknxt = p;
7803}
7804
7805
Eric Andersencb57d552001-06-28 07:25:16 +00007806static void
Eric Andersen2870d962001-07-02 17:27:21 +00007807setstackmark(struct stackmark *mark)
7808{
Eric Andersencb57d552001-06-28 07:25:16 +00007809 mark->stackp = stackp;
7810 mark->stacknxt = stacknxt;
7811 mark->stacknleft = stacknleft;
7812 mark->marknext = markp;
7813 markp = mark;
7814}
7815
7816
7817static void
Eric Andersen2870d962001-07-02 17:27:21 +00007818popstackmark(struct stackmark *mark)
7819{
Eric Andersencb57d552001-06-28 07:25:16 +00007820 struct stack_block *sp;
7821
7822 INTOFF;
7823 markp = mark->marknext;
7824 while (stackp != mark->stackp) {
7825 sp = stackp;
7826 stackp = sp->prev;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00007827 free(sp);
Eric Andersencb57d552001-06-28 07:25:16 +00007828 }
7829 stacknxt = mark->stacknxt;
7830 stacknleft = mark->stacknleft;
7831 INTON;
7832}
7833
7834
7835/*
7836 * When the parser reads in a string, it wants to stick the string on the
7837 * stack and only adjust the stack pointer when it knows how big the
7838 * string is. Stackblock (defined in stack.h) returns a pointer to a block
7839 * of space on top of the stack and stackblocklen returns the length of
7840 * this block. Growstackblock will grow this space by at least one byte,
7841 * possibly moving it (like realloc). Grabstackblock actually allocates the
7842 * part of the block that has been used.
7843 */
7844
7845static void
Eric Andersen2870d962001-07-02 17:27:21 +00007846growstackblock(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00007847 char *p;
7848 int newlen = ALIGN(stacknleft * 2 + 100);
7849 char *oldspace = stacknxt;
7850 int oldlen = stacknleft;
7851 struct stack_block *sp;
7852 struct stack_block *oldstackp;
7853
7854 if (stacknxt == stackp->space && stackp != &stackbase) {
7855 INTOFF;
7856 oldstackp = stackp;
7857 sp = stackp;
7858 stackp = sp->prev;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007859 sp = xrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen);
Eric Andersencb57d552001-06-28 07:25:16 +00007860 sp->prev = stackp;
7861 stackp = sp;
7862 stacknxt = sp->space;
7863 stacknleft = newlen;
7864 {
7865 /* Stack marks pointing to the start of the old block
Eric Andersen2870d962001-07-02 17:27:21 +00007866 * must be relocated to point to the new block
Eric Andersencb57d552001-06-28 07:25:16 +00007867 */
7868 struct stackmark *xmark;
7869 xmark = markp;
7870 while (xmark != NULL && xmark->stackp == oldstackp) {
7871 xmark->stackp = stackp;
7872 xmark->stacknxt = stacknxt;
7873 xmark->stacknleft = stacknleft;
7874 xmark = xmark->marknext;
7875 }
7876 }
7877 INTON;
7878 } else {
7879 p = stalloc(newlen);
7880 memcpy(p, oldspace, oldlen);
Eric Andersen2870d962001-07-02 17:27:21 +00007881 stacknxt = p; /* free the space */
7882 stacknleft += newlen; /* we just allocated */
Eric Andersencb57d552001-06-28 07:25:16 +00007883 }
7884}
7885
7886
7887
Eric Andersen2870d962001-07-02 17:27:21 +00007888static inline void
7889grabstackblock(int len)
Eric Andersencb57d552001-06-28 07:25:16 +00007890{
7891 len = ALIGN(len);
7892 stacknxt += len;
7893 stacknleft -= len;
7894}
7895
7896
7897
7898/*
7899 * The following routines are somewhat easier to use that the above.
7900 * The user declares a variable of type STACKSTR, which may be declared
7901 * to be a register. The macro STARTSTACKSTR initializes things. Then
7902 * the user uses the macro STPUTC to add characters to the string. In
7903 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
7904 * grown as necessary. When the user is done, she can just leave the
7905 * string there and refer to it using stackblock(). Or she can allocate
7906 * the space for it using grabstackstr(). If it is necessary to allow
7907 * someone else to use the stack temporarily and then continue to grow
7908 * the string, the user should use grabstack to allocate the space, and
7909 * then call ungrabstr(p) to return to the previous mode of operation.
7910 *
7911 * USTPUTC is like STPUTC except that it doesn't check for overflow.
7912 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
7913 * is space for at least one character.
7914 */
7915
7916
7917static char *
Eric Andersen2870d962001-07-02 17:27:21 +00007918growstackstr(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00007919 int len = stackblocksize();
7920 if (herefd >= 0 && len >= 1024) {
7921 xwrite(herefd, stackblock(), len);
7922 sstrnleft = len - 1;
7923 return stackblock();
7924 }
7925 growstackblock();
7926 sstrnleft = stackblocksize() - len - 1;
7927 return stackblock() + len;
7928}
7929
7930
7931/*
7932 * Called from CHECKSTRSPACE.
7933 */
7934
7935static char *
7936makestrspace(size_t newlen) {
7937 int len = stackblocksize() - sstrnleft;
7938 do {
7939 growstackblock();
7940 sstrnleft = stackblocksize() - len;
7941 } while (sstrnleft < newlen);
7942 return stackblock() + len;
7943}
7944
7945
7946
7947static void
Eric Andersen2870d962001-07-02 17:27:21 +00007948ungrabstackstr(char *s, char *p)
7949{
Eric Andersencb57d552001-06-28 07:25:16 +00007950 stacknleft += stacknxt - s;
7951 stacknxt = s;
7952 sstrnleft = stacknleft - (p - s);
7953}
Eric Andersencb57d552001-06-28 07:25:16 +00007954/*
7955 * Miscelaneous builtins.
7956 */
7957
7958
7959#undef rflag
7960
Eric Andersencb57d552001-06-28 07:25:16 +00007961#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersen62483552001-07-10 06:09:16 +00007962typedef long rlim_t;
Eric Andersencb57d552001-06-28 07:25:16 +00007963#endif
7964
7965
7966
7967/*
7968 * The read builtin. The -e option causes backslashes to escape the
7969 * following character.
7970 *
7971 * This uses unbuffered input, which may be avoidable in some cases.
7972 */
7973
7974static int
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007975readcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007976{
7977 char **ap;
7978 int backslash;
7979 char c;
7980 int rflag;
7981 char *prompt;
7982 const char *ifs;
7983 char *p;
7984 int startword;
7985 int status;
7986 int i;
7987
7988 rflag = 0;
7989 prompt = NULL;
7990 while ((i = nextopt("p:r")) != '\0') {
7991 if (i == 'p')
7992 prompt = optionarg;
7993 else
7994 rflag = 1;
7995 }
7996 if (prompt && isatty(0)) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007997 out2str(prompt); /* read without cmdedit */
Eric Andersencb57d552001-06-28 07:25:16 +00007998 flushall();
7999 }
8000 if (*(ap = argptr) == NULL)
8001 error("arg count");
8002 if ((ifs = bltinlookup("IFS")) == NULL)
8003 ifs = defifs;
8004 status = 0;
8005 startword = 1;
8006 backslash = 0;
8007 STARTSTACKSTR(p);
8008 for (;;) {
8009 if (read(0, &c, 1) != 1) {
8010 status = 1;
8011 break;
8012 }
8013 if (c == '\0')
8014 continue;
8015 if (backslash) {
8016 backslash = 0;
8017 if (c != '\n')
8018 STPUTC(c, p);
8019 continue;
8020 }
8021 if (!rflag && c == '\\') {
8022 backslash++;
8023 continue;
8024 }
8025 if (c == '\n')
8026 break;
8027 if (startword && *ifs == ' ' && strchr(ifs, c)) {
8028 continue;
8029 }
8030 startword = 0;
8031 if (backslash && c == '\\') {
8032 if (read(0, &c, 1) != 1) {
8033 status = 1;
8034 break;
8035 }
8036 STPUTC(c, p);
8037 } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
8038 STACKSTRNUL(p);
8039 setvar(*ap, stackblock(), 0);
8040 ap++;
8041 startword = 1;
8042 STARTSTACKSTR(p);
8043 } else {
8044 STPUTC(c, p);
8045 }
8046 }
8047 STACKSTRNUL(p);
8048 /* Remove trailing blanks */
8049 while (stackblock() <= --p && strchr(ifs, *p) != NULL)
8050 *p = '\0';
8051 setvar(*ap, stackblock(), 0);
8052 while (*++ap != NULL)
8053 setvar(*ap, nullstr, 0);
8054 return status;
8055}
8056
8057
8058
8059static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008060umaskcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008061{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008062 static const char permuser[3] = "ugo";
8063 static const char permmode[3] = "rwx";
8064 static const short int permmask[] = {
8065 S_IRUSR, S_IWUSR, S_IXUSR,
8066 S_IRGRP, S_IWGRP, S_IXGRP,
8067 S_IROTH, S_IWOTH, S_IXOTH
8068 };
8069
Eric Andersencb57d552001-06-28 07:25:16 +00008070 char *ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008071 mode_t mask;
Eric Andersencb57d552001-06-28 07:25:16 +00008072 int i;
8073 int symbolic_mode = 0;
8074
Eric Andersen62483552001-07-10 06:09:16 +00008075 while (nextopt("S") != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00008076 symbolic_mode = 1;
8077 }
8078
8079 INTOFF;
8080 mask = umask(0);
8081 umask(mask);
8082 INTON;
8083
8084 if ((ap = *argptr) == NULL) {
8085 if (symbolic_mode) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008086 char buf[18];
8087 char *p = buf;
8088 for (i=0 ; i<3 ; i++) {
8089 int j;
8090 *p++ = permuser[i];
8091 *p++ = '=';
8092 for (j=0 ; j<3 ; j++) {
8093 if ((mask & permmask[3*i+j]) == 0) {
8094 *p++ = permmode[j];
8095 }
8096 }
8097 *p++ = ',';
8098 }
8099 *--p = 0;
8100 puts(buf);
Eric Andersencb57d552001-06-28 07:25:16 +00008101 } else {
Eric Andersen62483552001-07-10 06:09:16 +00008102 printf("%.4o\n", mask);
Eric Andersencb57d552001-06-28 07:25:16 +00008103 }
8104 } else {
Eric Andersen62483552001-07-10 06:09:16 +00008105 if (is_digit((unsigned char)*ap)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008106 mask = 0;
8107 do {
8108 if (*ap >= '8' || *ap < '0')
8109 error("Illegal number: %s", argv[1]);
8110 mask = (mask << 3) + (*ap - '0');
8111 } while (*++ap != '\0');
8112 umask(mask);
8113 } else {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008114 mask = ~mask & 0777;
Matt Kraai1f0c4362001-12-20 23:13:26 +00008115 if (! parse_mode(ap, &mask)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008116 error("Illegal mode: %s", ap);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008117 }
Eric Andersencb57d552001-06-28 07:25:16 +00008118 umask(~mask & 0777);
8119 }
8120 }
8121 return 0;
8122}
8123
8124/*
8125 * ulimit builtin
8126 *
8127 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
8128 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
8129 * ash by J.T. Conklin.
8130 *
8131 * Public domain.
8132 */
8133
8134struct limits {
8135 const char *name;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008136 short cmd;
8137 short factor; /* multiply by to get rlim_{cur,max} values */
Eric Andersencb57d552001-06-28 07:25:16 +00008138};
8139
8140static const struct limits limits[] = {
8141#ifdef RLIMIT_CPU
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008142 { "time(seconds)", RLIMIT_CPU, 1 },
Eric Andersencb57d552001-06-28 07:25:16 +00008143#endif
8144#ifdef RLIMIT_FSIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008145 { "file(blocks)", RLIMIT_FSIZE, 512 },
Eric Andersencb57d552001-06-28 07:25:16 +00008146#endif
8147#ifdef RLIMIT_DATA
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008148 { "data(kbytes)", RLIMIT_DATA, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008149#endif
8150#ifdef RLIMIT_STACK
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008151 { "stack(kbytes)", RLIMIT_STACK, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008152#endif
8153#ifdef RLIMIT_CORE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008154 { "coredump(blocks)", RLIMIT_CORE, 512 },
Eric Andersencb57d552001-06-28 07:25:16 +00008155#endif
8156#ifdef RLIMIT_RSS
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008157 { "memory(kbytes)", RLIMIT_RSS, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008158#endif
8159#ifdef RLIMIT_MEMLOCK
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008160 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008161#endif
8162#ifdef RLIMIT_NPROC
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008163 { "process(processes)", RLIMIT_NPROC, 1 },
Eric Andersencb57d552001-06-28 07:25:16 +00008164#endif
8165#ifdef RLIMIT_NOFILE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008166 { "nofiles(descriptors)", RLIMIT_NOFILE, 1 },
Eric Andersencb57d552001-06-28 07:25:16 +00008167#endif
8168#ifdef RLIMIT_VMEM
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008169 { "vmemory(kbytes)", RLIMIT_VMEM, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008170#endif
8171#ifdef RLIMIT_SWAP
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008172 { "swap(kbytes)", RLIMIT_SWAP, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008173#endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008174 { NULL, 0, 0 }
Eric Andersencb57d552001-06-28 07:25:16 +00008175};
8176
8177static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008178ulimitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008179{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008180 static const char unlimited_string[] = "unlimited";
Eric Andersen2870d962001-07-02 17:27:21 +00008181 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00008182 rlim_t val = 0;
8183 enum { SOFT = 0x1, HARD = 0x2 }
8184 how = SOFT | HARD;
Eric Andersen2870d962001-07-02 17:27:21 +00008185 const struct limits *l;
8186 int set, all = 0;
8187 int optc, what;
8188 struct rlimit limit;
Eric Andersencb57d552001-06-28 07:25:16 +00008189
8190 what = 'f';
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008191
8192 while ((optc = nextopt("HSa"
8193#ifdef RLIMIT_CPU
8194 "t"
8195#endif
8196#ifdef RLIMIT_FSIZE
8197 "f"
8198#endif
8199#ifdef RLIMIT_DATA
8200 "d"
8201#endif
8202#ifdef RLIMIT_STACK
8203 "s"
8204#endif
8205#ifdef RLIMIT_CORE
8206 "c"
8207#endif
8208#ifdef RLIMIT_RSS
8209 "m"
8210#endif
8211#ifdef RLIMIT_MEMLOCK
8212 "l"
8213#endif
8214#ifdef RLIMIT_NPROC
8215 "p"
8216#endif
8217#ifdef RLIMIT_NOFILE
8218 "n"
8219#endif
8220#ifdef RLIMIT_VMEM
8221 "v"
8222#endif
8223#ifdef RLIMIT_SWAP
8224 "w"
8225#endif
8226 )) != '\0') {
8227 if (optc == 'H') {
Eric Andersencb57d552001-06-28 07:25:16 +00008228 how = HARD;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008229 } else if (optc == 'S') {
Eric Andersencb57d552001-06-28 07:25:16 +00008230 how = SOFT;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008231 } else if (optc == 'a') {
Eric Andersencb57d552001-06-28 07:25:16 +00008232 all = 1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008233 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00008234 what = optc;
8235 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008236 }
Eric Andersencb57d552001-06-28 07:25:16 +00008237
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008238 for (l = limits; l->name; l++) {
8239 if(l->name[0] == what)
8240 break;
8241 if(l->name[1]=='w' && what=='w')
8242 break;
8243 }
Eric Andersencb57d552001-06-28 07:25:16 +00008244
8245 set = *argptr ? 1 : 0;
8246 if (set) {
8247 char *p = *argptr;
8248
8249 if (all || argptr[1])
8250 error("too many arguments");
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008251 if (strcmp(p, unlimited_string) == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00008252 val = RLIM_INFINITY;
8253 else {
8254 val = (rlim_t) 0;
8255
8256 while ((c = *p++) >= '0' && c <= '9')
8257 {
8258 val = (val * 10) + (long)(c - '0');
8259 if (val < (rlim_t) 0)
8260 break;
8261 }
8262 if (c)
8263 error("bad number");
8264 val *= l->factor;
8265 }
8266 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008267
Eric Andersencb57d552001-06-28 07:25:16 +00008268 if (all) {
8269 for (l = limits; l->name; l++) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008270 printf("%-20s ", l->name);
Eric Andersencb57d552001-06-28 07:25:16 +00008271 getrlimit(l->cmd, &limit);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008272 OUTPUT_LIMIT:
Eric Andersencb57d552001-06-28 07:25:16 +00008273 if (how & SOFT)
8274 val = limit.rlim_cur;
8275 else if (how & HARD)
8276 val = limit.rlim_max;
8277
Eric Andersencb57d552001-06-28 07:25:16 +00008278 if (val == RLIM_INFINITY)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008279 puts(unlimited_string);
Eric Andersencb57d552001-06-28 07:25:16 +00008280 else
8281 {
8282 val /= l->factor;
Eric Andersen62483552001-07-10 06:09:16 +00008283 printf("%lld\n", (long long) val);
Eric Andersencb57d552001-06-28 07:25:16 +00008284 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008285 if (!all) {
8286 break;
8287 }
Eric Andersencb57d552001-06-28 07:25:16 +00008288 }
8289 return 0;
8290 }
8291
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008292 if (!set) {
8293 goto OUTPUT_LIMIT;
Eric Andersencb57d552001-06-28 07:25:16 +00008294 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008295
8296 getrlimit(l->cmd, &limit);
8297 if (how & HARD)
8298 limit.rlim_max = val;
8299 if (how & SOFT)
8300 limit.rlim_cur = val;
8301 if (setrlimit(l->cmd, &limit) < 0)
8302 error("error setting limit (%m)");
Eric Andersencb57d552001-06-28 07:25:16 +00008303 return 0;
8304}
Eric Andersencb57d552001-06-28 07:25:16 +00008305/*
8306 * prefix -- see if pfx is a prefix of string.
8307 */
8308
8309static int
Eric Andersen62483552001-07-10 06:09:16 +00008310prefix(char const *pfx, char const *string)
8311{
Eric Andersencb57d552001-06-28 07:25:16 +00008312 while (*pfx) {
8313 if (*pfx++ != *string++)
8314 return 0;
8315 }
8316 return 1;
8317}
8318
Eric Andersen2870d962001-07-02 17:27:21 +00008319/*
8320 * Return true if s is a string of digits, and save munber in intptr
8321 * nagative is bad
8322 */
8323
8324static int
8325is_number(const char *p, int *intptr)
8326{
8327 int ret = 0;
8328
8329 do {
8330 if (! is_digit(*p))
8331 return 0;
8332 ret *= 10;
8333 ret += digit_val(*p);
8334 p++;
8335 } while (*p != '\0');
8336
8337 *intptr = ret;
8338 return 1;
8339}
Eric Andersencb57d552001-06-28 07:25:16 +00008340
8341/*
8342 * Convert a string of digits to an integer, printing an error message on
8343 * failure.
8344 */
8345
8346static int
Eric Andersen2870d962001-07-02 17:27:21 +00008347number(const char *s)
8348{
8349 int i;
8350 if (! is_number(s, &i))
Eric Andersencb57d552001-06-28 07:25:16 +00008351 error("Illegal number: %s", s);
Eric Andersen2870d962001-07-02 17:27:21 +00008352 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00008353}
8354
Eric Andersencb57d552001-06-28 07:25:16 +00008355/*
8356 * Produce a possibly single quoted string suitable as input to the shell.
8357 * The return string is allocated on the stack.
8358 */
8359
8360static char *
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008361single_quote(const char *s)
8362{
Eric Andersencb57d552001-06-28 07:25:16 +00008363 char *p;
8364
8365 STARTSTACKSTR(p);
8366
8367 do {
8368 char *q = p;
8369 size_t len1, len1p, len2, len2p;
8370
8371 len1 = strcspn(s, "'");
8372 len2 = strspn(s + len1, "'");
8373
8374 len1p = len1 ? len1 + 2 : len1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008375 len2p = len2 + ((len2 < 2) ? len2 : 2);
Eric Andersencb57d552001-06-28 07:25:16 +00008376
8377 CHECKSTRSPACE(len1p + len2p + 1, p);
8378
8379 if (len1) {
8380 *p = '\'';
Eric Andersencb57d552001-06-28 07:25:16 +00008381 q = p + 1 + len1;
8382 memcpy(p + 1, s, len1);
Eric Andersencb57d552001-06-28 07:25:16 +00008383 *q++ = '\'';
8384 s += len1;
8385 }
8386
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008387 if (len2 > 1) {
Eric Andersencb57d552001-06-28 07:25:16 +00008388 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008389 q += 1 + len2;
8390 memcpy(q + 1, s, len2);
8391 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008392 s += len2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008393 } else if (len2 == 1) {
8394 *q++ = '\\';
8395 *q = '\'';
8396 s++;
Eric Andersencb57d552001-06-28 07:25:16 +00008397 }
8398
8399 STADJUST(len1p + len2p, p);
8400 } while (*s);
8401
8402 USTPUTC(0, p);
8403
8404 return grabstackstr(p);
8405}
8406
8407/*
8408 * Like strdup but works with the ash stack.
8409 */
8410
8411static char *
8412sstrdup(const char *p)
8413{
8414 size_t len = strlen(p) + 1;
8415 return memcpy(stalloc(len), p, len);
8416}
8417
Eric Andersencb57d552001-06-28 07:25:16 +00008418
8419/*
Eric Andersencb57d552001-06-28 07:25:16 +00008420 * Routine for dealing with parsed shell commands.
8421 */
8422
8423
Eric Andersen62483552001-07-10 06:09:16 +00008424static void sizenodelist (const struct nodelist *);
8425static struct nodelist *copynodelist (const struct nodelist *);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008426static char *nodexstrdup (const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00008427
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00008428#define CALCSIZE_TABLE
8429#define COPYNODE_TABLE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008430#if defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE)
8431/*
8432 * To collect a lot of redundant code in case statements for copynode()
8433 * and calcsize(), we implement a mini language here. Each type of node
8434 * struct has an associated instruction sequence that operates on its
8435 * members via their offsets. The instruction are pack in unsigned chars
8436 * with format IIDDDDDE where the bits are
8437 * I : part of the instruction opcode, which are
8438 * 00 : member is a pointer to another node
8439 * 40 : member is an integer
8440 * 80 : member is a pointer to a nodelist
8441 * CC : member is a pointer to a char string
8442 * D : data - the actual offset of the member to operate on in the struct
8443 * (since we assume bit 0 is set, it is not shifted)
8444 * E : flag signaling end of instruction sequence
8445 *
8446 * WARNING: In order to handle larger offsets for 64bit archs, this code
8447 * assumes that no offset can be an odd number and stores the
8448 * end-of-instructions flag in bit 0.
8449 */
8450
8451#define NODE_INTEGER 0x40
8452#define NODE_NODELIST 0x80
8453#define NODE_CHARPTR 0xC0
8454#define NODE_NOMORE 0x01 /* Note: no offset should be odd (aligned)*/
8455#define NODE_MBRMASK 0xC0
8456#define NODE_OFFSETMASK 0x3E
8457
8458static const unsigned char copynode_ops[35] = {
8459#define COPYNODE_OPS0 0
8460 offsetof(union node, nbinary.ch2),
8461 offsetof(union node, nbinary.ch1)|NODE_NOMORE,
8462#define COPYNODE_OPS1 (COPYNODE_OPS0 + 2)
8463 offsetof(union node, ncmd.redirect),
8464 offsetof(union node, ncmd.args),
8465 offsetof(union node, ncmd.assign),
8466 offsetof(union node, ncmd.backgnd)|NODE_INTEGER|NODE_NOMORE,
8467#define COPYNODE_OPS2 (COPYNODE_OPS1 + 4)
8468 offsetof(union node, npipe.cmdlist)|NODE_NODELIST,
8469 offsetof(union node, npipe.backgnd)|NODE_INTEGER|NODE_NOMORE,
8470#define COPYNODE_OPS3 (COPYNODE_OPS2 + 2)
8471 offsetof(union node, nredir.redirect),
8472 offsetof(union node, nredir.n)|NODE_NOMORE,
8473#define COPYNODE_OPS4 (COPYNODE_OPS3 + 2)
8474 offsetof(union node, nif.elsepart),
8475 offsetof(union node, nif.ifpart),
8476 offsetof(union node, nif.test)|NODE_NOMORE,
8477#define COPYNODE_OPS5 (COPYNODE_OPS4 + 3)
8478 offsetof(union node, nfor.var)|NODE_CHARPTR,
8479 offsetof(union node, nfor.body),
8480 offsetof(union node, nfor.args)|NODE_NOMORE,
8481#define COPYNODE_OPS6 (COPYNODE_OPS5 + 3)
8482 offsetof(union node, ncase.cases),
8483 offsetof(union node, ncase.expr)|NODE_NOMORE,
8484#define COPYNODE_OPS7 (COPYNODE_OPS6 + 2)
8485 offsetof(union node, nclist.body),
8486 offsetof(union node, nclist.pattern),
8487 offsetof(union node, nclist.next)|NODE_NOMORE,
8488#define COPYNODE_OPS8 (COPYNODE_OPS7 + 3)
8489 offsetof(union node, narg.backquote)|NODE_NODELIST,
8490 offsetof(union node, narg.text)|NODE_CHARPTR,
8491 offsetof(union node, narg.next)|NODE_NOMORE,
8492#define COPYNODE_OPS9 (COPYNODE_OPS8 + 3)
8493 offsetof(union node, nfile.fname),
8494 offsetof(union node, nfile.fd)|NODE_INTEGER,
8495 offsetof(union node, nfile.next)|NODE_NOMORE,
8496#define COPYNODE_OPS10 (COPYNODE_OPS9 + 3)
8497 offsetof(union node, ndup.vname),
8498 offsetof(union node, ndup.dupfd)|NODE_INTEGER,
8499 offsetof(union node, ndup.fd)|NODE_INTEGER,
8500 offsetof(union node, ndup.next)|NODE_NOMORE,
8501#define COPYNODE_OPS11 (COPYNODE_OPS10 + 4)
8502 offsetof(union node, nhere.doc),
8503 offsetof(union node, nhere.fd)|NODE_INTEGER,
8504 offsetof(union node, nhere.next)|NODE_NOMORE,
8505#define COPYNODE_OPS12 (COPYNODE_OPS11 + 3)
8506 offsetof(union node, nnot.com)|NODE_NOMORE,
8507};
8508
8509#if COPYNODE_OPS12 != 34
8510#error COPYNODE_OPS12 is incorrect
8511#endif
8512
8513static const unsigned char copynode_ops_index[26] = {
8514 COPYNODE_OPS0, /* NSEMI */
8515 COPYNODE_OPS1, /* NCMD */
8516 COPYNODE_OPS2, /* NPIPE */
8517 COPYNODE_OPS3, /* NREDIR */
8518 COPYNODE_OPS3, /* NBACKGND */
8519 COPYNODE_OPS3, /* NSUBSHELL */
8520 COPYNODE_OPS0, /* NAND */
8521 COPYNODE_OPS0, /* NOR */
8522 COPYNODE_OPS4, /* NIF */
8523 COPYNODE_OPS0, /* NWHILE */
8524 COPYNODE_OPS0, /* NUNTIL */
8525 COPYNODE_OPS5, /* NFOR */
8526 COPYNODE_OPS6, /* NCASE */
8527 COPYNODE_OPS7, /* NCLIST */
8528 COPYNODE_OPS8, /* NDEFUN */
8529 COPYNODE_OPS8, /* NARG */
8530 COPYNODE_OPS9, /* NTO */
8531 COPYNODE_OPS9, /* NFROM */
8532 COPYNODE_OPS9, /* NFROMTO */
8533 COPYNODE_OPS9, /* NAPPEND */
8534 COPYNODE_OPS9, /* NTOOV */
8535 COPYNODE_OPS10, /* NTOFD */
8536 COPYNODE_OPS10, /* NFROMFD */
8537 COPYNODE_OPS11, /* NHERE */
8538 COPYNODE_OPS11, /* NXHERE */
8539 COPYNODE_OPS12, /* NNOT */
8540};
8541
8542#if NODE_CHARPTR != NODE_MBRMASK
8543#error NODE_CHARPTR != NODE_MBRMASK!!!
8544#endif
8545#endif /* defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE) */
8546
8547#ifdef COPYNODE_TABLE
8548static union node *
8549copynode(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008550{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008551 union node *new;
8552 const unsigned char *p;
8553
Manuel Novoa III c639a352001-08-12 17:32:56 +00008554 if (n == NULL) {
8555 return NULL;
8556 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008557 new = funcblock;
8558 new->type = n->type;
8559 funcblock = (char *) funcblock + (int) nodesize[n->type];
8560 p = copynode_ops + (int) copynode_ops_index[n->type];
8561 do {
8562 char *nn = ((char *) new) + ((int)(*p & NODE_OFFSETMASK));
8563 const char *no = ((const char *) n) + ((int)(*p & NODE_OFFSETMASK));
8564
8565 if (!(*p & NODE_MBRMASK)) { /* standard node */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008566 *((union node **)nn) = copynode(*((const union node **) no));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008567 } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008568 *((const char **)nn) = nodexstrdup(*((const char **)no));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008569 } else if (*p & NODE_NODELIST) { /* nodelist */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008570 *((struct nodelist **)nn)
8571 = copynodelist(*((const struct nodelist **) no));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008572 } else { /* integer */
8573 *((int *) nn) = *((int *) no);
8574 }
8575 } while (!(*p++ & NODE_NOMORE));
8576 return new;
Eric Andersencb57d552001-06-28 07:25:16 +00008577}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008578#else /* COPYNODE_TABLE */
Eric Andersencb57d552001-06-28 07:25:16 +00008579static union node *
Eric Andersen62483552001-07-10 06:09:16 +00008580copynode(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008581{
Eric Andersen62483552001-07-10 06:09:16 +00008582 union node *new;
Eric Andersencb57d552001-06-28 07:25:16 +00008583
8584 if (n == NULL)
Manuel Novoa III c639a352001-08-12 17:32:56 +00008585 return NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008586 new = funcblock;
8587 funcblock = (char *) funcblock + nodesize[n->type];
8588 switch (n->type) {
8589 case NSEMI:
8590 case NAND:
8591 case NOR:
8592 case NWHILE:
8593 case NUNTIL:
8594 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8595 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8596 break;
8597 case NCMD:
8598 new->ncmd.redirect = copynode(n->ncmd.redirect);
8599 new->ncmd.args = copynode(n->ncmd.args);
8600 new->ncmd.assign = copynode(n->ncmd.assign);
8601 new->ncmd.backgnd = n->ncmd.backgnd;
8602 break;
8603 case NPIPE:
8604 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8605 new->npipe.backgnd = n->npipe.backgnd;
8606 break;
8607 case NREDIR:
8608 case NBACKGND:
8609 case NSUBSHELL:
8610 new->nredir.redirect = copynode(n->nredir.redirect);
8611 new->nredir.n = copynode(n->nredir.n);
8612 break;
8613 case NIF:
8614 new->nif.elsepart = copynode(n->nif.elsepart);
8615 new->nif.ifpart = copynode(n->nif.ifpart);
8616 new->nif.test = copynode(n->nif.test);
8617 break;
8618 case NFOR:
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008619 new->nfor.var = nodexstrdup(n->nfor.var);
Eric Andersencb57d552001-06-28 07:25:16 +00008620 new->nfor.body = copynode(n->nfor.body);
8621 new->nfor.args = copynode(n->nfor.args);
8622 break;
8623 case NCASE:
8624 new->ncase.cases = copynode(n->ncase.cases);
8625 new->ncase.expr = copynode(n->ncase.expr);
8626 break;
8627 case NCLIST:
8628 new->nclist.body = copynode(n->nclist.body);
8629 new->nclist.pattern = copynode(n->nclist.pattern);
8630 new->nclist.next = copynode(n->nclist.next);
8631 break;
8632 case NDEFUN:
8633 case NARG:
8634 new->narg.backquote = copynodelist(n->narg.backquote);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008635 new->narg.text = nodexstrdup(n->narg.text);
Eric Andersencb57d552001-06-28 07:25:16 +00008636 new->narg.next = copynode(n->narg.next);
8637 break;
8638 case NTO:
8639 case NFROM:
8640 case NFROMTO:
8641 case NAPPEND:
8642 case NTOOV:
8643 new->nfile.fname = copynode(n->nfile.fname);
8644 new->nfile.fd = n->nfile.fd;
8645 new->nfile.next = copynode(n->nfile.next);
8646 break;
8647 case NTOFD:
8648 case NFROMFD:
8649 new->ndup.vname = copynode(n->ndup.vname);
8650 new->ndup.dupfd = n->ndup.dupfd;
8651 new->ndup.fd = n->ndup.fd;
8652 new->ndup.next = copynode(n->ndup.next);
8653 break;
8654 case NHERE:
8655 case NXHERE:
8656 new->nhere.doc = copynode(n->nhere.doc);
8657 new->nhere.fd = n->nhere.fd;
8658 new->nhere.next = copynode(n->nhere.next);
8659 break;
8660 case NNOT:
8661 new->nnot.com = copynode(n->nnot.com);
8662 break;
8663 };
8664 new->type = n->type;
Eric Andersen62483552001-07-10 06:09:16 +00008665 return new;
Eric Andersencb57d552001-06-28 07:25:16 +00008666}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008667#endif /* COPYNODE_TABLE */
8668
8669#ifdef CALCSIZE_TABLE
8670static void
8671calcsize(const union node *n)
8672{
8673 const unsigned char *p;
8674
8675 if (n == NULL)
8676 return;
8677 funcblocksize += (int) nodesize[n->type];
8678
8679 p = copynode_ops + (int) copynode_ops_index[n->type];
8680 do {
8681 const char *no = ((const char *) n) + ((int)(*p & NODE_OFFSETMASK));
8682
8683 if (!(*p & NODE_MBRMASK)) { /* standard node */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008684 calcsize(*((const union node **) no));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008685 } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008686 funcstringsize += strlen(*((const char **)no)) + 1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008687 } else if (*p & NODE_NODELIST) { /* nodelist */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008688 sizenodelist(*((const struct nodelist **) no));
8689 } /* else integer -- ignore */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008690 } while (!(*p++ & NODE_NOMORE));
8691}
8692#else /* CALCSIZE_TABLE */
8693static void
8694calcsize(const union node *n)
8695{
8696 if (n == NULL)
8697 return;
8698 funcblocksize += nodesize[n->type];
8699 switch (n->type) {
8700 case NSEMI:
8701 case NAND:
8702 case NOR:
8703 case NWHILE:
8704 case NUNTIL:
8705 calcsize(n->nbinary.ch2);
8706 calcsize(n->nbinary.ch1);
8707 break;
8708 case NCMD:
8709 calcsize(n->ncmd.redirect);
8710 calcsize(n->ncmd.args);
8711 calcsize(n->ncmd.assign);
8712 break;
8713 case NPIPE:
8714 sizenodelist(n->npipe.cmdlist);
8715 break;
8716 case NREDIR:
8717 case NBACKGND:
8718 case NSUBSHELL:
8719 calcsize(n->nredir.redirect);
8720 calcsize(n->nredir.n);
8721 break;
8722 case NIF:
8723 calcsize(n->nif.elsepart);
8724 calcsize(n->nif.ifpart);
8725 calcsize(n->nif.test);
8726 break;
8727 case NFOR:
8728 funcstringsize += strlen(n->nfor.var) + 1;
8729 calcsize(n->nfor.body);
8730 calcsize(n->nfor.args);
8731 break;
8732 case NCASE:
8733 calcsize(n->ncase.cases);
8734 calcsize(n->ncase.expr);
8735 break;
8736 case NCLIST:
8737 calcsize(n->nclist.body);
8738 calcsize(n->nclist.pattern);
8739 calcsize(n->nclist.next);
8740 break;
8741 case NDEFUN:
8742 case NARG:
8743 sizenodelist(n->narg.backquote);
8744 funcstringsize += strlen(n->narg.text) + 1;
8745 calcsize(n->narg.next);
8746 break;
8747 case NTO:
8748 case NFROM:
8749 case NFROMTO:
8750 case NAPPEND:
8751 case NTOOV:
8752 calcsize(n->nfile.fname);
8753 calcsize(n->nfile.next);
8754 break;
8755 case NTOFD:
8756 case NFROMFD:
8757 calcsize(n->ndup.vname);
8758 calcsize(n->ndup.next);
8759 break;
8760 case NHERE:
8761 case NXHERE:
8762 calcsize(n->nhere.doc);
8763 calcsize(n->nhere.next);
8764 break;
8765 case NNOT:
8766 calcsize(n->nnot.com);
8767 break;
8768 };
8769}
8770#endif /* CALCSIZE_TABLE */
8771
8772static void
8773sizenodelist(const struct nodelist *lp)
8774{
8775 while (lp) {
8776 funcblocksize += ALIGN(sizeof(struct nodelist));
8777 calcsize(lp->n);
8778 lp = lp->next;
8779 }
8780}
Eric Andersencb57d552001-06-28 07:25:16 +00008781
8782
8783static struct nodelist *
Eric Andersen62483552001-07-10 06:09:16 +00008784copynodelist(const struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008785{
8786 struct nodelist *start;
8787 struct nodelist **lpp;
8788
8789 lpp = &start;
8790 while (lp) {
8791 *lpp = funcblock;
8792 funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist));
8793 (*lpp)->n = copynode(lp->n);
8794 lp = lp->next;
8795 lpp = &(*lpp)->next;
8796 }
8797 *lpp = NULL;
8798 return start;
8799}
8800
8801
Eric Andersencb57d552001-06-28 07:25:16 +00008802static char *
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008803nodexstrdup(const char *s)
Eric Andersencb57d552001-06-28 07:25:16 +00008804{
Eric Andersen62483552001-07-10 06:09:16 +00008805 const char *p = s;
8806 char *q = funcstring;
Eric Andersencb57d552001-06-28 07:25:16 +00008807 char *rtn = funcstring;
8808
8809 while ((*q++ = *p++) != '\0')
8810 continue;
8811 funcstring = q;
8812 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00008813}
8814
Eric Andersend35c5df2002-01-09 15:37:36 +00008815#ifdef CONFIG_ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00008816static int getopts (char *, char *, char **, int *, int *);
Eric Andersencb57d552001-06-28 07:25:16 +00008817#endif
8818
Eric Andersencb57d552001-06-28 07:25:16 +00008819/*
8820 * Process the shell command line arguments.
8821 */
8822
8823static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008824procargs(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008825{
8826 int i;
8827
8828 argptr = argv;
8829 if (argc > 0)
8830 argptr++;
8831 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00008832 optent_val(i) = 2;
Eric Andersencb57d552001-06-28 07:25:16 +00008833 options(1);
8834 if (*argptr == NULL && minusc == NULL)
8835 sflag = 1;
8836 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8837 iflag = 1;
8838 if (mflag == 2)
8839 mflag = iflag;
8840 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00008841 if (optent_val(i) == 2)
8842 optent_val(i) = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008843 arg0 = argv[0];
8844 if (sflag == 0 && minusc == NULL) {
8845 commandname = argv[0];
8846 arg0 = *argptr++;
8847 setinputfile(arg0, 0);
8848 commandname = arg0;
8849 }
8850 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8851 if (argptr && minusc && *argptr)
Eric Andersen2870d962001-07-02 17:27:21 +00008852 arg0 = *argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00008853
8854 shellparam.p = argptr;
8855 shellparam.optind = 1;
8856 shellparam.optoff = -1;
8857 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8858 while (*argptr) {
8859 shellparam.nparam++;
8860 argptr++;
8861 }
8862 optschanged();
8863}
8864
8865
Eric Andersencb57d552001-06-28 07:25:16 +00008866
8867/*
8868 * Process shell options. The global variable argptr contains a pointer
8869 * to the argument list; we advance it past the options.
8870 */
8871
Eric Andersen62483552001-07-10 06:09:16 +00008872static inline void
8873minus_o(const char *name, int val)
8874{
8875 int i;
8876
8877 if (name == NULL) {
8878 out1str("Current option settings\n");
8879 for (i = 0; i < NOPTS; i++)
8880 printf("%-16s%s\n", optent_name(optlist[i]),
8881 optent_val(i) ? "on" : "off");
8882 } else {
8883 for (i = 0; i < NOPTS; i++)
8884 if (equal(name, optent_name(optlist[i]))) {
8885 setoption(optent_letter(optlist[i]), val);
8886 return;
8887 }
8888 error("Illegal option -o %s", name);
8889 }
8890}
8891
8892
Eric Andersencb57d552001-06-28 07:25:16 +00008893static void
Eric Andersen62483552001-07-10 06:09:16 +00008894options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00008895{
8896 char *p;
8897 int val;
8898 int c;
8899
8900 if (cmdline)
8901 minusc = NULL;
8902 while ((p = *argptr) != NULL) {
8903 argptr++;
8904 if ((c = *p++) == '-') {
8905 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00008906 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8907 if (!cmdline) {
8908 /* "-" means turn off -x and -v */
8909 if (p[0] == '\0')
8910 xflag = vflag = 0;
8911 /* "--" means reset params */
8912 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00008913 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00008914 }
8915 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00008916 }
8917 } else if (c == '+') {
8918 val = 0;
8919 } else {
8920 argptr--;
8921 break;
8922 }
8923 while ((c = *p++) != '\0') {
8924 if (c == 'c' && cmdline) {
8925 char *q;
Eric Andersen2870d962001-07-02 17:27:21 +00008926#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */
Eric Andersencb57d552001-06-28 07:25:16 +00008927 if (*p == '\0')
8928#endif
8929 q = *argptr++;
8930 if (q == NULL || minusc != NULL)
8931 error("Bad -c option");
8932 minusc = q;
8933#ifdef NOHACK
8934 break;
8935#endif
8936 } else if (c == 'o') {
8937 minus_o(*argptr, val);
8938 if (*argptr)
8939 argptr++;
Robert Griebl64f70cc2002-05-14 23:22:06 +00008940 } else if (cmdline && (c == '-')) { // long options
8941 if ( strcmp ( p, "login" ) == 0 )
8942 isloginsh = 1;
8943 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008944 } else {
8945 setoption(c, val);
8946 }
8947 }
8948 }
8949}
8950
Eric Andersencb57d552001-06-28 07:25:16 +00008951
8952static void
Eric Andersen2870d962001-07-02 17:27:21 +00008953setoption(int flag, int val)
8954{
Eric Andersencb57d552001-06-28 07:25:16 +00008955 int i;
8956
8957 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00008958 if (optent_letter(optlist[i]) == flag) {
8959 optent_val(i) = val;
Eric Andersencb57d552001-06-28 07:25:16 +00008960 if (val) {
8961 /* #%$ hack for ksh semantics */
8962 if (flag == 'V')
8963 Eflag = 0;
8964 else if (flag == 'E')
8965 Vflag = 0;
8966 }
8967 return;
8968 }
8969 error("Illegal option -%c", flag);
8970 /* NOTREACHED */
8971}
8972
8973
8974
Eric Andersencb57d552001-06-28 07:25:16 +00008975/*
8976 * Set the shell parameters.
8977 */
8978
8979static void
Eric Andersen2870d962001-07-02 17:27:21 +00008980setparam(char **argv)
8981{
Eric Andersencb57d552001-06-28 07:25:16 +00008982 char **newparam;
8983 char **ap;
8984 int nparam;
8985
8986 for (nparam = 0 ; argv[nparam] ; nparam++);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008987 ap = newparam = xmalloc((nparam + 1) * sizeof *ap);
Eric Andersencb57d552001-06-28 07:25:16 +00008988 while (*argv) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008989 *ap++ = xstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +00008990 }
8991 *ap = NULL;
8992 freeparam(&shellparam);
8993 shellparam.malloc = 1;
8994 shellparam.nparam = nparam;
8995 shellparam.p = newparam;
8996 shellparam.optind = 1;
8997 shellparam.optoff = -1;
8998}
8999
9000
9001/*
9002 * Free the list of positional parameters.
9003 */
9004
9005static void
Eric Andersen2870d962001-07-02 17:27:21 +00009006freeparam(volatile struct shparam *param)
9007{
Eric Andersencb57d552001-06-28 07:25:16 +00009008 char **ap;
9009
9010 if (param->malloc) {
9011 for (ap = param->p ; *ap ; ap++)
Aaron Lehmann49c024a2002-08-02 06:39:47 +00009012 free(*ap);
9013 free(param->p);
Eric Andersencb57d552001-06-28 07:25:16 +00009014 }
9015}
9016
9017
9018
9019/*
9020 * The shift builtin command.
9021 */
9022
9023static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00009024shiftcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009025{
9026 int n;
9027 char **ap1, **ap2;
9028
9029 n = 1;
9030 if (argc > 1)
9031 n = number(argv[1]);
9032 if (n > shellparam.nparam)
9033 error("can't shift that many");
9034 INTOFF;
9035 shellparam.nparam -= n;
9036 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
9037 if (shellparam.malloc)
Aaron Lehmann49c024a2002-08-02 06:39:47 +00009038 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +00009039 }
9040 ap2 = shellparam.p;
9041 while ((*ap2++ = *ap1++) != NULL);
9042 shellparam.optind = 1;
9043 shellparam.optoff = -1;
9044 INTON;
9045 return 0;
9046}
9047
9048
9049
9050/*
9051 * The set command builtin.
9052 */
9053
9054static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00009055setcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009056{
9057 if (argc == 1)
9058 return showvarscmd(argc, argv);
9059 INTOFF;
9060 options(0);
9061 optschanged();
9062 if (*argptr != NULL) {
9063 setparam(argptr);
9064 }
9065 INTON;
9066 return 0;
9067}
9068
9069
9070static void
Eric Andersen2870d962001-07-02 17:27:21 +00009071getoptsreset(const char *value)
Eric Andersencb57d552001-06-28 07:25:16 +00009072{
9073 shellparam.optind = number(value);
9074 shellparam.optoff = -1;
9075}
9076
Eric Andersenbdfd0d72001-10-24 05:00:29 +00009077#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00009078static void change_lc_all(const char *value)
9079{
9080 if(value != 0 && *value != 0)
9081 setlocale(LC_ALL, value);
9082}
9083
9084static void change_lc_ctype(const char *value)
9085{
9086 if(value != 0 && *value != 0)
9087 setlocale(LC_CTYPE, value);
9088}
9089
9090#endif
9091
Eric Andersend35c5df2002-01-09 15:37:36 +00009092#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00009093/*
9094 * The getopts builtin. Shellparam.optnext points to the next argument
9095 * to be processed. Shellparam.optptr points to the next character to
9096 * be processed in the current argument. If shellparam.optnext is NULL,
9097 * then it's the first time getopts has been called.
9098 */
9099
9100static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00009101getoptscmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009102{
9103 char **optbase;
9104
9105 if (argc < 3)
9106 error("Usage: getopts optstring var [arg]");
9107 else if (argc == 3) {
9108 optbase = shellparam.p;
9109 if (shellparam.optind > shellparam.nparam + 1) {
9110 shellparam.optind = 1;
9111 shellparam.optoff = -1;
9112 }
9113 }
9114 else {
9115 optbase = &argv[3];
9116 if (shellparam.optind > argc - 2) {
9117 shellparam.optind = 1;
9118 shellparam.optoff = -1;
9119 }
9120 }
9121
9122 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9123 &shellparam.optoff);
9124}
9125
9126/*
9127 * Safe version of setvar, returns 1 on success 0 on failure.
9128 */
9129
9130static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00009131setvarsafe(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009132{
9133 struct jmploc jmploc;
9134 struct jmploc *volatile savehandler = handler;
9135 int err = 0;
9136#ifdef __GNUC__
9137 (void) &err;
9138#endif
9139
9140 if (setjmp(jmploc.loc))
9141 err = 1;
9142 else {
9143 handler = &jmploc;
9144 setvar(name, val, flags);
9145 }
9146 handler = savehandler;
9147 return err;
9148}
9149
9150static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00009151getopts(char *optstr, char *optvar, char **optfirst, int *myoptind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009152{
9153 char *p, *q;
9154 char c = '?';
9155 int done = 0;
9156 int err = 0;
9157 char s[10];
9158 char **optnext = optfirst + *myoptind - 1;
9159
9160 if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
9161 strlen(*(optnext - 1)) < *optoff)
9162 p = NULL;
9163 else
9164 p = *(optnext - 1) + *optoff;
9165 if (p == NULL || *p == '\0') {
9166 /* Current word is done, advance */
9167 if (optnext == NULL)
9168 return 1;
9169 p = *optnext;
9170 if (p == NULL || *p != '-' || *++p == '\0') {
9171atend:
9172 *myoptind = optnext - optfirst + 1;
9173 p = NULL;
9174 done = 1;
9175 goto out;
9176 }
9177 optnext++;
Eric Andersen2870d962001-07-02 17:27:21 +00009178 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009179 goto atend;
9180 }
9181
9182 c = *p++;
9183 for (q = optstr; *q != c; ) {
9184 if (*q == '\0') {
9185 if (optstr[0] == ':') {
9186 s[0] = c;
9187 s[1] = '\0';
9188 err |= setvarsafe("OPTARG", s, 0);
9189 }
9190 else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009191 out2fmt("Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009192 (void) unsetvar("OPTARG");
9193 }
9194 c = '?';
9195 goto bad;
9196 }
9197 if (*++q == ':')
9198 q++;
9199 }
9200
9201 if (*++q == ':') {
9202 if (*p == '\0' && (p = *optnext) == NULL) {
9203 if (optstr[0] == ':') {
9204 s[0] = c;
9205 s[1] = '\0';
9206 err |= setvarsafe("OPTARG", s, 0);
9207 c = ':';
9208 }
9209 else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009210 out2fmt("No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009211 (void) unsetvar("OPTARG");
9212 c = '?';
9213 }
9214 goto bad;
9215 }
9216
9217 if (p == *optnext)
9218 optnext++;
9219 setvarsafe("OPTARG", p, 0);
9220 p = NULL;
9221 }
9222 else
9223 setvarsafe("OPTARG", "", 0);
9224 *myoptind = optnext - optfirst + 1;
9225 goto out;
9226
9227bad:
9228 *myoptind = 1;
9229 p = NULL;
9230out:
9231 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersen3102ac42001-07-06 04:26:23 +00009232 snprintf(s, sizeof(s), "%d", *myoptind);
Eric Andersencb57d552001-06-28 07:25:16 +00009233 err |= setvarsafe("OPTIND", s, VNOFUNC);
9234 s[0] = c;
9235 s[1] = '\0';
9236 err |= setvarsafe(optvar, s, 0);
9237 if (err) {
9238 *myoptind = 1;
9239 *optoff = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00009240 exraise(EXERROR);
9241 }
9242 return done;
9243}
Eric Andersen2870d962001-07-02 17:27:21 +00009244#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009245
9246/*
9247 * XXX - should get rid of. have all builtins use getopt(3). the
9248 * library getopt must have the BSD extension static variable "optreset"
9249 * otherwise it can't be used within the shell safely.
9250 *
9251 * Standard option processing (a la getopt) for builtin routines. The
9252 * only argument that is passed to nextopt is the option string; the
9253 * other arguments are unnecessary. It return the character, or '\0' on
9254 * end of input.
9255 */
9256
9257static int
Eric Andersen62483552001-07-10 06:09:16 +00009258nextopt(const char *optstring)
9259{
Eric Andersencb57d552001-06-28 07:25:16 +00009260 char *p;
9261 const char *q;
9262 char c;
9263
9264 if ((p = optptr) == NULL || *p == '\0') {
9265 p = *argptr;
9266 if (p == NULL || *p != '-' || *++p == '\0')
9267 return '\0';
9268 argptr++;
Eric Andersen2870d962001-07-02 17:27:21 +00009269 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009270 return '\0';
9271 }
9272 c = *p++;
9273 for (q = optstring ; *q != c ; ) {
9274 if (*q == '\0')
9275 error("Illegal option -%c", c);
9276 if (*++q == ':')
9277 q++;
9278 }
9279 if (*++q == ':') {
9280 if (*p == '\0' && (p = *argptr++) == NULL)
9281 error("No arg for -%c option", c);
9282 optionarg = p;
9283 p = NULL;
9284 }
9285 optptr = p;
9286 return c;
9287}
9288
Eric Andersencb57d552001-06-28 07:25:16 +00009289static void
9290flushall() {
Eric Andersencb57d552001-06-28 07:25:16 +00009291 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009292 fflush(stdout);
Eric Andersencb57d552001-06-28 07:25:16 +00009293 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009294}
9295
9296
9297static void
Eric Andersen3102ac42001-07-06 04:26:23 +00009298out2fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009299{
9300 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00009301 va_start(ap, fmt);
Eric Andersen3102ac42001-07-06 04:26:23 +00009302 vfprintf(stderr, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009303 va_end(ap);
9304}
9305
Eric Andersencb57d552001-06-28 07:25:16 +00009306/*
9307 * Version of write which resumes after a signal is caught.
9308 */
9309
9310static int
Eric Andersen2870d962001-07-02 17:27:21 +00009311xwrite(int fd, const char *buf, int nbytes)
9312{
Eric Andersencb57d552001-06-28 07:25:16 +00009313 int ntry;
9314 int i;
9315 int n;
9316
9317 n = nbytes;
9318 ntry = 0;
9319 for (;;) {
9320 i = write(fd, buf, n);
9321 if (i > 0) {
9322 if ((n -= i) <= 0)
9323 return nbytes;
9324 buf += i;
9325 ntry = 0;
9326 } else if (i == 0) {
9327 if (++ntry > 10)
9328 return nbytes - n;
9329 } else if (errno != EINTR) {
9330 return -1;
9331 }
9332 }
9333}
9334
9335
Eric Andersencb57d552001-06-28 07:25:16 +00009336/*
9337 * Shell command parser.
9338 */
9339
9340#define EOFMARKLEN 79
9341
9342
9343
9344struct heredoc {
Eric Andersen2870d962001-07-02 17:27:21 +00009345 struct heredoc *next; /* next here document in list */
9346 union node *here; /* redirection node */
9347 char *eofmark; /* string indicating end of input */
9348 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009349};
9350
Eric Andersen2870d962001-07-02 17:27:21 +00009351static struct heredoc *heredoclist; /* list of here documents to read */
9352static int parsebackquote; /* nonzero if we are inside backquotes */
9353static int doprompt; /* if set, prompt the user */
9354static int needprompt; /* true if interactive and at start of line */
9355static int lasttoken; /* last token read */
Eric Andersencb57d552001-06-28 07:25:16 +00009356
Eric Andersen2870d962001-07-02 17:27:21 +00009357static char *wordtext; /* text of last word returned by readtoken */
Eric Andersencb57d552001-06-28 07:25:16 +00009358
Eric Andersen2870d962001-07-02 17:27:21 +00009359static struct nodelist *backquotelist;
9360static union node *redirnode;
Eric Andersen044228d2001-07-17 01:12:36 +00009361static struct heredoc *heredoc;
Eric Andersen2870d962001-07-02 17:27:21 +00009362static int quoteflag; /* set if (part of) last token was quoted */
9363static int startlinno; /* line # where last token started */
Eric Andersencb57d552001-06-28 07:25:16 +00009364
9365
Eric Andersen2870d962001-07-02 17:27:21 +00009366static union node *list (int);
9367static union node *andor (void);
9368static union node *pipeline (void);
9369static union node *command (void);
Eric Andersena3483db2001-10-24 08:01:06 +00009370static union node *simplecmd(union node **rpp, union node *redir);
Eric Andersen2870d962001-07-02 17:27:21 +00009371static void parsefname (void);
9372static void parseheredoc (void);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009373static char peektoken (void);
Eric Andersen2870d962001-07-02 17:27:21 +00009374static int readtoken (void);
9375static int xxreadtoken (void);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009376static int readtoken1 (int, int, const char *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00009377static int noexpand (char *);
9378static void synexpect (int) __attribute__((noreturn));
9379static void synerror (const char *) __attribute__((noreturn));
9380static void setprompt (int);
Eric Andersencb57d552001-06-28 07:25:16 +00009381
9382
9383/*
9384 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9385 * valid parse tree indicating a blank line.)
9386 */
9387
Eric Andersen2870d962001-07-02 17:27:21 +00009388static union node *
Eric Andersencb57d552001-06-28 07:25:16 +00009389parsecmd(int interact)
9390{
9391 int t;
9392
9393 tokpushback = 0;
9394 doprompt = interact;
9395 if (doprompt)
9396 setprompt(1);
9397 else
9398 setprompt(0);
9399 needprompt = 0;
9400 t = readtoken();
9401 if (t == TEOF)
9402 return NEOF;
9403 if (t == TNL)
9404 return NULL;
9405 tokpushback++;
9406 return list(1);
9407}
9408
9409
9410static union node *
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00009411list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +00009412{
9413 union node *n1, *n2, *n3;
9414 int tok;
9415
9416 checkkwd = 2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009417 if (nlflag == 0 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009418 return NULL;
9419 n1 = NULL;
9420 for (;;) {
9421 n2 = andor();
9422 tok = readtoken();
9423 if (tok == TBACKGND) {
9424 if (n2->type == NCMD || n2->type == NPIPE) {
9425 n2->ncmd.backgnd = 1;
9426 } else if (n2->type == NREDIR) {
9427 n2->type = NBACKGND;
9428 } else {
9429 n3 = (union node *)stalloc(sizeof (struct nredir));
9430 n3->type = NBACKGND;
9431 n3->nredir.n = n2;
9432 n3->nredir.redirect = NULL;
9433 n2 = n3;
9434 }
9435 }
9436 if (n1 == NULL) {
9437 n1 = n2;
9438 }
9439 else {
9440 n3 = (union node *)stalloc(sizeof (struct nbinary));
9441 n3->type = NSEMI;
9442 n3->nbinary.ch1 = n1;
9443 n3->nbinary.ch2 = n2;
9444 n1 = n3;
9445 }
9446 switch (tok) {
9447 case TBACKGND:
9448 case TSEMI:
9449 tok = readtoken();
9450 /* fall through */
9451 case TNL:
9452 if (tok == TNL) {
9453 parseheredoc();
9454 if (nlflag)
9455 return n1;
9456 } else {
9457 tokpushback++;
9458 }
9459 checkkwd = 2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009460 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009461 return n1;
9462 break;
9463 case TEOF:
9464 if (heredoclist)
9465 parseheredoc();
9466 else
Eric Andersen2870d962001-07-02 17:27:21 +00009467 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009468 return n1;
9469 default:
9470 if (nlflag)
9471 synexpect(-1);
9472 tokpushback++;
9473 return n1;
9474 }
9475 }
9476}
9477
9478
9479
9480static union node *
9481andor() {
9482 union node *n1, *n2, *n3;
9483 int t;
9484
9485 checkkwd = 1;
9486 n1 = pipeline();
9487 for (;;) {
9488 if ((t = readtoken()) == TAND) {
9489 t = NAND;
9490 } else if (t == TOR) {
9491 t = NOR;
9492 } else {
9493 tokpushback++;
9494 return n1;
9495 }
9496 checkkwd = 2;
9497 n2 = pipeline();
9498 n3 = (union node *)stalloc(sizeof (struct nbinary));
9499 n3->type = t;
9500 n3->nbinary.ch1 = n1;
9501 n3->nbinary.ch2 = n2;
9502 n1 = n3;
9503 }
9504}
9505
9506
9507
9508static union node *
9509pipeline() {
9510 union node *n1, *n2, *pipenode;
9511 struct nodelist *lp, *prev;
9512 int negate;
9513
9514 negate = 0;
9515 TRACE(("pipeline: entered\n"));
9516 if (readtoken() == TNOT) {
9517 negate = !negate;
9518 checkkwd = 1;
9519 } else
9520 tokpushback++;
9521 n1 = command();
9522 if (readtoken() == TPIPE) {
9523 pipenode = (union node *)stalloc(sizeof (struct npipe));
9524 pipenode->type = NPIPE;
9525 pipenode->npipe.backgnd = 0;
9526 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9527 pipenode->npipe.cmdlist = lp;
9528 lp->n = n1;
9529 do {
9530 prev = lp;
9531 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9532 checkkwd = 2;
9533 lp->n = command();
9534 prev->next = lp;
9535 } while (readtoken() == TPIPE);
9536 lp->next = NULL;
9537 n1 = pipenode;
9538 }
9539 tokpushback++;
9540 if (negate) {
9541 n2 = (union node *)stalloc(sizeof (struct nnot));
9542 n2->type = NNOT;
9543 n2->nnot.com = n1;
9544 return n2;
9545 } else
9546 return n1;
9547}
9548
9549
9550
9551static union node *
Eric Andersena3483db2001-10-24 08:01:06 +00009552command(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009553 union node *n1, *n2;
9554 union node *ap, **app;
9555 union node *cp, **cpp;
9556 union node *redir, **rpp;
9557 int t;
9558
9559 redir = NULL;
9560 n1 = NULL;
9561 rpp = &redir;
9562
Eric Andersen88cec252001-09-06 17:35:20 +00009563 /* Check for redirection which may precede command */
9564 while (readtoken() == TREDIR) {
9565 *rpp = n2 = redirnode;
9566 rpp = &n2->nfile.next;
9567 parsefname();
9568 }
9569 tokpushback++;
9570
Eric Andersencb57d552001-06-28 07:25:16 +00009571 switch (readtoken()) {
9572 case TIF:
9573 n1 = (union node *)stalloc(sizeof (struct nif));
9574 n1->type = NIF;
9575 n1->nif.test = list(0);
9576 if (readtoken() != TTHEN)
9577 synexpect(TTHEN);
9578 n1->nif.ifpart = list(0);
9579 n2 = n1;
9580 while (readtoken() == TELIF) {
9581 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9582 n2 = n2->nif.elsepart;
9583 n2->type = NIF;
9584 n2->nif.test = list(0);
9585 if (readtoken() != TTHEN)
9586 synexpect(TTHEN);
9587 n2->nif.ifpart = list(0);
9588 }
9589 if (lasttoken == TELSE)
9590 n2->nif.elsepart = list(0);
9591 else {
9592 n2->nif.elsepart = NULL;
9593 tokpushback++;
9594 }
9595 if (readtoken() != TFI)
9596 synexpect(TFI);
9597 checkkwd = 1;
9598 break;
9599 case TWHILE:
9600 case TUNTIL: {
9601 int got;
9602 n1 = (union node *)stalloc(sizeof (struct nbinary));
9603 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9604 n1->nbinary.ch1 = list(0);
9605 if ((got=readtoken()) != TDO) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009606TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009607 synexpect(TDO);
9608 }
9609 n1->nbinary.ch2 = list(0);
9610 if (readtoken() != TDONE)
9611 synexpect(TDONE);
9612 checkkwd = 1;
9613 break;
9614 }
9615 case TFOR:
9616 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9617 synerror("Bad for loop variable");
9618 n1 = (union node *)stalloc(sizeof (struct nfor));
9619 n1->type = NFOR;
9620 n1->nfor.var = wordtext;
9621 checkkwd = 1;
9622 if (readtoken() == TIN) {
9623 app = &ap;
9624 while (readtoken() == TWORD) {
9625 n2 = (union node *)stalloc(sizeof (struct narg));
9626 n2->type = NARG;
9627 n2->narg.text = wordtext;
9628 n2->narg.backquote = backquotelist;
9629 *app = n2;
9630 app = &n2->narg.next;
9631 }
9632 *app = NULL;
9633 n1->nfor.args = ap;
9634 if (lasttoken != TNL && lasttoken != TSEMI)
9635 synexpect(-1);
9636 } else {
9637 static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
9638 '@', '=', '\0'};
9639 n2 = (union node *)stalloc(sizeof (struct narg));
9640 n2->type = NARG;
9641 n2->narg.text = argvars;
9642 n2->narg.backquote = NULL;
9643 n2->narg.next = NULL;
9644 n1->nfor.args = n2;
9645 /*
9646 * Newline or semicolon here is optional (but note
9647 * that the original Bourne shell only allowed NL).
9648 */
9649 if (lasttoken != TNL && lasttoken != TSEMI)
9650 tokpushback++;
9651 }
9652 checkkwd = 2;
9653 if (readtoken() != TDO)
9654 synexpect(TDO);
9655 n1->nfor.body = list(0);
9656 if (readtoken() != TDONE)
9657 synexpect(TDONE);
9658 checkkwd = 1;
9659 break;
9660 case TCASE:
9661 n1 = (union node *)stalloc(sizeof (struct ncase));
9662 n1->type = NCASE;
9663 if (readtoken() != TWORD)
9664 synexpect(TWORD);
9665 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9666 n2->type = NARG;
9667 n2->narg.text = wordtext;
9668 n2->narg.backquote = backquotelist;
9669 n2->narg.next = NULL;
9670 do {
9671 checkkwd = 1;
9672 } while (readtoken() == TNL);
9673 if (lasttoken != TIN)
9674 synerror("expecting \"in\"");
9675 cpp = &n1->ncase.cases;
9676 checkkwd = 2, readtoken();
9677 do {
9678 if (lasttoken == TLP)
9679 readtoken();
9680 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9681 cp->type = NCLIST;
9682 app = &cp->nclist.pattern;
9683 for (;;) {
9684 *app = ap = (union node *)stalloc(sizeof (struct narg));
9685 ap->type = NARG;
9686 ap->narg.text = wordtext;
9687 ap->narg.backquote = backquotelist;
9688 if (checkkwd = 2, readtoken() != TPIPE)
9689 break;
9690 app = &ap->narg.next;
9691 readtoken();
9692 }
9693 ap->narg.next = NULL;
9694 if (lasttoken != TRP)
9695 synexpect(TRP);
9696 cp->nclist.body = list(0);
9697
9698 checkkwd = 2;
9699 if ((t = readtoken()) != TESAC) {
9700 if (t != TENDCASE)
9701 synexpect(TENDCASE);
9702 else
9703 checkkwd = 2, readtoken();
9704 }
9705 cpp = &cp->nclist.next;
9706 } while(lasttoken != TESAC);
9707 *cpp = NULL;
9708 checkkwd = 1;
9709 break;
9710 case TLP:
9711 n1 = (union node *)stalloc(sizeof (struct nredir));
9712 n1->type = NSUBSHELL;
9713 n1->nredir.n = list(0);
9714 n1->nredir.redirect = NULL;
9715 if (readtoken() != TRP)
9716 synexpect(TRP);
9717 checkkwd = 1;
9718 break;
9719 case TBEGIN:
9720 n1 = list(0);
9721 if (readtoken() != TEND)
9722 synexpect(TEND);
9723 checkkwd = 1;
9724 break;
9725 /* Handle an empty command like other simple commands. */
9726 case TSEMI:
9727 case TAND:
9728 case TOR:
9729 case TNL:
9730 case TEOF:
9731 case TRP:
9732 case TBACKGND:
9733 /*
9734 * An empty command before a ; doesn't make much sense, and
9735 * should certainly be disallowed in the case of `if ;'.
9736 */
9737 if (!redir)
9738 synexpect(-1);
9739 case TWORD:
Eric Andersencb57d552001-06-28 07:25:16 +00009740 tokpushback++;
Eric Andersena3483db2001-10-24 08:01:06 +00009741 n1 = simplecmd(rpp, redir);
Eric Andersencb57d552001-06-28 07:25:16 +00009742 return n1;
9743 default:
9744 synexpect(-1);
9745 /* NOTREACHED */
9746 }
9747
9748 /* Now check for redirection which may follow command */
9749 while (readtoken() == TREDIR) {
9750 *rpp = n2 = redirnode;
9751 rpp = &n2->nfile.next;
9752 parsefname();
9753 }
9754 tokpushback++;
9755 *rpp = NULL;
9756 if (redir) {
9757 if (n1->type != NSUBSHELL) {
9758 n2 = (union node *)stalloc(sizeof (struct nredir));
9759 n2->type = NREDIR;
9760 n2->nredir.n = n1;
9761 n1 = n2;
9762 }
9763 n1->nredir.redirect = redir;
9764 }
9765
9766 return n1;
9767}
9768
9769
9770static union node *
Eric Andersena3483db2001-10-24 08:01:06 +00009771simplecmd(union node **rpp, union node *redir) {
Eric Andersencb57d552001-06-28 07:25:16 +00009772 union node *args, **app;
9773 union node *n = NULL;
9774 union node *vars, **vpp;
Eric Andersena3483db2001-10-24 08:01:06 +00009775 union node **orig_rpp;
Eric Andersencb57d552001-06-28 07:25:16 +00009776
9777 args = NULL;
9778 app = &args;
9779 vars = NULL;
9780 vpp = &vars;
Eric Andersena3483db2001-10-24 08:01:06 +00009781
9782 /* If we don't have any redirections already, then we must reset
9783 rpp to be the address of the local redir variable. */
9784 if (redir == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00009785 rpp = &redir;
Eric Andersena3483db2001-10-24 08:01:06 +00009786 /* We save the incoming value, because we need this for shell
9787 functions. There can not be a redirect or an argument between
9788 the function name and the open parenthesis. */
9789 orig_rpp = rpp;
Eric Andersencb57d552001-06-28 07:25:16 +00009790
9791 checkalias = 2;
9792 for (;;) {
9793 switch (readtoken()) {
9794 case TWORD:
9795 case TASSIGN:
9796 n = (union node *)stalloc(sizeof (struct narg));
9797 n->type = NARG;
9798 n->narg.text = wordtext;
9799 n->narg.backquote = backquotelist;
9800 if (lasttoken == TWORD) {
9801 *app = n;
9802 app = &n->narg.next;
9803 } else {
9804 *vpp = n;
9805 vpp = &n->narg.next;
9806 }
9807 break;
9808 case TREDIR:
9809 *rpp = n = redirnode;
9810 rpp = &n->nfile.next;
Eric Andersen2870d962001-07-02 17:27:21 +00009811 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +00009812 break;
9813 case TLP:
9814 if (
9815 args && app == &args->narg.next &&
Eric Andersena3483db2001-10-24 08:01:06 +00009816 !vars && rpp == orig_rpp
Eric Andersencb57d552001-06-28 07:25:16 +00009817 ) {
9818 /* We have a function */
9819 if (readtoken() != TRP)
9820 synexpect(TRP);
Eric Andersencb57d552001-06-28 07:25:16 +00009821 n->type = NDEFUN;
9822 checkkwd = 2;
9823 n->narg.next = command();
9824 return n;
9825 }
9826 /* fall through */
9827 default:
9828 tokpushback++;
9829 goto out;
9830 }
9831 }
9832out:
9833 *app = NULL;
9834 *vpp = NULL;
9835 *rpp = NULL;
9836 n = (union node *)stalloc(sizeof (struct ncmd));
9837 n->type = NCMD;
9838 n->ncmd.backgnd = 0;
9839 n->ncmd.args = args;
9840 n->ncmd.assign = vars;
9841 n->ncmd.redirect = redir;
9842 return n;
9843}
9844
9845static union node *
Eric Andersen2870d962001-07-02 17:27:21 +00009846makename(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009847 union node *n;
9848
9849 n = (union node *)stalloc(sizeof (struct narg));
9850 n->type = NARG;
9851 n->narg.next = NULL;
9852 n->narg.text = wordtext;
9853 n->narg.backquote = backquotelist;
9854 return n;
9855}
9856
9857static void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +00009858{
Eric Andersencb57d552001-06-28 07:25:16 +00009859 TRACE(("Fix redir %s %d\n", text, err));
9860 if (!err)
9861 n->ndup.vname = NULL;
9862
9863 if (is_digit(text[0]) && text[1] == '\0')
9864 n->ndup.dupfd = digit_val(text[0]);
9865 else if (text[0] == '-' && text[1] == '\0')
9866 n->ndup.dupfd = -1;
9867 else {
9868
9869 if (err)
9870 synerror("Bad fd number");
9871 else
9872 n->ndup.vname = makename();
9873 }
9874}
9875
9876
9877static void
Eric Andersen2870d962001-07-02 17:27:21 +00009878parsefname(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009879 union node *n = redirnode;
9880
9881 if (readtoken() != TWORD)
9882 synexpect(-1);
9883 if (n->type == NHERE) {
9884 struct heredoc *here = heredoc;
9885 struct heredoc *p;
9886 int i;
9887
9888 if (quoteflag == 0)
9889 n->type = NXHERE;
9890 TRACE(("Here document %d\n", n->type));
9891 if (here->striptabs) {
9892 while (*wordtext == '\t')
9893 wordtext++;
9894 }
9895 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9896 synerror("Illegal eof marker for << redirection");
9897 rmescapes(wordtext);
9898 here->eofmark = wordtext;
9899 here->next = NULL;
9900 if (heredoclist == NULL)
9901 heredoclist = here;
9902 else {
9903 for (p = heredoclist ; p->next ; p = p->next);
9904 p->next = here;
9905 }
9906 } else if (n->type == NTOFD || n->type == NFROMFD) {
9907 fixredir(n, wordtext, 0);
9908 } else {
9909 n->nfile.fname = makename();
9910 }
9911}
9912
9913
9914/*
9915 * Input any here documents.
9916 */
9917
9918static void
9919parseheredoc() {
9920 struct heredoc *here;
9921 union node *n;
9922
9923 while (heredoclist) {
9924 here = heredoclist;
9925 heredoclist = here->next;
9926 if (needprompt) {
9927 setprompt(2);
9928 needprompt = 0;
9929 }
9930 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9931 here->eofmark, here->striptabs);
9932 n = (union node *)stalloc(sizeof (struct narg));
9933 n->narg.type = NARG;
9934 n->narg.next = NULL;
9935 n->narg.text = wordtext;
9936 n->narg.backquote = backquotelist;
9937 here->here->nhere.doc = n;
9938 }
9939}
9940
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009941static char
Eric Andersencb57d552001-06-28 07:25:16 +00009942peektoken() {
9943 int t;
9944
9945 t = readtoken();
9946 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009947 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +00009948}
9949
9950static int
9951readtoken() {
9952 int t;
Eric Andersen7467c8d2001-07-12 20:26:32 +00009953
Eric Andersencb57d552001-06-28 07:25:16 +00009954 int savecheckalias = checkalias;
Eric Andersen8e139872002-07-04 00:19:46 +00009955#ifdef CONFIG_ASH_ALIAS
Eric Andersen7467c8d2001-07-12 20:26:32 +00009956 int savecheckkwd = checkkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009957 struct alias *ap;
Eric Andersen2870d962001-07-02 17:27:21 +00009958#endif
9959
Eric Andersencb57d552001-06-28 07:25:16 +00009960#ifdef DEBUG
9961 int alreadyseen = tokpushback;
9962#endif
9963
Eric Andersend35c5df2002-01-09 15:37:36 +00009964#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00009965top:
Eric Andersen2870d962001-07-02 17:27:21 +00009966#endif
9967
Eric Andersencb57d552001-06-28 07:25:16 +00009968 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +00009969
Eric Andersencb57d552001-06-28 07:25:16 +00009970 checkalias = savecheckalias;
9971
9972 if (checkkwd) {
9973 /*
9974 * eat newlines
9975 */
9976 if (checkkwd == 2) {
9977 checkkwd = 0;
9978 while (t == TNL) {
9979 parseheredoc();
9980 t = xxreadtoken();
9981 }
9982 }
9983 checkkwd = 0;
9984 /*
9985 * check for keywords
9986 */
9987 if (t == TWORD && !quoteflag)
9988 {
9989 const char *const *pp;
9990
9991 if ((pp = findkwd(wordtext))) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009992 lasttoken = t = pp - tokname_array;
9993 TRACE(("keyword %s recognized\n", tokname(t)));
Eric Andersencb57d552001-06-28 07:25:16 +00009994 goto out;
9995 }
9996 }
9997 }
9998
Eric Andersen7467c8d2001-07-12 20:26:32 +00009999
Eric Andersencb57d552001-06-28 07:25:16 +000010000 if (t != TWORD) {
10001 if (t != TREDIR) {
10002 checkalias = 0;
10003 }
10004 } else if (checkalias == 2 && isassignment(wordtext)) {
10005 lasttoken = t = TASSIGN;
10006 } else if (checkalias) {
Eric Andersen8e139872002-07-04 00:19:46 +000010007#ifdef CONFIG_ASH_ALIAS
Eric Andersenec074692001-10-31 11:05:49 +000010008 if (!quoteflag && (ap = *__lookupalias(wordtext)) != NULL && !(ap->flag & ALIASINUSE)) {
Eric Andersencb57d552001-06-28 07:25:16 +000010009 if (*ap->val) {
10010 pushstring(ap->val, strlen(ap->val), ap);
10011 }
10012 checkkwd = savecheckkwd;
10013 goto top;
10014 }
Eric Andersen2870d962001-07-02 17:27:21 +000010015#endif
Eric Andersen8e139872002-07-04 00:19:46 +000010016 checkalias = 0;
Eric Andersen7467c8d2001-07-12 20:26:32 +000010017 }
Eric Andersencb57d552001-06-28 07:25:16 +000010018out:
10019#ifdef DEBUG
10020 if (!alreadyseen)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010021 TRACE(("token %s %s\n", tokname(t), t == TWORD || t == TASSIGN ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +000010022 else
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010023 TRACE(("reread token %s %s\n", tokname(t), t == TWORD || t == TASSIGN ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +000010024#endif
10025 return (t);
10026}
10027
10028
10029/*
10030 * Read the next input token.
10031 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +000010032 * backquotes. We set quoteflag to true if any part of the word was
10033 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +000010034 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +000010035 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +000010036 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +000010037 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +000010038 *
10039 * [Change comment: here documents and internal procedures]
10040 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10041 * word parsing code into a separate routine. In this case, readtoken
10042 * doesn't need to have any internal procedures, but parseword does.
10043 * We could also make parseoperator in essence the main routine, and
10044 * have parseword (readtoken1?) handle both words and redirection.]
10045 */
10046
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +000010047#define NEW_xxreadtoken
10048#ifdef NEW_xxreadtoken
10049
10050static const char xxreadtoken_chars[] = "\n()&|;"; /* singles must be first! */
10051static const char xxreadtoken_tokens[] = {
10052 TNL, TLP, TRP, /* only single occurrence allowed */
10053 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10054 TEOF, /* corresponds to trailing nul */
10055 TAND, TOR, TENDCASE, /* if double occurrence */
10056};
10057
10058#define xxreadtoken_doubles \
10059 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10060#define xxreadtoken_singles \
10061 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10062
10063static int
10064xxreadtoken() {
10065 int c;
10066
10067 if (tokpushback) {
10068 tokpushback = 0;
10069 return lasttoken;
10070 }
10071 if (needprompt) {
10072 setprompt(2);
10073 needprompt = 0;
10074 }
10075 startlinno = plinno;
10076 for (;;) { /* until token or start of word found */
10077 c = pgetc_macro();
10078
10079 if ((c!=' ') && (c!='\t')
Eric Andersend35c5df2002-01-09 15:37:36 +000010080#ifdef CONFIG_ASH_ALIAS
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +000010081 && (c!=PEOA)
10082#endif
10083 ) {
10084 if (c=='#') {
10085 while ((c = pgetc()) != '\n' && c != PEOF);
10086 pungetc();
10087 } else if (c=='\\') {
10088 if (pgetc() != '\n') {
10089 pungetc();
10090 goto READTOKEN1;
10091 }
10092 startlinno = ++plinno;
10093 setprompt(doprompt ? 2 : 0);
10094 } else {
10095 const char *p
10096 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10097
10098 if (c!=PEOF) {
10099 if (c=='\n') {
10100 plinno++;
10101 needprompt = doprompt;
10102 }
10103
10104 p = strchr(xxreadtoken_chars, c);
10105 if (p == NULL) {
10106 READTOKEN1:
10107 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10108 }
10109
10110 if (p-xxreadtoken_chars >= xxreadtoken_singles) {
10111 if (pgetc() == *p) { /* double occurrence? */
10112 p += xxreadtoken_doubles + 1;
10113 } else {
10114 pungetc();
10115 }
10116 }
10117 }
10118
10119 return lasttoken = xxreadtoken_tokens[p-xxreadtoken_chars];
10120 }
10121 }
10122 }
10123}
10124
10125
10126#else
Eric Andersen2870d962001-07-02 17:27:21 +000010127#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010128
10129static int
10130xxreadtoken() {
10131 int c;
10132
10133 if (tokpushback) {
10134 tokpushback = 0;
10135 return lasttoken;
10136 }
10137 if (needprompt) {
10138 setprompt(2);
10139 needprompt = 0;
10140 }
10141 startlinno = plinno;
Eric Andersen2870d962001-07-02 17:27:21 +000010142 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010143 c = pgetc_macro();
10144 switch (c) {
10145 case ' ': case '\t':
Eric Andersend35c5df2002-01-09 15:37:36 +000010146#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010147 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010148#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010149 continue;
10150 case '#':
10151 while ((c = pgetc()) != '\n' && c != PEOF);
10152 pungetc();
10153 continue;
10154 case '\\':
10155 if (pgetc() == '\n') {
10156 startlinno = ++plinno;
10157 if (doprompt)
10158 setprompt(2);
10159 else
10160 setprompt(0);
10161 continue;
10162 }
10163 pungetc();
10164 goto breakloop;
10165 case '\n':
10166 plinno++;
10167 needprompt = doprompt;
10168 RETURN(TNL);
10169 case PEOF:
10170 RETURN(TEOF);
10171 case '&':
10172 if (pgetc() == '&')
10173 RETURN(TAND);
10174 pungetc();
10175 RETURN(TBACKGND);
10176 case '|':
10177 if (pgetc() == '|')
10178 RETURN(TOR);
10179 pungetc();
10180 RETURN(TPIPE);
10181 case ';':
10182 if (pgetc() == ';')
10183 RETURN(TENDCASE);
10184 pungetc();
10185 RETURN(TSEMI);
10186 case '(':
10187 RETURN(TLP);
10188 case ')':
10189 RETURN(TRP);
10190 default:
10191 goto breakloop;
10192 }
10193 }
10194breakloop:
10195 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10196#undef RETURN
10197}
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +000010198#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010199
Eric Andersencb57d552001-06-28 07:25:16 +000010200/*
10201 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10202 * is not NULL, read a here document. In the latter case, eofmark is the
10203 * word which marks the end of the document and striptabs is true if
10204 * leading tabs should be stripped from the document. The argument firstc
10205 * is the first character of the input token or document.
10206 *
10207 * Because C does not have internal subroutines, I have simulated them
10208 * using goto's to implement the subroutine linkage. The following macros
10209 * will run code that appears at the end of readtoken1.
10210 */
10211
Eric Andersen2870d962001-07-02 17:27:21 +000010212#define CHECKEND() {goto checkend; checkend_return:;}
10213#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10214#define PARSESUB() {goto parsesub; parsesub_return:;}
10215#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10216#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10217#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010218
10219static int
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010220readtoken1(int firstc, int syntax, const char *eofmark, int striptabs)
10221{
Eric Andersencb57d552001-06-28 07:25:16 +000010222 int c = firstc;
10223 char *out;
10224 int len;
10225 char line[EOFMARKLEN + 1];
10226 struct nodelist *bqlist;
10227 int quotef;
10228 int dblquote;
Eric Andersen2870d962001-07-02 17:27:21 +000010229 int varnest; /* levels of variables expansion */
10230 int arinest; /* levels of arithmetic expansion */
10231 int parenlevel; /* levels of parens in arithmetic */
10232 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +000010233 int oldstyle;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010234 int prevsyntax; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010235#if __GNUC__
10236 /* Avoid longjmp clobbering */
10237 (void) &out;
10238 (void) &quotef;
10239 (void) &dblquote;
10240 (void) &varnest;
10241 (void) &arinest;
10242 (void) &parenlevel;
10243 (void) &dqvarnest;
10244 (void) &oldstyle;
10245 (void) &prevsyntax;
10246 (void) &syntax;
10247#endif
10248
10249 startlinno = plinno;
10250 dblquote = 0;
10251 if (syntax == DQSYNTAX)
10252 dblquote = 1;
10253 quotef = 0;
10254 bqlist = NULL;
10255 varnest = 0;
10256 arinest = 0;
10257 parenlevel = 0;
10258 dqvarnest = 0;
10259
10260 STARTSTACKSTR(out);
Eric Andersen2870d962001-07-02 17:27:21 +000010261 loop: { /* for each line, until end of word */
10262 CHECKEND(); /* set c to PEOF if at end of here document */
10263 for (;;) { /* until end of line or end of word */
10264 CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010265 switch(SIT(c,syntax)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010266 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010267 if (syntax == BASESYNTAX)
Eric Andersen2870d962001-07-02 17:27:21 +000010268 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010269 USTPUTC(c, out);
10270 plinno++;
10271 if (doprompt)
10272 setprompt(2);
10273 else
10274 setprompt(0);
10275 c = pgetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010276 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010277 case CWORD:
10278 USTPUTC(c, out);
10279 break;
10280 case CCTL:
10281 if ((eofmark == NULL || dblquote) &&
10282 dqvarnest == 0)
10283 USTPUTC(CTLESC, out);
10284 USTPUTC(c, out);
10285 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010286 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010287 c = pgetc2();
10288 if (c == PEOF) {
10289 USTPUTC('\\', out);
10290 pungetc();
10291 } else if (c == '\n') {
10292 if (doprompt)
10293 setprompt(2);
10294 else
10295 setprompt(0);
10296 } else {
10297 if (dblquote && c != '\\' && c != '`' && c != '$'
10298 && (c != '"' || eofmark != NULL))
10299 USTPUTC('\\', out);
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010300 if (SIT(c,SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010301 USTPUTC(CTLESC, out);
10302 else if (eofmark == NULL)
10303 USTPUTC(CTLQUOTEMARK, out);
10304 USTPUTC(c, out);
10305 quotef++;
10306 }
10307 break;
10308 case CSQUOTE:
10309 if (eofmark == NULL)
10310 USTPUTC(CTLQUOTEMARK, out);
10311 syntax = SQSYNTAX;
10312 break;
10313 case CDQUOTE:
10314 if (eofmark == NULL)
10315 USTPUTC(CTLQUOTEMARK, out);
10316 syntax = DQSYNTAX;
10317 dblquote = 1;
10318 break;
10319 case CENDQUOTE:
10320 if (eofmark != NULL && arinest == 0 &&
10321 varnest == 0) {
10322 USTPUTC(c, out);
10323 } else {
10324 if (arinest) {
10325 syntax = ARISYNTAX;
10326 dblquote = 0;
10327 } else if (eofmark == NULL &&
10328 dqvarnest == 0) {
10329 syntax = BASESYNTAX;
10330 dblquote = 0;
10331 }
10332 quotef++;
10333 }
10334 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010335 case CVAR: /* '$' */
10336 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010337 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010338 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010339 if (varnest > 0) {
10340 varnest--;
10341 if (dqvarnest > 0) {
10342 dqvarnest--;
10343 }
10344 USTPUTC(CTLENDVAR, out);
10345 } else {
10346 USTPUTC(c, out);
10347 }
10348 break;
Eric Andersend35c5df2002-01-09 15:37:36 +000010349#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +000010350 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010351 parenlevel++;
10352 USTPUTC(c, out);
10353 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010354 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010355 if (parenlevel > 0) {
10356 USTPUTC(c, out);
10357 --parenlevel;
10358 } else {
10359 if (pgetc() == ')') {
10360 if (--arinest == 0) {
10361 USTPUTC(CTLENDARI, out);
10362 syntax = prevsyntax;
10363 if (syntax == DQSYNTAX)
10364 dblquote = 1;
10365 else
10366 dblquote = 0;
10367 } else
10368 USTPUTC(')', out);
10369 } else {
10370 /*
10371 * unbalanced parens
10372 * (don't 2nd guess - no error)
10373 */
10374 pungetc();
10375 USTPUTC(')', out);
10376 }
10377 }
10378 break;
10379#endif
Eric Andersen2870d962001-07-02 17:27:21 +000010380 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010381 PARSEBACKQOLD();
10382 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010383 case CENDFILE:
10384 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010385 case CIGN:
10386 break;
10387 default:
10388 if (varnest == 0)
Eric Andersen2870d962001-07-02 17:27:21 +000010389 goto endword; /* exit outer loop */
Eric Andersend35c5df2002-01-09 15:37:36 +000010390#ifdef CONFIG_ASH_ALIAS
Eric Andersen3102ac42001-07-06 04:26:23 +000010391 if (c != PEOA)
10392#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010393 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010394
Eric Andersencb57d552001-06-28 07:25:16 +000010395 }
10396 c = pgetc_macro();
10397 }
10398 }
10399endword:
10400 if (syntax == ARISYNTAX)
10401 synerror("Missing '))'");
10402 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10403 synerror("Unterminated quoted string");
10404 if (varnest != 0) {
10405 startlinno = plinno;
10406 synerror("Missing '}'");
10407 }
10408 USTPUTC('\0', out);
10409 len = out - stackblock();
10410 out = stackblock();
10411 if (eofmark == NULL) {
10412 if ((c == '>' || c == '<')
10413 && quotef == 0
10414 && len <= 2
10415 && (*out == '\0' || is_digit(*out))) {
10416 PARSEREDIR();
10417 return lasttoken = TREDIR;
10418 } else {
10419 pungetc();
10420 }
10421 }
10422 quoteflag = quotef;
10423 backquotelist = bqlist;
10424 grabstackblock(len);
10425 wordtext = out;
10426 return lasttoken = TWORD;
10427/* end of readtoken routine */
10428
10429
10430
10431/*
10432 * Check to see whether we are at the end of the here document. When this
10433 * is called, c is set to the first character of the next input line. If
10434 * we are at the end of the here document, this routine sets the c to PEOF.
10435 */
10436
10437checkend: {
10438 if (eofmark) {
Eric Andersend35c5df2002-01-09 15:37:36 +000010439#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010440 if (c == PEOA) {
10441 c = pgetc2();
10442 }
Eric Andersen2870d962001-07-02 17:27:21 +000010443#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010444 if (striptabs) {
10445 while (c == '\t') {
10446 c = pgetc2();
10447 }
10448 }
10449 if (c == *eofmark) {
10450 if (pfgets(line, sizeof line) != NULL) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010451 const char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010452
10453 p = line;
10454 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10455 if (*p == '\n' && *q == '\0') {
10456 c = PEOF;
10457 plinno++;
10458 needprompt = doprompt;
10459 } else {
10460 pushstring(line, strlen(line), NULL);
10461 }
10462 }
10463 }
10464 }
10465 goto checkend_return;
10466}
10467
10468
10469/*
10470 * Parse a redirection operator. The variable "out" points to a string
10471 * specifying the fd to be redirected. The variable "c" contains the
10472 * first character of the redirection operator.
10473 */
10474
10475parseredir: {
10476 char fd = *out;
10477 union node *np;
10478
10479 np = (union node *)stalloc(sizeof (struct nfile));
10480 if (c == '>') {
10481 np->nfile.fd = 1;
10482 c = pgetc();
10483 if (c == '>')
10484 np->type = NAPPEND;
10485 else if (c == '&')
10486 np->type = NTOFD;
10487 else if (c == '|')
10488 np->type = NTOOV;
10489 else {
10490 np->type = NTO;
10491 pungetc();
10492 }
Eric Andersen2870d962001-07-02 17:27:21 +000010493 } else { /* c == '<' */
Eric Andersencb57d552001-06-28 07:25:16 +000010494 np->nfile.fd = 0;
10495 switch (c = pgetc()) {
10496 case '<':
10497 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10498 np = (union node *)stalloc(sizeof (struct nhere));
10499 np->nfile.fd = 0;
10500 }
10501 np->type = NHERE;
10502 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10503 heredoc->here = np;
10504 if ((c = pgetc()) == '-') {
10505 heredoc->striptabs = 1;
10506 } else {
10507 heredoc->striptabs = 0;
10508 pungetc();
10509 }
10510 break;
10511
10512 case '&':
10513 np->type = NFROMFD;
10514 break;
10515
10516 case '>':
10517 np->type = NFROMTO;
10518 break;
10519
10520 default:
10521 np->type = NFROM;
10522 pungetc();
10523 break;
10524 }
10525 }
10526 if (fd != '\0')
10527 np->nfile.fd = digit_val(fd);
10528 redirnode = np;
10529 goto parseredir_return;
10530}
10531
10532
10533/*
10534 * Parse a substitution. At this point, we have read the dollar sign
10535 * and nothing else.
10536 */
10537
10538parsesub: {
10539 int subtype;
10540 int typeloc;
10541 int flags;
10542 char *p;
10543 static const char types[] = "}-+?=";
10544
10545 c = pgetc();
10546 if (
10547 c <= PEOA ||
10548 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10549 ) {
10550 USTPUTC('$', out);
10551 pungetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010552 } else if (c == '(') { /* $(command) or $((arith)) */
Eric Andersencb57d552001-06-28 07:25:16 +000010553 if (pgetc() == '(') {
10554 PARSEARITH();
10555 } else {
10556 pungetc();
10557 PARSEBACKQNEW();
10558 }
10559 } else {
10560 USTPUTC(CTLVAR, out);
10561 typeloc = out - stackblock();
10562 USTPUTC(VSNORMAL, out);
10563 subtype = VSNORMAL;
10564 if (c == '{') {
10565 c = pgetc();
10566 if (c == '#') {
10567 if ((c = pgetc()) == '}')
10568 c = '#';
10569 else
10570 subtype = VSLENGTH;
10571 }
10572 else
10573 subtype = 0;
10574 }
10575 if (c > PEOA && is_name(c)) {
10576 do {
10577 STPUTC(c, out);
10578 c = pgetc();
10579 } while (c > PEOA && is_in_name(c));
10580 } else if (is_digit(c)) {
10581 do {
10582 USTPUTC(c, out);
10583 c = pgetc();
10584 } while (is_digit(c));
10585 }
10586 else if (is_special(c)) {
10587 USTPUTC(c, out);
10588 c = pgetc();
10589 }
10590 else
Eric Andersen2870d962001-07-02 17:27:21 +000010591badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010592
10593 STPUTC('=', out);
10594 flags = 0;
10595 if (subtype == 0) {
10596 switch (c) {
10597 case ':':
10598 flags = VSNUL;
10599 c = pgetc();
10600 /*FALLTHROUGH*/
10601 default:
10602 p = strchr(types, c);
10603 if (p == NULL)
10604 goto badsub;
10605 subtype = p - types + VSNORMAL;
10606 break;
10607 case '%':
10608 case '#':
10609 {
10610 int cc = c;
10611 subtype = c == '#' ? VSTRIMLEFT :
10612 VSTRIMRIGHT;
10613 c = pgetc();
10614 if (c == cc)
10615 subtype++;
10616 else
10617 pungetc();
10618 break;
10619 }
10620 }
10621 } else {
10622 pungetc();
10623 }
10624 if (dblquote || arinest)
10625 flags |= VSQUOTE;
10626 *(stackblock() + typeloc) = subtype | flags;
10627 if (subtype != VSNORMAL) {
10628 varnest++;
10629 if (dblquote) {
10630 dqvarnest++;
10631 }
10632 }
10633 }
10634 goto parsesub_return;
10635}
10636
10637
10638/*
10639 * Called to parse command substitutions. Newstyle is set if the command
10640 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10641 * list of commands (passed by reference), and savelen is the number of
10642 * characters on the top of the stack which must be preserved.
10643 */
10644
10645parsebackq: {
10646 struct nodelist **nlpp;
10647 int savepbq;
10648 union node *n;
10649 char *volatile str;
10650 struct jmploc jmploc;
10651 struct jmploc *volatile savehandler;
10652 int savelen;
10653 int saveprompt;
10654#ifdef __GNUC__
10655 (void) &saveprompt;
10656#endif
10657
10658 savepbq = parsebackquote;
10659 if (setjmp(jmploc.loc)) {
Aaron Lehmann49c024a2002-08-02 06:39:47 +000010660 free(str);
Eric Andersencb57d552001-06-28 07:25:16 +000010661 parsebackquote = 0;
10662 handler = savehandler;
10663 longjmp(handler->loc, 1);
10664 }
10665 INTOFF;
10666 str = NULL;
10667 savelen = out - stackblock();
10668 if (savelen > 0) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010669 str = xmalloc(savelen);
Eric Andersencb57d552001-06-28 07:25:16 +000010670 memcpy(str, stackblock(), savelen);
10671 }
10672 savehandler = handler;
10673 handler = &jmploc;
10674 INTON;
Eric Andersen2870d962001-07-02 17:27:21 +000010675 if (oldstyle) {
10676 /* We must read until the closing backquote, giving special
10677 treatment to some slashes, and then push the string and
10678 reread it as input, interpreting it normally. */
10679 char *pout;
10680 int pc;
10681 int psavelen;
10682 char *pstr;
Eric Andersencb57d552001-06-28 07:25:16 +000010683
10684
Eric Andersen2870d962001-07-02 17:27:21 +000010685 STARTSTACKSTR(pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010686 for (;;) {
10687 if (needprompt) {
10688 setprompt(2);
10689 needprompt = 0;
10690 }
10691 switch (pc = pgetc()) {
10692 case '`':
10693 goto done;
10694
10695 case '\\':
Eric Andersen2870d962001-07-02 17:27:21 +000010696 if ((pc = pgetc()) == '\n') {
Eric Andersencb57d552001-06-28 07:25:16 +000010697 plinno++;
10698 if (doprompt)
10699 setprompt(2);
10700 else
10701 setprompt(0);
10702 /*
10703 * If eating a newline, avoid putting
10704 * the newline into the new character
10705 * stream (via the STPUTC after the
10706 * switch).
10707 */
10708 continue;
10709 }
Eric Andersen2870d962001-07-02 17:27:21 +000010710 if (pc != '\\' && pc != '`' && pc != '$'
10711 && (!dblquote || pc != '"'))
10712 STPUTC('\\', pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010713 if (pc > PEOA) {
10714 break;
10715 }
10716 /* fall through */
10717
10718 case PEOF:
Eric Andersend35c5df2002-01-09 15:37:36 +000010719#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010720 case PEOA:
Eric Andersen2870d962001-07-02 17:27:21 +000010721#endif
10722 startlinno = plinno;
Eric Andersencb57d552001-06-28 07:25:16 +000010723 synerror("EOF in backquote substitution");
10724
10725 case '\n':
10726 plinno++;
10727 needprompt = doprompt;
10728 break;
10729
10730 default:
10731 break;
10732 }
10733 STPUTC(pc, pout);
Eric Andersen2870d962001-07-02 17:27:21 +000010734 }
Eric Andersencb57d552001-06-28 07:25:16 +000010735done:
Eric Andersen2870d962001-07-02 17:27:21 +000010736 STPUTC('\0', pout);
10737 psavelen = pout - stackblock();
10738 if (psavelen > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010739 pstr = grabstackstr(pout);
10740 setinputstring(pstr);
Eric Andersen2870d962001-07-02 17:27:21 +000010741 }
10742 }
Eric Andersencb57d552001-06-28 07:25:16 +000010743 nlpp = &bqlist;
10744 while (*nlpp)
10745 nlpp = &(*nlpp)->next;
10746 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10747 (*nlpp)->next = NULL;
10748 parsebackquote = oldstyle;
10749
10750 if (oldstyle) {
10751 saveprompt = doprompt;
10752 doprompt = 0;
10753 }
10754
10755 n = list(0);
10756
10757 if (oldstyle)
10758 doprompt = saveprompt;
10759 else {
10760 if (readtoken() != TRP)
10761 synexpect(TRP);
10762 }
10763
10764 (*nlpp)->n = n;
Eric Andersen2870d962001-07-02 17:27:21 +000010765 if (oldstyle) {
Eric Andersencb57d552001-06-28 07:25:16 +000010766 /*
10767 * Start reading from old file again, ignoring any pushed back
10768 * tokens left from the backquote parsing
10769 */
Eric Andersen2870d962001-07-02 17:27:21 +000010770 popfile();
Eric Andersencb57d552001-06-28 07:25:16 +000010771 tokpushback = 0;
10772 }
10773 while (stackblocksize() <= savelen)
10774 growstackblock();
10775 STARTSTACKSTR(out);
10776 if (str) {
10777 memcpy(out, str, savelen);
10778 STADJUST(savelen, out);
10779 INTOFF;
Aaron Lehmann49c024a2002-08-02 06:39:47 +000010780 free(str);
Eric Andersencb57d552001-06-28 07:25:16 +000010781 str = NULL;
10782 INTON;
10783 }
10784 parsebackquote = savepbq;
10785 handler = savehandler;
10786 if (arinest || dblquote)
10787 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10788 else
10789 USTPUTC(CTLBACKQ, out);
10790 if (oldstyle)
10791 goto parsebackq_oldreturn;
10792 else
10793 goto parsebackq_newreturn;
10794}
10795
10796/*
10797 * Parse an arithmetic expansion (indicate start of one and set state)
10798 */
10799parsearith: {
10800
10801 if (++arinest == 1) {
10802 prevsyntax = syntax;
10803 syntax = ARISYNTAX;
10804 USTPUTC(CTLARI, out);
10805 if (dblquote)
10806 USTPUTC('"',out);
10807 else
10808 USTPUTC(' ',out);
10809 } else {
10810 /*
10811 * we collapse embedded arithmetic expansion to
10812 * parenthesis, which should be equivalent
10813 */
10814 USTPUTC('(', out);
10815 }
10816 goto parsearith_return;
10817}
10818
10819} /* end of readtoken */
10820
10821
Eric Andersencb57d552001-06-28 07:25:16 +000010822/*
10823 * Returns true if the text contains nothing to expand (no dollar signs
10824 * or backquotes).
10825 */
10826
10827static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010828noexpand(char *text)
10829{
Eric Andersencb57d552001-06-28 07:25:16 +000010830 char *p;
10831 char c;
10832
10833 p = text;
10834 while ((c = *p++) != '\0') {
10835 if (c == CTLQUOTEMARK)
10836 continue;
10837 if (c == CTLESC)
10838 p++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010839 else if (SIT(c,BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010840 return 0;
10841 }
10842 return 1;
10843}
10844
10845
10846/*
10847 * Return true if the argument is a legal variable name (a letter or
10848 * underscore followed by zero or more letters, underscores, and digits).
10849 */
10850
10851static int
Eric Andersen2870d962001-07-02 17:27:21 +000010852goodname(const char *name)
10853{
10854 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000010855
10856 p = name;
10857 if (! is_name(*p))
10858 return 0;
10859 while (*++p) {
10860 if (! is_in_name(*p))
10861 return 0;
10862 }
10863 return 1;
10864}
10865
10866
10867/*
10868 * Called when an unexpected token is read during the parse. The argument
10869 * is the token that is expected, or -1 if more than one type of token can
10870 * occur at this point.
10871 */
10872
10873static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010874synexpect(int token)
Eric Andersencb57d552001-06-28 07:25:16 +000010875{
10876 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010877 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000010878
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010879 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10880 if (token >= 0)
10881 sprintf(msg+l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000010882 synerror(msg);
10883 /* NOTREACHED */
10884}
10885
10886
10887static void
Eric Andersen2870d962001-07-02 17:27:21 +000010888synerror(const char *msg)
10889{
Eric Andersencb57d552001-06-28 07:25:16 +000010890 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +000010891 out2fmt("%s: %d: ", commandname, startlinno);
10892 out2fmt("Syntax error: %s\n", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000010893 error((char *)NULL);
10894 /* NOTREACHED */
10895}
10896
Eric Andersencb57d552001-06-28 07:25:16 +000010897
10898/*
10899 * called by editline -- any expansions to the prompt
10900 * should be added here.
10901 */
Eric Andersen2870d962001-07-02 17:27:21 +000010902static void
Eric Andersen62483552001-07-10 06:09:16 +000010903setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000010904{
Eric Andersen62483552001-07-10 06:09:16 +000010905 char *prompt;
10906 switch (whichprompt) {
10907 case 1:
10908 prompt = ps1val();
10909 break;
10910 case 2:
10911 prompt = ps2val();
10912 break;
10913 default: /* 0 */
10914 prompt = "";
10915 }
10916 putprompt(prompt);
Eric Andersencb57d552001-06-28 07:25:16 +000010917}
10918
Eric Andersencb57d552001-06-28 07:25:16 +000010919
Eric Andersencb57d552001-06-28 07:25:16 +000010920/*
10921 * Code for dealing with input/output redirection.
10922 */
10923
Eric Andersen2870d962001-07-02 17:27:21 +000010924#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000010925#ifndef PIPE_BUF
Eric Andersen2870d962001-07-02 17:27:21 +000010926# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000010927#else
10928# define PIPESIZE PIPE_BUF
10929#endif
10930
10931
Eric Andersen62483552001-07-10 06:09:16 +000010932/*
10933 * Open a file in noclobber mode.
10934 * The code was copied from bash.
10935 */
10936static inline int
10937noclobberopen(const char *fname)
10938{
10939 int r, fd;
10940 struct stat finfo, finfo2;
10941
10942 /*
10943 * If the file exists and is a regular file, return an error
10944 * immediately.
10945 */
10946 r = stat(fname, &finfo);
10947 if (r == 0 && S_ISREG(finfo.st_mode)) {
10948 errno = EEXIST;
10949 return -1;
10950 }
10951
10952 /*
10953 * If the file was not present (r != 0), make sure we open it
10954 * exclusively so that if it is created before we open it, our open
10955 * will fail. Make sure that we do not truncate an existing file.
10956 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10957 * file was not a regular file, we leave O_EXCL off.
10958 */
10959 if (r != 0)
10960 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10961 fd = open(fname, O_WRONLY|O_CREAT, 0666);
10962
10963 /* If the open failed, return the file descriptor right away. */
10964 if (fd < 0)
10965 return fd;
10966
10967 /*
10968 * OK, the open succeeded, but the file may have been changed from a
10969 * non-regular file to a regular file between the stat and the open.
10970 * We are assuming that the O_EXCL open handles the case where FILENAME
10971 * did not exist and is symlinked to an existing file between the stat
10972 * and open.
10973 */
10974
10975 /*
10976 * If we can open it and fstat the file descriptor, and neither check
10977 * revealed that it was a regular file, and the file has not been
10978 * replaced, return the file descriptor.
10979 */
10980 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10981 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
10982 return fd;
10983
10984 /* The file has been replaced. badness. */
10985 close(fd);
10986 errno = EEXIST;
10987 return -1;
10988}
Eric Andersencb57d552001-06-28 07:25:16 +000010989
10990/*
Eric Andersen62483552001-07-10 06:09:16 +000010991 * Handle here documents. Normally we fork off a process to write the
10992 * data to a pipe. If the document is short, we can stuff the data in
10993 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000010994 */
10995
Eric Andersen62483552001-07-10 06:09:16 +000010996static inline int
10997openhere(const union node *redir)
10998{
10999 int pip[2];
11000 int len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011001
Eric Andersen62483552001-07-10 06:09:16 +000011002 if (pipe(pip) < 0)
11003 error("Pipe call failed");
11004 if (redir->type == NHERE) {
11005 len = strlen(redir->nhere.doc->narg.text);
11006 if (len <= PIPESIZE) {
11007 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11008 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011009 }
Eric Andersencb57d552001-06-28 07:25:16 +000011010 }
Eric Andersen62483552001-07-10 06:09:16 +000011011 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
11012 close(pip[0]);
11013 signal(SIGINT, SIG_IGN);
11014 signal(SIGQUIT, SIG_IGN);
11015 signal(SIGHUP, SIG_IGN);
11016#ifdef SIGTSTP
11017 signal(SIGTSTP, SIG_IGN);
11018#endif
11019 signal(SIGPIPE, SIG_DFL);
11020 if (redir->type == NHERE)
11021 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11022 else
11023 expandhere(redir->nhere.doc, pip[1]);
11024 _exit(0);
11025 }
11026out:
11027 close(pip[1]);
11028 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000011029}
11030
11031
Eric Andersen62483552001-07-10 06:09:16 +000011032static inline int
11033openredirect(const union node *redir)
11034{
Eric Andersencb57d552001-06-28 07:25:16 +000011035 char *fname;
11036 int f;
11037
11038 switch (redir->nfile.type) {
11039 case NFROM:
11040 fname = redir->nfile.expfname;
11041 if ((f = open(fname, O_RDONLY)) < 0)
11042 goto eopen;
11043 break;
11044 case NFROMTO:
11045 fname = redir->nfile.expfname;
11046 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
11047 goto ecreate;
11048 break;
11049 case NTO:
11050 /* Take care of noclobber mode. */
11051 if (Cflag) {
11052 fname = redir->nfile.expfname;
11053 if ((f = noclobberopen(fname)) < 0)
11054 goto ecreate;
11055 break;
11056 }
11057 case NTOOV:
11058 fname = redir->nfile.expfname;
11059#ifdef O_CREAT
11060 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
11061 goto ecreate;
11062#else
11063 if ((f = creat(fname, 0666)) < 0)
11064 goto ecreate;
11065#endif
11066 break;
11067 case NAPPEND:
11068 fname = redir->nfile.expfname;
11069#ifdef O_APPEND
11070 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
11071 goto ecreate;
11072#else
11073 if ((f = open(fname, O_WRONLY)) < 0
11074 && (f = creat(fname, 0666)) < 0)
11075 goto ecreate;
11076 lseek(f, (off_t)0, 2);
11077#endif
11078 break;
11079 default:
11080#ifdef DEBUG
11081 abort();
11082#endif
11083 /* Fall through to eliminate warning. */
11084 case NTOFD:
11085 case NFROMFD:
11086 f = -1;
11087 break;
11088 case NHERE:
11089 case NXHERE:
11090 f = openhere(redir);
11091 break;
11092 }
11093
11094 return f;
11095ecreate:
11096 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11097eopen:
11098 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11099}
11100
11101
Eric Andersen62483552001-07-10 06:09:16 +000011102/*
11103 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11104 * old file descriptors are stashed away so that the redirection can be
11105 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11106 * standard output, and the standard error if it becomes a duplicate of
11107 * stdout.
11108 */
11109
Eric Andersencb57d552001-06-28 07:25:16 +000011110static void
Eric Andersen62483552001-07-10 06:09:16 +000011111redirect(union node *redir, int flags)
11112{
11113 union node *n;
11114 struct redirtab *sv = NULL;
Eric Andersen2276d832002-07-11 11:11:56 +000011115 int i = EMPTY;
Eric Andersen62483552001-07-10 06:09:16 +000011116 int fd;
11117 int newfd;
11118 int try;
11119 int fd1dup = flags & REDIR_BACKQ;; /* stdout `cmd` redir to pipe */
11120
11121 if (flags & REDIR_PUSH) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011122 sv = xmalloc(sizeof (struct redirtab));
Eric Andersen62483552001-07-10 06:09:16 +000011123 for (i = 0 ; i < 10 ; i++)
11124 sv->renamed[i] = EMPTY;
11125 sv->next = redirlist;
11126 redirlist = sv;
11127 }
11128 for (n = redir ; n ; n = n->nfile.next) {
11129 fd = n->nfile.fd;
11130 try = 0;
11131 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11132 n->ndup.dupfd == fd)
11133 continue; /* redirect from/to same file descriptor */
11134
11135 INTOFF;
11136 newfd = openredirect(n);
11137 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
11138 if (newfd == fd) {
11139 try++;
11140 } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
11141 switch (errno) {
11142 case EBADF:
11143 if (!try) {
11144 dupredirect(n, newfd, fd1dup);
11145 try++;
11146 break;
11147 }
11148 /* FALLTHROUGH*/
11149 default:
11150 if (newfd >= 0) {
11151 close(newfd);
11152 }
11153 INTON;
11154 error("%d: %m", fd);
11155 /* NOTREACHED */
11156 }
11157 }
11158 if (!try) {
11159 close(fd);
11160 if (flags & REDIR_PUSH) {
11161 sv->renamed[fd] = i;
11162 }
11163 }
11164 } else if (fd != newfd) {
11165 close(fd);
11166 }
11167 if (fd == 0)
11168 fd0_redirected++;
11169 if (!try)
11170 dupredirect(n, newfd, fd1dup);
11171 INTON;
11172 }
11173}
11174
11175
11176static void
11177dupredirect(const union node *redir, int f, int fd1dup)
Eric Andersen2870d962001-07-02 17:27:21 +000011178{
Eric Andersencb57d552001-06-28 07:25:16 +000011179 int fd = redir->nfile.fd;
11180
Eric Andersen62483552001-07-10 06:09:16 +000011181 if(fd==1)
11182 fd1dup = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011183 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Eric Andersen2870d962001-07-02 17:27:21 +000011184 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
Eric Andersen62483552001-07-10 06:09:16 +000011185 if (redir->ndup.dupfd!=1 || fd1dup!=1)
Eric Andersencb57d552001-06-28 07:25:16 +000011186 dup_as_newfd(redir->ndup.dupfd, fd);
11187 }
11188 return;
11189 }
11190
11191 if (f != fd) {
11192 dup_as_newfd(f, fd);
11193 close(f);
11194 }
11195 return;
11196}
11197
11198
Eric Andersencb57d552001-06-28 07:25:16 +000011199
Eric Andersencb57d552001-06-28 07:25:16 +000011200/*
11201 * Undo the effects of the last redirection.
11202 */
11203
11204static void
Eric Andersen2870d962001-07-02 17:27:21 +000011205popredir(void)
11206{
Eric Andersencb57d552001-06-28 07:25:16 +000011207 struct redirtab *rp = redirlist;
11208 int i;
11209
11210 INTOFF;
11211 for (i = 0 ; i < 10 ; i++) {
11212 if (rp->renamed[i] != EMPTY) {
Eric Andersen2870d962001-07-02 17:27:21 +000011213 if (i == 0)
11214 fd0_redirected--;
Eric Andersencb57d552001-06-28 07:25:16 +000011215 close(i);
11216 if (rp->renamed[i] >= 0) {
11217 dup_as_newfd(rp->renamed[i], i);
11218 close(rp->renamed[i]);
11219 }
Eric Andersencb57d552001-06-28 07:25:16 +000011220 }
11221 }
11222 redirlist = rp->next;
Aaron Lehmann49c024a2002-08-02 06:39:47 +000011223 free(rp);
Eric Andersencb57d552001-06-28 07:25:16 +000011224 INTON;
11225}
11226
11227/*
Eric Andersencb57d552001-06-28 07:25:16 +000011228 * Discard all saved file descriptors.
11229 */
11230
11231static void
Eric Andersen2870d962001-07-02 17:27:21 +000011232clearredir(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000011233 struct redirtab *rp;
11234 int i;
11235
11236 for (rp = redirlist ; rp ; rp = rp->next) {
11237 for (i = 0 ; i < 10 ; i++) {
11238 if (rp->renamed[i] >= 0) {
11239 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011240 }
11241 rp->renamed[i] = EMPTY;
11242 }
11243 }
Eric Andersencb57d552001-06-28 07:25:16 +000011244}
11245
11246
Eric Andersencb57d552001-06-28 07:25:16 +000011247/*
11248 * Copy a file descriptor to be >= to. Returns -1
11249 * if the source file descriptor is closed, EMPTY if there are no unused
11250 * file descriptors left.
11251 */
11252
11253static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011254dup_as_newfd(int from, int to)
Eric Andersencb57d552001-06-28 07:25:16 +000011255{
11256 int newfd;
11257
11258 newfd = fcntl(from, F_DUPFD, to);
11259 if (newfd < 0) {
11260 if (errno == EMFILE)
11261 return EMPTY;
11262 else
Eric Andersen2870d962001-07-02 17:27:21 +000011263 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011264 }
11265 return newfd;
11266}
11267
Eric Andersencb57d552001-06-28 07:25:16 +000011268#ifdef DEBUG
Eric Andersenec074692001-10-31 11:05:49 +000011269/*
11270 * Debugging stuff.
11271 */
Eric Andersen2870d962001-07-02 17:27:21 +000011272static void shtree (union node *, int, char *, FILE*);
11273static void shcmd (union node *, FILE *);
11274static void sharg (union node *, FILE *);
11275static void indent (int, char *, FILE *);
11276static void trstring (char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011277
11278
11279static void
11280showtree(n)
Eric Andersen69a20f02001-10-31 10:40:37 +000011281 unode *n;
Eric Andersencb57d552001-06-28 07:25:16 +000011282{
11283 trputs("showtree called\n");
11284 shtree(n, 1, NULL, stdout);
11285}
11286
11287
11288static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011289shtree(union node *n, int ind, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011290{
11291 struct nodelist *lp;
11292 const char *s;
11293
11294 if (n == NULL)
11295 return;
11296
11297 indent(ind, pfx, fp);
11298 switch(n->type) {
11299 case NSEMI:
11300 s = "; ";
11301 goto binop;
11302 case NAND:
11303 s = " && ";
11304 goto binop;
11305 case NOR:
11306 s = " || ";
11307binop:
11308 shtree(n->nbinary.ch1, ind, NULL, fp);
11309 /* if (ind < 0) */
11310 fputs(s, fp);
11311 shtree(n->nbinary.ch2, ind, NULL, fp);
11312 break;
11313 case NCMD:
11314 shcmd(n, fp);
11315 if (ind >= 0)
11316 putc('\n', fp);
11317 break;
11318 case NPIPE:
11319 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11320 shcmd(lp->n, fp);
11321 if (lp->next)
11322 fputs(" | ", fp);
11323 }
11324 if (n->npipe.backgnd)
11325 fputs(" &", fp);
11326 if (ind >= 0)
11327 putc('\n', fp);
11328 break;
11329 default:
11330 fprintf(fp, "<node type %d>", n->type);
11331 if (ind >= 0)
11332 putc('\n', fp);
11333 break;
11334 }
11335}
11336
11337
11338
11339static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011340shcmd(union node *cmd, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011341{
11342 union node *np;
11343 int first;
11344 const char *s;
11345 int dftfd;
11346
11347 first = 1;
11348 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11349 if (! first)
11350 putchar(' ');
11351 sharg(np, fp);
11352 first = 0;
11353 }
11354 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11355 if (! first)
11356 putchar(' ');
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011357#if 1
11358 s = "*error*";
11359 dftfd = 0;
11360 if ((np->nfile.type <= NFROMFD) && (np->nfile.type >= NTO)) {
11361 s = redir_strings[np->nfile.type - NTO];
11362 if (*s == '>') {
11363 dftfd = 1;
11364 }
11365 }
11366#else
Eric Andersencb57d552001-06-28 07:25:16 +000011367 switch (np->nfile.type) {
Eric Andersen2870d962001-07-02 17:27:21 +000011368 case NTO: s = ">"; dftfd = 1; break;
11369 case NAPPEND: s = ">>"; dftfd = 1; break;
11370 case NTOFD: s = ">&"; dftfd = 1; break;
11371 case NTOOV: s = ">|"; dftfd = 1; break;
11372 case NFROM: s = "<"; dftfd = 0; break;
11373 case NFROMFD: s = "<&"; dftfd = 0; break;
11374 case NFROMTO: s = "<>"; dftfd = 0; break;
11375 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011376 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011377#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011378 if (np->nfile.fd != dftfd)
11379 fprintf(fp, "%d", np->nfile.fd);
11380 fputs(s, fp);
11381 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11382 fprintf(fp, "%d", np->ndup.dupfd);
11383 } else {
11384 sharg(np->nfile.fname, fp);
11385 }
11386 first = 0;
11387 }
11388}
11389
Eric Andersencb57d552001-06-28 07:25:16 +000011390static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011391sharg(union node *arg, FILE *fp)
11392{
Eric Andersencb57d552001-06-28 07:25:16 +000011393 char *p;
11394 struct nodelist *bqlist;
11395 int subtype;
11396
11397 if (arg->type != NARG) {
11398 printf("<node type %d>\n", arg->type);
11399 fflush(stdout);
11400 abort();
11401 }
11402 bqlist = arg->narg.backquote;
11403 for (p = arg->narg.text ; *p ; p++) {
11404 switch (*p) {
11405 case CTLESC:
11406 putc(*++p, fp);
11407 break;
11408 case CTLVAR:
11409 putc('$', fp);
11410 putc('{', fp);
11411 subtype = *++p;
11412 if (subtype == VSLENGTH)
11413 putc('#', fp);
11414
11415 while (*p != '=')
11416 putc(*p++, fp);
11417
11418 if (subtype & VSNUL)
11419 putc(':', fp);
11420
11421 switch (subtype & VSTYPE) {
11422 case VSNORMAL:
11423 putc('}', fp);
11424 break;
11425 case VSMINUS:
11426 putc('-', fp);
11427 break;
11428 case VSPLUS:
11429 putc('+', fp);
11430 break;
11431 case VSQUESTION:
11432 putc('?', fp);
11433 break;
11434 case VSASSIGN:
11435 putc('=', fp);
11436 break;
11437 case VSTRIMLEFT:
11438 putc('#', fp);
11439 break;
11440 case VSTRIMLEFTMAX:
11441 putc('#', fp);
11442 putc('#', fp);
11443 break;
11444 case VSTRIMRIGHT:
11445 putc('%', fp);
11446 break;
11447 case VSTRIMRIGHTMAX:
11448 putc('%', fp);
11449 putc('%', fp);
11450 break;
11451 case VSLENGTH:
11452 break;
11453 default:
11454 printf("<subtype %d>", subtype);
11455 }
11456 break;
11457 case CTLENDVAR:
11458 putc('}', fp);
11459 break;
11460 case CTLBACKQ:
11461 case CTLBACKQ|CTLQUOTE:
11462 putc('$', fp);
11463 putc('(', fp);
11464 shtree(bqlist->n, -1, NULL, fp);
11465 putc(')', fp);
11466 break;
11467 default:
11468 putc(*p, fp);
11469 break;
11470 }
11471 }
11472}
11473
11474
11475static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011476indent(int amount, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011477{
11478 int i;
11479
11480 for (i = 0 ; i < amount ; i++) {
11481 if (pfx && i == amount - 1)
11482 fputs(pfx, fp);
11483 putc('\t', fp);
11484 }
11485}
Eric Andersencb57d552001-06-28 07:25:16 +000011486
11487
Eric Andersencb57d552001-06-28 07:25:16 +000011488FILE *tracefile;
11489
11490#if DEBUG == 2
11491static int debug = 1;
11492#else
11493static int debug = 0;
11494#endif
11495
11496
11497static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011498trputc(int c)
Eric Andersencb57d552001-06-28 07:25:16 +000011499{
11500 if (tracefile == NULL)
11501 return;
11502 putc(c, tracefile);
11503 if (c == '\n')
11504 fflush(tracefile);
11505}
11506
11507static void
11508trace(const char *fmt, ...)
11509{
11510 va_list va;
Eric Andersencb57d552001-06-28 07:25:16 +000011511 va_start(va, fmt);
Eric Andersencb57d552001-06-28 07:25:16 +000011512 if (tracefile != NULL) {
11513 (void) vfprintf(tracefile, fmt, va);
11514 if (strchr(fmt, '\n'))
11515 (void) fflush(tracefile);
11516 }
11517 va_end(va);
11518}
11519
11520
11521static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011522trputs(const char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011523{
11524 if (tracefile == NULL)
11525 return;
11526 fputs(s, tracefile);
11527 if (strchr(s, '\n'))
11528 fflush(tracefile);
11529}
11530
11531
11532static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011533trstring(char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011534{
11535 char *p;
11536 char c;
11537
11538 if (tracefile == NULL)
11539 return;
11540 putc('"', tracefile);
11541 for (p = s ; *p ; p++) {
11542 switch (*p) {
11543 case '\n': c = 'n'; goto backslash;
11544 case '\t': c = 't'; goto backslash;
11545 case '\r': c = 'r'; goto backslash;
11546 case '"': c = '"'; goto backslash;
11547 case '\\': c = '\\'; goto backslash;
11548 case CTLESC: c = 'e'; goto backslash;
11549 case CTLVAR: c = 'v'; goto backslash;
11550 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11551 case CTLBACKQ: c = 'q'; goto backslash;
11552 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
Eric Andersen2870d962001-07-02 17:27:21 +000011553backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011554 putc(c, tracefile);
11555 break;
11556 default:
11557 if (*p >= ' ' && *p <= '~')
11558 putc(*p, tracefile);
11559 else {
11560 putc('\\', tracefile);
11561 putc(*p >> 6 & 03, tracefile);
11562 putc(*p >> 3 & 07, tracefile);
11563 putc(*p & 07, tracefile);
11564 }
11565 break;
11566 }
11567 }
11568 putc('"', tracefile);
11569}
11570
11571
11572static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011573trargs(char **ap)
Eric Andersencb57d552001-06-28 07:25:16 +000011574{
11575 if (tracefile == NULL)
11576 return;
11577 while (*ap) {
11578 trstring(*ap++);
11579 if (*ap)
11580 putc(' ', tracefile);
11581 else
11582 putc('\n', tracefile);
11583 }
11584 fflush(tracefile);
11585}
11586
11587
11588static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011589opentrace()
11590{
Eric Andersencb57d552001-06-28 07:25:16 +000011591 char s[100];
11592#ifdef O_APPEND
11593 int flags;
11594#endif
11595
11596 if (!debug)
11597 return;
11598#ifdef not_this_way
11599 {
11600 char *p;
11601 if ((p = getenv("HOME")) == NULL) {
11602 if (geteuid() == 0)
11603 p = "/";
11604 else
11605 p = "/tmp";
11606 }
Eric Andersen2870d962001-07-02 17:27:21 +000011607 strcpy(s, p);
Eric Andersencb57d552001-06-28 07:25:16 +000011608 strcat(s, "/trace");
11609 }
11610#else
Eric Andersen2870d962001-07-02 17:27:21 +000011611 strcpy(s, "./trace");
Eric Andersencb57d552001-06-28 07:25:16 +000011612#endif /* not_this_way */
Matt Kraaia5f09c62001-11-12 16:44:55 +000011613 if ((tracefile = wfopen(s, "a")) == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000011614 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011615#ifdef O_APPEND
11616 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11617 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11618#endif
11619 fputs("\nTracing started.\n", tracefile);
11620 fflush(tracefile);
11621}
11622#endif /* DEBUG */
11623
11624
11625/*
Eric Andersencb57d552001-06-28 07:25:16 +000011626 * The trap builtin.
11627 */
11628
11629static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011630trapcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011631{
11632 char *action;
11633 char **ap;
11634 int signo;
11635
11636 if (argc <= 1) {
11637 for (signo = 0 ; signo < NSIG ; signo++) {
11638 if (trap[signo] != NULL) {
11639 char *p;
Eric Andersen34506362001-08-02 05:02:46 +000011640 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011641
11642 p = single_quote(trap[signo]);
Eric Andersen34506362001-08-02 05:02:46 +000011643 sn = sys_siglist[signo];
11644 if(sn==NULL)
11645 sn = u_signal_names(0, &signo, 0);
11646 if(sn==NULL)
11647 sn = "???";
11648 printf("trap -- %s %s\n", p, sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011649 stunalloc(p);
11650 }
11651 }
11652 return 0;
11653 }
11654 ap = argv + 1;
11655 if (argc == 2)
11656 action = NULL;
11657 else
11658 action = *ap++;
11659 while (*ap) {
11660 if ((signo = decode_signal(*ap, 0)) < 0)
11661 error("%s: bad trap", *ap);
11662 INTOFF;
11663 if (action) {
11664 if (action[0] == '-' && action[1] == '\0')
11665 action = NULL;
11666 else
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011667 action = xstrdup(action);
Eric Andersencb57d552001-06-28 07:25:16 +000011668 }
Aaron Lehmann49c024a2002-08-02 06:39:47 +000011669 free(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000011670 trap[signo] = action;
11671 if (signo != 0)
11672 setsignal(signo);
11673 INTON;
11674 ap++;
11675 }
11676 return 0;
11677}
11678
11679
11680
Eric Andersencb57d552001-06-28 07:25:16 +000011681
11682
11683
11684/*
11685 * Set the signal handler for the specified signal. The routine figures
11686 * out what it should be set to.
11687 */
11688
11689static void
Eric Andersen2870d962001-07-02 17:27:21 +000011690setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011691{
11692 int action;
11693 char *t;
11694 struct sigaction act;
11695
11696 if ((t = trap[signo]) == NULL)
11697 action = S_DFL;
11698 else if (*t != '\0')
11699 action = S_CATCH;
11700 else
11701 action = S_IGN;
11702 if (rootshell && action == S_DFL) {
11703 switch (signo) {
11704 case SIGINT:
11705 if (iflag || minusc || sflag == 0)
11706 action = S_CATCH;
11707 break;
11708 case SIGQUIT:
11709#ifdef DEBUG
11710 {
Eric Andersencb57d552001-06-28 07:25:16 +000011711
11712 if (debug)
11713 break;
11714 }
11715#endif
11716 /* FALLTHROUGH */
11717 case SIGTERM:
11718 if (iflag)
11719 action = S_IGN;
11720 break;
Eric Andersend35c5df2002-01-09 15:37:36 +000011721#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +000011722 case SIGTSTP:
11723 case SIGTTOU:
11724 if (mflag)
11725 action = S_IGN;
11726 break;
11727#endif
11728 }
11729 }
11730
11731 t = &sigmode[signo - 1];
11732 if (*t == 0) {
11733 /*
11734 * current setting unknown
11735 */
11736 if (sigaction(signo, 0, &act) == -1) {
11737 /*
11738 * Pretend it worked; maybe we should give a warning
11739 * here, but other shells don't. We don't alter
11740 * sigmode, so that we retry every time.
11741 */
11742 return;
11743 }
11744 if (act.sa_handler == SIG_IGN) {
11745 if (mflag && (signo == SIGTSTP ||
11746 signo == SIGTTIN || signo == SIGTTOU)) {
Eric Andersen2870d962001-07-02 17:27:21 +000011747 *t = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000011748 } else
11749 *t = S_HARD_IGN;
11750 } else {
Eric Andersen2870d962001-07-02 17:27:21 +000011751 *t = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000011752 }
11753 }
11754 if (*t == S_HARD_IGN || *t == action)
11755 return;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011756 act.sa_handler = ((action == S_CATCH) ? onsig
11757 : ((action == S_IGN) ? SIG_IGN : SIG_DFL));
Eric Andersencb57d552001-06-28 07:25:16 +000011758 *t = action;
11759 act.sa_flags = 0;
11760 sigemptyset(&act.sa_mask);
11761 sigaction(signo, &act, 0);
11762}
11763
11764/*
11765 * Ignore a signal.
11766 */
11767
11768static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011769ignoresig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011770{
11771 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11772 signal(signo, SIG_IGN);
11773 }
11774 sigmode[signo - 1] = S_HARD_IGN;
11775}
11776
11777
Eric Andersencb57d552001-06-28 07:25:16 +000011778/*
11779 * Signal handler.
11780 */
11781
11782static void
Eric Andersen2870d962001-07-02 17:27:21 +000011783onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011784{
11785 if (signo == SIGINT && trap[SIGINT] == NULL) {
11786 onint();
11787 return;
11788 }
11789 gotsig[signo - 1] = 1;
11790 pendingsigs++;
11791}
11792
11793
Eric Andersencb57d552001-06-28 07:25:16 +000011794/*
11795 * Called to execute a trap. Perhaps we should avoid entering new trap
11796 * handlers while we are executing a trap handler.
11797 */
11798
11799static void
Eric Andersen2870d962001-07-02 17:27:21 +000011800dotrap(void)
11801{
Eric Andersencb57d552001-06-28 07:25:16 +000011802 int i;
11803 int savestatus;
11804
11805 for (;;) {
11806 for (i = 1 ; ; i++) {
11807 if (gotsig[i - 1])
11808 break;
11809 if (i >= NSIG - 1)
11810 goto done;
11811 }
11812 gotsig[i - 1] = 0;
11813 savestatus=exitstatus;
11814 evalstring(trap[i], 0);
11815 exitstatus=savestatus;
11816 }
11817done:
11818 pendingsigs = 0;
11819}
11820
Eric Andersencb57d552001-06-28 07:25:16 +000011821/*
11822 * Called to exit the shell.
11823 */
11824
11825static void
Eric Andersen2870d962001-07-02 17:27:21 +000011826exitshell(int status)
Eric Andersencb57d552001-06-28 07:25:16 +000011827{
11828 struct jmploc loc1, loc2;
11829 char *p;
11830
11831 TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
11832 if (setjmp(loc1.loc)) {
11833 goto l1;
11834 }
11835 if (setjmp(loc2.loc)) {
11836 goto l2;
11837 }
11838 handler = &loc1;
11839 if ((p = trap[0]) != NULL && *p != '\0') {
11840 trap[0] = NULL;
11841 evalstring(p, 0);
11842 }
Eric Andersen2870d962001-07-02 17:27:21 +000011843l1: handler = &loc2; /* probably unnecessary */
Eric Andersencb57d552001-06-28 07:25:16 +000011844 flushall();
Eric Andersend35c5df2002-01-09 15:37:36 +000011845#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +000011846 setjobctl(0);
11847#endif
11848l2: _exit(status);
11849 /* NOTREACHED */
11850}
11851
11852static int decode_signal(const char *string, int minsig)
11853{
11854 int signo;
Eric Andersen34506362001-08-02 05:02:46 +000011855 const char *name = u_signal_names(string, &signo, minsig);
Eric Andersencb57d552001-06-28 07:25:16 +000011856
Eric Andersen34506362001-08-02 05:02:46 +000011857 return name ? signo : -1;
Eric Andersencb57d552001-06-28 07:25:16 +000011858}
Eric Andersen34506362001-08-02 05:02:46 +000011859
Eric Andersen2870d962001-07-02 17:27:21 +000011860static struct var **hashvar (const char *);
11861static void showvars (const char *, int, int);
11862static struct var **findvar (struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011863
11864/*
11865 * Initialize the varable symbol tables and import the environment
11866 */
11867
Eric Andersencb57d552001-06-28 07:25:16 +000011868/*
11869 * This routine initializes the builtin variables. It is called when the
11870 * shell is initialized and again when a shell procedure is spawned.
11871 */
11872
11873static void
11874initvar() {
11875 const struct varinit *ip;
11876 struct var *vp;
11877 struct var **vpp;
11878
11879 for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
11880 if ((vp->flags & VEXPORT) == 0) {
11881 vpp = hashvar(ip->text);
11882 vp->next = *vpp;
11883 *vpp = vp;
Matt Kraaic8227632001-11-12 16:57:27 +000011884 vp->text = xstrdup(ip->text);
Eric Andersencb57d552001-06-28 07:25:16 +000011885 vp->flags = ip->flags;
11886 vp->func = ip->func;
11887 }
11888 }
Tim Riker497a8852002-04-13 05:37:10 +000011889#if !defined(CONFIG_FEATURE_COMMAND_EDITING) || !defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
Eric Andersencb57d552001-06-28 07:25:16 +000011890 /*
11891 * PS1 depends on uid
11892 */
11893 if ((vps1.flags & VEXPORT) == 0) {
Aaron Lehmann9a218bf2001-12-31 06:13:38 +000011894 vpp = hashvar("PS1=$");
Eric Andersencb57d552001-06-28 07:25:16 +000011895 vps1.next = *vpp;
11896 *vpp = &vps1;
Matt Kraaic8227632001-11-12 16:57:27 +000011897 vps1.text = xstrdup(geteuid() ? "PS1=$ " : "PS1=# ");
Eric Andersencb57d552001-06-28 07:25:16 +000011898 vps1.flags = VSTRFIXED|VTEXTFIXED;
11899 }
Tim Riker497a8852002-04-13 05:37:10 +000011900#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011901}
11902
11903/*
11904 * Set the value of a variable. The flags argument is ored with the
11905 * flags of the variable. If val is NULL, the variable is unset.
11906 */
11907
11908static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011909setvar(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011910{
11911 const char *p;
11912 int len;
11913 int namelen;
11914 char *nameeq;
11915 int isbad;
11916 int vallen = 0;
11917
11918 isbad = 0;
11919 p = name;
11920 if (! is_name(*p))
11921 isbad = 1;
11922 p++;
11923 for (;;) {
11924 if (! is_in_name(*p)) {
11925 if (*p == '\0' || *p == '=')
11926 break;
11927 isbad = 1;
11928 }
11929 p++;
11930 }
11931 namelen = p - name;
11932 if (isbad)
11933 error("%.*s: bad variable name", namelen, name);
Eric Andersen2870d962001-07-02 17:27:21 +000011934 len = namelen + 2; /* 2 is space for '=' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +000011935 if (val == NULL) {
11936 flags |= VUNSET;
11937 } else {
11938 len += vallen = strlen(val);
11939 }
11940 INTOFF;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011941 nameeq = xmalloc(len);
Eric Andersencb57d552001-06-28 07:25:16 +000011942 memcpy(nameeq, name, namelen);
11943 nameeq[namelen] = '=';
11944 if (val) {
11945 memcpy(nameeq + namelen + 1, val, vallen + 1);
11946 } else {
11947 nameeq[namelen + 1] = '\0';
11948 }
11949 setvareq(nameeq, flags);
11950 INTON;
11951}
11952
11953
11954
11955/*
11956 * Same as setvar except that the variable and value are passed in
11957 * the first argument as name=value. Since the first argument will
11958 * be actually stored in the table, it should not be a string that
11959 * will go away.
11960 */
11961
11962static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011963setvareq(char *s, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011964{
11965 struct var *vp, **vpp;
11966
11967 vpp = hashvar(s);
11968 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
11969 if ((vp = *findvar(vpp, s))) {
11970 if (vp->flags & VREADONLY) {
11971 size_t len = strchr(s, '=') - s;
11972 error("%.*s: is read only", len, s);
11973 }
11974 INTOFF;
11975
11976 if (vp->func && (flags & VNOFUNC) == 0)
11977 (*vp->func)(strchr(s, '=') + 1);
11978
11979 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Aaron Lehmann49c024a2002-08-02 06:39:47 +000011980 free(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000011981
11982 vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
11983 vp->flags |= flags;
11984 vp->text = s;
11985
Eric Andersend35c5df2002-01-09 15:37:36 +000011986#ifdef CONFIG_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000011987 /*
11988 * We could roll this to a function, to handle it as
11989 * a regular variable function callback, but why bother?
11990 */
11991 if (iflag && (vp == &vmpath || (vp == &vmail && !mpathset())))
11992 chkmail(1);
Eric Andersenec074692001-10-31 11:05:49 +000011993#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011994 INTON;
11995 return;
11996 }
11997 /* not found */
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011998 vp = xmalloc(sizeof (*vp));
Eric Andersencb57d552001-06-28 07:25:16 +000011999 vp->flags = flags;
12000 vp->text = s;
12001 vp->next = *vpp;
12002 vp->func = NULL;
12003 *vpp = vp;
12004}
12005
12006
12007
12008/*
12009 * Process a linked list of variable assignments.
12010 */
12011
12012static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012013listsetvar(struct strlist *mylist)
12014{
Eric Andersencb57d552001-06-28 07:25:16 +000012015 struct strlist *lp;
12016
12017 INTOFF;
12018 for (lp = mylist ; lp ; lp = lp->next) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012019 setvareq(xstrdup(lp->text), 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012020 }
12021 INTON;
12022}
12023
12024
12025
12026/*
12027 * Find the value of a variable. Returns NULL if not set.
12028 */
12029
Eric Andersen62483552001-07-10 06:09:16 +000012030static const char *
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012031lookupvar(const char *name)
Eric Andersenec074692001-10-31 11:05:49 +000012032{
Eric Andersencb57d552001-06-28 07:25:16 +000012033 struct var *v;
12034
12035 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
12036 return strchr(v->text, '=') + 1;
12037 }
12038 return NULL;
12039}
12040
12041
12042
12043/*
12044 * Search the environment of a builtin command.
12045 */
12046
Eric Andersen62483552001-07-10 06:09:16 +000012047static const char *
12048bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012049{
Eric Andersen62483552001-07-10 06:09:16 +000012050 const struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012051
12052 for (sp = cmdenviron ; sp ; sp = sp->next) {
12053 if (varequal(sp->text, name))
12054 return strchr(sp->text, '=') + 1;
12055 }
12056 return lookupvar(name);
12057}
12058
12059
12060
12061/*
12062 * Generate a list of exported variables. This routine is used to construct
12063 * the third argument to execve when executing a program.
12064 */
12065
12066static char **
12067environment() {
12068 int nenv;
12069 struct var **vpp;
12070 struct var *vp;
12071 char **env;
12072 char **ep;
12073
12074 nenv = 0;
12075 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12076 for (vp = *vpp ; vp ; vp = vp->next)
12077 if (vp->flags & VEXPORT)
12078 nenv++;
12079 }
12080 ep = env = stalloc((nenv + 1) * sizeof *env);
12081 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12082 for (vp = *vpp ; vp ; vp = vp->next)
12083 if (vp->flags & VEXPORT)
12084 *ep++ = vp->text;
12085 }
12086 *ep = NULL;
12087 return env;
12088}
12089
12090
12091/*
12092 * Called when a shell procedure is invoked to clear out nonexported
12093 * variables. It is also necessary to reallocate variables of with
12094 * VSTACK set since these are currently allocated on the stack.
12095 */
12096
Eric Andersencb57d552001-06-28 07:25:16 +000012097static void
Eric Andersen2870d962001-07-02 17:27:21 +000012098shprocvar(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000012099 struct var **vpp;
12100 struct var *vp, **prev;
12101
12102 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12103 for (prev = vpp ; (vp = *prev) != NULL ; ) {
12104 if ((vp->flags & VEXPORT) == 0) {
12105 *prev = vp->next;
12106 if ((vp->flags & VTEXTFIXED) == 0)
Aaron Lehmann49c024a2002-08-02 06:39:47 +000012107 free(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012108 if ((vp->flags & VSTRFIXED) == 0)
Aaron Lehmann49c024a2002-08-02 06:39:47 +000012109 free(vp);
Eric Andersencb57d552001-06-28 07:25:16 +000012110 } else {
12111 if (vp->flags & VSTACK) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012112 vp->text = xstrdup(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012113 vp->flags &=~ VSTACK;
12114 }
12115 prev = &vp->next;
12116 }
12117 }
12118 }
12119 initvar();
12120}
12121
12122
12123
12124/*
12125 * Command to list all variables which are set. Currently this command
12126 * is invoked from the set command when the set command is called without
12127 * any variables.
12128 */
12129
12130static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012131showvarscmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012132{
12133 showvars(nullstr, VUNSET, VUNSET);
12134 return 0;
12135}
12136
12137
12138
12139/*
12140 * The export and readonly commands.
12141 */
12142
12143static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012144exportcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012145{
12146 struct var *vp;
12147 char *name;
12148 const char *p;
12149 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12150 int pflag;
12151
12152 listsetvar(cmdenviron);
12153 pflag = (nextopt("p") == 'p');
12154 if (argc > 1 && !pflag) {
12155 while ((name = *argptr++) != NULL) {
12156 if ((p = strchr(name, '=')) != NULL) {
12157 p++;
12158 } else {
12159 if ((vp = *findvar(hashvar(name), name))) {
12160 vp->flags |= flag;
12161 goto found;
12162 }
12163 }
12164 setvar(name, p, flag);
12165found:;
12166 }
12167 } else {
12168 showvars(argv[0], flag, 0);
12169 }
12170 return 0;
12171}
12172
Eric Andersen34506362001-08-02 05:02:46 +000012173
Eric Andersencb57d552001-06-28 07:25:16 +000012174/*
12175 * The "local" command.
12176 */
12177
Eric Andersen2870d962001-07-02 17:27:21 +000012178/* funcnest nonzero if we are currently evaluating a function */
12179
Eric Andersencb57d552001-06-28 07:25:16 +000012180static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012181localcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012182{
12183 char *name;
12184
Eric Andersen2870d962001-07-02 17:27:21 +000012185 if (! funcnest)
Eric Andersencb57d552001-06-28 07:25:16 +000012186 error("Not in a function");
12187 while ((name = *argptr++) != NULL) {
12188 mklocal(name);
12189 }
12190 return 0;
12191}
12192
12193
12194/*
12195 * Make a variable a local variable. When a variable is made local, it's
12196 * value and flags are saved in a localvar structure. The saved values
12197 * will be restored when the shell function returns. We handle the name
12198 * "-" as a special case.
12199 */
12200
12201static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012202mklocal(char *name)
12203{
Eric Andersencb57d552001-06-28 07:25:16 +000012204 struct localvar *lvp;
12205 struct var **vpp;
12206 struct var *vp;
12207
12208 INTOFF;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012209 lvp = xmalloc(sizeof (struct localvar));
Eric Andersencb57d552001-06-28 07:25:16 +000012210 if (name[0] == '-' && name[1] == '\0') {
12211 char *p;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012212 p = xmalloc(sizeof optet_vals);
Eric Andersen2870d962001-07-02 17:27:21 +000012213 lvp->text = memcpy(p, optet_vals, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000012214 vp = NULL;
12215 } else {
12216 vpp = hashvar(name);
12217 vp = *findvar(vpp, name);
12218 if (vp == NULL) {
12219 if (strchr(name, '='))
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012220 setvareq(xstrdup(name), VSTRFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +000012221 else
12222 setvar(name, NULL, VSTRFIXED);
Eric Andersen2870d962001-07-02 17:27:21 +000012223 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012224 lvp->text = NULL;
12225 lvp->flags = VUNSET;
12226 } else {
12227 lvp->text = vp->text;
12228 lvp->flags = vp->flags;
12229 vp->flags |= VSTRFIXED|VTEXTFIXED;
12230 if (strchr(name, '='))
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012231 setvareq(xstrdup(name), 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012232 }
12233 }
12234 lvp->vp = vp;
12235 lvp->next = localvars;
12236 localvars = lvp;
12237 INTON;
12238}
12239
12240
12241/*
12242 * Called after a function returns.
12243 */
12244
12245static void
12246poplocalvars() {
12247 struct localvar *lvp;
12248 struct var *vp;
12249
12250 while ((lvp = localvars) != NULL) {
12251 localvars = lvp->next;
12252 vp = lvp->vp;
Eric Andersen2870d962001-07-02 17:27:21 +000012253 if (vp == NULL) { /* $- saved */
12254 memcpy(optet_vals, lvp->text, sizeof optet_vals);
Aaron Lehmann49c024a2002-08-02 06:39:47 +000012255 free(lvp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012256 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12257 (void)unsetvar(vp->text);
12258 } else {
12259 if ((vp->flags & VTEXTFIXED) == 0)
Aaron Lehmann49c024a2002-08-02 06:39:47 +000012260 free(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012261 vp->flags = lvp->flags;
12262 vp->text = lvp->text;
12263 }
Aaron Lehmann49c024a2002-08-02 06:39:47 +000012264 free(lvp);
Eric Andersencb57d552001-06-28 07:25:16 +000012265 }
12266}
12267
12268
12269static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012270setvarcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012271{
12272 if (argc <= 2)
12273 return unsetcmd(argc, argv);
12274 else if (argc == 3)
12275 setvar(argv[1], argv[2], 0);
12276 else
12277 error("List assignment not implemented");
12278 return 0;
12279}
12280
12281
12282/*
12283 * The unset builtin command. We unset the function before we unset the
12284 * variable to allow a function to be unset when there is a readonly variable
12285 * with the same name.
12286 */
12287
12288static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012289unsetcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012290{
12291 char **ap;
12292 int i;
12293 int flg_func = 0;
12294 int flg_var = 0;
12295 int ret = 0;
12296
12297 while ((i = nextopt("vf")) != '\0') {
12298 if (i == 'f')
12299 flg_func = 1;
12300 else
12301 flg_var = 1;
12302 }
12303 if (flg_func == 0 && flg_var == 0)
12304 flg_var = 1;
12305
12306 for (ap = argptr; *ap ; ap++) {
12307 if (flg_func)
12308 unsetfunc(*ap);
12309 if (flg_var)
12310 ret |= unsetvar(*ap);
12311 }
12312 return ret;
12313}
12314
12315
12316/*
12317 * Unset the specified variable.
12318 */
12319
12320static int
Eric Andersen62483552001-07-10 06:09:16 +000012321unsetvar(const char *s)
12322{
Eric Andersencb57d552001-06-28 07:25:16 +000012323 struct var **vpp;
12324 struct var *vp;
12325
12326 vpp = findvar(hashvar(s), s);
12327 vp = *vpp;
12328 if (vp) {
12329 if (vp->flags & VREADONLY)
12330 return (1);
12331 INTOFF;
12332 if (*(strchr(vp->text, '=') + 1) != '\0')
12333 setvar(s, nullstr, 0);
12334 vp->flags &= ~VEXPORT;
12335 vp->flags |= VUNSET;
12336 if ((vp->flags & VSTRFIXED) == 0) {
12337 if ((vp->flags & VTEXTFIXED) == 0)
Aaron Lehmann49c024a2002-08-02 06:39:47 +000012338 free(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012339 *vpp = vp->next;
Aaron Lehmann49c024a2002-08-02 06:39:47 +000012340 free(vp);
Eric Andersencb57d552001-06-28 07:25:16 +000012341 }
12342 INTON;
12343 return (0);
12344 }
12345
12346 return (0);
12347}
12348
12349
12350
12351/*
12352 * Find the appropriate entry in the hash table from the name.
12353 */
12354
12355static struct var **
Eric Andersen62483552001-07-10 06:09:16 +000012356hashvar(const char *p)
12357{
Eric Andersencb57d552001-06-28 07:25:16 +000012358 unsigned int hashval;
12359
12360 hashval = ((unsigned char) *p) << 4;
12361 while (*p && *p != '=')
12362 hashval += (unsigned char) *p++;
12363 return &vartab[hashval % VTABSIZE];
12364}
12365
12366
12367
12368/*
12369 * Returns true if the two strings specify the same varable. The first
12370 * variable name is terminated by '='; the second may be terminated by
12371 * either '=' or '\0'.
12372 */
12373
12374static int
Eric Andersen62483552001-07-10 06:09:16 +000012375varequal(const char *p, const char *q)
12376{
Eric Andersencb57d552001-06-28 07:25:16 +000012377 while (*p == *q++) {
12378 if (*p++ == '=')
12379 return 1;
12380 }
12381 if (*p == '=' && *(q - 1) == '\0')
12382 return 1;
12383 return 0;
12384}
12385
12386static void
12387showvars(const char *myprefix, int mask, int xor)
12388{
12389 struct var **vpp;
12390 struct var *vp;
12391 const char *sep = myprefix == nullstr ? myprefix : spcstr;
12392
12393 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12394 for (vp = *vpp ; vp ; vp = vp->next) {
12395 if ((vp->flags & mask) ^ xor) {
12396 char *p;
12397 int len;
12398
12399 p = strchr(vp->text, '=') + 1;
12400 len = p - vp->text;
12401 p = single_quote(p);
12402
Eric Andersen62483552001-07-10 06:09:16 +000012403 printf("%s%s%.*s%s\n", myprefix, sep, len,
12404 vp->text, p);
Eric Andersencb57d552001-06-28 07:25:16 +000012405 stunalloc(p);
12406 }
12407 }
12408 }
12409}
12410
12411static struct var **
12412findvar(struct var **vpp, const char *name)
12413{
12414 for (; *vpp; vpp = &(*vpp)->next) {
12415 if (varequal((*vpp)->text, name)) {
12416 break;
12417 }
12418 }
12419 return vpp;
12420}
12421
12422/*
12423 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
12424 * This file contains code for the times builtin.
Aaron Lehmann49c024a2002-08-02 06:39:47 +000012425 * $Id: ash.c,v 1.56 2002/08/02 06:39:47 aaronl Exp $
Eric Andersencb57d552001-06-28 07:25:16 +000012426 */
12427static int timescmd (int argc, char **argv)
12428{
12429 struct tms buf;
12430 long int clk_tck = sysconf(_SC_CLK_TCK);
12431
12432 times(&buf);
12433 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
12434 (int) (buf.tms_utime / clk_tck / 60),
12435 ((double) buf.tms_utime) / clk_tck,
12436 (int) (buf.tms_stime / clk_tck / 60),
12437 ((double) buf.tms_stime) / clk_tck,
12438 (int) (buf.tms_cutime / clk_tck / 60),
12439 ((double) buf.tms_cutime) / clk_tck,
12440 (int) (buf.tms_cstime / clk_tck / 60),
12441 ((double) buf.tms_cstime) / clk_tck);
12442 return 0;
12443}
12444
Eric Andersend35c5df2002-01-09 15:37:36 +000012445#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012446/* The let builtin. */
12447int letcmd(int argc, char **argv)
Eric Andersen74bcd162001-07-30 21:41:37 +000012448{
Eric Andersen34506362001-08-02 05:02:46 +000012449 int errcode;
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012450 long result=0;
12451 if (argc == 2) {
12452 char *tmp, *expression, p[13];
12453 expression = strchr(argv[1], '=');
12454 if (!expression) {
Eric Andersen34506362001-08-02 05:02:46 +000012455 /* Cannot use 'error()' here, or the return code
12456 * will be incorrect */
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012457 out2fmt("sh: let: syntax error: \"%s\"\n", argv[1]);
12458 return 0;
Eric Andersen74bcd162001-07-30 21:41:37 +000012459 }
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012460 *expression = '\0';
12461 tmp = ++expression;
Eric Andersen34506362001-08-02 05:02:46 +000012462 result = arith(tmp, &errcode);
12463 if (errcode < 0) {
12464 /* Cannot use 'error()' here, or the return code
12465 * will be incorrect */
12466 out2fmt("sh: let: ");
12467 if(errcode == -2)
12468 out2fmt("divide by zero");
12469 else
12470 out2fmt("syntax error: \"%s=%s\"\n", argv[1], expression);
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012471 return 0;
12472 }
12473 snprintf(p, 12, "%ld", result);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012474 setvar(argv[1], xstrdup(p), 0);
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012475 } else if (argc >= 3)
12476 synerror("invalid operand");
12477 return !result;
Eric Andersen74bcd162001-07-30 21:41:37 +000012478}
12479#endif
12480
12481
12482
Eric Andersendf82f612001-06-28 07:46:40 +000012483/*-
12484 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000012485 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000012486 *
12487 * This code is derived from software contributed to Berkeley by
12488 * Kenneth Almquist.
12489 *
12490 * Redistribution and use in source and binary forms, with or without
12491 * modification, are permitted provided that the following conditions
12492 * are met:
12493 * 1. Redistributions of source code must retain the above copyright
12494 * notice, this list of conditions and the following disclaimer.
12495 * 2. Redistributions in binary form must reproduce the above copyright
12496 * notice, this list of conditions and the following disclaimer in the
12497 * documentation and/or other materials provided with the distribution.
12498 *
Eric Andersen2870d962001-07-02 17:27:21 +000012499 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
12500 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000012501 *
12502 * 4. Neither the name of the University nor the names of its contributors
12503 * may be used to endorse or promote products derived from this software
12504 * without specific prior written permission.
12505 *
12506 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
12507 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
12508 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
12509 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
12510 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
12511 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
12512 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
12513 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
12514 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
12515 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
12516 * SUCH DAMAGE.
12517 */