blob: 53fb56c2c0246382259f2de9a3facee3f7d9ad6e [file] [log] [blame]
Eric Andersendf82f612001-06-28 07:46:40 +00001/* vi: set sw=4 ts=4: */
2/*
3 * ash shell port for busybox
4 *
5 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +00006 * The Regents of the University of California. All rights reserved.
Eric Andersencb57d552001-06-28 07:25:16 +00007 *
8 * This code is derived from software contributed to Berkeley by
9 * Kenneth Almquist.
10 *
Eric Andersendf82f612001-06-28 07:46:40 +000011 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
Eric Andersencb57d552001-06-28 07:25:16 +000015 *
Eric Andersendf82f612001-06-28 07:46:40 +000016 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
Eric Andersen2870d962001-07-02 17:27:21 +000025 * This version of ash is adapted from the source in Debian's ash 0.3.8-5
26 * package.
Eric Andersendf82f612001-06-28 07:46:40 +000027 *
Eric Andersen2870d962001-07-02 17:27:21 +000028 * Modified by Erik Andersen <andersee@debian.org> and
Eric Andersen7467c8d2001-07-12 20:26:32 +000029 * Vladimir Oleynik <dzo@simtreas.ru> to be used in busybox
Eric Andersen2870d962001-07-02 17:27:21 +000030 *
Eric Andersendf82f612001-06-28 07:46:40 +000031 *
32 * Original copyright notice is retained at the end of this file.
Eric Andersencb57d552001-06-28 07:25:16 +000033 */
34
Eric Andersen2870d962001-07-02 17:27:21 +000035
36/* These defines allow you to adjust the feature set to be compiled
37 * into the ash shell. As a rule, enabling these options will make
38 * ash get bigger... With all of these options off, ash adds about
Eric Andersen62483552001-07-10 06:09:16 +000039 * 60k to busybox on an x86 system.*/
Eric Andersen2870d962001-07-02 17:27:21 +000040
41
42/* Enable job control. This allows you to run jobs in the background,
43 * which is great when ash is being used as an interactive shell, but
Eric Andersen3102ac42001-07-06 04:26:23 +000044 * it completely useless for is all you are doing is running scripts.
Eric Andersen2870d962001-07-02 17:27:21 +000045 * This adds about 2.5k on an x86 system. */
Eric Andersen62483552001-07-10 06:09:16 +000046#undef JOBS
Eric Andersen2870d962001-07-02 17:27:21 +000047
48/* This enables alias support in ash. If you want to support things
49 * like "alias ls='ls -l'" with ash, enable this. This is only useful
50 * when ash is used as an intractive shell. This adds about 1.5k */
51#define ASH_ALIAS
52
53/* If you need ash to act as a full Posix shell, with full math
Eric Andersen74bcd162001-07-30 21:41:37 +000054 * support, enable this. This adds a bit over 2k an x86 system. */
Eric Andersen34506362001-08-02 05:02:46 +000055//#undef ASH_MATH_SUPPORT
Eric Andersen74bcd162001-07-30 21:41:37 +000056#define ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +000057
Eric Andersen2870d962001-07-02 17:27:21 +000058/* Getopts is used by shell procedures to parse positional parameters.
59 * You probably want to leave this disabled, and use the busybox getopt
60 * applet if you want to do this sort of thing. There are some scripts
Manuel Novoa III 16815d42001-08-10 19:36:07 +000061 * out there that use it, so it you need it, enable. Most people will
Eric Andersen2870d962001-07-02 17:27:21 +000062 * leave this disabled. This adds 1k on an x86 system. */
63#undef ASH_GETOPTS
64
65/* This allows you to override shell builtins and use whatever is on
66 * the filesystem. This is most useful when ash is acting as a
Eric Andersen62483552001-07-10 06:09:16 +000067 * standalone shell. Adds about 272 bytes. */
Eric Andersen2870d962001-07-02 17:27:21 +000068#undef ASH_CMDCMD
69
Eric Andersen2870d962001-07-02 17:27:21 +000070
Eric Andersen3102ac42001-07-06 04:26:23 +000071/* Optimize size vs speed as size */
72#define ASH_OPTIMIZE_FOR_SIZE
73
Eric Andersen2870d962001-07-02 17:27:21 +000074/* Enable this to compile in extra debugging noise. When debugging is
75 * on, debugging info will be written to $HOME/trace and a quit signal
76 * will generate a core dump. */
77#undef DEBUG
78
Eric Andersen2870d962001-07-02 17:27:21 +000079/* These are here to work with glibc -- Don't change these... */
Eric Andersendf82f612001-06-28 07:46:40 +000080#undef FNMATCH_BROKEN
81#undef GLOB_BROKEN
Eric Andersencb57d552001-06-28 07:25:16 +000082
83#include <assert.h>
Manuel Novoa III 16815d42001-08-10 19:36:07 +000084#include <stddef.h>
Eric Andersencb57d552001-06-28 07:25:16 +000085#include <ctype.h>
86#include <dirent.h>
87#include <errno.h>
88#include <fcntl.h>
89#include <limits.h>
90#include <paths.h>
91#include <pwd.h>
92#include <setjmp.h>
93#include <signal.h>
94#include <stdarg.h>
Eric Andersencb57d552001-06-28 07:25:16 +000095#include <stdio.h>
96#include <stdlib.h>
97#include <string.h>
98#include <sysexits.h>
99#include <unistd.h>
100#include <sys/stat.h>
101#include <sys/cdefs.h>
102#include <sys/ioctl.h>
103#include <sys/param.h>
104#include <sys/resource.h>
105#include <sys/time.h>
106#include <sys/times.h>
107#include <sys/types.h>
108#include <sys/wait.h>
109
110
111#if !defined(FNMATCH_BROKEN)
112#include <fnmatch.h>
113#endif
114#if !defined(GLOB_BROKEN)
115#include <glob.h>
116#endif
117
Eric Andersen2870d962001-07-02 17:27:21 +0000118#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +0000119#include <termios.h>
Eric Andersencb57d552001-06-28 07:25:16 +0000120#endif
121
Eric Andersencb57d552001-06-28 07:25:16 +0000122#include "busybox.h"
Eric Andersen2870d962001-07-02 17:27:21 +0000123#include "cmdedit.h"
124
Eric Andersen2870d962001-07-02 17:27:21 +0000125/*
126 * This file was generated by the mksyntax program.
127 */
128
129/* Syntax classes */
130#define CWORD 0 /* character is nothing special */
131#define CNL 1 /* newline character */
132#define CBACK 2 /* a backslash character */
133#define CSQUOTE 3 /* single quote */
134#define CDQUOTE 4 /* double quote */
135#define CENDQUOTE 5 /* a terminating quote */
136#define CBQUOTE 6 /* backwards single quote */
137#define CVAR 7 /* a dollar sign */
138#define CENDVAR 8 /* a '}' character */
139#define CLP 9 /* a left paren in arithmetic */
140#define CRP 10 /* a right paren in arithmetic */
141#define CENDFILE 11 /* end of file */
142#define CCTL 12 /* like CWORD, except it must be escaped */
143#define CSPCL 13 /* these terminate a word */
144#define CIGN 14 /* character should be ignored */
145
Eric Andersen2870d962001-07-02 17:27:21 +0000146#define SYNBASE 130
147#define PEOF -130
148
149#define PEOA -129
150
151#define TEOF 0
152#define TNL 1
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000153#define TREDIR 2
154#define TWORD 3
155#define TASSIGN 4
156#define TSEMI 5
157#define TBACKGND 6
158#define TAND 7
159#define TOR 8
160#define TPIPE 9
161#define TLP 10
162#define TRP 11
163#define TENDCASE 12
164#define TENDBQUOTE 13
Eric Andersen2870d962001-07-02 17:27:21 +0000165#define TNOT 14
166#define TCASE 15
167#define TDO 16
168#define TDONE 17
169#define TELIF 18
170#define TELSE 19
171#define TESAC 20
172#define TFI 21
173#define TFOR 22
174#define TIF 23
175#define TIN 24
176#define TTHEN 25
177#define TUNTIL 26
178#define TWHILE 27
179#define TBEGIN 28
180#define TEND 29
181
182
Eric Andersen2870d962001-07-02 17:27:21 +0000183
184/* control characters in argument strings */
185#define CTLESC '\201'
186#define CTLVAR '\202'
187#define CTLENDVAR '\203'
188#define CTLBACKQ '\204'
189#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
190/* CTLBACKQ | CTLQUOTE == '\205' */
191#define CTLARI '\206'
192#define CTLENDARI '\207'
193#define CTLQUOTEMARK '\210'
194
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000195
Eric Andersen62483552001-07-10 06:09:16 +0000196#define is_digit(c) ((c)>='0' && (c)<='9')
Eric Andersen2870d962001-07-02 17:27:21 +0000197#define is_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalpha((unsigned char) (c))))
198#define is_in_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalnum((unsigned char) (c))))
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000199
200/*
201 * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
202 * (assuming ascii char codes, as the original implementation did)
203 */
204#define is_special(c) \
205 ( (((unsigned int)c) - 33 < 32) \
206 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
207
Eric Andersen2870d962001-07-02 17:27:21 +0000208#define digit_val(c) ((c) - '0')
Eric Andersencb57d552001-06-28 07:25:16 +0000209
210
211#define _DIAGASSERT(x)
212
Eric Andersen3102ac42001-07-06 04:26:23 +0000213
Eric Andersencb57d552001-06-28 07:25:16 +0000214
Eric Andersen2870d962001-07-02 17:27:21 +0000215#define S_DFL 1 /* default signal handling (SIG_DFL) */
216#define S_CATCH 2 /* signal is caught */
217#define S_IGN 3 /* signal is ignored (SIG_IGN) */
218#define S_HARD_IGN 4 /* signal is ignored permenantly */
219#define S_RESET 5 /* temporary - to reset a hard ignored sig */
Eric Andersencb57d552001-06-28 07:25:16 +0000220
221
Eric Andersen2870d962001-07-02 17:27:21 +0000222/* variable substitution byte (follows CTLVAR) */
223#define VSTYPE 0x0f /* type of variable substitution */
224#define VSNUL 0x10 /* colon--treat the empty string as unset */
225#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
Eric Andersencb57d552001-06-28 07:25:16 +0000226
Eric Andersen2870d962001-07-02 17:27:21 +0000227/* values of VSTYPE field */
228#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
229#define VSMINUS 0x2 /* ${var-text} */
230#define VSPLUS 0x3 /* ${var+text} */
231#define VSQUESTION 0x4 /* ${var?message} */
232#define VSASSIGN 0x5 /* ${var=text} */
233#define VSTRIMLEFT 0x6 /* ${var#pattern} */
234#define VSTRIMLEFTMAX 0x7 /* ${var##pattern} */
235#define VSTRIMRIGHT 0x8 /* ${var%pattern} */
236#define VSTRIMRIGHTMAX 0x9 /* ${var%%pattern} */
237#define VSLENGTH 0xa /* ${#var} */
Eric Andersencb57d552001-06-28 07:25:16 +0000238
Eric Andersen2870d962001-07-02 17:27:21 +0000239/* flags passed to redirect */
240#define REDIR_PUSH 01 /* save previous values of file descriptors */
Eric Andersen3102ac42001-07-06 04:26:23 +0000241#define REDIR_BACKQ 02 /* save the command output to pipe */
Eric Andersencb57d552001-06-28 07:25:16 +0000242
Eric Andersen2870d962001-07-02 17:27:21 +0000243/*
244 * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
245 * so we use _setjmp instead.
246 */
247
Eric Andersen62483552001-07-10 06:09:16 +0000248#if defined(BSD)
Eric Andersen2870d962001-07-02 17:27:21 +0000249#define setjmp(jmploc) _setjmp(jmploc)
250#define longjmp(jmploc, val) _longjmp(jmploc, val)
251#endif
252
253/*
254 * Most machines require the value returned from malloc to be aligned
255 * in some way. The following macro will get this right on many machines.
256 */
257
258#ifndef ALIGN
259union align {
260 int i;
261 char *cp;
262};
263
264#define ALIGN(nbytes) (((nbytes) + sizeof(union align) - 1) & ~(sizeof(union align) - 1))
265#endif
266
267#ifdef BB_LOCALE_SUPPORT
268#include <locale.h>
269static void change_lc_all(const char *value);
270static void change_lc_ctype(const char *value);
271#endif
272
273/*
274 * These macros allow the user to suspend the handling of interrupt signals
275 * over a period of time. This is similar to SIGHOLD to or sigblock, but
276 * much more efficient and portable. (But hacking the kernel is so much
277 * more fun than worrying about efficiency and portability. :-))
278 */
279
280static void onint (void);
281static volatile int suppressint;
282static volatile int intpending;
283
284#define INTOFF suppressint++
Eric Andersen3102ac42001-07-06 04:26:23 +0000285#ifndef ASH_OPTIMIZE_FOR_SIZE
Eric Andersen2870d962001-07-02 17:27:21 +0000286#define INTON { if (--suppressint == 0 && intpending) onint(); }
Eric Andersen3102ac42001-07-06 04:26:23 +0000287#define FORCEINTON {suppressint = 0; if (intpending) onint();}
Eric Andersen2870d962001-07-02 17:27:21 +0000288#else
289static void __inton (void);
Eric Andersen3102ac42001-07-06 04:26:23 +0000290static void forceinton (void);
Eric Andersen2870d962001-07-02 17:27:21 +0000291#define INTON __inton()
Eric Andersen3102ac42001-07-06 04:26:23 +0000292#define FORCEINTON forceinton()
Eric Andersen2870d962001-07-02 17:27:21 +0000293#endif
Eric Andersen3102ac42001-07-06 04:26:23 +0000294
Eric Andersen2870d962001-07-02 17:27:21 +0000295#define CLEAR_PENDING_INT intpending = 0
296#define int_pending() intpending
297
298
299typedef void *pointer;
300#ifndef NULL
301#define NULL (void *)0
302#endif
303
304static inline pointer ckmalloc (int sz) { return xmalloc(sz); }
305static inline pointer ckrealloc(void *p, int sz) { return xrealloc(p, sz); }
306static inline char * savestr (const char *s) { return xstrdup(s); }
307
308static pointer stalloc (int);
309static void stunalloc (pointer);
310static void ungrabstackstr (char *, char *);
311static char * growstackstr(void);
Eric Andersen3102ac42001-07-06 04:26:23 +0000312static char * makestrspace(size_t newlen);
Eric Andersen2870d962001-07-02 17:27:21 +0000313static char *sstrdup (const char *);
314
315/*
316 * Parse trees for commands are allocated in lifo order, so we use a stack
317 * to make this more efficient, and also to avoid all sorts of exception
318 * handling code to handle interrupts in the middle of a parse.
319 *
320 * The size 504 was chosen because the Ultrix malloc handles that size
321 * well.
322 */
323
324#define MINSIZE 504 /* minimum size of a block */
325
326
327struct stack_block {
328 struct stack_block *prev;
329 char space[MINSIZE];
330};
331
332static struct stack_block stackbase;
333static struct stack_block *stackp = &stackbase;
334static struct stackmark *markp;
335static char *stacknxt = stackbase.space;
336static int stacknleft = MINSIZE;
337
338
339#define equal(s1, s2) (strcmp(s1, s2) == 0)
340
341#define stackblock() stacknxt
342#define stackblocksize() stacknleft
343#define STARTSTACKSTR(p) p = stackblock(), sstrnleft = stackblocksize()
Eric Andersen3102ac42001-07-06 04:26:23 +0000344
Eric Andersen2870d962001-07-02 17:27:21 +0000345#define STPUTC(c, p) (--sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(), *p++ = (c)))
346#define CHECKSTRSPACE(n, p) { if (sstrnleft < n) p = makestrspace(n); }
Eric Andersen2870d962001-07-02 17:27:21 +0000347#define STACKSTRNUL(p) (sstrnleft == 0? (p = growstackstr(), *p = '\0') : (*p = '\0'))
Eric Andersen3102ac42001-07-06 04:26:23 +0000348
349
350#define USTPUTC(c, p) (--sstrnleft, *p++ = (c))
Eric Andersen2870d962001-07-02 17:27:21 +0000351#define STUNPUTC(p) (++sstrnleft, --p)
352#define STTOPC(p) p[-1]
353#define STADJUST(amount, p) (p += (amount), sstrnleft -= (amount))
354#define grabstackstr(p) stalloc(stackblocksize() - sstrnleft)
355
356#define ckfree(p) free((pointer)(p))
357
Eric Andersen2870d962001-07-02 17:27:21 +0000358
359#ifdef DEBUG
360#define TRACE(param) trace param
361static void trace (const char *, ...);
362static void trargs (char **);
363static void showtree (union node *);
364static void trputc (int);
365static void trputs (const char *);
366static void opentrace (void);
367#else
368#define TRACE(param)
369#endif
370
371#define NSEMI 0
372#define NCMD 1
373#define NPIPE 2
374#define NREDIR 3
375#define NBACKGND 4
376#define NSUBSHELL 5
377#define NAND 6
378#define NOR 7
379#define NIF 8
380#define NWHILE 9
381#define NUNTIL 10
382#define NFOR 11
383#define NCASE 12
384#define NCLIST 13
385#define NDEFUN 14
386#define NARG 15
387#define NTO 16
388#define NFROM 17
389#define NFROMTO 18
390#define NAPPEND 19
391#define NTOOV 20
392#define NTOFD 21
393#define NFROMFD 22
394#define NHERE 23
395#define NXHERE 24
396#define NNOT 25
397
398/*
399 * expandarg() flags
400 */
401#define EXP_FULL 0x1 /* perform word splitting & file globbing */
402#define EXP_TILDE 0x2 /* do normal tilde expansion */
403#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
404#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
405#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
406#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
407
408
409#define NOPTS 16
410
411static char optet_vals[NOPTS];
412
413static const char * const optlist[NOPTS] = {
414 "e" "errexit",
415 "f" "noglob",
416 "I" "ignoreeof",
417 "i" "interactive",
418 "m" "monitor",
419 "n" "noexec",
420 "s" "stdin",
421 "x" "xtrace",
422 "v" "verbose",
423 "V" "vi",
424 "E" "emacs",
425 "C" "noclobber",
426 "a" "allexport",
427 "b" "notify",
428 "u" "nounset",
429 "q" "quietprofile"
430};
431
432#define optent_name(optent) (optent+1)
433#define optent_letter(optent) optent[0]
434#define optent_val(optent) optet_vals[optent]
435
436#define eflag optent_val(0)
437#define fflag optent_val(1)
438#define Iflag optent_val(2)
439#define iflag optent_val(3)
440#define mflag optent_val(4)
441#define nflag optent_val(5)
442#define sflag optent_val(6)
443#define xflag optent_val(7)
444#define vflag optent_val(8)
445#define Vflag optent_val(9)
446#define Eflag optent_val(10)
447#define Cflag optent_val(11)
448#define aflag optent_val(12)
449#define bflag optent_val(13)
450#define uflag optent_val(14)
451#define qflag optent_val(15)
452
453
454/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
455#define FORK_FG 0
456#define FORK_BG 1
457#define FORK_NOJOB 2
458
459
460struct nbinary {
461 int type;
462 union node *ch1;
463 union node *ch2;
464};
465
466
467struct ncmd {
468 int type;
469 int backgnd;
470 union node *assign;
471 union node *args;
472 union node *redirect;
473};
474
475
476struct npipe {
477 int type;
478 int backgnd;
479 struct nodelist *cmdlist;
480};
481
482
483struct nredir {
484 int type;
485 union node *n;
486 union node *redirect;
487};
488
489
490struct nif {
491 int type;
492 union node *test;
493 union node *ifpart;
494 union node *elsepart;
495};
496
497
498struct nfor {
499 int type;
500 union node *args;
501 union node *body;
502 char *var;
503};
504
505
506struct ncase {
507 int type;
508 union node *expr;
509 union node *cases;
510};
511
512
513struct nclist {
514 int type;
515 union node *next;
516 union node *pattern;
517 union node *body;
518};
519
520
521struct narg {
522 int type;
523 union node *next;
524 char *text;
525 struct nodelist *backquote;
526};
527
528
529struct nfile {
530 int type;
531 union node *next;
532 int fd;
533 union node *fname;
534 char *expfname;
535};
536
537
538struct ndup {
539 int type;
540 union node *next;
541 int fd;
542 int dupfd;
543 union node *vname;
544};
545
546
547struct nhere {
548 int type;
549 union node *next;
550 int fd;
551 union node *doc;
552};
553
554
555struct nnot {
556 int type;
557 union node *com;
558};
559
560
561union node {
562 int type;
563 struct nbinary nbinary;
564 struct ncmd ncmd;
565 struct npipe npipe;
566 struct nredir nredir;
567 struct nif nif;
568 struct nfor nfor;
569 struct ncase ncase;
570 struct nclist nclist;
571 struct narg narg;
572 struct nfile nfile;
573 struct ndup ndup;
574 struct nhere nhere;
575 struct nnot nnot;
576};
577
578
579struct nodelist {
580 struct nodelist *next;
581 union node *n;
582};
583
584struct backcmd { /* result of evalbackcmd */
585 int fd; /* file descriptor to read from */
586 char *buf; /* buffer */
587 int nleft; /* number of chars in buffer */
588 struct job *jp; /* job structure for command */
589};
590
591struct cmdentry {
592 int cmdtype;
593 union param {
594 int index;
595 union node *func;
596 const struct builtincmd *cmd;
597 } u;
598};
599
600struct strlist {
601 struct strlist *next;
602 char *text;
603};
604
605
606struct arglist {
607 struct strlist *list;
608 struct strlist **lastp;
609};
610
611struct strpush {
612 struct strpush *prev; /* preceding string on stack */
613 char *prevstring;
614 int prevnleft;
615#ifdef ASH_ALIAS
616 struct alias *ap; /* if push was associated with an alias */
617#endif
618 char *string; /* remember the string since it may change */
619};
620
621struct parsefile {
622 struct parsefile *prev; /* preceding file on stack */
623 int linno; /* current line */
624 int fd; /* file descriptor (or -1 if string) */
625 int nleft; /* number of chars left in this line */
626 int lleft; /* number of chars left in this buffer */
627 char *nextc; /* next char in buffer */
628 char *buf; /* input buffer */
629 struct strpush *strpush; /* for pushing strings at this level */
630 struct strpush basestrpush; /* so pushing one is fast */
631};
632
633struct stackmark {
634 struct stack_block *stackp;
635 char *stacknxt;
636 int stacknleft;
637 struct stackmark *marknext;
638};
639
640struct shparam {
641 int nparam; /* # of positional parameters (without $0) */
642 unsigned char malloc; /* if parameter list dynamically allocated */
643 char **p; /* parameter list */
644 int optind; /* next parameter to be processed by getopts */
645 int optoff; /* used by getopts */
646};
647
Eric Andersen62483552001-07-10 06:09:16 +0000648/*
649 * When commands are first encountered, they are entered in a hash table.
650 * This ensures that a full path search will not have to be done for them
651 * on each invocation.
652 *
653 * We should investigate converting to a linear search, even though that
654 * would make the command name "hash" a misnomer.
655 */
656#define CMDTABLESIZE 31 /* should be prime */
657#define ARB 1 /* actual size determined at run time */
658
659
660
661struct tblentry {
662 struct tblentry *next; /* next entry in hash chain */
663 union param param; /* definition of builtin function */
664 short cmdtype; /* index identifying command */
665 char rehash; /* if set, cd done since entry created */
666 char cmdname[ARB]; /* name of command */
667};
668
669
670static struct tblentry *cmdtable[CMDTABLESIZE];
671static int builtinloc = -1; /* index in path of %builtin, or -1 */
672static int exerrno = 0; /* Last exec error */
673
674
675static void tryexec (char *, char **, char **);
676static void printentry (struct tblentry *, int);
677static void clearcmdentry (int);
678static struct tblentry *cmdlookup (const char *, int);
679static void delete_cmd_entry (void);
680static int path_change (const char *, int *);
681
682
Eric Andersen2870d962001-07-02 17:27:21 +0000683static void flushall (void);
Eric Andersen3102ac42001-07-06 04:26:23 +0000684static void out2fmt (const char *, ...)
685 __attribute__((__format__(__printf__,1,2)));
Eric Andersen2870d962001-07-02 17:27:21 +0000686static int xwrite (int, const char *, int);
Eric Andersen2870d962001-07-02 17:27:21 +0000687
Manuel Novoa III c639a352001-08-12 17:32:56 +0000688static inline void outstr (const char *p, FILE *file) { fputs(p, file); }
Eric Andersen3102ac42001-07-06 04:26:23 +0000689static void out1str(const char *p) { outstr(p, stdout); }
690static void out2str(const char *p) { outstr(p, stderr); }
Eric Andersen2870d962001-07-02 17:27:21 +0000691
Eric Andersen62483552001-07-10 06:09:16 +0000692#ifndef ASH_OPTIMIZE_FOR_SIZE
Eric Andersen3102ac42001-07-06 04:26:23 +0000693#define out2c(c) putc((c), stderr)
Eric Andersen62483552001-07-10 06:09:16 +0000694#else
695static void out2c(int c) { putc(c, stderr); }
696#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000697
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000698
699#ifdef ASH_OPTIMIZE_FOR_SIZE
700#define USE_SIT_FUNCTION
701#endif
702
703/* number syntax index */
704#define BASESYNTAX 0 /* not in quotes */
705#define DQSYNTAX 1 /* in double quotes */
706#define SQSYNTAX 2 /* in single quotes */
707#define ARISYNTAX 3 /* in arithmetic */
708
709static const char S_I_T[][4] = {
710 /* 0 */ { CSPCL, CIGN, CIGN, CIGN }, /* PEOA */
711 /* 1 */ { CSPCL, CWORD, CWORD, CWORD }, /* ' ' */
712 /* 2 */ { CNL, CNL, CNL, CNL }, /* \n */
713 /* 3 */ { CWORD, CCTL, CCTL, CWORD }, /* !*-/:=?[]~ */
714 /* 4 */ { CDQUOTE, CENDQUOTE, CWORD, CDQUOTE }, /* '"' */
715 /* 5 */ { CVAR, CVAR, CWORD, CVAR }, /* $ */
716 /* 6 */ { CSQUOTE, CWORD, CENDQUOTE, CSQUOTE }, /* "'" */
717 /* 7 */ { CSPCL, CWORD, CWORD, CLP }, /* ( */
718 /* 8 */ { CSPCL, CWORD, CWORD, CRP }, /* ) */
719 /* 9 */ { CBACK, CBACK, CCTL, CBACK }, /* \ */
720 /* 10 */ { CBQUOTE, CBQUOTE, CWORD, CBQUOTE }, /* ` */
721 /* 11 */ { CENDVAR, CENDVAR, CWORD, CENDVAR }, /* } */
722#ifndef USE_SIT_FUNCTION
723 /* 12 */ { CENDFILE, CENDFILE, CENDFILE, CENDFILE }, /* PEOF */
724 /* 13 */ { CWORD, CWORD, CWORD, CWORD }, /* 0-9A-Za-z */
725 /* 14 */ { CCTL, CCTL, CCTL, CCTL } /* CTLESC ... */
726#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000727};
728
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000729#ifdef USE_SIT_FUNCTION
730
731#define U_C(c) ((unsigned char)(c))
732
733static int SIT(int c, int syntax)
734{
735 static const char spec_symbls[]="\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
736 static const char syntax_index_table [] = {
737 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
738 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
739 3, 1, 3, 3, 9, 3,10, 1, /* "=>?[\\]`|" */
740 11,3 }; /* "}~" */
741 const char *s;
742 int indx;
743
744 if(c==PEOF) /* 2^8+2 */
745 return CENDFILE;
746 if(c==PEOA) /* 2^8+1 */
747 indx = 0;
748 else if(U_C(c)>=U_C(CTLESC) && U_C(c)<=U_C(CTLQUOTEMARK))
749 return CCTL;
750 else {
751 s = strchr(spec_symbls, c);
752 if(s==0)
753 return CWORD;
754 indx = syntax_index_table[(s-spec_symbls)];
755 }
756 return S_I_T[indx][syntax];
757}
758
759#else /* USE_SIT_FUNCTION */
760
761#define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
762
763#define CSPCL_CIGN_CIGN_CIGN 0
764#define CSPCL_CWORD_CWORD_CWORD 1
765#define CNL_CNL_CNL_CNL 2
766#define CWORD_CCTL_CCTL_CWORD 3
767#define CDQUOTE_CENDQUOTE_CWORD_CDQUOTE 4
768#define CVAR_CVAR_CWORD_CVAR 5
769#define CSQUOTE_CWORD_CENDQUOTE_CSQUOTE 6
770#define CSPCL_CWORD_CWORD_CLP 7
771#define CSPCL_CWORD_CWORD_CRP 8
772#define CBACK_CBACK_CCTL_CBACK 9
773#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
774#define CENDVAR_CENDVAR_CWORD_CENDVAR 11
775#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
776#define CWORD_CWORD_CWORD_CWORD 13
777#define CCTL_CCTL_CCTL_CCTL 14
778
779static const char syntax_index_table[258] = {
780 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
781 /* 0 -130 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
782 /* 1 -129 PEOA */ CSPCL_CIGN_CIGN_CIGN,
783 /* 2 -128 0xff */ CWORD_CWORD_CWORD_CWORD,
784 /* 3 -127 */ CCTL_CCTL_CCTL_CCTL, /* CTLQUOTEMARK */
785 /* 4 -126 */ CCTL_CCTL_CCTL_CCTL,
786 /* 5 -125 */ CCTL_CCTL_CCTL_CCTL,
787 /* 6 -124 */ CCTL_CCTL_CCTL_CCTL,
788 /* 7 -123 */ CCTL_CCTL_CCTL_CCTL,
789 /* 8 -122 */ CCTL_CCTL_CCTL_CCTL,
790 /* 9 -121 */ CCTL_CCTL_CCTL_CCTL,
791 /* 10 -120 */ CCTL_CCTL_CCTL_CCTL, /* CTLESC */
792 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
793 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
794 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
795 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
796 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
797 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
798 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
799 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
800 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
801 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
802 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
803 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
804 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
805 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
806 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
807 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
808 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
809 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
810 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
811 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
812 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
813 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
814 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
815 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
816 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
817 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
818 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
819 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
820 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
821 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
822 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
823 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
824 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
825 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
826 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
827 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
828 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
829 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
830 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
831 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
832 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
833 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
834 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
835 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
836 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
837 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
838 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
839 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
840 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
841 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
842 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
843 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
844 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
845 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
846 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
847 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
848 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
849 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
850 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
851 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
852 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
853 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
854 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
855 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
856 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
857 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
858 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
859 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
860 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
861 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
862 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
863 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
864 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
865 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
866 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
867 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
868 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
869 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
870 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
871 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
872 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
873 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
874 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
875 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
876 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
877 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
878 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
879 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
880 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
881 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
882 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
883 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
884 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
885 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
886 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
887 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
888 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
889 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
890 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
891 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
892 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
893 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
894 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
895 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
896 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
897 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
898 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
899 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
900 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
901 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
902 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
903 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
904 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
905 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
906 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
907 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
908 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
909 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
910 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
911 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
912 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
913 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
914 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
915 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
916 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
917 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
918 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
919 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
920 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
921 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
922 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
923 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
924 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
925 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
926 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
927 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
928 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
929 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
930 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
931 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
932 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
933 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
934 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
935 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
936 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
937 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
938 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
939 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
940 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
941 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
942 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
943 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
944 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
945 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CDQUOTE,
946 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
947 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
948 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
949 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
950 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CSQUOTE,
951 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
952 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
953 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
954 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
955 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
956 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
957 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
958 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
959 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
960 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
961 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
962 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
963 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
964 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
965 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
966 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
967 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
968 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
969 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
970 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
971 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
972 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
973 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
974 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
975 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
976 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
977 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
978 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
979 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
980 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
981 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
982 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
983 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
984 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
985 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
986 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
987 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
988 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
989 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
990 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
991 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
992 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
993 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
994 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
995 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
996 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
997 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
998 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
999 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
1000 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
1001 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
1002 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
1003 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
1004 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
1005 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
1006 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
1007 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
1008 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
1009 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
1010 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
1011 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
1012 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
1013 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
1014 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
1015 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
1016 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
1017 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
1018 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
1019 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
1020 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
1021 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
1022 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
1023 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
1024 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
1025 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
1026 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
1027 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
1028 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
1029 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
1030 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
1031 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
1032 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
1033 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
1034 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
1035 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
1036 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
1037 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
1038 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
Eric Andersen2870d962001-07-02 17:27:21 +00001039};
1040
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001041#endif /* USE_SIT_FUNCTION */
Eric Andersen2870d962001-07-02 17:27:21 +00001042
Eric Andersen2870d962001-07-02 17:27:21 +00001043
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001044/* first char is indicating which tokens mark the end of a list */
1045static const char *const tokname_array[] = {
1046 "\1end of file",
1047 "\0newline",
1048 "\0redirection",
1049 "\0word",
1050 "\0assignment",
1051 "\0;",
1052 "\0&",
1053 "\0&&",
1054 "\0||",
1055 "\0|",
1056 "\0(",
1057 "\1)",
1058 "\1;;",
1059 "\1`",
Eric Andersen2870d962001-07-02 17:27:21 +00001060#define KWDOFFSET 14
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001061 /* the following are keywords */
1062 "\0!",
1063 "\0case",
1064 "\1do",
1065 "\1done",
1066 "\1elif",
1067 "\1else",
1068 "\1esac",
1069 "\1fi",
1070 "\0for",
1071 "\0if",
1072 "\0in",
1073 "\1then",
1074 "\0until",
1075 "\0while",
1076 "\0{",
1077 "\1}",
Eric Andersen2870d962001-07-02 17:27:21 +00001078};
1079
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001080static const char *tokname(int tok)
1081{
1082 static char buf[16];
1083
1084 if(tok>=TSEMI)
1085 buf[0] = '"';
1086 sprintf(buf+(tok>=TSEMI), "%s%c",
1087 tokname_array[tok]+1, (tok>=TSEMI ? '"' : 0));
1088 return buf;
1089}
Eric Andersen2870d962001-07-02 17:27:21 +00001090
1091static int plinno = 1; /* input line number */
1092
1093static int parselleft; /* copy of parsefile->lleft */
1094
1095static struct parsefile basepf; /* top level input file */
1096static char basebuf[BUFSIZ]; /* buffer for top level input file */
1097static struct parsefile *parsefile = &basepf; /* current input file */
1098
1099/*
1100 * NEOF is returned by parsecmd when it encounters an end of file. It
1101 * must be distinct from NULL, so we use the address of a variable that
1102 * happens to be handy.
1103 */
1104
1105static int tokpushback; /* last token pushed back */
1106#define NEOF ((union node *)&tokpushback)
1107static int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */
1108
1109
1110static void error (const char *, ...) __attribute__((__noreturn__));
1111static void exerror (int, const char *, ...) __attribute__((__noreturn__));
1112static void shellexec (char **, char **, const char *, int)
1113 __attribute__((noreturn));
1114static void exitshell (int) __attribute__((noreturn));
1115
1116static int goodname(const char *);
1117static void ignoresig (int);
1118static void onsig (int);
1119static void dotrap (void);
1120static int decode_signal (const char *, int);
1121
1122static void shprocvar(void);
1123static void deletefuncs(void);
1124static void setparam (char **);
1125static void freeparam (volatile struct shparam *);
1126
1127/* reasons for skipping commands (see comment on breakcmd routine) */
1128#define SKIPBREAK 1
1129#define SKIPCONT 2
1130#define SKIPFUNC 3
1131#define SKIPFILE 4
1132
1133/* values of cmdtype */
1134#define CMDUNKNOWN -1 /* no entry in table for command */
1135#define CMDNORMAL 0 /* command is an executable program */
1136#define CMDBUILTIN 1 /* command is a shell builtin */
1137#define CMDFUNCTION 2 /* command is a shell function */
1138
1139#define DO_ERR 1 /* find_command prints errors */
1140#define DO_ABS 2 /* find_command checks absolute paths */
1141#define DO_NOFUN 4 /* find_command ignores functions */
1142#define DO_BRUTE 8 /* find_command ignores hash table */
1143
1144/*
1145 * Shell variables.
1146 */
1147
1148/* flags */
1149#define VEXPORT 0x01 /* variable is exported */
1150#define VREADONLY 0x02 /* variable cannot be modified */
1151#define VSTRFIXED 0x04 /* variable struct is staticly allocated */
1152#define VTEXTFIXED 0x08 /* text is staticly allocated */
1153#define VSTACK 0x10 /* text is allocated on the stack */
1154#define VUNSET 0x20 /* the variable is not set */
1155#define VNOFUNC 0x40 /* don't call the callback function */
1156
1157
1158struct var {
1159 struct var *next; /* next entry in hash list */
1160 int flags; /* flags are defined above */
1161 char *text; /* name=value */
1162 void (*func) (const char *);
1163 /* function to be called when */
1164 /* the variable gets set/unset */
1165};
1166
1167struct localvar {
1168 struct localvar *next; /* next local variable in list */
1169 struct var *vp; /* the variable that was made local */
1170 int flags; /* saved flags */
1171 char *text; /* saved text */
1172};
1173
1174
Eric Andersen62483552001-07-10 06:09:16 +00001175#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00001176#define rmescapes(p) _rmescapes((p), 0)
1177static char *_rmescapes (char *, int);
1178#else
1179static void rmescapes (char *);
1180#endif
1181
1182static int casematch (union node *, const char *);
1183static void clearredir(void);
1184static void popstring(void);
1185static void readcmdfile (const char *);
1186
1187static int number (const char *);
1188static int is_number (const char *, int *num);
1189static char *single_quote (const char *);
1190static int nextopt (const char *);
1191
1192static void redirect (union node *, int);
1193static void popredir (void);
1194static int dup_as_newfd (int, int);
1195
1196static void changepath(const char *newval);
1197static void getoptsreset(const char *value);
1198
1199
1200static int parsenleft; /* copy of parsefile->nleft */
1201static char *parsenextc; /* copy of parsefile->nextc */
1202static int rootpid; /* pid of main shell */
1203static int rootshell; /* true if we aren't a child of the main shell */
1204
1205static const char spcstr[] = " ";
1206static const char snlfmt[] = "%s\n";
1207
1208static int sstrnleft;
1209static int herefd = -1;
1210
1211static struct localvar *localvars;
1212
1213static struct var vifs;
1214static struct var vmail;
1215static struct var vmpath;
1216static struct var vpath;
1217static struct var vps1;
1218static struct var vps2;
1219static struct var voptind;
1220#ifdef BB_LOCALE_SUPPORT
1221static struct var vlc_all;
1222static struct var vlc_ctype;
1223#endif
1224
1225struct varinit {
1226 struct var *var;
1227 int flags;
1228 const char *text;
1229 void (*func) (const char *);
1230};
1231
1232static const char defpathvar[] =
1233 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
1234#define defpath (defpathvar + 5)
1235
1236#ifdef IFS_BROKEN
1237static const char defifsvar[] = "IFS= \t\n";
1238#define defifs (defifsvar + 4)
1239#else
1240static const char defifs[] = " \t\n";
1241#endif
1242
1243static const struct varinit varinit[] = {
1244#ifdef IFS_BROKEN
1245 { &vifs, VSTRFIXED|VTEXTFIXED, defifsvar,
1246#else
1247 { &vifs, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS=",
1248#endif
1249 NULL },
1250 { &vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=",
1251 NULL },
1252 { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=",
1253 NULL },
1254 { &vpath, VSTRFIXED|VTEXTFIXED, defpathvar,
1255 changepath },
1256 /*
1257 * vps1 depends on uid
1258 */
1259 { &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ",
1260 NULL },
1261 { &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1",
1262 getoptsreset },
1263#ifdef BB_LOCALE_SUPPORT
1264 { &vlc_all, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL=",
1265 change_lc_all },
1266 { &vlc_ctype, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE=",
1267 change_lc_ctype },
1268#endif
1269 { NULL, 0, NULL,
1270 NULL }
1271};
1272
1273#define VTABSIZE 39
1274
1275static struct var *vartab[VTABSIZE];
1276
1277/*
1278 * The following macros access the values of the above variables.
1279 * They have to skip over the name. They return the null string
1280 * for unset variables.
1281 */
1282
1283#define ifsval() (vifs.text + 4)
1284#define ifsset() ((vifs.flags & VUNSET) == 0)
1285#define mailval() (vmail.text + 5)
1286#define mpathval() (vmpath.text + 9)
1287#define pathval() (vpath.text + 5)
1288#define ps1val() (vps1.text + 4)
1289#define ps2val() (vps2.text + 4)
1290#define optindval() (voptind.text + 7)
1291
1292#define mpathset() ((vmpath.flags & VUNSET) == 0)
1293
1294static void initvar (void);
1295static void setvar (const char *, const char *, int);
1296static void setvareq (char *, int);
1297static void listsetvar (struct strlist *);
Eric Andersen62483552001-07-10 06:09:16 +00001298static const char *lookupvar (const char *);
1299static const char *bltinlookup (const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001300static char **environment (void);
1301static int showvarscmd (int, char **);
1302static void mklocal (char *);
1303static void poplocalvars (void);
1304static int unsetvar (const char *);
1305static int varequal (const char *, const char *);
1306
1307
1308static char *arg0; /* value of $0 */
1309static struct shparam shellparam; /* current positional parameters */
1310static char **argptr; /* argument list for builtin commands */
1311static char *optionarg; /* set by nextopt (like getopt) */
1312static char *optptr; /* used by nextopt */
1313static char *minusc; /* argument to -c option */
1314
1315
1316#ifdef ASH_ALIAS
1317
1318#define ALIASINUSE 1
1319#define ALIASDEAD 2
1320
Eric Andersen3102ac42001-07-06 04:26:23 +00001321#define ATABSIZE 39
1322
Eric Andersen2870d962001-07-02 17:27:21 +00001323struct alias {
1324 struct alias *next;
1325 char *name;
1326 char *val;
1327 int flag;
1328};
1329
1330static struct alias *atab[ATABSIZE];
1331
1332static void setalias (char *, char *);
1333static struct alias **hashalias (const char *);
1334static struct alias *freealias (struct alias *);
1335static struct alias **__lookupalias (const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00001336
1337static void
1338setalias(name, val)
1339 char *name, *val;
1340{
1341 struct alias *ap, **app;
1342
1343 app = __lookupalias(name);
1344 ap = *app;
1345 INTOFF;
1346 if (ap) {
1347 if (!(ap->flag & ALIASINUSE)) {
1348 ckfree(ap->val);
1349 }
Eric Andersen2870d962001-07-02 17:27:21 +00001350 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00001351 ap->flag &= ~ALIASDEAD;
1352 } else {
1353 /* not found */
1354 ap = ckmalloc(sizeof (struct alias));
1355 ap->name = savestr(name);
1356 ap->val = savestr(val);
1357 ap->flag = 0;
1358 ap->next = 0;
1359 *app = ap;
1360 }
1361 INTON;
1362}
1363
1364static int
Eric Andersen2870d962001-07-02 17:27:21 +00001365unalias(char *name)
1366{
Eric Andersencb57d552001-06-28 07:25:16 +00001367 struct alias **app;
1368
1369 app = __lookupalias(name);
1370
1371 if (*app) {
1372 INTOFF;
1373 *app = freealias(*app);
1374 INTON;
1375 return (0);
1376 }
1377
1378 return (1);
1379}
1380
Eric Andersencb57d552001-06-28 07:25:16 +00001381static void
Eric Andersen2870d962001-07-02 17:27:21 +00001382rmaliases(void)
1383{
Eric Andersencb57d552001-06-28 07:25:16 +00001384 struct alias *ap, **app;
1385 int i;
1386
1387 INTOFF;
1388 for (i = 0; i < ATABSIZE; i++) {
1389 app = &atab[i];
1390 for (ap = *app; ap; ap = *app) {
1391 *app = freealias(*app);
1392 if (ap == *app) {
1393 app = &ap->next;
1394 }
1395 }
1396 }
1397 INTON;
1398}
1399
Eric Andersen2870d962001-07-02 17:27:21 +00001400static struct alias *
1401lookupalias(const char *name, int check)
Eric Andersencb57d552001-06-28 07:25:16 +00001402{
1403 struct alias *ap = *__lookupalias(name);
1404
1405 if (check && ap && (ap->flag & ALIASINUSE))
1406 return (NULL);
1407 return (ap);
1408}
1409
Eric Andersen2870d962001-07-02 17:27:21 +00001410static void
1411printalias(const struct alias *ap) {
1412 char *p;
1413
1414 p = single_quote(ap->val);
Eric Andersen62483552001-07-10 06:09:16 +00001415 printf("alias %s=%s\n", ap->name, p);
Eric Andersen2870d962001-07-02 17:27:21 +00001416 stunalloc(p);
1417}
1418
Eric Andersencb57d552001-06-28 07:25:16 +00001419
1420/*
1421 * TODO - sort output
1422 */
1423static int
Eric Andersen2870d962001-07-02 17:27:21 +00001424aliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001425{
1426 char *n, *v;
1427 int ret = 0;
1428 struct alias *ap;
1429
1430 if (argc == 1) {
1431 int i;
1432
1433 for (i = 0; i < ATABSIZE; i++)
1434 for (ap = atab[i]; ap; ap = ap->next) {
1435 printalias(ap);
1436 }
1437 return (0);
1438 }
1439 while ((n = *++argv) != NULL) {
1440 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
1441 if ((ap = *__lookupalias(n)) == NULL) {
Eric Andersen3102ac42001-07-06 04:26:23 +00001442 out2fmt("%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00001443 ret = 1;
1444 } else
1445 printalias(ap);
1446 }
1447 else {
1448 *v++ = '\0';
1449 setalias(n, v);
1450 }
1451 }
1452
1453 return (ret);
1454}
1455
1456static int
Eric Andersen2870d962001-07-02 17:27:21 +00001457unaliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001458{
1459 int i;
1460
1461 while ((i = nextopt("a")) != '\0') {
1462 if (i == 'a') {
1463 rmaliases();
1464 return (0);
1465 }
1466 }
1467 for (i = 0; *argptr; argptr++) {
1468 if (unalias(*argptr)) {
Eric Andersen3102ac42001-07-06 04:26:23 +00001469 out2fmt("%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00001470 i = 1;
1471 }
1472 }
1473
1474 return (i);
1475}
1476
1477static struct alias **
1478hashalias(p)
1479 const char *p;
1480 {
1481 unsigned int hashval;
1482
1483 hashval = *p << 4;
1484 while (*p)
1485 hashval+= *p++;
1486 return &atab[hashval % ATABSIZE];
1487}
1488
1489static struct alias *
1490freealias(struct alias *ap) {
1491 struct alias *next;
1492
1493 if (ap->flag & ALIASINUSE) {
1494 ap->flag |= ALIASDEAD;
1495 return ap;
1496 }
1497
1498 next = ap->next;
1499 ckfree(ap->name);
1500 ckfree(ap->val);
1501 ckfree(ap);
1502 return next;
1503}
1504
Eric Andersencb57d552001-06-28 07:25:16 +00001505
1506static struct alias **
1507__lookupalias(const char *name) {
1508 struct alias **app = hashalias(name);
1509
1510 for (; *app; app = &(*app)->next) {
1511 if (equal(name, (*app)->name)) {
1512 break;
1513 }
1514 }
1515
1516 return app;
1517}
Eric Andersen2870d962001-07-02 17:27:21 +00001518#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001519
1520#ifdef ASH_MATH_SUPPORT
Eric Andersen74bcd162001-07-30 21:41:37 +00001521/* The generated file arith.c has been replaced with a custom hand
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001522 * written implementation written by Aaron Lehmann <aaronl@vitelus.com>.
1523 * This is now part of libbb, so that it can be used by all the shells
Eric Andersen74bcd162001-07-30 21:41:37 +00001524 * in busybox. */
Eric Andersen2870d962001-07-02 17:27:21 +00001525#define ARITH_NUM 257
1526#define ARITH_LPAREN 258
1527#define ARITH_RPAREN 259
1528#define ARITH_OR 260
1529#define ARITH_AND 261
1530#define ARITH_BOR 262
1531#define ARITH_BXOR 263
1532#define ARITH_BAND 264
1533#define ARITH_EQ 265
1534#define ARITH_NE 266
1535#define ARITH_LT 267
1536#define ARITH_GT 268
1537#define ARITH_GE 269
1538#define ARITH_LE 270
1539#define ARITH_LSHIFT 271
1540#define ARITH_RSHIFT 272
1541#define ARITH_ADD 273
1542#define ARITH_SUB 274
1543#define ARITH_MUL 275
1544#define ARITH_DIV 276
1545#define ARITH_REM 277
1546#define ARITH_UNARYMINUS 278
1547#define ARITH_UNARYPLUS 279
1548#define ARITH_NOT 280
1549#define ARITH_BNOT 281
1550
1551static void expari (int);
Eric Andersencb57d552001-06-28 07:25:16 +00001552#endif
1553
Eric Andersen2870d962001-07-02 17:27:21 +00001554static char *trap[NSIG]; /* trap handler commands */
1555static char sigmode[NSIG - 1]; /* current value of signal */
1556static char gotsig[NSIG - 1]; /* indicates specified signal received */
1557static int pendingsigs; /* indicates some signal received */
1558
Eric Andersencb57d552001-06-28 07:25:16 +00001559/*
1560 * This file was generated by the mkbuiltins program.
1561 */
1562
Eric Andersen2870d962001-07-02 17:27:21 +00001563#ifdef JOBS
1564static int bgcmd (int, char **);
1565static int fgcmd (int, char **);
1566static int killcmd (int, char **);
1567#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001568static int bltincmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001569static int cdcmd (int, char **);
1570static int breakcmd (int, char **);
1571#ifdef ASH_CMDCMD
1572static int commandcmd (int, char **);
1573#endif
1574static int dotcmd (int, char **);
1575static int evalcmd (int, char **);
1576static int execcmd (int, char **);
1577static int exitcmd (int, char **);
1578static int exportcmd (int, char **);
1579static int histcmd (int, char **);
1580static int hashcmd (int, char **);
Eric Andersen1c039232001-07-07 00:05:55 +00001581static int helpcmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001582static int jobscmd (int, char **);
1583static int localcmd (int, char **);
Eric Andersen3102ac42001-07-06 04:26:23 +00001584#ifndef BB_PWD
Eric Andersen2870d962001-07-02 17:27:21 +00001585static int pwdcmd (int, char **);
1586#endif
1587static int readcmd (int, char **);
1588static int returncmd (int, char **);
1589static int setcmd (int, char **);
1590static int setvarcmd (int, char **);
1591static int shiftcmd (int, char **);
1592static int trapcmd (int, char **);
1593static int umaskcmd (int, char **);
1594#ifdef ASH_ALIAS
1595static int aliascmd (int, char **);
1596static int unaliascmd (int, char **);
1597#endif
1598static int unsetcmd (int, char **);
1599static int waitcmd (int, char **);
1600static int ulimitcmd (int, char **);
1601static int timescmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001602#ifdef ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +00001603static int letcmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001604#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001605static int typecmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001606#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00001607static int getoptscmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001608#endif
1609
Eric Andersen2870d962001-07-02 17:27:21 +00001610#ifndef BB_TRUE_FALSE
Eric Andersen2870d962001-07-02 17:27:21 +00001611static int true_main (int, char **);
1612static int false_main (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001613#endif
1614
1615static void setpwd (const char *, int);
1616
1617
1618#define BUILTIN_NOSPEC "0"
1619#define BUILTIN_SPECIAL "1"
1620#define BUILTIN_REGULAR "2"
1621#define BUILTIN_ASSIGN "4"
1622#define BUILTIN_SPEC_ASSG "5"
1623#define BUILTIN_REG_ASSG "6"
1624
1625#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1626#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1627#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
1628
1629struct builtincmd {
1630 const char *name;
1631 int (*const builtinfunc) (int, char **);
1632 //unsigned flags;
1633};
1634
Eric Andersencb57d552001-06-28 07:25:16 +00001635
1636/* It is CRUCIAL that this listing be kept in ascii order, otherwise
1637 * the binary search in find_builtin() will stop working. If you value
1638 * your kneecaps, you'll be sure to *make sure* that any changes made
1639 * to this array result in the listing remaining in ascii order. You
1640 * have been warned.
1641 */
1642static const struct builtincmd builtincmds[] = {
Eric Andersen62483552001-07-10 06:09:16 +00001643 { BUILTIN_SPECIAL ".", dotcmd }, /* first, see declare DOTCMD */
Eric Andersen2870d962001-07-02 17:27:21 +00001644 { BUILTIN_SPECIAL ":", true_main },
1645#ifdef ASH_ALIAS
1646 { BUILTIN_REG_ASSG "alias", aliascmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001647#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001648#ifdef JOBS
1649 { BUILTIN_REGULAR "bg", bgcmd },
1650#endif
1651 { BUILTIN_SPECIAL "break", breakcmd },
Eric Andersen3102ac42001-07-06 04:26:23 +00001652 { BUILTIN_SPECIAL "builtin", bltincmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001653 { BUILTIN_REGULAR "cd", cdcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001654 { BUILTIN_NOSPEC "chdir", cdcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001655#ifdef ASH_CMDCMD
1656 { BUILTIN_REGULAR "command", commandcmd },
1657#endif
1658 { BUILTIN_SPECIAL "continue", breakcmd },
1659 { BUILTIN_SPECIAL "eval", evalcmd },
1660 { BUILTIN_SPECIAL "exec", execcmd },
1661 { BUILTIN_SPECIAL "exit", exitcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001662 { BUILTIN_SPEC_ASSG "export", exportcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001663 { BUILTIN_REGULAR "false", false_main },
Eric Andersen2870d962001-07-02 17:27:21 +00001664 { BUILTIN_REGULAR "fc", histcmd },
1665#ifdef JOBS
1666 { BUILTIN_REGULAR "fg", fgcmd },
1667#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001668#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00001669 { BUILTIN_REGULAR "getopts", getoptscmd },
1670#endif
1671 { BUILTIN_NOSPEC "hash", hashcmd },
Eric Andersen1c039232001-07-07 00:05:55 +00001672 { BUILTIN_NOSPEC "help", helpcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001673 { BUILTIN_REGULAR "jobs", jobscmd },
1674#ifdef JOBS
1675 { BUILTIN_REGULAR "kill", killcmd },
1676#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001677#ifdef ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +00001678 { BUILTIN_REGULAR "let", letcmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001679#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001680 { BUILTIN_ASSIGN "local", localcmd },
Eric Andersen3102ac42001-07-06 04:26:23 +00001681#ifndef BB_PWD
Eric Andersen2870d962001-07-02 17:27:21 +00001682 { BUILTIN_NOSPEC "pwd", pwdcmd },
1683#endif
1684 { BUILTIN_REGULAR "read", readcmd },
1685 { BUILTIN_SPEC_ASSG "readonly", exportcmd },
1686 { BUILTIN_SPECIAL "return", returncmd },
1687 { BUILTIN_SPECIAL "set", setcmd },
1688 { BUILTIN_NOSPEC "setvar", setvarcmd },
1689 { BUILTIN_SPECIAL "shift", shiftcmd },
1690 { BUILTIN_SPECIAL "times", timescmd },
1691 { BUILTIN_SPECIAL "trap", trapcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001692 { BUILTIN_REGULAR "true", true_main },
Eric Andersen2870d962001-07-02 17:27:21 +00001693 { BUILTIN_NOSPEC "type", typecmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001694 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1695 { BUILTIN_REGULAR "umask", umaskcmd },
1696#ifdef ASH_ALIAS
1697 { BUILTIN_REGULAR "unalias", unaliascmd },
1698#endif
1699 { BUILTIN_SPECIAL "unset", unsetcmd },
1700 { BUILTIN_REGULAR "wait", waitcmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001701};
1702#define NUMBUILTINS (sizeof (builtincmds) / sizeof (struct builtincmd) )
1703
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001704#define DOTCMD &builtincmds[0]
Eric Andersen2870d962001-07-02 17:27:21 +00001705static struct builtincmd *BLTINCMD;
1706static struct builtincmd *EXECCMD;
1707static struct builtincmd *EVALCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00001708
Eric Andersen2870d962001-07-02 17:27:21 +00001709/* states */
1710#define JOBSTOPPED 1 /* all procs are stopped */
1711#define JOBDONE 2 /* all procs are completed */
Eric Andersencb57d552001-06-28 07:25:16 +00001712
Eric Andersen2870d962001-07-02 17:27:21 +00001713/*
1714 * A job structure contains information about a job. A job is either a
1715 * single process or a set of processes contained in a pipeline. In the
1716 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1717 * array of pids.
1718 */
Eric Andersencb57d552001-06-28 07:25:16 +00001719
Eric Andersen2870d962001-07-02 17:27:21 +00001720struct procstat {
1721 pid_t pid; /* process id */
1722 int status; /* status flags (defined above) */
1723 char *cmd; /* text of command being run */
1724};
Eric Andersencb57d552001-06-28 07:25:16 +00001725
Eric Andersen2870d962001-07-02 17:27:21 +00001726
1727static int job_warning; /* user was warned about stopped jobs */
1728
1729#ifdef JOBS
1730static void setjobctl(int enable);
1731#else
1732#define setjobctl(on) /* do nothing */
Eric Andersencb57d552001-06-28 07:25:16 +00001733#endif
1734
Eric Andersen2870d962001-07-02 17:27:21 +00001735
1736struct job {
1737 struct procstat ps0; /* status of process */
1738 struct procstat *ps; /* status or processes when more than one */
1739 short nprocs; /* number of processes */
1740 short pgrp; /* process group of this job */
1741 char state; /* true if job is finished */
1742 char used; /* true if this entry is in used */
1743 char changed; /* true if status has changed */
1744#ifdef JOBS
1745 char jobctl; /* job running under job control */
1746#endif
1747};
1748
1749static struct job *jobtab; /* array of jobs */
1750static int njobs; /* size of array */
1751static int backgndpid = -1; /* pid of last background process */
1752#ifdef JOBS
1753static int initialpgrp; /* pgrp of shell on invocation */
1754static int curjob; /* current job */
1755static int jobctl;
1756#endif
1757static int intreceived;
1758
Eric Andersen62483552001-07-10 06:09:16 +00001759static struct job *makejob (const union node *, int);
1760static int forkshell (struct job *, const union node *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00001761static int waitforjob (struct job *);
1762
1763static int docd (char *, int);
1764static char *getcomponent (void);
1765static void updatepwd (const char *);
1766static void getpwd (void);
1767
1768static char *padvance (const char **, const char *);
1769
1770static char nullstr[1]; /* zero length string */
1771static char *curdir = nullstr; /* current working directory */
1772static char *cdcomppath;
1773
Eric Andersencb57d552001-06-28 07:25:16 +00001774static int
1775cdcmd(argc, argv)
1776 int argc;
1777 char **argv;
1778{
1779 const char *dest;
1780 const char *path;
1781 char *p;
1782 struct stat statb;
1783 int print = 0;
1784
1785 nextopt(nullstr);
1786 if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME")) == NULL)
1787 error("HOME not set");
1788 if (*dest == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00001789 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001790 if (dest[0] == '-' && dest[1] == '\0') {
1791 dest = bltinlookup("OLDPWD");
1792 if (!dest || !*dest) {
1793 dest = curdir;
1794 }
1795 print = 1;
1796 if (dest)
Eric Andersen2870d962001-07-02 17:27:21 +00001797 print = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00001798 else
Eric Andersen2870d962001-07-02 17:27:21 +00001799 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001800 }
1801 if (*dest == '/' || (path = bltinlookup("CDPATH")) == NULL)
1802 path = nullstr;
1803 while ((p = padvance(&path, dest)) != NULL) {
1804 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
1805 if (!print) {
1806 /*
1807 * XXX - rethink
1808 */
1809 if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
1810 p += 2;
1811 print = strcmp(p, dest);
1812 }
1813 if (docd(p, print) >= 0)
1814 return 0;
1815
1816 }
1817 }
1818 error("can't cd to %s", dest);
1819 /* NOTREACHED */
1820}
1821
1822
1823/*
1824 * Actually do the chdir. In an interactive shell, print the
1825 * directory name if "print" is nonzero.
1826 */
1827
1828static int
1829docd(dest, print)
1830 char *dest;
1831 int print;
1832{
1833 char *p;
1834 char *q;
1835 char *component;
1836 struct stat statb;
1837 int first;
1838 int badstat;
1839
1840 TRACE(("docd(\"%s\", %d) called\n", dest, print));
1841
1842 /*
1843 * Check each component of the path. If we find a symlink or
1844 * something we can't stat, clear curdir to force a getcwd()
1845 * next time we get the value of the current directory.
1846 */
1847 badstat = 0;
1848 cdcomppath = sstrdup(dest);
1849 STARTSTACKSTR(p);
1850 if (*dest == '/') {
1851 STPUTC('/', p);
1852 cdcomppath++;
1853 }
1854 first = 1;
1855 while ((q = getcomponent()) != NULL) {
1856 if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0'))
1857 continue;
1858 if (! first)
1859 STPUTC('/', p);
1860 first = 0;
1861 component = q;
1862 while (*q)
1863 STPUTC(*q++, p);
1864 if (equal(component, ".."))
1865 continue;
1866 STACKSTRNUL(p);
1867 if ((lstat(stackblock(), &statb) < 0)
1868 || (S_ISLNK(statb.st_mode))) {
1869 /* print = 1; */
1870 badstat = 1;
1871 break;
1872 }
1873 }
1874
1875 INTOFF;
1876 if (chdir(dest) < 0) {
1877 INTON;
1878 return -1;
1879 }
1880 updatepwd(badstat ? NULL : dest);
1881 INTON;
1882 if (print && iflag)
Eric Andersen62483552001-07-10 06:09:16 +00001883 printf(snlfmt, curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00001884 return 0;
1885}
1886
1887
1888/*
1889 * Get the next component of the path name pointed to by cdcomppath.
1890 * This routine overwrites the string pointed to by cdcomppath.
1891 */
1892
1893static char *
1894getcomponent() {
1895 char *p;
1896 char *start;
1897
1898 if ((p = cdcomppath) == NULL)
1899 return NULL;
1900 start = cdcomppath;
1901 while (*p != '/' && *p != '\0')
1902 p++;
1903 if (*p == '\0') {
1904 cdcomppath = NULL;
1905 } else {
1906 *p++ = '\0';
1907 cdcomppath = p;
1908 }
1909 return start;
1910}
1911
1912
1913
1914/*
1915 * Update curdir (the name of the current directory) in response to a
1916 * cd command. We also call hashcd to let the routines in exec.c know
1917 * that the current directory has changed.
1918 */
1919
Eric Andersen2870d962001-07-02 17:27:21 +00001920static void hashcd (void);
1921
Eric Andersencb57d552001-06-28 07:25:16 +00001922static void
Eric Andersen2870d962001-07-02 17:27:21 +00001923updatepwd(const char *dir)
1924{
Eric Andersencb57d552001-06-28 07:25:16 +00001925 char *new;
1926 char *p;
1927 size_t len;
1928
Eric Andersen2870d962001-07-02 17:27:21 +00001929 hashcd(); /* update command hash table */
Eric Andersencb57d552001-06-28 07:25:16 +00001930
1931 /*
1932 * If our argument is NULL, we don't know the current directory
1933 * any more because we traversed a symbolic link or something
1934 * we couldn't stat().
1935 */
1936 if (dir == NULL || curdir == nullstr) {
1937 setpwd(0, 1);
1938 return;
1939 }
1940 len = strlen(dir);
1941 cdcomppath = sstrdup(dir);
1942 STARTSTACKSTR(new);
1943 if (*dir != '/') {
1944 p = curdir;
1945 while (*p)
1946 STPUTC(*p++, new);
1947 if (p[-1] == '/')
1948 STUNPUTC(new);
1949 }
1950 while ((p = getcomponent()) != NULL) {
1951 if (equal(p, "..")) {
1952 while (new > stackblock() && (STUNPUTC(new), *new) != '/');
1953 } else if (*p != '\0' && ! equal(p, ".")) {
1954 STPUTC('/', new);
1955 while (*p)
1956 STPUTC(*p++, new);
1957 }
1958 }
1959 if (new == stackblock())
1960 STPUTC('/', new);
1961 STACKSTRNUL(new);
1962 setpwd(stackblock(), 1);
1963}
1964
1965
Eric Andersen3102ac42001-07-06 04:26:23 +00001966#ifndef BB_PWD
Eric Andersencb57d552001-06-28 07:25:16 +00001967static int
1968pwdcmd(argc, argv)
1969 int argc;
1970 char **argv;
1971{
Eric Andersen62483552001-07-10 06:09:16 +00001972 printf(snlfmt, curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00001973 return 0;
1974}
Eric Andersen2870d962001-07-02 17:27:21 +00001975#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001976
1977/*
1978 * Find out what the current directory is. If we already know the current
1979 * directory, this routine returns immediately.
1980 */
1981static void
Eric Andersen2870d962001-07-02 17:27:21 +00001982getpwd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00001983{
Eric Andersen2870d962001-07-02 17:27:21 +00001984 curdir = xgetcwd(0);
1985 if(curdir==0)
1986 curdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00001987}
1988
1989static void
1990setpwd(const char *val, int setold)
1991{
1992 if (setold) {
1993 setvar("OLDPWD", curdir, VEXPORT);
1994 }
1995 INTOFF;
1996 if (curdir != nullstr) {
1997 free(curdir);
1998 curdir = nullstr;
1999 }
2000 if (!val) {
2001 getpwd();
2002 } else {
2003 curdir = savestr(val);
2004 }
2005 INTON;
2006 setvar("PWD", curdir, VEXPORT);
2007}
2008
Eric Andersencb57d552001-06-28 07:25:16 +00002009/*
2010 * Errors and exceptions.
2011 */
2012
2013/*
2014 * Code to handle exceptions in C.
2015 */
2016
Eric Andersen2870d962001-07-02 17:27:21 +00002017/*
2018 * We enclose jmp_buf in a structure so that we can declare pointers to
2019 * jump locations. The global variable handler contains the location to
2020 * jump to when an exception occurs, and the global variable exception
2021 * contains a code identifying the exeception. To implement nested
2022 * exception handlers, the user should save the value of handler on entry
2023 * to an inner scope, set handler to point to a jmploc structure for the
2024 * inner scope, and restore handler on exit from the scope.
2025 */
2026
2027struct jmploc {
2028 jmp_buf loc;
2029};
2030
2031/* exceptions */
2032#define EXINT 0 /* SIGINT received */
2033#define EXERROR 1 /* a generic error */
2034#define EXSHELLPROC 2 /* execute a shell procedure */
2035#define EXEXEC 3 /* command execution failed */
2036
2037static struct jmploc *handler;
Eric Andersencb57d552001-06-28 07:25:16 +00002038static int exception;
Eric Andersencb57d552001-06-28 07:25:16 +00002039
Eric Andersen2870d962001-07-02 17:27:21 +00002040static void exverror (int, const char *, va_list)
Eric Andersencb57d552001-06-28 07:25:16 +00002041 __attribute__((__noreturn__));
2042
2043/*
2044 * Called to raise an exception. Since C doesn't include exceptions, we
2045 * just do a longjmp to the exception handler. The type of exception is
2046 * stored in the global variable "exception".
2047 */
2048
Eric Andersen2870d962001-07-02 17:27:21 +00002049static void exraise (int) __attribute__((__noreturn__));
2050
Eric Andersencb57d552001-06-28 07:25:16 +00002051static void
Eric Andersen2870d962001-07-02 17:27:21 +00002052exraise(int e)
Eric Andersencb57d552001-06-28 07:25:16 +00002053{
2054#ifdef DEBUG
2055 if (handler == NULL)
2056 abort();
2057#endif
Eric Andersen62483552001-07-10 06:09:16 +00002058 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00002059 exception = e;
2060 longjmp(handler->loc, 1);
2061}
2062
2063
2064/*
2065 * Called from trap.c when a SIGINT is received. (If the user specifies
2066 * that SIGINT is to be trapped or ignored using the trap builtin, then
2067 * this routine is not called.) Suppressint is nonzero when interrupts
2068 * are held using the INTOFF macro. The call to _exit is necessary because
2069 * there is a short period after a fork before the signal handlers are
2070 * set to the appropriate value for the child. (The test for iflag is
2071 * just defensive programming.)
2072 */
2073
2074static void
Eric Andersen2870d962001-07-02 17:27:21 +00002075onint(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00002076 sigset_t mysigset;
2077
2078 if (suppressint) {
2079 intpending++;
2080 return;
2081 }
2082 intpending = 0;
2083 sigemptyset(&mysigset);
2084 sigprocmask(SIG_SETMASK, &mysigset, NULL);
2085 if (rootshell && iflag)
2086 exraise(EXINT);
2087 else {
2088 signal(SIGINT, SIG_DFL);
2089 raise(SIGINT);
2090 }
2091 /* NOTREACHED */
2092}
2093
2094
Eric Andersen2870d962001-07-02 17:27:21 +00002095static char *commandname; /* currently executing command */
2096
Eric Andersencb57d552001-06-28 07:25:16 +00002097/*
2098 * Exverror is called to raise the error exception. If the first argument
2099 * is not NULL then error prints an error message using printf style
2100 * formatting. It then raises the error exception.
2101 */
2102static void
Eric Andersen2870d962001-07-02 17:27:21 +00002103exverror(int cond, const char *msg, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00002104{
2105 CLEAR_PENDING_INT;
2106 INTOFF;
2107
2108#ifdef DEBUG
2109 if (msg)
2110 TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
2111 else
2112 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2113#endif
2114 if (msg) {
2115 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +00002116 out2fmt("%s: ", commandname);
2117 vfprintf(stderr, msg, ap);
2118 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00002119 }
Eric Andersencb57d552001-06-28 07:25:16 +00002120 exraise(cond);
2121 /* NOTREACHED */
2122}
2123
2124
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002125static void
Eric Andersencb57d552001-06-28 07:25:16 +00002126error(const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002127{
Eric Andersencb57d552001-06-28 07:25:16 +00002128 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002129 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002130 exverror(EXERROR, msg, ap);
2131 /* NOTREACHED */
2132 va_end(ap);
2133}
2134
2135
Eric Andersencb57d552001-06-28 07:25:16 +00002136static void
2137exerror(int cond, const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002138{
Eric Andersencb57d552001-06-28 07:25:16 +00002139 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002140 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002141 exverror(cond, msg, ap);
2142 /* NOTREACHED */
2143 va_end(ap);
2144}
2145
2146
2147
2148/*
2149 * Table of error messages.
2150 */
2151
2152struct errname {
Eric Andersen2870d962001-07-02 17:27:21 +00002153 short errcode; /* error number */
Eric Andersen62483552001-07-10 06:09:16 +00002154 char action; /* operation which encountered the error */
Eric Andersencb57d552001-06-28 07:25:16 +00002155};
2156
Eric Andersen2870d962001-07-02 17:27:21 +00002157/*
2158 * Types of operations (passed to the errmsg routine).
2159 */
2160
2161#define E_OPEN 01 /* opening a file */
2162#define E_CREAT 02 /* creating a file */
2163#define E_EXEC 04 /* executing a program */
Eric Andersencb57d552001-06-28 07:25:16 +00002164
2165#define ALL (E_OPEN|E_CREAT|E_EXEC)
2166
2167static const struct errname errormsg[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00002168 { EINTR, ALL },
2169 { EACCES, ALL },
2170 { EIO, ALL },
2171 { ENOENT, E_OPEN },
2172 { ENOENT, E_CREAT },
2173 { ENOENT, E_EXEC },
2174 { ENOTDIR, E_OPEN },
2175 { ENOTDIR, E_CREAT },
2176 { ENOTDIR, E_EXEC },
2177 { EISDIR, ALL },
2178 { EEXIST, E_CREAT },
2179#ifdef EMFILE
2180 { EMFILE, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002181#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002182 { ENFILE, ALL },
2183 { ENOSPC, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002184#ifdef EDQUOT
Eric Andersen2870d962001-07-02 17:27:21 +00002185 { EDQUOT, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002186#endif
2187#ifdef ENOSR
Eric Andersen2870d962001-07-02 17:27:21 +00002188 { ENOSR, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002189#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002190 { ENXIO, ALL },
2191 { EROFS, ALL },
2192 { ETXTBSY, ALL },
2193#ifdef EAGAIN
2194 { EAGAIN, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002195#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002196 { ENOMEM, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002197#ifdef ENOLINK
Eric Andersen2870d962001-07-02 17:27:21 +00002198 { ENOLINK, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002199#endif
2200#ifdef EMULTIHOP
Eric Andersen2870d962001-07-02 17:27:21 +00002201 { EMULTIHOP, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002202#endif
2203#ifdef ECOMM
Eric Andersen2870d962001-07-02 17:27:21 +00002204 { ECOMM, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002205#endif
2206#ifdef ESTALE
Eric Andersen2870d962001-07-02 17:27:21 +00002207 { ESTALE, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002208#endif
2209#ifdef ETIMEDOUT
Eric Andersen2870d962001-07-02 17:27:21 +00002210 { ETIMEDOUT, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002211#endif
2212#ifdef ELOOP
Eric Andersen2870d962001-07-02 17:27:21 +00002213 { ELOOP, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002214#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002215 { E2BIG, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002216#ifdef ELIBACC
Eric Andersen2870d962001-07-02 17:27:21 +00002217 { ELIBACC, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002218#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002219};
2220
Eric Andersen2870d962001-07-02 17:27:21 +00002221#define ERRNAME_SIZE (sizeof(errormsg)/sizeof(struct errname))
Eric Andersencb57d552001-06-28 07:25:16 +00002222
2223/*
2224 * Return a string describing an error. The returned string may be a
2225 * pointer to a static buffer that will be overwritten on the next call.
2226 * Action describes the operation that got the error.
2227 */
2228
2229static const char *
Eric Andersen2870d962001-07-02 17:27:21 +00002230errmsg(int e, int action)
Eric Andersencb57d552001-06-28 07:25:16 +00002231{
2232 struct errname const *ep;
2233 static char buf[12];
2234
Eric Andersen2870d962001-07-02 17:27:21 +00002235 for (ep = errormsg ; ep < errormsg+ERRNAME_SIZE; ep++) {
Eric Andersencb57d552001-06-28 07:25:16 +00002236 if (ep->errcode == e && (ep->action & action) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00002237 return strerror(e);
Eric Andersencb57d552001-06-28 07:25:16 +00002238 }
Eric Andersen2870d962001-07-02 17:27:21 +00002239
Eric Andersen3102ac42001-07-06 04:26:23 +00002240 snprintf(buf, sizeof buf, "error %d", e);
Eric Andersencb57d552001-06-28 07:25:16 +00002241 return buf;
2242}
2243
2244
Eric Andersen3102ac42001-07-06 04:26:23 +00002245#ifdef ASH_OPTIMIZE_FOR_SIZE
Eric Andersencb57d552001-06-28 07:25:16 +00002246static void
2247__inton() {
2248 if (--suppressint == 0 && intpending) {
2249 onint();
2250 }
2251}
Eric Andersen3102ac42001-07-06 04:26:23 +00002252static void forceinton (void) {
2253 suppressint = 0;
2254 if (intpending)
2255 onint();
2256}
Eric Andersencb57d552001-06-28 07:25:16 +00002257#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002258
2259/* flags in argument to evaltree */
Eric Andersen2870d962001-07-02 17:27:21 +00002260#define EV_EXIT 01 /* exit after evaluating tree */
2261#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2262#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00002263
Eric Andersen2870d962001-07-02 17:27:21 +00002264static int evalskip; /* set if we are skipping commands */
2265static int skipcount; /* number of levels to skip */
2266static int loopnest; /* current loop nesting level */
2267static int funcnest; /* depth of function calls */
Eric Andersencb57d552001-06-28 07:25:16 +00002268
2269
Eric Andersen2870d962001-07-02 17:27:21 +00002270static struct strlist *cmdenviron; /* environment for builtin command */
2271static int exitstatus; /* exit status of last command */
2272static int oexitstatus; /* saved exit status */
Eric Andersencb57d552001-06-28 07:25:16 +00002273
Eric Andersen62483552001-07-10 06:09:16 +00002274static void evalsubshell (const union node *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00002275static void expredir (union node *);
Eric Andersen2870d962001-07-02 17:27:21 +00002276static void prehash (union node *);
2277static void eprintlist (struct strlist *);
Eric Andersencb57d552001-06-28 07:25:16 +00002278
Eric Andersen2870d962001-07-02 17:27:21 +00002279static union node *parsecmd(int);
Eric Andersencb57d552001-06-28 07:25:16 +00002280/*
2281 * Called to reset things after an exception.
2282 */
2283
Eric Andersencb57d552001-06-28 07:25:16 +00002284/*
2285 * The eval commmand.
2286 */
Eric Andersen2870d962001-07-02 17:27:21 +00002287static void evalstring (char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00002288
2289static int
2290evalcmd(argc, argv)
2291 int argc;
2292 char **argv;
2293{
Eric Andersen2870d962001-07-02 17:27:21 +00002294 char *p;
2295 char *concat;
2296 char **ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002297
Eric Andersen2870d962001-07-02 17:27:21 +00002298 if (argc > 1) {
2299 p = argv[1];
2300 if (argc > 2) {
2301 STARTSTACKSTR(concat);
2302 ap = argv + 2;
2303 for (;;) {
2304 while (*p)
2305 STPUTC(*p++, concat);
2306 if ((p = *ap++) == NULL)
2307 break;
2308 STPUTC(' ', concat);
2309 }
2310 STPUTC('\0', concat);
2311 p = grabstackstr(concat);
2312 }
2313 evalstring(p, EV_TESTED);
2314 }
2315 return exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002316}
2317
Eric Andersencb57d552001-06-28 07:25:16 +00002318/*
2319 * Execute a command or commands contained in a string.
2320 */
2321
Eric Andersen2870d962001-07-02 17:27:21 +00002322static void evaltree (union node *, int);
2323static void setinputstring (char *);
2324static void popfile (void);
2325static void setstackmark(struct stackmark *mark);
2326static void popstackmark(struct stackmark *mark);
2327
2328
Eric Andersencb57d552001-06-28 07:25:16 +00002329static void
Eric Andersen2870d962001-07-02 17:27:21 +00002330evalstring(char *s, int flag)
2331{
Eric Andersencb57d552001-06-28 07:25:16 +00002332 union node *n;
2333 struct stackmark smark;
2334
2335 setstackmark(&smark);
2336 setinputstring(s);
2337 while ((n = parsecmd(0)) != NEOF) {
2338 evaltree(n, flag);
2339 popstackmark(&smark);
2340 }
2341 popfile();
2342 popstackmark(&smark);
2343}
2344
Eric Andersen2870d962001-07-02 17:27:21 +00002345static struct builtincmd *find_builtin (const char *);
Eric Andersen62483552001-07-10 06:09:16 +00002346static void expandarg (union node *, struct arglist *, int);
2347static void calcsize (const union node *);
2348static union node *copynode (const union node *);
2349
2350/*
2351 * Make a copy of a parse tree.
2352 */
2353
2354static int funcblocksize; /* size of structures in function */
2355static int funcstringsize; /* size of strings in node */
2356static pointer funcblock; /* block to allocate function from */
2357static char *funcstring; /* block to allocate strings from */
2358
2359
2360static inline union node *
2361copyfunc(union node *n)
2362{
2363 if (n == NULL)
2364 return NULL;
2365 funcblocksize = 0;
2366 funcstringsize = 0;
2367 calcsize(n);
2368 funcblock = ckmalloc(funcblocksize + funcstringsize);
2369 funcstring = (char *) funcblock + funcblocksize;
2370 return copynode(n);
2371}
2372
2373/*
2374 * Free a parse tree.
2375 */
Eric Andersencb57d552001-06-28 07:25:16 +00002376
2377static void
Eric Andersen62483552001-07-10 06:09:16 +00002378freefunc(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00002379{
Eric Andersen62483552001-07-10 06:09:16 +00002380 if (n)
2381 ckfree(n);
Eric Andersencb57d552001-06-28 07:25:16 +00002382}
2383
2384
Eric Andersen62483552001-07-10 06:09:16 +00002385/*
2386 * Add a new command entry, replacing any existing command entry for
2387 * the same name.
2388 */
2389
2390static inline void
2391addcmdentry(char *name, struct cmdentry *entry)
2392{
2393 struct tblentry *cmdp;
2394
2395 INTOFF;
2396 cmdp = cmdlookup(name, 1);
2397 if (cmdp->cmdtype == CMDFUNCTION) {
2398 freefunc(cmdp->param.func);
2399 }
2400 cmdp->cmdtype = entry->cmdtype;
2401 cmdp->param = entry->u;
2402 INTON;
2403}
2404
2405static inline void
2406evalloop(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002407{
2408 int status;
2409
2410 loopnest++;
2411 status = 0;
2412 for (;;) {
2413 evaltree(n->nbinary.ch1, EV_TESTED);
2414 if (evalskip) {
Eric Andersen2870d962001-07-02 17:27:21 +00002415skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002416 evalskip = 0;
2417 continue;
2418 }
2419 if (evalskip == SKIPBREAK && --skipcount <= 0)
2420 evalskip = 0;
2421 break;
2422 }
2423 if (n->type == NWHILE) {
2424 if (exitstatus != 0)
2425 break;
2426 } else {
2427 if (exitstatus == 0)
2428 break;
2429 }
2430 evaltree(n->nbinary.ch2, flags & EV_TESTED);
2431 status = exitstatus;
2432 if (evalskip)
2433 goto skipping;
2434 }
2435 loopnest--;
2436 exitstatus = status;
2437}
2438
Eric Andersencb57d552001-06-28 07:25:16 +00002439static void
Eric Andersen62483552001-07-10 06:09:16 +00002440evalfor(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002441{
2442 struct arglist arglist;
2443 union node *argp;
2444 struct strlist *sp;
2445 struct stackmark smark;
2446
2447 setstackmark(&smark);
2448 arglist.lastp = &arglist.list;
2449 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2450 oexitstatus = exitstatus;
2451 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2452 if (evalskip)
2453 goto out;
2454 }
2455 *arglist.lastp = NULL;
2456
2457 exitstatus = 0;
2458 loopnest++;
2459 for (sp = arglist.list ; sp ; sp = sp->next) {
2460 setvar(n->nfor.var, sp->text, 0);
2461 evaltree(n->nfor.body, flags & EV_TESTED);
2462 if (evalskip) {
2463 if (evalskip == SKIPCONT && --skipcount <= 0) {
2464 evalskip = 0;
2465 continue;
2466 }
2467 if (evalskip == SKIPBREAK && --skipcount <= 0)
2468 evalskip = 0;
2469 break;
2470 }
2471 }
2472 loopnest--;
2473out:
2474 popstackmark(&smark);
2475}
2476
Eric Andersen62483552001-07-10 06:09:16 +00002477static inline void
2478evalcase(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002479{
2480 union node *cp;
2481 union node *patp;
2482 struct arglist arglist;
2483 struct stackmark smark;
2484
2485 setstackmark(&smark);
2486 arglist.lastp = &arglist.list;
2487 oexitstatus = exitstatus;
2488 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2489 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2490 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2491 if (casematch(patp, arglist.list->text)) {
2492 if (evalskip == 0) {
2493 evaltree(cp->nclist.body, flags);
2494 }
2495 goto out;
2496 }
2497 }
2498 }
2499out:
2500 popstackmark(&smark);
2501}
2502
Eric Andersencb57d552001-06-28 07:25:16 +00002503/*
Eric Andersencb57d552001-06-28 07:25:16 +00002504 * Evaluate a pipeline. All the processes in the pipeline are children
2505 * of the process creating the pipeline. (This differs from some versions
2506 * of the shell, which make the last process in a pipeline the parent
2507 * of all the rest.)
2508 */
2509
Eric Andersen62483552001-07-10 06:09:16 +00002510static inline void
Eric Andersencb57d552001-06-28 07:25:16 +00002511evalpipe(n)
2512 union node *n;
2513{
2514 struct job *jp;
2515 struct nodelist *lp;
2516 int pipelen;
2517 int prevfd;
2518 int pip[2];
2519
2520 TRACE(("evalpipe(0x%lx) called\n", (long)n));
2521 pipelen = 0;
2522 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
2523 pipelen++;
2524 INTOFF;
2525 jp = makejob(n, pipelen);
2526 prevfd = -1;
2527 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
2528 prehash(lp->n);
2529 pip[1] = -1;
2530 if (lp->next) {
2531 if (pipe(pip) < 0) {
2532 close(prevfd);
2533 error("Pipe call failed");
2534 }
2535 }
2536 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
2537 INTON;
2538 if (prevfd > 0) {
2539 close(0);
2540 dup_as_newfd(prevfd, 0);
2541 close(prevfd);
2542 if (pip[0] == 0) {
2543 pip[0] = -1;
2544 }
2545 }
2546 if (pip[1] >= 0) {
2547 if (pip[0] >= 0) {
2548 close(pip[0]);
2549 }
2550 if (pip[1] != 1) {
2551 close(1);
2552 dup_as_newfd(pip[1], 1);
2553 close(pip[1]);
2554 }
2555 }
2556 evaltree(lp->n, EV_EXIT);
2557 }
2558 if (prevfd >= 0)
2559 close(prevfd);
2560 prevfd = pip[0];
2561 close(pip[1]);
2562 }
2563 INTON;
2564 if (n->npipe.backgnd == 0) {
2565 INTOFF;
2566 exitstatus = waitforjob(jp);
2567 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
2568 INTON;
2569 }
2570}
2571
Eric Andersen2870d962001-07-02 17:27:21 +00002572static void find_command (const char *, struct cmdentry *, int, const char *);
2573
2574static int
2575isassignment(const char *word) {
2576 if (!is_name(*word)) {
2577 return 0;
2578 }
2579 do {
2580 word++;
2581 } while (is_in_name(*word));
2582 return *word == '=';
2583}
2584
Eric Andersen62483552001-07-10 06:09:16 +00002585
Eric Andersencb57d552001-06-28 07:25:16 +00002586static void
Eric Andersen3102ac42001-07-06 04:26:23 +00002587evalcommand(union node *cmd, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002588{
2589 struct stackmark smark;
2590 union node *argp;
2591 struct arglist arglist;
2592 struct arglist varlist;
2593 char **argv;
2594 int argc;
2595 char **envp;
2596 struct strlist *sp;
2597 int mode;
Eric Andersencb57d552001-06-28 07:25:16 +00002598 struct cmdentry cmdentry;
2599 struct job *jp;
2600 char *volatile savecmdname;
2601 volatile struct shparam saveparam;
2602 struct localvar *volatile savelocalvars;
2603 volatile int e;
2604 char *lastarg;
2605 const char *path;
2606 const struct builtincmd *firstbltin;
2607 struct jmploc *volatile savehandler;
2608 struct jmploc jmploc;
2609#if __GNUC__
2610 /* Avoid longjmp clobbering */
2611 (void) &argv;
2612 (void) &argc;
2613 (void) &lastarg;
2614 (void) &flags;
2615#endif
2616
2617 /* First expand the arguments. */
2618 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
2619 setstackmark(&smark);
2620 arglist.lastp = &arglist.list;
2621 varlist.lastp = &varlist.list;
2622 arglist.list = 0;
2623 oexitstatus = exitstatus;
2624 exitstatus = 0;
2625 path = pathval();
2626 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
2627 expandarg(argp, &varlist, EXP_VARTILDE);
2628 }
2629 for (
2630 argp = cmd->ncmd.args; argp && !arglist.list;
2631 argp = argp->narg.next
2632 ) {
2633 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2634 }
2635 if (argp) {
2636 struct builtincmd *bcmd;
Eric Andersen62483552001-07-10 06:09:16 +00002637 int pseudovarflag;
Eric Andersencb57d552001-06-28 07:25:16 +00002638 bcmd = find_builtin(arglist.list->text);
Eric Andersen2870d962001-07-02 17:27:21 +00002639 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00002640 for (; argp; argp = argp->narg.next) {
2641 if (pseudovarflag && isassignment(argp->narg.text)) {
2642 expandarg(argp, &arglist, EXP_VARTILDE);
2643 continue;
2644 }
2645 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2646 }
2647 }
2648 *arglist.lastp = NULL;
2649 *varlist.lastp = NULL;
2650 expredir(cmd->ncmd.redirect);
2651 argc = 0;
2652 for (sp = arglist.list ; sp ; sp = sp->next)
2653 argc++;
2654 argv = stalloc(sizeof (char *) * (argc + 1));
2655
2656 for (sp = arglist.list ; sp ; sp = sp->next) {
2657 TRACE(("evalcommand arg: %s\n", sp->text));
2658 *argv++ = sp->text;
2659 }
2660 *argv = NULL;
2661 lastarg = NULL;
2662 if (iflag && funcnest == 0 && argc > 0)
2663 lastarg = argv[-1];
2664 argv -= argc;
2665
2666 /* Print the command if xflag is set. */
2667 if (xflag) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002668 out2c('+');
Eric Andersencb57d552001-06-28 07:25:16 +00002669 eprintlist(varlist.list);
2670 eprintlist(arglist.list);
Eric Andersen3102ac42001-07-06 04:26:23 +00002671 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00002672 }
2673
2674 /* Now locate the command. */
2675 if (argc == 0) {
2676 cmdentry.cmdtype = CMDBUILTIN;
2677 firstbltin = cmdentry.u.cmd = BLTINCMD;
2678 } else {
2679 const char *oldpath;
2680 int findflag = DO_ERR;
2681 int oldfindflag;
2682
2683 /*
2684 * Modify the command lookup path, if a PATH= assignment
2685 * is present
2686 */
2687 for (sp = varlist.list ; sp ; sp = sp->next)
2688 if (varequal(sp->text, defpathvar)) {
2689 path = sp->text + 5;
2690 findflag |= DO_BRUTE;
2691 }
2692 oldpath = path;
2693 oldfindflag = findflag;
2694 firstbltin = 0;
2695 for(;;) {
2696 find_command(argv[0], &cmdentry, findflag, path);
Eric Andersen2870d962001-07-02 17:27:21 +00002697 if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */
Eric Andersencb57d552001-06-28 07:25:16 +00002698 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002699 goto out;
2700 }
2701 /* implement bltin and command here */
2702 if (cmdentry.cmdtype != CMDBUILTIN) {
2703 break;
2704 }
2705 if (!firstbltin) {
2706 firstbltin = cmdentry.u.cmd;
2707 }
2708 if (cmdentry.u.cmd == BLTINCMD) {
2709 for(;;) {
2710 struct builtincmd *bcmd;
2711
2712 argv++;
2713 if (--argc == 0)
2714 goto found;
2715 if (!(bcmd = find_builtin(*argv))) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002716 out2fmt("%s: not found\n", *argv);
Eric Andersencb57d552001-06-28 07:25:16 +00002717 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002718 goto out;
2719 }
2720 cmdentry.u.cmd = bcmd;
2721 if (bcmd != BLTINCMD)
2722 break;
2723 }
2724 }
Eric Andersen2870d962001-07-02 17:27:21 +00002725 if (cmdentry.u.cmd == find_builtin("command")) {
Eric Andersencb57d552001-06-28 07:25:16 +00002726 argv++;
2727 if (--argc == 0) {
2728 goto found;
2729 }
2730 if (*argv[0] == '-') {
2731 if (!equal(argv[0], "-p")) {
2732 argv--;
2733 argc++;
2734 break;
2735 }
2736 argv++;
2737 if (--argc == 0) {
2738 goto found;
2739 }
2740 path = defpath;
2741 findflag |= DO_BRUTE;
2742 } else {
2743 path = oldpath;
2744 findflag = oldfindflag;
2745 }
2746 findflag |= DO_NOFUN;
2747 continue;
2748 }
2749found:
2750 break;
2751 }
2752 }
2753
2754 /* Fork off a child process if necessary. */
2755 if (cmd->ncmd.backgnd
2756 || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00002757 ) {
2758 jp = makejob(cmd, 1);
2759 mode = cmd->ncmd.backgnd;
Eric Andersencb57d552001-06-28 07:25:16 +00002760 if (forkshell(jp, cmd, mode) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00002761 goto parent; /* at end of routine */
Eric Andersencb57d552001-06-28 07:25:16 +00002762 flags |= EV_EXIT;
2763 }
2764
2765 /* This is the child process if a fork occurred. */
2766 /* Execute the command. */
2767 if (cmdentry.cmdtype == CMDFUNCTION) {
2768#ifdef DEBUG
2769 trputs("Shell function: "); trargs(argv);
2770#endif
2771 exitstatus = oexitstatus;
2772 redirect(cmd->ncmd.redirect, REDIR_PUSH);
2773 saveparam = shellparam;
2774 shellparam.malloc = 0;
2775 shellparam.nparam = argc - 1;
2776 shellparam.p = argv + 1;
2777 INTOFF;
2778 savelocalvars = localvars;
2779 localvars = NULL;
2780 INTON;
2781 if (setjmp(jmploc.loc)) {
2782 if (exception == EXSHELLPROC) {
2783 freeparam((volatile struct shparam *)
2784 &saveparam);
2785 } else {
2786 saveparam.optind = shellparam.optind;
2787 saveparam.optoff = shellparam.optoff;
2788 freeparam(&shellparam);
2789 shellparam = saveparam;
2790 }
2791 poplocalvars();
2792 localvars = savelocalvars;
2793 handler = savehandler;
2794 longjmp(handler->loc, 1);
2795 }
2796 savehandler = handler;
2797 handler = &jmploc;
2798 for (sp = varlist.list ; sp ; sp = sp->next)
2799 mklocal(sp->text);
2800 funcnest++;
2801 evaltree(cmdentry.u.func, flags & EV_TESTED);
2802 funcnest--;
2803 INTOFF;
2804 poplocalvars();
2805 localvars = savelocalvars;
2806 saveparam.optind = shellparam.optind;
2807 saveparam.optoff = shellparam.optoff;
2808 freeparam(&shellparam);
2809 shellparam = saveparam;
2810 handler = savehandler;
2811 popredir();
2812 INTON;
2813 if (evalskip == SKIPFUNC) {
2814 evalskip = 0;
2815 skipcount = 0;
2816 }
2817 if (flags & EV_EXIT)
2818 exitshell(exitstatus);
2819 } else if (cmdentry.cmdtype == CMDBUILTIN) {
2820#ifdef DEBUG
2821 trputs("builtin command: "); trargs(argv);
2822#endif
2823 mode = (cmdentry.u.cmd == EXECCMD)? 0 : REDIR_PUSH;
Eric Andersencb57d552001-06-28 07:25:16 +00002824 redirect(cmd->ncmd.redirect, mode);
2825 savecmdname = commandname;
Eric Andersen2870d962001-07-02 17:27:21 +00002826 if (IS_BUILTIN_SPECIAL(firstbltin)) {
Eric Andersencb57d552001-06-28 07:25:16 +00002827 listsetvar(varlist.list);
2828 } else {
2829 cmdenviron = varlist.list;
2830 }
2831 e = -1;
2832 if (setjmp(jmploc.loc)) {
2833 e = exception;
2834 exitstatus = (e == EXINT)? SIGINT+128 : 2;
2835 goto cmddone;
2836 }
2837 savehandler = handler;
2838 handler = &jmploc;
2839 commandname = argv[0];
2840 argptr = argv + 1;
Eric Andersen2870d962001-07-02 17:27:21 +00002841 optptr = NULL; /* initialize nextopt */
Eric Andersencb57d552001-06-28 07:25:16 +00002842 exitstatus = (*cmdentry.u.cmd->builtinfunc)(argc, argv);
2843 flushall();
2844cmddone:
Eric Andersencb57d552001-06-28 07:25:16 +00002845 cmdenviron = NULL;
2846 if (e != EXSHELLPROC) {
2847 commandname = savecmdname;
2848 if (flags & EV_EXIT)
2849 exitshell(exitstatus);
2850 }
2851 handler = savehandler;
2852 if (e != -1) {
2853 if ((e != EXERROR && e != EXEXEC)
2854 || cmdentry.u.cmd == BLTINCMD
2855 || cmdentry.u.cmd == DOTCMD
2856 || cmdentry.u.cmd == EVALCMD
2857 || cmdentry.u.cmd == EXECCMD)
2858 exraise(e);
2859 FORCEINTON;
2860 }
2861 if (cmdentry.u.cmd != EXECCMD)
2862 popredir();
Eric Andersencb57d552001-06-28 07:25:16 +00002863 } else {
2864#ifdef DEBUG
2865 trputs("normal command: "); trargs(argv);
2866#endif
2867 redirect(cmd->ncmd.redirect, 0);
2868 clearredir();
2869 for (sp = varlist.list ; sp ; sp = sp->next)
2870 setvareq(sp->text, VEXPORT|VSTACK);
2871 envp = environment();
2872 shellexec(argv, envp, path, cmdentry.u.index);
2873 }
2874 goto out;
2875
Eric Andersen2870d962001-07-02 17:27:21 +00002876parent: /* parent process gets here (if we forked) */
2877 if (mode == 0) { /* argument to fork */
Eric Andersencb57d552001-06-28 07:25:16 +00002878 INTOFF;
2879 exitstatus = waitforjob(jp);
2880 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00002881 }
2882
2883out:
2884 if (lastarg)
2885 setvar("_", lastarg, 0);
2886 popstackmark(&smark);
2887}
2888
Eric Andersen62483552001-07-10 06:09:16 +00002889/*
2890 * Evaluate a parse tree. The value is left in the global variable
2891 * exitstatus.
2892 */
2893static void
2894evaltree(n, flags)
2895 union node *n;
2896 int flags;
2897{
2898 int checkexit = 0;
2899 if (n == NULL) {
2900 TRACE(("evaltree(NULL) called\n"));
2901 goto out;
2902 }
2903 TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
2904 switch (n->type) {
2905 case NSEMI:
2906 evaltree(n->nbinary.ch1, flags & EV_TESTED);
2907 if (evalskip)
2908 goto out;
2909 evaltree(n->nbinary.ch2, flags);
2910 break;
2911 case NAND:
2912 evaltree(n->nbinary.ch1, EV_TESTED);
2913 if (evalskip || exitstatus != 0)
2914 goto out;
2915 evaltree(n->nbinary.ch2, flags);
2916 break;
2917 case NOR:
2918 evaltree(n->nbinary.ch1, EV_TESTED);
2919 if (evalskip || exitstatus == 0)
2920 goto out;
2921 evaltree(n->nbinary.ch2, flags);
2922 break;
2923 case NREDIR:
2924 expredir(n->nredir.redirect);
2925 redirect(n->nredir.redirect, REDIR_PUSH);
2926 evaltree(n->nredir.n, flags);
2927 popredir();
2928 break;
2929 case NSUBSHELL:
2930 evalsubshell(n, flags);
2931 break;
2932 case NBACKGND:
2933 evalsubshell(n, flags);
2934 break;
2935 case NIF: {
2936 evaltree(n->nif.test, EV_TESTED);
2937 if (evalskip)
2938 goto out;
2939 if (exitstatus == 0)
2940 evaltree(n->nif.ifpart, flags);
2941 else if (n->nif.elsepart)
2942 evaltree(n->nif.elsepart, flags);
2943 else
2944 exitstatus = 0;
2945 break;
2946 }
2947 case NWHILE:
2948 case NUNTIL:
2949 evalloop(n, flags);
2950 break;
2951 case NFOR:
2952 evalfor(n, flags);
2953 break;
2954 case NCASE:
2955 evalcase(n, flags);
2956 break;
2957 case NDEFUN: {
2958 struct builtincmd *bcmd;
2959 struct cmdentry entry;
2960 if (
2961 (bcmd = find_builtin(n->narg.text)) &&
2962 IS_BUILTIN_SPECIAL(bcmd)
2963 ) {
2964 out2fmt("%s is a special built-in\n", n->narg.text);
2965 exitstatus = 1;
2966 break;
2967 }
2968 entry.cmdtype = CMDFUNCTION;
2969 entry.u.func = copyfunc(n->narg.next);
2970 addcmdentry(n->narg.text, &entry);
2971 exitstatus = 0;
2972 break;
2973 }
2974 case NNOT:
2975 evaltree(n->nnot.com, EV_TESTED);
2976 exitstatus = !exitstatus;
2977 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002978
Eric Andersen62483552001-07-10 06:09:16 +00002979 case NPIPE:
2980 evalpipe(n);
2981 checkexit = 1;
2982 break;
2983 case NCMD:
2984 evalcommand(n, flags);
2985 checkexit = 1;
2986 break;
2987#ifdef DEBUG
2988 default:
2989 printf("Node type = %d\n", n->type);
2990 break;
2991#endif
2992 }
2993out:
2994 if (pendingsigs)
2995 dotrap();
2996 if (
2997 flags & EV_EXIT ||
2998 (checkexit && eflag && exitstatus && !(flags & EV_TESTED))
2999 )
3000 exitshell(exitstatus);
3001}
3002
3003/*
3004 * Kick off a subshell to evaluate a tree.
3005 */
3006
3007static void
3008evalsubshell(const union node *n, int flags)
3009{
3010 struct job *jp;
3011 int backgnd = (n->type == NBACKGND);
3012
3013 expredir(n->nredir.redirect);
3014 jp = makejob(n, 1);
3015 if (forkshell(jp, n, backgnd) == 0) {
3016 if (backgnd)
3017 flags &=~ EV_TESTED;
3018 redirect(n->nredir.redirect, 0);
3019 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
3020 }
3021 if (! backgnd) {
3022 INTOFF;
3023 exitstatus = waitforjob(jp);
3024 INTON;
3025 }
3026}
3027
3028/*
3029 * Compute the names of the files in a redirection list.
3030 */
3031
3032static void fixredir(union node *n, const char *text, int err);
3033
3034static void
3035expredir(union node *n)
3036{
3037 union node *redir;
3038
3039 for (redir = n ; redir ; redir = redir->nfile.next) {
3040 struct arglist fn;
3041 fn.lastp = &fn.list;
3042 oexitstatus = exitstatus;
3043 switch (redir->type) {
3044 case NFROMTO:
3045 case NFROM:
3046 case NTO:
3047 case NAPPEND:
3048 case NTOOV:
3049 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3050 redir->nfile.expfname = fn.list->text;
3051 break;
3052 case NFROMFD:
3053 case NTOFD:
3054 if (redir->ndup.vname) {
3055 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3056 fixredir(redir, fn.list->text, 1);
3057 }
3058 break;
3059 }
3060 }
3061}
3062
3063
3064/*
3065 * Execute a command inside back quotes. If it's a builtin command, we
3066 * want to save its output in a block obtained from malloc. Otherwise
3067 * we fork off a subprocess and get the output of the command via a pipe.
3068 * Should be called with interrupts off.
3069 */
3070
3071static void
3072evalbackcmd(union node *n, struct backcmd *result)
3073{
3074 int pip[2];
3075 struct job *jp;
3076 struct stackmark smark; /* unnecessary */
3077
3078 setstackmark(&smark);
3079 result->fd = -1;
3080 result->buf = NULL;
3081 result->nleft = 0;
3082 result->jp = NULL;
3083 if (n == NULL) {
3084 exitstatus = 0;
3085 goto out;
3086 }
3087 exitstatus = 0;
3088 if (pipe(pip) < 0)
3089 error("Pipe call failed");
3090 jp = makejob(n, 1);
3091 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3092 FORCEINTON;
3093 close(pip[0]);
3094 if (pip[1] != 1) {
3095 close(1);
3096 dup_as_newfd(pip[1], 1);
3097 close(pip[1]);
3098 }
3099 eflag = 0;
3100 evaltree(n, EV_EXIT);
3101 }
3102 close(pip[1]);
3103 result->fd = pip[0];
3104 result->jp = jp;
3105out:
3106 popstackmark(&smark);
3107 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
3108 result->fd, result->buf, result->nleft, result->jp));
3109}
3110
3111
3112/*
3113 * Execute a simple command.
3114 */
Eric Andersencb57d552001-06-28 07:25:16 +00003115
3116/*
3117 * Search for a command. This is called before we fork so that the
3118 * location of the command will be available in the parent as well as
3119 * the child. The check for "goodname" is an overly conservative
3120 * check that the name will not be subject to expansion.
3121 */
3122
3123static void
3124prehash(n)
3125 union node *n;
3126{
3127 struct cmdentry entry;
3128
3129 if (n->type == NCMD && n->ncmd.args)
3130 if (goodname(n->ncmd.args->narg.text))
3131 find_command(n->ncmd.args->narg.text, &entry, 0,
3132 pathval());
3133}
3134
3135
Eric Andersencb57d552001-06-28 07:25:16 +00003136/*
3137 * Builtin commands. Builtin commands whose functions are closely
3138 * tied to evaluation are implemented here.
3139 */
3140
3141/*
3142 * No command given, or a bltin command with no arguments. Set the
3143 * specified variables.
3144 */
3145
3146int
3147bltincmd(argc, argv)
3148 int argc;
3149 char **argv;
3150{
3151 /*
3152 * Preserve exitstatus of a previous possible redirection
3153 * as POSIX mandates
3154 */
3155 return exitstatus;
3156}
3157
3158
3159/*
3160 * Handle break and continue commands. Break, continue, and return are
3161 * all handled by setting the evalskip flag. The evaluation routines
3162 * above all check this flag, and if it is set they start skipping
3163 * commands rather than executing them. The variable skipcount is
3164 * the number of loops to break/continue, or the number of function
3165 * levels to return. (The latter is always 1.) It should probably
3166 * be an error to break out of more loops than exist, but it isn't
3167 * in the standard shell so we don't make it one here.
3168 */
3169
3170static int
3171breakcmd(argc, argv)
3172 int argc;
3173 char **argv;
3174{
3175 int n = argc > 1 ? number(argv[1]) : 1;
3176
3177 if (n > loopnest)
3178 n = loopnest;
3179 if (n > 0) {
3180 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
3181 skipcount = n;
3182 }
3183 return 0;
3184}
3185
3186
3187/*
3188 * The return command.
3189 */
3190
3191static int
3192returncmd(argc, argv)
3193 int argc;
3194 char **argv;
3195{
3196 int ret = argc > 1 ? number(argv[1]) : oexitstatus;
3197
3198 if (funcnest) {
3199 evalskip = SKIPFUNC;
3200 skipcount = 1;
3201 return ret;
3202 }
3203 else {
3204 /* Do what ksh does; skip the rest of the file */
3205 evalskip = SKIPFILE;
3206 skipcount = 1;
3207 return ret;
3208 }
3209}
3210
3211
3212#ifndef BB_TRUE_FALSE
3213static int
3214false_main(argc, argv)
3215 int argc;
3216 char **argv;
3217{
3218 return 1;
3219}
3220
3221
3222static int
3223true_main(argc, argv)
3224 int argc;
3225 char **argv;
3226{
3227 return 0;
3228}
3229#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003230
3231/*
3232 * Controls whether the shell is interactive or not.
3233 */
3234
3235static void setsignal(int signo);
3236static void chkmail(int silent);
3237
3238
3239static void
3240setinteractive(int on)
3241{
3242 static int is_interactive;
Eric Andersen1c039232001-07-07 00:05:55 +00003243 static int do_banner=0;
Eric Andersen2870d962001-07-02 17:27:21 +00003244
3245 if (on == is_interactive)
3246 return;
3247 setsignal(SIGINT);
3248 setsignal(SIGQUIT);
3249 setsignal(SIGTERM);
3250 chkmail(1);
3251 is_interactive = on;
Eric Andersen1c039232001-07-07 00:05:55 +00003252 if (do_banner==0 && is_interactive) {
3253 /* Looks like they want an interactive shell */
3254 printf( "\n\n" BB_BANNER " Built-in shell (ash)\n");
3255 printf( "Enter 'help' for a list of built-in commands.\n\n");
3256 do_banner=1;
3257 }
Eric Andersen2870d962001-07-02 17:27:21 +00003258}
3259
3260static void
3261optschanged(void)
3262{
3263 setinteractive(iflag);
3264 setjobctl(mflag);
3265}
3266
Eric Andersencb57d552001-06-28 07:25:16 +00003267
3268static int
3269execcmd(argc, argv)
3270 int argc;
3271 char **argv;
3272{
3273 if (argc > 1) {
3274 struct strlist *sp;
3275
Eric Andersen2870d962001-07-02 17:27:21 +00003276 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003277 mflag = 0;
3278 optschanged();
3279 for (sp = cmdenviron; sp ; sp = sp->next)
3280 setvareq(sp->text, VEXPORT|VSTACK);
3281 shellexec(argv + 1, environment(), pathval(), 0);
3282 }
3283 return 0;
3284}
3285
3286static void
3287eprintlist(struct strlist *sp)
3288{
3289 for (; sp; sp = sp->next) {
Eric Andersen3102ac42001-07-06 04:26:23 +00003290 out2fmt(" %s",sp->text);
Eric Andersencb57d552001-06-28 07:25:16 +00003291 }
3292}
Eric Andersencb57d552001-06-28 07:25:16 +00003293
3294/*
3295 * Exec a program. Never returns. If you change this routine, you may
3296 * have to change the find_command routine as well.
3297 */
3298
Eric Andersen2870d962001-07-02 17:27:21 +00003299static const char *pathopt; /* set by padvance */
3300
Eric Andersencb57d552001-06-28 07:25:16 +00003301static void
3302shellexec(argv, envp, path, idx)
3303 char **argv, **envp;
3304 const char *path;
3305 int idx;
3306{
3307 char *cmdname;
3308 int e;
3309
3310 if (strchr(argv[0], '/') != NULL) {
3311 tryexec(argv[0], argv, envp);
3312 e = errno;
3313 } else {
3314 e = ENOENT;
3315 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3316 if (--idx < 0 && pathopt == NULL) {
3317 tryexec(cmdname, argv, envp);
3318 if (errno != ENOENT && errno != ENOTDIR)
3319 e = errno;
3320 }
3321 stunalloc(cmdname);
3322 }
3323 }
3324
3325 /* Map to POSIX errors */
3326 switch (e) {
3327 case EACCES:
3328 exerrno = 126;
3329 break;
3330 case ENOENT:
3331 exerrno = 127;
3332 break;
3333 default:
3334 exerrno = 2;
3335 break;
3336 }
3337 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3338 /* NOTREACHED */
3339}
3340
Eric Andersen2870d962001-07-02 17:27:21 +00003341/*
3342 * Clear traps on a fork.
3343 */
3344static void
3345clear_traps(void) {
3346 char **tp;
3347
3348 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
3349 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
3350 INTOFF;
3351 ckfree(*tp);
3352 *tp = NULL;
3353 if (tp != &trap[0])
3354 setsignal(tp - trap);
3355 INTON;
3356 }
3357 }
3358}
3359
3360
3361static void
3362initshellproc(void) {
3363
3364#ifdef ASH_ALIAS
3365 /* from alias.c: */
3366 {
3367 rmaliases();
3368 }
3369#endif
3370 /* from eval.c: */
3371 {
3372 exitstatus = 0;
3373 }
3374
3375 /* from exec.c: */
3376 {
3377 deletefuncs();
3378 }
3379
3380 /* from jobs.c: */
3381 {
3382 backgndpid = -1;
3383#ifdef JOBS
3384 jobctl = 0;
3385#endif
3386 }
3387
3388 /* from options.c: */
3389 {
3390 int i;
3391
3392 for (i = 0; i < NOPTS; i++)
3393 optent_val(i) = 0;
3394 optschanged();
3395
3396 }
3397
3398 /* from redir.c: */
3399 {
3400 clearredir();
3401 }
3402
3403 /* from trap.c: */
3404 {
3405 char *sm;
3406
3407 clear_traps();
3408 for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) {
3409 if (*sm == S_IGN)
3410 *sm = S_HARD_IGN;
3411 }
3412 }
3413
3414 /* from var.c: */
3415 {
3416 shprocvar();
3417 }
3418}
3419
3420static int preadbuffer(void);
3421static void pushfile (void);
Eric Andersen2870d962001-07-02 17:27:21 +00003422
3423/*
3424 * Read a character from the script, returning PEOF on end of file.
3425 * Nul characters in the input are silently discarded.
3426 */
3427
Eric Andersen3102ac42001-07-06 04:26:23 +00003428#ifndef ASH_OPTIMIZE_FOR_SIZE
Eric Andersen2870d962001-07-02 17:27:21 +00003429#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
3430static int
3431pgetc(void)
3432{
3433 return pgetc_macro();
3434}
3435#else
3436static int
3437pgetc_macro(void)
3438{
3439 return --parsenleft >= 0? *parsenextc++ : preadbuffer();
3440}
3441
3442static inline int
3443pgetc(void)
3444{
3445 return pgetc_macro();
3446}
3447#endif
3448
3449
3450/*
3451 * Undo the last call to pgetc. Only one character may be pushed back.
3452 * PEOF may be pushed back.
3453 */
3454
3455static void
3456pungetc() {
3457 parsenleft++;
3458 parsenextc--;
3459}
3460
3461
3462static void
3463popfile(void) {
3464 struct parsefile *pf = parsefile;
3465
3466 INTOFF;
3467 if (pf->fd >= 0)
3468 close(pf->fd);
3469 if (pf->buf)
3470 ckfree(pf->buf);
3471 while (pf->strpush)
3472 popstring();
3473 parsefile = pf->prev;
3474 ckfree(pf);
3475 parsenleft = parsefile->nleft;
3476 parselleft = parsefile->lleft;
3477 parsenextc = parsefile->nextc;
3478 plinno = parsefile->linno;
3479 INTON;
3480}
3481
3482
3483/*
3484 * Return to top level.
3485 */
3486
3487static void
3488popallfiles(void) {
3489 while (parsefile != &basepf)
3490 popfile();
3491}
3492
3493/*
3494 * Close the file(s) that the shell is reading commands from. Called
3495 * after a fork is done.
3496 */
3497
3498static void
3499closescript() {
3500 popallfiles();
3501 if (parsefile->fd > 0) {
3502 close(parsefile->fd);
3503 parsefile->fd = 0;
3504 }
3505}
3506
3507
3508/*
3509 * Like setinputfile, but takes an open file descriptor. Call this with
3510 * interrupts off.
3511 */
3512
3513static void
3514setinputfd(fd, push)
3515 int fd, push;
3516{
3517 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
3518 if (push) {
3519 pushfile();
3520 parsefile->buf = 0;
3521 } else {
3522 closescript();
3523 while (parsefile->strpush)
3524 popstring();
3525 }
3526 parsefile->fd = fd;
3527 if (parsefile->buf == NULL)
3528 parsefile->buf = ckmalloc(BUFSIZ);
3529 parselleft = parsenleft = 0;
3530 plinno = 1;
3531}
3532
3533
3534/*
3535 * Set the input to take input from a file. If push is set, push the
3536 * old input onto the stack first.
3537 */
3538
3539static void
3540setinputfile(const char *fname, int push)
3541{
3542 int fd;
3543 int myfileno2;
3544
3545 INTOFF;
3546 if ((fd = open(fname, O_RDONLY)) < 0)
3547 error("Can't open %s", fname);
3548 if (fd < 10) {
3549 myfileno2 = dup_as_newfd(fd, 10);
3550 close(fd);
3551 if (myfileno2 < 0)
3552 error("Out of file descriptors");
3553 fd = myfileno2;
3554 }
3555 setinputfd(fd, push);
3556 INTON;
3557}
3558
Eric Andersencb57d552001-06-28 07:25:16 +00003559
3560static void
Eric Andersen62483552001-07-10 06:09:16 +00003561tryexec(char *cmd, char **argv, char **envp)
3562{
Eric Andersencb57d552001-06-28 07:25:16 +00003563 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003564
Eric Andersen3102ac42001-07-06 04:26:23 +00003565#ifdef BB_FEATURE_SH_STANDALONE_SHELL
3566 char *name = cmd;
3567 char** argv_l=argv;
3568 int argc_l;
3569#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
3570 name = get_last_path_component(name);
3571#endif
3572 argv_l=envp;
3573 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
3574 putenv(*argv_l);
3575 argv_l=argv;
Eric Andersen62483552001-07-10 06:09:16 +00003576 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
Eric Andersen3102ac42001-07-06 04:26:23 +00003577 optind = 1;
3578 run_applet_by_name(name, argc_l, argv);
3579#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003580 execve(cmd, argv, envp);
Eric Andersencb57d552001-06-28 07:25:16 +00003581 e = errno;
3582 if (e == ENOEXEC) {
3583 INTOFF;
3584 initshellproc();
3585 setinputfile(cmd, 0);
3586 commandname = arg0 = savestr(argv[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00003587 setparam(argv + 1);
3588 exraise(EXSHELLPROC);
3589 }
3590 errno = e;
3591}
3592
Eric Andersen2870d962001-07-02 17:27:21 +00003593static char *commandtext (const union node *);
Eric Andersencb57d552001-06-28 07:25:16 +00003594
3595/*
3596 * Do a path search. The variable path (passed by reference) should be
3597 * set to the start of the path before the first call; padvance will update
3598 * this value as it proceeds. Successive calls to padvance will return
3599 * the possible path expansions in sequence. If an option (indicated by
3600 * a percent sign) appears in the path entry then the global variable
3601 * pathopt will be set to point to it; otherwise pathopt will be set to
3602 * NULL.
3603 */
3604
3605static const char *pathopt;
3606
Eric Andersen2870d962001-07-02 17:27:21 +00003607static void growstackblock(void);
3608
3609
Eric Andersencb57d552001-06-28 07:25:16 +00003610static char *
Eric Andersen2870d962001-07-02 17:27:21 +00003611padvance(const char **path, const char *name)
3612{
Eric Andersencb57d552001-06-28 07:25:16 +00003613 const char *p;
3614 char *q;
3615 const char *start;
3616 int len;
3617
3618 if (*path == NULL)
3619 return NULL;
3620 start = *path;
3621 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
Eric Andersen2870d962001-07-02 17:27:21 +00003622 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003623 while (stackblocksize() < len)
3624 growstackblock();
3625 q = stackblock();
3626 if (p != start) {
3627 memcpy(q, start, p - start);
3628 q += p - start;
3629 *q++ = '/';
3630 }
3631 strcpy(q, name);
3632 pathopt = NULL;
3633 if (*p == '%') {
3634 pathopt = ++p;
3635 while (*p && *p != ':') p++;
3636 }
3637 if (*p == ':')
3638 *path = p + 1;
3639 else
3640 *path = NULL;
3641 return stalloc(len);
3642}
3643
Eric Andersen62483552001-07-10 06:09:16 +00003644/*
3645 * Wrapper around strcmp for qsort/bsearch/...
3646 */
3647static int
3648pstrcmp(const void *a, const void *b)
3649{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003650 return strcmp((const char *) a, (*(const char *const *) b) + 1);
Eric Andersen62483552001-07-10 06:09:16 +00003651}
3652
3653/*
3654 * Find a keyword is in a sorted array.
3655 */
3656
3657static const char *const *
3658findkwd(const char *s)
3659{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003660 return bsearch(s, tokname_array + KWDOFFSET,
3661 (sizeof(tokname_array)/sizeof(const char *)) - KWDOFFSET,
3662 sizeof(const char *), pstrcmp);
Eric Andersen62483552001-07-10 06:09:16 +00003663}
Eric Andersencb57d552001-06-28 07:25:16 +00003664
3665
3666/*** Command hashing code ***/
3667
3668
3669static int
3670hashcmd(argc, argv)
3671 int argc;
3672 char **argv;
3673{
3674 struct tblentry **pp;
3675 struct tblentry *cmdp;
3676 int c;
3677 int verbose;
3678 struct cmdentry entry;
3679 char *name;
Eric Andersen62483552001-07-10 06:09:16 +00003680#ifdef ASH_ALIAS
3681 const struct alias *ap;
3682#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003683
3684 verbose = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003685 while ((c = nextopt("rvV")) != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00003686 if (c == 'r') {
3687 clearcmdentry(0);
3688 return 0;
Eric Andersen62483552001-07-10 06:09:16 +00003689 } else if (c == 'v' || c == 'V') {
3690 verbose = c;
Eric Andersencb57d552001-06-28 07:25:16 +00003691 }
3692 }
3693 if (*argptr == NULL) {
3694 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3695 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3696 if (cmdp->cmdtype != CMDBUILTIN) {
3697 printentry(cmdp, verbose);
3698 }
3699 }
3700 }
3701 return 0;
3702 }
3703 c = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003704 while ((name = *argptr++) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00003705 if ((cmdp = cmdlookup(name, 0)) != NULL
3706 && (cmdp->cmdtype == CMDNORMAL
3707 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3708 delete_cmd_entry();
Eric Andersen62483552001-07-10 06:09:16 +00003709#ifdef ASH_ALIAS
3710 /* Then look at the aliases */
3711 if ((ap = lookupalias(name, 0)) != NULL) {
3712 if (verbose=='v')
3713 printf("%s is an alias for %s\n", name, ap->val);
3714 else
3715 printalias(ap);
3716 continue;
3717 }
3718#endif
3719 /* First look at the keywords */
3720 if (findkwd(name)!=0) {
3721 if (verbose=='v')
3722 printf("%s is a shell keyword\n", name);
3723 else
3724 printf(snlfmt, name);
3725 continue;
3726 }
3727
Eric Andersencb57d552001-06-28 07:25:16 +00003728 find_command(name, &entry, DO_ERR, pathval());
3729 if (entry.cmdtype == CMDUNKNOWN) c = 1;
3730 else if (verbose) {
3731 cmdp = cmdlookup(name, 0);
Eric Andersen62483552001-07-10 06:09:16 +00003732 if (cmdp) printentry(cmdp, verbose=='v');
Eric Andersencb57d552001-06-28 07:25:16 +00003733 flushall();
3734 }
Eric Andersencb57d552001-06-28 07:25:16 +00003735 }
3736 return c;
3737}
3738
Eric Andersencb57d552001-06-28 07:25:16 +00003739static void
3740printentry(cmdp, verbose)
3741 struct tblentry *cmdp;
3742 int verbose;
3743 {
3744 int idx;
3745 const char *path;
3746 char *name;
3747
Eric Andersen62483552001-07-10 06:09:16 +00003748 printf("%s%s", cmdp->cmdname, (verbose ? " is " : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00003749 if (cmdp->cmdtype == CMDNORMAL) {
3750 idx = cmdp->param.index;
3751 path = pathval();
3752 do {
3753 name = padvance(&path, cmdp->cmdname);
3754 stunalloc(name);
3755 } while (--idx >= 0);
Eric Andersen62483552001-07-10 06:09:16 +00003756 if(verbose)
3757 out1str(name);
Eric Andersencb57d552001-06-28 07:25:16 +00003758 } else if (cmdp->cmdtype == CMDBUILTIN) {
Eric Andersen62483552001-07-10 06:09:16 +00003759 if(verbose)
3760 out1str("a shell builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00003761 } else if (cmdp->cmdtype == CMDFUNCTION) {
Eric Andersencb57d552001-06-28 07:25:16 +00003762 if (verbose) {
3763 INTOFF;
Eric Andersen62483552001-07-10 06:09:16 +00003764 out1str("a function\n");
Eric Andersencb57d552001-06-28 07:25:16 +00003765 name = commandtext(cmdp->param.func);
Eric Andersen62483552001-07-10 06:09:16 +00003766 printf("%s() {\n %s\n}", cmdp->cmdname, name);
Eric Andersencb57d552001-06-28 07:25:16 +00003767 ckfree(name);
3768 INTON;
3769 }
3770#ifdef DEBUG
3771 } else {
3772 error("internal error: cmdtype %d", cmdp->cmdtype);
3773#endif
3774 }
Eric Andersen62483552001-07-10 06:09:16 +00003775 printf(snlfmt, cmdp->rehash ? "*" : nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +00003776}
3777
3778
3779
Eric Andersen1c039232001-07-07 00:05:55 +00003780/*** List the available builtins ***/
3781
3782
3783static int helpcmd(int argc, char** argv)
3784{
3785 int col, i;
Eric Andersen1c039232001-07-07 00:05:55 +00003786
Eric Andersen62483552001-07-10 06:09:16 +00003787 printf("\nBuilt-in commands:\n-------------------\n");
3788 for (col=0, i=0; i < NUMBUILTINS; i++) {
3789 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3790 builtincmds[i].name+1);
Eric Andersen1c039232001-07-07 00:05:55 +00003791 if (col > 60) {
3792 printf("\n");
3793 col = 0;
3794 }
3795 }
3796#ifdef BB_FEATURE_SH_STANDALONE_SHELL
3797 {
Eric Andersen1c039232001-07-07 00:05:55 +00003798 extern const struct BB_applet applets[];
3799 extern const size_t NUM_APPLETS;
3800
Eric Andersen62483552001-07-10 06:09:16 +00003801 for (i=0; i < NUM_APPLETS; i++) {
3802
3803 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3804 applets[i].name);
Eric Andersen1c039232001-07-07 00:05:55 +00003805 if (col > 60) {
3806 printf("\n");
3807 col = 0;
3808 }
3809 }
3810 }
3811#endif
3812 printf("\n\n");
3813 return EXIT_SUCCESS;
3814}
3815
Eric Andersencb57d552001-06-28 07:25:16 +00003816/*
3817 * Resolve a command name. If you change this routine, you may have to
3818 * change the shellexec routine as well.
3819 */
3820
Eric Andersen2870d962001-07-02 17:27:21 +00003821static int prefix (const char *, const char *);
3822
Eric Andersencb57d552001-06-28 07:25:16 +00003823static void
Eric Andersen2870d962001-07-02 17:27:21 +00003824find_command(const char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003825{
3826 struct tblentry *cmdp;
3827 int idx;
3828 int prev;
3829 char *fullname;
3830 struct stat statb;
3831 int e;
3832 int bltin;
3833 int firstchange;
3834 int updatetbl;
Eric Andersen62483552001-07-10 06:09:16 +00003835 int regular;
Eric Andersencb57d552001-06-28 07:25:16 +00003836 struct builtincmd *bcmd;
3837
3838 /* If name contains a slash, don't use the hash table */
3839 if (strchr(name, '/') != NULL) {
3840 if (act & DO_ABS) {
3841 while (stat(name, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003842 if (errno != ENOENT && errno != ENOTDIR)
3843 e = errno;
3844 entry->cmdtype = CMDUNKNOWN;
3845 entry->u.index = -1;
3846 return;
3847 }
3848 entry->cmdtype = CMDNORMAL;
3849 entry->u.index = -1;
3850 return;
3851 }
3852 entry->cmdtype = CMDNORMAL;
3853 entry->u.index = 0;
3854 return;
3855 }
3856
3857 updatetbl = 1;
3858 if (act & DO_BRUTE) {
3859 firstchange = path_change(path, &bltin);
3860 } else {
3861 bltin = builtinloc;
3862 firstchange = 9999;
3863 }
3864
3865 /* If name is in the table, and not invalidated by cd, we're done */
3866 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
3867 if (cmdp->cmdtype == CMDFUNCTION) {
3868 if (act & DO_NOFUN) {
3869 updatetbl = 0;
3870 } else {
3871 goto success;
3872 }
3873 } else if (act & DO_BRUTE) {
3874 if ((cmdp->cmdtype == CMDNORMAL &&
3875 cmdp->param.index >= firstchange) ||
3876 (cmdp->cmdtype == CMDBUILTIN &&
3877 ((builtinloc < 0 && bltin >= 0) ?
3878 bltin : builtinloc) >= firstchange)) {
3879 /* need to recompute the entry */
3880 } else {
3881 goto success;
3882 }
3883 } else {
3884 goto success;
3885 }
3886 }
3887
3888 bcmd = find_builtin(name);
Eric Andersen2870d962001-07-02 17:27:21 +00003889 regular = bcmd && IS_BUILTIN_REGULAR(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00003890
3891 if (regular) {
3892 if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) {
Eric Andersen2870d962001-07-02 17:27:21 +00003893 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003894 }
3895 } else if (act & DO_BRUTE) {
3896 if (firstchange == 0) {
3897 updatetbl = 0;
3898 }
3899 }
3900
3901 /* If %builtin not in path, check for builtin next */
3902 if (regular || (bltin < 0 && bcmd)) {
3903builtin:
3904 if (!updatetbl) {
3905 entry->cmdtype = CMDBUILTIN;
3906 entry->u.cmd = bcmd;
3907 return;
3908 }
3909 INTOFF;
3910 cmdp = cmdlookup(name, 1);
3911 cmdp->cmdtype = CMDBUILTIN;
3912 cmdp->param.cmd = bcmd;
3913 INTON;
3914 goto success;
3915 }
3916
3917 /* We have to search path. */
Eric Andersen2870d962001-07-02 17:27:21 +00003918 prev = -1; /* where to start */
3919 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00003920 if (cmdp->cmdtype == CMDBUILTIN)
3921 prev = builtinloc;
3922 else
3923 prev = cmdp->param.index;
3924 }
3925
3926 e = ENOENT;
3927 idx = -1;
3928loop:
3929 while ((fullname = padvance(&path, name)) != NULL) {
3930 stunalloc(fullname);
3931 idx++;
3932 if (idx >= firstchange) {
3933 updatetbl = 0;
3934 }
3935 if (pathopt) {
3936 if (prefix("builtin", pathopt)) {
3937 if ((bcmd = find_builtin(name))) {
3938 goto builtin;
3939 }
3940 continue;
3941 } else if (!(act & DO_NOFUN) &&
3942 prefix("func", pathopt)) {
3943 /* handled below */
3944 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00003945 continue; /* ignore unimplemented options */
Eric Andersencb57d552001-06-28 07:25:16 +00003946 }
3947 }
3948 /* if rehash, don't redo absolute path names */
3949 if (fullname[0] == '/' && idx <= prev &&
3950 idx < firstchange) {
3951 if (idx < prev)
3952 continue;
3953 TRACE(("searchexec \"%s\": no change\n", name));
3954 goto success;
3955 }
3956 while (stat(fullname, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003957 if (errno != ENOENT && errno != ENOTDIR)
3958 e = errno;
3959 goto loop;
3960 }
Eric Andersen2870d962001-07-02 17:27:21 +00003961 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00003962 if (!S_ISREG(statb.st_mode))
3963 continue;
Eric Andersen2870d962001-07-02 17:27:21 +00003964 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00003965 stalloc(strlen(fullname) + 1);
3966 readcmdfile(fullname);
3967 if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
3968 error("%s not defined in %s", name, fullname);
3969 stunalloc(fullname);
3970 goto success;
3971 }
Eric Andersencb57d552001-06-28 07:25:16 +00003972 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
3973 /* If we aren't called with DO_BRUTE and cmdp is set, it must
3974 be a function and we're being called with DO_NOFUN */
3975 if (!updatetbl) {
3976 entry->cmdtype = CMDNORMAL;
3977 entry->u.index = idx;
3978 return;
3979 }
3980 INTOFF;
3981 cmdp = cmdlookup(name, 1);
3982 cmdp->cmdtype = CMDNORMAL;
3983 cmdp->param.index = idx;
3984 INTON;
3985 goto success;
3986 }
3987
3988 /* We failed. If there was an entry for this command, delete it */
3989 if (cmdp && updatetbl)
3990 delete_cmd_entry();
3991 if (act & DO_ERR)
Eric Andersen3102ac42001-07-06 04:26:23 +00003992 out2fmt("%s: %s\n", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00003993 entry->cmdtype = CMDUNKNOWN;
3994 return;
3995
3996success:
3997 cmdp->rehash = 0;
3998 entry->cmdtype = cmdp->cmdtype;
3999 entry->u = cmdp->param;
4000}
4001
4002
4003
4004/*
4005 * Search the table of builtin commands.
4006 */
4007
Eric Andersen2870d962001-07-02 17:27:21 +00004008static int
4009bstrcmp(const void *name, const void *b)
4010{
4011 return strcmp((const char *)name, (*(const char *const *) b)+1);
4012}
4013
4014static struct builtincmd *
4015find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00004016{
4017 struct builtincmd *bp;
4018
Eric Andersen2870d962001-07-02 17:27:21 +00004019 bp = bsearch(name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd),
4020 bstrcmp
Eric Andersencb57d552001-06-28 07:25:16 +00004021 );
4022 return bp;
4023}
4024
4025
4026/*
4027 * Called when a cd is done. Marks all commands so the next time they
4028 * are executed they will be rehashed.
4029 */
4030
4031static void
Eric Andersen2870d962001-07-02 17:27:21 +00004032hashcd(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00004033 struct tblentry **pp;
4034 struct tblentry *cmdp;
4035
4036 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4037 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4038 if (cmdp->cmdtype == CMDNORMAL
4039 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
4040 cmdp->rehash = 1;
4041 }
4042 }
4043}
4044
4045
4046
4047/*
4048 * Called before PATH is changed. The argument is the new value of PATH;
4049 * pathval() still returns the old value at this point. Called with
4050 * interrupts off.
4051 */
4052
4053static void
Eric Andersen2870d962001-07-02 17:27:21 +00004054changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00004055{
4056 int firstchange;
4057 int bltin;
4058
4059 firstchange = path_change(newval, &bltin);
4060 if (builtinloc < 0 && bltin >= 0)
Eric Andersen2870d962001-07-02 17:27:21 +00004061 builtinloc = bltin; /* zap builtins */
Eric Andersencb57d552001-06-28 07:25:16 +00004062 clearcmdentry(firstchange);
4063 builtinloc = bltin;
4064}
4065
4066
4067/*
4068 * Clear out command entries. The argument specifies the first entry in
4069 * PATH which has changed.
4070 */
4071
4072static void
4073clearcmdentry(firstchange)
4074 int firstchange;
4075{
4076 struct tblentry **tblp;
4077 struct tblentry **pp;
4078 struct tblentry *cmdp;
4079
4080 INTOFF;
4081 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4082 pp = tblp;
4083 while ((cmdp = *pp) != NULL) {
4084 if ((cmdp->cmdtype == CMDNORMAL &&
4085 cmdp->param.index >= firstchange)
4086 || (cmdp->cmdtype == CMDBUILTIN &&
4087 builtinloc >= firstchange)) {
4088 *pp = cmdp->next;
4089 ckfree(cmdp);
4090 } else {
4091 pp = &cmdp->next;
4092 }
4093 }
4094 }
4095 INTON;
4096}
4097
4098
4099/*
4100 * Delete all functions.
4101 */
4102
Eric Andersencb57d552001-06-28 07:25:16 +00004103static void
Eric Andersen2870d962001-07-02 17:27:21 +00004104deletefuncs(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00004105 struct tblentry **tblp;
4106 struct tblentry **pp;
4107 struct tblentry *cmdp;
4108
4109 INTOFF;
4110 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4111 pp = tblp;
4112 while ((cmdp = *pp) != NULL) {
4113 if (cmdp->cmdtype == CMDFUNCTION) {
4114 *pp = cmdp->next;
4115 freefunc(cmdp->param.func);
4116 ckfree(cmdp);
4117 } else {
4118 pp = &cmdp->next;
4119 }
4120 }
4121 }
4122 INTON;
4123}
4124
4125
4126
4127/*
4128 * Locate a command in the command hash table. If "add" is nonzero,
4129 * add the command to the table if it is not already present. The
4130 * variable "lastcmdentry" is set to point to the address of the link
4131 * pointing to the entry, so that delete_cmd_entry can delete the
4132 * entry.
4133 */
4134
Eric Andersen2870d962001-07-02 17:27:21 +00004135static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00004136
4137static struct tblentry *
Eric Andersen2870d962001-07-02 17:27:21 +00004138cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00004139{
4140 int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00004141 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00004142 struct tblentry *cmdp;
4143 struct tblentry **pp;
4144
4145 p = name;
4146 hashval = *p << 4;
4147 while (*p)
4148 hashval += *p++;
4149 hashval &= 0x7FFF;
4150 pp = &cmdtable[hashval % CMDTABLESIZE];
4151 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4152 if (equal(cmdp->cmdname, name))
4153 break;
4154 pp = &cmdp->next;
4155 }
4156 if (add && cmdp == NULL) {
4157 INTOFF;
4158 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4159 + strlen(name) + 1);
4160 cmdp->next = NULL;
4161 cmdp->cmdtype = CMDUNKNOWN;
4162 cmdp->rehash = 0;
4163 strcpy(cmdp->cmdname, name);
4164 INTON;
4165 }
4166 lastcmdentry = pp;
4167 return cmdp;
4168}
4169
4170/*
4171 * Delete the command entry returned on the last lookup.
4172 */
4173
4174static void
4175delete_cmd_entry() {
4176 struct tblentry *cmdp;
4177
4178 INTOFF;
4179 cmdp = *lastcmdentry;
4180 *lastcmdentry = cmdp->next;
4181 ckfree(cmdp);
4182 INTON;
4183}
4184
4185
4186
Eric Andersencb57d552001-06-28 07:25:16 +00004187
4188
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004189static const unsigned char nodesize[26] = {
Eric Andersen62483552001-07-10 06:09:16 +00004190 ALIGN(sizeof (struct nbinary)),
4191 ALIGN(sizeof (struct ncmd)),
4192 ALIGN(sizeof (struct npipe)),
4193 ALIGN(sizeof (struct nredir)),
4194 ALIGN(sizeof (struct nredir)),
4195 ALIGN(sizeof (struct nredir)),
4196 ALIGN(sizeof (struct nbinary)),
4197 ALIGN(sizeof (struct nbinary)),
4198 ALIGN(sizeof (struct nif)),
4199 ALIGN(sizeof (struct nbinary)),
4200 ALIGN(sizeof (struct nbinary)),
4201 ALIGN(sizeof (struct nfor)),
4202 ALIGN(sizeof (struct ncase)),
4203 ALIGN(sizeof (struct nclist)),
4204 ALIGN(sizeof (struct narg)),
4205 ALIGN(sizeof (struct narg)),
4206 ALIGN(sizeof (struct nfile)),
4207 ALIGN(sizeof (struct nfile)),
4208 ALIGN(sizeof (struct nfile)),
4209 ALIGN(sizeof (struct nfile)),
4210 ALIGN(sizeof (struct nfile)),
4211 ALIGN(sizeof (struct ndup)),
4212 ALIGN(sizeof (struct ndup)),
4213 ALIGN(sizeof (struct nhere)),
4214 ALIGN(sizeof (struct nhere)),
4215 ALIGN(sizeof (struct nnot)),
4216};
Eric Andersencb57d552001-06-28 07:25:16 +00004217
Eric Andersencb57d552001-06-28 07:25:16 +00004218
4219
4220/*
4221 * Delete a function if it exists.
4222 */
4223
4224static void
Eric Andersen2870d962001-07-02 17:27:21 +00004225unsetfunc(char *name)
4226{
Eric Andersencb57d552001-06-28 07:25:16 +00004227 struct tblentry *cmdp;
4228
4229 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
4230 freefunc(cmdp->param.func);
4231 delete_cmd_entry();
4232 }
4233}
4234
Eric Andersen2870d962001-07-02 17:27:21 +00004235
4236/*
Eric Andersencb57d552001-06-28 07:25:16 +00004237 * Locate and print what a word is...
4238 */
4239
4240static int
Eric Andersen62483552001-07-10 06:09:16 +00004241typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004242{
4243 int i;
4244 int err = 0;
Eric Andersen62483552001-07-10 06:09:16 +00004245 char *argv_a[2];
4246
4247 argv_a[1] = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004248
4249 for (i = 1; i < argc; i++) {
Eric Andersen62483552001-07-10 06:09:16 +00004250 argv_a[0] = argv[i];
4251 argptr = argv_a;
4252 optptr = "v";
4253 err |= hashcmd(argc, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00004254 }
4255 return err;
4256}
4257
Eric Andersen2870d962001-07-02 17:27:21 +00004258#ifdef ASH_CMDCMD
Eric Andersencb57d552001-06-28 07:25:16 +00004259static int
4260commandcmd(argc, argv)
4261 int argc;
4262 char **argv;
4263{
4264 int c;
4265 int default_path = 0;
4266 int verify_only = 0;
4267 int verbose_verify_only = 0;
4268
4269 while ((c = nextopt("pvV")) != '\0')
4270 switch (c) {
4271 case 'p':
4272 default_path = 1;
4273 break;
4274 case 'v':
4275 verify_only = 1;
4276 break;
4277 case 'V':
4278 verbose_verify_only = 1;
4279 break;
Eric Andersencb57d552001-06-28 07:25:16 +00004280 }
4281
4282 if (default_path + verify_only + verbose_verify_only > 1 ||
4283 !*argptr) {
Eric Andersen62483552001-07-10 06:09:16 +00004284 out2str(
4285 "command [-p] command [arg ...]\n"
4286 "command {-v|-V} command\n");
Eric Andersencb57d552001-06-28 07:25:16 +00004287 return EX_USAGE;
4288 }
4289
Eric Andersencb57d552001-06-28 07:25:16 +00004290 if (verify_only || verbose_verify_only) {
Eric Andersen62483552001-07-10 06:09:16 +00004291 char *argv_a[2];
4292
4293 argv_a[1] = 0;
4294 argv_a[0] = *argptr;
4295 argptr = argv_a;
4296 optptr = verbose_verify_only ? "v" : "V"; /* reverse special */
4297 return hashcmd(argc, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00004298 }
Eric Andersencb57d552001-06-28 07:25:16 +00004299
4300 return 0;
4301}
Eric Andersen2870d962001-07-02 17:27:21 +00004302#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004303
4304static int
4305path_change(newval, bltin)
4306 const char *newval;
4307 int *bltin;
4308{
4309 const char *old, *new;
4310 int idx;
4311 int firstchange;
4312
4313 old = pathval();
4314 new = newval;
Eric Andersen2870d962001-07-02 17:27:21 +00004315 firstchange = 9999; /* assume no change */
Eric Andersencb57d552001-06-28 07:25:16 +00004316 idx = 0;
4317 *bltin = -1;
4318 for (;;) {
4319 if (*old != *new) {
4320 firstchange = idx;
4321 if ((*old == '\0' && *new == ':')
4322 || (*old == ':' && *new == '\0'))
4323 firstchange++;
Eric Andersen2870d962001-07-02 17:27:21 +00004324 old = new; /* ignore subsequent differences */
Eric Andersencb57d552001-06-28 07:25:16 +00004325 }
4326 if (*new == '\0')
4327 break;
4328 if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1))
4329 *bltin = idx;
4330 if (*new == ':') {
4331 idx++;
4332 }
4333 new++, old++;
4334 }
4335 if (builtinloc >= 0 && *bltin < 0)
4336 firstchange = 0;
4337 return firstchange;
4338}
Eric Andersencb57d552001-06-28 07:25:16 +00004339/*
4340 * Routines to expand arguments to commands. We have to deal with
4341 * backquotes, shell variables, and file metacharacters.
4342 */
4343/*
4344 * _rmescape() flags
4345 */
Eric Andersen2870d962001-07-02 17:27:21 +00004346#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4347#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Eric Andersencb57d552001-06-28 07:25:16 +00004348
4349/*
4350 * Structure specifying which parts of the string should be searched
4351 * for IFS characters.
4352 */
4353
4354struct ifsregion {
Eric Andersen2870d962001-07-02 17:27:21 +00004355 struct ifsregion *next; /* next region in list */
4356 int begoff; /* offset of start of region */
4357 int endoff; /* offset of end of region */
4358 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004359};
4360
4361
Eric Andersen2870d962001-07-02 17:27:21 +00004362static char *expdest; /* output of current string */
4363static struct nodelist *argbackq; /* list of back quote expressions */
4364static struct ifsregion ifsfirst; /* first struct in list of ifs regions */
4365static struct ifsregion *ifslastp; /* last struct in list */
4366static struct arglist exparg; /* holds expanded arg list */
Eric Andersencb57d552001-06-28 07:25:16 +00004367
Eric Andersen2870d962001-07-02 17:27:21 +00004368static void argstr (char *, int);
4369static char *exptilde (char *, int);
4370static void expbackq (union node *, int, int);
4371static int subevalvar (char *, char *, int, int, int, int, int);
Eric Andersen2870d962001-07-02 17:27:21 +00004372static int varisset (char *, int);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004373static void strtodest (const char *, int, int);
Eric Andersen2870d962001-07-02 17:27:21 +00004374static void varvalue (char *, int, int);
4375static void recordregion (int, int, int);
4376static void removerecordregions (int);
4377static void ifsbreakup (char *, struct arglist *);
4378static void ifsfree (void);
4379static void expandmeta (struct strlist *, int);
Eric Andersen62483552001-07-10 06:09:16 +00004380#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00004381#define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB)
4382#if !defined(GLOB_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00004383static void addglob (const glob_t *);
Eric Andersencb57d552001-06-28 07:25:16 +00004384#endif
4385#endif
Eric Andersen62483552001-07-10 06:09:16 +00004386#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersen2870d962001-07-02 17:27:21 +00004387static void expmeta (char *, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004388#endif
Eric Andersen62483552001-07-10 06:09:16 +00004389#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersen2870d962001-07-02 17:27:21 +00004390static struct strlist *expsort (struct strlist *);
4391static struct strlist *msort (struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004392#endif
Eric Andersen2870d962001-07-02 17:27:21 +00004393static int patmatch (char *, char *, int);
Eric Andersen62483552001-07-10 06:09:16 +00004394#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00004395static int patmatch2 (char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004396#else
Eric Andersen2870d962001-07-02 17:27:21 +00004397static int pmatch (char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004398#define patmatch2 patmatch
4399#endif
Eric Andersen2870d962001-07-02 17:27:21 +00004400static char *cvtnum (int, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004401
4402/*
4403 * Expand shell variables and backquotes inside a here document.
4404 */
4405
Eric Andersen2870d962001-07-02 17:27:21 +00004406/* arg: the document, fd: where to write the expanded version */
Eric Andersen62483552001-07-10 06:09:16 +00004407static inline void
Eric Andersen2870d962001-07-02 17:27:21 +00004408expandhere(union node *arg, int fd)
4409{
Eric Andersencb57d552001-06-28 07:25:16 +00004410 herefd = fd;
4411 expandarg(arg, (struct arglist *)NULL, 0);
4412 xwrite(fd, stackblock(), expdest - stackblock());
4413}
4414
4415
4416/*
4417 * Perform variable substitution and command substitution on an argument,
4418 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4419 * perform splitting and file name expansion. When arglist is NULL, perform
4420 * here document expansion.
4421 */
4422
4423static void
4424expandarg(arg, arglist, flag)
4425 union node *arg;
4426 struct arglist *arglist;
4427 int flag;
4428{
4429 struct strlist *sp;
4430 char *p;
4431
4432 argbackq = arg->narg.backquote;
4433 STARTSTACKSTR(expdest);
4434 ifsfirst.next = NULL;
4435 ifslastp = NULL;
4436 argstr(arg->narg.text, flag);
4437 if (arglist == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00004438 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004439 }
4440 STPUTC('\0', expdest);
4441 p = grabstackstr(expdest);
4442 exparg.lastp = &exparg.list;
4443 /*
4444 * TODO - EXP_REDIR
4445 */
4446 if (flag & EXP_FULL) {
4447 ifsbreakup(p, &exparg);
4448 *exparg.lastp = NULL;
4449 exparg.lastp = &exparg.list;
4450 expandmeta(exparg.list, flag);
4451 } else {
4452 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4453 rmescapes(p);
4454 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4455 sp->text = p;
4456 *exparg.lastp = sp;
4457 exparg.lastp = &sp->next;
4458 }
4459 ifsfree();
4460 *exparg.lastp = NULL;
4461 if (exparg.list) {
4462 *arglist->lastp = exparg.list;
4463 arglist->lastp = exparg.lastp;
4464 }
4465}
4466
4467
Eric Andersen62483552001-07-10 06:09:16 +00004468/*
4469 * Expand a variable, and return a pointer to the next character in the
4470 * input string.
4471 */
4472
4473static inline char *
4474evalvar(p, flag)
4475 char *p;
4476 int flag;
4477{
4478 int subtype;
4479 int varflags;
4480 char *var;
4481 const char *val;
4482 int patloc;
4483 int c;
4484 int set;
4485 int special;
4486 int startloc;
4487 int varlen;
4488 int easy;
4489 int quotes = flag & (EXP_FULL | EXP_CASE);
4490
4491 varflags = *p++;
4492 subtype = varflags & VSTYPE;
4493 var = p;
4494 special = 0;
4495 if (! is_name(*p))
4496 special = 1;
4497 p = strchr(p, '=') + 1;
4498again: /* jump here after setting a variable with ${var=text} */
4499 if (special) {
4500 set = varisset(var, varflags & VSNUL);
4501 val = NULL;
4502 } else {
4503 val = lookupvar(var);
4504 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
4505 val = NULL;
4506 set = 0;
4507 } else
4508 set = 1;
4509 }
4510 varlen = 0;
4511 startloc = expdest - stackblock();
4512 if (set && subtype != VSPLUS) {
4513 /* insert the value of the variable */
4514 if (special) {
4515 varvalue(var, varflags & VSQUOTE, flag);
4516 if (subtype == VSLENGTH) {
4517 varlen = expdest - stackblock() - startloc;
4518 STADJUST(-varlen, expdest);
4519 }
4520 } else {
4521 if (subtype == VSLENGTH) {
4522 varlen = strlen(val);
4523 } else {
4524 strtodest(
4525 val,
4526 varflags & VSQUOTE ?
4527 DQSYNTAX : BASESYNTAX,
4528 quotes
4529 );
4530 }
4531 }
4532 }
4533
4534 if (subtype == VSPLUS)
4535 set = ! set;
4536
4537 easy = ((varflags & VSQUOTE) == 0 ||
4538 (*var == '@' && shellparam.nparam != 1));
4539
4540
4541 switch (subtype) {
4542 case VSLENGTH:
4543 expdest = cvtnum(varlen, expdest);
4544 goto record;
4545
4546 case VSNORMAL:
4547 if (!easy)
4548 break;
4549record:
4550 recordregion(startloc, expdest - stackblock(),
4551 varflags & VSQUOTE);
4552 break;
4553
4554 case VSPLUS:
4555 case VSMINUS:
4556 if (!set) {
4557 argstr(p, flag);
4558 break;
4559 }
4560 if (easy)
4561 goto record;
4562 break;
4563
4564 case VSTRIMLEFT:
4565 case VSTRIMLEFTMAX:
4566 case VSTRIMRIGHT:
4567 case VSTRIMRIGHTMAX:
4568 if (!set)
4569 break;
4570 /*
4571 * Terminate the string and start recording the pattern
4572 * right after it
4573 */
4574 STPUTC('\0', expdest);
4575 patloc = expdest - stackblock();
4576 if (subevalvar(p, NULL, patloc, subtype,
4577 startloc, varflags, quotes) == 0) {
4578 int amount = (expdest - stackblock() - patloc) + 1;
4579 STADJUST(-amount, expdest);
4580 }
4581 /* Remove any recorded regions beyond start of variable */
4582 removerecordregions(startloc);
4583 goto record;
4584
4585 case VSASSIGN:
4586 case VSQUESTION:
4587 if (!set) {
4588 if (subevalvar(p, var, 0, subtype, startloc,
4589 varflags, quotes)) {
4590 varflags &= ~VSNUL;
4591 /*
4592 * Remove any recorded regions beyond
4593 * start of variable
4594 */
4595 removerecordregions(startloc);
4596 goto again;
4597 }
4598 break;
4599 }
4600 if (easy)
4601 goto record;
4602 break;
4603
4604#ifdef DEBUG
4605 default:
4606 abort();
4607#endif
4608 }
4609
4610 if (subtype != VSNORMAL) { /* skip to end of alternative */
4611 int nesting = 1;
4612 for (;;) {
4613 if ((c = *p++) == CTLESC)
4614 p++;
4615 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
4616 if (set)
4617 argbackq = argbackq->next;
4618 } else if (c == CTLVAR) {
4619 if ((*p++ & VSTYPE) != VSNORMAL)
4620 nesting++;
4621 } else if (c == CTLENDVAR) {
4622 if (--nesting == 0)
4623 break;
4624 }
4625 }
4626 }
4627 return p;
4628}
4629
Eric Andersencb57d552001-06-28 07:25:16 +00004630
4631/*
4632 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4633 * characters to allow for further processing. Otherwise treat
4634 * $@ like $* since no splitting will be performed.
4635 */
4636
4637static void
4638argstr(p, flag)
4639 char *p;
4640 int flag;
4641{
4642 char c;
Eric Andersen2870d962001-07-02 17:27:21 +00004643 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
Eric Andersencb57d552001-06-28 07:25:16 +00004644 int firsteq = 1;
4645
4646 if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
4647 p = exptilde(p, flag);
4648 for (;;) {
4649 switch (c = *p++) {
4650 case '\0':
4651 case CTLENDVAR: /* ??? */
4652 goto breakloop;
4653 case CTLQUOTEMARK:
4654 /* "$@" syntax adherence hack */
4655 if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
4656 break;
4657 if ((flag & EXP_FULL) != 0)
4658 STPUTC(c, expdest);
4659 break;
4660 case CTLESC:
4661 if (quotes)
4662 STPUTC(c, expdest);
4663 c = *p++;
4664 STPUTC(c, expdest);
4665 break;
4666 case CTLVAR:
4667 p = evalvar(p, flag);
4668 break;
4669 case CTLBACKQ:
4670 case CTLBACKQ|CTLQUOTE:
4671 expbackq(argbackq->n, c & CTLQUOTE, flag);
4672 argbackq = argbackq->next;
4673 break;
4674#ifdef ASH_MATH_SUPPORT
4675 case CTLENDARI:
4676 expari(flag);
4677 break;
Eric Andersen2870d962001-07-02 17:27:21 +00004678#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004679 case ':':
4680 case '=':
4681 /*
4682 * sort of a hack - expand tildes in variable
4683 * assignments (after the first '=' and after ':'s).
4684 */
4685 STPUTC(c, expdest);
4686 if (flag & EXP_VARTILDE && *p == '~') {
4687 if (c == '=') {
4688 if (firsteq)
4689 firsteq = 0;
4690 else
4691 break;
4692 }
4693 p = exptilde(p, flag);
4694 }
4695 break;
4696 default:
4697 STPUTC(c, expdest);
4698 }
4699 }
4700breakloop:;
4701 return;
4702}
4703
4704static char *
4705exptilde(p, flag)
4706 char *p;
4707 int flag;
4708{
4709 char c, *startp = p;
4710 struct passwd *pw;
4711 const char *home;
4712 int quotes = flag & (EXP_FULL | EXP_CASE);
4713
4714 while ((c = *p) != '\0') {
4715 switch(c) {
4716 case CTLESC:
4717 return (startp);
4718 case CTLQUOTEMARK:
4719 return (startp);
4720 case ':':
4721 if (flag & EXP_VARTILDE)
4722 goto done;
4723 break;
4724 case '/':
4725 goto done;
4726 }
4727 p++;
4728 }
4729done:
4730 *p = '\0';
4731 if (*(startp+1) == '\0') {
4732 if ((home = lookupvar("HOME")) == NULL)
4733 goto lose;
4734 } else {
4735 if ((pw = getpwnam(startp+1)) == NULL)
4736 goto lose;
4737 home = pw->pw_dir;
4738 }
4739 if (*home == '\0')
4740 goto lose;
4741 *p = c;
4742 strtodest(home, SQSYNTAX, quotes);
4743 return (p);
4744lose:
4745 *p = c;
4746 return (startp);
4747}
4748
4749
Eric Andersen2870d962001-07-02 17:27:21 +00004750static void
4751removerecordregions(int endoff)
Eric Andersencb57d552001-06-28 07:25:16 +00004752{
4753 if (ifslastp == NULL)
4754 return;
4755
4756 if (ifsfirst.endoff > endoff) {
4757 while (ifsfirst.next != NULL) {
4758 struct ifsregion *ifsp;
4759 INTOFF;
4760 ifsp = ifsfirst.next->next;
4761 ckfree(ifsfirst.next);
4762 ifsfirst.next = ifsp;
4763 INTON;
4764 }
4765 if (ifsfirst.begoff > endoff)
4766 ifslastp = NULL;
4767 else {
4768 ifslastp = &ifsfirst;
4769 ifsfirst.endoff = endoff;
4770 }
4771 return;
4772 }
Eric Andersen2870d962001-07-02 17:27:21 +00004773
Eric Andersencb57d552001-06-28 07:25:16 +00004774 ifslastp = &ifsfirst;
4775 while (ifslastp->next && ifslastp->next->begoff < endoff)
4776 ifslastp=ifslastp->next;
4777 while (ifslastp->next != NULL) {
4778 struct ifsregion *ifsp;
4779 INTOFF;
4780 ifsp = ifslastp->next->next;
4781 ckfree(ifslastp->next);
4782 ifslastp->next = ifsp;
4783 INTON;
4784 }
4785 if (ifslastp->endoff > endoff)
4786 ifslastp->endoff = endoff;
4787}
4788
4789
4790#ifdef ASH_MATH_SUPPORT
4791/*
4792 * Expand arithmetic expression. Backup to start of expression,
4793 * evaluate, place result in (backed up) result, adjust string position.
4794 */
4795static void
Eric Andersen2870d962001-07-02 17:27:21 +00004796expari(int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004797{
4798 char *p, *start;
Eric Andersen34506362001-08-02 05:02:46 +00004799 int errcode;
Eric Andersencb57d552001-06-28 07:25:16 +00004800 int result;
4801 int begoff;
4802 int quotes = flag & (EXP_FULL | EXP_CASE);
4803 int quoted;
4804
Eric Andersen2870d962001-07-02 17:27:21 +00004805 /* ifsfree(); */
Eric Andersencb57d552001-06-28 07:25:16 +00004806
4807 /*
4808 * This routine is slightly over-complicated for
4809 * efficiency. First we make sure there is
4810 * enough space for the result, which may be bigger
4811 * than the expression if we add exponentation. Next we
4812 * scan backwards looking for the start of arithmetic. If the
4813 * next previous character is a CTLESC character, then we
4814 * have to rescan starting from the beginning since CTLESC
4815 * characters have to be processed left to right.
4816 */
4817 CHECKSTRSPACE(10, expdest);
4818 USTPUTC('\0', expdest);
4819 start = stackblock();
4820 p = expdest - 1;
4821 while (*p != CTLARI && p >= start)
4822 --p;
4823 if (*p != CTLARI)
4824 error("missing CTLARI (shouldn't happen)");
4825 if (p > start && *(p-1) == CTLESC)
4826 for (p = start; *p != CTLARI; p++)
4827 if (*p == CTLESC)
4828 p++;
4829
4830 if (p[1] == '"')
4831 quoted=1;
4832 else
4833 quoted=0;
4834 begoff = p - start;
4835 removerecordregions(begoff);
4836 if (quotes)
4837 rmescapes(p+2);
Eric Andersen34506362001-08-02 05:02:46 +00004838 result = arith(p+2, &errcode);
4839 if (errcode < 0) {
4840 if(errcode == -2)
4841 error("divide by zero");
4842 else
4843 error("syntax error: \"%s\"\n", p+2);
4844 }
Eric Andersen3102ac42001-07-06 04:26:23 +00004845 snprintf(p, 12, "%d", result);
Eric Andersencb57d552001-06-28 07:25:16 +00004846
4847 while (*p++)
4848 ;
4849
4850 if (quoted == 0)
4851 recordregion(begoff, p - 1 - start, 0);
4852 result = expdest - p + 1;
4853 STADJUST(-result, expdest);
4854}
Eric Andersen2870d962001-07-02 17:27:21 +00004855#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004856
4857/*
4858 * Expand stuff in backwards quotes.
4859 */
4860
4861static void
4862expbackq(cmd, quoted, flag)
4863 union node *cmd;
4864 int quoted;
4865 int flag;
4866{
4867 volatile struct backcmd in;
4868 int i;
4869 char buf[128];
4870 char *p;
4871 char *dest = expdest;
4872 volatile struct ifsregion saveifs;
4873 struct ifsregion *volatile savelastp;
4874 struct nodelist *volatile saveargbackq;
4875 char lastc;
4876 int startloc = dest - stackblock();
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004877 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +00004878 volatile int saveherefd;
4879 int quotes = flag & (EXP_FULL | EXP_CASE);
4880 struct jmploc jmploc;
4881 struct jmploc *volatile savehandler;
4882 int ex;
4883
4884#if __GNUC__
4885 /* Avoid longjmp clobbering */
4886 (void) &dest;
4887 (void) &syntax;
4888#endif
4889
4890 in.fd = -1;
4891 in.buf = 0;
4892 in.jp = 0;
4893
4894 INTOFF;
4895 saveifs = ifsfirst;
4896 savelastp = ifslastp;
4897 saveargbackq = argbackq;
4898 saveherefd = herefd;
4899 herefd = -1;
4900 if ((ex = setjmp(jmploc.loc))) {
4901 goto err1;
4902 }
4903 savehandler = handler;
4904 handler = &jmploc;
4905 INTON;
4906 p = grabstackstr(dest);
4907 evalbackcmd(cmd, (struct backcmd *) &in);
4908 ungrabstackstr(p, dest);
4909err1:
4910 INTOFF;
4911 ifsfirst = saveifs;
4912 ifslastp = savelastp;
4913 argbackq = saveargbackq;
4914 herefd = saveherefd;
4915 if (ex) {
4916 goto err2;
4917 }
4918
4919 p = in.buf;
4920 lastc = '\0';
4921 for (;;) {
4922 if (--in.nleft < 0) {
4923 if (in.fd < 0)
4924 break;
Eric Andersen7467c8d2001-07-12 20:26:32 +00004925 i = safe_read(in.fd, buf, sizeof buf);
Eric Andersencb57d552001-06-28 07:25:16 +00004926 TRACE(("expbackq: read returns %d\n", i));
4927 if (i <= 0)
4928 break;
4929 p = buf;
4930 in.nleft = i - 1;
4931 }
4932 lastc = *p++;
4933 if (lastc != '\0') {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004934 if (quotes && SIT(lastc, syntax) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +00004935 STPUTC(CTLESC, dest);
4936 STPUTC(lastc, dest);
4937 }
4938 }
4939
4940 /* Eat all trailing newlines */
4941 for (; dest > stackblock() && dest[-1] == '\n';)
4942 STUNPUTC(dest);
4943
4944err2:
4945 if (in.fd >= 0)
4946 close(in.fd);
4947 if (in.buf)
4948 ckfree(in.buf);
4949 if (in.jp)
4950 exitstatus = waitforjob(in.jp);
4951 handler = savehandler;
4952 if (ex) {
4953 longjmp(handler->loc, 1);
4954 }
4955 if (quoted == 0)
4956 recordregion(startloc, dest - stackblock(), 0);
4957 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4958 (dest - stackblock()) - startloc,
4959 (dest - stackblock()) - startloc,
4960 stackblock() + startloc));
4961 expdest = dest;
4962 INTON;
4963}
4964
Eric Andersencb57d552001-06-28 07:25:16 +00004965static int
4966subevalvar(p, str, strloc, subtype, startloc, varflags, quotes)
4967 char *p;
4968 char *str;
4969 int strloc;
4970 int subtype;
4971 int startloc;
4972 int varflags;
4973 int quotes;
4974{
4975 char *startp;
4976 char *loc = NULL;
4977 char *q;
4978 int c = 0;
4979 int saveherefd = herefd;
4980 struct nodelist *saveargbackq = argbackq;
4981 int amount;
4982
4983 herefd = -1;
4984 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
4985 STACKSTRNUL(expdest);
4986 herefd = saveherefd;
4987 argbackq = saveargbackq;
4988 startp = stackblock() + startloc;
4989 if (str == NULL)
4990 str = stackblock() + strloc;
4991
4992 switch (subtype) {
4993 case VSASSIGN:
4994 setvar(str, startp, 0);
4995 amount = startp - expdest;
4996 STADJUST(amount, expdest);
4997 varflags &= ~VSNUL;
4998 if (c != 0)
4999 *loc = c;
5000 return 1;
5001
5002 case VSQUESTION:
5003 if (*p != CTLENDVAR) {
Eric Andersen3102ac42001-07-06 04:26:23 +00005004 out2fmt(snlfmt, startp);
Eric Andersencb57d552001-06-28 07:25:16 +00005005 error((char *)NULL);
5006 }
5007 error("%.*s: parameter %snot set", p - str - 1,
5008 str, (varflags & VSNUL) ? "null or "
5009 : nullstr);
5010 /* NOTREACHED */
5011
5012 case VSTRIMLEFT:
5013 for (loc = startp; loc < str; loc++) {
5014 c = *loc;
5015 *loc = '\0';
5016 if (patmatch2(str, startp, quotes))
5017 goto recordleft;
5018 *loc = c;
5019 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00005020 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00005021 }
5022 return 0;
5023
5024 case VSTRIMLEFTMAX:
5025 for (loc = str - 1; loc >= startp;) {
5026 c = *loc;
5027 *loc = '\0';
5028 if (patmatch2(str, startp, quotes))
5029 goto recordleft;
5030 *loc = c;
5031 loc--;
5032 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
5033 for (q = startp; q < loc; q++)
5034 if (*q == CTLESC)
5035 q++;
5036 if (q > loc)
5037 loc--;
5038 }
5039 }
5040 return 0;
5041
5042 case VSTRIMRIGHT:
Eric Andersen2870d962001-07-02 17:27:21 +00005043 for (loc = str - 1; loc >= startp;) {
Eric Andersencb57d552001-06-28 07:25:16 +00005044 if (patmatch2(str, loc, quotes))
5045 goto recordright;
5046 loc--;
Eric Andersen2870d962001-07-02 17:27:21 +00005047 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
Eric Andersencb57d552001-06-28 07:25:16 +00005048 for (q = startp; q < loc; q++)
5049 if (*q == CTLESC)
5050 q++;
5051 if (q > loc)
5052 loc--;
5053 }
5054 }
5055 return 0;
5056
5057 case VSTRIMRIGHTMAX:
5058 for (loc = startp; loc < str - 1; loc++) {
5059 if (patmatch2(str, loc, quotes))
5060 goto recordright;
5061 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00005062 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00005063 }
5064 return 0;
5065
5066#ifdef DEBUG
5067 default:
5068 abort();
5069#endif
5070 }
5071
5072recordleft:
5073 *loc = c;
5074 amount = ((str - 1) - (loc - startp)) - expdest;
5075 STADJUST(amount, expdest);
5076 while (loc != str - 1)
5077 *startp++ = *loc++;
5078 return 1;
5079
5080recordright:
5081 amount = loc - expdest;
5082 STADJUST(amount, expdest);
5083 STPUTC('\0', expdest);
5084 STADJUST(-1, expdest);
5085 return 1;
5086}
5087
5088
5089/*
Eric Andersencb57d552001-06-28 07:25:16 +00005090 * Test whether a specialized variable is set.
5091 */
5092
5093static int
5094varisset(name, nulok)
5095 char *name;
5096 int nulok;
5097{
5098 if (*name == '!')
5099 return backgndpid != -1;
5100 else if (*name == '@' || *name == '*') {
5101 if (*shellparam.p == NULL)
5102 return 0;
5103
5104 if (nulok) {
5105 char **av;
5106
5107 for (av = shellparam.p; *av; av++)
5108 if (**av != '\0')
5109 return 1;
5110 return 0;
5111 }
5112 } else if (is_digit(*name)) {
5113 char *ap;
5114 int num = atoi(name);
5115
5116 if (num > shellparam.nparam)
5117 return 0;
5118
5119 if (num == 0)
5120 ap = arg0;
5121 else
5122 ap = shellparam.p[num - 1];
5123
5124 if (nulok && (ap == NULL || *ap == '\0'))
5125 return 0;
5126 }
5127 return 1;
5128}
5129
Eric Andersencb57d552001-06-28 07:25:16 +00005130/*
5131 * Put a string on the stack.
5132 */
5133
5134static void
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005135strtodest(const char *p, int syntax, int quotes)
Eric Andersencb57d552001-06-28 07:25:16 +00005136{
5137 while (*p) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005138 if (quotes && SIT(*p,syntax) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +00005139 STPUTC(CTLESC, expdest);
5140 STPUTC(*p++, expdest);
5141 }
5142}
5143
Eric Andersencb57d552001-06-28 07:25:16 +00005144/*
5145 * Add the value of a specialized variable to the stack string.
5146 */
5147
5148static void
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005149varvalue(char *name, int quoted, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00005150{
5151 int num;
5152 char *p;
5153 int i;
5154 int sep;
5155 int sepq = 0;
5156 char **ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005157 int syntax;
Eric Andersencb57d552001-06-28 07:25:16 +00005158 int allow_split = flags & EXP_FULL;
5159 int quotes = flags & (EXP_FULL | EXP_CASE);
5160
5161 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5162 switch (*name) {
5163 case '$':
5164 num = rootpid;
5165 goto numvar;
5166 case '?':
5167 num = oexitstatus;
5168 goto numvar;
5169 case '#':
5170 num = shellparam.nparam;
5171 goto numvar;
5172 case '!':
5173 num = backgndpid;
5174numvar:
5175 expdest = cvtnum(num, expdest);
5176 break;
5177 case '-':
5178 for (i = 0 ; i < NOPTS ; i++) {
Eric Andersen2870d962001-07-02 17:27:21 +00005179 if (optent_val(i))
5180 STPUTC(optent_letter(optlist[i]), expdest);
Eric Andersencb57d552001-06-28 07:25:16 +00005181 }
5182 break;
5183 case '@':
5184 if (allow_split && quoted) {
5185 sep = 1 << CHAR_BIT;
5186 goto param;
5187 }
5188 /* fall through */
5189 case '*':
5190 sep = ifsset() ? ifsval()[0] : ' ';
5191 if (quotes) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005192 sepq = SIT(sep,syntax) == CCTL;
Eric Andersencb57d552001-06-28 07:25:16 +00005193 }
5194param:
5195 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
5196 strtodest(p, syntax, quotes);
5197 if (*ap && sep) {
5198 if (sepq)
5199 STPUTC(CTLESC, expdest);
5200 STPUTC(sep, expdest);
5201 }
5202 }
5203 break;
5204 case '0':
5205 strtodest(arg0, syntax, quotes);
5206 break;
5207 default:
5208 num = atoi(name);
5209 if (num > 0 && num <= shellparam.nparam) {
5210 strtodest(shellparam.p[num - 1], syntax, quotes);
5211 }
5212 break;
5213 }
5214}
5215
5216
Eric Andersencb57d552001-06-28 07:25:16 +00005217/*
5218 * Record the fact that we have to scan this region of the
5219 * string for IFS characters.
5220 */
5221
5222static void
5223recordregion(start, end, nulonly)
5224 int start;
5225 int end;
5226 int nulonly;
5227{
5228 struct ifsregion *ifsp;
5229
5230 if (ifslastp == NULL) {
5231 ifsp = &ifsfirst;
5232 } else {
5233 INTOFF;
5234 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
5235 ifsp->next = NULL;
5236 ifslastp->next = ifsp;
5237 INTON;
5238 }
5239 ifslastp = ifsp;
5240 ifslastp->begoff = start;
5241 ifslastp->endoff = end;
5242 ifslastp->nulonly = nulonly;
5243}
5244
5245
5246
5247/*
5248 * Break the argument string into pieces based upon IFS and add the
5249 * strings to the argument list. The regions of the string to be
5250 * searched for IFS characters have been stored by recordregion.
5251 */
5252static void
5253ifsbreakup(string, arglist)
5254 char *string;
5255 struct arglist *arglist;
5256 {
5257 struct ifsregion *ifsp;
5258 struct strlist *sp;
5259 char *start;
5260 char *p;
5261 char *q;
5262 const char *ifs, *realifs;
5263 int ifsspc;
5264 int nulonly;
5265
5266
5267 start = string;
5268 ifsspc = 0;
5269 nulonly = 0;
5270 realifs = ifsset() ? ifsval() : defifs;
5271 if (ifslastp != NULL) {
5272 ifsp = &ifsfirst;
5273 do {
5274 p = string + ifsp->begoff;
5275 nulonly = ifsp->nulonly;
5276 ifs = nulonly ? nullstr : realifs;
5277 ifsspc = 0;
5278 while (p < string + ifsp->endoff) {
5279 q = p;
5280 if (*p == CTLESC)
5281 p++;
5282 if (strchr(ifs, *p)) {
5283 if (!nulonly)
5284 ifsspc = (strchr(defifs, *p) != NULL);
5285 /* Ignore IFS whitespace at start */
5286 if (q == start && ifsspc) {
5287 p++;
5288 start = p;
5289 continue;
5290 }
5291 *q = '\0';
5292 sp = (struct strlist *)stalloc(sizeof *sp);
5293 sp->text = start;
5294 *arglist->lastp = sp;
5295 arglist->lastp = &sp->next;
5296 p++;
5297 if (!nulonly) {
5298 for (;;) {
5299 if (p >= string + ifsp->endoff) {
5300 break;
5301 }
5302 q = p;
5303 if (*p == CTLESC)
5304 p++;
5305 if (strchr(ifs, *p) == NULL ) {
5306 p = q;
5307 break;
5308 } else if (strchr(defifs, *p) == NULL) {
5309 if (ifsspc) {
5310 p++;
5311 ifsspc = 0;
5312 } else {
5313 p = q;
5314 break;
5315 }
5316 } else
5317 p++;
5318 }
5319 }
5320 start = p;
5321 } else
5322 p++;
5323 }
5324 } while ((ifsp = ifsp->next) != NULL);
5325 if (!(*start || (!ifsspc && start > string && nulonly))) {
5326 return;
5327 }
5328 }
5329
5330 sp = (struct strlist *)stalloc(sizeof *sp);
5331 sp->text = start;
5332 *arglist->lastp = sp;
5333 arglist->lastp = &sp->next;
5334}
5335
5336static void
5337ifsfree()
5338{
5339 while (ifsfirst.next != NULL) {
5340 struct ifsregion *ifsp;
5341 INTOFF;
5342 ifsp = ifsfirst.next->next;
5343 ckfree(ifsfirst.next);
5344 ifsfirst.next = ifsp;
5345 INTON;
5346 }
5347 ifslastp = NULL;
5348 ifsfirst.next = NULL;
5349}
5350
Eric Andersen2870d962001-07-02 17:27:21 +00005351/*
5352 * Add a file name to the list.
5353 */
Eric Andersencb57d552001-06-28 07:25:16 +00005354
Eric Andersen2870d962001-07-02 17:27:21 +00005355static void
5356addfname(const char *name)
5357{
5358 char *p;
5359 struct strlist *sp;
5360
5361 p = sstrdup(name);
5362 sp = (struct strlist *)stalloc(sizeof *sp);
5363 sp->text = p;
5364 *exparg.lastp = sp;
5365 exparg.lastp = &sp->next;
5366}
Eric Andersencb57d552001-06-28 07:25:16 +00005367
5368/*
5369 * Expand shell metacharacters. At this point, the only control characters
5370 * should be escapes. The results are stored in the list exparg.
5371 */
5372
Eric Andersen62483552001-07-10 06:09:16 +00005373#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00005374static void
5375expandmeta(str, flag)
5376 struct strlist *str;
5377 int flag;
5378{
5379 const char *p;
5380 glob_t pglob;
5381 /* TODO - EXP_REDIR */
5382
5383 while (str) {
5384 if (fflag)
5385 goto nometa;
5386 p = preglob(str->text);
5387 INTOFF;
Eric Andersen34506362001-08-02 05:02:46 +00005388 switch (glob(p, 0, 0, &pglob)) {
Eric Andersencb57d552001-06-28 07:25:16 +00005389 case 0:
Eric Andersen34506362001-08-02 05:02:46 +00005390 if(pglob.gl_pathv[1]==0 && !strcmp(p, pglob.gl_pathv[0]))
Eric Andersencb57d552001-06-28 07:25:16 +00005391 goto nometa2;
5392 addglob(&pglob);
5393 globfree(&pglob);
5394 INTON;
5395 break;
5396 case GLOB_NOMATCH:
5397nometa2:
5398 globfree(&pglob);
5399 INTON;
5400nometa:
5401 *exparg.lastp = str;
5402 rmescapes(str->text);
5403 exparg.lastp = &str->next;
5404 break;
Eric Andersen2870d962001-07-02 17:27:21 +00005405 default: /* GLOB_NOSPACE */
Eric Andersencb57d552001-06-28 07:25:16 +00005406 error("Out of space");
5407 }
5408 str = str->next;
5409 }
5410}
5411
5412
5413/*
5414 * Add the result of glob(3) to the list.
5415 */
5416
5417static void
5418addglob(pglob)
5419 const glob_t *pglob;
5420{
5421 char **p = pglob->gl_pathv;
5422
5423 do {
5424 addfname(*p);
5425 } while (*++p);
5426}
5427
5428
Eric Andersen2870d962001-07-02 17:27:21 +00005429#else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005430static char *expdir;
5431
5432
5433static void
5434expandmeta(str, flag)
5435 struct strlist *str;
5436 int flag;
5437{
5438 char *p;
5439 struct strlist **savelastp;
5440 struct strlist *sp;
5441 char c;
5442 /* TODO - EXP_REDIR */
5443
5444 while (str) {
5445 if (fflag)
5446 goto nometa;
5447 p = str->text;
Eric Andersen2870d962001-07-02 17:27:21 +00005448 for (;;) { /* fast check for meta chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005449 if ((c = *p++) == '\0')
5450 goto nometa;
5451 if (c == '*' || c == '?' || c == '[' || c == '!')
5452 break;
5453 }
5454 savelastp = exparg.lastp;
5455 INTOFF;
5456 if (expdir == NULL) {
5457 int i = strlen(str->text);
5458 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5459 }
5460
5461 expmeta(expdir, str->text);
5462 ckfree(expdir);
5463 expdir = NULL;
5464 INTON;
5465 if (exparg.lastp == savelastp) {
5466 /*
5467 * no matches
5468 */
5469nometa:
5470 *exparg.lastp = str;
5471 rmescapes(str->text);
5472 exparg.lastp = &str->next;
5473 } else {
5474 *exparg.lastp = NULL;
5475 *savelastp = sp = expsort(*savelastp);
5476 while (sp->next != NULL)
5477 sp = sp->next;
5478 exparg.lastp = &sp->next;
5479 }
5480 str = str->next;
5481 }
5482}
5483
5484
5485/*
5486 * Do metacharacter (i.e. *, ?, [...]) expansion.
5487 */
5488
5489static void
5490expmeta(enddir, name)
5491 char *enddir;
5492 char *name;
5493 {
5494 char *p;
5495 const char *cp;
5496 char *q;
5497 char *start;
5498 char *endname;
5499 int metaflag;
5500 struct stat statb;
5501 DIR *dirp;
5502 struct dirent *dp;
5503 int atend;
5504 int matchdot;
5505
5506 metaflag = 0;
5507 start = name;
5508 for (p = name ; ; p++) {
5509 if (*p == '*' || *p == '?')
5510 metaflag = 1;
5511 else if (*p == '[') {
5512 q = p + 1;
5513 if (*q == '!')
5514 q++;
5515 for (;;) {
5516 while (*q == CTLQUOTEMARK)
5517 q++;
5518 if (*q == CTLESC)
5519 q++;
5520 if (*q == '/' || *q == '\0')
5521 break;
5522 if (*++q == ']') {
5523 metaflag = 1;
5524 break;
5525 }
5526 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005527 } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) {
Eric Andersencb57d552001-06-28 07:25:16 +00005528 metaflag = 1;
5529 } else if (*p == '\0')
5530 break;
5531 else if (*p == CTLQUOTEMARK)
5532 continue;
5533 else if (*p == CTLESC)
5534 p++;
5535 if (*p == '/') {
5536 if (metaflag)
5537 break;
5538 start = p + 1;
5539 }
5540 }
Eric Andersen2870d962001-07-02 17:27:21 +00005541 if (metaflag == 0) { /* we've reached the end of the file name */
Eric Andersencb57d552001-06-28 07:25:16 +00005542 if (enddir != expdir)
5543 metaflag++;
5544 for (p = name ; ; p++) {
5545 if (*p == CTLQUOTEMARK)
5546 continue;
5547 if (*p == CTLESC)
5548 p++;
5549 *enddir++ = *p;
5550 if (*p == '\0')
5551 break;
5552 }
5553 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5554 addfname(expdir);
5555 return;
5556 }
5557 endname = p;
5558 if (start != name) {
5559 p = name;
5560 while (p < start) {
5561 while (*p == CTLQUOTEMARK)
5562 p++;
5563 if (*p == CTLESC)
5564 p++;
5565 *enddir++ = *p++;
5566 }
5567 }
5568 if (enddir == expdir) {
5569 cp = ".";
5570 } else if (enddir == expdir + 1 && *expdir == '/') {
5571 cp = "/";
5572 } else {
5573 cp = expdir;
5574 enddir[-1] = '\0';
5575 }
5576 if ((dirp = opendir(cp)) == NULL)
5577 return;
5578 if (enddir != expdir)
5579 enddir[-1] = '/';
5580 if (*endname == 0) {
5581 atend = 1;
5582 } else {
5583 atend = 0;
5584 *endname++ = '\0';
5585 }
5586 matchdot = 0;
5587 p = start;
5588 while (*p == CTLQUOTEMARK)
5589 p++;
5590 if (*p == CTLESC)
5591 p++;
5592 if (*p == '.')
5593 matchdot++;
5594 while (! int_pending() && (dp = readdir(dirp)) != NULL) {
5595 if (dp->d_name[0] == '.' && ! matchdot)
5596 continue;
5597 if (patmatch(start, dp->d_name, 0)) {
5598 if (atend) {
Eric Andersen2870d962001-07-02 17:27:21 +00005599 strcpy(enddir, dp->d_name);
Eric Andersencb57d552001-06-28 07:25:16 +00005600 addfname(expdir);
5601 } else {
5602 for (p = enddir, cp = dp->d_name;
5603 (*p++ = *cp++) != '\0';)
5604 continue;
5605 p[-1] = '/';
5606 expmeta(p, endname);
5607 }
5608 }
5609 }
5610 closedir(dirp);
5611 if (! atend)
5612 endname[-1] = '/';
5613}
Eric Andersen2870d962001-07-02 17:27:21 +00005614#endif /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005615
5616
Eric Andersencb57d552001-06-28 07:25:16 +00005617
Eric Andersen62483552001-07-10 06:09:16 +00005618#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersencb57d552001-06-28 07:25:16 +00005619/*
5620 * Sort the results of file name expansion. It calculates the number of
5621 * strings to sort and then calls msort (short for merge sort) to do the
5622 * work.
5623 */
5624
5625static struct strlist *
5626expsort(str)
5627 struct strlist *str;
5628 {
5629 int len;
5630 struct strlist *sp;
5631
5632 len = 0;
5633 for (sp = str ; sp ; sp = sp->next)
5634 len++;
5635 return msort(str, len);
5636}
5637
5638
5639static struct strlist *
5640msort(list, len)
5641 struct strlist *list;
5642 int len;
5643{
5644 struct strlist *p, *q = NULL;
5645 struct strlist **lpp;
5646 int half;
5647 int n;
5648
5649 if (len <= 1)
5650 return list;
5651 half = len >> 1;
5652 p = list;
5653 for (n = half ; --n >= 0 ; ) {
5654 q = p;
5655 p = p->next;
5656 }
Eric Andersen2870d962001-07-02 17:27:21 +00005657 q->next = NULL; /* terminate first half of list */
5658 q = msort(list, half); /* sort first half of list */
5659 p = msort(p, len - half); /* sort second half */
Eric Andersencb57d552001-06-28 07:25:16 +00005660 lpp = &list;
5661 for (;;) {
5662 if (strcmp(p->text, q->text) < 0) {
5663 *lpp = p;
5664 lpp = &p->next;
5665 if ((p = *lpp) == NULL) {
5666 *lpp = q;
5667 break;
5668 }
5669 } else {
5670 *lpp = q;
5671 lpp = &q->next;
5672 if ((q = *lpp) == NULL) {
5673 *lpp = p;
5674 break;
5675 }
5676 }
5677 }
5678 return list;
5679}
5680#endif
5681
5682
5683
5684/*
5685 * Returns true if the pattern matches the string.
5686 */
5687
Eric Andersen62483552001-07-10 06:09:16 +00005688#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00005689/* squoted: string might have quote chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005690static int
Eric Andersen2870d962001-07-02 17:27:21 +00005691patmatch(char *pattern, char *string, int squoted)
5692{
Eric Andersencb57d552001-06-28 07:25:16 +00005693 const char *p;
5694 char *q;
5695
5696 p = preglob(pattern);
5697 q = squoted ? _rmescapes(string, RMESCAPE_ALLOC) : string;
5698
5699 return !fnmatch(p, q, 0);
5700}
5701
5702
5703static int
Eric Andersen2870d962001-07-02 17:27:21 +00005704patmatch2(char *pattern, char *string, int squoted)
5705{
Eric Andersencb57d552001-06-28 07:25:16 +00005706 char *p;
5707 int res;
5708
5709 sstrnleft--;
5710 p = grabstackstr(expdest);
5711 res = patmatch(pattern, string, squoted);
5712 ungrabstackstr(p, expdest);
5713 return res;
5714}
5715#else
5716static int
Eric Andersen2870d962001-07-02 17:27:21 +00005717patmatch(char *pattern, char *string, int squoted) {
5718 return pmatch(pattern, string, squoted);
Eric Andersencb57d552001-06-28 07:25:16 +00005719}
5720
5721
5722static int
Eric Andersen2870d962001-07-02 17:27:21 +00005723pmatch(char *pattern, char *string, int squoted)
5724{
Eric Andersencb57d552001-06-28 07:25:16 +00005725 char *p, *q;
5726 char c;
5727
5728 p = pattern;
5729 q = string;
5730 for (;;) {
5731 switch (c = *p++) {
5732 case '\0':
5733 goto breakloop;
5734 case CTLESC:
5735 if (squoted && *q == CTLESC)
5736 q++;
5737 if (*q++ != *p++)
5738 return 0;
5739 break;
5740 case CTLQUOTEMARK:
5741 continue;
5742 case '?':
5743 if (squoted && *q == CTLESC)
5744 q++;
5745 if (*q++ == '\0')
5746 return 0;
5747 break;
5748 case '*':
5749 c = *p;
5750 while (c == CTLQUOTEMARK || c == '*')
5751 c = *++p;
5752 if (c != CTLESC && c != CTLQUOTEMARK &&
5753 c != '?' && c != '*' && c != '[') {
5754 while (*q != c) {
5755 if (squoted && *q == CTLESC &&
5756 q[1] == c)
5757 break;
5758 if (*q == '\0')
5759 return 0;
5760 if (squoted && *q == CTLESC)
5761 q++;
5762 q++;
5763 }
5764 }
5765 do {
5766 if (pmatch(p, q, squoted))
5767 return 1;
5768 if (squoted && *q == CTLESC)
5769 q++;
5770 } while (*q++ != '\0');
5771 return 0;
5772 case '[': {
5773 char *endp;
5774 int invert, found;
5775 char chr;
5776
5777 endp = p;
5778 if (*endp == '!')
5779 endp++;
5780 for (;;) {
5781 while (*endp == CTLQUOTEMARK)
5782 endp++;
5783 if (*endp == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00005784 goto dft; /* no matching ] */
Eric Andersencb57d552001-06-28 07:25:16 +00005785 if (*endp == CTLESC)
5786 endp++;
5787 if (*++endp == ']')
5788 break;
5789 }
5790 invert = 0;
5791 if (*p == '!') {
5792 invert++;
5793 p++;
5794 }
5795 found = 0;
5796 chr = *q++;
5797 if (squoted && chr == CTLESC)
5798 chr = *q++;
5799 if (chr == '\0')
5800 return 0;
5801 c = *p++;
5802 do {
5803 if (c == CTLQUOTEMARK)
5804 continue;
5805 if (c == CTLESC)
5806 c = *p++;
5807 if (*p == '-' && p[1] != ']') {
5808 p++;
5809 while (*p == CTLQUOTEMARK)
5810 p++;
5811 if (*p == CTLESC)
5812 p++;
5813 if (chr >= c && chr <= *p)
5814 found = 1;
5815 p++;
5816 } else {
5817 if (chr == c)
5818 found = 1;
5819 }
5820 } while ((c = *p++) != ']');
5821 if (found == invert)
5822 return 0;
5823 break;
5824 }
Eric Andersen2870d962001-07-02 17:27:21 +00005825dft: default:
Eric Andersencb57d552001-06-28 07:25:16 +00005826 if (squoted && *q == CTLESC)
5827 q++;
5828 if (*q++ != c)
5829 return 0;
5830 break;
5831 }
5832 }
5833breakloop:
5834 if (*q != '\0')
5835 return 0;
5836 return 1;
5837}
5838#endif
5839
5840
5841
5842/*
5843 * Remove any CTLESC characters from a string.
5844 */
5845
Eric Andersen62483552001-07-10 06:09:16 +00005846#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00005847static char *
Eric Andersen2870d962001-07-02 17:27:21 +00005848_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005849{
5850 char *p, *q, *r;
5851 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5852
5853 p = strpbrk(str, qchars);
5854 if (!p) {
5855 return str;
5856 }
5857 q = p;
5858 r = str;
5859 if (flag & RMESCAPE_ALLOC) {
5860 size_t len = p - str;
5861 q = r = stalloc(strlen(p) + len + 1);
5862 if (len > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00005863 memcpy(q, str, len);
5864 q += len;
Eric Andersencb57d552001-06-28 07:25:16 +00005865 }
5866 }
5867 while (*p) {
5868 if (*p == CTLQUOTEMARK) {
5869 p++;
5870 continue;
5871 }
5872 if (*p == CTLESC) {
5873 p++;
5874 if (flag & RMESCAPE_GLOB && *p != '/') {
5875 *q++ = '\\';
5876 }
5877 }
5878 *q++ = *p++;
5879 }
5880 *q = '\0';
5881 return r;
5882}
5883#else
5884static void
5885rmescapes(str)
5886 char *str;
5887{
5888 char *p, *q;
5889
5890 p = str;
5891 while (*p != CTLESC && *p != CTLQUOTEMARK) {
5892 if (*p++ == '\0')
5893 return;
5894 }
5895 q = p;
5896 while (*p) {
5897 if (*p == CTLQUOTEMARK) {
5898 p++;
5899 continue;
5900 }
5901 if (*p == CTLESC)
5902 p++;
5903 *q++ = *p++;
5904 }
5905 *q = '\0';
5906}
5907#endif
5908
5909
5910
5911/*
5912 * See if a pattern matches in a case statement.
5913 */
5914
5915static int
Eric Andersen2870d962001-07-02 17:27:21 +00005916casematch(union node *pattern, const char *val)
5917{
Eric Andersencb57d552001-06-28 07:25:16 +00005918 struct stackmark smark;
5919 int result;
5920 char *p;
5921
5922 setstackmark(&smark);
5923 argbackq = pattern->narg.backquote;
5924 STARTSTACKSTR(expdest);
5925 ifslastp = NULL;
5926 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5927 STPUTC('\0', expdest);
5928 p = grabstackstr(expdest);
Eric Andersen2870d962001-07-02 17:27:21 +00005929 result = patmatch(p, (char *)val, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00005930 popstackmark(&smark);
5931 return result;
5932}
5933
5934/*
5935 * Our own itoa().
5936 */
5937
5938static char *
5939cvtnum(num, buf)
5940 int num;
5941 char *buf;
5942 {
5943 int len;
5944
5945 CHECKSTRSPACE(32, buf);
5946 len = sprintf(buf, "%d", num);
5947 STADJUST(len, buf);
5948 return buf;
5949}
Eric Andersencb57d552001-06-28 07:25:16 +00005950/*
5951 * Editline and history functions (and glue).
5952 */
5953static int histcmd(argc, argv)
5954 int argc;
5955 char **argv;
5956{
5957 error("not compiled with history support");
5958 /* NOTREACHED */
5959}
5960
5961
Eric Andersencb57d552001-06-28 07:25:16 +00005962struct redirtab {
5963 struct redirtab *next;
Russ Dill4db35642001-07-26 05:58:40 +00005964 short renamed[10]; /* Current ash support only 0-9 descriptors */
Eric Andersen34506362001-08-02 05:02:46 +00005965 /* char on arm (and others) can't be negative */
Eric Andersencb57d552001-06-28 07:25:16 +00005966};
5967
Eric Andersen2870d962001-07-02 17:27:21 +00005968static struct redirtab *redirlist;
Eric Andersencb57d552001-06-28 07:25:16 +00005969
5970extern char **environ;
5971
5972
5973
5974/*
5975 * Initialization code.
5976 */
5977
5978static void
Eric Andersen2870d962001-07-02 17:27:21 +00005979init(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00005980
5981 /* from cd.c: */
5982 {
5983 setpwd(0, 0);
5984 }
5985
5986 /* from input.c: */
5987 {
5988 basepf.nextc = basepf.buf = basebuf;
5989 }
5990
Eric Andersencb57d552001-06-28 07:25:16 +00005991 /* from var.c: */
5992 {
5993 char **envp;
5994 char ppid[32];
5995
5996 initvar();
5997 for (envp = environ ; *envp ; envp++) {
5998 if (strchr(*envp, '=')) {
5999 setvareq(*envp, VEXPORT|VTEXTFIXED);
6000 }
6001 }
6002
Eric Andersen3102ac42001-07-06 04:26:23 +00006003 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
Eric Andersencb57d552001-06-28 07:25:16 +00006004 setvar("PPID", ppid, 0);
6005 }
6006}
6007
6008
6009
6010/*
6011 * This routine is called when an error or an interrupt occurs in an
6012 * interactive shell and control is returned to the main command loop.
6013 */
6014
Eric Andersen2870d962001-07-02 17:27:21 +00006015/* 1 == check for aliases, 2 == also check for assignments */
Eric Andersen7467c8d2001-07-12 20:26:32 +00006016static int checkalias; /* also used in no alias mode for check assignments */
Eric Andersen2870d962001-07-02 17:27:21 +00006017
Eric Andersencb57d552001-06-28 07:25:16 +00006018static void
Eric Andersen2870d962001-07-02 17:27:21 +00006019reset(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00006020
6021 /* from eval.c: */
6022 {
6023 evalskip = 0;
6024 loopnest = 0;
6025 funcnest = 0;
6026 }
6027
6028 /* from input.c: */
6029 {
6030 if (exception != EXSHELLPROC)
Eric Andersen2870d962001-07-02 17:27:21 +00006031 parselleft = parsenleft = 0; /* clear input buffer */
Eric Andersencb57d552001-06-28 07:25:16 +00006032 popallfiles();
6033 }
6034
6035 /* from parser.c: */
6036 {
6037 tokpushback = 0;
6038 checkkwd = 0;
6039 checkalias = 0;
6040 }
6041
6042 /* from redir.c: */
6043 {
6044 while (redirlist)
6045 popredir();
6046 }
6047
Eric Andersencb57d552001-06-28 07:25:16 +00006048}
6049
6050
6051
6052/*
Eric Andersencb57d552001-06-28 07:25:16 +00006053 * This file implements the input routines used by the parser.
6054 */
6055
6056#ifdef BB_FEATURE_COMMAND_EDITING
Eric Andersencb57d552001-06-28 07:25:16 +00006057static const char * cmdedit_prompt;
6058static inline void putprompt(const char *s) {
6059 cmdedit_prompt = s;
6060}
6061#else
6062static inline void putprompt(const char *s) {
6063 out2str(s);
6064}
6065#endif
6066
Eric Andersen2870d962001-07-02 17:27:21 +00006067#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
Eric Andersencb57d552001-06-28 07:25:16 +00006068
Eric Andersencb57d552001-06-28 07:25:16 +00006069
Eric Andersencb57d552001-06-28 07:25:16 +00006070
Eric Andersen2870d962001-07-02 17:27:21 +00006071/*
6072 * Same as pgetc(), but ignores PEOA.
6073 */
Eric Andersencb57d552001-06-28 07:25:16 +00006074
Eric Andersen2870d962001-07-02 17:27:21 +00006075#ifdef ASH_ALIAS
6076static int
6077pgetc2()
6078{
6079 int c;
6080 do {
6081 c = pgetc_macro();
6082 } while (c == PEOA);
6083 return c;
Eric Andersencb57d552001-06-28 07:25:16 +00006084}
Eric Andersen2870d962001-07-02 17:27:21 +00006085#else
6086static inline int pgetc2() { return pgetc_macro(); }
Eric Andersencb57d552001-06-28 07:25:16 +00006087#endif
6088
Eric Andersencb57d552001-06-28 07:25:16 +00006089/*
6090 * Read a line from the script.
6091 */
6092
Eric Andersen62483552001-07-10 06:09:16 +00006093static inline char *
Eric Andersen2870d962001-07-02 17:27:21 +00006094pfgets(char *line, int len)
Eric Andersencb57d552001-06-28 07:25:16 +00006095{
6096 char *p = line;
6097 int nleft = len;
6098 int c;
6099
6100 while (--nleft > 0) {
6101 c = pgetc2();
6102 if (c == PEOF) {
6103 if (p == line)
6104 return NULL;
6105 break;
6106 }
6107 *p++ = c;
6108 if (c == '\n')
6109 break;
6110 }
6111 *p = '\0';
6112 return line;
6113}
6114
Eric Andersen62483552001-07-10 06:09:16 +00006115static inline int
Eric Andersen2870d962001-07-02 17:27:21 +00006116preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006117{
6118 int nr;
6119 char *buf = parsefile->buf;
6120 parsenextc = buf;
6121
6122retry:
6123#ifdef BB_FEATURE_COMMAND_EDITING
6124 {
Eric Andersen34506362001-08-02 05:02:46 +00006125 if (!iflag || parsefile->fd)
Eric Andersen7467c8d2001-07-12 20:26:32 +00006126 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersen2870d962001-07-02 17:27:21 +00006127 else {
Eric Andersen044228d2001-07-17 01:12:36 +00006128 nr = cmdedit_read_input((char*)cmdedit_prompt, buf);
Eric Andersencb57d552001-06-28 07:25:16 +00006129 }
6130 }
6131#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00006132 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006133#endif
6134
6135 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006136 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6137 int flags = fcntl(0, F_GETFL, 0);
6138 if (flags >= 0 && flags & O_NONBLOCK) {
6139 flags &=~ O_NONBLOCK;
6140 if (fcntl(0, F_SETFL, flags) >= 0) {
6141 out2str("sh: turning off NDELAY mode\n");
6142 goto retry;
6143 }
6144 }
6145 }
6146 }
6147 return nr;
6148}
6149
Eric Andersen2870d962001-07-02 17:27:21 +00006150static void
6151popstring(void)
6152{
6153 struct strpush *sp = parsefile->strpush;
6154
6155 INTOFF;
6156#ifdef ASH_ALIAS
6157 if (sp->ap) {
6158 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6159 if (!checkalias) {
6160 checkalias = 1;
6161 }
6162 }
6163 if (sp->string != sp->ap->val) {
6164 ckfree(sp->string);
6165 }
6166
6167 sp->ap->flag &= ~ALIASINUSE;
6168 if (sp->ap->flag & ALIASDEAD) {
6169 unalias(sp->ap->name);
6170 }
6171 }
6172#endif
6173 parsenextc = sp->prevstring;
6174 parsenleft = sp->prevnleft;
6175/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6176 parsefile->strpush = sp->prev;
6177 if (sp != &(parsefile->basestrpush))
6178 ckfree(sp);
6179 INTON;
6180}
6181
6182
Eric Andersencb57d552001-06-28 07:25:16 +00006183/*
6184 * Refill the input buffer and return the next input character:
6185 *
6186 * 1) If a string was pushed back on the input, pop it;
6187 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6188 * from a string so we can't refill the buffer, return EOF.
6189 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6190 * 4) Process input up to the next newline, deleting nul characters.
6191 */
6192
6193static int
Eric Andersen2870d962001-07-02 17:27:21 +00006194preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006195{
6196 char *p, *q;
6197 int more;
6198 char savec;
6199
6200 while (parsefile->strpush) {
Eric Andersen2870d962001-07-02 17:27:21 +00006201#ifdef ASH_ALIAS
6202 if (parsenleft == -1 && parsefile->strpush->ap &&
6203 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00006204 return PEOA;
6205 }
Eric Andersen2870d962001-07-02 17:27:21 +00006206#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006207 popstring();
6208 if (--parsenleft >= 0)
6209 return (*parsenextc++);
6210 }
6211 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6212 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00006213 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00006214
6215again:
6216 if (parselleft <= 0) {
6217 if ((parselleft = preadfd()) <= 0) {
6218 parselleft = parsenleft = EOF_NLEFT;
6219 return PEOF;
6220 }
6221 }
6222
6223 q = p = parsenextc;
6224
6225 /* delete nul characters */
6226 for (more = 1; more;) {
6227 switch (*p) {
6228 case '\0':
Eric Andersen2870d962001-07-02 17:27:21 +00006229 p++; /* Skip nul */
Eric Andersencb57d552001-06-28 07:25:16 +00006230 goto check;
6231
6232
6233 case '\n':
6234 parsenleft = q - parsenextc;
6235 more = 0; /* Stop processing here */
6236 break;
6237 }
6238
6239 *q++ = *p++;
6240check:
6241 if (--parselleft <= 0 && more) {
6242 parsenleft = q - parsenextc - 1;
6243 if (parsenleft < 0)
6244 goto again;
6245 more = 0;
6246 }
6247 }
6248
6249 savec = *q;
6250 *q = '\0';
6251
6252 if (vflag) {
6253 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00006254 }
6255
6256 *q = savec;
6257
6258 return *parsenextc++;
6259}
6260
Eric Andersencb57d552001-06-28 07:25:16 +00006261
6262/*
6263 * Push a string back onto the input at this current parsefile level.
6264 * We handle aliases this way.
6265 */
6266static void
Eric Andersen2870d962001-07-02 17:27:21 +00006267pushstring(char *s, int len, void *ap)
6268{
Eric Andersencb57d552001-06-28 07:25:16 +00006269 struct strpush *sp;
6270
6271 INTOFF;
6272/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6273 if (parsefile->strpush) {
6274 sp = ckmalloc(sizeof (struct strpush));
6275 sp->prev = parsefile->strpush;
6276 parsefile->strpush = sp;
6277 } else
6278 sp = parsefile->strpush = &(parsefile->basestrpush);
6279 sp->prevstring = parsenextc;
6280 sp->prevnleft = parsenleft;
Eric Andersen2870d962001-07-02 17:27:21 +00006281#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00006282 sp->ap = (struct alias *)ap;
6283 if (ap) {
6284 ((struct alias *)ap)->flag |= ALIASINUSE;
6285 sp->string = s;
6286 }
Eric Andersen2870d962001-07-02 17:27:21 +00006287#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006288 parsenextc = s;
6289 parsenleft = len;
6290 INTON;
6291}
6292
Eric Andersencb57d552001-06-28 07:25:16 +00006293
Eric Andersencb57d552001-06-28 07:25:16 +00006294/*
6295 * Like setinputfile, but takes input from a string.
6296 */
6297
6298static void
Eric Andersen62483552001-07-10 06:09:16 +00006299setinputstring(char *string)
6300{
Eric Andersencb57d552001-06-28 07:25:16 +00006301 INTOFF;
6302 pushfile();
6303 parsenextc = string;
6304 parsenleft = strlen(string);
6305 parsefile->buf = NULL;
6306 plinno = 1;
6307 INTON;
6308}
6309
6310
6311
6312/*
6313 * To handle the "." command, a stack of input files is used. Pushfile
6314 * adds a new entry to the stack and popfile restores the previous level.
6315 */
6316
6317static void
Eric Andersen2870d962001-07-02 17:27:21 +00006318pushfile(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00006319 struct parsefile *pf;
6320
6321 parsefile->nleft = parsenleft;
6322 parsefile->lleft = parselleft;
6323 parsefile->nextc = parsenextc;
6324 parsefile->linno = plinno;
6325 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6326 pf->prev = parsefile;
6327 pf->fd = -1;
6328 pf->strpush = NULL;
6329 pf->basestrpush.prev = NULL;
6330 parsefile = pf;
6331}
6332
Eric Andersen2870d962001-07-02 17:27:21 +00006333#ifdef JOBS
6334static void restartjob (struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00006335#endif
Eric Andersen2870d962001-07-02 17:27:21 +00006336static void freejob (struct job *);
6337static struct job *getjob (const char *);
6338static int dowait (int, struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00006339static void waitonint(int);
6340
6341
Eric Andersen2870d962001-07-02 17:27:21 +00006342/*
6343 * We keep track of whether or not fd0 has been redirected. This is for
6344 * background commands, where we want to redirect fd0 to /dev/null only
6345 * if it hasn't already been redirected.
6346*/
6347static int fd0_redirected = 0;
6348
6349/* Return true if fd 0 has already been redirected at least once. */
6350static inline int
6351fd0_redirected_p () {
6352 return fd0_redirected != 0;
6353}
6354
Eric Andersen62483552001-07-10 06:09:16 +00006355static void dupredirect (const union node *, int, int fd1dup);
Eric Andersen2870d962001-07-02 17:27:21 +00006356
6357#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006358/*
6359 * Turn job control on and off.
6360 *
6361 * Note: This code assumes that the third arg to ioctl is a character
6362 * pointer, which is true on Berkeley systems but not System V. Since
6363 * System V doesn't have job control yet, this isn't a problem now.
6364 */
6365
Eric Andersen2870d962001-07-02 17:27:21 +00006366
Eric Andersencb57d552001-06-28 07:25:16 +00006367
6368static void setjobctl(int enable)
6369{
6370#ifdef OLD_TTY_DRIVER
6371 int ldisc;
6372#endif
6373
6374 if (enable == jobctl || rootshell == 0)
6375 return;
6376 if (enable) {
6377 do { /* while we are in the background */
6378#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006379 if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006380#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006381 initialpgrp = tcgetpgrp(2);
Eric Andersencb57d552001-06-28 07:25:16 +00006382 if (initialpgrp < 0) {
6383#endif
Eric Andersen8c145dc2001-07-10 16:57:09 +00006384 out2str("sh: can't access tty; job control turned off\n");
Eric Andersencb57d552001-06-28 07:25:16 +00006385 mflag = 0;
6386 return;
6387 }
6388 if (initialpgrp == -1)
6389 initialpgrp = getpgrp();
6390 else if (initialpgrp != getpgrp()) {
6391 killpg(initialpgrp, SIGTTIN);
6392 continue;
6393 }
6394 } while (0);
6395#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006396 if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
Eric Andersen8c145dc2001-07-10 16:57:09 +00006397 out2str("sh: need new tty driver to run job control; job control turned off\n");
Eric Andersencb57d552001-06-28 07:25:16 +00006398 mflag = 0;
6399 return;
6400 }
6401#endif
6402 setsignal(SIGTSTP);
6403 setsignal(SIGTTOU);
6404 setsignal(SIGTTIN);
6405 setpgid(0, rootpid);
6406#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006407 ioctl(2, TIOCSPGRP, (char *)&rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00006408#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006409 tcsetpgrp(2, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00006410#endif
Eric Andersen8c145dc2001-07-10 16:57:09 +00006411 } else { /* turning job control off */
Eric Andersencb57d552001-06-28 07:25:16 +00006412 setpgid(0, initialpgrp);
6413#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006414 ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006415#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006416 tcsetpgrp(2, initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006417#endif
6418 setsignal(SIGTSTP);
6419 setsignal(SIGTTOU);
6420 setsignal(SIGTTIN);
6421 }
6422 jobctl = enable;
6423}
6424#endif
6425
6426
Eric Andersen2870d962001-07-02 17:27:21 +00006427#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006428static int
6429killcmd(argc, argv)
6430 int argc;
6431 char **argv;
6432{
6433 int signo = -1;
6434 int list = 0;
6435 int i;
6436 pid_t pid;
6437 struct job *jp;
6438
6439 if (argc <= 1) {
6440usage:
6441 error(
6442"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6443"kill -l [exitstatus]"
6444 );
6445 }
6446
6447 if (*argv[1] == '-') {
6448 signo = decode_signal(argv[1] + 1, 1);
6449 if (signo < 0) {
6450 int c;
6451
6452 while ((c = nextopt("ls:")) != '\0')
6453 switch (c) {
6454 case 'l':
6455 list = 1;
6456 break;
6457 case 's':
6458 signo = decode_signal(optionarg, 1);
6459 if (signo < 0) {
6460 error(
6461 "invalid signal number or name: %s",
6462 optionarg
6463 );
6464 }
Eric Andersen2870d962001-07-02 17:27:21 +00006465 break;
Eric Andersencb57d552001-06-28 07:25:16 +00006466#ifdef DEBUG
6467 default:
6468 error(
6469 "nextopt returned character code 0%o", c);
6470#endif
6471 }
6472 } else
6473 argptr++;
6474 }
6475
6476 if (!list && signo < 0)
6477 signo = SIGTERM;
6478
6479 if ((signo < 0 || !*argptr) ^ list) {
6480 goto usage;
6481 }
6482
6483 if (list) {
Eric Andersen34506362001-08-02 05:02:46 +00006484 const char *name;
6485
Eric Andersencb57d552001-06-28 07:25:16 +00006486 if (!*argptr) {
6487 out1str("0\n");
6488 for (i = 1; i < NSIG; i++) {
Eric Andersen34506362001-08-02 05:02:46 +00006489 name = u_signal_names(0, &i, 1);
6490 if(name)
6491 printf(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006492 }
6493 return 0;
6494 }
Eric Andersen34506362001-08-02 05:02:46 +00006495 name = u_signal_names(*argptr, &signo, -1);
6496 if (name)
6497 printf(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006498 else
6499 error("invalid signal number or exit status: %s",
6500 *argptr);
6501 return 0;
6502 }
6503
6504 do {
6505 if (**argptr == '%') {
6506 jp = getjob(*argptr);
6507 if (jp->jobctl == 0)
6508 error("job %s not created under job control",
6509 *argptr);
6510 pid = -jp->ps[0].pid;
6511 } else
6512 pid = atoi(*argptr);
6513 if (kill(pid, signo) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00006514 error("%s: %m", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006515 } while (*++argptr);
6516
6517 return 0;
6518}
6519
6520static int
6521fgcmd(argc, argv)
6522 int argc;
6523 char **argv;
6524{
6525 struct job *jp;
6526 int pgrp;
6527 int status;
6528
6529 jp = getjob(argv[1]);
6530 if (jp->jobctl == 0)
6531 error("job not created under job control");
6532 pgrp = jp->ps[0].pid;
6533#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006534 ioctl(2, TIOCSPGRP, (char *)&pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006535#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006536 tcsetpgrp(2, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006537#endif
6538 restartjob(jp);
6539 INTOFF;
6540 status = waitforjob(jp);
6541 INTON;
6542 return status;
6543}
6544
6545
6546static int
6547bgcmd(argc, argv)
6548 int argc;
6549 char **argv;
6550{
6551 struct job *jp;
6552
6553 do {
6554 jp = getjob(*++argv);
6555 if (jp->jobctl == 0)
6556 error("job not created under job control");
6557 restartjob(jp);
6558 } while (--argc > 1);
6559 return 0;
6560}
6561
6562
6563static void
6564restartjob(jp)
6565 struct job *jp;
6566{
6567 struct procstat *ps;
6568 int i;
6569
6570 if (jp->state == JOBDONE)
6571 return;
6572 INTOFF;
6573 killpg(jp->ps[0].pid, SIGCONT);
6574 for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
6575 if (WIFSTOPPED(ps->status)) {
6576 ps->status = -1;
6577 jp->state = 0;
6578 }
6579 }
6580 INTON;
6581}
6582#endif
6583
Eric Andersen2870d962001-07-02 17:27:21 +00006584static void showjobs(int change);
6585
Eric Andersencb57d552001-06-28 07:25:16 +00006586
6587static int
6588jobscmd(argc, argv)
6589 int argc;
6590 char **argv;
6591{
6592 showjobs(0);
6593 return 0;
6594}
6595
6596
6597/*
6598 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6599 * statuses have changed since the last call to showjobs.
6600 *
6601 * If the shell is interrupted in the process of creating a job, the
6602 * result may be a job structure containing zero processes. Such structures
6603 * will be freed here.
6604 */
6605
6606static void
6607showjobs(change)
6608 int change;
6609{
6610 int jobno;
6611 int procno;
6612 int i;
6613 struct job *jp;
6614 struct procstat *ps;
6615 int col;
6616 char s[64];
6617
6618 TRACE(("showjobs(%d) called\n", change));
6619 while (dowait(0, (struct job *)NULL) > 0);
6620 for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
6621 if (! jp->used)
6622 continue;
6623 if (jp->nprocs == 0) {
6624 freejob(jp);
6625 continue;
6626 }
6627 if (change && ! jp->changed)
6628 continue;
6629 procno = jp->nprocs;
Eric Andersen2870d962001-07-02 17:27:21 +00006630 for (ps = jp->ps ; ; ps++) { /* for each process */
Eric Andersencb57d552001-06-28 07:25:16 +00006631 if (ps == jp->ps)
Eric Andersen3102ac42001-07-06 04:26:23 +00006632 snprintf(s, 64, "[%d] %ld ", jobno,
Eric Andersencb57d552001-06-28 07:25:16 +00006633 (long)ps->pid);
6634 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006635 snprintf(s, 64, " %ld ",
Eric Andersencb57d552001-06-28 07:25:16 +00006636 (long)ps->pid);
6637 out1str(s);
6638 col = strlen(s);
6639 s[0] = '\0';
6640 if (ps->status == -1) {
6641 /* don't print anything */
6642 } else if (WIFEXITED(ps->status)) {
Eric Andersen3102ac42001-07-06 04:26:23 +00006643 snprintf(s, 64, "Exit %d",
Eric Andersencb57d552001-06-28 07:25:16 +00006644 WEXITSTATUS(ps->status));
6645 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00006646#ifdef JOBS
6647 if (WIFSTOPPED(ps->status))
Eric Andersencb57d552001-06-28 07:25:16 +00006648 i = WSTOPSIG(ps->status);
6649 else /* WIFSIGNALED(ps->status) */
6650#endif
6651 i = WTERMSIG(ps->status);
6652 if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
Eric Andersen2870d962001-07-02 17:27:21 +00006653 strcpy(s, sys_siglist[i & 0x7F]);
Eric Andersencb57d552001-06-28 07:25:16 +00006654 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006655 snprintf(s, 64, "Signal %d", i & 0x7F);
Eric Andersencb57d552001-06-28 07:25:16 +00006656 if (WCOREDUMP(ps->status))
6657 strcat(s, " (core dumped)");
6658 }
6659 out1str(s);
6660 col += strlen(s);
Eric Andersen62483552001-07-10 06:09:16 +00006661 printf(
Eric Andersencb57d552001-06-28 07:25:16 +00006662 "%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ',
6663 ps->cmd
6664 );
6665 if (--procno <= 0)
6666 break;
6667 }
6668 jp->changed = 0;
6669 if (jp->state == JOBDONE) {
6670 freejob(jp);
6671 }
6672 }
6673}
6674
6675
6676/*
6677 * Mark a job structure as unused.
6678 */
6679
6680static void
Eric Andersen62483552001-07-10 06:09:16 +00006681freejob(struct job *jp)
6682{
6683 const struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006684 int i;
6685
6686 INTOFF;
6687 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6688 if (ps->cmd != nullstr)
6689 ckfree(ps->cmd);
6690 }
6691 if (jp->ps != &jp->ps0)
6692 ckfree(jp->ps);
6693 jp->used = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006694#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006695 if (curjob == jp - jobtab + 1)
6696 curjob = 0;
6697#endif
6698 INTON;
6699}
6700
6701
6702
6703static int
6704waitcmd(argc, argv)
6705 int argc;
6706 char **argv;
6707{
6708 struct job *job;
6709 int status, retval;
6710 struct job *jp;
6711
6712 if (--argc > 0) {
6713start:
6714 job = getjob(*++argv);
6715 } else {
6716 job = NULL;
6717 }
Eric Andersen2870d962001-07-02 17:27:21 +00006718 for (;;) { /* loop until process terminated or stopped */
Eric Andersencb57d552001-06-28 07:25:16 +00006719 if (job != NULL) {
6720 if (job->state) {
6721 status = job->ps[job->nprocs - 1].status;
6722 if (! iflag)
6723 freejob(job);
6724 if (--argc) {
6725 goto start;
6726 }
6727 if (WIFEXITED(status))
6728 retval = WEXITSTATUS(status);
Eric Andersen2870d962001-07-02 17:27:21 +00006729#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006730 else if (WIFSTOPPED(status))
6731 retval = WSTOPSIG(status) + 128;
6732#endif
6733 else {
6734 /* XXX: limits number of signals */
6735 retval = WTERMSIG(status) + 128;
6736 }
6737 return retval;
6738 }
6739 } else {
6740 for (jp = jobtab ; ; jp++) {
Eric Andersen2870d962001-07-02 17:27:21 +00006741 if (jp >= jobtab + njobs) { /* no running procs */
Eric Andersencb57d552001-06-28 07:25:16 +00006742 return 0;
6743 }
6744 if (jp->used && jp->state == 0)
6745 break;
6746 }
6747 }
6748 if (dowait(2, 0) < 0 && errno == EINTR) {
6749 return 129;
6750 }
6751 }
6752}
6753
6754
6755
6756/*
6757 * Convert a job name to a job structure.
6758 */
6759
6760static struct job *
Eric Andersen2870d962001-07-02 17:27:21 +00006761getjob(const char *name)
6762{
Eric Andersencb57d552001-06-28 07:25:16 +00006763 int jobno;
6764 struct job *jp;
6765 int pid;
6766 int i;
6767
6768 if (name == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00006769#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006770currentjob:
6771 if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
6772 error("No current job");
6773 return &jobtab[jobno - 1];
6774#else
6775 error("No current job");
6776#endif
6777 } else if (name[0] == '%') {
6778 if (is_digit(name[1])) {
6779 jobno = number(name + 1);
6780 if (jobno > 0 && jobno <= njobs
6781 && jobtab[jobno - 1].used != 0)
6782 return &jobtab[jobno - 1];
Eric Andersen2870d962001-07-02 17:27:21 +00006783#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006784 } else if (name[1] == '%' && name[2] == '\0') {
6785 goto currentjob;
6786#endif
6787 } else {
6788 struct job *found = NULL;
6789 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
6790 if (jp->used && jp->nprocs > 0
6791 && prefix(name + 1, jp->ps[0].cmd)) {
6792 if (found)
6793 error("%s: ambiguous", name);
6794 found = jp;
6795 }
6796 }
6797 if (found)
6798 return found;
6799 }
Eric Andersen2870d962001-07-02 17:27:21 +00006800 } else if (is_number(name, &pid)) {
Eric Andersencb57d552001-06-28 07:25:16 +00006801 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
6802 if (jp->used && jp->nprocs > 0
6803 && jp->ps[jp->nprocs - 1].pid == pid)
6804 return jp;
6805 }
6806 }
6807 error("No such job: %s", name);
6808 /* NOTREACHED */
6809}
6810
6811
6812
6813/*
6814 * Return a new job structure,
6815 */
6816
Eric Andersen2870d962001-07-02 17:27:21 +00006817static struct job *
Eric Andersen62483552001-07-10 06:09:16 +00006818makejob(const union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00006819{
6820 int i;
6821 struct job *jp;
6822
6823 for (i = njobs, jp = jobtab ; ; jp++) {
6824 if (--i < 0) {
6825 INTOFF;
6826 if (njobs == 0) {
6827 jobtab = ckmalloc(4 * sizeof jobtab[0]);
6828 } else {
6829 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
6830 memcpy(jp, jobtab, njobs * sizeof jp[0]);
6831 /* Relocate `ps' pointers */
6832 for (i = 0; i < njobs; i++)
6833 if (jp[i].ps == &jobtab[i].ps0)
6834 jp[i].ps = &jp[i].ps0;
6835 ckfree(jobtab);
6836 jobtab = jp;
6837 }
6838 jp = jobtab + njobs;
6839 for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
6840 INTON;
6841 break;
6842 }
6843 if (jp->used == 0)
6844 break;
6845 }
6846 INTOFF;
6847 jp->state = 0;
6848 jp->used = 1;
6849 jp->changed = 0;
6850 jp->nprocs = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006851#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006852 jp->jobctl = jobctl;
6853#endif
6854 if (nprocs > 1) {
6855 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
6856 } else {
6857 jp->ps = &jp->ps0;
6858 }
6859 INTON;
6860 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
6861 jp - jobtab + 1));
6862 return jp;
6863}
6864
6865
6866/*
6867 * Fork of a subshell. If we are doing job control, give the subshell its
6868 * own process group. Jp is a job structure that the job is to be added to.
6869 * N is the command that will be evaluated by the child. Both jp and n may
6870 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00006871 * FORK_FG - Fork off a foreground process.
6872 * FORK_BG - Fork off a background process.
6873 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
6874 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00006875 *
6876 * When job control is turned off, background processes have their standard
6877 * input redirected to /dev/null (except for the second and later processes
6878 * in a pipeline).
6879 */
6880
Eric Andersen2870d962001-07-02 17:27:21 +00006881
6882
Eric Andersencb57d552001-06-28 07:25:16 +00006883static int
Eric Andersen62483552001-07-10 06:09:16 +00006884forkshell(struct job *jp, const union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00006885{
6886 int pid;
Eric Andersen62483552001-07-10 06:09:16 +00006887#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006888 int pgrp;
Eric Andersen62483552001-07-10 06:09:16 +00006889#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006890 const char *devnull = _PATH_DEVNULL;
6891 const char *nullerr = "Can't open %s";
6892
6893 TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
6894 mode));
6895 INTOFF;
6896 pid = fork();
6897 if (pid == -1) {
6898 TRACE(("Fork failed, errno=%d\n", errno));
6899 INTON;
6900 error("Cannot fork");
6901 }
6902 if (pid == 0) {
6903 struct job *p;
6904 int wasroot;
6905 int i;
6906
6907 TRACE(("Child shell %d\n", getpid()));
6908 wasroot = rootshell;
6909 rootshell = 0;
6910 closescript();
6911 INTON;
6912 clear_traps();
Eric Andersen2870d962001-07-02 17:27:21 +00006913#ifdef JOBS
6914 jobctl = 0; /* do job control only in root shell */
Eric Andersencb57d552001-06-28 07:25:16 +00006915 if (wasroot && mode != FORK_NOJOB && mflag) {
6916 if (jp == NULL || jp->nprocs == 0)
6917 pgrp = getpid();
6918 else
6919 pgrp = jp->ps[0].pid;
6920 setpgid(0, pgrp);
6921 if (mode == FORK_FG) {
6922 /*** this causes superfluous TIOCSPGRPS ***/
6923#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006924 if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006925 error("TIOCSPGRP failed, errno=%d", errno);
6926#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006927 if (tcsetpgrp(2, pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006928 error("tcsetpgrp failed, errno=%d", errno);
6929#endif
6930 }
6931 setsignal(SIGTSTP);
6932 setsignal(SIGTTOU);
6933 } else if (mode == FORK_BG) {
6934 ignoresig(SIGINT);
6935 ignoresig(SIGQUIT);
6936 if ((jp == NULL || jp->nprocs == 0) &&
6937 ! fd0_redirected_p ()) {
6938 close(0);
6939 if (open(devnull, O_RDONLY) != 0)
6940 error(nullerr, devnull);
6941 }
6942 }
6943#else
6944 if (mode == FORK_BG) {
6945 ignoresig(SIGINT);
6946 ignoresig(SIGQUIT);
6947 if ((jp == NULL || jp->nprocs == 0) &&
6948 ! fd0_redirected_p ()) {
6949 close(0);
6950 if (open(devnull, O_RDONLY) != 0)
6951 error(nullerr, devnull);
6952 }
6953 }
6954#endif
6955 for (i = njobs, p = jobtab ; --i >= 0 ; p++)
6956 if (p->used)
6957 freejob(p);
6958 if (wasroot && iflag) {
6959 setsignal(SIGINT);
6960 setsignal(SIGQUIT);
6961 setsignal(SIGTERM);
6962 }
6963 return pid;
6964 }
Eric Andersen62483552001-07-10 06:09:16 +00006965#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006966 if (rootshell && mode != FORK_NOJOB && mflag) {
6967 if (jp == NULL || jp->nprocs == 0)
6968 pgrp = pid;
6969 else
6970 pgrp = jp->ps[0].pid;
6971 setpgid(pid, pgrp);
6972 }
Eric Andersen62483552001-07-10 06:09:16 +00006973#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006974 if (mode == FORK_BG)
Eric Andersen2870d962001-07-02 17:27:21 +00006975 backgndpid = pid; /* set $! */
Eric Andersencb57d552001-06-28 07:25:16 +00006976 if (jp) {
6977 struct procstat *ps = &jp->ps[jp->nprocs++];
6978 ps->pid = pid;
6979 ps->status = -1;
6980 ps->cmd = nullstr;
6981 if (iflag && rootshell && n)
6982 ps->cmd = commandtext(n);
6983 }
6984 INTON;
6985 TRACE(("In parent shell: child = %d\n", pid));
6986 return pid;
6987}
6988
6989
6990
6991/*
6992 * Wait for job to finish.
6993 *
6994 * Under job control we have the problem that while a child process is
6995 * running interrupts generated by the user are sent to the child but not
6996 * to the shell. This means that an infinite loop started by an inter-
6997 * active user may be hard to kill. With job control turned off, an
6998 * interactive user may place an interactive program inside a loop. If
6999 * the interactive program catches interrupts, the user doesn't want
7000 * these interrupts to also abort the loop. The approach we take here
7001 * is to have the shell ignore interrupt signals while waiting for a
7002 * forground process to terminate, and then send itself an interrupt
7003 * signal if the child process was terminated by an interrupt signal.
7004 * Unfortunately, some programs want to do a bit of cleanup and then
7005 * exit on interrupt; unless these processes terminate themselves by
7006 * sending a signal to themselves (instead of calling exit) they will
7007 * confuse this approach.
7008 */
7009
7010static int
Eric Andersen62483552001-07-10 06:09:16 +00007011waitforjob(struct job *jp)
7012{
Eric Andersen2870d962001-07-02 17:27:21 +00007013#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007014 int mypgrp = getpgrp();
7015#endif
7016 int status;
7017 int st;
7018 struct sigaction act, oact;
7019
7020 INTOFF;
7021 intreceived = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00007022#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007023 if (!jobctl) {
7024#else
7025 if (!iflag) {
7026#endif
7027 sigaction(SIGINT, 0, &act);
7028 act.sa_handler = waitonint;
7029 sigaction(SIGINT, &act, &oact);
7030 }
7031 TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
7032 while (jp->state == 0) {
7033 dowait(1, jp);
7034 }
Eric Andersen2870d962001-07-02 17:27:21 +00007035#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007036 if (!jobctl) {
7037#else
7038 if (!iflag) {
7039#endif
7040 sigaction(SIGINT, &oact, 0);
7041 if (intreceived && trap[SIGINT]) kill(getpid(), SIGINT);
7042 }
Eric Andersen2870d962001-07-02 17:27:21 +00007043#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007044 if (jp->jobctl) {
7045#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00007046 if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007047 error("TIOCSPGRP failed, errno=%d\n", errno);
7048#else
Eric Andersen3102ac42001-07-06 04:26:23 +00007049 if (tcsetpgrp(2, mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007050 error("tcsetpgrp failed, errno=%d\n", errno);
7051#endif
7052 }
7053 if (jp->state == JOBSTOPPED)
7054 curjob = jp - jobtab + 1;
7055#endif
7056 status = jp->ps[jp->nprocs - 1].status;
7057 /* convert to 8 bits */
7058 if (WIFEXITED(status))
7059 st = WEXITSTATUS(status);
Eric Andersen2870d962001-07-02 17:27:21 +00007060#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007061 else if (WIFSTOPPED(status))
7062 st = WSTOPSIG(status) + 128;
7063#endif
7064 else
7065 st = WTERMSIG(status) + 128;
Eric Andersen2870d962001-07-02 17:27:21 +00007066#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007067 if (jp->jobctl) {
7068 /*
7069 * This is truly gross.
7070 * If we're doing job control, then we did a TIOCSPGRP which
7071 * caused us (the shell) to no longer be in the controlling
7072 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7073 * intuit from the subprocess exit status whether a SIGINT
7074 * occured, and if so interrupt ourselves. Yuck. - mycroft
7075 */
7076 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
7077 raise(SIGINT);
7078 }
Eric Andersen2870d962001-07-02 17:27:21 +00007079 if (jp->state == JOBDONE)
7080
Eric Andersencb57d552001-06-28 07:25:16 +00007081#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007082 freejob(jp);
7083 INTON;
7084 return st;
7085}
7086
7087
7088
7089/*
7090 * Wait for a process to terminate.
7091 */
7092
Eric Andersen62483552001-07-10 06:09:16 +00007093/*
7094 * Do a wait system call. If job control is compiled in, we accept
7095 * stopped processes. If block is zero, we return a value of zero
7096 * rather than blocking.
7097 *
7098 * System V doesn't have a non-blocking wait system call. It does
7099 * have a SIGCLD signal that is sent to a process when one of it's
7100 * children dies. The obvious way to use SIGCLD would be to install
7101 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7102 * was received, and have waitproc bump another counter when it got
7103 * the status of a process. Waitproc would then know that a wait
7104 * system call would not block if the two counters were different.
7105 * This approach doesn't work because if a process has children that
7106 * have not been waited for, System V will send it a SIGCLD when it
7107 * installs a signal handler for SIGCLD. What this means is that when
7108 * a child exits, the shell will be sent SIGCLD signals continuously
7109 * until is runs out of stack space, unless it does a wait call before
7110 * restoring the signal handler. The code below takes advantage of
7111 * this (mis)feature by installing a signal handler for SIGCLD and
7112 * then checking to see whether it was called. If there are any
7113 * children to be waited for, it will be.
7114 *
7115 */
7116
7117static inline int
7118waitproc(int block, int *status)
7119{
7120 int flags;
7121
7122 flags = 0;
7123#ifdef JOBS
7124 if (jobctl)
7125 flags |= WUNTRACED;
7126#endif
7127 if (block == 0)
7128 flags |= WNOHANG;
7129 return wait3(status, flags, (struct rusage *)NULL);
7130}
7131
Eric Andersencb57d552001-06-28 07:25:16 +00007132static int
Eric Andersen62483552001-07-10 06:09:16 +00007133dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00007134{
7135 int pid;
7136 int status;
7137 struct procstat *sp;
7138 struct job *jp;
7139 struct job *thisjob;
7140 int done;
7141 int stopped;
7142 int core;
7143 int sig;
7144
7145 TRACE(("dowait(%d) called\n", block));
7146 do {
7147 pid = waitproc(block, &status);
7148 TRACE(("wait returns %d, status=%d\n", pid, status));
7149 } while (!(block & 2) && pid == -1 && errno == EINTR);
7150 if (pid <= 0)
7151 return pid;
7152 INTOFF;
7153 thisjob = NULL;
7154 for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
7155 if (jp->used) {
7156 done = 1;
7157 stopped = 1;
7158 for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
7159 if (sp->pid == -1)
7160 continue;
7161 if (sp->pid == pid) {
7162 TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
7163 sp->status = status;
7164 thisjob = jp;
7165 }
7166 if (sp->status == -1)
7167 stopped = 0;
7168 else if (WIFSTOPPED(sp->status))
7169 done = 0;
7170 }
Eric Andersen2870d962001-07-02 17:27:21 +00007171 if (stopped) { /* stopped or done */
Eric Andersencb57d552001-06-28 07:25:16 +00007172 int state = done? JOBDONE : JOBSTOPPED;
7173 if (jp->state != state) {
7174 TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
7175 jp->state = state;
Eric Andersen2870d962001-07-02 17:27:21 +00007176#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007177 if (done && curjob == jp - jobtab + 1)
Eric Andersen2870d962001-07-02 17:27:21 +00007178 curjob = 0; /* no current job */
Eric Andersencb57d552001-06-28 07:25:16 +00007179#endif
7180 }
7181 }
7182 }
7183 }
7184 INTON;
7185 if (! rootshell || ! iflag || (job && thisjob == job)) {
7186 core = WCOREDUMP(status);
Eric Andersen2870d962001-07-02 17:27:21 +00007187#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007188 if (WIFSTOPPED(status)) sig = WSTOPSIG(status);
7189 else
7190#endif
7191 if (WIFEXITED(status)) sig = 0;
7192 else sig = WTERMSIG(status);
7193
7194 if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
7195 if (thisjob != job)
Eric Andersen3102ac42001-07-06 04:26:23 +00007196 out2fmt("%d: ", pid);
Eric Andersen2870d962001-07-02 17:27:21 +00007197#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007198 if (sig == SIGTSTP && rootshell && iflag)
Eric Andersen3102ac42001-07-06 04:26:23 +00007199 out2fmt("%%%ld ",
Eric Andersencb57d552001-06-28 07:25:16 +00007200 (long)(job - jobtab + 1));
7201#endif
7202 if (sig < NSIG && sys_siglist[sig])
7203 out2str(sys_siglist[sig]);
7204 else
Eric Andersen3102ac42001-07-06 04:26:23 +00007205 out2fmt("Signal %d", sig);
Eric Andersencb57d552001-06-28 07:25:16 +00007206 if (core)
7207 out2str(" - core dumped");
7208 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00007209 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00007210 TRACE(("Not printing status: status=%d, sig=%d\n",
Eric Andersencb57d552001-06-28 07:25:16 +00007211 status, sig));
7212 }
7213 } else {
7214 TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
7215 if (thisjob)
7216 thisjob->changed = 1;
7217 }
7218 return pid;
7219}
7220
7221
7222
Eric Andersencb57d552001-06-28 07:25:16 +00007223
7224/*
7225 * return 1 if there are stopped jobs, otherwise 0
7226 */
Eric Andersencb57d552001-06-28 07:25:16 +00007227static int
Eric Andersen2870d962001-07-02 17:27:21 +00007228stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007229{
7230 int jobno;
7231 struct job *jp;
7232
7233 if (job_warning)
7234 return (0);
7235 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
7236 if (jp->used == 0)
7237 continue;
7238 if (jp->state == JOBSTOPPED) {
7239 out2str("You have stopped jobs.\n");
7240 job_warning = 2;
7241 return (1);
7242 }
7243 }
7244
7245 return (0);
7246}
7247
7248/*
7249 * Return a string identifying a command (to be printed by the
7250 * jobs command.
7251 */
7252
7253static char *cmdnextc;
7254static int cmdnleft;
Eric Andersen2870d962001-07-02 17:27:21 +00007255#define MAXCMDTEXT 200
Eric Andersencb57d552001-06-28 07:25:16 +00007256
Eric Andersen2870d962001-07-02 17:27:21 +00007257static void
7258cmdputs(const char *s)
7259{
7260 const char *p;
7261 char *q;
7262 char c;
7263 int subtype = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007264
Eric Andersen2870d962001-07-02 17:27:21 +00007265 if (cmdnleft <= 0)
7266 return;
7267 p = s;
7268 q = cmdnextc;
7269 while ((c = *p++) != '\0') {
7270 if (c == CTLESC)
7271 *q++ = *p++;
7272 else if (c == CTLVAR) {
7273 *q++ = '$';
7274 if (--cmdnleft > 0)
7275 *q++ = '{';
7276 subtype = *p++;
7277 } else if (c == '=' && subtype != 0) {
7278 *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
7279 subtype = 0;
7280 } else if (c == CTLENDVAR) {
7281 *q++ = '}';
7282 } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
7283 cmdnleft++; /* ignore it */
7284 else
7285 *q++ = c;
7286 if (--cmdnleft <= 0) {
7287 *q++ = '.';
7288 *q++ = '.';
7289 *q++ = '.';
7290 break;
7291 }
7292 }
7293 cmdnextc = q;
Eric Andersencb57d552001-06-28 07:25:16 +00007294}
7295
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007296//#define CMDTXT_TABLE
7297#ifdef CMDTXT_TABLE
7298/*
7299 * To collect a lot of redundant code in cmdtxt() case statements, we
7300 * implement a mini language here. Each type of node struct has an
7301 * associated instruction sequence that operates on its members via
7302 * their offsets. The instruction are pack in unsigned chars with
7303 * format IIDDDDDE where the bits are
7304 * I : part of the instruction opcode, which are
7305 * 00 : member is a pointer to another node -- process it recursively
7306 * 40 : member is a pointer to a char string -- output it
7307 * 80 : output the string whose index is stored in the data field
7308 * CC : flag signaling that this case needs external processing
7309 * D : data - either the (shifted) index of a fixed string to output or
7310 * the actual offset of the member to operate on in the struct
7311 * (since we assume bit 0 is set, the offset is not shifted)
7312 * E : flag signaling end of instruction sequence
7313 *
7314 * WARNING: In order to handle larger offsets for 64bit archs, this code
7315 * assumes that no offset can be an odd number and stores the
7316 * end-of-instructions flag in bit 0.
7317 */
Eric Andersencb57d552001-06-28 07:25:16 +00007318
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007319#define CMDTXT_NOMORE 0x01 /* NOTE: no offset should be odd */
7320#define CMDTXT_CHARPTR 0x40
7321#define CMDTXT_STRING 0x80
7322#define CMDTXT_SPECIAL 0xC0
7323#define CMDTXT_OFFSETMASK 0x3E
7324
7325static const char * const cmdtxt_strings[] = {
7326 /* 0 1 2 3 4 5 6 7 */
7327 "; ", "(", ")", " && ", " || ", "if ", "; then ", "...",
7328 /* 8 9 10 11 12 13 */
7329 "while ", "; do ", "; done", "until ", "for ", " in ...",
7330 /* 14 15 16 17 */
7331 "case ", "???", "() ...", "<<..."
7332};
7333
7334static const char * const redir_strings[] = {
7335 ">", "<", "<>", ">>", ">|", ">&", "<&"
7336};
7337
7338static const unsigned char cmdtxt_ops[] = {
7339#define CMDTXT_NSEMI 0
7340 offsetof(union node, nbinary.ch1),
7341 0|CMDTXT_STRING,
7342 offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7343#define CMDTXT_NCMD (CMDTXT_NSEMI + 3)
7344#define CMDTXT_NPIPE (CMDTXT_NCMD)
7345#define CMDTXT_NCASE (CMDTXT_NCMD)
7346#define CMDTXT_NTO (CMDTXT_NCMD)
7347#define CMDTXT_NFROM (CMDTXT_NCMD)
7348#define CMDTXT_NFROMTO (CMDTXT_NCMD)
7349#define CMDTXT_NAPPEND (CMDTXT_NCMD)
7350#define CMDTXT_NTOOV (CMDTXT_NCMD)
7351#define CMDTXT_NTOFD (CMDTXT_NCMD)
7352#define CMDTXT_NFROMFD (CMDTXT_NCMD)
7353 CMDTXT_SPECIAL,
7354#define CMDTXT_NREDIR (CMDTXT_NPIPE + 1)
7355#define CMDTXT_NBACKGND (CMDTXT_NREDIR)
7356 offsetof(union node, nredir.n)|CMDTXT_NOMORE,
7357#define CMDTXT_NSUBSHELL (CMDTXT_NBACKGND + 1)
7358 (1*2)|CMDTXT_STRING,
7359 offsetof(union node, nredir.n),
7360 (2*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7361#define CMDTXT_NAND (CMDTXT_NSUBSHELL + 3)
7362 offsetof(union node, nbinary.ch1),
7363 (3*2)|CMDTXT_STRING,
7364 offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7365#define CMDTXT_NOR (CMDTXT_NAND + 3)
7366 offsetof(union node, nbinary.ch1),
7367 (4*2)|CMDTXT_STRING,
7368 offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7369#define CMDTXT_NIF (CMDTXT_NOR + 3)
7370 (5*2)|CMDTXT_STRING,
7371 offsetof(union node, nif.test),
7372 (6*2)|CMDTXT_STRING,
7373 offsetof(union node, nif.ifpart),
7374 (7*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7375#define CMDTXT_NWHILE (CMDTXT_NIF + 5)
7376 (8*2)|CMDTXT_STRING,
7377 offsetof(union node, nbinary.ch1),
7378 (9*2)|CMDTXT_STRING,
7379 offsetof(union node, nbinary.ch2),
7380 (10*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7381#define CMDTXT_NUNTIL (CMDTXT_NWHILE + 5)
7382 (11*2)|CMDTXT_STRING,
7383 offsetof(union node, nbinary.ch1),
7384 (9*2)|CMDTXT_STRING,
7385 offsetof(union node, nbinary.ch2),
7386 (10*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7387#define CMDTXT_NFOR (CMDTXT_NUNTIL + 5)
7388 (12*2)|CMDTXT_STRING,
7389 offsetof(union node, nfor.var)|CMDTXT_CHARPTR,
7390 (13*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7391#define CMDTXT_NCLIST (CMDTXT_NFOR + 3) /* TODO: IS THIS CORRECT??? */
7392#define CMDTXT_NNOT (CMDTXT_NCLIST) /* TODO: IS THIS CORRECT??? */
7393 (15*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7394#define CMDTXT_NDEFUN (CMDTXT_NCLIST + 1)
7395 offsetof(union node, narg.text)|CMDTXT_CHARPTR,
7396 (16*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7397#define CMDTXT_NARG (CMDTXT_NDEFUN + 2)
7398 offsetof(union node, narg.text)|CMDTXT_CHARPTR|CMDTXT_NOMORE,
7399#define CMDTXT_NHERE (CMDTXT_NARG + 1)
7400#define CMDTXT_NXHERE (CMDTXT_NHERE)
7401 (17*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7402};
7403
7404#if CMDTXT_NXHERE != 36
7405#error CMDTXT_NXHERE
7406#endif
7407
7408static const unsigned char cmdtxt_ops_index[26] = {
7409 CMDTXT_NSEMI,
7410 CMDTXT_NCMD,
7411 CMDTXT_NPIPE,
7412 CMDTXT_NREDIR,
7413 CMDTXT_NBACKGND,
7414 CMDTXT_NSUBSHELL,
7415 CMDTXT_NAND,
7416 CMDTXT_NOR,
7417 CMDTXT_NIF,
7418 CMDTXT_NWHILE,
7419 CMDTXT_NUNTIL,
7420 CMDTXT_NFOR,
7421 CMDTXT_NCASE,
7422 CMDTXT_NCLIST,
7423 CMDTXT_NDEFUN,
7424 CMDTXT_NARG,
7425 CMDTXT_NTO,
7426 CMDTXT_NFROM,
7427 CMDTXT_NFROMTO,
7428 CMDTXT_NAPPEND,
7429 CMDTXT_NTOOV,
7430 CMDTXT_NTOFD,
7431 CMDTXT_NFROMFD,
7432 CMDTXT_NHERE,
7433 CMDTXT_NXHERE,
7434 CMDTXT_NNOT,
7435};
7436
7437static void
7438cmdtxt(const union node *n)
7439{
7440 const char *p;
7441
7442 if (n == NULL)
7443 return;
7444
7445 p = cmdtxt_ops + (int) cmdtxt_ops_index[n->type];
7446 if ((*p & CMDTXT_SPECIAL) != CMDTXT_SPECIAL) { /* normal case */
7447 do {
7448 if (*p & CMDTXT_STRING) { /* output fixed string */
7449 cmdputs(cmdtxt_strings[((int)(*p & CMDTXT_OFFSETMASK) >> 1)]);
Manuel Novoa III c639a352001-08-12 17:32:56 +00007450 } else {
7451 const char *pf = ((const char *) n)
7452 + ((int)(*p & CMDTXT_OFFSETMASK));
7453 if (*p & CMDTXT_CHARPTR) { /* output dynamic string */
7454 cmdputs(*((const char **) pf));
7455 } else { /* output field */
7456 cmdtxt(*((const union node **) pf));
7457 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007458 }
7459 } while (!(*p++ & CMDTXT_NOMORE));
7460 } else if (n->type == NCMD) {
7461 union node *np;
7462 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7463 cmdtxt(np);
7464 if (np->narg.next)
7465 cmdputs(spcstr);
7466 }
7467 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7468 cmdputs(spcstr);
7469 cmdtxt(np);
7470 }
7471 } else if (n->type == NPIPE) {
7472 struct nodelist *lp;
7473 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7474 cmdtxt(lp->n);
7475 if (lp->next)
7476 cmdputs(" | ");
7477 }
7478 } else if (n->type == NCASE) {
7479 cmdputs(cmdtxt_strings[14]);
7480 cmdputs(n->ncase.expr->narg.text);
7481 cmdputs(cmdtxt_strings[13]);
7482 } else {
7483#if (NTO != 16) || (NFROM != 17) || (NFROMTO != 18) || (NAPPEND != 19) || (NTOOV != 20) || (NTOFD != 21) || (NFROMFD != 22)
7484#error Assumption violated regarding range and ordering of NTO ... NFROMFD!
7485#endif
7486 char s[2];
7487
7488#ifdef DEBUG
7489 assert((n->type >= NTO) && (n->type <= NFROMFD));
7490#endif
7491
7492 p = redir_strings[n->type - NTO];
7493 if (n->nfile.fd != ('>' == *p)) {
7494 s[0] = n->nfile.fd + '0';
7495 s[1] = '\0';
7496 cmdputs(s);
7497 }
7498 cmdputs(p);
7499 if (n->type >= NTOFD) {
7500 s[0] = n->ndup.dupfd + '0';
7501 s[1] = '\0';
7502 cmdputs(s);
7503 } else {
7504 cmdtxt(n->nfile.fname);
7505 }
7506 }
7507}
7508#else /* CMDTXT_TABLE */
Eric Andersencb57d552001-06-28 07:25:16 +00007509static void
Eric Andersen2870d962001-07-02 17:27:21 +00007510cmdtxt(const union node *n)
7511{
Eric Andersencb57d552001-06-28 07:25:16 +00007512 union node *np;
7513 struct nodelist *lp;
7514 const char *p;
7515 int i;
7516 char s[2];
7517
7518 if (n == NULL)
7519 return;
7520 switch (n->type) {
7521 case NSEMI:
7522 cmdtxt(n->nbinary.ch1);
7523 cmdputs("; ");
7524 cmdtxt(n->nbinary.ch2);
7525 break;
7526 case NAND:
7527 cmdtxt(n->nbinary.ch1);
7528 cmdputs(" && ");
7529 cmdtxt(n->nbinary.ch2);
7530 break;
7531 case NOR:
7532 cmdtxt(n->nbinary.ch1);
7533 cmdputs(" || ");
7534 cmdtxt(n->nbinary.ch2);
7535 break;
7536 case NPIPE:
7537 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7538 cmdtxt(lp->n);
7539 if (lp->next)
7540 cmdputs(" | ");
7541 }
7542 break;
7543 case NSUBSHELL:
7544 cmdputs("(");
7545 cmdtxt(n->nredir.n);
7546 cmdputs(")");
7547 break;
7548 case NREDIR:
7549 case NBACKGND:
7550 cmdtxt(n->nredir.n);
7551 break;
7552 case NIF:
7553 cmdputs("if ");
7554 cmdtxt(n->nif.test);
7555 cmdputs("; then ");
7556 cmdtxt(n->nif.ifpart);
7557 cmdputs("...");
7558 break;
7559 case NWHILE:
7560 cmdputs("while ");
7561 goto until;
7562 case NUNTIL:
7563 cmdputs("until ");
7564until:
7565 cmdtxt(n->nbinary.ch1);
7566 cmdputs("; do ");
7567 cmdtxt(n->nbinary.ch2);
7568 cmdputs("; done");
7569 break;
7570 case NFOR:
7571 cmdputs("for ");
7572 cmdputs(n->nfor.var);
7573 cmdputs(" in ...");
7574 break;
7575 case NCASE:
7576 cmdputs("case ");
7577 cmdputs(n->ncase.expr->narg.text);
7578 cmdputs(" in ...");
7579 break;
7580 case NDEFUN:
7581 cmdputs(n->narg.text);
7582 cmdputs("() ...");
7583 break;
7584 case NCMD:
7585 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7586 cmdtxt(np);
7587 if (np->narg.next)
7588 cmdputs(spcstr);
7589 }
7590 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7591 cmdputs(spcstr);
7592 cmdtxt(np);
7593 }
7594 break;
7595 case NARG:
7596 cmdputs(n->narg.text);
7597 break;
7598 case NTO:
7599 p = ">"; i = 1; goto redir;
7600 case NAPPEND:
7601 p = ">>"; i = 1; goto redir;
7602 case NTOFD:
7603 p = ">&"; i = 1; goto redir;
7604 case NTOOV:
7605 p = ">|"; i = 1; goto redir;
7606 case NFROM:
7607 p = "<"; i = 0; goto redir;
7608 case NFROMFD:
7609 p = "<&"; i = 0; goto redir;
7610 case NFROMTO:
7611 p = "<>"; i = 0; goto redir;
7612redir:
7613 if (n->nfile.fd != i) {
7614 s[0] = n->nfile.fd + '0';
7615 s[1] = '\0';
7616 cmdputs(s);
7617 }
7618 cmdputs(p);
7619 if (n->type == NTOFD || n->type == NFROMFD) {
7620 s[0] = n->ndup.dupfd + '0';
7621 s[1] = '\0';
7622 cmdputs(s);
7623 } else {
7624 cmdtxt(n->nfile.fname);
7625 }
7626 break;
7627 case NHERE:
7628 case NXHERE:
7629 cmdputs("<<...");
7630 break;
7631 default:
7632 cmdputs("???");
7633 break;
7634 }
7635}
Manuel Novoa III c639a352001-08-12 17:32:56 +00007636#endif /* CMDTXT_TABLE */
Eric Andersencb57d552001-06-28 07:25:16 +00007637
Eric Andersen2870d962001-07-02 17:27:21 +00007638static char *
7639commandtext(const union node *n)
7640{
7641 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007642
Eric Andersen2870d962001-07-02 17:27:21 +00007643 cmdnextc = name = ckmalloc(MAXCMDTEXT);
7644 cmdnleft = MAXCMDTEXT - 4;
7645 cmdtxt(n);
7646 *cmdnextc = '\0';
7647 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00007648}
7649
Eric Andersen2870d962001-07-02 17:27:21 +00007650
Eric Andersencb57d552001-06-28 07:25:16 +00007651static void waitonint(int sig) {
7652 intreceived = 1;
7653 return;
7654}
Eric Andersencb57d552001-06-28 07:25:16 +00007655/*
7656 * Routines to check for mail. (Perhaps make part of main.c?)
7657 */
7658
7659
7660#define MAXMBOXES 10
7661
7662
Eric Andersen2870d962001-07-02 17:27:21 +00007663static int nmboxes; /* number of mailboxes */
7664static time_t mailtime[MAXMBOXES]; /* times of mailboxes */
Eric Andersencb57d552001-06-28 07:25:16 +00007665
7666
7667
7668/*
7669 * Print appropriate message(s) if mail has arrived. If the argument is
7670 * nozero, then the value of MAIL has changed, so we just update the
7671 * values.
7672 */
7673
7674static void
Eric Andersen2870d962001-07-02 17:27:21 +00007675chkmail(int silent)
Eric Andersencb57d552001-06-28 07:25:16 +00007676{
7677 int i;
7678 const char *mpath;
7679 char *p;
7680 char *q;
7681 struct stackmark smark;
7682 struct stat statb;
7683
7684 if (silent)
7685 nmboxes = 10;
7686 if (nmboxes == 0)
7687 return;
7688 setstackmark(&smark);
7689 mpath = mpathset()? mpathval() : mailval();
7690 for (i = 0 ; i < nmboxes ; i++) {
7691 p = padvance(&mpath, nullstr);
7692 if (p == NULL)
7693 break;
7694 if (*p == '\0')
7695 continue;
7696 for (q = p ; *q ; q++);
7697#ifdef DEBUG
7698 if (q[-1] != '/')
7699 abort();
7700#endif
Eric Andersen2870d962001-07-02 17:27:21 +00007701 q[-1] = '\0'; /* delete trailing '/' */
Eric Andersencb57d552001-06-28 07:25:16 +00007702 if (stat(p, &statb) < 0)
7703 statb.st_size = 0;
7704 if (statb.st_size > mailtime[i] && ! silent) {
Eric Andersen3102ac42001-07-06 04:26:23 +00007705 out2fmt(snlfmt,
7706 pathopt? pathopt : "you have mail");
Eric Andersencb57d552001-06-28 07:25:16 +00007707 }
7708 mailtime[i] = statb.st_size;
Eric Andersencb57d552001-06-28 07:25:16 +00007709 }
7710 nmboxes = i;
7711 popstackmark(&smark);
7712}
Eric Andersencb57d552001-06-28 07:25:16 +00007713
7714#define PROFILE 0
7715
Eric Andersencb57d552001-06-28 07:25:16 +00007716#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007717static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007718extern int etext();
7719#endif
7720
Eric Andersen2870d962001-07-02 17:27:21 +00007721static void read_profile (const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007722static void cmdloop (int);
7723static void options (int);
Eric Andersen2870d962001-07-02 17:27:21 +00007724static void setoption (int, int);
7725static void procargs (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00007726
Eric Andersen2870d962001-07-02 17:27:21 +00007727
Eric Andersencb57d552001-06-28 07:25:16 +00007728/*
7729 * Main routine. We initialize things, parse the arguments, execute
7730 * profiles if we're a login shell, and then call cmdloop to execute
7731 * commands. The setjmp call sets up the location to jump to when an
7732 * exception occurs. When an exception occurs the variable "state"
7733 * is used to figure out how far we had gotten.
7734 */
7735
7736int
Matt Kraai2d91deb2001-08-01 17:21:35 +00007737ash_main(argc, argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007738 int argc;
7739 char **argv;
7740{
7741 struct jmploc jmploc;
7742 struct stackmark smark;
7743 volatile int state;
Eric Andersen62483552001-07-10 06:09:16 +00007744 const char *shinit;
Eric Andersencb57d552001-06-28 07:25:16 +00007745
Eric Andersencb57d552001-06-28 07:25:16 +00007746 BLTINCMD = find_builtin("builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00007747 EXECCMD = find_builtin("exec");
7748 EVALCMD = find_builtin("eval");
7749
Eric Andersen1c039232001-07-07 00:05:55 +00007750#ifndef BB_FEATURE_SH_FANCY_PROMPT
7751 unsetenv("PS1");
7752 unsetenv("PS2");
7753#endif
7754
Eric Andersencb57d552001-06-28 07:25:16 +00007755#if PROFILE
7756 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7757#endif
7758#if defined(linux) || defined(__GNU__)
7759 signal(SIGCHLD, SIG_DFL);
7760#endif
7761 state = 0;
7762 if (setjmp(jmploc.loc)) {
7763 INTOFF;
7764 /*
7765 * When a shell procedure is executed, we raise the
7766 * exception EXSHELLPROC to clean up before executing
7767 * the shell procedure.
7768 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007769 if (exception == EXSHELLPROC) {
Eric Andersencb57d552001-06-28 07:25:16 +00007770 rootpid = getpid();
7771 rootshell = 1;
7772 minusc = NULL;
7773 state = 3;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007774 } else {
7775 if (exception == EXEXEC) {
7776 exitstatus = exerrno;
7777 } else if (exception == EXERROR) {
7778 exitstatus = 2;
7779 }
Eric Andersencb57d552001-06-28 07:25:16 +00007780 if (state == 0 || iflag == 0 || ! rootshell)
7781 exitshell(exitstatus);
7782 }
7783 reset();
Eric Andersen2870d962001-07-02 17:27:21 +00007784 if (exception == EXINT) {
Eric Andersencb57d552001-06-28 07:25:16 +00007785 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00007786 }
7787 popstackmark(&smark);
Eric Andersen2870d962001-07-02 17:27:21 +00007788 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007789 if (state == 1)
7790 goto state1;
7791 else if (state == 2)
7792 goto state2;
7793 else if (state == 3)
7794 goto state3;
7795 else
7796 goto state4;
7797 }
7798 handler = &jmploc;
7799#ifdef DEBUG
7800 opentrace();
7801 trputs("Shell args: "); trargs(argv);
7802#endif
7803 rootpid = getpid();
7804 rootshell = 1;
7805 init();
7806 setstackmark(&smark);
7807 procargs(argc, argv);
7808 if (argv[0] && argv[0][0] == '-') {
7809 state = 1;
7810 read_profile("/etc/profile");
7811state1:
7812 state = 2;
7813 read_profile(".profile");
7814 }
7815state2:
7816 state = 3;
7817#ifndef linux
7818 if (getuid() == geteuid() && getgid() == getegid()) {
7819#endif
7820 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7821 state = 3;
7822 read_profile(shinit);
7823 }
7824#ifndef linux
7825 }
7826#endif
7827state3:
7828 state = 4;
7829 if (sflag == 0 || minusc) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007830 static const char sigs[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00007831 SIGINT, SIGQUIT, SIGHUP,
Eric Andersencb57d552001-06-28 07:25:16 +00007832#ifdef SIGTSTP
7833 SIGTSTP,
7834#endif
7835 SIGPIPE
7836 };
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007837#define SIGSSIZE ((sizeof(sigs)/sizeof(sigs[0])) - 1) /* trailing nul */
Eric Andersencb57d552001-06-28 07:25:16 +00007838 int i;
7839
7840 for (i = 0; i < SIGSSIZE; i++)
7841 setsignal(sigs[i]);
7842 }
7843
7844 if (minusc)
7845 evalstring(minusc, 0);
7846
7847 if (sflag || minusc == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00007848state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007849 cmdloop(1);
7850 }
7851#if PROFILE
7852 monitor(0);
7853#endif
7854 exitshell(exitstatus);
7855 /* NOTREACHED */
7856}
7857
7858
7859/*
7860 * Read and execute commands. "Top" is nonzero for the top level command
7861 * loop; it turns on prompting if the shell is interactive.
7862 */
7863
7864static void
Eric Andersen2870d962001-07-02 17:27:21 +00007865cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00007866{
7867 union node *n;
7868 struct stackmark smark;
7869 int inter;
7870 int numeof = 0;
7871
7872 TRACE(("cmdloop(%d) called\n", top));
7873 setstackmark(&smark);
7874 for (;;) {
7875 if (pendingsigs)
7876 dotrap();
7877 inter = 0;
7878 if (iflag && top) {
7879 inter++;
7880 showjobs(1);
7881 chkmail(0);
Eric Andersen3102ac42001-07-06 04:26:23 +00007882 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00007883 }
7884 n = parsecmd(inter);
7885 /* showtree(n); DEBUG */
7886 if (n == NEOF) {
7887 if (!top || numeof >= 50)
7888 break;
7889 if (!stoppedjobs()) {
7890 if (!Iflag)
7891 break;
7892 out2str("\nUse \"exit\" to leave shell.\n");
7893 }
7894 numeof++;
7895 } else if (n != NULL && nflag == 0) {
7896 job_warning = (job_warning == 2) ? 1 : 0;
7897 numeof = 0;
7898 evaltree(n, 0);
7899 }
7900 popstackmark(&smark);
7901 setstackmark(&smark);
7902 if (evalskip == SKIPFILE) {
7903 evalskip = 0;
7904 break;
7905 }
7906 }
7907 popstackmark(&smark);
7908}
7909
7910
7911
7912/*
7913 * Read /etc/profile or .profile. Return on error.
7914 */
7915
7916static void
7917read_profile(name)
7918 const char *name;
7919{
7920 int fd;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007921 int xflag_save;
7922 int vflag_save;
Eric Andersencb57d552001-06-28 07:25:16 +00007923
7924 INTOFF;
7925 if ((fd = open(name, O_RDONLY)) >= 0)
7926 setinputfd(fd, 1);
7927 INTON;
7928 if (fd < 0)
7929 return;
7930 /* -q turns off -x and -v just when executing init files */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007931 /* Note: Might do a little redundant work, but reduces code size. */
7932 xflag_save = xflag;
7933 vflag_save = vflag;
Eric Andersencb57d552001-06-28 07:25:16 +00007934 if (qflag) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007935 vflag = xflag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007936 }
7937 cmdloop(0);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007938 xflag = xflag_save;
7939 vflag = vflag_save;
Eric Andersencb57d552001-06-28 07:25:16 +00007940 popfile();
7941}
7942
7943
7944
7945/*
7946 * Read a file containing shell functions.
7947 */
7948
7949static void
Eric Andersen2870d962001-07-02 17:27:21 +00007950readcmdfile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00007951{
7952 int fd;
7953
7954 INTOFF;
7955 if ((fd = open(name, O_RDONLY)) >= 0)
7956 setinputfd(fd, 1);
7957 else
7958 error("Can't open %s", name);
7959 INTON;
7960 cmdloop(0);
7961 popfile();
7962}
7963
7964
7965
7966/*
7967 * Take commands from a file. To be compatable we should do a path
7968 * search for the file, which is necessary to find sub-commands.
7969 */
7970
7971
Eric Andersen62483552001-07-10 06:09:16 +00007972static inline char *
Eric Andersencb57d552001-06-28 07:25:16 +00007973find_dot_file(mybasename)
7974 char *mybasename;
7975{
7976 char *fullname;
7977 const char *path = pathval();
7978 struct stat statb;
7979
7980 /* don't try this for absolute or relative paths */
7981 if (strchr(mybasename, '/'))
7982 return mybasename;
7983
7984 while ((fullname = padvance(&path, mybasename)) != NULL) {
7985 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
7986 /*
7987 * Don't bother freeing here, since it will
7988 * be freed by the caller.
7989 */
7990 return fullname;
7991 }
7992 stunalloc(fullname);
7993 }
7994
7995 /* not found in the PATH */
7996 error("%s: not found", mybasename);
7997 /* NOTREACHED */
7998}
7999
8000static int
8001dotcmd(argc, argv)
8002 int argc;
8003 char **argv;
8004{
8005 struct strlist *sp;
8006 exitstatus = 0;
8007
8008 for (sp = cmdenviron; sp ; sp = sp->next)
8009 setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
8010
Eric Andersen2870d962001-07-02 17:27:21 +00008011 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00008012 char *fullname;
8013 struct stackmark smark;
8014
8015 setstackmark(&smark);
8016 fullname = find_dot_file(argv[1]);
8017 setinputfile(fullname, 1);
8018 commandname = fullname;
8019 cmdloop(0);
8020 popfile();
8021 popstackmark(&smark);
8022 }
8023 return exitstatus;
8024}
8025
8026
8027static int
8028exitcmd(argc, argv)
8029 int argc;
8030 char **argv;
8031{
8032 if (stoppedjobs())
8033 return 0;
8034 if (argc > 1)
8035 exitstatus = number(argv[1]);
8036 else
8037 exitstatus = oexitstatus;
8038 exitshell(exitstatus);
8039 /* NOTREACHED */
8040}
Eric Andersen62483552001-07-10 06:09:16 +00008041
Eric Andersen2870d962001-07-02 17:27:21 +00008042static pointer
8043stalloc(int nbytes)
Eric Andersencb57d552001-06-28 07:25:16 +00008044{
8045 char *p;
8046
8047 nbytes = ALIGN(nbytes);
8048 if (nbytes > stacknleft) {
8049 int blocksize;
8050 struct stack_block *sp;
8051
8052 blocksize = nbytes;
8053 if (blocksize < MINSIZE)
8054 blocksize = MINSIZE;
8055 INTOFF;
8056 sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
8057 sp->prev = stackp;
8058 stacknxt = sp->space;
8059 stacknleft = blocksize;
8060 stackp = sp;
8061 INTON;
8062 }
8063 p = stacknxt;
8064 stacknxt += nbytes;
8065 stacknleft -= nbytes;
8066 return p;
8067}
8068
8069
8070static void
Eric Andersen2870d962001-07-02 17:27:21 +00008071stunalloc(pointer p)
8072{
Eric Andersencb57d552001-06-28 07:25:16 +00008073#ifdef DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +00008074 if (p == NULL) { /*DEBUG */
Eric Andersencb57d552001-06-28 07:25:16 +00008075 write(2, "stunalloc\n", 10);
8076 abort();
8077 }
8078#endif
8079 if (!(stacknxt >= (char *)p && (char *)p >= stackp->space)) {
8080 p = stackp->space;
8081 }
8082 stacknleft += stacknxt - (char *)p;
8083 stacknxt = p;
8084}
8085
8086
Eric Andersencb57d552001-06-28 07:25:16 +00008087static void
Eric Andersen2870d962001-07-02 17:27:21 +00008088setstackmark(struct stackmark *mark)
8089{
Eric Andersencb57d552001-06-28 07:25:16 +00008090 mark->stackp = stackp;
8091 mark->stacknxt = stacknxt;
8092 mark->stacknleft = stacknleft;
8093 mark->marknext = markp;
8094 markp = mark;
8095}
8096
8097
8098static void
Eric Andersen2870d962001-07-02 17:27:21 +00008099popstackmark(struct stackmark *mark)
8100{
Eric Andersencb57d552001-06-28 07:25:16 +00008101 struct stack_block *sp;
8102
8103 INTOFF;
8104 markp = mark->marknext;
8105 while (stackp != mark->stackp) {
8106 sp = stackp;
8107 stackp = sp->prev;
8108 ckfree(sp);
8109 }
8110 stacknxt = mark->stacknxt;
8111 stacknleft = mark->stacknleft;
8112 INTON;
8113}
8114
8115
8116/*
8117 * When the parser reads in a string, it wants to stick the string on the
8118 * stack and only adjust the stack pointer when it knows how big the
8119 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8120 * of space on top of the stack and stackblocklen returns the length of
8121 * this block. Growstackblock will grow this space by at least one byte,
8122 * possibly moving it (like realloc). Grabstackblock actually allocates the
8123 * part of the block that has been used.
8124 */
8125
8126static void
Eric Andersen2870d962001-07-02 17:27:21 +00008127growstackblock(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00008128 char *p;
8129 int newlen = ALIGN(stacknleft * 2 + 100);
8130 char *oldspace = stacknxt;
8131 int oldlen = stacknleft;
8132 struct stack_block *sp;
8133 struct stack_block *oldstackp;
8134
8135 if (stacknxt == stackp->space && stackp != &stackbase) {
8136 INTOFF;
8137 oldstackp = stackp;
8138 sp = stackp;
8139 stackp = sp->prev;
8140 sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen);
8141 sp->prev = stackp;
8142 stackp = sp;
8143 stacknxt = sp->space;
8144 stacknleft = newlen;
8145 {
8146 /* Stack marks pointing to the start of the old block
Eric Andersen2870d962001-07-02 17:27:21 +00008147 * must be relocated to point to the new block
Eric Andersencb57d552001-06-28 07:25:16 +00008148 */
8149 struct stackmark *xmark;
8150 xmark = markp;
8151 while (xmark != NULL && xmark->stackp == oldstackp) {
8152 xmark->stackp = stackp;
8153 xmark->stacknxt = stacknxt;
8154 xmark->stacknleft = stacknleft;
8155 xmark = xmark->marknext;
8156 }
8157 }
8158 INTON;
8159 } else {
8160 p = stalloc(newlen);
8161 memcpy(p, oldspace, oldlen);
Eric Andersen2870d962001-07-02 17:27:21 +00008162 stacknxt = p; /* free the space */
8163 stacknleft += newlen; /* we just allocated */
Eric Andersencb57d552001-06-28 07:25:16 +00008164 }
8165}
8166
8167
8168
Eric Andersen2870d962001-07-02 17:27:21 +00008169static inline void
8170grabstackblock(int len)
Eric Andersencb57d552001-06-28 07:25:16 +00008171{
8172 len = ALIGN(len);
8173 stacknxt += len;
8174 stacknleft -= len;
8175}
8176
8177
8178
8179/*
8180 * The following routines are somewhat easier to use that the above.
8181 * The user declares a variable of type STACKSTR, which may be declared
8182 * to be a register. The macro STARTSTACKSTR initializes things. Then
8183 * the user uses the macro STPUTC to add characters to the string. In
8184 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8185 * grown as necessary. When the user is done, she can just leave the
8186 * string there and refer to it using stackblock(). Or she can allocate
8187 * the space for it using grabstackstr(). If it is necessary to allow
8188 * someone else to use the stack temporarily and then continue to grow
8189 * the string, the user should use grabstack to allocate the space, and
8190 * then call ungrabstr(p) to return to the previous mode of operation.
8191 *
8192 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8193 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8194 * is space for at least one character.
8195 */
8196
8197
8198static char *
Eric Andersen2870d962001-07-02 17:27:21 +00008199growstackstr(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00008200 int len = stackblocksize();
8201 if (herefd >= 0 && len >= 1024) {
8202 xwrite(herefd, stackblock(), len);
8203 sstrnleft = len - 1;
8204 return stackblock();
8205 }
8206 growstackblock();
8207 sstrnleft = stackblocksize() - len - 1;
8208 return stackblock() + len;
8209}
8210
8211
8212/*
8213 * Called from CHECKSTRSPACE.
8214 */
8215
8216static char *
8217makestrspace(size_t newlen) {
8218 int len = stackblocksize() - sstrnleft;
8219 do {
8220 growstackblock();
8221 sstrnleft = stackblocksize() - len;
8222 } while (sstrnleft < newlen);
8223 return stackblock() + len;
8224}
8225
8226
8227
8228static void
Eric Andersen2870d962001-07-02 17:27:21 +00008229ungrabstackstr(char *s, char *p)
8230{
Eric Andersencb57d552001-06-28 07:25:16 +00008231 stacknleft += stacknxt - s;
8232 stacknxt = s;
8233 sstrnleft = stacknleft - (p - s);
8234}
Eric Andersencb57d552001-06-28 07:25:16 +00008235/*
8236 * Miscelaneous builtins.
8237 */
8238
8239
8240#undef rflag
8241
Eric Andersencb57d552001-06-28 07:25:16 +00008242#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersen62483552001-07-10 06:09:16 +00008243typedef long rlim_t;
Eric Andersencb57d552001-06-28 07:25:16 +00008244#endif
8245
8246
8247
8248/*
8249 * The read builtin. The -e option causes backslashes to escape the
8250 * following character.
8251 *
8252 * This uses unbuffered input, which may be avoidable in some cases.
8253 */
8254
8255static int
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008256readcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008257{
8258 char **ap;
8259 int backslash;
8260 char c;
8261 int rflag;
8262 char *prompt;
8263 const char *ifs;
8264 char *p;
8265 int startword;
8266 int status;
8267 int i;
8268
8269 rflag = 0;
8270 prompt = NULL;
8271 while ((i = nextopt("p:r")) != '\0') {
8272 if (i == 'p')
8273 prompt = optionarg;
8274 else
8275 rflag = 1;
8276 }
8277 if (prompt && isatty(0)) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008278 out2str(prompt); /* read without cmdedit */
Eric Andersencb57d552001-06-28 07:25:16 +00008279 flushall();
8280 }
8281 if (*(ap = argptr) == NULL)
8282 error("arg count");
8283 if ((ifs = bltinlookup("IFS")) == NULL)
8284 ifs = defifs;
8285 status = 0;
8286 startword = 1;
8287 backslash = 0;
8288 STARTSTACKSTR(p);
8289 for (;;) {
8290 if (read(0, &c, 1) != 1) {
8291 status = 1;
8292 break;
8293 }
8294 if (c == '\0')
8295 continue;
8296 if (backslash) {
8297 backslash = 0;
8298 if (c != '\n')
8299 STPUTC(c, p);
8300 continue;
8301 }
8302 if (!rflag && c == '\\') {
8303 backslash++;
8304 continue;
8305 }
8306 if (c == '\n')
8307 break;
8308 if (startword && *ifs == ' ' && strchr(ifs, c)) {
8309 continue;
8310 }
8311 startword = 0;
8312 if (backslash && c == '\\') {
8313 if (read(0, &c, 1) != 1) {
8314 status = 1;
8315 break;
8316 }
8317 STPUTC(c, p);
8318 } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
8319 STACKSTRNUL(p);
8320 setvar(*ap, stackblock(), 0);
8321 ap++;
8322 startword = 1;
8323 STARTSTACKSTR(p);
8324 } else {
8325 STPUTC(c, p);
8326 }
8327 }
8328 STACKSTRNUL(p);
8329 /* Remove trailing blanks */
8330 while (stackblock() <= --p && strchr(ifs, *p) != NULL)
8331 *p = '\0';
8332 setvar(*ap, stackblock(), 0);
8333 while (*++ap != NULL)
8334 setvar(*ap, nullstr, 0);
8335 return status;
8336}
8337
8338
8339
8340static int
8341umaskcmd(argc, argv)
8342 int argc;
8343 char **argv;
8344{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008345 static const char permuser[3] = "ugo";
8346 static const char permmode[3] = "rwx";
8347 static const short int permmask[] = {
8348 S_IRUSR, S_IWUSR, S_IXUSR,
8349 S_IRGRP, S_IWGRP, S_IXGRP,
8350 S_IROTH, S_IWOTH, S_IXOTH
8351 };
8352
Eric Andersencb57d552001-06-28 07:25:16 +00008353 char *ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008354 mode_t mask;
Eric Andersencb57d552001-06-28 07:25:16 +00008355 int i;
8356 int symbolic_mode = 0;
8357
Eric Andersen62483552001-07-10 06:09:16 +00008358 while (nextopt("S") != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00008359 symbolic_mode = 1;
8360 }
8361
8362 INTOFF;
8363 mask = umask(0);
8364 umask(mask);
8365 INTON;
8366
8367 if ((ap = *argptr) == NULL) {
8368 if (symbolic_mode) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008369 char buf[18];
8370 char *p = buf;
8371 for (i=0 ; i<3 ; i++) {
8372 int j;
8373 *p++ = permuser[i];
8374 *p++ = '=';
8375 for (j=0 ; j<3 ; j++) {
8376 if ((mask & permmask[3*i+j]) == 0) {
8377 *p++ = permmode[j];
8378 }
8379 }
8380 *p++ = ',';
8381 }
8382 *--p = 0;
8383 puts(buf);
Eric Andersencb57d552001-06-28 07:25:16 +00008384 } else {
Eric Andersen62483552001-07-10 06:09:16 +00008385 printf("%.4o\n", mask);
Eric Andersencb57d552001-06-28 07:25:16 +00008386 }
8387 } else {
Eric Andersen62483552001-07-10 06:09:16 +00008388 if (is_digit((unsigned char)*ap)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008389 mask = 0;
8390 do {
8391 if (*ap >= '8' || *ap < '0')
8392 error("Illegal number: %s", argv[1]);
8393 mask = (mask << 3) + (*ap - '0');
8394 } while (*++ap != '\0');
8395 umask(mask);
8396 } else {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008397 mask = ~mask & 0777;
8398 if (parse_mode(ap, &mask) == FALSE) {
Eric Andersencb57d552001-06-28 07:25:16 +00008399 error("Illegal mode: %s", ap);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008400 }
Eric Andersencb57d552001-06-28 07:25:16 +00008401 umask(~mask & 0777);
8402 }
8403 }
8404 return 0;
8405}
8406
8407/*
8408 * ulimit builtin
8409 *
8410 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
8411 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
8412 * ash by J.T. Conklin.
8413 *
8414 * Public domain.
8415 */
8416
8417struct limits {
8418 const char *name;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008419 short cmd;
8420 short factor; /* multiply by to get rlim_{cur,max} values */
Eric Andersencb57d552001-06-28 07:25:16 +00008421};
8422
8423static const struct limits limits[] = {
8424#ifdef RLIMIT_CPU
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008425 { "time(seconds)", RLIMIT_CPU, 1 },
Eric Andersencb57d552001-06-28 07:25:16 +00008426#endif
8427#ifdef RLIMIT_FSIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008428 { "file(blocks)", RLIMIT_FSIZE, 512 },
Eric Andersencb57d552001-06-28 07:25:16 +00008429#endif
8430#ifdef RLIMIT_DATA
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008431 { "data(kbytes)", RLIMIT_DATA, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008432#endif
8433#ifdef RLIMIT_STACK
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008434 { "stack(kbytes)", RLIMIT_STACK, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008435#endif
8436#ifdef RLIMIT_CORE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008437 { "coredump(blocks)", RLIMIT_CORE, 512 },
Eric Andersencb57d552001-06-28 07:25:16 +00008438#endif
8439#ifdef RLIMIT_RSS
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008440 { "memory(kbytes)", RLIMIT_RSS, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008441#endif
8442#ifdef RLIMIT_MEMLOCK
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008443 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008444#endif
8445#ifdef RLIMIT_NPROC
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008446 { "process(processes)", RLIMIT_NPROC, 1 },
Eric Andersencb57d552001-06-28 07:25:16 +00008447#endif
8448#ifdef RLIMIT_NOFILE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008449 { "nofiles(descriptors)", RLIMIT_NOFILE, 1 },
Eric Andersencb57d552001-06-28 07:25:16 +00008450#endif
8451#ifdef RLIMIT_VMEM
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008452 { "vmemory(kbytes)", RLIMIT_VMEM, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008453#endif
8454#ifdef RLIMIT_SWAP
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008455 { "swap(kbytes)", RLIMIT_SWAP, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008456#endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008457 { NULL, 0, 0 }
Eric Andersencb57d552001-06-28 07:25:16 +00008458};
8459
8460static int
8461ulimitcmd(argc, argv)
8462 int argc;
8463 char **argv;
8464{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008465 static const char unlimited_string[] = "unlimited";
Eric Andersen2870d962001-07-02 17:27:21 +00008466 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00008467 rlim_t val = 0;
8468 enum { SOFT = 0x1, HARD = 0x2 }
8469 how = SOFT | HARD;
Eric Andersen2870d962001-07-02 17:27:21 +00008470 const struct limits *l;
8471 int set, all = 0;
8472 int optc, what;
8473 struct rlimit limit;
Eric Andersencb57d552001-06-28 07:25:16 +00008474
8475 what = 'f';
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008476
8477 while ((optc = nextopt("HSa"
8478#ifdef RLIMIT_CPU
8479 "t"
8480#endif
8481#ifdef RLIMIT_FSIZE
8482 "f"
8483#endif
8484#ifdef RLIMIT_DATA
8485 "d"
8486#endif
8487#ifdef RLIMIT_STACK
8488 "s"
8489#endif
8490#ifdef RLIMIT_CORE
8491 "c"
8492#endif
8493#ifdef RLIMIT_RSS
8494 "m"
8495#endif
8496#ifdef RLIMIT_MEMLOCK
8497 "l"
8498#endif
8499#ifdef RLIMIT_NPROC
8500 "p"
8501#endif
8502#ifdef RLIMIT_NOFILE
8503 "n"
8504#endif
8505#ifdef RLIMIT_VMEM
8506 "v"
8507#endif
8508#ifdef RLIMIT_SWAP
8509 "w"
8510#endif
8511 )) != '\0') {
8512 if (optc == 'H') {
Eric Andersencb57d552001-06-28 07:25:16 +00008513 how = HARD;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008514 } else if (optc == 'S') {
Eric Andersencb57d552001-06-28 07:25:16 +00008515 how = SOFT;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008516 } else if (optc == 'a') {
Eric Andersencb57d552001-06-28 07:25:16 +00008517 all = 1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008518 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00008519 what = optc;
8520 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008521 }
Eric Andersencb57d552001-06-28 07:25:16 +00008522
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008523 for (l = limits; l->name; l++) {
8524 if(l->name[0] == what)
8525 break;
8526 if(l->name[1]=='w' && what=='w')
8527 break;
8528 }
Eric Andersencb57d552001-06-28 07:25:16 +00008529
8530 set = *argptr ? 1 : 0;
8531 if (set) {
8532 char *p = *argptr;
8533
8534 if (all || argptr[1])
8535 error("too many arguments");
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008536 if (strcmp(p, unlimited_string) == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00008537 val = RLIM_INFINITY;
8538 else {
8539 val = (rlim_t) 0;
8540
8541 while ((c = *p++) >= '0' && c <= '9')
8542 {
8543 val = (val * 10) + (long)(c - '0');
8544 if (val < (rlim_t) 0)
8545 break;
8546 }
8547 if (c)
8548 error("bad number");
8549 val *= l->factor;
8550 }
8551 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008552
Eric Andersencb57d552001-06-28 07:25:16 +00008553 if (all) {
8554 for (l = limits; l->name; l++) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008555 printf("%-20s ", l->name);
Eric Andersencb57d552001-06-28 07:25:16 +00008556 getrlimit(l->cmd, &limit);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008557 OUTPUT_LIMIT:
Eric Andersencb57d552001-06-28 07:25:16 +00008558 if (how & SOFT)
8559 val = limit.rlim_cur;
8560 else if (how & HARD)
8561 val = limit.rlim_max;
8562
Eric Andersencb57d552001-06-28 07:25:16 +00008563 if (val == RLIM_INFINITY)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008564 puts(unlimited_string);
Eric Andersencb57d552001-06-28 07:25:16 +00008565 else
8566 {
8567 val /= l->factor;
Eric Andersen62483552001-07-10 06:09:16 +00008568 printf("%lld\n", (long long) val);
Eric Andersencb57d552001-06-28 07:25:16 +00008569 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008570 if (!all) {
8571 break;
8572 }
Eric Andersencb57d552001-06-28 07:25:16 +00008573 }
8574 return 0;
8575 }
8576
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008577 if (!set) {
8578 goto OUTPUT_LIMIT;
Eric Andersencb57d552001-06-28 07:25:16 +00008579 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008580
8581 getrlimit(l->cmd, &limit);
8582 if (how & HARD)
8583 limit.rlim_max = val;
8584 if (how & SOFT)
8585 limit.rlim_cur = val;
8586 if (setrlimit(l->cmd, &limit) < 0)
8587 error("error setting limit (%m)");
Eric Andersencb57d552001-06-28 07:25:16 +00008588 return 0;
8589}
Eric Andersencb57d552001-06-28 07:25:16 +00008590/*
8591 * prefix -- see if pfx is a prefix of string.
8592 */
8593
8594static int
Eric Andersen62483552001-07-10 06:09:16 +00008595prefix(char const *pfx, char const *string)
8596{
Eric Andersencb57d552001-06-28 07:25:16 +00008597 while (*pfx) {
8598 if (*pfx++ != *string++)
8599 return 0;
8600 }
8601 return 1;
8602}
8603
Eric Andersen2870d962001-07-02 17:27:21 +00008604/*
8605 * Return true if s is a string of digits, and save munber in intptr
8606 * nagative is bad
8607 */
8608
8609static int
8610is_number(const char *p, int *intptr)
8611{
8612 int ret = 0;
8613
8614 do {
8615 if (! is_digit(*p))
8616 return 0;
8617 ret *= 10;
8618 ret += digit_val(*p);
8619 p++;
8620 } while (*p != '\0');
8621
8622 *intptr = ret;
8623 return 1;
8624}
Eric Andersencb57d552001-06-28 07:25:16 +00008625
8626/*
8627 * Convert a string of digits to an integer, printing an error message on
8628 * failure.
8629 */
8630
8631static int
Eric Andersen2870d962001-07-02 17:27:21 +00008632number(const char *s)
8633{
8634 int i;
8635 if (! is_number(s, &i))
Eric Andersencb57d552001-06-28 07:25:16 +00008636 error("Illegal number: %s", s);
Eric Andersen2870d962001-07-02 17:27:21 +00008637 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00008638}
8639
Eric Andersencb57d552001-06-28 07:25:16 +00008640/*
8641 * Produce a possibly single quoted string suitable as input to the shell.
8642 * The return string is allocated on the stack.
8643 */
8644
8645static char *
8646single_quote(const char *s) {
8647 char *p;
8648
8649 STARTSTACKSTR(p);
8650
8651 do {
8652 char *q = p;
8653 size_t len1, len1p, len2, len2p;
8654
8655 len1 = strcspn(s, "'");
8656 len2 = strspn(s + len1, "'");
8657
8658 len1p = len1 ? len1 + 2 : len1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008659 len2p = len2 + ((len2 < 2) ? len2 : 2);
Eric Andersencb57d552001-06-28 07:25:16 +00008660
8661 CHECKSTRSPACE(len1p + len2p + 1, p);
8662
8663 if (len1) {
8664 *p = '\'';
Eric Andersencb57d552001-06-28 07:25:16 +00008665 q = p + 1 + len1;
8666 memcpy(p + 1, s, len1);
Eric Andersencb57d552001-06-28 07:25:16 +00008667 *q++ = '\'';
8668 s += len1;
8669 }
8670
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008671 if (len2 > 1) {
Eric Andersencb57d552001-06-28 07:25:16 +00008672 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008673 q += 1 + len2;
8674 memcpy(q + 1, s, len2);
8675 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008676 s += len2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008677 } else if (len2 == 1) {
8678 *q++ = '\\';
8679 *q = '\'';
8680 s++;
Eric Andersencb57d552001-06-28 07:25:16 +00008681 }
8682
8683 STADJUST(len1p + len2p, p);
8684 } while (*s);
8685
8686 USTPUTC(0, p);
8687
8688 return grabstackstr(p);
8689}
8690
8691/*
8692 * Like strdup but works with the ash stack.
8693 */
8694
8695static char *
8696sstrdup(const char *p)
8697{
8698 size_t len = strlen(p) + 1;
8699 return memcpy(stalloc(len), p, len);
8700}
8701
Eric Andersencb57d552001-06-28 07:25:16 +00008702
8703/*
Eric Andersencb57d552001-06-28 07:25:16 +00008704 * Routine for dealing with parsed shell commands.
8705 */
8706
8707
Eric Andersen62483552001-07-10 06:09:16 +00008708static void sizenodelist (const struct nodelist *);
8709static struct nodelist *copynodelist (const struct nodelist *);
8710static char *nodesavestr (const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00008711
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008712//#define CALCSIZE_TABLE
8713//#define COPYNODE_TABLE
8714#if defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE)
8715/*
8716 * To collect a lot of redundant code in case statements for copynode()
8717 * and calcsize(), we implement a mini language here. Each type of node
8718 * struct has an associated instruction sequence that operates on its
8719 * members via their offsets. The instruction are pack in unsigned chars
8720 * with format IIDDDDDE where the bits are
8721 * I : part of the instruction opcode, which are
8722 * 00 : member is a pointer to another node
8723 * 40 : member is an integer
8724 * 80 : member is a pointer to a nodelist
8725 * CC : member is a pointer to a char string
8726 * D : data - the actual offset of the member to operate on in the struct
8727 * (since we assume bit 0 is set, it is not shifted)
8728 * E : flag signaling end of instruction sequence
8729 *
8730 * WARNING: In order to handle larger offsets for 64bit archs, this code
8731 * assumes that no offset can be an odd number and stores the
8732 * end-of-instructions flag in bit 0.
8733 */
8734
8735#define NODE_INTEGER 0x40
8736#define NODE_NODELIST 0x80
8737#define NODE_CHARPTR 0xC0
8738#define NODE_NOMORE 0x01 /* Note: no offset should be odd (aligned)*/
8739#define NODE_MBRMASK 0xC0
8740#define NODE_OFFSETMASK 0x3E
8741
8742static const unsigned char copynode_ops[35] = {
8743#define COPYNODE_OPS0 0
8744 offsetof(union node, nbinary.ch2),
8745 offsetof(union node, nbinary.ch1)|NODE_NOMORE,
8746#define COPYNODE_OPS1 (COPYNODE_OPS0 + 2)
8747 offsetof(union node, ncmd.redirect),
8748 offsetof(union node, ncmd.args),
8749 offsetof(union node, ncmd.assign),
8750 offsetof(union node, ncmd.backgnd)|NODE_INTEGER|NODE_NOMORE,
8751#define COPYNODE_OPS2 (COPYNODE_OPS1 + 4)
8752 offsetof(union node, npipe.cmdlist)|NODE_NODELIST,
8753 offsetof(union node, npipe.backgnd)|NODE_INTEGER|NODE_NOMORE,
8754#define COPYNODE_OPS3 (COPYNODE_OPS2 + 2)
8755 offsetof(union node, nredir.redirect),
8756 offsetof(union node, nredir.n)|NODE_NOMORE,
8757#define COPYNODE_OPS4 (COPYNODE_OPS3 + 2)
8758 offsetof(union node, nif.elsepart),
8759 offsetof(union node, nif.ifpart),
8760 offsetof(union node, nif.test)|NODE_NOMORE,
8761#define COPYNODE_OPS5 (COPYNODE_OPS4 + 3)
8762 offsetof(union node, nfor.var)|NODE_CHARPTR,
8763 offsetof(union node, nfor.body),
8764 offsetof(union node, nfor.args)|NODE_NOMORE,
8765#define COPYNODE_OPS6 (COPYNODE_OPS5 + 3)
8766 offsetof(union node, ncase.cases),
8767 offsetof(union node, ncase.expr)|NODE_NOMORE,
8768#define COPYNODE_OPS7 (COPYNODE_OPS6 + 2)
8769 offsetof(union node, nclist.body),
8770 offsetof(union node, nclist.pattern),
8771 offsetof(union node, nclist.next)|NODE_NOMORE,
8772#define COPYNODE_OPS8 (COPYNODE_OPS7 + 3)
8773 offsetof(union node, narg.backquote)|NODE_NODELIST,
8774 offsetof(union node, narg.text)|NODE_CHARPTR,
8775 offsetof(union node, narg.next)|NODE_NOMORE,
8776#define COPYNODE_OPS9 (COPYNODE_OPS8 + 3)
8777 offsetof(union node, nfile.fname),
8778 offsetof(union node, nfile.fd)|NODE_INTEGER,
8779 offsetof(union node, nfile.next)|NODE_NOMORE,
8780#define COPYNODE_OPS10 (COPYNODE_OPS9 + 3)
8781 offsetof(union node, ndup.vname),
8782 offsetof(union node, ndup.dupfd)|NODE_INTEGER,
8783 offsetof(union node, ndup.fd)|NODE_INTEGER,
8784 offsetof(union node, ndup.next)|NODE_NOMORE,
8785#define COPYNODE_OPS11 (COPYNODE_OPS10 + 4)
8786 offsetof(union node, nhere.doc),
8787 offsetof(union node, nhere.fd)|NODE_INTEGER,
8788 offsetof(union node, nhere.next)|NODE_NOMORE,
8789#define COPYNODE_OPS12 (COPYNODE_OPS11 + 3)
8790 offsetof(union node, nnot.com)|NODE_NOMORE,
8791};
8792
8793#if COPYNODE_OPS12 != 34
8794#error COPYNODE_OPS12 is incorrect
8795#endif
8796
8797static const unsigned char copynode_ops_index[26] = {
8798 COPYNODE_OPS0, /* NSEMI */
8799 COPYNODE_OPS1, /* NCMD */
8800 COPYNODE_OPS2, /* NPIPE */
8801 COPYNODE_OPS3, /* NREDIR */
8802 COPYNODE_OPS3, /* NBACKGND */
8803 COPYNODE_OPS3, /* NSUBSHELL */
8804 COPYNODE_OPS0, /* NAND */
8805 COPYNODE_OPS0, /* NOR */
8806 COPYNODE_OPS4, /* NIF */
8807 COPYNODE_OPS0, /* NWHILE */
8808 COPYNODE_OPS0, /* NUNTIL */
8809 COPYNODE_OPS5, /* NFOR */
8810 COPYNODE_OPS6, /* NCASE */
8811 COPYNODE_OPS7, /* NCLIST */
8812 COPYNODE_OPS8, /* NDEFUN */
8813 COPYNODE_OPS8, /* NARG */
8814 COPYNODE_OPS9, /* NTO */
8815 COPYNODE_OPS9, /* NFROM */
8816 COPYNODE_OPS9, /* NFROMTO */
8817 COPYNODE_OPS9, /* NAPPEND */
8818 COPYNODE_OPS9, /* NTOOV */
8819 COPYNODE_OPS10, /* NTOFD */
8820 COPYNODE_OPS10, /* NFROMFD */
8821 COPYNODE_OPS11, /* NHERE */
8822 COPYNODE_OPS11, /* NXHERE */
8823 COPYNODE_OPS12, /* NNOT */
8824};
8825
8826#if NODE_CHARPTR != NODE_MBRMASK
8827#error NODE_CHARPTR != NODE_MBRMASK!!!
8828#endif
8829#endif /* defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE) */
8830
8831#ifdef COPYNODE_TABLE
8832static union node *
8833copynode(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008834{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008835 union node *new;
8836 const unsigned char *p;
8837
Manuel Novoa III c639a352001-08-12 17:32:56 +00008838 if (n == NULL) {
8839 return NULL;
8840 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008841 new = funcblock;
8842 new->type = n->type;
8843 funcblock = (char *) funcblock + (int) nodesize[n->type];
8844 p = copynode_ops + (int) copynode_ops_index[n->type];
8845 do {
8846 char *nn = ((char *) new) + ((int)(*p & NODE_OFFSETMASK));
8847 const char *no = ((const char *) n) + ((int)(*p & NODE_OFFSETMASK));
8848
8849 if (!(*p & NODE_MBRMASK)) { /* standard node */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008850 *((union node **)nn) = copynode(*((const union node **) no));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008851 } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008852 *((const char **)nn) = nodesavestr(*((const char **)no));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008853 } else if (*p & NODE_NODELIST) { /* nodelist */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008854 *((struct nodelist **)nn)
8855 = copynodelist(*((const struct nodelist **) no));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008856 } else { /* integer */
8857 *((int *) nn) = *((int *) no);
8858 }
8859 } while (!(*p++ & NODE_NOMORE));
8860 return new;
Eric Andersencb57d552001-06-28 07:25:16 +00008861}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008862#else /* COPYNODE_TABLE */
Eric Andersencb57d552001-06-28 07:25:16 +00008863static union node *
Eric Andersen62483552001-07-10 06:09:16 +00008864copynode(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008865{
Eric Andersen62483552001-07-10 06:09:16 +00008866 union node *new;
Eric Andersencb57d552001-06-28 07:25:16 +00008867
8868 if (n == NULL)
Manuel Novoa III c639a352001-08-12 17:32:56 +00008869 return NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008870 new = funcblock;
8871 funcblock = (char *) funcblock + nodesize[n->type];
8872 switch (n->type) {
8873 case NSEMI:
8874 case NAND:
8875 case NOR:
8876 case NWHILE:
8877 case NUNTIL:
8878 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8879 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8880 break;
8881 case NCMD:
8882 new->ncmd.redirect = copynode(n->ncmd.redirect);
8883 new->ncmd.args = copynode(n->ncmd.args);
8884 new->ncmd.assign = copynode(n->ncmd.assign);
8885 new->ncmd.backgnd = n->ncmd.backgnd;
8886 break;
8887 case NPIPE:
8888 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8889 new->npipe.backgnd = n->npipe.backgnd;
8890 break;
8891 case NREDIR:
8892 case NBACKGND:
8893 case NSUBSHELL:
8894 new->nredir.redirect = copynode(n->nredir.redirect);
8895 new->nredir.n = copynode(n->nredir.n);
8896 break;
8897 case NIF:
8898 new->nif.elsepart = copynode(n->nif.elsepart);
8899 new->nif.ifpart = copynode(n->nif.ifpart);
8900 new->nif.test = copynode(n->nif.test);
8901 break;
8902 case NFOR:
8903 new->nfor.var = nodesavestr(n->nfor.var);
8904 new->nfor.body = copynode(n->nfor.body);
8905 new->nfor.args = copynode(n->nfor.args);
8906 break;
8907 case NCASE:
8908 new->ncase.cases = copynode(n->ncase.cases);
8909 new->ncase.expr = copynode(n->ncase.expr);
8910 break;
8911 case NCLIST:
8912 new->nclist.body = copynode(n->nclist.body);
8913 new->nclist.pattern = copynode(n->nclist.pattern);
8914 new->nclist.next = copynode(n->nclist.next);
8915 break;
8916 case NDEFUN:
8917 case NARG:
8918 new->narg.backquote = copynodelist(n->narg.backquote);
8919 new->narg.text = nodesavestr(n->narg.text);
8920 new->narg.next = copynode(n->narg.next);
8921 break;
8922 case NTO:
8923 case NFROM:
8924 case NFROMTO:
8925 case NAPPEND:
8926 case NTOOV:
8927 new->nfile.fname = copynode(n->nfile.fname);
8928 new->nfile.fd = n->nfile.fd;
8929 new->nfile.next = copynode(n->nfile.next);
8930 break;
8931 case NTOFD:
8932 case NFROMFD:
8933 new->ndup.vname = copynode(n->ndup.vname);
8934 new->ndup.dupfd = n->ndup.dupfd;
8935 new->ndup.fd = n->ndup.fd;
8936 new->ndup.next = copynode(n->ndup.next);
8937 break;
8938 case NHERE:
8939 case NXHERE:
8940 new->nhere.doc = copynode(n->nhere.doc);
8941 new->nhere.fd = n->nhere.fd;
8942 new->nhere.next = copynode(n->nhere.next);
8943 break;
8944 case NNOT:
8945 new->nnot.com = copynode(n->nnot.com);
8946 break;
8947 };
8948 new->type = n->type;
Eric Andersen62483552001-07-10 06:09:16 +00008949 return new;
Eric Andersencb57d552001-06-28 07:25:16 +00008950}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008951#endif /* COPYNODE_TABLE */
8952
8953#ifdef CALCSIZE_TABLE
8954static void
8955calcsize(const union node *n)
8956{
8957 const unsigned char *p;
8958
8959 if (n == NULL)
8960 return;
8961 funcblocksize += (int) nodesize[n->type];
8962
8963 p = copynode_ops + (int) copynode_ops_index[n->type];
8964 do {
8965 const char *no = ((const char *) n) + ((int)(*p & NODE_OFFSETMASK));
8966
8967 if (!(*p & NODE_MBRMASK)) { /* standard node */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008968 calcsize(*((const union node **) no));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008969 } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008970 funcstringsize += strlen(*((const char **)no)) + 1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008971 } else if (*p & NODE_NODELIST) { /* nodelist */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008972 sizenodelist(*((const struct nodelist **) no));
8973 } /* else integer -- ignore */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008974 } while (!(*p++ & NODE_NOMORE));
8975}
8976#else /* CALCSIZE_TABLE */
8977static void
8978calcsize(const union node *n)
8979{
8980 if (n == NULL)
8981 return;
8982 funcblocksize += nodesize[n->type];
8983 switch (n->type) {
8984 case NSEMI:
8985 case NAND:
8986 case NOR:
8987 case NWHILE:
8988 case NUNTIL:
8989 calcsize(n->nbinary.ch2);
8990 calcsize(n->nbinary.ch1);
8991 break;
8992 case NCMD:
8993 calcsize(n->ncmd.redirect);
8994 calcsize(n->ncmd.args);
8995 calcsize(n->ncmd.assign);
8996 break;
8997 case NPIPE:
8998 sizenodelist(n->npipe.cmdlist);
8999 break;
9000 case NREDIR:
9001 case NBACKGND:
9002 case NSUBSHELL:
9003 calcsize(n->nredir.redirect);
9004 calcsize(n->nredir.n);
9005 break;
9006 case NIF:
9007 calcsize(n->nif.elsepart);
9008 calcsize(n->nif.ifpart);
9009 calcsize(n->nif.test);
9010 break;
9011 case NFOR:
9012 funcstringsize += strlen(n->nfor.var) + 1;
9013 calcsize(n->nfor.body);
9014 calcsize(n->nfor.args);
9015 break;
9016 case NCASE:
9017 calcsize(n->ncase.cases);
9018 calcsize(n->ncase.expr);
9019 break;
9020 case NCLIST:
9021 calcsize(n->nclist.body);
9022 calcsize(n->nclist.pattern);
9023 calcsize(n->nclist.next);
9024 break;
9025 case NDEFUN:
9026 case NARG:
9027 sizenodelist(n->narg.backquote);
9028 funcstringsize += strlen(n->narg.text) + 1;
9029 calcsize(n->narg.next);
9030 break;
9031 case NTO:
9032 case NFROM:
9033 case NFROMTO:
9034 case NAPPEND:
9035 case NTOOV:
9036 calcsize(n->nfile.fname);
9037 calcsize(n->nfile.next);
9038 break;
9039 case NTOFD:
9040 case NFROMFD:
9041 calcsize(n->ndup.vname);
9042 calcsize(n->ndup.next);
9043 break;
9044 case NHERE:
9045 case NXHERE:
9046 calcsize(n->nhere.doc);
9047 calcsize(n->nhere.next);
9048 break;
9049 case NNOT:
9050 calcsize(n->nnot.com);
9051 break;
9052 };
9053}
9054#endif /* CALCSIZE_TABLE */
9055
9056static void
9057sizenodelist(const struct nodelist *lp)
9058{
9059 while (lp) {
9060 funcblocksize += ALIGN(sizeof(struct nodelist));
9061 calcsize(lp->n);
9062 lp = lp->next;
9063 }
9064}
Eric Andersencb57d552001-06-28 07:25:16 +00009065
9066
9067static struct nodelist *
Eric Andersen62483552001-07-10 06:09:16 +00009068copynodelist(const struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00009069{
9070 struct nodelist *start;
9071 struct nodelist **lpp;
9072
9073 lpp = &start;
9074 while (lp) {
9075 *lpp = funcblock;
9076 funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist));
9077 (*lpp)->n = copynode(lp->n);
9078 lp = lp->next;
9079 lpp = &(*lpp)->next;
9080 }
9081 *lpp = NULL;
9082 return start;
9083}
9084
9085
Eric Andersencb57d552001-06-28 07:25:16 +00009086static char *
Eric Andersen62483552001-07-10 06:09:16 +00009087nodesavestr(const char *s)
Eric Andersencb57d552001-06-28 07:25:16 +00009088{
Eric Andersen62483552001-07-10 06:09:16 +00009089 const char *p = s;
9090 char *q = funcstring;
Eric Andersencb57d552001-06-28 07:25:16 +00009091 char *rtn = funcstring;
9092
9093 while ((*q++ = *p++) != '\0')
9094 continue;
9095 funcstring = q;
9096 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00009097}
9098
Eric Andersencb57d552001-06-28 07:25:16 +00009099#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00009100static int getopts (char *, char *, char **, int *, int *);
Eric Andersencb57d552001-06-28 07:25:16 +00009101#endif
9102
9103
9104/*
9105 * Process the shell command line arguments.
9106 */
9107
9108static void
9109procargs(argc, argv)
9110 int argc;
9111 char **argv;
9112{
9113 int i;
9114
9115 argptr = argv;
9116 if (argc > 0)
9117 argptr++;
9118 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009119 optent_val(i) = 2;
Eric Andersencb57d552001-06-28 07:25:16 +00009120 options(1);
9121 if (*argptr == NULL && minusc == NULL)
9122 sflag = 1;
9123 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
9124 iflag = 1;
9125 if (mflag == 2)
9126 mflag = iflag;
9127 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009128 if (optent_val(i) == 2)
9129 optent_val(i) = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009130 arg0 = argv[0];
9131 if (sflag == 0 && minusc == NULL) {
9132 commandname = argv[0];
9133 arg0 = *argptr++;
9134 setinputfile(arg0, 0);
9135 commandname = arg0;
9136 }
9137 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
9138 if (argptr && minusc && *argptr)
Eric Andersen2870d962001-07-02 17:27:21 +00009139 arg0 = *argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00009140
9141 shellparam.p = argptr;
9142 shellparam.optind = 1;
9143 shellparam.optoff = -1;
9144 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
9145 while (*argptr) {
9146 shellparam.nparam++;
9147 argptr++;
9148 }
9149 optschanged();
9150}
9151
9152
Eric Andersencb57d552001-06-28 07:25:16 +00009153
9154/*
9155 * Process shell options. The global variable argptr contains a pointer
9156 * to the argument list; we advance it past the options.
9157 */
9158
Eric Andersen62483552001-07-10 06:09:16 +00009159static inline void
9160minus_o(const char *name, int val)
9161{
9162 int i;
9163
9164 if (name == NULL) {
9165 out1str("Current option settings\n");
9166 for (i = 0; i < NOPTS; i++)
9167 printf("%-16s%s\n", optent_name(optlist[i]),
9168 optent_val(i) ? "on" : "off");
9169 } else {
9170 for (i = 0; i < NOPTS; i++)
9171 if (equal(name, optent_name(optlist[i]))) {
9172 setoption(optent_letter(optlist[i]), val);
9173 return;
9174 }
9175 error("Illegal option -o %s", name);
9176 }
9177}
9178
9179
Eric Andersencb57d552001-06-28 07:25:16 +00009180static void
Eric Andersen62483552001-07-10 06:09:16 +00009181options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00009182{
9183 char *p;
9184 int val;
9185 int c;
9186
9187 if (cmdline)
9188 minusc = NULL;
9189 while ((p = *argptr) != NULL) {
9190 argptr++;
9191 if ((c = *p++) == '-') {
9192 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00009193 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
9194 if (!cmdline) {
9195 /* "-" means turn off -x and -v */
9196 if (p[0] == '\0')
9197 xflag = vflag = 0;
9198 /* "--" means reset params */
9199 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00009200 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00009201 }
9202 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00009203 }
9204 } else if (c == '+') {
9205 val = 0;
9206 } else {
9207 argptr--;
9208 break;
9209 }
9210 while ((c = *p++) != '\0') {
9211 if (c == 'c' && cmdline) {
9212 char *q;
Eric Andersen2870d962001-07-02 17:27:21 +00009213#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */
Eric Andersencb57d552001-06-28 07:25:16 +00009214 if (*p == '\0')
9215#endif
9216 q = *argptr++;
9217 if (q == NULL || minusc != NULL)
9218 error("Bad -c option");
9219 minusc = q;
9220#ifdef NOHACK
9221 break;
9222#endif
9223 } else if (c == 'o') {
9224 minus_o(*argptr, val);
9225 if (*argptr)
9226 argptr++;
9227 } else {
9228 setoption(c, val);
9229 }
9230 }
9231 }
9232}
9233
Eric Andersencb57d552001-06-28 07:25:16 +00009234
9235static void
Eric Andersen2870d962001-07-02 17:27:21 +00009236setoption(int flag, int val)
9237{
Eric Andersencb57d552001-06-28 07:25:16 +00009238 int i;
9239
9240 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009241 if (optent_letter(optlist[i]) == flag) {
9242 optent_val(i) = val;
Eric Andersencb57d552001-06-28 07:25:16 +00009243 if (val) {
9244 /* #%$ hack for ksh semantics */
9245 if (flag == 'V')
9246 Eflag = 0;
9247 else if (flag == 'E')
9248 Vflag = 0;
9249 }
9250 return;
9251 }
9252 error("Illegal option -%c", flag);
9253 /* NOTREACHED */
9254}
9255
9256
9257
Eric Andersencb57d552001-06-28 07:25:16 +00009258/*
9259 * Set the shell parameters.
9260 */
9261
9262static void
Eric Andersen2870d962001-07-02 17:27:21 +00009263setparam(char **argv)
9264{
Eric Andersencb57d552001-06-28 07:25:16 +00009265 char **newparam;
9266 char **ap;
9267 int nparam;
9268
9269 for (nparam = 0 ; argv[nparam] ; nparam++);
9270 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
9271 while (*argv) {
9272 *ap++ = savestr(*argv++);
9273 }
9274 *ap = NULL;
9275 freeparam(&shellparam);
9276 shellparam.malloc = 1;
9277 shellparam.nparam = nparam;
9278 shellparam.p = newparam;
9279 shellparam.optind = 1;
9280 shellparam.optoff = -1;
9281}
9282
9283
9284/*
9285 * Free the list of positional parameters.
9286 */
9287
9288static void
Eric Andersen2870d962001-07-02 17:27:21 +00009289freeparam(volatile struct shparam *param)
9290{
Eric Andersencb57d552001-06-28 07:25:16 +00009291 char **ap;
9292
9293 if (param->malloc) {
9294 for (ap = param->p ; *ap ; ap++)
9295 ckfree(*ap);
9296 ckfree(param->p);
9297 }
9298}
9299
9300
9301
9302/*
9303 * The shift builtin command.
9304 */
9305
9306static int
9307shiftcmd(argc, argv)
9308 int argc;
9309 char **argv;
9310{
9311 int n;
9312 char **ap1, **ap2;
9313
9314 n = 1;
9315 if (argc > 1)
9316 n = number(argv[1]);
9317 if (n > shellparam.nparam)
9318 error("can't shift that many");
9319 INTOFF;
9320 shellparam.nparam -= n;
9321 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
9322 if (shellparam.malloc)
9323 ckfree(*ap1);
9324 }
9325 ap2 = shellparam.p;
9326 while ((*ap2++ = *ap1++) != NULL);
9327 shellparam.optind = 1;
9328 shellparam.optoff = -1;
9329 INTON;
9330 return 0;
9331}
9332
9333
9334
9335/*
9336 * The set command builtin.
9337 */
9338
9339static int
9340setcmd(argc, argv)
9341 int argc;
9342 char **argv;
9343{
9344 if (argc == 1)
9345 return showvarscmd(argc, argv);
9346 INTOFF;
9347 options(0);
9348 optschanged();
9349 if (*argptr != NULL) {
9350 setparam(argptr);
9351 }
9352 INTON;
9353 return 0;
9354}
9355
9356
9357static void
Eric Andersen2870d962001-07-02 17:27:21 +00009358getoptsreset(const char *value)
Eric Andersencb57d552001-06-28 07:25:16 +00009359{
9360 shellparam.optind = number(value);
9361 shellparam.optoff = -1;
9362}
9363
Eric Andersen2870d962001-07-02 17:27:21 +00009364#ifdef BB_LOCALE_SUPPORT
9365static void change_lc_all(const char *value)
9366{
9367 if(value != 0 && *value != 0)
9368 setlocale(LC_ALL, value);
9369}
9370
9371static void change_lc_ctype(const char *value)
9372{
9373 if(value != 0 && *value != 0)
9374 setlocale(LC_CTYPE, value);
9375}
9376
9377#endif
9378
Eric Andersencb57d552001-06-28 07:25:16 +00009379#ifdef ASH_GETOPTS
9380/*
9381 * The getopts builtin. Shellparam.optnext points to the next argument
9382 * to be processed. Shellparam.optptr points to the next character to
9383 * be processed in the current argument. If shellparam.optnext is NULL,
9384 * then it's the first time getopts has been called.
9385 */
9386
9387static int
9388getoptscmd(argc, argv)
9389 int argc;
9390 char **argv;
9391{
9392 char **optbase;
9393
9394 if (argc < 3)
9395 error("Usage: getopts optstring var [arg]");
9396 else if (argc == 3) {
9397 optbase = shellparam.p;
9398 if (shellparam.optind > shellparam.nparam + 1) {
9399 shellparam.optind = 1;
9400 shellparam.optoff = -1;
9401 }
9402 }
9403 else {
9404 optbase = &argv[3];
9405 if (shellparam.optind > argc - 2) {
9406 shellparam.optind = 1;
9407 shellparam.optoff = -1;
9408 }
9409 }
9410
9411 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9412 &shellparam.optoff);
9413}
9414
9415/*
9416 * Safe version of setvar, returns 1 on success 0 on failure.
9417 */
9418
9419static int
9420setvarsafe(name, val, flags)
9421 const char *name, *val;
9422 int flags;
9423{
9424 struct jmploc jmploc;
9425 struct jmploc *volatile savehandler = handler;
9426 int err = 0;
9427#ifdef __GNUC__
9428 (void) &err;
9429#endif
9430
9431 if (setjmp(jmploc.loc))
9432 err = 1;
9433 else {
9434 handler = &jmploc;
9435 setvar(name, val, flags);
9436 }
9437 handler = savehandler;
9438 return err;
9439}
9440
9441static int
9442getopts(optstr, optvar, optfirst, myoptind, optoff)
9443 char *optstr;
9444 char *optvar;
9445 char **optfirst;
9446 int *myoptind;
9447 int *optoff;
9448{
9449 char *p, *q;
9450 char c = '?';
9451 int done = 0;
9452 int err = 0;
9453 char s[10];
9454 char **optnext = optfirst + *myoptind - 1;
9455
9456 if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
9457 strlen(*(optnext - 1)) < *optoff)
9458 p = NULL;
9459 else
9460 p = *(optnext - 1) + *optoff;
9461 if (p == NULL || *p == '\0') {
9462 /* Current word is done, advance */
9463 if (optnext == NULL)
9464 return 1;
9465 p = *optnext;
9466 if (p == NULL || *p != '-' || *++p == '\0') {
9467atend:
9468 *myoptind = optnext - optfirst + 1;
9469 p = NULL;
9470 done = 1;
9471 goto out;
9472 }
9473 optnext++;
Eric Andersen2870d962001-07-02 17:27:21 +00009474 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009475 goto atend;
9476 }
9477
9478 c = *p++;
9479 for (q = optstr; *q != c; ) {
9480 if (*q == '\0') {
9481 if (optstr[0] == ':') {
9482 s[0] = c;
9483 s[1] = '\0';
9484 err |= setvarsafe("OPTARG", s, 0);
9485 }
9486 else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009487 out2fmt("Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009488 (void) unsetvar("OPTARG");
9489 }
9490 c = '?';
9491 goto bad;
9492 }
9493 if (*++q == ':')
9494 q++;
9495 }
9496
9497 if (*++q == ':') {
9498 if (*p == '\0' && (p = *optnext) == NULL) {
9499 if (optstr[0] == ':') {
9500 s[0] = c;
9501 s[1] = '\0';
9502 err |= setvarsafe("OPTARG", s, 0);
9503 c = ':';
9504 }
9505 else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009506 out2fmt("No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009507 (void) unsetvar("OPTARG");
9508 c = '?';
9509 }
9510 goto bad;
9511 }
9512
9513 if (p == *optnext)
9514 optnext++;
9515 setvarsafe("OPTARG", p, 0);
9516 p = NULL;
9517 }
9518 else
9519 setvarsafe("OPTARG", "", 0);
9520 *myoptind = optnext - optfirst + 1;
9521 goto out;
9522
9523bad:
9524 *myoptind = 1;
9525 p = NULL;
9526out:
9527 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersen3102ac42001-07-06 04:26:23 +00009528 snprintf(s, sizeof(s), "%d", *myoptind);
Eric Andersencb57d552001-06-28 07:25:16 +00009529 err |= setvarsafe("OPTIND", s, VNOFUNC);
9530 s[0] = c;
9531 s[1] = '\0';
9532 err |= setvarsafe(optvar, s, 0);
9533 if (err) {
9534 *myoptind = 1;
9535 *optoff = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00009536 exraise(EXERROR);
9537 }
9538 return done;
9539}
Eric Andersen2870d962001-07-02 17:27:21 +00009540#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009541
9542/*
9543 * XXX - should get rid of. have all builtins use getopt(3). the
9544 * library getopt must have the BSD extension static variable "optreset"
9545 * otherwise it can't be used within the shell safely.
9546 *
9547 * Standard option processing (a la getopt) for builtin routines. The
9548 * only argument that is passed to nextopt is the option string; the
9549 * other arguments are unnecessary. It return the character, or '\0' on
9550 * end of input.
9551 */
9552
9553static int
Eric Andersen62483552001-07-10 06:09:16 +00009554nextopt(const char *optstring)
9555{
Eric Andersencb57d552001-06-28 07:25:16 +00009556 char *p;
9557 const char *q;
9558 char c;
9559
9560 if ((p = optptr) == NULL || *p == '\0') {
9561 p = *argptr;
9562 if (p == NULL || *p != '-' || *++p == '\0')
9563 return '\0';
9564 argptr++;
Eric Andersen2870d962001-07-02 17:27:21 +00009565 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009566 return '\0';
9567 }
9568 c = *p++;
9569 for (q = optstring ; *q != c ; ) {
9570 if (*q == '\0')
9571 error("Illegal option -%c", c);
9572 if (*++q == ':')
9573 q++;
9574 }
9575 if (*++q == ':') {
9576 if (*p == '\0' && (p = *argptr++) == NULL)
9577 error("No arg for -%c option", c);
9578 optionarg = p;
9579 p = NULL;
9580 }
9581 optptr = p;
9582 return c;
9583}
9584
Eric Andersencb57d552001-06-28 07:25:16 +00009585static void
9586flushall() {
Eric Andersencb57d552001-06-28 07:25:16 +00009587 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009588 fflush(stdout);
Eric Andersencb57d552001-06-28 07:25:16 +00009589 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009590}
9591
9592
9593static void
Eric Andersen3102ac42001-07-06 04:26:23 +00009594out2fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009595{
9596 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00009597 va_start(ap, fmt);
Eric Andersen3102ac42001-07-06 04:26:23 +00009598 vfprintf(stderr, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009599 va_end(ap);
9600}
9601
Eric Andersencb57d552001-06-28 07:25:16 +00009602/*
9603 * Version of write which resumes after a signal is caught.
9604 */
9605
9606static int
Eric Andersen2870d962001-07-02 17:27:21 +00009607xwrite(int fd, const char *buf, int nbytes)
9608{
Eric Andersencb57d552001-06-28 07:25:16 +00009609 int ntry;
9610 int i;
9611 int n;
9612
9613 n = nbytes;
9614 ntry = 0;
9615 for (;;) {
9616 i = write(fd, buf, n);
9617 if (i > 0) {
9618 if ((n -= i) <= 0)
9619 return nbytes;
9620 buf += i;
9621 ntry = 0;
9622 } else if (i == 0) {
9623 if (++ntry > 10)
9624 return nbytes - n;
9625 } else if (errno != EINTR) {
9626 return -1;
9627 }
9628 }
9629}
9630
9631
Eric Andersencb57d552001-06-28 07:25:16 +00009632/*
9633 * Shell command parser.
9634 */
9635
9636#define EOFMARKLEN 79
9637
9638
9639
9640struct heredoc {
Eric Andersen2870d962001-07-02 17:27:21 +00009641 struct heredoc *next; /* next here document in list */
9642 union node *here; /* redirection node */
9643 char *eofmark; /* string indicating end of input */
9644 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009645};
9646
Eric Andersen2870d962001-07-02 17:27:21 +00009647static struct heredoc *heredoclist; /* list of here documents to read */
9648static int parsebackquote; /* nonzero if we are inside backquotes */
9649static int doprompt; /* if set, prompt the user */
9650static int needprompt; /* true if interactive and at start of line */
9651static int lasttoken; /* last token read */
Eric Andersencb57d552001-06-28 07:25:16 +00009652
Eric Andersen2870d962001-07-02 17:27:21 +00009653static char *wordtext; /* text of last word returned by readtoken */
Eric Andersencb57d552001-06-28 07:25:16 +00009654
Eric Andersen2870d962001-07-02 17:27:21 +00009655static struct nodelist *backquotelist;
9656static union node *redirnode;
Eric Andersen044228d2001-07-17 01:12:36 +00009657static struct heredoc *heredoc;
Eric Andersen2870d962001-07-02 17:27:21 +00009658static int quoteflag; /* set if (part of) last token was quoted */
9659static int startlinno; /* line # where last token started */
Eric Andersencb57d552001-06-28 07:25:16 +00009660
9661
Eric Andersen2870d962001-07-02 17:27:21 +00009662static union node *list (int);
9663static union node *andor (void);
9664static union node *pipeline (void);
9665static union node *command (void);
9666static union node *simplecmd (void);
9667static void parsefname (void);
9668static void parseheredoc (void);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009669static char peektoken (void);
Eric Andersen2870d962001-07-02 17:27:21 +00009670static int readtoken (void);
9671static int xxreadtoken (void);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009672static int readtoken1 (int, int, const char *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00009673static int noexpand (char *);
9674static void synexpect (int) __attribute__((noreturn));
9675static void synerror (const char *) __attribute__((noreturn));
9676static void setprompt (int);
Eric Andersencb57d552001-06-28 07:25:16 +00009677
9678
9679/*
9680 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9681 * valid parse tree indicating a blank line.)
9682 */
9683
Eric Andersen2870d962001-07-02 17:27:21 +00009684static union node *
Eric Andersencb57d552001-06-28 07:25:16 +00009685parsecmd(int interact)
9686{
9687 int t;
9688
9689 tokpushback = 0;
9690 doprompt = interact;
9691 if (doprompt)
9692 setprompt(1);
9693 else
9694 setprompt(0);
9695 needprompt = 0;
9696 t = readtoken();
9697 if (t == TEOF)
9698 return NEOF;
9699 if (t == TNL)
9700 return NULL;
9701 tokpushback++;
9702 return list(1);
9703}
9704
9705
9706static union node *
9707list(nlflag)
9708 int nlflag;
9709{
9710 union node *n1, *n2, *n3;
9711 int tok;
9712
9713 checkkwd = 2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009714 if (nlflag == 0 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009715 return NULL;
9716 n1 = NULL;
9717 for (;;) {
9718 n2 = andor();
9719 tok = readtoken();
9720 if (tok == TBACKGND) {
9721 if (n2->type == NCMD || n2->type == NPIPE) {
9722 n2->ncmd.backgnd = 1;
9723 } else if (n2->type == NREDIR) {
9724 n2->type = NBACKGND;
9725 } else {
9726 n3 = (union node *)stalloc(sizeof (struct nredir));
9727 n3->type = NBACKGND;
9728 n3->nredir.n = n2;
9729 n3->nredir.redirect = NULL;
9730 n2 = n3;
9731 }
9732 }
9733 if (n1 == NULL) {
9734 n1 = n2;
9735 }
9736 else {
9737 n3 = (union node *)stalloc(sizeof (struct nbinary));
9738 n3->type = NSEMI;
9739 n3->nbinary.ch1 = n1;
9740 n3->nbinary.ch2 = n2;
9741 n1 = n3;
9742 }
9743 switch (tok) {
9744 case TBACKGND:
9745 case TSEMI:
9746 tok = readtoken();
9747 /* fall through */
9748 case TNL:
9749 if (tok == TNL) {
9750 parseheredoc();
9751 if (nlflag)
9752 return n1;
9753 } else {
9754 tokpushback++;
9755 }
9756 checkkwd = 2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009757 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009758 return n1;
9759 break;
9760 case TEOF:
9761 if (heredoclist)
9762 parseheredoc();
9763 else
Eric Andersen2870d962001-07-02 17:27:21 +00009764 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009765 return n1;
9766 default:
9767 if (nlflag)
9768 synexpect(-1);
9769 tokpushback++;
9770 return n1;
9771 }
9772 }
9773}
9774
9775
9776
9777static union node *
9778andor() {
9779 union node *n1, *n2, *n3;
9780 int t;
9781
9782 checkkwd = 1;
9783 n1 = pipeline();
9784 for (;;) {
9785 if ((t = readtoken()) == TAND) {
9786 t = NAND;
9787 } else if (t == TOR) {
9788 t = NOR;
9789 } else {
9790 tokpushback++;
9791 return n1;
9792 }
9793 checkkwd = 2;
9794 n2 = pipeline();
9795 n3 = (union node *)stalloc(sizeof (struct nbinary));
9796 n3->type = t;
9797 n3->nbinary.ch1 = n1;
9798 n3->nbinary.ch2 = n2;
9799 n1 = n3;
9800 }
9801}
9802
9803
9804
9805static union node *
9806pipeline() {
9807 union node *n1, *n2, *pipenode;
9808 struct nodelist *lp, *prev;
9809 int negate;
9810
9811 negate = 0;
9812 TRACE(("pipeline: entered\n"));
9813 if (readtoken() == TNOT) {
9814 negate = !negate;
9815 checkkwd = 1;
9816 } else
9817 tokpushback++;
9818 n1 = command();
9819 if (readtoken() == TPIPE) {
9820 pipenode = (union node *)stalloc(sizeof (struct npipe));
9821 pipenode->type = NPIPE;
9822 pipenode->npipe.backgnd = 0;
9823 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9824 pipenode->npipe.cmdlist = lp;
9825 lp->n = n1;
9826 do {
9827 prev = lp;
9828 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9829 checkkwd = 2;
9830 lp->n = command();
9831 prev->next = lp;
9832 } while (readtoken() == TPIPE);
9833 lp->next = NULL;
9834 n1 = pipenode;
9835 }
9836 tokpushback++;
9837 if (negate) {
9838 n2 = (union node *)stalloc(sizeof (struct nnot));
9839 n2->type = NNOT;
9840 n2->nnot.com = n1;
9841 return n2;
9842 } else
9843 return n1;
9844}
9845
9846
9847
9848static union node *
9849command() {
9850 union node *n1, *n2;
9851 union node *ap, **app;
9852 union node *cp, **cpp;
9853 union node *redir, **rpp;
9854 int t;
9855
9856 redir = NULL;
9857 n1 = NULL;
9858 rpp = &redir;
9859
9860 switch (readtoken()) {
9861 case TIF:
9862 n1 = (union node *)stalloc(sizeof (struct nif));
9863 n1->type = NIF;
9864 n1->nif.test = list(0);
9865 if (readtoken() != TTHEN)
9866 synexpect(TTHEN);
9867 n1->nif.ifpart = list(0);
9868 n2 = n1;
9869 while (readtoken() == TELIF) {
9870 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9871 n2 = n2->nif.elsepart;
9872 n2->type = NIF;
9873 n2->nif.test = list(0);
9874 if (readtoken() != TTHEN)
9875 synexpect(TTHEN);
9876 n2->nif.ifpart = list(0);
9877 }
9878 if (lasttoken == TELSE)
9879 n2->nif.elsepart = list(0);
9880 else {
9881 n2->nif.elsepart = NULL;
9882 tokpushback++;
9883 }
9884 if (readtoken() != TFI)
9885 synexpect(TFI);
9886 checkkwd = 1;
9887 break;
9888 case TWHILE:
9889 case TUNTIL: {
9890 int got;
9891 n1 = (union node *)stalloc(sizeof (struct nbinary));
9892 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9893 n1->nbinary.ch1 = list(0);
9894 if ((got=readtoken()) != TDO) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009895TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009896 synexpect(TDO);
9897 }
9898 n1->nbinary.ch2 = list(0);
9899 if (readtoken() != TDONE)
9900 synexpect(TDONE);
9901 checkkwd = 1;
9902 break;
9903 }
9904 case TFOR:
9905 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9906 synerror("Bad for loop variable");
9907 n1 = (union node *)stalloc(sizeof (struct nfor));
9908 n1->type = NFOR;
9909 n1->nfor.var = wordtext;
9910 checkkwd = 1;
9911 if (readtoken() == TIN) {
9912 app = &ap;
9913 while (readtoken() == TWORD) {
9914 n2 = (union node *)stalloc(sizeof (struct narg));
9915 n2->type = NARG;
9916 n2->narg.text = wordtext;
9917 n2->narg.backquote = backquotelist;
9918 *app = n2;
9919 app = &n2->narg.next;
9920 }
9921 *app = NULL;
9922 n1->nfor.args = ap;
9923 if (lasttoken != TNL && lasttoken != TSEMI)
9924 synexpect(-1);
9925 } else {
9926 static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
9927 '@', '=', '\0'};
9928 n2 = (union node *)stalloc(sizeof (struct narg));
9929 n2->type = NARG;
9930 n2->narg.text = argvars;
9931 n2->narg.backquote = NULL;
9932 n2->narg.next = NULL;
9933 n1->nfor.args = n2;
9934 /*
9935 * Newline or semicolon here is optional (but note
9936 * that the original Bourne shell only allowed NL).
9937 */
9938 if (lasttoken != TNL && lasttoken != TSEMI)
9939 tokpushback++;
9940 }
9941 checkkwd = 2;
9942 if (readtoken() != TDO)
9943 synexpect(TDO);
9944 n1->nfor.body = list(0);
9945 if (readtoken() != TDONE)
9946 synexpect(TDONE);
9947 checkkwd = 1;
9948 break;
9949 case TCASE:
9950 n1 = (union node *)stalloc(sizeof (struct ncase));
9951 n1->type = NCASE;
9952 if (readtoken() != TWORD)
9953 synexpect(TWORD);
9954 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9955 n2->type = NARG;
9956 n2->narg.text = wordtext;
9957 n2->narg.backquote = backquotelist;
9958 n2->narg.next = NULL;
9959 do {
9960 checkkwd = 1;
9961 } while (readtoken() == TNL);
9962 if (lasttoken != TIN)
9963 synerror("expecting \"in\"");
9964 cpp = &n1->ncase.cases;
9965 checkkwd = 2, readtoken();
9966 do {
9967 if (lasttoken == TLP)
9968 readtoken();
9969 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9970 cp->type = NCLIST;
9971 app = &cp->nclist.pattern;
9972 for (;;) {
9973 *app = ap = (union node *)stalloc(sizeof (struct narg));
9974 ap->type = NARG;
9975 ap->narg.text = wordtext;
9976 ap->narg.backquote = backquotelist;
9977 if (checkkwd = 2, readtoken() != TPIPE)
9978 break;
9979 app = &ap->narg.next;
9980 readtoken();
9981 }
9982 ap->narg.next = NULL;
9983 if (lasttoken != TRP)
9984 synexpect(TRP);
9985 cp->nclist.body = list(0);
9986
9987 checkkwd = 2;
9988 if ((t = readtoken()) != TESAC) {
9989 if (t != TENDCASE)
9990 synexpect(TENDCASE);
9991 else
9992 checkkwd = 2, readtoken();
9993 }
9994 cpp = &cp->nclist.next;
9995 } while(lasttoken != TESAC);
9996 *cpp = NULL;
9997 checkkwd = 1;
9998 break;
9999 case TLP:
10000 n1 = (union node *)stalloc(sizeof (struct nredir));
10001 n1->type = NSUBSHELL;
10002 n1->nredir.n = list(0);
10003 n1->nredir.redirect = NULL;
10004 if (readtoken() != TRP)
10005 synexpect(TRP);
10006 checkkwd = 1;
10007 break;
10008 case TBEGIN:
10009 n1 = list(0);
10010 if (readtoken() != TEND)
10011 synexpect(TEND);
10012 checkkwd = 1;
10013 break;
10014 /* Handle an empty command like other simple commands. */
10015 case TSEMI:
10016 case TAND:
10017 case TOR:
10018 case TNL:
10019 case TEOF:
10020 case TRP:
10021 case TBACKGND:
10022 /*
10023 * An empty command before a ; doesn't make much sense, and
10024 * should certainly be disallowed in the case of `if ;'.
10025 */
10026 if (!redir)
10027 synexpect(-1);
10028 case TWORD:
10029 case TREDIR:
10030 tokpushback++;
10031 n1 = simplecmd();
10032 return n1;
10033 default:
10034 synexpect(-1);
10035 /* NOTREACHED */
10036 }
10037
10038 /* Now check for redirection which may follow command */
10039 while (readtoken() == TREDIR) {
10040 *rpp = n2 = redirnode;
10041 rpp = &n2->nfile.next;
10042 parsefname();
10043 }
10044 tokpushback++;
10045 *rpp = NULL;
10046 if (redir) {
10047 if (n1->type != NSUBSHELL) {
10048 n2 = (union node *)stalloc(sizeof (struct nredir));
10049 n2->type = NREDIR;
10050 n2->nredir.n = n1;
10051 n1 = n2;
10052 }
10053 n1->nredir.redirect = redir;
10054 }
10055
10056 return n1;
10057}
10058
10059
10060static union node *
10061simplecmd() {
10062 union node *args, **app;
10063 union node *n = NULL;
10064 union node *vars, **vpp;
10065 union node **rpp, *redir;
10066
10067 args = NULL;
10068 app = &args;
10069 vars = NULL;
10070 vpp = &vars;
10071 redir = NULL;
10072 rpp = &redir;
10073
10074 checkalias = 2;
10075 for (;;) {
10076 switch (readtoken()) {
10077 case TWORD:
10078 case TASSIGN:
10079 n = (union node *)stalloc(sizeof (struct narg));
10080 n->type = NARG;
10081 n->narg.text = wordtext;
10082 n->narg.backquote = backquotelist;
10083 if (lasttoken == TWORD) {
10084 *app = n;
10085 app = &n->narg.next;
10086 } else {
10087 *vpp = n;
10088 vpp = &n->narg.next;
10089 }
10090 break;
10091 case TREDIR:
10092 *rpp = n = redirnode;
10093 rpp = &n->nfile.next;
Eric Andersen2870d962001-07-02 17:27:21 +000010094 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +000010095 break;
10096 case TLP:
10097 if (
10098 args && app == &args->narg.next &&
10099 !vars && !redir
10100 ) {
10101 /* We have a function */
10102 if (readtoken() != TRP)
10103 synexpect(TRP);
Eric Andersencb57d552001-06-28 07:25:16 +000010104 n->type = NDEFUN;
10105 checkkwd = 2;
10106 n->narg.next = command();
10107 return n;
10108 }
10109 /* fall through */
10110 default:
10111 tokpushback++;
10112 goto out;
10113 }
10114 }
10115out:
10116 *app = NULL;
10117 *vpp = NULL;
10118 *rpp = NULL;
10119 n = (union node *)stalloc(sizeof (struct ncmd));
10120 n->type = NCMD;
10121 n->ncmd.backgnd = 0;
10122 n->ncmd.args = args;
10123 n->ncmd.assign = vars;
10124 n->ncmd.redirect = redir;
10125 return n;
10126}
10127
10128static union node *
Eric Andersen2870d962001-07-02 17:27:21 +000010129makename(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000010130 union node *n;
10131
10132 n = (union node *)stalloc(sizeof (struct narg));
10133 n->type = NARG;
10134 n->narg.next = NULL;
10135 n->narg.text = wordtext;
10136 n->narg.backquote = backquotelist;
10137 return n;
10138}
10139
10140static void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +000010141{
Eric Andersencb57d552001-06-28 07:25:16 +000010142 TRACE(("Fix redir %s %d\n", text, err));
10143 if (!err)
10144 n->ndup.vname = NULL;
10145
10146 if (is_digit(text[0]) && text[1] == '\0')
10147 n->ndup.dupfd = digit_val(text[0]);
10148 else if (text[0] == '-' && text[1] == '\0')
10149 n->ndup.dupfd = -1;
10150 else {
10151
10152 if (err)
10153 synerror("Bad fd number");
10154 else
10155 n->ndup.vname = makename();
10156 }
10157}
10158
10159
10160static void
Eric Andersen2870d962001-07-02 17:27:21 +000010161parsefname(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000010162 union node *n = redirnode;
10163
10164 if (readtoken() != TWORD)
10165 synexpect(-1);
10166 if (n->type == NHERE) {
10167 struct heredoc *here = heredoc;
10168 struct heredoc *p;
10169 int i;
10170
10171 if (quoteflag == 0)
10172 n->type = NXHERE;
10173 TRACE(("Here document %d\n", n->type));
10174 if (here->striptabs) {
10175 while (*wordtext == '\t')
10176 wordtext++;
10177 }
10178 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
10179 synerror("Illegal eof marker for << redirection");
10180 rmescapes(wordtext);
10181 here->eofmark = wordtext;
10182 here->next = NULL;
10183 if (heredoclist == NULL)
10184 heredoclist = here;
10185 else {
10186 for (p = heredoclist ; p->next ; p = p->next);
10187 p->next = here;
10188 }
10189 } else if (n->type == NTOFD || n->type == NFROMFD) {
10190 fixredir(n, wordtext, 0);
10191 } else {
10192 n->nfile.fname = makename();
10193 }
10194}
10195
10196
10197/*
10198 * Input any here documents.
10199 */
10200
10201static void
10202parseheredoc() {
10203 struct heredoc *here;
10204 union node *n;
10205
10206 while (heredoclist) {
10207 here = heredoclist;
10208 heredoclist = here->next;
10209 if (needprompt) {
10210 setprompt(2);
10211 needprompt = 0;
10212 }
10213 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
10214 here->eofmark, here->striptabs);
10215 n = (union node *)stalloc(sizeof (struct narg));
10216 n->narg.type = NARG;
10217 n->narg.next = NULL;
10218 n->narg.text = wordtext;
10219 n->narg.backquote = backquotelist;
10220 here->here->nhere.doc = n;
10221 }
10222}
10223
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010224static char
Eric Andersencb57d552001-06-28 07:25:16 +000010225peektoken() {
10226 int t;
10227
10228 t = readtoken();
10229 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010230 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +000010231}
10232
10233static int
10234readtoken() {
10235 int t;
Eric Andersen7467c8d2001-07-12 20:26:32 +000010236
Eric Andersen2870d962001-07-02 17:27:21 +000010237#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010238 int savecheckalias = checkalias;
Eric Andersen7467c8d2001-07-12 20:26:32 +000010239 int savecheckkwd = checkkwd;
Eric Andersencb57d552001-06-28 07:25:16 +000010240 struct alias *ap;
Eric Andersen2870d962001-07-02 17:27:21 +000010241#endif
10242
Eric Andersencb57d552001-06-28 07:25:16 +000010243#ifdef DEBUG
10244 int alreadyseen = tokpushback;
10245#endif
10246
Eric Andersen2870d962001-07-02 17:27:21 +000010247#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010248top:
Eric Andersen2870d962001-07-02 17:27:21 +000010249#endif
10250
Eric Andersencb57d552001-06-28 07:25:16 +000010251 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +000010252
10253#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010254 checkalias = savecheckalias;
Eric Andersen2870d962001-07-02 17:27:21 +000010255#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010256
10257 if (checkkwd) {
10258 /*
10259 * eat newlines
10260 */
10261 if (checkkwd == 2) {
10262 checkkwd = 0;
10263 while (t == TNL) {
10264 parseheredoc();
10265 t = xxreadtoken();
10266 }
10267 }
10268 checkkwd = 0;
10269 /*
10270 * check for keywords
10271 */
10272 if (t == TWORD && !quoteflag)
10273 {
10274 const char *const *pp;
10275
10276 if ((pp = findkwd(wordtext))) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010277 lasttoken = t = pp - tokname_array;
10278 TRACE(("keyword %s recognized\n", tokname(t)));
Eric Andersencb57d552001-06-28 07:25:16 +000010279 goto out;
10280 }
10281 }
10282 }
10283
Eric Andersen7467c8d2001-07-12 20:26:32 +000010284
Eric Andersencb57d552001-06-28 07:25:16 +000010285 if (t != TWORD) {
10286 if (t != TREDIR) {
10287 checkalias = 0;
10288 }
10289 } else if (checkalias == 2 && isassignment(wordtext)) {
10290 lasttoken = t = TASSIGN;
Eric Andersen7467c8d2001-07-12 20:26:32 +000010291#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010292 } else if (checkalias) {
10293 if (!quoteflag && (ap = lookupalias(wordtext, 1)) != NULL) {
10294 if (*ap->val) {
10295 pushstring(ap->val, strlen(ap->val), ap);
10296 }
10297 checkkwd = savecheckkwd;
10298 goto top;
10299 }
10300 checkalias = 0;
Eric Andersen2870d962001-07-02 17:27:21 +000010301#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +000010302 }
Eric Andersencb57d552001-06-28 07:25:16 +000010303out:
10304#ifdef DEBUG
10305 if (!alreadyseen)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010306 TRACE(("token %s %s\n", tokname(t), t == TWORD || t == TASSIGN ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +000010307 else
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010308 TRACE(("reread token %s %s\n", tokname(t), t == TWORD || t == TASSIGN ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +000010309#endif
10310 return (t);
10311}
10312
10313
10314/*
10315 * Read the next input token.
10316 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +000010317 * backquotes. We set quoteflag to true if any part of the word was
10318 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +000010319 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +000010320 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +000010321 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +000010322 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +000010323 *
10324 * [Change comment: here documents and internal procedures]
10325 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10326 * word parsing code into a separate routine. In this case, readtoken
10327 * doesn't need to have any internal procedures, but parseword does.
10328 * We could also make parseoperator in essence the main routine, and
10329 * have parseword (readtoken1?) handle both words and redirection.]
10330 */
10331
Eric Andersen2870d962001-07-02 17:27:21 +000010332#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010333
10334static int
10335xxreadtoken() {
10336 int c;
10337
10338 if (tokpushback) {
10339 tokpushback = 0;
10340 return lasttoken;
10341 }
10342 if (needprompt) {
10343 setprompt(2);
10344 needprompt = 0;
10345 }
10346 startlinno = plinno;
Eric Andersen2870d962001-07-02 17:27:21 +000010347 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010348 c = pgetc_macro();
10349 switch (c) {
10350 case ' ': case '\t':
Eric Andersen3102ac42001-07-06 04:26:23 +000010351#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010352 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010353#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010354 continue;
10355 case '#':
10356 while ((c = pgetc()) != '\n' && c != PEOF);
10357 pungetc();
10358 continue;
10359 case '\\':
10360 if (pgetc() == '\n') {
10361 startlinno = ++plinno;
10362 if (doprompt)
10363 setprompt(2);
10364 else
10365 setprompt(0);
10366 continue;
10367 }
10368 pungetc();
10369 goto breakloop;
10370 case '\n':
10371 plinno++;
10372 needprompt = doprompt;
10373 RETURN(TNL);
10374 case PEOF:
10375 RETURN(TEOF);
10376 case '&':
10377 if (pgetc() == '&')
10378 RETURN(TAND);
10379 pungetc();
10380 RETURN(TBACKGND);
10381 case '|':
10382 if (pgetc() == '|')
10383 RETURN(TOR);
10384 pungetc();
10385 RETURN(TPIPE);
10386 case ';':
10387 if (pgetc() == ';')
10388 RETURN(TENDCASE);
10389 pungetc();
10390 RETURN(TSEMI);
10391 case '(':
10392 RETURN(TLP);
10393 case ')':
10394 RETURN(TRP);
10395 default:
10396 goto breakloop;
10397 }
10398 }
10399breakloop:
10400 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10401#undef RETURN
10402}
10403
10404
10405
10406/*
10407 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10408 * is not NULL, read a here document. In the latter case, eofmark is the
10409 * word which marks the end of the document and striptabs is true if
10410 * leading tabs should be stripped from the document. The argument firstc
10411 * is the first character of the input token or document.
10412 *
10413 * Because C does not have internal subroutines, I have simulated them
10414 * using goto's to implement the subroutine linkage. The following macros
10415 * will run code that appears at the end of readtoken1.
10416 */
10417
Eric Andersen2870d962001-07-02 17:27:21 +000010418#define CHECKEND() {goto checkend; checkend_return:;}
10419#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10420#define PARSESUB() {goto parsesub; parsesub_return:;}
10421#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10422#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10423#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010424
10425static int
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010426readtoken1(int firstc, int syntax, const char *eofmark, int striptabs)
10427{
Eric Andersencb57d552001-06-28 07:25:16 +000010428 int c = firstc;
10429 char *out;
10430 int len;
10431 char line[EOFMARKLEN + 1];
10432 struct nodelist *bqlist;
10433 int quotef;
10434 int dblquote;
Eric Andersen2870d962001-07-02 17:27:21 +000010435 int varnest; /* levels of variables expansion */
10436 int arinest; /* levels of arithmetic expansion */
10437 int parenlevel; /* levels of parens in arithmetic */
10438 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +000010439 int oldstyle;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010440 int prevsyntax; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010441#if __GNUC__
10442 /* Avoid longjmp clobbering */
10443 (void) &out;
10444 (void) &quotef;
10445 (void) &dblquote;
10446 (void) &varnest;
10447 (void) &arinest;
10448 (void) &parenlevel;
10449 (void) &dqvarnest;
10450 (void) &oldstyle;
10451 (void) &prevsyntax;
10452 (void) &syntax;
10453#endif
10454
10455 startlinno = plinno;
10456 dblquote = 0;
10457 if (syntax == DQSYNTAX)
10458 dblquote = 1;
10459 quotef = 0;
10460 bqlist = NULL;
10461 varnest = 0;
10462 arinest = 0;
10463 parenlevel = 0;
10464 dqvarnest = 0;
10465
10466 STARTSTACKSTR(out);
Eric Andersen2870d962001-07-02 17:27:21 +000010467 loop: { /* for each line, until end of word */
10468 CHECKEND(); /* set c to PEOF if at end of here document */
10469 for (;;) { /* until end of line or end of word */
10470 CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010471 switch(SIT(c,syntax)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010472 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010473 if (syntax == BASESYNTAX)
Eric Andersen2870d962001-07-02 17:27:21 +000010474 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010475 USTPUTC(c, out);
10476 plinno++;
10477 if (doprompt)
10478 setprompt(2);
10479 else
10480 setprompt(0);
10481 c = pgetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010482 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010483 case CWORD:
10484 USTPUTC(c, out);
10485 break;
10486 case CCTL:
10487 if ((eofmark == NULL || dblquote) &&
10488 dqvarnest == 0)
10489 USTPUTC(CTLESC, out);
10490 USTPUTC(c, out);
10491 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010492 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010493 c = pgetc2();
10494 if (c == PEOF) {
10495 USTPUTC('\\', out);
10496 pungetc();
10497 } else if (c == '\n') {
10498 if (doprompt)
10499 setprompt(2);
10500 else
10501 setprompt(0);
10502 } else {
10503 if (dblquote && c != '\\' && c != '`' && c != '$'
10504 && (c != '"' || eofmark != NULL))
10505 USTPUTC('\\', out);
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010506 if (SIT(c,SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010507 USTPUTC(CTLESC, out);
10508 else if (eofmark == NULL)
10509 USTPUTC(CTLQUOTEMARK, out);
10510 USTPUTC(c, out);
10511 quotef++;
10512 }
10513 break;
10514 case CSQUOTE:
10515 if (eofmark == NULL)
10516 USTPUTC(CTLQUOTEMARK, out);
10517 syntax = SQSYNTAX;
10518 break;
10519 case CDQUOTE:
10520 if (eofmark == NULL)
10521 USTPUTC(CTLQUOTEMARK, out);
10522 syntax = DQSYNTAX;
10523 dblquote = 1;
10524 break;
10525 case CENDQUOTE:
10526 if (eofmark != NULL && arinest == 0 &&
10527 varnest == 0) {
10528 USTPUTC(c, out);
10529 } else {
10530 if (arinest) {
10531 syntax = ARISYNTAX;
10532 dblquote = 0;
10533 } else if (eofmark == NULL &&
10534 dqvarnest == 0) {
10535 syntax = BASESYNTAX;
10536 dblquote = 0;
10537 }
10538 quotef++;
10539 }
10540 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010541 case CVAR: /* '$' */
10542 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010543 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010544 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010545 if (varnest > 0) {
10546 varnest--;
10547 if (dqvarnest > 0) {
10548 dqvarnest--;
10549 }
10550 USTPUTC(CTLENDVAR, out);
10551 } else {
10552 USTPUTC(c, out);
10553 }
10554 break;
10555#ifdef ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +000010556 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010557 parenlevel++;
10558 USTPUTC(c, out);
10559 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010560 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010561 if (parenlevel > 0) {
10562 USTPUTC(c, out);
10563 --parenlevel;
10564 } else {
10565 if (pgetc() == ')') {
10566 if (--arinest == 0) {
10567 USTPUTC(CTLENDARI, out);
10568 syntax = prevsyntax;
10569 if (syntax == DQSYNTAX)
10570 dblquote = 1;
10571 else
10572 dblquote = 0;
10573 } else
10574 USTPUTC(')', out);
10575 } else {
10576 /*
10577 * unbalanced parens
10578 * (don't 2nd guess - no error)
10579 */
10580 pungetc();
10581 USTPUTC(')', out);
10582 }
10583 }
10584 break;
10585#endif
Eric Andersen2870d962001-07-02 17:27:21 +000010586 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010587 PARSEBACKQOLD();
10588 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010589 case CENDFILE:
10590 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010591 case CIGN:
10592 break;
10593 default:
10594 if (varnest == 0)
Eric Andersen2870d962001-07-02 17:27:21 +000010595 goto endword; /* exit outer loop */
Eric Andersen3102ac42001-07-06 04:26:23 +000010596#ifdef ASH_ALIAS
10597 if (c != PEOA)
10598#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010599 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010600
Eric Andersencb57d552001-06-28 07:25:16 +000010601 }
10602 c = pgetc_macro();
10603 }
10604 }
10605endword:
10606 if (syntax == ARISYNTAX)
10607 synerror("Missing '))'");
10608 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10609 synerror("Unterminated quoted string");
10610 if (varnest != 0) {
10611 startlinno = plinno;
10612 synerror("Missing '}'");
10613 }
10614 USTPUTC('\0', out);
10615 len = out - stackblock();
10616 out = stackblock();
10617 if (eofmark == NULL) {
10618 if ((c == '>' || c == '<')
10619 && quotef == 0
10620 && len <= 2
10621 && (*out == '\0' || is_digit(*out))) {
10622 PARSEREDIR();
10623 return lasttoken = TREDIR;
10624 } else {
10625 pungetc();
10626 }
10627 }
10628 quoteflag = quotef;
10629 backquotelist = bqlist;
10630 grabstackblock(len);
10631 wordtext = out;
10632 return lasttoken = TWORD;
10633/* end of readtoken routine */
10634
10635
10636
10637/*
10638 * Check to see whether we are at the end of the here document. When this
10639 * is called, c is set to the first character of the next input line. If
10640 * we are at the end of the here document, this routine sets the c to PEOF.
10641 */
10642
10643checkend: {
10644 if (eofmark) {
Eric Andersen2870d962001-07-02 17:27:21 +000010645#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010646 if (c == PEOA) {
10647 c = pgetc2();
10648 }
Eric Andersen2870d962001-07-02 17:27:21 +000010649#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010650 if (striptabs) {
10651 while (c == '\t') {
10652 c = pgetc2();
10653 }
10654 }
10655 if (c == *eofmark) {
10656 if (pfgets(line, sizeof line) != NULL) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010657 const char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010658
10659 p = line;
10660 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10661 if (*p == '\n' && *q == '\0') {
10662 c = PEOF;
10663 plinno++;
10664 needprompt = doprompt;
10665 } else {
10666 pushstring(line, strlen(line), NULL);
10667 }
10668 }
10669 }
10670 }
10671 goto checkend_return;
10672}
10673
10674
10675/*
10676 * Parse a redirection operator. The variable "out" points to a string
10677 * specifying the fd to be redirected. The variable "c" contains the
10678 * first character of the redirection operator.
10679 */
10680
10681parseredir: {
10682 char fd = *out;
10683 union node *np;
10684
10685 np = (union node *)stalloc(sizeof (struct nfile));
10686 if (c == '>') {
10687 np->nfile.fd = 1;
10688 c = pgetc();
10689 if (c == '>')
10690 np->type = NAPPEND;
10691 else if (c == '&')
10692 np->type = NTOFD;
10693 else if (c == '|')
10694 np->type = NTOOV;
10695 else {
10696 np->type = NTO;
10697 pungetc();
10698 }
Eric Andersen2870d962001-07-02 17:27:21 +000010699 } else { /* c == '<' */
Eric Andersencb57d552001-06-28 07:25:16 +000010700 np->nfile.fd = 0;
10701 switch (c = pgetc()) {
10702 case '<':
10703 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10704 np = (union node *)stalloc(sizeof (struct nhere));
10705 np->nfile.fd = 0;
10706 }
10707 np->type = NHERE;
10708 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10709 heredoc->here = np;
10710 if ((c = pgetc()) == '-') {
10711 heredoc->striptabs = 1;
10712 } else {
10713 heredoc->striptabs = 0;
10714 pungetc();
10715 }
10716 break;
10717
10718 case '&':
10719 np->type = NFROMFD;
10720 break;
10721
10722 case '>':
10723 np->type = NFROMTO;
10724 break;
10725
10726 default:
10727 np->type = NFROM;
10728 pungetc();
10729 break;
10730 }
10731 }
10732 if (fd != '\0')
10733 np->nfile.fd = digit_val(fd);
10734 redirnode = np;
10735 goto parseredir_return;
10736}
10737
10738
10739/*
10740 * Parse a substitution. At this point, we have read the dollar sign
10741 * and nothing else.
10742 */
10743
10744parsesub: {
10745 int subtype;
10746 int typeloc;
10747 int flags;
10748 char *p;
10749 static const char types[] = "}-+?=";
10750
10751 c = pgetc();
10752 if (
10753 c <= PEOA ||
10754 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10755 ) {
10756 USTPUTC('$', out);
10757 pungetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010758 } else if (c == '(') { /* $(command) or $((arith)) */
Eric Andersencb57d552001-06-28 07:25:16 +000010759 if (pgetc() == '(') {
10760 PARSEARITH();
10761 } else {
10762 pungetc();
10763 PARSEBACKQNEW();
10764 }
10765 } else {
10766 USTPUTC(CTLVAR, out);
10767 typeloc = out - stackblock();
10768 USTPUTC(VSNORMAL, out);
10769 subtype = VSNORMAL;
10770 if (c == '{') {
10771 c = pgetc();
10772 if (c == '#') {
10773 if ((c = pgetc()) == '}')
10774 c = '#';
10775 else
10776 subtype = VSLENGTH;
10777 }
10778 else
10779 subtype = 0;
10780 }
10781 if (c > PEOA && is_name(c)) {
10782 do {
10783 STPUTC(c, out);
10784 c = pgetc();
10785 } while (c > PEOA && is_in_name(c));
10786 } else if (is_digit(c)) {
10787 do {
10788 USTPUTC(c, out);
10789 c = pgetc();
10790 } while (is_digit(c));
10791 }
10792 else if (is_special(c)) {
10793 USTPUTC(c, out);
10794 c = pgetc();
10795 }
10796 else
Eric Andersen2870d962001-07-02 17:27:21 +000010797badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010798
10799 STPUTC('=', out);
10800 flags = 0;
10801 if (subtype == 0) {
10802 switch (c) {
10803 case ':':
10804 flags = VSNUL;
10805 c = pgetc();
10806 /*FALLTHROUGH*/
10807 default:
10808 p = strchr(types, c);
10809 if (p == NULL)
10810 goto badsub;
10811 subtype = p - types + VSNORMAL;
10812 break;
10813 case '%':
10814 case '#':
10815 {
10816 int cc = c;
10817 subtype = c == '#' ? VSTRIMLEFT :
10818 VSTRIMRIGHT;
10819 c = pgetc();
10820 if (c == cc)
10821 subtype++;
10822 else
10823 pungetc();
10824 break;
10825 }
10826 }
10827 } else {
10828 pungetc();
10829 }
10830 if (dblquote || arinest)
10831 flags |= VSQUOTE;
10832 *(stackblock() + typeloc) = subtype | flags;
10833 if (subtype != VSNORMAL) {
10834 varnest++;
10835 if (dblquote) {
10836 dqvarnest++;
10837 }
10838 }
10839 }
10840 goto parsesub_return;
10841}
10842
10843
10844/*
10845 * Called to parse command substitutions. Newstyle is set if the command
10846 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10847 * list of commands (passed by reference), and savelen is the number of
10848 * characters on the top of the stack which must be preserved.
10849 */
10850
10851parsebackq: {
10852 struct nodelist **nlpp;
10853 int savepbq;
10854 union node *n;
10855 char *volatile str;
10856 struct jmploc jmploc;
10857 struct jmploc *volatile savehandler;
10858 int savelen;
10859 int saveprompt;
10860#ifdef __GNUC__
10861 (void) &saveprompt;
10862#endif
10863
10864 savepbq = parsebackquote;
10865 if (setjmp(jmploc.loc)) {
10866 if (str)
10867 ckfree(str);
10868 parsebackquote = 0;
10869 handler = savehandler;
10870 longjmp(handler->loc, 1);
10871 }
10872 INTOFF;
10873 str = NULL;
10874 savelen = out - stackblock();
10875 if (savelen > 0) {
10876 str = ckmalloc(savelen);
10877 memcpy(str, stackblock(), savelen);
10878 }
10879 savehandler = handler;
10880 handler = &jmploc;
10881 INTON;
Eric Andersen2870d962001-07-02 17:27:21 +000010882 if (oldstyle) {
10883 /* We must read until the closing backquote, giving special
10884 treatment to some slashes, and then push the string and
10885 reread it as input, interpreting it normally. */
10886 char *pout;
10887 int pc;
10888 int psavelen;
10889 char *pstr;
Eric Andersencb57d552001-06-28 07:25:16 +000010890
10891
Eric Andersen2870d962001-07-02 17:27:21 +000010892 STARTSTACKSTR(pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010893 for (;;) {
10894 if (needprompt) {
10895 setprompt(2);
10896 needprompt = 0;
10897 }
10898 switch (pc = pgetc()) {
10899 case '`':
10900 goto done;
10901
10902 case '\\':
Eric Andersen2870d962001-07-02 17:27:21 +000010903 if ((pc = pgetc()) == '\n') {
Eric Andersencb57d552001-06-28 07:25:16 +000010904 plinno++;
10905 if (doprompt)
10906 setprompt(2);
10907 else
10908 setprompt(0);
10909 /*
10910 * If eating a newline, avoid putting
10911 * the newline into the new character
10912 * stream (via the STPUTC after the
10913 * switch).
10914 */
10915 continue;
10916 }
Eric Andersen2870d962001-07-02 17:27:21 +000010917 if (pc != '\\' && pc != '`' && pc != '$'
10918 && (!dblquote || pc != '"'))
10919 STPUTC('\\', pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010920 if (pc > PEOA) {
10921 break;
10922 }
10923 /* fall through */
10924
10925 case PEOF:
Eric Andersen2870d962001-07-02 17:27:21 +000010926#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010927 case PEOA:
Eric Andersen2870d962001-07-02 17:27:21 +000010928#endif
10929 startlinno = plinno;
Eric Andersencb57d552001-06-28 07:25:16 +000010930 synerror("EOF in backquote substitution");
10931
10932 case '\n':
10933 plinno++;
10934 needprompt = doprompt;
10935 break;
10936
10937 default:
10938 break;
10939 }
10940 STPUTC(pc, pout);
Eric Andersen2870d962001-07-02 17:27:21 +000010941 }
Eric Andersencb57d552001-06-28 07:25:16 +000010942done:
Eric Andersen2870d962001-07-02 17:27:21 +000010943 STPUTC('\0', pout);
10944 psavelen = pout - stackblock();
10945 if (psavelen > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010946 pstr = grabstackstr(pout);
10947 setinputstring(pstr);
Eric Andersen2870d962001-07-02 17:27:21 +000010948 }
10949 }
Eric Andersencb57d552001-06-28 07:25:16 +000010950 nlpp = &bqlist;
10951 while (*nlpp)
10952 nlpp = &(*nlpp)->next;
10953 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10954 (*nlpp)->next = NULL;
10955 parsebackquote = oldstyle;
10956
10957 if (oldstyle) {
10958 saveprompt = doprompt;
10959 doprompt = 0;
10960 }
10961
10962 n = list(0);
10963
10964 if (oldstyle)
10965 doprompt = saveprompt;
10966 else {
10967 if (readtoken() != TRP)
10968 synexpect(TRP);
10969 }
10970
10971 (*nlpp)->n = n;
Eric Andersen2870d962001-07-02 17:27:21 +000010972 if (oldstyle) {
Eric Andersencb57d552001-06-28 07:25:16 +000010973 /*
10974 * Start reading from old file again, ignoring any pushed back
10975 * tokens left from the backquote parsing
10976 */
Eric Andersen2870d962001-07-02 17:27:21 +000010977 popfile();
Eric Andersencb57d552001-06-28 07:25:16 +000010978 tokpushback = 0;
10979 }
10980 while (stackblocksize() <= savelen)
10981 growstackblock();
10982 STARTSTACKSTR(out);
10983 if (str) {
10984 memcpy(out, str, savelen);
10985 STADJUST(savelen, out);
10986 INTOFF;
10987 ckfree(str);
10988 str = NULL;
10989 INTON;
10990 }
10991 parsebackquote = savepbq;
10992 handler = savehandler;
10993 if (arinest || dblquote)
10994 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10995 else
10996 USTPUTC(CTLBACKQ, out);
10997 if (oldstyle)
10998 goto parsebackq_oldreturn;
10999 else
11000 goto parsebackq_newreturn;
11001}
11002
11003/*
11004 * Parse an arithmetic expansion (indicate start of one and set state)
11005 */
11006parsearith: {
11007
11008 if (++arinest == 1) {
11009 prevsyntax = syntax;
11010 syntax = ARISYNTAX;
11011 USTPUTC(CTLARI, out);
11012 if (dblquote)
11013 USTPUTC('"',out);
11014 else
11015 USTPUTC(' ',out);
11016 } else {
11017 /*
11018 * we collapse embedded arithmetic expansion to
11019 * parenthesis, which should be equivalent
11020 */
11021 USTPUTC('(', out);
11022 }
11023 goto parsearith_return;
11024}
11025
11026} /* end of readtoken */
11027
11028
Eric Andersencb57d552001-06-28 07:25:16 +000011029/*
11030 * Returns true if the text contains nothing to expand (no dollar signs
11031 * or backquotes).
11032 */
11033
11034static int
11035noexpand(text)
11036 char *text;
11037 {
11038 char *p;
11039 char c;
11040
11041 p = text;
11042 while ((c = *p++) != '\0') {
11043 if (c == CTLQUOTEMARK)
11044 continue;
11045 if (c == CTLESC)
11046 p++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011047 else if (SIT(c,BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000011048 return 0;
11049 }
11050 return 1;
11051}
11052
11053
11054/*
11055 * Return true if the argument is a legal variable name (a letter or
11056 * underscore followed by zero or more letters, underscores, and digits).
11057 */
11058
11059static int
Eric Andersen2870d962001-07-02 17:27:21 +000011060goodname(const char *name)
11061{
11062 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000011063
11064 p = name;
11065 if (! is_name(*p))
11066 return 0;
11067 while (*++p) {
11068 if (! is_in_name(*p))
11069 return 0;
11070 }
11071 return 1;
11072}
11073
11074
11075/*
11076 * Called when an unexpected token is read during the parse. The argument
11077 * is the token that is expected, or -1 if more than one type of token can
11078 * occur at this point.
11079 */
11080
11081static void
11082synexpect(token)
11083 int token;
11084{
11085 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011086 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000011087
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011088 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
11089 if (token >= 0)
11090 sprintf(msg+l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000011091 synerror(msg);
11092 /* NOTREACHED */
11093}
11094
11095
11096static void
Eric Andersen2870d962001-07-02 17:27:21 +000011097synerror(const char *msg)
11098{
Eric Andersencb57d552001-06-28 07:25:16 +000011099 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +000011100 out2fmt("%s: %d: ", commandname, startlinno);
11101 out2fmt("Syntax error: %s\n", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000011102 error((char *)NULL);
11103 /* NOTREACHED */
11104}
11105
Eric Andersencb57d552001-06-28 07:25:16 +000011106
11107/*
11108 * called by editline -- any expansions to the prompt
11109 * should be added here.
11110 */
Eric Andersen2870d962001-07-02 17:27:21 +000011111static void
Eric Andersen62483552001-07-10 06:09:16 +000011112setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000011113{
Eric Andersen62483552001-07-10 06:09:16 +000011114 char *prompt;
11115 switch (whichprompt) {
11116 case 1:
11117 prompt = ps1val();
11118 break;
11119 case 2:
11120 prompt = ps2val();
11121 break;
11122 default: /* 0 */
11123 prompt = "";
11124 }
11125 putprompt(prompt);
Eric Andersencb57d552001-06-28 07:25:16 +000011126}
11127
Eric Andersencb57d552001-06-28 07:25:16 +000011128
Eric Andersencb57d552001-06-28 07:25:16 +000011129/*
11130 * Code for dealing with input/output redirection.
11131 */
11132
Eric Andersen2870d962001-07-02 17:27:21 +000011133#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000011134#ifndef PIPE_BUF
Eric Andersen2870d962001-07-02 17:27:21 +000011135# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000011136#else
11137# define PIPESIZE PIPE_BUF
11138#endif
11139
11140
Eric Andersen62483552001-07-10 06:09:16 +000011141/*
11142 * Open a file in noclobber mode.
11143 * The code was copied from bash.
11144 */
11145static inline int
11146noclobberopen(const char *fname)
11147{
11148 int r, fd;
11149 struct stat finfo, finfo2;
11150
11151 /*
11152 * If the file exists and is a regular file, return an error
11153 * immediately.
11154 */
11155 r = stat(fname, &finfo);
11156 if (r == 0 && S_ISREG(finfo.st_mode)) {
11157 errno = EEXIST;
11158 return -1;
11159 }
11160
11161 /*
11162 * If the file was not present (r != 0), make sure we open it
11163 * exclusively so that if it is created before we open it, our open
11164 * will fail. Make sure that we do not truncate an existing file.
11165 * Note that we don't turn on O_EXCL unless the stat failed -- if the
11166 * file was not a regular file, we leave O_EXCL off.
11167 */
11168 if (r != 0)
11169 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
11170 fd = open(fname, O_WRONLY|O_CREAT, 0666);
11171
11172 /* If the open failed, return the file descriptor right away. */
11173 if (fd < 0)
11174 return fd;
11175
11176 /*
11177 * OK, the open succeeded, but the file may have been changed from a
11178 * non-regular file to a regular file between the stat and the open.
11179 * We are assuming that the O_EXCL open handles the case where FILENAME
11180 * did not exist and is symlinked to an existing file between the stat
11181 * and open.
11182 */
11183
11184 /*
11185 * If we can open it and fstat the file descriptor, and neither check
11186 * revealed that it was a regular file, and the file has not been
11187 * replaced, return the file descriptor.
11188 */
11189 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
11190 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
11191 return fd;
11192
11193 /* The file has been replaced. badness. */
11194 close(fd);
11195 errno = EEXIST;
11196 return -1;
11197}
Eric Andersencb57d552001-06-28 07:25:16 +000011198
11199/*
Eric Andersen62483552001-07-10 06:09:16 +000011200 * Handle here documents. Normally we fork off a process to write the
11201 * data to a pipe. If the document is short, we can stuff the data in
11202 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000011203 */
11204
Eric Andersen62483552001-07-10 06:09:16 +000011205static inline int
11206openhere(const union node *redir)
11207{
11208 int pip[2];
11209 int len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011210
Eric Andersen62483552001-07-10 06:09:16 +000011211 if (pipe(pip) < 0)
11212 error("Pipe call failed");
11213 if (redir->type == NHERE) {
11214 len = strlen(redir->nhere.doc->narg.text);
11215 if (len <= PIPESIZE) {
11216 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11217 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011218 }
Eric Andersencb57d552001-06-28 07:25:16 +000011219 }
Eric Andersen62483552001-07-10 06:09:16 +000011220 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
11221 close(pip[0]);
11222 signal(SIGINT, SIG_IGN);
11223 signal(SIGQUIT, SIG_IGN);
11224 signal(SIGHUP, SIG_IGN);
11225#ifdef SIGTSTP
11226 signal(SIGTSTP, SIG_IGN);
11227#endif
11228 signal(SIGPIPE, SIG_DFL);
11229 if (redir->type == NHERE)
11230 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11231 else
11232 expandhere(redir->nhere.doc, pip[1]);
11233 _exit(0);
11234 }
11235out:
11236 close(pip[1]);
11237 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000011238}
11239
11240
Eric Andersen62483552001-07-10 06:09:16 +000011241static inline int
11242openredirect(const union node *redir)
11243{
Eric Andersencb57d552001-06-28 07:25:16 +000011244 char *fname;
11245 int f;
11246
11247 switch (redir->nfile.type) {
11248 case NFROM:
11249 fname = redir->nfile.expfname;
11250 if ((f = open(fname, O_RDONLY)) < 0)
11251 goto eopen;
11252 break;
11253 case NFROMTO:
11254 fname = redir->nfile.expfname;
11255 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
11256 goto ecreate;
11257 break;
11258 case NTO:
11259 /* Take care of noclobber mode. */
11260 if (Cflag) {
11261 fname = redir->nfile.expfname;
11262 if ((f = noclobberopen(fname)) < 0)
11263 goto ecreate;
11264 break;
11265 }
11266 case NTOOV:
11267 fname = redir->nfile.expfname;
11268#ifdef O_CREAT
11269 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
11270 goto ecreate;
11271#else
11272 if ((f = creat(fname, 0666)) < 0)
11273 goto ecreate;
11274#endif
11275 break;
11276 case NAPPEND:
11277 fname = redir->nfile.expfname;
11278#ifdef O_APPEND
11279 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
11280 goto ecreate;
11281#else
11282 if ((f = open(fname, O_WRONLY)) < 0
11283 && (f = creat(fname, 0666)) < 0)
11284 goto ecreate;
11285 lseek(f, (off_t)0, 2);
11286#endif
11287 break;
11288 default:
11289#ifdef DEBUG
11290 abort();
11291#endif
11292 /* Fall through to eliminate warning. */
11293 case NTOFD:
11294 case NFROMFD:
11295 f = -1;
11296 break;
11297 case NHERE:
11298 case NXHERE:
11299 f = openhere(redir);
11300 break;
11301 }
11302
11303 return f;
11304ecreate:
11305 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11306eopen:
11307 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11308}
11309
11310
Eric Andersen62483552001-07-10 06:09:16 +000011311/*
11312 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11313 * old file descriptors are stashed away so that the redirection can be
11314 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11315 * standard output, and the standard error if it becomes a duplicate of
11316 * stdout.
11317 */
11318
Eric Andersencb57d552001-06-28 07:25:16 +000011319static void
Eric Andersen62483552001-07-10 06:09:16 +000011320redirect(union node *redir, int flags)
11321{
11322 union node *n;
11323 struct redirtab *sv = NULL;
11324 int i;
11325 int fd;
11326 int newfd;
11327 int try;
11328 int fd1dup = flags & REDIR_BACKQ;; /* stdout `cmd` redir to pipe */
11329
11330 if (flags & REDIR_PUSH) {
11331 sv = ckmalloc(sizeof (struct redirtab));
11332 for (i = 0 ; i < 10 ; i++)
11333 sv->renamed[i] = EMPTY;
11334 sv->next = redirlist;
11335 redirlist = sv;
11336 }
11337 for (n = redir ; n ; n = n->nfile.next) {
11338 fd = n->nfile.fd;
11339 try = 0;
11340 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11341 n->ndup.dupfd == fd)
11342 continue; /* redirect from/to same file descriptor */
11343
11344 INTOFF;
11345 newfd = openredirect(n);
11346 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
11347 if (newfd == fd) {
11348 try++;
11349 } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
11350 switch (errno) {
11351 case EBADF:
11352 if (!try) {
11353 dupredirect(n, newfd, fd1dup);
11354 try++;
11355 break;
11356 }
11357 /* FALLTHROUGH*/
11358 default:
11359 if (newfd >= 0) {
11360 close(newfd);
11361 }
11362 INTON;
11363 error("%d: %m", fd);
11364 /* NOTREACHED */
11365 }
11366 }
11367 if (!try) {
11368 close(fd);
11369 if (flags & REDIR_PUSH) {
11370 sv->renamed[fd] = i;
11371 }
11372 }
11373 } else if (fd != newfd) {
11374 close(fd);
11375 }
11376 if (fd == 0)
11377 fd0_redirected++;
11378 if (!try)
11379 dupredirect(n, newfd, fd1dup);
11380 INTON;
11381 }
11382}
11383
11384
11385static void
11386dupredirect(const union node *redir, int f, int fd1dup)
Eric Andersen2870d962001-07-02 17:27:21 +000011387{
Eric Andersencb57d552001-06-28 07:25:16 +000011388 int fd = redir->nfile.fd;
11389
Eric Andersen62483552001-07-10 06:09:16 +000011390 if(fd==1)
11391 fd1dup = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011392 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Eric Andersen2870d962001-07-02 17:27:21 +000011393 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
Eric Andersen62483552001-07-10 06:09:16 +000011394 if (redir->ndup.dupfd!=1 || fd1dup!=1)
Eric Andersencb57d552001-06-28 07:25:16 +000011395 dup_as_newfd(redir->ndup.dupfd, fd);
11396 }
11397 return;
11398 }
11399
11400 if (f != fd) {
11401 dup_as_newfd(f, fd);
11402 close(f);
11403 }
11404 return;
11405}
11406
11407
Eric Andersencb57d552001-06-28 07:25:16 +000011408
Eric Andersencb57d552001-06-28 07:25:16 +000011409/*
11410 * Undo the effects of the last redirection.
11411 */
11412
11413static void
Eric Andersen2870d962001-07-02 17:27:21 +000011414popredir(void)
11415{
Eric Andersencb57d552001-06-28 07:25:16 +000011416 struct redirtab *rp = redirlist;
11417 int i;
11418
11419 INTOFF;
11420 for (i = 0 ; i < 10 ; i++) {
11421 if (rp->renamed[i] != EMPTY) {
Eric Andersen2870d962001-07-02 17:27:21 +000011422 if (i == 0)
11423 fd0_redirected--;
Eric Andersencb57d552001-06-28 07:25:16 +000011424 close(i);
11425 if (rp->renamed[i] >= 0) {
11426 dup_as_newfd(rp->renamed[i], i);
11427 close(rp->renamed[i]);
11428 }
Eric Andersencb57d552001-06-28 07:25:16 +000011429 }
11430 }
11431 redirlist = rp->next;
11432 ckfree(rp);
11433 INTON;
11434}
11435
11436/*
Eric Andersencb57d552001-06-28 07:25:16 +000011437 * Discard all saved file descriptors.
11438 */
11439
11440static void
Eric Andersen2870d962001-07-02 17:27:21 +000011441clearredir(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000011442 struct redirtab *rp;
11443 int i;
11444
11445 for (rp = redirlist ; rp ; rp = rp->next) {
11446 for (i = 0 ; i < 10 ; i++) {
11447 if (rp->renamed[i] >= 0) {
11448 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011449 }
11450 rp->renamed[i] = EMPTY;
11451 }
11452 }
Eric Andersencb57d552001-06-28 07:25:16 +000011453}
11454
11455
Eric Andersencb57d552001-06-28 07:25:16 +000011456/*
11457 * Copy a file descriptor to be >= to. Returns -1
11458 * if the source file descriptor is closed, EMPTY if there are no unused
11459 * file descriptors left.
11460 */
11461
11462static int
11463dup_as_newfd(from, to)
11464 int from;
11465 int to;
11466{
11467 int newfd;
11468
11469 newfd = fcntl(from, F_DUPFD, to);
11470 if (newfd < 0) {
11471 if (errno == EMFILE)
11472 return EMPTY;
11473 else
Eric Andersen2870d962001-07-02 17:27:21 +000011474 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011475 }
11476 return newfd;
11477}
11478
Eric Andersencb57d552001-06-28 07:25:16 +000011479#ifdef DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +000011480static void shtree (union node *, int, char *, FILE*);
11481static void shcmd (union node *, FILE *);
11482static void sharg (union node *, FILE *);
11483static void indent (int, char *, FILE *);
11484static void trstring (char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011485
11486
11487static void
11488showtree(n)
11489 union node *n;
11490{
11491 trputs("showtree called\n");
11492 shtree(n, 1, NULL, stdout);
11493}
11494
11495
11496static void
11497shtree(n, ind, pfx, fp)
11498 union node *n;
11499 int ind;
11500 char *pfx;
11501 FILE *fp;
11502{
11503 struct nodelist *lp;
11504 const char *s;
11505
11506 if (n == NULL)
11507 return;
11508
11509 indent(ind, pfx, fp);
11510 switch(n->type) {
11511 case NSEMI:
11512 s = "; ";
11513 goto binop;
11514 case NAND:
11515 s = " && ";
11516 goto binop;
11517 case NOR:
11518 s = " || ";
11519binop:
11520 shtree(n->nbinary.ch1, ind, NULL, fp);
11521 /* if (ind < 0) */
11522 fputs(s, fp);
11523 shtree(n->nbinary.ch2, ind, NULL, fp);
11524 break;
11525 case NCMD:
11526 shcmd(n, fp);
11527 if (ind >= 0)
11528 putc('\n', fp);
11529 break;
11530 case NPIPE:
11531 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11532 shcmd(lp->n, fp);
11533 if (lp->next)
11534 fputs(" | ", fp);
11535 }
11536 if (n->npipe.backgnd)
11537 fputs(" &", fp);
11538 if (ind >= 0)
11539 putc('\n', fp);
11540 break;
11541 default:
11542 fprintf(fp, "<node type %d>", n->type);
11543 if (ind >= 0)
11544 putc('\n', fp);
11545 break;
11546 }
11547}
11548
11549
11550
11551static void
11552shcmd(cmd, fp)
11553 union node *cmd;
11554 FILE *fp;
11555{
11556 union node *np;
11557 int first;
11558 const char *s;
11559 int dftfd;
11560
11561 first = 1;
11562 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11563 if (! first)
11564 putchar(' ');
11565 sharg(np, fp);
11566 first = 0;
11567 }
11568 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11569 if (! first)
11570 putchar(' ');
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011571#if 1
11572 s = "*error*";
11573 dftfd = 0;
11574 if ((np->nfile.type <= NFROMFD) && (np->nfile.type >= NTO)) {
11575 s = redir_strings[np->nfile.type - NTO];
11576 if (*s == '>') {
11577 dftfd = 1;
11578 }
11579 }
11580#else
Eric Andersencb57d552001-06-28 07:25:16 +000011581 switch (np->nfile.type) {
Eric Andersen2870d962001-07-02 17:27:21 +000011582 case NTO: s = ">"; dftfd = 1; break;
11583 case NAPPEND: s = ">>"; dftfd = 1; break;
11584 case NTOFD: s = ">&"; dftfd = 1; break;
11585 case NTOOV: s = ">|"; dftfd = 1; break;
11586 case NFROM: s = "<"; dftfd = 0; break;
11587 case NFROMFD: s = "<&"; dftfd = 0; break;
11588 case NFROMTO: s = "<>"; dftfd = 0; break;
11589 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011590 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011591#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011592 if (np->nfile.fd != dftfd)
11593 fprintf(fp, "%d", np->nfile.fd);
11594 fputs(s, fp);
11595 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11596 fprintf(fp, "%d", np->ndup.dupfd);
11597 } else {
11598 sharg(np->nfile.fname, fp);
11599 }
11600 first = 0;
11601 }
11602}
11603
11604
11605
11606static void
11607sharg(arg, fp)
11608 union node *arg;
11609 FILE *fp;
11610 {
11611 char *p;
11612 struct nodelist *bqlist;
11613 int subtype;
11614
11615 if (arg->type != NARG) {
11616 printf("<node type %d>\n", arg->type);
11617 fflush(stdout);
11618 abort();
11619 }
11620 bqlist = arg->narg.backquote;
11621 for (p = arg->narg.text ; *p ; p++) {
11622 switch (*p) {
11623 case CTLESC:
11624 putc(*++p, fp);
11625 break;
11626 case CTLVAR:
11627 putc('$', fp);
11628 putc('{', fp);
11629 subtype = *++p;
11630 if (subtype == VSLENGTH)
11631 putc('#', fp);
11632
11633 while (*p != '=')
11634 putc(*p++, fp);
11635
11636 if (subtype & VSNUL)
11637 putc(':', fp);
11638
11639 switch (subtype & VSTYPE) {
11640 case VSNORMAL:
11641 putc('}', fp);
11642 break;
11643 case VSMINUS:
11644 putc('-', fp);
11645 break;
11646 case VSPLUS:
11647 putc('+', fp);
11648 break;
11649 case VSQUESTION:
11650 putc('?', fp);
11651 break;
11652 case VSASSIGN:
11653 putc('=', fp);
11654 break;
11655 case VSTRIMLEFT:
11656 putc('#', fp);
11657 break;
11658 case VSTRIMLEFTMAX:
11659 putc('#', fp);
11660 putc('#', fp);
11661 break;
11662 case VSTRIMRIGHT:
11663 putc('%', fp);
11664 break;
11665 case VSTRIMRIGHTMAX:
11666 putc('%', fp);
11667 putc('%', fp);
11668 break;
11669 case VSLENGTH:
11670 break;
11671 default:
11672 printf("<subtype %d>", subtype);
11673 }
11674 break;
11675 case CTLENDVAR:
11676 putc('}', fp);
11677 break;
11678 case CTLBACKQ:
11679 case CTLBACKQ|CTLQUOTE:
11680 putc('$', fp);
11681 putc('(', fp);
11682 shtree(bqlist->n, -1, NULL, fp);
11683 putc(')', fp);
11684 break;
11685 default:
11686 putc(*p, fp);
11687 break;
11688 }
11689 }
11690}
11691
11692
11693static void
11694indent(amount, pfx, fp)
11695 int amount;
11696 char *pfx;
11697 FILE *fp;
11698{
11699 int i;
11700
11701 for (i = 0 ; i < amount ; i++) {
11702 if (pfx && i == amount - 1)
11703 fputs(pfx, fp);
11704 putc('\t', fp);
11705 }
11706}
11707#endif
11708
11709
11710
11711/*
11712 * Debugging stuff.
11713 */
11714
11715
11716#ifdef DEBUG
11717FILE *tracefile;
11718
11719#if DEBUG == 2
11720static int debug = 1;
11721#else
11722static int debug = 0;
11723#endif
11724
11725
11726static void
11727trputc(c)
11728 int c;
11729{
11730 if (tracefile == NULL)
11731 return;
11732 putc(c, tracefile);
11733 if (c == '\n')
11734 fflush(tracefile);
11735}
11736
11737static void
11738trace(const char *fmt, ...)
11739{
11740 va_list va;
Eric Andersencb57d552001-06-28 07:25:16 +000011741 va_start(va, fmt);
Eric Andersencb57d552001-06-28 07:25:16 +000011742 if (tracefile != NULL) {
11743 (void) vfprintf(tracefile, fmt, va);
11744 if (strchr(fmt, '\n'))
11745 (void) fflush(tracefile);
11746 }
11747 va_end(va);
11748}
11749
11750
11751static void
11752trputs(s)
11753 const char *s;
11754{
11755 if (tracefile == NULL)
11756 return;
11757 fputs(s, tracefile);
11758 if (strchr(s, '\n'))
11759 fflush(tracefile);
11760}
11761
11762
11763static void
11764trstring(s)
11765 char *s;
11766{
11767 char *p;
11768 char c;
11769
11770 if (tracefile == NULL)
11771 return;
11772 putc('"', tracefile);
11773 for (p = s ; *p ; p++) {
11774 switch (*p) {
11775 case '\n': c = 'n'; goto backslash;
11776 case '\t': c = 't'; goto backslash;
11777 case '\r': c = 'r'; goto backslash;
11778 case '"': c = '"'; goto backslash;
11779 case '\\': c = '\\'; goto backslash;
11780 case CTLESC: c = 'e'; goto backslash;
11781 case CTLVAR: c = 'v'; goto backslash;
11782 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11783 case CTLBACKQ: c = 'q'; goto backslash;
11784 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
Eric Andersen2870d962001-07-02 17:27:21 +000011785backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011786 putc(c, tracefile);
11787 break;
11788 default:
11789 if (*p >= ' ' && *p <= '~')
11790 putc(*p, tracefile);
11791 else {
11792 putc('\\', tracefile);
11793 putc(*p >> 6 & 03, tracefile);
11794 putc(*p >> 3 & 07, tracefile);
11795 putc(*p & 07, tracefile);
11796 }
11797 break;
11798 }
11799 }
11800 putc('"', tracefile);
11801}
11802
11803
11804static void
11805trargs(ap)
11806 char **ap;
11807{
11808 if (tracefile == NULL)
11809 return;
11810 while (*ap) {
11811 trstring(*ap++);
11812 if (*ap)
11813 putc(' ', tracefile);
11814 else
11815 putc('\n', tracefile);
11816 }
11817 fflush(tracefile);
11818}
11819
11820
11821static void
11822opentrace() {
11823 char s[100];
11824#ifdef O_APPEND
11825 int flags;
11826#endif
11827
11828 if (!debug)
11829 return;
11830#ifdef not_this_way
11831 {
11832 char *p;
11833 if ((p = getenv("HOME")) == NULL) {
11834 if (geteuid() == 0)
11835 p = "/";
11836 else
11837 p = "/tmp";
11838 }
Eric Andersen2870d962001-07-02 17:27:21 +000011839 strcpy(s, p);
Eric Andersencb57d552001-06-28 07:25:16 +000011840 strcat(s, "/trace");
11841 }
11842#else
Eric Andersen2870d962001-07-02 17:27:21 +000011843 strcpy(s, "./trace");
Eric Andersencb57d552001-06-28 07:25:16 +000011844#endif /* not_this_way */
11845 if ((tracefile = fopen(s, "a")) == NULL) {
11846 fprintf(stderr, "Can't open %s\n", s);
11847 return;
11848 }
11849#ifdef O_APPEND
11850 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11851 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11852#endif
11853 fputs("\nTracing started.\n", tracefile);
11854 fflush(tracefile);
11855}
11856#endif /* DEBUG */
11857
11858
11859/*
Eric Andersencb57d552001-06-28 07:25:16 +000011860 * The trap builtin.
11861 */
11862
11863static int
11864trapcmd(argc, argv)
11865 int argc;
11866 char **argv;
11867{
11868 char *action;
11869 char **ap;
11870 int signo;
11871
11872 if (argc <= 1) {
11873 for (signo = 0 ; signo < NSIG ; signo++) {
11874 if (trap[signo] != NULL) {
11875 char *p;
Eric Andersen34506362001-08-02 05:02:46 +000011876 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011877
11878 p = single_quote(trap[signo]);
Eric Andersen34506362001-08-02 05:02:46 +000011879 sn = sys_siglist[signo];
11880 if(sn==NULL)
11881 sn = u_signal_names(0, &signo, 0);
11882 if(sn==NULL)
11883 sn = "???";
11884 printf("trap -- %s %s\n", p, sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011885 stunalloc(p);
11886 }
11887 }
11888 return 0;
11889 }
11890 ap = argv + 1;
11891 if (argc == 2)
11892 action = NULL;
11893 else
11894 action = *ap++;
11895 while (*ap) {
11896 if ((signo = decode_signal(*ap, 0)) < 0)
11897 error("%s: bad trap", *ap);
11898 INTOFF;
11899 if (action) {
11900 if (action[0] == '-' && action[1] == '\0')
11901 action = NULL;
11902 else
11903 action = savestr(action);
11904 }
11905 if (trap[signo])
11906 ckfree(trap[signo]);
11907 trap[signo] = action;
11908 if (signo != 0)
11909 setsignal(signo);
11910 INTON;
11911 ap++;
11912 }
11913 return 0;
11914}
11915
11916
11917
Eric Andersencb57d552001-06-28 07:25:16 +000011918
11919
11920
11921/*
11922 * Set the signal handler for the specified signal. The routine figures
11923 * out what it should be set to.
11924 */
11925
11926static void
Eric Andersen2870d962001-07-02 17:27:21 +000011927setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011928{
11929 int action;
11930 char *t;
11931 struct sigaction act;
11932
11933 if ((t = trap[signo]) == NULL)
11934 action = S_DFL;
11935 else if (*t != '\0')
11936 action = S_CATCH;
11937 else
11938 action = S_IGN;
11939 if (rootshell && action == S_DFL) {
11940 switch (signo) {
11941 case SIGINT:
11942 if (iflag || minusc || sflag == 0)
11943 action = S_CATCH;
11944 break;
11945 case SIGQUIT:
11946#ifdef DEBUG
11947 {
Eric Andersencb57d552001-06-28 07:25:16 +000011948
11949 if (debug)
11950 break;
11951 }
11952#endif
11953 /* FALLTHROUGH */
11954 case SIGTERM:
11955 if (iflag)
11956 action = S_IGN;
11957 break;
Eric Andersen2870d962001-07-02 17:27:21 +000011958#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000011959 case SIGTSTP:
11960 case SIGTTOU:
11961 if (mflag)
11962 action = S_IGN;
11963 break;
11964#endif
11965 }
11966 }
11967
11968 t = &sigmode[signo - 1];
11969 if (*t == 0) {
11970 /*
11971 * current setting unknown
11972 */
11973 if (sigaction(signo, 0, &act) == -1) {
11974 /*
11975 * Pretend it worked; maybe we should give a warning
11976 * here, but other shells don't. We don't alter
11977 * sigmode, so that we retry every time.
11978 */
11979 return;
11980 }
11981 if (act.sa_handler == SIG_IGN) {
11982 if (mflag && (signo == SIGTSTP ||
11983 signo == SIGTTIN || signo == SIGTTOU)) {
Eric Andersen2870d962001-07-02 17:27:21 +000011984 *t = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000011985 } else
11986 *t = S_HARD_IGN;
11987 } else {
Eric Andersen2870d962001-07-02 17:27:21 +000011988 *t = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000011989 }
11990 }
11991 if (*t == S_HARD_IGN || *t == action)
11992 return;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011993 act.sa_handler = ((action == S_CATCH) ? onsig
11994 : ((action == S_IGN) ? SIG_IGN : SIG_DFL));
Eric Andersencb57d552001-06-28 07:25:16 +000011995 *t = action;
11996 act.sa_flags = 0;
11997 sigemptyset(&act.sa_mask);
11998 sigaction(signo, &act, 0);
11999}
12000
12001/*
12002 * Ignore a signal.
12003 */
12004
12005static void
12006ignoresig(signo)
12007 int signo;
12008{
12009 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
12010 signal(signo, SIG_IGN);
12011 }
12012 sigmode[signo - 1] = S_HARD_IGN;
12013}
12014
12015
Eric Andersencb57d552001-06-28 07:25:16 +000012016/*
12017 * Signal handler.
12018 */
12019
12020static void
Eric Andersen2870d962001-07-02 17:27:21 +000012021onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000012022{
12023 if (signo == SIGINT && trap[SIGINT] == NULL) {
12024 onint();
12025 return;
12026 }
12027 gotsig[signo - 1] = 1;
12028 pendingsigs++;
12029}
12030
12031
Eric Andersencb57d552001-06-28 07:25:16 +000012032/*
12033 * Called to execute a trap. Perhaps we should avoid entering new trap
12034 * handlers while we are executing a trap handler.
12035 */
12036
12037static void
Eric Andersen2870d962001-07-02 17:27:21 +000012038dotrap(void)
12039{
Eric Andersencb57d552001-06-28 07:25:16 +000012040 int i;
12041 int savestatus;
12042
12043 for (;;) {
12044 for (i = 1 ; ; i++) {
12045 if (gotsig[i - 1])
12046 break;
12047 if (i >= NSIG - 1)
12048 goto done;
12049 }
12050 gotsig[i - 1] = 0;
12051 savestatus=exitstatus;
12052 evalstring(trap[i], 0);
12053 exitstatus=savestatus;
12054 }
12055done:
12056 pendingsigs = 0;
12057}
12058
Eric Andersencb57d552001-06-28 07:25:16 +000012059/*
12060 * Called to exit the shell.
12061 */
12062
12063static void
Eric Andersen2870d962001-07-02 17:27:21 +000012064exitshell(int status)
Eric Andersencb57d552001-06-28 07:25:16 +000012065{
12066 struct jmploc loc1, loc2;
12067 char *p;
12068
12069 TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
12070 if (setjmp(loc1.loc)) {
12071 goto l1;
12072 }
12073 if (setjmp(loc2.loc)) {
12074 goto l2;
12075 }
12076 handler = &loc1;
12077 if ((p = trap[0]) != NULL && *p != '\0') {
12078 trap[0] = NULL;
12079 evalstring(p, 0);
12080 }
Eric Andersen2870d962001-07-02 17:27:21 +000012081l1: handler = &loc2; /* probably unnecessary */
Eric Andersencb57d552001-06-28 07:25:16 +000012082 flushall();
Eric Andersen2870d962001-07-02 17:27:21 +000012083#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000012084 setjobctl(0);
12085#endif
12086l2: _exit(status);
12087 /* NOTREACHED */
12088}
12089
12090static int decode_signal(const char *string, int minsig)
12091{
12092 int signo;
Eric Andersen34506362001-08-02 05:02:46 +000012093 const char *name = u_signal_names(string, &signo, minsig);
Eric Andersencb57d552001-06-28 07:25:16 +000012094
Eric Andersen34506362001-08-02 05:02:46 +000012095 return name ? signo : -1;
Eric Andersencb57d552001-06-28 07:25:16 +000012096}
Eric Andersen34506362001-08-02 05:02:46 +000012097
Eric Andersen2870d962001-07-02 17:27:21 +000012098static struct var **hashvar (const char *);
12099static void showvars (const char *, int, int);
12100static struct var **findvar (struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000012101
12102/*
12103 * Initialize the varable symbol tables and import the environment
12104 */
12105
Eric Andersencb57d552001-06-28 07:25:16 +000012106/*
12107 * This routine initializes the builtin variables. It is called when the
12108 * shell is initialized and again when a shell procedure is spawned.
12109 */
12110
12111static void
12112initvar() {
12113 const struct varinit *ip;
12114 struct var *vp;
12115 struct var **vpp;
12116
12117 for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
12118 if ((vp->flags & VEXPORT) == 0) {
12119 vpp = hashvar(ip->text);
12120 vp->next = *vpp;
12121 *vpp = vp;
12122 vp->text = strdup(ip->text);
12123 vp->flags = ip->flags;
12124 vp->func = ip->func;
12125 }
12126 }
12127 /*
12128 * PS1 depends on uid
12129 */
12130 if ((vps1.flags & VEXPORT) == 0) {
12131 vpp = hashvar("PS1=");
12132 vps1.next = *vpp;
12133 *vpp = &vps1;
12134 vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# ");
12135 vps1.flags = VSTRFIXED|VTEXTFIXED;
12136 }
12137}
12138
12139/*
12140 * Set the value of a variable. The flags argument is ored with the
12141 * flags of the variable. If val is NULL, the variable is unset.
12142 */
12143
12144static void
12145setvar(name, val, flags)
12146 const char *name, *val;
12147 int flags;
12148{
12149 const char *p;
12150 int len;
12151 int namelen;
12152 char *nameeq;
12153 int isbad;
12154 int vallen = 0;
12155
12156 isbad = 0;
12157 p = name;
12158 if (! is_name(*p))
12159 isbad = 1;
12160 p++;
12161 for (;;) {
12162 if (! is_in_name(*p)) {
12163 if (*p == '\0' || *p == '=')
12164 break;
12165 isbad = 1;
12166 }
12167 p++;
12168 }
12169 namelen = p - name;
12170 if (isbad)
12171 error("%.*s: bad variable name", namelen, name);
Eric Andersen2870d962001-07-02 17:27:21 +000012172 len = namelen + 2; /* 2 is space for '=' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +000012173 if (val == NULL) {
12174 flags |= VUNSET;
12175 } else {
12176 len += vallen = strlen(val);
12177 }
12178 INTOFF;
12179 nameeq = ckmalloc(len);
12180 memcpy(nameeq, name, namelen);
12181 nameeq[namelen] = '=';
12182 if (val) {
12183 memcpy(nameeq + namelen + 1, val, vallen + 1);
12184 } else {
12185 nameeq[namelen + 1] = '\0';
12186 }
12187 setvareq(nameeq, flags);
12188 INTON;
12189}
12190
12191
12192
12193/*
12194 * Same as setvar except that the variable and value are passed in
12195 * the first argument as name=value. Since the first argument will
12196 * be actually stored in the table, it should not be a string that
12197 * will go away.
12198 */
12199
12200static void
12201setvareq(s, flags)
12202 char *s;
12203 int flags;
12204{
12205 struct var *vp, **vpp;
12206
12207 vpp = hashvar(s);
12208 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
12209 if ((vp = *findvar(vpp, s))) {
12210 if (vp->flags & VREADONLY) {
12211 size_t len = strchr(s, '=') - s;
12212 error("%.*s: is read only", len, s);
12213 }
12214 INTOFF;
12215
12216 if (vp->func && (flags & VNOFUNC) == 0)
12217 (*vp->func)(strchr(s, '=') + 1);
12218
12219 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12220 ckfree(vp->text);
12221
12222 vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
12223 vp->flags |= flags;
12224 vp->text = s;
12225
12226 /*
12227 * We could roll this to a function, to handle it as
12228 * a regular variable function callback, but why bother?
12229 */
12230 if (iflag && (vp == &vmpath || (vp == &vmail && !mpathset())))
12231 chkmail(1);
12232 INTON;
12233 return;
12234 }
12235 /* not found */
12236 vp = ckmalloc(sizeof (*vp));
12237 vp->flags = flags;
12238 vp->text = s;
12239 vp->next = *vpp;
12240 vp->func = NULL;
12241 *vpp = vp;
12242}
12243
12244
12245
12246/*
12247 * Process a linked list of variable assignments.
12248 */
12249
12250static void
12251listsetvar(mylist)
12252 struct strlist *mylist;
12253 {
12254 struct strlist *lp;
12255
12256 INTOFF;
12257 for (lp = mylist ; lp ; lp = lp->next) {
12258 setvareq(savestr(lp->text), 0);
12259 }
12260 INTON;
12261}
12262
12263
12264
12265/*
12266 * Find the value of a variable. Returns NULL if not set.
12267 */
12268
Eric Andersen62483552001-07-10 06:09:16 +000012269static const char *
Eric Andersencb57d552001-06-28 07:25:16 +000012270lookupvar(name)
12271 const char *name;
12272 {
12273 struct var *v;
12274
12275 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
12276 return strchr(v->text, '=') + 1;
12277 }
12278 return NULL;
12279}
12280
12281
12282
12283/*
12284 * Search the environment of a builtin command.
12285 */
12286
Eric Andersen62483552001-07-10 06:09:16 +000012287static const char *
12288bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012289{
Eric Andersen62483552001-07-10 06:09:16 +000012290 const struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012291
12292 for (sp = cmdenviron ; sp ; sp = sp->next) {
12293 if (varequal(sp->text, name))
12294 return strchr(sp->text, '=') + 1;
12295 }
12296 return lookupvar(name);
12297}
12298
12299
12300
12301/*
12302 * Generate a list of exported variables. This routine is used to construct
12303 * the third argument to execve when executing a program.
12304 */
12305
12306static char **
12307environment() {
12308 int nenv;
12309 struct var **vpp;
12310 struct var *vp;
12311 char **env;
12312 char **ep;
12313
12314 nenv = 0;
12315 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12316 for (vp = *vpp ; vp ; vp = vp->next)
12317 if (vp->flags & VEXPORT)
12318 nenv++;
12319 }
12320 ep = env = stalloc((nenv + 1) * sizeof *env);
12321 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12322 for (vp = *vpp ; vp ; vp = vp->next)
12323 if (vp->flags & VEXPORT)
12324 *ep++ = vp->text;
12325 }
12326 *ep = NULL;
12327 return env;
12328}
12329
12330
12331/*
12332 * Called when a shell procedure is invoked to clear out nonexported
12333 * variables. It is also necessary to reallocate variables of with
12334 * VSTACK set since these are currently allocated on the stack.
12335 */
12336
Eric Andersencb57d552001-06-28 07:25:16 +000012337static void
Eric Andersen2870d962001-07-02 17:27:21 +000012338shprocvar(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000012339 struct var **vpp;
12340 struct var *vp, **prev;
12341
12342 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12343 for (prev = vpp ; (vp = *prev) != NULL ; ) {
12344 if ((vp->flags & VEXPORT) == 0) {
12345 *prev = vp->next;
12346 if ((vp->flags & VTEXTFIXED) == 0)
12347 ckfree(vp->text);
12348 if ((vp->flags & VSTRFIXED) == 0)
12349 ckfree(vp);
12350 } else {
12351 if (vp->flags & VSTACK) {
12352 vp->text = savestr(vp->text);
12353 vp->flags &=~ VSTACK;
12354 }
12355 prev = &vp->next;
12356 }
12357 }
12358 }
12359 initvar();
12360}
12361
12362
12363
12364/*
12365 * Command to list all variables which are set. Currently this command
12366 * is invoked from the set command when the set command is called without
12367 * any variables.
12368 */
12369
12370static int
12371showvarscmd(argc, argv)
12372 int argc;
12373 char **argv;
12374{
12375 showvars(nullstr, VUNSET, VUNSET);
12376 return 0;
12377}
12378
12379
12380
12381/*
12382 * The export and readonly commands.
12383 */
12384
12385static int
12386exportcmd(argc, argv)
12387 int argc;
12388 char **argv;
12389{
12390 struct var *vp;
12391 char *name;
12392 const char *p;
12393 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12394 int pflag;
12395
12396 listsetvar(cmdenviron);
12397 pflag = (nextopt("p") == 'p');
12398 if (argc > 1 && !pflag) {
12399 while ((name = *argptr++) != NULL) {
12400 if ((p = strchr(name, '=')) != NULL) {
12401 p++;
12402 } else {
12403 if ((vp = *findvar(hashvar(name), name))) {
12404 vp->flags |= flag;
12405 goto found;
12406 }
12407 }
12408 setvar(name, p, flag);
12409found:;
12410 }
12411 } else {
12412 showvars(argv[0], flag, 0);
12413 }
12414 return 0;
12415}
12416
Eric Andersen34506362001-08-02 05:02:46 +000012417
Eric Andersencb57d552001-06-28 07:25:16 +000012418/*
12419 * The "local" command.
12420 */
12421
Eric Andersen2870d962001-07-02 17:27:21 +000012422/* funcnest nonzero if we are currently evaluating a function */
12423
Eric Andersencb57d552001-06-28 07:25:16 +000012424static int
12425localcmd(argc, argv)
12426 int argc;
12427 char **argv;
12428{
12429 char *name;
12430
Eric Andersen2870d962001-07-02 17:27:21 +000012431 if (! funcnest)
Eric Andersencb57d552001-06-28 07:25:16 +000012432 error("Not in a function");
12433 while ((name = *argptr++) != NULL) {
12434 mklocal(name);
12435 }
12436 return 0;
12437}
12438
12439
12440/*
12441 * Make a variable a local variable. When a variable is made local, it's
12442 * value and flags are saved in a localvar structure. The saved values
12443 * will be restored when the shell function returns. We handle the name
12444 * "-" as a special case.
12445 */
12446
12447static void
12448mklocal(name)
12449 char *name;
12450 {
12451 struct localvar *lvp;
12452 struct var **vpp;
12453 struct var *vp;
12454
12455 INTOFF;
12456 lvp = ckmalloc(sizeof (struct localvar));
12457 if (name[0] == '-' && name[1] == '\0') {
12458 char *p;
Eric Andersen2870d962001-07-02 17:27:21 +000012459 p = ckmalloc(sizeof optet_vals);
12460 lvp->text = memcpy(p, optet_vals, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000012461 vp = NULL;
12462 } else {
12463 vpp = hashvar(name);
12464 vp = *findvar(vpp, name);
12465 if (vp == NULL) {
12466 if (strchr(name, '='))
12467 setvareq(savestr(name), VSTRFIXED);
12468 else
12469 setvar(name, NULL, VSTRFIXED);
Eric Andersen2870d962001-07-02 17:27:21 +000012470 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012471 lvp->text = NULL;
12472 lvp->flags = VUNSET;
12473 } else {
12474 lvp->text = vp->text;
12475 lvp->flags = vp->flags;
12476 vp->flags |= VSTRFIXED|VTEXTFIXED;
12477 if (strchr(name, '='))
12478 setvareq(savestr(name), 0);
12479 }
12480 }
12481 lvp->vp = vp;
12482 lvp->next = localvars;
12483 localvars = lvp;
12484 INTON;
12485}
12486
12487
12488/*
12489 * Called after a function returns.
12490 */
12491
12492static void
12493poplocalvars() {
12494 struct localvar *lvp;
12495 struct var *vp;
12496
12497 while ((lvp = localvars) != NULL) {
12498 localvars = lvp->next;
12499 vp = lvp->vp;
Eric Andersen2870d962001-07-02 17:27:21 +000012500 if (vp == NULL) { /* $- saved */
12501 memcpy(optet_vals, lvp->text, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000012502 ckfree(lvp->text);
12503 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12504 (void)unsetvar(vp->text);
12505 } else {
12506 if ((vp->flags & VTEXTFIXED) == 0)
12507 ckfree(vp->text);
12508 vp->flags = lvp->flags;
12509 vp->text = lvp->text;
12510 }
12511 ckfree(lvp);
12512 }
12513}
12514
12515
12516static int
12517setvarcmd(argc, argv)
12518 int argc;
12519 char **argv;
12520{
12521 if (argc <= 2)
12522 return unsetcmd(argc, argv);
12523 else if (argc == 3)
12524 setvar(argv[1], argv[2], 0);
12525 else
12526 error("List assignment not implemented");
12527 return 0;
12528}
12529
12530
12531/*
12532 * The unset builtin command. We unset the function before we unset the
12533 * variable to allow a function to be unset when there is a readonly variable
12534 * with the same name.
12535 */
12536
12537static int
12538unsetcmd(argc, argv)
12539 int argc;
12540 char **argv;
12541{
12542 char **ap;
12543 int i;
12544 int flg_func = 0;
12545 int flg_var = 0;
12546 int ret = 0;
12547
12548 while ((i = nextopt("vf")) != '\0') {
12549 if (i == 'f')
12550 flg_func = 1;
12551 else
12552 flg_var = 1;
12553 }
12554 if (flg_func == 0 && flg_var == 0)
12555 flg_var = 1;
12556
12557 for (ap = argptr; *ap ; ap++) {
12558 if (flg_func)
12559 unsetfunc(*ap);
12560 if (flg_var)
12561 ret |= unsetvar(*ap);
12562 }
12563 return ret;
12564}
12565
12566
12567/*
12568 * Unset the specified variable.
12569 */
12570
12571static int
Eric Andersen62483552001-07-10 06:09:16 +000012572unsetvar(const char *s)
12573{
Eric Andersencb57d552001-06-28 07:25:16 +000012574 struct var **vpp;
12575 struct var *vp;
12576
12577 vpp = findvar(hashvar(s), s);
12578 vp = *vpp;
12579 if (vp) {
12580 if (vp->flags & VREADONLY)
12581 return (1);
12582 INTOFF;
12583 if (*(strchr(vp->text, '=') + 1) != '\0')
12584 setvar(s, nullstr, 0);
12585 vp->flags &= ~VEXPORT;
12586 vp->flags |= VUNSET;
12587 if ((vp->flags & VSTRFIXED) == 0) {
12588 if ((vp->flags & VTEXTFIXED) == 0)
12589 ckfree(vp->text);
12590 *vpp = vp->next;
12591 ckfree(vp);
12592 }
12593 INTON;
12594 return (0);
12595 }
12596
12597 return (0);
12598}
12599
12600
12601
12602/*
12603 * Find the appropriate entry in the hash table from the name.
12604 */
12605
12606static struct var **
Eric Andersen62483552001-07-10 06:09:16 +000012607hashvar(const char *p)
12608{
Eric Andersencb57d552001-06-28 07:25:16 +000012609 unsigned int hashval;
12610
12611 hashval = ((unsigned char) *p) << 4;
12612 while (*p && *p != '=')
12613 hashval += (unsigned char) *p++;
12614 return &vartab[hashval % VTABSIZE];
12615}
12616
12617
12618
12619/*
12620 * Returns true if the two strings specify the same varable. The first
12621 * variable name is terminated by '='; the second may be terminated by
12622 * either '=' or '\0'.
12623 */
12624
12625static int
Eric Andersen62483552001-07-10 06:09:16 +000012626varequal(const char *p, const char *q)
12627{
Eric Andersencb57d552001-06-28 07:25:16 +000012628 while (*p == *q++) {
12629 if (*p++ == '=')
12630 return 1;
12631 }
12632 if (*p == '=' && *(q - 1) == '\0')
12633 return 1;
12634 return 0;
12635}
12636
12637static void
12638showvars(const char *myprefix, int mask, int xor)
12639{
12640 struct var **vpp;
12641 struct var *vp;
12642 const char *sep = myprefix == nullstr ? myprefix : spcstr;
12643
12644 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12645 for (vp = *vpp ; vp ; vp = vp->next) {
12646 if ((vp->flags & mask) ^ xor) {
12647 char *p;
12648 int len;
12649
12650 p = strchr(vp->text, '=') + 1;
12651 len = p - vp->text;
12652 p = single_quote(p);
12653
Eric Andersen62483552001-07-10 06:09:16 +000012654 printf("%s%s%.*s%s\n", myprefix, sep, len,
12655 vp->text, p);
Eric Andersencb57d552001-06-28 07:25:16 +000012656 stunalloc(p);
12657 }
12658 }
12659 }
12660}
12661
12662static struct var **
12663findvar(struct var **vpp, const char *name)
12664{
12665 for (; *vpp; vpp = &(*vpp)->next) {
12666 if (varequal((*vpp)->text, name)) {
12667 break;
12668 }
12669 }
12670 return vpp;
12671}
12672
12673/*
12674 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
12675 * This file contains code for the times builtin.
Manuel Novoa III c639a352001-08-12 17:32:56 +000012676 * $Id: ash.c,v 1.22 2001/08/12 17:32:56 mjn3 Exp $
Eric Andersencb57d552001-06-28 07:25:16 +000012677 */
12678static int timescmd (int argc, char **argv)
12679{
12680 struct tms buf;
12681 long int clk_tck = sysconf(_SC_CLK_TCK);
12682
12683 times(&buf);
12684 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
12685 (int) (buf.tms_utime / clk_tck / 60),
12686 ((double) buf.tms_utime) / clk_tck,
12687 (int) (buf.tms_stime / clk_tck / 60),
12688 ((double) buf.tms_stime) / clk_tck,
12689 (int) (buf.tms_cutime / clk_tck / 60),
12690 ((double) buf.tms_cutime) / clk_tck,
12691 (int) (buf.tms_cstime / clk_tck / 60),
12692 ((double) buf.tms_cstime) / clk_tck);
12693 return 0;
12694}
12695
Eric Andersen74bcd162001-07-30 21:41:37 +000012696#ifdef ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012697/* The let builtin. */
12698int letcmd(int argc, char **argv)
Eric Andersen74bcd162001-07-30 21:41:37 +000012699{
Eric Andersen34506362001-08-02 05:02:46 +000012700 int errcode;
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012701 long result=0;
12702 if (argc == 2) {
12703 char *tmp, *expression, p[13];
12704 expression = strchr(argv[1], '=');
12705 if (!expression) {
Eric Andersen34506362001-08-02 05:02:46 +000012706 /* Cannot use 'error()' here, or the return code
12707 * will be incorrect */
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012708 out2fmt("sh: let: syntax error: \"%s\"\n", argv[1]);
12709 return 0;
Eric Andersen74bcd162001-07-30 21:41:37 +000012710 }
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012711 *expression = '\0';
12712 tmp = ++expression;
Eric Andersen34506362001-08-02 05:02:46 +000012713 result = arith(tmp, &errcode);
12714 if (errcode < 0) {
12715 /* Cannot use 'error()' here, or the return code
12716 * will be incorrect */
12717 out2fmt("sh: let: ");
12718 if(errcode == -2)
12719 out2fmt("divide by zero");
12720 else
12721 out2fmt("syntax error: \"%s=%s\"\n", argv[1], expression);
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012722 return 0;
12723 }
12724 snprintf(p, 12, "%ld", result);
12725 setvar(argv[1], savestr(p), 0);
12726 } else if (argc >= 3)
12727 synerror("invalid operand");
12728 return !result;
Eric Andersen74bcd162001-07-30 21:41:37 +000012729}
12730#endif
12731
12732
12733
Eric Andersendf82f612001-06-28 07:46:40 +000012734/*-
12735 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000012736 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000012737 *
12738 * This code is derived from software contributed to Berkeley by
12739 * Kenneth Almquist.
12740 *
12741 * Redistribution and use in source and binary forms, with or without
12742 * modification, are permitted provided that the following conditions
12743 * are met:
12744 * 1. Redistributions of source code must retain the above copyright
12745 * notice, this list of conditions and the following disclaimer.
12746 * 2. Redistributions in binary form must reproduce the above copyright
12747 * notice, this list of conditions and the following disclaimer in the
12748 * documentation and/or other materials provided with the distribution.
12749 *
Eric Andersen2870d962001-07-02 17:27:21 +000012750 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
12751 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000012752 *
12753 * 4. Neither the name of the University nor the names of its contributors
12754 * may be used to endorse or promote products derived from this software
12755 * without specific prior written permission.
12756 *
12757 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
12758 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
12759 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
12760 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
12761 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
12762 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
12763 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
12764 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
12765 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
12766 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
12767 * SUCH DAMAGE.
12768 */