blob: a4c41564367d48b9b95e7699f68c2f08621b811c [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>
Eric Andersen1a10eec2001-10-24 17:19:38 +000071#include "pwd.h"
Eric Andersencb57d552001-06-28 07:25:16 +000072
73
74#if !defined(FNMATCH_BROKEN)
75#include <fnmatch.h>
76#endif
77#if !defined(GLOB_BROKEN)
78#include <glob.h>
79#endif
80
Eric Andersend35c5df2002-01-09 15:37:36 +000081#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +000082#include <termios.h>
Eric Andersencb57d552001-06-28 07:25:16 +000083#endif
84
Eric Andersencb57d552001-06-28 07:25:16 +000085#include "busybox.h"
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
311#define ckfree(p) free((pointer)(p))
312
Eric Andersen2870d962001-07-02 17:27:21 +0000313
314#ifdef DEBUG
315#define TRACE(param) trace param
Eric Andersen69a20f02001-10-31 10:40:37 +0000316typedef union node unode;
Eric Andersen2870d962001-07-02 17:27:21 +0000317static void trace (const char *, ...);
318static void trargs (char **);
Eric Andersen69a20f02001-10-31 10:40:37 +0000319static void showtree (unode *);
Eric Andersen2870d962001-07-02 17:27:21 +0000320static void trputc (int);
321static void trputs (const char *);
322static void opentrace (void);
323#else
324#define TRACE(param)
325#endif
326
327#define NSEMI 0
328#define NCMD 1
329#define NPIPE 2
330#define NREDIR 3
331#define NBACKGND 4
332#define NSUBSHELL 5
333#define NAND 6
334#define NOR 7
335#define NIF 8
336#define NWHILE 9
337#define NUNTIL 10
338#define NFOR 11
339#define NCASE 12
340#define NCLIST 13
341#define NDEFUN 14
342#define NARG 15
343#define NTO 16
344#define NFROM 17
345#define NFROMTO 18
346#define NAPPEND 19
347#define NTOOV 20
348#define NTOFD 21
349#define NFROMFD 22
350#define NHERE 23
351#define NXHERE 24
352#define NNOT 25
353
354/*
355 * expandarg() flags
356 */
357#define EXP_FULL 0x1 /* perform word splitting & file globbing */
358#define EXP_TILDE 0x2 /* do normal tilde expansion */
359#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
360#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
361#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
362#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
363
364
365#define NOPTS 16
366
367static char optet_vals[NOPTS];
368
369static const char * const optlist[NOPTS] = {
370 "e" "errexit",
371 "f" "noglob",
372 "I" "ignoreeof",
373 "i" "interactive",
374 "m" "monitor",
375 "n" "noexec",
376 "s" "stdin",
377 "x" "xtrace",
378 "v" "verbose",
379 "V" "vi",
380 "E" "emacs",
381 "C" "noclobber",
382 "a" "allexport",
383 "b" "notify",
384 "u" "nounset",
385 "q" "quietprofile"
386};
387
388#define optent_name(optent) (optent+1)
389#define optent_letter(optent) optent[0]
390#define optent_val(optent) optet_vals[optent]
391
392#define eflag optent_val(0)
393#define fflag optent_val(1)
394#define Iflag optent_val(2)
395#define iflag optent_val(3)
396#define mflag optent_val(4)
397#define nflag optent_val(5)
398#define sflag optent_val(6)
399#define xflag optent_val(7)
400#define vflag optent_val(8)
401#define Vflag optent_val(9)
402#define Eflag optent_val(10)
403#define Cflag optent_val(11)
404#define aflag optent_val(12)
405#define bflag optent_val(13)
406#define uflag optent_val(14)
407#define qflag optent_val(15)
408
409
410/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
411#define FORK_FG 0
412#define FORK_BG 1
413#define FORK_NOJOB 2
414
415
416struct nbinary {
417 int type;
418 union node *ch1;
419 union node *ch2;
420};
421
422
423struct ncmd {
424 int type;
425 int backgnd;
426 union node *assign;
427 union node *args;
428 union node *redirect;
429};
430
431
432struct npipe {
433 int type;
434 int backgnd;
435 struct nodelist *cmdlist;
436};
437
438
439struct nredir {
440 int type;
441 union node *n;
442 union node *redirect;
443};
444
445
446struct nif {
447 int type;
448 union node *test;
449 union node *ifpart;
450 union node *elsepart;
451};
452
453
454struct nfor {
455 int type;
456 union node *args;
457 union node *body;
458 char *var;
459};
460
461
462struct ncase {
463 int type;
464 union node *expr;
465 union node *cases;
466};
467
468
469struct nclist {
470 int type;
471 union node *next;
472 union node *pattern;
473 union node *body;
474};
475
476
477struct narg {
478 int type;
479 union node *next;
480 char *text;
481 struct nodelist *backquote;
482};
483
484
485struct nfile {
486 int type;
487 union node *next;
488 int fd;
489 union node *fname;
490 char *expfname;
491};
492
493
494struct ndup {
495 int type;
496 union node *next;
497 int fd;
498 int dupfd;
499 union node *vname;
500};
501
502
503struct nhere {
504 int type;
505 union node *next;
506 int fd;
507 union node *doc;
508};
509
510
511struct nnot {
512 int type;
513 union node *com;
514};
515
516
517union node {
518 int type;
519 struct nbinary nbinary;
520 struct ncmd ncmd;
521 struct npipe npipe;
522 struct nredir nredir;
523 struct nif nif;
524 struct nfor nfor;
525 struct ncase ncase;
526 struct nclist nclist;
527 struct narg narg;
528 struct nfile nfile;
529 struct ndup ndup;
530 struct nhere nhere;
531 struct nnot nnot;
532};
533
534
535struct nodelist {
536 struct nodelist *next;
537 union node *n;
538};
539
540struct backcmd { /* result of evalbackcmd */
541 int fd; /* file descriptor to read from */
542 char *buf; /* buffer */
543 int nleft; /* number of chars in buffer */
544 struct job *jp; /* job structure for command */
545};
546
547struct cmdentry {
548 int cmdtype;
549 union param {
550 int index;
551 union node *func;
552 const struct builtincmd *cmd;
553 } u;
554};
555
556struct strlist {
557 struct strlist *next;
558 char *text;
559};
560
561
562struct arglist {
563 struct strlist *list;
564 struct strlist **lastp;
565};
566
567struct strpush {
568 struct strpush *prev; /* preceding string on stack */
569 char *prevstring;
570 int prevnleft;
Eric Andersend35c5df2002-01-09 15:37:36 +0000571#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +0000572 struct alias *ap; /* if push was associated with an alias */
573#endif
574 char *string; /* remember the string since it may change */
575};
576
577struct parsefile {
578 struct parsefile *prev; /* preceding file on stack */
579 int linno; /* current line */
580 int fd; /* file descriptor (or -1 if string) */
581 int nleft; /* number of chars left in this line */
582 int lleft; /* number of chars left in this buffer */
583 char *nextc; /* next char in buffer */
584 char *buf; /* input buffer */
585 struct strpush *strpush; /* for pushing strings at this level */
586 struct strpush basestrpush; /* so pushing one is fast */
587};
588
589struct stackmark {
590 struct stack_block *stackp;
591 char *stacknxt;
592 int stacknleft;
593 struct stackmark *marknext;
594};
595
596struct shparam {
597 int nparam; /* # of positional parameters (without $0) */
598 unsigned char malloc; /* if parameter list dynamically allocated */
599 char **p; /* parameter list */
600 int optind; /* next parameter to be processed by getopts */
601 int optoff; /* used by getopts */
602};
603
Eric Andersen62483552001-07-10 06:09:16 +0000604/*
605 * When commands are first encountered, they are entered in a hash table.
606 * This ensures that a full path search will not have to be done for them
607 * on each invocation.
608 *
609 * We should investigate converting to a linear search, even though that
610 * would make the command name "hash" a misnomer.
611 */
612#define CMDTABLESIZE 31 /* should be prime */
613#define ARB 1 /* actual size determined at run time */
614
615
616
617struct tblentry {
618 struct tblentry *next; /* next entry in hash chain */
619 union param param; /* definition of builtin function */
620 short cmdtype; /* index identifying command */
621 char rehash; /* if set, cd done since entry created */
622 char cmdname[ARB]; /* name of command */
623};
624
625
626static struct tblentry *cmdtable[CMDTABLESIZE];
627static int builtinloc = -1; /* index in path of %builtin, or -1 */
628static int exerrno = 0; /* Last exec error */
629
630
631static void tryexec (char *, char **, char **);
632static void printentry (struct tblentry *, int);
633static void clearcmdentry (int);
634static struct tblentry *cmdlookup (const char *, int);
635static void delete_cmd_entry (void);
636static int path_change (const char *, int *);
637
638
Eric Andersen2870d962001-07-02 17:27:21 +0000639static void flushall (void);
Eric Andersen3102ac42001-07-06 04:26:23 +0000640static void out2fmt (const char *, ...)
641 __attribute__((__format__(__printf__,1,2)));
Eric Andersen2870d962001-07-02 17:27:21 +0000642static int xwrite (int, const char *, int);
Eric Andersen2870d962001-07-02 17:27:21 +0000643
Manuel Novoa III c639a352001-08-12 17:32:56 +0000644static inline void outstr (const char *p, FILE *file) { fputs(p, file); }
Eric Andersen3102ac42001-07-06 04:26:23 +0000645static void out1str(const char *p) { outstr(p, stdout); }
646static void out2str(const char *p) { outstr(p, stderr); }
Eric Andersen2870d962001-07-02 17:27:21 +0000647
Eric Andersend35c5df2002-01-09 15:37:36 +0000648#ifndef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Eric Andersen3102ac42001-07-06 04:26:23 +0000649#define out2c(c) putc((c), stderr)
Eric Andersen62483552001-07-10 06:09:16 +0000650#else
651static void out2c(int c) { putc(c, stderr); }
652#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000653
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000654
Eric Andersend35c5df2002-01-09 15:37:36 +0000655#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000656#define USE_SIT_FUNCTION
657#endif
658
659/* number syntax index */
660#define BASESYNTAX 0 /* not in quotes */
661#define DQSYNTAX 1 /* in double quotes */
662#define SQSYNTAX 2 /* in single quotes */
663#define ARISYNTAX 3 /* in arithmetic */
664
665static const char S_I_T[][4] = {
666 /* 0 */ { CSPCL, CIGN, CIGN, CIGN }, /* PEOA */
667 /* 1 */ { CSPCL, CWORD, CWORD, CWORD }, /* ' ' */
668 /* 2 */ { CNL, CNL, CNL, CNL }, /* \n */
669 /* 3 */ { CWORD, CCTL, CCTL, CWORD }, /* !*-/:=?[]~ */
670 /* 4 */ { CDQUOTE, CENDQUOTE, CWORD, CDQUOTE }, /* '"' */
671 /* 5 */ { CVAR, CVAR, CWORD, CVAR }, /* $ */
672 /* 6 */ { CSQUOTE, CWORD, CENDQUOTE, CSQUOTE }, /* "'" */
673 /* 7 */ { CSPCL, CWORD, CWORD, CLP }, /* ( */
674 /* 8 */ { CSPCL, CWORD, CWORD, CRP }, /* ) */
675 /* 9 */ { CBACK, CBACK, CCTL, CBACK }, /* \ */
676 /* 10 */ { CBQUOTE, CBQUOTE, CWORD, CBQUOTE }, /* ` */
677 /* 11 */ { CENDVAR, CENDVAR, CWORD, CENDVAR }, /* } */
678#ifndef USE_SIT_FUNCTION
679 /* 12 */ { CENDFILE, CENDFILE, CENDFILE, CENDFILE }, /* PEOF */
680 /* 13 */ { CWORD, CWORD, CWORD, CWORD }, /* 0-9A-Za-z */
681 /* 14 */ { CCTL, CCTL, CCTL, CCTL } /* CTLESC ... */
682#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000683};
684
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000685#ifdef USE_SIT_FUNCTION
686
687#define U_C(c) ((unsigned char)(c))
688
689static int SIT(int c, int syntax)
690{
691 static const char spec_symbls[]="\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
692 static const char syntax_index_table [] = {
693 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
694 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
695 3, 1, 3, 3, 9, 3,10, 1, /* "=>?[\\]`|" */
696 11,3 }; /* "}~" */
697 const char *s;
698 int indx;
699
700 if(c==PEOF) /* 2^8+2 */
701 return CENDFILE;
702 if(c==PEOA) /* 2^8+1 */
703 indx = 0;
704 else if(U_C(c)>=U_C(CTLESC) && U_C(c)<=U_C(CTLQUOTEMARK))
705 return CCTL;
706 else {
707 s = strchr(spec_symbls, c);
708 if(s==0)
709 return CWORD;
710 indx = syntax_index_table[(s-spec_symbls)];
711 }
712 return S_I_T[indx][syntax];
713}
714
715#else /* USE_SIT_FUNCTION */
716
717#define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
718
719#define CSPCL_CIGN_CIGN_CIGN 0
720#define CSPCL_CWORD_CWORD_CWORD 1
721#define CNL_CNL_CNL_CNL 2
722#define CWORD_CCTL_CCTL_CWORD 3
723#define CDQUOTE_CENDQUOTE_CWORD_CDQUOTE 4
724#define CVAR_CVAR_CWORD_CVAR 5
725#define CSQUOTE_CWORD_CENDQUOTE_CSQUOTE 6
726#define CSPCL_CWORD_CWORD_CLP 7
727#define CSPCL_CWORD_CWORD_CRP 8
728#define CBACK_CBACK_CCTL_CBACK 9
729#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
730#define CENDVAR_CENDVAR_CWORD_CENDVAR 11
731#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
732#define CWORD_CWORD_CWORD_CWORD 13
733#define CCTL_CCTL_CCTL_CCTL 14
734
735static const char syntax_index_table[258] = {
736 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
737 /* 0 -130 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
738 /* 1 -129 PEOA */ CSPCL_CIGN_CIGN_CIGN,
739 /* 2 -128 0xff */ CWORD_CWORD_CWORD_CWORD,
740 /* 3 -127 */ CCTL_CCTL_CCTL_CCTL, /* CTLQUOTEMARK */
741 /* 4 -126 */ CCTL_CCTL_CCTL_CCTL,
742 /* 5 -125 */ CCTL_CCTL_CCTL_CCTL,
743 /* 6 -124 */ CCTL_CCTL_CCTL_CCTL,
744 /* 7 -123 */ CCTL_CCTL_CCTL_CCTL,
745 /* 8 -122 */ CCTL_CCTL_CCTL_CCTL,
746 /* 9 -121 */ CCTL_CCTL_CCTL_CCTL,
747 /* 10 -120 */ CCTL_CCTL_CCTL_CCTL, /* CTLESC */
748 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
749 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
750 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
751 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
752 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
753 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
754 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
755 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
756 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
757 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
758 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
759 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
760 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
761 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
762 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
763 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
764 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
765 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
766 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
767 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
768 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
769 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
770 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
771 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
772 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
773 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
774 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
775 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
776 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
777 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
778 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
779 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
780 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
781 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
782 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
783 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
784 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
785 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
786 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
787 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
788 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
789 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
790 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
791 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
792 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
793 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
794 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
795 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
796 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
797 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
798 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
799 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
800 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
801 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
802 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
803 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
804 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
805 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
806 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
807 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
808 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
809 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
810 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
811 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
812 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
813 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
814 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
815 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
816 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
817 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
818 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
819 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
820 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
821 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
822 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
823 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
824 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
825 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
826 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
827 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
828 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
829 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
830 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
831 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
832 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
833 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
834 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
835 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
836 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
837 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
838 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
839 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
840 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
841 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
842 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
843 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
844 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
845 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
846 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
847 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
848 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
849 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
850 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
851 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
852 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
853 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
854 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
855 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
856 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
857 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
858 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
859 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
860 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
861 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
862 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
863 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
864 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
865 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
866 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
867 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
868 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
869 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
870 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
871 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
872 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
873 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
874 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
875 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
876 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
877 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
878 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
879 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
880 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
881 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
882 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
883 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
884 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
885 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
886 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
887 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
888 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
889 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
890 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
891 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
892 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
893 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
894 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
895 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
896 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
897 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
898 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
899 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
900 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
901 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CDQUOTE,
902 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
903 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
904 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
905 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
906 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CSQUOTE,
907 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
908 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
909 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
910 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
911 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
912 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
913 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
914 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
915 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
916 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
917 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
918 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
919 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
920 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
921 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
922 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
923 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
924 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
925 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
926 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
927 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
928 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
929 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
930 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
931 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
932 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
933 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
934 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
935 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
936 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
937 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
938 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
939 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
940 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
941 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
942 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
943 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
944 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
945 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
946 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
947 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
948 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
949 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
950 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
951 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
952 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
953 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
954 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
955 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
956 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
957 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
958 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
959 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
960 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
961 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
962 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
963 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
964 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
965 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
966 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
967 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
968 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
969 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
970 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
971 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
972 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
973 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
974 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
975 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
976 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
977 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
978 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
979 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
980 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
981 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
982 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
983 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
984 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
985 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
986 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
987 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
988 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
989 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
990 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
991 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
992 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
993 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
994 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
Eric Andersen2870d962001-07-02 17:27:21 +0000995};
996
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000997#endif /* USE_SIT_FUNCTION */
Eric Andersen2870d962001-07-02 17:27:21 +0000998
Eric Andersen2870d962001-07-02 17:27:21 +0000999
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001000/* first char is indicating which tokens mark the end of a list */
1001static const char *const tokname_array[] = {
1002 "\1end of file",
1003 "\0newline",
1004 "\0redirection",
1005 "\0word",
1006 "\0assignment",
1007 "\0;",
1008 "\0&",
1009 "\0&&",
1010 "\0||",
1011 "\0|",
1012 "\0(",
1013 "\1)",
1014 "\1;;",
1015 "\1`",
Eric Andersen2870d962001-07-02 17:27:21 +00001016#define KWDOFFSET 14
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001017 /* the following are keywords */
1018 "\0!",
1019 "\0case",
1020 "\1do",
1021 "\1done",
1022 "\1elif",
1023 "\1else",
1024 "\1esac",
1025 "\1fi",
1026 "\0for",
1027 "\0if",
1028 "\0in",
1029 "\1then",
1030 "\0until",
1031 "\0while",
1032 "\0{",
1033 "\1}",
Eric Andersen2870d962001-07-02 17:27:21 +00001034};
1035
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001036static const char *tokname(int tok)
1037{
1038 static char buf[16];
1039
1040 if(tok>=TSEMI)
1041 buf[0] = '"';
1042 sprintf(buf+(tok>=TSEMI), "%s%c",
1043 tokname_array[tok]+1, (tok>=TSEMI ? '"' : 0));
1044 return buf;
1045}
Eric Andersen2870d962001-07-02 17:27:21 +00001046
1047static int plinno = 1; /* input line number */
1048
1049static int parselleft; /* copy of parsefile->lleft */
1050
1051static struct parsefile basepf; /* top level input file */
1052static char basebuf[BUFSIZ]; /* buffer for top level input file */
1053static struct parsefile *parsefile = &basepf; /* current input file */
1054
1055/*
1056 * NEOF is returned by parsecmd when it encounters an end of file. It
1057 * must be distinct from NULL, so we use the address of a variable that
1058 * happens to be handy.
1059 */
1060
1061static int tokpushback; /* last token pushed back */
1062#define NEOF ((union node *)&tokpushback)
1063static int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */
1064
1065
1066static void error (const char *, ...) __attribute__((__noreturn__));
1067static void exerror (int, const char *, ...) __attribute__((__noreturn__));
1068static void shellexec (char **, char **, const char *, int)
1069 __attribute__((noreturn));
1070static void exitshell (int) __attribute__((noreturn));
1071
1072static int goodname(const char *);
1073static void ignoresig (int);
1074static void onsig (int);
1075static void dotrap (void);
1076static int decode_signal (const char *, int);
1077
1078static void shprocvar(void);
1079static void deletefuncs(void);
1080static void setparam (char **);
1081static void freeparam (volatile struct shparam *);
1082
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001083static void find_command (const char *, struct cmdentry *, int, const char *);
1084
1085static inline void hashcd (void);
1086
Eric Andersen2870d962001-07-02 17:27:21 +00001087/* reasons for skipping commands (see comment on breakcmd routine) */
1088#define SKIPBREAK 1
1089#define SKIPCONT 2
1090#define SKIPFUNC 3
1091#define SKIPFILE 4
1092
1093/* values of cmdtype */
1094#define CMDUNKNOWN -1 /* no entry in table for command */
1095#define CMDNORMAL 0 /* command is an executable program */
1096#define CMDBUILTIN 1 /* command is a shell builtin */
1097#define CMDFUNCTION 2 /* command is a shell function */
1098
1099#define DO_ERR 1 /* find_command prints errors */
1100#define DO_ABS 2 /* find_command checks absolute paths */
1101#define DO_NOFUN 4 /* find_command ignores functions */
1102#define DO_BRUTE 8 /* find_command ignores hash table */
1103
1104/*
1105 * Shell variables.
1106 */
1107
1108/* flags */
1109#define VEXPORT 0x01 /* variable is exported */
1110#define VREADONLY 0x02 /* variable cannot be modified */
1111#define VSTRFIXED 0x04 /* variable struct is staticly allocated */
1112#define VTEXTFIXED 0x08 /* text is staticly allocated */
1113#define VSTACK 0x10 /* text is allocated on the stack */
1114#define VUNSET 0x20 /* the variable is not set */
1115#define VNOFUNC 0x40 /* don't call the callback function */
1116
1117
1118struct var {
1119 struct var *next; /* next entry in hash list */
1120 int flags; /* flags are defined above */
1121 char *text; /* name=value */
1122 void (*func) (const char *);
1123 /* function to be called when */
1124 /* the variable gets set/unset */
1125};
1126
1127struct localvar {
1128 struct localvar *next; /* next local variable in list */
1129 struct var *vp; /* the variable that was made local */
1130 int flags; /* saved flags */
1131 char *text; /* saved text */
1132};
1133
1134
Eric Andersen62483552001-07-10 06:09:16 +00001135#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00001136#define rmescapes(p) _rmescapes((p), 0)
1137static char *_rmescapes (char *, int);
1138#else
1139static void rmescapes (char *);
1140#endif
1141
1142static int casematch (union node *, const char *);
1143static void clearredir(void);
1144static void popstring(void);
1145static void readcmdfile (const char *);
1146
1147static int number (const char *);
1148static int is_number (const char *, int *num);
1149static char *single_quote (const char *);
1150static int nextopt (const char *);
1151
1152static void redirect (union node *, int);
1153static void popredir (void);
1154static int dup_as_newfd (int, int);
1155
1156static void changepath(const char *newval);
1157static void getoptsreset(const char *value);
1158
1159
1160static int parsenleft; /* copy of parsefile->nleft */
1161static char *parsenextc; /* copy of parsefile->nextc */
1162static int rootpid; /* pid of main shell */
1163static int rootshell; /* true if we aren't a child of the main shell */
1164
1165static const char spcstr[] = " ";
1166static const char snlfmt[] = "%s\n";
1167
1168static int sstrnleft;
1169static int herefd = -1;
1170
1171static struct localvar *localvars;
1172
1173static struct var vifs;
1174static struct var vmail;
1175static struct var vmpath;
1176static struct var vpath;
1177static struct var vps1;
1178static struct var vps2;
1179static struct var voptind;
Eric Andersenbdfd0d72001-10-24 05:00:29 +00001180#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00001181static struct var vlc_all;
1182static struct var vlc_ctype;
1183#endif
1184
1185struct varinit {
1186 struct var *var;
1187 int flags;
1188 const char *text;
1189 void (*func) (const char *);
1190};
1191
1192static const char defpathvar[] =
1193 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
1194#define defpath (defpathvar + 5)
1195
1196#ifdef IFS_BROKEN
1197static const char defifsvar[] = "IFS= \t\n";
1198#define defifs (defifsvar + 4)
1199#else
1200static const char defifs[] = " \t\n";
1201#endif
1202
1203static const struct varinit varinit[] = {
1204#ifdef IFS_BROKEN
1205 { &vifs, VSTRFIXED|VTEXTFIXED, defifsvar,
1206#else
1207 { &vifs, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS=",
1208#endif
1209 NULL },
1210 { &vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=",
1211 NULL },
1212 { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=",
1213 NULL },
1214 { &vpath, VSTRFIXED|VTEXTFIXED, defpathvar,
1215 changepath },
1216 /*
1217 * vps1 depends on uid
1218 */
1219 { &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)) {
1307 ckfree(ap->val);
1308 }
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;
1448 ckfree(ap->name);
1449 ckfree(ap->val);
1450 ckfree(ap);
1451 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/*
2174 * Free a parse tree.
2175 */
Eric Andersencb57d552001-06-28 07:25:16 +00002176
2177static void
Eric Andersen62483552001-07-10 06:09:16 +00002178freefunc(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00002179{
Eric Andersen62483552001-07-10 06:09:16 +00002180 if (n)
2181 ckfree(n);
Eric Andersencb57d552001-06-28 07:25:16 +00002182}
2183
2184
Eric Andersen62483552001-07-10 06:09:16 +00002185/*
2186 * Add a new command entry, replacing any existing command entry for
2187 * the same name.
2188 */
2189
2190static inline void
2191addcmdentry(char *name, struct cmdentry *entry)
2192{
2193 struct tblentry *cmdp;
2194
2195 INTOFF;
2196 cmdp = cmdlookup(name, 1);
2197 if (cmdp->cmdtype == CMDFUNCTION) {
2198 freefunc(cmdp->param.func);
2199 }
2200 cmdp->cmdtype = entry->cmdtype;
2201 cmdp->param = entry->u;
2202 INTON;
2203}
2204
2205static inline void
2206evalloop(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002207{
2208 int status;
2209
2210 loopnest++;
2211 status = 0;
2212 for (;;) {
2213 evaltree(n->nbinary.ch1, EV_TESTED);
2214 if (evalskip) {
Eric Andersen2870d962001-07-02 17:27:21 +00002215skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002216 evalskip = 0;
2217 continue;
2218 }
2219 if (evalskip == SKIPBREAK && --skipcount <= 0)
2220 evalskip = 0;
2221 break;
2222 }
2223 if (n->type == NWHILE) {
2224 if (exitstatus != 0)
2225 break;
2226 } else {
2227 if (exitstatus == 0)
2228 break;
2229 }
2230 evaltree(n->nbinary.ch2, flags & EV_TESTED);
2231 status = exitstatus;
2232 if (evalskip)
2233 goto skipping;
2234 }
2235 loopnest--;
2236 exitstatus = status;
2237}
2238
Eric Andersencb57d552001-06-28 07:25:16 +00002239static void
Eric Andersen62483552001-07-10 06:09:16 +00002240evalfor(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002241{
2242 struct arglist arglist;
2243 union node *argp;
2244 struct strlist *sp;
2245 struct stackmark smark;
2246
2247 setstackmark(&smark);
2248 arglist.lastp = &arglist.list;
2249 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2250 oexitstatus = exitstatus;
2251 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2252 if (evalskip)
2253 goto out;
2254 }
2255 *arglist.lastp = NULL;
2256
2257 exitstatus = 0;
2258 loopnest++;
2259 for (sp = arglist.list ; sp ; sp = sp->next) {
2260 setvar(n->nfor.var, sp->text, 0);
2261 evaltree(n->nfor.body, flags & EV_TESTED);
2262 if (evalskip) {
2263 if (evalskip == SKIPCONT && --skipcount <= 0) {
2264 evalskip = 0;
2265 continue;
2266 }
2267 if (evalskip == SKIPBREAK && --skipcount <= 0)
2268 evalskip = 0;
2269 break;
2270 }
2271 }
2272 loopnest--;
2273out:
2274 popstackmark(&smark);
2275}
2276
Eric Andersen62483552001-07-10 06:09:16 +00002277static inline void
2278evalcase(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002279{
2280 union node *cp;
2281 union node *patp;
2282 struct arglist arglist;
2283 struct stackmark smark;
2284
2285 setstackmark(&smark);
2286 arglist.lastp = &arglist.list;
2287 oexitstatus = exitstatus;
2288 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2289 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2290 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2291 if (casematch(patp, arglist.list->text)) {
2292 if (evalskip == 0) {
2293 evaltree(cp->nclist.body, flags);
2294 }
2295 goto out;
2296 }
2297 }
2298 }
2299out:
2300 popstackmark(&smark);
2301}
2302
Eric Andersencb57d552001-06-28 07:25:16 +00002303/*
Eric Andersencb57d552001-06-28 07:25:16 +00002304 * Evaluate a pipeline. All the processes in the pipeline are children
2305 * of the process creating the pipeline. (This differs from some versions
2306 * of the shell, which make the last process in a pipeline the parent
2307 * of all the rest.)
2308 */
2309
Eric Andersen74400cc2001-10-18 04:11:39 +00002310static inline void evalpipe(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00002311{
2312 struct job *jp;
2313 struct nodelist *lp;
2314 int pipelen;
2315 int prevfd;
2316 int pip[2];
2317
2318 TRACE(("evalpipe(0x%lx) called\n", (long)n));
2319 pipelen = 0;
2320 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
2321 pipelen++;
2322 INTOFF;
2323 jp = makejob(n, pipelen);
2324 prevfd = -1;
2325 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00002326 /*
2327 * Search for a command. This is called before we fork so that the
2328 * location of the command will be available in the parent as well as
2329 * the child. The check for "goodname" is an overly conservative
2330 * check that the name will not be subject to expansion.
2331 */
2332
2333 struct cmdentry entry;
2334 union node *lpn = lp->n;
2335 if (lpn->type == NCMD && lpn->ncmd.args && goodname(lpn->ncmd.args->narg.text))
2336 find_command(lpn->ncmd.args->narg.text, &entry, 0, pathval());
2337
Eric Andersencb57d552001-06-28 07:25:16 +00002338 pip[1] = -1;
2339 if (lp->next) {
2340 if (pipe(pip) < 0) {
2341 close(prevfd);
2342 error("Pipe call failed");
2343 }
2344 }
2345 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
2346 INTON;
2347 if (prevfd > 0) {
2348 close(0);
2349 dup_as_newfd(prevfd, 0);
2350 close(prevfd);
2351 if (pip[0] == 0) {
2352 pip[0] = -1;
2353 }
2354 }
2355 if (pip[1] >= 0) {
2356 if (pip[0] >= 0) {
2357 close(pip[0]);
2358 }
2359 if (pip[1] != 1) {
2360 close(1);
2361 dup_as_newfd(pip[1], 1);
2362 close(pip[1]);
2363 }
2364 }
2365 evaltree(lp->n, EV_EXIT);
2366 }
2367 if (prevfd >= 0)
2368 close(prevfd);
2369 prevfd = pip[0];
2370 close(pip[1]);
2371 }
2372 INTON;
2373 if (n->npipe.backgnd == 0) {
2374 INTOFF;
2375 exitstatus = waitforjob(jp);
2376 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
2377 INTON;
2378 }
2379}
2380
Eric Andersen2870d962001-07-02 17:27:21 +00002381static int
2382isassignment(const char *word) {
2383 if (!is_name(*word)) {
2384 return 0;
2385 }
2386 do {
2387 word++;
2388 } while (is_in_name(*word));
2389 return *word == '=';
2390}
2391
Eric Andersen62483552001-07-10 06:09:16 +00002392
Eric Andersencb57d552001-06-28 07:25:16 +00002393static void
Eric Andersen3102ac42001-07-06 04:26:23 +00002394evalcommand(union node *cmd, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002395{
2396 struct stackmark smark;
2397 union node *argp;
2398 struct arglist arglist;
2399 struct arglist varlist;
2400 char **argv;
2401 int argc;
2402 char **envp;
2403 struct strlist *sp;
2404 int mode;
Eric Andersencb57d552001-06-28 07:25:16 +00002405 struct cmdentry cmdentry;
2406 struct job *jp;
2407 char *volatile savecmdname;
2408 volatile struct shparam saveparam;
2409 struct localvar *volatile savelocalvars;
2410 volatile int e;
2411 char *lastarg;
2412 const char *path;
2413 const struct builtincmd *firstbltin;
2414 struct jmploc *volatile savehandler;
2415 struct jmploc jmploc;
2416#if __GNUC__
2417 /* Avoid longjmp clobbering */
2418 (void) &argv;
2419 (void) &argc;
2420 (void) &lastarg;
2421 (void) &flags;
2422#endif
2423
2424 /* First expand the arguments. */
2425 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
2426 setstackmark(&smark);
2427 arglist.lastp = &arglist.list;
2428 varlist.lastp = &varlist.list;
2429 arglist.list = 0;
2430 oexitstatus = exitstatus;
2431 exitstatus = 0;
2432 path = pathval();
2433 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
2434 expandarg(argp, &varlist, EXP_VARTILDE);
2435 }
2436 for (
2437 argp = cmd->ncmd.args; argp && !arglist.list;
2438 argp = argp->narg.next
2439 ) {
2440 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2441 }
2442 if (argp) {
2443 struct builtincmd *bcmd;
Eric Andersen62483552001-07-10 06:09:16 +00002444 int pseudovarflag;
Eric Andersencb57d552001-06-28 07:25:16 +00002445 bcmd = find_builtin(arglist.list->text);
Eric Andersen2870d962001-07-02 17:27:21 +00002446 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00002447 for (; argp; argp = argp->narg.next) {
2448 if (pseudovarflag && isassignment(argp->narg.text)) {
2449 expandarg(argp, &arglist, EXP_VARTILDE);
2450 continue;
2451 }
2452 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2453 }
2454 }
2455 *arglist.lastp = NULL;
2456 *varlist.lastp = NULL;
2457 expredir(cmd->ncmd.redirect);
2458 argc = 0;
2459 for (sp = arglist.list ; sp ; sp = sp->next)
2460 argc++;
2461 argv = stalloc(sizeof (char *) * (argc + 1));
2462
2463 for (sp = arglist.list ; sp ; sp = sp->next) {
2464 TRACE(("evalcommand arg: %s\n", sp->text));
2465 *argv++ = sp->text;
2466 }
2467 *argv = NULL;
2468 lastarg = NULL;
2469 if (iflag && funcnest == 0 && argc > 0)
2470 lastarg = argv[-1];
2471 argv -= argc;
2472
2473 /* Print the command if xflag is set. */
2474 if (xflag) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002475 out2c('+');
Eric Andersencb57d552001-06-28 07:25:16 +00002476 eprintlist(varlist.list);
2477 eprintlist(arglist.list);
Eric Andersen3102ac42001-07-06 04:26:23 +00002478 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00002479 }
2480
2481 /* Now locate the command. */
2482 if (argc == 0) {
2483 cmdentry.cmdtype = CMDBUILTIN;
2484 firstbltin = cmdentry.u.cmd = BLTINCMD;
2485 } else {
2486 const char *oldpath;
2487 int findflag = DO_ERR;
2488 int oldfindflag;
2489
2490 /*
2491 * Modify the command lookup path, if a PATH= assignment
2492 * is present
2493 */
2494 for (sp = varlist.list ; sp ; sp = sp->next)
2495 if (varequal(sp->text, defpathvar)) {
2496 path = sp->text + 5;
2497 findflag |= DO_BRUTE;
2498 }
2499 oldpath = path;
2500 oldfindflag = findflag;
2501 firstbltin = 0;
2502 for(;;) {
2503 find_command(argv[0], &cmdentry, findflag, path);
Eric Andersen2870d962001-07-02 17:27:21 +00002504 if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */
Eric Andersencb57d552001-06-28 07:25:16 +00002505 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002506 goto out;
2507 }
2508 /* implement bltin and command here */
2509 if (cmdentry.cmdtype != CMDBUILTIN) {
2510 break;
2511 }
2512 if (!firstbltin) {
2513 firstbltin = cmdentry.u.cmd;
2514 }
2515 if (cmdentry.u.cmd == BLTINCMD) {
2516 for(;;) {
2517 struct builtincmd *bcmd;
2518
2519 argv++;
2520 if (--argc == 0)
2521 goto found;
2522 if (!(bcmd = find_builtin(*argv))) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002523 out2fmt("%s: not found\n", *argv);
Eric Andersencb57d552001-06-28 07:25:16 +00002524 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002525 goto out;
2526 }
2527 cmdentry.u.cmd = bcmd;
2528 if (bcmd != BLTINCMD)
2529 break;
2530 }
2531 }
Eric Andersen2870d962001-07-02 17:27:21 +00002532 if (cmdentry.u.cmd == find_builtin("command")) {
Eric Andersencb57d552001-06-28 07:25:16 +00002533 argv++;
2534 if (--argc == 0) {
2535 goto found;
2536 }
2537 if (*argv[0] == '-') {
2538 if (!equal(argv[0], "-p")) {
2539 argv--;
2540 argc++;
2541 break;
2542 }
2543 argv++;
2544 if (--argc == 0) {
2545 goto found;
2546 }
2547 path = defpath;
2548 findflag |= DO_BRUTE;
2549 } else {
2550 path = oldpath;
2551 findflag = oldfindflag;
2552 }
2553 findflag |= DO_NOFUN;
2554 continue;
2555 }
2556found:
2557 break;
2558 }
2559 }
2560
2561 /* Fork off a child process if necessary. */
2562 if (cmd->ncmd.backgnd
2563 || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00002564 ) {
2565 jp = makejob(cmd, 1);
2566 mode = cmd->ncmd.backgnd;
Eric Andersencb57d552001-06-28 07:25:16 +00002567 if (forkshell(jp, cmd, mode) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00002568 goto parent; /* at end of routine */
Eric Andersencb57d552001-06-28 07:25:16 +00002569 flags |= EV_EXIT;
2570 }
2571
2572 /* This is the child process if a fork occurred. */
2573 /* Execute the command. */
2574 if (cmdentry.cmdtype == CMDFUNCTION) {
2575#ifdef DEBUG
2576 trputs("Shell function: "); trargs(argv);
2577#endif
2578 exitstatus = oexitstatus;
2579 redirect(cmd->ncmd.redirect, REDIR_PUSH);
2580 saveparam = shellparam;
2581 shellparam.malloc = 0;
2582 shellparam.nparam = argc - 1;
2583 shellparam.p = argv + 1;
2584 INTOFF;
2585 savelocalvars = localvars;
2586 localvars = NULL;
2587 INTON;
2588 if (setjmp(jmploc.loc)) {
2589 if (exception == EXSHELLPROC) {
2590 freeparam((volatile struct shparam *)
2591 &saveparam);
2592 } else {
2593 saveparam.optind = shellparam.optind;
2594 saveparam.optoff = shellparam.optoff;
2595 freeparam(&shellparam);
2596 shellparam = saveparam;
2597 }
2598 poplocalvars();
2599 localvars = savelocalvars;
2600 handler = savehandler;
2601 longjmp(handler->loc, 1);
2602 }
2603 savehandler = handler;
2604 handler = &jmploc;
2605 for (sp = varlist.list ; sp ; sp = sp->next)
2606 mklocal(sp->text);
2607 funcnest++;
2608 evaltree(cmdentry.u.func, flags & EV_TESTED);
2609 funcnest--;
2610 INTOFF;
2611 poplocalvars();
2612 localvars = savelocalvars;
2613 saveparam.optind = shellparam.optind;
2614 saveparam.optoff = shellparam.optoff;
2615 freeparam(&shellparam);
2616 shellparam = saveparam;
2617 handler = savehandler;
2618 popredir();
2619 INTON;
2620 if (evalskip == SKIPFUNC) {
2621 evalskip = 0;
2622 skipcount = 0;
2623 }
2624 if (flags & EV_EXIT)
2625 exitshell(exitstatus);
2626 } else if (cmdentry.cmdtype == CMDBUILTIN) {
2627#ifdef DEBUG
2628 trputs("builtin command: "); trargs(argv);
2629#endif
2630 mode = (cmdentry.u.cmd == EXECCMD)? 0 : REDIR_PUSH;
Eric Andersencb57d552001-06-28 07:25:16 +00002631 redirect(cmd->ncmd.redirect, mode);
2632 savecmdname = commandname;
Eric Andersen2870d962001-07-02 17:27:21 +00002633 if (IS_BUILTIN_SPECIAL(firstbltin)) {
Eric Andersencb57d552001-06-28 07:25:16 +00002634 listsetvar(varlist.list);
2635 } else {
2636 cmdenviron = varlist.list;
2637 }
2638 e = -1;
2639 if (setjmp(jmploc.loc)) {
2640 e = exception;
2641 exitstatus = (e == EXINT)? SIGINT+128 : 2;
2642 goto cmddone;
2643 }
2644 savehandler = handler;
2645 handler = &jmploc;
2646 commandname = argv[0];
2647 argptr = argv + 1;
Eric Andersen2870d962001-07-02 17:27:21 +00002648 optptr = NULL; /* initialize nextopt */
Eric Andersencb57d552001-06-28 07:25:16 +00002649 exitstatus = (*cmdentry.u.cmd->builtinfunc)(argc, argv);
2650 flushall();
2651cmddone:
Eric Andersencb57d552001-06-28 07:25:16 +00002652 cmdenviron = NULL;
2653 if (e != EXSHELLPROC) {
2654 commandname = savecmdname;
2655 if (flags & EV_EXIT)
2656 exitshell(exitstatus);
2657 }
2658 handler = savehandler;
2659 if (e != -1) {
2660 if ((e != EXERROR && e != EXEXEC)
2661 || cmdentry.u.cmd == BLTINCMD
2662 || cmdentry.u.cmd == DOTCMD
2663 || cmdentry.u.cmd == EVALCMD
2664 || cmdentry.u.cmd == EXECCMD)
2665 exraise(e);
2666 FORCEINTON;
2667 }
2668 if (cmdentry.u.cmd != EXECCMD)
2669 popredir();
Eric Andersencb57d552001-06-28 07:25:16 +00002670 } else {
2671#ifdef DEBUG
2672 trputs("normal command: "); trargs(argv);
2673#endif
2674 redirect(cmd->ncmd.redirect, 0);
2675 clearredir();
2676 for (sp = varlist.list ; sp ; sp = sp->next)
2677 setvareq(sp->text, VEXPORT|VSTACK);
2678 envp = environment();
2679 shellexec(argv, envp, path, cmdentry.u.index);
2680 }
2681 goto out;
2682
Eric Andersen2870d962001-07-02 17:27:21 +00002683parent: /* parent process gets here (if we forked) */
2684 if (mode == 0) { /* argument to fork */
Eric Andersencb57d552001-06-28 07:25:16 +00002685 INTOFF;
2686 exitstatus = waitforjob(jp);
2687 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00002688 }
2689
2690out:
2691 if (lastarg)
2692 setvar("_", lastarg, 0);
2693 popstackmark(&smark);
2694}
2695
Eric Andersen62483552001-07-10 06:09:16 +00002696/*
2697 * Evaluate a parse tree. The value is left in the global variable
2698 * exitstatus.
2699 */
2700static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00002701evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00002702{
2703 int checkexit = 0;
2704 if (n == NULL) {
2705 TRACE(("evaltree(NULL) called\n"));
2706 goto out;
2707 }
2708 TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
2709 switch (n->type) {
2710 case NSEMI:
2711 evaltree(n->nbinary.ch1, flags & EV_TESTED);
2712 if (evalskip)
2713 goto out;
2714 evaltree(n->nbinary.ch2, flags);
2715 break;
2716 case NAND:
2717 evaltree(n->nbinary.ch1, EV_TESTED);
2718 if (evalskip || exitstatus != 0)
2719 goto out;
2720 evaltree(n->nbinary.ch2, flags);
2721 break;
2722 case NOR:
2723 evaltree(n->nbinary.ch1, EV_TESTED);
2724 if (evalskip || exitstatus == 0)
2725 goto out;
2726 evaltree(n->nbinary.ch2, flags);
2727 break;
2728 case NREDIR:
2729 expredir(n->nredir.redirect);
2730 redirect(n->nredir.redirect, REDIR_PUSH);
2731 evaltree(n->nredir.n, flags);
2732 popredir();
2733 break;
2734 case NSUBSHELL:
2735 evalsubshell(n, flags);
2736 break;
2737 case NBACKGND:
2738 evalsubshell(n, flags);
2739 break;
2740 case NIF: {
2741 evaltree(n->nif.test, EV_TESTED);
2742 if (evalskip)
2743 goto out;
2744 if (exitstatus == 0)
2745 evaltree(n->nif.ifpart, flags);
2746 else if (n->nif.elsepart)
2747 evaltree(n->nif.elsepart, flags);
2748 else
2749 exitstatus = 0;
2750 break;
2751 }
2752 case NWHILE:
2753 case NUNTIL:
2754 evalloop(n, flags);
2755 break;
2756 case NFOR:
2757 evalfor(n, flags);
2758 break;
2759 case NCASE:
2760 evalcase(n, flags);
2761 break;
2762 case NDEFUN: {
2763 struct builtincmd *bcmd;
2764 struct cmdentry entry;
2765 if (
2766 (bcmd = find_builtin(n->narg.text)) &&
2767 IS_BUILTIN_SPECIAL(bcmd)
2768 ) {
2769 out2fmt("%s is a special built-in\n", n->narg.text);
2770 exitstatus = 1;
2771 break;
2772 }
2773 entry.cmdtype = CMDFUNCTION;
2774 entry.u.func = copyfunc(n->narg.next);
2775 addcmdentry(n->narg.text, &entry);
2776 exitstatus = 0;
2777 break;
2778 }
2779 case NNOT:
2780 evaltree(n->nnot.com, EV_TESTED);
2781 exitstatus = !exitstatus;
2782 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002783
Eric Andersen62483552001-07-10 06:09:16 +00002784 case NPIPE:
2785 evalpipe(n);
2786 checkexit = 1;
2787 break;
2788 case NCMD:
2789 evalcommand(n, flags);
2790 checkexit = 1;
2791 break;
2792#ifdef DEBUG
2793 default:
2794 printf("Node type = %d\n", n->type);
2795 break;
2796#endif
2797 }
2798out:
2799 if (pendingsigs)
2800 dotrap();
2801 if (
2802 flags & EV_EXIT ||
2803 (checkexit && eflag && exitstatus && !(flags & EV_TESTED))
2804 )
2805 exitshell(exitstatus);
2806}
2807
2808/*
2809 * Kick off a subshell to evaluate a tree.
2810 */
2811
2812static void
2813evalsubshell(const union node *n, int flags)
2814{
2815 struct job *jp;
2816 int backgnd = (n->type == NBACKGND);
2817
2818 expredir(n->nredir.redirect);
2819 jp = makejob(n, 1);
2820 if (forkshell(jp, n, backgnd) == 0) {
2821 if (backgnd)
2822 flags &=~ EV_TESTED;
2823 redirect(n->nredir.redirect, 0);
2824 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
2825 }
2826 if (! backgnd) {
2827 INTOFF;
2828 exitstatus = waitforjob(jp);
2829 INTON;
2830 }
2831}
2832
2833/*
2834 * Compute the names of the files in a redirection list.
2835 */
2836
2837static void fixredir(union node *n, const char *text, int err);
2838
2839static void
2840expredir(union node *n)
2841{
2842 union node *redir;
2843
2844 for (redir = n ; redir ; redir = redir->nfile.next) {
2845 struct arglist fn;
2846 fn.lastp = &fn.list;
2847 oexitstatus = exitstatus;
2848 switch (redir->type) {
2849 case NFROMTO:
2850 case NFROM:
2851 case NTO:
2852 case NAPPEND:
2853 case NTOOV:
2854 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
2855 redir->nfile.expfname = fn.list->text;
2856 break;
2857 case NFROMFD:
2858 case NTOFD:
2859 if (redir->ndup.vname) {
2860 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
2861 fixredir(redir, fn.list->text, 1);
2862 }
2863 break;
2864 }
2865 }
2866}
2867
2868
2869/*
2870 * Execute a command inside back quotes. If it's a builtin command, we
2871 * want to save its output in a block obtained from malloc. Otherwise
2872 * we fork off a subprocess and get the output of the command via a pipe.
2873 * Should be called with interrupts off.
2874 */
2875
2876static void
2877evalbackcmd(union node *n, struct backcmd *result)
2878{
2879 int pip[2];
2880 struct job *jp;
2881 struct stackmark smark; /* unnecessary */
2882
2883 setstackmark(&smark);
2884 result->fd = -1;
2885 result->buf = NULL;
2886 result->nleft = 0;
2887 result->jp = NULL;
2888 if (n == NULL) {
2889 exitstatus = 0;
2890 goto out;
2891 }
2892 exitstatus = 0;
2893 if (pipe(pip) < 0)
2894 error("Pipe call failed");
2895 jp = makejob(n, 1);
2896 if (forkshell(jp, n, FORK_NOJOB) == 0) {
2897 FORCEINTON;
2898 close(pip[0]);
2899 if (pip[1] != 1) {
2900 close(1);
2901 dup_as_newfd(pip[1], 1);
2902 close(pip[1]);
2903 }
2904 eflag = 0;
2905 evaltree(n, EV_EXIT);
2906 }
2907 close(pip[1]);
2908 result->fd = pip[0];
2909 result->jp = jp;
2910out:
2911 popstackmark(&smark);
2912 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
2913 result->fd, result->buf, result->nleft, result->jp));
2914}
2915
2916
2917/*
2918 * Execute a simple command.
2919 */
Eric Andersencb57d552001-06-28 07:25:16 +00002920
Eric Andersencb57d552001-06-28 07:25:16 +00002921
Eric Andersencb57d552001-06-28 07:25:16 +00002922/*
2923 * Builtin commands. Builtin commands whose functions are closely
2924 * tied to evaluation are implemented here.
2925 */
2926
2927/*
2928 * No command given, or a bltin command with no arguments. Set the
2929 * specified variables.
2930 */
2931
2932int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00002933bltincmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002934{
2935 /*
2936 * Preserve exitstatus of a previous possible redirection
2937 * as POSIX mandates
2938 */
2939 return exitstatus;
2940}
2941
2942
2943/*
2944 * Handle break and continue commands. Break, continue, and return are
2945 * all handled by setting the evalskip flag. The evaluation routines
2946 * above all check this flag, and if it is set they start skipping
2947 * commands rather than executing them. The variable skipcount is
2948 * the number of loops to break/continue, or the number of function
2949 * levels to return. (The latter is always 1.) It should probably
2950 * be an error to break out of more loops than exist, but it isn't
2951 * in the standard shell so we don't make it one here.
2952 */
2953
2954static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00002955breakcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002956{
2957 int n = argc > 1 ? number(argv[1]) : 1;
2958
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00002959 if (n <= 0)
2960 error("Illegal number: %s", argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00002961 if (n > loopnest)
2962 n = loopnest;
2963 if (n > 0) {
2964 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
2965 skipcount = n;
2966 }
2967 return 0;
2968}
2969
2970
2971/*
2972 * The return command.
2973 */
2974
2975static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00002976returncmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002977{
2978 int ret = argc > 1 ? number(argv[1]) : oexitstatus;
2979
2980 if (funcnest) {
2981 evalskip = SKIPFUNC;
2982 skipcount = 1;
2983 return ret;
2984 }
2985 else {
2986 /* Do what ksh does; skip the rest of the file */
2987 evalskip = SKIPFILE;
2988 skipcount = 1;
2989 return ret;
2990 }
2991}
2992
2993
Eric Andersen69a20f02001-10-31 10:40:37 +00002994#ifndef CONFIG_FALSE
Eric Andersencb57d552001-06-28 07:25:16 +00002995static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00002996false_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002997{
2998 return 1;
2999}
Eric Andersen69a20f02001-10-31 10:40:37 +00003000#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003001
Eric Andersen69a20f02001-10-31 10:40:37 +00003002#ifndef CONFIG_TRUE
Eric Andersencb57d552001-06-28 07:25:16 +00003003static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003004true_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003005{
3006 return 0;
3007}
3008#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003009
3010/*
3011 * Controls whether the shell is interactive or not.
3012 */
3013
3014static void setsignal(int signo);
Eric Andersen2870d962001-07-02 17:27:21 +00003015
Eric Andersend35c5df2002-01-09 15:37:36 +00003016#ifdef CONFIG_ASH_MAIL
Eric Andersenec074692001-10-31 11:05:49 +00003017static void chkmail(int silent);
3018#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003019
3020static void
3021setinteractive(int on)
3022{
3023 static int is_interactive;
Eric Andersen1c039232001-07-07 00:05:55 +00003024 static int do_banner=0;
Eric Andersen2870d962001-07-02 17:27:21 +00003025
3026 if (on == is_interactive)
3027 return;
3028 setsignal(SIGINT);
3029 setsignal(SIGQUIT);
3030 setsignal(SIGTERM);
Eric Andersend35c5df2002-01-09 15:37:36 +00003031#ifdef CONFIG_ASH_MAIL
Eric Andersen2870d962001-07-02 17:27:21 +00003032 chkmail(1);
Eric Andersenec074692001-10-31 11:05:49 +00003033#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003034 is_interactive = on;
Eric Andersen1c039232001-07-07 00:05:55 +00003035 if (do_banner==0 && is_interactive) {
3036 /* Looks like they want an interactive shell */
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003037#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
Eric Andersen1c039232001-07-07 00:05:55 +00003038 printf( "\n\n" BB_BANNER " Built-in shell (ash)\n");
3039 printf( "Enter 'help' for a list of built-in commands.\n\n");
Eric Andersend63dee42001-10-19 00:22:23 +00003040#endif
Eric Andersen1c039232001-07-07 00:05:55 +00003041 do_banner=1;
3042 }
Eric Andersen2870d962001-07-02 17:27:21 +00003043}
3044
3045static void
3046optschanged(void)
3047{
3048 setinteractive(iflag);
3049 setjobctl(mflag);
3050}
3051
Eric Andersencb57d552001-06-28 07:25:16 +00003052
3053static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003054execcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003055{
3056 if (argc > 1) {
3057 struct strlist *sp;
3058
Eric Andersen2870d962001-07-02 17:27:21 +00003059 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003060 mflag = 0;
3061 optschanged();
3062 for (sp = cmdenviron; sp ; sp = sp->next)
3063 setvareq(sp->text, VEXPORT|VSTACK);
3064 shellexec(argv + 1, environment(), pathval(), 0);
3065 }
3066 return 0;
3067}
3068
3069static void
3070eprintlist(struct strlist *sp)
3071{
3072 for (; sp; sp = sp->next) {
Eric Andersen3102ac42001-07-06 04:26:23 +00003073 out2fmt(" %s",sp->text);
Eric Andersencb57d552001-06-28 07:25:16 +00003074 }
3075}
Eric Andersencb57d552001-06-28 07:25:16 +00003076
3077/*
3078 * Exec a program. Never returns. If you change this routine, you may
3079 * have to change the find_command routine as well.
3080 */
3081
Eric Andersen2870d962001-07-02 17:27:21 +00003082static const char *pathopt; /* set by padvance */
3083
Eric Andersencb57d552001-06-28 07:25:16 +00003084static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003085shellexec(char **argv, char **envp, const char *path, int idx)
Eric Andersencb57d552001-06-28 07:25:16 +00003086{
3087 char *cmdname;
3088 int e;
3089
3090 if (strchr(argv[0], '/') != NULL) {
3091 tryexec(argv[0], argv, envp);
3092 e = errno;
3093 } else {
3094 e = ENOENT;
3095 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3096 if (--idx < 0 && pathopt == NULL) {
3097 tryexec(cmdname, argv, envp);
3098 if (errno != ENOENT && errno != ENOTDIR)
3099 e = errno;
3100 }
3101 stunalloc(cmdname);
3102 }
3103 }
3104
3105 /* Map to POSIX errors */
3106 switch (e) {
3107 case EACCES:
3108 exerrno = 126;
3109 break;
3110 case ENOENT:
3111 exerrno = 127;
3112 break;
3113 default:
3114 exerrno = 2;
3115 break;
3116 }
3117 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3118 /* NOTREACHED */
3119}
3120
Eric Andersen2870d962001-07-02 17:27:21 +00003121/*
3122 * Clear traps on a fork.
3123 */
3124static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003125clear_traps(void)
3126{
Eric Andersen2870d962001-07-02 17:27:21 +00003127 char **tp;
3128
3129 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
3130 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
3131 INTOFF;
3132 ckfree(*tp);
3133 *tp = NULL;
3134 if (tp != &trap[0])
3135 setsignal(tp - trap);
3136 INTON;
3137 }
3138 }
3139}
3140
3141
3142static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003143initshellproc(void)
3144{
Eric Andersen2870d962001-07-02 17:27:21 +00003145
Eric Andersend35c5df2002-01-09 15:37:36 +00003146#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00003147 /* from alias.c: */
3148 {
3149 rmaliases();
3150 }
3151#endif
3152 /* from eval.c: */
3153 {
3154 exitstatus = 0;
3155 }
3156
3157 /* from exec.c: */
3158 {
3159 deletefuncs();
3160 }
3161
3162 /* from jobs.c: */
3163 {
3164 backgndpid = -1;
Eric Andersend35c5df2002-01-09 15:37:36 +00003165#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen2870d962001-07-02 17:27:21 +00003166 jobctl = 0;
3167#endif
3168 }
3169
3170 /* from options.c: */
3171 {
3172 int i;
3173
3174 for (i = 0; i < NOPTS; i++)
3175 optent_val(i) = 0;
3176 optschanged();
3177
3178 }
3179
3180 /* from redir.c: */
3181 {
3182 clearredir();
3183 }
3184
3185 /* from trap.c: */
3186 {
3187 char *sm;
3188
3189 clear_traps();
3190 for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) {
3191 if (*sm == S_IGN)
3192 *sm = S_HARD_IGN;
3193 }
3194 }
3195
3196 /* from var.c: */
3197 {
3198 shprocvar();
3199 }
3200}
3201
3202static int preadbuffer(void);
3203static void pushfile (void);
Eric Andersen2870d962001-07-02 17:27:21 +00003204
3205/*
3206 * Read a character from the script, returning PEOF on end of file.
3207 * Nul characters in the input are silently discarded.
3208 */
3209
Eric Andersend35c5df2002-01-09 15:37:36 +00003210#ifndef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Eric Andersen2870d962001-07-02 17:27:21 +00003211#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
3212static int
3213pgetc(void)
3214{
3215 return pgetc_macro();
3216}
3217#else
3218static int
3219pgetc_macro(void)
3220{
3221 return --parsenleft >= 0? *parsenextc++ : preadbuffer();
3222}
3223
3224static inline int
3225pgetc(void)
3226{
3227 return pgetc_macro();
3228}
3229#endif
3230
3231
3232/*
3233 * Undo the last call to pgetc. Only one character may be pushed back.
3234 * PEOF may be pushed back.
3235 */
3236
Eric Andersen74400cc2001-10-18 04:11:39 +00003237static void pungetc(void)
3238{
Eric Andersen2870d962001-07-02 17:27:21 +00003239 parsenleft++;
3240 parsenextc--;
3241}
3242
3243
3244static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003245popfile(void)
3246{
Eric Andersen2870d962001-07-02 17:27:21 +00003247 struct parsefile *pf = parsefile;
3248
3249 INTOFF;
3250 if (pf->fd >= 0)
3251 close(pf->fd);
3252 if (pf->buf)
3253 ckfree(pf->buf);
3254 while (pf->strpush)
3255 popstring();
3256 parsefile = pf->prev;
3257 ckfree(pf);
3258 parsenleft = parsefile->nleft;
3259 parselleft = parsefile->lleft;
3260 parsenextc = parsefile->nextc;
3261 plinno = parsefile->linno;
3262 INTON;
3263}
3264
3265
3266/*
3267 * Return to top level.
3268 */
3269
3270static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003271popallfiles(void)
3272{
Eric Andersen2870d962001-07-02 17:27:21 +00003273 while (parsefile != &basepf)
3274 popfile();
3275}
3276
3277/*
3278 * Close the file(s) that the shell is reading commands from. Called
3279 * after a fork is done.
3280 */
3281
Eric Andersen74400cc2001-10-18 04:11:39 +00003282static void closescript(void)
3283{
Eric Andersen2870d962001-07-02 17:27:21 +00003284 popallfiles();
3285 if (parsefile->fd > 0) {
3286 close(parsefile->fd);
3287 parsefile->fd = 0;
3288 }
3289}
3290
3291
3292/*
3293 * Like setinputfile, but takes an open file descriptor. Call this with
3294 * interrupts off.
3295 */
3296
Eric Andersen74400cc2001-10-18 04:11:39 +00003297static void setinputfd(int fd, int push)
Eric Andersen2870d962001-07-02 17:27:21 +00003298{
3299 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
3300 if (push) {
3301 pushfile();
3302 parsefile->buf = 0;
3303 } else {
3304 closescript();
3305 while (parsefile->strpush)
3306 popstring();
3307 }
3308 parsefile->fd = fd;
3309 if (parsefile->buf == NULL)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003310 parsefile->buf = xmalloc(BUFSIZ);
Eric Andersen2870d962001-07-02 17:27:21 +00003311 parselleft = parsenleft = 0;
3312 plinno = 1;
3313}
3314
3315
3316/*
3317 * Set the input to take input from a file. If push is set, push the
3318 * old input onto the stack first.
3319 */
3320
3321static void
3322setinputfile(const char *fname, int push)
3323{
3324 int fd;
3325 int myfileno2;
3326
3327 INTOFF;
3328 if ((fd = open(fname, O_RDONLY)) < 0)
3329 error("Can't open %s", fname);
3330 if (fd < 10) {
3331 myfileno2 = dup_as_newfd(fd, 10);
3332 close(fd);
3333 if (myfileno2 < 0)
3334 error("Out of file descriptors");
3335 fd = myfileno2;
3336 }
3337 setinputfd(fd, push);
3338 INTON;
3339}
3340
Eric Andersencb57d552001-06-28 07:25:16 +00003341
3342static void
Eric Andersen62483552001-07-10 06:09:16 +00003343tryexec(char *cmd, char **argv, char **envp)
3344{
Eric Andersencb57d552001-06-28 07:25:16 +00003345 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003346
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003347#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Eric Andersen3102ac42001-07-06 04:26:23 +00003348 char *name = cmd;
3349 char** argv_l=argv;
3350 int argc_l;
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003351#ifdef CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
Eric Andersen3102ac42001-07-06 04:26:23 +00003352 name = get_last_path_component(name);
3353#endif
3354 argv_l=envp;
3355 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
3356 putenv(*argv_l);
3357 argv_l=argv;
Eric Andersen62483552001-07-10 06:09:16 +00003358 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
Eric Andersen3102ac42001-07-06 04:26:23 +00003359 optind = 1;
3360 run_applet_by_name(name, argc_l, argv);
3361#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003362 execve(cmd, argv, envp);
Eric Andersencb57d552001-06-28 07:25:16 +00003363 e = errno;
3364 if (e == ENOEXEC) {
3365 INTOFF;
3366 initshellproc();
3367 setinputfile(cmd, 0);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003368 commandname = arg0 = xstrdup(argv[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00003369 setparam(argv + 1);
3370 exraise(EXSHELLPROC);
3371 }
3372 errno = e;
3373}
3374
Eric Andersen2870d962001-07-02 17:27:21 +00003375static char *commandtext (const union node *);
Eric Andersencb57d552001-06-28 07:25:16 +00003376
3377/*
3378 * Do a path search. The variable path (passed by reference) should be
3379 * set to the start of the path before the first call; padvance will update
3380 * this value as it proceeds. Successive calls to padvance will return
3381 * the possible path expansions in sequence. If an option (indicated by
3382 * a percent sign) appears in the path entry then the global variable
3383 * pathopt will be set to point to it; otherwise pathopt will be set to
3384 * NULL.
3385 */
3386
3387static const char *pathopt;
3388
Eric Andersen2870d962001-07-02 17:27:21 +00003389static void growstackblock(void);
3390
3391
Eric Andersencb57d552001-06-28 07:25:16 +00003392static char *
Eric Andersen2870d962001-07-02 17:27:21 +00003393padvance(const char **path, const char *name)
3394{
Eric Andersencb57d552001-06-28 07:25:16 +00003395 const char *p;
3396 char *q;
3397 const char *start;
3398 int len;
3399
3400 if (*path == NULL)
3401 return NULL;
3402 start = *path;
3403 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
Eric Andersen2870d962001-07-02 17:27:21 +00003404 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003405 while (stackblocksize() < len)
3406 growstackblock();
3407 q = stackblock();
3408 if (p != start) {
3409 memcpy(q, start, p - start);
3410 q += p - start;
3411 *q++ = '/';
3412 }
3413 strcpy(q, name);
3414 pathopt = NULL;
3415 if (*p == '%') {
3416 pathopt = ++p;
3417 while (*p && *p != ':') p++;
3418 }
3419 if (*p == ':')
3420 *path = p + 1;
3421 else
3422 *path = NULL;
3423 return stalloc(len);
3424}
3425
Eric Andersen62483552001-07-10 06:09:16 +00003426/*
3427 * Wrapper around strcmp for qsort/bsearch/...
3428 */
3429static int
3430pstrcmp(const void *a, const void *b)
3431{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003432 return strcmp((const char *) a, (*(const char *const *) b) + 1);
Eric Andersen62483552001-07-10 06:09:16 +00003433}
3434
3435/*
3436 * Find a keyword is in a sorted array.
3437 */
3438
3439static const char *const *
3440findkwd(const char *s)
3441{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003442 return bsearch(s, tokname_array + KWDOFFSET,
3443 (sizeof(tokname_array)/sizeof(const char *)) - KWDOFFSET,
3444 sizeof(const char *), pstrcmp);
Eric Andersen62483552001-07-10 06:09:16 +00003445}
Eric Andersencb57d552001-06-28 07:25:16 +00003446
3447
3448/*** Command hashing code ***/
3449
3450
3451static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003452hashcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003453{
3454 struct tblentry **pp;
3455 struct tblentry *cmdp;
3456 int c;
3457 int verbose;
3458 struct cmdentry entry;
3459 char *name;
Eric Andersend35c5df2002-01-09 15:37:36 +00003460#ifdef CONFIG_ASH_ALIAS
Eric Andersen62483552001-07-10 06:09:16 +00003461 const struct alias *ap;
3462#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003463
3464 verbose = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003465 while ((c = nextopt("rvV")) != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00003466 if (c == 'r') {
3467 clearcmdentry(0);
3468 return 0;
Eric Andersen62483552001-07-10 06:09:16 +00003469 } else if (c == 'v' || c == 'V') {
3470 verbose = c;
Eric Andersencb57d552001-06-28 07:25:16 +00003471 }
3472 }
3473 if (*argptr == NULL) {
3474 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3475 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3476 if (cmdp->cmdtype != CMDBUILTIN) {
3477 printentry(cmdp, verbose);
3478 }
3479 }
3480 }
3481 return 0;
3482 }
3483 c = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003484 while ((name = *argptr++) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00003485 if ((cmdp = cmdlookup(name, 0)) != NULL
3486 && (cmdp->cmdtype == CMDNORMAL
3487 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3488 delete_cmd_entry();
Eric Andersend35c5df2002-01-09 15:37:36 +00003489#ifdef CONFIG_ASH_ALIAS
Eric Andersen62483552001-07-10 06:09:16 +00003490 /* Then look at the aliases */
Eric Andersenec074692001-10-31 11:05:49 +00003491 if ((ap = *__lookupalias(name)) != NULL) {
Eric Andersen62483552001-07-10 06:09:16 +00003492 if (verbose=='v')
3493 printf("%s is an alias for %s\n", name, ap->val);
3494 else
3495 printalias(ap);
3496 continue;
3497 }
3498#endif
3499 /* First look at the keywords */
3500 if (findkwd(name)!=0) {
3501 if (verbose=='v')
3502 printf("%s is a shell keyword\n", name);
3503 else
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003504 puts(name);
Eric Andersen62483552001-07-10 06:09:16 +00003505 continue;
3506 }
3507
Eric Andersencb57d552001-06-28 07:25:16 +00003508 find_command(name, &entry, DO_ERR, pathval());
3509 if (entry.cmdtype == CMDUNKNOWN) c = 1;
3510 else if (verbose) {
3511 cmdp = cmdlookup(name, 0);
Eric Andersen62483552001-07-10 06:09:16 +00003512 if (cmdp) printentry(cmdp, verbose=='v');
Eric Andersencb57d552001-06-28 07:25:16 +00003513 flushall();
3514 }
Eric Andersencb57d552001-06-28 07:25:16 +00003515 }
3516 return c;
3517}
3518
Eric Andersencb57d552001-06-28 07:25:16 +00003519static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003520printentry(struct tblentry *cmdp, int verbose)
3521{
Eric Andersencb57d552001-06-28 07:25:16 +00003522 int idx;
3523 const char *path;
3524 char *name;
3525
Eric Andersen62483552001-07-10 06:09:16 +00003526 printf("%s%s", cmdp->cmdname, (verbose ? " is " : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00003527 if (cmdp->cmdtype == CMDNORMAL) {
3528 idx = cmdp->param.index;
3529 path = pathval();
3530 do {
3531 name = padvance(&path, cmdp->cmdname);
3532 stunalloc(name);
3533 } while (--idx >= 0);
Eric Andersen62483552001-07-10 06:09:16 +00003534 if(verbose)
3535 out1str(name);
Eric Andersencb57d552001-06-28 07:25:16 +00003536 } else if (cmdp->cmdtype == CMDBUILTIN) {
Eric Andersen62483552001-07-10 06:09:16 +00003537 if(verbose)
3538 out1str("a shell builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00003539 } else if (cmdp->cmdtype == CMDFUNCTION) {
Eric Andersencb57d552001-06-28 07:25:16 +00003540 if (verbose) {
3541 INTOFF;
Eric Andersen62483552001-07-10 06:09:16 +00003542 out1str("a function\n");
Eric Andersencb57d552001-06-28 07:25:16 +00003543 name = commandtext(cmdp->param.func);
Eric Andersen62483552001-07-10 06:09:16 +00003544 printf("%s() {\n %s\n}", cmdp->cmdname, name);
Eric Andersencb57d552001-06-28 07:25:16 +00003545 ckfree(name);
3546 INTON;
3547 }
3548#ifdef DEBUG
3549 } else {
3550 error("internal error: cmdtype %d", cmdp->cmdtype);
3551#endif
3552 }
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003553 puts(cmdp->rehash ? "*" : nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +00003554}
3555
3556
3557
Eric Andersen1c039232001-07-07 00:05:55 +00003558/*** List the available builtins ***/
3559
3560
3561static int helpcmd(int argc, char** argv)
3562{
3563 int col, i;
Eric Andersen1c039232001-07-07 00:05:55 +00003564
Eric Andersen62483552001-07-10 06:09:16 +00003565 printf("\nBuilt-in commands:\n-------------------\n");
3566 for (col=0, i=0; i < NUMBUILTINS; i++) {
3567 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3568 builtincmds[i].name+1);
Eric Andersen1c039232001-07-07 00:05:55 +00003569 if (col > 60) {
3570 printf("\n");
3571 col = 0;
3572 }
3573 }
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003574#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Eric Andersen1c039232001-07-07 00:05:55 +00003575 {
Eric Andersen1c039232001-07-07 00:05:55 +00003576 extern const struct BB_applet applets[];
3577 extern const size_t NUM_APPLETS;
3578
Eric Andersen62483552001-07-10 06:09:16 +00003579 for (i=0; i < NUM_APPLETS; i++) {
3580
3581 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3582 applets[i].name);
Eric Andersen1c039232001-07-07 00:05:55 +00003583 if (col > 60) {
3584 printf("\n");
3585 col = 0;
3586 }
3587 }
3588 }
3589#endif
3590 printf("\n\n");
3591 return EXIT_SUCCESS;
3592}
3593
Eric Andersencb57d552001-06-28 07:25:16 +00003594/*
3595 * Resolve a command name. If you change this routine, you may have to
3596 * change the shellexec routine as well.
3597 */
3598
Eric Andersen2870d962001-07-02 17:27:21 +00003599static int prefix (const char *, const char *);
3600
Eric Andersencb57d552001-06-28 07:25:16 +00003601static void
Eric Andersen2870d962001-07-02 17:27:21 +00003602find_command(const char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003603{
3604 struct tblentry *cmdp;
3605 int idx;
3606 int prev;
3607 char *fullname;
3608 struct stat statb;
3609 int e;
3610 int bltin;
3611 int firstchange;
3612 int updatetbl;
Eric Andersen62483552001-07-10 06:09:16 +00003613 int regular;
Eric Andersencb57d552001-06-28 07:25:16 +00003614 struct builtincmd *bcmd;
3615
3616 /* If name contains a slash, don't use the hash table */
3617 if (strchr(name, '/') != NULL) {
3618 if (act & DO_ABS) {
3619 while (stat(name, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003620 if (errno != ENOENT && errno != ENOTDIR)
3621 e = errno;
3622 entry->cmdtype = CMDUNKNOWN;
3623 entry->u.index = -1;
3624 return;
3625 }
3626 entry->cmdtype = CMDNORMAL;
3627 entry->u.index = -1;
3628 return;
3629 }
3630 entry->cmdtype = CMDNORMAL;
3631 entry->u.index = 0;
3632 return;
3633 }
3634
3635 updatetbl = 1;
3636 if (act & DO_BRUTE) {
3637 firstchange = path_change(path, &bltin);
3638 } else {
3639 bltin = builtinloc;
3640 firstchange = 9999;
3641 }
3642
3643 /* If name is in the table, and not invalidated by cd, we're done */
3644 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
3645 if (cmdp->cmdtype == CMDFUNCTION) {
3646 if (act & DO_NOFUN) {
3647 updatetbl = 0;
3648 } else {
3649 goto success;
3650 }
3651 } else if (act & DO_BRUTE) {
3652 if ((cmdp->cmdtype == CMDNORMAL &&
3653 cmdp->param.index >= firstchange) ||
3654 (cmdp->cmdtype == CMDBUILTIN &&
3655 ((builtinloc < 0 && bltin >= 0) ?
3656 bltin : builtinloc) >= firstchange)) {
3657 /* need to recompute the entry */
3658 } else {
3659 goto success;
3660 }
3661 } else {
3662 goto success;
3663 }
3664 }
3665
3666 bcmd = find_builtin(name);
Eric Andersen2870d962001-07-02 17:27:21 +00003667 regular = bcmd && IS_BUILTIN_REGULAR(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00003668
3669 if (regular) {
3670 if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) {
Eric Andersen2870d962001-07-02 17:27:21 +00003671 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003672 }
3673 } else if (act & DO_BRUTE) {
3674 if (firstchange == 0) {
3675 updatetbl = 0;
3676 }
3677 }
3678
3679 /* If %builtin not in path, check for builtin next */
3680 if (regular || (bltin < 0 && bcmd)) {
3681builtin:
3682 if (!updatetbl) {
3683 entry->cmdtype = CMDBUILTIN;
3684 entry->u.cmd = bcmd;
3685 return;
3686 }
3687 INTOFF;
3688 cmdp = cmdlookup(name, 1);
3689 cmdp->cmdtype = CMDBUILTIN;
3690 cmdp->param.cmd = bcmd;
3691 INTON;
3692 goto success;
3693 }
3694
3695 /* We have to search path. */
Eric Andersen2870d962001-07-02 17:27:21 +00003696 prev = -1; /* where to start */
3697 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00003698 if (cmdp->cmdtype == CMDBUILTIN)
3699 prev = builtinloc;
3700 else
3701 prev = cmdp->param.index;
3702 }
3703
3704 e = ENOENT;
3705 idx = -1;
3706loop:
3707 while ((fullname = padvance(&path, name)) != NULL) {
3708 stunalloc(fullname);
3709 idx++;
3710 if (idx >= firstchange) {
3711 updatetbl = 0;
3712 }
3713 if (pathopt) {
3714 if (prefix("builtin", pathopt)) {
3715 if ((bcmd = find_builtin(name))) {
3716 goto builtin;
3717 }
3718 continue;
3719 } else if (!(act & DO_NOFUN) &&
3720 prefix("func", pathopt)) {
3721 /* handled below */
3722 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00003723 continue; /* ignore unimplemented options */
Eric Andersencb57d552001-06-28 07:25:16 +00003724 }
3725 }
3726 /* if rehash, don't redo absolute path names */
3727 if (fullname[0] == '/' && idx <= prev &&
3728 idx < firstchange) {
3729 if (idx < prev)
3730 continue;
3731 TRACE(("searchexec \"%s\": no change\n", name));
3732 goto success;
3733 }
3734 while (stat(fullname, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003735 if (errno != ENOENT && errno != ENOTDIR)
3736 e = errno;
3737 goto loop;
3738 }
Eric Andersen2870d962001-07-02 17:27:21 +00003739 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00003740 if (!S_ISREG(statb.st_mode))
3741 continue;
Eric Andersen2870d962001-07-02 17:27:21 +00003742 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00003743 stalloc(strlen(fullname) + 1);
3744 readcmdfile(fullname);
3745 if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
3746 error("%s not defined in %s", name, fullname);
3747 stunalloc(fullname);
3748 goto success;
3749 }
Eric Andersencb57d552001-06-28 07:25:16 +00003750 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
3751 /* If we aren't called with DO_BRUTE and cmdp is set, it must
3752 be a function and we're being called with DO_NOFUN */
3753 if (!updatetbl) {
3754 entry->cmdtype = CMDNORMAL;
3755 entry->u.index = idx;
3756 return;
3757 }
3758 INTOFF;
3759 cmdp = cmdlookup(name, 1);
3760 cmdp->cmdtype = CMDNORMAL;
3761 cmdp->param.index = idx;
3762 INTON;
3763 goto success;
3764 }
3765
3766 /* We failed. If there was an entry for this command, delete it */
3767 if (cmdp && updatetbl)
3768 delete_cmd_entry();
3769 if (act & DO_ERR)
Eric Andersen3102ac42001-07-06 04:26:23 +00003770 out2fmt("%s: %s\n", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00003771 entry->cmdtype = CMDUNKNOWN;
3772 return;
3773
3774success:
3775 cmdp->rehash = 0;
3776 entry->cmdtype = cmdp->cmdtype;
3777 entry->u = cmdp->param;
3778}
3779
3780
3781
3782/*
3783 * Search the table of builtin commands.
3784 */
3785
Eric Andersen2870d962001-07-02 17:27:21 +00003786static int
3787bstrcmp(const void *name, const void *b)
3788{
3789 return strcmp((const char *)name, (*(const char *const *) b)+1);
3790}
3791
3792static struct builtincmd *
3793find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00003794{
3795 struct builtincmd *bp;
3796
Eric Andersen2870d962001-07-02 17:27:21 +00003797 bp = bsearch(name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd),
3798 bstrcmp
Eric Andersencb57d552001-06-28 07:25:16 +00003799 );
3800 return bp;
3801}
3802
3803
3804/*
3805 * Called when a cd is done. Marks all commands so the next time they
3806 * are executed they will be rehashed.
3807 */
3808
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003809static inline void
3810hashcd(void)
3811{
Eric Andersencb57d552001-06-28 07:25:16 +00003812 struct tblentry **pp;
3813 struct tblentry *cmdp;
3814
3815 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3816 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3817 if (cmdp->cmdtype == CMDNORMAL
3818 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
3819 cmdp->rehash = 1;
3820 }
3821 }
3822}
3823
3824
3825
3826/*
3827 * Called before PATH is changed. The argument is the new value of PATH;
3828 * pathval() still returns the old value at this point. Called with
3829 * interrupts off.
3830 */
3831
3832static void
Eric Andersen2870d962001-07-02 17:27:21 +00003833changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00003834{
3835 int firstchange;
3836 int bltin;
3837
3838 firstchange = path_change(newval, &bltin);
3839 if (builtinloc < 0 && bltin >= 0)
Eric Andersen2870d962001-07-02 17:27:21 +00003840 builtinloc = bltin; /* zap builtins */
Eric Andersencb57d552001-06-28 07:25:16 +00003841 clearcmdentry(firstchange);
3842 builtinloc = bltin;
3843}
3844
3845
3846/*
3847 * Clear out command entries. The argument specifies the first entry in
3848 * PATH which has changed.
3849 */
3850
3851static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003852clearcmdentry(int firstchange)
Eric Andersencb57d552001-06-28 07:25:16 +00003853{
3854 struct tblentry **tblp;
3855 struct tblentry **pp;
3856 struct tblentry *cmdp;
3857
3858 INTOFF;
3859 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
3860 pp = tblp;
3861 while ((cmdp = *pp) != NULL) {
3862 if ((cmdp->cmdtype == CMDNORMAL &&
3863 cmdp->param.index >= firstchange)
3864 || (cmdp->cmdtype == CMDBUILTIN &&
3865 builtinloc >= firstchange)) {
3866 *pp = cmdp->next;
3867 ckfree(cmdp);
3868 } else {
3869 pp = &cmdp->next;
3870 }
3871 }
3872 }
3873 INTON;
3874}
3875
3876
3877/*
3878 * Delete all functions.
3879 */
3880
Eric Andersencb57d552001-06-28 07:25:16 +00003881static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003882deletefuncs(void)
3883{
Eric Andersencb57d552001-06-28 07:25:16 +00003884 struct tblentry **tblp;
3885 struct tblentry **pp;
3886 struct tblentry *cmdp;
3887
3888 INTOFF;
3889 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
3890 pp = tblp;
3891 while ((cmdp = *pp) != NULL) {
3892 if (cmdp->cmdtype == CMDFUNCTION) {
3893 *pp = cmdp->next;
3894 freefunc(cmdp->param.func);
3895 ckfree(cmdp);
3896 } else {
3897 pp = &cmdp->next;
3898 }
3899 }
3900 }
3901 INTON;
3902}
3903
3904
3905
3906/*
3907 * Locate a command in the command hash table. If "add" is nonzero,
3908 * add the command to the table if it is not already present. The
3909 * variable "lastcmdentry" is set to point to the address of the link
3910 * pointing to the entry, so that delete_cmd_entry can delete the
3911 * entry.
3912 */
3913
Eric Andersen2870d962001-07-02 17:27:21 +00003914static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00003915
3916static struct tblentry *
Eric Andersen2870d962001-07-02 17:27:21 +00003917cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00003918{
3919 int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00003920 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00003921 struct tblentry *cmdp;
3922 struct tblentry **pp;
3923
3924 p = name;
3925 hashval = *p << 4;
3926 while (*p)
3927 hashval += *p++;
3928 hashval &= 0x7FFF;
3929 pp = &cmdtable[hashval % CMDTABLESIZE];
3930 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3931 if (equal(cmdp->cmdname, name))
3932 break;
3933 pp = &cmdp->next;
3934 }
3935 if (add && cmdp == NULL) {
3936 INTOFF;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003937 cmdp = *pp = xmalloc(sizeof (struct tblentry) - ARB
Eric Andersencb57d552001-06-28 07:25:16 +00003938 + strlen(name) + 1);
3939 cmdp->next = NULL;
3940 cmdp->cmdtype = CMDUNKNOWN;
3941 cmdp->rehash = 0;
3942 strcpy(cmdp->cmdname, name);
3943 INTON;
3944 }
3945 lastcmdentry = pp;
3946 return cmdp;
3947}
3948
3949/*
3950 * Delete the command entry returned on the last lookup.
3951 */
3952
3953static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003954delete_cmd_entry()
3955{
Eric Andersencb57d552001-06-28 07:25:16 +00003956 struct tblentry *cmdp;
3957
3958 INTOFF;
3959 cmdp = *lastcmdentry;
3960 *lastcmdentry = cmdp->next;
3961 ckfree(cmdp);
3962 INTON;
3963}
3964
3965
3966
Eric Andersencb57d552001-06-28 07:25:16 +00003967
3968
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003969static const unsigned char nodesize[26] = {
Eric Andersen62483552001-07-10 06:09:16 +00003970 ALIGN(sizeof (struct nbinary)),
3971 ALIGN(sizeof (struct ncmd)),
3972 ALIGN(sizeof (struct npipe)),
3973 ALIGN(sizeof (struct nredir)),
3974 ALIGN(sizeof (struct nredir)),
3975 ALIGN(sizeof (struct nredir)),
3976 ALIGN(sizeof (struct nbinary)),
3977 ALIGN(sizeof (struct nbinary)),
3978 ALIGN(sizeof (struct nif)),
3979 ALIGN(sizeof (struct nbinary)),
3980 ALIGN(sizeof (struct nbinary)),
3981 ALIGN(sizeof (struct nfor)),
3982 ALIGN(sizeof (struct ncase)),
3983 ALIGN(sizeof (struct nclist)),
3984 ALIGN(sizeof (struct narg)),
3985 ALIGN(sizeof (struct narg)),
3986 ALIGN(sizeof (struct nfile)),
3987 ALIGN(sizeof (struct nfile)),
3988 ALIGN(sizeof (struct nfile)),
3989 ALIGN(sizeof (struct nfile)),
3990 ALIGN(sizeof (struct nfile)),
3991 ALIGN(sizeof (struct ndup)),
3992 ALIGN(sizeof (struct ndup)),
3993 ALIGN(sizeof (struct nhere)),
3994 ALIGN(sizeof (struct nhere)),
3995 ALIGN(sizeof (struct nnot)),
3996};
Eric Andersencb57d552001-06-28 07:25:16 +00003997
Eric Andersencb57d552001-06-28 07:25:16 +00003998
3999
4000/*
4001 * Delete a function if it exists.
4002 */
4003
4004static void
Eric Andersen2870d962001-07-02 17:27:21 +00004005unsetfunc(char *name)
4006{
Eric Andersencb57d552001-06-28 07:25:16 +00004007 struct tblentry *cmdp;
4008
4009 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
4010 freefunc(cmdp->param.func);
4011 delete_cmd_entry();
4012 }
4013}
4014
Eric Andersen2870d962001-07-02 17:27:21 +00004015
4016/*
Eric Andersencb57d552001-06-28 07:25:16 +00004017 * Locate and print what a word is...
4018 */
4019
4020static int
Eric Andersen62483552001-07-10 06:09:16 +00004021typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004022{
4023 int i;
4024 int err = 0;
Eric Andersen62483552001-07-10 06:09:16 +00004025 char *argv_a[2];
4026
4027 argv_a[1] = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004028
4029 for (i = 1; i < argc; i++) {
Eric Andersen62483552001-07-10 06:09:16 +00004030 argv_a[0] = argv[i];
4031 argptr = argv_a;
4032 optptr = "v";
4033 err |= hashcmd(argc, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00004034 }
4035 return err;
4036}
4037
Eric Andersend35c5df2002-01-09 15:37:36 +00004038#ifdef CONFIG_ASH_CMDCMD
Eric Andersencb57d552001-06-28 07:25:16 +00004039static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004040commandcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004041{
4042 int c;
4043 int default_path = 0;
4044 int verify_only = 0;
4045 int verbose_verify_only = 0;
4046
4047 while ((c = nextopt("pvV")) != '\0')
4048 switch (c) {
4049 case 'p':
4050 default_path = 1;
4051 break;
4052 case 'v':
4053 verify_only = 1;
4054 break;
4055 case 'V':
4056 verbose_verify_only = 1;
4057 break;
Eric Andersencb57d552001-06-28 07:25:16 +00004058 }
4059
4060 if (default_path + verify_only + verbose_verify_only > 1 ||
4061 !*argptr) {
Eric Andersen62483552001-07-10 06:09:16 +00004062 out2str(
4063 "command [-p] command [arg ...]\n"
4064 "command {-v|-V} command\n");
Eric Andersencb57d552001-06-28 07:25:16 +00004065 return EX_USAGE;
4066 }
4067
Eric Andersencb57d552001-06-28 07:25:16 +00004068 if (verify_only || verbose_verify_only) {
Eric Andersen62483552001-07-10 06:09:16 +00004069 char *argv_a[2];
4070
4071 argv_a[1] = 0;
4072 argv_a[0] = *argptr;
4073 argptr = argv_a;
4074 optptr = verbose_verify_only ? "v" : "V"; /* reverse special */
4075 return hashcmd(argc, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00004076 }
Eric Andersencb57d552001-06-28 07:25:16 +00004077
4078 return 0;
4079}
Eric Andersen2870d962001-07-02 17:27:21 +00004080#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004081
4082static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004083path_change(const char *newval, int *bltin)
Eric Andersencb57d552001-06-28 07:25:16 +00004084{
4085 const char *old, *new;
4086 int idx;
4087 int firstchange;
4088
4089 old = pathval();
4090 new = newval;
Eric Andersen2870d962001-07-02 17:27:21 +00004091 firstchange = 9999; /* assume no change */
Eric Andersencb57d552001-06-28 07:25:16 +00004092 idx = 0;
4093 *bltin = -1;
4094 for (;;) {
4095 if (*old != *new) {
4096 firstchange = idx;
4097 if ((*old == '\0' && *new == ':')
4098 || (*old == ':' && *new == '\0'))
4099 firstchange++;
Eric Andersen2870d962001-07-02 17:27:21 +00004100 old = new; /* ignore subsequent differences */
Eric Andersencb57d552001-06-28 07:25:16 +00004101 }
4102 if (*new == '\0')
4103 break;
4104 if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1))
4105 *bltin = idx;
4106 if (*new == ':') {
4107 idx++;
4108 }
4109 new++, old++;
4110 }
4111 if (builtinloc >= 0 && *bltin < 0)
4112 firstchange = 0;
4113 return firstchange;
4114}
Eric Andersencb57d552001-06-28 07:25:16 +00004115/*
4116 * Routines to expand arguments to commands. We have to deal with
4117 * backquotes, shell variables, and file metacharacters.
4118 */
4119/*
4120 * _rmescape() flags
4121 */
Eric Andersen2870d962001-07-02 17:27:21 +00004122#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4123#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Eric Andersencb57d552001-06-28 07:25:16 +00004124
4125/*
4126 * Structure specifying which parts of the string should be searched
4127 * for IFS characters.
4128 */
4129
4130struct ifsregion {
Eric Andersen2870d962001-07-02 17:27:21 +00004131 struct ifsregion *next; /* next region in list */
4132 int begoff; /* offset of start of region */
4133 int endoff; /* offset of end of region */
4134 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004135};
4136
4137
Eric Andersen2870d962001-07-02 17:27:21 +00004138static char *expdest; /* output of current string */
4139static struct nodelist *argbackq; /* list of back quote expressions */
4140static struct ifsregion ifsfirst; /* first struct in list of ifs regions */
4141static struct ifsregion *ifslastp; /* last struct in list */
4142static struct arglist exparg; /* holds expanded arg list */
Eric Andersencb57d552001-06-28 07:25:16 +00004143
Eric Andersen2870d962001-07-02 17:27:21 +00004144static void argstr (char *, int);
4145static char *exptilde (char *, int);
4146static void expbackq (union node *, int, int);
4147static int subevalvar (char *, char *, int, int, int, int, int);
Eric Andersen2870d962001-07-02 17:27:21 +00004148static int varisset (char *, int);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004149static void strtodest (const char *, int, int);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004150static inline void varvalue (char *, int, int);
Eric Andersen2870d962001-07-02 17:27:21 +00004151static void recordregion (int, int, int);
4152static void removerecordregions (int);
4153static void ifsbreakup (char *, struct arglist *);
4154static void ifsfree (void);
4155static void expandmeta (struct strlist *, int);
Eric Andersen62483552001-07-10 06:09:16 +00004156#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00004157#define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB)
4158#if !defined(GLOB_BROKEN)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004159static inline void addglob (const glob_t *);
Eric Andersencb57d552001-06-28 07:25:16 +00004160#endif
4161#endif
Eric Andersen62483552001-07-10 06:09:16 +00004162#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersen2870d962001-07-02 17:27:21 +00004163static void expmeta (char *, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004164#endif
Eric Andersen62483552001-07-10 06:09:16 +00004165#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersen2870d962001-07-02 17:27:21 +00004166static struct strlist *expsort (struct strlist *);
4167static struct strlist *msort (struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004168#endif
Eric Andersen2870d962001-07-02 17:27:21 +00004169static int patmatch (char *, char *, int);
Eric Andersen62483552001-07-10 06:09:16 +00004170#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00004171static int patmatch2 (char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004172#else
Eric Andersen2870d962001-07-02 17:27:21 +00004173static int pmatch (char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004174#define patmatch2 patmatch
4175#endif
Eric Andersen2870d962001-07-02 17:27:21 +00004176static char *cvtnum (int, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004177
4178/*
4179 * Expand shell variables and backquotes inside a here document.
4180 */
4181
Eric Andersen2870d962001-07-02 17:27:21 +00004182/* arg: the document, fd: where to write the expanded version */
Eric Andersen62483552001-07-10 06:09:16 +00004183static inline void
Eric Andersen2870d962001-07-02 17:27:21 +00004184expandhere(union node *arg, int fd)
4185{
Eric Andersencb57d552001-06-28 07:25:16 +00004186 herefd = fd;
4187 expandarg(arg, (struct arglist *)NULL, 0);
4188 xwrite(fd, stackblock(), expdest - stackblock());
4189}
4190
4191
4192/*
4193 * Perform variable substitution and command substitution on an argument,
4194 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4195 * perform splitting and file name expansion. When arglist is NULL, perform
4196 * here document expansion.
4197 */
4198
4199static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004200expandarg(union node *arg, struct arglist *arglist, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004201{
4202 struct strlist *sp;
4203 char *p;
4204
4205 argbackq = arg->narg.backquote;
4206 STARTSTACKSTR(expdest);
4207 ifsfirst.next = NULL;
4208 ifslastp = NULL;
4209 argstr(arg->narg.text, flag);
4210 if (arglist == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00004211 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004212 }
4213 STPUTC('\0', expdest);
4214 p = grabstackstr(expdest);
4215 exparg.lastp = &exparg.list;
4216 /*
4217 * TODO - EXP_REDIR
4218 */
4219 if (flag & EXP_FULL) {
4220 ifsbreakup(p, &exparg);
4221 *exparg.lastp = NULL;
4222 exparg.lastp = &exparg.list;
4223 expandmeta(exparg.list, flag);
4224 } else {
4225 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4226 rmescapes(p);
4227 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4228 sp->text = p;
4229 *exparg.lastp = sp;
4230 exparg.lastp = &sp->next;
4231 }
4232 ifsfree();
4233 *exparg.lastp = NULL;
4234 if (exparg.list) {
4235 *arglist->lastp = exparg.list;
4236 arglist->lastp = exparg.lastp;
4237 }
4238}
4239
4240
Eric Andersen62483552001-07-10 06:09:16 +00004241/*
4242 * Expand a variable, and return a pointer to the next character in the
4243 * input string.
4244 */
4245
Eric Andersen74400cc2001-10-18 04:11:39 +00004246static inline char * evalvar(char *p, int flag)
Eric Andersen62483552001-07-10 06:09:16 +00004247{
4248 int subtype;
4249 int varflags;
4250 char *var;
4251 const char *val;
4252 int patloc;
4253 int c;
4254 int set;
4255 int special;
4256 int startloc;
4257 int varlen;
4258 int easy;
4259 int quotes = flag & (EXP_FULL | EXP_CASE);
4260
4261 varflags = *p++;
4262 subtype = varflags & VSTYPE;
4263 var = p;
4264 special = 0;
4265 if (! is_name(*p))
4266 special = 1;
4267 p = strchr(p, '=') + 1;
4268again: /* jump here after setting a variable with ${var=text} */
4269 if (special) {
4270 set = varisset(var, varflags & VSNUL);
4271 val = NULL;
4272 } else {
4273 val = lookupvar(var);
4274 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
4275 val = NULL;
4276 set = 0;
4277 } else
4278 set = 1;
4279 }
4280 varlen = 0;
4281 startloc = expdest - stackblock();
4282 if (set && subtype != VSPLUS) {
4283 /* insert the value of the variable */
4284 if (special) {
4285 varvalue(var, varflags & VSQUOTE, flag);
4286 if (subtype == VSLENGTH) {
4287 varlen = expdest - stackblock() - startloc;
4288 STADJUST(-varlen, expdest);
4289 }
4290 } else {
4291 if (subtype == VSLENGTH) {
4292 varlen = strlen(val);
4293 } else {
4294 strtodest(
4295 val,
4296 varflags & VSQUOTE ?
4297 DQSYNTAX : BASESYNTAX,
4298 quotes
4299 );
4300 }
4301 }
4302 }
4303
4304 if (subtype == VSPLUS)
4305 set = ! set;
4306
4307 easy = ((varflags & VSQUOTE) == 0 ||
4308 (*var == '@' && shellparam.nparam != 1));
4309
4310
4311 switch (subtype) {
4312 case VSLENGTH:
4313 expdest = cvtnum(varlen, expdest);
4314 goto record;
4315
4316 case VSNORMAL:
4317 if (!easy)
4318 break;
4319record:
4320 recordregion(startloc, expdest - stackblock(),
4321 varflags & VSQUOTE);
4322 break;
4323
4324 case VSPLUS:
4325 case VSMINUS:
4326 if (!set) {
4327 argstr(p, flag);
4328 break;
4329 }
4330 if (easy)
4331 goto record;
4332 break;
4333
4334 case VSTRIMLEFT:
4335 case VSTRIMLEFTMAX:
4336 case VSTRIMRIGHT:
4337 case VSTRIMRIGHTMAX:
4338 if (!set)
4339 break;
4340 /*
4341 * Terminate the string and start recording the pattern
4342 * right after it
4343 */
4344 STPUTC('\0', expdest);
4345 patloc = expdest - stackblock();
4346 if (subevalvar(p, NULL, patloc, subtype,
4347 startloc, varflags, quotes) == 0) {
4348 int amount = (expdest - stackblock() - patloc) + 1;
4349 STADJUST(-amount, expdest);
4350 }
4351 /* Remove any recorded regions beyond start of variable */
4352 removerecordregions(startloc);
4353 goto record;
4354
4355 case VSASSIGN:
4356 case VSQUESTION:
4357 if (!set) {
4358 if (subevalvar(p, var, 0, subtype, startloc,
4359 varflags, quotes)) {
4360 varflags &= ~VSNUL;
4361 /*
4362 * Remove any recorded regions beyond
4363 * start of variable
4364 */
4365 removerecordregions(startloc);
4366 goto again;
4367 }
4368 break;
4369 }
4370 if (easy)
4371 goto record;
4372 break;
4373
4374#ifdef DEBUG
4375 default:
4376 abort();
4377#endif
4378 }
4379
4380 if (subtype != VSNORMAL) { /* skip to end of alternative */
4381 int nesting = 1;
4382 for (;;) {
4383 if ((c = *p++) == CTLESC)
4384 p++;
4385 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
4386 if (set)
4387 argbackq = argbackq->next;
4388 } else if (c == CTLVAR) {
4389 if ((*p++ & VSTYPE) != VSNORMAL)
4390 nesting++;
4391 } else if (c == CTLENDVAR) {
4392 if (--nesting == 0)
4393 break;
4394 }
4395 }
4396 }
4397 return p;
4398}
4399
Eric Andersencb57d552001-06-28 07:25:16 +00004400
4401/*
4402 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4403 * characters to allow for further processing. Otherwise treat
4404 * $@ like $* since no splitting will be performed.
4405 */
4406
4407static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004408argstr(char *p, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004409{
4410 char c;
Eric Andersen2870d962001-07-02 17:27:21 +00004411 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
Eric Andersencb57d552001-06-28 07:25:16 +00004412 int firsteq = 1;
4413
4414 if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
4415 p = exptilde(p, flag);
4416 for (;;) {
4417 switch (c = *p++) {
4418 case '\0':
4419 case CTLENDVAR: /* ??? */
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004420 return;
Eric Andersencb57d552001-06-28 07:25:16 +00004421 case CTLQUOTEMARK:
4422 /* "$@" syntax adherence hack */
4423 if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
4424 break;
4425 if ((flag & EXP_FULL) != 0)
4426 STPUTC(c, expdest);
4427 break;
4428 case CTLESC:
4429 if (quotes)
4430 STPUTC(c, expdest);
4431 c = *p++;
4432 STPUTC(c, expdest);
4433 break;
4434 case CTLVAR:
4435 p = evalvar(p, flag);
4436 break;
4437 case CTLBACKQ:
4438 case CTLBACKQ|CTLQUOTE:
4439 expbackq(argbackq->n, c & CTLQUOTE, flag);
4440 argbackq = argbackq->next;
4441 break;
Eric Andersend35c5df2002-01-09 15:37:36 +00004442#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +00004443 case CTLENDARI:
4444 expari(flag);
4445 break;
Eric Andersen2870d962001-07-02 17:27:21 +00004446#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004447 case ':':
4448 case '=':
4449 /*
4450 * sort of a hack - expand tildes in variable
4451 * assignments (after the first '=' and after ':'s).
4452 */
4453 STPUTC(c, expdest);
4454 if (flag & EXP_VARTILDE && *p == '~') {
4455 if (c == '=') {
4456 if (firsteq)
4457 firsteq = 0;
4458 else
4459 break;
4460 }
4461 p = exptilde(p, flag);
4462 }
4463 break;
4464 default:
4465 STPUTC(c, expdest);
4466 }
4467 }
Eric Andersencb57d552001-06-28 07:25:16 +00004468 return;
4469}
4470
4471static char *
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004472exptilde(char *p, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004473{
4474 char c, *startp = p;
4475 struct passwd *pw;
4476 const char *home;
4477 int quotes = flag & (EXP_FULL | EXP_CASE);
4478
4479 while ((c = *p) != '\0') {
4480 switch(c) {
4481 case CTLESC:
4482 return (startp);
4483 case CTLQUOTEMARK:
4484 return (startp);
4485 case ':':
4486 if (flag & EXP_VARTILDE)
4487 goto done;
4488 break;
4489 case '/':
4490 goto done;
4491 }
4492 p++;
4493 }
4494done:
4495 *p = '\0';
4496 if (*(startp+1) == '\0') {
4497 if ((home = lookupvar("HOME")) == NULL)
4498 goto lose;
4499 } else {
4500 if ((pw = getpwnam(startp+1)) == NULL)
4501 goto lose;
4502 home = pw->pw_dir;
4503 }
4504 if (*home == '\0')
4505 goto lose;
4506 *p = c;
4507 strtodest(home, SQSYNTAX, quotes);
4508 return (p);
4509lose:
4510 *p = c;
4511 return (startp);
4512}
4513
4514
Eric Andersen2870d962001-07-02 17:27:21 +00004515static void
4516removerecordregions(int endoff)
Eric Andersencb57d552001-06-28 07:25:16 +00004517{
4518 if (ifslastp == NULL)
4519 return;
4520
4521 if (ifsfirst.endoff > endoff) {
4522 while (ifsfirst.next != NULL) {
4523 struct ifsregion *ifsp;
4524 INTOFF;
4525 ifsp = ifsfirst.next->next;
4526 ckfree(ifsfirst.next);
4527 ifsfirst.next = ifsp;
4528 INTON;
4529 }
4530 if (ifsfirst.begoff > endoff)
4531 ifslastp = NULL;
4532 else {
4533 ifslastp = &ifsfirst;
4534 ifsfirst.endoff = endoff;
4535 }
4536 return;
4537 }
Eric Andersen2870d962001-07-02 17:27:21 +00004538
Eric Andersencb57d552001-06-28 07:25:16 +00004539 ifslastp = &ifsfirst;
4540 while (ifslastp->next && ifslastp->next->begoff < endoff)
4541 ifslastp=ifslastp->next;
4542 while (ifslastp->next != NULL) {
4543 struct ifsregion *ifsp;
4544 INTOFF;
4545 ifsp = ifslastp->next->next;
4546 ckfree(ifslastp->next);
4547 ifslastp->next = ifsp;
4548 INTON;
4549 }
4550 if (ifslastp->endoff > endoff)
4551 ifslastp->endoff = endoff;
4552}
4553
4554
Eric Andersend35c5df2002-01-09 15:37:36 +00004555#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +00004556/*
4557 * Expand arithmetic expression. Backup to start of expression,
4558 * evaluate, place result in (backed up) result, adjust string position.
4559 */
4560static void
Eric Andersen2870d962001-07-02 17:27:21 +00004561expari(int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004562{
4563 char *p, *start;
Eric Andersen34506362001-08-02 05:02:46 +00004564 int errcode;
Eric Andersencb57d552001-06-28 07:25:16 +00004565 int result;
4566 int begoff;
4567 int quotes = flag & (EXP_FULL | EXP_CASE);
4568 int quoted;
4569
Eric Andersen2870d962001-07-02 17:27:21 +00004570 /* ifsfree(); */
Eric Andersencb57d552001-06-28 07:25:16 +00004571
4572 /*
4573 * This routine is slightly over-complicated for
4574 * efficiency. First we make sure there is
4575 * enough space for the result, which may be bigger
4576 * than the expression if we add exponentation. Next we
4577 * scan backwards looking for the start of arithmetic. If the
4578 * next previous character is a CTLESC character, then we
4579 * have to rescan starting from the beginning since CTLESC
4580 * characters have to be processed left to right.
4581 */
4582 CHECKSTRSPACE(10, expdest);
4583 USTPUTC('\0', expdest);
4584 start = stackblock();
4585 p = expdest - 1;
4586 while (*p != CTLARI && p >= start)
4587 --p;
4588 if (*p != CTLARI)
4589 error("missing CTLARI (shouldn't happen)");
4590 if (p > start && *(p-1) == CTLESC)
4591 for (p = start; *p != CTLARI; p++)
4592 if (*p == CTLESC)
4593 p++;
4594
4595 if (p[1] == '"')
4596 quoted=1;
4597 else
4598 quoted=0;
4599 begoff = p - start;
4600 removerecordregions(begoff);
4601 if (quotes)
4602 rmescapes(p+2);
Eric Andersen34506362001-08-02 05:02:46 +00004603 result = arith(p+2, &errcode);
4604 if (errcode < 0) {
4605 if(errcode == -2)
4606 error("divide by zero");
4607 else
4608 error("syntax error: \"%s\"\n", p+2);
4609 }
Eric Andersen3102ac42001-07-06 04:26:23 +00004610 snprintf(p, 12, "%d", result);
Eric Andersencb57d552001-06-28 07:25:16 +00004611
4612 while (*p++)
4613 ;
4614
4615 if (quoted == 0)
4616 recordregion(begoff, p - 1 - start, 0);
4617 result = expdest - p + 1;
4618 STADJUST(-result, expdest);
4619}
Eric Andersen2870d962001-07-02 17:27:21 +00004620#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004621
4622/*
4623 * Expand stuff in backwards quotes.
4624 */
4625
4626static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004627expbackq(union node *cmd, int quoted, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004628{
4629 volatile struct backcmd in;
4630 int i;
4631 char buf[128];
4632 char *p;
4633 char *dest = expdest;
4634 volatile struct ifsregion saveifs;
4635 struct ifsregion *volatile savelastp;
4636 struct nodelist *volatile saveargbackq;
4637 char lastc;
4638 int startloc = dest - stackblock();
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004639 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +00004640 volatile int saveherefd;
4641 int quotes = flag & (EXP_FULL | EXP_CASE);
4642 struct jmploc jmploc;
4643 struct jmploc *volatile savehandler;
4644 int ex;
4645
4646#if __GNUC__
4647 /* Avoid longjmp clobbering */
4648 (void) &dest;
4649 (void) &syntax;
4650#endif
4651
4652 in.fd = -1;
4653 in.buf = 0;
4654 in.jp = 0;
4655
4656 INTOFF;
4657 saveifs = ifsfirst;
4658 savelastp = ifslastp;
4659 saveargbackq = argbackq;
4660 saveherefd = herefd;
4661 herefd = -1;
4662 if ((ex = setjmp(jmploc.loc))) {
4663 goto err1;
4664 }
4665 savehandler = handler;
4666 handler = &jmploc;
4667 INTON;
4668 p = grabstackstr(dest);
4669 evalbackcmd(cmd, (struct backcmd *) &in);
4670 ungrabstackstr(p, dest);
4671err1:
4672 INTOFF;
4673 ifsfirst = saveifs;
4674 ifslastp = savelastp;
4675 argbackq = saveargbackq;
4676 herefd = saveherefd;
4677 if (ex) {
4678 goto err2;
4679 }
4680
4681 p = in.buf;
4682 lastc = '\0';
4683 for (;;) {
4684 if (--in.nleft < 0) {
4685 if (in.fd < 0)
4686 break;
Eric Andersen7467c8d2001-07-12 20:26:32 +00004687 i = safe_read(in.fd, buf, sizeof buf);
Eric Andersencb57d552001-06-28 07:25:16 +00004688 TRACE(("expbackq: read returns %d\n", i));
4689 if (i <= 0)
4690 break;
4691 p = buf;
4692 in.nleft = i - 1;
4693 }
4694 lastc = *p++;
4695 if (lastc != '\0') {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004696 if (quotes && SIT(lastc, syntax) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +00004697 STPUTC(CTLESC, dest);
4698 STPUTC(lastc, dest);
4699 }
4700 }
4701
4702 /* Eat all trailing newlines */
4703 for (; dest > stackblock() && dest[-1] == '\n';)
4704 STUNPUTC(dest);
4705
4706err2:
4707 if (in.fd >= 0)
4708 close(in.fd);
4709 if (in.buf)
4710 ckfree(in.buf);
4711 if (in.jp)
4712 exitstatus = waitforjob(in.jp);
4713 handler = savehandler;
4714 if (ex) {
4715 longjmp(handler->loc, 1);
4716 }
4717 if (quoted == 0)
4718 recordregion(startloc, dest - stackblock(), 0);
4719 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4720 (dest - stackblock()) - startloc,
4721 (dest - stackblock()) - startloc,
4722 stackblock() + startloc));
4723 expdest = dest;
4724 INTON;
4725}
4726
Eric Andersencb57d552001-06-28 07:25:16 +00004727static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004728subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
Eric Andersencb57d552001-06-28 07:25:16 +00004729{
4730 char *startp;
4731 char *loc = NULL;
4732 char *q;
4733 int c = 0;
4734 int saveherefd = herefd;
4735 struct nodelist *saveargbackq = argbackq;
4736 int amount;
4737
4738 herefd = -1;
4739 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
4740 STACKSTRNUL(expdest);
4741 herefd = saveherefd;
4742 argbackq = saveargbackq;
4743 startp = stackblock() + startloc;
4744 if (str == NULL)
4745 str = stackblock() + strloc;
4746
4747 switch (subtype) {
4748 case VSASSIGN:
4749 setvar(str, startp, 0);
4750 amount = startp - expdest;
4751 STADJUST(amount, expdest);
4752 varflags &= ~VSNUL;
4753 if (c != 0)
4754 *loc = c;
4755 return 1;
4756
4757 case VSQUESTION:
4758 if (*p != CTLENDVAR) {
Eric Andersen3102ac42001-07-06 04:26:23 +00004759 out2fmt(snlfmt, startp);
Eric Andersencb57d552001-06-28 07:25:16 +00004760 error((char *)NULL);
4761 }
4762 error("%.*s: parameter %snot set", p - str - 1,
4763 str, (varflags & VSNUL) ? "null or "
4764 : nullstr);
4765 /* NOTREACHED */
4766
4767 case VSTRIMLEFT:
4768 for (loc = startp; loc < str; loc++) {
4769 c = *loc;
4770 *loc = '\0';
4771 if (patmatch2(str, startp, quotes))
4772 goto recordleft;
4773 *loc = c;
4774 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00004775 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00004776 }
4777 return 0;
4778
4779 case VSTRIMLEFTMAX:
4780 for (loc = str - 1; loc >= startp;) {
4781 c = *loc;
4782 *loc = '\0';
4783 if (patmatch2(str, startp, quotes))
4784 goto recordleft;
4785 *loc = c;
4786 loc--;
4787 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
4788 for (q = startp; q < loc; q++)
4789 if (*q == CTLESC)
4790 q++;
4791 if (q > loc)
4792 loc--;
4793 }
4794 }
4795 return 0;
4796
4797 case VSTRIMRIGHT:
Eric Andersen2870d962001-07-02 17:27:21 +00004798 for (loc = str - 1; loc >= startp;) {
Eric Andersencb57d552001-06-28 07:25:16 +00004799 if (patmatch2(str, loc, quotes))
4800 goto recordright;
4801 loc--;
Eric Andersen2870d962001-07-02 17:27:21 +00004802 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
Eric Andersencb57d552001-06-28 07:25:16 +00004803 for (q = startp; q < loc; q++)
4804 if (*q == CTLESC)
4805 q++;
4806 if (q > loc)
4807 loc--;
4808 }
4809 }
4810 return 0;
4811
4812 case VSTRIMRIGHTMAX:
4813 for (loc = startp; loc < str - 1; loc++) {
4814 if (patmatch2(str, loc, quotes))
4815 goto recordright;
4816 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00004817 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00004818 }
4819 return 0;
4820
4821#ifdef DEBUG
4822 default:
4823 abort();
4824#endif
4825 }
4826
4827recordleft:
4828 *loc = c;
4829 amount = ((str - 1) - (loc - startp)) - expdest;
4830 STADJUST(amount, expdest);
4831 while (loc != str - 1)
4832 *startp++ = *loc++;
4833 return 1;
4834
4835recordright:
4836 amount = loc - expdest;
4837 STADJUST(amount, expdest);
4838 STPUTC('\0', expdest);
4839 STADJUST(-1, expdest);
4840 return 1;
4841}
4842
4843
4844/*
Eric Andersencb57d552001-06-28 07:25:16 +00004845 * Test whether a specialized variable is set.
4846 */
4847
4848static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004849varisset(char *name, int nulok)
Eric Andersencb57d552001-06-28 07:25:16 +00004850{
4851 if (*name == '!')
4852 return backgndpid != -1;
4853 else if (*name == '@' || *name == '*') {
4854 if (*shellparam.p == NULL)
4855 return 0;
4856
4857 if (nulok) {
4858 char **av;
4859
4860 for (av = shellparam.p; *av; av++)
4861 if (**av != '\0')
4862 return 1;
4863 return 0;
4864 }
4865 } else if (is_digit(*name)) {
4866 char *ap;
4867 int num = atoi(name);
4868
4869 if (num > shellparam.nparam)
4870 return 0;
4871
4872 if (num == 0)
4873 ap = arg0;
4874 else
4875 ap = shellparam.p[num - 1];
4876
4877 if (nulok && (ap == NULL || *ap == '\0'))
4878 return 0;
4879 }
4880 return 1;
4881}
4882
Eric Andersencb57d552001-06-28 07:25:16 +00004883/*
4884 * Put a string on the stack.
4885 */
4886
4887static void
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004888strtodest(const char *p, int syntax, int quotes)
Eric Andersencb57d552001-06-28 07:25:16 +00004889{
4890 while (*p) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004891 if (quotes && SIT(*p,syntax) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +00004892 STPUTC(CTLESC, expdest);
4893 STPUTC(*p++, expdest);
4894 }
4895}
4896
Eric Andersencb57d552001-06-28 07:25:16 +00004897/*
4898 * Add the value of a specialized variable to the stack string.
4899 */
4900
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004901static inline void
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004902varvalue(char *name, int quoted, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00004903{
4904 int num;
4905 char *p;
4906 int i;
4907 int sep;
4908 int sepq = 0;
4909 char **ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004910 int syntax;
Eric Andersencb57d552001-06-28 07:25:16 +00004911 int allow_split = flags & EXP_FULL;
4912 int quotes = flags & (EXP_FULL | EXP_CASE);
4913
4914 syntax = quoted ? DQSYNTAX : BASESYNTAX;
4915 switch (*name) {
4916 case '$':
4917 num = rootpid;
4918 goto numvar;
4919 case '?':
4920 num = oexitstatus;
4921 goto numvar;
4922 case '#':
4923 num = shellparam.nparam;
4924 goto numvar;
4925 case '!':
4926 num = backgndpid;
4927numvar:
4928 expdest = cvtnum(num, expdest);
4929 break;
4930 case '-':
4931 for (i = 0 ; i < NOPTS ; i++) {
Eric Andersen2870d962001-07-02 17:27:21 +00004932 if (optent_val(i))
4933 STPUTC(optent_letter(optlist[i]), expdest);
Eric Andersencb57d552001-06-28 07:25:16 +00004934 }
4935 break;
4936 case '@':
4937 if (allow_split && quoted) {
4938 sep = 1 << CHAR_BIT;
4939 goto param;
4940 }
4941 /* fall through */
4942 case '*':
4943 sep = ifsset() ? ifsval()[0] : ' ';
4944 if (quotes) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004945 sepq = SIT(sep,syntax) == CCTL;
Eric Andersencb57d552001-06-28 07:25:16 +00004946 }
4947param:
4948 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
4949 strtodest(p, syntax, quotes);
4950 if (*ap && sep) {
4951 if (sepq)
4952 STPUTC(CTLESC, expdest);
4953 STPUTC(sep, expdest);
4954 }
4955 }
4956 break;
4957 case '0':
4958 strtodest(arg0, syntax, quotes);
4959 break;
4960 default:
4961 num = atoi(name);
4962 if (num > 0 && num <= shellparam.nparam) {
4963 strtodest(shellparam.p[num - 1], syntax, quotes);
4964 }
4965 break;
4966 }
4967}
4968
4969
Eric Andersencb57d552001-06-28 07:25:16 +00004970/*
4971 * Record the fact that we have to scan this region of the
4972 * string for IFS characters.
4973 */
4974
4975static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004976recordregion(int start, int end, int nulonly)
Eric Andersencb57d552001-06-28 07:25:16 +00004977{
4978 struct ifsregion *ifsp;
4979
4980 if (ifslastp == NULL) {
4981 ifsp = &ifsfirst;
4982 } else {
4983 INTOFF;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004984 ifsp = (struct ifsregion *)xmalloc(sizeof (struct ifsregion));
Eric Andersencb57d552001-06-28 07:25:16 +00004985 ifsp->next = NULL;
4986 ifslastp->next = ifsp;
4987 INTON;
4988 }
4989 ifslastp = ifsp;
4990 ifslastp->begoff = start;
4991 ifslastp->endoff = end;
4992 ifslastp->nulonly = nulonly;
4993}
4994
4995
4996
4997/*
4998 * Break the argument string into pieces based upon IFS and add the
4999 * strings to the argument list. The regions of the string to be
5000 * searched for IFS characters have been stored by recordregion.
5001 */
5002static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005003ifsbreakup(char *string, struct arglist *arglist)
5004{
Eric Andersencb57d552001-06-28 07:25:16 +00005005 struct ifsregion *ifsp;
5006 struct strlist *sp;
5007 char *start;
5008 char *p;
5009 char *q;
5010 const char *ifs, *realifs;
5011 int ifsspc;
5012 int nulonly;
5013
5014
5015 start = string;
5016 ifsspc = 0;
5017 nulonly = 0;
5018 realifs = ifsset() ? ifsval() : defifs;
5019 if (ifslastp != NULL) {
5020 ifsp = &ifsfirst;
5021 do {
5022 p = string + ifsp->begoff;
5023 nulonly = ifsp->nulonly;
5024 ifs = nulonly ? nullstr : realifs;
5025 ifsspc = 0;
5026 while (p < string + ifsp->endoff) {
5027 q = p;
5028 if (*p == CTLESC)
5029 p++;
5030 if (strchr(ifs, *p)) {
5031 if (!nulonly)
5032 ifsspc = (strchr(defifs, *p) != NULL);
5033 /* Ignore IFS whitespace at start */
5034 if (q == start && ifsspc) {
5035 p++;
5036 start = p;
5037 continue;
5038 }
5039 *q = '\0';
5040 sp = (struct strlist *)stalloc(sizeof *sp);
5041 sp->text = start;
5042 *arglist->lastp = sp;
5043 arglist->lastp = &sp->next;
5044 p++;
5045 if (!nulonly) {
5046 for (;;) {
5047 if (p >= string + ifsp->endoff) {
5048 break;
5049 }
5050 q = p;
5051 if (*p == CTLESC)
5052 p++;
5053 if (strchr(ifs, *p) == NULL ) {
5054 p = q;
5055 break;
5056 } else if (strchr(defifs, *p) == NULL) {
5057 if (ifsspc) {
5058 p++;
5059 ifsspc = 0;
5060 } else {
5061 p = q;
5062 break;
5063 }
5064 } else
5065 p++;
5066 }
5067 }
5068 start = p;
5069 } else
5070 p++;
5071 }
5072 } while ((ifsp = ifsp->next) != NULL);
5073 if (!(*start || (!ifsspc && start > string && nulonly))) {
5074 return;
5075 }
5076 }
5077
5078 sp = (struct strlist *)stalloc(sizeof *sp);
5079 sp->text = start;
5080 *arglist->lastp = sp;
5081 arglist->lastp = &sp->next;
5082}
5083
5084static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005085ifsfree(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005086{
5087 while (ifsfirst.next != NULL) {
5088 struct ifsregion *ifsp;
5089 INTOFF;
5090 ifsp = ifsfirst.next->next;
5091 ckfree(ifsfirst.next);
5092 ifsfirst.next = ifsp;
5093 INTON;
5094 }
5095 ifslastp = NULL;
5096 ifsfirst.next = NULL;
5097}
5098
Eric Andersen2870d962001-07-02 17:27:21 +00005099/*
5100 * Add a file name to the list.
5101 */
Eric Andersencb57d552001-06-28 07:25:16 +00005102
Eric Andersen2870d962001-07-02 17:27:21 +00005103static void
5104addfname(const char *name)
5105{
Eric Andersen2870d962001-07-02 17:27:21 +00005106 struct strlist *sp;
5107
Eric Andersen2870d962001-07-02 17:27:21 +00005108 sp = (struct strlist *)stalloc(sizeof *sp);
Aaron Lehmann95877b62001-12-31 06:00:57 +00005109 sp->text = sstrdup(name);
Eric Andersen2870d962001-07-02 17:27:21 +00005110 *exparg.lastp = sp;
5111 exparg.lastp = &sp->next;
5112}
Eric Andersencb57d552001-06-28 07:25:16 +00005113
5114/*
5115 * Expand shell metacharacters. At this point, the only control characters
5116 * should be escapes. The results are stored in the list exparg.
5117 */
5118
Eric Andersen62483552001-07-10 06:09:16 +00005119#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00005120static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005121expandmeta(struct strlist *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005122{
5123 const char *p;
5124 glob_t pglob;
5125 /* TODO - EXP_REDIR */
5126
5127 while (str) {
5128 if (fflag)
5129 goto nometa;
5130 p = preglob(str->text);
5131 INTOFF;
Eric Andersen34506362001-08-02 05:02:46 +00005132 switch (glob(p, 0, 0, &pglob)) {
Eric Andersencb57d552001-06-28 07:25:16 +00005133 case 0:
Eric Andersen34506362001-08-02 05:02:46 +00005134 if(pglob.gl_pathv[1]==0 && !strcmp(p, pglob.gl_pathv[0]))
Eric Andersencb57d552001-06-28 07:25:16 +00005135 goto nometa2;
5136 addglob(&pglob);
5137 globfree(&pglob);
5138 INTON;
5139 break;
5140 case GLOB_NOMATCH:
5141nometa2:
5142 globfree(&pglob);
5143 INTON;
5144nometa:
5145 *exparg.lastp = str;
5146 rmescapes(str->text);
5147 exparg.lastp = &str->next;
5148 break;
Eric Andersen2870d962001-07-02 17:27:21 +00005149 default: /* GLOB_NOSPACE */
Eric Andersencb57d552001-06-28 07:25:16 +00005150 error("Out of space");
5151 }
5152 str = str->next;
5153 }
5154}
5155
5156
5157/*
5158 * Add the result of glob(3) to the list.
5159 */
5160
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005161static inline void
5162addglob(const glob_t *pglob)
Eric Andersencb57d552001-06-28 07:25:16 +00005163{
5164 char **p = pglob->gl_pathv;
5165
5166 do {
5167 addfname(*p);
5168 } while (*++p);
5169}
5170
5171
Eric Andersen2870d962001-07-02 17:27:21 +00005172#else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005173static char *expdir;
5174
5175
5176static void
Eric Andersenceef50b2001-12-21 11:22:26 +00005177expandmeta(struct strlist *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005178{
5179 char *p;
5180 struct strlist **savelastp;
5181 struct strlist *sp;
5182 char c;
5183 /* TODO - EXP_REDIR */
5184
5185 while (str) {
5186 if (fflag)
5187 goto nometa;
5188 p = str->text;
Eric Andersen2870d962001-07-02 17:27:21 +00005189 for (;;) { /* fast check for meta chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005190 if ((c = *p++) == '\0')
5191 goto nometa;
5192 if (c == '*' || c == '?' || c == '[' || c == '!')
5193 break;
5194 }
5195 savelastp = exparg.lastp;
5196 INTOFF;
5197 if (expdir == NULL) {
5198 int i = strlen(str->text);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005199 expdir = xmalloc(i < 2048 ? 2048 : i); /* XXX */
Eric Andersencb57d552001-06-28 07:25:16 +00005200 }
5201
5202 expmeta(expdir, str->text);
5203 ckfree(expdir);
5204 expdir = NULL;
5205 INTON;
5206 if (exparg.lastp == savelastp) {
5207 /*
5208 * no matches
5209 */
5210nometa:
5211 *exparg.lastp = str;
5212 rmescapes(str->text);
5213 exparg.lastp = &str->next;
5214 } else {
5215 *exparg.lastp = NULL;
5216 *savelastp = sp = expsort(*savelastp);
5217 while (sp->next != NULL)
5218 sp = sp->next;
5219 exparg.lastp = &sp->next;
5220 }
5221 str = str->next;
5222 }
5223}
5224
5225
5226/*
5227 * Do metacharacter (i.e. *, ?, [...]) expansion.
5228 */
5229
5230static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005231expmeta(char *enddir, char *name)
5232{
Eric Andersencb57d552001-06-28 07:25:16 +00005233 char *p;
5234 const char *cp;
5235 char *q;
5236 char *start;
5237 char *endname;
5238 int metaflag;
5239 struct stat statb;
5240 DIR *dirp;
5241 struct dirent *dp;
5242 int atend;
5243 int matchdot;
5244
5245 metaflag = 0;
5246 start = name;
5247 for (p = name ; ; p++) {
5248 if (*p == '*' || *p == '?')
5249 metaflag = 1;
5250 else if (*p == '[') {
5251 q = p + 1;
5252 if (*q == '!')
5253 q++;
5254 for (;;) {
5255 while (*q == CTLQUOTEMARK)
5256 q++;
5257 if (*q == CTLESC)
5258 q++;
5259 if (*q == '/' || *q == '\0')
5260 break;
5261 if (*++q == ']') {
5262 metaflag = 1;
5263 break;
5264 }
5265 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005266 } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) {
Eric Andersencb57d552001-06-28 07:25:16 +00005267 metaflag = 1;
5268 } else if (*p == '\0')
5269 break;
5270 else if (*p == CTLQUOTEMARK)
5271 continue;
5272 else if (*p == CTLESC)
5273 p++;
5274 if (*p == '/') {
5275 if (metaflag)
5276 break;
5277 start = p + 1;
5278 }
5279 }
Eric Andersen2870d962001-07-02 17:27:21 +00005280 if (metaflag == 0) { /* we've reached the end of the file name */
Eric Andersencb57d552001-06-28 07:25:16 +00005281 if (enddir != expdir)
5282 metaflag++;
5283 for (p = name ; ; p++) {
5284 if (*p == CTLQUOTEMARK)
5285 continue;
5286 if (*p == CTLESC)
5287 p++;
5288 *enddir++ = *p;
5289 if (*p == '\0')
5290 break;
5291 }
5292 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5293 addfname(expdir);
5294 return;
5295 }
5296 endname = p;
5297 if (start != name) {
5298 p = name;
5299 while (p < start) {
5300 while (*p == CTLQUOTEMARK)
5301 p++;
5302 if (*p == CTLESC)
5303 p++;
5304 *enddir++ = *p++;
5305 }
5306 }
5307 if (enddir == expdir) {
5308 cp = ".";
5309 } else if (enddir == expdir + 1 && *expdir == '/') {
5310 cp = "/";
5311 } else {
5312 cp = expdir;
5313 enddir[-1] = '\0';
5314 }
5315 if ((dirp = opendir(cp)) == NULL)
5316 return;
5317 if (enddir != expdir)
5318 enddir[-1] = '/';
5319 if (*endname == 0) {
5320 atend = 1;
5321 } else {
5322 atend = 0;
5323 *endname++ = '\0';
5324 }
5325 matchdot = 0;
5326 p = start;
5327 while (*p == CTLQUOTEMARK)
5328 p++;
5329 if (*p == CTLESC)
5330 p++;
5331 if (*p == '.')
5332 matchdot++;
5333 while (! int_pending() && (dp = readdir(dirp)) != NULL) {
5334 if (dp->d_name[0] == '.' && ! matchdot)
5335 continue;
5336 if (patmatch(start, dp->d_name, 0)) {
5337 if (atend) {
Eric Andersen2870d962001-07-02 17:27:21 +00005338 strcpy(enddir, dp->d_name);
Eric Andersencb57d552001-06-28 07:25:16 +00005339 addfname(expdir);
5340 } else {
5341 for (p = enddir, cp = dp->d_name;
5342 (*p++ = *cp++) != '\0';)
5343 continue;
5344 p[-1] = '/';
5345 expmeta(p, endname);
5346 }
5347 }
5348 }
5349 closedir(dirp);
5350 if (! atend)
5351 endname[-1] = '/';
5352}
Eric Andersen2870d962001-07-02 17:27:21 +00005353#endif /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005354
5355
Eric Andersencb57d552001-06-28 07:25:16 +00005356
Eric Andersen62483552001-07-10 06:09:16 +00005357#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersencb57d552001-06-28 07:25:16 +00005358/*
5359 * Sort the results of file name expansion. It calculates the number of
5360 * strings to sort and then calls msort (short for merge sort) to do the
5361 * work.
5362 */
5363
5364static struct strlist *
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005365expsort(struct strlist *str)
5366{
Eric Andersencb57d552001-06-28 07:25:16 +00005367 int len;
5368 struct strlist *sp;
5369
5370 len = 0;
5371 for (sp = str ; sp ; sp = sp->next)
5372 len++;
5373 return msort(str, len);
5374}
5375
5376
5377static struct strlist *
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005378msort(struct strlist *list, int len)
Eric Andersencb57d552001-06-28 07:25:16 +00005379{
5380 struct strlist *p, *q = NULL;
5381 struct strlist **lpp;
5382 int half;
5383 int n;
5384
5385 if (len <= 1)
5386 return list;
5387 half = len >> 1;
5388 p = list;
5389 for (n = half ; --n >= 0 ; ) {
5390 q = p;
5391 p = p->next;
5392 }
Eric Andersen2870d962001-07-02 17:27:21 +00005393 q->next = NULL; /* terminate first half of list */
5394 q = msort(list, half); /* sort first half of list */
5395 p = msort(p, len - half); /* sort second half */
Eric Andersencb57d552001-06-28 07:25:16 +00005396 lpp = &list;
5397 for (;;) {
5398 if (strcmp(p->text, q->text) < 0) {
5399 *lpp = p;
5400 lpp = &p->next;
5401 if ((p = *lpp) == NULL) {
5402 *lpp = q;
5403 break;
5404 }
5405 } else {
5406 *lpp = q;
5407 lpp = &q->next;
5408 if ((q = *lpp) == NULL) {
5409 *lpp = p;
5410 break;
5411 }
5412 }
5413 }
5414 return list;
5415}
5416#endif
5417
5418
5419
5420/*
5421 * Returns true if the pattern matches the string.
5422 */
5423
Eric Andersen62483552001-07-10 06:09:16 +00005424#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00005425/* squoted: string might have quote chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005426static int
Eric Andersen2870d962001-07-02 17:27:21 +00005427patmatch(char *pattern, char *string, int squoted)
5428{
Eric Andersencb57d552001-06-28 07:25:16 +00005429 const char *p;
5430 char *q;
5431
5432 p = preglob(pattern);
5433 q = squoted ? _rmescapes(string, RMESCAPE_ALLOC) : string;
5434
5435 return !fnmatch(p, q, 0);
5436}
5437
5438
5439static int
Eric Andersen2870d962001-07-02 17:27:21 +00005440patmatch2(char *pattern, char *string, int squoted)
5441{
Eric Andersencb57d552001-06-28 07:25:16 +00005442 char *p;
5443 int res;
5444
5445 sstrnleft--;
5446 p = grabstackstr(expdest);
5447 res = patmatch(pattern, string, squoted);
5448 ungrabstackstr(p, expdest);
5449 return res;
5450}
5451#else
5452static int
Eric Andersen2870d962001-07-02 17:27:21 +00005453patmatch(char *pattern, char *string, int squoted) {
5454 return pmatch(pattern, string, squoted);
Eric Andersencb57d552001-06-28 07:25:16 +00005455}
5456
5457
5458static int
Eric Andersen2870d962001-07-02 17:27:21 +00005459pmatch(char *pattern, char *string, int squoted)
5460{
Eric Andersencb57d552001-06-28 07:25:16 +00005461 char *p, *q;
5462 char c;
5463
5464 p = pattern;
5465 q = string;
5466 for (;;) {
5467 switch (c = *p++) {
5468 case '\0':
5469 goto breakloop;
5470 case CTLESC:
5471 if (squoted && *q == CTLESC)
5472 q++;
5473 if (*q++ != *p++)
5474 return 0;
5475 break;
5476 case CTLQUOTEMARK:
5477 continue;
5478 case '?':
5479 if (squoted && *q == CTLESC)
5480 q++;
5481 if (*q++ == '\0')
5482 return 0;
5483 break;
5484 case '*':
5485 c = *p;
5486 while (c == CTLQUOTEMARK || c == '*')
5487 c = *++p;
5488 if (c != CTLESC && c != CTLQUOTEMARK &&
5489 c != '?' && c != '*' && c != '[') {
5490 while (*q != c) {
5491 if (squoted && *q == CTLESC &&
5492 q[1] == c)
5493 break;
5494 if (*q == '\0')
5495 return 0;
5496 if (squoted && *q == CTLESC)
5497 q++;
5498 q++;
5499 }
5500 }
5501 do {
5502 if (pmatch(p, q, squoted))
5503 return 1;
5504 if (squoted && *q == CTLESC)
5505 q++;
5506 } while (*q++ != '\0');
5507 return 0;
5508 case '[': {
5509 char *endp;
5510 int invert, found;
5511 char chr;
5512
5513 endp = p;
5514 if (*endp == '!')
5515 endp++;
5516 for (;;) {
5517 while (*endp == CTLQUOTEMARK)
5518 endp++;
5519 if (*endp == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00005520 goto dft; /* no matching ] */
Eric Andersencb57d552001-06-28 07:25:16 +00005521 if (*endp == CTLESC)
5522 endp++;
5523 if (*++endp == ']')
5524 break;
5525 }
5526 invert = 0;
5527 if (*p == '!') {
5528 invert++;
5529 p++;
5530 }
5531 found = 0;
5532 chr = *q++;
5533 if (squoted && chr == CTLESC)
5534 chr = *q++;
5535 if (chr == '\0')
5536 return 0;
5537 c = *p++;
5538 do {
5539 if (c == CTLQUOTEMARK)
5540 continue;
5541 if (c == CTLESC)
5542 c = *p++;
5543 if (*p == '-' && p[1] != ']') {
5544 p++;
5545 while (*p == CTLQUOTEMARK)
5546 p++;
5547 if (*p == CTLESC)
5548 p++;
5549 if (chr >= c && chr <= *p)
5550 found = 1;
5551 p++;
5552 } else {
5553 if (chr == c)
5554 found = 1;
5555 }
5556 } while ((c = *p++) != ']');
5557 if (found == invert)
5558 return 0;
5559 break;
5560 }
Eric Andersen2870d962001-07-02 17:27:21 +00005561dft: default:
Eric Andersencb57d552001-06-28 07:25:16 +00005562 if (squoted && *q == CTLESC)
5563 q++;
5564 if (*q++ != c)
5565 return 0;
5566 break;
5567 }
5568 }
5569breakloop:
5570 if (*q != '\0')
5571 return 0;
5572 return 1;
5573}
5574#endif
5575
5576
5577
5578/*
5579 * Remove any CTLESC characters from a string.
5580 */
5581
Eric Andersen62483552001-07-10 06:09:16 +00005582#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00005583static char *
Eric Andersen2870d962001-07-02 17:27:21 +00005584_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005585{
5586 char *p, *q, *r;
5587 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5588
5589 p = strpbrk(str, qchars);
5590 if (!p) {
5591 return str;
5592 }
5593 q = p;
5594 r = str;
5595 if (flag & RMESCAPE_ALLOC) {
5596 size_t len = p - str;
5597 q = r = stalloc(strlen(p) + len + 1);
5598 if (len > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00005599 memcpy(q, str, len);
5600 q += len;
Eric Andersencb57d552001-06-28 07:25:16 +00005601 }
5602 }
5603 while (*p) {
5604 if (*p == CTLQUOTEMARK) {
5605 p++;
5606 continue;
5607 }
5608 if (*p == CTLESC) {
5609 p++;
5610 if (flag & RMESCAPE_GLOB && *p != '/') {
5611 *q++ = '\\';
5612 }
5613 }
5614 *q++ = *p++;
5615 }
5616 *q = '\0';
5617 return r;
5618}
5619#else
5620static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005621rmescapes(char *str)
Eric Andersencb57d552001-06-28 07:25:16 +00005622{
5623 char *p, *q;
5624
5625 p = str;
5626 while (*p != CTLESC && *p != CTLQUOTEMARK) {
5627 if (*p++ == '\0')
5628 return;
5629 }
5630 q = p;
5631 while (*p) {
5632 if (*p == CTLQUOTEMARK) {
5633 p++;
5634 continue;
5635 }
5636 if (*p == CTLESC)
5637 p++;
5638 *q++ = *p++;
5639 }
5640 *q = '\0';
5641}
5642#endif
5643
5644
5645
5646/*
5647 * See if a pattern matches in a case statement.
5648 */
5649
5650static int
Eric Andersen2870d962001-07-02 17:27:21 +00005651casematch(union node *pattern, const char *val)
5652{
Eric Andersencb57d552001-06-28 07:25:16 +00005653 struct stackmark smark;
5654 int result;
5655 char *p;
5656
5657 setstackmark(&smark);
5658 argbackq = pattern->narg.backquote;
5659 STARTSTACKSTR(expdest);
5660 ifslastp = NULL;
5661 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5662 STPUTC('\0', expdest);
5663 p = grabstackstr(expdest);
Eric Andersen2870d962001-07-02 17:27:21 +00005664 result = patmatch(p, (char *)val, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00005665 popstackmark(&smark);
5666 return result;
5667}
5668
5669/*
5670 * Our own itoa().
5671 */
5672
5673static char *
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005674cvtnum(int num, char *buf)
5675{
Eric Andersencb57d552001-06-28 07:25:16 +00005676 int len;
5677
5678 CHECKSTRSPACE(32, buf);
5679 len = sprintf(buf, "%d", num);
5680 STADJUST(len, buf);
5681 return buf;
5682}
Eric Andersencb57d552001-06-28 07:25:16 +00005683/*
5684 * Editline and history functions (and glue).
5685 */
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005686static int histcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00005687{
5688 error("not compiled with history support");
5689 /* NOTREACHED */
5690}
5691
5692
Eric Andersencb57d552001-06-28 07:25:16 +00005693struct redirtab {
5694 struct redirtab *next;
Russ Dill4db35642001-07-26 05:58:40 +00005695 short renamed[10]; /* Current ash support only 0-9 descriptors */
Eric Andersen34506362001-08-02 05:02:46 +00005696 /* char on arm (and others) can't be negative */
Eric Andersencb57d552001-06-28 07:25:16 +00005697};
5698
Eric Andersen2870d962001-07-02 17:27:21 +00005699static struct redirtab *redirlist;
Eric Andersencb57d552001-06-28 07:25:16 +00005700
5701extern char **environ;
5702
5703
5704
5705/*
5706 * Initialization code.
5707 */
5708
5709static void
Eric Andersen2870d962001-07-02 17:27:21 +00005710init(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00005711
5712 /* from cd.c: */
5713 {
Eric Andersena3483db2001-10-24 08:01:06 +00005714 curdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00005715 setpwd(0, 0);
5716 }
5717
5718 /* from input.c: */
5719 {
5720 basepf.nextc = basepf.buf = basebuf;
5721 }
5722
Eric Andersencb57d552001-06-28 07:25:16 +00005723 /* from var.c: */
5724 {
5725 char **envp;
5726 char ppid[32];
5727
5728 initvar();
5729 for (envp = environ ; *envp ; envp++) {
5730 if (strchr(*envp, '=')) {
5731 setvareq(*envp, VEXPORT|VTEXTFIXED);
5732 }
5733 }
5734
Eric Andersen3102ac42001-07-06 04:26:23 +00005735 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
Eric Andersencb57d552001-06-28 07:25:16 +00005736 setvar("PPID", ppid, 0);
5737 }
5738}
5739
5740
5741
5742/*
5743 * This routine is called when an error or an interrupt occurs in an
5744 * interactive shell and control is returned to the main command loop.
5745 */
5746
Eric Andersen2870d962001-07-02 17:27:21 +00005747/* 1 == check for aliases, 2 == also check for assignments */
Eric Andersen7467c8d2001-07-12 20:26:32 +00005748static int checkalias; /* also used in no alias mode for check assignments */
Eric Andersen2870d962001-07-02 17:27:21 +00005749
Eric Andersencb57d552001-06-28 07:25:16 +00005750static void
Eric Andersen2870d962001-07-02 17:27:21 +00005751reset(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00005752
5753 /* from eval.c: */
5754 {
5755 evalskip = 0;
5756 loopnest = 0;
5757 funcnest = 0;
5758 }
5759
5760 /* from input.c: */
5761 {
5762 if (exception != EXSHELLPROC)
Eric Andersen2870d962001-07-02 17:27:21 +00005763 parselleft = parsenleft = 0; /* clear input buffer */
Eric Andersencb57d552001-06-28 07:25:16 +00005764 popallfiles();
5765 }
5766
5767 /* from parser.c: */
5768 {
5769 tokpushback = 0;
5770 checkkwd = 0;
5771 checkalias = 0;
5772 }
5773
5774 /* from redir.c: */
5775 {
5776 while (redirlist)
5777 popredir();
5778 }
5779
Eric Andersencb57d552001-06-28 07:25:16 +00005780}
5781
5782
5783
5784/*
Eric Andersencb57d552001-06-28 07:25:16 +00005785 * This file implements the input routines used by the parser.
5786 */
5787
Eric Andersenbdfd0d72001-10-24 05:00:29 +00005788#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersencb57d552001-06-28 07:25:16 +00005789static const char * cmdedit_prompt;
5790static inline void putprompt(const char *s) {
5791 cmdedit_prompt = s;
5792}
5793#else
5794static inline void putprompt(const char *s) {
5795 out2str(s);
5796}
5797#endif
5798
Eric Andersen2870d962001-07-02 17:27:21 +00005799#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
Eric Andersencb57d552001-06-28 07:25:16 +00005800
Eric Andersencb57d552001-06-28 07:25:16 +00005801
Eric Andersencb57d552001-06-28 07:25:16 +00005802
Eric Andersen2870d962001-07-02 17:27:21 +00005803/*
5804 * Same as pgetc(), but ignores PEOA.
5805 */
Eric Andersencb57d552001-06-28 07:25:16 +00005806
Eric Andersend35c5df2002-01-09 15:37:36 +00005807#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00005808static int
Eric Andersen74400cc2001-10-18 04:11:39 +00005809pgetc2(void)
Eric Andersen2870d962001-07-02 17:27:21 +00005810{
5811 int c;
5812 do {
5813 c = pgetc_macro();
5814 } while (c == PEOA);
5815 return c;
Eric Andersencb57d552001-06-28 07:25:16 +00005816}
Eric Andersen2870d962001-07-02 17:27:21 +00005817#else
Eric Andersend35c5df2002-01-09 15:37:36 +00005818static inline int pgetc2(void) { return pgetc_macro(); }
Eric Andersencb57d552001-06-28 07:25:16 +00005819#endif
5820
Eric Andersencb57d552001-06-28 07:25:16 +00005821/*
5822 * Read a line from the script.
5823 */
5824
Eric Andersen62483552001-07-10 06:09:16 +00005825static inline char *
Eric Andersen2870d962001-07-02 17:27:21 +00005826pfgets(char *line, int len)
Eric Andersencb57d552001-06-28 07:25:16 +00005827{
5828 char *p = line;
5829 int nleft = len;
5830 int c;
5831
5832 while (--nleft > 0) {
5833 c = pgetc2();
5834 if (c == PEOF) {
5835 if (p == line)
5836 return NULL;
5837 break;
5838 }
5839 *p++ = c;
5840 if (c == '\n')
5841 break;
5842 }
5843 *p = '\0';
5844 return line;
5845}
5846
Eric Andersen62483552001-07-10 06:09:16 +00005847static inline int
Eric Andersen2870d962001-07-02 17:27:21 +00005848preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005849{
5850 int nr;
5851 char *buf = parsefile->buf;
5852 parsenextc = buf;
5853
5854retry:
Eric Andersenbdfd0d72001-10-24 05:00:29 +00005855#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersencb57d552001-06-28 07:25:16 +00005856 {
Eric Andersen34506362001-08-02 05:02:46 +00005857 if (!iflag || parsefile->fd)
Eric Andersen7467c8d2001-07-12 20:26:32 +00005858 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersen2870d962001-07-02 17:27:21 +00005859 else {
Eric Andersen044228d2001-07-17 01:12:36 +00005860 nr = cmdedit_read_input((char*)cmdedit_prompt, buf);
Eric Andersencb57d552001-06-28 07:25:16 +00005861 }
5862 }
5863#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00005864 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00005865#endif
5866
5867 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00005868 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
5869 int flags = fcntl(0, F_GETFL, 0);
5870 if (flags >= 0 && flags & O_NONBLOCK) {
5871 flags &=~ O_NONBLOCK;
5872 if (fcntl(0, F_SETFL, flags) >= 0) {
5873 out2str("sh: turning off NDELAY mode\n");
5874 goto retry;
5875 }
5876 }
5877 }
5878 }
5879 return nr;
5880}
5881
Eric Andersen2870d962001-07-02 17:27:21 +00005882static void
5883popstring(void)
5884{
5885 struct strpush *sp = parsefile->strpush;
5886
5887 INTOFF;
Eric Andersend35c5df2002-01-09 15:37:36 +00005888#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00005889 if (sp->ap) {
5890 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
5891 if (!checkalias) {
5892 checkalias = 1;
5893 }
5894 }
5895 if (sp->string != sp->ap->val) {
5896 ckfree(sp->string);
5897 }
5898
5899 sp->ap->flag &= ~ALIASINUSE;
5900 if (sp->ap->flag & ALIASDEAD) {
5901 unalias(sp->ap->name);
5902 }
5903 }
5904#endif
5905 parsenextc = sp->prevstring;
5906 parsenleft = sp->prevnleft;
5907/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
5908 parsefile->strpush = sp->prev;
5909 if (sp != &(parsefile->basestrpush))
5910 ckfree(sp);
5911 INTON;
5912}
5913
5914
Eric Andersencb57d552001-06-28 07:25:16 +00005915/*
5916 * Refill the input buffer and return the next input character:
5917 *
5918 * 1) If a string was pushed back on the input, pop it;
5919 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
5920 * from a string so we can't refill the buffer, return EOF.
5921 * 3) If the is more stuff in this buffer, use it else call read to fill it.
5922 * 4) Process input up to the next newline, deleting nul characters.
5923 */
5924
5925static int
Eric Andersen2870d962001-07-02 17:27:21 +00005926preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005927{
5928 char *p, *q;
5929 int more;
5930 char savec;
5931
5932 while (parsefile->strpush) {
Eric Andersend35c5df2002-01-09 15:37:36 +00005933#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00005934 if (parsenleft == -1 && parsefile->strpush->ap &&
5935 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00005936 return PEOA;
5937 }
Eric Andersen2870d962001-07-02 17:27:21 +00005938#endif
Eric Andersencb57d552001-06-28 07:25:16 +00005939 popstring();
5940 if (--parsenleft >= 0)
5941 return (*parsenextc++);
5942 }
5943 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
5944 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00005945 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00005946
5947again:
5948 if (parselleft <= 0) {
5949 if ((parselleft = preadfd()) <= 0) {
5950 parselleft = parsenleft = EOF_NLEFT;
5951 return PEOF;
5952 }
5953 }
5954
5955 q = p = parsenextc;
5956
5957 /* delete nul characters */
5958 for (more = 1; more;) {
5959 switch (*p) {
5960 case '\0':
Eric Andersen2870d962001-07-02 17:27:21 +00005961 p++; /* Skip nul */
Eric Andersencb57d552001-06-28 07:25:16 +00005962 goto check;
5963
5964
5965 case '\n':
5966 parsenleft = q - parsenextc;
5967 more = 0; /* Stop processing here */
5968 break;
5969 }
5970
5971 *q++ = *p++;
5972check:
5973 if (--parselleft <= 0 && more) {
5974 parsenleft = q - parsenextc - 1;
5975 if (parsenleft < 0)
5976 goto again;
5977 more = 0;
5978 }
5979 }
5980
5981 savec = *q;
5982 *q = '\0';
5983
5984 if (vflag) {
5985 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00005986 }
5987
5988 *q = savec;
5989
5990 return *parsenextc++;
5991}
5992
Eric Andersencb57d552001-06-28 07:25:16 +00005993
5994/*
5995 * Push a string back onto the input at this current parsefile level.
5996 * We handle aliases this way.
5997 */
5998static void
Eric Andersen2870d962001-07-02 17:27:21 +00005999pushstring(char *s, int len, void *ap)
6000{
Eric Andersencb57d552001-06-28 07:25:16 +00006001 struct strpush *sp;
6002
6003 INTOFF;
6004/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6005 if (parsefile->strpush) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006006 sp = xmalloc(sizeof (struct strpush));
Eric Andersencb57d552001-06-28 07:25:16 +00006007 sp->prev = parsefile->strpush;
6008 parsefile->strpush = sp;
6009 } else
6010 sp = parsefile->strpush = &(parsefile->basestrpush);
6011 sp->prevstring = parsenextc;
6012 sp->prevnleft = parsenleft;
Eric Andersend35c5df2002-01-09 15:37:36 +00006013#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00006014 sp->ap = (struct alias *)ap;
6015 if (ap) {
6016 ((struct alias *)ap)->flag |= ALIASINUSE;
6017 sp->string = s;
6018 }
Eric Andersen2870d962001-07-02 17:27:21 +00006019#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006020 parsenextc = s;
6021 parsenleft = len;
6022 INTON;
6023}
6024
Eric Andersencb57d552001-06-28 07:25:16 +00006025
Eric Andersencb57d552001-06-28 07:25:16 +00006026/*
6027 * Like setinputfile, but takes input from a string.
6028 */
6029
6030static void
Eric Andersen62483552001-07-10 06:09:16 +00006031setinputstring(char *string)
6032{
Eric Andersencb57d552001-06-28 07:25:16 +00006033 INTOFF;
6034 pushfile();
6035 parsenextc = string;
6036 parsenleft = strlen(string);
6037 parsefile->buf = NULL;
6038 plinno = 1;
6039 INTON;
6040}
6041
6042
6043
6044/*
6045 * To handle the "." command, a stack of input files is used. Pushfile
6046 * adds a new entry to the stack and popfile restores the previous level.
6047 */
6048
6049static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006050pushfile(void)
6051{
Eric Andersencb57d552001-06-28 07:25:16 +00006052 struct parsefile *pf;
6053
6054 parsefile->nleft = parsenleft;
6055 parsefile->lleft = parselleft;
6056 parsefile->nextc = parsenextc;
6057 parsefile->linno = plinno;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006058 pf = (struct parsefile *)xmalloc(sizeof (struct parsefile));
Eric Andersencb57d552001-06-28 07:25:16 +00006059 pf->prev = parsefile;
6060 pf->fd = -1;
6061 pf->strpush = NULL;
6062 pf->basestrpush.prev = NULL;
6063 parsefile = pf;
6064}
6065
Eric Andersend35c5df2002-01-09 15:37:36 +00006066#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen2870d962001-07-02 17:27:21 +00006067static void restartjob (struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00006068#endif
Eric Andersen2870d962001-07-02 17:27:21 +00006069static void freejob (struct job *);
6070static struct job *getjob (const char *);
6071static int dowait (int, struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00006072static void waitonint(int);
6073
6074
Eric Andersen2870d962001-07-02 17:27:21 +00006075/*
6076 * We keep track of whether or not fd0 has been redirected. This is for
6077 * background commands, where we want to redirect fd0 to /dev/null only
6078 * if it hasn't already been redirected.
6079*/
6080static int fd0_redirected = 0;
6081
6082/* Return true if fd 0 has already been redirected at least once. */
6083static inline int
Eric Andersen74400cc2001-10-18 04:11:39 +00006084fd0_redirected_p (void)
6085{
Eric Andersen2870d962001-07-02 17:27:21 +00006086 return fd0_redirected != 0;
6087}
6088
Eric Andersen62483552001-07-10 06:09:16 +00006089static void dupredirect (const union node *, int, int fd1dup);
Eric Andersen2870d962001-07-02 17:27:21 +00006090
Eric Andersend35c5df2002-01-09 15:37:36 +00006091#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006092/*
6093 * Turn job control on and off.
6094 *
6095 * Note: This code assumes that the third arg to ioctl is a character
6096 * pointer, which is true on Berkeley systems but not System V. Since
6097 * System V doesn't have job control yet, this isn't a problem now.
6098 */
6099
Eric Andersen2870d962001-07-02 17:27:21 +00006100
Eric Andersencb57d552001-06-28 07:25:16 +00006101
6102static void setjobctl(int enable)
6103{
6104#ifdef OLD_TTY_DRIVER
6105 int ldisc;
6106#endif
6107
6108 if (enable == jobctl || rootshell == 0)
6109 return;
6110 if (enable) {
6111 do { /* while we are in the background */
6112#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006113 if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006114#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006115 initialpgrp = tcgetpgrp(2);
Eric Andersencb57d552001-06-28 07:25:16 +00006116 if (initialpgrp < 0) {
6117#endif
Eric Andersen8c145dc2001-07-10 16:57:09 +00006118 out2str("sh: can't access tty; job control turned off\n");
Eric Andersencb57d552001-06-28 07:25:16 +00006119 mflag = 0;
6120 return;
6121 }
6122 if (initialpgrp == -1)
6123 initialpgrp = getpgrp();
6124 else if (initialpgrp != getpgrp()) {
6125 killpg(initialpgrp, SIGTTIN);
6126 continue;
6127 }
6128 } while (0);
6129#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006130 if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
Eric Andersen8c145dc2001-07-10 16:57:09 +00006131 out2str("sh: need new tty driver to run job control; job control turned off\n");
Eric Andersencb57d552001-06-28 07:25:16 +00006132 mflag = 0;
6133 return;
6134 }
6135#endif
6136 setsignal(SIGTSTP);
6137 setsignal(SIGTTOU);
6138 setsignal(SIGTTIN);
6139 setpgid(0, rootpid);
6140#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006141 ioctl(2, TIOCSPGRP, (char *)&rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00006142#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006143 tcsetpgrp(2, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00006144#endif
Eric Andersen8c145dc2001-07-10 16:57:09 +00006145 } else { /* turning job control off */
Eric Andersencb57d552001-06-28 07:25:16 +00006146 setpgid(0, initialpgrp);
6147#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006148 ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006149#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006150 tcsetpgrp(2, initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006151#endif
6152 setsignal(SIGTSTP);
6153 setsignal(SIGTTOU);
6154 setsignal(SIGTTIN);
6155 }
6156 jobctl = enable;
6157}
6158#endif
6159
6160
Eric Andersend35c5df2002-01-09 15:37:36 +00006161#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006162static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006163killcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006164{
6165 int signo = -1;
6166 int list = 0;
6167 int i;
6168 pid_t pid;
6169 struct job *jp;
6170
6171 if (argc <= 1) {
6172usage:
6173 error(
6174"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6175"kill -l [exitstatus]"
6176 );
6177 }
6178
6179 if (*argv[1] == '-') {
6180 signo = decode_signal(argv[1] + 1, 1);
6181 if (signo < 0) {
6182 int c;
6183
6184 while ((c = nextopt("ls:")) != '\0')
6185 switch (c) {
6186 case 'l':
6187 list = 1;
6188 break;
6189 case 's':
6190 signo = decode_signal(optionarg, 1);
6191 if (signo < 0) {
6192 error(
6193 "invalid signal number or name: %s",
6194 optionarg
6195 );
6196 }
Eric Andersen2870d962001-07-02 17:27:21 +00006197 break;
Eric Andersencb57d552001-06-28 07:25:16 +00006198#ifdef DEBUG
6199 default:
6200 error(
6201 "nextopt returned character code 0%o", c);
6202#endif
6203 }
6204 } else
6205 argptr++;
6206 }
6207
6208 if (!list && signo < 0)
6209 signo = SIGTERM;
6210
6211 if ((signo < 0 || !*argptr) ^ list) {
6212 goto usage;
6213 }
6214
6215 if (list) {
Eric Andersen34506362001-08-02 05:02:46 +00006216 const char *name;
6217
Eric Andersencb57d552001-06-28 07:25:16 +00006218 if (!*argptr) {
6219 out1str("0\n");
6220 for (i = 1; i < NSIG; i++) {
Eric Andersen34506362001-08-02 05:02:46 +00006221 name = u_signal_names(0, &i, 1);
6222 if(name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006223 puts(name);
Eric Andersencb57d552001-06-28 07:25:16 +00006224 }
6225 return 0;
6226 }
Eric Andersen34506362001-08-02 05:02:46 +00006227 name = u_signal_names(*argptr, &signo, -1);
6228 if (name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006229 puts(name);
Eric Andersencb57d552001-06-28 07:25:16 +00006230 else
6231 error("invalid signal number or exit status: %s",
6232 *argptr);
6233 return 0;
6234 }
6235
6236 do {
6237 if (**argptr == '%') {
6238 jp = getjob(*argptr);
6239 if (jp->jobctl == 0)
6240 error("job %s not created under job control",
6241 *argptr);
6242 pid = -jp->ps[0].pid;
6243 } else
6244 pid = atoi(*argptr);
6245 if (kill(pid, signo) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00006246 error("%s: %m", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006247 } while (*++argptr);
6248
6249 return 0;
6250}
6251
6252static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006253fgcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006254{
6255 struct job *jp;
6256 int pgrp;
6257 int status;
6258
6259 jp = getjob(argv[1]);
6260 if (jp->jobctl == 0)
6261 error("job not created under job control");
6262 pgrp = jp->ps[0].pid;
6263#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006264 ioctl(2, TIOCSPGRP, (char *)&pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006265#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006266 tcsetpgrp(2, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006267#endif
6268 restartjob(jp);
Eric Andersencb57d552001-06-28 07:25:16 +00006269 status = waitforjob(jp);
Eric Andersencb57d552001-06-28 07:25:16 +00006270 return status;
6271}
6272
6273
6274static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006275bgcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006276{
6277 struct job *jp;
6278
6279 do {
6280 jp = getjob(*++argv);
6281 if (jp->jobctl == 0)
6282 error("job not created under job control");
6283 restartjob(jp);
6284 } while (--argc > 1);
6285 return 0;
6286}
6287
6288
6289static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006290restartjob(struct job *jp)
Eric Andersencb57d552001-06-28 07:25:16 +00006291{
6292 struct procstat *ps;
6293 int i;
6294
6295 if (jp->state == JOBDONE)
6296 return;
6297 INTOFF;
6298 killpg(jp->ps[0].pid, SIGCONT);
6299 for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
6300 if (WIFSTOPPED(ps->status)) {
6301 ps->status = -1;
6302 jp->state = 0;
6303 }
6304 }
6305 INTON;
6306}
6307#endif
6308
Eric Andersen2870d962001-07-02 17:27:21 +00006309static void showjobs(int change);
6310
Eric Andersencb57d552001-06-28 07:25:16 +00006311
6312static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006313jobscmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006314{
6315 showjobs(0);
6316 return 0;
6317}
6318
6319
6320/*
6321 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6322 * statuses have changed since the last call to showjobs.
6323 *
6324 * If the shell is interrupted in the process of creating a job, the
6325 * result may be a job structure containing zero processes. Such structures
6326 * will be freed here.
6327 */
6328
6329static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006330showjobs(int change)
Eric Andersencb57d552001-06-28 07:25:16 +00006331{
6332 int jobno;
6333 int procno;
6334 int i;
6335 struct job *jp;
6336 struct procstat *ps;
6337 int col;
6338 char s[64];
6339
6340 TRACE(("showjobs(%d) called\n", change));
6341 while (dowait(0, (struct job *)NULL) > 0);
6342 for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
6343 if (! jp->used)
6344 continue;
6345 if (jp->nprocs == 0) {
6346 freejob(jp);
6347 continue;
6348 }
6349 if (change && ! jp->changed)
6350 continue;
6351 procno = jp->nprocs;
Eric Andersen2870d962001-07-02 17:27:21 +00006352 for (ps = jp->ps ; ; ps++) { /* for each process */
Eric Andersencb57d552001-06-28 07:25:16 +00006353 if (ps == jp->ps)
Eric Andersen3102ac42001-07-06 04:26:23 +00006354 snprintf(s, 64, "[%d] %ld ", jobno,
Eric Andersencb57d552001-06-28 07:25:16 +00006355 (long)ps->pid);
6356 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006357 snprintf(s, 64, " %ld ",
Eric Andersencb57d552001-06-28 07:25:16 +00006358 (long)ps->pid);
6359 out1str(s);
6360 col = strlen(s);
6361 s[0] = '\0';
6362 if (ps->status == -1) {
6363 /* don't print anything */
6364 } else if (WIFEXITED(ps->status)) {
Eric Andersen3102ac42001-07-06 04:26:23 +00006365 snprintf(s, 64, "Exit %d",
Eric Andersencb57d552001-06-28 07:25:16 +00006366 WEXITSTATUS(ps->status));
6367 } else {
Eric Andersend35c5df2002-01-09 15:37:36 +00006368#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen2870d962001-07-02 17:27:21 +00006369 if (WIFSTOPPED(ps->status))
Eric Andersencb57d552001-06-28 07:25:16 +00006370 i = WSTOPSIG(ps->status);
6371 else /* WIFSIGNALED(ps->status) */
6372#endif
6373 i = WTERMSIG(ps->status);
6374 if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
Eric Andersen2870d962001-07-02 17:27:21 +00006375 strcpy(s, sys_siglist[i & 0x7F]);
Eric Andersencb57d552001-06-28 07:25:16 +00006376 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006377 snprintf(s, 64, "Signal %d", i & 0x7F);
Eric Andersencb57d552001-06-28 07:25:16 +00006378 if (WCOREDUMP(ps->status))
6379 strcat(s, " (core dumped)");
6380 }
6381 out1str(s);
6382 col += strlen(s);
Eric Andersen62483552001-07-10 06:09:16 +00006383 printf(
Eric Andersencb57d552001-06-28 07:25:16 +00006384 "%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ',
6385 ps->cmd
6386 );
6387 if (--procno <= 0)
6388 break;
6389 }
6390 jp->changed = 0;
6391 if (jp->state == JOBDONE) {
6392 freejob(jp);
6393 }
6394 }
6395}
6396
6397
6398/*
6399 * Mark a job structure as unused.
6400 */
6401
6402static void
Eric Andersen62483552001-07-10 06:09:16 +00006403freejob(struct job *jp)
6404{
6405 const struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006406 int i;
6407
6408 INTOFF;
6409 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6410 if (ps->cmd != nullstr)
6411 ckfree(ps->cmd);
6412 }
6413 if (jp->ps != &jp->ps0)
6414 ckfree(jp->ps);
6415 jp->used = 0;
Eric Andersend35c5df2002-01-09 15:37:36 +00006416#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006417 if (curjob == jp - jobtab + 1)
6418 curjob = 0;
6419#endif
6420 INTON;
6421}
6422
6423
6424
6425static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006426waitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006427{
6428 struct job *job;
6429 int status, retval;
6430 struct job *jp;
6431
6432 if (--argc > 0) {
6433start:
6434 job = getjob(*++argv);
6435 } else {
6436 job = NULL;
6437 }
Eric Andersen2870d962001-07-02 17:27:21 +00006438 for (;;) { /* loop until process terminated or stopped */
Eric Andersencb57d552001-06-28 07:25:16 +00006439 if (job != NULL) {
6440 if (job->state) {
6441 status = job->ps[job->nprocs - 1].status;
6442 if (! iflag)
6443 freejob(job);
6444 if (--argc) {
6445 goto start;
6446 }
6447 if (WIFEXITED(status))
6448 retval = WEXITSTATUS(status);
Eric Andersend35c5df2002-01-09 15:37:36 +00006449#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006450 else if (WIFSTOPPED(status))
6451 retval = WSTOPSIG(status) + 128;
6452#endif
6453 else {
6454 /* XXX: limits number of signals */
6455 retval = WTERMSIG(status) + 128;
6456 }
6457 return retval;
6458 }
6459 } else {
6460 for (jp = jobtab ; ; jp++) {
Eric Andersen2870d962001-07-02 17:27:21 +00006461 if (jp >= jobtab + njobs) { /* no running procs */
Eric Andersencb57d552001-06-28 07:25:16 +00006462 return 0;
6463 }
6464 if (jp->used && jp->state == 0)
6465 break;
6466 }
6467 }
6468 if (dowait(2, 0) < 0 && errno == EINTR) {
6469 return 129;
6470 }
6471 }
6472}
6473
6474
6475
6476/*
6477 * Convert a job name to a job structure.
6478 */
6479
6480static struct job *
Eric Andersen2870d962001-07-02 17:27:21 +00006481getjob(const char *name)
6482{
Eric Andersencb57d552001-06-28 07:25:16 +00006483 int jobno;
6484 struct job *jp;
6485 int pid;
6486 int i;
6487
6488 if (name == NULL) {
Eric Andersend35c5df2002-01-09 15:37:36 +00006489#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006490currentjob:
6491 if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
6492 error("No current job");
6493 return &jobtab[jobno - 1];
6494#else
6495 error("No current job");
6496#endif
6497 } else if (name[0] == '%') {
6498 if (is_digit(name[1])) {
6499 jobno = number(name + 1);
6500 if (jobno > 0 && jobno <= njobs
6501 && jobtab[jobno - 1].used != 0)
6502 return &jobtab[jobno - 1];
Eric Andersend35c5df2002-01-09 15:37:36 +00006503#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006504 } else if (name[1] == '%' && name[2] == '\0') {
6505 goto currentjob;
6506#endif
6507 } else {
6508 struct job *found = NULL;
6509 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
6510 if (jp->used && jp->nprocs > 0
6511 && prefix(name + 1, jp->ps[0].cmd)) {
6512 if (found)
6513 error("%s: ambiguous", name);
6514 found = jp;
6515 }
6516 }
6517 if (found)
6518 return found;
6519 }
Eric Andersen2870d962001-07-02 17:27:21 +00006520 } else if (is_number(name, &pid)) {
Eric Andersencb57d552001-06-28 07:25:16 +00006521 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
6522 if (jp->used && jp->nprocs > 0
6523 && jp->ps[jp->nprocs - 1].pid == pid)
6524 return jp;
6525 }
6526 }
6527 error("No such job: %s", name);
6528 /* NOTREACHED */
6529}
6530
6531
6532
6533/*
6534 * Return a new job structure,
6535 */
6536
Eric Andersen2870d962001-07-02 17:27:21 +00006537static struct job *
Eric Andersen62483552001-07-10 06:09:16 +00006538makejob(const union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00006539{
6540 int i;
6541 struct job *jp;
6542
6543 for (i = njobs, jp = jobtab ; ; jp++) {
6544 if (--i < 0) {
6545 INTOFF;
6546 if (njobs == 0) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006547 jobtab = xmalloc(4 * sizeof jobtab[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00006548 } else {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006549 jp = xmalloc((njobs + 4) * sizeof jobtab[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00006550 memcpy(jp, jobtab, njobs * sizeof jp[0]);
6551 /* Relocate `ps' pointers */
6552 for (i = 0; i < njobs; i++)
6553 if (jp[i].ps == &jobtab[i].ps0)
6554 jp[i].ps = &jp[i].ps0;
6555 ckfree(jobtab);
6556 jobtab = jp;
6557 }
6558 jp = jobtab + njobs;
6559 for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
6560 INTON;
6561 break;
6562 }
6563 if (jp->used == 0)
6564 break;
6565 }
6566 INTOFF;
6567 jp->state = 0;
6568 jp->used = 1;
6569 jp->changed = 0;
6570 jp->nprocs = 0;
Eric Andersend35c5df2002-01-09 15:37:36 +00006571#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006572 jp->jobctl = jobctl;
6573#endif
6574 if (nprocs > 1) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006575 jp->ps = xmalloc(nprocs * sizeof (struct procstat));
Eric Andersencb57d552001-06-28 07:25:16 +00006576 } else {
6577 jp->ps = &jp->ps0;
6578 }
6579 INTON;
6580 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
6581 jp - jobtab + 1));
6582 return jp;
6583}
6584
6585
6586/*
6587 * Fork of a subshell. If we are doing job control, give the subshell its
6588 * own process group. Jp is a job structure that the job is to be added to.
6589 * N is the command that will be evaluated by the child. Both jp and n may
6590 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00006591 * FORK_FG - Fork off a foreground process.
6592 * FORK_BG - Fork off a background process.
6593 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
6594 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00006595 *
6596 * When job control is turned off, background processes have their standard
6597 * input redirected to /dev/null (except for the second and later processes
6598 * in a pipeline).
6599 */
6600
Eric Andersen2870d962001-07-02 17:27:21 +00006601
6602
Eric Andersencb57d552001-06-28 07:25:16 +00006603static int
Eric Andersen62483552001-07-10 06:09:16 +00006604forkshell(struct job *jp, const union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00006605{
6606 int pid;
Eric Andersend35c5df2002-01-09 15:37:36 +00006607#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006608 int pgrp;
Eric Andersen62483552001-07-10 06:09:16 +00006609#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006610 const char *devnull = _PATH_DEVNULL;
6611 const char *nullerr = "Can't open %s";
6612
6613 TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
6614 mode));
6615 INTOFF;
Eric Andersen72f9a422001-10-28 05:12:20 +00006616#if !defined(__UCLIBC__) || defined(__UCLIBC_HAS_MMU__)
Eric Andersencb57d552001-06-28 07:25:16 +00006617 pid = fork();
Eric Andersen72f9a422001-10-28 05:12:20 +00006618#else
6619 pid = vfork();
6620#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006621 if (pid == -1) {
6622 TRACE(("Fork failed, errno=%d\n", errno));
6623 INTON;
6624 error("Cannot fork");
6625 }
6626 if (pid == 0) {
6627 struct job *p;
6628 int wasroot;
6629 int i;
6630
6631 TRACE(("Child shell %d\n", getpid()));
6632 wasroot = rootshell;
6633 rootshell = 0;
6634 closescript();
6635 INTON;
6636 clear_traps();
Eric Andersend35c5df2002-01-09 15:37:36 +00006637#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen2870d962001-07-02 17:27:21 +00006638 jobctl = 0; /* do job control only in root shell */
Eric Andersencb57d552001-06-28 07:25:16 +00006639 if (wasroot && mode != FORK_NOJOB && mflag) {
6640 if (jp == NULL || jp->nprocs == 0)
6641 pgrp = getpid();
6642 else
6643 pgrp = jp->ps[0].pid;
6644 setpgid(0, pgrp);
6645 if (mode == FORK_FG) {
6646 /*** this causes superfluous TIOCSPGRPS ***/
6647#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006648 if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006649 error("TIOCSPGRP failed, errno=%d", errno);
6650#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006651 if (tcsetpgrp(2, pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006652 error("tcsetpgrp failed, errno=%d", errno);
6653#endif
6654 }
6655 setsignal(SIGTSTP);
6656 setsignal(SIGTTOU);
6657 } else if (mode == FORK_BG) {
Eric Andersencb57d552001-06-28 07:25:16 +00006658#else
6659 if (mode == FORK_BG) {
Aaron Lehmann1a698662001-12-31 06:12:48 +00006660#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006661 ignoresig(SIGINT);
6662 ignoresig(SIGQUIT);
6663 if ((jp == NULL || jp->nprocs == 0) &&
6664 ! fd0_redirected_p ()) {
6665 close(0);
6666 if (open(devnull, O_RDONLY) != 0)
6667 error(nullerr, devnull);
6668 }
6669 }
Eric Andersencb57d552001-06-28 07:25:16 +00006670 for (i = njobs, p = jobtab ; --i >= 0 ; p++)
6671 if (p->used)
6672 freejob(p);
6673 if (wasroot && iflag) {
6674 setsignal(SIGINT);
6675 setsignal(SIGQUIT);
6676 setsignal(SIGTERM);
6677 }
6678 return pid;
6679 }
Eric Andersend35c5df2002-01-09 15:37:36 +00006680#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006681 if (rootshell && mode != FORK_NOJOB && mflag) {
6682 if (jp == NULL || jp->nprocs == 0)
6683 pgrp = pid;
6684 else
6685 pgrp = jp->ps[0].pid;
6686 setpgid(pid, pgrp);
6687 }
Eric Andersen62483552001-07-10 06:09:16 +00006688#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006689 if (mode == FORK_BG)
Eric Andersen2870d962001-07-02 17:27:21 +00006690 backgndpid = pid; /* set $! */
Eric Andersencb57d552001-06-28 07:25:16 +00006691 if (jp) {
6692 struct procstat *ps = &jp->ps[jp->nprocs++];
6693 ps->pid = pid;
6694 ps->status = -1;
6695 ps->cmd = nullstr;
6696 if (iflag && rootshell && n)
6697 ps->cmd = commandtext(n);
6698 }
6699 INTON;
6700 TRACE(("In parent shell: child = %d\n", pid));
6701 return pid;
6702}
6703
6704
6705
6706/*
6707 * Wait for job to finish.
6708 *
6709 * Under job control we have the problem that while a child process is
6710 * running interrupts generated by the user are sent to the child but not
6711 * to the shell. This means that an infinite loop started by an inter-
6712 * active user may be hard to kill. With job control turned off, an
6713 * interactive user may place an interactive program inside a loop. If
6714 * the interactive program catches interrupts, the user doesn't want
6715 * these interrupts to also abort the loop. The approach we take here
6716 * is to have the shell ignore interrupt signals while waiting for a
6717 * forground process to terminate, and then send itself an interrupt
6718 * signal if the child process was terminated by an interrupt signal.
6719 * Unfortunately, some programs want to do a bit of cleanup and then
6720 * exit on interrupt; unless these processes terminate themselves by
6721 * sending a signal to themselves (instead of calling exit) they will
6722 * confuse this approach.
6723 */
6724
6725static int
Eric Andersen62483552001-07-10 06:09:16 +00006726waitforjob(struct job *jp)
6727{
Eric Andersend35c5df2002-01-09 15:37:36 +00006728#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006729 int mypgrp = getpgrp();
6730#endif
6731 int status;
6732 int st;
6733 struct sigaction act, oact;
6734
6735 INTOFF;
6736 intreceived = 0;
Eric Andersend35c5df2002-01-09 15:37:36 +00006737#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006738 if (!jobctl) {
6739#else
6740 if (!iflag) {
6741#endif
6742 sigaction(SIGINT, 0, &act);
6743 act.sa_handler = waitonint;
6744 sigaction(SIGINT, &act, &oact);
6745 }
6746 TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
6747 while (jp->state == 0) {
6748 dowait(1, jp);
6749 }
Eric Andersend35c5df2002-01-09 15:37:36 +00006750#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006751 if (!jobctl) {
6752#else
6753 if (!iflag) {
6754#endif
6755 sigaction(SIGINT, &oact, 0);
6756 if (intreceived && trap[SIGINT]) kill(getpid(), SIGINT);
6757 }
Eric Andersend35c5df2002-01-09 15:37:36 +00006758#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006759 if (jp->jobctl) {
6760#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006761 if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006762 error("TIOCSPGRP failed, errno=%d\n", errno);
6763#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006764 if (tcsetpgrp(2, mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006765 error("tcsetpgrp failed, errno=%d\n", errno);
6766#endif
6767 }
Eric Andersend35c5df2002-01-09 15:37:36 +00006768 if (jp->state == CONFIG_ASH_JOB_CONTROLTOPPED)
Eric Andersencb57d552001-06-28 07:25:16 +00006769 curjob = jp - jobtab + 1;
6770#endif
6771 status = jp->ps[jp->nprocs - 1].status;
6772 /* convert to 8 bits */
6773 if (WIFEXITED(status))
6774 st = WEXITSTATUS(status);
Eric Andersend35c5df2002-01-09 15:37:36 +00006775#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006776 else if (WIFSTOPPED(status))
6777 st = WSTOPSIG(status) + 128;
6778#endif
6779 else
6780 st = WTERMSIG(status) + 128;
Eric Andersend35c5df2002-01-09 15:37:36 +00006781#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006782 if (jp->jobctl) {
6783 /*
6784 * This is truly gross.
6785 * If we're doing job control, then we did a TIOCSPGRP which
6786 * caused us (the shell) to no longer be in the controlling
6787 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
6788 * intuit from the subprocess exit status whether a SIGINT
6789 * occured, and if so interrupt ourselves. Yuck. - mycroft
6790 */
6791 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
6792 raise(SIGINT);
6793 }
Eric Andersen2870d962001-07-02 17:27:21 +00006794 if (jp->state == JOBDONE)
6795
Eric Andersencb57d552001-06-28 07:25:16 +00006796#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006797 freejob(jp);
6798 INTON;
6799 return st;
6800}
6801
6802
6803
6804/*
6805 * Wait for a process to terminate.
6806 */
6807
Eric Andersen62483552001-07-10 06:09:16 +00006808/*
6809 * Do a wait system call. If job control is compiled in, we accept
6810 * stopped processes. If block is zero, we return a value of zero
6811 * rather than blocking.
6812 *
6813 * System V doesn't have a non-blocking wait system call. It does
6814 * have a SIGCLD signal that is sent to a process when one of it's
6815 * children dies. The obvious way to use SIGCLD would be to install
6816 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
6817 * was received, and have waitproc bump another counter when it got
6818 * the status of a process. Waitproc would then know that a wait
6819 * system call would not block if the two counters were different.
6820 * This approach doesn't work because if a process has children that
6821 * have not been waited for, System V will send it a SIGCLD when it
6822 * installs a signal handler for SIGCLD. What this means is that when
6823 * a child exits, the shell will be sent SIGCLD signals continuously
6824 * until is runs out of stack space, unless it does a wait call before
6825 * restoring the signal handler. The code below takes advantage of
6826 * this (mis)feature by installing a signal handler for SIGCLD and
6827 * then checking to see whether it was called. If there are any
6828 * children to be waited for, it will be.
6829 *
6830 */
6831
6832static inline int
6833waitproc(int block, int *status)
6834{
6835 int flags;
6836
6837 flags = 0;
Eric Andersend35c5df2002-01-09 15:37:36 +00006838#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen62483552001-07-10 06:09:16 +00006839 if (jobctl)
6840 flags |= WUNTRACED;
6841#endif
6842 if (block == 0)
6843 flags |= WNOHANG;
6844 return wait3(status, flags, (struct rusage *)NULL);
6845}
6846
Eric Andersencb57d552001-06-28 07:25:16 +00006847static int
Eric Andersen62483552001-07-10 06:09:16 +00006848dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00006849{
6850 int pid;
6851 int status;
6852 struct procstat *sp;
6853 struct job *jp;
6854 struct job *thisjob;
6855 int done;
6856 int stopped;
6857 int core;
6858 int sig;
6859
6860 TRACE(("dowait(%d) called\n", block));
6861 do {
6862 pid = waitproc(block, &status);
6863 TRACE(("wait returns %d, status=%d\n", pid, status));
6864 } while (!(block & 2) && pid == -1 && errno == EINTR);
6865 if (pid <= 0)
6866 return pid;
6867 INTOFF;
6868 thisjob = NULL;
6869 for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
6870 if (jp->used) {
6871 done = 1;
6872 stopped = 1;
6873 for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
6874 if (sp->pid == -1)
6875 continue;
6876 if (sp->pid == pid) {
6877 TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
6878 sp->status = status;
6879 thisjob = jp;
6880 }
6881 if (sp->status == -1)
6882 stopped = 0;
6883 else if (WIFSTOPPED(sp->status))
6884 done = 0;
6885 }
Eric Andersen2870d962001-07-02 17:27:21 +00006886 if (stopped) { /* stopped or done */
Eric Andersend35c5df2002-01-09 15:37:36 +00006887 int state = done? JOBDONE : CONFIG_ASH_JOB_CONTROLTOPPED;
Eric Andersencb57d552001-06-28 07:25:16 +00006888 if (jp->state != state) {
6889 TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
6890 jp->state = state;
Eric Andersend35c5df2002-01-09 15:37:36 +00006891#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006892 if (done && curjob == jp - jobtab + 1)
Eric Andersen2870d962001-07-02 17:27:21 +00006893 curjob = 0; /* no current job */
Eric Andersencb57d552001-06-28 07:25:16 +00006894#endif
6895 }
6896 }
6897 }
6898 }
6899 INTON;
6900 if (! rootshell || ! iflag || (job && thisjob == job)) {
6901 core = WCOREDUMP(status);
Eric Andersend35c5df2002-01-09 15:37:36 +00006902#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006903 if (WIFSTOPPED(status)) sig = WSTOPSIG(status);
6904 else
6905#endif
6906 if (WIFEXITED(status)) sig = 0;
6907 else sig = WTERMSIG(status);
6908
6909 if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
6910 if (thisjob != job)
Eric Andersen3102ac42001-07-06 04:26:23 +00006911 out2fmt("%d: ", pid);
Eric Andersend35c5df2002-01-09 15:37:36 +00006912#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006913 if (sig == SIGTSTP && rootshell && iflag)
Eric Andersen3102ac42001-07-06 04:26:23 +00006914 out2fmt("%%%ld ",
Eric Andersencb57d552001-06-28 07:25:16 +00006915 (long)(job - jobtab + 1));
6916#endif
6917 if (sig < NSIG && sys_siglist[sig])
6918 out2str(sys_siglist[sig]);
6919 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006920 out2fmt("Signal %d", sig);
Eric Andersencb57d552001-06-28 07:25:16 +00006921 if (core)
6922 out2str(" - core dumped");
6923 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00006924 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00006925 TRACE(("Not printing status: status=%d, sig=%d\n",
Eric Andersencb57d552001-06-28 07:25:16 +00006926 status, sig));
6927 }
6928 } else {
6929 TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
6930 if (thisjob)
6931 thisjob->changed = 1;
6932 }
6933 return pid;
6934}
6935
6936
6937
Eric Andersencb57d552001-06-28 07:25:16 +00006938
6939/*
6940 * return 1 if there are stopped jobs, otherwise 0
6941 */
Eric Andersencb57d552001-06-28 07:25:16 +00006942static int
Eric Andersen2870d962001-07-02 17:27:21 +00006943stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006944{
6945 int jobno;
6946 struct job *jp;
6947
6948 if (job_warning)
6949 return (0);
6950 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
6951 if (jp->used == 0)
6952 continue;
Eric Andersend35c5df2002-01-09 15:37:36 +00006953 if (jp->state == CONFIG_ASH_JOB_CONTROLTOPPED) {
Eric Andersencb57d552001-06-28 07:25:16 +00006954 out2str("You have stopped jobs.\n");
6955 job_warning = 2;
6956 return (1);
6957 }
6958 }
6959
6960 return (0);
6961}
6962
6963/*
6964 * Return a string identifying a command (to be printed by the
6965 * jobs command.
6966 */
6967
6968static char *cmdnextc;
6969static int cmdnleft;
Eric Andersen2870d962001-07-02 17:27:21 +00006970#define MAXCMDTEXT 200
Eric Andersencb57d552001-06-28 07:25:16 +00006971
Eric Andersen2870d962001-07-02 17:27:21 +00006972static void
6973cmdputs(const char *s)
6974{
6975 const char *p;
6976 char *q;
6977 char c;
6978 int subtype = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00006979
Eric Andersen2870d962001-07-02 17:27:21 +00006980 if (cmdnleft <= 0)
6981 return;
6982 p = s;
6983 q = cmdnextc;
6984 while ((c = *p++) != '\0') {
6985 if (c == CTLESC)
6986 *q++ = *p++;
6987 else if (c == CTLVAR) {
6988 *q++ = '$';
6989 if (--cmdnleft > 0)
6990 *q++ = '{';
6991 subtype = *p++;
6992 } else if (c == '=' && subtype != 0) {
6993 *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
6994 subtype = 0;
6995 } else if (c == CTLENDVAR) {
6996 *q++ = '}';
6997 } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
6998 cmdnleft++; /* ignore it */
6999 else
7000 *q++ = c;
7001 if (--cmdnleft <= 0) {
7002 *q++ = '.';
7003 *q++ = '.';
7004 *q++ = '.';
7005 break;
7006 }
7007 }
7008 cmdnextc = q;
Eric Andersencb57d552001-06-28 07:25:16 +00007009}
7010
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00007011#define CMDTXT_TABLE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007012#ifdef CMDTXT_TABLE
7013/*
7014 * To collect a lot of redundant code in cmdtxt() case statements, we
7015 * implement a mini language here. Each type of node struct has an
7016 * associated instruction sequence that operates on its members via
7017 * their offsets. The instruction are pack in unsigned chars with
7018 * format IIDDDDDE where the bits are
7019 * I : part of the instruction opcode, which are
7020 * 00 : member is a pointer to another node -- process it recursively
7021 * 40 : member is a pointer to a char string -- output it
7022 * 80 : output the string whose index is stored in the data field
7023 * CC : flag signaling that this case needs external processing
7024 * D : data - either the (shifted) index of a fixed string to output or
7025 * the actual offset of the member to operate on in the struct
7026 * (since we assume bit 0 is set, the offset is not shifted)
7027 * E : flag signaling end of instruction sequence
7028 *
7029 * WARNING: In order to handle larger offsets for 64bit archs, this code
7030 * assumes that no offset can be an odd number and stores the
7031 * end-of-instructions flag in bit 0.
7032 */
Eric Andersencb57d552001-06-28 07:25:16 +00007033
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007034#define CMDTXT_NOMORE 0x01 /* NOTE: no offset should be odd */
7035#define CMDTXT_CHARPTR 0x40
7036#define CMDTXT_STRING 0x80
7037#define CMDTXT_SPECIAL 0xC0
7038#define CMDTXT_OFFSETMASK 0x3E
7039
7040static const char * const cmdtxt_strings[] = {
7041 /* 0 1 2 3 4 5 6 7 */
7042 "; ", "(", ")", " && ", " || ", "if ", "; then ", "...",
7043 /* 8 9 10 11 12 13 */
7044 "while ", "; do ", "; done", "until ", "for ", " in ...",
7045 /* 14 15 16 17 */
7046 "case ", "???", "() ...", "<<..."
7047};
7048
7049static const char * const redir_strings[] = {
7050 ">", "<", "<>", ">>", ">|", ">&", "<&"
7051};
7052
7053static const unsigned char cmdtxt_ops[] = {
7054#define CMDTXT_NSEMI 0
7055 offsetof(union node, nbinary.ch1),
7056 0|CMDTXT_STRING,
7057 offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7058#define CMDTXT_NCMD (CMDTXT_NSEMI + 3)
7059#define CMDTXT_NPIPE (CMDTXT_NCMD)
7060#define CMDTXT_NCASE (CMDTXT_NCMD)
7061#define CMDTXT_NTO (CMDTXT_NCMD)
7062#define CMDTXT_NFROM (CMDTXT_NCMD)
7063#define CMDTXT_NFROMTO (CMDTXT_NCMD)
7064#define CMDTXT_NAPPEND (CMDTXT_NCMD)
7065#define CMDTXT_NTOOV (CMDTXT_NCMD)
7066#define CMDTXT_NTOFD (CMDTXT_NCMD)
7067#define CMDTXT_NFROMFD (CMDTXT_NCMD)
7068 CMDTXT_SPECIAL,
7069#define CMDTXT_NREDIR (CMDTXT_NPIPE + 1)
7070#define CMDTXT_NBACKGND (CMDTXT_NREDIR)
7071 offsetof(union node, nredir.n)|CMDTXT_NOMORE,
7072#define CMDTXT_NSUBSHELL (CMDTXT_NBACKGND + 1)
7073 (1*2)|CMDTXT_STRING,
7074 offsetof(union node, nredir.n),
7075 (2*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7076#define CMDTXT_NAND (CMDTXT_NSUBSHELL + 3)
7077 offsetof(union node, nbinary.ch1),
7078 (3*2)|CMDTXT_STRING,
7079 offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7080#define CMDTXT_NOR (CMDTXT_NAND + 3)
7081 offsetof(union node, nbinary.ch1),
7082 (4*2)|CMDTXT_STRING,
7083 offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7084#define CMDTXT_NIF (CMDTXT_NOR + 3)
7085 (5*2)|CMDTXT_STRING,
7086 offsetof(union node, nif.test),
7087 (6*2)|CMDTXT_STRING,
7088 offsetof(union node, nif.ifpart),
7089 (7*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7090#define CMDTXT_NWHILE (CMDTXT_NIF + 5)
7091 (8*2)|CMDTXT_STRING,
7092 offsetof(union node, nbinary.ch1),
7093 (9*2)|CMDTXT_STRING,
7094 offsetof(union node, nbinary.ch2),
7095 (10*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7096#define CMDTXT_NUNTIL (CMDTXT_NWHILE + 5)
7097 (11*2)|CMDTXT_STRING,
7098 offsetof(union node, nbinary.ch1),
7099 (9*2)|CMDTXT_STRING,
7100 offsetof(union node, nbinary.ch2),
7101 (10*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7102#define CMDTXT_NFOR (CMDTXT_NUNTIL + 5)
7103 (12*2)|CMDTXT_STRING,
7104 offsetof(union node, nfor.var)|CMDTXT_CHARPTR,
7105 (13*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7106#define CMDTXT_NCLIST (CMDTXT_NFOR + 3) /* TODO: IS THIS CORRECT??? */
7107#define CMDTXT_NNOT (CMDTXT_NCLIST) /* TODO: IS THIS CORRECT??? */
7108 (15*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7109#define CMDTXT_NDEFUN (CMDTXT_NCLIST + 1)
7110 offsetof(union node, narg.text)|CMDTXT_CHARPTR,
7111 (16*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7112#define CMDTXT_NARG (CMDTXT_NDEFUN + 2)
7113 offsetof(union node, narg.text)|CMDTXT_CHARPTR|CMDTXT_NOMORE,
7114#define CMDTXT_NHERE (CMDTXT_NARG + 1)
7115#define CMDTXT_NXHERE (CMDTXT_NHERE)
7116 (17*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7117};
7118
7119#if CMDTXT_NXHERE != 36
7120#error CMDTXT_NXHERE
7121#endif
7122
7123static const unsigned char cmdtxt_ops_index[26] = {
7124 CMDTXT_NSEMI,
7125 CMDTXT_NCMD,
7126 CMDTXT_NPIPE,
7127 CMDTXT_NREDIR,
7128 CMDTXT_NBACKGND,
7129 CMDTXT_NSUBSHELL,
7130 CMDTXT_NAND,
7131 CMDTXT_NOR,
7132 CMDTXT_NIF,
7133 CMDTXT_NWHILE,
7134 CMDTXT_NUNTIL,
7135 CMDTXT_NFOR,
7136 CMDTXT_NCASE,
7137 CMDTXT_NCLIST,
7138 CMDTXT_NDEFUN,
7139 CMDTXT_NARG,
7140 CMDTXT_NTO,
7141 CMDTXT_NFROM,
7142 CMDTXT_NFROMTO,
7143 CMDTXT_NAPPEND,
7144 CMDTXT_NTOOV,
7145 CMDTXT_NTOFD,
7146 CMDTXT_NFROMFD,
7147 CMDTXT_NHERE,
7148 CMDTXT_NXHERE,
7149 CMDTXT_NNOT,
7150};
7151
7152static void
7153cmdtxt(const union node *n)
7154{
7155 const char *p;
7156
7157 if (n == NULL)
7158 return;
7159
7160 p = cmdtxt_ops + (int) cmdtxt_ops_index[n->type];
7161 if ((*p & CMDTXT_SPECIAL) != CMDTXT_SPECIAL) { /* normal case */
7162 do {
7163 if (*p & CMDTXT_STRING) { /* output fixed string */
7164 cmdputs(cmdtxt_strings[((int)(*p & CMDTXT_OFFSETMASK) >> 1)]);
Manuel Novoa III c639a352001-08-12 17:32:56 +00007165 } else {
7166 const char *pf = ((const char *) n)
7167 + ((int)(*p & CMDTXT_OFFSETMASK));
7168 if (*p & CMDTXT_CHARPTR) { /* output dynamic string */
7169 cmdputs(*((const char **) pf));
7170 } else { /* output field */
7171 cmdtxt(*((const union node **) pf));
7172 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007173 }
7174 } while (!(*p++ & CMDTXT_NOMORE));
7175 } else if (n->type == NCMD) {
7176 union node *np;
7177 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7178 cmdtxt(np);
7179 if (np->narg.next)
7180 cmdputs(spcstr);
7181 }
7182 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7183 cmdputs(spcstr);
7184 cmdtxt(np);
7185 }
7186 } else if (n->type == NPIPE) {
7187 struct nodelist *lp;
7188 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7189 cmdtxt(lp->n);
7190 if (lp->next)
7191 cmdputs(" | ");
7192 }
7193 } else if (n->type == NCASE) {
7194 cmdputs(cmdtxt_strings[14]);
7195 cmdputs(n->ncase.expr->narg.text);
7196 cmdputs(cmdtxt_strings[13]);
7197 } else {
7198#if (NTO != 16) || (NFROM != 17) || (NFROMTO != 18) || (NAPPEND != 19) || (NTOOV != 20) || (NTOFD != 21) || (NFROMFD != 22)
7199#error Assumption violated regarding range and ordering of NTO ... NFROMFD!
7200#endif
7201 char s[2];
7202
7203#ifdef DEBUG
7204 assert((n->type >= NTO) && (n->type <= NFROMFD));
7205#endif
7206
7207 p = redir_strings[n->type - NTO];
7208 if (n->nfile.fd != ('>' == *p)) {
7209 s[0] = n->nfile.fd + '0';
7210 s[1] = '\0';
7211 cmdputs(s);
7212 }
7213 cmdputs(p);
7214 if (n->type >= NTOFD) {
7215 s[0] = n->ndup.dupfd + '0';
7216 s[1] = '\0';
7217 cmdputs(s);
7218 } else {
7219 cmdtxt(n->nfile.fname);
7220 }
7221 }
7222}
7223#else /* CMDTXT_TABLE */
Eric Andersencb57d552001-06-28 07:25:16 +00007224static void
Eric Andersen2870d962001-07-02 17:27:21 +00007225cmdtxt(const union node *n)
7226{
Eric Andersencb57d552001-06-28 07:25:16 +00007227 union node *np;
7228 struct nodelist *lp;
7229 const char *p;
7230 int i;
7231 char s[2];
7232
7233 if (n == NULL)
7234 return;
7235 switch (n->type) {
7236 case NSEMI:
7237 cmdtxt(n->nbinary.ch1);
7238 cmdputs("; ");
7239 cmdtxt(n->nbinary.ch2);
7240 break;
7241 case NAND:
7242 cmdtxt(n->nbinary.ch1);
7243 cmdputs(" && ");
7244 cmdtxt(n->nbinary.ch2);
7245 break;
7246 case NOR:
7247 cmdtxt(n->nbinary.ch1);
7248 cmdputs(" || ");
7249 cmdtxt(n->nbinary.ch2);
7250 break;
7251 case NPIPE:
7252 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7253 cmdtxt(lp->n);
7254 if (lp->next)
7255 cmdputs(" | ");
7256 }
7257 break;
7258 case NSUBSHELL:
7259 cmdputs("(");
7260 cmdtxt(n->nredir.n);
7261 cmdputs(")");
7262 break;
7263 case NREDIR:
7264 case NBACKGND:
7265 cmdtxt(n->nredir.n);
7266 break;
7267 case NIF:
7268 cmdputs("if ");
7269 cmdtxt(n->nif.test);
7270 cmdputs("; then ");
7271 cmdtxt(n->nif.ifpart);
7272 cmdputs("...");
7273 break;
7274 case NWHILE:
7275 cmdputs("while ");
7276 goto until;
7277 case NUNTIL:
7278 cmdputs("until ");
7279until:
7280 cmdtxt(n->nbinary.ch1);
7281 cmdputs("; do ");
7282 cmdtxt(n->nbinary.ch2);
7283 cmdputs("; done");
7284 break;
7285 case NFOR:
7286 cmdputs("for ");
7287 cmdputs(n->nfor.var);
7288 cmdputs(" in ...");
7289 break;
7290 case NCASE:
7291 cmdputs("case ");
7292 cmdputs(n->ncase.expr->narg.text);
7293 cmdputs(" in ...");
7294 break;
7295 case NDEFUN:
7296 cmdputs(n->narg.text);
7297 cmdputs("() ...");
7298 break;
7299 case NCMD:
7300 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7301 cmdtxt(np);
7302 if (np->narg.next)
7303 cmdputs(spcstr);
7304 }
7305 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7306 cmdputs(spcstr);
7307 cmdtxt(np);
7308 }
7309 break;
7310 case NARG:
7311 cmdputs(n->narg.text);
7312 break;
7313 case NTO:
7314 p = ">"; i = 1; goto redir;
7315 case NAPPEND:
7316 p = ">>"; i = 1; goto redir;
7317 case NTOFD:
7318 p = ">&"; i = 1; goto redir;
7319 case NTOOV:
7320 p = ">|"; i = 1; goto redir;
7321 case NFROM:
7322 p = "<"; i = 0; goto redir;
7323 case NFROMFD:
7324 p = "<&"; i = 0; goto redir;
7325 case NFROMTO:
7326 p = "<>"; i = 0; goto redir;
7327redir:
7328 if (n->nfile.fd != i) {
7329 s[0] = n->nfile.fd + '0';
7330 s[1] = '\0';
7331 cmdputs(s);
7332 }
7333 cmdputs(p);
7334 if (n->type == NTOFD || n->type == NFROMFD) {
7335 s[0] = n->ndup.dupfd + '0';
7336 s[1] = '\0';
7337 cmdputs(s);
7338 } else {
7339 cmdtxt(n->nfile.fname);
7340 }
7341 break;
7342 case NHERE:
7343 case NXHERE:
7344 cmdputs("<<...");
7345 break;
7346 default:
7347 cmdputs("???");
7348 break;
7349 }
7350}
Manuel Novoa III c639a352001-08-12 17:32:56 +00007351#endif /* CMDTXT_TABLE */
Eric Andersencb57d552001-06-28 07:25:16 +00007352
Eric Andersen2870d962001-07-02 17:27:21 +00007353static char *
7354commandtext(const union node *n)
7355{
7356 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007357
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007358 cmdnextc = name = xmalloc(MAXCMDTEXT);
Eric Andersen2870d962001-07-02 17:27:21 +00007359 cmdnleft = MAXCMDTEXT - 4;
7360 cmdtxt(n);
7361 *cmdnextc = '\0';
7362 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00007363}
7364
Eric Andersen2870d962001-07-02 17:27:21 +00007365
Eric Andersencb57d552001-06-28 07:25:16 +00007366static void waitonint(int sig) {
7367 intreceived = 1;
7368 return;
7369}
Eric Andersenec074692001-10-31 11:05:49 +00007370
Eric Andersend35c5df2002-01-09 15:37:36 +00007371#ifdef CONFIG_ASH_MAIL
Eric Andersenec074692001-10-31 11:05:49 +00007372
Eric Andersencb57d552001-06-28 07:25:16 +00007373/*
Eric Andersenec074692001-10-31 11:05:49 +00007374 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +00007375 */
7376
7377
7378#define MAXMBOXES 10
7379
7380
Eric Andersen2870d962001-07-02 17:27:21 +00007381static int nmboxes; /* number of mailboxes */
7382static time_t mailtime[MAXMBOXES]; /* times of mailboxes */
Eric Andersencb57d552001-06-28 07:25:16 +00007383
7384
7385
7386/*
7387 * Print appropriate message(s) if mail has arrived. If the argument is
7388 * nozero, then the value of MAIL has changed, so we just update the
7389 * values.
7390 */
7391
7392static void
Eric Andersen2870d962001-07-02 17:27:21 +00007393chkmail(int silent)
Eric Andersencb57d552001-06-28 07:25:16 +00007394{
7395 int i;
7396 const char *mpath;
7397 char *p;
7398 char *q;
7399 struct stackmark smark;
7400 struct stat statb;
7401
7402 if (silent)
7403 nmboxes = 10;
7404 if (nmboxes == 0)
7405 return;
7406 setstackmark(&smark);
7407 mpath = mpathset()? mpathval() : mailval();
7408 for (i = 0 ; i < nmboxes ; i++) {
7409 p = padvance(&mpath, nullstr);
7410 if (p == NULL)
7411 break;
7412 if (*p == '\0')
7413 continue;
7414 for (q = p ; *q ; q++);
7415#ifdef DEBUG
7416 if (q[-1] != '/')
7417 abort();
7418#endif
Eric Andersen2870d962001-07-02 17:27:21 +00007419 q[-1] = '\0'; /* delete trailing '/' */
Eric Andersencb57d552001-06-28 07:25:16 +00007420 if (stat(p, &statb) < 0)
7421 statb.st_size = 0;
7422 if (statb.st_size > mailtime[i] && ! silent) {
Eric Andersen3102ac42001-07-06 04:26:23 +00007423 out2fmt(snlfmt,
7424 pathopt? pathopt : "you have mail");
Eric Andersencb57d552001-06-28 07:25:16 +00007425 }
7426 mailtime[i] = statb.st_size;
Eric Andersencb57d552001-06-28 07:25:16 +00007427 }
7428 nmboxes = i;
7429 popstackmark(&smark);
7430}
Eric Andersencb57d552001-06-28 07:25:16 +00007431
Eric Andersend35c5df2002-01-09 15:37:36 +00007432#endif /* CONFIG_ASH_MAIL */
Eric Andersenec074692001-10-31 11:05:49 +00007433
Eric Andersencb57d552001-06-28 07:25:16 +00007434#define PROFILE 0
7435
Eric Andersencb57d552001-06-28 07:25:16 +00007436#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007437static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007438extern int etext();
7439#endif
7440
Eric Andersen2870d962001-07-02 17:27:21 +00007441static void read_profile (const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007442static void cmdloop (int);
7443static void options (int);
Eric Andersen2870d962001-07-02 17:27:21 +00007444static void setoption (int, int);
7445static void procargs (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00007446
Eric Andersen2870d962001-07-02 17:27:21 +00007447
Eric Andersencb57d552001-06-28 07:25:16 +00007448/*
7449 * Main routine. We initialize things, parse the arguments, execute
7450 * profiles if we're a login shell, and then call cmdloop to execute
7451 * commands. The setjmp call sets up the location to jump to when an
7452 * exception occurs. When an exception occurs the variable "state"
7453 * is used to figure out how far we had gotten.
7454 */
7455
7456int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007457ash_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007458{
7459 struct jmploc jmploc;
7460 struct stackmark smark;
7461 volatile int state;
Eric Andersen62483552001-07-10 06:09:16 +00007462 const char *shinit;
Eric Andersencb57d552001-06-28 07:25:16 +00007463
Eric Andersencb57d552001-06-28 07:25:16 +00007464 BLTINCMD = find_builtin("builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00007465 EXECCMD = find_builtin("exec");
7466 EVALCMD = find_builtin("eval");
7467
Eric Andersenbdfd0d72001-10-24 05:00:29 +00007468#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
Eric Andersen1c039232001-07-07 00:05:55 +00007469 unsetenv("PS1");
7470 unsetenv("PS2");
7471#endif
7472
Eric Andersencb57d552001-06-28 07:25:16 +00007473#if PROFILE
7474 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7475#endif
7476#if defined(linux) || defined(__GNU__)
7477 signal(SIGCHLD, SIG_DFL);
7478#endif
7479 state = 0;
7480 if (setjmp(jmploc.loc)) {
7481 INTOFF;
7482 /*
7483 * When a shell procedure is executed, we raise the
7484 * exception EXSHELLPROC to clean up before executing
7485 * the shell procedure.
7486 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007487 if (exception == EXSHELLPROC) {
Eric Andersencb57d552001-06-28 07:25:16 +00007488 rootpid = getpid();
7489 rootshell = 1;
7490 minusc = NULL;
7491 state = 3;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007492 } else {
7493 if (exception == EXEXEC) {
7494 exitstatus = exerrno;
7495 } else if (exception == EXERROR) {
7496 exitstatus = 2;
7497 }
Eric Andersencb57d552001-06-28 07:25:16 +00007498 if (state == 0 || iflag == 0 || ! rootshell)
7499 exitshell(exitstatus);
7500 }
7501 reset();
Eric Andersen2870d962001-07-02 17:27:21 +00007502 if (exception == EXINT) {
Eric Andersencb57d552001-06-28 07:25:16 +00007503 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00007504 }
7505 popstackmark(&smark);
Eric Andersen2870d962001-07-02 17:27:21 +00007506 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007507 if (state == 1)
7508 goto state1;
7509 else if (state == 2)
7510 goto state2;
7511 else if (state == 3)
7512 goto state3;
7513 else
7514 goto state4;
7515 }
7516 handler = &jmploc;
7517#ifdef DEBUG
7518 opentrace();
7519 trputs("Shell args: "); trargs(argv);
7520#endif
7521 rootpid = getpid();
7522 rootshell = 1;
7523 init();
7524 setstackmark(&smark);
7525 procargs(argc, argv);
7526 if (argv[0] && argv[0][0] == '-') {
7527 state = 1;
7528 read_profile("/etc/profile");
7529state1:
7530 state = 2;
7531 read_profile(".profile");
7532 }
7533state2:
7534 state = 3;
7535#ifndef linux
7536 if (getuid() == geteuid() && getgid() == getegid()) {
7537#endif
7538 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7539 state = 3;
7540 read_profile(shinit);
7541 }
7542#ifndef linux
7543 }
7544#endif
7545state3:
7546 state = 4;
7547 if (sflag == 0 || minusc) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007548 static const char sigs[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00007549 SIGINT, SIGQUIT, SIGHUP,
Eric Andersencb57d552001-06-28 07:25:16 +00007550#ifdef SIGTSTP
7551 SIGTSTP,
7552#endif
7553 SIGPIPE
7554 };
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007555#define SIGSSIZE ((sizeof(sigs)/sizeof(sigs[0])) - 1) /* trailing nul */
Eric Andersencb57d552001-06-28 07:25:16 +00007556 int i;
7557
7558 for (i = 0; i < SIGSSIZE; i++)
7559 setsignal(sigs[i]);
7560 }
7561
7562 if (minusc)
7563 evalstring(minusc, 0);
7564
7565 if (sflag || minusc == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00007566state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007567 cmdloop(1);
7568 }
7569#if PROFILE
7570 monitor(0);
7571#endif
7572 exitshell(exitstatus);
7573 /* NOTREACHED */
7574}
7575
7576
7577/*
7578 * Read and execute commands. "Top" is nonzero for the top level command
7579 * loop; it turns on prompting if the shell is interactive.
7580 */
7581
7582static void
Eric Andersen2870d962001-07-02 17:27:21 +00007583cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00007584{
7585 union node *n;
7586 struct stackmark smark;
7587 int inter;
7588 int numeof = 0;
7589
7590 TRACE(("cmdloop(%d) called\n", top));
7591 setstackmark(&smark);
7592 for (;;) {
7593 if (pendingsigs)
7594 dotrap();
7595 inter = 0;
7596 if (iflag && top) {
7597 inter++;
7598 showjobs(1);
Eric Andersend35c5df2002-01-09 15:37:36 +00007599#ifdef CONFIG_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +00007600 chkmail(0);
Eric Andersenec074692001-10-31 11:05:49 +00007601#endif
Eric Andersen3102ac42001-07-06 04:26:23 +00007602 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00007603 }
7604 n = parsecmd(inter);
7605 /* showtree(n); DEBUG */
7606 if (n == NEOF) {
7607 if (!top || numeof >= 50)
7608 break;
7609 if (!stoppedjobs()) {
7610 if (!Iflag)
7611 break;
7612 out2str("\nUse \"exit\" to leave shell.\n");
7613 }
7614 numeof++;
7615 } else if (n != NULL && nflag == 0) {
7616 job_warning = (job_warning == 2) ? 1 : 0;
7617 numeof = 0;
7618 evaltree(n, 0);
7619 }
7620 popstackmark(&smark);
7621 setstackmark(&smark);
7622 if (evalskip == SKIPFILE) {
7623 evalskip = 0;
7624 break;
7625 }
7626 }
7627 popstackmark(&smark);
7628}
7629
7630
7631
7632/*
7633 * Read /etc/profile or .profile. Return on error.
7634 */
7635
7636static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007637read_profile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00007638{
7639 int fd;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007640 int xflag_save;
7641 int vflag_save;
Eric Andersencb57d552001-06-28 07:25:16 +00007642
7643 INTOFF;
7644 if ((fd = open(name, O_RDONLY)) >= 0)
7645 setinputfd(fd, 1);
7646 INTON;
7647 if (fd < 0)
7648 return;
7649 /* -q turns off -x and -v just when executing init files */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007650 /* Note: Might do a little redundant work, but reduces code size. */
7651 xflag_save = xflag;
7652 vflag_save = vflag;
Eric Andersencb57d552001-06-28 07:25:16 +00007653 if (qflag) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007654 vflag = xflag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007655 }
7656 cmdloop(0);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007657 xflag = xflag_save;
7658 vflag = vflag_save;
Eric Andersencb57d552001-06-28 07:25:16 +00007659 popfile();
7660}
7661
7662
7663
7664/*
7665 * Read a file containing shell functions.
7666 */
7667
7668static void
Eric Andersen2870d962001-07-02 17:27:21 +00007669readcmdfile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00007670{
7671 int fd;
7672
7673 INTOFF;
7674 if ((fd = open(name, O_RDONLY)) >= 0)
7675 setinputfd(fd, 1);
7676 else
7677 error("Can't open %s", name);
7678 INTON;
7679 cmdloop(0);
7680 popfile();
7681}
7682
7683
7684
7685/*
7686 * Take commands from a file. To be compatable we should do a path
7687 * search for the file, which is necessary to find sub-commands.
7688 */
7689
Eric Andersen62483552001-07-10 06:09:16 +00007690static inline char *
Eric Andersen74400cc2001-10-18 04:11:39 +00007691find_dot_file(char *mybasename)
Eric Andersencb57d552001-06-28 07:25:16 +00007692{
7693 char *fullname;
7694 const char *path = pathval();
7695 struct stat statb;
7696
7697 /* don't try this for absolute or relative paths */
7698 if (strchr(mybasename, '/'))
7699 return mybasename;
7700
7701 while ((fullname = padvance(&path, mybasename)) != NULL) {
7702 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
7703 /*
7704 * Don't bother freeing here, since it will
7705 * be freed by the caller.
7706 */
7707 return fullname;
7708 }
7709 stunalloc(fullname);
7710 }
7711
7712 /* not found in the PATH */
7713 error("%s: not found", mybasename);
7714 /* NOTREACHED */
7715}
7716
7717static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007718dotcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007719{
7720 struct strlist *sp;
Eric Andersen69a20f02001-10-31 10:40:37 +00007721 volatile struct shparam saveparam;
Eric Andersencb57d552001-06-28 07:25:16 +00007722 exitstatus = 0;
7723
7724 for (sp = cmdenviron; sp ; sp = sp->next)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007725 setvareq(xstrdup(sp->text), VSTRFIXED|VTEXTFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +00007726
Eric Andersen2870d962001-07-02 17:27:21 +00007727 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00007728 char *fullname;
7729 struct stackmark smark;
7730
7731 setstackmark(&smark);
7732 fullname = find_dot_file(argv[1]);
Eric Andersen69a20f02001-10-31 10:40:37 +00007733
7734 if (argc>2) {
7735 saveparam = shellparam;
7736 shellparam.malloc = 0;
7737 shellparam.nparam = argc - 2;
7738 shellparam.p = argv + 2;
7739 };
7740
Eric Andersencb57d552001-06-28 07:25:16 +00007741 setinputfile(fullname, 1);
7742 commandname = fullname;
7743 cmdloop(0);
7744 popfile();
Eric Andersen69a20f02001-10-31 10:40:37 +00007745
7746 if (argc>2) {
7747 freeparam(&shellparam);
7748 shellparam = saveparam;
7749 };
7750
Eric Andersencb57d552001-06-28 07:25:16 +00007751 popstackmark(&smark);
7752 }
7753 return exitstatus;
7754}
7755
7756
7757static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007758exitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007759{
7760 if (stoppedjobs())
7761 return 0;
7762 if (argc > 1)
7763 exitstatus = number(argv[1]);
7764 else
7765 exitstatus = oexitstatus;
7766 exitshell(exitstatus);
7767 /* NOTREACHED */
7768}
Eric Andersen62483552001-07-10 06:09:16 +00007769
Eric Andersen2870d962001-07-02 17:27:21 +00007770static pointer
7771stalloc(int nbytes)
Eric Andersencb57d552001-06-28 07:25:16 +00007772{
7773 char *p;
7774
7775 nbytes = ALIGN(nbytes);
7776 if (nbytes > stacknleft) {
7777 int blocksize;
7778 struct stack_block *sp;
7779
7780 blocksize = nbytes;
7781 if (blocksize < MINSIZE)
7782 blocksize = MINSIZE;
7783 INTOFF;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007784 sp = xmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
Eric Andersencb57d552001-06-28 07:25:16 +00007785 sp->prev = stackp;
7786 stacknxt = sp->space;
7787 stacknleft = blocksize;
7788 stackp = sp;
7789 INTON;
7790 }
7791 p = stacknxt;
7792 stacknxt += nbytes;
7793 stacknleft -= nbytes;
7794 return p;
7795}
7796
7797
7798static void
Eric Andersen2870d962001-07-02 17:27:21 +00007799stunalloc(pointer p)
7800{
Eric Andersencb57d552001-06-28 07:25:16 +00007801#ifdef DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +00007802 if (p == NULL) { /*DEBUG */
Eric Andersencb57d552001-06-28 07:25:16 +00007803 write(2, "stunalloc\n", 10);
7804 abort();
7805 }
7806#endif
7807 if (!(stacknxt >= (char *)p && (char *)p >= stackp->space)) {
7808 p = stackp->space;
7809 }
7810 stacknleft += stacknxt - (char *)p;
7811 stacknxt = p;
7812}
7813
7814
Eric Andersencb57d552001-06-28 07:25:16 +00007815static void
Eric Andersen2870d962001-07-02 17:27:21 +00007816setstackmark(struct stackmark *mark)
7817{
Eric Andersencb57d552001-06-28 07:25:16 +00007818 mark->stackp = stackp;
7819 mark->stacknxt = stacknxt;
7820 mark->stacknleft = stacknleft;
7821 mark->marknext = markp;
7822 markp = mark;
7823}
7824
7825
7826static void
Eric Andersen2870d962001-07-02 17:27:21 +00007827popstackmark(struct stackmark *mark)
7828{
Eric Andersencb57d552001-06-28 07:25:16 +00007829 struct stack_block *sp;
7830
7831 INTOFF;
7832 markp = mark->marknext;
7833 while (stackp != mark->stackp) {
7834 sp = stackp;
7835 stackp = sp->prev;
7836 ckfree(sp);
7837 }
7838 stacknxt = mark->stacknxt;
7839 stacknleft = mark->stacknleft;
7840 INTON;
7841}
7842
7843
7844/*
7845 * When the parser reads in a string, it wants to stick the string on the
7846 * stack and only adjust the stack pointer when it knows how big the
7847 * string is. Stackblock (defined in stack.h) returns a pointer to a block
7848 * of space on top of the stack and stackblocklen returns the length of
7849 * this block. Growstackblock will grow this space by at least one byte,
7850 * possibly moving it (like realloc). Grabstackblock actually allocates the
7851 * part of the block that has been used.
7852 */
7853
7854static void
Eric Andersen2870d962001-07-02 17:27:21 +00007855growstackblock(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00007856 char *p;
7857 int newlen = ALIGN(stacknleft * 2 + 100);
7858 char *oldspace = stacknxt;
7859 int oldlen = stacknleft;
7860 struct stack_block *sp;
7861 struct stack_block *oldstackp;
7862
7863 if (stacknxt == stackp->space && stackp != &stackbase) {
7864 INTOFF;
7865 oldstackp = stackp;
7866 sp = stackp;
7867 stackp = sp->prev;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007868 sp = xrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen);
Eric Andersencb57d552001-06-28 07:25:16 +00007869 sp->prev = stackp;
7870 stackp = sp;
7871 stacknxt = sp->space;
7872 stacknleft = newlen;
7873 {
7874 /* Stack marks pointing to the start of the old block
Eric Andersen2870d962001-07-02 17:27:21 +00007875 * must be relocated to point to the new block
Eric Andersencb57d552001-06-28 07:25:16 +00007876 */
7877 struct stackmark *xmark;
7878 xmark = markp;
7879 while (xmark != NULL && xmark->stackp == oldstackp) {
7880 xmark->stackp = stackp;
7881 xmark->stacknxt = stacknxt;
7882 xmark->stacknleft = stacknleft;
7883 xmark = xmark->marknext;
7884 }
7885 }
7886 INTON;
7887 } else {
7888 p = stalloc(newlen);
7889 memcpy(p, oldspace, oldlen);
Eric Andersen2870d962001-07-02 17:27:21 +00007890 stacknxt = p; /* free the space */
7891 stacknleft += newlen; /* we just allocated */
Eric Andersencb57d552001-06-28 07:25:16 +00007892 }
7893}
7894
7895
7896
Eric Andersen2870d962001-07-02 17:27:21 +00007897static inline void
7898grabstackblock(int len)
Eric Andersencb57d552001-06-28 07:25:16 +00007899{
7900 len = ALIGN(len);
7901 stacknxt += len;
7902 stacknleft -= len;
7903}
7904
7905
7906
7907/*
7908 * The following routines are somewhat easier to use that the above.
7909 * The user declares a variable of type STACKSTR, which may be declared
7910 * to be a register. The macro STARTSTACKSTR initializes things. Then
7911 * the user uses the macro STPUTC to add characters to the string. In
7912 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
7913 * grown as necessary. When the user is done, she can just leave the
7914 * string there and refer to it using stackblock(). Or she can allocate
7915 * the space for it using grabstackstr(). If it is necessary to allow
7916 * someone else to use the stack temporarily and then continue to grow
7917 * the string, the user should use grabstack to allocate the space, and
7918 * then call ungrabstr(p) to return to the previous mode of operation.
7919 *
7920 * USTPUTC is like STPUTC except that it doesn't check for overflow.
7921 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
7922 * is space for at least one character.
7923 */
7924
7925
7926static char *
Eric Andersen2870d962001-07-02 17:27:21 +00007927growstackstr(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00007928 int len = stackblocksize();
7929 if (herefd >= 0 && len >= 1024) {
7930 xwrite(herefd, stackblock(), len);
7931 sstrnleft = len - 1;
7932 return stackblock();
7933 }
7934 growstackblock();
7935 sstrnleft = stackblocksize() - len - 1;
7936 return stackblock() + len;
7937}
7938
7939
7940/*
7941 * Called from CHECKSTRSPACE.
7942 */
7943
7944static char *
7945makestrspace(size_t newlen) {
7946 int len = stackblocksize() - sstrnleft;
7947 do {
7948 growstackblock();
7949 sstrnleft = stackblocksize() - len;
7950 } while (sstrnleft < newlen);
7951 return stackblock() + len;
7952}
7953
7954
7955
7956static void
Eric Andersen2870d962001-07-02 17:27:21 +00007957ungrabstackstr(char *s, char *p)
7958{
Eric Andersencb57d552001-06-28 07:25:16 +00007959 stacknleft += stacknxt - s;
7960 stacknxt = s;
7961 sstrnleft = stacknleft - (p - s);
7962}
Eric Andersencb57d552001-06-28 07:25:16 +00007963/*
7964 * Miscelaneous builtins.
7965 */
7966
7967
7968#undef rflag
7969
Eric Andersencb57d552001-06-28 07:25:16 +00007970#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersen62483552001-07-10 06:09:16 +00007971typedef long rlim_t;
Eric Andersencb57d552001-06-28 07:25:16 +00007972#endif
7973
7974
7975
7976/*
7977 * The read builtin. The -e option causes backslashes to escape the
7978 * following character.
7979 *
7980 * This uses unbuffered input, which may be avoidable in some cases.
7981 */
7982
7983static int
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007984readcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007985{
7986 char **ap;
7987 int backslash;
7988 char c;
7989 int rflag;
7990 char *prompt;
7991 const char *ifs;
7992 char *p;
7993 int startword;
7994 int status;
7995 int i;
7996
7997 rflag = 0;
7998 prompt = NULL;
7999 while ((i = nextopt("p:r")) != '\0') {
8000 if (i == 'p')
8001 prompt = optionarg;
8002 else
8003 rflag = 1;
8004 }
8005 if (prompt && isatty(0)) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008006 out2str(prompt); /* read without cmdedit */
Eric Andersencb57d552001-06-28 07:25:16 +00008007 flushall();
8008 }
8009 if (*(ap = argptr) == NULL)
8010 error("arg count");
8011 if ((ifs = bltinlookup("IFS")) == NULL)
8012 ifs = defifs;
8013 status = 0;
8014 startword = 1;
8015 backslash = 0;
8016 STARTSTACKSTR(p);
8017 for (;;) {
8018 if (read(0, &c, 1) != 1) {
8019 status = 1;
8020 break;
8021 }
8022 if (c == '\0')
8023 continue;
8024 if (backslash) {
8025 backslash = 0;
8026 if (c != '\n')
8027 STPUTC(c, p);
8028 continue;
8029 }
8030 if (!rflag && c == '\\') {
8031 backslash++;
8032 continue;
8033 }
8034 if (c == '\n')
8035 break;
8036 if (startword && *ifs == ' ' && strchr(ifs, c)) {
8037 continue;
8038 }
8039 startword = 0;
8040 if (backslash && c == '\\') {
8041 if (read(0, &c, 1) != 1) {
8042 status = 1;
8043 break;
8044 }
8045 STPUTC(c, p);
8046 } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
8047 STACKSTRNUL(p);
8048 setvar(*ap, stackblock(), 0);
8049 ap++;
8050 startword = 1;
8051 STARTSTACKSTR(p);
8052 } else {
8053 STPUTC(c, p);
8054 }
8055 }
8056 STACKSTRNUL(p);
8057 /* Remove trailing blanks */
8058 while (stackblock() <= --p && strchr(ifs, *p) != NULL)
8059 *p = '\0';
8060 setvar(*ap, stackblock(), 0);
8061 while (*++ap != NULL)
8062 setvar(*ap, nullstr, 0);
8063 return status;
8064}
8065
8066
8067
8068static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008069umaskcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008070{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008071 static const char permuser[3] = "ugo";
8072 static const char permmode[3] = "rwx";
8073 static const short int permmask[] = {
8074 S_IRUSR, S_IWUSR, S_IXUSR,
8075 S_IRGRP, S_IWGRP, S_IXGRP,
8076 S_IROTH, S_IWOTH, S_IXOTH
8077 };
8078
Eric Andersencb57d552001-06-28 07:25:16 +00008079 char *ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008080 mode_t mask;
Eric Andersencb57d552001-06-28 07:25:16 +00008081 int i;
8082 int symbolic_mode = 0;
8083
Eric Andersen62483552001-07-10 06:09:16 +00008084 while (nextopt("S") != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00008085 symbolic_mode = 1;
8086 }
8087
8088 INTOFF;
8089 mask = umask(0);
8090 umask(mask);
8091 INTON;
8092
8093 if ((ap = *argptr) == NULL) {
8094 if (symbolic_mode) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008095 char buf[18];
8096 char *p = buf;
8097 for (i=0 ; i<3 ; i++) {
8098 int j;
8099 *p++ = permuser[i];
8100 *p++ = '=';
8101 for (j=0 ; j<3 ; j++) {
8102 if ((mask & permmask[3*i+j]) == 0) {
8103 *p++ = permmode[j];
8104 }
8105 }
8106 *p++ = ',';
8107 }
8108 *--p = 0;
8109 puts(buf);
Eric Andersencb57d552001-06-28 07:25:16 +00008110 } else {
Eric Andersen62483552001-07-10 06:09:16 +00008111 printf("%.4o\n", mask);
Eric Andersencb57d552001-06-28 07:25:16 +00008112 }
8113 } else {
Eric Andersen62483552001-07-10 06:09:16 +00008114 if (is_digit((unsigned char)*ap)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008115 mask = 0;
8116 do {
8117 if (*ap >= '8' || *ap < '0')
8118 error("Illegal number: %s", argv[1]);
8119 mask = (mask << 3) + (*ap - '0');
8120 } while (*++ap != '\0');
8121 umask(mask);
8122 } else {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008123 mask = ~mask & 0777;
Matt Kraai1f0c4362001-12-20 23:13:26 +00008124 if (! parse_mode(ap, &mask)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008125 error("Illegal mode: %s", ap);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008126 }
Eric Andersencb57d552001-06-28 07:25:16 +00008127 umask(~mask & 0777);
8128 }
8129 }
8130 return 0;
8131}
8132
8133/*
8134 * ulimit builtin
8135 *
8136 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
8137 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
8138 * ash by J.T. Conklin.
8139 *
8140 * Public domain.
8141 */
8142
8143struct limits {
8144 const char *name;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008145 short cmd;
8146 short factor; /* multiply by to get rlim_{cur,max} values */
Eric Andersencb57d552001-06-28 07:25:16 +00008147};
8148
8149static const struct limits limits[] = {
8150#ifdef RLIMIT_CPU
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008151 { "time(seconds)", RLIMIT_CPU, 1 },
Eric Andersencb57d552001-06-28 07:25:16 +00008152#endif
8153#ifdef RLIMIT_FSIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008154 { "file(blocks)", RLIMIT_FSIZE, 512 },
Eric Andersencb57d552001-06-28 07:25:16 +00008155#endif
8156#ifdef RLIMIT_DATA
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008157 { "data(kbytes)", RLIMIT_DATA, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008158#endif
8159#ifdef RLIMIT_STACK
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008160 { "stack(kbytes)", RLIMIT_STACK, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008161#endif
8162#ifdef RLIMIT_CORE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008163 { "coredump(blocks)", RLIMIT_CORE, 512 },
Eric Andersencb57d552001-06-28 07:25:16 +00008164#endif
8165#ifdef RLIMIT_RSS
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008166 { "memory(kbytes)", RLIMIT_RSS, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008167#endif
8168#ifdef RLIMIT_MEMLOCK
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008169 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008170#endif
8171#ifdef RLIMIT_NPROC
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008172 { "process(processes)", RLIMIT_NPROC, 1 },
Eric Andersencb57d552001-06-28 07:25:16 +00008173#endif
8174#ifdef RLIMIT_NOFILE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008175 { "nofiles(descriptors)", RLIMIT_NOFILE, 1 },
Eric Andersencb57d552001-06-28 07:25:16 +00008176#endif
8177#ifdef RLIMIT_VMEM
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008178 { "vmemory(kbytes)", RLIMIT_VMEM, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008179#endif
8180#ifdef RLIMIT_SWAP
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008181 { "swap(kbytes)", RLIMIT_SWAP, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008182#endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008183 { NULL, 0, 0 }
Eric Andersencb57d552001-06-28 07:25:16 +00008184};
8185
8186static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008187ulimitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008188{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008189 static const char unlimited_string[] = "unlimited";
Eric Andersen2870d962001-07-02 17:27:21 +00008190 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00008191 rlim_t val = 0;
8192 enum { SOFT = 0x1, HARD = 0x2 }
8193 how = SOFT | HARD;
Eric Andersen2870d962001-07-02 17:27:21 +00008194 const struct limits *l;
8195 int set, all = 0;
8196 int optc, what;
8197 struct rlimit limit;
Eric Andersencb57d552001-06-28 07:25:16 +00008198
8199 what = 'f';
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008200
8201 while ((optc = nextopt("HSa"
8202#ifdef RLIMIT_CPU
8203 "t"
8204#endif
8205#ifdef RLIMIT_FSIZE
8206 "f"
8207#endif
8208#ifdef RLIMIT_DATA
8209 "d"
8210#endif
8211#ifdef RLIMIT_STACK
8212 "s"
8213#endif
8214#ifdef RLIMIT_CORE
8215 "c"
8216#endif
8217#ifdef RLIMIT_RSS
8218 "m"
8219#endif
8220#ifdef RLIMIT_MEMLOCK
8221 "l"
8222#endif
8223#ifdef RLIMIT_NPROC
8224 "p"
8225#endif
8226#ifdef RLIMIT_NOFILE
8227 "n"
8228#endif
8229#ifdef RLIMIT_VMEM
8230 "v"
8231#endif
8232#ifdef RLIMIT_SWAP
8233 "w"
8234#endif
8235 )) != '\0') {
8236 if (optc == 'H') {
Eric Andersencb57d552001-06-28 07:25:16 +00008237 how = HARD;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008238 } else if (optc == 'S') {
Eric Andersencb57d552001-06-28 07:25:16 +00008239 how = SOFT;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008240 } else if (optc == 'a') {
Eric Andersencb57d552001-06-28 07:25:16 +00008241 all = 1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008242 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00008243 what = optc;
8244 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008245 }
Eric Andersencb57d552001-06-28 07:25:16 +00008246
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008247 for (l = limits; l->name; l++) {
8248 if(l->name[0] == what)
8249 break;
8250 if(l->name[1]=='w' && what=='w')
8251 break;
8252 }
Eric Andersencb57d552001-06-28 07:25:16 +00008253
8254 set = *argptr ? 1 : 0;
8255 if (set) {
8256 char *p = *argptr;
8257
8258 if (all || argptr[1])
8259 error("too many arguments");
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008260 if (strcmp(p, unlimited_string) == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00008261 val = RLIM_INFINITY;
8262 else {
8263 val = (rlim_t) 0;
8264
8265 while ((c = *p++) >= '0' && c <= '9')
8266 {
8267 val = (val * 10) + (long)(c - '0');
8268 if (val < (rlim_t) 0)
8269 break;
8270 }
8271 if (c)
8272 error("bad number");
8273 val *= l->factor;
8274 }
8275 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008276
Eric Andersencb57d552001-06-28 07:25:16 +00008277 if (all) {
8278 for (l = limits; l->name; l++) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008279 printf("%-20s ", l->name);
Eric Andersencb57d552001-06-28 07:25:16 +00008280 getrlimit(l->cmd, &limit);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008281 OUTPUT_LIMIT:
Eric Andersencb57d552001-06-28 07:25:16 +00008282 if (how & SOFT)
8283 val = limit.rlim_cur;
8284 else if (how & HARD)
8285 val = limit.rlim_max;
8286
Eric Andersencb57d552001-06-28 07:25:16 +00008287 if (val == RLIM_INFINITY)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008288 puts(unlimited_string);
Eric Andersencb57d552001-06-28 07:25:16 +00008289 else
8290 {
8291 val /= l->factor;
Eric Andersen62483552001-07-10 06:09:16 +00008292 printf("%lld\n", (long long) val);
Eric Andersencb57d552001-06-28 07:25:16 +00008293 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008294 if (!all) {
8295 break;
8296 }
Eric Andersencb57d552001-06-28 07:25:16 +00008297 }
8298 return 0;
8299 }
8300
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008301 if (!set) {
8302 goto OUTPUT_LIMIT;
Eric Andersencb57d552001-06-28 07:25:16 +00008303 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008304
8305 getrlimit(l->cmd, &limit);
8306 if (how & HARD)
8307 limit.rlim_max = val;
8308 if (how & SOFT)
8309 limit.rlim_cur = val;
8310 if (setrlimit(l->cmd, &limit) < 0)
8311 error("error setting limit (%m)");
Eric Andersencb57d552001-06-28 07:25:16 +00008312 return 0;
8313}
Eric Andersencb57d552001-06-28 07:25:16 +00008314/*
8315 * prefix -- see if pfx is a prefix of string.
8316 */
8317
8318static int
Eric Andersen62483552001-07-10 06:09:16 +00008319prefix(char const *pfx, char const *string)
8320{
Eric Andersencb57d552001-06-28 07:25:16 +00008321 while (*pfx) {
8322 if (*pfx++ != *string++)
8323 return 0;
8324 }
8325 return 1;
8326}
8327
Eric Andersen2870d962001-07-02 17:27:21 +00008328/*
8329 * Return true if s is a string of digits, and save munber in intptr
8330 * nagative is bad
8331 */
8332
8333static int
8334is_number(const char *p, int *intptr)
8335{
8336 int ret = 0;
8337
8338 do {
8339 if (! is_digit(*p))
8340 return 0;
8341 ret *= 10;
8342 ret += digit_val(*p);
8343 p++;
8344 } while (*p != '\0');
8345
8346 *intptr = ret;
8347 return 1;
8348}
Eric Andersencb57d552001-06-28 07:25:16 +00008349
8350/*
8351 * Convert a string of digits to an integer, printing an error message on
8352 * failure.
8353 */
8354
8355static int
Eric Andersen2870d962001-07-02 17:27:21 +00008356number(const char *s)
8357{
8358 int i;
8359 if (! is_number(s, &i))
Eric Andersencb57d552001-06-28 07:25:16 +00008360 error("Illegal number: %s", s);
Eric Andersen2870d962001-07-02 17:27:21 +00008361 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00008362}
8363
Eric Andersencb57d552001-06-28 07:25:16 +00008364/*
8365 * Produce a possibly single quoted string suitable as input to the shell.
8366 * The return string is allocated on the stack.
8367 */
8368
8369static char *
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008370single_quote(const char *s)
8371{
Eric Andersencb57d552001-06-28 07:25:16 +00008372 char *p;
8373
8374 STARTSTACKSTR(p);
8375
8376 do {
8377 char *q = p;
8378 size_t len1, len1p, len2, len2p;
8379
8380 len1 = strcspn(s, "'");
8381 len2 = strspn(s + len1, "'");
8382
8383 len1p = len1 ? len1 + 2 : len1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008384 len2p = len2 + ((len2 < 2) ? len2 : 2);
Eric Andersencb57d552001-06-28 07:25:16 +00008385
8386 CHECKSTRSPACE(len1p + len2p + 1, p);
8387
8388 if (len1) {
8389 *p = '\'';
Eric Andersencb57d552001-06-28 07:25:16 +00008390 q = p + 1 + len1;
8391 memcpy(p + 1, s, len1);
Eric Andersencb57d552001-06-28 07:25:16 +00008392 *q++ = '\'';
8393 s += len1;
8394 }
8395
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008396 if (len2 > 1) {
Eric Andersencb57d552001-06-28 07:25:16 +00008397 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008398 q += 1 + len2;
8399 memcpy(q + 1, s, len2);
8400 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008401 s += len2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008402 } else if (len2 == 1) {
8403 *q++ = '\\';
8404 *q = '\'';
8405 s++;
Eric Andersencb57d552001-06-28 07:25:16 +00008406 }
8407
8408 STADJUST(len1p + len2p, p);
8409 } while (*s);
8410
8411 USTPUTC(0, p);
8412
8413 return grabstackstr(p);
8414}
8415
8416/*
8417 * Like strdup but works with the ash stack.
8418 */
8419
8420static char *
8421sstrdup(const char *p)
8422{
8423 size_t len = strlen(p) + 1;
8424 return memcpy(stalloc(len), p, len);
8425}
8426
Eric Andersencb57d552001-06-28 07:25:16 +00008427
8428/*
Eric Andersencb57d552001-06-28 07:25:16 +00008429 * Routine for dealing with parsed shell commands.
8430 */
8431
8432
Eric Andersen62483552001-07-10 06:09:16 +00008433static void sizenodelist (const struct nodelist *);
8434static struct nodelist *copynodelist (const struct nodelist *);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008435static char *nodexstrdup (const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00008436
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00008437#define CALCSIZE_TABLE
8438#define COPYNODE_TABLE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008439#if defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE)
8440/*
8441 * To collect a lot of redundant code in case statements for copynode()
8442 * and calcsize(), we implement a mini language here. Each type of node
8443 * struct has an associated instruction sequence that operates on its
8444 * members via their offsets. The instruction are pack in unsigned chars
8445 * with format IIDDDDDE where the bits are
8446 * I : part of the instruction opcode, which are
8447 * 00 : member is a pointer to another node
8448 * 40 : member is an integer
8449 * 80 : member is a pointer to a nodelist
8450 * CC : member is a pointer to a char string
8451 * D : data - the actual offset of the member to operate on in the struct
8452 * (since we assume bit 0 is set, it is not shifted)
8453 * E : flag signaling end of instruction sequence
8454 *
8455 * WARNING: In order to handle larger offsets for 64bit archs, this code
8456 * assumes that no offset can be an odd number and stores the
8457 * end-of-instructions flag in bit 0.
8458 */
8459
8460#define NODE_INTEGER 0x40
8461#define NODE_NODELIST 0x80
8462#define NODE_CHARPTR 0xC0
8463#define NODE_NOMORE 0x01 /* Note: no offset should be odd (aligned)*/
8464#define NODE_MBRMASK 0xC0
8465#define NODE_OFFSETMASK 0x3E
8466
8467static const unsigned char copynode_ops[35] = {
8468#define COPYNODE_OPS0 0
8469 offsetof(union node, nbinary.ch2),
8470 offsetof(union node, nbinary.ch1)|NODE_NOMORE,
8471#define COPYNODE_OPS1 (COPYNODE_OPS0 + 2)
8472 offsetof(union node, ncmd.redirect),
8473 offsetof(union node, ncmd.args),
8474 offsetof(union node, ncmd.assign),
8475 offsetof(union node, ncmd.backgnd)|NODE_INTEGER|NODE_NOMORE,
8476#define COPYNODE_OPS2 (COPYNODE_OPS1 + 4)
8477 offsetof(union node, npipe.cmdlist)|NODE_NODELIST,
8478 offsetof(union node, npipe.backgnd)|NODE_INTEGER|NODE_NOMORE,
8479#define COPYNODE_OPS3 (COPYNODE_OPS2 + 2)
8480 offsetof(union node, nredir.redirect),
8481 offsetof(union node, nredir.n)|NODE_NOMORE,
8482#define COPYNODE_OPS4 (COPYNODE_OPS3 + 2)
8483 offsetof(union node, nif.elsepart),
8484 offsetof(union node, nif.ifpart),
8485 offsetof(union node, nif.test)|NODE_NOMORE,
8486#define COPYNODE_OPS5 (COPYNODE_OPS4 + 3)
8487 offsetof(union node, nfor.var)|NODE_CHARPTR,
8488 offsetof(union node, nfor.body),
8489 offsetof(union node, nfor.args)|NODE_NOMORE,
8490#define COPYNODE_OPS6 (COPYNODE_OPS5 + 3)
8491 offsetof(union node, ncase.cases),
8492 offsetof(union node, ncase.expr)|NODE_NOMORE,
8493#define COPYNODE_OPS7 (COPYNODE_OPS6 + 2)
8494 offsetof(union node, nclist.body),
8495 offsetof(union node, nclist.pattern),
8496 offsetof(union node, nclist.next)|NODE_NOMORE,
8497#define COPYNODE_OPS8 (COPYNODE_OPS7 + 3)
8498 offsetof(union node, narg.backquote)|NODE_NODELIST,
8499 offsetof(union node, narg.text)|NODE_CHARPTR,
8500 offsetof(union node, narg.next)|NODE_NOMORE,
8501#define COPYNODE_OPS9 (COPYNODE_OPS8 + 3)
8502 offsetof(union node, nfile.fname),
8503 offsetof(union node, nfile.fd)|NODE_INTEGER,
8504 offsetof(union node, nfile.next)|NODE_NOMORE,
8505#define COPYNODE_OPS10 (COPYNODE_OPS9 + 3)
8506 offsetof(union node, ndup.vname),
8507 offsetof(union node, ndup.dupfd)|NODE_INTEGER,
8508 offsetof(union node, ndup.fd)|NODE_INTEGER,
8509 offsetof(union node, ndup.next)|NODE_NOMORE,
8510#define COPYNODE_OPS11 (COPYNODE_OPS10 + 4)
8511 offsetof(union node, nhere.doc),
8512 offsetof(union node, nhere.fd)|NODE_INTEGER,
8513 offsetof(union node, nhere.next)|NODE_NOMORE,
8514#define COPYNODE_OPS12 (COPYNODE_OPS11 + 3)
8515 offsetof(union node, nnot.com)|NODE_NOMORE,
8516};
8517
8518#if COPYNODE_OPS12 != 34
8519#error COPYNODE_OPS12 is incorrect
8520#endif
8521
8522static const unsigned char copynode_ops_index[26] = {
8523 COPYNODE_OPS0, /* NSEMI */
8524 COPYNODE_OPS1, /* NCMD */
8525 COPYNODE_OPS2, /* NPIPE */
8526 COPYNODE_OPS3, /* NREDIR */
8527 COPYNODE_OPS3, /* NBACKGND */
8528 COPYNODE_OPS3, /* NSUBSHELL */
8529 COPYNODE_OPS0, /* NAND */
8530 COPYNODE_OPS0, /* NOR */
8531 COPYNODE_OPS4, /* NIF */
8532 COPYNODE_OPS0, /* NWHILE */
8533 COPYNODE_OPS0, /* NUNTIL */
8534 COPYNODE_OPS5, /* NFOR */
8535 COPYNODE_OPS6, /* NCASE */
8536 COPYNODE_OPS7, /* NCLIST */
8537 COPYNODE_OPS8, /* NDEFUN */
8538 COPYNODE_OPS8, /* NARG */
8539 COPYNODE_OPS9, /* NTO */
8540 COPYNODE_OPS9, /* NFROM */
8541 COPYNODE_OPS9, /* NFROMTO */
8542 COPYNODE_OPS9, /* NAPPEND */
8543 COPYNODE_OPS9, /* NTOOV */
8544 COPYNODE_OPS10, /* NTOFD */
8545 COPYNODE_OPS10, /* NFROMFD */
8546 COPYNODE_OPS11, /* NHERE */
8547 COPYNODE_OPS11, /* NXHERE */
8548 COPYNODE_OPS12, /* NNOT */
8549};
8550
8551#if NODE_CHARPTR != NODE_MBRMASK
8552#error NODE_CHARPTR != NODE_MBRMASK!!!
8553#endif
8554#endif /* defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE) */
8555
8556#ifdef COPYNODE_TABLE
8557static union node *
8558copynode(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008559{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008560 union node *new;
8561 const unsigned char *p;
8562
Manuel Novoa III c639a352001-08-12 17:32:56 +00008563 if (n == NULL) {
8564 return NULL;
8565 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008566 new = funcblock;
8567 new->type = n->type;
8568 funcblock = (char *) funcblock + (int) nodesize[n->type];
8569 p = copynode_ops + (int) copynode_ops_index[n->type];
8570 do {
8571 char *nn = ((char *) new) + ((int)(*p & NODE_OFFSETMASK));
8572 const char *no = ((const char *) n) + ((int)(*p & NODE_OFFSETMASK));
8573
8574 if (!(*p & NODE_MBRMASK)) { /* standard node */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008575 *((union node **)nn) = copynode(*((const union node **) no));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008576 } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008577 *((const char **)nn) = nodexstrdup(*((const char **)no));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008578 } else if (*p & NODE_NODELIST) { /* nodelist */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008579 *((struct nodelist **)nn)
8580 = copynodelist(*((const struct nodelist **) no));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008581 } else { /* integer */
8582 *((int *) nn) = *((int *) no);
8583 }
8584 } while (!(*p++ & NODE_NOMORE));
8585 return new;
Eric Andersencb57d552001-06-28 07:25:16 +00008586}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008587#else /* COPYNODE_TABLE */
Eric Andersencb57d552001-06-28 07:25:16 +00008588static union node *
Eric Andersen62483552001-07-10 06:09:16 +00008589copynode(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008590{
Eric Andersen62483552001-07-10 06:09:16 +00008591 union node *new;
Eric Andersencb57d552001-06-28 07:25:16 +00008592
8593 if (n == NULL)
Manuel Novoa III c639a352001-08-12 17:32:56 +00008594 return NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008595 new = funcblock;
8596 funcblock = (char *) funcblock + nodesize[n->type];
8597 switch (n->type) {
8598 case NSEMI:
8599 case NAND:
8600 case NOR:
8601 case NWHILE:
8602 case NUNTIL:
8603 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8604 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8605 break;
8606 case NCMD:
8607 new->ncmd.redirect = copynode(n->ncmd.redirect);
8608 new->ncmd.args = copynode(n->ncmd.args);
8609 new->ncmd.assign = copynode(n->ncmd.assign);
8610 new->ncmd.backgnd = n->ncmd.backgnd;
8611 break;
8612 case NPIPE:
8613 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8614 new->npipe.backgnd = n->npipe.backgnd;
8615 break;
8616 case NREDIR:
8617 case NBACKGND:
8618 case NSUBSHELL:
8619 new->nredir.redirect = copynode(n->nredir.redirect);
8620 new->nredir.n = copynode(n->nredir.n);
8621 break;
8622 case NIF:
8623 new->nif.elsepart = copynode(n->nif.elsepart);
8624 new->nif.ifpart = copynode(n->nif.ifpart);
8625 new->nif.test = copynode(n->nif.test);
8626 break;
8627 case NFOR:
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008628 new->nfor.var = nodexstrdup(n->nfor.var);
Eric Andersencb57d552001-06-28 07:25:16 +00008629 new->nfor.body = copynode(n->nfor.body);
8630 new->nfor.args = copynode(n->nfor.args);
8631 break;
8632 case NCASE:
8633 new->ncase.cases = copynode(n->ncase.cases);
8634 new->ncase.expr = copynode(n->ncase.expr);
8635 break;
8636 case NCLIST:
8637 new->nclist.body = copynode(n->nclist.body);
8638 new->nclist.pattern = copynode(n->nclist.pattern);
8639 new->nclist.next = copynode(n->nclist.next);
8640 break;
8641 case NDEFUN:
8642 case NARG:
8643 new->narg.backquote = copynodelist(n->narg.backquote);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008644 new->narg.text = nodexstrdup(n->narg.text);
Eric Andersencb57d552001-06-28 07:25:16 +00008645 new->narg.next = copynode(n->narg.next);
8646 break;
8647 case NTO:
8648 case NFROM:
8649 case NFROMTO:
8650 case NAPPEND:
8651 case NTOOV:
8652 new->nfile.fname = copynode(n->nfile.fname);
8653 new->nfile.fd = n->nfile.fd;
8654 new->nfile.next = copynode(n->nfile.next);
8655 break;
8656 case NTOFD:
8657 case NFROMFD:
8658 new->ndup.vname = copynode(n->ndup.vname);
8659 new->ndup.dupfd = n->ndup.dupfd;
8660 new->ndup.fd = n->ndup.fd;
8661 new->ndup.next = copynode(n->ndup.next);
8662 break;
8663 case NHERE:
8664 case NXHERE:
8665 new->nhere.doc = copynode(n->nhere.doc);
8666 new->nhere.fd = n->nhere.fd;
8667 new->nhere.next = copynode(n->nhere.next);
8668 break;
8669 case NNOT:
8670 new->nnot.com = copynode(n->nnot.com);
8671 break;
8672 };
8673 new->type = n->type;
Eric Andersen62483552001-07-10 06:09:16 +00008674 return new;
Eric Andersencb57d552001-06-28 07:25:16 +00008675}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008676#endif /* COPYNODE_TABLE */
8677
8678#ifdef CALCSIZE_TABLE
8679static void
8680calcsize(const union node *n)
8681{
8682 const unsigned char *p;
8683
8684 if (n == NULL)
8685 return;
8686 funcblocksize += (int) nodesize[n->type];
8687
8688 p = copynode_ops + (int) copynode_ops_index[n->type];
8689 do {
8690 const char *no = ((const char *) n) + ((int)(*p & NODE_OFFSETMASK));
8691
8692 if (!(*p & NODE_MBRMASK)) { /* standard node */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008693 calcsize(*((const union node **) no));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008694 } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008695 funcstringsize += strlen(*((const char **)no)) + 1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008696 } else if (*p & NODE_NODELIST) { /* nodelist */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008697 sizenodelist(*((const struct nodelist **) no));
8698 } /* else integer -- ignore */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008699 } while (!(*p++ & NODE_NOMORE));
8700}
8701#else /* CALCSIZE_TABLE */
8702static void
8703calcsize(const union node *n)
8704{
8705 if (n == NULL)
8706 return;
8707 funcblocksize += nodesize[n->type];
8708 switch (n->type) {
8709 case NSEMI:
8710 case NAND:
8711 case NOR:
8712 case NWHILE:
8713 case NUNTIL:
8714 calcsize(n->nbinary.ch2);
8715 calcsize(n->nbinary.ch1);
8716 break;
8717 case NCMD:
8718 calcsize(n->ncmd.redirect);
8719 calcsize(n->ncmd.args);
8720 calcsize(n->ncmd.assign);
8721 break;
8722 case NPIPE:
8723 sizenodelist(n->npipe.cmdlist);
8724 break;
8725 case NREDIR:
8726 case NBACKGND:
8727 case NSUBSHELL:
8728 calcsize(n->nredir.redirect);
8729 calcsize(n->nredir.n);
8730 break;
8731 case NIF:
8732 calcsize(n->nif.elsepart);
8733 calcsize(n->nif.ifpart);
8734 calcsize(n->nif.test);
8735 break;
8736 case NFOR:
8737 funcstringsize += strlen(n->nfor.var) + 1;
8738 calcsize(n->nfor.body);
8739 calcsize(n->nfor.args);
8740 break;
8741 case NCASE:
8742 calcsize(n->ncase.cases);
8743 calcsize(n->ncase.expr);
8744 break;
8745 case NCLIST:
8746 calcsize(n->nclist.body);
8747 calcsize(n->nclist.pattern);
8748 calcsize(n->nclist.next);
8749 break;
8750 case NDEFUN:
8751 case NARG:
8752 sizenodelist(n->narg.backquote);
8753 funcstringsize += strlen(n->narg.text) + 1;
8754 calcsize(n->narg.next);
8755 break;
8756 case NTO:
8757 case NFROM:
8758 case NFROMTO:
8759 case NAPPEND:
8760 case NTOOV:
8761 calcsize(n->nfile.fname);
8762 calcsize(n->nfile.next);
8763 break;
8764 case NTOFD:
8765 case NFROMFD:
8766 calcsize(n->ndup.vname);
8767 calcsize(n->ndup.next);
8768 break;
8769 case NHERE:
8770 case NXHERE:
8771 calcsize(n->nhere.doc);
8772 calcsize(n->nhere.next);
8773 break;
8774 case NNOT:
8775 calcsize(n->nnot.com);
8776 break;
8777 };
8778}
8779#endif /* CALCSIZE_TABLE */
8780
8781static void
8782sizenodelist(const struct nodelist *lp)
8783{
8784 while (lp) {
8785 funcblocksize += ALIGN(sizeof(struct nodelist));
8786 calcsize(lp->n);
8787 lp = lp->next;
8788 }
8789}
Eric Andersencb57d552001-06-28 07:25:16 +00008790
8791
8792static struct nodelist *
Eric Andersen62483552001-07-10 06:09:16 +00008793copynodelist(const struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008794{
8795 struct nodelist *start;
8796 struct nodelist **lpp;
8797
8798 lpp = &start;
8799 while (lp) {
8800 *lpp = funcblock;
8801 funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist));
8802 (*lpp)->n = copynode(lp->n);
8803 lp = lp->next;
8804 lpp = &(*lpp)->next;
8805 }
8806 *lpp = NULL;
8807 return start;
8808}
8809
8810
Eric Andersencb57d552001-06-28 07:25:16 +00008811static char *
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008812nodexstrdup(const char *s)
Eric Andersencb57d552001-06-28 07:25:16 +00008813{
Eric Andersen62483552001-07-10 06:09:16 +00008814 const char *p = s;
8815 char *q = funcstring;
Eric Andersencb57d552001-06-28 07:25:16 +00008816 char *rtn = funcstring;
8817
8818 while ((*q++ = *p++) != '\0')
8819 continue;
8820 funcstring = q;
8821 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00008822}
8823
Eric Andersend35c5df2002-01-09 15:37:36 +00008824#ifdef CONFIG_ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00008825static int getopts (char *, char *, char **, int *, int *);
Eric Andersencb57d552001-06-28 07:25:16 +00008826#endif
8827
8828
8829/*
8830 * Process the shell command line arguments.
8831 */
8832
8833static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008834procargs(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008835{
8836 int i;
8837
8838 argptr = argv;
8839 if (argc > 0)
8840 argptr++;
8841 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00008842 optent_val(i) = 2;
Eric Andersencb57d552001-06-28 07:25:16 +00008843 options(1);
8844 if (*argptr == NULL && minusc == NULL)
8845 sflag = 1;
8846 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8847 iflag = 1;
8848 if (mflag == 2)
8849 mflag = iflag;
8850 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00008851 if (optent_val(i) == 2)
8852 optent_val(i) = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008853 arg0 = argv[0];
8854 if (sflag == 0 && minusc == NULL) {
8855 commandname = argv[0];
8856 arg0 = *argptr++;
8857 setinputfile(arg0, 0);
8858 commandname = arg0;
8859 }
8860 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8861 if (argptr && minusc && *argptr)
Eric Andersen2870d962001-07-02 17:27:21 +00008862 arg0 = *argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00008863
8864 shellparam.p = argptr;
8865 shellparam.optind = 1;
8866 shellparam.optoff = -1;
8867 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8868 while (*argptr) {
8869 shellparam.nparam++;
8870 argptr++;
8871 }
8872 optschanged();
8873}
8874
8875
Eric Andersencb57d552001-06-28 07:25:16 +00008876
8877/*
8878 * Process shell options. The global variable argptr contains a pointer
8879 * to the argument list; we advance it past the options.
8880 */
8881
Eric Andersen62483552001-07-10 06:09:16 +00008882static inline void
8883minus_o(const char *name, int val)
8884{
8885 int i;
8886
8887 if (name == NULL) {
8888 out1str("Current option settings\n");
8889 for (i = 0; i < NOPTS; i++)
8890 printf("%-16s%s\n", optent_name(optlist[i]),
8891 optent_val(i) ? "on" : "off");
8892 } else {
8893 for (i = 0; i < NOPTS; i++)
8894 if (equal(name, optent_name(optlist[i]))) {
8895 setoption(optent_letter(optlist[i]), val);
8896 return;
8897 }
8898 error("Illegal option -o %s", name);
8899 }
8900}
8901
8902
Eric Andersencb57d552001-06-28 07:25:16 +00008903static void
Eric Andersen62483552001-07-10 06:09:16 +00008904options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00008905{
8906 char *p;
8907 int val;
8908 int c;
8909
8910 if (cmdline)
8911 minusc = NULL;
8912 while ((p = *argptr) != NULL) {
8913 argptr++;
8914 if ((c = *p++) == '-') {
8915 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00008916 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8917 if (!cmdline) {
8918 /* "-" means turn off -x and -v */
8919 if (p[0] == '\0')
8920 xflag = vflag = 0;
8921 /* "--" means reset params */
8922 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00008923 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00008924 }
8925 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00008926 }
8927 } else if (c == '+') {
8928 val = 0;
8929 } else {
8930 argptr--;
8931 break;
8932 }
8933 while ((c = *p++) != '\0') {
8934 if (c == 'c' && cmdline) {
8935 char *q;
Eric Andersen2870d962001-07-02 17:27:21 +00008936#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */
Eric Andersencb57d552001-06-28 07:25:16 +00008937 if (*p == '\0')
8938#endif
8939 q = *argptr++;
8940 if (q == NULL || minusc != NULL)
8941 error("Bad -c option");
8942 minusc = q;
8943#ifdef NOHACK
8944 break;
8945#endif
8946 } else if (c == 'o') {
8947 minus_o(*argptr, val);
8948 if (*argptr)
8949 argptr++;
8950 } else {
8951 setoption(c, val);
8952 }
8953 }
8954 }
8955}
8956
Eric Andersencb57d552001-06-28 07:25:16 +00008957
8958static void
Eric Andersen2870d962001-07-02 17:27:21 +00008959setoption(int flag, int val)
8960{
Eric Andersencb57d552001-06-28 07:25:16 +00008961 int i;
8962
8963 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00008964 if (optent_letter(optlist[i]) == flag) {
8965 optent_val(i) = val;
Eric Andersencb57d552001-06-28 07:25:16 +00008966 if (val) {
8967 /* #%$ hack for ksh semantics */
8968 if (flag == 'V')
8969 Eflag = 0;
8970 else if (flag == 'E')
8971 Vflag = 0;
8972 }
8973 return;
8974 }
8975 error("Illegal option -%c", flag);
8976 /* NOTREACHED */
8977}
8978
8979
8980
Eric Andersencb57d552001-06-28 07:25:16 +00008981/*
8982 * Set the shell parameters.
8983 */
8984
8985static void
Eric Andersen2870d962001-07-02 17:27:21 +00008986setparam(char **argv)
8987{
Eric Andersencb57d552001-06-28 07:25:16 +00008988 char **newparam;
8989 char **ap;
8990 int nparam;
8991
8992 for (nparam = 0 ; argv[nparam] ; nparam++);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008993 ap = newparam = xmalloc((nparam + 1) * sizeof *ap);
Eric Andersencb57d552001-06-28 07:25:16 +00008994 while (*argv) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008995 *ap++ = xstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +00008996 }
8997 *ap = NULL;
8998 freeparam(&shellparam);
8999 shellparam.malloc = 1;
9000 shellparam.nparam = nparam;
9001 shellparam.p = newparam;
9002 shellparam.optind = 1;
9003 shellparam.optoff = -1;
9004}
9005
9006
9007/*
9008 * Free the list of positional parameters.
9009 */
9010
9011static void
Eric Andersen2870d962001-07-02 17:27:21 +00009012freeparam(volatile struct shparam *param)
9013{
Eric Andersencb57d552001-06-28 07:25:16 +00009014 char **ap;
9015
9016 if (param->malloc) {
9017 for (ap = param->p ; *ap ; ap++)
9018 ckfree(*ap);
9019 ckfree(param->p);
9020 }
9021}
9022
9023
9024
9025/*
9026 * The shift builtin command.
9027 */
9028
9029static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00009030shiftcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009031{
9032 int n;
9033 char **ap1, **ap2;
9034
9035 n = 1;
9036 if (argc > 1)
9037 n = number(argv[1]);
9038 if (n > shellparam.nparam)
9039 error("can't shift that many");
9040 INTOFF;
9041 shellparam.nparam -= n;
9042 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
9043 if (shellparam.malloc)
9044 ckfree(*ap1);
9045 }
9046 ap2 = shellparam.p;
9047 while ((*ap2++ = *ap1++) != NULL);
9048 shellparam.optind = 1;
9049 shellparam.optoff = -1;
9050 INTON;
9051 return 0;
9052}
9053
9054
9055
9056/*
9057 * The set command builtin.
9058 */
9059
9060static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00009061setcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009062{
9063 if (argc == 1)
9064 return showvarscmd(argc, argv);
9065 INTOFF;
9066 options(0);
9067 optschanged();
9068 if (*argptr != NULL) {
9069 setparam(argptr);
9070 }
9071 INTON;
9072 return 0;
9073}
9074
9075
9076static void
Eric Andersen2870d962001-07-02 17:27:21 +00009077getoptsreset(const char *value)
Eric Andersencb57d552001-06-28 07:25:16 +00009078{
9079 shellparam.optind = number(value);
9080 shellparam.optoff = -1;
9081}
9082
Eric Andersenbdfd0d72001-10-24 05:00:29 +00009083#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00009084static void change_lc_all(const char *value)
9085{
9086 if(value != 0 && *value != 0)
9087 setlocale(LC_ALL, value);
9088}
9089
9090static void change_lc_ctype(const char *value)
9091{
9092 if(value != 0 && *value != 0)
9093 setlocale(LC_CTYPE, value);
9094}
9095
9096#endif
9097
Eric Andersend35c5df2002-01-09 15:37:36 +00009098#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00009099/*
9100 * The getopts builtin. Shellparam.optnext points to the next argument
9101 * to be processed. Shellparam.optptr points to the next character to
9102 * be processed in the current argument. If shellparam.optnext is NULL,
9103 * then it's the first time getopts has been called.
9104 */
9105
9106static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00009107getoptscmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009108{
9109 char **optbase;
9110
9111 if (argc < 3)
9112 error("Usage: getopts optstring var [arg]");
9113 else if (argc == 3) {
9114 optbase = shellparam.p;
9115 if (shellparam.optind > shellparam.nparam + 1) {
9116 shellparam.optind = 1;
9117 shellparam.optoff = -1;
9118 }
9119 }
9120 else {
9121 optbase = &argv[3];
9122 if (shellparam.optind > argc - 2) {
9123 shellparam.optind = 1;
9124 shellparam.optoff = -1;
9125 }
9126 }
9127
9128 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9129 &shellparam.optoff);
9130}
9131
9132/*
9133 * Safe version of setvar, returns 1 on success 0 on failure.
9134 */
9135
9136static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00009137setvarsafe(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009138{
9139 struct jmploc jmploc;
9140 struct jmploc *volatile savehandler = handler;
9141 int err = 0;
9142#ifdef __GNUC__
9143 (void) &err;
9144#endif
9145
9146 if (setjmp(jmploc.loc))
9147 err = 1;
9148 else {
9149 handler = &jmploc;
9150 setvar(name, val, flags);
9151 }
9152 handler = savehandler;
9153 return err;
9154}
9155
9156static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00009157getopts(char *optstr, char *optvar, char **optfirst, int *myoptind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009158{
9159 char *p, *q;
9160 char c = '?';
9161 int done = 0;
9162 int err = 0;
9163 char s[10];
9164 char **optnext = optfirst + *myoptind - 1;
9165
9166 if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
9167 strlen(*(optnext - 1)) < *optoff)
9168 p = NULL;
9169 else
9170 p = *(optnext - 1) + *optoff;
9171 if (p == NULL || *p == '\0') {
9172 /* Current word is done, advance */
9173 if (optnext == NULL)
9174 return 1;
9175 p = *optnext;
9176 if (p == NULL || *p != '-' || *++p == '\0') {
9177atend:
9178 *myoptind = optnext - optfirst + 1;
9179 p = NULL;
9180 done = 1;
9181 goto out;
9182 }
9183 optnext++;
Eric Andersen2870d962001-07-02 17:27:21 +00009184 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009185 goto atend;
9186 }
9187
9188 c = *p++;
9189 for (q = optstr; *q != c; ) {
9190 if (*q == '\0') {
9191 if (optstr[0] == ':') {
9192 s[0] = c;
9193 s[1] = '\0';
9194 err |= setvarsafe("OPTARG", s, 0);
9195 }
9196 else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009197 out2fmt("Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009198 (void) unsetvar("OPTARG");
9199 }
9200 c = '?';
9201 goto bad;
9202 }
9203 if (*++q == ':')
9204 q++;
9205 }
9206
9207 if (*++q == ':') {
9208 if (*p == '\0' && (p = *optnext) == NULL) {
9209 if (optstr[0] == ':') {
9210 s[0] = c;
9211 s[1] = '\0';
9212 err |= setvarsafe("OPTARG", s, 0);
9213 c = ':';
9214 }
9215 else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009216 out2fmt("No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009217 (void) unsetvar("OPTARG");
9218 c = '?';
9219 }
9220 goto bad;
9221 }
9222
9223 if (p == *optnext)
9224 optnext++;
9225 setvarsafe("OPTARG", p, 0);
9226 p = NULL;
9227 }
9228 else
9229 setvarsafe("OPTARG", "", 0);
9230 *myoptind = optnext - optfirst + 1;
9231 goto out;
9232
9233bad:
9234 *myoptind = 1;
9235 p = NULL;
9236out:
9237 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersen3102ac42001-07-06 04:26:23 +00009238 snprintf(s, sizeof(s), "%d", *myoptind);
Eric Andersencb57d552001-06-28 07:25:16 +00009239 err |= setvarsafe("OPTIND", s, VNOFUNC);
9240 s[0] = c;
9241 s[1] = '\0';
9242 err |= setvarsafe(optvar, s, 0);
9243 if (err) {
9244 *myoptind = 1;
9245 *optoff = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00009246 exraise(EXERROR);
9247 }
9248 return done;
9249}
Eric Andersen2870d962001-07-02 17:27:21 +00009250#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009251
9252/*
9253 * XXX - should get rid of. have all builtins use getopt(3). the
9254 * library getopt must have the BSD extension static variable "optreset"
9255 * otherwise it can't be used within the shell safely.
9256 *
9257 * Standard option processing (a la getopt) for builtin routines. The
9258 * only argument that is passed to nextopt is the option string; the
9259 * other arguments are unnecessary. It return the character, or '\0' on
9260 * end of input.
9261 */
9262
9263static int
Eric Andersen62483552001-07-10 06:09:16 +00009264nextopt(const char *optstring)
9265{
Eric Andersencb57d552001-06-28 07:25:16 +00009266 char *p;
9267 const char *q;
9268 char c;
9269
9270 if ((p = optptr) == NULL || *p == '\0') {
9271 p = *argptr;
9272 if (p == NULL || *p != '-' || *++p == '\0')
9273 return '\0';
9274 argptr++;
Eric Andersen2870d962001-07-02 17:27:21 +00009275 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009276 return '\0';
9277 }
9278 c = *p++;
9279 for (q = optstring ; *q != c ; ) {
9280 if (*q == '\0')
9281 error("Illegal option -%c", c);
9282 if (*++q == ':')
9283 q++;
9284 }
9285 if (*++q == ':') {
9286 if (*p == '\0' && (p = *argptr++) == NULL)
9287 error("No arg for -%c option", c);
9288 optionarg = p;
9289 p = NULL;
9290 }
9291 optptr = p;
9292 return c;
9293}
9294
Eric Andersencb57d552001-06-28 07:25:16 +00009295static void
9296flushall() {
Eric Andersencb57d552001-06-28 07:25:16 +00009297 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009298 fflush(stdout);
Eric Andersencb57d552001-06-28 07:25:16 +00009299 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009300}
9301
9302
9303static void
Eric Andersen3102ac42001-07-06 04:26:23 +00009304out2fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009305{
9306 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00009307 va_start(ap, fmt);
Eric Andersen3102ac42001-07-06 04:26:23 +00009308 vfprintf(stderr, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009309 va_end(ap);
9310}
9311
Eric Andersencb57d552001-06-28 07:25:16 +00009312/*
9313 * Version of write which resumes after a signal is caught.
9314 */
9315
9316static int
Eric Andersen2870d962001-07-02 17:27:21 +00009317xwrite(int fd, const char *buf, int nbytes)
9318{
Eric Andersencb57d552001-06-28 07:25:16 +00009319 int ntry;
9320 int i;
9321 int n;
9322
9323 n = nbytes;
9324 ntry = 0;
9325 for (;;) {
9326 i = write(fd, buf, n);
9327 if (i > 0) {
9328 if ((n -= i) <= 0)
9329 return nbytes;
9330 buf += i;
9331 ntry = 0;
9332 } else if (i == 0) {
9333 if (++ntry > 10)
9334 return nbytes - n;
9335 } else if (errno != EINTR) {
9336 return -1;
9337 }
9338 }
9339}
9340
9341
Eric Andersencb57d552001-06-28 07:25:16 +00009342/*
9343 * Shell command parser.
9344 */
9345
9346#define EOFMARKLEN 79
9347
9348
9349
9350struct heredoc {
Eric Andersen2870d962001-07-02 17:27:21 +00009351 struct heredoc *next; /* next here document in list */
9352 union node *here; /* redirection node */
9353 char *eofmark; /* string indicating end of input */
9354 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009355};
9356
Eric Andersen2870d962001-07-02 17:27:21 +00009357static struct heredoc *heredoclist; /* list of here documents to read */
9358static int parsebackquote; /* nonzero if we are inside backquotes */
9359static int doprompt; /* if set, prompt the user */
9360static int needprompt; /* true if interactive and at start of line */
9361static int lasttoken; /* last token read */
Eric Andersencb57d552001-06-28 07:25:16 +00009362
Eric Andersen2870d962001-07-02 17:27:21 +00009363static char *wordtext; /* text of last word returned by readtoken */
Eric Andersencb57d552001-06-28 07:25:16 +00009364
Eric Andersen2870d962001-07-02 17:27:21 +00009365static struct nodelist *backquotelist;
9366static union node *redirnode;
Eric Andersen044228d2001-07-17 01:12:36 +00009367static struct heredoc *heredoc;
Eric Andersen2870d962001-07-02 17:27:21 +00009368static int quoteflag; /* set if (part of) last token was quoted */
9369static int startlinno; /* line # where last token started */
Eric Andersencb57d552001-06-28 07:25:16 +00009370
9371
Eric Andersen2870d962001-07-02 17:27:21 +00009372static union node *list (int);
9373static union node *andor (void);
9374static union node *pipeline (void);
9375static union node *command (void);
Eric Andersena3483db2001-10-24 08:01:06 +00009376static union node *simplecmd(union node **rpp, union node *redir);
Eric Andersen2870d962001-07-02 17:27:21 +00009377static void parsefname (void);
9378static void parseheredoc (void);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009379static char peektoken (void);
Eric Andersen2870d962001-07-02 17:27:21 +00009380static int readtoken (void);
9381static int xxreadtoken (void);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009382static int readtoken1 (int, int, const char *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00009383static int noexpand (char *);
9384static void synexpect (int) __attribute__((noreturn));
9385static void synerror (const char *) __attribute__((noreturn));
9386static void setprompt (int);
Eric Andersencb57d552001-06-28 07:25:16 +00009387
9388
9389/*
9390 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9391 * valid parse tree indicating a blank line.)
9392 */
9393
Eric Andersen2870d962001-07-02 17:27:21 +00009394static union node *
Eric Andersencb57d552001-06-28 07:25:16 +00009395parsecmd(int interact)
9396{
9397 int t;
9398
9399 tokpushback = 0;
9400 doprompt = interact;
9401 if (doprompt)
9402 setprompt(1);
9403 else
9404 setprompt(0);
9405 needprompt = 0;
9406 t = readtoken();
9407 if (t == TEOF)
9408 return NEOF;
9409 if (t == TNL)
9410 return NULL;
9411 tokpushback++;
9412 return list(1);
9413}
9414
9415
9416static union node *
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00009417list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +00009418{
9419 union node *n1, *n2, *n3;
9420 int tok;
9421
9422 checkkwd = 2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009423 if (nlflag == 0 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009424 return NULL;
9425 n1 = NULL;
9426 for (;;) {
9427 n2 = andor();
9428 tok = readtoken();
9429 if (tok == TBACKGND) {
9430 if (n2->type == NCMD || n2->type == NPIPE) {
9431 n2->ncmd.backgnd = 1;
9432 } else if (n2->type == NREDIR) {
9433 n2->type = NBACKGND;
9434 } else {
9435 n3 = (union node *)stalloc(sizeof (struct nredir));
9436 n3->type = NBACKGND;
9437 n3->nredir.n = n2;
9438 n3->nredir.redirect = NULL;
9439 n2 = n3;
9440 }
9441 }
9442 if (n1 == NULL) {
9443 n1 = n2;
9444 }
9445 else {
9446 n3 = (union node *)stalloc(sizeof (struct nbinary));
9447 n3->type = NSEMI;
9448 n3->nbinary.ch1 = n1;
9449 n3->nbinary.ch2 = n2;
9450 n1 = n3;
9451 }
9452 switch (tok) {
9453 case TBACKGND:
9454 case TSEMI:
9455 tok = readtoken();
9456 /* fall through */
9457 case TNL:
9458 if (tok == TNL) {
9459 parseheredoc();
9460 if (nlflag)
9461 return n1;
9462 } else {
9463 tokpushback++;
9464 }
9465 checkkwd = 2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009466 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009467 return n1;
9468 break;
9469 case TEOF:
9470 if (heredoclist)
9471 parseheredoc();
9472 else
Eric Andersen2870d962001-07-02 17:27:21 +00009473 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009474 return n1;
9475 default:
9476 if (nlflag)
9477 synexpect(-1);
9478 tokpushback++;
9479 return n1;
9480 }
9481 }
9482}
9483
9484
9485
9486static union node *
9487andor() {
9488 union node *n1, *n2, *n3;
9489 int t;
9490
9491 checkkwd = 1;
9492 n1 = pipeline();
9493 for (;;) {
9494 if ((t = readtoken()) == TAND) {
9495 t = NAND;
9496 } else if (t == TOR) {
9497 t = NOR;
9498 } else {
9499 tokpushback++;
9500 return n1;
9501 }
9502 checkkwd = 2;
9503 n2 = pipeline();
9504 n3 = (union node *)stalloc(sizeof (struct nbinary));
9505 n3->type = t;
9506 n3->nbinary.ch1 = n1;
9507 n3->nbinary.ch2 = n2;
9508 n1 = n3;
9509 }
9510}
9511
9512
9513
9514static union node *
9515pipeline() {
9516 union node *n1, *n2, *pipenode;
9517 struct nodelist *lp, *prev;
9518 int negate;
9519
9520 negate = 0;
9521 TRACE(("pipeline: entered\n"));
9522 if (readtoken() == TNOT) {
9523 negate = !negate;
9524 checkkwd = 1;
9525 } else
9526 tokpushback++;
9527 n1 = command();
9528 if (readtoken() == TPIPE) {
9529 pipenode = (union node *)stalloc(sizeof (struct npipe));
9530 pipenode->type = NPIPE;
9531 pipenode->npipe.backgnd = 0;
9532 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9533 pipenode->npipe.cmdlist = lp;
9534 lp->n = n1;
9535 do {
9536 prev = lp;
9537 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9538 checkkwd = 2;
9539 lp->n = command();
9540 prev->next = lp;
9541 } while (readtoken() == TPIPE);
9542 lp->next = NULL;
9543 n1 = pipenode;
9544 }
9545 tokpushback++;
9546 if (negate) {
9547 n2 = (union node *)stalloc(sizeof (struct nnot));
9548 n2->type = NNOT;
9549 n2->nnot.com = n1;
9550 return n2;
9551 } else
9552 return n1;
9553}
9554
9555
9556
9557static union node *
Eric Andersena3483db2001-10-24 08:01:06 +00009558command(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009559 union node *n1, *n2;
9560 union node *ap, **app;
9561 union node *cp, **cpp;
9562 union node *redir, **rpp;
9563 int t;
9564
9565 redir = NULL;
9566 n1 = NULL;
9567 rpp = &redir;
9568
Eric Andersen88cec252001-09-06 17:35:20 +00009569 /* Check for redirection which may precede command */
9570 while (readtoken() == TREDIR) {
9571 *rpp = n2 = redirnode;
9572 rpp = &n2->nfile.next;
9573 parsefname();
9574 }
9575 tokpushback++;
9576
Eric Andersencb57d552001-06-28 07:25:16 +00009577 switch (readtoken()) {
9578 case TIF:
9579 n1 = (union node *)stalloc(sizeof (struct nif));
9580 n1->type = NIF;
9581 n1->nif.test = list(0);
9582 if (readtoken() != TTHEN)
9583 synexpect(TTHEN);
9584 n1->nif.ifpart = list(0);
9585 n2 = n1;
9586 while (readtoken() == TELIF) {
9587 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9588 n2 = n2->nif.elsepart;
9589 n2->type = NIF;
9590 n2->nif.test = list(0);
9591 if (readtoken() != TTHEN)
9592 synexpect(TTHEN);
9593 n2->nif.ifpart = list(0);
9594 }
9595 if (lasttoken == TELSE)
9596 n2->nif.elsepart = list(0);
9597 else {
9598 n2->nif.elsepart = NULL;
9599 tokpushback++;
9600 }
9601 if (readtoken() != TFI)
9602 synexpect(TFI);
9603 checkkwd = 1;
9604 break;
9605 case TWHILE:
9606 case TUNTIL: {
9607 int got;
9608 n1 = (union node *)stalloc(sizeof (struct nbinary));
9609 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9610 n1->nbinary.ch1 = list(0);
9611 if ((got=readtoken()) != TDO) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009612TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009613 synexpect(TDO);
9614 }
9615 n1->nbinary.ch2 = list(0);
9616 if (readtoken() != TDONE)
9617 synexpect(TDONE);
9618 checkkwd = 1;
9619 break;
9620 }
9621 case TFOR:
9622 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9623 synerror("Bad for loop variable");
9624 n1 = (union node *)stalloc(sizeof (struct nfor));
9625 n1->type = NFOR;
9626 n1->nfor.var = wordtext;
9627 checkkwd = 1;
9628 if (readtoken() == TIN) {
9629 app = &ap;
9630 while (readtoken() == TWORD) {
9631 n2 = (union node *)stalloc(sizeof (struct narg));
9632 n2->type = NARG;
9633 n2->narg.text = wordtext;
9634 n2->narg.backquote = backquotelist;
9635 *app = n2;
9636 app = &n2->narg.next;
9637 }
9638 *app = NULL;
9639 n1->nfor.args = ap;
9640 if (lasttoken != TNL && lasttoken != TSEMI)
9641 synexpect(-1);
9642 } else {
9643 static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
9644 '@', '=', '\0'};
9645 n2 = (union node *)stalloc(sizeof (struct narg));
9646 n2->type = NARG;
9647 n2->narg.text = argvars;
9648 n2->narg.backquote = NULL;
9649 n2->narg.next = NULL;
9650 n1->nfor.args = n2;
9651 /*
9652 * Newline or semicolon here is optional (but note
9653 * that the original Bourne shell only allowed NL).
9654 */
9655 if (lasttoken != TNL && lasttoken != TSEMI)
9656 tokpushback++;
9657 }
9658 checkkwd = 2;
9659 if (readtoken() != TDO)
9660 synexpect(TDO);
9661 n1->nfor.body = list(0);
9662 if (readtoken() != TDONE)
9663 synexpect(TDONE);
9664 checkkwd = 1;
9665 break;
9666 case TCASE:
9667 n1 = (union node *)stalloc(sizeof (struct ncase));
9668 n1->type = NCASE;
9669 if (readtoken() != TWORD)
9670 synexpect(TWORD);
9671 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9672 n2->type = NARG;
9673 n2->narg.text = wordtext;
9674 n2->narg.backquote = backquotelist;
9675 n2->narg.next = NULL;
9676 do {
9677 checkkwd = 1;
9678 } while (readtoken() == TNL);
9679 if (lasttoken != TIN)
9680 synerror("expecting \"in\"");
9681 cpp = &n1->ncase.cases;
9682 checkkwd = 2, readtoken();
9683 do {
9684 if (lasttoken == TLP)
9685 readtoken();
9686 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9687 cp->type = NCLIST;
9688 app = &cp->nclist.pattern;
9689 for (;;) {
9690 *app = ap = (union node *)stalloc(sizeof (struct narg));
9691 ap->type = NARG;
9692 ap->narg.text = wordtext;
9693 ap->narg.backquote = backquotelist;
9694 if (checkkwd = 2, readtoken() != TPIPE)
9695 break;
9696 app = &ap->narg.next;
9697 readtoken();
9698 }
9699 ap->narg.next = NULL;
9700 if (lasttoken != TRP)
9701 synexpect(TRP);
9702 cp->nclist.body = list(0);
9703
9704 checkkwd = 2;
9705 if ((t = readtoken()) != TESAC) {
9706 if (t != TENDCASE)
9707 synexpect(TENDCASE);
9708 else
9709 checkkwd = 2, readtoken();
9710 }
9711 cpp = &cp->nclist.next;
9712 } while(lasttoken != TESAC);
9713 *cpp = NULL;
9714 checkkwd = 1;
9715 break;
9716 case TLP:
9717 n1 = (union node *)stalloc(sizeof (struct nredir));
9718 n1->type = NSUBSHELL;
9719 n1->nredir.n = list(0);
9720 n1->nredir.redirect = NULL;
9721 if (readtoken() != TRP)
9722 synexpect(TRP);
9723 checkkwd = 1;
9724 break;
9725 case TBEGIN:
9726 n1 = list(0);
9727 if (readtoken() != TEND)
9728 synexpect(TEND);
9729 checkkwd = 1;
9730 break;
9731 /* Handle an empty command like other simple commands. */
9732 case TSEMI:
9733 case TAND:
9734 case TOR:
9735 case TNL:
9736 case TEOF:
9737 case TRP:
9738 case TBACKGND:
9739 /*
9740 * An empty command before a ; doesn't make much sense, and
9741 * should certainly be disallowed in the case of `if ;'.
9742 */
9743 if (!redir)
9744 synexpect(-1);
9745 case TWORD:
Eric Andersencb57d552001-06-28 07:25:16 +00009746 tokpushback++;
Eric Andersena3483db2001-10-24 08:01:06 +00009747 n1 = simplecmd(rpp, redir);
Eric Andersencb57d552001-06-28 07:25:16 +00009748 return n1;
9749 default:
9750 synexpect(-1);
9751 /* NOTREACHED */
9752 }
9753
9754 /* Now check for redirection which may follow command */
9755 while (readtoken() == TREDIR) {
9756 *rpp = n2 = redirnode;
9757 rpp = &n2->nfile.next;
9758 parsefname();
9759 }
9760 tokpushback++;
9761 *rpp = NULL;
9762 if (redir) {
9763 if (n1->type != NSUBSHELL) {
9764 n2 = (union node *)stalloc(sizeof (struct nredir));
9765 n2->type = NREDIR;
9766 n2->nredir.n = n1;
9767 n1 = n2;
9768 }
9769 n1->nredir.redirect = redir;
9770 }
9771
9772 return n1;
9773}
9774
9775
9776static union node *
Eric Andersena3483db2001-10-24 08:01:06 +00009777simplecmd(union node **rpp, union node *redir) {
Eric Andersencb57d552001-06-28 07:25:16 +00009778 union node *args, **app;
9779 union node *n = NULL;
9780 union node *vars, **vpp;
Eric Andersena3483db2001-10-24 08:01:06 +00009781 union node **orig_rpp;
Eric Andersencb57d552001-06-28 07:25:16 +00009782
9783 args = NULL;
9784 app = &args;
9785 vars = NULL;
9786 vpp = &vars;
Eric Andersena3483db2001-10-24 08:01:06 +00009787
9788 /* If we don't have any redirections already, then we must reset
9789 rpp to be the address of the local redir variable. */
9790 if (redir == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00009791 rpp = &redir;
Eric Andersena3483db2001-10-24 08:01:06 +00009792 /* We save the incoming value, because we need this for shell
9793 functions. There can not be a redirect or an argument between
9794 the function name and the open parenthesis. */
9795 orig_rpp = rpp;
Eric Andersencb57d552001-06-28 07:25:16 +00009796
9797 checkalias = 2;
9798 for (;;) {
9799 switch (readtoken()) {
9800 case TWORD:
9801 case TASSIGN:
9802 n = (union node *)stalloc(sizeof (struct narg));
9803 n->type = NARG;
9804 n->narg.text = wordtext;
9805 n->narg.backquote = backquotelist;
9806 if (lasttoken == TWORD) {
9807 *app = n;
9808 app = &n->narg.next;
9809 } else {
9810 *vpp = n;
9811 vpp = &n->narg.next;
9812 }
9813 break;
9814 case TREDIR:
9815 *rpp = n = redirnode;
9816 rpp = &n->nfile.next;
Eric Andersen2870d962001-07-02 17:27:21 +00009817 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +00009818 break;
9819 case TLP:
9820 if (
9821 args && app == &args->narg.next &&
Eric Andersena3483db2001-10-24 08:01:06 +00009822 !vars && rpp == orig_rpp
Eric Andersencb57d552001-06-28 07:25:16 +00009823 ) {
9824 /* We have a function */
9825 if (readtoken() != TRP)
9826 synexpect(TRP);
Eric Andersencb57d552001-06-28 07:25:16 +00009827 n->type = NDEFUN;
9828 checkkwd = 2;
9829 n->narg.next = command();
9830 return n;
9831 }
9832 /* fall through */
9833 default:
9834 tokpushback++;
9835 goto out;
9836 }
9837 }
9838out:
9839 *app = NULL;
9840 *vpp = NULL;
9841 *rpp = NULL;
9842 n = (union node *)stalloc(sizeof (struct ncmd));
9843 n->type = NCMD;
9844 n->ncmd.backgnd = 0;
9845 n->ncmd.args = args;
9846 n->ncmd.assign = vars;
9847 n->ncmd.redirect = redir;
9848 return n;
9849}
9850
9851static union node *
Eric Andersen2870d962001-07-02 17:27:21 +00009852makename(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009853 union node *n;
9854
9855 n = (union node *)stalloc(sizeof (struct narg));
9856 n->type = NARG;
9857 n->narg.next = NULL;
9858 n->narg.text = wordtext;
9859 n->narg.backquote = backquotelist;
9860 return n;
9861}
9862
9863static void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +00009864{
Eric Andersencb57d552001-06-28 07:25:16 +00009865 TRACE(("Fix redir %s %d\n", text, err));
9866 if (!err)
9867 n->ndup.vname = NULL;
9868
9869 if (is_digit(text[0]) && text[1] == '\0')
9870 n->ndup.dupfd = digit_val(text[0]);
9871 else if (text[0] == '-' && text[1] == '\0')
9872 n->ndup.dupfd = -1;
9873 else {
9874
9875 if (err)
9876 synerror("Bad fd number");
9877 else
9878 n->ndup.vname = makename();
9879 }
9880}
9881
9882
9883static void
Eric Andersen2870d962001-07-02 17:27:21 +00009884parsefname(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009885 union node *n = redirnode;
9886
9887 if (readtoken() != TWORD)
9888 synexpect(-1);
9889 if (n->type == NHERE) {
9890 struct heredoc *here = heredoc;
9891 struct heredoc *p;
9892 int i;
9893
9894 if (quoteflag == 0)
9895 n->type = NXHERE;
9896 TRACE(("Here document %d\n", n->type));
9897 if (here->striptabs) {
9898 while (*wordtext == '\t')
9899 wordtext++;
9900 }
9901 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9902 synerror("Illegal eof marker for << redirection");
9903 rmescapes(wordtext);
9904 here->eofmark = wordtext;
9905 here->next = NULL;
9906 if (heredoclist == NULL)
9907 heredoclist = here;
9908 else {
9909 for (p = heredoclist ; p->next ; p = p->next);
9910 p->next = here;
9911 }
9912 } else if (n->type == NTOFD || n->type == NFROMFD) {
9913 fixredir(n, wordtext, 0);
9914 } else {
9915 n->nfile.fname = makename();
9916 }
9917}
9918
9919
9920/*
9921 * Input any here documents.
9922 */
9923
9924static void
9925parseheredoc() {
9926 struct heredoc *here;
9927 union node *n;
9928
9929 while (heredoclist) {
9930 here = heredoclist;
9931 heredoclist = here->next;
9932 if (needprompt) {
9933 setprompt(2);
9934 needprompt = 0;
9935 }
9936 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9937 here->eofmark, here->striptabs);
9938 n = (union node *)stalloc(sizeof (struct narg));
9939 n->narg.type = NARG;
9940 n->narg.next = NULL;
9941 n->narg.text = wordtext;
9942 n->narg.backquote = backquotelist;
9943 here->here->nhere.doc = n;
9944 }
9945}
9946
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009947static char
Eric Andersencb57d552001-06-28 07:25:16 +00009948peektoken() {
9949 int t;
9950
9951 t = readtoken();
9952 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009953 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +00009954}
9955
9956static int
9957readtoken() {
9958 int t;
Eric Andersen7467c8d2001-07-12 20:26:32 +00009959
Eric Andersend35c5df2002-01-09 15:37:36 +00009960#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00009961 int savecheckalias = checkalias;
Eric Andersen7467c8d2001-07-12 20:26:32 +00009962 int savecheckkwd = checkkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009963 struct alias *ap;
Eric Andersen2870d962001-07-02 17:27:21 +00009964#endif
9965
Eric Andersencb57d552001-06-28 07:25:16 +00009966#ifdef DEBUG
9967 int alreadyseen = tokpushback;
9968#endif
9969
Eric Andersend35c5df2002-01-09 15:37:36 +00009970#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00009971top:
Eric Andersen2870d962001-07-02 17:27:21 +00009972#endif
9973
Eric Andersencb57d552001-06-28 07:25:16 +00009974 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +00009975
Eric Andersend35c5df2002-01-09 15:37:36 +00009976#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00009977 checkalias = savecheckalias;
Eric Andersen2870d962001-07-02 17:27:21 +00009978#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009979
9980 if (checkkwd) {
9981 /*
9982 * eat newlines
9983 */
9984 if (checkkwd == 2) {
9985 checkkwd = 0;
9986 while (t == TNL) {
9987 parseheredoc();
9988 t = xxreadtoken();
9989 }
9990 }
9991 checkkwd = 0;
9992 /*
9993 * check for keywords
9994 */
9995 if (t == TWORD && !quoteflag)
9996 {
9997 const char *const *pp;
9998
9999 if ((pp = findkwd(wordtext))) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010000 lasttoken = t = pp - tokname_array;
10001 TRACE(("keyword %s recognized\n", tokname(t)));
Eric Andersencb57d552001-06-28 07:25:16 +000010002 goto out;
10003 }
10004 }
10005 }
10006
Eric Andersen7467c8d2001-07-12 20:26:32 +000010007
Eric Andersencb57d552001-06-28 07:25:16 +000010008 if (t != TWORD) {
10009 if (t != TREDIR) {
10010 checkalias = 0;
10011 }
10012 } else if (checkalias == 2 && isassignment(wordtext)) {
10013 lasttoken = t = TASSIGN;
Eric Andersend35c5df2002-01-09 15:37:36 +000010014#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010015 } else if (checkalias) {
Eric Andersenec074692001-10-31 11:05:49 +000010016 if (!quoteflag && (ap = *__lookupalias(wordtext)) != NULL && !(ap->flag & ALIASINUSE)) {
Eric Andersencb57d552001-06-28 07:25:16 +000010017 if (*ap->val) {
10018 pushstring(ap->val, strlen(ap->val), ap);
10019 }
10020 checkkwd = savecheckkwd;
10021 goto top;
10022 }
10023 checkalias = 0;
Eric Andersen2870d962001-07-02 17:27:21 +000010024#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +000010025 }
Eric Andersencb57d552001-06-28 07:25:16 +000010026out:
10027#ifdef DEBUG
10028 if (!alreadyseen)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010029 TRACE(("token %s %s\n", tokname(t), t == TWORD || t == TASSIGN ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +000010030 else
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010031 TRACE(("reread token %s %s\n", tokname(t), t == TWORD || t == TASSIGN ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +000010032#endif
10033 return (t);
10034}
10035
10036
10037/*
10038 * Read the next input token.
10039 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +000010040 * backquotes. We set quoteflag to true if any part of the word was
10041 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +000010042 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +000010043 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +000010044 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +000010045 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +000010046 *
10047 * [Change comment: here documents and internal procedures]
10048 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10049 * word parsing code into a separate routine. In this case, readtoken
10050 * doesn't need to have any internal procedures, but parseword does.
10051 * We could also make parseoperator in essence the main routine, and
10052 * have parseword (readtoken1?) handle both words and redirection.]
10053 */
10054
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +000010055#define NEW_xxreadtoken
10056#ifdef NEW_xxreadtoken
10057
10058static const char xxreadtoken_chars[] = "\n()&|;"; /* singles must be first! */
10059static const char xxreadtoken_tokens[] = {
10060 TNL, TLP, TRP, /* only single occurrence allowed */
10061 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10062 TEOF, /* corresponds to trailing nul */
10063 TAND, TOR, TENDCASE, /* if double occurrence */
10064};
10065
10066#define xxreadtoken_doubles \
10067 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10068#define xxreadtoken_singles \
10069 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10070
10071static int
10072xxreadtoken() {
10073 int c;
10074
10075 if (tokpushback) {
10076 tokpushback = 0;
10077 return lasttoken;
10078 }
10079 if (needprompt) {
10080 setprompt(2);
10081 needprompt = 0;
10082 }
10083 startlinno = plinno;
10084 for (;;) { /* until token or start of word found */
10085 c = pgetc_macro();
10086
10087 if ((c!=' ') && (c!='\t')
Eric Andersend35c5df2002-01-09 15:37:36 +000010088#ifdef CONFIG_ASH_ALIAS
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +000010089 && (c!=PEOA)
10090#endif
10091 ) {
10092 if (c=='#') {
10093 while ((c = pgetc()) != '\n' && c != PEOF);
10094 pungetc();
10095 } else if (c=='\\') {
10096 if (pgetc() != '\n') {
10097 pungetc();
10098 goto READTOKEN1;
10099 }
10100 startlinno = ++plinno;
10101 setprompt(doprompt ? 2 : 0);
10102 } else {
10103 const char *p
10104 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10105
10106 if (c!=PEOF) {
10107 if (c=='\n') {
10108 plinno++;
10109 needprompt = doprompt;
10110 }
10111
10112 p = strchr(xxreadtoken_chars, c);
10113 if (p == NULL) {
10114 READTOKEN1:
10115 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10116 }
10117
10118 if (p-xxreadtoken_chars >= xxreadtoken_singles) {
10119 if (pgetc() == *p) { /* double occurrence? */
10120 p += xxreadtoken_doubles + 1;
10121 } else {
10122 pungetc();
10123 }
10124 }
10125 }
10126
10127 return lasttoken = xxreadtoken_tokens[p-xxreadtoken_chars];
10128 }
10129 }
10130 }
10131}
10132
10133
10134#else
Eric Andersen2870d962001-07-02 17:27:21 +000010135#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010136
10137static int
10138xxreadtoken() {
10139 int c;
10140
10141 if (tokpushback) {
10142 tokpushback = 0;
10143 return lasttoken;
10144 }
10145 if (needprompt) {
10146 setprompt(2);
10147 needprompt = 0;
10148 }
10149 startlinno = plinno;
Eric Andersen2870d962001-07-02 17:27:21 +000010150 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010151 c = pgetc_macro();
10152 switch (c) {
10153 case ' ': case '\t':
Eric Andersend35c5df2002-01-09 15:37:36 +000010154#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010155 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010156#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010157 continue;
10158 case '#':
10159 while ((c = pgetc()) != '\n' && c != PEOF);
10160 pungetc();
10161 continue;
10162 case '\\':
10163 if (pgetc() == '\n') {
10164 startlinno = ++plinno;
10165 if (doprompt)
10166 setprompt(2);
10167 else
10168 setprompt(0);
10169 continue;
10170 }
10171 pungetc();
10172 goto breakloop;
10173 case '\n':
10174 plinno++;
10175 needprompt = doprompt;
10176 RETURN(TNL);
10177 case PEOF:
10178 RETURN(TEOF);
10179 case '&':
10180 if (pgetc() == '&')
10181 RETURN(TAND);
10182 pungetc();
10183 RETURN(TBACKGND);
10184 case '|':
10185 if (pgetc() == '|')
10186 RETURN(TOR);
10187 pungetc();
10188 RETURN(TPIPE);
10189 case ';':
10190 if (pgetc() == ';')
10191 RETURN(TENDCASE);
10192 pungetc();
10193 RETURN(TSEMI);
10194 case '(':
10195 RETURN(TLP);
10196 case ')':
10197 RETURN(TRP);
10198 default:
10199 goto breakloop;
10200 }
10201 }
10202breakloop:
10203 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10204#undef RETURN
10205}
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +000010206#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010207
Eric Andersencb57d552001-06-28 07:25:16 +000010208/*
10209 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10210 * is not NULL, read a here document. In the latter case, eofmark is the
10211 * word which marks the end of the document and striptabs is true if
10212 * leading tabs should be stripped from the document. The argument firstc
10213 * is the first character of the input token or document.
10214 *
10215 * Because C does not have internal subroutines, I have simulated them
10216 * using goto's to implement the subroutine linkage. The following macros
10217 * will run code that appears at the end of readtoken1.
10218 */
10219
Eric Andersen2870d962001-07-02 17:27:21 +000010220#define CHECKEND() {goto checkend; checkend_return:;}
10221#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10222#define PARSESUB() {goto parsesub; parsesub_return:;}
10223#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10224#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10225#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010226
10227static int
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010228readtoken1(int firstc, int syntax, const char *eofmark, int striptabs)
10229{
Eric Andersencb57d552001-06-28 07:25:16 +000010230 int c = firstc;
10231 char *out;
10232 int len;
10233 char line[EOFMARKLEN + 1];
10234 struct nodelist *bqlist;
10235 int quotef;
10236 int dblquote;
Eric Andersen2870d962001-07-02 17:27:21 +000010237 int varnest; /* levels of variables expansion */
10238 int arinest; /* levels of arithmetic expansion */
10239 int parenlevel; /* levels of parens in arithmetic */
10240 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +000010241 int oldstyle;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010242 int prevsyntax; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010243#if __GNUC__
10244 /* Avoid longjmp clobbering */
10245 (void) &out;
10246 (void) &quotef;
10247 (void) &dblquote;
10248 (void) &varnest;
10249 (void) &arinest;
10250 (void) &parenlevel;
10251 (void) &dqvarnest;
10252 (void) &oldstyle;
10253 (void) &prevsyntax;
10254 (void) &syntax;
10255#endif
10256
10257 startlinno = plinno;
10258 dblquote = 0;
10259 if (syntax == DQSYNTAX)
10260 dblquote = 1;
10261 quotef = 0;
10262 bqlist = NULL;
10263 varnest = 0;
10264 arinest = 0;
10265 parenlevel = 0;
10266 dqvarnest = 0;
10267
10268 STARTSTACKSTR(out);
Eric Andersen2870d962001-07-02 17:27:21 +000010269 loop: { /* for each line, until end of word */
10270 CHECKEND(); /* set c to PEOF if at end of here document */
10271 for (;;) { /* until end of line or end of word */
10272 CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010273 switch(SIT(c,syntax)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010274 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010275 if (syntax == BASESYNTAX)
Eric Andersen2870d962001-07-02 17:27:21 +000010276 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010277 USTPUTC(c, out);
10278 plinno++;
10279 if (doprompt)
10280 setprompt(2);
10281 else
10282 setprompt(0);
10283 c = pgetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010284 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010285 case CWORD:
10286 USTPUTC(c, out);
10287 break;
10288 case CCTL:
10289 if ((eofmark == NULL || dblquote) &&
10290 dqvarnest == 0)
10291 USTPUTC(CTLESC, out);
10292 USTPUTC(c, out);
10293 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010294 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010295 c = pgetc2();
10296 if (c == PEOF) {
10297 USTPUTC('\\', out);
10298 pungetc();
10299 } else if (c == '\n') {
10300 if (doprompt)
10301 setprompt(2);
10302 else
10303 setprompt(0);
10304 } else {
10305 if (dblquote && c != '\\' && c != '`' && c != '$'
10306 && (c != '"' || eofmark != NULL))
10307 USTPUTC('\\', out);
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010308 if (SIT(c,SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010309 USTPUTC(CTLESC, out);
10310 else if (eofmark == NULL)
10311 USTPUTC(CTLQUOTEMARK, out);
10312 USTPUTC(c, out);
10313 quotef++;
10314 }
10315 break;
10316 case CSQUOTE:
10317 if (eofmark == NULL)
10318 USTPUTC(CTLQUOTEMARK, out);
10319 syntax = SQSYNTAX;
10320 break;
10321 case CDQUOTE:
10322 if (eofmark == NULL)
10323 USTPUTC(CTLQUOTEMARK, out);
10324 syntax = DQSYNTAX;
10325 dblquote = 1;
10326 break;
10327 case CENDQUOTE:
10328 if (eofmark != NULL && arinest == 0 &&
10329 varnest == 0) {
10330 USTPUTC(c, out);
10331 } else {
10332 if (arinest) {
10333 syntax = ARISYNTAX;
10334 dblquote = 0;
10335 } else if (eofmark == NULL &&
10336 dqvarnest == 0) {
10337 syntax = BASESYNTAX;
10338 dblquote = 0;
10339 }
10340 quotef++;
10341 }
10342 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010343 case CVAR: /* '$' */
10344 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010345 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010346 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010347 if (varnest > 0) {
10348 varnest--;
10349 if (dqvarnest > 0) {
10350 dqvarnest--;
10351 }
10352 USTPUTC(CTLENDVAR, out);
10353 } else {
10354 USTPUTC(c, out);
10355 }
10356 break;
Eric Andersend35c5df2002-01-09 15:37:36 +000010357#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +000010358 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010359 parenlevel++;
10360 USTPUTC(c, out);
10361 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010362 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010363 if (parenlevel > 0) {
10364 USTPUTC(c, out);
10365 --parenlevel;
10366 } else {
10367 if (pgetc() == ')') {
10368 if (--arinest == 0) {
10369 USTPUTC(CTLENDARI, out);
10370 syntax = prevsyntax;
10371 if (syntax == DQSYNTAX)
10372 dblquote = 1;
10373 else
10374 dblquote = 0;
10375 } else
10376 USTPUTC(')', out);
10377 } else {
10378 /*
10379 * unbalanced parens
10380 * (don't 2nd guess - no error)
10381 */
10382 pungetc();
10383 USTPUTC(')', out);
10384 }
10385 }
10386 break;
10387#endif
Eric Andersen2870d962001-07-02 17:27:21 +000010388 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010389 PARSEBACKQOLD();
10390 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010391 case CENDFILE:
10392 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010393 case CIGN:
10394 break;
10395 default:
10396 if (varnest == 0)
Eric Andersen2870d962001-07-02 17:27:21 +000010397 goto endword; /* exit outer loop */
Eric Andersend35c5df2002-01-09 15:37:36 +000010398#ifdef CONFIG_ASH_ALIAS
Eric Andersen3102ac42001-07-06 04:26:23 +000010399 if (c != PEOA)
10400#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010401 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010402
Eric Andersencb57d552001-06-28 07:25:16 +000010403 }
10404 c = pgetc_macro();
10405 }
10406 }
10407endword:
10408 if (syntax == ARISYNTAX)
10409 synerror("Missing '))'");
10410 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10411 synerror("Unterminated quoted string");
10412 if (varnest != 0) {
10413 startlinno = plinno;
10414 synerror("Missing '}'");
10415 }
10416 USTPUTC('\0', out);
10417 len = out - stackblock();
10418 out = stackblock();
10419 if (eofmark == NULL) {
10420 if ((c == '>' || c == '<')
10421 && quotef == 0
10422 && len <= 2
10423 && (*out == '\0' || is_digit(*out))) {
10424 PARSEREDIR();
10425 return lasttoken = TREDIR;
10426 } else {
10427 pungetc();
10428 }
10429 }
10430 quoteflag = quotef;
10431 backquotelist = bqlist;
10432 grabstackblock(len);
10433 wordtext = out;
10434 return lasttoken = TWORD;
10435/* end of readtoken routine */
10436
10437
10438
10439/*
10440 * Check to see whether we are at the end of the here document. When this
10441 * is called, c is set to the first character of the next input line. If
10442 * we are at the end of the here document, this routine sets the c to PEOF.
10443 */
10444
10445checkend: {
10446 if (eofmark) {
Eric Andersend35c5df2002-01-09 15:37:36 +000010447#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010448 if (c == PEOA) {
10449 c = pgetc2();
10450 }
Eric Andersen2870d962001-07-02 17:27:21 +000010451#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010452 if (striptabs) {
10453 while (c == '\t') {
10454 c = pgetc2();
10455 }
10456 }
10457 if (c == *eofmark) {
10458 if (pfgets(line, sizeof line) != NULL) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010459 const char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010460
10461 p = line;
10462 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10463 if (*p == '\n' && *q == '\0') {
10464 c = PEOF;
10465 plinno++;
10466 needprompt = doprompt;
10467 } else {
10468 pushstring(line, strlen(line), NULL);
10469 }
10470 }
10471 }
10472 }
10473 goto checkend_return;
10474}
10475
10476
10477/*
10478 * Parse a redirection operator. The variable "out" points to a string
10479 * specifying the fd to be redirected. The variable "c" contains the
10480 * first character of the redirection operator.
10481 */
10482
10483parseredir: {
10484 char fd = *out;
10485 union node *np;
10486
10487 np = (union node *)stalloc(sizeof (struct nfile));
10488 if (c == '>') {
10489 np->nfile.fd = 1;
10490 c = pgetc();
10491 if (c == '>')
10492 np->type = NAPPEND;
10493 else if (c == '&')
10494 np->type = NTOFD;
10495 else if (c == '|')
10496 np->type = NTOOV;
10497 else {
10498 np->type = NTO;
10499 pungetc();
10500 }
Eric Andersen2870d962001-07-02 17:27:21 +000010501 } else { /* c == '<' */
Eric Andersencb57d552001-06-28 07:25:16 +000010502 np->nfile.fd = 0;
10503 switch (c = pgetc()) {
10504 case '<':
10505 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10506 np = (union node *)stalloc(sizeof (struct nhere));
10507 np->nfile.fd = 0;
10508 }
10509 np->type = NHERE;
10510 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10511 heredoc->here = np;
10512 if ((c = pgetc()) == '-') {
10513 heredoc->striptabs = 1;
10514 } else {
10515 heredoc->striptabs = 0;
10516 pungetc();
10517 }
10518 break;
10519
10520 case '&':
10521 np->type = NFROMFD;
10522 break;
10523
10524 case '>':
10525 np->type = NFROMTO;
10526 break;
10527
10528 default:
10529 np->type = NFROM;
10530 pungetc();
10531 break;
10532 }
10533 }
10534 if (fd != '\0')
10535 np->nfile.fd = digit_val(fd);
10536 redirnode = np;
10537 goto parseredir_return;
10538}
10539
10540
10541/*
10542 * Parse a substitution. At this point, we have read the dollar sign
10543 * and nothing else.
10544 */
10545
10546parsesub: {
10547 int subtype;
10548 int typeloc;
10549 int flags;
10550 char *p;
10551 static const char types[] = "}-+?=";
10552
10553 c = pgetc();
10554 if (
10555 c <= PEOA ||
10556 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10557 ) {
10558 USTPUTC('$', out);
10559 pungetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010560 } else if (c == '(') { /* $(command) or $((arith)) */
Eric Andersencb57d552001-06-28 07:25:16 +000010561 if (pgetc() == '(') {
10562 PARSEARITH();
10563 } else {
10564 pungetc();
10565 PARSEBACKQNEW();
10566 }
10567 } else {
10568 USTPUTC(CTLVAR, out);
10569 typeloc = out - stackblock();
10570 USTPUTC(VSNORMAL, out);
10571 subtype = VSNORMAL;
10572 if (c == '{') {
10573 c = pgetc();
10574 if (c == '#') {
10575 if ((c = pgetc()) == '}')
10576 c = '#';
10577 else
10578 subtype = VSLENGTH;
10579 }
10580 else
10581 subtype = 0;
10582 }
10583 if (c > PEOA && is_name(c)) {
10584 do {
10585 STPUTC(c, out);
10586 c = pgetc();
10587 } while (c > PEOA && is_in_name(c));
10588 } else if (is_digit(c)) {
10589 do {
10590 USTPUTC(c, out);
10591 c = pgetc();
10592 } while (is_digit(c));
10593 }
10594 else if (is_special(c)) {
10595 USTPUTC(c, out);
10596 c = pgetc();
10597 }
10598 else
Eric Andersen2870d962001-07-02 17:27:21 +000010599badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010600
10601 STPUTC('=', out);
10602 flags = 0;
10603 if (subtype == 0) {
10604 switch (c) {
10605 case ':':
10606 flags = VSNUL;
10607 c = pgetc();
10608 /*FALLTHROUGH*/
10609 default:
10610 p = strchr(types, c);
10611 if (p == NULL)
10612 goto badsub;
10613 subtype = p - types + VSNORMAL;
10614 break;
10615 case '%':
10616 case '#':
10617 {
10618 int cc = c;
10619 subtype = c == '#' ? VSTRIMLEFT :
10620 VSTRIMRIGHT;
10621 c = pgetc();
10622 if (c == cc)
10623 subtype++;
10624 else
10625 pungetc();
10626 break;
10627 }
10628 }
10629 } else {
10630 pungetc();
10631 }
10632 if (dblquote || arinest)
10633 flags |= VSQUOTE;
10634 *(stackblock() + typeloc) = subtype | flags;
10635 if (subtype != VSNORMAL) {
10636 varnest++;
10637 if (dblquote) {
10638 dqvarnest++;
10639 }
10640 }
10641 }
10642 goto parsesub_return;
10643}
10644
10645
10646/*
10647 * Called to parse command substitutions. Newstyle is set if the command
10648 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10649 * list of commands (passed by reference), and savelen is the number of
10650 * characters on the top of the stack which must be preserved.
10651 */
10652
10653parsebackq: {
10654 struct nodelist **nlpp;
10655 int savepbq;
10656 union node *n;
10657 char *volatile str;
10658 struct jmploc jmploc;
10659 struct jmploc *volatile savehandler;
10660 int savelen;
10661 int saveprompt;
10662#ifdef __GNUC__
10663 (void) &saveprompt;
10664#endif
10665
10666 savepbq = parsebackquote;
10667 if (setjmp(jmploc.loc)) {
10668 if (str)
10669 ckfree(str);
10670 parsebackquote = 0;
10671 handler = savehandler;
10672 longjmp(handler->loc, 1);
10673 }
10674 INTOFF;
10675 str = NULL;
10676 savelen = out - stackblock();
10677 if (savelen > 0) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010678 str = xmalloc(savelen);
Eric Andersencb57d552001-06-28 07:25:16 +000010679 memcpy(str, stackblock(), savelen);
10680 }
10681 savehandler = handler;
10682 handler = &jmploc;
10683 INTON;
Eric Andersen2870d962001-07-02 17:27:21 +000010684 if (oldstyle) {
10685 /* We must read until the closing backquote, giving special
10686 treatment to some slashes, and then push the string and
10687 reread it as input, interpreting it normally. */
10688 char *pout;
10689 int pc;
10690 int psavelen;
10691 char *pstr;
Eric Andersencb57d552001-06-28 07:25:16 +000010692
10693
Eric Andersen2870d962001-07-02 17:27:21 +000010694 STARTSTACKSTR(pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010695 for (;;) {
10696 if (needprompt) {
10697 setprompt(2);
10698 needprompt = 0;
10699 }
10700 switch (pc = pgetc()) {
10701 case '`':
10702 goto done;
10703
10704 case '\\':
Eric Andersen2870d962001-07-02 17:27:21 +000010705 if ((pc = pgetc()) == '\n') {
Eric Andersencb57d552001-06-28 07:25:16 +000010706 plinno++;
10707 if (doprompt)
10708 setprompt(2);
10709 else
10710 setprompt(0);
10711 /*
10712 * If eating a newline, avoid putting
10713 * the newline into the new character
10714 * stream (via the STPUTC after the
10715 * switch).
10716 */
10717 continue;
10718 }
Eric Andersen2870d962001-07-02 17:27:21 +000010719 if (pc != '\\' && pc != '`' && pc != '$'
10720 && (!dblquote || pc != '"'))
10721 STPUTC('\\', pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010722 if (pc > PEOA) {
10723 break;
10724 }
10725 /* fall through */
10726
10727 case PEOF:
Eric Andersend35c5df2002-01-09 15:37:36 +000010728#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010729 case PEOA:
Eric Andersen2870d962001-07-02 17:27:21 +000010730#endif
10731 startlinno = plinno;
Eric Andersencb57d552001-06-28 07:25:16 +000010732 synerror("EOF in backquote substitution");
10733
10734 case '\n':
10735 plinno++;
10736 needprompt = doprompt;
10737 break;
10738
10739 default:
10740 break;
10741 }
10742 STPUTC(pc, pout);
Eric Andersen2870d962001-07-02 17:27:21 +000010743 }
Eric Andersencb57d552001-06-28 07:25:16 +000010744done:
Eric Andersen2870d962001-07-02 17:27:21 +000010745 STPUTC('\0', pout);
10746 psavelen = pout - stackblock();
10747 if (psavelen > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010748 pstr = grabstackstr(pout);
10749 setinputstring(pstr);
Eric Andersen2870d962001-07-02 17:27:21 +000010750 }
10751 }
Eric Andersencb57d552001-06-28 07:25:16 +000010752 nlpp = &bqlist;
10753 while (*nlpp)
10754 nlpp = &(*nlpp)->next;
10755 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10756 (*nlpp)->next = NULL;
10757 parsebackquote = oldstyle;
10758
10759 if (oldstyle) {
10760 saveprompt = doprompt;
10761 doprompt = 0;
10762 }
10763
10764 n = list(0);
10765
10766 if (oldstyle)
10767 doprompt = saveprompt;
10768 else {
10769 if (readtoken() != TRP)
10770 synexpect(TRP);
10771 }
10772
10773 (*nlpp)->n = n;
Eric Andersen2870d962001-07-02 17:27:21 +000010774 if (oldstyle) {
Eric Andersencb57d552001-06-28 07:25:16 +000010775 /*
10776 * Start reading from old file again, ignoring any pushed back
10777 * tokens left from the backquote parsing
10778 */
Eric Andersen2870d962001-07-02 17:27:21 +000010779 popfile();
Eric Andersencb57d552001-06-28 07:25:16 +000010780 tokpushback = 0;
10781 }
10782 while (stackblocksize() <= savelen)
10783 growstackblock();
10784 STARTSTACKSTR(out);
10785 if (str) {
10786 memcpy(out, str, savelen);
10787 STADJUST(savelen, out);
10788 INTOFF;
10789 ckfree(str);
10790 str = NULL;
10791 INTON;
10792 }
10793 parsebackquote = savepbq;
10794 handler = savehandler;
10795 if (arinest || dblquote)
10796 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10797 else
10798 USTPUTC(CTLBACKQ, out);
10799 if (oldstyle)
10800 goto parsebackq_oldreturn;
10801 else
10802 goto parsebackq_newreturn;
10803}
10804
10805/*
10806 * Parse an arithmetic expansion (indicate start of one and set state)
10807 */
10808parsearith: {
10809
10810 if (++arinest == 1) {
10811 prevsyntax = syntax;
10812 syntax = ARISYNTAX;
10813 USTPUTC(CTLARI, out);
10814 if (dblquote)
10815 USTPUTC('"',out);
10816 else
10817 USTPUTC(' ',out);
10818 } else {
10819 /*
10820 * we collapse embedded arithmetic expansion to
10821 * parenthesis, which should be equivalent
10822 */
10823 USTPUTC('(', out);
10824 }
10825 goto parsearith_return;
10826}
10827
10828} /* end of readtoken */
10829
10830
Eric Andersencb57d552001-06-28 07:25:16 +000010831/*
10832 * Returns true if the text contains nothing to expand (no dollar signs
10833 * or backquotes).
10834 */
10835
10836static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010837noexpand(char *text)
10838{
Eric Andersencb57d552001-06-28 07:25:16 +000010839 char *p;
10840 char c;
10841
10842 p = text;
10843 while ((c = *p++) != '\0') {
10844 if (c == CTLQUOTEMARK)
10845 continue;
10846 if (c == CTLESC)
10847 p++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010848 else if (SIT(c,BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010849 return 0;
10850 }
10851 return 1;
10852}
10853
10854
10855/*
10856 * Return true if the argument is a legal variable name (a letter or
10857 * underscore followed by zero or more letters, underscores, and digits).
10858 */
10859
10860static int
Eric Andersen2870d962001-07-02 17:27:21 +000010861goodname(const char *name)
10862{
10863 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000010864
10865 p = name;
10866 if (! is_name(*p))
10867 return 0;
10868 while (*++p) {
10869 if (! is_in_name(*p))
10870 return 0;
10871 }
10872 return 1;
10873}
10874
10875
10876/*
10877 * Called when an unexpected token is read during the parse. The argument
10878 * is the token that is expected, or -1 if more than one type of token can
10879 * occur at this point.
10880 */
10881
10882static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010883synexpect(int token)
Eric Andersencb57d552001-06-28 07:25:16 +000010884{
10885 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010886 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000010887
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010888 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10889 if (token >= 0)
10890 sprintf(msg+l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000010891 synerror(msg);
10892 /* NOTREACHED */
10893}
10894
10895
10896static void
Eric Andersen2870d962001-07-02 17:27:21 +000010897synerror(const char *msg)
10898{
Eric Andersencb57d552001-06-28 07:25:16 +000010899 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +000010900 out2fmt("%s: %d: ", commandname, startlinno);
10901 out2fmt("Syntax error: %s\n", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000010902 error((char *)NULL);
10903 /* NOTREACHED */
10904}
10905
Eric Andersencb57d552001-06-28 07:25:16 +000010906
10907/*
10908 * called by editline -- any expansions to the prompt
10909 * should be added here.
10910 */
Eric Andersen2870d962001-07-02 17:27:21 +000010911static void
Eric Andersen62483552001-07-10 06:09:16 +000010912setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000010913{
Eric Andersen62483552001-07-10 06:09:16 +000010914 char *prompt;
10915 switch (whichprompt) {
10916 case 1:
10917 prompt = ps1val();
10918 break;
10919 case 2:
10920 prompt = ps2val();
10921 break;
10922 default: /* 0 */
10923 prompt = "";
10924 }
10925 putprompt(prompt);
Eric Andersencb57d552001-06-28 07:25:16 +000010926}
10927
Eric Andersencb57d552001-06-28 07:25:16 +000010928
Eric Andersencb57d552001-06-28 07:25:16 +000010929/*
10930 * Code for dealing with input/output redirection.
10931 */
10932
Eric Andersen2870d962001-07-02 17:27:21 +000010933#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000010934#ifndef PIPE_BUF
Eric Andersen2870d962001-07-02 17:27:21 +000010935# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000010936#else
10937# define PIPESIZE PIPE_BUF
10938#endif
10939
10940
Eric Andersen62483552001-07-10 06:09:16 +000010941/*
10942 * Open a file in noclobber mode.
10943 * The code was copied from bash.
10944 */
10945static inline int
10946noclobberopen(const char *fname)
10947{
10948 int r, fd;
10949 struct stat finfo, finfo2;
10950
10951 /*
10952 * If the file exists and is a regular file, return an error
10953 * immediately.
10954 */
10955 r = stat(fname, &finfo);
10956 if (r == 0 && S_ISREG(finfo.st_mode)) {
10957 errno = EEXIST;
10958 return -1;
10959 }
10960
10961 /*
10962 * If the file was not present (r != 0), make sure we open it
10963 * exclusively so that if it is created before we open it, our open
10964 * will fail. Make sure that we do not truncate an existing file.
10965 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10966 * file was not a regular file, we leave O_EXCL off.
10967 */
10968 if (r != 0)
10969 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10970 fd = open(fname, O_WRONLY|O_CREAT, 0666);
10971
10972 /* If the open failed, return the file descriptor right away. */
10973 if (fd < 0)
10974 return fd;
10975
10976 /*
10977 * OK, the open succeeded, but the file may have been changed from a
10978 * non-regular file to a regular file between the stat and the open.
10979 * We are assuming that the O_EXCL open handles the case where FILENAME
10980 * did not exist and is symlinked to an existing file between the stat
10981 * and open.
10982 */
10983
10984 /*
10985 * If we can open it and fstat the file descriptor, and neither check
10986 * revealed that it was a regular file, and the file has not been
10987 * replaced, return the file descriptor.
10988 */
10989 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10990 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
10991 return fd;
10992
10993 /* The file has been replaced. badness. */
10994 close(fd);
10995 errno = EEXIST;
10996 return -1;
10997}
Eric Andersencb57d552001-06-28 07:25:16 +000010998
10999/*
Eric Andersen62483552001-07-10 06:09:16 +000011000 * Handle here documents. Normally we fork off a process to write the
11001 * data to a pipe. If the document is short, we can stuff the data in
11002 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000011003 */
11004
Eric Andersen62483552001-07-10 06:09:16 +000011005static inline int
11006openhere(const union node *redir)
11007{
11008 int pip[2];
11009 int len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011010
Eric Andersen62483552001-07-10 06:09:16 +000011011 if (pipe(pip) < 0)
11012 error("Pipe call failed");
11013 if (redir->type == NHERE) {
11014 len = strlen(redir->nhere.doc->narg.text);
11015 if (len <= PIPESIZE) {
11016 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11017 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011018 }
Eric Andersencb57d552001-06-28 07:25:16 +000011019 }
Eric Andersen62483552001-07-10 06:09:16 +000011020 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
11021 close(pip[0]);
11022 signal(SIGINT, SIG_IGN);
11023 signal(SIGQUIT, SIG_IGN);
11024 signal(SIGHUP, SIG_IGN);
11025#ifdef SIGTSTP
11026 signal(SIGTSTP, SIG_IGN);
11027#endif
11028 signal(SIGPIPE, SIG_DFL);
11029 if (redir->type == NHERE)
11030 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11031 else
11032 expandhere(redir->nhere.doc, pip[1]);
11033 _exit(0);
11034 }
11035out:
11036 close(pip[1]);
11037 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000011038}
11039
11040
Eric Andersen62483552001-07-10 06:09:16 +000011041static inline int
11042openredirect(const union node *redir)
11043{
Eric Andersencb57d552001-06-28 07:25:16 +000011044 char *fname;
11045 int f;
11046
11047 switch (redir->nfile.type) {
11048 case NFROM:
11049 fname = redir->nfile.expfname;
11050 if ((f = open(fname, O_RDONLY)) < 0)
11051 goto eopen;
11052 break;
11053 case NFROMTO:
11054 fname = redir->nfile.expfname;
11055 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
11056 goto ecreate;
11057 break;
11058 case NTO:
11059 /* Take care of noclobber mode. */
11060 if (Cflag) {
11061 fname = redir->nfile.expfname;
11062 if ((f = noclobberopen(fname)) < 0)
11063 goto ecreate;
11064 break;
11065 }
11066 case NTOOV:
11067 fname = redir->nfile.expfname;
11068#ifdef O_CREAT
11069 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
11070 goto ecreate;
11071#else
11072 if ((f = creat(fname, 0666)) < 0)
11073 goto ecreate;
11074#endif
11075 break;
11076 case NAPPEND:
11077 fname = redir->nfile.expfname;
11078#ifdef O_APPEND
11079 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
11080 goto ecreate;
11081#else
11082 if ((f = open(fname, O_WRONLY)) < 0
11083 && (f = creat(fname, 0666)) < 0)
11084 goto ecreate;
11085 lseek(f, (off_t)0, 2);
11086#endif
11087 break;
11088 default:
11089#ifdef DEBUG
11090 abort();
11091#endif
11092 /* Fall through to eliminate warning. */
11093 case NTOFD:
11094 case NFROMFD:
11095 f = -1;
11096 break;
11097 case NHERE:
11098 case NXHERE:
11099 f = openhere(redir);
11100 break;
11101 }
11102
11103 return f;
11104ecreate:
11105 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11106eopen:
11107 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11108}
11109
11110
Eric Andersen62483552001-07-10 06:09:16 +000011111/*
11112 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11113 * old file descriptors are stashed away so that the redirection can be
11114 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11115 * standard output, and the standard error if it becomes a duplicate of
11116 * stdout.
11117 */
11118
Eric Andersencb57d552001-06-28 07:25:16 +000011119static void
Eric Andersen62483552001-07-10 06:09:16 +000011120redirect(union node *redir, int flags)
11121{
11122 union node *n;
11123 struct redirtab *sv = NULL;
11124 int i;
11125 int fd;
11126 int newfd;
11127 int try;
11128 int fd1dup = flags & REDIR_BACKQ;; /* stdout `cmd` redir to pipe */
11129
11130 if (flags & REDIR_PUSH) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011131 sv = xmalloc(sizeof (struct redirtab));
Eric Andersen62483552001-07-10 06:09:16 +000011132 for (i = 0 ; i < 10 ; i++)
11133 sv->renamed[i] = EMPTY;
11134 sv->next = redirlist;
11135 redirlist = sv;
11136 }
11137 for (n = redir ; n ; n = n->nfile.next) {
11138 fd = n->nfile.fd;
11139 try = 0;
11140 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11141 n->ndup.dupfd == fd)
11142 continue; /* redirect from/to same file descriptor */
11143
11144 INTOFF;
11145 newfd = openredirect(n);
11146 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
11147 if (newfd == fd) {
11148 try++;
11149 } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
11150 switch (errno) {
11151 case EBADF:
11152 if (!try) {
11153 dupredirect(n, newfd, fd1dup);
11154 try++;
11155 break;
11156 }
11157 /* FALLTHROUGH*/
11158 default:
11159 if (newfd >= 0) {
11160 close(newfd);
11161 }
11162 INTON;
11163 error("%d: %m", fd);
11164 /* NOTREACHED */
11165 }
11166 }
11167 if (!try) {
11168 close(fd);
11169 if (flags & REDIR_PUSH) {
11170 sv->renamed[fd] = i;
11171 }
11172 }
11173 } else if (fd != newfd) {
11174 close(fd);
11175 }
11176 if (fd == 0)
11177 fd0_redirected++;
11178 if (!try)
11179 dupredirect(n, newfd, fd1dup);
11180 INTON;
11181 }
11182}
11183
11184
11185static void
11186dupredirect(const union node *redir, int f, int fd1dup)
Eric Andersen2870d962001-07-02 17:27:21 +000011187{
Eric Andersencb57d552001-06-28 07:25:16 +000011188 int fd = redir->nfile.fd;
11189
Eric Andersen62483552001-07-10 06:09:16 +000011190 if(fd==1)
11191 fd1dup = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011192 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Eric Andersen2870d962001-07-02 17:27:21 +000011193 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
Eric Andersen62483552001-07-10 06:09:16 +000011194 if (redir->ndup.dupfd!=1 || fd1dup!=1)
Eric Andersencb57d552001-06-28 07:25:16 +000011195 dup_as_newfd(redir->ndup.dupfd, fd);
11196 }
11197 return;
11198 }
11199
11200 if (f != fd) {
11201 dup_as_newfd(f, fd);
11202 close(f);
11203 }
11204 return;
11205}
11206
11207
Eric Andersencb57d552001-06-28 07:25:16 +000011208
Eric Andersencb57d552001-06-28 07:25:16 +000011209/*
11210 * Undo the effects of the last redirection.
11211 */
11212
11213static void
Eric Andersen2870d962001-07-02 17:27:21 +000011214popredir(void)
11215{
Eric Andersencb57d552001-06-28 07:25:16 +000011216 struct redirtab *rp = redirlist;
11217 int i;
11218
11219 INTOFF;
11220 for (i = 0 ; i < 10 ; i++) {
11221 if (rp->renamed[i] != EMPTY) {
Eric Andersen2870d962001-07-02 17:27:21 +000011222 if (i == 0)
11223 fd0_redirected--;
Eric Andersencb57d552001-06-28 07:25:16 +000011224 close(i);
11225 if (rp->renamed[i] >= 0) {
11226 dup_as_newfd(rp->renamed[i], i);
11227 close(rp->renamed[i]);
11228 }
Eric Andersencb57d552001-06-28 07:25:16 +000011229 }
11230 }
11231 redirlist = rp->next;
11232 ckfree(rp);
11233 INTON;
11234}
11235
11236/*
Eric Andersencb57d552001-06-28 07:25:16 +000011237 * Discard all saved file descriptors.
11238 */
11239
11240static void
Eric Andersen2870d962001-07-02 17:27:21 +000011241clearredir(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000011242 struct redirtab *rp;
11243 int i;
11244
11245 for (rp = redirlist ; rp ; rp = rp->next) {
11246 for (i = 0 ; i < 10 ; i++) {
11247 if (rp->renamed[i] >= 0) {
11248 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011249 }
11250 rp->renamed[i] = EMPTY;
11251 }
11252 }
Eric Andersencb57d552001-06-28 07:25:16 +000011253}
11254
11255
Eric Andersencb57d552001-06-28 07:25:16 +000011256/*
11257 * Copy a file descriptor to be >= to. Returns -1
11258 * if the source file descriptor is closed, EMPTY if there are no unused
11259 * file descriptors left.
11260 */
11261
11262static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011263dup_as_newfd(int from, int to)
Eric Andersencb57d552001-06-28 07:25:16 +000011264{
11265 int newfd;
11266
11267 newfd = fcntl(from, F_DUPFD, to);
11268 if (newfd < 0) {
11269 if (errno == EMFILE)
11270 return EMPTY;
11271 else
Eric Andersen2870d962001-07-02 17:27:21 +000011272 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011273 }
11274 return newfd;
11275}
11276
Eric Andersencb57d552001-06-28 07:25:16 +000011277#ifdef DEBUG
Eric Andersenec074692001-10-31 11:05:49 +000011278/*
11279 * Debugging stuff.
11280 */
Eric Andersen2870d962001-07-02 17:27:21 +000011281static void shtree (union node *, int, char *, FILE*);
11282static void shcmd (union node *, FILE *);
11283static void sharg (union node *, FILE *);
11284static void indent (int, char *, FILE *);
11285static void trstring (char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011286
11287
11288static void
11289showtree(n)
Eric Andersen69a20f02001-10-31 10:40:37 +000011290 unode *n;
Eric Andersencb57d552001-06-28 07:25:16 +000011291{
11292 trputs("showtree called\n");
11293 shtree(n, 1, NULL, stdout);
11294}
11295
11296
11297static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011298shtree(union node *n, int ind, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011299{
11300 struct nodelist *lp;
11301 const char *s;
11302
11303 if (n == NULL)
11304 return;
11305
11306 indent(ind, pfx, fp);
11307 switch(n->type) {
11308 case NSEMI:
11309 s = "; ";
11310 goto binop;
11311 case NAND:
11312 s = " && ";
11313 goto binop;
11314 case NOR:
11315 s = " || ";
11316binop:
11317 shtree(n->nbinary.ch1, ind, NULL, fp);
11318 /* if (ind < 0) */
11319 fputs(s, fp);
11320 shtree(n->nbinary.ch2, ind, NULL, fp);
11321 break;
11322 case NCMD:
11323 shcmd(n, fp);
11324 if (ind >= 0)
11325 putc('\n', fp);
11326 break;
11327 case NPIPE:
11328 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11329 shcmd(lp->n, fp);
11330 if (lp->next)
11331 fputs(" | ", fp);
11332 }
11333 if (n->npipe.backgnd)
11334 fputs(" &", fp);
11335 if (ind >= 0)
11336 putc('\n', fp);
11337 break;
11338 default:
11339 fprintf(fp, "<node type %d>", n->type);
11340 if (ind >= 0)
11341 putc('\n', fp);
11342 break;
11343 }
11344}
11345
11346
11347
11348static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011349shcmd(union node *cmd, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011350{
11351 union node *np;
11352 int first;
11353 const char *s;
11354 int dftfd;
11355
11356 first = 1;
11357 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11358 if (! first)
11359 putchar(' ');
11360 sharg(np, fp);
11361 first = 0;
11362 }
11363 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11364 if (! first)
11365 putchar(' ');
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011366#if 1
11367 s = "*error*";
11368 dftfd = 0;
11369 if ((np->nfile.type <= NFROMFD) && (np->nfile.type >= NTO)) {
11370 s = redir_strings[np->nfile.type - NTO];
11371 if (*s == '>') {
11372 dftfd = 1;
11373 }
11374 }
11375#else
Eric Andersencb57d552001-06-28 07:25:16 +000011376 switch (np->nfile.type) {
Eric Andersen2870d962001-07-02 17:27:21 +000011377 case NTO: s = ">"; dftfd = 1; break;
11378 case NAPPEND: s = ">>"; dftfd = 1; break;
11379 case NTOFD: s = ">&"; dftfd = 1; break;
11380 case NTOOV: s = ">|"; dftfd = 1; break;
11381 case NFROM: s = "<"; dftfd = 0; break;
11382 case NFROMFD: s = "<&"; dftfd = 0; break;
11383 case NFROMTO: s = "<>"; dftfd = 0; break;
11384 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011385 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011386#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011387 if (np->nfile.fd != dftfd)
11388 fprintf(fp, "%d", np->nfile.fd);
11389 fputs(s, fp);
11390 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11391 fprintf(fp, "%d", np->ndup.dupfd);
11392 } else {
11393 sharg(np->nfile.fname, fp);
11394 }
11395 first = 0;
11396 }
11397}
11398
Eric Andersencb57d552001-06-28 07:25:16 +000011399static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011400sharg(union node *arg, FILE *fp)
11401{
Eric Andersencb57d552001-06-28 07:25:16 +000011402 char *p;
11403 struct nodelist *bqlist;
11404 int subtype;
11405
11406 if (arg->type != NARG) {
11407 printf("<node type %d>\n", arg->type);
11408 fflush(stdout);
11409 abort();
11410 }
11411 bqlist = arg->narg.backquote;
11412 for (p = arg->narg.text ; *p ; p++) {
11413 switch (*p) {
11414 case CTLESC:
11415 putc(*++p, fp);
11416 break;
11417 case CTLVAR:
11418 putc('$', fp);
11419 putc('{', fp);
11420 subtype = *++p;
11421 if (subtype == VSLENGTH)
11422 putc('#', fp);
11423
11424 while (*p != '=')
11425 putc(*p++, fp);
11426
11427 if (subtype & VSNUL)
11428 putc(':', fp);
11429
11430 switch (subtype & VSTYPE) {
11431 case VSNORMAL:
11432 putc('}', fp);
11433 break;
11434 case VSMINUS:
11435 putc('-', fp);
11436 break;
11437 case VSPLUS:
11438 putc('+', fp);
11439 break;
11440 case VSQUESTION:
11441 putc('?', fp);
11442 break;
11443 case VSASSIGN:
11444 putc('=', fp);
11445 break;
11446 case VSTRIMLEFT:
11447 putc('#', fp);
11448 break;
11449 case VSTRIMLEFTMAX:
11450 putc('#', fp);
11451 putc('#', fp);
11452 break;
11453 case VSTRIMRIGHT:
11454 putc('%', fp);
11455 break;
11456 case VSTRIMRIGHTMAX:
11457 putc('%', fp);
11458 putc('%', fp);
11459 break;
11460 case VSLENGTH:
11461 break;
11462 default:
11463 printf("<subtype %d>", subtype);
11464 }
11465 break;
11466 case CTLENDVAR:
11467 putc('}', fp);
11468 break;
11469 case CTLBACKQ:
11470 case CTLBACKQ|CTLQUOTE:
11471 putc('$', fp);
11472 putc('(', fp);
11473 shtree(bqlist->n, -1, NULL, fp);
11474 putc(')', fp);
11475 break;
11476 default:
11477 putc(*p, fp);
11478 break;
11479 }
11480 }
11481}
11482
11483
11484static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011485indent(int amount, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011486{
11487 int i;
11488
11489 for (i = 0 ; i < amount ; i++) {
11490 if (pfx && i == amount - 1)
11491 fputs(pfx, fp);
11492 putc('\t', fp);
11493 }
11494}
Eric Andersencb57d552001-06-28 07:25:16 +000011495
11496
Eric Andersencb57d552001-06-28 07:25:16 +000011497FILE *tracefile;
11498
11499#if DEBUG == 2
11500static int debug = 1;
11501#else
11502static int debug = 0;
11503#endif
11504
11505
11506static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011507trputc(int c)
Eric Andersencb57d552001-06-28 07:25:16 +000011508{
11509 if (tracefile == NULL)
11510 return;
11511 putc(c, tracefile);
11512 if (c == '\n')
11513 fflush(tracefile);
11514}
11515
11516static void
11517trace(const char *fmt, ...)
11518{
11519 va_list va;
Eric Andersencb57d552001-06-28 07:25:16 +000011520 va_start(va, fmt);
Eric Andersencb57d552001-06-28 07:25:16 +000011521 if (tracefile != NULL) {
11522 (void) vfprintf(tracefile, fmt, va);
11523 if (strchr(fmt, '\n'))
11524 (void) fflush(tracefile);
11525 }
11526 va_end(va);
11527}
11528
11529
11530static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011531trputs(const char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011532{
11533 if (tracefile == NULL)
11534 return;
11535 fputs(s, tracefile);
11536 if (strchr(s, '\n'))
11537 fflush(tracefile);
11538}
11539
11540
11541static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011542trstring(char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011543{
11544 char *p;
11545 char c;
11546
11547 if (tracefile == NULL)
11548 return;
11549 putc('"', tracefile);
11550 for (p = s ; *p ; p++) {
11551 switch (*p) {
11552 case '\n': c = 'n'; goto backslash;
11553 case '\t': c = 't'; goto backslash;
11554 case '\r': c = 'r'; goto backslash;
11555 case '"': c = '"'; goto backslash;
11556 case '\\': c = '\\'; goto backslash;
11557 case CTLESC: c = 'e'; goto backslash;
11558 case CTLVAR: c = 'v'; goto backslash;
11559 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11560 case CTLBACKQ: c = 'q'; goto backslash;
11561 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
Eric Andersen2870d962001-07-02 17:27:21 +000011562backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011563 putc(c, tracefile);
11564 break;
11565 default:
11566 if (*p >= ' ' && *p <= '~')
11567 putc(*p, tracefile);
11568 else {
11569 putc('\\', tracefile);
11570 putc(*p >> 6 & 03, tracefile);
11571 putc(*p >> 3 & 07, tracefile);
11572 putc(*p & 07, tracefile);
11573 }
11574 break;
11575 }
11576 }
11577 putc('"', tracefile);
11578}
11579
11580
11581static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011582trargs(char **ap)
Eric Andersencb57d552001-06-28 07:25:16 +000011583{
11584 if (tracefile == NULL)
11585 return;
11586 while (*ap) {
11587 trstring(*ap++);
11588 if (*ap)
11589 putc(' ', tracefile);
11590 else
11591 putc('\n', tracefile);
11592 }
11593 fflush(tracefile);
11594}
11595
11596
11597static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011598opentrace()
11599{
Eric Andersencb57d552001-06-28 07:25:16 +000011600 char s[100];
11601#ifdef O_APPEND
11602 int flags;
11603#endif
11604
11605 if (!debug)
11606 return;
11607#ifdef not_this_way
11608 {
11609 char *p;
11610 if ((p = getenv("HOME")) == NULL) {
11611 if (geteuid() == 0)
11612 p = "/";
11613 else
11614 p = "/tmp";
11615 }
Eric Andersen2870d962001-07-02 17:27:21 +000011616 strcpy(s, p);
Eric Andersencb57d552001-06-28 07:25:16 +000011617 strcat(s, "/trace");
11618 }
11619#else
Eric Andersen2870d962001-07-02 17:27:21 +000011620 strcpy(s, "./trace");
Eric Andersencb57d552001-06-28 07:25:16 +000011621#endif /* not_this_way */
Matt Kraaia5f09c62001-11-12 16:44:55 +000011622 if ((tracefile = wfopen(s, "a")) == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000011623 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011624#ifdef O_APPEND
11625 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11626 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11627#endif
11628 fputs("\nTracing started.\n", tracefile);
11629 fflush(tracefile);
11630}
11631#endif /* DEBUG */
11632
11633
11634/*
Eric Andersencb57d552001-06-28 07:25:16 +000011635 * The trap builtin.
11636 */
11637
11638static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011639trapcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011640{
11641 char *action;
11642 char **ap;
11643 int signo;
11644
11645 if (argc <= 1) {
11646 for (signo = 0 ; signo < NSIG ; signo++) {
11647 if (trap[signo] != NULL) {
11648 char *p;
Eric Andersen34506362001-08-02 05:02:46 +000011649 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011650
11651 p = single_quote(trap[signo]);
Eric Andersen34506362001-08-02 05:02:46 +000011652 sn = sys_siglist[signo];
11653 if(sn==NULL)
11654 sn = u_signal_names(0, &signo, 0);
11655 if(sn==NULL)
11656 sn = "???";
11657 printf("trap -- %s %s\n", p, sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011658 stunalloc(p);
11659 }
11660 }
11661 return 0;
11662 }
11663 ap = argv + 1;
11664 if (argc == 2)
11665 action = NULL;
11666 else
11667 action = *ap++;
11668 while (*ap) {
11669 if ((signo = decode_signal(*ap, 0)) < 0)
11670 error("%s: bad trap", *ap);
11671 INTOFF;
11672 if (action) {
11673 if (action[0] == '-' && action[1] == '\0')
11674 action = NULL;
11675 else
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011676 action = xstrdup(action);
Eric Andersencb57d552001-06-28 07:25:16 +000011677 }
11678 if (trap[signo])
11679 ckfree(trap[signo]);
11680 trap[signo] = action;
11681 if (signo != 0)
11682 setsignal(signo);
11683 INTON;
11684 ap++;
11685 }
11686 return 0;
11687}
11688
11689
11690
Eric Andersencb57d552001-06-28 07:25:16 +000011691
11692
11693
11694/*
11695 * Set the signal handler for the specified signal. The routine figures
11696 * out what it should be set to.
11697 */
11698
11699static void
Eric Andersen2870d962001-07-02 17:27:21 +000011700setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011701{
11702 int action;
11703 char *t;
11704 struct sigaction act;
11705
11706 if ((t = trap[signo]) == NULL)
11707 action = S_DFL;
11708 else if (*t != '\0')
11709 action = S_CATCH;
11710 else
11711 action = S_IGN;
11712 if (rootshell && action == S_DFL) {
11713 switch (signo) {
11714 case SIGINT:
11715 if (iflag || minusc || sflag == 0)
11716 action = S_CATCH;
11717 break;
11718 case SIGQUIT:
11719#ifdef DEBUG
11720 {
Eric Andersencb57d552001-06-28 07:25:16 +000011721
11722 if (debug)
11723 break;
11724 }
11725#endif
11726 /* FALLTHROUGH */
11727 case SIGTERM:
11728 if (iflag)
11729 action = S_IGN;
11730 break;
Eric Andersend35c5df2002-01-09 15:37:36 +000011731#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +000011732 case SIGTSTP:
11733 case SIGTTOU:
11734 if (mflag)
11735 action = S_IGN;
11736 break;
11737#endif
11738 }
11739 }
11740
11741 t = &sigmode[signo - 1];
11742 if (*t == 0) {
11743 /*
11744 * current setting unknown
11745 */
11746 if (sigaction(signo, 0, &act) == -1) {
11747 /*
11748 * Pretend it worked; maybe we should give a warning
11749 * here, but other shells don't. We don't alter
11750 * sigmode, so that we retry every time.
11751 */
11752 return;
11753 }
11754 if (act.sa_handler == SIG_IGN) {
11755 if (mflag && (signo == SIGTSTP ||
11756 signo == SIGTTIN || signo == SIGTTOU)) {
Eric Andersen2870d962001-07-02 17:27:21 +000011757 *t = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000011758 } else
11759 *t = S_HARD_IGN;
11760 } else {
Eric Andersen2870d962001-07-02 17:27:21 +000011761 *t = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000011762 }
11763 }
11764 if (*t == S_HARD_IGN || *t == action)
11765 return;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011766 act.sa_handler = ((action == S_CATCH) ? onsig
11767 : ((action == S_IGN) ? SIG_IGN : SIG_DFL));
Eric Andersencb57d552001-06-28 07:25:16 +000011768 *t = action;
11769 act.sa_flags = 0;
11770 sigemptyset(&act.sa_mask);
11771 sigaction(signo, &act, 0);
11772}
11773
11774/*
11775 * Ignore a signal.
11776 */
11777
11778static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011779ignoresig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011780{
11781 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11782 signal(signo, SIG_IGN);
11783 }
11784 sigmode[signo - 1] = S_HARD_IGN;
11785}
11786
11787
Eric Andersencb57d552001-06-28 07:25:16 +000011788/*
11789 * Signal handler.
11790 */
11791
11792static void
Eric Andersen2870d962001-07-02 17:27:21 +000011793onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011794{
11795 if (signo == SIGINT && trap[SIGINT] == NULL) {
11796 onint();
11797 return;
11798 }
11799 gotsig[signo - 1] = 1;
11800 pendingsigs++;
11801}
11802
11803
Eric Andersencb57d552001-06-28 07:25:16 +000011804/*
11805 * Called to execute a trap. Perhaps we should avoid entering new trap
11806 * handlers while we are executing a trap handler.
11807 */
11808
11809static void
Eric Andersen2870d962001-07-02 17:27:21 +000011810dotrap(void)
11811{
Eric Andersencb57d552001-06-28 07:25:16 +000011812 int i;
11813 int savestatus;
11814
11815 for (;;) {
11816 for (i = 1 ; ; i++) {
11817 if (gotsig[i - 1])
11818 break;
11819 if (i >= NSIG - 1)
11820 goto done;
11821 }
11822 gotsig[i - 1] = 0;
11823 savestatus=exitstatus;
11824 evalstring(trap[i], 0);
11825 exitstatus=savestatus;
11826 }
11827done:
11828 pendingsigs = 0;
11829}
11830
Eric Andersencb57d552001-06-28 07:25:16 +000011831/*
11832 * Called to exit the shell.
11833 */
11834
11835static void
Eric Andersen2870d962001-07-02 17:27:21 +000011836exitshell(int status)
Eric Andersencb57d552001-06-28 07:25:16 +000011837{
11838 struct jmploc loc1, loc2;
11839 char *p;
11840
11841 TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
11842 if (setjmp(loc1.loc)) {
11843 goto l1;
11844 }
11845 if (setjmp(loc2.loc)) {
11846 goto l2;
11847 }
11848 handler = &loc1;
11849 if ((p = trap[0]) != NULL && *p != '\0') {
11850 trap[0] = NULL;
11851 evalstring(p, 0);
11852 }
Eric Andersen2870d962001-07-02 17:27:21 +000011853l1: handler = &loc2; /* probably unnecessary */
Eric Andersencb57d552001-06-28 07:25:16 +000011854 flushall();
Eric Andersend35c5df2002-01-09 15:37:36 +000011855#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +000011856 setjobctl(0);
11857#endif
11858l2: _exit(status);
11859 /* NOTREACHED */
11860}
11861
11862static int decode_signal(const char *string, int minsig)
11863{
11864 int signo;
Eric Andersen34506362001-08-02 05:02:46 +000011865 const char *name = u_signal_names(string, &signo, minsig);
Eric Andersencb57d552001-06-28 07:25:16 +000011866
Eric Andersen34506362001-08-02 05:02:46 +000011867 return name ? signo : -1;
Eric Andersencb57d552001-06-28 07:25:16 +000011868}
Eric Andersen34506362001-08-02 05:02:46 +000011869
Eric Andersen2870d962001-07-02 17:27:21 +000011870static struct var **hashvar (const char *);
11871static void showvars (const char *, int, int);
11872static struct var **findvar (struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011873
11874/*
11875 * Initialize the varable symbol tables and import the environment
11876 */
11877
Eric Andersencb57d552001-06-28 07:25:16 +000011878/*
11879 * This routine initializes the builtin variables. It is called when the
11880 * shell is initialized and again when a shell procedure is spawned.
11881 */
11882
11883static void
11884initvar() {
11885 const struct varinit *ip;
11886 struct var *vp;
11887 struct var **vpp;
11888
11889 for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
11890 if ((vp->flags & VEXPORT) == 0) {
11891 vpp = hashvar(ip->text);
11892 vp->next = *vpp;
11893 *vpp = vp;
Matt Kraaic8227632001-11-12 16:57:27 +000011894 vp->text = xstrdup(ip->text);
Eric Andersencb57d552001-06-28 07:25:16 +000011895 vp->flags = ip->flags;
11896 vp->func = ip->func;
11897 }
11898 }
11899 /*
11900 * PS1 depends on uid
11901 */
11902 if ((vps1.flags & VEXPORT) == 0) {
Aaron Lehmann9a218bf2001-12-31 06:13:38 +000011903 vpp = hashvar("PS1=$");
Eric Andersencb57d552001-06-28 07:25:16 +000011904 vps1.next = *vpp;
11905 *vpp = &vps1;
Matt Kraaic8227632001-11-12 16:57:27 +000011906 vps1.text = xstrdup(geteuid() ? "PS1=$ " : "PS1=# ");
Eric Andersencb57d552001-06-28 07:25:16 +000011907 vps1.flags = VSTRFIXED|VTEXTFIXED;
11908 }
11909}
11910
11911/*
11912 * Set the value of a variable. The flags argument is ored with the
11913 * flags of the variable. If val is NULL, the variable is unset.
11914 */
11915
11916static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011917setvar(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011918{
11919 const char *p;
11920 int len;
11921 int namelen;
11922 char *nameeq;
11923 int isbad;
11924 int vallen = 0;
11925
11926 isbad = 0;
11927 p = name;
11928 if (! is_name(*p))
11929 isbad = 1;
11930 p++;
11931 for (;;) {
11932 if (! is_in_name(*p)) {
11933 if (*p == '\0' || *p == '=')
11934 break;
11935 isbad = 1;
11936 }
11937 p++;
11938 }
11939 namelen = p - name;
11940 if (isbad)
11941 error("%.*s: bad variable name", namelen, name);
Eric Andersen2870d962001-07-02 17:27:21 +000011942 len = namelen + 2; /* 2 is space for '=' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +000011943 if (val == NULL) {
11944 flags |= VUNSET;
11945 } else {
11946 len += vallen = strlen(val);
11947 }
11948 INTOFF;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011949 nameeq = xmalloc(len);
Eric Andersencb57d552001-06-28 07:25:16 +000011950 memcpy(nameeq, name, namelen);
11951 nameeq[namelen] = '=';
11952 if (val) {
11953 memcpy(nameeq + namelen + 1, val, vallen + 1);
11954 } else {
11955 nameeq[namelen + 1] = '\0';
11956 }
11957 setvareq(nameeq, flags);
11958 INTON;
11959}
11960
11961
11962
11963/*
11964 * Same as setvar except that the variable and value are passed in
11965 * the first argument as name=value. Since the first argument will
11966 * be actually stored in the table, it should not be a string that
11967 * will go away.
11968 */
11969
11970static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011971setvareq(char *s, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011972{
11973 struct var *vp, **vpp;
11974
11975 vpp = hashvar(s);
11976 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
11977 if ((vp = *findvar(vpp, s))) {
11978 if (vp->flags & VREADONLY) {
11979 size_t len = strchr(s, '=') - s;
11980 error("%.*s: is read only", len, s);
11981 }
11982 INTOFF;
11983
11984 if (vp->func && (flags & VNOFUNC) == 0)
11985 (*vp->func)(strchr(s, '=') + 1);
11986
11987 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
11988 ckfree(vp->text);
11989
11990 vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
11991 vp->flags |= flags;
11992 vp->text = s;
11993
Eric Andersend35c5df2002-01-09 15:37:36 +000011994#ifdef CONFIG_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000011995 /*
11996 * We could roll this to a function, to handle it as
11997 * a regular variable function callback, but why bother?
11998 */
11999 if (iflag && (vp == &vmpath || (vp == &vmail && !mpathset())))
12000 chkmail(1);
Eric Andersenec074692001-10-31 11:05:49 +000012001#endif
Eric Andersencb57d552001-06-28 07:25:16 +000012002 INTON;
12003 return;
12004 }
12005 /* not found */
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012006 vp = xmalloc(sizeof (*vp));
Eric Andersencb57d552001-06-28 07:25:16 +000012007 vp->flags = flags;
12008 vp->text = s;
12009 vp->next = *vpp;
12010 vp->func = NULL;
12011 *vpp = vp;
12012}
12013
12014
12015
12016/*
12017 * Process a linked list of variable assignments.
12018 */
12019
12020static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012021listsetvar(struct strlist *mylist)
12022{
Eric Andersencb57d552001-06-28 07:25:16 +000012023 struct strlist *lp;
12024
12025 INTOFF;
12026 for (lp = mylist ; lp ; lp = lp->next) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012027 setvareq(xstrdup(lp->text), 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012028 }
12029 INTON;
12030}
12031
12032
12033
12034/*
12035 * Find the value of a variable. Returns NULL if not set.
12036 */
12037
Eric Andersen62483552001-07-10 06:09:16 +000012038static const char *
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012039lookupvar(const char *name)
Eric Andersenec074692001-10-31 11:05:49 +000012040{
Eric Andersencb57d552001-06-28 07:25:16 +000012041 struct var *v;
12042
12043 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
12044 return strchr(v->text, '=') + 1;
12045 }
12046 return NULL;
12047}
12048
12049
12050
12051/*
12052 * Search the environment of a builtin command.
12053 */
12054
Eric Andersen62483552001-07-10 06:09:16 +000012055static const char *
12056bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012057{
Eric Andersen62483552001-07-10 06:09:16 +000012058 const struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012059
12060 for (sp = cmdenviron ; sp ; sp = sp->next) {
12061 if (varequal(sp->text, name))
12062 return strchr(sp->text, '=') + 1;
12063 }
12064 return lookupvar(name);
12065}
12066
12067
12068
12069/*
12070 * Generate a list of exported variables. This routine is used to construct
12071 * the third argument to execve when executing a program.
12072 */
12073
12074static char **
12075environment() {
12076 int nenv;
12077 struct var **vpp;
12078 struct var *vp;
12079 char **env;
12080 char **ep;
12081
12082 nenv = 0;
12083 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12084 for (vp = *vpp ; vp ; vp = vp->next)
12085 if (vp->flags & VEXPORT)
12086 nenv++;
12087 }
12088 ep = env = stalloc((nenv + 1) * sizeof *env);
12089 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12090 for (vp = *vpp ; vp ; vp = vp->next)
12091 if (vp->flags & VEXPORT)
12092 *ep++ = vp->text;
12093 }
12094 *ep = NULL;
12095 return env;
12096}
12097
12098
12099/*
12100 * Called when a shell procedure is invoked to clear out nonexported
12101 * variables. It is also necessary to reallocate variables of with
12102 * VSTACK set since these are currently allocated on the stack.
12103 */
12104
Eric Andersencb57d552001-06-28 07:25:16 +000012105static void
Eric Andersen2870d962001-07-02 17:27:21 +000012106shprocvar(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000012107 struct var **vpp;
12108 struct var *vp, **prev;
12109
12110 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12111 for (prev = vpp ; (vp = *prev) != NULL ; ) {
12112 if ((vp->flags & VEXPORT) == 0) {
12113 *prev = vp->next;
12114 if ((vp->flags & VTEXTFIXED) == 0)
12115 ckfree(vp->text);
12116 if ((vp->flags & VSTRFIXED) == 0)
12117 ckfree(vp);
12118 } else {
12119 if (vp->flags & VSTACK) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012120 vp->text = xstrdup(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012121 vp->flags &=~ VSTACK;
12122 }
12123 prev = &vp->next;
12124 }
12125 }
12126 }
12127 initvar();
12128}
12129
12130
12131
12132/*
12133 * Command to list all variables which are set. Currently this command
12134 * is invoked from the set command when the set command is called without
12135 * any variables.
12136 */
12137
12138static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012139showvarscmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012140{
12141 showvars(nullstr, VUNSET, VUNSET);
12142 return 0;
12143}
12144
12145
12146
12147/*
12148 * The export and readonly commands.
12149 */
12150
12151static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012152exportcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012153{
12154 struct var *vp;
12155 char *name;
12156 const char *p;
12157 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12158 int pflag;
12159
12160 listsetvar(cmdenviron);
12161 pflag = (nextopt("p") == 'p');
12162 if (argc > 1 && !pflag) {
12163 while ((name = *argptr++) != NULL) {
12164 if ((p = strchr(name, '=')) != NULL) {
12165 p++;
12166 } else {
12167 if ((vp = *findvar(hashvar(name), name))) {
12168 vp->flags |= flag;
12169 goto found;
12170 }
12171 }
12172 setvar(name, p, flag);
12173found:;
12174 }
12175 } else {
12176 showvars(argv[0], flag, 0);
12177 }
12178 return 0;
12179}
12180
Eric Andersen34506362001-08-02 05:02:46 +000012181
Eric Andersencb57d552001-06-28 07:25:16 +000012182/*
12183 * The "local" command.
12184 */
12185
Eric Andersen2870d962001-07-02 17:27:21 +000012186/* funcnest nonzero if we are currently evaluating a function */
12187
Eric Andersencb57d552001-06-28 07:25:16 +000012188static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012189localcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012190{
12191 char *name;
12192
Eric Andersen2870d962001-07-02 17:27:21 +000012193 if (! funcnest)
Eric Andersencb57d552001-06-28 07:25:16 +000012194 error("Not in a function");
12195 while ((name = *argptr++) != NULL) {
12196 mklocal(name);
12197 }
12198 return 0;
12199}
12200
12201
12202/*
12203 * Make a variable a local variable. When a variable is made local, it's
12204 * value and flags are saved in a localvar structure. The saved values
12205 * will be restored when the shell function returns. We handle the name
12206 * "-" as a special case.
12207 */
12208
12209static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012210mklocal(char *name)
12211{
Eric Andersencb57d552001-06-28 07:25:16 +000012212 struct localvar *lvp;
12213 struct var **vpp;
12214 struct var *vp;
12215
12216 INTOFF;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012217 lvp = xmalloc(sizeof (struct localvar));
Eric Andersencb57d552001-06-28 07:25:16 +000012218 if (name[0] == '-' && name[1] == '\0') {
12219 char *p;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012220 p = xmalloc(sizeof optet_vals);
Eric Andersen2870d962001-07-02 17:27:21 +000012221 lvp->text = memcpy(p, optet_vals, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000012222 vp = NULL;
12223 } else {
12224 vpp = hashvar(name);
12225 vp = *findvar(vpp, name);
12226 if (vp == NULL) {
12227 if (strchr(name, '='))
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012228 setvareq(xstrdup(name), VSTRFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +000012229 else
12230 setvar(name, NULL, VSTRFIXED);
Eric Andersen2870d962001-07-02 17:27:21 +000012231 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012232 lvp->text = NULL;
12233 lvp->flags = VUNSET;
12234 } else {
12235 lvp->text = vp->text;
12236 lvp->flags = vp->flags;
12237 vp->flags |= VSTRFIXED|VTEXTFIXED;
12238 if (strchr(name, '='))
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012239 setvareq(xstrdup(name), 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012240 }
12241 }
12242 lvp->vp = vp;
12243 lvp->next = localvars;
12244 localvars = lvp;
12245 INTON;
12246}
12247
12248
12249/*
12250 * Called after a function returns.
12251 */
12252
12253static void
12254poplocalvars() {
12255 struct localvar *lvp;
12256 struct var *vp;
12257
12258 while ((lvp = localvars) != NULL) {
12259 localvars = lvp->next;
12260 vp = lvp->vp;
Eric Andersen2870d962001-07-02 17:27:21 +000012261 if (vp == NULL) { /* $- saved */
12262 memcpy(optet_vals, lvp->text, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000012263 ckfree(lvp->text);
12264 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12265 (void)unsetvar(vp->text);
12266 } else {
12267 if ((vp->flags & VTEXTFIXED) == 0)
12268 ckfree(vp->text);
12269 vp->flags = lvp->flags;
12270 vp->text = lvp->text;
12271 }
12272 ckfree(lvp);
12273 }
12274}
12275
12276
12277static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012278setvarcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012279{
12280 if (argc <= 2)
12281 return unsetcmd(argc, argv);
12282 else if (argc == 3)
12283 setvar(argv[1], argv[2], 0);
12284 else
12285 error("List assignment not implemented");
12286 return 0;
12287}
12288
12289
12290/*
12291 * The unset builtin command. We unset the function before we unset the
12292 * variable to allow a function to be unset when there is a readonly variable
12293 * with the same name.
12294 */
12295
12296static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012297unsetcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012298{
12299 char **ap;
12300 int i;
12301 int flg_func = 0;
12302 int flg_var = 0;
12303 int ret = 0;
12304
12305 while ((i = nextopt("vf")) != '\0') {
12306 if (i == 'f')
12307 flg_func = 1;
12308 else
12309 flg_var = 1;
12310 }
12311 if (flg_func == 0 && flg_var == 0)
12312 flg_var = 1;
12313
12314 for (ap = argptr; *ap ; ap++) {
12315 if (flg_func)
12316 unsetfunc(*ap);
12317 if (flg_var)
12318 ret |= unsetvar(*ap);
12319 }
12320 return ret;
12321}
12322
12323
12324/*
12325 * Unset the specified variable.
12326 */
12327
12328static int
Eric Andersen62483552001-07-10 06:09:16 +000012329unsetvar(const char *s)
12330{
Eric Andersencb57d552001-06-28 07:25:16 +000012331 struct var **vpp;
12332 struct var *vp;
12333
12334 vpp = findvar(hashvar(s), s);
12335 vp = *vpp;
12336 if (vp) {
12337 if (vp->flags & VREADONLY)
12338 return (1);
12339 INTOFF;
12340 if (*(strchr(vp->text, '=') + 1) != '\0')
12341 setvar(s, nullstr, 0);
12342 vp->flags &= ~VEXPORT;
12343 vp->flags |= VUNSET;
12344 if ((vp->flags & VSTRFIXED) == 0) {
12345 if ((vp->flags & VTEXTFIXED) == 0)
12346 ckfree(vp->text);
12347 *vpp = vp->next;
12348 ckfree(vp);
12349 }
12350 INTON;
12351 return (0);
12352 }
12353
12354 return (0);
12355}
12356
12357
12358
12359/*
12360 * Find the appropriate entry in the hash table from the name.
12361 */
12362
12363static struct var **
Eric Andersen62483552001-07-10 06:09:16 +000012364hashvar(const char *p)
12365{
Eric Andersencb57d552001-06-28 07:25:16 +000012366 unsigned int hashval;
12367
12368 hashval = ((unsigned char) *p) << 4;
12369 while (*p && *p != '=')
12370 hashval += (unsigned char) *p++;
12371 return &vartab[hashval % VTABSIZE];
12372}
12373
12374
12375
12376/*
12377 * Returns true if the two strings specify the same varable. The first
12378 * variable name is terminated by '='; the second may be terminated by
12379 * either '=' or '\0'.
12380 */
12381
12382static int
Eric Andersen62483552001-07-10 06:09:16 +000012383varequal(const char *p, const char *q)
12384{
Eric Andersencb57d552001-06-28 07:25:16 +000012385 while (*p == *q++) {
12386 if (*p++ == '=')
12387 return 1;
12388 }
12389 if (*p == '=' && *(q - 1) == '\0')
12390 return 1;
12391 return 0;
12392}
12393
12394static void
12395showvars(const char *myprefix, int mask, int xor)
12396{
12397 struct var **vpp;
12398 struct var *vp;
12399 const char *sep = myprefix == nullstr ? myprefix : spcstr;
12400
12401 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12402 for (vp = *vpp ; vp ; vp = vp->next) {
12403 if ((vp->flags & mask) ^ xor) {
12404 char *p;
12405 int len;
12406
12407 p = strchr(vp->text, '=') + 1;
12408 len = p - vp->text;
12409 p = single_quote(p);
12410
Eric Andersen62483552001-07-10 06:09:16 +000012411 printf("%s%s%.*s%s\n", myprefix, sep, len,
12412 vp->text, p);
Eric Andersencb57d552001-06-28 07:25:16 +000012413 stunalloc(p);
12414 }
12415 }
12416 }
12417}
12418
12419static struct var **
12420findvar(struct var **vpp, const char *name)
12421{
12422 for (; *vpp; vpp = &(*vpp)->next) {
12423 if (varequal((*vpp)->text, name)) {
12424 break;
12425 }
12426 }
12427 return vpp;
12428}
12429
12430/*
12431 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
12432 * This file contains code for the times builtin.
Eric Andersend35c5df2002-01-09 15:37:36 +000012433 * $Id: ash.c,v 1.46 2002/01/09 15:37:36 andersen Exp $
Eric Andersencb57d552001-06-28 07:25:16 +000012434 */
12435static int timescmd (int argc, char **argv)
12436{
12437 struct tms buf;
12438 long int clk_tck = sysconf(_SC_CLK_TCK);
12439
12440 times(&buf);
12441 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
12442 (int) (buf.tms_utime / clk_tck / 60),
12443 ((double) buf.tms_utime) / clk_tck,
12444 (int) (buf.tms_stime / clk_tck / 60),
12445 ((double) buf.tms_stime) / clk_tck,
12446 (int) (buf.tms_cutime / clk_tck / 60),
12447 ((double) buf.tms_cutime) / clk_tck,
12448 (int) (buf.tms_cstime / clk_tck / 60),
12449 ((double) buf.tms_cstime) / clk_tck);
12450 return 0;
12451}
12452
Eric Andersend35c5df2002-01-09 15:37:36 +000012453#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012454/* The let builtin. */
12455int letcmd(int argc, char **argv)
Eric Andersen74bcd162001-07-30 21:41:37 +000012456{
Eric Andersen34506362001-08-02 05:02:46 +000012457 int errcode;
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012458 long result=0;
12459 if (argc == 2) {
12460 char *tmp, *expression, p[13];
12461 expression = strchr(argv[1], '=');
12462 if (!expression) {
Eric Andersen34506362001-08-02 05:02:46 +000012463 /* Cannot use 'error()' here, or the return code
12464 * will be incorrect */
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012465 out2fmt("sh: let: syntax error: \"%s\"\n", argv[1]);
12466 return 0;
Eric Andersen74bcd162001-07-30 21:41:37 +000012467 }
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012468 *expression = '\0';
12469 tmp = ++expression;
Eric Andersen34506362001-08-02 05:02:46 +000012470 result = arith(tmp, &errcode);
12471 if (errcode < 0) {
12472 /* Cannot use 'error()' here, or the return code
12473 * will be incorrect */
12474 out2fmt("sh: let: ");
12475 if(errcode == -2)
12476 out2fmt("divide by zero");
12477 else
12478 out2fmt("syntax error: \"%s=%s\"\n", argv[1], expression);
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012479 return 0;
12480 }
12481 snprintf(p, 12, "%ld", result);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012482 setvar(argv[1], xstrdup(p), 0);
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012483 } else if (argc >= 3)
12484 synerror("invalid operand");
12485 return !result;
Eric Andersen74bcd162001-07-30 21:41:37 +000012486}
12487#endif
12488
12489
12490
Eric Andersendf82f612001-06-28 07:46:40 +000012491/*-
12492 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000012493 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000012494 *
12495 * This code is derived from software contributed to Berkeley by
12496 * Kenneth Almquist.
12497 *
12498 * Redistribution and use in source and binary forms, with or without
12499 * modification, are permitted provided that the following conditions
12500 * are met:
12501 * 1. Redistributions of source code must retain the above copyright
12502 * notice, this list of conditions and the following disclaimer.
12503 * 2. Redistributions in binary form must reproduce the above copyright
12504 * notice, this list of conditions and the following disclaimer in the
12505 * documentation and/or other materials provided with the distribution.
12506 *
Eric Andersen2870d962001-07-02 17:27:21 +000012507 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
12508 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000012509 *
12510 * 4. Neither the name of the University nor the names of its contributors
12511 * may be used to endorse or promote products derived from this software
12512 * without specific prior written permission.
12513 *
12514 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
12515 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
12516 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
12517 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
12518 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
12519 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
12520 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
12521 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
12522 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
12523 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
12524 * SUCH DAMAGE.
12525 */