blob: bd34c0efb712715b40376276fe4366a113e99914 [file] [log] [blame]
Eric Andersendf82f612001-06-28 07:46:40 +00001/* vi: set sw=4 ts=4: */
2/*
3 * ash shell port for busybox
4 *
5 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +00006 * The Regents of the University of California. All rights reserved.
Eric Andersencb57d552001-06-28 07:25:16 +00007 *
8 * This code is derived from software contributed to Berkeley by
9 * Kenneth Almquist.
10 *
Eric Andersendf82f612001-06-28 07:46:40 +000011 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
Eric Andersencb57d552001-06-28 07:25:16 +000015 *
Eric Andersendf82f612001-06-28 07:46:40 +000016 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
Eric Andersen2870d962001-07-02 17:27:21 +000025 * This version of ash is adapted from the source in Debian's ash 0.3.8-5
26 * package.
Eric Andersendf82f612001-06-28 07:46:40 +000027 *
Eric Andersen2870d962001-07-02 17:27:21 +000028 * Modified by Erik Andersen <andersee@debian.org> and
Eric Andersen7467c8d2001-07-12 20:26:32 +000029 * Vladimir Oleynik <dzo@simtreas.ru> to be used in busybox
Eric Andersen2870d962001-07-02 17:27:21 +000030 *
Eric Andersendf82f612001-06-28 07:46:40 +000031 *
32 * Original copyright notice is retained at the end of this file.
Eric Andersencb57d552001-06-28 07:25:16 +000033 */
34
Eric Andersen2870d962001-07-02 17:27:21 +000035
36/* These defines allow you to adjust the feature set to be compiled
37 * into the ash shell. As a rule, enabling these options will make
38 * ash get bigger... With all of these options off, ash adds about
Eric Andersen62483552001-07-10 06:09:16 +000039 * 60k to busybox on an x86 system.*/
Eric Andersen2870d962001-07-02 17:27:21 +000040
41
42/* Enable job control. This allows you to run jobs in the background,
43 * which is great when ash is being used as an interactive shell, but
Eric Andersen3102ac42001-07-06 04:26:23 +000044 * it completely useless for is all you are doing is running scripts.
Eric Andersen2870d962001-07-02 17:27:21 +000045 * This adds about 2.5k on an x86 system. */
Eric Andersen62483552001-07-10 06:09:16 +000046#undef JOBS
Eric Andersen2870d962001-07-02 17:27:21 +000047
48/* This enables alias support in ash. If you want to support things
49 * like "alias ls='ls -l'" with ash, enable this. This is only useful
50 * when ash is used as an intractive shell. This adds about 1.5k */
51#define ASH_ALIAS
52
53/* If you need ash to act as a full Posix shell, with full math
Eric Andersen74bcd162001-07-30 21:41:37 +000054 * support, enable this. This adds a bit over 2k an x86 system. */
Eric Andersen34506362001-08-02 05:02:46 +000055//#undef ASH_MATH_SUPPORT
Eric Andersen74bcd162001-07-30 21:41:37 +000056#define ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +000057
Eric Andersen2870d962001-07-02 17:27:21 +000058/* Getopts is used by shell procedures to parse positional parameters.
59 * You probably want to leave this disabled, and use the busybox getopt
60 * applet if you want to do this sort of thing. There are some scripts
Manuel Novoa III 16815d42001-08-10 19:36:07 +000061 * out there that use it, so it you need it, enable. Most people will
Eric Andersen2870d962001-07-02 17:27:21 +000062 * leave this disabled. This adds 1k on an x86 system. */
63#undef ASH_GETOPTS
64
65/* This allows you to override shell builtins and use whatever is on
66 * the filesystem. This is most useful when ash is acting as a
Eric Andersen62483552001-07-10 06:09:16 +000067 * standalone shell. Adds about 272 bytes. */
Eric Andersen2870d962001-07-02 17:27:21 +000068#undef ASH_CMDCMD
69
Eric Andersen2870d962001-07-02 17:27:21 +000070
Eric Andersen3102ac42001-07-06 04:26:23 +000071/* Optimize size vs speed as size */
72#define ASH_OPTIMIZE_FOR_SIZE
73
Eric Andersen2870d962001-07-02 17:27:21 +000074/* Enable this to compile in extra debugging noise. When debugging is
75 * on, debugging info will be written to $HOME/trace and a quit signal
76 * will generate a core dump. */
77#undef DEBUG
78
Eric Andersen2870d962001-07-02 17:27:21 +000079/* These are here to work with glibc -- Don't change these... */
Eric Andersendf82f612001-06-28 07:46:40 +000080#undef FNMATCH_BROKEN
81#undef GLOB_BROKEN
Eric Andersencb57d552001-06-28 07:25:16 +000082
83#include <assert.h>
Manuel Novoa III 16815d42001-08-10 19:36:07 +000084#include <stddef.h>
Eric Andersencb57d552001-06-28 07:25:16 +000085#include <ctype.h>
86#include <dirent.h>
87#include <errno.h>
88#include <fcntl.h>
89#include <limits.h>
90#include <paths.h>
91#include <pwd.h>
92#include <setjmp.h>
93#include <signal.h>
94#include <stdarg.h>
Eric Andersencb57d552001-06-28 07:25:16 +000095#include <stdio.h>
96#include <stdlib.h>
97#include <string.h>
98#include <sysexits.h>
99#include <unistd.h>
100#include <sys/stat.h>
101#include <sys/cdefs.h>
102#include <sys/ioctl.h>
103#include <sys/param.h>
104#include <sys/resource.h>
105#include <sys/time.h>
106#include <sys/times.h>
107#include <sys/types.h>
108#include <sys/wait.h>
109
110
111#if !defined(FNMATCH_BROKEN)
112#include <fnmatch.h>
113#endif
114#if !defined(GLOB_BROKEN)
115#include <glob.h>
116#endif
117
Eric Andersen2870d962001-07-02 17:27:21 +0000118#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +0000119#include <termios.h>
Eric Andersencb57d552001-06-28 07:25:16 +0000120#endif
121
Eric Andersencb57d552001-06-28 07:25:16 +0000122#include "busybox.h"
Eric Andersen2870d962001-07-02 17:27:21 +0000123#include "cmdedit.h"
124
Eric Andersen2870d962001-07-02 17:27:21 +0000125/*
126 * This file was generated by the mksyntax program.
127 */
128
129/* Syntax classes */
130#define CWORD 0 /* character is nothing special */
131#define CNL 1 /* newline character */
132#define CBACK 2 /* a backslash character */
133#define CSQUOTE 3 /* single quote */
134#define CDQUOTE 4 /* double quote */
135#define CENDQUOTE 5 /* a terminating quote */
136#define CBQUOTE 6 /* backwards single quote */
137#define CVAR 7 /* a dollar sign */
138#define CENDVAR 8 /* a '}' character */
139#define CLP 9 /* a left paren in arithmetic */
140#define CRP 10 /* a right paren in arithmetic */
141#define CENDFILE 11 /* end of file */
142#define CCTL 12 /* like CWORD, except it must be escaped */
143#define CSPCL 13 /* these terminate a word */
144#define CIGN 14 /* character should be ignored */
145
Eric Andersen2870d962001-07-02 17:27:21 +0000146#define SYNBASE 130
147#define PEOF -130
148
149#define PEOA -129
150
151#define TEOF 0
152#define TNL 1
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000153#define TREDIR 2
154#define TWORD 3
155#define TASSIGN 4
156#define TSEMI 5
157#define TBACKGND 6
158#define TAND 7
159#define TOR 8
160#define TPIPE 9
161#define TLP 10
162#define TRP 11
163#define TENDCASE 12
164#define TENDBQUOTE 13
Eric Andersen2870d962001-07-02 17:27:21 +0000165#define TNOT 14
166#define TCASE 15
167#define TDO 16
168#define TDONE 17
169#define TELIF 18
170#define TELSE 19
171#define TESAC 20
172#define TFI 21
173#define TFOR 22
174#define TIF 23
175#define TIN 24
176#define TTHEN 25
177#define TUNTIL 26
178#define TWHILE 27
179#define TBEGIN 28
180#define TEND 29
181
182
Eric Andersen2870d962001-07-02 17:27:21 +0000183
184/* control characters in argument strings */
185#define CTLESC '\201'
186#define CTLVAR '\202'
187#define CTLENDVAR '\203'
188#define CTLBACKQ '\204'
189#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
190/* CTLBACKQ | CTLQUOTE == '\205' */
191#define CTLARI '\206'
192#define CTLENDARI '\207'
193#define CTLQUOTEMARK '\210'
194
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000195
Eric Andersen62483552001-07-10 06:09:16 +0000196#define is_digit(c) ((c)>='0' && (c)<='9')
Eric Andersen2870d962001-07-02 17:27:21 +0000197#define is_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalpha((unsigned char) (c))))
198#define is_in_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalnum((unsigned char) (c))))
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000199
200/*
201 * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
202 * (assuming ascii char codes, as the original implementation did)
203 */
204#define is_special(c) \
205 ( (((unsigned int)c) - 33 < 32) \
206 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
207
Eric Andersen2870d962001-07-02 17:27:21 +0000208#define digit_val(c) ((c) - '0')
Eric Andersencb57d552001-06-28 07:25:16 +0000209
210
211#define _DIAGASSERT(x)
212
Eric Andersen3102ac42001-07-06 04:26:23 +0000213
Eric Andersencb57d552001-06-28 07:25:16 +0000214
Eric Andersen2870d962001-07-02 17:27:21 +0000215#define S_DFL 1 /* default signal handling (SIG_DFL) */
216#define S_CATCH 2 /* signal is caught */
217#define S_IGN 3 /* signal is ignored (SIG_IGN) */
218#define S_HARD_IGN 4 /* signal is ignored permenantly */
219#define S_RESET 5 /* temporary - to reset a hard ignored sig */
Eric Andersencb57d552001-06-28 07:25:16 +0000220
221
Eric Andersen2870d962001-07-02 17:27:21 +0000222/* variable substitution byte (follows CTLVAR) */
223#define VSTYPE 0x0f /* type of variable substitution */
224#define VSNUL 0x10 /* colon--treat the empty string as unset */
225#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
Eric Andersencb57d552001-06-28 07:25:16 +0000226
Eric Andersen2870d962001-07-02 17:27:21 +0000227/* values of VSTYPE field */
228#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
229#define VSMINUS 0x2 /* ${var-text} */
230#define VSPLUS 0x3 /* ${var+text} */
231#define VSQUESTION 0x4 /* ${var?message} */
232#define VSASSIGN 0x5 /* ${var=text} */
233#define VSTRIMLEFT 0x6 /* ${var#pattern} */
234#define VSTRIMLEFTMAX 0x7 /* ${var##pattern} */
235#define VSTRIMRIGHT 0x8 /* ${var%pattern} */
236#define VSTRIMRIGHTMAX 0x9 /* ${var%%pattern} */
237#define VSLENGTH 0xa /* ${#var} */
Eric Andersencb57d552001-06-28 07:25:16 +0000238
Eric Andersen2870d962001-07-02 17:27:21 +0000239/* flags passed to redirect */
240#define REDIR_PUSH 01 /* save previous values of file descriptors */
Eric Andersen3102ac42001-07-06 04:26:23 +0000241#define REDIR_BACKQ 02 /* save the command output to pipe */
Eric Andersencb57d552001-06-28 07:25:16 +0000242
Eric Andersen2870d962001-07-02 17:27:21 +0000243/*
244 * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
245 * so we use _setjmp instead.
246 */
247
Eric Andersen62483552001-07-10 06:09:16 +0000248#if defined(BSD)
Eric Andersen2870d962001-07-02 17:27:21 +0000249#define setjmp(jmploc) _setjmp(jmploc)
250#define longjmp(jmploc, val) _longjmp(jmploc, val)
251#endif
252
253/*
254 * Most machines require the value returned from malloc to be aligned
255 * in some way. The following macro will get this right on many machines.
256 */
257
258#ifndef ALIGN
259union align {
260 int i;
261 char *cp;
262};
263
264#define ALIGN(nbytes) (((nbytes) + sizeof(union align) - 1) & ~(sizeof(union align) - 1))
265#endif
266
267#ifdef BB_LOCALE_SUPPORT
268#include <locale.h>
269static void change_lc_all(const char *value);
270static void change_lc_ctype(const char *value);
271#endif
272
273/*
274 * These macros allow the user to suspend the handling of interrupt signals
275 * over a period of time. This is similar to SIGHOLD to or sigblock, but
276 * much more efficient and portable. (But hacking the kernel is so much
277 * more fun than worrying about efficiency and portability. :-))
278 */
279
280static void onint (void);
281static volatile int suppressint;
282static volatile int intpending;
283
284#define INTOFF suppressint++
Eric Andersen3102ac42001-07-06 04:26:23 +0000285#ifndef ASH_OPTIMIZE_FOR_SIZE
Eric Andersen2870d962001-07-02 17:27:21 +0000286#define INTON { if (--suppressint == 0 && intpending) onint(); }
Eric Andersen3102ac42001-07-06 04:26:23 +0000287#define FORCEINTON {suppressint = 0; if (intpending) onint();}
Eric Andersen2870d962001-07-02 17:27:21 +0000288#else
289static void __inton (void);
Eric Andersen3102ac42001-07-06 04:26:23 +0000290static void forceinton (void);
Eric Andersen2870d962001-07-02 17:27:21 +0000291#define INTON __inton()
Eric Andersen3102ac42001-07-06 04:26:23 +0000292#define FORCEINTON forceinton()
Eric Andersen2870d962001-07-02 17:27:21 +0000293#endif
Eric Andersen3102ac42001-07-06 04:26:23 +0000294
Eric Andersen2870d962001-07-02 17:27:21 +0000295#define CLEAR_PENDING_INT intpending = 0
296#define int_pending() intpending
297
298
299typedef void *pointer;
300#ifndef NULL
301#define NULL (void *)0
302#endif
303
304static inline pointer ckmalloc (int sz) { return xmalloc(sz); }
305static inline pointer ckrealloc(void *p, int sz) { return xrealloc(p, sz); }
306static inline char * savestr (const char *s) { return xstrdup(s); }
307
308static pointer stalloc (int);
309static void stunalloc (pointer);
310static void ungrabstackstr (char *, char *);
311static char * growstackstr(void);
Eric Andersen3102ac42001-07-06 04:26:23 +0000312static char * makestrspace(size_t newlen);
Eric Andersen2870d962001-07-02 17:27:21 +0000313static char *sstrdup (const char *);
314
315/*
316 * Parse trees for commands are allocated in lifo order, so we use a stack
317 * to make this more efficient, and also to avoid all sorts of exception
318 * handling code to handle interrupts in the middle of a parse.
319 *
320 * The size 504 was chosen because the Ultrix malloc handles that size
321 * well.
322 */
323
324#define MINSIZE 504 /* minimum size of a block */
325
326
327struct stack_block {
328 struct stack_block *prev;
329 char space[MINSIZE];
330};
331
332static struct stack_block stackbase;
333static struct stack_block *stackp = &stackbase;
334static struct stackmark *markp;
335static char *stacknxt = stackbase.space;
336static int stacknleft = MINSIZE;
337
338
339#define equal(s1, s2) (strcmp(s1, s2) == 0)
340
341#define stackblock() stacknxt
342#define stackblocksize() stacknleft
343#define STARTSTACKSTR(p) p = stackblock(), sstrnleft = stackblocksize()
Eric Andersen3102ac42001-07-06 04:26:23 +0000344
Eric Andersen2870d962001-07-02 17:27:21 +0000345#define STPUTC(c, p) (--sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(), *p++ = (c)))
346#define CHECKSTRSPACE(n, p) { if (sstrnleft < n) p = makestrspace(n); }
Eric Andersen2870d962001-07-02 17:27:21 +0000347#define STACKSTRNUL(p) (sstrnleft == 0? (p = growstackstr(), *p = '\0') : (*p = '\0'))
Eric Andersen3102ac42001-07-06 04:26:23 +0000348
349
350#define USTPUTC(c, p) (--sstrnleft, *p++ = (c))
Eric Andersen2870d962001-07-02 17:27:21 +0000351#define STUNPUTC(p) (++sstrnleft, --p)
352#define STTOPC(p) p[-1]
353#define STADJUST(amount, p) (p += (amount), sstrnleft -= (amount))
354#define grabstackstr(p) stalloc(stackblocksize() - sstrnleft)
355
356#define ckfree(p) free((pointer)(p))
357
Eric Andersen2870d962001-07-02 17:27:21 +0000358
359#ifdef DEBUG
360#define TRACE(param) trace param
361static void trace (const char *, ...);
362static void trargs (char **);
363static void showtree (union node *);
364static void trputc (int);
365static void trputs (const char *);
366static void opentrace (void);
367#else
368#define TRACE(param)
369#endif
370
371#define NSEMI 0
372#define NCMD 1
373#define NPIPE 2
374#define NREDIR 3
375#define NBACKGND 4
376#define NSUBSHELL 5
377#define NAND 6
378#define NOR 7
379#define NIF 8
380#define NWHILE 9
381#define NUNTIL 10
382#define NFOR 11
383#define NCASE 12
384#define NCLIST 13
385#define NDEFUN 14
386#define NARG 15
387#define NTO 16
388#define NFROM 17
389#define NFROMTO 18
390#define NAPPEND 19
391#define NTOOV 20
392#define NTOFD 21
393#define NFROMFD 22
394#define NHERE 23
395#define NXHERE 24
396#define NNOT 25
397
398/*
399 * expandarg() flags
400 */
401#define EXP_FULL 0x1 /* perform word splitting & file globbing */
402#define EXP_TILDE 0x2 /* do normal tilde expansion */
403#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
404#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
405#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
406#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
407
408
409#define NOPTS 16
410
411static char optet_vals[NOPTS];
412
413static const char * const optlist[NOPTS] = {
414 "e" "errexit",
415 "f" "noglob",
416 "I" "ignoreeof",
417 "i" "interactive",
418 "m" "monitor",
419 "n" "noexec",
420 "s" "stdin",
421 "x" "xtrace",
422 "v" "verbose",
423 "V" "vi",
424 "E" "emacs",
425 "C" "noclobber",
426 "a" "allexport",
427 "b" "notify",
428 "u" "nounset",
429 "q" "quietprofile"
430};
431
432#define optent_name(optent) (optent+1)
433#define optent_letter(optent) optent[0]
434#define optent_val(optent) optet_vals[optent]
435
436#define eflag optent_val(0)
437#define fflag optent_val(1)
438#define Iflag optent_val(2)
439#define iflag optent_val(3)
440#define mflag optent_val(4)
441#define nflag optent_val(5)
442#define sflag optent_val(6)
443#define xflag optent_val(7)
444#define vflag optent_val(8)
445#define Vflag optent_val(9)
446#define Eflag optent_val(10)
447#define Cflag optent_val(11)
448#define aflag optent_val(12)
449#define bflag optent_val(13)
450#define uflag optent_val(14)
451#define qflag optent_val(15)
452
453
454/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
455#define FORK_FG 0
456#define FORK_BG 1
457#define FORK_NOJOB 2
458
459
460struct nbinary {
461 int type;
462 union node *ch1;
463 union node *ch2;
464};
465
466
467struct ncmd {
468 int type;
469 int backgnd;
470 union node *assign;
471 union node *args;
472 union node *redirect;
473};
474
475
476struct npipe {
477 int type;
478 int backgnd;
479 struct nodelist *cmdlist;
480};
481
482
483struct nredir {
484 int type;
485 union node *n;
486 union node *redirect;
487};
488
489
490struct nif {
491 int type;
492 union node *test;
493 union node *ifpart;
494 union node *elsepart;
495};
496
497
498struct nfor {
499 int type;
500 union node *args;
501 union node *body;
502 char *var;
503};
504
505
506struct ncase {
507 int type;
508 union node *expr;
509 union node *cases;
510};
511
512
513struct nclist {
514 int type;
515 union node *next;
516 union node *pattern;
517 union node *body;
518};
519
520
521struct narg {
522 int type;
523 union node *next;
524 char *text;
525 struct nodelist *backquote;
526};
527
528
529struct nfile {
530 int type;
531 union node *next;
532 int fd;
533 union node *fname;
534 char *expfname;
535};
536
537
538struct ndup {
539 int type;
540 union node *next;
541 int fd;
542 int dupfd;
543 union node *vname;
544};
545
546
547struct nhere {
548 int type;
549 union node *next;
550 int fd;
551 union node *doc;
552};
553
554
555struct nnot {
556 int type;
557 union node *com;
558};
559
560
561union node {
562 int type;
563 struct nbinary nbinary;
564 struct ncmd ncmd;
565 struct npipe npipe;
566 struct nredir nredir;
567 struct nif nif;
568 struct nfor nfor;
569 struct ncase ncase;
570 struct nclist nclist;
571 struct narg narg;
572 struct nfile nfile;
573 struct ndup ndup;
574 struct nhere nhere;
575 struct nnot nnot;
576};
577
578
579struct nodelist {
580 struct nodelist *next;
581 union node *n;
582};
583
584struct backcmd { /* result of evalbackcmd */
585 int fd; /* file descriptor to read from */
586 char *buf; /* buffer */
587 int nleft; /* number of chars in buffer */
588 struct job *jp; /* job structure for command */
589};
590
591struct cmdentry {
592 int cmdtype;
593 union param {
594 int index;
595 union node *func;
596 const struct builtincmd *cmd;
597 } u;
598};
599
600struct strlist {
601 struct strlist *next;
602 char *text;
603};
604
605
606struct arglist {
607 struct strlist *list;
608 struct strlist **lastp;
609};
610
611struct strpush {
612 struct strpush *prev; /* preceding string on stack */
613 char *prevstring;
614 int prevnleft;
615#ifdef ASH_ALIAS
616 struct alias *ap; /* if push was associated with an alias */
617#endif
618 char *string; /* remember the string since it may change */
619};
620
621struct parsefile {
622 struct parsefile *prev; /* preceding file on stack */
623 int linno; /* current line */
624 int fd; /* file descriptor (or -1 if string) */
625 int nleft; /* number of chars left in this line */
626 int lleft; /* number of chars left in this buffer */
627 char *nextc; /* next char in buffer */
628 char *buf; /* input buffer */
629 struct strpush *strpush; /* for pushing strings at this level */
630 struct strpush basestrpush; /* so pushing one is fast */
631};
632
633struct stackmark {
634 struct stack_block *stackp;
635 char *stacknxt;
636 int stacknleft;
637 struct stackmark *marknext;
638};
639
640struct shparam {
641 int nparam; /* # of positional parameters (without $0) */
642 unsigned char malloc; /* if parameter list dynamically allocated */
643 char **p; /* parameter list */
644 int optind; /* next parameter to be processed by getopts */
645 int optoff; /* used by getopts */
646};
647
Eric Andersen62483552001-07-10 06:09:16 +0000648/*
649 * When commands are first encountered, they are entered in a hash table.
650 * This ensures that a full path search will not have to be done for them
651 * on each invocation.
652 *
653 * We should investigate converting to a linear search, even though that
654 * would make the command name "hash" a misnomer.
655 */
656#define CMDTABLESIZE 31 /* should be prime */
657#define ARB 1 /* actual size determined at run time */
658
659
660
661struct tblentry {
662 struct tblentry *next; /* next entry in hash chain */
663 union param param; /* definition of builtin function */
664 short cmdtype; /* index identifying command */
665 char rehash; /* if set, cd done since entry created */
666 char cmdname[ARB]; /* name of command */
667};
668
669
670static struct tblentry *cmdtable[CMDTABLESIZE];
671static int builtinloc = -1; /* index in path of %builtin, or -1 */
672static int exerrno = 0; /* Last exec error */
673
674
675static void tryexec (char *, char **, char **);
676static void printentry (struct tblentry *, int);
677static void clearcmdentry (int);
678static struct tblentry *cmdlookup (const char *, int);
679static void delete_cmd_entry (void);
680static int path_change (const char *, int *);
681
682
Eric Andersen2870d962001-07-02 17:27:21 +0000683static void flushall (void);
Eric Andersen3102ac42001-07-06 04:26:23 +0000684static void out2fmt (const char *, ...)
685 __attribute__((__format__(__printf__,1,2)));
Eric Andersen2870d962001-07-02 17:27:21 +0000686static int xwrite (int, const char *, int);
Eric Andersen2870d962001-07-02 17:27:21 +0000687
Manuel Novoa III c639a352001-08-12 17:32:56 +0000688static inline void outstr (const char *p, FILE *file) { fputs(p, file); }
Eric Andersen3102ac42001-07-06 04:26:23 +0000689static void out1str(const char *p) { outstr(p, stdout); }
690static void out2str(const char *p) { outstr(p, stderr); }
Eric Andersen2870d962001-07-02 17:27:21 +0000691
Eric Andersen62483552001-07-10 06:09:16 +0000692#ifndef ASH_OPTIMIZE_FOR_SIZE
Eric Andersen3102ac42001-07-06 04:26:23 +0000693#define out2c(c) putc((c), stderr)
Eric Andersen62483552001-07-10 06:09:16 +0000694#else
695static void out2c(int c) { putc(c, stderr); }
696#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000697
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000698
699#ifdef ASH_OPTIMIZE_FOR_SIZE
700#define USE_SIT_FUNCTION
701#endif
702
703/* number syntax index */
704#define BASESYNTAX 0 /* not in quotes */
705#define DQSYNTAX 1 /* in double quotes */
706#define SQSYNTAX 2 /* in single quotes */
707#define ARISYNTAX 3 /* in arithmetic */
708
709static const char S_I_T[][4] = {
710 /* 0 */ { CSPCL, CIGN, CIGN, CIGN }, /* PEOA */
711 /* 1 */ { CSPCL, CWORD, CWORD, CWORD }, /* ' ' */
712 /* 2 */ { CNL, CNL, CNL, CNL }, /* \n */
713 /* 3 */ { CWORD, CCTL, CCTL, CWORD }, /* !*-/:=?[]~ */
714 /* 4 */ { CDQUOTE, CENDQUOTE, CWORD, CDQUOTE }, /* '"' */
715 /* 5 */ { CVAR, CVAR, CWORD, CVAR }, /* $ */
716 /* 6 */ { CSQUOTE, CWORD, CENDQUOTE, CSQUOTE }, /* "'" */
717 /* 7 */ { CSPCL, CWORD, CWORD, CLP }, /* ( */
718 /* 8 */ { CSPCL, CWORD, CWORD, CRP }, /* ) */
719 /* 9 */ { CBACK, CBACK, CCTL, CBACK }, /* \ */
720 /* 10 */ { CBQUOTE, CBQUOTE, CWORD, CBQUOTE }, /* ` */
721 /* 11 */ { CENDVAR, CENDVAR, CWORD, CENDVAR }, /* } */
722#ifndef USE_SIT_FUNCTION
723 /* 12 */ { CENDFILE, CENDFILE, CENDFILE, CENDFILE }, /* PEOF */
724 /* 13 */ { CWORD, CWORD, CWORD, CWORD }, /* 0-9A-Za-z */
725 /* 14 */ { CCTL, CCTL, CCTL, CCTL } /* CTLESC ... */
726#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000727};
728
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000729#ifdef USE_SIT_FUNCTION
730
731#define U_C(c) ((unsigned char)(c))
732
733static int SIT(int c, int syntax)
734{
735 static const char spec_symbls[]="\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
736 static const char syntax_index_table [] = {
737 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
738 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
739 3, 1, 3, 3, 9, 3,10, 1, /* "=>?[\\]`|" */
740 11,3 }; /* "}~" */
741 const char *s;
742 int indx;
743
744 if(c==PEOF) /* 2^8+2 */
745 return CENDFILE;
746 if(c==PEOA) /* 2^8+1 */
747 indx = 0;
748 else if(U_C(c)>=U_C(CTLESC) && U_C(c)<=U_C(CTLQUOTEMARK))
749 return CCTL;
750 else {
751 s = strchr(spec_symbls, c);
752 if(s==0)
753 return CWORD;
754 indx = syntax_index_table[(s-spec_symbls)];
755 }
756 return S_I_T[indx][syntax];
757}
758
759#else /* USE_SIT_FUNCTION */
760
761#define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
762
763#define CSPCL_CIGN_CIGN_CIGN 0
764#define CSPCL_CWORD_CWORD_CWORD 1
765#define CNL_CNL_CNL_CNL 2
766#define CWORD_CCTL_CCTL_CWORD 3
767#define CDQUOTE_CENDQUOTE_CWORD_CDQUOTE 4
768#define CVAR_CVAR_CWORD_CVAR 5
769#define CSQUOTE_CWORD_CENDQUOTE_CSQUOTE 6
770#define CSPCL_CWORD_CWORD_CLP 7
771#define CSPCL_CWORD_CWORD_CRP 8
772#define CBACK_CBACK_CCTL_CBACK 9
773#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
774#define CENDVAR_CENDVAR_CWORD_CENDVAR 11
775#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
776#define CWORD_CWORD_CWORD_CWORD 13
777#define CCTL_CCTL_CCTL_CCTL 14
778
779static const char syntax_index_table[258] = {
780 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
781 /* 0 -130 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
782 /* 1 -129 PEOA */ CSPCL_CIGN_CIGN_CIGN,
783 /* 2 -128 0xff */ CWORD_CWORD_CWORD_CWORD,
784 /* 3 -127 */ CCTL_CCTL_CCTL_CCTL, /* CTLQUOTEMARK */
785 /* 4 -126 */ CCTL_CCTL_CCTL_CCTL,
786 /* 5 -125 */ CCTL_CCTL_CCTL_CCTL,
787 /* 6 -124 */ CCTL_CCTL_CCTL_CCTL,
788 /* 7 -123 */ CCTL_CCTL_CCTL_CCTL,
789 /* 8 -122 */ CCTL_CCTL_CCTL_CCTL,
790 /* 9 -121 */ CCTL_CCTL_CCTL_CCTL,
791 /* 10 -120 */ CCTL_CCTL_CCTL_CCTL, /* CTLESC */
792 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
793 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
794 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
795 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
796 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
797 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
798 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
799 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
800 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
801 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
802 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
803 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
804 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
805 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
806 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
807 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
808 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
809 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
810 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
811 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
812 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
813 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
814 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
815 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
816 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
817 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
818 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
819 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
820 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
821 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
822 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
823 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
824 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
825 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
826 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
827 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
828 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
829 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
830 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
831 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
832 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
833 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
834 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
835 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
836 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
837 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
838 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
839 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
840 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
841 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
842 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
843 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
844 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
845 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
846 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
847 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
848 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
849 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
850 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
851 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
852 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
853 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
854 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
855 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
856 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
857 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
858 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
859 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
860 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
861 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
862 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
863 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
864 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
865 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
866 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
867 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
868 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
869 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
870 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
871 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
872 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
873 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
874 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
875 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
876 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
877 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
878 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
879 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
880 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
881 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
882 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
883 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
884 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
885 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
886 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
887 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
888 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
889 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
890 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
891 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
892 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
893 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
894 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
895 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
896 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
897 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
898 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
899 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
900 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
901 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
902 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
903 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
904 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
905 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
906 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
907 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
908 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
909 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
910 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
911 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
912 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
913 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
914 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
915 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
916 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
917 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
918 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
919 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
920 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
921 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
922 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
923 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
924 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
925 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
926 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
927 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
928 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
929 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
930 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
931 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
932 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
933 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
934 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
935 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
936 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
937 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
938 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
939 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
940 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
941 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
942 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
943 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
944 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
945 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CDQUOTE,
946 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
947 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
948 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
949 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
950 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CSQUOTE,
951 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
952 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
953 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
954 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
955 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
956 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
957 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
958 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
959 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
960 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
961 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
962 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
963 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
964 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
965 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
966 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
967 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
968 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
969 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
970 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
971 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
972 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
973 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
974 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
975 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
976 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
977 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
978 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
979 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
980 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
981 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
982 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
983 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
984 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
985 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
986 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
987 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
988 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
989 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
990 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
991 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
992 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
993 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
994 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
995 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
996 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
997 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
998 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
999 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
1000 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
1001 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
1002 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
1003 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
1004 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
1005 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
1006 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
1007 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
1008 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
1009 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
1010 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
1011 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
1012 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
1013 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
1014 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
1015 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
1016 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
1017 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
1018 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
1019 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
1020 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
1021 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
1022 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
1023 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
1024 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
1025 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
1026 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
1027 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
1028 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
1029 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
1030 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
1031 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
1032 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
1033 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
1034 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
1035 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
1036 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
1037 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
1038 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
Eric Andersen2870d962001-07-02 17:27:21 +00001039};
1040
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001041#endif /* USE_SIT_FUNCTION */
Eric Andersen2870d962001-07-02 17:27:21 +00001042
Eric Andersen2870d962001-07-02 17:27:21 +00001043
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001044/* first char is indicating which tokens mark the end of a list */
1045static const char *const tokname_array[] = {
1046 "\1end of file",
1047 "\0newline",
1048 "\0redirection",
1049 "\0word",
1050 "\0assignment",
1051 "\0;",
1052 "\0&",
1053 "\0&&",
1054 "\0||",
1055 "\0|",
1056 "\0(",
1057 "\1)",
1058 "\1;;",
1059 "\1`",
Eric Andersen2870d962001-07-02 17:27:21 +00001060#define KWDOFFSET 14
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001061 /* the following are keywords */
1062 "\0!",
1063 "\0case",
1064 "\1do",
1065 "\1done",
1066 "\1elif",
1067 "\1else",
1068 "\1esac",
1069 "\1fi",
1070 "\0for",
1071 "\0if",
1072 "\0in",
1073 "\1then",
1074 "\0until",
1075 "\0while",
1076 "\0{",
1077 "\1}",
Eric Andersen2870d962001-07-02 17:27:21 +00001078};
1079
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001080static const char *tokname(int tok)
1081{
1082 static char buf[16];
1083
1084 if(tok>=TSEMI)
1085 buf[0] = '"';
1086 sprintf(buf+(tok>=TSEMI), "%s%c",
1087 tokname_array[tok]+1, (tok>=TSEMI ? '"' : 0));
1088 return buf;
1089}
Eric Andersen2870d962001-07-02 17:27:21 +00001090
1091static int plinno = 1; /* input line number */
1092
1093static int parselleft; /* copy of parsefile->lleft */
1094
1095static struct parsefile basepf; /* top level input file */
1096static char basebuf[BUFSIZ]; /* buffer for top level input file */
1097static struct parsefile *parsefile = &basepf; /* current input file */
1098
1099/*
1100 * NEOF is returned by parsecmd when it encounters an end of file. It
1101 * must be distinct from NULL, so we use the address of a variable that
1102 * happens to be handy.
1103 */
1104
1105static int tokpushback; /* last token pushed back */
1106#define NEOF ((union node *)&tokpushback)
1107static int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */
1108
1109
1110static void error (const char *, ...) __attribute__((__noreturn__));
1111static void exerror (int, const char *, ...) __attribute__((__noreturn__));
1112static void shellexec (char **, char **, const char *, int)
1113 __attribute__((noreturn));
1114static void exitshell (int) __attribute__((noreturn));
1115
1116static int goodname(const char *);
1117static void ignoresig (int);
1118static void onsig (int);
1119static void dotrap (void);
1120static int decode_signal (const char *, int);
1121
1122static void shprocvar(void);
1123static void deletefuncs(void);
1124static void setparam (char **);
1125static void freeparam (volatile struct shparam *);
1126
1127/* reasons for skipping commands (see comment on breakcmd routine) */
1128#define SKIPBREAK 1
1129#define SKIPCONT 2
1130#define SKIPFUNC 3
1131#define SKIPFILE 4
1132
1133/* values of cmdtype */
1134#define CMDUNKNOWN -1 /* no entry in table for command */
1135#define CMDNORMAL 0 /* command is an executable program */
1136#define CMDBUILTIN 1 /* command is a shell builtin */
1137#define CMDFUNCTION 2 /* command is a shell function */
1138
1139#define DO_ERR 1 /* find_command prints errors */
1140#define DO_ABS 2 /* find_command checks absolute paths */
1141#define DO_NOFUN 4 /* find_command ignores functions */
1142#define DO_BRUTE 8 /* find_command ignores hash table */
1143
1144/*
1145 * Shell variables.
1146 */
1147
1148/* flags */
1149#define VEXPORT 0x01 /* variable is exported */
1150#define VREADONLY 0x02 /* variable cannot be modified */
1151#define VSTRFIXED 0x04 /* variable struct is staticly allocated */
1152#define VTEXTFIXED 0x08 /* text is staticly allocated */
1153#define VSTACK 0x10 /* text is allocated on the stack */
1154#define VUNSET 0x20 /* the variable is not set */
1155#define VNOFUNC 0x40 /* don't call the callback function */
1156
1157
1158struct var {
1159 struct var *next; /* next entry in hash list */
1160 int flags; /* flags are defined above */
1161 char *text; /* name=value */
1162 void (*func) (const char *);
1163 /* function to be called when */
1164 /* the variable gets set/unset */
1165};
1166
1167struct localvar {
1168 struct localvar *next; /* next local variable in list */
1169 struct var *vp; /* the variable that was made local */
1170 int flags; /* saved flags */
1171 char *text; /* saved text */
1172};
1173
1174
Eric Andersen62483552001-07-10 06:09:16 +00001175#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00001176#define rmescapes(p) _rmescapes((p), 0)
1177static char *_rmescapes (char *, int);
1178#else
1179static void rmescapes (char *);
1180#endif
1181
1182static int casematch (union node *, const char *);
1183static void clearredir(void);
1184static void popstring(void);
1185static void readcmdfile (const char *);
1186
1187static int number (const char *);
1188static int is_number (const char *, int *num);
1189static char *single_quote (const char *);
1190static int nextopt (const char *);
1191
1192static void redirect (union node *, int);
1193static void popredir (void);
1194static int dup_as_newfd (int, int);
1195
1196static void changepath(const char *newval);
1197static void getoptsreset(const char *value);
1198
1199
1200static int parsenleft; /* copy of parsefile->nleft */
1201static char *parsenextc; /* copy of parsefile->nextc */
1202static int rootpid; /* pid of main shell */
1203static int rootshell; /* true if we aren't a child of the main shell */
1204
1205static const char spcstr[] = " ";
1206static const char snlfmt[] = "%s\n";
1207
1208static int sstrnleft;
1209static int herefd = -1;
1210
1211static struct localvar *localvars;
1212
1213static struct var vifs;
1214static struct var vmail;
1215static struct var vmpath;
1216static struct var vpath;
1217static struct var vps1;
1218static struct var vps2;
1219static struct var voptind;
1220#ifdef BB_LOCALE_SUPPORT
1221static struct var vlc_all;
1222static struct var vlc_ctype;
1223#endif
1224
1225struct varinit {
1226 struct var *var;
1227 int flags;
1228 const char *text;
1229 void (*func) (const char *);
1230};
1231
1232static const char defpathvar[] =
1233 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
1234#define defpath (defpathvar + 5)
1235
1236#ifdef IFS_BROKEN
1237static const char defifsvar[] = "IFS= \t\n";
1238#define defifs (defifsvar + 4)
1239#else
1240static const char defifs[] = " \t\n";
1241#endif
1242
1243static const struct varinit varinit[] = {
1244#ifdef IFS_BROKEN
1245 { &vifs, VSTRFIXED|VTEXTFIXED, defifsvar,
1246#else
1247 { &vifs, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS=",
1248#endif
1249 NULL },
1250 { &vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=",
1251 NULL },
1252 { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=",
1253 NULL },
1254 { &vpath, VSTRFIXED|VTEXTFIXED, defpathvar,
1255 changepath },
1256 /*
1257 * vps1 depends on uid
1258 */
1259 { &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ",
1260 NULL },
1261 { &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1",
1262 getoptsreset },
1263#ifdef BB_LOCALE_SUPPORT
1264 { &vlc_all, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL=",
1265 change_lc_all },
1266 { &vlc_ctype, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE=",
1267 change_lc_ctype },
1268#endif
1269 { NULL, 0, NULL,
1270 NULL }
1271};
1272
1273#define VTABSIZE 39
1274
1275static struct var *vartab[VTABSIZE];
1276
1277/*
1278 * The following macros access the values of the above variables.
1279 * They have to skip over the name. They return the null string
1280 * for unset variables.
1281 */
1282
1283#define ifsval() (vifs.text + 4)
1284#define ifsset() ((vifs.flags & VUNSET) == 0)
1285#define mailval() (vmail.text + 5)
1286#define mpathval() (vmpath.text + 9)
1287#define pathval() (vpath.text + 5)
1288#define ps1val() (vps1.text + 4)
1289#define ps2val() (vps2.text + 4)
1290#define optindval() (voptind.text + 7)
1291
1292#define mpathset() ((vmpath.flags & VUNSET) == 0)
1293
1294static void initvar (void);
1295static void setvar (const char *, const char *, int);
1296static void setvareq (char *, int);
1297static void listsetvar (struct strlist *);
Eric Andersen62483552001-07-10 06:09:16 +00001298static const char *lookupvar (const char *);
1299static const char *bltinlookup (const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001300static char **environment (void);
1301static int showvarscmd (int, char **);
1302static void mklocal (char *);
1303static void poplocalvars (void);
1304static int unsetvar (const char *);
1305static int varequal (const char *, const char *);
1306
1307
1308static char *arg0; /* value of $0 */
1309static struct shparam shellparam; /* current positional parameters */
1310static char **argptr; /* argument list for builtin commands */
1311static char *optionarg; /* set by nextopt (like getopt) */
1312static char *optptr; /* used by nextopt */
1313static char *minusc; /* argument to -c option */
1314
1315
1316#ifdef ASH_ALIAS
1317
1318#define ALIASINUSE 1
1319#define ALIASDEAD 2
1320
Eric Andersen3102ac42001-07-06 04:26:23 +00001321#define ATABSIZE 39
1322
Eric Andersen2870d962001-07-02 17:27:21 +00001323struct alias {
1324 struct alias *next;
1325 char *name;
1326 char *val;
1327 int flag;
1328};
1329
1330static struct alias *atab[ATABSIZE];
1331
1332static void setalias (char *, char *);
1333static struct alias **hashalias (const char *);
1334static struct alias *freealias (struct alias *);
1335static struct alias **__lookupalias (const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00001336
1337static void
1338setalias(name, val)
1339 char *name, *val;
1340{
1341 struct alias *ap, **app;
1342
1343 app = __lookupalias(name);
1344 ap = *app;
1345 INTOFF;
1346 if (ap) {
1347 if (!(ap->flag & ALIASINUSE)) {
1348 ckfree(ap->val);
1349 }
Eric Andersen2870d962001-07-02 17:27:21 +00001350 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00001351 ap->flag &= ~ALIASDEAD;
1352 } else {
1353 /* not found */
1354 ap = ckmalloc(sizeof (struct alias));
1355 ap->name = savestr(name);
1356 ap->val = savestr(val);
1357 ap->flag = 0;
1358 ap->next = 0;
1359 *app = ap;
1360 }
1361 INTON;
1362}
1363
1364static int
Eric Andersen2870d962001-07-02 17:27:21 +00001365unalias(char *name)
1366{
Eric Andersencb57d552001-06-28 07:25:16 +00001367 struct alias **app;
1368
1369 app = __lookupalias(name);
1370
1371 if (*app) {
1372 INTOFF;
1373 *app = freealias(*app);
1374 INTON;
1375 return (0);
1376 }
1377
1378 return (1);
1379}
1380
Eric Andersencb57d552001-06-28 07:25:16 +00001381static void
Eric Andersen2870d962001-07-02 17:27:21 +00001382rmaliases(void)
1383{
Eric Andersencb57d552001-06-28 07:25:16 +00001384 struct alias *ap, **app;
1385 int i;
1386
1387 INTOFF;
1388 for (i = 0; i < ATABSIZE; i++) {
1389 app = &atab[i];
1390 for (ap = *app; ap; ap = *app) {
1391 *app = freealias(*app);
1392 if (ap == *app) {
1393 app = &ap->next;
1394 }
1395 }
1396 }
1397 INTON;
1398}
1399
Eric Andersen2870d962001-07-02 17:27:21 +00001400static struct alias *
1401lookupalias(const char *name, int check)
Eric Andersencb57d552001-06-28 07:25:16 +00001402{
1403 struct alias *ap = *__lookupalias(name);
1404
1405 if (check && ap && (ap->flag & ALIASINUSE))
1406 return (NULL);
1407 return (ap);
1408}
1409
Eric Andersen2870d962001-07-02 17:27:21 +00001410static void
1411printalias(const struct alias *ap) {
1412 char *p;
1413
1414 p = single_quote(ap->val);
Eric Andersen62483552001-07-10 06:09:16 +00001415 printf("alias %s=%s\n", ap->name, p);
Eric Andersen2870d962001-07-02 17:27:21 +00001416 stunalloc(p);
1417}
1418
Eric Andersencb57d552001-06-28 07:25:16 +00001419
1420/*
1421 * TODO - sort output
1422 */
1423static int
Eric Andersen2870d962001-07-02 17:27:21 +00001424aliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001425{
1426 char *n, *v;
1427 int ret = 0;
1428 struct alias *ap;
1429
1430 if (argc == 1) {
1431 int i;
1432
1433 for (i = 0; i < ATABSIZE; i++)
1434 for (ap = atab[i]; ap; ap = ap->next) {
1435 printalias(ap);
1436 }
1437 return (0);
1438 }
1439 while ((n = *++argv) != NULL) {
1440 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
1441 if ((ap = *__lookupalias(n)) == NULL) {
Eric Andersen3102ac42001-07-06 04:26:23 +00001442 out2fmt("%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00001443 ret = 1;
1444 } else
1445 printalias(ap);
1446 }
1447 else {
1448 *v++ = '\0';
1449 setalias(n, v);
1450 }
1451 }
1452
1453 return (ret);
1454}
1455
1456static int
Eric Andersen2870d962001-07-02 17:27:21 +00001457unaliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001458{
1459 int i;
1460
1461 while ((i = nextopt("a")) != '\0') {
1462 if (i == 'a') {
1463 rmaliases();
1464 return (0);
1465 }
1466 }
1467 for (i = 0; *argptr; argptr++) {
1468 if (unalias(*argptr)) {
Eric Andersen3102ac42001-07-06 04:26:23 +00001469 out2fmt("%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00001470 i = 1;
1471 }
1472 }
1473
1474 return (i);
1475}
1476
1477static struct alias **
1478hashalias(p)
1479 const char *p;
1480 {
1481 unsigned int hashval;
1482
1483 hashval = *p << 4;
1484 while (*p)
1485 hashval+= *p++;
1486 return &atab[hashval % ATABSIZE];
1487}
1488
1489static struct alias *
1490freealias(struct alias *ap) {
1491 struct alias *next;
1492
1493 if (ap->flag & ALIASINUSE) {
1494 ap->flag |= ALIASDEAD;
1495 return ap;
1496 }
1497
1498 next = ap->next;
1499 ckfree(ap->name);
1500 ckfree(ap->val);
1501 ckfree(ap);
1502 return next;
1503}
1504
Eric Andersencb57d552001-06-28 07:25:16 +00001505
1506static struct alias **
1507__lookupalias(const char *name) {
1508 struct alias **app = hashalias(name);
1509
1510 for (; *app; app = &(*app)->next) {
1511 if (equal(name, (*app)->name)) {
1512 break;
1513 }
1514 }
1515
1516 return app;
1517}
Eric Andersen2870d962001-07-02 17:27:21 +00001518#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001519
1520#ifdef ASH_MATH_SUPPORT
Eric Andersen74bcd162001-07-30 21:41:37 +00001521/* The generated file arith.c has been replaced with a custom hand
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001522 * written implementation written by Aaron Lehmann <aaronl@vitelus.com>.
1523 * This is now part of libbb, so that it can be used by all the shells
Eric Andersen74bcd162001-07-30 21:41:37 +00001524 * in busybox. */
Eric Andersen2870d962001-07-02 17:27:21 +00001525#define ARITH_NUM 257
1526#define ARITH_LPAREN 258
1527#define ARITH_RPAREN 259
1528#define ARITH_OR 260
1529#define ARITH_AND 261
1530#define ARITH_BOR 262
1531#define ARITH_BXOR 263
1532#define ARITH_BAND 264
1533#define ARITH_EQ 265
1534#define ARITH_NE 266
1535#define ARITH_LT 267
1536#define ARITH_GT 268
1537#define ARITH_GE 269
1538#define ARITH_LE 270
1539#define ARITH_LSHIFT 271
1540#define ARITH_RSHIFT 272
1541#define ARITH_ADD 273
1542#define ARITH_SUB 274
1543#define ARITH_MUL 275
1544#define ARITH_DIV 276
1545#define ARITH_REM 277
1546#define ARITH_UNARYMINUS 278
1547#define ARITH_UNARYPLUS 279
1548#define ARITH_NOT 280
1549#define ARITH_BNOT 281
1550
1551static void expari (int);
Eric Andersencb57d552001-06-28 07:25:16 +00001552#endif
1553
Eric Andersen2870d962001-07-02 17:27:21 +00001554static char *trap[NSIG]; /* trap handler commands */
1555static char sigmode[NSIG - 1]; /* current value of signal */
1556static char gotsig[NSIG - 1]; /* indicates specified signal received */
1557static int pendingsigs; /* indicates some signal received */
1558
Eric Andersencb57d552001-06-28 07:25:16 +00001559/*
1560 * This file was generated by the mkbuiltins program.
1561 */
1562
Eric Andersen2870d962001-07-02 17:27:21 +00001563#ifdef JOBS
1564static int bgcmd (int, char **);
1565static int fgcmd (int, char **);
1566static int killcmd (int, char **);
1567#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001568static int bltincmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001569static int cdcmd (int, char **);
1570static int breakcmd (int, char **);
1571#ifdef ASH_CMDCMD
1572static int commandcmd (int, char **);
1573#endif
1574static int dotcmd (int, char **);
1575static int evalcmd (int, char **);
1576static int execcmd (int, char **);
1577static int exitcmd (int, char **);
1578static int exportcmd (int, char **);
1579static int histcmd (int, char **);
1580static int hashcmd (int, char **);
Eric Andersen1c039232001-07-07 00:05:55 +00001581static int helpcmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001582static int jobscmd (int, char **);
1583static int localcmd (int, char **);
Eric Andersen3102ac42001-07-06 04:26:23 +00001584#ifndef BB_PWD
Eric Andersen2870d962001-07-02 17:27:21 +00001585static int pwdcmd (int, char **);
1586#endif
1587static int readcmd (int, char **);
1588static int returncmd (int, char **);
1589static int setcmd (int, char **);
1590static int setvarcmd (int, char **);
1591static int shiftcmd (int, char **);
1592static int trapcmd (int, char **);
1593static int umaskcmd (int, char **);
1594#ifdef ASH_ALIAS
1595static int aliascmd (int, char **);
1596static int unaliascmd (int, char **);
1597#endif
1598static int unsetcmd (int, char **);
1599static int waitcmd (int, char **);
1600static int ulimitcmd (int, char **);
1601static int timescmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001602#ifdef ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +00001603static int letcmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001604#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001605static int typecmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001606#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00001607static int getoptscmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001608#endif
1609
Eric Andersen2870d962001-07-02 17:27:21 +00001610#ifndef BB_TRUE_FALSE
Eric Andersen2870d962001-07-02 17:27:21 +00001611static int true_main (int, char **);
1612static int false_main (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001613#endif
1614
1615static void setpwd (const char *, int);
1616
1617
1618#define BUILTIN_NOSPEC "0"
1619#define BUILTIN_SPECIAL "1"
1620#define BUILTIN_REGULAR "2"
1621#define BUILTIN_ASSIGN "4"
1622#define BUILTIN_SPEC_ASSG "5"
1623#define BUILTIN_REG_ASSG "6"
1624
1625#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1626#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1627#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
1628
1629struct builtincmd {
1630 const char *name;
1631 int (*const builtinfunc) (int, char **);
1632 //unsigned flags;
1633};
1634
Eric Andersencb57d552001-06-28 07:25:16 +00001635
1636/* It is CRUCIAL that this listing be kept in ascii order, otherwise
1637 * the binary search in find_builtin() will stop working. If you value
1638 * your kneecaps, you'll be sure to *make sure* that any changes made
1639 * to this array result in the listing remaining in ascii order. You
1640 * have been warned.
1641 */
1642static const struct builtincmd builtincmds[] = {
Eric Andersen62483552001-07-10 06:09:16 +00001643 { BUILTIN_SPECIAL ".", dotcmd }, /* first, see declare DOTCMD */
Eric Andersen2870d962001-07-02 17:27:21 +00001644 { BUILTIN_SPECIAL ":", true_main },
1645#ifdef ASH_ALIAS
1646 { BUILTIN_REG_ASSG "alias", aliascmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001647#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001648#ifdef JOBS
1649 { BUILTIN_REGULAR "bg", bgcmd },
1650#endif
1651 { BUILTIN_SPECIAL "break", breakcmd },
Eric Andersen3102ac42001-07-06 04:26:23 +00001652 { BUILTIN_SPECIAL "builtin", bltincmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001653 { BUILTIN_REGULAR "cd", cdcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001654 { BUILTIN_NOSPEC "chdir", cdcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001655#ifdef ASH_CMDCMD
1656 { BUILTIN_REGULAR "command", commandcmd },
1657#endif
1658 { BUILTIN_SPECIAL "continue", breakcmd },
1659 { BUILTIN_SPECIAL "eval", evalcmd },
1660 { BUILTIN_SPECIAL "exec", execcmd },
1661 { BUILTIN_SPECIAL "exit", exitcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001662 { BUILTIN_SPEC_ASSG "export", exportcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001663 { BUILTIN_REGULAR "false", false_main },
Eric Andersen2870d962001-07-02 17:27:21 +00001664 { BUILTIN_REGULAR "fc", histcmd },
1665#ifdef JOBS
1666 { BUILTIN_REGULAR "fg", fgcmd },
1667#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001668#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00001669 { BUILTIN_REGULAR "getopts", getoptscmd },
1670#endif
1671 { BUILTIN_NOSPEC "hash", hashcmd },
Eric Andersen1c039232001-07-07 00:05:55 +00001672 { BUILTIN_NOSPEC "help", helpcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001673 { BUILTIN_REGULAR "jobs", jobscmd },
1674#ifdef JOBS
1675 { BUILTIN_REGULAR "kill", killcmd },
1676#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001677#ifdef ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +00001678 { BUILTIN_REGULAR "let", letcmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001679#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001680 { BUILTIN_ASSIGN "local", localcmd },
Eric Andersen3102ac42001-07-06 04:26:23 +00001681#ifndef BB_PWD
Eric Andersen2870d962001-07-02 17:27:21 +00001682 { BUILTIN_NOSPEC "pwd", pwdcmd },
1683#endif
1684 { BUILTIN_REGULAR "read", readcmd },
1685 { BUILTIN_SPEC_ASSG "readonly", exportcmd },
1686 { BUILTIN_SPECIAL "return", returncmd },
1687 { BUILTIN_SPECIAL "set", setcmd },
1688 { BUILTIN_NOSPEC "setvar", setvarcmd },
1689 { BUILTIN_SPECIAL "shift", shiftcmd },
1690 { BUILTIN_SPECIAL "times", timescmd },
1691 { BUILTIN_SPECIAL "trap", trapcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001692 { BUILTIN_REGULAR "true", true_main },
Eric Andersen2870d962001-07-02 17:27:21 +00001693 { BUILTIN_NOSPEC "type", typecmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001694 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1695 { BUILTIN_REGULAR "umask", umaskcmd },
1696#ifdef ASH_ALIAS
1697 { BUILTIN_REGULAR "unalias", unaliascmd },
1698#endif
1699 { BUILTIN_SPECIAL "unset", unsetcmd },
1700 { BUILTIN_REGULAR "wait", waitcmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001701};
1702#define NUMBUILTINS (sizeof (builtincmds) / sizeof (struct builtincmd) )
1703
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001704#define DOTCMD &builtincmds[0]
Eric Andersen2870d962001-07-02 17:27:21 +00001705static struct builtincmd *BLTINCMD;
1706static struct builtincmd *EXECCMD;
1707static struct builtincmd *EVALCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00001708
Eric Andersen2870d962001-07-02 17:27:21 +00001709/* states */
1710#define JOBSTOPPED 1 /* all procs are stopped */
1711#define JOBDONE 2 /* all procs are completed */
Eric Andersencb57d552001-06-28 07:25:16 +00001712
Eric Andersen2870d962001-07-02 17:27:21 +00001713/*
1714 * A job structure contains information about a job. A job is either a
1715 * single process or a set of processes contained in a pipeline. In the
1716 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1717 * array of pids.
1718 */
Eric Andersencb57d552001-06-28 07:25:16 +00001719
Eric Andersen2870d962001-07-02 17:27:21 +00001720struct procstat {
1721 pid_t pid; /* process id */
1722 int status; /* status flags (defined above) */
1723 char *cmd; /* text of command being run */
1724};
Eric Andersencb57d552001-06-28 07:25:16 +00001725
Eric Andersen2870d962001-07-02 17:27:21 +00001726
1727static int job_warning; /* user was warned about stopped jobs */
1728
1729#ifdef JOBS
1730static void setjobctl(int enable);
1731#else
1732#define setjobctl(on) /* do nothing */
Eric Andersencb57d552001-06-28 07:25:16 +00001733#endif
1734
Eric Andersen2870d962001-07-02 17:27:21 +00001735
1736struct job {
1737 struct procstat ps0; /* status of process */
1738 struct procstat *ps; /* status or processes when more than one */
1739 short nprocs; /* number of processes */
1740 short pgrp; /* process group of this job */
1741 char state; /* true if job is finished */
1742 char used; /* true if this entry is in used */
1743 char changed; /* true if status has changed */
1744#ifdef JOBS
1745 char jobctl; /* job running under job control */
1746#endif
1747};
1748
1749static struct job *jobtab; /* array of jobs */
1750static int njobs; /* size of array */
1751static int backgndpid = -1; /* pid of last background process */
1752#ifdef JOBS
1753static int initialpgrp; /* pgrp of shell on invocation */
1754static int curjob; /* current job */
1755static int jobctl;
1756#endif
1757static int intreceived;
1758
Eric Andersen62483552001-07-10 06:09:16 +00001759static struct job *makejob (const union node *, int);
1760static int forkshell (struct job *, const union node *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00001761static int waitforjob (struct job *);
1762
1763static int docd (char *, int);
1764static char *getcomponent (void);
1765static void updatepwd (const char *);
1766static void getpwd (void);
1767
1768static char *padvance (const char **, const char *);
1769
1770static char nullstr[1]; /* zero length string */
1771static char *curdir = nullstr; /* current working directory */
1772static char *cdcomppath;
1773
Eric Andersencb57d552001-06-28 07:25:16 +00001774static int
1775cdcmd(argc, argv)
1776 int argc;
1777 char **argv;
1778{
1779 const char *dest;
1780 const char *path;
1781 char *p;
1782 struct stat statb;
1783 int print = 0;
1784
1785 nextopt(nullstr);
1786 if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME")) == NULL)
1787 error("HOME not set");
1788 if (*dest == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00001789 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001790 if (dest[0] == '-' && dest[1] == '\0') {
1791 dest = bltinlookup("OLDPWD");
1792 if (!dest || !*dest) {
1793 dest = curdir;
1794 }
1795 print = 1;
1796 if (dest)
Eric Andersen2870d962001-07-02 17:27:21 +00001797 print = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00001798 else
Eric Andersen2870d962001-07-02 17:27:21 +00001799 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001800 }
1801 if (*dest == '/' || (path = bltinlookup("CDPATH")) == NULL)
1802 path = nullstr;
1803 while ((p = padvance(&path, dest)) != NULL) {
1804 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
1805 if (!print) {
1806 /*
1807 * XXX - rethink
1808 */
1809 if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
1810 p += 2;
1811 print = strcmp(p, dest);
1812 }
1813 if (docd(p, print) >= 0)
1814 return 0;
1815
1816 }
1817 }
1818 error("can't cd to %s", dest);
1819 /* NOTREACHED */
1820}
1821
1822
1823/*
1824 * Actually do the chdir. In an interactive shell, print the
1825 * directory name if "print" is nonzero.
1826 */
1827
1828static int
1829docd(dest, print)
1830 char *dest;
1831 int print;
1832{
1833 char *p;
1834 char *q;
1835 char *component;
1836 struct stat statb;
1837 int first;
1838 int badstat;
1839
1840 TRACE(("docd(\"%s\", %d) called\n", dest, print));
1841
1842 /*
1843 * Check each component of the path. If we find a symlink or
1844 * something we can't stat, clear curdir to force a getcwd()
1845 * next time we get the value of the current directory.
1846 */
1847 badstat = 0;
1848 cdcomppath = sstrdup(dest);
1849 STARTSTACKSTR(p);
1850 if (*dest == '/') {
1851 STPUTC('/', p);
1852 cdcomppath++;
1853 }
1854 first = 1;
1855 while ((q = getcomponent()) != NULL) {
1856 if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0'))
1857 continue;
1858 if (! first)
1859 STPUTC('/', p);
1860 first = 0;
1861 component = q;
1862 while (*q)
1863 STPUTC(*q++, p);
1864 if (equal(component, ".."))
1865 continue;
1866 STACKSTRNUL(p);
1867 if ((lstat(stackblock(), &statb) < 0)
1868 || (S_ISLNK(statb.st_mode))) {
1869 /* print = 1; */
1870 badstat = 1;
1871 break;
1872 }
1873 }
1874
1875 INTOFF;
1876 if (chdir(dest) < 0) {
1877 INTON;
1878 return -1;
1879 }
1880 updatepwd(badstat ? NULL : dest);
1881 INTON;
1882 if (print && iflag)
Eric Andersen62483552001-07-10 06:09:16 +00001883 printf(snlfmt, curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00001884 return 0;
1885}
1886
1887
1888/*
1889 * Get the next component of the path name pointed to by cdcomppath.
1890 * This routine overwrites the string pointed to by cdcomppath.
1891 */
1892
1893static char *
1894getcomponent() {
1895 char *p;
1896 char *start;
1897
1898 if ((p = cdcomppath) == NULL)
1899 return NULL;
1900 start = cdcomppath;
1901 while (*p != '/' && *p != '\0')
1902 p++;
1903 if (*p == '\0') {
1904 cdcomppath = NULL;
1905 } else {
1906 *p++ = '\0';
1907 cdcomppath = p;
1908 }
1909 return start;
1910}
1911
1912
1913
1914/*
1915 * Update curdir (the name of the current directory) in response to a
1916 * cd command. We also call hashcd to let the routines in exec.c know
1917 * that the current directory has changed.
1918 */
1919
Eric Andersen2870d962001-07-02 17:27:21 +00001920static void hashcd (void);
1921
Eric Andersencb57d552001-06-28 07:25:16 +00001922static void
Eric Andersen2870d962001-07-02 17:27:21 +00001923updatepwd(const char *dir)
1924{
Eric Andersencb57d552001-06-28 07:25:16 +00001925 char *new;
1926 char *p;
1927 size_t len;
1928
Eric Andersen2870d962001-07-02 17:27:21 +00001929 hashcd(); /* update command hash table */
Eric Andersencb57d552001-06-28 07:25:16 +00001930
1931 /*
1932 * If our argument is NULL, we don't know the current directory
1933 * any more because we traversed a symbolic link or something
1934 * we couldn't stat().
1935 */
1936 if (dir == NULL || curdir == nullstr) {
1937 setpwd(0, 1);
1938 return;
1939 }
1940 len = strlen(dir);
1941 cdcomppath = sstrdup(dir);
1942 STARTSTACKSTR(new);
1943 if (*dir != '/') {
1944 p = curdir;
1945 while (*p)
1946 STPUTC(*p++, new);
1947 if (p[-1] == '/')
1948 STUNPUTC(new);
1949 }
1950 while ((p = getcomponent()) != NULL) {
1951 if (equal(p, "..")) {
1952 while (new > stackblock() && (STUNPUTC(new), *new) != '/');
1953 } else if (*p != '\0' && ! equal(p, ".")) {
1954 STPUTC('/', new);
1955 while (*p)
1956 STPUTC(*p++, new);
1957 }
1958 }
1959 if (new == stackblock())
1960 STPUTC('/', new);
1961 STACKSTRNUL(new);
1962 setpwd(stackblock(), 1);
1963}
1964
1965
Eric Andersen3102ac42001-07-06 04:26:23 +00001966#ifndef BB_PWD
Eric Andersencb57d552001-06-28 07:25:16 +00001967static int
1968pwdcmd(argc, argv)
1969 int argc;
1970 char **argv;
1971{
Eric Andersen62483552001-07-10 06:09:16 +00001972 printf(snlfmt, curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00001973 return 0;
1974}
Eric Andersen2870d962001-07-02 17:27:21 +00001975#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001976
1977/*
1978 * Find out what the current directory is. If we already know the current
1979 * directory, this routine returns immediately.
1980 */
1981static void
Eric Andersen2870d962001-07-02 17:27:21 +00001982getpwd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00001983{
Eric Andersen2870d962001-07-02 17:27:21 +00001984 curdir = xgetcwd(0);
1985 if(curdir==0)
1986 curdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00001987}
1988
1989static void
1990setpwd(const char *val, int setold)
1991{
1992 if (setold) {
1993 setvar("OLDPWD", curdir, VEXPORT);
1994 }
1995 INTOFF;
1996 if (curdir != nullstr) {
1997 free(curdir);
1998 curdir = nullstr;
1999 }
2000 if (!val) {
2001 getpwd();
2002 } else {
2003 curdir = savestr(val);
2004 }
2005 INTON;
2006 setvar("PWD", curdir, VEXPORT);
2007}
2008
Eric Andersencb57d552001-06-28 07:25:16 +00002009/*
2010 * Errors and exceptions.
2011 */
2012
2013/*
2014 * Code to handle exceptions in C.
2015 */
2016
Eric Andersen2870d962001-07-02 17:27:21 +00002017/*
2018 * We enclose jmp_buf in a structure so that we can declare pointers to
2019 * jump locations. The global variable handler contains the location to
2020 * jump to when an exception occurs, and the global variable exception
2021 * contains a code identifying the exeception. To implement nested
2022 * exception handlers, the user should save the value of handler on entry
2023 * to an inner scope, set handler to point to a jmploc structure for the
2024 * inner scope, and restore handler on exit from the scope.
2025 */
2026
2027struct jmploc {
2028 jmp_buf loc;
2029};
2030
2031/* exceptions */
2032#define EXINT 0 /* SIGINT received */
2033#define EXERROR 1 /* a generic error */
2034#define EXSHELLPROC 2 /* execute a shell procedure */
2035#define EXEXEC 3 /* command execution failed */
2036
2037static struct jmploc *handler;
Eric Andersencb57d552001-06-28 07:25:16 +00002038static int exception;
Eric Andersencb57d552001-06-28 07:25:16 +00002039
Eric Andersen2870d962001-07-02 17:27:21 +00002040static void exverror (int, const char *, va_list)
Eric Andersencb57d552001-06-28 07:25:16 +00002041 __attribute__((__noreturn__));
2042
2043/*
2044 * Called to raise an exception. Since C doesn't include exceptions, we
2045 * just do a longjmp to the exception handler. The type of exception is
2046 * stored in the global variable "exception".
2047 */
2048
Eric Andersen2870d962001-07-02 17:27:21 +00002049static void exraise (int) __attribute__((__noreturn__));
2050
Eric Andersencb57d552001-06-28 07:25:16 +00002051static void
Eric Andersen2870d962001-07-02 17:27:21 +00002052exraise(int e)
Eric Andersencb57d552001-06-28 07:25:16 +00002053{
2054#ifdef DEBUG
2055 if (handler == NULL)
2056 abort();
2057#endif
Eric Andersen62483552001-07-10 06:09:16 +00002058 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00002059 exception = e;
2060 longjmp(handler->loc, 1);
2061}
2062
2063
2064/*
2065 * Called from trap.c when a SIGINT is received. (If the user specifies
2066 * that SIGINT is to be trapped or ignored using the trap builtin, then
2067 * this routine is not called.) Suppressint is nonzero when interrupts
2068 * are held using the INTOFF macro. The call to _exit is necessary because
2069 * there is a short period after a fork before the signal handlers are
2070 * set to the appropriate value for the child. (The test for iflag is
2071 * just defensive programming.)
2072 */
2073
2074static void
Eric Andersen2870d962001-07-02 17:27:21 +00002075onint(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00002076 sigset_t mysigset;
2077
2078 if (suppressint) {
2079 intpending++;
2080 return;
2081 }
2082 intpending = 0;
2083 sigemptyset(&mysigset);
2084 sigprocmask(SIG_SETMASK, &mysigset, NULL);
2085 if (rootshell && iflag)
2086 exraise(EXINT);
2087 else {
2088 signal(SIGINT, SIG_DFL);
2089 raise(SIGINT);
2090 }
2091 /* NOTREACHED */
2092}
2093
2094
Eric Andersen2870d962001-07-02 17:27:21 +00002095static char *commandname; /* currently executing command */
2096
Eric Andersencb57d552001-06-28 07:25:16 +00002097/*
2098 * Exverror is called to raise the error exception. If the first argument
2099 * is not NULL then error prints an error message using printf style
2100 * formatting. It then raises the error exception.
2101 */
2102static void
Eric Andersen2870d962001-07-02 17:27:21 +00002103exverror(int cond, const char *msg, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00002104{
2105 CLEAR_PENDING_INT;
2106 INTOFF;
2107
2108#ifdef DEBUG
2109 if (msg)
2110 TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
2111 else
2112 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2113#endif
2114 if (msg) {
2115 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +00002116 out2fmt("%s: ", commandname);
2117 vfprintf(stderr, msg, ap);
2118 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00002119 }
Eric Andersencb57d552001-06-28 07:25:16 +00002120 exraise(cond);
2121 /* NOTREACHED */
2122}
2123
2124
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002125static void
Eric Andersencb57d552001-06-28 07:25:16 +00002126error(const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002127{
Eric Andersencb57d552001-06-28 07:25:16 +00002128 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002129 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002130 exverror(EXERROR, msg, ap);
2131 /* NOTREACHED */
2132 va_end(ap);
2133}
2134
2135
Eric Andersencb57d552001-06-28 07:25:16 +00002136static void
2137exerror(int cond, const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002138{
Eric Andersencb57d552001-06-28 07:25:16 +00002139 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002140 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002141 exverror(cond, msg, ap);
2142 /* NOTREACHED */
2143 va_end(ap);
2144}
2145
2146
2147
2148/*
2149 * Table of error messages.
2150 */
2151
2152struct errname {
Eric Andersen2870d962001-07-02 17:27:21 +00002153 short errcode; /* error number */
Eric Andersen62483552001-07-10 06:09:16 +00002154 char action; /* operation which encountered the error */
Eric Andersencb57d552001-06-28 07:25:16 +00002155};
2156
Eric Andersen2870d962001-07-02 17:27:21 +00002157/*
2158 * Types of operations (passed to the errmsg routine).
2159 */
2160
2161#define E_OPEN 01 /* opening a file */
2162#define E_CREAT 02 /* creating a file */
2163#define E_EXEC 04 /* executing a program */
Eric Andersencb57d552001-06-28 07:25:16 +00002164
2165#define ALL (E_OPEN|E_CREAT|E_EXEC)
2166
2167static const struct errname errormsg[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00002168 { EINTR, ALL },
2169 { EACCES, ALL },
2170 { EIO, ALL },
2171 { ENOENT, E_OPEN },
2172 { ENOENT, E_CREAT },
2173 { ENOENT, E_EXEC },
2174 { ENOTDIR, E_OPEN },
2175 { ENOTDIR, E_CREAT },
2176 { ENOTDIR, E_EXEC },
2177 { EISDIR, ALL },
2178 { EEXIST, E_CREAT },
2179#ifdef EMFILE
2180 { EMFILE, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002181#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002182 { ENFILE, ALL },
2183 { ENOSPC, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002184#ifdef EDQUOT
Eric Andersen2870d962001-07-02 17:27:21 +00002185 { EDQUOT, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002186#endif
2187#ifdef ENOSR
Eric Andersen2870d962001-07-02 17:27:21 +00002188 { ENOSR, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002189#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002190 { ENXIO, ALL },
2191 { EROFS, ALL },
2192 { ETXTBSY, ALL },
2193#ifdef EAGAIN
2194 { EAGAIN, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002195#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002196 { ENOMEM, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002197#ifdef ENOLINK
Eric Andersen2870d962001-07-02 17:27:21 +00002198 { ENOLINK, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002199#endif
2200#ifdef EMULTIHOP
Eric Andersen2870d962001-07-02 17:27:21 +00002201 { EMULTIHOP, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002202#endif
2203#ifdef ECOMM
Eric Andersen2870d962001-07-02 17:27:21 +00002204 { ECOMM, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002205#endif
2206#ifdef ESTALE
Eric Andersen2870d962001-07-02 17:27:21 +00002207 { ESTALE, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002208#endif
2209#ifdef ETIMEDOUT
Eric Andersen2870d962001-07-02 17:27:21 +00002210 { ETIMEDOUT, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002211#endif
2212#ifdef ELOOP
Eric Andersen2870d962001-07-02 17:27:21 +00002213 { ELOOP, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002214#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002215 { E2BIG, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002216#ifdef ELIBACC
Eric Andersen2870d962001-07-02 17:27:21 +00002217 { ELIBACC, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002218#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002219};
2220
Eric Andersen2870d962001-07-02 17:27:21 +00002221#define ERRNAME_SIZE (sizeof(errormsg)/sizeof(struct errname))
Eric Andersencb57d552001-06-28 07:25:16 +00002222
2223/*
2224 * Return a string describing an error. The returned string may be a
2225 * pointer to a static buffer that will be overwritten on the next call.
2226 * Action describes the operation that got the error.
2227 */
2228
2229static const char *
Eric Andersen2870d962001-07-02 17:27:21 +00002230errmsg(int e, int action)
Eric Andersencb57d552001-06-28 07:25:16 +00002231{
2232 struct errname const *ep;
2233 static char buf[12];
2234
Eric Andersen2870d962001-07-02 17:27:21 +00002235 for (ep = errormsg ; ep < errormsg+ERRNAME_SIZE; ep++) {
Eric Andersencb57d552001-06-28 07:25:16 +00002236 if (ep->errcode == e && (ep->action & action) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00002237 return strerror(e);
Eric Andersencb57d552001-06-28 07:25:16 +00002238 }
Eric Andersen2870d962001-07-02 17:27:21 +00002239
Eric Andersen3102ac42001-07-06 04:26:23 +00002240 snprintf(buf, sizeof buf, "error %d", e);
Eric Andersencb57d552001-06-28 07:25:16 +00002241 return buf;
2242}
2243
2244
Eric Andersen3102ac42001-07-06 04:26:23 +00002245#ifdef ASH_OPTIMIZE_FOR_SIZE
Eric Andersencb57d552001-06-28 07:25:16 +00002246static void
2247__inton() {
2248 if (--suppressint == 0 && intpending) {
2249 onint();
2250 }
2251}
Eric Andersen3102ac42001-07-06 04:26:23 +00002252static void forceinton (void) {
2253 suppressint = 0;
2254 if (intpending)
2255 onint();
2256}
Eric Andersencb57d552001-06-28 07:25:16 +00002257#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002258
2259/* flags in argument to evaltree */
Eric Andersen2870d962001-07-02 17:27:21 +00002260#define EV_EXIT 01 /* exit after evaluating tree */
2261#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2262#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00002263
Eric Andersen2870d962001-07-02 17:27:21 +00002264static int evalskip; /* set if we are skipping commands */
2265static int skipcount; /* number of levels to skip */
2266static int loopnest; /* current loop nesting level */
2267static int funcnest; /* depth of function calls */
Eric Andersencb57d552001-06-28 07:25:16 +00002268
2269
Eric Andersen2870d962001-07-02 17:27:21 +00002270static struct strlist *cmdenviron; /* environment for builtin command */
2271static int exitstatus; /* exit status of last command */
2272static int oexitstatus; /* saved exit status */
Eric Andersencb57d552001-06-28 07:25:16 +00002273
Eric Andersen62483552001-07-10 06:09:16 +00002274static void evalsubshell (const union node *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00002275static void expredir (union node *);
Eric Andersen2870d962001-07-02 17:27:21 +00002276static void prehash (union node *);
2277static void eprintlist (struct strlist *);
Eric Andersencb57d552001-06-28 07:25:16 +00002278
Eric Andersen2870d962001-07-02 17:27:21 +00002279static union node *parsecmd(int);
Eric Andersencb57d552001-06-28 07:25:16 +00002280/*
2281 * Called to reset things after an exception.
2282 */
2283
Eric Andersencb57d552001-06-28 07:25:16 +00002284/*
2285 * The eval commmand.
2286 */
Eric Andersen2870d962001-07-02 17:27:21 +00002287static void evalstring (char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00002288
2289static int
2290evalcmd(argc, argv)
2291 int argc;
2292 char **argv;
2293{
Eric Andersen2870d962001-07-02 17:27:21 +00002294 char *p;
2295 char *concat;
2296 char **ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002297
Eric Andersen2870d962001-07-02 17:27:21 +00002298 if (argc > 1) {
2299 p = argv[1];
2300 if (argc > 2) {
2301 STARTSTACKSTR(concat);
2302 ap = argv + 2;
2303 for (;;) {
2304 while (*p)
2305 STPUTC(*p++, concat);
2306 if ((p = *ap++) == NULL)
2307 break;
2308 STPUTC(' ', concat);
2309 }
2310 STPUTC('\0', concat);
2311 p = grabstackstr(concat);
2312 }
2313 evalstring(p, EV_TESTED);
2314 }
2315 return exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002316}
2317
Eric Andersencb57d552001-06-28 07:25:16 +00002318/*
2319 * Execute a command or commands contained in a string.
2320 */
2321
Eric Andersen2870d962001-07-02 17:27:21 +00002322static void evaltree (union node *, int);
2323static void setinputstring (char *);
2324static void popfile (void);
2325static void setstackmark(struct stackmark *mark);
2326static void popstackmark(struct stackmark *mark);
2327
2328
Eric Andersencb57d552001-06-28 07:25:16 +00002329static void
Eric Andersen2870d962001-07-02 17:27:21 +00002330evalstring(char *s, int flag)
2331{
Eric Andersencb57d552001-06-28 07:25:16 +00002332 union node *n;
2333 struct stackmark smark;
2334
2335 setstackmark(&smark);
2336 setinputstring(s);
2337 while ((n = parsecmd(0)) != NEOF) {
2338 evaltree(n, flag);
2339 popstackmark(&smark);
2340 }
2341 popfile();
2342 popstackmark(&smark);
2343}
2344
Eric Andersen2870d962001-07-02 17:27:21 +00002345static struct builtincmd *find_builtin (const char *);
Eric Andersen62483552001-07-10 06:09:16 +00002346static void expandarg (union node *, struct arglist *, int);
2347static void calcsize (const union node *);
2348static union node *copynode (const union node *);
2349
2350/*
2351 * Make a copy of a parse tree.
2352 */
2353
2354static int funcblocksize; /* size of structures in function */
2355static int funcstringsize; /* size of strings in node */
2356static pointer funcblock; /* block to allocate function from */
2357static char *funcstring; /* block to allocate strings from */
2358
2359
2360static inline union node *
2361copyfunc(union node *n)
2362{
2363 if (n == NULL)
2364 return NULL;
2365 funcblocksize = 0;
2366 funcstringsize = 0;
2367 calcsize(n);
2368 funcblock = ckmalloc(funcblocksize + funcstringsize);
2369 funcstring = (char *) funcblock + funcblocksize;
2370 return copynode(n);
2371}
2372
2373/*
2374 * Free a parse tree.
2375 */
Eric Andersencb57d552001-06-28 07:25:16 +00002376
2377static void
Eric Andersen62483552001-07-10 06:09:16 +00002378freefunc(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00002379{
Eric Andersen62483552001-07-10 06:09:16 +00002380 if (n)
2381 ckfree(n);
Eric Andersencb57d552001-06-28 07:25:16 +00002382}
2383
2384
Eric Andersen62483552001-07-10 06:09:16 +00002385/*
2386 * Add a new command entry, replacing any existing command entry for
2387 * the same name.
2388 */
2389
2390static inline void
2391addcmdentry(char *name, struct cmdentry *entry)
2392{
2393 struct tblentry *cmdp;
2394
2395 INTOFF;
2396 cmdp = cmdlookup(name, 1);
2397 if (cmdp->cmdtype == CMDFUNCTION) {
2398 freefunc(cmdp->param.func);
2399 }
2400 cmdp->cmdtype = entry->cmdtype;
2401 cmdp->param = entry->u;
2402 INTON;
2403}
2404
2405static inline void
2406evalloop(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002407{
2408 int status;
2409
2410 loopnest++;
2411 status = 0;
2412 for (;;) {
2413 evaltree(n->nbinary.ch1, EV_TESTED);
2414 if (evalskip) {
Eric Andersen2870d962001-07-02 17:27:21 +00002415skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002416 evalskip = 0;
2417 continue;
2418 }
2419 if (evalskip == SKIPBREAK && --skipcount <= 0)
2420 evalskip = 0;
2421 break;
2422 }
2423 if (n->type == NWHILE) {
2424 if (exitstatus != 0)
2425 break;
2426 } else {
2427 if (exitstatus == 0)
2428 break;
2429 }
2430 evaltree(n->nbinary.ch2, flags & EV_TESTED);
2431 status = exitstatus;
2432 if (evalskip)
2433 goto skipping;
2434 }
2435 loopnest--;
2436 exitstatus = status;
2437}
2438
Eric Andersencb57d552001-06-28 07:25:16 +00002439static void
Eric Andersen62483552001-07-10 06:09:16 +00002440evalfor(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002441{
2442 struct arglist arglist;
2443 union node *argp;
2444 struct strlist *sp;
2445 struct stackmark smark;
2446
2447 setstackmark(&smark);
2448 arglist.lastp = &arglist.list;
2449 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2450 oexitstatus = exitstatus;
2451 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2452 if (evalskip)
2453 goto out;
2454 }
2455 *arglist.lastp = NULL;
2456
2457 exitstatus = 0;
2458 loopnest++;
2459 for (sp = arglist.list ; sp ; sp = sp->next) {
2460 setvar(n->nfor.var, sp->text, 0);
2461 evaltree(n->nfor.body, flags & EV_TESTED);
2462 if (evalskip) {
2463 if (evalskip == SKIPCONT && --skipcount <= 0) {
2464 evalskip = 0;
2465 continue;
2466 }
2467 if (evalskip == SKIPBREAK && --skipcount <= 0)
2468 evalskip = 0;
2469 break;
2470 }
2471 }
2472 loopnest--;
2473out:
2474 popstackmark(&smark);
2475}
2476
Eric Andersen62483552001-07-10 06:09:16 +00002477static inline void
2478evalcase(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002479{
2480 union node *cp;
2481 union node *patp;
2482 struct arglist arglist;
2483 struct stackmark smark;
2484
2485 setstackmark(&smark);
2486 arglist.lastp = &arglist.list;
2487 oexitstatus = exitstatus;
2488 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2489 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2490 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2491 if (casematch(patp, arglist.list->text)) {
2492 if (evalskip == 0) {
2493 evaltree(cp->nclist.body, flags);
2494 }
2495 goto out;
2496 }
2497 }
2498 }
2499out:
2500 popstackmark(&smark);
2501}
2502
Eric Andersencb57d552001-06-28 07:25:16 +00002503/*
Eric Andersencb57d552001-06-28 07:25:16 +00002504 * Evaluate a pipeline. All the processes in the pipeline are children
2505 * of the process creating the pipeline. (This differs from some versions
2506 * of the shell, which make the last process in a pipeline the parent
2507 * of all the rest.)
2508 */
2509
Eric Andersen62483552001-07-10 06:09:16 +00002510static inline void
Eric Andersencb57d552001-06-28 07:25:16 +00002511evalpipe(n)
2512 union node *n;
2513{
2514 struct job *jp;
2515 struct nodelist *lp;
2516 int pipelen;
2517 int prevfd;
2518 int pip[2];
2519
2520 TRACE(("evalpipe(0x%lx) called\n", (long)n));
2521 pipelen = 0;
2522 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
2523 pipelen++;
2524 INTOFF;
2525 jp = makejob(n, pipelen);
2526 prevfd = -1;
2527 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
2528 prehash(lp->n);
2529 pip[1] = -1;
2530 if (lp->next) {
2531 if (pipe(pip) < 0) {
2532 close(prevfd);
2533 error("Pipe call failed");
2534 }
2535 }
2536 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
2537 INTON;
2538 if (prevfd > 0) {
2539 close(0);
2540 dup_as_newfd(prevfd, 0);
2541 close(prevfd);
2542 if (pip[0] == 0) {
2543 pip[0] = -1;
2544 }
2545 }
2546 if (pip[1] >= 0) {
2547 if (pip[0] >= 0) {
2548 close(pip[0]);
2549 }
2550 if (pip[1] != 1) {
2551 close(1);
2552 dup_as_newfd(pip[1], 1);
2553 close(pip[1]);
2554 }
2555 }
2556 evaltree(lp->n, EV_EXIT);
2557 }
2558 if (prevfd >= 0)
2559 close(prevfd);
2560 prevfd = pip[0];
2561 close(pip[1]);
2562 }
2563 INTON;
2564 if (n->npipe.backgnd == 0) {
2565 INTOFF;
2566 exitstatus = waitforjob(jp);
2567 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
2568 INTON;
2569 }
2570}
2571
Eric Andersen2870d962001-07-02 17:27:21 +00002572static void find_command (const char *, struct cmdentry *, int, const char *);
2573
2574static int
2575isassignment(const char *word) {
2576 if (!is_name(*word)) {
2577 return 0;
2578 }
2579 do {
2580 word++;
2581 } while (is_in_name(*word));
2582 return *word == '=';
2583}
2584
Eric Andersen62483552001-07-10 06:09:16 +00002585
Eric Andersencb57d552001-06-28 07:25:16 +00002586static void
Eric Andersen3102ac42001-07-06 04:26:23 +00002587evalcommand(union node *cmd, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002588{
2589 struct stackmark smark;
2590 union node *argp;
2591 struct arglist arglist;
2592 struct arglist varlist;
2593 char **argv;
2594 int argc;
2595 char **envp;
2596 struct strlist *sp;
2597 int mode;
Eric Andersencb57d552001-06-28 07:25:16 +00002598 struct cmdentry cmdentry;
2599 struct job *jp;
2600 char *volatile savecmdname;
2601 volatile struct shparam saveparam;
2602 struct localvar *volatile savelocalvars;
2603 volatile int e;
2604 char *lastarg;
2605 const char *path;
2606 const struct builtincmd *firstbltin;
2607 struct jmploc *volatile savehandler;
2608 struct jmploc jmploc;
2609#if __GNUC__
2610 /* Avoid longjmp clobbering */
2611 (void) &argv;
2612 (void) &argc;
2613 (void) &lastarg;
2614 (void) &flags;
2615#endif
2616
2617 /* First expand the arguments. */
2618 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
2619 setstackmark(&smark);
2620 arglist.lastp = &arglist.list;
2621 varlist.lastp = &varlist.list;
2622 arglist.list = 0;
2623 oexitstatus = exitstatus;
2624 exitstatus = 0;
2625 path = pathval();
2626 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
2627 expandarg(argp, &varlist, EXP_VARTILDE);
2628 }
2629 for (
2630 argp = cmd->ncmd.args; argp && !arglist.list;
2631 argp = argp->narg.next
2632 ) {
2633 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2634 }
2635 if (argp) {
2636 struct builtincmd *bcmd;
Eric Andersen62483552001-07-10 06:09:16 +00002637 int pseudovarflag;
Eric Andersencb57d552001-06-28 07:25:16 +00002638 bcmd = find_builtin(arglist.list->text);
Eric Andersen2870d962001-07-02 17:27:21 +00002639 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00002640 for (; argp; argp = argp->narg.next) {
2641 if (pseudovarflag && isassignment(argp->narg.text)) {
2642 expandarg(argp, &arglist, EXP_VARTILDE);
2643 continue;
2644 }
2645 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2646 }
2647 }
2648 *arglist.lastp = NULL;
2649 *varlist.lastp = NULL;
2650 expredir(cmd->ncmd.redirect);
2651 argc = 0;
2652 for (sp = arglist.list ; sp ; sp = sp->next)
2653 argc++;
2654 argv = stalloc(sizeof (char *) * (argc + 1));
2655
2656 for (sp = arglist.list ; sp ; sp = sp->next) {
2657 TRACE(("evalcommand arg: %s\n", sp->text));
2658 *argv++ = sp->text;
2659 }
2660 *argv = NULL;
2661 lastarg = NULL;
2662 if (iflag && funcnest == 0 && argc > 0)
2663 lastarg = argv[-1];
2664 argv -= argc;
2665
2666 /* Print the command if xflag is set. */
2667 if (xflag) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002668 out2c('+');
Eric Andersencb57d552001-06-28 07:25:16 +00002669 eprintlist(varlist.list);
2670 eprintlist(arglist.list);
Eric Andersen3102ac42001-07-06 04:26:23 +00002671 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00002672 }
2673
2674 /* Now locate the command. */
2675 if (argc == 0) {
2676 cmdentry.cmdtype = CMDBUILTIN;
2677 firstbltin = cmdentry.u.cmd = BLTINCMD;
2678 } else {
2679 const char *oldpath;
2680 int findflag = DO_ERR;
2681 int oldfindflag;
2682
2683 /*
2684 * Modify the command lookup path, if a PATH= assignment
2685 * is present
2686 */
2687 for (sp = varlist.list ; sp ; sp = sp->next)
2688 if (varequal(sp->text, defpathvar)) {
2689 path = sp->text + 5;
2690 findflag |= DO_BRUTE;
2691 }
2692 oldpath = path;
2693 oldfindflag = findflag;
2694 firstbltin = 0;
2695 for(;;) {
2696 find_command(argv[0], &cmdentry, findflag, path);
Eric Andersen2870d962001-07-02 17:27:21 +00002697 if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */
Eric Andersencb57d552001-06-28 07:25:16 +00002698 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002699 goto out;
2700 }
2701 /* implement bltin and command here */
2702 if (cmdentry.cmdtype != CMDBUILTIN) {
2703 break;
2704 }
2705 if (!firstbltin) {
2706 firstbltin = cmdentry.u.cmd;
2707 }
2708 if (cmdentry.u.cmd == BLTINCMD) {
2709 for(;;) {
2710 struct builtincmd *bcmd;
2711
2712 argv++;
2713 if (--argc == 0)
2714 goto found;
2715 if (!(bcmd = find_builtin(*argv))) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002716 out2fmt("%s: not found\n", *argv);
Eric Andersencb57d552001-06-28 07:25:16 +00002717 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002718 goto out;
2719 }
2720 cmdentry.u.cmd = bcmd;
2721 if (bcmd != BLTINCMD)
2722 break;
2723 }
2724 }
Eric Andersen2870d962001-07-02 17:27:21 +00002725 if (cmdentry.u.cmd == find_builtin("command")) {
Eric Andersencb57d552001-06-28 07:25:16 +00002726 argv++;
2727 if (--argc == 0) {
2728 goto found;
2729 }
2730 if (*argv[0] == '-') {
2731 if (!equal(argv[0], "-p")) {
2732 argv--;
2733 argc++;
2734 break;
2735 }
2736 argv++;
2737 if (--argc == 0) {
2738 goto found;
2739 }
2740 path = defpath;
2741 findflag |= DO_BRUTE;
2742 } else {
2743 path = oldpath;
2744 findflag = oldfindflag;
2745 }
2746 findflag |= DO_NOFUN;
2747 continue;
2748 }
2749found:
2750 break;
2751 }
2752 }
2753
2754 /* Fork off a child process if necessary. */
2755 if (cmd->ncmd.backgnd
2756 || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00002757 ) {
2758 jp = makejob(cmd, 1);
2759 mode = cmd->ncmd.backgnd;
Eric Andersencb57d552001-06-28 07:25:16 +00002760 if (forkshell(jp, cmd, mode) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00002761 goto parent; /* at end of routine */
Eric Andersencb57d552001-06-28 07:25:16 +00002762 flags |= EV_EXIT;
2763 }
2764
2765 /* This is the child process if a fork occurred. */
2766 /* Execute the command. */
2767 if (cmdentry.cmdtype == CMDFUNCTION) {
2768#ifdef DEBUG
2769 trputs("Shell function: "); trargs(argv);
2770#endif
2771 exitstatus = oexitstatus;
2772 redirect(cmd->ncmd.redirect, REDIR_PUSH);
2773 saveparam = shellparam;
2774 shellparam.malloc = 0;
2775 shellparam.nparam = argc - 1;
2776 shellparam.p = argv + 1;
2777 INTOFF;
2778 savelocalvars = localvars;
2779 localvars = NULL;
2780 INTON;
2781 if (setjmp(jmploc.loc)) {
2782 if (exception == EXSHELLPROC) {
2783 freeparam((volatile struct shparam *)
2784 &saveparam);
2785 } else {
2786 saveparam.optind = shellparam.optind;
2787 saveparam.optoff = shellparam.optoff;
2788 freeparam(&shellparam);
2789 shellparam = saveparam;
2790 }
2791 poplocalvars();
2792 localvars = savelocalvars;
2793 handler = savehandler;
2794 longjmp(handler->loc, 1);
2795 }
2796 savehandler = handler;
2797 handler = &jmploc;
2798 for (sp = varlist.list ; sp ; sp = sp->next)
2799 mklocal(sp->text);
2800 funcnest++;
2801 evaltree(cmdentry.u.func, flags & EV_TESTED);
2802 funcnest--;
2803 INTOFF;
2804 poplocalvars();
2805 localvars = savelocalvars;
2806 saveparam.optind = shellparam.optind;
2807 saveparam.optoff = shellparam.optoff;
2808 freeparam(&shellparam);
2809 shellparam = saveparam;
2810 handler = savehandler;
2811 popredir();
2812 INTON;
2813 if (evalskip == SKIPFUNC) {
2814 evalskip = 0;
2815 skipcount = 0;
2816 }
2817 if (flags & EV_EXIT)
2818 exitshell(exitstatus);
2819 } else if (cmdentry.cmdtype == CMDBUILTIN) {
2820#ifdef DEBUG
2821 trputs("builtin command: "); trargs(argv);
2822#endif
2823 mode = (cmdentry.u.cmd == EXECCMD)? 0 : REDIR_PUSH;
Eric Andersencb57d552001-06-28 07:25:16 +00002824 redirect(cmd->ncmd.redirect, mode);
2825 savecmdname = commandname;
Eric Andersen2870d962001-07-02 17:27:21 +00002826 if (IS_BUILTIN_SPECIAL(firstbltin)) {
Eric Andersencb57d552001-06-28 07:25:16 +00002827 listsetvar(varlist.list);
2828 } else {
2829 cmdenviron = varlist.list;
2830 }
2831 e = -1;
2832 if (setjmp(jmploc.loc)) {
2833 e = exception;
2834 exitstatus = (e == EXINT)? SIGINT+128 : 2;
2835 goto cmddone;
2836 }
2837 savehandler = handler;
2838 handler = &jmploc;
2839 commandname = argv[0];
2840 argptr = argv + 1;
Eric Andersen2870d962001-07-02 17:27:21 +00002841 optptr = NULL; /* initialize nextopt */
Eric Andersencb57d552001-06-28 07:25:16 +00002842 exitstatus = (*cmdentry.u.cmd->builtinfunc)(argc, argv);
2843 flushall();
2844cmddone:
Eric Andersencb57d552001-06-28 07:25:16 +00002845 cmdenviron = NULL;
2846 if (e != EXSHELLPROC) {
2847 commandname = savecmdname;
2848 if (flags & EV_EXIT)
2849 exitshell(exitstatus);
2850 }
2851 handler = savehandler;
2852 if (e != -1) {
2853 if ((e != EXERROR && e != EXEXEC)
2854 || cmdentry.u.cmd == BLTINCMD
2855 || cmdentry.u.cmd == DOTCMD
2856 || cmdentry.u.cmd == EVALCMD
2857 || cmdentry.u.cmd == EXECCMD)
2858 exraise(e);
2859 FORCEINTON;
2860 }
2861 if (cmdentry.u.cmd != EXECCMD)
2862 popredir();
Eric Andersencb57d552001-06-28 07:25:16 +00002863 } else {
2864#ifdef DEBUG
2865 trputs("normal command: "); trargs(argv);
2866#endif
2867 redirect(cmd->ncmd.redirect, 0);
2868 clearredir();
2869 for (sp = varlist.list ; sp ; sp = sp->next)
2870 setvareq(sp->text, VEXPORT|VSTACK);
2871 envp = environment();
2872 shellexec(argv, envp, path, cmdentry.u.index);
2873 }
2874 goto out;
2875
Eric Andersen2870d962001-07-02 17:27:21 +00002876parent: /* parent process gets here (if we forked) */
2877 if (mode == 0) { /* argument to fork */
Eric Andersencb57d552001-06-28 07:25:16 +00002878 INTOFF;
2879 exitstatus = waitforjob(jp);
2880 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00002881 }
2882
2883out:
2884 if (lastarg)
2885 setvar("_", lastarg, 0);
2886 popstackmark(&smark);
2887}
2888
Eric Andersen62483552001-07-10 06:09:16 +00002889/*
2890 * Evaluate a parse tree. The value is left in the global variable
2891 * exitstatus.
2892 */
2893static void
2894evaltree(n, flags)
2895 union node *n;
2896 int flags;
2897{
2898 int checkexit = 0;
2899 if (n == NULL) {
2900 TRACE(("evaltree(NULL) called\n"));
2901 goto out;
2902 }
2903 TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
2904 switch (n->type) {
2905 case NSEMI:
2906 evaltree(n->nbinary.ch1, flags & EV_TESTED);
2907 if (evalskip)
2908 goto out;
2909 evaltree(n->nbinary.ch2, flags);
2910 break;
2911 case NAND:
2912 evaltree(n->nbinary.ch1, EV_TESTED);
2913 if (evalskip || exitstatus != 0)
2914 goto out;
2915 evaltree(n->nbinary.ch2, flags);
2916 break;
2917 case NOR:
2918 evaltree(n->nbinary.ch1, EV_TESTED);
2919 if (evalskip || exitstatus == 0)
2920 goto out;
2921 evaltree(n->nbinary.ch2, flags);
2922 break;
2923 case NREDIR:
2924 expredir(n->nredir.redirect);
2925 redirect(n->nredir.redirect, REDIR_PUSH);
2926 evaltree(n->nredir.n, flags);
2927 popredir();
2928 break;
2929 case NSUBSHELL:
2930 evalsubshell(n, flags);
2931 break;
2932 case NBACKGND:
2933 evalsubshell(n, flags);
2934 break;
2935 case NIF: {
2936 evaltree(n->nif.test, EV_TESTED);
2937 if (evalskip)
2938 goto out;
2939 if (exitstatus == 0)
2940 evaltree(n->nif.ifpart, flags);
2941 else if (n->nif.elsepart)
2942 evaltree(n->nif.elsepart, flags);
2943 else
2944 exitstatus = 0;
2945 break;
2946 }
2947 case NWHILE:
2948 case NUNTIL:
2949 evalloop(n, flags);
2950 break;
2951 case NFOR:
2952 evalfor(n, flags);
2953 break;
2954 case NCASE:
2955 evalcase(n, flags);
2956 break;
2957 case NDEFUN: {
2958 struct builtincmd *bcmd;
2959 struct cmdentry entry;
2960 if (
2961 (bcmd = find_builtin(n->narg.text)) &&
2962 IS_BUILTIN_SPECIAL(bcmd)
2963 ) {
2964 out2fmt("%s is a special built-in\n", n->narg.text);
2965 exitstatus = 1;
2966 break;
2967 }
2968 entry.cmdtype = CMDFUNCTION;
2969 entry.u.func = copyfunc(n->narg.next);
2970 addcmdentry(n->narg.text, &entry);
2971 exitstatus = 0;
2972 break;
2973 }
2974 case NNOT:
2975 evaltree(n->nnot.com, EV_TESTED);
2976 exitstatus = !exitstatus;
2977 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002978
Eric Andersen62483552001-07-10 06:09:16 +00002979 case NPIPE:
2980 evalpipe(n);
2981 checkexit = 1;
2982 break;
2983 case NCMD:
2984 evalcommand(n, flags);
2985 checkexit = 1;
2986 break;
2987#ifdef DEBUG
2988 default:
2989 printf("Node type = %d\n", n->type);
2990 break;
2991#endif
2992 }
2993out:
2994 if (pendingsigs)
2995 dotrap();
2996 if (
2997 flags & EV_EXIT ||
2998 (checkexit && eflag && exitstatus && !(flags & EV_TESTED))
2999 )
3000 exitshell(exitstatus);
3001}
3002
3003/*
3004 * Kick off a subshell to evaluate a tree.
3005 */
3006
3007static void
3008evalsubshell(const union node *n, int flags)
3009{
3010 struct job *jp;
3011 int backgnd = (n->type == NBACKGND);
3012
3013 expredir(n->nredir.redirect);
3014 jp = makejob(n, 1);
3015 if (forkshell(jp, n, backgnd) == 0) {
3016 if (backgnd)
3017 flags &=~ EV_TESTED;
3018 redirect(n->nredir.redirect, 0);
3019 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
3020 }
3021 if (! backgnd) {
3022 INTOFF;
3023 exitstatus = waitforjob(jp);
3024 INTON;
3025 }
3026}
3027
3028/*
3029 * Compute the names of the files in a redirection list.
3030 */
3031
3032static void fixredir(union node *n, const char *text, int err);
3033
3034static void
3035expredir(union node *n)
3036{
3037 union node *redir;
3038
3039 for (redir = n ; redir ; redir = redir->nfile.next) {
3040 struct arglist fn;
3041 fn.lastp = &fn.list;
3042 oexitstatus = exitstatus;
3043 switch (redir->type) {
3044 case NFROMTO:
3045 case NFROM:
3046 case NTO:
3047 case NAPPEND:
3048 case NTOOV:
3049 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3050 redir->nfile.expfname = fn.list->text;
3051 break;
3052 case NFROMFD:
3053 case NTOFD:
3054 if (redir->ndup.vname) {
3055 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3056 fixredir(redir, fn.list->text, 1);
3057 }
3058 break;
3059 }
3060 }
3061}
3062
3063
3064/*
3065 * Execute a command inside back quotes. If it's a builtin command, we
3066 * want to save its output in a block obtained from malloc. Otherwise
3067 * we fork off a subprocess and get the output of the command via a pipe.
3068 * Should be called with interrupts off.
3069 */
3070
3071static void
3072evalbackcmd(union node *n, struct backcmd *result)
3073{
3074 int pip[2];
3075 struct job *jp;
3076 struct stackmark smark; /* unnecessary */
3077
3078 setstackmark(&smark);
3079 result->fd = -1;
3080 result->buf = NULL;
3081 result->nleft = 0;
3082 result->jp = NULL;
3083 if (n == NULL) {
3084 exitstatus = 0;
3085 goto out;
3086 }
3087 exitstatus = 0;
3088 if (pipe(pip) < 0)
3089 error("Pipe call failed");
3090 jp = makejob(n, 1);
3091 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3092 FORCEINTON;
3093 close(pip[0]);
3094 if (pip[1] != 1) {
3095 close(1);
3096 dup_as_newfd(pip[1], 1);
3097 close(pip[1]);
3098 }
3099 eflag = 0;
3100 evaltree(n, EV_EXIT);
3101 }
3102 close(pip[1]);
3103 result->fd = pip[0];
3104 result->jp = jp;
3105out:
3106 popstackmark(&smark);
3107 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
3108 result->fd, result->buf, result->nleft, result->jp));
3109}
3110
3111
3112/*
3113 * Execute a simple command.
3114 */
Eric Andersencb57d552001-06-28 07:25:16 +00003115
3116/*
3117 * Search for a command. This is called before we fork so that the
3118 * location of the command will be available in the parent as well as
3119 * the child. The check for "goodname" is an overly conservative
3120 * check that the name will not be subject to expansion.
3121 */
3122
3123static void
3124prehash(n)
3125 union node *n;
3126{
3127 struct cmdentry entry;
3128
3129 if (n->type == NCMD && n->ncmd.args)
3130 if (goodname(n->ncmd.args->narg.text))
3131 find_command(n->ncmd.args->narg.text, &entry, 0,
3132 pathval());
3133}
3134
3135
Eric Andersencb57d552001-06-28 07:25:16 +00003136/*
3137 * Builtin commands. Builtin commands whose functions are closely
3138 * tied to evaluation are implemented here.
3139 */
3140
3141/*
3142 * No command given, or a bltin command with no arguments. Set the
3143 * specified variables.
3144 */
3145
3146int
3147bltincmd(argc, argv)
3148 int argc;
3149 char **argv;
3150{
3151 /*
3152 * Preserve exitstatus of a previous possible redirection
3153 * as POSIX mandates
3154 */
3155 return exitstatus;
3156}
3157
3158
3159/*
3160 * Handle break and continue commands. Break, continue, and return are
3161 * all handled by setting the evalskip flag. The evaluation routines
3162 * above all check this flag, and if it is set they start skipping
3163 * commands rather than executing them. The variable skipcount is
3164 * the number of loops to break/continue, or the number of function
3165 * levels to return. (The latter is always 1.) It should probably
3166 * be an error to break out of more loops than exist, but it isn't
3167 * in the standard shell so we don't make it one here.
3168 */
3169
3170static int
3171breakcmd(argc, argv)
3172 int argc;
3173 char **argv;
3174{
3175 int n = argc > 1 ? number(argv[1]) : 1;
3176
3177 if (n > loopnest)
3178 n = loopnest;
3179 if (n > 0) {
3180 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
3181 skipcount = n;
3182 }
3183 return 0;
3184}
3185
3186
3187/*
3188 * The return command.
3189 */
3190
3191static int
3192returncmd(argc, argv)
3193 int argc;
3194 char **argv;
3195{
3196 int ret = argc > 1 ? number(argv[1]) : oexitstatus;
3197
3198 if (funcnest) {
3199 evalskip = SKIPFUNC;
3200 skipcount = 1;
3201 return ret;
3202 }
3203 else {
3204 /* Do what ksh does; skip the rest of the file */
3205 evalskip = SKIPFILE;
3206 skipcount = 1;
3207 return ret;
3208 }
3209}
3210
3211
3212#ifndef BB_TRUE_FALSE
3213static int
3214false_main(argc, argv)
3215 int argc;
3216 char **argv;
3217{
3218 return 1;
3219}
3220
3221
3222static int
3223true_main(argc, argv)
3224 int argc;
3225 char **argv;
3226{
3227 return 0;
3228}
3229#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003230
3231/*
3232 * Controls whether the shell is interactive or not.
3233 */
3234
3235static void setsignal(int signo);
3236static void chkmail(int silent);
3237
3238
3239static void
3240setinteractive(int on)
3241{
3242 static int is_interactive;
Eric Andersen1c039232001-07-07 00:05:55 +00003243 static int do_banner=0;
Eric Andersen2870d962001-07-02 17:27:21 +00003244
3245 if (on == is_interactive)
3246 return;
3247 setsignal(SIGINT);
3248 setsignal(SIGQUIT);
3249 setsignal(SIGTERM);
3250 chkmail(1);
3251 is_interactive = on;
Eric Andersen1c039232001-07-07 00:05:55 +00003252 if (do_banner==0 && is_interactive) {
3253 /* Looks like they want an interactive shell */
3254 printf( "\n\n" BB_BANNER " Built-in shell (ash)\n");
3255 printf( "Enter 'help' for a list of built-in commands.\n\n");
3256 do_banner=1;
3257 }
Eric Andersen2870d962001-07-02 17:27:21 +00003258}
3259
3260static void
3261optschanged(void)
3262{
3263 setinteractive(iflag);
3264 setjobctl(mflag);
3265}
3266
Eric Andersencb57d552001-06-28 07:25:16 +00003267
3268static int
3269execcmd(argc, argv)
3270 int argc;
3271 char **argv;
3272{
3273 if (argc > 1) {
3274 struct strlist *sp;
3275
Eric Andersen2870d962001-07-02 17:27:21 +00003276 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003277 mflag = 0;
3278 optschanged();
3279 for (sp = cmdenviron; sp ; sp = sp->next)
3280 setvareq(sp->text, VEXPORT|VSTACK);
3281 shellexec(argv + 1, environment(), pathval(), 0);
3282 }
3283 return 0;
3284}
3285
3286static void
3287eprintlist(struct strlist *sp)
3288{
3289 for (; sp; sp = sp->next) {
Eric Andersen3102ac42001-07-06 04:26:23 +00003290 out2fmt(" %s",sp->text);
Eric Andersencb57d552001-06-28 07:25:16 +00003291 }
3292}
Eric Andersencb57d552001-06-28 07:25:16 +00003293
3294/*
3295 * Exec a program. Never returns. If you change this routine, you may
3296 * have to change the find_command routine as well.
3297 */
3298
Eric Andersen2870d962001-07-02 17:27:21 +00003299static const char *pathopt; /* set by padvance */
3300
Eric Andersencb57d552001-06-28 07:25:16 +00003301static void
3302shellexec(argv, envp, path, idx)
3303 char **argv, **envp;
3304 const char *path;
3305 int idx;
3306{
3307 char *cmdname;
3308 int e;
3309
3310 if (strchr(argv[0], '/') != NULL) {
3311 tryexec(argv[0], argv, envp);
3312 e = errno;
3313 } else {
3314 e = ENOENT;
3315 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3316 if (--idx < 0 && pathopt == NULL) {
3317 tryexec(cmdname, argv, envp);
3318 if (errno != ENOENT && errno != ENOTDIR)
3319 e = errno;
3320 }
3321 stunalloc(cmdname);
3322 }
3323 }
3324
3325 /* Map to POSIX errors */
3326 switch (e) {
3327 case EACCES:
3328 exerrno = 126;
3329 break;
3330 case ENOENT:
3331 exerrno = 127;
3332 break;
3333 default:
3334 exerrno = 2;
3335 break;
3336 }
3337 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3338 /* NOTREACHED */
3339}
3340
Eric Andersen2870d962001-07-02 17:27:21 +00003341/*
3342 * Clear traps on a fork.
3343 */
3344static void
3345clear_traps(void) {
3346 char **tp;
3347
3348 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
3349 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
3350 INTOFF;
3351 ckfree(*tp);
3352 *tp = NULL;
3353 if (tp != &trap[0])
3354 setsignal(tp - trap);
3355 INTON;
3356 }
3357 }
3358}
3359
3360
3361static void
3362initshellproc(void) {
3363
3364#ifdef ASH_ALIAS
3365 /* from alias.c: */
3366 {
3367 rmaliases();
3368 }
3369#endif
3370 /* from eval.c: */
3371 {
3372 exitstatus = 0;
3373 }
3374
3375 /* from exec.c: */
3376 {
3377 deletefuncs();
3378 }
3379
3380 /* from jobs.c: */
3381 {
3382 backgndpid = -1;
3383#ifdef JOBS
3384 jobctl = 0;
3385#endif
3386 }
3387
3388 /* from options.c: */
3389 {
3390 int i;
3391
3392 for (i = 0; i < NOPTS; i++)
3393 optent_val(i) = 0;
3394 optschanged();
3395
3396 }
3397
3398 /* from redir.c: */
3399 {
3400 clearredir();
3401 }
3402
3403 /* from trap.c: */
3404 {
3405 char *sm;
3406
3407 clear_traps();
3408 for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) {
3409 if (*sm == S_IGN)
3410 *sm = S_HARD_IGN;
3411 }
3412 }
3413
3414 /* from var.c: */
3415 {
3416 shprocvar();
3417 }
3418}
3419
3420static int preadbuffer(void);
3421static void pushfile (void);
Eric Andersen2870d962001-07-02 17:27:21 +00003422
3423/*
3424 * Read a character from the script, returning PEOF on end of file.
3425 * Nul characters in the input are silently discarded.
3426 */
3427
Eric Andersen3102ac42001-07-06 04:26:23 +00003428#ifndef ASH_OPTIMIZE_FOR_SIZE
Eric Andersen2870d962001-07-02 17:27:21 +00003429#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
3430static int
3431pgetc(void)
3432{
3433 return pgetc_macro();
3434}
3435#else
3436static int
3437pgetc_macro(void)
3438{
3439 return --parsenleft >= 0? *parsenextc++ : preadbuffer();
3440}
3441
3442static inline int
3443pgetc(void)
3444{
3445 return pgetc_macro();
3446}
3447#endif
3448
3449
3450/*
3451 * Undo the last call to pgetc. Only one character may be pushed back.
3452 * PEOF may be pushed back.
3453 */
3454
3455static void
3456pungetc() {
3457 parsenleft++;
3458 parsenextc--;
3459}
3460
3461
3462static void
3463popfile(void) {
3464 struct parsefile *pf = parsefile;
3465
3466 INTOFF;
3467 if (pf->fd >= 0)
3468 close(pf->fd);
3469 if (pf->buf)
3470 ckfree(pf->buf);
3471 while (pf->strpush)
3472 popstring();
3473 parsefile = pf->prev;
3474 ckfree(pf);
3475 parsenleft = parsefile->nleft;
3476 parselleft = parsefile->lleft;
3477 parsenextc = parsefile->nextc;
3478 plinno = parsefile->linno;
3479 INTON;
3480}
3481
3482
3483/*
3484 * Return to top level.
3485 */
3486
3487static void
3488popallfiles(void) {
3489 while (parsefile != &basepf)
3490 popfile();
3491}
3492
3493/*
3494 * Close the file(s) that the shell is reading commands from. Called
3495 * after a fork is done.
3496 */
3497
3498static void
3499closescript() {
3500 popallfiles();
3501 if (parsefile->fd > 0) {
3502 close(parsefile->fd);
3503 parsefile->fd = 0;
3504 }
3505}
3506
3507
3508/*
3509 * Like setinputfile, but takes an open file descriptor. Call this with
3510 * interrupts off.
3511 */
3512
3513static void
3514setinputfd(fd, push)
3515 int fd, push;
3516{
3517 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
3518 if (push) {
3519 pushfile();
3520 parsefile->buf = 0;
3521 } else {
3522 closescript();
3523 while (parsefile->strpush)
3524 popstring();
3525 }
3526 parsefile->fd = fd;
3527 if (parsefile->buf == NULL)
3528 parsefile->buf = ckmalloc(BUFSIZ);
3529 parselleft = parsenleft = 0;
3530 plinno = 1;
3531}
3532
3533
3534/*
3535 * Set the input to take input from a file. If push is set, push the
3536 * old input onto the stack first.
3537 */
3538
3539static void
3540setinputfile(const char *fname, int push)
3541{
3542 int fd;
3543 int myfileno2;
3544
3545 INTOFF;
3546 if ((fd = open(fname, O_RDONLY)) < 0)
3547 error("Can't open %s", fname);
3548 if (fd < 10) {
3549 myfileno2 = dup_as_newfd(fd, 10);
3550 close(fd);
3551 if (myfileno2 < 0)
3552 error("Out of file descriptors");
3553 fd = myfileno2;
3554 }
3555 setinputfd(fd, push);
3556 INTON;
3557}
3558
Eric Andersencb57d552001-06-28 07:25:16 +00003559
3560static void
Eric Andersen62483552001-07-10 06:09:16 +00003561tryexec(char *cmd, char **argv, char **envp)
3562{
Eric Andersencb57d552001-06-28 07:25:16 +00003563 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003564
Eric Andersen3102ac42001-07-06 04:26:23 +00003565#ifdef BB_FEATURE_SH_STANDALONE_SHELL
3566 char *name = cmd;
3567 char** argv_l=argv;
3568 int argc_l;
3569#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
3570 name = get_last_path_component(name);
3571#endif
3572 argv_l=envp;
3573 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
3574 putenv(*argv_l);
3575 argv_l=argv;
Eric Andersen62483552001-07-10 06:09:16 +00003576 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
Eric Andersen3102ac42001-07-06 04:26:23 +00003577 optind = 1;
3578 run_applet_by_name(name, argc_l, argv);
3579#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003580 execve(cmd, argv, envp);
Eric Andersencb57d552001-06-28 07:25:16 +00003581 e = errno;
3582 if (e == ENOEXEC) {
3583 INTOFF;
3584 initshellproc();
3585 setinputfile(cmd, 0);
3586 commandname = arg0 = savestr(argv[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00003587 setparam(argv + 1);
3588 exraise(EXSHELLPROC);
3589 }
3590 errno = e;
3591}
3592
Eric Andersen2870d962001-07-02 17:27:21 +00003593static char *commandtext (const union node *);
Eric Andersencb57d552001-06-28 07:25:16 +00003594
3595/*
3596 * Do a path search. The variable path (passed by reference) should be
3597 * set to the start of the path before the first call; padvance will update
3598 * this value as it proceeds. Successive calls to padvance will return
3599 * the possible path expansions in sequence. If an option (indicated by
3600 * a percent sign) appears in the path entry then the global variable
3601 * pathopt will be set to point to it; otherwise pathopt will be set to
3602 * NULL.
3603 */
3604
3605static const char *pathopt;
3606
Eric Andersen2870d962001-07-02 17:27:21 +00003607static void growstackblock(void);
3608
3609
Eric Andersencb57d552001-06-28 07:25:16 +00003610static char *
Eric Andersen2870d962001-07-02 17:27:21 +00003611padvance(const char **path, const char *name)
3612{
Eric Andersencb57d552001-06-28 07:25:16 +00003613 const char *p;
3614 char *q;
3615 const char *start;
3616 int len;
3617
3618 if (*path == NULL)
3619 return NULL;
3620 start = *path;
3621 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
Eric Andersen2870d962001-07-02 17:27:21 +00003622 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003623 while (stackblocksize() < len)
3624 growstackblock();
3625 q = stackblock();
3626 if (p != start) {
3627 memcpy(q, start, p - start);
3628 q += p - start;
3629 *q++ = '/';
3630 }
3631 strcpy(q, name);
3632 pathopt = NULL;
3633 if (*p == '%') {
3634 pathopt = ++p;
3635 while (*p && *p != ':') p++;
3636 }
3637 if (*p == ':')
3638 *path = p + 1;
3639 else
3640 *path = NULL;
3641 return stalloc(len);
3642}
3643
Eric Andersen62483552001-07-10 06:09:16 +00003644/*
3645 * Wrapper around strcmp for qsort/bsearch/...
3646 */
3647static int
3648pstrcmp(const void *a, const void *b)
3649{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003650 return strcmp((const char *) a, (*(const char *const *) b) + 1);
Eric Andersen62483552001-07-10 06:09:16 +00003651}
3652
3653/*
3654 * Find a keyword is in a sorted array.
3655 */
3656
3657static const char *const *
3658findkwd(const char *s)
3659{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003660 return bsearch(s, tokname_array + KWDOFFSET,
3661 (sizeof(tokname_array)/sizeof(const char *)) - KWDOFFSET,
3662 sizeof(const char *), pstrcmp);
Eric Andersen62483552001-07-10 06:09:16 +00003663}
Eric Andersencb57d552001-06-28 07:25:16 +00003664
3665
3666/*** Command hashing code ***/
3667
3668
3669static int
3670hashcmd(argc, argv)
3671 int argc;
3672 char **argv;
3673{
3674 struct tblentry **pp;
3675 struct tblentry *cmdp;
3676 int c;
3677 int verbose;
3678 struct cmdentry entry;
3679 char *name;
Eric Andersen62483552001-07-10 06:09:16 +00003680#ifdef ASH_ALIAS
3681 const struct alias *ap;
3682#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003683
3684 verbose = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003685 while ((c = nextopt("rvV")) != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00003686 if (c == 'r') {
3687 clearcmdentry(0);
3688 return 0;
Eric Andersen62483552001-07-10 06:09:16 +00003689 } else if (c == 'v' || c == 'V') {
3690 verbose = c;
Eric Andersencb57d552001-06-28 07:25:16 +00003691 }
3692 }
3693 if (*argptr == NULL) {
3694 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3695 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3696 if (cmdp->cmdtype != CMDBUILTIN) {
3697 printentry(cmdp, verbose);
3698 }
3699 }
3700 }
3701 return 0;
3702 }
3703 c = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003704 while ((name = *argptr++) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00003705 if ((cmdp = cmdlookup(name, 0)) != NULL
3706 && (cmdp->cmdtype == CMDNORMAL
3707 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3708 delete_cmd_entry();
Eric Andersen62483552001-07-10 06:09:16 +00003709#ifdef ASH_ALIAS
3710 /* Then look at the aliases */
3711 if ((ap = lookupalias(name, 0)) != NULL) {
3712 if (verbose=='v')
3713 printf("%s is an alias for %s\n", name, ap->val);
3714 else
3715 printalias(ap);
3716 continue;
3717 }
3718#endif
3719 /* First look at the keywords */
3720 if (findkwd(name)!=0) {
3721 if (verbose=='v')
3722 printf("%s is a shell keyword\n", name);
3723 else
3724 printf(snlfmt, name);
3725 continue;
3726 }
3727
Eric Andersencb57d552001-06-28 07:25:16 +00003728 find_command(name, &entry, DO_ERR, pathval());
3729 if (entry.cmdtype == CMDUNKNOWN) c = 1;
3730 else if (verbose) {
3731 cmdp = cmdlookup(name, 0);
Eric Andersen62483552001-07-10 06:09:16 +00003732 if (cmdp) printentry(cmdp, verbose=='v');
Eric Andersencb57d552001-06-28 07:25:16 +00003733 flushall();
3734 }
Eric Andersencb57d552001-06-28 07:25:16 +00003735 }
3736 return c;
3737}
3738
Eric Andersencb57d552001-06-28 07:25:16 +00003739static void
3740printentry(cmdp, verbose)
3741 struct tblentry *cmdp;
3742 int verbose;
3743 {
3744 int idx;
3745 const char *path;
3746 char *name;
3747
Eric Andersen62483552001-07-10 06:09:16 +00003748 printf("%s%s", cmdp->cmdname, (verbose ? " is " : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00003749 if (cmdp->cmdtype == CMDNORMAL) {
3750 idx = cmdp->param.index;
3751 path = pathval();
3752 do {
3753 name = padvance(&path, cmdp->cmdname);
3754 stunalloc(name);
3755 } while (--idx >= 0);
Eric Andersen62483552001-07-10 06:09:16 +00003756 if(verbose)
3757 out1str(name);
Eric Andersencb57d552001-06-28 07:25:16 +00003758 } else if (cmdp->cmdtype == CMDBUILTIN) {
Eric Andersen62483552001-07-10 06:09:16 +00003759 if(verbose)
3760 out1str("a shell builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00003761 } else if (cmdp->cmdtype == CMDFUNCTION) {
Eric Andersencb57d552001-06-28 07:25:16 +00003762 if (verbose) {
3763 INTOFF;
Eric Andersen62483552001-07-10 06:09:16 +00003764 out1str("a function\n");
Eric Andersencb57d552001-06-28 07:25:16 +00003765 name = commandtext(cmdp->param.func);
Eric Andersen62483552001-07-10 06:09:16 +00003766 printf("%s() {\n %s\n}", cmdp->cmdname, name);
Eric Andersencb57d552001-06-28 07:25:16 +00003767 ckfree(name);
3768 INTON;
3769 }
3770#ifdef DEBUG
3771 } else {
3772 error("internal error: cmdtype %d", cmdp->cmdtype);
3773#endif
3774 }
Eric Andersen62483552001-07-10 06:09:16 +00003775 printf(snlfmt, cmdp->rehash ? "*" : nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +00003776}
3777
3778
3779
Eric Andersen1c039232001-07-07 00:05:55 +00003780/*** List the available builtins ***/
3781
3782
3783static int helpcmd(int argc, char** argv)
3784{
3785 int col, i;
Eric Andersen1c039232001-07-07 00:05:55 +00003786
Eric Andersen62483552001-07-10 06:09:16 +00003787 printf("\nBuilt-in commands:\n-------------------\n");
3788 for (col=0, i=0; i < NUMBUILTINS; i++) {
3789 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3790 builtincmds[i].name+1);
Eric Andersen1c039232001-07-07 00:05:55 +00003791 if (col > 60) {
3792 printf("\n");
3793 col = 0;
3794 }
3795 }
3796#ifdef BB_FEATURE_SH_STANDALONE_SHELL
3797 {
Eric Andersen1c039232001-07-07 00:05:55 +00003798 extern const struct BB_applet applets[];
3799 extern const size_t NUM_APPLETS;
3800
Eric Andersen62483552001-07-10 06:09:16 +00003801 for (i=0; i < NUM_APPLETS; i++) {
3802
3803 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3804 applets[i].name);
Eric Andersen1c039232001-07-07 00:05:55 +00003805 if (col > 60) {
3806 printf("\n");
3807 col = 0;
3808 }
3809 }
3810 }
3811#endif
3812 printf("\n\n");
3813 return EXIT_SUCCESS;
3814}
3815
Eric Andersencb57d552001-06-28 07:25:16 +00003816/*
3817 * Resolve a command name. If you change this routine, you may have to
3818 * change the shellexec routine as well.
3819 */
3820
Eric Andersen2870d962001-07-02 17:27:21 +00003821static int prefix (const char *, const char *);
3822
Eric Andersencb57d552001-06-28 07:25:16 +00003823static void
Eric Andersen2870d962001-07-02 17:27:21 +00003824find_command(const char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003825{
3826 struct tblentry *cmdp;
3827 int idx;
3828 int prev;
3829 char *fullname;
3830 struct stat statb;
3831 int e;
3832 int bltin;
3833 int firstchange;
3834 int updatetbl;
Eric Andersen62483552001-07-10 06:09:16 +00003835 int regular;
Eric Andersencb57d552001-06-28 07:25:16 +00003836 struct builtincmd *bcmd;
3837
3838 /* If name contains a slash, don't use the hash table */
3839 if (strchr(name, '/') != NULL) {
3840 if (act & DO_ABS) {
3841 while (stat(name, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003842 if (errno != ENOENT && errno != ENOTDIR)
3843 e = errno;
3844 entry->cmdtype = CMDUNKNOWN;
3845 entry->u.index = -1;
3846 return;
3847 }
3848 entry->cmdtype = CMDNORMAL;
3849 entry->u.index = -1;
3850 return;
3851 }
3852 entry->cmdtype = CMDNORMAL;
3853 entry->u.index = 0;
3854 return;
3855 }
3856
3857 updatetbl = 1;
3858 if (act & DO_BRUTE) {
3859 firstchange = path_change(path, &bltin);
3860 } else {
3861 bltin = builtinloc;
3862 firstchange = 9999;
3863 }
3864
3865 /* If name is in the table, and not invalidated by cd, we're done */
3866 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
3867 if (cmdp->cmdtype == CMDFUNCTION) {
3868 if (act & DO_NOFUN) {
3869 updatetbl = 0;
3870 } else {
3871 goto success;
3872 }
3873 } else if (act & DO_BRUTE) {
3874 if ((cmdp->cmdtype == CMDNORMAL &&
3875 cmdp->param.index >= firstchange) ||
3876 (cmdp->cmdtype == CMDBUILTIN &&
3877 ((builtinloc < 0 && bltin >= 0) ?
3878 bltin : builtinloc) >= firstchange)) {
3879 /* need to recompute the entry */
3880 } else {
3881 goto success;
3882 }
3883 } else {
3884 goto success;
3885 }
3886 }
3887
3888 bcmd = find_builtin(name);
Eric Andersen2870d962001-07-02 17:27:21 +00003889 regular = bcmd && IS_BUILTIN_REGULAR(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00003890
3891 if (regular) {
3892 if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) {
Eric Andersen2870d962001-07-02 17:27:21 +00003893 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003894 }
3895 } else if (act & DO_BRUTE) {
3896 if (firstchange == 0) {
3897 updatetbl = 0;
3898 }
3899 }
3900
3901 /* If %builtin not in path, check for builtin next */
3902 if (regular || (bltin < 0 && bcmd)) {
3903builtin:
3904 if (!updatetbl) {
3905 entry->cmdtype = CMDBUILTIN;
3906 entry->u.cmd = bcmd;
3907 return;
3908 }
3909 INTOFF;
3910 cmdp = cmdlookup(name, 1);
3911 cmdp->cmdtype = CMDBUILTIN;
3912 cmdp->param.cmd = bcmd;
3913 INTON;
3914 goto success;
3915 }
3916
3917 /* We have to search path. */
Eric Andersen2870d962001-07-02 17:27:21 +00003918 prev = -1; /* where to start */
3919 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00003920 if (cmdp->cmdtype == CMDBUILTIN)
3921 prev = builtinloc;
3922 else
3923 prev = cmdp->param.index;
3924 }
3925
3926 e = ENOENT;
3927 idx = -1;
3928loop:
3929 while ((fullname = padvance(&path, name)) != NULL) {
3930 stunalloc(fullname);
3931 idx++;
3932 if (idx >= firstchange) {
3933 updatetbl = 0;
3934 }
3935 if (pathopt) {
3936 if (prefix("builtin", pathopt)) {
3937 if ((bcmd = find_builtin(name))) {
3938 goto builtin;
3939 }
3940 continue;
3941 } else if (!(act & DO_NOFUN) &&
3942 prefix("func", pathopt)) {
3943 /* handled below */
3944 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00003945 continue; /* ignore unimplemented options */
Eric Andersencb57d552001-06-28 07:25:16 +00003946 }
3947 }
3948 /* if rehash, don't redo absolute path names */
3949 if (fullname[0] == '/' && idx <= prev &&
3950 idx < firstchange) {
3951 if (idx < prev)
3952 continue;
3953 TRACE(("searchexec \"%s\": no change\n", name));
3954 goto success;
3955 }
3956 while (stat(fullname, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003957 if (errno != ENOENT && errno != ENOTDIR)
3958 e = errno;
3959 goto loop;
3960 }
Eric Andersen2870d962001-07-02 17:27:21 +00003961 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00003962 if (!S_ISREG(statb.st_mode))
3963 continue;
Eric Andersen2870d962001-07-02 17:27:21 +00003964 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00003965 stalloc(strlen(fullname) + 1);
3966 readcmdfile(fullname);
3967 if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
3968 error("%s not defined in %s", name, fullname);
3969 stunalloc(fullname);
3970 goto success;
3971 }
Eric Andersencb57d552001-06-28 07:25:16 +00003972 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
3973 /* If we aren't called with DO_BRUTE and cmdp is set, it must
3974 be a function and we're being called with DO_NOFUN */
3975 if (!updatetbl) {
3976 entry->cmdtype = CMDNORMAL;
3977 entry->u.index = idx;
3978 return;
3979 }
3980 INTOFF;
3981 cmdp = cmdlookup(name, 1);
3982 cmdp->cmdtype = CMDNORMAL;
3983 cmdp->param.index = idx;
3984 INTON;
3985 goto success;
3986 }
3987
3988 /* We failed. If there was an entry for this command, delete it */
3989 if (cmdp && updatetbl)
3990 delete_cmd_entry();
3991 if (act & DO_ERR)
Eric Andersen3102ac42001-07-06 04:26:23 +00003992 out2fmt("%s: %s\n", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00003993 entry->cmdtype = CMDUNKNOWN;
3994 return;
3995
3996success:
3997 cmdp->rehash = 0;
3998 entry->cmdtype = cmdp->cmdtype;
3999 entry->u = cmdp->param;
4000}
4001
4002
4003
4004/*
4005 * Search the table of builtin commands.
4006 */
4007
Eric Andersen2870d962001-07-02 17:27:21 +00004008static int
4009bstrcmp(const void *name, const void *b)
4010{
4011 return strcmp((const char *)name, (*(const char *const *) b)+1);
4012}
4013
4014static struct builtincmd *
4015find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00004016{
4017 struct builtincmd *bp;
4018
Eric Andersen2870d962001-07-02 17:27:21 +00004019 bp = bsearch(name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd),
4020 bstrcmp
Eric Andersencb57d552001-06-28 07:25:16 +00004021 );
4022 return bp;
4023}
4024
4025
4026/*
4027 * Called when a cd is done. Marks all commands so the next time they
4028 * are executed they will be rehashed.
4029 */
4030
4031static void
Eric Andersen2870d962001-07-02 17:27:21 +00004032hashcd(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00004033 struct tblentry **pp;
4034 struct tblentry *cmdp;
4035
4036 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4037 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4038 if (cmdp->cmdtype == CMDNORMAL
4039 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
4040 cmdp->rehash = 1;
4041 }
4042 }
4043}
4044
4045
4046
4047/*
4048 * Called before PATH is changed. The argument is the new value of PATH;
4049 * pathval() still returns the old value at this point. Called with
4050 * interrupts off.
4051 */
4052
4053static void
Eric Andersen2870d962001-07-02 17:27:21 +00004054changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00004055{
4056 int firstchange;
4057 int bltin;
4058
4059 firstchange = path_change(newval, &bltin);
4060 if (builtinloc < 0 && bltin >= 0)
Eric Andersen2870d962001-07-02 17:27:21 +00004061 builtinloc = bltin; /* zap builtins */
Eric Andersencb57d552001-06-28 07:25:16 +00004062 clearcmdentry(firstchange);
4063 builtinloc = bltin;
4064}
4065
4066
4067/*
4068 * Clear out command entries. The argument specifies the first entry in
4069 * PATH which has changed.
4070 */
4071
4072static void
4073clearcmdentry(firstchange)
4074 int firstchange;
4075{
4076 struct tblentry **tblp;
4077 struct tblentry **pp;
4078 struct tblentry *cmdp;
4079
4080 INTOFF;
4081 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4082 pp = tblp;
4083 while ((cmdp = *pp) != NULL) {
4084 if ((cmdp->cmdtype == CMDNORMAL &&
4085 cmdp->param.index >= firstchange)
4086 || (cmdp->cmdtype == CMDBUILTIN &&
4087 builtinloc >= firstchange)) {
4088 *pp = cmdp->next;
4089 ckfree(cmdp);
4090 } else {
4091 pp = &cmdp->next;
4092 }
4093 }
4094 }
4095 INTON;
4096}
4097
4098
4099/*
4100 * Delete all functions.
4101 */
4102
Eric Andersencb57d552001-06-28 07:25:16 +00004103static void
Eric Andersen2870d962001-07-02 17:27:21 +00004104deletefuncs(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00004105 struct tblentry **tblp;
4106 struct tblentry **pp;
4107 struct tblentry *cmdp;
4108
4109 INTOFF;
4110 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4111 pp = tblp;
4112 while ((cmdp = *pp) != NULL) {
4113 if (cmdp->cmdtype == CMDFUNCTION) {
4114 *pp = cmdp->next;
4115 freefunc(cmdp->param.func);
4116 ckfree(cmdp);
4117 } else {
4118 pp = &cmdp->next;
4119 }
4120 }
4121 }
4122 INTON;
4123}
4124
4125
4126
4127/*
4128 * Locate a command in the command hash table. If "add" is nonzero,
4129 * add the command to the table if it is not already present. The
4130 * variable "lastcmdentry" is set to point to the address of the link
4131 * pointing to the entry, so that delete_cmd_entry can delete the
4132 * entry.
4133 */
4134
Eric Andersen2870d962001-07-02 17:27:21 +00004135static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00004136
4137static struct tblentry *
Eric Andersen2870d962001-07-02 17:27:21 +00004138cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00004139{
4140 int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00004141 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00004142 struct tblentry *cmdp;
4143 struct tblentry **pp;
4144
4145 p = name;
4146 hashval = *p << 4;
4147 while (*p)
4148 hashval += *p++;
4149 hashval &= 0x7FFF;
4150 pp = &cmdtable[hashval % CMDTABLESIZE];
4151 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4152 if (equal(cmdp->cmdname, name))
4153 break;
4154 pp = &cmdp->next;
4155 }
4156 if (add && cmdp == NULL) {
4157 INTOFF;
4158 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4159 + strlen(name) + 1);
4160 cmdp->next = NULL;
4161 cmdp->cmdtype = CMDUNKNOWN;
4162 cmdp->rehash = 0;
4163 strcpy(cmdp->cmdname, name);
4164 INTON;
4165 }
4166 lastcmdentry = pp;
4167 return cmdp;
4168}
4169
4170/*
4171 * Delete the command entry returned on the last lookup.
4172 */
4173
4174static void
4175delete_cmd_entry() {
4176 struct tblentry *cmdp;
4177
4178 INTOFF;
4179 cmdp = *lastcmdentry;
4180 *lastcmdentry = cmdp->next;
4181 ckfree(cmdp);
4182 INTON;
4183}
4184
4185
4186
Eric Andersencb57d552001-06-28 07:25:16 +00004187
4188
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004189static const unsigned char nodesize[26] = {
Eric Andersen62483552001-07-10 06:09:16 +00004190 ALIGN(sizeof (struct nbinary)),
4191 ALIGN(sizeof (struct ncmd)),
4192 ALIGN(sizeof (struct npipe)),
4193 ALIGN(sizeof (struct nredir)),
4194 ALIGN(sizeof (struct nredir)),
4195 ALIGN(sizeof (struct nredir)),
4196 ALIGN(sizeof (struct nbinary)),
4197 ALIGN(sizeof (struct nbinary)),
4198 ALIGN(sizeof (struct nif)),
4199 ALIGN(sizeof (struct nbinary)),
4200 ALIGN(sizeof (struct nbinary)),
4201 ALIGN(sizeof (struct nfor)),
4202 ALIGN(sizeof (struct ncase)),
4203 ALIGN(sizeof (struct nclist)),
4204 ALIGN(sizeof (struct narg)),
4205 ALIGN(sizeof (struct narg)),
4206 ALIGN(sizeof (struct nfile)),
4207 ALIGN(sizeof (struct nfile)),
4208 ALIGN(sizeof (struct nfile)),
4209 ALIGN(sizeof (struct nfile)),
4210 ALIGN(sizeof (struct nfile)),
4211 ALIGN(sizeof (struct ndup)),
4212 ALIGN(sizeof (struct ndup)),
4213 ALIGN(sizeof (struct nhere)),
4214 ALIGN(sizeof (struct nhere)),
4215 ALIGN(sizeof (struct nnot)),
4216};
Eric Andersencb57d552001-06-28 07:25:16 +00004217
Eric Andersencb57d552001-06-28 07:25:16 +00004218
4219
4220/*
4221 * Delete a function if it exists.
4222 */
4223
4224static void
Eric Andersen2870d962001-07-02 17:27:21 +00004225unsetfunc(char *name)
4226{
Eric Andersencb57d552001-06-28 07:25:16 +00004227 struct tblentry *cmdp;
4228
4229 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
4230 freefunc(cmdp->param.func);
4231 delete_cmd_entry();
4232 }
4233}
4234
Eric Andersen2870d962001-07-02 17:27:21 +00004235
4236/*
Eric Andersencb57d552001-06-28 07:25:16 +00004237 * Locate and print what a word is...
4238 */
4239
4240static int
Eric Andersen62483552001-07-10 06:09:16 +00004241typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004242{
4243 int i;
4244 int err = 0;
Eric Andersen62483552001-07-10 06:09:16 +00004245 char *argv_a[2];
4246
4247 argv_a[1] = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004248
4249 for (i = 1; i < argc; i++) {
Eric Andersen62483552001-07-10 06:09:16 +00004250 argv_a[0] = argv[i];
4251 argptr = argv_a;
4252 optptr = "v";
4253 err |= hashcmd(argc, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00004254 }
4255 return err;
4256}
4257
Eric Andersen2870d962001-07-02 17:27:21 +00004258#ifdef ASH_CMDCMD
Eric Andersencb57d552001-06-28 07:25:16 +00004259static int
4260commandcmd(argc, argv)
4261 int argc;
4262 char **argv;
4263{
4264 int c;
4265 int default_path = 0;
4266 int verify_only = 0;
4267 int verbose_verify_only = 0;
4268
4269 while ((c = nextopt("pvV")) != '\0')
4270 switch (c) {
4271 case 'p':
4272 default_path = 1;
4273 break;
4274 case 'v':
4275 verify_only = 1;
4276 break;
4277 case 'V':
4278 verbose_verify_only = 1;
4279 break;
Eric Andersencb57d552001-06-28 07:25:16 +00004280 }
4281
4282 if (default_path + verify_only + verbose_verify_only > 1 ||
4283 !*argptr) {
Eric Andersen62483552001-07-10 06:09:16 +00004284 out2str(
4285 "command [-p] command [arg ...]\n"
4286 "command {-v|-V} command\n");
Eric Andersencb57d552001-06-28 07:25:16 +00004287 return EX_USAGE;
4288 }
4289
Eric Andersencb57d552001-06-28 07:25:16 +00004290 if (verify_only || verbose_verify_only) {
Eric Andersen62483552001-07-10 06:09:16 +00004291 char *argv_a[2];
4292
4293 argv_a[1] = 0;
4294 argv_a[0] = *argptr;
4295 argptr = argv_a;
4296 optptr = verbose_verify_only ? "v" : "V"; /* reverse special */
4297 return hashcmd(argc, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00004298 }
Eric Andersencb57d552001-06-28 07:25:16 +00004299
4300 return 0;
4301}
Eric Andersen2870d962001-07-02 17:27:21 +00004302#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004303
4304static int
4305path_change(newval, bltin)
4306 const char *newval;
4307 int *bltin;
4308{
4309 const char *old, *new;
4310 int idx;
4311 int firstchange;
4312
4313 old = pathval();
4314 new = newval;
Eric Andersen2870d962001-07-02 17:27:21 +00004315 firstchange = 9999; /* assume no change */
Eric Andersencb57d552001-06-28 07:25:16 +00004316 idx = 0;
4317 *bltin = -1;
4318 for (;;) {
4319 if (*old != *new) {
4320 firstchange = idx;
4321 if ((*old == '\0' && *new == ':')
4322 || (*old == ':' && *new == '\0'))
4323 firstchange++;
Eric Andersen2870d962001-07-02 17:27:21 +00004324 old = new; /* ignore subsequent differences */
Eric Andersencb57d552001-06-28 07:25:16 +00004325 }
4326 if (*new == '\0')
4327 break;
4328 if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1))
4329 *bltin = idx;
4330 if (*new == ':') {
4331 idx++;
4332 }
4333 new++, old++;
4334 }
4335 if (builtinloc >= 0 && *bltin < 0)
4336 firstchange = 0;
4337 return firstchange;
4338}
Eric Andersencb57d552001-06-28 07:25:16 +00004339/*
4340 * Routines to expand arguments to commands. We have to deal with
4341 * backquotes, shell variables, and file metacharacters.
4342 */
4343/*
4344 * _rmescape() flags
4345 */
Eric Andersen2870d962001-07-02 17:27:21 +00004346#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4347#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Eric Andersencb57d552001-06-28 07:25:16 +00004348
4349/*
4350 * Structure specifying which parts of the string should be searched
4351 * for IFS characters.
4352 */
4353
4354struct ifsregion {
Eric Andersen2870d962001-07-02 17:27:21 +00004355 struct ifsregion *next; /* next region in list */
4356 int begoff; /* offset of start of region */
4357 int endoff; /* offset of end of region */
4358 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004359};
4360
4361
Eric Andersen2870d962001-07-02 17:27:21 +00004362static char *expdest; /* output of current string */
4363static struct nodelist *argbackq; /* list of back quote expressions */
4364static struct ifsregion ifsfirst; /* first struct in list of ifs regions */
4365static struct ifsregion *ifslastp; /* last struct in list */
4366static struct arglist exparg; /* holds expanded arg list */
Eric Andersencb57d552001-06-28 07:25:16 +00004367
Eric Andersen2870d962001-07-02 17:27:21 +00004368static void argstr (char *, int);
4369static char *exptilde (char *, int);
4370static void expbackq (union node *, int, int);
4371static int subevalvar (char *, char *, int, int, int, int, int);
Eric Andersen2870d962001-07-02 17:27:21 +00004372static int varisset (char *, int);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004373static void strtodest (const char *, int, int);
Eric Andersen2870d962001-07-02 17:27:21 +00004374static void varvalue (char *, int, int);
4375static void recordregion (int, int, int);
4376static void removerecordregions (int);
4377static void ifsbreakup (char *, struct arglist *);
4378static void ifsfree (void);
4379static void expandmeta (struct strlist *, int);
Eric Andersen62483552001-07-10 06:09:16 +00004380#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00004381#define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB)
4382#if !defined(GLOB_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00004383static void addglob (const glob_t *);
Eric Andersencb57d552001-06-28 07:25:16 +00004384#endif
4385#endif
Eric Andersen62483552001-07-10 06:09:16 +00004386#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersen2870d962001-07-02 17:27:21 +00004387static void expmeta (char *, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004388#endif
Eric Andersen62483552001-07-10 06:09:16 +00004389#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersen2870d962001-07-02 17:27:21 +00004390static struct strlist *expsort (struct strlist *);
4391static struct strlist *msort (struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004392#endif
Eric Andersen2870d962001-07-02 17:27:21 +00004393static int patmatch (char *, char *, int);
Eric Andersen62483552001-07-10 06:09:16 +00004394#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00004395static int patmatch2 (char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004396#else
Eric Andersen2870d962001-07-02 17:27:21 +00004397static int pmatch (char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004398#define patmatch2 patmatch
4399#endif
Eric Andersen2870d962001-07-02 17:27:21 +00004400static char *cvtnum (int, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004401
4402/*
4403 * Expand shell variables and backquotes inside a here document.
4404 */
4405
Eric Andersen2870d962001-07-02 17:27:21 +00004406/* arg: the document, fd: where to write the expanded version */
Eric Andersen62483552001-07-10 06:09:16 +00004407static inline void
Eric Andersen2870d962001-07-02 17:27:21 +00004408expandhere(union node *arg, int fd)
4409{
Eric Andersencb57d552001-06-28 07:25:16 +00004410 herefd = fd;
4411 expandarg(arg, (struct arglist *)NULL, 0);
4412 xwrite(fd, stackblock(), expdest - stackblock());
4413}
4414
4415
4416/*
4417 * Perform variable substitution and command substitution on an argument,
4418 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4419 * perform splitting and file name expansion. When arglist is NULL, perform
4420 * here document expansion.
4421 */
4422
4423static void
4424expandarg(arg, arglist, flag)
4425 union node *arg;
4426 struct arglist *arglist;
4427 int flag;
4428{
4429 struct strlist *sp;
4430 char *p;
4431
4432 argbackq = arg->narg.backquote;
4433 STARTSTACKSTR(expdest);
4434 ifsfirst.next = NULL;
4435 ifslastp = NULL;
4436 argstr(arg->narg.text, flag);
4437 if (arglist == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00004438 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004439 }
4440 STPUTC('\0', expdest);
4441 p = grabstackstr(expdest);
4442 exparg.lastp = &exparg.list;
4443 /*
4444 * TODO - EXP_REDIR
4445 */
4446 if (flag & EXP_FULL) {
4447 ifsbreakup(p, &exparg);
4448 *exparg.lastp = NULL;
4449 exparg.lastp = &exparg.list;
4450 expandmeta(exparg.list, flag);
4451 } else {
4452 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4453 rmescapes(p);
4454 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4455 sp->text = p;
4456 *exparg.lastp = sp;
4457 exparg.lastp = &sp->next;
4458 }
4459 ifsfree();
4460 *exparg.lastp = NULL;
4461 if (exparg.list) {
4462 *arglist->lastp = exparg.list;
4463 arglist->lastp = exparg.lastp;
4464 }
4465}
4466
4467
Eric Andersen62483552001-07-10 06:09:16 +00004468/*
4469 * Expand a variable, and return a pointer to the next character in the
4470 * input string.
4471 */
4472
4473static inline char *
4474evalvar(p, flag)
4475 char *p;
4476 int flag;
4477{
4478 int subtype;
4479 int varflags;
4480 char *var;
4481 const char *val;
4482 int patloc;
4483 int c;
4484 int set;
4485 int special;
4486 int startloc;
4487 int varlen;
4488 int easy;
4489 int quotes = flag & (EXP_FULL | EXP_CASE);
4490
4491 varflags = *p++;
4492 subtype = varflags & VSTYPE;
4493 var = p;
4494 special = 0;
4495 if (! is_name(*p))
4496 special = 1;
4497 p = strchr(p, '=') + 1;
4498again: /* jump here after setting a variable with ${var=text} */
4499 if (special) {
4500 set = varisset(var, varflags & VSNUL);
4501 val = NULL;
4502 } else {
4503 val = lookupvar(var);
4504 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
4505 val = NULL;
4506 set = 0;
4507 } else
4508 set = 1;
4509 }
4510 varlen = 0;
4511 startloc = expdest - stackblock();
4512 if (set && subtype != VSPLUS) {
4513 /* insert the value of the variable */
4514 if (special) {
4515 varvalue(var, varflags & VSQUOTE, flag);
4516 if (subtype == VSLENGTH) {
4517 varlen = expdest - stackblock() - startloc;
4518 STADJUST(-varlen, expdest);
4519 }
4520 } else {
4521 if (subtype == VSLENGTH) {
4522 varlen = strlen(val);
4523 } else {
4524 strtodest(
4525 val,
4526 varflags & VSQUOTE ?
4527 DQSYNTAX : BASESYNTAX,
4528 quotes
4529 );
4530 }
4531 }
4532 }
4533
4534 if (subtype == VSPLUS)
4535 set = ! set;
4536
4537 easy = ((varflags & VSQUOTE) == 0 ||
4538 (*var == '@' && shellparam.nparam != 1));
4539
4540
4541 switch (subtype) {
4542 case VSLENGTH:
4543 expdest = cvtnum(varlen, expdest);
4544 goto record;
4545
4546 case VSNORMAL:
4547 if (!easy)
4548 break;
4549record:
4550 recordregion(startloc, expdest - stackblock(),
4551 varflags & VSQUOTE);
4552 break;
4553
4554 case VSPLUS:
4555 case VSMINUS:
4556 if (!set) {
4557 argstr(p, flag);
4558 break;
4559 }
4560 if (easy)
4561 goto record;
4562 break;
4563
4564 case VSTRIMLEFT:
4565 case VSTRIMLEFTMAX:
4566 case VSTRIMRIGHT:
4567 case VSTRIMRIGHTMAX:
4568 if (!set)
4569 break;
4570 /*
4571 * Terminate the string and start recording the pattern
4572 * right after it
4573 */
4574 STPUTC('\0', expdest);
4575 patloc = expdest - stackblock();
4576 if (subevalvar(p, NULL, patloc, subtype,
4577 startloc, varflags, quotes) == 0) {
4578 int amount = (expdest - stackblock() - patloc) + 1;
4579 STADJUST(-amount, expdest);
4580 }
4581 /* Remove any recorded regions beyond start of variable */
4582 removerecordregions(startloc);
4583 goto record;
4584
4585 case VSASSIGN:
4586 case VSQUESTION:
4587 if (!set) {
4588 if (subevalvar(p, var, 0, subtype, startloc,
4589 varflags, quotes)) {
4590 varflags &= ~VSNUL;
4591 /*
4592 * Remove any recorded regions beyond
4593 * start of variable
4594 */
4595 removerecordregions(startloc);
4596 goto again;
4597 }
4598 break;
4599 }
4600 if (easy)
4601 goto record;
4602 break;
4603
4604#ifdef DEBUG
4605 default:
4606 abort();
4607#endif
4608 }
4609
4610 if (subtype != VSNORMAL) { /* skip to end of alternative */
4611 int nesting = 1;
4612 for (;;) {
4613 if ((c = *p++) == CTLESC)
4614 p++;
4615 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
4616 if (set)
4617 argbackq = argbackq->next;
4618 } else if (c == CTLVAR) {
4619 if ((*p++ & VSTYPE) != VSNORMAL)
4620 nesting++;
4621 } else if (c == CTLENDVAR) {
4622 if (--nesting == 0)
4623 break;
4624 }
4625 }
4626 }
4627 return p;
4628}
4629
Eric Andersencb57d552001-06-28 07:25:16 +00004630
4631/*
4632 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4633 * characters to allow for further processing. Otherwise treat
4634 * $@ like $* since no splitting will be performed.
4635 */
4636
4637static void
4638argstr(p, flag)
4639 char *p;
4640 int flag;
4641{
4642 char c;
Eric Andersen2870d962001-07-02 17:27:21 +00004643 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
Eric Andersencb57d552001-06-28 07:25:16 +00004644 int firsteq = 1;
4645
4646 if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
4647 p = exptilde(p, flag);
4648 for (;;) {
4649 switch (c = *p++) {
4650 case '\0':
4651 case CTLENDVAR: /* ??? */
4652 goto breakloop;
4653 case CTLQUOTEMARK:
4654 /* "$@" syntax adherence hack */
4655 if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
4656 break;
4657 if ((flag & EXP_FULL) != 0)
4658 STPUTC(c, expdest);
4659 break;
4660 case CTLESC:
4661 if (quotes)
4662 STPUTC(c, expdest);
4663 c = *p++;
4664 STPUTC(c, expdest);
4665 break;
4666 case CTLVAR:
4667 p = evalvar(p, flag);
4668 break;
4669 case CTLBACKQ:
4670 case CTLBACKQ|CTLQUOTE:
4671 expbackq(argbackq->n, c & CTLQUOTE, flag);
4672 argbackq = argbackq->next;
4673 break;
4674#ifdef ASH_MATH_SUPPORT
4675 case CTLENDARI:
4676 expari(flag);
4677 break;
Eric Andersen2870d962001-07-02 17:27:21 +00004678#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004679 case ':':
4680 case '=':
4681 /*
4682 * sort of a hack - expand tildes in variable
4683 * assignments (after the first '=' and after ':'s).
4684 */
4685 STPUTC(c, expdest);
4686 if (flag & EXP_VARTILDE && *p == '~') {
4687 if (c == '=') {
4688 if (firsteq)
4689 firsteq = 0;
4690 else
4691 break;
4692 }
4693 p = exptilde(p, flag);
4694 }
4695 break;
4696 default:
4697 STPUTC(c, expdest);
4698 }
4699 }
4700breakloop:;
4701 return;
4702}
4703
4704static char *
4705exptilde(p, flag)
4706 char *p;
4707 int flag;
4708{
4709 char c, *startp = p;
4710 struct passwd *pw;
4711 const char *home;
4712 int quotes = flag & (EXP_FULL | EXP_CASE);
4713
4714 while ((c = *p) != '\0') {
4715 switch(c) {
4716 case CTLESC:
4717 return (startp);
4718 case CTLQUOTEMARK:
4719 return (startp);
4720 case ':':
4721 if (flag & EXP_VARTILDE)
4722 goto done;
4723 break;
4724 case '/':
4725 goto done;
4726 }
4727 p++;
4728 }
4729done:
4730 *p = '\0';
4731 if (*(startp+1) == '\0') {
4732 if ((home = lookupvar("HOME")) == NULL)
4733 goto lose;
4734 } else {
4735 if ((pw = getpwnam(startp+1)) == NULL)
4736 goto lose;
4737 home = pw->pw_dir;
4738 }
4739 if (*home == '\0')
4740 goto lose;
4741 *p = c;
4742 strtodest(home, SQSYNTAX, quotes);
4743 return (p);
4744lose:
4745 *p = c;
4746 return (startp);
4747}
4748
4749
Eric Andersen2870d962001-07-02 17:27:21 +00004750static void
4751removerecordregions(int endoff)
Eric Andersencb57d552001-06-28 07:25:16 +00004752{
4753 if (ifslastp == NULL)
4754 return;
4755
4756 if (ifsfirst.endoff > endoff) {
4757 while (ifsfirst.next != NULL) {
4758 struct ifsregion *ifsp;
4759 INTOFF;
4760 ifsp = ifsfirst.next->next;
4761 ckfree(ifsfirst.next);
4762 ifsfirst.next = ifsp;
4763 INTON;
4764 }
4765 if (ifsfirst.begoff > endoff)
4766 ifslastp = NULL;
4767 else {
4768 ifslastp = &ifsfirst;
4769 ifsfirst.endoff = endoff;
4770 }
4771 return;
4772 }
Eric Andersen2870d962001-07-02 17:27:21 +00004773
Eric Andersencb57d552001-06-28 07:25:16 +00004774 ifslastp = &ifsfirst;
4775 while (ifslastp->next && ifslastp->next->begoff < endoff)
4776 ifslastp=ifslastp->next;
4777 while (ifslastp->next != NULL) {
4778 struct ifsregion *ifsp;
4779 INTOFF;
4780 ifsp = ifslastp->next->next;
4781 ckfree(ifslastp->next);
4782 ifslastp->next = ifsp;
4783 INTON;
4784 }
4785 if (ifslastp->endoff > endoff)
4786 ifslastp->endoff = endoff;
4787}
4788
4789
4790#ifdef ASH_MATH_SUPPORT
4791/*
4792 * Expand arithmetic expression. Backup to start of expression,
4793 * evaluate, place result in (backed up) result, adjust string position.
4794 */
4795static void
Eric Andersen2870d962001-07-02 17:27:21 +00004796expari(int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004797{
4798 char *p, *start;
Eric Andersen34506362001-08-02 05:02:46 +00004799 int errcode;
Eric Andersencb57d552001-06-28 07:25:16 +00004800 int result;
4801 int begoff;
4802 int quotes = flag & (EXP_FULL | EXP_CASE);
4803 int quoted;
4804
Eric Andersen2870d962001-07-02 17:27:21 +00004805 /* ifsfree(); */
Eric Andersencb57d552001-06-28 07:25:16 +00004806
4807 /*
4808 * This routine is slightly over-complicated for
4809 * efficiency. First we make sure there is
4810 * enough space for the result, which may be bigger
4811 * than the expression if we add exponentation. Next we
4812 * scan backwards looking for the start of arithmetic. If the
4813 * next previous character is a CTLESC character, then we
4814 * have to rescan starting from the beginning since CTLESC
4815 * characters have to be processed left to right.
4816 */
4817 CHECKSTRSPACE(10, expdest);
4818 USTPUTC('\0', expdest);
4819 start = stackblock();
4820 p = expdest - 1;
4821 while (*p != CTLARI && p >= start)
4822 --p;
4823 if (*p != CTLARI)
4824 error("missing CTLARI (shouldn't happen)");
4825 if (p > start && *(p-1) == CTLESC)
4826 for (p = start; *p != CTLARI; p++)
4827 if (*p == CTLESC)
4828 p++;
4829
4830 if (p[1] == '"')
4831 quoted=1;
4832 else
4833 quoted=0;
4834 begoff = p - start;
4835 removerecordregions(begoff);
4836 if (quotes)
4837 rmescapes(p+2);
Eric Andersen34506362001-08-02 05:02:46 +00004838 result = arith(p+2, &errcode);
4839 if (errcode < 0) {
4840 if(errcode == -2)
4841 error("divide by zero");
4842 else
4843 error("syntax error: \"%s\"\n", p+2);
4844 }
Eric Andersen3102ac42001-07-06 04:26:23 +00004845 snprintf(p, 12, "%d", result);
Eric Andersencb57d552001-06-28 07:25:16 +00004846
4847 while (*p++)
4848 ;
4849
4850 if (quoted == 0)
4851 recordregion(begoff, p - 1 - start, 0);
4852 result = expdest - p + 1;
4853 STADJUST(-result, expdest);
4854}
Eric Andersen2870d962001-07-02 17:27:21 +00004855#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004856
4857/*
4858 * Expand stuff in backwards quotes.
4859 */
4860
4861static void
4862expbackq(cmd, quoted, flag)
4863 union node *cmd;
4864 int quoted;
4865 int flag;
4866{
4867 volatile struct backcmd in;
4868 int i;
4869 char buf[128];
4870 char *p;
4871 char *dest = expdest;
4872 volatile struct ifsregion saveifs;
4873 struct ifsregion *volatile savelastp;
4874 struct nodelist *volatile saveargbackq;
4875 char lastc;
4876 int startloc = dest - stackblock();
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004877 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +00004878 volatile int saveherefd;
4879 int quotes = flag & (EXP_FULL | EXP_CASE);
4880 struct jmploc jmploc;
4881 struct jmploc *volatile savehandler;
4882 int ex;
4883
4884#if __GNUC__
4885 /* Avoid longjmp clobbering */
4886 (void) &dest;
4887 (void) &syntax;
4888#endif
4889
4890 in.fd = -1;
4891 in.buf = 0;
4892 in.jp = 0;
4893
4894 INTOFF;
4895 saveifs = ifsfirst;
4896 savelastp = ifslastp;
4897 saveargbackq = argbackq;
4898 saveherefd = herefd;
4899 herefd = -1;
4900 if ((ex = setjmp(jmploc.loc))) {
4901 goto err1;
4902 }
4903 savehandler = handler;
4904 handler = &jmploc;
4905 INTON;
4906 p = grabstackstr(dest);
4907 evalbackcmd(cmd, (struct backcmd *) &in);
4908 ungrabstackstr(p, dest);
4909err1:
4910 INTOFF;
4911 ifsfirst = saveifs;
4912 ifslastp = savelastp;
4913 argbackq = saveargbackq;
4914 herefd = saveherefd;
4915 if (ex) {
4916 goto err2;
4917 }
4918
4919 p = in.buf;
4920 lastc = '\0';
4921 for (;;) {
4922 if (--in.nleft < 0) {
4923 if (in.fd < 0)
4924 break;
Eric Andersen7467c8d2001-07-12 20:26:32 +00004925 i = safe_read(in.fd, buf, sizeof buf);
Eric Andersencb57d552001-06-28 07:25:16 +00004926 TRACE(("expbackq: read returns %d\n", i));
4927 if (i <= 0)
4928 break;
4929 p = buf;
4930 in.nleft = i - 1;
4931 }
4932 lastc = *p++;
4933 if (lastc != '\0') {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004934 if (quotes && SIT(lastc, syntax) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +00004935 STPUTC(CTLESC, dest);
4936 STPUTC(lastc, dest);
4937 }
4938 }
4939
4940 /* Eat all trailing newlines */
4941 for (; dest > stackblock() && dest[-1] == '\n';)
4942 STUNPUTC(dest);
4943
4944err2:
4945 if (in.fd >= 0)
4946 close(in.fd);
4947 if (in.buf)
4948 ckfree(in.buf);
4949 if (in.jp)
4950 exitstatus = waitforjob(in.jp);
4951 handler = savehandler;
4952 if (ex) {
4953 longjmp(handler->loc, 1);
4954 }
4955 if (quoted == 0)
4956 recordregion(startloc, dest - stackblock(), 0);
4957 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4958 (dest - stackblock()) - startloc,
4959 (dest - stackblock()) - startloc,
4960 stackblock() + startloc));
4961 expdest = dest;
4962 INTON;
4963}
4964
Eric Andersencb57d552001-06-28 07:25:16 +00004965static int
4966subevalvar(p, str, strloc, subtype, startloc, varflags, quotes)
4967 char *p;
4968 char *str;
4969 int strloc;
4970 int subtype;
4971 int startloc;
4972 int varflags;
4973 int quotes;
4974{
4975 char *startp;
4976 char *loc = NULL;
4977 char *q;
4978 int c = 0;
4979 int saveherefd = herefd;
4980 struct nodelist *saveargbackq = argbackq;
4981 int amount;
4982
4983 herefd = -1;
4984 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
4985 STACKSTRNUL(expdest);
4986 herefd = saveherefd;
4987 argbackq = saveargbackq;
4988 startp = stackblock() + startloc;
4989 if (str == NULL)
4990 str = stackblock() + strloc;
4991
4992 switch (subtype) {
4993 case VSASSIGN:
4994 setvar(str, startp, 0);
4995 amount = startp - expdest;
4996 STADJUST(amount, expdest);
4997 varflags &= ~VSNUL;
4998 if (c != 0)
4999 *loc = c;
5000 return 1;
5001
5002 case VSQUESTION:
5003 if (*p != CTLENDVAR) {
Eric Andersen3102ac42001-07-06 04:26:23 +00005004 out2fmt(snlfmt, startp);
Eric Andersencb57d552001-06-28 07:25:16 +00005005 error((char *)NULL);
5006 }
5007 error("%.*s: parameter %snot set", p - str - 1,
5008 str, (varflags & VSNUL) ? "null or "
5009 : nullstr);
5010 /* NOTREACHED */
5011
5012 case VSTRIMLEFT:
5013 for (loc = startp; loc < str; loc++) {
5014 c = *loc;
5015 *loc = '\0';
5016 if (patmatch2(str, startp, quotes))
5017 goto recordleft;
5018 *loc = c;
5019 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00005020 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00005021 }
5022 return 0;
5023
5024 case VSTRIMLEFTMAX:
5025 for (loc = str - 1; loc >= startp;) {
5026 c = *loc;
5027 *loc = '\0';
5028 if (patmatch2(str, startp, quotes))
5029 goto recordleft;
5030 *loc = c;
5031 loc--;
5032 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
5033 for (q = startp; q < loc; q++)
5034 if (*q == CTLESC)
5035 q++;
5036 if (q > loc)
5037 loc--;
5038 }
5039 }
5040 return 0;
5041
5042 case VSTRIMRIGHT:
Eric Andersen2870d962001-07-02 17:27:21 +00005043 for (loc = str - 1; loc >= startp;) {
Eric Andersencb57d552001-06-28 07:25:16 +00005044 if (patmatch2(str, loc, quotes))
5045 goto recordright;
5046 loc--;
Eric Andersen2870d962001-07-02 17:27:21 +00005047 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
Eric Andersencb57d552001-06-28 07:25:16 +00005048 for (q = startp; q < loc; q++)
5049 if (*q == CTLESC)
5050 q++;
5051 if (q > loc)
5052 loc--;
5053 }
5054 }
5055 return 0;
5056
5057 case VSTRIMRIGHTMAX:
5058 for (loc = startp; loc < str - 1; loc++) {
5059 if (patmatch2(str, loc, quotes))
5060 goto recordright;
5061 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00005062 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00005063 }
5064 return 0;
5065
5066#ifdef DEBUG
5067 default:
5068 abort();
5069#endif
5070 }
5071
5072recordleft:
5073 *loc = c;
5074 amount = ((str - 1) - (loc - startp)) - expdest;
5075 STADJUST(amount, expdest);
5076 while (loc != str - 1)
5077 *startp++ = *loc++;
5078 return 1;
5079
5080recordright:
5081 amount = loc - expdest;
5082 STADJUST(amount, expdest);
5083 STPUTC('\0', expdest);
5084 STADJUST(-1, expdest);
5085 return 1;
5086}
5087
5088
5089/*
Eric Andersencb57d552001-06-28 07:25:16 +00005090 * Test whether a specialized variable is set.
5091 */
5092
5093static int
5094varisset(name, nulok)
5095 char *name;
5096 int nulok;
5097{
5098 if (*name == '!')
5099 return backgndpid != -1;
5100 else if (*name == '@' || *name == '*') {
5101 if (*shellparam.p == NULL)
5102 return 0;
5103
5104 if (nulok) {
5105 char **av;
5106
5107 for (av = shellparam.p; *av; av++)
5108 if (**av != '\0')
5109 return 1;
5110 return 0;
5111 }
5112 } else if (is_digit(*name)) {
5113 char *ap;
5114 int num = atoi(name);
5115
5116 if (num > shellparam.nparam)
5117 return 0;
5118
5119 if (num == 0)
5120 ap = arg0;
5121 else
5122 ap = shellparam.p[num - 1];
5123
5124 if (nulok && (ap == NULL || *ap == '\0'))
5125 return 0;
5126 }
5127 return 1;
5128}
5129
Eric Andersencb57d552001-06-28 07:25:16 +00005130/*
5131 * Put a string on the stack.
5132 */
5133
5134static void
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005135strtodest(const char *p, int syntax, int quotes)
Eric Andersencb57d552001-06-28 07:25:16 +00005136{
5137 while (*p) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005138 if (quotes && SIT(*p,syntax) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +00005139 STPUTC(CTLESC, expdest);
5140 STPUTC(*p++, expdest);
5141 }
5142}
5143
Eric Andersencb57d552001-06-28 07:25:16 +00005144/*
5145 * Add the value of a specialized variable to the stack string.
5146 */
5147
5148static void
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005149varvalue(char *name, int quoted, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00005150{
5151 int num;
5152 char *p;
5153 int i;
5154 int sep;
5155 int sepq = 0;
5156 char **ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005157 int syntax;
Eric Andersencb57d552001-06-28 07:25:16 +00005158 int allow_split = flags & EXP_FULL;
5159 int quotes = flags & (EXP_FULL | EXP_CASE);
5160
5161 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5162 switch (*name) {
5163 case '$':
5164 num = rootpid;
5165 goto numvar;
5166 case '?':
5167 num = oexitstatus;
5168 goto numvar;
5169 case '#':
5170 num = shellparam.nparam;
5171 goto numvar;
5172 case '!':
5173 num = backgndpid;
5174numvar:
5175 expdest = cvtnum(num, expdest);
5176 break;
5177 case '-':
5178 for (i = 0 ; i < NOPTS ; i++) {
Eric Andersen2870d962001-07-02 17:27:21 +00005179 if (optent_val(i))
5180 STPUTC(optent_letter(optlist[i]), expdest);
Eric Andersencb57d552001-06-28 07:25:16 +00005181 }
5182 break;
5183 case '@':
5184 if (allow_split && quoted) {
5185 sep = 1 << CHAR_BIT;
5186 goto param;
5187 }
5188 /* fall through */
5189 case '*':
5190 sep = ifsset() ? ifsval()[0] : ' ';
5191 if (quotes) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005192 sepq = SIT(sep,syntax) == CCTL;
Eric Andersencb57d552001-06-28 07:25:16 +00005193 }
5194param:
5195 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
5196 strtodest(p, syntax, quotes);
5197 if (*ap && sep) {
5198 if (sepq)
5199 STPUTC(CTLESC, expdest);
5200 STPUTC(sep, expdest);
5201 }
5202 }
5203 break;
5204 case '0':
5205 strtodest(arg0, syntax, quotes);
5206 break;
5207 default:
5208 num = atoi(name);
5209 if (num > 0 && num <= shellparam.nparam) {
5210 strtodest(shellparam.p[num - 1], syntax, quotes);
5211 }
5212 break;
5213 }
5214}
5215
5216
Eric Andersencb57d552001-06-28 07:25:16 +00005217/*
5218 * Record the fact that we have to scan this region of the
5219 * string for IFS characters.
5220 */
5221
5222static void
5223recordregion(start, end, nulonly)
5224 int start;
5225 int end;
5226 int nulonly;
5227{
5228 struct ifsregion *ifsp;
5229
5230 if (ifslastp == NULL) {
5231 ifsp = &ifsfirst;
5232 } else {
5233 INTOFF;
5234 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
5235 ifsp->next = NULL;
5236 ifslastp->next = ifsp;
5237 INTON;
5238 }
5239 ifslastp = ifsp;
5240 ifslastp->begoff = start;
5241 ifslastp->endoff = end;
5242 ifslastp->nulonly = nulonly;
5243}
5244
5245
5246
5247/*
5248 * Break the argument string into pieces based upon IFS and add the
5249 * strings to the argument list. The regions of the string to be
5250 * searched for IFS characters have been stored by recordregion.
5251 */
5252static void
5253ifsbreakup(string, arglist)
5254 char *string;
5255 struct arglist *arglist;
5256 {
5257 struct ifsregion *ifsp;
5258 struct strlist *sp;
5259 char *start;
5260 char *p;
5261 char *q;
5262 const char *ifs, *realifs;
5263 int ifsspc;
5264 int nulonly;
5265
5266
5267 start = string;
5268 ifsspc = 0;
5269 nulonly = 0;
5270 realifs = ifsset() ? ifsval() : defifs;
5271 if (ifslastp != NULL) {
5272 ifsp = &ifsfirst;
5273 do {
5274 p = string + ifsp->begoff;
5275 nulonly = ifsp->nulonly;
5276 ifs = nulonly ? nullstr : realifs;
5277 ifsspc = 0;
5278 while (p < string + ifsp->endoff) {
5279 q = p;
5280 if (*p == CTLESC)
5281 p++;
5282 if (strchr(ifs, *p)) {
5283 if (!nulonly)
5284 ifsspc = (strchr(defifs, *p) != NULL);
5285 /* Ignore IFS whitespace at start */
5286 if (q == start && ifsspc) {
5287 p++;
5288 start = p;
5289 continue;
5290 }
5291 *q = '\0';
5292 sp = (struct strlist *)stalloc(sizeof *sp);
5293 sp->text = start;
5294 *arglist->lastp = sp;
5295 arglist->lastp = &sp->next;
5296 p++;
5297 if (!nulonly) {
5298 for (;;) {
5299 if (p >= string + ifsp->endoff) {
5300 break;
5301 }
5302 q = p;
5303 if (*p == CTLESC)
5304 p++;
5305 if (strchr(ifs, *p) == NULL ) {
5306 p = q;
5307 break;
5308 } else if (strchr(defifs, *p) == NULL) {
5309 if (ifsspc) {
5310 p++;
5311 ifsspc = 0;
5312 } else {
5313 p = q;
5314 break;
5315 }
5316 } else
5317 p++;
5318 }
5319 }
5320 start = p;
5321 } else
5322 p++;
5323 }
5324 } while ((ifsp = ifsp->next) != NULL);
5325 if (!(*start || (!ifsspc && start > string && nulonly))) {
5326 return;
5327 }
5328 }
5329
5330 sp = (struct strlist *)stalloc(sizeof *sp);
5331 sp->text = start;
5332 *arglist->lastp = sp;
5333 arglist->lastp = &sp->next;
5334}
5335
5336static void
5337ifsfree()
5338{
5339 while (ifsfirst.next != NULL) {
5340 struct ifsregion *ifsp;
5341 INTOFF;
5342 ifsp = ifsfirst.next->next;
5343 ckfree(ifsfirst.next);
5344 ifsfirst.next = ifsp;
5345 INTON;
5346 }
5347 ifslastp = NULL;
5348 ifsfirst.next = NULL;
5349}
5350
Eric Andersen2870d962001-07-02 17:27:21 +00005351/*
5352 * Add a file name to the list.
5353 */
Eric Andersencb57d552001-06-28 07:25:16 +00005354
Eric Andersen2870d962001-07-02 17:27:21 +00005355static void
5356addfname(const char *name)
5357{
5358 char *p;
5359 struct strlist *sp;
5360
5361 p = sstrdup(name);
5362 sp = (struct strlist *)stalloc(sizeof *sp);
5363 sp->text = p;
5364 *exparg.lastp = sp;
5365 exparg.lastp = &sp->next;
5366}
Eric Andersencb57d552001-06-28 07:25:16 +00005367
5368/*
5369 * Expand shell metacharacters. At this point, the only control characters
5370 * should be escapes. The results are stored in the list exparg.
5371 */
5372
Eric Andersen62483552001-07-10 06:09:16 +00005373#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00005374static void
5375expandmeta(str, flag)
5376 struct strlist *str;
5377 int flag;
5378{
5379 const char *p;
5380 glob_t pglob;
5381 /* TODO - EXP_REDIR */
5382
5383 while (str) {
5384 if (fflag)
5385 goto nometa;
5386 p = preglob(str->text);
5387 INTOFF;
Eric Andersen34506362001-08-02 05:02:46 +00005388 switch (glob(p, 0, 0, &pglob)) {
Eric Andersencb57d552001-06-28 07:25:16 +00005389 case 0:
Eric Andersen34506362001-08-02 05:02:46 +00005390 if(pglob.gl_pathv[1]==0 && !strcmp(p, pglob.gl_pathv[0]))
Eric Andersencb57d552001-06-28 07:25:16 +00005391 goto nometa2;
5392 addglob(&pglob);
5393 globfree(&pglob);
5394 INTON;
5395 break;
5396 case GLOB_NOMATCH:
5397nometa2:
5398 globfree(&pglob);
5399 INTON;
5400nometa:
5401 *exparg.lastp = str;
5402 rmescapes(str->text);
5403 exparg.lastp = &str->next;
5404 break;
Eric Andersen2870d962001-07-02 17:27:21 +00005405 default: /* GLOB_NOSPACE */
Eric Andersencb57d552001-06-28 07:25:16 +00005406 error("Out of space");
5407 }
5408 str = str->next;
5409 }
5410}
5411
5412
5413/*
5414 * Add the result of glob(3) to the list.
5415 */
5416
5417static void
5418addglob(pglob)
5419 const glob_t *pglob;
5420{
5421 char **p = pglob->gl_pathv;
5422
5423 do {
5424 addfname(*p);
5425 } while (*++p);
5426}
5427
5428
Eric Andersen2870d962001-07-02 17:27:21 +00005429#else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005430static char *expdir;
5431
5432
5433static void
5434expandmeta(str, flag)
5435 struct strlist *str;
5436 int flag;
5437{
5438 char *p;
5439 struct strlist **savelastp;
5440 struct strlist *sp;
5441 char c;
5442 /* TODO - EXP_REDIR */
5443
5444 while (str) {
5445 if (fflag)
5446 goto nometa;
5447 p = str->text;
Eric Andersen2870d962001-07-02 17:27:21 +00005448 for (;;) { /* fast check for meta chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005449 if ((c = *p++) == '\0')
5450 goto nometa;
5451 if (c == '*' || c == '?' || c == '[' || c == '!')
5452 break;
5453 }
5454 savelastp = exparg.lastp;
5455 INTOFF;
5456 if (expdir == NULL) {
5457 int i = strlen(str->text);
5458 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5459 }
5460
5461 expmeta(expdir, str->text);
5462 ckfree(expdir);
5463 expdir = NULL;
5464 INTON;
5465 if (exparg.lastp == savelastp) {
5466 /*
5467 * no matches
5468 */
5469nometa:
5470 *exparg.lastp = str;
5471 rmescapes(str->text);
5472 exparg.lastp = &str->next;
5473 } else {
5474 *exparg.lastp = NULL;
5475 *savelastp = sp = expsort(*savelastp);
5476 while (sp->next != NULL)
5477 sp = sp->next;
5478 exparg.lastp = &sp->next;
5479 }
5480 str = str->next;
5481 }
5482}
5483
5484
5485/*
5486 * Do metacharacter (i.e. *, ?, [...]) expansion.
5487 */
5488
5489static void
5490expmeta(enddir, name)
5491 char *enddir;
5492 char *name;
5493 {
5494 char *p;
5495 const char *cp;
5496 char *q;
5497 char *start;
5498 char *endname;
5499 int metaflag;
5500 struct stat statb;
5501 DIR *dirp;
5502 struct dirent *dp;
5503 int atend;
5504 int matchdot;
5505
5506 metaflag = 0;
5507 start = name;
5508 for (p = name ; ; p++) {
5509 if (*p == '*' || *p == '?')
5510 metaflag = 1;
5511 else if (*p == '[') {
5512 q = p + 1;
5513 if (*q == '!')
5514 q++;
5515 for (;;) {
5516 while (*q == CTLQUOTEMARK)
5517 q++;
5518 if (*q == CTLESC)
5519 q++;
5520 if (*q == '/' || *q == '\0')
5521 break;
5522 if (*++q == ']') {
5523 metaflag = 1;
5524 break;
5525 }
5526 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005527 } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) {
Eric Andersencb57d552001-06-28 07:25:16 +00005528 metaflag = 1;
5529 } else if (*p == '\0')
5530 break;
5531 else if (*p == CTLQUOTEMARK)
5532 continue;
5533 else if (*p == CTLESC)
5534 p++;
5535 if (*p == '/') {
5536 if (metaflag)
5537 break;
5538 start = p + 1;
5539 }
5540 }
Eric Andersen2870d962001-07-02 17:27:21 +00005541 if (metaflag == 0) { /* we've reached the end of the file name */
Eric Andersencb57d552001-06-28 07:25:16 +00005542 if (enddir != expdir)
5543 metaflag++;
5544 for (p = name ; ; p++) {
5545 if (*p == CTLQUOTEMARK)
5546 continue;
5547 if (*p == CTLESC)
5548 p++;
5549 *enddir++ = *p;
5550 if (*p == '\0')
5551 break;
5552 }
5553 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5554 addfname(expdir);
5555 return;
5556 }
5557 endname = p;
5558 if (start != name) {
5559 p = name;
5560 while (p < start) {
5561 while (*p == CTLQUOTEMARK)
5562 p++;
5563 if (*p == CTLESC)
5564 p++;
5565 *enddir++ = *p++;
5566 }
5567 }
5568 if (enddir == expdir) {
5569 cp = ".";
5570 } else if (enddir == expdir + 1 && *expdir == '/') {
5571 cp = "/";
5572 } else {
5573 cp = expdir;
5574 enddir[-1] = '\0';
5575 }
5576 if ((dirp = opendir(cp)) == NULL)
5577 return;
5578 if (enddir != expdir)
5579 enddir[-1] = '/';
5580 if (*endname == 0) {
5581 atend = 1;
5582 } else {
5583 atend = 0;
5584 *endname++ = '\0';
5585 }
5586 matchdot = 0;
5587 p = start;
5588 while (*p == CTLQUOTEMARK)
5589 p++;
5590 if (*p == CTLESC)
5591 p++;
5592 if (*p == '.')
5593 matchdot++;
5594 while (! int_pending() && (dp = readdir(dirp)) != NULL) {
5595 if (dp->d_name[0] == '.' && ! matchdot)
5596 continue;
5597 if (patmatch(start, dp->d_name, 0)) {
5598 if (atend) {
Eric Andersen2870d962001-07-02 17:27:21 +00005599 strcpy(enddir, dp->d_name);
Eric Andersencb57d552001-06-28 07:25:16 +00005600 addfname(expdir);
5601 } else {
5602 for (p = enddir, cp = dp->d_name;
5603 (*p++ = *cp++) != '\0';)
5604 continue;
5605 p[-1] = '/';
5606 expmeta(p, endname);
5607 }
5608 }
5609 }
5610 closedir(dirp);
5611 if (! atend)
5612 endname[-1] = '/';
5613}
Eric Andersen2870d962001-07-02 17:27:21 +00005614#endif /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005615
5616
Eric Andersencb57d552001-06-28 07:25:16 +00005617
Eric Andersen62483552001-07-10 06:09:16 +00005618#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersencb57d552001-06-28 07:25:16 +00005619/*
5620 * Sort the results of file name expansion. It calculates the number of
5621 * strings to sort and then calls msort (short for merge sort) to do the
5622 * work.
5623 */
5624
5625static struct strlist *
5626expsort(str)
5627 struct strlist *str;
5628 {
5629 int len;
5630 struct strlist *sp;
5631
5632 len = 0;
5633 for (sp = str ; sp ; sp = sp->next)
5634 len++;
5635 return msort(str, len);
5636}
5637
5638
5639static struct strlist *
5640msort(list, len)
5641 struct strlist *list;
5642 int len;
5643{
5644 struct strlist *p, *q = NULL;
5645 struct strlist **lpp;
5646 int half;
5647 int n;
5648
5649 if (len <= 1)
5650 return list;
5651 half = len >> 1;
5652 p = list;
5653 for (n = half ; --n >= 0 ; ) {
5654 q = p;
5655 p = p->next;
5656 }
Eric Andersen2870d962001-07-02 17:27:21 +00005657 q->next = NULL; /* terminate first half of list */
5658 q = msort(list, half); /* sort first half of list */
5659 p = msort(p, len - half); /* sort second half */
Eric Andersencb57d552001-06-28 07:25:16 +00005660 lpp = &list;
5661 for (;;) {
5662 if (strcmp(p->text, q->text) < 0) {
5663 *lpp = p;
5664 lpp = &p->next;
5665 if ((p = *lpp) == NULL) {
5666 *lpp = q;
5667 break;
5668 }
5669 } else {
5670 *lpp = q;
5671 lpp = &q->next;
5672 if ((q = *lpp) == NULL) {
5673 *lpp = p;
5674 break;
5675 }
5676 }
5677 }
5678 return list;
5679}
5680#endif
5681
5682
5683
5684/*
5685 * Returns true if the pattern matches the string.
5686 */
5687
Eric Andersen62483552001-07-10 06:09:16 +00005688#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00005689/* squoted: string might have quote chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005690static int
Eric Andersen2870d962001-07-02 17:27:21 +00005691patmatch(char *pattern, char *string, int squoted)
5692{
Eric Andersencb57d552001-06-28 07:25:16 +00005693 const char *p;
5694 char *q;
5695
5696 p = preglob(pattern);
5697 q = squoted ? _rmescapes(string, RMESCAPE_ALLOC) : string;
5698
5699 return !fnmatch(p, q, 0);
5700}
5701
5702
5703static int
Eric Andersen2870d962001-07-02 17:27:21 +00005704patmatch2(char *pattern, char *string, int squoted)
5705{
Eric Andersencb57d552001-06-28 07:25:16 +00005706 char *p;
5707 int res;
5708
5709 sstrnleft--;
5710 p = grabstackstr(expdest);
5711 res = patmatch(pattern, string, squoted);
5712 ungrabstackstr(p, expdest);
5713 return res;
5714}
5715#else
5716static int
Eric Andersen2870d962001-07-02 17:27:21 +00005717patmatch(char *pattern, char *string, int squoted) {
5718 return pmatch(pattern, string, squoted);
Eric Andersencb57d552001-06-28 07:25:16 +00005719}
5720
5721
5722static int
Eric Andersen2870d962001-07-02 17:27:21 +00005723pmatch(char *pattern, char *string, int squoted)
5724{
Eric Andersencb57d552001-06-28 07:25:16 +00005725 char *p, *q;
5726 char c;
5727
5728 p = pattern;
5729 q = string;
5730 for (;;) {
5731 switch (c = *p++) {
5732 case '\0':
5733 goto breakloop;
5734 case CTLESC:
5735 if (squoted && *q == CTLESC)
5736 q++;
5737 if (*q++ != *p++)
5738 return 0;
5739 break;
5740 case CTLQUOTEMARK:
5741 continue;
5742 case '?':
5743 if (squoted && *q == CTLESC)
5744 q++;
5745 if (*q++ == '\0')
5746 return 0;
5747 break;
5748 case '*':
5749 c = *p;
5750 while (c == CTLQUOTEMARK || c == '*')
5751 c = *++p;
5752 if (c != CTLESC && c != CTLQUOTEMARK &&
5753 c != '?' && c != '*' && c != '[') {
5754 while (*q != c) {
5755 if (squoted && *q == CTLESC &&
5756 q[1] == c)
5757 break;
5758 if (*q == '\0')
5759 return 0;
5760 if (squoted && *q == CTLESC)
5761 q++;
5762 q++;
5763 }
5764 }
5765 do {
5766 if (pmatch(p, q, squoted))
5767 return 1;
5768 if (squoted && *q == CTLESC)
5769 q++;
5770 } while (*q++ != '\0');
5771 return 0;
5772 case '[': {
5773 char *endp;
5774 int invert, found;
5775 char chr;
5776
5777 endp = p;
5778 if (*endp == '!')
5779 endp++;
5780 for (;;) {
5781 while (*endp == CTLQUOTEMARK)
5782 endp++;
5783 if (*endp == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00005784 goto dft; /* no matching ] */
Eric Andersencb57d552001-06-28 07:25:16 +00005785 if (*endp == CTLESC)
5786 endp++;
5787 if (*++endp == ']')
5788 break;
5789 }
5790 invert = 0;
5791 if (*p == '!') {
5792 invert++;
5793 p++;
5794 }
5795 found = 0;
5796 chr = *q++;
5797 if (squoted && chr == CTLESC)
5798 chr = *q++;
5799 if (chr == '\0')
5800 return 0;
5801 c = *p++;
5802 do {
5803 if (c == CTLQUOTEMARK)
5804 continue;
5805 if (c == CTLESC)
5806 c = *p++;
5807 if (*p == '-' && p[1] != ']') {
5808 p++;
5809 while (*p == CTLQUOTEMARK)
5810 p++;
5811 if (*p == CTLESC)
5812 p++;
5813 if (chr >= c && chr <= *p)
5814 found = 1;
5815 p++;
5816 } else {
5817 if (chr == c)
5818 found = 1;
5819 }
5820 } while ((c = *p++) != ']');
5821 if (found == invert)
5822 return 0;
5823 break;
5824 }
Eric Andersen2870d962001-07-02 17:27:21 +00005825dft: default:
Eric Andersencb57d552001-06-28 07:25:16 +00005826 if (squoted && *q == CTLESC)
5827 q++;
5828 if (*q++ != c)
5829 return 0;
5830 break;
5831 }
5832 }
5833breakloop:
5834 if (*q != '\0')
5835 return 0;
5836 return 1;
5837}
5838#endif
5839
5840
5841
5842/*
5843 * Remove any CTLESC characters from a string.
5844 */
5845
Eric Andersen62483552001-07-10 06:09:16 +00005846#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00005847static char *
Eric Andersen2870d962001-07-02 17:27:21 +00005848_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005849{
5850 char *p, *q, *r;
5851 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5852
5853 p = strpbrk(str, qchars);
5854 if (!p) {
5855 return str;
5856 }
5857 q = p;
5858 r = str;
5859 if (flag & RMESCAPE_ALLOC) {
5860 size_t len = p - str;
5861 q = r = stalloc(strlen(p) + len + 1);
5862 if (len > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00005863 memcpy(q, str, len);
5864 q += len;
Eric Andersencb57d552001-06-28 07:25:16 +00005865 }
5866 }
5867 while (*p) {
5868 if (*p == CTLQUOTEMARK) {
5869 p++;
5870 continue;
5871 }
5872 if (*p == CTLESC) {
5873 p++;
5874 if (flag & RMESCAPE_GLOB && *p != '/') {
5875 *q++ = '\\';
5876 }
5877 }
5878 *q++ = *p++;
5879 }
5880 *q = '\0';
5881 return r;
5882}
5883#else
5884static void
5885rmescapes(str)
5886 char *str;
5887{
5888 char *p, *q;
5889
5890 p = str;
5891 while (*p != CTLESC && *p != CTLQUOTEMARK) {
5892 if (*p++ == '\0')
5893 return;
5894 }
5895 q = p;
5896 while (*p) {
5897 if (*p == CTLQUOTEMARK) {
5898 p++;
5899 continue;
5900 }
5901 if (*p == CTLESC)
5902 p++;
5903 *q++ = *p++;
5904 }
5905 *q = '\0';
5906}
5907#endif
5908
5909
5910
5911/*
5912 * See if a pattern matches in a case statement.
5913 */
5914
5915static int
Eric Andersen2870d962001-07-02 17:27:21 +00005916casematch(union node *pattern, const char *val)
5917{
Eric Andersencb57d552001-06-28 07:25:16 +00005918 struct stackmark smark;
5919 int result;
5920 char *p;
5921
5922 setstackmark(&smark);
5923 argbackq = pattern->narg.backquote;
5924 STARTSTACKSTR(expdest);
5925 ifslastp = NULL;
5926 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5927 STPUTC('\0', expdest);
5928 p = grabstackstr(expdest);
Eric Andersen2870d962001-07-02 17:27:21 +00005929 result = patmatch(p, (char *)val, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00005930 popstackmark(&smark);
5931 return result;
5932}
5933
5934/*
5935 * Our own itoa().
5936 */
5937
5938static char *
5939cvtnum(num, buf)
5940 int num;
5941 char *buf;
5942 {
5943 int len;
5944
5945 CHECKSTRSPACE(32, buf);
5946 len = sprintf(buf, "%d", num);
5947 STADJUST(len, buf);
5948 return buf;
5949}
Eric Andersencb57d552001-06-28 07:25:16 +00005950/*
5951 * Editline and history functions (and glue).
5952 */
5953static int histcmd(argc, argv)
5954 int argc;
5955 char **argv;
5956{
5957 error("not compiled with history support");
5958 /* NOTREACHED */
5959}
5960
5961
Eric Andersencb57d552001-06-28 07:25:16 +00005962struct redirtab {
5963 struct redirtab *next;
Russ Dill4db35642001-07-26 05:58:40 +00005964 short renamed[10]; /* Current ash support only 0-9 descriptors */
Eric Andersen34506362001-08-02 05:02:46 +00005965 /* char on arm (and others) can't be negative */
Eric Andersencb57d552001-06-28 07:25:16 +00005966};
5967
Eric Andersen2870d962001-07-02 17:27:21 +00005968static struct redirtab *redirlist;
Eric Andersencb57d552001-06-28 07:25:16 +00005969
5970extern char **environ;
5971
5972
5973
5974/*
5975 * Initialization code.
5976 */
5977
5978static void
Eric Andersen2870d962001-07-02 17:27:21 +00005979init(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00005980
5981 /* from cd.c: */
5982 {
5983 setpwd(0, 0);
5984 }
5985
5986 /* from input.c: */
5987 {
5988 basepf.nextc = basepf.buf = basebuf;
5989 }
5990
Eric Andersencb57d552001-06-28 07:25:16 +00005991 /* from var.c: */
5992 {
5993 char **envp;
5994 char ppid[32];
5995
5996 initvar();
5997 for (envp = environ ; *envp ; envp++) {
5998 if (strchr(*envp, '=')) {
5999 setvareq(*envp, VEXPORT|VTEXTFIXED);
6000 }
6001 }
6002
Eric Andersen3102ac42001-07-06 04:26:23 +00006003 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
Eric Andersencb57d552001-06-28 07:25:16 +00006004 setvar("PPID", ppid, 0);
6005 }
6006}
6007
6008
6009
6010/*
6011 * This routine is called when an error or an interrupt occurs in an
6012 * interactive shell and control is returned to the main command loop.
6013 */
6014
Eric Andersen2870d962001-07-02 17:27:21 +00006015/* 1 == check for aliases, 2 == also check for assignments */
Eric Andersen7467c8d2001-07-12 20:26:32 +00006016static int checkalias; /* also used in no alias mode for check assignments */
Eric Andersen2870d962001-07-02 17:27:21 +00006017
Eric Andersencb57d552001-06-28 07:25:16 +00006018static void
Eric Andersen2870d962001-07-02 17:27:21 +00006019reset(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00006020
6021 /* from eval.c: */
6022 {
6023 evalskip = 0;
6024 loopnest = 0;
6025 funcnest = 0;
6026 }
6027
6028 /* from input.c: */
6029 {
6030 if (exception != EXSHELLPROC)
Eric Andersen2870d962001-07-02 17:27:21 +00006031 parselleft = parsenleft = 0; /* clear input buffer */
Eric Andersencb57d552001-06-28 07:25:16 +00006032 popallfiles();
6033 }
6034
6035 /* from parser.c: */
6036 {
6037 tokpushback = 0;
6038 checkkwd = 0;
6039 checkalias = 0;
6040 }
6041
6042 /* from redir.c: */
6043 {
6044 while (redirlist)
6045 popredir();
6046 }
6047
Eric Andersencb57d552001-06-28 07:25:16 +00006048}
6049
6050
6051
6052/*
Eric Andersencb57d552001-06-28 07:25:16 +00006053 * This file implements the input routines used by the parser.
6054 */
6055
6056#ifdef BB_FEATURE_COMMAND_EDITING
Eric Andersencb57d552001-06-28 07:25:16 +00006057static const char * cmdedit_prompt;
6058static inline void putprompt(const char *s) {
6059 cmdedit_prompt = s;
6060}
6061#else
6062static inline void putprompt(const char *s) {
6063 out2str(s);
6064}
6065#endif
6066
Eric Andersen2870d962001-07-02 17:27:21 +00006067#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
Eric Andersencb57d552001-06-28 07:25:16 +00006068
Eric Andersencb57d552001-06-28 07:25:16 +00006069
Eric Andersencb57d552001-06-28 07:25:16 +00006070
Eric Andersen2870d962001-07-02 17:27:21 +00006071/*
6072 * Same as pgetc(), but ignores PEOA.
6073 */
Eric Andersencb57d552001-06-28 07:25:16 +00006074
Eric Andersen2870d962001-07-02 17:27:21 +00006075#ifdef ASH_ALIAS
6076static int
6077pgetc2()
6078{
6079 int c;
6080 do {
6081 c = pgetc_macro();
6082 } while (c == PEOA);
6083 return c;
Eric Andersencb57d552001-06-28 07:25:16 +00006084}
Eric Andersen2870d962001-07-02 17:27:21 +00006085#else
6086static inline int pgetc2() { return pgetc_macro(); }
Eric Andersencb57d552001-06-28 07:25:16 +00006087#endif
6088
Eric Andersencb57d552001-06-28 07:25:16 +00006089/*
6090 * Read a line from the script.
6091 */
6092
Eric Andersen62483552001-07-10 06:09:16 +00006093static inline char *
Eric Andersen2870d962001-07-02 17:27:21 +00006094pfgets(char *line, int len)
Eric Andersencb57d552001-06-28 07:25:16 +00006095{
6096 char *p = line;
6097 int nleft = len;
6098 int c;
6099
6100 while (--nleft > 0) {
6101 c = pgetc2();
6102 if (c == PEOF) {
6103 if (p == line)
6104 return NULL;
6105 break;
6106 }
6107 *p++ = c;
6108 if (c == '\n')
6109 break;
6110 }
6111 *p = '\0';
6112 return line;
6113}
6114
Eric Andersen62483552001-07-10 06:09:16 +00006115static inline int
Eric Andersen2870d962001-07-02 17:27:21 +00006116preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006117{
6118 int nr;
6119 char *buf = parsefile->buf;
6120 parsenextc = buf;
6121
6122retry:
6123#ifdef BB_FEATURE_COMMAND_EDITING
6124 {
Eric Andersen34506362001-08-02 05:02:46 +00006125 if (!iflag || parsefile->fd)
Eric Andersen7467c8d2001-07-12 20:26:32 +00006126 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersen2870d962001-07-02 17:27:21 +00006127 else {
Eric Andersen044228d2001-07-17 01:12:36 +00006128 nr = cmdedit_read_input((char*)cmdedit_prompt, buf);
Eric Andersencb57d552001-06-28 07:25:16 +00006129 }
6130 }
6131#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00006132 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006133#endif
6134
6135 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006136 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6137 int flags = fcntl(0, F_GETFL, 0);
6138 if (flags >= 0 && flags & O_NONBLOCK) {
6139 flags &=~ O_NONBLOCK;
6140 if (fcntl(0, F_SETFL, flags) >= 0) {
6141 out2str("sh: turning off NDELAY mode\n");
6142 goto retry;
6143 }
6144 }
6145 }
6146 }
6147 return nr;
6148}
6149
Eric Andersen2870d962001-07-02 17:27:21 +00006150static void
6151popstring(void)
6152{
6153 struct strpush *sp = parsefile->strpush;
6154
6155 INTOFF;
6156#ifdef ASH_ALIAS
6157 if (sp->ap) {
6158 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6159 if (!checkalias) {
6160 checkalias = 1;
6161 }
6162 }
6163 if (sp->string != sp->ap->val) {
6164 ckfree(sp->string);
6165 }
6166
6167 sp->ap->flag &= ~ALIASINUSE;
6168 if (sp->ap->flag & ALIASDEAD) {
6169 unalias(sp->ap->name);
6170 }
6171 }
6172#endif
6173 parsenextc = sp->prevstring;
6174 parsenleft = sp->prevnleft;
6175/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6176 parsefile->strpush = sp->prev;
6177 if (sp != &(parsefile->basestrpush))
6178 ckfree(sp);
6179 INTON;
6180}
6181
6182
Eric Andersencb57d552001-06-28 07:25:16 +00006183/*
6184 * Refill the input buffer and return the next input character:
6185 *
6186 * 1) If a string was pushed back on the input, pop it;
6187 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6188 * from a string so we can't refill the buffer, return EOF.
6189 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6190 * 4) Process input up to the next newline, deleting nul characters.
6191 */
6192
6193static int
Eric Andersen2870d962001-07-02 17:27:21 +00006194preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006195{
6196 char *p, *q;
6197 int more;
6198 char savec;
6199
6200 while (parsefile->strpush) {
Eric Andersen2870d962001-07-02 17:27:21 +00006201#ifdef ASH_ALIAS
6202 if (parsenleft == -1 && parsefile->strpush->ap &&
6203 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00006204 return PEOA;
6205 }
Eric Andersen2870d962001-07-02 17:27:21 +00006206#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006207 popstring();
6208 if (--parsenleft >= 0)
6209 return (*parsenextc++);
6210 }
6211 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6212 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00006213 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00006214
6215again:
6216 if (parselleft <= 0) {
6217 if ((parselleft = preadfd()) <= 0) {
6218 parselleft = parsenleft = EOF_NLEFT;
6219 return PEOF;
6220 }
6221 }
6222
6223 q = p = parsenextc;
6224
6225 /* delete nul characters */
6226 for (more = 1; more;) {
6227 switch (*p) {
6228 case '\0':
Eric Andersen2870d962001-07-02 17:27:21 +00006229 p++; /* Skip nul */
Eric Andersencb57d552001-06-28 07:25:16 +00006230 goto check;
6231
6232
6233 case '\n':
6234 parsenleft = q - parsenextc;
6235 more = 0; /* Stop processing here */
6236 break;
6237 }
6238
6239 *q++ = *p++;
6240check:
6241 if (--parselleft <= 0 && more) {
6242 parsenleft = q - parsenextc - 1;
6243 if (parsenleft < 0)
6244 goto again;
6245 more = 0;
6246 }
6247 }
6248
6249 savec = *q;
6250 *q = '\0';
6251
6252 if (vflag) {
6253 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00006254 }
6255
6256 *q = savec;
6257
6258 return *parsenextc++;
6259}
6260
Eric Andersencb57d552001-06-28 07:25:16 +00006261
6262/*
6263 * Push a string back onto the input at this current parsefile level.
6264 * We handle aliases this way.
6265 */
6266static void
Eric Andersen2870d962001-07-02 17:27:21 +00006267pushstring(char *s, int len, void *ap)
6268{
Eric Andersencb57d552001-06-28 07:25:16 +00006269 struct strpush *sp;
6270
6271 INTOFF;
6272/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6273 if (parsefile->strpush) {
6274 sp = ckmalloc(sizeof (struct strpush));
6275 sp->prev = parsefile->strpush;
6276 parsefile->strpush = sp;
6277 } else
6278 sp = parsefile->strpush = &(parsefile->basestrpush);
6279 sp->prevstring = parsenextc;
6280 sp->prevnleft = parsenleft;
Eric Andersen2870d962001-07-02 17:27:21 +00006281#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00006282 sp->ap = (struct alias *)ap;
6283 if (ap) {
6284 ((struct alias *)ap)->flag |= ALIASINUSE;
6285 sp->string = s;
6286 }
Eric Andersen2870d962001-07-02 17:27:21 +00006287#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006288 parsenextc = s;
6289 parsenleft = len;
6290 INTON;
6291}
6292
Eric Andersencb57d552001-06-28 07:25:16 +00006293
Eric Andersencb57d552001-06-28 07:25:16 +00006294/*
6295 * Like setinputfile, but takes input from a string.
6296 */
6297
6298static void
Eric Andersen62483552001-07-10 06:09:16 +00006299setinputstring(char *string)
6300{
Eric Andersencb57d552001-06-28 07:25:16 +00006301 INTOFF;
6302 pushfile();
6303 parsenextc = string;
6304 parsenleft = strlen(string);
6305 parsefile->buf = NULL;
6306 plinno = 1;
6307 INTON;
6308}
6309
6310
6311
6312/*
6313 * To handle the "." command, a stack of input files is used. Pushfile
6314 * adds a new entry to the stack and popfile restores the previous level.
6315 */
6316
6317static void
Eric Andersen2870d962001-07-02 17:27:21 +00006318pushfile(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00006319 struct parsefile *pf;
6320
6321 parsefile->nleft = parsenleft;
6322 parsefile->lleft = parselleft;
6323 parsefile->nextc = parsenextc;
6324 parsefile->linno = plinno;
6325 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6326 pf->prev = parsefile;
6327 pf->fd = -1;
6328 pf->strpush = NULL;
6329 pf->basestrpush.prev = NULL;
6330 parsefile = pf;
6331}
6332
Eric Andersen2870d962001-07-02 17:27:21 +00006333#ifdef JOBS
6334static void restartjob (struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00006335#endif
Eric Andersen2870d962001-07-02 17:27:21 +00006336static void freejob (struct job *);
6337static struct job *getjob (const char *);
6338static int dowait (int, struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00006339static void waitonint(int);
6340
6341
Eric Andersen2870d962001-07-02 17:27:21 +00006342/*
6343 * We keep track of whether or not fd0 has been redirected. This is for
6344 * background commands, where we want to redirect fd0 to /dev/null only
6345 * if it hasn't already been redirected.
6346*/
6347static int fd0_redirected = 0;
6348
6349/* Return true if fd 0 has already been redirected at least once. */
6350static inline int
6351fd0_redirected_p () {
6352 return fd0_redirected != 0;
6353}
6354
Eric Andersen62483552001-07-10 06:09:16 +00006355static void dupredirect (const union node *, int, int fd1dup);
Eric Andersen2870d962001-07-02 17:27:21 +00006356
6357#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006358/*
6359 * Turn job control on and off.
6360 *
6361 * Note: This code assumes that the third arg to ioctl is a character
6362 * pointer, which is true on Berkeley systems but not System V. Since
6363 * System V doesn't have job control yet, this isn't a problem now.
6364 */
6365
Eric Andersen2870d962001-07-02 17:27:21 +00006366
Eric Andersencb57d552001-06-28 07:25:16 +00006367
6368static void setjobctl(int enable)
6369{
6370#ifdef OLD_TTY_DRIVER
6371 int ldisc;
6372#endif
6373
6374 if (enable == jobctl || rootshell == 0)
6375 return;
6376 if (enable) {
6377 do { /* while we are in the background */
6378#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006379 if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006380#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006381 initialpgrp = tcgetpgrp(2);
Eric Andersencb57d552001-06-28 07:25:16 +00006382 if (initialpgrp < 0) {
6383#endif
Eric Andersen8c145dc2001-07-10 16:57:09 +00006384 out2str("sh: can't access tty; job control turned off\n");
Eric Andersencb57d552001-06-28 07:25:16 +00006385 mflag = 0;
6386 return;
6387 }
6388 if (initialpgrp == -1)
6389 initialpgrp = getpgrp();
6390 else if (initialpgrp != getpgrp()) {
6391 killpg(initialpgrp, SIGTTIN);
6392 continue;
6393 }
6394 } while (0);
6395#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006396 if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
Eric Andersen8c145dc2001-07-10 16:57:09 +00006397 out2str("sh: need new tty driver to run job control; job control turned off\n");
Eric Andersencb57d552001-06-28 07:25:16 +00006398 mflag = 0;
6399 return;
6400 }
6401#endif
6402 setsignal(SIGTSTP);
6403 setsignal(SIGTTOU);
6404 setsignal(SIGTTIN);
6405 setpgid(0, rootpid);
6406#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006407 ioctl(2, TIOCSPGRP, (char *)&rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00006408#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006409 tcsetpgrp(2, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00006410#endif
Eric Andersen8c145dc2001-07-10 16:57:09 +00006411 } else { /* turning job control off */
Eric Andersencb57d552001-06-28 07:25:16 +00006412 setpgid(0, initialpgrp);
6413#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006414 ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006415#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006416 tcsetpgrp(2, initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006417#endif
6418 setsignal(SIGTSTP);
6419 setsignal(SIGTTOU);
6420 setsignal(SIGTTIN);
6421 }
6422 jobctl = enable;
6423}
6424#endif
6425
6426
Eric Andersen2870d962001-07-02 17:27:21 +00006427#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006428static int
6429killcmd(argc, argv)
6430 int argc;
6431 char **argv;
6432{
6433 int signo = -1;
6434 int list = 0;
6435 int i;
6436 pid_t pid;
6437 struct job *jp;
6438
6439 if (argc <= 1) {
6440usage:
6441 error(
6442"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6443"kill -l [exitstatus]"
6444 );
6445 }
6446
6447 if (*argv[1] == '-') {
6448 signo = decode_signal(argv[1] + 1, 1);
6449 if (signo < 0) {
6450 int c;
6451
6452 while ((c = nextopt("ls:")) != '\0')
6453 switch (c) {
6454 case 'l':
6455 list = 1;
6456 break;
6457 case 's':
6458 signo = decode_signal(optionarg, 1);
6459 if (signo < 0) {
6460 error(
6461 "invalid signal number or name: %s",
6462 optionarg
6463 );
6464 }
Eric Andersen2870d962001-07-02 17:27:21 +00006465 break;
Eric Andersencb57d552001-06-28 07:25:16 +00006466#ifdef DEBUG
6467 default:
6468 error(
6469 "nextopt returned character code 0%o", c);
6470#endif
6471 }
6472 } else
6473 argptr++;
6474 }
6475
6476 if (!list && signo < 0)
6477 signo = SIGTERM;
6478
6479 if ((signo < 0 || !*argptr) ^ list) {
6480 goto usage;
6481 }
6482
6483 if (list) {
Eric Andersen34506362001-08-02 05:02:46 +00006484 const char *name;
6485
Eric Andersencb57d552001-06-28 07:25:16 +00006486 if (!*argptr) {
6487 out1str("0\n");
6488 for (i = 1; i < NSIG; i++) {
Eric Andersen34506362001-08-02 05:02:46 +00006489 name = u_signal_names(0, &i, 1);
6490 if(name)
6491 printf(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006492 }
6493 return 0;
6494 }
Eric Andersen34506362001-08-02 05:02:46 +00006495 name = u_signal_names(*argptr, &signo, -1);
6496 if (name)
6497 printf(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006498 else
6499 error("invalid signal number or exit status: %s",
6500 *argptr);
6501 return 0;
6502 }
6503
6504 do {
6505 if (**argptr == '%') {
6506 jp = getjob(*argptr);
6507 if (jp->jobctl == 0)
6508 error("job %s not created under job control",
6509 *argptr);
6510 pid = -jp->ps[0].pid;
6511 } else
6512 pid = atoi(*argptr);
6513 if (kill(pid, signo) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00006514 error("%s: %m", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006515 } while (*++argptr);
6516
6517 return 0;
6518}
6519
6520static int
6521fgcmd(argc, argv)
6522 int argc;
6523 char **argv;
6524{
6525 struct job *jp;
6526 int pgrp;
6527 int status;
6528
6529 jp = getjob(argv[1]);
6530 if (jp->jobctl == 0)
6531 error("job not created under job control");
6532 pgrp = jp->ps[0].pid;
6533#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006534 ioctl(2, TIOCSPGRP, (char *)&pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006535#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006536 tcsetpgrp(2, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006537#endif
6538 restartjob(jp);
6539 INTOFF;
6540 status = waitforjob(jp);
6541 INTON;
6542 return status;
6543}
6544
6545
6546static int
6547bgcmd(argc, argv)
6548 int argc;
6549 char **argv;
6550{
6551 struct job *jp;
6552
6553 do {
6554 jp = getjob(*++argv);
6555 if (jp->jobctl == 0)
6556 error("job not created under job control");
6557 restartjob(jp);
6558 } while (--argc > 1);
6559 return 0;
6560}
6561
6562
6563static void
6564restartjob(jp)
6565 struct job *jp;
6566{
6567 struct procstat *ps;
6568 int i;
6569
6570 if (jp->state == JOBDONE)
6571 return;
6572 INTOFF;
6573 killpg(jp->ps[0].pid, SIGCONT);
6574 for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
6575 if (WIFSTOPPED(ps->status)) {
6576 ps->status = -1;
6577 jp->state = 0;
6578 }
6579 }
6580 INTON;
6581}
6582#endif
6583
Eric Andersen2870d962001-07-02 17:27:21 +00006584static void showjobs(int change);
6585
Eric Andersencb57d552001-06-28 07:25:16 +00006586
6587static int
6588jobscmd(argc, argv)
6589 int argc;
6590 char **argv;
6591{
6592 showjobs(0);
6593 return 0;
6594}
6595
6596
6597/*
6598 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6599 * statuses have changed since the last call to showjobs.
6600 *
6601 * If the shell is interrupted in the process of creating a job, the
6602 * result may be a job structure containing zero processes. Such structures
6603 * will be freed here.
6604 */
6605
6606static void
6607showjobs(change)
6608 int change;
6609{
6610 int jobno;
6611 int procno;
6612 int i;
6613 struct job *jp;
6614 struct procstat *ps;
6615 int col;
6616 char s[64];
6617
6618 TRACE(("showjobs(%d) called\n", change));
6619 while (dowait(0, (struct job *)NULL) > 0);
6620 for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
6621 if (! jp->used)
6622 continue;
6623 if (jp->nprocs == 0) {
6624 freejob(jp);
6625 continue;
6626 }
6627 if (change && ! jp->changed)
6628 continue;
6629 procno = jp->nprocs;
Eric Andersen2870d962001-07-02 17:27:21 +00006630 for (ps = jp->ps ; ; ps++) { /* for each process */
Eric Andersencb57d552001-06-28 07:25:16 +00006631 if (ps == jp->ps)
Eric Andersen3102ac42001-07-06 04:26:23 +00006632 snprintf(s, 64, "[%d] %ld ", jobno,
Eric Andersencb57d552001-06-28 07:25:16 +00006633 (long)ps->pid);
6634 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006635 snprintf(s, 64, " %ld ",
Eric Andersencb57d552001-06-28 07:25:16 +00006636 (long)ps->pid);
6637 out1str(s);
6638 col = strlen(s);
6639 s[0] = '\0';
6640 if (ps->status == -1) {
6641 /* don't print anything */
6642 } else if (WIFEXITED(ps->status)) {
Eric Andersen3102ac42001-07-06 04:26:23 +00006643 snprintf(s, 64, "Exit %d",
Eric Andersencb57d552001-06-28 07:25:16 +00006644 WEXITSTATUS(ps->status));
6645 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00006646#ifdef JOBS
6647 if (WIFSTOPPED(ps->status))
Eric Andersencb57d552001-06-28 07:25:16 +00006648 i = WSTOPSIG(ps->status);
6649 else /* WIFSIGNALED(ps->status) */
6650#endif
6651 i = WTERMSIG(ps->status);
6652 if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
Eric Andersen2870d962001-07-02 17:27:21 +00006653 strcpy(s, sys_siglist[i & 0x7F]);
Eric Andersencb57d552001-06-28 07:25:16 +00006654 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006655 snprintf(s, 64, "Signal %d", i & 0x7F);
Eric Andersencb57d552001-06-28 07:25:16 +00006656 if (WCOREDUMP(ps->status))
6657 strcat(s, " (core dumped)");
6658 }
6659 out1str(s);
6660 col += strlen(s);
Eric Andersen62483552001-07-10 06:09:16 +00006661 printf(
Eric Andersencb57d552001-06-28 07:25:16 +00006662 "%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ',
6663 ps->cmd
6664 );
6665 if (--procno <= 0)
6666 break;
6667 }
6668 jp->changed = 0;
6669 if (jp->state == JOBDONE) {
6670 freejob(jp);
6671 }
6672 }
6673}
6674
6675
6676/*
6677 * Mark a job structure as unused.
6678 */
6679
6680static void
Eric Andersen62483552001-07-10 06:09:16 +00006681freejob(struct job *jp)
6682{
6683 const struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006684 int i;
6685
6686 INTOFF;
6687 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6688 if (ps->cmd != nullstr)
6689 ckfree(ps->cmd);
6690 }
6691 if (jp->ps != &jp->ps0)
6692 ckfree(jp->ps);
6693 jp->used = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006694#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006695 if (curjob == jp - jobtab + 1)
6696 curjob = 0;
6697#endif
6698 INTON;
6699}
6700
6701
6702
6703static int
6704waitcmd(argc, argv)
6705 int argc;
6706 char **argv;
6707{
6708 struct job *job;
6709 int status, retval;
6710 struct job *jp;
6711
6712 if (--argc > 0) {
6713start:
6714 job = getjob(*++argv);
6715 } else {
6716 job = NULL;
6717 }
Eric Andersen2870d962001-07-02 17:27:21 +00006718 for (;;) { /* loop until process terminated or stopped */
Eric Andersencb57d552001-06-28 07:25:16 +00006719 if (job != NULL) {
6720 if (job->state) {
6721 status = job->ps[job->nprocs - 1].status;
6722 if (! iflag)
6723 freejob(job);
6724 if (--argc) {
6725 goto start;
6726 }
6727 if (WIFEXITED(status))
6728 retval = WEXITSTATUS(status);
Eric Andersen2870d962001-07-02 17:27:21 +00006729#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006730 else if (WIFSTOPPED(status))
6731 retval = WSTOPSIG(status) + 128;
6732#endif
6733 else {
6734 /* XXX: limits number of signals */
6735 retval = WTERMSIG(status) + 128;
6736 }
6737 return retval;
6738 }
6739 } else {
6740 for (jp = jobtab ; ; jp++) {
Eric Andersen2870d962001-07-02 17:27:21 +00006741 if (jp >= jobtab + njobs) { /* no running procs */
Eric Andersencb57d552001-06-28 07:25:16 +00006742 return 0;
6743 }
6744 if (jp->used && jp->state == 0)
6745 break;
6746 }
6747 }
6748 if (dowait(2, 0) < 0 && errno == EINTR) {
6749 return 129;
6750 }
6751 }
6752}
6753
6754
6755
6756/*
6757 * Convert a job name to a job structure.
6758 */
6759
6760static struct job *
Eric Andersen2870d962001-07-02 17:27:21 +00006761getjob(const char *name)
6762{
Eric Andersencb57d552001-06-28 07:25:16 +00006763 int jobno;
6764 struct job *jp;
6765 int pid;
6766 int i;
6767
6768 if (name == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00006769#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006770currentjob:
6771 if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
6772 error("No current job");
6773 return &jobtab[jobno - 1];
6774#else
6775 error("No current job");
6776#endif
6777 } else if (name[0] == '%') {
6778 if (is_digit(name[1])) {
6779 jobno = number(name + 1);
6780 if (jobno > 0 && jobno <= njobs
6781 && jobtab[jobno - 1].used != 0)
6782 return &jobtab[jobno - 1];
Eric Andersen2870d962001-07-02 17:27:21 +00006783#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006784 } else if (name[1] == '%' && name[2] == '\0') {
6785 goto currentjob;
6786#endif
6787 } else {
6788 struct job *found = NULL;
6789 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
6790 if (jp->used && jp->nprocs > 0
6791 && prefix(name + 1, jp->ps[0].cmd)) {
6792 if (found)
6793 error("%s: ambiguous", name);
6794 found = jp;
6795 }
6796 }
6797 if (found)
6798 return found;
6799 }
Eric Andersen2870d962001-07-02 17:27:21 +00006800 } else if (is_number(name, &pid)) {
Eric Andersencb57d552001-06-28 07:25:16 +00006801 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
6802 if (jp->used && jp->nprocs > 0
6803 && jp->ps[jp->nprocs - 1].pid == pid)
6804 return jp;
6805 }
6806 }
6807 error("No such job: %s", name);
6808 /* NOTREACHED */
6809}
6810
6811
6812
6813/*
6814 * Return a new job structure,
6815 */
6816
Eric Andersen2870d962001-07-02 17:27:21 +00006817static struct job *
Eric Andersen62483552001-07-10 06:09:16 +00006818makejob(const union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00006819{
6820 int i;
6821 struct job *jp;
6822
6823 for (i = njobs, jp = jobtab ; ; jp++) {
6824 if (--i < 0) {
6825 INTOFF;
6826 if (njobs == 0) {
6827 jobtab = ckmalloc(4 * sizeof jobtab[0]);
6828 } else {
6829 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
6830 memcpy(jp, jobtab, njobs * sizeof jp[0]);
6831 /* Relocate `ps' pointers */
6832 for (i = 0; i < njobs; i++)
6833 if (jp[i].ps == &jobtab[i].ps0)
6834 jp[i].ps = &jp[i].ps0;
6835 ckfree(jobtab);
6836 jobtab = jp;
6837 }
6838 jp = jobtab + njobs;
6839 for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
6840 INTON;
6841 break;
6842 }
6843 if (jp->used == 0)
6844 break;
6845 }
6846 INTOFF;
6847 jp->state = 0;
6848 jp->used = 1;
6849 jp->changed = 0;
6850 jp->nprocs = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006851#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006852 jp->jobctl = jobctl;
6853#endif
6854 if (nprocs > 1) {
6855 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
6856 } else {
6857 jp->ps = &jp->ps0;
6858 }
6859 INTON;
6860 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
6861 jp - jobtab + 1));
6862 return jp;
6863}
6864
6865
6866/*
6867 * Fork of a subshell. If we are doing job control, give the subshell its
6868 * own process group. Jp is a job structure that the job is to be added to.
6869 * N is the command that will be evaluated by the child. Both jp and n may
6870 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00006871 * FORK_FG - Fork off a foreground process.
6872 * FORK_BG - Fork off a background process.
6873 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
6874 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00006875 *
6876 * When job control is turned off, background processes have their standard
6877 * input redirected to /dev/null (except for the second and later processes
6878 * in a pipeline).
6879 */
6880
Eric Andersen2870d962001-07-02 17:27:21 +00006881
6882
Eric Andersencb57d552001-06-28 07:25:16 +00006883static int
Eric Andersen62483552001-07-10 06:09:16 +00006884forkshell(struct job *jp, const union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00006885{
6886 int pid;
Eric Andersen62483552001-07-10 06:09:16 +00006887#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006888 int pgrp;
Eric Andersen62483552001-07-10 06:09:16 +00006889#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006890 const char *devnull = _PATH_DEVNULL;
6891 const char *nullerr = "Can't open %s";
6892
6893 TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
6894 mode));
6895 INTOFF;
6896 pid = fork();
6897 if (pid == -1) {
6898 TRACE(("Fork failed, errno=%d\n", errno));
6899 INTON;
6900 error("Cannot fork");
6901 }
6902 if (pid == 0) {
6903 struct job *p;
6904 int wasroot;
6905 int i;
6906
6907 TRACE(("Child shell %d\n", getpid()));
6908 wasroot = rootshell;
6909 rootshell = 0;
6910 closescript();
6911 INTON;
6912 clear_traps();
Eric Andersen2870d962001-07-02 17:27:21 +00006913#ifdef JOBS
6914 jobctl = 0; /* do job control only in root shell */
Eric Andersencb57d552001-06-28 07:25:16 +00006915 if (wasroot && mode != FORK_NOJOB && mflag) {
6916 if (jp == NULL || jp->nprocs == 0)
6917 pgrp = getpid();
6918 else
6919 pgrp = jp->ps[0].pid;
6920 setpgid(0, pgrp);
6921 if (mode == FORK_FG) {
6922 /*** this causes superfluous TIOCSPGRPS ***/
6923#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006924 if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006925 error("TIOCSPGRP failed, errno=%d", errno);
6926#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006927 if (tcsetpgrp(2, pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006928 error("tcsetpgrp failed, errno=%d", errno);
6929#endif
6930 }
6931 setsignal(SIGTSTP);
6932 setsignal(SIGTTOU);
6933 } else if (mode == FORK_BG) {
6934 ignoresig(SIGINT);
6935 ignoresig(SIGQUIT);
6936 if ((jp == NULL || jp->nprocs == 0) &&
6937 ! fd0_redirected_p ()) {
6938 close(0);
6939 if (open(devnull, O_RDONLY) != 0)
6940 error(nullerr, devnull);
6941 }
6942 }
6943#else
6944 if (mode == FORK_BG) {
6945 ignoresig(SIGINT);
6946 ignoresig(SIGQUIT);
6947 if ((jp == NULL || jp->nprocs == 0) &&
6948 ! fd0_redirected_p ()) {
6949 close(0);
6950 if (open(devnull, O_RDONLY) != 0)
6951 error(nullerr, devnull);
6952 }
6953 }
6954#endif
6955 for (i = njobs, p = jobtab ; --i >= 0 ; p++)
6956 if (p->used)
6957 freejob(p);
6958 if (wasroot && iflag) {
6959 setsignal(SIGINT);
6960 setsignal(SIGQUIT);
6961 setsignal(SIGTERM);
6962 }
6963 return pid;
6964 }
Eric Andersen62483552001-07-10 06:09:16 +00006965#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006966 if (rootshell && mode != FORK_NOJOB && mflag) {
6967 if (jp == NULL || jp->nprocs == 0)
6968 pgrp = pid;
6969 else
6970 pgrp = jp->ps[0].pid;
6971 setpgid(pid, pgrp);
6972 }
Eric Andersen62483552001-07-10 06:09:16 +00006973#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006974 if (mode == FORK_BG)
Eric Andersen2870d962001-07-02 17:27:21 +00006975 backgndpid = pid; /* set $! */
Eric Andersencb57d552001-06-28 07:25:16 +00006976 if (jp) {
6977 struct procstat *ps = &jp->ps[jp->nprocs++];
6978 ps->pid = pid;
6979 ps->status = -1;
6980 ps->cmd = nullstr;
6981 if (iflag && rootshell && n)
6982 ps->cmd = commandtext(n);
6983 }
6984 INTON;
6985 TRACE(("In parent shell: child = %d\n", pid));
6986 return pid;
6987}
6988
6989
6990
6991/*
6992 * Wait for job to finish.
6993 *
6994 * Under job control we have the problem that while a child process is
6995 * running interrupts generated by the user are sent to the child but not
6996 * to the shell. This means that an infinite loop started by an inter-
6997 * active user may be hard to kill. With job control turned off, an
6998 * interactive user may place an interactive program inside a loop. If
6999 * the interactive program catches interrupts, the user doesn't want
7000 * these interrupts to also abort the loop. The approach we take here
7001 * is to have the shell ignore interrupt signals while waiting for a
7002 * forground process to terminate, and then send itself an interrupt
7003 * signal if the child process was terminated by an interrupt signal.
7004 * Unfortunately, some programs want to do a bit of cleanup and then
7005 * exit on interrupt; unless these processes terminate themselves by
7006 * sending a signal to themselves (instead of calling exit) they will
7007 * confuse this approach.
7008 */
7009
7010static int
Eric Andersen62483552001-07-10 06:09:16 +00007011waitforjob(struct job *jp)
7012{
Eric Andersen2870d962001-07-02 17:27:21 +00007013#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007014 int mypgrp = getpgrp();
7015#endif
7016 int status;
7017 int st;
7018 struct sigaction act, oact;
7019
7020 INTOFF;
7021 intreceived = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00007022#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007023 if (!jobctl) {
7024#else
7025 if (!iflag) {
7026#endif
7027 sigaction(SIGINT, 0, &act);
7028 act.sa_handler = waitonint;
7029 sigaction(SIGINT, &act, &oact);
7030 }
7031 TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
7032 while (jp->state == 0) {
7033 dowait(1, jp);
7034 }
Eric Andersen2870d962001-07-02 17:27:21 +00007035#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007036 if (!jobctl) {
7037#else
7038 if (!iflag) {
7039#endif
7040 sigaction(SIGINT, &oact, 0);
7041 if (intreceived && trap[SIGINT]) kill(getpid(), SIGINT);
7042 }
Eric Andersen2870d962001-07-02 17:27:21 +00007043#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007044 if (jp->jobctl) {
7045#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00007046 if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007047 error("TIOCSPGRP failed, errno=%d\n", errno);
7048#else
Eric Andersen3102ac42001-07-06 04:26:23 +00007049 if (tcsetpgrp(2, mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007050 error("tcsetpgrp failed, errno=%d\n", errno);
7051#endif
7052 }
7053 if (jp->state == JOBSTOPPED)
7054 curjob = jp - jobtab + 1;
7055#endif
7056 status = jp->ps[jp->nprocs - 1].status;
7057 /* convert to 8 bits */
7058 if (WIFEXITED(status))
7059 st = WEXITSTATUS(status);
Eric Andersen2870d962001-07-02 17:27:21 +00007060#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007061 else if (WIFSTOPPED(status))
7062 st = WSTOPSIG(status) + 128;
7063#endif
7064 else
7065 st = WTERMSIG(status) + 128;
Eric Andersen2870d962001-07-02 17:27:21 +00007066#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007067 if (jp->jobctl) {
7068 /*
7069 * This is truly gross.
7070 * If we're doing job control, then we did a TIOCSPGRP which
7071 * caused us (the shell) to no longer be in the controlling
7072 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7073 * intuit from the subprocess exit status whether a SIGINT
7074 * occured, and if so interrupt ourselves. Yuck. - mycroft
7075 */
7076 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
7077 raise(SIGINT);
7078 }
Eric Andersen2870d962001-07-02 17:27:21 +00007079 if (jp->state == JOBDONE)
7080
Eric Andersencb57d552001-06-28 07:25:16 +00007081#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007082 freejob(jp);
7083 INTON;
7084 return st;
7085}
7086
7087
7088
7089/*
7090 * Wait for a process to terminate.
7091 */
7092
Eric Andersen62483552001-07-10 06:09:16 +00007093/*
7094 * Do a wait system call. If job control is compiled in, we accept
7095 * stopped processes. If block is zero, we return a value of zero
7096 * rather than blocking.
7097 *
7098 * System V doesn't have a non-blocking wait system call. It does
7099 * have a SIGCLD signal that is sent to a process when one of it's
7100 * children dies. The obvious way to use SIGCLD would be to install
7101 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7102 * was received, and have waitproc bump another counter when it got
7103 * the status of a process. Waitproc would then know that a wait
7104 * system call would not block if the two counters were different.
7105 * This approach doesn't work because if a process has children that
7106 * have not been waited for, System V will send it a SIGCLD when it
7107 * installs a signal handler for SIGCLD. What this means is that when
7108 * a child exits, the shell will be sent SIGCLD signals continuously
7109 * until is runs out of stack space, unless it does a wait call before
7110 * restoring the signal handler. The code below takes advantage of
7111 * this (mis)feature by installing a signal handler for SIGCLD and
7112 * then checking to see whether it was called. If there are any
7113 * children to be waited for, it will be.
7114 *
7115 */
7116
7117static inline int
7118waitproc(int block, int *status)
7119{
7120 int flags;
7121
7122 flags = 0;
7123#ifdef JOBS
7124 if (jobctl)
7125 flags |= WUNTRACED;
7126#endif
7127 if (block == 0)
7128 flags |= WNOHANG;
7129 return wait3(status, flags, (struct rusage *)NULL);
7130}
7131
Eric Andersencb57d552001-06-28 07:25:16 +00007132static int
Eric Andersen62483552001-07-10 06:09:16 +00007133dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00007134{
7135 int pid;
7136 int status;
7137 struct procstat *sp;
7138 struct job *jp;
7139 struct job *thisjob;
7140 int done;
7141 int stopped;
7142 int core;
7143 int sig;
7144
7145 TRACE(("dowait(%d) called\n", block));
7146 do {
7147 pid = waitproc(block, &status);
7148 TRACE(("wait returns %d, status=%d\n", pid, status));
7149 } while (!(block & 2) && pid == -1 && errno == EINTR);
7150 if (pid <= 0)
7151 return pid;
7152 INTOFF;
7153 thisjob = NULL;
7154 for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
7155 if (jp->used) {
7156 done = 1;
7157 stopped = 1;
7158 for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
7159 if (sp->pid == -1)
7160 continue;
7161 if (sp->pid == pid) {
7162 TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
7163 sp->status = status;
7164 thisjob = jp;
7165 }
7166 if (sp->status == -1)
7167 stopped = 0;
7168 else if (WIFSTOPPED(sp->status))
7169 done = 0;
7170 }
Eric Andersen2870d962001-07-02 17:27:21 +00007171 if (stopped) { /* stopped or done */
Eric Andersencb57d552001-06-28 07:25:16 +00007172 int state = done? JOBDONE : JOBSTOPPED;
7173 if (jp->state != state) {
7174 TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
7175 jp->state = state;
Eric Andersen2870d962001-07-02 17:27:21 +00007176#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007177 if (done && curjob == jp - jobtab + 1)
Eric Andersen2870d962001-07-02 17:27:21 +00007178 curjob = 0; /* no current job */
Eric Andersencb57d552001-06-28 07:25:16 +00007179#endif
7180 }
7181 }
7182 }
7183 }
7184 INTON;
7185 if (! rootshell || ! iflag || (job && thisjob == job)) {
7186 core = WCOREDUMP(status);
Eric Andersen2870d962001-07-02 17:27:21 +00007187#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007188 if (WIFSTOPPED(status)) sig = WSTOPSIG(status);
7189 else
7190#endif
7191 if (WIFEXITED(status)) sig = 0;
7192 else sig = WTERMSIG(status);
7193
7194 if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
7195 if (thisjob != job)
Eric Andersen3102ac42001-07-06 04:26:23 +00007196 out2fmt("%d: ", pid);
Eric Andersen2870d962001-07-02 17:27:21 +00007197#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007198 if (sig == SIGTSTP && rootshell && iflag)
Eric Andersen3102ac42001-07-06 04:26:23 +00007199 out2fmt("%%%ld ",
Eric Andersencb57d552001-06-28 07:25:16 +00007200 (long)(job - jobtab + 1));
7201#endif
7202 if (sig < NSIG && sys_siglist[sig])
7203 out2str(sys_siglist[sig]);
7204 else
Eric Andersen3102ac42001-07-06 04:26:23 +00007205 out2fmt("Signal %d", sig);
Eric Andersencb57d552001-06-28 07:25:16 +00007206 if (core)
7207 out2str(" - core dumped");
7208 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00007209 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00007210 TRACE(("Not printing status: status=%d, sig=%d\n",
Eric Andersencb57d552001-06-28 07:25:16 +00007211 status, sig));
7212 }
7213 } else {
7214 TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
7215 if (thisjob)
7216 thisjob->changed = 1;
7217 }
7218 return pid;
7219}
7220
7221
7222
Eric Andersencb57d552001-06-28 07:25:16 +00007223
7224/*
7225 * return 1 if there are stopped jobs, otherwise 0
7226 */
Eric Andersencb57d552001-06-28 07:25:16 +00007227static int
Eric Andersen2870d962001-07-02 17:27:21 +00007228stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007229{
7230 int jobno;
7231 struct job *jp;
7232
7233 if (job_warning)
7234 return (0);
7235 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
7236 if (jp->used == 0)
7237 continue;
7238 if (jp->state == JOBSTOPPED) {
7239 out2str("You have stopped jobs.\n");
7240 job_warning = 2;
7241 return (1);
7242 }
7243 }
7244
7245 return (0);
7246}
7247
7248/*
7249 * Return a string identifying a command (to be printed by the
7250 * jobs command.
7251 */
7252
7253static char *cmdnextc;
7254static int cmdnleft;
Eric Andersen2870d962001-07-02 17:27:21 +00007255#define MAXCMDTEXT 200
Eric Andersencb57d552001-06-28 07:25:16 +00007256
Eric Andersen2870d962001-07-02 17:27:21 +00007257static void
7258cmdputs(const char *s)
7259{
7260 const char *p;
7261 char *q;
7262 char c;
7263 int subtype = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007264
Eric Andersen2870d962001-07-02 17:27:21 +00007265 if (cmdnleft <= 0)
7266 return;
7267 p = s;
7268 q = cmdnextc;
7269 while ((c = *p++) != '\0') {
7270 if (c == CTLESC)
7271 *q++ = *p++;
7272 else if (c == CTLVAR) {
7273 *q++ = '$';
7274 if (--cmdnleft > 0)
7275 *q++ = '{';
7276 subtype = *p++;
7277 } else if (c == '=' && subtype != 0) {
7278 *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
7279 subtype = 0;
7280 } else if (c == CTLENDVAR) {
7281 *q++ = '}';
7282 } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
7283 cmdnleft++; /* ignore it */
7284 else
7285 *q++ = c;
7286 if (--cmdnleft <= 0) {
7287 *q++ = '.';
7288 *q++ = '.';
7289 *q++ = '.';
7290 break;
7291 }
7292 }
7293 cmdnextc = q;
Eric Andersencb57d552001-06-28 07:25:16 +00007294}
7295
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007296//#define CMDTXT_TABLE
7297#ifdef CMDTXT_TABLE
7298/*
7299 * To collect a lot of redundant code in cmdtxt() case statements, we
7300 * implement a mini language here. Each type of node struct has an
7301 * associated instruction sequence that operates on its members via
7302 * their offsets. The instruction are pack in unsigned chars with
7303 * format IIDDDDDE where the bits are
7304 * I : part of the instruction opcode, which are
7305 * 00 : member is a pointer to another node -- process it recursively
7306 * 40 : member is a pointer to a char string -- output it
7307 * 80 : output the string whose index is stored in the data field
7308 * CC : flag signaling that this case needs external processing
7309 * D : data - either the (shifted) index of a fixed string to output or
7310 * the actual offset of the member to operate on in the struct
7311 * (since we assume bit 0 is set, the offset is not shifted)
7312 * E : flag signaling end of instruction sequence
7313 *
7314 * WARNING: In order to handle larger offsets for 64bit archs, this code
7315 * assumes that no offset can be an odd number and stores the
7316 * end-of-instructions flag in bit 0.
7317 */
Eric Andersencb57d552001-06-28 07:25:16 +00007318
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007319#define CMDTXT_NOMORE 0x01 /* NOTE: no offset should be odd */
7320#define CMDTXT_CHARPTR 0x40
7321#define CMDTXT_STRING 0x80
7322#define CMDTXT_SPECIAL 0xC0
7323#define CMDTXT_OFFSETMASK 0x3E
7324
7325static const char * const cmdtxt_strings[] = {
7326 /* 0 1 2 3 4 5 6 7 */
7327 "; ", "(", ")", " && ", " || ", "if ", "; then ", "...",
7328 /* 8 9 10 11 12 13 */
7329 "while ", "; do ", "; done", "until ", "for ", " in ...",
7330 /* 14 15 16 17 */
7331 "case ", "???", "() ...", "<<..."
7332};
7333
7334static const char * const redir_strings[] = {
7335 ">", "<", "<>", ">>", ">|", ">&", "<&"
7336};
7337
7338static const unsigned char cmdtxt_ops[] = {
7339#define CMDTXT_NSEMI 0
7340 offsetof(union node, nbinary.ch1),
7341 0|CMDTXT_STRING,
7342 offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7343#define CMDTXT_NCMD (CMDTXT_NSEMI + 3)
7344#define CMDTXT_NPIPE (CMDTXT_NCMD)
7345#define CMDTXT_NCASE (CMDTXT_NCMD)
7346#define CMDTXT_NTO (CMDTXT_NCMD)
7347#define CMDTXT_NFROM (CMDTXT_NCMD)
7348#define CMDTXT_NFROMTO (CMDTXT_NCMD)
7349#define CMDTXT_NAPPEND (CMDTXT_NCMD)
7350#define CMDTXT_NTOOV (CMDTXT_NCMD)
7351#define CMDTXT_NTOFD (CMDTXT_NCMD)
7352#define CMDTXT_NFROMFD (CMDTXT_NCMD)
7353 CMDTXT_SPECIAL,
7354#define CMDTXT_NREDIR (CMDTXT_NPIPE + 1)
7355#define CMDTXT_NBACKGND (CMDTXT_NREDIR)
7356 offsetof(union node, nredir.n)|CMDTXT_NOMORE,
7357#define CMDTXT_NSUBSHELL (CMDTXT_NBACKGND + 1)
7358 (1*2)|CMDTXT_STRING,
7359 offsetof(union node, nredir.n),
7360 (2*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7361#define CMDTXT_NAND (CMDTXT_NSUBSHELL + 3)
7362 offsetof(union node, nbinary.ch1),
7363 (3*2)|CMDTXT_STRING,
7364 offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7365#define CMDTXT_NOR (CMDTXT_NAND + 3)
7366 offsetof(union node, nbinary.ch1),
7367 (4*2)|CMDTXT_STRING,
7368 offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7369#define CMDTXT_NIF (CMDTXT_NOR + 3)
7370 (5*2)|CMDTXT_STRING,
7371 offsetof(union node, nif.test),
7372 (6*2)|CMDTXT_STRING,
7373 offsetof(union node, nif.ifpart),
7374 (7*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7375#define CMDTXT_NWHILE (CMDTXT_NIF + 5)
7376 (8*2)|CMDTXT_STRING,
7377 offsetof(union node, nbinary.ch1),
7378 (9*2)|CMDTXT_STRING,
7379 offsetof(union node, nbinary.ch2),
7380 (10*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7381#define CMDTXT_NUNTIL (CMDTXT_NWHILE + 5)
7382 (11*2)|CMDTXT_STRING,
7383 offsetof(union node, nbinary.ch1),
7384 (9*2)|CMDTXT_STRING,
7385 offsetof(union node, nbinary.ch2),
7386 (10*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7387#define CMDTXT_NFOR (CMDTXT_NUNTIL + 5)
7388 (12*2)|CMDTXT_STRING,
7389 offsetof(union node, nfor.var)|CMDTXT_CHARPTR,
7390 (13*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7391#define CMDTXT_NCLIST (CMDTXT_NFOR + 3) /* TODO: IS THIS CORRECT??? */
7392#define CMDTXT_NNOT (CMDTXT_NCLIST) /* TODO: IS THIS CORRECT??? */
7393 (15*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7394#define CMDTXT_NDEFUN (CMDTXT_NCLIST + 1)
7395 offsetof(union node, narg.text)|CMDTXT_CHARPTR,
7396 (16*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7397#define CMDTXT_NARG (CMDTXT_NDEFUN + 2)
7398 offsetof(union node, narg.text)|CMDTXT_CHARPTR|CMDTXT_NOMORE,
7399#define CMDTXT_NHERE (CMDTXT_NARG + 1)
7400#define CMDTXT_NXHERE (CMDTXT_NHERE)
7401 (17*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7402};
7403
7404#if CMDTXT_NXHERE != 36
7405#error CMDTXT_NXHERE
7406#endif
7407
7408static const unsigned char cmdtxt_ops_index[26] = {
7409 CMDTXT_NSEMI,
7410 CMDTXT_NCMD,
7411 CMDTXT_NPIPE,
7412 CMDTXT_NREDIR,
7413 CMDTXT_NBACKGND,
7414 CMDTXT_NSUBSHELL,
7415 CMDTXT_NAND,
7416 CMDTXT_NOR,
7417 CMDTXT_NIF,
7418 CMDTXT_NWHILE,
7419 CMDTXT_NUNTIL,
7420 CMDTXT_NFOR,
7421 CMDTXT_NCASE,
7422 CMDTXT_NCLIST,
7423 CMDTXT_NDEFUN,
7424 CMDTXT_NARG,
7425 CMDTXT_NTO,
7426 CMDTXT_NFROM,
7427 CMDTXT_NFROMTO,
7428 CMDTXT_NAPPEND,
7429 CMDTXT_NTOOV,
7430 CMDTXT_NTOFD,
7431 CMDTXT_NFROMFD,
7432 CMDTXT_NHERE,
7433 CMDTXT_NXHERE,
7434 CMDTXT_NNOT,
7435};
7436
7437static void
7438cmdtxt(const union node *n)
7439{
7440 const char *p;
7441
7442 if (n == NULL)
7443 return;
7444
7445 p = cmdtxt_ops + (int) cmdtxt_ops_index[n->type];
7446 if ((*p & CMDTXT_SPECIAL) != CMDTXT_SPECIAL) { /* normal case */
7447 do {
7448 if (*p & CMDTXT_STRING) { /* output fixed string */
7449 cmdputs(cmdtxt_strings[((int)(*p & CMDTXT_OFFSETMASK) >> 1)]);
Manuel Novoa III c639a352001-08-12 17:32:56 +00007450 } else {
7451 const char *pf = ((const char *) n)
7452 + ((int)(*p & CMDTXT_OFFSETMASK));
7453 if (*p & CMDTXT_CHARPTR) { /* output dynamic string */
7454 cmdputs(*((const char **) pf));
7455 } else { /* output field */
7456 cmdtxt(*((const union node **) pf));
7457 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007458 }
7459 } while (!(*p++ & CMDTXT_NOMORE));
7460 } else if (n->type == NCMD) {
7461 union node *np;
7462 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7463 cmdtxt(np);
7464 if (np->narg.next)
7465 cmdputs(spcstr);
7466 }
7467 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7468 cmdputs(spcstr);
7469 cmdtxt(np);
7470 }
7471 } else if (n->type == NPIPE) {
7472 struct nodelist *lp;
7473 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7474 cmdtxt(lp->n);
7475 if (lp->next)
7476 cmdputs(" | ");
7477 }
7478 } else if (n->type == NCASE) {
7479 cmdputs(cmdtxt_strings[14]);
7480 cmdputs(n->ncase.expr->narg.text);
7481 cmdputs(cmdtxt_strings[13]);
7482 } else {
7483#if (NTO != 16) || (NFROM != 17) || (NFROMTO != 18) || (NAPPEND != 19) || (NTOOV != 20) || (NTOFD != 21) || (NFROMFD != 22)
7484#error Assumption violated regarding range and ordering of NTO ... NFROMFD!
7485#endif
7486 char s[2];
7487
7488#ifdef DEBUG
7489 assert((n->type >= NTO) && (n->type <= NFROMFD));
7490#endif
7491
7492 p = redir_strings[n->type - NTO];
7493 if (n->nfile.fd != ('>' == *p)) {
7494 s[0] = n->nfile.fd + '0';
7495 s[1] = '\0';
7496 cmdputs(s);
7497 }
7498 cmdputs(p);
7499 if (n->type >= NTOFD) {
7500 s[0] = n->ndup.dupfd + '0';
7501 s[1] = '\0';
7502 cmdputs(s);
7503 } else {
7504 cmdtxt(n->nfile.fname);
7505 }
7506 }
7507}
7508#else /* CMDTXT_TABLE */
Eric Andersencb57d552001-06-28 07:25:16 +00007509static void
Eric Andersen2870d962001-07-02 17:27:21 +00007510cmdtxt(const union node *n)
7511{
Eric Andersencb57d552001-06-28 07:25:16 +00007512 union node *np;
7513 struct nodelist *lp;
7514 const char *p;
7515 int i;
7516 char s[2];
7517
7518 if (n == NULL)
7519 return;
7520 switch (n->type) {
7521 case NSEMI:
7522 cmdtxt(n->nbinary.ch1);
7523 cmdputs("; ");
7524 cmdtxt(n->nbinary.ch2);
7525 break;
7526 case NAND:
7527 cmdtxt(n->nbinary.ch1);
7528 cmdputs(" && ");
7529 cmdtxt(n->nbinary.ch2);
7530 break;
7531 case NOR:
7532 cmdtxt(n->nbinary.ch1);
7533 cmdputs(" || ");
7534 cmdtxt(n->nbinary.ch2);
7535 break;
7536 case NPIPE:
7537 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7538 cmdtxt(lp->n);
7539 if (lp->next)
7540 cmdputs(" | ");
7541 }
7542 break;
7543 case NSUBSHELL:
7544 cmdputs("(");
7545 cmdtxt(n->nredir.n);
7546 cmdputs(")");
7547 break;
7548 case NREDIR:
7549 case NBACKGND:
7550 cmdtxt(n->nredir.n);
7551 break;
7552 case NIF:
7553 cmdputs("if ");
7554 cmdtxt(n->nif.test);
7555 cmdputs("; then ");
7556 cmdtxt(n->nif.ifpart);
7557 cmdputs("...");
7558 break;
7559 case NWHILE:
7560 cmdputs("while ");
7561 goto until;
7562 case NUNTIL:
7563 cmdputs("until ");
7564until:
7565 cmdtxt(n->nbinary.ch1);
7566 cmdputs("; do ");
7567 cmdtxt(n->nbinary.ch2);
7568 cmdputs("; done");
7569 break;
7570 case NFOR:
7571 cmdputs("for ");
7572 cmdputs(n->nfor.var);
7573 cmdputs(" in ...");
7574 break;
7575 case NCASE:
7576 cmdputs("case ");
7577 cmdputs(n->ncase.expr->narg.text);
7578 cmdputs(" in ...");
7579 break;
7580 case NDEFUN:
7581 cmdputs(n->narg.text);
7582 cmdputs("() ...");
7583 break;
7584 case NCMD:
7585 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7586 cmdtxt(np);
7587 if (np->narg.next)
7588 cmdputs(spcstr);
7589 }
7590 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7591 cmdputs(spcstr);
7592 cmdtxt(np);
7593 }
7594 break;
7595 case NARG:
7596 cmdputs(n->narg.text);
7597 break;
7598 case NTO:
7599 p = ">"; i = 1; goto redir;
7600 case NAPPEND:
7601 p = ">>"; i = 1; goto redir;
7602 case NTOFD:
7603 p = ">&"; i = 1; goto redir;
7604 case NTOOV:
7605 p = ">|"; i = 1; goto redir;
7606 case NFROM:
7607 p = "<"; i = 0; goto redir;
7608 case NFROMFD:
7609 p = "<&"; i = 0; goto redir;
7610 case NFROMTO:
7611 p = "<>"; i = 0; goto redir;
7612redir:
7613 if (n->nfile.fd != i) {
7614 s[0] = n->nfile.fd + '0';
7615 s[1] = '\0';
7616 cmdputs(s);
7617 }
7618 cmdputs(p);
7619 if (n->type == NTOFD || n->type == NFROMFD) {
7620 s[0] = n->ndup.dupfd + '0';
7621 s[1] = '\0';
7622 cmdputs(s);
7623 } else {
7624 cmdtxt(n->nfile.fname);
7625 }
7626 break;
7627 case NHERE:
7628 case NXHERE:
7629 cmdputs("<<...");
7630 break;
7631 default:
7632 cmdputs("???");
7633 break;
7634 }
7635}
Manuel Novoa III c639a352001-08-12 17:32:56 +00007636#endif /* CMDTXT_TABLE */
Eric Andersencb57d552001-06-28 07:25:16 +00007637
Eric Andersen2870d962001-07-02 17:27:21 +00007638static char *
7639commandtext(const union node *n)
7640{
7641 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007642
Eric Andersen2870d962001-07-02 17:27:21 +00007643 cmdnextc = name = ckmalloc(MAXCMDTEXT);
7644 cmdnleft = MAXCMDTEXT - 4;
7645 cmdtxt(n);
7646 *cmdnextc = '\0';
7647 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00007648}
7649
Eric Andersen2870d962001-07-02 17:27:21 +00007650
Eric Andersencb57d552001-06-28 07:25:16 +00007651static void waitonint(int sig) {
7652 intreceived = 1;
7653 return;
7654}
Eric Andersencb57d552001-06-28 07:25:16 +00007655/*
7656 * Routines to check for mail. (Perhaps make part of main.c?)
7657 */
7658
7659
7660#define MAXMBOXES 10
7661
7662
Eric Andersen2870d962001-07-02 17:27:21 +00007663static int nmboxes; /* number of mailboxes */
7664static time_t mailtime[MAXMBOXES]; /* times of mailboxes */
Eric Andersencb57d552001-06-28 07:25:16 +00007665
7666
7667
7668/*
7669 * Print appropriate message(s) if mail has arrived. If the argument is
7670 * nozero, then the value of MAIL has changed, so we just update the
7671 * values.
7672 */
7673
7674static void
Eric Andersen2870d962001-07-02 17:27:21 +00007675chkmail(int silent)
Eric Andersencb57d552001-06-28 07:25:16 +00007676{
7677 int i;
7678 const char *mpath;
7679 char *p;
7680 char *q;
7681 struct stackmark smark;
7682 struct stat statb;
7683
7684 if (silent)
7685 nmboxes = 10;
7686 if (nmboxes == 0)
7687 return;
7688 setstackmark(&smark);
7689 mpath = mpathset()? mpathval() : mailval();
7690 for (i = 0 ; i < nmboxes ; i++) {
7691 p = padvance(&mpath, nullstr);
7692 if (p == NULL)
7693 break;
7694 if (*p == '\0')
7695 continue;
7696 for (q = p ; *q ; q++);
7697#ifdef DEBUG
7698 if (q[-1] != '/')
7699 abort();
7700#endif
Eric Andersen2870d962001-07-02 17:27:21 +00007701 q[-1] = '\0'; /* delete trailing '/' */
Eric Andersencb57d552001-06-28 07:25:16 +00007702 if (stat(p, &statb) < 0)
7703 statb.st_size = 0;
7704 if (statb.st_size > mailtime[i] && ! silent) {
Eric Andersen3102ac42001-07-06 04:26:23 +00007705 out2fmt(snlfmt,
7706 pathopt? pathopt : "you have mail");
Eric Andersencb57d552001-06-28 07:25:16 +00007707 }
7708 mailtime[i] = statb.st_size;
Eric Andersencb57d552001-06-28 07:25:16 +00007709 }
7710 nmboxes = i;
7711 popstackmark(&smark);
7712}
Eric Andersencb57d552001-06-28 07:25:16 +00007713
7714#define PROFILE 0
7715
Eric Andersencb57d552001-06-28 07:25:16 +00007716#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007717static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007718extern int etext();
7719#endif
7720
Eric Andersen2870d962001-07-02 17:27:21 +00007721static void read_profile (const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007722static void cmdloop (int);
7723static void options (int);
Eric Andersen2870d962001-07-02 17:27:21 +00007724static void setoption (int, int);
7725static void procargs (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00007726
Eric Andersen2870d962001-07-02 17:27:21 +00007727
Eric Andersencb57d552001-06-28 07:25:16 +00007728/*
7729 * Main routine. We initialize things, parse the arguments, execute
7730 * profiles if we're a login shell, and then call cmdloop to execute
7731 * commands. The setjmp call sets up the location to jump to when an
7732 * exception occurs. When an exception occurs the variable "state"
7733 * is used to figure out how far we had gotten.
7734 */
7735
7736int
Matt Kraai2d91deb2001-08-01 17:21:35 +00007737ash_main(argc, argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007738 int argc;
7739 char **argv;
7740{
7741 struct jmploc jmploc;
7742 struct stackmark smark;
7743 volatile int state;
Eric Andersen62483552001-07-10 06:09:16 +00007744 const char *shinit;
Eric Andersencb57d552001-06-28 07:25:16 +00007745
Eric Andersencb57d552001-06-28 07:25:16 +00007746 BLTINCMD = find_builtin("builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00007747 EXECCMD = find_builtin("exec");
7748 EVALCMD = find_builtin("eval");
7749
Eric Andersen1c039232001-07-07 00:05:55 +00007750#ifndef BB_FEATURE_SH_FANCY_PROMPT
7751 unsetenv("PS1");
7752 unsetenv("PS2");
7753#endif
7754
Eric Andersencb57d552001-06-28 07:25:16 +00007755#if PROFILE
7756 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7757#endif
7758#if defined(linux) || defined(__GNU__)
7759 signal(SIGCHLD, SIG_DFL);
7760#endif
7761 state = 0;
7762 if (setjmp(jmploc.loc)) {
7763 INTOFF;
7764 /*
7765 * When a shell procedure is executed, we raise the
7766 * exception EXSHELLPROC to clean up before executing
7767 * the shell procedure.
7768 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007769 if (exception == EXSHELLPROC) {
Eric Andersencb57d552001-06-28 07:25:16 +00007770 rootpid = getpid();
7771 rootshell = 1;
7772 minusc = NULL;
7773 state = 3;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007774 } else {
7775 if (exception == EXEXEC) {
7776 exitstatus = exerrno;
7777 } else if (exception == EXERROR) {
7778 exitstatus = 2;
7779 }
Eric Andersencb57d552001-06-28 07:25:16 +00007780 if (state == 0 || iflag == 0 || ! rootshell)
7781 exitshell(exitstatus);
7782 }
7783 reset();
Eric Andersen2870d962001-07-02 17:27:21 +00007784 if (exception == EXINT) {
Eric Andersencb57d552001-06-28 07:25:16 +00007785 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00007786 }
7787 popstackmark(&smark);
Eric Andersen2870d962001-07-02 17:27:21 +00007788 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007789 if (state == 1)
7790 goto state1;
7791 else if (state == 2)
7792 goto state2;
7793 else if (state == 3)
7794 goto state3;
7795 else
7796 goto state4;
7797 }
7798 handler = &jmploc;
7799#ifdef DEBUG
7800 opentrace();
7801 trputs("Shell args: "); trargs(argv);
7802#endif
7803 rootpid = getpid();
7804 rootshell = 1;
7805 init();
7806 setstackmark(&smark);
7807 procargs(argc, argv);
7808 if (argv[0] && argv[0][0] == '-') {
7809 state = 1;
7810 read_profile("/etc/profile");
7811state1:
7812 state = 2;
7813 read_profile(".profile");
7814 }
7815state2:
7816 state = 3;
7817#ifndef linux
7818 if (getuid() == geteuid() && getgid() == getegid()) {
7819#endif
7820 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7821 state = 3;
7822 read_profile(shinit);
7823 }
7824#ifndef linux
7825 }
7826#endif
7827state3:
7828 state = 4;
7829 if (sflag == 0 || minusc) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007830 static const char sigs[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00007831 SIGINT, SIGQUIT, SIGHUP,
Eric Andersencb57d552001-06-28 07:25:16 +00007832#ifdef SIGTSTP
7833 SIGTSTP,
7834#endif
7835 SIGPIPE
7836 };
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007837#define SIGSSIZE ((sizeof(sigs)/sizeof(sigs[0])) - 1) /* trailing nul */
Eric Andersencb57d552001-06-28 07:25:16 +00007838 int i;
7839
7840 for (i = 0; i < SIGSSIZE; i++)
7841 setsignal(sigs[i]);
7842 }
7843
7844 if (minusc)
7845 evalstring(minusc, 0);
7846
7847 if (sflag || minusc == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00007848state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007849 cmdloop(1);
7850 }
7851#if PROFILE
7852 monitor(0);
7853#endif
7854 exitshell(exitstatus);
7855 /* NOTREACHED */
7856}
7857
7858
7859/*
7860 * Read and execute commands. "Top" is nonzero for the top level command
7861 * loop; it turns on prompting if the shell is interactive.
7862 */
7863
7864static void
Eric Andersen2870d962001-07-02 17:27:21 +00007865cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00007866{
7867 union node *n;
7868 struct stackmark smark;
7869 int inter;
7870 int numeof = 0;
7871
7872 TRACE(("cmdloop(%d) called\n", top));
7873 setstackmark(&smark);
7874 for (;;) {
7875 if (pendingsigs)
7876 dotrap();
7877 inter = 0;
7878 if (iflag && top) {
7879 inter++;
7880 showjobs(1);
7881 chkmail(0);
Eric Andersen3102ac42001-07-06 04:26:23 +00007882 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00007883 }
7884 n = parsecmd(inter);
7885 /* showtree(n); DEBUG */
7886 if (n == NEOF) {
7887 if (!top || numeof >= 50)
7888 break;
7889 if (!stoppedjobs()) {
7890 if (!Iflag)
7891 break;
7892 out2str("\nUse \"exit\" to leave shell.\n");
7893 }
7894 numeof++;
7895 } else if (n != NULL && nflag == 0) {
7896 job_warning = (job_warning == 2) ? 1 : 0;
7897 numeof = 0;
7898 evaltree(n, 0);
7899 }
7900 popstackmark(&smark);
7901 setstackmark(&smark);
7902 if (evalskip == SKIPFILE) {
7903 evalskip = 0;
7904 break;
7905 }
7906 }
7907 popstackmark(&smark);
7908}
7909
7910
7911
7912/*
7913 * Read /etc/profile or .profile. Return on error.
7914 */
7915
7916static void
7917read_profile(name)
7918 const char *name;
7919{
7920 int fd;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007921 int xflag_save;
7922 int vflag_save;
Eric Andersencb57d552001-06-28 07:25:16 +00007923
7924 INTOFF;
7925 if ((fd = open(name, O_RDONLY)) >= 0)
7926 setinputfd(fd, 1);
7927 INTON;
7928 if (fd < 0)
7929 return;
7930 /* -q turns off -x and -v just when executing init files */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007931 /* Note: Might do a little redundant work, but reduces code size. */
7932 xflag_save = xflag;
7933 vflag_save = vflag;
Eric Andersencb57d552001-06-28 07:25:16 +00007934 if (qflag) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007935 vflag = xflag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007936 }
7937 cmdloop(0);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007938 xflag = xflag_save;
7939 vflag = vflag_save;
Eric Andersencb57d552001-06-28 07:25:16 +00007940 popfile();
7941}
7942
7943
7944
7945/*
7946 * Read a file containing shell functions.
7947 */
7948
7949static void
Eric Andersen2870d962001-07-02 17:27:21 +00007950readcmdfile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00007951{
7952 int fd;
7953
7954 INTOFF;
7955 if ((fd = open(name, O_RDONLY)) >= 0)
7956 setinputfd(fd, 1);
7957 else
7958 error("Can't open %s", name);
7959 INTON;
7960 cmdloop(0);
7961 popfile();
7962}
7963
7964
7965
7966/*
7967 * Take commands from a file. To be compatable we should do a path
7968 * search for the file, which is necessary to find sub-commands.
7969 */
7970
7971
Eric Andersen62483552001-07-10 06:09:16 +00007972static inline char *
Eric Andersencb57d552001-06-28 07:25:16 +00007973find_dot_file(mybasename)
7974 char *mybasename;
7975{
7976 char *fullname;
7977 const char *path = pathval();
7978 struct stat statb;
7979
7980 /* don't try this for absolute or relative paths */
7981 if (strchr(mybasename, '/'))
7982 return mybasename;
7983
7984 while ((fullname = padvance(&path, mybasename)) != NULL) {
7985 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
7986 /*
7987 * Don't bother freeing here, since it will
7988 * be freed by the caller.
7989 */
7990 return fullname;
7991 }
7992 stunalloc(fullname);
7993 }
7994
7995 /* not found in the PATH */
7996 error("%s: not found", mybasename);
7997 /* NOTREACHED */
7998}
7999
8000static int
8001dotcmd(argc, argv)
8002 int argc;
8003 char **argv;
8004{
8005 struct strlist *sp;
8006 exitstatus = 0;
8007
8008 for (sp = cmdenviron; sp ; sp = sp->next)
8009 setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
8010
Eric Andersen2870d962001-07-02 17:27:21 +00008011 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00008012 char *fullname;
8013 struct stackmark smark;
8014
8015 setstackmark(&smark);
8016 fullname = find_dot_file(argv[1]);
8017 setinputfile(fullname, 1);
8018 commandname = fullname;
8019 cmdloop(0);
8020 popfile();
8021 popstackmark(&smark);
8022 }
8023 return exitstatus;
8024}
8025
8026
8027static int
8028exitcmd(argc, argv)
8029 int argc;
8030 char **argv;
8031{
8032 if (stoppedjobs())
8033 return 0;
8034 if (argc > 1)
8035 exitstatus = number(argv[1]);
8036 else
8037 exitstatus = oexitstatus;
8038 exitshell(exitstatus);
8039 /* NOTREACHED */
8040}
Eric Andersen62483552001-07-10 06:09:16 +00008041
Eric Andersen2870d962001-07-02 17:27:21 +00008042static pointer
8043stalloc(int nbytes)
Eric Andersencb57d552001-06-28 07:25:16 +00008044{
8045 char *p;
8046
8047 nbytes = ALIGN(nbytes);
8048 if (nbytes > stacknleft) {
8049 int blocksize;
8050 struct stack_block *sp;
8051
8052 blocksize = nbytes;
8053 if (blocksize < MINSIZE)
8054 blocksize = MINSIZE;
8055 INTOFF;
8056 sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
8057 sp->prev = stackp;
8058 stacknxt = sp->space;
8059 stacknleft = blocksize;
8060 stackp = sp;
8061 INTON;
8062 }
8063 p = stacknxt;
8064 stacknxt += nbytes;
8065 stacknleft -= nbytes;
8066 return p;
8067}
8068
8069
8070static void
Eric Andersen2870d962001-07-02 17:27:21 +00008071stunalloc(pointer p)
8072{
Eric Andersencb57d552001-06-28 07:25:16 +00008073#ifdef DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +00008074 if (p == NULL) { /*DEBUG */
Eric Andersencb57d552001-06-28 07:25:16 +00008075 write(2, "stunalloc\n", 10);
8076 abort();
8077 }
8078#endif
8079 if (!(stacknxt >= (char *)p && (char *)p >= stackp->space)) {
8080 p = stackp->space;
8081 }
8082 stacknleft += stacknxt - (char *)p;
8083 stacknxt = p;
8084}
8085
8086
Eric Andersencb57d552001-06-28 07:25:16 +00008087static void
Eric Andersen2870d962001-07-02 17:27:21 +00008088setstackmark(struct stackmark *mark)
8089{
Eric Andersencb57d552001-06-28 07:25:16 +00008090 mark->stackp = stackp;
8091 mark->stacknxt = stacknxt;
8092 mark->stacknleft = stacknleft;
8093 mark->marknext = markp;
8094 markp = mark;
8095}
8096
8097
8098static void
Eric Andersen2870d962001-07-02 17:27:21 +00008099popstackmark(struct stackmark *mark)
8100{
Eric Andersencb57d552001-06-28 07:25:16 +00008101 struct stack_block *sp;
8102
8103 INTOFF;
8104 markp = mark->marknext;
8105 while (stackp != mark->stackp) {
8106 sp = stackp;
8107 stackp = sp->prev;
8108 ckfree(sp);
8109 }
8110 stacknxt = mark->stacknxt;
8111 stacknleft = mark->stacknleft;
8112 INTON;
8113}
8114
8115
8116/*
8117 * When the parser reads in a string, it wants to stick the string on the
8118 * stack and only adjust the stack pointer when it knows how big the
8119 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8120 * of space on top of the stack and stackblocklen returns the length of
8121 * this block. Growstackblock will grow this space by at least one byte,
8122 * possibly moving it (like realloc). Grabstackblock actually allocates the
8123 * part of the block that has been used.
8124 */
8125
8126static void
Eric Andersen2870d962001-07-02 17:27:21 +00008127growstackblock(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00008128 char *p;
8129 int newlen = ALIGN(stacknleft * 2 + 100);
8130 char *oldspace = stacknxt;
8131 int oldlen = stacknleft;
8132 struct stack_block *sp;
8133 struct stack_block *oldstackp;
8134
8135 if (stacknxt == stackp->space && stackp != &stackbase) {
8136 INTOFF;
8137 oldstackp = stackp;
8138 sp = stackp;
8139 stackp = sp->prev;
8140 sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen);
8141 sp->prev = stackp;
8142 stackp = sp;
8143 stacknxt = sp->space;
8144 stacknleft = newlen;
8145 {
8146 /* Stack marks pointing to the start of the old block
Eric Andersen2870d962001-07-02 17:27:21 +00008147 * must be relocated to point to the new block
Eric Andersencb57d552001-06-28 07:25:16 +00008148 */
8149 struct stackmark *xmark;
8150 xmark = markp;
8151 while (xmark != NULL && xmark->stackp == oldstackp) {
8152 xmark->stackp = stackp;
8153 xmark->stacknxt = stacknxt;
8154 xmark->stacknleft = stacknleft;
8155 xmark = xmark->marknext;
8156 }
8157 }
8158 INTON;
8159 } else {
8160 p = stalloc(newlen);
8161 memcpy(p, oldspace, oldlen);
Eric Andersen2870d962001-07-02 17:27:21 +00008162 stacknxt = p; /* free the space */
8163 stacknleft += newlen; /* we just allocated */
Eric Andersencb57d552001-06-28 07:25:16 +00008164 }
8165}
8166
8167
8168
Eric Andersen2870d962001-07-02 17:27:21 +00008169static inline void
8170grabstackblock(int len)
Eric Andersencb57d552001-06-28 07:25:16 +00008171{
8172 len = ALIGN(len);
8173 stacknxt += len;
8174 stacknleft -= len;
8175}
8176
8177
8178
8179/*
8180 * The following routines are somewhat easier to use that the above.
8181 * The user declares a variable of type STACKSTR, which may be declared
8182 * to be a register. The macro STARTSTACKSTR initializes things. Then
8183 * the user uses the macro STPUTC to add characters to the string. In
8184 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8185 * grown as necessary. When the user is done, she can just leave the
8186 * string there and refer to it using stackblock(). Or she can allocate
8187 * the space for it using grabstackstr(). If it is necessary to allow
8188 * someone else to use the stack temporarily and then continue to grow
8189 * the string, the user should use grabstack to allocate the space, and
8190 * then call ungrabstr(p) to return to the previous mode of operation.
8191 *
8192 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8193 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8194 * is space for at least one character.
8195 */
8196
8197
8198static char *
Eric Andersen2870d962001-07-02 17:27:21 +00008199growstackstr(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00008200 int len = stackblocksize();
8201 if (herefd >= 0 && len >= 1024) {
8202 xwrite(herefd, stackblock(), len);
8203 sstrnleft = len - 1;
8204 return stackblock();
8205 }
8206 growstackblock();
8207 sstrnleft = stackblocksize() - len - 1;
8208 return stackblock() + len;
8209}
8210
8211
8212/*
8213 * Called from CHECKSTRSPACE.
8214 */
8215
8216static char *
8217makestrspace(size_t newlen) {
8218 int len = stackblocksize() - sstrnleft;
8219 do {
8220 growstackblock();
8221 sstrnleft = stackblocksize() - len;
8222 } while (sstrnleft < newlen);
8223 return stackblock() + len;
8224}
8225
8226
8227
8228static void
Eric Andersen2870d962001-07-02 17:27:21 +00008229ungrabstackstr(char *s, char *p)
8230{
Eric Andersencb57d552001-06-28 07:25:16 +00008231 stacknleft += stacknxt - s;
8232 stacknxt = s;
8233 sstrnleft = stacknleft - (p - s);
8234}
Eric Andersencb57d552001-06-28 07:25:16 +00008235/*
8236 * Miscelaneous builtins.
8237 */
8238
8239
8240#undef rflag
8241
Eric Andersencb57d552001-06-28 07:25:16 +00008242#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersen62483552001-07-10 06:09:16 +00008243typedef long rlim_t;
Eric Andersencb57d552001-06-28 07:25:16 +00008244#endif
8245
8246
8247
8248/*
8249 * The read builtin. The -e option causes backslashes to escape the
8250 * following character.
8251 *
8252 * This uses unbuffered input, which may be avoidable in some cases.
8253 */
8254
8255static int
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008256readcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008257{
8258 char **ap;
8259 int backslash;
8260 char c;
8261 int rflag;
8262 char *prompt;
8263 const char *ifs;
8264 char *p;
8265 int startword;
8266 int status;
8267 int i;
8268
8269 rflag = 0;
8270 prompt = NULL;
8271 while ((i = nextopt("p:r")) != '\0') {
8272 if (i == 'p')
8273 prompt = optionarg;
8274 else
8275 rflag = 1;
8276 }
8277 if (prompt && isatty(0)) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008278 out2str(prompt); /* read without cmdedit */
Eric Andersencb57d552001-06-28 07:25:16 +00008279 flushall();
8280 }
8281 if (*(ap = argptr) == NULL)
8282 error("arg count");
8283 if ((ifs = bltinlookup("IFS")) == NULL)
8284 ifs = defifs;
8285 status = 0;
8286 startword = 1;
8287 backslash = 0;
8288 STARTSTACKSTR(p);
8289 for (;;) {
8290 if (read(0, &c, 1) != 1) {
8291 status = 1;
8292 break;
8293 }
8294 if (c == '\0')
8295 continue;
8296 if (backslash) {
8297 backslash = 0;
8298 if (c != '\n')
8299 STPUTC(c, p);
8300 continue;
8301 }
8302 if (!rflag && c == '\\') {
8303 backslash++;
8304 continue;
8305 }
8306 if (c == '\n')
8307 break;
8308 if (startword && *ifs == ' ' && strchr(ifs, c)) {
8309 continue;
8310 }
8311 startword = 0;
8312 if (backslash && c == '\\') {
8313 if (read(0, &c, 1) != 1) {
8314 status = 1;
8315 break;
8316 }
8317 STPUTC(c, p);
8318 } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
8319 STACKSTRNUL(p);
8320 setvar(*ap, stackblock(), 0);
8321 ap++;
8322 startword = 1;
8323 STARTSTACKSTR(p);
8324 } else {
8325 STPUTC(c, p);
8326 }
8327 }
8328 STACKSTRNUL(p);
8329 /* Remove trailing blanks */
8330 while (stackblock() <= --p && strchr(ifs, *p) != NULL)
8331 *p = '\0';
8332 setvar(*ap, stackblock(), 0);
8333 while (*++ap != NULL)
8334 setvar(*ap, nullstr, 0);
8335 return status;
8336}
8337
8338
8339
8340static int
8341umaskcmd(argc, argv)
8342 int argc;
8343 char **argv;
8344{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008345 static const char permuser[3] = "ugo";
8346 static const char permmode[3] = "rwx";
8347 static const short int permmask[] = {
8348 S_IRUSR, S_IWUSR, S_IXUSR,
8349 S_IRGRP, S_IWGRP, S_IXGRP,
8350 S_IROTH, S_IWOTH, S_IXOTH
8351 };
8352
Eric Andersencb57d552001-06-28 07:25:16 +00008353 char *ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008354 mode_t mask;
Eric Andersencb57d552001-06-28 07:25:16 +00008355 int i;
8356 int symbolic_mode = 0;
8357
Eric Andersen62483552001-07-10 06:09:16 +00008358 while (nextopt("S") != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00008359 symbolic_mode = 1;
8360 }
8361
8362 INTOFF;
8363 mask = umask(0);
8364 umask(mask);
8365 INTON;
8366
8367 if ((ap = *argptr) == NULL) {
8368 if (symbolic_mode) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008369 char buf[18];
8370 char *p = buf;
8371 for (i=0 ; i<3 ; i++) {
8372 int j;
8373 *p++ = permuser[i];
8374 *p++ = '=';
8375 for (j=0 ; j<3 ; j++) {
8376 if ((mask & permmask[3*i+j]) == 0) {
8377 *p++ = permmode[j];
8378 }
8379 }
8380 *p++ = ',';
8381 }
8382 *--p = 0;
8383 puts(buf);
Eric Andersencb57d552001-06-28 07:25:16 +00008384 } else {
Eric Andersen62483552001-07-10 06:09:16 +00008385 printf("%.4o\n", mask);
Eric Andersencb57d552001-06-28 07:25:16 +00008386 }
8387 } else {
Eric Andersen62483552001-07-10 06:09:16 +00008388 if (is_digit((unsigned char)*ap)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008389 mask = 0;
8390 do {
8391 if (*ap >= '8' || *ap < '0')
8392 error("Illegal number: %s", argv[1]);
8393 mask = (mask << 3) + (*ap - '0');
8394 } while (*++ap != '\0');
8395 umask(mask);
8396 } else {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008397 mask = ~mask & 0777;
8398 if (parse_mode(ap, &mask) == FALSE) {
Eric Andersencb57d552001-06-28 07:25:16 +00008399 error("Illegal mode: %s", ap);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008400 }
Eric Andersencb57d552001-06-28 07:25:16 +00008401 umask(~mask & 0777);
8402 }
8403 }
8404 return 0;
8405}
8406
8407/*
8408 * ulimit builtin
8409 *
8410 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
8411 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
8412 * ash by J.T. Conklin.
8413 *
8414 * Public domain.
8415 */
8416
8417struct limits {
8418 const char *name;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008419 short cmd;
8420 short factor; /* multiply by to get rlim_{cur,max} values */
Eric Andersencb57d552001-06-28 07:25:16 +00008421};
8422
8423static const struct limits limits[] = {
8424#ifdef RLIMIT_CPU
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008425 { "time(seconds)", RLIMIT_CPU, 1 },
Eric Andersencb57d552001-06-28 07:25:16 +00008426#endif
8427#ifdef RLIMIT_FSIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008428 { "file(blocks)", RLIMIT_FSIZE, 512 },
Eric Andersencb57d552001-06-28 07:25:16 +00008429#endif
8430#ifdef RLIMIT_DATA
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008431 { "data(kbytes)", RLIMIT_DATA, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008432#endif
8433#ifdef RLIMIT_STACK
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008434 { "stack(kbytes)", RLIMIT_STACK, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008435#endif
8436#ifdef RLIMIT_CORE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008437 { "coredump(blocks)", RLIMIT_CORE, 512 },
Eric Andersencb57d552001-06-28 07:25:16 +00008438#endif
8439#ifdef RLIMIT_RSS
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008440 { "memory(kbytes)", RLIMIT_RSS, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008441#endif
8442#ifdef RLIMIT_MEMLOCK
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008443 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008444#endif
8445#ifdef RLIMIT_NPROC
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008446 { "process(processes)", RLIMIT_NPROC, 1 },
Eric Andersencb57d552001-06-28 07:25:16 +00008447#endif
8448#ifdef RLIMIT_NOFILE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008449 { "nofiles(descriptors)", RLIMIT_NOFILE, 1 },
Eric Andersencb57d552001-06-28 07:25:16 +00008450#endif
8451#ifdef RLIMIT_VMEM
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008452 { "vmemory(kbytes)", RLIMIT_VMEM, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008453#endif
8454#ifdef RLIMIT_SWAP
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008455 { "swap(kbytes)", RLIMIT_SWAP, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008456#endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008457 { NULL, 0, 0 }
Eric Andersencb57d552001-06-28 07:25:16 +00008458};
8459
8460static int
8461ulimitcmd(argc, argv)
8462 int argc;
8463 char **argv;
8464{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008465 static const char unlimited_string[] = "unlimited";
Eric Andersen2870d962001-07-02 17:27:21 +00008466 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00008467 rlim_t val = 0;
8468 enum { SOFT = 0x1, HARD = 0x2 }
8469 how = SOFT | HARD;
Eric Andersen2870d962001-07-02 17:27:21 +00008470 const struct limits *l;
8471 int set, all = 0;
8472 int optc, what;
8473 struct rlimit limit;
Eric Andersencb57d552001-06-28 07:25:16 +00008474
8475 what = 'f';
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008476
8477 while ((optc = nextopt("HSa"
8478#ifdef RLIMIT_CPU
8479 "t"
8480#endif
8481#ifdef RLIMIT_FSIZE
8482 "f"
8483#endif
8484#ifdef RLIMIT_DATA
8485 "d"
8486#endif
8487#ifdef RLIMIT_STACK
8488 "s"
8489#endif
8490#ifdef RLIMIT_CORE
8491 "c"
8492#endif
8493#ifdef RLIMIT_RSS
8494 "m"
8495#endif
8496#ifdef RLIMIT_MEMLOCK
8497 "l"
8498#endif
8499#ifdef RLIMIT_NPROC
8500 "p"
8501#endif
8502#ifdef RLIMIT_NOFILE
8503 "n"
8504#endif
8505#ifdef RLIMIT_VMEM
8506 "v"
8507#endif
8508#ifdef RLIMIT_SWAP
8509 "w"
8510#endif
8511 )) != '\0') {
8512 if (optc == 'H') {
Eric Andersencb57d552001-06-28 07:25:16 +00008513 how = HARD;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008514 } else if (optc == 'S') {
Eric Andersencb57d552001-06-28 07:25:16 +00008515 how = SOFT;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008516 } else if (optc == 'a') {
Eric Andersencb57d552001-06-28 07:25:16 +00008517 all = 1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008518 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00008519 what = optc;
8520 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008521 }
Eric Andersencb57d552001-06-28 07:25:16 +00008522
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008523 for (l = limits; l->name; l++) {
8524 if(l->name[0] == what)
8525 break;
8526 if(l->name[1]=='w' && what=='w')
8527 break;
8528 }
Eric Andersencb57d552001-06-28 07:25:16 +00008529
8530 set = *argptr ? 1 : 0;
8531 if (set) {
8532 char *p = *argptr;
8533
8534 if (all || argptr[1])
8535 error("too many arguments");
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008536 if (strcmp(p, unlimited_string) == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00008537 val = RLIM_INFINITY;
8538 else {
8539 val = (rlim_t) 0;
8540
8541 while ((c = *p++) >= '0' && c <= '9')
8542 {
8543 val = (val * 10) + (long)(c - '0');
8544 if (val < (rlim_t) 0)
8545 break;
8546 }
8547 if (c)
8548 error("bad number");
8549 val *= l->factor;
8550 }
8551 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008552
Eric Andersencb57d552001-06-28 07:25:16 +00008553 if (all) {
8554 for (l = limits; l->name; l++) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008555 printf("%-20s ", l->name);
Eric Andersencb57d552001-06-28 07:25:16 +00008556 getrlimit(l->cmd, &limit);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008557 OUTPUT_LIMIT:
Eric Andersencb57d552001-06-28 07:25:16 +00008558 if (how & SOFT)
8559 val = limit.rlim_cur;
8560 else if (how & HARD)
8561 val = limit.rlim_max;
8562
Eric Andersencb57d552001-06-28 07:25:16 +00008563 if (val == RLIM_INFINITY)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008564 puts(unlimited_string);
Eric Andersencb57d552001-06-28 07:25:16 +00008565 else
8566 {
8567 val /= l->factor;
Eric Andersen62483552001-07-10 06:09:16 +00008568 printf("%lld\n", (long long) val);
Eric Andersencb57d552001-06-28 07:25:16 +00008569 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008570 if (!all) {
8571 break;
8572 }
Eric Andersencb57d552001-06-28 07:25:16 +00008573 }
8574 return 0;
8575 }
8576
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008577 if (!set) {
8578 goto OUTPUT_LIMIT;
Eric Andersencb57d552001-06-28 07:25:16 +00008579 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008580
8581 getrlimit(l->cmd, &limit);
8582 if (how & HARD)
8583 limit.rlim_max = val;
8584 if (how & SOFT)
8585 limit.rlim_cur = val;
8586 if (setrlimit(l->cmd, &limit) < 0)
8587 error("error setting limit (%m)");
Eric Andersencb57d552001-06-28 07:25:16 +00008588 return 0;
8589}
Eric Andersencb57d552001-06-28 07:25:16 +00008590/*
8591 * prefix -- see if pfx is a prefix of string.
8592 */
8593
8594static int
Eric Andersen62483552001-07-10 06:09:16 +00008595prefix(char const *pfx, char const *string)
8596{
Eric Andersencb57d552001-06-28 07:25:16 +00008597 while (*pfx) {
8598 if (*pfx++ != *string++)
8599 return 0;
8600 }
8601 return 1;
8602}
8603
Eric Andersen2870d962001-07-02 17:27:21 +00008604/*
8605 * Return true if s is a string of digits, and save munber in intptr
8606 * nagative is bad
8607 */
8608
8609static int
8610is_number(const char *p, int *intptr)
8611{
8612 int ret = 0;
8613
8614 do {
8615 if (! is_digit(*p))
8616 return 0;
8617 ret *= 10;
8618 ret += digit_val(*p);
8619 p++;
8620 } while (*p != '\0');
8621
8622 *intptr = ret;
8623 return 1;
8624}
Eric Andersencb57d552001-06-28 07:25:16 +00008625
8626/*
8627 * Convert a string of digits to an integer, printing an error message on
8628 * failure.
8629 */
8630
8631static int
Eric Andersen2870d962001-07-02 17:27:21 +00008632number(const char *s)
8633{
8634 int i;
8635 if (! is_number(s, &i))
Eric Andersencb57d552001-06-28 07:25:16 +00008636 error("Illegal number: %s", s);
Eric Andersen2870d962001-07-02 17:27:21 +00008637 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00008638}
8639
Eric Andersencb57d552001-06-28 07:25:16 +00008640/*
8641 * Produce a possibly single quoted string suitable as input to the shell.
8642 * The return string is allocated on the stack.
8643 */
8644
8645static char *
8646single_quote(const char *s) {
8647 char *p;
8648
8649 STARTSTACKSTR(p);
8650
8651 do {
8652 char *q = p;
8653 size_t len1, len1p, len2, len2p;
8654
8655 len1 = strcspn(s, "'");
8656 len2 = strspn(s + len1, "'");
8657
8658 len1p = len1 ? len1 + 2 : len1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008659 len2p = len2 + ((len2 < 2) ? len2 : 2);
Eric Andersencb57d552001-06-28 07:25:16 +00008660
8661 CHECKSTRSPACE(len1p + len2p + 1, p);
8662
8663 if (len1) {
8664 *p = '\'';
Eric Andersencb57d552001-06-28 07:25:16 +00008665 q = p + 1 + len1;
8666 memcpy(p + 1, s, len1);
Eric Andersencb57d552001-06-28 07:25:16 +00008667 *q++ = '\'';
8668 s += len1;
8669 }
8670
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008671 if (len2 > 1) {
Eric Andersencb57d552001-06-28 07:25:16 +00008672 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008673 q += 1 + len2;
8674 memcpy(q + 1, s, len2);
8675 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008676 s += len2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008677 } else if (len2 == 1) {
8678 *q++ = '\\';
8679 *q = '\'';
8680 s++;
Eric Andersencb57d552001-06-28 07:25:16 +00008681 }
8682
8683 STADJUST(len1p + len2p, p);
8684 } while (*s);
8685
8686 USTPUTC(0, p);
8687
8688 return grabstackstr(p);
8689}
8690
8691/*
8692 * Like strdup but works with the ash stack.
8693 */
8694
8695static char *
8696sstrdup(const char *p)
8697{
8698 size_t len = strlen(p) + 1;
8699 return memcpy(stalloc(len), p, len);
8700}
8701
Eric Andersencb57d552001-06-28 07:25:16 +00008702
8703/*
Eric Andersencb57d552001-06-28 07:25:16 +00008704 * Routine for dealing with parsed shell commands.
8705 */
8706
8707
Eric Andersen62483552001-07-10 06:09:16 +00008708static void sizenodelist (const struct nodelist *);
8709static struct nodelist *copynodelist (const struct nodelist *);
8710static char *nodesavestr (const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00008711
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008712//#define CALCSIZE_TABLE
8713//#define COPYNODE_TABLE
8714#if defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE)
8715/*
8716 * To collect a lot of redundant code in case statements for copynode()
8717 * and calcsize(), we implement a mini language here. Each type of node
8718 * struct has an associated instruction sequence that operates on its
8719 * members via their offsets. The instruction are pack in unsigned chars
8720 * with format IIDDDDDE where the bits are
8721 * I : part of the instruction opcode, which are
8722 * 00 : member is a pointer to another node
8723 * 40 : member is an integer
8724 * 80 : member is a pointer to a nodelist
8725 * CC : member is a pointer to a char string
8726 * D : data - the actual offset of the member to operate on in the struct
8727 * (since we assume bit 0 is set, it is not shifted)
8728 * E : flag signaling end of instruction sequence
8729 *
8730 * WARNING: In order to handle larger offsets for 64bit archs, this code
8731 * assumes that no offset can be an odd number and stores the
8732 * end-of-instructions flag in bit 0.
8733 */
8734
8735#define NODE_INTEGER 0x40
8736#define NODE_NODELIST 0x80
8737#define NODE_CHARPTR 0xC0
8738#define NODE_NOMORE 0x01 /* Note: no offset should be odd (aligned)*/
8739#define NODE_MBRMASK 0xC0
8740#define NODE_OFFSETMASK 0x3E
8741
8742static const unsigned char copynode_ops[35] = {
8743#define COPYNODE_OPS0 0
8744 offsetof(union node, nbinary.ch2),
8745 offsetof(union node, nbinary.ch1)|NODE_NOMORE,
8746#define COPYNODE_OPS1 (COPYNODE_OPS0 + 2)
8747 offsetof(union node, ncmd.redirect),
8748 offsetof(union node, ncmd.args),
8749 offsetof(union node, ncmd.assign),
8750 offsetof(union node, ncmd.backgnd)|NODE_INTEGER|NODE_NOMORE,
8751#define COPYNODE_OPS2 (COPYNODE_OPS1 + 4)
8752 offsetof(union node, npipe.cmdlist)|NODE_NODELIST,
8753 offsetof(union node, npipe.backgnd)|NODE_INTEGER|NODE_NOMORE,
8754#define COPYNODE_OPS3 (COPYNODE_OPS2 + 2)
8755 offsetof(union node, nredir.redirect),
8756 offsetof(union node, nredir.n)|NODE_NOMORE,
8757#define COPYNODE_OPS4 (COPYNODE_OPS3 + 2)
8758 offsetof(union node, nif.elsepart),
8759 offsetof(union node, nif.ifpart),
8760 offsetof(union node, nif.test)|NODE_NOMORE,
8761#define COPYNODE_OPS5 (COPYNODE_OPS4 + 3)
8762 offsetof(union node, nfor.var)|NODE_CHARPTR,
8763 offsetof(union node, nfor.body),
8764 offsetof(union node, nfor.args)|NODE_NOMORE,
8765#define COPYNODE_OPS6 (COPYNODE_OPS5 + 3)
8766 offsetof(union node, ncase.cases),
8767 offsetof(union node, ncase.expr)|NODE_NOMORE,
8768#define COPYNODE_OPS7 (COPYNODE_OPS6 + 2)
8769 offsetof(union node, nclist.body),
8770 offsetof(union node, nclist.pattern),
8771 offsetof(union node, nclist.next)|NODE_NOMORE,
8772#define COPYNODE_OPS8 (COPYNODE_OPS7 + 3)
8773 offsetof(union node, narg.backquote)|NODE_NODELIST,
8774 offsetof(union node, narg.text)|NODE_CHARPTR,
8775 offsetof(union node, narg.next)|NODE_NOMORE,
8776#define COPYNODE_OPS9 (COPYNODE_OPS8 + 3)
8777 offsetof(union node, nfile.fname),
8778 offsetof(union node, nfile.fd)|NODE_INTEGER,
8779 offsetof(union node, nfile.next)|NODE_NOMORE,
8780#define COPYNODE_OPS10 (COPYNODE_OPS9 + 3)
8781 offsetof(union node, ndup.vname),
8782 offsetof(union node, ndup.dupfd)|NODE_INTEGER,
8783 offsetof(union node, ndup.fd)|NODE_INTEGER,
8784 offsetof(union node, ndup.next)|NODE_NOMORE,
8785#define COPYNODE_OPS11 (COPYNODE_OPS10 + 4)
8786 offsetof(union node, nhere.doc),
8787 offsetof(union node, nhere.fd)|NODE_INTEGER,
8788 offsetof(union node, nhere.next)|NODE_NOMORE,
8789#define COPYNODE_OPS12 (COPYNODE_OPS11 + 3)
8790 offsetof(union node, nnot.com)|NODE_NOMORE,
8791};
8792
8793#if COPYNODE_OPS12 != 34
8794#error COPYNODE_OPS12 is incorrect
8795#endif
8796
8797static const unsigned char copynode_ops_index[26] = {
8798 COPYNODE_OPS0, /* NSEMI */
8799 COPYNODE_OPS1, /* NCMD */
8800 COPYNODE_OPS2, /* NPIPE */
8801 COPYNODE_OPS3, /* NREDIR */
8802 COPYNODE_OPS3, /* NBACKGND */
8803 COPYNODE_OPS3, /* NSUBSHELL */
8804 COPYNODE_OPS0, /* NAND */
8805 COPYNODE_OPS0, /* NOR */
8806 COPYNODE_OPS4, /* NIF */
8807 COPYNODE_OPS0, /* NWHILE */
8808 COPYNODE_OPS0, /* NUNTIL */
8809 COPYNODE_OPS5, /* NFOR */
8810 COPYNODE_OPS6, /* NCASE */
8811 COPYNODE_OPS7, /* NCLIST */
8812 COPYNODE_OPS8, /* NDEFUN */
8813 COPYNODE_OPS8, /* NARG */
8814 COPYNODE_OPS9, /* NTO */
8815 COPYNODE_OPS9, /* NFROM */
8816 COPYNODE_OPS9, /* NFROMTO */
8817 COPYNODE_OPS9, /* NAPPEND */
8818 COPYNODE_OPS9, /* NTOOV */
8819 COPYNODE_OPS10, /* NTOFD */
8820 COPYNODE_OPS10, /* NFROMFD */
8821 COPYNODE_OPS11, /* NHERE */
8822 COPYNODE_OPS11, /* NXHERE */
8823 COPYNODE_OPS12, /* NNOT */
8824};
8825
8826#if NODE_CHARPTR != NODE_MBRMASK
8827#error NODE_CHARPTR != NODE_MBRMASK!!!
8828#endif
8829#endif /* defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE) */
8830
8831#ifdef COPYNODE_TABLE
8832static union node *
8833copynode(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008834{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008835 union node *new;
8836 const unsigned char *p;
8837
Manuel Novoa III c639a352001-08-12 17:32:56 +00008838 if (n == NULL) {
8839 return NULL;
8840 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008841 new = funcblock;
8842 new->type = n->type;
8843 funcblock = (char *) funcblock + (int) nodesize[n->type];
8844 p = copynode_ops + (int) copynode_ops_index[n->type];
8845 do {
8846 char *nn = ((char *) new) + ((int)(*p & NODE_OFFSETMASK));
8847 const char *no = ((const char *) n) + ((int)(*p & NODE_OFFSETMASK));
8848
8849 if (!(*p & NODE_MBRMASK)) { /* standard node */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008850 *((union node **)nn) = copynode(*((const union node **) no));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008851 } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008852 *((const char **)nn) = nodesavestr(*((const char **)no));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008853 } else if (*p & NODE_NODELIST) { /* nodelist */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008854 *((struct nodelist **)nn)
8855 = copynodelist(*((const struct nodelist **) no));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008856 } else { /* integer */
8857 *((int *) nn) = *((int *) no);
8858 }
8859 } while (!(*p++ & NODE_NOMORE));
8860 return new;
Eric Andersencb57d552001-06-28 07:25:16 +00008861}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008862#else /* COPYNODE_TABLE */
Eric Andersencb57d552001-06-28 07:25:16 +00008863static union node *
Eric Andersen62483552001-07-10 06:09:16 +00008864copynode(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008865{
Eric Andersen62483552001-07-10 06:09:16 +00008866 union node *new;
Eric Andersencb57d552001-06-28 07:25:16 +00008867
8868 if (n == NULL)
Manuel Novoa III c639a352001-08-12 17:32:56 +00008869 return NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008870 new = funcblock;
8871 funcblock = (char *) funcblock + nodesize[n->type];
8872 switch (n->type) {
8873 case NSEMI:
8874 case NAND:
8875 case NOR:
8876 case NWHILE:
8877 case NUNTIL:
8878 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8879 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8880 break;
8881 case NCMD:
8882 new->ncmd.redirect = copynode(n->ncmd.redirect);
8883 new->ncmd.args = copynode(n->ncmd.args);
8884 new->ncmd.assign = copynode(n->ncmd.assign);
8885 new->ncmd.backgnd = n->ncmd.backgnd;
8886 break;
8887 case NPIPE:
8888 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8889 new->npipe.backgnd = n->npipe.backgnd;
8890 break;
8891 case NREDIR:
8892 case NBACKGND:
8893 case NSUBSHELL:
8894 new->nredir.redirect = copynode(n->nredir.redirect);
8895 new->nredir.n = copynode(n->nredir.n);
8896 break;
8897 case NIF:
8898 new->nif.elsepart = copynode(n->nif.elsepart);
8899 new->nif.ifpart = copynode(n->nif.ifpart);
8900 new->nif.test = copynode(n->nif.test);
8901 break;
8902 case NFOR:
8903 new->nfor.var = nodesavestr(n->nfor.var);
8904 new->nfor.body = copynode(n->nfor.body);
8905 new->nfor.args = copynode(n->nfor.args);
8906 break;
8907 case NCASE:
8908 new->ncase.cases = copynode(n->ncase.cases);
8909 new->ncase.expr = copynode(n->ncase.expr);
8910 break;
8911 case NCLIST:
8912 new->nclist.body = copynode(n->nclist.body);
8913 new->nclist.pattern = copynode(n->nclist.pattern);
8914 new->nclist.next = copynode(n->nclist.next);
8915 break;
8916 case NDEFUN:
8917 case NARG:
8918 new->narg.backquote = copynodelist(n->narg.backquote);
8919 new->narg.text = nodesavestr(n->narg.text);
8920 new->narg.next = copynode(n->narg.next);
8921 break;
8922 case NTO:
8923 case NFROM:
8924 case NFROMTO:
8925 case NAPPEND:
8926 case NTOOV:
8927 new->nfile.fname = copynode(n->nfile.fname);
8928 new->nfile.fd = n->nfile.fd;
8929 new->nfile.next = copynode(n->nfile.next);
8930 break;
8931 case NTOFD:
8932 case NFROMFD:
8933 new->ndup.vname = copynode(n->ndup.vname);
8934 new->ndup.dupfd = n->ndup.dupfd;
8935 new->ndup.fd = n->ndup.fd;
8936 new->ndup.next = copynode(n->ndup.next);
8937 break;
8938 case NHERE:
8939 case NXHERE:
8940 new->nhere.doc = copynode(n->nhere.doc);
8941 new->nhere.fd = n->nhere.fd;
8942 new->nhere.next = copynode(n->nhere.next);
8943 break;
8944 case NNOT:
8945 new->nnot.com = copynode(n->nnot.com);
8946 break;
8947 };
8948 new->type = n->type;
Eric Andersen62483552001-07-10 06:09:16 +00008949 return new;
Eric Andersencb57d552001-06-28 07:25:16 +00008950}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008951#endif /* COPYNODE_TABLE */
8952
8953#ifdef CALCSIZE_TABLE
8954static void
8955calcsize(const union node *n)
8956{
8957 const unsigned char *p;
8958
8959 if (n == NULL)
8960 return;
8961 funcblocksize += (int) nodesize[n->type];
8962
8963 p = copynode_ops + (int) copynode_ops_index[n->type];
8964 do {
8965 const char *no = ((const char *) n) + ((int)(*p & NODE_OFFSETMASK));
8966
8967 if (!(*p & NODE_MBRMASK)) { /* standard node */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008968 calcsize(*((const union node **) no));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008969 } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008970 funcstringsize += strlen(*((const char **)no)) + 1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008971 } else if (*p & NODE_NODELIST) { /* nodelist */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008972 sizenodelist(*((const struct nodelist **) no));
8973 } /* else integer -- ignore */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008974 } while (!(*p++ & NODE_NOMORE));
8975}
8976#else /* CALCSIZE_TABLE */
8977static void
8978calcsize(const union node *n)
8979{
8980 if (n == NULL)
8981 return;
8982 funcblocksize += nodesize[n->type];
8983 switch (n->type) {
8984 case NSEMI:
8985 case NAND:
8986 case NOR:
8987 case NWHILE:
8988 case NUNTIL:
8989 calcsize(n->nbinary.ch2);
8990 calcsize(n->nbinary.ch1);
8991 break;
8992 case NCMD:
8993 calcsize(n->ncmd.redirect);
8994 calcsize(n->ncmd.args);
8995 calcsize(n->ncmd.assign);
8996 break;
8997 case NPIPE:
8998 sizenodelist(n->npipe.cmdlist);
8999 break;
9000 case NREDIR:
9001 case NBACKGND:
9002 case NSUBSHELL:
9003 calcsize(n->nredir.redirect);
9004 calcsize(n->nredir.n);
9005 break;
9006 case NIF:
9007 calcsize(n->nif.elsepart);
9008 calcsize(n->nif.ifpart);
9009 calcsize(n->nif.test);
9010 break;
9011 case NFOR:
9012 funcstringsize += strlen(n->nfor.var) + 1;
9013 calcsize(n->nfor.body);
9014 calcsize(n->nfor.args);
9015 break;
9016 case NCASE:
9017 calcsize(n->ncase.cases);
9018 calcsize(n->ncase.expr);
9019 break;
9020 case NCLIST:
9021 calcsize(n->nclist.body);
9022 calcsize(n->nclist.pattern);
9023 calcsize(n->nclist.next);
9024 break;
9025 case NDEFUN:
9026 case NARG:
9027 sizenodelist(n->narg.backquote);
9028 funcstringsize += strlen(n->narg.text) + 1;
9029 calcsize(n->narg.next);
9030 break;
9031 case NTO:
9032 case NFROM:
9033 case NFROMTO:
9034 case NAPPEND:
9035 case NTOOV:
9036 calcsize(n->nfile.fname);
9037 calcsize(n->nfile.next);
9038 break;
9039 case NTOFD:
9040 case NFROMFD:
9041 calcsize(n->ndup.vname);
9042 calcsize(n->ndup.next);
9043 break;
9044 case NHERE:
9045 case NXHERE:
9046 calcsize(n->nhere.doc);
9047 calcsize(n->nhere.next);
9048 break;
9049 case NNOT:
9050 calcsize(n->nnot.com);
9051 break;
9052 };
9053}
9054#endif /* CALCSIZE_TABLE */
9055
9056static void
9057sizenodelist(const struct nodelist *lp)
9058{
9059 while (lp) {
9060 funcblocksize += ALIGN(sizeof(struct nodelist));
9061 calcsize(lp->n);
9062 lp = lp->next;
9063 }
9064}
Eric Andersencb57d552001-06-28 07:25:16 +00009065
9066
9067static struct nodelist *
Eric Andersen62483552001-07-10 06:09:16 +00009068copynodelist(const struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00009069{
9070 struct nodelist *start;
9071 struct nodelist **lpp;
9072
9073 lpp = &start;
9074 while (lp) {
9075 *lpp = funcblock;
9076 funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist));
9077 (*lpp)->n = copynode(lp->n);
9078 lp = lp->next;
9079 lpp = &(*lpp)->next;
9080 }
9081 *lpp = NULL;
9082 return start;
9083}
9084
9085
Eric Andersencb57d552001-06-28 07:25:16 +00009086static char *
Eric Andersen62483552001-07-10 06:09:16 +00009087nodesavestr(const char *s)
Eric Andersencb57d552001-06-28 07:25:16 +00009088{
Eric Andersen62483552001-07-10 06:09:16 +00009089 const char *p = s;
9090 char *q = funcstring;
Eric Andersencb57d552001-06-28 07:25:16 +00009091 char *rtn = funcstring;
9092
9093 while ((*q++ = *p++) != '\0')
9094 continue;
9095 funcstring = q;
9096 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00009097}
9098
Eric Andersencb57d552001-06-28 07:25:16 +00009099#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00009100static int getopts (char *, char *, char **, int *, int *);
Eric Andersencb57d552001-06-28 07:25:16 +00009101#endif
9102
9103
9104/*
9105 * Process the shell command line arguments.
9106 */
9107
9108static void
9109procargs(argc, argv)
9110 int argc;
9111 char **argv;
9112{
9113 int i;
9114
9115 argptr = argv;
9116 if (argc > 0)
9117 argptr++;
9118 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009119 optent_val(i) = 2;
Eric Andersencb57d552001-06-28 07:25:16 +00009120 options(1);
9121 if (*argptr == NULL && minusc == NULL)
9122 sflag = 1;
9123 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
9124 iflag = 1;
9125 if (mflag == 2)
9126 mflag = iflag;
9127 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009128 if (optent_val(i) == 2)
9129 optent_val(i) = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009130 arg0 = argv[0];
9131 if (sflag == 0 && minusc == NULL) {
9132 commandname = argv[0];
9133 arg0 = *argptr++;
9134 setinputfile(arg0, 0);
9135 commandname = arg0;
9136 }
9137 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
9138 if (argptr && minusc && *argptr)
Eric Andersen2870d962001-07-02 17:27:21 +00009139 arg0 = *argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00009140
9141 shellparam.p = argptr;
9142 shellparam.optind = 1;
9143 shellparam.optoff = -1;
9144 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
9145 while (*argptr) {
9146 shellparam.nparam++;
9147 argptr++;
9148 }
9149 optschanged();
9150}
9151
9152
Eric Andersencb57d552001-06-28 07:25:16 +00009153
9154/*
9155 * Process shell options. The global variable argptr contains a pointer
9156 * to the argument list; we advance it past the options.
9157 */
9158
Eric Andersen62483552001-07-10 06:09:16 +00009159static inline void
9160minus_o(const char *name, int val)
9161{
9162 int i;
9163
9164 if (name == NULL) {
9165 out1str("Current option settings\n");
9166 for (i = 0; i < NOPTS; i++)
9167 printf("%-16s%s\n", optent_name(optlist[i]),
9168 optent_val(i) ? "on" : "off");
9169 } else {
9170 for (i = 0; i < NOPTS; i++)
9171 if (equal(name, optent_name(optlist[i]))) {
9172 setoption(optent_letter(optlist[i]), val);
9173 return;
9174 }
9175 error("Illegal option -o %s", name);
9176 }
9177}
9178
9179
Eric Andersencb57d552001-06-28 07:25:16 +00009180static void
Eric Andersen62483552001-07-10 06:09:16 +00009181options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00009182{
9183 char *p;
9184 int val;
9185 int c;
9186
9187 if (cmdline)
9188 minusc = NULL;
9189 while ((p = *argptr) != NULL) {
9190 argptr++;
9191 if ((c = *p++) == '-') {
9192 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00009193 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
9194 if (!cmdline) {
9195 /* "-" means turn off -x and -v */
9196 if (p[0] == '\0')
9197 xflag = vflag = 0;
9198 /* "--" means reset params */
9199 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00009200 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00009201 }
9202 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00009203 }
9204 } else if (c == '+') {
9205 val = 0;
9206 } else {
9207 argptr--;
9208 break;
9209 }
9210 while ((c = *p++) != '\0') {
9211 if (c == 'c' && cmdline) {
9212 char *q;
Eric Andersen2870d962001-07-02 17:27:21 +00009213#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */
Eric Andersencb57d552001-06-28 07:25:16 +00009214 if (*p == '\0')
9215#endif
9216 q = *argptr++;
9217 if (q == NULL || minusc != NULL)
9218 error("Bad -c option");
9219 minusc = q;
9220#ifdef NOHACK
9221 break;
9222#endif
9223 } else if (c == 'o') {
9224 minus_o(*argptr, val);
9225 if (*argptr)
9226 argptr++;
9227 } else {
9228 setoption(c, val);
9229 }
9230 }
9231 }
9232}
9233
Eric Andersencb57d552001-06-28 07:25:16 +00009234
9235static void
Eric Andersen2870d962001-07-02 17:27:21 +00009236setoption(int flag, int val)
9237{
Eric Andersencb57d552001-06-28 07:25:16 +00009238 int i;
9239
9240 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009241 if (optent_letter(optlist[i]) == flag) {
9242 optent_val(i) = val;
Eric Andersencb57d552001-06-28 07:25:16 +00009243 if (val) {
9244 /* #%$ hack for ksh semantics */
9245 if (flag == 'V')
9246 Eflag = 0;
9247 else if (flag == 'E')
9248 Vflag = 0;
9249 }
9250 return;
9251 }
9252 error("Illegal option -%c", flag);
9253 /* NOTREACHED */
9254}
9255
9256
9257
Eric Andersencb57d552001-06-28 07:25:16 +00009258/*
9259 * Set the shell parameters.
9260 */
9261
9262static void
Eric Andersen2870d962001-07-02 17:27:21 +00009263setparam(char **argv)
9264{
Eric Andersencb57d552001-06-28 07:25:16 +00009265 char **newparam;
9266 char **ap;
9267 int nparam;
9268
9269 for (nparam = 0 ; argv[nparam] ; nparam++);
9270 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
9271 while (*argv) {
9272 *ap++ = savestr(*argv++);
9273 }
9274 *ap = NULL;
9275 freeparam(&shellparam);
9276 shellparam.malloc = 1;
9277 shellparam.nparam = nparam;
9278 shellparam.p = newparam;
9279 shellparam.optind = 1;
9280 shellparam.optoff = -1;
9281}
9282
9283
9284/*
9285 * Free the list of positional parameters.
9286 */
9287
9288static void
Eric Andersen2870d962001-07-02 17:27:21 +00009289freeparam(volatile struct shparam *param)
9290{
Eric Andersencb57d552001-06-28 07:25:16 +00009291 char **ap;
9292
9293 if (param->malloc) {
9294 for (ap = param->p ; *ap ; ap++)
9295 ckfree(*ap);
9296 ckfree(param->p);
9297 }
9298}
9299
9300
9301
9302/*
9303 * The shift builtin command.
9304 */
9305
9306static int
9307shiftcmd(argc, argv)
9308 int argc;
9309 char **argv;
9310{
9311 int n;
9312 char **ap1, **ap2;
9313
9314 n = 1;
9315 if (argc > 1)
9316 n = number(argv[1]);
9317 if (n > shellparam.nparam)
9318 error("can't shift that many");
9319 INTOFF;
9320 shellparam.nparam -= n;
9321 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
9322 if (shellparam.malloc)
9323 ckfree(*ap1);
9324 }
9325 ap2 = shellparam.p;
9326 while ((*ap2++ = *ap1++) != NULL);
9327 shellparam.optind = 1;
9328 shellparam.optoff = -1;
9329 INTON;
9330 return 0;
9331}
9332
9333
9334
9335/*
9336 * The set command builtin.
9337 */
9338
9339static int
9340setcmd(argc, argv)
9341 int argc;
9342 char **argv;
9343{
9344 if (argc == 1)
9345 return showvarscmd(argc, argv);
9346 INTOFF;
9347 options(0);
9348 optschanged();
9349 if (*argptr != NULL) {
9350 setparam(argptr);
9351 }
9352 INTON;
9353 return 0;
9354}
9355
9356
9357static void
Eric Andersen2870d962001-07-02 17:27:21 +00009358getoptsreset(const char *value)
Eric Andersencb57d552001-06-28 07:25:16 +00009359{
9360 shellparam.optind = number(value);
9361 shellparam.optoff = -1;
9362}
9363
Eric Andersen2870d962001-07-02 17:27:21 +00009364#ifdef BB_LOCALE_SUPPORT
9365static void change_lc_all(const char *value)
9366{
9367 if(value != 0 && *value != 0)
9368 setlocale(LC_ALL, value);
9369}
9370
9371static void change_lc_ctype(const char *value)
9372{
9373 if(value != 0 && *value != 0)
9374 setlocale(LC_CTYPE, value);
9375}
9376
9377#endif
9378
Eric Andersencb57d552001-06-28 07:25:16 +00009379#ifdef ASH_GETOPTS
9380/*
9381 * The getopts builtin. Shellparam.optnext points to the next argument
9382 * to be processed. Shellparam.optptr points to the next character to
9383 * be processed in the current argument. If shellparam.optnext is NULL,
9384 * then it's the first time getopts has been called.
9385 */
9386
9387static int
9388getoptscmd(argc, argv)
9389 int argc;
9390 char **argv;
9391{
9392 char **optbase;
9393
9394 if (argc < 3)
9395 error("Usage: getopts optstring var [arg]");
9396 else if (argc == 3) {
9397 optbase = shellparam.p;
9398 if (shellparam.optind > shellparam.nparam + 1) {
9399 shellparam.optind = 1;
9400 shellparam.optoff = -1;
9401 }
9402 }
9403 else {
9404 optbase = &argv[3];
9405 if (shellparam.optind > argc - 2) {
9406 shellparam.optind = 1;
9407 shellparam.optoff = -1;
9408 }
9409 }
9410
9411 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9412 &shellparam.optoff);
9413}
9414
9415/*
9416 * Safe version of setvar, returns 1 on success 0 on failure.
9417 */
9418
9419static int
9420setvarsafe(name, val, flags)
9421 const char *name, *val;
9422 int flags;
9423{
9424 struct jmploc jmploc;
9425 struct jmploc *volatile savehandler = handler;
9426 int err = 0;
9427#ifdef __GNUC__
9428 (void) &err;
9429#endif
9430
9431 if (setjmp(jmploc.loc))
9432 err = 1;
9433 else {
9434 handler = &jmploc;
9435 setvar(name, val, flags);
9436 }
9437 handler = savehandler;
9438 return err;
9439}
9440
9441static int
9442getopts(optstr, optvar, optfirst, myoptind, optoff)
9443 char *optstr;
9444 char *optvar;
9445 char **optfirst;
9446 int *myoptind;
9447 int *optoff;
9448{
9449 char *p, *q;
9450 char c = '?';
9451 int done = 0;
9452 int err = 0;
9453 char s[10];
9454 char **optnext = optfirst + *myoptind - 1;
9455
9456 if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
9457 strlen(*(optnext - 1)) < *optoff)
9458 p = NULL;
9459 else
9460 p = *(optnext - 1) + *optoff;
9461 if (p == NULL || *p == '\0') {
9462 /* Current word is done, advance */
9463 if (optnext == NULL)
9464 return 1;
9465 p = *optnext;
9466 if (p == NULL || *p != '-' || *++p == '\0') {
9467atend:
9468 *myoptind = optnext - optfirst + 1;
9469 p = NULL;
9470 done = 1;
9471 goto out;
9472 }
9473 optnext++;
Eric Andersen2870d962001-07-02 17:27:21 +00009474 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009475 goto atend;
9476 }
9477
9478 c = *p++;
9479 for (q = optstr; *q != c; ) {
9480 if (*q == '\0') {
9481 if (optstr[0] == ':') {
9482 s[0] = c;
9483 s[1] = '\0';
9484 err |= setvarsafe("OPTARG", s, 0);
9485 }
9486 else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009487 out2fmt("Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009488 (void) unsetvar("OPTARG");
9489 }
9490 c = '?';
9491 goto bad;
9492 }
9493 if (*++q == ':')
9494 q++;
9495 }
9496
9497 if (*++q == ':') {
9498 if (*p == '\0' && (p = *optnext) == NULL) {
9499 if (optstr[0] == ':') {
9500 s[0] = c;
9501 s[1] = '\0';
9502 err |= setvarsafe("OPTARG", s, 0);
9503 c = ':';
9504 }
9505 else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009506 out2fmt("No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009507 (void) unsetvar("OPTARG");
9508 c = '?';
9509 }
9510 goto bad;
9511 }
9512
9513 if (p == *optnext)
9514 optnext++;
9515 setvarsafe("OPTARG", p, 0);
9516 p = NULL;
9517 }
9518 else
9519 setvarsafe("OPTARG", "", 0);
9520 *myoptind = optnext - optfirst + 1;
9521 goto out;
9522
9523bad:
9524 *myoptind = 1;
9525 p = NULL;
9526out:
9527 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersen3102ac42001-07-06 04:26:23 +00009528 snprintf(s, sizeof(s), "%d", *myoptind);
Eric Andersencb57d552001-06-28 07:25:16 +00009529 err |= setvarsafe("OPTIND", s, VNOFUNC);
9530 s[0] = c;
9531 s[1] = '\0';
9532 err |= setvarsafe(optvar, s, 0);
9533 if (err) {
9534 *myoptind = 1;
9535 *optoff = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00009536 exraise(EXERROR);
9537 }
9538 return done;
9539}
Eric Andersen2870d962001-07-02 17:27:21 +00009540#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009541
9542/*
9543 * XXX - should get rid of. have all builtins use getopt(3). the
9544 * library getopt must have the BSD extension static variable "optreset"
9545 * otherwise it can't be used within the shell safely.
9546 *
9547 * Standard option processing (a la getopt) for builtin routines. The
9548 * only argument that is passed to nextopt is the option string; the
9549 * other arguments are unnecessary. It return the character, or '\0' on
9550 * end of input.
9551 */
9552
9553static int
Eric Andersen62483552001-07-10 06:09:16 +00009554nextopt(const char *optstring)
9555{
Eric Andersencb57d552001-06-28 07:25:16 +00009556 char *p;
9557 const char *q;
9558 char c;
9559
9560 if ((p = optptr) == NULL || *p == '\0') {
9561 p = *argptr;
9562 if (p == NULL || *p != '-' || *++p == '\0')
9563 return '\0';
9564 argptr++;
Eric Andersen2870d962001-07-02 17:27:21 +00009565 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009566 return '\0';
9567 }
9568 c = *p++;
9569 for (q = optstring ; *q != c ; ) {
9570 if (*q == '\0')
9571 error("Illegal option -%c", c);
9572 if (*++q == ':')
9573 q++;
9574 }
9575 if (*++q == ':') {
9576 if (*p == '\0' && (p = *argptr++) == NULL)
9577 error("No arg for -%c option", c);
9578 optionarg = p;
9579 p = NULL;
9580 }
9581 optptr = p;
9582 return c;
9583}
9584
Eric Andersencb57d552001-06-28 07:25:16 +00009585static void
9586flushall() {
Eric Andersencb57d552001-06-28 07:25:16 +00009587 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009588 fflush(stdout);
Eric Andersencb57d552001-06-28 07:25:16 +00009589 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009590}
9591
9592
9593static void
Eric Andersen3102ac42001-07-06 04:26:23 +00009594out2fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009595{
9596 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00009597 va_start(ap, fmt);
Eric Andersen3102ac42001-07-06 04:26:23 +00009598 vfprintf(stderr, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009599 va_end(ap);
9600}
9601
Eric Andersencb57d552001-06-28 07:25:16 +00009602/*
9603 * Version of write which resumes after a signal is caught.
9604 */
9605
9606static int
Eric Andersen2870d962001-07-02 17:27:21 +00009607xwrite(int fd, const char *buf, int nbytes)
9608{
Eric Andersencb57d552001-06-28 07:25:16 +00009609 int ntry;
9610 int i;
9611 int n;
9612
9613 n = nbytes;
9614 ntry = 0;
9615 for (;;) {
9616 i = write(fd, buf, n);
9617 if (i > 0) {
9618 if ((n -= i) <= 0)
9619 return nbytes;
9620 buf += i;
9621 ntry = 0;
9622 } else if (i == 0) {
9623 if (++ntry > 10)
9624 return nbytes - n;
9625 } else if (errno != EINTR) {
9626 return -1;
9627 }
9628 }
9629}
9630
9631
Eric Andersencb57d552001-06-28 07:25:16 +00009632/*
9633 * Shell command parser.
9634 */
9635
9636#define EOFMARKLEN 79
9637
9638
9639
9640struct heredoc {
Eric Andersen2870d962001-07-02 17:27:21 +00009641 struct heredoc *next; /* next here document in list */
9642 union node *here; /* redirection node */
9643 char *eofmark; /* string indicating end of input */
9644 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009645};
9646
Eric Andersen2870d962001-07-02 17:27:21 +00009647static struct heredoc *heredoclist; /* list of here documents to read */
9648static int parsebackquote; /* nonzero if we are inside backquotes */
9649static int doprompt; /* if set, prompt the user */
9650static int needprompt; /* true if interactive and at start of line */
9651static int lasttoken; /* last token read */
Eric Andersencb57d552001-06-28 07:25:16 +00009652
Eric Andersen2870d962001-07-02 17:27:21 +00009653static char *wordtext; /* text of last word returned by readtoken */
Eric Andersencb57d552001-06-28 07:25:16 +00009654
Eric Andersen2870d962001-07-02 17:27:21 +00009655static struct nodelist *backquotelist;
9656static union node *redirnode;
Eric Andersen044228d2001-07-17 01:12:36 +00009657static struct heredoc *heredoc;
Eric Andersen2870d962001-07-02 17:27:21 +00009658static int quoteflag; /* set if (part of) last token was quoted */
9659static int startlinno; /* line # where last token started */
Eric Andersencb57d552001-06-28 07:25:16 +00009660
9661
Eric Andersen2870d962001-07-02 17:27:21 +00009662static union node *list (int);
9663static union node *andor (void);
9664static union node *pipeline (void);
9665static union node *command (void);
9666static union node *simplecmd (void);
9667static void parsefname (void);
9668static void parseheredoc (void);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009669static char peektoken (void);
Eric Andersen2870d962001-07-02 17:27:21 +00009670static int readtoken (void);
9671static int xxreadtoken (void);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009672static int readtoken1 (int, int, const char *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00009673static int noexpand (char *);
9674static void synexpect (int) __attribute__((noreturn));
9675static void synerror (const char *) __attribute__((noreturn));
9676static void setprompt (int);
Eric Andersencb57d552001-06-28 07:25:16 +00009677
9678
9679/*
9680 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9681 * valid parse tree indicating a blank line.)
9682 */
9683
Eric Andersen2870d962001-07-02 17:27:21 +00009684static union node *
Eric Andersencb57d552001-06-28 07:25:16 +00009685parsecmd(int interact)
9686{
9687 int t;
9688
9689 tokpushback = 0;
9690 doprompt = interact;
9691 if (doprompt)
9692 setprompt(1);
9693 else
9694 setprompt(0);
9695 needprompt = 0;
9696 t = readtoken();
9697 if (t == TEOF)
9698 return NEOF;
9699 if (t == TNL)
9700 return NULL;
9701 tokpushback++;
9702 return list(1);
9703}
9704
9705
9706static union node *
9707list(nlflag)
9708 int nlflag;
9709{
9710 union node *n1, *n2, *n3;
9711 int tok;
9712
9713 checkkwd = 2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009714 if (nlflag == 0 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009715 return NULL;
9716 n1 = NULL;
9717 for (;;) {
9718 n2 = andor();
9719 tok = readtoken();
9720 if (tok == TBACKGND) {
9721 if (n2->type == NCMD || n2->type == NPIPE) {
9722 n2->ncmd.backgnd = 1;
9723 } else if (n2->type == NREDIR) {
9724 n2->type = NBACKGND;
9725 } else {
9726 n3 = (union node *)stalloc(sizeof (struct nredir));
9727 n3->type = NBACKGND;
9728 n3->nredir.n = n2;
9729 n3->nredir.redirect = NULL;
9730 n2 = n3;
9731 }
9732 }
9733 if (n1 == NULL) {
9734 n1 = n2;
9735 }
9736 else {
9737 n3 = (union node *)stalloc(sizeof (struct nbinary));
9738 n3->type = NSEMI;
9739 n3->nbinary.ch1 = n1;
9740 n3->nbinary.ch2 = n2;
9741 n1 = n3;
9742 }
9743 switch (tok) {
9744 case TBACKGND:
9745 case TSEMI:
9746 tok = readtoken();
9747 /* fall through */
9748 case TNL:
9749 if (tok == TNL) {
9750 parseheredoc();
9751 if (nlflag)
9752 return n1;
9753 } else {
9754 tokpushback++;
9755 }
9756 checkkwd = 2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009757 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009758 return n1;
9759 break;
9760 case TEOF:
9761 if (heredoclist)
9762 parseheredoc();
9763 else
Eric Andersen2870d962001-07-02 17:27:21 +00009764 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009765 return n1;
9766 default:
9767 if (nlflag)
9768 synexpect(-1);
9769 tokpushback++;
9770 return n1;
9771 }
9772 }
9773}
9774
9775
9776
9777static union node *
9778andor() {
9779 union node *n1, *n2, *n3;
9780 int t;
9781
9782 checkkwd = 1;
9783 n1 = pipeline();
9784 for (;;) {
9785 if ((t = readtoken()) == TAND) {
9786 t = NAND;
9787 } else if (t == TOR) {
9788 t = NOR;
9789 } else {
9790 tokpushback++;
9791 return n1;
9792 }
9793 checkkwd = 2;
9794 n2 = pipeline();
9795 n3 = (union node *)stalloc(sizeof (struct nbinary));
9796 n3->type = t;
9797 n3->nbinary.ch1 = n1;
9798 n3->nbinary.ch2 = n2;
9799 n1 = n3;
9800 }
9801}
9802
9803
9804
9805static union node *
9806pipeline() {
9807 union node *n1, *n2, *pipenode;
9808 struct nodelist *lp, *prev;
9809 int negate;
9810
9811 negate = 0;
9812 TRACE(("pipeline: entered\n"));
9813 if (readtoken() == TNOT) {
9814 negate = !negate;
9815 checkkwd = 1;
9816 } else
9817 tokpushback++;
9818 n1 = command();
9819 if (readtoken() == TPIPE) {
9820 pipenode = (union node *)stalloc(sizeof (struct npipe));
9821 pipenode->type = NPIPE;
9822 pipenode->npipe.backgnd = 0;
9823 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9824 pipenode->npipe.cmdlist = lp;
9825 lp->n = n1;
9826 do {
9827 prev = lp;
9828 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9829 checkkwd = 2;
9830 lp->n = command();
9831 prev->next = lp;
9832 } while (readtoken() == TPIPE);
9833 lp->next = NULL;
9834 n1 = pipenode;
9835 }
9836 tokpushback++;
9837 if (negate) {
9838 n2 = (union node *)stalloc(sizeof (struct nnot));
9839 n2->type = NNOT;
9840 n2->nnot.com = n1;
9841 return n2;
9842 } else
9843 return n1;
9844}
9845
9846
9847
9848static union node *
9849command() {
9850 union node *n1, *n2;
9851 union node *ap, **app;
9852 union node *cp, **cpp;
9853 union node *redir, **rpp;
9854 int t;
9855
9856 redir = NULL;
9857 n1 = NULL;
9858 rpp = &redir;
9859
Eric Andersen88cec252001-09-06 17:35:20 +00009860 /* Check for redirection which may precede command */
9861 while (readtoken() == TREDIR) {
9862 *rpp = n2 = redirnode;
9863 rpp = &n2->nfile.next;
9864 parsefname();
9865 }
9866 tokpushback++;
9867
Eric Andersencb57d552001-06-28 07:25:16 +00009868 switch (readtoken()) {
9869 case TIF:
9870 n1 = (union node *)stalloc(sizeof (struct nif));
9871 n1->type = NIF;
9872 n1->nif.test = list(0);
9873 if (readtoken() != TTHEN)
9874 synexpect(TTHEN);
9875 n1->nif.ifpart = list(0);
9876 n2 = n1;
9877 while (readtoken() == TELIF) {
9878 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9879 n2 = n2->nif.elsepart;
9880 n2->type = NIF;
9881 n2->nif.test = list(0);
9882 if (readtoken() != TTHEN)
9883 synexpect(TTHEN);
9884 n2->nif.ifpart = list(0);
9885 }
9886 if (lasttoken == TELSE)
9887 n2->nif.elsepart = list(0);
9888 else {
9889 n2->nif.elsepart = NULL;
9890 tokpushback++;
9891 }
9892 if (readtoken() != TFI)
9893 synexpect(TFI);
9894 checkkwd = 1;
9895 break;
9896 case TWHILE:
9897 case TUNTIL: {
9898 int got;
9899 n1 = (union node *)stalloc(sizeof (struct nbinary));
9900 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9901 n1->nbinary.ch1 = list(0);
9902 if ((got=readtoken()) != TDO) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009903TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009904 synexpect(TDO);
9905 }
9906 n1->nbinary.ch2 = list(0);
9907 if (readtoken() != TDONE)
9908 synexpect(TDONE);
9909 checkkwd = 1;
9910 break;
9911 }
9912 case TFOR:
9913 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9914 synerror("Bad for loop variable");
9915 n1 = (union node *)stalloc(sizeof (struct nfor));
9916 n1->type = NFOR;
9917 n1->nfor.var = wordtext;
9918 checkkwd = 1;
9919 if (readtoken() == TIN) {
9920 app = &ap;
9921 while (readtoken() == TWORD) {
9922 n2 = (union node *)stalloc(sizeof (struct narg));
9923 n2->type = NARG;
9924 n2->narg.text = wordtext;
9925 n2->narg.backquote = backquotelist;
9926 *app = n2;
9927 app = &n2->narg.next;
9928 }
9929 *app = NULL;
9930 n1->nfor.args = ap;
9931 if (lasttoken != TNL && lasttoken != TSEMI)
9932 synexpect(-1);
9933 } else {
9934 static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
9935 '@', '=', '\0'};
9936 n2 = (union node *)stalloc(sizeof (struct narg));
9937 n2->type = NARG;
9938 n2->narg.text = argvars;
9939 n2->narg.backquote = NULL;
9940 n2->narg.next = NULL;
9941 n1->nfor.args = n2;
9942 /*
9943 * Newline or semicolon here is optional (but note
9944 * that the original Bourne shell only allowed NL).
9945 */
9946 if (lasttoken != TNL && lasttoken != TSEMI)
9947 tokpushback++;
9948 }
9949 checkkwd = 2;
9950 if (readtoken() != TDO)
9951 synexpect(TDO);
9952 n1->nfor.body = list(0);
9953 if (readtoken() != TDONE)
9954 synexpect(TDONE);
9955 checkkwd = 1;
9956 break;
9957 case TCASE:
9958 n1 = (union node *)stalloc(sizeof (struct ncase));
9959 n1->type = NCASE;
9960 if (readtoken() != TWORD)
9961 synexpect(TWORD);
9962 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9963 n2->type = NARG;
9964 n2->narg.text = wordtext;
9965 n2->narg.backquote = backquotelist;
9966 n2->narg.next = NULL;
9967 do {
9968 checkkwd = 1;
9969 } while (readtoken() == TNL);
9970 if (lasttoken != TIN)
9971 synerror("expecting \"in\"");
9972 cpp = &n1->ncase.cases;
9973 checkkwd = 2, readtoken();
9974 do {
9975 if (lasttoken == TLP)
9976 readtoken();
9977 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9978 cp->type = NCLIST;
9979 app = &cp->nclist.pattern;
9980 for (;;) {
9981 *app = ap = (union node *)stalloc(sizeof (struct narg));
9982 ap->type = NARG;
9983 ap->narg.text = wordtext;
9984 ap->narg.backquote = backquotelist;
9985 if (checkkwd = 2, readtoken() != TPIPE)
9986 break;
9987 app = &ap->narg.next;
9988 readtoken();
9989 }
9990 ap->narg.next = NULL;
9991 if (lasttoken != TRP)
9992 synexpect(TRP);
9993 cp->nclist.body = list(0);
9994
9995 checkkwd = 2;
9996 if ((t = readtoken()) != TESAC) {
9997 if (t != TENDCASE)
9998 synexpect(TENDCASE);
9999 else
10000 checkkwd = 2, readtoken();
10001 }
10002 cpp = &cp->nclist.next;
10003 } while(lasttoken != TESAC);
10004 *cpp = NULL;
10005 checkkwd = 1;
10006 break;
10007 case TLP:
10008 n1 = (union node *)stalloc(sizeof (struct nredir));
10009 n1->type = NSUBSHELL;
10010 n1->nredir.n = list(0);
10011 n1->nredir.redirect = NULL;
10012 if (readtoken() != TRP)
10013 synexpect(TRP);
10014 checkkwd = 1;
10015 break;
10016 case TBEGIN:
10017 n1 = list(0);
10018 if (readtoken() != TEND)
10019 synexpect(TEND);
10020 checkkwd = 1;
10021 break;
10022 /* Handle an empty command like other simple commands. */
10023 case TSEMI:
10024 case TAND:
10025 case TOR:
10026 case TNL:
10027 case TEOF:
10028 case TRP:
10029 case TBACKGND:
10030 /*
10031 * An empty command before a ; doesn't make much sense, and
10032 * should certainly be disallowed in the case of `if ;'.
10033 */
10034 if (!redir)
10035 synexpect(-1);
10036 case TWORD:
Eric Andersencb57d552001-06-28 07:25:16 +000010037 tokpushback++;
10038 n1 = simplecmd();
10039 return n1;
10040 default:
10041 synexpect(-1);
10042 /* NOTREACHED */
10043 }
10044
10045 /* Now check for redirection which may follow command */
10046 while (readtoken() == TREDIR) {
10047 *rpp = n2 = redirnode;
10048 rpp = &n2->nfile.next;
10049 parsefname();
10050 }
10051 tokpushback++;
10052 *rpp = NULL;
10053 if (redir) {
10054 if (n1->type != NSUBSHELL) {
10055 n2 = (union node *)stalloc(sizeof (struct nredir));
10056 n2->type = NREDIR;
10057 n2->nredir.n = n1;
10058 n1 = n2;
10059 }
10060 n1->nredir.redirect = redir;
10061 }
10062
10063 return n1;
10064}
10065
10066
10067static union node *
10068simplecmd() {
10069 union node *args, **app;
10070 union node *n = NULL;
10071 union node *vars, **vpp;
10072 union node **rpp, *redir;
10073
10074 args = NULL;
10075 app = &args;
10076 vars = NULL;
10077 vpp = &vars;
10078 redir = NULL;
10079 rpp = &redir;
10080
10081 checkalias = 2;
10082 for (;;) {
10083 switch (readtoken()) {
10084 case TWORD:
10085 case TASSIGN:
10086 n = (union node *)stalloc(sizeof (struct narg));
10087 n->type = NARG;
10088 n->narg.text = wordtext;
10089 n->narg.backquote = backquotelist;
10090 if (lasttoken == TWORD) {
10091 *app = n;
10092 app = &n->narg.next;
10093 } else {
10094 *vpp = n;
10095 vpp = &n->narg.next;
10096 }
10097 break;
10098 case TREDIR:
10099 *rpp = n = redirnode;
10100 rpp = &n->nfile.next;
Eric Andersen2870d962001-07-02 17:27:21 +000010101 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +000010102 break;
10103 case TLP:
10104 if (
10105 args && app == &args->narg.next &&
10106 !vars && !redir
10107 ) {
10108 /* We have a function */
10109 if (readtoken() != TRP)
10110 synexpect(TRP);
Eric Andersencb57d552001-06-28 07:25:16 +000010111 n->type = NDEFUN;
10112 checkkwd = 2;
10113 n->narg.next = command();
10114 return n;
10115 }
10116 /* fall through */
10117 default:
10118 tokpushback++;
10119 goto out;
10120 }
10121 }
10122out:
10123 *app = NULL;
10124 *vpp = NULL;
10125 *rpp = NULL;
10126 n = (union node *)stalloc(sizeof (struct ncmd));
10127 n->type = NCMD;
10128 n->ncmd.backgnd = 0;
10129 n->ncmd.args = args;
10130 n->ncmd.assign = vars;
10131 n->ncmd.redirect = redir;
10132 return n;
10133}
10134
10135static union node *
Eric Andersen2870d962001-07-02 17:27:21 +000010136makename(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000010137 union node *n;
10138
10139 n = (union node *)stalloc(sizeof (struct narg));
10140 n->type = NARG;
10141 n->narg.next = NULL;
10142 n->narg.text = wordtext;
10143 n->narg.backquote = backquotelist;
10144 return n;
10145}
10146
10147static void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +000010148{
Eric Andersencb57d552001-06-28 07:25:16 +000010149 TRACE(("Fix redir %s %d\n", text, err));
10150 if (!err)
10151 n->ndup.vname = NULL;
10152
10153 if (is_digit(text[0]) && text[1] == '\0')
10154 n->ndup.dupfd = digit_val(text[0]);
10155 else if (text[0] == '-' && text[1] == '\0')
10156 n->ndup.dupfd = -1;
10157 else {
10158
10159 if (err)
10160 synerror("Bad fd number");
10161 else
10162 n->ndup.vname = makename();
10163 }
10164}
10165
10166
10167static void
Eric Andersen2870d962001-07-02 17:27:21 +000010168parsefname(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000010169 union node *n = redirnode;
10170
10171 if (readtoken() != TWORD)
10172 synexpect(-1);
10173 if (n->type == NHERE) {
10174 struct heredoc *here = heredoc;
10175 struct heredoc *p;
10176 int i;
10177
10178 if (quoteflag == 0)
10179 n->type = NXHERE;
10180 TRACE(("Here document %d\n", n->type));
10181 if (here->striptabs) {
10182 while (*wordtext == '\t')
10183 wordtext++;
10184 }
10185 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
10186 synerror("Illegal eof marker for << redirection");
10187 rmescapes(wordtext);
10188 here->eofmark = wordtext;
10189 here->next = NULL;
10190 if (heredoclist == NULL)
10191 heredoclist = here;
10192 else {
10193 for (p = heredoclist ; p->next ; p = p->next);
10194 p->next = here;
10195 }
10196 } else if (n->type == NTOFD || n->type == NFROMFD) {
10197 fixredir(n, wordtext, 0);
10198 } else {
10199 n->nfile.fname = makename();
10200 }
10201}
10202
10203
10204/*
10205 * Input any here documents.
10206 */
10207
10208static void
10209parseheredoc() {
10210 struct heredoc *here;
10211 union node *n;
10212
10213 while (heredoclist) {
10214 here = heredoclist;
10215 heredoclist = here->next;
10216 if (needprompt) {
10217 setprompt(2);
10218 needprompt = 0;
10219 }
10220 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
10221 here->eofmark, here->striptabs);
10222 n = (union node *)stalloc(sizeof (struct narg));
10223 n->narg.type = NARG;
10224 n->narg.next = NULL;
10225 n->narg.text = wordtext;
10226 n->narg.backquote = backquotelist;
10227 here->here->nhere.doc = n;
10228 }
10229}
10230
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010231static char
Eric Andersencb57d552001-06-28 07:25:16 +000010232peektoken() {
10233 int t;
10234
10235 t = readtoken();
10236 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010237 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +000010238}
10239
10240static int
10241readtoken() {
10242 int t;
Eric Andersen7467c8d2001-07-12 20:26:32 +000010243
Eric Andersen2870d962001-07-02 17:27:21 +000010244#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010245 int savecheckalias = checkalias;
Eric Andersen7467c8d2001-07-12 20:26:32 +000010246 int savecheckkwd = checkkwd;
Eric Andersencb57d552001-06-28 07:25:16 +000010247 struct alias *ap;
Eric Andersen2870d962001-07-02 17:27:21 +000010248#endif
10249
Eric Andersencb57d552001-06-28 07:25:16 +000010250#ifdef DEBUG
10251 int alreadyseen = tokpushback;
10252#endif
10253
Eric Andersen2870d962001-07-02 17:27:21 +000010254#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010255top:
Eric Andersen2870d962001-07-02 17:27:21 +000010256#endif
10257
Eric Andersencb57d552001-06-28 07:25:16 +000010258 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +000010259
10260#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010261 checkalias = savecheckalias;
Eric Andersen2870d962001-07-02 17:27:21 +000010262#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010263
10264 if (checkkwd) {
10265 /*
10266 * eat newlines
10267 */
10268 if (checkkwd == 2) {
10269 checkkwd = 0;
10270 while (t == TNL) {
10271 parseheredoc();
10272 t = xxreadtoken();
10273 }
10274 }
10275 checkkwd = 0;
10276 /*
10277 * check for keywords
10278 */
10279 if (t == TWORD && !quoteflag)
10280 {
10281 const char *const *pp;
10282
10283 if ((pp = findkwd(wordtext))) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010284 lasttoken = t = pp - tokname_array;
10285 TRACE(("keyword %s recognized\n", tokname(t)));
Eric Andersencb57d552001-06-28 07:25:16 +000010286 goto out;
10287 }
10288 }
10289 }
10290
Eric Andersen7467c8d2001-07-12 20:26:32 +000010291
Eric Andersencb57d552001-06-28 07:25:16 +000010292 if (t != TWORD) {
10293 if (t != TREDIR) {
10294 checkalias = 0;
10295 }
10296 } else if (checkalias == 2 && isassignment(wordtext)) {
10297 lasttoken = t = TASSIGN;
Eric Andersen7467c8d2001-07-12 20:26:32 +000010298#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010299 } else if (checkalias) {
10300 if (!quoteflag && (ap = lookupalias(wordtext, 1)) != NULL) {
10301 if (*ap->val) {
10302 pushstring(ap->val, strlen(ap->val), ap);
10303 }
10304 checkkwd = savecheckkwd;
10305 goto top;
10306 }
10307 checkalias = 0;
Eric Andersen2870d962001-07-02 17:27:21 +000010308#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +000010309 }
Eric Andersencb57d552001-06-28 07:25:16 +000010310out:
10311#ifdef DEBUG
10312 if (!alreadyseen)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010313 TRACE(("token %s %s\n", tokname(t), t == TWORD || t == TASSIGN ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +000010314 else
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010315 TRACE(("reread token %s %s\n", tokname(t), t == TWORD || t == TASSIGN ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +000010316#endif
10317 return (t);
10318}
10319
10320
10321/*
10322 * Read the next input token.
10323 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +000010324 * backquotes. We set quoteflag to true if any part of the word was
10325 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +000010326 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +000010327 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +000010328 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +000010329 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +000010330 *
10331 * [Change comment: here documents and internal procedures]
10332 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10333 * word parsing code into a separate routine. In this case, readtoken
10334 * doesn't need to have any internal procedures, but parseword does.
10335 * We could also make parseoperator in essence the main routine, and
10336 * have parseword (readtoken1?) handle both words and redirection.]
10337 */
10338
Eric Andersen2870d962001-07-02 17:27:21 +000010339#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010340
10341static int
10342xxreadtoken() {
10343 int c;
10344
10345 if (tokpushback) {
10346 tokpushback = 0;
10347 return lasttoken;
10348 }
10349 if (needprompt) {
10350 setprompt(2);
10351 needprompt = 0;
10352 }
10353 startlinno = plinno;
Eric Andersen2870d962001-07-02 17:27:21 +000010354 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010355 c = pgetc_macro();
10356 switch (c) {
10357 case ' ': case '\t':
Eric Andersen3102ac42001-07-06 04:26:23 +000010358#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010359 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010360#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010361 continue;
10362 case '#':
10363 while ((c = pgetc()) != '\n' && c != PEOF);
10364 pungetc();
10365 continue;
10366 case '\\':
10367 if (pgetc() == '\n') {
10368 startlinno = ++plinno;
10369 if (doprompt)
10370 setprompt(2);
10371 else
10372 setprompt(0);
10373 continue;
10374 }
10375 pungetc();
10376 goto breakloop;
10377 case '\n':
10378 plinno++;
10379 needprompt = doprompt;
10380 RETURN(TNL);
10381 case PEOF:
10382 RETURN(TEOF);
10383 case '&':
10384 if (pgetc() == '&')
10385 RETURN(TAND);
10386 pungetc();
10387 RETURN(TBACKGND);
10388 case '|':
10389 if (pgetc() == '|')
10390 RETURN(TOR);
10391 pungetc();
10392 RETURN(TPIPE);
10393 case ';':
10394 if (pgetc() == ';')
10395 RETURN(TENDCASE);
10396 pungetc();
10397 RETURN(TSEMI);
10398 case '(':
10399 RETURN(TLP);
10400 case ')':
10401 RETURN(TRP);
10402 default:
10403 goto breakloop;
10404 }
10405 }
10406breakloop:
10407 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10408#undef RETURN
10409}
10410
10411
10412
10413/*
10414 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10415 * is not NULL, read a here document. In the latter case, eofmark is the
10416 * word which marks the end of the document and striptabs is true if
10417 * leading tabs should be stripped from the document. The argument firstc
10418 * is the first character of the input token or document.
10419 *
10420 * Because C does not have internal subroutines, I have simulated them
10421 * using goto's to implement the subroutine linkage. The following macros
10422 * will run code that appears at the end of readtoken1.
10423 */
10424
Eric Andersen2870d962001-07-02 17:27:21 +000010425#define CHECKEND() {goto checkend; checkend_return:;}
10426#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10427#define PARSESUB() {goto parsesub; parsesub_return:;}
10428#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10429#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10430#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010431
10432static int
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010433readtoken1(int firstc, int syntax, const char *eofmark, int striptabs)
10434{
Eric Andersencb57d552001-06-28 07:25:16 +000010435 int c = firstc;
10436 char *out;
10437 int len;
10438 char line[EOFMARKLEN + 1];
10439 struct nodelist *bqlist;
10440 int quotef;
10441 int dblquote;
Eric Andersen2870d962001-07-02 17:27:21 +000010442 int varnest; /* levels of variables expansion */
10443 int arinest; /* levels of arithmetic expansion */
10444 int parenlevel; /* levels of parens in arithmetic */
10445 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +000010446 int oldstyle;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010447 int prevsyntax; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010448#if __GNUC__
10449 /* Avoid longjmp clobbering */
10450 (void) &out;
10451 (void) &quotef;
10452 (void) &dblquote;
10453 (void) &varnest;
10454 (void) &arinest;
10455 (void) &parenlevel;
10456 (void) &dqvarnest;
10457 (void) &oldstyle;
10458 (void) &prevsyntax;
10459 (void) &syntax;
10460#endif
10461
10462 startlinno = plinno;
10463 dblquote = 0;
10464 if (syntax == DQSYNTAX)
10465 dblquote = 1;
10466 quotef = 0;
10467 bqlist = NULL;
10468 varnest = 0;
10469 arinest = 0;
10470 parenlevel = 0;
10471 dqvarnest = 0;
10472
10473 STARTSTACKSTR(out);
Eric Andersen2870d962001-07-02 17:27:21 +000010474 loop: { /* for each line, until end of word */
10475 CHECKEND(); /* set c to PEOF if at end of here document */
10476 for (;;) { /* until end of line or end of word */
10477 CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010478 switch(SIT(c,syntax)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010479 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010480 if (syntax == BASESYNTAX)
Eric Andersen2870d962001-07-02 17:27:21 +000010481 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010482 USTPUTC(c, out);
10483 plinno++;
10484 if (doprompt)
10485 setprompt(2);
10486 else
10487 setprompt(0);
10488 c = pgetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010489 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010490 case CWORD:
10491 USTPUTC(c, out);
10492 break;
10493 case CCTL:
10494 if ((eofmark == NULL || dblquote) &&
10495 dqvarnest == 0)
10496 USTPUTC(CTLESC, out);
10497 USTPUTC(c, out);
10498 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010499 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010500 c = pgetc2();
10501 if (c == PEOF) {
10502 USTPUTC('\\', out);
10503 pungetc();
10504 } else if (c == '\n') {
10505 if (doprompt)
10506 setprompt(2);
10507 else
10508 setprompt(0);
10509 } else {
10510 if (dblquote && c != '\\' && c != '`' && c != '$'
10511 && (c != '"' || eofmark != NULL))
10512 USTPUTC('\\', out);
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010513 if (SIT(c,SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010514 USTPUTC(CTLESC, out);
10515 else if (eofmark == NULL)
10516 USTPUTC(CTLQUOTEMARK, out);
10517 USTPUTC(c, out);
10518 quotef++;
10519 }
10520 break;
10521 case CSQUOTE:
10522 if (eofmark == NULL)
10523 USTPUTC(CTLQUOTEMARK, out);
10524 syntax = SQSYNTAX;
10525 break;
10526 case CDQUOTE:
10527 if (eofmark == NULL)
10528 USTPUTC(CTLQUOTEMARK, out);
10529 syntax = DQSYNTAX;
10530 dblquote = 1;
10531 break;
10532 case CENDQUOTE:
10533 if (eofmark != NULL && arinest == 0 &&
10534 varnest == 0) {
10535 USTPUTC(c, out);
10536 } else {
10537 if (arinest) {
10538 syntax = ARISYNTAX;
10539 dblquote = 0;
10540 } else if (eofmark == NULL &&
10541 dqvarnest == 0) {
10542 syntax = BASESYNTAX;
10543 dblquote = 0;
10544 }
10545 quotef++;
10546 }
10547 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010548 case CVAR: /* '$' */
10549 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010550 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010551 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010552 if (varnest > 0) {
10553 varnest--;
10554 if (dqvarnest > 0) {
10555 dqvarnest--;
10556 }
10557 USTPUTC(CTLENDVAR, out);
10558 } else {
10559 USTPUTC(c, out);
10560 }
10561 break;
10562#ifdef ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +000010563 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010564 parenlevel++;
10565 USTPUTC(c, out);
10566 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010567 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010568 if (parenlevel > 0) {
10569 USTPUTC(c, out);
10570 --parenlevel;
10571 } else {
10572 if (pgetc() == ')') {
10573 if (--arinest == 0) {
10574 USTPUTC(CTLENDARI, out);
10575 syntax = prevsyntax;
10576 if (syntax == DQSYNTAX)
10577 dblquote = 1;
10578 else
10579 dblquote = 0;
10580 } else
10581 USTPUTC(')', out);
10582 } else {
10583 /*
10584 * unbalanced parens
10585 * (don't 2nd guess - no error)
10586 */
10587 pungetc();
10588 USTPUTC(')', out);
10589 }
10590 }
10591 break;
10592#endif
Eric Andersen2870d962001-07-02 17:27:21 +000010593 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010594 PARSEBACKQOLD();
10595 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010596 case CENDFILE:
10597 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010598 case CIGN:
10599 break;
10600 default:
10601 if (varnest == 0)
Eric Andersen2870d962001-07-02 17:27:21 +000010602 goto endword; /* exit outer loop */
Eric Andersen3102ac42001-07-06 04:26:23 +000010603#ifdef ASH_ALIAS
10604 if (c != PEOA)
10605#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010606 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010607
Eric Andersencb57d552001-06-28 07:25:16 +000010608 }
10609 c = pgetc_macro();
10610 }
10611 }
10612endword:
10613 if (syntax == ARISYNTAX)
10614 synerror("Missing '))'");
10615 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10616 synerror("Unterminated quoted string");
10617 if (varnest != 0) {
10618 startlinno = plinno;
10619 synerror("Missing '}'");
10620 }
10621 USTPUTC('\0', out);
10622 len = out - stackblock();
10623 out = stackblock();
10624 if (eofmark == NULL) {
10625 if ((c == '>' || c == '<')
10626 && quotef == 0
10627 && len <= 2
10628 && (*out == '\0' || is_digit(*out))) {
10629 PARSEREDIR();
10630 return lasttoken = TREDIR;
10631 } else {
10632 pungetc();
10633 }
10634 }
10635 quoteflag = quotef;
10636 backquotelist = bqlist;
10637 grabstackblock(len);
10638 wordtext = out;
10639 return lasttoken = TWORD;
10640/* end of readtoken routine */
10641
10642
10643
10644/*
10645 * Check to see whether we are at the end of the here document. When this
10646 * is called, c is set to the first character of the next input line. If
10647 * we are at the end of the here document, this routine sets the c to PEOF.
10648 */
10649
10650checkend: {
10651 if (eofmark) {
Eric Andersen2870d962001-07-02 17:27:21 +000010652#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010653 if (c == PEOA) {
10654 c = pgetc2();
10655 }
Eric Andersen2870d962001-07-02 17:27:21 +000010656#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010657 if (striptabs) {
10658 while (c == '\t') {
10659 c = pgetc2();
10660 }
10661 }
10662 if (c == *eofmark) {
10663 if (pfgets(line, sizeof line) != NULL) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010664 const char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010665
10666 p = line;
10667 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10668 if (*p == '\n' && *q == '\0') {
10669 c = PEOF;
10670 plinno++;
10671 needprompt = doprompt;
10672 } else {
10673 pushstring(line, strlen(line), NULL);
10674 }
10675 }
10676 }
10677 }
10678 goto checkend_return;
10679}
10680
10681
10682/*
10683 * Parse a redirection operator. The variable "out" points to a string
10684 * specifying the fd to be redirected. The variable "c" contains the
10685 * first character of the redirection operator.
10686 */
10687
10688parseredir: {
10689 char fd = *out;
10690 union node *np;
10691
10692 np = (union node *)stalloc(sizeof (struct nfile));
10693 if (c == '>') {
10694 np->nfile.fd = 1;
10695 c = pgetc();
10696 if (c == '>')
10697 np->type = NAPPEND;
10698 else if (c == '&')
10699 np->type = NTOFD;
10700 else if (c == '|')
10701 np->type = NTOOV;
10702 else {
10703 np->type = NTO;
10704 pungetc();
10705 }
Eric Andersen2870d962001-07-02 17:27:21 +000010706 } else { /* c == '<' */
Eric Andersencb57d552001-06-28 07:25:16 +000010707 np->nfile.fd = 0;
10708 switch (c = pgetc()) {
10709 case '<':
10710 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10711 np = (union node *)stalloc(sizeof (struct nhere));
10712 np->nfile.fd = 0;
10713 }
10714 np->type = NHERE;
10715 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10716 heredoc->here = np;
10717 if ((c = pgetc()) == '-') {
10718 heredoc->striptabs = 1;
10719 } else {
10720 heredoc->striptabs = 0;
10721 pungetc();
10722 }
10723 break;
10724
10725 case '&':
10726 np->type = NFROMFD;
10727 break;
10728
10729 case '>':
10730 np->type = NFROMTO;
10731 break;
10732
10733 default:
10734 np->type = NFROM;
10735 pungetc();
10736 break;
10737 }
10738 }
10739 if (fd != '\0')
10740 np->nfile.fd = digit_val(fd);
10741 redirnode = np;
10742 goto parseredir_return;
10743}
10744
10745
10746/*
10747 * Parse a substitution. At this point, we have read the dollar sign
10748 * and nothing else.
10749 */
10750
10751parsesub: {
10752 int subtype;
10753 int typeloc;
10754 int flags;
10755 char *p;
10756 static const char types[] = "}-+?=";
10757
10758 c = pgetc();
10759 if (
10760 c <= PEOA ||
10761 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10762 ) {
10763 USTPUTC('$', out);
10764 pungetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010765 } else if (c == '(') { /* $(command) or $((arith)) */
Eric Andersencb57d552001-06-28 07:25:16 +000010766 if (pgetc() == '(') {
10767 PARSEARITH();
10768 } else {
10769 pungetc();
10770 PARSEBACKQNEW();
10771 }
10772 } else {
10773 USTPUTC(CTLVAR, out);
10774 typeloc = out - stackblock();
10775 USTPUTC(VSNORMAL, out);
10776 subtype = VSNORMAL;
10777 if (c == '{') {
10778 c = pgetc();
10779 if (c == '#') {
10780 if ((c = pgetc()) == '}')
10781 c = '#';
10782 else
10783 subtype = VSLENGTH;
10784 }
10785 else
10786 subtype = 0;
10787 }
10788 if (c > PEOA && is_name(c)) {
10789 do {
10790 STPUTC(c, out);
10791 c = pgetc();
10792 } while (c > PEOA && is_in_name(c));
10793 } else if (is_digit(c)) {
10794 do {
10795 USTPUTC(c, out);
10796 c = pgetc();
10797 } while (is_digit(c));
10798 }
10799 else if (is_special(c)) {
10800 USTPUTC(c, out);
10801 c = pgetc();
10802 }
10803 else
Eric Andersen2870d962001-07-02 17:27:21 +000010804badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010805
10806 STPUTC('=', out);
10807 flags = 0;
10808 if (subtype == 0) {
10809 switch (c) {
10810 case ':':
10811 flags = VSNUL;
10812 c = pgetc();
10813 /*FALLTHROUGH*/
10814 default:
10815 p = strchr(types, c);
10816 if (p == NULL)
10817 goto badsub;
10818 subtype = p - types + VSNORMAL;
10819 break;
10820 case '%':
10821 case '#':
10822 {
10823 int cc = c;
10824 subtype = c == '#' ? VSTRIMLEFT :
10825 VSTRIMRIGHT;
10826 c = pgetc();
10827 if (c == cc)
10828 subtype++;
10829 else
10830 pungetc();
10831 break;
10832 }
10833 }
10834 } else {
10835 pungetc();
10836 }
10837 if (dblquote || arinest)
10838 flags |= VSQUOTE;
10839 *(stackblock() + typeloc) = subtype | flags;
10840 if (subtype != VSNORMAL) {
10841 varnest++;
10842 if (dblquote) {
10843 dqvarnest++;
10844 }
10845 }
10846 }
10847 goto parsesub_return;
10848}
10849
10850
10851/*
10852 * Called to parse command substitutions. Newstyle is set if the command
10853 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10854 * list of commands (passed by reference), and savelen is the number of
10855 * characters on the top of the stack which must be preserved.
10856 */
10857
10858parsebackq: {
10859 struct nodelist **nlpp;
10860 int savepbq;
10861 union node *n;
10862 char *volatile str;
10863 struct jmploc jmploc;
10864 struct jmploc *volatile savehandler;
10865 int savelen;
10866 int saveprompt;
10867#ifdef __GNUC__
10868 (void) &saveprompt;
10869#endif
10870
10871 savepbq = parsebackquote;
10872 if (setjmp(jmploc.loc)) {
10873 if (str)
10874 ckfree(str);
10875 parsebackquote = 0;
10876 handler = savehandler;
10877 longjmp(handler->loc, 1);
10878 }
10879 INTOFF;
10880 str = NULL;
10881 savelen = out - stackblock();
10882 if (savelen > 0) {
10883 str = ckmalloc(savelen);
10884 memcpy(str, stackblock(), savelen);
10885 }
10886 savehandler = handler;
10887 handler = &jmploc;
10888 INTON;
Eric Andersen2870d962001-07-02 17:27:21 +000010889 if (oldstyle) {
10890 /* We must read until the closing backquote, giving special
10891 treatment to some slashes, and then push the string and
10892 reread it as input, interpreting it normally. */
10893 char *pout;
10894 int pc;
10895 int psavelen;
10896 char *pstr;
Eric Andersencb57d552001-06-28 07:25:16 +000010897
10898
Eric Andersen2870d962001-07-02 17:27:21 +000010899 STARTSTACKSTR(pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010900 for (;;) {
10901 if (needprompt) {
10902 setprompt(2);
10903 needprompt = 0;
10904 }
10905 switch (pc = pgetc()) {
10906 case '`':
10907 goto done;
10908
10909 case '\\':
Eric Andersen2870d962001-07-02 17:27:21 +000010910 if ((pc = pgetc()) == '\n') {
Eric Andersencb57d552001-06-28 07:25:16 +000010911 plinno++;
10912 if (doprompt)
10913 setprompt(2);
10914 else
10915 setprompt(0);
10916 /*
10917 * If eating a newline, avoid putting
10918 * the newline into the new character
10919 * stream (via the STPUTC after the
10920 * switch).
10921 */
10922 continue;
10923 }
Eric Andersen2870d962001-07-02 17:27:21 +000010924 if (pc != '\\' && pc != '`' && pc != '$'
10925 && (!dblquote || pc != '"'))
10926 STPUTC('\\', pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010927 if (pc > PEOA) {
10928 break;
10929 }
10930 /* fall through */
10931
10932 case PEOF:
Eric Andersen2870d962001-07-02 17:27:21 +000010933#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010934 case PEOA:
Eric Andersen2870d962001-07-02 17:27:21 +000010935#endif
10936 startlinno = plinno;
Eric Andersencb57d552001-06-28 07:25:16 +000010937 synerror("EOF in backquote substitution");
10938
10939 case '\n':
10940 plinno++;
10941 needprompt = doprompt;
10942 break;
10943
10944 default:
10945 break;
10946 }
10947 STPUTC(pc, pout);
Eric Andersen2870d962001-07-02 17:27:21 +000010948 }
Eric Andersencb57d552001-06-28 07:25:16 +000010949done:
Eric Andersen2870d962001-07-02 17:27:21 +000010950 STPUTC('\0', pout);
10951 psavelen = pout - stackblock();
10952 if (psavelen > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010953 pstr = grabstackstr(pout);
10954 setinputstring(pstr);
Eric Andersen2870d962001-07-02 17:27:21 +000010955 }
10956 }
Eric Andersencb57d552001-06-28 07:25:16 +000010957 nlpp = &bqlist;
10958 while (*nlpp)
10959 nlpp = &(*nlpp)->next;
10960 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10961 (*nlpp)->next = NULL;
10962 parsebackquote = oldstyle;
10963
10964 if (oldstyle) {
10965 saveprompt = doprompt;
10966 doprompt = 0;
10967 }
10968
10969 n = list(0);
10970
10971 if (oldstyle)
10972 doprompt = saveprompt;
10973 else {
10974 if (readtoken() != TRP)
10975 synexpect(TRP);
10976 }
10977
10978 (*nlpp)->n = n;
Eric Andersen2870d962001-07-02 17:27:21 +000010979 if (oldstyle) {
Eric Andersencb57d552001-06-28 07:25:16 +000010980 /*
10981 * Start reading from old file again, ignoring any pushed back
10982 * tokens left from the backquote parsing
10983 */
Eric Andersen2870d962001-07-02 17:27:21 +000010984 popfile();
Eric Andersencb57d552001-06-28 07:25:16 +000010985 tokpushback = 0;
10986 }
10987 while (stackblocksize() <= savelen)
10988 growstackblock();
10989 STARTSTACKSTR(out);
10990 if (str) {
10991 memcpy(out, str, savelen);
10992 STADJUST(savelen, out);
10993 INTOFF;
10994 ckfree(str);
10995 str = NULL;
10996 INTON;
10997 }
10998 parsebackquote = savepbq;
10999 handler = savehandler;
11000 if (arinest || dblquote)
11001 USTPUTC(CTLBACKQ | CTLQUOTE, out);
11002 else
11003 USTPUTC(CTLBACKQ, out);
11004 if (oldstyle)
11005 goto parsebackq_oldreturn;
11006 else
11007 goto parsebackq_newreturn;
11008}
11009
11010/*
11011 * Parse an arithmetic expansion (indicate start of one and set state)
11012 */
11013parsearith: {
11014
11015 if (++arinest == 1) {
11016 prevsyntax = syntax;
11017 syntax = ARISYNTAX;
11018 USTPUTC(CTLARI, out);
11019 if (dblquote)
11020 USTPUTC('"',out);
11021 else
11022 USTPUTC(' ',out);
11023 } else {
11024 /*
11025 * we collapse embedded arithmetic expansion to
11026 * parenthesis, which should be equivalent
11027 */
11028 USTPUTC('(', out);
11029 }
11030 goto parsearith_return;
11031}
11032
11033} /* end of readtoken */
11034
11035
Eric Andersencb57d552001-06-28 07:25:16 +000011036/*
11037 * Returns true if the text contains nothing to expand (no dollar signs
11038 * or backquotes).
11039 */
11040
11041static int
11042noexpand(text)
11043 char *text;
11044 {
11045 char *p;
11046 char c;
11047
11048 p = text;
11049 while ((c = *p++) != '\0') {
11050 if (c == CTLQUOTEMARK)
11051 continue;
11052 if (c == CTLESC)
11053 p++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011054 else if (SIT(c,BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000011055 return 0;
11056 }
11057 return 1;
11058}
11059
11060
11061/*
11062 * Return true if the argument is a legal variable name (a letter or
11063 * underscore followed by zero or more letters, underscores, and digits).
11064 */
11065
11066static int
Eric Andersen2870d962001-07-02 17:27:21 +000011067goodname(const char *name)
11068{
11069 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000011070
11071 p = name;
11072 if (! is_name(*p))
11073 return 0;
11074 while (*++p) {
11075 if (! is_in_name(*p))
11076 return 0;
11077 }
11078 return 1;
11079}
11080
11081
11082/*
11083 * Called when an unexpected token is read during the parse. The argument
11084 * is the token that is expected, or -1 if more than one type of token can
11085 * occur at this point.
11086 */
11087
11088static void
11089synexpect(token)
11090 int token;
11091{
11092 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011093 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000011094
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011095 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
11096 if (token >= 0)
11097 sprintf(msg+l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000011098 synerror(msg);
11099 /* NOTREACHED */
11100}
11101
11102
11103static void
Eric Andersen2870d962001-07-02 17:27:21 +000011104synerror(const char *msg)
11105{
Eric Andersencb57d552001-06-28 07:25:16 +000011106 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +000011107 out2fmt("%s: %d: ", commandname, startlinno);
11108 out2fmt("Syntax error: %s\n", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000011109 error((char *)NULL);
11110 /* NOTREACHED */
11111}
11112
Eric Andersencb57d552001-06-28 07:25:16 +000011113
11114/*
11115 * called by editline -- any expansions to the prompt
11116 * should be added here.
11117 */
Eric Andersen2870d962001-07-02 17:27:21 +000011118static void
Eric Andersen62483552001-07-10 06:09:16 +000011119setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000011120{
Eric Andersen62483552001-07-10 06:09:16 +000011121 char *prompt;
11122 switch (whichprompt) {
11123 case 1:
11124 prompt = ps1val();
11125 break;
11126 case 2:
11127 prompt = ps2val();
11128 break;
11129 default: /* 0 */
11130 prompt = "";
11131 }
11132 putprompt(prompt);
Eric Andersencb57d552001-06-28 07:25:16 +000011133}
11134
Eric Andersencb57d552001-06-28 07:25:16 +000011135
Eric Andersencb57d552001-06-28 07:25:16 +000011136/*
11137 * Code for dealing with input/output redirection.
11138 */
11139
Eric Andersen2870d962001-07-02 17:27:21 +000011140#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000011141#ifndef PIPE_BUF
Eric Andersen2870d962001-07-02 17:27:21 +000011142# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000011143#else
11144# define PIPESIZE PIPE_BUF
11145#endif
11146
11147
Eric Andersen62483552001-07-10 06:09:16 +000011148/*
11149 * Open a file in noclobber mode.
11150 * The code was copied from bash.
11151 */
11152static inline int
11153noclobberopen(const char *fname)
11154{
11155 int r, fd;
11156 struct stat finfo, finfo2;
11157
11158 /*
11159 * If the file exists and is a regular file, return an error
11160 * immediately.
11161 */
11162 r = stat(fname, &finfo);
11163 if (r == 0 && S_ISREG(finfo.st_mode)) {
11164 errno = EEXIST;
11165 return -1;
11166 }
11167
11168 /*
11169 * If the file was not present (r != 0), make sure we open it
11170 * exclusively so that if it is created before we open it, our open
11171 * will fail. Make sure that we do not truncate an existing file.
11172 * Note that we don't turn on O_EXCL unless the stat failed -- if the
11173 * file was not a regular file, we leave O_EXCL off.
11174 */
11175 if (r != 0)
11176 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
11177 fd = open(fname, O_WRONLY|O_CREAT, 0666);
11178
11179 /* If the open failed, return the file descriptor right away. */
11180 if (fd < 0)
11181 return fd;
11182
11183 /*
11184 * OK, the open succeeded, but the file may have been changed from a
11185 * non-regular file to a regular file between the stat and the open.
11186 * We are assuming that the O_EXCL open handles the case where FILENAME
11187 * did not exist and is symlinked to an existing file between the stat
11188 * and open.
11189 */
11190
11191 /*
11192 * If we can open it and fstat the file descriptor, and neither check
11193 * revealed that it was a regular file, and the file has not been
11194 * replaced, return the file descriptor.
11195 */
11196 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
11197 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
11198 return fd;
11199
11200 /* The file has been replaced. badness. */
11201 close(fd);
11202 errno = EEXIST;
11203 return -1;
11204}
Eric Andersencb57d552001-06-28 07:25:16 +000011205
11206/*
Eric Andersen62483552001-07-10 06:09:16 +000011207 * Handle here documents. Normally we fork off a process to write the
11208 * data to a pipe. If the document is short, we can stuff the data in
11209 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000011210 */
11211
Eric Andersen62483552001-07-10 06:09:16 +000011212static inline int
11213openhere(const union node *redir)
11214{
11215 int pip[2];
11216 int len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011217
Eric Andersen62483552001-07-10 06:09:16 +000011218 if (pipe(pip) < 0)
11219 error("Pipe call failed");
11220 if (redir->type == NHERE) {
11221 len = strlen(redir->nhere.doc->narg.text);
11222 if (len <= PIPESIZE) {
11223 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11224 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011225 }
Eric Andersencb57d552001-06-28 07:25:16 +000011226 }
Eric Andersen62483552001-07-10 06:09:16 +000011227 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
11228 close(pip[0]);
11229 signal(SIGINT, SIG_IGN);
11230 signal(SIGQUIT, SIG_IGN);
11231 signal(SIGHUP, SIG_IGN);
11232#ifdef SIGTSTP
11233 signal(SIGTSTP, SIG_IGN);
11234#endif
11235 signal(SIGPIPE, SIG_DFL);
11236 if (redir->type == NHERE)
11237 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11238 else
11239 expandhere(redir->nhere.doc, pip[1]);
11240 _exit(0);
11241 }
11242out:
11243 close(pip[1]);
11244 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000011245}
11246
11247
Eric Andersen62483552001-07-10 06:09:16 +000011248static inline int
11249openredirect(const union node *redir)
11250{
Eric Andersencb57d552001-06-28 07:25:16 +000011251 char *fname;
11252 int f;
11253
11254 switch (redir->nfile.type) {
11255 case NFROM:
11256 fname = redir->nfile.expfname;
11257 if ((f = open(fname, O_RDONLY)) < 0)
11258 goto eopen;
11259 break;
11260 case NFROMTO:
11261 fname = redir->nfile.expfname;
11262 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
11263 goto ecreate;
11264 break;
11265 case NTO:
11266 /* Take care of noclobber mode. */
11267 if (Cflag) {
11268 fname = redir->nfile.expfname;
11269 if ((f = noclobberopen(fname)) < 0)
11270 goto ecreate;
11271 break;
11272 }
11273 case NTOOV:
11274 fname = redir->nfile.expfname;
11275#ifdef O_CREAT
11276 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
11277 goto ecreate;
11278#else
11279 if ((f = creat(fname, 0666)) < 0)
11280 goto ecreate;
11281#endif
11282 break;
11283 case NAPPEND:
11284 fname = redir->nfile.expfname;
11285#ifdef O_APPEND
11286 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
11287 goto ecreate;
11288#else
11289 if ((f = open(fname, O_WRONLY)) < 0
11290 && (f = creat(fname, 0666)) < 0)
11291 goto ecreate;
11292 lseek(f, (off_t)0, 2);
11293#endif
11294 break;
11295 default:
11296#ifdef DEBUG
11297 abort();
11298#endif
11299 /* Fall through to eliminate warning. */
11300 case NTOFD:
11301 case NFROMFD:
11302 f = -1;
11303 break;
11304 case NHERE:
11305 case NXHERE:
11306 f = openhere(redir);
11307 break;
11308 }
11309
11310 return f;
11311ecreate:
11312 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11313eopen:
11314 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11315}
11316
11317
Eric Andersen62483552001-07-10 06:09:16 +000011318/*
11319 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11320 * old file descriptors are stashed away so that the redirection can be
11321 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11322 * standard output, and the standard error if it becomes a duplicate of
11323 * stdout.
11324 */
11325
Eric Andersencb57d552001-06-28 07:25:16 +000011326static void
Eric Andersen62483552001-07-10 06:09:16 +000011327redirect(union node *redir, int flags)
11328{
11329 union node *n;
11330 struct redirtab *sv = NULL;
11331 int i;
11332 int fd;
11333 int newfd;
11334 int try;
11335 int fd1dup = flags & REDIR_BACKQ;; /* stdout `cmd` redir to pipe */
11336
11337 if (flags & REDIR_PUSH) {
11338 sv = ckmalloc(sizeof (struct redirtab));
11339 for (i = 0 ; i < 10 ; i++)
11340 sv->renamed[i] = EMPTY;
11341 sv->next = redirlist;
11342 redirlist = sv;
11343 }
11344 for (n = redir ; n ; n = n->nfile.next) {
11345 fd = n->nfile.fd;
11346 try = 0;
11347 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11348 n->ndup.dupfd == fd)
11349 continue; /* redirect from/to same file descriptor */
11350
11351 INTOFF;
11352 newfd = openredirect(n);
11353 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
11354 if (newfd == fd) {
11355 try++;
11356 } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
11357 switch (errno) {
11358 case EBADF:
11359 if (!try) {
11360 dupredirect(n, newfd, fd1dup);
11361 try++;
11362 break;
11363 }
11364 /* FALLTHROUGH*/
11365 default:
11366 if (newfd >= 0) {
11367 close(newfd);
11368 }
11369 INTON;
11370 error("%d: %m", fd);
11371 /* NOTREACHED */
11372 }
11373 }
11374 if (!try) {
11375 close(fd);
11376 if (flags & REDIR_PUSH) {
11377 sv->renamed[fd] = i;
11378 }
11379 }
11380 } else if (fd != newfd) {
11381 close(fd);
11382 }
11383 if (fd == 0)
11384 fd0_redirected++;
11385 if (!try)
11386 dupredirect(n, newfd, fd1dup);
11387 INTON;
11388 }
11389}
11390
11391
11392static void
11393dupredirect(const union node *redir, int f, int fd1dup)
Eric Andersen2870d962001-07-02 17:27:21 +000011394{
Eric Andersencb57d552001-06-28 07:25:16 +000011395 int fd = redir->nfile.fd;
11396
Eric Andersen62483552001-07-10 06:09:16 +000011397 if(fd==1)
11398 fd1dup = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011399 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Eric Andersen2870d962001-07-02 17:27:21 +000011400 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
Eric Andersen62483552001-07-10 06:09:16 +000011401 if (redir->ndup.dupfd!=1 || fd1dup!=1)
Eric Andersencb57d552001-06-28 07:25:16 +000011402 dup_as_newfd(redir->ndup.dupfd, fd);
11403 }
11404 return;
11405 }
11406
11407 if (f != fd) {
11408 dup_as_newfd(f, fd);
11409 close(f);
11410 }
11411 return;
11412}
11413
11414
Eric Andersencb57d552001-06-28 07:25:16 +000011415
Eric Andersencb57d552001-06-28 07:25:16 +000011416/*
11417 * Undo the effects of the last redirection.
11418 */
11419
11420static void
Eric Andersen2870d962001-07-02 17:27:21 +000011421popredir(void)
11422{
Eric Andersencb57d552001-06-28 07:25:16 +000011423 struct redirtab *rp = redirlist;
11424 int i;
11425
11426 INTOFF;
11427 for (i = 0 ; i < 10 ; i++) {
11428 if (rp->renamed[i] != EMPTY) {
Eric Andersen2870d962001-07-02 17:27:21 +000011429 if (i == 0)
11430 fd0_redirected--;
Eric Andersencb57d552001-06-28 07:25:16 +000011431 close(i);
11432 if (rp->renamed[i] >= 0) {
11433 dup_as_newfd(rp->renamed[i], i);
11434 close(rp->renamed[i]);
11435 }
Eric Andersencb57d552001-06-28 07:25:16 +000011436 }
11437 }
11438 redirlist = rp->next;
11439 ckfree(rp);
11440 INTON;
11441}
11442
11443/*
Eric Andersencb57d552001-06-28 07:25:16 +000011444 * Discard all saved file descriptors.
11445 */
11446
11447static void
Eric Andersen2870d962001-07-02 17:27:21 +000011448clearredir(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000011449 struct redirtab *rp;
11450 int i;
11451
11452 for (rp = redirlist ; rp ; rp = rp->next) {
11453 for (i = 0 ; i < 10 ; i++) {
11454 if (rp->renamed[i] >= 0) {
11455 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011456 }
11457 rp->renamed[i] = EMPTY;
11458 }
11459 }
Eric Andersencb57d552001-06-28 07:25:16 +000011460}
11461
11462
Eric Andersencb57d552001-06-28 07:25:16 +000011463/*
11464 * Copy a file descriptor to be >= to. Returns -1
11465 * if the source file descriptor is closed, EMPTY if there are no unused
11466 * file descriptors left.
11467 */
11468
11469static int
11470dup_as_newfd(from, to)
11471 int from;
11472 int to;
11473{
11474 int newfd;
11475
11476 newfd = fcntl(from, F_DUPFD, to);
11477 if (newfd < 0) {
11478 if (errno == EMFILE)
11479 return EMPTY;
11480 else
Eric Andersen2870d962001-07-02 17:27:21 +000011481 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011482 }
11483 return newfd;
11484}
11485
Eric Andersencb57d552001-06-28 07:25:16 +000011486#ifdef DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +000011487static void shtree (union node *, int, char *, FILE*);
11488static void shcmd (union node *, FILE *);
11489static void sharg (union node *, FILE *);
11490static void indent (int, char *, FILE *);
11491static void trstring (char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011492
11493
11494static void
11495showtree(n)
11496 union node *n;
11497{
11498 trputs("showtree called\n");
11499 shtree(n, 1, NULL, stdout);
11500}
11501
11502
11503static void
11504shtree(n, ind, pfx, fp)
11505 union node *n;
11506 int ind;
11507 char *pfx;
11508 FILE *fp;
11509{
11510 struct nodelist *lp;
11511 const char *s;
11512
11513 if (n == NULL)
11514 return;
11515
11516 indent(ind, pfx, fp);
11517 switch(n->type) {
11518 case NSEMI:
11519 s = "; ";
11520 goto binop;
11521 case NAND:
11522 s = " && ";
11523 goto binop;
11524 case NOR:
11525 s = " || ";
11526binop:
11527 shtree(n->nbinary.ch1, ind, NULL, fp);
11528 /* if (ind < 0) */
11529 fputs(s, fp);
11530 shtree(n->nbinary.ch2, ind, NULL, fp);
11531 break;
11532 case NCMD:
11533 shcmd(n, fp);
11534 if (ind >= 0)
11535 putc('\n', fp);
11536 break;
11537 case NPIPE:
11538 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11539 shcmd(lp->n, fp);
11540 if (lp->next)
11541 fputs(" | ", fp);
11542 }
11543 if (n->npipe.backgnd)
11544 fputs(" &", fp);
11545 if (ind >= 0)
11546 putc('\n', fp);
11547 break;
11548 default:
11549 fprintf(fp, "<node type %d>", n->type);
11550 if (ind >= 0)
11551 putc('\n', fp);
11552 break;
11553 }
11554}
11555
11556
11557
11558static void
11559shcmd(cmd, fp)
11560 union node *cmd;
11561 FILE *fp;
11562{
11563 union node *np;
11564 int first;
11565 const char *s;
11566 int dftfd;
11567
11568 first = 1;
11569 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11570 if (! first)
11571 putchar(' ');
11572 sharg(np, fp);
11573 first = 0;
11574 }
11575 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11576 if (! first)
11577 putchar(' ');
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011578#if 1
11579 s = "*error*";
11580 dftfd = 0;
11581 if ((np->nfile.type <= NFROMFD) && (np->nfile.type >= NTO)) {
11582 s = redir_strings[np->nfile.type - NTO];
11583 if (*s == '>') {
11584 dftfd = 1;
11585 }
11586 }
11587#else
Eric Andersencb57d552001-06-28 07:25:16 +000011588 switch (np->nfile.type) {
Eric Andersen2870d962001-07-02 17:27:21 +000011589 case NTO: s = ">"; dftfd = 1; break;
11590 case NAPPEND: s = ">>"; dftfd = 1; break;
11591 case NTOFD: s = ">&"; dftfd = 1; break;
11592 case NTOOV: s = ">|"; dftfd = 1; break;
11593 case NFROM: s = "<"; dftfd = 0; break;
11594 case NFROMFD: s = "<&"; dftfd = 0; break;
11595 case NFROMTO: s = "<>"; dftfd = 0; break;
11596 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011597 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011598#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011599 if (np->nfile.fd != dftfd)
11600 fprintf(fp, "%d", np->nfile.fd);
11601 fputs(s, fp);
11602 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11603 fprintf(fp, "%d", np->ndup.dupfd);
11604 } else {
11605 sharg(np->nfile.fname, fp);
11606 }
11607 first = 0;
11608 }
11609}
11610
11611
11612
11613static void
11614sharg(arg, fp)
11615 union node *arg;
11616 FILE *fp;
11617 {
11618 char *p;
11619 struct nodelist *bqlist;
11620 int subtype;
11621
11622 if (arg->type != NARG) {
11623 printf("<node type %d>\n", arg->type);
11624 fflush(stdout);
11625 abort();
11626 }
11627 bqlist = arg->narg.backquote;
11628 for (p = arg->narg.text ; *p ; p++) {
11629 switch (*p) {
11630 case CTLESC:
11631 putc(*++p, fp);
11632 break;
11633 case CTLVAR:
11634 putc('$', fp);
11635 putc('{', fp);
11636 subtype = *++p;
11637 if (subtype == VSLENGTH)
11638 putc('#', fp);
11639
11640 while (*p != '=')
11641 putc(*p++, fp);
11642
11643 if (subtype & VSNUL)
11644 putc(':', fp);
11645
11646 switch (subtype & VSTYPE) {
11647 case VSNORMAL:
11648 putc('}', fp);
11649 break;
11650 case VSMINUS:
11651 putc('-', fp);
11652 break;
11653 case VSPLUS:
11654 putc('+', fp);
11655 break;
11656 case VSQUESTION:
11657 putc('?', fp);
11658 break;
11659 case VSASSIGN:
11660 putc('=', fp);
11661 break;
11662 case VSTRIMLEFT:
11663 putc('#', fp);
11664 break;
11665 case VSTRIMLEFTMAX:
11666 putc('#', fp);
11667 putc('#', fp);
11668 break;
11669 case VSTRIMRIGHT:
11670 putc('%', fp);
11671 break;
11672 case VSTRIMRIGHTMAX:
11673 putc('%', fp);
11674 putc('%', fp);
11675 break;
11676 case VSLENGTH:
11677 break;
11678 default:
11679 printf("<subtype %d>", subtype);
11680 }
11681 break;
11682 case CTLENDVAR:
11683 putc('}', fp);
11684 break;
11685 case CTLBACKQ:
11686 case CTLBACKQ|CTLQUOTE:
11687 putc('$', fp);
11688 putc('(', fp);
11689 shtree(bqlist->n, -1, NULL, fp);
11690 putc(')', fp);
11691 break;
11692 default:
11693 putc(*p, fp);
11694 break;
11695 }
11696 }
11697}
11698
11699
11700static void
11701indent(amount, pfx, fp)
11702 int amount;
11703 char *pfx;
11704 FILE *fp;
11705{
11706 int i;
11707
11708 for (i = 0 ; i < amount ; i++) {
11709 if (pfx && i == amount - 1)
11710 fputs(pfx, fp);
11711 putc('\t', fp);
11712 }
11713}
11714#endif
11715
11716
11717
11718/*
11719 * Debugging stuff.
11720 */
11721
11722
11723#ifdef DEBUG
11724FILE *tracefile;
11725
11726#if DEBUG == 2
11727static int debug = 1;
11728#else
11729static int debug = 0;
11730#endif
11731
11732
11733static void
11734trputc(c)
11735 int c;
11736{
11737 if (tracefile == NULL)
11738 return;
11739 putc(c, tracefile);
11740 if (c == '\n')
11741 fflush(tracefile);
11742}
11743
11744static void
11745trace(const char *fmt, ...)
11746{
11747 va_list va;
Eric Andersencb57d552001-06-28 07:25:16 +000011748 va_start(va, fmt);
Eric Andersencb57d552001-06-28 07:25:16 +000011749 if (tracefile != NULL) {
11750 (void) vfprintf(tracefile, fmt, va);
11751 if (strchr(fmt, '\n'))
11752 (void) fflush(tracefile);
11753 }
11754 va_end(va);
11755}
11756
11757
11758static void
11759trputs(s)
11760 const char *s;
11761{
11762 if (tracefile == NULL)
11763 return;
11764 fputs(s, tracefile);
11765 if (strchr(s, '\n'))
11766 fflush(tracefile);
11767}
11768
11769
11770static void
11771trstring(s)
11772 char *s;
11773{
11774 char *p;
11775 char c;
11776
11777 if (tracefile == NULL)
11778 return;
11779 putc('"', tracefile);
11780 for (p = s ; *p ; p++) {
11781 switch (*p) {
11782 case '\n': c = 'n'; goto backslash;
11783 case '\t': c = 't'; goto backslash;
11784 case '\r': c = 'r'; goto backslash;
11785 case '"': c = '"'; goto backslash;
11786 case '\\': c = '\\'; goto backslash;
11787 case CTLESC: c = 'e'; goto backslash;
11788 case CTLVAR: c = 'v'; goto backslash;
11789 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11790 case CTLBACKQ: c = 'q'; goto backslash;
11791 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
Eric Andersen2870d962001-07-02 17:27:21 +000011792backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011793 putc(c, tracefile);
11794 break;
11795 default:
11796 if (*p >= ' ' && *p <= '~')
11797 putc(*p, tracefile);
11798 else {
11799 putc('\\', tracefile);
11800 putc(*p >> 6 & 03, tracefile);
11801 putc(*p >> 3 & 07, tracefile);
11802 putc(*p & 07, tracefile);
11803 }
11804 break;
11805 }
11806 }
11807 putc('"', tracefile);
11808}
11809
11810
11811static void
11812trargs(ap)
11813 char **ap;
11814{
11815 if (tracefile == NULL)
11816 return;
11817 while (*ap) {
11818 trstring(*ap++);
11819 if (*ap)
11820 putc(' ', tracefile);
11821 else
11822 putc('\n', tracefile);
11823 }
11824 fflush(tracefile);
11825}
11826
11827
11828static void
11829opentrace() {
11830 char s[100];
11831#ifdef O_APPEND
11832 int flags;
11833#endif
11834
11835 if (!debug)
11836 return;
11837#ifdef not_this_way
11838 {
11839 char *p;
11840 if ((p = getenv("HOME")) == NULL) {
11841 if (geteuid() == 0)
11842 p = "/";
11843 else
11844 p = "/tmp";
11845 }
Eric Andersen2870d962001-07-02 17:27:21 +000011846 strcpy(s, p);
Eric Andersencb57d552001-06-28 07:25:16 +000011847 strcat(s, "/trace");
11848 }
11849#else
Eric Andersen2870d962001-07-02 17:27:21 +000011850 strcpy(s, "./trace");
Eric Andersencb57d552001-06-28 07:25:16 +000011851#endif /* not_this_way */
11852 if ((tracefile = fopen(s, "a")) == NULL) {
11853 fprintf(stderr, "Can't open %s\n", s);
11854 return;
11855 }
11856#ifdef O_APPEND
11857 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11858 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11859#endif
11860 fputs("\nTracing started.\n", tracefile);
11861 fflush(tracefile);
11862}
11863#endif /* DEBUG */
11864
11865
11866/*
Eric Andersencb57d552001-06-28 07:25:16 +000011867 * The trap builtin.
11868 */
11869
11870static int
11871trapcmd(argc, argv)
11872 int argc;
11873 char **argv;
11874{
11875 char *action;
11876 char **ap;
11877 int signo;
11878
11879 if (argc <= 1) {
11880 for (signo = 0 ; signo < NSIG ; signo++) {
11881 if (trap[signo] != NULL) {
11882 char *p;
Eric Andersen34506362001-08-02 05:02:46 +000011883 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011884
11885 p = single_quote(trap[signo]);
Eric Andersen34506362001-08-02 05:02:46 +000011886 sn = sys_siglist[signo];
11887 if(sn==NULL)
11888 sn = u_signal_names(0, &signo, 0);
11889 if(sn==NULL)
11890 sn = "???";
11891 printf("trap -- %s %s\n", p, sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011892 stunalloc(p);
11893 }
11894 }
11895 return 0;
11896 }
11897 ap = argv + 1;
11898 if (argc == 2)
11899 action = NULL;
11900 else
11901 action = *ap++;
11902 while (*ap) {
11903 if ((signo = decode_signal(*ap, 0)) < 0)
11904 error("%s: bad trap", *ap);
11905 INTOFF;
11906 if (action) {
11907 if (action[0] == '-' && action[1] == '\0')
11908 action = NULL;
11909 else
11910 action = savestr(action);
11911 }
11912 if (trap[signo])
11913 ckfree(trap[signo]);
11914 trap[signo] = action;
11915 if (signo != 0)
11916 setsignal(signo);
11917 INTON;
11918 ap++;
11919 }
11920 return 0;
11921}
11922
11923
11924
Eric Andersencb57d552001-06-28 07:25:16 +000011925
11926
11927
11928/*
11929 * Set the signal handler for the specified signal. The routine figures
11930 * out what it should be set to.
11931 */
11932
11933static void
Eric Andersen2870d962001-07-02 17:27:21 +000011934setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011935{
11936 int action;
11937 char *t;
11938 struct sigaction act;
11939
11940 if ((t = trap[signo]) == NULL)
11941 action = S_DFL;
11942 else if (*t != '\0')
11943 action = S_CATCH;
11944 else
11945 action = S_IGN;
11946 if (rootshell && action == S_DFL) {
11947 switch (signo) {
11948 case SIGINT:
11949 if (iflag || minusc || sflag == 0)
11950 action = S_CATCH;
11951 break;
11952 case SIGQUIT:
11953#ifdef DEBUG
11954 {
Eric Andersencb57d552001-06-28 07:25:16 +000011955
11956 if (debug)
11957 break;
11958 }
11959#endif
11960 /* FALLTHROUGH */
11961 case SIGTERM:
11962 if (iflag)
11963 action = S_IGN;
11964 break;
Eric Andersen2870d962001-07-02 17:27:21 +000011965#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000011966 case SIGTSTP:
11967 case SIGTTOU:
11968 if (mflag)
11969 action = S_IGN;
11970 break;
11971#endif
11972 }
11973 }
11974
11975 t = &sigmode[signo - 1];
11976 if (*t == 0) {
11977 /*
11978 * current setting unknown
11979 */
11980 if (sigaction(signo, 0, &act) == -1) {
11981 /*
11982 * Pretend it worked; maybe we should give a warning
11983 * here, but other shells don't. We don't alter
11984 * sigmode, so that we retry every time.
11985 */
11986 return;
11987 }
11988 if (act.sa_handler == SIG_IGN) {
11989 if (mflag && (signo == SIGTSTP ||
11990 signo == SIGTTIN || signo == SIGTTOU)) {
Eric Andersen2870d962001-07-02 17:27:21 +000011991 *t = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000011992 } else
11993 *t = S_HARD_IGN;
11994 } else {
Eric Andersen2870d962001-07-02 17:27:21 +000011995 *t = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000011996 }
11997 }
11998 if (*t == S_HARD_IGN || *t == action)
11999 return;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000012000 act.sa_handler = ((action == S_CATCH) ? onsig
12001 : ((action == S_IGN) ? SIG_IGN : SIG_DFL));
Eric Andersencb57d552001-06-28 07:25:16 +000012002 *t = action;
12003 act.sa_flags = 0;
12004 sigemptyset(&act.sa_mask);
12005 sigaction(signo, &act, 0);
12006}
12007
12008/*
12009 * Ignore a signal.
12010 */
12011
12012static void
12013ignoresig(signo)
12014 int signo;
12015{
12016 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
12017 signal(signo, SIG_IGN);
12018 }
12019 sigmode[signo - 1] = S_HARD_IGN;
12020}
12021
12022
Eric Andersencb57d552001-06-28 07:25:16 +000012023/*
12024 * Signal handler.
12025 */
12026
12027static void
Eric Andersen2870d962001-07-02 17:27:21 +000012028onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000012029{
12030 if (signo == SIGINT && trap[SIGINT] == NULL) {
12031 onint();
12032 return;
12033 }
12034 gotsig[signo - 1] = 1;
12035 pendingsigs++;
12036}
12037
12038
Eric Andersencb57d552001-06-28 07:25:16 +000012039/*
12040 * Called to execute a trap. Perhaps we should avoid entering new trap
12041 * handlers while we are executing a trap handler.
12042 */
12043
12044static void
Eric Andersen2870d962001-07-02 17:27:21 +000012045dotrap(void)
12046{
Eric Andersencb57d552001-06-28 07:25:16 +000012047 int i;
12048 int savestatus;
12049
12050 for (;;) {
12051 for (i = 1 ; ; i++) {
12052 if (gotsig[i - 1])
12053 break;
12054 if (i >= NSIG - 1)
12055 goto done;
12056 }
12057 gotsig[i - 1] = 0;
12058 savestatus=exitstatus;
12059 evalstring(trap[i], 0);
12060 exitstatus=savestatus;
12061 }
12062done:
12063 pendingsigs = 0;
12064}
12065
Eric Andersencb57d552001-06-28 07:25:16 +000012066/*
12067 * Called to exit the shell.
12068 */
12069
12070static void
Eric Andersen2870d962001-07-02 17:27:21 +000012071exitshell(int status)
Eric Andersencb57d552001-06-28 07:25:16 +000012072{
12073 struct jmploc loc1, loc2;
12074 char *p;
12075
12076 TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
12077 if (setjmp(loc1.loc)) {
12078 goto l1;
12079 }
12080 if (setjmp(loc2.loc)) {
12081 goto l2;
12082 }
12083 handler = &loc1;
12084 if ((p = trap[0]) != NULL && *p != '\0') {
12085 trap[0] = NULL;
12086 evalstring(p, 0);
12087 }
Eric Andersen2870d962001-07-02 17:27:21 +000012088l1: handler = &loc2; /* probably unnecessary */
Eric Andersencb57d552001-06-28 07:25:16 +000012089 flushall();
Eric Andersen2870d962001-07-02 17:27:21 +000012090#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000012091 setjobctl(0);
12092#endif
12093l2: _exit(status);
12094 /* NOTREACHED */
12095}
12096
12097static int decode_signal(const char *string, int minsig)
12098{
12099 int signo;
Eric Andersen34506362001-08-02 05:02:46 +000012100 const char *name = u_signal_names(string, &signo, minsig);
Eric Andersencb57d552001-06-28 07:25:16 +000012101
Eric Andersen34506362001-08-02 05:02:46 +000012102 return name ? signo : -1;
Eric Andersencb57d552001-06-28 07:25:16 +000012103}
Eric Andersen34506362001-08-02 05:02:46 +000012104
Eric Andersen2870d962001-07-02 17:27:21 +000012105static struct var **hashvar (const char *);
12106static void showvars (const char *, int, int);
12107static struct var **findvar (struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000012108
12109/*
12110 * Initialize the varable symbol tables and import the environment
12111 */
12112
Eric Andersencb57d552001-06-28 07:25:16 +000012113/*
12114 * This routine initializes the builtin variables. It is called when the
12115 * shell is initialized and again when a shell procedure is spawned.
12116 */
12117
12118static void
12119initvar() {
12120 const struct varinit *ip;
12121 struct var *vp;
12122 struct var **vpp;
12123
12124 for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
12125 if ((vp->flags & VEXPORT) == 0) {
12126 vpp = hashvar(ip->text);
12127 vp->next = *vpp;
12128 *vpp = vp;
12129 vp->text = strdup(ip->text);
12130 vp->flags = ip->flags;
12131 vp->func = ip->func;
12132 }
12133 }
12134 /*
12135 * PS1 depends on uid
12136 */
12137 if ((vps1.flags & VEXPORT) == 0) {
12138 vpp = hashvar("PS1=");
12139 vps1.next = *vpp;
12140 *vpp = &vps1;
12141 vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# ");
12142 vps1.flags = VSTRFIXED|VTEXTFIXED;
12143 }
12144}
12145
12146/*
12147 * Set the value of a variable. The flags argument is ored with the
12148 * flags of the variable. If val is NULL, the variable is unset.
12149 */
12150
12151static void
12152setvar(name, val, flags)
12153 const char *name, *val;
12154 int flags;
12155{
12156 const char *p;
12157 int len;
12158 int namelen;
12159 char *nameeq;
12160 int isbad;
12161 int vallen = 0;
12162
12163 isbad = 0;
12164 p = name;
12165 if (! is_name(*p))
12166 isbad = 1;
12167 p++;
12168 for (;;) {
12169 if (! is_in_name(*p)) {
12170 if (*p == '\0' || *p == '=')
12171 break;
12172 isbad = 1;
12173 }
12174 p++;
12175 }
12176 namelen = p - name;
12177 if (isbad)
12178 error("%.*s: bad variable name", namelen, name);
Eric Andersen2870d962001-07-02 17:27:21 +000012179 len = namelen + 2; /* 2 is space for '=' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +000012180 if (val == NULL) {
12181 flags |= VUNSET;
12182 } else {
12183 len += vallen = strlen(val);
12184 }
12185 INTOFF;
12186 nameeq = ckmalloc(len);
12187 memcpy(nameeq, name, namelen);
12188 nameeq[namelen] = '=';
12189 if (val) {
12190 memcpy(nameeq + namelen + 1, val, vallen + 1);
12191 } else {
12192 nameeq[namelen + 1] = '\0';
12193 }
12194 setvareq(nameeq, flags);
12195 INTON;
12196}
12197
12198
12199
12200/*
12201 * Same as setvar except that the variable and value are passed in
12202 * the first argument as name=value. Since the first argument will
12203 * be actually stored in the table, it should not be a string that
12204 * will go away.
12205 */
12206
12207static void
12208setvareq(s, flags)
12209 char *s;
12210 int flags;
12211{
12212 struct var *vp, **vpp;
12213
12214 vpp = hashvar(s);
12215 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
12216 if ((vp = *findvar(vpp, s))) {
12217 if (vp->flags & VREADONLY) {
12218 size_t len = strchr(s, '=') - s;
12219 error("%.*s: is read only", len, s);
12220 }
12221 INTOFF;
12222
12223 if (vp->func && (flags & VNOFUNC) == 0)
12224 (*vp->func)(strchr(s, '=') + 1);
12225
12226 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12227 ckfree(vp->text);
12228
12229 vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
12230 vp->flags |= flags;
12231 vp->text = s;
12232
12233 /*
12234 * We could roll this to a function, to handle it as
12235 * a regular variable function callback, but why bother?
12236 */
12237 if (iflag && (vp == &vmpath || (vp == &vmail && !mpathset())))
12238 chkmail(1);
12239 INTON;
12240 return;
12241 }
12242 /* not found */
12243 vp = ckmalloc(sizeof (*vp));
12244 vp->flags = flags;
12245 vp->text = s;
12246 vp->next = *vpp;
12247 vp->func = NULL;
12248 *vpp = vp;
12249}
12250
12251
12252
12253/*
12254 * Process a linked list of variable assignments.
12255 */
12256
12257static void
12258listsetvar(mylist)
12259 struct strlist *mylist;
12260 {
12261 struct strlist *lp;
12262
12263 INTOFF;
12264 for (lp = mylist ; lp ; lp = lp->next) {
12265 setvareq(savestr(lp->text), 0);
12266 }
12267 INTON;
12268}
12269
12270
12271
12272/*
12273 * Find the value of a variable. Returns NULL if not set.
12274 */
12275
Eric Andersen62483552001-07-10 06:09:16 +000012276static const char *
Eric Andersencb57d552001-06-28 07:25:16 +000012277lookupvar(name)
12278 const char *name;
12279 {
12280 struct var *v;
12281
12282 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
12283 return strchr(v->text, '=') + 1;
12284 }
12285 return NULL;
12286}
12287
12288
12289
12290/*
12291 * Search the environment of a builtin command.
12292 */
12293
Eric Andersen62483552001-07-10 06:09:16 +000012294static const char *
12295bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012296{
Eric Andersen62483552001-07-10 06:09:16 +000012297 const struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012298
12299 for (sp = cmdenviron ; sp ; sp = sp->next) {
12300 if (varequal(sp->text, name))
12301 return strchr(sp->text, '=') + 1;
12302 }
12303 return lookupvar(name);
12304}
12305
12306
12307
12308/*
12309 * Generate a list of exported variables. This routine is used to construct
12310 * the third argument to execve when executing a program.
12311 */
12312
12313static char **
12314environment() {
12315 int nenv;
12316 struct var **vpp;
12317 struct var *vp;
12318 char **env;
12319 char **ep;
12320
12321 nenv = 0;
12322 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12323 for (vp = *vpp ; vp ; vp = vp->next)
12324 if (vp->flags & VEXPORT)
12325 nenv++;
12326 }
12327 ep = env = stalloc((nenv + 1) * sizeof *env);
12328 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12329 for (vp = *vpp ; vp ; vp = vp->next)
12330 if (vp->flags & VEXPORT)
12331 *ep++ = vp->text;
12332 }
12333 *ep = NULL;
12334 return env;
12335}
12336
12337
12338/*
12339 * Called when a shell procedure is invoked to clear out nonexported
12340 * variables. It is also necessary to reallocate variables of with
12341 * VSTACK set since these are currently allocated on the stack.
12342 */
12343
Eric Andersencb57d552001-06-28 07:25:16 +000012344static void
Eric Andersen2870d962001-07-02 17:27:21 +000012345shprocvar(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000012346 struct var **vpp;
12347 struct var *vp, **prev;
12348
12349 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12350 for (prev = vpp ; (vp = *prev) != NULL ; ) {
12351 if ((vp->flags & VEXPORT) == 0) {
12352 *prev = vp->next;
12353 if ((vp->flags & VTEXTFIXED) == 0)
12354 ckfree(vp->text);
12355 if ((vp->flags & VSTRFIXED) == 0)
12356 ckfree(vp);
12357 } else {
12358 if (vp->flags & VSTACK) {
12359 vp->text = savestr(vp->text);
12360 vp->flags &=~ VSTACK;
12361 }
12362 prev = &vp->next;
12363 }
12364 }
12365 }
12366 initvar();
12367}
12368
12369
12370
12371/*
12372 * Command to list all variables which are set. Currently this command
12373 * is invoked from the set command when the set command is called without
12374 * any variables.
12375 */
12376
12377static int
12378showvarscmd(argc, argv)
12379 int argc;
12380 char **argv;
12381{
12382 showvars(nullstr, VUNSET, VUNSET);
12383 return 0;
12384}
12385
12386
12387
12388/*
12389 * The export and readonly commands.
12390 */
12391
12392static int
12393exportcmd(argc, argv)
12394 int argc;
12395 char **argv;
12396{
12397 struct var *vp;
12398 char *name;
12399 const char *p;
12400 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12401 int pflag;
12402
12403 listsetvar(cmdenviron);
12404 pflag = (nextopt("p") == 'p');
12405 if (argc > 1 && !pflag) {
12406 while ((name = *argptr++) != NULL) {
12407 if ((p = strchr(name, '=')) != NULL) {
12408 p++;
12409 } else {
12410 if ((vp = *findvar(hashvar(name), name))) {
12411 vp->flags |= flag;
12412 goto found;
12413 }
12414 }
12415 setvar(name, p, flag);
12416found:;
12417 }
12418 } else {
12419 showvars(argv[0], flag, 0);
12420 }
12421 return 0;
12422}
12423
Eric Andersen34506362001-08-02 05:02:46 +000012424
Eric Andersencb57d552001-06-28 07:25:16 +000012425/*
12426 * The "local" command.
12427 */
12428
Eric Andersen2870d962001-07-02 17:27:21 +000012429/* funcnest nonzero if we are currently evaluating a function */
12430
Eric Andersencb57d552001-06-28 07:25:16 +000012431static int
12432localcmd(argc, argv)
12433 int argc;
12434 char **argv;
12435{
12436 char *name;
12437
Eric Andersen2870d962001-07-02 17:27:21 +000012438 if (! funcnest)
Eric Andersencb57d552001-06-28 07:25:16 +000012439 error("Not in a function");
12440 while ((name = *argptr++) != NULL) {
12441 mklocal(name);
12442 }
12443 return 0;
12444}
12445
12446
12447/*
12448 * Make a variable a local variable. When a variable is made local, it's
12449 * value and flags are saved in a localvar structure. The saved values
12450 * will be restored when the shell function returns. We handle the name
12451 * "-" as a special case.
12452 */
12453
12454static void
12455mklocal(name)
12456 char *name;
12457 {
12458 struct localvar *lvp;
12459 struct var **vpp;
12460 struct var *vp;
12461
12462 INTOFF;
12463 lvp = ckmalloc(sizeof (struct localvar));
12464 if (name[0] == '-' && name[1] == '\0') {
12465 char *p;
Eric Andersen2870d962001-07-02 17:27:21 +000012466 p = ckmalloc(sizeof optet_vals);
12467 lvp->text = memcpy(p, optet_vals, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000012468 vp = NULL;
12469 } else {
12470 vpp = hashvar(name);
12471 vp = *findvar(vpp, name);
12472 if (vp == NULL) {
12473 if (strchr(name, '='))
12474 setvareq(savestr(name), VSTRFIXED);
12475 else
12476 setvar(name, NULL, VSTRFIXED);
Eric Andersen2870d962001-07-02 17:27:21 +000012477 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012478 lvp->text = NULL;
12479 lvp->flags = VUNSET;
12480 } else {
12481 lvp->text = vp->text;
12482 lvp->flags = vp->flags;
12483 vp->flags |= VSTRFIXED|VTEXTFIXED;
12484 if (strchr(name, '='))
12485 setvareq(savestr(name), 0);
12486 }
12487 }
12488 lvp->vp = vp;
12489 lvp->next = localvars;
12490 localvars = lvp;
12491 INTON;
12492}
12493
12494
12495/*
12496 * Called after a function returns.
12497 */
12498
12499static void
12500poplocalvars() {
12501 struct localvar *lvp;
12502 struct var *vp;
12503
12504 while ((lvp = localvars) != NULL) {
12505 localvars = lvp->next;
12506 vp = lvp->vp;
Eric Andersen2870d962001-07-02 17:27:21 +000012507 if (vp == NULL) { /* $- saved */
12508 memcpy(optet_vals, lvp->text, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000012509 ckfree(lvp->text);
12510 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12511 (void)unsetvar(vp->text);
12512 } else {
12513 if ((vp->flags & VTEXTFIXED) == 0)
12514 ckfree(vp->text);
12515 vp->flags = lvp->flags;
12516 vp->text = lvp->text;
12517 }
12518 ckfree(lvp);
12519 }
12520}
12521
12522
12523static int
12524setvarcmd(argc, argv)
12525 int argc;
12526 char **argv;
12527{
12528 if (argc <= 2)
12529 return unsetcmd(argc, argv);
12530 else if (argc == 3)
12531 setvar(argv[1], argv[2], 0);
12532 else
12533 error("List assignment not implemented");
12534 return 0;
12535}
12536
12537
12538/*
12539 * The unset builtin command. We unset the function before we unset the
12540 * variable to allow a function to be unset when there is a readonly variable
12541 * with the same name.
12542 */
12543
12544static int
12545unsetcmd(argc, argv)
12546 int argc;
12547 char **argv;
12548{
12549 char **ap;
12550 int i;
12551 int flg_func = 0;
12552 int flg_var = 0;
12553 int ret = 0;
12554
12555 while ((i = nextopt("vf")) != '\0') {
12556 if (i == 'f')
12557 flg_func = 1;
12558 else
12559 flg_var = 1;
12560 }
12561 if (flg_func == 0 && flg_var == 0)
12562 flg_var = 1;
12563
12564 for (ap = argptr; *ap ; ap++) {
12565 if (flg_func)
12566 unsetfunc(*ap);
12567 if (flg_var)
12568 ret |= unsetvar(*ap);
12569 }
12570 return ret;
12571}
12572
12573
12574/*
12575 * Unset the specified variable.
12576 */
12577
12578static int
Eric Andersen62483552001-07-10 06:09:16 +000012579unsetvar(const char *s)
12580{
Eric Andersencb57d552001-06-28 07:25:16 +000012581 struct var **vpp;
12582 struct var *vp;
12583
12584 vpp = findvar(hashvar(s), s);
12585 vp = *vpp;
12586 if (vp) {
12587 if (vp->flags & VREADONLY)
12588 return (1);
12589 INTOFF;
12590 if (*(strchr(vp->text, '=') + 1) != '\0')
12591 setvar(s, nullstr, 0);
12592 vp->flags &= ~VEXPORT;
12593 vp->flags |= VUNSET;
12594 if ((vp->flags & VSTRFIXED) == 0) {
12595 if ((vp->flags & VTEXTFIXED) == 0)
12596 ckfree(vp->text);
12597 *vpp = vp->next;
12598 ckfree(vp);
12599 }
12600 INTON;
12601 return (0);
12602 }
12603
12604 return (0);
12605}
12606
12607
12608
12609/*
12610 * Find the appropriate entry in the hash table from the name.
12611 */
12612
12613static struct var **
Eric Andersen62483552001-07-10 06:09:16 +000012614hashvar(const char *p)
12615{
Eric Andersencb57d552001-06-28 07:25:16 +000012616 unsigned int hashval;
12617
12618 hashval = ((unsigned char) *p) << 4;
12619 while (*p && *p != '=')
12620 hashval += (unsigned char) *p++;
12621 return &vartab[hashval % VTABSIZE];
12622}
12623
12624
12625
12626/*
12627 * Returns true if the two strings specify the same varable. The first
12628 * variable name is terminated by '='; the second may be terminated by
12629 * either '=' or '\0'.
12630 */
12631
12632static int
Eric Andersen62483552001-07-10 06:09:16 +000012633varequal(const char *p, const char *q)
12634{
Eric Andersencb57d552001-06-28 07:25:16 +000012635 while (*p == *q++) {
12636 if (*p++ == '=')
12637 return 1;
12638 }
12639 if (*p == '=' && *(q - 1) == '\0')
12640 return 1;
12641 return 0;
12642}
12643
12644static void
12645showvars(const char *myprefix, int mask, int xor)
12646{
12647 struct var **vpp;
12648 struct var *vp;
12649 const char *sep = myprefix == nullstr ? myprefix : spcstr;
12650
12651 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12652 for (vp = *vpp ; vp ; vp = vp->next) {
12653 if ((vp->flags & mask) ^ xor) {
12654 char *p;
12655 int len;
12656
12657 p = strchr(vp->text, '=') + 1;
12658 len = p - vp->text;
12659 p = single_quote(p);
12660
Eric Andersen62483552001-07-10 06:09:16 +000012661 printf("%s%s%.*s%s\n", myprefix, sep, len,
12662 vp->text, p);
Eric Andersencb57d552001-06-28 07:25:16 +000012663 stunalloc(p);
12664 }
12665 }
12666 }
12667}
12668
12669static struct var **
12670findvar(struct var **vpp, const char *name)
12671{
12672 for (; *vpp; vpp = &(*vpp)->next) {
12673 if (varequal((*vpp)->text, name)) {
12674 break;
12675 }
12676 }
12677 return vpp;
12678}
12679
12680/*
12681 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
12682 * This file contains code for the times builtin.
Eric Andersen88cec252001-09-06 17:35:20 +000012683 * $Id: ash.c,v 1.23 2001/09/06 17:35:20 andersen Exp $
Eric Andersencb57d552001-06-28 07:25:16 +000012684 */
12685static int timescmd (int argc, char **argv)
12686{
12687 struct tms buf;
12688 long int clk_tck = sysconf(_SC_CLK_TCK);
12689
12690 times(&buf);
12691 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
12692 (int) (buf.tms_utime / clk_tck / 60),
12693 ((double) buf.tms_utime) / clk_tck,
12694 (int) (buf.tms_stime / clk_tck / 60),
12695 ((double) buf.tms_stime) / clk_tck,
12696 (int) (buf.tms_cutime / clk_tck / 60),
12697 ((double) buf.tms_cutime) / clk_tck,
12698 (int) (buf.tms_cstime / clk_tck / 60),
12699 ((double) buf.tms_cstime) / clk_tck);
12700 return 0;
12701}
12702
Eric Andersen74bcd162001-07-30 21:41:37 +000012703#ifdef ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012704/* The let builtin. */
12705int letcmd(int argc, char **argv)
Eric Andersen74bcd162001-07-30 21:41:37 +000012706{
Eric Andersen34506362001-08-02 05:02:46 +000012707 int errcode;
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012708 long result=0;
12709 if (argc == 2) {
12710 char *tmp, *expression, p[13];
12711 expression = strchr(argv[1], '=');
12712 if (!expression) {
Eric Andersen34506362001-08-02 05:02:46 +000012713 /* Cannot use 'error()' here, or the return code
12714 * will be incorrect */
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012715 out2fmt("sh: let: syntax error: \"%s\"\n", argv[1]);
12716 return 0;
Eric Andersen74bcd162001-07-30 21:41:37 +000012717 }
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012718 *expression = '\0';
12719 tmp = ++expression;
Eric Andersen34506362001-08-02 05:02:46 +000012720 result = arith(tmp, &errcode);
12721 if (errcode < 0) {
12722 /* Cannot use 'error()' here, or the return code
12723 * will be incorrect */
12724 out2fmt("sh: let: ");
12725 if(errcode == -2)
12726 out2fmt("divide by zero");
12727 else
12728 out2fmt("syntax error: \"%s=%s\"\n", argv[1], expression);
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012729 return 0;
12730 }
12731 snprintf(p, 12, "%ld", result);
12732 setvar(argv[1], savestr(p), 0);
12733 } else if (argc >= 3)
12734 synerror("invalid operand");
12735 return !result;
Eric Andersen74bcd162001-07-30 21:41:37 +000012736}
12737#endif
12738
12739
12740
Eric Andersendf82f612001-06-28 07:46:40 +000012741/*-
12742 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000012743 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000012744 *
12745 * This code is derived from software contributed to Berkeley by
12746 * Kenneth Almquist.
12747 *
12748 * Redistribution and use in source and binary forms, with or without
12749 * modification, are permitted provided that the following conditions
12750 * are met:
12751 * 1. Redistributions of source code must retain the above copyright
12752 * notice, this list of conditions and the following disclaimer.
12753 * 2. Redistributions in binary form must reproduce the above copyright
12754 * notice, this list of conditions and the following disclaimer in the
12755 * documentation and/or other materials provided with the distribution.
12756 *
Eric Andersen2870d962001-07-02 17:27:21 +000012757 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
12758 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000012759 *
12760 * 4. Neither the name of the University nor the names of its contributors
12761 * may be used to endorse or promote products derived from this software
12762 * without specific prior written permission.
12763 *
12764 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
12765 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
12766 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
12767 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
12768 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
12769 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
12770 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
12771 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
12772 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
12773 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
12774 * SUCH DAMAGE.
12775 */