blob: 334d2fdddc37c225a59badf3bed3d534ad1fa17a [file] [log] [blame]
Eric Andersendf82f612001-06-28 07:46:40 +00001/* vi: set sw=4 ts=4: */
2/*
3 * ash shell port for busybox
4 *
5 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +00006 * The Regents of the University of California. All rights reserved.
Eric Andersencb57d552001-06-28 07:25:16 +00007 *
8 * This code is derived from software contributed to Berkeley by
9 * Kenneth Almquist.
10 *
Eric Andersendf82f612001-06-28 07:46:40 +000011 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
Eric Andersencb57d552001-06-28 07:25:16 +000015 *
Eric Andersendf82f612001-06-28 07:46:40 +000016 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
Eric Andersen2870d962001-07-02 17:27:21 +000025 * This version of ash is adapted from the source in Debian's ash 0.3.8-5
26 * package.
Eric Andersendf82f612001-06-28 07:46:40 +000027 *
Eric Andersen2870d962001-07-02 17:27:21 +000028 * Modified by Erik Andersen <andersee@debian.org> and
Eric Andersen7467c8d2001-07-12 20:26:32 +000029 * Vladimir Oleynik <dzo@simtreas.ru> to be used in busybox
Eric Andersen2870d962001-07-02 17:27:21 +000030 *
Eric Andersendf82f612001-06-28 07:46:40 +000031 *
32 * Original copyright notice is retained at the end of this file.
Eric Andersencb57d552001-06-28 07:25:16 +000033 */
34
Eric Andersen2870d962001-07-02 17:27:21 +000035
36/* These defines allow you to adjust the feature set to be compiled
37 * into the ash shell. As a rule, enabling these options will make
38 * ash get bigger... With all of these options off, ash adds about
Eric Andersen62483552001-07-10 06:09:16 +000039 * 60k to busybox on an x86 system.*/
Eric Andersen2870d962001-07-02 17:27:21 +000040
41
42/* Enable job control. This allows you to run jobs in the background,
43 * which is great when ash is being used as an interactive shell, but
Eric Andersen3102ac42001-07-06 04:26:23 +000044 * it completely useless for is all you are doing is running scripts.
Eric Andersen2870d962001-07-02 17:27:21 +000045 * This adds about 2.5k on an x86 system. */
Eric Andersen62483552001-07-10 06:09:16 +000046#undef JOBS
Eric Andersen2870d962001-07-02 17:27:21 +000047
48/* This enables alias support in ash. If you want to support things
49 * like "alias ls='ls -l'" with ash, enable this. This is only useful
50 * when ash is used as an intractive shell. This adds about 1.5k */
51#define ASH_ALIAS
52
53/* If you need ash to act as a full Posix shell, with full math
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;
Eric Andersen7467c8d2001-07-12 20:26:32 +00004998 i = safe_read(in.fd, buf, sizeof buf);
Eric Andersencb57d552001-06-28 07:25:16 +00004999 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/* 1 == check for aliases, 2 == also check for assignments */
Eric Andersen7467c8d2001-07-12 20:26:32 +00006095static int checkalias; /* also used in no alias mode for check assignments */
Eric Andersen2870d962001-07-02 17:27:21 +00006096
Eric Andersencb57d552001-06-28 07:25:16 +00006097static void
Eric Andersen2870d962001-07-02 17:27:21 +00006098reset(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00006099
6100 /* from eval.c: */
6101 {
6102 evalskip = 0;
6103 loopnest = 0;
6104 funcnest = 0;
6105 }
6106
6107 /* from input.c: */
6108 {
6109 if (exception != EXSHELLPROC)
Eric Andersen2870d962001-07-02 17:27:21 +00006110 parselleft = parsenleft = 0; /* clear input buffer */
Eric Andersencb57d552001-06-28 07:25:16 +00006111 popallfiles();
6112 }
6113
6114 /* from parser.c: */
6115 {
6116 tokpushback = 0;
6117 checkkwd = 0;
6118 checkalias = 0;
6119 }
6120
6121 /* from redir.c: */
6122 {
6123 while (redirlist)
6124 popredir();
6125 }
6126
Eric Andersencb57d552001-06-28 07:25:16 +00006127}
6128
6129
6130
6131/*
Eric Andersencb57d552001-06-28 07:25:16 +00006132 * This file implements the input routines used by the parser.
6133 */
6134
6135#ifdef BB_FEATURE_COMMAND_EDITING
Eric Andersencb57d552001-06-28 07:25:16 +00006136static const char * cmdedit_prompt;
6137static inline void putprompt(const char *s) {
6138 cmdedit_prompt = s;
6139}
6140#else
6141static inline void putprompt(const char *s) {
6142 out2str(s);
6143}
6144#endif
6145
Eric Andersen2870d962001-07-02 17:27:21 +00006146#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
Eric Andersencb57d552001-06-28 07:25:16 +00006147
Eric Andersencb57d552001-06-28 07:25:16 +00006148
Eric Andersencb57d552001-06-28 07:25:16 +00006149
Eric Andersen2870d962001-07-02 17:27:21 +00006150/*
6151 * Same as pgetc(), but ignores PEOA.
6152 */
Eric Andersencb57d552001-06-28 07:25:16 +00006153
Eric Andersen2870d962001-07-02 17:27:21 +00006154#ifdef ASH_ALIAS
6155static int
6156pgetc2()
6157{
6158 int c;
6159 do {
6160 c = pgetc_macro();
6161 } while (c == PEOA);
6162 return c;
Eric Andersencb57d552001-06-28 07:25:16 +00006163}
Eric Andersen2870d962001-07-02 17:27:21 +00006164#else
6165static inline int pgetc2() { return pgetc_macro(); }
Eric Andersencb57d552001-06-28 07:25:16 +00006166#endif
6167
Eric Andersencb57d552001-06-28 07:25:16 +00006168/*
6169 * Read a line from the script.
6170 */
6171
Eric Andersen62483552001-07-10 06:09:16 +00006172static inline char *
Eric Andersen2870d962001-07-02 17:27:21 +00006173pfgets(char *line, int len)
Eric Andersencb57d552001-06-28 07:25:16 +00006174{
6175 char *p = line;
6176 int nleft = len;
6177 int c;
6178
6179 while (--nleft > 0) {
6180 c = pgetc2();
6181 if (c == PEOF) {
6182 if (p == line)
6183 return NULL;
6184 break;
6185 }
6186 *p++ = c;
6187 if (c == '\n')
6188 break;
6189 }
6190 *p = '\0';
6191 return line;
6192}
6193
Eric Andersen62483552001-07-10 06:09:16 +00006194static inline int
Eric Andersen2870d962001-07-02 17:27:21 +00006195preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006196{
6197 int nr;
6198 char *buf = parsefile->buf;
6199 parsenextc = buf;
6200
6201retry:
6202#ifdef BB_FEATURE_COMMAND_EDITING
6203 {
Eric Andersen7467c8d2001-07-12 20:26:32 +00006204 if (!iflag)
6205 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersen2870d962001-07-02 17:27:21 +00006206 else {
Eric Andersencb57d552001-06-28 07:25:16 +00006207 cmdedit_read_input((char*)cmdedit_prompt, buf);
6208 nr = strlen(buf);
Eric Andersencb57d552001-06-28 07:25:16 +00006209 }
6210 }
6211#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00006212 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006213#endif
6214
6215 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006216 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6217 int flags = fcntl(0, F_GETFL, 0);
6218 if (flags >= 0 && flags & O_NONBLOCK) {
6219 flags &=~ O_NONBLOCK;
6220 if (fcntl(0, F_SETFL, flags) >= 0) {
6221 out2str("sh: turning off NDELAY mode\n");
6222 goto retry;
6223 }
6224 }
6225 }
6226 }
6227 return nr;
6228}
6229
Eric Andersen2870d962001-07-02 17:27:21 +00006230static void
6231popstring(void)
6232{
6233 struct strpush *sp = parsefile->strpush;
6234
6235 INTOFF;
6236#ifdef ASH_ALIAS
6237 if (sp->ap) {
6238 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6239 if (!checkalias) {
6240 checkalias = 1;
6241 }
6242 }
6243 if (sp->string != sp->ap->val) {
6244 ckfree(sp->string);
6245 }
6246
6247 sp->ap->flag &= ~ALIASINUSE;
6248 if (sp->ap->flag & ALIASDEAD) {
6249 unalias(sp->ap->name);
6250 }
6251 }
6252#endif
6253 parsenextc = sp->prevstring;
6254 parsenleft = sp->prevnleft;
6255/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6256 parsefile->strpush = sp->prev;
6257 if (sp != &(parsefile->basestrpush))
6258 ckfree(sp);
6259 INTON;
6260}
6261
6262
Eric Andersencb57d552001-06-28 07:25:16 +00006263/*
6264 * Refill the input buffer and return the next input character:
6265 *
6266 * 1) If a string was pushed back on the input, pop it;
6267 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6268 * from a string so we can't refill the buffer, return EOF.
6269 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6270 * 4) Process input up to the next newline, deleting nul characters.
6271 */
6272
6273static int
Eric Andersen2870d962001-07-02 17:27:21 +00006274preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006275{
6276 char *p, *q;
6277 int more;
6278 char savec;
6279
6280 while (parsefile->strpush) {
Eric Andersen2870d962001-07-02 17:27:21 +00006281#ifdef ASH_ALIAS
6282 if (parsenleft == -1 && parsefile->strpush->ap &&
6283 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00006284 return PEOA;
6285 }
Eric Andersen2870d962001-07-02 17:27:21 +00006286#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006287 popstring();
6288 if (--parsenleft >= 0)
6289 return (*parsenextc++);
6290 }
6291 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6292 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00006293 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00006294
6295again:
6296 if (parselleft <= 0) {
6297 if ((parselleft = preadfd()) <= 0) {
6298 parselleft = parsenleft = EOF_NLEFT;
6299 return PEOF;
6300 }
6301 }
6302
6303 q = p = parsenextc;
6304
6305 /* delete nul characters */
6306 for (more = 1; more;) {
6307 switch (*p) {
6308 case '\0':
Eric Andersen2870d962001-07-02 17:27:21 +00006309 p++; /* Skip nul */
Eric Andersencb57d552001-06-28 07:25:16 +00006310 goto check;
6311
6312
6313 case '\n':
6314 parsenleft = q - parsenextc;
6315 more = 0; /* Stop processing here */
6316 break;
6317 }
6318
6319 *q++ = *p++;
6320check:
6321 if (--parselleft <= 0 && more) {
6322 parsenleft = q - parsenextc - 1;
6323 if (parsenleft < 0)
6324 goto again;
6325 more = 0;
6326 }
6327 }
6328
6329 savec = *q;
6330 *q = '\0';
6331
6332 if (vflag) {
6333 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00006334 }
6335
6336 *q = savec;
6337
6338 return *parsenextc++;
6339}
6340
Eric Andersencb57d552001-06-28 07:25:16 +00006341
6342/*
6343 * Push a string back onto the input at this current parsefile level.
6344 * We handle aliases this way.
6345 */
6346static void
Eric Andersen2870d962001-07-02 17:27:21 +00006347pushstring(char *s, int len, void *ap)
6348{
Eric Andersencb57d552001-06-28 07:25:16 +00006349 struct strpush *sp;
6350
6351 INTOFF;
6352/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6353 if (parsefile->strpush) {
6354 sp = ckmalloc(sizeof (struct strpush));
6355 sp->prev = parsefile->strpush;
6356 parsefile->strpush = sp;
6357 } else
6358 sp = parsefile->strpush = &(parsefile->basestrpush);
6359 sp->prevstring = parsenextc;
6360 sp->prevnleft = parsenleft;
Eric Andersen2870d962001-07-02 17:27:21 +00006361#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00006362 sp->ap = (struct alias *)ap;
6363 if (ap) {
6364 ((struct alias *)ap)->flag |= ALIASINUSE;
6365 sp->string = s;
6366 }
Eric Andersen2870d962001-07-02 17:27:21 +00006367#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006368 parsenextc = s;
6369 parsenleft = len;
6370 INTON;
6371}
6372
Eric Andersencb57d552001-06-28 07:25:16 +00006373
Eric Andersencb57d552001-06-28 07:25:16 +00006374/*
6375 * Like setinputfile, but takes input from a string.
6376 */
6377
6378static void
Eric Andersen62483552001-07-10 06:09:16 +00006379setinputstring(char *string)
6380{
Eric Andersencb57d552001-06-28 07:25:16 +00006381 INTOFF;
6382 pushfile();
6383 parsenextc = string;
6384 parsenleft = strlen(string);
6385 parsefile->buf = NULL;
6386 plinno = 1;
6387 INTON;
6388}
6389
6390
6391
6392/*
6393 * To handle the "." command, a stack of input files is used. Pushfile
6394 * adds a new entry to the stack and popfile restores the previous level.
6395 */
6396
6397static void
Eric Andersen2870d962001-07-02 17:27:21 +00006398pushfile(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00006399 struct parsefile *pf;
6400
6401 parsefile->nleft = parsenleft;
6402 parsefile->lleft = parselleft;
6403 parsefile->nextc = parsenextc;
6404 parsefile->linno = plinno;
6405 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6406 pf->prev = parsefile;
6407 pf->fd = -1;
6408 pf->strpush = NULL;
6409 pf->basestrpush.prev = NULL;
6410 parsefile = pf;
6411}
6412
Eric Andersen2870d962001-07-02 17:27:21 +00006413#ifdef JOBS
6414static void restartjob (struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00006415#endif
Eric Andersen2870d962001-07-02 17:27:21 +00006416static void freejob (struct job *);
6417static struct job *getjob (const char *);
6418static int dowait (int, struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00006419static void waitonint(int);
6420
6421
Eric Andersen2870d962001-07-02 17:27:21 +00006422/*
6423 * We keep track of whether or not fd0 has been redirected. This is for
6424 * background commands, where we want to redirect fd0 to /dev/null only
6425 * if it hasn't already been redirected.
6426*/
6427static int fd0_redirected = 0;
6428
6429/* Return true if fd 0 has already been redirected at least once. */
6430static inline int
6431fd0_redirected_p () {
6432 return fd0_redirected != 0;
6433}
6434
Eric Andersen62483552001-07-10 06:09:16 +00006435static void dupredirect (const union node *, int, int fd1dup);
Eric Andersen2870d962001-07-02 17:27:21 +00006436
6437#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006438/*
6439 * Turn job control on and off.
6440 *
6441 * Note: This code assumes that the third arg to ioctl is a character
6442 * pointer, which is true on Berkeley systems but not System V. Since
6443 * System V doesn't have job control yet, this isn't a problem now.
6444 */
6445
Eric Andersen2870d962001-07-02 17:27:21 +00006446
Eric Andersencb57d552001-06-28 07:25:16 +00006447
6448static void setjobctl(int enable)
6449{
6450#ifdef OLD_TTY_DRIVER
6451 int ldisc;
6452#endif
6453
6454 if (enable == jobctl || rootshell == 0)
6455 return;
6456 if (enable) {
6457 do { /* while we are in the background */
6458#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006459 if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006460#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006461 initialpgrp = tcgetpgrp(2);
Eric Andersencb57d552001-06-28 07:25:16 +00006462 if (initialpgrp < 0) {
6463#endif
Eric Andersen8c145dc2001-07-10 16:57:09 +00006464 out2str("sh: can't access tty; job control turned off\n");
Eric Andersencb57d552001-06-28 07:25:16 +00006465 mflag = 0;
6466 return;
6467 }
6468 if (initialpgrp == -1)
6469 initialpgrp = getpgrp();
6470 else if (initialpgrp != getpgrp()) {
6471 killpg(initialpgrp, SIGTTIN);
6472 continue;
6473 }
6474 } while (0);
6475#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006476 if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
Eric Andersen8c145dc2001-07-10 16:57:09 +00006477 out2str("sh: need new tty driver to run job control; job control turned off\n");
Eric Andersencb57d552001-06-28 07:25:16 +00006478 mflag = 0;
6479 return;
6480 }
6481#endif
6482 setsignal(SIGTSTP);
6483 setsignal(SIGTTOU);
6484 setsignal(SIGTTIN);
6485 setpgid(0, rootpid);
6486#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006487 ioctl(2, TIOCSPGRP, (char *)&rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00006488#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006489 tcsetpgrp(2, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00006490#endif
Eric Andersen8c145dc2001-07-10 16:57:09 +00006491 } else { /* turning job control off */
Eric Andersencb57d552001-06-28 07:25:16 +00006492 setpgid(0, initialpgrp);
6493#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006494 ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006495#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006496 tcsetpgrp(2, initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006497#endif
6498 setsignal(SIGTSTP);
6499 setsignal(SIGTTOU);
6500 setsignal(SIGTTIN);
6501 }
6502 jobctl = enable;
6503}
6504#endif
6505
6506
Eric Andersencb57d552001-06-28 07:25:16 +00006507/* A translation list so we can be polite to our users. */
6508static char *signal_names[NSIG + 2] = {
6509 "EXIT",
6510 "SIGHUP",
6511 "SIGINT",
6512 "SIGQUIT",
6513 "SIGILL",
6514 "SIGTRAP",
6515 "SIGABRT",
6516 "SIGBUS",
6517 "SIGFPE",
6518 "SIGKILL",
6519 "SIGUSR1",
6520 "SIGSEGV",
6521 "SIGUSR2",
6522 "SIGPIPE",
6523 "SIGALRM",
6524 "SIGTERM",
6525 "SIGJUNK(16)",
6526 "SIGCHLD",
6527 "SIGCONT",
6528 "SIGSTOP",
6529 "SIGTSTP",
6530 "SIGTTIN",
6531 "SIGTTOU",
6532 "SIGURG",
6533 "SIGXCPU",
6534 "SIGXFSZ",
6535 "SIGVTALRM",
6536 "SIGPROF",
6537 "SIGWINCH",
6538 "SIGIO",
6539 "SIGPWR",
6540 "SIGSYS",
Eric Andersen62483552001-07-10 06:09:16 +00006541#ifdef SIGRTMIN
Eric Andersencb57d552001-06-28 07:25:16 +00006542 "SIGRTMIN",
6543 "SIGRTMIN+1",
6544 "SIGRTMIN+2",
6545 "SIGRTMIN+3",
6546 "SIGRTMIN+4",
6547 "SIGRTMIN+5",
6548 "SIGRTMIN+6",
6549 "SIGRTMIN+7",
6550 "SIGRTMIN+8",
6551 "SIGRTMIN+9",
6552 "SIGRTMIN+10",
6553 "SIGRTMIN+11",
6554 "SIGRTMIN+12",
6555 "SIGRTMIN+13",
6556 "SIGRTMIN+14",
6557 "SIGRTMIN+15",
6558 "SIGRTMAX-15",
6559 "SIGRTMAX-14",
6560 "SIGRTMAX-13",
6561 "SIGRTMAX-12",
6562 "SIGRTMAX-11",
6563 "SIGRTMAX-10",
6564 "SIGRTMAX-9",
6565 "SIGRTMAX-8",
6566 "SIGRTMAX-7",
6567 "SIGRTMAX-6",
6568 "SIGRTMAX-5",
6569 "SIGRTMAX-4",
6570 "SIGRTMAX-3",
6571 "SIGRTMAX-2",
6572 "SIGRTMAX-1",
6573 "SIGRTMAX",
Eric Andersen62483552001-07-10 06:09:16 +00006574#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006575 "DEBUG",
6576 (char *)0x0,
6577};
6578
6579
6580
Eric Andersen2870d962001-07-02 17:27:21 +00006581#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006582static int
6583killcmd(argc, argv)
6584 int argc;
6585 char **argv;
6586{
6587 int signo = -1;
6588 int list = 0;
6589 int i;
6590 pid_t pid;
6591 struct job *jp;
6592
6593 if (argc <= 1) {
6594usage:
6595 error(
6596"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6597"kill -l [exitstatus]"
6598 );
6599 }
6600
6601 if (*argv[1] == '-') {
6602 signo = decode_signal(argv[1] + 1, 1);
6603 if (signo < 0) {
6604 int c;
6605
6606 while ((c = nextopt("ls:")) != '\0')
6607 switch (c) {
6608 case 'l':
6609 list = 1;
6610 break;
6611 case 's':
6612 signo = decode_signal(optionarg, 1);
6613 if (signo < 0) {
6614 error(
6615 "invalid signal number or name: %s",
6616 optionarg
6617 );
6618 }
Eric Andersen2870d962001-07-02 17:27:21 +00006619 break;
Eric Andersencb57d552001-06-28 07:25:16 +00006620#ifdef DEBUG
6621 default:
6622 error(
6623 "nextopt returned character code 0%o", c);
6624#endif
6625 }
6626 } else
6627 argptr++;
6628 }
6629
6630 if (!list && signo < 0)
6631 signo = SIGTERM;
6632
6633 if ((signo < 0 || !*argptr) ^ list) {
6634 goto usage;
6635 }
6636
6637 if (list) {
6638 if (!*argptr) {
6639 out1str("0\n");
6640 for (i = 1; i < NSIG; i++) {
Eric Andersen62483552001-07-10 06:09:16 +00006641 printf(snlfmt, signal_names[i] + 3);
Eric Andersencb57d552001-06-28 07:25:16 +00006642 }
6643 return 0;
6644 }
6645 signo = atoi(*argptr);
6646 if (signo > 128)
6647 signo -= 128;
6648 if (0 < signo && signo < NSIG)
Eric Andersen62483552001-07-10 06:09:16 +00006649 printf(snlfmt, signal_names[signo] + 3);
Eric Andersencb57d552001-06-28 07:25:16 +00006650 else
6651 error("invalid signal number or exit status: %s",
6652 *argptr);
6653 return 0;
6654 }
6655
6656 do {
6657 if (**argptr == '%') {
6658 jp = getjob(*argptr);
6659 if (jp->jobctl == 0)
6660 error("job %s not created under job control",
6661 *argptr);
6662 pid = -jp->ps[0].pid;
6663 } else
6664 pid = atoi(*argptr);
6665 if (kill(pid, signo) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00006666 error("%s: %m", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006667 } while (*++argptr);
6668
6669 return 0;
6670}
6671
6672static int
6673fgcmd(argc, argv)
6674 int argc;
6675 char **argv;
6676{
6677 struct job *jp;
6678 int pgrp;
6679 int status;
6680
6681 jp = getjob(argv[1]);
6682 if (jp->jobctl == 0)
6683 error("job not created under job control");
6684 pgrp = jp->ps[0].pid;
6685#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006686 ioctl(2, TIOCSPGRP, (char *)&pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006687#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006688 tcsetpgrp(2, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006689#endif
6690 restartjob(jp);
6691 INTOFF;
6692 status = waitforjob(jp);
6693 INTON;
6694 return status;
6695}
6696
6697
6698static int
6699bgcmd(argc, argv)
6700 int argc;
6701 char **argv;
6702{
6703 struct job *jp;
6704
6705 do {
6706 jp = getjob(*++argv);
6707 if (jp->jobctl == 0)
6708 error("job not created under job control");
6709 restartjob(jp);
6710 } while (--argc > 1);
6711 return 0;
6712}
6713
6714
6715static void
6716restartjob(jp)
6717 struct job *jp;
6718{
6719 struct procstat *ps;
6720 int i;
6721
6722 if (jp->state == JOBDONE)
6723 return;
6724 INTOFF;
6725 killpg(jp->ps[0].pid, SIGCONT);
6726 for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
6727 if (WIFSTOPPED(ps->status)) {
6728 ps->status = -1;
6729 jp->state = 0;
6730 }
6731 }
6732 INTON;
6733}
6734#endif
6735
Eric Andersen2870d962001-07-02 17:27:21 +00006736static void showjobs(int change);
6737
Eric Andersencb57d552001-06-28 07:25:16 +00006738
6739static int
6740jobscmd(argc, argv)
6741 int argc;
6742 char **argv;
6743{
6744 showjobs(0);
6745 return 0;
6746}
6747
6748
6749/*
6750 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6751 * statuses have changed since the last call to showjobs.
6752 *
6753 * If the shell is interrupted in the process of creating a job, the
6754 * result may be a job structure containing zero processes. Such structures
6755 * will be freed here.
6756 */
6757
6758static void
6759showjobs(change)
6760 int change;
6761{
6762 int jobno;
6763 int procno;
6764 int i;
6765 struct job *jp;
6766 struct procstat *ps;
6767 int col;
6768 char s[64];
6769
6770 TRACE(("showjobs(%d) called\n", change));
6771 while (dowait(0, (struct job *)NULL) > 0);
6772 for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
6773 if (! jp->used)
6774 continue;
6775 if (jp->nprocs == 0) {
6776 freejob(jp);
6777 continue;
6778 }
6779 if (change && ! jp->changed)
6780 continue;
6781 procno = jp->nprocs;
Eric Andersen2870d962001-07-02 17:27:21 +00006782 for (ps = jp->ps ; ; ps++) { /* for each process */
Eric Andersencb57d552001-06-28 07:25:16 +00006783 if (ps == jp->ps)
Eric Andersen3102ac42001-07-06 04:26:23 +00006784 snprintf(s, 64, "[%d] %ld ", jobno,
Eric Andersencb57d552001-06-28 07:25:16 +00006785 (long)ps->pid);
6786 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006787 snprintf(s, 64, " %ld ",
Eric Andersencb57d552001-06-28 07:25:16 +00006788 (long)ps->pid);
6789 out1str(s);
6790 col = strlen(s);
6791 s[0] = '\0';
6792 if (ps->status == -1) {
6793 /* don't print anything */
6794 } else if (WIFEXITED(ps->status)) {
Eric Andersen3102ac42001-07-06 04:26:23 +00006795 snprintf(s, 64, "Exit %d",
Eric Andersencb57d552001-06-28 07:25:16 +00006796 WEXITSTATUS(ps->status));
6797 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00006798#ifdef JOBS
6799 if (WIFSTOPPED(ps->status))
Eric Andersencb57d552001-06-28 07:25:16 +00006800 i = WSTOPSIG(ps->status);
6801 else /* WIFSIGNALED(ps->status) */
6802#endif
6803 i = WTERMSIG(ps->status);
6804 if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
Eric Andersen2870d962001-07-02 17:27:21 +00006805 strcpy(s, sys_siglist[i & 0x7F]);
Eric Andersencb57d552001-06-28 07:25:16 +00006806 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006807 snprintf(s, 64, "Signal %d", i & 0x7F);
Eric Andersencb57d552001-06-28 07:25:16 +00006808 if (WCOREDUMP(ps->status))
6809 strcat(s, " (core dumped)");
6810 }
6811 out1str(s);
6812 col += strlen(s);
Eric Andersen62483552001-07-10 06:09:16 +00006813 printf(
Eric Andersencb57d552001-06-28 07:25:16 +00006814 "%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ',
6815 ps->cmd
6816 );
6817 if (--procno <= 0)
6818 break;
6819 }
6820 jp->changed = 0;
6821 if (jp->state == JOBDONE) {
6822 freejob(jp);
6823 }
6824 }
6825}
6826
6827
6828/*
6829 * Mark a job structure as unused.
6830 */
6831
6832static void
Eric Andersen62483552001-07-10 06:09:16 +00006833freejob(struct job *jp)
6834{
6835 const struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006836 int i;
6837
6838 INTOFF;
6839 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6840 if (ps->cmd != nullstr)
6841 ckfree(ps->cmd);
6842 }
6843 if (jp->ps != &jp->ps0)
6844 ckfree(jp->ps);
6845 jp->used = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006846#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006847 if (curjob == jp - jobtab + 1)
6848 curjob = 0;
6849#endif
6850 INTON;
6851}
6852
6853
6854
6855static int
6856waitcmd(argc, argv)
6857 int argc;
6858 char **argv;
6859{
6860 struct job *job;
6861 int status, retval;
6862 struct job *jp;
6863
6864 if (--argc > 0) {
6865start:
6866 job = getjob(*++argv);
6867 } else {
6868 job = NULL;
6869 }
Eric Andersen2870d962001-07-02 17:27:21 +00006870 for (;;) { /* loop until process terminated or stopped */
Eric Andersencb57d552001-06-28 07:25:16 +00006871 if (job != NULL) {
6872 if (job->state) {
6873 status = job->ps[job->nprocs - 1].status;
6874 if (! iflag)
6875 freejob(job);
6876 if (--argc) {
6877 goto start;
6878 }
6879 if (WIFEXITED(status))
6880 retval = WEXITSTATUS(status);
Eric Andersen2870d962001-07-02 17:27:21 +00006881#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006882 else if (WIFSTOPPED(status))
6883 retval = WSTOPSIG(status) + 128;
6884#endif
6885 else {
6886 /* XXX: limits number of signals */
6887 retval = WTERMSIG(status) + 128;
6888 }
6889 return retval;
6890 }
6891 } else {
6892 for (jp = jobtab ; ; jp++) {
Eric Andersen2870d962001-07-02 17:27:21 +00006893 if (jp >= jobtab + njobs) { /* no running procs */
Eric Andersencb57d552001-06-28 07:25:16 +00006894 return 0;
6895 }
6896 if (jp->used && jp->state == 0)
6897 break;
6898 }
6899 }
6900 if (dowait(2, 0) < 0 && errno == EINTR) {
6901 return 129;
6902 }
6903 }
6904}
6905
6906
6907
6908/*
6909 * Convert a job name to a job structure.
6910 */
6911
6912static struct job *
Eric Andersen2870d962001-07-02 17:27:21 +00006913getjob(const char *name)
6914{
Eric Andersencb57d552001-06-28 07:25:16 +00006915 int jobno;
6916 struct job *jp;
6917 int pid;
6918 int i;
6919
6920 if (name == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00006921#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006922currentjob:
6923 if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
6924 error("No current job");
6925 return &jobtab[jobno - 1];
6926#else
6927 error("No current job");
6928#endif
6929 } else if (name[0] == '%') {
6930 if (is_digit(name[1])) {
6931 jobno = number(name + 1);
6932 if (jobno > 0 && jobno <= njobs
6933 && jobtab[jobno - 1].used != 0)
6934 return &jobtab[jobno - 1];
Eric Andersen2870d962001-07-02 17:27:21 +00006935#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006936 } else if (name[1] == '%' && name[2] == '\0') {
6937 goto currentjob;
6938#endif
6939 } else {
6940 struct job *found = NULL;
6941 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
6942 if (jp->used && jp->nprocs > 0
6943 && prefix(name + 1, jp->ps[0].cmd)) {
6944 if (found)
6945 error("%s: ambiguous", name);
6946 found = jp;
6947 }
6948 }
6949 if (found)
6950 return found;
6951 }
Eric Andersen2870d962001-07-02 17:27:21 +00006952 } else if (is_number(name, &pid)) {
Eric Andersencb57d552001-06-28 07:25:16 +00006953 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
6954 if (jp->used && jp->nprocs > 0
6955 && jp->ps[jp->nprocs - 1].pid == pid)
6956 return jp;
6957 }
6958 }
6959 error("No such job: %s", name);
6960 /* NOTREACHED */
6961}
6962
6963
6964
6965/*
6966 * Return a new job structure,
6967 */
6968
Eric Andersen2870d962001-07-02 17:27:21 +00006969static struct job *
Eric Andersen62483552001-07-10 06:09:16 +00006970makejob(const union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00006971{
6972 int i;
6973 struct job *jp;
6974
6975 for (i = njobs, jp = jobtab ; ; jp++) {
6976 if (--i < 0) {
6977 INTOFF;
6978 if (njobs == 0) {
6979 jobtab = ckmalloc(4 * sizeof jobtab[0]);
6980 } else {
6981 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
6982 memcpy(jp, jobtab, njobs * sizeof jp[0]);
6983 /* Relocate `ps' pointers */
6984 for (i = 0; i < njobs; i++)
6985 if (jp[i].ps == &jobtab[i].ps0)
6986 jp[i].ps = &jp[i].ps0;
6987 ckfree(jobtab);
6988 jobtab = jp;
6989 }
6990 jp = jobtab + njobs;
6991 for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
6992 INTON;
6993 break;
6994 }
6995 if (jp->used == 0)
6996 break;
6997 }
6998 INTOFF;
6999 jp->state = 0;
7000 jp->used = 1;
7001 jp->changed = 0;
7002 jp->nprocs = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00007003#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007004 jp->jobctl = jobctl;
7005#endif
7006 if (nprocs > 1) {
7007 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7008 } else {
7009 jp->ps = &jp->ps0;
7010 }
7011 INTON;
7012 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7013 jp - jobtab + 1));
7014 return jp;
7015}
7016
7017
7018/*
7019 * Fork of a subshell. If we are doing job control, give the subshell its
7020 * own process group. Jp is a job structure that the job is to be added to.
7021 * N is the command that will be evaluated by the child. Both jp and n may
7022 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00007023 * FORK_FG - Fork off a foreground process.
7024 * FORK_BG - Fork off a background process.
7025 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7026 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00007027 *
7028 * When job control is turned off, background processes have their standard
7029 * input redirected to /dev/null (except for the second and later processes
7030 * in a pipeline).
7031 */
7032
Eric Andersen2870d962001-07-02 17:27:21 +00007033
7034
Eric Andersencb57d552001-06-28 07:25:16 +00007035static int
Eric Andersen62483552001-07-10 06:09:16 +00007036forkshell(struct job *jp, const union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00007037{
7038 int pid;
Eric Andersen62483552001-07-10 06:09:16 +00007039#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007040 int pgrp;
Eric Andersen62483552001-07-10 06:09:16 +00007041#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007042 const char *devnull = _PATH_DEVNULL;
7043 const char *nullerr = "Can't open %s";
7044
7045 TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
7046 mode));
7047 INTOFF;
7048 pid = fork();
7049 if (pid == -1) {
7050 TRACE(("Fork failed, errno=%d\n", errno));
7051 INTON;
7052 error("Cannot fork");
7053 }
7054 if (pid == 0) {
7055 struct job *p;
7056 int wasroot;
7057 int i;
7058
7059 TRACE(("Child shell %d\n", getpid()));
7060 wasroot = rootshell;
7061 rootshell = 0;
7062 closescript();
7063 INTON;
7064 clear_traps();
Eric Andersen2870d962001-07-02 17:27:21 +00007065#ifdef JOBS
7066 jobctl = 0; /* do job control only in root shell */
Eric Andersencb57d552001-06-28 07:25:16 +00007067 if (wasroot && mode != FORK_NOJOB && mflag) {
7068 if (jp == NULL || jp->nprocs == 0)
7069 pgrp = getpid();
7070 else
7071 pgrp = jp->ps[0].pid;
7072 setpgid(0, pgrp);
7073 if (mode == FORK_FG) {
7074 /*** this causes superfluous TIOCSPGRPS ***/
7075#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00007076 if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007077 error("TIOCSPGRP failed, errno=%d", errno);
7078#else
Eric Andersen3102ac42001-07-06 04:26:23 +00007079 if (tcsetpgrp(2, pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007080 error("tcsetpgrp failed, errno=%d", errno);
7081#endif
7082 }
7083 setsignal(SIGTSTP);
7084 setsignal(SIGTTOU);
7085 } else if (mode == FORK_BG) {
7086 ignoresig(SIGINT);
7087 ignoresig(SIGQUIT);
7088 if ((jp == NULL || jp->nprocs == 0) &&
7089 ! fd0_redirected_p ()) {
7090 close(0);
7091 if (open(devnull, O_RDONLY) != 0)
7092 error(nullerr, devnull);
7093 }
7094 }
7095#else
7096 if (mode == FORK_BG) {
7097 ignoresig(SIGINT);
7098 ignoresig(SIGQUIT);
7099 if ((jp == NULL || jp->nprocs == 0) &&
7100 ! fd0_redirected_p ()) {
7101 close(0);
7102 if (open(devnull, O_RDONLY) != 0)
7103 error(nullerr, devnull);
7104 }
7105 }
7106#endif
7107 for (i = njobs, p = jobtab ; --i >= 0 ; p++)
7108 if (p->used)
7109 freejob(p);
7110 if (wasroot && iflag) {
7111 setsignal(SIGINT);
7112 setsignal(SIGQUIT);
7113 setsignal(SIGTERM);
7114 }
7115 return pid;
7116 }
Eric Andersen62483552001-07-10 06:09:16 +00007117#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007118 if (rootshell && mode != FORK_NOJOB && mflag) {
7119 if (jp == NULL || jp->nprocs == 0)
7120 pgrp = pid;
7121 else
7122 pgrp = jp->ps[0].pid;
7123 setpgid(pid, pgrp);
7124 }
Eric Andersen62483552001-07-10 06:09:16 +00007125#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007126 if (mode == FORK_BG)
Eric Andersen2870d962001-07-02 17:27:21 +00007127 backgndpid = pid; /* set $! */
Eric Andersencb57d552001-06-28 07:25:16 +00007128 if (jp) {
7129 struct procstat *ps = &jp->ps[jp->nprocs++];
7130 ps->pid = pid;
7131 ps->status = -1;
7132 ps->cmd = nullstr;
7133 if (iflag && rootshell && n)
7134 ps->cmd = commandtext(n);
7135 }
7136 INTON;
7137 TRACE(("In parent shell: child = %d\n", pid));
7138 return pid;
7139}
7140
7141
7142
7143/*
7144 * Wait for job to finish.
7145 *
7146 * Under job control we have the problem that while a child process is
7147 * running interrupts generated by the user are sent to the child but not
7148 * to the shell. This means that an infinite loop started by an inter-
7149 * active user may be hard to kill. With job control turned off, an
7150 * interactive user may place an interactive program inside a loop. If
7151 * the interactive program catches interrupts, the user doesn't want
7152 * these interrupts to also abort the loop. The approach we take here
7153 * is to have the shell ignore interrupt signals while waiting for a
7154 * forground process to terminate, and then send itself an interrupt
7155 * signal if the child process was terminated by an interrupt signal.
7156 * Unfortunately, some programs want to do a bit of cleanup and then
7157 * exit on interrupt; unless these processes terminate themselves by
7158 * sending a signal to themselves (instead of calling exit) they will
7159 * confuse this approach.
7160 */
7161
7162static int
Eric Andersen62483552001-07-10 06:09:16 +00007163waitforjob(struct job *jp)
7164{
Eric Andersen2870d962001-07-02 17:27:21 +00007165#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007166 int mypgrp = getpgrp();
7167#endif
7168 int status;
7169 int st;
7170 struct sigaction act, oact;
7171
7172 INTOFF;
7173 intreceived = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00007174#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007175 if (!jobctl) {
7176#else
7177 if (!iflag) {
7178#endif
7179 sigaction(SIGINT, 0, &act);
7180 act.sa_handler = waitonint;
7181 sigaction(SIGINT, &act, &oact);
7182 }
7183 TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
7184 while (jp->state == 0) {
7185 dowait(1, jp);
7186 }
Eric Andersen2870d962001-07-02 17:27:21 +00007187#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007188 if (!jobctl) {
7189#else
7190 if (!iflag) {
7191#endif
7192 sigaction(SIGINT, &oact, 0);
7193 if (intreceived && trap[SIGINT]) kill(getpid(), SIGINT);
7194 }
Eric Andersen2870d962001-07-02 17:27:21 +00007195#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007196 if (jp->jobctl) {
7197#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00007198 if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007199 error("TIOCSPGRP failed, errno=%d\n", errno);
7200#else
Eric Andersen3102ac42001-07-06 04:26:23 +00007201 if (tcsetpgrp(2, mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007202 error("tcsetpgrp failed, errno=%d\n", errno);
7203#endif
7204 }
7205 if (jp->state == JOBSTOPPED)
7206 curjob = jp - jobtab + 1;
7207#endif
7208 status = jp->ps[jp->nprocs - 1].status;
7209 /* convert to 8 bits */
7210 if (WIFEXITED(status))
7211 st = WEXITSTATUS(status);
Eric Andersen2870d962001-07-02 17:27:21 +00007212#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007213 else if (WIFSTOPPED(status))
7214 st = WSTOPSIG(status) + 128;
7215#endif
7216 else
7217 st = WTERMSIG(status) + 128;
Eric Andersen2870d962001-07-02 17:27:21 +00007218#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007219 if (jp->jobctl) {
7220 /*
7221 * This is truly gross.
7222 * If we're doing job control, then we did a TIOCSPGRP which
7223 * caused us (the shell) to no longer be in the controlling
7224 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7225 * intuit from the subprocess exit status whether a SIGINT
7226 * occured, and if so interrupt ourselves. Yuck. - mycroft
7227 */
7228 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
7229 raise(SIGINT);
7230 }
Eric Andersen2870d962001-07-02 17:27:21 +00007231 if (jp->state == JOBDONE)
7232
Eric Andersencb57d552001-06-28 07:25:16 +00007233#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007234 freejob(jp);
7235 INTON;
7236 return st;
7237}
7238
7239
7240
7241/*
7242 * Wait for a process to terminate.
7243 */
7244
Eric Andersen62483552001-07-10 06:09:16 +00007245/*
7246 * Do a wait system call. If job control is compiled in, we accept
7247 * stopped processes. If block is zero, we return a value of zero
7248 * rather than blocking.
7249 *
7250 * System V doesn't have a non-blocking wait system call. It does
7251 * have a SIGCLD signal that is sent to a process when one of it's
7252 * children dies. The obvious way to use SIGCLD would be to install
7253 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7254 * was received, and have waitproc bump another counter when it got
7255 * the status of a process. Waitproc would then know that a wait
7256 * system call would not block if the two counters were different.
7257 * This approach doesn't work because if a process has children that
7258 * have not been waited for, System V will send it a SIGCLD when it
7259 * installs a signal handler for SIGCLD. What this means is that when
7260 * a child exits, the shell will be sent SIGCLD signals continuously
7261 * until is runs out of stack space, unless it does a wait call before
7262 * restoring the signal handler. The code below takes advantage of
7263 * this (mis)feature by installing a signal handler for SIGCLD and
7264 * then checking to see whether it was called. If there are any
7265 * children to be waited for, it will be.
7266 *
7267 */
7268
7269static inline int
7270waitproc(int block, int *status)
7271{
7272 int flags;
7273
7274 flags = 0;
7275#ifdef JOBS
7276 if (jobctl)
7277 flags |= WUNTRACED;
7278#endif
7279 if (block == 0)
7280 flags |= WNOHANG;
7281 return wait3(status, flags, (struct rusage *)NULL);
7282}
7283
Eric Andersencb57d552001-06-28 07:25:16 +00007284static int
Eric Andersen62483552001-07-10 06:09:16 +00007285dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00007286{
7287 int pid;
7288 int status;
7289 struct procstat *sp;
7290 struct job *jp;
7291 struct job *thisjob;
7292 int done;
7293 int stopped;
7294 int core;
7295 int sig;
7296
7297 TRACE(("dowait(%d) called\n", block));
7298 do {
7299 pid = waitproc(block, &status);
7300 TRACE(("wait returns %d, status=%d\n", pid, status));
7301 } while (!(block & 2) && pid == -1 && errno == EINTR);
7302 if (pid <= 0)
7303 return pid;
7304 INTOFF;
7305 thisjob = NULL;
7306 for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
7307 if (jp->used) {
7308 done = 1;
7309 stopped = 1;
7310 for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
7311 if (sp->pid == -1)
7312 continue;
7313 if (sp->pid == pid) {
7314 TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
7315 sp->status = status;
7316 thisjob = jp;
7317 }
7318 if (sp->status == -1)
7319 stopped = 0;
7320 else if (WIFSTOPPED(sp->status))
7321 done = 0;
7322 }
Eric Andersen2870d962001-07-02 17:27:21 +00007323 if (stopped) { /* stopped or done */
Eric Andersencb57d552001-06-28 07:25:16 +00007324 int state = done? JOBDONE : JOBSTOPPED;
7325 if (jp->state != state) {
7326 TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
7327 jp->state = state;
Eric Andersen2870d962001-07-02 17:27:21 +00007328#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007329 if (done && curjob == jp - jobtab + 1)
Eric Andersen2870d962001-07-02 17:27:21 +00007330 curjob = 0; /* no current job */
Eric Andersencb57d552001-06-28 07:25:16 +00007331#endif
7332 }
7333 }
7334 }
7335 }
7336 INTON;
7337 if (! rootshell || ! iflag || (job && thisjob == job)) {
7338 core = WCOREDUMP(status);
Eric Andersen2870d962001-07-02 17:27:21 +00007339#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007340 if (WIFSTOPPED(status)) sig = WSTOPSIG(status);
7341 else
7342#endif
7343 if (WIFEXITED(status)) sig = 0;
7344 else sig = WTERMSIG(status);
7345
7346 if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
7347 if (thisjob != job)
Eric Andersen3102ac42001-07-06 04:26:23 +00007348 out2fmt("%d: ", pid);
Eric Andersen2870d962001-07-02 17:27:21 +00007349#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007350 if (sig == SIGTSTP && rootshell && iflag)
Eric Andersen3102ac42001-07-06 04:26:23 +00007351 out2fmt("%%%ld ",
Eric Andersencb57d552001-06-28 07:25:16 +00007352 (long)(job - jobtab + 1));
7353#endif
7354 if (sig < NSIG && sys_siglist[sig])
7355 out2str(sys_siglist[sig]);
7356 else
Eric Andersen3102ac42001-07-06 04:26:23 +00007357 out2fmt("Signal %d", sig);
Eric Andersencb57d552001-06-28 07:25:16 +00007358 if (core)
7359 out2str(" - core dumped");
7360 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00007361 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00007362 TRACE(("Not printing status: status=%d, sig=%d\n",
Eric Andersencb57d552001-06-28 07:25:16 +00007363 status, sig));
7364 }
7365 } else {
7366 TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
7367 if (thisjob)
7368 thisjob->changed = 1;
7369 }
7370 return pid;
7371}
7372
7373
7374
Eric Andersencb57d552001-06-28 07:25:16 +00007375
7376/*
7377 * return 1 if there are stopped jobs, otherwise 0
7378 */
Eric Andersencb57d552001-06-28 07:25:16 +00007379static int
Eric Andersen2870d962001-07-02 17:27:21 +00007380stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007381{
7382 int jobno;
7383 struct job *jp;
7384
7385 if (job_warning)
7386 return (0);
7387 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
7388 if (jp->used == 0)
7389 continue;
7390 if (jp->state == JOBSTOPPED) {
7391 out2str("You have stopped jobs.\n");
7392 job_warning = 2;
7393 return (1);
7394 }
7395 }
7396
7397 return (0);
7398}
7399
7400/*
7401 * Return a string identifying a command (to be printed by the
7402 * jobs command.
7403 */
7404
7405static char *cmdnextc;
7406static int cmdnleft;
Eric Andersen2870d962001-07-02 17:27:21 +00007407#define MAXCMDTEXT 200
Eric Andersencb57d552001-06-28 07:25:16 +00007408
Eric Andersen2870d962001-07-02 17:27:21 +00007409static void
7410cmdputs(const char *s)
7411{
7412 const char *p;
7413 char *q;
7414 char c;
7415 int subtype = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007416
Eric Andersen2870d962001-07-02 17:27:21 +00007417 if (cmdnleft <= 0)
7418 return;
7419 p = s;
7420 q = cmdnextc;
7421 while ((c = *p++) != '\0') {
7422 if (c == CTLESC)
7423 *q++ = *p++;
7424 else if (c == CTLVAR) {
7425 *q++ = '$';
7426 if (--cmdnleft > 0)
7427 *q++ = '{';
7428 subtype = *p++;
7429 } else if (c == '=' && subtype != 0) {
7430 *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
7431 subtype = 0;
7432 } else if (c == CTLENDVAR) {
7433 *q++ = '}';
7434 } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
7435 cmdnleft++; /* ignore it */
7436 else
7437 *q++ = c;
7438 if (--cmdnleft <= 0) {
7439 *q++ = '.';
7440 *q++ = '.';
7441 *q++ = '.';
7442 break;
7443 }
7444 }
7445 cmdnextc = q;
Eric Andersencb57d552001-06-28 07:25:16 +00007446}
7447
7448
7449static void
Eric Andersen2870d962001-07-02 17:27:21 +00007450cmdtxt(const union node *n)
7451{
Eric Andersencb57d552001-06-28 07:25:16 +00007452 union node *np;
7453 struct nodelist *lp;
7454 const char *p;
7455 int i;
7456 char s[2];
7457
7458 if (n == NULL)
7459 return;
7460 switch (n->type) {
7461 case NSEMI:
7462 cmdtxt(n->nbinary.ch1);
7463 cmdputs("; ");
7464 cmdtxt(n->nbinary.ch2);
7465 break;
7466 case NAND:
7467 cmdtxt(n->nbinary.ch1);
7468 cmdputs(" && ");
7469 cmdtxt(n->nbinary.ch2);
7470 break;
7471 case NOR:
7472 cmdtxt(n->nbinary.ch1);
7473 cmdputs(" || ");
7474 cmdtxt(n->nbinary.ch2);
7475 break;
7476 case NPIPE:
7477 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7478 cmdtxt(lp->n);
7479 if (lp->next)
7480 cmdputs(" | ");
7481 }
7482 break;
7483 case NSUBSHELL:
7484 cmdputs("(");
7485 cmdtxt(n->nredir.n);
7486 cmdputs(")");
7487 break;
7488 case NREDIR:
7489 case NBACKGND:
7490 cmdtxt(n->nredir.n);
7491 break;
7492 case NIF:
7493 cmdputs("if ");
7494 cmdtxt(n->nif.test);
7495 cmdputs("; then ");
7496 cmdtxt(n->nif.ifpart);
7497 cmdputs("...");
7498 break;
7499 case NWHILE:
7500 cmdputs("while ");
7501 goto until;
7502 case NUNTIL:
7503 cmdputs("until ");
7504until:
7505 cmdtxt(n->nbinary.ch1);
7506 cmdputs("; do ");
7507 cmdtxt(n->nbinary.ch2);
7508 cmdputs("; done");
7509 break;
7510 case NFOR:
7511 cmdputs("for ");
7512 cmdputs(n->nfor.var);
7513 cmdputs(" in ...");
7514 break;
7515 case NCASE:
7516 cmdputs("case ");
7517 cmdputs(n->ncase.expr->narg.text);
7518 cmdputs(" in ...");
7519 break;
7520 case NDEFUN:
7521 cmdputs(n->narg.text);
7522 cmdputs("() ...");
7523 break;
7524 case NCMD:
7525 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7526 cmdtxt(np);
7527 if (np->narg.next)
7528 cmdputs(spcstr);
7529 }
7530 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7531 cmdputs(spcstr);
7532 cmdtxt(np);
7533 }
7534 break;
7535 case NARG:
7536 cmdputs(n->narg.text);
7537 break;
7538 case NTO:
7539 p = ">"; i = 1; goto redir;
7540 case NAPPEND:
7541 p = ">>"; i = 1; goto redir;
7542 case NTOFD:
7543 p = ">&"; i = 1; goto redir;
7544 case NTOOV:
7545 p = ">|"; i = 1; goto redir;
7546 case NFROM:
7547 p = "<"; i = 0; goto redir;
7548 case NFROMFD:
7549 p = "<&"; i = 0; goto redir;
7550 case NFROMTO:
7551 p = "<>"; i = 0; goto redir;
7552redir:
7553 if (n->nfile.fd != i) {
7554 s[0] = n->nfile.fd + '0';
7555 s[1] = '\0';
7556 cmdputs(s);
7557 }
7558 cmdputs(p);
7559 if (n->type == NTOFD || n->type == NFROMFD) {
7560 s[0] = n->ndup.dupfd + '0';
7561 s[1] = '\0';
7562 cmdputs(s);
7563 } else {
7564 cmdtxt(n->nfile.fname);
7565 }
7566 break;
7567 case NHERE:
7568 case NXHERE:
7569 cmdputs("<<...");
7570 break;
7571 default:
7572 cmdputs("???");
7573 break;
7574 }
7575}
7576
7577
Eric Andersen2870d962001-07-02 17:27:21 +00007578static char *
7579commandtext(const union node *n)
7580{
7581 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007582
Eric Andersen2870d962001-07-02 17:27:21 +00007583 cmdnextc = name = ckmalloc(MAXCMDTEXT);
7584 cmdnleft = MAXCMDTEXT - 4;
7585 cmdtxt(n);
7586 *cmdnextc = '\0';
7587 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00007588}
7589
Eric Andersen2870d962001-07-02 17:27:21 +00007590
Eric Andersencb57d552001-06-28 07:25:16 +00007591static void waitonint(int sig) {
7592 intreceived = 1;
7593 return;
7594}
Eric Andersencb57d552001-06-28 07:25:16 +00007595/*
7596 * Routines to check for mail. (Perhaps make part of main.c?)
7597 */
7598
7599
7600#define MAXMBOXES 10
7601
7602
Eric Andersen2870d962001-07-02 17:27:21 +00007603static int nmboxes; /* number of mailboxes */
7604static time_t mailtime[MAXMBOXES]; /* times of mailboxes */
Eric Andersencb57d552001-06-28 07:25:16 +00007605
7606
7607
7608/*
7609 * Print appropriate message(s) if mail has arrived. If the argument is
7610 * nozero, then the value of MAIL has changed, so we just update the
7611 * values.
7612 */
7613
7614static void
Eric Andersen2870d962001-07-02 17:27:21 +00007615chkmail(int silent)
Eric Andersencb57d552001-06-28 07:25:16 +00007616{
7617 int i;
7618 const char *mpath;
7619 char *p;
7620 char *q;
7621 struct stackmark smark;
7622 struct stat statb;
7623
7624 if (silent)
7625 nmboxes = 10;
7626 if (nmboxes == 0)
7627 return;
7628 setstackmark(&smark);
7629 mpath = mpathset()? mpathval() : mailval();
7630 for (i = 0 ; i < nmboxes ; i++) {
7631 p = padvance(&mpath, nullstr);
7632 if (p == NULL)
7633 break;
7634 if (*p == '\0')
7635 continue;
7636 for (q = p ; *q ; q++);
7637#ifdef DEBUG
7638 if (q[-1] != '/')
7639 abort();
7640#endif
Eric Andersen2870d962001-07-02 17:27:21 +00007641 q[-1] = '\0'; /* delete trailing '/' */
Eric Andersencb57d552001-06-28 07:25:16 +00007642 if (stat(p, &statb) < 0)
7643 statb.st_size = 0;
7644 if (statb.st_size > mailtime[i] && ! silent) {
Eric Andersen3102ac42001-07-06 04:26:23 +00007645 out2fmt(snlfmt,
7646 pathopt? pathopt : "you have mail");
Eric Andersencb57d552001-06-28 07:25:16 +00007647 }
7648 mailtime[i] = statb.st_size;
Eric Andersencb57d552001-06-28 07:25:16 +00007649 }
7650 nmboxes = i;
7651 popstackmark(&smark);
7652}
Eric Andersencb57d552001-06-28 07:25:16 +00007653
7654#define PROFILE 0
7655
Eric Andersencb57d552001-06-28 07:25:16 +00007656#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007657static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007658extern int etext();
7659#endif
7660
Eric Andersen2870d962001-07-02 17:27:21 +00007661static void read_profile (const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007662static void cmdloop (int);
7663static void options (int);
Eric Andersen2870d962001-07-02 17:27:21 +00007664static void setoption (int, int);
7665static void procargs (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00007666
Eric Andersen2870d962001-07-02 17:27:21 +00007667
Eric Andersencb57d552001-06-28 07:25:16 +00007668/*
7669 * Main routine. We initialize things, parse the arguments, execute
7670 * profiles if we're a login shell, and then call cmdloop to execute
7671 * commands. The setjmp call sets up the location to jump to when an
7672 * exception occurs. When an exception occurs the variable "state"
7673 * is used to figure out how far we had gotten.
7674 */
7675
7676int
7677shell_main(argc, argv)
7678 int argc;
7679 char **argv;
7680{
7681 struct jmploc jmploc;
7682 struct stackmark smark;
7683 volatile int state;
Eric Andersen62483552001-07-10 06:09:16 +00007684 const char *shinit;
Eric Andersencb57d552001-06-28 07:25:16 +00007685
Eric Andersencb57d552001-06-28 07:25:16 +00007686 BLTINCMD = find_builtin("builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00007687 EXECCMD = find_builtin("exec");
7688 EVALCMD = find_builtin("eval");
7689
Eric Andersen1c039232001-07-07 00:05:55 +00007690#ifndef BB_FEATURE_SH_FANCY_PROMPT
7691 unsetenv("PS1");
7692 unsetenv("PS2");
7693#endif
7694
Eric Andersencb57d552001-06-28 07:25:16 +00007695#if PROFILE
7696 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7697#endif
7698#if defined(linux) || defined(__GNU__)
7699 signal(SIGCHLD, SIG_DFL);
7700#endif
7701 state = 0;
7702 if (setjmp(jmploc.loc)) {
7703 INTOFF;
7704 /*
7705 * When a shell procedure is executed, we raise the
7706 * exception EXSHELLPROC to clean up before executing
7707 * the shell procedure.
7708 */
7709 switch (exception) {
7710 case EXSHELLPROC:
7711 rootpid = getpid();
7712 rootshell = 1;
7713 minusc = NULL;
7714 state = 3;
7715 break;
7716
7717 case EXEXEC:
7718 exitstatus = exerrno;
7719 break;
7720
7721 case EXERROR:
7722 exitstatus = 2;
7723 break;
7724
7725 default:
7726 break;
7727 }
7728
7729 if (exception != EXSHELLPROC) {
7730 if (state == 0 || iflag == 0 || ! rootshell)
7731 exitshell(exitstatus);
7732 }
7733 reset();
Eric Andersen2870d962001-07-02 17:27:21 +00007734 if (exception == EXINT) {
Eric Andersencb57d552001-06-28 07:25:16 +00007735 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00007736 }
7737 popstackmark(&smark);
Eric Andersen2870d962001-07-02 17:27:21 +00007738 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007739 if (state == 1)
7740 goto state1;
7741 else if (state == 2)
7742 goto state2;
7743 else if (state == 3)
7744 goto state3;
7745 else
7746 goto state4;
7747 }
7748 handler = &jmploc;
7749#ifdef DEBUG
7750 opentrace();
7751 trputs("Shell args: "); trargs(argv);
7752#endif
7753 rootpid = getpid();
7754 rootshell = 1;
7755 init();
7756 setstackmark(&smark);
7757 procargs(argc, argv);
7758 if (argv[0] && argv[0][0] == '-') {
7759 state = 1;
7760 read_profile("/etc/profile");
7761state1:
7762 state = 2;
7763 read_profile(".profile");
7764 }
7765state2:
7766 state = 3;
7767#ifndef linux
7768 if (getuid() == geteuid() && getgid() == getegid()) {
7769#endif
7770 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7771 state = 3;
7772 read_profile(shinit);
7773 }
7774#ifndef linux
7775 }
7776#endif
7777state3:
7778 state = 4;
7779 if (sflag == 0 || minusc) {
7780 static int sigs[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00007781 SIGINT, SIGQUIT, SIGHUP,
Eric Andersencb57d552001-06-28 07:25:16 +00007782#ifdef SIGTSTP
7783 SIGTSTP,
7784#endif
7785 SIGPIPE
7786 };
7787#define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0]))
7788 int i;
7789
7790 for (i = 0; i < SIGSSIZE; i++)
7791 setsignal(sigs[i]);
7792 }
7793
7794 if (minusc)
7795 evalstring(minusc, 0);
7796
7797 if (sflag || minusc == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00007798state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007799 cmdloop(1);
7800 }
7801#if PROFILE
7802 monitor(0);
7803#endif
7804 exitshell(exitstatus);
7805 /* NOTREACHED */
7806}
7807
7808
7809/*
7810 * Read and execute commands. "Top" is nonzero for the top level command
7811 * loop; it turns on prompting if the shell is interactive.
7812 */
7813
7814static void
Eric Andersen2870d962001-07-02 17:27:21 +00007815cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00007816{
7817 union node *n;
7818 struct stackmark smark;
7819 int inter;
7820 int numeof = 0;
7821
7822 TRACE(("cmdloop(%d) called\n", top));
7823 setstackmark(&smark);
7824 for (;;) {
7825 if (pendingsigs)
7826 dotrap();
7827 inter = 0;
7828 if (iflag && top) {
7829 inter++;
7830 showjobs(1);
7831 chkmail(0);
Eric Andersen3102ac42001-07-06 04:26:23 +00007832 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00007833 }
7834 n = parsecmd(inter);
7835 /* showtree(n); DEBUG */
7836 if (n == NEOF) {
7837 if (!top || numeof >= 50)
7838 break;
7839 if (!stoppedjobs()) {
7840 if (!Iflag)
7841 break;
7842 out2str("\nUse \"exit\" to leave shell.\n");
7843 }
7844 numeof++;
7845 } else if (n != NULL && nflag == 0) {
7846 job_warning = (job_warning == 2) ? 1 : 0;
7847 numeof = 0;
7848 evaltree(n, 0);
7849 }
7850 popstackmark(&smark);
7851 setstackmark(&smark);
7852 if (evalskip == SKIPFILE) {
7853 evalskip = 0;
7854 break;
7855 }
7856 }
7857 popstackmark(&smark);
7858}
7859
7860
7861
7862/*
7863 * Read /etc/profile or .profile. Return on error.
7864 */
7865
7866static void
7867read_profile(name)
7868 const char *name;
7869{
7870 int fd;
7871 int xflag_set = 0;
7872 int vflag_set = 0;
7873
7874 INTOFF;
7875 if ((fd = open(name, O_RDONLY)) >= 0)
7876 setinputfd(fd, 1);
7877 INTON;
7878 if (fd < 0)
7879 return;
7880 /* -q turns off -x and -v just when executing init files */
7881 if (qflag) {
7882 if (xflag)
7883 xflag = 0, xflag_set = 1;
7884 if (vflag)
7885 vflag = 0, vflag_set = 1;
7886 }
7887 cmdloop(0);
7888 if (qflag) {
7889 if (xflag_set)
7890 xflag = 1;
7891 if (vflag_set)
7892 vflag = 1;
7893 }
7894 popfile();
7895}
7896
7897
7898
7899/*
7900 * Read a file containing shell functions.
7901 */
7902
7903static void
Eric Andersen2870d962001-07-02 17:27:21 +00007904readcmdfile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00007905{
7906 int fd;
7907
7908 INTOFF;
7909 if ((fd = open(name, O_RDONLY)) >= 0)
7910 setinputfd(fd, 1);
7911 else
7912 error("Can't open %s", name);
7913 INTON;
7914 cmdloop(0);
7915 popfile();
7916}
7917
7918
7919
7920/*
7921 * Take commands from a file. To be compatable we should do a path
7922 * search for the file, which is necessary to find sub-commands.
7923 */
7924
7925
Eric Andersen62483552001-07-10 06:09:16 +00007926static inline char *
Eric Andersencb57d552001-06-28 07:25:16 +00007927find_dot_file(mybasename)
7928 char *mybasename;
7929{
7930 char *fullname;
7931 const char *path = pathval();
7932 struct stat statb;
7933
7934 /* don't try this for absolute or relative paths */
7935 if (strchr(mybasename, '/'))
7936 return mybasename;
7937
7938 while ((fullname = padvance(&path, mybasename)) != NULL) {
7939 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
7940 /*
7941 * Don't bother freeing here, since it will
7942 * be freed by the caller.
7943 */
7944 return fullname;
7945 }
7946 stunalloc(fullname);
7947 }
7948
7949 /* not found in the PATH */
7950 error("%s: not found", mybasename);
7951 /* NOTREACHED */
7952}
7953
7954static int
7955dotcmd(argc, argv)
7956 int argc;
7957 char **argv;
7958{
7959 struct strlist *sp;
7960 exitstatus = 0;
7961
7962 for (sp = cmdenviron; sp ; sp = sp->next)
7963 setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
7964
Eric Andersen2870d962001-07-02 17:27:21 +00007965 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00007966 char *fullname;
7967 struct stackmark smark;
7968
7969 setstackmark(&smark);
7970 fullname = find_dot_file(argv[1]);
7971 setinputfile(fullname, 1);
7972 commandname = fullname;
7973 cmdloop(0);
7974 popfile();
7975 popstackmark(&smark);
7976 }
7977 return exitstatus;
7978}
7979
7980
7981static int
7982exitcmd(argc, argv)
7983 int argc;
7984 char **argv;
7985{
7986 if (stoppedjobs())
7987 return 0;
7988 if (argc > 1)
7989 exitstatus = number(argv[1]);
7990 else
7991 exitstatus = oexitstatus;
7992 exitshell(exitstatus);
7993 /* NOTREACHED */
7994}
Eric Andersen62483552001-07-10 06:09:16 +00007995
Eric Andersen2870d962001-07-02 17:27:21 +00007996static pointer
7997stalloc(int nbytes)
Eric Andersencb57d552001-06-28 07:25:16 +00007998{
7999 char *p;
8000
8001 nbytes = ALIGN(nbytes);
8002 if (nbytes > stacknleft) {
8003 int blocksize;
8004 struct stack_block *sp;
8005
8006 blocksize = nbytes;
8007 if (blocksize < MINSIZE)
8008 blocksize = MINSIZE;
8009 INTOFF;
8010 sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
8011 sp->prev = stackp;
8012 stacknxt = sp->space;
8013 stacknleft = blocksize;
8014 stackp = sp;
8015 INTON;
8016 }
8017 p = stacknxt;
8018 stacknxt += nbytes;
8019 stacknleft -= nbytes;
8020 return p;
8021}
8022
8023
8024static void
Eric Andersen2870d962001-07-02 17:27:21 +00008025stunalloc(pointer p)
8026{
Eric Andersencb57d552001-06-28 07:25:16 +00008027#ifdef DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +00008028 if (p == NULL) { /*DEBUG */
Eric Andersencb57d552001-06-28 07:25:16 +00008029 write(2, "stunalloc\n", 10);
8030 abort();
8031 }
8032#endif
8033 if (!(stacknxt >= (char *)p && (char *)p >= stackp->space)) {
8034 p = stackp->space;
8035 }
8036 stacknleft += stacknxt - (char *)p;
8037 stacknxt = p;
8038}
8039
8040
Eric Andersencb57d552001-06-28 07:25:16 +00008041static void
Eric Andersen2870d962001-07-02 17:27:21 +00008042setstackmark(struct stackmark *mark)
8043{
Eric Andersencb57d552001-06-28 07:25:16 +00008044 mark->stackp = stackp;
8045 mark->stacknxt = stacknxt;
8046 mark->stacknleft = stacknleft;
8047 mark->marknext = markp;
8048 markp = mark;
8049}
8050
8051
8052static void
Eric Andersen2870d962001-07-02 17:27:21 +00008053popstackmark(struct stackmark *mark)
8054{
Eric Andersencb57d552001-06-28 07:25:16 +00008055 struct stack_block *sp;
8056
8057 INTOFF;
8058 markp = mark->marknext;
8059 while (stackp != mark->stackp) {
8060 sp = stackp;
8061 stackp = sp->prev;
8062 ckfree(sp);
8063 }
8064 stacknxt = mark->stacknxt;
8065 stacknleft = mark->stacknleft;
8066 INTON;
8067}
8068
8069
8070/*
8071 * When the parser reads in a string, it wants to stick the string on the
8072 * stack and only adjust the stack pointer when it knows how big the
8073 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8074 * of space on top of the stack and stackblocklen returns the length of
8075 * this block. Growstackblock will grow this space by at least one byte,
8076 * possibly moving it (like realloc). Grabstackblock actually allocates the
8077 * part of the block that has been used.
8078 */
8079
8080static void
Eric Andersen2870d962001-07-02 17:27:21 +00008081growstackblock(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00008082 char *p;
8083 int newlen = ALIGN(stacknleft * 2 + 100);
8084 char *oldspace = stacknxt;
8085 int oldlen = stacknleft;
8086 struct stack_block *sp;
8087 struct stack_block *oldstackp;
8088
8089 if (stacknxt == stackp->space && stackp != &stackbase) {
8090 INTOFF;
8091 oldstackp = stackp;
8092 sp = stackp;
8093 stackp = sp->prev;
8094 sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen);
8095 sp->prev = stackp;
8096 stackp = sp;
8097 stacknxt = sp->space;
8098 stacknleft = newlen;
8099 {
8100 /* Stack marks pointing to the start of the old block
Eric Andersen2870d962001-07-02 17:27:21 +00008101 * must be relocated to point to the new block
Eric Andersencb57d552001-06-28 07:25:16 +00008102 */
8103 struct stackmark *xmark;
8104 xmark = markp;
8105 while (xmark != NULL && xmark->stackp == oldstackp) {
8106 xmark->stackp = stackp;
8107 xmark->stacknxt = stacknxt;
8108 xmark->stacknleft = stacknleft;
8109 xmark = xmark->marknext;
8110 }
8111 }
8112 INTON;
8113 } else {
8114 p = stalloc(newlen);
8115 memcpy(p, oldspace, oldlen);
Eric Andersen2870d962001-07-02 17:27:21 +00008116 stacknxt = p; /* free the space */
8117 stacknleft += newlen; /* we just allocated */
Eric Andersencb57d552001-06-28 07:25:16 +00008118 }
8119}
8120
8121
8122
Eric Andersen2870d962001-07-02 17:27:21 +00008123static inline void
8124grabstackblock(int len)
Eric Andersencb57d552001-06-28 07:25:16 +00008125{
8126 len = ALIGN(len);
8127 stacknxt += len;
8128 stacknleft -= len;
8129}
8130
8131
8132
8133/*
8134 * The following routines are somewhat easier to use that the above.
8135 * The user declares a variable of type STACKSTR, which may be declared
8136 * to be a register. The macro STARTSTACKSTR initializes things. Then
8137 * the user uses the macro STPUTC to add characters to the string. In
8138 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8139 * grown as necessary. When the user is done, she can just leave the
8140 * string there and refer to it using stackblock(). Or she can allocate
8141 * the space for it using grabstackstr(). If it is necessary to allow
8142 * someone else to use the stack temporarily and then continue to grow
8143 * the string, the user should use grabstack to allocate the space, and
8144 * then call ungrabstr(p) to return to the previous mode of operation.
8145 *
8146 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8147 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8148 * is space for at least one character.
8149 */
8150
8151
8152static char *
Eric Andersen2870d962001-07-02 17:27:21 +00008153growstackstr(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00008154 int len = stackblocksize();
8155 if (herefd >= 0 && len >= 1024) {
8156 xwrite(herefd, stackblock(), len);
8157 sstrnleft = len - 1;
8158 return stackblock();
8159 }
8160 growstackblock();
8161 sstrnleft = stackblocksize() - len - 1;
8162 return stackblock() + len;
8163}
8164
8165
8166/*
8167 * Called from CHECKSTRSPACE.
8168 */
8169
8170static char *
8171makestrspace(size_t newlen) {
8172 int len = stackblocksize() - sstrnleft;
8173 do {
8174 growstackblock();
8175 sstrnleft = stackblocksize() - len;
8176 } while (sstrnleft < newlen);
8177 return stackblock() + len;
8178}
8179
8180
8181
8182static void
Eric Andersen2870d962001-07-02 17:27:21 +00008183ungrabstackstr(char *s, char *p)
8184{
Eric Andersencb57d552001-06-28 07:25:16 +00008185 stacknleft += stacknxt - s;
8186 stacknxt = s;
8187 sstrnleft = stacknleft - (p - s);
8188}
Eric Andersencb57d552001-06-28 07:25:16 +00008189/*
8190 * Miscelaneous builtins.
8191 */
8192
8193
8194#undef rflag
8195
Eric Andersen62483552001-07-10 06:09:16 +00008196//#ifdef __GLIBC__
Eric Andersen2870d962001-07-02 17:27:21 +00008197static mode_t getmode(const void *, mode_t);
Eric Andersencb57d552001-06-28 07:25:16 +00008198static void *setmode(const char *);
Eric Andersen62483552001-07-10 06:09:16 +00008199//#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008200
8201#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersen62483552001-07-10 06:09:16 +00008202typedef long rlim_t;
Eric Andersencb57d552001-06-28 07:25:16 +00008203#endif
8204
8205
8206
8207/*
8208 * The read builtin. The -e option causes backslashes to escape the
8209 * following character.
8210 *
8211 * This uses unbuffered input, which may be avoidable in some cases.
8212 */
8213
8214static int
8215readcmd(argc, argv)
8216 int argc;
8217 char **argv;
8218{
8219 char **ap;
8220 int backslash;
8221 char c;
8222 int rflag;
8223 char *prompt;
8224 const char *ifs;
8225 char *p;
8226 int startword;
8227 int status;
8228 int i;
8229
8230 rflag = 0;
8231 prompt = NULL;
8232 while ((i = nextopt("p:r")) != '\0') {
8233 if (i == 'p')
8234 prompt = optionarg;
8235 else
8236 rflag = 1;
8237 }
8238 if (prompt && isatty(0)) {
8239 putprompt(prompt);
8240 flushall();
8241 }
8242 if (*(ap = argptr) == NULL)
8243 error("arg count");
8244 if ((ifs = bltinlookup("IFS")) == NULL)
8245 ifs = defifs;
8246 status = 0;
8247 startword = 1;
8248 backslash = 0;
8249 STARTSTACKSTR(p);
8250 for (;;) {
8251 if (read(0, &c, 1) != 1) {
8252 status = 1;
8253 break;
8254 }
8255 if (c == '\0')
8256 continue;
8257 if (backslash) {
8258 backslash = 0;
8259 if (c != '\n')
8260 STPUTC(c, p);
8261 continue;
8262 }
8263 if (!rflag && c == '\\') {
8264 backslash++;
8265 continue;
8266 }
8267 if (c == '\n')
8268 break;
8269 if (startword && *ifs == ' ' && strchr(ifs, c)) {
8270 continue;
8271 }
8272 startword = 0;
8273 if (backslash && c == '\\') {
8274 if (read(0, &c, 1) != 1) {
8275 status = 1;
8276 break;
8277 }
8278 STPUTC(c, p);
8279 } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
8280 STACKSTRNUL(p);
8281 setvar(*ap, stackblock(), 0);
8282 ap++;
8283 startword = 1;
8284 STARTSTACKSTR(p);
8285 } else {
8286 STPUTC(c, p);
8287 }
8288 }
8289 STACKSTRNUL(p);
8290 /* Remove trailing blanks */
8291 while (stackblock() <= --p && strchr(ifs, *p) != NULL)
8292 *p = '\0';
8293 setvar(*ap, stackblock(), 0);
8294 while (*++ap != NULL)
8295 setvar(*ap, nullstr, 0);
8296 return status;
8297}
8298
8299
8300
8301static int
8302umaskcmd(argc, argv)
8303 int argc;
8304 char **argv;
8305{
8306 char *ap;
8307 int mask;
8308 int i;
8309 int symbolic_mode = 0;
8310
Eric Andersen62483552001-07-10 06:09:16 +00008311 while (nextopt("S") != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00008312 symbolic_mode = 1;
8313 }
8314
8315 INTOFF;
8316 mask = umask(0);
8317 umask(mask);
8318 INTON;
8319
8320 if ((ap = *argptr) == NULL) {
8321 if (symbolic_mode) {
8322 char u[4], g[4], o[4];
8323
8324 i = 0;
8325 if ((mask & S_IRUSR) == 0)
8326 u[i++] = 'r';
8327 if ((mask & S_IWUSR) == 0)
8328 u[i++] = 'w';
8329 if ((mask & S_IXUSR) == 0)
8330 u[i++] = 'x';
8331 u[i] = '\0';
8332
8333 i = 0;
8334 if ((mask & S_IRGRP) == 0)
8335 g[i++] = 'r';
8336 if ((mask & S_IWGRP) == 0)
8337 g[i++] = 'w';
8338 if ((mask & S_IXGRP) == 0)
8339 g[i++] = 'x';
8340 g[i] = '\0';
8341
8342 i = 0;
8343 if ((mask & S_IROTH) == 0)
8344 o[i++] = 'r';
8345 if ((mask & S_IWOTH) == 0)
8346 o[i++] = 'w';
8347 if ((mask & S_IXOTH) == 0)
8348 o[i++] = 'x';
8349 o[i] = '\0';
8350
Eric Andersen62483552001-07-10 06:09:16 +00008351 printf("u=%s,g=%s,o=%s\n", u, g, o);
Eric Andersencb57d552001-06-28 07:25:16 +00008352 } else {
Eric Andersen62483552001-07-10 06:09:16 +00008353 printf("%.4o\n", mask);
Eric Andersencb57d552001-06-28 07:25:16 +00008354 }
8355 } else {
Eric Andersen62483552001-07-10 06:09:16 +00008356 if (is_digit((unsigned char)*ap)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008357 mask = 0;
8358 do {
8359 if (*ap >= '8' || *ap < '0')
8360 error("Illegal number: %s", argv[1]);
8361 mask = (mask << 3) + (*ap - '0');
8362 } while (*++ap != '\0');
8363 umask(mask);
8364 } else {
8365 void *set;
8366
8367 INTOFF;
8368 if ((set = setmode(ap)) != 0) {
8369 mask = getmode(set, ~mask & 0777);
8370 ckfree(set);
8371 }
8372 INTON;
8373 if (!set)
8374 error("Illegal mode: %s", ap);
8375
8376 umask(~mask & 0777);
8377 }
8378 }
8379 return 0;
8380}
8381
8382/*
8383 * ulimit builtin
8384 *
8385 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
8386 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
8387 * ash by J.T. Conklin.
8388 *
8389 * Public domain.
8390 */
8391
8392struct limits {
8393 const char *name;
Eric Andersen2870d962001-07-02 17:27:21 +00008394 int cmd;
8395 int factor; /* multiply by to get rlim_{cur,max} values */
8396 char option;
Eric Andersencb57d552001-06-28 07:25:16 +00008397};
8398
8399static const struct limits limits[] = {
8400#ifdef RLIMIT_CPU
Eric Andersen2870d962001-07-02 17:27:21 +00008401 { "time(seconds)", RLIMIT_CPU, 1, 't' },
Eric Andersencb57d552001-06-28 07:25:16 +00008402#endif
8403#ifdef RLIMIT_FSIZE
Eric Andersen2870d962001-07-02 17:27:21 +00008404 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
Eric Andersencb57d552001-06-28 07:25:16 +00008405#endif
8406#ifdef RLIMIT_DATA
Eric Andersen2870d962001-07-02 17:27:21 +00008407 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
Eric Andersencb57d552001-06-28 07:25:16 +00008408#endif
8409#ifdef RLIMIT_STACK
Eric Andersen2870d962001-07-02 17:27:21 +00008410 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
Eric Andersencb57d552001-06-28 07:25:16 +00008411#endif
8412#ifdef RLIMIT_CORE
Eric Andersen2870d962001-07-02 17:27:21 +00008413 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
Eric Andersencb57d552001-06-28 07:25:16 +00008414#endif
8415#ifdef RLIMIT_RSS
Eric Andersen2870d962001-07-02 17:27:21 +00008416 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
Eric Andersencb57d552001-06-28 07:25:16 +00008417#endif
8418#ifdef RLIMIT_MEMLOCK
Eric Andersen2870d962001-07-02 17:27:21 +00008419 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
Eric Andersencb57d552001-06-28 07:25:16 +00008420#endif
8421#ifdef RLIMIT_NPROC
Eric Andersen2870d962001-07-02 17:27:21 +00008422 { "process(processes)", RLIMIT_NPROC, 1, 'p' },
Eric Andersencb57d552001-06-28 07:25:16 +00008423#endif
8424#ifdef RLIMIT_NOFILE
Eric Andersen2870d962001-07-02 17:27:21 +00008425 { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
Eric Andersencb57d552001-06-28 07:25:16 +00008426#endif
8427#ifdef RLIMIT_VMEM
Eric Andersen2870d962001-07-02 17:27:21 +00008428 { "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' },
Eric Andersencb57d552001-06-28 07:25:16 +00008429#endif
8430#ifdef RLIMIT_SWAP
Eric Andersen2870d962001-07-02 17:27:21 +00008431 { "swap(kbytes)", RLIMIT_SWAP, 1024, 'w' },
Eric Andersencb57d552001-06-28 07:25:16 +00008432#endif
Eric Andersen2870d962001-07-02 17:27:21 +00008433 { (char *) 0, 0, 0, '\0' }
Eric Andersencb57d552001-06-28 07:25:16 +00008434};
8435
8436static int
8437ulimitcmd(argc, argv)
8438 int argc;
8439 char **argv;
8440{
Eric Andersen2870d962001-07-02 17:27:21 +00008441 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00008442 rlim_t val = 0;
8443 enum { SOFT = 0x1, HARD = 0x2 }
8444 how = SOFT | HARD;
Eric Andersen2870d962001-07-02 17:27:21 +00008445 const struct limits *l;
8446 int set, all = 0;
8447 int optc, what;
8448 struct rlimit limit;
Eric Andersencb57d552001-06-28 07:25:16 +00008449
8450 what = 'f';
8451 while ((optc = nextopt("HSatfdsmcnpl")) != '\0')
8452 switch (optc) {
8453 case 'H':
8454 how = HARD;
8455 break;
8456 case 'S':
8457 how = SOFT;
8458 break;
8459 case 'a':
8460 all = 1;
8461 break;
8462 default:
8463 what = optc;
8464 }
8465
8466 for (l = limits; l->name && l->option != what; l++)
8467 ;
8468 if (!l->name)
8469 error("internal error (%c)", what);
8470
8471 set = *argptr ? 1 : 0;
8472 if (set) {
8473 char *p = *argptr;
8474
8475 if (all || argptr[1])
8476 error("too many arguments");
8477 if (strcmp(p, "unlimited") == 0)
8478 val = RLIM_INFINITY;
8479 else {
8480 val = (rlim_t) 0;
8481
8482 while ((c = *p++) >= '0' && c <= '9')
8483 {
8484 val = (val * 10) + (long)(c - '0');
8485 if (val < (rlim_t) 0)
8486 break;
8487 }
8488 if (c)
8489 error("bad number");
8490 val *= l->factor;
8491 }
8492 }
8493 if (all) {
8494 for (l = limits; l->name; l++) {
8495 getrlimit(l->cmd, &limit);
8496 if (how & SOFT)
8497 val = limit.rlim_cur;
8498 else if (how & HARD)
8499 val = limit.rlim_max;
8500
Eric Andersen62483552001-07-10 06:09:16 +00008501 printf("%-20s ", l->name);
Eric Andersencb57d552001-06-28 07:25:16 +00008502 if (val == RLIM_INFINITY)
Eric Andersen62483552001-07-10 06:09:16 +00008503 printf("unlimited\n");
Eric Andersencb57d552001-06-28 07:25:16 +00008504 else
8505 {
8506 val /= l->factor;
Eric Andersen62483552001-07-10 06:09:16 +00008507 printf("%lld\n", (long long) val);
Eric Andersencb57d552001-06-28 07:25:16 +00008508 }
8509 }
8510 return 0;
8511 }
8512
8513 getrlimit(l->cmd, &limit);
8514 if (set) {
8515 if (how & HARD)
8516 limit.rlim_max = val;
8517 if (how & SOFT)
8518 limit.rlim_cur = val;
8519 if (setrlimit(l->cmd, &limit) < 0)
Eric Andersen2870d962001-07-02 17:27:21 +00008520 error("error setting limit (%m)");
Eric Andersencb57d552001-06-28 07:25:16 +00008521 } else {
8522 if (how & SOFT)
8523 val = limit.rlim_cur;
8524 else if (how & HARD)
8525 val = limit.rlim_max;
8526
8527 if (val == RLIM_INFINITY)
Eric Andersen62483552001-07-10 06:09:16 +00008528 printf("unlimited\n");
Eric Andersencb57d552001-06-28 07:25:16 +00008529 else
8530 {
8531 val /= l->factor;
Eric Andersen62483552001-07-10 06:09:16 +00008532 printf("%lld\n", (long long) val);
Eric Andersencb57d552001-06-28 07:25:16 +00008533 }
8534 }
8535 return 0;
8536}
Eric Andersencb57d552001-06-28 07:25:16 +00008537/*
8538 * prefix -- see if pfx is a prefix of string.
8539 */
8540
8541static int
Eric Andersen62483552001-07-10 06:09:16 +00008542prefix(char const *pfx, char const *string)
8543{
Eric Andersencb57d552001-06-28 07:25:16 +00008544 while (*pfx) {
8545 if (*pfx++ != *string++)
8546 return 0;
8547 }
8548 return 1;
8549}
8550
Eric Andersen2870d962001-07-02 17:27:21 +00008551/*
8552 * Return true if s is a string of digits, and save munber in intptr
8553 * nagative is bad
8554 */
8555
8556static int
8557is_number(const char *p, int *intptr)
8558{
8559 int ret = 0;
8560
8561 do {
8562 if (! is_digit(*p))
8563 return 0;
8564 ret *= 10;
8565 ret += digit_val(*p);
8566 p++;
8567 } while (*p != '\0');
8568
8569 *intptr = ret;
8570 return 1;
8571}
Eric Andersencb57d552001-06-28 07:25:16 +00008572
8573/*
8574 * Convert a string of digits to an integer, printing an error message on
8575 * failure.
8576 */
8577
8578static int
Eric Andersen2870d962001-07-02 17:27:21 +00008579number(const char *s)
8580{
8581 int i;
8582 if (! is_number(s, &i))
Eric Andersencb57d552001-06-28 07:25:16 +00008583 error("Illegal number: %s", s);
Eric Andersen2870d962001-07-02 17:27:21 +00008584 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00008585}
8586
Eric Andersencb57d552001-06-28 07:25:16 +00008587/*
8588 * Produce a possibly single quoted string suitable as input to the shell.
8589 * The return string is allocated on the stack.
8590 */
8591
8592static char *
8593single_quote(const char *s) {
8594 char *p;
8595
8596 STARTSTACKSTR(p);
8597
8598 do {
8599 char *q = p;
8600 size_t len1, len1p, len2, len2p;
8601
8602 len1 = strcspn(s, "'");
8603 len2 = strspn(s + len1, "'");
8604
8605 len1p = len1 ? len1 + 2 : len1;
8606 switch (len2) {
8607 case 0:
8608 len2p = 0;
8609 break;
8610 case 1:
8611 len2p = 2;
8612 break;
8613 default:
8614 len2p = len2 + 2;
8615 }
8616
8617 CHECKSTRSPACE(len1p + len2p + 1, p);
8618
8619 if (len1) {
8620 *p = '\'';
Eric Andersencb57d552001-06-28 07:25:16 +00008621 q = p + 1 + len1;
8622 memcpy(p + 1, s, len1);
Eric Andersencb57d552001-06-28 07:25:16 +00008623 *q++ = '\'';
8624 s += len1;
8625 }
8626
8627 switch (len2) {
8628 case 0:
8629 break;
8630 case 1:
8631 *q++ = '\\';
8632 *q = '\'';
8633 s++;
8634 break;
8635 default:
8636 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008637 q += 1 + len2;
8638 memcpy(q + 1, s, len2);
8639 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008640 s += len2;
8641 }
8642
8643 STADJUST(len1p + len2p, p);
8644 } while (*s);
8645
8646 USTPUTC(0, p);
8647
8648 return grabstackstr(p);
8649}
8650
8651/*
8652 * Like strdup but works with the ash stack.
8653 */
8654
8655static char *
8656sstrdup(const char *p)
8657{
8658 size_t len = strlen(p) + 1;
8659 return memcpy(stalloc(len), p, len);
8660}
8661
Eric Andersencb57d552001-06-28 07:25:16 +00008662
8663/*
Eric Andersencb57d552001-06-28 07:25:16 +00008664 * Routine for dealing with parsed shell commands.
8665 */
8666
8667
Eric Andersen62483552001-07-10 06:09:16 +00008668static void sizenodelist (const struct nodelist *);
8669static struct nodelist *copynodelist (const struct nodelist *);
8670static char *nodesavestr (const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00008671
8672static void
Eric Andersen62483552001-07-10 06:09:16 +00008673calcsize(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008674{
8675 if (n == NULL)
8676 return;
8677 funcblocksize += nodesize[n->type];
8678 switch (n->type) {
8679 case NSEMI:
8680 case NAND:
8681 case NOR:
8682 case NWHILE:
8683 case NUNTIL:
8684 calcsize(n->nbinary.ch2);
8685 calcsize(n->nbinary.ch1);
8686 break;
8687 case NCMD:
8688 calcsize(n->ncmd.redirect);
8689 calcsize(n->ncmd.args);
8690 calcsize(n->ncmd.assign);
8691 break;
8692 case NPIPE:
8693 sizenodelist(n->npipe.cmdlist);
8694 break;
8695 case NREDIR:
8696 case NBACKGND:
8697 case NSUBSHELL:
8698 calcsize(n->nredir.redirect);
8699 calcsize(n->nredir.n);
8700 break;
8701 case NIF:
8702 calcsize(n->nif.elsepart);
8703 calcsize(n->nif.ifpart);
8704 calcsize(n->nif.test);
8705 break;
8706 case NFOR:
8707 funcstringsize += strlen(n->nfor.var) + 1;
8708 calcsize(n->nfor.body);
8709 calcsize(n->nfor.args);
8710 break;
8711 case NCASE:
8712 calcsize(n->ncase.cases);
8713 calcsize(n->ncase.expr);
8714 break;
8715 case NCLIST:
8716 calcsize(n->nclist.body);
8717 calcsize(n->nclist.pattern);
8718 calcsize(n->nclist.next);
8719 break;
8720 case NDEFUN:
8721 case NARG:
8722 sizenodelist(n->narg.backquote);
8723 funcstringsize += strlen(n->narg.text) + 1;
8724 calcsize(n->narg.next);
8725 break;
8726 case NTO:
8727 case NFROM:
8728 case NFROMTO:
8729 case NAPPEND:
8730 case NTOOV:
8731 calcsize(n->nfile.fname);
8732 calcsize(n->nfile.next);
8733 break;
8734 case NTOFD:
8735 case NFROMFD:
8736 calcsize(n->ndup.vname);
8737 calcsize(n->ndup.next);
8738 break;
8739 case NHERE:
8740 case NXHERE:
8741 calcsize(n->nhere.doc);
8742 calcsize(n->nhere.next);
8743 break;
8744 case NNOT:
8745 calcsize(n->nnot.com);
8746 break;
8747 };
8748}
8749
Eric Andersencb57d552001-06-28 07:25:16 +00008750static void
Eric Andersen62483552001-07-10 06:09:16 +00008751sizenodelist(const struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008752{
8753 while (lp) {
8754 funcblocksize += ALIGN(sizeof(struct nodelist));
8755 calcsize(lp->n);
8756 lp = lp->next;
8757 }
8758}
8759
8760
Eric Andersencb57d552001-06-28 07:25:16 +00008761static union node *
Eric Andersen62483552001-07-10 06:09:16 +00008762copynode(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008763{
Eric Andersen62483552001-07-10 06:09:16 +00008764 union node *new;
Eric Andersencb57d552001-06-28 07:25:16 +00008765
8766 if (n == NULL)
8767 return NULL;
8768 new = funcblock;
8769 funcblock = (char *) funcblock + nodesize[n->type];
8770 switch (n->type) {
8771 case NSEMI:
8772 case NAND:
8773 case NOR:
8774 case NWHILE:
8775 case NUNTIL:
8776 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8777 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8778 break;
8779 case NCMD:
8780 new->ncmd.redirect = copynode(n->ncmd.redirect);
8781 new->ncmd.args = copynode(n->ncmd.args);
8782 new->ncmd.assign = copynode(n->ncmd.assign);
8783 new->ncmd.backgnd = n->ncmd.backgnd;
8784 break;
8785 case NPIPE:
8786 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8787 new->npipe.backgnd = n->npipe.backgnd;
8788 break;
8789 case NREDIR:
8790 case NBACKGND:
8791 case NSUBSHELL:
8792 new->nredir.redirect = copynode(n->nredir.redirect);
8793 new->nredir.n = copynode(n->nredir.n);
8794 break;
8795 case NIF:
8796 new->nif.elsepart = copynode(n->nif.elsepart);
8797 new->nif.ifpart = copynode(n->nif.ifpart);
8798 new->nif.test = copynode(n->nif.test);
8799 break;
8800 case NFOR:
8801 new->nfor.var = nodesavestr(n->nfor.var);
8802 new->nfor.body = copynode(n->nfor.body);
8803 new->nfor.args = copynode(n->nfor.args);
8804 break;
8805 case NCASE:
8806 new->ncase.cases = copynode(n->ncase.cases);
8807 new->ncase.expr = copynode(n->ncase.expr);
8808 break;
8809 case NCLIST:
8810 new->nclist.body = copynode(n->nclist.body);
8811 new->nclist.pattern = copynode(n->nclist.pattern);
8812 new->nclist.next = copynode(n->nclist.next);
8813 break;
8814 case NDEFUN:
8815 case NARG:
8816 new->narg.backquote = copynodelist(n->narg.backquote);
8817 new->narg.text = nodesavestr(n->narg.text);
8818 new->narg.next = copynode(n->narg.next);
8819 break;
8820 case NTO:
8821 case NFROM:
8822 case NFROMTO:
8823 case NAPPEND:
8824 case NTOOV:
8825 new->nfile.fname = copynode(n->nfile.fname);
8826 new->nfile.fd = n->nfile.fd;
8827 new->nfile.next = copynode(n->nfile.next);
8828 break;
8829 case NTOFD:
8830 case NFROMFD:
8831 new->ndup.vname = copynode(n->ndup.vname);
8832 new->ndup.dupfd = n->ndup.dupfd;
8833 new->ndup.fd = n->ndup.fd;
8834 new->ndup.next = copynode(n->ndup.next);
8835 break;
8836 case NHERE:
8837 case NXHERE:
8838 new->nhere.doc = copynode(n->nhere.doc);
8839 new->nhere.fd = n->nhere.fd;
8840 new->nhere.next = copynode(n->nhere.next);
8841 break;
8842 case NNOT:
8843 new->nnot.com = copynode(n->nnot.com);
8844 break;
8845 };
8846 new->type = n->type;
Eric Andersen62483552001-07-10 06:09:16 +00008847 return new;
Eric Andersencb57d552001-06-28 07:25:16 +00008848}
8849
8850
8851static struct nodelist *
Eric Andersen62483552001-07-10 06:09:16 +00008852copynodelist(const struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008853{
8854 struct nodelist *start;
8855 struct nodelist **lpp;
8856
8857 lpp = &start;
8858 while (lp) {
8859 *lpp = funcblock;
8860 funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist));
8861 (*lpp)->n = copynode(lp->n);
8862 lp = lp->next;
8863 lpp = &(*lpp)->next;
8864 }
8865 *lpp = NULL;
8866 return start;
8867}
8868
8869
Eric Andersencb57d552001-06-28 07:25:16 +00008870static char *
Eric Andersen62483552001-07-10 06:09:16 +00008871nodesavestr(const char *s)
Eric Andersencb57d552001-06-28 07:25:16 +00008872{
8873#ifdef _GNU_SOURCE
8874 char *rtn = funcstring;
8875
8876 funcstring = stpcpy(funcstring, s) + 1;
8877 return rtn;
8878#else
Eric Andersen62483552001-07-10 06:09:16 +00008879 const char *p = s;
8880 char *q = funcstring;
Eric Andersencb57d552001-06-28 07:25:16 +00008881 char *rtn = funcstring;
8882
8883 while ((*q++ = *p++) != '\0')
8884 continue;
8885 funcstring = q;
8886 return rtn;
8887#endif
8888}
8889
Eric Andersencb57d552001-06-28 07:25:16 +00008890#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00008891static int getopts (char *, char *, char **, int *, int *);
Eric Andersencb57d552001-06-28 07:25:16 +00008892#endif
8893
8894
8895/*
8896 * Process the shell command line arguments.
8897 */
8898
8899static void
8900procargs(argc, argv)
8901 int argc;
8902 char **argv;
8903{
8904 int i;
8905
8906 argptr = argv;
8907 if (argc > 0)
8908 argptr++;
8909 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00008910 optent_val(i) = 2;
Eric Andersencb57d552001-06-28 07:25:16 +00008911 options(1);
8912 if (*argptr == NULL && minusc == NULL)
8913 sflag = 1;
8914 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8915 iflag = 1;
8916 if (mflag == 2)
8917 mflag = iflag;
8918 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00008919 if (optent_val(i) == 2)
8920 optent_val(i) = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008921 arg0 = argv[0];
8922 if (sflag == 0 && minusc == NULL) {
8923 commandname = argv[0];
8924 arg0 = *argptr++;
8925 setinputfile(arg0, 0);
8926 commandname = arg0;
8927 }
8928 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8929 if (argptr && minusc && *argptr)
Eric Andersen2870d962001-07-02 17:27:21 +00008930 arg0 = *argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00008931
8932 shellparam.p = argptr;
8933 shellparam.optind = 1;
8934 shellparam.optoff = -1;
8935 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8936 while (*argptr) {
8937 shellparam.nparam++;
8938 argptr++;
8939 }
8940 optschanged();
8941}
8942
8943
Eric Andersencb57d552001-06-28 07:25:16 +00008944
8945/*
8946 * Process shell options. The global variable argptr contains a pointer
8947 * to the argument list; we advance it past the options.
8948 */
8949
Eric Andersen62483552001-07-10 06:09:16 +00008950static inline void
8951minus_o(const char *name, int val)
8952{
8953 int i;
8954
8955 if (name == NULL) {
8956 out1str("Current option settings\n");
8957 for (i = 0; i < NOPTS; i++)
8958 printf("%-16s%s\n", optent_name(optlist[i]),
8959 optent_val(i) ? "on" : "off");
8960 } else {
8961 for (i = 0; i < NOPTS; i++)
8962 if (equal(name, optent_name(optlist[i]))) {
8963 setoption(optent_letter(optlist[i]), val);
8964 return;
8965 }
8966 error("Illegal option -o %s", name);
8967 }
8968}
8969
8970
Eric Andersencb57d552001-06-28 07:25:16 +00008971static void
Eric Andersen62483552001-07-10 06:09:16 +00008972options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00008973{
8974 char *p;
8975 int val;
8976 int c;
8977
8978 if (cmdline)
8979 minusc = NULL;
8980 while ((p = *argptr) != NULL) {
8981 argptr++;
8982 if ((c = *p++) == '-') {
8983 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00008984 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8985 if (!cmdline) {
8986 /* "-" means turn off -x and -v */
8987 if (p[0] == '\0')
8988 xflag = vflag = 0;
8989 /* "--" means reset params */
8990 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00008991 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00008992 }
8993 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00008994 }
8995 } else if (c == '+') {
8996 val = 0;
8997 } else {
8998 argptr--;
8999 break;
9000 }
9001 while ((c = *p++) != '\0') {
9002 if (c == 'c' && cmdline) {
9003 char *q;
Eric Andersen2870d962001-07-02 17:27:21 +00009004#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */
Eric Andersencb57d552001-06-28 07:25:16 +00009005 if (*p == '\0')
9006#endif
9007 q = *argptr++;
9008 if (q == NULL || minusc != NULL)
9009 error("Bad -c option");
9010 minusc = q;
9011#ifdef NOHACK
9012 break;
9013#endif
9014 } else if (c == 'o') {
9015 minus_o(*argptr, val);
9016 if (*argptr)
9017 argptr++;
9018 } else {
9019 setoption(c, val);
9020 }
9021 }
9022 }
9023}
9024
Eric Andersencb57d552001-06-28 07:25:16 +00009025
9026static void
Eric Andersen2870d962001-07-02 17:27:21 +00009027setoption(int flag, int val)
9028{
Eric Andersencb57d552001-06-28 07:25:16 +00009029 int i;
9030
9031 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009032 if (optent_letter(optlist[i]) == flag) {
9033 optent_val(i) = val;
Eric Andersencb57d552001-06-28 07:25:16 +00009034 if (val) {
9035 /* #%$ hack for ksh semantics */
9036 if (flag == 'V')
9037 Eflag = 0;
9038 else if (flag == 'E')
9039 Vflag = 0;
9040 }
9041 return;
9042 }
9043 error("Illegal option -%c", flag);
9044 /* NOTREACHED */
9045}
9046
9047
9048
Eric Andersencb57d552001-06-28 07:25:16 +00009049/*
9050 * Set the shell parameters.
9051 */
9052
9053static void
Eric Andersen2870d962001-07-02 17:27:21 +00009054setparam(char **argv)
9055{
Eric Andersencb57d552001-06-28 07:25:16 +00009056 char **newparam;
9057 char **ap;
9058 int nparam;
9059
9060 for (nparam = 0 ; argv[nparam] ; nparam++);
9061 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
9062 while (*argv) {
9063 *ap++ = savestr(*argv++);
9064 }
9065 *ap = NULL;
9066 freeparam(&shellparam);
9067 shellparam.malloc = 1;
9068 shellparam.nparam = nparam;
9069 shellparam.p = newparam;
9070 shellparam.optind = 1;
9071 shellparam.optoff = -1;
9072}
9073
9074
9075/*
9076 * Free the list of positional parameters.
9077 */
9078
9079static void
Eric Andersen2870d962001-07-02 17:27:21 +00009080freeparam(volatile struct shparam *param)
9081{
Eric Andersencb57d552001-06-28 07:25:16 +00009082 char **ap;
9083
9084 if (param->malloc) {
9085 for (ap = param->p ; *ap ; ap++)
9086 ckfree(*ap);
9087 ckfree(param->p);
9088 }
9089}
9090
9091
9092
9093/*
9094 * The shift builtin command.
9095 */
9096
9097static int
9098shiftcmd(argc, argv)
9099 int argc;
9100 char **argv;
9101{
9102 int n;
9103 char **ap1, **ap2;
9104
9105 n = 1;
9106 if (argc > 1)
9107 n = number(argv[1]);
9108 if (n > shellparam.nparam)
9109 error("can't shift that many");
9110 INTOFF;
9111 shellparam.nparam -= n;
9112 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
9113 if (shellparam.malloc)
9114 ckfree(*ap1);
9115 }
9116 ap2 = shellparam.p;
9117 while ((*ap2++ = *ap1++) != NULL);
9118 shellparam.optind = 1;
9119 shellparam.optoff = -1;
9120 INTON;
9121 return 0;
9122}
9123
9124
9125
9126/*
9127 * The set command builtin.
9128 */
9129
9130static int
9131setcmd(argc, argv)
9132 int argc;
9133 char **argv;
9134{
9135 if (argc == 1)
9136 return showvarscmd(argc, argv);
9137 INTOFF;
9138 options(0);
9139 optschanged();
9140 if (*argptr != NULL) {
9141 setparam(argptr);
9142 }
9143 INTON;
9144 return 0;
9145}
9146
9147
9148static void
Eric Andersen2870d962001-07-02 17:27:21 +00009149getoptsreset(const char *value)
Eric Andersencb57d552001-06-28 07:25:16 +00009150{
9151 shellparam.optind = number(value);
9152 shellparam.optoff = -1;
9153}
9154
Eric Andersen2870d962001-07-02 17:27:21 +00009155#ifdef BB_LOCALE_SUPPORT
9156static void change_lc_all(const char *value)
9157{
9158 if(value != 0 && *value != 0)
9159 setlocale(LC_ALL, value);
9160}
9161
9162static void change_lc_ctype(const char *value)
9163{
9164 if(value != 0 && *value != 0)
9165 setlocale(LC_CTYPE, value);
9166}
9167
9168#endif
9169
Eric Andersencb57d552001-06-28 07:25:16 +00009170#ifdef ASH_GETOPTS
9171/*
9172 * The getopts builtin. Shellparam.optnext points to the next argument
9173 * to be processed. Shellparam.optptr points to the next character to
9174 * be processed in the current argument. If shellparam.optnext is NULL,
9175 * then it's the first time getopts has been called.
9176 */
9177
9178static int
9179getoptscmd(argc, argv)
9180 int argc;
9181 char **argv;
9182{
9183 char **optbase;
9184
9185 if (argc < 3)
9186 error("Usage: getopts optstring var [arg]");
9187 else if (argc == 3) {
9188 optbase = shellparam.p;
9189 if (shellparam.optind > shellparam.nparam + 1) {
9190 shellparam.optind = 1;
9191 shellparam.optoff = -1;
9192 }
9193 }
9194 else {
9195 optbase = &argv[3];
9196 if (shellparam.optind > argc - 2) {
9197 shellparam.optind = 1;
9198 shellparam.optoff = -1;
9199 }
9200 }
9201
9202 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9203 &shellparam.optoff);
9204}
9205
9206/*
9207 * Safe version of setvar, returns 1 on success 0 on failure.
9208 */
9209
9210static int
9211setvarsafe(name, val, flags)
9212 const char *name, *val;
9213 int flags;
9214{
9215 struct jmploc jmploc;
9216 struct jmploc *volatile savehandler = handler;
9217 int err = 0;
9218#ifdef __GNUC__
9219 (void) &err;
9220#endif
9221
9222 if (setjmp(jmploc.loc))
9223 err = 1;
9224 else {
9225 handler = &jmploc;
9226 setvar(name, val, flags);
9227 }
9228 handler = savehandler;
9229 return err;
9230}
9231
9232static int
9233getopts(optstr, optvar, optfirst, myoptind, optoff)
9234 char *optstr;
9235 char *optvar;
9236 char **optfirst;
9237 int *myoptind;
9238 int *optoff;
9239{
9240 char *p, *q;
9241 char c = '?';
9242 int done = 0;
9243 int err = 0;
9244 char s[10];
9245 char **optnext = optfirst + *myoptind - 1;
9246
9247 if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
9248 strlen(*(optnext - 1)) < *optoff)
9249 p = NULL;
9250 else
9251 p = *(optnext - 1) + *optoff;
9252 if (p == NULL || *p == '\0') {
9253 /* Current word is done, advance */
9254 if (optnext == NULL)
9255 return 1;
9256 p = *optnext;
9257 if (p == NULL || *p != '-' || *++p == '\0') {
9258atend:
9259 *myoptind = optnext - optfirst + 1;
9260 p = NULL;
9261 done = 1;
9262 goto out;
9263 }
9264 optnext++;
Eric Andersen2870d962001-07-02 17:27:21 +00009265 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009266 goto atend;
9267 }
9268
9269 c = *p++;
9270 for (q = optstr; *q != c; ) {
9271 if (*q == '\0') {
9272 if (optstr[0] == ':') {
9273 s[0] = c;
9274 s[1] = '\0';
9275 err |= setvarsafe("OPTARG", s, 0);
9276 }
9277 else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009278 out2fmt("Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009279 (void) unsetvar("OPTARG");
9280 }
9281 c = '?';
9282 goto bad;
9283 }
9284 if (*++q == ':')
9285 q++;
9286 }
9287
9288 if (*++q == ':') {
9289 if (*p == '\0' && (p = *optnext) == NULL) {
9290 if (optstr[0] == ':') {
9291 s[0] = c;
9292 s[1] = '\0';
9293 err |= setvarsafe("OPTARG", s, 0);
9294 c = ':';
9295 }
9296 else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009297 out2fmt("No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009298 (void) unsetvar("OPTARG");
9299 c = '?';
9300 }
9301 goto bad;
9302 }
9303
9304 if (p == *optnext)
9305 optnext++;
9306 setvarsafe("OPTARG", p, 0);
9307 p = NULL;
9308 }
9309 else
9310 setvarsafe("OPTARG", "", 0);
9311 *myoptind = optnext - optfirst + 1;
9312 goto out;
9313
9314bad:
9315 *myoptind = 1;
9316 p = NULL;
9317out:
9318 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersen3102ac42001-07-06 04:26:23 +00009319 snprintf(s, sizeof(s), "%d", *myoptind);
Eric Andersencb57d552001-06-28 07:25:16 +00009320 err |= setvarsafe("OPTIND", s, VNOFUNC);
9321 s[0] = c;
9322 s[1] = '\0';
9323 err |= setvarsafe(optvar, s, 0);
9324 if (err) {
9325 *myoptind = 1;
9326 *optoff = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00009327 exraise(EXERROR);
9328 }
9329 return done;
9330}
Eric Andersen2870d962001-07-02 17:27:21 +00009331#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009332
9333/*
9334 * XXX - should get rid of. have all builtins use getopt(3). the
9335 * library getopt must have the BSD extension static variable "optreset"
9336 * otherwise it can't be used within the shell safely.
9337 *
9338 * Standard option processing (a la getopt) for builtin routines. The
9339 * only argument that is passed to nextopt is the option string; the
9340 * other arguments are unnecessary. It return the character, or '\0' on
9341 * end of input.
9342 */
9343
9344static int
Eric Andersen62483552001-07-10 06:09:16 +00009345nextopt(const char *optstring)
9346{
Eric Andersencb57d552001-06-28 07:25:16 +00009347 char *p;
9348 const char *q;
9349 char c;
9350
9351 if ((p = optptr) == NULL || *p == '\0') {
9352 p = *argptr;
9353 if (p == NULL || *p != '-' || *++p == '\0')
9354 return '\0';
9355 argptr++;
Eric Andersen2870d962001-07-02 17:27:21 +00009356 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009357 return '\0';
9358 }
9359 c = *p++;
9360 for (q = optstring ; *q != c ; ) {
9361 if (*q == '\0')
9362 error("Illegal option -%c", c);
9363 if (*++q == ':')
9364 q++;
9365 }
9366 if (*++q == ':') {
9367 if (*p == '\0' && (p = *argptr++) == NULL)
9368 error("No arg for -%c option", c);
9369 optionarg = p;
9370 p = NULL;
9371 }
9372 optptr = p;
9373 return c;
9374}
9375
Eric Andersencb57d552001-06-28 07:25:16 +00009376static void
9377flushall() {
Eric Andersencb57d552001-06-28 07:25:16 +00009378 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009379 fflush(stdout);
Eric Andersencb57d552001-06-28 07:25:16 +00009380 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009381}
9382
9383
9384static void
Eric Andersen3102ac42001-07-06 04:26:23 +00009385out2fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009386{
9387 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00009388 va_start(ap, fmt);
Eric Andersen3102ac42001-07-06 04:26:23 +00009389 vfprintf(stderr, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009390 va_end(ap);
9391}
9392
Eric Andersencb57d552001-06-28 07:25:16 +00009393/*
9394 * Version of write which resumes after a signal is caught.
9395 */
9396
9397static int
Eric Andersen2870d962001-07-02 17:27:21 +00009398xwrite(int fd, const char *buf, int nbytes)
9399{
Eric Andersencb57d552001-06-28 07:25:16 +00009400 int ntry;
9401 int i;
9402 int n;
9403
9404 n = nbytes;
9405 ntry = 0;
9406 for (;;) {
9407 i = write(fd, buf, n);
9408 if (i > 0) {
9409 if ((n -= i) <= 0)
9410 return nbytes;
9411 buf += i;
9412 ntry = 0;
9413 } else if (i == 0) {
9414 if (++ntry > 10)
9415 return nbytes - n;
9416 } else if (errno != EINTR) {
9417 return -1;
9418 }
9419 }
9420}
9421
9422
Eric Andersencb57d552001-06-28 07:25:16 +00009423/*
9424 * Shell command parser.
9425 */
9426
9427#define EOFMARKLEN 79
9428
9429
9430
9431struct heredoc {
Eric Andersen2870d962001-07-02 17:27:21 +00009432 struct heredoc *next; /* next here document in list */
9433 union node *here; /* redirection node */
9434 char *eofmark; /* string indicating end of input */
9435 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009436};
9437
Eric Andersen2870d962001-07-02 17:27:21 +00009438static struct heredoc *heredoclist; /* list of here documents to read */
9439static int parsebackquote; /* nonzero if we are inside backquotes */
9440static int doprompt; /* if set, prompt the user */
9441static int needprompt; /* true if interactive and at start of line */
9442static int lasttoken; /* last token read */
Eric Andersencb57d552001-06-28 07:25:16 +00009443
Eric Andersen2870d962001-07-02 17:27:21 +00009444static char *wordtext; /* text of last word returned by readtoken */
Eric Andersencb57d552001-06-28 07:25:16 +00009445
Eric Andersen2870d962001-07-02 17:27:21 +00009446static struct nodelist *backquotelist;
9447static union node *redirnode;
Eric Andersencb57d552001-06-28 07:25:16 +00009448struct heredoc *heredoc;
Eric Andersen2870d962001-07-02 17:27:21 +00009449static int quoteflag; /* set if (part of) last token was quoted */
9450static int startlinno; /* line # where last token started */
Eric Andersencb57d552001-06-28 07:25:16 +00009451
9452
Eric Andersen2870d962001-07-02 17:27:21 +00009453static union node *list (int);
9454static union node *andor (void);
9455static union node *pipeline (void);
9456static union node *command (void);
9457static union node *simplecmd (void);
9458static void parsefname (void);
9459static void parseheredoc (void);
9460static int peektoken (void);
9461static int readtoken (void);
9462static int xxreadtoken (void);
9463static int readtoken1 (int, char const *, char *, int);
9464static int noexpand (char *);
9465static void synexpect (int) __attribute__((noreturn));
9466static void synerror (const char *) __attribute__((noreturn));
9467static void setprompt (int);
Eric Andersencb57d552001-06-28 07:25:16 +00009468
9469
9470/*
9471 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9472 * valid parse tree indicating a blank line.)
9473 */
9474
Eric Andersen2870d962001-07-02 17:27:21 +00009475static union node *
Eric Andersencb57d552001-06-28 07:25:16 +00009476parsecmd(int interact)
9477{
9478 int t;
9479
9480 tokpushback = 0;
9481 doprompt = interact;
9482 if (doprompt)
9483 setprompt(1);
9484 else
9485 setprompt(0);
9486 needprompt = 0;
9487 t = readtoken();
9488 if (t == TEOF)
9489 return NEOF;
9490 if (t == TNL)
9491 return NULL;
9492 tokpushback++;
9493 return list(1);
9494}
9495
9496
9497static union node *
9498list(nlflag)
9499 int nlflag;
9500{
9501 union node *n1, *n2, *n3;
9502 int tok;
9503
9504 checkkwd = 2;
9505 if (nlflag == 0 && tokendlist[peektoken()])
9506 return NULL;
9507 n1 = NULL;
9508 for (;;) {
9509 n2 = andor();
9510 tok = readtoken();
9511 if (tok == TBACKGND) {
9512 if (n2->type == NCMD || n2->type == NPIPE) {
9513 n2->ncmd.backgnd = 1;
9514 } else if (n2->type == NREDIR) {
9515 n2->type = NBACKGND;
9516 } else {
9517 n3 = (union node *)stalloc(sizeof (struct nredir));
9518 n3->type = NBACKGND;
9519 n3->nredir.n = n2;
9520 n3->nredir.redirect = NULL;
9521 n2 = n3;
9522 }
9523 }
9524 if (n1 == NULL) {
9525 n1 = n2;
9526 }
9527 else {
9528 n3 = (union node *)stalloc(sizeof (struct nbinary));
9529 n3->type = NSEMI;
9530 n3->nbinary.ch1 = n1;
9531 n3->nbinary.ch2 = n2;
9532 n1 = n3;
9533 }
9534 switch (tok) {
9535 case TBACKGND:
9536 case TSEMI:
9537 tok = readtoken();
9538 /* fall through */
9539 case TNL:
9540 if (tok == TNL) {
9541 parseheredoc();
9542 if (nlflag)
9543 return n1;
9544 } else {
9545 tokpushback++;
9546 }
9547 checkkwd = 2;
9548 if (tokendlist[peektoken()])
9549 return n1;
9550 break;
9551 case TEOF:
9552 if (heredoclist)
9553 parseheredoc();
9554 else
Eric Andersen2870d962001-07-02 17:27:21 +00009555 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009556 return n1;
9557 default:
9558 if (nlflag)
9559 synexpect(-1);
9560 tokpushback++;
9561 return n1;
9562 }
9563 }
9564}
9565
9566
9567
9568static union node *
9569andor() {
9570 union node *n1, *n2, *n3;
9571 int t;
9572
9573 checkkwd = 1;
9574 n1 = pipeline();
9575 for (;;) {
9576 if ((t = readtoken()) == TAND) {
9577 t = NAND;
9578 } else if (t == TOR) {
9579 t = NOR;
9580 } else {
9581 tokpushback++;
9582 return n1;
9583 }
9584 checkkwd = 2;
9585 n2 = pipeline();
9586 n3 = (union node *)stalloc(sizeof (struct nbinary));
9587 n3->type = t;
9588 n3->nbinary.ch1 = n1;
9589 n3->nbinary.ch2 = n2;
9590 n1 = n3;
9591 }
9592}
9593
9594
9595
9596static union node *
9597pipeline() {
9598 union node *n1, *n2, *pipenode;
9599 struct nodelist *lp, *prev;
9600 int negate;
9601
9602 negate = 0;
9603 TRACE(("pipeline: entered\n"));
9604 if (readtoken() == TNOT) {
9605 negate = !negate;
9606 checkkwd = 1;
9607 } else
9608 tokpushback++;
9609 n1 = command();
9610 if (readtoken() == TPIPE) {
9611 pipenode = (union node *)stalloc(sizeof (struct npipe));
9612 pipenode->type = NPIPE;
9613 pipenode->npipe.backgnd = 0;
9614 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9615 pipenode->npipe.cmdlist = lp;
9616 lp->n = n1;
9617 do {
9618 prev = lp;
9619 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9620 checkkwd = 2;
9621 lp->n = command();
9622 prev->next = lp;
9623 } while (readtoken() == TPIPE);
9624 lp->next = NULL;
9625 n1 = pipenode;
9626 }
9627 tokpushback++;
9628 if (negate) {
9629 n2 = (union node *)stalloc(sizeof (struct nnot));
9630 n2->type = NNOT;
9631 n2->nnot.com = n1;
9632 return n2;
9633 } else
9634 return n1;
9635}
9636
9637
9638
9639static union node *
9640command() {
9641 union node *n1, *n2;
9642 union node *ap, **app;
9643 union node *cp, **cpp;
9644 union node *redir, **rpp;
9645 int t;
9646
9647 redir = NULL;
9648 n1 = NULL;
9649 rpp = &redir;
9650
9651 switch (readtoken()) {
9652 case TIF:
9653 n1 = (union node *)stalloc(sizeof (struct nif));
9654 n1->type = NIF;
9655 n1->nif.test = list(0);
9656 if (readtoken() != TTHEN)
9657 synexpect(TTHEN);
9658 n1->nif.ifpart = list(0);
9659 n2 = n1;
9660 while (readtoken() == TELIF) {
9661 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9662 n2 = n2->nif.elsepart;
9663 n2->type = NIF;
9664 n2->nif.test = list(0);
9665 if (readtoken() != TTHEN)
9666 synexpect(TTHEN);
9667 n2->nif.ifpart = list(0);
9668 }
9669 if (lasttoken == TELSE)
9670 n2->nif.elsepart = list(0);
9671 else {
9672 n2->nif.elsepart = NULL;
9673 tokpushback++;
9674 }
9675 if (readtoken() != TFI)
9676 synexpect(TFI);
9677 checkkwd = 1;
9678 break;
9679 case TWHILE:
9680 case TUNTIL: {
9681 int got;
9682 n1 = (union node *)stalloc(sizeof (struct nbinary));
9683 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9684 n1->nbinary.ch1 = list(0);
9685 if ((got=readtoken()) != TDO) {
9686TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
9687 synexpect(TDO);
9688 }
9689 n1->nbinary.ch2 = list(0);
9690 if (readtoken() != TDONE)
9691 synexpect(TDONE);
9692 checkkwd = 1;
9693 break;
9694 }
9695 case TFOR:
9696 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9697 synerror("Bad for loop variable");
9698 n1 = (union node *)stalloc(sizeof (struct nfor));
9699 n1->type = NFOR;
9700 n1->nfor.var = wordtext;
9701 checkkwd = 1;
9702 if (readtoken() == TIN) {
9703 app = &ap;
9704 while (readtoken() == TWORD) {
9705 n2 = (union node *)stalloc(sizeof (struct narg));
9706 n2->type = NARG;
9707 n2->narg.text = wordtext;
9708 n2->narg.backquote = backquotelist;
9709 *app = n2;
9710 app = &n2->narg.next;
9711 }
9712 *app = NULL;
9713 n1->nfor.args = ap;
9714 if (lasttoken != TNL && lasttoken != TSEMI)
9715 synexpect(-1);
9716 } else {
9717 static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
9718 '@', '=', '\0'};
9719 n2 = (union node *)stalloc(sizeof (struct narg));
9720 n2->type = NARG;
9721 n2->narg.text = argvars;
9722 n2->narg.backquote = NULL;
9723 n2->narg.next = NULL;
9724 n1->nfor.args = n2;
9725 /*
9726 * Newline or semicolon here is optional (but note
9727 * that the original Bourne shell only allowed NL).
9728 */
9729 if (lasttoken != TNL && lasttoken != TSEMI)
9730 tokpushback++;
9731 }
9732 checkkwd = 2;
9733 if (readtoken() != TDO)
9734 synexpect(TDO);
9735 n1->nfor.body = list(0);
9736 if (readtoken() != TDONE)
9737 synexpect(TDONE);
9738 checkkwd = 1;
9739 break;
9740 case TCASE:
9741 n1 = (union node *)stalloc(sizeof (struct ncase));
9742 n1->type = NCASE;
9743 if (readtoken() != TWORD)
9744 synexpect(TWORD);
9745 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9746 n2->type = NARG;
9747 n2->narg.text = wordtext;
9748 n2->narg.backquote = backquotelist;
9749 n2->narg.next = NULL;
9750 do {
9751 checkkwd = 1;
9752 } while (readtoken() == TNL);
9753 if (lasttoken != TIN)
9754 synerror("expecting \"in\"");
9755 cpp = &n1->ncase.cases;
9756 checkkwd = 2, readtoken();
9757 do {
9758 if (lasttoken == TLP)
9759 readtoken();
9760 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9761 cp->type = NCLIST;
9762 app = &cp->nclist.pattern;
9763 for (;;) {
9764 *app = ap = (union node *)stalloc(sizeof (struct narg));
9765 ap->type = NARG;
9766 ap->narg.text = wordtext;
9767 ap->narg.backquote = backquotelist;
9768 if (checkkwd = 2, readtoken() != TPIPE)
9769 break;
9770 app = &ap->narg.next;
9771 readtoken();
9772 }
9773 ap->narg.next = NULL;
9774 if (lasttoken != TRP)
9775 synexpect(TRP);
9776 cp->nclist.body = list(0);
9777
9778 checkkwd = 2;
9779 if ((t = readtoken()) != TESAC) {
9780 if (t != TENDCASE)
9781 synexpect(TENDCASE);
9782 else
9783 checkkwd = 2, readtoken();
9784 }
9785 cpp = &cp->nclist.next;
9786 } while(lasttoken != TESAC);
9787 *cpp = NULL;
9788 checkkwd = 1;
9789 break;
9790 case TLP:
9791 n1 = (union node *)stalloc(sizeof (struct nredir));
9792 n1->type = NSUBSHELL;
9793 n1->nredir.n = list(0);
9794 n1->nredir.redirect = NULL;
9795 if (readtoken() != TRP)
9796 synexpect(TRP);
9797 checkkwd = 1;
9798 break;
9799 case TBEGIN:
9800 n1 = list(0);
9801 if (readtoken() != TEND)
9802 synexpect(TEND);
9803 checkkwd = 1;
9804 break;
9805 /* Handle an empty command like other simple commands. */
9806 case TSEMI:
9807 case TAND:
9808 case TOR:
9809 case TNL:
9810 case TEOF:
9811 case TRP:
9812 case TBACKGND:
9813 /*
9814 * An empty command before a ; doesn't make much sense, and
9815 * should certainly be disallowed in the case of `if ;'.
9816 */
9817 if (!redir)
9818 synexpect(-1);
9819 case TWORD:
9820 case TREDIR:
9821 tokpushback++;
9822 n1 = simplecmd();
9823 return n1;
9824 default:
9825 synexpect(-1);
9826 /* NOTREACHED */
9827 }
9828
9829 /* Now check for redirection which may follow command */
9830 while (readtoken() == TREDIR) {
9831 *rpp = n2 = redirnode;
9832 rpp = &n2->nfile.next;
9833 parsefname();
9834 }
9835 tokpushback++;
9836 *rpp = NULL;
9837 if (redir) {
9838 if (n1->type != NSUBSHELL) {
9839 n2 = (union node *)stalloc(sizeof (struct nredir));
9840 n2->type = NREDIR;
9841 n2->nredir.n = n1;
9842 n1 = n2;
9843 }
9844 n1->nredir.redirect = redir;
9845 }
9846
9847 return n1;
9848}
9849
9850
9851static union node *
9852simplecmd() {
9853 union node *args, **app;
9854 union node *n = NULL;
9855 union node *vars, **vpp;
9856 union node **rpp, *redir;
9857
9858 args = NULL;
9859 app = &args;
9860 vars = NULL;
9861 vpp = &vars;
9862 redir = NULL;
9863 rpp = &redir;
9864
9865 checkalias = 2;
9866 for (;;) {
9867 switch (readtoken()) {
9868 case TWORD:
9869 case TASSIGN:
9870 n = (union node *)stalloc(sizeof (struct narg));
9871 n->type = NARG;
9872 n->narg.text = wordtext;
9873 n->narg.backquote = backquotelist;
9874 if (lasttoken == TWORD) {
9875 *app = n;
9876 app = &n->narg.next;
9877 } else {
9878 *vpp = n;
9879 vpp = &n->narg.next;
9880 }
9881 break;
9882 case TREDIR:
9883 *rpp = n = redirnode;
9884 rpp = &n->nfile.next;
Eric Andersen2870d962001-07-02 17:27:21 +00009885 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +00009886 break;
9887 case TLP:
9888 if (
9889 args && app == &args->narg.next &&
9890 !vars && !redir
9891 ) {
9892 /* We have a function */
9893 if (readtoken() != TRP)
9894 synexpect(TRP);
Eric Andersencb57d552001-06-28 07:25:16 +00009895 n->type = NDEFUN;
9896 checkkwd = 2;
9897 n->narg.next = command();
9898 return n;
9899 }
9900 /* fall through */
9901 default:
9902 tokpushback++;
9903 goto out;
9904 }
9905 }
9906out:
9907 *app = NULL;
9908 *vpp = NULL;
9909 *rpp = NULL;
9910 n = (union node *)stalloc(sizeof (struct ncmd));
9911 n->type = NCMD;
9912 n->ncmd.backgnd = 0;
9913 n->ncmd.args = args;
9914 n->ncmd.assign = vars;
9915 n->ncmd.redirect = redir;
9916 return n;
9917}
9918
9919static union node *
Eric Andersen2870d962001-07-02 17:27:21 +00009920makename(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009921 union node *n;
9922
9923 n = (union node *)stalloc(sizeof (struct narg));
9924 n->type = NARG;
9925 n->narg.next = NULL;
9926 n->narg.text = wordtext;
9927 n->narg.backquote = backquotelist;
9928 return n;
9929}
9930
9931static void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +00009932{
Eric Andersencb57d552001-06-28 07:25:16 +00009933 TRACE(("Fix redir %s %d\n", text, err));
9934 if (!err)
9935 n->ndup.vname = NULL;
9936
9937 if (is_digit(text[0]) && text[1] == '\0')
9938 n->ndup.dupfd = digit_val(text[0]);
9939 else if (text[0] == '-' && text[1] == '\0')
9940 n->ndup.dupfd = -1;
9941 else {
9942
9943 if (err)
9944 synerror("Bad fd number");
9945 else
9946 n->ndup.vname = makename();
9947 }
9948}
9949
9950
9951static void
Eric Andersen2870d962001-07-02 17:27:21 +00009952parsefname(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009953 union node *n = redirnode;
9954
9955 if (readtoken() != TWORD)
9956 synexpect(-1);
9957 if (n->type == NHERE) {
9958 struct heredoc *here = heredoc;
9959 struct heredoc *p;
9960 int i;
9961
9962 if (quoteflag == 0)
9963 n->type = NXHERE;
9964 TRACE(("Here document %d\n", n->type));
9965 if (here->striptabs) {
9966 while (*wordtext == '\t')
9967 wordtext++;
9968 }
9969 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9970 synerror("Illegal eof marker for << redirection");
9971 rmescapes(wordtext);
9972 here->eofmark = wordtext;
9973 here->next = NULL;
9974 if (heredoclist == NULL)
9975 heredoclist = here;
9976 else {
9977 for (p = heredoclist ; p->next ; p = p->next);
9978 p->next = here;
9979 }
9980 } else if (n->type == NTOFD || n->type == NFROMFD) {
9981 fixredir(n, wordtext, 0);
9982 } else {
9983 n->nfile.fname = makename();
9984 }
9985}
9986
9987
9988/*
9989 * Input any here documents.
9990 */
9991
9992static void
9993parseheredoc() {
9994 struct heredoc *here;
9995 union node *n;
9996
9997 while (heredoclist) {
9998 here = heredoclist;
9999 heredoclist = here->next;
10000 if (needprompt) {
10001 setprompt(2);
10002 needprompt = 0;
10003 }
10004 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
10005 here->eofmark, here->striptabs);
10006 n = (union node *)stalloc(sizeof (struct narg));
10007 n->narg.type = NARG;
10008 n->narg.next = NULL;
10009 n->narg.text = wordtext;
10010 n->narg.backquote = backquotelist;
10011 here->here->nhere.doc = n;
10012 }
10013}
10014
10015static int
10016peektoken() {
10017 int t;
10018
10019 t = readtoken();
10020 tokpushback++;
10021 return (t);
10022}
10023
10024static int
10025readtoken() {
10026 int t;
Eric Andersen7467c8d2001-07-12 20:26:32 +000010027
Eric Andersen2870d962001-07-02 17:27:21 +000010028#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010029 int savecheckalias = checkalias;
Eric Andersen7467c8d2001-07-12 20:26:32 +000010030 int savecheckkwd = checkkwd;
Eric Andersencb57d552001-06-28 07:25:16 +000010031 struct alias *ap;
Eric Andersen2870d962001-07-02 17:27:21 +000010032#endif
10033
Eric Andersencb57d552001-06-28 07:25:16 +000010034#ifdef DEBUG
10035 int alreadyseen = tokpushback;
10036#endif
10037
Eric Andersen2870d962001-07-02 17:27:21 +000010038#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010039top:
Eric Andersen2870d962001-07-02 17:27:21 +000010040#endif
10041
Eric Andersencb57d552001-06-28 07:25:16 +000010042 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +000010043
10044#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010045 checkalias = savecheckalias;
Eric Andersen2870d962001-07-02 17:27:21 +000010046#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010047
10048 if (checkkwd) {
10049 /*
10050 * eat newlines
10051 */
10052 if (checkkwd == 2) {
10053 checkkwd = 0;
10054 while (t == TNL) {
10055 parseheredoc();
10056 t = xxreadtoken();
10057 }
10058 }
10059 checkkwd = 0;
10060 /*
10061 * check for keywords
10062 */
10063 if (t == TWORD && !quoteflag)
10064 {
10065 const char *const *pp;
10066
10067 if ((pp = findkwd(wordtext))) {
10068 lasttoken = t = pp - parsekwd + KWDOFFSET;
10069 TRACE(("keyword %s recognized\n", tokname[t]));
10070 goto out;
10071 }
10072 }
10073 }
10074
Eric Andersen7467c8d2001-07-12 20:26:32 +000010075
Eric Andersencb57d552001-06-28 07:25:16 +000010076 if (t != TWORD) {
10077 if (t != TREDIR) {
10078 checkalias = 0;
10079 }
10080 } else if (checkalias == 2 && isassignment(wordtext)) {
10081 lasttoken = t = TASSIGN;
Eric Andersen7467c8d2001-07-12 20:26:32 +000010082#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010083 } else if (checkalias) {
10084 if (!quoteflag && (ap = lookupalias(wordtext, 1)) != NULL) {
10085 if (*ap->val) {
10086 pushstring(ap->val, strlen(ap->val), ap);
10087 }
10088 checkkwd = savecheckkwd;
10089 goto top;
10090 }
10091 checkalias = 0;
Eric Andersen2870d962001-07-02 17:27:21 +000010092#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +000010093 }
Eric Andersencb57d552001-06-28 07:25:16 +000010094out:
10095#ifdef DEBUG
10096 if (!alreadyseen)
10097 TRACE(("token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : ""));
10098 else
10099 TRACE(("reread token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : ""));
10100#endif
10101 return (t);
10102}
10103
10104
10105/*
10106 * Read the next input token.
10107 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +000010108 * backquotes. We set quoteflag to true if any part of the word was
10109 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +000010110 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +000010111 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +000010112 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +000010113 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +000010114 *
10115 * [Change comment: here documents and internal procedures]
10116 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10117 * word parsing code into a separate routine. In this case, readtoken
10118 * doesn't need to have any internal procedures, but parseword does.
10119 * We could also make parseoperator in essence the main routine, and
10120 * have parseword (readtoken1?) handle both words and redirection.]
10121 */
10122
Eric Andersen2870d962001-07-02 17:27:21 +000010123#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010124
10125static int
10126xxreadtoken() {
10127 int c;
10128
10129 if (tokpushback) {
10130 tokpushback = 0;
10131 return lasttoken;
10132 }
10133 if (needprompt) {
10134 setprompt(2);
10135 needprompt = 0;
10136 }
10137 startlinno = plinno;
Eric Andersen2870d962001-07-02 17:27:21 +000010138 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010139 c = pgetc_macro();
10140 switch (c) {
10141 case ' ': case '\t':
Eric Andersen3102ac42001-07-06 04:26:23 +000010142#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010143 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010144#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010145 continue;
10146 case '#':
10147 while ((c = pgetc()) != '\n' && c != PEOF);
10148 pungetc();
10149 continue;
10150 case '\\':
10151 if (pgetc() == '\n') {
10152 startlinno = ++plinno;
10153 if (doprompt)
10154 setprompt(2);
10155 else
10156 setprompt(0);
10157 continue;
10158 }
10159 pungetc();
10160 goto breakloop;
10161 case '\n':
10162 plinno++;
10163 needprompt = doprompt;
10164 RETURN(TNL);
10165 case PEOF:
10166 RETURN(TEOF);
10167 case '&':
10168 if (pgetc() == '&')
10169 RETURN(TAND);
10170 pungetc();
10171 RETURN(TBACKGND);
10172 case '|':
10173 if (pgetc() == '|')
10174 RETURN(TOR);
10175 pungetc();
10176 RETURN(TPIPE);
10177 case ';':
10178 if (pgetc() == ';')
10179 RETURN(TENDCASE);
10180 pungetc();
10181 RETURN(TSEMI);
10182 case '(':
10183 RETURN(TLP);
10184 case ')':
10185 RETURN(TRP);
10186 default:
10187 goto breakloop;
10188 }
10189 }
10190breakloop:
10191 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10192#undef RETURN
10193}
10194
10195
10196
10197/*
10198 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10199 * is not NULL, read a here document. In the latter case, eofmark is the
10200 * word which marks the end of the document and striptabs is true if
10201 * leading tabs should be stripped from the document. The argument firstc
10202 * is the first character of the input token or document.
10203 *
10204 * Because C does not have internal subroutines, I have simulated them
10205 * using goto's to implement the subroutine linkage. The following macros
10206 * will run code that appears at the end of readtoken1.
10207 */
10208
Eric Andersen2870d962001-07-02 17:27:21 +000010209#define CHECKEND() {goto checkend; checkend_return:;}
10210#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10211#define PARSESUB() {goto parsesub; parsesub_return:;}
10212#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10213#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10214#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010215
10216static int
10217readtoken1(firstc, syntax, eofmark, striptabs)
10218 int firstc;
10219 char const *syntax;
10220 char *eofmark;
10221 int striptabs;
10222 {
10223 int c = firstc;
10224 char *out;
10225 int len;
10226 char line[EOFMARKLEN + 1];
10227 struct nodelist *bqlist;
10228 int quotef;
10229 int dblquote;
Eric Andersen2870d962001-07-02 17:27:21 +000010230 int varnest; /* levels of variables expansion */
10231 int arinest; /* levels of arithmetic expansion */
10232 int parenlevel; /* levels of parens in arithmetic */
10233 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +000010234 int oldstyle;
Eric Andersen2870d962001-07-02 17:27:21 +000010235 char const *prevsyntax; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010236#if __GNUC__
10237 /* Avoid longjmp clobbering */
10238 (void) &out;
10239 (void) &quotef;
10240 (void) &dblquote;
10241 (void) &varnest;
10242 (void) &arinest;
10243 (void) &parenlevel;
10244 (void) &dqvarnest;
10245 (void) &oldstyle;
10246 (void) &prevsyntax;
10247 (void) &syntax;
10248#endif
10249
10250 startlinno = plinno;
10251 dblquote = 0;
10252 if (syntax == DQSYNTAX)
10253 dblquote = 1;
10254 quotef = 0;
10255 bqlist = NULL;
10256 varnest = 0;
10257 arinest = 0;
10258 parenlevel = 0;
10259 dqvarnest = 0;
10260
10261 STARTSTACKSTR(out);
Eric Andersen2870d962001-07-02 17:27:21 +000010262 loop: { /* for each line, until end of word */
10263 CHECKEND(); /* set c to PEOF if at end of here document */
10264 for (;;) { /* until end of line or end of word */
10265 CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
Eric Andersencb57d552001-06-28 07:25:16 +000010266 switch(syntax[c]) {
Eric Andersen2870d962001-07-02 17:27:21 +000010267 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010268 if (syntax == BASESYNTAX)
Eric Andersen2870d962001-07-02 17:27:21 +000010269 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010270 USTPUTC(c, out);
10271 plinno++;
10272 if (doprompt)
10273 setprompt(2);
10274 else
10275 setprompt(0);
10276 c = pgetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010277 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010278 case CWORD:
10279 USTPUTC(c, out);
10280 break;
10281 case CCTL:
10282 if ((eofmark == NULL || dblquote) &&
10283 dqvarnest == 0)
10284 USTPUTC(CTLESC, out);
10285 USTPUTC(c, out);
10286 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010287 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010288 c = pgetc2();
10289 if (c == PEOF) {
10290 USTPUTC('\\', out);
10291 pungetc();
10292 } else if (c == '\n') {
10293 if (doprompt)
10294 setprompt(2);
10295 else
10296 setprompt(0);
10297 } else {
10298 if (dblquote && c != '\\' && c != '`' && c != '$'
10299 && (c != '"' || eofmark != NULL))
10300 USTPUTC('\\', out);
10301 if (SQSYNTAX[c] == CCTL)
10302 USTPUTC(CTLESC, out);
10303 else if (eofmark == NULL)
10304 USTPUTC(CTLQUOTEMARK, out);
10305 USTPUTC(c, out);
10306 quotef++;
10307 }
10308 break;
10309 case CSQUOTE:
10310 if (eofmark == NULL)
10311 USTPUTC(CTLQUOTEMARK, out);
10312 syntax = SQSYNTAX;
10313 break;
10314 case CDQUOTE:
10315 if (eofmark == NULL)
10316 USTPUTC(CTLQUOTEMARK, out);
10317 syntax = DQSYNTAX;
10318 dblquote = 1;
10319 break;
10320 case CENDQUOTE:
10321 if (eofmark != NULL && arinest == 0 &&
10322 varnest == 0) {
10323 USTPUTC(c, out);
10324 } else {
10325 if (arinest) {
10326 syntax = ARISYNTAX;
10327 dblquote = 0;
10328 } else if (eofmark == NULL &&
10329 dqvarnest == 0) {
10330 syntax = BASESYNTAX;
10331 dblquote = 0;
10332 }
10333 quotef++;
10334 }
10335 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010336 case CVAR: /* '$' */
10337 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010338 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010339 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010340 if (varnest > 0) {
10341 varnest--;
10342 if (dqvarnest > 0) {
10343 dqvarnest--;
10344 }
10345 USTPUTC(CTLENDVAR, out);
10346 } else {
10347 USTPUTC(c, out);
10348 }
10349 break;
10350#ifdef ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +000010351 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010352 parenlevel++;
10353 USTPUTC(c, out);
10354 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010355 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010356 if (parenlevel > 0) {
10357 USTPUTC(c, out);
10358 --parenlevel;
10359 } else {
10360 if (pgetc() == ')') {
10361 if (--arinest == 0) {
10362 USTPUTC(CTLENDARI, out);
10363 syntax = prevsyntax;
10364 if (syntax == DQSYNTAX)
10365 dblquote = 1;
10366 else
10367 dblquote = 0;
10368 } else
10369 USTPUTC(')', out);
10370 } else {
10371 /*
10372 * unbalanced parens
10373 * (don't 2nd guess - no error)
10374 */
10375 pungetc();
10376 USTPUTC(')', out);
10377 }
10378 }
10379 break;
10380#endif
Eric Andersen2870d962001-07-02 17:27:21 +000010381 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010382 PARSEBACKQOLD();
10383 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010384 case CENDFILE:
10385 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010386 case CIGN:
10387 break;
10388 default:
10389 if (varnest == 0)
Eric Andersen2870d962001-07-02 17:27:21 +000010390 goto endword; /* exit outer loop */
Eric Andersen3102ac42001-07-06 04:26:23 +000010391#ifdef ASH_ALIAS
10392 if (c != PEOA)
10393#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010394 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010395
Eric Andersencb57d552001-06-28 07:25:16 +000010396 }
10397 c = pgetc_macro();
10398 }
10399 }
10400endword:
10401 if (syntax == ARISYNTAX)
10402 synerror("Missing '))'");
10403 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10404 synerror("Unterminated quoted string");
10405 if (varnest != 0) {
10406 startlinno = plinno;
10407 synerror("Missing '}'");
10408 }
10409 USTPUTC('\0', out);
10410 len = out - stackblock();
10411 out = stackblock();
10412 if (eofmark == NULL) {
10413 if ((c == '>' || c == '<')
10414 && quotef == 0
10415 && len <= 2
10416 && (*out == '\0' || is_digit(*out))) {
10417 PARSEREDIR();
10418 return lasttoken = TREDIR;
10419 } else {
10420 pungetc();
10421 }
10422 }
10423 quoteflag = quotef;
10424 backquotelist = bqlist;
10425 grabstackblock(len);
10426 wordtext = out;
10427 return lasttoken = TWORD;
10428/* end of readtoken routine */
10429
10430
10431
10432/*
10433 * Check to see whether we are at the end of the here document. When this
10434 * is called, c is set to the first character of the next input line. If
10435 * we are at the end of the here document, this routine sets the c to PEOF.
10436 */
10437
10438checkend: {
10439 if (eofmark) {
Eric Andersen2870d962001-07-02 17:27:21 +000010440#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010441 if (c == PEOA) {
10442 c = pgetc2();
10443 }
Eric Andersen2870d962001-07-02 17:27:21 +000010444#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010445 if (striptabs) {
10446 while (c == '\t') {
10447 c = pgetc2();
10448 }
10449 }
10450 if (c == *eofmark) {
10451 if (pfgets(line, sizeof line) != NULL) {
10452 char *p, *q;
10453
10454 p = line;
10455 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10456 if (*p == '\n' && *q == '\0') {
10457 c = PEOF;
10458 plinno++;
10459 needprompt = doprompt;
10460 } else {
10461 pushstring(line, strlen(line), NULL);
10462 }
10463 }
10464 }
10465 }
10466 goto checkend_return;
10467}
10468
10469
10470/*
10471 * Parse a redirection operator. The variable "out" points to a string
10472 * specifying the fd to be redirected. The variable "c" contains the
10473 * first character of the redirection operator.
10474 */
10475
10476parseredir: {
10477 char fd = *out;
10478 union node *np;
10479
10480 np = (union node *)stalloc(sizeof (struct nfile));
10481 if (c == '>') {
10482 np->nfile.fd = 1;
10483 c = pgetc();
10484 if (c == '>')
10485 np->type = NAPPEND;
10486 else if (c == '&')
10487 np->type = NTOFD;
10488 else if (c == '|')
10489 np->type = NTOOV;
10490 else {
10491 np->type = NTO;
10492 pungetc();
10493 }
Eric Andersen2870d962001-07-02 17:27:21 +000010494 } else { /* c == '<' */
Eric Andersencb57d552001-06-28 07:25:16 +000010495 np->nfile.fd = 0;
10496 switch (c = pgetc()) {
10497 case '<':
10498 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10499 np = (union node *)stalloc(sizeof (struct nhere));
10500 np->nfile.fd = 0;
10501 }
10502 np->type = NHERE;
10503 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10504 heredoc->here = np;
10505 if ((c = pgetc()) == '-') {
10506 heredoc->striptabs = 1;
10507 } else {
10508 heredoc->striptabs = 0;
10509 pungetc();
10510 }
10511 break;
10512
10513 case '&':
10514 np->type = NFROMFD;
10515 break;
10516
10517 case '>':
10518 np->type = NFROMTO;
10519 break;
10520
10521 default:
10522 np->type = NFROM;
10523 pungetc();
10524 break;
10525 }
10526 }
10527 if (fd != '\0')
10528 np->nfile.fd = digit_val(fd);
10529 redirnode = np;
10530 goto parseredir_return;
10531}
10532
10533
10534/*
10535 * Parse a substitution. At this point, we have read the dollar sign
10536 * and nothing else.
10537 */
10538
10539parsesub: {
10540 int subtype;
10541 int typeloc;
10542 int flags;
10543 char *p;
10544 static const char types[] = "}-+?=";
10545
10546 c = pgetc();
10547 if (
10548 c <= PEOA ||
10549 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10550 ) {
10551 USTPUTC('$', out);
10552 pungetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010553 } else if (c == '(') { /* $(command) or $((arith)) */
Eric Andersencb57d552001-06-28 07:25:16 +000010554 if (pgetc() == '(') {
10555 PARSEARITH();
10556 } else {
10557 pungetc();
10558 PARSEBACKQNEW();
10559 }
10560 } else {
10561 USTPUTC(CTLVAR, out);
10562 typeloc = out - stackblock();
10563 USTPUTC(VSNORMAL, out);
10564 subtype = VSNORMAL;
10565 if (c == '{') {
10566 c = pgetc();
10567 if (c == '#') {
10568 if ((c = pgetc()) == '}')
10569 c = '#';
10570 else
10571 subtype = VSLENGTH;
10572 }
10573 else
10574 subtype = 0;
10575 }
10576 if (c > PEOA && is_name(c)) {
10577 do {
10578 STPUTC(c, out);
10579 c = pgetc();
10580 } while (c > PEOA && is_in_name(c));
10581 } else if (is_digit(c)) {
10582 do {
10583 USTPUTC(c, out);
10584 c = pgetc();
10585 } while (is_digit(c));
10586 }
10587 else if (is_special(c)) {
10588 USTPUTC(c, out);
10589 c = pgetc();
10590 }
10591 else
Eric Andersen2870d962001-07-02 17:27:21 +000010592badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010593
10594 STPUTC('=', out);
10595 flags = 0;
10596 if (subtype == 0) {
10597 switch (c) {
10598 case ':':
10599 flags = VSNUL;
10600 c = pgetc();
10601 /*FALLTHROUGH*/
10602 default:
10603 p = strchr(types, c);
10604 if (p == NULL)
10605 goto badsub;
10606 subtype = p - types + VSNORMAL;
10607 break;
10608 case '%':
10609 case '#':
10610 {
10611 int cc = c;
10612 subtype = c == '#' ? VSTRIMLEFT :
10613 VSTRIMRIGHT;
10614 c = pgetc();
10615 if (c == cc)
10616 subtype++;
10617 else
10618 pungetc();
10619 break;
10620 }
10621 }
10622 } else {
10623 pungetc();
10624 }
10625 if (dblquote || arinest)
10626 flags |= VSQUOTE;
10627 *(stackblock() + typeloc) = subtype | flags;
10628 if (subtype != VSNORMAL) {
10629 varnest++;
10630 if (dblquote) {
10631 dqvarnest++;
10632 }
10633 }
10634 }
10635 goto parsesub_return;
10636}
10637
10638
10639/*
10640 * Called to parse command substitutions. Newstyle is set if the command
10641 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10642 * list of commands (passed by reference), and savelen is the number of
10643 * characters on the top of the stack which must be preserved.
10644 */
10645
10646parsebackq: {
10647 struct nodelist **nlpp;
10648 int savepbq;
10649 union node *n;
10650 char *volatile str;
10651 struct jmploc jmploc;
10652 struct jmploc *volatile savehandler;
10653 int savelen;
10654 int saveprompt;
10655#ifdef __GNUC__
10656 (void) &saveprompt;
10657#endif
10658
10659 savepbq = parsebackquote;
10660 if (setjmp(jmploc.loc)) {
10661 if (str)
10662 ckfree(str);
10663 parsebackquote = 0;
10664 handler = savehandler;
10665 longjmp(handler->loc, 1);
10666 }
10667 INTOFF;
10668 str = NULL;
10669 savelen = out - stackblock();
10670 if (savelen > 0) {
10671 str = ckmalloc(savelen);
10672 memcpy(str, stackblock(), savelen);
10673 }
10674 savehandler = handler;
10675 handler = &jmploc;
10676 INTON;
Eric Andersen2870d962001-07-02 17:27:21 +000010677 if (oldstyle) {
10678 /* We must read until the closing backquote, giving special
10679 treatment to some slashes, and then push the string and
10680 reread it as input, interpreting it normally. */
10681 char *pout;
10682 int pc;
10683 int psavelen;
10684 char *pstr;
Eric Andersencb57d552001-06-28 07:25:16 +000010685
10686
Eric Andersen2870d962001-07-02 17:27:21 +000010687 STARTSTACKSTR(pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010688 for (;;) {
10689 if (needprompt) {
10690 setprompt(2);
10691 needprompt = 0;
10692 }
10693 switch (pc = pgetc()) {
10694 case '`':
10695 goto done;
10696
10697 case '\\':
Eric Andersen2870d962001-07-02 17:27:21 +000010698 if ((pc = pgetc()) == '\n') {
Eric Andersencb57d552001-06-28 07:25:16 +000010699 plinno++;
10700 if (doprompt)
10701 setprompt(2);
10702 else
10703 setprompt(0);
10704 /*
10705 * If eating a newline, avoid putting
10706 * the newline into the new character
10707 * stream (via the STPUTC after the
10708 * switch).
10709 */
10710 continue;
10711 }
Eric Andersen2870d962001-07-02 17:27:21 +000010712 if (pc != '\\' && pc != '`' && pc != '$'
10713 && (!dblquote || pc != '"'))
10714 STPUTC('\\', pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010715 if (pc > PEOA) {
10716 break;
10717 }
10718 /* fall through */
10719
10720 case PEOF:
Eric Andersen2870d962001-07-02 17:27:21 +000010721#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010722 case PEOA:
Eric Andersen2870d962001-07-02 17:27:21 +000010723#endif
10724 startlinno = plinno;
Eric Andersencb57d552001-06-28 07:25:16 +000010725 synerror("EOF in backquote substitution");
10726
10727 case '\n':
10728 plinno++;
10729 needprompt = doprompt;
10730 break;
10731
10732 default:
10733 break;
10734 }
10735 STPUTC(pc, pout);
Eric Andersen2870d962001-07-02 17:27:21 +000010736 }
Eric Andersencb57d552001-06-28 07:25:16 +000010737done:
Eric Andersen2870d962001-07-02 17:27:21 +000010738 STPUTC('\0', pout);
10739 psavelen = pout - stackblock();
10740 if (psavelen > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010741 pstr = grabstackstr(pout);
10742 setinputstring(pstr);
Eric Andersen2870d962001-07-02 17:27:21 +000010743 }
10744 }
Eric Andersencb57d552001-06-28 07:25:16 +000010745 nlpp = &bqlist;
10746 while (*nlpp)
10747 nlpp = &(*nlpp)->next;
10748 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10749 (*nlpp)->next = NULL;
10750 parsebackquote = oldstyle;
10751
10752 if (oldstyle) {
10753 saveprompt = doprompt;
10754 doprompt = 0;
10755 }
10756
10757 n = list(0);
10758
10759 if (oldstyle)
10760 doprompt = saveprompt;
10761 else {
10762 if (readtoken() != TRP)
10763 synexpect(TRP);
10764 }
10765
10766 (*nlpp)->n = n;
Eric Andersen2870d962001-07-02 17:27:21 +000010767 if (oldstyle) {
Eric Andersencb57d552001-06-28 07:25:16 +000010768 /*
10769 * Start reading from old file again, ignoring any pushed back
10770 * tokens left from the backquote parsing
10771 */
Eric Andersen2870d962001-07-02 17:27:21 +000010772 popfile();
Eric Andersencb57d552001-06-28 07:25:16 +000010773 tokpushback = 0;
10774 }
10775 while (stackblocksize() <= savelen)
10776 growstackblock();
10777 STARTSTACKSTR(out);
10778 if (str) {
10779 memcpy(out, str, savelen);
10780 STADJUST(savelen, out);
10781 INTOFF;
10782 ckfree(str);
10783 str = NULL;
10784 INTON;
10785 }
10786 parsebackquote = savepbq;
10787 handler = savehandler;
10788 if (arinest || dblquote)
10789 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10790 else
10791 USTPUTC(CTLBACKQ, out);
10792 if (oldstyle)
10793 goto parsebackq_oldreturn;
10794 else
10795 goto parsebackq_newreturn;
10796}
10797
10798/*
10799 * Parse an arithmetic expansion (indicate start of one and set state)
10800 */
10801parsearith: {
10802
10803 if (++arinest == 1) {
10804 prevsyntax = syntax;
10805 syntax = ARISYNTAX;
10806 USTPUTC(CTLARI, out);
10807 if (dblquote)
10808 USTPUTC('"',out);
10809 else
10810 USTPUTC(' ',out);
10811 } else {
10812 /*
10813 * we collapse embedded arithmetic expansion to
10814 * parenthesis, which should be equivalent
10815 */
10816 USTPUTC('(', out);
10817 }
10818 goto parsearith_return;
10819}
10820
10821} /* end of readtoken */
10822
10823
Eric Andersencb57d552001-06-28 07:25:16 +000010824/*
10825 * Returns true if the text contains nothing to expand (no dollar signs
10826 * or backquotes).
10827 */
10828
10829static int
10830noexpand(text)
10831 char *text;
10832 {
10833 char *p;
10834 char c;
10835
10836 p = text;
10837 while ((c = *p++) != '\0') {
10838 if (c == CTLQUOTEMARK)
10839 continue;
10840 if (c == CTLESC)
10841 p++;
10842 else if (BASESYNTAX[(int)c] == CCTL)
10843 return 0;
10844 }
10845 return 1;
10846}
10847
10848
10849/*
10850 * Return true if the argument is a legal variable name (a letter or
10851 * underscore followed by zero or more letters, underscores, and digits).
10852 */
10853
10854static int
Eric Andersen2870d962001-07-02 17:27:21 +000010855goodname(const char *name)
10856{
10857 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000010858
10859 p = name;
10860 if (! is_name(*p))
10861 return 0;
10862 while (*++p) {
10863 if (! is_in_name(*p))
10864 return 0;
10865 }
10866 return 1;
10867}
10868
10869
10870/*
10871 * Called when an unexpected token is read during the parse. The argument
10872 * is the token that is expected, or -1 if more than one type of token can
10873 * occur at this point.
10874 */
10875
10876static void
10877synexpect(token)
10878 int token;
10879{
10880 char msg[64];
10881
10882 if (token >= 0) {
Eric Andersen3102ac42001-07-06 04:26:23 +000010883 snprintf(msg, 64, "%s unexpected (expecting %s)",
Eric Andersencb57d552001-06-28 07:25:16 +000010884 tokname[lasttoken], tokname[token]);
10885 } else {
Eric Andersen3102ac42001-07-06 04:26:23 +000010886 snprintf(msg, 64, "%s unexpected", tokname[lasttoken]);
Eric Andersencb57d552001-06-28 07:25:16 +000010887 }
10888 synerror(msg);
10889 /* NOTREACHED */
10890}
10891
10892
10893static void
Eric Andersen2870d962001-07-02 17:27:21 +000010894synerror(const char *msg)
10895{
Eric Andersencb57d552001-06-28 07:25:16 +000010896 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +000010897 out2fmt("%s: %d: ", commandname, startlinno);
10898 out2fmt("Syntax error: %s\n", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000010899 error((char *)NULL);
10900 /* NOTREACHED */
10901}
10902
Eric Andersencb57d552001-06-28 07:25:16 +000010903
10904/*
10905 * called by editline -- any expansions to the prompt
10906 * should be added here.
10907 */
Eric Andersen2870d962001-07-02 17:27:21 +000010908static void
Eric Andersen62483552001-07-10 06:09:16 +000010909setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000010910{
Eric Andersen62483552001-07-10 06:09:16 +000010911 char *prompt;
10912 switch (whichprompt) {
10913 case 1:
10914 prompt = ps1val();
10915 break;
10916 case 2:
10917 prompt = ps2val();
10918 break;
10919 default: /* 0 */
10920 prompt = "";
10921 }
10922 putprompt(prompt);
Eric Andersencb57d552001-06-28 07:25:16 +000010923}
10924
Eric Andersencb57d552001-06-28 07:25:16 +000010925
Eric Andersencb57d552001-06-28 07:25:16 +000010926/*
10927 * Code for dealing with input/output redirection.
10928 */
10929
Eric Andersen2870d962001-07-02 17:27:21 +000010930#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000010931#ifndef PIPE_BUF
Eric Andersen2870d962001-07-02 17:27:21 +000010932# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000010933#else
10934# define PIPESIZE PIPE_BUF
10935#endif
10936
10937
Eric Andersen62483552001-07-10 06:09:16 +000010938/*
10939 * Open a file in noclobber mode.
10940 * The code was copied from bash.
10941 */
10942static inline int
10943noclobberopen(const char *fname)
10944{
10945 int r, fd;
10946 struct stat finfo, finfo2;
10947
10948 /*
10949 * If the file exists and is a regular file, return an error
10950 * immediately.
10951 */
10952 r = stat(fname, &finfo);
10953 if (r == 0 && S_ISREG(finfo.st_mode)) {
10954 errno = EEXIST;
10955 return -1;
10956 }
10957
10958 /*
10959 * If the file was not present (r != 0), make sure we open it
10960 * exclusively so that if it is created before we open it, our open
10961 * will fail. Make sure that we do not truncate an existing file.
10962 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10963 * file was not a regular file, we leave O_EXCL off.
10964 */
10965 if (r != 0)
10966 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10967 fd = open(fname, O_WRONLY|O_CREAT, 0666);
10968
10969 /* If the open failed, return the file descriptor right away. */
10970 if (fd < 0)
10971 return fd;
10972
10973 /*
10974 * OK, the open succeeded, but the file may have been changed from a
10975 * non-regular file to a regular file between the stat and the open.
10976 * We are assuming that the O_EXCL open handles the case where FILENAME
10977 * did not exist and is symlinked to an existing file between the stat
10978 * and open.
10979 */
10980
10981 /*
10982 * If we can open it and fstat the file descriptor, and neither check
10983 * revealed that it was a regular file, and the file has not been
10984 * replaced, return the file descriptor.
10985 */
10986 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10987 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
10988 return fd;
10989
10990 /* The file has been replaced. badness. */
10991 close(fd);
10992 errno = EEXIST;
10993 return -1;
10994}
Eric Andersencb57d552001-06-28 07:25:16 +000010995
10996/*
Eric Andersen62483552001-07-10 06:09:16 +000010997 * Handle here documents. Normally we fork off a process to write the
10998 * data to a pipe. If the document is short, we can stuff the data in
10999 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000011000 */
11001
Eric Andersen62483552001-07-10 06:09:16 +000011002static inline int
11003openhere(const union node *redir)
11004{
11005 int pip[2];
11006 int len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011007
Eric Andersen62483552001-07-10 06:09:16 +000011008 if (pipe(pip) < 0)
11009 error("Pipe call failed");
11010 if (redir->type == NHERE) {
11011 len = strlen(redir->nhere.doc->narg.text);
11012 if (len <= PIPESIZE) {
11013 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11014 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011015 }
Eric Andersencb57d552001-06-28 07:25:16 +000011016 }
Eric Andersen62483552001-07-10 06:09:16 +000011017 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
11018 close(pip[0]);
11019 signal(SIGINT, SIG_IGN);
11020 signal(SIGQUIT, SIG_IGN);
11021 signal(SIGHUP, SIG_IGN);
11022#ifdef SIGTSTP
11023 signal(SIGTSTP, SIG_IGN);
11024#endif
11025 signal(SIGPIPE, SIG_DFL);
11026 if (redir->type == NHERE)
11027 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11028 else
11029 expandhere(redir->nhere.doc, pip[1]);
11030 _exit(0);
11031 }
11032out:
11033 close(pip[1]);
11034 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000011035}
11036
11037
Eric Andersen62483552001-07-10 06:09:16 +000011038static inline int
11039openredirect(const union node *redir)
11040{
Eric Andersencb57d552001-06-28 07:25:16 +000011041 char *fname;
11042 int f;
11043
11044 switch (redir->nfile.type) {
11045 case NFROM:
11046 fname = redir->nfile.expfname;
11047 if ((f = open(fname, O_RDONLY)) < 0)
11048 goto eopen;
11049 break;
11050 case NFROMTO:
11051 fname = redir->nfile.expfname;
11052 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
11053 goto ecreate;
11054 break;
11055 case NTO:
11056 /* Take care of noclobber mode. */
11057 if (Cflag) {
11058 fname = redir->nfile.expfname;
11059 if ((f = noclobberopen(fname)) < 0)
11060 goto ecreate;
11061 break;
11062 }
11063 case NTOOV:
11064 fname = redir->nfile.expfname;
11065#ifdef O_CREAT
11066 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
11067 goto ecreate;
11068#else
11069 if ((f = creat(fname, 0666)) < 0)
11070 goto ecreate;
11071#endif
11072 break;
11073 case NAPPEND:
11074 fname = redir->nfile.expfname;
11075#ifdef O_APPEND
11076 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
11077 goto ecreate;
11078#else
11079 if ((f = open(fname, O_WRONLY)) < 0
11080 && (f = creat(fname, 0666)) < 0)
11081 goto ecreate;
11082 lseek(f, (off_t)0, 2);
11083#endif
11084 break;
11085 default:
11086#ifdef DEBUG
11087 abort();
11088#endif
11089 /* Fall through to eliminate warning. */
11090 case NTOFD:
11091 case NFROMFD:
11092 f = -1;
11093 break;
11094 case NHERE:
11095 case NXHERE:
11096 f = openhere(redir);
11097 break;
11098 }
11099
11100 return f;
11101ecreate:
11102 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11103eopen:
11104 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11105}
11106
11107
Eric Andersen62483552001-07-10 06:09:16 +000011108/*
11109 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11110 * old file descriptors are stashed away so that the redirection can be
11111 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11112 * standard output, and the standard error if it becomes a duplicate of
11113 * stdout.
11114 */
11115
Eric Andersencb57d552001-06-28 07:25:16 +000011116static void
Eric Andersen62483552001-07-10 06:09:16 +000011117redirect(union node *redir, int flags)
11118{
11119 union node *n;
11120 struct redirtab *sv = NULL;
11121 int i;
11122 int fd;
11123 int newfd;
11124 int try;
11125 int fd1dup = flags & REDIR_BACKQ;; /* stdout `cmd` redir to pipe */
11126
11127 if (flags & REDIR_PUSH) {
11128 sv = ckmalloc(sizeof (struct redirtab));
11129 for (i = 0 ; i < 10 ; i++)
11130 sv->renamed[i] = EMPTY;
11131 sv->next = redirlist;
11132 redirlist = sv;
11133 }
11134 for (n = redir ; n ; n = n->nfile.next) {
11135 fd = n->nfile.fd;
11136 try = 0;
11137 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11138 n->ndup.dupfd == fd)
11139 continue; /* redirect from/to same file descriptor */
11140
11141 INTOFF;
11142 newfd = openredirect(n);
11143 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
11144 if (newfd == fd) {
11145 try++;
11146 } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
11147 switch (errno) {
11148 case EBADF:
11149 if (!try) {
11150 dupredirect(n, newfd, fd1dup);
11151 try++;
11152 break;
11153 }
11154 /* FALLTHROUGH*/
11155 default:
11156 if (newfd >= 0) {
11157 close(newfd);
11158 }
11159 INTON;
11160 error("%d: %m", fd);
11161 /* NOTREACHED */
11162 }
11163 }
11164 if (!try) {
11165 close(fd);
11166 if (flags & REDIR_PUSH) {
11167 sv->renamed[fd] = i;
11168 }
11169 }
11170 } else if (fd != newfd) {
11171 close(fd);
11172 }
11173 if (fd == 0)
11174 fd0_redirected++;
11175 if (!try)
11176 dupredirect(n, newfd, fd1dup);
11177 INTON;
11178 }
11179}
11180
11181
11182static void
11183dupredirect(const union node *redir, int f, int fd1dup)
Eric Andersen2870d962001-07-02 17:27:21 +000011184{
Eric Andersencb57d552001-06-28 07:25:16 +000011185 int fd = redir->nfile.fd;
11186
Eric Andersen62483552001-07-10 06:09:16 +000011187 if(fd==1)
11188 fd1dup = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011189 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Eric Andersen2870d962001-07-02 17:27:21 +000011190 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
Eric Andersen62483552001-07-10 06:09:16 +000011191 if (redir->ndup.dupfd!=1 || fd1dup!=1)
Eric Andersencb57d552001-06-28 07:25:16 +000011192 dup_as_newfd(redir->ndup.dupfd, fd);
11193 }
11194 return;
11195 }
11196
11197 if (f != fd) {
11198 dup_as_newfd(f, fd);
11199 close(f);
11200 }
11201 return;
11202}
11203
11204
Eric Andersencb57d552001-06-28 07:25:16 +000011205
Eric Andersencb57d552001-06-28 07:25:16 +000011206/*
11207 * Undo the effects of the last redirection.
11208 */
11209
11210static void
Eric Andersen2870d962001-07-02 17:27:21 +000011211popredir(void)
11212{
Eric Andersencb57d552001-06-28 07:25:16 +000011213 struct redirtab *rp = redirlist;
11214 int i;
11215
11216 INTOFF;
11217 for (i = 0 ; i < 10 ; i++) {
11218 if (rp->renamed[i] != EMPTY) {
Eric Andersen2870d962001-07-02 17:27:21 +000011219 if (i == 0)
11220 fd0_redirected--;
Eric Andersencb57d552001-06-28 07:25:16 +000011221 close(i);
11222 if (rp->renamed[i] >= 0) {
11223 dup_as_newfd(rp->renamed[i], i);
11224 close(rp->renamed[i]);
11225 }
Eric Andersencb57d552001-06-28 07:25:16 +000011226 }
11227 }
11228 redirlist = rp->next;
11229 ckfree(rp);
11230 INTON;
11231}
11232
11233/*
Eric Andersencb57d552001-06-28 07:25:16 +000011234 * Discard all saved file descriptors.
11235 */
11236
11237static void
Eric Andersen2870d962001-07-02 17:27:21 +000011238clearredir(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000011239 struct redirtab *rp;
11240 int i;
11241
11242 for (rp = redirlist ; rp ; rp = rp->next) {
11243 for (i = 0 ; i < 10 ; i++) {
11244 if (rp->renamed[i] >= 0) {
11245 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011246 }
11247 rp->renamed[i] = EMPTY;
11248 }
11249 }
Eric Andersencb57d552001-06-28 07:25:16 +000011250}
11251
11252
Eric Andersencb57d552001-06-28 07:25:16 +000011253/*
11254 * Copy a file descriptor to be >= to. Returns -1
11255 * if the source file descriptor is closed, EMPTY if there are no unused
11256 * file descriptors left.
11257 */
11258
11259static int
11260dup_as_newfd(from, to)
11261 int from;
11262 int to;
11263{
11264 int newfd;
11265
11266 newfd = fcntl(from, F_DUPFD, to);
11267 if (newfd < 0) {
11268 if (errno == EMFILE)
11269 return EMPTY;
11270 else
Eric Andersen2870d962001-07-02 17:27:21 +000011271 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011272 }
11273 return newfd;
11274}
11275
Eric Andersen2870d962001-07-02 17:27:21 +000011276/*#ifdef __weak_alias
Eric Andersencb57d552001-06-28 07:25:16 +000011277__weak_alias(getmode,_getmode)
11278__weak_alias(setmode,_setmode)
Eric Andersen2870d962001-07-02 17:27:21 +000011279#endif*/
Eric Andersencb57d552001-06-28 07:25:16 +000011280
Eric Andersen62483552001-07-10 06:09:16 +000011281#ifndef S_ISTXT
11282#if defined(__GLIBC__) && __GLIBC__ >= 2
Eric Andersencb57d552001-06-28 07:25:16 +000011283#define S_ISTXT __S_ISVTX
Eric Andersen62483552001-07-10 06:09:16 +000011284#else
11285#define S_ISTXT S_ISVTX
11286#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011287#endif
11288
Eric Andersen2870d962001-07-02 17:27:21 +000011289#define SET_LEN 6 /* initial # of bitcmd struct to malloc */
11290#define SET_LEN_INCR 4 /* # of bitcmd structs to add as needed */
Eric Andersencb57d552001-06-28 07:25:16 +000011291
11292typedef struct bitcmd {
Eric Andersen2870d962001-07-02 17:27:21 +000011293 char cmd;
11294 char cmd2;
11295 mode_t bits;
Eric Andersencb57d552001-06-28 07:25:16 +000011296} BITCMD;
11297
Eric Andersen2870d962001-07-02 17:27:21 +000011298#define CMD2_CLR 0x01
11299#define CMD2_SET 0x02
11300#define CMD2_GBITS 0x04
11301#define CMD2_OBITS 0x08
11302#define CMD2_UBITS 0x10
Eric Andersencb57d552001-06-28 07:25:16 +000011303
Eric Andersen2870d962001-07-02 17:27:21 +000011304static BITCMD *addcmd (BITCMD *, int, int, int, u_int);
11305static void compress_mode (BITCMD *);
Eric Andersencb57d552001-06-28 07:25:16 +000011306#ifdef SETMODE_DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +000011307static void dumpmode (BITCMD *);
Eric Andersencb57d552001-06-28 07:25:16 +000011308#endif
11309
11310/*
11311 * Given the old mode and an array of bitcmd structures, apply the operations
11312 * described in the bitcmd structures to the old mode, and return the new mode.
11313 * Note that there is no '=' command; a strict assignment is just a '-' (clear
11314 * bits) followed by a '+' (set bits).
11315 */
Eric Andersen2870d962001-07-02 17:27:21 +000011316static mode_t
Eric Andersencb57d552001-06-28 07:25:16 +000011317getmode(bbox, omode)
11318 const void *bbox;
11319 mode_t omode;
11320{
11321 const BITCMD *set;
11322 mode_t clrval, newmode, value;
11323
11324 _DIAGASSERT(bbox != NULL);
11325
11326 set = (const BITCMD *)bbox;
11327 newmode = omode;
11328 for (value = 0;; set++)
11329 switch(set->cmd) {
11330 /*
11331 * When copying the user, group or other bits around, we "know"
11332 * where the bits are in the mode so that we can do shifts to
11333 * copy them around. If we don't use shifts, it gets real
11334 * grundgy with lots of single bit checks and bit sets.
11335 */
11336 case 'u':
11337 value = (newmode & S_IRWXU) >> 6;
11338 goto common;
11339
11340 case 'g':
11341 value = (newmode & S_IRWXG) >> 3;
11342 goto common;
11343
11344 case 'o':
11345 value = newmode & S_IRWXO;
Eric Andersen2870d962001-07-02 17:27:21 +000011346common: if (set->cmd2 & CMD2_CLR) {
Eric Andersencb57d552001-06-28 07:25:16 +000011347 clrval =
11348 (set->cmd2 & CMD2_SET) ? S_IRWXO : value;
11349 if (set->cmd2 & CMD2_UBITS)
11350 newmode &= ~((clrval<<6) & set->bits);
11351 if (set->cmd2 & CMD2_GBITS)
11352 newmode &= ~((clrval<<3) & set->bits);
11353 if (set->cmd2 & CMD2_OBITS)
11354 newmode &= ~(clrval & set->bits);
11355 }
11356 if (set->cmd2 & CMD2_SET) {
11357 if (set->cmd2 & CMD2_UBITS)
11358 newmode |= (value<<6) & set->bits;
11359 if (set->cmd2 & CMD2_GBITS)
11360 newmode |= (value<<3) & set->bits;
11361 if (set->cmd2 & CMD2_OBITS)
11362 newmode |= value & set->bits;
11363 }
11364 break;
11365
11366 case '+':
11367 newmode |= set->bits;
11368 break;
11369
11370 case '-':
11371 newmode &= ~set->bits;
11372 break;
11373
11374 case 'X':
11375 if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
11376 newmode |= set->bits;
11377 break;
11378
11379 case '\0':
11380 default:
11381#ifdef SETMODE_DEBUG
11382 (void)printf("getmode:%04o -> %04o\n", omode, newmode);
11383#endif
11384 return (newmode);
11385 }
11386}
11387
Eric Andersen2870d962001-07-02 17:27:21 +000011388#define ADDCMD(a, b, c, d) do { \
11389 if (set >= endset) { \
11390 BITCMD *newset; \
11391 setlen += SET_LEN_INCR; \
11392 newset = realloc(saveset, sizeof(BITCMD) * setlen); \
11393 if (newset == NULL) { \
11394 free(saveset); \
11395 return (NULL); \
11396 } \
11397 set = newset + (set - saveset); \
11398 saveset = newset; \
11399 endset = newset + (setlen - 2); \
11400 } \
11401 set = addcmd(set, (a), (b), (c), (d)); \
Eric Andersencb57d552001-06-28 07:25:16 +000011402} while (/*CONSTCOND*/0)
11403
Eric Andersen2870d962001-07-02 17:27:21 +000011404#define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
Eric Andersencb57d552001-06-28 07:25:16 +000011405
11406static void *
11407setmode(p)
11408 const char *p;
11409{
11410 int perm, who;
11411 char op, *ep;
11412 BITCMD *set, *saveset, *endset;
11413 sigset_t mysigset, sigoset;
11414 mode_t mask;
Eric Andersen2870d962001-07-02 17:27:21 +000011415 int equalopdone = 0; /* pacify gcc */
Eric Andersencb57d552001-06-28 07:25:16 +000011416 int permXbits, setlen;
11417
11418 if (!*p)
11419 return (NULL);
11420
11421 /*
11422 * Get a copy of the mask for the permissions that are mask relative.
11423 * Flip the bits, we want what's not set. Since it's possible that
11424 * the caller is opening files inside a signal handler, protect them
11425 * as best we can.
11426 */
11427 sigfillset(&mysigset);
11428 (void)sigprocmask(SIG_BLOCK, &mysigset, &sigoset);
11429 (void)umask(mask = umask(0));
11430 mask = ~mask;
11431 (void)sigprocmask(SIG_SETMASK, &sigoset, NULL);
11432
11433 setlen = SET_LEN + 2;
Eric Andersen2870d962001-07-02 17:27:21 +000011434
Eric Andersencb57d552001-06-28 07:25:16 +000011435 if ((set = malloc((u_int)(sizeof(BITCMD) * setlen))) == NULL)
11436 return (NULL);
11437 saveset = set;
11438 endset = set + (setlen - 2);
11439
11440 /*
11441 * If an absolute number, get it and return; disallow non-octal digits
11442 * or illegal bits.
11443 */
Eric Andersen62483552001-07-10 06:09:16 +000011444 if (is_digit((unsigned char)*p)) {
Eric Andersencb57d552001-06-28 07:25:16 +000011445 perm = (mode_t)strtol(p, &ep, 8);
11446 if (*ep || perm & ~(STANDARD_BITS|S_ISTXT)) {
11447 free(saveset);
11448 return (NULL);
11449 }
11450 ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask);
11451 set->cmd = 0;
11452 return (saveset);
11453 }
11454
11455 /*
11456 * Build list of structures to set/clear/copy bits as described by
11457 * each clause of the symbolic mode.
11458 */
11459 for (;;) {
11460 /* First, find out which bits might be modified. */
11461 for (who = 0;; ++p) {
11462 switch (*p) {
11463 case 'a':
11464 who |= STANDARD_BITS;
11465 break;
11466 case 'u':
11467 who |= S_ISUID|S_IRWXU;
11468 break;
11469 case 'g':
11470 who |= S_ISGID|S_IRWXG;
11471 break;
11472 case 'o':
11473 who |= S_IRWXO;
11474 break;
11475 default:
11476 goto getop;
11477 }
11478 }
11479
Eric Andersen2870d962001-07-02 17:27:21 +000011480getop: if ((op = *p++) != '+' && op != '-' && op != '=') {
Eric Andersencb57d552001-06-28 07:25:16 +000011481 free(saveset);
11482 return (NULL);
11483 }
11484 if (op == '=')
11485 equalopdone = 0;
11486
11487 who &= ~S_ISTXT;
11488 for (perm = 0, permXbits = 0;; ++p) {
11489 switch (*p) {
11490 case 'r':
11491 perm |= S_IRUSR|S_IRGRP|S_IROTH;
11492 break;
11493 case 's':
11494 /*
Eric Andersen2870d962001-07-02 17:27:21 +000011495 * If specific bits where requested and
11496 * only "other" bits ignore set-id.
Eric Andersencb57d552001-06-28 07:25:16 +000011497 */
11498 if (who == 0 || (who & ~S_IRWXO))
11499 perm |= S_ISUID|S_ISGID;
11500 break;
11501 case 't':
11502 /*
Eric Andersen2870d962001-07-02 17:27:21 +000011503 * If specific bits where requested and
11504 * only "other" bits ignore set-id.
Eric Andersencb57d552001-06-28 07:25:16 +000011505 */
11506 if (who == 0 || (who & ~S_IRWXO)) {
11507 who |= S_ISTXT;
11508 perm |= S_ISTXT;
11509 }
11510 break;
11511 case 'w':
11512 perm |= S_IWUSR|S_IWGRP|S_IWOTH;
11513 break;
11514 case 'X':
11515 permXbits = S_IXUSR|S_IXGRP|S_IXOTH;
11516 break;
11517 case 'x':
11518 perm |= S_IXUSR|S_IXGRP|S_IXOTH;
11519 break;
11520 case 'u':
11521 case 'g':
11522 case 'o':
11523 /*
11524 * When ever we hit 'u', 'g', or 'o', we have
11525 * to flush out any partial mode that we have,
11526 * and then do the copying of the mode bits.
11527 */
11528 if (perm) {
11529 ADDCMD(op, who, perm, mask);
11530 perm = 0;
11531 }
11532 if (op == '=')
11533 equalopdone = 1;
11534 if (op == '+' && permXbits) {
11535 ADDCMD('X', who, permXbits, mask);
11536 permXbits = 0;
11537 }
11538 ADDCMD(*p, who, op, mask);
11539 break;
11540
11541 default:
11542 /*
11543 * Add any permissions that we haven't already
11544 * done.
11545 */
11546 if (perm || (op == '=' && !equalopdone)) {
11547 if (op == '=')
11548 equalopdone = 1;
11549 ADDCMD(op, who, perm, mask);
11550 perm = 0;
11551 }
11552 if (permXbits) {
11553 ADDCMD('X', who, permXbits, mask);
11554 permXbits = 0;
11555 }
11556 goto apply;
11557 }
11558 }
11559
Eric Andersen2870d962001-07-02 17:27:21 +000011560apply: if (!*p)
Eric Andersencb57d552001-06-28 07:25:16 +000011561 break;
11562 if (*p != ',')
11563 goto getop;
11564 ++p;
11565 }
11566 set->cmd = 0;
11567#ifdef SETMODE_DEBUG
11568 (void)printf("Before compress_mode()\n");
11569 dumpmode(saveset);
11570#endif
11571 compress_mode(saveset);
11572#ifdef SETMODE_DEBUG
11573 (void)printf("After compress_mode()\n");
11574 dumpmode(saveset);
11575#endif
11576 return (saveset);
11577}
11578
11579static BITCMD *
11580addcmd(set, op, who, oparg, mask)
11581 BITCMD *set;
11582 int oparg, who;
11583 int op;
11584 u_int mask;
11585{
11586
11587 _DIAGASSERT(set != NULL);
11588
11589 switch (op) {
11590 case '=':
11591 set->cmd = '-';
11592 set->bits = who ? who : STANDARD_BITS;
11593 set++;
11594
11595 op = '+';
11596 /* FALLTHROUGH */
11597 case '+':
11598 case '-':
11599 case 'X':
11600 set->cmd = op;
11601 set->bits = (who ? who : mask) & oparg;
11602 break;
11603
11604 case 'u':
11605 case 'g':
11606 case 'o':
11607 set->cmd = op;
11608 if (who) {
11609 set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) |
11610 ((who & S_IRGRP) ? CMD2_GBITS : 0) |
11611 ((who & S_IROTH) ? CMD2_OBITS : 0);
11612 set->bits = (mode_t)~0;
11613 } else {
11614 set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS;
11615 set->bits = mask;
11616 }
Eric Andersen2870d962001-07-02 17:27:21 +000011617
Eric Andersencb57d552001-06-28 07:25:16 +000011618 if (oparg == '+')
11619 set->cmd2 |= CMD2_SET;
11620 else if (oparg == '-')
11621 set->cmd2 |= CMD2_CLR;
11622 else if (oparg == '=')
11623 set->cmd2 |= CMD2_SET|CMD2_CLR;
11624 break;
11625 }
11626 return (set + 1);
11627}
11628
11629#ifdef SETMODE_DEBUG
11630static void
11631dumpmode(set)
11632 BITCMD *set;
11633{
11634
11635 _DIAGASSERT(set != NULL);
11636
11637 for (; set->cmd; ++set)
11638 (void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n",
11639 set->cmd, set->bits, set->cmd2 ? " cmd2:" : "",
11640 set->cmd2 & CMD2_CLR ? " CLR" : "",
11641 set->cmd2 & CMD2_SET ? " SET" : "",
11642 set->cmd2 & CMD2_UBITS ? " UBITS" : "",
11643 set->cmd2 & CMD2_GBITS ? " GBITS" : "",
11644 set->cmd2 & CMD2_OBITS ? " OBITS" : "");
11645}
11646#endif
11647
11648/*
11649 * Given an array of bitcmd structures, compress by compacting consecutive
11650 * '+', '-' and 'X' commands into at most 3 commands, one of each. The 'u',
Eric Andersen2870d962001-07-02 17:27:21 +000011651 * 'g' and 'o' commands continue to be separate. They could probably be
Eric Andersencb57d552001-06-28 07:25:16 +000011652 * compacted, but it's not worth the effort.
11653 */
11654static void
11655compress_mode(set)
11656 BITCMD *set;
11657{
11658 BITCMD *nset;
11659 int setbits, clrbits, Xbits, op;
11660
11661 _DIAGASSERT(set != NULL);
11662
11663 for (nset = set;;) {
11664 /* Copy over any 'u', 'g' and 'o' commands. */
11665 while ((op = nset->cmd) != '+' && op != '-' && op != 'X') {
11666 *set++ = *nset++;
11667 if (!op)
11668 return;
11669 }
11670
11671 for (setbits = clrbits = Xbits = 0;; nset++) {
11672 if ((op = nset->cmd) == '-') {
11673 clrbits |= nset->bits;
11674 setbits &= ~nset->bits;
11675 Xbits &= ~nset->bits;
11676 } else if (op == '+') {
11677 setbits |= nset->bits;
11678 clrbits &= ~nset->bits;
11679 Xbits &= ~nset->bits;
11680 } else if (op == 'X')
11681 Xbits |= nset->bits & ~setbits;
11682 else
11683 break;
11684 }
11685 if (clrbits) {
11686 set->cmd = '-';
11687 set->cmd2 = 0;
11688 set->bits = clrbits;
11689 set++;
11690 }
11691 if (setbits) {
11692 set->cmd = '+';
11693 set->cmd2 = 0;
11694 set->bits = setbits;
11695 set++;
11696 }
11697 if (Xbits) {
11698 set->cmd = 'X';
11699 set->cmd2 = 0;
11700 set->bits = Xbits;
11701 set++;
11702 }
11703 }
11704}
Eric Andersencb57d552001-06-28 07:25:16 +000011705#ifdef DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +000011706static void shtree (union node *, int, char *, FILE*);
11707static void shcmd (union node *, FILE *);
11708static void sharg (union node *, FILE *);
11709static void indent (int, char *, FILE *);
11710static void trstring (char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011711
11712
11713static void
11714showtree(n)
11715 union node *n;
11716{
11717 trputs("showtree called\n");
11718 shtree(n, 1, NULL, stdout);
11719}
11720
11721
11722static void
11723shtree(n, ind, pfx, fp)
11724 union node *n;
11725 int ind;
11726 char *pfx;
11727 FILE *fp;
11728{
11729 struct nodelist *lp;
11730 const char *s;
11731
11732 if (n == NULL)
11733 return;
11734
11735 indent(ind, pfx, fp);
11736 switch(n->type) {
11737 case NSEMI:
11738 s = "; ";
11739 goto binop;
11740 case NAND:
11741 s = " && ";
11742 goto binop;
11743 case NOR:
11744 s = " || ";
11745binop:
11746 shtree(n->nbinary.ch1, ind, NULL, fp);
11747 /* if (ind < 0) */
11748 fputs(s, fp);
11749 shtree(n->nbinary.ch2, ind, NULL, fp);
11750 break;
11751 case NCMD:
11752 shcmd(n, fp);
11753 if (ind >= 0)
11754 putc('\n', fp);
11755 break;
11756 case NPIPE:
11757 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11758 shcmd(lp->n, fp);
11759 if (lp->next)
11760 fputs(" | ", fp);
11761 }
11762 if (n->npipe.backgnd)
11763 fputs(" &", fp);
11764 if (ind >= 0)
11765 putc('\n', fp);
11766 break;
11767 default:
11768 fprintf(fp, "<node type %d>", n->type);
11769 if (ind >= 0)
11770 putc('\n', fp);
11771 break;
11772 }
11773}
11774
11775
11776
11777static void
11778shcmd(cmd, fp)
11779 union node *cmd;
11780 FILE *fp;
11781{
11782 union node *np;
11783 int first;
11784 const char *s;
11785 int dftfd;
11786
11787 first = 1;
11788 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11789 if (! first)
11790 putchar(' ');
11791 sharg(np, fp);
11792 first = 0;
11793 }
11794 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11795 if (! first)
11796 putchar(' ');
11797 switch (np->nfile.type) {
Eric Andersen2870d962001-07-02 17:27:21 +000011798 case NTO: s = ">"; dftfd = 1; break;
11799 case NAPPEND: s = ">>"; dftfd = 1; break;
11800 case NTOFD: s = ">&"; dftfd = 1; break;
11801 case NTOOV: s = ">|"; dftfd = 1; break;
11802 case NFROM: s = "<"; dftfd = 0; break;
11803 case NFROMFD: s = "<&"; dftfd = 0; break;
11804 case NFROMTO: s = "<>"; dftfd = 0; break;
11805 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011806 }
11807 if (np->nfile.fd != dftfd)
11808 fprintf(fp, "%d", np->nfile.fd);
11809 fputs(s, fp);
11810 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11811 fprintf(fp, "%d", np->ndup.dupfd);
11812 } else {
11813 sharg(np->nfile.fname, fp);
11814 }
11815 first = 0;
11816 }
11817}
11818
11819
11820
11821static void
11822sharg(arg, fp)
11823 union node *arg;
11824 FILE *fp;
11825 {
11826 char *p;
11827 struct nodelist *bqlist;
11828 int subtype;
11829
11830 if (arg->type != NARG) {
11831 printf("<node type %d>\n", arg->type);
11832 fflush(stdout);
11833 abort();
11834 }
11835 bqlist = arg->narg.backquote;
11836 for (p = arg->narg.text ; *p ; p++) {
11837 switch (*p) {
11838 case CTLESC:
11839 putc(*++p, fp);
11840 break;
11841 case CTLVAR:
11842 putc('$', fp);
11843 putc('{', fp);
11844 subtype = *++p;
11845 if (subtype == VSLENGTH)
11846 putc('#', fp);
11847
11848 while (*p != '=')
11849 putc(*p++, fp);
11850
11851 if (subtype & VSNUL)
11852 putc(':', fp);
11853
11854 switch (subtype & VSTYPE) {
11855 case VSNORMAL:
11856 putc('}', fp);
11857 break;
11858 case VSMINUS:
11859 putc('-', fp);
11860 break;
11861 case VSPLUS:
11862 putc('+', fp);
11863 break;
11864 case VSQUESTION:
11865 putc('?', fp);
11866 break;
11867 case VSASSIGN:
11868 putc('=', fp);
11869 break;
11870 case VSTRIMLEFT:
11871 putc('#', fp);
11872 break;
11873 case VSTRIMLEFTMAX:
11874 putc('#', fp);
11875 putc('#', fp);
11876 break;
11877 case VSTRIMRIGHT:
11878 putc('%', fp);
11879 break;
11880 case VSTRIMRIGHTMAX:
11881 putc('%', fp);
11882 putc('%', fp);
11883 break;
11884 case VSLENGTH:
11885 break;
11886 default:
11887 printf("<subtype %d>", subtype);
11888 }
11889 break;
11890 case CTLENDVAR:
11891 putc('}', fp);
11892 break;
11893 case CTLBACKQ:
11894 case CTLBACKQ|CTLQUOTE:
11895 putc('$', fp);
11896 putc('(', fp);
11897 shtree(bqlist->n, -1, NULL, fp);
11898 putc(')', fp);
11899 break;
11900 default:
11901 putc(*p, fp);
11902 break;
11903 }
11904 }
11905}
11906
11907
11908static void
11909indent(amount, pfx, fp)
11910 int amount;
11911 char *pfx;
11912 FILE *fp;
11913{
11914 int i;
11915
11916 for (i = 0 ; i < amount ; i++) {
11917 if (pfx && i == amount - 1)
11918 fputs(pfx, fp);
11919 putc('\t', fp);
11920 }
11921}
11922#endif
11923
11924
11925
11926/*
11927 * Debugging stuff.
11928 */
11929
11930
11931#ifdef DEBUG
11932FILE *tracefile;
11933
11934#if DEBUG == 2
11935static int debug = 1;
11936#else
11937static int debug = 0;
11938#endif
11939
11940
11941static void
11942trputc(c)
11943 int c;
11944{
11945 if (tracefile == NULL)
11946 return;
11947 putc(c, tracefile);
11948 if (c == '\n')
11949 fflush(tracefile);
11950}
11951
11952static void
11953trace(const char *fmt, ...)
11954{
11955 va_list va;
11956#ifdef __STDC__
11957 va_start(va, fmt);
11958#else
11959 char *fmt;
11960 va_start(va);
11961 fmt = va_arg(va, char *);
11962#endif
11963 if (tracefile != NULL) {
11964 (void) vfprintf(tracefile, fmt, va);
11965 if (strchr(fmt, '\n'))
11966 (void) fflush(tracefile);
11967 }
11968 va_end(va);
11969}
11970
11971
11972static void
11973trputs(s)
11974 const char *s;
11975{
11976 if (tracefile == NULL)
11977 return;
11978 fputs(s, tracefile);
11979 if (strchr(s, '\n'))
11980 fflush(tracefile);
11981}
11982
11983
11984static void
11985trstring(s)
11986 char *s;
11987{
11988 char *p;
11989 char c;
11990
11991 if (tracefile == NULL)
11992 return;
11993 putc('"', tracefile);
11994 for (p = s ; *p ; p++) {
11995 switch (*p) {
11996 case '\n': c = 'n'; goto backslash;
11997 case '\t': c = 't'; goto backslash;
11998 case '\r': c = 'r'; goto backslash;
11999 case '"': c = '"'; goto backslash;
12000 case '\\': c = '\\'; goto backslash;
12001 case CTLESC: c = 'e'; goto backslash;
12002 case CTLVAR: c = 'v'; goto backslash;
12003 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
12004 case CTLBACKQ: c = 'q'; goto backslash;
12005 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
Eric Andersen2870d962001-07-02 17:27:21 +000012006backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000012007 putc(c, tracefile);
12008 break;
12009 default:
12010 if (*p >= ' ' && *p <= '~')
12011 putc(*p, tracefile);
12012 else {
12013 putc('\\', tracefile);
12014 putc(*p >> 6 & 03, tracefile);
12015 putc(*p >> 3 & 07, tracefile);
12016 putc(*p & 07, tracefile);
12017 }
12018 break;
12019 }
12020 }
12021 putc('"', tracefile);
12022}
12023
12024
12025static void
12026trargs(ap)
12027 char **ap;
12028{
12029 if (tracefile == NULL)
12030 return;
12031 while (*ap) {
12032 trstring(*ap++);
12033 if (*ap)
12034 putc(' ', tracefile);
12035 else
12036 putc('\n', tracefile);
12037 }
12038 fflush(tracefile);
12039}
12040
12041
12042static void
12043opentrace() {
12044 char s[100];
12045#ifdef O_APPEND
12046 int flags;
12047#endif
12048
12049 if (!debug)
12050 return;
12051#ifdef not_this_way
12052 {
12053 char *p;
12054 if ((p = getenv("HOME")) == NULL) {
12055 if (geteuid() == 0)
12056 p = "/";
12057 else
12058 p = "/tmp";
12059 }
Eric Andersen2870d962001-07-02 17:27:21 +000012060 strcpy(s, p);
Eric Andersencb57d552001-06-28 07:25:16 +000012061 strcat(s, "/trace");
12062 }
12063#else
Eric Andersen2870d962001-07-02 17:27:21 +000012064 strcpy(s, "./trace");
Eric Andersencb57d552001-06-28 07:25:16 +000012065#endif /* not_this_way */
12066 if ((tracefile = fopen(s, "a")) == NULL) {
12067 fprintf(stderr, "Can't open %s\n", s);
12068 return;
12069 }
12070#ifdef O_APPEND
12071 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
12072 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
12073#endif
12074 fputs("\nTracing started.\n", tracefile);
12075 fflush(tracefile);
12076}
12077#endif /* DEBUG */
12078
12079
12080/*
Eric Andersencb57d552001-06-28 07:25:16 +000012081 * The trap builtin.
12082 */
12083
12084static int
12085trapcmd(argc, argv)
12086 int argc;
12087 char **argv;
12088{
12089 char *action;
12090 char **ap;
12091 int signo;
12092
12093 if (argc <= 1) {
12094 for (signo = 0 ; signo < NSIG ; signo++) {
12095 if (trap[signo] != NULL) {
12096 char *p;
12097
12098 p = single_quote(trap[signo]);
Eric Andersen62483552001-07-10 06:09:16 +000012099 printf("trap -- %s %s\n", p,
Eric Andersencb57d552001-06-28 07:25:16 +000012100 signal_names[signo] + (signo ? 3 : 0)
12101 );
12102 stunalloc(p);
12103 }
12104 }
12105 return 0;
12106 }
12107 ap = argv + 1;
12108 if (argc == 2)
12109 action = NULL;
12110 else
12111 action = *ap++;
12112 while (*ap) {
12113 if ((signo = decode_signal(*ap, 0)) < 0)
12114 error("%s: bad trap", *ap);
12115 INTOFF;
12116 if (action) {
12117 if (action[0] == '-' && action[1] == '\0')
12118 action = NULL;
12119 else
12120 action = savestr(action);
12121 }
12122 if (trap[signo])
12123 ckfree(trap[signo]);
12124 trap[signo] = action;
12125 if (signo != 0)
12126 setsignal(signo);
12127 INTON;
12128 ap++;
12129 }
12130 return 0;
12131}
12132
12133
12134
Eric Andersencb57d552001-06-28 07:25:16 +000012135
12136
12137
12138/*
12139 * Set the signal handler for the specified signal. The routine figures
12140 * out what it should be set to.
12141 */
12142
12143static void
Eric Andersen2870d962001-07-02 17:27:21 +000012144setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000012145{
12146 int action;
12147 char *t;
12148 struct sigaction act;
12149
12150 if ((t = trap[signo]) == NULL)
12151 action = S_DFL;
12152 else if (*t != '\0')
12153 action = S_CATCH;
12154 else
12155 action = S_IGN;
12156 if (rootshell && action == S_DFL) {
12157 switch (signo) {
12158 case SIGINT:
12159 if (iflag || minusc || sflag == 0)
12160 action = S_CATCH;
12161 break;
12162 case SIGQUIT:
12163#ifdef DEBUG
12164 {
Eric Andersencb57d552001-06-28 07:25:16 +000012165
12166 if (debug)
12167 break;
12168 }
12169#endif
12170 /* FALLTHROUGH */
12171 case SIGTERM:
12172 if (iflag)
12173 action = S_IGN;
12174 break;
Eric Andersen2870d962001-07-02 17:27:21 +000012175#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000012176 case SIGTSTP:
12177 case SIGTTOU:
12178 if (mflag)
12179 action = S_IGN;
12180 break;
12181#endif
12182 }
12183 }
12184
12185 t = &sigmode[signo - 1];
12186 if (*t == 0) {
12187 /*
12188 * current setting unknown
12189 */
12190 if (sigaction(signo, 0, &act) == -1) {
12191 /*
12192 * Pretend it worked; maybe we should give a warning
12193 * here, but other shells don't. We don't alter
12194 * sigmode, so that we retry every time.
12195 */
12196 return;
12197 }
12198 if (act.sa_handler == SIG_IGN) {
12199 if (mflag && (signo == SIGTSTP ||
12200 signo == SIGTTIN || signo == SIGTTOU)) {
Eric Andersen2870d962001-07-02 17:27:21 +000012201 *t = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000012202 } else
12203 *t = S_HARD_IGN;
12204 } else {
Eric Andersen2870d962001-07-02 17:27:21 +000012205 *t = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000012206 }
12207 }
12208 if (*t == S_HARD_IGN || *t == action)
12209 return;
12210 switch (action) {
12211 case S_CATCH:
12212 act.sa_handler = onsig;
12213 break;
12214 case S_IGN:
12215 act.sa_handler = SIG_IGN;
12216 break;
12217 default:
12218 act.sa_handler = SIG_DFL;
12219 }
12220 *t = action;
12221 act.sa_flags = 0;
12222 sigemptyset(&act.sa_mask);
12223 sigaction(signo, &act, 0);
12224}
12225
12226/*
12227 * Ignore a signal.
12228 */
12229
12230static void
12231ignoresig(signo)
12232 int signo;
12233{
12234 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
12235 signal(signo, SIG_IGN);
12236 }
12237 sigmode[signo - 1] = S_HARD_IGN;
12238}
12239
12240
Eric Andersencb57d552001-06-28 07:25:16 +000012241/*
12242 * Signal handler.
12243 */
12244
12245static void
Eric Andersen2870d962001-07-02 17:27:21 +000012246onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000012247{
12248 if (signo == SIGINT && trap[SIGINT] == NULL) {
12249 onint();
12250 return;
12251 }
12252 gotsig[signo - 1] = 1;
12253 pendingsigs++;
12254}
12255
12256
Eric Andersencb57d552001-06-28 07:25:16 +000012257/*
12258 * Called to execute a trap. Perhaps we should avoid entering new trap
12259 * handlers while we are executing a trap handler.
12260 */
12261
12262static void
Eric Andersen2870d962001-07-02 17:27:21 +000012263dotrap(void)
12264{
Eric Andersencb57d552001-06-28 07:25:16 +000012265 int i;
12266 int savestatus;
12267
12268 for (;;) {
12269 for (i = 1 ; ; i++) {
12270 if (gotsig[i - 1])
12271 break;
12272 if (i >= NSIG - 1)
12273 goto done;
12274 }
12275 gotsig[i - 1] = 0;
12276 savestatus=exitstatus;
12277 evalstring(trap[i], 0);
12278 exitstatus=savestatus;
12279 }
12280done:
12281 pendingsigs = 0;
12282}
12283
Eric Andersencb57d552001-06-28 07:25:16 +000012284/*
12285 * Called to exit the shell.
12286 */
12287
12288static void
Eric Andersen2870d962001-07-02 17:27:21 +000012289exitshell(int status)
Eric Andersencb57d552001-06-28 07:25:16 +000012290{
12291 struct jmploc loc1, loc2;
12292 char *p;
12293
12294 TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
12295 if (setjmp(loc1.loc)) {
12296 goto l1;
12297 }
12298 if (setjmp(loc2.loc)) {
12299 goto l2;
12300 }
12301 handler = &loc1;
12302 if ((p = trap[0]) != NULL && *p != '\0') {
12303 trap[0] = NULL;
12304 evalstring(p, 0);
12305 }
Eric Andersen2870d962001-07-02 17:27:21 +000012306l1: handler = &loc2; /* probably unnecessary */
Eric Andersencb57d552001-06-28 07:25:16 +000012307 flushall();
Eric Andersen2870d962001-07-02 17:27:21 +000012308#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000012309 setjobctl(0);
12310#endif
12311l2: _exit(status);
12312 /* NOTREACHED */
12313}
12314
12315static int decode_signal(const char *string, int minsig)
12316{
12317 int signo;
12318
Eric Andersen2870d962001-07-02 17:27:21 +000012319 if (is_number(string, &signo)) {
Eric Andersencb57d552001-06-28 07:25:16 +000012320 if (signo >= NSIG) {
12321 return -1;
12322 }
12323 return signo;
12324 }
12325
12326 signo = minsig;
12327 if (!signo) {
12328 goto zero;
12329 }
12330 for (; signo < NSIG; signo++) {
12331 if (!strcasecmp(string, &(signal_names[signo])[3])) {
12332 return signo;
12333 }
12334zero:
12335 if (!strcasecmp(string, signal_names[signo])) {
12336 return signo;
12337 }
12338 }
12339
12340 return -1;
12341}
Eric Andersen2870d962001-07-02 17:27:21 +000012342static struct var **hashvar (const char *);
12343static void showvars (const char *, int, int);
12344static struct var **findvar (struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000012345
12346/*
12347 * Initialize the varable symbol tables and import the environment
12348 */
12349
Eric Andersencb57d552001-06-28 07:25:16 +000012350/*
12351 * This routine initializes the builtin variables. It is called when the
12352 * shell is initialized and again when a shell procedure is spawned.
12353 */
12354
12355static void
12356initvar() {
12357 const struct varinit *ip;
12358 struct var *vp;
12359 struct var **vpp;
12360
12361 for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
12362 if ((vp->flags & VEXPORT) == 0) {
12363 vpp = hashvar(ip->text);
12364 vp->next = *vpp;
12365 *vpp = vp;
12366 vp->text = strdup(ip->text);
12367 vp->flags = ip->flags;
12368 vp->func = ip->func;
12369 }
12370 }
12371 /*
12372 * PS1 depends on uid
12373 */
12374 if ((vps1.flags & VEXPORT) == 0) {
12375 vpp = hashvar("PS1=");
12376 vps1.next = *vpp;
12377 *vpp = &vps1;
12378 vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# ");
12379 vps1.flags = VSTRFIXED|VTEXTFIXED;
12380 }
12381}
12382
12383/*
12384 * Set the value of a variable. The flags argument is ored with the
12385 * flags of the variable. If val is NULL, the variable is unset.
12386 */
12387
12388static void
12389setvar(name, val, flags)
12390 const char *name, *val;
12391 int flags;
12392{
12393 const char *p;
12394 int len;
12395 int namelen;
12396 char *nameeq;
12397 int isbad;
12398 int vallen = 0;
12399
12400 isbad = 0;
12401 p = name;
12402 if (! is_name(*p))
12403 isbad = 1;
12404 p++;
12405 for (;;) {
12406 if (! is_in_name(*p)) {
12407 if (*p == '\0' || *p == '=')
12408 break;
12409 isbad = 1;
12410 }
12411 p++;
12412 }
12413 namelen = p - name;
12414 if (isbad)
12415 error("%.*s: bad variable name", namelen, name);
Eric Andersen2870d962001-07-02 17:27:21 +000012416 len = namelen + 2; /* 2 is space for '=' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +000012417 if (val == NULL) {
12418 flags |= VUNSET;
12419 } else {
12420 len += vallen = strlen(val);
12421 }
12422 INTOFF;
12423 nameeq = ckmalloc(len);
12424 memcpy(nameeq, name, namelen);
12425 nameeq[namelen] = '=';
12426 if (val) {
12427 memcpy(nameeq + namelen + 1, val, vallen + 1);
12428 } else {
12429 nameeq[namelen + 1] = '\0';
12430 }
12431 setvareq(nameeq, flags);
12432 INTON;
12433}
12434
12435
12436
12437/*
12438 * Same as setvar except that the variable and value are passed in
12439 * the first argument as name=value. Since the first argument will
12440 * be actually stored in the table, it should not be a string that
12441 * will go away.
12442 */
12443
12444static void
12445setvareq(s, flags)
12446 char *s;
12447 int flags;
12448{
12449 struct var *vp, **vpp;
12450
12451 vpp = hashvar(s);
12452 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
12453 if ((vp = *findvar(vpp, s))) {
12454 if (vp->flags & VREADONLY) {
12455 size_t len = strchr(s, '=') - s;
12456 error("%.*s: is read only", len, s);
12457 }
12458 INTOFF;
12459
12460 if (vp->func && (flags & VNOFUNC) == 0)
12461 (*vp->func)(strchr(s, '=') + 1);
12462
12463 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12464 ckfree(vp->text);
12465
12466 vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
12467 vp->flags |= flags;
12468 vp->text = s;
12469
12470 /*
12471 * We could roll this to a function, to handle it as
12472 * a regular variable function callback, but why bother?
12473 */
12474 if (iflag && (vp == &vmpath || (vp == &vmail && !mpathset())))
12475 chkmail(1);
12476 INTON;
12477 return;
12478 }
12479 /* not found */
12480 vp = ckmalloc(sizeof (*vp));
12481 vp->flags = flags;
12482 vp->text = s;
12483 vp->next = *vpp;
12484 vp->func = NULL;
12485 *vpp = vp;
12486}
12487
12488
12489
12490/*
12491 * Process a linked list of variable assignments.
12492 */
12493
12494static void
12495listsetvar(mylist)
12496 struct strlist *mylist;
12497 {
12498 struct strlist *lp;
12499
12500 INTOFF;
12501 for (lp = mylist ; lp ; lp = lp->next) {
12502 setvareq(savestr(lp->text), 0);
12503 }
12504 INTON;
12505}
12506
12507
12508
12509/*
12510 * Find the value of a variable. Returns NULL if not set.
12511 */
12512
Eric Andersen62483552001-07-10 06:09:16 +000012513static const char *
Eric Andersencb57d552001-06-28 07:25:16 +000012514lookupvar(name)
12515 const char *name;
12516 {
12517 struct var *v;
12518
12519 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
12520 return strchr(v->text, '=') + 1;
12521 }
12522 return NULL;
12523}
12524
12525
12526
12527/*
12528 * Search the environment of a builtin command.
12529 */
12530
Eric Andersen62483552001-07-10 06:09:16 +000012531static const char *
12532bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012533{
Eric Andersen62483552001-07-10 06:09:16 +000012534 const struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012535
12536 for (sp = cmdenviron ; sp ; sp = sp->next) {
12537 if (varequal(sp->text, name))
12538 return strchr(sp->text, '=') + 1;
12539 }
12540 return lookupvar(name);
12541}
12542
12543
12544
12545/*
12546 * Generate a list of exported variables. This routine is used to construct
12547 * the third argument to execve when executing a program.
12548 */
12549
12550static char **
12551environment() {
12552 int nenv;
12553 struct var **vpp;
12554 struct var *vp;
12555 char **env;
12556 char **ep;
12557
12558 nenv = 0;
12559 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12560 for (vp = *vpp ; vp ; vp = vp->next)
12561 if (vp->flags & VEXPORT)
12562 nenv++;
12563 }
12564 ep = env = stalloc((nenv + 1) * sizeof *env);
12565 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12566 for (vp = *vpp ; vp ; vp = vp->next)
12567 if (vp->flags & VEXPORT)
12568 *ep++ = vp->text;
12569 }
12570 *ep = NULL;
12571 return env;
12572}
12573
12574
12575/*
12576 * Called when a shell procedure is invoked to clear out nonexported
12577 * variables. It is also necessary to reallocate variables of with
12578 * VSTACK set since these are currently allocated on the stack.
12579 */
12580
Eric Andersencb57d552001-06-28 07:25:16 +000012581static void
Eric Andersen2870d962001-07-02 17:27:21 +000012582shprocvar(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000012583 struct var **vpp;
12584 struct var *vp, **prev;
12585
12586 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12587 for (prev = vpp ; (vp = *prev) != NULL ; ) {
12588 if ((vp->flags & VEXPORT) == 0) {
12589 *prev = vp->next;
12590 if ((vp->flags & VTEXTFIXED) == 0)
12591 ckfree(vp->text);
12592 if ((vp->flags & VSTRFIXED) == 0)
12593 ckfree(vp);
12594 } else {
12595 if (vp->flags & VSTACK) {
12596 vp->text = savestr(vp->text);
12597 vp->flags &=~ VSTACK;
12598 }
12599 prev = &vp->next;
12600 }
12601 }
12602 }
12603 initvar();
12604}
12605
12606
12607
12608/*
12609 * Command to list all variables which are set. Currently this command
12610 * is invoked from the set command when the set command is called without
12611 * any variables.
12612 */
12613
12614static int
12615showvarscmd(argc, argv)
12616 int argc;
12617 char **argv;
12618{
12619 showvars(nullstr, VUNSET, VUNSET);
12620 return 0;
12621}
12622
12623
12624
12625/*
12626 * The export and readonly commands.
12627 */
12628
12629static int
12630exportcmd(argc, argv)
12631 int argc;
12632 char **argv;
12633{
12634 struct var *vp;
12635 char *name;
12636 const char *p;
12637 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12638 int pflag;
12639
12640 listsetvar(cmdenviron);
12641 pflag = (nextopt("p") == 'p');
12642 if (argc > 1 && !pflag) {
12643 while ((name = *argptr++) != NULL) {
12644 if ((p = strchr(name, '=')) != NULL) {
12645 p++;
12646 } else {
12647 if ((vp = *findvar(hashvar(name), name))) {
12648 vp->flags |= flag;
12649 goto found;
12650 }
12651 }
12652 setvar(name, p, flag);
12653found:;
12654 }
12655 } else {
12656 showvars(argv[0], flag, 0);
12657 }
12658 return 0;
12659}
12660
12661
12662/*
12663 * The "local" command.
12664 */
12665
Eric Andersen2870d962001-07-02 17:27:21 +000012666/* funcnest nonzero if we are currently evaluating a function */
12667
Eric Andersencb57d552001-06-28 07:25:16 +000012668static int
12669localcmd(argc, argv)
12670 int argc;
12671 char **argv;
12672{
12673 char *name;
12674
Eric Andersen2870d962001-07-02 17:27:21 +000012675 if (! funcnest)
Eric Andersencb57d552001-06-28 07:25:16 +000012676 error("Not in a function");
12677 while ((name = *argptr++) != NULL) {
12678 mklocal(name);
12679 }
12680 return 0;
12681}
12682
12683
12684/*
12685 * Make a variable a local variable. When a variable is made local, it's
12686 * value and flags are saved in a localvar structure. The saved values
12687 * will be restored when the shell function returns. We handle the name
12688 * "-" as a special case.
12689 */
12690
12691static void
12692mklocal(name)
12693 char *name;
12694 {
12695 struct localvar *lvp;
12696 struct var **vpp;
12697 struct var *vp;
12698
12699 INTOFF;
12700 lvp = ckmalloc(sizeof (struct localvar));
12701 if (name[0] == '-' && name[1] == '\0') {
12702 char *p;
Eric Andersen2870d962001-07-02 17:27:21 +000012703 p = ckmalloc(sizeof optet_vals);
12704 lvp->text = memcpy(p, optet_vals, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000012705 vp = NULL;
12706 } else {
12707 vpp = hashvar(name);
12708 vp = *findvar(vpp, name);
12709 if (vp == NULL) {
12710 if (strchr(name, '='))
12711 setvareq(savestr(name), VSTRFIXED);
12712 else
12713 setvar(name, NULL, VSTRFIXED);
Eric Andersen2870d962001-07-02 17:27:21 +000012714 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012715 lvp->text = NULL;
12716 lvp->flags = VUNSET;
12717 } else {
12718 lvp->text = vp->text;
12719 lvp->flags = vp->flags;
12720 vp->flags |= VSTRFIXED|VTEXTFIXED;
12721 if (strchr(name, '='))
12722 setvareq(savestr(name), 0);
12723 }
12724 }
12725 lvp->vp = vp;
12726 lvp->next = localvars;
12727 localvars = lvp;
12728 INTON;
12729}
12730
12731
12732/*
12733 * Called after a function returns.
12734 */
12735
12736static void
12737poplocalvars() {
12738 struct localvar *lvp;
12739 struct var *vp;
12740
12741 while ((lvp = localvars) != NULL) {
12742 localvars = lvp->next;
12743 vp = lvp->vp;
Eric Andersen2870d962001-07-02 17:27:21 +000012744 if (vp == NULL) { /* $- saved */
12745 memcpy(optet_vals, lvp->text, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000012746 ckfree(lvp->text);
12747 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12748 (void)unsetvar(vp->text);
12749 } else {
12750 if ((vp->flags & VTEXTFIXED) == 0)
12751 ckfree(vp->text);
12752 vp->flags = lvp->flags;
12753 vp->text = lvp->text;
12754 }
12755 ckfree(lvp);
12756 }
12757}
12758
12759
12760static int
12761setvarcmd(argc, argv)
12762 int argc;
12763 char **argv;
12764{
12765 if (argc <= 2)
12766 return unsetcmd(argc, argv);
12767 else if (argc == 3)
12768 setvar(argv[1], argv[2], 0);
12769 else
12770 error("List assignment not implemented");
12771 return 0;
12772}
12773
12774
12775/*
12776 * The unset builtin command. We unset the function before we unset the
12777 * variable to allow a function to be unset when there is a readonly variable
12778 * with the same name.
12779 */
12780
12781static int
12782unsetcmd(argc, argv)
12783 int argc;
12784 char **argv;
12785{
12786 char **ap;
12787 int i;
12788 int flg_func = 0;
12789 int flg_var = 0;
12790 int ret = 0;
12791
12792 while ((i = nextopt("vf")) != '\0') {
12793 if (i == 'f')
12794 flg_func = 1;
12795 else
12796 flg_var = 1;
12797 }
12798 if (flg_func == 0 && flg_var == 0)
12799 flg_var = 1;
12800
12801 for (ap = argptr; *ap ; ap++) {
12802 if (flg_func)
12803 unsetfunc(*ap);
12804 if (flg_var)
12805 ret |= unsetvar(*ap);
12806 }
12807 return ret;
12808}
12809
12810
12811/*
12812 * Unset the specified variable.
12813 */
12814
12815static int
Eric Andersen62483552001-07-10 06:09:16 +000012816unsetvar(const char *s)
12817{
Eric Andersencb57d552001-06-28 07:25:16 +000012818 struct var **vpp;
12819 struct var *vp;
12820
12821 vpp = findvar(hashvar(s), s);
12822 vp = *vpp;
12823 if (vp) {
12824 if (vp->flags & VREADONLY)
12825 return (1);
12826 INTOFF;
12827 if (*(strchr(vp->text, '=') + 1) != '\0')
12828 setvar(s, nullstr, 0);
12829 vp->flags &= ~VEXPORT;
12830 vp->flags |= VUNSET;
12831 if ((vp->flags & VSTRFIXED) == 0) {
12832 if ((vp->flags & VTEXTFIXED) == 0)
12833 ckfree(vp->text);
12834 *vpp = vp->next;
12835 ckfree(vp);
12836 }
12837 INTON;
12838 return (0);
12839 }
12840
12841 return (0);
12842}
12843
12844
12845
12846/*
12847 * Find the appropriate entry in the hash table from the name.
12848 */
12849
12850static struct var **
Eric Andersen62483552001-07-10 06:09:16 +000012851hashvar(const char *p)
12852{
Eric Andersencb57d552001-06-28 07:25:16 +000012853 unsigned int hashval;
12854
12855 hashval = ((unsigned char) *p) << 4;
12856 while (*p && *p != '=')
12857 hashval += (unsigned char) *p++;
12858 return &vartab[hashval % VTABSIZE];
12859}
12860
12861
12862
12863/*
12864 * Returns true if the two strings specify the same varable. The first
12865 * variable name is terminated by '='; the second may be terminated by
12866 * either '=' or '\0'.
12867 */
12868
12869static int
Eric Andersen62483552001-07-10 06:09:16 +000012870varequal(const char *p, const char *q)
12871{
Eric Andersencb57d552001-06-28 07:25:16 +000012872 while (*p == *q++) {
12873 if (*p++ == '=')
12874 return 1;
12875 }
12876 if (*p == '=' && *(q - 1) == '\0')
12877 return 1;
12878 return 0;
12879}
12880
12881static void
12882showvars(const char *myprefix, int mask, int xor)
12883{
12884 struct var **vpp;
12885 struct var *vp;
12886 const char *sep = myprefix == nullstr ? myprefix : spcstr;
12887
12888 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12889 for (vp = *vpp ; vp ; vp = vp->next) {
12890 if ((vp->flags & mask) ^ xor) {
12891 char *p;
12892 int len;
12893
12894 p = strchr(vp->text, '=') + 1;
12895 len = p - vp->text;
12896 p = single_quote(p);
12897
Eric Andersen62483552001-07-10 06:09:16 +000012898 printf("%s%s%.*s%s\n", myprefix, sep, len,
12899 vp->text, p);
Eric Andersencb57d552001-06-28 07:25:16 +000012900 stunalloc(p);
12901 }
12902 }
12903 }
12904}
12905
12906static struct var **
12907findvar(struct var **vpp, const char *name)
12908{
12909 for (; *vpp; vpp = &(*vpp)->next) {
12910 if (varequal((*vpp)->text, name)) {
12911 break;
12912 }
12913 }
12914 return vpp;
12915}
12916
12917/*
12918 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
12919 * This file contains code for the times builtin.
Eric Andersen7467c8d2001-07-12 20:26:32 +000012920 * $Id: ash.c,v 1.10 2001/07/12 20:26:31 andersen Exp $
Eric Andersencb57d552001-06-28 07:25:16 +000012921 */
12922static int timescmd (int argc, char **argv)
12923{
12924 struct tms buf;
12925 long int clk_tck = sysconf(_SC_CLK_TCK);
12926
12927 times(&buf);
12928 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
12929 (int) (buf.tms_utime / clk_tck / 60),
12930 ((double) buf.tms_utime) / clk_tck,
12931 (int) (buf.tms_stime / clk_tck / 60),
12932 ((double) buf.tms_stime) / clk_tck,
12933 (int) (buf.tms_cutime / clk_tck / 60),
12934 ((double) buf.tms_cutime) / clk_tck,
12935 (int) (buf.tms_cstime / clk_tck / 60),
12936 ((double) buf.tms_cstime) / clk_tck);
12937 return 0;
12938}
12939
Eric Andersendf82f612001-06-28 07:46:40 +000012940
12941/*-
12942 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000012943 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000012944 *
12945 * This code is derived from software contributed to Berkeley by
12946 * Kenneth Almquist.
12947 *
12948 * Redistribution and use in source and binary forms, with or without
12949 * modification, are permitted provided that the following conditions
12950 * are met:
12951 * 1. Redistributions of source code must retain the above copyright
12952 * notice, this list of conditions and the following disclaimer.
12953 * 2. Redistributions in binary form must reproduce the above copyright
12954 * notice, this list of conditions and the following disclaimer in the
12955 * documentation and/or other materials provided with the distribution.
12956 *
Eric Andersen2870d962001-07-02 17:27:21 +000012957 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
12958 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000012959 *
12960 * 4. Neither the name of the University nor the names of its contributors
12961 * may be used to endorse or promote products derived from this software
12962 * without specific prior written permission.
12963 *
12964 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
12965 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
12966 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
12967 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
12968 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
12969 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
12970 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
12971 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
12972 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
12973 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
12974 * SUCH DAMAGE.
12975 */