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