blob: 15e1adb7caac868feb5605f1d9414d02b57ef080 [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. */
55#define ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +000056
Eric Andersen2870d962001-07-02 17:27:21 +000057/* Getopts is used by shell procedures to parse positional parameters.
58 * You probably want to leave this disabled, and use the busybox getopt
59 * applet if you want to do this sort of thing. There are some scripts
60 * out there that use it, so it you need it, enable. Most people will
61 * leave this disabled. This adds 1k on an x86 system. */
62#undef ASH_GETOPTS
63
64/* This allows you to override shell builtins and use whatever is on
65 * the filesystem. This is most useful when ash is acting as a
Eric Andersen62483552001-07-10 06:09:16 +000066 * standalone shell. Adds about 272 bytes. */
Eric Andersen2870d962001-07-02 17:27:21 +000067#undef ASH_CMDCMD
68
Eric Andersen2870d962001-07-02 17:27:21 +000069
Eric Andersen3102ac42001-07-06 04:26:23 +000070/* Optimize size vs speed as size */
71#define ASH_OPTIMIZE_FOR_SIZE
72
Eric Andersen2870d962001-07-02 17:27:21 +000073/* Enable this to compile in extra debugging noise. When debugging is
74 * on, debugging info will be written to $HOME/trace and a quit signal
75 * will generate a core dump. */
76#undef DEBUG
77
Eric Andersen2870d962001-07-02 17:27:21 +000078/* These are here to work with glibc -- Don't change these... */
Eric Andersendf82f612001-06-28 07:46:40 +000079#undef FNMATCH_BROKEN
80#undef GLOB_BROKEN
Eric Andersen2870d962001-07-02 17:27:21 +000081#undef _GNU_SOURCE
Eric Andersen74bcd162001-07-30 21:41:37 +000082#undef __USE_GNU
Eric Andersencb57d552001-06-28 07:25:16 +000083
84#include <assert.h>
85#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
146/* Syntax classes for is_ functions */
147#define ISDIGIT 01 /* a digit */
148#define ISUPPER 02 /* an upper case letter */
149#define ISLOWER 04 /* a lower case letter */
150#define ISUNDER 010 /* an underscore */
151#define ISSPECL 020 /* the name of a special parameter */
152
153#define SYNBASE 130
154#define PEOF -130
155
156#define PEOA -129
157
158#define TEOF 0
159#define TNL 1
160#define TSEMI 2
161#define TBACKGND 3
162#define TAND 4
163#define TOR 5
164#define TPIPE 6
165#define TLP 7
166#define TRP 8
167#define TENDCASE 9
168#define TENDBQUOTE 10
169#define TREDIR 11
170#define TWORD 12
171#define TASSIGN 13
172#define TNOT 14
173#define TCASE 15
174#define TDO 16
175#define TDONE 17
176#define TELIF 18
177#define TELSE 19
178#define TESAC 20
179#define TFI 21
180#define TFOR 22
181#define TIF 23
182#define TIN 24
183#define TTHEN 25
184#define TUNTIL 26
185#define TWHILE 27
186#define TBEGIN 28
187#define TEND 29
188
189
190#define BASESYNTAX (basesyntax + SYNBASE)
191#define DQSYNTAX (dqsyntax + SYNBASE)
192#define SQSYNTAX (sqsyntax + SYNBASE)
193#define ARISYNTAX (arisyntax + SYNBASE)
194
195/* control characters in argument strings */
196#define CTLESC '\201'
197#define CTLVAR '\202'
198#define CTLENDVAR '\203'
199#define CTLBACKQ '\204'
200#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
201/* CTLBACKQ | CTLQUOTE == '\205' */
202#define CTLARI '\206'
203#define CTLENDARI '\207'
204#define CTLQUOTEMARK '\210'
205
Eric Andersen62483552001-07-10 06:09:16 +0000206#define is_digit(c) ((c)>='0' && (c)<='9')
Eric Andersen2870d962001-07-02 17:27:21 +0000207#define is_alpha(c) (((c) < CTLESC || (c) > CTLENDARI) && isalpha((unsigned char) (c)))
208#define is_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalpha((unsigned char) (c))))
209#define is_in_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalnum((unsigned char) (c))))
210#define is_special(c) ((is_type+SYNBASE)[c] & (ISSPECL|ISDIGIT))
211#define digit_val(c) ((c) - '0')
Eric Andersencb57d552001-06-28 07:25:16 +0000212
213
214#define _DIAGASSERT(x)
215
Eric Andersen3102ac42001-07-06 04:26:23 +0000216
Eric Andersencb57d552001-06-28 07:25:16 +0000217
Eric Andersen2870d962001-07-02 17:27:21 +0000218#define S_DFL 1 /* default signal handling (SIG_DFL) */
219#define S_CATCH 2 /* signal is caught */
220#define S_IGN 3 /* signal is ignored (SIG_IGN) */
221#define S_HARD_IGN 4 /* signal is ignored permenantly */
222#define S_RESET 5 /* temporary - to reset a hard ignored sig */
Eric Andersencb57d552001-06-28 07:25:16 +0000223
224
Eric Andersen2870d962001-07-02 17:27:21 +0000225/* variable substitution byte (follows CTLVAR) */
226#define VSTYPE 0x0f /* type of variable substitution */
227#define VSNUL 0x10 /* colon--treat the empty string as unset */
228#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
Eric Andersencb57d552001-06-28 07:25:16 +0000229
Eric Andersen2870d962001-07-02 17:27:21 +0000230/* values of VSTYPE field */
231#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
232#define VSMINUS 0x2 /* ${var-text} */
233#define VSPLUS 0x3 /* ${var+text} */
234#define VSQUESTION 0x4 /* ${var?message} */
235#define VSASSIGN 0x5 /* ${var=text} */
236#define VSTRIMLEFT 0x6 /* ${var#pattern} */
237#define VSTRIMLEFTMAX 0x7 /* ${var##pattern} */
238#define VSTRIMRIGHT 0x8 /* ${var%pattern} */
239#define VSTRIMRIGHTMAX 0x9 /* ${var%%pattern} */
240#define VSLENGTH 0xa /* ${#var} */
Eric Andersencb57d552001-06-28 07:25:16 +0000241
Eric Andersen2870d962001-07-02 17:27:21 +0000242/* flags passed to redirect */
243#define REDIR_PUSH 01 /* save previous values of file descriptors */
Eric Andersen3102ac42001-07-06 04:26:23 +0000244#define REDIR_BACKQ 02 /* save the command output to pipe */
Eric Andersencb57d552001-06-28 07:25:16 +0000245
Eric Andersen2870d962001-07-02 17:27:21 +0000246/*
247 * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
248 * so we use _setjmp instead.
249 */
250
Eric Andersen62483552001-07-10 06:09:16 +0000251#if defined(BSD)
Eric Andersen2870d962001-07-02 17:27:21 +0000252#define setjmp(jmploc) _setjmp(jmploc)
253#define longjmp(jmploc, val) _longjmp(jmploc, val)
254#endif
255
256/*
257 * Most machines require the value returned from malloc to be aligned
258 * in some way. The following macro will get this right on many machines.
259 */
260
261#ifndef ALIGN
262union align {
263 int i;
264 char *cp;
265};
266
267#define ALIGN(nbytes) (((nbytes) + sizeof(union align) - 1) & ~(sizeof(union align) - 1))
268#endif
269
270#ifdef BB_LOCALE_SUPPORT
271#include <locale.h>
272static void change_lc_all(const char *value);
273static void change_lc_ctype(const char *value);
274#endif
275
276/*
277 * These macros allow the user to suspend the handling of interrupt signals
278 * over a period of time. This is similar to SIGHOLD to or sigblock, but
279 * much more efficient and portable. (But hacking the kernel is so much
280 * more fun than worrying about efficiency and portability. :-))
281 */
282
283static void onint (void);
284static volatile int suppressint;
285static volatile int intpending;
286
287#define INTOFF suppressint++
Eric Andersen3102ac42001-07-06 04:26:23 +0000288#ifndef ASH_OPTIMIZE_FOR_SIZE
Eric Andersen2870d962001-07-02 17:27:21 +0000289#define INTON { if (--suppressint == 0 && intpending) onint(); }
Eric Andersen3102ac42001-07-06 04:26:23 +0000290#define FORCEINTON {suppressint = 0; if (intpending) onint();}
Eric Andersen2870d962001-07-02 17:27:21 +0000291#else
292static void __inton (void);
Eric Andersen3102ac42001-07-06 04:26:23 +0000293static void forceinton (void);
Eric Andersen2870d962001-07-02 17:27:21 +0000294#define INTON __inton()
Eric Andersen3102ac42001-07-06 04:26:23 +0000295#define FORCEINTON forceinton()
Eric Andersen2870d962001-07-02 17:27:21 +0000296#endif
Eric Andersen3102ac42001-07-06 04:26:23 +0000297
Eric Andersen2870d962001-07-02 17:27:21 +0000298#define CLEAR_PENDING_INT intpending = 0
299#define int_pending() intpending
300
301
302typedef void *pointer;
303#ifndef NULL
304#define NULL (void *)0
305#endif
306
307static inline pointer ckmalloc (int sz) { return xmalloc(sz); }
308static inline pointer ckrealloc(void *p, int sz) { return xrealloc(p, sz); }
309static inline char * savestr (const char *s) { return xstrdup(s); }
310
311static pointer stalloc (int);
312static void stunalloc (pointer);
313static void ungrabstackstr (char *, char *);
314static char * growstackstr(void);
Eric Andersen3102ac42001-07-06 04:26:23 +0000315static char * makestrspace(size_t newlen);
Eric Andersen2870d962001-07-02 17:27:21 +0000316static char *sstrdup (const char *);
317
318/*
319 * Parse trees for commands are allocated in lifo order, so we use a stack
320 * to make this more efficient, and also to avoid all sorts of exception
321 * handling code to handle interrupts in the middle of a parse.
322 *
323 * The size 504 was chosen because the Ultrix malloc handles that size
324 * well.
325 */
326
327#define MINSIZE 504 /* minimum size of a block */
328
329
330struct stack_block {
331 struct stack_block *prev;
332 char space[MINSIZE];
333};
334
335static struct stack_block stackbase;
336static struct stack_block *stackp = &stackbase;
337static struct stackmark *markp;
338static char *stacknxt = stackbase.space;
339static int stacknleft = MINSIZE;
340
341
342#define equal(s1, s2) (strcmp(s1, s2) == 0)
343
344#define stackblock() stacknxt
345#define stackblocksize() stacknleft
346#define STARTSTACKSTR(p) p = stackblock(), sstrnleft = stackblocksize()
Eric Andersen3102ac42001-07-06 04:26:23 +0000347
Eric Andersen2870d962001-07-02 17:27:21 +0000348#define STPUTC(c, p) (--sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(), *p++ = (c)))
349#define CHECKSTRSPACE(n, p) { if (sstrnleft < n) p = makestrspace(n); }
Eric Andersen2870d962001-07-02 17:27:21 +0000350#define STACKSTRNUL(p) (sstrnleft == 0? (p = growstackstr(), *p = '\0') : (*p = '\0'))
Eric Andersen3102ac42001-07-06 04:26:23 +0000351
352
353#define USTPUTC(c, p) (--sstrnleft, *p++ = (c))
Eric Andersen2870d962001-07-02 17:27:21 +0000354#define STUNPUTC(p) (++sstrnleft, --p)
355#define STTOPC(p) p[-1]
356#define STADJUST(amount, p) (p += (amount), sstrnleft -= (amount))
357#define grabstackstr(p) stalloc(stackblocksize() - sstrnleft)
358
359#define ckfree(p) free((pointer)(p))
360
Eric Andersen2870d962001-07-02 17:27:21 +0000361
362#ifdef DEBUG
363#define TRACE(param) trace param
364static void trace (const char *, ...);
365static void trargs (char **);
366static void showtree (union node *);
367static void trputc (int);
368static void trputs (const char *);
369static void opentrace (void);
370#else
371#define TRACE(param)
372#endif
373
374#define NSEMI 0
375#define NCMD 1
376#define NPIPE 2
377#define NREDIR 3
378#define NBACKGND 4
379#define NSUBSHELL 5
380#define NAND 6
381#define NOR 7
382#define NIF 8
383#define NWHILE 9
384#define NUNTIL 10
385#define NFOR 11
386#define NCASE 12
387#define NCLIST 13
388#define NDEFUN 14
389#define NARG 15
390#define NTO 16
391#define NFROM 17
392#define NFROMTO 18
393#define NAPPEND 19
394#define NTOOV 20
395#define NTOFD 21
396#define NFROMFD 22
397#define NHERE 23
398#define NXHERE 24
399#define NNOT 25
400
401/*
402 * expandarg() flags
403 */
404#define EXP_FULL 0x1 /* perform word splitting & file globbing */
405#define EXP_TILDE 0x2 /* do normal tilde expansion */
406#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
407#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
408#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
409#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
410
411
412#define NOPTS 16
413
414static char optet_vals[NOPTS];
415
416static const char * const optlist[NOPTS] = {
417 "e" "errexit",
418 "f" "noglob",
419 "I" "ignoreeof",
420 "i" "interactive",
421 "m" "monitor",
422 "n" "noexec",
423 "s" "stdin",
424 "x" "xtrace",
425 "v" "verbose",
426 "V" "vi",
427 "E" "emacs",
428 "C" "noclobber",
429 "a" "allexport",
430 "b" "notify",
431 "u" "nounset",
432 "q" "quietprofile"
433};
434
435#define optent_name(optent) (optent+1)
436#define optent_letter(optent) optent[0]
437#define optent_val(optent) optet_vals[optent]
438
439#define eflag optent_val(0)
440#define fflag optent_val(1)
441#define Iflag optent_val(2)
442#define iflag optent_val(3)
443#define mflag optent_val(4)
444#define nflag optent_val(5)
445#define sflag optent_val(6)
446#define xflag optent_val(7)
447#define vflag optent_val(8)
448#define Vflag optent_val(9)
449#define Eflag optent_val(10)
450#define Cflag optent_val(11)
451#define aflag optent_val(12)
452#define bflag optent_val(13)
453#define uflag optent_val(14)
454#define qflag optent_val(15)
455
456
457/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
458#define FORK_FG 0
459#define FORK_BG 1
460#define FORK_NOJOB 2
461
462
463struct nbinary {
464 int type;
465 union node *ch1;
466 union node *ch2;
467};
468
469
470struct ncmd {
471 int type;
472 int backgnd;
473 union node *assign;
474 union node *args;
475 union node *redirect;
476};
477
478
479struct npipe {
480 int type;
481 int backgnd;
482 struct nodelist *cmdlist;
483};
484
485
486struct nredir {
487 int type;
488 union node *n;
489 union node *redirect;
490};
491
492
493struct nif {
494 int type;
495 union node *test;
496 union node *ifpart;
497 union node *elsepart;
498};
499
500
501struct nfor {
502 int type;
503 union node *args;
504 union node *body;
505 char *var;
506};
507
508
509struct ncase {
510 int type;
511 union node *expr;
512 union node *cases;
513};
514
515
516struct nclist {
517 int type;
518 union node *next;
519 union node *pattern;
520 union node *body;
521};
522
523
524struct narg {
525 int type;
526 union node *next;
527 char *text;
528 struct nodelist *backquote;
529};
530
531
532struct nfile {
533 int type;
534 union node *next;
535 int fd;
536 union node *fname;
537 char *expfname;
538};
539
540
541struct ndup {
542 int type;
543 union node *next;
544 int fd;
545 int dupfd;
546 union node *vname;
547};
548
549
550struct nhere {
551 int type;
552 union node *next;
553 int fd;
554 union node *doc;
555};
556
557
558struct nnot {
559 int type;
560 union node *com;
561};
562
563
564union node {
565 int type;
566 struct nbinary nbinary;
567 struct ncmd ncmd;
568 struct npipe npipe;
569 struct nredir nredir;
570 struct nif nif;
571 struct nfor nfor;
572 struct ncase ncase;
573 struct nclist nclist;
574 struct narg narg;
575 struct nfile nfile;
576 struct ndup ndup;
577 struct nhere nhere;
578 struct nnot nnot;
579};
580
581
582struct nodelist {
583 struct nodelist *next;
584 union node *n;
585};
586
587struct backcmd { /* result of evalbackcmd */
588 int fd; /* file descriptor to read from */
589 char *buf; /* buffer */
590 int nleft; /* number of chars in buffer */
591 struct job *jp; /* job structure for command */
592};
593
594struct cmdentry {
595 int cmdtype;
596 union param {
597 int index;
598 union node *func;
599 const struct builtincmd *cmd;
600 } u;
601};
602
603struct strlist {
604 struct strlist *next;
605 char *text;
606};
607
608
609struct arglist {
610 struct strlist *list;
611 struct strlist **lastp;
612};
613
614struct strpush {
615 struct strpush *prev; /* preceding string on stack */
616 char *prevstring;
617 int prevnleft;
618#ifdef ASH_ALIAS
619 struct alias *ap; /* if push was associated with an alias */
620#endif
621 char *string; /* remember the string since it may change */
622};
623
624struct parsefile {
625 struct parsefile *prev; /* preceding file on stack */
626 int linno; /* current line */
627 int fd; /* file descriptor (or -1 if string) */
628 int nleft; /* number of chars left in this line */
629 int lleft; /* number of chars left in this buffer */
630 char *nextc; /* next char in buffer */
631 char *buf; /* input buffer */
632 struct strpush *strpush; /* for pushing strings at this level */
633 struct strpush basestrpush; /* so pushing one is fast */
634};
635
636struct stackmark {
637 struct stack_block *stackp;
638 char *stacknxt;
639 int stacknleft;
640 struct stackmark *marknext;
641};
642
643struct shparam {
644 int nparam; /* # of positional parameters (without $0) */
645 unsigned char malloc; /* if parameter list dynamically allocated */
646 char **p; /* parameter list */
647 int optind; /* next parameter to be processed by getopts */
648 int optoff; /* used by getopts */
649};
650
Eric Andersen62483552001-07-10 06:09:16 +0000651/*
652 * When commands are first encountered, they are entered in a hash table.
653 * This ensures that a full path search will not have to be done for them
654 * on each invocation.
655 *
656 * We should investigate converting to a linear search, even though that
657 * would make the command name "hash" a misnomer.
658 */
659#define CMDTABLESIZE 31 /* should be prime */
660#define ARB 1 /* actual size determined at run time */
661
662
663
664struct tblentry {
665 struct tblentry *next; /* next entry in hash chain */
666 union param param; /* definition of builtin function */
667 short cmdtype; /* index identifying command */
668 char rehash; /* if set, cd done since entry created */
669 char cmdname[ARB]; /* name of command */
670};
671
672
673static struct tblentry *cmdtable[CMDTABLESIZE];
674static int builtinloc = -1; /* index in path of %builtin, or -1 */
675static int exerrno = 0; /* Last exec error */
676
677
678static void tryexec (char *, char **, char **);
679static void printentry (struct tblentry *, int);
680static void clearcmdentry (int);
681static struct tblentry *cmdlookup (const char *, int);
682static void delete_cmd_entry (void);
683static int path_change (const char *, int *);
684
685
Eric Andersen2870d962001-07-02 17:27:21 +0000686static void flushall (void);
Eric Andersen3102ac42001-07-06 04:26:23 +0000687static void out2fmt (const char *, ...)
688 __attribute__((__format__(__printf__,1,2)));
Eric Andersen2870d962001-07-02 17:27:21 +0000689static int xwrite (int, const char *, int);
Eric Andersen2870d962001-07-02 17:27:21 +0000690
Eric Andersen3102ac42001-07-06 04:26:23 +0000691static void outstr (const char *p, FILE *file) { fputs(p, file); }
692static void out1str(const char *p) { outstr(p, stdout); }
693static void out2str(const char *p) { outstr(p, stderr); }
Eric Andersen2870d962001-07-02 17:27:21 +0000694
Eric Andersen62483552001-07-10 06:09:16 +0000695#ifndef ASH_OPTIMIZE_FOR_SIZE
Eric Andersen3102ac42001-07-06 04:26:23 +0000696#define out2c(c) putc((c), stderr)
Eric Andersen62483552001-07-10 06:09:16 +0000697#else
698static void out2c(int c) { putc(c, stderr); }
699#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000700
701/* syntax table used when not in quotes */
702static const char basesyntax[257] = {
703 CENDFILE, CSPCL, CWORD, CCTL,
704 CCTL, CCTL, CCTL, CCTL,
705 CCTL, CCTL, CCTL, CWORD,
706 CWORD, CWORD, CWORD, CWORD,
707 CWORD, CWORD, CWORD, CWORD,
708 CWORD, CWORD, CWORD, CWORD,
709 CWORD, CWORD, CWORD, CWORD,
710 CWORD, CWORD, CWORD, CWORD,
711 CWORD, CWORD, CWORD, CWORD,
712 CWORD, CWORD, CWORD, CWORD,
713 CWORD, CWORD, CWORD, CWORD,
714 CWORD, CWORD, CWORD, CWORD,
715 CWORD, CWORD, CWORD, CWORD,
716 CWORD, CWORD, CWORD, CWORD,
717 CWORD, CWORD, CWORD, CWORD,
718 CWORD, CWORD, CWORD, CWORD,
719 CWORD, CWORD, CWORD, CWORD,
720 CWORD, CWORD, CWORD, CWORD,
721 CWORD, CWORD, CWORD, CWORD,
722 CWORD, CWORD, CWORD, CWORD,
723 CWORD, CWORD, CWORD, CWORD,
724 CWORD, CWORD, CWORD, CWORD,
725 CWORD, CWORD, CWORD, CWORD,
726 CWORD, CWORD, CWORD, CWORD,
727 CWORD, CWORD, CWORD, CWORD,
728 CWORD, CWORD, CWORD, CWORD,
729 CWORD, CWORD, CWORD, CWORD,
730 CWORD, CWORD, CWORD, CWORD,
731 CWORD, CWORD, CWORD, CWORD,
732 CWORD, CWORD, CWORD, CWORD,
733 CWORD, CWORD, CWORD, CWORD,
734 CWORD, CWORD, CWORD, CWORD,
735 CWORD, CWORD, CWORD, CWORD,
736 CWORD, CWORD, CWORD, CWORD,
737 CWORD, CWORD, CWORD, CSPCL,
738 CNL, CWORD, CWORD, CWORD,
739 CWORD, CWORD, CWORD, CWORD,
740 CWORD, CWORD, CWORD, CWORD,
741 CWORD, CWORD, CWORD, CWORD,
742 CWORD, CWORD, CWORD, CWORD,
743 CWORD, CWORD, CSPCL, CWORD,
744 CDQUOTE, CWORD, CVAR, CWORD,
745 CSPCL, CSQUOTE, CSPCL, CSPCL,
746 CWORD, CWORD, CWORD, CWORD,
747 CWORD, CWORD, CWORD, CWORD,
748 CWORD, CWORD, CWORD, CWORD,
749 CWORD, CWORD, CWORD, CWORD,
750 CWORD, CSPCL, CSPCL, CWORD,
751 CSPCL, CWORD, CWORD, CWORD,
752 CWORD, CWORD, CWORD, CWORD,
753 CWORD, CWORD, CWORD, CWORD,
754 CWORD, CWORD, CWORD, CWORD,
755 CWORD, CWORD, CWORD, CWORD,
756 CWORD, CWORD, CWORD, CWORD,
757 CWORD, CWORD, CWORD, CWORD,
758 CWORD, CWORD, CBACK, CWORD,
759 CWORD, CWORD, CBQUOTE, CWORD,
760 CWORD, CWORD, CWORD, CWORD,
761 CWORD, CWORD, CWORD, CWORD,
762 CWORD, CWORD, CWORD, CWORD,
763 CWORD, CWORD, CWORD, CWORD,
764 CWORD, CWORD, CWORD, CWORD,
765 CWORD, CWORD, CWORD, CWORD,
766 CWORD, CWORD, CSPCL, CENDVAR,
767 CWORD
768};
769
770/* syntax table used when in double quotes */
771static const char dqsyntax[257] = {
772 CENDFILE, CIGN, CWORD, CCTL,
773 CCTL, CCTL, CCTL, CCTL,
774 CCTL, CCTL, CCTL, CWORD,
775 CWORD, CWORD, CWORD, CWORD,
776 CWORD, CWORD, CWORD, CWORD,
777 CWORD, CWORD, CWORD, CWORD,
778 CWORD, CWORD, CWORD, CWORD,
779 CWORD, CWORD, CWORD, CWORD,
780 CWORD, CWORD, CWORD, CWORD,
781 CWORD, CWORD, CWORD, CWORD,
782 CWORD, CWORD, CWORD, CWORD,
783 CWORD, CWORD, CWORD, CWORD,
784 CWORD, CWORD, CWORD, CWORD,
785 CWORD, CWORD, CWORD, CWORD,
786 CWORD, CWORD, CWORD, CWORD,
787 CWORD, CWORD, CWORD, CWORD,
788 CWORD, CWORD, CWORD, CWORD,
789 CWORD, CWORD, CWORD, CWORD,
790 CWORD, CWORD, CWORD, CWORD,
791 CWORD, CWORD, CWORD, CWORD,
792 CWORD, CWORD, CWORD, CWORD,
793 CWORD, CWORD, CWORD, CWORD,
794 CWORD, CWORD, CWORD, CWORD,
795 CWORD, CWORD, CWORD, CWORD,
796 CWORD, CWORD, CWORD, CWORD,
797 CWORD, CWORD, CWORD, CWORD,
798 CWORD, CWORD, CWORD, CWORD,
799 CWORD, CWORD, CWORD, CWORD,
800 CWORD, CWORD, CWORD, CWORD,
801 CWORD, CWORD, CWORD, CWORD,
802 CWORD, CWORD, CWORD, CWORD,
803 CWORD, CWORD, CWORD, CWORD,
804 CWORD, CWORD, CWORD, CWORD,
805 CWORD, CWORD, CWORD, CWORD,
806 CWORD, CWORD, CWORD, CWORD,
807 CNL, CWORD, CWORD, CWORD,
808 CWORD, CWORD, CWORD, CWORD,
809 CWORD, CWORD, CWORD, CWORD,
810 CWORD, CWORD, CWORD, CWORD,
811 CWORD, CWORD, CWORD, CWORD,
812 CWORD, CWORD, CWORD, CCTL,
813 CENDQUOTE,CWORD, CVAR, CWORD,
814 CWORD, CWORD, CWORD, CWORD,
815 CCTL, CWORD, CWORD, CCTL,
816 CWORD, CCTL, CWORD, CWORD,
817 CWORD, CWORD, CWORD, CWORD,
818 CWORD, CWORD, CWORD, CWORD,
819 CCTL, CWORD, CWORD, CCTL,
820 CWORD, CCTL, CWORD, CWORD,
821 CWORD, CWORD, CWORD, CWORD,
822 CWORD, CWORD, CWORD, CWORD,
823 CWORD, CWORD, CWORD, CWORD,
824 CWORD, CWORD, CWORD, CWORD,
825 CWORD, CWORD, CWORD, CWORD,
826 CWORD, CWORD, CWORD, CWORD,
827 CWORD, CCTL, CBACK, CCTL,
828 CWORD, CWORD, CBQUOTE, CWORD,
829 CWORD, CWORD, CWORD, CWORD,
830 CWORD, CWORD, CWORD, CWORD,
831 CWORD, CWORD, CWORD, CWORD,
832 CWORD, CWORD, CWORD, CWORD,
833 CWORD, CWORD, CWORD, CWORD,
834 CWORD, CWORD, CWORD, CWORD,
835 CWORD, CWORD, CWORD, CENDVAR,
836 CCTL
837};
838
839/* syntax table used when in single quotes */
840static const char sqsyntax[257] = {
841 CENDFILE, CIGN, CWORD, CCTL,
842 CCTL, CCTL, CCTL, CCTL,
843 CCTL, CCTL, CCTL, CWORD,
844 CWORD, CWORD, CWORD, CWORD,
845 CWORD, CWORD, CWORD, CWORD,
846 CWORD, CWORD, CWORD, CWORD,
847 CWORD, CWORD, CWORD, CWORD,
848 CWORD, CWORD, CWORD, CWORD,
849 CWORD, CWORD, CWORD, CWORD,
850 CWORD, CWORD, CWORD, CWORD,
851 CWORD, CWORD, CWORD, CWORD,
852 CWORD, CWORD, CWORD, CWORD,
853 CWORD, CWORD, CWORD, CWORD,
854 CWORD, CWORD, CWORD, CWORD,
855 CWORD, CWORD, CWORD, CWORD,
856 CWORD, CWORD, CWORD, CWORD,
857 CWORD, CWORD, CWORD, CWORD,
858 CWORD, CWORD, CWORD, CWORD,
859 CWORD, CWORD, CWORD, CWORD,
860 CWORD, CWORD, CWORD, CWORD,
861 CWORD, CWORD, CWORD, CWORD,
862 CWORD, CWORD, CWORD, CWORD,
863 CWORD, CWORD, CWORD, CWORD,
864 CWORD, CWORD, CWORD, CWORD,
865 CWORD, CWORD, CWORD, CWORD,
866 CWORD, CWORD, CWORD, CWORD,
867 CWORD, CWORD, CWORD, CWORD,
868 CWORD, CWORD, CWORD, CWORD,
869 CWORD, CWORD, CWORD, CWORD,
870 CWORD, CWORD, CWORD, CWORD,
871 CWORD, CWORD, CWORD, CWORD,
872 CWORD, CWORD, CWORD, CWORD,
873 CWORD, CWORD, CWORD, CWORD,
874 CWORD, CWORD, CWORD, CWORD,
875 CWORD, CWORD, CWORD, CWORD,
876 CNL, CWORD, CWORD, CWORD,
877 CWORD, CWORD, CWORD, CWORD,
878 CWORD, CWORD, CWORD, CWORD,
879 CWORD, CWORD, CWORD, CWORD,
880 CWORD, CWORD, CWORD, CWORD,
881 CWORD, CWORD, CWORD, CCTL,
882 CWORD, CWORD, CWORD, CWORD,
883 CWORD, CENDQUOTE,CWORD, CWORD,
884 CCTL, CWORD, CWORD, CCTL,
885 CWORD, CCTL, CWORD, CWORD,
886 CWORD, CWORD, CWORD, CWORD,
887 CWORD, CWORD, CWORD, CWORD,
888 CCTL, CWORD, CWORD, CCTL,
889 CWORD, CCTL, CWORD, CWORD,
890 CWORD, CWORD, CWORD, CWORD,
891 CWORD, CWORD, CWORD, CWORD,
892 CWORD, CWORD, CWORD, CWORD,
893 CWORD, CWORD, CWORD, CWORD,
894 CWORD, CWORD, CWORD, CWORD,
895 CWORD, CWORD, CWORD, CWORD,
896 CWORD, CCTL, CCTL, CCTL,
897 CWORD, CWORD, CWORD, CWORD,
898 CWORD, CWORD, CWORD, CWORD,
899 CWORD, CWORD, CWORD, CWORD,
900 CWORD, CWORD, CWORD, CWORD,
901 CWORD, CWORD, CWORD, CWORD,
902 CWORD, CWORD, CWORD, CWORD,
903 CWORD, CWORD, CWORD, CWORD,
904 CWORD, CWORD, CWORD, CWORD,
905 CCTL
906};
907
908/* syntax table used when in arithmetic */
909static const char arisyntax[257] = {
910 CENDFILE, CIGN, CWORD, CCTL,
911 CCTL, CCTL, CCTL, CCTL,
912 CCTL, CCTL, CCTL, CWORD,
913 CWORD, CWORD, CWORD, CWORD,
914 CWORD, CWORD, CWORD, CWORD,
915 CWORD, CWORD, CWORD, CWORD,
916 CWORD, CWORD, CWORD, CWORD,
917 CWORD, CWORD, CWORD, CWORD,
918 CWORD, CWORD, CWORD, CWORD,
919 CWORD, CWORD, CWORD, CWORD,
920 CWORD, CWORD, CWORD, CWORD,
921 CWORD, CWORD, CWORD, CWORD,
922 CWORD, CWORD, CWORD, CWORD,
923 CWORD, CWORD, CWORD, CWORD,
924 CWORD, CWORD, CWORD, CWORD,
925 CWORD, CWORD, CWORD, CWORD,
926 CWORD, CWORD, CWORD, CWORD,
927 CWORD, CWORD, CWORD, CWORD,
928 CWORD, CWORD, CWORD, CWORD,
929 CWORD, CWORD, CWORD, CWORD,
930 CWORD, CWORD, CWORD, CWORD,
931 CWORD, CWORD, CWORD, CWORD,
932 CWORD, CWORD, CWORD, CWORD,
933 CWORD, CWORD, CWORD, CWORD,
934 CWORD, CWORD, CWORD, CWORD,
935 CWORD, CWORD, CWORD, CWORD,
936 CWORD, CWORD, CWORD, CWORD,
937 CWORD, CWORD, CWORD, CWORD,
938 CWORD, CWORD, CWORD, CWORD,
939 CWORD, CWORD, CWORD, CWORD,
940 CWORD, CWORD, CWORD, CWORD,
941 CWORD, CWORD, CWORD, CWORD,
942 CWORD, CWORD, CWORD, CWORD,
943 CWORD, CWORD, CWORD, CWORD,
944 CWORD, CWORD, CWORD, CWORD,
945 CNL, CWORD, CWORD, CWORD,
946 CWORD, CWORD, CWORD, CWORD,
947 CWORD, CWORD, CWORD, CWORD,
948 CWORD, CWORD, CWORD, CWORD,
949 CWORD, CWORD, CWORD, CWORD,
950 CWORD, CWORD, CWORD, CWORD,
951 CDQUOTE, CWORD, CVAR, CWORD,
952 CWORD, CSQUOTE, CLP, CRP,
953 CWORD, CWORD, CWORD, CWORD,
954 CWORD, CWORD, CWORD, CWORD,
955 CWORD, CWORD, CWORD, CWORD,
956 CWORD, CWORD, CWORD, CWORD,
957 CWORD, CWORD, CWORD, CWORD,
958 CWORD, CWORD, CWORD, CWORD,
959 CWORD, CWORD, CWORD, CWORD,
960 CWORD, CWORD, CWORD, CWORD,
961 CWORD, CWORD, CWORD, CWORD,
962 CWORD, CWORD, CWORD, CWORD,
963 CWORD, CWORD, CWORD, CWORD,
964 CWORD, CWORD, CWORD, CWORD,
965 CWORD, CWORD, CBACK, CWORD,
966 CWORD, CWORD, CBQUOTE, CWORD,
967 CWORD, CWORD, CWORD, CWORD,
968 CWORD, CWORD, CWORD, CWORD,
969 CWORD, CWORD, CWORD, CWORD,
970 CWORD, CWORD, CWORD, CWORD,
971 CWORD, CWORD, CWORD, CWORD,
972 CWORD, CWORD, CWORD, CWORD,
973 CWORD, CWORD, CWORD, CENDVAR,
974 CWORD
975};
976
977/* character classification table */
978static const char is_type[257] = {
979 0, 0, 0, 0,
980 0, 0, 0, 0,
981 0, 0, 0, 0,
982 0, 0, 0, 0,
983 0, 0, 0, 0,
984 0, 0, 0, 0,
985 0, 0, 0, 0,
986 0, 0, 0, 0,
987 0, 0, 0, 0,
988 0, 0, 0, 0,
989 0, 0, 0, 0,
990 0, 0, 0, 0,
991 0, 0, 0, 0,
992 0, 0, 0, 0,
993 0, 0, 0, 0,
994 0, 0, 0, 0,
995 0, 0, 0, 0,
996 0, 0, 0, 0,
997 0, 0, 0, 0,
998 0, 0, 0, 0,
999 0, 0, 0, 0,
1000 0, 0, 0, 0,
1001 0, 0, 0, 0,
1002 0, 0, 0, 0,
1003 0, 0, 0, 0,
1004 0, 0, 0, 0,
1005 0, 0, 0, 0,
1006 0, 0, 0, 0,
1007 0, 0, 0, 0,
1008 0, 0, 0, 0,
1009 0, 0, 0, 0,
1010 0, 0, 0, 0,
1011 0, 0, 0, 0,
1012 0, 0, 0, 0,
1013 0, 0, 0, 0,
1014 0, 0, 0, 0,
1015 0, 0, 0, 0,
1016 0, 0, 0, 0,
1017 0, 0, 0, 0,
1018 0, 0, 0, 0,
1019 0, 0, 0, ISSPECL,
1020 0, ISSPECL, ISSPECL, 0,
1021 0, 0, 0, 0,
1022 ISSPECL, 0, 0, ISSPECL,
1023 0, 0, ISDIGIT, ISDIGIT,
1024 ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT,
1025 ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT,
1026 0, 0, 0, 0,
1027 0, ISSPECL, ISSPECL, ISUPPER,
1028 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
1029 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
1030 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
1031 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
1032 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
1033 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
1034 ISUPPER, 0, 0, 0,
1035 0, ISUNDER, 0, ISLOWER,
1036 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
1037 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
1038 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
1039 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
1040 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
1041 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
1042 ISLOWER, 0, 0, 0,
1043 0
1044};
1045
1046/* Array indicating which tokens mark the end of a list */
1047static const char tokendlist[] = {
1048 1,
1049 0,
1050 0,
1051 0,
1052 0,
1053 0,
1054 0,
1055 0,
1056 1,
1057 1,
1058 1,
1059 0,
1060 0,
1061 0,
1062 0,
1063 0,
1064 1,
1065 1,
1066 1,
1067 1,
1068 1,
1069 1,
1070 0,
1071 0,
1072 0,
1073 1,
1074 0,
1075 0,
1076 0,
1077 1,
1078};
1079
1080static const char *const tokname[] = {
1081 "end of file",
1082 "newline",
1083 "\";\"",
1084 "\"&\"",
1085 "\"&&\"",
1086 "\"||\"",
1087 "\"|\"",
1088 "\"(\"",
1089 "\")\"",
1090 "\";;\"",
1091 "\"`\"",
1092 "redirection",
1093 "word",
1094 "assignment",
1095 "\"!\"",
1096 "\"case\"",
1097 "\"do\"",
1098 "\"done\"",
1099 "\"elif\"",
1100 "\"else\"",
1101 "\"esac\"",
1102 "\"fi\"",
1103 "\"for\"",
1104 "\"if\"",
1105 "\"in\"",
1106 "\"then\"",
1107 "\"until\"",
1108 "\"while\"",
1109 "\"{\"",
1110 "\"}\"",
1111};
1112
1113#define KWDOFFSET 14
1114
1115static const char *const parsekwd[] = {
1116 "!",
1117 "case",
1118 "do",
1119 "done",
1120 "elif",
1121 "else",
1122 "esac",
1123 "fi",
1124 "for",
1125 "if",
1126 "in",
1127 "then",
1128 "until",
1129 "while",
1130 "{",
1131 "}"
1132};
1133
1134
1135static int plinno = 1; /* input line number */
1136
1137static int parselleft; /* copy of parsefile->lleft */
1138
1139static struct parsefile basepf; /* top level input file */
1140static char basebuf[BUFSIZ]; /* buffer for top level input file */
1141static struct parsefile *parsefile = &basepf; /* current input file */
1142
1143/*
1144 * NEOF is returned by parsecmd when it encounters an end of file. It
1145 * must be distinct from NULL, so we use the address of a variable that
1146 * happens to be handy.
1147 */
1148
1149static int tokpushback; /* last token pushed back */
1150#define NEOF ((union node *)&tokpushback)
1151static int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */
1152
1153
1154static void error (const char *, ...) __attribute__((__noreturn__));
1155static void exerror (int, const char *, ...) __attribute__((__noreturn__));
1156static void shellexec (char **, char **, const char *, int)
1157 __attribute__((noreturn));
1158static void exitshell (int) __attribute__((noreturn));
1159
1160static int goodname(const char *);
1161static void ignoresig (int);
1162static void onsig (int);
1163static void dotrap (void);
1164static int decode_signal (const char *, int);
1165
1166static void shprocvar(void);
1167static void deletefuncs(void);
1168static void setparam (char **);
1169static void freeparam (volatile struct shparam *);
1170
1171/* reasons for skipping commands (see comment on breakcmd routine) */
1172#define SKIPBREAK 1
1173#define SKIPCONT 2
1174#define SKIPFUNC 3
1175#define SKIPFILE 4
1176
1177/* values of cmdtype */
1178#define CMDUNKNOWN -1 /* no entry in table for command */
1179#define CMDNORMAL 0 /* command is an executable program */
1180#define CMDBUILTIN 1 /* command is a shell builtin */
1181#define CMDFUNCTION 2 /* command is a shell function */
1182
1183#define DO_ERR 1 /* find_command prints errors */
1184#define DO_ABS 2 /* find_command checks absolute paths */
1185#define DO_NOFUN 4 /* find_command ignores functions */
1186#define DO_BRUTE 8 /* find_command ignores hash table */
1187
1188/*
1189 * Shell variables.
1190 */
1191
1192/* flags */
1193#define VEXPORT 0x01 /* variable is exported */
1194#define VREADONLY 0x02 /* variable cannot be modified */
1195#define VSTRFIXED 0x04 /* variable struct is staticly allocated */
1196#define VTEXTFIXED 0x08 /* text is staticly allocated */
1197#define VSTACK 0x10 /* text is allocated on the stack */
1198#define VUNSET 0x20 /* the variable is not set */
1199#define VNOFUNC 0x40 /* don't call the callback function */
1200
1201
1202struct var {
1203 struct var *next; /* next entry in hash list */
1204 int flags; /* flags are defined above */
1205 char *text; /* name=value */
1206 void (*func) (const char *);
1207 /* function to be called when */
1208 /* the variable gets set/unset */
1209};
1210
1211struct localvar {
1212 struct localvar *next; /* next local variable in list */
1213 struct var *vp; /* the variable that was made local */
1214 int flags; /* saved flags */
1215 char *text; /* saved text */
1216};
1217
1218
Eric Andersen62483552001-07-10 06:09:16 +00001219#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00001220#define rmescapes(p) _rmescapes((p), 0)
1221static char *_rmescapes (char *, int);
1222#else
1223static void rmescapes (char *);
1224#endif
1225
1226static int casematch (union node *, const char *);
1227static void clearredir(void);
1228static void popstring(void);
1229static void readcmdfile (const char *);
1230
1231static int number (const char *);
1232static int is_number (const char *, int *num);
1233static char *single_quote (const char *);
1234static int nextopt (const char *);
1235
1236static void redirect (union node *, int);
1237static void popredir (void);
1238static int dup_as_newfd (int, int);
1239
1240static void changepath(const char *newval);
1241static void getoptsreset(const char *value);
1242
1243
1244static int parsenleft; /* copy of parsefile->nleft */
1245static char *parsenextc; /* copy of parsefile->nextc */
1246static int rootpid; /* pid of main shell */
1247static int rootshell; /* true if we aren't a child of the main shell */
1248
1249static const char spcstr[] = " ";
1250static const char snlfmt[] = "%s\n";
1251
1252static int sstrnleft;
1253static int herefd = -1;
1254
1255static struct localvar *localvars;
1256
1257static struct var vifs;
1258static struct var vmail;
1259static struct var vmpath;
1260static struct var vpath;
1261static struct var vps1;
1262static struct var vps2;
1263static struct var voptind;
1264#ifdef BB_LOCALE_SUPPORT
1265static struct var vlc_all;
1266static struct var vlc_ctype;
1267#endif
1268
1269struct varinit {
1270 struct var *var;
1271 int flags;
1272 const char *text;
1273 void (*func) (const char *);
1274};
1275
1276static const char defpathvar[] =
1277 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
1278#define defpath (defpathvar + 5)
1279
1280#ifdef IFS_BROKEN
1281static const char defifsvar[] = "IFS= \t\n";
1282#define defifs (defifsvar + 4)
1283#else
1284static const char defifs[] = " \t\n";
1285#endif
1286
1287static const struct varinit varinit[] = {
1288#ifdef IFS_BROKEN
1289 { &vifs, VSTRFIXED|VTEXTFIXED, defifsvar,
1290#else
1291 { &vifs, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS=",
1292#endif
1293 NULL },
1294 { &vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=",
1295 NULL },
1296 { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=",
1297 NULL },
1298 { &vpath, VSTRFIXED|VTEXTFIXED, defpathvar,
1299 changepath },
1300 /*
1301 * vps1 depends on uid
1302 */
1303 { &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ",
1304 NULL },
1305 { &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1",
1306 getoptsreset },
1307#ifdef BB_LOCALE_SUPPORT
1308 { &vlc_all, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL=",
1309 change_lc_all },
1310 { &vlc_ctype, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE=",
1311 change_lc_ctype },
1312#endif
1313 { NULL, 0, NULL,
1314 NULL }
1315};
1316
1317#define VTABSIZE 39
1318
1319static struct var *vartab[VTABSIZE];
1320
1321/*
1322 * The following macros access the values of the above variables.
1323 * They have to skip over the name. They return the null string
1324 * for unset variables.
1325 */
1326
1327#define ifsval() (vifs.text + 4)
1328#define ifsset() ((vifs.flags & VUNSET) == 0)
1329#define mailval() (vmail.text + 5)
1330#define mpathval() (vmpath.text + 9)
1331#define pathval() (vpath.text + 5)
1332#define ps1val() (vps1.text + 4)
1333#define ps2val() (vps2.text + 4)
1334#define optindval() (voptind.text + 7)
1335
1336#define mpathset() ((vmpath.flags & VUNSET) == 0)
1337
1338static void initvar (void);
1339static void setvar (const char *, const char *, int);
1340static void setvareq (char *, int);
1341static void listsetvar (struct strlist *);
Eric Andersen62483552001-07-10 06:09:16 +00001342static const char *lookupvar (const char *);
1343static const char *bltinlookup (const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001344static char **environment (void);
1345static int showvarscmd (int, char **);
1346static void mklocal (char *);
1347static void poplocalvars (void);
1348static int unsetvar (const char *);
1349static int varequal (const char *, const char *);
1350
1351
1352static char *arg0; /* value of $0 */
1353static struct shparam shellparam; /* current positional parameters */
1354static char **argptr; /* argument list for builtin commands */
1355static char *optionarg; /* set by nextopt (like getopt) */
1356static char *optptr; /* used by nextopt */
1357static char *minusc; /* argument to -c option */
1358
1359
1360#ifdef ASH_ALIAS
1361
1362#define ALIASINUSE 1
1363#define ALIASDEAD 2
1364
Eric Andersen3102ac42001-07-06 04:26:23 +00001365#define ATABSIZE 39
1366
Eric Andersen2870d962001-07-02 17:27:21 +00001367struct alias {
1368 struct alias *next;
1369 char *name;
1370 char *val;
1371 int flag;
1372};
1373
1374static struct alias *atab[ATABSIZE];
1375
1376static void setalias (char *, char *);
1377static struct alias **hashalias (const char *);
1378static struct alias *freealias (struct alias *);
1379static struct alias **__lookupalias (const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00001380
1381static void
1382setalias(name, val)
1383 char *name, *val;
1384{
1385 struct alias *ap, **app;
1386
1387 app = __lookupalias(name);
1388 ap = *app;
1389 INTOFF;
1390 if (ap) {
1391 if (!(ap->flag & ALIASINUSE)) {
1392 ckfree(ap->val);
1393 }
Eric Andersen2870d962001-07-02 17:27:21 +00001394 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00001395 ap->flag &= ~ALIASDEAD;
1396 } else {
1397 /* not found */
1398 ap = ckmalloc(sizeof (struct alias));
1399 ap->name = savestr(name);
1400 ap->val = savestr(val);
1401 ap->flag = 0;
1402 ap->next = 0;
1403 *app = ap;
1404 }
1405 INTON;
1406}
1407
1408static int
Eric Andersen2870d962001-07-02 17:27:21 +00001409unalias(char *name)
1410{
Eric Andersencb57d552001-06-28 07:25:16 +00001411 struct alias **app;
1412
1413 app = __lookupalias(name);
1414
1415 if (*app) {
1416 INTOFF;
1417 *app = freealias(*app);
1418 INTON;
1419 return (0);
1420 }
1421
1422 return (1);
1423}
1424
Eric Andersencb57d552001-06-28 07:25:16 +00001425static void
Eric Andersen2870d962001-07-02 17:27:21 +00001426rmaliases(void)
1427{
Eric Andersencb57d552001-06-28 07:25:16 +00001428 struct alias *ap, **app;
1429 int i;
1430
1431 INTOFF;
1432 for (i = 0; i < ATABSIZE; i++) {
1433 app = &atab[i];
1434 for (ap = *app; ap; ap = *app) {
1435 *app = freealias(*app);
1436 if (ap == *app) {
1437 app = &ap->next;
1438 }
1439 }
1440 }
1441 INTON;
1442}
1443
Eric Andersen2870d962001-07-02 17:27:21 +00001444static struct alias *
1445lookupalias(const char *name, int check)
Eric Andersencb57d552001-06-28 07:25:16 +00001446{
1447 struct alias *ap = *__lookupalias(name);
1448
1449 if (check && ap && (ap->flag & ALIASINUSE))
1450 return (NULL);
1451 return (ap);
1452}
1453
Eric Andersen2870d962001-07-02 17:27:21 +00001454static void
1455printalias(const struct alias *ap) {
1456 char *p;
1457
1458 p = single_quote(ap->val);
Eric Andersen62483552001-07-10 06:09:16 +00001459 printf("alias %s=%s\n", ap->name, p);
Eric Andersen2870d962001-07-02 17:27:21 +00001460 stunalloc(p);
1461}
1462
Eric Andersencb57d552001-06-28 07:25:16 +00001463
1464/*
1465 * TODO - sort output
1466 */
1467static int
Eric Andersen2870d962001-07-02 17:27:21 +00001468aliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001469{
1470 char *n, *v;
1471 int ret = 0;
1472 struct alias *ap;
1473
1474 if (argc == 1) {
1475 int i;
1476
1477 for (i = 0; i < ATABSIZE; i++)
1478 for (ap = atab[i]; ap; ap = ap->next) {
1479 printalias(ap);
1480 }
1481 return (0);
1482 }
1483 while ((n = *++argv) != NULL) {
1484 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
1485 if ((ap = *__lookupalias(n)) == NULL) {
Eric Andersen3102ac42001-07-06 04:26:23 +00001486 out2fmt("%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00001487 ret = 1;
1488 } else
1489 printalias(ap);
1490 }
1491 else {
1492 *v++ = '\0';
1493 setalias(n, v);
1494 }
1495 }
1496
1497 return (ret);
1498}
1499
1500static int
Eric Andersen2870d962001-07-02 17:27:21 +00001501unaliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001502{
1503 int i;
1504
1505 while ((i = nextopt("a")) != '\0') {
1506 if (i == 'a') {
1507 rmaliases();
1508 return (0);
1509 }
1510 }
1511 for (i = 0; *argptr; argptr++) {
1512 if (unalias(*argptr)) {
Eric Andersen3102ac42001-07-06 04:26:23 +00001513 out2fmt("%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00001514 i = 1;
1515 }
1516 }
1517
1518 return (i);
1519}
1520
1521static struct alias **
1522hashalias(p)
1523 const char *p;
1524 {
1525 unsigned int hashval;
1526
1527 hashval = *p << 4;
1528 while (*p)
1529 hashval+= *p++;
1530 return &atab[hashval % ATABSIZE];
1531}
1532
1533static struct alias *
1534freealias(struct alias *ap) {
1535 struct alias *next;
1536
1537 if (ap->flag & ALIASINUSE) {
1538 ap->flag |= ALIASDEAD;
1539 return ap;
1540 }
1541
1542 next = ap->next;
1543 ckfree(ap->name);
1544 ckfree(ap->val);
1545 ckfree(ap);
1546 return next;
1547}
1548
Eric Andersencb57d552001-06-28 07:25:16 +00001549
1550static struct alias **
1551__lookupalias(const char *name) {
1552 struct alias **app = hashalias(name);
1553
1554 for (; *app; app = &(*app)->next) {
1555 if (equal(name, (*app)->name)) {
1556 break;
1557 }
1558 }
1559
1560 return app;
1561}
Eric Andersen2870d962001-07-02 17:27:21 +00001562#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001563
1564#ifdef ASH_MATH_SUPPORT
Eric Andersen74bcd162001-07-30 21:41:37 +00001565/* The generated file arith.c has been replaced with a custom hand
1566 * written implementation written by Aaron Lehmann <aaronl@vitelus.com>.
1567 * This is now part of libbb, so that it can be used by all the shells
1568 * in busybox. */
Eric Andersen2870d962001-07-02 17:27:21 +00001569#define ARITH_NUM 257
1570#define ARITH_LPAREN 258
1571#define ARITH_RPAREN 259
1572#define ARITH_OR 260
1573#define ARITH_AND 261
1574#define ARITH_BOR 262
1575#define ARITH_BXOR 263
1576#define ARITH_BAND 264
1577#define ARITH_EQ 265
1578#define ARITH_NE 266
1579#define ARITH_LT 267
1580#define ARITH_GT 268
1581#define ARITH_GE 269
1582#define ARITH_LE 270
1583#define ARITH_LSHIFT 271
1584#define ARITH_RSHIFT 272
1585#define ARITH_ADD 273
1586#define ARITH_SUB 274
1587#define ARITH_MUL 275
1588#define ARITH_DIV 276
1589#define ARITH_REM 277
1590#define ARITH_UNARYMINUS 278
1591#define ARITH_UNARYPLUS 279
1592#define ARITH_NOT 280
1593#define ARITH_BNOT 281
1594
1595static void expari (int);
Eric Andersencb57d552001-06-28 07:25:16 +00001596#endif
1597
Eric Andersen2870d962001-07-02 17:27:21 +00001598static char *trap[NSIG]; /* trap handler commands */
1599static char sigmode[NSIG - 1]; /* current value of signal */
1600static char gotsig[NSIG - 1]; /* indicates specified signal received */
1601static int pendingsigs; /* indicates some signal received */
1602
Eric Andersencb57d552001-06-28 07:25:16 +00001603/*
1604 * This file was generated by the mkbuiltins program.
1605 */
1606
Eric Andersen2870d962001-07-02 17:27:21 +00001607#ifdef JOBS
1608static int bgcmd (int, char **);
1609static int fgcmd (int, char **);
1610static int killcmd (int, char **);
1611#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001612static int bltincmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001613static int cdcmd (int, char **);
1614static int breakcmd (int, char **);
1615#ifdef ASH_CMDCMD
1616static int commandcmd (int, char **);
1617#endif
1618static int dotcmd (int, char **);
1619static int evalcmd (int, char **);
1620static int execcmd (int, char **);
1621static int exitcmd (int, char **);
1622static int exportcmd (int, char **);
1623static int histcmd (int, char **);
1624static int hashcmd (int, char **);
Eric Andersen1c039232001-07-07 00:05:55 +00001625static int helpcmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001626static int jobscmd (int, char **);
1627static int localcmd (int, char **);
Eric Andersen3102ac42001-07-06 04:26:23 +00001628#ifndef BB_PWD
Eric Andersen2870d962001-07-02 17:27:21 +00001629static int pwdcmd (int, char **);
1630#endif
1631static int readcmd (int, char **);
1632static int returncmd (int, char **);
1633static int setcmd (int, char **);
1634static int setvarcmd (int, char **);
1635static int shiftcmd (int, char **);
1636static int trapcmd (int, char **);
1637static int umaskcmd (int, char **);
1638#ifdef ASH_ALIAS
1639static int aliascmd (int, char **);
1640static int unaliascmd (int, char **);
1641#endif
1642static int unsetcmd (int, char **);
1643static int waitcmd (int, char **);
1644static int ulimitcmd (int, char **);
1645static int timescmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001646#ifdef ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +00001647static int letcmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001648#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001649static int typecmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001650#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00001651static int getoptscmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001652#endif
1653
Eric Andersen2870d962001-07-02 17:27:21 +00001654#ifndef BB_TRUE_FALSE
Eric Andersen2870d962001-07-02 17:27:21 +00001655static int true_main (int, char **);
1656static int false_main (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001657#endif
1658
1659static void setpwd (const char *, int);
1660
1661
1662#define BUILTIN_NOSPEC "0"
1663#define BUILTIN_SPECIAL "1"
1664#define BUILTIN_REGULAR "2"
1665#define BUILTIN_ASSIGN "4"
1666#define BUILTIN_SPEC_ASSG "5"
1667#define BUILTIN_REG_ASSG "6"
1668
1669#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1670#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1671#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
1672
1673struct builtincmd {
1674 const char *name;
1675 int (*const builtinfunc) (int, char **);
1676 //unsigned flags;
1677};
1678
Eric Andersencb57d552001-06-28 07:25:16 +00001679
1680/* It is CRUCIAL that this listing be kept in ascii order, otherwise
1681 * the binary search in find_builtin() will stop working. If you value
1682 * your kneecaps, you'll be sure to *make sure* that any changes made
1683 * to this array result in the listing remaining in ascii order. You
1684 * have been warned.
1685 */
1686static const struct builtincmd builtincmds[] = {
Eric Andersen62483552001-07-10 06:09:16 +00001687 { BUILTIN_SPECIAL ".", dotcmd }, /* first, see declare DOTCMD */
Eric Andersen2870d962001-07-02 17:27:21 +00001688 { BUILTIN_SPECIAL ":", true_main },
1689#ifdef ASH_ALIAS
1690 { BUILTIN_REG_ASSG "alias", aliascmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001691#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001692#ifdef JOBS
1693 { BUILTIN_REGULAR "bg", bgcmd },
1694#endif
1695 { BUILTIN_SPECIAL "break", breakcmd },
Eric Andersen3102ac42001-07-06 04:26:23 +00001696 { BUILTIN_SPECIAL "builtin", bltincmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001697 { BUILTIN_REGULAR "cd", cdcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001698 { BUILTIN_NOSPEC "chdir", cdcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001699#ifdef ASH_CMDCMD
1700 { BUILTIN_REGULAR "command", commandcmd },
1701#endif
1702 { BUILTIN_SPECIAL "continue", breakcmd },
1703 { BUILTIN_SPECIAL "eval", evalcmd },
1704 { BUILTIN_SPECIAL "exec", execcmd },
1705 { BUILTIN_SPECIAL "exit", exitcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001706 { BUILTIN_SPEC_ASSG "export", exportcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001707 { BUILTIN_REGULAR "false", false_main },
Eric Andersen2870d962001-07-02 17:27:21 +00001708 { BUILTIN_REGULAR "fc", histcmd },
1709#ifdef JOBS
1710 { BUILTIN_REGULAR "fg", fgcmd },
1711#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001712#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00001713 { BUILTIN_REGULAR "getopts", getoptscmd },
1714#endif
1715 { BUILTIN_NOSPEC "hash", hashcmd },
Eric Andersen1c039232001-07-07 00:05:55 +00001716 { BUILTIN_NOSPEC "help", helpcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001717 { BUILTIN_REGULAR "jobs", jobscmd },
1718#ifdef JOBS
1719 { BUILTIN_REGULAR "kill", killcmd },
1720#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001721#ifdef ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +00001722 { BUILTIN_REGULAR "let", letcmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001723#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001724 { BUILTIN_ASSIGN "local", localcmd },
Eric Andersen3102ac42001-07-06 04:26:23 +00001725#ifndef BB_PWD
Eric Andersen2870d962001-07-02 17:27:21 +00001726 { BUILTIN_NOSPEC "pwd", pwdcmd },
1727#endif
1728 { BUILTIN_REGULAR "read", readcmd },
1729 { BUILTIN_SPEC_ASSG "readonly", exportcmd },
1730 { BUILTIN_SPECIAL "return", returncmd },
1731 { BUILTIN_SPECIAL "set", setcmd },
1732 { BUILTIN_NOSPEC "setvar", setvarcmd },
1733 { BUILTIN_SPECIAL "shift", shiftcmd },
1734 { BUILTIN_SPECIAL "times", timescmd },
1735 { BUILTIN_SPECIAL "trap", trapcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001736 { BUILTIN_REGULAR "true", true_main },
Eric Andersen2870d962001-07-02 17:27:21 +00001737 { BUILTIN_NOSPEC "type", typecmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001738 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1739 { BUILTIN_REGULAR "umask", umaskcmd },
1740#ifdef ASH_ALIAS
1741 { BUILTIN_REGULAR "unalias", unaliascmd },
1742#endif
1743 { BUILTIN_SPECIAL "unset", unsetcmd },
1744 { BUILTIN_REGULAR "wait", waitcmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001745};
1746#define NUMBUILTINS (sizeof (builtincmds) / sizeof (struct builtincmd) )
1747
Eric Andersen2870d962001-07-02 17:27:21 +00001748static const struct builtincmd *DOTCMD = &builtincmds[0];
1749static struct builtincmd *BLTINCMD;
1750static struct builtincmd *EXECCMD;
1751static struct builtincmd *EVALCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00001752
Eric Andersen2870d962001-07-02 17:27:21 +00001753/* states */
1754#define JOBSTOPPED 1 /* all procs are stopped */
1755#define JOBDONE 2 /* all procs are completed */
Eric Andersencb57d552001-06-28 07:25:16 +00001756
Eric Andersen2870d962001-07-02 17:27:21 +00001757/*
1758 * A job structure contains information about a job. A job is either a
1759 * single process or a set of processes contained in a pipeline. In the
1760 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1761 * array of pids.
1762 */
Eric Andersencb57d552001-06-28 07:25:16 +00001763
Eric Andersen2870d962001-07-02 17:27:21 +00001764struct procstat {
1765 pid_t pid; /* process id */
1766 int status; /* status flags (defined above) */
1767 char *cmd; /* text of command being run */
1768};
Eric Andersencb57d552001-06-28 07:25:16 +00001769
Eric Andersen2870d962001-07-02 17:27:21 +00001770
1771static int job_warning; /* user was warned about stopped jobs */
1772
1773#ifdef JOBS
1774static void setjobctl(int enable);
1775#else
1776#define setjobctl(on) /* do nothing */
Eric Andersencb57d552001-06-28 07:25:16 +00001777#endif
1778
Eric Andersen2870d962001-07-02 17:27:21 +00001779
1780struct job {
1781 struct procstat ps0; /* status of process */
1782 struct procstat *ps; /* status or processes when more than one */
1783 short nprocs; /* number of processes */
1784 short pgrp; /* process group of this job */
1785 char state; /* true if job is finished */
1786 char used; /* true if this entry is in used */
1787 char changed; /* true if status has changed */
1788#ifdef JOBS
1789 char jobctl; /* job running under job control */
1790#endif
1791};
1792
1793static struct job *jobtab; /* array of jobs */
1794static int njobs; /* size of array */
1795static int backgndpid = -1; /* pid of last background process */
1796#ifdef JOBS
1797static int initialpgrp; /* pgrp of shell on invocation */
1798static int curjob; /* current job */
1799static int jobctl;
1800#endif
1801static int intreceived;
1802
Eric Andersen62483552001-07-10 06:09:16 +00001803static struct job *makejob (const union node *, int);
1804static int forkshell (struct job *, const union node *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00001805static int waitforjob (struct job *);
1806
1807static int docd (char *, int);
1808static char *getcomponent (void);
1809static void updatepwd (const char *);
1810static void getpwd (void);
1811
1812static char *padvance (const char **, const char *);
1813
1814static char nullstr[1]; /* zero length string */
1815static char *curdir = nullstr; /* current working directory */
1816static char *cdcomppath;
1817
Eric Andersencb57d552001-06-28 07:25:16 +00001818static int
1819cdcmd(argc, argv)
1820 int argc;
1821 char **argv;
1822{
1823 const char *dest;
1824 const char *path;
1825 char *p;
1826 struct stat statb;
1827 int print = 0;
1828
1829 nextopt(nullstr);
1830 if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME")) == NULL)
1831 error("HOME not set");
1832 if (*dest == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00001833 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001834 if (dest[0] == '-' && dest[1] == '\0') {
1835 dest = bltinlookup("OLDPWD");
1836 if (!dest || !*dest) {
1837 dest = curdir;
1838 }
1839 print = 1;
1840 if (dest)
Eric Andersen2870d962001-07-02 17:27:21 +00001841 print = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00001842 else
Eric Andersen2870d962001-07-02 17:27:21 +00001843 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001844 }
1845 if (*dest == '/' || (path = bltinlookup("CDPATH")) == NULL)
1846 path = nullstr;
1847 while ((p = padvance(&path, dest)) != NULL) {
1848 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
1849 if (!print) {
1850 /*
1851 * XXX - rethink
1852 */
1853 if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
1854 p += 2;
1855 print = strcmp(p, dest);
1856 }
1857 if (docd(p, print) >= 0)
1858 return 0;
1859
1860 }
1861 }
1862 error("can't cd to %s", dest);
1863 /* NOTREACHED */
1864}
1865
1866
1867/*
1868 * Actually do the chdir. In an interactive shell, print the
1869 * directory name if "print" is nonzero.
1870 */
1871
1872static int
1873docd(dest, print)
1874 char *dest;
1875 int print;
1876{
1877 char *p;
1878 char *q;
1879 char *component;
1880 struct stat statb;
1881 int first;
1882 int badstat;
1883
1884 TRACE(("docd(\"%s\", %d) called\n", dest, print));
1885
1886 /*
1887 * Check each component of the path. If we find a symlink or
1888 * something we can't stat, clear curdir to force a getcwd()
1889 * next time we get the value of the current directory.
1890 */
1891 badstat = 0;
1892 cdcomppath = sstrdup(dest);
1893 STARTSTACKSTR(p);
1894 if (*dest == '/') {
1895 STPUTC('/', p);
1896 cdcomppath++;
1897 }
1898 first = 1;
1899 while ((q = getcomponent()) != NULL) {
1900 if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0'))
1901 continue;
1902 if (! first)
1903 STPUTC('/', p);
1904 first = 0;
1905 component = q;
1906 while (*q)
1907 STPUTC(*q++, p);
1908 if (equal(component, ".."))
1909 continue;
1910 STACKSTRNUL(p);
1911 if ((lstat(stackblock(), &statb) < 0)
1912 || (S_ISLNK(statb.st_mode))) {
1913 /* print = 1; */
1914 badstat = 1;
1915 break;
1916 }
1917 }
1918
1919 INTOFF;
1920 if (chdir(dest) < 0) {
1921 INTON;
1922 return -1;
1923 }
1924 updatepwd(badstat ? NULL : dest);
1925 INTON;
1926 if (print && iflag)
Eric Andersen62483552001-07-10 06:09:16 +00001927 printf(snlfmt, curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00001928 return 0;
1929}
1930
1931
1932/*
1933 * Get the next component of the path name pointed to by cdcomppath.
1934 * This routine overwrites the string pointed to by cdcomppath.
1935 */
1936
1937static char *
1938getcomponent() {
1939 char *p;
1940 char *start;
1941
1942 if ((p = cdcomppath) == NULL)
1943 return NULL;
1944 start = cdcomppath;
1945 while (*p != '/' && *p != '\0')
1946 p++;
1947 if (*p == '\0') {
1948 cdcomppath = NULL;
1949 } else {
1950 *p++ = '\0';
1951 cdcomppath = p;
1952 }
1953 return start;
1954}
1955
1956
1957
1958/*
1959 * Update curdir (the name of the current directory) in response to a
1960 * cd command. We also call hashcd to let the routines in exec.c know
1961 * that the current directory has changed.
1962 */
1963
Eric Andersen2870d962001-07-02 17:27:21 +00001964static void hashcd (void);
1965
Eric Andersencb57d552001-06-28 07:25:16 +00001966static void
Eric Andersen2870d962001-07-02 17:27:21 +00001967updatepwd(const char *dir)
1968{
Eric Andersencb57d552001-06-28 07:25:16 +00001969 char *new;
1970 char *p;
1971 size_t len;
1972
Eric Andersen2870d962001-07-02 17:27:21 +00001973 hashcd(); /* update command hash table */
Eric Andersencb57d552001-06-28 07:25:16 +00001974
1975 /*
1976 * If our argument is NULL, we don't know the current directory
1977 * any more because we traversed a symbolic link or something
1978 * we couldn't stat().
1979 */
1980 if (dir == NULL || curdir == nullstr) {
1981 setpwd(0, 1);
1982 return;
1983 }
1984 len = strlen(dir);
1985 cdcomppath = sstrdup(dir);
1986 STARTSTACKSTR(new);
1987 if (*dir != '/') {
1988 p = curdir;
1989 while (*p)
1990 STPUTC(*p++, new);
1991 if (p[-1] == '/')
1992 STUNPUTC(new);
1993 }
1994 while ((p = getcomponent()) != NULL) {
1995 if (equal(p, "..")) {
1996 while (new > stackblock() && (STUNPUTC(new), *new) != '/');
1997 } else if (*p != '\0' && ! equal(p, ".")) {
1998 STPUTC('/', new);
1999 while (*p)
2000 STPUTC(*p++, new);
2001 }
2002 }
2003 if (new == stackblock())
2004 STPUTC('/', new);
2005 STACKSTRNUL(new);
2006 setpwd(stackblock(), 1);
2007}
2008
2009
Eric Andersen3102ac42001-07-06 04:26:23 +00002010#ifndef BB_PWD
Eric Andersencb57d552001-06-28 07:25:16 +00002011static int
2012pwdcmd(argc, argv)
2013 int argc;
2014 char **argv;
2015{
Eric Andersen62483552001-07-10 06:09:16 +00002016 printf(snlfmt, curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00002017 return 0;
2018}
Eric Andersen2870d962001-07-02 17:27:21 +00002019#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002020
2021/*
2022 * Find out what the current directory is. If we already know the current
2023 * directory, this routine returns immediately.
2024 */
2025static void
Eric Andersen2870d962001-07-02 17:27:21 +00002026getpwd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00002027{
Eric Andersen2870d962001-07-02 17:27:21 +00002028 curdir = xgetcwd(0);
2029 if(curdir==0)
2030 curdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00002031}
2032
2033static void
2034setpwd(const char *val, int setold)
2035{
2036 if (setold) {
2037 setvar("OLDPWD", curdir, VEXPORT);
2038 }
2039 INTOFF;
2040 if (curdir != nullstr) {
2041 free(curdir);
2042 curdir = nullstr;
2043 }
2044 if (!val) {
2045 getpwd();
2046 } else {
2047 curdir = savestr(val);
2048 }
2049 INTON;
2050 setvar("PWD", curdir, VEXPORT);
2051}
2052
Eric Andersencb57d552001-06-28 07:25:16 +00002053/*
2054 * Errors and exceptions.
2055 */
2056
2057/*
2058 * Code to handle exceptions in C.
2059 */
2060
Eric Andersen2870d962001-07-02 17:27:21 +00002061/*
2062 * We enclose jmp_buf in a structure so that we can declare pointers to
2063 * jump locations. The global variable handler contains the location to
2064 * jump to when an exception occurs, and the global variable exception
2065 * contains a code identifying the exeception. To implement nested
2066 * exception handlers, the user should save the value of handler on entry
2067 * to an inner scope, set handler to point to a jmploc structure for the
2068 * inner scope, and restore handler on exit from the scope.
2069 */
2070
2071struct jmploc {
2072 jmp_buf loc;
2073};
2074
2075/* exceptions */
2076#define EXINT 0 /* SIGINT received */
2077#define EXERROR 1 /* a generic error */
2078#define EXSHELLPROC 2 /* execute a shell procedure */
2079#define EXEXEC 3 /* command execution failed */
2080
2081static struct jmploc *handler;
Eric Andersencb57d552001-06-28 07:25:16 +00002082static int exception;
Eric Andersencb57d552001-06-28 07:25:16 +00002083
Eric Andersen2870d962001-07-02 17:27:21 +00002084static void exverror (int, const char *, va_list)
Eric Andersencb57d552001-06-28 07:25:16 +00002085 __attribute__((__noreturn__));
2086
2087/*
2088 * Called to raise an exception. Since C doesn't include exceptions, we
2089 * just do a longjmp to the exception handler. The type of exception is
2090 * stored in the global variable "exception".
2091 */
2092
Eric Andersen2870d962001-07-02 17:27:21 +00002093static void exraise (int) __attribute__((__noreturn__));
2094
Eric Andersencb57d552001-06-28 07:25:16 +00002095static void
Eric Andersen2870d962001-07-02 17:27:21 +00002096exraise(int e)
Eric Andersencb57d552001-06-28 07:25:16 +00002097{
2098#ifdef DEBUG
2099 if (handler == NULL)
2100 abort();
2101#endif
Eric Andersen62483552001-07-10 06:09:16 +00002102 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00002103 exception = e;
2104 longjmp(handler->loc, 1);
2105}
2106
2107
2108/*
2109 * Called from trap.c when a SIGINT is received. (If the user specifies
2110 * that SIGINT is to be trapped or ignored using the trap builtin, then
2111 * this routine is not called.) Suppressint is nonzero when interrupts
2112 * are held using the INTOFF macro. The call to _exit is necessary because
2113 * there is a short period after a fork before the signal handlers are
2114 * set to the appropriate value for the child. (The test for iflag is
2115 * just defensive programming.)
2116 */
2117
2118static void
Eric Andersen2870d962001-07-02 17:27:21 +00002119onint(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00002120 sigset_t mysigset;
2121
2122 if (suppressint) {
2123 intpending++;
2124 return;
2125 }
2126 intpending = 0;
2127 sigemptyset(&mysigset);
2128 sigprocmask(SIG_SETMASK, &mysigset, NULL);
2129 if (rootshell && iflag)
2130 exraise(EXINT);
2131 else {
2132 signal(SIGINT, SIG_DFL);
2133 raise(SIGINT);
2134 }
2135 /* NOTREACHED */
2136}
2137
2138
Eric Andersen2870d962001-07-02 17:27:21 +00002139static char *commandname; /* currently executing command */
2140
Eric Andersencb57d552001-06-28 07:25:16 +00002141/*
2142 * Exverror is called to raise the error exception. If the first argument
2143 * is not NULL then error prints an error message using printf style
2144 * formatting. It then raises the error exception.
2145 */
2146static void
Eric Andersen2870d962001-07-02 17:27:21 +00002147exverror(int cond, const char *msg, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00002148{
2149 CLEAR_PENDING_INT;
2150 INTOFF;
2151
2152#ifdef DEBUG
2153 if (msg)
2154 TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
2155 else
2156 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2157#endif
2158 if (msg) {
2159 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +00002160 out2fmt("%s: ", commandname);
2161 vfprintf(stderr, msg, ap);
2162 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00002163 }
Eric Andersencb57d552001-06-28 07:25:16 +00002164 exraise(cond);
2165 /* NOTREACHED */
2166}
2167
2168
Eric Andersen74bcd162001-07-30 21:41:37 +00002169static void
Eric Andersencb57d552001-06-28 07:25:16 +00002170error(const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002171{
Eric Andersencb57d552001-06-28 07:25:16 +00002172 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002173 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002174 exverror(EXERROR, msg, ap);
2175 /* NOTREACHED */
2176 va_end(ap);
2177}
2178
2179
Eric Andersencb57d552001-06-28 07:25:16 +00002180static void
2181exerror(int cond, const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002182{
Eric Andersencb57d552001-06-28 07:25:16 +00002183 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002184 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002185 exverror(cond, msg, ap);
2186 /* NOTREACHED */
2187 va_end(ap);
2188}
2189
2190
2191
2192/*
2193 * Table of error messages.
2194 */
2195
2196struct errname {
Eric Andersen2870d962001-07-02 17:27:21 +00002197 short errcode; /* error number */
Eric Andersen62483552001-07-10 06:09:16 +00002198 char action; /* operation which encountered the error */
Eric Andersencb57d552001-06-28 07:25:16 +00002199};
2200
Eric Andersen2870d962001-07-02 17:27:21 +00002201/*
2202 * Types of operations (passed to the errmsg routine).
2203 */
2204
2205#define E_OPEN 01 /* opening a file */
2206#define E_CREAT 02 /* creating a file */
2207#define E_EXEC 04 /* executing a program */
Eric Andersencb57d552001-06-28 07:25:16 +00002208
2209#define ALL (E_OPEN|E_CREAT|E_EXEC)
2210
2211static const struct errname errormsg[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00002212 { EINTR, ALL },
2213 { EACCES, ALL },
2214 { EIO, ALL },
2215 { ENOENT, E_OPEN },
2216 { ENOENT, E_CREAT },
2217 { ENOENT, E_EXEC },
2218 { ENOTDIR, E_OPEN },
2219 { ENOTDIR, E_CREAT },
2220 { ENOTDIR, E_EXEC },
2221 { EISDIR, ALL },
2222 { EEXIST, E_CREAT },
2223#ifdef EMFILE
2224 { EMFILE, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002225#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002226 { ENFILE, ALL },
2227 { ENOSPC, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002228#ifdef EDQUOT
Eric Andersen2870d962001-07-02 17:27:21 +00002229 { EDQUOT, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002230#endif
2231#ifdef ENOSR
Eric Andersen2870d962001-07-02 17:27:21 +00002232 { ENOSR, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002233#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002234 { ENXIO, ALL },
2235 { EROFS, ALL },
2236 { ETXTBSY, ALL },
2237#ifdef EAGAIN
2238 { EAGAIN, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002239#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002240 { ENOMEM, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002241#ifdef ENOLINK
Eric Andersen2870d962001-07-02 17:27:21 +00002242 { ENOLINK, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002243#endif
2244#ifdef EMULTIHOP
Eric Andersen2870d962001-07-02 17:27:21 +00002245 { EMULTIHOP, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002246#endif
2247#ifdef ECOMM
Eric Andersen2870d962001-07-02 17:27:21 +00002248 { ECOMM, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002249#endif
2250#ifdef ESTALE
Eric Andersen2870d962001-07-02 17:27:21 +00002251 { ESTALE, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002252#endif
2253#ifdef ETIMEDOUT
Eric Andersen2870d962001-07-02 17:27:21 +00002254 { ETIMEDOUT, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002255#endif
2256#ifdef ELOOP
Eric Andersen2870d962001-07-02 17:27:21 +00002257 { ELOOP, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002258#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002259 { E2BIG, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002260#ifdef ELIBACC
Eric Andersen2870d962001-07-02 17:27:21 +00002261 { ELIBACC, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002262#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002263};
2264
Eric Andersen2870d962001-07-02 17:27:21 +00002265#define ERRNAME_SIZE (sizeof(errormsg)/sizeof(struct errname))
Eric Andersencb57d552001-06-28 07:25:16 +00002266
2267/*
2268 * Return a string describing an error. The returned string may be a
2269 * pointer to a static buffer that will be overwritten on the next call.
2270 * Action describes the operation that got the error.
2271 */
2272
2273static const char *
Eric Andersen2870d962001-07-02 17:27:21 +00002274errmsg(int e, int action)
Eric Andersencb57d552001-06-28 07:25:16 +00002275{
2276 struct errname const *ep;
2277 static char buf[12];
2278
Eric Andersen2870d962001-07-02 17:27:21 +00002279 for (ep = errormsg ; ep < errormsg+ERRNAME_SIZE; ep++) {
Eric Andersencb57d552001-06-28 07:25:16 +00002280 if (ep->errcode == e && (ep->action & action) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00002281 return strerror(e);
Eric Andersencb57d552001-06-28 07:25:16 +00002282 }
Eric Andersen2870d962001-07-02 17:27:21 +00002283
Eric Andersen3102ac42001-07-06 04:26:23 +00002284 snprintf(buf, sizeof buf, "error %d", e);
Eric Andersencb57d552001-06-28 07:25:16 +00002285 return buf;
2286}
2287
2288
Eric Andersen3102ac42001-07-06 04:26:23 +00002289#ifdef ASH_OPTIMIZE_FOR_SIZE
Eric Andersencb57d552001-06-28 07:25:16 +00002290static void
2291__inton() {
2292 if (--suppressint == 0 && intpending) {
2293 onint();
2294 }
2295}
Eric Andersen3102ac42001-07-06 04:26:23 +00002296static void forceinton (void) {
2297 suppressint = 0;
2298 if (intpending)
2299 onint();
2300}
Eric Andersencb57d552001-06-28 07:25:16 +00002301#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002302
2303/* flags in argument to evaltree */
Eric Andersen2870d962001-07-02 17:27:21 +00002304#define EV_EXIT 01 /* exit after evaluating tree */
2305#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2306#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00002307
Eric Andersen2870d962001-07-02 17:27:21 +00002308static int evalskip; /* set if we are skipping commands */
2309static int skipcount; /* number of levels to skip */
2310static int loopnest; /* current loop nesting level */
2311static int funcnest; /* depth of function calls */
Eric Andersencb57d552001-06-28 07:25:16 +00002312
2313
Eric Andersen2870d962001-07-02 17:27:21 +00002314static struct strlist *cmdenviron; /* environment for builtin command */
2315static int exitstatus; /* exit status of last command */
2316static int oexitstatus; /* saved exit status */
Eric Andersencb57d552001-06-28 07:25:16 +00002317
Eric Andersen62483552001-07-10 06:09:16 +00002318static void evalsubshell (const union node *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00002319static void expredir (union node *);
Eric Andersen2870d962001-07-02 17:27:21 +00002320static void prehash (union node *);
2321static void eprintlist (struct strlist *);
Eric Andersencb57d552001-06-28 07:25:16 +00002322
Eric Andersen2870d962001-07-02 17:27:21 +00002323static union node *parsecmd(int);
Eric Andersencb57d552001-06-28 07:25:16 +00002324/*
2325 * Called to reset things after an exception.
2326 */
2327
Eric Andersencb57d552001-06-28 07:25:16 +00002328/*
2329 * The eval commmand.
2330 */
Eric Andersen2870d962001-07-02 17:27:21 +00002331static void evalstring (char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00002332
2333static int
2334evalcmd(argc, argv)
2335 int argc;
2336 char **argv;
2337{
Eric Andersen2870d962001-07-02 17:27:21 +00002338 char *p;
2339 char *concat;
2340 char **ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002341
Eric Andersen2870d962001-07-02 17:27:21 +00002342 if (argc > 1) {
2343 p = argv[1];
2344 if (argc > 2) {
2345 STARTSTACKSTR(concat);
2346 ap = argv + 2;
2347 for (;;) {
2348 while (*p)
2349 STPUTC(*p++, concat);
2350 if ((p = *ap++) == NULL)
2351 break;
2352 STPUTC(' ', concat);
2353 }
2354 STPUTC('\0', concat);
2355 p = grabstackstr(concat);
2356 }
2357 evalstring(p, EV_TESTED);
2358 }
2359 return exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002360}
2361
Eric Andersencb57d552001-06-28 07:25:16 +00002362/*
2363 * Execute a command or commands contained in a string.
2364 */
2365
Eric Andersen2870d962001-07-02 17:27:21 +00002366static void evaltree (union node *, int);
2367static void setinputstring (char *);
2368static void popfile (void);
2369static void setstackmark(struct stackmark *mark);
2370static void popstackmark(struct stackmark *mark);
2371
2372
Eric Andersencb57d552001-06-28 07:25:16 +00002373static void
Eric Andersen2870d962001-07-02 17:27:21 +00002374evalstring(char *s, int flag)
2375{
Eric Andersencb57d552001-06-28 07:25:16 +00002376 union node *n;
2377 struct stackmark smark;
2378
2379 setstackmark(&smark);
2380 setinputstring(s);
2381 while ((n = parsecmd(0)) != NEOF) {
2382 evaltree(n, flag);
2383 popstackmark(&smark);
2384 }
2385 popfile();
2386 popstackmark(&smark);
2387}
2388
Eric Andersen2870d962001-07-02 17:27:21 +00002389static struct builtincmd *find_builtin (const char *);
Eric Andersen62483552001-07-10 06:09:16 +00002390static void expandarg (union node *, struct arglist *, int);
2391static void calcsize (const union node *);
2392static union node *copynode (const union node *);
2393
2394/*
2395 * Make a copy of a parse tree.
2396 */
2397
2398static int funcblocksize; /* size of structures in function */
2399static int funcstringsize; /* size of strings in node */
2400static pointer funcblock; /* block to allocate function from */
2401static char *funcstring; /* block to allocate strings from */
2402
2403
2404static inline union node *
2405copyfunc(union node *n)
2406{
2407 if (n == NULL)
2408 return NULL;
2409 funcblocksize = 0;
2410 funcstringsize = 0;
2411 calcsize(n);
2412 funcblock = ckmalloc(funcblocksize + funcstringsize);
2413 funcstring = (char *) funcblock + funcblocksize;
2414 return copynode(n);
2415}
2416
2417/*
2418 * Free a parse tree.
2419 */
Eric Andersencb57d552001-06-28 07:25:16 +00002420
2421static void
Eric Andersen62483552001-07-10 06:09:16 +00002422freefunc(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00002423{
Eric Andersen62483552001-07-10 06:09:16 +00002424 if (n)
2425 ckfree(n);
Eric Andersencb57d552001-06-28 07:25:16 +00002426}
2427
2428
Eric Andersen62483552001-07-10 06:09:16 +00002429/*
2430 * Add a new command entry, replacing any existing command entry for
2431 * the same name.
2432 */
2433
2434static inline void
2435addcmdentry(char *name, struct cmdentry *entry)
2436{
2437 struct tblentry *cmdp;
2438
2439 INTOFF;
2440 cmdp = cmdlookup(name, 1);
2441 if (cmdp->cmdtype == CMDFUNCTION) {
2442 freefunc(cmdp->param.func);
2443 }
2444 cmdp->cmdtype = entry->cmdtype;
2445 cmdp->param = entry->u;
2446 INTON;
2447}
2448
2449static inline void
2450evalloop(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002451{
2452 int status;
2453
2454 loopnest++;
2455 status = 0;
2456 for (;;) {
2457 evaltree(n->nbinary.ch1, EV_TESTED);
2458 if (evalskip) {
Eric Andersen2870d962001-07-02 17:27:21 +00002459skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002460 evalskip = 0;
2461 continue;
2462 }
2463 if (evalskip == SKIPBREAK && --skipcount <= 0)
2464 evalskip = 0;
2465 break;
2466 }
2467 if (n->type == NWHILE) {
2468 if (exitstatus != 0)
2469 break;
2470 } else {
2471 if (exitstatus == 0)
2472 break;
2473 }
2474 evaltree(n->nbinary.ch2, flags & EV_TESTED);
2475 status = exitstatus;
2476 if (evalskip)
2477 goto skipping;
2478 }
2479 loopnest--;
2480 exitstatus = status;
2481}
2482
Eric Andersencb57d552001-06-28 07:25:16 +00002483static void
Eric Andersen62483552001-07-10 06:09:16 +00002484evalfor(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002485{
2486 struct arglist arglist;
2487 union node *argp;
2488 struct strlist *sp;
2489 struct stackmark smark;
2490
2491 setstackmark(&smark);
2492 arglist.lastp = &arglist.list;
2493 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2494 oexitstatus = exitstatus;
2495 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2496 if (evalskip)
2497 goto out;
2498 }
2499 *arglist.lastp = NULL;
2500
2501 exitstatus = 0;
2502 loopnest++;
2503 for (sp = arglist.list ; sp ; sp = sp->next) {
2504 setvar(n->nfor.var, sp->text, 0);
2505 evaltree(n->nfor.body, flags & EV_TESTED);
2506 if (evalskip) {
2507 if (evalskip == SKIPCONT && --skipcount <= 0) {
2508 evalskip = 0;
2509 continue;
2510 }
2511 if (evalskip == SKIPBREAK && --skipcount <= 0)
2512 evalskip = 0;
2513 break;
2514 }
2515 }
2516 loopnest--;
2517out:
2518 popstackmark(&smark);
2519}
2520
Eric Andersen62483552001-07-10 06:09:16 +00002521static inline void
2522evalcase(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002523{
2524 union node *cp;
2525 union node *patp;
2526 struct arglist arglist;
2527 struct stackmark smark;
2528
2529 setstackmark(&smark);
2530 arglist.lastp = &arglist.list;
2531 oexitstatus = exitstatus;
2532 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2533 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2534 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2535 if (casematch(patp, arglist.list->text)) {
2536 if (evalskip == 0) {
2537 evaltree(cp->nclist.body, flags);
2538 }
2539 goto out;
2540 }
2541 }
2542 }
2543out:
2544 popstackmark(&smark);
2545}
2546
Eric Andersencb57d552001-06-28 07:25:16 +00002547/*
Eric Andersencb57d552001-06-28 07:25:16 +00002548 * Evaluate a pipeline. All the processes in the pipeline are children
2549 * of the process creating the pipeline. (This differs from some versions
2550 * of the shell, which make the last process in a pipeline the parent
2551 * of all the rest.)
2552 */
2553
Eric Andersen62483552001-07-10 06:09:16 +00002554static inline void
Eric Andersencb57d552001-06-28 07:25:16 +00002555evalpipe(n)
2556 union node *n;
2557{
2558 struct job *jp;
2559 struct nodelist *lp;
2560 int pipelen;
2561 int prevfd;
2562 int pip[2];
2563
2564 TRACE(("evalpipe(0x%lx) called\n", (long)n));
2565 pipelen = 0;
2566 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
2567 pipelen++;
2568 INTOFF;
2569 jp = makejob(n, pipelen);
2570 prevfd = -1;
2571 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
2572 prehash(lp->n);
2573 pip[1] = -1;
2574 if (lp->next) {
2575 if (pipe(pip) < 0) {
2576 close(prevfd);
2577 error("Pipe call failed");
2578 }
2579 }
2580 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
2581 INTON;
2582 if (prevfd > 0) {
2583 close(0);
2584 dup_as_newfd(prevfd, 0);
2585 close(prevfd);
2586 if (pip[0] == 0) {
2587 pip[0] = -1;
2588 }
2589 }
2590 if (pip[1] >= 0) {
2591 if (pip[0] >= 0) {
2592 close(pip[0]);
2593 }
2594 if (pip[1] != 1) {
2595 close(1);
2596 dup_as_newfd(pip[1], 1);
2597 close(pip[1]);
2598 }
2599 }
2600 evaltree(lp->n, EV_EXIT);
2601 }
2602 if (prevfd >= 0)
2603 close(prevfd);
2604 prevfd = pip[0];
2605 close(pip[1]);
2606 }
2607 INTON;
2608 if (n->npipe.backgnd == 0) {
2609 INTOFF;
2610 exitstatus = waitforjob(jp);
2611 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
2612 INTON;
2613 }
2614}
2615
Eric Andersen2870d962001-07-02 17:27:21 +00002616static void find_command (const char *, struct cmdentry *, int, const char *);
2617
2618static int
2619isassignment(const char *word) {
2620 if (!is_name(*word)) {
2621 return 0;
2622 }
2623 do {
2624 word++;
2625 } while (is_in_name(*word));
2626 return *word == '=';
2627}
2628
Eric Andersen62483552001-07-10 06:09:16 +00002629
Eric Andersencb57d552001-06-28 07:25:16 +00002630static void
Eric Andersen3102ac42001-07-06 04:26:23 +00002631evalcommand(union node *cmd, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002632{
2633 struct stackmark smark;
2634 union node *argp;
2635 struct arglist arglist;
2636 struct arglist varlist;
2637 char **argv;
2638 int argc;
2639 char **envp;
2640 struct strlist *sp;
2641 int mode;
Eric Andersencb57d552001-06-28 07:25:16 +00002642 struct cmdentry cmdentry;
2643 struct job *jp;
2644 char *volatile savecmdname;
2645 volatile struct shparam saveparam;
2646 struct localvar *volatile savelocalvars;
2647 volatile int e;
2648 char *lastarg;
2649 const char *path;
2650 const struct builtincmd *firstbltin;
2651 struct jmploc *volatile savehandler;
2652 struct jmploc jmploc;
2653#if __GNUC__
2654 /* Avoid longjmp clobbering */
2655 (void) &argv;
2656 (void) &argc;
2657 (void) &lastarg;
2658 (void) &flags;
2659#endif
2660
2661 /* First expand the arguments. */
2662 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
2663 setstackmark(&smark);
2664 arglist.lastp = &arglist.list;
2665 varlist.lastp = &varlist.list;
2666 arglist.list = 0;
2667 oexitstatus = exitstatus;
2668 exitstatus = 0;
2669 path = pathval();
2670 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
2671 expandarg(argp, &varlist, EXP_VARTILDE);
2672 }
2673 for (
2674 argp = cmd->ncmd.args; argp && !arglist.list;
2675 argp = argp->narg.next
2676 ) {
2677 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2678 }
2679 if (argp) {
2680 struct builtincmd *bcmd;
Eric Andersen62483552001-07-10 06:09:16 +00002681 int pseudovarflag;
Eric Andersencb57d552001-06-28 07:25:16 +00002682 bcmd = find_builtin(arglist.list->text);
Eric Andersen2870d962001-07-02 17:27:21 +00002683 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00002684 for (; argp; argp = argp->narg.next) {
2685 if (pseudovarflag && isassignment(argp->narg.text)) {
2686 expandarg(argp, &arglist, EXP_VARTILDE);
2687 continue;
2688 }
2689 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2690 }
2691 }
2692 *arglist.lastp = NULL;
2693 *varlist.lastp = NULL;
2694 expredir(cmd->ncmd.redirect);
2695 argc = 0;
2696 for (sp = arglist.list ; sp ; sp = sp->next)
2697 argc++;
2698 argv = stalloc(sizeof (char *) * (argc + 1));
2699
2700 for (sp = arglist.list ; sp ; sp = sp->next) {
2701 TRACE(("evalcommand arg: %s\n", sp->text));
2702 *argv++ = sp->text;
2703 }
2704 *argv = NULL;
2705 lastarg = NULL;
2706 if (iflag && funcnest == 0 && argc > 0)
2707 lastarg = argv[-1];
2708 argv -= argc;
2709
2710 /* Print the command if xflag is set. */
2711 if (xflag) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002712 out2c('+');
Eric Andersencb57d552001-06-28 07:25:16 +00002713 eprintlist(varlist.list);
2714 eprintlist(arglist.list);
Eric Andersen3102ac42001-07-06 04:26:23 +00002715 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00002716 }
2717
2718 /* Now locate the command. */
2719 if (argc == 0) {
2720 cmdentry.cmdtype = CMDBUILTIN;
2721 firstbltin = cmdentry.u.cmd = BLTINCMD;
2722 } else {
2723 const char *oldpath;
2724 int findflag = DO_ERR;
2725 int oldfindflag;
2726
2727 /*
2728 * Modify the command lookup path, if a PATH= assignment
2729 * is present
2730 */
2731 for (sp = varlist.list ; sp ; sp = sp->next)
2732 if (varequal(sp->text, defpathvar)) {
2733 path = sp->text + 5;
2734 findflag |= DO_BRUTE;
2735 }
2736 oldpath = path;
2737 oldfindflag = findflag;
2738 firstbltin = 0;
2739 for(;;) {
2740 find_command(argv[0], &cmdentry, findflag, path);
Eric Andersen2870d962001-07-02 17:27:21 +00002741 if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */
Eric Andersencb57d552001-06-28 07:25:16 +00002742 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002743 goto out;
2744 }
2745 /* implement bltin and command here */
2746 if (cmdentry.cmdtype != CMDBUILTIN) {
2747 break;
2748 }
2749 if (!firstbltin) {
2750 firstbltin = cmdentry.u.cmd;
2751 }
2752 if (cmdentry.u.cmd == BLTINCMD) {
2753 for(;;) {
2754 struct builtincmd *bcmd;
2755
2756 argv++;
2757 if (--argc == 0)
2758 goto found;
2759 if (!(bcmd = find_builtin(*argv))) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002760 out2fmt("%s: not found\n", *argv);
Eric Andersencb57d552001-06-28 07:25:16 +00002761 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002762 goto out;
2763 }
2764 cmdentry.u.cmd = bcmd;
2765 if (bcmd != BLTINCMD)
2766 break;
2767 }
2768 }
Eric Andersen2870d962001-07-02 17:27:21 +00002769 if (cmdentry.u.cmd == find_builtin("command")) {
Eric Andersencb57d552001-06-28 07:25:16 +00002770 argv++;
2771 if (--argc == 0) {
2772 goto found;
2773 }
2774 if (*argv[0] == '-') {
2775 if (!equal(argv[0], "-p")) {
2776 argv--;
2777 argc++;
2778 break;
2779 }
2780 argv++;
2781 if (--argc == 0) {
2782 goto found;
2783 }
2784 path = defpath;
2785 findflag |= DO_BRUTE;
2786 } else {
2787 path = oldpath;
2788 findflag = oldfindflag;
2789 }
2790 findflag |= DO_NOFUN;
2791 continue;
2792 }
2793found:
2794 break;
2795 }
2796 }
2797
2798 /* Fork off a child process if necessary. */
2799 if (cmd->ncmd.backgnd
2800 || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00002801 ) {
2802 jp = makejob(cmd, 1);
2803 mode = cmd->ncmd.backgnd;
Eric Andersencb57d552001-06-28 07:25:16 +00002804 if (forkshell(jp, cmd, mode) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00002805 goto parent; /* at end of routine */
Eric Andersencb57d552001-06-28 07:25:16 +00002806 flags |= EV_EXIT;
2807 }
2808
2809 /* This is the child process if a fork occurred. */
2810 /* Execute the command. */
2811 if (cmdentry.cmdtype == CMDFUNCTION) {
2812#ifdef DEBUG
2813 trputs("Shell function: "); trargs(argv);
2814#endif
2815 exitstatus = oexitstatus;
2816 redirect(cmd->ncmd.redirect, REDIR_PUSH);
2817 saveparam = shellparam;
2818 shellparam.malloc = 0;
2819 shellparam.nparam = argc - 1;
2820 shellparam.p = argv + 1;
2821 INTOFF;
2822 savelocalvars = localvars;
2823 localvars = NULL;
2824 INTON;
2825 if (setjmp(jmploc.loc)) {
2826 if (exception == EXSHELLPROC) {
2827 freeparam((volatile struct shparam *)
2828 &saveparam);
2829 } else {
2830 saveparam.optind = shellparam.optind;
2831 saveparam.optoff = shellparam.optoff;
2832 freeparam(&shellparam);
2833 shellparam = saveparam;
2834 }
2835 poplocalvars();
2836 localvars = savelocalvars;
2837 handler = savehandler;
2838 longjmp(handler->loc, 1);
2839 }
2840 savehandler = handler;
2841 handler = &jmploc;
2842 for (sp = varlist.list ; sp ; sp = sp->next)
2843 mklocal(sp->text);
2844 funcnest++;
2845 evaltree(cmdentry.u.func, flags & EV_TESTED);
2846 funcnest--;
2847 INTOFF;
2848 poplocalvars();
2849 localvars = savelocalvars;
2850 saveparam.optind = shellparam.optind;
2851 saveparam.optoff = shellparam.optoff;
2852 freeparam(&shellparam);
2853 shellparam = saveparam;
2854 handler = savehandler;
2855 popredir();
2856 INTON;
2857 if (evalskip == SKIPFUNC) {
2858 evalskip = 0;
2859 skipcount = 0;
2860 }
2861 if (flags & EV_EXIT)
2862 exitshell(exitstatus);
2863 } else if (cmdentry.cmdtype == CMDBUILTIN) {
2864#ifdef DEBUG
2865 trputs("builtin command: "); trargs(argv);
2866#endif
2867 mode = (cmdentry.u.cmd == EXECCMD)? 0 : REDIR_PUSH;
Eric Andersencb57d552001-06-28 07:25:16 +00002868 redirect(cmd->ncmd.redirect, mode);
2869 savecmdname = commandname;
Eric Andersen2870d962001-07-02 17:27:21 +00002870 if (IS_BUILTIN_SPECIAL(firstbltin)) {
Eric Andersencb57d552001-06-28 07:25:16 +00002871 listsetvar(varlist.list);
2872 } else {
2873 cmdenviron = varlist.list;
2874 }
2875 e = -1;
2876 if (setjmp(jmploc.loc)) {
2877 e = exception;
2878 exitstatus = (e == EXINT)? SIGINT+128 : 2;
2879 goto cmddone;
2880 }
2881 savehandler = handler;
2882 handler = &jmploc;
2883 commandname = argv[0];
2884 argptr = argv + 1;
Eric Andersen2870d962001-07-02 17:27:21 +00002885 optptr = NULL; /* initialize nextopt */
Eric Andersencb57d552001-06-28 07:25:16 +00002886 exitstatus = (*cmdentry.u.cmd->builtinfunc)(argc, argv);
2887 flushall();
2888cmddone:
Eric Andersencb57d552001-06-28 07:25:16 +00002889 cmdenviron = NULL;
2890 if (e != EXSHELLPROC) {
2891 commandname = savecmdname;
2892 if (flags & EV_EXIT)
2893 exitshell(exitstatus);
2894 }
2895 handler = savehandler;
2896 if (e != -1) {
2897 if ((e != EXERROR && e != EXEXEC)
2898 || cmdentry.u.cmd == BLTINCMD
2899 || cmdentry.u.cmd == DOTCMD
2900 || cmdentry.u.cmd == EVALCMD
2901 || cmdentry.u.cmd == EXECCMD)
2902 exraise(e);
2903 FORCEINTON;
2904 }
2905 if (cmdentry.u.cmd != EXECCMD)
2906 popredir();
Eric Andersencb57d552001-06-28 07:25:16 +00002907 } else {
2908#ifdef DEBUG
2909 trputs("normal command: "); trargs(argv);
2910#endif
2911 redirect(cmd->ncmd.redirect, 0);
2912 clearredir();
2913 for (sp = varlist.list ; sp ; sp = sp->next)
2914 setvareq(sp->text, VEXPORT|VSTACK);
2915 envp = environment();
2916 shellexec(argv, envp, path, cmdentry.u.index);
2917 }
2918 goto out;
2919
Eric Andersen2870d962001-07-02 17:27:21 +00002920parent: /* parent process gets here (if we forked) */
2921 if (mode == 0) { /* argument to fork */
Eric Andersencb57d552001-06-28 07:25:16 +00002922 INTOFF;
2923 exitstatus = waitforjob(jp);
2924 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00002925 }
2926
2927out:
2928 if (lastarg)
2929 setvar("_", lastarg, 0);
2930 popstackmark(&smark);
2931}
2932
Eric Andersen62483552001-07-10 06:09:16 +00002933/*
2934 * Evaluate a parse tree. The value is left in the global variable
2935 * exitstatus.
2936 */
2937static void
2938evaltree(n, flags)
2939 union node *n;
2940 int flags;
2941{
2942 int checkexit = 0;
2943 if (n == NULL) {
2944 TRACE(("evaltree(NULL) called\n"));
2945 goto out;
2946 }
2947 TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
2948 switch (n->type) {
2949 case NSEMI:
2950 evaltree(n->nbinary.ch1, flags & EV_TESTED);
2951 if (evalskip)
2952 goto out;
2953 evaltree(n->nbinary.ch2, flags);
2954 break;
2955 case NAND:
2956 evaltree(n->nbinary.ch1, EV_TESTED);
2957 if (evalskip || exitstatus != 0)
2958 goto out;
2959 evaltree(n->nbinary.ch2, flags);
2960 break;
2961 case NOR:
2962 evaltree(n->nbinary.ch1, EV_TESTED);
2963 if (evalskip || exitstatus == 0)
2964 goto out;
2965 evaltree(n->nbinary.ch2, flags);
2966 break;
2967 case NREDIR:
2968 expredir(n->nredir.redirect);
2969 redirect(n->nredir.redirect, REDIR_PUSH);
2970 evaltree(n->nredir.n, flags);
2971 popredir();
2972 break;
2973 case NSUBSHELL:
2974 evalsubshell(n, flags);
2975 break;
2976 case NBACKGND:
2977 evalsubshell(n, flags);
2978 break;
2979 case NIF: {
2980 evaltree(n->nif.test, EV_TESTED);
2981 if (evalskip)
2982 goto out;
2983 if (exitstatus == 0)
2984 evaltree(n->nif.ifpart, flags);
2985 else if (n->nif.elsepart)
2986 evaltree(n->nif.elsepart, flags);
2987 else
2988 exitstatus = 0;
2989 break;
2990 }
2991 case NWHILE:
2992 case NUNTIL:
2993 evalloop(n, flags);
2994 break;
2995 case NFOR:
2996 evalfor(n, flags);
2997 break;
2998 case NCASE:
2999 evalcase(n, flags);
3000 break;
3001 case NDEFUN: {
3002 struct builtincmd *bcmd;
3003 struct cmdentry entry;
3004 if (
3005 (bcmd = find_builtin(n->narg.text)) &&
3006 IS_BUILTIN_SPECIAL(bcmd)
3007 ) {
3008 out2fmt("%s is a special built-in\n", n->narg.text);
3009 exitstatus = 1;
3010 break;
3011 }
3012 entry.cmdtype = CMDFUNCTION;
3013 entry.u.func = copyfunc(n->narg.next);
3014 addcmdentry(n->narg.text, &entry);
3015 exitstatus = 0;
3016 break;
3017 }
3018 case NNOT:
3019 evaltree(n->nnot.com, EV_TESTED);
3020 exitstatus = !exitstatus;
3021 break;
Eric Andersencb57d552001-06-28 07:25:16 +00003022
Eric Andersen62483552001-07-10 06:09:16 +00003023 case NPIPE:
3024 evalpipe(n);
3025 checkexit = 1;
3026 break;
3027 case NCMD:
3028 evalcommand(n, flags);
3029 checkexit = 1;
3030 break;
3031#ifdef DEBUG
3032 default:
3033 printf("Node type = %d\n", n->type);
3034 break;
3035#endif
3036 }
3037out:
3038 if (pendingsigs)
3039 dotrap();
3040 if (
3041 flags & EV_EXIT ||
3042 (checkexit && eflag && exitstatus && !(flags & EV_TESTED))
3043 )
3044 exitshell(exitstatus);
3045}
3046
3047/*
3048 * Kick off a subshell to evaluate a tree.
3049 */
3050
3051static void
3052evalsubshell(const union node *n, int flags)
3053{
3054 struct job *jp;
3055 int backgnd = (n->type == NBACKGND);
3056
3057 expredir(n->nredir.redirect);
3058 jp = makejob(n, 1);
3059 if (forkshell(jp, n, backgnd) == 0) {
3060 if (backgnd)
3061 flags &=~ EV_TESTED;
3062 redirect(n->nredir.redirect, 0);
3063 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
3064 }
3065 if (! backgnd) {
3066 INTOFF;
3067 exitstatus = waitforjob(jp);
3068 INTON;
3069 }
3070}
3071
3072/*
3073 * Compute the names of the files in a redirection list.
3074 */
3075
3076static void fixredir(union node *n, const char *text, int err);
3077
3078static void
3079expredir(union node *n)
3080{
3081 union node *redir;
3082
3083 for (redir = n ; redir ; redir = redir->nfile.next) {
3084 struct arglist fn;
3085 fn.lastp = &fn.list;
3086 oexitstatus = exitstatus;
3087 switch (redir->type) {
3088 case NFROMTO:
3089 case NFROM:
3090 case NTO:
3091 case NAPPEND:
3092 case NTOOV:
3093 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3094 redir->nfile.expfname = fn.list->text;
3095 break;
3096 case NFROMFD:
3097 case NTOFD:
3098 if (redir->ndup.vname) {
3099 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3100 fixredir(redir, fn.list->text, 1);
3101 }
3102 break;
3103 }
3104 }
3105}
3106
3107
3108/*
3109 * Execute a command inside back quotes. If it's a builtin command, we
3110 * want to save its output in a block obtained from malloc. Otherwise
3111 * we fork off a subprocess and get the output of the command via a pipe.
3112 * Should be called with interrupts off.
3113 */
3114
3115static void
3116evalbackcmd(union node *n, struct backcmd *result)
3117{
3118 int pip[2];
3119 struct job *jp;
3120 struct stackmark smark; /* unnecessary */
3121
3122 setstackmark(&smark);
3123 result->fd = -1;
3124 result->buf = NULL;
3125 result->nleft = 0;
3126 result->jp = NULL;
3127 if (n == NULL) {
3128 exitstatus = 0;
3129 goto out;
3130 }
3131 exitstatus = 0;
3132 if (pipe(pip) < 0)
3133 error("Pipe call failed");
3134 jp = makejob(n, 1);
3135 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3136 FORCEINTON;
3137 close(pip[0]);
3138 if (pip[1] != 1) {
3139 close(1);
3140 dup_as_newfd(pip[1], 1);
3141 close(pip[1]);
3142 }
3143 eflag = 0;
3144 evaltree(n, EV_EXIT);
3145 }
3146 close(pip[1]);
3147 result->fd = pip[0];
3148 result->jp = jp;
3149out:
3150 popstackmark(&smark);
3151 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
3152 result->fd, result->buf, result->nleft, result->jp));
3153}
3154
3155
3156/*
3157 * Execute a simple command.
3158 */
Eric Andersencb57d552001-06-28 07:25:16 +00003159
3160/*
3161 * Search for a command. This is called before we fork so that the
3162 * location of the command will be available in the parent as well as
3163 * the child. The check for "goodname" is an overly conservative
3164 * check that the name will not be subject to expansion.
3165 */
3166
3167static void
3168prehash(n)
3169 union node *n;
3170{
3171 struct cmdentry entry;
3172
3173 if (n->type == NCMD && n->ncmd.args)
3174 if (goodname(n->ncmd.args->narg.text))
3175 find_command(n->ncmd.args->narg.text, &entry, 0,
3176 pathval());
3177}
3178
3179
Eric Andersencb57d552001-06-28 07:25:16 +00003180/*
3181 * Builtin commands. Builtin commands whose functions are closely
3182 * tied to evaluation are implemented here.
3183 */
3184
3185/*
3186 * No command given, or a bltin command with no arguments. Set the
3187 * specified variables.
3188 */
3189
3190int
3191bltincmd(argc, argv)
3192 int argc;
3193 char **argv;
3194{
3195 /*
3196 * Preserve exitstatus of a previous possible redirection
3197 * as POSIX mandates
3198 */
3199 return exitstatus;
3200}
3201
3202
3203/*
3204 * Handle break and continue commands. Break, continue, and return are
3205 * all handled by setting the evalskip flag. The evaluation routines
3206 * above all check this flag, and if it is set they start skipping
3207 * commands rather than executing them. The variable skipcount is
3208 * the number of loops to break/continue, or the number of function
3209 * levels to return. (The latter is always 1.) It should probably
3210 * be an error to break out of more loops than exist, but it isn't
3211 * in the standard shell so we don't make it one here.
3212 */
3213
3214static int
3215breakcmd(argc, argv)
3216 int argc;
3217 char **argv;
3218{
3219 int n = argc > 1 ? number(argv[1]) : 1;
3220
3221 if (n > loopnest)
3222 n = loopnest;
3223 if (n > 0) {
3224 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
3225 skipcount = n;
3226 }
3227 return 0;
3228}
3229
3230
3231/*
3232 * The return command.
3233 */
3234
3235static int
3236returncmd(argc, argv)
3237 int argc;
3238 char **argv;
3239{
3240 int ret = argc > 1 ? number(argv[1]) : oexitstatus;
3241
3242 if (funcnest) {
3243 evalskip = SKIPFUNC;
3244 skipcount = 1;
3245 return ret;
3246 }
3247 else {
3248 /* Do what ksh does; skip the rest of the file */
3249 evalskip = SKIPFILE;
3250 skipcount = 1;
3251 return ret;
3252 }
3253}
3254
3255
3256#ifndef BB_TRUE_FALSE
3257static int
3258false_main(argc, argv)
3259 int argc;
3260 char **argv;
3261{
3262 return 1;
3263}
3264
3265
3266static int
3267true_main(argc, argv)
3268 int argc;
3269 char **argv;
3270{
3271 return 0;
3272}
3273#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003274
3275/*
3276 * Controls whether the shell is interactive or not.
3277 */
3278
3279static void setsignal(int signo);
3280static void chkmail(int silent);
3281
3282
3283static void
3284setinteractive(int on)
3285{
3286 static int is_interactive;
Eric Andersen1c039232001-07-07 00:05:55 +00003287 static int do_banner=0;
Eric Andersen2870d962001-07-02 17:27:21 +00003288
3289 if (on == is_interactive)
3290 return;
3291 setsignal(SIGINT);
3292 setsignal(SIGQUIT);
3293 setsignal(SIGTERM);
3294 chkmail(1);
3295 is_interactive = on;
Eric Andersen1c039232001-07-07 00:05:55 +00003296 if (do_banner==0 && is_interactive) {
3297 /* Looks like they want an interactive shell */
3298 printf( "\n\n" BB_BANNER " Built-in shell (ash)\n");
3299 printf( "Enter 'help' for a list of built-in commands.\n\n");
3300 do_banner=1;
3301 }
Eric Andersen2870d962001-07-02 17:27:21 +00003302}
3303
3304static void
3305optschanged(void)
3306{
3307 setinteractive(iflag);
3308 setjobctl(mflag);
3309}
3310
Eric Andersencb57d552001-06-28 07:25:16 +00003311
3312static int
3313execcmd(argc, argv)
3314 int argc;
3315 char **argv;
3316{
3317 if (argc > 1) {
3318 struct strlist *sp;
3319
Eric Andersen2870d962001-07-02 17:27:21 +00003320 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003321 mflag = 0;
3322 optschanged();
3323 for (sp = cmdenviron; sp ; sp = sp->next)
3324 setvareq(sp->text, VEXPORT|VSTACK);
3325 shellexec(argv + 1, environment(), pathval(), 0);
3326 }
3327 return 0;
3328}
3329
3330static void
3331eprintlist(struct strlist *sp)
3332{
3333 for (; sp; sp = sp->next) {
Eric Andersen3102ac42001-07-06 04:26:23 +00003334 out2fmt(" %s",sp->text);
Eric Andersencb57d552001-06-28 07:25:16 +00003335 }
3336}
Eric Andersencb57d552001-06-28 07:25:16 +00003337
3338/*
3339 * Exec a program. Never returns. If you change this routine, you may
3340 * have to change the find_command routine as well.
3341 */
3342
Eric Andersen2870d962001-07-02 17:27:21 +00003343static const char *pathopt; /* set by padvance */
3344
Eric Andersencb57d552001-06-28 07:25:16 +00003345static void
3346shellexec(argv, envp, path, idx)
3347 char **argv, **envp;
3348 const char *path;
3349 int idx;
3350{
3351 char *cmdname;
3352 int e;
3353
3354 if (strchr(argv[0], '/') != NULL) {
3355 tryexec(argv[0], argv, envp);
3356 e = errno;
3357 } else {
3358 e = ENOENT;
3359 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3360 if (--idx < 0 && pathopt == NULL) {
3361 tryexec(cmdname, argv, envp);
3362 if (errno != ENOENT && errno != ENOTDIR)
3363 e = errno;
3364 }
3365 stunalloc(cmdname);
3366 }
3367 }
3368
3369 /* Map to POSIX errors */
3370 switch (e) {
3371 case EACCES:
3372 exerrno = 126;
3373 break;
3374 case ENOENT:
3375 exerrno = 127;
3376 break;
3377 default:
3378 exerrno = 2;
3379 break;
3380 }
3381 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3382 /* NOTREACHED */
3383}
3384
Eric Andersen2870d962001-07-02 17:27:21 +00003385/*
3386 * Clear traps on a fork.
3387 */
3388static void
3389clear_traps(void) {
3390 char **tp;
3391
3392 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
3393 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
3394 INTOFF;
3395 ckfree(*tp);
3396 *tp = NULL;
3397 if (tp != &trap[0])
3398 setsignal(tp - trap);
3399 INTON;
3400 }
3401 }
3402}
3403
3404
3405static void
3406initshellproc(void) {
3407
3408#ifdef ASH_ALIAS
3409 /* from alias.c: */
3410 {
3411 rmaliases();
3412 }
3413#endif
3414 /* from eval.c: */
3415 {
3416 exitstatus = 0;
3417 }
3418
3419 /* from exec.c: */
3420 {
3421 deletefuncs();
3422 }
3423
3424 /* from jobs.c: */
3425 {
3426 backgndpid = -1;
3427#ifdef JOBS
3428 jobctl = 0;
3429#endif
3430 }
3431
3432 /* from options.c: */
3433 {
3434 int i;
3435
3436 for (i = 0; i < NOPTS; i++)
3437 optent_val(i) = 0;
3438 optschanged();
3439
3440 }
3441
3442 /* from redir.c: */
3443 {
3444 clearredir();
3445 }
3446
3447 /* from trap.c: */
3448 {
3449 char *sm;
3450
3451 clear_traps();
3452 for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) {
3453 if (*sm == S_IGN)
3454 *sm = S_HARD_IGN;
3455 }
3456 }
3457
3458 /* from var.c: */
3459 {
3460 shprocvar();
3461 }
3462}
3463
3464static int preadbuffer(void);
3465static void pushfile (void);
Eric Andersen2870d962001-07-02 17:27:21 +00003466
3467/*
3468 * Read a character from the script, returning PEOF on end of file.
3469 * Nul characters in the input are silently discarded.
3470 */
3471
Eric Andersen3102ac42001-07-06 04:26:23 +00003472#ifndef ASH_OPTIMIZE_FOR_SIZE
Eric Andersen2870d962001-07-02 17:27:21 +00003473#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
3474static int
3475pgetc(void)
3476{
3477 return pgetc_macro();
3478}
3479#else
3480static int
3481pgetc_macro(void)
3482{
3483 return --parsenleft >= 0? *parsenextc++ : preadbuffer();
3484}
3485
3486static inline int
3487pgetc(void)
3488{
3489 return pgetc_macro();
3490}
3491#endif
3492
3493
3494/*
3495 * Undo the last call to pgetc. Only one character may be pushed back.
3496 * PEOF may be pushed back.
3497 */
3498
3499static void
3500pungetc() {
3501 parsenleft++;
3502 parsenextc--;
3503}
3504
3505
3506static void
3507popfile(void) {
3508 struct parsefile *pf = parsefile;
3509
3510 INTOFF;
3511 if (pf->fd >= 0)
3512 close(pf->fd);
3513 if (pf->buf)
3514 ckfree(pf->buf);
3515 while (pf->strpush)
3516 popstring();
3517 parsefile = pf->prev;
3518 ckfree(pf);
3519 parsenleft = parsefile->nleft;
3520 parselleft = parsefile->lleft;
3521 parsenextc = parsefile->nextc;
3522 plinno = parsefile->linno;
3523 INTON;
3524}
3525
3526
3527/*
3528 * Return to top level.
3529 */
3530
3531static void
3532popallfiles(void) {
3533 while (parsefile != &basepf)
3534 popfile();
3535}
3536
3537/*
3538 * Close the file(s) that the shell is reading commands from. Called
3539 * after a fork is done.
3540 */
3541
3542static void
3543closescript() {
3544 popallfiles();
3545 if (parsefile->fd > 0) {
3546 close(parsefile->fd);
3547 parsefile->fd = 0;
3548 }
3549}
3550
3551
3552/*
3553 * Like setinputfile, but takes an open file descriptor. Call this with
3554 * interrupts off.
3555 */
3556
3557static void
3558setinputfd(fd, push)
3559 int fd, push;
3560{
3561 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
3562 if (push) {
3563 pushfile();
3564 parsefile->buf = 0;
3565 } else {
3566 closescript();
3567 while (parsefile->strpush)
3568 popstring();
3569 }
3570 parsefile->fd = fd;
3571 if (parsefile->buf == NULL)
3572 parsefile->buf = ckmalloc(BUFSIZ);
3573 parselleft = parsenleft = 0;
3574 plinno = 1;
3575}
3576
3577
3578/*
3579 * Set the input to take input from a file. If push is set, push the
3580 * old input onto the stack first.
3581 */
3582
3583static void
3584setinputfile(const char *fname, int push)
3585{
3586 int fd;
3587 int myfileno2;
3588
3589 INTOFF;
3590 if ((fd = open(fname, O_RDONLY)) < 0)
3591 error("Can't open %s", fname);
3592 if (fd < 10) {
3593 myfileno2 = dup_as_newfd(fd, 10);
3594 close(fd);
3595 if (myfileno2 < 0)
3596 error("Out of file descriptors");
3597 fd = myfileno2;
3598 }
3599 setinputfd(fd, push);
3600 INTON;
3601}
3602
Eric Andersencb57d552001-06-28 07:25:16 +00003603
3604static void
Eric Andersen62483552001-07-10 06:09:16 +00003605tryexec(char *cmd, char **argv, char **envp)
3606{
Eric Andersencb57d552001-06-28 07:25:16 +00003607 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003608
Eric Andersen3102ac42001-07-06 04:26:23 +00003609#ifdef BB_FEATURE_SH_STANDALONE_SHELL
3610 char *name = cmd;
3611 char** argv_l=argv;
3612 int argc_l;
3613#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
3614 name = get_last_path_component(name);
3615#endif
3616 argv_l=envp;
3617 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
3618 putenv(*argv_l);
3619 argv_l=argv;
Eric Andersen62483552001-07-10 06:09:16 +00003620 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
Eric Andersen3102ac42001-07-06 04:26:23 +00003621 optind = 1;
3622 run_applet_by_name(name, argc_l, argv);
3623#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003624 execve(cmd, argv, envp);
Eric Andersencb57d552001-06-28 07:25:16 +00003625 e = errno;
3626 if (e == ENOEXEC) {
3627 INTOFF;
3628 initshellproc();
3629 setinputfile(cmd, 0);
3630 commandname = arg0 = savestr(argv[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00003631 setparam(argv + 1);
3632 exraise(EXSHELLPROC);
3633 }
3634 errno = e;
3635}
3636
Eric Andersen2870d962001-07-02 17:27:21 +00003637static char *commandtext (const union node *);
Eric Andersencb57d552001-06-28 07:25:16 +00003638
3639/*
3640 * Do a path search. The variable path (passed by reference) should be
3641 * set to the start of the path before the first call; padvance will update
3642 * this value as it proceeds. Successive calls to padvance will return
3643 * the possible path expansions in sequence. If an option (indicated by
3644 * a percent sign) appears in the path entry then the global variable
3645 * pathopt will be set to point to it; otherwise pathopt will be set to
3646 * NULL.
3647 */
3648
3649static const char *pathopt;
3650
Eric Andersen2870d962001-07-02 17:27:21 +00003651static void growstackblock(void);
3652
3653
Eric Andersencb57d552001-06-28 07:25:16 +00003654static char *
Eric Andersen2870d962001-07-02 17:27:21 +00003655padvance(const char **path, const char *name)
3656{
Eric Andersencb57d552001-06-28 07:25:16 +00003657 const char *p;
3658 char *q;
3659 const char *start;
3660 int len;
3661
3662 if (*path == NULL)
3663 return NULL;
3664 start = *path;
3665 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
Eric Andersen2870d962001-07-02 17:27:21 +00003666 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003667 while (stackblocksize() < len)
3668 growstackblock();
3669 q = stackblock();
3670 if (p != start) {
3671 memcpy(q, start, p - start);
3672 q += p - start;
3673 *q++ = '/';
3674 }
3675 strcpy(q, name);
3676 pathopt = NULL;
3677 if (*p == '%') {
3678 pathopt = ++p;
3679 while (*p && *p != ':') p++;
3680 }
3681 if (*p == ':')
3682 *path = p + 1;
3683 else
3684 *path = NULL;
3685 return stalloc(len);
3686}
3687
Eric Andersen62483552001-07-10 06:09:16 +00003688/*
3689 * Wrapper around strcmp for qsort/bsearch/...
3690 */
3691static int
3692pstrcmp(const void *a, const void *b)
3693{
3694 return strcmp((const char *) a, *(const char *const *) b);
3695}
3696
3697/*
3698 * Find a keyword is in a sorted array.
3699 */
3700
3701static const char *const *
3702findkwd(const char *s)
3703{
3704 return bsearch(s, parsekwd, sizeof(parsekwd) / sizeof(const char *),
3705 sizeof(const char *), pstrcmp);
3706}
Eric Andersencb57d552001-06-28 07:25:16 +00003707
3708
3709/*** Command hashing code ***/
3710
3711
3712static int
3713hashcmd(argc, argv)
3714 int argc;
3715 char **argv;
3716{
3717 struct tblentry **pp;
3718 struct tblentry *cmdp;
3719 int c;
3720 int verbose;
3721 struct cmdentry entry;
3722 char *name;
Eric Andersen62483552001-07-10 06:09:16 +00003723#ifdef ASH_ALIAS
3724 const struct alias *ap;
3725#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003726
3727 verbose = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003728 while ((c = nextopt("rvV")) != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00003729 if (c == 'r') {
3730 clearcmdentry(0);
3731 return 0;
Eric Andersen62483552001-07-10 06:09:16 +00003732 } else if (c == 'v' || c == 'V') {
3733 verbose = c;
Eric Andersencb57d552001-06-28 07:25:16 +00003734 }
3735 }
3736 if (*argptr == NULL) {
3737 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3738 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3739 if (cmdp->cmdtype != CMDBUILTIN) {
3740 printentry(cmdp, verbose);
3741 }
3742 }
3743 }
3744 return 0;
3745 }
3746 c = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003747 while ((name = *argptr++) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00003748 if ((cmdp = cmdlookup(name, 0)) != NULL
3749 && (cmdp->cmdtype == CMDNORMAL
3750 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3751 delete_cmd_entry();
Eric Andersen62483552001-07-10 06:09:16 +00003752#ifdef ASH_ALIAS
3753 /* Then look at the aliases */
3754 if ((ap = lookupalias(name, 0)) != NULL) {
3755 if (verbose=='v')
3756 printf("%s is an alias for %s\n", name, ap->val);
3757 else
3758 printalias(ap);
3759 continue;
3760 }
3761#endif
3762 /* First look at the keywords */
3763 if (findkwd(name)!=0) {
3764 if (verbose=='v')
3765 printf("%s is a shell keyword\n", name);
3766 else
3767 printf(snlfmt, name);
3768 continue;
3769 }
3770
Eric Andersencb57d552001-06-28 07:25:16 +00003771 find_command(name, &entry, DO_ERR, pathval());
3772 if (entry.cmdtype == CMDUNKNOWN) c = 1;
3773 else if (verbose) {
3774 cmdp = cmdlookup(name, 0);
Eric Andersen62483552001-07-10 06:09:16 +00003775 if (cmdp) printentry(cmdp, verbose=='v');
Eric Andersencb57d552001-06-28 07:25:16 +00003776 flushall();
3777 }
Eric Andersencb57d552001-06-28 07:25:16 +00003778 }
3779 return c;
3780}
3781
Eric Andersencb57d552001-06-28 07:25:16 +00003782static void
3783printentry(cmdp, verbose)
3784 struct tblentry *cmdp;
3785 int verbose;
3786 {
3787 int idx;
3788 const char *path;
3789 char *name;
3790
Eric Andersen62483552001-07-10 06:09:16 +00003791 printf("%s%s", cmdp->cmdname, (verbose ? " is " : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00003792 if (cmdp->cmdtype == CMDNORMAL) {
3793 idx = cmdp->param.index;
3794 path = pathval();
3795 do {
3796 name = padvance(&path, cmdp->cmdname);
3797 stunalloc(name);
3798 } while (--idx >= 0);
Eric Andersen62483552001-07-10 06:09:16 +00003799 if(verbose)
3800 out1str(name);
Eric Andersencb57d552001-06-28 07:25:16 +00003801 } else if (cmdp->cmdtype == CMDBUILTIN) {
Eric Andersen62483552001-07-10 06:09:16 +00003802 if(verbose)
3803 out1str("a shell builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00003804 } else if (cmdp->cmdtype == CMDFUNCTION) {
Eric Andersencb57d552001-06-28 07:25:16 +00003805 if (verbose) {
3806 INTOFF;
Eric Andersen62483552001-07-10 06:09:16 +00003807 out1str("a function\n");
Eric Andersencb57d552001-06-28 07:25:16 +00003808 name = commandtext(cmdp->param.func);
Eric Andersen62483552001-07-10 06:09:16 +00003809 printf("%s() {\n %s\n}", cmdp->cmdname, name);
Eric Andersencb57d552001-06-28 07:25:16 +00003810 ckfree(name);
3811 INTON;
3812 }
3813#ifdef DEBUG
3814 } else {
3815 error("internal error: cmdtype %d", cmdp->cmdtype);
3816#endif
3817 }
Eric Andersen62483552001-07-10 06:09:16 +00003818 printf(snlfmt, cmdp->rehash ? "*" : nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +00003819}
3820
3821
3822
Eric Andersen1c039232001-07-07 00:05:55 +00003823/*** List the available builtins ***/
3824
3825
3826static int helpcmd(int argc, char** argv)
3827{
3828 int col, i;
Eric Andersen1c039232001-07-07 00:05:55 +00003829
Eric Andersen62483552001-07-10 06:09:16 +00003830 printf("\nBuilt-in commands:\n-------------------\n");
3831 for (col=0, i=0; i < NUMBUILTINS; i++) {
3832 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3833 builtincmds[i].name+1);
Eric Andersen1c039232001-07-07 00:05:55 +00003834 if (col > 60) {
3835 printf("\n");
3836 col = 0;
3837 }
3838 }
3839#ifdef BB_FEATURE_SH_STANDALONE_SHELL
3840 {
Eric Andersen1c039232001-07-07 00:05:55 +00003841 extern const struct BB_applet applets[];
3842 extern const size_t NUM_APPLETS;
3843
Eric Andersen62483552001-07-10 06:09:16 +00003844 for (i=0; i < NUM_APPLETS; i++) {
3845
3846 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3847 applets[i].name);
Eric Andersen1c039232001-07-07 00:05:55 +00003848 if (col > 60) {
3849 printf("\n");
3850 col = 0;
3851 }
3852 }
3853 }
3854#endif
3855 printf("\n\n");
3856 return EXIT_SUCCESS;
3857}
3858
Eric Andersencb57d552001-06-28 07:25:16 +00003859/*
3860 * Resolve a command name. If you change this routine, you may have to
3861 * change the shellexec routine as well.
3862 */
3863
Eric Andersen2870d962001-07-02 17:27:21 +00003864static int prefix (const char *, const char *);
3865
Eric Andersencb57d552001-06-28 07:25:16 +00003866static void
Eric Andersen2870d962001-07-02 17:27:21 +00003867find_command(const char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003868{
3869 struct tblentry *cmdp;
3870 int idx;
3871 int prev;
3872 char *fullname;
3873 struct stat statb;
3874 int e;
3875 int bltin;
3876 int firstchange;
3877 int updatetbl;
Eric Andersen62483552001-07-10 06:09:16 +00003878 int regular;
Eric Andersencb57d552001-06-28 07:25:16 +00003879 struct builtincmd *bcmd;
3880
3881 /* If name contains a slash, don't use the hash table */
3882 if (strchr(name, '/') != NULL) {
3883 if (act & DO_ABS) {
3884 while (stat(name, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003885 if (errno != ENOENT && errno != ENOTDIR)
3886 e = errno;
3887 entry->cmdtype = CMDUNKNOWN;
3888 entry->u.index = -1;
3889 return;
3890 }
3891 entry->cmdtype = CMDNORMAL;
3892 entry->u.index = -1;
3893 return;
3894 }
3895 entry->cmdtype = CMDNORMAL;
3896 entry->u.index = 0;
3897 return;
3898 }
3899
3900 updatetbl = 1;
3901 if (act & DO_BRUTE) {
3902 firstchange = path_change(path, &bltin);
3903 } else {
3904 bltin = builtinloc;
3905 firstchange = 9999;
3906 }
3907
3908 /* If name is in the table, and not invalidated by cd, we're done */
3909 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
3910 if (cmdp->cmdtype == CMDFUNCTION) {
3911 if (act & DO_NOFUN) {
3912 updatetbl = 0;
3913 } else {
3914 goto success;
3915 }
3916 } else if (act & DO_BRUTE) {
3917 if ((cmdp->cmdtype == CMDNORMAL &&
3918 cmdp->param.index >= firstchange) ||
3919 (cmdp->cmdtype == CMDBUILTIN &&
3920 ((builtinloc < 0 && bltin >= 0) ?
3921 bltin : builtinloc) >= firstchange)) {
3922 /* need to recompute the entry */
3923 } else {
3924 goto success;
3925 }
3926 } else {
3927 goto success;
3928 }
3929 }
3930
3931 bcmd = find_builtin(name);
Eric Andersen2870d962001-07-02 17:27:21 +00003932 regular = bcmd && IS_BUILTIN_REGULAR(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00003933
3934 if (regular) {
3935 if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) {
Eric Andersen2870d962001-07-02 17:27:21 +00003936 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003937 }
3938 } else if (act & DO_BRUTE) {
3939 if (firstchange == 0) {
3940 updatetbl = 0;
3941 }
3942 }
3943
3944 /* If %builtin not in path, check for builtin next */
3945 if (regular || (bltin < 0 && bcmd)) {
3946builtin:
3947 if (!updatetbl) {
3948 entry->cmdtype = CMDBUILTIN;
3949 entry->u.cmd = bcmd;
3950 return;
3951 }
3952 INTOFF;
3953 cmdp = cmdlookup(name, 1);
3954 cmdp->cmdtype = CMDBUILTIN;
3955 cmdp->param.cmd = bcmd;
3956 INTON;
3957 goto success;
3958 }
3959
3960 /* We have to search path. */
Eric Andersen2870d962001-07-02 17:27:21 +00003961 prev = -1; /* where to start */
3962 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00003963 if (cmdp->cmdtype == CMDBUILTIN)
3964 prev = builtinloc;
3965 else
3966 prev = cmdp->param.index;
3967 }
3968
3969 e = ENOENT;
3970 idx = -1;
3971loop:
3972 while ((fullname = padvance(&path, name)) != NULL) {
3973 stunalloc(fullname);
3974 idx++;
3975 if (idx >= firstchange) {
3976 updatetbl = 0;
3977 }
3978 if (pathopt) {
3979 if (prefix("builtin", pathopt)) {
3980 if ((bcmd = find_builtin(name))) {
3981 goto builtin;
3982 }
3983 continue;
3984 } else if (!(act & DO_NOFUN) &&
3985 prefix("func", pathopt)) {
3986 /* handled below */
3987 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00003988 continue; /* ignore unimplemented options */
Eric Andersencb57d552001-06-28 07:25:16 +00003989 }
3990 }
3991 /* if rehash, don't redo absolute path names */
3992 if (fullname[0] == '/' && idx <= prev &&
3993 idx < firstchange) {
3994 if (idx < prev)
3995 continue;
3996 TRACE(("searchexec \"%s\": no change\n", name));
3997 goto success;
3998 }
3999 while (stat(fullname, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00004000 if (errno != ENOENT && errno != ENOTDIR)
4001 e = errno;
4002 goto loop;
4003 }
Eric Andersen2870d962001-07-02 17:27:21 +00004004 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00004005 if (!S_ISREG(statb.st_mode))
4006 continue;
Eric Andersen2870d962001-07-02 17:27:21 +00004007 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00004008 stalloc(strlen(fullname) + 1);
4009 readcmdfile(fullname);
4010 if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
4011 error("%s not defined in %s", name, fullname);
4012 stunalloc(fullname);
4013 goto success;
4014 }
Eric Andersencb57d552001-06-28 07:25:16 +00004015 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
4016 /* If we aren't called with DO_BRUTE and cmdp is set, it must
4017 be a function and we're being called with DO_NOFUN */
4018 if (!updatetbl) {
4019 entry->cmdtype = CMDNORMAL;
4020 entry->u.index = idx;
4021 return;
4022 }
4023 INTOFF;
4024 cmdp = cmdlookup(name, 1);
4025 cmdp->cmdtype = CMDNORMAL;
4026 cmdp->param.index = idx;
4027 INTON;
4028 goto success;
4029 }
4030
4031 /* We failed. If there was an entry for this command, delete it */
4032 if (cmdp && updatetbl)
4033 delete_cmd_entry();
4034 if (act & DO_ERR)
Eric Andersen3102ac42001-07-06 04:26:23 +00004035 out2fmt("%s: %s\n", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00004036 entry->cmdtype = CMDUNKNOWN;
4037 return;
4038
4039success:
4040 cmdp->rehash = 0;
4041 entry->cmdtype = cmdp->cmdtype;
4042 entry->u = cmdp->param;
4043}
4044
4045
4046
4047/*
4048 * Search the table of builtin commands.
4049 */
4050
Eric Andersen2870d962001-07-02 17:27:21 +00004051static int
4052bstrcmp(const void *name, const void *b)
4053{
4054 return strcmp((const char *)name, (*(const char *const *) b)+1);
4055}
4056
4057static struct builtincmd *
4058find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00004059{
4060 struct builtincmd *bp;
4061
Eric Andersen2870d962001-07-02 17:27:21 +00004062 bp = bsearch(name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd),
4063 bstrcmp
Eric Andersencb57d552001-06-28 07:25:16 +00004064 );
4065 return bp;
4066}
4067
4068
4069/*
4070 * Called when a cd is done. Marks all commands so the next time they
4071 * are executed they will be rehashed.
4072 */
4073
4074static void
Eric Andersen2870d962001-07-02 17:27:21 +00004075hashcd(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00004076 struct tblentry **pp;
4077 struct tblentry *cmdp;
4078
4079 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4080 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4081 if (cmdp->cmdtype == CMDNORMAL
4082 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
4083 cmdp->rehash = 1;
4084 }
4085 }
4086}
4087
4088
4089
4090/*
4091 * Called before PATH is changed. The argument is the new value of PATH;
4092 * pathval() still returns the old value at this point. Called with
4093 * interrupts off.
4094 */
4095
4096static void
Eric Andersen2870d962001-07-02 17:27:21 +00004097changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00004098{
4099 int firstchange;
4100 int bltin;
4101
4102 firstchange = path_change(newval, &bltin);
4103 if (builtinloc < 0 && bltin >= 0)
Eric Andersen2870d962001-07-02 17:27:21 +00004104 builtinloc = bltin; /* zap builtins */
Eric Andersencb57d552001-06-28 07:25:16 +00004105 clearcmdentry(firstchange);
4106 builtinloc = bltin;
4107}
4108
4109
4110/*
4111 * Clear out command entries. The argument specifies the first entry in
4112 * PATH which has changed.
4113 */
4114
4115static void
4116clearcmdentry(firstchange)
4117 int firstchange;
4118{
4119 struct tblentry **tblp;
4120 struct tblentry **pp;
4121 struct tblentry *cmdp;
4122
4123 INTOFF;
4124 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4125 pp = tblp;
4126 while ((cmdp = *pp) != NULL) {
4127 if ((cmdp->cmdtype == CMDNORMAL &&
4128 cmdp->param.index >= firstchange)
4129 || (cmdp->cmdtype == CMDBUILTIN &&
4130 builtinloc >= firstchange)) {
4131 *pp = cmdp->next;
4132 ckfree(cmdp);
4133 } else {
4134 pp = &cmdp->next;
4135 }
4136 }
4137 }
4138 INTON;
4139}
4140
4141
4142/*
4143 * Delete all functions.
4144 */
4145
Eric Andersencb57d552001-06-28 07:25:16 +00004146static void
Eric Andersen2870d962001-07-02 17:27:21 +00004147deletefuncs(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00004148 struct tblentry **tblp;
4149 struct tblentry **pp;
4150 struct tblentry *cmdp;
4151
4152 INTOFF;
4153 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4154 pp = tblp;
4155 while ((cmdp = *pp) != NULL) {
4156 if (cmdp->cmdtype == CMDFUNCTION) {
4157 *pp = cmdp->next;
4158 freefunc(cmdp->param.func);
4159 ckfree(cmdp);
4160 } else {
4161 pp = &cmdp->next;
4162 }
4163 }
4164 }
4165 INTON;
4166}
4167
4168
4169
4170/*
4171 * Locate a command in the command hash table. If "add" is nonzero,
4172 * add the command to the table if it is not already present. The
4173 * variable "lastcmdentry" is set to point to the address of the link
4174 * pointing to the entry, so that delete_cmd_entry can delete the
4175 * entry.
4176 */
4177
Eric Andersen2870d962001-07-02 17:27:21 +00004178static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00004179
4180static struct tblentry *
Eric Andersen2870d962001-07-02 17:27:21 +00004181cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00004182{
4183 int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00004184 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00004185 struct tblentry *cmdp;
4186 struct tblentry **pp;
4187
4188 p = name;
4189 hashval = *p << 4;
4190 while (*p)
4191 hashval += *p++;
4192 hashval &= 0x7FFF;
4193 pp = &cmdtable[hashval % CMDTABLESIZE];
4194 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4195 if (equal(cmdp->cmdname, name))
4196 break;
4197 pp = &cmdp->next;
4198 }
4199 if (add && cmdp == NULL) {
4200 INTOFF;
4201 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4202 + strlen(name) + 1);
4203 cmdp->next = NULL;
4204 cmdp->cmdtype = CMDUNKNOWN;
4205 cmdp->rehash = 0;
4206 strcpy(cmdp->cmdname, name);
4207 INTON;
4208 }
4209 lastcmdentry = pp;
4210 return cmdp;
4211}
4212
4213/*
4214 * Delete the command entry returned on the last lookup.
4215 */
4216
4217static void
4218delete_cmd_entry() {
4219 struct tblentry *cmdp;
4220
4221 INTOFF;
4222 cmdp = *lastcmdentry;
4223 *lastcmdentry = cmdp->next;
4224 ckfree(cmdp);
4225 INTON;
4226}
4227
4228
4229
Eric Andersencb57d552001-06-28 07:25:16 +00004230
4231
Eric Andersen62483552001-07-10 06:09:16 +00004232static const short nodesize[26] = {
4233 ALIGN(sizeof (struct nbinary)),
4234 ALIGN(sizeof (struct ncmd)),
4235 ALIGN(sizeof (struct npipe)),
4236 ALIGN(sizeof (struct nredir)),
4237 ALIGN(sizeof (struct nredir)),
4238 ALIGN(sizeof (struct nredir)),
4239 ALIGN(sizeof (struct nbinary)),
4240 ALIGN(sizeof (struct nbinary)),
4241 ALIGN(sizeof (struct nif)),
4242 ALIGN(sizeof (struct nbinary)),
4243 ALIGN(sizeof (struct nbinary)),
4244 ALIGN(sizeof (struct nfor)),
4245 ALIGN(sizeof (struct ncase)),
4246 ALIGN(sizeof (struct nclist)),
4247 ALIGN(sizeof (struct narg)),
4248 ALIGN(sizeof (struct narg)),
4249 ALIGN(sizeof (struct nfile)),
4250 ALIGN(sizeof (struct nfile)),
4251 ALIGN(sizeof (struct nfile)),
4252 ALIGN(sizeof (struct nfile)),
4253 ALIGN(sizeof (struct nfile)),
4254 ALIGN(sizeof (struct ndup)),
4255 ALIGN(sizeof (struct ndup)),
4256 ALIGN(sizeof (struct nhere)),
4257 ALIGN(sizeof (struct nhere)),
4258 ALIGN(sizeof (struct nnot)),
4259};
Eric Andersencb57d552001-06-28 07:25:16 +00004260
Eric Andersencb57d552001-06-28 07:25:16 +00004261
4262
4263/*
4264 * Delete a function if it exists.
4265 */
4266
4267static void
Eric Andersen2870d962001-07-02 17:27:21 +00004268unsetfunc(char *name)
4269{
Eric Andersencb57d552001-06-28 07:25:16 +00004270 struct tblentry *cmdp;
4271
4272 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
4273 freefunc(cmdp->param.func);
4274 delete_cmd_entry();
4275 }
4276}
4277
Eric Andersen2870d962001-07-02 17:27:21 +00004278
4279/*
Eric Andersencb57d552001-06-28 07:25:16 +00004280 * Locate and print what a word is...
4281 */
4282
4283static int
Eric Andersen62483552001-07-10 06:09:16 +00004284typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004285{
4286 int i;
4287 int err = 0;
Eric Andersen62483552001-07-10 06:09:16 +00004288 char *argv_a[2];
4289
4290 argv_a[1] = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004291
4292 for (i = 1; i < argc; i++) {
Eric Andersen62483552001-07-10 06:09:16 +00004293 argv_a[0] = argv[i];
4294 argptr = argv_a;
4295 optptr = "v";
4296 err |= hashcmd(argc, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00004297 }
4298 return err;
4299}
4300
Eric Andersen2870d962001-07-02 17:27:21 +00004301#ifdef ASH_CMDCMD
Eric Andersencb57d552001-06-28 07:25:16 +00004302static int
4303commandcmd(argc, argv)
4304 int argc;
4305 char **argv;
4306{
4307 int c;
4308 int default_path = 0;
4309 int verify_only = 0;
4310 int verbose_verify_only = 0;
4311
4312 while ((c = nextopt("pvV")) != '\0')
4313 switch (c) {
4314 case 'p':
4315 default_path = 1;
4316 break;
4317 case 'v':
4318 verify_only = 1;
4319 break;
4320 case 'V':
4321 verbose_verify_only = 1;
4322 break;
Eric Andersencb57d552001-06-28 07:25:16 +00004323 }
4324
4325 if (default_path + verify_only + verbose_verify_only > 1 ||
4326 !*argptr) {
Eric Andersen62483552001-07-10 06:09:16 +00004327 out2str(
4328 "command [-p] command [arg ...]\n"
4329 "command {-v|-V} command\n");
Eric Andersencb57d552001-06-28 07:25:16 +00004330 return EX_USAGE;
4331 }
4332
Eric Andersencb57d552001-06-28 07:25:16 +00004333 if (verify_only || verbose_verify_only) {
Eric Andersen62483552001-07-10 06:09:16 +00004334 char *argv_a[2];
4335
4336 argv_a[1] = 0;
4337 argv_a[0] = *argptr;
4338 argptr = argv_a;
4339 optptr = verbose_verify_only ? "v" : "V"; /* reverse special */
4340 return hashcmd(argc, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00004341 }
Eric Andersencb57d552001-06-28 07:25:16 +00004342
4343 return 0;
4344}
Eric Andersen2870d962001-07-02 17:27:21 +00004345#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004346
4347static int
4348path_change(newval, bltin)
4349 const char *newval;
4350 int *bltin;
4351{
4352 const char *old, *new;
4353 int idx;
4354 int firstchange;
4355
4356 old = pathval();
4357 new = newval;
Eric Andersen2870d962001-07-02 17:27:21 +00004358 firstchange = 9999; /* assume no change */
Eric Andersencb57d552001-06-28 07:25:16 +00004359 idx = 0;
4360 *bltin = -1;
4361 for (;;) {
4362 if (*old != *new) {
4363 firstchange = idx;
4364 if ((*old == '\0' && *new == ':')
4365 || (*old == ':' && *new == '\0'))
4366 firstchange++;
Eric Andersen2870d962001-07-02 17:27:21 +00004367 old = new; /* ignore subsequent differences */
Eric Andersencb57d552001-06-28 07:25:16 +00004368 }
4369 if (*new == '\0')
4370 break;
4371 if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1))
4372 *bltin = idx;
4373 if (*new == ':') {
4374 idx++;
4375 }
4376 new++, old++;
4377 }
4378 if (builtinloc >= 0 && *bltin < 0)
4379 firstchange = 0;
4380 return firstchange;
4381}
Eric Andersencb57d552001-06-28 07:25:16 +00004382/*
4383 * Routines to expand arguments to commands. We have to deal with
4384 * backquotes, shell variables, and file metacharacters.
4385 */
4386/*
4387 * _rmescape() flags
4388 */
Eric Andersen2870d962001-07-02 17:27:21 +00004389#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4390#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Eric Andersencb57d552001-06-28 07:25:16 +00004391
4392/*
4393 * Structure specifying which parts of the string should be searched
4394 * for IFS characters.
4395 */
4396
4397struct ifsregion {
Eric Andersen2870d962001-07-02 17:27:21 +00004398 struct ifsregion *next; /* next region in list */
4399 int begoff; /* offset of start of region */
4400 int endoff; /* offset of end of region */
4401 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004402};
4403
4404
Eric Andersen2870d962001-07-02 17:27:21 +00004405static char *expdest; /* output of current string */
4406static struct nodelist *argbackq; /* list of back quote expressions */
4407static struct ifsregion ifsfirst; /* first struct in list of ifs regions */
4408static struct ifsregion *ifslastp; /* last struct in list */
4409static struct arglist exparg; /* holds expanded arg list */
Eric Andersencb57d552001-06-28 07:25:16 +00004410
Eric Andersen2870d962001-07-02 17:27:21 +00004411static void argstr (char *, int);
4412static char *exptilde (char *, int);
4413static void expbackq (union node *, int, int);
4414static int subevalvar (char *, char *, int, int, int, int, int);
Eric Andersen2870d962001-07-02 17:27:21 +00004415static int varisset (char *, int);
4416static void strtodest (const char *, const char *, int);
4417static void varvalue (char *, int, int);
4418static void recordregion (int, int, int);
4419static void removerecordregions (int);
4420static void ifsbreakup (char *, struct arglist *);
4421static void ifsfree (void);
4422static void expandmeta (struct strlist *, int);
Eric Andersen62483552001-07-10 06:09:16 +00004423#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00004424#define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB)
4425#if !defined(GLOB_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00004426static void addglob (const glob_t *);
Eric Andersencb57d552001-06-28 07:25:16 +00004427#endif
4428#endif
Eric Andersen62483552001-07-10 06:09:16 +00004429#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersen2870d962001-07-02 17:27:21 +00004430static void expmeta (char *, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004431#endif
Eric Andersen62483552001-07-10 06:09:16 +00004432#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersen2870d962001-07-02 17:27:21 +00004433static struct strlist *expsort (struct strlist *);
4434static struct strlist *msort (struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004435#endif
Eric Andersen2870d962001-07-02 17:27:21 +00004436static int patmatch (char *, char *, int);
Eric Andersen62483552001-07-10 06:09:16 +00004437#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00004438static int patmatch2 (char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004439#else
Eric Andersen2870d962001-07-02 17:27:21 +00004440static int pmatch (char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004441#define patmatch2 patmatch
4442#endif
Eric Andersen2870d962001-07-02 17:27:21 +00004443static char *cvtnum (int, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004444
4445/*
4446 * Expand shell variables and backquotes inside a here document.
4447 */
4448
Eric Andersen2870d962001-07-02 17:27:21 +00004449/* arg: the document, fd: where to write the expanded version */
Eric Andersen62483552001-07-10 06:09:16 +00004450static inline void
Eric Andersen2870d962001-07-02 17:27:21 +00004451expandhere(union node *arg, int fd)
4452{
Eric Andersencb57d552001-06-28 07:25:16 +00004453 herefd = fd;
4454 expandarg(arg, (struct arglist *)NULL, 0);
4455 xwrite(fd, stackblock(), expdest - stackblock());
4456}
4457
4458
4459/*
4460 * Perform variable substitution and command substitution on an argument,
4461 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4462 * perform splitting and file name expansion. When arglist is NULL, perform
4463 * here document expansion.
4464 */
4465
4466static void
4467expandarg(arg, arglist, flag)
4468 union node *arg;
4469 struct arglist *arglist;
4470 int flag;
4471{
4472 struct strlist *sp;
4473 char *p;
4474
4475 argbackq = arg->narg.backquote;
4476 STARTSTACKSTR(expdest);
4477 ifsfirst.next = NULL;
4478 ifslastp = NULL;
4479 argstr(arg->narg.text, flag);
4480 if (arglist == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00004481 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004482 }
4483 STPUTC('\0', expdest);
4484 p = grabstackstr(expdest);
4485 exparg.lastp = &exparg.list;
4486 /*
4487 * TODO - EXP_REDIR
4488 */
4489 if (flag & EXP_FULL) {
4490 ifsbreakup(p, &exparg);
4491 *exparg.lastp = NULL;
4492 exparg.lastp = &exparg.list;
4493 expandmeta(exparg.list, flag);
4494 } else {
4495 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4496 rmescapes(p);
4497 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4498 sp->text = p;
4499 *exparg.lastp = sp;
4500 exparg.lastp = &sp->next;
4501 }
4502 ifsfree();
4503 *exparg.lastp = NULL;
4504 if (exparg.list) {
4505 *arglist->lastp = exparg.list;
4506 arglist->lastp = exparg.lastp;
4507 }
4508}
4509
4510
Eric Andersen62483552001-07-10 06:09:16 +00004511/*
4512 * Expand a variable, and return a pointer to the next character in the
4513 * input string.
4514 */
4515
4516static inline char *
4517evalvar(p, flag)
4518 char *p;
4519 int flag;
4520{
4521 int subtype;
4522 int varflags;
4523 char *var;
4524 const char *val;
4525 int patloc;
4526 int c;
4527 int set;
4528 int special;
4529 int startloc;
4530 int varlen;
4531 int easy;
4532 int quotes = flag & (EXP_FULL | EXP_CASE);
4533
4534 varflags = *p++;
4535 subtype = varflags & VSTYPE;
4536 var = p;
4537 special = 0;
4538 if (! is_name(*p))
4539 special = 1;
4540 p = strchr(p, '=') + 1;
4541again: /* jump here after setting a variable with ${var=text} */
4542 if (special) {
4543 set = varisset(var, varflags & VSNUL);
4544 val = NULL;
4545 } else {
4546 val = lookupvar(var);
4547 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
4548 val = NULL;
4549 set = 0;
4550 } else
4551 set = 1;
4552 }
4553 varlen = 0;
4554 startloc = expdest - stackblock();
4555 if (set && subtype != VSPLUS) {
4556 /* insert the value of the variable */
4557 if (special) {
4558 varvalue(var, varflags & VSQUOTE, flag);
4559 if (subtype == VSLENGTH) {
4560 varlen = expdest - stackblock() - startloc;
4561 STADJUST(-varlen, expdest);
4562 }
4563 } else {
4564 if (subtype == VSLENGTH) {
4565 varlen = strlen(val);
4566 } else {
4567 strtodest(
4568 val,
4569 varflags & VSQUOTE ?
4570 DQSYNTAX : BASESYNTAX,
4571 quotes
4572 );
4573 }
4574 }
4575 }
4576
4577 if (subtype == VSPLUS)
4578 set = ! set;
4579
4580 easy = ((varflags & VSQUOTE) == 0 ||
4581 (*var == '@' && shellparam.nparam != 1));
4582
4583
4584 switch (subtype) {
4585 case VSLENGTH:
4586 expdest = cvtnum(varlen, expdest);
4587 goto record;
4588
4589 case VSNORMAL:
4590 if (!easy)
4591 break;
4592record:
4593 recordregion(startloc, expdest - stackblock(),
4594 varflags & VSQUOTE);
4595 break;
4596
4597 case VSPLUS:
4598 case VSMINUS:
4599 if (!set) {
4600 argstr(p, flag);
4601 break;
4602 }
4603 if (easy)
4604 goto record;
4605 break;
4606
4607 case VSTRIMLEFT:
4608 case VSTRIMLEFTMAX:
4609 case VSTRIMRIGHT:
4610 case VSTRIMRIGHTMAX:
4611 if (!set)
4612 break;
4613 /*
4614 * Terminate the string and start recording the pattern
4615 * right after it
4616 */
4617 STPUTC('\0', expdest);
4618 patloc = expdest - stackblock();
4619 if (subevalvar(p, NULL, patloc, subtype,
4620 startloc, varflags, quotes) == 0) {
4621 int amount = (expdest - stackblock() - patloc) + 1;
4622 STADJUST(-amount, expdest);
4623 }
4624 /* Remove any recorded regions beyond start of variable */
4625 removerecordregions(startloc);
4626 goto record;
4627
4628 case VSASSIGN:
4629 case VSQUESTION:
4630 if (!set) {
4631 if (subevalvar(p, var, 0, subtype, startloc,
4632 varflags, quotes)) {
4633 varflags &= ~VSNUL;
4634 /*
4635 * Remove any recorded regions beyond
4636 * start of variable
4637 */
4638 removerecordregions(startloc);
4639 goto again;
4640 }
4641 break;
4642 }
4643 if (easy)
4644 goto record;
4645 break;
4646
4647#ifdef DEBUG
4648 default:
4649 abort();
4650#endif
4651 }
4652
4653 if (subtype != VSNORMAL) { /* skip to end of alternative */
4654 int nesting = 1;
4655 for (;;) {
4656 if ((c = *p++) == CTLESC)
4657 p++;
4658 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
4659 if (set)
4660 argbackq = argbackq->next;
4661 } else if (c == CTLVAR) {
4662 if ((*p++ & VSTYPE) != VSNORMAL)
4663 nesting++;
4664 } else if (c == CTLENDVAR) {
4665 if (--nesting == 0)
4666 break;
4667 }
4668 }
4669 }
4670 return p;
4671}
4672
Eric Andersencb57d552001-06-28 07:25:16 +00004673
4674/*
4675 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4676 * characters to allow for further processing. Otherwise treat
4677 * $@ like $* since no splitting will be performed.
4678 */
4679
4680static void
4681argstr(p, flag)
4682 char *p;
4683 int flag;
4684{
4685 char c;
Eric Andersen2870d962001-07-02 17:27:21 +00004686 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
Eric Andersencb57d552001-06-28 07:25:16 +00004687 int firsteq = 1;
4688
4689 if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
4690 p = exptilde(p, flag);
4691 for (;;) {
4692 switch (c = *p++) {
4693 case '\0':
4694 case CTLENDVAR: /* ??? */
4695 goto breakloop;
4696 case CTLQUOTEMARK:
4697 /* "$@" syntax adherence hack */
4698 if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
4699 break;
4700 if ((flag & EXP_FULL) != 0)
4701 STPUTC(c, expdest);
4702 break;
4703 case CTLESC:
4704 if (quotes)
4705 STPUTC(c, expdest);
4706 c = *p++;
4707 STPUTC(c, expdest);
4708 break;
4709 case CTLVAR:
4710 p = evalvar(p, flag);
4711 break;
4712 case CTLBACKQ:
4713 case CTLBACKQ|CTLQUOTE:
4714 expbackq(argbackq->n, c & CTLQUOTE, flag);
4715 argbackq = argbackq->next;
4716 break;
4717#ifdef ASH_MATH_SUPPORT
4718 case CTLENDARI:
4719 expari(flag);
4720 break;
Eric Andersen2870d962001-07-02 17:27:21 +00004721#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004722 case ':':
4723 case '=':
4724 /*
4725 * sort of a hack - expand tildes in variable
4726 * assignments (after the first '=' and after ':'s).
4727 */
4728 STPUTC(c, expdest);
4729 if (flag & EXP_VARTILDE && *p == '~') {
4730 if (c == '=') {
4731 if (firsteq)
4732 firsteq = 0;
4733 else
4734 break;
4735 }
4736 p = exptilde(p, flag);
4737 }
4738 break;
4739 default:
4740 STPUTC(c, expdest);
4741 }
4742 }
4743breakloop:;
4744 return;
4745}
4746
4747static char *
4748exptilde(p, flag)
4749 char *p;
4750 int flag;
4751{
4752 char c, *startp = p;
4753 struct passwd *pw;
4754 const char *home;
4755 int quotes = flag & (EXP_FULL | EXP_CASE);
4756
4757 while ((c = *p) != '\0') {
4758 switch(c) {
4759 case CTLESC:
4760 return (startp);
4761 case CTLQUOTEMARK:
4762 return (startp);
4763 case ':':
4764 if (flag & EXP_VARTILDE)
4765 goto done;
4766 break;
4767 case '/':
4768 goto done;
4769 }
4770 p++;
4771 }
4772done:
4773 *p = '\0';
4774 if (*(startp+1) == '\0') {
4775 if ((home = lookupvar("HOME")) == NULL)
4776 goto lose;
4777 } else {
4778 if ((pw = getpwnam(startp+1)) == NULL)
4779 goto lose;
4780 home = pw->pw_dir;
4781 }
4782 if (*home == '\0')
4783 goto lose;
4784 *p = c;
4785 strtodest(home, SQSYNTAX, quotes);
4786 return (p);
4787lose:
4788 *p = c;
4789 return (startp);
4790}
4791
4792
Eric Andersen2870d962001-07-02 17:27:21 +00004793static void
4794removerecordregions(int endoff)
Eric Andersencb57d552001-06-28 07:25:16 +00004795{
4796 if (ifslastp == NULL)
4797 return;
4798
4799 if (ifsfirst.endoff > endoff) {
4800 while (ifsfirst.next != NULL) {
4801 struct ifsregion *ifsp;
4802 INTOFF;
4803 ifsp = ifsfirst.next->next;
4804 ckfree(ifsfirst.next);
4805 ifsfirst.next = ifsp;
4806 INTON;
4807 }
4808 if (ifsfirst.begoff > endoff)
4809 ifslastp = NULL;
4810 else {
4811 ifslastp = &ifsfirst;
4812 ifsfirst.endoff = endoff;
4813 }
4814 return;
4815 }
Eric Andersen2870d962001-07-02 17:27:21 +00004816
Eric Andersencb57d552001-06-28 07:25:16 +00004817 ifslastp = &ifsfirst;
4818 while (ifslastp->next && ifslastp->next->begoff < endoff)
4819 ifslastp=ifslastp->next;
4820 while (ifslastp->next != NULL) {
4821 struct ifsregion *ifsp;
4822 INTOFF;
4823 ifsp = ifslastp->next->next;
4824 ckfree(ifslastp->next);
4825 ifslastp->next = ifsp;
4826 INTON;
4827 }
4828 if (ifslastp->endoff > endoff)
4829 ifslastp->endoff = endoff;
4830}
4831
4832
4833#ifdef ASH_MATH_SUPPORT
4834/*
4835 * Expand arithmetic expression. Backup to start of expression,
4836 * evaluate, place result in (backed up) result, adjust string position.
4837 */
4838static void
Eric Andersen2870d962001-07-02 17:27:21 +00004839expari(int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004840{
4841 char *p, *start;
4842 int result;
4843 int begoff;
4844 int quotes = flag & (EXP_FULL | EXP_CASE);
4845 int quoted;
4846
Eric Andersen2870d962001-07-02 17:27:21 +00004847 /* ifsfree(); */
Eric Andersencb57d552001-06-28 07:25:16 +00004848
4849 /*
4850 * This routine is slightly over-complicated for
4851 * efficiency. First we make sure there is
4852 * enough space for the result, which may be bigger
4853 * than the expression if we add exponentation. Next we
4854 * scan backwards looking for the start of arithmetic. If the
4855 * next previous character is a CTLESC character, then we
4856 * have to rescan starting from the beginning since CTLESC
4857 * characters have to be processed left to right.
4858 */
4859 CHECKSTRSPACE(10, expdest);
4860 USTPUTC('\0', expdest);
4861 start = stackblock();
4862 p = expdest - 1;
4863 while (*p != CTLARI && p >= start)
4864 --p;
4865 if (*p != CTLARI)
4866 error("missing CTLARI (shouldn't happen)");
4867 if (p > start && *(p-1) == CTLESC)
4868 for (p = start; *p != CTLARI; p++)
4869 if (*p == CTLESC)
4870 p++;
4871
4872 if (p[1] == '"')
4873 quoted=1;
4874 else
4875 quoted=0;
4876 begoff = p - start;
4877 removerecordregions(begoff);
4878 if (quotes)
4879 rmescapes(p+2);
Eric Andersenfa1c5aa2001-07-31 21:38:23 +00004880 result = arith(p+2);
4881 if (result < 0)
4882 error("arith: syntax error: \"%s\"\n", p+2);
Eric Andersen3102ac42001-07-06 04:26:23 +00004883 snprintf(p, 12, "%d", result);
Eric Andersencb57d552001-06-28 07:25:16 +00004884
4885 while (*p++)
4886 ;
4887
4888 if (quoted == 0)
4889 recordregion(begoff, p - 1 - start, 0);
4890 result = expdest - p + 1;
4891 STADJUST(-result, expdest);
4892}
Eric Andersen2870d962001-07-02 17:27:21 +00004893#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004894
4895/*
4896 * Expand stuff in backwards quotes.
4897 */
4898
4899static void
4900expbackq(cmd, quoted, flag)
4901 union node *cmd;
4902 int quoted;
4903 int flag;
4904{
4905 volatile struct backcmd in;
4906 int i;
4907 char buf[128];
4908 char *p;
4909 char *dest = expdest;
4910 volatile struct ifsregion saveifs;
4911 struct ifsregion *volatile savelastp;
4912 struct nodelist *volatile saveargbackq;
4913 char lastc;
4914 int startloc = dest - stackblock();
4915 char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
4916 volatile int saveherefd;
4917 int quotes = flag & (EXP_FULL | EXP_CASE);
4918 struct jmploc jmploc;
4919 struct jmploc *volatile savehandler;
4920 int ex;
4921
4922#if __GNUC__
4923 /* Avoid longjmp clobbering */
4924 (void) &dest;
4925 (void) &syntax;
4926#endif
4927
4928 in.fd = -1;
4929 in.buf = 0;
4930 in.jp = 0;
4931
4932 INTOFF;
4933 saveifs = ifsfirst;
4934 savelastp = ifslastp;
4935 saveargbackq = argbackq;
4936 saveherefd = herefd;
4937 herefd = -1;
4938 if ((ex = setjmp(jmploc.loc))) {
4939 goto err1;
4940 }
4941 savehandler = handler;
4942 handler = &jmploc;
4943 INTON;
4944 p = grabstackstr(dest);
4945 evalbackcmd(cmd, (struct backcmd *) &in);
4946 ungrabstackstr(p, dest);
4947err1:
4948 INTOFF;
4949 ifsfirst = saveifs;
4950 ifslastp = savelastp;
4951 argbackq = saveargbackq;
4952 herefd = saveherefd;
4953 if (ex) {
4954 goto err2;
4955 }
4956
4957 p = in.buf;
4958 lastc = '\0';
4959 for (;;) {
4960 if (--in.nleft < 0) {
4961 if (in.fd < 0)
4962 break;
Eric Andersen7467c8d2001-07-12 20:26:32 +00004963 i = safe_read(in.fd, buf, sizeof buf);
Eric Andersencb57d552001-06-28 07:25:16 +00004964 TRACE(("expbackq: read returns %d\n", i));
4965 if (i <= 0)
4966 break;
4967 p = buf;
4968 in.nleft = i - 1;
4969 }
4970 lastc = *p++;
4971 if (lastc != '\0') {
4972 if (quotes && syntax[(int)lastc] == CCTL)
4973 STPUTC(CTLESC, dest);
4974 STPUTC(lastc, dest);
4975 }
4976 }
4977
4978 /* Eat all trailing newlines */
4979 for (; dest > stackblock() && dest[-1] == '\n';)
4980 STUNPUTC(dest);
4981
4982err2:
4983 if (in.fd >= 0)
4984 close(in.fd);
4985 if (in.buf)
4986 ckfree(in.buf);
4987 if (in.jp)
4988 exitstatus = waitforjob(in.jp);
4989 handler = savehandler;
4990 if (ex) {
4991 longjmp(handler->loc, 1);
4992 }
4993 if (quoted == 0)
4994 recordregion(startloc, dest - stackblock(), 0);
4995 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4996 (dest - stackblock()) - startloc,
4997 (dest - stackblock()) - startloc,
4998 stackblock() + startloc));
4999 expdest = dest;
5000 INTON;
5001}
5002
Eric Andersencb57d552001-06-28 07:25:16 +00005003static int
5004subevalvar(p, str, strloc, subtype, startloc, varflags, quotes)
5005 char *p;
5006 char *str;
5007 int strloc;
5008 int subtype;
5009 int startloc;
5010 int varflags;
5011 int quotes;
5012{
5013 char *startp;
5014 char *loc = NULL;
5015 char *q;
5016 int c = 0;
5017 int saveherefd = herefd;
5018 struct nodelist *saveargbackq = argbackq;
5019 int amount;
5020
5021 herefd = -1;
5022 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5023 STACKSTRNUL(expdest);
5024 herefd = saveherefd;
5025 argbackq = saveargbackq;
5026 startp = stackblock() + startloc;
5027 if (str == NULL)
5028 str = stackblock() + strloc;
5029
5030 switch (subtype) {
5031 case VSASSIGN:
5032 setvar(str, startp, 0);
5033 amount = startp - expdest;
5034 STADJUST(amount, expdest);
5035 varflags &= ~VSNUL;
5036 if (c != 0)
5037 *loc = c;
5038 return 1;
5039
5040 case VSQUESTION:
5041 if (*p != CTLENDVAR) {
Eric Andersen3102ac42001-07-06 04:26:23 +00005042 out2fmt(snlfmt, startp);
Eric Andersencb57d552001-06-28 07:25:16 +00005043 error((char *)NULL);
5044 }
5045 error("%.*s: parameter %snot set", p - str - 1,
5046 str, (varflags & VSNUL) ? "null or "
5047 : nullstr);
5048 /* NOTREACHED */
5049
5050 case VSTRIMLEFT:
5051 for (loc = startp; loc < str; loc++) {
5052 c = *loc;
5053 *loc = '\0';
5054 if (patmatch2(str, startp, quotes))
5055 goto recordleft;
5056 *loc = c;
5057 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00005058 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00005059 }
5060 return 0;
5061
5062 case VSTRIMLEFTMAX:
5063 for (loc = str - 1; loc >= startp;) {
5064 c = *loc;
5065 *loc = '\0';
5066 if (patmatch2(str, startp, quotes))
5067 goto recordleft;
5068 *loc = c;
5069 loc--;
5070 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
5071 for (q = startp; q < loc; q++)
5072 if (*q == CTLESC)
5073 q++;
5074 if (q > loc)
5075 loc--;
5076 }
5077 }
5078 return 0;
5079
5080 case VSTRIMRIGHT:
Eric Andersen2870d962001-07-02 17:27:21 +00005081 for (loc = str - 1; loc >= startp;) {
Eric Andersencb57d552001-06-28 07:25:16 +00005082 if (patmatch2(str, loc, quotes))
5083 goto recordright;
5084 loc--;
Eric Andersen2870d962001-07-02 17:27:21 +00005085 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
Eric Andersencb57d552001-06-28 07:25:16 +00005086 for (q = startp; q < loc; q++)
5087 if (*q == CTLESC)
5088 q++;
5089 if (q > loc)
5090 loc--;
5091 }
5092 }
5093 return 0;
5094
5095 case VSTRIMRIGHTMAX:
5096 for (loc = startp; loc < str - 1; loc++) {
5097 if (patmatch2(str, loc, quotes))
5098 goto recordright;
5099 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00005100 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00005101 }
5102 return 0;
5103
5104#ifdef DEBUG
5105 default:
5106 abort();
5107#endif
5108 }
5109
5110recordleft:
5111 *loc = c;
5112 amount = ((str - 1) - (loc - startp)) - expdest;
5113 STADJUST(amount, expdest);
5114 while (loc != str - 1)
5115 *startp++ = *loc++;
5116 return 1;
5117
5118recordright:
5119 amount = loc - expdest;
5120 STADJUST(amount, expdest);
5121 STPUTC('\0', expdest);
5122 STADJUST(-1, expdest);
5123 return 1;
5124}
5125
5126
5127/*
Eric Andersencb57d552001-06-28 07:25:16 +00005128 * Test whether a specialized variable is set.
5129 */
5130
5131static int
5132varisset(name, nulok)
5133 char *name;
5134 int nulok;
5135{
5136 if (*name == '!')
5137 return backgndpid != -1;
5138 else if (*name == '@' || *name == '*') {
5139 if (*shellparam.p == NULL)
5140 return 0;
5141
5142 if (nulok) {
5143 char **av;
5144
5145 for (av = shellparam.p; *av; av++)
5146 if (**av != '\0')
5147 return 1;
5148 return 0;
5149 }
5150 } else if (is_digit(*name)) {
5151 char *ap;
5152 int num = atoi(name);
5153
5154 if (num > shellparam.nparam)
5155 return 0;
5156
5157 if (num == 0)
5158 ap = arg0;
5159 else
5160 ap = shellparam.p[num - 1];
5161
5162 if (nulok && (ap == NULL || *ap == '\0'))
5163 return 0;
5164 }
5165 return 1;
5166}
5167
Eric Andersencb57d552001-06-28 07:25:16 +00005168/*
5169 * Put a string on the stack.
5170 */
5171
5172static void
5173strtodest(p, syntax, quotes)
5174 const char *p;
5175 const char *syntax;
5176 int quotes;
5177{
5178 while (*p) {
5179 if (quotes && syntax[(int) *p] == CCTL)
5180 STPUTC(CTLESC, expdest);
5181 STPUTC(*p++, expdest);
5182 }
5183}
5184
Eric Andersencb57d552001-06-28 07:25:16 +00005185/*
5186 * Add the value of a specialized variable to the stack string.
5187 */
5188
5189static void
5190varvalue(name, quoted, flags)
5191 char *name;
5192 int quoted;
5193 int flags;
5194{
5195 int num;
5196 char *p;
5197 int i;
5198 int sep;
5199 int sepq = 0;
5200 char **ap;
5201 char const *syntax;
5202 int allow_split = flags & EXP_FULL;
5203 int quotes = flags & (EXP_FULL | EXP_CASE);
5204
5205 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5206 switch (*name) {
5207 case '$':
5208 num = rootpid;
5209 goto numvar;
5210 case '?':
5211 num = oexitstatus;
5212 goto numvar;
5213 case '#':
5214 num = shellparam.nparam;
5215 goto numvar;
5216 case '!':
5217 num = backgndpid;
5218numvar:
5219 expdest = cvtnum(num, expdest);
5220 break;
5221 case '-':
5222 for (i = 0 ; i < NOPTS ; i++) {
Eric Andersen2870d962001-07-02 17:27:21 +00005223 if (optent_val(i))
5224 STPUTC(optent_letter(optlist[i]), expdest);
Eric Andersencb57d552001-06-28 07:25:16 +00005225 }
5226 break;
5227 case '@':
5228 if (allow_split && quoted) {
5229 sep = 1 << CHAR_BIT;
5230 goto param;
5231 }
5232 /* fall through */
5233 case '*':
5234 sep = ifsset() ? ifsval()[0] : ' ';
5235 if (quotes) {
5236 sepq = syntax[(int) sep] == CCTL;
5237 }
5238param:
5239 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
5240 strtodest(p, syntax, quotes);
5241 if (*ap && sep) {
5242 if (sepq)
5243 STPUTC(CTLESC, expdest);
5244 STPUTC(sep, expdest);
5245 }
5246 }
5247 break;
5248 case '0':
5249 strtodest(arg0, syntax, quotes);
5250 break;
5251 default:
5252 num = atoi(name);
5253 if (num > 0 && num <= shellparam.nparam) {
5254 strtodest(shellparam.p[num - 1], syntax, quotes);
5255 }
5256 break;
5257 }
5258}
5259
5260
Eric Andersencb57d552001-06-28 07:25:16 +00005261/*
5262 * Record the fact that we have to scan this region of the
5263 * string for IFS characters.
5264 */
5265
5266static void
5267recordregion(start, end, nulonly)
5268 int start;
5269 int end;
5270 int nulonly;
5271{
5272 struct ifsregion *ifsp;
5273
5274 if (ifslastp == NULL) {
5275 ifsp = &ifsfirst;
5276 } else {
5277 INTOFF;
5278 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
5279 ifsp->next = NULL;
5280 ifslastp->next = ifsp;
5281 INTON;
5282 }
5283 ifslastp = ifsp;
5284 ifslastp->begoff = start;
5285 ifslastp->endoff = end;
5286 ifslastp->nulonly = nulonly;
5287}
5288
5289
5290
5291/*
5292 * Break the argument string into pieces based upon IFS and add the
5293 * strings to the argument list. The regions of the string to be
5294 * searched for IFS characters have been stored by recordregion.
5295 */
5296static void
5297ifsbreakup(string, arglist)
5298 char *string;
5299 struct arglist *arglist;
5300 {
5301 struct ifsregion *ifsp;
5302 struct strlist *sp;
5303 char *start;
5304 char *p;
5305 char *q;
5306 const char *ifs, *realifs;
5307 int ifsspc;
5308 int nulonly;
5309
5310
5311 start = string;
5312 ifsspc = 0;
5313 nulonly = 0;
5314 realifs = ifsset() ? ifsval() : defifs;
5315 if (ifslastp != NULL) {
5316 ifsp = &ifsfirst;
5317 do {
5318 p = string + ifsp->begoff;
5319 nulonly = ifsp->nulonly;
5320 ifs = nulonly ? nullstr : realifs;
5321 ifsspc = 0;
5322 while (p < string + ifsp->endoff) {
5323 q = p;
5324 if (*p == CTLESC)
5325 p++;
5326 if (strchr(ifs, *p)) {
5327 if (!nulonly)
5328 ifsspc = (strchr(defifs, *p) != NULL);
5329 /* Ignore IFS whitespace at start */
5330 if (q == start && ifsspc) {
5331 p++;
5332 start = p;
5333 continue;
5334 }
5335 *q = '\0';
5336 sp = (struct strlist *)stalloc(sizeof *sp);
5337 sp->text = start;
5338 *arglist->lastp = sp;
5339 arglist->lastp = &sp->next;
5340 p++;
5341 if (!nulonly) {
5342 for (;;) {
5343 if (p >= string + ifsp->endoff) {
5344 break;
5345 }
5346 q = p;
5347 if (*p == CTLESC)
5348 p++;
5349 if (strchr(ifs, *p) == NULL ) {
5350 p = q;
5351 break;
5352 } else if (strchr(defifs, *p) == NULL) {
5353 if (ifsspc) {
5354 p++;
5355 ifsspc = 0;
5356 } else {
5357 p = q;
5358 break;
5359 }
5360 } else
5361 p++;
5362 }
5363 }
5364 start = p;
5365 } else
5366 p++;
5367 }
5368 } while ((ifsp = ifsp->next) != NULL);
5369 if (!(*start || (!ifsspc && start > string && nulonly))) {
5370 return;
5371 }
5372 }
5373
5374 sp = (struct strlist *)stalloc(sizeof *sp);
5375 sp->text = start;
5376 *arglist->lastp = sp;
5377 arglist->lastp = &sp->next;
5378}
5379
5380static void
5381ifsfree()
5382{
5383 while (ifsfirst.next != NULL) {
5384 struct ifsregion *ifsp;
5385 INTOFF;
5386 ifsp = ifsfirst.next->next;
5387 ckfree(ifsfirst.next);
5388 ifsfirst.next = ifsp;
5389 INTON;
5390 }
5391 ifslastp = NULL;
5392 ifsfirst.next = NULL;
5393}
5394
Eric Andersen2870d962001-07-02 17:27:21 +00005395/*
5396 * Add a file name to the list.
5397 */
Eric Andersencb57d552001-06-28 07:25:16 +00005398
Eric Andersen2870d962001-07-02 17:27:21 +00005399static void
5400addfname(const char *name)
5401{
5402 char *p;
5403 struct strlist *sp;
5404
5405 p = sstrdup(name);
5406 sp = (struct strlist *)stalloc(sizeof *sp);
5407 sp->text = p;
5408 *exparg.lastp = sp;
5409 exparg.lastp = &sp->next;
5410}
Eric Andersencb57d552001-06-28 07:25:16 +00005411
5412/*
5413 * Expand shell metacharacters. At this point, the only control characters
5414 * should be escapes. The results are stored in the list exparg.
5415 */
5416
Eric Andersen62483552001-07-10 06:09:16 +00005417#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00005418static void
5419expandmeta(str, flag)
5420 struct strlist *str;
5421 int flag;
5422{
5423 const char *p;
5424 glob_t pglob;
5425 /* TODO - EXP_REDIR */
5426
5427 while (str) {
5428 if (fflag)
5429 goto nometa;
5430 p = preglob(str->text);
5431 INTOFF;
5432 switch (glob(p, GLOB_NOMAGIC, 0, &pglob)) {
5433 case 0:
5434 if (!(pglob.gl_flags & GLOB_MAGCHAR))
5435 goto nometa2;
5436 addglob(&pglob);
5437 globfree(&pglob);
5438 INTON;
5439 break;
5440 case GLOB_NOMATCH:
5441nometa2:
5442 globfree(&pglob);
5443 INTON;
5444nometa:
5445 *exparg.lastp = str;
5446 rmescapes(str->text);
5447 exparg.lastp = &str->next;
5448 break;
Eric Andersen2870d962001-07-02 17:27:21 +00005449 default: /* GLOB_NOSPACE */
Eric Andersencb57d552001-06-28 07:25:16 +00005450 error("Out of space");
5451 }
5452 str = str->next;
5453 }
5454}
5455
5456
5457/*
5458 * Add the result of glob(3) to the list.
5459 */
5460
5461static void
5462addglob(pglob)
5463 const glob_t *pglob;
5464{
5465 char **p = pglob->gl_pathv;
5466
5467 do {
5468 addfname(*p);
5469 } while (*++p);
5470}
5471
5472
Eric Andersen2870d962001-07-02 17:27:21 +00005473#else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005474static char *expdir;
5475
5476
5477static void
5478expandmeta(str, flag)
5479 struct strlist *str;
5480 int flag;
5481{
5482 char *p;
5483 struct strlist **savelastp;
5484 struct strlist *sp;
5485 char c;
5486 /* TODO - EXP_REDIR */
5487
5488 while (str) {
5489 if (fflag)
5490 goto nometa;
5491 p = str->text;
Eric Andersen2870d962001-07-02 17:27:21 +00005492 for (;;) { /* fast check for meta chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005493 if ((c = *p++) == '\0')
5494 goto nometa;
5495 if (c == '*' || c == '?' || c == '[' || c == '!')
5496 break;
5497 }
5498 savelastp = exparg.lastp;
5499 INTOFF;
5500 if (expdir == NULL) {
5501 int i = strlen(str->text);
5502 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5503 }
5504
5505 expmeta(expdir, str->text);
5506 ckfree(expdir);
5507 expdir = NULL;
5508 INTON;
5509 if (exparg.lastp == savelastp) {
5510 /*
5511 * no matches
5512 */
5513nometa:
5514 *exparg.lastp = str;
5515 rmescapes(str->text);
5516 exparg.lastp = &str->next;
5517 } else {
5518 *exparg.lastp = NULL;
5519 *savelastp = sp = expsort(*savelastp);
5520 while (sp->next != NULL)
5521 sp = sp->next;
5522 exparg.lastp = &sp->next;
5523 }
5524 str = str->next;
5525 }
5526}
5527
5528
5529/*
5530 * Do metacharacter (i.e. *, ?, [...]) expansion.
5531 */
5532
5533static void
5534expmeta(enddir, name)
5535 char *enddir;
5536 char *name;
5537 {
5538 char *p;
5539 const char *cp;
5540 char *q;
5541 char *start;
5542 char *endname;
5543 int metaflag;
5544 struct stat statb;
5545 DIR *dirp;
5546 struct dirent *dp;
5547 int atend;
5548 int matchdot;
5549
5550 metaflag = 0;
5551 start = name;
5552 for (p = name ; ; p++) {
5553 if (*p == '*' || *p == '?')
5554 metaflag = 1;
5555 else if (*p == '[') {
5556 q = p + 1;
5557 if (*q == '!')
5558 q++;
5559 for (;;) {
5560 while (*q == CTLQUOTEMARK)
5561 q++;
5562 if (*q == CTLESC)
5563 q++;
5564 if (*q == '/' || *q == '\0')
5565 break;
5566 if (*++q == ']') {
5567 metaflag = 1;
5568 break;
5569 }
5570 }
Eric Andersen2870d962001-07-02 17:27:21 +00005571 } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) {
Eric Andersencb57d552001-06-28 07:25:16 +00005572 metaflag = 1;
5573 } else if (*p == '\0')
5574 break;
5575 else if (*p == CTLQUOTEMARK)
5576 continue;
5577 else if (*p == CTLESC)
5578 p++;
5579 if (*p == '/') {
5580 if (metaflag)
5581 break;
5582 start = p + 1;
5583 }
5584 }
Eric Andersen2870d962001-07-02 17:27:21 +00005585 if (metaflag == 0) { /* we've reached the end of the file name */
Eric Andersencb57d552001-06-28 07:25:16 +00005586 if (enddir != expdir)
5587 metaflag++;
5588 for (p = name ; ; p++) {
5589 if (*p == CTLQUOTEMARK)
5590 continue;
5591 if (*p == CTLESC)
5592 p++;
5593 *enddir++ = *p;
5594 if (*p == '\0')
5595 break;
5596 }
5597 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5598 addfname(expdir);
5599 return;
5600 }
5601 endname = p;
5602 if (start != name) {
5603 p = name;
5604 while (p < start) {
5605 while (*p == CTLQUOTEMARK)
5606 p++;
5607 if (*p == CTLESC)
5608 p++;
5609 *enddir++ = *p++;
5610 }
5611 }
5612 if (enddir == expdir) {
5613 cp = ".";
5614 } else if (enddir == expdir + 1 && *expdir == '/') {
5615 cp = "/";
5616 } else {
5617 cp = expdir;
5618 enddir[-1] = '\0';
5619 }
5620 if ((dirp = opendir(cp)) == NULL)
5621 return;
5622 if (enddir != expdir)
5623 enddir[-1] = '/';
5624 if (*endname == 0) {
5625 atend = 1;
5626 } else {
5627 atend = 0;
5628 *endname++ = '\0';
5629 }
5630 matchdot = 0;
5631 p = start;
5632 while (*p == CTLQUOTEMARK)
5633 p++;
5634 if (*p == CTLESC)
5635 p++;
5636 if (*p == '.')
5637 matchdot++;
5638 while (! int_pending() && (dp = readdir(dirp)) != NULL) {
5639 if (dp->d_name[0] == '.' && ! matchdot)
5640 continue;
5641 if (patmatch(start, dp->d_name, 0)) {
5642 if (atend) {
Eric Andersen2870d962001-07-02 17:27:21 +00005643 strcpy(enddir, dp->d_name);
Eric Andersencb57d552001-06-28 07:25:16 +00005644 addfname(expdir);
5645 } else {
5646 for (p = enddir, cp = dp->d_name;
5647 (*p++ = *cp++) != '\0';)
5648 continue;
5649 p[-1] = '/';
5650 expmeta(p, endname);
5651 }
5652 }
5653 }
5654 closedir(dirp);
5655 if (! atend)
5656 endname[-1] = '/';
5657}
Eric Andersen2870d962001-07-02 17:27:21 +00005658#endif /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005659
5660
Eric Andersencb57d552001-06-28 07:25:16 +00005661
Eric Andersen62483552001-07-10 06:09:16 +00005662#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersencb57d552001-06-28 07:25:16 +00005663/*
5664 * Sort the results of file name expansion. It calculates the number of
5665 * strings to sort and then calls msort (short for merge sort) to do the
5666 * work.
5667 */
5668
5669static struct strlist *
5670expsort(str)
5671 struct strlist *str;
5672 {
5673 int len;
5674 struct strlist *sp;
5675
5676 len = 0;
5677 for (sp = str ; sp ; sp = sp->next)
5678 len++;
5679 return msort(str, len);
5680}
5681
5682
5683static struct strlist *
5684msort(list, len)
5685 struct strlist *list;
5686 int len;
5687{
5688 struct strlist *p, *q = NULL;
5689 struct strlist **lpp;
5690 int half;
5691 int n;
5692
5693 if (len <= 1)
5694 return list;
5695 half = len >> 1;
5696 p = list;
5697 for (n = half ; --n >= 0 ; ) {
5698 q = p;
5699 p = p->next;
5700 }
Eric Andersen2870d962001-07-02 17:27:21 +00005701 q->next = NULL; /* terminate first half of list */
5702 q = msort(list, half); /* sort first half of list */
5703 p = msort(p, len - half); /* sort second half */
Eric Andersencb57d552001-06-28 07:25:16 +00005704 lpp = &list;
5705 for (;;) {
5706 if (strcmp(p->text, q->text) < 0) {
5707 *lpp = p;
5708 lpp = &p->next;
5709 if ((p = *lpp) == NULL) {
5710 *lpp = q;
5711 break;
5712 }
5713 } else {
5714 *lpp = q;
5715 lpp = &q->next;
5716 if ((q = *lpp) == NULL) {
5717 *lpp = p;
5718 break;
5719 }
5720 }
5721 }
5722 return list;
5723}
5724#endif
5725
5726
5727
5728/*
5729 * Returns true if the pattern matches the string.
5730 */
5731
Eric Andersen62483552001-07-10 06:09:16 +00005732#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00005733/* squoted: string might have quote chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005734static int
Eric Andersen2870d962001-07-02 17:27:21 +00005735patmatch(char *pattern, char *string, int squoted)
5736{
Eric Andersencb57d552001-06-28 07:25:16 +00005737 const char *p;
5738 char *q;
5739
5740 p = preglob(pattern);
5741 q = squoted ? _rmescapes(string, RMESCAPE_ALLOC) : string;
5742
5743 return !fnmatch(p, q, 0);
5744}
5745
5746
5747static int
Eric Andersen2870d962001-07-02 17:27:21 +00005748patmatch2(char *pattern, char *string, int squoted)
5749{
Eric Andersencb57d552001-06-28 07:25:16 +00005750 char *p;
5751 int res;
5752
5753 sstrnleft--;
5754 p = grabstackstr(expdest);
5755 res = patmatch(pattern, string, squoted);
5756 ungrabstackstr(p, expdest);
5757 return res;
5758}
5759#else
5760static int
Eric Andersen2870d962001-07-02 17:27:21 +00005761patmatch(char *pattern, char *string, int squoted) {
5762 return pmatch(pattern, string, squoted);
Eric Andersencb57d552001-06-28 07:25:16 +00005763}
5764
5765
5766static int
Eric Andersen2870d962001-07-02 17:27:21 +00005767pmatch(char *pattern, char *string, int squoted)
5768{
Eric Andersencb57d552001-06-28 07:25:16 +00005769 char *p, *q;
5770 char c;
5771
5772 p = pattern;
5773 q = string;
5774 for (;;) {
5775 switch (c = *p++) {
5776 case '\0':
5777 goto breakloop;
5778 case CTLESC:
5779 if (squoted && *q == CTLESC)
5780 q++;
5781 if (*q++ != *p++)
5782 return 0;
5783 break;
5784 case CTLQUOTEMARK:
5785 continue;
5786 case '?':
5787 if (squoted && *q == CTLESC)
5788 q++;
5789 if (*q++ == '\0')
5790 return 0;
5791 break;
5792 case '*':
5793 c = *p;
5794 while (c == CTLQUOTEMARK || c == '*')
5795 c = *++p;
5796 if (c != CTLESC && c != CTLQUOTEMARK &&
5797 c != '?' && c != '*' && c != '[') {
5798 while (*q != c) {
5799 if (squoted && *q == CTLESC &&
5800 q[1] == c)
5801 break;
5802 if (*q == '\0')
5803 return 0;
5804 if (squoted && *q == CTLESC)
5805 q++;
5806 q++;
5807 }
5808 }
5809 do {
5810 if (pmatch(p, q, squoted))
5811 return 1;
5812 if (squoted && *q == CTLESC)
5813 q++;
5814 } while (*q++ != '\0');
5815 return 0;
5816 case '[': {
5817 char *endp;
5818 int invert, found;
5819 char chr;
5820
5821 endp = p;
5822 if (*endp == '!')
5823 endp++;
5824 for (;;) {
5825 while (*endp == CTLQUOTEMARK)
5826 endp++;
5827 if (*endp == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00005828 goto dft; /* no matching ] */
Eric Andersencb57d552001-06-28 07:25:16 +00005829 if (*endp == CTLESC)
5830 endp++;
5831 if (*++endp == ']')
5832 break;
5833 }
5834 invert = 0;
5835 if (*p == '!') {
5836 invert++;
5837 p++;
5838 }
5839 found = 0;
5840 chr = *q++;
5841 if (squoted && chr == CTLESC)
5842 chr = *q++;
5843 if (chr == '\0')
5844 return 0;
5845 c = *p++;
5846 do {
5847 if (c == CTLQUOTEMARK)
5848 continue;
5849 if (c == CTLESC)
5850 c = *p++;
5851 if (*p == '-' && p[1] != ']') {
5852 p++;
5853 while (*p == CTLQUOTEMARK)
5854 p++;
5855 if (*p == CTLESC)
5856 p++;
5857 if (chr >= c && chr <= *p)
5858 found = 1;
5859 p++;
5860 } else {
5861 if (chr == c)
5862 found = 1;
5863 }
5864 } while ((c = *p++) != ']');
5865 if (found == invert)
5866 return 0;
5867 break;
5868 }
Eric Andersen2870d962001-07-02 17:27:21 +00005869dft: default:
Eric Andersencb57d552001-06-28 07:25:16 +00005870 if (squoted && *q == CTLESC)
5871 q++;
5872 if (*q++ != c)
5873 return 0;
5874 break;
5875 }
5876 }
5877breakloop:
5878 if (*q != '\0')
5879 return 0;
5880 return 1;
5881}
5882#endif
5883
5884
5885
5886/*
5887 * Remove any CTLESC characters from a string.
5888 */
5889
Eric Andersen62483552001-07-10 06:09:16 +00005890#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00005891static char *
Eric Andersen2870d962001-07-02 17:27:21 +00005892_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005893{
5894 char *p, *q, *r;
5895 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5896
5897 p = strpbrk(str, qchars);
5898 if (!p) {
5899 return str;
5900 }
5901 q = p;
5902 r = str;
5903 if (flag & RMESCAPE_ALLOC) {
5904 size_t len = p - str;
5905 q = r = stalloc(strlen(p) + len + 1);
5906 if (len > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00005907 memcpy(q, str, len);
5908 q += len;
Eric Andersencb57d552001-06-28 07:25:16 +00005909 }
5910 }
5911 while (*p) {
5912 if (*p == CTLQUOTEMARK) {
5913 p++;
5914 continue;
5915 }
5916 if (*p == CTLESC) {
5917 p++;
5918 if (flag & RMESCAPE_GLOB && *p != '/') {
5919 *q++ = '\\';
5920 }
5921 }
5922 *q++ = *p++;
5923 }
5924 *q = '\0';
5925 return r;
5926}
5927#else
5928static void
5929rmescapes(str)
5930 char *str;
5931{
5932 char *p, *q;
5933
5934 p = str;
5935 while (*p != CTLESC && *p != CTLQUOTEMARK) {
5936 if (*p++ == '\0')
5937 return;
5938 }
5939 q = p;
5940 while (*p) {
5941 if (*p == CTLQUOTEMARK) {
5942 p++;
5943 continue;
5944 }
5945 if (*p == CTLESC)
5946 p++;
5947 *q++ = *p++;
5948 }
5949 *q = '\0';
5950}
5951#endif
5952
5953
5954
5955/*
5956 * See if a pattern matches in a case statement.
5957 */
5958
5959static int
Eric Andersen2870d962001-07-02 17:27:21 +00005960casematch(union node *pattern, const char *val)
5961{
Eric Andersencb57d552001-06-28 07:25:16 +00005962 struct stackmark smark;
5963 int result;
5964 char *p;
5965
5966 setstackmark(&smark);
5967 argbackq = pattern->narg.backquote;
5968 STARTSTACKSTR(expdest);
5969 ifslastp = NULL;
5970 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5971 STPUTC('\0', expdest);
5972 p = grabstackstr(expdest);
Eric Andersen2870d962001-07-02 17:27:21 +00005973 result = patmatch(p, (char *)val, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00005974 popstackmark(&smark);
5975 return result;
5976}
5977
5978/*
5979 * Our own itoa().
5980 */
5981
5982static char *
5983cvtnum(num, buf)
5984 int num;
5985 char *buf;
5986 {
5987 int len;
5988
5989 CHECKSTRSPACE(32, buf);
5990 len = sprintf(buf, "%d", num);
5991 STADJUST(len, buf);
5992 return buf;
5993}
Eric Andersencb57d552001-06-28 07:25:16 +00005994/*
5995 * Editline and history functions (and glue).
5996 */
5997static int histcmd(argc, argv)
5998 int argc;
5999 char **argv;
6000{
6001 error("not compiled with history support");
6002 /* NOTREACHED */
6003}
6004
6005
Eric Andersencb57d552001-06-28 07:25:16 +00006006struct redirtab {
6007 struct redirtab *next;
Russ Dill4db35642001-07-26 05:58:40 +00006008 short renamed[10]; /* Current ash support only 0-9 descriptors */
6009 /* char renamed[10]; */ /* char on arm (and others) can't be negative */
Eric Andersencb57d552001-06-28 07:25:16 +00006010};
6011
Eric Andersen2870d962001-07-02 17:27:21 +00006012static struct redirtab *redirlist;
Eric Andersencb57d552001-06-28 07:25:16 +00006013
6014extern char **environ;
6015
6016
6017
6018/*
6019 * Initialization code.
6020 */
6021
6022static void
Eric Andersen2870d962001-07-02 17:27:21 +00006023init(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00006024
6025 /* from cd.c: */
6026 {
6027 setpwd(0, 0);
6028 }
6029
6030 /* from input.c: */
6031 {
6032 basepf.nextc = basepf.buf = basebuf;
6033 }
6034
Eric Andersencb57d552001-06-28 07:25:16 +00006035 /* from var.c: */
6036 {
6037 char **envp;
6038 char ppid[32];
6039
6040 initvar();
6041 for (envp = environ ; *envp ; envp++) {
6042 if (strchr(*envp, '=')) {
6043 setvareq(*envp, VEXPORT|VTEXTFIXED);
6044 }
6045 }
6046
Eric Andersen3102ac42001-07-06 04:26:23 +00006047 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
Eric Andersencb57d552001-06-28 07:25:16 +00006048 setvar("PPID", ppid, 0);
6049 }
6050}
6051
6052
6053
6054/*
6055 * This routine is called when an error or an interrupt occurs in an
6056 * interactive shell and control is returned to the main command loop.
6057 */
6058
Eric Andersen2870d962001-07-02 17:27:21 +00006059/* 1 == check for aliases, 2 == also check for assignments */
Eric Andersen7467c8d2001-07-12 20:26:32 +00006060static int checkalias; /* also used in no alias mode for check assignments */
Eric Andersen2870d962001-07-02 17:27:21 +00006061
Eric Andersencb57d552001-06-28 07:25:16 +00006062static void
Eric Andersen2870d962001-07-02 17:27:21 +00006063reset(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00006064
6065 /* from eval.c: */
6066 {
6067 evalskip = 0;
6068 loopnest = 0;
6069 funcnest = 0;
6070 }
6071
6072 /* from input.c: */
6073 {
6074 if (exception != EXSHELLPROC)
Eric Andersen2870d962001-07-02 17:27:21 +00006075 parselleft = parsenleft = 0; /* clear input buffer */
Eric Andersencb57d552001-06-28 07:25:16 +00006076 popallfiles();
6077 }
6078
6079 /* from parser.c: */
6080 {
6081 tokpushback = 0;
6082 checkkwd = 0;
6083 checkalias = 0;
6084 }
6085
6086 /* from redir.c: */
6087 {
6088 while (redirlist)
6089 popredir();
6090 }
6091
Eric Andersencb57d552001-06-28 07:25:16 +00006092}
6093
6094
6095
6096/*
Eric Andersencb57d552001-06-28 07:25:16 +00006097 * This file implements the input routines used by the parser.
6098 */
6099
6100#ifdef BB_FEATURE_COMMAND_EDITING
Eric Andersencb57d552001-06-28 07:25:16 +00006101static const char * cmdedit_prompt;
6102static inline void putprompt(const char *s) {
6103 cmdedit_prompt = s;
6104}
6105#else
6106static inline void putprompt(const char *s) {
6107 out2str(s);
6108}
6109#endif
6110
Eric Andersen2870d962001-07-02 17:27:21 +00006111#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
Eric Andersencb57d552001-06-28 07:25:16 +00006112
Eric Andersencb57d552001-06-28 07:25:16 +00006113
Eric Andersencb57d552001-06-28 07:25:16 +00006114
Eric Andersen2870d962001-07-02 17:27:21 +00006115/*
6116 * Same as pgetc(), but ignores PEOA.
6117 */
Eric Andersencb57d552001-06-28 07:25:16 +00006118
Eric Andersen2870d962001-07-02 17:27:21 +00006119#ifdef ASH_ALIAS
6120static int
6121pgetc2()
6122{
6123 int c;
6124 do {
6125 c = pgetc_macro();
6126 } while (c == PEOA);
6127 return c;
Eric Andersencb57d552001-06-28 07:25:16 +00006128}
Eric Andersen2870d962001-07-02 17:27:21 +00006129#else
6130static inline int pgetc2() { return pgetc_macro(); }
Eric Andersencb57d552001-06-28 07:25:16 +00006131#endif
6132
Eric Andersencb57d552001-06-28 07:25:16 +00006133/*
6134 * Read a line from the script.
6135 */
6136
Eric Andersen62483552001-07-10 06:09:16 +00006137static inline char *
Eric Andersen2870d962001-07-02 17:27:21 +00006138pfgets(char *line, int len)
Eric Andersencb57d552001-06-28 07:25:16 +00006139{
6140 char *p = line;
6141 int nleft = len;
6142 int c;
6143
6144 while (--nleft > 0) {
6145 c = pgetc2();
6146 if (c == PEOF) {
6147 if (p == line)
6148 return NULL;
6149 break;
6150 }
6151 *p++ = c;
6152 if (c == '\n')
6153 break;
6154 }
6155 *p = '\0';
6156 return line;
6157}
6158
Eric Andersen62483552001-07-10 06:09:16 +00006159static inline int
Eric Andersen2870d962001-07-02 17:27:21 +00006160preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006161{
6162 int nr;
6163 char *buf = parsefile->buf;
6164 parsenextc = buf;
6165
6166retry:
6167#ifdef BB_FEATURE_COMMAND_EDITING
6168 {
Eric Andersenbc4c0302001-07-17 01:14:06 +00006169 if (parsefile->fd)
Eric Andersen7467c8d2001-07-12 20:26:32 +00006170 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersen2870d962001-07-02 17:27:21 +00006171 else {
Eric Andersen044228d2001-07-17 01:12:36 +00006172 nr = cmdedit_read_input((char*)cmdedit_prompt, buf);
Eric Andersencb57d552001-06-28 07:25:16 +00006173 }
6174 }
6175#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00006176 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006177#endif
6178
6179 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006180 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6181 int flags = fcntl(0, F_GETFL, 0);
6182 if (flags >= 0 && flags & O_NONBLOCK) {
6183 flags &=~ O_NONBLOCK;
6184 if (fcntl(0, F_SETFL, flags) >= 0) {
6185 out2str("sh: turning off NDELAY mode\n");
6186 goto retry;
6187 }
6188 }
6189 }
6190 }
6191 return nr;
6192}
6193
Eric Andersen2870d962001-07-02 17:27:21 +00006194static void
6195popstring(void)
6196{
6197 struct strpush *sp = parsefile->strpush;
6198
6199 INTOFF;
6200#ifdef ASH_ALIAS
6201 if (sp->ap) {
6202 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6203 if (!checkalias) {
6204 checkalias = 1;
6205 }
6206 }
6207 if (sp->string != sp->ap->val) {
6208 ckfree(sp->string);
6209 }
6210
6211 sp->ap->flag &= ~ALIASINUSE;
6212 if (sp->ap->flag & ALIASDEAD) {
6213 unalias(sp->ap->name);
6214 }
6215 }
6216#endif
6217 parsenextc = sp->prevstring;
6218 parsenleft = sp->prevnleft;
6219/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6220 parsefile->strpush = sp->prev;
6221 if (sp != &(parsefile->basestrpush))
6222 ckfree(sp);
6223 INTON;
6224}
6225
6226
Eric Andersencb57d552001-06-28 07:25:16 +00006227/*
6228 * Refill the input buffer and return the next input character:
6229 *
6230 * 1) If a string was pushed back on the input, pop it;
6231 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6232 * from a string so we can't refill the buffer, return EOF.
6233 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6234 * 4) Process input up to the next newline, deleting nul characters.
6235 */
6236
6237static int
Eric Andersen2870d962001-07-02 17:27:21 +00006238preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006239{
6240 char *p, *q;
6241 int more;
6242 char savec;
6243
6244 while (parsefile->strpush) {
Eric Andersen2870d962001-07-02 17:27:21 +00006245#ifdef ASH_ALIAS
6246 if (parsenleft == -1 && parsefile->strpush->ap &&
6247 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00006248 return PEOA;
6249 }
Eric Andersen2870d962001-07-02 17:27:21 +00006250#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006251 popstring();
6252 if (--parsenleft >= 0)
6253 return (*parsenextc++);
6254 }
6255 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6256 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00006257 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00006258
6259again:
6260 if (parselleft <= 0) {
6261 if ((parselleft = preadfd()) <= 0) {
6262 parselleft = parsenleft = EOF_NLEFT;
6263 return PEOF;
6264 }
6265 }
6266
6267 q = p = parsenextc;
6268
6269 /* delete nul characters */
6270 for (more = 1; more;) {
6271 switch (*p) {
6272 case '\0':
Eric Andersen2870d962001-07-02 17:27:21 +00006273 p++; /* Skip nul */
Eric Andersencb57d552001-06-28 07:25:16 +00006274 goto check;
6275
6276
6277 case '\n':
6278 parsenleft = q - parsenextc;
6279 more = 0; /* Stop processing here */
6280 break;
6281 }
6282
6283 *q++ = *p++;
6284check:
6285 if (--parselleft <= 0 && more) {
6286 parsenleft = q - parsenextc - 1;
6287 if (parsenleft < 0)
6288 goto again;
6289 more = 0;
6290 }
6291 }
6292
6293 savec = *q;
6294 *q = '\0';
6295
6296 if (vflag) {
6297 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00006298 }
6299
6300 *q = savec;
6301
6302 return *parsenextc++;
6303}
6304
Eric Andersencb57d552001-06-28 07:25:16 +00006305
6306/*
6307 * Push a string back onto the input at this current parsefile level.
6308 * We handle aliases this way.
6309 */
6310static void
Eric Andersen2870d962001-07-02 17:27:21 +00006311pushstring(char *s, int len, void *ap)
6312{
Eric Andersencb57d552001-06-28 07:25:16 +00006313 struct strpush *sp;
6314
6315 INTOFF;
6316/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6317 if (parsefile->strpush) {
6318 sp = ckmalloc(sizeof (struct strpush));
6319 sp->prev = parsefile->strpush;
6320 parsefile->strpush = sp;
6321 } else
6322 sp = parsefile->strpush = &(parsefile->basestrpush);
6323 sp->prevstring = parsenextc;
6324 sp->prevnleft = parsenleft;
Eric Andersen2870d962001-07-02 17:27:21 +00006325#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00006326 sp->ap = (struct alias *)ap;
6327 if (ap) {
6328 ((struct alias *)ap)->flag |= ALIASINUSE;
6329 sp->string = s;
6330 }
Eric Andersen2870d962001-07-02 17:27:21 +00006331#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006332 parsenextc = s;
6333 parsenleft = len;
6334 INTON;
6335}
6336
Eric Andersencb57d552001-06-28 07:25:16 +00006337
Eric Andersencb57d552001-06-28 07:25:16 +00006338/*
6339 * Like setinputfile, but takes input from a string.
6340 */
6341
6342static void
Eric Andersen62483552001-07-10 06:09:16 +00006343setinputstring(char *string)
6344{
Eric Andersencb57d552001-06-28 07:25:16 +00006345 INTOFF;
6346 pushfile();
6347 parsenextc = string;
6348 parsenleft = strlen(string);
6349 parsefile->buf = NULL;
6350 plinno = 1;
6351 INTON;
6352}
6353
6354
6355
6356/*
6357 * To handle the "." command, a stack of input files is used. Pushfile
6358 * adds a new entry to the stack and popfile restores the previous level.
6359 */
6360
6361static void
Eric Andersen2870d962001-07-02 17:27:21 +00006362pushfile(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00006363 struct parsefile *pf;
6364
6365 parsefile->nleft = parsenleft;
6366 parsefile->lleft = parselleft;
6367 parsefile->nextc = parsenextc;
6368 parsefile->linno = plinno;
6369 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6370 pf->prev = parsefile;
6371 pf->fd = -1;
6372 pf->strpush = NULL;
6373 pf->basestrpush.prev = NULL;
6374 parsefile = pf;
6375}
6376
Eric Andersen2870d962001-07-02 17:27:21 +00006377#ifdef JOBS
6378static void restartjob (struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00006379#endif
Eric Andersen2870d962001-07-02 17:27:21 +00006380static void freejob (struct job *);
6381static struct job *getjob (const char *);
6382static int dowait (int, struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00006383static void waitonint(int);
6384
6385
Eric Andersen2870d962001-07-02 17:27:21 +00006386/*
6387 * We keep track of whether or not fd0 has been redirected. This is for
6388 * background commands, where we want to redirect fd0 to /dev/null only
6389 * if it hasn't already been redirected.
6390*/
6391static int fd0_redirected = 0;
6392
6393/* Return true if fd 0 has already been redirected at least once. */
6394static inline int
6395fd0_redirected_p () {
6396 return fd0_redirected != 0;
6397}
6398
Eric Andersen62483552001-07-10 06:09:16 +00006399static void dupredirect (const union node *, int, int fd1dup);
Eric Andersen2870d962001-07-02 17:27:21 +00006400
6401#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006402/*
6403 * Turn job control on and off.
6404 *
6405 * Note: This code assumes that the third arg to ioctl is a character
6406 * pointer, which is true on Berkeley systems but not System V. Since
6407 * System V doesn't have job control yet, this isn't a problem now.
6408 */
6409
Eric Andersen2870d962001-07-02 17:27:21 +00006410
Eric Andersencb57d552001-06-28 07:25:16 +00006411
6412static void setjobctl(int enable)
6413{
6414#ifdef OLD_TTY_DRIVER
6415 int ldisc;
6416#endif
6417
6418 if (enable == jobctl || rootshell == 0)
6419 return;
6420 if (enable) {
6421 do { /* while we are in the background */
6422#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006423 if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006424#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006425 initialpgrp = tcgetpgrp(2);
Eric Andersencb57d552001-06-28 07:25:16 +00006426 if (initialpgrp < 0) {
6427#endif
Eric Andersen8c145dc2001-07-10 16:57:09 +00006428 out2str("sh: can't access tty; job control turned off\n");
Eric Andersencb57d552001-06-28 07:25:16 +00006429 mflag = 0;
6430 return;
6431 }
6432 if (initialpgrp == -1)
6433 initialpgrp = getpgrp();
6434 else if (initialpgrp != getpgrp()) {
6435 killpg(initialpgrp, SIGTTIN);
6436 continue;
6437 }
6438 } while (0);
6439#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006440 if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
Eric Andersen8c145dc2001-07-10 16:57:09 +00006441 out2str("sh: need new tty driver to run job control; job control turned off\n");
Eric Andersencb57d552001-06-28 07:25:16 +00006442 mflag = 0;
6443 return;
6444 }
6445#endif
6446 setsignal(SIGTSTP);
6447 setsignal(SIGTTOU);
6448 setsignal(SIGTTIN);
6449 setpgid(0, rootpid);
6450#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006451 ioctl(2, TIOCSPGRP, (char *)&rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00006452#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006453 tcsetpgrp(2, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00006454#endif
Eric Andersen8c145dc2001-07-10 16:57:09 +00006455 } else { /* turning job control off */
Eric Andersencb57d552001-06-28 07:25:16 +00006456 setpgid(0, initialpgrp);
6457#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006458 ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006459#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006460 tcsetpgrp(2, initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006461#endif
6462 setsignal(SIGTSTP);
6463 setsignal(SIGTTOU);
6464 setsignal(SIGTTIN);
6465 }
6466 jobctl = enable;
6467}
6468#endif
6469
6470
Eric Andersencb57d552001-06-28 07:25:16 +00006471/* A translation list so we can be polite to our users. */
6472static char *signal_names[NSIG + 2] = {
6473 "EXIT",
6474 "SIGHUP",
6475 "SIGINT",
6476 "SIGQUIT",
6477 "SIGILL",
6478 "SIGTRAP",
6479 "SIGABRT",
6480 "SIGBUS",
6481 "SIGFPE",
6482 "SIGKILL",
6483 "SIGUSR1",
6484 "SIGSEGV",
6485 "SIGUSR2",
6486 "SIGPIPE",
6487 "SIGALRM",
6488 "SIGTERM",
6489 "SIGJUNK(16)",
6490 "SIGCHLD",
6491 "SIGCONT",
6492 "SIGSTOP",
6493 "SIGTSTP",
6494 "SIGTTIN",
6495 "SIGTTOU",
6496 "SIGURG",
6497 "SIGXCPU",
6498 "SIGXFSZ",
6499 "SIGVTALRM",
6500 "SIGPROF",
6501 "SIGWINCH",
6502 "SIGIO",
6503 "SIGPWR",
6504 "SIGSYS",
Eric Andersen62483552001-07-10 06:09:16 +00006505#ifdef SIGRTMIN
Eric Andersencb57d552001-06-28 07:25:16 +00006506 "SIGRTMIN",
6507 "SIGRTMIN+1",
6508 "SIGRTMIN+2",
6509 "SIGRTMIN+3",
6510 "SIGRTMIN+4",
6511 "SIGRTMIN+5",
6512 "SIGRTMIN+6",
6513 "SIGRTMIN+7",
6514 "SIGRTMIN+8",
6515 "SIGRTMIN+9",
6516 "SIGRTMIN+10",
6517 "SIGRTMIN+11",
6518 "SIGRTMIN+12",
6519 "SIGRTMIN+13",
6520 "SIGRTMIN+14",
6521 "SIGRTMIN+15",
6522 "SIGRTMAX-15",
6523 "SIGRTMAX-14",
6524 "SIGRTMAX-13",
6525 "SIGRTMAX-12",
6526 "SIGRTMAX-11",
6527 "SIGRTMAX-10",
6528 "SIGRTMAX-9",
6529 "SIGRTMAX-8",
6530 "SIGRTMAX-7",
6531 "SIGRTMAX-6",
6532 "SIGRTMAX-5",
6533 "SIGRTMAX-4",
6534 "SIGRTMAX-3",
6535 "SIGRTMAX-2",
6536 "SIGRTMAX-1",
6537 "SIGRTMAX",
Eric Andersen62483552001-07-10 06:09:16 +00006538#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006539 "DEBUG",
6540 (char *)0x0,
6541};
6542
6543
6544
Eric Andersen2870d962001-07-02 17:27:21 +00006545#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006546static int
6547killcmd(argc, argv)
6548 int argc;
6549 char **argv;
6550{
6551 int signo = -1;
6552 int list = 0;
6553 int i;
6554 pid_t pid;
6555 struct job *jp;
6556
6557 if (argc <= 1) {
6558usage:
6559 error(
6560"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6561"kill -l [exitstatus]"
6562 );
6563 }
6564
6565 if (*argv[1] == '-') {
6566 signo = decode_signal(argv[1] + 1, 1);
6567 if (signo < 0) {
6568 int c;
6569
6570 while ((c = nextopt("ls:")) != '\0')
6571 switch (c) {
6572 case 'l':
6573 list = 1;
6574 break;
6575 case 's':
6576 signo = decode_signal(optionarg, 1);
6577 if (signo < 0) {
6578 error(
6579 "invalid signal number or name: %s",
6580 optionarg
6581 );
6582 }
Eric Andersen2870d962001-07-02 17:27:21 +00006583 break;
Eric Andersencb57d552001-06-28 07:25:16 +00006584#ifdef DEBUG
6585 default:
6586 error(
6587 "nextopt returned character code 0%o", c);
6588#endif
6589 }
6590 } else
6591 argptr++;
6592 }
6593
6594 if (!list && signo < 0)
6595 signo = SIGTERM;
6596
6597 if ((signo < 0 || !*argptr) ^ list) {
6598 goto usage;
6599 }
6600
6601 if (list) {
6602 if (!*argptr) {
6603 out1str("0\n");
6604 for (i = 1; i < NSIG; i++) {
Eric Andersen62483552001-07-10 06:09:16 +00006605 printf(snlfmt, signal_names[i] + 3);
Eric Andersencb57d552001-06-28 07:25:16 +00006606 }
6607 return 0;
6608 }
6609 signo = atoi(*argptr);
6610 if (signo > 128)
6611 signo -= 128;
6612 if (0 < signo && signo < NSIG)
Eric Andersen62483552001-07-10 06:09:16 +00006613 printf(snlfmt, signal_names[signo] + 3);
Eric Andersencb57d552001-06-28 07:25:16 +00006614 else
6615 error("invalid signal number or exit status: %s",
6616 *argptr);
6617 return 0;
6618 }
6619
6620 do {
6621 if (**argptr == '%') {
6622 jp = getjob(*argptr);
6623 if (jp->jobctl == 0)
6624 error("job %s not created under job control",
6625 *argptr);
6626 pid = -jp->ps[0].pid;
6627 } else
6628 pid = atoi(*argptr);
6629 if (kill(pid, signo) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00006630 error("%s: %m", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006631 } while (*++argptr);
6632
6633 return 0;
6634}
6635
6636static int
6637fgcmd(argc, argv)
6638 int argc;
6639 char **argv;
6640{
6641 struct job *jp;
6642 int pgrp;
6643 int status;
6644
6645 jp = getjob(argv[1]);
6646 if (jp->jobctl == 0)
6647 error("job not created under job control");
6648 pgrp = jp->ps[0].pid;
6649#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006650 ioctl(2, TIOCSPGRP, (char *)&pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006651#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006652 tcsetpgrp(2, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006653#endif
6654 restartjob(jp);
6655 INTOFF;
6656 status = waitforjob(jp);
6657 INTON;
6658 return status;
6659}
6660
6661
6662static int
6663bgcmd(argc, argv)
6664 int argc;
6665 char **argv;
6666{
6667 struct job *jp;
6668
6669 do {
6670 jp = getjob(*++argv);
6671 if (jp->jobctl == 0)
6672 error("job not created under job control");
6673 restartjob(jp);
6674 } while (--argc > 1);
6675 return 0;
6676}
6677
6678
6679static void
6680restartjob(jp)
6681 struct job *jp;
6682{
6683 struct procstat *ps;
6684 int i;
6685
6686 if (jp->state == JOBDONE)
6687 return;
6688 INTOFF;
6689 killpg(jp->ps[0].pid, SIGCONT);
6690 for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
6691 if (WIFSTOPPED(ps->status)) {
6692 ps->status = -1;
6693 jp->state = 0;
6694 }
6695 }
6696 INTON;
6697}
6698#endif
6699
Eric Andersen2870d962001-07-02 17:27:21 +00006700static void showjobs(int change);
6701
Eric Andersencb57d552001-06-28 07:25:16 +00006702
6703static int
6704jobscmd(argc, argv)
6705 int argc;
6706 char **argv;
6707{
6708 showjobs(0);
6709 return 0;
6710}
6711
6712
6713/*
6714 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6715 * statuses have changed since the last call to showjobs.
6716 *
6717 * If the shell is interrupted in the process of creating a job, the
6718 * result may be a job structure containing zero processes. Such structures
6719 * will be freed here.
6720 */
6721
6722static void
6723showjobs(change)
6724 int change;
6725{
6726 int jobno;
6727 int procno;
6728 int i;
6729 struct job *jp;
6730 struct procstat *ps;
6731 int col;
6732 char s[64];
6733
6734 TRACE(("showjobs(%d) called\n", change));
6735 while (dowait(0, (struct job *)NULL) > 0);
6736 for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
6737 if (! jp->used)
6738 continue;
6739 if (jp->nprocs == 0) {
6740 freejob(jp);
6741 continue;
6742 }
6743 if (change && ! jp->changed)
6744 continue;
6745 procno = jp->nprocs;
Eric Andersen2870d962001-07-02 17:27:21 +00006746 for (ps = jp->ps ; ; ps++) { /* for each process */
Eric Andersencb57d552001-06-28 07:25:16 +00006747 if (ps == jp->ps)
Eric Andersen3102ac42001-07-06 04:26:23 +00006748 snprintf(s, 64, "[%d] %ld ", jobno,
Eric Andersencb57d552001-06-28 07:25:16 +00006749 (long)ps->pid);
6750 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006751 snprintf(s, 64, " %ld ",
Eric Andersencb57d552001-06-28 07:25:16 +00006752 (long)ps->pid);
6753 out1str(s);
6754 col = strlen(s);
6755 s[0] = '\0';
6756 if (ps->status == -1) {
6757 /* don't print anything */
6758 } else if (WIFEXITED(ps->status)) {
Eric Andersen3102ac42001-07-06 04:26:23 +00006759 snprintf(s, 64, "Exit %d",
Eric Andersencb57d552001-06-28 07:25:16 +00006760 WEXITSTATUS(ps->status));
6761 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00006762#ifdef JOBS
6763 if (WIFSTOPPED(ps->status))
Eric Andersencb57d552001-06-28 07:25:16 +00006764 i = WSTOPSIG(ps->status);
6765 else /* WIFSIGNALED(ps->status) */
6766#endif
6767 i = WTERMSIG(ps->status);
6768 if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
Eric Andersen2870d962001-07-02 17:27:21 +00006769 strcpy(s, sys_siglist[i & 0x7F]);
Eric Andersencb57d552001-06-28 07:25:16 +00006770 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006771 snprintf(s, 64, "Signal %d", i & 0x7F);
Eric Andersencb57d552001-06-28 07:25:16 +00006772 if (WCOREDUMP(ps->status))
6773 strcat(s, " (core dumped)");
6774 }
6775 out1str(s);
6776 col += strlen(s);
Eric Andersen62483552001-07-10 06:09:16 +00006777 printf(
Eric Andersencb57d552001-06-28 07:25:16 +00006778 "%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ',
6779 ps->cmd
6780 );
6781 if (--procno <= 0)
6782 break;
6783 }
6784 jp->changed = 0;
6785 if (jp->state == JOBDONE) {
6786 freejob(jp);
6787 }
6788 }
6789}
6790
6791
6792/*
6793 * Mark a job structure as unused.
6794 */
6795
6796static void
Eric Andersen62483552001-07-10 06:09:16 +00006797freejob(struct job *jp)
6798{
6799 const struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006800 int i;
6801
6802 INTOFF;
6803 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6804 if (ps->cmd != nullstr)
6805 ckfree(ps->cmd);
6806 }
6807 if (jp->ps != &jp->ps0)
6808 ckfree(jp->ps);
6809 jp->used = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006810#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006811 if (curjob == jp - jobtab + 1)
6812 curjob = 0;
6813#endif
6814 INTON;
6815}
6816
6817
6818
6819static int
6820waitcmd(argc, argv)
6821 int argc;
6822 char **argv;
6823{
6824 struct job *job;
6825 int status, retval;
6826 struct job *jp;
6827
6828 if (--argc > 0) {
6829start:
6830 job = getjob(*++argv);
6831 } else {
6832 job = NULL;
6833 }
Eric Andersen2870d962001-07-02 17:27:21 +00006834 for (;;) { /* loop until process terminated or stopped */
Eric Andersencb57d552001-06-28 07:25:16 +00006835 if (job != NULL) {
6836 if (job->state) {
6837 status = job->ps[job->nprocs - 1].status;
6838 if (! iflag)
6839 freejob(job);
6840 if (--argc) {
6841 goto start;
6842 }
6843 if (WIFEXITED(status))
6844 retval = WEXITSTATUS(status);
Eric Andersen2870d962001-07-02 17:27:21 +00006845#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006846 else if (WIFSTOPPED(status))
6847 retval = WSTOPSIG(status) + 128;
6848#endif
6849 else {
6850 /* XXX: limits number of signals */
6851 retval = WTERMSIG(status) + 128;
6852 }
6853 return retval;
6854 }
6855 } else {
6856 for (jp = jobtab ; ; jp++) {
Eric Andersen2870d962001-07-02 17:27:21 +00006857 if (jp >= jobtab + njobs) { /* no running procs */
Eric Andersencb57d552001-06-28 07:25:16 +00006858 return 0;
6859 }
6860 if (jp->used && jp->state == 0)
6861 break;
6862 }
6863 }
6864 if (dowait(2, 0) < 0 && errno == EINTR) {
6865 return 129;
6866 }
6867 }
6868}
6869
6870
6871
6872/*
6873 * Convert a job name to a job structure.
6874 */
6875
6876static struct job *
Eric Andersen2870d962001-07-02 17:27:21 +00006877getjob(const char *name)
6878{
Eric Andersencb57d552001-06-28 07:25:16 +00006879 int jobno;
6880 struct job *jp;
6881 int pid;
6882 int i;
6883
6884 if (name == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00006885#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006886currentjob:
6887 if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
6888 error("No current job");
6889 return &jobtab[jobno - 1];
6890#else
6891 error("No current job");
6892#endif
6893 } else if (name[0] == '%') {
6894 if (is_digit(name[1])) {
6895 jobno = number(name + 1);
6896 if (jobno > 0 && jobno <= njobs
6897 && jobtab[jobno - 1].used != 0)
6898 return &jobtab[jobno - 1];
Eric Andersen2870d962001-07-02 17:27:21 +00006899#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006900 } else if (name[1] == '%' && name[2] == '\0') {
6901 goto currentjob;
6902#endif
6903 } else {
6904 struct job *found = NULL;
6905 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
6906 if (jp->used && jp->nprocs > 0
6907 && prefix(name + 1, jp->ps[0].cmd)) {
6908 if (found)
6909 error("%s: ambiguous", name);
6910 found = jp;
6911 }
6912 }
6913 if (found)
6914 return found;
6915 }
Eric Andersen2870d962001-07-02 17:27:21 +00006916 } else if (is_number(name, &pid)) {
Eric Andersencb57d552001-06-28 07:25:16 +00006917 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
6918 if (jp->used && jp->nprocs > 0
6919 && jp->ps[jp->nprocs - 1].pid == pid)
6920 return jp;
6921 }
6922 }
6923 error("No such job: %s", name);
6924 /* NOTREACHED */
6925}
6926
6927
6928
6929/*
6930 * Return a new job structure,
6931 */
6932
Eric Andersen2870d962001-07-02 17:27:21 +00006933static struct job *
Eric Andersen62483552001-07-10 06:09:16 +00006934makejob(const union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00006935{
6936 int i;
6937 struct job *jp;
6938
6939 for (i = njobs, jp = jobtab ; ; jp++) {
6940 if (--i < 0) {
6941 INTOFF;
6942 if (njobs == 0) {
6943 jobtab = ckmalloc(4 * sizeof jobtab[0]);
6944 } else {
6945 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
6946 memcpy(jp, jobtab, njobs * sizeof jp[0]);
6947 /* Relocate `ps' pointers */
6948 for (i = 0; i < njobs; i++)
6949 if (jp[i].ps == &jobtab[i].ps0)
6950 jp[i].ps = &jp[i].ps0;
6951 ckfree(jobtab);
6952 jobtab = jp;
6953 }
6954 jp = jobtab + njobs;
6955 for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
6956 INTON;
6957 break;
6958 }
6959 if (jp->used == 0)
6960 break;
6961 }
6962 INTOFF;
6963 jp->state = 0;
6964 jp->used = 1;
6965 jp->changed = 0;
6966 jp->nprocs = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006967#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006968 jp->jobctl = jobctl;
6969#endif
6970 if (nprocs > 1) {
6971 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
6972 } else {
6973 jp->ps = &jp->ps0;
6974 }
6975 INTON;
6976 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
6977 jp - jobtab + 1));
6978 return jp;
6979}
6980
6981
6982/*
6983 * Fork of a subshell. If we are doing job control, give the subshell its
6984 * own process group. Jp is a job structure that the job is to be added to.
6985 * N is the command that will be evaluated by the child. Both jp and n may
6986 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00006987 * FORK_FG - Fork off a foreground process.
6988 * FORK_BG - Fork off a background process.
6989 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
6990 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00006991 *
6992 * When job control is turned off, background processes have their standard
6993 * input redirected to /dev/null (except for the second and later processes
6994 * in a pipeline).
6995 */
6996
Eric Andersen2870d962001-07-02 17:27:21 +00006997
6998
Eric Andersencb57d552001-06-28 07:25:16 +00006999static int
Eric Andersen62483552001-07-10 06:09:16 +00007000forkshell(struct job *jp, const union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00007001{
7002 int pid;
Eric Andersen62483552001-07-10 06:09:16 +00007003#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007004 int pgrp;
Eric Andersen62483552001-07-10 06:09:16 +00007005#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007006 const char *devnull = _PATH_DEVNULL;
7007 const char *nullerr = "Can't open %s";
7008
7009 TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
7010 mode));
7011 INTOFF;
7012 pid = fork();
7013 if (pid == -1) {
7014 TRACE(("Fork failed, errno=%d\n", errno));
7015 INTON;
7016 error("Cannot fork");
7017 }
7018 if (pid == 0) {
7019 struct job *p;
7020 int wasroot;
7021 int i;
7022
7023 TRACE(("Child shell %d\n", getpid()));
7024 wasroot = rootshell;
7025 rootshell = 0;
7026 closescript();
7027 INTON;
7028 clear_traps();
Eric Andersen2870d962001-07-02 17:27:21 +00007029#ifdef JOBS
7030 jobctl = 0; /* do job control only in root shell */
Eric Andersencb57d552001-06-28 07:25:16 +00007031 if (wasroot && mode != FORK_NOJOB && mflag) {
7032 if (jp == NULL || jp->nprocs == 0)
7033 pgrp = getpid();
7034 else
7035 pgrp = jp->ps[0].pid;
7036 setpgid(0, pgrp);
7037 if (mode == FORK_FG) {
7038 /*** this causes superfluous TIOCSPGRPS ***/
7039#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00007040 if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007041 error("TIOCSPGRP failed, errno=%d", errno);
7042#else
Eric Andersen3102ac42001-07-06 04:26:23 +00007043 if (tcsetpgrp(2, pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007044 error("tcsetpgrp failed, errno=%d", errno);
7045#endif
7046 }
7047 setsignal(SIGTSTP);
7048 setsignal(SIGTTOU);
7049 } else if (mode == FORK_BG) {
7050 ignoresig(SIGINT);
7051 ignoresig(SIGQUIT);
7052 if ((jp == NULL || jp->nprocs == 0) &&
7053 ! fd0_redirected_p ()) {
7054 close(0);
7055 if (open(devnull, O_RDONLY) != 0)
7056 error(nullerr, devnull);
7057 }
7058 }
7059#else
7060 if (mode == FORK_BG) {
7061 ignoresig(SIGINT);
7062 ignoresig(SIGQUIT);
7063 if ((jp == NULL || jp->nprocs == 0) &&
7064 ! fd0_redirected_p ()) {
7065 close(0);
7066 if (open(devnull, O_RDONLY) != 0)
7067 error(nullerr, devnull);
7068 }
7069 }
7070#endif
7071 for (i = njobs, p = jobtab ; --i >= 0 ; p++)
7072 if (p->used)
7073 freejob(p);
7074 if (wasroot && iflag) {
7075 setsignal(SIGINT);
7076 setsignal(SIGQUIT);
7077 setsignal(SIGTERM);
7078 }
7079 return pid;
7080 }
Eric Andersen62483552001-07-10 06:09:16 +00007081#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007082 if (rootshell && mode != FORK_NOJOB && mflag) {
7083 if (jp == NULL || jp->nprocs == 0)
7084 pgrp = pid;
7085 else
7086 pgrp = jp->ps[0].pid;
7087 setpgid(pid, pgrp);
7088 }
Eric Andersen62483552001-07-10 06:09:16 +00007089#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007090 if (mode == FORK_BG)
Eric Andersen2870d962001-07-02 17:27:21 +00007091 backgndpid = pid; /* set $! */
Eric Andersencb57d552001-06-28 07:25:16 +00007092 if (jp) {
7093 struct procstat *ps = &jp->ps[jp->nprocs++];
7094 ps->pid = pid;
7095 ps->status = -1;
7096 ps->cmd = nullstr;
7097 if (iflag && rootshell && n)
7098 ps->cmd = commandtext(n);
7099 }
7100 INTON;
7101 TRACE(("In parent shell: child = %d\n", pid));
7102 return pid;
7103}
7104
7105
7106
7107/*
7108 * Wait for job to finish.
7109 *
7110 * Under job control we have the problem that while a child process is
7111 * running interrupts generated by the user are sent to the child but not
7112 * to the shell. This means that an infinite loop started by an inter-
7113 * active user may be hard to kill. With job control turned off, an
7114 * interactive user may place an interactive program inside a loop. If
7115 * the interactive program catches interrupts, the user doesn't want
7116 * these interrupts to also abort the loop. The approach we take here
7117 * is to have the shell ignore interrupt signals while waiting for a
7118 * forground process to terminate, and then send itself an interrupt
7119 * signal if the child process was terminated by an interrupt signal.
7120 * Unfortunately, some programs want to do a bit of cleanup and then
7121 * exit on interrupt; unless these processes terminate themselves by
7122 * sending a signal to themselves (instead of calling exit) they will
7123 * confuse this approach.
7124 */
7125
7126static int
Eric Andersen62483552001-07-10 06:09:16 +00007127waitforjob(struct job *jp)
7128{
Eric Andersen2870d962001-07-02 17:27:21 +00007129#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007130 int mypgrp = getpgrp();
7131#endif
7132 int status;
7133 int st;
7134 struct sigaction act, oact;
7135
7136 INTOFF;
7137 intreceived = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00007138#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007139 if (!jobctl) {
7140#else
7141 if (!iflag) {
7142#endif
7143 sigaction(SIGINT, 0, &act);
7144 act.sa_handler = waitonint;
7145 sigaction(SIGINT, &act, &oact);
7146 }
7147 TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
7148 while (jp->state == 0) {
7149 dowait(1, jp);
7150 }
Eric Andersen2870d962001-07-02 17:27:21 +00007151#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007152 if (!jobctl) {
7153#else
7154 if (!iflag) {
7155#endif
7156 sigaction(SIGINT, &oact, 0);
7157 if (intreceived && trap[SIGINT]) kill(getpid(), SIGINT);
7158 }
Eric Andersen2870d962001-07-02 17:27:21 +00007159#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007160 if (jp->jobctl) {
7161#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00007162 if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007163 error("TIOCSPGRP failed, errno=%d\n", errno);
7164#else
Eric Andersen3102ac42001-07-06 04:26:23 +00007165 if (tcsetpgrp(2, mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007166 error("tcsetpgrp failed, errno=%d\n", errno);
7167#endif
7168 }
7169 if (jp->state == JOBSTOPPED)
7170 curjob = jp - jobtab + 1;
7171#endif
7172 status = jp->ps[jp->nprocs - 1].status;
7173 /* convert to 8 bits */
7174 if (WIFEXITED(status))
7175 st = WEXITSTATUS(status);
Eric Andersen2870d962001-07-02 17:27:21 +00007176#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007177 else if (WIFSTOPPED(status))
7178 st = WSTOPSIG(status) + 128;
7179#endif
7180 else
7181 st = WTERMSIG(status) + 128;
Eric Andersen2870d962001-07-02 17:27:21 +00007182#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007183 if (jp->jobctl) {
7184 /*
7185 * This is truly gross.
7186 * If we're doing job control, then we did a TIOCSPGRP which
7187 * caused us (the shell) to no longer be in the controlling
7188 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7189 * intuit from the subprocess exit status whether a SIGINT
7190 * occured, and if so interrupt ourselves. Yuck. - mycroft
7191 */
7192 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
7193 raise(SIGINT);
7194 }
Eric Andersen2870d962001-07-02 17:27:21 +00007195 if (jp->state == JOBDONE)
7196
Eric Andersencb57d552001-06-28 07:25:16 +00007197#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007198 freejob(jp);
7199 INTON;
7200 return st;
7201}
7202
7203
7204
7205/*
7206 * Wait for a process to terminate.
7207 */
7208
Eric Andersen62483552001-07-10 06:09:16 +00007209/*
7210 * Do a wait system call. If job control is compiled in, we accept
7211 * stopped processes. If block is zero, we return a value of zero
7212 * rather than blocking.
7213 *
7214 * System V doesn't have a non-blocking wait system call. It does
7215 * have a SIGCLD signal that is sent to a process when one of it's
7216 * children dies. The obvious way to use SIGCLD would be to install
7217 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7218 * was received, and have waitproc bump another counter when it got
7219 * the status of a process. Waitproc would then know that a wait
7220 * system call would not block if the two counters were different.
7221 * This approach doesn't work because if a process has children that
7222 * have not been waited for, System V will send it a SIGCLD when it
7223 * installs a signal handler for SIGCLD. What this means is that when
7224 * a child exits, the shell will be sent SIGCLD signals continuously
7225 * until is runs out of stack space, unless it does a wait call before
7226 * restoring the signal handler. The code below takes advantage of
7227 * this (mis)feature by installing a signal handler for SIGCLD and
7228 * then checking to see whether it was called. If there are any
7229 * children to be waited for, it will be.
7230 *
7231 */
7232
7233static inline int
7234waitproc(int block, int *status)
7235{
7236 int flags;
7237
7238 flags = 0;
7239#ifdef JOBS
7240 if (jobctl)
7241 flags |= WUNTRACED;
7242#endif
7243 if (block == 0)
7244 flags |= WNOHANG;
7245 return wait3(status, flags, (struct rusage *)NULL);
7246}
7247
Eric Andersencb57d552001-06-28 07:25:16 +00007248static int
Eric Andersen62483552001-07-10 06:09:16 +00007249dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00007250{
7251 int pid;
7252 int status;
7253 struct procstat *sp;
7254 struct job *jp;
7255 struct job *thisjob;
7256 int done;
7257 int stopped;
7258 int core;
7259 int sig;
7260
7261 TRACE(("dowait(%d) called\n", block));
7262 do {
7263 pid = waitproc(block, &status);
7264 TRACE(("wait returns %d, status=%d\n", pid, status));
7265 } while (!(block & 2) && pid == -1 && errno == EINTR);
7266 if (pid <= 0)
7267 return pid;
7268 INTOFF;
7269 thisjob = NULL;
7270 for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
7271 if (jp->used) {
7272 done = 1;
7273 stopped = 1;
7274 for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
7275 if (sp->pid == -1)
7276 continue;
7277 if (sp->pid == pid) {
7278 TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
7279 sp->status = status;
7280 thisjob = jp;
7281 }
7282 if (sp->status == -1)
7283 stopped = 0;
7284 else if (WIFSTOPPED(sp->status))
7285 done = 0;
7286 }
Eric Andersen2870d962001-07-02 17:27:21 +00007287 if (stopped) { /* stopped or done */
Eric Andersencb57d552001-06-28 07:25:16 +00007288 int state = done? JOBDONE : JOBSTOPPED;
7289 if (jp->state != state) {
7290 TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
7291 jp->state = state;
Eric Andersen2870d962001-07-02 17:27:21 +00007292#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007293 if (done && curjob == jp - jobtab + 1)
Eric Andersen2870d962001-07-02 17:27:21 +00007294 curjob = 0; /* no current job */
Eric Andersencb57d552001-06-28 07:25:16 +00007295#endif
7296 }
7297 }
7298 }
7299 }
7300 INTON;
7301 if (! rootshell || ! iflag || (job && thisjob == job)) {
7302 core = WCOREDUMP(status);
Eric Andersen2870d962001-07-02 17:27:21 +00007303#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007304 if (WIFSTOPPED(status)) sig = WSTOPSIG(status);
7305 else
7306#endif
7307 if (WIFEXITED(status)) sig = 0;
7308 else sig = WTERMSIG(status);
7309
7310 if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
7311 if (thisjob != job)
Eric Andersen3102ac42001-07-06 04:26:23 +00007312 out2fmt("%d: ", pid);
Eric Andersen2870d962001-07-02 17:27:21 +00007313#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007314 if (sig == SIGTSTP && rootshell && iflag)
Eric Andersen3102ac42001-07-06 04:26:23 +00007315 out2fmt("%%%ld ",
Eric Andersencb57d552001-06-28 07:25:16 +00007316 (long)(job - jobtab + 1));
7317#endif
7318 if (sig < NSIG && sys_siglist[sig])
7319 out2str(sys_siglist[sig]);
7320 else
Eric Andersen3102ac42001-07-06 04:26:23 +00007321 out2fmt("Signal %d", sig);
Eric Andersencb57d552001-06-28 07:25:16 +00007322 if (core)
7323 out2str(" - core dumped");
7324 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00007325 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00007326 TRACE(("Not printing status: status=%d, sig=%d\n",
Eric Andersencb57d552001-06-28 07:25:16 +00007327 status, sig));
7328 }
7329 } else {
7330 TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
7331 if (thisjob)
7332 thisjob->changed = 1;
7333 }
7334 return pid;
7335}
7336
7337
7338
Eric Andersencb57d552001-06-28 07:25:16 +00007339
7340/*
7341 * return 1 if there are stopped jobs, otherwise 0
7342 */
Eric Andersencb57d552001-06-28 07:25:16 +00007343static int
Eric Andersen2870d962001-07-02 17:27:21 +00007344stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007345{
7346 int jobno;
7347 struct job *jp;
7348
7349 if (job_warning)
7350 return (0);
7351 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
7352 if (jp->used == 0)
7353 continue;
7354 if (jp->state == JOBSTOPPED) {
7355 out2str("You have stopped jobs.\n");
7356 job_warning = 2;
7357 return (1);
7358 }
7359 }
7360
7361 return (0);
7362}
7363
7364/*
7365 * Return a string identifying a command (to be printed by the
7366 * jobs command.
7367 */
7368
7369static char *cmdnextc;
7370static int cmdnleft;
Eric Andersen2870d962001-07-02 17:27:21 +00007371#define MAXCMDTEXT 200
Eric Andersencb57d552001-06-28 07:25:16 +00007372
Eric Andersen2870d962001-07-02 17:27:21 +00007373static void
7374cmdputs(const char *s)
7375{
7376 const char *p;
7377 char *q;
7378 char c;
7379 int subtype = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007380
Eric Andersen2870d962001-07-02 17:27:21 +00007381 if (cmdnleft <= 0)
7382 return;
7383 p = s;
7384 q = cmdnextc;
7385 while ((c = *p++) != '\0') {
7386 if (c == CTLESC)
7387 *q++ = *p++;
7388 else if (c == CTLVAR) {
7389 *q++ = '$';
7390 if (--cmdnleft > 0)
7391 *q++ = '{';
7392 subtype = *p++;
7393 } else if (c == '=' && subtype != 0) {
7394 *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
7395 subtype = 0;
7396 } else if (c == CTLENDVAR) {
7397 *q++ = '}';
7398 } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
7399 cmdnleft++; /* ignore it */
7400 else
7401 *q++ = c;
7402 if (--cmdnleft <= 0) {
7403 *q++ = '.';
7404 *q++ = '.';
7405 *q++ = '.';
7406 break;
7407 }
7408 }
7409 cmdnextc = q;
Eric Andersencb57d552001-06-28 07:25:16 +00007410}
7411
7412
7413static void
Eric Andersen2870d962001-07-02 17:27:21 +00007414cmdtxt(const union node *n)
7415{
Eric Andersencb57d552001-06-28 07:25:16 +00007416 union node *np;
7417 struct nodelist *lp;
7418 const char *p;
7419 int i;
7420 char s[2];
7421
7422 if (n == NULL)
7423 return;
7424 switch (n->type) {
7425 case NSEMI:
7426 cmdtxt(n->nbinary.ch1);
7427 cmdputs("; ");
7428 cmdtxt(n->nbinary.ch2);
7429 break;
7430 case NAND:
7431 cmdtxt(n->nbinary.ch1);
7432 cmdputs(" && ");
7433 cmdtxt(n->nbinary.ch2);
7434 break;
7435 case NOR:
7436 cmdtxt(n->nbinary.ch1);
7437 cmdputs(" || ");
7438 cmdtxt(n->nbinary.ch2);
7439 break;
7440 case NPIPE:
7441 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7442 cmdtxt(lp->n);
7443 if (lp->next)
7444 cmdputs(" | ");
7445 }
7446 break;
7447 case NSUBSHELL:
7448 cmdputs("(");
7449 cmdtxt(n->nredir.n);
7450 cmdputs(")");
7451 break;
7452 case NREDIR:
7453 case NBACKGND:
7454 cmdtxt(n->nredir.n);
7455 break;
7456 case NIF:
7457 cmdputs("if ");
7458 cmdtxt(n->nif.test);
7459 cmdputs("; then ");
7460 cmdtxt(n->nif.ifpart);
7461 cmdputs("...");
7462 break;
7463 case NWHILE:
7464 cmdputs("while ");
7465 goto until;
7466 case NUNTIL:
7467 cmdputs("until ");
7468until:
7469 cmdtxt(n->nbinary.ch1);
7470 cmdputs("; do ");
7471 cmdtxt(n->nbinary.ch2);
7472 cmdputs("; done");
7473 break;
7474 case NFOR:
7475 cmdputs("for ");
7476 cmdputs(n->nfor.var);
7477 cmdputs(" in ...");
7478 break;
7479 case NCASE:
7480 cmdputs("case ");
7481 cmdputs(n->ncase.expr->narg.text);
7482 cmdputs(" in ...");
7483 break;
7484 case NDEFUN:
7485 cmdputs(n->narg.text);
7486 cmdputs("() ...");
7487 break;
7488 case NCMD:
7489 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7490 cmdtxt(np);
7491 if (np->narg.next)
7492 cmdputs(spcstr);
7493 }
7494 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7495 cmdputs(spcstr);
7496 cmdtxt(np);
7497 }
7498 break;
7499 case NARG:
7500 cmdputs(n->narg.text);
7501 break;
7502 case NTO:
7503 p = ">"; i = 1; goto redir;
7504 case NAPPEND:
7505 p = ">>"; i = 1; goto redir;
7506 case NTOFD:
7507 p = ">&"; i = 1; goto redir;
7508 case NTOOV:
7509 p = ">|"; i = 1; goto redir;
7510 case NFROM:
7511 p = "<"; i = 0; goto redir;
7512 case NFROMFD:
7513 p = "<&"; i = 0; goto redir;
7514 case NFROMTO:
7515 p = "<>"; i = 0; goto redir;
7516redir:
7517 if (n->nfile.fd != i) {
7518 s[0] = n->nfile.fd + '0';
7519 s[1] = '\0';
7520 cmdputs(s);
7521 }
7522 cmdputs(p);
7523 if (n->type == NTOFD || n->type == NFROMFD) {
7524 s[0] = n->ndup.dupfd + '0';
7525 s[1] = '\0';
7526 cmdputs(s);
7527 } else {
7528 cmdtxt(n->nfile.fname);
7529 }
7530 break;
7531 case NHERE:
7532 case NXHERE:
7533 cmdputs("<<...");
7534 break;
7535 default:
7536 cmdputs("???");
7537 break;
7538 }
7539}
7540
7541
Eric Andersen2870d962001-07-02 17:27:21 +00007542static char *
7543commandtext(const union node *n)
7544{
7545 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007546
Eric Andersen2870d962001-07-02 17:27:21 +00007547 cmdnextc = name = ckmalloc(MAXCMDTEXT);
7548 cmdnleft = MAXCMDTEXT - 4;
7549 cmdtxt(n);
7550 *cmdnextc = '\0';
7551 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00007552}
7553
Eric Andersen2870d962001-07-02 17:27:21 +00007554
Eric Andersencb57d552001-06-28 07:25:16 +00007555static void waitonint(int sig) {
7556 intreceived = 1;
7557 return;
7558}
Eric Andersencb57d552001-06-28 07:25:16 +00007559/*
7560 * Routines to check for mail. (Perhaps make part of main.c?)
7561 */
7562
7563
7564#define MAXMBOXES 10
7565
7566
Eric Andersen2870d962001-07-02 17:27:21 +00007567static int nmboxes; /* number of mailboxes */
7568static time_t mailtime[MAXMBOXES]; /* times of mailboxes */
Eric Andersencb57d552001-06-28 07:25:16 +00007569
7570
7571
7572/*
7573 * Print appropriate message(s) if mail has arrived. If the argument is
7574 * nozero, then the value of MAIL has changed, so we just update the
7575 * values.
7576 */
7577
7578static void
Eric Andersen2870d962001-07-02 17:27:21 +00007579chkmail(int silent)
Eric Andersencb57d552001-06-28 07:25:16 +00007580{
7581 int i;
7582 const char *mpath;
7583 char *p;
7584 char *q;
7585 struct stackmark smark;
7586 struct stat statb;
7587
7588 if (silent)
7589 nmboxes = 10;
7590 if (nmboxes == 0)
7591 return;
7592 setstackmark(&smark);
7593 mpath = mpathset()? mpathval() : mailval();
7594 for (i = 0 ; i < nmboxes ; i++) {
7595 p = padvance(&mpath, nullstr);
7596 if (p == NULL)
7597 break;
7598 if (*p == '\0')
7599 continue;
7600 for (q = p ; *q ; q++);
7601#ifdef DEBUG
7602 if (q[-1] != '/')
7603 abort();
7604#endif
Eric Andersen2870d962001-07-02 17:27:21 +00007605 q[-1] = '\0'; /* delete trailing '/' */
Eric Andersencb57d552001-06-28 07:25:16 +00007606 if (stat(p, &statb) < 0)
7607 statb.st_size = 0;
7608 if (statb.st_size > mailtime[i] && ! silent) {
Eric Andersen3102ac42001-07-06 04:26:23 +00007609 out2fmt(snlfmt,
7610 pathopt? pathopt : "you have mail");
Eric Andersencb57d552001-06-28 07:25:16 +00007611 }
7612 mailtime[i] = statb.st_size;
Eric Andersencb57d552001-06-28 07:25:16 +00007613 }
7614 nmboxes = i;
7615 popstackmark(&smark);
7616}
Eric Andersencb57d552001-06-28 07:25:16 +00007617
7618#define PROFILE 0
7619
Eric Andersencb57d552001-06-28 07:25:16 +00007620#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007621static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007622extern int etext();
7623#endif
7624
Eric Andersen2870d962001-07-02 17:27:21 +00007625static void read_profile (const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007626static void cmdloop (int);
7627static void options (int);
Eric Andersen2870d962001-07-02 17:27:21 +00007628static void setoption (int, int);
7629static void procargs (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00007630
Eric Andersen2870d962001-07-02 17:27:21 +00007631
Eric Andersencb57d552001-06-28 07:25:16 +00007632/*
7633 * Main routine. We initialize things, parse the arguments, execute
7634 * profiles if we're a login shell, and then call cmdloop to execute
7635 * commands. The setjmp call sets up the location to jump to when an
7636 * exception occurs. When an exception occurs the variable "state"
7637 * is used to figure out how far we had gotten.
7638 */
7639
7640int
7641shell_main(argc, argv)
7642 int argc;
7643 char **argv;
7644{
7645 struct jmploc jmploc;
7646 struct stackmark smark;
7647 volatile int state;
Eric Andersen62483552001-07-10 06:09:16 +00007648 const char *shinit;
Eric Andersencb57d552001-06-28 07:25:16 +00007649
Eric Andersencb57d552001-06-28 07:25:16 +00007650 BLTINCMD = find_builtin("builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00007651 EXECCMD = find_builtin("exec");
7652 EVALCMD = find_builtin("eval");
7653
Eric Andersen1c039232001-07-07 00:05:55 +00007654#ifndef BB_FEATURE_SH_FANCY_PROMPT
7655 unsetenv("PS1");
7656 unsetenv("PS2");
7657#endif
7658
Eric Andersencb57d552001-06-28 07:25:16 +00007659#if PROFILE
7660 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7661#endif
7662#if defined(linux) || defined(__GNU__)
7663 signal(SIGCHLD, SIG_DFL);
7664#endif
7665 state = 0;
7666 if (setjmp(jmploc.loc)) {
7667 INTOFF;
7668 /*
7669 * When a shell procedure is executed, we raise the
7670 * exception EXSHELLPROC to clean up before executing
7671 * the shell procedure.
7672 */
7673 switch (exception) {
7674 case EXSHELLPROC:
7675 rootpid = getpid();
7676 rootshell = 1;
7677 minusc = NULL;
7678 state = 3;
7679 break;
7680
7681 case EXEXEC:
7682 exitstatus = exerrno;
7683 break;
7684
7685 case EXERROR:
7686 exitstatus = 2;
7687 break;
7688
7689 default:
7690 break;
7691 }
7692
7693 if (exception != EXSHELLPROC) {
7694 if (state == 0 || iflag == 0 || ! rootshell)
7695 exitshell(exitstatus);
7696 }
7697 reset();
Eric Andersen2870d962001-07-02 17:27:21 +00007698 if (exception == EXINT) {
Eric Andersencb57d552001-06-28 07:25:16 +00007699 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00007700 }
7701 popstackmark(&smark);
Eric Andersen2870d962001-07-02 17:27:21 +00007702 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007703 if (state == 1)
7704 goto state1;
7705 else if (state == 2)
7706 goto state2;
7707 else if (state == 3)
7708 goto state3;
7709 else
7710 goto state4;
7711 }
7712 handler = &jmploc;
7713#ifdef DEBUG
7714 opentrace();
7715 trputs("Shell args: "); trargs(argv);
7716#endif
7717 rootpid = getpid();
7718 rootshell = 1;
7719 init();
7720 setstackmark(&smark);
7721 procargs(argc, argv);
7722 if (argv[0] && argv[0][0] == '-') {
7723 state = 1;
7724 read_profile("/etc/profile");
7725state1:
7726 state = 2;
7727 read_profile(".profile");
7728 }
7729state2:
7730 state = 3;
7731#ifndef linux
7732 if (getuid() == geteuid() && getgid() == getegid()) {
7733#endif
7734 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7735 state = 3;
7736 read_profile(shinit);
7737 }
7738#ifndef linux
7739 }
7740#endif
7741state3:
7742 state = 4;
7743 if (sflag == 0 || minusc) {
7744 static int sigs[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00007745 SIGINT, SIGQUIT, SIGHUP,
Eric Andersencb57d552001-06-28 07:25:16 +00007746#ifdef SIGTSTP
7747 SIGTSTP,
7748#endif
7749 SIGPIPE
7750 };
7751#define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0]))
7752 int i;
7753
7754 for (i = 0; i < SIGSSIZE; i++)
7755 setsignal(sigs[i]);
7756 }
7757
7758 if (minusc)
7759 evalstring(minusc, 0);
7760
7761 if (sflag || minusc == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00007762state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007763 cmdloop(1);
7764 }
7765#if PROFILE
7766 monitor(0);
7767#endif
7768 exitshell(exitstatus);
7769 /* NOTREACHED */
7770}
7771
7772
7773/*
7774 * Read and execute commands. "Top" is nonzero for the top level command
7775 * loop; it turns on prompting if the shell is interactive.
7776 */
7777
7778static void
Eric Andersen2870d962001-07-02 17:27:21 +00007779cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00007780{
7781 union node *n;
7782 struct stackmark smark;
7783 int inter;
7784 int numeof = 0;
7785
7786 TRACE(("cmdloop(%d) called\n", top));
7787 setstackmark(&smark);
7788 for (;;) {
7789 if (pendingsigs)
7790 dotrap();
7791 inter = 0;
7792 if (iflag && top) {
7793 inter++;
7794 showjobs(1);
7795 chkmail(0);
Eric Andersen3102ac42001-07-06 04:26:23 +00007796 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00007797 }
7798 n = parsecmd(inter);
7799 /* showtree(n); DEBUG */
7800 if (n == NEOF) {
7801 if (!top || numeof >= 50)
7802 break;
7803 if (!stoppedjobs()) {
7804 if (!Iflag)
7805 break;
7806 out2str("\nUse \"exit\" to leave shell.\n");
7807 }
7808 numeof++;
7809 } else if (n != NULL && nflag == 0) {
7810 job_warning = (job_warning == 2) ? 1 : 0;
7811 numeof = 0;
7812 evaltree(n, 0);
7813 }
7814 popstackmark(&smark);
7815 setstackmark(&smark);
7816 if (evalskip == SKIPFILE) {
7817 evalskip = 0;
7818 break;
7819 }
7820 }
7821 popstackmark(&smark);
7822}
7823
7824
7825
7826/*
7827 * Read /etc/profile or .profile. Return on error.
7828 */
7829
7830static void
7831read_profile(name)
7832 const char *name;
7833{
7834 int fd;
7835 int xflag_set = 0;
7836 int vflag_set = 0;
7837
7838 INTOFF;
7839 if ((fd = open(name, O_RDONLY)) >= 0)
7840 setinputfd(fd, 1);
7841 INTON;
7842 if (fd < 0)
7843 return;
7844 /* -q turns off -x and -v just when executing init files */
7845 if (qflag) {
7846 if (xflag)
7847 xflag = 0, xflag_set = 1;
7848 if (vflag)
7849 vflag = 0, vflag_set = 1;
7850 }
7851 cmdloop(0);
7852 if (qflag) {
7853 if (xflag_set)
7854 xflag = 1;
7855 if (vflag_set)
7856 vflag = 1;
7857 }
7858 popfile();
7859}
7860
7861
7862
7863/*
7864 * Read a file containing shell functions.
7865 */
7866
7867static void
Eric Andersen2870d962001-07-02 17:27:21 +00007868readcmdfile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00007869{
7870 int fd;
7871
7872 INTOFF;
7873 if ((fd = open(name, O_RDONLY)) >= 0)
7874 setinputfd(fd, 1);
7875 else
7876 error("Can't open %s", name);
7877 INTON;
7878 cmdloop(0);
7879 popfile();
7880}
7881
7882
7883
7884/*
7885 * Take commands from a file. To be compatable we should do a path
7886 * search for the file, which is necessary to find sub-commands.
7887 */
7888
7889
Eric Andersen62483552001-07-10 06:09:16 +00007890static inline char *
Eric Andersencb57d552001-06-28 07:25:16 +00007891find_dot_file(mybasename)
7892 char *mybasename;
7893{
7894 char *fullname;
7895 const char *path = pathval();
7896 struct stat statb;
7897
7898 /* don't try this for absolute or relative paths */
7899 if (strchr(mybasename, '/'))
7900 return mybasename;
7901
7902 while ((fullname = padvance(&path, mybasename)) != NULL) {
7903 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
7904 /*
7905 * Don't bother freeing here, since it will
7906 * be freed by the caller.
7907 */
7908 return fullname;
7909 }
7910 stunalloc(fullname);
7911 }
7912
7913 /* not found in the PATH */
7914 error("%s: not found", mybasename);
7915 /* NOTREACHED */
7916}
7917
7918static int
7919dotcmd(argc, argv)
7920 int argc;
7921 char **argv;
7922{
7923 struct strlist *sp;
7924 exitstatus = 0;
7925
7926 for (sp = cmdenviron; sp ; sp = sp->next)
7927 setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
7928
Eric Andersen2870d962001-07-02 17:27:21 +00007929 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00007930 char *fullname;
7931 struct stackmark smark;
7932
7933 setstackmark(&smark);
7934 fullname = find_dot_file(argv[1]);
7935 setinputfile(fullname, 1);
7936 commandname = fullname;
7937 cmdloop(0);
7938 popfile();
7939 popstackmark(&smark);
7940 }
7941 return exitstatus;
7942}
7943
7944
7945static int
7946exitcmd(argc, argv)
7947 int argc;
7948 char **argv;
7949{
7950 if (stoppedjobs())
7951 return 0;
7952 if (argc > 1)
7953 exitstatus = number(argv[1]);
7954 else
7955 exitstatus = oexitstatus;
7956 exitshell(exitstatus);
7957 /* NOTREACHED */
7958}
Eric Andersen62483552001-07-10 06:09:16 +00007959
Eric Andersen2870d962001-07-02 17:27:21 +00007960static pointer
7961stalloc(int nbytes)
Eric Andersencb57d552001-06-28 07:25:16 +00007962{
7963 char *p;
7964
7965 nbytes = ALIGN(nbytes);
7966 if (nbytes > stacknleft) {
7967 int blocksize;
7968 struct stack_block *sp;
7969
7970 blocksize = nbytes;
7971 if (blocksize < MINSIZE)
7972 blocksize = MINSIZE;
7973 INTOFF;
7974 sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
7975 sp->prev = stackp;
7976 stacknxt = sp->space;
7977 stacknleft = blocksize;
7978 stackp = sp;
7979 INTON;
7980 }
7981 p = stacknxt;
7982 stacknxt += nbytes;
7983 stacknleft -= nbytes;
7984 return p;
7985}
7986
7987
7988static void
Eric Andersen2870d962001-07-02 17:27:21 +00007989stunalloc(pointer p)
7990{
Eric Andersencb57d552001-06-28 07:25:16 +00007991#ifdef DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +00007992 if (p == NULL) { /*DEBUG */
Eric Andersencb57d552001-06-28 07:25:16 +00007993 write(2, "stunalloc\n", 10);
7994 abort();
7995 }
7996#endif
7997 if (!(stacknxt >= (char *)p && (char *)p >= stackp->space)) {
7998 p = stackp->space;
7999 }
8000 stacknleft += stacknxt - (char *)p;
8001 stacknxt = p;
8002}
8003
8004
Eric Andersencb57d552001-06-28 07:25:16 +00008005static void
Eric Andersen2870d962001-07-02 17:27:21 +00008006setstackmark(struct stackmark *mark)
8007{
Eric Andersencb57d552001-06-28 07:25:16 +00008008 mark->stackp = stackp;
8009 mark->stacknxt = stacknxt;
8010 mark->stacknleft = stacknleft;
8011 mark->marknext = markp;
8012 markp = mark;
8013}
8014
8015
8016static void
Eric Andersen2870d962001-07-02 17:27:21 +00008017popstackmark(struct stackmark *mark)
8018{
Eric Andersencb57d552001-06-28 07:25:16 +00008019 struct stack_block *sp;
8020
8021 INTOFF;
8022 markp = mark->marknext;
8023 while (stackp != mark->stackp) {
8024 sp = stackp;
8025 stackp = sp->prev;
8026 ckfree(sp);
8027 }
8028 stacknxt = mark->stacknxt;
8029 stacknleft = mark->stacknleft;
8030 INTON;
8031}
8032
8033
8034/*
8035 * When the parser reads in a string, it wants to stick the string on the
8036 * stack and only adjust the stack pointer when it knows how big the
8037 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8038 * of space on top of the stack and stackblocklen returns the length of
8039 * this block. Growstackblock will grow this space by at least one byte,
8040 * possibly moving it (like realloc). Grabstackblock actually allocates the
8041 * part of the block that has been used.
8042 */
8043
8044static void
Eric Andersen2870d962001-07-02 17:27:21 +00008045growstackblock(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00008046 char *p;
8047 int newlen = ALIGN(stacknleft * 2 + 100);
8048 char *oldspace = stacknxt;
8049 int oldlen = stacknleft;
8050 struct stack_block *sp;
8051 struct stack_block *oldstackp;
8052
8053 if (stacknxt == stackp->space && stackp != &stackbase) {
8054 INTOFF;
8055 oldstackp = stackp;
8056 sp = stackp;
8057 stackp = sp->prev;
8058 sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen);
8059 sp->prev = stackp;
8060 stackp = sp;
8061 stacknxt = sp->space;
8062 stacknleft = newlen;
8063 {
8064 /* Stack marks pointing to the start of the old block
Eric Andersen2870d962001-07-02 17:27:21 +00008065 * must be relocated to point to the new block
Eric Andersencb57d552001-06-28 07:25:16 +00008066 */
8067 struct stackmark *xmark;
8068 xmark = markp;
8069 while (xmark != NULL && xmark->stackp == oldstackp) {
8070 xmark->stackp = stackp;
8071 xmark->stacknxt = stacknxt;
8072 xmark->stacknleft = stacknleft;
8073 xmark = xmark->marknext;
8074 }
8075 }
8076 INTON;
8077 } else {
8078 p = stalloc(newlen);
8079 memcpy(p, oldspace, oldlen);
Eric Andersen2870d962001-07-02 17:27:21 +00008080 stacknxt = p; /* free the space */
8081 stacknleft += newlen; /* we just allocated */
Eric Andersencb57d552001-06-28 07:25:16 +00008082 }
8083}
8084
8085
8086
Eric Andersen2870d962001-07-02 17:27:21 +00008087static inline void
8088grabstackblock(int len)
Eric Andersencb57d552001-06-28 07:25:16 +00008089{
8090 len = ALIGN(len);
8091 stacknxt += len;
8092 stacknleft -= len;
8093}
8094
8095
8096
8097/*
8098 * The following routines are somewhat easier to use that the above.
8099 * The user declares a variable of type STACKSTR, which may be declared
8100 * to be a register. The macro STARTSTACKSTR initializes things. Then
8101 * the user uses the macro STPUTC to add characters to the string. In
8102 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8103 * grown as necessary. When the user is done, she can just leave the
8104 * string there and refer to it using stackblock(). Or she can allocate
8105 * the space for it using grabstackstr(). If it is necessary to allow
8106 * someone else to use the stack temporarily and then continue to grow
8107 * the string, the user should use grabstack to allocate the space, and
8108 * then call ungrabstr(p) to return to the previous mode of operation.
8109 *
8110 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8111 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8112 * is space for at least one character.
8113 */
8114
8115
8116static char *
Eric Andersen2870d962001-07-02 17:27:21 +00008117growstackstr(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00008118 int len = stackblocksize();
8119 if (herefd >= 0 && len >= 1024) {
8120 xwrite(herefd, stackblock(), len);
8121 sstrnleft = len - 1;
8122 return stackblock();
8123 }
8124 growstackblock();
8125 sstrnleft = stackblocksize() - len - 1;
8126 return stackblock() + len;
8127}
8128
8129
8130/*
8131 * Called from CHECKSTRSPACE.
8132 */
8133
8134static char *
8135makestrspace(size_t newlen) {
8136 int len = stackblocksize() - sstrnleft;
8137 do {
8138 growstackblock();
8139 sstrnleft = stackblocksize() - len;
8140 } while (sstrnleft < newlen);
8141 return stackblock() + len;
8142}
8143
8144
8145
8146static void
Eric Andersen2870d962001-07-02 17:27:21 +00008147ungrabstackstr(char *s, char *p)
8148{
Eric Andersencb57d552001-06-28 07:25:16 +00008149 stacknleft += stacknxt - s;
8150 stacknxt = s;
8151 sstrnleft = stacknleft - (p - s);
8152}
Eric Andersencb57d552001-06-28 07:25:16 +00008153/*
8154 * Miscelaneous builtins.
8155 */
8156
8157
8158#undef rflag
8159
Eric Andersen62483552001-07-10 06:09:16 +00008160//#ifdef __GLIBC__
Eric Andersen2870d962001-07-02 17:27:21 +00008161static mode_t getmode(const void *, mode_t);
Eric Andersencb57d552001-06-28 07:25:16 +00008162static void *setmode(const char *);
Eric Andersen62483552001-07-10 06:09:16 +00008163//#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008164
8165#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersen62483552001-07-10 06:09:16 +00008166typedef long rlim_t;
Eric Andersencb57d552001-06-28 07:25:16 +00008167#endif
8168
8169
8170
8171/*
8172 * The read builtin. The -e option causes backslashes to escape the
8173 * following character.
8174 *
8175 * This uses unbuffered input, which may be avoidable in some cases.
8176 */
8177
8178static int
8179readcmd(argc, argv)
8180 int argc;
8181 char **argv;
8182{
8183 char **ap;
8184 int backslash;
8185 char c;
8186 int rflag;
8187 char *prompt;
8188 const char *ifs;
8189 char *p;
8190 int startword;
8191 int status;
8192 int i;
8193
8194 rflag = 0;
8195 prompt = NULL;
8196 while ((i = nextopt("p:r")) != '\0') {
8197 if (i == 'p')
8198 prompt = optionarg;
8199 else
8200 rflag = 1;
8201 }
8202 if (prompt && isatty(0)) {
8203 putprompt(prompt);
8204 flushall();
8205 }
8206 if (*(ap = argptr) == NULL)
8207 error("arg count");
8208 if ((ifs = bltinlookup("IFS")) == NULL)
8209 ifs = defifs;
8210 status = 0;
8211 startword = 1;
8212 backslash = 0;
8213 STARTSTACKSTR(p);
8214 for (;;) {
8215 if (read(0, &c, 1) != 1) {
8216 status = 1;
8217 break;
8218 }
8219 if (c == '\0')
8220 continue;
8221 if (backslash) {
8222 backslash = 0;
8223 if (c != '\n')
8224 STPUTC(c, p);
8225 continue;
8226 }
8227 if (!rflag && c == '\\') {
8228 backslash++;
8229 continue;
8230 }
8231 if (c == '\n')
8232 break;
8233 if (startword && *ifs == ' ' && strchr(ifs, c)) {
8234 continue;
8235 }
8236 startword = 0;
8237 if (backslash && c == '\\') {
8238 if (read(0, &c, 1) != 1) {
8239 status = 1;
8240 break;
8241 }
8242 STPUTC(c, p);
8243 } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
8244 STACKSTRNUL(p);
8245 setvar(*ap, stackblock(), 0);
8246 ap++;
8247 startword = 1;
8248 STARTSTACKSTR(p);
8249 } else {
8250 STPUTC(c, p);
8251 }
8252 }
8253 STACKSTRNUL(p);
8254 /* Remove trailing blanks */
8255 while (stackblock() <= --p && strchr(ifs, *p) != NULL)
8256 *p = '\0';
8257 setvar(*ap, stackblock(), 0);
8258 while (*++ap != NULL)
8259 setvar(*ap, nullstr, 0);
8260 return status;
8261}
8262
8263
8264
8265static int
8266umaskcmd(argc, argv)
8267 int argc;
8268 char **argv;
8269{
8270 char *ap;
8271 int mask;
8272 int i;
8273 int symbolic_mode = 0;
8274
Eric Andersen62483552001-07-10 06:09:16 +00008275 while (nextopt("S") != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00008276 symbolic_mode = 1;
8277 }
8278
8279 INTOFF;
8280 mask = umask(0);
8281 umask(mask);
8282 INTON;
8283
8284 if ((ap = *argptr) == NULL) {
8285 if (symbolic_mode) {
8286 char u[4], g[4], o[4];
8287
8288 i = 0;
8289 if ((mask & S_IRUSR) == 0)
8290 u[i++] = 'r';
8291 if ((mask & S_IWUSR) == 0)
8292 u[i++] = 'w';
8293 if ((mask & S_IXUSR) == 0)
8294 u[i++] = 'x';
8295 u[i] = '\0';
8296
8297 i = 0;
8298 if ((mask & S_IRGRP) == 0)
8299 g[i++] = 'r';
8300 if ((mask & S_IWGRP) == 0)
8301 g[i++] = 'w';
8302 if ((mask & S_IXGRP) == 0)
8303 g[i++] = 'x';
8304 g[i] = '\0';
8305
8306 i = 0;
8307 if ((mask & S_IROTH) == 0)
8308 o[i++] = 'r';
8309 if ((mask & S_IWOTH) == 0)
8310 o[i++] = 'w';
8311 if ((mask & S_IXOTH) == 0)
8312 o[i++] = 'x';
8313 o[i] = '\0';
8314
Eric Andersen62483552001-07-10 06:09:16 +00008315 printf("u=%s,g=%s,o=%s\n", u, g, o);
Eric Andersencb57d552001-06-28 07:25:16 +00008316 } else {
Eric Andersen62483552001-07-10 06:09:16 +00008317 printf("%.4o\n", mask);
Eric Andersencb57d552001-06-28 07:25:16 +00008318 }
8319 } else {
Eric Andersen62483552001-07-10 06:09:16 +00008320 if (is_digit((unsigned char)*ap)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008321 mask = 0;
8322 do {
8323 if (*ap >= '8' || *ap < '0')
8324 error("Illegal number: %s", argv[1]);
8325 mask = (mask << 3) + (*ap - '0');
8326 } while (*++ap != '\0');
8327 umask(mask);
8328 } else {
8329 void *set;
8330
8331 INTOFF;
8332 if ((set = setmode(ap)) != 0) {
8333 mask = getmode(set, ~mask & 0777);
8334 ckfree(set);
8335 }
8336 INTON;
8337 if (!set)
8338 error("Illegal mode: %s", ap);
8339
8340 umask(~mask & 0777);
8341 }
8342 }
8343 return 0;
8344}
8345
8346/*
8347 * ulimit builtin
8348 *
8349 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
8350 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
8351 * ash by J.T. Conklin.
8352 *
8353 * Public domain.
8354 */
8355
8356struct limits {
8357 const char *name;
Eric Andersen2870d962001-07-02 17:27:21 +00008358 int cmd;
8359 int factor; /* multiply by to get rlim_{cur,max} values */
8360 char option;
Eric Andersencb57d552001-06-28 07:25:16 +00008361};
8362
8363static const struct limits limits[] = {
8364#ifdef RLIMIT_CPU
Eric Andersen2870d962001-07-02 17:27:21 +00008365 { "time(seconds)", RLIMIT_CPU, 1, 't' },
Eric Andersencb57d552001-06-28 07:25:16 +00008366#endif
8367#ifdef RLIMIT_FSIZE
Eric Andersen2870d962001-07-02 17:27:21 +00008368 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
Eric Andersencb57d552001-06-28 07:25:16 +00008369#endif
8370#ifdef RLIMIT_DATA
Eric Andersen2870d962001-07-02 17:27:21 +00008371 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
Eric Andersencb57d552001-06-28 07:25:16 +00008372#endif
8373#ifdef RLIMIT_STACK
Eric Andersen2870d962001-07-02 17:27:21 +00008374 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
Eric Andersencb57d552001-06-28 07:25:16 +00008375#endif
8376#ifdef RLIMIT_CORE
Eric Andersen2870d962001-07-02 17:27:21 +00008377 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
Eric Andersencb57d552001-06-28 07:25:16 +00008378#endif
8379#ifdef RLIMIT_RSS
Eric Andersen2870d962001-07-02 17:27:21 +00008380 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
Eric Andersencb57d552001-06-28 07:25:16 +00008381#endif
8382#ifdef RLIMIT_MEMLOCK
Eric Andersen2870d962001-07-02 17:27:21 +00008383 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
Eric Andersencb57d552001-06-28 07:25:16 +00008384#endif
8385#ifdef RLIMIT_NPROC
Eric Andersen2870d962001-07-02 17:27:21 +00008386 { "process(processes)", RLIMIT_NPROC, 1, 'p' },
Eric Andersencb57d552001-06-28 07:25:16 +00008387#endif
8388#ifdef RLIMIT_NOFILE
Eric Andersen2870d962001-07-02 17:27:21 +00008389 { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
Eric Andersencb57d552001-06-28 07:25:16 +00008390#endif
8391#ifdef RLIMIT_VMEM
Eric Andersen2870d962001-07-02 17:27:21 +00008392 { "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' },
Eric Andersencb57d552001-06-28 07:25:16 +00008393#endif
8394#ifdef RLIMIT_SWAP
Eric Andersen2870d962001-07-02 17:27:21 +00008395 { "swap(kbytes)", RLIMIT_SWAP, 1024, 'w' },
Eric Andersencb57d552001-06-28 07:25:16 +00008396#endif
Eric Andersen2870d962001-07-02 17:27:21 +00008397 { (char *) 0, 0, 0, '\0' }
Eric Andersencb57d552001-06-28 07:25:16 +00008398};
8399
8400static int
8401ulimitcmd(argc, argv)
8402 int argc;
8403 char **argv;
8404{
Eric Andersen2870d962001-07-02 17:27:21 +00008405 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00008406 rlim_t val = 0;
8407 enum { SOFT = 0x1, HARD = 0x2 }
8408 how = SOFT | HARD;
Eric Andersen2870d962001-07-02 17:27:21 +00008409 const struct limits *l;
8410 int set, all = 0;
8411 int optc, what;
8412 struct rlimit limit;
Eric Andersencb57d552001-06-28 07:25:16 +00008413
8414 what = 'f';
8415 while ((optc = nextopt("HSatfdsmcnpl")) != '\0')
8416 switch (optc) {
8417 case 'H':
8418 how = HARD;
8419 break;
8420 case 'S':
8421 how = SOFT;
8422 break;
8423 case 'a':
8424 all = 1;
8425 break;
8426 default:
8427 what = optc;
8428 }
8429
8430 for (l = limits; l->name && l->option != what; l++)
8431 ;
8432 if (!l->name)
8433 error("internal error (%c)", what);
8434
8435 set = *argptr ? 1 : 0;
8436 if (set) {
8437 char *p = *argptr;
8438
8439 if (all || argptr[1])
8440 error("too many arguments");
8441 if (strcmp(p, "unlimited") == 0)
8442 val = RLIM_INFINITY;
8443 else {
8444 val = (rlim_t) 0;
8445
8446 while ((c = *p++) >= '0' && c <= '9')
8447 {
8448 val = (val * 10) + (long)(c - '0');
8449 if (val < (rlim_t) 0)
8450 break;
8451 }
8452 if (c)
8453 error("bad number");
8454 val *= l->factor;
8455 }
8456 }
8457 if (all) {
8458 for (l = limits; l->name; l++) {
8459 getrlimit(l->cmd, &limit);
8460 if (how & SOFT)
8461 val = limit.rlim_cur;
8462 else if (how & HARD)
8463 val = limit.rlim_max;
8464
Eric Andersen62483552001-07-10 06:09:16 +00008465 printf("%-20s ", l->name);
Eric Andersencb57d552001-06-28 07:25:16 +00008466 if (val == RLIM_INFINITY)
Eric Andersen62483552001-07-10 06:09:16 +00008467 printf("unlimited\n");
Eric Andersencb57d552001-06-28 07:25:16 +00008468 else
8469 {
8470 val /= l->factor;
Eric Andersen62483552001-07-10 06:09:16 +00008471 printf("%lld\n", (long long) val);
Eric Andersencb57d552001-06-28 07:25:16 +00008472 }
8473 }
8474 return 0;
8475 }
8476
8477 getrlimit(l->cmd, &limit);
8478 if (set) {
8479 if (how & HARD)
8480 limit.rlim_max = val;
8481 if (how & SOFT)
8482 limit.rlim_cur = val;
8483 if (setrlimit(l->cmd, &limit) < 0)
Eric Andersen2870d962001-07-02 17:27:21 +00008484 error("error setting limit (%m)");
Eric Andersencb57d552001-06-28 07:25:16 +00008485 } else {
8486 if (how & SOFT)
8487 val = limit.rlim_cur;
8488 else if (how & HARD)
8489 val = limit.rlim_max;
8490
8491 if (val == RLIM_INFINITY)
Eric Andersen62483552001-07-10 06:09:16 +00008492 printf("unlimited\n");
Eric Andersencb57d552001-06-28 07:25:16 +00008493 else
8494 {
8495 val /= l->factor;
Eric Andersen62483552001-07-10 06:09:16 +00008496 printf("%lld\n", (long long) val);
Eric Andersencb57d552001-06-28 07:25:16 +00008497 }
8498 }
8499 return 0;
8500}
Eric Andersencb57d552001-06-28 07:25:16 +00008501/*
8502 * prefix -- see if pfx is a prefix of string.
8503 */
8504
8505static int
Eric Andersen62483552001-07-10 06:09:16 +00008506prefix(char const *pfx, char const *string)
8507{
Eric Andersencb57d552001-06-28 07:25:16 +00008508 while (*pfx) {
8509 if (*pfx++ != *string++)
8510 return 0;
8511 }
8512 return 1;
8513}
8514
Eric Andersen2870d962001-07-02 17:27:21 +00008515/*
8516 * Return true if s is a string of digits, and save munber in intptr
8517 * nagative is bad
8518 */
8519
8520static int
8521is_number(const char *p, int *intptr)
8522{
8523 int ret = 0;
8524
8525 do {
8526 if (! is_digit(*p))
8527 return 0;
8528 ret *= 10;
8529 ret += digit_val(*p);
8530 p++;
8531 } while (*p != '\0');
8532
8533 *intptr = ret;
8534 return 1;
8535}
Eric Andersencb57d552001-06-28 07:25:16 +00008536
8537/*
8538 * Convert a string of digits to an integer, printing an error message on
8539 * failure.
8540 */
8541
8542static int
Eric Andersen2870d962001-07-02 17:27:21 +00008543number(const char *s)
8544{
8545 int i;
8546 if (! is_number(s, &i))
Eric Andersencb57d552001-06-28 07:25:16 +00008547 error("Illegal number: %s", s);
Eric Andersen2870d962001-07-02 17:27:21 +00008548 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00008549}
8550
Eric Andersencb57d552001-06-28 07:25:16 +00008551/*
8552 * Produce a possibly single quoted string suitable as input to the shell.
8553 * The return string is allocated on the stack.
8554 */
8555
8556static char *
8557single_quote(const char *s) {
8558 char *p;
8559
8560 STARTSTACKSTR(p);
8561
8562 do {
8563 char *q = p;
8564 size_t len1, len1p, len2, len2p;
8565
8566 len1 = strcspn(s, "'");
8567 len2 = strspn(s + len1, "'");
8568
8569 len1p = len1 ? len1 + 2 : len1;
8570 switch (len2) {
8571 case 0:
8572 len2p = 0;
8573 break;
8574 case 1:
8575 len2p = 2;
8576 break;
8577 default:
8578 len2p = len2 + 2;
8579 }
8580
8581 CHECKSTRSPACE(len1p + len2p + 1, p);
8582
8583 if (len1) {
8584 *p = '\'';
Eric Andersencb57d552001-06-28 07:25:16 +00008585 q = p + 1 + len1;
8586 memcpy(p + 1, s, len1);
Eric Andersencb57d552001-06-28 07:25:16 +00008587 *q++ = '\'';
8588 s += len1;
8589 }
8590
8591 switch (len2) {
8592 case 0:
8593 break;
8594 case 1:
8595 *q++ = '\\';
8596 *q = '\'';
8597 s++;
8598 break;
8599 default:
8600 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008601 q += 1 + len2;
8602 memcpy(q + 1, s, len2);
8603 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008604 s += len2;
8605 }
8606
8607 STADJUST(len1p + len2p, p);
8608 } while (*s);
8609
8610 USTPUTC(0, p);
8611
8612 return grabstackstr(p);
8613}
8614
8615/*
8616 * Like strdup but works with the ash stack.
8617 */
8618
8619static char *
8620sstrdup(const char *p)
8621{
8622 size_t len = strlen(p) + 1;
8623 return memcpy(stalloc(len), p, len);
8624}
8625
Eric Andersencb57d552001-06-28 07:25:16 +00008626
8627/*
Eric Andersencb57d552001-06-28 07:25:16 +00008628 * Routine for dealing with parsed shell commands.
8629 */
8630
8631
Eric Andersen62483552001-07-10 06:09:16 +00008632static void sizenodelist (const struct nodelist *);
8633static struct nodelist *copynodelist (const struct nodelist *);
8634static char *nodesavestr (const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00008635
8636static void
Eric Andersen62483552001-07-10 06:09:16 +00008637calcsize(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008638{
8639 if (n == NULL)
8640 return;
8641 funcblocksize += nodesize[n->type];
8642 switch (n->type) {
8643 case NSEMI:
8644 case NAND:
8645 case NOR:
8646 case NWHILE:
8647 case NUNTIL:
8648 calcsize(n->nbinary.ch2);
8649 calcsize(n->nbinary.ch1);
8650 break;
8651 case NCMD:
8652 calcsize(n->ncmd.redirect);
8653 calcsize(n->ncmd.args);
8654 calcsize(n->ncmd.assign);
8655 break;
8656 case NPIPE:
8657 sizenodelist(n->npipe.cmdlist);
8658 break;
8659 case NREDIR:
8660 case NBACKGND:
8661 case NSUBSHELL:
8662 calcsize(n->nredir.redirect);
8663 calcsize(n->nredir.n);
8664 break;
8665 case NIF:
8666 calcsize(n->nif.elsepart);
8667 calcsize(n->nif.ifpart);
8668 calcsize(n->nif.test);
8669 break;
8670 case NFOR:
8671 funcstringsize += strlen(n->nfor.var) + 1;
8672 calcsize(n->nfor.body);
8673 calcsize(n->nfor.args);
8674 break;
8675 case NCASE:
8676 calcsize(n->ncase.cases);
8677 calcsize(n->ncase.expr);
8678 break;
8679 case NCLIST:
8680 calcsize(n->nclist.body);
8681 calcsize(n->nclist.pattern);
8682 calcsize(n->nclist.next);
8683 break;
8684 case NDEFUN:
8685 case NARG:
8686 sizenodelist(n->narg.backquote);
8687 funcstringsize += strlen(n->narg.text) + 1;
8688 calcsize(n->narg.next);
8689 break;
8690 case NTO:
8691 case NFROM:
8692 case NFROMTO:
8693 case NAPPEND:
8694 case NTOOV:
8695 calcsize(n->nfile.fname);
8696 calcsize(n->nfile.next);
8697 break;
8698 case NTOFD:
8699 case NFROMFD:
8700 calcsize(n->ndup.vname);
8701 calcsize(n->ndup.next);
8702 break;
8703 case NHERE:
8704 case NXHERE:
8705 calcsize(n->nhere.doc);
8706 calcsize(n->nhere.next);
8707 break;
8708 case NNOT:
8709 calcsize(n->nnot.com);
8710 break;
8711 };
8712}
8713
Eric Andersencb57d552001-06-28 07:25:16 +00008714static void
Eric Andersen62483552001-07-10 06:09:16 +00008715sizenodelist(const struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008716{
8717 while (lp) {
8718 funcblocksize += ALIGN(sizeof(struct nodelist));
8719 calcsize(lp->n);
8720 lp = lp->next;
8721 }
8722}
8723
8724
Eric Andersencb57d552001-06-28 07:25:16 +00008725static union node *
Eric Andersen62483552001-07-10 06:09:16 +00008726copynode(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008727{
Eric Andersen62483552001-07-10 06:09:16 +00008728 union node *new;
Eric Andersencb57d552001-06-28 07:25:16 +00008729
8730 if (n == NULL)
8731 return NULL;
8732 new = funcblock;
8733 funcblock = (char *) funcblock + nodesize[n->type];
8734 switch (n->type) {
8735 case NSEMI:
8736 case NAND:
8737 case NOR:
8738 case NWHILE:
8739 case NUNTIL:
8740 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8741 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8742 break;
8743 case NCMD:
8744 new->ncmd.redirect = copynode(n->ncmd.redirect);
8745 new->ncmd.args = copynode(n->ncmd.args);
8746 new->ncmd.assign = copynode(n->ncmd.assign);
8747 new->ncmd.backgnd = n->ncmd.backgnd;
8748 break;
8749 case NPIPE:
8750 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8751 new->npipe.backgnd = n->npipe.backgnd;
8752 break;
8753 case NREDIR:
8754 case NBACKGND:
8755 case NSUBSHELL:
8756 new->nredir.redirect = copynode(n->nredir.redirect);
8757 new->nredir.n = copynode(n->nredir.n);
8758 break;
8759 case NIF:
8760 new->nif.elsepart = copynode(n->nif.elsepart);
8761 new->nif.ifpart = copynode(n->nif.ifpart);
8762 new->nif.test = copynode(n->nif.test);
8763 break;
8764 case NFOR:
8765 new->nfor.var = nodesavestr(n->nfor.var);
8766 new->nfor.body = copynode(n->nfor.body);
8767 new->nfor.args = copynode(n->nfor.args);
8768 break;
8769 case NCASE:
8770 new->ncase.cases = copynode(n->ncase.cases);
8771 new->ncase.expr = copynode(n->ncase.expr);
8772 break;
8773 case NCLIST:
8774 new->nclist.body = copynode(n->nclist.body);
8775 new->nclist.pattern = copynode(n->nclist.pattern);
8776 new->nclist.next = copynode(n->nclist.next);
8777 break;
8778 case NDEFUN:
8779 case NARG:
8780 new->narg.backquote = copynodelist(n->narg.backquote);
8781 new->narg.text = nodesavestr(n->narg.text);
8782 new->narg.next = copynode(n->narg.next);
8783 break;
8784 case NTO:
8785 case NFROM:
8786 case NFROMTO:
8787 case NAPPEND:
8788 case NTOOV:
8789 new->nfile.fname = copynode(n->nfile.fname);
8790 new->nfile.fd = n->nfile.fd;
8791 new->nfile.next = copynode(n->nfile.next);
8792 break;
8793 case NTOFD:
8794 case NFROMFD:
8795 new->ndup.vname = copynode(n->ndup.vname);
8796 new->ndup.dupfd = n->ndup.dupfd;
8797 new->ndup.fd = n->ndup.fd;
8798 new->ndup.next = copynode(n->ndup.next);
8799 break;
8800 case NHERE:
8801 case NXHERE:
8802 new->nhere.doc = copynode(n->nhere.doc);
8803 new->nhere.fd = n->nhere.fd;
8804 new->nhere.next = copynode(n->nhere.next);
8805 break;
8806 case NNOT:
8807 new->nnot.com = copynode(n->nnot.com);
8808 break;
8809 };
8810 new->type = n->type;
Eric Andersen62483552001-07-10 06:09:16 +00008811 return new;
Eric Andersencb57d552001-06-28 07:25:16 +00008812}
8813
8814
8815static struct nodelist *
Eric Andersen62483552001-07-10 06:09:16 +00008816copynodelist(const struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008817{
8818 struct nodelist *start;
8819 struct nodelist **lpp;
8820
8821 lpp = &start;
8822 while (lp) {
8823 *lpp = funcblock;
8824 funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist));
8825 (*lpp)->n = copynode(lp->n);
8826 lp = lp->next;
8827 lpp = &(*lpp)->next;
8828 }
8829 *lpp = NULL;
8830 return start;
8831}
8832
8833
Eric Andersencb57d552001-06-28 07:25:16 +00008834static char *
Eric Andersen62483552001-07-10 06:09:16 +00008835nodesavestr(const char *s)
Eric Andersencb57d552001-06-28 07:25:16 +00008836{
8837#ifdef _GNU_SOURCE
8838 char *rtn = funcstring;
8839
8840 funcstring = stpcpy(funcstring, s) + 1;
8841 return rtn;
8842#else
Eric Andersen62483552001-07-10 06:09:16 +00008843 const char *p = s;
8844 char *q = funcstring;
Eric Andersencb57d552001-06-28 07:25:16 +00008845 char *rtn = funcstring;
8846
8847 while ((*q++ = *p++) != '\0')
8848 continue;
8849 funcstring = q;
8850 return rtn;
8851#endif
8852}
8853
Eric Andersencb57d552001-06-28 07:25:16 +00008854#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00008855static int getopts (char *, char *, char **, int *, int *);
Eric Andersencb57d552001-06-28 07:25:16 +00008856#endif
8857
8858
8859/*
8860 * Process the shell command line arguments.
8861 */
8862
8863static void
8864procargs(argc, argv)
8865 int argc;
8866 char **argv;
8867{
8868 int i;
8869
8870 argptr = argv;
8871 if (argc > 0)
8872 argptr++;
8873 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00008874 optent_val(i) = 2;
Eric Andersencb57d552001-06-28 07:25:16 +00008875 options(1);
8876 if (*argptr == NULL && minusc == NULL)
8877 sflag = 1;
8878 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8879 iflag = 1;
8880 if (mflag == 2)
8881 mflag = iflag;
8882 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00008883 if (optent_val(i) == 2)
8884 optent_val(i) = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008885 arg0 = argv[0];
8886 if (sflag == 0 && minusc == NULL) {
8887 commandname = argv[0];
8888 arg0 = *argptr++;
8889 setinputfile(arg0, 0);
8890 commandname = arg0;
8891 }
8892 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8893 if (argptr && minusc && *argptr)
Eric Andersen2870d962001-07-02 17:27:21 +00008894 arg0 = *argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00008895
8896 shellparam.p = argptr;
8897 shellparam.optind = 1;
8898 shellparam.optoff = -1;
8899 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8900 while (*argptr) {
8901 shellparam.nparam++;
8902 argptr++;
8903 }
8904 optschanged();
8905}
8906
8907
Eric Andersencb57d552001-06-28 07:25:16 +00008908
8909/*
8910 * Process shell options. The global variable argptr contains a pointer
8911 * to the argument list; we advance it past the options.
8912 */
8913
Eric Andersen62483552001-07-10 06:09:16 +00008914static inline void
8915minus_o(const char *name, int val)
8916{
8917 int i;
8918
8919 if (name == NULL) {
8920 out1str("Current option settings\n");
8921 for (i = 0; i < NOPTS; i++)
8922 printf("%-16s%s\n", optent_name(optlist[i]),
8923 optent_val(i) ? "on" : "off");
8924 } else {
8925 for (i = 0; i < NOPTS; i++)
8926 if (equal(name, optent_name(optlist[i]))) {
8927 setoption(optent_letter(optlist[i]), val);
8928 return;
8929 }
8930 error("Illegal option -o %s", name);
8931 }
8932}
8933
8934
Eric Andersencb57d552001-06-28 07:25:16 +00008935static void
Eric Andersen62483552001-07-10 06:09:16 +00008936options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00008937{
8938 char *p;
8939 int val;
8940 int c;
8941
8942 if (cmdline)
8943 minusc = NULL;
8944 while ((p = *argptr) != NULL) {
8945 argptr++;
8946 if ((c = *p++) == '-') {
8947 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00008948 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8949 if (!cmdline) {
8950 /* "-" means turn off -x and -v */
8951 if (p[0] == '\0')
8952 xflag = vflag = 0;
8953 /* "--" means reset params */
8954 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00008955 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00008956 }
8957 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00008958 }
8959 } else if (c == '+') {
8960 val = 0;
8961 } else {
8962 argptr--;
8963 break;
8964 }
8965 while ((c = *p++) != '\0') {
8966 if (c == 'c' && cmdline) {
8967 char *q;
Eric Andersen2870d962001-07-02 17:27:21 +00008968#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */
Eric Andersencb57d552001-06-28 07:25:16 +00008969 if (*p == '\0')
8970#endif
8971 q = *argptr++;
8972 if (q == NULL || minusc != NULL)
8973 error("Bad -c option");
8974 minusc = q;
8975#ifdef NOHACK
8976 break;
8977#endif
8978 } else if (c == 'o') {
8979 minus_o(*argptr, val);
8980 if (*argptr)
8981 argptr++;
8982 } else {
8983 setoption(c, val);
8984 }
8985 }
8986 }
8987}
8988
Eric Andersencb57d552001-06-28 07:25:16 +00008989
8990static void
Eric Andersen2870d962001-07-02 17:27:21 +00008991setoption(int flag, int val)
8992{
Eric Andersencb57d552001-06-28 07:25:16 +00008993 int i;
8994
8995 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00008996 if (optent_letter(optlist[i]) == flag) {
8997 optent_val(i) = val;
Eric Andersencb57d552001-06-28 07:25:16 +00008998 if (val) {
8999 /* #%$ hack for ksh semantics */
9000 if (flag == 'V')
9001 Eflag = 0;
9002 else if (flag == 'E')
9003 Vflag = 0;
9004 }
9005 return;
9006 }
9007 error("Illegal option -%c", flag);
9008 /* NOTREACHED */
9009}
9010
9011
9012
Eric Andersencb57d552001-06-28 07:25:16 +00009013/*
9014 * Set the shell parameters.
9015 */
9016
9017static void
Eric Andersen2870d962001-07-02 17:27:21 +00009018setparam(char **argv)
9019{
Eric Andersencb57d552001-06-28 07:25:16 +00009020 char **newparam;
9021 char **ap;
9022 int nparam;
9023
9024 for (nparam = 0 ; argv[nparam] ; nparam++);
9025 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
9026 while (*argv) {
9027 *ap++ = savestr(*argv++);
9028 }
9029 *ap = NULL;
9030 freeparam(&shellparam);
9031 shellparam.malloc = 1;
9032 shellparam.nparam = nparam;
9033 shellparam.p = newparam;
9034 shellparam.optind = 1;
9035 shellparam.optoff = -1;
9036}
9037
9038
9039/*
9040 * Free the list of positional parameters.
9041 */
9042
9043static void
Eric Andersen2870d962001-07-02 17:27:21 +00009044freeparam(volatile struct shparam *param)
9045{
Eric Andersencb57d552001-06-28 07:25:16 +00009046 char **ap;
9047
9048 if (param->malloc) {
9049 for (ap = param->p ; *ap ; ap++)
9050 ckfree(*ap);
9051 ckfree(param->p);
9052 }
9053}
9054
9055
9056
9057/*
9058 * The shift builtin command.
9059 */
9060
9061static int
9062shiftcmd(argc, argv)
9063 int argc;
9064 char **argv;
9065{
9066 int n;
9067 char **ap1, **ap2;
9068
9069 n = 1;
9070 if (argc > 1)
9071 n = number(argv[1]);
9072 if (n > shellparam.nparam)
9073 error("can't shift that many");
9074 INTOFF;
9075 shellparam.nparam -= n;
9076 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
9077 if (shellparam.malloc)
9078 ckfree(*ap1);
9079 }
9080 ap2 = shellparam.p;
9081 while ((*ap2++ = *ap1++) != NULL);
9082 shellparam.optind = 1;
9083 shellparam.optoff = -1;
9084 INTON;
9085 return 0;
9086}
9087
9088
9089
9090/*
9091 * The set command builtin.
9092 */
9093
9094static int
9095setcmd(argc, argv)
9096 int argc;
9097 char **argv;
9098{
9099 if (argc == 1)
9100 return showvarscmd(argc, argv);
9101 INTOFF;
9102 options(0);
9103 optschanged();
9104 if (*argptr != NULL) {
9105 setparam(argptr);
9106 }
9107 INTON;
9108 return 0;
9109}
9110
9111
9112static void
Eric Andersen2870d962001-07-02 17:27:21 +00009113getoptsreset(const char *value)
Eric Andersencb57d552001-06-28 07:25:16 +00009114{
9115 shellparam.optind = number(value);
9116 shellparam.optoff = -1;
9117}
9118
Eric Andersen2870d962001-07-02 17:27:21 +00009119#ifdef BB_LOCALE_SUPPORT
9120static void change_lc_all(const char *value)
9121{
9122 if(value != 0 && *value != 0)
9123 setlocale(LC_ALL, value);
9124}
9125
9126static void change_lc_ctype(const char *value)
9127{
9128 if(value != 0 && *value != 0)
9129 setlocale(LC_CTYPE, value);
9130}
9131
9132#endif
9133
Eric Andersencb57d552001-06-28 07:25:16 +00009134#ifdef ASH_GETOPTS
9135/*
9136 * The getopts builtin. Shellparam.optnext points to the next argument
9137 * to be processed. Shellparam.optptr points to the next character to
9138 * be processed in the current argument. If shellparam.optnext is NULL,
9139 * then it's the first time getopts has been called.
9140 */
9141
9142static int
9143getoptscmd(argc, argv)
9144 int argc;
9145 char **argv;
9146{
9147 char **optbase;
9148
9149 if (argc < 3)
9150 error("Usage: getopts optstring var [arg]");
9151 else if (argc == 3) {
9152 optbase = shellparam.p;
9153 if (shellparam.optind > shellparam.nparam + 1) {
9154 shellparam.optind = 1;
9155 shellparam.optoff = -1;
9156 }
9157 }
9158 else {
9159 optbase = &argv[3];
9160 if (shellparam.optind > argc - 2) {
9161 shellparam.optind = 1;
9162 shellparam.optoff = -1;
9163 }
9164 }
9165
9166 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9167 &shellparam.optoff);
9168}
9169
9170/*
9171 * Safe version of setvar, returns 1 on success 0 on failure.
9172 */
9173
9174static int
9175setvarsafe(name, val, flags)
9176 const char *name, *val;
9177 int flags;
9178{
9179 struct jmploc jmploc;
9180 struct jmploc *volatile savehandler = handler;
9181 int err = 0;
9182#ifdef __GNUC__
9183 (void) &err;
9184#endif
9185
9186 if (setjmp(jmploc.loc))
9187 err = 1;
9188 else {
9189 handler = &jmploc;
9190 setvar(name, val, flags);
9191 }
9192 handler = savehandler;
9193 return err;
9194}
9195
9196static int
9197getopts(optstr, optvar, optfirst, myoptind, optoff)
9198 char *optstr;
9199 char *optvar;
9200 char **optfirst;
9201 int *myoptind;
9202 int *optoff;
9203{
9204 char *p, *q;
9205 char c = '?';
9206 int done = 0;
9207 int err = 0;
9208 char s[10];
9209 char **optnext = optfirst + *myoptind - 1;
9210
9211 if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
9212 strlen(*(optnext - 1)) < *optoff)
9213 p = NULL;
9214 else
9215 p = *(optnext - 1) + *optoff;
9216 if (p == NULL || *p == '\0') {
9217 /* Current word is done, advance */
9218 if (optnext == NULL)
9219 return 1;
9220 p = *optnext;
9221 if (p == NULL || *p != '-' || *++p == '\0') {
9222atend:
9223 *myoptind = optnext - optfirst + 1;
9224 p = NULL;
9225 done = 1;
9226 goto out;
9227 }
9228 optnext++;
Eric Andersen2870d962001-07-02 17:27:21 +00009229 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009230 goto atend;
9231 }
9232
9233 c = *p++;
9234 for (q = optstr; *q != c; ) {
9235 if (*q == '\0') {
9236 if (optstr[0] == ':') {
9237 s[0] = c;
9238 s[1] = '\0';
9239 err |= setvarsafe("OPTARG", s, 0);
9240 }
9241 else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009242 out2fmt("Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009243 (void) unsetvar("OPTARG");
9244 }
9245 c = '?';
9246 goto bad;
9247 }
9248 if (*++q == ':')
9249 q++;
9250 }
9251
9252 if (*++q == ':') {
9253 if (*p == '\0' && (p = *optnext) == NULL) {
9254 if (optstr[0] == ':') {
9255 s[0] = c;
9256 s[1] = '\0';
9257 err |= setvarsafe("OPTARG", s, 0);
9258 c = ':';
9259 }
9260 else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009261 out2fmt("No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009262 (void) unsetvar("OPTARG");
9263 c = '?';
9264 }
9265 goto bad;
9266 }
9267
9268 if (p == *optnext)
9269 optnext++;
9270 setvarsafe("OPTARG", p, 0);
9271 p = NULL;
9272 }
9273 else
9274 setvarsafe("OPTARG", "", 0);
9275 *myoptind = optnext - optfirst + 1;
9276 goto out;
9277
9278bad:
9279 *myoptind = 1;
9280 p = NULL;
9281out:
9282 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersen3102ac42001-07-06 04:26:23 +00009283 snprintf(s, sizeof(s), "%d", *myoptind);
Eric Andersencb57d552001-06-28 07:25:16 +00009284 err |= setvarsafe("OPTIND", s, VNOFUNC);
9285 s[0] = c;
9286 s[1] = '\0';
9287 err |= setvarsafe(optvar, s, 0);
9288 if (err) {
9289 *myoptind = 1;
9290 *optoff = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00009291 exraise(EXERROR);
9292 }
9293 return done;
9294}
Eric Andersen2870d962001-07-02 17:27:21 +00009295#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009296
9297/*
9298 * XXX - should get rid of. have all builtins use getopt(3). the
9299 * library getopt must have the BSD extension static variable "optreset"
9300 * otherwise it can't be used within the shell safely.
9301 *
9302 * Standard option processing (a la getopt) for builtin routines. The
9303 * only argument that is passed to nextopt is the option string; the
9304 * other arguments are unnecessary. It return the character, or '\0' on
9305 * end of input.
9306 */
9307
9308static int
Eric Andersen62483552001-07-10 06:09:16 +00009309nextopt(const char *optstring)
9310{
Eric Andersencb57d552001-06-28 07:25:16 +00009311 char *p;
9312 const char *q;
9313 char c;
9314
9315 if ((p = optptr) == NULL || *p == '\0') {
9316 p = *argptr;
9317 if (p == NULL || *p != '-' || *++p == '\0')
9318 return '\0';
9319 argptr++;
Eric Andersen2870d962001-07-02 17:27:21 +00009320 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009321 return '\0';
9322 }
9323 c = *p++;
9324 for (q = optstring ; *q != c ; ) {
9325 if (*q == '\0')
9326 error("Illegal option -%c", c);
9327 if (*++q == ':')
9328 q++;
9329 }
9330 if (*++q == ':') {
9331 if (*p == '\0' && (p = *argptr++) == NULL)
9332 error("No arg for -%c option", c);
9333 optionarg = p;
9334 p = NULL;
9335 }
9336 optptr = p;
9337 return c;
9338}
9339
Eric Andersencb57d552001-06-28 07:25:16 +00009340static void
9341flushall() {
Eric Andersencb57d552001-06-28 07:25:16 +00009342 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009343 fflush(stdout);
Eric Andersencb57d552001-06-28 07:25:16 +00009344 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009345}
9346
9347
9348static void
Eric Andersen3102ac42001-07-06 04:26:23 +00009349out2fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009350{
9351 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00009352 va_start(ap, fmt);
Eric Andersen3102ac42001-07-06 04:26:23 +00009353 vfprintf(stderr, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009354 va_end(ap);
9355}
9356
Eric Andersencb57d552001-06-28 07:25:16 +00009357/*
9358 * Version of write which resumes after a signal is caught.
9359 */
9360
9361static int
Eric Andersen2870d962001-07-02 17:27:21 +00009362xwrite(int fd, const char *buf, int nbytes)
9363{
Eric Andersencb57d552001-06-28 07:25:16 +00009364 int ntry;
9365 int i;
9366 int n;
9367
9368 n = nbytes;
9369 ntry = 0;
9370 for (;;) {
9371 i = write(fd, buf, n);
9372 if (i > 0) {
9373 if ((n -= i) <= 0)
9374 return nbytes;
9375 buf += i;
9376 ntry = 0;
9377 } else if (i == 0) {
9378 if (++ntry > 10)
9379 return nbytes - n;
9380 } else if (errno != EINTR) {
9381 return -1;
9382 }
9383 }
9384}
9385
9386
Eric Andersencb57d552001-06-28 07:25:16 +00009387/*
9388 * Shell command parser.
9389 */
9390
9391#define EOFMARKLEN 79
9392
9393
9394
9395struct heredoc {
Eric Andersen2870d962001-07-02 17:27:21 +00009396 struct heredoc *next; /* next here document in list */
9397 union node *here; /* redirection node */
9398 char *eofmark; /* string indicating end of input */
9399 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009400};
9401
Eric Andersen2870d962001-07-02 17:27:21 +00009402static struct heredoc *heredoclist; /* list of here documents to read */
9403static int parsebackquote; /* nonzero if we are inside backquotes */
9404static int doprompt; /* if set, prompt the user */
9405static int needprompt; /* true if interactive and at start of line */
9406static int lasttoken; /* last token read */
Eric Andersencb57d552001-06-28 07:25:16 +00009407
Eric Andersen2870d962001-07-02 17:27:21 +00009408static char *wordtext; /* text of last word returned by readtoken */
Eric Andersencb57d552001-06-28 07:25:16 +00009409
Eric Andersen2870d962001-07-02 17:27:21 +00009410static struct nodelist *backquotelist;
9411static union node *redirnode;
Eric Andersen044228d2001-07-17 01:12:36 +00009412static struct heredoc *heredoc;
Eric Andersen2870d962001-07-02 17:27:21 +00009413static int quoteflag; /* set if (part of) last token was quoted */
9414static int startlinno; /* line # where last token started */
Eric Andersencb57d552001-06-28 07:25:16 +00009415
9416
Eric Andersen2870d962001-07-02 17:27:21 +00009417static union node *list (int);
9418static union node *andor (void);
9419static union node *pipeline (void);
9420static union node *command (void);
9421static union node *simplecmd (void);
9422static void parsefname (void);
9423static void parseheredoc (void);
9424static int peektoken (void);
9425static int readtoken (void);
9426static int xxreadtoken (void);
9427static int readtoken1 (int, char const *, char *, int);
9428static int noexpand (char *);
9429static void synexpect (int) __attribute__((noreturn));
9430static void synerror (const char *) __attribute__((noreturn));
9431static void setprompt (int);
Eric Andersencb57d552001-06-28 07:25:16 +00009432
9433
9434/*
9435 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9436 * valid parse tree indicating a blank line.)
9437 */
9438
Eric Andersen2870d962001-07-02 17:27:21 +00009439static union node *
Eric Andersencb57d552001-06-28 07:25:16 +00009440parsecmd(int interact)
9441{
9442 int t;
9443
9444 tokpushback = 0;
9445 doprompt = interact;
9446 if (doprompt)
9447 setprompt(1);
9448 else
9449 setprompt(0);
9450 needprompt = 0;
9451 t = readtoken();
9452 if (t == TEOF)
9453 return NEOF;
9454 if (t == TNL)
9455 return NULL;
9456 tokpushback++;
9457 return list(1);
9458}
9459
9460
9461static union node *
9462list(nlflag)
9463 int nlflag;
9464{
9465 union node *n1, *n2, *n3;
9466 int tok;
9467
9468 checkkwd = 2;
9469 if (nlflag == 0 && tokendlist[peektoken()])
9470 return NULL;
9471 n1 = NULL;
9472 for (;;) {
9473 n2 = andor();
9474 tok = readtoken();
9475 if (tok == TBACKGND) {
9476 if (n2->type == NCMD || n2->type == NPIPE) {
9477 n2->ncmd.backgnd = 1;
9478 } else if (n2->type == NREDIR) {
9479 n2->type = NBACKGND;
9480 } else {
9481 n3 = (union node *)stalloc(sizeof (struct nredir));
9482 n3->type = NBACKGND;
9483 n3->nredir.n = n2;
9484 n3->nredir.redirect = NULL;
9485 n2 = n3;
9486 }
9487 }
9488 if (n1 == NULL) {
9489 n1 = n2;
9490 }
9491 else {
9492 n3 = (union node *)stalloc(sizeof (struct nbinary));
9493 n3->type = NSEMI;
9494 n3->nbinary.ch1 = n1;
9495 n3->nbinary.ch2 = n2;
9496 n1 = n3;
9497 }
9498 switch (tok) {
9499 case TBACKGND:
9500 case TSEMI:
9501 tok = readtoken();
9502 /* fall through */
9503 case TNL:
9504 if (tok == TNL) {
9505 parseheredoc();
9506 if (nlflag)
9507 return n1;
9508 } else {
9509 tokpushback++;
9510 }
9511 checkkwd = 2;
9512 if (tokendlist[peektoken()])
9513 return n1;
9514 break;
9515 case TEOF:
9516 if (heredoclist)
9517 parseheredoc();
9518 else
Eric Andersen2870d962001-07-02 17:27:21 +00009519 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009520 return n1;
9521 default:
9522 if (nlflag)
9523 synexpect(-1);
9524 tokpushback++;
9525 return n1;
9526 }
9527 }
9528}
9529
9530
9531
9532static union node *
9533andor() {
9534 union node *n1, *n2, *n3;
9535 int t;
9536
9537 checkkwd = 1;
9538 n1 = pipeline();
9539 for (;;) {
9540 if ((t = readtoken()) == TAND) {
9541 t = NAND;
9542 } else if (t == TOR) {
9543 t = NOR;
9544 } else {
9545 tokpushback++;
9546 return n1;
9547 }
9548 checkkwd = 2;
9549 n2 = pipeline();
9550 n3 = (union node *)stalloc(sizeof (struct nbinary));
9551 n3->type = t;
9552 n3->nbinary.ch1 = n1;
9553 n3->nbinary.ch2 = n2;
9554 n1 = n3;
9555 }
9556}
9557
9558
9559
9560static union node *
9561pipeline() {
9562 union node *n1, *n2, *pipenode;
9563 struct nodelist *lp, *prev;
9564 int negate;
9565
9566 negate = 0;
9567 TRACE(("pipeline: entered\n"));
9568 if (readtoken() == TNOT) {
9569 negate = !negate;
9570 checkkwd = 1;
9571 } else
9572 tokpushback++;
9573 n1 = command();
9574 if (readtoken() == TPIPE) {
9575 pipenode = (union node *)stalloc(sizeof (struct npipe));
9576 pipenode->type = NPIPE;
9577 pipenode->npipe.backgnd = 0;
9578 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9579 pipenode->npipe.cmdlist = lp;
9580 lp->n = n1;
9581 do {
9582 prev = lp;
9583 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9584 checkkwd = 2;
9585 lp->n = command();
9586 prev->next = lp;
9587 } while (readtoken() == TPIPE);
9588 lp->next = NULL;
9589 n1 = pipenode;
9590 }
9591 tokpushback++;
9592 if (negate) {
9593 n2 = (union node *)stalloc(sizeof (struct nnot));
9594 n2->type = NNOT;
9595 n2->nnot.com = n1;
9596 return n2;
9597 } else
9598 return n1;
9599}
9600
9601
9602
9603static union node *
9604command() {
9605 union node *n1, *n2;
9606 union node *ap, **app;
9607 union node *cp, **cpp;
9608 union node *redir, **rpp;
9609 int t;
9610
9611 redir = NULL;
9612 n1 = NULL;
9613 rpp = &redir;
9614
9615 switch (readtoken()) {
9616 case TIF:
9617 n1 = (union node *)stalloc(sizeof (struct nif));
9618 n1->type = NIF;
9619 n1->nif.test = list(0);
9620 if (readtoken() != TTHEN)
9621 synexpect(TTHEN);
9622 n1->nif.ifpart = list(0);
9623 n2 = n1;
9624 while (readtoken() == TELIF) {
9625 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9626 n2 = n2->nif.elsepart;
9627 n2->type = NIF;
9628 n2->nif.test = list(0);
9629 if (readtoken() != TTHEN)
9630 synexpect(TTHEN);
9631 n2->nif.ifpart = list(0);
9632 }
9633 if (lasttoken == TELSE)
9634 n2->nif.elsepart = list(0);
9635 else {
9636 n2->nif.elsepart = NULL;
9637 tokpushback++;
9638 }
9639 if (readtoken() != TFI)
9640 synexpect(TFI);
9641 checkkwd = 1;
9642 break;
9643 case TWHILE:
9644 case TUNTIL: {
9645 int got;
9646 n1 = (union node *)stalloc(sizeof (struct nbinary));
9647 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9648 n1->nbinary.ch1 = list(0);
9649 if ((got=readtoken()) != TDO) {
9650TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
9651 synexpect(TDO);
9652 }
9653 n1->nbinary.ch2 = list(0);
9654 if (readtoken() != TDONE)
9655 synexpect(TDONE);
9656 checkkwd = 1;
9657 break;
9658 }
9659 case TFOR:
9660 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9661 synerror("Bad for loop variable");
9662 n1 = (union node *)stalloc(sizeof (struct nfor));
9663 n1->type = NFOR;
9664 n1->nfor.var = wordtext;
9665 checkkwd = 1;
9666 if (readtoken() == TIN) {
9667 app = &ap;
9668 while (readtoken() == TWORD) {
9669 n2 = (union node *)stalloc(sizeof (struct narg));
9670 n2->type = NARG;
9671 n2->narg.text = wordtext;
9672 n2->narg.backquote = backquotelist;
9673 *app = n2;
9674 app = &n2->narg.next;
9675 }
9676 *app = NULL;
9677 n1->nfor.args = ap;
9678 if (lasttoken != TNL && lasttoken != TSEMI)
9679 synexpect(-1);
9680 } else {
9681 static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
9682 '@', '=', '\0'};
9683 n2 = (union node *)stalloc(sizeof (struct narg));
9684 n2->type = NARG;
9685 n2->narg.text = argvars;
9686 n2->narg.backquote = NULL;
9687 n2->narg.next = NULL;
9688 n1->nfor.args = n2;
9689 /*
9690 * Newline or semicolon here is optional (but note
9691 * that the original Bourne shell only allowed NL).
9692 */
9693 if (lasttoken != TNL && lasttoken != TSEMI)
9694 tokpushback++;
9695 }
9696 checkkwd = 2;
9697 if (readtoken() != TDO)
9698 synexpect(TDO);
9699 n1->nfor.body = list(0);
9700 if (readtoken() != TDONE)
9701 synexpect(TDONE);
9702 checkkwd = 1;
9703 break;
9704 case TCASE:
9705 n1 = (union node *)stalloc(sizeof (struct ncase));
9706 n1->type = NCASE;
9707 if (readtoken() != TWORD)
9708 synexpect(TWORD);
9709 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9710 n2->type = NARG;
9711 n2->narg.text = wordtext;
9712 n2->narg.backquote = backquotelist;
9713 n2->narg.next = NULL;
9714 do {
9715 checkkwd = 1;
9716 } while (readtoken() == TNL);
9717 if (lasttoken != TIN)
9718 synerror("expecting \"in\"");
9719 cpp = &n1->ncase.cases;
9720 checkkwd = 2, readtoken();
9721 do {
9722 if (lasttoken == TLP)
9723 readtoken();
9724 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9725 cp->type = NCLIST;
9726 app = &cp->nclist.pattern;
9727 for (;;) {
9728 *app = ap = (union node *)stalloc(sizeof (struct narg));
9729 ap->type = NARG;
9730 ap->narg.text = wordtext;
9731 ap->narg.backquote = backquotelist;
9732 if (checkkwd = 2, readtoken() != TPIPE)
9733 break;
9734 app = &ap->narg.next;
9735 readtoken();
9736 }
9737 ap->narg.next = NULL;
9738 if (lasttoken != TRP)
9739 synexpect(TRP);
9740 cp->nclist.body = list(0);
9741
9742 checkkwd = 2;
9743 if ((t = readtoken()) != TESAC) {
9744 if (t != TENDCASE)
9745 synexpect(TENDCASE);
9746 else
9747 checkkwd = 2, readtoken();
9748 }
9749 cpp = &cp->nclist.next;
9750 } while(lasttoken != TESAC);
9751 *cpp = NULL;
9752 checkkwd = 1;
9753 break;
9754 case TLP:
9755 n1 = (union node *)stalloc(sizeof (struct nredir));
9756 n1->type = NSUBSHELL;
9757 n1->nredir.n = list(0);
9758 n1->nredir.redirect = NULL;
9759 if (readtoken() != TRP)
9760 synexpect(TRP);
9761 checkkwd = 1;
9762 break;
9763 case TBEGIN:
9764 n1 = list(0);
9765 if (readtoken() != TEND)
9766 synexpect(TEND);
9767 checkkwd = 1;
9768 break;
9769 /* Handle an empty command like other simple commands. */
9770 case TSEMI:
9771 case TAND:
9772 case TOR:
9773 case TNL:
9774 case TEOF:
9775 case TRP:
9776 case TBACKGND:
9777 /*
9778 * An empty command before a ; doesn't make much sense, and
9779 * should certainly be disallowed in the case of `if ;'.
9780 */
9781 if (!redir)
9782 synexpect(-1);
9783 case TWORD:
9784 case TREDIR:
9785 tokpushback++;
9786 n1 = simplecmd();
9787 return n1;
9788 default:
9789 synexpect(-1);
9790 /* NOTREACHED */
9791 }
9792
9793 /* Now check for redirection which may follow command */
9794 while (readtoken() == TREDIR) {
9795 *rpp = n2 = redirnode;
9796 rpp = &n2->nfile.next;
9797 parsefname();
9798 }
9799 tokpushback++;
9800 *rpp = NULL;
9801 if (redir) {
9802 if (n1->type != NSUBSHELL) {
9803 n2 = (union node *)stalloc(sizeof (struct nredir));
9804 n2->type = NREDIR;
9805 n2->nredir.n = n1;
9806 n1 = n2;
9807 }
9808 n1->nredir.redirect = redir;
9809 }
9810
9811 return n1;
9812}
9813
9814
9815static union node *
9816simplecmd() {
9817 union node *args, **app;
9818 union node *n = NULL;
9819 union node *vars, **vpp;
9820 union node **rpp, *redir;
9821
9822 args = NULL;
9823 app = &args;
9824 vars = NULL;
9825 vpp = &vars;
9826 redir = NULL;
9827 rpp = &redir;
9828
9829 checkalias = 2;
9830 for (;;) {
9831 switch (readtoken()) {
9832 case TWORD:
9833 case TASSIGN:
9834 n = (union node *)stalloc(sizeof (struct narg));
9835 n->type = NARG;
9836 n->narg.text = wordtext;
9837 n->narg.backquote = backquotelist;
9838 if (lasttoken == TWORD) {
9839 *app = n;
9840 app = &n->narg.next;
9841 } else {
9842 *vpp = n;
9843 vpp = &n->narg.next;
9844 }
9845 break;
9846 case TREDIR:
9847 *rpp = n = redirnode;
9848 rpp = &n->nfile.next;
Eric Andersen2870d962001-07-02 17:27:21 +00009849 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +00009850 break;
9851 case TLP:
9852 if (
9853 args && app == &args->narg.next &&
9854 !vars && !redir
9855 ) {
9856 /* We have a function */
9857 if (readtoken() != TRP)
9858 synexpect(TRP);
Eric Andersencb57d552001-06-28 07:25:16 +00009859 n->type = NDEFUN;
9860 checkkwd = 2;
9861 n->narg.next = command();
9862 return n;
9863 }
9864 /* fall through */
9865 default:
9866 tokpushback++;
9867 goto out;
9868 }
9869 }
9870out:
9871 *app = NULL;
9872 *vpp = NULL;
9873 *rpp = NULL;
9874 n = (union node *)stalloc(sizeof (struct ncmd));
9875 n->type = NCMD;
9876 n->ncmd.backgnd = 0;
9877 n->ncmd.args = args;
9878 n->ncmd.assign = vars;
9879 n->ncmd.redirect = redir;
9880 return n;
9881}
9882
9883static union node *
Eric Andersen2870d962001-07-02 17:27:21 +00009884makename(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009885 union node *n;
9886
9887 n = (union node *)stalloc(sizeof (struct narg));
9888 n->type = NARG;
9889 n->narg.next = NULL;
9890 n->narg.text = wordtext;
9891 n->narg.backquote = backquotelist;
9892 return n;
9893}
9894
9895static void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +00009896{
Eric Andersencb57d552001-06-28 07:25:16 +00009897 TRACE(("Fix redir %s %d\n", text, err));
9898 if (!err)
9899 n->ndup.vname = NULL;
9900
9901 if (is_digit(text[0]) && text[1] == '\0')
9902 n->ndup.dupfd = digit_val(text[0]);
9903 else if (text[0] == '-' && text[1] == '\0')
9904 n->ndup.dupfd = -1;
9905 else {
9906
9907 if (err)
9908 synerror("Bad fd number");
9909 else
9910 n->ndup.vname = makename();
9911 }
9912}
9913
9914
9915static void
Eric Andersen2870d962001-07-02 17:27:21 +00009916parsefname(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009917 union node *n = redirnode;
9918
9919 if (readtoken() != TWORD)
9920 synexpect(-1);
9921 if (n->type == NHERE) {
9922 struct heredoc *here = heredoc;
9923 struct heredoc *p;
9924 int i;
9925
9926 if (quoteflag == 0)
9927 n->type = NXHERE;
9928 TRACE(("Here document %d\n", n->type));
9929 if (here->striptabs) {
9930 while (*wordtext == '\t')
9931 wordtext++;
9932 }
9933 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9934 synerror("Illegal eof marker for << redirection");
9935 rmescapes(wordtext);
9936 here->eofmark = wordtext;
9937 here->next = NULL;
9938 if (heredoclist == NULL)
9939 heredoclist = here;
9940 else {
9941 for (p = heredoclist ; p->next ; p = p->next);
9942 p->next = here;
9943 }
9944 } else if (n->type == NTOFD || n->type == NFROMFD) {
9945 fixredir(n, wordtext, 0);
9946 } else {
9947 n->nfile.fname = makename();
9948 }
9949}
9950
9951
9952/*
9953 * Input any here documents.
9954 */
9955
9956static void
9957parseheredoc() {
9958 struct heredoc *here;
9959 union node *n;
9960
9961 while (heredoclist) {
9962 here = heredoclist;
9963 heredoclist = here->next;
9964 if (needprompt) {
9965 setprompt(2);
9966 needprompt = 0;
9967 }
9968 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9969 here->eofmark, here->striptabs);
9970 n = (union node *)stalloc(sizeof (struct narg));
9971 n->narg.type = NARG;
9972 n->narg.next = NULL;
9973 n->narg.text = wordtext;
9974 n->narg.backquote = backquotelist;
9975 here->here->nhere.doc = n;
9976 }
9977}
9978
9979static int
9980peektoken() {
9981 int t;
9982
9983 t = readtoken();
9984 tokpushback++;
9985 return (t);
9986}
9987
9988static int
9989readtoken() {
9990 int t;
Eric Andersen7467c8d2001-07-12 20:26:32 +00009991
Eric Andersen2870d962001-07-02 17:27:21 +00009992#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00009993 int savecheckalias = checkalias;
Eric Andersen7467c8d2001-07-12 20:26:32 +00009994 int savecheckkwd = checkkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009995 struct alias *ap;
Eric Andersen2870d962001-07-02 17:27:21 +00009996#endif
9997
Eric Andersencb57d552001-06-28 07:25:16 +00009998#ifdef DEBUG
9999 int alreadyseen = tokpushback;
10000#endif
10001
Eric Andersen2870d962001-07-02 17:27:21 +000010002#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010003top:
Eric Andersen2870d962001-07-02 17:27:21 +000010004#endif
10005
Eric Andersencb57d552001-06-28 07:25:16 +000010006 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +000010007
10008#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010009 checkalias = savecheckalias;
Eric Andersen2870d962001-07-02 17:27:21 +000010010#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010011
10012 if (checkkwd) {
10013 /*
10014 * eat newlines
10015 */
10016 if (checkkwd == 2) {
10017 checkkwd = 0;
10018 while (t == TNL) {
10019 parseheredoc();
10020 t = xxreadtoken();
10021 }
10022 }
10023 checkkwd = 0;
10024 /*
10025 * check for keywords
10026 */
10027 if (t == TWORD && !quoteflag)
10028 {
10029 const char *const *pp;
10030
10031 if ((pp = findkwd(wordtext))) {
10032 lasttoken = t = pp - parsekwd + KWDOFFSET;
10033 TRACE(("keyword %s recognized\n", tokname[t]));
10034 goto out;
10035 }
10036 }
10037 }
10038
Eric Andersen7467c8d2001-07-12 20:26:32 +000010039
Eric Andersencb57d552001-06-28 07:25:16 +000010040 if (t != TWORD) {
10041 if (t != TREDIR) {
10042 checkalias = 0;
10043 }
10044 } else if (checkalias == 2 && isassignment(wordtext)) {
10045 lasttoken = t = TASSIGN;
Eric Andersen7467c8d2001-07-12 20:26:32 +000010046#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010047 } else if (checkalias) {
10048 if (!quoteflag && (ap = lookupalias(wordtext, 1)) != NULL) {
10049 if (*ap->val) {
10050 pushstring(ap->val, strlen(ap->val), ap);
10051 }
10052 checkkwd = savecheckkwd;
10053 goto top;
10054 }
10055 checkalias = 0;
Eric Andersen2870d962001-07-02 17:27:21 +000010056#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +000010057 }
Eric Andersencb57d552001-06-28 07:25:16 +000010058out:
10059#ifdef DEBUG
10060 if (!alreadyseen)
10061 TRACE(("token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : ""));
10062 else
10063 TRACE(("reread token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : ""));
10064#endif
10065 return (t);
10066}
10067
10068
10069/*
10070 * Read the next input token.
10071 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +000010072 * backquotes. We set quoteflag to true if any part of the word was
10073 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +000010074 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +000010075 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +000010076 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +000010077 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +000010078 *
10079 * [Change comment: here documents and internal procedures]
10080 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10081 * word parsing code into a separate routine. In this case, readtoken
10082 * doesn't need to have any internal procedures, but parseword does.
10083 * We could also make parseoperator in essence the main routine, and
10084 * have parseword (readtoken1?) handle both words and redirection.]
10085 */
10086
Eric Andersen2870d962001-07-02 17:27:21 +000010087#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010088
10089static int
10090xxreadtoken() {
10091 int c;
10092
10093 if (tokpushback) {
10094 tokpushback = 0;
10095 return lasttoken;
10096 }
10097 if (needprompt) {
10098 setprompt(2);
10099 needprompt = 0;
10100 }
10101 startlinno = plinno;
Eric Andersen2870d962001-07-02 17:27:21 +000010102 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010103 c = pgetc_macro();
10104 switch (c) {
10105 case ' ': case '\t':
Eric Andersen3102ac42001-07-06 04:26:23 +000010106#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010107 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010108#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010109 continue;
10110 case '#':
10111 while ((c = pgetc()) != '\n' && c != PEOF);
10112 pungetc();
10113 continue;
10114 case '\\':
10115 if (pgetc() == '\n') {
10116 startlinno = ++plinno;
10117 if (doprompt)
10118 setprompt(2);
10119 else
10120 setprompt(0);
10121 continue;
10122 }
10123 pungetc();
10124 goto breakloop;
10125 case '\n':
10126 plinno++;
10127 needprompt = doprompt;
10128 RETURN(TNL);
10129 case PEOF:
10130 RETURN(TEOF);
10131 case '&':
10132 if (pgetc() == '&')
10133 RETURN(TAND);
10134 pungetc();
10135 RETURN(TBACKGND);
10136 case '|':
10137 if (pgetc() == '|')
10138 RETURN(TOR);
10139 pungetc();
10140 RETURN(TPIPE);
10141 case ';':
10142 if (pgetc() == ';')
10143 RETURN(TENDCASE);
10144 pungetc();
10145 RETURN(TSEMI);
10146 case '(':
10147 RETURN(TLP);
10148 case ')':
10149 RETURN(TRP);
10150 default:
10151 goto breakloop;
10152 }
10153 }
10154breakloop:
10155 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10156#undef RETURN
10157}
10158
10159
10160
10161/*
10162 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10163 * is not NULL, read a here document. In the latter case, eofmark is the
10164 * word which marks the end of the document and striptabs is true if
10165 * leading tabs should be stripped from the document. The argument firstc
10166 * is the first character of the input token or document.
10167 *
10168 * Because C does not have internal subroutines, I have simulated them
10169 * using goto's to implement the subroutine linkage. The following macros
10170 * will run code that appears at the end of readtoken1.
10171 */
10172
Eric Andersen2870d962001-07-02 17:27:21 +000010173#define CHECKEND() {goto checkend; checkend_return:;}
10174#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10175#define PARSESUB() {goto parsesub; parsesub_return:;}
10176#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10177#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10178#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010179
10180static int
10181readtoken1(firstc, syntax, eofmark, striptabs)
10182 int firstc;
10183 char const *syntax;
10184 char *eofmark;
10185 int striptabs;
10186 {
10187 int c = firstc;
10188 char *out;
10189 int len;
10190 char line[EOFMARKLEN + 1];
10191 struct nodelist *bqlist;
10192 int quotef;
10193 int dblquote;
Eric Andersen2870d962001-07-02 17:27:21 +000010194 int varnest; /* levels of variables expansion */
10195 int arinest; /* levels of arithmetic expansion */
10196 int parenlevel; /* levels of parens in arithmetic */
10197 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +000010198 int oldstyle;
Eric Andersen2870d962001-07-02 17:27:21 +000010199 char const *prevsyntax; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010200#if __GNUC__
10201 /* Avoid longjmp clobbering */
10202 (void) &out;
10203 (void) &quotef;
10204 (void) &dblquote;
10205 (void) &varnest;
10206 (void) &arinest;
10207 (void) &parenlevel;
10208 (void) &dqvarnest;
10209 (void) &oldstyle;
10210 (void) &prevsyntax;
10211 (void) &syntax;
10212#endif
10213
10214 startlinno = plinno;
10215 dblquote = 0;
10216 if (syntax == DQSYNTAX)
10217 dblquote = 1;
10218 quotef = 0;
10219 bqlist = NULL;
10220 varnest = 0;
10221 arinest = 0;
10222 parenlevel = 0;
10223 dqvarnest = 0;
10224
10225 STARTSTACKSTR(out);
Eric Andersen2870d962001-07-02 17:27:21 +000010226 loop: { /* for each line, until end of word */
10227 CHECKEND(); /* set c to PEOF if at end of here document */
10228 for (;;) { /* until end of line or end of word */
10229 CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
Eric Andersencb57d552001-06-28 07:25:16 +000010230 switch(syntax[c]) {
Eric Andersen2870d962001-07-02 17:27:21 +000010231 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010232 if (syntax == BASESYNTAX)
Eric Andersen2870d962001-07-02 17:27:21 +000010233 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010234 USTPUTC(c, out);
10235 plinno++;
10236 if (doprompt)
10237 setprompt(2);
10238 else
10239 setprompt(0);
10240 c = pgetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010241 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010242 case CWORD:
10243 USTPUTC(c, out);
10244 break;
10245 case CCTL:
10246 if ((eofmark == NULL || dblquote) &&
10247 dqvarnest == 0)
10248 USTPUTC(CTLESC, out);
10249 USTPUTC(c, out);
10250 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010251 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010252 c = pgetc2();
10253 if (c == PEOF) {
10254 USTPUTC('\\', out);
10255 pungetc();
10256 } else if (c == '\n') {
10257 if (doprompt)
10258 setprompt(2);
10259 else
10260 setprompt(0);
10261 } else {
10262 if (dblquote && c != '\\' && c != '`' && c != '$'
10263 && (c != '"' || eofmark != NULL))
10264 USTPUTC('\\', out);
10265 if (SQSYNTAX[c] == CCTL)
10266 USTPUTC(CTLESC, out);
10267 else if (eofmark == NULL)
10268 USTPUTC(CTLQUOTEMARK, out);
10269 USTPUTC(c, out);
10270 quotef++;
10271 }
10272 break;
10273 case CSQUOTE:
10274 if (eofmark == NULL)
10275 USTPUTC(CTLQUOTEMARK, out);
10276 syntax = SQSYNTAX;
10277 break;
10278 case CDQUOTE:
10279 if (eofmark == NULL)
10280 USTPUTC(CTLQUOTEMARK, out);
10281 syntax = DQSYNTAX;
10282 dblquote = 1;
10283 break;
10284 case CENDQUOTE:
10285 if (eofmark != NULL && arinest == 0 &&
10286 varnest == 0) {
10287 USTPUTC(c, out);
10288 } else {
10289 if (arinest) {
10290 syntax = ARISYNTAX;
10291 dblquote = 0;
10292 } else if (eofmark == NULL &&
10293 dqvarnest == 0) {
10294 syntax = BASESYNTAX;
10295 dblquote = 0;
10296 }
10297 quotef++;
10298 }
10299 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010300 case CVAR: /* '$' */
10301 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010302 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010303 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010304 if (varnest > 0) {
10305 varnest--;
10306 if (dqvarnest > 0) {
10307 dqvarnest--;
10308 }
10309 USTPUTC(CTLENDVAR, out);
10310 } else {
10311 USTPUTC(c, out);
10312 }
10313 break;
10314#ifdef ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +000010315 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010316 parenlevel++;
10317 USTPUTC(c, out);
10318 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010319 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010320 if (parenlevel > 0) {
10321 USTPUTC(c, out);
10322 --parenlevel;
10323 } else {
10324 if (pgetc() == ')') {
10325 if (--arinest == 0) {
10326 USTPUTC(CTLENDARI, out);
10327 syntax = prevsyntax;
10328 if (syntax == DQSYNTAX)
10329 dblquote = 1;
10330 else
10331 dblquote = 0;
10332 } else
10333 USTPUTC(')', out);
10334 } else {
10335 /*
10336 * unbalanced parens
10337 * (don't 2nd guess - no error)
10338 */
10339 pungetc();
10340 USTPUTC(')', out);
10341 }
10342 }
10343 break;
10344#endif
Eric Andersen2870d962001-07-02 17:27:21 +000010345 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010346 PARSEBACKQOLD();
10347 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010348 case CENDFILE:
10349 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010350 case CIGN:
10351 break;
10352 default:
10353 if (varnest == 0)
Eric Andersen2870d962001-07-02 17:27:21 +000010354 goto endword; /* exit outer loop */
Eric Andersen3102ac42001-07-06 04:26:23 +000010355#ifdef ASH_ALIAS
10356 if (c != PEOA)
10357#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010358 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010359
Eric Andersencb57d552001-06-28 07:25:16 +000010360 }
10361 c = pgetc_macro();
10362 }
10363 }
10364endword:
10365 if (syntax == ARISYNTAX)
10366 synerror("Missing '))'");
10367 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10368 synerror("Unterminated quoted string");
10369 if (varnest != 0) {
10370 startlinno = plinno;
10371 synerror("Missing '}'");
10372 }
10373 USTPUTC('\0', out);
10374 len = out - stackblock();
10375 out = stackblock();
10376 if (eofmark == NULL) {
10377 if ((c == '>' || c == '<')
10378 && quotef == 0
10379 && len <= 2
10380 && (*out == '\0' || is_digit(*out))) {
10381 PARSEREDIR();
10382 return lasttoken = TREDIR;
10383 } else {
10384 pungetc();
10385 }
10386 }
10387 quoteflag = quotef;
10388 backquotelist = bqlist;
10389 grabstackblock(len);
10390 wordtext = out;
10391 return lasttoken = TWORD;
10392/* end of readtoken routine */
10393
10394
10395
10396/*
10397 * Check to see whether we are at the end of the here document. When this
10398 * is called, c is set to the first character of the next input line. If
10399 * we are at the end of the here document, this routine sets the c to PEOF.
10400 */
10401
10402checkend: {
10403 if (eofmark) {
Eric Andersen2870d962001-07-02 17:27:21 +000010404#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010405 if (c == PEOA) {
10406 c = pgetc2();
10407 }
Eric Andersen2870d962001-07-02 17:27:21 +000010408#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010409 if (striptabs) {
10410 while (c == '\t') {
10411 c = pgetc2();
10412 }
10413 }
10414 if (c == *eofmark) {
10415 if (pfgets(line, sizeof line) != NULL) {
10416 char *p, *q;
10417
10418 p = line;
10419 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10420 if (*p == '\n' && *q == '\0') {
10421 c = PEOF;
10422 plinno++;
10423 needprompt = doprompt;
10424 } else {
10425 pushstring(line, strlen(line), NULL);
10426 }
10427 }
10428 }
10429 }
10430 goto checkend_return;
10431}
10432
10433
10434/*
10435 * Parse a redirection operator. The variable "out" points to a string
10436 * specifying the fd to be redirected. The variable "c" contains the
10437 * first character of the redirection operator.
10438 */
10439
10440parseredir: {
10441 char fd = *out;
10442 union node *np;
10443
10444 np = (union node *)stalloc(sizeof (struct nfile));
10445 if (c == '>') {
10446 np->nfile.fd = 1;
10447 c = pgetc();
10448 if (c == '>')
10449 np->type = NAPPEND;
10450 else if (c == '&')
10451 np->type = NTOFD;
10452 else if (c == '|')
10453 np->type = NTOOV;
10454 else {
10455 np->type = NTO;
10456 pungetc();
10457 }
Eric Andersen2870d962001-07-02 17:27:21 +000010458 } else { /* c == '<' */
Eric Andersencb57d552001-06-28 07:25:16 +000010459 np->nfile.fd = 0;
10460 switch (c = pgetc()) {
10461 case '<':
10462 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10463 np = (union node *)stalloc(sizeof (struct nhere));
10464 np->nfile.fd = 0;
10465 }
10466 np->type = NHERE;
10467 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10468 heredoc->here = np;
10469 if ((c = pgetc()) == '-') {
10470 heredoc->striptabs = 1;
10471 } else {
10472 heredoc->striptabs = 0;
10473 pungetc();
10474 }
10475 break;
10476
10477 case '&':
10478 np->type = NFROMFD;
10479 break;
10480
10481 case '>':
10482 np->type = NFROMTO;
10483 break;
10484
10485 default:
10486 np->type = NFROM;
10487 pungetc();
10488 break;
10489 }
10490 }
10491 if (fd != '\0')
10492 np->nfile.fd = digit_val(fd);
10493 redirnode = np;
10494 goto parseredir_return;
10495}
10496
10497
10498/*
10499 * Parse a substitution. At this point, we have read the dollar sign
10500 * and nothing else.
10501 */
10502
10503parsesub: {
10504 int subtype;
10505 int typeloc;
10506 int flags;
10507 char *p;
10508 static const char types[] = "}-+?=";
10509
10510 c = pgetc();
10511 if (
10512 c <= PEOA ||
10513 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10514 ) {
10515 USTPUTC('$', out);
10516 pungetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010517 } else if (c == '(') { /* $(command) or $((arith)) */
Eric Andersencb57d552001-06-28 07:25:16 +000010518 if (pgetc() == '(') {
10519 PARSEARITH();
10520 } else {
10521 pungetc();
10522 PARSEBACKQNEW();
10523 }
10524 } else {
10525 USTPUTC(CTLVAR, out);
10526 typeloc = out - stackblock();
10527 USTPUTC(VSNORMAL, out);
10528 subtype = VSNORMAL;
10529 if (c == '{') {
10530 c = pgetc();
10531 if (c == '#') {
10532 if ((c = pgetc()) == '}')
10533 c = '#';
10534 else
10535 subtype = VSLENGTH;
10536 }
10537 else
10538 subtype = 0;
10539 }
10540 if (c > PEOA && is_name(c)) {
10541 do {
10542 STPUTC(c, out);
10543 c = pgetc();
10544 } while (c > PEOA && is_in_name(c));
10545 } else if (is_digit(c)) {
10546 do {
10547 USTPUTC(c, out);
10548 c = pgetc();
10549 } while (is_digit(c));
10550 }
10551 else if (is_special(c)) {
10552 USTPUTC(c, out);
10553 c = pgetc();
10554 }
10555 else
Eric Andersen2870d962001-07-02 17:27:21 +000010556badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010557
10558 STPUTC('=', out);
10559 flags = 0;
10560 if (subtype == 0) {
10561 switch (c) {
10562 case ':':
10563 flags = VSNUL;
10564 c = pgetc();
10565 /*FALLTHROUGH*/
10566 default:
10567 p = strchr(types, c);
10568 if (p == NULL)
10569 goto badsub;
10570 subtype = p - types + VSNORMAL;
10571 break;
10572 case '%':
10573 case '#':
10574 {
10575 int cc = c;
10576 subtype = c == '#' ? VSTRIMLEFT :
10577 VSTRIMRIGHT;
10578 c = pgetc();
10579 if (c == cc)
10580 subtype++;
10581 else
10582 pungetc();
10583 break;
10584 }
10585 }
10586 } else {
10587 pungetc();
10588 }
10589 if (dblquote || arinest)
10590 flags |= VSQUOTE;
10591 *(stackblock() + typeloc) = subtype | flags;
10592 if (subtype != VSNORMAL) {
10593 varnest++;
10594 if (dblquote) {
10595 dqvarnest++;
10596 }
10597 }
10598 }
10599 goto parsesub_return;
10600}
10601
10602
10603/*
10604 * Called to parse command substitutions. Newstyle is set if the command
10605 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10606 * list of commands (passed by reference), and savelen is the number of
10607 * characters on the top of the stack which must be preserved.
10608 */
10609
10610parsebackq: {
10611 struct nodelist **nlpp;
10612 int savepbq;
10613 union node *n;
10614 char *volatile str;
10615 struct jmploc jmploc;
10616 struct jmploc *volatile savehandler;
10617 int savelen;
10618 int saveprompt;
10619#ifdef __GNUC__
10620 (void) &saveprompt;
10621#endif
10622
10623 savepbq = parsebackquote;
10624 if (setjmp(jmploc.loc)) {
10625 if (str)
10626 ckfree(str);
10627 parsebackquote = 0;
10628 handler = savehandler;
10629 longjmp(handler->loc, 1);
10630 }
10631 INTOFF;
10632 str = NULL;
10633 savelen = out - stackblock();
10634 if (savelen > 0) {
10635 str = ckmalloc(savelen);
10636 memcpy(str, stackblock(), savelen);
10637 }
10638 savehandler = handler;
10639 handler = &jmploc;
10640 INTON;
Eric Andersen2870d962001-07-02 17:27:21 +000010641 if (oldstyle) {
10642 /* We must read until the closing backquote, giving special
10643 treatment to some slashes, and then push the string and
10644 reread it as input, interpreting it normally. */
10645 char *pout;
10646 int pc;
10647 int psavelen;
10648 char *pstr;
Eric Andersencb57d552001-06-28 07:25:16 +000010649
10650
Eric Andersen2870d962001-07-02 17:27:21 +000010651 STARTSTACKSTR(pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010652 for (;;) {
10653 if (needprompt) {
10654 setprompt(2);
10655 needprompt = 0;
10656 }
10657 switch (pc = pgetc()) {
10658 case '`':
10659 goto done;
10660
10661 case '\\':
Eric Andersen2870d962001-07-02 17:27:21 +000010662 if ((pc = pgetc()) == '\n') {
Eric Andersencb57d552001-06-28 07:25:16 +000010663 plinno++;
10664 if (doprompt)
10665 setprompt(2);
10666 else
10667 setprompt(0);
10668 /*
10669 * If eating a newline, avoid putting
10670 * the newline into the new character
10671 * stream (via the STPUTC after the
10672 * switch).
10673 */
10674 continue;
10675 }
Eric Andersen2870d962001-07-02 17:27:21 +000010676 if (pc != '\\' && pc != '`' && pc != '$'
10677 && (!dblquote || pc != '"'))
10678 STPUTC('\\', pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010679 if (pc > PEOA) {
10680 break;
10681 }
10682 /* fall through */
10683
10684 case PEOF:
Eric Andersen2870d962001-07-02 17:27:21 +000010685#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010686 case PEOA:
Eric Andersen2870d962001-07-02 17:27:21 +000010687#endif
10688 startlinno = plinno;
Eric Andersencb57d552001-06-28 07:25:16 +000010689 synerror("EOF in backquote substitution");
10690
10691 case '\n':
10692 plinno++;
10693 needprompt = doprompt;
10694 break;
10695
10696 default:
10697 break;
10698 }
10699 STPUTC(pc, pout);
Eric Andersen2870d962001-07-02 17:27:21 +000010700 }
Eric Andersencb57d552001-06-28 07:25:16 +000010701done:
Eric Andersen2870d962001-07-02 17:27:21 +000010702 STPUTC('\0', pout);
10703 psavelen = pout - stackblock();
10704 if (psavelen > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010705 pstr = grabstackstr(pout);
10706 setinputstring(pstr);
Eric Andersen2870d962001-07-02 17:27:21 +000010707 }
10708 }
Eric Andersencb57d552001-06-28 07:25:16 +000010709 nlpp = &bqlist;
10710 while (*nlpp)
10711 nlpp = &(*nlpp)->next;
10712 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10713 (*nlpp)->next = NULL;
10714 parsebackquote = oldstyle;
10715
10716 if (oldstyle) {
10717 saveprompt = doprompt;
10718 doprompt = 0;
10719 }
10720
10721 n = list(0);
10722
10723 if (oldstyle)
10724 doprompt = saveprompt;
10725 else {
10726 if (readtoken() != TRP)
10727 synexpect(TRP);
10728 }
10729
10730 (*nlpp)->n = n;
Eric Andersen2870d962001-07-02 17:27:21 +000010731 if (oldstyle) {
Eric Andersencb57d552001-06-28 07:25:16 +000010732 /*
10733 * Start reading from old file again, ignoring any pushed back
10734 * tokens left from the backquote parsing
10735 */
Eric Andersen2870d962001-07-02 17:27:21 +000010736 popfile();
Eric Andersencb57d552001-06-28 07:25:16 +000010737 tokpushback = 0;
10738 }
10739 while (stackblocksize() <= savelen)
10740 growstackblock();
10741 STARTSTACKSTR(out);
10742 if (str) {
10743 memcpy(out, str, savelen);
10744 STADJUST(savelen, out);
10745 INTOFF;
10746 ckfree(str);
10747 str = NULL;
10748 INTON;
10749 }
10750 parsebackquote = savepbq;
10751 handler = savehandler;
10752 if (arinest || dblquote)
10753 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10754 else
10755 USTPUTC(CTLBACKQ, out);
10756 if (oldstyle)
10757 goto parsebackq_oldreturn;
10758 else
10759 goto parsebackq_newreturn;
10760}
10761
10762/*
10763 * Parse an arithmetic expansion (indicate start of one and set state)
10764 */
10765parsearith: {
10766
10767 if (++arinest == 1) {
10768 prevsyntax = syntax;
10769 syntax = ARISYNTAX;
10770 USTPUTC(CTLARI, out);
10771 if (dblquote)
10772 USTPUTC('"',out);
10773 else
10774 USTPUTC(' ',out);
10775 } else {
10776 /*
10777 * we collapse embedded arithmetic expansion to
10778 * parenthesis, which should be equivalent
10779 */
10780 USTPUTC('(', out);
10781 }
10782 goto parsearith_return;
10783}
10784
10785} /* end of readtoken */
10786
10787
Eric Andersencb57d552001-06-28 07:25:16 +000010788/*
10789 * Returns true if the text contains nothing to expand (no dollar signs
10790 * or backquotes).
10791 */
10792
10793static int
10794noexpand(text)
10795 char *text;
10796 {
10797 char *p;
10798 char c;
10799
10800 p = text;
10801 while ((c = *p++) != '\0') {
10802 if (c == CTLQUOTEMARK)
10803 continue;
10804 if (c == CTLESC)
10805 p++;
10806 else if (BASESYNTAX[(int)c] == CCTL)
10807 return 0;
10808 }
10809 return 1;
10810}
10811
10812
10813/*
10814 * Return true if the argument is a legal variable name (a letter or
10815 * underscore followed by zero or more letters, underscores, and digits).
10816 */
10817
10818static int
Eric Andersen2870d962001-07-02 17:27:21 +000010819goodname(const char *name)
10820{
10821 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000010822
10823 p = name;
10824 if (! is_name(*p))
10825 return 0;
10826 while (*++p) {
10827 if (! is_in_name(*p))
10828 return 0;
10829 }
10830 return 1;
10831}
10832
10833
10834/*
10835 * Called when an unexpected token is read during the parse. The argument
10836 * is the token that is expected, or -1 if more than one type of token can
10837 * occur at this point.
10838 */
10839
10840static void
10841synexpect(token)
10842 int token;
10843{
10844 char msg[64];
10845
10846 if (token >= 0) {
Eric Andersen3102ac42001-07-06 04:26:23 +000010847 snprintf(msg, 64, "%s unexpected (expecting %s)",
Eric Andersencb57d552001-06-28 07:25:16 +000010848 tokname[lasttoken], tokname[token]);
10849 } else {
Eric Andersen3102ac42001-07-06 04:26:23 +000010850 snprintf(msg, 64, "%s unexpected", tokname[lasttoken]);
Eric Andersencb57d552001-06-28 07:25:16 +000010851 }
10852 synerror(msg);
10853 /* NOTREACHED */
10854}
10855
10856
10857static void
Eric Andersen2870d962001-07-02 17:27:21 +000010858synerror(const char *msg)
10859{
Eric Andersencb57d552001-06-28 07:25:16 +000010860 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +000010861 out2fmt("%s: %d: ", commandname, startlinno);
10862 out2fmt("Syntax error: %s\n", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000010863 error((char *)NULL);
10864 /* NOTREACHED */
10865}
10866
Eric Andersencb57d552001-06-28 07:25:16 +000010867
10868/*
10869 * called by editline -- any expansions to the prompt
10870 * should be added here.
10871 */
Eric Andersen2870d962001-07-02 17:27:21 +000010872static void
Eric Andersen62483552001-07-10 06:09:16 +000010873setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000010874{
Eric Andersen62483552001-07-10 06:09:16 +000010875 char *prompt;
10876 switch (whichprompt) {
10877 case 1:
10878 prompt = ps1val();
10879 break;
10880 case 2:
10881 prompt = ps2val();
10882 break;
10883 default: /* 0 */
10884 prompt = "";
10885 }
10886 putprompt(prompt);
Eric Andersencb57d552001-06-28 07:25:16 +000010887}
10888
Eric Andersencb57d552001-06-28 07:25:16 +000010889
Eric Andersencb57d552001-06-28 07:25:16 +000010890/*
10891 * Code for dealing with input/output redirection.
10892 */
10893
Eric Andersen2870d962001-07-02 17:27:21 +000010894#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000010895#ifndef PIPE_BUF
Eric Andersen2870d962001-07-02 17:27:21 +000010896# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000010897#else
10898# define PIPESIZE PIPE_BUF
10899#endif
10900
10901
Eric Andersen62483552001-07-10 06:09:16 +000010902/*
10903 * Open a file in noclobber mode.
10904 * The code was copied from bash.
10905 */
10906static inline int
10907noclobberopen(const char *fname)
10908{
10909 int r, fd;
10910 struct stat finfo, finfo2;
10911
10912 /*
10913 * If the file exists and is a regular file, return an error
10914 * immediately.
10915 */
10916 r = stat(fname, &finfo);
10917 if (r == 0 && S_ISREG(finfo.st_mode)) {
10918 errno = EEXIST;
10919 return -1;
10920 }
10921
10922 /*
10923 * If the file was not present (r != 0), make sure we open it
10924 * exclusively so that if it is created before we open it, our open
10925 * will fail. Make sure that we do not truncate an existing file.
10926 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10927 * file was not a regular file, we leave O_EXCL off.
10928 */
10929 if (r != 0)
10930 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10931 fd = open(fname, O_WRONLY|O_CREAT, 0666);
10932
10933 /* If the open failed, return the file descriptor right away. */
10934 if (fd < 0)
10935 return fd;
10936
10937 /*
10938 * OK, the open succeeded, but the file may have been changed from a
10939 * non-regular file to a regular file between the stat and the open.
10940 * We are assuming that the O_EXCL open handles the case where FILENAME
10941 * did not exist and is symlinked to an existing file between the stat
10942 * and open.
10943 */
10944
10945 /*
10946 * If we can open it and fstat the file descriptor, and neither check
10947 * revealed that it was a regular file, and the file has not been
10948 * replaced, return the file descriptor.
10949 */
10950 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10951 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
10952 return fd;
10953
10954 /* The file has been replaced. badness. */
10955 close(fd);
10956 errno = EEXIST;
10957 return -1;
10958}
Eric Andersencb57d552001-06-28 07:25:16 +000010959
10960/*
Eric Andersen62483552001-07-10 06:09:16 +000010961 * Handle here documents. Normally we fork off a process to write the
10962 * data to a pipe. If the document is short, we can stuff the data in
10963 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000010964 */
10965
Eric Andersen62483552001-07-10 06:09:16 +000010966static inline int
10967openhere(const union node *redir)
10968{
10969 int pip[2];
10970 int len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010971
Eric Andersen62483552001-07-10 06:09:16 +000010972 if (pipe(pip) < 0)
10973 error("Pipe call failed");
10974 if (redir->type == NHERE) {
10975 len = strlen(redir->nhere.doc->narg.text);
10976 if (len <= PIPESIZE) {
10977 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10978 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010979 }
Eric Andersencb57d552001-06-28 07:25:16 +000010980 }
Eric Andersen62483552001-07-10 06:09:16 +000010981 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
10982 close(pip[0]);
10983 signal(SIGINT, SIG_IGN);
10984 signal(SIGQUIT, SIG_IGN);
10985 signal(SIGHUP, SIG_IGN);
10986#ifdef SIGTSTP
10987 signal(SIGTSTP, SIG_IGN);
10988#endif
10989 signal(SIGPIPE, SIG_DFL);
10990 if (redir->type == NHERE)
10991 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10992 else
10993 expandhere(redir->nhere.doc, pip[1]);
10994 _exit(0);
10995 }
10996out:
10997 close(pip[1]);
10998 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000010999}
11000
11001
Eric Andersen62483552001-07-10 06:09:16 +000011002static inline int
11003openredirect(const union node *redir)
11004{
Eric Andersencb57d552001-06-28 07:25:16 +000011005 char *fname;
11006 int f;
11007
11008 switch (redir->nfile.type) {
11009 case NFROM:
11010 fname = redir->nfile.expfname;
11011 if ((f = open(fname, O_RDONLY)) < 0)
11012 goto eopen;
11013 break;
11014 case NFROMTO:
11015 fname = redir->nfile.expfname;
11016 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
11017 goto ecreate;
11018 break;
11019 case NTO:
11020 /* Take care of noclobber mode. */
11021 if (Cflag) {
11022 fname = redir->nfile.expfname;
11023 if ((f = noclobberopen(fname)) < 0)
11024 goto ecreate;
11025 break;
11026 }
11027 case NTOOV:
11028 fname = redir->nfile.expfname;
11029#ifdef O_CREAT
11030 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
11031 goto ecreate;
11032#else
11033 if ((f = creat(fname, 0666)) < 0)
11034 goto ecreate;
11035#endif
11036 break;
11037 case NAPPEND:
11038 fname = redir->nfile.expfname;
11039#ifdef O_APPEND
11040 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
11041 goto ecreate;
11042#else
11043 if ((f = open(fname, O_WRONLY)) < 0
11044 && (f = creat(fname, 0666)) < 0)
11045 goto ecreate;
11046 lseek(f, (off_t)0, 2);
11047#endif
11048 break;
11049 default:
11050#ifdef DEBUG
11051 abort();
11052#endif
11053 /* Fall through to eliminate warning. */
11054 case NTOFD:
11055 case NFROMFD:
11056 f = -1;
11057 break;
11058 case NHERE:
11059 case NXHERE:
11060 f = openhere(redir);
11061 break;
11062 }
11063
11064 return f;
11065ecreate:
11066 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11067eopen:
11068 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11069}
11070
11071
Eric Andersen62483552001-07-10 06:09:16 +000011072/*
11073 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11074 * old file descriptors are stashed away so that the redirection can be
11075 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11076 * standard output, and the standard error if it becomes a duplicate of
11077 * stdout.
11078 */
11079
Eric Andersencb57d552001-06-28 07:25:16 +000011080static void
Eric Andersen62483552001-07-10 06:09:16 +000011081redirect(union node *redir, int flags)
11082{
11083 union node *n;
11084 struct redirtab *sv = NULL;
11085 int i;
11086 int fd;
11087 int newfd;
11088 int try;
11089 int fd1dup = flags & REDIR_BACKQ;; /* stdout `cmd` redir to pipe */
11090
11091 if (flags & REDIR_PUSH) {
11092 sv = ckmalloc(sizeof (struct redirtab));
11093 for (i = 0 ; i < 10 ; i++)
11094 sv->renamed[i] = EMPTY;
11095 sv->next = redirlist;
11096 redirlist = sv;
11097 }
11098 for (n = redir ; n ; n = n->nfile.next) {
11099 fd = n->nfile.fd;
11100 try = 0;
11101 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11102 n->ndup.dupfd == fd)
11103 continue; /* redirect from/to same file descriptor */
11104
11105 INTOFF;
11106 newfd = openredirect(n);
11107 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
11108 if (newfd == fd) {
11109 try++;
11110 } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
11111 switch (errno) {
11112 case EBADF:
11113 if (!try) {
11114 dupredirect(n, newfd, fd1dup);
11115 try++;
11116 break;
11117 }
11118 /* FALLTHROUGH*/
11119 default:
11120 if (newfd >= 0) {
11121 close(newfd);
11122 }
11123 INTON;
11124 error("%d: %m", fd);
11125 /* NOTREACHED */
11126 }
11127 }
11128 if (!try) {
11129 close(fd);
11130 if (flags & REDIR_PUSH) {
11131 sv->renamed[fd] = i;
11132 }
11133 }
11134 } else if (fd != newfd) {
11135 close(fd);
11136 }
11137 if (fd == 0)
11138 fd0_redirected++;
11139 if (!try)
11140 dupredirect(n, newfd, fd1dup);
11141 INTON;
11142 }
11143}
11144
11145
11146static void
11147dupredirect(const union node *redir, int f, int fd1dup)
Eric Andersen2870d962001-07-02 17:27:21 +000011148{
Eric Andersencb57d552001-06-28 07:25:16 +000011149 int fd = redir->nfile.fd;
11150
Eric Andersen62483552001-07-10 06:09:16 +000011151 if(fd==1)
11152 fd1dup = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011153 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Eric Andersen2870d962001-07-02 17:27:21 +000011154 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
Eric Andersen62483552001-07-10 06:09:16 +000011155 if (redir->ndup.dupfd!=1 || fd1dup!=1)
Eric Andersencb57d552001-06-28 07:25:16 +000011156 dup_as_newfd(redir->ndup.dupfd, fd);
11157 }
11158 return;
11159 }
11160
11161 if (f != fd) {
11162 dup_as_newfd(f, fd);
11163 close(f);
11164 }
11165 return;
11166}
11167
11168
Eric Andersencb57d552001-06-28 07:25:16 +000011169
Eric Andersencb57d552001-06-28 07:25:16 +000011170/*
11171 * Undo the effects of the last redirection.
11172 */
11173
11174static void
Eric Andersen2870d962001-07-02 17:27:21 +000011175popredir(void)
11176{
Eric Andersencb57d552001-06-28 07:25:16 +000011177 struct redirtab *rp = redirlist;
11178 int i;
11179
11180 INTOFF;
11181 for (i = 0 ; i < 10 ; i++) {
11182 if (rp->renamed[i] != EMPTY) {
Eric Andersen2870d962001-07-02 17:27:21 +000011183 if (i == 0)
11184 fd0_redirected--;
Eric Andersencb57d552001-06-28 07:25:16 +000011185 close(i);
11186 if (rp->renamed[i] >= 0) {
11187 dup_as_newfd(rp->renamed[i], i);
11188 close(rp->renamed[i]);
11189 }
Eric Andersencb57d552001-06-28 07:25:16 +000011190 }
11191 }
11192 redirlist = rp->next;
11193 ckfree(rp);
11194 INTON;
11195}
11196
11197/*
Eric Andersencb57d552001-06-28 07:25:16 +000011198 * Discard all saved file descriptors.
11199 */
11200
11201static void
Eric Andersen2870d962001-07-02 17:27:21 +000011202clearredir(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000011203 struct redirtab *rp;
11204 int i;
11205
11206 for (rp = redirlist ; rp ; rp = rp->next) {
11207 for (i = 0 ; i < 10 ; i++) {
11208 if (rp->renamed[i] >= 0) {
11209 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011210 }
11211 rp->renamed[i] = EMPTY;
11212 }
11213 }
Eric Andersencb57d552001-06-28 07:25:16 +000011214}
11215
11216
Eric Andersencb57d552001-06-28 07:25:16 +000011217/*
11218 * Copy a file descriptor to be >= to. Returns -1
11219 * if the source file descriptor is closed, EMPTY if there are no unused
11220 * file descriptors left.
11221 */
11222
11223static int
11224dup_as_newfd(from, to)
11225 int from;
11226 int to;
11227{
11228 int newfd;
11229
11230 newfd = fcntl(from, F_DUPFD, to);
11231 if (newfd < 0) {
11232 if (errno == EMFILE)
11233 return EMPTY;
11234 else
Eric Andersen2870d962001-07-02 17:27:21 +000011235 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011236 }
11237 return newfd;
11238}
11239
Eric Andersen2870d962001-07-02 17:27:21 +000011240/*#ifdef __weak_alias
Eric Andersencb57d552001-06-28 07:25:16 +000011241__weak_alias(getmode,_getmode)
11242__weak_alias(setmode,_setmode)
Eric Andersen2870d962001-07-02 17:27:21 +000011243#endif*/
Eric Andersencb57d552001-06-28 07:25:16 +000011244
Eric Andersen62483552001-07-10 06:09:16 +000011245#ifndef S_ISTXT
11246#if defined(__GLIBC__) && __GLIBC__ >= 2
Eric Andersencb57d552001-06-28 07:25:16 +000011247#define S_ISTXT __S_ISVTX
Eric Andersen62483552001-07-10 06:09:16 +000011248#else
11249#define S_ISTXT S_ISVTX
11250#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011251#endif
11252
Eric Andersen2870d962001-07-02 17:27:21 +000011253#define SET_LEN 6 /* initial # of bitcmd struct to malloc */
11254#define SET_LEN_INCR 4 /* # of bitcmd structs to add as needed */
Eric Andersencb57d552001-06-28 07:25:16 +000011255
11256typedef struct bitcmd {
Eric Andersen2870d962001-07-02 17:27:21 +000011257 char cmd;
11258 char cmd2;
11259 mode_t bits;
Eric Andersencb57d552001-06-28 07:25:16 +000011260} BITCMD;
11261
Eric Andersen2870d962001-07-02 17:27:21 +000011262#define CMD2_CLR 0x01
11263#define CMD2_SET 0x02
11264#define CMD2_GBITS 0x04
11265#define CMD2_OBITS 0x08
11266#define CMD2_UBITS 0x10
Eric Andersencb57d552001-06-28 07:25:16 +000011267
Eric Andersen2870d962001-07-02 17:27:21 +000011268static BITCMD *addcmd (BITCMD *, int, int, int, u_int);
11269static void compress_mode (BITCMD *);
Eric Andersencb57d552001-06-28 07:25:16 +000011270#ifdef SETMODE_DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +000011271static void dumpmode (BITCMD *);
Eric Andersencb57d552001-06-28 07:25:16 +000011272#endif
11273
11274/*
11275 * Given the old mode and an array of bitcmd structures, apply the operations
11276 * described in the bitcmd structures to the old mode, and return the new mode.
11277 * Note that there is no '=' command; a strict assignment is just a '-' (clear
11278 * bits) followed by a '+' (set bits).
11279 */
Eric Andersen2870d962001-07-02 17:27:21 +000011280static mode_t
Eric Andersencb57d552001-06-28 07:25:16 +000011281getmode(bbox, omode)
11282 const void *bbox;
11283 mode_t omode;
11284{
11285 const BITCMD *set;
11286 mode_t clrval, newmode, value;
11287
11288 _DIAGASSERT(bbox != NULL);
11289
11290 set = (const BITCMD *)bbox;
11291 newmode = omode;
11292 for (value = 0;; set++)
11293 switch(set->cmd) {
11294 /*
11295 * When copying the user, group or other bits around, we "know"
11296 * where the bits are in the mode so that we can do shifts to
11297 * copy them around. If we don't use shifts, it gets real
11298 * grundgy with lots of single bit checks and bit sets.
11299 */
11300 case 'u':
11301 value = (newmode & S_IRWXU) >> 6;
11302 goto common;
11303
11304 case 'g':
11305 value = (newmode & S_IRWXG) >> 3;
11306 goto common;
11307
11308 case 'o':
11309 value = newmode & S_IRWXO;
Eric Andersen2870d962001-07-02 17:27:21 +000011310common: if (set->cmd2 & CMD2_CLR) {
Eric Andersencb57d552001-06-28 07:25:16 +000011311 clrval =
11312 (set->cmd2 & CMD2_SET) ? S_IRWXO : value;
11313 if (set->cmd2 & CMD2_UBITS)
11314 newmode &= ~((clrval<<6) & set->bits);
11315 if (set->cmd2 & CMD2_GBITS)
11316 newmode &= ~((clrval<<3) & set->bits);
11317 if (set->cmd2 & CMD2_OBITS)
11318 newmode &= ~(clrval & set->bits);
11319 }
11320 if (set->cmd2 & CMD2_SET) {
11321 if (set->cmd2 & CMD2_UBITS)
11322 newmode |= (value<<6) & set->bits;
11323 if (set->cmd2 & CMD2_GBITS)
11324 newmode |= (value<<3) & set->bits;
11325 if (set->cmd2 & CMD2_OBITS)
11326 newmode |= value & set->bits;
11327 }
11328 break;
11329
11330 case '+':
11331 newmode |= set->bits;
11332 break;
11333
11334 case '-':
11335 newmode &= ~set->bits;
11336 break;
11337
11338 case 'X':
11339 if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
11340 newmode |= set->bits;
11341 break;
11342
11343 case '\0':
11344 default:
11345#ifdef SETMODE_DEBUG
11346 (void)printf("getmode:%04o -> %04o\n", omode, newmode);
11347#endif
11348 return (newmode);
11349 }
11350}
11351
Eric Andersen2870d962001-07-02 17:27:21 +000011352#define ADDCMD(a, b, c, d) do { \
11353 if (set >= endset) { \
11354 BITCMD *newset; \
11355 setlen += SET_LEN_INCR; \
11356 newset = realloc(saveset, sizeof(BITCMD) * setlen); \
11357 if (newset == NULL) { \
11358 free(saveset); \
11359 return (NULL); \
11360 } \
11361 set = newset + (set - saveset); \
11362 saveset = newset; \
11363 endset = newset + (setlen - 2); \
11364 } \
11365 set = addcmd(set, (a), (b), (c), (d)); \
Eric Andersencb57d552001-06-28 07:25:16 +000011366} while (/*CONSTCOND*/0)
11367
Eric Andersen2870d962001-07-02 17:27:21 +000011368#define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
Eric Andersencb57d552001-06-28 07:25:16 +000011369
11370static void *
11371setmode(p)
11372 const char *p;
11373{
11374 int perm, who;
11375 char op, *ep;
11376 BITCMD *set, *saveset, *endset;
11377 sigset_t mysigset, sigoset;
11378 mode_t mask;
Eric Andersen2870d962001-07-02 17:27:21 +000011379 int equalopdone = 0; /* pacify gcc */
Eric Andersencb57d552001-06-28 07:25:16 +000011380 int permXbits, setlen;
11381
11382 if (!*p)
11383 return (NULL);
11384
11385 /*
11386 * Get a copy of the mask for the permissions that are mask relative.
11387 * Flip the bits, we want what's not set. Since it's possible that
11388 * the caller is opening files inside a signal handler, protect them
11389 * as best we can.
11390 */
11391 sigfillset(&mysigset);
11392 (void)sigprocmask(SIG_BLOCK, &mysigset, &sigoset);
11393 (void)umask(mask = umask(0));
11394 mask = ~mask;
11395 (void)sigprocmask(SIG_SETMASK, &sigoset, NULL);
11396
11397 setlen = SET_LEN + 2;
Eric Andersen2870d962001-07-02 17:27:21 +000011398
Eric Andersencb57d552001-06-28 07:25:16 +000011399 if ((set = malloc((u_int)(sizeof(BITCMD) * setlen))) == NULL)
11400 return (NULL);
11401 saveset = set;
11402 endset = set + (setlen - 2);
11403
11404 /*
11405 * If an absolute number, get it and return; disallow non-octal digits
11406 * or illegal bits.
11407 */
Eric Andersen62483552001-07-10 06:09:16 +000011408 if (is_digit((unsigned char)*p)) {
Eric Andersencb57d552001-06-28 07:25:16 +000011409 perm = (mode_t)strtol(p, &ep, 8);
11410 if (*ep || perm & ~(STANDARD_BITS|S_ISTXT)) {
11411 free(saveset);
11412 return (NULL);
11413 }
11414 ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask);
11415 set->cmd = 0;
11416 return (saveset);
11417 }
11418
11419 /*
11420 * Build list of structures to set/clear/copy bits as described by
11421 * each clause of the symbolic mode.
11422 */
11423 for (;;) {
11424 /* First, find out which bits might be modified. */
11425 for (who = 0;; ++p) {
11426 switch (*p) {
11427 case 'a':
11428 who |= STANDARD_BITS;
11429 break;
11430 case 'u':
11431 who |= S_ISUID|S_IRWXU;
11432 break;
11433 case 'g':
11434 who |= S_ISGID|S_IRWXG;
11435 break;
11436 case 'o':
11437 who |= S_IRWXO;
11438 break;
11439 default:
11440 goto getop;
11441 }
11442 }
11443
Eric Andersen2870d962001-07-02 17:27:21 +000011444getop: if ((op = *p++) != '+' && op != '-' && op != '=') {
Eric Andersencb57d552001-06-28 07:25:16 +000011445 free(saveset);
11446 return (NULL);
11447 }
11448 if (op == '=')
11449 equalopdone = 0;
11450
11451 who &= ~S_ISTXT;
11452 for (perm = 0, permXbits = 0;; ++p) {
11453 switch (*p) {
11454 case 'r':
11455 perm |= S_IRUSR|S_IRGRP|S_IROTH;
11456 break;
11457 case 's':
11458 /*
Eric Andersen2870d962001-07-02 17:27:21 +000011459 * If specific bits where requested and
11460 * only "other" bits ignore set-id.
Eric Andersencb57d552001-06-28 07:25:16 +000011461 */
11462 if (who == 0 || (who & ~S_IRWXO))
11463 perm |= S_ISUID|S_ISGID;
11464 break;
11465 case 't':
11466 /*
Eric Andersen2870d962001-07-02 17:27:21 +000011467 * If specific bits where requested and
11468 * only "other" bits ignore set-id.
Eric Andersencb57d552001-06-28 07:25:16 +000011469 */
11470 if (who == 0 || (who & ~S_IRWXO)) {
11471 who |= S_ISTXT;
11472 perm |= S_ISTXT;
11473 }
11474 break;
11475 case 'w':
11476 perm |= S_IWUSR|S_IWGRP|S_IWOTH;
11477 break;
11478 case 'X':
11479 permXbits = S_IXUSR|S_IXGRP|S_IXOTH;
11480 break;
11481 case 'x':
11482 perm |= S_IXUSR|S_IXGRP|S_IXOTH;
11483 break;
11484 case 'u':
11485 case 'g':
11486 case 'o':
11487 /*
11488 * When ever we hit 'u', 'g', or 'o', we have
11489 * to flush out any partial mode that we have,
11490 * and then do the copying of the mode bits.
11491 */
11492 if (perm) {
11493 ADDCMD(op, who, perm, mask);
11494 perm = 0;
11495 }
11496 if (op == '=')
11497 equalopdone = 1;
11498 if (op == '+' && permXbits) {
11499 ADDCMD('X', who, permXbits, mask);
11500 permXbits = 0;
11501 }
11502 ADDCMD(*p, who, op, mask);
11503 break;
11504
11505 default:
11506 /*
11507 * Add any permissions that we haven't already
11508 * done.
11509 */
11510 if (perm || (op == '=' && !equalopdone)) {
11511 if (op == '=')
11512 equalopdone = 1;
11513 ADDCMD(op, who, perm, mask);
11514 perm = 0;
11515 }
11516 if (permXbits) {
11517 ADDCMD('X', who, permXbits, mask);
11518 permXbits = 0;
11519 }
11520 goto apply;
11521 }
11522 }
11523
Eric Andersen2870d962001-07-02 17:27:21 +000011524apply: if (!*p)
Eric Andersencb57d552001-06-28 07:25:16 +000011525 break;
11526 if (*p != ',')
11527 goto getop;
11528 ++p;
11529 }
11530 set->cmd = 0;
11531#ifdef SETMODE_DEBUG
11532 (void)printf("Before compress_mode()\n");
11533 dumpmode(saveset);
11534#endif
11535 compress_mode(saveset);
11536#ifdef SETMODE_DEBUG
11537 (void)printf("After compress_mode()\n");
11538 dumpmode(saveset);
11539#endif
11540 return (saveset);
11541}
11542
11543static BITCMD *
11544addcmd(set, op, who, oparg, mask)
11545 BITCMD *set;
11546 int oparg, who;
11547 int op;
11548 u_int mask;
11549{
11550
11551 _DIAGASSERT(set != NULL);
11552
11553 switch (op) {
11554 case '=':
11555 set->cmd = '-';
11556 set->bits = who ? who : STANDARD_BITS;
11557 set++;
11558
11559 op = '+';
11560 /* FALLTHROUGH */
11561 case '+':
11562 case '-':
11563 case 'X':
11564 set->cmd = op;
11565 set->bits = (who ? who : mask) & oparg;
11566 break;
11567
11568 case 'u':
11569 case 'g':
11570 case 'o':
11571 set->cmd = op;
11572 if (who) {
11573 set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) |
11574 ((who & S_IRGRP) ? CMD2_GBITS : 0) |
11575 ((who & S_IROTH) ? CMD2_OBITS : 0);
11576 set->bits = (mode_t)~0;
11577 } else {
11578 set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS;
11579 set->bits = mask;
11580 }
Eric Andersen2870d962001-07-02 17:27:21 +000011581
Eric Andersencb57d552001-06-28 07:25:16 +000011582 if (oparg == '+')
11583 set->cmd2 |= CMD2_SET;
11584 else if (oparg == '-')
11585 set->cmd2 |= CMD2_CLR;
11586 else if (oparg == '=')
11587 set->cmd2 |= CMD2_SET|CMD2_CLR;
11588 break;
11589 }
11590 return (set + 1);
11591}
11592
11593#ifdef SETMODE_DEBUG
11594static void
11595dumpmode(set)
11596 BITCMD *set;
11597{
11598
11599 _DIAGASSERT(set != NULL);
11600
11601 for (; set->cmd; ++set)
11602 (void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n",
11603 set->cmd, set->bits, set->cmd2 ? " cmd2:" : "",
11604 set->cmd2 & CMD2_CLR ? " CLR" : "",
11605 set->cmd2 & CMD2_SET ? " SET" : "",
11606 set->cmd2 & CMD2_UBITS ? " UBITS" : "",
11607 set->cmd2 & CMD2_GBITS ? " GBITS" : "",
11608 set->cmd2 & CMD2_OBITS ? " OBITS" : "");
11609}
11610#endif
11611
11612/*
11613 * Given an array of bitcmd structures, compress by compacting consecutive
11614 * '+', '-' and 'X' commands into at most 3 commands, one of each. The 'u',
Eric Andersen2870d962001-07-02 17:27:21 +000011615 * 'g' and 'o' commands continue to be separate. They could probably be
Eric Andersencb57d552001-06-28 07:25:16 +000011616 * compacted, but it's not worth the effort.
11617 */
11618static void
11619compress_mode(set)
11620 BITCMD *set;
11621{
11622 BITCMD *nset;
11623 int setbits, clrbits, Xbits, op;
11624
11625 _DIAGASSERT(set != NULL);
11626
11627 for (nset = set;;) {
11628 /* Copy over any 'u', 'g' and 'o' commands. */
11629 while ((op = nset->cmd) != '+' && op != '-' && op != 'X') {
11630 *set++ = *nset++;
11631 if (!op)
11632 return;
11633 }
11634
11635 for (setbits = clrbits = Xbits = 0;; nset++) {
11636 if ((op = nset->cmd) == '-') {
11637 clrbits |= nset->bits;
11638 setbits &= ~nset->bits;
11639 Xbits &= ~nset->bits;
11640 } else if (op == '+') {
11641 setbits |= nset->bits;
11642 clrbits &= ~nset->bits;
11643 Xbits &= ~nset->bits;
11644 } else if (op == 'X')
11645 Xbits |= nset->bits & ~setbits;
11646 else
11647 break;
11648 }
11649 if (clrbits) {
11650 set->cmd = '-';
11651 set->cmd2 = 0;
11652 set->bits = clrbits;
11653 set++;
11654 }
11655 if (setbits) {
11656 set->cmd = '+';
11657 set->cmd2 = 0;
11658 set->bits = setbits;
11659 set++;
11660 }
11661 if (Xbits) {
11662 set->cmd = 'X';
11663 set->cmd2 = 0;
11664 set->bits = Xbits;
11665 set++;
11666 }
11667 }
11668}
Eric Andersencb57d552001-06-28 07:25:16 +000011669#ifdef DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +000011670static void shtree (union node *, int, char *, FILE*);
11671static void shcmd (union node *, FILE *);
11672static void sharg (union node *, FILE *);
11673static void indent (int, char *, FILE *);
11674static void trstring (char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011675
11676
11677static void
11678showtree(n)
11679 union node *n;
11680{
11681 trputs("showtree called\n");
11682 shtree(n, 1, NULL, stdout);
11683}
11684
11685
11686static void
11687shtree(n, ind, pfx, fp)
11688 union node *n;
11689 int ind;
11690 char *pfx;
11691 FILE *fp;
11692{
11693 struct nodelist *lp;
11694 const char *s;
11695
11696 if (n == NULL)
11697 return;
11698
11699 indent(ind, pfx, fp);
11700 switch(n->type) {
11701 case NSEMI:
11702 s = "; ";
11703 goto binop;
11704 case NAND:
11705 s = " && ";
11706 goto binop;
11707 case NOR:
11708 s = " || ";
11709binop:
11710 shtree(n->nbinary.ch1, ind, NULL, fp);
11711 /* if (ind < 0) */
11712 fputs(s, fp);
11713 shtree(n->nbinary.ch2, ind, NULL, fp);
11714 break;
11715 case NCMD:
11716 shcmd(n, fp);
11717 if (ind >= 0)
11718 putc('\n', fp);
11719 break;
11720 case NPIPE:
11721 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11722 shcmd(lp->n, fp);
11723 if (lp->next)
11724 fputs(" | ", fp);
11725 }
11726 if (n->npipe.backgnd)
11727 fputs(" &", fp);
11728 if (ind >= 0)
11729 putc('\n', fp);
11730 break;
11731 default:
11732 fprintf(fp, "<node type %d>", n->type);
11733 if (ind >= 0)
11734 putc('\n', fp);
11735 break;
11736 }
11737}
11738
11739
11740
11741static void
11742shcmd(cmd, fp)
11743 union node *cmd;
11744 FILE *fp;
11745{
11746 union node *np;
11747 int first;
11748 const char *s;
11749 int dftfd;
11750
11751 first = 1;
11752 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11753 if (! first)
11754 putchar(' ');
11755 sharg(np, fp);
11756 first = 0;
11757 }
11758 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11759 if (! first)
11760 putchar(' ');
11761 switch (np->nfile.type) {
Eric Andersen2870d962001-07-02 17:27:21 +000011762 case NTO: s = ">"; dftfd = 1; break;
11763 case NAPPEND: s = ">>"; dftfd = 1; break;
11764 case NTOFD: s = ">&"; dftfd = 1; break;
11765 case NTOOV: s = ">|"; dftfd = 1; break;
11766 case NFROM: s = "<"; dftfd = 0; break;
11767 case NFROMFD: s = "<&"; dftfd = 0; break;
11768 case NFROMTO: s = "<>"; dftfd = 0; break;
11769 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011770 }
11771 if (np->nfile.fd != dftfd)
11772 fprintf(fp, "%d", np->nfile.fd);
11773 fputs(s, fp);
11774 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11775 fprintf(fp, "%d", np->ndup.dupfd);
11776 } else {
11777 sharg(np->nfile.fname, fp);
11778 }
11779 first = 0;
11780 }
11781}
11782
11783
11784
11785static void
11786sharg(arg, fp)
11787 union node *arg;
11788 FILE *fp;
11789 {
11790 char *p;
11791 struct nodelist *bqlist;
11792 int subtype;
11793
11794 if (arg->type != NARG) {
11795 printf("<node type %d>\n", arg->type);
11796 fflush(stdout);
11797 abort();
11798 }
11799 bqlist = arg->narg.backquote;
11800 for (p = arg->narg.text ; *p ; p++) {
11801 switch (*p) {
11802 case CTLESC:
11803 putc(*++p, fp);
11804 break;
11805 case CTLVAR:
11806 putc('$', fp);
11807 putc('{', fp);
11808 subtype = *++p;
11809 if (subtype == VSLENGTH)
11810 putc('#', fp);
11811
11812 while (*p != '=')
11813 putc(*p++, fp);
11814
11815 if (subtype & VSNUL)
11816 putc(':', fp);
11817
11818 switch (subtype & VSTYPE) {
11819 case VSNORMAL:
11820 putc('}', fp);
11821 break;
11822 case VSMINUS:
11823 putc('-', fp);
11824 break;
11825 case VSPLUS:
11826 putc('+', fp);
11827 break;
11828 case VSQUESTION:
11829 putc('?', fp);
11830 break;
11831 case VSASSIGN:
11832 putc('=', fp);
11833 break;
11834 case VSTRIMLEFT:
11835 putc('#', fp);
11836 break;
11837 case VSTRIMLEFTMAX:
11838 putc('#', fp);
11839 putc('#', fp);
11840 break;
11841 case VSTRIMRIGHT:
11842 putc('%', fp);
11843 break;
11844 case VSTRIMRIGHTMAX:
11845 putc('%', fp);
11846 putc('%', fp);
11847 break;
11848 case VSLENGTH:
11849 break;
11850 default:
11851 printf("<subtype %d>", subtype);
11852 }
11853 break;
11854 case CTLENDVAR:
11855 putc('}', fp);
11856 break;
11857 case CTLBACKQ:
11858 case CTLBACKQ|CTLQUOTE:
11859 putc('$', fp);
11860 putc('(', fp);
11861 shtree(bqlist->n, -1, NULL, fp);
11862 putc(')', fp);
11863 break;
11864 default:
11865 putc(*p, fp);
11866 break;
11867 }
11868 }
11869}
11870
11871
11872static void
11873indent(amount, pfx, fp)
11874 int amount;
11875 char *pfx;
11876 FILE *fp;
11877{
11878 int i;
11879
11880 for (i = 0 ; i < amount ; i++) {
11881 if (pfx && i == amount - 1)
11882 fputs(pfx, fp);
11883 putc('\t', fp);
11884 }
11885}
11886#endif
11887
11888
11889
11890/*
11891 * Debugging stuff.
11892 */
11893
11894
11895#ifdef DEBUG
11896FILE *tracefile;
11897
11898#if DEBUG == 2
11899static int debug = 1;
11900#else
11901static int debug = 0;
11902#endif
11903
11904
11905static void
11906trputc(c)
11907 int c;
11908{
11909 if (tracefile == NULL)
11910 return;
11911 putc(c, tracefile);
11912 if (c == '\n')
11913 fflush(tracefile);
11914}
11915
11916static void
11917trace(const char *fmt, ...)
11918{
11919 va_list va;
Eric Andersencb57d552001-06-28 07:25:16 +000011920 va_start(va, fmt);
Eric Andersencb57d552001-06-28 07:25:16 +000011921 if (tracefile != NULL) {
11922 (void) vfprintf(tracefile, fmt, va);
11923 if (strchr(fmt, '\n'))
11924 (void) fflush(tracefile);
11925 }
11926 va_end(va);
11927}
11928
11929
11930static void
11931trputs(s)
11932 const char *s;
11933{
11934 if (tracefile == NULL)
11935 return;
11936 fputs(s, tracefile);
11937 if (strchr(s, '\n'))
11938 fflush(tracefile);
11939}
11940
11941
11942static void
11943trstring(s)
11944 char *s;
11945{
11946 char *p;
11947 char c;
11948
11949 if (tracefile == NULL)
11950 return;
11951 putc('"', tracefile);
11952 for (p = s ; *p ; p++) {
11953 switch (*p) {
11954 case '\n': c = 'n'; goto backslash;
11955 case '\t': c = 't'; goto backslash;
11956 case '\r': c = 'r'; goto backslash;
11957 case '"': c = '"'; goto backslash;
11958 case '\\': c = '\\'; goto backslash;
11959 case CTLESC: c = 'e'; goto backslash;
11960 case CTLVAR: c = 'v'; goto backslash;
11961 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11962 case CTLBACKQ: c = 'q'; goto backslash;
11963 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
Eric Andersen2870d962001-07-02 17:27:21 +000011964backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011965 putc(c, tracefile);
11966 break;
11967 default:
11968 if (*p >= ' ' && *p <= '~')
11969 putc(*p, tracefile);
11970 else {
11971 putc('\\', tracefile);
11972 putc(*p >> 6 & 03, tracefile);
11973 putc(*p >> 3 & 07, tracefile);
11974 putc(*p & 07, tracefile);
11975 }
11976 break;
11977 }
11978 }
11979 putc('"', tracefile);
11980}
11981
11982
11983static void
11984trargs(ap)
11985 char **ap;
11986{
11987 if (tracefile == NULL)
11988 return;
11989 while (*ap) {
11990 trstring(*ap++);
11991 if (*ap)
11992 putc(' ', tracefile);
11993 else
11994 putc('\n', tracefile);
11995 }
11996 fflush(tracefile);
11997}
11998
11999
12000static void
12001opentrace() {
12002 char s[100];
12003#ifdef O_APPEND
12004 int flags;
12005#endif
12006
12007 if (!debug)
12008 return;
12009#ifdef not_this_way
12010 {
12011 char *p;
12012 if ((p = getenv("HOME")) == NULL) {
12013 if (geteuid() == 0)
12014 p = "/";
12015 else
12016 p = "/tmp";
12017 }
Eric Andersen2870d962001-07-02 17:27:21 +000012018 strcpy(s, p);
Eric Andersencb57d552001-06-28 07:25:16 +000012019 strcat(s, "/trace");
12020 }
12021#else
Eric Andersen2870d962001-07-02 17:27:21 +000012022 strcpy(s, "./trace");
Eric Andersencb57d552001-06-28 07:25:16 +000012023#endif /* not_this_way */
12024 if ((tracefile = fopen(s, "a")) == NULL) {
12025 fprintf(stderr, "Can't open %s\n", s);
12026 return;
12027 }
12028#ifdef O_APPEND
12029 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
12030 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
12031#endif
12032 fputs("\nTracing started.\n", tracefile);
12033 fflush(tracefile);
12034}
12035#endif /* DEBUG */
12036
12037
12038/*
Eric Andersencb57d552001-06-28 07:25:16 +000012039 * The trap builtin.
12040 */
12041
12042static int
12043trapcmd(argc, argv)
12044 int argc;
12045 char **argv;
12046{
12047 char *action;
12048 char **ap;
12049 int signo;
12050
12051 if (argc <= 1) {
12052 for (signo = 0 ; signo < NSIG ; signo++) {
12053 if (trap[signo] != NULL) {
12054 char *p;
12055
12056 p = single_quote(trap[signo]);
Eric Andersen62483552001-07-10 06:09:16 +000012057 printf("trap -- %s %s\n", p,
Eric Andersencb57d552001-06-28 07:25:16 +000012058 signal_names[signo] + (signo ? 3 : 0)
12059 );
12060 stunalloc(p);
12061 }
12062 }
12063 return 0;
12064 }
12065 ap = argv + 1;
12066 if (argc == 2)
12067 action = NULL;
12068 else
12069 action = *ap++;
12070 while (*ap) {
12071 if ((signo = decode_signal(*ap, 0)) < 0)
12072 error("%s: bad trap", *ap);
12073 INTOFF;
12074 if (action) {
12075 if (action[0] == '-' && action[1] == '\0')
12076 action = NULL;
12077 else
12078 action = savestr(action);
12079 }
12080 if (trap[signo])
12081 ckfree(trap[signo]);
12082 trap[signo] = action;
12083 if (signo != 0)
12084 setsignal(signo);
12085 INTON;
12086 ap++;
12087 }
12088 return 0;
12089}
12090
12091
12092
Eric Andersencb57d552001-06-28 07:25:16 +000012093
12094
12095
12096/*
12097 * Set the signal handler for the specified signal. The routine figures
12098 * out what it should be set to.
12099 */
12100
12101static void
Eric Andersen2870d962001-07-02 17:27:21 +000012102setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000012103{
12104 int action;
12105 char *t;
12106 struct sigaction act;
12107
12108 if ((t = trap[signo]) == NULL)
12109 action = S_DFL;
12110 else if (*t != '\0')
12111 action = S_CATCH;
12112 else
12113 action = S_IGN;
12114 if (rootshell && action == S_DFL) {
12115 switch (signo) {
12116 case SIGINT:
12117 if (iflag || minusc || sflag == 0)
12118 action = S_CATCH;
12119 break;
12120 case SIGQUIT:
12121#ifdef DEBUG
12122 {
Eric Andersencb57d552001-06-28 07:25:16 +000012123
12124 if (debug)
12125 break;
12126 }
12127#endif
12128 /* FALLTHROUGH */
12129 case SIGTERM:
12130 if (iflag)
12131 action = S_IGN;
12132 break;
Eric Andersen2870d962001-07-02 17:27:21 +000012133#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000012134 case SIGTSTP:
12135 case SIGTTOU:
12136 if (mflag)
12137 action = S_IGN;
12138 break;
12139#endif
12140 }
12141 }
12142
12143 t = &sigmode[signo - 1];
12144 if (*t == 0) {
12145 /*
12146 * current setting unknown
12147 */
12148 if (sigaction(signo, 0, &act) == -1) {
12149 /*
12150 * Pretend it worked; maybe we should give a warning
12151 * here, but other shells don't. We don't alter
12152 * sigmode, so that we retry every time.
12153 */
12154 return;
12155 }
12156 if (act.sa_handler == SIG_IGN) {
12157 if (mflag && (signo == SIGTSTP ||
12158 signo == SIGTTIN || signo == SIGTTOU)) {
Eric Andersen2870d962001-07-02 17:27:21 +000012159 *t = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000012160 } else
12161 *t = S_HARD_IGN;
12162 } else {
Eric Andersen2870d962001-07-02 17:27:21 +000012163 *t = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000012164 }
12165 }
12166 if (*t == S_HARD_IGN || *t == action)
12167 return;
12168 switch (action) {
12169 case S_CATCH:
12170 act.sa_handler = onsig;
12171 break;
12172 case S_IGN:
12173 act.sa_handler = SIG_IGN;
12174 break;
12175 default:
12176 act.sa_handler = SIG_DFL;
12177 }
12178 *t = action;
12179 act.sa_flags = 0;
12180 sigemptyset(&act.sa_mask);
12181 sigaction(signo, &act, 0);
12182}
12183
12184/*
12185 * Ignore a signal.
12186 */
12187
12188static void
12189ignoresig(signo)
12190 int signo;
12191{
12192 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
12193 signal(signo, SIG_IGN);
12194 }
12195 sigmode[signo - 1] = S_HARD_IGN;
12196}
12197
12198
Eric Andersencb57d552001-06-28 07:25:16 +000012199/*
12200 * Signal handler.
12201 */
12202
12203static void
Eric Andersen2870d962001-07-02 17:27:21 +000012204onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000012205{
12206 if (signo == SIGINT && trap[SIGINT] == NULL) {
12207 onint();
12208 return;
12209 }
12210 gotsig[signo - 1] = 1;
12211 pendingsigs++;
12212}
12213
12214
Eric Andersencb57d552001-06-28 07:25:16 +000012215/*
12216 * Called to execute a trap. Perhaps we should avoid entering new trap
12217 * handlers while we are executing a trap handler.
12218 */
12219
12220static void
Eric Andersen2870d962001-07-02 17:27:21 +000012221dotrap(void)
12222{
Eric Andersencb57d552001-06-28 07:25:16 +000012223 int i;
12224 int savestatus;
12225
12226 for (;;) {
12227 for (i = 1 ; ; i++) {
12228 if (gotsig[i - 1])
12229 break;
12230 if (i >= NSIG - 1)
12231 goto done;
12232 }
12233 gotsig[i - 1] = 0;
12234 savestatus=exitstatus;
12235 evalstring(trap[i], 0);
12236 exitstatus=savestatus;
12237 }
12238done:
12239 pendingsigs = 0;
12240}
12241
Eric Andersencb57d552001-06-28 07:25:16 +000012242/*
12243 * Called to exit the shell.
12244 */
12245
12246static void
Eric Andersen2870d962001-07-02 17:27:21 +000012247exitshell(int status)
Eric Andersencb57d552001-06-28 07:25:16 +000012248{
12249 struct jmploc loc1, loc2;
12250 char *p;
12251
12252 TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
12253 if (setjmp(loc1.loc)) {
12254 goto l1;
12255 }
12256 if (setjmp(loc2.loc)) {
12257 goto l2;
12258 }
12259 handler = &loc1;
12260 if ((p = trap[0]) != NULL && *p != '\0') {
12261 trap[0] = NULL;
12262 evalstring(p, 0);
12263 }
Eric Andersen2870d962001-07-02 17:27:21 +000012264l1: handler = &loc2; /* probably unnecessary */
Eric Andersencb57d552001-06-28 07:25:16 +000012265 flushall();
Eric Andersen2870d962001-07-02 17:27:21 +000012266#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000012267 setjobctl(0);
12268#endif
12269l2: _exit(status);
12270 /* NOTREACHED */
12271}
12272
12273static int decode_signal(const char *string, int minsig)
12274{
12275 int signo;
12276
Eric Andersen2870d962001-07-02 17:27:21 +000012277 if (is_number(string, &signo)) {
Eric Andersencb57d552001-06-28 07:25:16 +000012278 if (signo >= NSIG) {
12279 return -1;
12280 }
12281 return signo;
12282 }
12283
12284 signo = minsig;
12285 if (!signo) {
12286 goto zero;
12287 }
12288 for (; signo < NSIG; signo++) {
12289 if (!strcasecmp(string, &(signal_names[signo])[3])) {
12290 return signo;
12291 }
12292zero:
12293 if (!strcasecmp(string, signal_names[signo])) {
12294 return signo;
12295 }
12296 }
12297
12298 return -1;
12299}
Eric Andersen2870d962001-07-02 17:27:21 +000012300static struct var **hashvar (const char *);
12301static void showvars (const char *, int, int);
12302static struct var **findvar (struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000012303
12304/*
12305 * Initialize the varable symbol tables and import the environment
12306 */
12307
Eric Andersencb57d552001-06-28 07:25:16 +000012308/*
12309 * This routine initializes the builtin variables. It is called when the
12310 * shell is initialized and again when a shell procedure is spawned.
12311 */
12312
12313static void
12314initvar() {
12315 const struct varinit *ip;
12316 struct var *vp;
12317 struct var **vpp;
12318
12319 for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
12320 if ((vp->flags & VEXPORT) == 0) {
12321 vpp = hashvar(ip->text);
12322 vp->next = *vpp;
12323 *vpp = vp;
12324 vp->text = strdup(ip->text);
12325 vp->flags = ip->flags;
12326 vp->func = ip->func;
12327 }
12328 }
12329 /*
12330 * PS1 depends on uid
12331 */
12332 if ((vps1.flags & VEXPORT) == 0) {
12333 vpp = hashvar("PS1=");
12334 vps1.next = *vpp;
12335 *vpp = &vps1;
12336 vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# ");
12337 vps1.flags = VSTRFIXED|VTEXTFIXED;
12338 }
12339}
12340
12341/*
12342 * Set the value of a variable. The flags argument is ored with the
12343 * flags of the variable. If val is NULL, the variable is unset.
12344 */
12345
12346static void
12347setvar(name, val, flags)
12348 const char *name, *val;
12349 int flags;
12350{
12351 const char *p;
12352 int len;
12353 int namelen;
12354 char *nameeq;
12355 int isbad;
12356 int vallen = 0;
12357
12358 isbad = 0;
12359 p = name;
12360 if (! is_name(*p))
12361 isbad = 1;
12362 p++;
12363 for (;;) {
12364 if (! is_in_name(*p)) {
12365 if (*p == '\0' || *p == '=')
12366 break;
12367 isbad = 1;
12368 }
12369 p++;
12370 }
12371 namelen = p - name;
12372 if (isbad)
12373 error("%.*s: bad variable name", namelen, name);
Eric Andersen2870d962001-07-02 17:27:21 +000012374 len = namelen + 2; /* 2 is space for '=' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +000012375 if (val == NULL) {
12376 flags |= VUNSET;
12377 } else {
12378 len += vallen = strlen(val);
12379 }
12380 INTOFF;
12381 nameeq = ckmalloc(len);
12382 memcpy(nameeq, name, namelen);
12383 nameeq[namelen] = '=';
12384 if (val) {
12385 memcpy(nameeq + namelen + 1, val, vallen + 1);
12386 } else {
12387 nameeq[namelen + 1] = '\0';
12388 }
12389 setvareq(nameeq, flags);
12390 INTON;
12391}
12392
12393
12394
12395/*
12396 * Same as setvar except that the variable and value are passed in
12397 * the first argument as name=value. Since the first argument will
12398 * be actually stored in the table, it should not be a string that
12399 * will go away.
12400 */
12401
12402static void
12403setvareq(s, flags)
12404 char *s;
12405 int flags;
12406{
12407 struct var *vp, **vpp;
12408
12409 vpp = hashvar(s);
12410 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
12411 if ((vp = *findvar(vpp, s))) {
12412 if (vp->flags & VREADONLY) {
12413 size_t len = strchr(s, '=') - s;
12414 error("%.*s: is read only", len, s);
12415 }
12416 INTOFF;
12417
12418 if (vp->func && (flags & VNOFUNC) == 0)
12419 (*vp->func)(strchr(s, '=') + 1);
12420
12421 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12422 ckfree(vp->text);
12423
12424 vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
12425 vp->flags |= flags;
12426 vp->text = s;
12427
12428 /*
12429 * We could roll this to a function, to handle it as
12430 * a regular variable function callback, but why bother?
12431 */
12432 if (iflag && (vp == &vmpath || (vp == &vmail && !mpathset())))
12433 chkmail(1);
12434 INTON;
12435 return;
12436 }
12437 /* not found */
12438 vp = ckmalloc(sizeof (*vp));
12439 vp->flags = flags;
12440 vp->text = s;
12441 vp->next = *vpp;
12442 vp->func = NULL;
12443 *vpp = vp;
12444}
12445
12446
12447
12448/*
12449 * Process a linked list of variable assignments.
12450 */
12451
12452static void
12453listsetvar(mylist)
12454 struct strlist *mylist;
12455 {
12456 struct strlist *lp;
12457
12458 INTOFF;
12459 for (lp = mylist ; lp ; lp = lp->next) {
12460 setvareq(savestr(lp->text), 0);
12461 }
12462 INTON;
12463}
12464
12465
12466
12467/*
12468 * Find the value of a variable. Returns NULL if not set.
12469 */
12470
Eric Andersen62483552001-07-10 06:09:16 +000012471static const char *
Eric Andersencb57d552001-06-28 07:25:16 +000012472lookupvar(name)
12473 const char *name;
12474 {
12475 struct var *v;
12476
12477 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
12478 return strchr(v->text, '=') + 1;
12479 }
12480 return NULL;
12481}
12482
12483
12484
12485/*
12486 * Search the environment of a builtin command.
12487 */
12488
Eric Andersen62483552001-07-10 06:09:16 +000012489static const char *
12490bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012491{
Eric Andersen62483552001-07-10 06:09:16 +000012492 const struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012493
12494 for (sp = cmdenviron ; sp ; sp = sp->next) {
12495 if (varequal(sp->text, name))
12496 return strchr(sp->text, '=') + 1;
12497 }
12498 return lookupvar(name);
12499}
12500
12501
12502
12503/*
12504 * Generate a list of exported variables. This routine is used to construct
12505 * the third argument to execve when executing a program.
12506 */
12507
12508static char **
12509environment() {
12510 int nenv;
12511 struct var **vpp;
12512 struct var *vp;
12513 char **env;
12514 char **ep;
12515
12516 nenv = 0;
12517 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12518 for (vp = *vpp ; vp ; vp = vp->next)
12519 if (vp->flags & VEXPORT)
12520 nenv++;
12521 }
12522 ep = env = stalloc((nenv + 1) * sizeof *env);
12523 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12524 for (vp = *vpp ; vp ; vp = vp->next)
12525 if (vp->flags & VEXPORT)
12526 *ep++ = vp->text;
12527 }
12528 *ep = NULL;
12529 return env;
12530}
12531
12532
12533/*
12534 * Called when a shell procedure is invoked to clear out nonexported
12535 * variables. It is also necessary to reallocate variables of with
12536 * VSTACK set since these are currently allocated on the stack.
12537 */
12538
Eric Andersencb57d552001-06-28 07:25:16 +000012539static void
Eric Andersen2870d962001-07-02 17:27:21 +000012540shprocvar(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000012541 struct var **vpp;
12542 struct var *vp, **prev;
12543
12544 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12545 for (prev = vpp ; (vp = *prev) != NULL ; ) {
12546 if ((vp->flags & VEXPORT) == 0) {
12547 *prev = vp->next;
12548 if ((vp->flags & VTEXTFIXED) == 0)
12549 ckfree(vp->text);
12550 if ((vp->flags & VSTRFIXED) == 0)
12551 ckfree(vp);
12552 } else {
12553 if (vp->flags & VSTACK) {
12554 vp->text = savestr(vp->text);
12555 vp->flags &=~ VSTACK;
12556 }
12557 prev = &vp->next;
12558 }
12559 }
12560 }
12561 initvar();
12562}
12563
12564
12565
12566/*
12567 * Command to list all variables which are set. Currently this command
12568 * is invoked from the set command when the set command is called without
12569 * any variables.
12570 */
12571
12572static int
12573showvarscmd(argc, argv)
12574 int argc;
12575 char **argv;
12576{
12577 showvars(nullstr, VUNSET, VUNSET);
12578 return 0;
12579}
12580
12581
12582
12583/*
12584 * The export and readonly commands.
12585 */
12586
12587static int
12588exportcmd(argc, argv)
12589 int argc;
12590 char **argv;
12591{
12592 struct var *vp;
12593 char *name;
12594 const char *p;
12595 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12596 int pflag;
12597
12598 listsetvar(cmdenviron);
12599 pflag = (nextopt("p") == 'p');
12600 if (argc > 1 && !pflag) {
12601 while ((name = *argptr++) != NULL) {
12602 if ((p = strchr(name, '=')) != NULL) {
12603 p++;
12604 } else {
12605 if ((vp = *findvar(hashvar(name), name))) {
12606 vp->flags |= flag;
12607 goto found;
12608 }
12609 }
12610 setvar(name, p, flag);
12611found:;
12612 }
12613 } else {
12614 showvars(argv[0], flag, 0);
12615 }
12616 return 0;
12617}
12618
Eric Andersencb57d552001-06-28 07:25:16 +000012619/*
12620 * The "local" command.
12621 */
12622
Eric Andersen2870d962001-07-02 17:27:21 +000012623/* funcnest nonzero if we are currently evaluating a function */
12624
Eric Andersencb57d552001-06-28 07:25:16 +000012625static int
12626localcmd(argc, argv)
12627 int argc;
12628 char **argv;
12629{
12630 char *name;
12631
Eric Andersen2870d962001-07-02 17:27:21 +000012632 if (! funcnest)
Eric Andersencb57d552001-06-28 07:25:16 +000012633 error("Not in a function");
12634 while ((name = *argptr++) != NULL) {
12635 mklocal(name);
12636 }
12637 return 0;
12638}
12639
12640
12641/*
12642 * Make a variable a local variable. When a variable is made local, it's
12643 * value and flags are saved in a localvar structure. The saved values
12644 * will be restored when the shell function returns. We handle the name
12645 * "-" as a special case.
12646 */
12647
12648static void
12649mklocal(name)
12650 char *name;
12651 {
12652 struct localvar *lvp;
12653 struct var **vpp;
12654 struct var *vp;
12655
12656 INTOFF;
12657 lvp = ckmalloc(sizeof (struct localvar));
12658 if (name[0] == '-' && name[1] == '\0') {
12659 char *p;
Eric Andersen2870d962001-07-02 17:27:21 +000012660 p = ckmalloc(sizeof optet_vals);
12661 lvp->text = memcpy(p, optet_vals, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000012662 vp = NULL;
12663 } else {
12664 vpp = hashvar(name);
12665 vp = *findvar(vpp, name);
12666 if (vp == NULL) {
12667 if (strchr(name, '='))
12668 setvareq(savestr(name), VSTRFIXED);
12669 else
12670 setvar(name, NULL, VSTRFIXED);
Eric Andersen2870d962001-07-02 17:27:21 +000012671 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012672 lvp->text = NULL;
12673 lvp->flags = VUNSET;
12674 } else {
12675 lvp->text = vp->text;
12676 lvp->flags = vp->flags;
12677 vp->flags |= VSTRFIXED|VTEXTFIXED;
12678 if (strchr(name, '='))
12679 setvareq(savestr(name), 0);
12680 }
12681 }
12682 lvp->vp = vp;
12683 lvp->next = localvars;
12684 localvars = lvp;
12685 INTON;
12686}
12687
12688
12689/*
12690 * Called after a function returns.
12691 */
12692
12693static void
12694poplocalvars() {
12695 struct localvar *lvp;
12696 struct var *vp;
12697
12698 while ((lvp = localvars) != NULL) {
12699 localvars = lvp->next;
12700 vp = lvp->vp;
Eric Andersen2870d962001-07-02 17:27:21 +000012701 if (vp == NULL) { /* $- saved */
12702 memcpy(optet_vals, lvp->text, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000012703 ckfree(lvp->text);
12704 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12705 (void)unsetvar(vp->text);
12706 } else {
12707 if ((vp->flags & VTEXTFIXED) == 0)
12708 ckfree(vp->text);
12709 vp->flags = lvp->flags;
12710 vp->text = lvp->text;
12711 }
12712 ckfree(lvp);
12713 }
12714}
12715
12716
12717static int
12718setvarcmd(argc, argv)
12719 int argc;
12720 char **argv;
12721{
12722 if (argc <= 2)
12723 return unsetcmd(argc, argv);
12724 else if (argc == 3)
12725 setvar(argv[1], argv[2], 0);
12726 else
12727 error("List assignment not implemented");
12728 return 0;
12729}
12730
12731
12732/*
12733 * The unset builtin command. We unset the function before we unset the
12734 * variable to allow a function to be unset when there is a readonly variable
12735 * with the same name.
12736 */
12737
12738static int
12739unsetcmd(argc, argv)
12740 int argc;
12741 char **argv;
12742{
12743 char **ap;
12744 int i;
12745 int flg_func = 0;
12746 int flg_var = 0;
12747 int ret = 0;
12748
12749 while ((i = nextopt("vf")) != '\0') {
12750 if (i == 'f')
12751 flg_func = 1;
12752 else
12753 flg_var = 1;
12754 }
12755 if (flg_func == 0 && flg_var == 0)
12756 flg_var = 1;
12757
12758 for (ap = argptr; *ap ; ap++) {
12759 if (flg_func)
12760 unsetfunc(*ap);
12761 if (flg_var)
12762 ret |= unsetvar(*ap);
12763 }
12764 return ret;
12765}
12766
12767
12768/*
12769 * Unset the specified variable.
12770 */
12771
12772static int
Eric Andersen62483552001-07-10 06:09:16 +000012773unsetvar(const char *s)
12774{
Eric Andersencb57d552001-06-28 07:25:16 +000012775 struct var **vpp;
12776 struct var *vp;
12777
12778 vpp = findvar(hashvar(s), s);
12779 vp = *vpp;
12780 if (vp) {
12781 if (vp->flags & VREADONLY)
12782 return (1);
12783 INTOFF;
12784 if (*(strchr(vp->text, '=') + 1) != '\0')
12785 setvar(s, nullstr, 0);
12786 vp->flags &= ~VEXPORT;
12787 vp->flags |= VUNSET;
12788 if ((vp->flags & VSTRFIXED) == 0) {
12789 if ((vp->flags & VTEXTFIXED) == 0)
12790 ckfree(vp->text);
12791 *vpp = vp->next;
12792 ckfree(vp);
12793 }
12794 INTON;
12795 return (0);
12796 }
12797
12798 return (0);
12799}
12800
12801
12802
12803/*
12804 * Find the appropriate entry in the hash table from the name.
12805 */
12806
12807static struct var **
Eric Andersen62483552001-07-10 06:09:16 +000012808hashvar(const char *p)
12809{
Eric Andersencb57d552001-06-28 07:25:16 +000012810 unsigned int hashval;
12811
12812 hashval = ((unsigned char) *p) << 4;
12813 while (*p && *p != '=')
12814 hashval += (unsigned char) *p++;
12815 return &vartab[hashval % VTABSIZE];
12816}
12817
12818
12819
12820/*
12821 * Returns true if the two strings specify the same varable. The first
12822 * variable name is terminated by '='; the second may be terminated by
12823 * either '=' or '\0'.
12824 */
12825
12826static int
Eric Andersen62483552001-07-10 06:09:16 +000012827varequal(const char *p, const char *q)
12828{
Eric Andersencb57d552001-06-28 07:25:16 +000012829 while (*p == *q++) {
12830 if (*p++ == '=')
12831 return 1;
12832 }
12833 if (*p == '=' && *(q - 1) == '\0')
12834 return 1;
12835 return 0;
12836}
12837
12838static void
12839showvars(const char *myprefix, int mask, int xor)
12840{
12841 struct var **vpp;
12842 struct var *vp;
12843 const char *sep = myprefix == nullstr ? myprefix : spcstr;
12844
12845 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12846 for (vp = *vpp ; vp ; vp = vp->next) {
12847 if ((vp->flags & mask) ^ xor) {
12848 char *p;
12849 int len;
12850
12851 p = strchr(vp->text, '=') + 1;
12852 len = p - vp->text;
12853 p = single_quote(p);
12854
Eric Andersen62483552001-07-10 06:09:16 +000012855 printf("%s%s%.*s%s\n", myprefix, sep, len,
12856 vp->text, p);
Eric Andersencb57d552001-06-28 07:25:16 +000012857 stunalloc(p);
12858 }
12859 }
12860 }
12861}
12862
12863static struct var **
12864findvar(struct var **vpp, const char *name)
12865{
12866 for (; *vpp; vpp = &(*vpp)->next) {
12867 if (varequal((*vpp)->text, name)) {
12868 break;
12869 }
12870 }
12871 return vpp;
12872}
12873
12874/*
12875 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
12876 * This file contains code for the times builtin.
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012877 * $Id: ash.c,v 1.15 2001/07/31 21:38:23 andersen Exp $
Eric Andersencb57d552001-06-28 07:25:16 +000012878 */
12879static int timescmd (int argc, char **argv)
12880{
12881 struct tms buf;
12882 long int clk_tck = sysconf(_SC_CLK_TCK);
12883
12884 times(&buf);
12885 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
12886 (int) (buf.tms_utime / clk_tck / 60),
12887 ((double) buf.tms_utime) / clk_tck,
12888 (int) (buf.tms_stime / clk_tck / 60),
12889 ((double) buf.tms_stime) / clk_tck,
12890 (int) (buf.tms_cutime / clk_tck / 60),
12891 ((double) buf.tms_cutime) / clk_tck,
12892 (int) (buf.tms_cstime / clk_tck / 60),
12893 ((double) buf.tms_cstime) / clk_tck);
12894 return 0;
12895}
12896
Eric Andersendf82f612001-06-28 07:46:40 +000012897
Eric Andersen74bcd162001-07-30 21:41:37 +000012898#ifdef ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012899/* The let builtin. */
12900int letcmd(int argc, char **argv)
Eric Andersen74bcd162001-07-30 21:41:37 +000012901{
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012902 long result=0;
12903 if (argc == 2) {
12904 char *tmp, *expression, p[13];
12905 expression = strchr(argv[1], '=');
12906 if (!expression) {
12907 out2fmt("sh: let: syntax error: \"%s\"\n", argv[1]);
12908 return 0;
Eric Andersen74bcd162001-07-30 21:41:37 +000012909 }
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012910 *expression = '\0';
12911 tmp = ++expression;
12912 result = arith(tmp);
12913 if (result < 0) {
12914 out2fmt("sh: let: syntax error: \"%s=%s\"\n", argv[1], expression);
12915 return 0;
12916 }
12917 snprintf(p, 12, "%ld", result);
12918 setvar(argv[1], savestr(p), 0);
12919 } else if (argc >= 3)
12920 synerror("invalid operand");
12921 return !result;
Eric Andersen74bcd162001-07-30 21:41:37 +000012922}
12923#endif
12924
12925
12926
Eric Andersendf82f612001-06-28 07:46:40 +000012927/*-
12928 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000012929 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000012930 *
12931 * This code is derived from software contributed to Berkeley by
12932 * Kenneth Almquist.
12933 *
12934 * Redistribution and use in source and binary forms, with or without
12935 * modification, are permitted provided that the following conditions
12936 * are met:
12937 * 1. Redistributions of source code must retain the above copyright
12938 * notice, this list of conditions and the following disclaimer.
12939 * 2. Redistributions in binary form must reproduce the above copyright
12940 * notice, this list of conditions and the following disclaimer in the
12941 * documentation and/or other materials provided with the distribution.
12942 *
Eric Andersen2870d962001-07-02 17:27:21 +000012943 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
12944 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000012945 *
12946 * 4. Neither the name of the University nor the names of its contributors
12947 * may be used to endorse or promote products derived from this software
12948 * without specific prior written permission.
12949 *
12950 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
12951 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
12952 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
12953 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
12954 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
12955 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
12956 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
12957 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
12958 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
12959 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
12960 * SUCH DAMAGE.
12961 */