blob: 5756c6304aaef5c9d5c58e8fc46b68a02b7bd21e [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
29 * Vladimir Oleynik <vodz@usa.net> to be used in busybox
30 *
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
54 * support, enable this. This option needs some work, since it
55 * doesn't compile right now... */
Eric Andersencb57d552001-06-28 07:25:16 +000056#undef ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +000057
Eric Andersen2870d962001-07-02 17:27:21 +000058/* Getopts is used by shell procedures to parse positional parameters.
59 * You probably want to leave this disabled, and use the busybox getopt
60 * applet if you want to do this sort of thing. There are some scripts
61 * out there that use it, so it you need it, enable. Most people will
62 * leave this disabled. This adds 1k on an x86 system. */
63#undef ASH_GETOPTS
64
65/* This allows you to override shell builtins and use whatever is on
66 * the filesystem. This is most useful when ash is acting as a
Eric Andersen62483552001-07-10 06:09:16 +000067 * standalone shell. Adds about 272 bytes. */
Eric Andersen2870d962001-07-02 17:27:21 +000068#undef ASH_CMDCMD
69
Eric Andersen2870d962001-07-02 17:27:21 +000070
Eric Andersen3102ac42001-07-06 04:26:23 +000071/* Optimize size vs speed as size */
72#define ASH_OPTIMIZE_FOR_SIZE
73
Eric Andersen2870d962001-07-02 17:27:21 +000074/* Enable this to compile in extra debugging noise. When debugging is
75 * on, debugging info will be written to $HOME/trace and a quit signal
76 * will generate a core dump. */
77#undef DEBUG
78
Eric Andersen2870d962001-07-02 17:27:21 +000079/* These are here to work with glibc -- Don't change these... */
Eric Andersendf82f612001-06-28 07:46:40 +000080#undef FNMATCH_BROKEN
81#undef GLOB_BROKEN
Eric Andersen2870d962001-07-02 17:27:21 +000082#undef _GNU_SOURCE
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
1565/* The generated file arith.c has been snipped. If you want this
1566 * stuff back in, feel free to add it to your own copy. */
Eric Andersen2870d962001-07-02 17:27:21 +00001567#define ARITH_NUM 257
1568#define ARITH_LPAREN 258
1569#define ARITH_RPAREN 259
1570#define ARITH_OR 260
1571#define ARITH_AND 261
1572#define ARITH_BOR 262
1573#define ARITH_BXOR 263
1574#define ARITH_BAND 264
1575#define ARITH_EQ 265
1576#define ARITH_NE 266
1577#define ARITH_LT 267
1578#define ARITH_GT 268
1579#define ARITH_GE 269
1580#define ARITH_LE 270
1581#define ARITH_LSHIFT 271
1582#define ARITH_RSHIFT 272
1583#define ARITH_ADD 273
1584#define ARITH_SUB 274
1585#define ARITH_MUL 275
1586#define ARITH_DIV 276
1587#define ARITH_REM 277
1588#define ARITH_UNARYMINUS 278
1589#define ARITH_UNARYPLUS 279
1590#define ARITH_NOT 280
1591#define ARITH_BNOT 281
1592
1593static void expari (int);
1594/* From arith.y */
1595static int arith (const char *);
1596static int expcmd (int , char **);
1597static void arith_lex_reset (void);
1598static int yylex (void);
1599
Eric Andersencb57d552001-06-28 07:25:16 +00001600#endif
1601
Eric Andersen2870d962001-07-02 17:27:21 +00001602static char *trap[NSIG]; /* trap handler commands */
1603static char sigmode[NSIG - 1]; /* current value of signal */
1604static char gotsig[NSIG - 1]; /* indicates specified signal received */
1605static int pendingsigs; /* indicates some signal received */
1606
Eric Andersencb57d552001-06-28 07:25:16 +00001607/*
1608 * This file was generated by the mkbuiltins program.
1609 */
1610
Eric Andersen2870d962001-07-02 17:27:21 +00001611#ifdef JOBS
1612static int bgcmd (int, char **);
1613static int fgcmd (int, char **);
1614static int killcmd (int, char **);
1615#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001616static int bltincmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001617static int cdcmd (int, char **);
1618static int breakcmd (int, char **);
1619#ifdef ASH_CMDCMD
1620static int commandcmd (int, char **);
1621#endif
1622static int dotcmd (int, char **);
1623static int evalcmd (int, char **);
1624static int execcmd (int, char **);
1625static int exitcmd (int, char **);
1626static int exportcmd (int, char **);
1627static int histcmd (int, char **);
1628static int hashcmd (int, char **);
Eric Andersen1c039232001-07-07 00:05:55 +00001629static int helpcmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001630static int jobscmd (int, char **);
1631static int localcmd (int, char **);
Eric Andersen3102ac42001-07-06 04:26:23 +00001632#ifndef BB_PWD
Eric Andersen2870d962001-07-02 17:27:21 +00001633static int pwdcmd (int, char **);
1634#endif
1635static int readcmd (int, char **);
1636static int returncmd (int, char **);
1637static int setcmd (int, char **);
1638static int setvarcmd (int, char **);
1639static int shiftcmd (int, char **);
1640static int trapcmd (int, char **);
1641static int umaskcmd (int, char **);
1642#ifdef ASH_ALIAS
1643static int aliascmd (int, char **);
1644static int unaliascmd (int, char **);
1645#endif
1646static int unsetcmd (int, char **);
1647static int waitcmd (int, char **);
1648static int ulimitcmd (int, char **);
1649static int timescmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001650#ifdef ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00001651static int expcmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001652#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001653static int typecmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001654#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00001655static int getoptscmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001656#endif
1657
Eric Andersen2870d962001-07-02 17:27:21 +00001658#ifndef BB_TRUE_FALSE
Eric Andersen2870d962001-07-02 17:27:21 +00001659static int true_main (int, char **);
1660static int false_main (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001661#endif
1662
1663static void setpwd (const char *, int);
1664
1665
1666#define BUILTIN_NOSPEC "0"
1667#define BUILTIN_SPECIAL "1"
1668#define BUILTIN_REGULAR "2"
1669#define BUILTIN_ASSIGN "4"
1670#define BUILTIN_SPEC_ASSG "5"
1671#define BUILTIN_REG_ASSG "6"
1672
1673#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1674#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1675#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
1676
1677struct builtincmd {
1678 const char *name;
1679 int (*const builtinfunc) (int, char **);
1680 //unsigned flags;
1681};
1682
Eric Andersencb57d552001-06-28 07:25:16 +00001683
1684/* It is CRUCIAL that this listing be kept in ascii order, otherwise
1685 * the binary search in find_builtin() will stop working. If you value
1686 * your kneecaps, you'll be sure to *make sure* that any changes made
1687 * to this array result in the listing remaining in ascii order. You
1688 * have been warned.
1689 */
1690static const struct builtincmd builtincmds[] = {
Eric Andersen62483552001-07-10 06:09:16 +00001691 { BUILTIN_SPECIAL ".", dotcmd }, /* first, see declare DOTCMD */
Eric Andersen2870d962001-07-02 17:27:21 +00001692 { BUILTIN_SPECIAL ":", true_main },
1693#ifdef ASH_ALIAS
1694 { BUILTIN_REG_ASSG "alias", aliascmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001695#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001696#ifdef JOBS
1697 { BUILTIN_REGULAR "bg", bgcmd },
1698#endif
1699 { BUILTIN_SPECIAL "break", breakcmd },
Eric Andersen3102ac42001-07-06 04:26:23 +00001700 { BUILTIN_SPECIAL "builtin", bltincmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001701 { BUILTIN_REGULAR "cd", cdcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001702 { BUILTIN_NOSPEC "chdir", cdcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001703#ifdef ASH_CMDCMD
1704 { BUILTIN_REGULAR "command", commandcmd },
1705#endif
1706 { BUILTIN_SPECIAL "continue", breakcmd },
1707 { BUILTIN_SPECIAL "eval", evalcmd },
1708 { BUILTIN_SPECIAL "exec", execcmd },
1709 { BUILTIN_SPECIAL "exit", exitcmd },
1710#ifdef ASH_MATH_SUPPORT
1711 { BUILTIN_NOSPEC "exp", expcmd },
1712#endif
1713 { BUILTIN_SPEC_ASSG "export", exportcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001714 { BUILTIN_REGULAR "false", false_main },
Eric Andersen2870d962001-07-02 17:27:21 +00001715 { BUILTIN_REGULAR "fc", histcmd },
1716#ifdef JOBS
1717 { BUILTIN_REGULAR "fg", fgcmd },
1718#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001719#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00001720 { BUILTIN_REGULAR "getopts", getoptscmd },
1721#endif
1722 { BUILTIN_NOSPEC "hash", hashcmd },
Eric Andersen1c039232001-07-07 00:05:55 +00001723 { BUILTIN_NOSPEC "help", helpcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001724 { BUILTIN_REGULAR "jobs", jobscmd },
1725#ifdef JOBS
1726 { BUILTIN_REGULAR "kill", killcmd },
1727#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001728#ifdef ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00001729 { BUILTIN_NOSPEC "let", expcmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001730#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001731 { BUILTIN_ASSIGN "local", localcmd },
Eric Andersen3102ac42001-07-06 04:26:23 +00001732#ifndef BB_PWD
Eric Andersen2870d962001-07-02 17:27:21 +00001733 { BUILTIN_NOSPEC "pwd", pwdcmd },
1734#endif
1735 { BUILTIN_REGULAR "read", readcmd },
1736 { BUILTIN_SPEC_ASSG "readonly", exportcmd },
1737 { BUILTIN_SPECIAL "return", returncmd },
1738 { BUILTIN_SPECIAL "set", setcmd },
1739 { BUILTIN_NOSPEC "setvar", setvarcmd },
1740 { BUILTIN_SPECIAL "shift", shiftcmd },
1741 { BUILTIN_SPECIAL "times", timescmd },
1742 { BUILTIN_SPECIAL "trap", trapcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001743 { BUILTIN_REGULAR "true", true_main },
Eric Andersen2870d962001-07-02 17:27:21 +00001744 { BUILTIN_NOSPEC "type", typecmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001745 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1746 { BUILTIN_REGULAR "umask", umaskcmd },
1747#ifdef ASH_ALIAS
1748 { BUILTIN_REGULAR "unalias", unaliascmd },
1749#endif
1750 { BUILTIN_SPECIAL "unset", unsetcmd },
1751 { BUILTIN_REGULAR "wait", waitcmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001752};
1753#define NUMBUILTINS (sizeof (builtincmds) / sizeof (struct builtincmd) )
1754
Eric Andersen2870d962001-07-02 17:27:21 +00001755static const struct builtincmd *DOTCMD = &builtincmds[0];
1756static struct builtincmd *BLTINCMD;
1757static struct builtincmd *EXECCMD;
1758static struct builtincmd *EVALCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00001759
Eric Andersen2870d962001-07-02 17:27:21 +00001760/* states */
1761#define JOBSTOPPED 1 /* all procs are stopped */
1762#define JOBDONE 2 /* all procs are completed */
Eric Andersencb57d552001-06-28 07:25:16 +00001763
Eric Andersen2870d962001-07-02 17:27:21 +00001764/*
1765 * A job structure contains information about a job. A job is either a
1766 * single process or a set of processes contained in a pipeline. In the
1767 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1768 * array of pids.
1769 */
Eric Andersencb57d552001-06-28 07:25:16 +00001770
Eric Andersen2870d962001-07-02 17:27:21 +00001771struct procstat {
1772 pid_t pid; /* process id */
1773 int status; /* status flags (defined above) */
1774 char *cmd; /* text of command being run */
1775};
Eric Andersencb57d552001-06-28 07:25:16 +00001776
Eric Andersen2870d962001-07-02 17:27:21 +00001777
1778static int job_warning; /* user was warned about stopped jobs */
1779
1780#ifdef JOBS
1781static void setjobctl(int enable);
1782#else
1783#define setjobctl(on) /* do nothing */
Eric Andersencb57d552001-06-28 07:25:16 +00001784#endif
1785
Eric Andersen2870d962001-07-02 17:27:21 +00001786
1787struct job {
1788 struct procstat ps0; /* status of process */
1789 struct procstat *ps; /* status or processes when more than one */
1790 short nprocs; /* number of processes */
1791 short pgrp; /* process group of this job */
1792 char state; /* true if job is finished */
1793 char used; /* true if this entry is in used */
1794 char changed; /* true if status has changed */
1795#ifdef JOBS
1796 char jobctl; /* job running under job control */
1797#endif
1798};
1799
1800static struct job *jobtab; /* array of jobs */
1801static int njobs; /* size of array */
1802static int backgndpid = -1; /* pid of last background process */
1803#ifdef JOBS
1804static int initialpgrp; /* pgrp of shell on invocation */
1805static int curjob; /* current job */
1806static int jobctl;
1807#endif
1808static int intreceived;
1809
Eric Andersen62483552001-07-10 06:09:16 +00001810static struct job *makejob (const union node *, int);
1811static int forkshell (struct job *, const union node *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00001812static int waitforjob (struct job *);
1813
1814static int docd (char *, int);
1815static char *getcomponent (void);
1816static void updatepwd (const char *);
1817static void getpwd (void);
1818
1819static char *padvance (const char **, const char *);
1820
1821static char nullstr[1]; /* zero length string */
1822static char *curdir = nullstr; /* current working directory */
1823static char *cdcomppath;
1824
Eric Andersencb57d552001-06-28 07:25:16 +00001825static int
1826cdcmd(argc, argv)
1827 int argc;
1828 char **argv;
1829{
1830 const char *dest;
1831 const char *path;
1832 char *p;
1833 struct stat statb;
1834 int print = 0;
1835
1836 nextopt(nullstr);
1837 if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME")) == NULL)
1838 error("HOME not set");
1839 if (*dest == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00001840 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001841 if (dest[0] == '-' && dest[1] == '\0') {
1842 dest = bltinlookup("OLDPWD");
1843 if (!dest || !*dest) {
1844 dest = curdir;
1845 }
1846 print = 1;
1847 if (dest)
Eric Andersen2870d962001-07-02 17:27:21 +00001848 print = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00001849 else
Eric Andersen2870d962001-07-02 17:27:21 +00001850 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001851 }
1852 if (*dest == '/' || (path = bltinlookup("CDPATH")) == NULL)
1853 path = nullstr;
1854 while ((p = padvance(&path, dest)) != NULL) {
1855 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
1856 if (!print) {
1857 /*
1858 * XXX - rethink
1859 */
1860 if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
1861 p += 2;
1862 print = strcmp(p, dest);
1863 }
1864 if (docd(p, print) >= 0)
1865 return 0;
1866
1867 }
1868 }
1869 error("can't cd to %s", dest);
1870 /* NOTREACHED */
1871}
1872
1873
1874/*
1875 * Actually do the chdir. In an interactive shell, print the
1876 * directory name if "print" is nonzero.
1877 */
1878
1879static int
1880docd(dest, print)
1881 char *dest;
1882 int print;
1883{
1884 char *p;
1885 char *q;
1886 char *component;
1887 struct stat statb;
1888 int first;
1889 int badstat;
1890
1891 TRACE(("docd(\"%s\", %d) called\n", dest, print));
1892
1893 /*
1894 * Check each component of the path. If we find a symlink or
1895 * something we can't stat, clear curdir to force a getcwd()
1896 * next time we get the value of the current directory.
1897 */
1898 badstat = 0;
1899 cdcomppath = sstrdup(dest);
1900 STARTSTACKSTR(p);
1901 if (*dest == '/') {
1902 STPUTC('/', p);
1903 cdcomppath++;
1904 }
1905 first = 1;
1906 while ((q = getcomponent()) != NULL) {
1907 if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0'))
1908 continue;
1909 if (! first)
1910 STPUTC('/', p);
1911 first = 0;
1912 component = q;
1913 while (*q)
1914 STPUTC(*q++, p);
1915 if (equal(component, ".."))
1916 continue;
1917 STACKSTRNUL(p);
1918 if ((lstat(stackblock(), &statb) < 0)
1919 || (S_ISLNK(statb.st_mode))) {
1920 /* print = 1; */
1921 badstat = 1;
1922 break;
1923 }
1924 }
1925
1926 INTOFF;
1927 if (chdir(dest) < 0) {
1928 INTON;
1929 return -1;
1930 }
1931 updatepwd(badstat ? NULL : dest);
1932 INTON;
1933 if (print && iflag)
Eric Andersen62483552001-07-10 06:09:16 +00001934 printf(snlfmt, curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00001935 return 0;
1936}
1937
1938
1939/*
1940 * Get the next component of the path name pointed to by cdcomppath.
1941 * This routine overwrites the string pointed to by cdcomppath.
1942 */
1943
1944static char *
1945getcomponent() {
1946 char *p;
1947 char *start;
1948
1949 if ((p = cdcomppath) == NULL)
1950 return NULL;
1951 start = cdcomppath;
1952 while (*p != '/' && *p != '\0')
1953 p++;
1954 if (*p == '\0') {
1955 cdcomppath = NULL;
1956 } else {
1957 *p++ = '\0';
1958 cdcomppath = p;
1959 }
1960 return start;
1961}
1962
1963
1964
1965/*
1966 * Update curdir (the name of the current directory) in response to a
1967 * cd command. We also call hashcd to let the routines in exec.c know
1968 * that the current directory has changed.
1969 */
1970
Eric Andersen2870d962001-07-02 17:27:21 +00001971static void hashcd (void);
1972
Eric Andersencb57d552001-06-28 07:25:16 +00001973static void
Eric Andersen2870d962001-07-02 17:27:21 +00001974updatepwd(const char *dir)
1975{
Eric Andersencb57d552001-06-28 07:25:16 +00001976 char *new;
1977 char *p;
1978 size_t len;
1979
Eric Andersen2870d962001-07-02 17:27:21 +00001980 hashcd(); /* update command hash table */
Eric Andersencb57d552001-06-28 07:25:16 +00001981
1982 /*
1983 * If our argument is NULL, we don't know the current directory
1984 * any more because we traversed a symbolic link or something
1985 * we couldn't stat().
1986 */
1987 if (dir == NULL || curdir == nullstr) {
1988 setpwd(0, 1);
1989 return;
1990 }
1991 len = strlen(dir);
1992 cdcomppath = sstrdup(dir);
1993 STARTSTACKSTR(new);
1994 if (*dir != '/') {
1995 p = curdir;
1996 while (*p)
1997 STPUTC(*p++, new);
1998 if (p[-1] == '/')
1999 STUNPUTC(new);
2000 }
2001 while ((p = getcomponent()) != NULL) {
2002 if (equal(p, "..")) {
2003 while (new > stackblock() && (STUNPUTC(new), *new) != '/');
2004 } else if (*p != '\0' && ! equal(p, ".")) {
2005 STPUTC('/', new);
2006 while (*p)
2007 STPUTC(*p++, new);
2008 }
2009 }
2010 if (new == stackblock())
2011 STPUTC('/', new);
2012 STACKSTRNUL(new);
2013 setpwd(stackblock(), 1);
2014}
2015
2016
Eric Andersen3102ac42001-07-06 04:26:23 +00002017#ifndef BB_PWD
Eric Andersencb57d552001-06-28 07:25:16 +00002018static int
2019pwdcmd(argc, argv)
2020 int argc;
2021 char **argv;
2022{
Eric Andersen62483552001-07-10 06:09:16 +00002023 printf(snlfmt, curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00002024 return 0;
2025}
Eric Andersen2870d962001-07-02 17:27:21 +00002026#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002027
2028/*
2029 * Find out what the current directory is. If we already know the current
2030 * directory, this routine returns immediately.
2031 */
2032static void
Eric Andersen2870d962001-07-02 17:27:21 +00002033getpwd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00002034{
Eric Andersen2870d962001-07-02 17:27:21 +00002035 curdir = xgetcwd(0);
2036 if(curdir==0)
2037 curdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00002038}
2039
2040static void
2041setpwd(const char *val, int setold)
2042{
2043 if (setold) {
2044 setvar("OLDPWD", curdir, VEXPORT);
2045 }
2046 INTOFF;
2047 if (curdir != nullstr) {
2048 free(curdir);
2049 curdir = nullstr;
2050 }
2051 if (!val) {
2052 getpwd();
2053 } else {
2054 curdir = savestr(val);
2055 }
2056 INTON;
2057 setvar("PWD", curdir, VEXPORT);
2058}
2059
Eric Andersencb57d552001-06-28 07:25:16 +00002060/*
2061 * Errors and exceptions.
2062 */
2063
2064/*
2065 * Code to handle exceptions in C.
2066 */
2067
Eric Andersen2870d962001-07-02 17:27:21 +00002068/*
2069 * We enclose jmp_buf in a structure so that we can declare pointers to
2070 * jump locations. The global variable handler contains the location to
2071 * jump to when an exception occurs, and the global variable exception
2072 * contains a code identifying the exeception. To implement nested
2073 * exception handlers, the user should save the value of handler on entry
2074 * to an inner scope, set handler to point to a jmploc structure for the
2075 * inner scope, and restore handler on exit from the scope.
2076 */
2077
2078struct jmploc {
2079 jmp_buf loc;
2080};
2081
2082/* exceptions */
2083#define EXINT 0 /* SIGINT received */
2084#define EXERROR 1 /* a generic error */
2085#define EXSHELLPROC 2 /* execute a shell procedure */
2086#define EXEXEC 3 /* command execution failed */
2087
2088static struct jmploc *handler;
Eric Andersencb57d552001-06-28 07:25:16 +00002089static int exception;
Eric Andersencb57d552001-06-28 07:25:16 +00002090
Eric Andersen2870d962001-07-02 17:27:21 +00002091static void exverror (int, const char *, va_list)
Eric Andersencb57d552001-06-28 07:25:16 +00002092 __attribute__((__noreturn__));
2093
2094/*
2095 * Called to raise an exception. Since C doesn't include exceptions, we
2096 * just do a longjmp to the exception handler. The type of exception is
2097 * stored in the global variable "exception".
2098 */
2099
Eric Andersen2870d962001-07-02 17:27:21 +00002100static void exraise (int) __attribute__((__noreturn__));
2101
Eric Andersencb57d552001-06-28 07:25:16 +00002102static void
Eric Andersen2870d962001-07-02 17:27:21 +00002103exraise(int e)
Eric Andersencb57d552001-06-28 07:25:16 +00002104{
2105#ifdef DEBUG
2106 if (handler == NULL)
2107 abort();
2108#endif
Eric Andersen62483552001-07-10 06:09:16 +00002109 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00002110 exception = e;
2111 longjmp(handler->loc, 1);
2112}
2113
2114
2115/*
2116 * Called from trap.c when a SIGINT is received. (If the user specifies
2117 * that SIGINT is to be trapped or ignored using the trap builtin, then
2118 * this routine is not called.) Suppressint is nonzero when interrupts
2119 * are held using the INTOFF macro. The call to _exit is necessary because
2120 * there is a short period after a fork before the signal handlers are
2121 * set to the appropriate value for the child. (The test for iflag is
2122 * just defensive programming.)
2123 */
2124
2125static void
Eric Andersen2870d962001-07-02 17:27:21 +00002126onint(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00002127 sigset_t mysigset;
2128
2129 if (suppressint) {
2130 intpending++;
2131 return;
2132 }
2133 intpending = 0;
2134 sigemptyset(&mysigset);
2135 sigprocmask(SIG_SETMASK, &mysigset, NULL);
2136 if (rootshell && iflag)
2137 exraise(EXINT);
2138 else {
2139 signal(SIGINT, SIG_DFL);
2140 raise(SIGINT);
2141 }
2142 /* NOTREACHED */
2143}
2144
2145
Eric Andersen2870d962001-07-02 17:27:21 +00002146static char *commandname; /* currently executing command */
2147
Eric Andersencb57d552001-06-28 07:25:16 +00002148/*
2149 * Exverror is called to raise the error exception. If the first argument
2150 * is not NULL then error prints an error message using printf style
2151 * formatting. It then raises the error exception.
2152 */
2153static void
Eric Andersen2870d962001-07-02 17:27:21 +00002154exverror(int cond, const char *msg, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00002155{
2156 CLEAR_PENDING_INT;
2157 INTOFF;
2158
2159#ifdef DEBUG
2160 if (msg)
2161 TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
2162 else
2163 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2164#endif
2165 if (msg) {
2166 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +00002167 out2fmt("%s: ", commandname);
2168 vfprintf(stderr, msg, ap);
2169 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00002170 }
Eric Andersencb57d552001-06-28 07:25:16 +00002171 exraise(cond);
2172 /* NOTREACHED */
2173}
2174
2175
2176#ifdef __STDC__
2177static void
2178error(const char *msg, ...)
2179#else
2180static void
2181error(va_alist)
2182 va_dcl
2183#endif
2184{
2185#ifndef __STDC__
2186 const char *msg;
2187#endif
2188 va_list ap;
2189#ifdef __STDC__
2190 va_start(ap, msg);
2191#else
2192 va_start(ap);
2193 msg = va_arg(ap, const char *);
2194#endif
2195 exverror(EXERROR, msg, ap);
2196 /* NOTREACHED */
2197 va_end(ap);
2198}
2199
2200
2201#ifdef __STDC__
2202static void
2203exerror(int cond, const char *msg, ...)
2204#else
2205static void
2206exerror(va_alist)
2207 va_dcl
2208#endif
2209{
2210#ifndef __STDC__
2211 int cond;
2212 const char *msg;
2213#endif
2214 va_list ap;
2215#ifdef __STDC__
2216 va_start(ap, msg);
2217#else
2218 va_start(ap);
2219 cond = va_arg(ap, int);
2220 msg = va_arg(ap, const char *);
2221#endif
2222 exverror(cond, msg, ap);
2223 /* NOTREACHED */
2224 va_end(ap);
2225}
2226
2227
2228
2229/*
2230 * Table of error messages.
2231 */
2232
2233struct errname {
Eric Andersen2870d962001-07-02 17:27:21 +00002234 short errcode; /* error number */
Eric Andersen62483552001-07-10 06:09:16 +00002235 char action; /* operation which encountered the error */
Eric Andersencb57d552001-06-28 07:25:16 +00002236};
2237
Eric Andersen2870d962001-07-02 17:27:21 +00002238/*
2239 * Types of operations (passed to the errmsg routine).
2240 */
2241
2242#define E_OPEN 01 /* opening a file */
2243#define E_CREAT 02 /* creating a file */
2244#define E_EXEC 04 /* executing a program */
Eric Andersencb57d552001-06-28 07:25:16 +00002245
2246#define ALL (E_OPEN|E_CREAT|E_EXEC)
2247
2248static const struct errname errormsg[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00002249 { EINTR, ALL },
2250 { EACCES, ALL },
2251 { EIO, ALL },
2252 { ENOENT, E_OPEN },
2253 { ENOENT, E_CREAT },
2254 { ENOENT, E_EXEC },
2255 { ENOTDIR, E_OPEN },
2256 { ENOTDIR, E_CREAT },
2257 { ENOTDIR, E_EXEC },
2258 { EISDIR, ALL },
2259 { EEXIST, E_CREAT },
2260#ifdef EMFILE
2261 { EMFILE, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002262#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002263 { ENFILE, ALL },
2264 { ENOSPC, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002265#ifdef EDQUOT
Eric Andersen2870d962001-07-02 17:27:21 +00002266 { EDQUOT, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002267#endif
2268#ifdef ENOSR
Eric Andersen2870d962001-07-02 17:27:21 +00002269 { ENOSR, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002270#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002271 { ENXIO, ALL },
2272 { EROFS, ALL },
2273 { ETXTBSY, ALL },
2274#ifdef EAGAIN
2275 { EAGAIN, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002276#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002277 { ENOMEM, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002278#ifdef ENOLINK
Eric Andersen2870d962001-07-02 17:27:21 +00002279 { ENOLINK, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002280#endif
2281#ifdef EMULTIHOP
Eric Andersen2870d962001-07-02 17:27:21 +00002282 { EMULTIHOP, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002283#endif
2284#ifdef ECOMM
Eric Andersen2870d962001-07-02 17:27:21 +00002285 { ECOMM, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002286#endif
2287#ifdef ESTALE
Eric Andersen2870d962001-07-02 17:27:21 +00002288 { ESTALE, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002289#endif
2290#ifdef ETIMEDOUT
Eric Andersen2870d962001-07-02 17:27:21 +00002291 { ETIMEDOUT, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002292#endif
2293#ifdef ELOOP
Eric Andersen2870d962001-07-02 17:27:21 +00002294 { ELOOP, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002295#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002296 { E2BIG, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002297#ifdef ELIBACC
Eric Andersen2870d962001-07-02 17:27:21 +00002298 { ELIBACC, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002299#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002300};
2301
Eric Andersen2870d962001-07-02 17:27:21 +00002302#define ERRNAME_SIZE (sizeof(errormsg)/sizeof(struct errname))
Eric Andersencb57d552001-06-28 07:25:16 +00002303
2304/*
2305 * Return a string describing an error. The returned string may be a
2306 * pointer to a static buffer that will be overwritten on the next call.
2307 * Action describes the operation that got the error.
2308 */
2309
2310static const char *
Eric Andersen2870d962001-07-02 17:27:21 +00002311errmsg(int e, int action)
Eric Andersencb57d552001-06-28 07:25:16 +00002312{
2313 struct errname const *ep;
2314 static char buf[12];
2315
Eric Andersen2870d962001-07-02 17:27:21 +00002316 for (ep = errormsg ; ep < errormsg+ERRNAME_SIZE; ep++) {
Eric Andersencb57d552001-06-28 07:25:16 +00002317 if (ep->errcode == e && (ep->action & action) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00002318 return strerror(e);
Eric Andersencb57d552001-06-28 07:25:16 +00002319 }
Eric Andersen2870d962001-07-02 17:27:21 +00002320
Eric Andersen3102ac42001-07-06 04:26:23 +00002321 snprintf(buf, sizeof buf, "error %d", e);
Eric Andersencb57d552001-06-28 07:25:16 +00002322 return buf;
2323}
2324
2325
Eric Andersen3102ac42001-07-06 04:26:23 +00002326#ifdef ASH_OPTIMIZE_FOR_SIZE
Eric Andersencb57d552001-06-28 07:25:16 +00002327static void
2328__inton() {
2329 if (--suppressint == 0 && intpending) {
2330 onint();
2331 }
2332}
Eric Andersen3102ac42001-07-06 04:26:23 +00002333static void forceinton (void) {
2334 suppressint = 0;
2335 if (intpending)
2336 onint();
2337}
Eric Andersencb57d552001-06-28 07:25:16 +00002338#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002339
2340/* flags in argument to evaltree */
Eric Andersen2870d962001-07-02 17:27:21 +00002341#define EV_EXIT 01 /* exit after evaluating tree */
2342#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2343#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00002344
Eric Andersen2870d962001-07-02 17:27:21 +00002345static int evalskip; /* set if we are skipping commands */
2346static int skipcount; /* number of levels to skip */
2347static int loopnest; /* current loop nesting level */
2348static int funcnest; /* depth of function calls */
Eric Andersencb57d552001-06-28 07:25:16 +00002349
2350
Eric Andersen2870d962001-07-02 17:27:21 +00002351static struct strlist *cmdenviron; /* environment for builtin command */
2352static int exitstatus; /* exit status of last command */
2353static int oexitstatus; /* saved exit status */
Eric Andersencb57d552001-06-28 07:25:16 +00002354
Eric Andersen62483552001-07-10 06:09:16 +00002355static void evalsubshell (const union node *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00002356static void expredir (union node *);
Eric Andersen2870d962001-07-02 17:27:21 +00002357static void prehash (union node *);
2358static void eprintlist (struct strlist *);
Eric Andersencb57d552001-06-28 07:25:16 +00002359
Eric Andersen2870d962001-07-02 17:27:21 +00002360static union node *parsecmd(int);
Eric Andersencb57d552001-06-28 07:25:16 +00002361/*
2362 * Called to reset things after an exception.
2363 */
2364
Eric Andersencb57d552001-06-28 07:25:16 +00002365/*
2366 * The eval commmand.
2367 */
Eric Andersen2870d962001-07-02 17:27:21 +00002368static void evalstring (char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00002369
2370static int
2371evalcmd(argc, argv)
2372 int argc;
2373 char **argv;
2374{
Eric Andersen2870d962001-07-02 17:27:21 +00002375 char *p;
2376 char *concat;
2377 char **ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002378
Eric Andersen2870d962001-07-02 17:27:21 +00002379 if (argc > 1) {
2380 p = argv[1];
2381 if (argc > 2) {
2382 STARTSTACKSTR(concat);
2383 ap = argv + 2;
2384 for (;;) {
2385 while (*p)
2386 STPUTC(*p++, concat);
2387 if ((p = *ap++) == NULL)
2388 break;
2389 STPUTC(' ', concat);
2390 }
2391 STPUTC('\0', concat);
2392 p = grabstackstr(concat);
2393 }
2394 evalstring(p, EV_TESTED);
2395 }
2396 return exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002397}
2398
Eric Andersencb57d552001-06-28 07:25:16 +00002399/*
2400 * Execute a command or commands contained in a string.
2401 */
2402
Eric Andersen2870d962001-07-02 17:27:21 +00002403static void evaltree (union node *, int);
2404static void setinputstring (char *);
2405static void popfile (void);
2406static void setstackmark(struct stackmark *mark);
2407static void popstackmark(struct stackmark *mark);
2408
2409
Eric Andersencb57d552001-06-28 07:25:16 +00002410static void
Eric Andersen2870d962001-07-02 17:27:21 +00002411evalstring(char *s, int flag)
2412{
Eric Andersencb57d552001-06-28 07:25:16 +00002413 union node *n;
2414 struct stackmark smark;
2415
2416 setstackmark(&smark);
2417 setinputstring(s);
2418 while ((n = parsecmd(0)) != NEOF) {
2419 evaltree(n, flag);
2420 popstackmark(&smark);
2421 }
2422 popfile();
2423 popstackmark(&smark);
2424}
2425
Eric Andersen2870d962001-07-02 17:27:21 +00002426static struct builtincmd *find_builtin (const char *);
Eric Andersen62483552001-07-10 06:09:16 +00002427static void expandarg (union node *, struct arglist *, int);
2428static void calcsize (const union node *);
2429static union node *copynode (const union node *);
2430
2431/*
2432 * Make a copy of a parse tree.
2433 */
2434
2435static int funcblocksize; /* size of structures in function */
2436static int funcstringsize; /* size of strings in node */
2437static pointer funcblock; /* block to allocate function from */
2438static char *funcstring; /* block to allocate strings from */
2439
2440
2441static inline union node *
2442copyfunc(union node *n)
2443{
2444 if (n == NULL)
2445 return NULL;
2446 funcblocksize = 0;
2447 funcstringsize = 0;
2448 calcsize(n);
2449 funcblock = ckmalloc(funcblocksize + funcstringsize);
2450 funcstring = (char *) funcblock + funcblocksize;
2451 return copynode(n);
2452}
2453
2454/*
2455 * Free a parse tree.
2456 */
Eric Andersencb57d552001-06-28 07:25:16 +00002457
2458static void
Eric Andersen62483552001-07-10 06:09:16 +00002459freefunc(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00002460{
Eric Andersen62483552001-07-10 06:09:16 +00002461 if (n)
2462 ckfree(n);
Eric Andersencb57d552001-06-28 07:25:16 +00002463}
2464
2465
Eric Andersen62483552001-07-10 06:09:16 +00002466/*
2467 * Add a new command entry, replacing any existing command entry for
2468 * the same name.
2469 */
2470
2471static inline void
2472addcmdentry(char *name, struct cmdentry *entry)
2473{
2474 struct tblentry *cmdp;
2475
2476 INTOFF;
2477 cmdp = cmdlookup(name, 1);
2478 if (cmdp->cmdtype == CMDFUNCTION) {
2479 freefunc(cmdp->param.func);
2480 }
2481 cmdp->cmdtype = entry->cmdtype;
2482 cmdp->param = entry->u;
2483 INTON;
2484}
2485
2486static inline void
2487evalloop(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002488{
2489 int status;
2490
2491 loopnest++;
2492 status = 0;
2493 for (;;) {
2494 evaltree(n->nbinary.ch1, EV_TESTED);
2495 if (evalskip) {
Eric Andersen2870d962001-07-02 17:27:21 +00002496skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002497 evalskip = 0;
2498 continue;
2499 }
2500 if (evalskip == SKIPBREAK && --skipcount <= 0)
2501 evalskip = 0;
2502 break;
2503 }
2504 if (n->type == NWHILE) {
2505 if (exitstatus != 0)
2506 break;
2507 } else {
2508 if (exitstatus == 0)
2509 break;
2510 }
2511 evaltree(n->nbinary.ch2, flags & EV_TESTED);
2512 status = exitstatus;
2513 if (evalskip)
2514 goto skipping;
2515 }
2516 loopnest--;
2517 exitstatus = status;
2518}
2519
Eric Andersencb57d552001-06-28 07:25:16 +00002520static void
Eric Andersen62483552001-07-10 06:09:16 +00002521evalfor(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002522{
2523 struct arglist arglist;
2524 union node *argp;
2525 struct strlist *sp;
2526 struct stackmark smark;
2527
2528 setstackmark(&smark);
2529 arglist.lastp = &arglist.list;
2530 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2531 oexitstatus = exitstatus;
2532 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2533 if (evalskip)
2534 goto out;
2535 }
2536 *arglist.lastp = NULL;
2537
2538 exitstatus = 0;
2539 loopnest++;
2540 for (sp = arglist.list ; sp ; sp = sp->next) {
2541 setvar(n->nfor.var, sp->text, 0);
2542 evaltree(n->nfor.body, flags & EV_TESTED);
2543 if (evalskip) {
2544 if (evalskip == SKIPCONT && --skipcount <= 0) {
2545 evalskip = 0;
2546 continue;
2547 }
2548 if (evalskip == SKIPBREAK && --skipcount <= 0)
2549 evalskip = 0;
2550 break;
2551 }
2552 }
2553 loopnest--;
2554out:
2555 popstackmark(&smark);
2556}
2557
Eric Andersen62483552001-07-10 06:09:16 +00002558static inline void
2559evalcase(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002560{
2561 union node *cp;
2562 union node *patp;
2563 struct arglist arglist;
2564 struct stackmark smark;
2565
2566 setstackmark(&smark);
2567 arglist.lastp = &arglist.list;
2568 oexitstatus = exitstatus;
2569 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2570 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2571 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2572 if (casematch(patp, arglist.list->text)) {
2573 if (evalskip == 0) {
2574 evaltree(cp->nclist.body, flags);
2575 }
2576 goto out;
2577 }
2578 }
2579 }
2580out:
2581 popstackmark(&smark);
2582}
2583
Eric Andersencb57d552001-06-28 07:25:16 +00002584/*
Eric Andersencb57d552001-06-28 07:25:16 +00002585 * Evaluate a pipeline. All the processes in the pipeline are children
2586 * of the process creating the pipeline. (This differs from some versions
2587 * of the shell, which make the last process in a pipeline the parent
2588 * of all the rest.)
2589 */
2590
Eric Andersen62483552001-07-10 06:09:16 +00002591static inline void
Eric Andersencb57d552001-06-28 07:25:16 +00002592evalpipe(n)
2593 union node *n;
2594{
2595 struct job *jp;
2596 struct nodelist *lp;
2597 int pipelen;
2598 int prevfd;
2599 int pip[2];
2600
2601 TRACE(("evalpipe(0x%lx) called\n", (long)n));
2602 pipelen = 0;
2603 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
2604 pipelen++;
2605 INTOFF;
2606 jp = makejob(n, pipelen);
2607 prevfd = -1;
2608 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
2609 prehash(lp->n);
2610 pip[1] = -1;
2611 if (lp->next) {
2612 if (pipe(pip) < 0) {
2613 close(prevfd);
2614 error("Pipe call failed");
2615 }
2616 }
2617 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
2618 INTON;
2619 if (prevfd > 0) {
2620 close(0);
2621 dup_as_newfd(prevfd, 0);
2622 close(prevfd);
2623 if (pip[0] == 0) {
2624 pip[0] = -1;
2625 }
2626 }
2627 if (pip[1] >= 0) {
2628 if (pip[0] >= 0) {
2629 close(pip[0]);
2630 }
2631 if (pip[1] != 1) {
2632 close(1);
2633 dup_as_newfd(pip[1], 1);
2634 close(pip[1]);
2635 }
2636 }
2637 evaltree(lp->n, EV_EXIT);
2638 }
2639 if (prevfd >= 0)
2640 close(prevfd);
2641 prevfd = pip[0];
2642 close(pip[1]);
2643 }
2644 INTON;
2645 if (n->npipe.backgnd == 0) {
2646 INTOFF;
2647 exitstatus = waitforjob(jp);
2648 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
2649 INTON;
2650 }
2651}
2652
Eric Andersen2870d962001-07-02 17:27:21 +00002653static void find_command (const char *, struct cmdentry *, int, const char *);
2654
2655static int
2656isassignment(const char *word) {
2657 if (!is_name(*word)) {
2658 return 0;
2659 }
2660 do {
2661 word++;
2662 } while (is_in_name(*word));
2663 return *word == '=';
2664}
2665
Eric Andersen62483552001-07-10 06:09:16 +00002666
Eric Andersencb57d552001-06-28 07:25:16 +00002667static void
Eric Andersen3102ac42001-07-06 04:26:23 +00002668evalcommand(union node *cmd, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002669{
2670 struct stackmark smark;
2671 union node *argp;
2672 struct arglist arglist;
2673 struct arglist varlist;
2674 char **argv;
2675 int argc;
2676 char **envp;
2677 struct strlist *sp;
2678 int mode;
Eric Andersencb57d552001-06-28 07:25:16 +00002679 struct cmdentry cmdentry;
2680 struct job *jp;
2681 char *volatile savecmdname;
2682 volatile struct shparam saveparam;
2683 struct localvar *volatile savelocalvars;
2684 volatile int e;
2685 char *lastarg;
2686 const char *path;
2687 const struct builtincmd *firstbltin;
2688 struct jmploc *volatile savehandler;
2689 struct jmploc jmploc;
2690#if __GNUC__
2691 /* Avoid longjmp clobbering */
2692 (void) &argv;
2693 (void) &argc;
2694 (void) &lastarg;
2695 (void) &flags;
2696#endif
2697
2698 /* First expand the arguments. */
2699 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
2700 setstackmark(&smark);
2701 arglist.lastp = &arglist.list;
2702 varlist.lastp = &varlist.list;
2703 arglist.list = 0;
2704 oexitstatus = exitstatus;
2705 exitstatus = 0;
2706 path = pathval();
2707 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
2708 expandarg(argp, &varlist, EXP_VARTILDE);
2709 }
2710 for (
2711 argp = cmd->ncmd.args; argp && !arglist.list;
2712 argp = argp->narg.next
2713 ) {
2714 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2715 }
2716 if (argp) {
2717 struct builtincmd *bcmd;
Eric Andersen62483552001-07-10 06:09:16 +00002718 int pseudovarflag;
Eric Andersencb57d552001-06-28 07:25:16 +00002719 bcmd = find_builtin(arglist.list->text);
Eric Andersen2870d962001-07-02 17:27:21 +00002720 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00002721 for (; argp; argp = argp->narg.next) {
2722 if (pseudovarflag && isassignment(argp->narg.text)) {
2723 expandarg(argp, &arglist, EXP_VARTILDE);
2724 continue;
2725 }
2726 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2727 }
2728 }
2729 *arglist.lastp = NULL;
2730 *varlist.lastp = NULL;
2731 expredir(cmd->ncmd.redirect);
2732 argc = 0;
2733 for (sp = arglist.list ; sp ; sp = sp->next)
2734 argc++;
2735 argv = stalloc(sizeof (char *) * (argc + 1));
2736
2737 for (sp = arglist.list ; sp ; sp = sp->next) {
2738 TRACE(("evalcommand arg: %s\n", sp->text));
2739 *argv++ = sp->text;
2740 }
2741 *argv = NULL;
2742 lastarg = NULL;
2743 if (iflag && funcnest == 0 && argc > 0)
2744 lastarg = argv[-1];
2745 argv -= argc;
2746
2747 /* Print the command if xflag is set. */
2748 if (xflag) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002749 out2c('+');
Eric Andersencb57d552001-06-28 07:25:16 +00002750 eprintlist(varlist.list);
2751 eprintlist(arglist.list);
Eric Andersen3102ac42001-07-06 04:26:23 +00002752 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00002753 }
2754
2755 /* Now locate the command. */
2756 if (argc == 0) {
2757 cmdentry.cmdtype = CMDBUILTIN;
2758 firstbltin = cmdentry.u.cmd = BLTINCMD;
2759 } else {
2760 const char *oldpath;
2761 int findflag = DO_ERR;
2762 int oldfindflag;
2763
2764 /*
2765 * Modify the command lookup path, if a PATH= assignment
2766 * is present
2767 */
2768 for (sp = varlist.list ; sp ; sp = sp->next)
2769 if (varequal(sp->text, defpathvar)) {
2770 path = sp->text + 5;
2771 findflag |= DO_BRUTE;
2772 }
2773 oldpath = path;
2774 oldfindflag = findflag;
2775 firstbltin = 0;
2776 for(;;) {
2777 find_command(argv[0], &cmdentry, findflag, path);
Eric Andersen2870d962001-07-02 17:27:21 +00002778 if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */
Eric Andersencb57d552001-06-28 07:25:16 +00002779 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002780 goto out;
2781 }
2782 /* implement bltin and command here */
2783 if (cmdentry.cmdtype != CMDBUILTIN) {
2784 break;
2785 }
2786 if (!firstbltin) {
2787 firstbltin = cmdentry.u.cmd;
2788 }
2789 if (cmdentry.u.cmd == BLTINCMD) {
2790 for(;;) {
2791 struct builtincmd *bcmd;
2792
2793 argv++;
2794 if (--argc == 0)
2795 goto found;
2796 if (!(bcmd = find_builtin(*argv))) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002797 out2fmt("%s: not found\n", *argv);
Eric Andersencb57d552001-06-28 07:25:16 +00002798 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002799 goto out;
2800 }
2801 cmdentry.u.cmd = bcmd;
2802 if (bcmd != BLTINCMD)
2803 break;
2804 }
2805 }
Eric Andersen2870d962001-07-02 17:27:21 +00002806 if (cmdentry.u.cmd == find_builtin("command")) {
Eric Andersencb57d552001-06-28 07:25:16 +00002807 argv++;
2808 if (--argc == 0) {
2809 goto found;
2810 }
2811 if (*argv[0] == '-') {
2812 if (!equal(argv[0], "-p")) {
2813 argv--;
2814 argc++;
2815 break;
2816 }
2817 argv++;
2818 if (--argc == 0) {
2819 goto found;
2820 }
2821 path = defpath;
2822 findflag |= DO_BRUTE;
2823 } else {
2824 path = oldpath;
2825 findflag = oldfindflag;
2826 }
2827 findflag |= DO_NOFUN;
2828 continue;
2829 }
2830found:
2831 break;
2832 }
2833 }
2834
2835 /* Fork off a child process if necessary. */
2836 if (cmd->ncmd.backgnd
2837 || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00002838 ) {
2839 jp = makejob(cmd, 1);
2840 mode = cmd->ncmd.backgnd;
Eric Andersencb57d552001-06-28 07:25:16 +00002841 if (forkshell(jp, cmd, mode) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00002842 goto parent; /* at end of routine */
Eric Andersencb57d552001-06-28 07:25:16 +00002843 flags |= EV_EXIT;
2844 }
2845
2846 /* This is the child process if a fork occurred. */
2847 /* Execute the command. */
2848 if (cmdentry.cmdtype == CMDFUNCTION) {
2849#ifdef DEBUG
2850 trputs("Shell function: "); trargs(argv);
2851#endif
2852 exitstatus = oexitstatus;
2853 redirect(cmd->ncmd.redirect, REDIR_PUSH);
2854 saveparam = shellparam;
2855 shellparam.malloc = 0;
2856 shellparam.nparam = argc - 1;
2857 shellparam.p = argv + 1;
2858 INTOFF;
2859 savelocalvars = localvars;
2860 localvars = NULL;
2861 INTON;
2862 if (setjmp(jmploc.loc)) {
2863 if (exception == EXSHELLPROC) {
2864 freeparam((volatile struct shparam *)
2865 &saveparam);
2866 } else {
2867 saveparam.optind = shellparam.optind;
2868 saveparam.optoff = shellparam.optoff;
2869 freeparam(&shellparam);
2870 shellparam = saveparam;
2871 }
2872 poplocalvars();
2873 localvars = savelocalvars;
2874 handler = savehandler;
2875 longjmp(handler->loc, 1);
2876 }
2877 savehandler = handler;
2878 handler = &jmploc;
2879 for (sp = varlist.list ; sp ; sp = sp->next)
2880 mklocal(sp->text);
2881 funcnest++;
2882 evaltree(cmdentry.u.func, flags & EV_TESTED);
2883 funcnest--;
2884 INTOFF;
2885 poplocalvars();
2886 localvars = savelocalvars;
2887 saveparam.optind = shellparam.optind;
2888 saveparam.optoff = shellparam.optoff;
2889 freeparam(&shellparam);
2890 shellparam = saveparam;
2891 handler = savehandler;
2892 popredir();
2893 INTON;
2894 if (evalskip == SKIPFUNC) {
2895 evalskip = 0;
2896 skipcount = 0;
2897 }
2898 if (flags & EV_EXIT)
2899 exitshell(exitstatus);
2900 } else if (cmdentry.cmdtype == CMDBUILTIN) {
2901#ifdef DEBUG
2902 trputs("builtin command: "); trargs(argv);
2903#endif
2904 mode = (cmdentry.u.cmd == EXECCMD)? 0 : REDIR_PUSH;
Eric Andersencb57d552001-06-28 07:25:16 +00002905 redirect(cmd->ncmd.redirect, mode);
2906 savecmdname = commandname;
Eric Andersen2870d962001-07-02 17:27:21 +00002907 if (IS_BUILTIN_SPECIAL(firstbltin)) {
Eric Andersencb57d552001-06-28 07:25:16 +00002908 listsetvar(varlist.list);
2909 } else {
2910 cmdenviron = varlist.list;
2911 }
2912 e = -1;
2913 if (setjmp(jmploc.loc)) {
2914 e = exception;
2915 exitstatus = (e == EXINT)? SIGINT+128 : 2;
2916 goto cmddone;
2917 }
2918 savehandler = handler;
2919 handler = &jmploc;
2920 commandname = argv[0];
2921 argptr = argv + 1;
Eric Andersen2870d962001-07-02 17:27:21 +00002922 optptr = NULL; /* initialize nextopt */
Eric Andersencb57d552001-06-28 07:25:16 +00002923 exitstatus = (*cmdentry.u.cmd->builtinfunc)(argc, argv);
2924 flushall();
2925cmddone:
Eric Andersencb57d552001-06-28 07:25:16 +00002926 cmdenviron = NULL;
2927 if (e != EXSHELLPROC) {
2928 commandname = savecmdname;
2929 if (flags & EV_EXIT)
2930 exitshell(exitstatus);
2931 }
2932 handler = savehandler;
2933 if (e != -1) {
2934 if ((e != EXERROR && e != EXEXEC)
2935 || cmdentry.u.cmd == BLTINCMD
2936 || cmdentry.u.cmd == DOTCMD
2937 || cmdentry.u.cmd == EVALCMD
2938 || cmdentry.u.cmd == EXECCMD)
2939 exraise(e);
2940 FORCEINTON;
2941 }
2942 if (cmdentry.u.cmd != EXECCMD)
2943 popredir();
Eric Andersencb57d552001-06-28 07:25:16 +00002944 } else {
2945#ifdef DEBUG
2946 trputs("normal command: "); trargs(argv);
2947#endif
2948 redirect(cmd->ncmd.redirect, 0);
2949 clearredir();
2950 for (sp = varlist.list ; sp ; sp = sp->next)
2951 setvareq(sp->text, VEXPORT|VSTACK);
2952 envp = environment();
2953 shellexec(argv, envp, path, cmdentry.u.index);
2954 }
2955 goto out;
2956
Eric Andersen2870d962001-07-02 17:27:21 +00002957parent: /* parent process gets here (if we forked) */
2958 if (mode == 0) { /* argument to fork */
Eric Andersencb57d552001-06-28 07:25:16 +00002959 INTOFF;
2960 exitstatus = waitforjob(jp);
2961 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00002962 }
2963
2964out:
2965 if (lastarg)
2966 setvar("_", lastarg, 0);
2967 popstackmark(&smark);
2968}
2969
Eric Andersen62483552001-07-10 06:09:16 +00002970/*
2971 * Evaluate a parse tree. The value is left in the global variable
2972 * exitstatus.
2973 */
2974static void
2975evaltree(n, flags)
2976 union node *n;
2977 int flags;
2978{
2979 int checkexit = 0;
2980 if (n == NULL) {
2981 TRACE(("evaltree(NULL) called\n"));
2982 goto out;
2983 }
2984 TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
2985 switch (n->type) {
2986 case NSEMI:
2987 evaltree(n->nbinary.ch1, flags & EV_TESTED);
2988 if (evalskip)
2989 goto out;
2990 evaltree(n->nbinary.ch2, flags);
2991 break;
2992 case NAND:
2993 evaltree(n->nbinary.ch1, EV_TESTED);
2994 if (evalskip || exitstatus != 0)
2995 goto out;
2996 evaltree(n->nbinary.ch2, flags);
2997 break;
2998 case NOR:
2999 evaltree(n->nbinary.ch1, EV_TESTED);
3000 if (evalskip || exitstatus == 0)
3001 goto out;
3002 evaltree(n->nbinary.ch2, flags);
3003 break;
3004 case NREDIR:
3005 expredir(n->nredir.redirect);
3006 redirect(n->nredir.redirect, REDIR_PUSH);
3007 evaltree(n->nredir.n, flags);
3008 popredir();
3009 break;
3010 case NSUBSHELL:
3011 evalsubshell(n, flags);
3012 break;
3013 case NBACKGND:
3014 evalsubshell(n, flags);
3015 break;
3016 case NIF: {
3017 evaltree(n->nif.test, EV_TESTED);
3018 if (evalskip)
3019 goto out;
3020 if (exitstatus == 0)
3021 evaltree(n->nif.ifpart, flags);
3022 else if (n->nif.elsepart)
3023 evaltree(n->nif.elsepart, flags);
3024 else
3025 exitstatus = 0;
3026 break;
3027 }
3028 case NWHILE:
3029 case NUNTIL:
3030 evalloop(n, flags);
3031 break;
3032 case NFOR:
3033 evalfor(n, flags);
3034 break;
3035 case NCASE:
3036 evalcase(n, flags);
3037 break;
3038 case NDEFUN: {
3039 struct builtincmd *bcmd;
3040 struct cmdentry entry;
3041 if (
3042 (bcmd = find_builtin(n->narg.text)) &&
3043 IS_BUILTIN_SPECIAL(bcmd)
3044 ) {
3045 out2fmt("%s is a special built-in\n", n->narg.text);
3046 exitstatus = 1;
3047 break;
3048 }
3049 entry.cmdtype = CMDFUNCTION;
3050 entry.u.func = copyfunc(n->narg.next);
3051 addcmdentry(n->narg.text, &entry);
3052 exitstatus = 0;
3053 break;
3054 }
3055 case NNOT:
3056 evaltree(n->nnot.com, EV_TESTED);
3057 exitstatus = !exitstatus;
3058 break;
Eric Andersencb57d552001-06-28 07:25:16 +00003059
Eric Andersen62483552001-07-10 06:09:16 +00003060 case NPIPE:
3061 evalpipe(n);
3062 checkexit = 1;
3063 break;
3064 case NCMD:
3065 evalcommand(n, flags);
3066 checkexit = 1;
3067 break;
3068#ifdef DEBUG
3069 default:
3070 printf("Node type = %d\n", n->type);
3071 break;
3072#endif
3073 }
3074out:
3075 if (pendingsigs)
3076 dotrap();
3077 if (
3078 flags & EV_EXIT ||
3079 (checkexit && eflag && exitstatus && !(flags & EV_TESTED))
3080 )
3081 exitshell(exitstatus);
3082}
3083
3084/*
3085 * Kick off a subshell to evaluate a tree.
3086 */
3087
3088static void
3089evalsubshell(const union node *n, int flags)
3090{
3091 struct job *jp;
3092 int backgnd = (n->type == NBACKGND);
3093
3094 expredir(n->nredir.redirect);
3095 jp = makejob(n, 1);
3096 if (forkshell(jp, n, backgnd) == 0) {
3097 if (backgnd)
3098 flags &=~ EV_TESTED;
3099 redirect(n->nredir.redirect, 0);
3100 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
3101 }
3102 if (! backgnd) {
3103 INTOFF;
3104 exitstatus = waitforjob(jp);
3105 INTON;
3106 }
3107}
3108
3109/*
3110 * Compute the names of the files in a redirection list.
3111 */
3112
3113static void fixredir(union node *n, const char *text, int err);
3114
3115static void
3116expredir(union node *n)
3117{
3118 union node *redir;
3119
3120 for (redir = n ; redir ; redir = redir->nfile.next) {
3121 struct arglist fn;
3122 fn.lastp = &fn.list;
3123 oexitstatus = exitstatus;
3124 switch (redir->type) {
3125 case NFROMTO:
3126 case NFROM:
3127 case NTO:
3128 case NAPPEND:
3129 case NTOOV:
3130 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3131 redir->nfile.expfname = fn.list->text;
3132 break;
3133 case NFROMFD:
3134 case NTOFD:
3135 if (redir->ndup.vname) {
3136 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3137 fixredir(redir, fn.list->text, 1);
3138 }
3139 break;
3140 }
3141 }
3142}
3143
3144
3145/*
3146 * Execute a command inside back quotes. If it's a builtin command, we
3147 * want to save its output in a block obtained from malloc. Otherwise
3148 * we fork off a subprocess and get the output of the command via a pipe.
3149 * Should be called with interrupts off.
3150 */
3151
3152static void
3153evalbackcmd(union node *n, struct backcmd *result)
3154{
3155 int pip[2];
3156 struct job *jp;
3157 struct stackmark smark; /* unnecessary */
3158
3159 setstackmark(&smark);
3160 result->fd = -1;
3161 result->buf = NULL;
3162 result->nleft = 0;
3163 result->jp = NULL;
3164 if (n == NULL) {
3165 exitstatus = 0;
3166 goto out;
3167 }
3168 exitstatus = 0;
3169 if (pipe(pip) < 0)
3170 error("Pipe call failed");
3171 jp = makejob(n, 1);
3172 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3173 FORCEINTON;
3174 close(pip[0]);
3175 if (pip[1] != 1) {
3176 close(1);
3177 dup_as_newfd(pip[1], 1);
3178 close(pip[1]);
3179 }
3180 eflag = 0;
3181 evaltree(n, EV_EXIT);
3182 }
3183 close(pip[1]);
3184 result->fd = pip[0];
3185 result->jp = jp;
3186out:
3187 popstackmark(&smark);
3188 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
3189 result->fd, result->buf, result->nleft, result->jp));
3190}
3191
3192
3193/*
3194 * Execute a simple command.
3195 */
Eric Andersencb57d552001-06-28 07:25:16 +00003196
3197/*
3198 * Search for a command. This is called before we fork so that the
3199 * location of the command will be available in the parent as well as
3200 * the child. The check for "goodname" is an overly conservative
3201 * check that the name will not be subject to expansion.
3202 */
3203
3204static void
3205prehash(n)
3206 union node *n;
3207{
3208 struct cmdentry entry;
3209
3210 if (n->type == NCMD && n->ncmd.args)
3211 if (goodname(n->ncmd.args->narg.text))
3212 find_command(n->ncmd.args->narg.text, &entry, 0,
3213 pathval());
3214}
3215
3216
Eric Andersencb57d552001-06-28 07:25:16 +00003217/*
3218 * Builtin commands. Builtin commands whose functions are closely
3219 * tied to evaluation are implemented here.
3220 */
3221
3222/*
3223 * No command given, or a bltin command with no arguments. Set the
3224 * specified variables.
3225 */
3226
3227int
3228bltincmd(argc, argv)
3229 int argc;
3230 char **argv;
3231{
3232 /*
3233 * Preserve exitstatus of a previous possible redirection
3234 * as POSIX mandates
3235 */
3236 return exitstatus;
3237}
3238
3239
3240/*
3241 * Handle break and continue commands. Break, continue, and return are
3242 * all handled by setting the evalskip flag. The evaluation routines
3243 * above all check this flag, and if it is set they start skipping
3244 * commands rather than executing them. The variable skipcount is
3245 * the number of loops to break/continue, or the number of function
3246 * levels to return. (The latter is always 1.) It should probably
3247 * be an error to break out of more loops than exist, but it isn't
3248 * in the standard shell so we don't make it one here.
3249 */
3250
3251static int
3252breakcmd(argc, argv)
3253 int argc;
3254 char **argv;
3255{
3256 int n = argc > 1 ? number(argv[1]) : 1;
3257
3258 if (n > loopnest)
3259 n = loopnest;
3260 if (n > 0) {
3261 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
3262 skipcount = n;
3263 }
3264 return 0;
3265}
3266
3267
3268/*
3269 * The return command.
3270 */
3271
3272static int
3273returncmd(argc, argv)
3274 int argc;
3275 char **argv;
3276{
3277 int ret = argc > 1 ? number(argv[1]) : oexitstatus;
3278
3279 if (funcnest) {
3280 evalskip = SKIPFUNC;
3281 skipcount = 1;
3282 return ret;
3283 }
3284 else {
3285 /* Do what ksh does; skip the rest of the file */
3286 evalskip = SKIPFILE;
3287 skipcount = 1;
3288 return ret;
3289 }
3290}
3291
3292
3293#ifndef BB_TRUE_FALSE
3294static int
3295false_main(argc, argv)
3296 int argc;
3297 char **argv;
3298{
3299 return 1;
3300}
3301
3302
3303static int
3304true_main(argc, argv)
3305 int argc;
3306 char **argv;
3307{
3308 return 0;
3309}
3310#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003311
3312/*
3313 * Controls whether the shell is interactive or not.
3314 */
3315
3316static void setsignal(int signo);
3317static void chkmail(int silent);
3318
3319
3320static void
3321setinteractive(int on)
3322{
3323 static int is_interactive;
Eric Andersen1c039232001-07-07 00:05:55 +00003324 static int do_banner=0;
Eric Andersen2870d962001-07-02 17:27:21 +00003325
3326 if (on == is_interactive)
3327 return;
3328 setsignal(SIGINT);
3329 setsignal(SIGQUIT);
3330 setsignal(SIGTERM);
3331 chkmail(1);
3332 is_interactive = on;
Eric Andersen1c039232001-07-07 00:05:55 +00003333 if (do_banner==0 && is_interactive) {
3334 /* Looks like they want an interactive shell */
3335 printf( "\n\n" BB_BANNER " Built-in shell (ash)\n");
3336 printf( "Enter 'help' for a list of built-in commands.\n\n");
3337 do_banner=1;
3338 }
Eric Andersen2870d962001-07-02 17:27:21 +00003339}
3340
3341static void
3342optschanged(void)
3343{
3344 setinteractive(iflag);
3345 setjobctl(mflag);
3346}
3347
Eric Andersencb57d552001-06-28 07:25:16 +00003348
3349static int
3350execcmd(argc, argv)
3351 int argc;
3352 char **argv;
3353{
3354 if (argc > 1) {
3355 struct strlist *sp;
3356
Eric Andersen2870d962001-07-02 17:27:21 +00003357 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003358 mflag = 0;
3359 optschanged();
3360 for (sp = cmdenviron; sp ; sp = sp->next)
3361 setvareq(sp->text, VEXPORT|VSTACK);
3362 shellexec(argv + 1, environment(), pathval(), 0);
3363 }
3364 return 0;
3365}
3366
3367static void
3368eprintlist(struct strlist *sp)
3369{
3370 for (; sp; sp = sp->next) {
Eric Andersen3102ac42001-07-06 04:26:23 +00003371 out2fmt(" %s",sp->text);
Eric Andersencb57d552001-06-28 07:25:16 +00003372 }
3373}
Eric Andersencb57d552001-06-28 07:25:16 +00003374
3375/*
3376 * Exec a program. Never returns. If you change this routine, you may
3377 * have to change the find_command routine as well.
3378 */
3379
Eric Andersen2870d962001-07-02 17:27:21 +00003380static const char *pathopt; /* set by padvance */
3381
Eric Andersencb57d552001-06-28 07:25:16 +00003382static void
3383shellexec(argv, envp, path, idx)
3384 char **argv, **envp;
3385 const char *path;
3386 int idx;
3387{
3388 char *cmdname;
3389 int e;
3390
3391 if (strchr(argv[0], '/') != NULL) {
3392 tryexec(argv[0], argv, envp);
3393 e = errno;
3394 } else {
3395 e = ENOENT;
3396 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3397 if (--idx < 0 && pathopt == NULL) {
3398 tryexec(cmdname, argv, envp);
3399 if (errno != ENOENT && errno != ENOTDIR)
3400 e = errno;
3401 }
3402 stunalloc(cmdname);
3403 }
3404 }
3405
3406 /* Map to POSIX errors */
3407 switch (e) {
3408 case EACCES:
3409 exerrno = 126;
3410 break;
3411 case ENOENT:
3412 exerrno = 127;
3413 break;
3414 default:
3415 exerrno = 2;
3416 break;
3417 }
3418 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3419 /* NOTREACHED */
3420}
3421
Eric Andersen2870d962001-07-02 17:27:21 +00003422/*
3423 * Clear traps on a fork.
3424 */
3425static void
3426clear_traps(void) {
3427 char **tp;
3428
3429 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
3430 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
3431 INTOFF;
3432 ckfree(*tp);
3433 *tp = NULL;
3434 if (tp != &trap[0])
3435 setsignal(tp - trap);
3436 INTON;
3437 }
3438 }
3439}
3440
3441
3442static void
3443initshellproc(void) {
3444
3445#ifdef ASH_ALIAS
3446 /* from alias.c: */
3447 {
3448 rmaliases();
3449 }
3450#endif
3451 /* from eval.c: */
3452 {
3453 exitstatus = 0;
3454 }
3455
3456 /* from exec.c: */
3457 {
3458 deletefuncs();
3459 }
3460
3461 /* from jobs.c: */
3462 {
3463 backgndpid = -1;
3464#ifdef JOBS
3465 jobctl = 0;
3466#endif
3467 }
3468
3469 /* from options.c: */
3470 {
3471 int i;
3472
3473 for (i = 0; i < NOPTS; i++)
3474 optent_val(i) = 0;
3475 optschanged();
3476
3477 }
3478
3479 /* from redir.c: */
3480 {
3481 clearredir();
3482 }
3483
3484 /* from trap.c: */
3485 {
3486 char *sm;
3487
3488 clear_traps();
3489 for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) {
3490 if (*sm == S_IGN)
3491 *sm = S_HARD_IGN;
3492 }
3493 }
3494
3495 /* from var.c: */
3496 {
3497 shprocvar();
3498 }
3499}
3500
3501static int preadbuffer(void);
3502static void pushfile (void);
Eric Andersen2870d962001-07-02 17:27:21 +00003503
3504/*
3505 * Read a character from the script, returning PEOF on end of file.
3506 * Nul characters in the input are silently discarded.
3507 */
3508
Eric Andersen3102ac42001-07-06 04:26:23 +00003509#ifndef ASH_OPTIMIZE_FOR_SIZE
Eric Andersen2870d962001-07-02 17:27:21 +00003510#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
3511static int
3512pgetc(void)
3513{
3514 return pgetc_macro();
3515}
3516#else
3517static int
3518pgetc_macro(void)
3519{
3520 return --parsenleft >= 0? *parsenextc++ : preadbuffer();
3521}
3522
3523static inline int
3524pgetc(void)
3525{
3526 return pgetc_macro();
3527}
3528#endif
3529
3530
3531/*
3532 * Undo the last call to pgetc. Only one character may be pushed back.
3533 * PEOF may be pushed back.
3534 */
3535
3536static void
3537pungetc() {
3538 parsenleft++;
3539 parsenextc--;
3540}
3541
3542
3543static void
3544popfile(void) {
3545 struct parsefile *pf = parsefile;
3546
3547 INTOFF;
3548 if (pf->fd >= 0)
3549 close(pf->fd);
3550 if (pf->buf)
3551 ckfree(pf->buf);
3552 while (pf->strpush)
3553 popstring();
3554 parsefile = pf->prev;
3555 ckfree(pf);
3556 parsenleft = parsefile->nleft;
3557 parselleft = parsefile->lleft;
3558 parsenextc = parsefile->nextc;
3559 plinno = parsefile->linno;
3560 INTON;
3561}
3562
3563
3564/*
3565 * Return to top level.
3566 */
3567
3568static void
3569popallfiles(void) {
3570 while (parsefile != &basepf)
3571 popfile();
3572}
3573
3574/*
3575 * Close the file(s) that the shell is reading commands from. Called
3576 * after a fork is done.
3577 */
3578
3579static void
3580closescript() {
3581 popallfiles();
3582 if (parsefile->fd > 0) {
3583 close(parsefile->fd);
3584 parsefile->fd = 0;
3585 }
3586}
3587
3588
3589/*
3590 * Like setinputfile, but takes an open file descriptor. Call this with
3591 * interrupts off.
3592 */
3593
3594static void
3595setinputfd(fd, push)
3596 int fd, push;
3597{
3598 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
3599 if (push) {
3600 pushfile();
3601 parsefile->buf = 0;
3602 } else {
3603 closescript();
3604 while (parsefile->strpush)
3605 popstring();
3606 }
3607 parsefile->fd = fd;
3608 if (parsefile->buf == NULL)
3609 parsefile->buf = ckmalloc(BUFSIZ);
3610 parselleft = parsenleft = 0;
3611 plinno = 1;
3612}
3613
3614
3615/*
3616 * Set the input to take input from a file. If push is set, push the
3617 * old input onto the stack first.
3618 */
3619
3620static void
3621setinputfile(const char *fname, int push)
3622{
3623 int fd;
3624 int myfileno2;
3625
3626 INTOFF;
3627 if ((fd = open(fname, O_RDONLY)) < 0)
3628 error("Can't open %s", fname);
3629 if (fd < 10) {
3630 myfileno2 = dup_as_newfd(fd, 10);
3631 close(fd);
3632 if (myfileno2 < 0)
3633 error("Out of file descriptors");
3634 fd = myfileno2;
3635 }
3636 setinputfd(fd, push);
3637 INTON;
3638}
3639
Eric Andersencb57d552001-06-28 07:25:16 +00003640
3641static void
Eric Andersen62483552001-07-10 06:09:16 +00003642tryexec(char *cmd, char **argv, char **envp)
3643{
Eric Andersencb57d552001-06-28 07:25:16 +00003644 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003645
Eric Andersen3102ac42001-07-06 04:26:23 +00003646#ifdef BB_FEATURE_SH_STANDALONE_SHELL
3647 char *name = cmd;
3648 char** argv_l=argv;
3649 int argc_l;
3650#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
3651 name = get_last_path_component(name);
3652#endif
3653 argv_l=envp;
3654 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
3655 putenv(*argv_l);
3656 argv_l=argv;
Eric Andersen62483552001-07-10 06:09:16 +00003657 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
Eric Andersen3102ac42001-07-06 04:26:23 +00003658 optind = 1;
3659 run_applet_by_name(name, argc_l, argv);
3660#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003661 execve(cmd, argv, envp);
Eric Andersencb57d552001-06-28 07:25:16 +00003662 e = errno;
3663 if (e == ENOEXEC) {
3664 INTOFF;
3665 initshellproc();
3666 setinputfile(cmd, 0);
3667 commandname = arg0 = savestr(argv[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00003668 setparam(argv + 1);
3669 exraise(EXSHELLPROC);
3670 }
3671 errno = e;
3672}
3673
Eric Andersen2870d962001-07-02 17:27:21 +00003674static char *commandtext (const union node *);
Eric Andersencb57d552001-06-28 07:25:16 +00003675
3676/*
3677 * Do a path search. The variable path (passed by reference) should be
3678 * set to the start of the path before the first call; padvance will update
3679 * this value as it proceeds. Successive calls to padvance will return
3680 * the possible path expansions in sequence. If an option (indicated by
3681 * a percent sign) appears in the path entry then the global variable
3682 * pathopt will be set to point to it; otherwise pathopt will be set to
3683 * NULL.
3684 */
3685
3686static const char *pathopt;
3687
Eric Andersen2870d962001-07-02 17:27:21 +00003688static void growstackblock(void);
3689
3690
Eric Andersencb57d552001-06-28 07:25:16 +00003691static char *
Eric Andersen2870d962001-07-02 17:27:21 +00003692padvance(const char **path, const char *name)
3693{
Eric Andersencb57d552001-06-28 07:25:16 +00003694 const char *p;
3695 char *q;
3696 const char *start;
3697 int len;
3698
3699 if (*path == NULL)
3700 return NULL;
3701 start = *path;
3702 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
Eric Andersen2870d962001-07-02 17:27:21 +00003703 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003704 while (stackblocksize() < len)
3705 growstackblock();
3706 q = stackblock();
3707 if (p != start) {
3708 memcpy(q, start, p - start);
3709 q += p - start;
3710 *q++ = '/';
3711 }
3712 strcpy(q, name);
3713 pathopt = NULL;
3714 if (*p == '%') {
3715 pathopt = ++p;
3716 while (*p && *p != ':') p++;
3717 }
3718 if (*p == ':')
3719 *path = p + 1;
3720 else
3721 *path = NULL;
3722 return stalloc(len);
3723}
3724
Eric Andersen62483552001-07-10 06:09:16 +00003725/*
3726 * Wrapper around strcmp for qsort/bsearch/...
3727 */
3728static int
3729pstrcmp(const void *a, const void *b)
3730{
3731 return strcmp((const char *) a, *(const char *const *) b);
3732}
3733
3734/*
3735 * Find a keyword is in a sorted array.
3736 */
3737
3738static const char *const *
3739findkwd(const char *s)
3740{
3741 return bsearch(s, parsekwd, sizeof(parsekwd) / sizeof(const char *),
3742 sizeof(const char *), pstrcmp);
3743}
Eric Andersencb57d552001-06-28 07:25:16 +00003744
3745
3746/*** Command hashing code ***/
3747
3748
3749static int
3750hashcmd(argc, argv)
3751 int argc;
3752 char **argv;
3753{
3754 struct tblentry **pp;
3755 struct tblentry *cmdp;
3756 int c;
3757 int verbose;
3758 struct cmdentry entry;
3759 char *name;
Eric Andersen62483552001-07-10 06:09:16 +00003760#ifdef ASH_ALIAS
3761 const struct alias *ap;
3762#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003763
3764 verbose = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003765 while ((c = nextopt("rvV")) != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00003766 if (c == 'r') {
3767 clearcmdentry(0);
3768 return 0;
Eric Andersen62483552001-07-10 06:09:16 +00003769 } else if (c == 'v' || c == 'V') {
3770 verbose = c;
Eric Andersencb57d552001-06-28 07:25:16 +00003771 }
3772 }
3773 if (*argptr == NULL) {
3774 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3775 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3776 if (cmdp->cmdtype != CMDBUILTIN) {
3777 printentry(cmdp, verbose);
3778 }
3779 }
3780 }
3781 return 0;
3782 }
3783 c = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003784 while ((name = *argptr++) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00003785 if ((cmdp = cmdlookup(name, 0)) != NULL
3786 && (cmdp->cmdtype == CMDNORMAL
3787 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3788 delete_cmd_entry();
Eric Andersen62483552001-07-10 06:09:16 +00003789#ifdef ASH_ALIAS
3790 /* Then look at the aliases */
3791 if ((ap = lookupalias(name, 0)) != NULL) {
3792 if (verbose=='v')
3793 printf("%s is an alias for %s\n", name, ap->val);
3794 else
3795 printalias(ap);
3796 continue;
3797 }
3798#endif
3799 /* First look at the keywords */
3800 if (findkwd(name)!=0) {
3801 if (verbose=='v')
3802 printf("%s is a shell keyword\n", name);
3803 else
3804 printf(snlfmt, name);
3805 continue;
3806 }
3807
Eric Andersencb57d552001-06-28 07:25:16 +00003808 find_command(name, &entry, DO_ERR, pathval());
3809 if (entry.cmdtype == CMDUNKNOWN) c = 1;
3810 else if (verbose) {
3811 cmdp = cmdlookup(name, 0);
Eric Andersen62483552001-07-10 06:09:16 +00003812 if (cmdp) printentry(cmdp, verbose=='v');
Eric Andersencb57d552001-06-28 07:25:16 +00003813 flushall();
3814 }
Eric Andersencb57d552001-06-28 07:25:16 +00003815 }
3816 return c;
3817}
3818
Eric Andersencb57d552001-06-28 07:25:16 +00003819static void
3820printentry(cmdp, verbose)
3821 struct tblentry *cmdp;
3822 int verbose;
3823 {
3824 int idx;
3825 const char *path;
3826 char *name;
3827
Eric Andersen62483552001-07-10 06:09:16 +00003828 printf("%s%s", cmdp->cmdname, (verbose ? " is " : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00003829 if (cmdp->cmdtype == CMDNORMAL) {
3830 idx = cmdp->param.index;
3831 path = pathval();
3832 do {
3833 name = padvance(&path, cmdp->cmdname);
3834 stunalloc(name);
3835 } while (--idx >= 0);
Eric Andersen62483552001-07-10 06:09:16 +00003836 if(verbose)
3837 out1str(name);
Eric Andersencb57d552001-06-28 07:25:16 +00003838 } else if (cmdp->cmdtype == CMDBUILTIN) {
Eric Andersen62483552001-07-10 06:09:16 +00003839 if(verbose)
3840 out1str("a shell builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00003841 } else if (cmdp->cmdtype == CMDFUNCTION) {
Eric Andersencb57d552001-06-28 07:25:16 +00003842 if (verbose) {
3843 INTOFF;
Eric Andersen62483552001-07-10 06:09:16 +00003844 out1str("a function\n");
Eric Andersencb57d552001-06-28 07:25:16 +00003845 name = commandtext(cmdp->param.func);
Eric Andersen62483552001-07-10 06:09:16 +00003846 printf("%s() {\n %s\n}", cmdp->cmdname, name);
Eric Andersencb57d552001-06-28 07:25:16 +00003847 ckfree(name);
3848 INTON;
3849 }
3850#ifdef DEBUG
3851 } else {
3852 error("internal error: cmdtype %d", cmdp->cmdtype);
3853#endif
3854 }
Eric Andersen62483552001-07-10 06:09:16 +00003855 printf(snlfmt, cmdp->rehash ? "*" : nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +00003856}
3857
3858
3859
Eric Andersen1c039232001-07-07 00:05:55 +00003860/*** List the available builtins ***/
3861
3862
3863static int helpcmd(int argc, char** argv)
3864{
3865 int col, i;
Eric Andersen1c039232001-07-07 00:05:55 +00003866
Eric Andersen62483552001-07-10 06:09:16 +00003867 printf("\nBuilt-in commands:\n-------------------\n");
3868 for (col=0, i=0; i < NUMBUILTINS; i++) {
3869 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3870 builtincmds[i].name+1);
Eric Andersen1c039232001-07-07 00:05:55 +00003871 if (col > 60) {
3872 printf("\n");
3873 col = 0;
3874 }
3875 }
3876#ifdef BB_FEATURE_SH_STANDALONE_SHELL
3877 {
Eric Andersen1c039232001-07-07 00:05:55 +00003878 extern const struct BB_applet applets[];
3879 extern const size_t NUM_APPLETS;
3880
Eric Andersen62483552001-07-10 06:09:16 +00003881 for (i=0; i < NUM_APPLETS; i++) {
3882
3883 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3884 applets[i].name);
Eric Andersen1c039232001-07-07 00:05:55 +00003885 if (col > 60) {
3886 printf("\n");
3887 col = 0;
3888 }
3889 }
3890 }
3891#endif
3892 printf("\n\n");
3893 return EXIT_SUCCESS;
3894}
3895
Eric Andersencb57d552001-06-28 07:25:16 +00003896/*
3897 * Resolve a command name. If you change this routine, you may have to
3898 * change the shellexec routine as well.
3899 */
3900
Eric Andersen2870d962001-07-02 17:27:21 +00003901static int prefix (const char *, const char *);
3902
Eric Andersencb57d552001-06-28 07:25:16 +00003903static void
Eric Andersen2870d962001-07-02 17:27:21 +00003904find_command(const char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003905{
3906 struct tblentry *cmdp;
3907 int idx;
3908 int prev;
3909 char *fullname;
3910 struct stat statb;
3911 int e;
3912 int bltin;
3913 int firstchange;
3914 int updatetbl;
Eric Andersen62483552001-07-10 06:09:16 +00003915 int regular;
Eric Andersencb57d552001-06-28 07:25:16 +00003916 struct builtincmd *bcmd;
3917
3918 /* If name contains a slash, don't use the hash table */
3919 if (strchr(name, '/') != NULL) {
3920 if (act & DO_ABS) {
3921 while (stat(name, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003922 if (errno != ENOENT && errno != ENOTDIR)
3923 e = errno;
3924 entry->cmdtype = CMDUNKNOWN;
3925 entry->u.index = -1;
3926 return;
3927 }
3928 entry->cmdtype = CMDNORMAL;
3929 entry->u.index = -1;
3930 return;
3931 }
3932 entry->cmdtype = CMDNORMAL;
3933 entry->u.index = 0;
3934 return;
3935 }
3936
3937 updatetbl = 1;
3938 if (act & DO_BRUTE) {
3939 firstchange = path_change(path, &bltin);
3940 } else {
3941 bltin = builtinloc;
3942 firstchange = 9999;
3943 }
3944
3945 /* If name is in the table, and not invalidated by cd, we're done */
3946 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
3947 if (cmdp->cmdtype == CMDFUNCTION) {
3948 if (act & DO_NOFUN) {
3949 updatetbl = 0;
3950 } else {
3951 goto success;
3952 }
3953 } else if (act & DO_BRUTE) {
3954 if ((cmdp->cmdtype == CMDNORMAL &&
3955 cmdp->param.index >= firstchange) ||
3956 (cmdp->cmdtype == CMDBUILTIN &&
3957 ((builtinloc < 0 && bltin >= 0) ?
3958 bltin : builtinloc) >= firstchange)) {
3959 /* need to recompute the entry */
3960 } else {
3961 goto success;
3962 }
3963 } else {
3964 goto success;
3965 }
3966 }
3967
3968 bcmd = find_builtin(name);
Eric Andersen2870d962001-07-02 17:27:21 +00003969 regular = bcmd && IS_BUILTIN_REGULAR(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00003970
3971 if (regular) {
3972 if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) {
Eric Andersen2870d962001-07-02 17:27:21 +00003973 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003974 }
3975 } else if (act & DO_BRUTE) {
3976 if (firstchange == 0) {
3977 updatetbl = 0;
3978 }
3979 }
3980
3981 /* If %builtin not in path, check for builtin next */
3982 if (regular || (bltin < 0 && bcmd)) {
3983builtin:
3984 if (!updatetbl) {
3985 entry->cmdtype = CMDBUILTIN;
3986 entry->u.cmd = bcmd;
3987 return;
3988 }
3989 INTOFF;
3990 cmdp = cmdlookup(name, 1);
3991 cmdp->cmdtype = CMDBUILTIN;
3992 cmdp->param.cmd = bcmd;
3993 INTON;
3994 goto success;
3995 }
3996
3997 /* We have to search path. */
Eric Andersen2870d962001-07-02 17:27:21 +00003998 prev = -1; /* where to start */
3999 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00004000 if (cmdp->cmdtype == CMDBUILTIN)
4001 prev = builtinloc;
4002 else
4003 prev = cmdp->param.index;
4004 }
4005
4006 e = ENOENT;
4007 idx = -1;
4008loop:
4009 while ((fullname = padvance(&path, name)) != NULL) {
4010 stunalloc(fullname);
4011 idx++;
4012 if (idx >= firstchange) {
4013 updatetbl = 0;
4014 }
4015 if (pathopt) {
4016 if (prefix("builtin", pathopt)) {
4017 if ((bcmd = find_builtin(name))) {
4018 goto builtin;
4019 }
4020 continue;
4021 } else if (!(act & DO_NOFUN) &&
4022 prefix("func", pathopt)) {
4023 /* handled below */
4024 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00004025 continue; /* ignore unimplemented options */
Eric Andersencb57d552001-06-28 07:25:16 +00004026 }
4027 }
4028 /* if rehash, don't redo absolute path names */
4029 if (fullname[0] == '/' && idx <= prev &&
4030 idx < firstchange) {
4031 if (idx < prev)
4032 continue;
4033 TRACE(("searchexec \"%s\": no change\n", name));
4034 goto success;
4035 }
4036 while (stat(fullname, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00004037 if (errno != ENOENT && errno != ENOTDIR)
4038 e = errno;
4039 goto loop;
4040 }
Eric Andersen2870d962001-07-02 17:27:21 +00004041 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00004042 if (!S_ISREG(statb.st_mode))
4043 continue;
Eric Andersen2870d962001-07-02 17:27:21 +00004044 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00004045 stalloc(strlen(fullname) + 1);
4046 readcmdfile(fullname);
4047 if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
4048 error("%s not defined in %s", name, fullname);
4049 stunalloc(fullname);
4050 goto success;
4051 }
Eric Andersencb57d552001-06-28 07:25:16 +00004052 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
4053 /* If we aren't called with DO_BRUTE and cmdp is set, it must
4054 be a function and we're being called with DO_NOFUN */
4055 if (!updatetbl) {
4056 entry->cmdtype = CMDNORMAL;
4057 entry->u.index = idx;
4058 return;
4059 }
4060 INTOFF;
4061 cmdp = cmdlookup(name, 1);
4062 cmdp->cmdtype = CMDNORMAL;
4063 cmdp->param.index = idx;
4064 INTON;
4065 goto success;
4066 }
4067
4068 /* We failed. If there was an entry for this command, delete it */
4069 if (cmdp && updatetbl)
4070 delete_cmd_entry();
4071 if (act & DO_ERR)
Eric Andersen3102ac42001-07-06 04:26:23 +00004072 out2fmt("%s: %s\n", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00004073 entry->cmdtype = CMDUNKNOWN;
4074 return;
4075
4076success:
4077 cmdp->rehash = 0;
4078 entry->cmdtype = cmdp->cmdtype;
4079 entry->u = cmdp->param;
4080}
4081
4082
4083
4084/*
4085 * Search the table of builtin commands.
4086 */
4087
Eric Andersen2870d962001-07-02 17:27:21 +00004088static int
4089bstrcmp(const void *name, const void *b)
4090{
4091 return strcmp((const char *)name, (*(const char *const *) b)+1);
4092}
4093
4094static struct builtincmd *
4095find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00004096{
4097 struct builtincmd *bp;
4098
Eric Andersen2870d962001-07-02 17:27:21 +00004099 bp = bsearch(name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd),
4100 bstrcmp
Eric Andersencb57d552001-06-28 07:25:16 +00004101 );
4102 return bp;
4103}
4104
4105
4106/*
4107 * Called when a cd is done. Marks all commands so the next time they
4108 * are executed they will be rehashed.
4109 */
4110
4111static void
Eric Andersen2870d962001-07-02 17:27:21 +00004112hashcd(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00004113 struct tblentry **pp;
4114 struct tblentry *cmdp;
4115
4116 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4117 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4118 if (cmdp->cmdtype == CMDNORMAL
4119 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
4120 cmdp->rehash = 1;
4121 }
4122 }
4123}
4124
4125
4126
4127/*
4128 * Called before PATH is changed. The argument is the new value of PATH;
4129 * pathval() still returns the old value at this point. Called with
4130 * interrupts off.
4131 */
4132
4133static void
Eric Andersen2870d962001-07-02 17:27:21 +00004134changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00004135{
4136 int firstchange;
4137 int bltin;
4138
4139 firstchange = path_change(newval, &bltin);
4140 if (builtinloc < 0 && bltin >= 0)
Eric Andersen2870d962001-07-02 17:27:21 +00004141 builtinloc = bltin; /* zap builtins */
Eric Andersencb57d552001-06-28 07:25:16 +00004142 clearcmdentry(firstchange);
4143 builtinloc = bltin;
4144}
4145
4146
4147/*
4148 * Clear out command entries. The argument specifies the first entry in
4149 * PATH which has changed.
4150 */
4151
4152static void
4153clearcmdentry(firstchange)
4154 int firstchange;
4155{
4156 struct tblentry **tblp;
4157 struct tblentry **pp;
4158 struct tblentry *cmdp;
4159
4160 INTOFF;
4161 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4162 pp = tblp;
4163 while ((cmdp = *pp) != NULL) {
4164 if ((cmdp->cmdtype == CMDNORMAL &&
4165 cmdp->param.index >= firstchange)
4166 || (cmdp->cmdtype == CMDBUILTIN &&
4167 builtinloc >= firstchange)) {
4168 *pp = cmdp->next;
4169 ckfree(cmdp);
4170 } else {
4171 pp = &cmdp->next;
4172 }
4173 }
4174 }
4175 INTON;
4176}
4177
4178
4179/*
4180 * Delete all functions.
4181 */
4182
Eric Andersencb57d552001-06-28 07:25:16 +00004183static void
Eric Andersen2870d962001-07-02 17:27:21 +00004184deletefuncs(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00004185 struct tblentry **tblp;
4186 struct tblentry **pp;
4187 struct tblentry *cmdp;
4188
4189 INTOFF;
4190 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4191 pp = tblp;
4192 while ((cmdp = *pp) != NULL) {
4193 if (cmdp->cmdtype == CMDFUNCTION) {
4194 *pp = cmdp->next;
4195 freefunc(cmdp->param.func);
4196 ckfree(cmdp);
4197 } else {
4198 pp = &cmdp->next;
4199 }
4200 }
4201 }
4202 INTON;
4203}
4204
4205
4206
4207/*
4208 * Locate a command in the command hash table. If "add" is nonzero,
4209 * add the command to the table if it is not already present. The
4210 * variable "lastcmdentry" is set to point to the address of the link
4211 * pointing to the entry, so that delete_cmd_entry can delete the
4212 * entry.
4213 */
4214
Eric Andersen2870d962001-07-02 17:27:21 +00004215static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00004216
4217static struct tblentry *
Eric Andersen2870d962001-07-02 17:27:21 +00004218cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00004219{
4220 int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00004221 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00004222 struct tblentry *cmdp;
4223 struct tblentry **pp;
4224
4225 p = name;
4226 hashval = *p << 4;
4227 while (*p)
4228 hashval += *p++;
4229 hashval &= 0x7FFF;
4230 pp = &cmdtable[hashval % CMDTABLESIZE];
4231 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4232 if (equal(cmdp->cmdname, name))
4233 break;
4234 pp = &cmdp->next;
4235 }
4236 if (add && cmdp == NULL) {
4237 INTOFF;
4238 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4239 + strlen(name) + 1);
4240 cmdp->next = NULL;
4241 cmdp->cmdtype = CMDUNKNOWN;
4242 cmdp->rehash = 0;
4243 strcpy(cmdp->cmdname, name);
4244 INTON;
4245 }
4246 lastcmdentry = pp;
4247 return cmdp;
4248}
4249
4250/*
4251 * Delete the command entry returned on the last lookup.
4252 */
4253
4254static void
4255delete_cmd_entry() {
4256 struct tblentry *cmdp;
4257
4258 INTOFF;
4259 cmdp = *lastcmdentry;
4260 *lastcmdentry = cmdp->next;
4261 ckfree(cmdp);
4262 INTON;
4263}
4264
4265
4266
Eric Andersencb57d552001-06-28 07:25:16 +00004267
4268
Eric Andersen62483552001-07-10 06:09:16 +00004269static const short nodesize[26] = {
4270 ALIGN(sizeof (struct nbinary)),
4271 ALIGN(sizeof (struct ncmd)),
4272 ALIGN(sizeof (struct npipe)),
4273 ALIGN(sizeof (struct nredir)),
4274 ALIGN(sizeof (struct nredir)),
4275 ALIGN(sizeof (struct nredir)),
4276 ALIGN(sizeof (struct nbinary)),
4277 ALIGN(sizeof (struct nbinary)),
4278 ALIGN(sizeof (struct nif)),
4279 ALIGN(sizeof (struct nbinary)),
4280 ALIGN(sizeof (struct nbinary)),
4281 ALIGN(sizeof (struct nfor)),
4282 ALIGN(sizeof (struct ncase)),
4283 ALIGN(sizeof (struct nclist)),
4284 ALIGN(sizeof (struct narg)),
4285 ALIGN(sizeof (struct narg)),
4286 ALIGN(sizeof (struct nfile)),
4287 ALIGN(sizeof (struct nfile)),
4288 ALIGN(sizeof (struct nfile)),
4289 ALIGN(sizeof (struct nfile)),
4290 ALIGN(sizeof (struct nfile)),
4291 ALIGN(sizeof (struct ndup)),
4292 ALIGN(sizeof (struct ndup)),
4293 ALIGN(sizeof (struct nhere)),
4294 ALIGN(sizeof (struct nhere)),
4295 ALIGN(sizeof (struct nnot)),
4296};
Eric Andersencb57d552001-06-28 07:25:16 +00004297
Eric Andersencb57d552001-06-28 07:25:16 +00004298
4299
4300/*
4301 * Delete a function if it exists.
4302 */
4303
4304static void
Eric Andersen2870d962001-07-02 17:27:21 +00004305unsetfunc(char *name)
4306{
Eric Andersencb57d552001-06-28 07:25:16 +00004307 struct tblentry *cmdp;
4308
4309 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
4310 freefunc(cmdp->param.func);
4311 delete_cmd_entry();
4312 }
4313}
4314
Eric Andersen2870d962001-07-02 17:27:21 +00004315
4316/*
Eric Andersencb57d552001-06-28 07:25:16 +00004317 * Locate and print what a word is...
4318 */
4319
4320static int
Eric Andersen62483552001-07-10 06:09:16 +00004321typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004322{
4323 int i;
4324 int err = 0;
Eric Andersen62483552001-07-10 06:09:16 +00004325 char *argv_a[2];
4326
4327 argv_a[1] = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004328
4329 for (i = 1; i < argc; i++) {
Eric Andersen62483552001-07-10 06:09:16 +00004330 argv_a[0] = argv[i];
4331 argptr = argv_a;
4332 optptr = "v";
4333 err |= hashcmd(argc, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00004334 }
4335 return err;
4336}
4337
Eric Andersen2870d962001-07-02 17:27:21 +00004338#ifdef ASH_CMDCMD
Eric Andersencb57d552001-06-28 07:25:16 +00004339static int
4340commandcmd(argc, argv)
4341 int argc;
4342 char **argv;
4343{
4344 int c;
4345 int default_path = 0;
4346 int verify_only = 0;
4347 int verbose_verify_only = 0;
4348
4349 while ((c = nextopt("pvV")) != '\0')
4350 switch (c) {
4351 case 'p':
4352 default_path = 1;
4353 break;
4354 case 'v':
4355 verify_only = 1;
4356 break;
4357 case 'V':
4358 verbose_verify_only = 1;
4359 break;
Eric Andersencb57d552001-06-28 07:25:16 +00004360 }
4361
4362 if (default_path + verify_only + verbose_verify_only > 1 ||
4363 !*argptr) {
Eric Andersen62483552001-07-10 06:09:16 +00004364 out2str(
4365 "command [-p] command [arg ...]\n"
4366 "command {-v|-V} command\n");
Eric Andersencb57d552001-06-28 07:25:16 +00004367 return EX_USAGE;
4368 }
4369
Eric Andersencb57d552001-06-28 07:25:16 +00004370 if (verify_only || verbose_verify_only) {
Eric Andersen62483552001-07-10 06:09:16 +00004371 char *argv_a[2];
4372
4373 argv_a[1] = 0;
4374 argv_a[0] = *argptr;
4375 argptr = argv_a;
4376 optptr = verbose_verify_only ? "v" : "V"; /* reverse special */
4377 return hashcmd(argc, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00004378 }
Eric Andersencb57d552001-06-28 07:25:16 +00004379
4380 return 0;
4381}
Eric Andersen2870d962001-07-02 17:27:21 +00004382#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004383
4384static int
4385path_change(newval, bltin)
4386 const char *newval;
4387 int *bltin;
4388{
4389 const char *old, *new;
4390 int idx;
4391 int firstchange;
4392
4393 old = pathval();
4394 new = newval;
Eric Andersen2870d962001-07-02 17:27:21 +00004395 firstchange = 9999; /* assume no change */
Eric Andersencb57d552001-06-28 07:25:16 +00004396 idx = 0;
4397 *bltin = -1;
4398 for (;;) {
4399 if (*old != *new) {
4400 firstchange = idx;
4401 if ((*old == '\0' && *new == ':')
4402 || (*old == ':' && *new == '\0'))
4403 firstchange++;
Eric Andersen2870d962001-07-02 17:27:21 +00004404 old = new; /* ignore subsequent differences */
Eric Andersencb57d552001-06-28 07:25:16 +00004405 }
4406 if (*new == '\0')
4407 break;
4408 if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1))
4409 *bltin = idx;
4410 if (*new == ':') {
4411 idx++;
4412 }
4413 new++, old++;
4414 }
4415 if (builtinloc >= 0 && *bltin < 0)
4416 firstchange = 0;
4417 return firstchange;
4418}
Eric Andersencb57d552001-06-28 07:25:16 +00004419/*
4420 * Routines to expand arguments to commands. We have to deal with
4421 * backquotes, shell variables, and file metacharacters.
4422 */
4423/*
4424 * _rmescape() flags
4425 */
Eric Andersen2870d962001-07-02 17:27:21 +00004426#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4427#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Eric Andersencb57d552001-06-28 07:25:16 +00004428
4429/*
4430 * Structure specifying which parts of the string should be searched
4431 * for IFS characters.
4432 */
4433
4434struct ifsregion {
Eric Andersen2870d962001-07-02 17:27:21 +00004435 struct ifsregion *next; /* next region in list */
4436 int begoff; /* offset of start of region */
4437 int endoff; /* offset of end of region */
4438 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004439};
4440
4441
Eric Andersen2870d962001-07-02 17:27:21 +00004442static char *expdest; /* output of current string */
4443static struct nodelist *argbackq; /* list of back quote expressions */
4444static struct ifsregion ifsfirst; /* first struct in list of ifs regions */
4445static struct ifsregion *ifslastp; /* last struct in list */
4446static struct arglist exparg; /* holds expanded arg list */
Eric Andersencb57d552001-06-28 07:25:16 +00004447
Eric Andersen2870d962001-07-02 17:27:21 +00004448static void argstr (char *, int);
4449static char *exptilde (char *, int);
4450static void expbackq (union node *, int, int);
4451static int subevalvar (char *, char *, int, int, int, int, int);
Eric Andersen2870d962001-07-02 17:27:21 +00004452static int varisset (char *, int);
4453static void strtodest (const char *, const char *, int);
4454static void varvalue (char *, int, int);
4455static void recordregion (int, int, int);
4456static void removerecordregions (int);
4457static void ifsbreakup (char *, struct arglist *);
4458static void ifsfree (void);
4459static void expandmeta (struct strlist *, int);
Eric Andersen62483552001-07-10 06:09:16 +00004460#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00004461#define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB)
4462#if !defined(GLOB_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00004463static void addglob (const glob_t *);
Eric Andersencb57d552001-06-28 07:25:16 +00004464#endif
4465#endif
Eric Andersen62483552001-07-10 06:09:16 +00004466#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersen2870d962001-07-02 17:27:21 +00004467static void expmeta (char *, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004468#endif
Eric Andersen62483552001-07-10 06:09:16 +00004469#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersen2870d962001-07-02 17:27:21 +00004470static struct strlist *expsort (struct strlist *);
4471static struct strlist *msort (struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004472#endif
Eric Andersen2870d962001-07-02 17:27:21 +00004473static int patmatch (char *, char *, int);
Eric Andersen62483552001-07-10 06:09:16 +00004474#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00004475static int patmatch2 (char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004476#else
Eric Andersen2870d962001-07-02 17:27:21 +00004477static int pmatch (char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004478#define patmatch2 patmatch
4479#endif
Eric Andersen2870d962001-07-02 17:27:21 +00004480static char *cvtnum (int, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004481
4482/*
4483 * Expand shell variables and backquotes inside a here document.
4484 */
4485
Eric Andersen2870d962001-07-02 17:27:21 +00004486/* arg: the document, fd: where to write the expanded version */
Eric Andersen62483552001-07-10 06:09:16 +00004487static inline void
Eric Andersen2870d962001-07-02 17:27:21 +00004488expandhere(union node *arg, int fd)
4489{
Eric Andersencb57d552001-06-28 07:25:16 +00004490 herefd = fd;
4491 expandarg(arg, (struct arglist *)NULL, 0);
4492 xwrite(fd, stackblock(), expdest - stackblock());
4493}
4494
4495
4496/*
4497 * Perform variable substitution and command substitution on an argument,
4498 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4499 * perform splitting and file name expansion. When arglist is NULL, perform
4500 * here document expansion.
4501 */
4502
4503static void
4504expandarg(arg, arglist, flag)
4505 union node *arg;
4506 struct arglist *arglist;
4507 int flag;
4508{
4509 struct strlist *sp;
4510 char *p;
4511
4512 argbackq = arg->narg.backquote;
4513 STARTSTACKSTR(expdest);
4514 ifsfirst.next = NULL;
4515 ifslastp = NULL;
4516 argstr(arg->narg.text, flag);
4517 if (arglist == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00004518 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004519 }
4520 STPUTC('\0', expdest);
4521 p = grabstackstr(expdest);
4522 exparg.lastp = &exparg.list;
4523 /*
4524 * TODO - EXP_REDIR
4525 */
4526 if (flag & EXP_FULL) {
4527 ifsbreakup(p, &exparg);
4528 *exparg.lastp = NULL;
4529 exparg.lastp = &exparg.list;
4530 expandmeta(exparg.list, flag);
4531 } else {
4532 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4533 rmescapes(p);
4534 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4535 sp->text = p;
4536 *exparg.lastp = sp;
4537 exparg.lastp = &sp->next;
4538 }
4539 ifsfree();
4540 *exparg.lastp = NULL;
4541 if (exparg.list) {
4542 *arglist->lastp = exparg.list;
4543 arglist->lastp = exparg.lastp;
4544 }
4545}
4546
4547
Eric Andersen62483552001-07-10 06:09:16 +00004548/*
4549 * Expand a variable, and return a pointer to the next character in the
4550 * input string.
4551 */
4552
4553static inline char *
4554evalvar(p, flag)
4555 char *p;
4556 int flag;
4557{
4558 int subtype;
4559 int varflags;
4560 char *var;
4561 const char *val;
4562 int patloc;
4563 int c;
4564 int set;
4565 int special;
4566 int startloc;
4567 int varlen;
4568 int easy;
4569 int quotes = flag & (EXP_FULL | EXP_CASE);
4570
4571 varflags = *p++;
4572 subtype = varflags & VSTYPE;
4573 var = p;
4574 special = 0;
4575 if (! is_name(*p))
4576 special = 1;
4577 p = strchr(p, '=') + 1;
4578again: /* jump here after setting a variable with ${var=text} */
4579 if (special) {
4580 set = varisset(var, varflags & VSNUL);
4581 val = NULL;
4582 } else {
4583 val = lookupvar(var);
4584 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
4585 val = NULL;
4586 set = 0;
4587 } else
4588 set = 1;
4589 }
4590 varlen = 0;
4591 startloc = expdest - stackblock();
4592 if (set && subtype != VSPLUS) {
4593 /* insert the value of the variable */
4594 if (special) {
4595 varvalue(var, varflags & VSQUOTE, flag);
4596 if (subtype == VSLENGTH) {
4597 varlen = expdest - stackblock() - startloc;
4598 STADJUST(-varlen, expdest);
4599 }
4600 } else {
4601 if (subtype == VSLENGTH) {
4602 varlen = strlen(val);
4603 } else {
4604 strtodest(
4605 val,
4606 varflags & VSQUOTE ?
4607 DQSYNTAX : BASESYNTAX,
4608 quotes
4609 );
4610 }
4611 }
4612 }
4613
4614 if (subtype == VSPLUS)
4615 set = ! set;
4616
4617 easy = ((varflags & VSQUOTE) == 0 ||
4618 (*var == '@' && shellparam.nparam != 1));
4619
4620
4621 switch (subtype) {
4622 case VSLENGTH:
4623 expdest = cvtnum(varlen, expdest);
4624 goto record;
4625
4626 case VSNORMAL:
4627 if (!easy)
4628 break;
4629record:
4630 recordregion(startloc, expdest - stackblock(),
4631 varflags & VSQUOTE);
4632 break;
4633
4634 case VSPLUS:
4635 case VSMINUS:
4636 if (!set) {
4637 argstr(p, flag);
4638 break;
4639 }
4640 if (easy)
4641 goto record;
4642 break;
4643
4644 case VSTRIMLEFT:
4645 case VSTRIMLEFTMAX:
4646 case VSTRIMRIGHT:
4647 case VSTRIMRIGHTMAX:
4648 if (!set)
4649 break;
4650 /*
4651 * Terminate the string and start recording the pattern
4652 * right after it
4653 */
4654 STPUTC('\0', expdest);
4655 patloc = expdest - stackblock();
4656 if (subevalvar(p, NULL, patloc, subtype,
4657 startloc, varflags, quotes) == 0) {
4658 int amount = (expdest - stackblock() - patloc) + 1;
4659 STADJUST(-amount, expdest);
4660 }
4661 /* Remove any recorded regions beyond start of variable */
4662 removerecordregions(startloc);
4663 goto record;
4664
4665 case VSASSIGN:
4666 case VSQUESTION:
4667 if (!set) {
4668 if (subevalvar(p, var, 0, subtype, startloc,
4669 varflags, quotes)) {
4670 varflags &= ~VSNUL;
4671 /*
4672 * Remove any recorded regions beyond
4673 * start of variable
4674 */
4675 removerecordregions(startloc);
4676 goto again;
4677 }
4678 break;
4679 }
4680 if (easy)
4681 goto record;
4682 break;
4683
4684#ifdef DEBUG
4685 default:
4686 abort();
4687#endif
4688 }
4689
4690 if (subtype != VSNORMAL) { /* skip to end of alternative */
4691 int nesting = 1;
4692 for (;;) {
4693 if ((c = *p++) == CTLESC)
4694 p++;
4695 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
4696 if (set)
4697 argbackq = argbackq->next;
4698 } else if (c == CTLVAR) {
4699 if ((*p++ & VSTYPE) != VSNORMAL)
4700 nesting++;
4701 } else if (c == CTLENDVAR) {
4702 if (--nesting == 0)
4703 break;
4704 }
4705 }
4706 }
4707 return p;
4708}
4709
Eric Andersencb57d552001-06-28 07:25:16 +00004710
4711/*
4712 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4713 * characters to allow for further processing. Otherwise treat
4714 * $@ like $* since no splitting will be performed.
4715 */
4716
4717static void
4718argstr(p, flag)
4719 char *p;
4720 int flag;
4721{
4722 char c;
Eric Andersen2870d962001-07-02 17:27:21 +00004723 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
Eric Andersencb57d552001-06-28 07:25:16 +00004724 int firsteq = 1;
4725
4726 if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
4727 p = exptilde(p, flag);
4728 for (;;) {
4729 switch (c = *p++) {
4730 case '\0':
4731 case CTLENDVAR: /* ??? */
4732 goto breakloop;
4733 case CTLQUOTEMARK:
4734 /* "$@" syntax adherence hack */
4735 if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
4736 break;
4737 if ((flag & EXP_FULL) != 0)
4738 STPUTC(c, expdest);
4739 break;
4740 case CTLESC:
4741 if (quotes)
4742 STPUTC(c, expdest);
4743 c = *p++;
4744 STPUTC(c, expdest);
4745 break;
4746 case CTLVAR:
4747 p = evalvar(p, flag);
4748 break;
4749 case CTLBACKQ:
4750 case CTLBACKQ|CTLQUOTE:
4751 expbackq(argbackq->n, c & CTLQUOTE, flag);
4752 argbackq = argbackq->next;
4753 break;
4754#ifdef ASH_MATH_SUPPORT
4755 case CTLENDARI:
4756 expari(flag);
4757 break;
Eric Andersen2870d962001-07-02 17:27:21 +00004758#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004759 case ':':
4760 case '=':
4761 /*
4762 * sort of a hack - expand tildes in variable
4763 * assignments (after the first '=' and after ':'s).
4764 */
4765 STPUTC(c, expdest);
4766 if (flag & EXP_VARTILDE && *p == '~') {
4767 if (c == '=') {
4768 if (firsteq)
4769 firsteq = 0;
4770 else
4771 break;
4772 }
4773 p = exptilde(p, flag);
4774 }
4775 break;
4776 default:
4777 STPUTC(c, expdest);
4778 }
4779 }
4780breakloop:;
4781 return;
4782}
4783
4784static char *
4785exptilde(p, flag)
4786 char *p;
4787 int flag;
4788{
4789 char c, *startp = p;
4790 struct passwd *pw;
4791 const char *home;
4792 int quotes = flag & (EXP_FULL | EXP_CASE);
4793
4794 while ((c = *p) != '\0') {
4795 switch(c) {
4796 case CTLESC:
4797 return (startp);
4798 case CTLQUOTEMARK:
4799 return (startp);
4800 case ':':
4801 if (flag & EXP_VARTILDE)
4802 goto done;
4803 break;
4804 case '/':
4805 goto done;
4806 }
4807 p++;
4808 }
4809done:
4810 *p = '\0';
4811 if (*(startp+1) == '\0') {
4812 if ((home = lookupvar("HOME")) == NULL)
4813 goto lose;
4814 } else {
4815 if ((pw = getpwnam(startp+1)) == NULL)
4816 goto lose;
4817 home = pw->pw_dir;
4818 }
4819 if (*home == '\0')
4820 goto lose;
4821 *p = c;
4822 strtodest(home, SQSYNTAX, quotes);
4823 return (p);
4824lose:
4825 *p = c;
4826 return (startp);
4827}
4828
4829
Eric Andersen2870d962001-07-02 17:27:21 +00004830static void
4831removerecordregions(int endoff)
Eric Andersencb57d552001-06-28 07:25:16 +00004832{
4833 if (ifslastp == NULL)
4834 return;
4835
4836 if (ifsfirst.endoff > endoff) {
4837 while (ifsfirst.next != NULL) {
4838 struct ifsregion *ifsp;
4839 INTOFF;
4840 ifsp = ifsfirst.next->next;
4841 ckfree(ifsfirst.next);
4842 ifsfirst.next = ifsp;
4843 INTON;
4844 }
4845 if (ifsfirst.begoff > endoff)
4846 ifslastp = NULL;
4847 else {
4848 ifslastp = &ifsfirst;
4849 ifsfirst.endoff = endoff;
4850 }
4851 return;
4852 }
Eric Andersen2870d962001-07-02 17:27:21 +00004853
Eric Andersencb57d552001-06-28 07:25:16 +00004854 ifslastp = &ifsfirst;
4855 while (ifslastp->next && ifslastp->next->begoff < endoff)
4856 ifslastp=ifslastp->next;
4857 while (ifslastp->next != NULL) {
4858 struct ifsregion *ifsp;
4859 INTOFF;
4860 ifsp = ifslastp->next->next;
4861 ckfree(ifslastp->next);
4862 ifslastp->next = ifsp;
4863 INTON;
4864 }
4865 if (ifslastp->endoff > endoff)
4866 ifslastp->endoff = endoff;
4867}
4868
4869
4870#ifdef ASH_MATH_SUPPORT
4871/*
4872 * Expand arithmetic expression. Backup to start of expression,
4873 * evaluate, place result in (backed up) result, adjust string position.
4874 */
4875static void
Eric Andersen2870d962001-07-02 17:27:21 +00004876expari(int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004877{
4878 char *p, *start;
4879 int result;
4880 int begoff;
4881 int quotes = flag & (EXP_FULL | EXP_CASE);
4882 int quoted;
4883
Eric Andersen2870d962001-07-02 17:27:21 +00004884 /* ifsfree(); */
Eric Andersencb57d552001-06-28 07:25:16 +00004885
4886 /*
4887 * This routine is slightly over-complicated for
4888 * efficiency. First we make sure there is
4889 * enough space for the result, which may be bigger
4890 * than the expression if we add exponentation. Next we
4891 * scan backwards looking for the start of arithmetic. If the
4892 * next previous character is a CTLESC character, then we
4893 * have to rescan starting from the beginning since CTLESC
4894 * characters have to be processed left to right.
4895 */
4896 CHECKSTRSPACE(10, expdest);
4897 USTPUTC('\0', expdest);
4898 start = stackblock();
4899 p = expdest - 1;
4900 while (*p != CTLARI && p >= start)
4901 --p;
4902 if (*p != CTLARI)
4903 error("missing CTLARI (shouldn't happen)");
4904 if (p > start && *(p-1) == CTLESC)
4905 for (p = start; *p != CTLARI; p++)
4906 if (*p == CTLESC)
4907 p++;
4908
4909 if (p[1] == '"')
4910 quoted=1;
4911 else
4912 quoted=0;
4913 begoff = p - start;
4914 removerecordregions(begoff);
4915 if (quotes)
4916 rmescapes(p+2);
4917 result = arith(p+2);
Eric Andersen3102ac42001-07-06 04:26:23 +00004918 snprintf(p, 12, "%d", result);
Eric Andersencb57d552001-06-28 07:25:16 +00004919
4920 while (*p++)
4921 ;
4922
4923 if (quoted == 0)
4924 recordregion(begoff, p - 1 - start, 0);
4925 result = expdest - p + 1;
4926 STADJUST(-result, expdest);
4927}
Eric Andersen2870d962001-07-02 17:27:21 +00004928#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004929
4930/*
4931 * Expand stuff in backwards quotes.
4932 */
4933
4934static void
4935expbackq(cmd, quoted, flag)
4936 union node *cmd;
4937 int quoted;
4938 int flag;
4939{
4940 volatile struct backcmd in;
4941 int i;
4942 char buf[128];
4943 char *p;
4944 char *dest = expdest;
4945 volatile struct ifsregion saveifs;
4946 struct ifsregion *volatile savelastp;
4947 struct nodelist *volatile saveargbackq;
4948 char lastc;
4949 int startloc = dest - stackblock();
4950 char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
4951 volatile int saveherefd;
4952 int quotes = flag & (EXP_FULL | EXP_CASE);
4953 struct jmploc jmploc;
4954 struct jmploc *volatile savehandler;
4955 int ex;
4956
4957#if __GNUC__
4958 /* Avoid longjmp clobbering */
4959 (void) &dest;
4960 (void) &syntax;
4961#endif
4962
4963 in.fd = -1;
4964 in.buf = 0;
4965 in.jp = 0;
4966
4967 INTOFF;
4968 saveifs = ifsfirst;
4969 savelastp = ifslastp;
4970 saveargbackq = argbackq;
4971 saveherefd = herefd;
4972 herefd = -1;
4973 if ((ex = setjmp(jmploc.loc))) {
4974 goto err1;
4975 }
4976 savehandler = handler;
4977 handler = &jmploc;
4978 INTON;
4979 p = grabstackstr(dest);
4980 evalbackcmd(cmd, (struct backcmd *) &in);
4981 ungrabstackstr(p, dest);
4982err1:
4983 INTOFF;
4984 ifsfirst = saveifs;
4985 ifslastp = savelastp;
4986 argbackq = saveargbackq;
4987 herefd = saveherefd;
4988 if (ex) {
4989 goto err2;
4990 }
4991
4992 p = in.buf;
4993 lastc = '\0';
4994 for (;;) {
4995 if (--in.nleft < 0) {
4996 if (in.fd < 0)
4997 break;
4998 while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR);
4999 TRACE(("expbackq: read returns %d\n", i));
5000 if (i <= 0)
5001 break;
5002 p = buf;
5003 in.nleft = i - 1;
5004 }
5005 lastc = *p++;
5006 if (lastc != '\0') {
5007 if (quotes && syntax[(int)lastc] == CCTL)
5008 STPUTC(CTLESC, dest);
5009 STPUTC(lastc, dest);
5010 }
5011 }
5012
5013 /* Eat all trailing newlines */
5014 for (; dest > stackblock() && dest[-1] == '\n';)
5015 STUNPUTC(dest);
5016
5017err2:
5018 if (in.fd >= 0)
5019 close(in.fd);
5020 if (in.buf)
5021 ckfree(in.buf);
5022 if (in.jp)
5023 exitstatus = waitforjob(in.jp);
5024 handler = savehandler;
5025 if (ex) {
5026 longjmp(handler->loc, 1);
5027 }
5028 if (quoted == 0)
5029 recordregion(startloc, dest - stackblock(), 0);
5030 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
5031 (dest - stackblock()) - startloc,
5032 (dest - stackblock()) - startloc,
5033 stackblock() + startloc));
5034 expdest = dest;
5035 INTON;
5036}
5037
Eric Andersencb57d552001-06-28 07:25:16 +00005038static int
5039subevalvar(p, str, strloc, subtype, startloc, varflags, quotes)
5040 char *p;
5041 char *str;
5042 int strloc;
5043 int subtype;
5044 int startloc;
5045 int varflags;
5046 int quotes;
5047{
5048 char *startp;
5049 char *loc = NULL;
5050 char *q;
5051 int c = 0;
5052 int saveherefd = herefd;
5053 struct nodelist *saveargbackq = argbackq;
5054 int amount;
5055
5056 herefd = -1;
5057 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5058 STACKSTRNUL(expdest);
5059 herefd = saveherefd;
5060 argbackq = saveargbackq;
5061 startp = stackblock() + startloc;
5062 if (str == NULL)
5063 str = stackblock() + strloc;
5064
5065 switch (subtype) {
5066 case VSASSIGN:
5067 setvar(str, startp, 0);
5068 amount = startp - expdest;
5069 STADJUST(amount, expdest);
5070 varflags &= ~VSNUL;
5071 if (c != 0)
5072 *loc = c;
5073 return 1;
5074
5075 case VSQUESTION:
5076 if (*p != CTLENDVAR) {
Eric Andersen3102ac42001-07-06 04:26:23 +00005077 out2fmt(snlfmt, startp);
Eric Andersencb57d552001-06-28 07:25:16 +00005078 error((char *)NULL);
5079 }
5080 error("%.*s: parameter %snot set", p - str - 1,
5081 str, (varflags & VSNUL) ? "null or "
5082 : nullstr);
5083 /* NOTREACHED */
5084
5085 case VSTRIMLEFT:
5086 for (loc = startp; loc < str; loc++) {
5087 c = *loc;
5088 *loc = '\0';
5089 if (patmatch2(str, startp, quotes))
5090 goto recordleft;
5091 *loc = c;
5092 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00005093 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00005094 }
5095 return 0;
5096
5097 case VSTRIMLEFTMAX:
5098 for (loc = str - 1; loc >= startp;) {
5099 c = *loc;
5100 *loc = '\0';
5101 if (patmatch2(str, startp, quotes))
5102 goto recordleft;
5103 *loc = c;
5104 loc--;
5105 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
5106 for (q = startp; q < loc; q++)
5107 if (*q == CTLESC)
5108 q++;
5109 if (q > loc)
5110 loc--;
5111 }
5112 }
5113 return 0;
5114
5115 case VSTRIMRIGHT:
Eric Andersen2870d962001-07-02 17:27:21 +00005116 for (loc = str - 1; loc >= startp;) {
Eric Andersencb57d552001-06-28 07:25:16 +00005117 if (patmatch2(str, loc, quotes))
5118 goto recordright;
5119 loc--;
Eric Andersen2870d962001-07-02 17:27:21 +00005120 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
Eric Andersencb57d552001-06-28 07:25:16 +00005121 for (q = startp; q < loc; q++)
5122 if (*q == CTLESC)
5123 q++;
5124 if (q > loc)
5125 loc--;
5126 }
5127 }
5128 return 0;
5129
5130 case VSTRIMRIGHTMAX:
5131 for (loc = startp; loc < str - 1; loc++) {
5132 if (patmatch2(str, loc, quotes))
5133 goto recordright;
5134 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00005135 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00005136 }
5137 return 0;
5138
5139#ifdef DEBUG
5140 default:
5141 abort();
5142#endif
5143 }
5144
5145recordleft:
5146 *loc = c;
5147 amount = ((str - 1) - (loc - startp)) - expdest;
5148 STADJUST(amount, expdest);
5149 while (loc != str - 1)
5150 *startp++ = *loc++;
5151 return 1;
5152
5153recordright:
5154 amount = loc - expdest;
5155 STADJUST(amount, expdest);
5156 STPUTC('\0', expdest);
5157 STADJUST(-1, expdest);
5158 return 1;
5159}
5160
5161
5162/*
Eric Andersencb57d552001-06-28 07:25:16 +00005163 * Test whether a specialized variable is set.
5164 */
5165
5166static int
5167varisset(name, nulok)
5168 char *name;
5169 int nulok;
5170{
5171 if (*name == '!')
5172 return backgndpid != -1;
5173 else if (*name == '@' || *name == '*') {
5174 if (*shellparam.p == NULL)
5175 return 0;
5176
5177 if (nulok) {
5178 char **av;
5179
5180 for (av = shellparam.p; *av; av++)
5181 if (**av != '\0')
5182 return 1;
5183 return 0;
5184 }
5185 } else if (is_digit(*name)) {
5186 char *ap;
5187 int num = atoi(name);
5188
5189 if (num > shellparam.nparam)
5190 return 0;
5191
5192 if (num == 0)
5193 ap = arg0;
5194 else
5195 ap = shellparam.p[num - 1];
5196
5197 if (nulok && (ap == NULL || *ap == '\0'))
5198 return 0;
5199 }
5200 return 1;
5201}
5202
Eric Andersencb57d552001-06-28 07:25:16 +00005203/*
5204 * Put a string on the stack.
5205 */
5206
5207static void
5208strtodest(p, syntax, quotes)
5209 const char *p;
5210 const char *syntax;
5211 int quotes;
5212{
5213 while (*p) {
5214 if (quotes && syntax[(int) *p] == CCTL)
5215 STPUTC(CTLESC, expdest);
5216 STPUTC(*p++, expdest);
5217 }
5218}
5219
Eric Andersencb57d552001-06-28 07:25:16 +00005220/*
5221 * Add the value of a specialized variable to the stack string.
5222 */
5223
5224static void
5225varvalue(name, quoted, flags)
5226 char *name;
5227 int quoted;
5228 int flags;
5229{
5230 int num;
5231 char *p;
5232 int i;
5233 int sep;
5234 int sepq = 0;
5235 char **ap;
5236 char const *syntax;
5237 int allow_split = flags & EXP_FULL;
5238 int quotes = flags & (EXP_FULL | EXP_CASE);
5239
5240 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5241 switch (*name) {
5242 case '$':
5243 num = rootpid;
5244 goto numvar;
5245 case '?':
5246 num = oexitstatus;
5247 goto numvar;
5248 case '#':
5249 num = shellparam.nparam;
5250 goto numvar;
5251 case '!':
5252 num = backgndpid;
5253numvar:
5254 expdest = cvtnum(num, expdest);
5255 break;
5256 case '-':
5257 for (i = 0 ; i < NOPTS ; i++) {
Eric Andersen2870d962001-07-02 17:27:21 +00005258 if (optent_val(i))
5259 STPUTC(optent_letter(optlist[i]), expdest);
Eric Andersencb57d552001-06-28 07:25:16 +00005260 }
5261 break;
5262 case '@':
5263 if (allow_split && quoted) {
5264 sep = 1 << CHAR_BIT;
5265 goto param;
5266 }
5267 /* fall through */
5268 case '*':
5269 sep = ifsset() ? ifsval()[0] : ' ';
5270 if (quotes) {
5271 sepq = syntax[(int) sep] == CCTL;
5272 }
5273param:
5274 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
5275 strtodest(p, syntax, quotes);
5276 if (*ap && sep) {
5277 if (sepq)
5278 STPUTC(CTLESC, expdest);
5279 STPUTC(sep, expdest);
5280 }
5281 }
5282 break;
5283 case '0':
5284 strtodest(arg0, syntax, quotes);
5285 break;
5286 default:
5287 num = atoi(name);
5288 if (num > 0 && num <= shellparam.nparam) {
5289 strtodest(shellparam.p[num - 1], syntax, quotes);
5290 }
5291 break;
5292 }
5293}
5294
5295
Eric Andersencb57d552001-06-28 07:25:16 +00005296/*
5297 * Record the fact that we have to scan this region of the
5298 * string for IFS characters.
5299 */
5300
5301static void
5302recordregion(start, end, nulonly)
5303 int start;
5304 int end;
5305 int nulonly;
5306{
5307 struct ifsregion *ifsp;
5308
5309 if (ifslastp == NULL) {
5310 ifsp = &ifsfirst;
5311 } else {
5312 INTOFF;
5313 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
5314 ifsp->next = NULL;
5315 ifslastp->next = ifsp;
5316 INTON;
5317 }
5318 ifslastp = ifsp;
5319 ifslastp->begoff = start;
5320 ifslastp->endoff = end;
5321 ifslastp->nulonly = nulonly;
5322}
5323
5324
5325
5326/*
5327 * Break the argument string into pieces based upon IFS and add the
5328 * strings to the argument list. The regions of the string to be
5329 * searched for IFS characters have been stored by recordregion.
5330 */
5331static void
5332ifsbreakup(string, arglist)
5333 char *string;
5334 struct arglist *arglist;
5335 {
5336 struct ifsregion *ifsp;
5337 struct strlist *sp;
5338 char *start;
5339 char *p;
5340 char *q;
5341 const char *ifs, *realifs;
5342 int ifsspc;
5343 int nulonly;
5344
5345
5346 start = string;
5347 ifsspc = 0;
5348 nulonly = 0;
5349 realifs = ifsset() ? ifsval() : defifs;
5350 if (ifslastp != NULL) {
5351 ifsp = &ifsfirst;
5352 do {
5353 p = string + ifsp->begoff;
5354 nulonly = ifsp->nulonly;
5355 ifs = nulonly ? nullstr : realifs;
5356 ifsspc = 0;
5357 while (p < string + ifsp->endoff) {
5358 q = p;
5359 if (*p == CTLESC)
5360 p++;
5361 if (strchr(ifs, *p)) {
5362 if (!nulonly)
5363 ifsspc = (strchr(defifs, *p) != NULL);
5364 /* Ignore IFS whitespace at start */
5365 if (q == start && ifsspc) {
5366 p++;
5367 start = p;
5368 continue;
5369 }
5370 *q = '\0';
5371 sp = (struct strlist *)stalloc(sizeof *sp);
5372 sp->text = start;
5373 *arglist->lastp = sp;
5374 arglist->lastp = &sp->next;
5375 p++;
5376 if (!nulonly) {
5377 for (;;) {
5378 if (p >= string + ifsp->endoff) {
5379 break;
5380 }
5381 q = p;
5382 if (*p == CTLESC)
5383 p++;
5384 if (strchr(ifs, *p) == NULL ) {
5385 p = q;
5386 break;
5387 } else if (strchr(defifs, *p) == NULL) {
5388 if (ifsspc) {
5389 p++;
5390 ifsspc = 0;
5391 } else {
5392 p = q;
5393 break;
5394 }
5395 } else
5396 p++;
5397 }
5398 }
5399 start = p;
5400 } else
5401 p++;
5402 }
5403 } while ((ifsp = ifsp->next) != NULL);
5404 if (!(*start || (!ifsspc && start > string && nulonly))) {
5405 return;
5406 }
5407 }
5408
5409 sp = (struct strlist *)stalloc(sizeof *sp);
5410 sp->text = start;
5411 *arglist->lastp = sp;
5412 arglist->lastp = &sp->next;
5413}
5414
5415static void
5416ifsfree()
5417{
5418 while (ifsfirst.next != NULL) {
5419 struct ifsregion *ifsp;
5420 INTOFF;
5421 ifsp = ifsfirst.next->next;
5422 ckfree(ifsfirst.next);
5423 ifsfirst.next = ifsp;
5424 INTON;
5425 }
5426 ifslastp = NULL;
5427 ifsfirst.next = NULL;
5428}
5429
Eric Andersen2870d962001-07-02 17:27:21 +00005430/*
5431 * Add a file name to the list.
5432 */
Eric Andersencb57d552001-06-28 07:25:16 +00005433
Eric Andersen2870d962001-07-02 17:27:21 +00005434static void
5435addfname(const char *name)
5436{
5437 char *p;
5438 struct strlist *sp;
5439
5440 p = sstrdup(name);
5441 sp = (struct strlist *)stalloc(sizeof *sp);
5442 sp->text = p;
5443 *exparg.lastp = sp;
5444 exparg.lastp = &sp->next;
5445}
Eric Andersencb57d552001-06-28 07:25:16 +00005446
5447/*
5448 * Expand shell metacharacters. At this point, the only control characters
5449 * should be escapes. The results are stored in the list exparg.
5450 */
5451
Eric Andersen62483552001-07-10 06:09:16 +00005452#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00005453static void
5454expandmeta(str, flag)
5455 struct strlist *str;
5456 int flag;
5457{
5458 const char *p;
5459 glob_t pglob;
5460 /* TODO - EXP_REDIR */
5461
5462 while (str) {
5463 if (fflag)
5464 goto nometa;
5465 p = preglob(str->text);
5466 INTOFF;
5467 switch (glob(p, GLOB_NOMAGIC, 0, &pglob)) {
5468 case 0:
5469 if (!(pglob.gl_flags & GLOB_MAGCHAR))
5470 goto nometa2;
5471 addglob(&pglob);
5472 globfree(&pglob);
5473 INTON;
5474 break;
5475 case GLOB_NOMATCH:
5476nometa2:
5477 globfree(&pglob);
5478 INTON;
5479nometa:
5480 *exparg.lastp = str;
5481 rmescapes(str->text);
5482 exparg.lastp = &str->next;
5483 break;
Eric Andersen2870d962001-07-02 17:27:21 +00005484 default: /* GLOB_NOSPACE */
Eric Andersencb57d552001-06-28 07:25:16 +00005485 error("Out of space");
5486 }
5487 str = str->next;
5488 }
5489}
5490
5491
5492/*
5493 * Add the result of glob(3) to the list.
5494 */
5495
5496static void
5497addglob(pglob)
5498 const glob_t *pglob;
5499{
5500 char **p = pglob->gl_pathv;
5501
5502 do {
5503 addfname(*p);
5504 } while (*++p);
5505}
5506
5507
Eric Andersen2870d962001-07-02 17:27:21 +00005508#else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005509static char *expdir;
5510
5511
5512static void
5513expandmeta(str, flag)
5514 struct strlist *str;
5515 int flag;
5516{
5517 char *p;
5518 struct strlist **savelastp;
5519 struct strlist *sp;
5520 char c;
5521 /* TODO - EXP_REDIR */
5522
5523 while (str) {
5524 if (fflag)
5525 goto nometa;
5526 p = str->text;
Eric Andersen2870d962001-07-02 17:27:21 +00005527 for (;;) { /* fast check for meta chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005528 if ((c = *p++) == '\0')
5529 goto nometa;
5530 if (c == '*' || c == '?' || c == '[' || c == '!')
5531 break;
5532 }
5533 savelastp = exparg.lastp;
5534 INTOFF;
5535 if (expdir == NULL) {
5536 int i = strlen(str->text);
5537 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5538 }
5539
5540 expmeta(expdir, str->text);
5541 ckfree(expdir);
5542 expdir = NULL;
5543 INTON;
5544 if (exparg.lastp == savelastp) {
5545 /*
5546 * no matches
5547 */
5548nometa:
5549 *exparg.lastp = str;
5550 rmescapes(str->text);
5551 exparg.lastp = &str->next;
5552 } else {
5553 *exparg.lastp = NULL;
5554 *savelastp = sp = expsort(*savelastp);
5555 while (sp->next != NULL)
5556 sp = sp->next;
5557 exparg.lastp = &sp->next;
5558 }
5559 str = str->next;
5560 }
5561}
5562
5563
5564/*
5565 * Do metacharacter (i.e. *, ?, [...]) expansion.
5566 */
5567
5568static void
5569expmeta(enddir, name)
5570 char *enddir;
5571 char *name;
5572 {
5573 char *p;
5574 const char *cp;
5575 char *q;
5576 char *start;
5577 char *endname;
5578 int metaflag;
5579 struct stat statb;
5580 DIR *dirp;
5581 struct dirent *dp;
5582 int atend;
5583 int matchdot;
5584
5585 metaflag = 0;
5586 start = name;
5587 for (p = name ; ; p++) {
5588 if (*p == '*' || *p == '?')
5589 metaflag = 1;
5590 else if (*p == '[') {
5591 q = p + 1;
5592 if (*q == '!')
5593 q++;
5594 for (;;) {
5595 while (*q == CTLQUOTEMARK)
5596 q++;
5597 if (*q == CTLESC)
5598 q++;
5599 if (*q == '/' || *q == '\0')
5600 break;
5601 if (*++q == ']') {
5602 metaflag = 1;
5603 break;
5604 }
5605 }
Eric Andersen2870d962001-07-02 17:27:21 +00005606 } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) {
Eric Andersencb57d552001-06-28 07:25:16 +00005607 metaflag = 1;
5608 } else if (*p == '\0')
5609 break;
5610 else if (*p == CTLQUOTEMARK)
5611 continue;
5612 else if (*p == CTLESC)
5613 p++;
5614 if (*p == '/') {
5615 if (metaflag)
5616 break;
5617 start = p + 1;
5618 }
5619 }
Eric Andersen2870d962001-07-02 17:27:21 +00005620 if (metaflag == 0) { /* we've reached the end of the file name */
Eric Andersencb57d552001-06-28 07:25:16 +00005621 if (enddir != expdir)
5622 metaflag++;
5623 for (p = name ; ; p++) {
5624 if (*p == CTLQUOTEMARK)
5625 continue;
5626 if (*p == CTLESC)
5627 p++;
5628 *enddir++ = *p;
5629 if (*p == '\0')
5630 break;
5631 }
5632 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5633 addfname(expdir);
5634 return;
5635 }
5636 endname = p;
5637 if (start != name) {
5638 p = name;
5639 while (p < start) {
5640 while (*p == CTLQUOTEMARK)
5641 p++;
5642 if (*p == CTLESC)
5643 p++;
5644 *enddir++ = *p++;
5645 }
5646 }
5647 if (enddir == expdir) {
5648 cp = ".";
5649 } else if (enddir == expdir + 1 && *expdir == '/') {
5650 cp = "/";
5651 } else {
5652 cp = expdir;
5653 enddir[-1] = '\0';
5654 }
5655 if ((dirp = opendir(cp)) == NULL)
5656 return;
5657 if (enddir != expdir)
5658 enddir[-1] = '/';
5659 if (*endname == 0) {
5660 atend = 1;
5661 } else {
5662 atend = 0;
5663 *endname++ = '\0';
5664 }
5665 matchdot = 0;
5666 p = start;
5667 while (*p == CTLQUOTEMARK)
5668 p++;
5669 if (*p == CTLESC)
5670 p++;
5671 if (*p == '.')
5672 matchdot++;
5673 while (! int_pending() && (dp = readdir(dirp)) != NULL) {
5674 if (dp->d_name[0] == '.' && ! matchdot)
5675 continue;
5676 if (patmatch(start, dp->d_name, 0)) {
5677 if (atend) {
Eric Andersen2870d962001-07-02 17:27:21 +00005678 strcpy(enddir, dp->d_name);
Eric Andersencb57d552001-06-28 07:25:16 +00005679 addfname(expdir);
5680 } else {
5681 for (p = enddir, cp = dp->d_name;
5682 (*p++ = *cp++) != '\0';)
5683 continue;
5684 p[-1] = '/';
5685 expmeta(p, endname);
5686 }
5687 }
5688 }
5689 closedir(dirp);
5690 if (! atend)
5691 endname[-1] = '/';
5692}
Eric Andersen2870d962001-07-02 17:27:21 +00005693#endif /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005694
5695
Eric Andersencb57d552001-06-28 07:25:16 +00005696
Eric Andersen62483552001-07-10 06:09:16 +00005697#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersencb57d552001-06-28 07:25:16 +00005698/*
5699 * Sort the results of file name expansion. It calculates the number of
5700 * strings to sort and then calls msort (short for merge sort) to do the
5701 * work.
5702 */
5703
5704static struct strlist *
5705expsort(str)
5706 struct strlist *str;
5707 {
5708 int len;
5709 struct strlist *sp;
5710
5711 len = 0;
5712 for (sp = str ; sp ; sp = sp->next)
5713 len++;
5714 return msort(str, len);
5715}
5716
5717
5718static struct strlist *
5719msort(list, len)
5720 struct strlist *list;
5721 int len;
5722{
5723 struct strlist *p, *q = NULL;
5724 struct strlist **lpp;
5725 int half;
5726 int n;
5727
5728 if (len <= 1)
5729 return list;
5730 half = len >> 1;
5731 p = list;
5732 for (n = half ; --n >= 0 ; ) {
5733 q = p;
5734 p = p->next;
5735 }
Eric Andersen2870d962001-07-02 17:27:21 +00005736 q->next = NULL; /* terminate first half of list */
5737 q = msort(list, half); /* sort first half of list */
5738 p = msort(p, len - half); /* sort second half */
Eric Andersencb57d552001-06-28 07:25:16 +00005739 lpp = &list;
5740 for (;;) {
5741 if (strcmp(p->text, q->text) < 0) {
5742 *lpp = p;
5743 lpp = &p->next;
5744 if ((p = *lpp) == NULL) {
5745 *lpp = q;
5746 break;
5747 }
5748 } else {
5749 *lpp = q;
5750 lpp = &q->next;
5751 if ((q = *lpp) == NULL) {
5752 *lpp = p;
5753 break;
5754 }
5755 }
5756 }
5757 return list;
5758}
5759#endif
5760
5761
5762
5763/*
5764 * Returns true if the pattern matches the string.
5765 */
5766
Eric Andersen62483552001-07-10 06:09:16 +00005767#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00005768/* squoted: string might have quote chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005769static int
Eric Andersen2870d962001-07-02 17:27:21 +00005770patmatch(char *pattern, char *string, int squoted)
5771{
Eric Andersencb57d552001-06-28 07:25:16 +00005772 const char *p;
5773 char *q;
5774
5775 p = preglob(pattern);
5776 q = squoted ? _rmescapes(string, RMESCAPE_ALLOC) : string;
5777
5778 return !fnmatch(p, q, 0);
5779}
5780
5781
5782static int
Eric Andersen2870d962001-07-02 17:27:21 +00005783patmatch2(char *pattern, char *string, int squoted)
5784{
Eric Andersencb57d552001-06-28 07:25:16 +00005785 char *p;
5786 int res;
5787
5788 sstrnleft--;
5789 p = grabstackstr(expdest);
5790 res = patmatch(pattern, string, squoted);
5791 ungrabstackstr(p, expdest);
5792 return res;
5793}
5794#else
5795static int
Eric Andersen2870d962001-07-02 17:27:21 +00005796patmatch(char *pattern, char *string, int squoted) {
5797 return pmatch(pattern, string, squoted);
Eric Andersencb57d552001-06-28 07:25:16 +00005798}
5799
5800
5801static int
Eric Andersen2870d962001-07-02 17:27:21 +00005802pmatch(char *pattern, char *string, int squoted)
5803{
Eric Andersencb57d552001-06-28 07:25:16 +00005804 char *p, *q;
5805 char c;
5806
5807 p = pattern;
5808 q = string;
5809 for (;;) {
5810 switch (c = *p++) {
5811 case '\0':
5812 goto breakloop;
5813 case CTLESC:
5814 if (squoted && *q == CTLESC)
5815 q++;
5816 if (*q++ != *p++)
5817 return 0;
5818 break;
5819 case CTLQUOTEMARK:
5820 continue;
5821 case '?':
5822 if (squoted && *q == CTLESC)
5823 q++;
5824 if (*q++ == '\0')
5825 return 0;
5826 break;
5827 case '*':
5828 c = *p;
5829 while (c == CTLQUOTEMARK || c == '*')
5830 c = *++p;
5831 if (c != CTLESC && c != CTLQUOTEMARK &&
5832 c != '?' && c != '*' && c != '[') {
5833 while (*q != c) {
5834 if (squoted && *q == CTLESC &&
5835 q[1] == c)
5836 break;
5837 if (*q == '\0')
5838 return 0;
5839 if (squoted && *q == CTLESC)
5840 q++;
5841 q++;
5842 }
5843 }
5844 do {
5845 if (pmatch(p, q, squoted))
5846 return 1;
5847 if (squoted && *q == CTLESC)
5848 q++;
5849 } while (*q++ != '\0');
5850 return 0;
5851 case '[': {
5852 char *endp;
5853 int invert, found;
5854 char chr;
5855
5856 endp = p;
5857 if (*endp == '!')
5858 endp++;
5859 for (;;) {
5860 while (*endp == CTLQUOTEMARK)
5861 endp++;
5862 if (*endp == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00005863 goto dft; /* no matching ] */
Eric Andersencb57d552001-06-28 07:25:16 +00005864 if (*endp == CTLESC)
5865 endp++;
5866 if (*++endp == ']')
5867 break;
5868 }
5869 invert = 0;
5870 if (*p == '!') {
5871 invert++;
5872 p++;
5873 }
5874 found = 0;
5875 chr = *q++;
5876 if (squoted && chr == CTLESC)
5877 chr = *q++;
5878 if (chr == '\0')
5879 return 0;
5880 c = *p++;
5881 do {
5882 if (c == CTLQUOTEMARK)
5883 continue;
5884 if (c == CTLESC)
5885 c = *p++;
5886 if (*p == '-' && p[1] != ']') {
5887 p++;
5888 while (*p == CTLQUOTEMARK)
5889 p++;
5890 if (*p == CTLESC)
5891 p++;
5892 if (chr >= c && chr <= *p)
5893 found = 1;
5894 p++;
5895 } else {
5896 if (chr == c)
5897 found = 1;
5898 }
5899 } while ((c = *p++) != ']');
5900 if (found == invert)
5901 return 0;
5902 break;
5903 }
Eric Andersen2870d962001-07-02 17:27:21 +00005904dft: default:
Eric Andersencb57d552001-06-28 07:25:16 +00005905 if (squoted && *q == CTLESC)
5906 q++;
5907 if (*q++ != c)
5908 return 0;
5909 break;
5910 }
5911 }
5912breakloop:
5913 if (*q != '\0')
5914 return 0;
5915 return 1;
5916}
5917#endif
5918
5919
5920
5921/*
5922 * Remove any CTLESC characters from a string.
5923 */
5924
Eric Andersen62483552001-07-10 06:09:16 +00005925#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00005926static char *
Eric Andersen2870d962001-07-02 17:27:21 +00005927_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005928{
5929 char *p, *q, *r;
5930 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5931
5932 p = strpbrk(str, qchars);
5933 if (!p) {
5934 return str;
5935 }
5936 q = p;
5937 r = str;
5938 if (flag & RMESCAPE_ALLOC) {
5939 size_t len = p - str;
5940 q = r = stalloc(strlen(p) + len + 1);
5941 if (len > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00005942 memcpy(q, str, len);
5943 q += len;
Eric Andersencb57d552001-06-28 07:25:16 +00005944 }
5945 }
5946 while (*p) {
5947 if (*p == CTLQUOTEMARK) {
5948 p++;
5949 continue;
5950 }
5951 if (*p == CTLESC) {
5952 p++;
5953 if (flag & RMESCAPE_GLOB && *p != '/') {
5954 *q++ = '\\';
5955 }
5956 }
5957 *q++ = *p++;
5958 }
5959 *q = '\0';
5960 return r;
5961}
5962#else
5963static void
5964rmescapes(str)
5965 char *str;
5966{
5967 char *p, *q;
5968
5969 p = str;
5970 while (*p != CTLESC && *p != CTLQUOTEMARK) {
5971 if (*p++ == '\0')
5972 return;
5973 }
5974 q = p;
5975 while (*p) {
5976 if (*p == CTLQUOTEMARK) {
5977 p++;
5978 continue;
5979 }
5980 if (*p == CTLESC)
5981 p++;
5982 *q++ = *p++;
5983 }
5984 *q = '\0';
5985}
5986#endif
5987
5988
5989
5990/*
5991 * See if a pattern matches in a case statement.
5992 */
5993
5994static int
Eric Andersen2870d962001-07-02 17:27:21 +00005995casematch(union node *pattern, const char *val)
5996{
Eric Andersencb57d552001-06-28 07:25:16 +00005997 struct stackmark smark;
5998 int result;
5999 char *p;
6000
6001 setstackmark(&smark);
6002 argbackq = pattern->narg.backquote;
6003 STARTSTACKSTR(expdest);
6004 ifslastp = NULL;
6005 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
6006 STPUTC('\0', expdest);
6007 p = grabstackstr(expdest);
Eric Andersen2870d962001-07-02 17:27:21 +00006008 result = patmatch(p, (char *)val, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006009 popstackmark(&smark);
6010 return result;
6011}
6012
6013/*
6014 * Our own itoa().
6015 */
6016
6017static char *
6018cvtnum(num, buf)
6019 int num;
6020 char *buf;
6021 {
6022 int len;
6023
6024 CHECKSTRSPACE(32, buf);
6025 len = sprintf(buf, "%d", num);
6026 STADJUST(len, buf);
6027 return buf;
6028}
Eric Andersencb57d552001-06-28 07:25:16 +00006029/*
6030 * Editline and history functions (and glue).
6031 */
6032static int histcmd(argc, argv)
6033 int argc;
6034 char **argv;
6035{
6036 error("not compiled with history support");
6037 /* NOTREACHED */
6038}
6039
6040
Eric Andersencb57d552001-06-28 07:25:16 +00006041struct redirtab {
6042 struct redirtab *next;
Eric Andersen62483552001-07-10 06:09:16 +00006043 /* short renamed[10]; *//* Current ash support only 0-9 descriptors */
6044 char renamed[10];
Eric Andersencb57d552001-06-28 07:25:16 +00006045};
6046
Eric Andersen2870d962001-07-02 17:27:21 +00006047static struct redirtab *redirlist;
Eric Andersencb57d552001-06-28 07:25:16 +00006048
6049extern char **environ;
6050
6051
6052
6053/*
6054 * Initialization code.
6055 */
6056
6057static void
Eric Andersen2870d962001-07-02 17:27:21 +00006058init(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00006059
6060 /* from cd.c: */
6061 {
6062 setpwd(0, 0);
6063 }
6064
6065 /* from input.c: */
6066 {
6067 basepf.nextc = basepf.buf = basebuf;
6068 }
6069
Eric Andersencb57d552001-06-28 07:25:16 +00006070 /* from var.c: */
6071 {
6072 char **envp;
6073 char ppid[32];
6074
6075 initvar();
6076 for (envp = environ ; *envp ; envp++) {
6077 if (strchr(*envp, '=')) {
6078 setvareq(*envp, VEXPORT|VTEXTFIXED);
6079 }
6080 }
6081
Eric Andersen3102ac42001-07-06 04:26:23 +00006082 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
Eric Andersencb57d552001-06-28 07:25:16 +00006083 setvar("PPID", ppid, 0);
6084 }
6085}
6086
6087
6088
6089/*
6090 * This routine is called when an error or an interrupt occurs in an
6091 * interactive shell and control is returned to the main command loop.
6092 */
6093
Eric Andersen2870d962001-07-02 17:27:21 +00006094#ifdef ASH_ALIAS
6095/* 1 == check for aliases, 2 == also check for assignments */
6096static int checkalias;
6097#endif
6098
Eric Andersencb57d552001-06-28 07:25:16 +00006099static void
Eric Andersen2870d962001-07-02 17:27:21 +00006100reset(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00006101
6102 /* from eval.c: */
6103 {
6104 evalskip = 0;
6105 loopnest = 0;
6106 funcnest = 0;
6107 }
6108
6109 /* from input.c: */
6110 {
6111 if (exception != EXSHELLPROC)
Eric Andersen2870d962001-07-02 17:27:21 +00006112 parselleft = parsenleft = 0; /* clear input buffer */
Eric Andersencb57d552001-06-28 07:25:16 +00006113 popallfiles();
6114 }
6115
6116 /* from parser.c: */
6117 {
6118 tokpushback = 0;
6119 checkkwd = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006120#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00006121 checkalias = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006122#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006123 }
6124
6125 /* from redir.c: */
6126 {
6127 while (redirlist)
6128 popredir();
6129 }
6130
Eric Andersencb57d552001-06-28 07:25:16 +00006131}
6132
6133
6134
6135/*
Eric Andersencb57d552001-06-28 07:25:16 +00006136 * This file implements the input routines used by the parser.
6137 */
6138
6139#ifdef BB_FEATURE_COMMAND_EDITING
6140unsigned int shell_context;
6141static const char * cmdedit_prompt;
6142static inline void putprompt(const char *s) {
6143 cmdedit_prompt = s;
6144}
6145#else
6146static inline void putprompt(const char *s) {
6147 out2str(s);
6148}
6149#endif
6150
Eric Andersen2870d962001-07-02 17:27:21 +00006151#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
Eric Andersencb57d552001-06-28 07:25:16 +00006152
Eric Andersencb57d552001-06-28 07:25:16 +00006153
Eric Andersencb57d552001-06-28 07:25:16 +00006154
Eric Andersen2870d962001-07-02 17:27:21 +00006155/*
6156 * Same as pgetc(), but ignores PEOA.
6157 */
Eric Andersencb57d552001-06-28 07:25:16 +00006158
Eric Andersen2870d962001-07-02 17:27:21 +00006159#ifdef ASH_ALIAS
6160static int
6161pgetc2()
6162{
6163 int c;
6164 do {
6165 c = pgetc_macro();
6166 } while (c == PEOA);
6167 return c;
Eric Andersencb57d552001-06-28 07:25:16 +00006168}
Eric Andersen2870d962001-07-02 17:27:21 +00006169#else
6170static inline int pgetc2() { return pgetc_macro(); }
Eric Andersencb57d552001-06-28 07:25:16 +00006171#endif
6172
Eric Andersencb57d552001-06-28 07:25:16 +00006173/*
6174 * Read a line from the script.
6175 */
6176
Eric Andersen62483552001-07-10 06:09:16 +00006177static inline char *
Eric Andersen2870d962001-07-02 17:27:21 +00006178pfgets(char *line, int len)
Eric Andersencb57d552001-06-28 07:25:16 +00006179{
6180 char *p = line;
6181 int nleft = len;
6182 int c;
6183
6184 while (--nleft > 0) {
6185 c = pgetc2();
6186 if (c == PEOF) {
6187 if (p == line)
6188 return NULL;
6189 break;
6190 }
6191 *p++ = c;
6192 if (c == '\n')
6193 break;
6194 }
6195 *p = '\0';
6196 return line;
6197}
6198
Eric Andersen62483552001-07-10 06:09:16 +00006199static inline int
Eric Andersen2870d962001-07-02 17:27:21 +00006200preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006201{
6202 int nr;
6203 char *buf = parsefile->buf;
6204 parsenextc = buf;
6205
6206retry:
6207#ifdef BB_FEATURE_COMMAND_EDITING
6208 {
6209 if (parsefile->fd)
6210 nr = read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersen2870d962001-07-02 17:27:21 +00006211 else {
Eric Andersencb57d552001-06-28 07:25:16 +00006212 do {
6213 cmdedit_read_input((char*)cmdedit_prompt, buf);
6214 nr = strlen(buf);
6215 } while (nr <=0 || shell_context);
6216 cmdedit_terminate();
6217 }
6218 }
6219#else
6220 nr = read(parsefile->fd, buf, BUFSIZ - 1);
6221#endif
6222
6223 if (nr < 0) {
6224 if (errno == EINTR)
6225 goto retry;
6226 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6227 int flags = fcntl(0, F_GETFL, 0);
6228 if (flags >= 0 && flags & O_NONBLOCK) {
6229 flags &=~ O_NONBLOCK;
6230 if (fcntl(0, F_SETFL, flags) >= 0) {
6231 out2str("sh: turning off NDELAY mode\n");
6232 goto retry;
6233 }
6234 }
6235 }
6236 }
6237 return nr;
6238}
6239
Eric Andersen2870d962001-07-02 17:27:21 +00006240static void
6241popstring(void)
6242{
6243 struct strpush *sp = parsefile->strpush;
6244
6245 INTOFF;
6246#ifdef ASH_ALIAS
6247 if (sp->ap) {
6248 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6249 if (!checkalias) {
6250 checkalias = 1;
6251 }
6252 }
6253 if (sp->string != sp->ap->val) {
6254 ckfree(sp->string);
6255 }
6256
6257 sp->ap->flag &= ~ALIASINUSE;
6258 if (sp->ap->flag & ALIASDEAD) {
6259 unalias(sp->ap->name);
6260 }
6261 }
6262#endif
6263 parsenextc = sp->prevstring;
6264 parsenleft = sp->prevnleft;
6265/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6266 parsefile->strpush = sp->prev;
6267 if (sp != &(parsefile->basestrpush))
6268 ckfree(sp);
6269 INTON;
6270}
6271
6272
Eric Andersencb57d552001-06-28 07:25:16 +00006273/*
6274 * Refill the input buffer and return the next input character:
6275 *
6276 * 1) If a string was pushed back on the input, pop it;
6277 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6278 * from a string so we can't refill the buffer, return EOF.
6279 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6280 * 4) Process input up to the next newline, deleting nul characters.
6281 */
6282
6283static int
Eric Andersen2870d962001-07-02 17:27:21 +00006284preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006285{
6286 char *p, *q;
6287 int more;
6288 char savec;
6289
6290 while (parsefile->strpush) {
Eric Andersen2870d962001-07-02 17:27:21 +00006291#ifdef ASH_ALIAS
6292 if (parsenleft == -1 && parsefile->strpush->ap &&
6293 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00006294 return PEOA;
6295 }
Eric Andersen2870d962001-07-02 17:27:21 +00006296#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006297 popstring();
6298 if (--parsenleft >= 0)
6299 return (*parsenextc++);
6300 }
6301 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6302 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00006303 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00006304
6305again:
6306 if (parselleft <= 0) {
6307 if ((parselleft = preadfd()) <= 0) {
6308 parselleft = parsenleft = EOF_NLEFT;
6309 return PEOF;
6310 }
6311 }
6312
6313 q = p = parsenextc;
6314
6315 /* delete nul characters */
6316 for (more = 1; more;) {
6317 switch (*p) {
6318 case '\0':
Eric Andersen2870d962001-07-02 17:27:21 +00006319 p++; /* Skip nul */
Eric Andersencb57d552001-06-28 07:25:16 +00006320 goto check;
6321
6322
6323 case '\n':
6324 parsenleft = q - parsenextc;
6325 more = 0; /* Stop processing here */
6326 break;
6327 }
6328
6329 *q++ = *p++;
6330check:
6331 if (--parselleft <= 0 && more) {
6332 parsenleft = q - parsenextc - 1;
6333 if (parsenleft < 0)
6334 goto again;
6335 more = 0;
6336 }
6337 }
6338
6339 savec = *q;
6340 *q = '\0';
6341
6342 if (vflag) {
6343 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00006344 }
6345
6346 *q = savec;
6347
6348 return *parsenextc++;
6349}
6350
Eric Andersencb57d552001-06-28 07:25:16 +00006351
6352/*
6353 * Push a string back onto the input at this current parsefile level.
6354 * We handle aliases this way.
6355 */
6356static void
Eric Andersen2870d962001-07-02 17:27:21 +00006357pushstring(char *s, int len, void *ap)
6358{
Eric Andersencb57d552001-06-28 07:25:16 +00006359 struct strpush *sp;
6360
6361 INTOFF;
6362/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6363 if (parsefile->strpush) {
6364 sp = ckmalloc(sizeof (struct strpush));
6365 sp->prev = parsefile->strpush;
6366 parsefile->strpush = sp;
6367 } else
6368 sp = parsefile->strpush = &(parsefile->basestrpush);
6369 sp->prevstring = parsenextc;
6370 sp->prevnleft = parsenleft;
Eric Andersen2870d962001-07-02 17:27:21 +00006371#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00006372 sp->ap = (struct alias *)ap;
6373 if (ap) {
6374 ((struct alias *)ap)->flag |= ALIASINUSE;
6375 sp->string = s;
6376 }
Eric Andersen2870d962001-07-02 17:27:21 +00006377#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006378 parsenextc = s;
6379 parsenleft = len;
6380 INTON;
6381}
6382
Eric Andersencb57d552001-06-28 07:25:16 +00006383
Eric Andersencb57d552001-06-28 07:25:16 +00006384/*
6385 * Like setinputfile, but takes input from a string.
6386 */
6387
6388static void
Eric Andersen62483552001-07-10 06:09:16 +00006389setinputstring(char *string)
6390{
Eric Andersencb57d552001-06-28 07:25:16 +00006391 INTOFF;
6392 pushfile();
6393 parsenextc = string;
6394 parsenleft = strlen(string);
6395 parsefile->buf = NULL;
6396 plinno = 1;
6397 INTON;
6398}
6399
6400
6401
6402/*
6403 * To handle the "." command, a stack of input files is used. Pushfile
6404 * adds a new entry to the stack and popfile restores the previous level.
6405 */
6406
6407static void
Eric Andersen2870d962001-07-02 17:27:21 +00006408pushfile(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00006409 struct parsefile *pf;
6410
6411 parsefile->nleft = parsenleft;
6412 parsefile->lleft = parselleft;
6413 parsefile->nextc = parsenextc;
6414 parsefile->linno = plinno;
6415 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6416 pf->prev = parsefile;
6417 pf->fd = -1;
6418 pf->strpush = NULL;
6419 pf->basestrpush.prev = NULL;
6420 parsefile = pf;
6421}
6422
Eric Andersen2870d962001-07-02 17:27:21 +00006423#ifdef JOBS
6424static void restartjob (struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00006425#endif
Eric Andersen2870d962001-07-02 17:27:21 +00006426static void freejob (struct job *);
6427static struct job *getjob (const char *);
6428static int dowait (int, struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00006429static void waitonint(int);
6430
6431
Eric Andersen2870d962001-07-02 17:27:21 +00006432/*
6433 * We keep track of whether or not fd0 has been redirected. This is for
6434 * background commands, where we want to redirect fd0 to /dev/null only
6435 * if it hasn't already been redirected.
6436*/
6437static int fd0_redirected = 0;
6438
6439/* Return true if fd 0 has already been redirected at least once. */
6440static inline int
6441fd0_redirected_p () {
6442 return fd0_redirected != 0;
6443}
6444
Eric Andersen62483552001-07-10 06:09:16 +00006445static void dupredirect (const union node *, int, int fd1dup);
Eric Andersen2870d962001-07-02 17:27:21 +00006446
6447#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006448/*
6449 * Turn job control on and off.
6450 *
6451 * Note: This code assumes that the third arg to ioctl is a character
6452 * pointer, which is true on Berkeley systems but not System V. Since
6453 * System V doesn't have job control yet, this isn't a problem now.
6454 */
6455
Eric Andersen2870d962001-07-02 17:27:21 +00006456
Eric Andersencb57d552001-06-28 07:25:16 +00006457
6458static void setjobctl(int enable)
6459{
6460#ifdef OLD_TTY_DRIVER
6461 int ldisc;
6462#endif
6463
6464 if (enable == jobctl || rootshell == 0)
6465 return;
6466 if (enable) {
6467 do { /* while we are in the background */
6468#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006469 if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006470#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006471 initialpgrp = tcgetpgrp(2);
Eric Andersencb57d552001-06-28 07:25:16 +00006472 if (initialpgrp < 0) {
6473#endif
6474 out2str("sh: can't access tty; job cenabletrol turned off\n");
6475 mflag = 0;
6476 return;
6477 }
6478 if (initialpgrp == -1)
6479 initialpgrp = getpgrp();
6480 else if (initialpgrp != getpgrp()) {
6481 killpg(initialpgrp, SIGTTIN);
6482 continue;
6483 }
6484 } while (0);
6485#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006486 if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
Eric Andersencb57d552001-06-28 07:25:16 +00006487 out2str("sh: need new tty driver to run job cenabletrol; job cenabletrol turned off\n");
6488 mflag = 0;
6489 return;
6490 }
6491#endif
6492 setsignal(SIGTSTP);
6493 setsignal(SIGTTOU);
6494 setsignal(SIGTTIN);
6495 setpgid(0, rootpid);
6496#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006497 ioctl(2, TIOCSPGRP, (char *)&rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00006498#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006499 tcsetpgrp(2, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00006500#endif
6501 } else { /* turning job cenabletrol off */
6502 setpgid(0, initialpgrp);
6503#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006504 ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006505#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006506 tcsetpgrp(2, initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006507#endif
6508 setsignal(SIGTSTP);
6509 setsignal(SIGTTOU);
6510 setsignal(SIGTTIN);
6511 }
6512 jobctl = enable;
6513}
6514#endif
6515
6516
Eric Andersencb57d552001-06-28 07:25:16 +00006517/* A translation list so we can be polite to our users. */
6518static char *signal_names[NSIG + 2] = {
6519 "EXIT",
6520 "SIGHUP",
6521 "SIGINT",
6522 "SIGQUIT",
6523 "SIGILL",
6524 "SIGTRAP",
6525 "SIGABRT",
6526 "SIGBUS",
6527 "SIGFPE",
6528 "SIGKILL",
6529 "SIGUSR1",
6530 "SIGSEGV",
6531 "SIGUSR2",
6532 "SIGPIPE",
6533 "SIGALRM",
6534 "SIGTERM",
6535 "SIGJUNK(16)",
6536 "SIGCHLD",
6537 "SIGCONT",
6538 "SIGSTOP",
6539 "SIGTSTP",
6540 "SIGTTIN",
6541 "SIGTTOU",
6542 "SIGURG",
6543 "SIGXCPU",
6544 "SIGXFSZ",
6545 "SIGVTALRM",
6546 "SIGPROF",
6547 "SIGWINCH",
6548 "SIGIO",
6549 "SIGPWR",
6550 "SIGSYS",
Eric Andersen62483552001-07-10 06:09:16 +00006551#ifdef SIGRTMIN
Eric Andersencb57d552001-06-28 07:25:16 +00006552 "SIGRTMIN",
6553 "SIGRTMIN+1",
6554 "SIGRTMIN+2",
6555 "SIGRTMIN+3",
6556 "SIGRTMIN+4",
6557 "SIGRTMIN+5",
6558 "SIGRTMIN+6",
6559 "SIGRTMIN+7",
6560 "SIGRTMIN+8",
6561 "SIGRTMIN+9",
6562 "SIGRTMIN+10",
6563 "SIGRTMIN+11",
6564 "SIGRTMIN+12",
6565 "SIGRTMIN+13",
6566 "SIGRTMIN+14",
6567 "SIGRTMIN+15",
6568 "SIGRTMAX-15",
6569 "SIGRTMAX-14",
6570 "SIGRTMAX-13",
6571 "SIGRTMAX-12",
6572 "SIGRTMAX-11",
6573 "SIGRTMAX-10",
6574 "SIGRTMAX-9",
6575 "SIGRTMAX-8",
6576 "SIGRTMAX-7",
6577 "SIGRTMAX-6",
6578 "SIGRTMAX-5",
6579 "SIGRTMAX-4",
6580 "SIGRTMAX-3",
6581 "SIGRTMAX-2",
6582 "SIGRTMAX-1",
6583 "SIGRTMAX",
Eric Andersen62483552001-07-10 06:09:16 +00006584#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006585 "DEBUG",
6586 (char *)0x0,
6587};
6588
6589
6590
Eric Andersen2870d962001-07-02 17:27:21 +00006591#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006592static int
6593killcmd(argc, argv)
6594 int argc;
6595 char **argv;
6596{
6597 int signo = -1;
6598 int list = 0;
6599 int i;
6600 pid_t pid;
6601 struct job *jp;
6602
6603 if (argc <= 1) {
6604usage:
6605 error(
6606"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6607"kill -l [exitstatus]"
6608 );
6609 }
6610
6611 if (*argv[1] == '-') {
6612 signo = decode_signal(argv[1] + 1, 1);
6613 if (signo < 0) {
6614 int c;
6615
6616 while ((c = nextopt("ls:")) != '\0')
6617 switch (c) {
6618 case 'l':
6619 list = 1;
6620 break;
6621 case 's':
6622 signo = decode_signal(optionarg, 1);
6623 if (signo < 0) {
6624 error(
6625 "invalid signal number or name: %s",
6626 optionarg
6627 );
6628 }
Eric Andersen2870d962001-07-02 17:27:21 +00006629 break;
Eric Andersencb57d552001-06-28 07:25:16 +00006630#ifdef DEBUG
6631 default:
6632 error(
6633 "nextopt returned character code 0%o", c);
6634#endif
6635 }
6636 } else
6637 argptr++;
6638 }
6639
6640 if (!list && signo < 0)
6641 signo = SIGTERM;
6642
6643 if ((signo < 0 || !*argptr) ^ list) {
6644 goto usage;
6645 }
6646
6647 if (list) {
6648 if (!*argptr) {
6649 out1str("0\n");
6650 for (i = 1; i < NSIG; i++) {
Eric Andersen62483552001-07-10 06:09:16 +00006651 printf(snlfmt, signal_names[i] + 3);
Eric Andersencb57d552001-06-28 07:25:16 +00006652 }
6653 return 0;
6654 }
6655 signo = atoi(*argptr);
6656 if (signo > 128)
6657 signo -= 128;
6658 if (0 < signo && signo < NSIG)
Eric Andersen62483552001-07-10 06:09:16 +00006659 printf(snlfmt, signal_names[signo] + 3);
Eric Andersencb57d552001-06-28 07:25:16 +00006660 else
6661 error("invalid signal number or exit status: %s",
6662 *argptr);
6663 return 0;
6664 }
6665
6666 do {
6667 if (**argptr == '%') {
6668 jp = getjob(*argptr);
6669 if (jp->jobctl == 0)
6670 error("job %s not created under job control",
6671 *argptr);
6672 pid = -jp->ps[0].pid;
6673 } else
6674 pid = atoi(*argptr);
6675 if (kill(pid, signo) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00006676 error("%s: %m", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006677 } while (*++argptr);
6678
6679 return 0;
6680}
6681
6682static int
6683fgcmd(argc, argv)
6684 int argc;
6685 char **argv;
6686{
6687 struct job *jp;
6688 int pgrp;
6689 int status;
6690
6691 jp = getjob(argv[1]);
6692 if (jp->jobctl == 0)
6693 error("job not created under job control");
6694 pgrp = jp->ps[0].pid;
6695#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006696 ioctl(2, TIOCSPGRP, (char *)&pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006697#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006698 tcsetpgrp(2, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006699#endif
6700 restartjob(jp);
6701 INTOFF;
6702 status = waitforjob(jp);
6703 INTON;
6704 return status;
6705}
6706
6707
6708static int
6709bgcmd(argc, argv)
6710 int argc;
6711 char **argv;
6712{
6713 struct job *jp;
6714
6715 do {
6716 jp = getjob(*++argv);
6717 if (jp->jobctl == 0)
6718 error("job not created under job control");
6719 restartjob(jp);
6720 } while (--argc > 1);
6721 return 0;
6722}
6723
6724
6725static void
6726restartjob(jp)
6727 struct job *jp;
6728{
6729 struct procstat *ps;
6730 int i;
6731
6732 if (jp->state == JOBDONE)
6733 return;
6734 INTOFF;
6735 killpg(jp->ps[0].pid, SIGCONT);
6736 for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
6737 if (WIFSTOPPED(ps->status)) {
6738 ps->status = -1;
6739 jp->state = 0;
6740 }
6741 }
6742 INTON;
6743}
6744#endif
6745
Eric Andersen2870d962001-07-02 17:27:21 +00006746static void showjobs(int change);
6747
Eric Andersencb57d552001-06-28 07:25:16 +00006748
6749static int
6750jobscmd(argc, argv)
6751 int argc;
6752 char **argv;
6753{
6754 showjobs(0);
6755 return 0;
6756}
6757
6758
6759/*
6760 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6761 * statuses have changed since the last call to showjobs.
6762 *
6763 * If the shell is interrupted in the process of creating a job, the
6764 * result may be a job structure containing zero processes. Such structures
6765 * will be freed here.
6766 */
6767
6768static void
6769showjobs(change)
6770 int change;
6771{
6772 int jobno;
6773 int procno;
6774 int i;
6775 struct job *jp;
6776 struct procstat *ps;
6777 int col;
6778 char s[64];
6779
6780 TRACE(("showjobs(%d) called\n", change));
6781 while (dowait(0, (struct job *)NULL) > 0);
6782 for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
6783 if (! jp->used)
6784 continue;
6785 if (jp->nprocs == 0) {
6786 freejob(jp);
6787 continue;
6788 }
6789 if (change && ! jp->changed)
6790 continue;
6791 procno = jp->nprocs;
Eric Andersen2870d962001-07-02 17:27:21 +00006792 for (ps = jp->ps ; ; ps++) { /* for each process */
Eric Andersencb57d552001-06-28 07:25:16 +00006793 if (ps == jp->ps)
Eric Andersen3102ac42001-07-06 04:26:23 +00006794 snprintf(s, 64, "[%d] %ld ", jobno,
Eric Andersencb57d552001-06-28 07:25:16 +00006795 (long)ps->pid);
6796 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006797 snprintf(s, 64, " %ld ",
Eric Andersencb57d552001-06-28 07:25:16 +00006798 (long)ps->pid);
6799 out1str(s);
6800 col = strlen(s);
6801 s[0] = '\0';
6802 if (ps->status == -1) {
6803 /* don't print anything */
6804 } else if (WIFEXITED(ps->status)) {
Eric Andersen3102ac42001-07-06 04:26:23 +00006805 snprintf(s, 64, "Exit %d",
Eric Andersencb57d552001-06-28 07:25:16 +00006806 WEXITSTATUS(ps->status));
6807 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00006808#ifdef JOBS
6809 if (WIFSTOPPED(ps->status))
Eric Andersencb57d552001-06-28 07:25:16 +00006810 i = WSTOPSIG(ps->status);
6811 else /* WIFSIGNALED(ps->status) */
6812#endif
6813 i = WTERMSIG(ps->status);
6814 if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
Eric Andersen2870d962001-07-02 17:27:21 +00006815 strcpy(s, sys_siglist[i & 0x7F]);
Eric Andersencb57d552001-06-28 07:25:16 +00006816 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006817 snprintf(s, 64, "Signal %d", i & 0x7F);
Eric Andersencb57d552001-06-28 07:25:16 +00006818 if (WCOREDUMP(ps->status))
6819 strcat(s, " (core dumped)");
6820 }
6821 out1str(s);
6822 col += strlen(s);
Eric Andersen62483552001-07-10 06:09:16 +00006823 printf(
Eric Andersencb57d552001-06-28 07:25:16 +00006824 "%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ',
6825 ps->cmd
6826 );
6827 if (--procno <= 0)
6828 break;
6829 }
6830 jp->changed = 0;
6831 if (jp->state == JOBDONE) {
6832 freejob(jp);
6833 }
6834 }
6835}
6836
6837
6838/*
6839 * Mark a job structure as unused.
6840 */
6841
6842static void
Eric Andersen62483552001-07-10 06:09:16 +00006843freejob(struct job *jp)
6844{
6845 const struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006846 int i;
6847
6848 INTOFF;
6849 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6850 if (ps->cmd != nullstr)
6851 ckfree(ps->cmd);
6852 }
6853 if (jp->ps != &jp->ps0)
6854 ckfree(jp->ps);
6855 jp->used = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006856#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006857 if (curjob == jp - jobtab + 1)
6858 curjob = 0;
6859#endif
6860 INTON;
6861}
6862
6863
6864
6865static int
6866waitcmd(argc, argv)
6867 int argc;
6868 char **argv;
6869{
6870 struct job *job;
6871 int status, retval;
6872 struct job *jp;
6873
6874 if (--argc > 0) {
6875start:
6876 job = getjob(*++argv);
6877 } else {
6878 job = NULL;
6879 }
Eric Andersen2870d962001-07-02 17:27:21 +00006880 for (;;) { /* loop until process terminated or stopped */
Eric Andersencb57d552001-06-28 07:25:16 +00006881 if (job != NULL) {
6882 if (job->state) {
6883 status = job->ps[job->nprocs - 1].status;
6884 if (! iflag)
6885 freejob(job);
6886 if (--argc) {
6887 goto start;
6888 }
6889 if (WIFEXITED(status))
6890 retval = WEXITSTATUS(status);
Eric Andersen2870d962001-07-02 17:27:21 +00006891#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006892 else if (WIFSTOPPED(status))
6893 retval = WSTOPSIG(status) + 128;
6894#endif
6895 else {
6896 /* XXX: limits number of signals */
6897 retval = WTERMSIG(status) + 128;
6898 }
6899 return retval;
6900 }
6901 } else {
6902 for (jp = jobtab ; ; jp++) {
Eric Andersen2870d962001-07-02 17:27:21 +00006903 if (jp >= jobtab + njobs) { /* no running procs */
Eric Andersencb57d552001-06-28 07:25:16 +00006904 return 0;
6905 }
6906 if (jp->used && jp->state == 0)
6907 break;
6908 }
6909 }
6910 if (dowait(2, 0) < 0 && errno == EINTR) {
6911 return 129;
6912 }
6913 }
6914}
6915
6916
6917
6918/*
6919 * Convert a job name to a job structure.
6920 */
6921
6922static struct job *
Eric Andersen2870d962001-07-02 17:27:21 +00006923getjob(const char *name)
6924{
Eric Andersencb57d552001-06-28 07:25:16 +00006925 int jobno;
6926 struct job *jp;
6927 int pid;
6928 int i;
6929
6930 if (name == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00006931#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006932currentjob:
6933 if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
6934 error("No current job");
6935 return &jobtab[jobno - 1];
6936#else
6937 error("No current job");
6938#endif
6939 } else if (name[0] == '%') {
6940 if (is_digit(name[1])) {
6941 jobno = number(name + 1);
6942 if (jobno > 0 && jobno <= njobs
6943 && jobtab[jobno - 1].used != 0)
6944 return &jobtab[jobno - 1];
Eric Andersen2870d962001-07-02 17:27:21 +00006945#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006946 } else if (name[1] == '%' && name[2] == '\0') {
6947 goto currentjob;
6948#endif
6949 } else {
6950 struct job *found = NULL;
6951 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
6952 if (jp->used && jp->nprocs > 0
6953 && prefix(name + 1, jp->ps[0].cmd)) {
6954 if (found)
6955 error("%s: ambiguous", name);
6956 found = jp;
6957 }
6958 }
6959 if (found)
6960 return found;
6961 }
Eric Andersen2870d962001-07-02 17:27:21 +00006962 } else if (is_number(name, &pid)) {
Eric Andersencb57d552001-06-28 07:25:16 +00006963 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
6964 if (jp->used && jp->nprocs > 0
6965 && jp->ps[jp->nprocs - 1].pid == pid)
6966 return jp;
6967 }
6968 }
6969 error("No such job: %s", name);
6970 /* NOTREACHED */
6971}
6972
6973
6974
6975/*
6976 * Return a new job structure,
6977 */
6978
Eric Andersen2870d962001-07-02 17:27:21 +00006979static struct job *
Eric Andersen62483552001-07-10 06:09:16 +00006980makejob(const union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00006981{
6982 int i;
6983 struct job *jp;
6984
6985 for (i = njobs, jp = jobtab ; ; jp++) {
6986 if (--i < 0) {
6987 INTOFF;
6988 if (njobs == 0) {
6989 jobtab = ckmalloc(4 * sizeof jobtab[0]);
6990 } else {
6991 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
6992 memcpy(jp, jobtab, njobs * sizeof jp[0]);
6993 /* Relocate `ps' pointers */
6994 for (i = 0; i < njobs; i++)
6995 if (jp[i].ps == &jobtab[i].ps0)
6996 jp[i].ps = &jp[i].ps0;
6997 ckfree(jobtab);
6998 jobtab = jp;
6999 }
7000 jp = jobtab + njobs;
7001 for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
7002 INTON;
7003 break;
7004 }
7005 if (jp->used == 0)
7006 break;
7007 }
7008 INTOFF;
7009 jp->state = 0;
7010 jp->used = 1;
7011 jp->changed = 0;
7012 jp->nprocs = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00007013#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007014 jp->jobctl = jobctl;
7015#endif
7016 if (nprocs > 1) {
7017 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7018 } else {
7019 jp->ps = &jp->ps0;
7020 }
7021 INTON;
7022 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7023 jp - jobtab + 1));
7024 return jp;
7025}
7026
7027
7028/*
7029 * Fork of a subshell. If we are doing job control, give the subshell its
7030 * own process group. Jp is a job structure that the job is to be added to.
7031 * N is the command that will be evaluated by the child. Both jp and n may
7032 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00007033 * FORK_FG - Fork off a foreground process.
7034 * FORK_BG - Fork off a background process.
7035 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7036 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00007037 *
7038 * When job control is turned off, background processes have their standard
7039 * input redirected to /dev/null (except for the second and later processes
7040 * in a pipeline).
7041 */
7042
Eric Andersen2870d962001-07-02 17:27:21 +00007043
7044
Eric Andersencb57d552001-06-28 07:25:16 +00007045static int
Eric Andersen62483552001-07-10 06:09:16 +00007046forkshell(struct job *jp, const union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00007047{
7048 int pid;
Eric Andersen62483552001-07-10 06:09:16 +00007049#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007050 int pgrp;
Eric Andersen62483552001-07-10 06:09:16 +00007051#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007052 const char *devnull = _PATH_DEVNULL;
7053 const char *nullerr = "Can't open %s";
7054
7055 TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
7056 mode));
7057 INTOFF;
7058 pid = fork();
7059 if (pid == -1) {
7060 TRACE(("Fork failed, errno=%d\n", errno));
7061 INTON;
7062 error("Cannot fork");
7063 }
7064 if (pid == 0) {
7065 struct job *p;
7066 int wasroot;
7067 int i;
7068
7069 TRACE(("Child shell %d\n", getpid()));
7070 wasroot = rootshell;
7071 rootshell = 0;
7072 closescript();
7073 INTON;
7074 clear_traps();
Eric Andersen2870d962001-07-02 17:27:21 +00007075#ifdef JOBS
7076 jobctl = 0; /* do job control only in root shell */
Eric Andersencb57d552001-06-28 07:25:16 +00007077 if (wasroot && mode != FORK_NOJOB && mflag) {
7078 if (jp == NULL || jp->nprocs == 0)
7079 pgrp = getpid();
7080 else
7081 pgrp = jp->ps[0].pid;
7082 setpgid(0, pgrp);
7083 if (mode == FORK_FG) {
7084 /*** this causes superfluous TIOCSPGRPS ***/
7085#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00007086 if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007087 error("TIOCSPGRP failed, errno=%d", errno);
7088#else
Eric Andersen3102ac42001-07-06 04:26:23 +00007089 if (tcsetpgrp(2, pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007090 error("tcsetpgrp failed, errno=%d", errno);
7091#endif
7092 }
7093 setsignal(SIGTSTP);
7094 setsignal(SIGTTOU);
7095 } else if (mode == FORK_BG) {
7096 ignoresig(SIGINT);
7097 ignoresig(SIGQUIT);
7098 if ((jp == NULL || jp->nprocs == 0) &&
7099 ! fd0_redirected_p ()) {
7100 close(0);
7101 if (open(devnull, O_RDONLY) != 0)
7102 error(nullerr, devnull);
7103 }
7104 }
7105#else
7106 if (mode == FORK_BG) {
7107 ignoresig(SIGINT);
7108 ignoresig(SIGQUIT);
7109 if ((jp == NULL || jp->nprocs == 0) &&
7110 ! fd0_redirected_p ()) {
7111 close(0);
7112 if (open(devnull, O_RDONLY) != 0)
7113 error(nullerr, devnull);
7114 }
7115 }
7116#endif
7117 for (i = njobs, p = jobtab ; --i >= 0 ; p++)
7118 if (p->used)
7119 freejob(p);
7120 if (wasroot && iflag) {
7121 setsignal(SIGINT);
7122 setsignal(SIGQUIT);
7123 setsignal(SIGTERM);
7124 }
7125 return pid;
7126 }
Eric Andersen62483552001-07-10 06:09:16 +00007127#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007128 if (rootshell && mode != FORK_NOJOB && mflag) {
7129 if (jp == NULL || jp->nprocs == 0)
7130 pgrp = pid;
7131 else
7132 pgrp = jp->ps[0].pid;
7133 setpgid(pid, pgrp);
7134 }
Eric Andersen62483552001-07-10 06:09:16 +00007135#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007136 if (mode == FORK_BG)
Eric Andersen2870d962001-07-02 17:27:21 +00007137 backgndpid = pid; /* set $! */
Eric Andersencb57d552001-06-28 07:25:16 +00007138 if (jp) {
7139 struct procstat *ps = &jp->ps[jp->nprocs++];
7140 ps->pid = pid;
7141 ps->status = -1;
7142 ps->cmd = nullstr;
7143 if (iflag && rootshell && n)
7144 ps->cmd = commandtext(n);
7145 }
7146 INTON;
7147 TRACE(("In parent shell: child = %d\n", pid));
7148 return pid;
7149}
7150
7151
7152
7153/*
7154 * Wait for job to finish.
7155 *
7156 * Under job control we have the problem that while a child process is
7157 * running interrupts generated by the user are sent to the child but not
7158 * to the shell. This means that an infinite loop started by an inter-
7159 * active user may be hard to kill. With job control turned off, an
7160 * interactive user may place an interactive program inside a loop. If
7161 * the interactive program catches interrupts, the user doesn't want
7162 * these interrupts to also abort the loop. The approach we take here
7163 * is to have the shell ignore interrupt signals while waiting for a
7164 * forground process to terminate, and then send itself an interrupt
7165 * signal if the child process was terminated by an interrupt signal.
7166 * Unfortunately, some programs want to do a bit of cleanup and then
7167 * exit on interrupt; unless these processes terminate themselves by
7168 * sending a signal to themselves (instead of calling exit) they will
7169 * confuse this approach.
7170 */
7171
7172static int
Eric Andersen62483552001-07-10 06:09:16 +00007173waitforjob(struct job *jp)
7174{
Eric Andersen2870d962001-07-02 17:27:21 +00007175#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007176 int mypgrp = getpgrp();
7177#endif
7178 int status;
7179 int st;
7180 struct sigaction act, oact;
7181
7182 INTOFF;
7183 intreceived = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00007184#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007185 if (!jobctl) {
7186#else
7187 if (!iflag) {
7188#endif
7189 sigaction(SIGINT, 0, &act);
7190 act.sa_handler = waitonint;
7191 sigaction(SIGINT, &act, &oact);
7192 }
7193 TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
7194 while (jp->state == 0) {
7195 dowait(1, jp);
7196 }
Eric Andersen2870d962001-07-02 17:27:21 +00007197#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007198 if (!jobctl) {
7199#else
7200 if (!iflag) {
7201#endif
7202 sigaction(SIGINT, &oact, 0);
7203 if (intreceived && trap[SIGINT]) kill(getpid(), SIGINT);
7204 }
Eric Andersen2870d962001-07-02 17:27:21 +00007205#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007206 if (jp->jobctl) {
7207#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00007208 if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007209 error("TIOCSPGRP failed, errno=%d\n", errno);
7210#else
Eric Andersen3102ac42001-07-06 04:26:23 +00007211 if (tcsetpgrp(2, mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007212 error("tcsetpgrp failed, errno=%d\n", errno);
7213#endif
7214 }
7215 if (jp->state == JOBSTOPPED)
7216 curjob = jp - jobtab + 1;
7217#endif
7218 status = jp->ps[jp->nprocs - 1].status;
7219 /* convert to 8 bits */
7220 if (WIFEXITED(status))
7221 st = WEXITSTATUS(status);
Eric Andersen2870d962001-07-02 17:27:21 +00007222#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007223 else if (WIFSTOPPED(status))
7224 st = WSTOPSIG(status) + 128;
7225#endif
7226 else
7227 st = WTERMSIG(status) + 128;
Eric Andersen2870d962001-07-02 17:27:21 +00007228#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007229 if (jp->jobctl) {
7230 /*
7231 * This is truly gross.
7232 * If we're doing job control, then we did a TIOCSPGRP which
7233 * caused us (the shell) to no longer be in the controlling
7234 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7235 * intuit from the subprocess exit status whether a SIGINT
7236 * occured, and if so interrupt ourselves. Yuck. - mycroft
7237 */
7238 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
7239 raise(SIGINT);
7240 }
Eric Andersen2870d962001-07-02 17:27:21 +00007241 if (jp->state == JOBDONE)
7242
Eric Andersencb57d552001-06-28 07:25:16 +00007243#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007244 freejob(jp);
7245 INTON;
7246 return st;
7247}
7248
7249
7250
7251/*
7252 * Wait for a process to terminate.
7253 */
7254
Eric Andersen62483552001-07-10 06:09:16 +00007255/*
7256 * Do a wait system call. If job control is compiled in, we accept
7257 * stopped processes. If block is zero, we return a value of zero
7258 * rather than blocking.
7259 *
7260 * System V doesn't have a non-blocking wait system call. It does
7261 * have a SIGCLD signal that is sent to a process when one of it's
7262 * children dies. The obvious way to use SIGCLD would be to install
7263 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7264 * was received, and have waitproc bump another counter when it got
7265 * the status of a process. Waitproc would then know that a wait
7266 * system call would not block if the two counters were different.
7267 * This approach doesn't work because if a process has children that
7268 * have not been waited for, System V will send it a SIGCLD when it
7269 * installs a signal handler for SIGCLD. What this means is that when
7270 * a child exits, the shell will be sent SIGCLD signals continuously
7271 * until is runs out of stack space, unless it does a wait call before
7272 * restoring the signal handler. The code below takes advantage of
7273 * this (mis)feature by installing a signal handler for SIGCLD and
7274 * then checking to see whether it was called. If there are any
7275 * children to be waited for, it will be.
7276 *
7277 */
7278
7279static inline int
7280waitproc(int block, int *status)
7281{
7282 int flags;
7283
7284 flags = 0;
7285#ifdef JOBS
7286 if (jobctl)
7287 flags |= WUNTRACED;
7288#endif
7289 if (block == 0)
7290 flags |= WNOHANG;
7291 return wait3(status, flags, (struct rusage *)NULL);
7292}
7293
Eric Andersencb57d552001-06-28 07:25:16 +00007294static int
Eric Andersen62483552001-07-10 06:09:16 +00007295dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00007296{
7297 int pid;
7298 int status;
7299 struct procstat *sp;
7300 struct job *jp;
7301 struct job *thisjob;
7302 int done;
7303 int stopped;
7304 int core;
7305 int sig;
7306
7307 TRACE(("dowait(%d) called\n", block));
7308 do {
7309 pid = waitproc(block, &status);
7310 TRACE(("wait returns %d, status=%d\n", pid, status));
7311 } while (!(block & 2) && pid == -1 && errno == EINTR);
7312 if (pid <= 0)
7313 return pid;
7314 INTOFF;
7315 thisjob = NULL;
7316 for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
7317 if (jp->used) {
7318 done = 1;
7319 stopped = 1;
7320 for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
7321 if (sp->pid == -1)
7322 continue;
7323 if (sp->pid == pid) {
7324 TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
7325 sp->status = status;
7326 thisjob = jp;
7327 }
7328 if (sp->status == -1)
7329 stopped = 0;
7330 else if (WIFSTOPPED(sp->status))
7331 done = 0;
7332 }
Eric Andersen2870d962001-07-02 17:27:21 +00007333 if (stopped) { /* stopped or done */
Eric Andersencb57d552001-06-28 07:25:16 +00007334 int state = done? JOBDONE : JOBSTOPPED;
7335 if (jp->state != state) {
7336 TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
7337 jp->state = state;
Eric Andersen2870d962001-07-02 17:27:21 +00007338#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007339 if (done && curjob == jp - jobtab + 1)
Eric Andersen2870d962001-07-02 17:27:21 +00007340 curjob = 0; /* no current job */
Eric Andersencb57d552001-06-28 07:25:16 +00007341#endif
7342 }
7343 }
7344 }
7345 }
7346 INTON;
7347 if (! rootshell || ! iflag || (job && thisjob == job)) {
7348 core = WCOREDUMP(status);
Eric Andersen2870d962001-07-02 17:27:21 +00007349#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007350 if (WIFSTOPPED(status)) sig = WSTOPSIG(status);
7351 else
7352#endif
7353 if (WIFEXITED(status)) sig = 0;
7354 else sig = WTERMSIG(status);
7355
7356 if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
7357 if (thisjob != job)
Eric Andersen3102ac42001-07-06 04:26:23 +00007358 out2fmt("%d: ", pid);
Eric Andersen2870d962001-07-02 17:27:21 +00007359#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007360 if (sig == SIGTSTP && rootshell && iflag)
Eric Andersen3102ac42001-07-06 04:26:23 +00007361 out2fmt("%%%ld ",
Eric Andersencb57d552001-06-28 07:25:16 +00007362 (long)(job - jobtab + 1));
7363#endif
7364 if (sig < NSIG && sys_siglist[sig])
7365 out2str(sys_siglist[sig]);
7366 else
Eric Andersen3102ac42001-07-06 04:26:23 +00007367 out2fmt("Signal %d", sig);
Eric Andersencb57d552001-06-28 07:25:16 +00007368 if (core)
7369 out2str(" - core dumped");
7370 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00007371 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00007372 TRACE(("Not printing status: status=%d, sig=%d\n",
Eric Andersencb57d552001-06-28 07:25:16 +00007373 status, sig));
7374 }
7375 } else {
7376 TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
7377 if (thisjob)
7378 thisjob->changed = 1;
7379 }
7380 return pid;
7381}
7382
7383
7384
Eric Andersencb57d552001-06-28 07:25:16 +00007385
7386/*
7387 * return 1 if there are stopped jobs, otherwise 0
7388 */
Eric Andersencb57d552001-06-28 07:25:16 +00007389static int
Eric Andersen2870d962001-07-02 17:27:21 +00007390stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007391{
7392 int jobno;
7393 struct job *jp;
7394
7395 if (job_warning)
7396 return (0);
7397 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
7398 if (jp->used == 0)
7399 continue;
7400 if (jp->state == JOBSTOPPED) {
7401 out2str("You have stopped jobs.\n");
7402 job_warning = 2;
7403 return (1);
7404 }
7405 }
7406
7407 return (0);
7408}
7409
7410/*
7411 * Return a string identifying a command (to be printed by the
7412 * jobs command.
7413 */
7414
7415static char *cmdnextc;
7416static int cmdnleft;
Eric Andersen2870d962001-07-02 17:27:21 +00007417#define MAXCMDTEXT 200
Eric Andersencb57d552001-06-28 07:25:16 +00007418
Eric Andersen2870d962001-07-02 17:27:21 +00007419static void
7420cmdputs(const char *s)
7421{
7422 const char *p;
7423 char *q;
7424 char c;
7425 int subtype = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007426
Eric Andersen2870d962001-07-02 17:27:21 +00007427 if (cmdnleft <= 0)
7428 return;
7429 p = s;
7430 q = cmdnextc;
7431 while ((c = *p++) != '\0') {
7432 if (c == CTLESC)
7433 *q++ = *p++;
7434 else if (c == CTLVAR) {
7435 *q++ = '$';
7436 if (--cmdnleft > 0)
7437 *q++ = '{';
7438 subtype = *p++;
7439 } else if (c == '=' && subtype != 0) {
7440 *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
7441 subtype = 0;
7442 } else if (c == CTLENDVAR) {
7443 *q++ = '}';
7444 } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
7445 cmdnleft++; /* ignore it */
7446 else
7447 *q++ = c;
7448 if (--cmdnleft <= 0) {
7449 *q++ = '.';
7450 *q++ = '.';
7451 *q++ = '.';
7452 break;
7453 }
7454 }
7455 cmdnextc = q;
Eric Andersencb57d552001-06-28 07:25:16 +00007456}
7457
7458
7459static void
Eric Andersen2870d962001-07-02 17:27:21 +00007460cmdtxt(const union node *n)
7461{
Eric Andersencb57d552001-06-28 07:25:16 +00007462 union node *np;
7463 struct nodelist *lp;
7464 const char *p;
7465 int i;
7466 char s[2];
7467
7468 if (n == NULL)
7469 return;
7470 switch (n->type) {
7471 case NSEMI:
7472 cmdtxt(n->nbinary.ch1);
7473 cmdputs("; ");
7474 cmdtxt(n->nbinary.ch2);
7475 break;
7476 case NAND:
7477 cmdtxt(n->nbinary.ch1);
7478 cmdputs(" && ");
7479 cmdtxt(n->nbinary.ch2);
7480 break;
7481 case NOR:
7482 cmdtxt(n->nbinary.ch1);
7483 cmdputs(" || ");
7484 cmdtxt(n->nbinary.ch2);
7485 break;
7486 case NPIPE:
7487 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7488 cmdtxt(lp->n);
7489 if (lp->next)
7490 cmdputs(" | ");
7491 }
7492 break;
7493 case NSUBSHELL:
7494 cmdputs("(");
7495 cmdtxt(n->nredir.n);
7496 cmdputs(")");
7497 break;
7498 case NREDIR:
7499 case NBACKGND:
7500 cmdtxt(n->nredir.n);
7501 break;
7502 case NIF:
7503 cmdputs("if ");
7504 cmdtxt(n->nif.test);
7505 cmdputs("; then ");
7506 cmdtxt(n->nif.ifpart);
7507 cmdputs("...");
7508 break;
7509 case NWHILE:
7510 cmdputs("while ");
7511 goto until;
7512 case NUNTIL:
7513 cmdputs("until ");
7514until:
7515 cmdtxt(n->nbinary.ch1);
7516 cmdputs("; do ");
7517 cmdtxt(n->nbinary.ch2);
7518 cmdputs("; done");
7519 break;
7520 case NFOR:
7521 cmdputs("for ");
7522 cmdputs(n->nfor.var);
7523 cmdputs(" in ...");
7524 break;
7525 case NCASE:
7526 cmdputs("case ");
7527 cmdputs(n->ncase.expr->narg.text);
7528 cmdputs(" in ...");
7529 break;
7530 case NDEFUN:
7531 cmdputs(n->narg.text);
7532 cmdputs("() ...");
7533 break;
7534 case NCMD:
7535 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7536 cmdtxt(np);
7537 if (np->narg.next)
7538 cmdputs(spcstr);
7539 }
7540 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7541 cmdputs(spcstr);
7542 cmdtxt(np);
7543 }
7544 break;
7545 case NARG:
7546 cmdputs(n->narg.text);
7547 break;
7548 case NTO:
7549 p = ">"; i = 1; goto redir;
7550 case NAPPEND:
7551 p = ">>"; i = 1; goto redir;
7552 case NTOFD:
7553 p = ">&"; i = 1; goto redir;
7554 case NTOOV:
7555 p = ">|"; i = 1; goto redir;
7556 case NFROM:
7557 p = "<"; i = 0; goto redir;
7558 case NFROMFD:
7559 p = "<&"; i = 0; goto redir;
7560 case NFROMTO:
7561 p = "<>"; i = 0; goto redir;
7562redir:
7563 if (n->nfile.fd != i) {
7564 s[0] = n->nfile.fd + '0';
7565 s[1] = '\0';
7566 cmdputs(s);
7567 }
7568 cmdputs(p);
7569 if (n->type == NTOFD || n->type == NFROMFD) {
7570 s[0] = n->ndup.dupfd + '0';
7571 s[1] = '\0';
7572 cmdputs(s);
7573 } else {
7574 cmdtxt(n->nfile.fname);
7575 }
7576 break;
7577 case NHERE:
7578 case NXHERE:
7579 cmdputs("<<...");
7580 break;
7581 default:
7582 cmdputs("???");
7583 break;
7584 }
7585}
7586
7587
Eric Andersen2870d962001-07-02 17:27:21 +00007588static char *
7589commandtext(const union node *n)
7590{
7591 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007592
Eric Andersen2870d962001-07-02 17:27:21 +00007593 cmdnextc = name = ckmalloc(MAXCMDTEXT);
7594 cmdnleft = MAXCMDTEXT - 4;
7595 cmdtxt(n);
7596 *cmdnextc = '\0';
7597 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00007598}
7599
Eric Andersen2870d962001-07-02 17:27:21 +00007600
Eric Andersencb57d552001-06-28 07:25:16 +00007601static void waitonint(int sig) {
7602 intreceived = 1;
7603 return;
7604}
Eric Andersencb57d552001-06-28 07:25:16 +00007605/*
7606 * Routines to check for mail. (Perhaps make part of main.c?)
7607 */
7608
7609
7610#define MAXMBOXES 10
7611
7612
Eric Andersen2870d962001-07-02 17:27:21 +00007613static int nmboxes; /* number of mailboxes */
7614static time_t mailtime[MAXMBOXES]; /* times of mailboxes */
Eric Andersencb57d552001-06-28 07:25:16 +00007615
7616
7617
7618/*
7619 * Print appropriate message(s) if mail has arrived. If the argument is
7620 * nozero, then the value of MAIL has changed, so we just update the
7621 * values.
7622 */
7623
7624static void
Eric Andersen2870d962001-07-02 17:27:21 +00007625chkmail(int silent)
Eric Andersencb57d552001-06-28 07:25:16 +00007626{
7627 int i;
7628 const char *mpath;
7629 char *p;
7630 char *q;
7631 struct stackmark smark;
7632 struct stat statb;
7633
7634 if (silent)
7635 nmboxes = 10;
7636 if (nmboxes == 0)
7637 return;
7638 setstackmark(&smark);
7639 mpath = mpathset()? mpathval() : mailval();
7640 for (i = 0 ; i < nmboxes ; i++) {
7641 p = padvance(&mpath, nullstr);
7642 if (p == NULL)
7643 break;
7644 if (*p == '\0')
7645 continue;
7646 for (q = p ; *q ; q++);
7647#ifdef DEBUG
7648 if (q[-1] != '/')
7649 abort();
7650#endif
Eric Andersen2870d962001-07-02 17:27:21 +00007651 q[-1] = '\0'; /* delete trailing '/' */
Eric Andersencb57d552001-06-28 07:25:16 +00007652 if (stat(p, &statb) < 0)
7653 statb.st_size = 0;
7654 if (statb.st_size > mailtime[i] && ! silent) {
Eric Andersen3102ac42001-07-06 04:26:23 +00007655 out2fmt(snlfmt,
7656 pathopt? pathopt : "you have mail");
Eric Andersencb57d552001-06-28 07:25:16 +00007657 }
7658 mailtime[i] = statb.st_size;
Eric Andersencb57d552001-06-28 07:25:16 +00007659 }
7660 nmboxes = i;
7661 popstackmark(&smark);
7662}
Eric Andersencb57d552001-06-28 07:25:16 +00007663
7664#define PROFILE 0
7665
Eric Andersencb57d552001-06-28 07:25:16 +00007666#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007667static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007668extern int etext();
7669#endif
7670
Eric Andersen2870d962001-07-02 17:27:21 +00007671static void read_profile (const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007672static void cmdloop (int);
7673static void options (int);
Eric Andersen2870d962001-07-02 17:27:21 +00007674static void setoption (int, int);
7675static void procargs (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00007676
Eric Andersen2870d962001-07-02 17:27:21 +00007677
Eric Andersencb57d552001-06-28 07:25:16 +00007678/*
7679 * Main routine. We initialize things, parse the arguments, execute
7680 * profiles if we're a login shell, and then call cmdloop to execute
7681 * commands. The setjmp call sets up the location to jump to when an
7682 * exception occurs. When an exception occurs the variable "state"
7683 * is used to figure out how far we had gotten.
7684 */
7685
7686int
7687shell_main(argc, argv)
7688 int argc;
7689 char **argv;
7690{
7691 struct jmploc jmploc;
7692 struct stackmark smark;
7693 volatile int state;
Eric Andersen62483552001-07-10 06:09:16 +00007694 const char *shinit;
Eric Andersencb57d552001-06-28 07:25:16 +00007695
Eric Andersencb57d552001-06-28 07:25:16 +00007696 BLTINCMD = find_builtin("builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00007697 EXECCMD = find_builtin("exec");
7698 EVALCMD = find_builtin("eval");
7699
Eric Andersen1c039232001-07-07 00:05:55 +00007700#ifndef BB_FEATURE_SH_FANCY_PROMPT
7701 unsetenv("PS1");
7702 unsetenv("PS2");
7703#endif
7704
Eric Andersencb57d552001-06-28 07:25:16 +00007705#if PROFILE
7706 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7707#endif
7708#if defined(linux) || defined(__GNU__)
7709 signal(SIGCHLD, SIG_DFL);
7710#endif
7711 state = 0;
7712 if (setjmp(jmploc.loc)) {
7713 INTOFF;
7714 /*
7715 * When a shell procedure is executed, we raise the
7716 * exception EXSHELLPROC to clean up before executing
7717 * the shell procedure.
7718 */
7719 switch (exception) {
7720 case EXSHELLPROC:
7721 rootpid = getpid();
7722 rootshell = 1;
7723 minusc = NULL;
7724 state = 3;
7725 break;
7726
7727 case EXEXEC:
7728 exitstatus = exerrno;
7729 break;
7730
7731 case EXERROR:
7732 exitstatus = 2;
7733 break;
7734
7735 default:
7736 break;
7737 }
7738
7739 if (exception != EXSHELLPROC) {
7740 if (state == 0 || iflag == 0 || ! rootshell)
7741 exitshell(exitstatus);
7742 }
7743 reset();
Eric Andersen2870d962001-07-02 17:27:21 +00007744 if (exception == EXINT) {
Eric Andersencb57d552001-06-28 07:25:16 +00007745 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00007746 }
7747 popstackmark(&smark);
Eric Andersen2870d962001-07-02 17:27:21 +00007748 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007749 if (state == 1)
7750 goto state1;
7751 else if (state == 2)
7752 goto state2;
7753 else if (state == 3)
7754 goto state3;
7755 else
7756 goto state4;
7757 }
7758 handler = &jmploc;
7759#ifdef DEBUG
7760 opentrace();
7761 trputs("Shell args: "); trargs(argv);
7762#endif
7763 rootpid = getpid();
7764 rootshell = 1;
7765 init();
7766 setstackmark(&smark);
7767 procargs(argc, argv);
7768 if (argv[0] && argv[0][0] == '-') {
7769 state = 1;
7770 read_profile("/etc/profile");
7771state1:
7772 state = 2;
7773 read_profile(".profile");
7774 }
7775state2:
7776 state = 3;
7777#ifndef linux
7778 if (getuid() == geteuid() && getgid() == getegid()) {
7779#endif
7780 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7781 state = 3;
7782 read_profile(shinit);
7783 }
7784#ifndef linux
7785 }
7786#endif
7787state3:
7788 state = 4;
7789 if (sflag == 0 || minusc) {
7790 static int sigs[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00007791 SIGINT, SIGQUIT, SIGHUP,
Eric Andersencb57d552001-06-28 07:25:16 +00007792#ifdef SIGTSTP
7793 SIGTSTP,
7794#endif
7795 SIGPIPE
7796 };
7797#define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0]))
7798 int i;
7799
7800 for (i = 0; i < SIGSSIZE; i++)
7801 setsignal(sigs[i]);
7802 }
7803
7804 if (minusc)
7805 evalstring(minusc, 0);
7806
7807 if (sflag || minusc == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00007808state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007809 cmdloop(1);
7810 }
7811#if PROFILE
7812 monitor(0);
7813#endif
7814 exitshell(exitstatus);
7815 /* NOTREACHED */
7816}
7817
7818
7819/*
7820 * Read and execute commands. "Top" is nonzero for the top level command
7821 * loop; it turns on prompting if the shell is interactive.
7822 */
7823
7824static void
Eric Andersen2870d962001-07-02 17:27:21 +00007825cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00007826{
7827 union node *n;
7828 struct stackmark smark;
7829 int inter;
7830 int numeof = 0;
7831
7832 TRACE(("cmdloop(%d) called\n", top));
7833 setstackmark(&smark);
7834 for (;;) {
7835 if (pendingsigs)
7836 dotrap();
7837 inter = 0;
7838 if (iflag && top) {
7839 inter++;
7840 showjobs(1);
7841 chkmail(0);
Eric Andersen3102ac42001-07-06 04:26:23 +00007842 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00007843 }
7844 n = parsecmd(inter);
7845 /* showtree(n); DEBUG */
7846 if (n == NEOF) {
7847 if (!top || numeof >= 50)
7848 break;
7849 if (!stoppedjobs()) {
7850 if (!Iflag)
7851 break;
7852 out2str("\nUse \"exit\" to leave shell.\n");
7853 }
7854 numeof++;
7855 } else if (n != NULL && nflag == 0) {
7856 job_warning = (job_warning == 2) ? 1 : 0;
7857 numeof = 0;
7858 evaltree(n, 0);
7859 }
7860 popstackmark(&smark);
7861 setstackmark(&smark);
7862 if (evalskip == SKIPFILE) {
7863 evalskip = 0;
7864 break;
7865 }
7866 }
7867 popstackmark(&smark);
7868}
7869
7870
7871
7872/*
7873 * Read /etc/profile or .profile. Return on error.
7874 */
7875
7876static void
7877read_profile(name)
7878 const char *name;
7879{
7880 int fd;
7881 int xflag_set = 0;
7882 int vflag_set = 0;
7883
7884 INTOFF;
7885 if ((fd = open(name, O_RDONLY)) >= 0)
7886 setinputfd(fd, 1);
7887 INTON;
7888 if (fd < 0)
7889 return;
7890 /* -q turns off -x and -v just when executing init files */
7891 if (qflag) {
7892 if (xflag)
7893 xflag = 0, xflag_set = 1;
7894 if (vflag)
7895 vflag = 0, vflag_set = 1;
7896 }
7897 cmdloop(0);
7898 if (qflag) {
7899 if (xflag_set)
7900 xflag = 1;
7901 if (vflag_set)
7902 vflag = 1;
7903 }
7904 popfile();
7905}
7906
7907
7908
7909/*
7910 * Read a file containing shell functions.
7911 */
7912
7913static void
Eric Andersen2870d962001-07-02 17:27:21 +00007914readcmdfile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00007915{
7916 int fd;
7917
7918 INTOFF;
7919 if ((fd = open(name, O_RDONLY)) >= 0)
7920 setinputfd(fd, 1);
7921 else
7922 error("Can't open %s", name);
7923 INTON;
7924 cmdloop(0);
7925 popfile();
7926}
7927
7928
7929
7930/*
7931 * Take commands from a file. To be compatable we should do a path
7932 * search for the file, which is necessary to find sub-commands.
7933 */
7934
7935
Eric Andersen62483552001-07-10 06:09:16 +00007936static inline char *
Eric Andersencb57d552001-06-28 07:25:16 +00007937find_dot_file(mybasename)
7938 char *mybasename;
7939{
7940 char *fullname;
7941 const char *path = pathval();
7942 struct stat statb;
7943
7944 /* don't try this for absolute or relative paths */
7945 if (strchr(mybasename, '/'))
7946 return mybasename;
7947
7948 while ((fullname = padvance(&path, mybasename)) != NULL) {
7949 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
7950 /*
7951 * Don't bother freeing here, since it will
7952 * be freed by the caller.
7953 */
7954 return fullname;
7955 }
7956 stunalloc(fullname);
7957 }
7958
7959 /* not found in the PATH */
7960 error("%s: not found", mybasename);
7961 /* NOTREACHED */
7962}
7963
7964static int
7965dotcmd(argc, argv)
7966 int argc;
7967 char **argv;
7968{
7969 struct strlist *sp;
7970 exitstatus = 0;
7971
7972 for (sp = cmdenviron; sp ; sp = sp->next)
7973 setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
7974
Eric Andersen2870d962001-07-02 17:27:21 +00007975 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00007976 char *fullname;
7977 struct stackmark smark;
7978
7979 setstackmark(&smark);
7980 fullname = find_dot_file(argv[1]);
7981 setinputfile(fullname, 1);
7982 commandname = fullname;
7983 cmdloop(0);
7984 popfile();
7985 popstackmark(&smark);
7986 }
7987 return exitstatus;
7988}
7989
7990
7991static int
7992exitcmd(argc, argv)
7993 int argc;
7994 char **argv;
7995{
7996 if (stoppedjobs())
7997 return 0;
7998 if (argc > 1)
7999 exitstatus = number(argv[1]);
8000 else
8001 exitstatus = oexitstatus;
8002 exitshell(exitstatus);
8003 /* NOTREACHED */
8004}
Eric Andersen62483552001-07-10 06:09:16 +00008005
Eric Andersen2870d962001-07-02 17:27:21 +00008006static pointer
8007stalloc(int nbytes)
Eric Andersencb57d552001-06-28 07:25:16 +00008008{
8009 char *p;
8010
8011 nbytes = ALIGN(nbytes);
8012 if (nbytes > stacknleft) {
8013 int blocksize;
8014 struct stack_block *sp;
8015
8016 blocksize = nbytes;
8017 if (blocksize < MINSIZE)
8018 blocksize = MINSIZE;
8019 INTOFF;
8020 sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
8021 sp->prev = stackp;
8022 stacknxt = sp->space;
8023 stacknleft = blocksize;
8024 stackp = sp;
8025 INTON;
8026 }
8027 p = stacknxt;
8028 stacknxt += nbytes;
8029 stacknleft -= nbytes;
8030 return p;
8031}
8032
8033
8034static void
Eric Andersen2870d962001-07-02 17:27:21 +00008035stunalloc(pointer p)
8036{
Eric Andersencb57d552001-06-28 07:25:16 +00008037#ifdef DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +00008038 if (p == NULL) { /*DEBUG */
Eric Andersencb57d552001-06-28 07:25:16 +00008039 write(2, "stunalloc\n", 10);
8040 abort();
8041 }
8042#endif
8043 if (!(stacknxt >= (char *)p && (char *)p >= stackp->space)) {
8044 p = stackp->space;
8045 }
8046 stacknleft += stacknxt - (char *)p;
8047 stacknxt = p;
8048}
8049
8050
Eric Andersencb57d552001-06-28 07:25:16 +00008051static void
Eric Andersen2870d962001-07-02 17:27:21 +00008052setstackmark(struct stackmark *mark)
8053{
Eric Andersencb57d552001-06-28 07:25:16 +00008054 mark->stackp = stackp;
8055 mark->stacknxt = stacknxt;
8056 mark->stacknleft = stacknleft;
8057 mark->marknext = markp;
8058 markp = mark;
8059}
8060
8061
8062static void
Eric Andersen2870d962001-07-02 17:27:21 +00008063popstackmark(struct stackmark *mark)
8064{
Eric Andersencb57d552001-06-28 07:25:16 +00008065 struct stack_block *sp;
8066
8067 INTOFF;
8068 markp = mark->marknext;
8069 while (stackp != mark->stackp) {
8070 sp = stackp;
8071 stackp = sp->prev;
8072 ckfree(sp);
8073 }
8074 stacknxt = mark->stacknxt;
8075 stacknleft = mark->stacknleft;
8076 INTON;
8077}
8078
8079
8080/*
8081 * When the parser reads in a string, it wants to stick the string on the
8082 * stack and only adjust the stack pointer when it knows how big the
8083 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8084 * of space on top of the stack and stackblocklen returns the length of
8085 * this block. Growstackblock will grow this space by at least one byte,
8086 * possibly moving it (like realloc). Grabstackblock actually allocates the
8087 * part of the block that has been used.
8088 */
8089
8090static void
Eric Andersen2870d962001-07-02 17:27:21 +00008091growstackblock(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00008092 char *p;
8093 int newlen = ALIGN(stacknleft * 2 + 100);
8094 char *oldspace = stacknxt;
8095 int oldlen = stacknleft;
8096 struct stack_block *sp;
8097 struct stack_block *oldstackp;
8098
8099 if (stacknxt == stackp->space && stackp != &stackbase) {
8100 INTOFF;
8101 oldstackp = stackp;
8102 sp = stackp;
8103 stackp = sp->prev;
8104 sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen);
8105 sp->prev = stackp;
8106 stackp = sp;
8107 stacknxt = sp->space;
8108 stacknleft = newlen;
8109 {
8110 /* Stack marks pointing to the start of the old block
Eric Andersen2870d962001-07-02 17:27:21 +00008111 * must be relocated to point to the new block
Eric Andersencb57d552001-06-28 07:25:16 +00008112 */
8113 struct stackmark *xmark;
8114 xmark = markp;
8115 while (xmark != NULL && xmark->stackp == oldstackp) {
8116 xmark->stackp = stackp;
8117 xmark->stacknxt = stacknxt;
8118 xmark->stacknleft = stacknleft;
8119 xmark = xmark->marknext;
8120 }
8121 }
8122 INTON;
8123 } else {
8124 p = stalloc(newlen);
8125 memcpy(p, oldspace, oldlen);
Eric Andersen2870d962001-07-02 17:27:21 +00008126 stacknxt = p; /* free the space */
8127 stacknleft += newlen; /* we just allocated */
Eric Andersencb57d552001-06-28 07:25:16 +00008128 }
8129}
8130
8131
8132
Eric Andersen2870d962001-07-02 17:27:21 +00008133static inline void
8134grabstackblock(int len)
Eric Andersencb57d552001-06-28 07:25:16 +00008135{
8136 len = ALIGN(len);
8137 stacknxt += len;
8138 stacknleft -= len;
8139}
8140
8141
8142
8143/*
8144 * The following routines are somewhat easier to use that the above.
8145 * The user declares a variable of type STACKSTR, which may be declared
8146 * to be a register. The macro STARTSTACKSTR initializes things. Then
8147 * the user uses the macro STPUTC to add characters to the string. In
8148 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8149 * grown as necessary. When the user is done, she can just leave the
8150 * string there and refer to it using stackblock(). Or she can allocate
8151 * the space for it using grabstackstr(). If it is necessary to allow
8152 * someone else to use the stack temporarily and then continue to grow
8153 * the string, the user should use grabstack to allocate the space, and
8154 * then call ungrabstr(p) to return to the previous mode of operation.
8155 *
8156 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8157 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8158 * is space for at least one character.
8159 */
8160
8161
8162static char *
Eric Andersen2870d962001-07-02 17:27:21 +00008163growstackstr(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00008164 int len = stackblocksize();
8165 if (herefd >= 0 && len >= 1024) {
8166 xwrite(herefd, stackblock(), len);
8167 sstrnleft = len - 1;
8168 return stackblock();
8169 }
8170 growstackblock();
8171 sstrnleft = stackblocksize() - len - 1;
8172 return stackblock() + len;
8173}
8174
8175
8176/*
8177 * Called from CHECKSTRSPACE.
8178 */
8179
8180static char *
8181makestrspace(size_t newlen) {
8182 int len = stackblocksize() - sstrnleft;
8183 do {
8184 growstackblock();
8185 sstrnleft = stackblocksize() - len;
8186 } while (sstrnleft < newlen);
8187 return stackblock() + len;
8188}
8189
8190
8191
8192static void
Eric Andersen2870d962001-07-02 17:27:21 +00008193ungrabstackstr(char *s, char *p)
8194{
Eric Andersencb57d552001-06-28 07:25:16 +00008195 stacknleft += stacknxt - s;
8196 stacknxt = s;
8197 sstrnleft = stacknleft - (p - s);
8198}
Eric Andersencb57d552001-06-28 07:25:16 +00008199/*
8200 * Miscelaneous builtins.
8201 */
8202
8203
8204#undef rflag
8205
Eric Andersen62483552001-07-10 06:09:16 +00008206//#ifdef __GLIBC__
Eric Andersen2870d962001-07-02 17:27:21 +00008207static mode_t getmode(const void *, mode_t);
Eric Andersencb57d552001-06-28 07:25:16 +00008208static void *setmode(const char *);
Eric Andersen62483552001-07-10 06:09:16 +00008209//#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008210
8211#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersen62483552001-07-10 06:09:16 +00008212typedef long rlim_t;
Eric Andersencb57d552001-06-28 07:25:16 +00008213#endif
8214
8215
8216
8217/*
8218 * The read builtin. The -e option causes backslashes to escape the
8219 * following character.
8220 *
8221 * This uses unbuffered input, which may be avoidable in some cases.
8222 */
8223
8224static int
8225readcmd(argc, argv)
8226 int argc;
8227 char **argv;
8228{
8229 char **ap;
8230 int backslash;
8231 char c;
8232 int rflag;
8233 char *prompt;
8234 const char *ifs;
8235 char *p;
8236 int startword;
8237 int status;
8238 int i;
8239
8240 rflag = 0;
8241 prompt = NULL;
8242 while ((i = nextopt("p:r")) != '\0') {
8243 if (i == 'p')
8244 prompt = optionarg;
8245 else
8246 rflag = 1;
8247 }
8248 if (prompt && isatty(0)) {
8249 putprompt(prompt);
8250 flushall();
8251 }
8252 if (*(ap = argptr) == NULL)
8253 error("arg count");
8254 if ((ifs = bltinlookup("IFS")) == NULL)
8255 ifs = defifs;
8256 status = 0;
8257 startword = 1;
8258 backslash = 0;
8259 STARTSTACKSTR(p);
8260 for (;;) {
8261 if (read(0, &c, 1) != 1) {
8262 status = 1;
8263 break;
8264 }
8265 if (c == '\0')
8266 continue;
8267 if (backslash) {
8268 backslash = 0;
8269 if (c != '\n')
8270 STPUTC(c, p);
8271 continue;
8272 }
8273 if (!rflag && c == '\\') {
8274 backslash++;
8275 continue;
8276 }
8277 if (c == '\n')
8278 break;
8279 if (startword && *ifs == ' ' && strchr(ifs, c)) {
8280 continue;
8281 }
8282 startword = 0;
8283 if (backslash && c == '\\') {
8284 if (read(0, &c, 1) != 1) {
8285 status = 1;
8286 break;
8287 }
8288 STPUTC(c, p);
8289 } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
8290 STACKSTRNUL(p);
8291 setvar(*ap, stackblock(), 0);
8292 ap++;
8293 startword = 1;
8294 STARTSTACKSTR(p);
8295 } else {
8296 STPUTC(c, p);
8297 }
8298 }
8299 STACKSTRNUL(p);
8300 /* Remove trailing blanks */
8301 while (stackblock() <= --p && strchr(ifs, *p) != NULL)
8302 *p = '\0';
8303 setvar(*ap, stackblock(), 0);
8304 while (*++ap != NULL)
8305 setvar(*ap, nullstr, 0);
8306 return status;
8307}
8308
8309
8310
8311static int
8312umaskcmd(argc, argv)
8313 int argc;
8314 char **argv;
8315{
8316 char *ap;
8317 int mask;
8318 int i;
8319 int symbolic_mode = 0;
8320
Eric Andersen62483552001-07-10 06:09:16 +00008321 while (nextopt("S") != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00008322 symbolic_mode = 1;
8323 }
8324
8325 INTOFF;
8326 mask = umask(0);
8327 umask(mask);
8328 INTON;
8329
8330 if ((ap = *argptr) == NULL) {
8331 if (symbolic_mode) {
8332 char u[4], g[4], o[4];
8333
8334 i = 0;
8335 if ((mask & S_IRUSR) == 0)
8336 u[i++] = 'r';
8337 if ((mask & S_IWUSR) == 0)
8338 u[i++] = 'w';
8339 if ((mask & S_IXUSR) == 0)
8340 u[i++] = 'x';
8341 u[i] = '\0';
8342
8343 i = 0;
8344 if ((mask & S_IRGRP) == 0)
8345 g[i++] = 'r';
8346 if ((mask & S_IWGRP) == 0)
8347 g[i++] = 'w';
8348 if ((mask & S_IXGRP) == 0)
8349 g[i++] = 'x';
8350 g[i] = '\0';
8351
8352 i = 0;
8353 if ((mask & S_IROTH) == 0)
8354 o[i++] = 'r';
8355 if ((mask & S_IWOTH) == 0)
8356 o[i++] = 'w';
8357 if ((mask & S_IXOTH) == 0)
8358 o[i++] = 'x';
8359 o[i] = '\0';
8360
Eric Andersen62483552001-07-10 06:09:16 +00008361 printf("u=%s,g=%s,o=%s\n", u, g, o);
Eric Andersencb57d552001-06-28 07:25:16 +00008362 } else {
Eric Andersen62483552001-07-10 06:09:16 +00008363 printf("%.4o\n", mask);
Eric Andersencb57d552001-06-28 07:25:16 +00008364 }
8365 } else {
Eric Andersen62483552001-07-10 06:09:16 +00008366 if (is_digit((unsigned char)*ap)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008367 mask = 0;
8368 do {
8369 if (*ap >= '8' || *ap < '0')
8370 error("Illegal number: %s", argv[1]);
8371 mask = (mask << 3) + (*ap - '0');
8372 } while (*++ap != '\0');
8373 umask(mask);
8374 } else {
8375 void *set;
8376
8377 INTOFF;
8378 if ((set = setmode(ap)) != 0) {
8379 mask = getmode(set, ~mask & 0777);
8380 ckfree(set);
8381 }
8382 INTON;
8383 if (!set)
8384 error("Illegal mode: %s", ap);
8385
8386 umask(~mask & 0777);
8387 }
8388 }
8389 return 0;
8390}
8391
8392/*
8393 * ulimit builtin
8394 *
8395 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
8396 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
8397 * ash by J.T. Conklin.
8398 *
8399 * Public domain.
8400 */
8401
8402struct limits {
8403 const char *name;
Eric Andersen2870d962001-07-02 17:27:21 +00008404 int cmd;
8405 int factor; /* multiply by to get rlim_{cur,max} values */
8406 char option;
Eric Andersencb57d552001-06-28 07:25:16 +00008407};
8408
8409static const struct limits limits[] = {
8410#ifdef RLIMIT_CPU
Eric Andersen2870d962001-07-02 17:27:21 +00008411 { "time(seconds)", RLIMIT_CPU, 1, 't' },
Eric Andersencb57d552001-06-28 07:25:16 +00008412#endif
8413#ifdef RLIMIT_FSIZE
Eric Andersen2870d962001-07-02 17:27:21 +00008414 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
Eric Andersencb57d552001-06-28 07:25:16 +00008415#endif
8416#ifdef RLIMIT_DATA
Eric Andersen2870d962001-07-02 17:27:21 +00008417 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
Eric Andersencb57d552001-06-28 07:25:16 +00008418#endif
8419#ifdef RLIMIT_STACK
Eric Andersen2870d962001-07-02 17:27:21 +00008420 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
Eric Andersencb57d552001-06-28 07:25:16 +00008421#endif
8422#ifdef RLIMIT_CORE
Eric Andersen2870d962001-07-02 17:27:21 +00008423 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
Eric Andersencb57d552001-06-28 07:25:16 +00008424#endif
8425#ifdef RLIMIT_RSS
Eric Andersen2870d962001-07-02 17:27:21 +00008426 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
Eric Andersencb57d552001-06-28 07:25:16 +00008427#endif
8428#ifdef RLIMIT_MEMLOCK
Eric Andersen2870d962001-07-02 17:27:21 +00008429 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
Eric Andersencb57d552001-06-28 07:25:16 +00008430#endif
8431#ifdef RLIMIT_NPROC
Eric Andersen2870d962001-07-02 17:27:21 +00008432 { "process(processes)", RLIMIT_NPROC, 1, 'p' },
Eric Andersencb57d552001-06-28 07:25:16 +00008433#endif
8434#ifdef RLIMIT_NOFILE
Eric Andersen2870d962001-07-02 17:27:21 +00008435 { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
Eric Andersencb57d552001-06-28 07:25:16 +00008436#endif
8437#ifdef RLIMIT_VMEM
Eric Andersen2870d962001-07-02 17:27:21 +00008438 { "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' },
Eric Andersencb57d552001-06-28 07:25:16 +00008439#endif
8440#ifdef RLIMIT_SWAP
Eric Andersen2870d962001-07-02 17:27:21 +00008441 { "swap(kbytes)", RLIMIT_SWAP, 1024, 'w' },
Eric Andersencb57d552001-06-28 07:25:16 +00008442#endif
Eric Andersen2870d962001-07-02 17:27:21 +00008443 { (char *) 0, 0, 0, '\0' }
Eric Andersencb57d552001-06-28 07:25:16 +00008444};
8445
8446static int
8447ulimitcmd(argc, argv)
8448 int argc;
8449 char **argv;
8450{
Eric Andersen2870d962001-07-02 17:27:21 +00008451 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00008452 rlim_t val = 0;
8453 enum { SOFT = 0x1, HARD = 0x2 }
8454 how = SOFT | HARD;
Eric Andersen2870d962001-07-02 17:27:21 +00008455 const struct limits *l;
8456 int set, all = 0;
8457 int optc, what;
8458 struct rlimit limit;
Eric Andersencb57d552001-06-28 07:25:16 +00008459
8460 what = 'f';
8461 while ((optc = nextopt("HSatfdsmcnpl")) != '\0')
8462 switch (optc) {
8463 case 'H':
8464 how = HARD;
8465 break;
8466 case 'S':
8467 how = SOFT;
8468 break;
8469 case 'a':
8470 all = 1;
8471 break;
8472 default:
8473 what = optc;
8474 }
8475
8476 for (l = limits; l->name && l->option != what; l++)
8477 ;
8478 if (!l->name)
8479 error("internal error (%c)", what);
8480
8481 set = *argptr ? 1 : 0;
8482 if (set) {
8483 char *p = *argptr;
8484
8485 if (all || argptr[1])
8486 error("too many arguments");
8487 if (strcmp(p, "unlimited") == 0)
8488 val = RLIM_INFINITY;
8489 else {
8490 val = (rlim_t) 0;
8491
8492 while ((c = *p++) >= '0' && c <= '9')
8493 {
8494 val = (val * 10) + (long)(c - '0');
8495 if (val < (rlim_t) 0)
8496 break;
8497 }
8498 if (c)
8499 error("bad number");
8500 val *= l->factor;
8501 }
8502 }
8503 if (all) {
8504 for (l = limits; l->name; l++) {
8505 getrlimit(l->cmd, &limit);
8506 if (how & SOFT)
8507 val = limit.rlim_cur;
8508 else if (how & HARD)
8509 val = limit.rlim_max;
8510
Eric Andersen62483552001-07-10 06:09:16 +00008511 printf("%-20s ", l->name);
Eric Andersencb57d552001-06-28 07:25:16 +00008512 if (val == RLIM_INFINITY)
Eric Andersen62483552001-07-10 06:09:16 +00008513 printf("unlimited\n");
Eric Andersencb57d552001-06-28 07:25:16 +00008514 else
8515 {
8516 val /= l->factor;
Eric Andersen62483552001-07-10 06:09:16 +00008517 printf("%lld\n", (long long) val);
Eric Andersencb57d552001-06-28 07:25:16 +00008518 }
8519 }
8520 return 0;
8521 }
8522
8523 getrlimit(l->cmd, &limit);
8524 if (set) {
8525 if (how & HARD)
8526 limit.rlim_max = val;
8527 if (how & SOFT)
8528 limit.rlim_cur = val;
8529 if (setrlimit(l->cmd, &limit) < 0)
Eric Andersen2870d962001-07-02 17:27:21 +00008530 error("error setting limit (%m)");
Eric Andersencb57d552001-06-28 07:25:16 +00008531 } else {
8532 if (how & SOFT)
8533 val = limit.rlim_cur;
8534 else if (how & HARD)
8535 val = limit.rlim_max;
8536
8537 if (val == RLIM_INFINITY)
Eric Andersen62483552001-07-10 06:09:16 +00008538 printf("unlimited\n");
Eric Andersencb57d552001-06-28 07:25:16 +00008539 else
8540 {
8541 val /= l->factor;
Eric Andersen62483552001-07-10 06:09:16 +00008542 printf("%lld\n", (long long) val);
Eric Andersencb57d552001-06-28 07:25:16 +00008543 }
8544 }
8545 return 0;
8546}
Eric Andersencb57d552001-06-28 07:25:16 +00008547/*
8548 * prefix -- see if pfx is a prefix of string.
8549 */
8550
8551static int
Eric Andersen62483552001-07-10 06:09:16 +00008552prefix(char const *pfx, char const *string)
8553{
Eric Andersencb57d552001-06-28 07:25:16 +00008554 while (*pfx) {
8555 if (*pfx++ != *string++)
8556 return 0;
8557 }
8558 return 1;
8559}
8560
Eric Andersen2870d962001-07-02 17:27:21 +00008561/*
8562 * Return true if s is a string of digits, and save munber in intptr
8563 * nagative is bad
8564 */
8565
8566static int
8567is_number(const char *p, int *intptr)
8568{
8569 int ret = 0;
8570
8571 do {
8572 if (! is_digit(*p))
8573 return 0;
8574 ret *= 10;
8575 ret += digit_val(*p);
8576 p++;
8577 } while (*p != '\0');
8578
8579 *intptr = ret;
8580 return 1;
8581}
Eric Andersencb57d552001-06-28 07:25:16 +00008582
8583/*
8584 * Convert a string of digits to an integer, printing an error message on
8585 * failure.
8586 */
8587
8588static int
Eric Andersen2870d962001-07-02 17:27:21 +00008589number(const char *s)
8590{
8591 int i;
8592 if (! is_number(s, &i))
Eric Andersencb57d552001-06-28 07:25:16 +00008593 error("Illegal number: %s", s);
Eric Andersen2870d962001-07-02 17:27:21 +00008594 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00008595}
8596
Eric Andersencb57d552001-06-28 07:25:16 +00008597/*
8598 * Produce a possibly single quoted string suitable as input to the shell.
8599 * The return string is allocated on the stack.
8600 */
8601
8602static char *
8603single_quote(const char *s) {
8604 char *p;
8605
8606 STARTSTACKSTR(p);
8607
8608 do {
8609 char *q = p;
8610 size_t len1, len1p, len2, len2p;
8611
8612 len1 = strcspn(s, "'");
8613 len2 = strspn(s + len1, "'");
8614
8615 len1p = len1 ? len1 + 2 : len1;
8616 switch (len2) {
8617 case 0:
8618 len2p = 0;
8619 break;
8620 case 1:
8621 len2p = 2;
8622 break;
8623 default:
8624 len2p = len2 + 2;
8625 }
8626
8627 CHECKSTRSPACE(len1p + len2p + 1, p);
8628
8629 if (len1) {
8630 *p = '\'';
Eric Andersencb57d552001-06-28 07:25:16 +00008631 q = p + 1 + len1;
8632 memcpy(p + 1, s, len1);
Eric Andersencb57d552001-06-28 07:25:16 +00008633 *q++ = '\'';
8634 s += len1;
8635 }
8636
8637 switch (len2) {
8638 case 0:
8639 break;
8640 case 1:
8641 *q++ = '\\';
8642 *q = '\'';
8643 s++;
8644 break;
8645 default:
8646 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008647 q += 1 + len2;
8648 memcpy(q + 1, s, len2);
8649 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008650 s += len2;
8651 }
8652
8653 STADJUST(len1p + len2p, p);
8654 } while (*s);
8655
8656 USTPUTC(0, p);
8657
8658 return grabstackstr(p);
8659}
8660
8661/*
8662 * Like strdup but works with the ash stack.
8663 */
8664
8665static char *
8666sstrdup(const char *p)
8667{
8668 size_t len = strlen(p) + 1;
8669 return memcpy(stalloc(len), p, len);
8670}
8671
Eric Andersencb57d552001-06-28 07:25:16 +00008672
8673/*
Eric Andersencb57d552001-06-28 07:25:16 +00008674 * Routine for dealing with parsed shell commands.
8675 */
8676
8677
Eric Andersen62483552001-07-10 06:09:16 +00008678static void sizenodelist (const struct nodelist *);
8679static struct nodelist *copynodelist (const struct nodelist *);
8680static char *nodesavestr (const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00008681
8682static void
Eric Andersen62483552001-07-10 06:09:16 +00008683calcsize(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008684{
8685 if (n == NULL)
8686 return;
8687 funcblocksize += nodesize[n->type];
8688 switch (n->type) {
8689 case NSEMI:
8690 case NAND:
8691 case NOR:
8692 case NWHILE:
8693 case NUNTIL:
8694 calcsize(n->nbinary.ch2);
8695 calcsize(n->nbinary.ch1);
8696 break;
8697 case NCMD:
8698 calcsize(n->ncmd.redirect);
8699 calcsize(n->ncmd.args);
8700 calcsize(n->ncmd.assign);
8701 break;
8702 case NPIPE:
8703 sizenodelist(n->npipe.cmdlist);
8704 break;
8705 case NREDIR:
8706 case NBACKGND:
8707 case NSUBSHELL:
8708 calcsize(n->nredir.redirect);
8709 calcsize(n->nredir.n);
8710 break;
8711 case NIF:
8712 calcsize(n->nif.elsepart);
8713 calcsize(n->nif.ifpart);
8714 calcsize(n->nif.test);
8715 break;
8716 case NFOR:
8717 funcstringsize += strlen(n->nfor.var) + 1;
8718 calcsize(n->nfor.body);
8719 calcsize(n->nfor.args);
8720 break;
8721 case NCASE:
8722 calcsize(n->ncase.cases);
8723 calcsize(n->ncase.expr);
8724 break;
8725 case NCLIST:
8726 calcsize(n->nclist.body);
8727 calcsize(n->nclist.pattern);
8728 calcsize(n->nclist.next);
8729 break;
8730 case NDEFUN:
8731 case NARG:
8732 sizenodelist(n->narg.backquote);
8733 funcstringsize += strlen(n->narg.text) + 1;
8734 calcsize(n->narg.next);
8735 break;
8736 case NTO:
8737 case NFROM:
8738 case NFROMTO:
8739 case NAPPEND:
8740 case NTOOV:
8741 calcsize(n->nfile.fname);
8742 calcsize(n->nfile.next);
8743 break;
8744 case NTOFD:
8745 case NFROMFD:
8746 calcsize(n->ndup.vname);
8747 calcsize(n->ndup.next);
8748 break;
8749 case NHERE:
8750 case NXHERE:
8751 calcsize(n->nhere.doc);
8752 calcsize(n->nhere.next);
8753 break;
8754 case NNOT:
8755 calcsize(n->nnot.com);
8756 break;
8757 };
8758}
8759
Eric Andersencb57d552001-06-28 07:25:16 +00008760static void
Eric Andersen62483552001-07-10 06:09:16 +00008761sizenodelist(const struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008762{
8763 while (lp) {
8764 funcblocksize += ALIGN(sizeof(struct nodelist));
8765 calcsize(lp->n);
8766 lp = lp->next;
8767 }
8768}
8769
8770
Eric Andersencb57d552001-06-28 07:25:16 +00008771static union node *
Eric Andersen62483552001-07-10 06:09:16 +00008772copynode(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008773{
Eric Andersen62483552001-07-10 06:09:16 +00008774 union node *new;
Eric Andersencb57d552001-06-28 07:25:16 +00008775
8776 if (n == NULL)
8777 return NULL;
8778 new = funcblock;
8779 funcblock = (char *) funcblock + nodesize[n->type];
8780 switch (n->type) {
8781 case NSEMI:
8782 case NAND:
8783 case NOR:
8784 case NWHILE:
8785 case NUNTIL:
8786 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8787 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8788 break;
8789 case NCMD:
8790 new->ncmd.redirect = copynode(n->ncmd.redirect);
8791 new->ncmd.args = copynode(n->ncmd.args);
8792 new->ncmd.assign = copynode(n->ncmd.assign);
8793 new->ncmd.backgnd = n->ncmd.backgnd;
8794 break;
8795 case NPIPE:
8796 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8797 new->npipe.backgnd = n->npipe.backgnd;
8798 break;
8799 case NREDIR:
8800 case NBACKGND:
8801 case NSUBSHELL:
8802 new->nredir.redirect = copynode(n->nredir.redirect);
8803 new->nredir.n = copynode(n->nredir.n);
8804 break;
8805 case NIF:
8806 new->nif.elsepart = copynode(n->nif.elsepart);
8807 new->nif.ifpart = copynode(n->nif.ifpart);
8808 new->nif.test = copynode(n->nif.test);
8809 break;
8810 case NFOR:
8811 new->nfor.var = nodesavestr(n->nfor.var);
8812 new->nfor.body = copynode(n->nfor.body);
8813 new->nfor.args = copynode(n->nfor.args);
8814 break;
8815 case NCASE:
8816 new->ncase.cases = copynode(n->ncase.cases);
8817 new->ncase.expr = copynode(n->ncase.expr);
8818 break;
8819 case NCLIST:
8820 new->nclist.body = copynode(n->nclist.body);
8821 new->nclist.pattern = copynode(n->nclist.pattern);
8822 new->nclist.next = copynode(n->nclist.next);
8823 break;
8824 case NDEFUN:
8825 case NARG:
8826 new->narg.backquote = copynodelist(n->narg.backquote);
8827 new->narg.text = nodesavestr(n->narg.text);
8828 new->narg.next = copynode(n->narg.next);
8829 break;
8830 case NTO:
8831 case NFROM:
8832 case NFROMTO:
8833 case NAPPEND:
8834 case NTOOV:
8835 new->nfile.fname = copynode(n->nfile.fname);
8836 new->nfile.fd = n->nfile.fd;
8837 new->nfile.next = copynode(n->nfile.next);
8838 break;
8839 case NTOFD:
8840 case NFROMFD:
8841 new->ndup.vname = copynode(n->ndup.vname);
8842 new->ndup.dupfd = n->ndup.dupfd;
8843 new->ndup.fd = n->ndup.fd;
8844 new->ndup.next = copynode(n->ndup.next);
8845 break;
8846 case NHERE:
8847 case NXHERE:
8848 new->nhere.doc = copynode(n->nhere.doc);
8849 new->nhere.fd = n->nhere.fd;
8850 new->nhere.next = copynode(n->nhere.next);
8851 break;
8852 case NNOT:
8853 new->nnot.com = copynode(n->nnot.com);
8854 break;
8855 };
8856 new->type = n->type;
Eric Andersen62483552001-07-10 06:09:16 +00008857 return new;
Eric Andersencb57d552001-06-28 07:25:16 +00008858}
8859
8860
8861static struct nodelist *
Eric Andersen62483552001-07-10 06:09:16 +00008862copynodelist(const struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008863{
8864 struct nodelist *start;
8865 struct nodelist **lpp;
8866
8867 lpp = &start;
8868 while (lp) {
8869 *lpp = funcblock;
8870 funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist));
8871 (*lpp)->n = copynode(lp->n);
8872 lp = lp->next;
8873 lpp = &(*lpp)->next;
8874 }
8875 *lpp = NULL;
8876 return start;
8877}
8878
8879
Eric Andersencb57d552001-06-28 07:25:16 +00008880static char *
Eric Andersen62483552001-07-10 06:09:16 +00008881nodesavestr(const char *s)
Eric Andersencb57d552001-06-28 07:25:16 +00008882{
8883#ifdef _GNU_SOURCE
8884 char *rtn = funcstring;
8885
8886 funcstring = stpcpy(funcstring, s) + 1;
8887 return rtn;
8888#else
Eric Andersen62483552001-07-10 06:09:16 +00008889 const char *p = s;
8890 char *q = funcstring;
Eric Andersencb57d552001-06-28 07:25:16 +00008891 char *rtn = funcstring;
8892
8893 while ((*q++ = *p++) != '\0')
8894 continue;
8895 funcstring = q;
8896 return rtn;
8897#endif
8898}
8899
Eric Andersencb57d552001-06-28 07:25:16 +00008900#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00008901static int getopts (char *, char *, char **, int *, int *);
Eric Andersencb57d552001-06-28 07:25:16 +00008902#endif
8903
8904
8905/*
8906 * Process the shell command line arguments.
8907 */
8908
8909static void
8910procargs(argc, argv)
8911 int argc;
8912 char **argv;
8913{
8914 int i;
8915
8916 argptr = argv;
8917 if (argc > 0)
8918 argptr++;
8919 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00008920 optent_val(i) = 2;
Eric Andersencb57d552001-06-28 07:25:16 +00008921 options(1);
8922 if (*argptr == NULL && minusc == NULL)
8923 sflag = 1;
8924 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8925 iflag = 1;
8926 if (mflag == 2)
8927 mflag = iflag;
8928 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00008929 if (optent_val(i) == 2)
8930 optent_val(i) = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008931 arg0 = argv[0];
8932 if (sflag == 0 && minusc == NULL) {
8933 commandname = argv[0];
8934 arg0 = *argptr++;
8935 setinputfile(arg0, 0);
8936 commandname = arg0;
8937 }
8938 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8939 if (argptr && minusc && *argptr)
Eric Andersen2870d962001-07-02 17:27:21 +00008940 arg0 = *argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00008941
8942 shellparam.p = argptr;
8943 shellparam.optind = 1;
8944 shellparam.optoff = -1;
8945 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8946 while (*argptr) {
8947 shellparam.nparam++;
8948 argptr++;
8949 }
8950 optschanged();
8951}
8952
8953
Eric Andersencb57d552001-06-28 07:25:16 +00008954
8955/*
8956 * Process shell options. The global variable argptr contains a pointer
8957 * to the argument list; we advance it past the options.
8958 */
8959
Eric Andersen62483552001-07-10 06:09:16 +00008960static inline void
8961minus_o(const char *name, int val)
8962{
8963 int i;
8964
8965 if (name == NULL) {
8966 out1str("Current option settings\n");
8967 for (i = 0; i < NOPTS; i++)
8968 printf("%-16s%s\n", optent_name(optlist[i]),
8969 optent_val(i) ? "on" : "off");
8970 } else {
8971 for (i = 0; i < NOPTS; i++)
8972 if (equal(name, optent_name(optlist[i]))) {
8973 setoption(optent_letter(optlist[i]), val);
8974 return;
8975 }
8976 error("Illegal option -o %s", name);
8977 }
8978}
8979
8980
Eric Andersencb57d552001-06-28 07:25:16 +00008981static void
Eric Andersen62483552001-07-10 06:09:16 +00008982options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00008983{
8984 char *p;
8985 int val;
8986 int c;
8987
8988 if (cmdline)
8989 minusc = NULL;
8990 while ((p = *argptr) != NULL) {
8991 argptr++;
8992 if ((c = *p++) == '-') {
8993 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00008994 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8995 if (!cmdline) {
8996 /* "-" means turn off -x and -v */
8997 if (p[0] == '\0')
8998 xflag = vflag = 0;
8999 /* "--" means reset params */
9000 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00009001 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00009002 }
9003 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00009004 }
9005 } else if (c == '+') {
9006 val = 0;
9007 } else {
9008 argptr--;
9009 break;
9010 }
9011 while ((c = *p++) != '\0') {
9012 if (c == 'c' && cmdline) {
9013 char *q;
Eric Andersen2870d962001-07-02 17:27:21 +00009014#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */
Eric Andersencb57d552001-06-28 07:25:16 +00009015 if (*p == '\0')
9016#endif
9017 q = *argptr++;
9018 if (q == NULL || minusc != NULL)
9019 error("Bad -c option");
9020 minusc = q;
9021#ifdef NOHACK
9022 break;
9023#endif
9024 } else if (c == 'o') {
9025 minus_o(*argptr, val);
9026 if (*argptr)
9027 argptr++;
9028 } else {
9029 setoption(c, val);
9030 }
9031 }
9032 }
9033}
9034
Eric Andersencb57d552001-06-28 07:25:16 +00009035
9036static void
Eric Andersen2870d962001-07-02 17:27:21 +00009037setoption(int flag, int val)
9038{
Eric Andersencb57d552001-06-28 07:25:16 +00009039 int i;
9040
9041 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009042 if (optent_letter(optlist[i]) == flag) {
9043 optent_val(i) = val;
Eric Andersencb57d552001-06-28 07:25:16 +00009044 if (val) {
9045 /* #%$ hack for ksh semantics */
9046 if (flag == 'V')
9047 Eflag = 0;
9048 else if (flag == 'E')
9049 Vflag = 0;
9050 }
9051 return;
9052 }
9053 error("Illegal option -%c", flag);
9054 /* NOTREACHED */
9055}
9056
9057
9058
Eric Andersencb57d552001-06-28 07:25:16 +00009059/*
9060 * Set the shell parameters.
9061 */
9062
9063static void
Eric Andersen2870d962001-07-02 17:27:21 +00009064setparam(char **argv)
9065{
Eric Andersencb57d552001-06-28 07:25:16 +00009066 char **newparam;
9067 char **ap;
9068 int nparam;
9069
9070 for (nparam = 0 ; argv[nparam] ; nparam++);
9071 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
9072 while (*argv) {
9073 *ap++ = savestr(*argv++);
9074 }
9075 *ap = NULL;
9076 freeparam(&shellparam);
9077 shellparam.malloc = 1;
9078 shellparam.nparam = nparam;
9079 shellparam.p = newparam;
9080 shellparam.optind = 1;
9081 shellparam.optoff = -1;
9082}
9083
9084
9085/*
9086 * Free the list of positional parameters.
9087 */
9088
9089static void
Eric Andersen2870d962001-07-02 17:27:21 +00009090freeparam(volatile struct shparam *param)
9091{
Eric Andersencb57d552001-06-28 07:25:16 +00009092 char **ap;
9093
9094 if (param->malloc) {
9095 for (ap = param->p ; *ap ; ap++)
9096 ckfree(*ap);
9097 ckfree(param->p);
9098 }
9099}
9100
9101
9102
9103/*
9104 * The shift builtin command.
9105 */
9106
9107static int
9108shiftcmd(argc, argv)
9109 int argc;
9110 char **argv;
9111{
9112 int n;
9113 char **ap1, **ap2;
9114
9115 n = 1;
9116 if (argc > 1)
9117 n = number(argv[1]);
9118 if (n > shellparam.nparam)
9119 error("can't shift that many");
9120 INTOFF;
9121 shellparam.nparam -= n;
9122 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
9123 if (shellparam.malloc)
9124 ckfree(*ap1);
9125 }
9126 ap2 = shellparam.p;
9127 while ((*ap2++ = *ap1++) != NULL);
9128 shellparam.optind = 1;
9129 shellparam.optoff = -1;
9130 INTON;
9131 return 0;
9132}
9133
9134
9135
9136/*
9137 * The set command builtin.
9138 */
9139
9140static int
9141setcmd(argc, argv)
9142 int argc;
9143 char **argv;
9144{
9145 if (argc == 1)
9146 return showvarscmd(argc, argv);
9147 INTOFF;
9148 options(0);
9149 optschanged();
9150 if (*argptr != NULL) {
9151 setparam(argptr);
9152 }
9153 INTON;
9154 return 0;
9155}
9156
9157
9158static void
Eric Andersen2870d962001-07-02 17:27:21 +00009159getoptsreset(const char *value)
Eric Andersencb57d552001-06-28 07:25:16 +00009160{
9161 shellparam.optind = number(value);
9162 shellparam.optoff = -1;
9163}
9164
Eric Andersen2870d962001-07-02 17:27:21 +00009165#ifdef BB_LOCALE_SUPPORT
9166static void change_lc_all(const char *value)
9167{
9168 if(value != 0 && *value != 0)
9169 setlocale(LC_ALL, value);
9170}
9171
9172static void change_lc_ctype(const char *value)
9173{
9174 if(value != 0 && *value != 0)
9175 setlocale(LC_CTYPE, value);
9176}
9177
9178#endif
9179
Eric Andersencb57d552001-06-28 07:25:16 +00009180#ifdef ASH_GETOPTS
9181/*
9182 * The getopts builtin. Shellparam.optnext points to the next argument
9183 * to be processed. Shellparam.optptr points to the next character to
9184 * be processed in the current argument. If shellparam.optnext is NULL,
9185 * then it's the first time getopts has been called.
9186 */
9187
9188static int
9189getoptscmd(argc, argv)
9190 int argc;
9191 char **argv;
9192{
9193 char **optbase;
9194
9195 if (argc < 3)
9196 error("Usage: getopts optstring var [arg]");
9197 else if (argc == 3) {
9198 optbase = shellparam.p;
9199 if (shellparam.optind > shellparam.nparam + 1) {
9200 shellparam.optind = 1;
9201 shellparam.optoff = -1;
9202 }
9203 }
9204 else {
9205 optbase = &argv[3];
9206 if (shellparam.optind > argc - 2) {
9207 shellparam.optind = 1;
9208 shellparam.optoff = -1;
9209 }
9210 }
9211
9212 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9213 &shellparam.optoff);
9214}
9215
9216/*
9217 * Safe version of setvar, returns 1 on success 0 on failure.
9218 */
9219
9220static int
9221setvarsafe(name, val, flags)
9222 const char *name, *val;
9223 int flags;
9224{
9225 struct jmploc jmploc;
9226 struct jmploc *volatile savehandler = handler;
9227 int err = 0;
9228#ifdef __GNUC__
9229 (void) &err;
9230#endif
9231
9232 if (setjmp(jmploc.loc))
9233 err = 1;
9234 else {
9235 handler = &jmploc;
9236 setvar(name, val, flags);
9237 }
9238 handler = savehandler;
9239 return err;
9240}
9241
9242static int
9243getopts(optstr, optvar, optfirst, myoptind, optoff)
9244 char *optstr;
9245 char *optvar;
9246 char **optfirst;
9247 int *myoptind;
9248 int *optoff;
9249{
9250 char *p, *q;
9251 char c = '?';
9252 int done = 0;
9253 int err = 0;
9254 char s[10];
9255 char **optnext = optfirst + *myoptind - 1;
9256
9257 if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
9258 strlen(*(optnext - 1)) < *optoff)
9259 p = NULL;
9260 else
9261 p = *(optnext - 1) + *optoff;
9262 if (p == NULL || *p == '\0') {
9263 /* Current word is done, advance */
9264 if (optnext == NULL)
9265 return 1;
9266 p = *optnext;
9267 if (p == NULL || *p != '-' || *++p == '\0') {
9268atend:
9269 *myoptind = optnext - optfirst + 1;
9270 p = NULL;
9271 done = 1;
9272 goto out;
9273 }
9274 optnext++;
Eric Andersen2870d962001-07-02 17:27:21 +00009275 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009276 goto atend;
9277 }
9278
9279 c = *p++;
9280 for (q = optstr; *q != c; ) {
9281 if (*q == '\0') {
9282 if (optstr[0] == ':') {
9283 s[0] = c;
9284 s[1] = '\0';
9285 err |= setvarsafe("OPTARG", s, 0);
9286 }
9287 else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009288 out2fmt("Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009289 (void) unsetvar("OPTARG");
9290 }
9291 c = '?';
9292 goto bad;
9293 }
9294 if (*++q == ':')
9295 q++;
9296 }
9297
9298 if (*++q == ':') {
9299 if (*p == '\0' && (p = *optnext) == NULL) {
9300 if (optstr[0] == ':') {
9301 s[0] = c;
9302 s[1] = '\0';
9303 err |= setvarsafe("OPTARG", s, 0);
9304 c = ':';
9305 }
9306 else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009307 out2fmt("No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009308 (void) unsetvar("OPTARG");
9309 c = '?';
9310 }
9311 goto bad;
9312 }
9313
9314 if (p == *optnext)
9315 optnext++;
9316 setvarsafe("OPTARG", p, 0);
9317 p = NULL;
9318 }
9319 else
9320 setvarsafe("OPTARG", "", 0);
9321 *myoptind = optnext - optfirst + 1;
9322 goto out;
9323
9324bad:
9325 *myoptind = 1;
9326 p = NULL;
9327out:
9328 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersen3102ac42001-07-06 04:26:23 +00009329 snprintf(s, sizeof(s), "%d", *myoptind);
Eric Andersencb57d552001-06-28 07:25:16 +00009330 err |= setvarsafe("OPTIND", s, VNOFUNC);
9331 s[0] = c;
9332 s[1] = '\0';
9333 err |= setvarsafe(optvar, s, 0);
9334 if (err) {
9335 *myoptind = 1;
9336 *optoff = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00009337 exraise(EXERROR);
9338 }
9339 return done;
9340}
Eric Andersen2870d962001-07-02 17:27:21 +00009341#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009342
9343/*
9344 * XXX - should get rid of. have all builtins use getopt(3). the
9345 * library getopt must have the BSD extension static variable "optreset"
9346 * otherwise it can't be used within the shell safely.
9347 *
9348 * Standard option processing (a la getopt) for builtin routines. The
9349 * only argument that is passed to nextopt is the option string; the
9350 * other arguments are unnecessary. It return the character, or '\0' on
9351 * end of input.
9352 */
9353
9354static int
Eric Andersen62483552001-07-10 06:09:16 +00009355nextopt(const char *optstring)
9356{
Eric Andersencb57d552001-06-28 07:25:16 +00009357 char *p;
9358 const char *q;
9359 char c;
9360
9361 if ((p = optptr) == NULL || *p == '\0') {
9362 p = *argptr;
9363 if (p == NULL || *p != '-' || *++p == '\0')
9364 return '\0';
9365 argptr++;
Eric Andersen2870d962001-07-02 17:27:21 +00009366 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009367 return '\0';
9368 }
9369 c = *p++;
9370 for (q = optstring ; *q != c ; ) {
9371 if (*q == '\0')
9372 error("Illegal option -%c", c);
9373 if (*++q == ':')
9374 q++;
9375 }
9376 if (*++q == ':') {
9377 if (*p == '\0' && (p = *argptr++) == NULL)
9378 error("No arg for -%c option", c);
9379 optionarg = p;
9380 p = NULL;
9381 }
9382 optptr = p;
9383 return c;
9384}
9385
Eric Andersencb57d552001-06-28 07:25:16 +00009386static void
9387flushall() {
Eric Andersencb57d552001-06-28 07:25:16 +00009388 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009389 fflush(stdout);
Eric Andersencb57d552001-06-28 07:25:16 +00009390 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009391}
9392
9393
9394static void
Eric Andersen3102ac42001-07-06 04:26:23 +00009395out2fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009396{
9397 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00009398 va_start(ap, fmt);
Eric Andersen3102ac42001-07-06 04:26:23 +00009399 vfprintf(stderr, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009400 va_end(ap);
9401}
9402
Eric Andersencb57d552001-06-28 07:25:16 +00009403/*
9404 * Version of write which resumes after a signal is caught.
9405 */
9406
9407static int
Eric Andersen2870d962001-07-02 17:27:21 +00009408xwrite(int fd, const char *buf, int nbytes)
9409{
Eric Andersencb57d552001-06-28 07:25:16 +00009410 int ntry;
9411 int i;
9412 int n;
9413
9414 n = nbytes;
9415 ntry = 0;
9416 for (;;) {
9417 i = write(fd, buf, n);
9418 if (i > 0) {
9419 if ((n -= i) <= 0)
9420 return nbytes;
9421 buf += i;
9422 ntry = 0;
9423 } else if (i == 0) {
9424 if (++ntry > 10)
9425 return nbytes - n;
9426 } else if (errno != EINTR) {
9427 return -1;
9428 }
9429 }
9430}
9431
9432
Eric Andersencb57d552001-06-28 07:25:16 +00009433/*
9434 * Shell command parser.
9435 */
9436
9437#define EOFMARKLEN 79
9438
9439
9440
9441struct heredoc {
Eric Andersen2870d962001-07-02 17:27:21 +00009442 struct heredoc *next; /* next here document in list */
9443 union node *here; /* redirection node */
9444 char *eofmark; /* string indicating end of input */
9445 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009446};
9447
Eric Andersen2870d962001-07-02 17:27:21 +00009448static struct heredoc *heredoclist; /* list of here documents to read */
9449static int parsebackquote; /* nonzero if we are inside backquotes */
9450static int doprompt; /* if set, prompt the user */
9451static int needprompt; /* true if interactive and at start of line */
9452static int lasttoken; /* last token read */
Eric Andersencb57d552001-06-28 07:25:16 +00009453
Eric Andersen2870d962001-07-02 17:27:21 +00009454static char *wordtext; /* text of last word returned by readtoken */
Eric Andersencb57d552001-06-28 07:25:16 +00009455
Eric Andersen2870d962001-07-02 17:27:21 +00009456static struct nodelist *backquotelist;
9457static union node *redirnode;
Eric Andersencb57d552001-06-28 07:25:16 +00009458struct heredoc *heredoc;
Eric Andersen2870d962001-07-02 17:27:21 +00009459static int quoteflag; /* set if (part of) last token was quoted */
9460static int startlinno; /* line # where last token started */
Eric Andersencb57d552001-06-28 07:25:16 +00009461
9462
Eric Andersen2870d962001-07-02 17:27:21 +00009463static union node *list (int);
9464static union node *andor (void);
9465static union node *pipeline (void);
9466static union node *command (void);
9467static union node *simplecmd (void);
9468static void parsefname (void);
9469static void parseheredoc (void);
9470static int peektoken (void);
9471static int readtoken (void);
9472static int xxreadtoken (void);
9473static int readtoken1 (int, char const *, char *, int);
9474static int noexpand (char *);
9475static void synexpect (int) __attribute__((noreturn));
9476static void synerror (const char *) __attribute__((noreturn));
9477static void setprompt (int);
Eric Andersencb57d552001-06-28 07:25:16 +00009478
9479
9480/*
9481 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9482 * valid parse tree indicating a blank line.)
9483 */
9484
Eric Andersen2870d962001-07-02 17:27:21 +00009485static union node *
Eric Andersencb57d552001-06-28 07:25:16 +00009486parsecmd(int interact)
9487{
9488 int t;
9489
9490 tokpushback = 0;
9491 doprompt = interact;
9492 if (doprompt)
9493 setprompt(1);
9494 else
9495 setprompt(0);
9496 needprompt = 0;
9497 t = readtoken();
9498 if (t == TEOF)
9499 return NEOF;
9500 if (t == TNL)
9501 return NULL;
9502 tokpushback++;
9503 return list(1);
9504}
9505
9506
9507static union node *
9508list(nlflag)
9509 int nlflag;
9510{
9511 union node *n1, *n2, *n3;
9512 int tok;
9513
9514 checkkwd = 2;
9515 if (nlflag == 0 && tokendlist[peektoken()])
9516 return NULL;
9517 n1 = NULL;
9518 for (;;) {
9519 n2 = andor();
9520 tok = readtoken();
9521 if (tok == TBACKGND) {
9522 if (n2->type == NCMD || n2->type == NPIPE) {
9523 n2->ncmd.backgnd = 1;
9524 } else if (n2->type == NREDIR) {
9525 n2->type = NBACKGND;
9526 } else {
9527 n3 = (union node *)stalloc(sizeof (struct nredir));
9528 n3->type = NBACKGND;
9529 n3->nredir.n = n2;
9530 n3->nredir.redirect = NULL;
9531 n2 = n3;
9532 }
9533 }
9534 if (n1 == NULL) {
9535 n1 = n2;
9536 }
9537 else {
9538 n3 = (union node *)stalloc(sizeof (struct nbinary));
9539 n3->type = NSEMI;
9540 n3->nbinary.ch1 = n1;
9541 n3->nbinary.ch2 = n2;
9542 n1 = n3;
9543 }
9544 switch (tok) {
9545 case TBACKGND:
9546 case TSEMI:
9547 tok = readtoken();
9548 /* fall through */
9549 case TNL:
9550 if (tok == TNL) {
9551 parseheredoc();
9552 if (nlflag)
9553 return n1;
9554 } else {
9555 tokpushback++;
9556 }
9557 checkkwd = 2;
9558 if (tokendlist[peektoken()])
9559 return n1;
9560 break;
9561 case TEOF:
9562 if (heredoclist)
9563 parseheredoc();
9564 else
Eric Andersen2870d962001-07-02 17:27:21 +00009565 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009566 return n1;
9567 default:
9568 if (nlflag)
9569 synexpect(-1);
9570 tokpushback++;
9571 return n1;
9572 }
9573 }
9574}
9575
9576
9577
9578static union node *
9579andor() {
9580 union node *n1, *n2, *n3;
9581 int t;
9582
9583 checkkwd = 1;
9584 n1 = pipeline();
9585 for (;;) {
9586 if ((t = readtoken()) == TAND) {
9587 t = NAND;
9588 } else if (t == TOR) {
9589 t = NOR;
9590 } else {
9591 tokpushback++;
9592 return n1;
9593 }
9594 checkkwd = 2;
9595 n2 = pipeline();
9596 n3 = (union node *)stalloc(sizeof (struct nbinary));
9597 n3->type = t;
9598 n3->nbinary.ch1 = n1;
9599 n3->nbinary.ch2 = n2;
9600 n1 = n3;
9601 }
9602}
9603
9604
9605
9606static union node *
9607pipeline() {
9608 union node *n1, *n2, *pipenode;
9609 struct nodelist *lp, *prev;
9610 int negate;
9611
9612 negate = 0;
9613 TRACE(("pipeline: entered\n"));
9614 if (readtoken() == TNOT) {
9615 negate = !negate;
9616 checkkwd = 1;
9617 } else
9618 tokpushback++;
9619 n1 = command();
9620 if (readtoken() == TPIPE) {
9621 pipenode = (union node *)stalloc(sizeof (struct npipe));
9622 pipenode->type = NPIPE;
9623 pipenode->npipe.backgnd = 0;
9624 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9625 pipenode->npipe.cmdlist = lp;
9626 lp->n = n1;
9627 do {
9628 prev = lp;
9629 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9630 checkkwd = 2;
9631 lp->n = command();
9632 prev->next = lp;
9633 } while (readtoken() == TPIPE);
9634 lp->next = NULL;
9635 n1 = pipenode;
9636 }
9637 tokpushback++;
9638 if (negate) {
9639 n2 = (union node *)stalloc(sizeof (struct nnot));
9640 n2->type = NNOT;
9641 n2->nnot.com = n1;
9642 return n2;
9643 } else
9644 return n1;
9645}
9646
9647
9648
9649static union node *
9650command() {
9651 union node *n1, *n2;
9652 union node *ap, **app;
9653 union node *cp, **cpp;
9654 union node *redir, **rpp;
9655 int t;
9656
9657 redir = NULL;
9658 n1 = NULL;
9659 rpp = &redir;
9660
9661 switch (readtoken()) {
9662 case TIF:
9663 n1 = (union node *)stalloc(sizeof (struct nif));
9664 n1->type = NIF;
9665 n1->nif.test = list(0);
9666 if (readtoken() != TTHEN)
9667 synexpect(TTHEN);
9668 n1->nif.ifpart = list(0);
9669 n2 = n1;
9670 while (readtoken() == TELIF) {
9671 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9672 n2 = n2->nif.elsepart;
9673 n2->type = NIF;
9674 n2->nif.test = list(0);
9675 if (readtoken() != TTHEN)
9676 synexpect(TTHEN);
9677 n2->nif.ifpart = list(0);
9678 }
9679 if (lasttoken == TELSE)
9680 n2->nif.elsepart = list(0);
9681 else {
9682 n2->nif.elsepart = NULL;
9683 tokpushback++;
9684 }
9685 if (readtoken() != TFI)
9686 synexpect(TFI);
9687 checkkwd = 1;
9688 break;
9689 case TWHILE:
9690 case TUNTIL: {
9691 int got;
9692 n1 = (union node *)stalloc(sizeof (struct nbinary));
9693 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9694 n1->nbinary.ch1 = list(0);
9695 if ((got=readtoken()) != TDO) {
9696TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
9697 synexpect(TDO);
9698 }
9699 n1->nbinary.ch2 = list(0);
9700 if (readtoken() != TDONE)
9701 synexpect(TDONE);
9702 checkkwd = 1;
9703 break;
9704 }
9705 case TFOR:
9706 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9707 synerror("Bad for loop variable");
9708 n1 = (union node *)stalloc(sizeof (struct nfor));
9709 n1->type = NFOR;
9710 n1->nfor.var = wordtext;
9711 checkkwd = 1;
9712 if (readtoken() == TIN) {
9713 app = &ap;
9714 while (readtoken() == TWORD) {
9715 n2 = (union node *)stalloc(sizeof (struct narg));
9716 n2->type = NARG;
9717 n2->narg.text = wordtext;
9718 n2->narg.backquote = backquotelist;
9719 *app = n2;
9720 app = &n2->narg.next;
9721 }
9722 *app = NULL;
9723 n1->nfor.args = ap;
9724 if (lasttoken != TNL && lasttoken != TSEMI)
9725 synexpect(-1);
9726 } else {
9727 static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
9728 '@', '=', '\0'};
9729 n2 = (union node *)stalloc(sizeof (struct narg));
9730 n2->type = NARG;
9731 n2->narg.text = argvars;
9732 n2->narg.backquote = NULL;
9733 n2->narg.next = NULL;
9734 n1->nfor.args = n2;
9735 /*
9736 * Newline or semicolon here is optional (but note
9737 * that the original Bourne shell only allowed NL).
9738 */
9739 if (lasttoken != TNL && lasttoken != TSEMI)
9740 tokpushback++;
9741 }
9742 checkkwd = 2;
9743 if (readtoken() != TDO)
9744 synexpect(TDO);
9745 n1->nfor.body = list(0);
9746 if (readtoken() != TDONE)
9747 synexpect(TDONE);
9748 checkkwd = 1;
9749 break;
9750 case TCASE:
9751 n1 = (union node *)stalloc(sizeof (struct ncase));
9752 n1->type = NCASE;
9753 if (readtoken() != TWORD)
9754 synexpect(TWORD);
9755 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9756 n2->type = NARG;
9757 n2->narg.text = wordtext;
9758 n2->narg.backquote = backquotelist;
9759 n2->narg.next = NULL;
9760 do {
9761 checkkwd = 1;
9762 } while (readtoken() == TNL);
9763 if (lasttoken != TIN)
9764 synerror("expecting \"in\"");
9765 cpp = &n1->ncase.cases;
9766 checkkwd = 2, readtoken();
9767 do {
9768 if (lasttoken == TLP)
9769 readtoken();
9770 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9771 cp->type = NCLIST;
9772 app = &cp->nclist.pattern;
9773 for (;;) {
9774 *app = ap = (union node *)stalloc(sizeof (struct narg));
9775 ap->type = NARG;
9776 ap->narg.text = wordtext;
9777 ap->narg.backquote = backquotelist;
9778 if (checkkwd = 2, readtoken() != TPIPE)
9779 break;
9780 app = &ap->narg.next;
9781 readtoken();
9782 }
9783 ap->narg.next = NULL;
9784 if (lasttoken != TRP)
9785 synexpect(TRP);
9786 cp->nclist.body = list(0);
9787
9788 checkkwd = 2;
9789 if ((t = readtoken()) != TESAC) {
9790 if (t != TENDCASE)
9791 synexpect(TENDCASE);
9792 else
9793 checkkwd = 2, readtoken();
9794 }
9795 cpp = &cp->nclist.next;
9796 } while(lasttoken != TESAC);
9797 *cpp = NULL;
9798 checkkwd = 1;
9799 break;
9800 case TLP:
9801 n1 = (union node *)stalloc(sizeof (struct nredir));
9802 n1->type = NSUBSHELL;
9803 n1->nredir.n = list(0);
9804 n1->nredir.redirect = NULL;
9805 if (readtoken() != TRP)
9806 synexpect(TRP);
9807 checkkwd = 1;
9808 break;
9809 case TBEGIN:
9810 n1 = list(0);
9811 if (readtoken() != TEND)
9812 synexpect(TEND);
9813 checkkwd = 1;
9814 break;
9815 /* Handle an empty command like other simple commands. */
9816 case TSEMI:
9817 case TAND:
9818 case TOR:
9819 case TNL:
9820 case TEOF:
9821 case TRP:
9822 case TBACKGND:
9823 /*
9824 * An empty command before a ; doesn't make much sense, and
9825 * should certainly be disallowed in the case of `if ;'.
9826 */
9827 if (!redir)
9828 synexpect(-1);
9829 case TWORD:
9830 case TREDIR:
9831 tokpushback++;
9832 n1 = simplecmd();
9833 return n1;
9834 default:
9835 synexpect(-1);
9836 /* NOTREACHED */
9837 }
9838
9839 /* Now check for redirection which may follow command */
9840 while (readtoken() == TREDIR) {
9841 *rpp = n2 = redirnode;
9842 rpp = &n2->nfile.next;
9843 parsefname();
9844 }
9845 tokpushback++;
9846 *rpp = NULL;
9847 if (redir) {
9848 if (n1->type != NSUBSHELL) {
9849 n2 = (union node *)stalloc(sizeof (struct nredir));
9850 n2->type = NREDIR;
9851 n2->nredir.n = n1;
9852 n1 = n2;
9853 }
9854 n1->nredir.redirect = redir;
9855 }
9856
9857 return n1;
9858}
9859
9860
9861static union node *
9862simplecmd() {
9863 union node *args, **app;
9864 union node *n = NULL;
9865 union node *vars, **vpp;
9866 union node **rpp, *redir;
9867
9868 args = NULL;
9869 app = &args;
9870 vars = NULL;
9871 vpp = &vars;
9872 redir = NULL;
9873 rpp = &redir;
9874
Eric Andersen2870d962001-07-02 17:27:21 +00009875#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00009876 checkalias = 2;
Eric Andersen2870d962001-07-02 17:27:21 +00009877#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009878 for (;;) {
9879 switch (readtoken()) {
9880 case TWORD:
9881 case TASSIGN:
9882 n = (union node *)stalloc(sizeof (struct narg));
9883 n->type = NARG;
9884 n->narg.text = wordtext;
9885 n->narg.backquote = backquotelist;
9886 if (lasttoken == TWORD) {
9887 *app = n;
9888 app = &n->narg.next;
9889 } else {
9890 *vpp = n;
9891 vpp = &n->narg.next;
9892 }
9893 break;
9894 case TREDIR:
9895 *rpp = n = redirnode;
9896 rpp = &n->nfile.next;
Eric Andersen2870d962001-07-02 17:27:21 +00009897 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +00009898 break;
9899 case TLP:
9900 if (
9901 args && app == &args->narg.next &&
9902 !vars && !redir
9903 ) {
9904 /* We have a function */
9905 if (readtoken() != TRP)
9906 synexpect(TRP);
Eric Andersencb57d552001-06-28 07:25:16 +00009907 n->type = NDEFUN;
9908 checkkwd = 2;
9909 n->narg.next = command();
9910 return n;
9911 }
9912 /* fall through */
9913 default:
9914 tokpushback++;
9915 goto out;
9916 }
9917 }
9918out:
9919 *app = NULL;
9920 *vpp = NULL;
9921 *rpp = NULL;
9922 n = (union node *)stalloc(sizeof (struct ncmd));
9923 n->type = NCMD;
9924 n->ncmd.backgnd = 0;
9925 n->ncmd.args = args;
9926 n->ncmd.assign = vars;
9927 n->ncmd.redirect = redir;
9928 return n;
9929}
9930
9931static union node *
Eric Andersen2870d962001-07-02 17:27:21 +00009932makename(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009933 union node *n;
9934
9935 n = (union node *)stalloc(sizeof (struct narg));
9936 n->type = NARG;
9937 n->narg.next = NULL;
9938 n->narg.text = wordtext;
9939 n->narg.backquote = backquotelist;
9940 return n;
9941}
9942
9943static void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +00009944{
Eric Andersencb57d552001-06-28 07:25:16 +00009945 TRACE(("Fix redir %s %d\n", text, err));
9946 if (!err)
9947 n->ndup.vname = NULL;
9948
9949 if (is_digit(text[0]) && text[1] == '\0')
9950 n->ndup.dupfd = digit_val(text[0]);
9951 else if (text[0] == '-' && text[1] == '\0')
9952 n->ndup.dupfd = -1;
9953 else {
9954
9955 if (err)
9956 synerror("Bad fd number");
9957 else
9958 n->ndup.vname = makename();
9959 }
9960}
9961
9962
9963static void
Eric Andersen2870d962001-07-02 17:27:21 +00009964parsefname(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009965 union node *n = redirnode;
9966
9967 if (readtoken() != TWORD)
9968 synexpect(-1);
9969 if (n->type == NHERE) {
9970 struct heredoc *here = heredoc;
9971 struct heredoc *p;
9972 int i;
9973
9974 if (quoteflag == 0)
9975 n->type = NXHERE;
9976 TRACE(("Here document %d\n", n->type));
9977 if (here->striptabs) {
9978 while (*wordtext == '\t')
9979 wordtext++;
9980 }
9981 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9982 synerror("Illegal eof marker for << redirection");
9983 rmescapes(wordtext);
9984 here->eofmark = wordtext;
9985 here->next = NULL;
9986 if (heredoclist == NULL)
9987 heredoclist = here;
9988 else {
9989 for (p = heredoclist ; p->next ; p = p->next);
9990 p->next = here;
9991 }
9992 } else if (n->type == NTOFD || n->type == NFROMFD) {
9993 fixredir(n, wordtext, 0);
9994 } else {
9995 n->nfile.fname = makename();
9996 }
9997}
9998
9999
10000/*
10001 * Input any here documents.
10002 */
10003
10004static void
10005parseheredoc() {
10006 struct heredoc *here;
10007 union node *n;
10008
10009 while (heredoclist) {
10010 here = heredoclist;
10011 heredoclist = here->next;
10012 if (needprompt) {
10013 setprompt(2);
10014 needprompt = 0;
10015 }
10016 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
10017 here->eofmark, here->striptabs);
10018 n = (union node *)stalloc(sizeof (struct narg));
10019 n->narg.type = NARG;
10020 n->narg.next = NULL;
10021 n->narg.text = wordtext;
10022 n->narg.backquote = backquotelist;
10023 here->here->nhere.doc = n;
10024 }
10025}
10026
10027static int
10028peektoken() {
10029 int t;
10030
10031 t = readtoken();
10032 tokpushback++;
10033 return (t);
10034}
10035
10036static int
10037readtoken() {
10038 int t;
Eric Andersen2870d962001-07-02 17:27:21 +000010039#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010040 int savecheckkwd = checkkwd;
10041 int savecheckalias = checkalias;
10042 struct alias *ap;
Eric Andersen2870d962001-07-02 17:27:21 +000010043#endif
10044
Eric Andersencb57d552001-06-28 07:25:16 +000010045#ifdef DEBUG
10046 int alreadyseen = tokpushback;
10047#endif
10048
Eric Andersen2870d962001-07-02 17:27:21 +000010049#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010050top:
Eric Andersen2870d962001-07-02 17:27:21 +000010051#endif
10052
Eric Andersencb57d552001-06-28 07:25:16 +000010053 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +000010054
10055#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010056 checkalias = savecheckalias;
Eric Andersen2870d962001-07-02 17:27:21 +000010057#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010058
10059 if (checkkwd) {
10060 /*
10061 * eat newlines
10062 */
10063 if (checkkwd == 2) {
10064 checkkwd = 0;
10065 while (t == TNL) {
10066 parseheredoc();
10067 t = xxreadtoken();
10068 }
10069 }
10070 checkkwd = 0;
10071 /*
10072 * check for keywords
10073 */
10074 if (t == TWORD && !quoteflag)
10075 {
10076 const char *const *pp;
10077
10078 if ((pp = findkwd(wordtext))) {
10079 lasttoken = t = pp - parsekwd + KWDOFFSET;
10080 TRACE(("keyword %s recognized\n", tokname[t]));
10081 goto out;
10082 }
10083 }
10084 }
10085
Eric Andersen2870d962001-07-02 17:27:21 +000010086#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010087 if (t != TWORD) {
10088 if (t != TREDIR) {
10089 checkalias = 0;
10090 }
10091 } else if (checkalias == 2 && isassignment(wordtext)) {
10092 lasttoken = t = TASSIGN;
10093 } else if (checkalias) {
10094 if (!quoteflag && (ap = lookupalias(wordtext, 1)) != NULL) {
10095 if (*ap->val) {
10096 pushstring(ap->val, strlen(ap->val), ap);
10097 }
10098 checkkwd = savecheckkwd;
10099 goto top;
10100 }
10101 checkalias = 0;
10102 }
Eric Andersen2870d962001-07-02 17:27:21 +000010103#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010104out:
10105#ifdef DEBUG
10106 if (!alreadyseen)
10107 TRACE(("token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : ""));
10108 else
10109 TRACE(("reread token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : ""));
10110#endif
10111 return (t);
10112}
10113
10114
10115/*
10116 * Read the next input token.
10117 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +000010118 * backquotes. We set quoteflag to true if any part of the word was
10119 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +000010120 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +000010121 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +000010122 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +000010123 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +000010124 *
10125 * [Change comment: here documents and internal procedures]
10126 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10127 * word parsing code into a separate routine. In this case, readtoken
10128 * doesn't need to have any internal procedures, but parseword does.
10129 * We could also make parseoperator in essence the main routine, and
10130 * have parseword (readtoken1?) handle both words and redirection.]
10131 */
10132
Eric Andersen2870d962001-07-02 17:27:21 +000010133#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010134
10135static int
10136xxreadtoken() {
10137 int c;
10138
10139 if (tokpushback) {
10140 tokpushback = 0;
10141 return lasttoken;
10142 }
10143 if (needprompt) {
10144 setprompt(2);
10145 needprompt = 0;
10146 }
10147 startlinno = plinno;
Eric Andersen2870d962001-07-02 17:27:21 +000010148 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010149 c = pgetc_macro();
10150 switch (c) {
10151 case ' ': case '\t':
Eric Andersen3102ac42001-07-06 04:26:23 +000010152#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010153 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010154#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010155 continue;
10156 case '#':
10157 while ((c = pgetc()) != '\n' && c != PEOF);
10158 pungetc();
10159 continue;
10160 case '\\':
10161 if (pgetc() == '\n') {
10162 startlinno = ++plinno;
10163 if (doprompt)
10164 setprompt(2);
10165 else
10166 setprompt(0);
10167 continue;
10168 }
10169 pungetc();
10170 goto breakloop;
10171 case '\n':
10172 plinno++;
10173 needprompt = doprompt;
10174 RETURN(TNL);
10175 case PEOF:
10176 RETURN(TEOF);
10177 case '&':
10178 if (pgetc() == '&')
10179 RETURN(TAND);
10180 pungetc();
10181 RETURN(TBACKGND);
10182 case '|':
10183 if (pgetc() == '|')
10184 RETURN(TOR);
10185 pungetc();
10186 RETURN(TPIPE);
10187 case ';':
10188 if (pgetc() == ';')
10189 RETURN(TENDCASE);
10190 pungetc();
10191 RETURN(TSEMI);
10192 case '(':
10193 RETURN(TLP);
10194 case ')':
10195 RETURN(TRP);
10196 default:
10197 goto breakloop;
10198 }
10199 }
10200breakloop:
10201 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10202#undef RETURN
10203}
10204
10205
10206
10207/*
10208 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10209 * is not NULL, read a here document. In the latter case, eofmark is the
10210 * word which marks the end of the document and striptabs is true if
10211 * leading tabs should be stripped from the document. The argument firstc
10212 * is the first character of the input token or document.
10213 *
10214 * Because C does not have internal subroutines, I have simulated them
10215 * using goto's to implement the subroutine linkage. The following macros
10216 * will run code that appears at the end of readtoken1.
10217 */
10218
Eric Andersen2870d962001-07-02 17:27:21 +000010219#define CHECKEND() {goto checkend; checkend_return:;}
10220#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10221#define PARSESUB() {goto parsesub; parsesub_return:;}
10222#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10223#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10224#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010225
10226static int
10227readtoken1(firstc, syntax, eofmark, striptabs)
10228 int firstc;
10229 char const *syntax;
10230 char *eofmark;
10231 int striptabs;
10232 {
10233 int c = firstc;
10234 char *out;
10235 int len;
10236 char line[EOFMARKLEN + 1];
10237 struct nodelist *bqlist;
10238 int quotef;
10239 int dblquote;
Eric Andersen2870d962001-07-02 17:27:21 +000010240 int varnest; /* levels of variables expansion */
10241 int arinest; /* levels of arithmetic expansion */
10242 int parenlevel; /* levels of parens in arithmetic */
10243 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +000010244 int oldstyle;
Eric Andersen2870d962001-07-02 17:27:21 +000010245 char const *prevsyntax; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010246#if __GNUC__
10247 /* Avoid longjmp clobbering */
10248 (void) &out;
10249 (void) &quotef;
10250 (void) &dblquote;
10251 (void) &varnest;
10252 (void) &arinest;
10253 (void) &parenlevel;
10254 (void) &dqvarnest;
10255 (void) &oldstyle;
10256 (void) &prevsyntax;
10257 (void) &syntax;
10258#endif
10259
10260 startlinno = plinno;
10261 dblquote = 0;
10262 if (syntax == DQSYNTAX)
10263 dblquote = 1;
10264 quotef = 0;
10265 bqlist = NULL;
10266 varnest = 0;
10267 arinest = 0;
10268 parenlevel = 0;
10269 dqvarnest = 0;
10270
10271 STARTSTACKSTR(out);
Eric Andersen2870d962001-07-02 17:27:21 +000010272 loop: { /* for each line, until end of word */
10273 CHECKEND(); /* set c to PEOF if at end of here document */
10274 for (;;) { /* until end of line or end of word */
10275 CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
Eric Andersencb57d552001-06-28 07:25:16 +000010276 switch(syntax[c]) {
Eric Andersen2870d962001-07-02 17:27:21 +000010277 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010278 if (syntax == BASESYNTAX)
Eric Andersen2870d962001-07-02 17:27:21 +000010279 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010280 USTPUTC(c, out);
10281 plinno++;
10282 if (doprompt)
10283 setprompt(2);
10284 else
10285 setprompt(0);
10286 c = pgetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010287 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010288 case CWORD:
10289 USTPUTC(c, out);
10290 break;
10291 case CCTL:
10292 if ((eofmark == NULL || dblquote) &&
10293 dqvarnest == 0)
10294 USTPUTC(CTLESC, out);
10295 USTPUTC(c, out);
10296 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010297 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010298 c = pgetc2();
10299 if (c == PEOF) {
10300 USTPUTC('\\', out);
10301 pungetc();
10302 } else if (c == '\n') {
10303 if (doprompt)
10304 setprompt(2);
10305 else
10306 setprompt(0);
10307 } else {
10308 if (dblquote && c != '\\' && c != '`' && c != '$'
10309 && (c != '"' || eofmark != NULL))
10310 USTPUTC('\\', out);
10311 if (SQSYNTAX[c] == CCTL)
10312 USTPUTC(CTLESC, out);
10313 else if (eofmark == NULL)
10314 USTPUTC(CTLQUOTEMARK, out);
10315 USTPUTC(c, out);
10316 quotef++;
10317 }
10318 break;
10319 case CSQUOTE:
10320 if (eofmark == NULL)
10321 USTPUTC(CTLQUOTEMARK, out);
10322 syntax = SQSYNTAX;
10323 break;
10324 case CDQUOTE:
10325 if (eofmark == NULL)
10326 USTPUTC(CTLQUOTEMARK, out);
10327 syntax = DQSYNTAX;
10328 dblquote = 1;
10329 break;
10330 case CENDQUOTE:
10331 if (eofmark != NULL && arinest == 0 &&
10332 varnest == 0) {
10333 USTPUTC(c, out);
10334 } else {
10335 if (arinest) {
10336 syntax = ARISYNTAX;
10337 dblquote = 0;
10338 } else if (eofmark == NULL &&
10339 dqvarnest == 0) {
10340 syntax = BASESYNTAX;
10341 dblquote = 0;
10342 }
10343 quotef++;
10344 }
10345 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010346 case CVAR: /* '$' */
10347 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010348 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010349 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010350 if (varnest > 0) {
10351 varnest--;
10352 if (dqvarnest > 0) {
10353 dqvarnest--;
10354 }
10355 USTPUTC(CTLENDVAR, out);
10356 } else {
10357 USTPUTC(c, out);
10358 }
10359 break;
10360#ifdef ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +000010361 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010362 parenlevel++;
10363 USTPUTC(c, out);
10364 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010365 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010366 if (parenlevel > 0) {
10367 USTPUTC(c, out);
10368 --parenlevel;
10369 } else {
10370 if (pgetc() == ')') {
10371 if (--arinest == 0) {
10372 USTPUTC(CTLENDARI, out);
10373 syntax = prevsyntax;
10374 if (syntax == DQSYNTAX)
10375 dblquote = 1;
10376 else
10377 dblquote = 0;
10378 } else
10379 USTPUTC(')', out);
10380 } else {
10381 /*
10382 * unbalanced parens
10383 * (don't 2nd guess - no error)
10384 */
10385 pungetc();
10386 USTPUTC(')', out);
10387 }
10388 }
10389 break;
10390#endif
Eric Andersen2870d962001-07-02 17:27:21 +000010391 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010392 PARSEBACKQOLD();
10393 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010394 case CENDFILE:
10395 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010396 case CIGN:
10397 break;
10398 default:
10399 if (varnest == 0)
Eric Andersen2870d962001-07-02 17:27:21 +000010400 goto endword; /* exit outer loop */
Eric Andersen3102ac42001-07-06 04:26:23 +000010401#ifdef ASH_ALIAS
10402 if (c != PEOA)
10403#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010404 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010405
Eric Andersencb57d552001-06-28 07:25:16 +000010406 }
10407 c = pgetc_macro();
10408 }
10409 }
10410endword:
10411 if (syntax == ARISYNTAX)
10412 synerror("Missing '))'");
10413 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10414 synerror("Unterminated quoted string");
10415 if (varnest != 0) {
10416 startlinno = plinno;
10417 synerror("Missing '}'");
10418 }
10419 USTPUTC('\0', out);
10420 len = out - stackblock();
10421 out = stackblock();
10422 if (eofmark == NULL) {
10423 if ((c == '>' || c == '<')
10424 && quotef == 0
10425 && len <= 2
10426 && (*out == '\0' || is_digit(*out))) {
10427 PARSEREDIR();
10428 return lasttoken = TREDIR;
10429 } else {
10430 pungetc();
10431 }
10432 }
10433 quoteflag = quotef;
10434 backquotelist = bqlist;
10435 grabstackblock(len);
10436 wordtext = out;
10437 return lasttoken = TWORD;
10438/* end of readtoken routine */
10439
10440
10441
10442/*
10443 * Check to see whether we are at the end of the here document. When this
10444 * is called, c is set to the first character of the next input line. If
10445 * we are at the end of the here document, this routine sets the c to PEOF.
10446 */
10447
10448checkend: {
10449 if (eofmark) {
Eric Andersen2870d962001-07-02 17:27:21 +000010450#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010451 if (c == PEOA) {
10452 c = pgetc2();
10453 }
Eric Andersen2870d962001-07-02 17:27:21 +000010454#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010455 if (striptabs) {
10456 while (c == '\t') {
10457 c = pgetc2();
10458 }
10459 }
10460 if (c == *eofmark) {
10461 if (pfgets(line, sizeof line) != NULL) {
10462 char *p, *q;
10463
10464 p = line;
10465 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10466 if (*p == '\n' && *q == '\0') {
10467 c = PEOF;
10468 plinno++;
10469 needprompt = doprompt;
10470 } else {
10471 pushstring(line, strlen(line), NULL);
10472 }
10473 }
10474 }
10475 }
10476 goto checkend_return;
10477}
10478
10479
10480/*
10481 * Parse a redirection operator. The variable "out" points to a string
10482 * specifying the fd to be redirected. The variable "c" contains the
10483 * first character of the redirection operator.
10484 */
10485
10486parseredir: {
10487 char fd = *out;
10488 union node *np;
10489
10490 np = (union node *)stalloc(sizeof (struct nfile));
10491 if (c == '>') {
10492 np->nfile.fd = 1;
10493 c = pgetc();
10494 if (c == '>')
10495 np->type = NAPPEND;
10496 else if (c == '&')
10497 np->type = NTOFD;
10498 else if (c == '|')
10499 np->type = NTOOV;
10500 else {
10501 np->type = NTO;
10502 pungetc();
10503 }
Eric Andersen2870d962001-07-02 17:27:21 +000010504 } else { /* c == '<' */
Eric Andersencb57d552001-06-28 07:25:16 +000010505 np->nfile.fd = 0;
10506 switch (c = pgetc()) {
10507 case '<':
10508 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10509 np = (union node *)stalloc(sizeof (struct nhere));
10510 np->nfile.fd = 0;
10511 }
10512 np->type = NHERE;
10513 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10514 heredoc->here = np;
10515 if ((c = pgetc()) == '-') {
10516 heredoc->striptabs = 1;
10517 } else {
10518 heredoc->striptabs = 0;
10519 pungetc();
10520 }
10521 break;
10522
10523 case '&':
10524 np->type = NFROMFD;
10525 break;
10526
10527 case '>':
10528 np->type = NFROMTO;
10529 break;
10530
10531 default:
10532 np->type = NFROM;
10533 pungetc();
10534 break;
10535 }
10536 }
10537 if (fd != '\0')
10538 np->nfile.fd = digit_val(fd);
10539 redirnode = np;
10540 goto parseredir_return;
10541}
10542
10543
10544/*
10545 * Parse a substitution. At this point, we have read the dollar sign
10546 * and nothing else.
10547 */
10548
10549parsesub: {
10550 int subtype;
10551 int typeloc;
10552 int flags;
10553 char *p;
10554 static const char types[] = "}-+?=";
10555
10556 c = pgetc();
10557 if (
10558 c <= PEOA ||
10559 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10560 ) {
10561 USTPUTC('$', out);
10562 pungetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010563 } else if (c == '(') { /* $(command) or $((arith)) */
Eric Andersencb57d552001-06-28 07:25:16 +000010564 if (pgetc() == '(') {
10565 PARSEARITH();
10566 } else {
10567 pungetc();
10568 PARSEBACKQNEW();
10569 }
10570 } else {
10571 USTPUTC(CTLVAR, out);
10572 typeloc = out - stackblock();
10573 USTPUTC(VSNORMAL, out);
10574 subtype = VSNORMAL;
10575 if (c == '{') {
10576 c = pgetc();
10577 if (c == '#') {
10578 if ((c = pgetc()) == '}')
10579 c = '#';
10580 else
10581 subtype = VSLENGTH;
10582 }
10583 else
10584 subtype = 0;
10585 }
10586 if (c > PEOA && is_name(c)) {
10587 do {
10588 STPUTC(c, out);
10589 c = pgetc();
10590 } while (c > PEOA && is_in_name(c));
10591 } else if (is_digit(c)) {
10592 do {
10593 USTPUTC(c, out);
10594 c = pgetc();
10595 } while (is_digit(c));
10596 }
10597 else if (is_special(c)) {
10598 USTPUTC(c, out);
10599 c = pgetc();
10600 }
10601 else
Eric Andersen2870d962001-07-02 17:27:21 +000010602badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010603
10604 STPUTC('=', out);
10605 flags = 0;
10606 if (subtype == 0) {
10607 switch (c) {
10608 case ':':
10609 flags = VSNUL;
10610 c = pgetc();
10611 /*FALLTHROUGH*/
10612 default:
10613 p = strchr(types, c);
10614 if (p == NULL)
10615 goto badsub;
10616 subtype = p - types + VSNORMAL;
10617 break;
10618 case '%':
10619 case '#':
10620 {
10621 int cc = c;
10622 subtype = c == '#' ? VSTRIMLEFT :
10623 VSTRIMRIGHT;
10624 c = pgetc();
10625 if (c == cc)
10626 subtype++;
10627 else
10628 pungetc();
10629 break;
10630 }
10631 }
10632 } else {
10633 pungetc();
10634 }
10635 if (dblquote || arinest)
10636 flags |= VSQUOTE;
10637 *(stackblock() + typeloc) = subtype | flags;
10638 if (subtype != VSNORMAL) {
10639 varnest++;
10640 if (dblquote) {
10641 dqvarnest++;
10642 }
10643 }
10644 }
10645 goto parsesub_return;
10646}
10647
10648
10649/*
10650 * Called to parse command substitutions. Newstyle is set if the command
10651 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10652 * list of commands (passed by reference), and savelen is the number of
10653 * characters on the top of the stack which must be preserved.
10654 */
10655
10656parsebackq: {
10657 struct nodelist **nlpp;
10658 int savepbq;
10659 union node *n;
10660 char *volatile str;
10661 struct jmploc jmploc;
10662 struct jmploc *volatile savehandler;
10663 int savelen;
10664 int saveprompt;
10665#ifdef __GNUC__
10666 (void) &saveprompt;
10667#endif
10668
10669 savepbq = parsebackquote;
10670 if (setjmp(jmploc.loc)) {
10671 if (str)
10672 ckfree(str);
10673 parsebackquote = 0;
10674 handler = savehandler;
10675 longjmp(handler->loc, 1);
10676 }
10677 INTOFF;
10678 str = NULL;
10679 savelen = out - stackblock();
10680 if (savelen > 0) {
10681 str = ckmalloc(savelen);
10682 memcpy(str, stackblock(), savelen);
10683 }
10684 savehandler = handler;
10685 handler = &jmploc;
10686 INTON;
Eric Andersen2870d962001-07-02 17:27:21 +000010687 if (oldstyle) {
10688 /* We must read until the closing backquote, giving special
10689 treatment to some slashes, and then push the string and
10690 reread it as input, interpreting it normally. */
10691 char *pout;
10692 int pc;
10693 int psavelen;
10694 char *pstr;
Eric Andersencb57d552001-06-28 07:25:16 +000010695
10696
Eric Andersen2870d962001-07-02 17:27:21 +000010697 STARTSTACKSTR(pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010698 for (;;) {
10699 if (needprompt) {
10700 setprompt(2);
10701 needprompt = 0;
10702 }
10703 switch (pc = pgetc()) {
10704 case '`':
10705 goto done;
10706
10707 case '\\':
Eric Andersen2870d962001-07-02 17:27:21 +000010708 if ((pc = pgetc()) == '\n') {
Eric Andersencb57d552001-06-28 07:25:16 +000010709 plinno++;
10710 if (doprompt)
10711 setprompt(2);
10712 else
10713 setprompt(0);
10714 /*
10715 * If eating a newline, avoid putting
10716 * the newline into the new character
10717 * stream (via the STPUTC after the
10718 * switch).
10719 */
10720 continue;
10721 }
Eric Andersen2870d962001-07-02 17:27:21 +000010722 if (pc != '\\' && pc != '`' && pc != '$'
10723 && (!dblquote || pc != '"'))
10724 STPUTC('\\', pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010725 if (pc > PEOA) {
10726 break;
10727 }
10728 /* fall through */
10729
10730 case PEOF:
Eric Andersen2870d962001-07-02 17:27:21 +000010731#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010732 case PEOA:
Eric Andersen2870d962001-07-02 17:27:21 +000010733#endif
10734 startlinno = plinno;
Eric Andersencb57d552001-06-28 07:25:16 +000010735 synerror("EOF in backquote substitution");
10736
10737 case '\n':
10738 plinno++;
10739 needprompt = doprompt;
10740 break;
10741
10742 default:
10743 break;
10744 }
10745 STPUTC(pc, pout);
Eric Andersen2870d962001-07-02 17:27:21 +000010746 }
Eric Andersencb57d552001-06-28 07:25:16 +000010747done:
Eric Andersen2870d962001-07-02 17:27:21 +000010748 STPUTC('\0', pout);
10749 psavelen = pout - stackblock();
10750 if (psavelen > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010751 pstr = grabstackstr(pout);
10752 setinputstring(pstr);
Eric Andersen2870d962001-07-02 17:27:21 +000010753 }
10754 }
Eric Andersencb57d552001-06-28 07:25:16 +000010755 nlpp = &bqlist;
10756 while (*nlpp)
10757 nlpp = &(*nlpp)->next;
10758 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10759 (*nlpp)->next = NULL;
10760 parsebackquote = oldstyle;
10761
10762 if (oldstyle) {
10763 saveprompt = doprompt;
10764 doprompt = 0;
10765 }
10766
10767 n = list(0);
10768
10769 if (oldstyle)
10770 doprompt = saveprompt;
10771 else {
10772 if (readtoken() != TRP)
10773 synexpect(TRP);
10774 }
10775
10776 (*nlpp)->n = n;
Eric Andersen2870d962001-07-02 17:27:21 +000010777 if (oldstyle) {
Eric Andersencb57d552001-06-28 07:25:16 +000010778 /*
10779 * Start reading from old file again, ignoring any pushed back
10780 * tokens left from the backquote parsing
10781 */
Eric Andersen2870d962001-07-02 17:27:21 +000010782 popfile();
Eric Andersencb57d552001-06-28 07:25:16 +000010783 tokpushback = 0;
10784 }
10785 while (stackblocksize() <= savelen)
10786 growstackblock();
10787 STARTSTACKSTR(out);
10788 if (str) {
10789 memcpy(out, str, savelen);
10790 STADJUST(savelen, out);
10791 INTOFF;
10792 ckfree(str);
10793 str = NULL;
10794 INTON;
10795 }
10796 parsebackquote = savepbq;
10797 handler = savehandler;
10798 if (arinest || dblquote)
10799 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10800 else
10801 USTPUTC(CTLBACKQ, out);
10802 if (oldstyle)
10803 goto parsebackq_oldreturn;
10804 else
10805 goto parsebackq_newreturn;
10806}
10807
10808/*
10809 * Parse an arithmetic expansion (indicate start of one and set state)
10810 */
10811parsearith: {
10812
10813 if (++arinest == 1) {
10814 prevsyntax = syntax;
10815 syntax = ARISYNTAX;
10816 USTPUTC(CTLARI, out);
10817 if (dblquote)
10818 USTPUTC('"',out);
10819 else
10820 USTPUTC(' ',out);
10821 } else {
10822 /*
10823 * we collapse embedded arithmetic expansion to
10824 * parenthesis, which should be equivalent
10825 */
10826 USTPUTC('(', out);
10827 }
10828 goto parsearith_return;
10829}
10830
10831} /* end of readtoken */
10832
10833
Eric Andersencb57d552001-06-28 07:25:16 +000010834/*
10835 * Returns true if the text contains nothing to expand (no dollar signs
10836 * or backquotes).
10837 */
10838
10839static int
10840noexpand(text)
10841 char *text;
10842 {
10843 char *p;
10844 char c;
10845
10846 p = text;
10847 while ((c = *p++) != '\0') {
10848 if (c == CTLQUOTEMARK)
10849 continue;
10850 if (c == CTLESC)
10851 p++;
10852 else if (BASESYNTAX[(int)c] == CCTL)
10853 return 0;
10854 }
10855 return 1;
10856}
10857
10858
10859/*
10860 * Return true if the argument is a legal variable name (a letter or
10861 * underscore followed by zero or more letters, underscores, and digits).
10862 */
10863
10864static int
Eric Andersen2870d962001-07-02 17:27:21 +000010865goodname(const char *name)
10866{
10867 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000010868
10869 p = name;
10870 if (! is_name(*p))
10871 return 0;
10872 while (*++p) {
10873 if (! is_in_name(*p))
10874 return 0;
10875 }
10876 return 1;
10877}
10878
10879
10880/*
10881 * Called when an unexpected token is read during the parse. The argument
10882 * is the token that is expected, or -1 if more than one type of token can
10883 * occur at this point.
10884 */
10885
10886static void
10887synexpect(token)
10888 int token;
10889{
10890 char msg[64];
10891
10892 if (token >= 0) {
Eric Andersen3102ac42001-07-06 04:26:23 +000010893 snprintf(msg, 64, "%s unexpected (expecting %s)",
Eric Andersencb57d552001-06-28 07:25:16 +000010894 tokname[lasttoken], tokname[token]);
10895 } else {
Eric Andersen3102ac42001-07-06 04:26:23 +000010896 snprintf(msg, 64, "%s unexpected", tokname[lasttoken]);
Eric Andersencb57d552001-06-28 07:25:16 +000010897 }
10898 synerror(msg);
10899 /* NOTREACHED */
10900}
10901
10902
10903static void
Eric Andersen2870d962001-07-02 17:27:21 +000010904synerror(const char *msg)
10905{
Eric Andersencb57d552001-06-28 07:25:16 +000010906 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +000010907 out2fmt("%s: %d: ", commandname, startlinno);
10908 out2fmt("Syntax error: %s\n", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000010909 error((char *)NULL);
10910 /* NOTREACHED */
10911}
10912
Eric Andersencb57d552001-06-28 07:25:16 +000010913
10914/*
10915 * called by editline -- any expansions to the prompt
10916 * should be added here.
10917 */
Eric Andersen2870d962001-07-02 17:27:21 +000010918static void
Eric Andersen62483552001-07-10 06:09:16 +000010919setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000010920{
Eric Andersen62483552001-07-10 06:09:16 +000010921 char *prompt;
10922 switch (whichprompt) {
10923 case 1:
10924 prompt = ps1val();
10925 break;
10926 case 2:
10927 prompt = ps2val();
10928 break;
10929 default: /* 0 */
10930 prompt = "";
10931 }
10932 putprompt(prompt);
Eric Andersencb57d552001-06-28 07:25:16 +000010933}
10934
Eric Andersencb57d552001-06-28 07:25:16 +000010935
Eric Andersencb57d552001-06-28 07:25:16 +000010936/*
10937 * Code for dealing with input/output redirection.
10938 */
10939
Eric Andersen2870d962001-07-02 17:27:21 +000010940#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000010941#ifndef PIPE_BUF
Eric Andersen2870d962001-07-02 17:27:21 +000010942# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000010943#else
10944# define PIPESIZE PIPE_BUF
10945#endif
10946
10947
Eric Andersen62483552001-07-10 06:09:16 +000010948/*
10949 * Open a file in noclobber mode.
10950 * The code was copied from bash.
10951 */
10952static inline int
10953noclobberopen(const char *fname)
10954{
10955 int r, fd;
10956 struct stat finfo, finfo2;
10957
10958 /*
10959 * If the file exists and is a regular file, return an error
10960 * immediately.
10961 */
10962 r = stat(fname, &finfo);
10963 if (r == 0 && S_ISREG(finfo.st_mode)) {
10964 errno = EEXIST;
10965 return -1;
10966 }
10967
10968 /*
10969 * If the file was not present (r != 0), make sure we open it
10970 * exclusively so that if it is created before we open it, our open
10971 * will fail. Make sure that we do not truncate an existing file.
10972 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10973 * file was not a regular file, we leave O_EXCL off.
10974 */
10975 if (r != 0)
10976 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10977 fd = open(fname, O_WRONLY|O_CREAT, 0666);
10978
10979 /* If the open failed, return the file descriptor right away. */
10980 if (fd < 0)
10981 return fd;
10982
10983 /*
10984 * OK, the open succeeded, but the file may have been changed from a
10985 * non-regular file to a regular file between the stat and the open.
10986 * We are assuming that the O_EXCL open handles the case where FILENAME
10987 * did not exist and is symlinked to an existing file between the stat
10988 * and open.
10989 */
10990
10991 /*
10992 * If we can open it and fstat the file descriptor, and neither check
10993 * revealed that it was a regular file, and the file has not been
10994 * replaced, return the file descriptor.
10995 */
10996 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10997 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
10998 return fd;
10999
11000 /* The file has been replaced. badness. */
11001 close(fd);
11002 errno = EEXIST;
11003 return -1;
11004}
Eric Andersencb57d552001-06-28 07:25:16 +000011005
11006/*
Eric Andersen62483552001-07-10 06:09:16 +000011007 * Handle here documents. Normally we fork off a process to write the
11008 * data to a pipe. If the document is short, we can stuff the data in
11009 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000011010 */
11011
Eric Andersen62483552001-07-10 06:09:16 +000011012static inline int
11013openhere(const union node *redir)
11014{
11015 int pip[2];
11016 int len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011017
Eric Andersen62483552001-07-10 06:09:16 +000011018 if (pipe(pip) < 0)
11019 error("Pipe call failed");
11020 if (redir->type == NHERE) {
11021 len = strlen(redir->nhere.doc->narg.text);
11022 if (len <= PIPESIZE) {
11023 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11024 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011025 }
Eric Andersencb57d552001-06-28 07:25:16 +000011026 }
Eric Andersen62483552001-07-10 06:09:16 +000011027 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
11028 close(pip[0]);
11029 signal(SIGINT, SIG_IGN);
11030 signal(SIGQUIT, SIG_IGN);
11031 signal(SIGHUP, SIG_IGN);
11032#ifdef SIGTSTP
11033 signal(SIGTSTP, SIG_IGN);
11034#endif
11035 signal(SIGPIPE, SIG_DFL);
11036 if (redir->type == NHERE)
11037 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11038 else
11039 expandhere(redir->nhere.doc, pip[1]);
11040 _exit(0);
11041 }
11042out:
11043 close(pip[1]);
11044 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000011045}
11046
11047
Eric Andersen62483552001-07-10 06:09:16 +000011048static inline int
11049openredirect(const union node *redir)
11050{
Eric Andersencb57d552001-06-28 07:25:16 +000011051 char *fname;
11052 int f;
11053
11054 switch (redir->nfile.type) {
11055 case NFROM:
11056 fname = redir->nfile.expfname;
11057 if ((f = open(fname, O_RDONLY)) < 0)
11058 goto eopen;
11059 break;
11060 case NFROMTO:
11061 fname = redir->nfile.expfname;
11062 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
11063 goto ecreate;
11064 break;
11065 case NTO:
11066 /* Take care of noclobber mode. */
11067 if (Cflag) {
11068 fname = redir->nfile.expfname;
11069 if ((f = noclobberopen(fname)) < 0)
11070 goto ecreate;
11071 break;
11072 }
11073 case NTOOV:
11074 fname = redir->nfile.expfname;
11075#ifdef O_CREAT
11076 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
11077 goto ecreate;
11078#else
11079 if ((f = creat(fname, 0666)) < 0)
11080 goto ecreate;
11081#endif
11082 break;
11083 case NAPPEND:
11084 fname = redir->nfile.expfname;
11085#ifdef O_APPEND
11086 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
11087 goto ecreate;
11088#else
11089 if ((f = open(fname, O_WRONLY)) < 0
11090 && (f = creat(fname, 0666)) < 0)
11091 goto ecreate;
11092 lseek(f, (off_t)0, 2);
11093#endif
11094 break;
11095 default:
11096#ifdef DEBUG
11097 abort();
11098#endif
11099 /* Fall through to eliminate warning. */
11100 case NTOFD:
11101 case NFROMFD:
11102 f = -1;
11103 break;
11104 case NHERE:
11105 case NXHERE:
11106 f = openhere(redir);
11107 break;
11108 }
11109
11110 return f;
11111ecreate:
11112 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11113eopen:
11114 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11115}
11116
11117
Eric Andersen62483552001-07-10 06:09:16 +000011118/*
11119 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11120 * old file descriptors are stashed away so that the redirection can be
11121 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11122 * standard output, and the standard error if it becomes a duplicate of
11123 * stdout.
11124 */
11125
Eric Andersencb57d552001-06-28 07:25:16 +000011126static void
Eric Andersen62483552001-07-10 06:09:16 +000011127redirect(union node *redir, int flags)
11128{
11129 union node *n;
11130 struct redirtab *sv = NULL;
11131 int i;
11132 int fd;
11133 int newfd;
11134 int try;
11135 int fd1dup = flags & REDIR_BACKQ;; /* stdout `cmd` redir to pipe */
11136
11137 if (flags & REDIR_PUSH) {
11138 sv = ckmalloc(sizeof (struct redirtab));
11139 for (i = 0 ; i < 10 ; i++)
11140 sv->renamed[i] = EMPTY;
11141 sv->next = redirlist;
11142 redirlist = sv;
11143 }
11144 for (n = redir ; n ; n = n->nfile.next) {
11145 fd = n->nfile.fd;
11146 try = 0;
11147 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11148 n->ndup.dupfd == fd)
11149 continue; /* redirect from/to same file descriptor */
11150
11151 INTOFF;
11152 newfd = openredirect(n);
11153 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
11154 if (newfd == fd) {
11155 try++;
11156 } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
11157 switch (errno) {
11158 case EBADF:
11159 if (!try) {
11160 dupredirect(n, newfd, fd1dup);
11161 try++;
11162 break;
11163 }
11164 /* FALLTHROUGH*/
11165 default:
11166 if (newfd >= 0) {
11167 close(newfd);
11168 }
11169 INTON;
11170 error("%d: %m", fd);
11171 /* NOTREACHED */
11172 }
11173 }
11174 if (!try) {
11175 close(fd);
11176 if (flags & REDIR_PUSH) {
11177 sv->renamed[fd] = i;
11178 }
11179 }
11180 } else if (fd != newfd) {
11181 close(fd);
11182 }
11183 if (fd == 0)
11184 fd0_redirected++;
11185 if (!try)
11186 dupredirect(n, newfd, fd1dup);
11187 INTON;
11188 }
11189}
11190
11191
11192static void
11193dupredirect(const union node *redir, int f, int fd1dup)
Eric Andersen2870d962001-07-02 17:27:21 +000011194{
Eric Andersencb57d552001-06-28 07:25:16 +000011195 int fd = redir->nfile.fd;
11196
Eric Andersen62483552001-07-10 06:09:16 +000011197 if(fd==1)
11198 fd1dup = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011199 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Eric Andersen2870d962001-07-02 17:27:21 +000011200 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
Eric Andersen62483552001-07-10 06:09:16 +000011201 if (redir->ndup.dupfd!=1 || fd1dup!=1)
Eric Andersencb57d552001-06-28 07:25:16 +000011202 dup_as_newfd(redir->ndup.dupfd, fd);
11203 }
11204 return;
11205 }
11206
11207 if (f != fd) {
11208 dup_as_newfd(f, fd);
11209 close(f);
11210 }
11211 return;
11212}
11213
11214
Eric Andersencb57d552001-06-28 07:25:16 +000011215
Eric Andersencb57d552001-06-28 07:25:16 +000011216/*
11217 * Undo the effects of the last redirection.
11218 */
11219
11220static void
Eric Andersen2870d962001-07-02 17:27:21 +000011221popredir(void)
11222{
Eric Andersencb57d552001-06-28 07:25:16 +000011223 struct redirtab *rp = redirlist;
11224 int i;
11225
11226 INTOFF;
11227 for (i = 0 ; i < 10 ; i++) {
11228 if (rp->renamed[i] != EMPTY) {
Eric Andersen2870d962001-07-02 17:27:21 +000011229 if (i == 0)
11230 fd0_redirected--;
Eric Andersencb57d552001-06-28 07:25:16 +000011231 close(i);
11232 if (rp->renamed[i] >= 0) {
11233 dup_as_newfd(rp->renamed[i], i);
11234 close(rp->renamed[i]);
11235 }
Eric Andersencb57d552001-06-28 07:25:16 +000011236 }
11237 }
11238 redirlist = rp->next;
11239 ckfree(rp);
11240 INTON;
11241}
11242
11243/*
Eric Andersencb57d552001-06-28 07:25:16 +000011244 * Discard all saved file descriptors.
11245 */
11246
11247static void
Eric Andersen2870d962001-07-02 17:27:21 +000011248clearredir(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000011249 struct redirtab *rp;
11250 int i;
11251
11252 for (rp = redirlist ; rp ; rp = rp->next) {
11253 for (i = 0 ; i < 10 ; i++) {
11254 if (rp->renamed[i] >= 0) {
11255 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011256 }
11257 rp->renamed[i] = EMPTY;
11258 }
11259 }
Eric Andersencb57d552001-06-28 07:25:16 +000011260}
11261
11262
Eric Andersencb57d552001-06-28 07:25:16 +000011263/*
11264 * Copy a file descriptor to be >= to. Returns -1
11265 * if the source file descriptor is closed, EMPTY if there are no unused
11266 * file descriptors left.
11267 */
11268
11269static int
11270dup_as_newfd(from, to)
11271 int from;
11272 int to;
11273{
11274 int newfd;
11275
11276 newfd = fcntl(from, F_DUPFD, to);
11277 if (newfd < 0) {
11278 if (errno == EMFILE)
11279 return EMPTY;
11280 else
Eric Andersen2870d962001-07-02 17:27:21 +000011281 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011282 }
11283 return newfd;
11284}
11285
Eric Andersen2870d962001-07-02 17:27:21 +000011286/*#ifdef __weak_alias
Eric Andersencb57d552001-06-28 07:25:16 +000011287__weak_alias(getmode,_getmode)
11288__weak_alias(setmode,_setmode)
Eric Andersen2870d962001-07-02 17:27:21 +000011289#endif*/
Eric Andersencb57d552001-06-28 07:25:16 +000011290
Eric Andersen62483552001-07-10 06:09:16 +000011291#ifndef S_ISTXT
11292#if defined(__GLIBC__) && __GLIBC__ >= 2
Eric Andersencb57d552001-06-28 07:25:16 +000011293#define S_ISTXT __S_ISVTX
Eric Andersen62483552001-07-10 06:09:16 +000011294#else
11295#define S_ISTXT S_ISVTX
11296#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011297#endif
11298
Eric Andersen2870d962001-07-02 17:27:21 +000011299#define SET_LEN 6 /* initial # of bitcmd struct to malloc */
11300#define SET_LEN_INCR 4 /* # of bitcmd structs to add as needed */
Eric Andersencb57d552001-06-28 07:25:16 +000011301
11302typedef struct bitcmd {
Eric Andersen2870d962001-07-02 17:27:21 +000011303 char cmd;
11304 char cmd2;
11305 mode_t bits;
Eric Andersencb57d552001-06-28 07:25:16 +000011306} BITCMD;
11307
Eric Andersen2870d962001-07-02 17:27:21 +000011308#define CMD2_CLR 0x01
11309#define CMD2_SET 0x02
11310#define CMD2_GBITS 0x04
11311#define CMD2_OBITS 0x08
11312#define CMD2_UBITS 0x10
Eric Andersencb57d552001-06-28 07:25:16 +000011313
Eric Andersen2870d962001-07-02 17:27:21 +000011314static BITCMD *addcmd (BITCMD *, int, int, int, u_int);
11315static void compress_mode (BITCMD *);
Eric Andersencb57d552001-06-28 07:25:16 +000011316#ifdef SETMODE_DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +000011317static void dumpmode (BITCMD *);
Eric Andersencb57d552001-06-28 07:25:16 +000011318#endif
11319
11320/*
11321 * Given the old mode and an array of bitcmd structures, apply the operations
11322 * described in the bitcmd structures to the old mode, and return the new mode.
11323 * Note that there is no '=' command; a strict assignment is just a '-' (clear
11324 * bits) followed by a '+' (set bits).
11325 */
Eric Andersen2870d962001-07-02 17:27:21 +000011326static mode_t
Eric Andersencb57d552001-06-28 07:25:16 +000011327getmode(bbox, omode)
11328 const void *bbox;
11329 mode_t omode;
11330{
11331 const BITCMD *set;
11332 mode_t clrval, newmode, value;
11333
11334 _DIAGASSERT(bbox != NULL);
11335
11336 set = (const BITCMD *)bbox;
11337 newmode = omode;
11338 for (value = 0;; set++)
11339 switch(set->cmd) {
11340 /*
11341 * When copying the user, group or other bits around, we "know"
11342 * where the bits are in the mode so that we can do shifts to
11343 * copy them around. If we don't use shifts, it gets real
11344 * grundgy with lots of single bit checks and bit sets.
11345 */
11346 case 'u':
11347 value = (newmode & S_IRWXU) >> 6;
11348 goto common;
11349
11350 case 'g':
11351 value = (newmode & S_IRWXG) >> 3;
11352 goto common;
11353
11354 case 'o':
11355 value = newmode & S_IRWXO;
Eric Andersen2870d962001-07-02 17:27:21 +000011356common: if (set->cmd2 & CMD2_CLR) {
Eric Andersencb57d552001-06-28 07:25:16 +000011357 clrval =
11358 (set->cmd2 & CMD2_SET) ? S_IRWXO : value;
11359 if (set->cmd2 & CMD2_UBITS)
11360 newmode &= ~((clrval<<6) & set->bits);
11361 if (set->cmd2 & CMD2_GBITS)
11362 newmode &= ~((clrval<<3) & set->bits);
11363 if (set->cmd2 & CMD2_OBITS)
11364 newmode &= ~(clrval & set->bits);
11365 }
11366 if (set->cmd2 & CMD2_SET) {
11367 if (set->cmd2 & CMD2_UBITS)
11368 newmode |= (value<<6) & set->bits;
11369 if (set->cmd2 & CMD2_GBITS)
11370 newmode |= (value<<3) & set->bits;
11371 if (set->cmd2 & CMD2_OBITS)
11372 newmode |= value & set->bits;
11373 }
11374 break;
11375
11376 case '+':
11377 newmode |= set->bits;
11378 break;
11379
11380 case '-':
11381 newmode &= ~set->bits;
11382 break;
11383
11384 case 'X':
11385 if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
11386 newmode |= set->bits;
11387 break;
11388
11389 case '\0':
11390 default:
11391#ifdef SETMODE_DEBUG
11392 (void)printf("getmode:%04o -> %04o\n", omode, newmode);
11393#endif
11394 return (newmode);
11395 }
11396}
11397
Eric Andersen2870d962001-07-02 17:27:21 +000011398#define ADDCMD(a, b, c, d) do { \
11399 if (set >= endset) { \
11400 BITCMD *newset; \
11401 setlen += SET_LEN_INCR; \
11402 newset = realloc(saveset, sizeof(BITCMD) * setlen); \
11403 if (newset == NULL) { \
11404 free(saveset); \
11405 return (NULL); \
11406 } \
11407 set = newset + (set - saveset); \
11408 saveset = newset; \
11409 endset = newset + (setlen - 2); \
11410 } \
11411 set = addcmd(set, (a), (b), (c), (d)); \
Eric Andersencb57d552001-06-28 07:25:16 +000011412} while (/*CONSTCOND*/0)
11413
Eric Andersen2870d962001-07-02 17:27:21 +000011414#define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
Eric Andersencb57d552001-06-28 07:25:16 +000011415
11416static void *
11417setmode(p)
11418 const char *p;
11419{
11420 int perm, who;
11421 char op, *ep;
11422 BITCMD *set, *saveset, *endset;
11423 sigset_t mysigset, sigoset;
11424 mode_t mask;
Eric Andersen2870d962001-07-02 17:27:21 +000011425 int equalopdone = 0; /* pacify gcc */
Eric Andersencb57d552001-06-28 07:25:16 +000011426 int permXbits, setlen;
11427
11428 if (!*p)
11429 return (NULL);
11430
11431 /*
11432 * Get a copy of the mask for the permissions that are mask relative.
11433 * Flip the bits, we want what's not set. Since it's possible that
11434 * the caller is opening files inside a signal handler, protect them
11435 * as best we can.
11436 */
11437 sigfillset(&mysigset);
11438 (void)sigprocmask(SIG_BLOCK, &mysigset, &sigoset);
11439 (void)umask(mask = umask(0));
11440 mask = ~mask;
11441 (void)sigprocmask(SIG_SETMASK, &sigoset, NULL);
11442
11443 setlen = SET_LEN + 2;
Eric Andersen2870d962001-07-02 17:27:21 +000011444
Eric Andersencb57d552001-06-28 07:25:16 +000011445 if ((set = malloc((u_int)(sizeof(BITCMD) * setlen))) == NULL)
11446 return (NULL);
11447 saveset = set;
11448 endset = set + (setlen - 2);
11449
11450 /*
11451 * If an absolute number, get it and return; disallow non-octal digits
11452 * or illegal bits.
11453 */
Eric Andersen62483552001-07-10 06:09:16 +000011454 if (is_digit((unsigned char)*p)) {
Eric Andersencb57d552001-06-28 07:25:16 +000011455 perm = (mode_t)strtol(p, &ep, 8);
11456 if (*ep || perm & ~(STANDARD_BITS|S_ISTXT)) {
11457 free(saveset);
11458 return (NULL);
11459 }
11460 ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask);
11461 set->cmd = 0;
11462 return (saveset);
11463 }
11464
11465 /*
11466 * Build list of structures to set/clear/copy bits as described by
11467 * each clause of the symbolic mode.
11468 */
11469 for (;;) {
11470 /* First, find out which bits might be modified. */
11471 for (who = 0;; ++p) {
11472 switch (*p) {
11473 case 'a':
11474 who |= STANDARD_BITS;
11475 break;
11476 case 'u':
11477 who |= S_ISUID|S_IRWXU;
11478 break;
11479 case 'g':
11480 who |= S_ISGID|S_IRWXG;
11481 break;
11482 case 'o':
11483 who |= S_IRWXO;
11484 break;
11485 default:
11486 goto getop;
11487 }
11488 }
11489
Eric Andersen2870d962001-07-02 17:27:21 +000011490getop: if ((op = *p++) != '+' && op != '-' && op != '=') {
Eric Andersencb57d552001-06-28 07:25:16 +000011491 free(saveset);
11492 return (NULL);
11493 }
11494 if (op == '=')
11495 equalopdone = 0;
11496
11497 who &= ~S_ISTXT;
11498 for (perm = 0, permXbits = 0;; ++p) {
11499 switch (*p) {
11500 case 'r':
11501 perm |= S_IRUSR|S_IRGRP|S_IROTH;
11502 break;
11503 case 's':
11504 /*
Eric Andersen2870d962001-07-02 17:27:21 +000011505 * If specific bits where requested and
11506 * only "other" bits ignore set-id.
Eric Andersencb57d552001-06-28 07:25:16 +000011507 */
11508 if (who == 0 || (who & ~S_IRWXO))
11509 perm |= S_ISUID|S_ISGID;
11510 break;
11511 case 't':
11512 /*
Eric Andersen2870d962001-07-02 17:27:21 +000011513 * If specific bits where requested and
11514 * only "other" bits ignore set-id.
Eric Andersencb57d552001-06-28 07:25:16 +000011515 */
11516 if (who == 0 || (who & ~S_IRWXO)) {
11517 who |= S_ISTXT;
11518 perm |= S_ISTXT;
11519 }
11520 break;
11521 case 'w':
11522 perm |= S_IWUSR|S_IWGRP|S_IWOTH;
11523 break;
11524 case 'X':
11525 permXbits = S_IXUSR|S_IXGRP|S_IXOTH;
11526 break;
11527 case 'x':
11528 perm |= S_IXUSR|S_IXGRP|S_IXOTH;
11529 break;
11530 case 'u':
11531 case 'g':
11532 case 'o':
11533 /*
11534 * When ever we hit 'u', 'g', or 'o', we have
11535 * to flush out any partial mode that we have,
11536 * and then do the copying of the mode bits.
11537 */
11538 if (perm) {
11539 ADDCMD(op, who, perm, mask);
11540 perm = 0;
11541 }
11542 if (op == '=')
11543 equalopdone = 1;
11544 if (op == '+' && permXbits) {
11545 ADDCMD('X', who, permXbits, mask);
11546 permXbits = 0;
11547 }
11548 ADDCMD(*p, who, op, mask);
11549 break;
11550
11551 default:
11552 /*
11553 * Add any permissions that we haven't already
11554 * done.
11555 */
11556 if (perm || (op == '=' && !equalopdone)) {
11557 if (op == '=')
11558 equalopdone = 1;
11559 ADDCMD(op, who, perm, mask);
11560 perm = 0;
11561 }
11562 if (permXbits) {
11563 ADDCMD('X', who, permXbits, mask);
11564 permXbits = 0;
11565 }
11566 goto apply;
11567 }
11568 }
11569
Eric Andersen2870d962001-07-02 17:27:21 +000011570apply: if (!*p)
Eric Andersencb57d552001-06-28 07:25:16 +000011571 break;
11572 if (*p != ',')
11573 goto getop;
11574 ++p;
11575 }
11576 set->cmd = 0;
11577#ifdef SETMODE_DEBUG
11578 (void)printf("Before compress_mode()\n");
11579 dumpmode(saveset);
11580#endif
11581 compress_mode(saveset);
11582#ifdef SETMODE_DEBUG
11583 (void)printf("After compress_mode()\n");
11584 dumpmode(saveset);
11585#endif
11586 return (saveset);
11587}
11588
11589static BITCMD *
11590addcmd(set, op, who, oparg, mask)
11591 BITCMD *set;
11592 int oparg, who;
11593 int op;
11594 u_int mask;
11595{
11596
11597 _DIAGASSERT(set != NULL);
11598
11599 switch (op) {
11600 case '=':
11601 set->cmd = '-';
11602 set->bits = who ? who : STANDARD_BITS;
11603 set++;
11604
11605 op = '+';
11606 /* FALLTHROUGH */
11607 case '+':
11608 case '-':
11609 case 'X':
11610 set->cmd = op;
11611 set->bits = (who ? who : mask) & oparg;
11612 break;
11613
11614 case 'u':
11615 case 'g':
11616 case 'o':
11617 set->cmd = op;
11618 if (who) {
11619 set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) |
11620 ((who & S_IRGRP) ? CMD2_GBITS : 0) |
11621 ((who & S_IROTH) ? CMD2_OBITS : 0);
11622 set->bits = (mode_t)~0;
11623 } else {
11624 set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS;
11625 set->bits = mask;
11626 }
Eric Andersen2870d962001-07-02 17:27:21 +000011627
Eric Andersencb57d552001-06-28 07:25:16 +000011628 if (oparg == '+')
11629 set->cmd2 |= CMD2_SET;
11630 else if (oparg == '-')
11631 set->cmd2 |= CMD2_CLR;
11632 else if (oparg == '=')
11633 set->cmd2 |= CMD2_SET|CMD2_CLR;
11634 break;
11635 }
11636 return (set + 1);
11637}
11638
11639#ifdef SETMODE_DEBUG
11640static void
11641dumpmode(set)
11642 BITCMD *set;
11643{
11644
11645 _DIAGASSERT(set != NULL);
11646
11647 for (; set->cmd; ++set)
11648 (void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n",
11649 set->cmd, set->bits, set->cmd2 ? " cmd2:" : "",
11650 set->cmd2 & CMD2_CLR ? " CLR" : "",
11651 set->cmd2 & CMD2_SET ? " SET" : "",
11652 set->cmd2 & CMD2_UBITS ? " UBITS" : "",
11653 set->cmd2 & CMD2_GBITS ? " GBITS" : "",
11654 set->cmd2 & CMD2_OBITS ? " OBITS" : "");
11655}
11656#endif
11657
11658/*
11659 * Given an array of bitcmd structures, compress by compacting consecutive
11660 * '+', '-' and 'X' commands into at most 3 commands, one of each. The 'u',
Eric Andersen2870d962001-07-02 17:27:21 +000011661 * 'g' and 'o' commands continue to be separate. They could probably be
Eric Andersencb57d552001-06-28 07:25:16 +000011662 * compacted, but it's not worth the effort.
11663 */
11664static void
11665compress_mode(set)
11666 BITCMD *set;
11667{
11668 BITCMD *nset;
11669 int setbits, clrbits, Xbits, op;
11670
11671 _DIAGASSERT(set != NULL);
11672
11673 for (nset = set;;) {
11674 /* Copy over any 'u', 'g' and 'o' commands. */
11675 while ((op = nset->cmd) != '+' && op != '-' && op != 'X') {
11676 *set++ = *nset++;
11677 if (!op)
11678 return;
11679 }
11680
11681 for (setbits = clrbits = Xbits = 0;; nset++) {
11682 if ((op = nset->cmd) == '-') {
11683 clrbits |= nset->bits;
11684 setbits &= ~nset->bits;
11685 Xbits &= ~nset->bits;
11686 } else if (op == '+') {
11687 setbits |= nset->bits;
11688 clrbits &= ~nset->bits;
11689 Xbits &= ~nset->bits;
11690 } else if (op == 'X')
11691 Xbits |= nset->bits & ~setbits;
11692 else
11693 break;
11694 }
11695 if (clrbits) {
11696 set->cmd = '-';
11697 set->cmd2 = 0;
11698 set->bits = clrbits;
11699 set++;
11700 }
11701 if (setbits) {
11702 set->cmd = '+';
11703 set->cmd2 = 0;
11704 set->bits = setbits;
11705 set++;
11706 }
11707 if (Xbits) {
11708 set->cmd = 'X';
11709 set->cmd2 = 0;
11710 set->bits = Xbits;
11711 set++;
11712 }
11713 }
11714}
Eric Andersencb57d552001-06-28 07:25:16 +000011715#ifdef DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +000011716static void shtree (union node *, int, char *, FILE*);
11717static void shcmd (union node *, FILE *);
11718static void sharg (union node *, FILE *);
11719static void indent (int, char *, FILE *);
11720static void trstring (char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011721
11722
11723static void
11724showtree(n)
11725 union node *n;
11726{
11727 trputs("showtree called\n");
11728 shtree(n, 1, NULL, stdout);
11729}
11730
11731
11732static void
11733shtree(n, ind, pfx, fp)
11734 union node *n;
11735 int ind;
11736 char *pfx;
11737 FILE *fp;
11738{
11739 struct nodelist *lp;
11740 const char *s;
11741
11742 if (n == NULL)
11743 return;
11744
11745 indent(ind, pfx, fp);
11746 switch(n->type) {
11747 case NSEMI:
11748 s = "; ";
11749 goto binop;
11750 case NAND:
11751 s = " && ";
11752 goto binop;
11753 case NOR:
11754 s = " || ";
11755binop:
11756 shtree(n->nbinary.ch1, ind, NULL, fp);
11757 /* if (ind < 0) */
11758 fputs(s, fp);
11759 shtree(n->nbinary.ch2, ind, NULL, fp);
11760 break;
11761 case NCMD:
11762 shcmd(n, fp);
11763 if (ind >= 0)
11764 putc('\n', fp);
11765 break;
11766 case NPIPE:
11767 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11768 shcmd(lp->n, fp);
11769 if (lp->next)
11770 fputs(" | ", fp);
11771 }
11772 if (n->npipe.backgnd)
11773 fputs(" &", fp);
11774 if (ind >= 0)
11775 putc('\n', fp);
11776 break;
11777 default:
11778 fprintf(fp, "<node type %d>", n->type);
11779 if (ind >= 0)
11780 putc('\n', fp);
11781 break;
11782 }
11783}
11784
11785
11786
11787static void
11788shcmd(cmd, fp)
11789 union node *cmd;
11790 FILE *fp;
11791{
11792 union node *np;
11793 int first;
11794 const char *s;
11795 int dftfd;
11796
11797 first = 1;
11798 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11799 if (! first)
11800 putchar(' ');
11801 sharg(np, fp);
11802 first = 0;
11803 }
11804 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11805 if (! first)
11806 putchar(' ');
11807 switch (np->nfile.type) {
Eric Andersen2870d962001-07-02 17:27:21 +000011808 case NTO: s = ">"; dftfd = 1; break;
11809 case NAPPEND: s = ">>"; dftfd = 1; break;
11810 case NTOFD: s = ">&"; dftfd = 1; break;
11811 case NTOOV: s = ">|"; dftfd = 1; break;
11812 case NFROM: s = "<"; dftfd = 0; break;
11813 case NFROMFD: s = "<&"; dftfd = 0; break;
11814 case NFROMTO: s = "<>"; dftfd = 0; break;
11815 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011816 }
11817 if (np->nfile.fd != dftfd)
11818 fprintf(fp, "%d", np->nfile.fd);
11819 fputs(s, fp);
11820 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11821 fprintf(fp, "%d", np->ndup.dupfd);
11822 } else {
11823 sharg(np->nfile.fname, fp);
11824 }
11825 first = 0;
11826 }
11827}
11828
11829
11830
11831static void
11832sharg(arg, fp)
11833 union node *arg;
11834 FILE *fp;
11835 {
11836 char *p;
11837 struct nodelist *bqlist;
11838 int subtype;
11839
11840 if (arg->type != NARG) {
11841 printf("<node type %d>\n", arg->type);
11842 fflush(stdout);
11843 abort();
11844 }
11845 bqlist = arg->narg.backquote;
11846 for (p = arg->narg.text ; *p ; p++) {
11847 switch (*p) {
11848 case CTLESC:
11849 putc(*++p, fp);
11850 break;
11851 case CTLVAR:
11852 putc('$', fp);
11853 putc('{', fp);
11854 subtype = *++p;
11855 if (subtype == VSLENGTH)
11856 putc('#', fp);
11857
11858 while (*p != '=')
11859 putc(*p++, fp);
11860
11861 if (subtype & VSNUL)
11862 putc(':', fp);
11863
11864 switch (subtype & VSTYPE) {
11865 case VSNORMAL:
11866 putc('}', fp);
11867 break;
11868 case VSMINUS:
11869 putc('-', fp);
11870 break;
11871 case VSPLUS:
11872 putc('+', fp);
11873 break;
11874 case VSQUESTION:
11875 putc('?', fp);
11876 break;
11877 case VSASSIGN:
11878 putc('=', fp);
11879 break;
11880 case VSTRIMLEFT:
11881 putc('#', fp);
11882 break;
11883 case VSTRIMLEFTMAX:
11884 putc('#', fp);
11885 putc('#', fp);
11886 break;
11887 case VSTRIMRIGHT:
11888 putc('%', fp);
11889 break;
11890 case VSTRIMRIGHTMAX:
11891 putc('%', fp);
11892 putc('%', fp);
11893 break;
11894 case VSLENGTH:
11895 break;
11896 default:
11897 printf("<subtype %d>", subtype);
11898 }
11899 break;
11900 case CTLENDVAR:
11901 putc('}', fp);
11902 break;
11903 case CTLBACKQ:
11904 case CTLBACKQ|CTLQUOTE:
11905 putc('$', fp);
11906 putc('(', fp);
11907 shtree(bqlist->n, -1, NULL, fp);
11908 putc(')', fp);
11909 break;
11910 default:
11911 putc(*p, fp);
11912 break;
11913 }
11914 }
11915}
11916
11917
11918static void
11919indent(amount, pfx, fp)
11920 int amount;
11921 char *pfx;
11922 FILE *fp;
11923{
11924 int i;
11925
11926 for (i = 0 ; i < amount ; i++) {
11927 if (pfx && i == amount - 1)
11928 fputs(pfx, fp);
11929 putc('\t', fp);
11930 }
11931}
11932#endif
11933
11934
11935
11936/*
11937 * Debugging stuff.
11938 */
11939
11940
11941#ifdef DEBUG
11942FILE *tracefile;
11943
11944#if DEBUG == 2
11945static int debug = 1;
11946#else
11947static int debug = 0;
11948#endif
11949
11950
11951static void
11952trputc(c)
11953 int c;
11954{
11955 if (tracefile == NULL)
11956 return;
11957 putc(c, tracefile);
11958 if (c == '\n')
11959 fflush(tracefile);
11960}
11961
11962static void
11963trace(const char *fmt, ...)
11964{
11965 va_list va;
11966#ifdef __STDC__
11967 va_start(va, fmt);
11968#else
11969 char *fmt;
11970 va_start(va);
11971 fmt = va_arg(va, char *);
11972#endif
11973 if (tracefile != NULL) {
11974 (void) vfprintf(tracefile, fmt, va);
11975 if (strchr(fmt, '\n'))
11976 (void) fflush(tracefile);
11977 }
11978 va_end(va);
11979}
11980
11981
11982static void
11983trputs(s)
11984 const char *s;
11985{
11986 if (tracefile == NULL)
11987 return;
11988 fputs(s, tracefile);
11989 if (strchr(s, '\n'))
11990 fflush(tracefile);
11991}
11992
11993
11994static void
11995trstring(s)
11996 char *s;
11997{
11998 char *p;
11999 char c;
12000
12001 if (tracefile == NULL)
12002 return;
12003 putc('"', tracefile);
12004 for (p = s ; *p ; p++) {
12005 switch (*p) {
12006 case '\n': c = 'n'; goto backslash;
12007 case '\t': c = 't'; goto backslash;
12008 case '\r': c = 'r'; goto backslash;
12009 case '"': c = '"'; goto backslash;
12010 case '\\': c = '\\'; goto backslash;
12011 case CTLESC: c = 'e'; goto backslash;
12012 case CTLVAR: c = 'v'; goto backslash;
12013 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
12014 case CTLBACKQ: c = 'q'; goto backslash;
12015 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
Eric Andersen2870d962001-07-02 17:27:21 +000012016backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000012017 putc(c, tracefile);
12018 break;
12019 default:
12020 if (*p >= ' ' && *p <= '~')
12021 putc(*p, tracefile);
12022 else {
12023 putc('\\', tracefile);
12024 putc(*p >> 6 & 03, tracefile);
12025 putc(*p >> 3 & 07, tracefile);
12026 putc(*p & 07, tracefile);
12027 }
12028 break;
12029 }
12030 }
12031 putc('"', tracefile);
12032}
12033
12034
12035static void
12036trargs(ap)
12037 char **ap;
12038{
12039 if (tracefile == NULL)
12040 return;
12041 while (*ap) {
12042 trstring(*ap++);
12043 if (*ap)
12044 putc(' ', tracefile);
12045 else
12046 putc('\n', tracefile);
12047 }
12048 fflush(tracefile);
12049}
12050
12051
12052static void
12053opentrace() {
12054 char s[100];
12055#ifdef O_APPEND
12056 int flags;
12057#endif
12058
12059 if (!debug)
12060 return;
12061#ifdef not_this_way
12062 {
12063 char *p;
12064 if ((p = getenv("HOME")) == NULL) {
12065 if (geteuid() == 0)
12066 p = "/";
12067 else
12068 p = "/tmp";
12069 }
Eric Andersen2870d962001-07-02 17:27:21 +000012070 strcpy(s, p);
Eric Andersencb57d552001-06-28 07:25:16 +000012071 strcat(s, "/trace");
12072 }
12073#else
Eric Andersen2870d962001-07-02 17:27:21 +000012074 strcpy(s, "./trace");
Eric Andersencb57d552001-06-28 07:25:16 +000012075#endif /* not_this_way */
12076 if ((tracefile = fopen(s, "a")) == NULL) {
12077 fprintf(stderr, "Can't open %s\n", s);
12078 return;
12079 }
12080#ifdef O_APPEND
12081 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
12082 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
12083#endif
12084 fputs("\nTracing started.\n", tracefile);
12085 fflush(tracefile);
12086}
12087#endif /* DEBUG */
12088
12089
12090/*
Eric Andersencb57d552001-06-28 07:25:16 +000012091 * The trap builtin.
12092 */
12093
12094static int
12095trapcmd(argc, argv)
12096 int argc;
12097 char **argv;
12098{
12099 char *action;
12100 char **ap;
12101 int signo;
12102
12103 if (argc <= 1) {
12104 for (signo = 0 ; signo < NSIG ; signo++) {
12105 if (trap[signo] != NULL) {
12106 char *p;
12107
12108 p = single_quote(trap[signo]);
Eric Andersen62483552001-07-10 06:09:16 +000012109 printf("trap -- %s %s\n", p,
Eric Andersencb57d552001-06-28 07:25:16 +000012110 signal_names[signo] + (signo ? 3 : 0)
12111 );
12112 stunalloc(p);
12113 }
12114 }
12115 return 0;
12116 }
12117 ap = argv + 1;
12118 if (argc == 2)
12119 action = NULL;
12120 else
12121 action = *ap++;
12122 while (*ap) {
12123 if ((signo = decode_signal(*ap, 0)) < 0)
12124 error("%s: bad trap", *ap);
12125 INTOFF;
12126 if (action) {
12127 if (action[0] == '-' && action[1] == '\0')
12128 action = NULL;
12129 else
12130 action = savestr(action);
12131 }
12132 if (trap[signo])
12133 ckfree(trap[signo]);
12134 trap[signo] = action;
12135 if (signo != 0)
12136 setsignal(signo);
12137 INTON;
12138 ap++;
12139 }
12140 return 0;
12141}
12142
12143
12144
Eric Andersencb57d552001-06-28 07:25:16 +000012145
12146
12147
12148/*
12149 * Set the signal handler for the specified signal. The routine figures
12150 * out what it should be set to.
12151 */
12152
12153static void
Eric Andersen2870d962001-07-02 17:27:21 +000012154setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000012155{
12156 int action;
12157 char *t;
12158 struct sigaction act;
12159
12160 if ((t = trap[signo]) == NULL)
12161 action = S_DFL;
12162 else if (*t != '\0')
12163 action = S_CATCH;
12164 else
12165 action = S_IGN;
12166 if (rootshell && action == S_DFL) {
12167 switch (signo) {
12168 case SIGINT:
12169 if (iflag || minusc || sflag == 0)
12170 action = S_CATCH;
12171 break;
12172 case SIGQUIT:
12173#ifdef DEBUG
12174 {
Eric Andersencb57d552001-06-28 07:25:16 +000012175
12176 if (debug)
12177 break;
12178 }
12179#endif
12180 /* FALLTHROUGH */
12181 case SIGTERM:
12182 if (iflag)
12183 action = S_IGN;
12184 break;
Eric Andersen2870d962001-07-02 17:27:21 +000012185#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000012186 case SIGTSTP:
12187 case SIGTTOU:
12188 if (mflag)
12189 action = S_IGN;
12190 break;
12191#endif
12192 }
12193 }
12194
12195 t = &sigmode[signo - 1];
12196 if (*t == 0) {
12197 /*
12198 * current setting unknown
12199 */
12200 if (sigaction(signo, 0, &act) == -1) {
12201 /*
12202 * Pretend it worked; maybe we should give a warning
12203 * here, but other shells don't. We don't alter
12204 * sigmode, so that we retry every time.
12205 */
12206 return;
12207 }
12208 if (act.sa_handler == SIG_IGN) {
12209 if (mflag && (signo == SIGTSTP ||
12210 signo == SIGTTIN || signo == SIGTTOU)) {
Eric Andersen2870d962001-07-02 17:27:21 +000012211 *t = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000012212 } else
12213 *t = S_HARD_IGN;
12214 } else {
Eric Andersen2870d962001-07-02 17:27:21 +000012215 *t = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000012216 }
12217 }
12218 if (*t == S_HARD_IGN || *t == action)
12219 return;
12220 switch (action) {
12221 case S_CATCH:
12222 act.sa_handler = onsig;
12223 break;
12224 case S_IGN:
12225 act.sa_handler = SIG_IGN;
12226 break;
12227 default:
12228 act.sa_handler = SIG_DFL;
12229 }
12230 *t = action;
12231 act.sa_flags = 0;
12232 sigemptyset(&act.sa_mask);
12233 sigaction(signo, &act, 0);
12234}
12235
12236/*
12237 * Ignore a signal.
12238 */
12239
12240static void
12241ignoresig(signo)
12242 int signo;
12243{
12244 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
12245 signal(signo, SIG_IGN);
12246 }
12247 sigmode[signo - 1] = S_HARD_IGN;
12248}
12249
12250
Eric Andersencb57d552001-06-28 07:25:16 +000012251/*
12252 * Signal handler.
12253 */
12254
12255static void
Eric Andersen2870d962001-07-02 17:27:21 +000012256onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000012257{
12258 if (signo == SIGINT && trap[SIGINT] == NULL) {
12259 onint();
12260 return;
12261 }
12262 gotsig[signo - 1] = 1;
12263 pendingsigs++;
12264}
12265
12266
Eric Andersencb57d552001-06-28 07:25:16 +000012267/*
12268 * Called to execute a trap. Perhaps we should avoid entering new trap
12269 * handlers while we are executing a trap handler.
12270 */
12271
12272static void
Eric Andersen2870d962001-07-02 17:27:21 +000012273dotrap(void)
12274{
Eric Andersencb57d552001-06-28 07:25:16 +000012275 int i;
12276 int savestatus;
12277
12278 for (;;) {
12279 for (i = 1 ; ; i++) {
12280 if (gotsig[i - 1])
12281 break;
12282 if (i >= NSIG - 1)
12283 goto done;
12284 }
12285 gotsig[i - 1] = 0;
12286 savestatus=exitstatus;
12287 evalstring(trap[i], 0);
12288 exitstatus=savestatus;
12289 }
12290done:
12291 pendingsigs = 0;
12292}
12293
Eric Andersencb57d552001-06-28 07:25:16 +000012294/*
12295 * Called to exit the shell.
12296 */
12297
12298static void
Eric Andersen2870d962001-07-02 17:27:21 +000012299exitshell(int status)
Eric Andersencb57d552001-06-28 07:25:16 +000012300{
12301 struct jmploc loc1, loc2;
12302 char *p;
12303
12304 TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
12305 if (setjmp(loc1.loc)) {
12306 goto l1;
12307 }
12308 if (setjmp(loc2.loc)) {
12309 goto l2;
12310 }
12311 handler = &loc1;
12312 if ((p = trap[0]) != NULL && *p != '\0') {
12313 trap[0] = NULL;
12314 evalstring(p, 0);
12315 }
Eric Andersen2870d962001-07-02 17:27:21 +000012316l1: handler = &loc2; /* probably unnecessary */
Eric Andersencb57d552001-06-28 07:25:16 +000012317 flushall();
Eric Andersen2870d962001-07-02 17:27:21 +000012318#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000012319 setjobctl(0);
12320#endif
12321l2: _exit(status);
12322 /* NOTREACHED */
12323}
12324
12325static int decode_signal(const char *string, int minsig)
12326{
12327 int signo;
12328
Eric Andersen2870d962001-07-02 17:27:21 +000012329 if (is_number(string, &signo)) {
Eric Andersencb57d552001-06-28 07:25:16 +000012330 if (signo >= NSIG) {
12331 return -1;
12332 }
12333 return signo;
12334 }
12335
12336 signo = minsig;
12337 if (!signo) {
12338 goto zero;
12339 }
12340 for (; signo < NSIG; signo++) {
12341 if (!strcasecmp(string, &(signal_names[signo])[3])) {
12342 return signo;
12343 }
12344zero:
12345 if (!strcasecmp(string, signal_names[signo])) {
12346 return signo;
12347 }
12348 }
12349
12350 return -1;
12351}
Eric Andersen2870d962001-07-02 17:27:21 +000012352static struct var **hashvar (const char *);
12353static void showvars (const char *, int, int);
12354static struct var **findvar (struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000012355
12356/*
12357 * Initialize the varable symbol tables and import the environment
12358 */
12359
Eric Andersencb57d552001-06-28 07:25:16 +000012360/*
12361 * This routine initializes the builtin variables. It is called when the
12362 * shell is initialized and again when a shell procedure is spawned.
12363 */
12364
12365static void
12366initvar() {
12367 const struct varinit *ip;
12368 struct var *vp;
12369 struct var **vpp;
12370
12371 for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
12372 if ((vp->flags & VEXPORT) == 0) {
12373 vpp = hashvar(ip->text);
12374 vp->next = *vpp;
12375 *vpp = vp;
12376 vp->text = strdup(ip->text);
12377 vp->flags = ip->flags;
12378 vp->func = ip->func;
12379 }
12380 }
12381 /*
12382 * PS1 depends on uid
12383 */
12384 if ((vps1.flags & VEXPORT) == 0) {
12385 vpp = hashvar("PS1=");
12386 vps1.next = *vpp;
12387 *vpp = &vps1;
12388 vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# ");
12389 vps1.flags = VSTRFIXED|VTEXTFIXED;
12390 }
12391}
12392
12393/*
12394 * Set the value of a variable. The flags argument is ored with the
12395 * flags of the variable. If val is NULL, the variable is unset.
12396 */
12397
12398static void
12399setvar(name, val, flags)
12400 const char *name, *val;
12401 int flags;
12402{
12403 const char *p;
12404 int len;
12405 int namelen;
12406 char *nameeq;
12407 int isbad;
12408 int vallen = 0;
12409
12410 isbad = 0;
12411 p = name;
12412 if (! is_name(*p))
12413 isbad = 1;
12414 p++;
12415 for (;;) {
12416 if (! is_in_name(*p)) {
12417 if (*p == '\0' || *p == '=')
12418 break;
12419 isbad = 1;
12420 }
12421 p++;
12422 }
12423 namelen = p - name;
12424 if (isbad)
12425 error("%.*s: bad variable name", namelen, name);
Eric Andersen2870d962001-07-02 17:27:21 +000012426 len = namelen + 2; /* 2 is space for '=' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +000012427 if (val == NULL) {
12428 flags |= VUNSET;
12429 } else {
12430 len += vallen = strlen(val);
12431 }
12432 INTOFF;
12433 nameeq = ckmalloc(len);
12434 memcpy(nameeq, name, namelen);
12435 nameeq[namelen] = '=';
12436 if (val) {
12437 memcpy(nameeq + namelen + 1, val, vallen + 1);
12438 } else {
12439 nameeq[namelen + 1] = '\0';
12440 }
12441 setvareq(nameeq, flags);
12442 INTON;
12443}
12444
12445
12446
12447/*
12448 * Same as setvar except that the variable and value are passed in
12449 * the first argument as name=value. Since the first argument will
12450 * be actually stored in the table, it should not be a string that
12451 * will go away.
12452 */
12453
12454static void
12455setvareq(s, flags)
12456 char *s;
12457 int flags;
12458{
12459 struct var *vp, **vpp;
12460
12461 vpp = hashvar(s);
12462 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
12463 if ((vp = *findvar(vpp, s))) {
12464 if (vp->flags & VREADONLY) {
12465 size_t len = strchr(s, '=') - s;
12466 error("%.*s: is read only", len, s);
12467 }
12468 INTOFF;
12469
12470 if (vp->func && (flags & VNOFUNC) == 0)
12471 (*vp->func)(strchr(s, '=') + 1);
12472
12473 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12474 ckfree(vp->text);
12475
12476 vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
12477 vp->flags |= flags;
12478 vp->text = s;
12479
12480 /*
12481 * We could roll this to a function, to handle it as
12482 * a regular variable function callback, but why bother?
12483 */
12484 if (iflag && (vp == &vmpath || (vp == &vmail && !mpathset())))
12485 chkmail(1);
12486 INTON;
12487 return;
12488 }
12489 /* not found */
12490 vp = ckmalloc(sizeof (*vp));
12491 vp->flags = flags;
12492 vp->text = s;
12493 vp->next = *vpp;
12494 vp->func = NULL;
12495 *vpp = vp;
12496}
12497
12498
12499
12500/*
12501 * Process a linked list of variable assignments.
12502 */
12503
12504static void
12505listsetvar(mylist)
12506 struct strlist *mylist;
12507 {
12508 struct strlist *lp;
12509
12510 INTOFF;
12511 for (lp = mylist ; lp ; lp = lp->next) {
12512 setvareq(savestr(lp->text), 0);
12513 }
12514 INTON;
12515}
12516
12517
12518
12519/*
12520 * Find the value of a variable. Returns NULL if not set.
12521 */
12522
Eric Andersen62483552001-07-10 06:09:16 +000012523static const char *
Eric Andersencb57d552001-06-28 07:25:16 +000012524lookupvar(name)
12525 const char *name;
12526 {
12527 struct var *v;
12528
12529 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
12530 return strchr(v->text, '=') + 1;
12531 }
12532 return NULL;
12533}
12534
12535
12536
12537/*
12538 * Search the environment of a builtin command.
12539 */
12540
Eric Andersen62483552001-07-10 06:09:16 +000012541static const char *
12542bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012543{
Eric Andersen62483552001-07-10 06:09:16 +000012544 const struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012545
12546 for (sp = cmdenviron ; sp ; sp = sp->next) {
12547 if (varequal(sp->text, name))
12548 return strchr(sp->text, '=') + 1;
12549 }
12550 return lookupvar(name);
12551}
12552
12553
12554
12555/*
12556 * Generate a list of exported variables. This routine is used to construct
12557 * the third argument to execve when executing a program.
12558 */
12559
12560static char **
12561environment() {
12562 int nenv;
12563 struct var **vpp;
12564 struct var *vp;
12565 char **env;
12566 char **ep;
12567
12568 nenv = 0;
12569 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12570 for (vp = *vpp ; vp ; vp = vp->next)
12571 if (vp->flags & VEXPORT)
12572 nenv++;
12573 }
12574 ep = env = stalloc((nenv + 1) * sizeof *env);
12575 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12576 for (vp = *vpp ; vp ; vp = vp->next)
12577 if (vp->flags & VEXPORT)
12578 *ep++ = vp->text;
12579 }
12580 *ep = NULL;
12581 return env;
12582}
12583
12584
12585/*
12586 * Called when a shell procedure is invoked to clear out nonexported
12587 * variables. It is also necessary to reallocate variables of with
12588 * VSTACK set since these are currently allocated on the stack.
12589 */
12590
Eric Andersencb57d552001-06-28 07:25:16 +000012591static void
Eric Andersen2870d962001-07-02 17:27:21 +000012592shprocvar(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000012593 struct var **vpp;
12594 struct var *vp, **prev;
12595
12596 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12597 for (prev = vpp ; (vp = *prev) != NULL ; ) {
12598 if ((vp->flags & VEXPORT) == 0) {
12599 *prev = vp->next;
12600 if ((vp->flags & VTEXTFIXED) == 0)
12601 ckfree(vp->text);
12602 if ((vp->flags & VSTRFIXED) == 0)
12603 ckfree(vp);
12604 } else {
12605 if (vp->flags & VSTACK) {
12606 vp->text = savestr(vp->text);
12607 vp->flags &=~ VSTACK;
12608 }
12609 prev = &vp->next;
12610 }
12611 }
12612 }
12613 initvar();
12614}
12615
12616
12617
12618/*
12619 * Command to list all variables which are set. Currently this command
12620 * is invoked from the set command when the set command is called without
12621 * any variables.
12622 */
12623
12624static int
12625showvarscmd(argc, argv)
12626 int argc;
12627 char **argv;
12628{
12629 showvars(nullstr, VUNSET, VUNSET);
12630 return 0;
12631}
12632
12633
12634
12635/*
12636 * The export and readonly commands.
12637 */
12638
12639static int
12640exportcmd(argc, argv)
12641 int argc;
12642 char **argv;
12643{
12644 struct var *vp;
12645 char *name;
12646 const char *p;
12647 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12648 int pflag;
12649
12650 listsetvar(cmdenviron);
12651 pflag = (nextopt("p") == 'p');
12652 if (argc > 1 && !pflag) {
12653 while ((name = *argptr++) != NULL) {
12654 if ((p = strchr(name, '=')) != NULL) {
12655 p++;
12656 } else {
12657 if ((vp = *findvar(hashvar(name), name))) {
12658 vp->flags |= flag;
12659 goto found;
12660 }
12661 }
12662 setvar(name, p, flag);
12663found:;
12664 }
12665 } else {
12666 showvars(argv[0], flag, 0);
12667 }
12668 return 0;
12669}
12670
12671
12672/*
12673 * The "local" command.
12674 */
12675
Eric Andersen2870d962001-07-02 17:27:21 +000012676/* funcnest nonzero if we are currently evaluating a function */
12677
Eric Andersencb57d552001-06-28 07:25:16 +000012678static int
12679localcmd(argc, argv)
12680 int argc;
12681 char **argv;
12682{
12683 char *name;
12684
Eric Andersen2870d962001-07-02 17:27:21 +000012685 if (! funcnest)
Eric Andersencb57d552001-06-28 07:25:16 +000012686 error("Not in a function");
12687 while ((name = *argptr++) != NULL) {
12688 mklocal(name);
12689 }
12690 return 0;
12691}
12692
12693
12694/*
12695 * Make a variable a local variable. When a variable is made local, it's
12696 * value and flags are saved in a localvar structure. The saved values
12697 * will be restored when the shell function returns. We handle the name
12698 * "-" as a special case.
12699 */
12700
12701static void
12702mklocal(name)
12703 char *name;
12704 {
12705 struct localvar *lvp;
12706 struct var **vpp;
12707 struct var *vp;
12708
12709 INTOFF;
12710 lvp = ckmalloc(sizeof (struct localvar));
12711 if (name[0] == '-' && name[1] == '\0') {
12712 char *p;
Eric Andersen2870d962001-07-02 17:27:21 +000012713 p = ckmalloc(sizeof optet_vals);
12714 lvp->text = memcpy(p, optet_vals, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000012715 vp = NULL;
12716 } else {
12717 vpp = hashvar(name);
12718 vp = *findvar(vpp, name);
12719 if (vp == NULL) {
12720 if (strchr(name, '='))
12721 setvareq(savestr(name), VSTRFIXED);
12722 else
12723 setvar(name, NULL, VSTRFIXED);
Eric Andersen2870d962001-07-02 17:27:21 +000012724 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012725 lvp->text = NULL;
12726 lvp->flags = VUNSET;
12727 } else {
12728 lvp->text = vp->text;
12729 lvp->flags = vp->flags;
12730 vp->flags |= VSTRFIXED|VTEXTFIXED;
12731 if (strchr(name, '='))
12732 setvareq(savestr(name), 0);
12733 }
12734 }
12735 lvp->vp = vp;
12736 lvp->next = localvars;
12737 localvars = lvp;
12738 INTON;
12739}
12740
12741
12742/*
12743 * Called after a function returns.
12744 */
12745
12746static void
12747poplocalvars() {
12748 struct localvar *lvp;
12749 struct var *vp;
12750
12751 while ((lvp = localvars) != NULL) {
12752 localvars = lvp->next;
12753 vp = lvp->vp;
Eric Andersen2870d962001-07-02 17:27:21 +000012754 if (vp == NULL) { /* $- saved */
12755 memcpy(optet_vals, lvp->text, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000012756 ckfree(lvp->text);
12757 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12758 (void)unsetvar(vp->text);
12759 } else {
12760 if ((vp->flags & VTEXTFIXED) == 0)
12761 ckfree(vp->text);
12762 vp->flags = lvp->flags;
12763 vp->text = lvp->text;
12764 }
12765 ckfree(lvp);
12766 }
12767}
12768
12769
12770static int
12771setvarcmd(argc, argv)
12772 int argc;
12773 char **argv;
12774{
12775 if (argc <= 2)
12776 return unsetcmd(argc, argv);
12777 else if (argc == 3)
12778 setvar(argv[1], argv[2], 0);
12779 else
12780 error("List assignment not implemented");
12781 return 0;
12782}
12783
12784
12785/*
12786 * The unset builtin command. We unset the function before we unset the
12787 * variable to allow a function to be unset when there is a readonly variable
12788 * with the same name.
12789 */
12790
12791static int
12792unsetcmd(argc, argv)
12793 int argc;
12794 char **argv;
12795{
12796 char **ap;
12797 int i;
12798 int flg_func = 0;
12799 int flg_var = 0;
12800 int ret = 0;
12801
12802 while ((i = nextopt("vf")) != '\0') {
12803 if (i == 'f')
12804 flg_func = 1;
12805 else
12806 flg_var = 1;
12807 }
12808 if (flg_func == 0 && flg_var == 0)
12809 flg_var = 1;
12810
12811 for (ap = argptr; *ap ; ap++) {
12812 if (flg_func)
12813 unsetfunc(*ap);
12814 if (flg_var)
12815 ret |= unsetvar(*ap);
12816 }
12817 return ret;
12818}
12819
12820
12821/*
12822 * Unset the specified variable.
12823 */
12824
12825static int
Eric Andersen62483552001-07-10 06:09:16 +000012826unsetvar(const char *s)
12827{
Eric Andersencb57d552001-06-28 07:25:16 +000012828 struct var **vpp;
12829 struct var *vp;
12830
12831 vpp = findvar(hashvar(s), s);
12832 vp = *vpp;
12833 if (vp) {
12834 if (vp->flags & VREADONLY)
12835 return (1);
12836 INTOFF;
12837 if (*(strchr(vp->text, '=') + 1) != '\0')
12838 setvar(s, nullstr, 0);
12839 vp->flags &= ~VEXPORT;
12840 vp->flags |= VUNSET;
12841 if ((vp->flags & VSTRFIXED) == 0) {
12842 if ((vp->flags & VTEXTFIXED) == 0)
12843 ckfree(vp->text);
12844 *vpp = vp->next;
12845 ckfree(vp);
12846 }
12847 INTON;
12848 return (0);
12849 }
12850
12851 return (0);
12852}
12853
12854
12855
12856/*
12857 * Find the appropriate entry in the hash table from the name.
12858 */
12859
12860static struct var **
Eric Andersen62483552001-07-10 06:09:16 +000012861hashvar(const char *p)
12862{
Eric Andersencb57d552001-06-28 07:25:16 +000012863 unsigned int hashval;
12864
12865 hashval = ((unsigned char) *p) << 4;
12866 while (*p && *p != '=')
12867 hashval += (unsigned char) *p++;
12868 return &vartab[hashval % VTABSIZE];
12869}
12870
12871
12872
12873/*
12874 * Returns true if the two strings specify the same varable. The first
12875 * variable name is terminated by '='; the second may be terminated by
12876 * either '=' or '\0'.
12877 */
12878
12879static int
Eric Andersen62483552001-07-10 06:09:16 +000012880varequal(const char *p, const char *q)
12881{
Eric Andersencb57d552001-06-28 07:25:16 +000012882 while (*p == *q++) {
12883 if (*p++ == '=')
12884 return 1;
12885 }
12886 if (*p == '=' && *(q - 1) == '\0')
12887 return 1;
12888 return 0;
12889}
12890
12891static void
12892showvars(const char *myprefix, int mask, int xor)
12893{
12894 struct var **vpp;
12895 struct var *vp;
12896 const char *sep = myprefix == nullstr ? myprefix : spcstr;
12897
12898 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12899 for (vp = *vpp ; vp ; vp = vp->next) {
12900 if ((vp->flags & mask) ^ xor) {
12901 char *p;
12902 int len;
12903
12904 p = strchr(vp->text, '=') + 1;
12905 len = p - vp->text;
12906 p = single_quote(p);
12907
Eric Andersen62483552001-07-10 06:09:16 +000012908 printf("%s%s%.*s%s\n", myprefix, sep, len,
12909 vp->text, p);
Eric Andersencb57d552001-06-28 07:25:16 +000012910 stunalloc(p);
12911 }
12912 }
12913 }
12914}
12915
12916static struct var **
12917findvar(struct var **vpp, const char *name)
12918{
12919 for (; *vpp; vpp = &(*vpp)->next) {
12920 if (varequal((*vpp)->text, name)) {
12921 break;
12922 }
12923 }
12924 return vpp;
12925}
12926
12927/*
12928 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
12929 * This file contains code for the times builtin.
Eric Andersen62483552001-07-10 06:09:16 +000012930 * $Id: ash.c,v 1.8 2001/07/10 06:09:16 andersen Exp $
Eric Andersencb57d552001-06-28 07:25:16 +000012931 */
12932static int timescmd (int argc, char **argv)
12933{
12934 struct tms buf;
12935 long int clk_tck = sysconf(_SC_CLK_TCK);
12936
12937 times(&buf);
12938 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
12939 (int) (buf.tms_utime / clk_tck / 60),
12940 ((double) buf.tms_utime) / clk_tck,
12941 (int) (buf.tms_stime / clk_tck / 60),
12942 ((double) buf.tms_stime) / clk_tck,
12943 (int) (buf.tms_cutime / clk_tck / 60),
12944 ((double) buf.tms_cutime) / clk_tck,
12945 (int) (buf.tms_cstime / clk_tck / 60),
12946 ((double) buf.tms_cstime) / clk_tck);
12947 return 0;
12948}
12949
Eric Andersendf82f612001-06-28 07:46:40 +000012950
12951/*-
12952 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000012953 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000012954 *
12955 * This code is derived from software contributed to Berkeley by
12956 * Kenneth Almquist.
12957 *
12958 * Redistribution and use in source and binary forms, with or without
12959 * modification, are permitted provided that the following conditions
12960 * are met:
12961 * 1. Redistributions of source code must retain the above copyright
12962 * notice, this list of conditions and the following disclaimer.
12963 * 2. Redistributions in binary form must reproduce the above copyright
12964 * notice, this list of conditions and the following disclaimer in the
12965 * documentation and/or other materials provided with the distribution.
12966 *
Eric Andersen2870d962001-07-02 17:27:21 +000012967 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
12968 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000012969 *
12970 * 4. Neither the name of the University nor the names of its contributors
12971 * may be used to endorse or promote products derived from this software
12972 * without specific prior written permission.
12973 *
12974 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
12975 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
12976 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
12977 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
12978 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
12979 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
12980 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
12981 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
12982 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
12983 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
12984 * SUCH DAMAGE.
12985 */