blob: bbde91cd12630aba2a62c89588398b4c23cdf758 [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)
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000689static void outstr (const char *p, FILE *file) { fputs(p, file); }
Eric Andersen3102ac42001-07-06 04:26:23 +0000690static void out1str(const char *p) { outstr(p, stdout); }
691static void out2str(const char *p) { outstr(p, stderr); }
Eric Andersen2870d962001-07-02 17:27:21 +0000692
Eric Andersen62483552001-07-10 06:09:16 +0000693#ifndef ASH_OPTIMIZE_FOR_SIZE
Eric Andersen3102ac42001-07-06 04:26:23 +0000694#define out2c(c) putc((c), stderr)
Eric Andersen62483552001-07-10 06:09:16 +0000695#else
696static void out2c(int c) { putc(c, stderr); }
697#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000698
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000699
700#ifdef ASH_OPTIMIZE_FOR_SIZE
701#define USE_SIT_FUNCTION
702#endif
703
704/* number syntax index */
705#define BASESYNTAX 0 /* not in quotes */
706#define DQSYNTAX 1 /* in double quotes */
707#define SQSYNTAX 2 /* in single quotes */
708#define ARISYNTAX 3 /* in arithmetic */
709
710static const char S_I_T[][4] = {
711 /* 0 */ { CSPCL, CIGN, CIGN, CIGN }, /* PEOA */
712 /* 1 */ { CSPCL, CWORD, CWORD, CWORD }, /* ' ' */
713 /* 2 */ { CNL, CNL, CNL, CNL }, /* \n */
714 /* 3 */ { CWORD, CCTL, CCTL, CWORD }, /* !*-/:=?[]~ */
715 /* 4 */ { CDQUOTE, CENDQUOTE, CWORD, CDQUOTE }, /* '"' */
716 /* 5 */ { CVAR, CVAR, CWORD, CVAR }, /* $ */
717 /* 6 */ { CSQUOTE, CWORD, CENDQUOTE, CSQUOTE }, /* "'" */
718 /* 7 */ { CSPCL, CWORD, CWORD, CLP }, /* ( */
719 /* 8 */ { CSPCL, CWORD, CWORD, CRP }, /* ) */
720 /* 9 */ { CBACK, CBACK, CCTL, CBACK }, /* \ */
721 /* 10 */ { CBQUOTE, CBQUOTE, CWORD, CBQUOTE }, /* ` */
722 /* 11 */ { CENDVAR, CENDVAR, CWORD, CENDVAR }, /* } */
723#ifndef USE_SIT_FUNCTION
724 /* 12 */ { CENDFILE, CENDFILE, CENDFILE, CENDFILE }, /* PEOF */
725 /* 13 */ { CWORD, CWORD, CWORD, CWORD }, /* 0-9A-Za-z */
726 /* 14 */ { CCTL, CCTL, CCTL, CCTL } /* CTLESC ... */
727#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000728};
729
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000730#ifdef USE_SIT_FUNCTION
731
732#define U_C(c) ((unsigned char)(c))
733
734static int SIT(int c, int syntax)
735{
736 static const char spec_symbls[]="\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
737 static const char syntax_index_table [] = {
738 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
739 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
740 3, 1, 3, 3, 9, 3,10, 1, /* "=>?[\\]`|" */
741 11,3 }; /* "}~" */
742 const char *s;
743 int indx;
744
745 if(c==PEOF) /* 2^8+2 */
746 return CENDFILE;
747 if(c==PEOA) /* 2^8+1 */
748 indx = 0;
749 else if(U_C(c)>=U_C(CTLESC) && U_C(c)<=U_C(CTLQUOTEMARK))
750 return CCTL;
751 else {
752 s = strchr(spec_symbls, c);
753 if(s==0)
754 return CWORD;
755 indx = syntax_index_table[(s-spec_symbls)];
756 }
757 return S_I_T[indx][syntax];
758}
759
760#else /* USE_SIT_FUNCTION */
761
762#define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
763
764#define CSPCL_CIGN_CIGN_CIGN 0
765#define CSPCL_CWORD_CWORD_CWORD 1
766#define CNL_CNL_CNL_CNL 2
767#define CWORD_CCTL_CCTL_CWORD 3
768#define CDQUOTE_CENDQUOTE_CWORD_CDQUOTE 4
769#define CVAR_CVAR_CWORD_CVAR 5
770#define CSQUOTE_CWORD_CENDQUOTE_CSQUOTE 6
771#define CSPCL_CWORD_CWORD_CLP 7
772#define CSPCL_CWORD_CWORD_CRP 8
773#define CBACK_CBACK_CCTL_CBACK 9
774#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
775#define CENDVAR_CENDVAR_CWORD_CENDVAR 11
776#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
777#define CWORD_CWORD_CWORD_CWORD 13
778#define CCTL_CCTL_CCTL_CCTL 14
779
780static const char syntax_index_table[258] = {
781 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
782 /* 0 -130 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
783 /* 1 -129 PEOA */ CSPCL_CIGN_CIGN_CIGN,
784 /* 2 -128 0xff */ CWORD_CWORD_CWORD_CWORD,
785 /* 3 -127 */ CCTL_CCTL_CCTL_CCTL, /* CTLQUOTEMARK */
786 /* 4 -126 */ CCTL_CCTL_CCTL_CCTL,
787 /* 5 -125 */ CCTL_CCTL_CCTL_CCTL,
788 /* 6 -124 */ CCTL_CCTL_CCTL_CCTL,
789 /* 7 -123 */ CCTL_CCTL_CCTL_CCTL,
790 /* 8 -122 */ CCTL_CCTL_CCTL_CCTL,
791 /* 9 -121 */ CCTL_CCTL_CCTL_CCTL,
792 /* 10 -120 */ CCTL_CCTL_CCTL_CCTL, /* CTLESC */
793 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
794 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
795 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
796 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
797 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
798 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
799 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
800 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
801 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
802 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
803 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
804 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
805 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
806 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
807 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
808 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
809 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
810 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
811 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
812 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
813 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
814 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
815 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
816 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
817 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
818 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
819 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
820 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
821 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
822 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
823 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
824 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
825 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
826 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
827 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
828 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
829 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
830 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
831 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
832 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
833 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
834 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
835 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
836 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
837 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
838 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
839 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
840 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
841 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
842 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
843 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
844 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
845 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
846 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
847 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
848 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
849 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
850 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
851 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
852 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
853 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
854 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
855 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
856 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
857 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
858 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
859 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
860 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
861 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
862 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
863 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
864 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
865 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
866 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
867 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
868 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
869 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
870 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
871 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
872 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
873 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
874 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
875 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
876 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
877 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
878 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
879 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
880 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
881 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
882 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
883 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
884 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
885 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
886 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
887 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
888 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
889 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
890 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
891 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
892 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
893 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
894 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
895 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
896 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
897 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
898 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
899 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
900 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
901 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
902 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
903 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
904 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
905 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
906 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
907 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
908 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
909 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
910 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
911 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
912 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
913 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
914 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
915 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
916 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
917 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
918 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
919 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
920 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
921 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
922 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
923 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
924 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
925 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
926 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
927 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
928 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
929 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
930 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
931 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
932 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
933 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
934 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
935 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
936 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
937 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
938 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
939 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
940 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
941 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
942 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
943 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
944 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
945 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
946 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CDQUOTE,
947 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
948 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
949 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
950 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
951 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CSQUOTE,
952 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
953 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
954 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
955 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
956 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
957 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
958 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
959 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
960 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
961 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
962 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
963 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
964 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
965 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
966 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
967 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
968 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
969 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
970 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
971 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
972 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
973 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
974 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
975 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
976 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
977 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
978 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
979 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
980 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
981 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
982 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
983 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
984 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
985 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
986 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
987 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
988 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
989 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
990 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
991 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
992 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
993 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
994 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
995 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
996 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
997 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
998 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
999 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
1000 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
1001 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
1002 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
1003 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
1004 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
1005 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
1006 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
1007 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
1008 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
1009 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
1010 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
1011 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
1012 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
1013 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
1014 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
1015 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
1016 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
1017 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
1018 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
1019 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
1020 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
1021 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
1022 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
1023 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
1024 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
1025 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
1026 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
1027 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
1028 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
1029 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
1030 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
1031 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
1032 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
1033 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
1034 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
1035 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
1036 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
1037 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
1038 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
1039 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
Eric Andersen2870d962001-07-02 17:27:21 +00001040};
1041
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001042#endif /* USE_SIT_FUNCTION */
Eric Andersen2870d962001-07-02 17:27:21 +00001043
Eric Andersen2870d962001-07-02 17:27:21 +00001044
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001045/* first char is indicating which tokens mark the end of a list */
1046static const char *const tokname_array[] = {
1047 "\1end of file",
1048 "\0newline",
1049 "\0redirection",
1050 "\0word",
1051 "\0assignment",
1052 "\0;",
1053 "\0&",
1054 "\0&&",
1055 "\0||",
1056 "\0|",
1057 "\0(",
1058 "\1)",
1059 "\1;;",
1060 "\1`",
Eric Andersen2870d962001-07-02 17:27:21 +00001061#define KWDOFFSET 14
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001062 /* the following are keywords */
1063 "\0!",
1064 "\0case",
1065 "\1do",
1066 "\1done",
1067 "\1elif",
1068 "\1else",
1069 "\1esac",
1070 "\1fi",
1071 "\0for",
1072 "\0if",
1073 "\0in",
1074 "\1then",
1075 "\0until",
1076 "\0while",
1077 "\0{",
1078 "\1}",
Eric Andersen2870d962001-07-02 17:27:21 +00001079};
1080
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001081static const char *tokname(int tok)
1082{
1083 static char buf[16];
1084
1085 if(tok>=TSEMI)
1086 buf[0] = '"';
1087 sprintf(buf+(tok>=TSEMI), "%s%c",
1088 tokname_array[tok]+1, (tok>=TSEMI ? '"' : 0));
1089 return buf;
1090}
Eric Andersen2870d962001-07-02 17:27:21 +00001091
1092static int plinno = 1; /* input line number */
1093
1094static int parselleft; /* copy of parsefile->lleft */
1095
1096static struct parsefile basepf; /* top level input file */
1097static char basebuf[BUFSIZ]; /* buffer for top level input file */
1098static struct parsefile *parsefile = &basepf; /* current input file */
1099
1100/*
1101 * NEOF is returned by parsecmd when it encounters an end of file. It
1102 * must be distinct from NULL, so we use the address of a variable that
1103 * happens to be handy.
1104 */
1105
1106static int tokpushback; /* last token pushed back */
1107#define NEOF ((union node *)&tokpushback)
1108static int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */
1109
1110
1111static void error (const char *, ...) __attribute__((__noreturn__));
1112static void exerror (int, const char *, ...) __attribute__((__noreturn__));
1113static void shellexec (char **, char **, const char *, int)
1114 __attribute__((noreturn));
1115static void exitshell (int) __attribute__((noreturn));
1116
1117static int goodname(const char *);
1118static void ignoresig (int);
1119static void onsig (int);
1120static void dotrap (void);
1121static int decode_signal (const char *, int);
1122
1123static void shprocvar(void);
1124static void deletefuncs(void);
1125static void setparam (char **);
1126static void freeparam (volatile struct shparam *);
1127
1128/* reasons for skipping commands (see comment on breakcmd routine) */
1129#define SKIPBREAK 1
1130#define SKIPCONT 2
1131#define SKIPFUNC 3
1132#define SKIPFILE 4
1133
1134/* values of cmdtype */
1135#define CMDUNKNOWN -1 /* no entry in table for command */
1136#define CMDNORMAL 0 /* command is an executable program */
1137#define CMDBUILTIN 1 /* command is a shell builtin */
1138#define CMDFUNCTION 2 /* command is a shell function */
1139
1140#define DO_ERR 1 /* find_command prints errors */
1141#define DO_ABS 2 /* find_command checks absolute paths */
1142#define DO_NOFUN 4 /* find_command ignores functions */
1143#define DO_BRUTE 8 /* find_command ignores hash table */
1144
1145/*
1146 * Shell variables.
1147 */
1148
1149/* flags */
1150#define VEXPORT 0x01 /* variable is exported */
1151#define VREADONLY 0x02 /* variable cannot be modified */
1152#define VSTRFIXED 0x04 /* variable struct is staticly allocated */
1153#define VTEXTFIXED 0x08 /* text is staticly allocated */
1154#define VSTACK 0x10 /* text is allocated on the stack */
1155#define VUNSET 0x20 /* the variable is not set */
1156#define VNOFUNC 0x40 /* don't call the callback function */
1157
1158
1159struct var {
1160 struct var *next; /* next entry in hash list */
1161 int flags; /* flags are defined above */
1162 char *text; /* name=value */
1163 void (*func) (const char *);
1164 /* function to be called when */
1165 /* the variable gets set/unset */
1166};
1167
1168struct localvar {
1169 struct localvar *next; /* next local variable in list */
1170 struct var *vp; /* the variable that was made local */
1171 int flags; /* saved flags */
1172 char *text; /* saved text */
1173};
1174
1175
Eric Andersen62483552001-07-10 06:09:16 +00001176#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00001177#define rmescapes(p) _rmescapes((p), 0)
1178static char *_rmescapes (char *, int);
1179#else
1180static void rmescapes (char *);
1181#endif
1182
1183static int casematch (union node *, const char *);
1184static void clearredir(void);
1185static void popstring(void);
1186static void readcmdfile (const char *);
1187
1188static int number (const char *);
1189static int is_number (const char *, int *num);
1190static char *single_quote (const char *);
1191static int nextopt (const char *);
1192
1193static void redirect (union node *, int);
1194static void popredir (void);
1195static int dup_as_newfd (int, int);
1196
1197static void changepath(const char *newval);
1198static void getoptsreset(const char *value);
1199
1200
1201static int parsenleft; /* copy of parsefile->nleft */
1202static char *parsenextc; /* copy of parsefile->nextc */
1203static int rootpid; /* pid of main shell */
1204static int rootshell; /* true if we aren't a child of the main shell */
1205
1206static const char spcstr[] = " ";
1207static const char snlfmt[] = "%s\n";
1208
1209static int sstrnleft;
1210static int herefd = -1;
1211
1212static struct localvar *localvars;
1213
1214static struct var vifs;
1215static struct var vmail;
1216static struct var vmpath;
1217static struct var vpath;
1218static struct var vps1;
1219static struct var vps2;
1220static struct var voptind;
1221#ifdef BB_LOCALE_SUPPORT
1222static struct var vlc_all;
1223static struct var vlc_ctype;
1224#endif
1225
1226struct varinit {
1227 struct var *var;
1228 int flags;
1229 const char *text;
1230 void (*func) (const char *);
1231};
1232
1233static const char defpathvar[] =
1234 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
1235#define defpath (defpathvar + 5)
1236
1237#ifdef IFS_BROKEN
1238static const char defifsvar[] = "IFS= \t\n";
1239#define defifs (defifsvar + 4)
1240#else
1241static const char defifs[] = " \t\n";
1242#endif
1243
1244static const struct varinit varinit[] = {
1245#ifdef IFS_BROKEN
1246 { &vifs, VSTRFIXED|VTEXTFIXED, defifsvar,
1247#else
1248 { &vifs, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS=",
1249#endif
1250 NULL },
1251 { &vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=",
1252 NULL },
1253 { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=",
1254 NULL },
1255 { &vpath, VSTRFIXED|VTEXTFIXED, defpathvar,
1256 changepath },
1257 /*
1258 * vps1 depends on uid
1259 */
1260 { &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ",
1261 NULL },
1262 { &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1",
1263 getoptsreset },
1264#ifdef BB_LOCALE_SUPPORT
1265 { &vlc_all, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL=",
1266 change_lc_all },
1267 { &vlc_ctype, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE=",
1268 change_lc_ctype },
1269#endif
1270 { NULL, 0, NULL,
1271 NULL }
1272};
1273
1274#define VTABSIZE 39
1275
1276static struct var *vartab[VTABSIZE];
1277
1278/*
1279 * The following macros access the values of the above variables.
1280 * They have to skip over the name. They return the null string
1281 * for unset variables.
1282 */
1283
1284#define ifsval() (vifs.text + 4)
1285#define ifsset() ((vifs.flags & VUNSET) == 0)
1286#define mailval() (vmail.text + 5)
1287#define mpathval() (vmpath.text + 9)
1288#define pathval() (vpath.text + 5)
1289#define ps1val() (vps1.text + 4)
1290#define ps2val() (vps2.text + 4)
1291#define optindval() (voptind.text + 7)
1292
1293#define mpathset() ((vmpath.flags & VUNSET) == 0)
1294
1295static void initvar (void);
1296static void setvar (const char *, const char *, int);
1297static void setvareq (char *, int);
1298static void listsetvar (struct strlist *);
Eric Andersen62483552001-07-10 06:09:16 +00001299static const char *lookupvar (const char *);
1300static const char *bltinlookup (const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001301static char **environment (void);
1302static int showvarscmd (int, char **);
1303static void mklocal (char *);
1304static void poplocalvars (void);
1305static int unsetvar (const char *);
1306static int varequal (const char *, const char *);
1307
1308
1309static char *arg0; /* value of $0 */
1310static struct shparam shellparam; /* current positional parameters */
1311static char **argptr; /* argument list for builtin commands */
1312static char *optionarg; /* set by nextopt (like getopt) */
1313static char *optptr; /* used by nextopt */
1314static char *minusc; /* argument to -c option */
1315
1316
1317#ifdef ASH_ALIAS
1318
1319#define ALIASINUSE 1
1320#define ALIASDEAD 2
1321
Eric Andersen3102ac42001-07-06 04:26:23 +00001322#define ATABSIZE 39
1323
Eric Andersen2870d962001-07-02 17:27:21 +00001324struct alias {
1325 struct alias *next;
1326 char *name;
1327 char *val;
1328 int flag;
1329};
1330
1331static struct alias *atab[ATABSIZE];
1332
1333static void setalias (char *, char *);
1334static struct alias **hashalias (const char *);
1335static struct alias *freealias (struct alias *);
1336static struct alias **__lookupalias (const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00001337
1338static void
1339setalias(name, val)
1340 char *name, *val;
1341{
1342 struct alias *ap, **app;
1343
1344 app = __lookupalias(name);
1345 ap = *app;
1346 INTOFF;
1347 if (ap) {
1348 if (!(ap->flag & ALIASINUSE)) {
1349 ckfree(ap->val);
1350 }
Eric Andersen2870d962001-07-02 17:27:21 +00001351 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00001352 ap->flag &= ~ALIASDEAD;
1353 } else {
1354 /* not found */
1355 ap = ckmalloc(sizeof (struct alias));
1356 ap->name = savestr(name);
1357 ap->val = savestr(val);
1358 ap->flag = 0;
1359 ap->next = 0;
1360 *app = ap;
1361 }
1362 INTON;
1363}
1364
1365static int
Eric Andersen2870d962001-07-02 17:27:21 +00001366unalias(char *name)
1367{
Eric Andersencb57d552001-06-28 07:25:16 +00001368 struct alias **app;
1369
1370 app = __lookupalias(name);
1371
1372 if (*app) {
1373 INTOFF;
1374 *app = freealias(*app);
1375 INTON;
1376 return (0);
1377 }
1378
1379 return (1);
1380}
1381
Eric Andersencb57d552001-06-28 07:25:16 +00001382static void
Eric Andersen2870d962001-07-02 17:27:21 +00001383rmaliases(void)
1384{
Eric Andersencb57d552001-06-28 07:25:16 +00001385 struct alias *ap, **app;
1386 int i;
1387
1388 INTOFF;
1389 for (i = 0; i < ATABSIZE; i++) {
1390 app = &atab[i];
1391 for (ap = *app; ap; ap = *app) {
1392 *app = freealias(*app);
1393 if (ap == *app) {
1394 app = &ap->next;
1395 }
1396 }
1397 }
1398 INTON;
1399}
1400
Eric Andersen2870d962001-07-02 17:27:21 +00001401static struct alias *
1402lookupalias(const char *name, int check)
Eric Andersencb57d552001-06-28 07:25:16 +00001403{
1404 struct alias *ap = *__lookupalias(name);
1405
1406 if (check && ap && (ap->flag & ALIASINUSE))
1407 return (NULL);
1408 return (ap);
1409}
1410
Eric Andersen2870d962001-07-02 17:27:21 +00001411static void
1412printalias(const struct alias *ap) {
1413 char *p;
1414
1415 p = single_quote(ap->val);
Eric Andersen62483552001-07-10 06:09:16 +00001416 printf("alias %s=%s\n", ap->name, p);
Eric Andersen2870d962001-07-02 17:27:21 +00001417 stunalloc(p);
1418}
1419
Eric Andersencb57d552001-06-28 07:25:16 +00001420
1421/*
1422 * TODO - sort output
1423 */
1424static int
Eric Andersen2870d962001-07-02 17:27:21 +00001425aliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001426{
1427 char *n, *v;
1428 int ret = 0;
1429 struct alias *ap;
1430
1431 if (argc == 1) {
1432 int i;
1433
1434 for (i = 0; i < ATABSIZE; i++)
1435 for (ap = atab[i]; ap; ap = ap->next) {
1436 printalias(ap);
1437 }
1438 return (0);
1439 }
1440 while ((n = *++argv) != NULL) {
1441 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
1442 if ((ap = *__lookupalias(n)) == NULL) {
Eric Andersen3102ac42001-07-06 04:26:23 +00001443 out2fmt("%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00001444 ret = 1;
1445 } else
1446 printalias(ap);
1447 }
1448 else {
1449 *v++ = '\0';
1450 setalias(n, v);
1451 }
1452 }
1453
1454 return (ret);
1455}
1456
1457static int
Eric Andersen2870d962001-07-02 17:27:21 +00001458unaliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001459{
1460 int i;
1461
1462 while ((i = nextopt("a")) != '\0') {
1463 if (i == 'a') {
1464 rmaliases();
1465 return (0);
1466 }
1467 }
1468 for (i = 0; *argptr; argptr++) {
1469 if (unalias(*argptr)) {
Eric Andersen3102ac42001-07-06 04:26:23 +00001470 out2fmt("%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00001471 i = 1;
1472 }
1473 }
1474
1475 return (i);
1476}
1477
1478static struct alias **
1479hashalias(p)
1480 const char *p;
1481 {
1482 unsigned int hashval;
1483
1484 hashval = *p << 4;
1485 while (*p)
1486 hashval+= *p++;
1487 return &atab[hashval % ATABSIZE];
1488}
1489
1490static struct alias *
1491freealias(struct alias *ap) {
1492 struct alias *next;
1493
1494 if (ap->flag & ALIASINUSE) {
1495 ap->flag |= ALIASDEAD;
1496 return ap;
1497 }
1498
1499 next = ap->next;
1500 ckfree(ap->name);
1501 ckfree(ap->val);
1502 ckfree(ap);
1503 return next;
1504}
1505
Eric Andersencb57d552001-06-28 07:25:16 +00001506
1507static struct alias **
1508__lookupalias(const char *name) {
1509 struct alias **app = hashalias(name);
1510
1511 for (; *app; app = &(*app)->next) {
1512 if (equal(name, (*app)->name)) {
1513 break;
1514 }
1515 }
1516
1517 return app;
1518}
Eric Andersen2870d962001-07-02 17:27:21 +00001519#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001520
1521#ifdef ASH_MATH_SUPPORT
Eric Andersen74bcd162001-07-30 21:41:37 +00001522/* The generated file arith.c has been replaced with a custom hand
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001523 * written implementation written by Aaron Lehmann <aaronl@vitelus.com>.
1524 * This is now part of libbb, so that it can be used by all the shells
Eric Andersen74bcd162001-07-30 21:41:37 +00001525 * in busybox. */
Eric Andersen2870d962001-07-02 17:27:21 +00001526#define ARITH_NUM 257
1527#define ARITH_LPAREN 258
1528#define ARITH_RPAREN 259
1529#define ARITH_OR 260
1530#define ARITH_AND 261
1531#define ARITH_BOR 262
1532#define ARITH_BXOR 263
1533#define ARITH_BAND 264
1534#define ARITH_EQ 265
1535#define ARITH_NE 266
1536#define ARITH_LT 267
1537#define ARITH_GT 268
1538#define ARITH_GE 269
1539#define ARITH_LE 270
1540#define ARITH_LSHIFT 271
1541#define ARITH_RSHIFT 272
1542#define ARITH_ADD 273
1543#define ARITH_SUB 274
1544#define ARITH_MUL 275
1545#define ARITH_DIV 276
1546#define ARITH_REM 277
1547#define ARITH_UNARYMINUS 278
1548#define ARITH_UNARYPLUS 279
1549#define ARITH_NOT 280
1550#define ARITH_BNOT 281
1551
1552static void expari (int);
Eric Andersencb57d552001-06-28 07:25:16 +00001553#endif
1554
Eric Andersen2870d962001-07-02 17:27:21 +00001555static char *trap[NSIG]; /* trap handler commands */
1556static char sigmode[NSIG - 1]; /* current value of signal */
1557static char gotsig[NSIG - 1]; /* indicates specified signal received */
1558static int pendingsigs; /* indicates some signal received */
1559
Eric Andersencb57d552001-06-28 07:25:16 +00001560/*
1561 * This file was generated by the mkbuiltins program.
1562 */
1563
Eric Andersen2870d962001-07-02 17:27:21 +00001564#ifdef JOBS
1565static int bgcmd (int, char **);
1566static int fgcmd (int, char **);
1567static int killcmd (int, char **);
1568#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001569static int bltincmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001570static int cdcmd (int, char **);
1571static int breakcmd (int, char **);
1572#ifdef ASH_CMDCMD
1573static int commandcmd (int, char **);
1574#endif
1575static int dotcmd (int, char **);
1576static int evalcmd (int, char **);
1577static int execcmd (int, char **);
1578static int exitcmd (int, char **);
1579static int exportcmd (int, char **);
1580static int histcmd (int, char **);
1581static int hashcmd (int, char **);
Eric Andersen1c039232001-07-07 00:05:55 +00001582static int helpcmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001583static int jobscmd (int, char **);
1584static int localcmd (int, char **);
Eric Andersen3102ac42001-07-06 04:26:23 +00001585#ifndef BB_PWD
Eric Andersen2870d962001-07-02 17:27:21 +00001586static int pwdcmd (int, char **);
1587#endif
1588static int readcmd (int, char **);
1589static int returncmd (int, char **);
1590static int setcmd (int, char **);
1591static int setvarcmd (int, char **);
1592static int shiftcmd (int, char **);
1593static int trapcmd (int, char **);
1594static int umaskcmd (int, char **);
1595#ifdef ASH_ALIAS
1596static int aliascmd (int, char **);
1597static int unaliascmd (int, char **);
1598#endif
1599static int unsetcmd (int, char **);
1600static int waitcmd (int, char **);
1601static int ulimitcmd (int, char **);
1602static int timescmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001603#ifdef ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +00001604static int letcmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001605#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001606static int typecmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001607#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00001608static int getoptscmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001609#endif
1610
Eric Andersen2870d962001-07-02 17:27:21 +00001611#ifndef BB_TRUE_FALSE
Eric Andersen2870d962001-07-02 17:27:21 +00001612static int true_main (int, char **);
1613static int false_main (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001614#endif
1615
1616static void setpwd (const char *, int);
1617
1618
1619#define BUILTIN_NOSPEC "0"
1620#define BUILTIN_SPECIAL "1"
1621#define BUILTIN_REGULAR "2"
1622#define BUILTIN_ASSIGN "4"
1623#define BUILTIN_SPEC_ASSG "5"
1624#define BUILTIN_REG_ASSG "6"
1625
1626#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1627#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1628#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
1629
1630struct builtincmd {
1631 const char *name;
1632 int (*const builtinfunc) (int, char **);
1633 //unsigned flags;
1634};
1635
Eric Andersencb57d552001-06-28 07:25:16 +00001636
1637/* It is CRUCIAL that this listing be kept in ascii order, otherwise
1638 * the binary search in find_builtin() will stop working. If you value
1639 * your kneecaps, you'll be sure to *make sure* that any changes made
1640 * to this array result in the listing remaining in ascii order. You
1641 * have been warned.
1642 */
1643static const struct builtincmd builtincmds[] = {
Eric Andersen62483552001-07-10 06:09:16 +00001644 { BUILTIN_SPECIAL ".", dotcmd }, /* first, see declare DOTCMD */
Eric Andersen2870d962001-07-02 17:27:21 +00001645 { BUILTIN_SPECIAL ":", true_main },
1646#ifdef ASH_ALIAS
1647 { BUILTIN_REG_ASSG "alias", aliascmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001648#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001649#ifdef JOBS
1650 { BUILTIN_REGULAR "bg", bgcmd },
1651#endif
1652 { BUILTIN_SPECIAL "break", breakcmd },
Eric Andersen3102ac42001-07-06 04:26:23 +00001653 { BUILTIN_SPECIAL "builtin", bltincmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001654 { BUILTIN_REGULAR "cd", cdcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001655 { BUILTIN_NOSPEC "chdir", cdcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001656#ifdef ASH_CMDCMD
1657 { BUILTIN_REGULAR "command", commandcmd },
1658#endif
1659 { BUILTIN_SPECIAL "continue", breakcmd },
1660 { BUILTIN_SPECIAL "eval", evalcmd },
1661 { BUILTIN_SPECIAL "exec", execcmd },
1662 { BUILTIN_SPECIAL "exit", exitcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001663 { BUILTIN_SPEC_ASSG "export", exportcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001664 { BUILTIN_REGULAR "false", false_main },
Eric Andersen2870d962001-07-02 17:27:21 +00001665 { BUILTIN_REGULAR "fc", histcmd },
1666#ifdef JOBS
1667 { BUILTIN_REGULAR "fg", fgcmd },
1668#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001669#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00001670 { BUILTIN_REGULAR "getopts", getoptscmd },
1671#endif
1672 { BUILTIN_NOSPEC "hash", hashcmd },
Eric Andersen1c039232001-07-07 00:05:55 +00001673 { BUILTIN_NOSPEC "help", helpcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001674 { BUILTIN_REGULAR "jobs", jobscmd },
1675#ifdef JOBS
1676 { BUILTIN_REGULAR "kill", killcmd },
1677#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001678#ifdef ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +00001679 { BUILTIN_REGULAR "let", letcmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001680#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001681 { BUILTIN_ASSIGN "local", localcmd },
Eric Andersen3102ac42001-07-06 04:26:23 +00001682#ifndef BB_PWD
Eric Andersen2870d962001-07-02 17:27:21 +00001683 { BUILTIN_NOSPEC "pwd", pwdcmd },
1684#endif
1685 { BUILTIN_REGULAR "read", readcmd },
1686 { BUILTIN_SPEC_ASSG "readonly", exportcmd },
1687 { BUILTIN_SPECIAL "return", returncmd },
1688 { BUILTIN_SPECIAL "set", setcmd },
1689 { BUILTIN_NOSPEC "setvar", setvarcmd },
1690 { BUILTIN_SPECIAL "shift", shiftcmd },
1691 { BUILTIN_SPECIAL "times", timescmd },
1692 { BUILTIN_SPECIAL "trap", trapcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001693 { BUILTIN_REGULAR "true", true_main },
Eric Andersen2870d962001-07-02 17:27:21 +00001694 { BUILTIN_NOSPEC "type", typecmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001695 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1696 { BUILTIN_REGULAR "umask", umaskcmd },
1697#ifdef ASH_ALIAS
1698 { BUILTIN_REGULAR "unalias", unaliascmd },
1699#endif
1700 { BUILTIN_SPECIAL "unset", unsetcmd },
1701 { BUILTIN_REGULAR "wait", waitcmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001702};
1703#define NUMBUILTINS (sizeof (builtincmds) / sizeof (struct builtincmd) )
1704
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001705#define DOTCMD &builtincmds[0]
Eric Andersen2870d962001-07-02 17:27:21 +00001706static struct builtincmd *BLTINCMD;
1707static struct builtincmd *EXECCMD;
1708static struct builtincmd *EVALCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00001709
Eric Andersen2870d962001-07-02 17:27:21 +00001710/* states */
1711#define JOBSTOPPED 1 /* all procs are stopped */
1712#define JOBDONE 2 /* all procs are completed */
Eric Andersencb57d552001-06-28 07:25:16 +00001713
Eric Andersen2870d962001-07-02 17:27:21 +00001714/*
1715 * A job structure contains information about a job. A job is either a
1716 * single process or a set of processes contained in a pipeline. In the
1717 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1718 * array of pids.
1719 */
Eric Andersencb57d552001-06-28 07:25:16 +00001720
Eric Andersen2870d962001-07-02 17:27:21 +00001721struct procstat {
1722 pid_t pid; /* process id */
1723 int status; /* status flags (defined above) */
1724 char *cmd; /* text of command being run */
1725};
Eric Andersencb57d552001-06-28 07:25:16 +00001726
Eric Andersen2870d962001-07-02 17:27:21 +00001727
1728static int job_warning; /* user was warned about stopped jobs */
1729
1730#ifdef JOBS
1731static void setjobctl(int enable);
1732#else
1733#define setjobctl(on) /* do nothing */
Eric Andersencb57d552001-06-28 07:25:16 +00001734#endif
1735
Eric Andersen2870d962001-07-02 17:27:21 +00001736
1737struct job {
1738 struct procstat ps0; /* status of process */
1739 struct procstat *ps; /* status or processes when more than one */
1740 short nprocs; /* number of processes */
1741 short pgrp; /* process group of this job */
1742 char state; /* true if job is finished */
1743 char used; /* true if this entry is in used */
1744 char changed; /* true if status has changed */
1745#ifdef JOBS
1746 char jobctl; /* job running under job control */
1747#endif
1748};
1749
1750static struct job *jobtab; /* array of jobs */
1751static int njobs; /* size of array */
1752static int backgndpid = -1; /* pid of last background process */
1753#ifdef JOBS
1754static int initialpgrp; /* pgrp of shell on invocation */
1755static int curjob; /* current job */
1756static int jobctl;
1757#endif
1758static int intreceived;
1759
Eric Andersen62483552001-07-10 06:09:16 +00001760static struct job *makejob (const union node *, int);
1761static int forkshell (struct job *, const union node *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00001762static int waitforjob (struct job *);
1763
1764static int docd (char *, int);
1765static char *getcomponent (void);
1766static void updatepwd (const char *);
1767static void getpwd (void);
1768
1769static char *padvance (const char **, const char *);
1770
1771static char nullstr[1]; /* zero length string */
1772static char *curdir = nullstr; /* current working directory */
1773static char *cdcomppath;
1774
Eric Andersencb57d552001-06-28 07:25:16 +00001775static int
1776cdcmd(argc, argv)
1777 int argc;
1778 char **argv;
1779{
1780 const char *dest;
1781 const char *path;
1782 char *p;
1783 struct stat statb;
1784 int print = 0;
1785
1786 nextopt(nullstr);
1787 if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME")) == NULL)
1788 error("HOME not set");
1789 if (*dest == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00001790 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001791 if (dest[0] == '-' && dest[1] == '\0') {
1792 dest = bltinlookup("OLDPWD");
1793 if (!dest || !*dest) {
1794 dest = curdir;
1795 }
1796 print = 1;
1797 if (dest)
Eric Andersen2870d962001-07-02 17:27:21 +00001798 print = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00001799 else
Eric Andersen2870d962001-07-02 17:27:21 +00001800 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001801 }
1802 if (*dest == '/' || (path = bltinlookup("CDPATH")) == NULL)
1803 path = nullstr;
1804 while ((p = padvance(&path, dest)) != NULL) {
1805 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
1806 if (!print) {
1807 /*
1808 * XXX - rethink
1809 */
1810 if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
1811 p += 2;
1812 print = strcmp(p, dest);
1813 }
1814 if (docd(p, print) >= 0)
1815 return 0;
1816
1817 }
1818 }
1819 error("can't cd to %s", dest);
1820 /* NOTREACHED */
1821}
1822
1823
1824/*
1825 * Actually do the chdir. In an interactive shell, print the
1826 * directory name if "print" is nonzero.
1827 */
1828
1829static int
1830docd(dest, print)
1831 char *dest;
1832 int print;
1833{
1834 char *p;
1835 char *q;
1836 char *component;
1837 struct stat statb;
1838 int first;
1839 int badstat;
1840
1841 TRACE(("docd(\"%s\", %d) called\n", dest, print));
1842
1843 /*
1844 * Check each component of the path. If we find a symlink or
1845 * something we can't stat, clear curdir to force a getcwd()
1846 * next time we get the value of the current directory.
1847 */
1848 badstat = 0;
1849 cdcomppath = sstrdup(dest);
1850 STARTSTACKSTR(p);
1851 if (*dest == '/') {
1852 STPUTC('/', p);
1853 cdcomppath++;
1854 }
1855 first = 1;
1856 while ((q = getcomponent()) != NULL) {
1857 if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0'))
1858 continue;
1859 if (! first)
1860 STPUTC('/', p);
1861 first = 0;
1862 component = q;
1863 while (*q)
1864 STPUTC(*q++, p);
1865 if (equal(component, ".."))
1866 continue;
1867 STACKSTRNUL(p);
1868 if ((lstat(stackblock(), &statb) < 0)
1869 || (S_ISLNK(statb.st_mode))) {
1870 /* print = 1; */
1871 badstat = 1;
1872 break;
1873 }
1874 }
1875
1876 INTOFF;
1877 if (chdir(dest) < 0) {
1878 INTON;
1879 return -1;
1880 }
1881 updatepwd(badstat ? NULL : dest);
1882 INTON;
1883 if (print && iflag)
Eric Andersen62483552001-07-10 06:09:16 +00001884 printf(snlfmt, curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00001885 return 0;
1886}
1887
1888
1889/*
1890 * Get the next component of the path name pointed to by cdcomppath.
1891 * This routine overwrites the string pointed to by cdcomppath.
1892 */
1893
1894static char *
1895getcomponent() {
1896 char *p;
1897 char *start;
1898
1899 if ((p = cdcomppath) == NULL)
1900 return NULL;
1901 start = cdcomppath;
1902 while (*p != '/' && *p != '\0')
1903 p++;
1904 if (*p == '\0') {
1905 cdcomppath = NULL;
1906 } else {
1907 *p++ = '\0';
1908 cdcomppath = p;
1909 }
1910 return start;
1911}
1912
1913
1914
1915/*
1916 * Update curdir (the name of the current directory) in response to a
1917 * cd command. We also call hashcd to let the routines in exec.c know
1918 * that the current directory has changed.
1919 */
1920
Eric Andersen2870d962001-07-02 17:27:21 +00001921static void hashcd (void);
1922
Eric Andersencb57d552001-06-28 07:25:16 +00001923static void
Eric Andersen2870d962001-07-02 17:27:21 +00001924updatepwd(const char *dir)
1925{
Eric Andersencb57d552001-06-28 07:25:16 +00001926 char *new;
1927 char *p;
1928 size_t len;
1929
Eric Andersen2870d962001-07-02 17:27:21 +00001930 hashcd(); /* update command hash table */
Eric Andersencb57d552001-06-28 07:25:16 +00001931
1932 /*
1933 * If our argument is NULL, we don't know the current directory
1934 * any more because we traversed a symbolic link or something
1935 * we couldn't stat().
1936 */
1937 if (dir == NULL || curdir == nullstr) {
1938 setpwd(0, 1);
1939 return;
1940 }
1941 len = strlen(dir);
1942 cdcomppath = sstrdup(dir);
1943 STARTSTACKSTR(new);
1944 if (*dir != '/') {
1945 p = curdir;
1946 while (*p)
1947 STPUTC(*p++, new);
1948 if (p[-1] == '/')
1949 STUNPUTC(new);
1950 }
1951 while ((p = getcomponent()) != NULL) {
1952 if (equal(p, "..")) {
1953 while (new > stackblock() && (STUNPUTC(new), *new) != '/');
1954 } else if (*p != '\0' && ! equal(p, ".")) {
1955 STPUTC('/', new);
1956 while (*p)
1957 STPUTC(*p++, new);
1958 }
1959 }
1960 if (new == stackblock())
1961 STPUTC('/', new);
1962 STACKSTRNUL(new);
1963 setpwd(stackblock(), 1);
1964}
1965
1966
Eric Andersen3102ac42001-07-06 04:26:23 +00001967#ifndef BB_PWD
Eric Andersencb57d552001-06-28 07:25:16 +00001968static int
1969pwdcmd(argc, argv)
1970 int argc;
1971 char **argv;
1972{
Eric Andersen62483552001-07-10 06:09:16 +00001973 printf(snlfmt, curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00001974 return 0;
1975}
Eric Andersen2870d962001-07-02 17:27:21 +00001976#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001977
1978/*
1979 * Find out what the current directory is. If we already know the current
1980 * directory, this routine returns immediately.
1981 */
1982static void
Eric Andersen2870d962001-07-02 17:27:21 +00001983getpwd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00001984{
Eric Andersen2870d962001-07-02 17:27:21 +00001985 curdir = xgetcwd(0);
1986 if(curdir==0)
1987 curdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00001988}
1989
1990static void
1991setpwd(const char *val, int setold)
1992{
1993 if (setold) {
1994 setvar("OLDPWD", curdir, VEXPORT);
1995 }
1996 INTOFF;
1997 if (curdir != nullstr) {
1998 free(curdir);
1999 curdir = nullstr;
2000 }
2001 if (!val) {
2002 getpwd();
2003 } else {
2004 curdir = savestr(val);
2005 }
2006 INTON;
2007 setvar("PWD", curdir, VEXPORT);
2008}
2009
Eric Andersencb57d552001-06-28 07:25:16 +00002010/*
2011 * Errors and exceptions.
2012 */
2013
2014/*
2015 * Code to handle exceptions in C.
2016 */
2017
Eric Andersen2870d962001-07-02 17:27:21 +00002018/*
2019 * We enclose jmp_buf in a structure so that we can declare pointers to
2020 * jump locations. The global variable handler contains the location to
2021 * jump to when an exception occurs, and the global variable exception
2022 * contains a code identifying the exeception. To implement nested
2023 * exception handlers, the user should save the value of handler on entry
2024 * to an inner scope, set handler to point to a jmploc structure for the
2025 * inner scope, and restore handler on exit from the scope.
2026 */
2027
2028struct jmploc {
2029 jmp_buf loc;
2030};
2031
2032/* exceptions */
2033#define EXINT 0 /* SIGINT received */
2034#define EXERROR 1 /* a generic error */
2035#define EXSHELLPROC 2 /* execute a shell procedure */
2036#define EXEXEC 3 /* command execution failed */
2037
2038static struct jmploc *handler;
Eric Andersencb57d552001-06-28 07:25:16 +00002039static int exception;
Eric Andersencb57d552001-06-28 07:25:16 +00002040
Eric Andersen2870d962001-07-02 17:27:21 +00002041static void exverror (int, const char *, va_list)
Eric Andersencb57d552001-06-28 07:25:16 +00002042 __attribute__((__noreturn__));
2043
2044/*
2045 * Called to raise an exception. Since C doesn't include exceptions, we
2046 * just do a longjmp to the exception handler. The type of exception is
2047 * stored in the global variable "exception".
2048 */
2049
Eric Andersen2870d962001-07-02 17:27:21 +00002050static void exraise (int) __attribute__((__noreturn__));
2051
Eric Andersencb57d552001-06-28 07:25:16 +00002052static void
Eric Andersen2870d962001-07-02 17:27:21 +00002053exraise(int e)
Eric Andersencb57d552001-06-28 07:25:16 +00002054{
2055#ifdef DEBUG
2056 if (handler == NULL)
2057 abort();
2058#endif
Eric Andersen62483552001-07-10 06:09:16 +00002059 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00002060 exception = e;
2061 longjmp(handler->loc, 1);
2062}
2063
2064
2065/*
2066 * Called from trap.c when a SIGINT is received. (If the user specifies
2067 * that SIGINT is to be trapped or ignored using the trap builtin, then
2068 * this routine is not called.) Suppressint is nonzero when interrupts
2069 * are held using the INTOFF macro. The call to _exit is necessary because
2070 * there is a short period after a fork before the signal handlers are
2071 * set to the appropriate value for the child. (The test for iflag is
2072 * just defensive programming.)
2073 */
2074
2075static void
Eric Andersen2870d962001-07-02 17:27:21 +00002076onint(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00002077 sigset_t mysigset;
2078
2079 if (suppressint) {
2080 intpending++;
2081 return;
2082 }
2083 intpending = 0;
2084 sigemptyset(&mysigset);
2085 sigprocmask(SIG_SETMASK, &mysigset, NULL);
2086 if (rootshell && iflag)
2087 exraise(EXINT);
2088 else {
2089 signal(SIGINT, SIG_DFL);
2090 raise(SIGINT);
2091 }
2092 /* NOTREACHED */
2093}
2094
2095
Eric Andersen2870d962001-07-02 17:27:21 +00002096static char *commandname; /* currently executing command */
2097
Eric Andersencb57d552001-06-28 07:25:16 +00002098/*
2099 * Exverror is called to raise the error exception. If the first argument
2100 * is not NULL then error prints an error message using printf style
2101 * formatting. It then raises the error exception.
2102 */
2103static void
Eric Andersen2870d962001-07-02 17:27:21 +00002104exverror(int cond, const char *msg, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00002105{
2106 CLEAR_PENDING_INT;
2107 INTOFF;
2108
2109#ifdef DEBUG
2110 if (msg)
2111 TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
2112 else
2113 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2114#endif
2115 if (msg) {
2116 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +00002117 out2fmt("%s: ", commandname);
2118 vfprintf(stderr, msg, ap);
2119 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00002120 }
Eric Andersencb57d552001-06-28 07:25:16 +00002121 exraise(cond);
2122 /* NOTREACHED */
2123}
2124
2125
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002126static void
Eric Andersencb57d552001-06-28 07:25:16 +00002127error(const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002128{
Eric Andersencb57d552001-06-28 07:25:16 +00002129 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002130 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002131 exverror(EXERROR, msg, ap);
2132 /* NOTREACHED */
2133 va_end(ap);
2134}
2135
2136
Eric Andersencb57d552001-06-28 07:25:16 +00002137static void
2138exerror(int cond, const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002139{
Eric Andersencb57d552001-06-28 07:25:16 +00002140 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002141 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002142 exverror(cond, msg, ap);
2143 /* NOTREACHED */
2144 va_end(ap);
2145}
2146
2147
2148
2149/*
2150 * Table of error messages.
2151 */
2152
2153struct errname {
Eric Andersen2870d962001-07-02 17:27:21 +00002154 short errcode; /* error number */
Eric Andersen62483552001-07-10 06:09:16 +00002155 char action; /* operation which encountered the error */
Eric Andersencb57d552001-06-28 07:25:16 +00002156};
2157
Eric Andersen2870d962001-07-02 17:27:21 +00002158/*
2159 * Types of operations (passed to the errmsg routine).
2160 */
2161
2162#define E_OPEN 01 /* opening a file */
2163#define E_CREAT 02 /* creating a file */
2164#define E_EXEC 04 /* executing a program */
Eric Andersencb57d552001-06-28 07:25:16 +00002165
2166#define ALL (E_OPEN|E_CREAT|E_EXEC)
2167
2168static const struct errname errormsg[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00002169 { EINTR, ALL },
2170 { EACCES, ALL },
2171 { EIO, ALL },
2172 { ENOENT, E_OPEN },
2173 { ENOENT, E_CREAT },
2174 { ENOENT, E_EXEC },
2175 { ENOTDIR, E_OPEN },
2176 { ENOTDIR, E_CREAT },
2177 { ENOTDIR, E_EXEC },
2178 { EISDIR, ALL },
2179 { EEXIST, E_CREAT },
2180#ifdef EMFILE
2181 { EMFILE, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002182#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002183 { ENFILE, ALL },
2184 { ENOSPC, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002185#ifdef EDQUOT
Eric Andersen2870d962001-07-02 17:27:21 +00002186 { EDQUOT, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002187#endif
2188#ifdef ENOSR
Eric Andersen2870d962001-07-02 17:27:21 +00002189 { ENOSR, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002190#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002191 { ENXIO, ALL },
2192 { EROFS, ALL },
2193 { ETXTBSY, ALL },
2194#ifdef EAGAIN
2195 { EAGAIN, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002196#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002197 { ENOMEM, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002198#ifdef ENOLINK
Eric Andersen2870d962001-07-02 17:27:21 +00002199 { ENOLINK, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002200#endif
2201#ifdef EMULTIHOP
Eric Andersen2870d962001-07-02 17:27:21 +00002202 { EMULTIHOP, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002203#endif
2204#ifdef ECOMM
Eric Andersen2870d962001-07-02 17:27:21 +00002205 { ECOMM, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002206#endif
2207#ifdef ESTALE
Eric Andersen2870d962001-07-02 17:27:21 +00002208 { ESTALE, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002209#endif
2210#ifdef ETIMEDOUT
Eric Andersen2870d962001-07-02 17:27:21 +00002211 { ETIMEDOUT, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002212#endif
2213#ifdef ELOOP
Eric Andersen2870d962001-07-02 17:27:21 +00002214 { ELOOP, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002215#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002216 { E2BIG, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002217#ifdef ELIBACC
Eric Andersen2870d962001-07-02 17:27:21 +00002218 { ELIBACC, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002219#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002220};
2221
Eric Andersen2870d962001-07-02 17:27:21 +00002222#define ERRNAME_SIZE (sizeof(errormsg)/sizeof(struct errname))
Eric Andersencb57d552001-06-28 07:25:16 +00002223
2224/*
2225 * Return a string describing an error. The returned string may be a
2226 * pointer to a static buffer that will be overwritten on the next call.
2227 * Action describes the operation that got the error.
2228 */
2229
2230static const char *
Eric Andersen2870d962001-07-02 17:27:21 +00002231errmsg(int e, int action)
Eric Andersencb57d552001-06-28 07:25:16 +00002232{
2233 struct errname const *ep;
2234 static char buf[12];
2235
Eric Andersen2870d962001-07-02 17:27:21 +00002236 for (ep = errormsg ; ep < errormsg+ERRNAME_SIZE; ep++) {
Eric Andersencb57d552001-06-28 07:25:16 +00002237 if (ep->errcode == e && (ep->action & action) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00002238 return strerror(e);
Eric Andersencb57d552001-06-28 07:25:16 +00002239 }
Eric Andersen2870d962001-07-02 17:27:21 +00002240
Eric Andersen3102ac42001-07-06 04:26:23 +00002241 snprintf(buf, sizeof buf, "error %d", e);
Eric Andersencb57d552001-06-28 07:25:16 +00002242 return buf;
2243}
2244
2245
Eric Andersen3102ac42001-07-06 04:26:23 +00002246#ifdef ASH_OPTIMIZE_FOR_SIZE
Eric Andersencb57d552001-06-28 07:25:16 +00002247static void
2248__inton() {
2249 if (--suppressint == 0 && intpending) {
2250 onint();
2251 }
2252}
Eric Andersen3102ac42001-07-06 04:26:23 +00002253static void forceinton (void) {
2254 suppressint = 0;
2255 if (intpending)
2256 onint();
2257}
Eric Andersencb57d552001-06-28 07:25:16 +00002258#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002259
2260/* flags in argument to evaltree */
Eric Andersen2870d962001-07-02 17:27:21 +00002261#define EV_EXIT 01 /* exit after evaluating tree */
2262#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2263#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00002264
Eric Andersen2870d962001-07-02 17:27:21 +00002265static int evalskip; /* set if we are skipping commands */
2266static int skipcount; /* number of levels to skip */
2267static int loopnest; /* current loop nesting level */
2268static int funcnest; /* depth of function calls */
Eric Andersencb57d552001-06-28 07:25:16 +00002269
2270
Eric Andersen2870d962001-07-02 17:27:21 +00002271static struct strlist *cmdenviron; /* environment for builtin command */
2272static int exitstatus; /* exit status of last command */
2273static int oexitstatus; /* saved exit status */
Eric Andersencb57d552001-06-28 07:25:16 +00002274
Eric Andersen62483552001-07-10 06:09:16 +00002275static void evalsubshell (const union node *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00002276static void expredir (union node *);
Eric Andersen2870d962001-07-02 17:27:21 +00002277static void prehash (union node *);
2278static void eprintlist (struct strlist *);
Eric Andersencb57d552001-06-28 07:25:16 +00002279
Eric Andersen2870d962001-07-02 17:27:21 +00002280static union node *parsecmd(int);
Eric Andersencb57d552001-06-28 07:25:16 +00002281/*
2282 * Called to reset things after an exception.
2283 */
2284
Eric Andersencb57d552001-06-28 07:25:16 +00002285/*
2286 * The eval commmand.
2287 */
Eric Andersen2870d962001-07-02 17:27:21 +00002288static void evalstring (char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00002289
2290static int
2291evalcmd(argc, argv)
2292 int argc;
2293 char **argv;
2294{
Eric Andersen2870d962001-07-02 17:27:21 +00002295 char *p;
2296 char *concat;
2297 char **ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002298
Eric Andersen2870d962001-07-02 17:27:21 +00002299 if (argc > 1) {
2300 p = argv[1];
2301 if (argc > 2) {
2302 STARTSTACKSTR(concat);
2303 ap = argv + 2;
2304 for (;;) {
2305 while (*p)
2306 STPUTC(*p++, concat);
2307 if ((p = *ap++) == NULL)
2308 break;
2309 STPUTC(' ', concat);
2310 }
2311 STPUTC('\0', concat);
2312 p = grabstackstr(concat);
2313 }
2314 evalstring(p, EV_TESTED);
2315 }
2316 return exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002317}
2318
Eric Andersencb57d552001-06-28 07:25:16 +00002319/*
2320 * Execute a command or commands contained in a string.
2321 */
2322
Eric Andersen2870d962001-07-02 17:27:21 +00002323static void evaltree (union node *, int);
2324static void setinputstring (char *);
2325static void popfile (void);
2326static void setstackmark(struct stackmark *mark);
2327static void popstackmark(struct stackmark *mark);
2328
2329
Eric Andersencb57d552001-06-28 07:25:16 +00002330static void
Eric Andersen2870d962001-07-02 17:27:21 +00002331evalstring(char *s, int flag)
2332{
Eric Andersencb57d552001-06-28 07:25:16 +00002333 union node *n;
2334 struct stackmark smark;
2335
2336 setstackmark(&smark);
2337 setinputstring(s);
2338 while ((n = parsecmd(0)) != NEOF) {
2339 evaltree(n, flag);
2340 popstackmark(&smark);
2341 }
2342 popfile();
2343 popstackmark(&smark);
2344}
2345
Eric Andersen2870d962001-07-02 17:27:21 +00002346static struct builtincmd *find_builtin (const char *);
Eric Andersen62483552001-07-10 06:09:16 +00002347static void expandarg (union node *, struct arglist *, int);
2348static void calcsize (const union node *);
2349static union node *copynode (const union node *);
2350
2351/*
2352 * Make a copy of a parse tree.
2353 */
2354
2355static int funcblocksize; /* size of structures in function */
2356static int funcstringsize; /* size of strings in node */
2357static pointer funcblock; /* block to allocate function from */
2358static char *funcstring; /* block to allocate strings from */
2359
2360
2361static inline union node *
2362copyfunc(union node *n)
2363{
2364 if (n == NULL)
2365 return NULL;
2366 funcblocksize = 0;
2367 funcstringsize = 0;
2368 calcsize(n);
2369 funcblock = ckmalloc(funcblocksize + funcstringsize);
2370 funcstring = (char *) funcblock + funcblocksize;
2371 return copynode(n);
2372}
2373
2374/*
2375 * Free a parse tree.
2376 */
Eric Andersencb57d552001-06-28 07:25:16 +00002377
2378static void
Eric Andersen62483552001-07-10 06:09:16 +00002379freefunc(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00002380{
Eric Andersen62483552001-07-10 06:09:16 +00002381 if (n)
2382 ckfree(n);
Eric Andersencb57d552001-06-28 07:25:16 +00002383}
2384
2385
Eric Andersen62483552001-07-10 06:09:16 +00002386/*
2387 * Add a new command entry, replacing any existing command entry for
2388 * the same name.
2389 */
2390
2391static inline void
2392addcmdentry(char *name, struct cmdentry *entry)
2393{
2394 struct tblentry *cmdp;
2395
2396 INTOFF;
2397 cmdp = cmdlookup(name, 1);
2398 if (cmdp->cmdtype == CMDFUNCTION) {
2399 freefunc(cmdp->param.func);
2400 }
2401 cmdp->cmdtype = entry->cmdtype;
2402 cmdp->param = entry->u;
2403 INTON;
2404}
2405
2406static inline void
2407evalloop(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002408{
2409 int status;
2410
2411 loopnest++;
2412 status = 0;
2413 for (;;) {
2414 evaltree(n->nbinary.ch1, EV_TESTED);
2415 if (evalskip) {
Eric Andersen2870d962001-07-02 17:27:21 +00002416skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002417 evalskip = 0;
2418 continue;
2419 }
2420 if (evalskip == SKIPBREAK && --skipcount <= 0)
2421 evalskip = 0;
2422 break;
2423 }
2424 if (n->type == NWHILE) {
2425 if (exitstatus != 0)
2426 break;
2427 } else {
2428 if (exitstatus == 0)
2429 break;
2430 }
2431 evaltree(n->nbinary.ch2, flags & EV_TESTED);
2432 status = exitstatus;
2433 if (evalskip)
2434 goto skipping;
2435 }
2436 loopnest--;
2437 exitstatus = status;
2438}
2439
Eric Andersencb57d552001-06-28 07:25:16 +00002440static void
Eric Andersen62483552001-07-10 06:09:16 +00002441evalfor(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002442{
2443 struct arglist arglist;
2444 union node *argp;
2445 struct strlist *sp;
2446 struct stackmark smark;
2447
2448 setstackmark(&smark);
2449 arglist.lastp = &arglist.list;
2450 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2451 oexitstatus = exitstatus;
2452 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2453 if (evalskip)
2454 goto out;
2455 }
2456 *arglist.lastp = NULL;
2457
2458 exitstatus = 0;
2459 loopnest++;
2460 for (sp = arglist.list ; sp ; sp = sp->next) {
2461 setvar(n->nfor.var, sp->text, 0);
2462 evaltree(n->nfor.body, flags & EV_TESTED);
2463 if (evalskip) {
2464 if (evalskip == SKIPCONT && --skipcount <= 0) {
2465 evalskip = 0;
2466 continue;
2467 }
2468 if (evalskip == SKIPBREAK && --skipcount <= 0)
2469 evalskip = 0;
2470 break;
2471 }
2472 }
2473 loopnest--;
2474out:
2475 popstackmark(&smark);
2476}
2477
Eric Andersen62483552001-07-10 06:09:16 +00002478static inline void
2479evalcase(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002480{
2481 union node *cp;
2482 union node *patp;
2483 struct arglist arglist;
2484 struct stackmark smark;
2485
2486 setstackmark(&smark);
2487 arglist.lastp = &arglist.list;
2488 oexitstatus = exitstatus;
2489 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2490 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2491 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2492 if (casematch(patp, arglist.list->text)) {
2493 if (evalskip == 0) {
2494 evaltree(cp->nclist.body, flags);
2495 }
2496 goto out;
2497 }
2498 }
2499 }
2500out:
2501 popstackmark(&smark);
2502}
2503
Eric Andersencb57d552001-06-28 07:25:16 +00002504/*
Eric Andersencb57d552001-06-28 07:25:16 +00002505 * Evaluate a pipeline. All the processes in the pipeline are children
2506 * of the process creating the pipeline. (This differs from some versions
2507 * of the shell, which make the last process in a pipeline the parent
2508 * of all the rest.)
2509 */
2510
Eric Andersen62483552001-07-10 06:09:16 +00002511static inline void
Eric Andersencb57d552001-06-28 07:25:16 +00002512evalpipe(n)
2513 union node *n;
2514{
2515 struct job *jp;
2516 struct nodelist *lp;
2517 int pipelen;
2518 int prevfd;
2519 int pip[2];
2520
2521 TRACE(("evalpipe(0x%lx) called\n", (long)n));
2522 pipelen = 0;
2523 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
2524 pipelen++;
2525 INTOFF;
2526 jp = makejob(n, pipelen);
2527 prevfd = -1;
2528 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
2529 prehash(lp->n);
2530 pip[1] = -1;
2531 if (lp->next) {
2532 if (pipe(pip) < 0) {
2533 close(prevfd);
2534 error("Pipe call failed");
2535 }
2536 }
2537 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
2538 INTON;
2539 if (prevfd > 0) {
2540 close(0);
2541 dup_as_newfd(prevfd, 0);
2542 close(prevfd);
2543 if (pip[0] == 0) {
2544 pip[0] = -1;
2545 }
2546 }
2547 if (pip[1] >= 0) {
2548 if (pip[0] >= 0) {
2549 close(pip[0]);
2550 }
2551 if (pip[1] != 1) {
2552 close(1);
2553 dup_as_newfd(pip[1], 1);
2554 close(pip[1]);
2555 }
2556 }
2557 evaltree(lp->n, EV_EXIT);
2558 }
2559 if (prevfd >= 0)
2560 close(prevfd);
2561 prevfd = pip[0];
2562 close(pip[1]);
2563 }
2564 INTON;
2565 if (n->npipe.backgnd == 0) {
2566 INTOFF;
2567 exitstatus = waitforjob(jp);
2568 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
2569 INTON;
2570 }
2571}
2572
Eric Andersen2870d962001-07-02 17:27:21 +00002573static void find_command (const char *, struct cmdentry *, int, const char *);
2574
2575static int
2576isassignment(const char *word) {
2577 if (!is_name(*word)) {
2578 return 0;
2579 }
2580 do {
2581 word++;
2582 } while (is_in_name(*word));
2583 return *word == '=';
2584}
2585
Eric Andersen62483552001-07-10 06:09:16 +00002586
Eric Andersencb57d552001-06-28 07:25:16 +00002587static void
Eric Andersen3102ac42001-07-06 04:26:23 +00002588evalcommand(union node *cmd, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002589{
2590 struct stackmark smark;
2591 union node *argp;
2592 struct arglist arglist;
2593 struct arglist varlist;
2594 char **argv;
2595 int argc;
2596 char **envp;
2597 struct strlist *sp;
2598 int mode;
Eric Andersencb57d552001-06-28 07:25:16 +00002599 struct cmdentry cmdentry;
2600 struct job *jp;
2601 char *volatile savecmdname;
2602 volatile struct shparam saveparam;
2603 struct localvar *volatile savelocalvars;
2604 volatile int e;
2605 char *lastarg;
2606 const char *path;
2607 const struct builtincmd *firstbltin;
2608 struct jmploc *volatile savehandler;
2609 struct jmploc jmploc;
2610#if __GNUC__
2611 /* Avoid longjmp clobbering */
2612 (void) &argv;
2613 (void) &argc;
2614 (void) &lastarg;
2615 (void) &flags;
2616#endif
2617
2618 /* First expand the arguments. */
2619 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
2620 setstackmark(&smark);
2621 arglist.lastp = &arglist.list;
2622 varlist.lastp = &varlist.list;
2623 arglist.list = 0;
2624 oexitstatus = exitstatus;
2625 exitstatus = 0;
2626 path = pathval();
2627 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
2628 expandarg(argp, &varlist, EXP_VARTILDE);
2629 }
2630 for (
2631 argp = cmd->ncmd.args; argp && !arglist.list;
2632 argp = argp->narg.next
2633 ) {
2634 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2635 }
2636 if (argp) {
2637 struct builtincmd *bcmd;
Eric Andersen62483552001-07-10 06:09:16 +00002638 int pseudovarflag;
Eric Andersencb57d552001-06-28 07:25:16 +00002639 bcmd = find_builtin(arglist.list->text);
Eric Andersen2870d962001-07-02 17:27:21 +00002640 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00002641 for (; argp; argp = argp->narg.next) {
2642 if (pseudovarflag && isassignment(argp->narg.text)) {
2643 expandarg(argp, &arglist, EXP_VARTILDE);
2644 continue;
2645 }
2646 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2647 }
2648 }
2649 *arglist.lastp = NULL;
2650 *varlist.lastp = NULL;
2651 expredir(cmd->ncmd.redirect);
2652 argc = 0;
2653 for (sp = arglist.list ; sp ; sp = sp->next)
2654 argc++;
2655 argv = stalloc(sizeof (char *) * (argc + 1));
2656
2657 for (sp = arglist.list ; sp ; sp = sp->next) {
2658 TRACE(("evalcommand arg: %s\n", sp->text));
2659 *argv++ = sp->text;
2660 }
2661 *argv = NULL;
2662 lastarg = NULL;
2663 if (iflag && funcnest == 0 && argc > 0)
2664 lastarg = argv[-1];
2665 argv -= argc;
2666
2667 /* Print the command if xflag is set. */
2668 if (xflag) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002669 out2c('+');
Eric Andersencb57d552001-06-28 07:25:16 +00002670 eprintlist(varlist.list);
2671 eprintlist(arglist.list);
Eric Andersen3102ac42001-07-06 04:26:23 +00002672 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00002673 }
2674
2675 /* Now locate the command. */
2676 if (argc == 0) {
2677 cmdentry.cmdtype = CMDBUILTIN;
2678 firstbltin = cmdentry.u.cmd = BLTINCMD;
2679 } else {
2680 const char *oldpath;
2681 int findflag = DO_ERR;
2682 int oldfindflag;
2683
2684 /*
2685 * Modify the command lookup path, if a PATH= assignment
2686 * is present
2687 */
2688 for (sp = varlist.list ; sp ; sp = sp->next)
2689 if (varequal(sp->text, defpathvar)) {
2690 path = sp->text + 5;
2691 findflag |= DO_BRUTE;
2692 }
2693 oldpath = path;
2694 oldfindflag = findflag;
2695 firstbltin = 0;
2696 for(;;) {
2697 find_command(argv[0], &cmdentry, findflag, path);
Eric Andersen2870d962001-07-02 17:27:21 +00002698 if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */
Eric Andersencb57d552001-06-28 07:25:16 +00002699 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002700 goto out;
2701 }
2702 /* implement bltin and command here */
2703 if (cmdentry.cmdtype != CMDBUILTIN) {
2704 break;
2705 }
2706 if (!firstbltin) {
2707 firstbltin = cmdentry.u.cmd;
2708 }
2709 if (cmdentry.u.cmd == BLTINCMD) {
2710 for(;;) {
2711 struct builtincmd *bcmd;
2712
2713 argv++;
2714 if (--argc == 0)
2715 goto found;
2716 if (!(bcmd = find_builtin(*argv))) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002717 out2fmt("%s: not found\n", *argv);
Eric Andersencb57d552001-06-28 07:25:16 +00002718 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002719 goto out;
2720 }
2721 cmdentry.u.cmd = bcmd;
2722 if (bcmd != BLTINCMD)
2723 break;
2724 }
2725 }
Eric Andersen2870d962001-07-02 17:27:21 +00002726 if (cmdentry.u.cmd == find_builtin("command")) {
Eric Andersencb57d552001-06-28 07:25:16 +00002727 argv++;
2728 if (--argc == 0) {
2729 goto found;
2730 }
2731 if (*argv[0] == '-') {
2732 if (!equal(argv[0], "-p")) {
2733 argv--;
2734 argc++;
2735 break;
2736 }
2737 argv++;
2738 if (--argc == 0) {
2739 goto found;
2740 }
2741 path = defpath;
2742 findflag |= DO_BRUTE;
2743 } else {
2744 path = oldpath;
2745 findflag = oldfindflag;
2746 }
2747 findflag |= DO_NOFUN;
2748 continue;
2749 }
2750found:
2751 break;
2752 }
2753 }
2754
2755 /* Fork off a child process if necessary. */
2756 if (cmd->ncmd.backgnd
2757 || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00002758 ) {
2759 jp = makejob(cmd, 1);
2760 mode = cmd->ncmd.backgnd;
Eric Andersencb57d552001-06-28 07:25:16 +00002761 if (forkshell(jp, cmd, mode) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00002762 goto parent; /* at end of routine */
Eric Andersencb57d552001-06-28 07:25:16 +00002763 flags |= EV_EXIT;
2764 }
2765
2766 /* This is the child process if a fork occurred. */
2767 /* Execute the command. */
2768 if (cmdentry.cmdtype == CMDFUNCTION) {
2769#ifdef DEBUG
2770 trputs("Shell function: "); trargs(argv);
2771#endif
2772 exitstatus = oexitstatus;
2773 redirect(cmd->ncmd.redirect, REDIR_PUSH);
2774 saveparam = shellparam;
2775 shellparam.malloc = 0;
2776 shellparam.nparam = argc - 1;
2777 shellparam.p = argv + 1;
2778 INTOFF;
2779 savelocalvars = localvars;
2780 localvars = NULL;
2781 INTON;
2782 if (setjmp(jmploc.loc)) {
2783 if (exception == EXSHELLPROC) {
2784 freeparam((volatile struct shparam *)
2785 &saveparam);
2786 } else {
2787 saveparam.optind = shellparam.optind;
2788 saveparam.optoff = shellparam.optoff;
2789 freeparam(&shellparam);
2790 shellparam = saveparam;
2791 }
2792 poplocalvars();
2793 localvars = savelocalvars;
2794 handler = savehandler;
2795 longjmp(handler->loc, 1);
2796 }
2797 savehandler = handler;
2798 handler = &jmploc;
2799 for (sp = varlist.list ; sp ; sp = sp->next)
2800 mklocal(sp->text);
2801 funcnest++;
2802 evaltree(cmdentry.u.func, flags & EV_TESTED);
2803 funcnest--;
2804 INTOFF;
2805 poplocalvars();
2806 localvars = savelocalvars;
2807 saveparam.optind = shellparam.optind;
2808 saveparam.optoff = shellparam.optoff;
2809 freeparam(&shellparam);
2810 shellparam = saveparam;
2811 handler = savehandler;
2812 popredir();
2813 INTON;
2814 if (evalskip == SKIPFUNC) {
2815 evalskip = 0;
2816 skipcount = 0;
2817 }
2818 if (flags & EV_EXIT)
2819 exitshell(exitstatus);
2820 } else if (cmdentry.cmdtype == CMDBUILTIN) {
2821#ifdef DEBUG
2822 trputs("builtin command: "); trargs(argv);
2823#endif
2824 mode = (cmdentry.u.cmd == EXECCMD)? 0 : REDIR_PUSH;
Eric Andersencb57d552001-06-28 07:25:16 +00002825 redirect(cmd->ncmd.redirect, mode);
2826 savecmdname = commandname;
Eric Andersen2870d962001-07-02 17:27:21 +00002827 if (IS_BUILTIN_SPECIAL(firstbltin)) {
Eric Andersencb57d552001-06-28 07:25:16 +00002828 listsetvar(varlist.list);
2829 } else {
2830 cmdenviron = varlist.list;
2831 }
2832 e = -1;
2833 if (setjmp(jmploc.loc)) {
2834 e = exception;
2835 exitstatus = (e == EXINT)? SIGINT+128 : 2;
2836 goto cmddone;
2837 }
2838 savehandler = handler;
2839 handler = &jmploc;
2840 commandname = argv[0];
2841 argptr = argv + 1;
Eric Andersen2870d962001-07-02 17:27:21 +00002842 optptr = NULL; /* initialize nextopt */
Eric Andersencb57d552001-06-28 07:25:16 +00002843 exitstatus = (*cmdentry.u.cmd->builtinfunc)(argc, argv);
2844 flushall();
2845cmddone:
Eric Andersencb57d552001-06-28 07:25:16 +00002846 cmdenviron = NULL;
2847 if (e != EXSHELLPROC) {
2848 commandname = savecmdname;
2849 if (flags & EV_EXIT)
2850 exitshell(exitstatus);
2851 }
2852 handler = savehandler;
2853 if (e != -1) {
2854 if ((e != EXERROR && e != EXEXEC)
2855 || cmdentry.u.cmd == BLTINCMD
2856 || cmdentry.u.cmd == DOTCMD
2857 || cmdentry.u.cmd == EVALCMD
2858 || cmdentry.u.cmd == EXECCMD)
2859 exraise(e);
2860 FORCEINTON;
2861 }
2862 if (cmdentry.u.cmd != EXECCMD)
2863 popredir();
Eric Andersencb57d552001-06-28 07:25:16 +00002864 } else {
2865#ifdef DEBUG
2866 trputs("normal command: "); trargs(argv);
2867#endif
2868 redirect(cmd->ncmd.redirect, 0);
2869 clearredir();
2870 for (sp = varlist.list ; sp ; sp = sp->next)
2871 setvareq(sp->text, VEXPORT|VSTACK);
2872 envp = environment();
2873 shellexec(argv, envp, path, cmdentry.u.index);
2874 }
2875 goto out;
2876
Eric Andersen2870d962001-07-02 17:27:21 +00002877parent: /* parent process gets here (if we forked) */
2878 if (mode == 0) { /* argument to fork */
Eric Andersencb57d552001-06-28 07:25:16 +00002879 INTOFF;
2880 exitstatus = waitforjob(jp);
2881 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00002882 }
2883
2884out:
2885 if (lastarg)
2886 setvar("_", lastarg, 0);
2887 popstackmark(&smark);
2888}
2889
Eric Andersen62483552001-07-10 06:09:16 +00002890/*
2891 * Evaluate a parse tree. The value is left in the global variable
2892 * exitstatus.
2893 */
2894static void
2895evaltree(n, flags)
2896 union node *n;
2897 int flags;
2898{
2899 int checkexit = 0;
2900 if (n == NULL) {
2901 TRACE(("evaltree(NULL) called\n"));
2902 goto out;
2903 }
2904 TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
2905 switch (n->type) {
2906 case NSEMI:
2907 evaltree(n->nbinary.ch1, flags & EV_TESTED);
2908 if (evalskip)
2909 goto out;
2910 evaltree(n->nbinary.ch2, flags);
2911 break;
2912 case NAND:
2913 evaltree(n->nbinary.ch1, EV_TESTED);
2914 if (evalskip || exitstatus != 0)
2915 goto out;
2916 evaltree(n->nbinary.ch2, flags);
2917 break;
2918 case NOR:
2919 evaltree(n->nbinary.ch1, EV_TESTED);
2920 if (evalskip || exitstatus == 0)
2921 goto out;
2922 evaltree(n->nbinary.ch2, flags);
2923 break;
2924 case NREDIR:
2925 expredir(n->nredir.redirect);
2926 redirect(n->nredir.redirect, REDIR_PUSH);
2927 evaltree(n->nredir.n, flags);
2928 popredir();
2929 break;
2930 case NSUBSHELL:
2931 evalsubshell(n, flags);
2932 break;
2933 case NBACKGND:
2934 evalsubshell(n, flags);
2935 break;
2936 case NIF: {
2937 evaltree(n->nif.test, EV_TESTED);
2938 if (evalskip)
2939 goto out;
2940 if (exitstatus == 0)
2941 evaltree(n->nif.ifpart, flags);
2942 else if (n->nif.elsepart)
2943 evaltree(n->nif.elsepart, flags);
2944 else
2945 exitstatus = 0;
2946 break;
2947 }
2948 case NWHILE:
2949 case NUNTIL:
2950 evalloop(n, flags);
2951 break;
2952 case NFOR:
2953 evalfor(n, flags);
2954 break;
2955 case NCASE:
2956 evalcase(n, flags);
2957 break;
2958 case NDEFUN: {
2959 struct builtincmd *bcmd;
2960 struct cmdentry entry;
2961 if (
2962 (bcmd = find_builtin(n->narg.text)) &&
2963 IS_BUILTIN_SPECIAL(bcmd)
2964 ) {
2965 out2fmt("%s is a special built-in\n", n->narg.text);
2966 exitstatus = 1;
2967 break;
2968 }
2969 entry.cmdtype = CMDFUNCTION;
2970 entry.u.func = copyfunc(n->narg.next);
2971 addcmdentry(n->narg.text, &entry);
2972 exitstatus = 0;
2973 break;
2974 }
2975 case NNOT:
2976 evaltree(n->nnot.com, EV_TESTED);
2977 exitstatus = !exitstatus;
2978 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002979
Eric Andersen62483552001-07-10 06:09:16 +00002980 case NPIPE:
2981 evalpipe(n);
2982 checkexit = 1;
2983 break;
2984 case NCMD:
2985 evalcommand(n, flags);
2986 checkexit = 1;
2987 break;
2988#ifdef DEBUG
2989 default:
2990 printf("Node type = %d\n", n->type);
2991 break;
2992#endif
2993 }
2994out:
2995 if (pendingsigs)
2996 dotrap();
2997 if (
2998 flags & EV_EXIT ||
2999 (checkexit && eflag && exitstatus && !(flags & EV_TESTED))
3000 )
3001 exitshell(exitstatus);
3002}
3003
3004/*
3005 * Kick off a subshell to evaluate a tree.
3006 */
3007
3008static void
3009evalsubshell(const union node *n, int flags)
3010{
3011 struct job *jp;
3012 int backgnd = (n->type == NBACKGND);
3013
3014 expredir(n->nredir.redirect);
3015 jp = makejob(n, 1);
3016 if (forkshell(jp, n, backgnd) == 0) {
3017 if (backgnd)
3018 flags &=~ EV_TESTED;
3019 redirect(n->nredir.redirect, 0);
3020 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
3021 }
3022 if (! backgnd) {
3023 INTOFF;
3024 exitstatus = waitforjob(jp);
3025 INTON;
3026 }
3027}
3028
3029/*
3030 * Compute the names of the files in a redirection list.
3031 */
3032
3033static void fixredir(union node *n, const char *text, int err);
3034
3035static void
3036expredir(union node *n)
3037{
3038 union node *redir;
3039
3040 for (redir = n ; redir ; redir = redir->nfile.next) {
3041 struct arglist fn;
3042 fn.lastp = &fn.list;
3043 oexitstatus = exitstatus;
3044 switch (redir->type) {
3045 case NFROMTO:
3046 case NFROM:
3047 case NTO:
3048 case NAPPEND:
3049 case NTOOV:
3050 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3051 redir->nfile.expfname = fn.list->text;
3052 break;
3053 case NFROMFD:
3054 case NTOFD:
3055 if (redir->ndup.vname) {
3056 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3057 fixredir(redir, fn.list->text, 1);
3058 }
3059 break;
3060 }
3061 }
3062}
3063
3064
3065/*
3066 * Execute a command inside back quotes. If it's a builtin command, we
3067 * want to save its output in a block obtained from malloc. Otherwise
3068 * we fork off a subprocess and get the output of the command via a pipe.
3069 * Should be called with interrupts off.
3070 */
3071
3072static void
3073evalbackcmd(union node *n, struct backcmd *result)
3074{
3075 int pip[2];
3076 struct job *jp;
3077 struct stackmark smark; /* unnecessary */
3078
3079 setstackmark(&smark);
3080 result->fd = -1;
3081 result->buf = NULL;
3082 result->nleft = 0;
3083 result->jp = NULL;
3084 if (n == NULL) {
3085 exitstatus = 0;
3086 goto out;
3087 }
3088 exitstatus = 0;
3089 if (pipe(pip) < 0)
3090 error("Pipe call failed");
3091 jp = makejob(n, 1);
3092 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3093 FORCEINTON;
3094 close(pip[0]);
3095 if (pip[1] != 1) {
3096 close(1);
3097 dup_as_newfd(pip[1], 1);
3098 close(pip[1]);
3099 }
3100 eflag = 0;
3101 evaltree(n, EV_EXIT);
3102 }
3103 close(pip[1]);
3104 result->fd = pip[0];
3105 result->jp = jp;
3106out:
3107 popstackmark(&smark);
3108 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
3109 result->fd, result->buf, result->nleft, result->jp));
3110}
3111
3112
3113/*
3114 * Execute a simple command.
3115 */
Eric Andersencb57d552001-06-28 07:25:16 +00003116
3117/*
3118 * Search for a command. This is called before we fork so that the
3119 * location of the command will be available in the parent as well as
3120 * the child. The check for "goodname" is an overly conservative
3121 * check that the name will not be subject to expansion.
3122 */
3123
3124static void
3125prehash(n)
3126 union node *n;
3127{
3128 struct cmdentry entry;
3129
3130 if (n->type == NCMD && n->ncmd.args)
3131 if (goodname(n->ncmd.args->narg.text))
3132 find_command(n->ncmd.args->narg.text, &entry, 0,
3133 pathval());
3134}
3135
3136
Eric Andersencb57d552001-06-28 07:25:16 +00003137/*
3138 * Builtin commands. Builtin commands whose functions are closely
3139 * tied to evaluation are implemented here.
3140 */
3141
3142/*
3143 * No command given, or a bltin command with no arguments. Set the
3144 * specified variables.
3145 */
3146
3147int
3148bltincmd(argc, argv)
3149 int argc;
3150 char **argv;
3151{
3152 /*
3153 * Preserve exitstatus of a previous possible redirection
3154 * as POSIX mandates
3155 */
3156 return exitstatus;
3157}
3158
3159
3160/*
3161 * Handle break and continue commands. Break, continue, and return are
3162 * all handled by setting the evalskip flag. The evaluation routines
3163 * above all check this flag, and if it is set they start skipping
3164 * commands rather than executing them. The variable skipcount is
3165 * the number of loops to break/continue, or the number of function
3166 * levels to return. (The latter is always 1.) It should probably
3167 * be an error to break out of more loops than exist, but it isn't
3168 * in the standard shell so we don't make it one here.
3169 */
3170
3171static int
3172breakcmd(argc, argv)
3173 int argc;
3174 char **argv;
3175{
3176 int n = argc > 1 ? number(argv[1]) : 1;
3177
3178 if (n > loopnest)
3179 n = loopnest;
3180 if (n > 0) {
3181 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
3182 skipcount = n;
3183 }
3184 return 0;
3185}
3186
3187
3188/*
3189 * The return command.
3190 */
3191
3192static int
3193returncmd(argc, argv)
3194 int argc;
3195 char **argv;
3196{
3197 int ret = argc > 1 ? number(argv[1]) : oexitstatus;
3198
3199 if (funcnest) {
3200 evalskip = SKIPFUNC;
3201 skipcount = 1;
3202 return ret;
3203 }
3204 else {
3205 /* Do what ksh does; skip the rest of the file */
3206 evalskip = SKIPFILE;
3207 skipcount = 1;
3208 return ret;
3209 }
3210}
3211
3212
3213#ifndef BB_TRUE_FALSE
3214static int
3215false_main(argc, argv)
3216 int argc;
3217 char **argv;
3218{
3219 return 1;
3220}
3221
3222
3223static int
3224true_main(argc, argv)
3225 int argc;
3226 char **argv;
3227{
3228 return 0;
3229}
3230#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003231
3232/*
3233 * Controls whether the shell is interactive or not.
3234 */
3235
3236static void setsignal(int signo);
3237static void chkmail(int silent);
3238
3239
3240static void
3241setinteractive(int on)
3242{
3243 static int is_interactive;
Eric Andersen1c039232001-07-07 00:05:55 +00003244 static int do_banner=0;
Eric Andersen2870d962001-07-02 17:27:21 +00003245
3246 if (on == is_interactive)
3247 return;
3248 setsignal(SIGINT);
3249 setsignal(SIGQUIT);
3250 setsignal(SIGTERM);
3251 chkmail(1);
3252 is_interactive = on;
Eric Andersen1c039232001-07-07 00:05:55 +00003253 if (do_banner==0 && is_interactive) {
3254 /* Looks like they want an interactive shell */
3255 printf( "\n\n" BB_BANNER " Built-in shell (ash)\n");
3256 printf( "Enter 'help' for a list of built-in commands.\n\n");
3257 do_banner=1;
3258 }
Eric Andersen2870d962001-07-02 17:27:21 +00003259}
3260
3261static void
3262optschanged(void)
3263{
3264 setinteractive(iflag);
3265 setjobctl(mflag);
3266}
3267
Eric Andersencb57d552001-06-28 07:25:16 +00003268
3269static int
3270execcmd(argc, argv)
3271 int argc;
3272 char **argv;
3273{
3274 if (argc > 1) {
3275 struct strlist *sp;
3276
Eric Andersen2870d962001-07-02 17:27:21 +00003277 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003278 mflag = 0;
3279 optschanged();
3280 for (sp = cmdenviron; sp ; sp = sp->next)
3281 setvareq(sp->text, VEXPORT|VSTACK);
3282 shellexec(argv + 1, environment(), pathval(), 0);
3283 }
3284 return 0;
3285}
3286
3287static void
3288eprintlist(struct strlist *sp)
3289{
3290 for (; sp; sp = sp->next) {
Eric Andersen3102ac42001-07-06 04:26:23 +00003291 out2fmt(" %s",sp->text);
Eric Andersencb57d552001-06-28 07:25:16 +00003292 }
3293}
Eric Andersencb57d552001-06-28 07:25:16 +00003294
3295/*
3296 * Exec a program. Never returns. If you change this routine, you may
3297 * have to change the find_command routine as well.
3298 */
3299
Eric Andersen2870d962001-07-02 17:27:21 +00003300static const char *pathopt; /* set by padvance */
3301
Eric Andersencb57d552001-06-28 07:25:16 +00003302static void
3303shellexec(argv, envp, path, idx)
3304 char **argv, **envp;
3305 const char *path;
3306 int idx;
3307{
3308 char *cmdname;
3309 int e;
3310
3311 if (strchr(argv[0], '/') != NULL) {
3312 tryexec(argv[0], argv, envp);
3313 e = errno;
3314 } else {
3315 e = ENOENT;
3316 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3317 if (--idx < 0 && pathopt == NULL) {
3318 tryexec(cmdname, argv, envp);
3319 if (errno != ENOENT && errno != ENOTDIR)
3320 e = errno;
3321 }
3322 stunalloc(cmdname);
3323 }
3324 }
3325
3326 /* Map to POSIX errors */
3327 switch (e) {
3328 case EACCES:
3329 exerrno = 126;
3330 break;
3331 case ENOENT:
3332 exerrno = 127;
3333 break;
3334 default:
3335 exerrno = 2;
3336 break;
3337 }
3338 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3339 /* NOTREACHED */
3340}
3341
Eric Andersen2870d962001-07-02 17:27:21 +00003342/*
3343 * Clear traps on a fork.
3344 */
3345static void
3346clear_traps(void) {
3347 char **tp;
3348
3349 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
3350 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
3351 INTOFF;
3352 ckfree(*tp);
3353 *tp = NULL;
3354 if (tp != &trap[0])
3355 setsignal(tp - trap);
3356 INTON;
3357 }
3358 }
3359}
3360
3361
3362static void
3363initshellproc(void) {
3364
3365#ifdef ASH_ALIAS
3366 /* from alias.c: */
3367 {
3368 rmaliases();
3369 }
3370#endif
3371 /* from eval.c: */
3372 {
3373 exitstatus = 0;
3374 }
3375
3376 /* from exec.c: */
3377 {
3378 deletefuncs();
3379 }
3380
3381 /* from jobs.c: */
3382 {
3383 backgndpid = -1;
3384#ifdef JOBS
3385 jobctl = 0;
3386#endif
3387 }
3388
3389 /* from options.c: */
3390 {
3391 int i;
3392
3393 for (i = 0; i < NOPTS; i++)
3394 optent_val(i) = 0;
3395 optschanged();
3396
3397 }
3398
3399 /* from redir.c: */
3400 {
3401 clearredir();
3402 }
3403
3404 /* from trap.c: */
3405 {
3406 char *sm;
3407
3408 clear_traps();
3409 for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) {
3410 if (*sm == S_IGN)
3411 *sm = S_HARD_IGN;
3412 }
3413 }
3414
3415 /* from var.c: */
3416 {
3417 shprocvar();
3418 }
3419}
3420
3421static int preadbuffer(void);
3422static void pushfile (void);
Eric Andersen2870d962001-07-02 17:27:21 +00003423
3424/*
3425 * Read a character from the script, returning PEOF on end of file.
3426 * Nul characters in the input are silently discarded.
3427 */
3428
Eric Andersen3102ac42001-07-06 04:26:23 +00003429#ifndef ASH_OPTIMIZE_FOR_SIZE
Eric Andersen2870d962001-07-02 17:27:21 +00003430#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
3431static int
3432pgetc(void)
3433{
3434 return pgetc_macro();
3435}
3436#else
3437static int
3438pgetc_macro(void)
3439{
3440 return --parsenleft >= 0? *parsenextc++ : preadbuffer();
3441}
3442
3443static inline int
3444pgetc(void)
3445{
3446 return pgetc_macro();
3447}
3448#endif
3449
3450
3451/*
3452 * Undo the last call to pgetc. Only one character may be pushed back.
3453 * PEOF may be pushed back.
3454 */
3455
3456static void
3457pungetc() {
3458 parsenleft++;
3459 parsenextc--;
3460}
3461
3462
3463static void
3464popfile(void) {
3465 struct parsefile *pf = parsefile;
3466
3467 INTOFF;
3468 if (pf->fd >= 0)
3469 close(pf->fd);
3470 if (pf->buf)
3471 ckfree(pf->buf);
3472 while (pf->strpush)
3473 popstring();
3474 parsefile = pf->prev;
3475 ckfree(pf);
3476 parsenleft = parsefile->nleft;
3477 parselleft = parsefile->lleft;
3478 parsenextc = parsefile->nextc;
3479 plinno = parsefile->linno;
3480 INTON;
3481}
3482
3483
3484/*
3485 * Return to top level.
3486 */
3487
3488static void
3489popallfiles(void) {
3490 while (parsefile != &basepf)
3491 popfile();
3492}
3493
3494/*
3495 * Close the file(s) that the shell is reading commands from. Called
3496 * after a fork is done.
3497 */
3498
3499static void
3500closescript() {
3501 popallfiles();
3502 if (parsefile->fd > 0) {
3503 close(parsefile->fd);
3504 parsefile->fd = 0;
3505 }
3506}
3507
3508
3509/*
3510 * Like setinputfile, but takes an open file descriptor. Call this with
3511 * interrupts off.
3512 */
3513
3514static void
3515setinputfd(fd, push)
3516 int fd, push;
3517{
3518 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
3519 if (push) {
3520 pushfile();
3521 parsefile->buf = 0;
3522 } else {
3523 closescript();
3524 while (parsefile->strpush)
3525 popstring();
3526 }
3527 parsefile->fd = fd;
3528 if (parsefile->buf == NULL)
3529 parsefile->buf = ckmalloc(BUFSIZ);
3530 parselleft = parsenleft = 0;
3531 plinno = 1;
3532}
3533
3534
3535/*
3536 * Set the input to take input from a file. If push is set, push the
3537 * old input onto the stack first.
3538 */
3539
3540static void
3541setinputfile(const char *fname, int push)
3542{
3543 int fd;
3544 int myfileno2;
3545
3546 INTOFF;
3547 if ((fd = open(fname, O_RDONLY)) < 0)
3548 error("Can't open %s", fname);
3549 if (fd < 10) {
3550 myfileno2 = dup_as_newfd(fd, 10);
3551 close(fd);
3552 if (myfileno2 < 0)
3553 error("Out of file descriptors");
3554 fd = myfileno2;
3555 }
3556 setinputfd(fd, push);
3557 INTON;
3558}
3559
Eric Andersencb57d552001-06-28 07:25:16 +00003560
3561static void
Eric Andersen62483552001-07-10 06:09:16 +00003562tryexec(char *cmd, char **argv, char **envp)
3563{
Eric Andersencb57d552001-06-28 07:25:16 +00003564 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003565
Eric Andersen3102ac42001-07-06 04:26:23 +00003566#ifdef BB_FEATURE_SH_STANDALONE_SHELL
3567 char *name = cmd;
3568 char** argv_l=argv;
3569 int argc_l;
3570#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
3571 name = get_last_path_component(name);
3572#endif
3573 argv_l=envp;
3574 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
3575 putenv(*argv_l);
3576 argv_l=argv;
Eric Andersen62483552001-07-10 06:09:16 +00003577 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
Eric Andersen3102ac42001-07-06 04:26:23 +00003578 optind = 1;
3579 run_applet_by_name(name, argc_l, argv);
3580#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003581 execve(cmd, argv, envp);
Eric Andersencb57d552001-06-28 07:25:16 +00003582 e = errno;
3583 if (e == ENOEXEC) {
3584 INTOFF;
3585 initshellproc();
3586 setinputfile(cmd, 0);
3587 commandname = arg0 = savestr(argv[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00003588 setparam(argv + 1);
3589 exraise(EXSHELLPROC);
3590 }
3591 errno = e;
3592}
3593
Eric Andersen2870d962001-07-02 17:27:21 +00003594static char *commandtext (const union node *);
Eric Andersencb57d552001-06-28 07:25:16 +00003595
3596/*
3597 * Do a path search. The variable path (passed by reference) should be
3598 * set to the start of the path before the first call; padvance will update
3599 * this value as it proceeds. Successive calls to padvance will return
3600 * the possible path expansions in sequence. If an option (indicated by
3601 * a percent sign) appears in the path entry then the global variable
3602 * pathopt will be set to point to it; otherwise pathopt will be set to
3603 * NULL.
3604 */
3605
3606static const char *pathopt;
3607
Eric Andersen2870d962001-07-02 17:27:21 +00003608static void growstackblock(void);
3609
3610
Eric Andersencb57d552001-06-28 07:25:16 +00003611static char *
Eric Andersen2870d962001-07-02 17:27:21 +00003612padvance(const char **path, const char *name)
3613{
Eric Andersencb57d552001-06-28 07:25:16 +00003614 const char *p;
3615 char *q;
3616 const char *start;
3617 int len;
3618
3619 if (*path == NULL)
3620 return NULL;
3621 start = *path;
3622 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
Eric Andersen2870d962001-07-02 17:27:21 +00003623 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003624 while (stackblocksize() < len)
3625 growstackblock();
3626 q = stackblock();
3627 if (p != start) {
3628 memcpy(q, start, p - start);
3629 q += p - start;
3630 *q++ = '/';
3631 }
3632 strcpy(q, name);
3633 pathopt = NULL;
3634 if (*p == '%') {
3635 pathopt = ++p;
3636 while (*p && *p != ':') p++;
3637 }
3638 if (*p == ':')
3639 *path = p + 1;
3640 else
3641 *path = NULL;
3642 return stalloc(len);
3643}
3644
Eric Andersen62483552001-07-10 06:09:16 +00003645/*
3646 * Wrapper around strcmp for qsort/bsearch/...
3647 */
3648static int
3649pstrcmp(const void *a, const void *b)
3650{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003651 return strcmp((const char *) a, (*(const char *const *) b) + 1);
Eric Andersen62483552001-07-10 06:09:16 +00003652}
3653
3654/*
3655 * Find a keyword is in a sorted array.
3656 */
3657
3658static const char *const *
3659findkwd(const char *s)
3660{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003661 return bsearch(s, tokname_array + KWDOFFSET,
3662 (sizeof(tokname_array)/sizeof(const char *)) - KWDOFFSET,
3663 sizeof(const char *), pstrcmp);
Eric Andersen62483552001-07-10 06:09:16 +00003664}
Eric Andersencb57d552001-06-28 07:25:16 +00003665
3666
3667/*** Command hashing code ***/
3668
3669
3670static int
3671hashcmd(argc, argv)
3672 int argc;
3673 char **argv;
3674{
3675 struct tblentry **pp;
3676 struct tblentry *cmdp;
3677 int c;
3678 int verbose;
3679 struct cmdentry entry;
3680 char *name;
Eric Andersen62483552001-07-10 06:09:16 +00003681#ifdef ASH_ALIAS
3682 const struct alias *ap;
3683#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003684
3685 verbose = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003686 while ((c = nextopt("rvV")) != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00003687 if (c == 'r') {
3688 clearcmdentry(0);
3689 return 0;
Eric Andersen62483552001-07-10 06:09:16 +00003690 } else if (c == 'v' || c == 'V') {
3691 verbose = c;
Eric Andersencb57d552001-06-28 07:25:16 +00003692 }
3693 }
3694 if (*argptr == NULL) {
3695 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3696 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3697 if (cmdp->cmdtype != CMDBUILTIN) {
3698 printentry(cmdp, verbose);
3699 }
3700 }
3701 }
3702 return 0;
3703 }
3704 c = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003705 while ((name = *argptr++) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00003706 if ((cmdp = cmdlookup(name, 0)) != NULL
3707 && (cmdp->cmdtype == CMDNORMAL
3708 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3709 delete_cmd_entry();
Eric Andersen62483552001-07-10 06:09:16 +00003710#ifdef ASH_ALIAS
3711 /* Then look at the aliases */
3712 if ((ap = lookupalias(name, 0)) != NULL) {
3713 if (verbose=='v')
3714 printf("%s is an alias for %s\n", name, ap->val);
3715 else
3716 printalias(ap);
3717 continue;
3718 }
3719#endif
3720 /* First look at the keywords */
3721 if (findkwd(name)!=0) {
3722 if (verbose=='v')
3723 printf("%s is a shell keyword\n", name);
3724 else
3725 printf(snlfmt, name);
3726 continue;
3727 }
3728
Eric Andersencb57d552001-06-28 07:25:16 +00003729 find_command(name, &entry, DO_ERR, pathval());
3730 if (entry.cmdtype == CMDUNKNOWN) c = 1;
3731 else if (verbose) {
3732 cmdp = cmdlookup(name, 0);
Eric Andersen62483552001-07-10 06:09:16 +00003733 if (cmdp) printentry(cmdp, verbose=='v');
Eric Andersencb57d552001-06-28 07:25:16 +00003734 flushall();
3735 }
Eric Andersencb57d552001-06-28 07:25:16 +00003736 }
3737 return c;
3738}
3739
Eric Andersencb57d552001-06-28 07:25:16 +00003740static void
3741printentry(cmdp, verbose)
3742 struct tblentry *cmdp;
3743 int verbose;
3744 {
3745 int idx;
3746 const char *path;
3747 char *name;
3748
Eric Andersen62483552001-07-10 06:09:16 +00003749 printf("%s%s", cmdp->cmdname, (verbose ? " is " : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00003750 if (cmdp->cmdtype == CMDNORMAL) {
3751 idx = cmdp->param.index;
3752 path = pathval();
3753 do {
3754 name = padvance(&path, cmdp->cmdname);
3755 stunalloc(name);
3756 } while (--idx >= 0);
Eric Andersen62483552001-07-10 06:09:16 +00003757 if(verbose)
3758 out1str(name);
Eric Andersencb57d552001-06-28 07:25:16 +00003759 } else if (cmdp->cmdtype == CMDBUILTIN) {
Eric Andersen62483552001-07-10 06:09:16 +00003760 if(verbose)
3761 out1str("a shell builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00003762 } else if (cmdp->cmdtype == CMDFUNCTION) {
Eric Andersencb57d552001-06-28 07:25:16 +00003763 if (verbose) {
3764 INTOFF;
Eric Andersen62483552001-07-10 06:09:16 +00003765 out1str("a function\n");
Eric Andersencb57d552001-06-28 07:25:16 +00003766 name = commandtext(cmdp->param.func);
Eric Andersen62483552001-07-10 06:09:16 +00003767 printf("%s() {\n %s\n}", cmdp->cmdname, name);
Eric Andersencb57d552001-06-28 07:25:16 +00003768 ckfree(name);
3769 INTON;
3770 }
3771#ifdef DEBUG
3772 } else {
3773 error("internal error: cmdtype %d", cmdp->cmdtype);
3774#endif
3775 }
Eric Andersen62483552001-07-10 06:09:16 +00003776 printf(snlfmt, cmdp->rehash ? "*" : nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +00003777}
3778
3779
3780
Eric Andersen1c039232001-07-07 00:05:55 +00003781/*** List the available builtins ***/
3782
3783
3784static int helpcmd(int argc, char** argv)
3785{
3786 int col, i;
Eric Andersen1c039232001-07-07 00:05:55 +00003787
Eric Andersen62483552001-07-10 06:09:16 +00003788 printf("\nBuilt-in commands:\n-------------------\n");
3789 for (col=0, i=0; i < NUMBUILTINS; i++) {
3790 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3791 builtincmds[i].name+1);
Eric Andersen1c039232001-07-07 00:05:55 +00003792 if (col > 60) {
3793 printf("\n");
3794 col = 0;
3795 }
3796 }
3797#ifdef BB_FEATURE_SH_STANDALONE_SHELL
3798 {
Eric Andersen1c039232001-07-07 00:05:55 +00003799 extern const struct BB_applet applets[];
3800 extern const size_t NUM_APPLETS;
3801
Eric Andersen62483552001-07-10 06:09:16 +00003802 for (i=0; i < NUM_APPLETS; i++) {
3803
3804 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3805 applets[i].name);
Eric Andersen1c039232001-07-07 00:05:55 +00003806 if (col > 60) {
3807 printf("\n");
3808 col = 0;
3809 }
3810 }
3811 }
3812#endif
3813 printf("\n\n");
3814 return EXIT_SUCCESS;
3815}
3816
Eric Andersencb57d552001-06-28 07:25:16 +00003817/*
3818 * Resolve a command name. If you change this routine, you may have to
3819 * change the shellexec routine as well.
3820 */
3821
Eric Andersen2870d962001-07-02 17:27:21 +00003822static int prefix (const char *, const char *);
3823
Eric Andersencb57d552001-06-28 07:25:16 +00003824static void
Eric Andersen2870d962001-07-02 17:27:21 +00003825find_command(const char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003826{
3827 struct tblentry *cmdp;
3828 int idx;
3829 int prev;
3830 char *fullname;
3831 struct stat statb;
3832 int e;
3833 int bltin;
3834 int firstchange;
3835 int updatetbl;
Eric Andersen62483552001-07-10 06:09:16 +00003836 int regular;
Eric Andersencb57d552001-06-28 07:25:16 +00003837 struct builtincmd *bcmd;
3838
3839 /* If name contains a slash, don't use the hash table */
3840 if (strchr(name, '/') != NULL) {
3841 if (act & DO_ABS) {
3842 while (stat(name, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003843 if (errno != ENOENT && errno != ENOTDIR)
3844 e = errno;
3845 entry->cmdtype = CMDUNKNOWN;
3846 entry->u.index = -1;
3847 return;
3848 }
3849 entry->cmdtype = CMDNORMAL;
3850 entry->u.index = -1;
3851 return;
3852 }
3853 entry->cmdtype = CMDNORMAL;
3854 entry->u.index = 0;
3855 return;
3856 }
3857
3858 updatetbl = 1;
3859 if (act & DO_BRUTE) {
3860 firstchange = path_change(path, &bltin);
3861 } else {
3862 bltin = builtinloc;
3863 firstchange = 9999;
3864 }
3865
3866 /* If name is in the table, and not invalidated by cd, we're done */
3867 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
3868 if (cmdp->cmdtype == CMDFUNCTION) {
3869 if (act & DO_NOFUN) {
3870 updatetbl = 0;
3871 } else {
3872 goto success;
3873 }
3874 } else if (act & DO_BRUTE) {
3875 if ((cmdp->cmdtype == CMDNORMAL &&
3876 cmdp->param.index >= firstchange) ||
3877 (cmdp->cmdtype == CMDBUILTIN &&
3878 ((builtinloc < 0 && bltin >= 0) ?
3879 bltin : builtinloc) >= firstchange)) {
3880 /* need to recompute the entry */
3881 } else {
3882 goto success;
3883 }
3884 } else {
3885 goto success;
3886 }
3887 }
3888
3889 bcmd = find_builtin(name);
Eric Andersen2870d962001-07-02 17:27:21 +00003890 regular = bcmd && IS_BUILTIN_REGULAR(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00003891
3892 if (regular) {
3893 if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) {
Eric Andersen2870d962001-07-02 17:27:21 +00003894 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003895 }
3896 } else if (act & DO_BRUTE) {
3897 if (firstchange == 0) {
3898 updatetbl = 0;
3899 }
3900 }
3901
3902 /* If %builtin not in path, check for builtin next */
3903 if (regular || (bltin < 0 && bcmd)) {
3904builtin:
3905 if (!updatetbl) {
3906 entry->cmdtype = CMDBUILTIN;
3907 entry->u.cmd = bcmd;
3908 return;
3909 }
3910 INTOFF;
3911 cmdp = cmdlookup(name, 1);
3912 cmdp->cmdtype = CMDBUILTIN;
3913 cmdp->param.cmd = bcmd;
3914 INTON;
3915 goto success;
3916 }
3917
3918 /* We have to search path. */
Eric Andersen2870d962001-07-02 17:27:21 +00003919 prev = -1; /* where to start */
3920 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00003921 if (cmdp->cmdtype == CMDBUILTIN)
3922 prev = builtinloc;
3923 else
3924 prev = cmdp->param.index;
3925 }
3926
3927 e = ENOENT;
3928 idx = -1;
3929loop:
3930 while ((fullname = padvance(&path, name)) != NULL) {
3931 stunalloc(fullname);
3932 idx++;
3933 if (idx >= firstchange) {
3934 updatetbl = 0;
3935 }
3936 if (pathopt) {
3937 if (prefix("builtin", pathopt)) {
3938 if ((bcmd = find_builtin(name))) {
3939 goto builtin;
3940 }
3941 continue;
3942 } else if (!(act & DO_NOFUN) &&
3943 prefix("func", pathopt)) {
3944 /* handled below */
3945 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00003946 continue; /* ignore unimplemented options */
Eric Andersencb57d552001-06-28 07:25:16 +00003947 }
3948 }
3949 /* if rehash, don't redo absolute path names */
3950 if (fullname[0] == '/' && idx <= prev &&
3951 idx < firstchange) {
3952 if (idx < prev)
3953 continue;
3954 TRACE(("searchexec \"%s\": no change\n", name));
3955 goto success;
3956 }
3957 while (stat(fullname, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003958 if (errno != ENOENT && errno != ENOTDIR)
3959 e = errno;
3960 goto loop;
3961 }
Eric Andersen2870d962001-07-02 17:27:21 +00003962 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00003963 if (!S_ISREG(statb.st_mode))
3964 continue;
Eric Andersen2870d962001-07-02 17:27:21 +00003965 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00003966 stalloc(strlen(fullname) + 1);
3967 readcmdfile(fullname);
3968 if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
3969 error("%s not defined in %s", name, fullname);
3970 stunalloc(fullname);
3971 goto success;
3972 }
Eric Andersencb57d552001-06-28 07:25:16 +00003973 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
3974 /* If we aren't called with DO_BRUTE and cmdp is set, it must
3975 be a function and we're being called with DO_NOFUN */
3976 if (!updatetbl) {
3977 entry->cmdtype = CMDNORMAL;
3978 entry->u.index = idx;
3979 return;
3980 }
3981 INTOFF;
3982 cmdp = cmdlookup(name, 1);
3983 cmdp->cmdtype = CMDNORMAL;
3984 cmdp->param.index = idx;
3985 INTON;
3986 goto success;
3987 }
3988
3989 /* We failed. If there was an entry for this command, delete it */
3990 if (cmdp && updatetbl)
3991 delete_cmd_entry();
3992 if (act & DO_ERR)
Eric Andersen3102ac42001-07-06 04:26:23 +00003993 out2fmt("%s: %s\n", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00003994 entry->cmdtype = CMDUNKNOWN;
3995 return;
3996
3997success:
3998 cmdp->rehash = 0;
3999 entry->cmdtype = cmdp->cmdtype;
4000 entry->u = cmdp->param;
4001}
4002
4003
4004
4005/*
4006 * Search the table of builtin commands.
4007 */
4008
Eric Andersen2870d962001-07-02 17:27:21 +00004009static int
4010bstrcmp(const void *name, const void *b)
4011{
4012 return strcmp((const char *)name, (*(const char *const *) b)+1);
4013}
4014
4015static struct builtincmd *
4016find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00004017{
4018 struct builtincmd *bp;
4019
Eric Andersen2870d962001-07-02 17:27:21 +00004020 bp = bsearch(name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd),
4021 bstrcmp
Eric Andersencb57d552001-06-28 07:25:16 +00004022 );
4023 return bp;
4024}
4025
4026
4027/*
4028 * Called when a cd is done. Marks all commands so the next time they
4029 * are executed they will be rehashed.
4030 */
4031
4032static void
Eric Andersen2870d962001-07-02 17:27:21 +00004033hashcd(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00004034 struct tblentry **pp;
4035 struct tblentry *cmdp;
4036
4037 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4038 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4039 if (cmdp->cmdtype == CMDNORMAL
4040 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
4041 cmdp->rehash = 1;
4042 }
4043 }
4044}
4045
4046
4047
4048/*
4049 * Called before PATH is changed. The argument is the new value of PATH;
4050 * pathval() still returns the old value at this point. Called with
4051 * interrupts off.
4052 */
4053
4054static void
Eric Andersen2870d962001-07-02 17:27:21 +00004055changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00004056{
4057 int firstchange;
4058 int bltin;
4059
4060 firstchange = path_change(newval, &bltin);
4061 if (builtinloc < 0 && bltin >= 0)
Eric Andersen2870d962001-07-02 17:27:21 +00004062 builtinloc = bltin; /* zap builtins */
Eric Andersencb57d552001-06-28 07:25:16 +00004063 clearcmdentry(firstchange);
4064 builtinloc = bltin;
4065}
4066
4067
4068/*
4069 * Clear out command entries. The argument specifies the first entry in
4070 * PATH which has changed.
4071 */
4072
4073static void
4074clearcmdentry(firstchange)
4075 int firstchange;
4076{
4077 struct tblentry **tblp;
4078 struct tblentry **pp;
4079 struct tblentry *cmdp;
4080
4081 INTOFF;
4082 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4083 pp = tblp;
4084 while ((cmdp = *pp) != NULL) {
4085 if ((cmdp->cmdtype == CMDNORMAL &&
4086 cmdp->param.index >= firstchange)
4087 || (cmdp->cmdtype == CMDBUILTIN &&
4088 builtinloc >= firstchange)) {
4089 *pp = cmdp->next;
4090 ckfree(cmdp);
4091 } else {
4092 pp = &cmdp->next;
4093 }
4094 }
4095 }
4096 INTON;
4097}
4098
4099
4100/*
4101 * Delete all functions.
4102 */
4103
Eric Andersencb57d552001-06-28 07:25:16 +00004104static void
Eric Andersen2870d962001-07-02 17:27:21 +00004105deletefuncs(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00004106 struct tblentry **tblp;
4107 struct tblentry **pp;
4108 struct tblentry *cmdp;
4109
4110 INTOFF;
4111 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4112 pp = tblp;
4113 while ((cmdp = *pp) != NULL) {
4114 if (cmdp->cmdtype == CMDFUNCTION) {
4115 *pp = cmdp->next;
4116 freefunc(cmdp->param.func);
4117 ckfree(cmdp);
4118 } else {
4119 pp = &cmdp->next;
4120 }
4121 }
4122 }
4123 INTON;
4124}
4125
4126
4127
4128/*
4129 * Locate a command in the command hash table. If "add" is nonzero,
4130 * add the command to the table if it is not already present. The
4131 * variable "lastcmdentry" is set to point to the address of the link
4132 * pointing to the entry, so that delete_cmd_entry can delete the
4133 * entry.
4134 */
4135
Eric Andersen2870d962001-07-02 17:27:21 +00004136static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00004137
4138static struct tblentry *
Eric Andersen2870d962001-07-02 17:27:21 +00004139cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00004140{
4141 int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00004142 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00004143 struct tblentry *cmdp;
4144 struct tblentry **pp;
4145
4146 p = name;
4147 hashval = *p << 4;
4148 while (*p)
4149 hashval += *p++;
4150 hashval &= 0x7FFF;
4151 pp = &cmdtable[hashval % CMDTABLESIZE];
4152 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4153 if (equal(cmdp->cmdname, name))
4154 break;
4155 pp = &cmdp->next;
4156 }
4157 if (add && cmdp == NULL) {
4158 INTOFF;
4159 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4160 + strlen(name) + 1);
4161 cmdp->next = NULL;
4162 cmdp->cmdtype = CMDUNKNOWN;
4163 cmdp->rehash = 0;
4164 strcpy(cmdp->cmdname, name);
4165 INTON;
4166 }
4167 lastcmdentry = pp;
4168 return cmdp;
4169}
4170
4171/*
4172 * Delete the command entry returned on the last lookup.
4173 */
4174
4175static void
4176delete_cmd_entry() {
4177 struct tblentry *cmdp;
4178
4179 INTOFF;
4180 cmdp = *lastcmdentry;
4181 *lastcmdentry = cmdp->next;
4182 ckfree(cmdp);
4183 INTON;
4184}
4185
4186
4187
Eric Andersencb57d552001-06-28 07:25:16 +00004188
4189
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004190static const unsigned char nodesize[26] = {
Eric Andersen62483552001-07-10 06:09:16 +00004191 ALIGN(sizeof (struct nbinary)),
4192 ALIGN(sizeof (struct ncmd)),
4193 ALIGN(sizeof (struct npipe)),
4194 ALIGN(sizeof (struct nredir)),
4195 ALIGN(sizeof (struct nredir)),
4196 ALIGN(sizeof (struct nredir)),
4197 ALIGN(sizeof (struct nbinary)),
4198 ALIGN(sizeof (struct nbinary)),
4199 ALIGN(sizeof (struct nif)),
4200 ALIGN(sizeof (struct nbinary)),
4201 ALIGN(sizeof (struct nbinary)),
4202 ALIGN(sizeof (struct nfor)),
4203 ALIGN(sizeof (struct ncase)),
4204 ALIGN(sizeof (struct nclist)),
4205 ALIGN(sizeof (struct narg)),
4206 ALIGN(sizeof (struct narg)),
4207 ALIGN(sizeof (struct nfile)),
4208 ALIGN(sizeof (struct nfile)),
4209 ALIGN(sizeof (struct nfile)),
4210 ALIGN(sizeof (struct nfile)),
4211 ALIGN(sizeof (struct nfile)),
4212 ALIGN(sizeof (struct ndup)),
4213 ALIGN(sizeof (struct ndup)),
4214 ALIGN(sizeof (struct nhere)),
4215 ALIGN(sizeof (struct nhere)),
4216 ALIGN(sizeof (struct nnot)),
4217};
Eric Andersencb57d552001-06-28 07:25:16 +00004218
Eric Andersencb57d552001-06-28 07:25:16 +00004219
4220
4221/*
4222 * Delete a function if it exists.
4223 */
4224
4225static void
Eric Andersen2870d962001-07-02 17:27:21 +00004226unsetfunc(char *name)
4227{
Eric Andersencb57d552001-06-28 07:25:16 +00004228 struct tblentry *cmdp;
4229
4230 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
4231 freefunc(cmdp->param.func);
4232 delete_cmd_entry();
4233 }
4234}
4235
Eric Andersen2870d962001-07-02 17:27:21 +00004236
4237/*
Eric Andersencb57d552001-06-28 07:25:16 +00004238 * Locate and print what a word is...
4239 */
4240
4241static int
Eric Andersen62483552001-07-10 06:09:16 +00004242typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004243{
4244 int i;
4245 int err = 0;
Eric Andersen62483552001-07-10 06:09:16 +00004246 char *argv_a[2];
4247
4248 argv_a[1] = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004249
4250 for (i = 1; i < argc; i++) {
Eric Andersen62483552001-07-10 06:09:16 +00004251 argv_a[0] = argv[i];
4252 argptr = argv_a;
4253 optptr = "v";
4254 err |= hashcmd(argc, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00004255 }
4256 return err;
4257}
4258
Eric Andersen2870d962001-07-02 17:27:21 +00004259#ifdef ASH_CMDCMD
Eric Andersencb57d552001-06-28 07:25:16 +00004260static int
4261commandcmd(argc, argv)
4262 int argc;
4263 char **argv;
4264{
4265 int c;
4266 int default_path = 0;
4267 int verify_only = 0;
4268 int verbose_verify_only = 0;
4269
4270 while ((c = nextopt("pvV")) != '\0')
4271 switch (c) {
4272 case 'p':
4273 default_path = 1;
4274 break;
4275 case 'v':
4276 verify_only = 1;
4277 break;
4278 case 'V':
4279 verbose_verify_only = 1;
4280 break;
Eric Andersencb57d552001-06-28 07:25:16 +00004281 }
4282
4283 if (default_path + verify_only + verbose_verify_only > 1 ||
4284 !*argptr) {
Eric Andersen62483552001-07-10 06:09:16 +00004285 out2str(
4286 "command [-p] command [arg ...]\n"
4287 "command {-v|-V} command\n");
Eric Andersencb57d552001-06-28 07:25:16 +00004288 return EX_USAGE;
4289 }
4290
Eric Andersencb57d552001-06-28 07:25:16 +00004291 if (verify_only || verbose_verify_only) {
Eric Andersen62483552001-07-10 06:09:16 +00004292 char *argv_a[2];
4293
4294 argv_a[1] = 0;
4295 argv_a[0] = *argptr;
4296 argptr = argv_a;
4297 optptr = verbose_verify_only ? "v" : "V"; /* reverse special */
4298 return hashcmd(argc, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00004299 }
Eric Andersencb57d552001-06-28 07:25:16 +00004300
4301 return 0;
4302}
Eric Andersen2870d962001-07-02 17:27:21 +00004303#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004304
4305static int
4306path_change(newval, bltin)
4307 const char *newval;
4308 int *bltin;
4309{
4310 const char *old, *new;
4311 int idx;
4312 int firstchange;
4313
4314 old = pathval();
4315 new = newval;
Eric Andersen2870d962001-07-02 17:27:21 +00004316 firstchange = 9999; /* assume no change */
Eric Andersencb57d552001-06-28 07:25:16 +00004317 idx = 0;
4318 *bltin = -1;
4319 for (;;) {
4320 if (*old != *new) {
4321 firstchange = idx;
4322 if ((*old == '\0' && *new == ':')
4323 || (*old == ':' && *new == '\0'))
4324 firstchange++;
Eric Andersen2870d962001-07-02 17:27:21 +00004325 old = new; /* ignore subsequent differences */
Eric Andersencb57d552001-06-28 07:25:16 +00004326 }
4327 if (*new == '\0')
4328 break;
4329 if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1))
4330 *bltin = idx;
4331 if (*new == ':') {
4332 idx++;
4333 }
4334 new++, old++;
4335 }
4336 if (builtinloc >= 0 && *bltin < 0)
4337 firstchange = 0;
4338 return firstchange;
4339}
Eric Andersencb57d552001-06-28 07:25:16 +00004340/*
4341 * Routines to expand arguments to commands. We have to deal with
4342 * backquotes, shell variables, and file metacharacters.
4343 */
4344/*
4345 * _rmescape() flags
4346 */
Eric Andersen2870d962001-07-02 17:27:21 +00004347#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4348#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Eric Andersencb57d552001-06-28 07:25:16 +00004349
4350/*
4351 * Structure specifying which parts of the string should be searched
4352 * for IFS characters.
4353 */
4354
4355struct ifsregion {
Eric Andersen2870d962001-07-02 17:27:21 +00004356 struct ifsregion *next; /* next region in list */
4357 int begoff; /* offset of start of region */
4358 int endoff; /* offset of end of region */
4359 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004360};
4361
4362
Eric Andersen2870d962001-07-02 17:27:21 +00004363static char *expdest; /* output of current string */
4364static struct nodelist *argbackq; /* list of back quote expressions */
4365static struct ifsregion ifsfirst; /* first struct in list of ifs regions */
4366static struct ifsregion *ifslastp; /* last struct in list */
4367static struct arglist exparg; /* holds expanded arg list */
Eric Andersencb57d552001-06-28 07:25:16 +00004368
Eric Andersen2870d962001-07-02 17:27:21 +00004369static void argstr (char *, int);
4370static char *exptilde (char *, int);
4371static void expbackq (union node *, int, int);
4372static int subevalvar (char *, char *, int, int, int, int, int);
Eric Andersen2870d962001-07-02 17:27:21 +00004373static int varisset (char *, int);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004374static void strtodest (const char *, int, int);
Eric Andersen2870d962001-07-02 17:27:21 +00004375static void varvalue (char *, int, int);
4376static void recordregion (int, int, int);
4377static void removerecordregions (int);
4378static void ifsbreakup (char *, struct arglist *);
4379static void ifsfree (void);
4380static void expandmeta (struct strlist *, int);
Eric Andersen62483552001-07-10 06:09:16 +00004381#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00004382#define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB)
4383#if !defined(GLOB_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00004384static void addglob (const glob_t *);
Eric Andersencb57d552001-06-28 07:25:16 +00004385#endif
4386#endif
Eric Andersen62483552001-07-10 06:09:16 +00004387#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersen2870d962001-07-02 17:27:21 +00004388static void expmeta (char *, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004389#endif
Eric Andersen62483552001-07-10 06:09:16 +00004390#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersen2870d962001-07-02 17:27:21 +00004391static struct strlist *expsort (struct strlist *);
4392static struct strlist *msort (struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004393#endif
Eric Andersen2870d962001-07-02 17:27:21 +00004394static int patmatch (char *, char *, int);
Eric Andersen62483552001-07-10 06:09:16 +00004395#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00004396static int patmatch2 (char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004397#else
Eric Andersen2870d962001-07-02 17:27:21 +00004398static int pmatch (char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004399#define patmatch2 patmatch
4400#endif
Eric Andersen2870d962001-07-02 17:27:21 +00004401static char *cvtnum (int, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004402
4403/*
4404 * Expand shell variables and backquotes inside a here document.
4405 */
4406
Eric Andersen2870d962001-07-02 17:27:21 +00004407/* arg: the document, fd: where to write the expanded version */
Eric Andersen62483552001-07-10 06:09:16 +00004408static inline void
Eric Andersen2870d962001-07-02 17:27:21 +00004409expandhere(union node *arg, int fd)
4410{
Eric Andersencb57d552001-06-28 07:25:16 +00004411 herefd = fd;
4412 expandarg(arg, (struct arglist *)NULL, 0);
4413 xwrite(fd, stackblock(), expdest - stackblock());
4414}
4415
4416
4417/*
4418 * Perform variable substitution and command substitution on an argument,
4419 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4420 * perform splitting and file name expansion. When arglist is NULL, perform
4421 * here document expansion.
4422 */
4423
4424static void
4425expandarg(arg, arglist, flag)
4426 union node *arg;
4427 struct arglist *arglist;
4428 int flag;
4429{
4430 struct strlist *sp;
4431 char *p;
4432
4433 argbackq = arg->narg.backquote;
4434 STARTSTACKSTR(expdest);
4435 ifsfirst.next = NULL;
4436 ifslastp = NULL;
4437 argstr(arg->narg.text, flag);
4438 if (arglist == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00004439 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004440 }
4441 STPUTC('\0', expdest);
4442 p = grabstackstr(expdest);
4443 exparg.lastp = &exparg.list;
4444 /*
4445 * TODO - EXP_REDIR
4446 */
4447 if (flag & EXP_FULL) {
4448 ifsbreakup(p, &exparg);
4449 *exparg.lastp = NULL;
4450 exparg.lastp = &exparg.list;
4451 expandmeta(exparg.list, flag);
4452 } else {
4453 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4454 rmescapes(p);
4455 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4456 sp->text = p;
4457 *exparg.lastp = sp;
4458 exparg.lastp = &sp->next;
4459 }
4460 ifsfree();
4461 *exparg.lastp = NULL;
4462 if (exparg.list) {
4463 *arglist->lastp = exparg.list;
4464 arglist->lastp = exparg.lastp;
4465 }
4466}
4467
4468
Eric Andersen62483552001-07-10 06:09:16 +00004469/*
4470 * Expand a variable, and return a pointer to the next character in the
4471 * input string.
4472 */
4473
4474static inline char *
4475evalvar(p, flag)
4476 char *p;
4477 int flag;
4478{
4479 int subtype;
4480 int varflags;
4481 char *var;
4482 const char *val;
4483 int patloc;
4484 int c;
4485 int set;
4486 int special;
4487 int startloc;
4488 int varlen;
4489 int easy;
4490 int quotes = flag & (EXP_FULL | EXP_CASE);
4491
4492 varflags = *p++;
4493 subtype = varflags & VSTYPE;
4494 var = p;
4495 special = 0;
4496 if (! is_name(*p))
4497 special = 1;
4498 p = strchr(p, '=') + 1;
4499again: /* jump here after setting a variable with ${var=text} */
4500 if (special) {
4501 set = varisset(var, varflags & VSNUL);
4502 val = NULL;
4503 } else {
4504 val = lookupvar(var);
4505 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
4506 val = NULL;
4507 set = 0;
4508 } else
4509 set = 1;
4510 }
4511 varlen = 0;
4512 startloc = expdest - stackblock();
4513 if (set && subtype != VSPLUS) {
4514 /* insert the value of the variable */
4515 if (special) {
4516 varvalue(var, varflags & VSQUOTE, flag);
4517 if (subtype == VSLENGTH) {
4518 varlen = expdest - stackblock() - startloc;
4519 STADJUST(-varlen, expdest);
4520 }
4521 } else {
4522 if (subtype == VSLENGTH) {
4523 varlen = strlen(val);
4524 } else {
4525 strtodest(
4526 val,
4527 varflags & VSQUOTE ?
4528 DQSYNTAX : BASESYNTAX,
4529 quotes
4530 );
4531 }
4532 }
4533 }
4534
4535 if (subtype == VSPLUS)
4536 set = ! set;
4537
4538 easy = ((varflags & VSQUOTE) == 0 ||
4539 (*var == '@' && shellparam.nparam != 1));
4540
4541
4542 switch (subtype) {
4543 case VSLENGTH:
4544 expdest = cvtnum(varlen, expdest);
4545 goto record;
4546
4547 case VSNORMAL:
4548 if (!easy)
4549 break;
4550record:
4551 recordregion(startloc, expdest - stackblock(),
4552 varflags & VSQUOTE);
4553 break;
4554
4555 case VSPLUS:
4556 case VSMINUS:
4557 if (!set) {
4558 argstr(p, flag);
4559 break;
4560 }
4561 if (easy)
4562 goto record;
4563 break;
4564
4565 case VSTRIMLEFT:
4566 case VSTRIMLEFTMAX:
4567 case VSTRIMRIGHT:
4568 case VSTRIMRIGHTMAX:
4569 if (!set)
4570 break;
4571 /*
4572 * Terminate the string and start recording the pattern
4573 * right after it
4574 */
4575 STPUTC('\0', expdest);
4576 patloc = expdest - stackblock();
4577 if (subevalvar(p, NULL, patloc, subtype,
4578 startloc, varflags, quotes) == 0) {
4579 int amount = (expdest - stackblock() - patloc) + 1;
4580 STADJUST(-amount, expdest);
4581 }
4582 /* Remove any recorded regions beyond start of variable */
4583 removerecordregions(startloc);
4584 goto record;
4585
4586 case VSASSIGN:
4587 case VSQUESTION:
4588 if (!set) {
4589 if (subevalvar(p, var, 0, subtype, startloc,
4590 varflags, quotes)) {
4591 varflags &= ~VSNUL;
4592 /*
4593 * Remove any recorded regions beyond
4594 * start of variable
4595 */
4596 removerecordregions(startloc);
4597 goto again;
4598 }
4599 break;
4600 }
4601 if (easy)
4602 goto record;
4603 break;
4604
4605#ifdef DEBUG
4606 default:
4607 abort();
4608#endif
4609 }
4610
4611 if (subtype != VSNORMAL) { /* skip to end of alternative */
4612 int nesting = 1;
4613 for (;;) {
4614 if ((c = *p++) == CTLESC)
4615 p++;
4616 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
4617 if (set)
4618 argbackq = argbackq->next;
4619 } else if (c == CTLVAR) {
4620 if ((*p++ & VSTYPE) != VSNORMAL)
4621 nesting++;
4622 } else if (c == CTLENDVAR) {
4623 if (--nesting == 0)
4624 break;
4625 }
4626 }
4627 }
4628 return p;
4629}
4630
Eric Andersencb57d552001-06-28 07:25:16 +00004631
4632/*
4633 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4634 * characters to allow for further processing. Otherwise treat
4635 * $@ like $* since no splitting will be performed.
4636 */
4637
4638static void
4639argstr(p, flag)
4640 char *p;
4641 int flag;
4642{
4643 char c;
Eric Andersen2870d962001-07-02 17:27:21 +00004644 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
Eric Andersencb57d552001-06-28 07:25:16 +00004645 int firsteq = 1;
4646
4647 if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
4648 p = exptilde(p, flag);
4649 for (;;) {
4650 switch (c = *p++) {
4651 case '\0':
4652 case CTLENDVAR: /* ??? */
4653 goto breakloop;
4654 case CTLQUOTEMARK:
4655 /* "$@" syntax adherence hack */
4656 if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
4657 break;
4658 if ((flag & EXP_FULL) != 0)
4659 STPUTC(c, expdest);
4660 break;
4661 case CTLESC:
4662 if (quotes)
4663 STPUTC(c, expdest);
4664 c = *p++;
4665 STPUTC(c, expdest);
4666 break;
4667 case CTLVAR:
4668 p = evalvar(p, flag);
4669 break;
4670 case CTLBACKQ:
4671 case CTLBACKQ|CTLQUOTE:
4672 expbackq(argbackq->n, c & CTLQUOTE, flag);
4673 argbackq = argbackq->next;
4674 break;
4675#ifdef ASH_MATH_SUPPORT
4676 case CTLENDARI:
4677 expari(flag);
4678 break;
Eric Andersen2870d962001-07-02 17:27:21 +00004679#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004680 case ':':
4681 case '=':
4682 /*
4683 * sort of a hack - expand tildes in variable
4684 * assignments (after the first '=' and after ':'s).
4685 */
4686 STPUTC(c, expdest);
4687 if (flag & EXP_VARTILDE && *p == '~') {
4688 if (c == '=') {
4689 if (firsteq)
4690 firsteq = 0;
4691 else
4692 break;
4693 }
4694 p = exptilde(p, flag);
4695 }
4696 break;
4697 default:
4698 STPUTC(c, expdest);
4699 }
4700 }
4701breakloop:;
4702 return;
4703}
4704
4705static char *
4706exptilde(p, flag)
4707 char *p;
4708 int flag;
4709{
4710 char c, *startp = p;
4711 struct passwd *pw;
4712 const char *home;
4713 int quotes = flag & (EXP_FULL | EXP_CASE);
4714
4715 while ((c = *p) != '\0') {
4716 switch(c) {
4717 case CTLESC:
4718 return (startp);
4719 case CTLQUOTEMARK:
4720 return (startp);
4721 case ':':
4722 if (flag & EXP_VARTILDE)
4723 goto done;
4724 break;
4725 case '/':
4726 goto done;
4727 }
4728 p++;
4729 }
4730done:
4731 *p = '\0';
4732 if (*(startp+1) == '\0') {
4733 if ((home = lookupvar("HOME")) == NULL)
4734 goto lose;
4735 } else {
4736 if ((pw = getpwnam(startp+1)) == NULL)
4737 goto lose;
4738 home = pw->pw_dir;
4739 }
4740 if (*home == '\0')
4741 goto lose;
4742 *p = c;
4743 strtodest(home, SQSYNTAX, quotes);
4744 return (p);
4745lose:
4746 *p = c;
4747 return (startp);
4748}
4749
4750
Eric Andersen2870d962001-07-02 17:27:21 +00004751static void
4752removerecordregions(int endoff)
Eric Andersencb57d552001-06-28 07:25:16 +00004753{
4754 if (ifslastp == NULL)
4755 return;
4756
4757 if (ifsfirst.endoff > endoff) {
4758 while (ifsfirst.next != NULL) {
4759 struct ifsregion *ifsp;
4760 INTOFF;
4761 ifsp = ifsfirst.next->next;
4762 ckfree(ifsfirst.next);
4763 ifsfirst.next = ifsp;
4764 INTON;
4765 }
4766 if (ifsfirst.begoff > endoff)
4767 ifslastp = NULL;
4768 else {
4769 ifslastp = &ifsfirst;
4770 ifsfirst.endoff = endoff;
4771 }
4772 return;
4773 }
Eric Andersen2870d962001-07-02 17:27:21 +00004774
Eric Andersencb57d552001-06-28 07:25:16 +00004775 ifslastp = &ifsfirst;
4776 while (ifslastp->next && ifslastp->next->begoff < endoff)
4777 ifslastp=ifslastp->next;
4778 while (ifslastp->next != NULL) {
4779 struct ifsregion *ifsp;
4780 INTOFF;
4781 ifsp = ifslastp->next->next;
4782 ckfree(ifslastp->next);
4783 ifslastp->next = ifsp;
4784 INTON;
4785 }
4786 if (ifslastp->endoff > endoff)
4787 ifslastp->endoff = endoff;
4788}
4789
4790
4791#ifdef ASH_MATH_SUPPORT
4792/*
4793 * Expand arithmetic expression. Backup to start of expression,
4794 * evaluate, place result in (backed up) result, adjust string position.
4795 */
4796static void
Eric Andersen2870d962001-07-02 17:27:21 +00004797expari(int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004798{
4799 char *p, *start;
Eric Andersen34506362001-08-02 05:02:46 +00004800 int errcode;
Eric Andersencb57d552001-06-28 07:25:16 +00004801 int result;
4802 int begoff;
4803 int quotes = flag & (EXP_FULL | EXP_CASE);
4804 int quoted;
4805
Eric Andersen2870d962001-07-02 17:27:21 +00004806 /* ifsfree(); */
Eric Andersencb57d552001-06-28 07:25:16 +00004807
4808 /*
4809 * This routine is slightly over-complicated for
4810 * efficiency. First we make sure there is
4811 * enough space for the result, which may be bigger
4812 * than the expression if we add exponentation. Next we
4813 * scan backwards looking for the start of arithmetic. If the
4814 * next previous character is a CTLESC character, then we
4815 * have to rescan starting from the beginning since CTLESC
4816 * characters have to be processed left to right.
4817 */
4818 CHECKSTRSPACE(10, expdest);
4819 USTPUTC('\0', expdest);
4820 start = stackblock();
4821 p = expdest - 1;
4822 while (*p != CTLARI && p >= start)
4823 --p;
4824 if (*p != CTLARI)
4825 error("missing CTLARI (shouldn't happen)");
4826 if (p > start && *(p-1) == CTLESC)
4827 for (p = start; *p != CTLARI; p++)
4828 if (*p == CTLESC)
4829 p++;
4830
4831 if (p[1] == '"')
4832 quoted=1;
4833 else
4834 quoted=0;
4835 begoff = p - start;
4836 removerecordregions(begoff);
4837 if (quotes)
4838 rmescapes(p+2);
Eric Andersen34506362001-08-02 05:02:46 +00004839 result = arith(p+2, &errcode);
4840 if (errcode < 0) {
4841 if(errcode == -2)
4842 error("divide by zero");
4843 else
4844 error("syntax error: \"%s\"\n", p+2);
4845 }
Eric Andersen3102ac42001-07-06 04:26:23 +00004846 snprintf(p, 12, "%d", result);
Eric Andersencb57d552001-06-28 07:25:16 +00004847
4848 while (*p++)
4849 ;
4850
4851 if (quoted == 0)
4852 recordregion(begoff, p - 1 - start, 0);
4853 result = expdest - p + 1;
4854 STADJUST(-result, expdest);
4855}
Eric Andersen2870d962001-07-02 17:27:21 +00004856#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004857
4858/*
4859 * Expand stuff in backwards quotes.
4860 */
4861
4862static void
4863expbackq(cmd, quoted, flag)
4864 union node *cmd;
4865 int quoted;
4866 int flag;
4867{
4868 volatile struct backcmd in;
4869 int i;
4870 char buf[128];
4871 char *p;
4872 char *dest = expdest;
4873 volatile struct ifsregion saveifs;
4874 struct ifsregion *volatile savelastp;
4875 struct nodelist *volatile saveargbackq;
4876 char lastc;
4877 int startloc = dest - stackblock();
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004878 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +00004879 volatile int saveherefd;
4880 int quotes = flag & (EXP_FULL | EXP_CASE);
4881 struct jmploc jmploc;
4882 struct jmploc *volatile savehandler;
4883 int ex;
4884
4885#if __GNUC__
4886 /* Avoid longjmp clobbering */
4887 (void) &dest;
4888 (void) &syntax;
4889#endif
4890
4891 in.fd = -1;
4892 in.buf = 0;
4893 in.jp = 0;
4894
4895 INTOFF;
4896 saveifs = ifsfirst;
4897 savelastp = ifslastp;
4898 saveargbackq = argbackq;
4899 saveherefd = herefd;
4900 herefd = -1;
4901 if ((ex = setjmp(jmploc.loc))) {
4902 goto err1;
4903 }
4904 savehandler = handler;
4905 handler = &jmploc;
4906 INTON;
4907 p = grabstackstr(dest);
4908 evalbackcmd(cmd, (struct backcmd *) &in);
4909 ungrabstackstr(p, dest);
4910err1:
4911 INTOFF;
4912 ifsfirst = saveifs;
4913 ifslastp = savelastp;
4914 argbackq = saveargbackq;
4915 herefd = saveherefd;
4916 if (ex) {
4917 goto err2;
4918 }
4919
4920 p = in.buf;
4921 lastc = '\0';
4922 for (;;) {
4923 if (--in.nleft < 0) {
4924 if (in.fd < 0)
4925 break;
Eric Andersen7467c8d2001-07-12 20:26:32 +00004926 i = safe_read(in.fd, buf, sizeof buf);
Eric Andersencb57d552001-06-28 07:25:16 +00004927 TRACE(("expbackq: read returns %d\n", i));
4928 if (i <= 0)
4929 break;
4930 p = buf;
4931 in.nleft = i - 1;
4932 }
4933 lastc = *p++;
4934 if (lastc != '\0') {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004935 if (quotes && SIT(lastc, syntax) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +00004936 STPUTC(CTLESC, dest);
4937 STPUTC(lastc, dest);
4938 }
4939 }
4940
4941 /* Eat all trailing newlines */
4942 for (; dest > stackblock() && dest[-1] == '\n';)
4943 STUNPUTC(dest);
4944
4945err2:
4946 if (in.fd >= 0)
4947 close(in.fd);
4948 if (in.buf)
4949 ckfree(in.buf);
4950 if (in.jp)
4951 exitstatus = waitforjob(in.jp);
4952 handler = savehandler;
4953 if (ex) {
4954 longjmp(handler->loc, 1);
4955 }
4956 if (quoted == 0)
4957 recordregion(startloc, dest - stackblock(), 0);
4958 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4959 (dest - stackblock()) - startloc,
4960 (dest - stackblock()) - startloc,
4961 stackblock() + startloc));
4962 expdest = dest;
4963 INTON;
4964}
4965
Eric Andersencb57d552001-06-28 07:25:16 +00004966static int
4967subevalvar(p, str, strloc, subtype, startloc, varflags, quotes)
4968 char *p;
4969 char *str;
4970 int strloc;
4971 int subtype;
4972 int startloc;
4973 int varflags;
4974 int quotes;
4975{
4976 char *startp;
4977 char *loc = NULL;
4978 char *q;
4979 int c = 0;
4980 int saveherefd = herefd;
4981 struct nodelist *saveargbackq = argbackq;
4982 int amount;
4983
4984 herefd = -1;
4985 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
4986 STACKSTRNUL(expdest);
4987 herefd = saveherefd;
4988 argbackq = saveargbackq;
4989 startp = stackblock() + startloc;
4990 if (str == NULL)
4991 str = stackblock() + strloc;
4992
4993 switch (subtype) {
4994 case VSASSIGN:
4995 setvar(str, startp, 0);
4996 amount = startp - expdest;
4997 STADJUST(amount, expdest);
4998 varflags &= ~VSNUL;
4999 if (c != 0)
5000 *loc = c;
5001 return 1;
5002
5003 case VSQUESTION:
5004 if (*p != CTLENDVAR) {
Eric Andersen3102ac42001-07-06 04:26:23 +00005005 out2fmt(snlfmt, startp);
Eric Andersencb57d552001-06-28 07:25:16 +00005006 error((char *)NULL);
5007 }
5008 error("%.*s: parameter %snot set", p - str - 1,
5009 str, (varflags & VSNUL) ? "null or "
5010 : nullstr);
5011 /* NOTREACHED */
5012
5013 case VSTRIMLEFT:
5014 for (loc = startp; loc < str; loc++) {
5015 c = *loc;
5016 *loc = '\0';
5017 if (patmatch2(str, startp, quotes))
5018 goto recordleft;
5019 *loc = c;
5020 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00005021 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00005022 }
5023 return 0;
5024
5025 case VSTRIMLEFTMAX:
5026 for (loc = str - 1; loc >= startp;) {
5027 c = *loc;
5028 *loc = '\0';
5029 if (patmatch2(str, startp, quotes))
5030 goto recordleft;
5031 *loc = c;
5032 loc--;
5033 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
5034 for (q = startp; q < loc; q++)
5035 if (*q == CTLESC)
5036 q++;
5037 if (q > loc)
5038 loc--;
5039 }
5040 }
5041 return 0;
5042
5043 case VSTRIMRIGHT:
Eric Andersen2870d962001-07-02 17:27:21 +00005044 for (loc = str - 1; loc >= startp;) {
Eric Andersencb57d552001-06-28 07:25:16 +00005045 if (patmatch2(str, loc, quotes))
5046 goto recordright;
5047 loc--;
Eric Andersen2870d962001-07-02 17:27:21 +00005048 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
Eric Andersencb57d552001-06-28 07:25:16 +00005049 for (q = startp; q < loc; q++)
5050 if (*q == CTLESC)
5051 q++;
5052 if (q > loc)
5053 loc--;
5054 }
5055 }
5056 return 0;
5057
5058 case VSTRIMRIGHTMAX:
5059 for (loc = startp; loc < str - 1; loc++) {
5060 if (patmatch2(str, loc, quotes))
5061 goto recordright;
5062 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00005063 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00005064 }
5065 return 0;
5066
5067#ifdef DEBUG
5068 default:
5069 abort();
5070#endif
5071 }
5072
5073recordleft:
5074 *loc = c;
5075 amount = ((str - 1) - (loc - startp)) - expdest;
5076 STADJUST(amount, expdest);
5077 while (loc != str - 1)
5078 *startp++ = *loc++;
5079 return 1;
5080
5081recordright:
5082 amount = loc - expdest;
5083 STADJUST(amount, expdest);
5084 STPUTC('\0', expdest);
5085 STADJUST(-1, expdest);
5086 return 1;
5087}
5088
5089
5090/*
Eric Andersencb57d552001-06-28 07:25:16 +00005091 * Test whether a specialized variable is set.
5092 */
5093
5094static int
5095varisset(name, nulok)
5096 char *name;
5097 int nulok;
5098{
5099 if (*name == '!')
5100 return backgndpid != -1;
5101 else if (*name == '@' || *name == '*') {
5102 if (*shellparam.p == NULL)
5103 return 0;
5104
5105 if (nulok) {
5106 char **av;
5107
5108 for (av = shellparam.p; *av; av++)
5109 if (**av != '\0')
5110 return 1;
5111 return 0;
5112 }
5113 } else if (is_digit(*name)) {
5114 char *ap;
5115 int num = atoi(name);
5116
5117 if (num > shellparam.nparam)
5118 return 0;
5119
5120 if (num == 0)
5121 ap = arg0;
5122 else
5123 ap = shellparam.p[num - 1];
5124
5125 if (nulok && (ap == NULL || *ap == '\0'))
5126 return 0;
5127 }
5128 return 1;
5129}
5130
Eric Andersencb57d552001-06-28 07:25:16 +00005131/*
5132 * Put a string on the stack.
5133 */
5134
5135static void
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005136strtodest(const char *p, int syntax, int quotes)
Eric Andersencb57d552001-06-28 07:25:16 +00005137{
5138 while (*p) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005139 if (quotes && SIT(*p,syntax) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +00005140 STPUTC(CTLESC, expdest);
5141 STPUTC(*p++, expdest);
5142 }
5143}
5144
Eric Andersencb57d552001-06-28 07:25:16 +00005145/*
5146 * Add the value of a specialized variable to the stack string.
5147 */
5148
5149static void
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005150varvalue(char *name, int quoted, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00005151{
5152 int num;
5153 char *p;
5154 int i;
5155 int sep;
5156 int sepq = 0;
5157 char **ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005158 int syntax;
Eric Andersencb57d552001-06-28 07:25:16 +00005159 int allow_split = flags & EXP_FULL;
5160 int quotes = flags & (EXP_FULL | EXP_CASE);
5161
5162 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5163 switch (*name) {
5164 case '$':
5165 num = rootpid;
5166 goto numvar;
5167 case '?':
5168 num = oexitstatus;
5169 goto numvar;
5170 case '#':
5171 num = shellparam.nparam;
5172 goto numvar;
5173 case '!':
5174 num = backgndpid;
5175numvar:
5176 expdest = cvtnum(num, expdest);
5177 break;
5178 case '-':
5179 for (i = 0 ; i < NOPTS ; i++) {
Eric Andersen2870d962001-07-02 17:27:21 +00005180 if (optent_val(i))
5181 STPUTC(optent_letter(optlist[i]), expdest);
Eric Andersencb57d552001-06-28 07:25:16 +00005182 }
5183 break;
5184 case '@':
5185 if (allow_split && quoted) {
5186 sep = 1 << CHAR_BIT;
5187 goto param;
5188 }
5189 /* fall through */
5190 case '*':
5191 sep = ifsset() ? ifsval()[0] : ' ';
5192 if (quotes) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005193 sepq = SIT(sep,syntax) == CCTL;
Eric Andersencb57d552001-06-28 07:25:16 +00005194 }
5195param:
5196 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
5197 strtodest(p, syntax, quotes);
5198 if (*ap && sep) {
5199 if (sepq)
5200 STPUTC(CTLESC, expdest);
5201 STPUTC(sep, expdest);
5202 }
5203 }
5204 break;
5205 case '0':
5206 strtodest(arg0, syntax, quotes);
5207 break;
5208 default:
5209 num = atoi(name);
5210 if (num > 0 && num <= shellparam.nparam) {
5211 strtodest(shellparam.p[num - 1], syntax, quotes);
5212 }
5213 break;
5214 }
5215}
5216
5217
Eric Andersencb57d552001-06-28 07:25:16 +00005218/*
5219 * Record the fact that we have to scan this region of the
5220 * string for IFS characters.
5221 */
5222
5223static void
5224recordregion(start, end, nulonly)
5225 int start;
5226 int end;
5227 int nulonly;
5228{
5229 struct ifsregion *ifsp;
5230
5231 if (ifslastp == NULL) {
5232 ifsp = &ifsfirst;
5233 } else {
5234 INTOFF;
5235 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
5236 ifsp->next = NULL;
5237 ifslastp->next = ifsp;
5238 INTON;
5239 }
5240 ifslastp = ifsp;
5241 ifslastp->begoff = start;
5242 ifslastp->endoff = end;
5243 ifslastp->nulonly = nulonly;
5244}
5245
5246
5247
5248/*
5249 * Break the argument string into pieces based upon IFS and add the
5250 * strings to the argument list. The regions of the string to be
5251 * searched for IFS characters have been stored by recordregion.
5252 */
5253static void
5254ifsbreakup(string, arglist)
5255 char *string;
5256 struct arglist *arglist;
5257 {
5258 struct ifsregion *ifsp;
5259 struct strlist *sp;
5260 char *start;
5261 char *p;
5262 char *q;
5263 const char *ifs, *realifs;
5264 int ifsspc;
5265 int nulonly;
5266
5267
5268 start = string;
5269 ifsspc = 0;
5270 nulonly = 0;
5271 realifs = ifsset() ? ifsval() : defifs;
5272 if (ifslastp != NULL) {
5273 ifsp = &ifsfirst;
5274 do {
5275 p = string + ifsp->begoff;
5276 nulonly = ifsp->nulonly;
5277 ifs = nulonly ? nullstr : realifs;
5278 ifsspc = 0;
5279 while (p < string + ifsp->endoff) {
5280 q = p;
5281 if (*p == CTLESC)
5282 p++;
5283 if (strchr(ifs, *p)) {
5284 if (!nulonly)
5285 ifsspc = (strchr(defifs, *p) != NULL);
5286 /* Ignore IFS whitespace at start */
5287 if (q == start && ifsspc) {
5288 p++;
5289 start = p;
5290 continue;
5291 }
5292 *q = '\0';
5293 sp = (struct strlist *)stalloc(sizeof *sp);
5294 sp->text = start;
5295 *arglist->lastp = sp;
5296 arglist->lastp = &sp->next;
5297 p++;
5298 if (!nulonly) {
5299 for (;;) {
5300 if (p >= string + ifsp->endoff) {
5301 break;
5302 }
5303 q = p;
5304 if (*p == CTLESC)
5305 p++;
5306 if (strchr(ifs, *p) == NULL ) {
5307 p = q;
5308 break;
5309 } else if (strchr(defifs, *p) == NULL) {
5310 if (ifsspc) {
5311 p++;
5312 ifsspc = 0;
5313 } else {
5314 p = q;
5315 break;
5316 }
5317 } else
5318 p++;
5319 }
5320 }
5321 start = p;
5322 } else
5323 p++;
5324 }
5325 } while ((ifsp = ifsp->next) != NULL);
5326 if (!(*start || (!ifsspc && start > string && nulonly))) {
5327 return;
5328 }
5329 }
5330
5331 sp = (struct strlist *)stalloc(sizeof *sp);
5332 sp->text = start;
5333 *arglist->lastp = sp;
5334 arglist->lastp = &sp->next;
5335}
5336
5337static void
5338ifsfree()
5339{
5340 while (ifsfirst.next != NULL) {
5341 struct ifsregion *ifsp;
5342 INTOFF;
5343 ifsp = ifsfirst.next->next;
5344 ckfree(ifsfirst.next);
5345 ifsfirst.next = ifsp;
5346 INTON;
5347 }
5348 ifslastp = NULL;
5349 ifsfirst.next = NULL;
5350}
5351
Eric Andersen2870d962001-07-02 17:27:21 +00005352/*
5353 * Add a file name to the list.
5354 */
Eric Andersencb57d552001-06-28 07:25:16 +00005355
Eric Andersen2870d962001-07-02 17:27:21 +00005356static void
5357addfname(const char *name)
5358{
5359 char *p;
5360 struct strlist *sp;
5361
5362 p = sstrdup(name);
5363 sp = (struct strlist *)stalloc(sizeof *sp);
5364 sp->text = p;
5365 *exparg.lastp = sp;
5366 exparg.lastp = &sp->next;
5367}
Eric Andersencb57d552001-06-28 07:25:16 +00005368
5369/*
5370 * Expand shell metacharacters. At this point, the only control characters
5371 * should be escapes. The results are stored in the list exparg.
5372 */
5373
Eric Andersen62483552001-07-10 06:09:16 +00005374#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00005375static void
5376expandmeta(str, flag)
5377 struct strlist *str;
5378 int flag;
5379{
5380 const char *p;
5381 glob_t pglob;
5382 /* TODO - EXP_REDIR */
5383
5384 while (str) {
5385 if (fflag)
5386 goto nometa;
5387 p = preglob(str->text);
5388 INTOFF;
Eric Andersen34506362001-08-02 05:02:46 +00005389 switch (glob(p, 0, 0, &pglob)) {
Eric Andersencb57d552001-06-28 07:25:16 +00005390 case 0:
Eric Andersen34506362001-08-02 05:02:46 +00005391 if(pglob.gl_pathv[1]==0 && !strcmp(p, pglob.gl_pathv[0]))
Eric Andersencb57d552001-06-28 07:25:16 +00005392 goto nometa2;
5393 addglob(&pglob);
5394 globfree(&pglob);
5395 INTON;
5396 break;
5397 case GLOB_NOMATCH:
5398nometa2:
5399 globfree(&pglob);
5400 INTON;
5401nometa:
5402 *exparg.lastp = str;
5403 rmescapes(str->text);
5404 exparg.lastp = &str->next;
5405 break;
Eric Andersen2870d962001-07-02 17:27:21 +00005406 default: /* GLOB_NOSPACE */
Eric Andersencb57d552001-06-28 07:25:16 +00005407 error("Out of space");
5408 }
5409 str = str->next;
5410 }
5411}
5412
5413
5414/*
5415 * Add the result of glob(3) to the list.
5416 */
5417
5418static void
5419addglob(pglob)
5420 const glob_t *pglob;
5421{
5422 char **p = pglob->gl_pathv;
5423
5424 do {
5425 addfname(*p);
5426 } while (*++p);
5427}
5428
5429
Eric Andersen2870d962001-07-02 17:27:21 +00005430#else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005431static char *expdir;
5432
5433
5434static void
5435expandmeta(str, flag)
5436 struct strlist *str;
5437 int flag;
5438{
5439 char *p;
5440 struct strlist **savelastp;
5441 struct strlist *sp;
5442 char c;
5443 /* TODO - EXP_REDIR */
5444
5445 while (str) {
5446 if (fflag)
5447 goto nometa;
5448 p = str->text;
Eric Andersen2870d962001-07-02 17:27:21 +00005449 for (;;) { /* fast check for meta chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005450 if ((c = *p++) == '\0')
5451 goto nometa;
5452 if (c == '*' || c == '?' || c == '[' || c == '!')
5453 break;
5454 }
5455 savelastp = exparg.lastp;
5456 INTOFF;
5457 if (expdir == NULL) {
5458 int i = strlen(str->text);
5459 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5460 }
5461
5462 expmeta(expdir, str->text);
5463 ckfree(expdir);
5464 expdir = NULL;
5465 INTON;
5466 if (exparg.lastp == savelastp) {
5467 /*
5468 * no matches
5469 */
5470nometa:
5471 *exparg.lastp = str;
5472 rmescapes(str->text);
5473 exparg.lastp = &str->next;
5474 } else {
5475 *exparg.lastp = NULL;
5476 *savelastp = sp = expsort(*savelastp);
5477 while (sp->next != NULL)
5478 sp = sp->next;
5479 exparg.lastp = &sp->next;
5480 }
5481 str = str->next;
5482 }
5483}
5484
5485
5486/*
5487 * Do metacharacter (i.e. *, ?, [...]) expansion.
5488 */
5489
5490static void
5491expmeta(enddir, name)
5492 char *enddir;
5493 char *name;
5494 {
5495 char *p;
5496 const char *cp;
5497 char *q;
5498 char *start;
5499 char *endname;
5500 int metaflag;
5501 struct stat statb;
5502 DIR *dirp;
5503 struct dirent *dp;
5504 int atend;
5505 int matchdot;
5506
5507 metaflag = 0;
5508 start = name;
5509 for (p = name ; ; p++) {
5510 if (*p == '*' || *p == '?')
5511 metaflag = 1;
5512 else if (*p == '[') {
5513 q = p + 1;
5514 if (*q == '!')
5515 q++;
5516 for (;;) {
5517 while (*q == CTLQUOTEMARK)
5518 q++;
5519 if (*q == CTLESC)
5520 q++;
5521 if (*q == '/' || *q == '\0')
5522 break;
5523 if (*++q == ']') {
5524 metaflag = 1;
5525 break;
5526 }
5527 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005528 } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) {
Eric Andersencb57d552001-06-28 07:25:16 +00005529 metaflag = 1;
5530 } else if (*p == '\0')
5531 break;
5532 else if (*p == CTLQUOTEMARK)
5533 continue;
5534 else if (*p == CTLESC)
5535 p++;
5536 if (*p == '/') {
5537 if (metaflag)
5538 break;
5539 start = p + 1;
5540 }
5541 }
Eric Andersen2870d962001-07-02 17:27:21 +00005542 if (metaflag == 0) { /* we've reached the end of the file name */
Eric Andersencb57d552001-06-28 07:25:16 +00005543 if (enddir != expdir)
5544 metaflag++;
5545 for (p = name ; ; p++) {
5546 if (*p == CTLQUOTEMARK)
5547 continue;
5548 if (*p == CTLESC)
5549 p++;
5550 *enddir++ = *p;
5551 if (*p == '\0')
5552 break;
5553 }
5554 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5555 addfname(expdir);
5556 return;
5557 }
5558 endname = p;
5559 if (start != name) {
5560 p = name;
5561 while (p < start) {
5562 while (*p == CTLQUOTEMARK)
5563 p++;
5564 if (*p == CTLESC)
5565 p++;
5566 *enddir++ = *p++;
5567 }
5568 }
5569 if (enddir == expdir) {
5570 cp = ".";
5571 } else if (enddir == expdir + 1 && *expdir == '/') {
5572 cp = "/";
5573 } else {
5574 cp = expdir;
5575 enddir[-1] = '\0';
5576 }
5577 if ((dirp = opendir(cp)) == NULL)
5578 return;
5579 if (enddir != expdir)
5580 enddir[-1] = '/';
5581 if (*endname == 0) {
5582 atend = 1;
5583 } else {
5584 atend = 0;
5585 *endname++ = '\0';
5586 }
5587 matchdot = 0;
5588 p = start;
5589 while (*p == CTLQUOTEMARK)
5590 p++;
5591 if (*p == CTLESC)
5592 p++;
5593 if (*p == '.')
5594 matchdot++;
5595 while (! int_pending() && (dp = readdir(dirp)) != NULL) {
5596 if (dp->d_name[0] == '.' && ! matchdot)
5597 continue;
5598 if (patmatch(start, dp->d_name, 0)) {
5599 if (atend) {
Eric Andersen2870d962001-07-02 17:27:21 +00005600 strcpy(enddir, dp->d_name);
Eric Andersencb57d552001-06-28 07:25:16 +00005601 addfname(expdir);
5602 } else {
5603 for (p = enddir, cp = dp->d_name;
5604 (*p++ = *cp++) != '\0';)
5605 continue;
5606 p[-1] = '/';
5607 expmeta(p, endname);
5608 }
5609 }
5610 }
5611 closedir(dirp);
5612 if (! atend)
5613 endname[-1] = '/';
5614}
Eric Andersen2870d962001-07-02 17:27:21 +00005615#endif /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005616
5617
Eric Andersencb57d552001-06-28 07:25:16 +00005618
Eric Andersen62483552001-07-10 06:09:16 +00005619#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersencb57d552001-06-28 07:25:16 +00005620/*
5621 * Sort the results of file name expansion. It calculates the number of
5622 * strings to sort and then calls msort (short for merge sort) to do the
5623 * work.
5624 */
5625
5626static struct strlist *
5627expsort(str)
5628 struct strlist *str;
5629 {
5630 int len;
5631 struct strlist *sp;
5632
5633 len = 0;
5634 for (sp = str ; sp ; sp = sp->next)
5635 len++;
5636 return msort(str, len);
5637}
5638
5639
5640static struct strlist *
5641msort(list, len)
5642 struct strlist *list;
5643 int len;
5644{
5645 struct strlist *p, *q = NULL;
5646 struct strlist **lpp;
5647 int half;
5648 int n;
5649
5650 if (len <= 1)
5651 return list;
5652 half = len >> 1;
5653 p = list;
5654 for (n = half ; --n >= 0 ; ) {
5655 q = p;
5656 p = p->next;
5657 }
Eric Andersen2870d962001-07-02 17:27:21 +00005658 q->next = NULL; /* terminate first half of list */
5659 q = msort(list, half); /* sort first half of list */
5660 p = msort(p, len - half); /* sort second half */
Eric Andersencb57d552001-06-28 07:25:16 +00005661 lpp = &list;
5662 for (;;) {
5663 if (strcmp(p->text, q->text) < 0) {
5664 *lpp = p;
5665 lpp = &p->next;
5666 if ((p = *lpp) == NULL) {
5667 *lpp = q;
5668 break;
5669 }
5670 } else {
5671 *lpp = q;
5672 lpp = &q->next;
5673 if ((q = *lpp) == NULL) {
5674 *lpp = p;
5675 break;
5676 }
5677 }
5678 }
5679 return list;
5680}
5681#endif
5682
5683
5684
5685/*
5686 * Returns true if the pattern matches the string.
5687 */
5688
Eric Andersen62483552001-07-10 06:09:16 +00005689#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00005690/* squoted: string might have quote chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005691static int
Eric Andersen2870d962001-07-02 17:27:21 +00005692patmatch(char *pattern, char *string, int squoted)
5693{
Eric Andersencb57d552001-06-28 07:25:16 +00005694 const char *p;
5695 char *q;
5696
5697 p = preglob(pattern);
5698 q = squoted ? _rmescapes(string, RMESCAPE_ALLOC) : string;
5699
5700 return !fnmatch(p, q, 0);
5701}
5702
5703
5704static int
Eric Andersen2870d962001-07-02 17:27:21 +00005705patmatch2(char *pattern, char *string, int squoted)
5706{
Eric Andersencb57d552001-06-28 07:25:16 +00005707 char *p;
5708 int res;
5709
5710 sstrnleft--;
5711 p = grabstackstr(expdest);
5712 res = patmatch(pattern, string, squoted);
5713 ungrabstackstr(p, expdest);
5714 return res;
5715}
5716#else
5717static int
Eric Andersen2870d962001-07-02 17:27:21 +00005718patmatch(char *pattern, char *string, int squoted) {
5719 return pmatch(pattern, string, squoted);
Eric Andersencb57d552001-06-28 07:25:16 +00005720}
5721
5722
5723static int
Eric Andersen2870d962001-07-02 17:27:21 +00005724pmatch(char *pattern, char *string, int squoted)
5725{
Eric Andersencb57d552001-06-28 07:25:16 +00005726 char *p, *q;
5727 char c;
5728
5729 p = pattern;
5730 q = string;
5731 for (;;) {
5732 switch (c = *p++) {
5733 case '\0':
5734 goto breakloop;
5735 case CTLESC:
5736 if (squoted && *q == CTLESC)
5737 q++;
5738 if (*q++ != *p++)
5739 return 0;
5740 break;
5741 case CTLQUOTEMARK:
5742 continue;
5743 case '?':
5744 if (squoted && *q == CTLESC)
5745 q++;
5746 if (*q++ == '\0')
5747 return 0;
5748 break;
5749 case '*':
5750 c = *p;
5751 while (c == CTLQUOTEMARK || c == '*')
5752 c = *++p;
5753 if (c != CTLESC && c != CTLQUOTEMARK &&
5754 c != '?' && c != '*' && c != '[') {
5755 while (*q != c) {
5756 if (squoted && *q == CTLESC &&
5757 q[1] == c)
5758 break;
5759 if (*q == '\0')
5760 return 0;
5761 if (squoted && *q == CTLESC)
5762 q++;
5763 q++;
5764 }
5765 }
5766 do {
5767 if (pmatch(p, q, squoted))
5768 return 1;
5769 if (squoted && *q == CTLESC)
5770 q++;
5771 } while (*q++ != '\0');
5772 return 0;
5773 case '[': {
5774 char *endp;
5775 int invert, found;
5776 char chr;
5777
5778 endp = p;
5779 if (*endp == '!')
5780 endp++;
5781 for (;;) {
5782 while (*endp == CTLQUOTEMARK)
5783 endp++;
5784 if (*endp == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00005785 goto dft; /* no matching ] */
Eric Andersencb57d552001-06-28 07:25:16 +00005786 if (*endp == CTLESC)
5787 endp++;
5788 if (*++endp == ']')
5789 break;
5790 }
5791 invert = 0;
5792 if (*p == '!') {
5793 invert++;
5794 p++;
5795 }
5796 found = 0;
5797 chr = *q++;
5798 if (squoted && chr == CTLESC)
5799 chr = *q++;
5800 if (chr == '\0')
5801 return 0;
5802 c = *p++;
5803 do {
5804 if (c == CTLQUOTEMARK)
5805 continue;
5806 if (c == CTLESC)
5807 c = *p++;
5808 if (*p == '-' && p[1] != ']') {
5809 p++;
5810 while (*p == CTLQUOTEMARK)
5811 p++;
5812 if (*p == CTLESC)
5813 p++;
5814 if (chr >= c && chr <= *p)
5815 found = 1;
5816 p++;
5817 } else {
5818 if (chr == c)
5819 found = 1;
5820 }
5821 } while ((c = *p++) != ']');
5822 if (found == invert)
5823 return 0;
5824 break;
5825 }
Eric Andersen2870d962001-07-02 17:27:21 +00005826dft: default:
Eric Andersencb57d552001-06-28 07:25:16 +00005827 if (squoted && *q == CTLESC)
5828 q++;
5829 if (*q++ != c)
5830 return 0;
5831 break;
5832 }
5833 }
5834breakloop:
5835 if (*q != '\0')
5836 return 0;
5837 return 1;
5838}
5839#endif
5840
5841
5842
5843/*
5844 * Remove any CTLESC characters from a string.
5845 */
5846
Eric Andersen62483552001-07-10 06:09:16 +00005847#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00005848static char *
Eric Andersen2870d962001-07-02 17:27:21 +00005849_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005850{
5851 char *p, *q, *r;
5852 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5853
5854 p = strpbrk(str, qchars);
5855 if (!p) {
5856 return str;
5857 }
5858 q = p;
5859 r = str;
5860 if (flag & RMESCAPE_ALLOC) {
5861 size_t len = p - str;
5862 q = r = stalloc(strlen(p) + len + 1);
5863 if (len > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00005864 memcpy(q, str, len);
5865 q += len;
Eric Andersencb57d552001-06-28 07:25:16 +00005866 }
5867 }
5868 while (*p) {
5869 if (*p == CTLQUOTEMARK) {
5870 p++;
5871 continue;
5872 }
5873 if (*p == CTLESC) {
5874 p++;
5875 if (flag & RMESCAPE_GLOB && *p != '/') {
5876 *q++ = '\\';
5877 }
5878 }
5879 *q++ = *p++;
5880 }
5881 *q = '\0';
5882 return r;
5883}
5884#else
5885static void
5886rmescapes(str)
5887 char *str;
5888{
5889 char *p, *q;
5890
5891 p = str;
5892 while (*p != CTLESC && *p != CTLQUOTEMARK) {
5893 if (*p++ == '\0')
5894 return;
5895 }
5896 q = p;
5897 while (*p) {
5898 if (*p == CTLQUOTEMARK) {
5899 p++;
5900 continue;
5901 }
5902 if (*p == CTLESC)
5903 p++;
5904 *q++ = *p++;
5905 }
5906 *q = '\0';
5907}
5908#endif
5909
5910
5911
5912/*
5913 * See if a pattern matches in a case statement.
5914 */
5915
5916static int
Eric Andersen2870d962001-07-02 17:27:21 +00005917casematch(union node *pattern, const char *val)
5918{
Eric Andersencb57d552001-06-28 07:25:16 +00005919 struct stackmark smark;
5920 int result;
5921 char *p;
5922
5923 setstackmark(&smark);
5924 argbackq = pattern->narg.backquote;
5925 STARTSTACKSTR(expdest);
5926 ifslastp = NULL;
5927 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5928 STPUTC('\0', expdest);
5929 p = grabstackstr(expdest);
Eric Andersen2870d962001-07-02 17:27:21 +00005930 result = patmatch(p, (char *)val, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00005931 popstackmark(&smark);
5932 return result;
5933}
5934
5935/*
5936 * Our own itoa().
5937 */
5938
5939static char *
5940cvtnum(num, buf)
5941 int num;
5942 char *buf;
5943 {
5944 int len;
5945
5946 CHECKSTRSPACE(32, buf);
5947 len = sprintf(buf, "%d", num);
5948 STADJUST(len, buf);
5949 return buf;
5950}
Eric Andersencb57d552001-06-28 07:25:16 +00005951/*
5952 * Editline and history functions (and glue).
5953 */
5954static int histcmd(argc, argv)
5955 int argc;
5956 char **argv;
5957{
5958 error("not compiled with history support");
5959 /* NOTREACHED */
5960}
5961
5962
Eric Andersencb57d552001-06-28 07:25:16 +00005963struct redirtab {
5964 struct redirtab *next;
Russ Dill4db35642001-07-26 05:58:40 +00005965 short renamed[10]; /* Current ash support only 0-9 descriptors */
Eric Andersen34506362001-08-02 05:02:46 +00005966 /* char on arm (and others) can't be negative */
Eric Andersencb57d552001-06-28 07:25:16 +00005967};
5968
Eric Andersen2870d962001-07-02 17:27:21 +00005969static struct redirtab *redirlist;
Eric Andersencb57d552001-06-28 07:25:16 +00005970
5971extern char **environ;
5972
5973
5974
5975/*
5976 * Initialization code.
5977 */
5978
5979static void
Eric Andersen2870d962001-07-02 17:27:21 +00005980init(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00005981
5982 /* from cd.c: */
5983 {
5984 setpwd(0, 0);
5985 }
5986
5987 /* from input.c: */
5988 {
5989 basepf.nextc = basepf.buf = basebuf;
5990 }
5991
Eric Andersencb57d552001-06-28 07:25:16 +00005992 /* from var.c: */
5993 {
5994 char **envp;
5995 char ppid[32];
5996
5997 initvar();
5998 for (envp = environ ; *envp ; envp++) {
5999 if (strchr(*envp, '=')) {
6000 setvareq(*envp, VEXPORT|VTEXTFIXED);
6001 }
6002 }
6003
Eric Andersen3102ac42001-07-06 04:26:23 +00006004 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
Eric Andersencb57d552001-06-28 07:25:16 +00006005 setvar("PPID", ppid, 0);
6006 }
6007}
6008
6009
6010
6011/*
6012 * This routine is called when an error or an interrupt occurs in an
6013 * interactive shell and control is returned to the main command loop.
6014 */
6015
Eric Andersen2870d962001-07-02 17:27:21 +00006016/* 1 == check for aliases, 2 == also check for assignments */
Eric Andersen7467c8d2001-07-12 20:26:32 +00006017static int checkalias; /* also used in no alias mode for check assignments */
Eric Andersen2870d962001-07-02 17:27:21 +00006018
Eric Andersencb57d552001-06-28 07:25:16 +00006019static void
Eric Andersen2870d962001-07-02 17:27:21 +00006020reset(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00006021
6022 /* from eval.c: */
6023 {
6024 evalskip = 0;
6025 loopnest = 0;
6026 funcnest = 0;
6027 }
6028
6029 /* from input.c: */
6030 {
6031 if (exception != EXSHELLPROC)
Eric Andersen2870d962001-07-02 17:27:21 +00006032 parselleft = parsenleft = 0; /* clear input buffer */
Eric Andersencb57d552001-06-28 07:25:16 +00006033 popallfiles();
6034 }
6035
6036 /* from parser.c: */
6037 {
6038 tokpushback = 0;
6039 checkkwd = 0;
6040 checkalias = 0;
6041 }
6042
6043 /* from redir.c: */
6044 {
6045 while (redirlist)
6046 popredir();
6047 }
6048
Eric Andersencb57d552001-06-28 07:25:16 +00006049}
6050
6051
6052
6053/*
Eric Andersencb57d552001-06-28 07:25:16 +00006054 * This file implements the input routines used by the parser.
6055 */
6056
6057#ifdef BB_FEATURE_COMMAND_EDITING
Eric Andersencb57d552001-06-28 07:25:16 +00006058static const char * cmdedit_prompt;
6059static inline void putprompt(const char *s) {
6060 cmdedit_prompt = s;
6061}
6062#else
6063static inline void putprompt(const char *s) {
6064 out2str(s);
6065}
6066#endif
6067
Eric Andersen2870d962001-07-02 17:27:21 +00006068#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
Eric Andersencb57d552001-06-28 07:25:16 +00006069
Eric Andersencb57d552001-06-28 07:25:16 +00006070
Eric Andersencb57d552001-06-28 07:25:16 +00006071
Eric Andersen2870d962001-07-02 17:27:21 +00006072/*
6073 * Same as pgetc(), but ignores PEOA.
6074 */
Eric Andersencb57d552001-06-28 07:25:16 +00006075
Eric Andersen2870d962001-07-02 17:27:21 +00006076#ifdef ASH_ALIAS
6077static int
6078pgetc2()
6079{
6080 int c;
6081 do {
6082 c = pgetc_macro();
6083 } while (c == PEOA);
6084 return c;
Eric Andersencb57d552001-06-28 07:25:16 +00006085}
Eric Andersen2870d962001-07-02 17:27:21 +00006086#else
6087static inline int pgetc2() { return pgetc_macro(); }
Eric Andersencb57d552001-06-28 07:25:16 +00006088#endif
6089
Eric Andersencb57d552001-06-28 07:25:16 +00006090/*
6091 * Read a line from the script.
6092 */
6093
Eric Andersen62483552001-07-10 06:09:16 +00006094static inline char *
Eric Andersen2870d962001-07-02 17:27:21 +00006095pfgets(char *line, int len)
Eric Andersencb57d552001-06-28 07:25:16 +00006096{
6097 char *p = line;
6098 int nleft = len;
6099 int c;
6100
6101 while (--nleft > 0) {
6102 c = pgetc2();
6103 if (c == PEOF) {
6104 if (p == line)
6105 return NULL;
6106 break;
6107 }
6108 *p++ = c;
6109 if (c == '\n')
6110 break;
6111 }
6112 *p = '\0';
6113 return line;
6114}
6115
Eric Andersen62483552001-07-10 06:09:16 +00006116static inline int
Eric Andersen2870d962001-07-02 17:27:21 +00006117preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006118{
6119 int nr;
6120 char *buf = parsefile->buf;
6121 parsenextc = buf;
6122
6123retry:
6124#ifdef BB_FEATURE_COMMAND_EDITING
6125 {
Eric Andersen34506362001-08-02 05:02:46 +00006126 if (!iflag || parsefile->fd)
Eric Andersen7467c8d2001-07-12 20:26:32 +00006127 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersen2870d962001-07-02 17:27:21 +00006128 else {
Eric Andersen044228d2001-07-17 01:12:36 +00006129 nr = cmdedit_read_input((char*)cmdedit_prompt, buf);
Eric Andersencb57d552001-06-28 07:25:16 +00006130 }
6131 }
6132#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00006133 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006134#endif
6135
6136 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006137 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6138 int flags = fcntl(0, F_GETFL, 0);
6139 if (flags >= 0 && flags & O_NONBLOCK) {
6140 flags &=~ O_NONBLOCK;
6141 if (fcntl(0, F_SETFL, flags) >= 0) {
6142 out2str("sh: turning off NDELAY mode\n");
6143 goto retry;
6144 }
6145 }
6146 }
6147 }
6148 return nr;
6149}
6150
Eric Andersen2870d962001-07-02 17:27:21 +00006151static void
6152popstring(void)
6153{
6154 struct strpush *sp = parsefile->strpush;
6155
6156 INTOFF;
6157#ifdef ASH_ALIAS
6158 if (sp->ap) {
6159 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6160 if (!checkalias) {
6161 checkalias = 1;
6162 }
6163 }
6164 if (sp->string != sp->ap->val) {
6165 ckfree(sp->string);
6166 }
6167
6168 sp->ap->flag &= ~ALIASINUSE;
6169 if (sp->ap->flag & ALIASDEAD) {
6170 unalias(sp->ap->name);
6171 }
6172 }
6173#endif
6174 parsenextc = sp->prevstring;
6175 parsenleft = sp->prevnleft;
6176/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6177 parsefile->strpush = sp->prev;
6178 if (sp != &(parsefile->basestrpush))
6179 ckfree(sp);
6180 INTON;
6181}
6182
6183
Eric Andersencb57d552001-06-28 07:25:16 +00006184/*
6185 * Refill the input buffer and return the next input character:
6186 *
6187 * 1) If a string was pushed back on the input, pop it;
6188 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6189 * from a string so we can't refill the buffer, return EOF.
6190 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6191 * 4) Process input up to the next newline, deleting nul characters.
6192 */
6193
6194static int
Eric Andersen2870d962001-07-02 17:27:21 +00006195preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006196{
6197 char *p, *q;
6198 int more;
6199 char savec;
6200
6201 while (parsefile->strpush) {
Eric Andersen2870d962001-07-02 17:27:21 +00006202#ifdef ASH_ALIAS
6203 if (parsenleft == -1 && parsefile->strpush->ap &&
6204 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00006205 return PEOA;
6206 }
Eric Andersen2870d962001-07-02 17:27:21 +00006207#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006208 popstring();
6209 if (--parsenleft >= 0)
6210 return (*parsenextc++);
6211 }
6212 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6213 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00006214 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00006215
6216again:
6217 if (parselleft <= 0) {
6218 if ((parselleft = preadfd()) <= 0) {
6219 parselleft = parsenleft = EOF_NLEFT;
6220 return PEOF;
6221 }
6222 }
6223
6224 q = p = parsenextc;
6225
6226 /* delete nul characters */
6227 for (more = 1; more;) {
6228 switch (*p) {
6229 case '\0':
Eric Andersen2870d962001-07-02 17:27:21 +00006230 p++; /* Skip nul */
Eric Andersencb57d552001-06-28 07:25:16 +00006231 goto check;
6232
6233
6234 case '\n':
6235 parsenleft = q - parsenextc;
6236 more = 0; /* Stop processing here */
6237 break;
6238 }
6239
6240 *q++ = *p++;
6241check:
6242 if (--parselleft <= 0 && more) {
6243 parsenleft = q - parsenextc - 1;
6244 if (parsenleft < 0)
6245 goto again;
6246 more = 0;
6247 }
6248 }
6249
6250 savec = *q;
6251 *q = '\0';
6252
6253 if (vflag) {
6254 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00006255 }
6256
6257 *q = savec;
6258
6259 return *parsenextc++;
6260}
6261
Eric Andersencb57d552001-06-28 07:25:16 +00006262
6263/*
6264 * Push a string back onto the input at this current parsefile level.
6265 * We handle aliases this way.
6266 */
6267static void
Eric Andersen2870d962001-07-02 17:27:21 +00006268pushstring(char *s, int len, void *ap)
6269{
Eric Andersencb57d552001-06-28 07:25:16 +00006270 struct strpush *sp;
6271
6272 INTOFF;
6273/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6274 if (parsefile->strpush) {
6275 sp = ckmalloc(sizeof (struct strpush));
6276 sp->prev = parsefile->strpush;
6277 parsefile->strpush = sp;
6278 } else
6279 sp = parsefile->strpush = &(parsefile->basestrpush);
6280 sp->prevstring = parsenextc;
6281 sp->prevnleft = parsenleft;
Eric Andersen2870d962001-07-02 17:27:21 +00006282#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00006283 sp->ap = (struct alias *)ap;
6284 if (ap) {
6285 ((struct alias *)ap)->flag |= ALIASINUSE;
6286 sp->string = s;
6287 }
Eric Andersen2870d962001-07-02 17:27:21 +00006288#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006289 parsenextc = s;
6290 parsenleft = len;
6291 INTON;
6292}
6293
Eric Andersencb57d552001-06-28 07:25:16 +00006294
Eric Andersencb57d552001-06-28 07:25:16 +00006295/*
6296 * Like setinputfile, but takes input from a string.
6297 */
6298
6299static void
Eric Andersen62483552001-07-10 06:09:16 +00006300setinputstring(char *string)
6301{
Eric Andersencb57d552001-06-28 07:25:16 +00006302 INTOFF;
6303 pushfile();
6304 parsenextc = string;
6305 parsenleft = strlen(string);
6306 parsefile->buf = NULL;
6307 plinno = 1;
6308 INTON;
6309}
6310
6311
6312
6313/*
6314 * To handle the "." command, a stack of input files is used. Pushfile
6315 * adds a new entry to the stack and popfile restores the previous level.
6316 */
6317
6318static void
Eric Andersen2870d962001-07-02 17:27:21 +00006319pushfile(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00006320 struct parsefile *pf;
6321
6322 parsefile->nleft = parsenleft;
6323 parsefile->lleft = parselleft;
6324 parsefile->nextc = parsenextc;
6325 parsefile->linno = plinno;
6326 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6327 pf->prev = parsefile;
6328 pf->fd = -1;
6329 pf->strpush = NULL;
6330 pf->basestrpush.prev = NULL;
6331 parsefile = pf;
6332}
6333
Eric Andersen2870d962001-07-02 17:27:21 +00006334#ifdef JOBS
6335static void restartjob (struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00006336#endif
Eric Andersen2870d962001-07-02 17:27:21 +00006337static void freejob (struct job *);
6338static struct job *getjob (const char *);
6339static int dowait (int, struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00006340static void waitonint(int);
6341
6342
Eric Andersen2870d962001-07-02 17:27:21 +00006343/*
6344 * We keep track of whether or not fd0 has been redirected. This is for
6345 * background commands, where we want to redirect fd0 to /dev/null only
6346 * if it hasn't already been redirected.
6347*/
6348static int fd0_redirected = 0;
6349
6350/* Return true if fd 0 has already been redirected at least once. */
6351static inline int
6352fd0_redirected_p () {
6353 return fd0_redirected != 0;
6354}
6355
Eric Andersen62483552001-07-10 06:09:16 +00006356static void dupredirect (const union node *, int, int fd1dup);
Eric Andersen2870d962001-07-02 17:27:21 +00006357
6358#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006359/*
6360 * Turn job control on and off.
6361 *
6362 * Note: This code assumes that the third arg to ioctl is a character
6363 * pointer, which is true on Berkeley systems but not System V. Since
6364 * System V doesn't have job control yet, this isn't a problem now.
6365 */
6366
Eric Andersen2870d962001-07-02 17:27:21 +00006367
Eric Andersencb57d552001-06-28 07:25:16 +00006368
6369static void setjobctl(int enable)
6370{
6371#ifdef OLD_TTY_DRIVER
6372 int ldisc;
6373#endif
6374
6375 if (enable == jobctl || rootshell == 0)
6376 return;
6377 if (enable) {
6378 do { /* while we are in the background */
6379#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006380 if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006381#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006382 initialpgrp = tcgetpgrp(2);
Eric Andersencb57d552001-06-28 07:25:16 +00006383 if (initialpgrp < 0) {
6384#endif
Eric Andersen8c145dc2001-07-10 16:57:09 +00006385 out2str("sh: can't access tty; job control turned off\n");
Eric Andersencb57d552001-06-28 07:25:16 +00006386 mflag = 0;
6387 return;
6388 }
6389 if (initialpgrp == -1)
6390 initialpgrp = getpgrp();
6391 else if (initialpgrp != getpgrp()) {
6392 killpg(initialpgrp, SIGTTIN);
6393 continue;
6394 }
6395 } while (0);
6396#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006397 if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
Eric Andersen8c145dc2001-07-10 16:57:09 +00006398 out2str("sh: need new tty driver to run job control; job control turned off\n");
Eric Andersencb57d552001-06-28 07:25:16 +00006399 mflag = 0;
6400 return;
6401 }
6402#endif
6403 setsignal(SIGTSTP);
6404 setsignal(SIGTTOU);
6405 setsignal(SIGTTIN);
6406 setpgid(0, rootpid);
6407#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006408 ioctl(2, TIOCSPGRP, (char *)&rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00006409#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006410 tcsetpgrp(2, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00006411#endif
Eric Andersen8c145dc2001-07-10 16:57:09 +00006412 } else { /* turning job control off */
Eric Andersencb57d552001-06-28 07:25:16 +00006413 setpgid(0, initialpgrp);
6414#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006415 ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006416#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006417 tcsetpgrp(2, initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006418#endif
6419 setsignal(SIGTSTP);
6420 setsignal(SIGTTOU);
6421 setsignal(SIGTTIN);
6422 }
6423 jobctl = enable;
6424}
6425#endif
6426
6427
Eric Andersen2870d962001-07-02 17:27:21 +00006428#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006429static int
6430killcmd(argc, argv)
6431 int argc;
6432 char **argv;
6433{
6434 int signo = -1;
6435 int list = 0;
6436 int i;
6437 pid_t pid;
6438 struct job *jp;
6439
6440 if (argc <= 1) {
6441usage:
6442 error(
6443"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6444"kill -l [exitstatus]"
6445 );
6446 }
6447
6448 if (*argv[1] == '-') {
6449 signo = decode_signal(argv[1] + 1, 1);
6450 if (signo < 0) {
6451 int c;
6452
6453 while ((c = nextopt("ls:")) != '\0')
6454 switch (c) {
6455 case 'l':
6456 list = 1;
6457 break;
6458 case 's':
6459 signo = decode_signal(optionarg, 1);
6460 if (signo < 0) {
6461 error(
6462 "invalid signal number or name: %s",
6463 optionarg
6464 );
6465 }
Eric Andersen2870d962001-07-02 17:27:21 +00006466 break;
Eric Andersencb57d552001-06-28 07:25:16 +00006467#ifdef DEBUG
6468 default:
6469 error(
6470 "nextopt returned character code 0%o", c);
6471#endif
6472 }
6473 } else
6474 argptr++;
6475 }
6476
6477 if (!list && signo < 0)
6478 signo = SIGTERM;
6479
6480 if ((signo < 0 || !*argptr) ^ list) {
6481 goto usage;
6482 }
6483
6484 if (list) {
Eric Andersen34506362001-08-02 05:02:46 +00006485 const char *name;
6486
Eric Andersencb57d552001-06-28 07:25:16 +00006487 if (!*argptr) {
6488 out1str("0\n");
6489 for (i = 1; i < NSIG; i++) {
Eric Andersen34506362001-08-02 05:02:46 +00006490 name = u_signal_names(0, &i, 1);
6491 if(name)
6492 printf(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006493 }
6494 return 0;
6495 }
Eric Andersen34506362001-08-02 05:02:46 +00006496 name = u_signal_names(*argptr, &signo, -1);
6497 if (name)
6498 printf(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006499 else
6500 error("invalid signal number or exit status: %s",
6501 *argptr);
6502 return 0;
6503 }
6504
6505 do {
6506 if (**argptr == '%') {
6507 jp = getjob(*argptr);
6508 if (jp->jobctl == 0)
6509 error("job %s not created under job control",
6510 *argptr);
6511 pid = -jp->ps[0].pid;
6512 } else
6513 pid = atoi(*argptr);
6514 if (kill(pid, signo) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00006515 error("%s: %m", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006516 } while (*++argptr);
6517
6518 return 0;
6519}
6520
6521static int
6522fgcmd(argc, argv)
6523 int argc;
6524 char **argv;
6525{
6526 struct job *jp;
6527 int pgrp;
6528 int status;
6529
6530 jp = getjob(argv[1]);
6531 if (jp->jobctl == 0)
6532 error("job not created under job control");
6533 pgrp = jp->ps[0].pid;
6534#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006535 ioctl(2, TIOCSPGRP, (char *)&pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006536#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006537 tcsetpgrp(2, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006538#endif
6539 restartjob(jp);
6540 INTOFF;
6541 status = waitforjob(jp);
6542 INTON;
6543 return status;
6544}
6545
6546
6547static int
6548bgcmd(argc, argv)
6549 int argc;
6550 char **argv;
6551{
6552 struct job *jp;
6553
6554 do {
6555 jp = getjob(*++argv);
6556 if (jp->jobctl == 0)
6557 error("job not created under job control");
6558 restartjob(jp);
6559 } while (--argc > 1);
6560 return 0;
6561}
6562
6563
6564static void
6565restartjob(jp)
6566 struct job *jp;
6567{
6568 struct procstat *ps;
6569 int i;
6570
6571 if (jp->state == JOBDONE)
6572 return;
6573 INTOFF;
6574 killpg(jp->ps[0].pid, SIGCONT);
6575 for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
6576 if (WIFSTOPPED(ps->status)) {
6577 ps->status = -1;
6578 jp->state = 0;
6579 }
6580 }
6581 INTON;
6582}
6583#endif
6584
Eric Andersen2870d962001-07-02 17:27:21 +00006585static void showjobs(int change);
6586
Eric Andersencb57d552001-06-28 07:25:16 +00006587
6588static int
6589jobscmd(argc, argv)
6590 int argc;
6591 char **argv;
6592{
6593 showjobs(0);
6594 return 0;
6595}
6596
6597
6598/*
6599 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6600 * statuses have changed since the last call to showjobs.
6601 *
6602 * If the shell is interrupted in the process of creating a job, the
6603 * result may be a job structure containing zero processes. Such structures
6604 * will be freed here.
6605 */
6606
6607static void
6608showjobs(change)
6609 int change;
6610{
6611 int jobno;
6612 int procno;
6613 int i;
6614 struct job *jp;
6615 struct procstat *ps;
6616 int col;
6617 char s[64];
6618
6619 TRACE(("showjobs(%d) called\n", change));
6620 while (dowait(0, (struct job *)NULL) > 0);
6621 for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
6622 if (! jp->used)
6623 continue;
6624 if (jp->nprocs == 0) {
6625 freejob(jp);
6626 continue;
6627 }
6628 if (change && ! jp->changed)
6629 continue;
6630 procno = jp->nprocs;
Eric Andersen2870d962001-07-02 17:27:21 +00006631 for (ps = jp->ps ; ; ps++) { /* for each process */
Eric Andersencb57d552001-06-28 07:25:16 +00006632 if (ps == jp->ps)
Eric Andersen3102ac42001-07-06 04:26:23 +00006633 snprintf(s, 64, "[%d] %ld ", jobno,
Eric Andersencb57d552001-06-28 07:25:16 +00006634 (long)ps->pid);
6635 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006636 snprintf(s, 64, " %ld ",
Eric Andersencb57d552001-06-28 07:25:16 +00006637 (long)ps->pid);
6638 out1str(s);
6639 col = strlen(s);
6640 s[0] = '\0';
6641 if (ps->status == -1) {
6642 /* don't print anything */
6643 } else if (WIFEXITED(ps->status)) {
Eric Andersen3102ac42001-07-06 04:26:23 +00006644 snprintf(s, 64, "Exit %d",
Eric Andersencb57d552001-06-28 07:25:16 +00006645 WEXITSTATUS(ps->status));
6646 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00006647#ifdef JOBS
6648 if (WIFSTOPPED(ps->status))
Eric Andersencb57d552001-06-28 07:25:16 +00006649 i = WSTOPSIG(ps->status);
6650 else /* WIFSIGNALED(ps->status) */
6651#endif
6652 i = WTERMSIG(ps->status);
6653 if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
Eric Andersen2870d962001-07-02 17:27:21 +00006654 strcpy(s, sys_siglist[i & 0x7F]);
Eric Andersencb57d552001-06-28 07:25:16 +00006655 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006656 snprintf(s, 64, "Signal %d", i & 0x7F);
Eric Andersencb57d552001-06-28 07:25:16 +00006657 if (WCOREDUMP(ps->status))
6658 strcat(s, " (core dumped)");
6659 }
6660 out1str(s);
6661 col += strlen(s);
Eric Andersen62483552001-07-10 06:09:16 +00006662 printf(
Eric Andersencb57d552001-06-28 07:25:16 +00006663 "%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ',
6664 ps->cmd
6665 );
6666 if (--procno <= 0)
6667 break;
6668 }
6669 jp->changed = 0;
6670 if (jp->state == JOBDONE) {
6671 freejob(jp);
6672 }
6673 }
6674}
6675
6676
6677/*
6678 * Mark a job structure as unused.
6679 */
6680
6681static void
Eric Andersen62483552001-07-10 06:09:16 +00006682freejob(struct job *jp)
6683{
6684 const struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006685 int i;
6686
6687 INTOFF;
6688 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6689 if (ps->cmd != nullstr)
6690 ckfree(ps->cmd);
6691 }
6692 if (jp->ps != &jp->ps0)
6693 ckfree(jp->ps);
6694 jp->used = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006695#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006696 if (curjob == jp - jobtab + 1)
6697 curjob = 0;
6698#endif
6699 INTON;
6700}
6701
6702
6703
6704static int
6705waitcmd(argc, argv)
6706 int argc;
6707 char **argv;
6708{
6709 struct job *job;
6710 int status, retval;
6711 struct job *jp;
6712
6713 if (--argc > 0) {
6714start:
6715 job = getjob(*++argv);
6716 } else {
6717 job = NULL;
6718 }
Eric Andersen2870d962001-07-02 17:27:21 +00006719 for (;;) { /* loop until process terminated or stopped */
Eric Andersencb57d552001-06-28 07:25:16 +00006720 if (job != NULL) {
6721 if (job->state) {
6722 status = job->ps[job->nprocs - 1].status;
6723 if (! iflag)
6724 freejob(job);
6725 if (--argc) {
6726 goto start;
6727 }
6728 if (WIFEXITED(status))
6729 retval = WEXITSTATUS(status);
Eric Andersen2870d962001-07-02 17:27:21 +00006730#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006731 else if (WIFSTOPPED(status))
6732 retval = WSTOPSIG(status) + 128;
6733#endif
6734 else {
6735 /* XXX: limits number of signals */
6736 retval = WTERMSIG(status) + 128;
6737 }
6738 return retval;
6739 }
6740 } else {
6741 for (jp = jobtab ; ; jp++) {
Eric Andersen2870d962001-07-02 17:27:21 +00006742 if (jp >= jobtab + njobs) { /* no running procs */
Eric Andersencb57d552001-06-28 07:25:16 +00006743 return 0;
6744 }
6745 if (jp->used && jp->state == 0)
6746 break;
6747 }
6748 }
6749 if (dowait(2, 0) < 0 && errno == EINTR) {
6750 return 129;
6751 }
6752 }
6753}
6754
6755
6756
6757/*
6758 * Convert a job name to a job structure.
6759 */
6760
6761static struct job *
Eric Andersen2870d962001-07-02 17:27:21 +00006762getjob(const char *name)
6763{
Eric Andersencb57d552001-06-28 07:25:16 +00006764 int jobno;
6765 struct job *jp;
6766 int pid;
6767 int i;
6768
6769 if (name == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00006770#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006771currentjob:
6772 if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
6773 error("No current job");
6774 return &jobtab[jobno - 1];
6775#else
6776 error("No current job");
6777#endif
6778 } else if (name[0] == '%') {
6779 if (is_digit(name[1])) {
6780 jobno = number(name + 1);
6781 if (jobno > 0 && jobno <= njobs
6782 && jobtab[jobno - 1].used != 0)
6783 return &jobtab[jobno - 1];
Eric Andersen2870d962001-07-02 17:27:21 +00006784#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006785 } else if (name[1] == '%' && name[2] == '\0') {
6786 goto currentjob;
6787#endif
6788 } else {
6789 struct job *found = NULL;
6790 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
6791 if (jp->used && jp->nprocs > 0
6792 && prefix(name + 1, jp->ps[0].cmd)) {
6793 if (found)
6794 error("%s: ambiguous", name);
6795 found = jp;
6796 }
6797 }
6798 if (found)
6799 return found;
6800 }
Eric Andersen2870d962001-07-02 17:27:21 +00006801 } else if (is_number(name, &pid)) {
Eric Andersencb57d552001-06-28 07:25:16 +00006802 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
6803 if (jp->used && jp->nprocs > 0
6804 && jp->ps[jp->nprocs - 1].pid == pid)
6805 return jp;
6806 }
6807 }
6808 error("No such job: %s", name);
6809 /* NOTREACHED */
6810}
6811
6812
6813
6814/*
6815 * Return a new job structure,
6816 */
6817
Eric Andersen2870d962001-07-02 17:27:21 +00006818static struct job *
Eric Andersen62483552001-07-10 06:09:16 +00006819makejob(const union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00006820{
6821 int i;
6822 struct job *jp;
6823
6824 for (i = njobs, jp = jobtab ; ; jp++) {
6825 if (--i < 0) {
6826 INTOFF;
6827 if (njobs == 0) {
6828 jobtab = ckmalloc(4 * sizeof jobtab[0]);
6829 } else {
6830 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
6831 memcpy(jp, jobtab, njobs * sizeof jp[0]);
6832 /* Relocate `ps' pointers */
6833 for (i = 0; i < njobs; i++)
6834 if (jp[i].ps == &jobtab[i].ps0)
6835 jp[i].ps = &jp[i].ps0;
6836 ckfree(jobtab);
6837 jobtab = jp;
6838 }
6839 jp = jobtab + njobs;
6840 for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
6841 INTON;
6842 break;
6843 }
6844 if (jp->used == 0)
6845 break;
6846 }
6847 INTOFF;
6848 jp->state = 0;
6849 jp->used = 1;
6850 jp->changed = 0;
6851 jp->nprocs = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006852#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006853 jp->jobctl = jobctl;
6854#endif
6855 if (nprocs > 1) {
6856 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
6857 } else {
6858 jp->ps = &jp->ps0;
6859 }
6860 INTON;
6861 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
6862 jp - jobtab + 1));
6863 return jp;
6864}
6865
6866
6867/*
6868 * Fork of a subshell. If we are doing job control, give the subshell its
6869 * own process group. Jp is a job structure that the job is to be added to.
6870 * N is the command that will be evaluated by the child. Both jp and n may
6871 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00006872 * FORK_FG - Fork off a foreground process.
6873 * FORK_BG - Fork off a background process.
6874 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
6875 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00006876 *
6877 * When job control is turned off, background processes have their standard
6878 * input redirected to /dev/null (except for the second and later processes
6879 * in a pipeline).
6880 */
6881
Eric Andersen2870d962001-07-02 17:27:21 +00006882
6883
Eric Andersencb57d552001-06-28 07:25:16 +00006884static int
Eric Andersen62483552001-07-10 06:09:16 +00006885forkshell(struct job *jp, const union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00006886{
6887 int pid;
Eric Andersen62483552001-07-10 06:09:16 +00006888#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006889 int pgrp;
Eric Andersen62483552001-07-10 06:09:16 +00006890#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006891 const char *devnull = _PATH_DEVNULL;
6892 const char *nullerr = "Can't open %s";
6893
6894 TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
6895 mode));
6896 INTOFF;
6897 pid = fork();
6898 if (pid == -1) {
6899 TRACE(("Fork failed, errno=%d\n", errno));
6900 INTON;
6901 error("Cannot fork");
6902 }
6903 if (pid == 0) {
6904 struct job *p;
6905 int wasroot;
6906 int i;
6907
6908 TRACE(("Child shell %d\n", getpid()));
6909 wasroot = rootshell;
6910 rootshell = 0;
6911 closescript();
6912 INTON;
6913 clear_traps();
Eric Andersen2870d962001-07-02 17:27:21 +00006914#ifdef JOBS
6915 jobctl = 0; /* do job control only in root shell */
Eric Andersencb57d552001-06-28 07:25:16 +00006916 if (wasroot && mode != FORK_NOJOB && mflag) {
6917 if (jp == NULL || jp->nprocs == 0)
6918 pgrp = getpid();
6919 else
6920 pgrp = jp->ps[0].pid;
6921 setpgid(0, pgrp);
6922 if (mode == FORK_FG) {
6923 /*** this causes superfluous TIOCSPGRPS ***/
6924#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006925 if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006926 error("TIOCSPGRP failed, errno=%d", errno);
6927#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006928 if (tcsetpgrp(2, pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006929 error("tcsetpgrp failed, errno=%d", errno);
6930#endif
6931 }
6932 setsignal(SIGTSTP);
6933 setsignal(SIGTTOU);
6934 } else if (mode == FORK_BG) {
6935 ignoresig(SIGINT);
6936 ignoresig(SIGQUIT);
6937 if ((jp == NULL || jp->nprocs == 0) &&
6938 ! fd0_redirected_p ()) {
6939 close(0);
6940 if (open(devnull, O_RDONLY) != 0)
6941 error(nullerr, devnull);
6942 }
6943 }
6944#else
6945 if (mode == FORK_BG) {
6946 ignoresig(SIGINT);
6947 ignoresig(SIGQUIT);
6948 if ((jp == NULL || jp->nprocs == 0) &&
6949 ! fd0_redirected_p ()) {
6950 close(0);
6951 if (open(devnull, O_RDONLY) != 0)
6952 error(nullerr, devnull);
6953 }
6954 }
6955#endif
6956 for (i = njobs, p = jobtab ; --i >= 0 ; p++)
6957 if (p->used)
6958 freejob(p);
6959 if (wasroot && iflag) {
6960 setsignal(SIGINT);
6961 setsignal(SIGQUIT);
6962 setsignal(SIGTERM);
6963 }
6964 return pid;
6965 }
Eric Andersen62483552001-07-10 06:09:16 +00006966#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006967 if (rootshell && mode != FORK_NOJOB && mflag) {
6968 if (jp == NULL || jp->nprocs == 0)
6969 pgrp = pid;
6970 else
6971 pgrp = jp->ps[0].pid;
6972 setpgid(pid, pgrp);
6973 }
Eric Andersen62483552001-07-10 06:09:16 +00006974#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006975 if (mode == FORK_BG)
Eric Andersen2870d962001-07-02 17:27:21 +00006976 backgndpid = pid; /* set $! */
Eric Andersencb57d552001-06-28 07:25:16 +00006977 if (jp) {
6978 struct procstat *ps = &jp->ps[jp->nprocs++];
6979 ps->pid = pid;
6980 ps->status = -1;
6981 ps->cmd = nullstr;
6982 if (iflag && rootshell && n)
6983 ps->cmd = commandtext(n);
6984 }
6985 INTON;
6986 TRACE(("In parent shell: child = %d\n", pid));
6987 return pid;
6988}
6989
6990
6991
6992/*
6993 * Wait for job to finish.
6994 *
6995 * Under job control we have the problem that while a child process is
6996 * running interrupts generated by the user are sent to the child but not
6997 * to the shell. This means that an infinite loop started by an inter-
6998 * active user may be hard to kill. With job control turned off, an
6999 * interactive user may place an interactive program inside a loop. If
7000 * the interactive program catches interrupts, the user doesn't want
7001 * these interrupts to also abort the loop. The approach we take here
7002 * is to have the shell ignore interrupt signals while waiting for a
7003 * forground process to terminate, and then send itself an interrupt
7004 * signal if the child process was terminated by an interrupt signal.
7005 * Unfortunately, some programs want to do a bit of cleanup and then
7006 * exit on interrupt; unless these processes terminate themselves by
7007 * sending a signal to themselves (instead of calling exit) they will
7008 * confuse this approach.
7009 */
7010
7011static int
Eric Andersen62483552001-07-10 06:09:16 +00007012waitforjob(struct job *jp)
7013{
Eric Andersen2870d962001-07-02 17:27:21 +00007014#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007015 int mypgrp = getpgrp();
7016#endif
7017 int status;
7018 int st;
7019 struct sigaction act, oact;
7020
7021 INTOFF;
7022 intreceived = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00007023#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007024 if (!jobctl) {
7025#else
7026 if (!iflag) {
7027#endif
7028 sigaction(SIGINT, 0, &act);
7029 act.sa_handler = waitonint;
7030 sigaction(SIGINT, &act, &oact);
7031 }
7032 TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
7033 while (jp->state == 0) {
7034 dowait(1, jp);
7035 }
Eric Andersen2870d962001-07-02 17:27:21 +00007036#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007037 if (!jobctl) {
7038#else
7039 if (!iflag) {
7040#endif
7041 sigaction(SIGINT, &oact, 0);
7042 if (intreceived && trap[SIGINT]) kill(getpid(), SIGINT);
7043 }
Eric Andersen2870d962001-07-02 17:27:21 +00007044#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007045 if (jp->jobctl) {
7046#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00007047 if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007048 error("TIOCSPGRP failed, errno=%d\n", errno);
7049#else
Eric Andersen3102ac42001-07-06 04:26:23 +00007050 if (tcsetpgrp(2, mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007051 error("tcsetpgrp failed, errno=%d\n", errno);
7052#endif
7053 }
7054 if (jp->state == JOBSTOPPED)
7055 curjob = jp - jobtab + 1;
7056#endif
7057 status = jp->ps[jp->nprocs - 1].status;
7058 /* convert to 8 bits */
7059 if (WIFEXITED(status))
7060 st = WEXITSTATUS(status);
Eric Andersen2870d962001-07-02 17:27:21 +00007061#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007062 else if (WIFSTOPPED(status))
7063 st = WSTOPSIG(status) + 128;
7064#endif
7065 else
7066 st = WTERMSIG(status) + 128;
Eric Andersen2870d962001-07-02 17:27:21 +00007067#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007068 if (jp->jobctl) {
7069 /*
7070 * This is truly gross.
7071 * If we're doing job control, then we did a TIOCSPGRP which
7072 * caused us (the shell) to no longer be in the controlling
7073 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7074 * intuit from the subprocess exit status whether a SIGINT
7075 * occured, and if so interrupt ourselves. Yuck. - mycroft
7076 */
7077 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
7078 raise(SIGINT);
7079 }
Eric Andersen2870d962001-07-02 17:27:21 +00007080 if (jp->state == JOBDONE)
7081
Eric Andersencb57d552001-06-28 07:25:16 +00007082#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007083 freejob(jp);
7084 INTON;
7085 return st;
7086}
7087
7088
7089
7090/*
7091 * Wait for a process to terminate.
7092 */
7093
Eric Andersen62483552001-07-10 06:09:16 +00007094/*
7095 * Do a wait system call. If job control is compiled in, we accept
7096 * stopped processes. If block is zero, we return a value of zero
7097 * rather than blocking.
7098 *
7099 * System V doesn't have a non-blocking wait system call. It does
7100 * have a SIGCLD signal that is sent to a process when one of it's
7101 * children dies. The obvious way to use SIGCLD would be to install
7102 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7103 * was received, and have waitproc bump another counter when it got
7104 * the status of a process. Waitproc would then know that a wait
7105 * system call would not block if the two counters were different.
7106 * This approach doesn't work because if a process has children that
7107 * have not been waited for, System V will send it a SIGCLD when it
7108 * installs a signal handler for SIGCLD. What this means is that when
7109 * a child exits, the shell will be sent SIGCLD signals continuously
7110 * until is runs out of stack space, unless it does a wait call before
7111 * restoring the signal handler. The code below takes advantage of
7112 * this (mis)feature by installing a signal handler for SIGCLD and
7113 * then checking to see whether it was called. If there are any
7114 * children to be waited for, it will be.
7115 *
7116 */
7117
7118static inline int
7119waitproc(int block, int *status)
7120{
7121 int flags;
7122
7123 flags = 0;
7124#ifdef JOBS
7125 if (jobctl)
7126 flags |= WUNTRACED;
7127#endif
7128 if (block == 0)
7129 flags |= WNOHANG;
7130 return wait3(status, flags, (struct rusage *)NULL);
7131}
7132
Eric Andersencb57d552001-06-28 07:25:16 +00007133static int
Eric Andersen62483552001-07-10 06:09:16 +00007134dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00007135{
7136 int pid;
7137 int status;
7138 struct procstat *sp;
7139 struct job *jp;
7140 struct job *thisjob;
7141 int done;
7142 int stopped;
7143 int core;
7144 int sig;
7145
7146 TRACE(("dowait(%d) called\n", block));
7147 do {
7148 pid = waitproc(block, &status);
7149 TRACE(("wait returns %d, status=%d\n", pid, status));
7150 } while (!(block & 2) && pid == -1 && errno == EINTR);
7151 if (pid <= 0)
7152 return pid;
7153 INTOFF;
7154 thisjob = NULL;
7155 for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
7156 if (jp->used) {
7157 done = 1;
7158 stopped = 1;
7159 for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
7160 if (sp->pid == -1)
7161 continue;
7162 if (sp->pid == pid) {
7163 TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
7164 sp->status = status;
7165 thisjob = jp;
7166 }
7167 if (sp->status == -1)
7168 stopped = 0;
7169 else if (WIFSTOPPED(sp->status))
7170 done = 0;
7171 }
Eric Andersen2870d962001-07-02 17:27:21 +00007172 if (stopped) { /* stopped or done */
Eric Andersencb57d552001-06-28 07:25:16 +00007173 int state = done? JOBDONE : JOBSTOPPED;
7174 if (jp->state != state) {
7175 TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
7176 jp->state = state;
Eric Andersen2870d962001-07-02 17:27:21 +00007177#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007178 if (done && curjob == jp - jobtab + 1)
Eric Andersen2870d962001-07-02 17:27:21 +00007179 curjob = 0; /* no current job */
Eric Andersencb57d552001-06-28 07:25:16 +00007180#endif
7181 }
7182 }
7183 }
7184 }
7185 INTON;
7186 if (! rootshell || ! iflag || (job && thisjob == job)) {
7187 core = WCOREDUMP(status);
Eric Andersen2870d962001-07-02 17:27:21 +00007188#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007189 if (WIFSTOPPED(status)) sig = WSTOPSIG(status);
7190 else
7191#endif
7192 if (WIFEXITED(status)) sig = 0;
7193 else sig = WTERMSIG(status);
7194
7195 if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
7196 if (thisjob != job)
Eric Andersen3102ac42001-07-06 04:26:23 +00007197 out2fmt("%d: ", pid);
Eric Andersen2870d962001-07-02 17:27:21 +00007198#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007199 if (sig == SIGTSTP && rootshell && iflag)
Eric Andersen3102ac42001-07-06 04:26:23 +00007200 out2fmt("%%%ld ",
Eric Andersencb57d552001-06-28 07:25:16 +00007201 (long)(job - jobtab + 1));
7202#endif
7203 if (sig < NSIG && sys_siglist[sig])
7204 out2str(sys_siglist[sig]);
7205 else
Eric Andersen3102ac42001-07-06 04:26:23 +00007206 out2fmt("Signal %d", sig);
Eric Andersencb57d552001-06-28 07:25:16 +00007207 if (core)
7208 out2str(" - core dumped");
7209 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00007210 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00007211 TRACE(("Not printing status: status=%d, sig=%d\n",
Eric Andersencb57d552001-06-28 07:25:16 +00007212 status, sig));
7213 }
7214 } else {
7215 TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
7216 if (thisjob)
7217 thisjob->changed = 1;
7218 }
7219 return pid;
7220}
7221
7222
7223
Eric Andersencb57d552001-06-28 07:25:16 +00007224
7225/*
7226 * return 1 if there are stopped jobs, otherwise 0
7227 */
Eric Andersencb57d552001-06-28 07:25:16 +00007228static int
Eric Andersen2870d962001-07-02 17:27:21 +00007229stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007230{
7231 int jobno;
7232 struct job *jp;
7233
7234 if (job_warning)
7235 return (0);
7236 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
7237 if (jp->used == 0)
7238 continue;
7239 if (jp->state == JOBSTOPPED) {
7240 out2str("You have stopped jobs.\n");
7241 job_warning = 2;
7242 return (1);
7243 }
7244 }
7245
7246 return (0);
7247}
7248
7249/*
7250 * Return a string identifying a command (to be printed by the
7251 * jobs command.
7252 */
7253
7254static char *cmdnextc;
7255static int cmdnleft;
Eric Andersen2870d962001-07-02 17:27:21 +00007256#define MAXCMDTEXT 200
Eric Andersencb57d552001-06-28 07:25:16 +00007257
Eric Andersen2870d962001-07-02 17:27:21 +00007258static void
7259cmdputs(const char *s)
7260{
7261 const char *p;
7262 char *q;
7263 char c;
7264 int subtype = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007265
Eric Andersen2870d962001-07-02 17:27:21 +00007266 if (cmdnleft <= 0)
7267 return;
7268 p = s;
7269 q = cmdnextc;
7270 while ((c = *p++) != '\0') {
7271 if (c == CTLESC)
7272 *q++ = *p++;
7273 else if (c == CTLVAR) {
7274 *q++ = '$';
7275 if (--cmdnleft > 0)
7276 *q++ = '{';
7277 subtype = *p++;
7278 } else if (c == '=' && subtype != 0) {
7279 *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
7280 subtype = 0;
7281 } else if (c == CTLENDVAR) {
7282 *q++ = '}';
7283 } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
7284 cmdnleft++; /* ignore it */
7285 else
7286 *q++ = c;
7287 if (--cmdnleft <= 0) {
7288 *q++ = '.';
7289 *q++ = '.';
7290 *q++ = '.';
7291 break;
7292 }
7293 }
7294 cmdnextc = q;
Eric Andersencb57d552001-06-28 07:25:16 +00007295}
7296
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007297//#define CMDTXT_TABLE
7298#ifdef CMDTXT_TABLE
7299/*
7300 * To collect a lot of redundant code in cmdtxt() case statements, we
7301 * implement a mini language here. Each type of node struct has an
7302 * associated instruction sequence that operates on its members via
7303 * their offsets. The instruction are pack in unsigned chars with
7304 * format IIDDDDDE where the bits are
7305 * I : part of the instruction opcode, which are
7306 * 00 : member is a pointer to another node -- process it recursively
7307 * 40 : member is a pointer to a char string -- output it
7308 * 80 : output the string whose index is stored in the data field
7309 * CC : flag signaling that this case needs external processing
7310 * D : data - either the (shifted) index of a fixed string to output or
7311 * the actual offset of the member to operate on in the struct
7312 * (since we assume bit 0 is set, the offset is not shifted)
7313 * E : flag signaling end of instruction sequence
7314 *
7315 * WARNING: In order to handle larger offsets for 64bit archs, this code
7316 * assumes that no offset can be an odd number and stores the
7317 * end-of-instructions flag in bit 0.
7318 */
Eric Andersencb57d552001-06-28 07:25:16 +00007319
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007320#define CMDTXT_NOMORE 0x01 /* NOTE: no offset should be odd */
7321#define CMDTXT_CHARPTR 0x40
7322#define CMDTXT_STRING 0x80
7323#define CMDTXT_SPECIAL 0xC0
7324#define CMDTXT_OFFSETMASK 0x3E
7325
7326static const char * const cmdtxt_strings[] = {
7327 /* 0 1 2 3 4 5 6 7 */
7328 "; ", "(", ")", " && ", " || ", "if ", "; then ", "...",
7329 /* 8 9 10 11 12 13 */
7330 "while ", "; do ", "; done", "until ", "for ", " in ...",
7331 /* 14 15 16 17 */
7332 "case ", "???", "() ...", "<<..."
7333};
7334
7335static const char * const redir_strings[] = {
7336 ">", "<", "<>", ">>", ">|", ">&", "<&"
7337};
7338
7339static const unsigned char cmdtxt_ops[] = {
7340#define CMDTXT_NSEMI 0
7341 offsetof(union node, nbinary.ch1),
7342 0|CMDTXT_STRING,
7343 offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7344#define CMDTXT_NCMD (CMDTXT_NSEMI + 3)
7345#define CMDTXT_NPIPE (CMDTXT_NCMD)
7346#define CMDTXT_NCASE (CMDTXT_NCMD)
7347#define CMDTXT_NTO (CMDTXT_NCMD)
7348#define CMDTXT_NFROM (CMDTXT_NCMD)
7349#define CMDTXT_NFROMTO (CMDTXT_NCMD)
7350#define CMDTXT_NAPPEND (CMDTXT_NCMD)
7351#define CMDTXT_NTOOV (CMDTXT_NCMD)
7352#define CMDTXT_NTOFD (CMDTXT_NCMD)
7353#define CMDTXT_NFROMFD (CMDTXT_NCMD)
7354 CMDTXT_SPECIAL,
7355#define CMDTXT_NREDIR (CMDTXT_NPIPE + 1)
7356#define CMDTXT_NBACKGND (CMDTXT_NREDIR)
7357 offsetof(union node, nredir.n)|CMDTXT_NOMORE,
7358#define CMDTXT_NSUBSHELL (CMDTXT_NBACKGND + 1)
7359 (1*2)|CMDTXT_STRING,
7360 offsetof(union node, nredir.n),
7361 (2*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7362#define CMDTXT_NAND (CMDTXT_NSUBSHELL + 3)
7363 offsetof(union node, nbinary.ch1),
7364 (3*2)|CMDTXT_STRING,
7365 offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7366#define CMDTXT_NOR (CMDTXT_NAND + 3)
7367 offsetof(union node, nbinary.ch1),
7368 (4*2)|CMDTXT_STRING,
7369 offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7370#define CMDTXT_NIF (CMDTXT_NOR + 3)
7371 (5*2)|CMDTXT_STRING,
7372 offsetof(union node, nif.test),
7373 (6*2)|CMDTXT_STRING,
7374 offsetof(union node, nif.ifpart),
7375 (7*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7376#define CMDTXT_NWHILE (CMDTXT_NIF + 5)
7377 (8*2)|CMDTXT_STRING,
7378 offsetof(union node, nbinary.ch1),
7379 (9*2)|CMDTXT_STRING,
7380 offsetof(union node, nbinary.ch2),
7381 (10*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7382#define CMDTXT_NUNTIL (CMDTXT_NWHILE + 5)
7383 (11*2)|CMDTXT_STRING,
7384 offsetof(union node, nbinary.ch1),
7385 (9*2)|CMDTXT_STRING,
7386 offsetof(union node, nbinary.ch2),
7387 (10*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7388#define CMDTXT_NFOR (CMDTXT_NUNTIL + 5)
7389 (12*2)|CMDTXT_STRING,
7390 offsetof(union node, nfor.var)|CMDTXT_CHARPTR,
7391 (13*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7392#define CMDTXT_NCLIST (CMDTXT_NFOR + 3) /* TODO: IS THIS CORRECT??? */
7393#define CMDTXT_NNOT (CMDTXT_NCLIST) /* TODO: IS THIS CORRECT??? */
7394 (15*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7395#define CMDTXT_NDEFUN (CMDTXT_NCLIST + 1)
7396 offsetof(union node, narg.text)|CMDTXT_CHARPTR,
7397 (16*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7398#define CMDTXT_NARG (CMDTXT_NDEFUN + 2)
7399 offsetof(union node, narg.text)|CMDTXT_CHARPTR|CMDTXT_NOMORE,
7400#define CMDTXT_NHERE (CMDTXT_NARG + 1)
7401#define CMDTXT_NXHERE (CMDTXT_NHERE)
7402 (17*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7403};
7404
7405#if CMDTXT_NXHERE != 36
7406#error CMDTXT_NXHERE
7407#endif
7408
7409static const unsigned char cmdtxt_ops_index[26] = {
7410 CMDTXT_NSEMI,
7411 CMDTXT_NCMD,
7412 CMDTXT_NPIPE,
7413 CMDTXT_NREDIR,
7414 CMDTXT_NBACKGND,
7415 CMDTXT_NSUBSHELL,
7416 CMDTXT_NAND,
7417 CMDTXT_NOR,
7418 CMDTXT_NIF,
7419 CMDTXT_NWHILE,
7420 CMDTXT_NUNTIL,
7421 CMDTXT_NFOR,
7422 CMDTXT_NCASE,
7423 CMDTXT_NCLIST,
7424 CMDTXT_NDEFUN,
7425 CMDTXT_NARG,
7426 CMDTXT_NTO,
7427 CMDTXT_NFROM,
7428 CMDTXT_NFROMTO,
7429 CMDTXT_NAPPEND,
7430 CMDTXT_NTOOV,
7431 CMDTXT_NTOFD,
7432 CMDTXT_NFROMFD,
7433 CMDTXT_NHERE,
7434 CMDTXT_NXHERE,
7435 CMDTXT_NNOT,
7436};
7437
7438static void
7439cmdtxt(const union node *n)
7440{
7441 const char *p;
7442
7443 if (n == NULL)
7444 return;
7445
7446 p = cmdtxt_ops + (int) cmdtxt_ops_index[n->type];
7447 if ((*p & CMDTXT_SPECIAL) != CMDTXT_SPECIAL) { /* normal case */
7448 do {
7449 if (*p & CMDTXT_STRING) { /* output fixed string */
7450 cmdputs(cmdtxt_strings[((int)(*p & CMDTXT_OFFSETMASK) >> 1)]);
7451 } else if (*p & CMDTXT_CHARPTR) { /* output dynamic string */
7452 cmdputs(((const char *) n) + ((int)(*p & CMDTXT_OFFSETMASK)));
7453 } else { /* output field */
7454 cmdtxt((const union node *)
7455 (((const char *) n) + ((int)(*p & CMDTXT_OFFSETMASK))));
7456 }
7457 } while (!(*p++ & CMDTXT_NOMORE));
7458 } else if (n->type == NCMD) {
7459 union node *np;
7460 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7461 cmdtxt(np);
7462 if (np->narg.next)
7463 cmdputs(spcstr);
7464 }
7465 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7466 cmdputs(spcstr);
7467 cmdtxt(np);
7468 }
7469 } else if (n->type == NPIPE) {
7470 struct nodelist *lp;
7471 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7472 cmdtxt(lp->n);
7473 if (lp->next)
7474 cmdputs(" | ");
7475 }
7476 } else if (n->type == NCASE) {
7477 cmdputs(cmdtxt_strings[14]);
7478 cmdputs(n->ncase.expr->narg.text);
7479 cmdputs(cmdtxt_strings[13]);
7480 } else {
7481#if (NTO != 16) || (NFROM != 17) || (NFROMTO != 18) || (NAPPEND != 19) || (NTOOV != 20) || (NTOFD != 21) || (NFROMFD != 22)
7482#error Assumption violated regarding range and ordering of NTO ... NFROMFD!
7483#endif
7484 char s[2];
7485
7486#ifdef DEBUG
7487 assert((n->type >= NTO) && (n->type <= NFROMFD));
7488#endif
7489
7490 p = redir_strings[n->type - NTO];
7491 if (n->nfile.fd != ('>' == *p)) {
7492 s[0] = n->nfile.fd + '0';
7493 s[1] = '\0';
7494 cmdputs(s);
7495 }
7496 cmdputs(p);
7497 if (n->type >= NTOFD) {
7498 s[0] = n->ndup.dupfd + '0';
7499 s[1] = '\0';
7500 cmdputs(s);
7501 } else {
7502 cmdtxt(n->nfile.fname);
7503 }
7504 }
7505}
7506#else /* CMDTXT_TABLE */
Eric Andersencb57d552001-06-28 07:25:16 +00007507static void
Eric Andersen2870d962001-07-02 17:27:21 +00007508cmdtxt(const union node *n)
7509{
Eric Andersencb57d552001-06-28 07:25:16 +00007510 union node *np;
7511 struct nodelist *lp;
7512 const char *p;
7513 int i;
7514 char s[2];
7515
7516 if (n == NULL)
7517 return;
7518 switch (n->type) {
7519 case NSEMI:
7520 cmdtxt(n->nbinary.ch1);
7521 cmdputs("; ");
7522 cmdtxt(n->nbinary.ch2);
7523 break;
7524 case NAND:
7525 cmdtxt(n->nbinary.ch1);
7526 cmdputs(" && ");
7527 cmdtxt(n->nbinary.ch2);
7528 break;
7529 case NOR:
7530 cmdtxt(n->nbinary.ch1);
7531 cmdputs(" || ");
7532 cmdtxt(n->nbinary.ch2);
7533 break;
7534 case NPIPE:
7535 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7536 cmdtxt(lp->n);
7537 if (lp->next)
7538 cmdputs(" | ");
7539 }
7540 break;
7541 case NSUBSHELL:
7542 cmdputs("(");
7543 cmdtxt(n->nredir.n);
7544 cmdputs(")");
7545 break;
7546 case NREDIR:
7547 case NBACKGND:
7548 cmdtxt(n->nredir.n);
7549 break;
7550 case NIF:
7551 cmdputs("if ");
7552 cmdtxt(n->nif.test);
7553 cmdputs("; then ");
7554 cmdtxt(n->nif.ifpart);
7555 cmdputs("...");
7556 break;
7557 case NWHILE:
7558 cmdputs("while ");
7559 goto until;
7560 case NUNTIL:
7561 cmdputs("until ");
7562until:
7563 cmdtxt(n->nbinary.ch1);
7564 cmdputs("; do ");
7565 cmdtxt(n->nbinary.ch2);
7566 cmdputs("; done");
7567 break;
7568 case NFOR:
7569 cmdputs("for ");
7570 cmdputs(n->nfor.var);
7571 cmdputs(" in ...");
7572 break;
7573 case NCASE:
7574 cmdputs("case ");
7575 cmdputs(n->ncase.expr->narg.text);
7576 cmdputs(" in ...");
7577 break;
7578 case NDEFUN:
7579 cmdputs(n->narg.text);
7580 cmdputs("() ...");
7581 break;
7582 case NCMD:
7583 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7584 cmdtxt(np);
7585 if (np->narg.next)
7586 cmdputs(spcstr);
7587 }
7588 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7589 cmdputs(spcstr);
7590 cmdtxt(np);
7591 }
7592 break;
7593 case NARG:
7594 cmdputs(n->narg.text);
7595 break;
7596 case NTO:
7597 p = ">"; i = 1; goto redir;
7598 case NAPPEND:
7599 p = ">>"; i = 1; goto redir;
7600 case NTOFD:
7601 p = ">&"; i = 1; goto redir;
7602 case NTOOV:
7603 p = ">|"; i = 1; goto redir;
7604 case NFROM:
7605 p = "<"; i = 0; goto redir;
7606 case NFROMFD:
7607 p = "<&"; i = 0; goto redir;
7608 case NFROMTO:
7609 p = "<>"; i = 0; goto redir;
7610redir:
7611 if (n->nfile.fd != i) {
7612 s[0] = n->nfile.fd + '0';
7613 s[1] = '\0';
7614 cmdputs(s);
7615 }
7616 cmdputs(p);
7617 if (n->type == NTOFD || n->type == NFROMFD) {
7618 s[0] = n->ndup.dupfd + '0';
7619 s[1] = '\0';
7620 cmdputs(s);
7621 } else {
7622 cmdtxt(n->nfile.fname);
7623 }
7624 break;
7625 case NHERE:
7626 case NXHERE:
7627 cmdputs("<<...");
7628 break;
7629 default:
7630 cmdputs("???");
7631 break;
7632 }
7633}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007634#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007635
Eric Andersen2870d962001-07-02 17:27:21 +00007636static char *
7637commandtext(const union node *n)
7638{
7639 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007640
Eric Andersen2870d962001-07-02 17:27:21 +00007641 cmdnextc = name = ckmalloc(MAXCMDTEXT);
7642 cmdnleft = MAXCMDTEXT - 4;
7643 cmdtxt(n);
7644 *cmdnextc = '\0';
7645 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00007646}
7647
Eric Andersen2870d962001-07-02 17:27:21 +00007648
Eric Andersencb57d552001-06-28 07:25:16 +00007649static void waitonint(int sig) {
7650 intreceived = 1;
7651 return;
7652}
Eric Andersencb57d552001-06-28 07:25:16 +00007653/*
7654 * Routines to check for mail. (Perhaps make part of main.c?)
7655 */
7656
7657
7658#define MAXMBOXES 10
7659
7660
Eric Andersen2870d962001-07-02 17:27:21 +00007661static int nmboxes; /* number of mailboxes */
7662static time_t mailtime[MAXMBOXES]; /* times of mailboxes */
Eric Andersencb57d552001-06-28 07:25:16 +00007663
7664
7665
7666/*
7667 * Print appropriate message(s) if mail has arrived. If the argument is
7668 * nozero, then the value of MAIL has changed, so we just update the
7669 * values.
7670 */
7671
7672static void
Eric Andersen2870d962001-07-02 17:27:21 +00007673chkmail(int silent)
Eric Andersencb57d552001-06-28 07:25:16 +00007674{
7675 int i;
7676 const char *mpath;
7677 char *p;
7678 char *q;
7679 struct stackmark smark;
7680 struct stat statb;
7681
7682 if (silent)
7683 nmboxes = 10;
7684 if (nmboxes == 0)
7685 return;
7686 setstackmark(&smark);
7687 mpath = mpathset()? mpathval() : mailval();
7688 for (i = 0 ; i < nmboxes ; i++) {
7689 p = padvance(&mpath, nullstr);
7690 if (p == NULL)
7691 break;
7692 if (*p == '\0')
7693 continue;
7694 for (q = p ; *q ; q++);
7695#ifdef DEBUG
7696 if (q[-1] != '/')
7697 abort();
7698#endif
Eric Andersen2870d962001-07-02 17:27:21 +00007699 q[-1] = '\0'; /* delete trailing '/' */
Eric Andersencb57d552001-06-28 07:25:16 +00007700 if (stat(p, &statb) < 0)
7701 statb.st_size = 0;
7702 if (statb.st_size > mailtime[i] && ! silent) {
Eric Andersen3102ac42001-07-06 04:26:23 +00007703 out2fmt(snlfmt,
7704 pathopt? pathopt : "you have mail");
Eric Andersencb57d552001-06-28 07:25:16 +00007705 }
7706 mailtime[i] = statb.st_size;
Eric Andersencb57d552001-06-28 07:25:16 +00007707 }
7708 nmboxes = i;
7709 popstackmark(&smark);
7710}
Eric Andersencb57d552001-06-28 07:25:16 +00007711
7712#define PROFILE 0
7713
Eric Andersencb57d552001-06-28 07:25:16 +00007714#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007715static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007716extern int etext();
7717#endif
7718
Eric Andersen2870d962001-07-02 17:27:21 +00007719static void read_profile (const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007720static void cmdloop (int);
7721static void options (int);
Eric Andersen2870d962001-07-02 17:27:21 +00007722static void setoption (int, int);
7723static void procargs (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00007724
Eric Andersen2870d962001-07-02 17:27:21 +00007725
Eric Andersencb57d552001-06-28 07:25:16 +00007726/*
7727 * Main routine. We initialize things, parse the arguments, execute
7728 * profiles if we're a login shell, and then call cmdloop to execute
7729 * commands. The setjmp call sets up the location to jump to when an
7730 * exception occurs. When an exception occurs the variable "state"
7731 * is used to figure out how far we had gotten.
7732 */
7733
7734int
Matt Kraai2d91deb2001-08-01 17:21:35 +00007735ash_main(argc, argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007736 int argc;
7737 char **argv;
7738{
7739 struct jmploc jmploc;
7740 struct stackmark smark;
7741 volatile int state;
Eric Andersen62483552001-07-10 06:09:16 +00007742 const char *shinit;
Eric Andersencb57d552001-06-28 07:25:16 +00007743
Eric Andersencb57d552001-06-28 07:25:16 +00007744 BLTINCMD = find_builtin("builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00007745 EXECCMD = find_builtin("exec");
7746 EVALCMD = find_builtin("eval");
7747
Eric Andersen1c039232001-07-07 00:05:55 +00007748#ifndef BB_FEATURE_SH_FANCY_PROMPT
7749 unsetenv("PS1");
7750 unsetenv("PS2");
7751#endif
7752
Eric Andersencb57d552001-06-28 07:25:16 +00007753#if PROFILE
7754 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7755#endif
7756#if defined(linux) || defined(__GNU__)
7757 signal(SIGCHLD, SIG_DFL);
7758#endif
7759 state = 0;
7760 if (setjmp(jmploc.loc)) {
7761 INTOFF;
7762 /*
7763 * When a shell procedure is executed, we raise the
7764 * exception EXSHELLPROC to clean up before executing
7765 * the shell procedure.
7766 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007767 if (exception == EXSHELLPROC) {
Eric Andersencb57d552001-06-28 07:25:16 +00007768 rootpid = getpid();
7769 rootshell = 1;
7770 minusc = NULL;
7771 state = 3;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007772 } else {
7773 if (exception == EXEXEC) {
7774 exitstatus = exerrno;
7775 } else if (exception == EXERROR) {
7776 exitstatus = 2;
7777 }
Eric Andersencb57d552001-06-28 07:25:16 +00007778 if (state == 0 || iflag == 0 || ! rootshell)
7779 exitshell(exitstatus);
7780 }
7781 reset();
Eric Andersen2870d962001-07-02 17:27:21 +00007782 if (exception == EXINT) {
Eric Andersencb57d552001-06-28 07:25:16 +00007783 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00007784 }
7785 popstackmark(&smark);
Eric Andersen2870d962001-07-02 17:27:21 +00007786 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007787 if (state == 1)
7788 goto state1;
7789 else if (state == 2)
7790 goto state2;
7791 else if (state == 3)
7792 goto state3;
7793 else
7794 goto state4;
7795 }
7796 handler = &jmploc;
7797#ifdef DEBUG
7798 opentrace();
7799 trputs("Shell args: "); trargs(argv);
7800#endif
7801 rootpid = getpid();
7802 rootshell = 1;
7803 init();
7804 setstackmark(&smark);
7805 procargs(argc, argv);
7806 if (argv[0] && argv[0][0] == '-') {
7807 state = 1;
7808 read_profile("/etc/profile");
7809state1:
7810 state = 2;
7811 read_profile(".profile");
7812 }
7813state2:
7814 state = 3;
7815#ifndef linux
7816 if (getuid() == geteuid() && getgid() == getegid()) {
7817#endif
7818 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7819 state = 3;
7820 read_profile(shinit);
7821 }
7822#ifndef linux
7823 }
7824#endif
7825state3:
7826 state = 4;
7827 if (sflag == 0 || minusc) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007828 static const char sigs[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00007829 SIGINT, SIGQUIT, SIGHUP,
Eric Andersencb57d552001-06-28 07:25:16 +00007830#ifdef SIGTSTP
7831 SIGTSTP,
7832#endif
7833 SIGPIPE
7834 };
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007835#define SIGSSIZE ((sizeof(sigs)/sizeof(sigs[0])) - 1) /* trailing nul */
Eric Andersencb57d552001-06-28 07:25:16 +00007836 int i;
7837
7838 for (i = 0; i < SIGSSIZE; i++)
7839 setsignal(sigs[i]);
7840 }
7841
7842 if (minusc)
7843 evalstring(minusc, 0);
7844
7845 if (sflag || minusc == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00007846state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007847 cmdloop(1);
7848 }
7849#if PROFILE
7850 monitor(0);
7851#endif
7852 exitshell(exitstatus);
7853 /* NOTREACHED */
7854}
7855
7856
7857/*
7858 * Read and execute commands. "Top" is nonzero for the top level command
7859 * loop; it turns on prompting if the shell is interactive.
7860 */
7861
7862static void
Eric Andersen2870d962001-07-02 17:27:21 +00007863cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00007864{
7865 union node *n;
7866 struct stackmark smark;
7867 int inter;
7868 int numeof = 0;
7869
7870 TRACE(("cmdloop(%d) called\n", top));
7871 setstackmark(&smark);
7872 for (;;) {
7873 if (pendingsigs)
7874 dotrap();
7875 inter = 0;
7876 if (iflag && top) {
7877 inter++;
7878 showjobs(1);
7879 chkmail(0);
Eric Andersen3102ac42001-07-06 04:26:23 +00007880 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00007881 }
7882 n = parsecmd(inter);
7883 /* showtree(n); DEBUG */
7884 if (n == NEOF) {
7885 if (!top || numeof >= 50)
7886 break;
7887 if (!stoppedjobs()) {
7888 if (!Iflag)
7889 break;
7890 out2str("\nUse \"exit\" to leave shell.\n");
7891 }
7892 numeof++;
7893 } else if (n != NULL && nflag == 0) {
7894 job_warning = (job_warning == 2) ? 1 : 0;
7895 numeof = 0;
7896 evaltree(n, 0);
7897 }
7898 popstackmark(&smark);
7899 setstackmark(&smark);
7900 if (evalskip == SKIPFILE) {
7901 evalskip = 0;
7902 break;
7903 }
7904 }
7905 popstackmark(&smark);
7906}
7907
7908
7909
7910/*
7911 * Read /etc/profile or .profile. Return on error.
7912 */
7913
7914static void
7915read_profile(name)
7916 const char *name;
7917{
7918 int fd;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007919 int xflag_save;
7920 int vflag_save;
Eric Andersencb57d552001-06-28 07:25:16 +00007921
7922 INTOFF;
7923 if ((fd = open(name, O_RDONLY)) >= 0)
7924 setinputfd(fd, 1);
7925 INTON;
7926 if (fd < 0)
7927 return;
7928 /* -q turns off -x and -v just when executing init files */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007929 /* Note: Might do a little redundant work, but reduces code size. */
7930 xflag_save = xflag;
7931 vflag_save = vflag;
Eric Andersencb57d552001-06-28 07:25:16 +00007932 if (qflag) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007933 vflag = xflag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007934 }
7935 cmdloop(0);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007936 xflag = xflag_save;
7937 vflag = vflag_save;
Eric Andersencb57d552001-06-28 07:25:16 +00007938 popfile();
7939}
7940
7941
7942
7943/*
7944 * Read a file containing shell functions.
7945 */
7946
7947static void
Eric Andersen2870d962001-07-02 17:27:21 +00007948readcmdfile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00007949{
7950 int fd;
7951
7952 INTOFF;
7953 if ((fd = open(name, O_RDONLY)) >= 0)
7954 setinputfd(fd, 1);
7955 else
7956 error("Can't open %s", name);
7957 INTON;
7958 cmdloop(0);
7959 popfile();
7960}
7961
7962
7963
7964/*
7965 * Take commands from a file. To be compatable we should do a path
7966 * search for the file, which is necessary to find sub-commands.
7967 */
7968
7969
Eric Andersen62483552001-07-10 06:09:16 +00007970static inline char *
Eric Andersencb57d552001-06-28 07:25:16 +00007971find_dot_file(mybasename)
7972 char *mybasename;
7973{
7974 char *fullname;
7975 const char *path = pathval();
7976 struct stat statb;
7977
7978 /* don't try this for absolute or relative paths */
7979 if (strchr(mybasename, '/'))
7980 return mybasename;
7981
7982 while ((fullname = padvance(&path, mybasename)) != NULL) {
7983 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
7984 /*
7985 * Don't bother freeing here, since it will
7986 * be freed by the caller.
7987 */
7988 return fullname;
7989 }
7990 stunalloc(fullname);
7991 }
7992
7993 /* not found in the PATH */
7994 error("%s: not found", mybasename);
7995 /* NOTREACHED */
7996}
7997
7998static int
7999dotcmd(argc, argv)
8000 int argc;
8001 char **argv;
8002{
8003 struct strlist *sp;
8004 exitstatus = 0;
8005
8006 for (sp = cmdenviron; sp ; sp = sp->next)
8007 setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
8008
Eric Andersen2870d962001-07-02 17:27:21 +00008009 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00008010 char *fullname;
8011 struct stackmark smark;
8012
8013 setstackmark(&smark);
8014 fullname = find_dot_file(argv[1]);
8015 setinputfile(fullname, 1);
8016 commandname = fullname;
8017 cmdloop(0);
8018 popfile();
8019 popstackmark(&smark);
8020 }
8021 return exitstatus;
8022}
8023
8024
8025static int
8026exitcmd(argc, argv)
8027 int argc;
8028 char **argv;
8029{
8030 if (stoppedjobs())
8031 return 0;
8032 if (argc > 1)
8033 exitstatus = number(argv[1]);
8034 else
8035 exitstatus = oexitstatus;
8036 exitshell(exitstatus);
8037 /* NOTREACHED */
8038}
Eric Andersen62483552001-07-10 06:09:16 +00008039
Eric Andersen2870d962001-07-02 17:27:21 +00008040static pointer
8041stalloc(int nbytes)
Eric Andersencb57d552001-06-28 07:25:16 +00008042{
8043 char *p;
8044
8045 nbytes = ALIGN(nbytes);
8046 if (nbytes > stacknleft) {
8047 int blocksize;
8048 struct stack_block *sp;
8049
8050 blocksize = nbytes;
8051 if (blocksize < MINSIZE)
8052 blocksize = MINSIZE;
8053 INTOFF;
8054 sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
8055 sp->prev = stackp;
8056 stacknxt = sp->space;
8057 stacknleft = blocksize;
8058 stackp = sp;
8059 INTON;
8060 }
8061 p = stacknxt;
8062 stacknxt += nbytes;
8063 stacknleft -= nbytes;
8064 return p;
8065}
8066
8067
8068static void
Eric Andersen2870d962001-07-02 17:27:21 +00008069stunalloc(pointer p)
8070{
Eric Andersencb57d552001-06-28 07:25:16 +00008071#ifdef DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +00008072 if (p == NULL) { /*DEBUG */
Eric Andersencb57d552001-06-28 07:25:16 +00008073 write(2, "stunalloc\n", 10);
8074 abort();
8075 }
8076#endif
8077 if (!(stacknxt >= (char *)p && (char *)p >= stackp->space)) {
8078 p = stackp->space;
8079 }
8080 stacknleft += stacknxt - (char *)p;
8081 stacknxt = p;
8082}
8083
8084
Eric Andersencb57d552001-06-28 07:25:16 +00008085static void
Eric Andersen2870d962001-07-02 17:27:21 +00008086setstackmark(struct stackmark *mark)
8087{
Eric Andersencb57d552001-06-28 07:25:16 +00008088 mark->stackp = stackp;
8089 mark->stacknxt = stacknxt;
8090 mark->stacknleft = stacknleft;
8091 mark->marknext = markp;
8092 markp = mark;
8093}
8094
8095
8096static void
Eric Andersen2870d962001-07-02 17:27:21 +00008097popstackmark(struct stackmark *mark)
8098{
Eric Andersencb57d552001-06-28 07:25:16 +00008099 struct stack_block *sp;
8100
8101 INTOFF;
8102 markp = mark->marknext;
8103 while (stackp != mark->stackp) {
8104 sp = stackp;
8105 stackp = sp->prev;
8106 ckfree(sp);
8107 }
8108 stacknxt = mark->stacknxt;
8109 stacknleft = mark->stacknleft;
8110 INTON;
8111}
8112
8113
8114/*
8115 * When the parser reads in a string, it wants to stick the string on the
8116 * stack and only adjust the stack pointer when it knows how big the
8117 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8118 * of space on top of the stack and stackblocklen returns the length of
8119 * this block. Growstackblock will grow this space by at least one byte,
8120 * possibly moving it (like realloc). Grabstackblock actually allocates the
8121 * part of the block that has been used.
8122 */
8123
8124static void
Eric Andersen2870d962001-07-02 17:27:21 +00008125growstackblock(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00008126 char *p;
8127 int newlen = ALIGN(stacknleft * 2 + 100);
8128 char *oldspace = stacknxt;
8129 int oldlen = stacknleft;
8130 struct stack_block *sp;
8131 struct stack_block *oldstackp;
8132
8133 if (stacknxt == stackp->space && stackp != &stackbase) {
8134 INTOFF;
8135 oldstackp = stackp;
8136 sp = stackp;
8137 stackp = sp->prev;
8138 sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen);
8139 sp->prev = stackp;
8140 stackp = sp;
8141 stacknxt = sp->space;
8142 stacknleft = newlen;
8143 {
8144 /* Stack marks pointing to the start of the old block
Eric Andersen2870d962001-07-02 17:27:21 +00008145 * must be relocated to point to the new block
Eric Andersencb57d552001-06-28 07:25:16 +00008146 */
8147 struct stackmark *xmark;
8148 xmark = markp;
8149 while (xmark != NULL && xmark->stackp == oldstackp) {
8150 xmark->stackp = stackp;
8151 xmark->stacknxt = stacknxt;
8152 xmark->stacknleft = stacknleft;
8153 xmark = xmark->marknext;
8154 }
8155 }
8156 INTON;
8157 } else {
8158 p = stalloc(newlen);
8159 memcpy(p, oldspace, oldlen);
Eric Andersen2870d962001-07-02 17:27:21 +00008160 stacknxt = p; /* free the space */
8161 stacknleft += newlen; /* we just allocated */
Eric Andersencb57d552001-06-28 07:25:16 +00008162 }
8163}
8164
8165
8166
Eric Andersen2870d962001-07-02 17:27:21 +00008167static inline void
8168grabstackblock(int len)
Eric Andersencb57d552001-06-28 07:25:16 +00008169{
8170 len = ALIGN(len);
8171 stacknxt += len;
8172 stacknleft -= len;
8173}
8174
8175
8176
8177/*
8178 * The following routines are somewhat easier to use that the above.
8179 * The user declares a variable of type STACKSTR, which may be declared
8180 * to be a register. The macro STARTSTACKSTR initializes things. Then
8181 * the user uses the macro STPUTC to add characters to the string. In
8182 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8183 * grown as necessary. When the user is done, she can just leave the
8184 * string there and refer to it using stackblock(). Or she can allocate
8185 * the space for it using grabstackstr(). If it is necessary to allow
8186 * someone else to use the stack temporarily and then continue to grow
8187 * the string, the user should use grabstack to allocate the space, and
8188 * then call ungrabstr(p) to return to the previous mode of operation.
8189 *
8190 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8191 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8192 * is space for at least one character.
8193 */
8194
8195
8196static char *
Eric Andersen2870d962001-07-02 17:27:21 +00008197growstackstr(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00008198 int len = stackblocksize();
8199 if (herefd >= 0 && len >= 1024) {
8200 xwrite(herefd, stackblock(), len);
8201 sstrnleft = len - 1;
8202 return stackblock();
8203 }
8204 growstackblock();
8205 sstrnleft = stackblocksize() - len - 1;
8206 return stackblock() + len;
8207}
8208
8209
8210/*
8211 * Called from CHECKSTRSPACE.
8212 */
8213
8214static char *
8215makestrspace(size_t newlen) {
8216 int len = stackblocksize() - sstrnleft;
8217 do {
8218 growstackblock();
8219 sstrnleft = stackblocksize() - len;
8220 } while (sstrnleft < newlen);
8221 return stackblock() + len;
8222}
8223
8224
8225
8226static void
Eric Andersen2870d962001-07-02 17:27:21 +00008227ungrabstackstr(char *s, char *p)
8228{
Eric Andersencb57d552001-06-28 07:25:16 +00008229 stacknleft += stacknxt - s;
8230 stacknxt = s;
8231 sstrnleft = stacknleft - (p - s);
8232}
Eric Andersencb57d552001-06-28 07:25:16 +00008233/*
8234 * Miscelaneous builtins.
8235 */
8236
8237
8238#undef rflag
8239
Eric Andersencb57d552001-06-28 07:25:16 +00008240#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersen62483552001-07-10 06:09:16 +00008241typedef long rlim_t;
Eric Andersencb57d552001-06-28 07:25:16 +00008242#endif
8243
8244
8245
8246/*
8247 * The read builtin. The -e option causes backslashes to escape the
8248 * following character.
8249 *
8250 * This uses unbuffered input, which may be avoidable in some cases.
8251 */
8252
8253static int
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008254readcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008255{
8256 char **ap;
8257 int backslash;
8258 char c;
8259 int rflag;
8260 char *prompt;
8261 const char *ifs;
8262 char *p;
8263 int startword;
8264 int status;
8265 int i;
8266
8267 rflag = 0;
8268 prompt = NULL;
8269 while ((i = nextopt("p:r")) != '\0') {
8270 if (i == 'p')
8271 prompt = optionarg;
8272 else
8273 rflag = 1;
8274 }
8275 if (prompt && isatty(0)) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008276 out2str(prompt); /* read without cmdedit */
Eric Andersencb57d552001-06-28 07:25:16 +00008277 flushall();
8278 }
8279 if (*(ap = argptr) == NULL)
8280 error("arg count");
8281 if ((ifs = bltinlookup("IFS")) == NULL)
8282 ifs = defifs;
8283 status = 0;
8284 startword = 1;
8285 backslash = 0;
8286 STARTSTACKSTR(p);
8287 for (;;) {
8288 if (read(0, &c, 1) != 1) {
8289 status = 1;
8290 break;
8291 }
8292 if (c == '\0')
8293 continue;
8294 if (backslash) {
8295 backslash = 0;
8296 if (c != '\n')
8297 STPUTC(c, p);
8298 continue;
8299 }
8300 if (!rflag && c == '\\') {
8301 backslash++;
8302 continue;
8303 }
8304 if (c == '\n')
8305 break;
8306 if (startword && *ifs == ' ' && strchr(ifs, c)) {
8307 continue;
8308 }
8309 startword = 0;
8310 if (backslash && c == '\\') {
8311 if (read(0, &c, 1) != 1) {
8312 status = 1;
8313 break;
8314 }
8315 STPUTC(c, p);
8316 } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
8317 STACKSTRNUL(p);
8318 setvar(*ap, stackblock(), 0);
8319 ap++;
8320 startword = 1;
8321 STARTSTACKSTR(p);
8322 } else {
8323 STPUTC(c, p);
8324 }
8325 }
8326 STACKSTRNUL(p);
8327 /* Remove trailing blanks */
8328 while (stackblock() <= --p && strchr(ifs, *p) != NULL)
8329 *p = '\0';
8330 setvar(*ap, stackblock(), 0);
8331 while (*++ap != NULL)
8332 setvar(*ap, nullstr, 0);
8333 return status;
8334}
8335
8336
8337
8338static int
8339umaskcmd(argc, argv)
8340 int argc;
8341 char **argv;
8342{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008343 static const char permuser[3] = "ugo";
8344 static const char permmode[3] = "rwx";
8345 static const short int permmask[] = {
8346 S_IRUSR, S_IWUSR, S_IXUSR,
8347 S_IRGRP, S_IWGRP, S_IXGRP,
8348 S_IROTH, S_IWOTH, S_IXOTH
8349 };
8350
Eric Andersencb57d552001-06-28 07:25:16 +00008351 char *ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008352 mode_t mask;
Eric Andersencb57d552001-06-28 07:25:16 +00008353 int i;
8354 int symbolic_mode = 0;
8355
Eric Andersen62483552001-07-10 06:09:16 +00008356 while (nextopt("S") != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00008357 symbolic_mode = 1;
8358 }
8359
8360 INTOFF;
8361 mask = umask(0);
8362 umask(mask);
8363 INTON;
8364
8365 if ((ap = *argptr) == NULL) {
8366 if (symbolic_mode) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008367 char buf[18];
8368 char *p = buf;
8369 for (i=0 ; i<3 ; i++) {
8370 int j;
8371 *p++ = permuser[i];
8372 *p++ = '=';
8373 for (j=0 ; j<3 ; j++) {
8374 if ((mask & permmask[3*i+j]) == 0) {
8375 *p++ = permmode[j];
8376 }
8377 }
8378 *p++ = ',';
8379 }
8380 *--p = 0;
8381 puts(buf);
Eric Andersencb57d552001-06-28 07:25:16 +00008382 } else {
Eric Andersen62483552001-07-10 06:09:16 +00008383 printf("%.4o\n", mask);
Eric Andersencb57d552001-06-28 07:25:16 +00008384 }
8385 } else {
Eric Andersen62483552001-07-10 06:09:16 +00008386 if (is_digit((unsigned char)*ap)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008387 mask = 0;
8388 do {
8389 if (*ap >= '8' || *ap < '0')
8390 error("Illegal number: %s", argv[1]);
8391 mask = (mask << 3) + (*ap - '0');
8392 } while (*++ap != '\0');
8393 umask(mask);
8394 } else {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008395 mask = ~mask & 0777;
8396 if (parse_mode(ap, &mask) == FALSE) {
Eric Andersencb57d552001-06-28 07:25:16 +00008397 error("Illegal mode: %s", ap);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008398 }
Eric Andersencb57d552001-06-28 07:25:16 +00008399 umask(~mask & 0777);
8400 }
8401 }
8402 return 0;
8403}
8404
8405/*
8406 * ulimit builtin
8407 *
8408 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
8409 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
8410 * ash by J.T. Conklin.
8411 *
8412 * Public domain.
8413 */
8414
8415struct limits {
8416 const char *name;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008417 short cmd;
8418 short factor; /* multiply by to get rlim_{cur,max} values */
Eric Andersencb57d552001-06-28 07:25:16 +00008419};
8420
8421static const struct limits limits[] = {
8422#ifdef RLIMIT_CPU
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008423 { "time(seconds)", RLIMIT_CPU, 1 },
Eric Andersencb57d552001-06-28 07:25:16 +00008424#endif
8425#ifdef RLIMIT_FSIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008426 { "file(blocks)", RLIMIT_FSIZE, 512 },
Eric Andersencb57d552001-06-28 07:25:16 +00008427#endif
8428#ifdef RLIMIT_DATA
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008429 { "data(kbytes)", RLIMIT_DATA, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008430#endif
8431#ifdef RLIMIT_STACK
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008432 { "stack(kbytes)", RLIMIT_STACK, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008433#endif
8434#ifdef RLIMIT_CORE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008435 { "coredump(blocks)", RLIMIT_CORE, 512 },
Eric Andersencb57d552001-06-28 07:25:16 +00008436#endif
8437#ifdef RLIMIT_RSS
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008438 { "memory(kbytes)", RLIMIT_RSS, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008439#endif
8440#ifdef RLIMIT_MEMLOCK
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008441 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008442#endif
8443#ifdef RLIMIT_NPROC
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008444 { "process(processes)", RLIMIT_NPROC, 1 },
Eric Andersencb57d552001-06-28 07:25:16 +00008445#endif
8446#ifdef RLIMIT_NOFILE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008447 { "nofiles(descriptors)", RLIMIT_NOFILE, 1 },
Eric Andersencb57d552001-06-28 07:25:16 +00008448#endif
8449#ifdef RLIMIT_VMEM
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008450 { "vmemory(kbytes)", RLIMIT_VMEM, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008451#endif
8452#ifdef RLIMIT_SWAP
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008453 { "swap(kbytes)", RLIMIT_SWAP, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008454#endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008455 { NULL, 0, 0 }
Eric Andersencb57d552001-06-28 07:25:16 +00008456};
8457
8458static int
8459ulimitcmd(argc, argv)
8460 int argc;
8461 char **argv;
8462{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008463 static const char unlimited_string[] = "unlimited";
Eric Andersen2870d962001-07-02 17:27:21 +00008464 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00008465 rlim_t val = 0;
8466 enum { SOFT = 0x1, HARD = 0x2 }
8467 how = SOFT | HARD;
Eric Andersen2870d962001-07-02 17:27:21 +00008468 const struct limits *l;
8469 int set, all = 0;
8470 int optc, what;
8471 struct rlimit limit;
Eric Andersencb57d552001-06-28 07:25:16 +00008472
8473 what = 'f';
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008474
8475 while ((optc = nextopt("HSa"
8476#ifdef RLIMIT_CPU
8477 "t"
8478#endif
8479#ifdef RLIMIT_FSIZE
8480 "f"
8481#endif
8482#ifdef RLIMIT_DATA
8483 "d"
8484#endif
8485#ifdef RLIMIT_STACK
8486 "s"
8487#endif
8488#ifdef RLIMIT_CORE
8489 "c"
8490#endif
8491#ifdef RLIMIT_RSS
8492 "m"
8493#endif
8494#ifdef RLIMIT_MEMLOCK
8495 "l"
8496#endif
8497#ifdef RLIMIT_NPROC
8498 "p"
8499#endif
8500#ifdef RLIMIT_NOFILE
8501 "n"
8502#endif
8503#ifdef RLIMIT_VMEM
8504 "v"
8505#endif
8506#ifdef RLIMIT_SWAP
8507 "w"
8508#endif
8509 )) != '\0') {
8510 if (optc == 'H') {
Eric Andersencb57d552001-06-28 07:25:16 +00008511 how = HARD;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008512 } else if (optc == 'S') {
Eric Andersencb57d552001-06-28 07:25:16 +00008513 how = SOFT;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008514 } else if (optc == 'a') {
Eric Andersencb57d552001-06-28 07:25:16 +00008515 all = 1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008516 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00008517 what = optc;
8518 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008519 }
Eric Andersencb57d552001-06-28 07:25:16 +00008520
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008521 for (l = limits; l->name; l++) {
8522 if(l->name[0] == what)
8523 break;
8524 if(l->name[1]=='w' && what=='w')
8525 break;
8526 }
Eric Andersencb57d552001-06-28 07:25:16 +00008527
8528 set = *argptr ? 1 : 0;
8529 if (set) {
8530 char *p = *argptr;
8531
8532 if (all || argptr[1])
8533 error("too many arguments");
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008534 if (strcmp(p, unlimited_string) == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00008535 val = RLIM_INFINITY;
8536 else {
8537 val = (rlim_t) 0;
8538
8539 while ((c = *p++) >= '0' && c <= '9')
8540 {
8541 val = (val * 10) + (long)(c - '0');
8542 if (val < (rlim_t) 0)
8543 break;
8544 }
8545 if (c)
8546 error("bad number");
8547 val *= l->factor;
8548 }
8549 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008550
Eric Andersencb57d552001-06-28 07:25:16 +00008551 if (all) {
8552 for (l = limits; l->name; l++) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008553 printf("%-20s ", l->name);
Eric Andersencb57d552001-06-28 07:25:16 +00008554 getrlimit(l->cmd, &limit);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008555 OUTPUT_LIMIT:
Eric Andersencb57d552001-06-28 07:25:16 +00008556 if (how & SOFT)
8557 val = limit.rlim_cur;
8558 else if (how & HARD)
8559 val = limit.rlim_max;
8560
Eric Andersencb57d552001-06-28 07:25:16 +00008561 if (val == RLIM_INFINITY)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008562 puts(unlimited_string);
Eric Andersencb57d552001-06-28 07:25:16 +00008563 else
8564 {
8565 val /= l->factor;
Eric Andersen62483552001-07-10 06:09:16 +00008566 printf("%lld\n", (long long) val);
Eric Andersencb57d552001-06-28 07:25:16 +00008567 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008568 if (!all) {
8569 break;
8570 }
Eric Andersencb57d552001-06-28 07:25:16 +00008571 }
8572 return 0;
8573 }
8574
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008575 if (!set) {
8576 goto OUTPUT_LIMIT;
Eric Andersencb57d552001-06-28 07:25:16 +00008577 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008578
8579 getrlimit(l->cmd, &limit);
8580 if (how & HARD)
8581 limit.rlim_max = val;
8582 if (how & SOFT)
8583 limit.rlim_cur = val;
8584 if (setrlimit(l->cmd, &limit) < 0)
8585 error("error setting limit (%m)");
Eric Andersencb57d552001-06-28 07:25:16 +00008586 return 0;
8587}
Eric Andersencb57d552001-06-28 07:25:16 +00008588/*
8589 * prefix -- see if pfx is a prefix of string.
8590 */
8591
8592static int
Eric Andersen62483552001-07-10 06:09:16 +00008593prefix(char const *pfx, char const *string)
8594{
Eric Andersencb57d552001-06-28 07:25:16 +00008595 while (*pfx) {
8596 if (*pfx++ != *string++)
8597 return 0;
8598 }
8599 return 1;
8600}
8601
Eric Andersen2870d962001-07-02 17:27:21 +00008602/*
8603 * Return true if s is a string of digits, and save munber in intptr
8604 * nagative is bad
8605 */
8606
8607static int
8608is_number(const char *p, int *intptr)
8609{
8610 int ret = 0;
8611
8612 do {
8613 if (! is_digit(*p))
8614 return 0;
8615 ret *= 10;
8616 ret += digit_val(*p);
8617 p++;
8618 } while (*p != '\0');
8619
8620 *intptr = ret;
8621 return 1;
8622}
Eric Andersencb57d552001-06-28 07:25:16 +00008623
8624/*
8625 * Convert a string of digits to an integer, printing an error message on
8626 * failure.
8627 */
8628
8629static int
Eric Andersen2870d962001-07-02 17:27:21 +00008630number(const char *s)
8631{
8632 int i;
8633 if (! is_number(s, &i))
Eric Andersencb57d552001-06-28 07:25:16 +00008634 error("Illegal number: %s", s);
Eric Andersen2870d962001-07-02 17:27:21 +00008635 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00008636}
8637
Eric Andersencb57d552001-06-28 07:25:16 +00008638/*
8639 * Produce a possibly single quoted string suitable as input to the shell.
8640 * The return string is allocated on the stack.
8641 */
8642
8643static char *
8644single_quote(const char *s) {
8645 char *p;
8646
8647 STARTSTACKSTR(p);
8648
8649 do {
8650 char *q = p;
8651 size_t len1, len1p, len2, len2p;
8652
8653 len1 = strcspn(s, "'");
8654 len2 = strspn(s + len1, "'");
8655
8656 len1p = len1 ? len1 + 2 : len1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008657 len2p = len2 + ((len2 < 2) ? len2 : 2);
Eric Andersencb57d552001-06-28 07:25:16 +00008658
8659 CHECKSTRSPACE(len1p + len2p + 1, p);
8660
8661 if (len1) {
8662 *p = '\'';
Eric Andersencb57d552001-06-28 07:25:16 +00008663 q = p + 1 + len1;
8664 memcpy(p + 1, s, len1);
Eric Andersencb57d552001-06-28 07:25:16 +00008665 *q++ = '\'';
8666 s += len1;
8667 }
8668
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008669 if (len2 > 1) {
Eric Andersencb57d552001-06-28 07:25:16 +00008670 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008671 q += 1 + len2;
8672 memcpy(q + 1, s, len2);
8673 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008674 s += len2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008675 } else if (len2 == 1) {
8676 *q++ = '\\';
8677 *q = '\'';
8678 s++;
Eric Andersencb57d552001-06-28 07:25:16 +00008679 }
8680
8681 STADJUST(len1p + len2p, p);
8682 } while (*s);
8683
8684 USTPUTC(0, p);
8685
8686 return grabstackstr(p);
8687}
8688
8689/*
8690 * Like strdup but works with the ash stack.
8691 */
8692
8693static char *
8694sstrdup(const char *p)
8695{
8696 size_t len = strlen(p) + 1;
8697 return memcpy(stalloc(len), p, len);
8698}
8699
Eric Andersencb57d552001-06-28 07:25:16 +00008700
8701/*
Eric Andersencb57d552001-06-28 07:25:16 +00008702 * Routine for dealing with parsed shell commands.
8703 */
8704
8705
Eric Andersen62483552001-07-10 06:09:16 +00008706static void sizenodelist (const struct nodelist *);
8707static struct nodelist *copynodelist (const struct nodelist *);
8708static char *nodesavestr (const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00008709
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008710//#define CALCSIZE_TABLE
8711//#define COPYNODE_TABLE
8712#if defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE)
8713/*
8714 * To collect a lot of redundant code in case statements for copynode()
8715 * and calcsize(), we implement a mini language here. Each type of node
8716 * struct has an associated instruction sequence that operates on its
8717 * members via their offsets. The instruction are pack in unsigned chars
8718 * with format IIDDDDDE where the bits are
8719 * I : part of the instruction opcode, which are
8720 * 00 : member is a pointer to another node
8721 * 40 : member is an integer
8722 * 80 : member is a pointer to a nodelist
8723 * CC : member is a pointer to a char string
8724 * D : data - the actual offset of the member to operate on in the struct
8725 * (since we assume bit 0 is set, it is not shifted)
8726 * E : flag signaling end of instruction sequence
8727 *
8728 * WARNING: In order to handle larger offsets for 64bit archs, this code
8729 * assumes that no offset can be an odd number and stores the
8730 * end-of-instructions flag in bit 0.
8731 */
8732
8733#define NODE_INTEGER 0x40
8734#define NODE_NODELIST 0x80
8735#define NODE_CHARPTR 0xC0
8736#define NODE_NOMORE 0x01 /* Note: no offset should be odd (aligned)*/
8737#define NODE_MBRMASK 0xC0
8738#define NODE_OFFSETMASK 0x3E
8739
8740static const unsigned char copynode_ops[35] = {
8741#define COPYNODE_OPS0 0
8742 offsetof(union node, nbinary.ch2),
8743 offsetof(union node, nbinary.ch1)|NODE_NOMORE,
8744#define COPYNODE_OPS1 (COPYNODE_OPS0 + 2)
8745 offsetof(union node, ncmd.redirect),
8746 offsetof(union node, ncmd.args),
8747 offsetof(union node, ncmd.assign),
8748 offsetof(union node, ncmd.backgnd)|NODE_INTEGER|NODE_NOMORE,
8749#define COPYNODE_OPS2 (COPYNODE_OPS1 + 4)
8750 offsetof(union node, npipe.cmdlist)|NODE_NODELIST,
8751 offsetof(union node, npipe.backgnd)|NODE_INTEGER|NODE_NOMORE,
8752#define COPYNODE_OPS3 (COPYNODE_OPS2 + 2)
8753 offsetof(union node, nredir.redirect),
8754 offsetof(union node, nredir.n)|NODE_NOMORE,
8755#define COPYNODE_OPS4 (COPYNODE_OPS3 + 2)
8756 offsetof(union node, nif.elsepart),
8757 offsetof(union node, nif.ifpart),
8758 offsetof(union node, nif.test)|NODE_NOMORE,
8759#define COPYNODE_OPS5 (COPYNODE_OPS4 + 3)
8760 offsetof(union node, nfor.var)|NODE_CHARPTR,
8761 offsetof(union node, nfor.body),
8762 offsetof(union node, nfor.args)|NODE_NOMORE,
8763#define COPYNODE_OPS6 (COPYNODE_OPS5 + 3)
8764 offsetof(union node, ncase.cases),
8765 offsetof(union node, ncase.expr)|NODE_NOMORE,
8766#define COPYNODE_OPS7 (COPYNODE_OPS6 + 2)
8767 offsetof(union node, nclist.body),
8768 offsetof(union node, nclist.pattern),
8769 offsetof(union node, nclist.next)|NODE_NOMORE,
8770#define COPYNODE_OPS8 (COPYNODE_OPS7 + 3)
8771 offsetof(union node, narg.backquote)|NODE_NODELIST,
8772 offsetof(union node, narg.text)|NODE_CHARPTR,
8773 offsetof(union node, narg.next)|NODE_NOMORE,
8774#define COPYNODE_OPS9 (COPYNODE_OPS8 + 3)
8775 offsetof(union node, nfile.fname),
8776 offsetof(union node, nfile.fd)|NODE_INTEGER,
8777 offsetof(union node, nfile.next)|NODE_NOMORE,
8778#define COPYNODE_OPS10 (COPYNODE_OPS9 + 3)
8779 offsetof(union node, ndup.vname),
8780 offsetof(union node, ndup.dupfd)|NODE_INTEGER,
8781 offsetof(union node, ndup.fd)|NODE_INTEGER,
8782 offsetof(union node, ndup.next)|NODE_NOMORE,
8783#define COPYNODE_OPS11 (COPYNODE_OPS10 + 4)
8784 offsetof(union node, nhere.doc),
8785 offsetof(union node, nhere.fd)|NODE_INTEGER,
8786 offsetof(union node, nhere.next)|NODE_NOMORE,
8787#define COPYNODE_OPS12 (COPYNODE_OPS11 + 3)
8788 offsetof(union node, nnot.com)|NODE_NOMORE,
8789};
8790
8791#if COPYNODE_OPS12 != 34
8792#error COPYNODE_OPS12 is incorrect
8793#endif
8794
8795static const unsigned char copynode_ops_index[26] = {
8796 COPYNODE_OPS0, /* NSEMI */
8797 COPYNODE_OPS1, /* NCMD */
8798 COPYNODE_OPS2, /* NPIPE */
8799 COPYNODE_OPS3, /* NREDIR */
8800 COPYNODE_OPS3, /* NBACKGND */
8801 COPYNODE_OPS3, /* NSUBSHELL */
8802 COPYNODE_OPS0, /* NAND */
8803 COPYNODE_OPS0, /* NOR */
8804 COPYNODE_OPS4, /* NIF */
8805 COPYNODE_OPS0, /* NWHILE */
8806 COPYNODE_OPS0, /* NUNTIL */
8807 COPYNODE_OPS5, /* NFOR */
8808 COPYNODE_OPS6, /* NCASE */
8809 COPYNODE_OPS7, /* NCLIST */
8810 COPYNODE_OPS8, /* NDEFUN */
8811 COPYNODE_OPS8, /* NARG */
8812 COPYNODE_OPS9, /* NTO */
8813 COPYNODE_OPS9, /* NFROM */
8814 COPYNODE_OPS9, /* NFROMTO */
8815 COPYNODE_OPS9, /* NAPPEND */
8816 COPYNODE_OPS9, /* NTOOV */
8817 COPYNODE_OPS10, /* NTOFD */
8818 COPYNODE_OPS10, /* NFROMFD */
8819 COPYNODE_OPS11, /* NHERE */
8820 COPYNODE_OPS11, /* NXHERE */
8821 COPYNODE_OPS12, /* NNOT */
8822};
8823
8824#if NODE_CHARPTR != NODE_MBRMASK
8825#error NODE_CHARPTR != NODE_MBRMASK!!!
8826#endif
8827#endif /* defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE) */
8828
8829#ifdef COPYNODE_TABLE
8830static union node *
8831copynode(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008832{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008833 union node *new;
8834 const unsigned char *p;
8835
Eric Andersencb57d552001-06-28 07:25:16 +00008836 if (n == NULL)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008837 return NULL;
8838 new = funcblock;
8839 new->type = n->type;
8840 funcblock = (char *) funcblock + (int) nodesize[n->type];
8841 p = copynode_ops + (int) copynode_ops_index[n->type];
8842 do {
8843 char *nn = ((char *) new) + ((int)(*p & NODE_OFFSETMASK));
8844 const char *no = ((const char *) n) + ((int)(*p & NODE_OFFSETMASK));
8845
8846 if (!(*p & NODE_MBRMASK)) { /* standard node */
8847 (union node *) nn = copynode((const union node *) no);
8848 } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
8849 nn = nodesavestr(no);
8850 } else if (*p & NODE_NODELIST) { /* nodelist */
8851 (struct nodelist *) nn
8852 = copynodelist((const struct nodelist *) no);
8853 } else { /* integer */
8854 *((int *) nn) = *((int *) no);
8855 }
8856 } while (!(*p++ & NODE_NOMORE));
8857 return new;
Eric Andersencb57d552001-06-28 07:25:16 +00008858}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008859#else /* COPYNODE_TABLE */
Eric Andersencb57d552001-06-28 07:25:16 +00008860static union node *
Eric Andersen62483552001-07-10 06:09:16 +00008861copynode(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008862{
Eric Andersen62483552001-07-10 06:09:16 +00008863 union node *new;
Eric Andersencb57d552001-06-28 07:25:16 +00008864
8865 if (n == NULL)
8866 return NULL;
8867 new = funcblock;
8868 funcblock = (char *) funcblock + nodesize[n->type];
8869 switch (n->type) {
8870 case NSEMI:
8871 case NAND:
8872 case NOR:
8873 case NWHILE:
8874 case NUNTIL:
8875 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8876 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8877 break;
8878 case NCMD:
8879 new->ncmd.redirect = copynode(n->ncmd.redirect);
8880 new->ncmd.args = copynode(n->ncmd.args);
8881 new->ncmd.assign = copynode(n->ncmd.assign);
8882 new->ncmd.backgnd = n->ncmd.backgnd;
8883 break;
8884 case NPIPE:
8885 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8886 new->npipe.backgnd = n->npipe.backgnd;
8887 break;
8888 case NREDIR:
8889 case NBACKGND:
8890 case NSUBSHELL:
8891 new->nredir.redirect = copynode(n->nredir.redirect);
8892 new->nredir.n = copynode(n->nredir.n);
8893 break;
8894 case NIF:
8895 new->nif.elsepart = copynode(n->nif.elsepart);
8896 new->nif.ifpart = copynode(n->nif.ifpart);
8897 new->nif.test = copynode(n->nif.test);
8898 break;
8899 case NFOR:
8900 new->nfor.var = nodesavestr(n->nfor.var);
8901 new->nfor.body = copynode(n->nfor.body);
8902 new->nfor.args = copynode(n->nfor.args);
8903 break;
8904 case NCASE:
8905 new->ncase.cases = copynode(n->ncase.cases);
8906 new->ncase.expr = copynode(n->ncase.expr);
8907 break;
8908 case NCLIST:
8909 new->nclist.body = copynode(n->nclist.body);
8910 new->nclist.pattern = copynode(n->nclist.pattern);
8911 new->nclist.next = copynode(n->nclist.next);
8912 break;
8913 case NDEFUN:
8914 case NARG:
8915 new->narg.backquote = copynodelist(n->narg.backquote);
8916 new->narg.text = nodesavestr(n->narg.text);
8917 new->narg.next = copynode(n->narg.next);
8918 break;
8919 case NTO:
8920 case NFROM:
8921 case NFROMTO:
8922 case NAPPEND:
8923 case NTOOV:
8924 new->nfile.fname = copynode(n->nfile.fname);
8925 new->nfile.fd = n->nfile.fd;
8926 new->nfile.next = copynode(n->nfile.next);
8927 break;
8928 case NTOFD:
8929 case NFROMFD:
8930 new->ndup.vname = copynode(n->ndup.vname);
8931 new->ndup.dupfd = n->ndup.dupfd;
8932 new->ndup.fd = n->ndup.fd;
8933 new->ndup.next = copynode(n->ndup.next);
8934 break;
8935 case NHERE:
8936 case NXHERE:
8937 new->nhere.doc = copynode(n->nhere.doc);
8938 new->nhere.fd = n->nhere.fd;
8939 new->nhere.next = copynode(n->nhere.next);
8940 break;
8941 case NNOT:
8942 new->nnot.com = copynode(n->nnot.com);
8943 break;
8944 };
8945 new->type = n->type;
Eric Andersen62483552001-07-10 06:09:16 +00008946 return new;
Eric Andersencb57d552001-06-28 07:25:16 +00008947}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008948#endif /* COPYNODE_TABLE */
8949
8950#ifdef CALCSIZE_TABLE
8951static void
8952calcsize(const union node *n)
8953{
8954 const unsigned char *p;
8955
8956 if (n == NULL)
8957 return;
8958 funcblocksize += (int) nodesize[n->type];
8959
8960 p = copynode_ops + (int) copynode_ops_index[n->type];
8961 do {
8962 const char *no = ((const char *) n) + ((int)(*p & NODE_OFFSETMASK));
8963
8964 if (!(*p & NODE_MBRMASK)) { /* standard node */
8965 calcsize((const union node *) no);
8966 } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
8967 funcstringsize += strlen(no) + 1;
8968 } else if (*p & NODE_NODELIST) { /* nodelist */
8969 sizenodelist((const struct nodelist *) no);
8970 }
8971 } while (!(*p++ & NODE_NOMORE));
8972}
8973#else /* CALCSIZE_TABLE */
8974static void
8975calcsize(const union node *n)
8976{
8977 if (n == NULL)
8978 return;
8979 funcblocksize += nodesize[n->type];
8980 switch (n->type) {
8981 case NSEMI:
8982 case NAND:
8983 case NOR:
8984 case NWHILE:
8985 case NUNTIL:
8986 calcsize(n->nbinary.ch2);
8987 calcsize(n->nbinary.ch1);
8988 break;
8989 case NCMD:
8990 calcsize(n->ncmd.redirect);
8991 calcsize(n->ncmd.args);
8992 calcsize(n->ncmd.assign);
8993 break;
8994 case NPIPE:
8995 sizenodelist(n->npipe.cmdlist);
8996 break;
8997 case NREDIR:
8998 case NBACKGND:
8999 case NSUBSHELL:
9000 calcsize(n->nredir.redirect);
9001 calcsize(n->nredir.n);
9002 break;
9003 case NIF:
9004 calcsize(n->nif.elsepart);
9005 calcsize(n->nif.ifpart);
9006 calcsize(n->nif.test);
9007 break;
9008 case NFOR:
9009 funcstringsize += strlen(n->nfor.var) + 1;
9010 calcsize(n->nfor.body);
9011 calcsize(n->nfor.args);
9012 break;
9013 case NCASE:
9014 calcsize(n->ncase.cases);
9015 calcsize(n->ncase.expr);
9016 break;
9017 case NCLIST:
9018 calcsize(n->nclist.body);
9019 calcsize(n->nclist.pattern);
9020 calcsize(n->nclist.next);
9021 break;
9022 case NDEFUN:
9023 case NARG:
9024 sizenodelist(n->narg.backquote);
9025 funcstringsize += strlen(n->narg.text) + 1;
9026 calcsize(n->narg.next);
9027 break;
9028 case NTO:
9029 case NFROM:
9030 case NFROMTO:
9031 case NAPPEND:
9032 case NTOOV:
9033 calcsize(n->nfile.fname);
9034 calcsize(n->nfile.next);
9035 break;
9036 case NTOFD:
9037 case NFROMFD:
9038 calcsize(n->ndup.vname);
9039 calcsize(n->ndup.next);
9040 break;
9041 case NHERE:
9042 case NXHERE:
9043 calcsize(n->nhere.doc);
9044 calcsize(n->nhere.next);
9045 break;
9046 case NNOT:
9047 calcsize(n->nnot.com);
9048 break;
9049 };
9050}
9051#endif /* CALCSIZE_TABLE */
9052
9053static void
9054sizenodelist(const struct nodelist *lp)
9055{
9056 while (lp) {
9057 funcblocksize += ALIGN(sizeof(struct nodelist));
9058 calcsize(lp->n);
9059 lp = lp->next;
9060 }
9061}
Eric Andersencb57d552001-06-28 07:25:16 +00009062
9063
9064static struct nodelist *
Eric Andersen62483552001-07-10 06:09:16 +00009065copynodelist(const struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00009066{
9067 struct nodelist *start;
9068 struct nodelist **lpp;
9069
9070 lpp = &start;
9071 while (lp) {
9072 *lpp = funcblock;
9073 funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist));
9074 (*lpp)->n = copynode(lp->n);
9075 lp = lp->next;
9076 lpp = &(*lpp)->next;
9077 }
9078 *lpp = NULL;
9079 return start;
9080}
9081
9082
Eric Andersencb57d552001-06-28 07:25:16 +00009083static char *
Eric Andersen62483552001-07-10 06:09:16 +00009084nodesavestr(const char *s)
Eric Andersencb57d552001-06-28 07:25:16 +00009085{
Eric Andersen62483552001-07-10 06:09:16 +00009086 const char *p = s;
9087 char *q = funcstring;
Eric Andersencb57d552001-06-28 07:25:16 +00009088 char *rtn = funcstring;
9089
9090 while ((*q++ = *p++) != '\0')
9091 continue;
9092 funcstring = q;
9093 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00009094}
9095
Eric Andersencb57d552001-06-28 07:25:16 +00009096#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00009097static int getopts (char *, char *, char **, int *, int *);
Eric Andersencb57d552001-06-28 07:25:16 +00009098#endif
9099
9100
9101/*
9102 * Process the shell command line arguments.
9103 */
9104
9105static void
9106procargs(argc, argv)
9107 int argc;
9108 char **argv;
9109{
9110 int i;
9111
9112 argptr = argv;
9113 if (argc > 0)
9114 argptr++;
9115 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009116 optent_val(i) = 2;
Eric Andersencb57d552001-06-28 07:25:16 +00009117 options(1);
9118 if (*argptr == NULL && minusc == NULL)
9119 sflag = 1;
9120 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
9121 iflag = 1;
9122 if (mflag == 2)
9123 mflag = iflag;
9124 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009125 if (optent_val(i) == 2)
9126 optent_val(i) = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009127 arg0 = argv[0];
9128 if (sflag == 0 && minusc == NULL) {
9129 commandname = argv[0];
9130 arg0 = *argptr++;
9131 setinputfile(arg0, 0);
9132 commandname = arg0;
9133 }
9134 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
9135 if (argptr && minusc && *argptr)
Eric Andersen2870d962001-07-02 17:27:21 +00009136 arg0 = *argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00009137
9138 shellparam.p = argptr;
9139 shellparam.optind = 1;
9140 shellparam.optoff = -1;
9141 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
9142 while (*argptr) {
9143 shellparam.nparam++;
9144 argptr++;
9145 }
9146 optschanged();
9147}
9148
9149
Eric Andersencb57d552001-06-28 07:25:16 +00009150
9151/*
9152 * Process shell options. The global variable argptr contains a pointer
9153 * to the argument list; we advance it past the options.
9154 */
9155
Eric Andersen62483552001-07-10 06:09:16 +00009156static inline void
9157minus_o(const char *name, int val)
9158{
9159 int i;
9160
9161 if (name == NULL) {
9162 out1str("Current option settings\n");
9163 for (i = 0; i < NOPTS; i++)
9164 printf("%-16s%s\n", optent_name(optlist[i]),
9165 optent_val(i) ? "on" : "off");
9166 } else {
9167 for (i = 0; i < NOPTS; i++)
9168 if (equal(name, optent_name(optlist[i]))) {
9169 setoption(optent_letter(optlist[i]), val);
9170 return;
9171 }
9172 error("Illegal option -o %s", name);
9173 }
9174}
9175
9176
Eric Andersencb57d552001-06-28 07:25:16 +00009177static void
Eric Andersen62483552001-07-10 06:09:16 +00009178options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00009179{
9180 char *p;
9181 int val;
9182 int c;
9183
9184 if (cmdline)
9185 minusc = NULL;
9186 while ((p = *argptr) != NULL) {
9187 argptr++;
9188 if ((c = *p++) == '-') {
9189 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00009190 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
9191 if (!cmdline) {
9192 /* "-" means turn off -x and -v */
9193 if (p[0] == '\0')
9194 xflag = vflag = 0;
9195 /* "--" means reset params */
9196 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00009197 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00009198 }
9199 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00009200 }
9201 } else if (c == '+') {
9202 val = 0;
9203 } else {
9204 argptr--;
9205 break;
9206 }
9207 while ((c = *p++) != '\0') {
9208 if (c == 'c' && cmdline) {
9209 char *q;
Eric Andersen2870d962001-07-02 17:27:21 +00009210#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */
Eric Andersencb57d552001-06-28 07:25:16 +00009211 if (*p == '\0')
9212#endif
9213 q = *argptr++;
9214 if (q == NULL || minusc != NULL)
9215 error("Bad -c option");
9216 minusc = q;
9217#ifdef NOHACK
9218 break;
9219#endif
9220 } else if (c == 'o') {
9221 minus_o(*argptr, val);
9222 if (*argptr)
9223 argptr++;
9224 } else {
9225 setoption(c, val);
9226 }
9227 }
9228 }
9229}
9230
Eric Andersencb57d552001-06-28 07:25:16 +00009231
9232static void
Eric Andersen2870d962001-07-02 17:27:21 +00009233setoption(int flag, int val)
9234{
Eric Andersencb57d552001-06-28 07:25:16 +00009235 int i;
9236
9237 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009238 if (optent_letter(optlist[i]) == flag) {
9239 optent_val(i) = val;
Eric Andersencb57d552001-06-28 07:25:16 +00009240 if (val) {
9241 /* #%$ hack for ksh semantics */
9242 if (flag == 'V')
9243 Eflag = 0;
9244 else if (flag == 'E')
9245 Vflag = 0;
9246 }
9247 return;
9248 }
9249 error("Illegal option -%c", flag);
9250 /* NOTREACHED */
9251}
9252
9253
9254
Eric Andersencb57d552001-06-28 07:25:16 +00009255/*
9256 * Set the shell parameters.
9257 */
9258
9259static void
Eric Andersen2870d962001-07-02 17:27:21 +00009260setparam(char **argv)
9261{
Eric Andersencb57d552001-06-28 07:25:16 +00009262 char **newparam;
9263 char **ap;
9264 int nparam;
9265
9266 for (nparam = 0 ; argv[nparam] ; nparam++);
9267 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
9268 while (*argv) {
9269 *ap++ = savestr(*argv++);
9270 }
9271 *ap = NULL;
9272 freeparam(&shellparam);
9273 shellparam.malloc = 1;
9274 shellparam.nparam = nparam;
9275 shellparam.p = newparam;
9276 shellparam.optind = 1;
9277 shellparam.optoff = -1;
9278}
9279
9280
9281/*
9282 * Free the list of positional parameters.
9283 */
9284
9285static void
Eric Andersen2870d962001-07-02 17:27:21 +00009286freeparam(volatile struct shparam *param)
9287{
Eric Andersencb57d552001-06-28 07:25:16 +00009288 char **ap;
9289
9290 if (param->malloc) {
9291 for (ap = param->p ; *ap ; ap++)
9292 ckfree(*ap);
9293 ckfree(param->p);
9294 }
9295}
9296
9297
9298
9299/*
9300 * The shift builtin command.
9301 */
9302
9303static int
9304shiftcmd(argc, argv)
9305 int argc;
9306 char **argv;
9307{
9308 int n;
9309 char **ap1, **ap2;
9310
9311 n = 1;
9312 if (argc > 1)
9313 n = number(argv[1]);
9314 if (n > shellparam.nparam)
9315 error("can't shift that many");
9316 INTOFF;
9317 shellparam.nparam -= n;
9318 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
9319 if (shellparam.malloc)
9320 ckfree(*ap1);
9321 }
9322 ap2 = shellparam.p;
9323 while ((*ap2++ = *ap1++) != NULL);
9324 shellparam.optind = 1;
9325 shellparam.optoff = -1;
9326 INTON;
9327 return 0;
9328}
9329
9330
9331
9332/*
9333 * The set command builtin.
9334 */
9335
9336static int
9337setcmd(argc, argv)
9338 int argc;
9339 char **argv;
9340{
9341 if (argc == 1)
9342 return showvarscmd(argc, argv);
9343 INTOFF;
9344 options(0);
9345 optschanged();
9346 if (*argptr != NULL) {
9347 setparam(argptr);
9348 }
9349 INTON;
9350 return 0;
9351}
9352
9353
9354static void
Eric Andersen2870d962001-07-02 17:27:21 +00009355getoptsreset(const char *value)
Eric Andersencb57d552001-06-28 07:25:16 +00009356{
9357 shellparam.optind = number(value);
9358 shellparam.optoff = -1;
9359}
9360
Eric Andersen2870d962001-07-02 17:27:21 +00009361#ifdef BB_LOCALE_SUPPORT
9362static void change_lc_all(const char *value)
9363{
9364 if(value != 0 && *value != 0)
9365 setlocale(LC_ALL, value);
9366}
9367
9368static void change_lc_ctype(const char *value)
9369{
9370 if(value != 0 && *value != 0)
9371 setlocale(LC_CTYPE, value);
9372}
9373
9374#endif
9375
Eric Andersencb57d552001-06-28 07:25:16 +00009376#ifdef ASH_GETOPTS
9377/*
9378 * The getopts builtin. Shellparam.optnext points to the next argument
9379 * to be processed. Shellparam.optptr points to the next character to
9380 * be processed in the current argument. If shellparam.optnext is NULL,
9381 * then it's the first time getopts has been called.
9382 */
9383
9384static int
9385getoptscmd(argc, argv)
9386 int argc;
9387 char **argv;
9388{
9389 char **optbase;
9390
9391 if (argc < 3)
9392 error("Usage: getopts optstring var [arg]");
9393 else if (argc == 3) {
9394 optbase = shellparam.p;
9395 if (shellparam.optind > shellparam.nparam + 1) {
9396 shellparam.optind = 1;
9397 shellparam.optoff = -1;
9398 }
9399 }
9400 else {
9401 optbase = &argv[3];
9402 if (shellparam.optind > argc - 2) {
9403 shellparam.optind = 1;
9404 shellparam.optoff = -1;
9405 }
9406 }
9407
9408 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9409 &shellparam.optoff);
9410}
9411
9412/*
9413 * Safe version of setvar, returns 1 on success 0 on failure.
9414 */
9415
9416static int
9417setvarsafe(name, val, flags)
9418 const char *name, *val;
9419 int flags;
9420{
9421 struct jmploc jmploc;
9422 struct jmploc *volatile savehandler = handler;
9423 int err = 0;
9424#ifdef __GNUC__
9425 (void) &err;
9426#endif
9427
9428 if (setjmp(jmploc.loc))
9429 err = 1;
9430 else {
9431 handler = &jmploc;
9432 setvar(name, val, flags);
9433 }
9434 handler = savehandler;
9435 return err;
9436}
9437
9438static int
9439getopts(optstr, optvar, optfirst, myoptind, optoff)
9440 char *optstr;
9441 char *optvar;
9442 char **optfirst;
9443 int *myoptind;
9444 int *optoff;
9445{
9446 char *p, *q;
9447 char c = '?';
9448 int done = 0;
9449 int err = 0;
9450 char s[10];
9451 char **optnext = optfirst + *myoptind - 1;
9452
9453 if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
9454 strlen(*(optnext - 1)) < *optoff)
9455 p = NULL;
9456 else
9457 p = *(optnext - 1) + *optoff;
9458 if (p == NULL || *p == '\0') {
9459 /* Current word is done, advance */
9460 if (optnext == NULL)
9461 return 1;
9462 p = *optnext;
9463 if (p == NULL || *p != '-' || *++p == '\0') {
9464atend:
9465 *myoptind = optnext - optfirst + 1;
9466 p = NULL;
9467 done = 1;
9468 goto out;
9469 }
9470 optnext++;
Eric Andersen2870d962001-07-02 17:27:21 +00009471 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009472 goto atend;
9473 }
9474
9475 c = *p++;
9476 for (q = optstr; *q != c; ) {
9477 if (*q == '\0') {
9478 if (optstr[0] == ':') {
9479 s[0] = c;
9480 s[1] = '\0';
9481 err |= setvarsafe("OPTARG", s, 0);
9482 }
9483 else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009484 out2fmt("Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009485 (void) unsetvar("OPTARG");
9486 }
9487 c = '?';
9488 goto bad;
9489 }
9490 if (*++q == ':')
9491 q++;
9492 }
9493
9494 if (*++q == ':') {
9495 if (*p == '\0' && (p = *optnext) == NULL) {
9496 if (optstr[0] == ':') {
9497 s[0] = c;
9498 s[1] = '\0';
9499 err |= setvarsafe("OPTARG", s, 0);
9500 c = ':';
9501 }
9502 else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009503 out2fmt("No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009504 (void) unsetvar("OPTARG");
9505 c = '?';
9506 }
9507 goto bad;
9508 }
9509
9510 if (p == *optnext)
9511 optnext++;
9512 setvarsafe("OPTARG", p, 0);
9513 p = NULL;
9514 }
9515 else
9516 setvarsafe("OPTARG", "", 0);
9517 *myoptind = optnext - optfirst + 1;
9518 goto out;
9519
9520bad:
9521 *myoptind = 1;
9522 p = NULL;
9523out:
9524 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersen3102ac42001-07-06 04:26:23 +00009525 snprintf(s, sizeof(s), "%d", *myoptind);
Eric Andersencb57d552001-06-28 07:25:16 +00009526 err |= setvarsafe("OPTIND", s, VNOFUNC);
9527 s[0] = c;
9528 s[1] = '\0';
9529 err |= setvarsafe(optvar, s, 0);
9530 if (err) {
9531 *myoptind = 1;
9532 *optoff = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00009533 exraise(EXERROR);
9534 }
9535 return done;
9536}
Eric Andersen2870d962001-07-02 17:27:21 +00009537#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009538
9539/*
9540 * XXX - should get rid of. have all builtins use getopt(3). the
9541 * library getopt must have the BSD extension static variable "optreset"
9542 * otherwise it can't be used within the shell safely.
9543 *
9544 * Standard option processing (a la getopt) for builtin routines. The
9545 * only argument that is passed to nextopt is the option string; the
9546 * other arguments are unnecessary. It return the character, or '\0' on
9547 * end of input.
9548 */
9549
9550static int
Eric Andersen62483552001-07-10 06:09:16 +00009551nextopt(const char *optstring)
9552{
Eric Andersencb57d552001-06-28 07:25:16 +00009553 char *p;
9554 const char *q;
9555 char c;
9556
9557 if ((p = optptr) == NULL || *p == '\0') {
9558 p = *argptr;
9559 if (p == NULL || *p != '-' || *++p == '\0')
9560 return '\0';
9561 argptr++;
Eric Andersen2870d962001-07-02 17:27:21 +00009562 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009563 return '\0';
9564 }
9565 c = *p++;
9566 for (q = optstring ; *q != c ; ) {
9567 if (*q == '\0')
9568 error("Illegal option -%c", c);
9569 if (*++q == ':')
9570 q++;
9571 }
9572 if (*++q == ':') {
9573 if (*p == '\0' && (p = *argptr++) == NULL)
9574 error("No arg for -%c option", c);
9575 optionarg = p;
9576 p = NULL;
9577 }
9578 optptr = p;
9579 return c;
9580}
9581
Eric Andersencb57d552001-06-28 07:25:16 +00009582static void
9583flushall() {
Eric Andersencb57d552001-06-28 07:25:16 +00009584 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009585 fflush(stdout);
Eric Andersencb57d552001-06-28 07:25:16 +00009586 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009587}
9588
9589
9590static void
Eric Andersen3102ac42001-07-06 04:26:23 +00009591out2fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009592{
9593 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00009594 va_start(ap, fmt);
Eric Andersen3102ac42001-07-06 04:26:23 +00009595 vfprintf(stderr, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009596 va_end(ap);
9597}
9598
Eric Andersencb57d552001-06-28 07:25:16 +00009599/*
9600 * Version of write which resumes after a signal is caught.
9601 */
9602
9603static int
Eric Andersen2870d962001-07-02 17:27:21 +00009604xwrite(int fd, const char *buf, int nbytes)
9605{
Eric Andersencb57d552001-06-28 07:25:16 +00009606 int ntry;
9607 int i;
9608 int n;
9609
9610 n = nbytes;
9611 ntry = 0;
9612 for (;;) {
9613 i = write(fd, buf, n);
9614 if (i > 0) {
9615 if ((n -= i) <= 0)
9616 return nbytes;
9617 buf += i;
9618 ntry = 0;
9619 } else if (i == 0) {
9620 if (++ntry > 10)
9621 return nbytes - n;
9622 } else if (errno != EINTR) {
9623 return -1;
9624 }
9625 }
9626}
9627
9628
Eric Andersencb57d552001-06-28 07:25:16 +00009629/*
9630 * Shell command parser.
9631 */
9632
9633#define EOFMARKLEN 79
9634
9635
9636
9637struct heredoc {
Eric Andersen2870d962001-07-02 17:27:21 +00009638 struct heredoc *next; /* next here document in list */
9639 union node *here; /* redirection node */
9640 char *eofmark; /* string indicating end of input */
9641 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009642};
9643
Eric Andersen2870d962001-07-02 17:27:21 +00009644static struct heredoc *heredoclist; /* list of here documents to read */
9645static int parsebackquote; /* nonzero if we are inside backquotes */
9646static int doprompt; /* if set, prompt the user */
9647static int needprompt; /* true if interactive and at start of line */
9648static int lasttoken; /* last token read */
Eric Andersencb57d552001-06-28 07:25:16 +00009649
Eric Andersen2870d962001-07-02 17:27:21 +00009650static char *wordtext; /* text of last word returned by readtoken */
Eric Andersencb57d552001-06-28 07:25:16 +00009651
Eric Andersen2870d962001-07-02 17:27:21 +00009652static struct nodelist *backquotelist;
9653static union node *redirnode;
Eric Andersen044228d2001-07-17 01:12:36 +00009654static struct heredoc *heredoc;
Eric Andersen2870d962001-07-02 17:27:21 +00009655static int quoteflag; /* set if (part of) last token was quoted */
9656static int startlinno; /* line # where last token started */
Eric Andersencb57d552001-06-28 07:25:16 +00009657
9658
Eric Andersen2870d962001-07-02 17:27:21 +00009659static union node *list (int);
9660static union node *andor (void);
9661static union node *pipeline (void);
9662static union node *command (void);
9663static union node *simplecmd (void);
9664static void parsefname (void);
9665static void parseheredoc (void);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009666static char peektoken (void);
Eric Andersen2870d962001-07-02 17:27:21 +00009667static int readtoken (void);
9668static int xxreadtoken (void);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009669static int readtoken1 (int, int, const char *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00009670static int noexpand (char *);
9671static void synexpect (int) __attribute__((noreturn));
9672static void synerror (const char *) __attribute__((noreturn));
9673static void setprompt (int);
Eric Andersencb57d552001-06-28 07:25:16 +00009674
9675
9676/*
9677 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9678 * valid parse tree indicating a blank line.)
9679 */
9680
Eric Andersen2870d962001-07-02 17:27:21 +00009681static union node *
Eric Andersencb57d552001-06-28 07:25:16 +00009682parsecmd(int interact)
9683{
9684 int t;
9685
9686 tokpushback = 0;
9687 doprompt = interact;
9688 if (doprompt)
9689 setprompt(1);
9690 else
9691 setprompt(0);
9692 needprompt = 0;
9693 t = readtoken();
9694 if (t == TEOF)
9695 return NEOF;
9696 if (t == TNL)
9697 return NULL;
9698 tokpushback++;
9699 return list(1);
9700}
9701
9702
9703static union node *
9704list(nlflag)
9705 int nlflag;
9706{
9707 union node *n1, *n2, *n3;
9708 int tok;
9709
9710 checkkwd = 2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009711 if (nlflag == 0 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009712 return NULL;
9713 n1 = NULL;
9714 for (;;) {
9715 n2 = andor();
9716 tok = readtoken();
9717 if (tok == TBACKGND) {
9718 if (n2->type == NCMD || n2->type == NPIPE) {
9719 n2->ncmd.backgnd = 1;
9720 } else if (n2->type == NREDIR) {
9721 n2->type = NBACKGND;
9722 } else {
9723 n3 = (union node *)stalloc(sizeof (struct nredir));
9724 n3->type = NBACKGND;
9725 n3->nredir.n = n2;
9726 n3->nredir.redirect = NULL;
9727 n2 = n3;
9728 }
9729 }
9730 if (n1 == NULL) {
9731 n1 = n2;
9732 }
9733 else {
9734 n3 = (union node *)stalloc(sizeof (struct nbinary));
9735 n3->type = NSEMI;
9736 n3->nbinary.ch1 = n1;
9737 n3->nbinary.ch2 = n2;
9738 n1 = n3;
9739 }
9740 switch (tok) {
9741 case TBACKGND:
9742 case TSEMI:
9743 tok = readtoken();
9744 /* fall through */
9745 case TNL:
9746 if (tok == TNL) {
9747 parseheredoc();
9748 if (nlflag)
9749 return n1;
9750 } else {
9751 tokpushback++;
9752 }
9753 checkkwd = 2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009754 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009755 return n1;
9756 break;
9757 case TEOF:
9758 if (heredoclist)
9759 parseheredoc();
9760 else
Eric Andersen2870d962001-07-02 17:27:21 +00009761 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009762 return n1;
9763 default:
9764 if (nlflag)
9765 synexpect(-1);
9766 tokpushback++;
9767 return n1;
9768 }
9769 }
9770}
9771
9772
9773
9774static union node *
9775andor() {
9776 union node *n1, *n2, *n3;
9777 int t;
9778
9779 checkkwd = 1;
9780 n1 = pipeline();
9781 for (;;) {
9782 if ((t = readtoken()) == TAND) {
9783 t = NAND;
9784 } else if (t == TOR) {
9785 t = NOR;
9786 } else {
9787 tokpushback++;
9788 return n1;
9789 }
9790 checkkwd = 2;
9791 n2 = pipeline();
9792 n3 = (union node *)stalloc(sizeof (struct nbinary));
9793 n3->type = t;
9794 n3->nbinary.ch1 = n1;
9795 n3->nbinary.ch2 = n2;
9796 n1 = n3;
9797 }
9798}
9799
9800
9801
9802static union node *
9803pipeline() {
9804 union node *n1, *n2, *pipenode;
9805 struct nodelist *lp, *prev;
9806 int negate;
9807
9808 negate = 0;
9809 TRACE(("pipeline: entered\n"));
9810 if (readtoken() == TNOT) {
9811 negate = !negate;
9812 checkkwd = 1;
9813 } else
9814 tokpushback++;
9815 n1 = command();
9816 if (readtoken() == TPIPE) {
9817 pipenode = (union node *)stalloc(sizeof (struct npipe));
9818 pipenode->type = NPIPE;
9819 pipenode->npipe.backgnd = 0;
9820 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9821 pipenode->npipe.cmdlist = lp;
9822 lp->n = n1;
9823 do {
9824 prev = lp;
9825 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9826 checkkwd = 2;
9827 lp->n = command();
9828 prev->next = lp;
9829 } while (readtoken() == TPIPE);
9830 lp->next = NULL;
9831 n1 = pipenode;
9832 }
9833 tokpushback++;
9834 if (negate) {
9835 n2 = (union node *)stalloc(sizeof (struct nnot));
9836 n2->type = NNOT;
9837 n2->nnot.com = n1;
9838 return n2;
9839 } else
9840 return n1;
9841}
9842
9843
9844
9845static union node *
9846command() {
9847 union node *n1, *n2;
9848 union node *ap, **app;
9849 union node *cp, **cpp;
9850 union node *redir, **rpp;
9851 int t;
9852
9853 redir = NULL;
9854 n1 = NULL;
9855 rpp = &redir;
9856
9857 switch (readtoken()) {
9858 case TIF:
9859 n1 = (union node *)stalloc(sizeof (struct nif));
9860 n1->type = NIF;
9861 n1->nif.test = list(0);
9862 if (readtoken() != TTHEN)
9863 synexpect(TTHEN);
9864 n1->nif.ifpart = list(0);
9865 n2 = n1;
9866 while (readtoken() == TELIF) {
9867 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9868 n2 = n2->nif.elsepart;
9869 n2->type = NIF;
9870 n2->nif.test = list(0);
9871 if (readtoken() != TTHEN)
9872 synexpect(TTHEN);
9873 n2->nif.ifpart = list(0);
9874 }
9875 if (lasttoken == TELSE)
9876 n2->nif.elsepart = list(0);
9877 else {
9878 n2->nif.elsepart = NULL;
9879 tokpushback++;
9880 }
9881 if (readtoken() != TFI)
9882 synexpect(TFI);
9883 checkkwd = 1;
9884 break;
9885 case TWHILE:
9886 case TUNTIL: {
9887 int got;
9888 n1 = (union node *)stalloc(sizeof (struct nbinary));
9889 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9890 n1->nbinary.ch1 = list(0);
9891 if ((got=readtoken()) != TDO) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009892TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009893 synexpect(TDO);
9894 }
9895 n1->nbinary.ch2 = list(0);
9896 if (readtoken() != TDONE)
9897 synexpect(TDONE);
9898 checkkwd = 1;
9899 break;
9900 }
9901 case TFOR:
9902 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9903 synerror("Bad for loop variable");
9904 n1 = (union node *)stalloc(sizeof (struct nfor));
9905 n1->type = NFOR;
9906 n1->nfor.var = wordtext;
9907 checkkwd = 1;
9908 if (readtoken() == TIN) {
9909 app = &ap;
9910 while (readtoken() == TWORD) {
9911 n2 = (union node *)stalloc(sizeof (struct narg));
9912 n2->type = NARG;
9913 n2->narg.text = wordtext;
9914 n2->narg.backquote = backquotelist;
9915 *app = n2;
9916 app = &n2->narg.next;
9917 }
9918 *app = NULL;
9919 n1->nfor.args = ap;
9920 if (lasttoken != TNL && lasttoken != TSEMI)
9921 synexpect(-1);
9922 } else {
9923 static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
9924 '@', '=', '\0'};
9925 n2 = (union node *)stalloc(sizeof (struct narg));
9926 n2->type = NARG;
9927 n2->narg.text = argvars;
9928 n2->narg.backquote = NULL;
9929 n2->narg.next = NULL;
9930 n1->nfor.args = n2;
9931 /*
9932 * Newline or semicolon here is optional (but note
9933 * that the original Bourne shell only allowed NL).
9934 */
9935 if (lasttoken != TNL && lasttoken != TSEMI)
9936 tokpushback++;
9937 }
9938 checkkwd = 2;
9939 if (readtoken() != TDO)
9940 synexpect(TDO);
9941 n1->nfor.body = list(0);
9942 if (readtoken() != TDONE)
9943 synexpect(TDONE);
9944 checkkwd = 1;
9945 break;
9946 case TCASE:
9947 n1 = (union node *)stalloc(sizeof (struct ncase));
9948 n1->type = NCASE;
9949 if (readtoken() != TWORD)
9950 synexpect(TWORD);
9951 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9952 n2->type = NARG;
9953 n2->narg.text = wordtext;
9954 n2->narg.backquote = backquotelist;
9955 n2->narg.next = NULL;
9956 do {
9957 checkkwd = 1;
9958 } while (readtoken() == TNL);
9959 if (lasttoken != TIN)
9960 synerror("expecting \"in\"");
9961 cpp = &n1->ncase.cases;
9962 checkkwd = 2, readtoken();
9963 do {
9964 if (lasttoken == TLP)
9965 readtoken();
9966 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9967 cp->type = NCLIST;
9968 app = &cp->nclist.pattern;
9969 for (;;) {
9970 *app = ap = (union node *)stalloc(sizeof (struct narg));
9971 ap->type = NARG;
9972 ap->narg.text = wordtext;
9973 ap->narg.backquote = backquotelist;
9974 if (checkkwd = 2, readtoken() != TPIPE)
9975 break;
9976 app = &ap->narg.next;
9977 readtoken();
9978 }
9979 ap->narg.next = NULL;
9980 if (lasttoken != TRP)
9981 synexpect(TRP);
9982 cp->nclist.body = list(0);
9983
9984 checkkwd = 2;
9985 if ((t = readtoken()) != TESAC) {
9986 if (t != TENDCASE)
9987 synexpect(TENDCASE);
9988 else
9989 checkkwd = 2, readtoken();
9990 }
9991 cpp = &cp->nclist.next;
9992 } while(lasttoken != TESAC);
9993 *cpp = NULL;
9994 checkkwd = 1;
9995 break;
9996 case TLP:
9997 n1 = (union node *)stalloc(sizeof (struct nredir));
9998 n1->type = NSUBSHELL;
9999 n1->nredir.n = list(0);
10000 n1->nredir.redirect = NULL;
10001 if (readtoken() != TRP)
10002 synexpect(TRP);
10003 checkkwd = 1;
10004 break;
10005 case TBEGIN:
10006 n1 = list(0);
10007 if (readtoken() != TEND)
10008 synexpect(TEND);
10009 checkkwd = 1;
10010 break;
10011 /* Handle an empty command like other simple commands. */
10012 case TSEMI:
10013 case TAND:
10014 case TOR:
10015 case TNL:
10016 case TEOF:
10017 case TRP:
10018 case TBACKGND:
10019 /*
10020 * An empty command before a ; doesn't make much sense, and
10021 * should certainly be disallowed in the case of `if ;'.
10022 */
10023 if (!redir)
10024 synexpect(-1);
10025 case TWORD:
10026 case TREDIR:
10027 tokpushback++;
10028 n1 = simplecmd();
10029 return n1;
10030 default:
10031 synexpect(-1);
10032 /* NOTREACHED */
10033 }
10034
10035 /* Now check for redirection which may follow command */
10036 while (readtoken() == TREDIR) {
10037 *rpp = n2 = redirnode;
10038 rpp = &n2->nfile.next;
10039 parsefname();
10040 }
10041 tokpushback++;
10042 *rpp = NULL;
10043 if (redir) {
10044 if (n1->type != NSUBSHELL) {
10045 n2 = (union node *)stalloc(sizeof (struct nredir));
10046 n2->type = NREDIR;
10047 n2->nredir.n = n1;
10048 n1 = n2;
10049 }
10050 n1->nredir.redirect = redir;
10051 }
10052
10053 return n1;
10054}
10055
10056
10057static union node *
10058simplecmd() {
10059 union node *args, **app;
10060 union node *n = NULL;
10061 union node *vars, **vpp;
10062 union node **rpp, *redir;
10063
10064 args = NULL;
10065 app = &args;
10066 vars = NULL;
10067 vpp = &vars;
10068 redir = NULL;
10069 rpp = &redir;
10070
10071 checkalias = 2;
10072 for (;;) {
10073 switch (readtoken()) {
10074 case TWORD:
10075 case TASSIGN:
10076 n = (union node *)stalloc(sizeof (struct narg));
10077 n->type = NARG;
10078 n->narg.text = wordtext;
10079 n->narg.backquote = backquotelist;
10080 if (lasttoken == TWORD) {
10081 *app = n;
10082 app = &n->narg.next;
10083 } else {
10084 *vpp = n;
10085 vpp = &n->narg.next;
10086 }
10087 break;
10088 case TREDIR:
10089 *rpp = n = redirnode;
10090 rpp = &n->nfile.next;
Eric Andersen2870d962001-07-02 17:27:21 +000010091 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +000010092 break;
10093 case TLP:
10094 if (
10095 args && app == &args->narg.next &&
10096 !vars && !redir
10097 ) {
10098 /* We have a function */
10099 if (readtoken() != TRP)
10100 synexpect(TRP);
Eric Andersencb57d552001-06-28 07:25:16 +000010101 n->type = NDEFUN;
10102 checkkwd = 2;
10103 n->narg.next = command();
10104 return n;
10105 }
10106 /* fall through */
10107 default:
10108 tokpushback++;
10109 goto out;
10110 }
10111 }
10112out:
10113 *app = NULL;
10114 *vpp = NULL;
10115 *rpp = NULL;
10116 n = (union node *)stalloc(sizeof (struct ncmd));
10117 n->type = NCMD;
10118 n->ncmd.backgnd = 0;
10119 n->ncmd.args = args;
10120 n->ncmd.assign = vars;
10121 n->ncmd.redirect = redir;
10122 return n;
10123}
10124
10125static union node *
Eric Andersen2870d962001-07-02 17:27:21 +000010126makename(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000010127 union node *n;
10128
10129 n = (union node *)stalloc(sizeof (struct narg));
10130 n->type = NARG;
10131 n->narg.next = NULL;
10132 n->narg.text = wordtext;
10133 n->narg.backquote = backquotelist;
10134 return n;
10135}
10136
10137static void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +000010138{
Eric Andersencb57d552001-06-28 07:25:16 +000010139 TRACE(("Fix redir %s %d\n", text, err));
10140 if (!err)
10141 n->ndup.vname = NULL;
10142
10143 if (is_digit(text[0]) && text[1] == '\0')
10144 n->ndup.dupfd = digit_val(text[0]);
10145 else if (text[0] == '-' && text[1] == '\0')
10146 n->ndup.dupfd = -1;
10147 else {
10148
10149 if (err)
10150 synerror("Bad fd number");
10151 else
10152 n->ndup.vname = makename();
10153 }
10154}
10155
10156
10157static void
Eric Andersen2870d962001-07-02 17:27:21 +000010158parsefname(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000010159 union node *n = redirnode;
10160
10161 if (readtoken() != TWORD)
10162 synexpect(-1);
10163 if (n->type == NHERE) {
10164 struct heredoc *here = heredoc;
10165 struct heredoc *p;
10166 int i;
10167
10168 if (quoteflag == 0)
10169 n->type = NXHERE;
10170 TRACE(("Here document %d\n", n->type));
10171 if (here->striptabs) {
10172 while (*wordtext == '\t')
10173 wordtext++;
10174 }
10175 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
10176 synerror("Illegal eof marker for << redirection");
10177 rmescapes(wordtext);
10178 here->eofmark = wordtext;
10179 here->next = NULL;
10180 if (heredoclist == NULL)
10181 heredoclist = here;
10182 else {
10183 for (p = heredoclist ; p->next ; p = p->next);
10184 p->next = here;
10185 }
10186 } else if (n->type == NTOFD || n->type == NFROMFD) {
10187 fixredir(n, wordtext, 0);
10188 } else {
10189 n->nfile.fname = makename();
10190 }
10191}
10192
10193
10194/*
10195 * Input any here documents.
10196 */
10197
10198static void
10199parseheredoc() {
10200 struct heredoc *here;
10201 union node *n;
10202
10203 while (heredoclist) {
10204 here = heredoclist;
10205 heredoclist = here->next;
10206 if (needprompt) {
10207 setprompt(2);
10208 needprompt = 0;
10209 }
10210 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
10211 here->eofmark, here->striptabs);
10212 n = (union node *)stalloc(sizeof (struct narg));
10213 n->narg.type = NARG;
10214 n->narg.next = NULL;
10215 n->narg.text = wordtext;
10216 n->narg.backquote = backquotelist;
10217 here->here->nhere.doc = n;
10218 }
10219}
10220
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010221static char
Eric Andersencb57d552001-06-28 07:25:16 +000010222peektoken() {
10223 int t;
10224
10225 t = readtoken();
10226 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010227 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +000010228}
10229
10230static int
10231readtoken() {
10232 int t;
Eric Andersen7467c8d2001-07-12 20:26:32 +000010233
Eric Andersen2870d962001-07-02 17:27:21 +000010234#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010235 int savecheckalias = checkalias;
Eric Andersen7467c8d2001-07-12 20:26:32 +000010236 int savecheckkwd = checkkwd;
Eric Andersencb57d552001-06-28 07:25:16 +000010237 struct alias *ap;
Eric Andersen2870d962001-07-02 17:27:21 +000010238#endif
10239
Eric Andersencb57d552001-06-28 07:25:16 +000010240#ifdef DEBUG
10241 int alreadyseen = tokpushback;
10242#endif
10243
Eric Andersen2870d962001-07-02 17:27:21 +000010244#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010245top:
Eric Andersen2870d962001-07-02 17:27:21 +000010246#endif
10247
Eric Andersencb57d552001-06-28 07:25:16 +000010248 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +000010249
10250#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010251 checkalias = savecheckalias;
Eric Andersen2870d962001-07-02 17:27:21 +000010252#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010253
10254 if (checkkwd) {
10255 /*
10256 * eat newlines
10257 */
10258 if (checkkwd == 2) {
10259 checkkwd = 0;
10260 while (t == TNL) {
10261 parseheredoc();
10262 t = xxreadtoken();
10263 }
10264 }
10265 checkkwd = 0;
10266 /*
10267 * check for keywords
10268 */
10269 if (t == TWORD && !quoteflag)
10270 {
10271 const char *const *pp;
10272
10273 if ((pp = findkwd(wordtext))) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010274 lasttoken = t = pp - tokname_array;
10275 TRACE(("keyword %s recognized\n", tokname(t)));
Eric Andersencb57d552001-06-28 07:25:16 +000010276 goto out;
10277 }
10278 }
10279 }
10280
Eric Andersen7467c8d2001-07-12 20:26:32 +000010281
Eric Andersencb57d552001-06-28 07:25:16 +000010282 if (t != TWORD) {
10283 if (t != TREDIR) {
10284 checkalias = 0;
10285 }
10286 } else if (checkalias == 2 && isassignment(wordtext)) {
10287 lasttoken = t = TASSIGN;
Eric Andersen7467c8d2001-07-12 20:26:32 +000010288#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010289 } else if (checkalias) {
10290 if (!quoteflag && (ap = lookupalias(wordtext, 1)) != NULL) {
10291 if (*ap->val) {
10292 pushstring(ap->val, strlen(ap->val), ap);
10293 }
10294 checkkwd = savecheckkwd;
10295 goto top;
10296 }
10297 checkalias = 0;
Eric Andersen2870d962001-07-02 17:27:21 +000010298#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +000010299 }
Eric Andersencb57d552001-06-28 07:25:16 +000010300out:
10301#ifdef DEBUG
10302 if (!alreadyseen)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010303 TRACE(("token %s %s\n", tokname(t), t == TWORD || t == TASSIGN ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +000010304 else
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010305 TRACE(("reread token %s %s\n", tokname(t), t == TWORD || t == TASSIGN ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +000010306#endif
10307 return (t);
10308}
10309
10310
10311/*
10312 * Read the next input token.
10313 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +000010314 * backquotes. We set quoteflag to true if any part of the word was
10315 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +000010316 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +000010317 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +000010318 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +000010319 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +000010320 *
10321 * [Change comment: here documents and internal procedures]
10322 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10323 * word parsing code into a separate routine. In this case, readtoken
10324 * doesn't need to have any internal procedures, but parseword does.
10325 * We could also make parseoperator in essence the main routine, and
10326 * have parseword (readtoken1?) handle both words and redirection.]
10327 */
10328
Eric Andersen2870d962001-07-02 17:27:21 +000010329#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010330
10331static int
10332xxreadtoken() {
10333 int c;
10334
10335 if (tokpushback) {
10336 tokpushback = 0;
10337 return lasttoken;
10338 }
10339 if (needprompt) {
10340 setprompt(2);
10341 needprompt = 0;
10342 }
10343 startlinno = plinno;
Eric Andersen2870d962001-07-02 17:27:21 +000010344 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010345 c = pgetc_macro();
10346 switch (c) {
10347 case ' ': case '\t':
Eric Andersen3102ac42001-07-06 04:26:23 +000010348#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010349 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010350#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010351 continue;
10352 case '#':
10353 while ((c = pgetc()) != '\n' && c != PEOF);
10354 pungetc();
10355 continue;
10356 case '\\':
10357 if (pgetc() == '\n') {
10358 startlinno = ++plinno;
10359 if (doprompt)
10360 setprompt(2);
10361 else
10362 setprompt(0);
10363 continue;
10364 }
10365 pungetc();
10366 goto breakloop;
10367 case '\n':
10368 plinno++;
10369 needprompt = doprompt;
10370 RETURN(TNL);
10371 case PEOF:
10372 RETURN(TEOF);
10373 case '&':
10374 if (pgetc() == '&')
10375 RETURN(TAND);
10376 pungetc();
10377 RETURN(TBACKGND);
10378 case '|':
10379 if (pgetc() == '|')
10380 RETURN(TOR);
10381 pungetc();
10382 RETURN(TPIPE);
10383 case ';':
10384 if (pgetc() == ';')
10385 RETURN(TENDCASE);
10386 pungetc();
10387 RETURN(TSEMI);
10388 case '(':
10389 RETURN(TLP);
10390 case ')':
10391 RETURN(TRP);
10392 default:
10393 goto breakloop;
10394 }
10395 }
10396breakloop:
10397 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10398#undef RETURN
10399}
10400
10401
10402
10403/*
10404 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10405 * is not NULL, read a here document. In the latter case, eofmark is the
10406 * word which marks the end of the document and striptabs is true if
10407 * leading tabs should be stripped from the document. The argument firstc
10408 * is the first character of the input token or document.
10409 *
10410 * Because C does not have internal subroutines, I have simulated them
10411 * using goto's to implement the subroutine linkage. The following macros
10412 * will run code that appears at the end of readtoken1.
10413 */
10414
Eric Andersen2870d962001-07-02 17:27:21 +000010415#define CHECKEND() {goto checkend; checkend_return:;}
10416#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10417#define PARSESUB() {goto parsesub; parsesub_return:;}
10418#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10419#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10420#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010421
10422static int
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010423readtoken1(int firstc, int syntax, const char *eofmark, int striptabs)
10424{
Eric Andersencb57d552001-06-28 07:25:16 +000010425 int c = firstc;
10426 char *out;
10427 int len;
10428 char line[EOFMARKLEN + 1];
10429 struct nodelist *bqlist;
10430 int quotef;
10431 int dblquote;
Eric Andersen2870d962001-07-02 17:27:21 +000010432 int varnest; /* levels of variables expansion */
10433 int arinest; /* levels of arithmetic expansion */
10434 int parenlevel; /* levels of parens in arithmetic */
10435 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +000010436 int oldstyle;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010437 int prevsyntax; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010438#if __GNUC__
10439 /* Avoid longjmp clobbering */
10440 (void) &out;
10441 (void) &quotef;
10442 (void) &dblquote;
10443 (void) &varnest;
10444 (void) &arinest;
10445 (void) &parenlevel;
10446 (void) &dqvarnest;
10447 (void) &oldstyle;
10448 (void) &prevsyntax;
10449 (void) &syntax;
10450#endif
10451
10452 startlinno = plinno;
10453 dblquote = 0;
10454 if (syntax == DQSYNTAX)
10455 dblquote = 1;
10456 quotef = 0;
10457 bqlist = NULL;
10458 varnest = 0;
10459 arinest = 0;
10460 parenlevel = 0;
10461 dqvarnest = 0;
10462
10463 STARTSTACKSTR(out);
Eric Andersen2870d962001-07-02 17:27:21 +000010464 loop: { /* for each line, until end of word */
10465 CHECKEND(); /* set c to PEOF if at end of here document */
10466 for (;;) { /* until end of line or end of word */
10467 CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010468 switch(SIT(c,syntax)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010469 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010470 if (syntax == BASESYNTAX)
Eric Andersen2870d962001-07-02 17:27:21 +000010471 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010472 USTPUTC(c, out);
10473 plinno++;
10474 if (doprompt)
10475 setprompt(2);
10476 else
10477 setprompt(0);
10478 c = pgetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010479 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010480 case CWORD:
10481 USTPUTC(c, out);
10482 break;
10483 case CCTL:
10484 if ((eofmark == NULL || dblquote) &&
10485 dqvarnest == 0)
10486 USTPUTC(CTLESC, out);
10487 USTPUTC(c, out);
10488 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010489 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010490 c = pgetc2();
10491 if (c == PEOF) {
10492 USTPUTC('\\', out);
10493 pungetc();
10494 } else if (c == '\n') {
10495 if (doprompt)
10496 setprompt(2);
10497 else
10498 setprompt(0);
10499 } else {
10500 if (dblquote && c != '\\' && c != '`' && c != '$'
10501 && (c != '"' || eofmark != NULL))
10502 USTPUTC('\\', out);
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010503 if (SIT(c,SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010504 USTPUTC(CTLESC, out);
10505 else if (eofmark == NULL)
10506 USTPUTC(CTLQUOTEMARK, out);
10507 USTPUTC(c, out);
10508 quotef++;
10509 }
10510 break;
10511 case CSQUOTE:
10512 if (eofmark == NULL)
10513 USTPUTC(CTLQUOTEMARK, out);
10514 syntax = SQSYNTAX;
10515 break;
10516 case CDQUOTE:
10517 if (eofmark == NULL)
10518 USTPUTC(CTLQUOTEMARK, out);
10519 syntax = DQSYNTAX;
10520 dblquote = 1;
10521 break;
10522 case CENDQUOTE:
10523 if (eofmark != NULL && arinest == 0 &&
10524 varnest == 0) {
10525 USTPUTC(c, out);
10526 } else {
10527 if (arinest) {
10528 syntax = ARISYNTAX;
10529 dblquote = 0;
10530 } else if (eofmark == NULL &&
10531 dqvarnest == 0) {
10532 syntax = BASESYNTAX;
10533 dblquote = 0;
10534 }
10535 quotef++;
10536 }
10537 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010538 case CVAR: /* '$' */
10539 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010540 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010541 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010542 if (varnest > 0) {
10543 varnest--;
10544 if (dqvarnest > 0) {
10545 dqvarnest--;
10546 }
10547 USTPUTC(CTLENDVAR, out);
10548 } else {
10549 USTPUTC(c, out);
10550 }
10551 break;
10552#ifdef ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +000010553 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010554 parenlevel++;
10555 USTPUTC(c, out);
10556 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010557 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010558 if (parenlevel > 0) {
10559 USTPUTC(c, out);
10560 --parenlevel;
10561 } else {
10562 if (pgetc() == ')') {
10563 if (--arinest == 0) {
10564 USTPUTC(CTLENDARI, out);
10565 syntax = prevsyntax;
10566 if (syntax == DQSYNTAX)
10567 dblquote = 1;
10568 else
10569 dblquote = 0;
10570 } else
10571 USTPUTC(')', out);
10572 } else {
10573 /*
10574 * unbalanced parens
10575 * (don't 2nd guess - no error)
10576 */
10577 pungetc();
10578 USTPUTC(')', out);
10579 }
10580 }
10581 break;
10582#endif
Eric Andersen2870d962001-07-02 17:27:21 +000010583 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010584 PARSEBACKQOLD();
10585 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010586 case CENDFILE:
10587 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010588 case CIGN:
10589 break;
10590 default:
10591 if (varnest == 0)
Eric Andersen2870d962001-07-02 17:27:21 +000010592 goto endword; /* exit outer loop */
Eric Andersen3102ac42001-07-06 04:26:23 +000010593#ifdef ASH_ALIAS
10594 if (c != PEOA)
10595#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010596 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010597
Eric Andersencb57d552001-06-28 07:25:16 +000010598 }
10599 c = pgetc_macro();
10600 }
10601 }
10602endword:
10603 if (syntax == ARISYNTAX)
10604 synerror("Missing '))'");
10605 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10606 synerror("Unterminated quoted string");
10607 if (varnest != 0) {
10608 startlinno = plinno;
10609 synerror("Missing '}'");
10610 }
10611 USTPUTC('\0', out);
10612 len = out - stackblock();
10613 out = stackblock();
10614 if (eofmark == NULL) {
10615 if ((c == '>' || c == '<')
10616 && quotef == 0
10617 && len <= 2
10618 && (*out == '\0' || is_digit(*out))) {
10619 PARSEREDIR();
10620 return lasttoken = TREDIR;
10621 } else {
10622 pungetc();
10623 }
10624 }
10625 quoteflag = quotef;
10626 backquotelist = bqlist;
10627 grabstackblock(len);
10628 wordtext = out;
10629 return lasttoken = TWORD;
10630/* end of readtoken routine */
10631
10632
10633
10634/*
10635 * Check to see whether we are at the end of the here document. When this
10636 * is called, c is set to the first character of the next input line. If
10637 * we are at the end of the here document, this routine sets the c to PEOF.
10638 */
10639
10640checkend: {
10641 if (eofmark) {
Eric Andersen2870d962001-07-02 17:27:21 +000010642#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010643 if (c == PEOA) {
10644 c = pgetc2();
10645 }
Eric Andersen2870d962001-07-02 17:27:21 +000010646#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010647 if (striptabs) {
10648 while (c == '\t') {
10649 c = pgetc2();
10650 }
10651 }
10652 if (c == *eofmark) {
10653 if (pfgets(line, sizeof line) != NULL) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010654 const char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010655
10656 p = line;
10657 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10658 if (*p == '\n' && *q == '\0') {
10659 c = PEOF;
10660 plinno++;
10661 needprompt = doprompt;
10662 } else {
10663 pushstring(line, strlen(line), NULL);
10664 }
10665 }
10666 }
10667 }
10668 goto checkend_return;
10669}
10670
10671
10672/*
10673 * Parse a redirection operator. The variable "out" points to a string
10674 * specifying the fd to be redirected. The variable "c" contains the
10675 * first character of the redirection operator.
10676 */
10677
10678parseredir: {
10679 char fd = *out;
10680 union node *np;
10681
10682 np = (union node *)stalloc(sizeof (struct nfile));
10683 if (c == '>') {
10684 np->nfile.fd = 1;
10685 c = pgetc();
10686 if (c == '>')
10687 np->type = NAPPEND;
10688 else if (c == '&')
10689 np->type = NTOFD;
10690 else if (c == '|')
10691 np->type = NTOOV;
10692 else {
10693 np->type = NTO;
10694 pungetc();
10695 }
Eric Andersen2870d962001-07-02 17:27:21 +000010696 } else { /* c == '<' */
Eric Andersencb57d552001-06-28 07:25:16 +000010697 np->nfile.fd = 0;
10698 switch (c = pgetc()) {
10699 case '<':
10700 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10701 np = (union node *)stalloc(sizeof (struct nhere));
10702 np->nfile.fd = 0;
10703 }
10704 np->type = NHERE;
10705 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10706 heredoc->here = np;
10707 if ((c = pgetc()) == '-') {
10708 heredoc->striptabs = 1;
10709 } else {
10710 heredoc->striptabs = 0;
10711 pungetc();
10712 }
10713 break;
10714
10715 case '&':
10716 np->type = NFROMFD;
10717 break;
10718
10719 case '>':
10720 np->type = NFROMTO;
10721 break;
10722
10723 default:
10724 np->type = NFROM;
10725 pungetc();
10726 break;
10727 }
10728 }
10729 if (fd != '\0')
10730 np->nfile.fd = digit_val(fd);
10731 redirnode = np;
10732 goto parseredir_return;
10733}
10734
10735
10736/*
10737 * Parse a substitution. At this point, we have read the dollar sign
10738 * and nothing else.
10739 */
10740
10741parsesub: {
10742 int subtype;
10743 int typeloc;
10744 int flags;
10745 char *p;
10746 static const char types[] = "}-+?=";
10747
10748 c = pgetc();
10749 if (
10750 c <= PEOA ||
10751 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10752 ) {
10753 USTPUTC('$', out);
10754 pungetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010755 } else if (c == '(') { /* $(command) or $((arith)) */
Eric Andersencb57d552001-06-28 07:25:16 +000010756 if (pgetc() == '(') {
10757 PARSEARITH();
10758 } else {
10759 pungetc();
10760 PARSEBACKQNEW();
10761 }
10762 } else {
10763 USTPUTC(CTLVAR, out);
10764 typeloc = out - stackblock();
10765 USTPUTC(VSNORMAL, out);
10766 subtype = VSNORMAL;
10767 if (c == '{') {
10768 c = pgetc();
10769 if (c == '#') {
10770 if ((c = pgetc()) == '}')
10771 c = '#';
10772 else
10773 subtype = VSLENGTH;
10774 }
10775 else
10776 subtype = 0;
10777 }
10778 if (c > PEOA && is_name(c)) {
10779 do {
10780 STPUTC(c, out);
10781 c = pgetc();
10782 } while (c > PEOA && is_in_name(c));
10783 } else if (is_digit(c)) {
10784 do {
10785 USTPUTC(c, out);
10786 c = pgetc();
10787 } while (is_digit(c));
10788 }
10789 else if (is_special(c)) {
10790 USTPUTC(c, out);
10791 c = pgetc();
10792 }
10793 else
Eric Andersen2870d962001-07-02 17:27:21 +000010794badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010795
10796 STPUTC('=', out);
10797 flags = 0;
10798 if (subtype == 0) {
10799 switch (c) {
10800 case ':':
10801 flags = VSNUL;
10802 c = pgetc();
10803 /*FALLTHROUGH*/
10804 default:
10805 p = strchr(types, c);
10806 if (p == NULL)
10807 goto badsub;
10808 subtype = p - types + VSNORMAL;
10809 break;
10810 case '%':
10811 case '#':
10812 {
10813 int cc = c;
10814 subtype = c == '#' ? VSTRIMLEFT :
10815 VSTRIMRIGHT;
10816 c = pgetc();
10817 if (c == cc)
10818 subtype++;
10819 else
10820 pungetc();
10821 break;
10822 }
10823 }
10824 } else {
10825 pungetc();
10826 }
10827 if (dblquote || arinest)
10828 flags |= VSQUOTE;
10829 *(stackblock() + typeloc) = subtype | flags;
10830 if (subtype != VSNORMAL) {
10831 varnest++;
10832 if (dblquote) {
10833 dqvarnest++;
10834 }
10835 }
10836 }
10837 goto parsesub_return;
10838}
10839
10840
10841/*
10842 * Called to parse command substitutions. Newstyle is set if the command
10843 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10844 * list of commands (passed by reference), and savelen is the number of
10845 * characters on the top of the stack which must be preserved.
10846 */
10847
10848parsebackq: {
10849 struct nodelist **nlpp;
10850 int savepbq;
10851 union node *n;
10852 char *volatile str;
10853 struct jmploc jmploc;
10854 struct jmploc *volatile savehandler;
10855 int savelen;
10856 int saveprompt;
10857#ifdef __GNUC__
10858 (void) &saveprompt;
10859#endif
10860
10861 savepbq = parsebackquote;
10862 if (setjmp(jmploc.loc)) {
10863 if (str)
10864 ckfree(str);
10865 parsebackquote = 0;
10866 handler = savehandler;
10867 longjmp(handler->loc, 1);
10868 }
10869 INTOFF;
10870 str = NULL;
10871 savelen = out - stackblock();
10872 if (savelen > 0) {
10873 str = ckmalloc(savelen);
10874 memcpy(str, stackblock(), savelen);
10875 }
10876 savehandler = handler;
10877 handler = &jmploc;
10878 INTON;
Eric Andersen2870d962001-07-02 17:27:21 +000010879 if (oldstyle) {
10880 /* We must read until the closing backquote, giving special
10881 treatment to some slashes, and then push the string and
10882 reread it as input, interpreting it normally. */
10883 char *pout;
10884 int pc;
10885 int psavelen;
10886 char *pstr;
Eric Andersencb57d552001-06-28 07:25:16 +000010887
10888
Eric Andersen2870d962001-07-02 17:27:21 +000010889 STARTSTACKSTR(pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010890 for (;;) {
10891 if (needprompt) {
10892 setprompt(2);
10893 needprompt = 0;
10894 }
10895 switch (pc = pgetc()) {
10896 case '`':
10897 goto done;
10898
10899 case '\\':
Eric Andersen2870d962001-07-02 17:27:21 +000010900 if ((pc = pgetc()) == '\n') {
Eric Andersencb57d552001-06-28 07:25:16 +000010901 plinno++;
10902 if (doprompt)
10903 setprompt(2);
10904 else
10905 setprompt(0);
10906 /*
10907 * If eating a newline, avoid putting
10908 * the newline into the new character
10909 * stream (via the STPUTC after the
10910 * switch).
10911 */
10912 continue;
10913 }
Eric Andersen2870d962001-07-02 17:27:21 +000010914 if (pc != '\\' && pc != '`' && pc != '$'
10915 && (!dblquote || pc != '"'))
10916 STPUTC('\\', pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010917 if (pc > PEOA) {
10918 break;
10919 }
10920 /* fall through */
10921
10922 case PEOF:
Eric Andersen2870d962001-07-02 17:27:21 +000010923#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010924 case PEOA:
Eric Andersen2870d962001-07-02 17:27:21 +000010925#endif
10926 startlinno = plinno;
Eric Andersencb57d552001-06-28 07:25:16 +000010927 synerror("EOF in backquote substitution");
10928
10929 case '\n':
10930 plinno++;
10931 needprompt = doprompt;
10932 break;
10933
10934 default:
10935 break;
10936 }
10937 STPUTC(pc, pout);
Eric Andersen2870d962001-07-02 17:27:21 +000010938 }
Eric Andersencb57d552001-06-28 07:25:16 +000010939done:
Eric Andersen2870d962001-07-02 17:27:21 +000010940 STPUTC('\0', pout);
10941 psavelen = pout - stackblock();
10942 if (psavelen > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010943 pstr = grabstackstr(pout);
10944 setinputstring(pstr);
Eric Andersen2870d962001-07-02 17:27:21 +000010945 }
10946 }
Eric Andersencb57d552001-06-28 07:25:16 +000010947 nlpp = &bqlist;
10948 while (*nlpp)
10949 nlpp = &(*nlpp)->next;
10950 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10951 (*nlpp)->next = NULL;
10952 parsebackquote = oldstyle;
10953
10954 if (oldstyle) {
10955 saveprompt = doprompt;
10956 doprompt = 0;
10957 }
10958
10959 n = list(0);
10960
10961 if (oldstyle)
10962 doprompt = saveprompt;
10963 else {
10964 if (readtoken() != TRP)
10965 synexpect(TRP);
10966 }
10967
10968 (*nlpp)->n = n;
Eric Andersen2870d962001-07-02 17:27:21 +000010969 if (oldstyle) {
Eric Andersencb57d552001-06-28 07:25:16 +000010970 /*
10971 * Start reading from old file again, ignoring any pushed back
10972 * tokens left from the backquote parsing
10973 */
Eric Andersen2870d962001-07-02 17:27:21 +000010974 popfile();
Eric Andersencb57d552001-06-28 07:25:16 +000010975 tokpushback = 0;
10976 }
10977 while (stackblocksize() <= savelen)
10978 growstackblock();
10979 STARTSTACKSTR(out);
10980 if (str) {
10981 memcpy(out, str, savelen);
10982 STADJUST(savelen, out);
10983 INTOFF;
10984 ckfree(str);
10985 str = NULL;
10986 INTON;
10987 }
10988 parsebackquote = savepbq;
10989 handler = savehandler;
10990 if (arinest || dblquote)
10991 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10992 else
10993 USTPUTC(CTLBACKQ, out);
10994 if (oldstyle)
10995 goto parsebackq_oldreturn;
10996 else
10997 goto parsebackq_newreturn;
10998}
10999
11000/*
11001 * Parse an arithmetic expansion (indicate start of one and set state)
11002 */
11003parsearith: {
11004
11005 if (++arinest == 1) {
11006 prevsyntax = syntax;
11007 syntax = ARISYNTAX;
11008 USTPUTC(CTLARI, out);
11009 if (dblquote)
11010 USTPUTC('"',out);
11011 else
11012 USTPUTC(' ',out);
11013 } else {
11014 /*
11015 * we collapse embedded arithmetic expansion to
11016 * parenthesis, which should be equivalent
11017 */
11018 USTPUTC('(', out);
11019 }
11020 goto parsearith_return;
11021}
11022
11023} /* end of readtoken */
11024
11025
Eric Andersencb57d552001-06-28 07:25:16 +000011026/*
11027 * Returns true if the text contains nothing to expand (no dollar signs
11028 * or backquotes).
11029 */
11030
11031static int
11032noexpand(text)
11033 char *text;
11034 {
11035 char *p;
11036 char c;
11037
11038 p = text;
11039 while ((c = *p++) != '\0') {
11040 if (c == CTLQUOTEMARK)
11041 continue;
11042 if (c == CTLESC)
11043 p++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011044 else if (SIT(c,BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000011045 return 0;
11046 }
11047 return 1;
11048}
11049
11050
11051/*
11052 * Return true if the argument is a legal variable name (a letter or
11053 * underscore followed by zero or more letters, underscores, and digits).
11054 */
11055
11056static int
Eric Andersen2870d962001-07-02 17:27:21 +000011057goodname(const char *name)
11058{
11059 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000011060
11061 p = name;
11062 if (! is_name(*p))
11063 return 0;
11064 while (*++p) {
11065 if (! is_in_name(*p))
11066 return 0;
11067 }
11068 return 1;
11069}
11070
11071
11072/*
11073 * Called when an unexpected token is read during the parse. The argument
11074 * is the token that is expected, or -1 if more than one type of token can
11075 * occur at this point.
11076 */
11077
11078static void
11079synexpect(token)
11080 int token;
11081{
11082 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011083 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000011084
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011085 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
11086 if (token >= 0)
11087 sprintf(msg+l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000011088 synerror(msg);
11089 /* NOTREACHED */
11090}
11091
11092
11093static void
Eric Andersen2870d962001-07-02 17:27:21 +000011094synerror(const char *msg)
11095{
Eric Andersencb57d552001-06-28 07:25:16 +000011096 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +000011097 out2fmt("%s: %d: ", commandname, startlinno);
11098 out2fmt("Syntax error: %s\n", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000011099 error((char *)NULL);
11100 /* NOTREACHED */
11101}
11102
Eric Andersencb57d552001-06-28 07:25:16 +000011103
11104/*
11105 * called by editline -- any expansions to the prompt
11106 * should be added here.
11107 */
Eric Andersen2870d962001-07-02 17:27:21 +000011108static void
Eric Andersen62483552001-07-10 06:09:16 +000011109setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000011110{
Eric Andersen62483552001-07-10 06:09:16 +000011111 char *prompt;
11112 switch (whichprompt) {
11113 case 1:
11114 prompt = ps1val();
11115 break;
11116 case 2:
11117 prompt = ps2val();
11118 break;
11119 default: /* 0 */
11120 prompt = "";
11121 }
11122 putprompt(prompt);
Eric Andersencb57d552001-06-28 07:25:16 +000011123}
11124
Eric Andersencb57d552001-06-28 07:25:16 +000011125
Eric Andersencb57d552001-06-28 07:25:16 +000011126/*
11127 * Code for dealing with input/output redirection.
11128 */
11129
Eric Andersen2870d962001-07-02 17:27:21 +000011130#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000011131#ifndef PIPE_BUF
Eric Andersen2870d962001-07-02 17:27:21 +000011132# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000011133#else
11134# define PIPESIZE PIPE_BUF
11135#endif
11136
11137
Eric Andersen62483552001-07-10 06:09:16 +000011138/*
11139 * Open a file in noclobber mode.
11140 * The code was copied from bash.
11141 */
11142static inline int
11143noclobberopen(const char *fname)
11144{
11145 int r, fd;
11146 struct stat finfo, finfo2;
11147
11148 /*
11149 * If the file exists and is a regular file, return an error
11150 * immediately.
11151 */
11152 r = stat(fname, &finfo);
11153 if (r == 0 && S_ISREG(finfo.st_mode)) {
11154 errno = EEXIST;
11155 return -1;
11156 }
11157
11158 /*
11159 * If the file was not present (r != 0), make sure we open it
11160 * exclusively so that if it is created before we open it, our open
11161 * will fail. Make sure that we do not truncate an existing file.
11162 * Note that we don't turn on O_EXCL unless the stat failed -- if the
11163 * file was not a regular file, we leave O_EXCL off.
11164 */
11165 if (r != 0)
11166 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
11167 fd = open(fname, O_WRONLY|O_CREAT, 0666);
11168
11169 /* If the open failed, return the file descriptor right away. */
11170 if (fd < 0)
11171 return fd;
11172
11173 /*
11174 * OK, the open succeeded, but the file may have been changed from a
11175 * non-regular file to a regular file between the stat and the open.
11176 * We are assuming that the O_EXCL open handles the case where FILENAME
11177 * did not exist and is symlinked to an existing file between the stat
11178 * and open.
11179 */
11180
11181 /*
11182 * If we can open it and fstat the file descriptor, and neither check
11183 * revealed that it was a regular file, and the file has not been
11184 * replaced, return the file descriptor.
11185 */
11186 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
11187 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
11188 return fd;
11189
11190 /* The file has been replaced. badness. */
11191 close(fd);
11192 errno = EEXIST;
11193 return -1;
11194}
Eric Andersencb57d552001-06-28 07:25:16 +000011195
11196/*
Eric Andersen62483552001-07-10 06:09:16 +000011197 * Handle here documents. Normally we fork off a process to write the
11198 * data to a pipe. If the document is short, we can stuff the data in
11199 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000011200 */
11201
Eric Andersen62483552001-07-10 06:09:16 +000011202static inline int
11203openhere(const union node *redir)
11204{
11205 int pip[2];
11206 int len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011207
Eric Andersen62483552001-07-10 06:09:16 +000011208 if (pipe(pip) < 0)
11209 error("Pipe call failed");
11210 if (redir->type == NHERE) {
11211 len = strlen(redir->nhere.doc->narg.text);
11212 if (len <= PIPESIZE) {
11213 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11214 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011215 }
Eric Andersencb57d552001-06-28 07:25:16 +000011216 }
Eric Andersen62483552001-07-10 06:09:16 +000011217 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
11218 close(pip[0]);
11219 signal(SIGINT, SIG_IGN);
11220 signal(SIGQUIT, SIG_IGN);
11221 signal(SIGHUP, SIG_IGN);
11222#ifdef SIGTSTP
11223 signal(SIGTSTP, SIG_IGN);
11224#endif
11225 signal(SIGPIPE, SIG_DFL);
11226 if (redir->type == NHERE)
11227 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11228 else
11229 expandhere(redir->nhere.doc, pip[1]);
11230 _exit(0);
11231 }
11232out:
11233 close(pip[1]);
11234 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000011235}
11236
11237
Eric Andersen62483552001-07-10 06:09:16 +000011238static inline int
11239openredirect(const union node *redir)
11240{
Eric Andersencb57d552001-06-28 07:25:16 +000011241 char *fname;
11242 int f;
11243
11244 switch (redir->nfile.type) {
11245 case NFROM:
11246 fname = redir->nfile.expfname;
11247 if ((f = open(fname, O_RDONLY)) < 0)
11248 goto eopen;
11249 break;
11250 case NFROMTO:
11251 fname = redir->nfile.expfname;
11252 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
11253 goto ecreate;
11254 break;
11255 case NTO:
11256 /* Take care of noclobber mode. */
11257 if (Cflag) {
11258 fname = redir->nfile.expfname;
11259 if ((f = noclobberopen(fname)) < 0)
11260 goto ecreate;
11261 break;
11262 }
11263 case NTOOV:
11264 fname = redir->nfile.expfname;
11265#ifdef O_CREAT
11266 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
11267 goto ecreate;
11268#else
11269 if ((f = creat(fname, 0666)) < 0)
11270 goto ecreate;
11271#endif
11272 break;
11273 case NAPPEND:
11274 fname = redir->nfile.expfname;
11275#ifdef O_APPEND
11276 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
11277 goto ecreate;
11278#else
11279 if ((f = open(fname, O_WRONLY)) < 0
11280 && (f = creat(fname, 0666)) < 0)
11281 goto ecreate;
11282 lseek(f, (off_t)0, 2);
11283#endif
11284 break;
11285 default:
11286#ifdef DEBUG
11287 abort();
11288#endif
11289 /* Fall through to eliminate warning. */
11290 case NTOFD:
11291 case NFROMFD:
11292 f = -1;
11293 break;
11294 case NHERE:
11295 case NXHERE:
11296 f = openhere(redir);
11297 break;
11298 }
11299
11300 return f;
11301ecreate:
11302 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11303eopen:
11304 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11305}
11306
11307
Eric Andersen62483552001-07-10 06:09:16 +000011308/*
11309 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11310 * old file descriptors are stashed away so that the redirection can be
11311 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11312 * standard output, and the standard error if it becomes a duplicate of
11313 * stdout.
11314 */
11315
Eric Andersencb57d552001-06-28 07:25:16 +000011316static void
Eric Andersen62483552001-07-10 06:09:16 +000011317redirect(union node *redir, int flags)
11318{
11319 union node *n;
11320 struct redirtab *sv = NULL;
11321 int i;
11322 int fd;
11323 int newfd;
11324 int try;
11325 int fd1dup = flags & REDIR_BACKQ;; /* stdout `cmd` redir to pipe */
11326
11327 if (flags & REDIR_PUSH) {
11328 sv = ckmalloc(sizeof (struct redirtab));
11329 for (i = 0 ; i < 10 ; i++)
11330 sv->renamed[i] = EMPTY;
11331 sv->next = redirlist;
11332 redirlist = sv;
11333 }
11334 for (n = redir ; n ; n = n->nfile.next) {
11335 fd = n->nfile.fd;
11336 try = 0;
11337 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11338 n->ndup.dupfd == fd)
11339 continue; /* redirect from/to same file descriptor */
11340
11341 INTOFF;
11342 newfd = openredirect(n);
11343 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
11344 if (newfd == fd) {
11345 try++;
11346 } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
11347 switch (errno) {
11348 case EBADF:
11349 if (!try) {
11350 dupredirect(n, newfd, fd1dup);
11351 try++;
11352 break;
11353 }
11354 /* FALLTHROUGH*/
11355 default:
11356 if (newfd >= 0) {
11357 close(newfd);
11358 }
11359 INTON;
11360 error("%d: %m", fd);
11361 /* NOTREACHED */
11362 }
11363 }
11364 if (!try) {
11365 close(fd);
11366 if (flags & REDIR_PUSH) {
11367 sv->renamed[fd] = i;
11368 }
11369 }
11370 } else if (fd != newfd) {
11371 close(fd);
11372 }
11373 if (fd == 0)
11374 fd0_redirected++;
11375 if (!try)
11376 dupredirect(n, newfd, fd1dup);
11377 INTON;
11378 }
11379}
11380
11381
11382static void
11383dupredirect(const union node *redir, int f, int fd1dup)
Eric Andersen2870d962001-07-02 17:27:21 +000011384{
Eric Andersencb57d552001-06-28 07:25:16 +000011385 int fd = redir->nfile.fd;
11386
Eric Andersen62483552001-07-10 06:09:16 +000011387 if(fd==1)
11388 fd1dup = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011389 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Eric Andersen2870d962001-07-02 17:27:21 +000011390 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
Eric Andersen62483552001-07-10 06:09:16 +000011391 if (redir->ndup.dupfd!=1 || fd1dup!=1)
Eric Andersencb57d552001-06-28 07:25:16 +000011392 dup_as_newfd(redir->ndup.dupfd, fd);
11393 }
11394 return;
11395 }
11396
11397 if (f != fd) {
11398 dup_as_newfd(f, fd);
11399 close(f);
11400 }
11401 return;
11402}
11403
11404
Eric Andersencb57d552001-06-28 07:25:16 +000011405
Eric Andersencb57d552001-06-28 07:25:16 +000011406/*
11407 * Undo the effects of the last redirection.
11408 */
11409
11410static void
Eric Andersen2870d962001-07-02 17:27:21 +000011411popredir(void)
11412{
Eric Andersencb57d552001-06-28 07:25:16 +000011413 struct redirtab *rp = redirlist;
11414 int i;
11415
11416 INTOFF;
11417 for (i = 0 ; i < 10 ; i++) {
11418 if (rp->renamed[i] != EMPTY) {
Eric Andersen2870d962001-07-02 17:27:21 +000011419 if (i == 0)
11420 fd0_redirected--;
Eric Andersencb57d552001-06-28 07:25:16 +000011421 close(i);
11422 if (rp->renamed[i] >= 0) {
11423 dup_as_newfd(rp->renamed[i], i);
11424 close(rp->renamed[i]);
11425 }
Eric Andersencb57d552001-06-28 07:25:16 +000011426 }
11427 }
11428 redirlist = rp->next;
11429 ckfree(rp);
11430 INTON;
11431}
11432
11433/*
Eric Andersencb57d552001-06-28 07:25:16 +000011434 * Discard all saved file descriptors.
11435 */
11436
11437static void
Eric Andersen2870d962001-07-02 17:27:21 +000011438clearredir(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000011439 struct redirtab *rp;
11440 int i;
11441
11442 for (rp = redirlist ; rp ; rp = rp->next) {
11443 for (i = 0 ; i < 10 ; i++) {
11444 if (rp->renamed[i] >= 0) {
11445 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011446 }
11447 rp->renamed[i] = EMPTY;
11448 }
11449 }
Eric Andersencb57d552001-06-28 07:25:16 +000011450}
11451
11452
Eric Andersencb57d552001-06-28 07:25:16 +000011453/*
11454 * Copy a file descriptor to be >= to. Returns -1
11455 * if the source file descriptor is closed, EMPTY if there are no unused
11456 * file descriptors left.
11457 */
11458
11459static int
11460dup_as_newfd(from, to)
11461 int from;
11462 int to;
11463{
11464 int newfd;
11465
11466 newfd = fcntl(from, F_DUPFD, to);
11467 if (newfd < 0) {
11468 if (errno == EMFILE)
11469 return EMPTY;
11470 else
Eric Andersen2870d962001-07-02 17:27:21 +000011471 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011472 }
11473 return newfd;
11474}
11475
Eric Andersencb57d552001-06-28 07:25:16 +000011476#ifdef DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +000011477static void shtree (union node *, int, char *, FILE*);
11478static void shcmd (union node *, FILE *);
11479static void sharg (union node *, FILE *);
11480static void indent (int, char *, FILE *);
11481static void trstring (char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011482
11483
11484static void
11485showtree(n)
11486 union node *n;
11487{
11488 trputs("showtree called\n");
11489 shtree(n, 1, NULL, stdout);
11490}
11491
11492
11493static void
11494shtree(n, ind, pfx, fp)
11495 union node *n;
11496 int ind;
11497 char *pfx;
11498 FILE *fp;
11499{
11500 struct nodelist *lp;
11501 const char *s;
11502
11503 if (n == NULL)
11504 return;
11505
11506 indent(ind, pfx, fp);
11507 switch(n->type) {
11508 case NSEMI:
11509 s = "; ";
11510 goto binop;
11511 case NAND:
11512 s = " && ";
11513 goto binop;
11514 case NOR:
11515 s = " || ";
11516binop:
11517 shtree(n->nbinary.ch1, ind, NULL, fp);
11518 /* if (ind < 0) */
11519 fputs(s, fp);
11520 shtree(n->nbinary.ch2, ind, NULL, fp);
11521 break;
11522 case NCMD:
11523 shcmd(n, fp);
11524 if (ind >= 0)
11525 putc('\n', fp);
11526 break;
11527 case NPIPE:
11528 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11529 shcmd(lp->n, fp);
11530 if (lp->next)
11531 fputs(" | ", fp);
11532 }
11533 if (n->npipe.backgnd)
11534 fputs(" &", fp);
11535 if (ind >= 0)
11536 putc('\n', fp);
11537 break;
11538 default:
11539 fprintf(fp, "<node type %d>", n->type);
11540 if (ind >= 0)
11541 putc('\n', fp);
11542 break;
11543 }
11544}
11545
11546
11547
11548static void
11549shcmd(cmd, fp)
11550 union node *cmd;
11551 FILE *fp;
11552{
11553 union node *np;
11554 int first;
11555 const char *s;
11556 int dftfd;
11557
11558 first = 1;
11559 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11560 if (! first)
11561 putchar(' ');
11562 sharg(np, fp);
11563 first = 0;
11564 }
11565 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11566 if (! first)
11567 putchar(' ');
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011568#if 1
11569 s = "*error*";
11570 dftfd = 0;
11571 if ((np->nfile.type <= NFROMFD) && (np->nfile.type >= NTO)) {
11572 s = redir_strings[np->nfile.type - NTO];
11573 if (*s == '>') {
11574 dftfd = 1;
11575 }
11576 }
11577#else
Eric Andersencb57d552001-06-28 07:25:16 +000011578 switch (np->nfile.type) {
Eric Andersen2870d962001-07-02 17:27:21 +000011579 case NTO: s = ">"; dftfd = 1; break;
11580 case NAPPEND: s = ">>"; dftfd = 1; break;
11581 case NTOFD: s = ">&"; dftfd = 1; break;
11582 case NTOOV: s = ">|"; dftfd = 1; break;
11583 case NFROM: s = "<"; dftfd = 0; break;
11584 case NFROMFD: s = "<&"; dftfd = 0; break;
11585 case NFROMTO: s = "<>"; dftfd = 0; break;
11586 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011587 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011588#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011589 if (np->nfile.fd != dftfd)
11590 fprintf(fp, "%d", np->nfile.fd);
11591 fputs(s, fp);
11592 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11593 fprintf(fp, "%d", np->ndup.dupfd);
11594 } else {
11595 sharg(np->nfile.fname, fp);
11596 }
11597 first = 0;
11598 }
11599}
11600
11601
11602
11603static void
11604sharg(arg, fp)
11605 union node *arg;
11606 FILE *fp;
11607 {
11608 char *p;
11609 struct nodelist *bqlist;
11610 int subtype;
11611
11612 if (arg->type != NARG) {
11613 printf("<node type %d>\n", arg->type);
11614 fflush(stdout);
11615 abort();
11616 }
11617 bqlist = arg->narg.backquote;
11618 for (p = arg->narg.text ; *p ; p++) {
11619 switch (*p) {
11620 case CTLESC:
11621 putc(*++p, fp);
11622 break;
11623 case CTLVAR:
11624 putc('$', fp);
11625 putc('{', fp);
11626 subtype = *++p;
11627 if (subtype == VSLENGTH)
11628 putc('#', fp);
11629
11630 while (*p != '=')
11631 putc(*p++, fp);
11632
11633 if (subtype & VSNUL)
11634 putc(':', fp);
11635
11636 switch (subtype & VSTYPE) {
11637 case VSNORMAL:
11638 putc('}', fp);
11639 break;
11640 case VSMINUS:
11641 putc('-', fp);
11642 break;
11643 case VSPLUS:
11644 putc('+', fp);
11645 break;
11646 case VSQUESTION:
11647 putc('?', fp);
11648 break;
11649 case VSASSIGN:
11650 putc('=', fp);
11651 break;
11652 case VSTRIMLEFT:
11653 putc('#', fp);
11654 break;
11655 case VSTRIMLEFTMAX:
11656 putc('#', fp);
11657 putc('#', fp);
11658 break;
11659 case VSTRIMRIGHT:
11660 putc('%', fp);
11661 break;
11662 case VSTRIMRIGHTMAX:
11663 putc('%', fp);
11664 putc('%', fp);
11665 break;
11666 case VSLENGTH:
11667 break;
11668 default:
11669 printf("<subtype %d>", subtype);
11670 }
11671 break;
11672 case CTLENDVAR:
11673 putc('}', fp);
11674 break;
11675 case CTLBACKQ:
11676 case CTLBACKQ|CTLQUOTE:
11677 putc('$', fp);
11678 putc('(', fp);
11679 shtree(bqlist->n, -1, NULL, fp);
11680 putc(')', fp);
11681 break;
11682 default:
11683 putc(*p, fp);
11684 break;
11685 }
11686 }
11687}
11688
11689
11690static void
11691indent(amount, pfx, fp)
11692 int amount;
11693 char *pfx;
11694 FILE *fp;
11695{
11696 int i;
11697
11698 for (i = 0 ; i < amount ; i++) {
11699 if (pfx && i == amount - 1)
11700 fputs(pfx, fp);
11701 putc('\t', fp);
11702 }
11703}
11704#endif
11705
11706
11707
11708/*
11709 * Debugging stuff.
11710 */
11711
11712
11713#ifdef DEBUG
11714FILE *tracefile;
11715
11716#if DEBUG == 2
11717static int debug = 1;
11718#else
11719static int debug = 0;
11720#endif
11721
11722
11723static void
11724trputc(c)
11725 int c;
11726{
11727 if (tracefile == NULL)
11728 return;
11729 putc(c, tracefile);
11730 if (c == '\n')
11731 fflush(tracefile);
11732}
11733
11734static void
11735trace(const char *fmt, ...)
11736{
11737 va_list va;
Eric Andersencb57d552001-06-28 07:25:16 +000011738 va_start(va, fmt);
Eric Andersencb57d552001-06-28 07:25:16 +000011739 if (tracefile != NULL) {
11740 (void) vfprintf(tracefile, fmt, va);
11741 if (strchr(fmt, '\n'))
11742 (void) fflush(tracefile);
11743 }
11744 va_end(va);
11745}
11746
11747
11748static void
11749trputs(s)
11750 const char *s;
11751{
11752 if (tracefile == NULL)
11753 return;
11754 fputs(s, tracefile);
11755 if (strchr(s, '\n'))
11756 fflush(tracefile);
11757}
11758
11759
11760static void
11761trstring(s)
11762 char *s;
11763{
11764 char *p;
11765 char c;
11766
11767 if (tracefile == NULL)
11768 return;
11769 putc('"', tracefile);
11770 for (p = s ; *p ; p++) {
11771 switch (*p) {
11772 case '\n': c = 'n'; goto backslash;
11773 case '\t': c = 't'; goto backslash;
11774 case '\r': c = 'r'; goto backslash;
11775 case '"': c = '"'; goto backslash;
11776 case '\\': c = '\\'; goto backslash;
11777 case CTLESC: c = 'e'; goto backslash;
11778 case CTLVAR: c = 'v'; goto backslash;
11779 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11780 case CTLBACKQ: c = 'q'; goto backslash;
11781 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
Eric Andersen2870d962001-07-02 17:27:21 +000011782backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011783 putc(c, tracefile);
11784 break;
11785 default:
11786 if (*p >= ' ' && *p <= '~')
11787 putc(*p, tracefile);
11788 else {
11789 putc('\\', tracefile);
11790 putc(*p >> 6 & 03, tracefile);
11791 putc(*p >> 3 & 07, tracefile);
11792 putc(*p & 07, tracefile);
11793 }
11794 break;
11795 }
11796 }
11797 putc('"', tracefile);
11798}
11799
11800
11801static void
11802trargs(ap)
11803 char **ap;
11804{
11805 if (tracefile == NULL)
11806 return;
11807 while (*ap) {
11808 trstring(*ap++);
11809 if (*ap)
11810 putc(' ', tracefile);
11811 else
11812 putc('\n', tracefile);
11813 }
11814 fflush(tracefile);
11815}
11816
11817
11818static void
11819opentrace() {
11820 char s[100];
11821#ifdef O_APPEND
11822 int flags;
11823#endif
11824
11825 if (!debug)
11826 return;
11827#ifdef not_this_way
11828 {
11829 char *p;
11830 if ((p = getenv("HOME")) == NULL) {
11831 if (geteuid() == 0)
11832 p = "/";
11833 else
11834 p = "/tmp";
11835 }
Eric Andersen2870d962001-07-02 17:27:21 +000011836 strcpy(s, p);
Eric Andersencb57d552001-06-28 07:25:16 +000011837 strcat(s, "/trace");
11838 }
11839#else
Eric Andersen2870d962001-07-02 17:27:21 +000011840 strcpy(s, "./trace");
Eric Andersencb57d552001-06-28 07:25:16 +000011841#endif /* not_this_way */
11842 if ((tracefile = fopen(s, "a")) == NULL) {
11843 fprintf(stderr, "Can't open %s\n", s);
11844 return;
11845 }
11846#ifdef O_APPEND
11847 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11848 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11849#endif
11850 fputs("\nTracing started.\n", tracefile);
11851 fflush(tracefile);
11852}
11853#endif /* DEBUG */
11854
11855
11856/*
Eric Andersencb57d552001-06-28 07:25:16 +000011857 * The trap builtin.
11858 */
11859
11860static int
11861trapcmd(argc, argv)
11862 int argc;
11863 char **argv;
11864{
11865 char *action;
11866 char **ap;
11867 int signo;
11868
11869 if (argc <= 1) {
11870 for (signo = 0 ; signo < NSIG ; signo++) {
11871 if (trap[signo] != NULL) {
11872 char *p;
Eric Andersen34506362001-08-02 05:02:46 +000011873 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011874
11875 p = single_quote(trap[signo]);
Eric Andersen34506362001-08-02 05:02:46 +000011876 sn = sys_siglist[signo];
11877 if(sn==NULL)
11878 sn = u_signal_names(0, &signo, 0);
11879 if(sn==NULL)
11880 sn = "???";
11881 printf("trap -- %s %s\n", p, sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011882 stunalloc(p);
11883 }
11884 }
11885 return 0;
11886 }
11887 ap = argv + 1;
11888 if (argc == 2)
11889 action = NULL;
11890 else
11891 action = *ap++;
11892 while (*ap) {
11893 if ((signo = decode_signal(*ap, 0)) < 0)
11894 error("%s: bad trap", *ap);
11895 INTOFF;
11896 if (action) {
11897 if (action[0] == '-' && action[1] == '\0')
11898 action = NULL;
11899 else
11900 action = savestr(action);
11901 }
11902 if (trap[signo])
11903 ckfree(trap[signo]);
11904 trap[signo] = action;
11905 if (signo != 0)
11906 setsignal(signo);
11907 INTON;
11908 ap++;
11909 }
11910 return 0;
11911}
11912
11913
11914
Eric Andersencb57d552001-06-28 07:25:16 +000011915
11916
11917
11918/*
11919 * Set the signal handler for the specified signal. The routine figures
11920 * out what it should be set to.
11921 */
11922
11923static void
Eric Andersen2870d962001-07-02 17:27:21 +000011924setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011925{
11926 int action;
11927 char *t;
11928 struct sigaction act;
11929
11930 if ((t = trap[signo]) == NULL)
11931 action = S_DFL;
11932 else if (*t != '\0')
11933 action = S_CATCH;
11934 else
11935 action = S_IGN;
11936 if (rootshell && action == S_DFL) {
11937 switch (signo) {
11938 case SIGINT:
11939 if (iflag || minusc || sflag == 0)
11940 action = S_CATCH;
11941 break;
11942 case SIGQUIT:
11943#ifdef DEBUG
11944 {
Eric Andersencb57d552001-06-28 07:25:16 +000011945
11946 if (debug)
11947 break;
11948 }
11949#endif
11950 /* FALLTHROUGH */
11951 case SIGTERM:
11952 if (iflag)
11953 action = S_IGN;
11954 break;
Eric Andersen2870d962001-07-02 17:27:21 +000011955#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000011956 case SIGTSTP:
11957 case SIGTTOU:
11958 if (mflag)
11959 action = S_IGN;
11960 break;
11961#endif
11962 }
11963 }
11964
11965 t = &sigmode[signo - 1];
11966 if (*t == 0) {
11967 /*
11968 * current setting unknown
11969 */
11970 if (sigaction(signo, 0, &act) == -1) {
11971 /*
11972 * Pretend it worked; maybe we should give a warning
11973 * here, but other shells don't. We don't alter
11974 * sigmode, so that we retry every time.
11975 */
11976 return;
11977 }
11978 if (act.sa_handler == SIG_IGN) {
11979 if (mflag && (signo == SIGTSTP ||
11980 signo == SIGTTIN || signo == SIGTTOU)) {
Eric Andersen2870d962001-07-02 17:27:21 +000011981 *t = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000011982 } else
11983 *t = S_HARD_IGN;
11984 } else {
Eric Andersen2870d962001-07-02 17:27:21 +000011985 *t = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000011986 }
11987 }
11988 if (*t == S_HARD_IGN || *t == action)
11989 return;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011990 act.sa_handler = ((action == S_CATCH) ? onsig
11991 : ((action == S_IGN) ? SIG_IGN : SIG_DFL));
Eric Andersencb57d552001-06-28 07:25:16 +000011992 *t = action;
11993 act.sa_flags = 0;
11994 sigemptyset(&act.sa_mask);
11995 sigaction(signo, &act, 0);
11996}
11997
11998/*
11999 * Ignore a signal.
12000 */
12001
12002static void
12003ignoresig(signo)
12004 int signo;
12005{
12006 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
12007 signal(signo, SIG_IGN);
12008 }
12009 sigmode[signo - 1] = S_HARD_IGN;
12010}
12011
12012
Eric Andersencb57d552001-06-28 07:25:16 +000012013/*
12014 * Signal handler.
12015 */
12016
12017static void
Eric Andersen2870d962001-07-02 17:27:21 +000012018onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000012019{
12020 if (signo == SIGINT && trap[SIGINT] == NULL) {
12021 onint();
12022 return;
12023 }
12024 gotsig[signo - 1] = 1;
12025 pendingsigs++;
12026}
12027
12028
Eric Andersencb57d552001-06-28 07:25:16 +000012029/*
12030 * Called to execute a trap. Perhaps we should avoid entering new trap
12031 * handlers while we are executing a trap handler.
12032 */
12033
12034static void
Eric Andersen2870d962001-07-02 17:27:21 +000012035dotrap(void)
12036{
Eric Andersencb57d552001-06-28 07:25:16 +000012037 int i;
12038 int savestatus;
12039
12040 for (;;) {
12041 for (i = 1 ; ; i++) {
12042 if (gotsig[i - 1])
12043 break;
12044 if (i >= NSIG - 1)
12045 goto done;
12046 }
12047 gotsig[i - 1] = 0;
12048 savestatus=exitstatus;
12049 evalstring(trap[i], 0);
12050 exitstatus=savestatus;
12051 }
12052done:
12053 pendingsigs = 0;
12054}
12055
Eric Andersencb57d552001-06-28 07:25:16 +000012056/*
12057 * Called to exit the shell.
12058 */
12059
12060static void
Eric Andersen2870d962001-07-02 17:27:21 +000012061exitshell(int status)
Eric Andersencb57d552001-06-28 07:25:16 +000012062{
12063 struct jmploc loc1, loc2;
12064 char *p;
12065
12066 TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
12067 if (setjmp(loc1.loc)) {
12068 goto l1;
12069 }
12070 if (setjmp(loc2.loc)) {
12071 goto l2;
12072 }
12073 handler = &loc1;
12074 if ((p = trap[0]) != NULL && *p != '\0') {
12075 trap[0] = NULL;
12076 evalstring(p, 0);
12077 }
Eric Andersen2870d962001-07-02 17:27:21 +000012078l1: handler = &loc2; /* probably unnecessary */
Eric Andersencb57d552001-06-28 07:25:16 +000012079 flushall();
Eric Andersen2870d962001-07-02 17:27:21 +000012080#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000012081 setjobctl(0);
12082#endif
12083l2: _exit(status);
12084 /* NOTREACHED */
12085}
12086
12087static int decode_signal(const char *string, int minsig)
12088{
12089 int signo;
Eric Andersen34506362001-08-02 05:02:46 +000012090 const char *name = u_signal_names(string, &signo, minsig);
Eric Andersencb57d552001-06-28 07:25:16 +000012091
Eric Andersen34506362001-08-02 05:02:46 +000012092 return name ? signo : -1;
Eric Andersencb57d552001-06-28 07:25:16 +000012093}
Eric Andersen34506362001-08-02 05:02:46 +000012094
Eric Andersen2870d962001-07-02 17:27:21 +000012095static struct var **hashvar (const char *);
12096static void showvars (const char *, int, int);
12097static struct var **findvar (struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000012098
12099/*
12100 * Initialize the varable symbol tables and import the environment
12101 */
12102
Eric Andersencb57d552001-06-28 07:25:16 +000012103/*
12104 * This routine initializes the builtin variables. It is called when the
12105 * shell is initialized and again when a shell procedure is spawned.
12106 */
12107
12108static void
12109initvar() {
12110 const struct varinit *ip;
12111 struct var *vp;
12112 struct var **vpp;
12113
12114 for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
12115 if ((vp->flags & VEXPORT) == 0) {
12116 vpp = hashvar(ip->text);
12117 vp->next = *vpp;
12118 *vpp = vp;
12119 vp->text = strdup(ip->text);
12120 vp->flags = ip->flags;
12121 vp->func = ip->func;
12122 }
12123 }
12124 /*
12125 * PS1 depends on uid
12126 */
12127 if ((vps1.flags & VEXPORT) == 0) {
12128 vpp = hashvar("PS1=");
12129 vps1.next = *vpp;
12130 *vpp = &vps1;
12131 vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# ");
12132 vps1.flags = VSTRFIXED|VTEXTFIXED;
12133 }
12134}
12135
12136/*
12137 * Set the value of a variable. The flags argument is ored with the
12138 * flags of the variable. If val is NULL, the variable is unset.
12139 */
12140
12141static void
12142setvar(name, val, flags)
12143 const char *name, *val;
12144 int flags;
12145{
12146 const char *p;
12147 int len;
12148 int namelen;
12149 char *nameeq;
12150 int isbad;
12151 int vallen = 0;
12152
12153 isbad = 0;
12154 p = name;
12155 if (! is_name(*p))
12156 isbad = 1;
12157 p++;
12158 for (;;) {
12159 if (! is_in_name(*p)) {
12160 if (*p == '\0' || *p == '=')
12161 break;
12162 isbad = 1;
12163 }
12164 p++;
12165 }
12166 namelen = p - name;
12167 if (isbad)
12168 error("%.*s: bad variable name", namelen, name);
Eric Andersen2870d962001-07-02 17:27:21 +000012169 len = namelen + 2; /* 2 is space for '=' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +000012170 if (val == NULL) {
12171 flags |= VUNSET;
12172 } else {
12173 len += vallen = strlen(val);
12174 }
12175 INTOFF;
12176 nameeq = ckmalloc(len);
12177 memcpy(nameeq, name, namelen);
12178 nameeq[namelen] = '=';
12179 if (val) {
12180 memcpy(nameeq + namelen + 1, val, vallen + 1);
12181 } else {
12182 nameeq[namelen + 1] = '\0';
12183 }
12184 setvareq(nameeq, flags);
12185 INTON;
12186}
12187
12188
12189
12190/*
12191 * Same as setvar except that the variable and value are passed in
12192 * the first argument as name=value. Since the first argument will
12193 * be actually stored in the table, it should not be a string that
12194 * will go away.
12195 */
12196
12197static void
12198setvareq(s, flags)
12199 char *s;
12200 int flags;
12201{
12202 struct var *vp, **vpp;
12203
12204 vpp = hashvar(s);
12205 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
12206 if ((vp = *findvar(vpp, s))) {
12207 if (vp->flags & VREADONLY) {
12208 size_t len = strchr(s, '=') - s;
12209 error("%.*s: is read only", len, s);
12210 }
12211 INTOFF;
12212
12213 if (vp->func && (flags & VNOFUNC) == 0)
12214 (*vp->func)(strchr(s, '=') + 1);
12215
12216 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12217 ckfree(vp->text);
12218
12219 vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
12220 vp->flags |= flags;
12221 vp->text = s;
12222
12223 /*
12224 * We could roll this to a function, to handle it as
12225 * a regular variable function callback, but why bother?
12226 */
12227 if (iflag && (vp == &vmpath || (vp == &vmail && !mpathset())))
12228 chkmail(1);
12229 INTON;
12230 return;
12231 }
12232 /* not found */
12233 vp = ckmalloc(sizeof (*vp));
12234 vp->flags = flags;
12235 vp->text = s;
12236 vp->next = *vpp;
12237 vp->func = NULL;
12238 *vpp = vp;
12239}
12240
12241
12242
12243/*
12244 * Process a linked list of variable assignments.
12245 */
12246
12247static void
12248listsetvar(mylist)
12249 struct strlist *mylist;
12250 {
12251 struct strlist *lp;
12252
12253 INTOFF;
12254 for (lp = mylist ; lp ; lp = lp->next) {
12255 setvareq(savestr(lp->text), 0);
12256 }
12257 INTON;
12258}
12259
12260
12261
12262/*
12263 * Find the value of a variable. Returns NULL if not set.
12264 */
12265
Eric Andersen62483552001-07-10 06:09:16 +000012266static const char *
Eric Andersencb57d552001-06-28 07:25:16 +000012267lookupvar(name)
12268 const char *name;
12269 {
12270 struct var *v;
12271
12272 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
12273 return strchr(v->text, '=') + 1;
12274 }
12275 return NULL;
12276}
12277
12278
12279
12280/*
12281 * Search the environment of a builtin command.
12282 */
12283
Eric Andersen62483552001-07-10 06:09:16 +000012284static const char *
12285bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012286{
Eric Andersen62483552001-07-10 06:09:16 +000012287 const struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012288
12289 for (sp = cmdenviron ; sp ; sp = sp->next) {
12290 if (varequal(sp->text, name))
12291 return strchr(sp->text, '=') + 1;
12292 }
12293 return lookupvar(name);
12294}
12295
12296
12297
12298/*
12299 * Generate a list of exported variables. This routine is used to construct
12300 * the third argument to execve when executing a program.
12301 */
12302
12303static char **
12304environment() {
12305 int nenv;
12306 struct var **vpp;
12307 struct var *vp;
12308 char **env;
12309 char **ep;
12310
12311 nenv = 0;
12312 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12313 for (vp = *vpp ; vp ; vp = vp->next)
12314 if (vp->flags & VEXPORT)
12315 nenv++;
12316 }
12317 ep = env = stalloc((nenv + 1) * sizeof *env);
12318 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12319 for (vp = *vpp ; vp ; vp = vp->next)
12320 if (vp->flags & VEXPORT)
12321 *ep++ = vp->text;
12322 }
12323 *ep = NULL;
12324 return env;
12325}
12326
12327
12328/*
12329 * Called when a shell procedure is invoked to clear out nonexported
12330 * variables. It is also necessary to reallocate variables of with
12331 * VSTACK set since these are currently allocated on the stack.
12332 */
12333
Eric Andersencb57d552001-06-28 07:25:16 +000012334static void
Eric Andersen2870d962001-07-02 17:27:21 +000012335shprocvar(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000012336 struct var **vpp;
12337 struct var *vp, **prev;
12338
12339 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12340 for (prev = vpp ; (vp = *prev) != NULL ; ) {
12341 if ((vp->flags & VEXPORT) == 0) {
12342 *prev = vp->next;
12343 if ((vp->flags & VTEXTFIXED) == 0)
12344 ckfree(vp->text);
12345 if ((vp->flags & VSTRFIXED) == 0)
12346 ckfree(vp);
12347 } else {
12348 if (vp->flags & VSTACK) {
12349 vp->text = savestr(vp->text);
12350 vp->flags &=~ VSTACK;
12351 }
12352 prev = &vp->next;
12353 }
12354 }
12355 }
12356 initvar();
12357}
12358
12359
12360
12361/*
12362 * Command to list all variables which are set. Currently this command
12363 * is invoked from the set command when the set command is called without
12364 * any variables.
12365 */
12366
12367static int
12368showvarscmd(argc, argv)
12369 int argc;
12370 char **argv;
12371{
12372 showvars(nullstr, VUNSET, VUNSET);
12373 return 0;
12374}
12375
12376
12377
12378/*
12379 * The export and readonly commands.
12380 */
12381
12382static int
12383exportcmd(argc, argv)
12384 int argc;
12385 char **argv;
12386{
12387 struct var *vp;
12388 char *name;
12389 const char *p;
12390 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12391 int pflag;
12392
12393 listsetvar(cmdenviron);
12394 pflag = (nextopt("p") == 'p');
12395 if (argc > 1 && !pflag) {
12396 while ((name = *argptr++) != NULL) {
12397 if ((p = strchr(name, '=')) != NULL) {
12398 p++;
12399 } else {
12400 if ((vp = *findvar(hashvar(name), name))) {
12401 vp->flags |= flag;
12402 goto found;
12403 }
12404 }
12405 setvar(name, p, flag);
12406found:;
12407 }
12408 } else {
12409 showvars(argv[0], flag, 0);
12410 }
12411 return 0;
12412}
12413
Eric Andersen34506362001-08-02 05:02:46 +000012414
Eric Andersencb57d552001-06-28 07:25:16 +000012415/*
12416 * The "local" command.
12417 */
12418
Eric Andersen2870d962001-07-02 17:27:21 +000012419/* funcnest nonzero if we are currently evaluating a function */
12420
Eric Andersencb57d552001-06-28 07:25:16 +000012421static int
12422localcmd(argc, argv)
12423 int argc;
12424 char **argv;
12425{
12426 char *name;
12427
Eric Andersen2870d962001-07-02 17:27:21 +000012428 if (! funcnest)
Eric Andersencb57d552001-06-28 07:25:16 +000012429 error("Not in a function");
12430 while ((name = *argptr++) != NULL) {
12431 mklocal(name);
12432 }
12433 return 0;
12434}
12435
12436
12437/*
12438 * Make a variable a local variable. When a variable is made local, it's
12439 * value and flags are saved in a localvar structure. The saved values
12440 * will be restored when the shell function returns. We handle the name
12441 * "-" as a special case.
12442 */
12443
12444static void
12445mklocal(name)
12446 char *name;
12447 {
12448 struct localvar *lvp;
12449 struct var **vpp;
12450 struct var *vp;
12451
12452 INTOFF;
12453 lvp = ckmalloc(sizeof (struct localvar));
12454 if (name[0] == '-' && name[1] == '\0') {
12455 char *p;
Eric Andersen2870d962001-07-02 17:27:21 +000012456 p = ckmalloc(sizeof optet_vals);
12457 lvp->text = memcpy(p, optet_vals, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000012458 vp = NULL;
12459 } else {
12460 vpp = hashvar(name);
12461 vp = *findvar(vpp, name);
12462 if (vp == NULL) {
12463 if (strchr(name, '='))
12464 setvareq(savestr(name), VSTRFIXED);
12465 else
12466 setvar(name, NULL, VSTRFIXED);
Eric Andersen2870d962001-07-02 17:27:21 +000012467 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012468 lvp->text = NULL;
12469 lvp->flags = VUNSET;
12470 } else {
12471 lvp->text = vp->text;
12472 lvp->flags = vp->flags;
12473 vp->flags |= VSTRFIXED|VTEXTFIXED;
12474 if (strchr(name, '='))
12475 setvareq(savestr(name), 0);
12476 }
12477 }
12478 lvp->vp = vp;
12479 lvp->next = localvars;
12480 localvars = lvp;
12481 INTON;
12482}
12483
12484
12485/*
12486 * Called after a function returns.
12487 */
12488
12489static void
12490poplocalvars() {
12491 struct localvar *lvp;
12492 struct var *vp;
12493
12494 while ((lvp = localvars) != NULL) {
12495 localvars = lvp->next;
12496 vp = lvp->vp;
Eric Andersen2870d962001-07-02 17:27:21 +000012497 if (vp == NULL) { /* $- saved */
12498 memcpy(optet_vals, lvp->text, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000012499 ckfree(lvp->text);
12500 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12501 (void)unsetvar(vp->text);
12502 } else {
12503 if ((vp->flags & VTEXTFIXED) == 0)
12504 ckfree(vp->text);
12505 vp->flags = lvp->flags;
12506 vp->text = lvp->text;
12507 }
12508 ckfree(lvp);
12509 }
12510}
12511
12512
12513static int
12514setvarcmd(argc, argv)
12515 int argc;
12516 char **argv;
12517{
12518 if (argc <= 2)
12519 return unsetcmd(argc, argv);
12520 else if (argc == 3)
12521 setvar(argv[1], argv[2], 0);
12522 else
12523 error("List assignment not implemented");
12524 return 0;
12525}
12526
12527
12528/*
12529 * The unset builtin command. We unset the function before we unset the
12530 * variable to allow a function to be unset when there is a readonly variable
12531 * with the same name.
12532 */
12533
12534static int
12535unsetcmd(argc, argv)
12536 int argc;
12537 char **argv;
12538{
12539 char **ap;
12540 int i;
12541 int flg_func = 0;
12542 int flg_var = 0;
12543 int ret = 0;
12544
12545 while ((i = nextopt("vf")) != '\0') {
12546 if (i == 'f')
12547 flg_func = 1;
12548 else
12549 flg_var = 1;
12550 }
12551 if (flg_func == 0 && flg_var == 0)
12552 flg_var = 1;
12553
12554 for (ap = argptr; *ap ; ap++) {
12555 if (flg_func)
12556 unsetfunc(*ap);
12557 if (flg_var)
12558 ret |= unsetvar(*ap);
12559 }
12560 return ret;
12561}
12562
12563
12564/*
12565 * Unset the specified variable.
12566 */
12567
12568static int
Eric Andersen62483552001-07-10 06:09:16 +000012569unsetvar(const char *s)
12570{
Eric Andersencb57d552001-06-28 07:25:16 +000012571 struct var **vpp;
12572 struct var *vp;
12573
12574 vpp = findvar(hashvar(s), s);
12575 vp = *vpp;
12576 if (vp) {
12577 if (vp->flags & VREADONLY)
12578 return (1);
12579 INTOFF;
12580 if (*(strchr(vp->text, '=') + 1) != '\0')
12581 setvar(s, nullstr, 0);
12582 vp->flags &= ~VEXPORT;
12583 vp->flags |= VUNSET;
12584 if ((vp->flags & VSTRFIXED) == 0) {
12585 if ((vp->flags & VTEXTFIXED) == 0)
12586 ckfree(vp->text);
12587 *vpp = vp->next;
12588 ckfree(vp);
12589 }
12590 INTON;
12591 return (0);
12592 }
12593
12594 return (0);
12595}
12596
12597
12598
12599/*
12600 * Find the appropriate entry in the hash table from the name.
12601 */
12602
12603static struct var **
Eric Andersen62483552001-07-10 06:09:16 +000012604hashvar(const char *p)
12605{
Eric Andersencb57d552001-06-28 07:25:16 +000012606 unsigned int hashval;
12607
12608 hashval = ((unsigned char) *p) << 4;
12609 while (*p && *p != '=')
12610 hashval += (unsigned char) *p++;
12611 return &vartab[hashval % VTABSIZE];
12612}
12613
12614
12615
12616/*
12617 * Returns true if the two strings specify the same varable. The first
12618 * variable name is terminated by '='; the second may be terminated by
12619 * either '=' or '\0'.
12620 */
12621
12622static int
Eric Andersen62483552001-07-10 06:09:16 +000012623varequal(const char *p, const char *q)
12624{
Eric Andersencb57d552001-06-28 07:25:16 +000012625 while (*p == *q++) {
12626 if (*p++ == '=')
12627 return 1;
12628 }
12629 if (*p == '=' && *(q - 1) == '\0')
12630 return 1;
12631 return 0;
12632}
12633
12634static void
12635showvars(const char *myprefix, int mask, int xor)
12636{
12637 struct var **vpp;
12638 struct var *vp;
12639 const char *sep = myprefix == nullstr ? myprefix : spcstr;
12640
12641 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12642 for (vp = *vpp ; vp ; vp = vp->next) {
12643 if ((vp->flags & mask) ^ xor) {
12644 char *p;
12645 int len;
12646
12647 p = strchr(vp->text, '=') + 1;
12648 len = p - vp->text;
12649 p = single_quote(p);
12650
Eric Andersen62483552001-07-10 06:09:16 +000012651 printf("%s%s%.*s%s\n", myprefix, sep, len,
12652 vp->text, p);
Eric Andersencb57d552001-06-28 07:25:16 +000012653 stunalloc(p);
12654 }
12655 }
12656 }
12657}
12658
12659static struct var **
12660findvar(struct var **vpp, const char *name)
12661{
12662 for (; *vpp; vpp = &(*vpp)->next) {
12663 if (varequal((*vpp)->text, name)) {
12664 break;
12665 }
12666 }
12667 return vpp;
12668}
12669
12670/*
12671 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
12672 * This file contains code for the times builtin.
Manuel Novoa III 16815d42001-08-10 19:36:07 +000012673 * $Id: ash.c,v 1.20 2001/08/10 19:36:07 mjn3 Exp $
Eric Andersencb57d552001-06-28 07:25:16 +000012674 */
12675static int timescmd (int argc, char **argv)
12676{
12677 struct tms buf;
12678 long int clk_tck = sysconf(_SC_CLK_TCK);
12679
12680 times(&buf);
12681 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
12682 (int) (buf.tms_utime / clk_tck / 60),
12683 ((double) buf.tms_utime) / clk_tck,
12684 (int) (buf.tms_stime / clk_tck / 60),
12685 ((double) buf.tms_stime) / clk_tck,
12686 (int) (buf.tms_cutime / clk_tck / 60),
12687 ((double) buf.tms_cutime) / clk_tck,
12688 (int) (buf.tms_cstime / clk_tck / 60),
12689 ((double) buf.tms_cstime) / clk_tck);
12690 return 0;
12691}
12692
Eric Andersen74bcd162001-07-30 21:41:37 +000012693#ifdef ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012694/* The let builtin. */
12695int letcmd(int argc, char **argv)
Eric Andersen74bcd162001-07-30 21:41:37 +000012696{
Eric Andersen34506362001-08-02 05:02:46 +000012697 int errcode;
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012698 long result=0;
12699 if (argc == 2) {
12700 char *tmp, *expression, p[13];
12701 expression = strchr(argv[1], '=');
12702 if (!expression) {
Eric Andersen34506362001-08-02 05:02:46 +000012703 /* Cannot use 'error()' here, or the return code
12704 * will be incorrect */
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012705 out2fmt("sh: let: syntax error: \"%s\"\n", argv[1]);
12706 return 0;
Eric Andersen74bcd162001-07-30 21:41:37 +000012707 }
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012708 *expression = '\0';
12709 tmp = ++expression;
Eric Andersen34506362001-08-02 05:02:46 +000012710 result = arith(tmp, &errcode);
12711 if (errcode < 0) {
12712 /* Cannot use 'error()' here, or the return code
12713 * will be incorrect */
12714 out2fmt("sh: let: ");
12715 if(errcode == -2)
12716 out2fmt("divide by zero");
12717 else
12718 out2fmt("syntax error: \"%s=%s\"\n", argv[1], expression);
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012719 return 0;
12720 }
12721 snprintf(p, 12, "%ld", result);
12722 setvar(argv[1], savestr(p), 0);
12723 } else if (argc >= 3)
12724 synerror("invalid operand");
12725 return !result;
Eric Andersen74bcd162001-07-30 21:41:37 +000012726}
12727#endif
12728
12729
12730
Eric Andersendf82f612001-06-28 07:46:40 +000012731/*-
12732 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000012733 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000012734 *
12735 * This code is derived from software contributed to Berkeley by
12736 * Kenneth Almquist.
12737 *
12738 * Redistribution and use in source and binary forms, with or without
12739 * modification, are permitted provided that the following conditions
12740 * are met:
12741 * 1. Redistributions of source code must retain the above copyright
12742 * notice, this list of conditions and the following disclaimer.
12743 * 2. Redistributions in binary form must reproduce the above copyright
12744 * notice, this list of conditions and the following disclaimer in the
12745 * documentation and/or other materials provided with the distribution.
12746 *
Eric Andersen2870d962001-07-02 17:27:21 +000012747 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
12748 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000012749 *
12750 * 4. Neither the name of the University nor the names of its contributors
12751 * may be used to endorse or promote products derived from this software
12752 * without specific prior written permission.
12753 *
12754 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
12755 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
12756 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
12757 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
12758 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
12759 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
12760 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
12761 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
12762 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
12763 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
12764 * SUCH DAMAGE.
12765 */