blob: 417ef5d13befebd20f449aafb78553ca8b32cd21 [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
Eric Andersen80dd0862001-08-10 18:42:04 +0000688#define outstr(p,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)]);
7450 } else if (*p & CMDTXT_CHARPTR) { /* output dynamic string */
7451 cmdputs(((const char *) n) + ((int)(*p & CMDTXT_OFFSETMASK)));
7452 } else { /* output field */
7453 cmdtxt((const union node *)
7454 (((const char *) n) + ((int)(*p & CMDTXT_OFFSETMASK))));
7455 }
7456 } while (!(*p++ & CMDTXT_NOMORE));
7457 } else if (n->type == NCMD) {
7458 union node *np;
7459 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7460 cmdtxt(np);
7461 if (np->narg.next)
7462 cmdputs(spcstr);
7463 }
7464 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7465 cmdputs(spcstr);
7466 cmdtxt(np);
7467 }
7468 } else if (n->type == NPIPE) {
7469 struct nodelist *lp;
7470 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7471 cmdtxt(lp->n);
7472 if (lp->next)
7473 cmdputs(" | ");
7474 }
7475 } else if (n->type == NCASE) {
7476 cmdputs(cmdtxt_strings[14]);
7477 cmdputs(n->ncase.expr->narg.text);
7478 cmdputs(cmdtxt_strings[13]);
7479 } else {
7480#if (NTO != 16) || (NFROM != 17) || (NFROMTO != 18) || (NAPPEND != 19) || (NTOOV != 20) || (NTOFD != 21) || (NFROMFD != 22)
7481#error Assumption violated regarding range and ordering of NTO ... NFROMFD!
7482#endif
7483 char s[2];
7484
7485#ifdef DEBUG
7486 assert((n->type >= NTO) && (n->type <= NFROMFD));
7487#endif
7488
7489 p = redir_strings[n->type - NTO];
7490 if (n->nfile.fd != ('>' == *p)) {
7491 s[0] = n->nfile.fd + '0';
7492 s[1] = '\0';
7493 cmdputs(s);
7494 }
7495 cmdputs(p);
7496 if (n->type >= NTOFD) {
7497 s[0] = n->ndup.dupfd + '0';
7498 s[1] = '\0';
7499 cmdputs(s);
7500 } else {
7501 cmdtxt(n->nfile.fname);
7502 }
7503 }
7504}
7505#else /* CMDTXT_TABLE */
Eric Andersencb57d552001-06-28 07:25:16 +00007506static void
Eric Andersen2870d962001-07-02 17:27:21 +00007507cmdtxt(const union node *n)
7508{
Eric Andersencb57d552001-06-28 07:25:16 +00007509 union node *np;
7510 struct nodelist *lp;
7511 const char *p;
7512 int i;
7513 char s[2];
7514
7515 if (n == NULL)
7516 return;
7517 switch (n->type) {
7518 case NSEMI:
7519 cmdtxt(n->nbinary.ch1);
7520 cmdputs("; ");
7521 cmdtxt(n->nbinary.ch2);
7522 break;
7523 case NAND:
7524 cmdtxt(n->nbinary.ch1);
7525 cmdputs(" && ");
7526 cmdtxt(n->nbinary.ch2);
7527 break;
7528 case NOR:
7529 cmdtxt(n->nbinary.ch1);
7530 cmdputs(" || ");
7531 cmdtxt(n->nbinary.ch2);
7532 break;
7533 case NPIPE:
7534 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7535 cmdtxt(lp->n);
7536 if (lp->next)
7537 cmdputs(" | ");
7538 }
7539 break;
7540 case NSUBSHELL:
7541 cmdputs("(");
7542 cmdtxt(n->nredir.n);
7543 cmdputs(")");
7544 break;
7545 case NREDIR:
7546 case NBACKGND:
7547 cmdtxt(n->nredir.n);
7548 break;
7549 case NIF:
7550 cmdputs("if ");
7551 cmdtxt(n->nif.test);
7552 cmdputs("; then ");
7553 cmdtxt(n->nif.ifpart);
7554 cmdputs("...");
7555 break;
7556 case NWHILE:
7557 cmdputs("while ");
7558 goto until;
7559 case NUNTIL:
7560 cmdputs("until ");
7561until:
7562 cmdtxt(n->nbinary.ch1);
7563 cmdputs("; do ");
7564 cmdtxt(n->nbinary.ch2);
7565 cmdputs("; done");
7566 break;
7567 case NFOR:
7568 cmdputs("for ");
7569 cmdputs(n->nfor.var);
7570 cmdputs(" in ...");
7571 break;
7572 case NCASE:
7573 cmdputs("case ");
7574 cmdputs(n->ncase.expr->narg.text);
7575 cmdputs(" in ...");
7576 break;
7577 case NDEFUN:
7578 cmdputs(n->narg.text);
7579 cmdputs("() ...");
7580 break;
7581 case NCMD:
7582 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7583 cmdtxt(np);
7584 if (np->narg.next)
7585 cmdputs(spcstr);
7586 }
7587 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7588 cmdputs(spcstr);
7589 cmdtxt(np);
7590 }
7591 break;
7592 case NARG:
7593 cmdputs(n->narg.text);
7594 break;
7595 case NTO:
7596 p = ">"; i = 1; goto redir;
7597 case NAPPEND:
7598 p = ">>"; i = 1; goto redir;
7599 case NTOFD:
7600 p = ">&"; i = 1; goto redir;
7601 case NTOOV:
7602 p = ">|"; i = 1; goto redir;
7603 case NFROM:
7604 p = "<"; i = 0; goto redir;
7605 case NFROMFD:
7606 p = "<&"; i = 0; goto redir;
7607 case NFROMTO:
7608 p = "<>"; i = 0; goto redir;
7609redir:
7610 if (n->nfile.fd != i) {
7611 s[0] = n->nfile.fd + '0';
7612 s[1] = '\0';
7613 cmdputs(s);
7614 }
7615 cmdputs(p);
7616 if (n->type == NTOFD || n->type == NFROMFD) {
7617 s[0] = n->ndup.dupfd + '0';
7618 s[1] = '\0';
7619 cmdputs(s);
7620 } else {
7621 cmdtxt(n->nfile.fname);
7622 }
7623 break;
7624 case NHERE:
7625 case NXHERE:
7626 cmdputs("<<...");
7627 break;
7628 default:
7629 cmdputs("???");
7630 break;
7631 }
7632}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007633#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007634
Eric Andersen2870d962001-07-02 17:27:21 +00007635static char *
7636commandtext(const union node *n)
7637{
7638 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007639
Eric Andersen2870d962001-07-02 17:27:21 +00007640 cmdnextc = name = ckmalloc(MAXCMDTEXT);
7641 cmdnleft = MAXCMDTEXT - 4;
7642 cmdtxt(n);
7643 *cmdnextc = '\0';
7644 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00007645}
7646
Eric Andersen2870d962001-07-02 17:27:21 +00007647
Eric Andersencb57d552001-06-28 07:25:16 +00007648static void waitonint(int sig) {
7649 intreceived = 1;
7650 return;
7651}
Eric Andersencb57d552001-06-28 07:25:16 +00007652/*
7653 * Routines to check for mail. (Perhaps make part of main.c?)
7654 */
7655
7656
7657#define MAXMBOXES 10
7658
7659
Eric Andersen2870d962001-07-02 17:27:21 +00007660static int nmboxes; /* number of mailboxes */
7661static time_t mailtime[MAXMBOXES]; /* times of mailboxes */
Eric Andersencb57d552001-06-28 07:25:16 +00007662
7663
7664
7665/*
7666 * Print appropriate message(s) if mail has arrived. If the argument is
7667 * nozero, then the value of MAIL has changed, so we just update the
7668 * values.
7669 */
7670
7671static void
Eric Andersen2870d962001-07-02 17:27:21 +00007672chkmail(int silent)
Eric Andersencb57d552001-06-28 07:25:16 +00007673{
7674 int i;
7675 const char *mpath;
7676 char *p;
7677 char *q;
7678 struct stackmark smark;
7679 struct stat statb;
7680
7681 if (silent)
7682 nmboxes = 10;
7683 if (nmboxes == 0)
7684 return;
7685 setstackmark(&smark);
7686 mpath = mpathset()? mpathval() : mailval();
7687 for (i = 0 ; i < nmboxes ; i++) {
7688 p = padvance(&mpath, nullstr);
7689 if (p == NULL)
7690 break;
7691 if (*p == '\0')
7692 continue;
7693 for (q = p ; *q ; q++);
7694#ifdef DEBUG
7695 if (q[-1] != '/')
7696 abort();
7697#endif
Eric Andersen2870d962001-07-02 17:27:21 +00007698 q[-1] = '\0'; /* delete trailing '/' */
Eric Andersencb57d552001-06-28 07:25:16 +00007699 if (stat(p, &statb) < 0)
7700 statb.st_size = 0;
7701 if (statb.st_size > mailtime[i] && ! silent) {
Eric Andersen3102ac42001-07-06 04:26:23 +00007702 out2fmt(snlfmt,
7703 pathopt? pathopt : "you have mail");
Eric Andersencb57d552001-06-28 07:25:16 +00007704 }
7705 mailtime[i] = statb.st_size;
Eric Andersencb57d552001-06-28 07:25:16 +00007706 }
7707 nmboxes = i;
7708 popstackmark(&smark);
7709}
Eric Andersencb57d552001-06-28 07:25:16 +00007710
7711#define PROFILE 0
7712
Eric Andersencb57d552001-06-28 07:25:16 +00007713#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007714static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007715extern int etext();
7716#endif
7717
Eric Andersen2870d962001-07-02 17:27:21 +00007718static void read_profile (const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007719static void cmdloop (int);
7720static void options (int);
Eric Andersen2870d962001-07-02 17:27:21 +00007721static void setoption (int, int);
7722static void procargs (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00007723
Eric Andersen2870d962001-07-02 17:27:21 +00007724
Eric Andersencb57d552001-06-28 07:25:16 +00007725/*
7726 * Main routine. We initialize things, parse the arguments, execute
7727 * profiles if we're a login shell, and then call cmdloop to execute
7728 * commands. The setjmp call sets up the location to jump to when an
7729 * exception occurs. When an exception occurs the variable "state"
7730 * is used to figure out how far we had gotten.
7731 */
7732
7733int
Matt Kraai2d91deb2001-08-01 17:21:35 +00007734ash_main(argc, argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007735 int argc;
7736 char **argv;
7737{
7738 struct jmploc jmploc;
7739 struct stackmark smark;
7740 volatile int state;
Eric Andersen62483552001-07-10 06:09:16 +00007741 const char *shinit;
Eric Andersencb57d552001-06-28 07:25:16 +00007742
Eric Andersencb57d552001-06-28 07:25:16 +00007743 BLTINCMD = find_builtin("builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00007744 EXECCMD = find_builtin("exec");
7745 EVALCMD = find_builtin("eval");
7746
Eric Andersen1c039232001-07-07 00:05:55 +00007747#ifndef BB_FEATURE_SH_FANCY_PROMPT
7748 unsetenv("PS1");
7749 unsetenv("PS2");
7750#endif
7751
Eric Andersencb57d552001-06-28 07:25:16 +00007752#if PROFILE
7753 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7754#endif
7755#if defined(linux) || defined(__GNU__)
7756 signal(SIGCHLD, SIG_DFL);
7757#endif
7758 state = 0;
7759 if (setjmp(jmploc.loc)) {
7760 INTOFF;
7761 /*
7762 * When a shell procedure is executed, we raise the
7763 * exception EXSHELLPROC to clean up before executing
7764 * the shell procedure.
7765 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007766 if (exception == EXSHELLPROC) {
Eric Andersencb57d552001-06-28 07:25:16 +00007767 rootpid = getpid();
7768 rootshell = 1;
7769 minusc = NULL;
7770 state = 3;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007771 } else {
7772 if (exception == EXEXEC) {
7773 exitstatus = exerrno;
7774 } else if (exception == EXERROR) {
7775 exitstatus = 2;
7776 }
Eric Andersencb57d552001-06-28 07:25:16 +00007777 if (state == 0 || iflag == 0 || ! rootshell)
7778 exitshell(exitstatus);
7779 }
7780 reset();
Eric Andersen2870d962001-07-02 17:27:21 +00007781 if (exception == EXINT) {
Eric Andersencb57d552001-06-28 07:25:16 +00007782 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00007783 }
7784 popstackmark(&smark);
Eric Andersen2870d962001-07-02 17:27:21 +00007785 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007786 if (state == 1)
7787 goto state1;
7788 else if (state == 2)
7789 goto state2;
7790 else if (state == 3)
7791 goto state3;
7792 else
7793 goto state4;
7794 }
7795 handler = &jmploc;
7796#ifdef DEBUG
7797 opentrace();
7798 trputs("Shell args: "); trargs(argv);
7799#endif
7800 rootpid = getpid();
7801 rootshell = 1;
7802 init();
7803 setstackmark(&smark);
7804 procargs(argc, argv);
7805 if (argv[0] && argv[0][0] == '-') {
7806 state = 1;
7807 read_profile("/etc/profile");
7808state1:
7809 state = 2;
7810 read_profile(".profile");
7811 }
7812state2:
7813 state = 3;
7814#ifndef linux
7815 if (getuid() == geteuid() && getgid() == getegid()) {
7816#endif
7817 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7818 state = 3;
7819 read_profile(shinit);
7820 }
7821#ifndef linux
7822 }
7823#endif
7824state3:
7825 state = 4;
7826 if (sflag == 0 || minusc) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007827 static const char sigs[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00007828 SIGINT, SIGQUIT, SIGHUP,
Eric Andersencb57d552001-06-28 07:25:16 +00007829#ifdef SIGTSTP
7830 SIGTSTP,
7831#endif
7832 SIGPIPE
7833 };
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007834#define SIGSSIZE ((sizeof(sigs)/sizeof(sigs[0])) - 1) /* trailing nul */
Eric Andersencb57d552001-06-28 07:25:16 +00007835 int i;
7836
7837 for (i = 0; i < SIGSSIZE; i++)
7838 setsignal(sigs[i]);
7839 }
7840
7841 if (minusc)
7842 evalstring(minusc, 0);
7843
7844 if (sflag || minusc == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00007845state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007846 cmdloop(1);
7847 }
7848#if PROFILE
7849 monitor(0);
7850#endif
7851 exitshell(exitstatus);
7852 /* NOTREACHED */
7853}
7854
7855
7856/*
7857 * Read and execute commands. "Top" is nonzero for the top level command
7858 * loop; it turns on prompting if the shell is interactive.
7859 */
7860
7861static void
Eric Andersen2870d962001-07-02 17:27:21 +00007862cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00007863{
7864 union node *n;
7865 struct stackmark smark;
7866 int inter;
7867 int numeof = 0;
7868
7869 TRACE(("cmdloop(%d) called\n", top));
7870 setstackmark(&smark);
7871 for (;;) {
7872 if (pendingsigs)
7873 dotrap();
7874 inter = 0;
7875 if (iflag && top) {
7876 inter++;
7877 showjobs(1);
7878 chkmail(0);
Eric Andersen3102ac42001-07-06 04:26:23 +00007879 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00007880 }
7881 n = parsecmd(inter);
7882 /* showtree(n); DEBUG */
7883 if (n == NEOF) {
7884 if (!top || numeof >= 50)
7885 break;
7886 if (!stoppedjobs()) {
7887 if (!Iflag)
7888 break;
7889 out2str("\nUse \"exit\" to leave shell.\n");
7890 }
7891 numeof++;
7892 } else if (n != NULL && nflag == 0) {
7893 job_warning = (job_warning == 2) ? 1 : 0;
7894 numeof = 0;
7895 evaltree(n, 0);
7896 }
7897 popstackmark(&smark);
7898 setstackmark(&smark);
7899 if (evalskip == SKIPFILE) {
7900 evalskip = 0;
7901 break;
7902 }
7903 }
7904 popstackmark(&smark);
7905}
7906
7907
7908
7909/*
7910 * Read /etc/profile or .profile. Return on error.
7911 */
7912
7913static void
7914read_profile(name)
7915 const char *name;
7916{
7917 int fd;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007918 int xflag_save;
7919 int vflag_save;
Eric Andersencb57d552001-06-28 07:25:16 +00007920
7921 INTOFF;
7922 if ((fd = open(name, O_RDONLY)) >= 0)
7923 setinputfd(fd, 1);
7924 INTON;
7925 if (fd < 0)
7926 return;
7927 /* -q turns off -x and -v just when executing init files */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007928 /* Note: Might do a little redundant work, but reduces code size. */
7929 xflag_save = xflag;
7930 vflag_save = vflag;
Eric Andersencb57d552001-06-28 07:25:16 +00007931 if (qflag) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007932 vflag = xflag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007933 }
7934 cmdloop(0);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007935 xflag = xflag_save;
7936 vflag = vflag_save;
Eric Andersencb57d552001-06-28 07:25:16 +00007937 popfile();
7938}
7939
7940
7941
7942/*
7943 * Read a file containing shell functions.
7944 */
7945
7946static void
Eric Andersen2870d962001-07-02 17:27:21 +00007947readcmdfile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00007948{
7949 int fd;
7950
7951 INTOFF;
7952 if ((fd = open(name, O_RDONLY)) >= 0)
7953 setinputfd(fd, 1);
7954 else
7955 error("Can't open %s", name);
7956 INTON;
7957 cmdloop(0);
7958 popfile();
7959}
7960
7961
7962
7963/*
7964 * Take commands from a file. To be compatable we should do a path
7965 * search for the file, which is necessary to find sub-commands.
7966 */
7967
7968
Eric Andersen62483552001-07-10 06:09:16 +00007969static inline char *
Eric Andersencb57d552001-06-28 07:25:16 +00007970find_dot_file(mybasename)
7971 char *mybasename;
7972{
7973 char *fullname;
7974 const char *path = pathval();
7975 struct stat statb;
7976
7977 /* don't try this for absolute or relative paths */
7978 if (strchr(mybasename, '/'))
7979 return mybasename;
7980
7981 while ((fullname = padvance(&path, mybasename)) != NULL) {
7982 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
7983 /*
7984 * Don't bother freeing here, since it will
7985 * be freed by the caller.
7986 */
7987 return fullname;
7988 }
7989 stunalloc(fullname);
7990 }
7991
7992 /* not found in the PATH */
7993 error("%s: not found", mybasename);
7994 /* NOTREACHED */
7995}
7996
7997static int
7998dotcmd(argc, argv)
7999 int argc;
8000 char **argv;
8001{
8002 struct strlist *sp;
8003 exitstatus = 0;
8004
8005 for (sp = cmdenviron; sp ; sp = sp->next)
8006 setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
8007
Eric Andersen2870d962001-07-02 17:27:21 +00008008 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00008009 char *fullname;
8010 struct stackmark smark;
8011
8012 setstackmark(&smark);
8013 fullname = find_dot_file(argv[1]);
8014 setinputfile(fullname, 1);
8015 commandname = fullname;
8016 cmdloop(0);
8017 popfile();
8018 popstackmark(&smark);
8019 }
8020 return exitstatus;
8021}
8022
8023
8024static int
8025exitcmd(argc, argv)
8026 int argc;
8027 char **argv;
8028{
8029 if (stoppedjobs())
8030 return 0;
8031 if (argc > 1)
8032 exitstatus = number(argv[1]);
8033 else
8034 exitstatus = oexitstatus;
8035 exitshell(exitstatus);
8036 /* NOTREACHED */
8037}
Eric Andersen62483552001-07-10 06:09:16 +00008038
Eric Andersen2870d962001-07-02 17:27:21 +00008039static pointer
8040stalloc(int nbytes)
Eric Andersencb57d552001-06-28 07:25:16 +00008041{
8042 char *p;
8043
8044 nbytes = ALIGN(nbytes);
8045 if (nbytes > stacknleft) {
8046 int blocksize;
8047 struct stack_block *sp;
8048
8049 blocksize = nbytes;
8050 if (blocksize < MINSIZE)
8051 blocksize = MINSIZE;
8052 INTOFF;
8053 sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
8054 sp->prev = stackp;
8055 stacknxt = sp->space;
8056 stacknleft = blocksize;
8057 stackp = sp;
8058 INTON;
8059 }
8060 p = stacknxt;
8061 stacknxt += nbytes;
8062 stacknleft -= nbytes;
8063 return p;
8064}
8065
8066
8067static void
Eric Andersen2870d962001-07-02 17:27:21 +00008068stunalloc(pointer p)
8069{
Eric Andersencb57d552001-06-28 07:25:16 +00008070#ifdef DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +00008071 if (p == NULL) { /*DEBUG */
Eric Andersencb57d552001-06-28 07:25:16 +00008072 write(2, "stunalloc\n", 10);
8073 abort();
8074 }
8075#endif
8076 if (!(stacknxt >= (char *)p && (char *)p >= stackp->space)) {
8077 p = stackp->space;
8078 }
8079 stacknleft += stacknxt - (char *)p;
8080 stacknxt = p;
8081}
8082
8083
Eric Andersencb57d552001-06-28 07:25:16 +00008084static void
Eric Andersen2870d962001-07-02 17:27:21 +00008085setstackmark(struct stackmark *mark)
8086{
Eric Andersencb57d552001-06-28 07:25:16 +00008087 mark->stackp = stackp;
8088 mark->stacknxt = stacknxt;
8089 mark->stacknleft = stacknleft;
8090 mark->marknext = markp;
8091 markp = mark;
8092}
8093
8094
8095static void
Eric Andersen2870d962001-07-02 17:27:21 +00008096popstackmark(struct stackmark *mark)
8097{
Eric Andersencb57d552001-06-28 07:25:16 +00008098 struct stack_block *sp;
8099
8100 INTOFF;
8101 markp = mark->marknext;
8102 while (stackp != mark->stackp) {
8103 sp = stackp;
8104 stackp = sp->prev;
8105 ckfree(sp);
8106 }
8107 stacknxt = mark->stacknxt;
8108 stacknleft = mark->stacknleft;
8109 INTON;
8110}
8111
8112
8113/*
8114 * When the parser reads in a string, it wants to stick the string on the
8115 * stack and only adjust the stack pointer when it knows how big the
8116 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8117 * of space on top of the stack and stackblocklen returns the length of
8118 * this block. Growstackblock will grow this space by at least one byte,
8119 * possibly moving it (like realloc). Grabstackblock actually allocates the
8120 * part of the block that has been used.
8121 */
8122
8123static void
Eric Andersen2870d962001-07-02 17:27:21 +00008124growstackblock(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00008125 char *p;
8126 int newlen = ALIGN(stacknleft * 2 + 100);
8127 char *oldspace = stacknxt;
8128 int oldlen = stacknleft;
8129 struct stack_block *sp;
8130 struct stack_block *oldstackp;
8131
8132 if (stacknxt == stackp->space && stackp != &stackbase) {
8133 INTOFF;
8134 oldstackp = stackp;
8135 sp = stackp;
8136 stackp = sp->prev;
8137 sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen);
8138 sp->prev = stackp;
8139 stackp = sp;
8140 stacknxt = sp->space;
8141 stacknleft = newlen;
8142 {
8143 /* Stack marks pointing to the start of the old block
Eric Andersen2870d962001-07-02 17:27:21 +00008144 * must be relocated to point to the new block
Eric Andersencb57d552001-06-28 07:25:16 +00008145 */
8146 struct stackmark *xmark;
8147 xmark = markp;
8148 while (xmark != NULL && xmark->stackp == oldstackp) {
8149 xmark->stackp = stackp;
8150 xmark->stacknxt = stacknxt;
8151 xmark->stacknleft = stacknleft;
8152 xmark = xmark->marknext;
8153 }
8154 }
8155 INTON;
8156 } else {
8157 p = stalloc(newlen);
8158 memcpy(p, oldspace, oldlen);
Eric Andersen2870d962001-07-02 17:27:21 +00008159 stacknxt = p; /* free the space */
8160 stacknleft += newlen; /* we just allocated */
Eric Andersencb57d552001-06-28 07:25:16 +00008161 }
8162}
8163
8164
8165
Eric Andersen2870d962001-07-02 17:27:21 +00008166static inline void
8167grabstackblock(int len)
Eric Andersencb57d552001-06-28 07:25:16 +00008168{
8169 len = ALIGN(len);
8170 stacknxt += len;
8171 stacknleft -= len;
8172}
8173
8174
8175
8176/*
8177 * The following routines are somewhat easier to use that the above.
8178 * The user declares a variable of type STACKSTR, which may be declared
8179 * to be a register. The macro STARTSTACKSTR initializes things. Then
8180 * the user uses the macro STPUTC to add characters to the string. In
8181 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8182 * grown as necessary. When the user is done, she can just leave the
8183 * string there and refer to it using stackblock(). Or she can allocate
8184 * the space for it using grabstackstr(). If it is necessary to allow
8185 * someone else to use the stack temporarily and then continue to grow
8186 * the string, the user should use grabstack to allocate the space, and
8187 * then call ungrabstr(p) to return to the previous mode of operation.
8188 *
8189 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8190 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8191 * is space for at least one character.
8192 */
8193
8194
8195static char *
Eric Andersen2870d962001-07-02 17:27:21 +00008196growstackstr(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00008197 int len = stackblocksize();
8198 if (herefd >= 0 && len >= 1024) {
8199 xwrite(herefd, stackblock(), len);
8200 sstrnleft = len - 1;
8201 return stackblock();
8202 }
8203 growstackblock();
8204 sstrnleft = stackblocksize() - len - 1;
8205 return stackblock() + len;
8206}
8207
8208
8209/*
8210 * Called from CHECKSTRSPACE.
8211 */
8212
8213static char *
8214makestrspace(size_t newlen) {
8215 int len = stackblocksize() - sstrnleft;
8216 do {
8217 growstackblock();
8218 sstrnleft = stackblocksize() - len;
8219 } while (sstrnleft < newlen);
8220 return stackblock() + len;
8221}
8222
8223
8224
8225static void
Eric Andersen2870d962001-07-02 17:27:21 +00008226ungrabstackstr(char *s, char *p)
8227{
Eric Andersencb57d552001-06-28 07:25:16 +00008228 stacknleft += stacknxt - s;
8229 stacknxt = s;
8230 sstrnleft = stacknleft - (p - s);
8231}
Eric Andersencb57d552001-06-28 07:25:16 +00008232/*
8233 * Miscelaneous builtins.
8234 */
8235
8236
8237#undef rflag
8238
Eric Andersencb57d552001-06-28 07:25:16 +00008239#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersen62483552001-07-10 06:09:16 +00008240typedef long rlim_t;
Eric Andersencb57d552001-06-28 07:25:16 +00008241#endif
8242
8243
8244
8245/*
8246 * The read builtin. The -e option causes backslashes to escape the
8247 * following character.
8248 *
8249 * This uses unbuffered input, which may be avoidable in some cases.
8250 */
8251
8252static int
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008253readcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008254{
8255 char **ap;
8256 int backslash;
8257 char c;
8258 int rflag;
8259 char *prompt;
8260 const char *ifs;
8261 char *p;
8262 int startword;
8263 int status;
8264 int i;
8265
8266 rflag = 0;
8267 prompt = NULL;
8268 while ((i = nextopt("p:r")) != '\0') {
8269 if (i == 'p')
8270 prompt = optionarg;
8271 else
8272 rflag = 1;
8273 }
8274 if (prompt && isatty(0)) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008275 out2str(prompt); /* read without cmdedit */
Eric Andersencb57d552001-06-28 07:25:16 +00008276 flushall();
8277 }
8278 if (*(ap = argptr) == NULL)
8279 error("arg count");
8280 if ((ifs = bltinlookup("IFS")) == NULL)
8281 ifs = defifs;
8282 status = 0;
8283 startword = 1;
8284 backslash = 0;
8285 STARTSTACKSTR(p);
8286 for (;;) {
8287 if (read(0, &c, 1) != 1) {
8288 status = 1;
8289 break;
8290 }
8291 if (c == '\0')
8292 continue;
8293 if (backslash) {
8294 backslash = 0;
8295 if (c != '\n')
8296 STPUTC(c, p);
8297 continue;
8298 }
8299 if (!rflag && c == '\\') {
8300 backslash++;
8301 continue;
8302 }
8303 if (c == '\n')
8304 break;
8305 if (startword && *ifs == ' ' && strchr(ifs, c)) {
8306 continue;
8307 }
8308 startword = 0;
8309 if (backslash && c == '\\') {
8310 if (read(0, &c, 1) != 1) {
8311 status = 1;
8312 break;
8313 }
8314 STPUTC(c, p);
8315 } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
8316 STACKSTRNUL(p);
8317 setvar(*ap, stackblock(), 0);
8318 ap++;
8319 startword = 1;
8320 STARTSTACKSTR(p);
8321 } else {
8322 STPUTC(c, p);
8323 }
8324 }
8325 STACKSTRNUL(p);
8326 /* Remove trailing blanks */
8327 while (stackblock() <= --p && strchr(ifs, *p) != NULL)
8328 *p = '\0';
8329 setvar(*ap, stackblock(), 0);
8330 while (*++ap != NULL)
8331 setvar(*ap, nullstr, 0);
8332 return status;
8333}
8334
8335
8336
8337static int
8338umaskcmd(argc, argv)
8339 int argc;
8340 char **argv;
8341{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008342 static const char permuser[3] = "ugo";
8343 static const char permmode[3] = "rwx";
8344 static const short int permmask[] = {
8345 S_IRUSR, S_IWUSR, S_IXUSR,
8346 S_IRGRP, S_IWGRP, S_IXGRP,
8347 S_IROTH, S_IWOTH, S_IXOTH
8348 };
8349
Eric Andersencb57d552001-06-28 07:25:16 +00008350 char *ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008351 mode_t mask;
Eric Andersencb57d552001-06-28 07:25:16 +00008352 int i;
8353 int symbolic_mode = 0;
8354
Eric Andersen62483552001-07-10 06:09:16 +00008355 while (nextopt("S") != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00008356 symbolic_mode = 1;
8357 }
8358
8359 INTOFF;
8360 mask = umask(0);
8361 umask(mask);
8362 INTON;
8363
8364 if ((ap = *argptr) == NULL) {
8365 if (symbolic_mode) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008366 char buf[18];
8367 char *p = buf;
8368 for (i=0 ; i<3 ; i++) {
8369 int j;
8370 *p++ = permuser[i];
8371 *p++ = '=';
8372 for (j=0 ; j<3 ; j++) {
8373 if ((mask & permmask[3*i+j]) == 0) {
8374 *p++ = permmode[j];
8375 }
8376 }
8377 *p++ = ',';
8378 }
8379 *--p = 0;
8380 puts(buf);
Eric Andersencb57d552001-06-28 07:25:16 +00008381 } else {
Eric Andersen62483552001-07-10 06:09:16 +00008382 printf("%.4o\n", mask);
Eric Andersencb57d552001-06-28 07:25:16 +00008383 }
8384 } else {
Eric Andersen62483552001-07-10 06:09:16 +00008385 if (is_digit((unsigned char)*ap)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008386 mask = 0;
8387 do {
8388 if (*ap >= '8' || *ap < '0')
8389 error("Illegal number: %s", argv[1]);
8390 mask = (mask << 3) + (*ap - '0');
8391 } while (*++ap != '\0');
8392 umask(mask);
8393 } else {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008394 mask = ~mask & 0777;
8395 if (parse_mode(ap, &mask) == FALSE) {
Eric Andersencb57d552001-06-28 07:25:16 +00008396 error("Illegal mode: %s", ap);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008397 }
Eric Andersencb57d552001-06-28 07:25:16 +00008398 umask(~mask & 0777);
8399 }
8400 }
8401 return 0;
8402}
8403
8404/*
8405 * ulimit builtin
8406 *
8407 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
8408 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
8409 * ash by J.T. Conklin.
8410 *
8411 * Public domain.
8412 */
8413
8414struct limits {
8415 const char *name;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008416 short cmd;
8417 short factor; /* multiply by to get rlim_{cur,max} values */
Eric Andersencb57d552001-06-28 07:25:16 +00008418};
8419
8420static const struct limits limits[] = {
8421#ifdef RLIMIT_CPU
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008422 { "time(seconds)", RLIMIT_CPU, 1 },
Eric Andersencb57d552001-06-28 07:25:16 +00008423#endif
8424#ifdef RLIMIT_FSIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008425 { "file(blocks)", RLIMIT_FSIZE, 512 },
Eric Andersencb57d552001-06-28 07:25:16 +00008426#endif
8427#ifdef RLIMIT_DATA
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008428 { "data(kbytes)", RLIMIT_DATA, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008429#endif
8430#ifdef RLIMIT_STACK
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008431 { "stack(kbytes)", RLIMIT_STACK, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008432#endif
8433#ifdef RLIMIT_CORE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008434 { "coredump(blocks)", RLIMIT_CORE, 512 },
Eric Andersencb57d552001-06-28 07:25:16 +00008435#endif
8436#ifdef RLIMIT_RSS
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008437 { "memory(kbytes)", RLIMIT_RSS, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008438#endif
8439#ifdef RLIMIT_MEMLOCK
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008440 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008441#endif
8442#ifdef RLIMIT_NPROC
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008443 { "process(processes)", RLIMIT_NPROC, 1 },
Eric Andersencb57d552001-06-28 07:25:16 +00008444#endif
8445#ifdef RLIMIT_NOFILE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008446 { "nofiles(descriptors)", RLIMIT_NOFILE, 1 },
Eric Andersencb57d552001-06-28 07:25:16 +00008447#endif
8448#ifdef RLIMIT_VMEM
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008449 { "vmemory(kbytes)", RLIMIT_VMEM, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008450#endif
8451#ifdef RLIMIT_SWAP
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008452 { "swap(kbytes)", RLIMIT_SWAP, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008453#endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008454 { NULL, 0, 0 }
Eric Andersencb57d552001-06-28 07:25:16 +00008455};
8456
8457static int
8458ulimitcmd(argc, argv)
8459 int argc;
8460 char **argv;
8461{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008462 static const char unlimited_string[] = "unlimited";
Eric Andersen2870d962001-07-02 17:27:21 +00008463 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00008464 rlim_t val = 0;
8465 enum { SOFT = 0x1, HARD = 0x2 }
8466 how = SOFT | HARD;
Eric Andersen2870d962001-07-02 17:27:21 +00008467 const struct limits *l;
8468 int set, all = 0;
8469 int optc, what;
8470 struct rlimit limit;
Eric Andersencb57d552001-06-28 07:25:16 +00008471
8472 what = 'f';
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008473
8474 while ((optc = nextopt("HSa"
8475#ifdef RLIMIT_CPU
8476 "t"
8477#endif
8478#ifdef RLIMIT_FSIZE
8479 "f"
8480#endif
8481#ifdef RLIMIT_DATA
8482 "d"
8483#endif
8484#ifdef RLIMIT_STACK
8485 "s"
8486#endif
8487#ifdef RLIMIT_CORE
8488 "c"
8489#endif
8490#ifdef RLIMIT_RSS
8491 "m"
8492#endif
8493#ifdef RLIMIT_MEMLOCK
8494 "l"
8495#endif
8496#ifdef RLIMIT_NPROC
8497 "p"
8498#endif
8499#ifdef RLIMIT_NOFILE
8500 "n"
8501#endif
8502#ifdef RLIMIT_VMEM
8503 "v"
8504#endif
8505#ifdef RLIMIT_SWAP
8506 "w"
8507#endif
8508 )) != '\0') {
8509 if (optc == 'H') {
Eric Andersencb57d552001-06-28 07:25:16 +00008510 how = HARD;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008511 } else if (optc == 'S') {
Eric Andersencb57d552001-06-28 07:25:16 +00008512 how = SOFT;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008513 } else if (optc == 'a') {
Eric Andersencb57d552001-06-28 07:25:16 +00008514 all = 1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008515 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00008516 what = optc;
8517 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008518 }
Eric Andersencb57d552001-06-28 07:25:16 +00008519
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008520 for (l = limits; l->name; l++) {
8521 if(l->name[0] == what)
8522 break;
8523 if(l->name[1]=='w' && what=='w')
8524 break;
8525 }
Eric Andersencb57d552001-06-28 07:25:16 +00008526
8527 set = *argptr ? 1 : 0;
8528 if (set) {
8529 char *p = *argptr;
8530
8531 if (all || argptr[1])
8532 error("too many arguments");
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008533 if (strcmp(p, unlimited_string) == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00008534 val = RLIM_INFINITY;
8535 else {
8536 val = (rlim_t) 0;
8537
8538 while ((c = *p++) >= '0' && c <= '9')
8539 {
8540 val = (val * 10) + (long)(c - '0');
8541 if (val < (rlim_t) 0)
8542 break;
8543 }
8544 if (c)
8545 error("bad number");
8546 val *= l->factor;
8547 }
8548 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008549
Eric Andersencb57d552001-06-28 07:25:16 +00008550 if (all) {
8551 for (l = limits; l->name; l++) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008552 printf("%-20s ", l->name);
Eric Andersencb57d552001-06-28 07:25:16 +00008553 getrlimit(l->cmd, &limit);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008554 OUTPUT_LIMIT:
Eric Andersencb57d552001-06-28 07:25:16 +00008555 if (how & SOFT)
8556 val = limit.rlim_cur;
8557 else if (how & HARD)
8558 val = limit.rlim_max;
8559
Eric Andersencb57d552001-06-28 07:25:16 +00008560 if (val == RLIM_INFINITY)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008561 puts(unlimited_string);
Eric Andersencb57d552001-06-28 07:25:16 +00008562 else
8563 {
8564 val /= l->factor;
Eric Andersen62483552001-07-10 06:09:16 +00008565 printf("%lld\n", (long long) val);
Eric Andersencb57d552001-06-28 07:25:16 +00008566 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008567 if (!all) {
8568 break;
8569 }
Eric Andersencb57d552001-06-28 07:25:16 +00008570 }
8571 return 0;
8572 }
8573
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008574 if (!set) {
8575 goto OUTPUT_LIMIT;
Eric Andersencb57d552001-06-28 07:25:16 +00008576 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008577
8578 getrlimit(l->cmd, &limit);
8579 if (how & HARD)
8580 limit.rlim_max = val;
8581 if (how & SOFT)
8582 limit.rlim_cur = val;
8583 if (setrlimit(l->cmd, &limit) < 0)
8584 error("error setting limit (%m)");
Eric Andersencb57d552001-06-28 07:25:16 +00008585 return 0;
8586}
Eric Andersencb57d552001-06-28 07:25:16 +00008587/*
8588 * prefix -- see if pfx is a prefix of string.
8589 */
8590
8591static int
Eric Andersen62483552001-07-10 06:09:16 +00008592prefix(char const *pfx, char const *string)
8593{
Eric Andersencb57d552001-06-28 07:25:16 +00008594 while (*pfx) {
8595 if (*pfx++ != *string++)
8596 return 0;
8597 }
8598 return 1;
8599}
8600
Eric Andersen2870d962001-07-02 17:27:21 +00008601/*
8602 * Return true if s is a string of digits, and save munber in intptr
8603 * nagative is bad
8604 */
8605
8606static int
8607is_number(const char *p, int *intptr)
8608{
8609 int ret = 0;
8610
8611 do {
8612 if (! is_digit(*p))
8613 return 0;
8614 ret *= 10;
8615 ret += digit_val(*p);
8616 p++;
8617 } while (*p != '\0');
8618
8619 *intptr = ret;
8620 return 1;
8621}
Eric Andersencb57d552001-06-28 07:25:16 +00008622
8623/*
8624 * Convert a string of digits to an integer, printing an error message on
8625 * failure.
8626 */
8627
8628static int
Eric Andersen2870d962001-07-02 17:27:21 +00008629number(const char *s)
8630{
8631 int i;
8632 if (! is_number(s, &i))
Eric Andersencb57d552001-06-28 07:25:16 +00008633 error("Illegal number: %s", s);
Eric Andersen2870d962001-07-02 17:27:21 +00008634 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00008635}
8636
Eric Andersencb57d552001-06-28 07:25:16 +00008637/*
8638 * Produce a possibly single quoted string suitable as input to the shell.
8639 * The return string is allocated on the stack.
8640 */
8641
8642static char *
8643single_quote(const char *s) {
8644 char *p;
8645
8646 STARTSTACKSTR(p);
8647
8648 do {
8649 char *q = p;
8650 size_t len1, len1p, len2, len2p;
8651
8652 len1 = strcspn(s, "'");
8653 len2 = strspn(s + len1, "'");
8654
8655 len1p = len1 ? len1 + 2 : len1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008656 len2p = len2 + ((len2 < 2) ? len2 : 2);
Eric Andersencb57d552001-06-28 07:25:16 +00008657
8658 CHECKSTRSPACE(len1p + len2p + 1, p);
8659
8660 if (len1) {
8661 *p = '\'';
Eric Andersencb57d552001-06-28 07:25:16 +00008662 q = p + 1 + len1;
8663 memcpy(p + 1, s, len1);
Eric Andersencb57d552001-06-28 07:25:16 +00008664 *q++ = '\'';
8665 s += len1;
8666 }
8667
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008668 if (len2 > 1) {
Eric Andersencb57d552001-06-28 07:25:16 +00008669 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008670 q += 1 + len2;
8671 memcpy(q + 1, s, len2);
8672 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008673 s += len2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008674 } else if (len2 == 1) {
8675 *q++ = '\\';
8676 *q = '\'';
8677 s++;
Eric Andersencb57d552001-06-28 07:25:16 +00008678 }
8679
8680 STADJUST(len1p + len2p, p);
8681 } while (*s);
8682
8683 USTPUTC(0, p);
8684
8685 return grabstackstr(p);
8686}
8687
8688/*
8689 * Like strdup but works with the ash stack.
8690 */
8691
8692static char *
8693sstrdup(const char *p)
8694{
8695 size_t len = strlen(p) + 1;
8696 return memcpy(stalloc(len), p, len);
8697}
8698
Eric Andersencb57d552001-06-28 07:25:16 +00008699
8700/*
Eric Andersencb57d552001-06-28 07:25:16 +00008701 * Routine for dealing with parsed shell commands.
8702 */
8703
8704
Eric Andersen62483552001-07-10 06:09:16 +00008705static void sizenodelist (const struct nodelist *);
8706static struct nodelist *copynodelist (const struct nodelist *);
8707static char *nodesavestr (const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00008708
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008709//#define CALCSIZE_TABLE
8710//#define COPYNODE_TABLE
8711#if defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE)
8712/*
8713 * To collect a lot of redundant code in case statements for copynode()
8714 * and calcsize(), we implement a mini language here. Each type of node
8715 * struct has an associated instruction sequence that operates on its
8716 * members via their offsets. The instruction are pack in unsigned chars
8717 * with format IIDDDDDE where the bits are
8718 * I : part of the instruction opcode, which are
8719 * 00 : member is a pointer to another node
8720 * 40 : member is an integer
8721 * 80 : member is a pointer to a nodelist
8722 * CC : member is a pointer to a char string
8723 * D : data - the actual offset of the member to operate on in the struct
8724 * (since we assume bit 0 is set, it is not shifted)
8725 * E : flag signaling end of instruction sequence
8726 *
8727 * WARNING: In order to handle larger offsets for 64bit archs, this code
8728 * assumes that no offset can be an odd number and stores the
8729 * end-of-instructions flag in bit 0.
8730 */
8731
8732#define NODE_INTEGER 0x40
8733#define NODE_NODELIST 0x80
8734#define NODE_CHARPTR 0xC0
8735#define NODE_NOMORE 0x01 /* Note: no offset should be odd (aligned)*/
8736#define NODE_MBRMASK 0xC0
8737#define NODE_OFFSETMASK 0x3E
8738
8739static const unsigned char copynode_ops[35] = {
8740#define COPYNODE_OPS0 0
8741 offsetof(union node, nbinary.ch2),
8742 offsetof(union node, nbinary.ch1)|NODE_NOMORE,
8743#define COPYNODE_OPS1 (COPYNODE_OPS0 + 2)
8744 offsetof(union node, ncmd.redirect),
8745 offsetof(union node, ncmd.args),
8746 offsetof(union node, ncmd.assign),
8747 offsetof(union node, ncmd.backgnd)|NODE_INTEGER|NODE_NOMORE,
8748#define COPYNODE_OPS2 (COPYNODE_OPS1 + 4)
8749 offsetof(union node, npipe.cmdlist)|NODE_NODELIST,
8750 offsetof(union node, npipe.backgnd)|NODE_INTEGER|NODE_NOMORE,
8751#define COPYNODE_OPS3 (COPYNODE_OPS2 + 2)
8752 offsetof(union node, nredir.redirect),
8753 offsetof(union node, nredir.n)|NODE_NOMORE,
8754#define COPYNODE_OPS4 (COPYNODE_OPS3 + 2)
8755 offsetof(union node, nif.elsepart),
8756 offsetof(union node, nif.ifpart),
8757 offsetof(union node, nif.test)|NODE_NOMORE,
8758#define COPYNODE_OPS5 (COPYNODE_OPS4 + 3)
8759 offsetof(union node, nfor.var)|NODE_CHARPTR,
8760 offsetof(union node, nfor.body),
8761 offsetof(union node, nfor.args)|NODE_NOMORE,
8762#define COPYNODE_OPS6 (COPYNODE_OPS5 + 3)
8763 offsetof(union node, ncase.cases),
8764 offsetof(union node, ncase.expr)|NODE_NOMORE,
8765#define COPYNODE_OPS7 (COPYNODE_OPS6 + 2)
8766 offsetof(union node, nclist.body),
8767 offsetof(union node, nclist.pattern),
8768 offsetof(union node, nclist.next)|NODE_NOMORE,
8769#define COPYNODE_OPS8 (COPYNODE_OPS7 + 3)
8770 offsetof(union node, narg.backquote)|NODE_NODELIST,
8771 offsetof(union node, narg.text)|NODE_CHARPTR,
8772 offsetof(union node, narg.next)|NODE_NOMORE,
8773#define COPYNODE_OPS9 (COPYNODE_OPS8 + 3)
8774 offsetof(union node, nfile.fname),
8775 offsetof(union node, nfile.fd)|NODE_INTEGER,
8776 offsetof(union node, nfile.next)|NODE_NOMORE,
8777#define COPYNODE_OPS10 (COPYNODE_OPS9 + 3)
8778 offsetof(union node, ndup.vname),
8779 offsetof(union node, ndup.dupfd)|NODE_INTEGER,
8780 offsetof(union node, ndup.fd)|NODE_INTEGER,
8781 offsetof(union node, ndup.next)|NODE_NOMORE,
8782#define COPYNODE_OPS11 (COPYNODE_OPS10 + 4)
8783 offsetof(union node, nhere.doc),
8784 offsetof(union node, nhere.fd)|NODE_INTEGER,
8785 offsetof(union node, nhere.next)|NODE_NOMORE,
8786#define COPYNODE_OPS12 (COPYNODE_OPS11 + 3)
8787 offsetof(union node, nnot.com)|NODE_NOMORE,
8788};
8789
8790#if COPYNODE_OPS12 != 34
8791#error COPYNODE_OPS12 is incorrect
8792#endif
8793
8794static const unsigned char copynode_ops_index[26] = {
8795 COPYNODE_OPS0, /* NSEMI */
8796 COPYNODE_OPS1, /* NCMD */
8797 COPYNODE_OPS2, /* NPIPE */
8798 COPYNODE_OPS3, /* NREDIR */
8799 COPYNODE_OPS3, /* NBACKGND */
8800 COPYNODE_OPS3, /* NSUBSHELL */
8801 COPYNODE_OPS0, /* NAND */
8802 COPYNODE_OPS0, /* NOR */
8803 COPYNODE_OPS4, /* NIF */
8804 COPYNODE_OPS0, /* NWHILE */
8805 COPYNODE_OPS0, /* NUNTIL */
8806 COPYNODE_OPS5, /* NFOR */
8807 COPYNODE_OPS6, /* NCASE */
8808 COPYNODE_OPS7, /* NCLIST */
8809 COPYNODE_OPS8, /* NDEFUN */
8810 COPYNODE_OPS8, /* NARG */
8811 COPYNODE_OPS9, /* NTO */
8812 COPYNODE_OPS9, /* NFROM */
8813 COPYNODE_OPS9, /* NFROMTO */
8814 COPYNODE_OPS9, /* NAPPEND */
8815 COPYNODE_OPS9, /* NTOOV */
8816 COPYNODE_OPS10, /* NTOFD */
8817 COPYNODE_OPS10, /* NFROMFD */
8818 COPYNODE_OPS11, /* NHERE */
8819 COPYNODE_OPS11, /* NXHERE */
8820 COPYNODE_OPS12, /* NNOT */
8821};
8822
8823#if NODE_CHARPTR != NODE_MBRMASK
8824#error NODE_CHARPTR != NODE_MBRMASK!!!
8825#endif
8826#endif /* defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE) */
8827
8828#ifdef COPYNODE_TABLE
8829static union node *
8830copynode(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008831{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008832 union node *new;
8833 const unsigned char *p;
8834
Eric Andersencb57d552001-06-28 07:25:16 +00008835 if (n == NULL)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008836 return NULL;
8837 new = funcblock;
8838 new->type = n->type;
8839 funcblock = (char *) funcblock + (int) nodesize[n->type];
8840 p = copynode_ops + (int) copynode_ops_index[n->type];
8841 do {
8842 char *nn = ((char *) new) + ((int)(*p & NODE_OFFSETMASK));
8843 const char *no = ((const char *) n) + ((int)(*p & NODE_OFFSETMASK));
8844
8845 if (!(*p & NODE_MBRMASK)) { /* standard node */
8846 (union node *) nn = copynode((const union node *) no);
8847 } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
8848 nn = nodesavestr(no);
8849 } else if (*p & NODE_NODELIST) { /* nodelist */
8850 (struct nodelist *) nn
8851 = copynodelist((const struct nodelist *) no);
8852 } else { /* integer */
8853 *((int *) nn) = *((int *) no);
8854 }
8855 } while (!(*p++ & NODE_NOMORE));
8856 return new;
Eric Andersencb57d552001-06-28 07:25:16 +00008857}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008858#else /* COPYNODE_TABLE */
Eric Andersencb57d552001-06-28 07:25:16 +00008859static union node *
Eric Andersen62483552001-07-10 06:09:16 +00008860copynode(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008861{
Eric Andersen62483552001-07-10 06:09:16 +00008862 union node *new;
Eric Andersencb57d552001-06-28 07:25:16 +00008863
8864 if (n == NULL)
8865 return NULL;
8866 new = funcblock;
8867 funcblock = (char *) funcblock + nodesize[n->type];
8868 switch (n->type) {
8869 case NSEMI:
8870 case NAND:
8871 case NOR:
8872 case NWHILE:
8873 case NUNTIL:
8874 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8875 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8876 break;
8877 case NCMD:
8878 new->ncmd.redirect = copynode(n->ncmd.redirect);
8879 new->ncmd.args = copynode(n->ncmd.args);
8880 new->ncmd.assign = copynode(n->ncmd.assign);
8881 new->ncmd.backgnd = n->ncmd.backgnd;
8882 break;
8883 case NPIPE:
8884 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8885 new->npipe.backgnd = n->npipe.backgnd;
8886 break;
8887 case NREDIR:
8888 case NBACKGND:
8889 case NSUBSHELL:
8890 new->nredir.redirect = copynode(n->nredir.redirect);
8891 new->nredir.n = copynode(n->nredir.n);
8892 break;
8893 case NIF:
8894 new->nif.elsepart = copynode(n->nif.elsepart);
8895 new->nif.ifpart = copynode(n->nif.ifpart);
8896 new->nif.test = copynode(n->nif.test);
8897 break;
8898 case NFOR:
8899 new->nfor.var = nodesavestr(n->nfor.var);
8900 new->nfor.body = copynode(n->nfor.body);
8901 new->nfor.args = copynode(n->nfor.args);
8902 break;
8903 case NCASE:
8904 new->ncase.cases = copynode(n->ncase.cases);
8905 new->ncase.expr = copynode(n->ncase.expr);
8906 break;
8907 case NCLIST:
8908 new->nclist.body = copynode(n->nclist.body);
8909 new->nclist.pattern = copynode(n->nclist.pattern);
8910 new->nclist.next = copynode(n->nclist.next);
8911 break;
8912 case NDEFUN:
8913 case NARG:
8914 new->narg.backquote = copynodelist(n->narg.backquote);
8915 new->narg.text = nodesavestr(n->narg.text);
8916 new->narg.next = copynode(n->narg.next);
8917 break;
8918 case NTO:
8919 case NFROM:
8920 case NFROMTO:
8921 case NAPPEND:
8922 case NTOOV:
8923 new->nfile.fname = copynode(n->nfile.fname);
8924 new->nfile.fd = n->nfile.fd;
8925 new->nfile.next = copynode(n->nfile.next);
8926 break;
8927 case NTOFD:
8928 case NFROMFD:
8929 new->ndup.vname = copynode(n->ndup.vname);
8930 new->ndup.dupfd = n->ndup.dupfd;
8931 new->ndup.fd = n->ndup.fd;
8932 new->ndup.next = copynode(n->ndup.next);
8933 break;
8934 case NHERE:
8935 case NXHERE:
8936 new->nhere.doc = copynode(n->nhere.doc);
8937 new->nhere.fd = n->nhere.fd;
8938 new->nhere.next = copynode(n->nhere.next);
8939 break;
8940 case NNOT:
8941 new->nnot.com = copynode(n->nnot.com);
8942 break;
8943 };
8944 new->type = n->type;
Eric Andersen62483552001-07-10 06:09:16 +00008945 return new;
Eric Andersencb57d552001-06-28 07:25:16 +00008946}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008947#endif /* COPYNODE_TABLE */
8948
8949#ifdef CALCSIZE_TABLE
8950static void
8951calcsize(const union node *n)
8952{
8953 const unsigned char *p;
8954
8955 if (n == NULL)
8956 return;
8957 funcblocksize += (int) nodesize[n->type];
8958
8959 p = copynode_ops + (int) copynode_ops_index[n->type];
8960 do {
8961 const char *no = ((const char *) n) + ((int)(*p & NODE_OFFSETMASK));
8962
8963 if (!(*p & NODE_MBRMASK)) { /* standard node */
8964 calcsize((const union node *) no);
8965 } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
8966 funcstringsize += strlen(no) + 1;
8967 } else if (*p & NODE_NODELIST) { /* nodelist */
8968 sizenodelist((const struct nodelist *) no);
8969 }
8970 } while (!(*p++ & NODE_NOMORE));
8971}
8972#else /* CALCSIZE_TABLE */
8973static void
8974calcsize(const union node *n)
8975{
8976 if (n == NULL)
8977 return;
8978 funcblocksize += nodesize[n->type];
8979 switch (n->type) {
8980 case NSEMI:
8981 case NAND:
8982 case NOR:
8983 case NWHILE:
8984 case NUNTIL:
8985 calcsize(n->nbinary.ch2);
8986 calcsize(n->nbinary.ch1);
8987 break;
8988 case NCMD:
8989 calcsize(n->ncmd.redirect);
8990 calcsize(n->ncmd.args);
8991 calcsize(n->ncmd.assign);
8992 break;
8993 case NPIPE:
8994 sizenodelist(n->npipe.cmdlist);
8995 break;
8996 case NREDIR:
8997 case NBACKGND:
8998 case NSUBSHELL:
8999 calcsize(n->nredir.redirect);
9000 calcsize(n->nredir.n);
9001 break;
9002 case NIF:
9003 calcsize(n->nif.elsepart);
9004 calcsize(n->nif.ifpart);
9005 calcsize(n->nif.test);
9006 break;
9007 case NFOR:
9008 funcstringsize += strlen(n->nfor.var) + 1;
9009 calcsize(n->nfor.body);
9010 calcsize(n->nfor.args);
9011 break;
9012 case NCASE:
9013 calcsize(n->ncase.cases);
9014 calcsize(n->ncase.expr);
9015 break;
9016 case NCLIST:
9017 calcsize(n->nclist.body);
9018 calcsize(n->nclist.pattern);
9019 calcsize(n->nclist.next);
9020 break;
9021 case NDEFUN:
9022 case NARG:
9023 sizenodelist(n->narg.backquote);
9024 funcstringsize += strlen(n->narg.text) + 1;
9025 calcsize(n->narg.next);
9026 break;
9027 case NTO:
9028 case NFROM:
9029 case NFROMTO:
9030 case NAPPEND:
9031 case NTOOV:
9032 calcsize(n->nfile.fname);
9033 calcsize(n->nfile.next);
9034 break;
9035 case NTOFD:
9036 case NFROMFD:
9037 calcsize(n->ndup.vname);
9038 calcsize(n->ndup.next);
9039 break;
9040 case NHERE:
9041 case NXHERE:
9042 calcsize(n->nhere.doc);
9043 calcsize(n->nhere.next);
9044 break;
9045 case NNOT:
9046 calcsize(n->nnot.com);
9047 break;
9048 };
9049}
9050#endif /* CALCSIZE_TABLE */
9051
9052static void
9053sizenodelist(const struct nodelist *lp)
9054{
9055 while (lp) {
9056 funcblocksize += ALIGN(sizeof(struct nodelist));
9057 calcsize(lp->n);
9058 lp = lp->next;
9059 }
9060}
Eric Andersencb57d552001-06-28 07:25:16 +00009061
9062
9063static struct nodelist *
Eric Andersen62483552001-07-10 06:09:16 +00009064copynodelist(const struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00009065{
9066 struct nodelist *start;
9067 struct nodelist **lpp;
9068
9069 lpp = &start;
9070 while (lp) {
9071 *lpp = funcblock;
9072 funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist));
9073 (*lpp)->n = copynode(lp->n);
9074 lp = lp->next;
9075 lpp = &(*lpp)->next;
9076 }
9077 *lpp = NULL;
9078 return start;
9079}
9080
9081
Eric Andersencb57d552001-06-28 07:25:16 +00009082static char *
Eric Andersen62483552001-07-10 06:09:16 +00009083nodesavestr(const char *s)
Eric Andersencb57d552001-06-28 07:25:16 +00009084{
Eric Andersen62483552001-07-10 06:09:16 +00009085 const char *p = s;
9086 char *q = funcstring;
Eric Andersencb57d552001-06-28 07:25:16 +00009087 char *rtn = funcstring;
9088
9089 while ((*q++ = *p++) != '\0')
9090 continue;
9091 funcstring = q;
9092 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00009093}
9094
Eric Andersencb57d552001-06-28 07:25:16 +00009095#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00009096static int getopts (char *, char *, char **, int *, int *);
Eric Andersencb57d552001-06-28 07:25:16 +00009097#endif
9098
9099
9100/*
9101 * Process the shell command line arguments.
9102 */
9103
9104static void
9105procargs(argc, argv)
9106 int argc;
9107 char **argv;
9108{
9109 int i;
9110
9111 argptr = argv;
9112 if (argc > 0)
9113 argptr++;
9114 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009115 optent_val(i) = 2;
Eric Andersencb57d552001-06-28 07:25:16 +00009116 options(1);
9117 if (*argptr == NULL && minusc == NULL)
9118 sflag = 1;
9119 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
9120 iflag = 1;
9121 if (mflag == 2)
9122 mflag = iflag;
9123 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009124 if (optent_val(i) == 2)
9125 optent_val(i) = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009126 arg0 = argv[0];
9127 if (sflag == 0 && minusc == NULL) {
9128 commandname = argv[0];
9129 arg0 = *argptr++;
9130 setinputfile(arg0, 0);
9131 commandname = arg0;
9132 }
9133 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
9134 if (argptr && minusc && *argptr)
Eric Andersen2870d962001-07-02 17:27:21 +00009135 arg0 = *argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00009136
9137 shellparam.p = argptr;
9138 shellparam.optind = 1;
9139 shellparam.optoff = -1;
9140 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
9141 while (*argptr) {
9142 shellparam.nparam++;
9143 argptr++;
9144 }
9145 optschanged();
9146}
9147
9148
Eric Andersencb57d552001-06-28 07:25:16 +00009149
9150/*
9151 * Process shell options. The global variable argptr contains a pointer
9152 * to the argument list; we advance it past the options.
9153 */
9154
Eric Andersen62483552001-07-10 06:09:16 +00009155static inline void
9156minus_o(const char *name, int val)
9157{
9158 int i;
9159
9160 if (name == NULL) {
9161 out1str("Current option settings\n");
9162 for (i = 0; i < NOPTS; i++)
9163 printf("%-16s%s\n", optent_name(optlist[i]),
9164 optent_val(i) ? "on" : "off");
9165 } else {
9166 for (i = 0; i < NOPTS; i++)
9167 if (equal(name, optent_name(optlist[i]))) {
9168 setoption(optent_letter(optlist[i]), val);
9169 return;
9170 }
9171 error("Illegal option -o %s", name);
9172 }
9173}
9174
9175
Eric Andersencb57d552001-06-28 07:25:16 +00009176static void
Eric Andersen62483552001-07-10 06:09:16 +00009177options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00009178{
9179 char *p;
9180 int val;
9181 int c;
9182
9183 if (cmdline)
9184 minusc = NULL;
9185 while ((p = *argptr) != NULL) {
9186 argptr++;
9187 if ((c = *p++) == '-') {
9188 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00009189 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
9190 if (!cmdline) {
9191 /* "-" means turn off -x and -v */
9192 if (p[0] == '\0')
9193 xflag = vflag = 0;
9194 /* "--" means reset params */
9195 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00009196 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00009197 }
9198 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00009199 }
9200 } else if (c == '+') {
9201 val = 0;
9202 } else {
9203 argptr--;
9204 break;
9205 }
9206 while ((c = *p++) != '\0') {
9207 if (c == 'c' && cmdline) {
9208 char *q;
Eric Andersen2870d962001-07-02 17:27:21 +00009209#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */
Eric Andersencb57d552001-06-28 07:25:16 +00009210 if (*p == '\0')
9211#endif
9212 q = *argptr++;
9213 if (q == NULL || minusc != NULL)
9214 error("Bad -c option");
9215 minusc = q;
9216#ifdef NOHACK
9217 break;
9218#endif
9219 } else if (c == 'o') {
9220 minus_o(*argptr, val);
9221 if (*argptr)
9222 argptr++;
9223 } else {
9224 setoption(c, val);
9225 }
9226 }
9227 }
9228}
9229
Eric Andersencb57d552001-06-28 07:25:16 +00009230
9231static void
Eric Andersen2870d962001-07-02 17:27:21 +00009232setoption(int flag, int val)
9233{
Eric Andersencb57d552001-06-28 07:25:16 +00009234 int i;
9235
9236 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009237 if (optent_letter(optlist[i]) == flag) {
9238 optent_val(i) = val;
Eric Andersencb57d552001-06-28 07:25:16 +00009239 if (val) {
9240 /* #%$ hack for ksh semantics */
9241 if (flag == 'V')
9242 Eflag = 0;
9243 else if (flag == 'E')
9244 Vflag = 0;
9245 }
9246 return;
9247 }
9248 error("Illegal option -%c", flag);
9249 /* NOTREACHED */
9250}
9251
9252
9253
Eric Andersencb57d552001-06-28 07:25:16 +00009254/*
9255 * Set the shell parameters.
9256 */
9257
9258static void
Eric Andersen2870d962001-07-02 17:27:21 +00009259setparam(char **argv)
9260{
Eric Andersencb57d552001-06-28 07:25:16 +00009261 char **newparam;
9262 char **ap;
9263 int nparam;
9264
9265 for (nparam = 0 ; argv[nparam] ; nparam++);
9266 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
9267 while (*argv) {
9268 *ap++ = savestr(*argv++);
9269 }
9270 *ap = NULL;
9271 freeparam(&shellparam);
9272 shellparam.malloc = 1;
9273 shellparam.nparam = nparam;
9274 shellparam.p = newparam;
9275 shellparam.optind = 1;
9276 shellparam.optoff = -1;
9277}
9278
9279
9280/*
9281 * Free the list of positional parameters.
9282 */
9283
9284static void
Eric Andersen2870d962001-07-02 17:27:21 +00009285freeparam(volatile struct shparam *param)
9286{
Eric Andersencb57d552001-06-28 07:25:16 +00009287 char **ap;
9288
9289 if (param->malloc) {
9290 for (ap = param->p ; *ap ; ap++)
9291 ckfree(*ap);
9292 ckfree(param->p);
9293 }
9294}
9295
9296
9297
9298/*
9299 * The shift builtin command.
9300 */
9301
9302static int
9303shiftcmd(argc, argv)
9304 int argc;
9305 char **argv;
9306{
9307 int n;
9308 char **ap1, **ap2;
9309
9310 n = 1;
9311 if (argc > 1)
9312 n = number(argv[1]);
9313 if (n > shellparam.nparam)
9314 error("can't shift that many");
9315 INTOFF;
9316 shellparam.nparam -= n;
9317 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
9318 if (shellparam.malloc)
9319 ckfree(*ap1);
9320 }
9321 ap2 = shellparam.p;
9322 while ((*ap2++ = *ap1++) != NULL);
9323 shellparam.optind = 1;
9324 shellparam.optoff = -1;
9325 INTON;
9326 return 0;
9327}
9328
9329
9330
9331/*
9332 * The set command builtin.
9333 */
9334
9335static int
9336setcmd(argc, argv)
9337 int argc;
9338 char **argv;
9339{
9340 if (argc == 1)
9341 return showvarscmd(argc, argv);
9342 INTOFF;
9343 options(0);
9344 optschanged();
9345 if (*argptr != NULL) {
9346 setparam(argptr);
9347 }
9348 INTON;
9349 return 0;
9350}
9351
9352
9353static void
Eric Andersen2870d962001-07-02 17:27:21 +00009354getoptsreset(const char *value)
Eric Andersencb57d552001-06-28 07:25:16 +00009355{
9356 shellparam.optind = number(value);
9357 shellparam.optoff = -1;
9358}
9359
Eric Andersen2870d962001-07-02 17:27:21 +00009360#ifdef BB_LOCALE_SUPPORT
9361static void change_lc_all(const char *value)
9362{
9363 if(value != 0 && *value != 0)
9364 setlocale(LC_ALL, value);
9365}
9366
9367static void change_lc_ctype(const char *value)
9368{
9369 if(value != 0 && *value != 0)
9370 setlocale(LC_CTYPE, value);
9371}
9372
9373#endif
9374
Eric Andersencb57d552001-06-28 07:25:16 +00009375#ifdef ASH_GETOPTS
9376/*
9377 * The getopts builtin. Shellparam.optnext points to the next argument
9378 * to be processed. Shellparam.optptr points to the next character to
9379 * be processed in the current argument. If shellparam.optnext is NULL,
9380 * then it's the first time getopts has been called.
9381 */
9382
9383static int
9384getoptscmd(argc, argv)
9385 int argc;
9386 char **argv;
9387{
9388 char **optbase;
9389
9390 if (argc < 3)
9391 error("Usage: getopts optstring var [arg]");
9392 else if (argc == 3) {
9393 optbase = shellparam.p;
9394 if (shellparam.optind > shellparam.nparam + 1) {
9395 shellparam.optind = 1;
9396 shellparam.optoff = -1;
9397 }
9398 }
9399 else {
9400 optbase = &argv[3];
9401 if (shellparam.optind > argc - 2) {
9402 shellparam.optind = 1;
9403 shellparam.optoff = -1;
9404 }
9405 }
9406
9407 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9408 &shellparam.optoff);
9409}
9410
9411/*
9412 * Safe version of setvar, returns 1 on success 0 on failure.
9413 */
9414
9415static int
9416setvarsafe(name, val, flags)
9417 const char *name, *val;
9418 int flags;
9419{
9420 struct jmploc jmploc;
9421 struct jmploc *volatile savehandler = handler;
9422 int err = 0;
9423#ifdef __GNUC__
9424 (void) &err;
9425#endif
9426
9427 if (setjmp(jmploc.loc))
9428 err = 1;
9429 else {
9430 handler = &jmploc;
9431 setvar(name, val, flags);
9432 }
9433 handler = savehandler;
9434 return err;
9435}
9436
9437static int
9438getopts(optstr, optvar, optfirst, myoptind, optoff)
9439 char *optstr;
9440 char *optvar;
9441 char **optfirst;
9442 int *myoptind;
9443 int *optoff;
9444{
9445 char *p, *q;
9446 char c = '?';
9447 int done = 0;
9448 int err = 0;
9449 char s[10];
9450 char **optnext = optfirst + *myoptind - 1;
9451
9452 if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
9453 strlen(*(optnext - 1)) < *optoff)
9454 p = NULL;
9455 else
9456 p = *(optnext - 1) + *optoff;
9457 if (p == NULL || *p == '\0') {
9458 /* Current word is done, advance */
9459 if (optnext == NULL)
9460 return 1;
9461 p = *optnext;
9462 if (p == NULL || *p != '-' || *++p == '\0') {
9463atend:
9464 *myoptind = optnext - optfirst + 1;
9465 p = NULL;
9466 done = 1;
9467 goto out;
9468 }
9469 optnext++;
Eric Andersen2870d962001-07-02 17:27:21 +00009470 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009471 goto atend;
9472 }
9473
9474 c = *p++;
9475 for (q = optstr; *q != c; ) {
9476 if (*q == '\0') {
9477 if (optstr[0] == ':') {
9478 s[0] = c;
9479 s[1] = '\0';
9480 err |= setvarsafe("OPTARG", s, 0);
9481 }
9482 else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009483 out2fmt("Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009484 (void) unsetvar("OPTARG");
9485 }
9486 c = '?';
9487 goto bad;
9488 }
9489 if (*++q == ':')
9490 q++;
9491 }
9492
9493 if (*++q == ':') {
9494 if (*p == '\0' && (p = *optnext) == NULL) {
9495 if (optstr[0] == ':') {
9496 s[0] = c;
9497 s[1] = '\0';
9498 err |= setvarsafe("OPTARG", s, 0);
9499 c = ':';
9500 }
9501 else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009502 out2fmt("No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009503 (void) unsetvar("OPTARG");
9504 c = '?';
9505 }
9506 goto bad;
9507 }
9508
9509 if (p == *optnext)
9510 optnext++;
9511 setvarsafe("OPTARG", p, 0);
9512 p = NULL;
9513 }
9514 else
9515 setvarsafe("OPTARG", "", 0);
9516 *myoptind = optnext - optfirst + 1;
9517 goto out;
9518
9519bad:
9520 *myoptind = 1;
9521 p = NULL;
9522out:
9523 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersen3102ac42001-07-06 04:26:23 +00009524 snprintf(s, sizeof(s), "%d", *myoptind);
Eric Andersencb57d552001-06-28 07:25:16 +00009525 err |= setvarsafe("OPTIND", s, VNOFUNC);
9526 s[0] = c;
9527 s[1] = '\0';
9528 err |= setvarsafe(optvar, s, 0);
9529 if (err) {
9530 *myoptind = 1;
9531 *optoff = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00009532 exraise(EXERROR);
9533 }
9534 return done;
9535}
Eric Andersen2870d962001-07-02 17:27:21 +00009536#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009537
9538/*
9539 * XXX - should get rid of. have all builtins use getopt(3). the
9540 * library getopt must have the BSD extension static variable "optreset"
9541 * otherwise it can't be used within the shell safely.
9542 *
9543 * Standard option processing (a la getopt) for builtin routines. The
9544 * only argument that is passed to nextopt is the option string; the
9545 * other arguments are unnecessary. It return the character, or '\0' on
9546 * end of input.
9547 */
9548
9549static int
Eric Andersen62483552001-07-10 06:09:16 +00009550nextopt(const char *optstring)
9551{
Eric Andersencb57d552001-06-28 07:25:16 +00009552 char *p;
9553 const char *q;
9554 char c;
9555
9556 if ((p = optptr) == NULL || *p == '\0') {
9557 p = *argptr;
9558 if (p == NULL || *p != '-' || *++p == '\0')
9559 return '\0';
9560 argptr++;
Eric Andersen2870d962001-07-02 17:27:21 +00009561 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009562 return '\0';
9563 }
9564 c = *p++;
9565 for (q = optstring ; *q != c ; ) {
9566 if (*q == '\0')
9567 error("Illegal option -%c", c);
9568 if (*++q == ':')
9569 q++;
9570 }
9571 if (*++q == ':') {
9572 if (*p == '\0' && (p = *argptr++) == NULL)
9573 error("No arg for -%c option", c);
9574 optionarg = p;
9575 p = NULL;
9576 }
9577 optptr = p;
9578 return c;
9579}
9580
Eric Andersencb57d552001-06-28 07:25:16 +00009581static void
9582flushall() {
Eric Andersencb57d552001-06-28 07:25:16 +00009583 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009584 fflush(stdout);
Eric Andersencb57d552001-06-28 07:25:16 +00009585 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009586}
9587
9588
9589static void
Eric Andersen3102ac42001-07-06 04:26:23 +00009590out2fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009591{
9592 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00009593 va_start(ap, fmt);
Eric Andersen3102ac42001-07-06 04:26:23 +00009594 vfprintf(stderr, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009595 va_end(ap);
9596}
9597
Eric Andersencb57d552001-06-28 07:25:16 +00009598/*
9599 * Version of write which resumes after a signal is caught.
9600 */
9601
9602static int
Eric Andersen2870d962001-07-02 17:27:21 +00009603xwrite(int fd, const char *buf, int nbytes)
9604{
Eric Andersencb57d552001-06-28 07:25:16 +00009605 int ntry;
9606 int i;
9607 int n;
9608
9609 n = nbytes;
9610 ntry = 0;
9611 for (;;) {
9612 i = write(fd, buf, n);
9613 if (i > 0) {
9614 if ((n -= i) <= 0)
9615 return nbytes;
9616 buf += i;
9617 ntry = 0;
9618 } else if (i == 0) {
9619 if (++ntry > 10)
9620 return nbytes - n;
9621 } else if (errno != EINTR) {
9622 return -1;
9623 }
9624 }
9625}
9626
9627
Eric Andersencb57d552001-06-28 07:25:16 +00009628/*
9629 * Shell command parser.
9630 */
9631
9632#define EOFMARKLEN 79
9633
9634
9635
9636struct heredoc {
Eric Andersen2870d962001-07-02 17:27:21 +00009637 struct heredoc *next; /* next here document in list */
9638 union node *here; /* redirection node */
9639 char *eofmark; /* string indicating end of input */
9640 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009641};
9642
Eric Andersen2870d962001-07-02 17:27:21 +00009643static struct heredoc *heredoclist; /* list of here documents to read */
9644static int parsebackquote; /* nonzero if we are inside backquotes */
9645static int doprompt; /* if set, prompt the user */
9646static int needprompt; /* true if interactive and at start of line */
9647static int lasttoken; /* last token read */
Eric Andersencb57d552001-06-28 07:25:16 +00009648
Eric Andersen2870d962001-07-02 17:27:21 +00009649static char *wordtext; /* text of last word returned by readtoken */
Eric Andersencb57d552001-06-28 07:25:16 +00009650
Eric Andersen2870d962001-07-02 17:27:21 +00009651static struct nodelist *backquotelist;
9652static union node *redirnode;
Eric Andersen044228d2001-07-17 01:12:36 +00009653static struct heredoc *heredoc;
Eric Andersen2870d962001-07-02 17:27:21 +00009654static int quoteflag; /* set if (part of) last token was quoted */
9655static int startlinno; /* line # where last token started */
Eric Andersencb57d552001-06-28 07:25:16 +00009656
9657
Eric Andersen2870d962001-07-02 17:27:21 +00009658static union node *list (int);
9659static union node *andor (void);
9660static union node *pipeline (void);
9661static union node *command (void);
9662static union node *simplecmd (void);
9663static void parsefname (void);
9664static void parseheredoc (void);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009665static char peektoken (void);
Eric Andersen2870d962001-07-02 17:27:21 +00009666static int readtoken (void);
9667static int xxreadtoken (void);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009668static int readtoken1 (int, int, const char *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00009669static int noexpand (char *);
9670static void synexpect (int) __attribute__((noreturn));
9671static void synerror (const char *) __attribute__((noreturn));
9672static void setprompt (int);
Eric Andersencb57d552001-06-28 07:25:16 +00009673
9674
9675/*
9676 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9677 * valid parse tree indicating a blank line.)
9678 */
9679
Eric Andersen2870d962001-07-02 17:27:21 +00009680static union node *
Eric Andersencb57d552001-06-28 07:25:16 +00009681parsecmd(int interact)
9682{
9683 int t;
9684
9685 tokpushback = 0;
9686 doprompt = interact;
9687 if (doprompt)
9688 setprompt(1);
9689 else
9690 setprompt(0);
9691 needprompt = 0;
9692 t = readtoken();
9693 if (t == TEOF)
9694 return NEOF;
9695 if (t == TNL)
9696 return NULL;
9697 tokpushback++;
9698 return list(1);
9699}
9700
9701
9702static union node *
9703list(nlflag)
9704 int nlflag;
9705{
9706 union node *n1, *n2, *n3;
9707 int tok;
9708
9709 checkkwd = 2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009710 if (nlflag == 0 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009711 return NULL;
9712 n1 = NULL;
9713 for (;;) {
9714 n2 = andor();
9715 tok = readtoken();
9716 if (tok == TBACKGND) {
9717 if (n2->type == NCMD || n2->type == NPIPE) {
9718 n2->ncmd.backgnd = 1;
9719 } else if (n2->type == NREDIR) {
9720 n2->type = NBACKGND;
9721 } else {
9722 n3 = (union node *)stalloc(sizeof (struct nredir));
9723 n3->type = NBACKGND;
9724 n3->nredir.n = n2;
9725 n3->nredir.redirect = NULL;
9726 n2 = n3;
9727 }
9728 }
9729 if (n1 == NULL) {
9730 n1 = n2;
9731 }
9732 else {
9733 n3 = (union node *)stalloc(sizeof (struct nbinary));
9734 n3->type = NSEMI;
9735 n3->nbinary.ch1 = n1;
9736 n3->nbinary.ch2 = n2;
9737 n1 = n3;
9738 }
9739 switch (tok) {
9740 case TBACKGND:
9741 case TSEMI:
9742 tok = readtoken();
9743 /* fall through */
9744 case TNL:
9745 if (tok == TNL) {
9746 parseheredoc();
9747 if (nlflag)
9748 return n1;
9749 } else {
9750 tokpushback++;
9751 }
9752 checkkwd = 2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009753 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009754 return n1;
9755 break;
9756 case TEOF:
9757 if (heredoclist)
9758 parseheredoc();
9759 else
Eric Andersen2870d962001-07-02 17:27:21 +00009760 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009761 return n1;
9762 default:
9763 if (nlflag)
9764 synexpect(-1);
9765 tokpushback++;
9766 return n1;
9767 }
9768 }
9769}
9770
9771
9772
9773static union node *
9774andor() {
9775 union node *n1, *n2, *n3;
9776 int t;
9777
9778 checkkwd = 1;
9779 n1 = pipeline();
9780 for (;;) {
9781 if ((t = readtoken()) == TAND) {
9782 t = NAND;
9783 } else if (t == TOR) {
9784 t = NOR;
9785 } else {
9786 tokpushback++;
9787 return n1;
9788 }
9789 checkkwd = 2;
9790 n2 = pipeline();
9791 n3 = (union node *)stalloc(sizeof (struct nbinary));
9792 n3->type = t;
9793 n3->nbinary.ch1 = n1;
9794 n3->nbinary.ch2 = n2;
9795 n1 = n3;
9796 }
9797}
9798
9799
9800
9801static union node *
9802pipeline() {
9803 union node *n1, *n2, *pipenode;
9804 struct nodelist *lp, *prev;
9805 int negate;
9806
9807 negate = 0;
9808 TRACE(("pipeline: entered\n"));
9809 if (readtoken() == TNOT) {
9810 negate = !negate;
9811 checkkwd = 1;
9812 } else
9813 tokpushback++;
9814 n1 = command();
9815 if (readtoken() == TPIPE) {
9816 pipenode = (union node *)stalloc(sizeof (struct npipe));
9817 pipenode->type = NPIPE;
9818 pipenode->npipe.backgnd = 0;
9819 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9820 pipenode->npipe.cmdlist = lp;
9821 lp->n = n1;
9822 do {
9823 prev = lp;
9824 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9825 checkkwd = 2;
9826 lp->n = command();
9827 prev->next = lp;
9828 } while (readtoken() == TPIPE);
9829 lp->next = NULL;
9830 n1 = pipenode;
9831 }
9832 tokpushback++;
9833 if (negate) {
9834 n2 = (union node *)stalloc(sizeof (struct nnot));
9835 n2->type = NNOT;
9836 n2->nnot.com = n1;
9837 return n2;
9838 } else
9839 return n1;
9840}
9841
9842
9843
9844static union node *
9845command() {
9846 union node *n1, *n2;
9847 union node *ap, **app;
9848 union node *cp, **cpp;
9849 union node *redir, **rpp;
9850 int t;
9851
9852 redir = NULL;
9853 n1 = NULL;
9854 rpp = &redir;
9855
9856 switch (readtoken()) {
9857 case TIF:
9858 n1 = (union node *)stalloc(sizeof (struct nif));
9859 n1->type = NIF;
9860 n1->nif.test = list(0);
9861 if (readtoken() != TTHEN)
9862 synexpect(TTHEN);
9863 n1->nif.ifpart = list(0);
9864 n2 = n1;
9865 while (readtoken() == TELIF) {
9866 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9867 n2 = n2->nif.elsepart;
9868 n2->type = NIF;
9869 n2->nif.test = list(0);
9870 if (readtoken() != TTHEN)
9871 synexpect(TTHEN);
9872 n2->nif.ifpart = list(0);
9873 }
9874 if (lasttoken == TELSE)
9875 n2->nif.elsepart = list(0);
9876 else {
9877 n2->nif.elsepart = NULL;
9878 tokpushback++;
9879 }
9880 if (readtoken() != TFI)
9881 synexpect(TFI);
9882 checkkwd = 1;
9883 break;
9884 case TWHILE:
9885 case TUNTIL: {
9886 int got;
9887 n1 = (union node *)stalloc(sizeof (struct nbinary));
9888 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9889 n1->nbinary.ch1 = list(0);
9890 if ((got=readtoken()) != TDO) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009891TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009892 synexpect(TDO);
9893 }
9894 n1->nbinary.ch2 = list(0);
9895 if (readtoken() != TDONE)
9896 synexpect(TDONE);
9897 checkkwd = 1;
9898 break;
9899 }
9900 case TFOR:
9901 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9902 synerror("Bad for loop variable");
9903 n1 = (union node *)stalloc(sizeof (struct nfor));
9904 n1->type = NFOR;
9905 n1->nfor.var = wordtext;
9906 checkkwd = 1;
9907 if (readtoken() == TIN) {
9908 app = &ap;
9909 while (readtoken() == TWORD) {
9910 n2 = (union node *)stalloc(sizeof (struct narg));
9911 n2->type = NARG;
9912 n2->narg.text = wordtext;
9913 n2->narg.backquote = backquotelist;
9914 *app = n2;
9915 app = &n2->narg.next;
9916 }
9917 *app = NULL;
9918 n1->nfor.args = ap;
9919 if (lasttoken != TNL && lasttoken != TSEMI)
9920 synexpect(-1);
9921 } else {
9922 static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
9923 '@', '=', '\0'};
9924 n2 = (union node *)stalloc(sizeof (struct narg));
9925 n2->type = NARG;
9926 n2->narg.text = argvars;
9927 n2->narg.backquote = NULL;
9928 n2->narg.next = NULL;
9929 n1->nfor.args = n2;
9930 /*
9931 * Newline or semicolon here is optional (but note
9932 * that the original Bourne shell only allowed NL).
9933 */
9934 if (lasttoken != TNL && lasttoken != TSEMI)
9935 tokpushback++;
9936 }
9937 checkkwd = 2;
9938 if (readtoken() != TDO)
9939 synexpect(TDO);
9940 n1->nfor.body = list(0);
9941 if (readtoken() != TDONE)
9942 synexpect(TDONE);
9943 checkkwd = 1;
9944 break;
9945 case TCASE:
9946 n1 = (union node *)stalloc(sizeof (struct ncase));
9947 n1->type = NCASE;
9948 if (readtoken() != TWORD)
9949 synexpect(TWORD);
9950 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9951 n2->type = NARG;
9952 n2->narg.text = wordtext;
9953 n2->narg.backquote = backquotelist;
9954 n2->narg.next = NULL;
9955 do {
9956 checkkwd = 1;
9957 } while (readtoken() == TNL);
9958 if (lasttoken != TIN)
9959 synerror("expecting \"in\"");
9960 cpp = &n1->ncase.cases;
9961 checkkwd = 2, readtoken();
9962 do {
9963 if (lasttoken == TLP)
9964 readtoken();
9965 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9966 cp->type = NCLIST;
9967 app = &cp->nclist.pattern;
9968 for (;;) {
9969 *app = ap = (union node *)stalloc(sizeof (struct narg));
9970 ap->type = NARG;
9971 ap->narg.text = wordtext;
9972 ap->narg.backquote = backquotelist;
9973 if (checkkwd = 2, readtoken() != TPIPE)
9974 break;
9975 app = &ap->narg.next;
9976 readtoken();
9977 }
9978 ap->narg.next = NULL;
9979 if (lasttoken != TRP)
9980 synexpect(TRP);
9981 cp->nclist.body = list(0);
9982
9983 checkkwd = 2;
9984 if ((t = readtoken()) != TESAC) {
9985 if (t != TENDCASE)
9986 synexpect(TENDCASE);
9987 else
9988 checkkwd = 2, readtoken();
9989 }
9990 cpp = &cp->nclist.next;
9991 } while(lasttoken != TESAC);
9992 *cpp = NULL;
9993 checkkwd = 1;
9994 break;
9995 case TLP:
9996 n1 = (union node *)stalloc(sizeof (struct nredir));
9997 n1->type = NSUBSHELL;
9998 n1->nredir.n = list(0);
9999 n1->nredir.redirect = NULL;
10000 if (readtoken() != TRP)
10001 synexpect(TRP);
10002 checkkwd = 1;
10003 break;
10004 case TBEGIN:
10005 n1 = list(0);
10006 if (readtoken() != TEND)
10007 synexpect(TEND);
10008 checkkwd = 1;
10009 break;
10010 /* Handle an empty command like other simple commands. */
10011 case TSEMI:
10012 case TAND:
10013 case TOR:
10014 case TNL:
10015 case TEOF:
10016 case TRP:
10017 case TBACKGND:
10018 /*
10019 * An empty command before a ; doesn't make much sense, and
10020 * should certainly be disallowed in the case of `if ;'.
10021 */
10022 if (!redir)
10023 synexpect(-1);
10024 case TWORD:
10025 case TREDIR:
10026 tokpushback++;
10027 n1 = simplecmd();
10028 return n1;
10029 default:
10030 synexpect(-1);
10031 /* NOTREACHED */
10032 }
10033
10034 /* Now check for redirection which may follow command */
10035 while (readtoken() == TREDIR) {
10036 *rpp = n2 = redirnode;
10037 rpp = &n2->nfile.next;
10038 parsefname();
10039 }
10040 tokpushback++;
10041 *rpp = NULL;
10042 if (redir) {
10043 if (n1->type != NSUBSHELL) {
10044 n2 = (union node *)stalloc(sizeof (struct nredir));
10045 n2->type = NREDIR;
10046 n2->nredir.n = n1;
10047 n1 = n2;
10048 }
10049 n1->nredir.redirect = redir;
10050 }
10051
10052 return n1;
10053}
10054
10055
10056static union node *
10057simplecmd() {
10058 union node *args, **app;
10059 union node *n = NULL;
10060 union node *vars, **vpp;
10061 union node **rpp, *redir;
10062
10063 args = NULL;
10064 app = &args;
10065 vars = NULL;
10066 vpp = &vars;
10067 redir = NULL;
10068 rpp = &redir;
10069
10070 checkalias = 2;
10071 for (;;) {
10072 switch (readtoken()) {
10073 case TWORD:
10074 case TASSIGN:
10075 n = (union node *)stalloc(sizeof (struct narg));
10076 n->type = NARG;
10077 n->narg.text = wordtext;
10078 n->narg.backquote = backquotelist;
10079 if (lasttoken == TWORD) {
10080 *app = n;
10081 app = &n->narg.next;
10082 } else {
10083 *vpp = n;
10084 vpp = &n->narg.next;
10085 }
10086 break;
10087 case TREDIR:
10088 *rpp = n = redirnode;
10089 rpp = &n->nfile.next;
Eric Andersen2870d962001-07-02 17:27:21 +000010090 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +000010091 break;
10092 case TLP:
10093 if (
10094 args && app == &args->narg.next &&
10095 !vars && !redir
10096 ) {
10097 /* We have a function */
10098 if (readtoken() != TRP)
10099 synexpect(TRP);
Eric Andersencb57d552001-06-28 07:25:16 +000010100 n->type = NDEFUN;
10101 checkkwd = 2;
10102 n->narg.next = command();
10103 return n;
10104 }
10105 /* fall through */
10106 default:
10107 tokpushback++;
10108 goto out;
10109 }
10110 }
10111out:
10112 *app = NULL;
10113 *vpp = NULL;
10114 *rpp = NULL;
10115 n = (union node *)stalloc(sizeof (struct ncmd));
10116 n->type = NCMD;
10117 n->ncmd.backgnd = 0;
10118 n->ncmd.args = args;
10119 n->ncmd.assign = vars;
10120 n->ncmd.redirect = redir;
10121 return n;
10122}
10123
10124static union node *
Eric Andersen2870d962001-07-02 17:27:21 +000010125makename(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000010126 union node *n;
10127
10128 n = (union node *)stalloc(sizeof (struct narg));
10129 n->type = NARG;
10130 n->narg.next = NULL;
10131 n->narg.text = wordtext;
10132 n->narg.backquote = backquotelist;
10133 return n;
10134}
10135
10136static void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +000010137{
Eric Andersencb57d552001-06-28 07:25:16 +000010138 TRACE(("Fix redir %s %d\n", text, err));
10139 if (!err)
10140 n->ndup.vname = NULL;
10141
10142 if (is_digit(text[0]) && text[1] == '\0')
10143 n->ndup.dupfd = digit_val(text[0]);
10144 else if (text[0] == '-' && text[1] == '\0')
10145 n->ndup.dupfd = -1;
10146 else {
10147
10148 if (err)
10149 synerror("Bad fd number");
10150 else
10151 n->ndup.vname = makename();
10152 }
10153}
10154
10155
10156static void
Eric Andersen2870d962001-07-02 17:27:21 +000010157parsefname(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000010158 union node *n = redirnode;
10159
10160 if (readtoken() != TWORD)
10161 synexpect(-1);
10162 if (n->type == NHERE) {
10163 struct heredoc *here = heredoc;
10164 struct heredoc *p;
10165 int i;
10166
10167 if (quoteflag == 0)
10168 n->type = NXHERE;
10169 TRACE(("Here document %d\n", n->type));
10170 if (here->striptabs) {
10171 while (*wordtext == '\t')
10172 wordtext++;
10173 }
10174 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
10175 synerror("Illegal eof marker for << redirection");
10176 rmescapes(wordtext);
10177 here->eofmark = wordtext;
10178 here->next = NULL;
10179 if (heredoclist == NULL)
10180 heredoclist = here;
10181 else {
10182 for (p = heredoclist ; p->next ; p = p->next);
10183 p->next = here;
10184 }
10185 } else if (n->type == NTOFD || n->type == NFROMFD) {
10186 fixredir(n, wordtext, 0);
10187 } else {
10188 n->nfile.fname = makename();
10189 }
10190}
10191
10192
10193/*
10194 * Input any here documents.
10195 */
10196
10197static void
10198parseheredoc() {
10199 struct heredoc *here;
10200 union node *n;
10201
10202 while (heredoclist) {
10203 here = heredoclist;
10204 heredoclist = here->next;
10205 if (needprompt) {
10206 setprompt(2);
10207 needprompt = 0;
10208 }
10209 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
10210 here->eofmark, here->striptabs);
10211 n = (union node *)stalloc(sizeof (struct narg));
10212 n->narg.type = NARG;
10213 n->narg.next = NULL;
10214 n->narg.text = wordtext;
10215 n->narg.backquote = backquotelist;
10216 here->here->nhere.doc = n;
10217 }
10218}
10219
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010220static char
Eric Andersencb57d552001-06-28 07:25:16 +000010221peektoken() {
10222 int t;
10223
10224 t = readtoken();
10225 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010226 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +000010227}
10228
10229static int
10230readtoken() {
10231 int t;
Eric Andersen7467c8d2001-07-12 20:26:32 +000010232
Eric Andersen2870d962001-07-02 17:27:21 +000010233#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010234 int savecheckalias = checkalias;
Eric Andersen7467c8d2001-07-12 20:26:32 +000010235 int savecheckkwd = checkkwd;
Eric Andersencb57d552001-06-28 07:25:16 +000010236 struct alias *ap;
Eric Andersen2870d962001-07-02 17:27:21 +000010237#endif
10238
Eric Andersencb57d552001-06-28 07:25:16 +000010239#ifdef DEBUG
10240 int alreadyseen = tokpushback;
10241#endif
10242
Eric Andersen2870d962001-07-02 17:27:21 +000010243#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010244top:
Eric Andersen2870d962001-07-02 17:27:21 +000010245#endif
10246
Eric Andersencb57d552001-06-28 07:25:16 +000010247 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +000010248
10249#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010250 checkalias = savecheckalias;
Eric Andersen2870d962001-07-02 17:27:21 +000010251#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010252
10253 if (checkkwd) {
10254 /*
10255 * eat newlines
10256 */
10257 if (checkkwd == 2) {
10258 checkkwd = 0;
10259 while (t == TNL) {
10260 parseheredoc();
10261 t = xxreadtoken();
10262 }
10263 }
10264 checkkwd = 0;
10265 /*
10266 * check for keywords
10267 */
10268 if (t == TWORD && !quoteflag)
10269 {
10270 const char *const *pp;
10271
10272 if ((pp = findkwd(wordtext))) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010273 lasttoken = t = pp - tokname_array;
10274 TRACE(("keyword %s recognized\n", tokname(t)));
Eric Andersencb57d552001-06-28 07:25:16 +000010275 goto out;
10276 }
10277 }
10278 }
10279
Eric Andersen7467c8d2001-07-12 20:26:32 +000010280
Eric Andersencb57d552001-06-28 07:25:16 +000010281 if (t != TWORD) {
10282 if (t != TREDIR) {
10283 checkalias = 0;
10284 }
10285 } else if (checkalias == 2 && isassignment(wordtext)) {
10286 lasttoken = t = TASSIGN;
Eric Andersen7467c8d2001-07-12 20:26:32 +000010287#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010288 } else if (checkalias) {
10289 if (!quoteflag && (ap = lookupalias(wordtext, 1)) != NULL) {
10290 if (*ap->val) {
10291 pushstring(ap->val, strlen(ap->val), ap);
10292 }
10293 checkkwd = savecheckkwd;
10294 goto top;
10295 }
10296 checkalias = 0;
Eric Andersen2870d962001-07-02 17:27:21 +000010297#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +000010298 }
Eric Andersencb57d552001-06-28 07:25:16 +000010299out:
10300#ifdef DEBUG
10301 if (!alreadyseen)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010302 TRACE(("token %s %s\n", tokname(t), t == TWORD || t == TASSIGN ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +000010303 else
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010304 TRACE(("reread token %s %s\n", tokname(t), t == TWORD || t == TASSIGN ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +000010305#endif
10306 return (t);
10307}
10308
10309
10310/*
10311 * Read the next input token.
10312 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +000010313 * backquotes. We set quoteflag to true if any part of the word was
10314 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +000010315 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +000010316 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +000010317 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +000010318 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +000010319 *
10320 * [Change comment: here documents and internal procedures]
10321 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10322 * word parsing code into a separate routine. In this case, readtoken
10323 * doesn't need to have any internal procedures, but parseword does.
10324 * We could also make parseoperator in essence the main routine, and
10325 * have parseword (readtoken1?) handle both words and redirection.]
10326 */
10327
Eric Andersen2870d962001-07-02 17:27:21 +000010328#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010329
10330static int
10331xxreadtoken() {
10332 int c;
10333
10334 if (tokpushback) {
10335 tokpushback = 0;
10336 return lasttoken;
10337 }
10338 if (needprompt) {
10339 setprompt(2);
10340 needprompt = 0;
10341 }
10342 startlinno = plinno;
Eric Andersen2870d962001-07-02 17:27:21 +000010343 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010344 c = pgetc_macro();
10345 switch (c) {
10346 case ' ': case '\t':
Eric Andersen3102ac42001-07-06 04:26:23 +000010347#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010348 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010349#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010350 continue;
10351 case '#':
10352 while ((c = pgetc()) != '\n' && c != PEOF);
10353 pungetc();
10354 continue;
10355 case '\\':
10356 if (pgetc() == '\n') {
10357 startlinno = ++plinno;
10358 if (doprompt)
10359 setprompt(2);
10360 else
10361 setprompt(0);
10362 continue;
10363 }
10364 pungetc();
10365 goto breakloop;
10366 case '\n':
10367 plinno++;
10368 needprompt = doprompt;
10369 RETURN(TNL);
10370 case PEOF:
10371 RETURN(TEOF);
10372 case '&':
10373 if (pgetc() == '&')
10374 RETURN(TAND);
10375 pungetc();
10376 RETURN(TBACKGND);
10377 case '|':
10378 if (pgetc() == '|')
10379 RETURN(TOR);
10380 pungetc();
10381 RETURN(TPIPE);
10382 case ';':
10383 if (pgetc() == ';')
10384 RETURN(TENDCASE);
10385 pungetc();
10386 RETURN(TSEMI);
10387 case '(':
10388 RETURN(TLP);
10389 case ')':
10390 RETURN(TRP);
10391 default:
10392 goto breakloop;
10393 }
10394 }
10395breakloop:
10396 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10397#undef RETURN
10398}
10399
10400
10401
10402/*
10403 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10404 * is not NULL, read a here document. In the latter case, eofmark is the
10405 * word which marks the end of the document and striptabs is true if
10406 * leading tabs should be stripped from the document. The argument firstc
10407 * is the first character of the input token or document.
10408 *
10409 * Because C does not have internal subroutines, I have simulated them
10410 * using goto's to implement the subroutine linkage. The following macros
10411 * will run code that appears at the end of readtoken1.
10412 */
10413
Eric Andersen2870d962001-07-02 17:27:21 +000010414#define CHECKEND() {goto checkend; checkend_return:;}
10415#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10416#define PARSESUB() {goto parsesub; parsesub_return:;}
10417#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10418#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10419#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010420
10421static int
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010422readtoken1(int firstc, int syntax, const char *eofmark, int striptabs)
10423{
Eric Andersencb57d552001-06-28 07:25:16 +000010424 int c = firstc;
10425 char *out;
10426 int len;
10427 char line[EOFMARKLEN + 1];
10428 struct nodelist *bqlist;
10429 int quotef;
10430 int dblquote;
Eric Andersen2870d962001-07-02 17:27:21 +000010431 int varnest; /* levels of variables expansion */
10432 int arinest; /* levels of arithmetic expansion */
10433 int parenlevel; /* levels of parens in arithmetic */
10434 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +000010435 int oldstyle;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010436 int prevsyntax; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010437#if __GNUC__
10438 /* Avoid longjmp clobbering */
10439 (void) &out;
10440 (void) &quotef;
10441 (void) &dblquote;
10442 (void) &varnest;
10443 (void) &arinest;
10444 (void) &parenlevel;
10445 (void) &dqvarnest;
10446 (void) &oldstyle;
10447 (void) &prevsyntax;
10448 (void) &syntax;
10449#endif
10450
10451 startlinno = plinno;
10452 dblquote = 0;
10453 if (syntax == DQSYNTAX)
10454 dblquote = 1;
10455 quotef = 0;
10456 bqlist = NULL;
10457 varnest = 0;
10458 arinest = 0;
10459 parenlevel = 0;
10460 dqvarnest = 0;
10461
10462 STARTSTACKSTR(out);
Eric Andersen2870d962001-07-02 17:27:21 +000010463 loop: { /* for each line, until end of word */
10464 CHECKEND(); /* set c to PEOF if at end of here document */
10465 for (;;) { /* until end of line or end of word */
10466 CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010467 switch(SIT(c,syntax)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010468 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010469 if (syntax == BASESYNTAX)
Eric Andersen2870d962001-07-02 17:27:21 +000010470 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010471 USTPUTC(c, out);
10472 plinno++;
10473 if (doprompt)
10474 setprompt(2);
10475 else
10476 setprompt(0);
10477 c = pgetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010478 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010479 case CWORD:
10480 USTPUTC(c, out);
10481 break;
10482 case CCTL:
10483 if ((eofmark == NULL || dblquote) &&
10484 dqvarnest == 0)
10485 USTPUTC(CTLESC, out);
10486 USTPUTC(c, out);
10487 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010488 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010489 c = pgetc2();
10490 if (c == PEOF) {
10491 USTPUTC('\\', out);
10492 pungetc();
10493 } else if (c == '\n') {
10494 if (doprompt)
10495 setprompt(2);
10496 else
10497 setprompt(0);
10498 } else {
10499 if (dblquote && c != '\\' && c != '`' && c != '$'
10500 && (c != '"' || eofmark != NULL))
10501 USTPUTC('\\', out);
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010502 if (SIT(c,SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010503 USTPUTC(CTLESC, out);
10504 else if (eofmark == NULL)
10505 USTPUTC(CTLQUOTEMARK, out);
10506 USTPUTC(c, out);
10507 quotef++;
10508 }
10509 break;
10510 case CSQUOTE:
10511 if (eofmark == NULL)
10512 USTPUTC(CTLQUOTEMARK, out);
10513 syntax = SQSYNTAX;
10514 break;
10515 case CDQUOTE:
10516 if (eofmark == NULL)
10517 USTPUTC(CTLQUOTEMARK, out);
10518 syntax = DQSYNTAX;
10519 dblquote = 1;
10520 break;
10521 case CENDQUOTE:
10522 if (eofmark != NULL && arinest == 0 &&
10523 varnest == 0) {
10524 USTPUTC(c, out);
10525 } else {
10526 if (arinest) {
10527 syntax = ARISYNTAX;
10528 dblquote = 0;
10529 } else if (eofmark == NULL &&
10530 dqvarnest == 0) {
10531 syntax = BASESYNTAX;
10532 dblquote = 0;
10533 }
10534 quotef++;
10535 }
10536 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010537 case CVAR: /* '$' */
10538 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010539 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010540 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010541 if (varnest > 0) {
10542 varnest--;
10543 if (dqvarnest > 0) {
10544 dqvarnest--;
10545 }
10546 USTPUTC(CTLENDVAR, out);
10547 } else {
10548 USTPUTC(c, out);
10549 }
10550 break;
10551#ifdef ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +000010552 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010553 parenlevel++;
10554 USTPUTC(c, out);
10555 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010556 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010557 if (parenlevel > 0) {
10558 USTPUTC(c, out);
10559 --parenlevel;
10560 } else {
10561 if (pgetc() == ')') {
10562 if (--arinest == 0) {
10563 USTPUTC(CTLENDARI, out);
10564 syntax = prevsyntax;
10565 if (syntax == DQSYNTAX)
10566 dblquote = 1;
10567 else
10568 dblquote = 0;
10569 } else
10570 USTPUTC(')', out);
10571 } else {
10572 /*
10573 * unbalanced parens
10574 * (don't 2nd guess - no error)
10575 */
10576 pungetc();
10577 USTPUTC(')', out);
10578 }
10579 }
10580 break;
10581#endif
Eric Andersen2870d962001-07-02 17:27:21 +000010582 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010583 PARSEBACKQOLD();
10584 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010585 case CENDFILE:
10586 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010587 case CIGN:
10588 break;
10589 default:
10590 if (varnest == 0)
Eric Andersen2870d962001-07-02 17:27:21 +000010591 goto endword; /* exit outer loop */
Eric Andersen3102ac42001-07-06 04:26:23 +000010592#ifdef ASH_ALIAS
10593 if (c != PEOA)
10594#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010595 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010596
Eric Andersencb57d552001-06-28 07:25:16 +000010597 }
10598 c = pgetc_macro();
10599 }
10600 }
10601endword:
10602 if (syntax == ARISYNTAX)
10603 synerror("Missing '))'");
10604 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10605 synerror("Unterminated quoted string");
10606 if (varnest != 0) {
10607 startlinno = plinno;
10608 synerror("Missing '}'");
10609 }
10610 USTPUTC('\0', out);
10611 len = out - stackblock();
10612 out = stackblock();
10613 if (eofmark == NULL) {
10614 if ((c == '>' || c == '<')
10615 && quotef == 0
10616 && len <= 2
10617 && (*out == '\0' || is_digit(*out))) {
10618 PARSEREDIR();
10619 return lasttoken = TREDIR;
10620 } else {
10621 pungetc();
10622 }
10623 }
10624 quoteflag = quotef;
10625 backquotelist = bqlist;
10626 grabstackblock(len);
10627 wordtext = out;
10628 return lasttoken = TWORD;
10629/* end of readtoken routine */
10630
10631
10632
10633/*
10634 * Check to see whether we are at the end of the here document. When this
10635 * is called, c is set to the first character of the next input line. If
10636 * we are at the end of the here document, this routine sets the c to PEOF.
10637 */
10638
10639checkend: {
10640 if (eofmark) {
Eric Andersen2870d962001-07-02 17:27:21 +000010641#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010642 if (c == PEOA) {
10643 c = pgetc2();
10644 }
Eric Andersen2870d962001-07-02 17:27:21 +000010645#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010646 if (striptabs) {
10647 while (c == '\t') {
10648 c = pgetc2();
10649 }
10650 }
10651 if (c == *eofmark) {
10652 if (pfgets(line, sizeof line) != NULL) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010653 const char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010654
10655 p = line;
10656 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10657 if (*p == '\n' && *q == '\0') {
10658 c = PEOF;
10659 plinno++;
10660 needprompt = doprompt;
10661 } else {
10662 pushstring(line, strlen(line), NULL);
10663 }
10664 }
10665 }
10666 }
10667 goto checkend_return;
10668}
10669
10670
10671/*
10672 * Parse a redirection operator. The variable "out" points to a string
10673 * specifying the fd to be redirected. The variable "c" contains the
10674 * first character of the redirection operator.
10675 */
10676
10677parseredir: {
10678 char fd = *out;
10679 union node *np;
10680
10681 np = (union node *)stalloc(sizeof (struct nfile));
10682 if (c == '>') {
10683 np->nfile.fd = 1;
10684 c = pgetc();
10685 if (c == '>')
10686 np->type = NAPPEND;
10687 else if (c == '&')
10688 np->type = NTOFD;
10689 else if (c == '|')
10690 np->type = NTOOV;
10691 else {
10692 np->type = NTO;
10693 pungetc();
10694 }
Eric Andersen2870d962001-07-02 17:27:21 +000010695 } else { /* c == '<' */
Eric Andersencb57d552001-06-28 07:25:16 +000010696 np->nfile.fd = 0;
10697 switch (c = pgetc()) {
10698 case '<':
10699 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10700 np = (union node *)stalloc(sizeof (struct nhere));
10701 np->nfile.fd = 0;
10702 }
10703 np->type = NHERE;
10704 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10705 heredoc->here = np;
10706 if ((c = pgetc()) == '-') {
10707 heredoc->striptabs = 1;
10708 } else {
10709 heredoc->striptabs = 0;
10710 pungetc();
10711 }
10712 break;
10713
10714 case '&':
10715 np->type = NFROMFD;
10716 break;
10717
10718 case '>':
10719 np->type = NFROMTO;
10720 break;
10721
10722 default:
10723 np->type = NFROM;
10724 pungetc();
10725 break;
10726 }
10727 }
10728 if (fd != '\0')
10729 np->nfile.fd = digit_val(fd);
10730 redirnode = np;
10731 goto parseredir_return;
10732}
10733
10734
10735/*
10736 * Parse a substitution. At this point, we have read the dollar sign
10737 * and nothing else.
10738 */
10739
10740parsesub: {
10741 int subtype;
10742 int typeloc;
10743 int flags;
10744 char *p;
10745 static const char types[] = "}-+?=";
10746
10747 c = pgetc();
10748 if (
10749 c <= PEOA ||
10750 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10751 ) {
10752 USTPUTC('$', out);
10753 pungetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010754 } else if (c == '(') { /* $(command) or $((arith)) */
Eric Andersencb57d552001-06-28 07:25:16 +000010755 if (pgetc() == '(') {
10756 PARSEARITH();
10757 } else {
10758 pungetc();
10759 PARSEBACKQNEW();
10760 }
10761 } else {
10762 USTPUTC(CTLVAR, out);
10763 typeloc = out - stackblock();
10764 USTPUTC(VSNORMAL, out);
10765 subtype = VSNORMAL;
10766 if (c == '{') {
10767 c = pgetc();
10768 if (c == '#') {
10769 if ((c = pgetc()) == '}')
10770 c = '#';
10771 else
10772 subtype = VSLENGTH;
10773 }
10774 else
10775 subtype = 0;
10776 }
10777 if (c > PEOA && is_name(c)) {
10778 do {
10779 STPUTC(c, out);
10780 c = pgetc();
10781 } while (c > PEOA && is_in_name(c));
10782 } else if (is_digit(c)) {
10783 do {
10784 USTPUTC(c, out);
10785 c = pgetc();
10786 } while (is_digit(c));
10787 }
10788 else if (is_special(c)) {
10789 USTPUTC(c, out);
10790 c = pgetc();
10791 }
10792 else
Eric Andersen2870d962001-07-02 17:27:21 +000010793badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010794
10795 STPUTC('=', out);
10796 flags = 0;
10797 if (subtype == 0) {
10798 switch (c) {
10799 case ':':
10800 flags = VSNUL;
10801 c = pgetc();
10802 /*FALLTHROUGH*/
10803 default:
10804 p = strchr(types, c);
10805 if (p == NULL)
10806 goto badsub;
10807 subtype = p - types + VSNORMAL;
10808 break;
10809 case '%':
10810 case '#':
10811 {
10812 int cc = c;
10813 subtype = c == '#' ? VSTRIMLEFT :
10814 VSTRIMRIGHT;
10815 c = pgetc();
10816 if (c == cc)
10817 subtype++;
10818 else
10819 pungetc();
10820 break;
10821 }
10822 }
10823 } else {
10824 pungetc();
10825 }
10826 if (dblquote || arinest)
10827 flags |= VSQUOTE;
10828 *(stackblock() + typeloc) = subtype | flags;
10829 if (subtype != VSNORMAL) {
10830 varnest++;
10831 if (dblquote) {
10832 dqvarnest++;
10833 }
10834 }
10835 }
10836 goto parsesub_return;
10837}
10838
10839
10840/*
10841 * Called to parse command substitutions. Newstyle is set if the command
10842 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10843 * list of commands (passed by reference), and savelen is the number of
10844 * characters on the top of the stack which must be preserved.
10845 */
10846
10847parsebackq: {
10848 struct nodelist **nlpp;
10849 int savepbq;
10850 union node *n;
10851 char *volatile str;
10852 struct jmploc jmploc;
10853 struct jmploc *volatile savehandler;
10854 int savelen;
10855 int saveprompt;
10856#ifdef __GNUC__
10857 (void) &saveprompt;
10858#endif
10859
10860 savepbq = parsebackquote;
10861 if (setjmp(jmploc.loc)) {
10862 if (str)
10863 ckfree(str);
10864 parsebackquote = 0;
10865 handler = savehandler;
10866 longjmp(handler->loc, 1);
10867 }
10868 INTOFF;
10869 str = NULL;
10870 savelen = out - stackblock();
10871 if (savelen > 0) {
10872 str = ckmalloc(savelen);
10873 memcpy(str, stackblock(), savelen);
10874 }
10875 savehandler = handler;
10876 handler = &jmploc;
10877 INTON;
Eric Andersen2870d962001-07-02 17:27:21 +000010878 if (oldstyle) {
10879 /* We must read until the closing backquote, giving special
10880 treatment to some slashes, and then push the string and
10881 reread it as input, interpreting it normally. */
10882 char *pout;
10883 int pc;
10884 int psavelen;
10885 char *pstr;
Eric Andersencb57d552001-06-28 07:25:16 +000010886
10887
Eric Andersen2870d962001-07-02 17:27:21 +000010888 STARTSTACKSTR(pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010889 for (;;) {
10890 if (needprompt) {
10891 setprompt(2);
10892 needprompt = 0;
10893 }
10894 switch (pc = pgetc()) {
10895 case '`':
10896 goto done;
10897
10898 case '\\':
Eric Andersen2870d962001-07-02 17:27:21 +000010899 if ((pc = pgetc()) == '\n') {
Eric Andersencb57d552001-06-28 07:25:16 +000010900 plinno++;
10901 if (doprompt)
10902 setprompt(2);
10903 else
10904 setprompt(0);
10905 /*
10906 * If eating a newline, avoid putting
10907 * the newline into the new character
10908 * stream (via the STPUTC after the
10909 * switch).
10910 */
10911 continue;
10912 }
Eric Andersen2870d962001-07-02 17:27:21 +000010913 if (pc != '\\' && pc != '`' && pc != '$'
10914 && (!dblquote || pc != '"'))
10915 STPUTC('\\', pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010916 if (pc > PEOA) {
10917 break;
10918 }
10919 /* fall through */
10920
10921 case PEOF:
Eric Andersen2870d962001-07-02 17:27:21 +000010922#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010923 case PEOA:
Eric Andersen2870d962001-07-02 17:27:21 +000010924#endif
10925 startlinno = plinno;
Eric Andersencb57d552001-06-28 07:25:16 +000010926 synerror("EOF in backquote substitution");
10927
10928 case '\n':
10929 plinno++;
10930 needprompt = doprompt;
10931 break;
10932
10933 default:
10934 break;
10935 }
10936 STPUTC(pc, pout);
Eric Andersen2870d962001-07-02 17:27:21 +000010937 }
Eric Andersencb57d552001-06-28 07:25:16 +000010938done:
Eric Andersen2870d962001-07-02 17:27:21 +000010939 STPUTC('\0', pout);
10940 psavelen = pout - stackblock();
10941 if (psavelen > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010942 pstr = grabstackstr(pout);
10943 setinputstring(pstr);
Eric Andersen2870d962001-07-02 17:27:21 +000010944 }
10945 }
Eric Andersencb57d552001-06-28 07:25:16 +000010946 nlpp = &bqlist;
10947 while (*nlpp)
10948 nlpp = &(*nlpp)->next;
10949 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10950 (*nlpp)->next = NULL;
10951 parsebackquote = oldstyle;
10952
10953 if (oldstyle) {
10954 saveprompt = doprompt;
10955 doprompt = 0;
10956 }
10957
10958 n = list(0);
10959
10960 if (oldstyle)
10961 doprompt = saveprompt;
10962 else {
10963 if (readtoken() != TRP)
10964 synexpect(TRP);
10965 }
10966
10967 (*nlpp)->n = n;
Eric Andersen2870d962001-07-02 17:27:21 +000010968 if (oldstyle) {
Eric Andersencb57d552001-06-28 07:25:16 +000010969 /*
10970 * Start reading from old file again, ignoring any pushed back
10971 * tokens left from the backquote parsing
10972 */
Eric Andersen2870d962001-07-02 17:27:21 +000010973 popfile();
Eric Andersencb57d552001-06-28 07:25:16 +000010974 tokpushback = 0;
10975 }
10976 while (stackblocksize() <= savelen)
10977 growstackblock();
10978 STARTSTACKSTR(out);
10979 if (str) {
10980 memcpy(out, str, savelen);
10981 STADJUST(savelen, out);
10982 INTOFF;
10983 ckfree(str);
10984 str = NULL;
10985 INTON;
10986 }
10987 parsebackquote = savepbq;
10988 handler = savehandler;
10989 if (arinest || dblquote)
10990 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10991 else
10992 USTPUTC(CTLBACKQ, out);
10993 if (oldstyle)
10994 goto parsebackq_oldreturn;
10995 else
10996 goto parsebackq_newreturn;
10997}
10998
10999/*
11000 * Parse an arithmetic expansion (indicate start of one and set state)
11001 */
11002parsearith: {
11003
11004 if (++arinest == 1) {
11005 prevsyntax = syntax;
11006 syntax = ARISYNTAX;
11007 USTPUTC(CTLARI, out);
11008 if (dblquote)
11009 USTPUTC('"',out);
11010 else
11011 USTPUTC(' ',out);
11012 } else {
11013 /*
11014 * we collapse embedded arithmetic expansion to
11015 * parenthesis, which should be equivalent
11016 */
11017 USTPUTC('(', out);
11018 }
11019 goto parsearith_return;
11020}
11021
11022} /* end of readtoken */
11023
11024
Eric Andersencb57d552001-06-28 07:25:16 +000011025/*
11026 * Returns true if the text contains nothing to expand (no dollar signs
11027 * or backquotes).
11028 */
11029
11030static int
11031noexpand(text)
11032 char *text;
11033 {
11034 char *p;
11035 char c;
11036
11037 p = text;
11038 while ((c = *p++) != '\0') {
11039 if (c == CTLQUOTEMARK)
11040 continue;
11041 if (c == CTLESC)
11042 p++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011043 else if (SIT(c,BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000011044 return 0;
11045 }
11046 return 1;
11047}
11048
11049
11050/*
11051 * Return true if the argument is a legal variable name (a letter or
11052 * underscore followed by zero or more letters, underscores, and digits).
11053 */
11054
11055static int
Eric Andersen2870d962001-07-02 17:27:21 +000011056goodname(const char *name)
11057{
11058 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000011059
11060 p = name;
11061 if (! is_name(*p))
11062 return 0;
11063 while (*++p) {
11064 if (! is_in_name(*p))
11065 return 0;
11066 }
11067 return 1;
11068}
11069
11070
11071/*
11072 * Called when an unexpected token is read during the parse. The argument
11073 * is the token that is expected, or -1 if more than one type of token can
11074 * occur at this point.
11075 */
11076
11077static void
11078synexpect(token)
11079 int token;
11080{
11081 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011082 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000011083
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011084 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
11085 if (token >= 0)
11086 sprintf(msg+l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000011087 synerror(msg);
11088 /* NOTREACHED */
11089}
11090
11091
11092static void
Eric Andersen2870d962001-07-02 17:27:21 +000011093synerror(const char *msg)
11094{
Eric Andersencb57d552001-06-28 07:25:16 +000011095 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +000011096 out2fmt("%s: %d: ", commandname, startlinno);
11097 out2fmt("Syntax error: %s\n", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000011098 error((char *)NULL);
11099 /* NOTREACHED */
11100}
11101
Eric Andersencb57d552001-06-28 07:25:16 +000011102
11103/*
11104 * called by editline -- any expansions to the prompt
11105 * should be added here.
11106 */
Eric Andersen2870d962001-07-02 17:27:21 +000011107static void
Eric Andersen62483552001-07-10 06:09:16 +000011108setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000011109{
Eric Andersen62483552001-07-10 06:09:16 +000011110 char *prompt;
11111 switch (whichprompt) {
11112 case 1:
11113 prompt = ps1val();
11114 break;
11115 case 2:
11116 prompt = ps2val();
11117 break;
11118 default: /* 0 */
11119 prompt = "";
11120 }
11121 putprompt(prompt);
Eric Andersencb57d552001-06-28 07:25:16 +000011122}
11123
Eric Andersencb57d552001-06-28 07:25:16 +000011124
Eric Andersencb57d552001-06-28 07:25:16 +000011125/*
11126 * Code for dealing with input/output redirection.
11127 */
11128
Eric Andersen2870d962001-07-02 17:27:21 +000011129#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000011130#ifndef PIPE_BUF
Eric Andersen2870d962001-07-02 17:27:21 +000011131# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000011132#else
11133# define PIPESIZE PIPE_BUF
11134#endif
11135
11136
Eric Andersen62483552001-07-10 06:09:16 +000011137/*
11138 * Open a file in noclobber mode.
11139 * The code was copied from bash.
11140 */
11141static inline int
11142noclobberopen(const char *fname)
11143{
11144 int r, fd;
11145 struct stat finfo, finfo2;
11146
11147 /*
11148 * If the file exists and is a regular file, return an error
11149 * immediately.
11150 */
11151 r = stat(fname, &finfo);
11152 if (r == 0 && S_ISREG(finfo.st_mode)) {
11153 errno = EEXIST;
11154 return -1;
11155 }
11156
11157 /*
11158 * If the file was not present (r != 0), make sure we open it
11159 * exclusively so that if it is created before we open it, our open
11160 * will fail. Make sure that we do not truncate an existing file.
11161 * Note that we don't turn on O_EXCL unless the stat failed -- if the
11162 * file was not a regular file, we leave O_EXCL off.
11163 */
11164 if (r != 0)
11165 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
11166 fd = open(fname, O_WRONLY|O_CREAT, 0666);
11167
11168 /* If the open failed, return the file descriptor right away. */
11169 if (fd < 0)
11170 return fd;
11171
11172 /*
11173 * OK, the open succeeded, but the file may have been changed from a
11174 * non-regular file to a regular file between the stat and the open.
11175 * We are assuming that the O_EXCL open handles the case where FILENAME
11176 * did not exist and is symlinked to an existing file between the stat
11177 * and open.
11178 */
11179
11180 /*
11181 * If we can open it and fstat the file descriptor, and neither check
11182 * revealed that it was a regular file, and the file has not been
11183 * replaced, return the file descriptor.
11184 */
11185 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
11186 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
11187 return fd;
11188
11189 /* The file has been replaced. badness. */
11190 close(fd);
11191 errno = EEXIST;
11192 return -1;
11193}
Eric Andersencb57d552001-06-28 07:25:16 +000011194
11195/*
Eric Andersen62483552001-07-10 06:09:16 +000011196 * Handle here documents. Normally we fork off a process to write the
11197 * data to a pipe. If the document is short, we can stuff the data in
11198 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000011199 */
11200
Eric Andersen62483552001-07-10 06:09:16 +000011201static inline int
11202openhere(const union node *redir)
11203{
11204 int pip[2];
11205 int len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011206
Eric Andersen62483552001-07-10 06:09:16 +000011207 if (pipe(pip) < 0)
11208 error("Pipe call failed");
11209 if (redir->type == NHERE) {
11210 len = strlen(redir->nhere.doc->narg.text);
11211 if (len <= PIPESIZE) {
11212 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11213 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011214 }
Eric Andersencb57d552001-06-28 07:25:16 +000011215 }
Eric Andersen62483552001-07-10 06:09:16 +000011216 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
11217 close(pip[0]);
11218 signal(SIGINT, SIG_IGN);
11219 signal(SIGQUIT, SIG_IGN);
11220 signal(SIGHUP, SIG_IGN);
11221#ifdef SIGTSTP
11222 signal(SIGTSTP, SIG_IGN);
11223#endif
11224 signal(SIGPIPE, SIG_DFL);
11225 if (redir->type == NHERE)
11226 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11227 else
11228 expandhere(redir->nhere.doc, pip[1]);
11229 _exit(0);
11230 }
11231out:
11232 close(pip[1]);
11233 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000011234}
11235
11236
Eric Andersen62483552001-07-10 06:09:16 +000011237static inline int
11238openredirect(const union node *redir)
11239{
Eric Andersencb57d552001-06-28 07:25:16 +000011240 char *fname;
11241 int f;
11242
11243 switch (redir->nfile.type) {
11244 case NFROM:
11245 fname = redir->nfile.expfname;
11246 if ((f = open(fname, O_RDONLY)) < 0)
11247 goto eopen;
11248 break;
11249 case NFROMTO:
11250 fname = redir->nfile.expfname;
11251 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
11252 goto ecreate;
11253 break;
11254 case NTO:
11255 /* Take care of noclobber mode. */
11256 if (Cflag) {
11257 fname = redir->nfile.expfname;
11258 if ((f = noclobberopen(fname)) < 0)
11259 goto ecreate;
11260 break;
11261 }
11262 case NTOOV:
11263 fname = redir->nfile.expfname;
11264#ifdef O_CREAT
11265 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
11266 goto ecreate;
11267#else
11268 if ((f = creat(fname, 0666)) < 0)
11269 goto ecreate;
11270#endif
11271 break;
11272 case NAPPEND:
11273 fname = redir->nfile.expfname;
11274#ifdef O_APPEND
11275 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
11276 goto ecreate;
11277#else
11278 if ((f = open(fname, O_WRONLY)) < 0
11279 && (f = creat(fname, 0666)) < 0)
11280 goto ecreate;
11281 lseek(f, (off_t)0, 2);
11282#endif
11283 break;
11284 default:
11285#ifdef DEBUG
11286 abort();
11287#endif
11288 /* Fall through to eliminate warning. */
11289 case NTOFD:
11290 case NFROMFD:
11291 f = -1;
11292 break;
11293 case NHERE:
11294 case NXHERE:
11295 f = openhere(redir);
11296 break;
11297 }
11298
11299 return f;
11300ecreate:
11301 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11302eopen:
11303 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11304}
11305
11306
Eric Andersen62483552001-07-10 06:09:16 +000011307/*
11308 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11309 * old file descriptors are stashed away so that the redirection can be
11310 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11311 * standard output, and the standard error if it becomes a duplicate of
11312 * stdout.
11313 */
11314
Eric Andersencb57d552001-06-28 07:25:16 +000011315static void
Eric Andersen62483552001-07-10 06:09:16 +000011316redirect(union node *redir, int flags)
11317{
11318 union node *n;
11319 struct redirtab *sv = NULL;
11320 int i;
11321 int fd;
11322 int newfd;
11323 int try;
11324 int fd1dup = flags & REDIR_BACKQ;; /* stdout `cmd` redir to pipe */
11325
11326 if (flags & REDIR_PUSH) {
11327 sv = ckmalloc(sizeof (struct redirtab));
11328 for (i = 0 ; i < 10 ; i++)
11329 sv->renamed[i] = EMPTY;
11330 sv->next = redirlist;
11331 redirlist = sv;
11332 }
11333 for (n = redir ; n ; n = n->nfile.next) {
11334 fd = n->nfile.fd;
11335 try = 0;
11336 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11337 n->ndup.dupfd == fd)
11338 continue; /* redirect from/to same file descriptor */
11339
11340 INTOFF;
11341 newfd = openredirect(n);
11342 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
11343 if (newfd == fd) {
11344 try++;
11345 } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
11346 switch (errno) {
11347 case EBADF:
11348 if (!try) {
11349 dupredirect(n, newfd, fd1dup);
11350 try++;
11351 break;
11352 }
11353 /* FALLTHROUGH*/
11354 default:
11355 if (newfd >= 0) {
11356 close(newfd);
11357 }
11358 INTON;
11359 error("%d: %m", fd);
11360 /* NOTREACHED */
11361 }
11362 }
11363 if (!try) {
11364 close(fd);
11365 if (flags & REDIR_PUSH) {
11366 sv->renamed[fd] = i;
11367 }
11368 }
11369 } else if (fd != newfd) {
11370 close(fd);
11371 }
11372 if (fd == 0)
11373 fd0_redirected++;
11374 if (!try)
11375 dupredirect(n, newfd, fd1dup);
11376 INTON;
11377 }
11378}
11379
11380
11381static void
11382dupredirect(const union node *redir, int f, int fd1dup)
Eric Andersen2870d962001-07-02 17:27:21 +000011383{
Eric Andersencb57d552001-06-28 07:25:16 +000011384 int fd = redir->nfile.fd;
11385
Eric Andersen62483552001-07-10 06:09:16 +000011386 if(fd==1)
11387 fd1dup = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011388 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Eric Andersen2870d962001-07-02 17:27:21 +000011389 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
Eric Andersen62483552001-07-10 06:09:16 +000011390 if (redir->ndup.dupfd!=1 || fd1dup!=1)
Eric Andersencb57d552001-06-28 07:25:16 +000011391 dup_as_newfd(redir->ndup.dupfd, fd);
11392 }
11393 return;
11394 }
11395
11396 if (f != fd) {
11397 dup_as_newfd(f, fd);
11398 close(f);
11399 }
11400 return;
11401}
11402
11403
Eric Andersencb57d552001-06-28 07:25:16 +000011404
Eric Andersencb57d552001-06-28 07:25:16 +000011405/*
11406 * Undo the effects of the last redirection.
11407 */
11408
11409static void
Eric Andersen2870d962001-07-02 17:27:21 +000011410popredir(void)
11411{
Eric Andersencb57d552001-06-28 07:25:16 +000011412 struct redirtab *rp = redirlist;
11413 int i;
11414
11415 INTOFF;
11416 for (i = 0 ; i < 10 ; i++) {
11417 if (rp->renamed[i] != EMPTY) {
Eric Andersen2870d962001-07-02 17:27:21 +000011418 if (i == 0)
11419 fd0_redirected--;
Eric Andersencb57d552001-06-28 07:25:16 +000011420 close(i);
11421 if (rp->renamed[i] >= 0) {
11422 dup_as_newfd(rp->renamed[i], i);
11423 close(rp->renamed[i]);
11424 }
Eric Andersencb57d552001-06-28 07:25:16 +000011425 }
11426 }
11427 redirlist = rp->next;
11428 ckfree(rp);
11429 INTON;
11430}
11431
11432/*
Eric Andersencb57d552001-06-28 07:25:16 +000011433 * Discard all saved file descriptors.
11434 */
11435
11436static void
Eric Andersen2870d962001-07-02 17:27:21 +000011437clearredir(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000011438 struct redirtab *rp;
11439 int i;
11440
11441 for (rp = redirlist ; rp ; rp = rp->next) {
11442 for (i = 0 ; i < 10 ; i++) {
11443 if (rp->renamed[i] >= 0) {
11444 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011445 }
11446 rp->renamed[i] = EMPTY;
11447 }
11448 }
Eric Andersencb57d552001-06-28 07:25:16 +000011449}
11450
11451
Eric Andersencb57d552001-06-28 07:25:16 +000011452/*
11453 * Copy a file descriptor to be >= to. Returns -1
11454 * if the source file descriptor is closed, EMPTY if there are no unused
11455 * file descriptors left.
11456 */
11457
11458static int
11459dup_as_newfd(from, to)
11460 int from;
11461 int to;
11462{
11463 int newfd;
11464
11465 newfd = fcntl(from, F_DUPFD, to);
11466 if (newfd < 0) {
11467 if (errno == EMFILE)
11468 return EMPTY;
11469 else
Eric Andersen2870d962001-07-02 17:27:21 +000011470 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011471 }
11472 return newfd;
11473}
11474
Eric Andersencb57d552001-06-28 07:25:16 +000011475#ifdef DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +000011476static void shtree (union node *, int, char *, FILE*);
11477static void shcmd (union node *, FILE *);
11478static void sharg (union node *, FILE *);
11479static void indent (int, char *, FILE *);
11480static void trstring (char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011481
11482
11483static void
11484showtree(n)
11485 union node *n;
11486{
11487 trputs("showtree called\n");
11488 shtree(n, 1, NULL, stdout);
11489}
11490
11491
11492static void
11493shtree(n, ind, pfx, fp)
11494 union node *n;
11495 int ind;
11496 char *pfx;
11497 FILE *fp;
11498{
11499 struct nodelist *lp;
11500 const char *s;
11501
11502 if (n == NULL)
11503 return;
11504
11505 indent(ind, pfx, fp);
11506 switch(n->type) {
11507 case NSEMI:
11508 s = "; ";
11509 goto binop;
11510 case NAND:
11511 s = " && ";
11512 goto binop;
11513 case NOR:
11514 s = " || ";
11515binop:
11516 shtree(n->nbinary.ch1, ind, NULL, fp);
11517 /* if (ind < 0) */
11518 fputs(s, fp);
11519 shtree(n->nbinary.ch2, ind, NULL, fp);
11520 break;
11521 case NCMD:
11522 shcmd(n, fp);
11523 if (ind >= 0)
11524 putc('\n', fp);
11525 break;
11526 case NPIPE:
11527 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11528 shcmd(lp->n, fp);
11529 if (lp->next)
11530 fputs(" | ", fp);
11531 }
11532 if (n->npipe.backgnd)
11533 fputs(" &", fp);
11534 if (ind >= 0)
11535 putc('\n', fp);
11536 break;
11537 default:
11538 fprintf(fp, "<node type %d>", n->type);
11539 if (ind >= 0)
11540 putc('\n', fp);
11541 break;
11542 }
11543}
11544
11545
11546
11547static void
11548shcmd(cmd, fp)
11549 union node *cmd;
11550 FILE *fp;
11551{
11552 union node *np;
11553 int first;
11554 const char *s;
11555 int dftfd;
11556
11557 first = 1;
11558 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11559 if (! first)
11560 putchar(' ');
11561 sharg(np, fp);
11562 first = 0;
11563 }
11564 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11565 if (! first)
11566 putchar(' ');
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011567#if 1
11568 s = "*error*";
11569 dftfd = 0;
11570 if ((np->nfile.type <= NFROMFD) && (np->nfile.type >= NTO)) {
11571 s = redir_strings[np->nfile.type - NTO];
11572 if (*s == '>') {
11573 dftfd = 1;
11574 }
11575 }
11576#else
Eric Andersencb57d552001-06-28 07:25:16 +000011577 switch (np->nfile.type) {
Eric Andersen2870d962001-07-02 17:27:21 +000011578 case NTO: s = ">"; dftfd = 1; break;
11579 case NAPPEND: s = ">>"; dftfd = 1; break;
11580 case NTOFD: s = ">&"; dftfd = 1; break;
11581 case NTOOV: s = ">|"; dftfd = 1; break;
11582 case NFROM: s = "<"; dftfd = 0; break;
11583 case NFROMFD: s = "<&"; dftfd = 0; break;
11584 case NFROMTO: s = "<>"; dftfd = 0; break;
11585 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011586 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011587#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011588 if (np->nfile.fd != dftfd)
11589 fprintf(fp, "%d", np->nfile.fd);
11590 fputs(s, fp);
11591 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11592 fprintf(fp, "%d", np->ndup.dupfd);
11593 } else {
11594 sharg(np->nfile.fname, fp);
11595 }
11596 first = 0;
11597 }
11598}
11599
11600
11601
11602static void
11603sharg(arg, fp)
11604 union node *arg;
11605 FILE *fp;
11606 {
11607 char *p;
11608 struct nodelist *bqlist;
11609 int subtype;
11610
11611 if (arg->type != NARG) {
11612 printf("<node type %d>\n", arg->type);
11613 fflush(stdout);
11614 abort();
11615 }
11616 bqlist = arg->narg.backquote;
11617 for (p = arg->narg.text ; *p ; p++) {
11618 switch (*p) {
11619 case CTLESC:
11620 putc(*++p, fp);
11621 break;
11622 case CTLVAR:
11623 putc('$', fp);
11624 putc('{', fp);
11625 subtype = *++p;
11626 if (subtype == VSLENGTH)
11627 putc('#', fp);
11628
11629 while (*p != '=')
11630 putc(*p++, fp);
11631
11632 if (subtype & VSNUL)
11633 putc(':', fp);
11634
11635 switch (subtype & VSTYPE) {
11636 case VSNORMAL:
11637 putc('}', fp);
11638 break;
11639 case VSMINUS:
11640 putc('-', fp);
11641 break;
11642 case VSPLUS:
11643 putc('+', fp);
11644 break;
11645 case VSQUESTION:
11646 putc('?', fp);
11647 break;
11648 case VSASSIGN:
11649 putc('=', fp);
11650 break;
11651 case VSTRIMLEFT:
11652 putc('#', fp);
11653 break;
11654 case VSTRIMLEFTMAX:
11655 putc('#', fp);
11656 putc('#', fp);
11657 break;
11658 case VSTRIMRIGHT:
11659 putc('%', fp);
11660 break;
11661 case VSTRIMRIGHTMAX:
11662 putc('%', fp);
11663 putc('%', fp);
11664 break;
11665 case VSLENGTH:
11666 break;
11667 default:
11668 printf("<subtype %d>", subtype);
11669 }
11670 break;
11671 case CTLENDVAR:
11672 putc('}', fp);
11673 break;
11674 case CTLBACKQ:
11675 case CTLBACKQ|CTLQUOTE:
11676 putc('$', fp);
11677 putc('(', fp);
11678 shtree(bqlist->n, -1, NULL, fp);
11679 putc(')', fp);
11680 break;
11681 default:
11682 putc(*p, fp);
11683 break;
11684 }
11685 }
11686}
11687
11688
11689static void
11690indent(amount, pfx, fp)
11691 int amount;
11692 char *pfx;
11693 FILE *fp;
11694{
11695 int i;
11696
11697 for (i = 0 ; i < amount ; i++) {
11698 if (pfx && i == amount - 1)
11699 fputs(pfx, fp);
11700 putc('\t', fp);
11701 }
11702}
11703#endif
11704
11705
11706
11707/*
11708 * Debugging stuff.
11709 */
11710
11711
11712#ifdef DEBUG
11713FILE *tracefile;
11714
11715#if DEBUG == 2
11716static int debug = 1;
11717#else
11718static int debug = 0;
11719#endif
11720
11721
11722static void
11723trputc(c)
11724 int c;
11725{
11726 if (tracefile == NULL)
11727 return;
11728 putc(c, tracefile);
11729 if (c == '\n')
11730 fflush(tracefile);
11731}
11732
11733static void
11734trace(const char *fmt, ...)
11735{
11736 va_list va;
Eric Andersencb57d552001-06-28 07:25:16 +000011737 va_start(va, fmt);
Eric Andersencb57d552001-06-28 07:25:16 +000011738 if (tracefile != NULL) {
11739 (void) vfprintf(tracefile, fmt, va);
11740 if (strchr(fmt, '\n'))
11741 (void) fflush(tracefile);
11742 }
11743 va_end(va);
11744}
11745
11746
11747static void
11748trputs(s)
11749 const char *s;
11750{
11751 if (tracefile == NULL)
11752 return;
11753 fputs(s, tracefile);
11754 if (strchr(s, '\n'))
11755 fflush(tracefile);
11756}
11757
11758
11759static void
11760trstring(s)
11761 char *s;
11762{
11763 char *p;
11764 char c;
11765
11766 if (tracefile == NULL)
11767 return;
11768 putc('"', tracefile);
11769 for (p = s ; *p ; p++) {
11770 switch (*p) {
11771 case '\n': c = 'n'; goto backslash;
11772 case '\t': c = 't'; goto backslash;
11773 case '\r': c = 'r'; goto backslash;
11774 case '"': c = '"'; goto backslash;
11775 case '\\': c = '\\'; goto backslash;
11776 case CTLESC: c = 'e'; goto backslash;
11777 case CTLVAR: c = 'v'; goto backslash;
11778 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11779 case CTLBACKQ: c = 'q'; goto backslash;
11780 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
Eric Andersen2870d962001-07-02 17:27:21 +000011781backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011782 putc(c, tracefile);
11783 break;
11784 default:
11785 if (*p >= ' ' && *p <= '~')
11786 putc(*p, tracefile);
11787 else {
11788 putc('\\', tracefile);
11789 putc(*p >> 6 & 03, tracefile);
11790 putc(*p >> 3 & 07, tracefile);
11791 putc(*p & 07, tracefile);
11792 }
11793 break;
11794 }
11795 }
11796 putc('"', tracefile);
11797}
11798
11799
11800static void
11801trargs(ap)
11802 char **ap;
11803{
11804 if (tracefile == NULL)
11805 return;
11806 while (*ap) {
11807 trstring(*ap++);
11808 if (*ap)
11809 putc(' ', tracefile);
11810 else
11811 putc('\n', tracefile);
11812 }
11813 fflush(tracefile);
11814}
11815
11816
11817static void
11818opentrace() {
11819 char s[100];
11820#ifdef O_APPEND
11821 int flags;
11822#endif
11823
11824 if (!debug)
11825 return;
11826#ifdef not_this_way
11827 {
11828 char *p;
11829 if ((p = getenv("HOME")) == NULL) {
11830 if (geteuid() == 0)
11831 p = "/";
11832 else
11833 p = "/tmp";
11834 }
Eric Andersen2870d962001-07-02 17:27:21 +000011835 strcpy(s, p);
Eric Andersencb57d552001-06-28 07:25:16 +000011836 strcat(s, "/trace");
11837 }
11838#else
Eric Andersen2870d962001-07-02 17:27:21 +000011839 strcpy(s, "./trace");
Eric Andersencb57d552001-06-28 07:25:16 +000011840#endif /* not_this_way */
11841 if ((tracefile = fopen(s, "a")) == NULL) {
11842 fprintf(stderr, "Can't open %s\n", s);
11843 return;
11844 }
11845#ifdef O_APPEND
11846 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11847 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11848#endif
11849 fputs("\nTracing started.\n", tracefile);
11850 fflush(tracefile);
11851}
11852#endif /* DEBUG */
11853
11854
11855/*
Eric Andersencb57d552001-06-28 07:25:16 +000011856 * The trap builtin.
11857 */
11858
11859static int
11860trapcmd(argc, argv)
11861 int argc;
11862 char **argv;
11863{
11864 char *action;
11865 char **ap;
11866 int signo;
11867
11868 if (argc <= 1) {
11869 for (signo = 0 ; signo < NSIG ; signo++) {
11870 if (trap[signo] != NULL) {
11871 char *p;
Eric Andersen34506362001-08-02 05:02:46 +000011872 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011873
11874 p = single_quote(trap[signo]);
Eric Andersen34506362001-08-02 05:02:46 +000011875 sn = sys_siglist[signo];
11876 if(sn==NULL)
11877 sn = u_signal_names(0, &signo, 0);
11878 if(sn==NULL)
11879 sn = "???";
11880 printf("trap -- %s %s\n", p, sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011881 stunalloc(p);
11882 }
11883 }
11884 return 0;
11885 }
11886 ap = argv + 1;
11887 if (argc == 2)
11888 action = NULL;
11889 else
11890 action = *ap++;
11891 while (*ap) {
11892 if ((signo = decode_signal(*ap, 0)) < 0)
11893 error("%s: bad trap", *ap);
11894 INTOFF;
11895 if (action) {
11896 if (action[0] == '-' && action[1] == '\0')
11897 action = NULL;
11898 else
11899 action = savestr(action);
11900 }
11901 if (trap[signo])
11902 ckfree(trap[signo]);
11903 trap[signo] = action;
11904 if (signo != 0)
11905 setsignal(signo);
11906 INTON;
11907 ap++;
11908 }
11909 return 0;
11910}
11911
11912
11913
Eric Andersencb57d552001-06-28 07:25:16 +000011914
11915
11916
11917/*
11918 * Set the signal handler for the specified signal. The routine figures
11919 * out what it should be set to.
11920 */
11921
11922static void
Eric Andersen2870d962001-07-02 17:27:21 +000011923setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011924{
11925 int action;
11926 char *t;
11927 struct sigaction act;
11928
11929 if ((t = trap[signo]) == NULL)
11930 action = S_DFL;
11931 else if (*t != '\0')
11932 action = S_CATCH;
11933 else
11934 action = S_IGN;
11935 if (rootshell && action == S_DFL) {
11936 switch (signo) {
11937 case SIGINT:
11938 if (iflag || minusc || sflag == 0)
11939 action = S_CATCH;
11940 break;
11941 case SIGQUIT:
11942#ifdef DEBUG
11943 {
Eric Andersencb57d552001-06-28 07:25:16 +000011944
11945 if (debug)
11946 break;
11947 }
11948#endif
11949 /* FALLTHROUGH */
11950 case SIGTERM:
11951 if (iflag)
11952 action = S_IGN;
11953 break;
Eric Andersen2870d962001-07-02 17:27:21 +000011954#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000011955 case SIGTSTP:
11956 case SIGTTOU:
11957 if (mflag)
11958 action = S_IGN;
11959 break;
11960#endif
11961 }
11962 }
11963
11964 t = &sigmode[signo - 1];
11965 if (*t == 0) {
11966 /*
11967 * current setting unknown
11968 */
11969 if (sigaction(signo, 0, &act) == -1) {
11970 /*
11971 * Pretend it worked; maybe we should give a warning
11972 * here, but other shells don't. We don't alter
11973 * sigmode, so that we retry every time.
11974 */
11975 return;
11976 }
11977 if (act.sa_handler == SIG_IGN) {
11978 if (mflag && (signo == SIGTSTP ||
11979 signo == SIGTTIN || signo == SIGTTOU)) {
Eric Andersen2870d962001-07-02 17:27:21 +000011980 *t = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000011981 } else
11982 *t = S_HARD_IGN;
11983 } else {
Eric Andersen2870d962001-07-02 17:27:21 +000011984 *t = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000011985 }
11986 }
11987 if (*t == S_HARD_IGN || *t == action)
11988 return;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011989 act.sa_handler = ((action == S_CATCH) ? onsig
11990 : ((action == S_IGN) ? SIG_IGN : SIG_DFL));
Eric Andersencb57d552001-06-28 07:25:16 +000011991 *t = action;
11992 act.sa_flags = 0;
11993 sigemptyset(&act.sa_mask);
11994 sigaction(signo, &act, 0);
11995}
11996
11997/*
11998 * Ignore a signal.
11999 */
12000
12001static void
12002ignoresig(signo)
12003 int signo;
12004{
12005 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
12006 signal(signo, SIG_IGN);
12007 }
12008 sigmode[signo - 1] = S_HARD_IGN;
12009}
12010
12011
Eric Andersencb57d552001-06-28 07:25:16 +000012012/*
12013 * Signal handler.
12014 */
12015
12016static void
Eric Andersen2870d962001-07-02 17:27:21 +000012017onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000012018{
12019 if (signo == SIGINT && trap[SIGINT] == NULL) {
12020 onint();
12021 return;
12022 }
12023 gotsig[signo - 1] = 1;
12024 pendingsigs++;
12025}
12026
12027
Eric Andersencb57d552001-06-28 07:25:16 +000012028/*
12029 * Called to execute a trap. Perhaps we should avoid entering new trap
12030 * handlers while we are executing a trap handler.
12031 */
12032
12033static void
Eric Andersen2870d962001-07-02 17:27:21 +000012034dotrap(void)
12035{
Eric Andersencb57d552001-06-28 07:25:16 +000012036 int i;
12037 int savestatus;
12038
12039 for (;;) {
12040 for (i = 1 ; ; i++) {
12041 if (gotsig[i - 1])
12042 break;
12043 if (i >= NSIG - 1)
12044 goto done;
12045 }
12046 gotsig[i - 1] = 0;
12047 savestatus=exitstatus;
12048 evalstring(trap[i], 0);
12049 exitstatus=savestatus;
12050 }
12051done:
12052 pendingsigs = 0;
12053}
12054
Eric Andersencb57d552001-06-28 07:25:16 +000012055/*
12056 * Called to exit the shell.
12057 */
12058
12059static void
Eric Andersen2870d962001-07-02 17:27:21 +000012060exitshell(int status)
Eric Andersencb57d552001-06-28 07:25:16 +000012061{
12062 struct jmploc loc1, loc2;
12063 char *p;
12064
12065 TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
12066 if (setjmp(loc1.loc)) {
12067 goto l1;
12068 }
12069 if (setjmp(loc2.loc)) {
12070 goto l2;
12071 }
12072 handler = &loc1;
12073 if ((p = trap[0]) != NULL && *p != '\0') {
12074 trap[0] = NULL;
12075 evalstring(p, 0);
12076 }
Eric Andersen2870d962001-07-02 17:27:21 +000012077l1: handler = &loc2; /* probably unnecessary */
Eric Andersencb57d552001-06-28 07:25:16 +000012078 flushall();
Eric Andersen2870d962001-07-02 17:27:21 +000012079#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000012080 setjobctl(0);
12081#endif
12082l2: _exit(status);
12083 /* NOTREACHED */
12084}
12085
12086static int decode_signal(const char *string, int minsig)
12087{
12088 int signo;
Eric Andersen34506362001-08-02 05:02:46 +000012089 const char *name = u_signal_names(string, &signo, minsig);
Eric Andersencb57d552001-06-28 07:25:16 +000012090
Eric Andersen34506362001-08-02 05:02:46 +000012091 return name ? signo : -1;
Eric Andersencb57d552001-06-28 07:25:16 +000012092}
Eric Andersen34506362001-08-02 05:02:46 +000012093
Eric Andersen2870d962001-07-02 17:27:21 +000012094static struct var **hashvar (const char *);
12095static void showvars (const char *, int, int);
12096static struct var **findvar (struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000012097
12098/*
12099 * Initialize the varable symbol tables and import the environment
12100 */
12101
Eric Andersencb57d552001-06-28 07:25:16 +000012102/*
12103 * This routine initializes the builtin variables. It is called when the
12104 * shell is initialized and again when a shell procedure is spawned.
12105 */
12106
12107static void
12108initvar() {
12109 const struct varinit *ip;
12110 struct var *vp;
12111 struct var **vpp;
12112
12113 for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
12114 if ((vp->flags & VEXPORT) == 0) {
12115 vpp = hashvar(ip->text);
12116 vp->next = *vpp;
12117 *vpp = vp;
12118 vp->text = strdup(ip->text);
12119 vp->flags = ip->flags;
12120 vp->func = ip->func;
12121 }
12122 }
12123 /*
12124 * PS1 depends on uid
12125 */
12126 if ((vps1.flags & VEXPORT) == 0) {
12127 vpp = hashvar("PS1=");
12128 vps1.next = *vpp;
12129 *vpp = &vps1;
12130 vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# ");
12131 vps1.flags = VSTRFIXED|VTEXTFIXED;
12132 }
12133}
12134
12135/*
12136 * Set the value of a variable. The flags argument is ored with the
12137 * flags of the variable. If val is NULL, the variable is unset.
12138 */
12139
12140static void
12141setvar(name, val, flags)
12142 const char *name, *val;
12143 int flags;
12144{
12145 const char *p;
12146 int len;
12147 int namelen;
12148 char *nameeq;
12149 int isbad;
12150 int vallen = 0;
12151
12152 isbad = 0;
12153 p = name;
12154 if (! is_name(*p))
12155 isbad = 1;
12156 p++;
12157 for (;;) {
12158 if (! is_in_name(*p)) {
12159 if (*p == '\0' || *p == '=')
12160 break;
12161 isbad = 1;
12162 }
12163 p++;
12164 }
12165 namelen = p - name;
12166 if (isbad)
12167 error("%.*s: bad variable name", namelen, name);
Eric Andersen2870d962001-07-02 17:27:21 +000012168 len = namelen + 2; /* 2 is space for '=' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +000012169 if (val == NULL) {
12170 flags |= VUNSET;
12171 } else {
12172 len += vallen = strlen(val);
12173 }
12174 INTOFF;
12175 nameeq = ckmalloc(len);
12176 memcpy(nameeq, name, namelen);
12177 nameeq[namelen] = '=';
12178 if (val) {
12179 memcpy(nameeq + namelen + 1, val, vallen + 1);
12180 } else {
12181 nameeq[namelen + 1] = '\0';
12182 }
12183 setvareq(nameeq, flags);
12184 INTON;
12185}
12186
12187
12188
12189/*
12190 * Same as setvar except that the variable and value are passed in
12191 * the first argument as name=value. Since the first argument will
12192 * be actually stored in the table, it should not be a string that
12193 * will go away.
12194 */
12195
12196static void
12197setvareq(s, flags)
12198 char *s;
12199 int flags;
12200{
12201 struct var *vp, **vpp;
12202
12203 vpp = hashvar(s);
12204 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
12205 if ((vp = *findvar(vpp, s))) {
12206 if (vp->flags & VREADONLY) {
12207 size_t len = strchr(s, '=') - s;
12208 error("%.*s: is read only", len, s);
12209 }
12210 INTOFF;
12211
12212 if (vp->func && (flags & VNOFUNC) == 0)
12213 (*vp->func)(strchr(s, '=') + 1);
12214
12215 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12216 ckfree(vp->text);
12217
12218 vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
12219 vp->flags |= flags;
12220 vp->text = s;
12221
12222 /*
12223 * We could roll this to a function, to handle it as
12224 * a regular variable function callback, but why bother?
12225 */
12226 if (iflag && (vp == &vmpath || (vp == &vmail && !mpathset())))
12227 chkmail(1);
12228 INTON;
12229 return;
12230 }
12231 /* not found */
12232 vp = ckmalloc(sizeof (*vp));
12233 vp->flags = flags;
12234 vp->text = s;
12235 vp->next = *vpp;
12236 vp->func = NULL;
12237 *vpp = vp;
12238}
12239
12240
12241
12242/*
12243 * Process a linked list of variable assignments.
12244 */
12245
12246static void
12247listsetvar(mylist)
12248 struct strlist *mylist;
12249 {
12250 struct strlist *lp;
12251
12252 INTOFF;
12253 for (lp = mylist ; lp ; lp = lp->next) {
12254 setvareq(savestr(lp->text), 0);
12255 }
12256 INTON;
12257}
12258
12259
12260
12261/*
12262 * Find the value of a variable. Returns NULL if not set.
12263 */
12264
Eric Andersen62483552001-07-10 06:09:16 +000012265static const char *
Eric Andersencb57d552001-06-28 07:25:16 +000012266lookupvar(name)
12267 const char *name;
12268 {
12269 struct var *v;
12270
12271 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
12272 return strchr(v->text, '=') + 1;
12273 }
12274 return NULL;
12275}
12276
12277
12278
12279/*
12280 * Search the environment of a builtin command.
12281 */
12282
Eric Andersen62483552001-07-10 06:09:16 +000012283static const char *
12284bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012285{
Eric Andersen62483552001-07-10 06:09:16 +000012286 const struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012287
12288 for (sp = cmdenviron ; sp ; sp = sp->next) {
12289 if (varequal(sp->text, name))
12290 return strchr(sp->text, '=') + 1;
12291 }
12292 return lookupvar(name);
12293}
12294
12295
12296
12297/*
12298 * Generate a list of exported variables. This routine is used to construct
12299 * the third argument to execve when executing a program.
12300 */
12301
12302static char **
12303environment() {
12304 int nenv;
12305 struct var **vpp;
12306 struct var *vp;
12307 char **env;
12308 char **ep;
12309
12310 nenv = 0;
12311 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12312 for (vp = *vpp ; vp ; vp = vp->next)
12313 if (vp->flags & VEXPORT)
12314 nenv++;
12315 }
12316 ep = env = stalloc((nenv + 1) * sizeof *env);
12317 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12318 for (vp = *vpp ; vp ; vp = vp->next)
12319 if (vp->flags & VEXPORT)
12320 *ep++ = vp->text;
12321 }
12322 *ep = NULL;
12323 return env;
12324}
12325
12326
12327/*
12328 * Called when a shell procedure is invoked to clear out nonexported
12329 * variables. It is also necessary to reallocate variables of with
12330 * VSTACK set since these are currently allocated on the stack.
12331 */
12332
Eric Andersencb57d552001-06-28 07:25:16 +000012333static void
Eric Andersen2870d962001-07-02 17:27:21 +000012334shprocvar(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000012335 struct var **vpp;
12336 struct var *vp, **prev;
12337
12338 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12339 for (prev = vpp ; (vp = *prev) != NULL ; ) {
12340 if ((vp->flags & VEXPORT) == 0) {
12341 *prev = vp->next;
12342 if ((vp->flags & VTEXTFIXED) == 0)
12343 ckfree(vp->text);
12344 if ((vp->flags & VSTRFIXED) == 0)
12345 ckfree(vp);
12346 } else {
12347 if (vp->flags & VSTACK) {
12348 vp->text = savestr(vp->text);
12349 vp->flags &=~ VSTACK;
12350 }
12351 prev = &vp->next;
12352 }
12353 }
12354 }
12355 initvar();
12356}
12357
12358
12359
12360/*
12361 * Command to list all variables which are set. Currently this command
12362 * is invoked from the set command when the set command is called without
12363 * any variables.
12364 */
12365
12366static int
12367showvarscmd(argc, argv)
12368 int argc;
12369 char **argv;
12370{
12371 showvars(nullstr, VUNSET, VUNSET);
12372 return 0;
12373}
12374
12375
12376
12377/*
12378 * The export and readonly commands.
12379 */
12380
12381static int
12382exportcmd(argc, argv)
12383 int argc;
12384 char **argv;
12385{
12386 struct var *vp;
12387 char *name;
12388 const char *p;
12389 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12390 int pflag;
12391
12392 listsetvar(cmdenviron);
12393 pflag = (nextopt("p") == 'p');
12394 if (argc > 1 && !pflag) {
12395 while ((name = *argptr++) != NULL) {
12396 if ((p = strchr(name, '=')) != NULL) {
12397 p++;
12398 } else {
12399 if ((vp = *findvar(hashvar(name), name))) {
12400 vp->flags |= flag;
12401 goto found;
12402 }
12403 }
12404 setvar(name, p, flag);
12405found:;
12406 }
12407 } else {
12408 showvars(argv[0], flag, 0);
12409 }
12410 return 0;
12411}
12412
Eric Andersen34506362001-08-02 05:02:46 +000012413
Eric Andersencb57d552001-06-28 07:25:16 +000012414/*
12415 * The "local" command.
12416 */
12417
Eric Andersen2870d962001-07-02 17:27:21 +000012418/* funcnest nonzero if we are currently evaluating a function */
12419
Eric Andersencb57d552001-06-28 07:25:16 +000012420static int
12421localcmd(argc, argv)
12422 int argc;
12423 char **argv;
12424{
12425 char *name;
12426
Eric Andersen2870d962001-07-02 17:27:21 +000012427 if (! funcnest)
Eric Andersencb57d552001-06-28 07:25:16 +000012428 error("Not in a function");
12429 while ((name = *argptr++) != NULL) {
12430 mklocal(name);
12431 }
12432 return 0;
12433}
12434
12435
12436/*
12437 * Make a variable a local variable. When a variable is made local, it's
12438 * value and flags are saved in a localvar structure. The saved values
12439 * will be restored when the shell function returns. We handle the name
12440 * "-" as a special case.
12441 */
12442
12443static void
12444mklocal(name)
12445 char *name;
12446 {
12447 struct localvar *lvp;
12448 struct var **vpp;
12449 struct var *vp;
12450
12451 INTOFF;
12452 lvp = ckmalloc(sizeof (struct localvar));
12453 if (name[0] == '-' && name[1] == '\0') {
12454 char *p;
Eric Andersen2870d962001-07-02 17:27:21 +000012455 p = ckmalloc(sizeof optet_vals);
12456 lvp->text = memcpy(p, optet_vals, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000012457 vp = NULL;
12458 } else {
12459 vpp = hashvar(name);
12460 vp = *findvar(vpp, name);
12461 if (vp == NULL) {
12462 if (strchr(name, '='))
12463 setvareq(savestr(name), VSTRFIXED);
12464 else
12465 setvar(name, NULL, VSTRFIXED);
Eric Andersen2870d962001-07-02 17:27:21 +000012466 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012467 lvp->text = NULL;
12468 lvp->flags = VUNSET;
12469 } else {
12470 lvp->text = vp->text;
12471 lvp->flags = vp->flags;
12472 vp->flags |= VSTRFIXED|VTEXTFIXED;
12473 if (strchr(name, '='))
12474 setvareq(savestr(name), 0);
12475 }
12476 }
12477 lvp->vp = vp;
12478 lvp->next = localvars;
12479 localvars = lvp;
12480 INTON;
12481}
12482
12483
12484/*
12485 * Called after a function returns.
12486 */
12487
12488static void
12489poplocalvars() {
12490 struct localvar *lvp;
12491 struct var *vp;
12492
12493 while ((lvp = localvars) != NULL) {
12494 localvars = lvp->next;
12495 vp = lvp->vp;
Eric Andersen2870d962001-07-02 17:27:21 +000012496 if (vp == NULL) { /* $- saved */
12497 memcpy(optet_vals, lvp->text, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000012498 ckfree(lvp->text);
12499 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12500 (void)unsetvar(vp->text);
12501 } else {
12502 if ((vp->flags & VTEXTFIXED) == 0)
12503 ckfree(vp->text);
12504 vp->flags = lvp->flags;
12505 vp->text = lvp->text;
12506 }
12507 ckfree(lvp);
12508 }
12509}
12510
12511
12512static int
12513setvarcmd(argc, argv)
12514 int argc;
12515 char **argv;
12516{
12517 if (argc <= 2)
12518 return unsetcmd(argc, argv);
12519 else if (argc == 3)
12520 setvar(argv[1], argv[2], 0);
12521 else
12522 error("List assignment not implemented");
12523 return 0;
12524}
12525
12526
12527/*
12528 * The unset builtin command. We unset the function before we unset the
12529 * variable to allow a function to be unset when there is a readonly variable
12530 * with the same name.
12531 */
12532
12533static int
12534unsetcmd(argc, argv)
12535 int argc;
12536 char **argv;
12537{
12538 char **ap;
12539 int i;
12540 int flg_func = 0;
12541 int flg_var = 0;
12542 int ret = 0;
12543
12544 while ((i = nextopt("vf")) != '\0') {
12545 if (i == 'f')
12546 flg_func = 1;
12547 else
12548 flg_var = 1;
12549 }
12550 if (flg_func == 0 && flg_var == 0)
12551 flg_var = 1;
12552
12553 for (ap = argptr; *ap ; ap++) {
12554 if (flg_func)
12555 unsetfunc(*ap);
12556 if (flg_var)
12557 ret |= unsetvar(*ap);
12558 }
12559 return ret;
12560}
12561
12562
12563/*
12564 * Unset the specified variable.
12565 */
12566
12567static int
Eric Andersen62483552001-07-10 06:09:16 +000012568unsetvar(const char *s)
12569{
Eric Andersencb57d552001-06-28 07:25:16 +000012570 struct var **vpp;
12571 struct var *vp;
12572
12573 vpp = findvar(hashvar(s), s);
12574 vp = *vpp;
12575 if (vp) {
12576 if (vp->flags & VREADONLY)
12577 return (1);
12578 INTOFF;
12579 if (*(strchr(vp->text, '=') + 1) != '\0')
12580 setvar(s, nullstr, 0);
12581 vp->flags &= ~VEXPORT;
12582 vp->flags |= VUNSET;
12583 if ((vp->flags & VSTRFIXED) == 0) {
12584 if ((vp->flags & VTEXTFIXED) == 0)
12585 ckfree(vp->text);
12586 *vpp = vp->next;
12587 ckfree(vp);
12588 }
12589 INTON;
12590 return (0);
12591 }
12592
12593 return (0);
12594}
12595
12596
12597
12598/*
12599 * Find the appropriate entry in the hash table from the name.
12600 */
12601
12602static struct var **
Eric Andersen62483552001-07-10 06:09:16 +000012603hashvar(const char *p)
12604{
Eric Andersencb57d552001-06-28 07:25:16 +000012605 unsigned int hashval;
12606
12607 hashval = ((unsigned char) *p) << 4;
12608 while (*p && *p != '=')
12609 hashval += (unsigned char) *p++;
12610 return &vartab[hashval % VTABSIZE];
12611}
12612
12613
12614
12615/*
12616 * Returns true if the two strings specify the same varable. The first
12617 * variable name is terminated by '='; the second may be terminated by
12618 * either '=' or '\0'.
12619 */
12620
12621static int
Eric Andersen62483552001-07-10 06:09:16 +000012622varequal(const char *p, const char *q)
12623{
Eric Andersencb57d552001-06-28 07:25:16 +000012624 while (*p == *q++) {
12625 if (*p++ == '=')
12626 return 1;
12627 }
12628 if (*p == '=' && *(q - 1) == '\0')
12629 return 1;
12630 return 0;
12631}
12632
12633static void
12634showvars(const char *myprefix, int mask, int xor)
12635{
12636 struct var **vpp;
12637 struct var *vp;
12638 const char *sep = myprefix == nullstr ? myprefix : spcstr;
12639
12640 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12641 for (vp = *vpp ; vp ; vp = vp->next) {
12642 if ((vp->flags & mask) ^ xor) {
12643 char *p;
12644 int len;
12645
12646 p = strchr(vp->text, '=') + 1;
12647 len = p - vp->text;
12648 p = single_quote(p);
12649
Eric Andersen62483552001-07-10 06:09:16 +000012650 printf("%s%s%.*s%s\n", myprefix, sep, len,
12651 vp->text, p);
Eric Andersencb57d552001-06-28 07:25:16 +000012652 stunalloc(p);
12653 }
12654 }
12655 }
12656}
12657
12658static struct var **
12659findvar(struct var **vpp, const char *name)
12660{
12661 for (; *vpp; vpp = &(*vpp)->next) {
12662 if (varequal((*vpp)->text, name)) {
12663 break;
12664 }
12665 }
12666 return vpp;
12667}
12668
12669/*
12670 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
12671 * This file contains code for the times builtin.
Eric Andersendd9173c2001-08-10 21:11:56 +000012672 * $Id: ash.c,v 1.21 2001/08/10 21:11:56 andersen Exp $
Eric Andersencb57d552001-06-28 07:25:16 +000012673 */
12674static int timescmd (int argc, char **argv)
12675{
12676 struct tms buf;
12677 long int clk_tck = sysconf(_SC_CLK_TCK);
12678
12679 times(&buf);
12680 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
12681 (int) (buf.tms_utime / clk_tck / 60),
12682 ((double) buf.tms_utime) / clk_tck,
12683 (int) (buf.tms_stime / clk_tck / 60),
12684 ((double) buf.tms_stime) / clk_tck,
12685 (int) (buf.tms_cutime / clk_tck / 60),
12686 ((double) buf.tms_cutime) / clk_tck,
12687 (int) (buf.tms_cstime / clk_tck / 60),
12688 ((double) buf.tms_cstime) / clk_tck);
12689 return 0;
12690}
12691
Eric Andersen74bcd162001-07-30 21:41:37 +000012692#ifdef ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012693/* The let builtin. */
12694int letcmd(int argc, char **argv)
Eric Andersen74bcd162001-07-30 21:41:37 +000012695{
Eric Andersen34506362001-08-02 05:02:46 +000012696 int errcode;
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012697 long result=0;
12698 if (argc == 2) {
12699 char *tmp, *expression, p[13];
12700 expression = strchr(argv[1], '=');
12701 if (!expression) {
Eric Andersen34506362001-08-02 05:02:46 +000012702 /* Cannot use 'error()' here, or the return code
12703 * will be incorrect */
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012704 out2fmt("sh: let: syntax error: \"%s\"\n", argv[1]);
12705 return 0;
Eric Andersen74bcd162001-07-30 21:41:37 +000012706 }
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012707 *expression = '\0';
12708 tmp = ++expression;
Eric Andersen34506362001-08-02 05:02:46 +000012709 result = arith(tmp, &errcode);
12710 if (errcode < 0) {
12711 /* Cannot use 'error()' here, or the return code
12712 * will be incorrect */
12713 out2fmt("sh: let: ");
12714 if(errcode == -2)
12715 out2fmt("divide by zero");
12716 else
12717 out2fmt("syntax error: \"%s=%s\"\n", argv[1], expression);
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012718 return 0;
12719 }
12720 snprintf(p, 12, "%ld", result);
12721 setvar(argv[1], savestr(p), 0);
12722 } else if (argc >= 3)
12723 synerror("invalid operand");
12724 return !result;
Eric Andersen74bcd162001-07-30 21:41:37 +000012725}
12726#endif
12727
12728
12729
Eric Andersendf82f612001-06-28 07:46:40 +000012730/*-
12731 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000012732 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000012733 *
12734 * This code is derived from software contributed to Berkeley by
12735 * Kenneth Almquist.
12736 *
12737 * Redistribution and use in source and binary forms, with or without
12738 * modification, are permitted provided that the following conditions
12739 * are met:
12740 * 1. Redistributions of source code must retain the above copyright
12741 * notice, this list of conditions and the following disclaimer.
12742 * 2. Redistributions in binary form must reproduce the above copyright
12743 * notice, this list of conditions and the following disclaimer in the
12744 * documentation and/or other materials provided with the distribution.
12745 *
Eric Andersen2870d962001-07-02 17:27:21 +000012746 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
12747 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000012748 *
12749 * 4. Neither the name of the University nor the names of its contributors
12750 * may be used to endorse or promote products derived from this software
12751 * without specific prior written permission.
12752 *
12753 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
12754 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
12755 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
12756 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
12757 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
12758 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
12759 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
12760 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
12761 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
12762 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
12763 * SUCH DAMAGE.
12764 */