blob: 9a5435e8be867971ecaa848a04e2b509e8877472 [file] [log] [blame]
Eric Andersendf82f612001-06-28 07:46:40 +00001/* vi: set sw=4 ts=4: */
2/*
3 * ash shell port for busybox
4 *
5 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +00006 * The Regents of the University of California. All rights reserved.
Eric Andersencb57d552001-06-28 07:25:16 +00007 *
8 * This code is derived from software contributed to Berkeley by
9 * Kenneth Almquist.
10 *
Eric Andersendf82f612001-06-28 07:46:40 +000011 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
Eric Andersencb57d552001-06-28 07:25:16 +000015 *
Eric Andersendf82f612001-06-28 07:46:40 +000016 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
Eric Andersen2870d962001-07-02 17:27:21 +000025 * This version of ash is adapted from the source in Debian's ash 0.3.8-5
26 * package.
Eric Andersendf82f612001-06-28 07:46:40 +000027 *
Eric Andersen2870d962001-07-02 17:27:21 +000028 * Modified by Erik Andersen <andersee@debian.org> and
Eric Andersen7467c8d2001-07-12 20:26:32 +000029 * Vladimir Oleynik <dzo@simtreas.ru> to be used in busybox
Eric Andersen2870d962001-07-02 17:27:21 +000030 *
Eric Andersendf82f612001-06-28 07:46:40 +000031 *
32 * Original copyright notice is retained at the end of this file.
Eric Andersencb57d552001-06-28 07:25:16 +000033 */
34
Eric Andersen2870d962001-07-02 17:27:21 +000035
36/* These defines allow you to adjust the feature set to be compiled
37 * into the ash shell. As a rule, enabling these options will make
38 * ash get bigger... With all of these options off, ash adds about
Eric Andersen62483552001-07-10 06:09:16 +000039 * 60k to busybox on an x86 system.*/
Eric Andersen2870d962001-07-02 17:27:21 +000040
41
42/* Enable job control. This allows you to run jobs in the background,
43 * which is great when ash is being used as an interactive shell, but
Eric Andersen3102ac42001-07-06 04:26:23 +000044 * it completely useless for is all you are doing is running scripts.
Eric Andersen2870d962001-07-02 17:27:21 +000045 * This adds about 2.5k on an x86 system. */
Eric Andersen62483552001-07-10 06:09:16 +000046#undef JOBS
Eric Andersen2870d962001-07-02 17:27:21 +000047
48/* This enables alias support in ash. If you want to support things
49 * like "alias ls='ls -l'" with ash, enable this. This is only useful
50 * when ash is used as an intractive shell. This adds about 1.5k */
51#define ASH_ALIAS
52
53/* If you need ash to act as a full Posix shell, with full math
Eric Andersen74bcd162001-07-30 21:41:37 +000054 * support, enable this. This adds a bit over 2k an x86 system. */
55#define ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +000056
Eric Andersen2870d962001-07-02 17:27:21 +000057/* Getopts is used by shell procedures to parse positional parameters.
58 * You probably want to leave this disabled, and use the busybox getopt
59 * applet if you want to do this sort of thing. There are some scripts
60 * out there that use it, so it you need it, enable. Most people will
61 * leave this disabled. This adds 1k on an x86 system. */
62#undef ASH_GETOPTS
63
64/* This allows you to override shell builtins and use whatever is on
65 * the filesystem. This is most useful when ash is acting as a
Eric Andersen62483552001-07-10 06:09:16 +000066 * standalone shell. Adds about 272 bytes. */
Eric Andersen2870d962001-07-02 17:27:21 +000067#undef ASH_CMDCMD
68
Eric Andersen2870d962001-07-02 17:27:21 +000069
Eric Andersen3102ac42001-07-06 04:26:23 +000070/* Optimize size vs speed as size */
71#define ASH_OPTIMIZE_FOR_SIZE
72
Eric Andersen2870d962001-07-02 17:27:21 +000073/* Enable this to compile in extra debugging noise. When debugging is
74 * on, debugging info will be written to $HOME/trace and a quit signal
75 * will generate a core dump. */
76#undef DEBUG
77
Eric Andersen2870d962001-07-02 17:27:21 +000078/* These are here to work with glibc -- Don't change these... */
Eric Andersendf82f612001-06-28 07:46:40 +000079#undef FNMATCH_BROKEN
80#undef GLOB_BROKEN
Eric Andersen2870d962001-07-02 17:27:21 +000081#undef _GNU_SOURCE
Eric Andersen74bcd162001-07-30 21:41:37 +000082#undef __USE_GNU
Eric Andersencb57d552001-06-28 07:25:16 +000083
84#include <assert.h>
85#include <ctype.h>
86#include <dirent.h>
87#include <errno.h>
88#include <fcntl.h>
89#include <limits.h>
90#include <paths.h>
91#include <pwd.h>
92#include <setjmp.h>
93#include <signal.h>
94#include <stdarg.h>
Eric Andersencb57d552001-06-28 07:25:16 +000095#include <stdio.h>
96#include <stdlib.h>
97#include <string.h>
98#include <sysexits.h>
99#include <unistd.h>
100#include <sys/stat.h>
101#include <sys/cdefs.h>
102#include <sys/ioctl.h>
103#include <sys/param.h>
104#include <sys/resource.h>
105#include <sys/time.h>
106#include <sys/times.h>
107#include <sys/types.h>
108#include <sys/wait.h>
109
110
111#if !defined(FNMATCH_BROKEN)
112#include <fnmatch.h>
113#endif
114#if !defined(GLOB_BROKEN)
115#include <glob.h>
116#endif
117
Eric Andersen2870d962001-07-02 17:27:21 +0000118#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +0000119#include <termios.h>
Eric Andersencb57d552001-06-28 07:25:16 +0000120#endif
121
Eric Andersencb57d552001-06-28 07:25:16 +0000122#include "busybox.h"
Eric Andersen2870d962001-07-02 17:27:21 +0000123#include "cmdedit.h"
124
Eric Andersen2870d962001-07-02 17:27:21 +0000125/*
126 * This file was generated by the mksyntax program.
127 */
128
129/* Syntax classes */
130#define CWORD 0 /* character is nothing special */
131#define CNL 1 /* newline character */
132#define CBACK 2 /* a backslash character */
133#define CSQUOTE 3 /* single quote */
134#define CDQUOTE 4 /* double quote */
135#define CENDQUOTE 5 /* a terminating quote */
136#define CBQUOTE 6 /* backwards single quote */
137#define CVAR 7 /* a dollar sign */
138#define CENDVAR 8 /* a '}' character */
139#define CLP 9 /* a left paren in arithmetic */
140#define CRP 10 /* a right paren in arithmetic */
141#define CENDFILE 11 /* end of file */
142#define CCTL 12 /* like CWORD, except it must be escaped */
143#define CSPCL 13 /* these terminate a word */
144#define CIGN 14 /* character should be ignored */
145
146/* Syntax classes for is_ functions */
147#define ISDIGIT 01 /* a digit */
148#define ISUPPER 02 /* an upper case letter */
149#define ISLOWER 04 /* a lower case letter */
150#define ISUNDER 010 /* an underscore */
151#define ISSPECL 020 /* the name of a special parameter */
152
153#define SYNBASE 130
154#define PEOF -130
155
156#define PEOA -129
157
158#define TEOF 0
159#define TNL 1
160#define TSEMI 2
161#define TBACKGND 3
162#define TAND 4
163#define TOR 5
164#define TPIPE 6
165#define TLP 7
166#define TRP 8
167#define TENDCASE 9
168#define TENDBQUOTE 10
169#define TREDIR 11
170#define TWORD 12
171#define TASSIGN 13
172#define TNOT 14
173#define TCASE 15
174#define TDO 16
175#define TDONE 17
176#define TELIF 18
177#define TELSE 19
178#define TESAC 20
179#define TFI 21
180#define TFOR 22
181#define TIF 23
182#define TIN 24
183#define TTHEN 25
184#define TUNTIL 26
185#define TWHILE 27
186#define TBEGIN 28
187#define TEND 29
188
189
190#define BASESYNTAX (basesyntax + SYNBASE)
191#define DQSYNTAX (dqsyntax + SYNBASE)
192#define SQSYNTAX (sqsyntax + SYNBASE)
193#define ARISYNTAX (arisyntax + SYNBASE)
194
195/* control characters in argument strings */
196#define CTLESC '\201'
197#define CTLVAR '\202'
198#define CTLENDVAR '\203'
199#define CTLBACKQ '\204'
200#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
201/* CTLBACKQ | CTLQUOTE == '\205' */
202#define CTLARI '\206'
203#define CTLENDARI '\207'
204#define CTLQUOTEMARK '\210'
205
Eric Andersen62483552001-07-10 06:09:16 +0000206#define is_digit(c) ((c)>='0' && (c)<='9')
Eric Andersen2870d962001-07-02 17:27:21 +0000207#define is_alpha(c) (((c) < CTLESC || (c) > CTLENDARI) && isalpha((unsigned char) (c)))
208#define is_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalpha((unsigned char) (c))))
209#define is_in_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalnum((unsigned char) (c))))
210#define is_special(c) ((is_type+SYNBASE)[c] & (ISSPECL|ISDIGIT))
211#define digit_val(c) ((c) - '0')
Eric Andersencb57d552001-06-28 07:25:16 +0000212
213
214#define _DIAGASSERT(x)
215
Eric Andersen3102ac42001-07-06 04:26:23 +0000216
Eric Andersencb57d552001-06-28 07:25:16 +0000217
Eric Andersen2870d962001-07-02 17:27:21 +0000218#define S_DFL 1 /* default signal handling (SIG_DFL) */
219#define S_CATCH 2 /* signal is caught */
220#define S_IGN 3 /* signal is ignored (SIG_IGN) */
221#define S_HARD_IGN 4 /* signal is ignored permenantly */
222#define S_RESET 5 /* temporary - to reset a hard ignored sig */
Eric Andersencb57d552001-06-28 07:25:16 +0000223
224
Eric Andersen2870d962001-07-02 17:27:21 +0000225/* variable substitution byte (follows CTLVAR) */
226#define VSTYPE 0x0f /* type of variable substitution */
227#define VSNUL 0x10 /* colon--treat the empty string as unset */
228#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
Eric Andersencb57d552001-06-28 07:25:16 +0000229
Eric Andersen2870d962001-07-02 17:27:21 +0000230/* values of VSTYPE field */
231#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
232#define VSMINUS 0x2 /* ${var-text} */
233#define VSPLUS 0x3 /* ${var+text} */
234#define VSQUESTION 0x4 /* ${var?message} */
235#define VSASSIGN 0x5 /* ${var=text} */
236#define VSTRIMLEFT 0x6 /* ${var#pattern} */
237#define VSTRIMLEFTMAX 0x7 /* ${var##pattern} */
238#define VSTRIMRIGHT 0x8 /* ${var%pattern} */
239#define VSTRIMRIGHTMAX 0x9 /* ${var%%pattern} */
240#define VSLENGTH 0xa /* ${#var} */
Eric Andersencb57d552001-06-28 07:25:16 +0000241
Eric Andersen2870d962001-07-02 17:27:21 +0000242/* flags passed to redirect */
243#define REDIR_PUSH 01 /* save previous values of file descriptors */
Eric Andersen3102ac42001-07-06 04:26:23 +0000244#define REDIR_BACKQ 02 /* save the command output to pipe */
Eric Andersencb57d552001-06-28 07:25:16 +0000245
Eric Andersen2870d962001-07-02 17:27:21 +0000246/*
247 * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
248 * so we use _setjmp instead.
249 */
250
Eric Andersen62483552001-07-10 06:09:16 +0000251#if defined(BSD)
Eric Andersen2870d962001-07-02 17:27:21 +0000252#define setjmp(jmploc) _setjmp(jmploc)
253#define longjmp(jmploc, val) _longjmp(jmploc, val)
254#endif
255
256/*
257 * Most machines require the value returned from malloc to be aligned
258 * in some way. The following macro will get this right on many machines.
259 */
260
261#ifndef ALIGN
262union align {
263 int i;
264 char *cp;
265};
266
267#define ALIGN(nbytes) (((nbytes) + sizeof(union align) - 1) & ~(sizeof(union align) - 1))
268#endif
269
270#ifdef BB_LOCALE_SUPPORT
271#include <locale.h>
272static void change_lc_all(const char *value);
273static void change_lc_ctype(const char *value);
274#endif
275
276/*
277 * These macros allow the user to suspend the handling of interrupt signals
278 * over a period of time. This is similar to SIGHOLD to or sigblock, but
279 * much more efficient and portable. (But hacking the kernel is so much
280 * more fun than worrying about efficiency and portability. :-))
281 */
282
283static void onint (void);
284static volatile int suppressint;
285static volatile int intpending;
286
287#define INTOFF suppressint++
Eric Andersen3102ac42001-07-06 04:26:23 +0000288#ifndef ASH_OPTIMIZE_FOR_SIZE
Eric Andersen2870d962001-07-02 17:27:21 +0000289#define INTON { if (--suppressint == 0 && intpending) onint(); }
Eric Andersen3102ac42001-07-06 04:26:23 +0000290#define FORCEINTON {suppressint = 0; if (intpending) onint();}
Eric Andersen2870d962001-07-02 17:27:21 +0000291#else
292static void __inton (void);
Eric Andersen3102ac42001-07-06 04:26:23 +0000293static void forceinton (void);
Eric Andersen2870d962001-07-02 17:27:21 +0000294#define INTON __inton()
Eric Andersen3102ac42001-07-06 04:26:23 +0000295#define FORCEINTON forceinton()
Eric Andersen2870d962001-07-02 17:27:21 +0000296#endif
Eric Andersen3102ac42001-07-06 04:26:23 +0000297
Eric Andersen2870d962001-07-02 17:27:21 +0000298#define CLEAR_PENDING_INT intpending = 0
299#define int_pending() intpending
300
301
302typedef void *pointer;
303#ifndef NULL
304#define NULL (void *)0
305#endif
306
307static inline pointer ckmalloc (int sz) { return xmalloc(sz); }
308static inline pointer ckrealloc(void *p, int sz) { return xrealloc(p, sz); }
309static inline char * savestr (const char *s) { return xstrdup(s); }
310
311static pointer stalloc (int);
312static void stunalloc (pointer);
313static void ungrabstackstr (char *, char *);
314static char * growstackstr(void);
Eric Andersen3102ac42001-07-06 04:26:23 +0000315static char * makestrspace(size_t newlen);
Eric Andersen2870d962001-07-02 17:27:21 +0000316static char *sstrdup (const char *);
317
318/*
319 * Parse trees for commands are allocated in lifo order, so we use a stack
320 * to make this more efficient, and also to avoid all sorts of exception
321 * handling code to handle interrupts in the middle of a parse.
322 *
323 * The size 504 was chosen because the Ultrix malloc handles that size
324 * well.
325 */
326
327#define MINSIZE 504 /* minimum size of a block */
328
329
330struct stack_block {
331 struct stack_block *prev;
332 char space[MINSIZE];
333};
334
335static struct stack_block stackbase;
336static struct stack_block *stackp = &stackbase;
337static struct stackmark *markp;
338static char *stacknxt = stackbase.space;
339static int stacknleft = MINSIZE;
340
341
342#define equal(s1, s2) (strcmp(s1, s2) == 0)
343
344#define stackblock() stacknxt
345#define stackblocksize() stacknleft
346#define STARTSTACKSTR(p) p = stackblock(), sstrnleft = stackblocksize()
Eric Andersen3102ac42001-07-06 04:26:23 +0000347
Eric Andersen2870d962001-07-02 17:27:21 +0000348#define STPUTC(c, p) (--sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(), *p++ = (c)))
349#define CHECKSTRSPACE(n, p) { if (sstrnleft < n) p = makestrspace(n); }
Eric Andersen2870d962001-07-02 17:27:21 +0000350#define STACKSTRNUL(p) (sstrnleft == 0? (p = growstackstr(), *p = '\0') : (*p = '\0'))
Eric Andersen3102ac42001-07-06 04:26:23 +0000351
352
353#define USTPUTC(c, p) (--sstrnleft, *p++ = (c))
Eric Andersen2870d962001-07-02 17:27:21 +0000354#define STUNPUTC(p) (++sstrnleft, --p)
355#define STTOPC(p) p[-1]
356#define STADJUST(amount, p) (p += (amount), sstrnleft -= (amount))
357#define grabstackstr(p) stalloc(stackblocksize() - sstrnleft)
358
359#define ckfree(p) free((pointer)(p))
360
Eric Andersen2870d962001-07-02 17:27:21 +0000361
362#ifdef DEBUG
363#define TRACE(param) trace param
364static void trace (const char *, ...);
365static void trargs (char **);
366static void showtree (union node *);
367static void trputc (int);
368static void trputs (const char *);
369static void opentrace (void);
370#else
371#define TRACE(param)
372#endif
373
374#define NSEMI 0
375#define NCMD 1
376#define NPIPE 2
377#define NREDIR 3
378#define NBACKGND 4
379#define NSUBSHELL 5
380#define NAND 6
381#define NOR 7
382#define NIF 8
383#define NWHILE 9
384#define NUNTIL 10
385#define NFOR 11
386#define NCASE 12
387#define NCLIST 13
388#define NDEFUN 14
389#define NARG 15
390#define NTO 16
391#define NFROM 17
392#define NFROMTO 18
393#define NAPPEND 19
394#define NTOOV 20
395#define NTOFD 21
396#define NFROMFD 22
397#define NHERE 23
398#define NXHERE 24
399#define NNOT 25
400
401/*
402 * expandarg() flags
403 */
404#define EXP_FULL 0x1 /* perform word splitting & file globbing */
405#define EXP_TILDE 0x2 /* do normal tilde expansion */
406#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
407#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
408#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
409#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
410
411
412#define NOPTS 16
413
414static char optet_vals[NOPTS];
415
416static const char * const optlist[NOPTS] = {
417 "e" "errexit",
418 "f" "noglob",
419 "I" "ignoreeof",
420 "i" "interactive",
421 "m" "monitor",
422 "n" "noexec",
423 "s" "stdin",
424 "x" "xtrace",
425 "v" "verbose",
426 "V" "vi",
427 "E" "emacs",
428 "C" "noclobber",
429 "a" "allexport",
430 "b" "notify",
431 "u" "nounset",
432 "q" "quietprofile"
433};
434
435#define optent_name(optent) (optent+1)
436#define optent_letter(optent) optent[0]
437#define optent_val(optent) optet_vals[optent]
438
439#define eflag optent_val(0)
440#define fflag optent_val(1)
441#define Iflag optent_val(2)
442#define iflag optent_val(3)
443#define mflag optent_val(4)
444#define nflag optent_val(5)
445#define sflag optent_val(6)
446#define xflag optent_val(7)
447#define vflag optent_val(8)
448#define Vflag optent_val(9)
449#define Eflag optent_val(10)
450#define Cflag optent_val(11)
451#define aflag optent_val(12)
452#define bflag optent_val(13)
453#define uflag optent_val(14)
454#define qflag optent_val(15)
455
456
457/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
458#define FORK_FG 0
459#define FORK_BG 1
460#define FORK_NOJOB 2
461
462
463struct nbinary {
464 int type;
465 union node *ch1;
466 union node *ch2;
467};
468
469
470struct ncmd {
471 int type;
472 int backgnd;
473 union node *assign;
474 union node *args;
475 union node *redirect;
476};
477
478
479struct npipe {
480 int type;
481 int backgnd;
482 struct nodelist *cmdlist;
483};
484
485
486struct nredir {
487 int type;
488 union node *n;
489 union node *redirect;
490};
491
492
493struct nif {
494 int type;
495 union node *test;
496 union node *ifpart;
497 union node *elsepart;
498};
499
500
501struct nfor {
502 int type;
503 union node *args;
504 union node *body;
505 char *var;
506};
507
508
509struct ncase {
510 int type;
511 union node *expr;
512 union node *cases;
513};
514
515
516struct nclist {
517 int type;
518 union node *next;
519 union node *pattern;
520 union node *body;
521};
522
523
524struct narg {
525 int type;
526 union node *next;
527 char *text;
528 struct nodelist *backquote;
529};
530
531
532struct nfile {
533 int type;
534 union node *next;
535 int fd;
536 union node *fname;
537 char *expfname;
538};
539
540
541struct ndup {
542 int type;
543 union node *next;
544 int fd;
545 int dupfd;
546 union node *vname;
547};
548
549
550struct nhere {
551 int type;
552 union node *next;
553 int fd;
554 union node *doc;
555};
556
557
558struct nnot {
559 int type;
560 union node *com;
561};
562
563
564union node {
565 int type;
566 struct nbinary nbinary;
567 struct ncmd ncmd;
568 struct npipe npipe;
569 struct nredir nredir;
570 struct nif nif;
571 struct nfor nfor;
572 struct ncase ncase;
573 struct nclist nclist;
574 struct narg narg;
575 struct nfile nfile;
576 struct ndup ndup;
577 struct nhere nhere;
578 struct nnot nnot;
579};
580
581
582struct nodelist {
583 struct nodelist *next;
584 union node *n;
585};
586
587struct backcmd { /* result of evalbackcmd */
588 int fd; /* file descriptor to read from */
589 char *buf; /* buffer */
590 int nleft; /* number of chars in buffer */
591 struct job *jp; /* job structure for command */
592};
593
594struct cmdentry {
595 int cmdtype;
596 union param {
597 int index;
598 union node *func;
599 const struct builtincmd *cmd;
600 } u;
601};
602
603struct strlist {
604 struct strlist *next;
605 char *text;
606};
607
608
609struct arglist {
610 struct strlist *list;
611 struct strlist **lastp;
612};
613
614struct strpush {
615 struct strpush *prev; /* preceding string on stack */
616 char *prevstring;
617 int prevnleft;
618#ifdef ASH_ALIAS
619 struct alias *ap; /* if push was associated with an alias */
620#endif
621 char *string; /* remember the string since it may change */
622};
623
624struct parsefile {
625 struct parsefile *prev; /* preceding file on stack */
626 int linno; /* current line */
627 int fd; /* file descriptor (or -1 if string) */
628 int nleft; /* number of chars left in this line */
629 int lleft; /* number of chars left in this buffer */
630 char *nextc; /* next char in buffer */
631 char *buf; /* input buffer */
632 struct strpush *strpush; /* for pushing strings at this level */
633 struct strpush basestrpush; /* so pushing one is fast */
634};
635
636struct stackmark {
637 struct stack_block *stackp;
638 char *stacknxt;
639 int stacknleft;
640 struct stackmark *marknext;
641};
642
643struct shparam {
644 int nparam; /* # of positional parameters (without $0) */
645 unsigned char malloc; /* if parameter list dynamically allocated */
646 char **p; /* parameter list */
647 int optind; /* next parameter to be processed by getopts */
648 int optoff; /* used by getopts */
649};
650
Eric Andersen62483552001-07-10 06:09:16 +0000651/*
652 * When commands are first encountered, they are entered in a hash table.
653 * This ensures that a full path search will not have to be done for them
654 * on each invocation.
655 *
656 * We should investigate converting to a linear search, even though that
657 * would make the command name "hash" a misnomer.
658 */
659#define CMDTABLESIZE 31 /* should be prime */
660#define ARB 1 /* actual size determined at run time */
661
662
663
664struct tblentry {
665 struct tblentry *next; /* next entry in hash chain */
666 union param param; /* definition of builtin function */
667 short cmdtype; /* index identifying command */
668 char rehash; /* if set, cd done since entry created */
669 char cmdname[ARB]; /* name of command */
670};
671
672
673static struct tblentry *cmdtable[CMDTABLESIZE];
674static int builtinloc = -1; /* index in path of %builtin, or -1 */
675static int exerrno = 0; /* Last exec error */
676
677
678static void tryexec (char *, char **, char **);
679static void printentry (struct tblentry *, int);
680static void clearcmdentry (int);
681static struct tblentry *cmdlookup (const char *, int);
682static void delete_cmd_entry (void);
683static int path_change (const char *, int *);
684
685
Eric Andersen2870d962001-07-02 17:27:21 +0000686static void flushall (void);
Eric Andersen3102ac42001-07-06 04:26:23 +0000687static void out2fmt (const char *, ...)
688 __attribute__((__format__(__printf__,1,2)));
Eric Andersen2870d962001-07-02 17:27:21 +0000689static int xwrite (int, const char *, int);
Eric Andersen2870d962001-07-02 17:27:21 +0000690
Eric Andersen3102ac42001-07-06 04:26:23 +0000691static void outstr (const char *p, FILE *file) { fputs(p, file); }
692static void out1str(const char *p) { outstr(p, stdout); }
693static void out2str(const char *p) { outstr(p, stderr); }
Eric Andersen2870d962001-07-02 17:27:21 +0000694
Eric Andersen62483552001-07-10 06:09:16 +0000695#ifndef ASH_OPTIMIZE_FOR_SIZE
Eric Andersen3102ac42001-07-06 04:26:23 +0000696#define out2c(c) putc((c), stderr)
Eric Andersen62483552001-07-10 06:09:16 +0000697#else
698static void out2c(int c) { putc(c, stderr); }
699#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000700
701/* syntax table used when not in quotes */
702static const char basesyntax[257] = {
703 CENDFILE, CSPCL, CWORD, CCTL,
704 CCTL, CCTL, CCTL, CCTL,
705 CCTL, CCTL, CCTL, CWORD,
706 CWORD, CWORD, CWORD, CWORD,
707 CWORD, CWORD, CWORD, CWORD,
708 CWORD, CWORD, CWORD, CWORD,
709 CWORD, CWORD, CWORD, CWORD,
710 CWORD, CWORD, CWORD, CWORD,
711 CWORD, CWORD, CWORD, CWORD,
712 CWORD, CWORD, CWORD, CWORD,
713 CWORD, CWORD, CWORD, CWORD,
714 CWORD, CWORD, CWORD, CWORD,
715 CWORD, CWORD, CWORD, CWORD,
716 CWORD, CWORD, CWORD, CWORD,
717 CWORD, CWORD, CWORD, CWORD,
718 CWORD, CWORD, CWORD, CWORD,
719 CWORD, CWORD, CWORD, CWORD,
720 CWORD, CWORD, CWORD, CWORD,
721 CWORD, CWORD, CWORD, CWORD,
722 CWORD, CWORD, CWORD, CWORD,
723 CWORD, CWORD, CWORD, CWORD,
724 CWORD, CWORD, CWORD, CWORD,
725 CWORD, CWORD, CWORD, CWORD,
726 CWORD, CWORD, CWORD, CWORD,
727 CWORD, CWORD, CWORD, CWORD,
728 CWORD, CWORD, CWORD, CWORD,
729 CWORD, CWORD, CWORD, CWORD,
730 CWORD, CWORD, CWORD, CWORD,
731 CWORD, CWORD, CWORD, CWORD,
732 CWORD, CWORD, CWORD, CWORD,
733 CWORD, CWORD, CWORD, CWORD,
734 CWORD, CWORD, CWORD, CWORD,
735 CWORD, CWORD, CWORD, CWORD,
736 CWORD, CWORD, CWORD, CWORD,
737 CWORD, CWORD, CWORD, CSPCL,
738 CNL, CWORD, CWORD, CWORD,
739 CWORD, CWORD, CWORD, CWORD,
740 CWORD, CWORD, CWORD, CWORD,
741 CWORD, CWORD, CWORD, CWORD,
742 CWORD, CWORD, CWORD, CWORD,
743 CWORD, CWORD, CSPCL, CWORD,
744 CDQUOTE, CWORD, CVAR, CWORD,
745 CSPCL, CSQUOTE, CSPCL, CSPCL,
746 CWORD, CWORD, CWORD, CWORD,
747 CWORD, CWORD, CWORD, CWORD,
748 CWORD, CWORD, CWORD, CWORD,
749 CWORD, CWORD, CWORD, CWORD,
750 CWORD, CSPCL, CSPCL, CWORD,
751 CSPCL, CWORD, CWORD, CWORD,
752 CWORD, CWORD, CWORD, CWORD,
753 CWORD, CWORD, CWORD, CWORD,
754 CWORD, CWORD, CWORD, CWORD,
755 CWORD, CWORD, CWORD, CWORD,
756 CWORD, CWORD, CWORD, CWORD,
757 CWORD, CWORD, CWORD, CWORD,
758 CWORD, CWORD, CBACK, CWORD,
759 CWORD, CWORD, CBQUOTE, CWORD,
760 CWORD, CWORD, CWORD, CWORD,
761 CWORD, CWORD, CWORD, CWORD,
762 CWORD, CWORD, CWORD, CWORD,
763 CWORD, CWORD, CWORD, CWORD,
764 CWORD, CWORD, CWORD, CWORD,
765 CWORD, CWORD, CWORD, CWORD,
766 CWORD, CWORD, CSPCL, CENDVAR,
767 CWORD
768};
769
770/* syntax table used when in double quotes */
771static const char dqsyntax[257] = {
772 CENDFILE, CIGN, CWORD, CCTL,
773 CCTL, CCTL, CCTL, CCTL,
774 CCTL, CCTL, CCTL, CWORD,
775 CWORD, CWORD, CWORD, CWORD,
776 CWORD, CWORD, CWORD, CWORD,
777 CWORD, CWORD, CWORD, CWORD,
778 CWORD, CWORD, CWORD, CWORD,
779 CWORD, CWORD, CWORD, CWORD,
780 CWORD, CWORD, CWORD, CWORD,
781 CWORD, CWORD, CWORD, CWORD,
782 CWORD, CWORD, CWORD, CWORD,
783 CWORD, CWORD, CWORD, CWORD,
784 CWORD, CWORD, CWORD, CWORD,
785 CWORD, CWORD, CWORD, CWORD,
786 CWORD, CWORD, CWORD, CWORD,
787 CWORD, CWORD, CWORD, CWORD,
788 CWORD, CWORD, CWORD, CWORD,
789 CWORD, CWORD, CWORD, CWORD,
790 CWORD, CWORD, CWORD, CWORD,
791 CWORD, CWORD, CWORD, CWORD,
792 CWORD, CWORD, CWORD, CWORD,
793 CWORD, CWORD, CWORD, CWORD,
794 CWORD, CWORD, CWORD, CWORD,
795 CWORD, CWORD, CWORD, CWORD,
796 CWORD, CWORD, CWORD, CWORD,
797 CWORD, CWORD, CWORD, CWORD,
798 CWORD, CWORD, CWORD, CWORD,
799 CWORD, CWORD, CWORD, CWORD,
800 CWORD, CWORD, CWORD, CWORD,
801 CWORD, CWORD, CWORD, CWORD,
802 CWORD, CWORD, CWORD, CWORD,
803 CWORD, CWORD, CWORD, CWORD,
804 CWORD, CWORD, CWORD, CWORD,
805 CWORD, CWORD, CWORD, CWORD,
806 CWORD, CWORD, CWORD, CWORD,
807 CNL, CWORD, CWORD, CWORD,
808 CWORD, CWORD, CWORD, CWORD,
809 CWORD, CWORD, CWORD, CWORD,
810 CWORD, CWORD, CWORD, CWORD,
811 CWORD, CWORD, CWORD, CWORD,
812 CWORD, CWORD, CWORD, CCTL,
813 CENDQUOTE,CWORD, CVAR, CWORD,
814 CWORD, CWORD, CWORD, CWORD,
815 CCTL, CWORD, CWORD, CCTL,
816 CWORD, CCTL, CWORD, CWORD,
817 CWORD, CWORD, CWORD, CWORD,
818 CWORD, CWORD, CWORD, CWORD,
819 CCTL, CWORD, CWORD, CCTL,
820 CWORD, CCTL, CWORD, CWORD,
821 CWORD, CWORD, CWORD, CWORD,
822 CWORD, CWORD, CWORD, CWORD,
823 CWORD, CWORD, CWORD, CWORD,
824 CWORD, CWORD, CWORD, CWORD,
825 CWORD, CWORD, CWORD, CWORD,
826 CWORD, CWORD, CWORD, CWORD,
827 CWORD, CCTL, CBACK, CCTL,
828 CWORD, CWORD, CBQUOTE, CWORD,
829 CWORD, CWORD, CWORD, CWORD,
830 CWORD, CWORD, CWORD, CWORD,
831 CWORD, CWORD, CWORD, CWORD,
832 CWORD, CWORD, CWORD, CWORD,
833 CWORD, CWORD, CWORD, CWORD,
834 CWORD, CWORD, CWORD, CWORD,
835 CWORD, CWORD, CWORD, CENDVAR,
836 CCTL
837};
838
839/* syntax table used when in single quotes */
840static const char sqsyntax[257] = {
841 CENDFILE, CIGN, CWORD, CCTL,
842 CCTL, CCTL, CCTL, CCTL,
843 CCTL, CCTL, CCTL, CWORD,
844 CWORD, CWORD, CWORD, CWORD,
845 CWORD, CWORD, CWORD, CWORD,
846 CWORD, CWORD, CWORD, CWORD,
847 CWORD, CWORD, CWORD, CWORD,
848 CWORD, CWORD, CWORD, CWORD,
849 CWORD, CWORD, CWORD, CWORD,
850 CWORD, CWORD, CWORD, CWORD,
851 CWORD, CWORD, CWORD, CWORD,
852 CWORD, CWORD, CWORD, CWORD,
853 CWORD, CWORD, CWORD, CWORD,
854 CWORD, CWORD, CWORD, CWORD,
855 CWORD, CWORD, CWORD, CWORD,
856 CWORD, CWORD, CWORD, CWORD,
857 CWORD, CWORD, CWORD, CWORD,
858 CWORD, CWORD, CWORD, CWORD,
859 CWORD, CWORD, CWORD, CWORD,
860 CWORD, CWORD, CWORD, CWORD,
861 CWORD, CWORD, CWORD, CWORD,
862 CWORD, CWORD, CWORD, CWORD,
863 CWORD, CWORD, CWORD, CWORD,
864 CWORD, CWORD, CWORD, CWORD,
865 CWORD, CWORD, CWORD, CWORD,
866 CWORD, CWORD, CWORD, CWORD,
867 CWORD, CWORD, CWORD, CWORD,
868 CWORD, CWORD, CWORD, CWORD,
869 CWORD, CWORD, CWORD, CWORD,
870 CWORD, CWORD, CWORD, CWORD,
871 CWORD, CWORD, CWORD, CWORD,
872 CWORD, CWORD, CWORD, CWORD,
873 CWORD, CWORD, CWORD, CWORD,
874 CWORD, CWORD, CWORD, CWORD,
875 CWORD, CWORD, CWORD, CWORD,
876 CNL, CWORD, CWORD, CWORD,
877 CWORD, CWORD, CWORD, CWORD,
878 CWORD, CWORD, CWORD, CWORD,
879 CWORD, CWORD, CWORD, CWORD,
880 CWORD, CWORD, CWORD, CWORD,
881 CWORD, CWORD, CWORD, CCTL,
882 CWORD, CWORD, CWORD, CWORD,
883 CWORD, CENDQUOTE,CWORD, CWORD,
884 CCTL, CWORD, CWORD, CCTL,
885 CWORD, CCTL, CWORD, CWORD,
886 CWORD, CWORD, CWORD, CWORD,
887 CWORD, CWORD, CWORD, CWORD,
888 CCTL, CWORD, CWORD, CCTL,
889 CWORD, CCTL, CWORD, CWORD,
890 CWORD, CWORD, CWORD, CWORD,
891 CWORD, CWORD, CWORD, CWORD,
892 CWORD, CWORD, CWORD, CWORD,
893 CWORD, CWORD, CWORD, CWORD,
894 CWORD, CWORD, CWORD, CWORD,
895 CWORD, CWORD, CWORD, CWORD,
896 CWORD, CCTL, CCTL, CCTL,
897 CWORD, CWORD, CWORD, CWORD,
898 CWORD, CWORD, CWORD, CWORD,
899 CWORD, CWORD, CWORD, CWORD,
900 CWORD, CWORD, CWORD, CWORD,
901 CWORD, CWORD, CWORD, CWORD,
902 CWORD, CWORD, CWORD, CWORD,
903 CWORD, CWORD, CWORD, CWORD,
904 CWORD, CWORD, CWORD, CWORD,
905 CCTL
906};
907
908/* syntax table used when in arithmetic */
909static const char arisyntax[257] = {
910 CENDFILE, CIGN, CWORD, CCTL,
911 CCTL, CCTL, CCTL, CCTL,
912 CCTL, CCTL, CCTL, CWORD,
913 CWORD, CWORD, CWORD, CWORD,
914 CWORD, CWORD, CWORD, CWORD,
915 CWORD, CWORD, CWORD, CWORD,
916 CWORD, CWORD, CWORD, CWORD,
917 CWORD, CWORD, CWORD, CWORD,
918 CWORD, CWORD, CWORD, CWORD,
919 CWORD, CWORD, CWORD, CWORD,
920 CWORD, CWORD, CWORD, CWORD,
921 CWORD, CWORD, CWORD, CWORD,
922 CWORD, CWORD, CWORD, CWORD,
923 CWORD, CWORD, CWORD, CWORD,
924 CWORD, CWORD, CWORD, CWORD,
925 CWORD, CWORD, CWORD, CWORD,
926 CWORD, CWORD, CWORD, CWORD,
927 CWORD, CWORD, CWORD, CWORD,
928 CWORD, CWORD, CWORD, CWORD,
929 CWORD, CWORD, CWORD, CWORD,
930 CWORD, CWORD, CWORD, CWORD,
931 CWORD, CWORD, CWORD, CWORD,
932 CWORD, CWORD, CWORD, CWORD,
933 CWORD, CWORD, CWORD, CWORD,
934 CWORD, CWORD, CWORD, CWORD,
935 CWORD, CWORD, CWORD, CWORD,
936 CWORD, CWORD, CWORD, CWORD,
937 CWORD, CWORD, CWORD, CWORD,
938 CWORD, CWORD, CWORD, CWORD,
939 CWORD, CWORD, CWORD, CWORD,
940 CWORD, CWORD, CWORD, CWORD,
941 CWORD, CWORD, CWORD, CWORD,
942 CWORD, CWORD, CWORD, CWORD,
943 CWORD, CWORD, CWORD, CWORD,
944 CWORD, CWORD, CWORD, CWORD,
945 CNL, CWORD, CWORD, CWORD,
946 CWORD, CWORD, CWORD, CWORD,
947 CWORD, CWORD, CWORD, CWORD,
948 CWORD, CWORD, CWORD, CWORD,
949 CWORD, CWORD, CWORD, CWORD,
950 CWORD, CWORD, CWORD, CWORD,
951 CDQUOTE, CWORD, CVAR, CWORD,
952 CWORD, CSQUOTE, CLP, CRP,
953 CWORD, CWORD, CWORD, CWORD,
954 CWORD, CWORD, CWORD, CWORD,
955 CWORD, CWORD, CWORD, CWORD,
956 CWORD, CWORD, CWORD, CWORD,
957 CWORD, CWORD, CWORD, CWORD,
958 CWORD, CWORD, CWORD, CWORD,
959 CWORD, CWORD, CWORD, CWORD,
960 CWORD, CWORD, CWORD, CWORD,
961 CWORD, CWORD, CWORD, CWORD,
962 CWORD, CWORD, CWORD, CWORD,
963 CWORD, CWORD, CWORD, CWORD,
964 CWORD, CWORD, CWORD, CWORD,
965 CWORD, CWORD, CBACK, CWORD,
966 CWORD, CWORD, CBQUOTE, CWORD,
967 CWORD, CWORD, CWORD, CWORD,
968 CWORD, CWORD, CWORD, CWORD,
969 CWORD, CWORD, CWORD, CWORD,
970 CWORD, CWORD, CWORD, CWORD,
971 CWORD, CWORD, CWORD, CWORD,
972 CWORD, CWORD, CWORD, CWORD,
973 CWORD, CWORD, CWORD, CENDVAR,
974 CWORD
975};
976
977/* character classification table */
978static const char is_type[257] = {
979 0, 0, 0, 0,
980 0, 0, 0, 0,
981 0, 0, 0, 0,
982 0, 0, 0, 0,
983 0, 0, 0, 0,
984 0, 0, 0, 0,
985 0, 0, 0, 0,
986 0, 0, 0, 0,
987 0, 0, 0, 0,
988 0, 0, 0, 0,
989 0, 0, 0, 0,
990 0, 0, 0, 0,
991 0, 0, 0, 0,
992 0, 0, 0, 0,
993 0, 0, 0, 0,
994 0, 0, 0, 0,
995 0, 0, 0, 0,
996 0, 0, 0, 0,
997 0, 0, 0, 0,
998 0, 0, 0, 0,
999 0, 0, 0, 0,
1000 0, 0, 0, 0,
1001 0, 0, 0, 0,
1002 0, 0, 0, 0,
1003 0, 0, 0, 0,
1004 0, 0, 0, 0,
1005 0, 0, 0, 0,
1006 0, 0, 0, 0,
1007 0, 0, 0, 0,
1008 0, 0, 0, 0,
1009 0, 0, 0, 0,
1010 0, 0, 0, 0,
1011 0, 0, 0, 0,
1012 0, 0, 0, 0,
1013 0, 0, 0, 0,
1014 0, 0, 0, 0,
1015 0, 0, 0, 0,
1016 0, 0, 0, 0,
1017 0, 0, 0, 0,
1018 0, 0, 0, 0,
1019 0, 0, 0, ISSPECL,
1020 0, ISSPECL, ISSPECL, 0,
1021 0, 0, 0, 0,
1022 ISSPECL, 0, 0, ISSPECL,
1023 0, 0, ISDIGIT, ISDIGIT,
1024 ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT,
1025 ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT,
1026 0, 0, 0, 0,
1027 0, ISSPECL, ISSPECL, ISUPPER,
1028 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
1029 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
1030 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
1031 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
1032 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
1033 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
1034 ISUPPER, 0, 0, 0,
1035 0, ISUNDER, 0, ISLOWER,
1036 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
1037 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
1038 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
1039 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
1040 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
1041 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
1042 ISLOWER, 0, 0, 0,
1043 0
1044};
1045
1046/* Array indicating which tokens mark the end of a list */
1047static const char tokendlist[] = {
1048 1,
1049 0,
1050 0,
1051 0,
1052 0,
1053 0,
1054 0,
1055 0,
1056 1,
1057 1,
1058 1,
1059 0,
1060 0,
1061 0,
1062 0,
1063 0,
1064 1,
1065 1,
1066 1,
1067 1,
1068 1,
1069 1,
1070 0,
1071 0,
1072 0,
1073 1,
1074 0,
1075 0,
1076 0,
1077 1,
1078};
1079
1080static const char *const tokname[] = {
1081 "end of file",
1082 "newline",
1083 "\";\"",
1084 "\"&\"",
1085 "\"&&\"",
1086 "\"||\"",
1087 "\"|\"",
1088 "\"(\"",
1089 "\")\"",
1090 "\";;\"",
1091 "\"`\"",
1092 "redirection",
1093 "word",
1094 "assignment",
1095 "\"!\"",
1096 "\"case\"",
1097 "\"do\"",
1098 "\"done\"",
1099 "\"elif\"",
1100 "\"else\"",
1101 "\"esac\"",
1102 "\"fi\"",
1103 "\"for\"",
1104 "\"if\"",
1105 "\"in\"",
1106 "\"then\"",
1107 "\"until\"",
1108 "\"while\"",
1109 "\"{\"",
1110 "\"}\"",
1111};
1112
1113#define KWDOFFSET 14
1114
1115static const char *const parsekwd[] = {
1116 "!",
1117 "case",
1118 "do",
1119 "done",
1120 "elif",
1121 "else",
1122 "esac",
1123 "fi",
1124 "for",
1125 "if",
1126 "in",
1127 "then",
1128 "until",
1129 "while",
1130 "{",
1131 "}"
1132};
1133
1134
1135static int plinno = 1; /* input line number */
1136
1137static int parselleft; /* copy of parsefile->lleft */
1138
1139static struct parsefile basepf; /* top level input file */
1140static char basebuf[BUFSIZ]; /* buffer for top level input file */
1141static struct parsefile *parsefile = &basepf; /* current input file */
1142
1143/*
1144 * NEOF is returned by parsecmd when it encounters an end of file. It
1145 * must be distinct from NULL, so we use the address of a variable that
1146 * happens to be handy.
1147 */
1148
1149static int tokpushback; /* last token pushed back */
1150#define NEOF ((union node *)&tokpushback)
1151static int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */
1152
1153
1154static void error (const char *, ...) __attribute__((__noreturn__));
1155static void exerror (int, const char *, ...) __attribute__((__noreturn__));
1156static void shellexec (char **, char **, const char *, int)
1157 __attribute__((noreturn));
1158static void exitshell (int) __attribute__((noreturn));
1159
1160static int goodname(const char *);
1161static void ignoresig (int);
1162static void onsig (int);
1163static void dotrap (void);
1164static int decode_signal (const char *, int);
1165
1166static void shprocvar(void);
1167static void deletefuncs(void);
1168static void setparam (char **);
1169static void freeparam (volatile struct shparam *);
1170
1171/* reasons for skipping commands (see comment on breakcmd routine) */
1172#define SKIPBREAK 1
1173#define SKIPCONT 2
1174#define SKIPFUNC 3
1175#define SKIPFILE 4
1176
1177/* values of cmdtype */
1178#define CMDUNKNOWN -1 /* no entry in table for command */
1179#define CMDNORMAL 0 /* command is an executable program */
1180#define CMDBUILTIN 1 /* command is a shell builtin */
1181#define CMDFUNCTION 2 /* command is a shell function */
1182
1183#define DO_ERR 1 /* find_command prints errors */
1184#define DO_ABS 2 /* find_command checks absolute paths */
1185#define DO_NOFUN 4 /* find_command ignores functions */
1186#define DO_BRUTE 8 /* find_command ignores hash table */
1187
1188/*
1189 * Shell variables.
1190 */
1191
1192/* flags */
1193#define VEXPORT 0x01 /* variable is exported */
1194#define VREADONLY 0x02 /* variable cannot be modified */
1195#define VSTRFIXED 0x04 /* variable struct is staticly allocated */
1196#define VTEXTFIXED 0x08 /* text is staticly allocated */
1197#define VSTACK 0x10 /* text is allocated on the stack */
1198#define VUNSET 0x20 /* the variable is not set */
1199#define VNOFUNC 0x40 /* don't call the callback function */
1200
1201
1202struct var {
1203 struct var *next; /* next entry in hash list */
1204 int flags; /* flags are defined above */
1205 char *text; /* name=value */
1206 void (*func) (const char *);
1207 /* function to be called when */
1208 /* the variable gets set/unset */
1209};
1210
1211struct localvar {
1212 struct localvar *next; /* next local variable in list */
1213 struct var *vp; /* the variable that was made local */
1214 int flags; /* saved flags */
1215 char *text; /* saved text */
1216};
1217
1218
Eric Andersen62483552001-07-10 06:09:16 +00001219#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00001220#define rmescapes(p) _rmescapes((p), 0)
1221static char *_rmescapes (char *, int);
1222#else
1223static void rmescapes (char *);
1224#endif
1225
1226static int casematch (union node *, const char *);
1227static void clearredir(void);
1228static void popstring(void);
1229static void readcmdfile (const char *);
1230
1231static int number (const char *);
1232static int is_number (const char *, int *num);
1233static char *single_quote (const char *);
1234static int nextopt (const char *);
1235
1236static void redirect (union node *, int);
1237static void popredir (void);
1238static int dup_as_newfd (int, int);
1239
1240static void changepath(const char *newval);
1241static void getoptsreset(const char *value);
1242
1243
1244static int parsenleft; /* copy of parsefile->nleft */
1245static char *parsenextc; /* copy of parsefile->nextc */
1246static int rootpid; /* pid of main shell */
1247static int rootshell; /* true if we aren't a child of the main shell */
1248
1249static const char spcstr[] = " ";
1250static const char snlfmt[] = "%s\n";
1251
1252static int sstrnleft;
1253static int herefd = -1;
1254
1255static struct localvar *localvars;
1256
1257static struct var vifs;
1258static struct var vmail;
1259static struct var vmpath;
1260static struct var vpath;
1261static struct var vps1;
1262static struct var vps2;
1263static struct var voptind;
1264#ifdef BB_LOCALE_SUPPORT
1265static struct var vlc_all;
1266static struct var vlc_ctype;
1267#endif
1268
1269struct varinit {
1270 struct var *var;
1271 int flags;
1272 const char *text;
1273 void (*func) (const char *);
1274};
1275
1276static const char defpathvar[] =
1277 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
1278#define defpath (defpathvar + 5)
1279
1280#ifdef IFS_BROKEN
1281static const char defifsvar[] = "IFS= \t\n";
1282#define defifs (defifsvar + 4)
1283#else
1284static const char defifs[] = " \t\n";
1285#endif
1286
1287static const struct varinit varinit[] = {
1288#ifdef IFS_BROKEN
1289 { &vifs, VSTRFIXED|VTEXTFIXED, defifsvar,
1290#else
1291 { &vifs, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS=",
1292#endif
1293 NULL },
1294 { &vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=",
1295 NULL },
1296 { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=",
1297 NULL },
1298 { &vpath, VSTRFIXED|VTEXTFIXED, defpathvar,
1299 changepath },
1300 /*
1301 * vps1 depends on uid
1302 */
1303 { &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ",
1304 NULL },
1305 { &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1",
1306 getoptsreset },
1307#ifdef BB_LOCALE_SUPPORT
1308 { &vlc_all, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL=",
1309 change_lc_all },
1310 { &vlc_ctype, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE=",
1311 change_lc_ctype },
1312#endif
1313 { NULL, 0, NULL,
1314 NULL }
1315};
1316
1317#define VTABSIZE 39
1318
1319static struct var *vartab[VTABSIZE];
1320
1321/*
1322 * The following macros access the values of the above variables.
1323 * They have to skip over the name. They return the null string
1324 * for unset variables.
1325 */
1326
1327#define ifsval() (vifs.text + 4)
1328#define ifsset() ((vifs.flags & VUNSET) == 0)
1329#define mailval() (vmail.text + 5)
1330#define mpathval() (vmpath.text + 9)
1331#define pathval() (vpath.text + 5)
1332#define ps1val() (vps1.text + 4)
1333#define ps2val() (vps2.text + 4)
1334#define optindval() (voptind.text + 7)
1335
1336#define mpathset() ((vmpath.flags & VUNSET) == 0)
1337
1338static void initvar (void);
1339static void setvar (const char *, const char *, int);
1340static void setvareq (char *, int);
1341static void listsetvar (struct strlist *);
Eric Andersen62483552001-07-10 06:09:16 +00001342static const char *lookupvar (const char *);
1343static const char *bltinlookup (const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001344static char **environment (void);
1345static int showvarscmd (int, char **);
1346static void mklocal (char *);
1347static void poplocalvars (void);
1348static int unsetvar (const char *);
1349static int varequal (const char *, const char *);
1350
1351
1352static char *arg0; /* value of $0 */
1353static struct shparam shellparam; /* current positional parameters */
1354static char **argptr; /* argument list for builtin commands */
1355static char *optionarg; /* set by nextopt (like getopt) */
1356static char *optptr; /* used by nextopt */
1357static char *minusc; /* argument to -c option */
1358
1359
1360#ifdef ASH_ALIAS
1361
1362#define ALIASINUSE 1
1363#define ALIASDEAD 2
1364
Eric Andersen3102ac42001-07-06 04:26:23 +00001365#define ATABSIZE 39
1366
Eric Andersen2870d962001-07-02 17:27:21 +00001367struct alias {
1368 struct alias *next;
1369 char *name;
1370 char *val;
1371 int flag;
1372};
1373
1374static struct alias *atab[ATABSIZE];
1375
1376static void setalias (char *, char *);
1377static struct alias **hashalias (const char *);
1378static struct alias *freealias (struct alias *);
1379static struct alias **__lookupalias (const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00001380
1381static void
1382setalias(name, val)
1383 char *name, *val;
1384{
1385 struct alias *ap, **app;
1386
1387 app = __lookupalias(name);
1388 ap = *app;
1389 INTOFF;
1390 if (ap) {
1391 if (!(ap->flag & ALIASINUSE)) {
1392 ckfree(ap->val);
1393 }
Eric Andersen2870d962001-07-02 17:27:21 +00001394 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00001395 ap->flag &= ~ALIASDEAD;
1396 } else {
1397 /* not found */
1398 ap = ckmalloc(sizeof (struct alias));
1399 ap->name = savestr(name);
1400 ap->val = savestr(val);
1401 ap->flag = 0;
1402 ap->next = 0;
1403 *app = ap;
1404 }
1405 INTON;
1406}
1407
1408static int
Eric Andersen2870d962001-07-02 17:27:21 +00001409unalias(char *name)
1410{
Eric Andersencb57d552001-06-28 07:25:16 +00001411 struct alias **app;
1412
1413 app = __lookupalias(name);
1414
1415 if (*app) {
1416 INTOFF;
1417 *app = freealias(*app);
1418 INTON;
1419 return (0);
1420 }
1421
1422 return (1);
1423}
1424
Eric Andersencb57d552001-06-28 07:25:16 +00001425static void
Eric Andersen2870d962001-07-02 17:27:21 +00001426rmaliases(void)
1427{
Eric Andersencb57d552001-06-28 07:25:16 +00001428 struct alias *ap, **app;
1429 int i;
1430
1431 INTOFF;
1432 for (i = 0; i < ATABSIZE; i++) {
1433 app = &atab[i];
1434 for (ap = *app; ap; ap = *app) {
1435 *app = freealias(*app);
1436 if (ap == *app) {
1437 app = &ap->next;
1438 }
1439 }
1440 }
1441 INTON;
1442}
1443
Eric Andersen2870d962001-07-02 17:27:21 +00001444static struct alias *
1445lookupalias(const char *name, int check)
Eric Andersencb57d552001-06-28 07:25:16 +00001446{
1447 struct alias *ap = *__lookupalias(name);
1448
1449 if (check && ap && (ap->flag & ALIASINUSE))
1450 return (NULL);
1451 return (ap);
1452}
1453
Eric Andersen2870d962001-07-02 17:27:21 +00001454static void
1455printalias(const struct alias *ap) {
1456 char *p;
1457
1458 p = single_quote(ap->val);
Eric Andersen62483552001-07-10 06:09:16 +00001459 printf("alias %s=%s\n", ap->name, p);
Eric Andersen2870d962001-07-02 17:27:21 +00001460 stunalloc(p);
1461}
1462
Eric Andersencb57d552001-06-28 07:25:16 +00001463
1464/*
1465 * TODO - sort output
1466 */
1467static int
Eric Andersen2870d962001-07-02 17:27:21 +00001468aliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001469{
1470 char *n, *v;
1471 int ret = 0;
1472 struct alias *ap;
1473
1474 if (argc == 1) {
1475 int i;
1476
1477 for (i = 0; i < ATABSIZE; i++)
1478 for (ap = atab[i]; ap; ap = ap->next) {
1479 printalias(ap);
1480 }
1481 return (0);
1482 }
1483 while ((n = *++argv) != NULL) {
1484 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
1485 if ((ap = *__lookupalias(n)) == NULL) {
Eric Andersen3102ac42001-07-06 04:26:23 +00001486 out2fmt("%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00001487 ret = 1;
1488 } else
1489 printalias(ap);
1490 }
1491 else {
1492 *v++ = '\0';
1493 setalias(n, v);
1494 }
1495 }
1496
1497 return (ret);
1498}
1499
1500static int
Eric Andersen2870d962001-07-02 17:27:21 +00001501unaliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001502{
1503 int i;
1504
1505 while ((i = nextopt("a")) != '\0') {
1506 if (i == 'a') {
1507 rmaliases();
1508 return (0);
1509 }
1510 }
1511 for (i = 0; *argptr; argptr++) {
1512 if (unalias(*argptr)) {
Eric Andersen3102ac42001-07-06 04:26:23 +00001513 out2fmt("%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00001514 i = 1;
1515 }
1516 }
1517
1518 return (i);
1519}
1520
1521static struct alias **
1522hashalias(p)
1523 const char *p;
1524 {
1525 unsigned int hashval;
1526
1527 hashval = *p << 4;
1528 while (*p)
1529 hashval+= *p++;
1530 return &atab[hashval % ATABSIZE];
1531}
1532
1533static struct alias *
1534freealias(struct alias *ap) {
1535 struct alias *next;
1536
1537 if (ap->flag & ALIASINUSE) {
1538 ap->flag |= ALIASDEAD;
1539 return ap;
1540 }
1541
1542 next = ap->next;
1543 ckfree(ap->name);
1544 ckfree(ap->val);
1545 ckfree(ap);
1546 return next;
1547}
1548
Eric Andersencb57d552001-06-28 07:25:16 +00001549
1550static struct alias **
1551__lookupalias(const char *name) {
1552 struct alias **app = hashalias(name);
1553
1554 for (; *app; app = &(*app)->next) {
1555 if (equal(name, (*app)->name)) {
1556 break;
1557 }
1558 }
1559
1560 return app;
1561}
Eric Andersen2870d962001-07-02 17:27:21 +00001562#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001563
1564#ifdef ASH_MATH_SUPPORT
Eric Andersen74bcd162001-07-30 21:41:37 +00001565/* The generated file arith.c has been replaced with a custom hand
1566 * written implementation written by Aaron Lehmann <aaronl@vitelus.com>.
1567 * This is now part of libbb, so that it can be used by all the shells
1568 * in busybox. */
Eric Andersen2870d962001-07-02 17:27:21 +00001569#define ARITH_NUM 257
1570#define ARITH_LPAREN 258
1571#define ARITH_RPAREN 259
1572#define ARITH_OR 260
1573#define ARITH_AND 261
1574#define ARITH_BOR 262
1575#define ARITH_BXOR 263
1576#define ARITH_BAND 264
1577#define ARITH_EQ 265
1578#define ARITH_NE 266
1579#define ARITH_LT 267
1580#define ARITH_GT 268
1581#define ARITH_GE 269
1582#define ARITH_LE 270
1583#define ARITH_LSHIFT 271
1584#define ARITH_RSHIFT 272
1585#define ARITH_ADD 273
1586#define ARITH_SUB 274
1587#define ARITH_MUL 275
1588#define ARITH_DIV 276
1589#define ARITH_REM 277
1590#define ARITH_UNARYMINUS 278
1591#define ARITH_UNARYPLUS 279
1592#define ARITH_NOT 280
1593#define ARITH_BNOT 281
1594
1595static void expari (int);
1596/* From arith.y */
Eric Andersen74bcd162001-07-30 21:41:37 +00001597static long ash_arith(const char *p);
Eric Andersen2870d962001-07-02 17:27:21 +00001598static int expcmd (int , char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001599#endif
1600
Eric Andersen2870d962001-07-02 17:27:21 +00001601static char *trap[NSIG]; /* trap handler commands */
1602static char sigmode[NSIG - 1]; /* current value of signal */
1603static char gotsig[NSIG - 1]; /* indicates specified signal received */
1604static int pendingsigs; /* indicates some signal received */
1605
Eric Andersencb57d552001-06-28 07:25:16 +00001606/*
1607 * This file was generated by the mkbuiltins program.
1608 */
1609
Eric Andersen2870d962001-07-02 17:27:21 +00001610#ifdef JOBS
1611static int bgcmd (int, char **);
1612static int fgcmd (int, char **);
1613static int killcmd (int, char **);
1614#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001615static int bltincmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001616static int cdcmd (int, char **);
1617static int breakcmd (int, char **);
1618#ifdef ASH_CMDCMD
1619static int commandcmd (int, char **);
1620#endif
1621static int dotcmd (int, char **);
1622static int evalcmd (int, char **);
1623static int execcmd (int, char **);
1624static int exitcmd (int, char **);
1625static int exportcmd (int, char **);
1626static int histcmd (int, char **);
1627static int hashcmd (int, char **);
Eric Andersen1c039232001-07-07 00:05:55 +00001628static int helpcmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001629static int jobscmd (int, char **);
1630static int localcmd (int, char **);
Eric Andersen3102ac42001-07-06 04:26:23 +00001631#ifndef BB_PWD
Eric Andersen2870d962001-07-02 17:27:21 +00001632static int pwdcmd (int, char **);
1633#endif
1634static int readcmd (int, char **);
1635static int returncmd (int, char **);
1636static int setcmd (int, char **);
1637static int setvarcmd (int, char **);
1638static int shiftcmd (int, char **);
1639static int trapcmd (int, char **);
1640static int umaskcmd (int, char **);
1641#ifdef ASH_ALIAS
1642static int aliascmd (int, char **);
1643static int unaliascmd (int, char **);
1644#endif
1645static int unsetcmd (int, char **);
1646static int waitcmd (int, char **);
1647static int ulimitcmd (int, char **);
1648static int timescmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001649#ifdef ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00001650static int expcmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001651#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001652static int typecmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001653#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00001654static int getoptscmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001655#endif
1656
Eric Andersen2870d962001-07-02 17:27:21 +00001657#ifndef BB_TRUE_FALSE
Eric Andersen2870d962001-07-02 17:27:21 +00001658static int true_main (int, char **);
1659static int false_main (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001660#endif
1661
1662static void setpwd (const char *, int);
1663
1664
1665#define BUILTIN_NOSPEC "0"
1666#define BUILTIN_SPECIAL "1"
1667#define BUILTIN_REGULAR "2"
1668#define BUILTIN_ASSIGN "4"
1669#define BUILTIN_SPEC_ASSG "5"
1670#define BUILTIN_REG_ASSG "6"
1671
1672#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1673#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1674#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
1675
1676struct builtincmd {
1677 const char *name;
1678 int (*const builtinfunc) (int, char **);
1679 //unsigned flags;
1680};
1681
Eric Andersencb57d552001-06-28 07:25:16 +00001682
1683/* It is CRUCIAL that this listing be kept in ascii order, otherwise
1684 * the binary search in find_builtin() will stop working. If you value
1685 * your kneecaps, you'll be sure to *make sure* that any changes made
1686 * to this array result in the listing remaining in ascii order. You
1687 * have been warned.
1688 */
1689static const struct builtincmd builtincmds[] = {
Eric Andersen62483552001-07-10 06:09:16 +00001690 { BUILTIN_SPECIAL ".", dotcmd }, /* first, see declare DOTCMD */
Eric Andersen2870d962001-07-02 17:27:21 +00001691 { BUILTIN_SPECIAL ":", true_main },
1692#ifdef ASH_ALIAS
1693 { BUILTIN_REG_ASSG "alias", aliascmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001694#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001695#ifdef JOBS
1696 { BUILTIN_REGULAR "bg", bgcmd },
1697#endif
1698 { BUILTIN_SPECIAL "break", breakcmd },
Eric Andersen3102ac42001-07-06 04:26:23 +00001699 { BUILTIN_SPECIAL "builtin", bltincmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001700 { BUILTIN_REGULAR "cd", cdcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001701 { BUILTIN_NOSPEC "chdir", cdcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001702#ifdef ASH_CMDCMD
1703 { BUILTIN_REGULAR "command", commandcmd },
1704#endif
1705 { BUILTIN_SPECIAL "continue", breakcmd },
1706 { BUILTIN_SPECIAL "eval", evalcmd },
1707 { BUILTIN_SPECIAL "exec", execcmd },
1708 { BUILTIN_SPECIAL "exit", exitcmd },
1709#ifdef ASH_MATH_SUPPORT
1710 { BUILTIN_NOSPEC "exp", expcmd },
1711#endif
1712 { BUILTIN_SPEC_ASSG "export", exportcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001713 { BUILTIN_REGULAR "false", false_main },
Eric Andersen2870d962001-07-02 17:27:21 +00001714 { BUILTIN_REGULAR "fc", histcmd },
1715#ifdef JOBS
1716 { BUILTIN_REGULAR "fg", fgcmd },
1717#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001718#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00001719 { BUILTIN_REGULAR "getopts", getoptscmd },
1720#endif
1721 { BUILTIN_NOSPEC "hash", hashcmd },
Eric Andersen1c039232001-07-07 00:05:55 +00001722 { BUILTIN_NOSPEC "help", helpcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001723 { BUILTIN_REGULAR "jobs", jobscmd },
1724#ifdef JOBS
1725 { BUILTIN_REGULAR "kill", killcmd },
1726#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001727#ifdef ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00001728 { BUILTIN_NOSPEC "let", expcmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001729#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001730 { BUILTIN_ASSIGN "local", localcmd },
Eric Andersen3102ac42001-07-06 04:26:23 +00001731#ifndef BB_PWD
Eric Andersen2870d962001-07-02 17:27:21 +00001732 { BUILTIN_NOSPEC "pwd", pwdcmd },
1733#endif
1734 { BUILTIN_REGULAR "read", readcmd },
1735 { BUILTIN_SPEC_ASSG "readonly", exportcmd },
1736 { BUILTIN_SPECIAL "return", returncmd },
1737 { BUILTIN_SPECIAL "set", setcmd },
1738 { BUILTIN_NOSPEC "setvar", setvarcmd },
1739 { BUILTIN_SPECIAL "shift", shiftcmd },
1740 { BUILTIN_SPECIAL "times", timescmd },
1741 { BUILTIN_SPECIAL "trap", trapcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001742 { BUILTIN_REGULAR "true", true_main },
Eric Andersen2870d962001-07-02 17:27:21 +00001743 { BUILTIN_NOSPEC "type", typecmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001744 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1745 { BUILTIN_REGULAR "umask", umaskcmd },
1746#ifdef ASH_ALIAS
1747 { BUILTIN_REGULAR "unalias", unaliascmd },
1748#endif
1749 { BUILTIN_SPECIAL "unset", unsetcmd },
1750 { BUILTIN_REGULAR "wait", waitcmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001751};
1752#define NUMBUILTINS (sizeof (builtincmds) / sizeof (struct builtincmd) )
1753
Eric Andersen2870d962001-07-02 17:27:21 +00001754static const struct builtincmd *DOTCMD = &builtincmds[0];
1755static struct builtincmd *BLTINCMD;
1756static struct builtincmd *EXECCMD;
1757static struct builtincmd *EVALCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00001758
Eric Andersen2870d962001-07-02 17:27:21 +00001759/* states */
1760#define JOBSTOPPED 1 /* all procs are stopped */
1761#define JOBDONE 2 /* all procs are completed */
Eric Andersencb57d552001-06-28 07:25:16 +00001762
Eric Andersen2870d962001-07-02 17:27:21 +00001763/*
1764 * A job structure contains information about a job. A job is either a
1765 * single process or a set of processes contained in a pipeline. In the
1766 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1767 * array of pids.
1768 */
Eric Andersencb57d552001-06-28 07:25:16 +00001769
Eric Andersen2870d962001-07-02 17:27:21 +00001770struct procstat {
1771 pid_t pid; /* process id */
1772 int status; /* status flags (defined above) */
1773 char *cmd; /* text of command being run */
1774};
Eric Andersencb57d552001-06-28 07:25:16 +00001775
Eric Andersen2870d962001-07-02 17:27:21 +00001776
1777static int job_warning; /* user was warned about stopped jobs */
1778
1779#ifdef JOBS
1780static void setjobctl(int enable);
1781#else
1782#define setjobctl(on) /* do nothing */
Eric Andersencb57d552001-06-28 07:25:16 +00001783#endif
1784
Eric Andersen2870d962001-07-02 17:27:21 +00001785
1786struct job {
1787 struct procstat ps0; /* status of process */
1788 struct procstat *ps; /* status or processes when more than one */
1789 short nprocs; /* number of processes */
1790 short pgrp; /* process group of this job */
1791 char state; /* true if job is finished */
1792 char used; /* true if this entry is in used */
1793 char changed; /* true if status has changed */
1794#ifdef JOBS
1795 char jobctl; /* job running under job control */
1796#endif
1797};
1798
1799static struct job *jobtab; /* array of jobs */
1800static int njobs; /* size of array */
1801static int backgndpid = -1; /* pid of last background process */
1802#ifdef JOBS
1803static int initialpgrp; /* pgrp of shell on invocation */
1804static int curjob; /* current job */
1805static int jobctl;
1806#endif
1807static int intreceived;
1808
Eric Andersen62483552001-07-10 06:09:16 +00001809static struct job *makejob (const union node *, int);
1810static int forkshell (struct job *, const union node *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00001811static int waitforjob (struct job *);
1812
1813static int docd (char *, int);
1814static char *getcomponent (void);
1815static void updatepwd (const char *);
1816static void getpwd (void);
1817
1818static char *padvance (const char **, const char *);
1819
1820static char nullstr[1]; /* zero length string */
1821static char *curdir = nullstr; /* current working directory */
1822static char *cdcomppath;
1823
Eric Andersencb57d552001-06-28 07:25:16 +00001824static int
1825cdcmd(argc, argv)
1826 int argc;
1827 char **argv;
1828{
1829 const char *dest;
1830 const char *path;
1831 char *p;
1832 struct stat statb;
1833 int print = 0;
1834
1835 nextopt(nullstr);
1836 if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME")) == NULL)
1837 error("HOME not set");
1838 if (*dest == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00001839 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001840 if (dest[0] == '-' && dest[1] == '\0') {
1841 dest = bltinlookup("OLDPWD");
1842 if (!dest || !*dest) {
1843 dest = curdir;
1844 }
1845 print = 1;
1846 if (dest)
Eric Andersen2870d962001-07-02 17:27:21 +00001847 print = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00001848 else
Eric Andersen2870d962001-07-02 17:27:21 +00001849 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001850 }
1851 if (*dest == '/' || (path = bltinlookup("CDPATH")) == NULL)
1852 path = nullstr;
1853 while ((p = padvance(&path, dest)) != NULL) {
1854 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
1855 if (!print) {
1856 /*
1857 * XXX - rethink
1858 */
1859 if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
1860 p += 2;
1861 print = strcmp(p, dest);
1862 }
1863 if (docd(p, print) >= 0)
1864 return 0;
1865
1866 }
1867 }
1868 error("can't cd to %s", dest);
1869 /* NOTREACHED */
1870}
1871
1872
1873/*
1874 * Actually do the chdir. In an interactive shell, print the
1875 * directory name if "print" is nonzero.
1876 */
1877
1878static int
1879docd(dest, print)
1880 char *dest;
1881 int print;
1882{
1883 char *p;
1884 char *q;
1885 char *component;
1886 struct stat statb;
1887 int first;
1888 int badstat;
1889
1890 TRACE(("docd(\"%s\", %d) called\n", dest, print));
1891
1892 /*
1893 * Check each component of the path. If we find a symlink or
1894 * something we can't stat, clear curdir to force a getcwd()
1895 * next time we get the value of the current directory.
1896 */
1897 badstat = 0;
1898 cdcomppath = sstrdup(dest);
1899 STARTSTACKSTR(p);
1900 if (*dest == '/') {
1901 STPUTC('/', p);
1902 cdcomppath++;
1903 }
1904 first = 1;
1905 while ((q = getcomponent()) != NULL) {
1906 if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0'))
1907 continue;
1908 if (! first)
1909 STPUTC('/', p);
1910 first = 0;
1911 component = q;
1912 while (*q)
1913 STPUTC(*q++, p);
1914 if (equal(component, ".."))
1915 continue;
1916 STACKSTRNUL(p);
1917 if ((lstat(stackblock(), &statb) < 0)
1918 || (S_ISLNK(statb.st_mode))) {
1919 /* print = 1; */
1920 badstat = 1;
1921 break;
1922 }
1923 }
1924
1925 INTOFF;
1926 if (chdir(dest) < 0) {
1927 INTON;
1928 return -1;
1929 }
1930 updatepwd(badstat ? NULL : dest);
1931 INTON;
1932 if (print && iflag)
Eric Andersen62483552001-07-10 06:09:16 +00001933 printf(snlfmt, curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00001934 return 0;
1935}
1936
1937
1938/*
1939 * Get the next component of the path name pointed to by cdcomppath.
1940 * This routine overwrites the string pointed to by cdcomppath.
1941 */
1942
1943static char *
1944getcomponent() {
1945 char *p;
1946 char *start;
1947
1948 if ((p = cdcomppath) == NULL)
1949 return NULL;
1950 start = cdcomppath;
1951 while (*p != '/' && *p != '\0')
1952 p++;
1953 if (*p == '\0') {
1954 cdcomppath = NULL;
1955 } else {
1956 *p++ = '\0';
1957 cdcomppath = p;
1958 }
1959 return start;
1960}
1961
1962
1963
1964/*
1965 * Update curdir (the name of the current directory) in response to a
1966 * cd command. We also call hashcd to let the routines in exec.c know
1967 * that the current directory has changed.
1968 */
1969
Eric Andersen2870d962001-07-02 17:27:21 +00001970static void hashcd (void);
1971
Eric Andersencb57d552001-06-28 07:25:16 +00001972static void
Eric Andersen2870d962001-07-02 17:27:21 +00001973updatepwd(const char *dir)
1974{
Eric Andersencb57d552001-06-28 07:25:16 +00001975 char *new;
1976 char *p;
1977 size_t len;
1978
Eric Andersen2870d962001-07-02 17:27:21 +00001979 hashcd(); /* update command hash table */
Eric Andersencb57d552001-06-28 07:25:16 +00001980
1981 /*
1982 * If our argument is NULL, we don't know the current directory
1983 * any more because we traversed a symbolic link or something
1984 * we couldn't stat().
1985 */
1986 if (dir == NULL || curdir == nullstr) {
1987 setpwd(0, 1);
1988 return;
1989 }
1990 len = strlen(dir);
1991 cdcomppath = sstrdup(dir);
1992 STARTSTACKSTR(new);
1993 if (*dir != '/') {
1994 p = curdir;
1995 while (*p)
1996 STPUTC(*p++, new);
1997 if (p[-1] == '/')
1998 STUNPUTC(new);
1999 }
2000 while ((p = getcomponent()) != NULL) {
2001 if (equal(p, "..")) {
2002 while (new > stackblock() && (STUNPUTC(new), *new) != '/');
2003 } else if (*p != '\0' && ! equal(p, ".")) {
2004 STPUTC('/', new);
2005 while (*p)
2006 STPUTC(*p++, new);
2007 }
2008 }
2009 if (new == stackblock())
2010 STPUTC('/', new);
2011 STACKSTRNUL(new);
2012 setpwd(stackblock(), 1);
2013}
2014
2015
Eric Andersen3102ac42001-07-06 04:26:23 +00002016#ifndef BB_PWD
Eric Andersencb57d552001-06-28 07:25:16 +00002017static int
2018pwdcmd(argc, argv)
2019 int argc;
2020 char **argv;
2021{
Eric Andersen62483552001-07-10 06:09:16 +00002022 printf(snlfmt, curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00002023 return 0;
2024}
Eric Andersen2870d962001-07-02 17:27:21 +00002025#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002026
2027/*
2028 * Find out what the current directory is. If we already know the current
2029 * directory, this routine returns immediately.
2030 */
2031static void
Eric Andersen2870d962001-07-02 17:27:21 +00002032getpwd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00002033{
Eric Andersen2870d962001-07-02 17:27:21 +00002034 curdir = xgetcwd(0);
2035 if(curdir==0)
2036 curdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00002037}
2038
2039static void
2040setpwd(const char *val, int setold)
2041{
2042 if (setold) {
2043 setvar("OLDPWD", curdir, VEXPORT);
2044 }
2045 INTOFF;
2046 if (curdir != nullstr) {
2047 free(curdir);
2048 curdir = nullstr;
2049 }
2050 if (!val) {
2051 getpwd();
2052 } else {
2053 curdir = savestr(val);
2054 }
2055 INTON;
2056 setvar("PWD", curdir, VEXPORT);
2057}
2058
Eric Andersencb57d552001-06-28 07:25:16 +00002059/*
2060 * Errors and exceptions.
2061 */
2062
2063/*
2064 * Code to handle exceptions in C.
2065 */
2066
Eric Andersen2870d962001-07-02 17:27:21 +00002067/*
2068 * We enclose jmp_buf in a structure so that we can declare pointers to
2069 * jump locations. The global variable handler contains the location to
2070 * jump to when an exception occurs, and the global variable exception
2071 * contains a code identifying the exeception. To implement nested
2072 * exception handlers, the user should save the value of handler on entry
2073 * to an inner scope, set handler to point to a jmploc structure for the
2074 * inner scope, and restore handler on exit from the scope.
2075 */
2076
2077struct jmploc {
2078 jmp_buf loc;
2079};
2080
2081/* exceptions */
2082#define EXINT 0 /* SIGINT received */
2083#define EXERROR 1 /* a generic error */
2084#define EXSHELLPROC 2 /* execute a shell procedure */
2085#define EXEXEC 3 /* command execution failed */
2086
2087static struct jmploc *handler;
Eric Andersencb57d552001-06-28 07:25:16 +00002088static int exception;
Eric Andersencb57d552001-06-28 07:25:16 +00002089
Eric Andersen2870d962001-07-02 17:27:21 +00002090static void exverror (int, const char *, va_list)
Eric Andersencb57d552001-06-28 07:25:16 +00002091 __attribute__((__noreturn__));
2092
2093/*
2094 * Called to raise an exception. Since C doesn't include exceptions, we
2095 * just do a longjmp to the exception handler. The type of exception is
2096 * stored in the global variable "exception".
2097 */
2098
Eric Andersen2870d962001-07-02 17:27:21 +00002099static void exraise (int) __attribute__((__noreturn__));
2100
Eric Andersencb57d552001-06-28 07:25:16 +00002101static void
Eric Andersen2870d962001-07-02 17:27:21 +00002102exraise(int e)
Eric Andersencb57d552001-06-28 07:25:16 +00002103{
2104#ifdef DEBUG
2105 if (handler == NULL)
2106 abort();
2107#endif
Eric Andersen62483552001-07-10 06:09:16 +00002108 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00002109 exception = e;
2110 longjmp(handler->loc, 1);
2111}
2112
2113
2114/*
2115 * Called from trap.c when a SIGINT is received. (If the user specifies
2116 * that SIGINT is to be trapped or ignored using the trap builtin, then
2117 * this routine is not called.) Suppressint is nonzero when interrupts
2118 * are held using the INTOFF macro. The call to _exit is necessary because
2119 * there is a short period after a fork before the signal handlers are
2120 * set to the appropriate value for the child. (The test for iflag is
2121 * just defensive programming.)
2122 */
2123
2124static void
Eric Andersen2870d962001-07-02 17:27:21 +00002125onint(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00002126 sigset_t mysigset;
2127
2128 if (suppressint) {
2129 intpending++;
2130 return;
2131 }
2132 intpending = 0;
2133 sigemptyset(&mysigset);
2134 sigprocmask(SIG_SETMASK, &mysigset, NULL);
2135 if (rootshell && iflag)
2136 exraise(EXINT);
2137 else {
2138 signal(SIGINT, SIG_DFL);
2139 raise(SIGINT);
2140 }
2141 /* NOTREACHED */
2142}
2143
2144
Eric Andersen2870d962001-07-02 17:27:21 +00002145static char *commandname; /* currently executing command */
2146
Eric Andersencb57d552001-06-28 07:25:16 +00002147/*
2148 * Exverror is called to raise the error exception. If the first argument
2149 * is not NULL then error prints an error message using printf style
2150 * formatting. It then raises the error exception.
2151 */
2152static void
Eric Andersen2870d962001-07-02 17:27:21 +00002153exverror(int cond, const char *msg, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00002154{
2155 CLEAR_PENDING_INT;
2156 INTOFF;
2157
2158#ifdef DEBUG
2159 if (msg)
2160 TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
2161 else
2162 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2163#endif
2164 if (msg) {
2165 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +00002166 out2fmt("%s: ", commandname);
2167 vfprintf(stderr, msg, ap);
2168 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00002169 }
Eric Andersencb57d552001-06-28 07:25:16 +00002170 exraise(cond);
2171 /* NOTREACHED */
2172}
2173
2174
Eric Andersen74bcd162001-07-30 21:41:37 +00002175static void
Eric Andersencb57d552001-06-28 07:25:16 +00002176error(const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002177{
Eric Andersencb57d552001-06-28 07:25:16 +00002178 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002179 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002180 exverror(EXERROR, msg, ap);
2181 /* NOTREACHED */
2182 va_end(ap);
2183}
2184
2185
Eric Andersencb57d552001-06-28 07:25:16 +00002186static void
2187exerror(int cond, const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002188{
Eric Andersencb57d552001-06-28 07:25:16 +00002189 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002190 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002191 exverror(cond, msg, ap);
2192 /* NOTREACHED */
2193 va_end(ap);
2194}
2195
2196
2197
2198/*
2199 * Table of error messages.
2200 */
2201
2202struct errname {
Eric Andersen2870d962001-07-02 17:27:21 +00002203 short errcode; /* error number */
Eric Andersen62483552001-07-10 06:09:16 +00002204 char action; /* operation which encountered the error */
Eric Andersencb57d552001-06-28 07:25:16 +00002205};
2206
Eric Andersen2870d962001-07-02 17:27:21 +00002207/*
2208 * Types of operations (passed to the errmsg routine).
2209 */
2210
2211#define E_OPEN 01 /* opening a file */
2212#define E_CREAT 02 /* creating a file */
2213#define E_EXEC 04 /* executing a program */
Eric Andersencb57d552001-06-28 07:25:16 +00002214
2215#define ALL (E_OPEN|E_CREAT|E_EXEC)
2216
2217static const struct errname errormsg[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00002218 { EINTR, ALL },
2219 { EACCES, ALL },
2220 { EIO, ALL },
2221 { ENOENT, E_OPEN },
2222 { ENOENT, E_CREAT },
2223 { ENOENT, E_EXEC },
2224 { ENOTDIR, E_OPEN },
2225 { ENOTDIR, E_CREAT },
2226 { ENOTDIR, E_EXEC },
2227 { EISDIR, ALL },
2228 { EEXIST, E_CREAT },
2229#ifdef EMFILE
2230 { EMFILE, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002231#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002232 { ENFILE, ALL },
2233 { ENOSPC, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002234#ifdef EDQUOT
Eric Andersen2870d962001-07-02 17:27:21 +00002235 { EDQUOT, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002236#endif
2237#ifdef ENOSR
Eric Andersen2870d962001-07-02 17:27:21 +00002238 { ENOSR, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002239#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002240 { ENXIO, ALL },
2241 { EROFS, ALL },
2242 { ETXTBSY, ALL },
2243#ifdef EAGAIN
2244 { EAGAIN, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002245#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002246 { ENOMEM, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002247#ifdef ENOLINK
Eric Andersen2870d962001-07-02 17:27:21 +00002248 { ENOLINK, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002249#endif
2250#ifdef EMULTIHOP
Eric Andersen2870d962001-07-02 17:27:21 +00002251 { EMULTIHOP, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002252#endif
2253#ifdef ECOMM
Eric Andersen2870d962001-07-02 17:27:21 +00002254 { ECOMM, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002255#endif
2256#ifdef ESTALE
Eric Andersen2870d962001-07-02 17:27:21 +00002257 { ESTALE, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002258#endif
2259#ifdef ETIMEDOUT
Eric Andersen2870d962001-07-02 17:27:21 +00002260 { ETIMEDOUT, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002261#endif
2262#ifdef ELOOP
Eric Andersen2870d962001-07-02 17:27:21 +00002263 { ELOOP, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002264#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002265 { E2BIG, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002266#ifdef ELIBACC
Eric Andersen2870d962001-07-02 17:27:21 +00002267 { ELIBACC, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002268#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002269};
2270
Eric Andersen2870d962001-07-02 17:27:21 +00002271#define ERRNAME_SIZE (sizeof(errormsg)/sizeof(struct errname))
Eric Andersencb57d552001-06-28 07:25:16 +00002272
2273/*
2274 * Return a string describing an error. The returned string may be a
2275 * pointer to a static buffer that will be overwritten on the next call.
2276 * Action describes the operation that got the error.
2277 */
2278
2279static const char *
Eric Andersen2870d962001-07-02 17:27:21 +00002280errmsg(int e, int action)
Eric Andersencb57d552001-06-28 07:25:16 +00002281{
2282 struct errname const *ep;
2283 static char buf[12];
2284
Eric Andersen2870d962001-07-02 17:27:21 +00002285 for (ep = errormsg ; ep < errormsg+ERRNAME_SIZE; ep++) {
Eric Andersencb57d552001-06-28 07:25:16 +00002286 if (ep->errcode == e && (ep->action & action) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00002287 return strerror(e);
Eric Andersencb57d552001-06-28 07:25:16 +00002288 }
Eric Andersen2870d962001-07-02 17:27:21 +00002289
Eric Andersen3102ac42001-07-06 04:26:23 +00002290 snprintf(buf, sizeof buf, "error %d", e);
Eric Andersencb57d552001-06-28 07:25:16 +00002291 return buf;
2292}
2293
2294
Eric Andersen3102ac42001-07-06 04:26:23 +00002295#ifdef ASH_OPTIMIZE_FOR_SIZE
Eric Andersencb57d552001-06-28 07:25:16 +00002296static void
2297__inton() {
2298 if (--suppressint == 0 && intpending) {
2299 onint();
2300 }
2301}
Eric Andersen3102ac42001-07-06 04:26:23 +00002302static void forceinton (void) {
2303 suppressint = 0;
2304 if (intpending)
2305 onint();
2306}
Eric Andersencb57d552001-06-28 07:25:16 +00002307#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002308
2309/* flags in argument to evaltree */
Eric Andersen2870d962001-07-02 17:27:21 +00002310#define EV_EXIT 01 /* exit after evaluating tree */
2311#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2312#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00002313
Eric Andersen2870d962001-07-02 17:27:21 +00002314static int evalskip; /* set if we are skipping commands */
2315static int skipcount; /* number of levels to skip */
2316static int loopnest; /* current loop nesting level */
2317static int funcnest; /* depth of function calls */
Eric Andersencb57d552001-06-28 07:25:16 +00002318
2319
Eric Andersen2870d962001-07-02 17:27:21 +00002320static struct strlist *cmdenviron; /* environment for builtin command */
2321static int exitstatus; /* exit status of last command */
2322static int oexitstatus; /* saved exit status */
Eric Andersencb57d552001-06-28 07:25:16 +00002323
Eric Andersen62483552001-07-10 06:09:16 +00002324static void evalsubshell (const union node *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00002325static void expredir (union node *);
Eric Andersen2870d962001-07-02 17:27:21 +00002326static void prehash (union node *);
2327static void eprintlist (struct strlist *);
Eric Andersencb57d552001-06-28 07:25:16 +00002328
Eric Andersen2870d962001-07-02 17:27:21 +00002329static union node *parsecmd(int);
Eric Andersencb57d552001-06-28 07:25:16 +00002330/*
2331 * Called to reset things after an exception.
2332 */
2333
Eric Andersencb57d552001-06-28 07:25:16 +00002334/*
2335 * The eval commmand.
2336 */
Eric Andersen2870d962001-07-02 17:27:21 +00002337static void evalstring (char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00002338
2339static int
2340evalcmd(argc, argv)
2341 int argc;
2342 char **argv;
2343{
Eric Andersen2870d962001-07-02 17:27:21 +00002344 char *p;
2345 char *concat;
2346 char **ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002347
Eric Andersen2870d962001-07-02 17:27:21 +00002348 if (argc > 1) {
2349 p = argv[1];
2350 if (argc > 2) {
2351 STARTSTACKSTR(concat);
2352 ap = argv + 2;
2353 for (;;) {
2354 while (*p)
2355 STPUTC(*p++, concat);
2356 if ((p = *ap++) == NULL)
2357 break;
2358 STPUTC(' ', concat);
2359 }
2360 STPUTC('\0', concat);
2361 p = grabstackstr(concat);
2362 }
2363 evalstring(p, EV_TESTED);
2364 }
2365 return exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002366}
2367
Eric Andersencb57d552001-06-28 07:25:16 +00002368/*
2369 * Execute a command or commands contained in a string.
2370 */
2371
Eric Andersen2870d962001-07-02 17:27:21 +00002372static void evaltree (union node *, int);
2373static void setinputstring (char *);
2374static void popfile (void);
2375static void setstackmark(struct stackmark *mark);
2376static void popstackmark(struct stackmark *mark);
2377
2378
Eric Andersencb57d552001-06-28 07:25:16 +00002379static void
Eric Andersen2870d962001-07-02 17:27:21 +00002380evalstring(char *s, int flag)
2381{
Eric Andersencb57d552001-06-28 07:25:16 +00002382 union node *n;
2383 struct stackmark smark;
2384
2385 setstackmark(&smark);
2386 setinputstring(s);
2387 while ((n = parsecmd(0)) != NEOF) {
2388 evaltree(n, flag);
2389 popstackmark(&smark);
2390 }
2391 popfile();
2392 popstackmark(&smark);
2393}
2394
Eric Andersen2870d962001-07-02 17:27:21 +00002395static struct builtincmd *find_builtin (const char *);
Eric Andersen62483552001-07-10 06:09:16 +00002396static void expandarg (union node *, struct arglist *, int);
2397static void calcsize (const union node *);
2398static union node *copynode (const union node *);
2399
2400/*
2401 * Make a copy of a parse tree.
2402 */
2403
2404static int funcblocksize; /* size of structures in function */
2405static int funcstringsize; /* size of strings in node */
2406static pointer funcblock; /* block to allocate function from */
2407static char *funcstring; /* block to allocate strings from */
2408
2409
2410static inline union node *
2411copyfunc(union node *n)
2412{
2413 if (n == NULL)
2414 return NULL;
2415 funcblocksize = 0;
2416 funcstringsize = 0;
2417 calcsize(n);
2418 funcblock = ckmalloc(funcblocksize + funcstringsize);
2419 funcstring = (char *) funcblock + funcblocksize;
2420 return copynode(n);
2421}
2422
2423/*
2424 * Free a parse tree.
2425 */
Eric Andersencb57d552001-06-28 07:25:16 +00002426
2427static void
Eric Andersen62483552001-07-10 06:09:16 +00002428freefunc(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00002429{
Eric Andersen62483552001-07-10 06:09:16 +00002430 if (n)
2431 ckfree(n);
Eric Andersencb57d552001-06-28 07:25:16 +00002432}
2433
2434
Eric Andersen62483552001-07-10 06:09:16 +00002435/*
2436 * Add a new command entry, replacing any existing command entry for
2437 * the same name.
2438 */
2439
2440static inline void
2441addcmdentry(char *name, struct cmdentry *entry)
2442{
2443 struct tblentry *cmdp;
2444
2445 INTOFF;
2446 cmdp = cmdlookup(name, 1);
2447 if (cmdp->cmdtype == CMDFUNCTION) {
2448 freefunc(cmdp->param.func);
2449 }
2450 cmdp->cmdtype = entry->cmdtype;
2451 cmdp->param = entry->u;
2452 INTON;
2453}
2454
2455static inline void
2456evalloop(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002457{
2458 int status;
2459
2460 loopnest++;
2461 status = 0;
2462 for (;;) {
2463 evaltree(n->nbinary.ch1, EV_TESTED);
2464 if (evalskip) {
Eric Andersen2870d962001-07-02 17:27:21 +00002465skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002466 evalskip = 0;
2467 continue;
2468 }
2469 if (evalskip == SKIPBREAK && --skipcount <= 0)
2470 evalskip = 0;
2471 break;
2472 }
2473 if (n->type == NWHILE) {
2474 if (exitstatus != 0)
2475 break;
2476 } else {
2477 if (exitstatus == 0)
2478 break;
2479 }
2480 evaltree(n->nbinary.ch2, flags & EV_TESTED);
2481 status = exitstatus;
2482 if (evalskip)
2483 goto skipping;
2484 }
2485 loopnest--;
2486 exitstatus = status;
2487}
2488
Eric Andersencb57d552001-06-28 07:25:16 +00002489static void
Eric Andersen62483552001-07-10 06:09:16 +00002490evalfor(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002491{
2492 struct arglist arglist;
2493 union node *argp;
2494 struct strlist *sp;
2495 struct stackmark smark;
2496
2497 setstackmark(&smark);
2498 arglist.lastp = &arglist.list;
2499 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2500 oexitstatus = exitstatus;
2501 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2502 if (evalskip)
2503 goto out;
2504 }
2505 *arglist.lastp = NULL;
2506
2507 exitstatus = 0;
2508 loopnest++;
2509 for (sp = arglist.list ; sp ; sp = sp->next) {
2510 setvar(n->nfor.var, sp->text, 0);
2511 evaltree(n->nfor.body, flags & EV_TESTED);
2512 if (evalskip) {
2513 if (evalskip == SKIPCONT && --skipcount <= 0) {
2514 evalskip = 0;
2515 continue;
2516 }
2517 if (evalskip == SKIPBREAK && --skipcount <= 0)
2518 evalskip = 0;
2519 break;
2520 }
2521 }
2522 loopnest--;
2523out:
2524 popstackmark(&smark);
2525}
2526
Eric Andersen62483552001-07-10 06:09:16 +00002527static inline void
2528evalcase(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002529{
2530 union node *cp;
2531 union node *patp;
2532 struct arglist arglist;
2533 struct stackmark smark;
2534
2535 setstackmark(&smark);
2536 arglist.lastp = &arglist.list;
2537 oexitstatus = exitstatus;
2538 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2539 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2540 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2541 if (casematch(patp, arglist.list->text)) {
2542 if (evalskip == 0) {
2543 evaltree(cp->nclist.body, flags);
2544 }
2545 goto out;
2546 }
2547 }
2548 }
2549out:
2550 popstackmark(&smark);
2551}
2552
Eric Andersencb57d552001-06-28 07:25:16 +00002553/*
Eric Andersencb57d552001-06-28 07:25:16 +00002554 * Evaluate a pipeline. All the processes in the pipeline are children
2555 * of the process creating the pipeline. (This differs from some versions
2556 * of the shell, which make the last process in a pipeline the parent
2557 * of all the rest.)
2558 */
2559
Eric Andersen62483552001-07-10 06:09:16 +00002560static inline void
Eric Andersencb57d552001-06-28 07:25:16 +00002561evalpipe(n)
2562 union node *n;
2563{
2564 struct job *jp;
2565 struct nodelist *lp;
2566 int pipelen;
2567 int prevfd;
2568 int pip[2];
2569
2570 TRACE(("evalpipe(0x%lx) called\n", (long)n));
2571 pipelen = 0;
2572 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
2573 pipelen++;
2574 INTOFF;
2575 jp = makejob(n, pipelen);
2576 prevfd = -1;
2577 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
2578 prehash(lp->n);
2579 pip[1] = -1;
2580 if (lp->next) {
2581 if (pipe(pip) < 0) {
2582 close(prevfd);
2583 error("Pipe call failed");
2584 }
2585 }
2586 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
2587 INTON;
2588 if (prevfd > 0) {
2589 close(0);
2590 dup_as_newfd(prevfd, 0);
2591 close(prevfd);
2592 if (pip[0] == 0) {
2593 pip[0] = -1;
2594 }
2595 }
2596 if (pip[1] >= 0) {
2597 if (pip[0] >= 0) {
2598 close(pip[0]);
2599 }
2600 if (pip[1] != 1) {
2601 close(1);
2602 dup_as_newfd(pip[1], 1);
2603 close(pip[1]);
2604 }
2605 }
2606 evaltree(lp->n, EV_EXIT);
2607 }
2608 if (prevfd >= 0)
2609 close(prevfd);
2610 prevfd = pip[0];
2611 close(pip[1]);
2612 }
2613 INTON;
2614 if (n->npipe.backgnd == 0) {
2615 INTOFF;
2616 exitstatus = waitforjob(jp);
2617 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
2618 INTON;
2619 }
2620}
2621
Eric Andersen2870d962001-07-02 17:27:21 +00002622static void find_command (const char *, struct cmdentry *, int, const char *);
2623
2624static int
2625isassignment(const char *word) {
2626 if (!is_name(*word)) {
2627 return 0;
2628 }
2629 do {
2630 word++;
2631 } while (is_in_name(*word));
2632 return *word == '=';
2633}
2634
Eric Andersen62483552001-07-10 06:09:16 +00002635
Eric Andersencb57d552001-06-28 07:25:16 +00002636static void
Eric Andersen3102ac42001-07-06 04:26:23 +00002637evalcommand(union node *cmd, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002638{
2639 struct stackmark smark;
2640 union node *argp;
2641 struct arglist arglist;
2642 struct arglist varlist;
2643 char **argv;
2644 int argc;
2645 char **envp;
2646 struct strlist *sp;
2647 int mode;
Eric Andersencb57d552001-06-28 07:25:16 +00002648 struct cmdentry cmdentry;
2649 struct job *jp;
2650 char *volatile savecmdname;
2651 volatile struct shparam saveparam;
2652 struct localvar *volatile savelocalvars;
2653 volatile int e;
2654 char *lastarg;
2655 const char *path;
2656 const struct builtincmd *firstbltin;
2657 struct jmploc *volatile savehandler;
2658 struct jmploc jmploc;
2659#if __GNUC__
2660 /* Avoid longjmp clobbering */
2661 (void) &argv;
2662 (void) &argc;
2663 (void) &lastarg;
2664 (void) &flags;
2665#endif
2666
2667 /* First expand the arguments. */
2668 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
2669 setstackmark(&smark);
2670 arglist.lastp = &arglist.list;
2671 varlist.lastp = &varlist.list;
2672 arglist.list = 0;
2673 oexitstatus = exitstatus;
2674 exitstatus = 0;
2675 path = pathval();
2676 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
2677 expandarg(argp, &varlist, EXP_VARTILDE);
2678 }
2679 for (
2680 argp = cmd->ncmd.args; argp && !arglist.list;
2681 argp = argp->narg.next
2682 ) {
2683 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2684 }
2685 if (argp) {
2686 struct builtincmd *bcmd;
Eric Andersen62483552001-07-10 06:09:16 +00002687 int pseudovarflag;
Eric Andersencb57d552001-06-28 07:25:16 +00002688 bcmd = find_builtin(arglist.list->text);
Eric Andersen2870d962001-07-02 17:27:21 +00002689 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00002690 for (; argp; argp = argp->narg.next) {
2691 if (pseudovarflag && isassignment(argp->narg.text)) {
2692 expandarg(argp, &arglist, EXP_VARTILDE);
2693 continue;
2694 }
2695 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2696 }
2697 }
2698 *arglist.lastp = NULL;
2699 *varlist.lastp = NULL;
2700 expredir(cmd->ncmd.redirect);
2701 argc = 0;
2702 for (sp = arglist.list ; sp ; sp = sp->next)
2703 argc++;
2704 argv = stalloc(sizeof (char *) * (argc + 1));
2705
2706 for (sp = arglist.list ; sp ; sp = sp->next) {
2707 TRACE(("evalcommand arg: %s\n", sp->text));
2708 *argv++ = sp->text;
2709 }
2710 *argv = NULL;
2711 lastarg = NULL;
2712 if (iflag && funcnest == 0 && argc > 0)
2713 lastarg = argv[-1];
2714 argv -= argc;
2715
2716 /* Print the command if xflag is set. */
2717 if (xflag) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002718 out2c('+');
Eric Andersencb57d552001-06-28 07:25:16 +00002719 eprintlist(varlist.list);
2720 eprintlist(arglist.list);
Eric Andersen3102ac42001-07-06 04:26:23 +00002721 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00002722 }
2723
2724 /* Now locate the command. */
2725 if (argc == 0) {
2726 cmdentry.cmdtype = CMDBUILTIN;
2727 firstbltin = cmdentry.u.cmd = BLTINCMD;
2728 } else {
2729 const char *oldpath;
2730 int findflag = DO_ERR;
2731 int oldfindflag;
2732
2733 /*
2734 * Modify the command lookup path, if a PATH= assignment
2735 * is present
2736 */
2737 for (sp = varlist.list ; sp ; sp = sp->next)
2738 if (varequal(sp->text, defpathvar)) {
2739 path = sp->text + 5;
2740 findflag |= DO_BRUTE;
2741 }
2742 oldpath = path;
2743 oldfindflag = findflag;
2744 firstbltin = 0;
2745 for(;;) {
2746 find_command(argv[0], &cmdentry, findflag, path);
Eric Andersen2870d962001-07-02 17:27:21 +00002747 if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */
Eric Andersencb57d552001-06-28 07:25:16 +00002748 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002749 goto out;
2750 }
2751 /* implement bltin and command here */
2752 if (cmdentry.cmdtype != CMDBUILTIN) {
2753 break;
2754 }
2755 if (!firstbltin) {
2756 firstbltin = cmdentry.u.cmd;
2757 }
2758 if (cmdentry.u.cmd == BLTINCMD) {
2759 for(;;) {
2760 struct builtincmd *bcmd;
2761
2762 argv++;
2763 if (--argc == 0)
2764 goto found;
2765 if (!(bcmd = find_builtin(*argv))) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002766 out2fmt("%s: not found\n", *argv);
Eric Andersencb57d552001-06-28 07:25:16 +00002767 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002768 goto out;
2769 }
2770 cmdentry.u.cmd = bcmd;
2771 if (bcmd != BLTINCMD)
2772 break;
2773 }
2774 }
Eric Andersen2870d962001-07-02 17:27:21 +00002775 if (cmdentry.u.cmd == find_builtin("command")) {
Eric Andersencb57d552001-06-28 07:25:16 +00002776 argv++;
2777 if (--argc == 0) {
2778 goto found;
2779 }
2780 if (*argv[0] == '-') {
2781 if (!equal(argv[0], "-p")) {
2782 argv--;
2783 argc++;
2784 break;
2785 }
2786 argv++;
2787 if (--argc == 0) {
2788 goto found;
2789 }
2790 path = defpath;
2791 findflag |= DO_BRUTE;
2792 } else {
2793 path = oldpath;
2794 findflag = oldfindflag;
2795 }
2796 findflag |= DO_NOFUN;
2797 continue;
2798 }
2799found:
2800 break;
2801 }
2802 }
2803
2804 /* Fork off a child process if necessary. */
2805 if (cmd->ncmd.backgnd
2806 || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00002807 ) {
2808 jp = makejob(cmd, 1);
2809 mode = cmd->ncmd.backgnd;
Eric Andersencb57d552001-06-28 07:25:16 +00002810 if (forkshell(jp, cmd, mode) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00002811 goto parent; /* at end of routine */
Eric Andersencb57d552001-06-28 07:25:16 +00002812 flags |= EV_EXIT;
2813 }
2814
2815 /* This is the child process if a fork occurred. */
2816 /* Execute the command. */
2817 if (cmdentry.cmdtype == CMDFUNCTION) {
2818#ifdef DEBUG
2819 trputs("Shell function: "); trargs(argv);
2820#endif
2821 exitstatus = oexitstatus;
2822 redirect(cmd->ncmd.redirect, REDIR_PUSH);
2823 saveparam = shellparam;
2824 shellparam.malloc = 0;
2825 shellparam.nparam = argc - 1;
2826 shellparam.p = argv + 1;
2827 INTOFF;
2828 savelocalvars = localvars;
2829 localvars = NULL;
2830 INTON;
2831 if (setjmp(jmploc.loc)) {
2832 if (exception == EXSHELLPROC) {
2833 freeparam((volatile struct shparam *)
2834 &saveparam);
2835 } else {
2836 saveparam.optind = shellparam.optind;
2837 saveparam.optoff = shellparam.optoff;
2838 freeparam(&shellparam);
2839 shellparam = saveparam;
2840 }
2841 poplocalvars();
2842 localvars = savelocalvars;
2843 handler = savehandler;
2844 longjmp(handler->loc, 1);
2845 }
2846 savehandler = handler;
2847 handler = &jmploc;
2848 for (sp = varlist.list ; sp ; sp = sp->next)
2849 mklocal(sp->text);
2850 funcnest++;
2851 evaltree(cmdentry.u.func, flags & EV_TESTED);
2852 funcnest--;
2853 INTOFF;
2854 poplocalvars();
2855 localvars = savelocalvars;
2856 saveparam.optind = shellparam.optind;
2857 saveparam.optoff = shellparam.optoff;
2858 freeparam(&shellparam);
2859 shellparam = saveparam;
2860 handler = savehandler;
2861 popredir();
2862 INTON;
2863 if (evalskip == SKIPFUNC) {
2864 evalskip = 0;
2865 skipcount = 0;
2866 }
2867 if (flags & EV_EXIT)
2868 exitshell(exitstatus);
2869 } else if (cmdentry.cmdtype == CMDBUILTIN) {
2870#ifdef DEBUG
2871 trputs("builtin command: "); trargs(argv);
2872#endif
2873 mode = (cmdentry.u.cmd == EXECCMD)? 0 : REDIR_PUSH;
Eric Andersencb57d552001-06-28 07:25:16 +00002874 redirect(cmd->ncmd.redirect, mode);
2875 savecmdname = commandname;
Eric Andersen2870d962001-07-02 17:27:21 +00002876 if (IS_BUILTIN_SPECIAL(firstbltin)) {
Eric Andersencb57d552001-06-28 07:25:16 +00002877 listsetvar(varlist.list);
2878 } else {
2879 cmdenviron = varlist.list;
2880 }
2881 e = -1;
2882 if (setjmp(jmploc.loc)) {
2883 e = exception;
2884 exitstatus = (e == EXINT)? SIGINT+128 : 2;
2885 goto cmddone;
2886 }
2887 savehandler = handler;
2888 handler = &jmploc;
2889 commandname = argv[0];
2890 argptr = argv + 1;
Eric Andersen2870d962001-07-02 17:27:21 +00002891 optptr = NULL; /* initialize nextopt */
Eric Andersencb57d552001-06-28 07:25:16 +00002892 exitstatus = (*cmdentry.u.cmd->builtinfunc)(argc, argv);
2893 flushall();
2894cmddone:
Eric Andersencb57d552001-06-28 07:25:16 +00002895 cmdenviron = NULL;
2896 if (e != EXSHELLPROC) {
2897 commandname = savecmdname;
2898 if (flags & EV_EXIT)
2899 exitshell(exitstatus);
2900 }
2901 handler = savehandler;
2902 if (e != -1) {
2903 if ((e != EXERROR && e != EXEXEC)
2904 || cmdentry.u.cmd == BLTINCMD
2905 || cmdentry.u.cmd == DOTCMD
2906 || cmdentry.u.cmd == EVALCMD
2907 || cmdentry.u.cmd == EXECCMD)
2908 exraise(e);
2909 FORCEINTON;
2910 }
2911 if (cmdentry.u.cmd != EXECCMD)
2912 popredir();
Eric Andersencb57d552001-06-28 07:25:16 +00002913 } else {
2914#ifdef DEBUG
2915 trputs("normal command: "); trargs(argv);
2916#endif
2917 redirect(cmd->ncmd.redirect, 0);
2918 clearredir();
2919 for (sp = varlist.list ; sp ; sp = sp->next)
2920 setvareq(sp->text, VEXPORT|VSTACK);
2921 envp = environment();
2922 shellexec(argv, envp, path, cmdentry.u.index);
2923 }
2924 goto out;
2925
Eric Andersen2870d962001-07-02 17:27:21 +00002926parent: /* parent process gets here (if we forked) */
2927 if (mode == 0) { /* argument to fork */
Eric Andersencb57d552001-06-28 07:25:16 +00002928 INTOFF;
2929 exitstatus = waitforjob(jp);
2930 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00002931 }
2932
2933out:
2934 if (lastarg)
2935 setvar("_", lastarg, 0);
2936 popstackmark(&smark);
2937}
2938
Eric Andersen62483552001-07-10 06:09:16 +00002939/*
2940 * Evaluate a parse tree. The value is left in the global variable
2941 * exitstatus.
2942 */
2943static void
2944evaltree(n, flags)
2945 union node *n;
2946 int flags;
2947{
2948 int checkexit = 0;
2949 if (n == NULL) {
2950 TRACE(("evaltree(NULL) called\n"));
2951 goto out;
2952 }
2953 TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
2954 switch (n->type) {
2955 case NSEMI:
2956 evaltree(n->nbinary.ch1, flags & EV_TESTED);
2957 if (evalskip)
2958 goto out;
2959 evaltree(n->nbinary.ch2, flags);
2960 break;
2961 case NAND:
2962 evaltree(n->nbinary.ch1, EV_TESTED);
2963 if (evalskip || exitstatus != 0)
2964 goto out;
2965 evaltree(n->nbinary.ch2, flags);
2966 break;
2967 case NOR:
2968 evaltree(n->nbinary.ch1, EV_TESTED);
2969 if (evalskip || exitstatus == 0)
2970 goto out;
2971 evaltree(n->nbinary.ch2, flags);
2972 break;
2973 case NREDIR:
2974 expredir(n->nredir.redirect);
2975 redirect(n->nredir.redirect, REDIR_PUSH);
2976 evaltree(n->nredir.n, flags);
2977 popredir();
2978 break;
2979 case NSUBSHELL:
2980 evalsubshell(n, flags);
2981 break;
2982 case NBACKGND:
2983 evalsubshell(n, flags);
2984 break;
2985 case NIF: {
2986 evaltree(n->nif.test, EV_TESTED);
2987 if (evalskip)
2988 goto out;
2989 if (exitstatus == 0)
2990 evaltree(n->nif.ifpart, flags);
2991 else if (n->nif.elsepart)
2992 evaltree(n->nif.elsepart, flags);
2993 else
2994 exitstatus = 0;
2995 break;
2996 }
2997 case NWHILE:
2998 case NUNTIL:
2999 evalloop(n, flags);
3000 break;
3001 case NFOR:
3002 evalfor(n, flags);
3003 break;
3004 case NCASE:
3005 evalcase(n, flags);
3006 break;
3007 case NDEFUN: {
3008 struct builtincmd *bcmd;
3009 struct cmdentry entry;
3010 if (
3011 (bcmd = find_builtin(n->narg.text)) &&
3012 IS_BUILTIN_SPECIAL(bcmd)
3013 ) {
3014 out2fmt("%s is a special built-in\n", n->narg.text);
3015 exitstatus = 1;
3016 break;
3017 }
3018 entry.cmdtype = CMDFUNCTION;
3019 entry.u.func = copyfunc(n->narg.next);
3020 addcmdentry(n->narg.text, &entry);
3021 exitstatus = 0;
3022 break;
3023 }
3024 case NNOT:
3025 evaltree(n->nnot.com, EV_TESTED);
3026 exitstatus = !exitstatus;
3027 break;
Eric Andersencb57d552001-06-28 07:25:16 +00003028
Eric Andersen62483552001-07-10 06:09:16 +00003029 case NPIPE:
3030 evalpipe(n);
3031 checkexit = 1;
3032 break;
3033 case NCMD:
3034 evalcommand(n, flags);
3035 checkexit = 1;
3036 break;
3037#ifdef DEBUG
3038 default:
3039 printf("Node type = %d\n", n->type);
3040 break;
3041#endif
3042 }
3043out:
3044 if (pendingsigs)
3045 dotrap();
3046 if (
3047 flags & EV_EXIT ||
3048 (checkexit && eflag && exitstatus && !(flags & EV_TESTED))
3049 )
3050 exitshell(exitstatus);
3051}
3052
3053/*
3054 * Kick off a subshell to evaluate a tree.
3055 */
3056
3057static void
3058evalsubshell(const union node *n, int flags)
3059{
3060 struct job *jp;
3061 int backgnd = (n->type == NBACKGND);
3062
3063 expredir(n->nredir.redirect);
3064 jp = makejob(n, 1);
3065 if (forkshell(jp, n, backgnd) == 0) {
3066 if (backgnd)
3067 flags &=~ EV_TESTED;
3068 redirect(n->nredir.redirect, 0);
3069 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
3070 }
3071 if (! backgnd) {
3072 INTOFF;
3073 exitstatus = waitforjob(jp);
3074 INTON;
3075 }
3076}
3077
3078/*
3079 * Compute the names of the files in a redirection list.
3080 */
3081
3082static void fixredir(union node *n, const char *text, int err);
3083
3084static void
3085expredir(union node *n)
3086{
3087 union node *redir;
3088
3089 for (redir = n ; redir ; redir = redir->nfile.next) {
3090 struct arglist fn;
3091 fn.lastp = &fn.list;
3092 oexitstatus = exitstatus;
3093 switch (redir->type) {
3094 case NFROMTO:
3095 case NFROM:
3096 case NTO:
3097 case NAPPEND:
3098 case NTOOV:
3099 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3100 redir->nfile.expfname = fn.list->text;
3101 break;
3102 case NFROMFD:
3103 case NTOFD:
3104 if (redir->ndup.vname) {
3105 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3106 fixredir(redir, fn.list->text, 1);
3107 }
3108 break;
3109 }
3110 }
3111}
3112
3113
3114/*
3115 * Execute a command inside back quotes. If it's a builtin command, we
3116 * want to save its output in a block obtained from malloc. Otherwise
3117 * we fork off a subprocess and get the output of the command via a pipe.
3118 * Should be called with interrupts off.
3119 */
3120
3121static void
3122evalbackcmd(union node *n, struct backcmd *result)
3123{
3124 int pip[2];
3125 struct job *jp;
3126 struct stackmark smark; /* unnecessary */
3127
3128 setstackmark(&smark);
3129 result->fd = -1;
3130 result->buf = NULL;
3131 result->nleft = 0;
3132 result->jp = NULL;
3133 if (n == NULL) {
3134 exitstatus = 0;
3135 goto out;
3136 }
3137 exitstatus = 0;
3138 if (pipe(pip) < 0)
3139 error("Pipe call failed");
3140 jp = makejob(n, 1);
3141 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3142 FORCEINTON;
3143 close(pip[0]);
3144 if (pip[1] != 1) {
3145 close(1);
3146 dup_as_newfd(pip[1], 1);
3147 close(pip[1]);
3148 }
3149 eflag = 0;
3150 evaltree(n, EV_EXIT);
3151 }
3152 close(pip[1]);
3153 result->fd = pip[0];
3154 result->jp = jp;
3155out:
3156 popstackmark(&smark);
3157 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
3158 result->fd, result->buf, result->nleft, result->jp));
3159}
3160
3161
3162/*
3163 * Execute a simple command.
3164 */
Eric Andersencb57d552001-06-28 07:25:16 +00003165
3166/*
3167 * Search for a command. This is called before we fork so that the
3168 * location of the command will be available in the parent as well as
3169 * the child. The check for "goodname" is an overly conservative
3170 * check that the name will not be subject to expansion.
3171 */
3172
3173static void
3174prehash(n)
3175 union node *n;
3176{
3177 struct cmdentry entry;
3178
3179 if (n->type == NCMD && n->ncmd.args)
3180 if (goodname(n->ncmd.args->narg.text))
3181 find_command(n->ncmd.args->narg.text, &entry, 0,
3182 pathval());
3183}
3184
3185
Eric Andersencb57d552001-06-28 07:25:16 +00003186/*
3187 * Builtin commands. Builtin commands whose functions are closely
3188 * tied to evaluation are implemented here.
3189 */
3190
3191/*
3192 * No command given, or a bltin command with no arguments. Set the
3193 * specified variables.
3194 */
3195
3196int
3197bltincmd(argc, argv)
3198 int argc;
3199 char **argv;
3200{
3201 /*
3202 * Preserve exitstatus of a previous possible redirection
3203 * as POSIX mandates
3204 */
3205 return exitstatus;
3206}
3207
3208
3209/*
3210 * Handle break and continue commands. Break, continue, and return are
3211 * all handled by setting the evalskip flag. The evaluation routines
3212 * above all check this flag, and if it is set they start skipping
3213 * commands rather than executing them. The variable skipcount is
3214 * the number of loops to break/continue, or the number of function
3215 * levels to return. (The latter is always 1.) It should probably
3216 * be an error to break out of more loops than exist, but it isn't
3217 * in the standard shell so we don't make it one here.
3218 */
3219
3220static int
3221breakcmd(argc, argv)
3222 int argc;
3223 char **argv;
3224{
3225 int n = argc > 1 ? number(argv[1]) : 1;
3226
3227 if (n > loopnest)
3228 n = loopnest;
3229 if (n > 0) {
3230 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
3231 skipcount = n;
3232 }
3233 return 0;
3234}
3235
3236
3237/*
3238 * The return command.
3239 */
3240
3241static int
3242returncmd(argc, argv)
3243 int argc;
3244 char **argv;
3245{
3246 int ret = argc > 1 ? number(argv[1]) : oexitstatus;
3247
3248 if (funcnest) {
3249 evalskip = SKIPFUNC;
3250 skipcount = 1;
3251 return ret;
3252 }
3253 else {
3254 /* Do what ksh does; skip the rest of the file */
3255 evalskip = SKIPFILE;
3256 skipcount = 1;
3257 return ret;
3258 }
3259}
3260
3261
3262#ifndef BB_TRUE_FALSE
3263static int
3264false_main(argc, argv)
3265 int argc;
3266 char **argv;
3267{
3268 return 1;
3269}
3270
3271
3272static int
3273true_main(argc, argv)
3274 int argc;
3275 char **argv;
3276{
3277 return 0;
3278}
3279#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003280
3281/*
3282 * Controls whether the shell is interactive or not.
3283 */
3284
3285static void setsignal(int signo);
3286static void chkmail(int silent);
3287
3288
3289static void
3290setinteractive(int on)
3291{
3292 static int is_interactive;
Eric Andersen1c039232001-07-07 00:05:55 +00003293 static int do_banner=0;
Eric Andersen2870d962001-07-02 17:27:21 +00003294
3295 if (on == is_interactive)
3296 return;
3297 setsignal(SIGINT);
3298 setsignal(SIGQUIT);
3299 setsignal(SIGTERM);
3300 chkmail(1);
3301 is_interactive = on;
Eric Andersen1c039232001-07-07 00:05:55 +00003302 if (do_banner==0 && is_interactive) {
3303 /* Looks like they want an interactive shell */
3304 printf( "\n\n" BB_BANNER " Built-in shell (ash)\n");
3305 printf( "Enter 'help' for a list of built-in commands.\n\n");
3306 do_banner=1;
3307 }
Eric Andersen2870d962001-07-02 17:27:21 +00003308}
3309
3310static void
3311optschanged(void)
3312{
3313 setinteractive(iflag);
3314 setjobctl(mflag);
3315}
3316
Eric Andersencb57d552001-06-28 07:25:16 +00003317
3318static int
3319execcmd(argc, argv)
3320 int argc;
3321 char **argv;
3322{
3323 if (argc > 1) {
3324 struct strlist *sp;
3325
Eric Andersen2870d962001-07-02 17:27:21 +00003326 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003327 mflag = 0;
3328 optschanged();
3329 for (sp = cmdenviron; sp ; sp = sp->next)
3330 setvareq(sp->text, VEXPORT|VSTACK);
3331 shellexec(argv + 1, environment(), pathval(), 0);
3332 }
3333 return 0;
3334}
3335
3336static void
3337eprintlist(struct strlist *sp)
3338{
3339 for (; sp; sp = sp->next) {
Eric Andersen3102ac42001-07-06 04:26:23 +00003340 out2fmt(" %s",sp->text);
Eric Andersencb57d552001-06-28 07:25:16 +00003341 }
3342}
Eric Andersencb57d552001-06-28 07:25:16 +00003343
3344/*
3345 * Exec a program. Never returns. If you change this routine, you may
3346 * have to change the find_command routine as well.
3347 */
3348
Eric Andersen2870d962001-07-02 17:27:21 +00003349static const char *pathopt; /* set by padvance */
3350
Eric Andersencb57d552001-06-28 07:25:16 +00003351static void
3352shellexec(argv, envp, path, idx)
3353 char **argv, **envp;
3354 const char *path;
3355 int idx;
3356{
3357 char *cmdname;
3358 int e;
3359
3360 if (strchr(argv[0], '/') != NULL) {
3361 tryexec(argv[0], argv, envp);
3362 e = errno;
3363 } else {
3364 e = ENOENT;
3365 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3366 if (--idx < 0 && pathopt == NULL) {
3367 tryexec(cmdname, argv, envp);
3368 if (errno != ENOENT && errno != ENOTDIR)
3369 e = errno;
3370 }
3371 stunalloc(cmdname);
3372 }
3373 }
3374
3375 /* Map to POSIX errors */
3376 switch (e) {
3377 case EACCES:
3378 exerrno = 126;
3379 break;
3380 case ENOENT:
3381 exerrno = 127;
3382 break;
3383 default:
3384 exerrno = 2;
3385 break;
3386 }
3387 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3388 /* NOTREACHED */
3389}
3390
Eric Andersen2870d962001-07-02 17:27:21 +00003391/*
3392 * Clear traps on a fork.
3393 */
3394static void
3395clear_traps(void) {
3396 char **tp;
3397
3398 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
3399 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
3400 INTOFF;
3401 ckfree(*tp);
3402 *tp = NULL;
3403 if (tp != &trap[0])
3404 setsignal(tp - trap);
3405 INTON;
3406 }
3407 }
3408}
3409
3410
3411static void
3412initshellproc(void) {
3413
3414#ifdef ASH_ALIAS
3415 /* from alias.c: */
3416 {
3417 rmaliases();
3418 }
3419#endif
3420 /* from eval.c: */
3421 {
3422 exitstatus = 0;
3423 }
3424
3425 /* from exec.c: */
3426 {
3427 deletefuncs();
3428 }
3429
3430 /* from jobs.c: */
3431 {
3432 backgndpid = -1;
3433#ifdef JOBS
3434 jobctl = 0;
3435#endif
3436 }
3437
3438 /* from options.c: */
3439 {
3440 int i;
3441
3442 for (i = 0; i < NOPTS; i++)
3443 optent_val(i) = 0;
3444 optschanged();
3445
3446 }
3447
3448 /* from redir.c: */
3449 {
3450 clearredir();
3451 }
3452
3453 /* from trap.c: */
3454 {
3455 char *sm;
3456
3457 clear_traps();
3458 for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) {
3459 if (*sm == S_IGN)
3460 *sm = S_HARD_IGN;
3461 }
3462 }
3463
3464 /* from var.c: */
3465 {
3466 shprocvar();
3467 }
3468}
3469
3470static int preadbuffer(void);
3471static void pushfile (void);
Eric Andersen2870d962001-07-02 17:27:21 +00003472
3473/*
3474 * Read a character from the script, returning PEOF on end of file.
3475 * Nul characters in the input are silently discarded.
3476 */
3477
Eric Andersen3102ac42001-07-06 04:26:23 +00003478#ifndef ASH_OPTIMIZE_FOR_SIZE
Eric Andersen2870d962001-07-02 17:27:21 +00003479#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
3480static int
3481pgetc(void)
3482{
3483 return pgetc_macro();
3484}
3485#else
3486static int
3487pgetc_macro(void)
3488{
3489 return --parsenleft >= 0? *parsenextc++ : preadbuffer();
3490}
3491
3492static inline int
3493pgetc(void)
3494{
3495 return pgetc_macro();
3496}
3497#endif
3498
3499
3500/*
3501 * Undo the last call to pgetc. Only one character may be pushed back.
3502 * PEOF may be pushed back.
3503 */
3504
3505static void
3506pungetc() {
3507 parsenleft++;
3508 parsenextc--;
3509}
3510
3511
3512static void
3513popfile(void) {
3514 struct parsefile *pf = parsefile;
3515
3516 INTOFF;
3517 if (pf->fd >= 0)
3518 close(pf->fd);
3519 if (pf->buf)
3520 ckfree(pf->buf);
3521 while (pf->strpush)
3522 popstring();
3523 parsefile = pf->prev;
3524 ckfree(pf);
3525 parsenleft = parsefile->nleft;
3526 parselleft = parsefile->lleft;
3527 parsenextc = parsefile->nextc;
3528 plinno = parsefile->linno;
3529 INTON;
3530}
3531
3532
3533/*
3534 * Return to top level.
3535 */
3536
3537static void
3538popallfiles(void) {
3539 while (parsefile != &basepf)
3540 popfile();
3541}
3542
3543/*
3544 * Close the file(s) that the shell is reading commands from. Called
3545 * after a fork is done.
3546 */
3547
3548static void
3549closescript() {
3550 popallfiles();
3551 if (parsefile->fd > 0) {
3552 close(parsefile->fd);
3553 parsefile->fd = 0;
3554 }
3555}
3556
3557
3558/*
3559 * Like setinputfile, but takes an open file descriptor. Call this with
3560 * interrupts off.
3561 */
3562
3563static void
3564setinputfd(fd, push)
3565 int fd, push;
3566{
3567 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
3568 if (push) {
3569 pushfile();
3570 parsefile->buf = 0;
3571 } else {
3572 closescript();
3573 while (parsefile->strpush)
3574 popstring();
3575 }
3576 parsefile->fd = fd;
3577 if (parsefile->buf == NULL)
3578 parsefile->buf = ckmalloc(BUFSIZ);
3579 parselleft = parsenleft = 0;
3580 plinno = 1;
3581}
3582
3583
3584/*
3585 * Set the input to take input from a file. If push is set, push the
3586 * old input onto the stack first.
3587 */
3588
3589static void
3590setinputfile(const char *fname, int push)
3591{
3592 int fd;
3593 int myfileno2;
3594
3595 INTOFF;
3596 if ((fd = open(fname, O_RDONLY)) < 0)
3597 error("Can't open %s", fname);
3598 if (fd < 10) {
3599 myfileno2 = dup_as_newfd(fd, 10);
3600 close(fd);
3601 if (myfileno2 < 0)
3602 error("Out of file descriptors");
3603 fd = myfileno2;
3604 }
3605 setinputfd(fd, push);
3606 INTON;
3607}
3608
Eric Andersencb57d552001-06-28 07:25:16 +00003609
3610static void
Eric Andersen62483552001-07-10 06:09:16 +00003611tryexec(char *cmd, char **argv, char **envp)
3612{
Eric Andersencb57d552001-06-28 07:25:16 +00003613 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003614
Eric Andersen3102ac42001-07-06 04:26:23 +00003615#ifdef BB_FEATURE_SH_STANDALONE_SHELL
3616 char *name = cmd;
3617 char** argv_l=argv;
3618 int argc_l;
3619#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
3620 name = get_last_path_component(name);
3621#endif
3622 argv_l=envp;
3623 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
3624 putenv(*argv_l);
3625 argv_l=argv;
Eric Andersen62483552001-07-10 06:09:16 +00003626 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
Eric Andersen3102ac42001-07-06 04:26:23 +00003627 optind = 1;
3628 run_applet_by_name(name, argc_l, argv);
3629#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003630 execve(cmd, argv, envp);
Eric Andersencb57d552001-06-28 07:25:16 +00003631 e = errno;
3632 if (e == ENOEXEC) {
3633 INTOFF;
3634 initshellproc();
3635 setinputfile(cmd, 0);
3636 commandname = arg0 = savestr(argv[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00003637 setparam(argv + 1);
3638 exraise(EXSHELLPROC);
3639 }
3640 errno = e;
3641}
3642
Eric Andersen2870d962001-07-02 17:27:21 +00003643static char *commandtext (const union node *);
Eric Andersencb57d552001-06-28 07:25:16 +00003644
3645/*
3646 * Do a path search. The variable path (passed by reference) should be
3647 * set to the start of the path before the first call; padvance will update
3648 * this value as it proceeds. Successive calls to padvance will return
3649 * the possible path expansions in sequence. If an option (indicated by
3650 * a percent sign) appears in the path entry then the global variable
3651 * pathopt will be set to point to it; otherwise pathopt will be set to
3652 * NULL.
3653 */
3654
3655static const char *pathopt;
3656
Eric Andersen2870d962001-07-02 17:27:21 +00003657static void growstackblock(void);
3658
3659
Eric Andersencb57d552001-06-28 07:25:16 +00003660static char *
Eric Andersen2870d962001-07-02 17:27:21 +00003661padvance(const char **path, const char *name)
3662{
Eric Andersencb57d552001-06-28 07:25:16 +00003663 const char *p;
3664 char *q;
3665 const char *start;
3666 int len;
3667
3668 if (*path == NULL)
3669 return NULL;
3670 start = *path;
3671 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
Eric Andersen2870d962001-07-02 17:27:21 +00003672 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003673 while (stackblocksize() < len)
3674 growstackblock();
3675 q = stackblock();
3676 if (p != start) {
3677 memcpy(q, start, p - start);
3678 q += p - start;
3679 *q++ = '/';
3680 }
3681 strcpy(q, name);
3682 pathopt = NULL;
3683 if (*p == '%') {
3684 pathopt = ++p;
3685 while (*p && *p != ':') p++;
3686 }
3687 if (*p == ':')
3688 *path = p + 1;
3689 else
3690 *path = NULL;
3691 return stalloc(len);
3692}
3693
Eric Andersen62483552001-07-10 06:09:16 +00003694/*
3695 * Wrapper around strcmp for qsort/bsearch/...
3696 */
3697static int
3698pstrcmp(const void *a, const void *b)
3699{
3700 return strcmp((const char *) a, *(const char *const *) b);
3701}
3702
3703/*
3704 * Find a keyword is in a sorted array.
3705 */
3706
3707static const char *const *
3708findkwd(const char *s)
3709{
3710 return bsearch(s, parsekwd, sizeof(parsekwd) / sizeof(const char *),
3711 sizeof(const char *), pstrcmp);
3712}
Eric Andersencb57d552001-06-28 07:25:16 +00003713
3714
3715/*** Command hashing code ***/
3716
3717
3718static int
3719hashcmd(argc, argv)
3720 int argc;
3721 char **argv;
3722{
3723 struct tblentry **pp;
3724 struct tblentry *cmdp;
3725 int c;
3726 int verbose;
3727 struct cmdentry entry;
3728 char *name;
Eric Andersen62483552001-07-10 06:09:16 +00003729#ifdef ASH_ALIAS
3730 const struct alias *ap;
3731#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003732
3733 verbose = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003734 while ((c = nextopt("rvV")) != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00003735 if (c == 'r') {
3736 clearcmdentry(0);
3737 return 0;
Eric Andersen62483552001-07-10 06:09:16 +00003738 } else if (c == 'v' || c == 'V') {
3739 verbose = c;
Eric Andersencb57d552001-06-28 07:25:16 +00003740 }
3741 }
3742 if (*argptr == NULL) {
3743 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3744 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3745 if (cmdp->cmdtype != CMDBUILTIN) {
3746 printentry(cmdp, verbose);
3747 }
3748 }
3749 }
3750 return 0;
3751 }
3752 c = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003753 while ((name = *argptr++) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00003754 if ((cmdp = cmdlookup(name, 0)) != NULL
3755 && (cmdp->cmdtype == CMDNORMAL
3756 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3757 delete_cmd_entry();
Eric Andersen62483552001-07-10 06:09:16 +00003758#ifdef ASH_ALIAS
3759 /* Then look at the aliases */
3760 if ((ap = lookupalias(name, 0)) != NULL) {
3761 if (verbose=='v')
3762 printf("%s is an alias for %s\n", name, ap->val);
3763 else
3764 printalias(ap);
3765 continue;
3766 }
3767#endif
3768 /* First look at the keywords */
3769 if (findkwd(name)!=0) {
3770 if (verbose=='v')
3771 printf("%s is a shell keyword\n", name);
3772 else
3773 printf(snlfmt, name);
3774 continue;
3775 }
3776
Eric Andersencb57d552001-06-28 07:25:16 +00003777 find_command(name, &entry, DO_ERR, pathval());
3778 if (entry.cmdtype == CMDUNKNOWN) c = 1;
3779 else if (verbose) {
3780 cmdp = cmdlookup(name, 0);
Eric Andersen62483552001-07-10 06:09:16 +00003781 if (cmdp) printentry(cmdp, verbose=='v');
Eric Andersencb57d552001-06-28 07:25:16 +00003782 flushall();
3783 }
Eric Andersencb57d552001-06-28 07:25:16 +00003784 }
3785 return c;
3786}
3787
Eric Andersencb57d552001-06-28 07:25:16 +00003788static void
3789printentry(cmdp, verbose)
3790 struct tblentry *cmdp;
3791 int verbose;
3792 {
3793 int idx;
3794 const char *path;
3795 char *name;
3796
Eric Andersen62483552001-07-10 06:09:16 +00003797 printf("%s%s", cmdp->cmdname, (verbose ? " is " : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00003798 if (cmdp->cmdtype == CMDNORMAL) {
3799 idx = cmdp->param.index;
3800 path = pathval();
3801 do {
3802 name = padvance(&path, cmdp->cmdname);
3803 stunalloc(name);
3804 } while (--idx >= 0);
Eric Andersen62483552001-07-10 06:09:16 +00003805 if(verbose)
3806 out1str(name);
Eric Andersencb57d552001-06-28 07:25:16 +00003807 } else if (cmdp->cmdtype == CMDBUILTIN) {
Eric Andersen62483552001-07-10 06:09:16 +00003808 if(verbose)
3809 out1str("a shell builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00003810 } else if (cmdp->cmdtype == CMDFUNCTION) {
Eric Andersencb57d552001-06-28 07:25:16 +00003811 if (verbose) {
3812 INTOFF;
Eric Andersen62483552001-07-10 06:09:16 +00003813 out1str("a function\n");
Eric Andersencb57d552001-06-28 07:25:16 +00003814 name = commandtext(cmdp->param.func);
Eric Andersen62483552001-07-10 06:09:16 +00003815 printf("%s() {\n %s\n}", cmdp->cmdname, name);
Eric Andersencb57d552001-06-28 07:25:16 +00003816 ckfree(name);
3817 INTON;
3818 }
3819#ifdef DEBUG
3820 } else {
3821 error("internal error: cmdtype %d", cmdp->cmdtype);
3822#endif
3823 }
Eric Andersen62483552001-07-10 06:09:16 +00003824 printf(snlfmt, cmdp->rehash ? "*" : nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +00003825}
3826
3827
3828
Eric Andersen1c039232001-07-07 00:05:55 +00003829/*** List the available builtins ***/
3830
3831
3832static int helpcmd(int argc, char** argv)
3833{
3834 int col, i;
Eric Andersen1c039232001-07-07 00:05:55 +00003835
Eric Andersen62483552001-07-10 06:09:16 +00003836 printf("\nBuilt-in commands:\n-------------------\n");
3837 for (col=0, i=0; i < NUMBUILTINS; i++) {
3838 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3839 builtincmds[i].name+1);
Eric Andersen1c039232001-07-07 00:05:55 +00003840 if (col > 60) {
3841 printf("\n");
3842 col = 0;
3843 }
3844 }
3845#ifdef BB_FEATURE_SH_STANDALONE_SHELL
3846 {
Eric Andersen1c039232001-07-07 00:05:55 +00003847 extern const struct BB_applet applets[];
3848 extern const size_t NUM_APPLETS;
3849
Eric Andersen62483552001-07-10 06:09:16 +00003850 for (i=0; i < NUM_APPLETS; i++) {
3851
3852 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3853 applets[i].name);
Eric Andersen1c039232001-07-07 00:05:55 +00003854 if (col > 60) {
3855 printf("\n");
3856 col = 0;
3857 }
3858 }
3859 }
3860#endif
3861 printf("\n\n");
3862 return EXIT_SUCCESS;
3863}
3864
Eric Andersencb57d552001-06-28 07:25:16 +00003865/*
3866 * Resolve a command name. If you change this routine, you may have to
3867 * change the shellexec routine as well.
3868 */
3869
Eric Andersen2870d962001-07-02 17:27:21 +00003870static int prefix (const char *, const char *);
3871
Eric Andersencb57d552001-06-28 07:25:16 +00003872static void
Eric Andersen2870d962001-07-02 17:27:21 +00003873find_command(const char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003874{
3875 struct tblentry *cmdp;
3876 int idx;
3877 int prev;
3878 char *fullname;
3879 struct stat statb;
3880 int e;
3881 int bltin;
3882 int firstchange;
3883 int updatetbl;
Eric Andersen62483552001-07-10 06:09:16 +00003884 int regular;
Eric Andersencb57d552001-06-28 07:25:16 +00003885 struct builtincmd *bcmd;
3886
3887 /* If name contains a slash, don't use the hash table */
3888 if (strchr(name, '/') != NULL) {
3889 if (act & DO_ABS) {
3890 while (stat(name, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003891 if (errno != ENOENT && errno != ENOTDIR)
3892 e = errno;
3893 entry->cmdtype = CMDUNKNOWN;
3894 entry->u.index = -1;
3895 return;
3896 }
3897 entry->cmdtype = CMDNORMAL;
3898 entry->u.index = -1;
3899 return;
3900 }
3901 entry->cmdtype = CMDNORMAL;
3902 entry->u.index = 0;
3903 return;
3904 }
3905
3906 updatetbl = 1;
3907 if (act & DO_BRUTE) {
3908 firstchange = path_change(path, &bltin);
3909 } else {
3910 bltin = builtinloc;
3911 firstchange = 9999;
3912 }
3913
3914 /* If name is in the table, and not invalidated by cd, we're done */
3915 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
3916 if (cmdp->cmdtype == CMDFUNCTION) {
3917 if (act & DO_NOFUN) {
3918 updatetbl = 0;
3919 } else {
3920 goto success;
3921 }
3922 } else if (act & DO_BRUTE) {
3923 if ((cmdp->cmdtype == CMDNORMAL &&
3924 cmdp->param.index >= firstchange) ||
3925 (cmdp->cmdtype == CMDBUILTIN &&
3926 ((builtinloc < 0 && bltin >= 0) ?
3927 bltin : builtinloc) >= firstchange)) {
3928 /* need to recompute the entry */
3929 } else {
3930 goto success;
3931 }
3932 } else {
3933 goto success;
3934 }
3935 }
3936
3937 bcmd = find_builtin(name);
Eric Andersen2870d962001-07-02 17:27:21 +00003938 regular = bcmd && IS_BUILTIN_REGULAR(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00003939
3940 if (regular) {
3941 if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) {
Eric Andersen2870d962001-07-02 17:27:21 +00003942 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003943 }
3944 } else if (act & DO_BRUTE) {
3945 if (firstchange == 0) {
3946 updatetbl = 0;
3947 }
3948 }
3949
3950 /* If %builtin not in path, check for builtin next */
3951 if (regular || (bltin < 0 && bcmd)) {
3952builtin:
3953 if (!updatetbl) {
3954 entry->cmdtype = CMDBUILTIN;
3955 entry->u.cmd = bcmd;
3956 return;
3957 }
3958 INTOFF;
3959 cmdp = cmdlookup(name, 1);
3960 cmdp->cmdtype = CMDBUILTIN;
3961 cmdp->param.cmd = bcmd;
3962 INTON;
3963 goto success;
3964 }
3965
3966 /* We have to search path. */
Eric Andersen2870d962001-07-02 17:27:21 +00003967 prev = -1; /* where to start */
3968 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00003969 if (cmdp->cmdtype == CMDBUILTIN)
3970 prev = builtinloc;
3971 else
3972 prev = cmdp->param.index;
3973 }
3974
3975 e = ENOENT;
3976 idx = -1;
3977loop:
3978 while ((fullname = padvance(&path, name)) != NULL) {
3979 stunalloc(fullname);
3980 idx++;
3981 if (idx >= firstchange) {
3982 updatetbl = 0;
3983 }
3984 if (pathopt) {
3985 if (prefix("builtin", pathopt)) {
3986 if ((bcmd = find_builtin(name))) {
3987 goto builtin;
3988 }
3989 continue;
3990 } else if (!(act & DO_NOFUN) &&
3991 prefix("func", pathopt)) {
3992 /* handled below */
3993 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00003994 continue; /* ignore unimplemented options */
Eric Andersencb57d552001-06-28 07:25:16 +00003995 }
3996 }
3997 /* if rehash, don't redo absolute path names */
3998 if (fullname[0] == '/' && idx <= prev &&
3999 idx < firstchange) {
4000 if (idx < prev)
4001 continue;
4002 TRACE(("searchexec \"%s\": no change\n", name));
4003 goto success;
4004 }
4005 while (stat(fullname, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00004006 if (errno != ENOENT && errno != ENOTDIR)
4007 e = errno;
4008 goto loop;
4009 }
Eric Andersen2870d962001-07-02 17:27:21 +00004010 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00004011 if (!S_ISREG(statb.st_mode))
4012 continue;
Eric Andersen2870d962001-07-02 17:27:21 +00004013 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00004014 stalloc(strlen(fullname) + 1);
4015 readcmdfile(fullname);
4016 if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
4017 error("%s not defined in %s", name, fullname);
4018 stunalloc(fullname);
4019 goto success;
4020 }
Eric Andersencb57d552001-06-28 07:25:16 +00004021 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
4022 /* If we aren't called with DO_BRUTE and cmdp is set, it must
4023 be a function and we're being called with DO_NOFUN */
4024 if (!updatetbl) {
4025 entry->cmdtype = CMDNORMAL;
4026 entry->u.index = idx;
4027 return;
4028 }
4029 INTOFF;
4030 cmdp = cmdlookup(name, 1);
4031 cmdp->cmdtype = CMDNORMAL;
4032 cmdp->param.index = idx;
4033 INTON;
4034 goto success;
4035 }
4036
4037 /* We failed. If there was an entry for this command, delete it */
4038 if (cmdp && updatetbl)
4039 delete_cmd_entry();
4040 if (act & DO_ERR)
Eric Andersen3102ac42001-07-06 04:26:23 +00004041 out2fmt("%s: %s\n", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00004042 entry->cmdtype = CMDUNKNOWN;
4043 return;
4044
4045success:
4046 cmdp->rehash = 0;
4047 entry->cmdtype = cmdp->cmdtype;
4048 entry->u = cmdp->param;
4049}
4050
4051
4052
4053/*
4054 * Search the table of builtin commands.
4055 */
4056
Eric Andersen2870d962001-07-02 17:27:21 +00004057static int
4058bstrcmp(const void *name, const void *b)
4059{
4060 return strcmp((const char *)name, (*(const char *const *) b)+1);
4061}
4062
4063static struct builtincmd *
4064find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00004065{
4066 struct builtincmd *bp;
4067
Eric Andersen2870d962001-07-02 17:27:21 +00004068 bp = bsearch(name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd),
4069 bstrcmp
Eric Andersencb57d552001-06-28 07:25:16 +00004070 );
4071 return bp;
4072}
4073
4074
4075/*
4076 * Called when a cd is done. Marks all commands so the next time they
4077 * are executed they will be rehashed.
4078 */
4079
4080static void
Eric Andersen2870d962001-07-02 17:27:21 +00004081hashcd(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00004082 struct tblentry **pp;
4083 struct tblentry *cmdp;
4084
4085 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4086 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4087 if (cmdp->cmdtype == CMDNORMAL
4088 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
4089 cmdp->rehash = 1;
4090 }
4091 }
4092}
4093
4094
4095
4096/*
4097 * Called before PATH is changed. The argument is the new value of PATH;
4098 * pathval() still returns the old value at this point. Called with
4099 * interrupts off.
4100 */
4101
4102static void
Eric Andersen2870d962001-07-02 17:27:21 +00004103changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00004104{
4105 int firstchange;
4106 int bltin;
4107
4108 firstchange = path_change(newval, &bltin);
4109 if (builtinloc < 0 && bltin >= 0)
Eric Andersen2870d962001-07-02 17:27:21 +00004110 builtinloc = bltin; /* zap builtins */
Eric Andersencb57d552001-06-28 07:25:16 +00004111 clearcmdentry(firstchange);
4112 builtinloc = bltin;
4113}
4114
4115
4116/*
4117 * Clear out command entries. The argument specifies the first entry in
4118 * PATH which has changed.
4119 */
4120
4121static void
4122clearcmdentry(firstchange)
4123 int firstchange;
4124{
4125 struct tblentry **tblp;
4126 struct tblentry **pp;
4127 struct tblentry *cmdp;
4128
4129 INTOFF;
4130 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4131 pp = tblp;
4132 while ((cmdp = *pp) != NULL) {
4133 if ((cmdp->cmdtype == CMDNORMAL &&
4134 cmdp->param.index >= firstchange)
4135 || (cmdp->cmdtype == CMDBUILTIN &&
4136 builtinloc >= firstchange)) {
4137 *pp = cmdp->next;
4138 ckfree(cmdp);
4139 } else {
4140 pp = &cmdp->next;
4141 }
4142 }
4143 }
4144 INTON;
4145}
4146
4147
4148/*
4149 * Delete all functions.
4150 */
4151
Eric Andersencb57d552001-06-28 07:25:16 +00004152static void
Eric Andersen2870d962001-07-02 17:27:21 +00004153deletefuncs(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00004154 struct tblentry **tblp;
4155 struct tblentry **pp;
4156 struct tblentry *cmdp;
4157
4158 INTOFF;
4159 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4160 pp = tblp;
4161 while ((cmdp = *pp) != NULL) {
4162 if (cmdp->cmdtype == CMDFUNCTION) {
4163 *pp = cmdp->next;
4164 freefunc(cmdp->param.func);
4165 ckfree(cmdp);
4166 } else {
4167 pp = &cmdp->next;
4168 }
4169 }
4170 }
4171 INTON;
4172}
4173
4174
4175
4176/*
4177 * Locate a command in the command hash table. If "add" is nonzero,
4178 * add the command to the table if it is not already present. The
4179 * variable "lastcmdentry" is set to point to the address of the link
4180 * pointing to the entry, so that delete_cmd_entry can delete the
4181 * entry.
4182 */
4183
Eric Andersen2870d962001-07-02 17:27:21 +00004184static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00004185
4186static struct tblentry *
Eric Andersen2870d962001-07-02 17:27:21 +00004187cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00004188{
4189 int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00004190 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00004191 struct tblentry *cmdp;
4192 struct tblentry **pp;
4193
4194 p = name;
4195 hashval = *p << 4;
4196 while (*p)
4197 hashval += *p++;
4198 hashval &= 0x7FFF;
4199 pp = &cmdtable[hashval % CMDTABLESIZE];
4200 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4201 if (equal(cmdp->cmdname, name))
4202 break;
4203 pp = &cmdp->next;
4204 }
4205 if (add && cmdp == NULL) {
4206 INTOFF;
4207 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4208 + strlen(name) + 1);
4209 cmdp->next = NULL;
4210 cmdp->cmdtype = CMDUNKNOWN;
4211 cmdp->rehash = 0;
4212 strcpy(cmdp->cmdname, name);
4213 INTON;
4214 }
4215 lastcmdentry = pp;
4216 return cmdp;
4217}
4218
4219/*
4220 * Delete the command entry returned on the last lookup.
4221 */
4222
4223static void
4224delete_cmd_entry() {
4225 struct tblentry *cmdp;
4226
4227 INTOFF;
4228 cmdp = *lastcmdentry;
4229 *lastcmdentry = cmdp->next;
4230 ckfree(cmdp);
4231 INTON;
4232}
4233
4234
4235
Eric Andersencb57d552001-06-28 07:25:16 +00004236
4237
Eric Andersen62483552001-07-10 06:09:16 +00004238static const short nodesize[26] = {
4239 ALIGN(sizeof (struct nbinary)),
4240 ALIGN(sizeof (struct ncmd)),
4241 ALIGN(sizeof (struct npipe)),
4242 ALIGN(sizeof (struct nredir)),
4243 ALIGN(sizeof (struct nredir)),
4244 ALIGN(sizeof (struct nredir)),
4245 ALIGN(sizeof (struct nbinary)),
4246 ALIGN(sizeof (struct nbinary)),
4247 ALIGN(sizeof (struct nif)),
4248 ALIGN(sizeof (struct nbinary)),
4249 ALIGN(sizeof (struct nbinary)),
4250 ALIGN(sizeof (struct nfor)),
4251 ALIGN(sizeof (struct ncase)),
4252 ALIGN(sizeof (struct nclist)),
4253 ALIGN(sizeof (struct narg)),
4254 ALIGN(sizeof (struct narg)),
4255 ALIGN(sizeof (struct nfile)),
4256 ALIGN(sizeof (struct nfile)),
4257 ALIGN(sizeof (struct nfile)),
4258 ALIGN(sizeof (struct nfile)),
4259 ALIGN(sizeof (struct nfile)),
4260 ALIGN(sizeof (struct ndup)),
4261 ALIGN(sizeof (struct ndup)),
4262 ALIGN(sizeof (struct nhere)),
4263 ALIGN(sizeof (struct nhere)),
4264 ALIGN(sizeof (struct nnot)),
4265};
Eric Andersencb57d552001-06-28 07:25:16 +00004266
Eric Andersencb57d552001-06-28 07:25:16 +00004267
4268
4269/*
4270 * Delete a function if it exists.
4271 */
4272
4273static void
Eric Andersen2870d962001-07-02 17:27:21 +00004274unsetfunc(char *name)
4275{
Eric Andersencb57d552001-06-28 07:25:16 +00004276 struct tblentry *cmdp;
4277
4278 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
4279 freefunc(cmdp->param.func);
4280 delete_cmd_entry();
4281 }
4282}
4283
Eric Andersen2870d962001-07-02 17:27:21 +00004284
4285/*
Eric Andersencb57d552001-06-28 07:25:16 +00004286 * Locate and print what a word is...
4287 */
4288
4289static int
Eric Andersen62483552001-07-10 06:09:16 +00004290typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004291{
4292 int i;
4293 int err = 0;
Eric Andersen62483552001-07-10 06:09:16 +00004294 char *argv_a[2];
4295
4296 argv_a[1] = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004297
4298 for (i = 1; i < argc; i++) {
Eric Andersen62483552001-07-10 06:09:16 +00004299 argv_a[0] = argv[i];
4300 argptr = argv_a;
4301 optptr = "v";
4302 err |= hashcmd(argc, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00004303 }
4304 return err;
4305}
4306
Eric Andersen2870d962001-07-02 17:27:21 +00004307#ifdef ASH_CMDCMD
Eric Andersencb57d552001-06-28 07:25:16 +00004308static int
4309commandcmd(argc, argv)
4310 int argc;
4311 char **argv;
4312{
4313 int c;
4314 int default_path = 0;
4315 int verify_only = 0;
4316 int verbose_verify_only = 0;
4317
4318 while ((c = nextopt("pvV")) != '\0')
4319 switch (c) {
4320 case 'p':
4321 default_path = 1;
4322 break;
4323 case 'v':
4324 verify_only = 1;
4325 break;
4326 case 'V':
4327 verbose_verify_only = 1;
4328 break;
Eric Andersencb57d552001-06-28 07:25:16 +00004329 }
4330
4331 if (default_path + verify_only + verbose_verify_only > 1 ||
4332 !*argptr) {
Eric Andersen62483552001-07-10 06:09:16 +00004333 out2str(
4334 "command [-p] command [arg ...]\n"
4335 "command {-v|-V} command\n");
Eric Andersencb57d552001-06-28 07:25:16 +00004336 return EX_USAGE;
4337 }
4338
Eric Andersencb57d552001-06-28 07:25:16 +00004339 if (verify_only || verbose_verify_only) {
Eric Andersen62483552001-07-10 06:09:16 +00004340 char *argv_a[2];
4341
4342 argv_a[1] = 0;
4343 argv_a[0] = *argptr;
4344 argptr = argv_a;
4345 optptr = verbose_verify_only ? "v" : "V"; /* reverse special */
4346 return hashcmd(argc, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00004347 }
Eric Andersencb57d552001-06-28 07:25:16 +00004348
4349 return 0;
4350}
Eric Andersen2870d962001-07-02 17:27:21 +00004351#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004352
4353static int
4354path_change(newval, bltin)
4355 const char *newval;
4356 int *bltin;
4357{
4358 const char *old, *new;
4359 int idx;
4360 int firstchange;
4361
4362 old = pathval();
4363 new = newval;
Eric Andersen2870d962001-07-02 17:27:21 +00004364 firstchange = 9999; /* assume no change */
Eric Andersencb57d552001-06-28 07:25:16 +00004365 idx = 0;
4366 *bltin = -1;
4367 for (;;) {
4368 if (*old != *new) {
4369 firstchange = idx;
4370 if ((*old == '\0' && *new == ':')
4371 || (*old == ':' && *new == '\0'))
4372 firstchange++;
Eric Andersen2870d962001-07-02 17:27:21 +00004373 old = new; /* ignore subsequent differences */
Eric Andersencb57d552001-06-28 07:25:16 +00004374 }
4375 if (*new == '\0')
4376 break;
4377 if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1))
4378 *bltin = idx;
4379 if (*new == ':') {
4380 idx++;
4381 }
4382 new++, old++;
4383 }
4384 if (builtinloc >= 0 && *bltin < 0)
4385 firstchange = 0;
4386 return firstchange;
4387}
Eric Andersencb57d552001-06-28 07:25:16 +00004388/*
4389 * Routines to expand arguments to commands. We have to deal with
4390 * backquotes, shell variables, and file metacharacters.
4391 */
4392/*
4393 * _rmescape() flags
4394 */
Eric Andersen2870d962001-07-02 17:27:21 +00004395#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4396#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Eric Andersencb57d552001-06-28 07:25:16 +00004397
4398/*
4399 * Structure specifying which parts of the string should be searched
4400 * for IFS characters.
4401 */
4402
4403struct ifsregion {
Eric Andersen2870d962001-07-02 17:27:21 +00004404 struct ifsregion *next; /* next region in list */
4405 int begoff; /* offset of start of region */
4406 int endoff; /* offset of end of region */
4407 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004408};
4409
4410
Eric Andersen2870d962001-07-02 17:27:21 +00004411static char *expdest; /* output of current string */
4412static struct nodelist *argbackq; /* list of back quote expressions */
4413static struct ifsregion ifsfirst; /* first struct in list of ifs regions */
4414static struct ifsregion *ifslastp; /* last struct in list */
4415static struct arglist exparg; /* holds expanded arg list */
Eric Andersencb57d552001-06-28 07:25:16 +00004416
Eric Andersen2870d962001-07-02 17:27:21 +00004417static void argstr (char *, int);
4418static char *exptilde (char *, int);
4419static void expbackq (union node *, int, int);
4420static int subevalvar (char *, char *, int, int, int, int, int);
Eric Andersen2870d962001-07-02 17:27:21 +00004421static int varisset (char *, int);
4422static void strtodest (const char *, const char *, int);
4423static void varvalue (char *, int, int);
4424static void recordregion (int, int, int);
4425static void removerecordregions (int);
4426static void ifsbreakup (char *, struct arglist *);
4427static void ifsfree (void);
4428static void expandmeta (struct strlist *, int);
Eric Andersen62483552001-07-10 06:09:16 +00004429#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00004430#define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB)
4431#if !defined(GLOB_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00004432static void addglob (const glob_t *);
Eric Andersencb57d552001-06-28 07:25:16 +00004433#endif
4434#endif
Eric Andersen62483552001-07-10 06:09:16 +00004435#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersen2870d962001-07-02 17:27:21 +00004436static void expmeta (char *, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004437#endif
Eric Andersen62483552001-07-10 06:09:16 +00004438#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersen2870d962001-07-02 17:27:21 +00004439static struct strlist *expsort (struct strlist *);
4440static struct strlist *msort (struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004441#endif
Eric Andersen2870d962001-07-02 17:27:21 +00004442static int patmatch (char *, char *, int);
Eric Andersen62483552001-07-10 06:09:16 +00004443#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00004444static int patmatch2 (char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004445#else
Eric Andersen2870d962001-07-02 17:27:21 +00004446static int pmatch (char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004447#define patmatch2 patmatch
4448#endif
Eric Andersen2870d962001-07-02 17:27:21 +00004449static char *cvtnum (int, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004450
4451/*
4452 * Expand shell variables and backquotes inside a here document.
4453 */
4454
Eric Andersen2870d962001-07-02 17:27:21 +00004455/* arg: the document, fd: where to write the expanded version */
Eric Andersen62483552001-07-10 06:09:16 +00004456static inline void
Eric Andersen2870d962001-07-02 17:27:21 +00004457expandhere(union node *arg, int fd)
4458{
Eric Andersencb57d552001-06-28 07:25:16 +00004459 herefd = fd;
4460 expandarg(arg, (struct arglist *)NULL, 0);
4461 xwrite(fd, stackblock(), expdest - stackblock());
4462}
4463
4464
4465/*
4466 * Perform variable substitution and command substitution on an argument,
4467 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4468 * perform splitting and file name expansion. When arglist is NULL, perform
4469 * here document expansion.
4470 */
4471
4472static void
4473expandarg(arg, arglist, flag)
4474 union node *arg;
4475 struct arglist *arglist;
4476 int flag;
4477{
4478 struct strlist *sp;
4479 char *p;
4480
4481 argbackq = arg->narg.backquote;
4482 STARTSTACKSTR(expdest);
4483 ifsfirst.next = NULL;
4484 ifslastp = NULL;
4485 argstr(arg->narg.text, flag);
4486 if (arglist == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00004487 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004488 }
4489 STPUTC('\0', expdest);
4490 p = grabstackstr(expdest);
4491 exparg.lastp = &exparg.list;
4492 /*
4493 * TODO - EXP_REDIR
4494 */
4495 if (flag & EXP_FULL) {
4496 ifsbreakup(p, &exparg);
4497 *exparg.lastp = NULL;
4498 exparg.lastp = &exparg.list;
4499 expandmeta(exparg.list, flag);
4500 } else {
4501 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4502 rmescapes(p);
4503 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4504 sp->text = p;
4505 *exparg.lastp = sp;
4506 exparg.lastp = &sp->next;
4507 }
4508 ifsfree();
4509 *exparg.lastp = NULL;
4510 if (exparg.list) {
4511 *arglist->lastp = exparg.list;
4512 arglist->lastp = exparg.lastp;
4513 }
4514}
4515
4516
Eric Andersen62483552001-07-10 06:09:16 +00004517/*
4518 * Expand a variable, and return a pointer to the next character in the
4519 * input string.
4520 */
4521
4522static inline char *
4523evalvar(p, flag)
4524 char *p;
4525 int flag;
4526{
4527 int subtype;
4528 int varflags;
4529 char *var;
4530 const char *val;
4531 int patloc;
4532 int c;
4533 int set;
4534 int special;
4535 int startloc;
4536 int varlen;
4537 int easy;
4538 int quotes = flag & (EXP_FULL | EXP_CASE);
4539
4540 varflags = *p++;
4541 subtype = varflags & VSTYPE;
4542 var = p;
4543 special = 0;
4544 if (! is_name(*p))
4545 special = 1;
4546 p = strchr(p, '=') + 1;
4547again: /* jump here after setting a variable with ${var=text} */
4548 if (special) {
4549 set = varisset(var, varflags & VSNUL);
4550 val = NULL;
4551 } else {
4552 val = lookupvar(var);
4553 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
4554 val = NULL;
4555 set = 0;
4556 } else
4557 set = 1;
4558 }
4559 varlen = 0;
4560 startloc = expdest - stackblock();
4561 if (set && subtype != VSPLUS) {
4562 /* insert the value of the variable */
4563 if (special) {
4564 varvalue(var, varflags & VSQUOTE, flag);
4565 if (subtype == VSLENGTH) {
4566 varlen = expdest - stackblock() - startloc;
4567 STADJUST(-varlen, expdest);
4568 }
4569 } else {
4570 if (subtype == VSLENGTH) {
4571 varlen = strlen(val);
4572 } else {
4573 strtodest(
4574 val,
4575 varflags & VSQUOTE ?
4576 DQSYNTAX : BASESYNTAX,
4577 quotes
4578 );
4579 }
4580 }
4581 }
4582
4583 if (subtype == VSPLUS)
4584 set = ! set;
4585
4586 easy = ((varflags & VSQUOTE) == 0 ||
4587 (*var == '@' && shellparam.nparam != 1));
4588
4589
4590 switch (subtype) {
4591 case VSLENGTH:
4592 expdest = cvtnum(varlen, expdest);
4593 goto record;
4594
4595 case VSNORMAL:
4596 if (!easy)
4597 break;
4598record:
4599 recordregion(startloc, expdest - stackblock(),
4600 varflags & VSQUOTE);
4601 break;
4602
4603 case VSPLUS:
4604 case VSMINUS:
4605 if (!set) {
4606 argstr(p, flag);
4607 break;
4608 }
4609 if (easy)
4610 goto record;
4611 break;
4612
4613 case VSTRIMLEFT:
4614 case VSTRIMLEFTMAX:
4615 case VSTRIMRIGHT:
4616 case VSTRIMRIGHTMAX:
4617 if (!set)
4618 break;
4619 /*
4620 * Terminate the string and start recording the pattern
4621 * right after it
4622 */
4623 STPUTC('\0', expdest);
4624 patloc = expdest - stackblock();
4625 if (subevalvar(p, NULL, patloc, subtype,
4626 startloc, varflags, quotes) == 0) {
4627 int amount = (expdest - stackblock() - patloc) + 1;
4628 STADJUST(-amount, expdest);
4629 }
4630 /* Remove any recorded regions beyond start of variable */
4631 removerecordregions(startloc);
4632 goto record;
4633
4634 case VSASSIGN:
4635 case VSQUESTION:
4636 if (!set) {
4637 if (subevalvar(p, var, 0, subtype, startloc,
4638 varflags, quotes)) {
4639 varflags &= ~VSNUL;
4640 /*
4641 * Remove any recorded regions beyond
4642 * start of variable
4643 */
4644 removerecordregions(startloc);
4645 goto again;
4646 }
4647 break;
4648 }
4649 if (easy)
4650 goto record;
4651 break;
4652
4653#ifdef DEBUG
4654 default:
4655 abort();
4656#endif
4657 }
4658
4659 if (subtype != VSNORMAL) { /* skip to end of alternative */
4660 int nesting = 1;
4661 for (;;) {
4662 if ((c = *p++) == CTLESC)
4663 p++;
4664 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
4665 if (set)
4666 argbackq = argbackq->next;
4667 } else if (c == CTLVAR) {
4668 if ((*p++ & VSTYPE) != VSNORMAL)
4669 nesting++;
4670 } else if (c == CTLENDVAR) {
4671 if (--nesting == 0)
4672 break;
4673 }
4674 }
4675 }
4676 return p;
4677}
4678
Eric Andersencb57d552001-06-28 07:25:16 +00004679
4680/*
4681 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4682 * characters to allow for further processing. Otherwise treat
4683 * $@ like $* since no splitting will be performed.
4684 */
4685
4686static void
4687argstr(p, flag)
4688 char *p;
4689 int flag;
4690{
4691 char c;
Eric Andersen2870d962001-07-02 17:27:21 +00004692 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
Eric Andersencb57d552001-06-28 07:25:16 +00004693 int firsteq = 1;
4694
4695 if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
4696 p = exptilde(p, flag);
4697 for (;;) {
4698 switch (c = *p++) {
4699 case '\0':
4700 case CTLENDVAR: /* ??? */
4701 goto breakloop;
4702 case CTLQUOTEMARK:
4703 /* "$@" syntax adherence hack */
4704 if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
4705 break;
4706 if ((flag & EXP_FULL) != 0)
4707 STPUTC(c, expdest);
4708 break;
4709 case CTLESC:
4710 if (quotes)
4711 STPUTC(c, expdest);
4712 c = *p++;
4713 STPUTC(c, expdest);
4714 break;
4715 case CTLVAR:
4716 p = evalvar(p, flag);
4717 break;
4718 case CTLBACKQ:
4719 case CTLBACKQ|CTLQUOTE:
4720 expbackq(argbackq->n, c & CTLQUOTE, flag);
4721 argbackq = argbackq->next;
4722 break;
4723#ifdef ASH_MATH_SUPPORT
4724 case CTLENDARI:
4725 expari(flag);
4726 break;
Eric Andersen2870d962001-07-02 17:27:21 +00004727#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004728 case ':':
4729 case '=':
4730 /*
4731 * sort of a hack - expand tildes in variable
4732 * assignments (after the first '=' and after ':'s).
4733 */
4734 STPUTC(c, expdest);
4735 if (flag & EXP_VARTILDE && *p == '~') {
4736 if (c == '=') {
4737 if (firsteq)
4738 firsteq = 0;
4739 else
4740 break;
4741 }
4742 p = exptilde(p, flag);
4743 }
4744 break;
4745 default:
4746 STPUTC(c, expdest);
4747 }
4748 }
4749breakloop:;
4750 return;
4751}
4752
4753static char *
4754exptilde(p, flag)
4755 char *p;
4756 int flag;
4757{
4758 char c, *startp = p;
4759 struct passwd *pw;
4760 const char *home;
4761 int quotes = flag & (EXP_FULL | EXP_CASE);
4762
4763 while ((c = *p) != '\0') {
4764 switch(c) {
4765 case CTLESC:
4766 return (startp);
4767 case CTLQUOTEMARK:
4768 return (startp);
4769 case ':':
4770 if (flag & EXP_VARTILDE)
4771 goto done;
4772 break;
4773 case '/':
4774 goto done;
4775 }
4776 p++;
4777 }
4778done:
4779 *p = '\0';
4780 if (*(startp+1) == '\0') {
4781 if ((home = lookupvar("HOME")) == NULL)
4782 goto lose;
4783 } else {
4784 if ((pw = getpwnam(startp+1)) == NULL)
4785 goto lose;
4786 home = pw->pw_dir;
4787 }
4788 if (*home == '\0')
4789 goto lose;
4790 *p = c;
4791 strtodest(home, SQSYNTAX, quotes);
4792 return (p);
4793lose:
4794 *p = c;
4795 return (startp);
4796}
4797
4798
Eric Andersen2870d962001-07-02 17:27:21 +00004799static void
4800removerecordregions(int endoff)
Eric Andersencb57d552001-06-28 07:25:16 +00004801{
4802 if (ifslastp == NULL)
4803 return;
4804
4805 if (ifsfirst.endoff > endoff) {
4806 while (ifsfirst.next != NULL) {
4807 struct ifsregion *ifsp;
4808 INTOFF;
4809 ifsp = ifsfirst.next->next;
4810 ckfree(ifsfirst.next);
4811 ifsfirst.next = ifsp;
4812 INTON;
4813 }
4814 if (ifsfirst.begoff > endoff)
4815 ifslastp = NULL;
4816 else {
4817 ifslastp = &ifsfirst;
4818 ifsfirst.endoff = endoff;
4819 }
4820 return;
4821 }
Eric Andersen2870d962001-07-02 17:27:21 +00004822
Eric Andersencb57d552001-06-28 07:25:16 +00004823 ifslastp = &ifsfirst;
4824 while (ifslastp->next && ifslastp->next->begoff < endoff)
4825 ifslastp=ifslastp->next;
4826 while (ifslastp->next != NULL) {
4827 struct ifsregion *ifsp;
4828 INTOFF;
4829 ifsp = ifslastp->next->next;
4830 ckfree(ifslastp->next);
4831 ifslastp->next = ifsp;
4832 INTON;
4833 }
4834 if (ifslastp->endoff > endoff)
4835 ifslastp->endoff = endoff;
4836}
4837
4838
4839#ifdef ASH_MATH_SUPPORT
4840/*
4841 * Expand arithmetic expression. Backup to start of expression,
4842 * evaluate, place result in (backed up) result, adjust string position.
4843 */
4844static void
Eric Andersen2870d962001-07-02 17:27:21 +00004845expari(int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004846{
4847 char *p, *start;
4848 int result;
4849 int begoff;
4850 int quotes = flag & (EXP_FULL | EXP_CASE);
4851 int quoted;
4852
Eric Andersen2870d962001-07-02 17:27:21 +00004853 /* ifsfree(); */
Eric Andersencb57d552001-06-28 07:25:16 +00004854
4855 /*
4856 * This routine is slightly over-complicated for
4857 * efficiency. First we make sure there is
4858 * enough space for the result, which may be bigger
4859 * than the expression if we add exponentation. Next we
4860 * scan backwards looking for the start of arithmetic. If the
4861 * next previous character is a CTLESC character, then we
4862 * have to rescan starting from the beginning since CTLESC
4863 * characters have to be processed left to right.
4864 */
4865 CHECKSTRSPACE(10, expdest);
4866 USTPUTC('\0', expdest);
4867 start = stackblock();
4868 p = expdest - 1;
4869 while (*p != CTLARI && p >= start)
4870 --p;
4871 if (*p != CTLARI)
4872 error("missing CTLARI (shouldn't happen)");
4873 if (p > start && *(p-1) == CTLESC)
4874 for (p = start; *p != CTLARI; p++)
4875 if (*p == CTLESC)
4876 p++;
4877
4878 if (p[1] == '"')
4879 quoted=1;
4880 else
4881 quoted=0;
4882 begoff = p - start;
4883 removerecordregions(begoff);
4884 if (quotes)
4885 rmescapes(p+2);
Eric Andersen74bcd162001-07-30 21:41:37 +00004886 result = ash_arith(p+2);
Eric Andersen3102ac42001-07-06 04:26:23 +00004887 snprintf(p, 12, "%d", result);
Eric Andersencb57d552001-06-28 07:25:16 +00004888
4889 while (*p++)
4890 ;
4891
4892 if (quoted == 0)
4893 recordregion(begoff, p - 1 - start, 0);
4894 result = expdest - p + 1;
4895 STADJUST(-result, expdest);
4896}
Eric Andersen2870d962001-07-02 17:27:21 +00004897#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004898
4899/*
4900 * Expand stuff in backwards quotes.
4901 */
4902
4903static void
4904expbackq(cmd, quoted, flag)
4905 union node *cmd;
4906 int quoted;
4907 int flag;
4908{
4909 volatile struct backcmd in;
4910 int i;
4911 char buf[128];
4912 char *p;
4913 char *dest = expdest;
4914 volatile struct ifsregion saveifs;
4915 struct ifsregion *volatile savelastp;
4916 struct nodelist *volatile saveargbackq;
4917 char lastc;
4918 int startloc = dest - stackblock();
4919 char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
4920 volatile int saveherefd;
4921 int quotes = flag & (EXP_FULL | EXP_CASE);
4922 struct jmploc jmploc;
4923 struct jmploc *volatile savehandler;
4924 int ex;
4925
4926#if __GNUC__
4927 /* Avoid longjmp clobbering */
4928 (void) &dest;
4929 (void) &syntax;
4930#endif
4931
4932 in.fd = -1;
4933 in.buf = 0;
4934 in.jp = 0;
4935
4936 INTOFF;
4937 saveifs = ifsfirst;
4938 savelastp = ifslastp;
4939 saveargbackq = argbackq;
4940 saveherefd = herefd;
4941 herefd = -1;
4942 if ((ex = setjmp(jmploc.loc))) {
4943 goto err1;
4944 }
4945 savehandler = handler;
4946 handler = &jmploc;
4947 INTON;
4948 p = grabstackstr(dest);
4949 evalbackcmd(cmd, (struct backcmd *) &in);
4950 ungrabstackstr(p, dest);
4951err1:
4952 INTOFF;
4953 ifsfirst = saveifs;
4954 ifslastp = savelastp;
4955 argbackq = saveargbackq;
4956 herefd = saveherefd;
4957 if (ex) {
4958 goto err2;
4959 }
4960
4961 p = in.buf;
4962 lastc = '\0';
4963 for (;;) {
4964 if (--in.nleft < 0) {
4965 if (in.fd < 0)
4966 break;
Eric Andersen7467c8d2001-07-12 20:26:32 +00004967 i = safe_read(in.fd, buf, sizeof buf);
Eric Andersencb57d552001-06-28 07:25:16 +00004968 TRACE(("expbackq: read returns %d\n", i));
4969 if (i <= 0)
4970 break;
4971 p = buf;
4972 in.nleft = i - 1;
4973 }
4974 lastc = *p++;
4975 if (lastc != '\0') {
4976 if (quotes && syntax[(int)lastc] == CCTL)
4977 STPUTC(CTLESC, dest);
4978 STPUTC(lastc, dest);
4979 }
4980 }
4981
4982 /* Eat all trailing newlines */
4983 for (; dest > stackblock() && dest[-1] == '\n';)
4984 STUNPUTC(dest);
4985
4986err2:
4987 if (in.fd >= 0)
4988 close(in.fd);
4989 if (in.buf)
4990 ckfree(in.buf);
4991 if (in.jp)
4992 exitstatus = waitforjob(in.jp);
4993 handler = savehandler;
4994 if (ex) {
4995 longjmp(handler->loc, 1);
4996 }
4997 if (quoted == 0)
4998 recordregion(startloc, dest - stackblock(), 0);
4999 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
5000 (dest - stackblock()) - startloc,
5001 (dest - stackblock()) - startloc,
5002 stackblock() + startloc));
5003 expdest = dest;
5004 INTON;
5005}
5006
Eric Andersencb57d552001-06-28 07:25:16 +00005007static int
5008subevalvar(p, str, strloc, subtype, startloc, varflags, quotes)
5009 char *p;
5010 char *str;
5011 int strloc;
5012 int subtype;
5013 int startloc;
5014 int varflags;
5015 int quotes;
5016{
5017 char *startp;
5018 char *loc = NULL;
5019 char *q;
5020 int c = 0;
5021 int saveherefd = herefd;
5022 struct nodelist *saveargbackq = argbackq;
5023 int amount;
5024
5025 herefd = -1;
5026 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5027 STACKSTRNUL(expdest);
5028 herefd = saveherefd;
5029 argbackq = saveargbackq;
5030 startp = stackblock() + startloc;
5031 if (str == NULL)
5032 str = stackblock() + strloc;
5033
5034 switch (subtype) {
5035 case VSASSIGN:
5036 setvar(str, startp, 0);
5037 amount = startp - expdest;
5038 STADJUST(amount, expdest);
5039 varflags &= ~VSNUL;
5040 if (c != 0)
5041 *loc = c;
5042 return 1;
5043
5044 case VSQUESTION:
5045 if (*p != CTLENDVAR) {
Eric Andersen3102ac42001-07-06 04:26:23 +00005046 out2fmt(snlfmt, startp);
Eric Andersencb57d552001-06-28 07:25:16 +00005047 error((char *)NULL);
5048 }
5049 error("%.*s: parameter %snot set", p - str - 1,
5050 str, (varflags & VSNUL) ? "null or "
5051 : nullstr);
5052 /* NOTREACHED */
5053
5054 case VSTRIMLEFT:
5055 for (loc = startp; loc < str; loc++) {
5056 c = *loc;
5057 *loc = '\0';
5058 if (patmatch2(str, startp, quotes))
5059 goto recordleft;
5060 *loc = c;
5061 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00005062 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00005063 }
5064 return 0;
5065
5066 case VSTRIMLEFTMAX:
5067 for (loc = str - 1; loc >= startp;) {
5068 c = *loc;
5069 *loc = '\0';
5070 if (patmatch2(str, startp, quotes))
5071 goto recordleft;
5072 *loc = c;
5073 loc--;
5074 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
5075 for (q = startp; q < loc; q++)
5076 if (*q == CTLESC)
5077 q++;
5078 if (q > loc)
5079 loc--;
5080 }
5081 }
5082 return 0;
5083
5084 case VSTRIMRIGHT:
Eric Andersen2870d962001-07-02 17:27:21 +00005085 for (loc = str - 1; loc >= startp;) {
Eric Andersencb57d552001-06-28 07:25:16 +00005086 if (patmatch2(str, loc, quotes))
5087 goto recordright;
5088 loc--;
Eric Andersen2870d962001-07-02 17:27:21 +00005089 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
Eric Andersencb57d552001-06-28 07:25:16 +00005090 for (q = startp; q < loc; q++)
5091 if (*q == CTLESC)
5092 q++;
5093 if (q > loc)
5094 loc--;
5095 }
5096 }
5097 return 0;
5098
5099 case VSTRIMRIGHTMAX:
5100 for (loc = startp; loc < str - 1; loc++) {
5101 if (patmatch2(str, loc, quotes))
5102 goto recordright;
5103 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00005104 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00005105 }
5106 return 0;
5107
5108#ifdef DEBUG
5109 default:
5110 abort();
5111#endif
5112 }
5113
5114recordleft:
5115 *loc = c;
5116 amount = ((str - 1) - (loc - startp)) - expdest;
5117 STADJUST(amount, expdest);
5118 while (loc != str - 1)
5119 *startp++ = *loc++;
5120 return 1;
5121
5122recordright:
5123 amount = loc - expdest;
5124 STADJUST(amount, expdest);
5125 STPUTC('\0', expdest);
5126 STADJUST(-1, expdest);
5127 return 1;
5128}
5129
5130
5131/*
Eric Andersencb57d552001-06-28 07:25:16 +00005132 * Test whether a specialized variable is set.
5133 */
5134
5135static int
5136varisset(name, nulok)
5137 char *name;
5138 int nulok;
5139{
5140 if (*name == '!')
5141 return backgndpid != -1;
5142 else if (*name == '@' || *name == '*') {
5143 if (*shellparam.p == NULL)
5144 return 0;
5145
5146 if (nulok) {
5147 char **av;
5148
5149 for (av = shellparam.p; *av; av++)
5150 if (**av != '\0')
5151 return 1;
5152 return 0;
5153 }
5154 } else if (is_digit(*name)) {
5155 char *ap;
5156 int num = atoi(name);
5157
5158 if (num > shellparam.nparam)
5159 return 0;
5160
5161 if (num == 0)
5162 ap = arg0;
5163 else
5164 ap = shellparam.p[num - 1];
5165
5166 if (nulok && (ap == NULL || *ap == '\0'))
5167 return 0;
5168 }
5169 return 1;
5170}
5171
Eric Andersencb57d552001-06-28 07:25:16 +00005172/*
5173 * Put a string on the stack.
5174 */
5175
5176static void
5177strtodest(p, syntax, quotes)
5178 const char *p;
5179 const char *syntax;
5180 int quotes;
5181{
5182 while (*p) {
5183 if (quotes && syntax[(int) *p] == CCTL)
5184 STPUTC(CTLESC, expdest);
5185 STPUTC(*p++, expdest);
5186 }
5187}
5188
Eric Andersencb57d552001-06-28 07:25:16 +00005189/*
5190 * Add the value of a specialized variable to the stack string.
5191 */
5192
5193static void
5194varvalue(name, quoted, flags)
5195 char *name;
5196 int quoted;
5197 int flags;
5198{
5199 int num;
5200 char *p;
5201 int i;
5202 int sep;
5203 int sepq = 0;
5204 char **ap;
5205 char const *syntax;
5206 int allow_split = flags & EXP_FULL;
5207 int quotes = flags & (EXP_FULL | EXP_CASE);
5208
5209 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5210 switch (*name) {
5211 case '$':
5212 num = rootpid;
5213 goto numvar;
5214 case '?':
5215 num = oexitstatus;
5216 goto numvar;
5217 case '#':
5218 num = shellparam.nparam;
5219 goto numvar;
5220 case '!':
5221 num = backgndpid;
5222numvar:
5223 expdest = cvtnum(num, expdest);
5224 break;
5225 case '-':
5226 for (i = 0 ; i < NOPTS ; i++) {
Eric Andersen2870d962001-07-02 17:27:21 +00005227 if (optent_val(i))
5228 STPUTC(optent_letter(optlist[i]), expdest);
Eric Andersencb57d552001-06-28 07:25:16 +00005229 }
5230 break;
5231 case '@':
5232 if (allow_split && quoted) {
5233 sep = 1 << CHAR_BIT;
5234 goto param;
5235 }
5236 /* fall through */
5237 case '*':
5238 sep = ifsset() ? ifsval()[0] : ' ';
5239 if (quotes) {
5240 sepq = syntax[(int) sep] == CCTL;
5241 }
5242param:
5243 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
5244 strtodest(p, syntax, quotes);
5245 if (*ap && sep) {
5246 if (sepq)
5247 STPUTC(CTLESC, expdest);
5248 STPUTC(sep, expdest);
5249 }
5250 }
5251 break;
5252 case '0':
5253 strtodest(arg0, syntax, quotes);
5254 break;
5255 default:
5256 num = atoi(name);
5257 if (num > 0 && num <= shellparam.nparam) {
5258 strtodest(shellparam.p[num - 1], syntax, quotes);
5259 }
5260 break;
5261 }
5262}
5263
5264
Eric Andersencb57d552001-06-28 07:25:16 +00005265/*
5266 * Record the fact that we have to scan this region of the
5267 * string for IFS characters.
5268 */
5269
5270static void
5271recordregion(start, end, nulonly)
5272 int start;
5273 int end;
5274 int nulonly;
5275{
5276 struct ifsregion *ifsp;
5277
5278 if (ifslastp == NULL) {
5279 ifsp = &ifsfirst;
5280 } else {
5281 INTOFF;
5282 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
5283 ifsp->next = NULL;
5284 ifslastp->next = ifsp;
5285 INTON;
5286 }
5287 ifslastp = ifsp;
5288 ifslastp->begoff = start;
5289 ifslastp->endoff = end;
5290 ifslastp->nulonly = nulonly;
5291}
5292
5293
5294
5295/*
5296 * Break the argument string into pieces based upon IFS and add the
5297 * strings to the argument list. The regions of the string to be
5298 * searched for IFS characters have been stored by recordregion.
5299 */
5300static void
5301ifsbreakup(string, arglist)
5302 char *string;
5303 struct arglist *arglist;
5304 {
5305 struct ifsregion *ifsp;
5306 struct strlist *sp;
5307 char *start;
5308 char *p;
5309 char *q;
5310 const char *ifs, *realifs;
5311 int ifsspc;
5312 int nulonly;
5313
5314
5315 start = string;
5316 ifsspc = 0;
5317 nulonly = 0;
5318 realifs = ifsset() ? ifsval() : defifs;
5319 if (ifslastp != NULL) {
5320 ifsp = &ifsfirst;
5321 do {
5322 p = string + ifsp->begoff;
5323 nulonly = ifsp->nulonly;
5324 ifs = nulonly ? nullstr : realifs;
5325 ifsspc = 0;
5326 while (p < string + ifsp->endoff) {
5327 q = p;
5328 if (*p == CTLESC)
5329 p++;
5330 if (strchr(ifs, *p)) {
5331 if (!nulonly)
5332 ifsspc = (strchr(defifs, *p) != NULL);
5333 /* Ignore IFS whitespace at start */
5334 if (q == start && ifsspc) {
5335 p++;
5336 start = p;
5337 continue;
5338 }
5339 *q = '\0';
5340 sp = (struct strlist *)stalloc(sizeof *sp);
5341 sp->text = start;
5342 *arglist->lastp = sp;
5343 arglist->lastp = &sp->next;
5344 p++;
5345 if (!nulonly) {
5346 for (;;) {
5347 if (p >= string + ifsp->endoff) {
5348 break;
5349 }
5350 q = p;
5351 if (*p == CTLESC)
5352 p++;
5353 if (strchr(ifs, *p) == NULL ) {
5354 p = q;
5355 break;
5356 } else if (strchr(defifs, *p) == NULL) {
5357 if (ifsspc) {
5358 p++;
5359 ifsspc = 0;
5360 } else {
5361 p = q;
5362 break;
5363 }
5364 } else
5365 p++;
5366 }
5367 }
5368 start = p;
5369 } else
5370 p++;
5371 }
5372 } while ((ifsp = ifsp->next) != NULL);
5373 if (!(*start || (!ifsspc && start > string && nulonly))) {
5374 return;
5375 }
5376 }
5377
5378 sp = (struct strlist *)stalloc(sizeof *sp);
5379 sp->text = start;
5380 *arglist->lastp = sp;
5381 arglist->lastp = &sp->next;
5382}
5383
5384static void
5385ifsfree()
5386{
5387 while (ifsfirst.next != NULL) {
5388 struct ifsregion *ifsp;
5389 INTOFF;
5390 ifsp = ifsfirst.next->next;
5391 ckfree(ifsfirst.next);
5392 ifsfirst.next = ifsp;
5393 INTON;
5394 }
5395 ifslastp = NULL;
5396 ifsfirst.next = NULL;
5397}
5398
Eric Andersen2870d962001-07-02 17:27:21 +00005399/*
5400 * Add a file name to the list.
5401 */
Eric Andersencb57d552001-06-28 07:25:16 +00005402
Eric Andersen2870d962001-07-02 17:27:21 +00005403static void
5404addfname(const char *name)
5405{
5406 char *p;
5407 struct strlist *sp;
5408
5409 p = sstrdup(name);
5410 sp = (struct strlist *)stalloc(sizeof *sp);
5411 sp->text = p;
5412 *exparg.lastp = sp;
5413 exparg.lastp = &sp->next;
5414}
Eric Andersencb57d552001-06-28 07:25:16 +00005415
5416/*
5417 * Expand shell metacharacters. At this point, the only control characters
5418 * should be escapes. The results are stored in the list exparg.
5419 */
5420
Eric Andersen62483552001-07-10 06:09:16 +00005421#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00005422static void
5423expandmeta(str, flag)
5424 struct strlist *str;
5425 int flag;
5426{
5427 const char *p;
5428 glob_t pglob;
5429 /* TODO - EXP_REDIR */
5430
5431 while (str) {
5432 if (fflag)
5433 goto nometa;
5434 p = preglob(str->text);
5435 INTOFF;
5436 switch (glob(p, GLOB_NOMAGIC, 0, &pglob)) {
5437 case 0:
5438 if (!(pglob.gl_flags & GLOB_MAGCHAR))
5439 goto nometa2;
5440 addglob(&pglob);
5441 globfree(&pglob);
5442 INTON;
5443 break;
5444 case GLOB_NOMATCH:
5445nometa2:
5446 globfree(&pglob);
5447 INTON;
5448nometa:
5449 *exparg.lastp = str;
5450 rmescapes(str->text);
5451 exparg.lastp = &str->next;
5452 break;
Eric Andersen2870d962001-07-02 17:27:21 +00005453 default: /* GLOB_NOSPACE */
Eric Andersencb57d552001-06-28 07:25:16 +00005454 error("Out of space");
5455 }
5456 str = str->next;
5457 }
5458}
5459
5460
5461/*
5462 * Add the result of glob(3) to the list.
5463 */
5464
5465static void
5466addglob(pglob)
5467 const glob_t *pglob;
5468{
5469 char **p = pglob->gl_pathv;
5470
5471 do {
5472 addfname(*p);
5473 } while (*++p);
5474}
5475
5476
Eric Andersen2870d962001-07-02 17:27:21 +00005477#else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005478static char *expdir;
5479
5480
5481static void
5482expandmeta(str, flag)
5483 struct strlist *str;
5484 int flag;
5485{
5486 char *p;
5487 struct strlist **savelastp;
5488 struct strlist *sp;
5489 char c;
5490 /* TODO - EXP_REDIR */
5491
5492 while (str) {
5493 if (fflag)
5494 goto nometa;
5495 p = str->text;
Eric Andersen2870d962001-07-02 17:27:21 +00005496 for (;;) { /* fast check for meta chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005497 if ((c = *p++) == '\0')
5498 goto nometa;
5499 if (c == '*' || c == '?' || c == '[' || c == '!')
5500 break;
5501 }
5502 savelastp = exparg.lastp;
5503 INTOFF;
5504 if (expdir == NULL) {
5505 int i = strlen(str->text);
5506 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5507 }
5508
5509 expmeta(expdir, str->text);
5510 ckfree(expdir);
5511 expdir = NULL;
5512 INTON;
5513 if (exparg.lastp == savelastp) {
5514 /*
5515 * no matches
5516 */
5517nometa:
5518 *exparg.lastp = str;
5519 rmescapes(str->text);
5520 exparg.lastp = &str->next;
5521 } else {
5522 *exparg.lastp = NULL;
5523 *savelastp = sp = expsort(*savelastp);
5524 while (sp->next != NULL)
5525 sp = sp->next;
5526 exparg.lastp = &sp->next;
5527 }
5528 str = str->next;
5529 }
5530}
5531
5532
5533/*
5534 * Do metacharacter (i.e. *, ?, [...]) expansion.
5535 */
5536
5537static void
5538expmeta(enddir, name)
5539 char *enddir;
5540 char *name;
5541 {
5542 char *p;
5543 const char *cp;
5544 char *q;
5545 char *start;
5546 char *endname;
5547 int metaflag;
5548 struct stat statb;
5549 DIR *dirp;
5550 struct dirent *dp;
5551 int atend;
5552 int matchdot;
5553
5554 metaflag = 0;
5555 start = name;
5556 for (p = name ; ; p++) {
5557 if (*p == '*' || *p == '?')
5558 metaflag = 1;
5559 else if (*p == '[') {
5560 q = p + 1;
5561 if (*q == '!')
5562 q++;
5563 for (;;) {
5564 while (*q == CTLQUOTEMARK)
5565 q++;
5566 if (*q == CTLESC)
5567 q++;
5568 if (*q == '/' || *q == '\0')
5569 break;
5570 if (*++q == ']') {
5571 metaflag = 1;
5572 break;
5573 }
5574 }
Eric Andersen2870d962001-07-02 17:27:21 +00005575 } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) {
Eric Andersencb57d552001-06-28 07:25:16 +00005576 metaflag = 1;
5577 } else if (*p == '\0')
5578 break;
5579 else if (*p == CTLQUOTEMARK)
5580 continue;
5581 else if (*p == CTLESC)
5582 p++;
5583 if (*p == '/') {
5584 if (metaflag)
5585 break;
5586 start = p + 1;
5587 }
5588 }
Eric Andersen2870d962001-07-02 17:27:21 +00005589 if (metaflag == 0) { /* we've reached the end of the file name */
Eric Andersencb57d552001-06-28 07:25:16 +00005590 if (enddir != expdir)
5591 metaflag++;
5592 for (p = name ; ; p++) {
5593 if (*p == CTLQUOTEMARK)
5594 continue;
5595 if (*p == CTLESC)
5596 p++;
5597 *enddir++ = *p;
5598 if (*p == '\0')
5599 break;
5600 }
5601 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5602 addfname(expdir);
5603 return;
5604 }
5605 endname = p;
5606 if (start != name) {
5607 p = name;
5608 while (p < start) {
5609 while (*p == CTLQUOTEMARK)
5610 p++;
5611 if (*p == CTLESC)
5612 p++;
5613 *enddir++ = *p++;
5614 }
5615 }
5616 if (enddir == expdir) {
5617 cp = ".";
5618 } else if (enddir == expdir + 1 && *expdir == '/') {
5619 cp = "/";
5620 } else {
5621 cp = expdir;
5622 enddir[-1] = '\0';
5623 }
5624 if ((dirp = opendir(cp)) == NULL)
5625 return;
5626 if (enddir != expdir)
5627 enddir[-1] = '/';
5628 if (*endname == 0) {
5629 atend = 1;
5630 } else {
5631 atend = 0;
5632 *endname++ = '\0';
5633 }
5634 matchdot = 0;
5635 p = start;
5636 while (*p == CTLQUOTEMARK)
5637 p++;
5638 if (*p == CTLESC)
5639 p++;
5640 if (*p == '.')
5641 matchdot++;
5642 while (! int_pending() && (dp = readdir(dirp)) != NULL) {
5643 if (dp->d_name[0] == '.' && ! matchdot)
5644 continue;
5645 if (patmatch(start, dp->d_name, 0)) {
5646 if (atend) {
Eric Andersen2870d962001-07-02 17:27:21 +00005647 strcpy(enddir, dp->d_name);
Eric Andersencb57d552001-06-28 07:25:16 +00005648 addfname(expdir);
5649 } else {
5650 for (p = enddir, cp = dp->d_name;
5651 (*p++ = *cp++) != '\0';)
5652 continue;
5653 p[-1] = '/';
5654 expmeta(p, endname);
5655 }
5656 }
5657 }
5658 closedir(dirp);
5659 if (! atend)
5660 endname[-1] = '/';
5661}
Eric Andersen2870d962001-07-02 17:27:21 +00005662#endif /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005663
5664
Eric Andersencb57d552001-06-28 07:25:16 +00005665
Eric Andersen62483552001-07-10 06:09:16 +00005666#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersencb57d552001-06-28 07:25:16 +00005667/*
5668 * Sort the results of file name expansion. It calculates the number of
5669 * strings to sort and then calls msort (short for merge sort) to do the
5670 * work.
5671 */
5672
5673static struct strlist *
5674expsort(str)
5675 struct strlist *str;
5676 {
5677 int len;
5678 struct strlist *sp;
5679
5680 len = 0;
5681 for (sp = str ; sp ; sp = sp->next)
5682 len++;
5683 return msort(str, len);
5684}
5685
5686
5687static struct strlist *
5688msort(list, len)
5689 struct strlist *list;
5690 int len;
5691{
5692 struct strlist *p, *q = NULL;
5693 struct strlist **lpp;
5694 int half;
5695 int n;
5696
5697 if (len <= 1)
5698 return list;
5699 half = len >> 1;
5700 p = list;
5701 for (n = half ; --n >= 0 ; ) {
5702 q = p;
5703 p = p->next;
5704 }
Eric Andersen2870d962001-07-02 17:27:21 +00005705 q->next = NULL; /* terminate first half of list */
5706 q = msort(list, half); /* sort first half of list */
5707 p = msort(p, len - half); /* sort second half */
Eric Andersencb57d552001-06-28 07:25:16 +00005708 lpp = &list;
5709 for (;;) {
5710 if (strcmp(p->text, q->text) < 0) {
5711 *lpp = p;
5712 lpp = &p->next;
5713 if ((p = *lpp) == NULL) {
5714 *lpp = q;
5715 break;
5716 }
5717 } else {
5718 *lpp = q;
5719 lpp = &q->next;
5720 if ((q = *lpp) == NULL) {
5721 *lpp = p;
5722 break;
5723 }
5724 }
5725 }
5726 return list;
5727}
5728#endif
5729
5730
5731
5732/*
5733 * Returns true if the pattern matches the string.
5734 */
5735
Eric Andersen62483552001-07-10 06:09:16 +00005736#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00005737/* squoted: string might have quote chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005738static int
Eric Andersen2870d962001-07-02 17:27:21 +00005739patmatch(char *pattern, char *string, int squoted)
5740{
Eric Andersencb57d552001-06-28 07:25:16 +00005741 const char *p;
5742 char *q;
5743
5744 p = preglob(pattern);
5745 q = squoted ? _rmescapes(string, RMESCAPE_ALLOC) : string;
5746
5747 return !fnmatch(p, q, 0);
5748}
5749
5750
5751static int
Eric Andersen2870d962001-07-02 17:27:21 +00005752patmatch2(char *pattern, char *string, int squoted)
5753{
Eric Andersencb57d552001-06-28 07:25:16 +00005754 char *p;
5755 int res;
5756
5757 sstrnleft--;
5758 p = grabstackstr(expdest);
5759 res = patmatch(pattern, string, squoted);
5760 ungrabstackstr(p, expdest);
5761 return res;
5762}
5763#else
5764static int
Eric Andersen2870d962001-07-02 17:27:21 +00005765patmatch(char *pattern, char *string, int squoted) {
5766 return pmatch(pattern, string, squoted);
Eric Andersencb57d552001-06-28 07:25:16 +00005767}
5768
5769
5770static int
Eric Andersen2870d962001-07-02 17:27:21 +00005771pmatch(char *pattern, char *string, int squoted)
5772{
Eric Andersencb57d552001-06-28 07:25:16 +00005773 char *p, *q;
5774 char c;
5775
5776 p = pattern;
5777 q = string;
5778 for (;;) {
5779 switch (c = *p++) {
5780 case '\0':
5781 goto breakloop;
5782 case CTLESC:
5783 if (squoted && *q == CTLESC)
5784 q++;
5785 if (*q++ != *p++)
5786 return 0;
5787 break;
5788 case CTLQUOTEMARK:
5789 continue;
5790 case '?':
5791 if (squoted && *q == CTLESC)
5792 q++;
5793 if (*q++ == '\0')
5794 return 0;
5795 break;
5796 case '*':
5797 c = *p;
5798 while (c == CTLQUOTEMARK || c == '*')
5799 c = *++p;
5800 if (c != CTLESC && c != CTLQUOTEMARK &&
5801 c != '?' && c != '*' && c != '[') {
5802 while (*q != c) {
5803 if (squoted && *q == CTLESC &&
5804 q[1] == c)
5805 break;
5806 if (*q == '\0')
5807 return 0;
5808 if (squoted && *q == CTLESC)
5809 q++;
5810 q++;
5811 }
5812 }
5813 do {
5814 if (pmatch(p, q, squoted))
5815 return 1;
5816 if (squoted && *q == CTLESC)
5817 q++;
5818 } while (*q++ != '\0');
5819 return 0;
5820 case '[': {
5821 char *endp;
5822 int invert, found;
5823 char chr;
5824
5825 endp = p;
5826 if (*endp == '!')
5827 endp++;
5828 for (;;) {
5829 while (*endp == CTLQUOTEMARK)
5830 endp++;
5831 if (*endp == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00005832 goto dft; /* no matching ] */
Eric Andersencb57d552001-06-28 07:25:16 +00005833 if (*endp == CTLESC)
5834 endp++;
5835 if (*++endp == ']')
5836 break;
5837 }
5838 invert = 0;
5839 if (*p == '!') {
5840 invert++;
5841 p++;
5842 }
5843 found = 0;
5844 chr = *q++;
5845 if (squoted && chr == CTLESC)
5846 chr = *q++;
5847 if (chr == '\0')
5848 return 0;
5849 c = *p++;
5850 do {
5851 if (c == CTLQUOTEMARK)
5852 continue;
5853 if (c == CTLESC)
5854 c = *p++;
5855 if (*p == '-' && p[1] != ']') {
5856 p++;
5857 while (*p == CTLQUOTEMARK)
5858 p++;
5859 if (*p == CTLESC)
5860 p++;
5861 if (chr >= c && chr <= *p)
5862 found = 1;
5863 p++;
5864 } else {
5865 if (chr == c)
5866 found = 1;
5867 }
5868 } while ((c = *p++) != ']');
5869 if (found == invert)
5870 return 0;
5871 break;
5872 }
Eric Andersen2870d962001-07-02 17:27:21 +00005873dft: default:
Eric Andersencb57d552001-06-28 07:25:16 +00005874 if (squoted && *q == CTLESC)
5875 q++;
5876 if (*q++ != c)
5877 return 0;
5878 break;
5879 }
5880 }
5881breakloop:
5882 if (*q != '\0')
5883 return 0;
5884 return 1;
5885}
5886#endif
5887
5888
5889
5890/*
5891 * Remove any CTLESC characters from a string.
5892 */
5893
Eric Andersen62483552001-07-10 06:09:16 +00005894#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00005895static char *
Eric Andersen2870d962001-07-02 17:27:21 +00005896_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005897{
5898 char *p, *q, *r;
5899 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5900
5901 p = strpbrk(str, qchars);
5902 if (!p) {
5903 return str;
5904 }
5905 q = p;
5906 r = str;
5907 if (flag & RMESCAPE_ALLOC) {
5908 size_t len = p - str;
5909 q = r = stalloc(strlen(p) + len + 1);
5910 if (len > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00005911 memcpy(q, str, len);
5912 q += len;
Eric Andersencb57d552001-06-28 07:25:16 +00005913 }
5914 }
5915 while (*p) {
5916 if (*p == CTLQUOTEMARK) {
5917 p++;
5918 continue;
5919 }
5920 if (*p == CTLESC) {
5921 p++;
5922 if (flag & RMESCAPE_GLOB && *p != '/') {
5923 *q++ = '\\';
5924 }
5925 }
5926 *q++ = *p++;
5927 }
5928 *q = '\0';
5929 return r;
5930}
5931#else
5932static void
5933rmescapes(str)
5934 char *str;
5935{
5936 char *p, *q;
5937
5938 p = str;
5939 while (*p != CTLESC && *p != CTLQUOTEMARK) {
5940 if (*p++ == '\0')
5941 return;
5942 }
5943 q = p;
5944 while (*p) {
5945 if (*p == CTLQUOTEMARK) {
5946 p++;
5947 continue;
5948 }
5949 if (*p == CTLESC)
5950 p++;
5951 *q++ = *p++;
5952 }
5953 *q = '\0';
5954}
5955#endif
5956
5957
5958
5959/*
5960 * See if a pattern matches in a case statement.
5961 */
5962
5963static int
Eric Andersen2870d962001-07-02 17:27:21 +00005964casematch(union node *pattern, const char *val)
5965{
Eric Andersencb57d552001-06-28 07:25:16 +00005966 struct stackmark smark;
5967 int result;
5968 char *p;
5969
5970 setstackmark(&smark);
5971 argbackq = pattern->narg.backquote;
5972 STARTSTACKSTR(expdest);
5973 ifslastp = NULL;
5974 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5975 STPUTC('\0', expdest);
5976 p = grabstackstr(expdest);
Eric Andersen2870d962001-07-02 17:27:21 +00005977 result = patmatch(p, (char *)val, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00005978 popstackmark(&smark);
5979 return result;
5980}
5981
5982/*
5983 * Our own itoa().
5984 */
5985
5986static char *
5987cvtnum(num, buf)
5988 int num;
5989 char *buf;
5990 {
5991 int len;
5992
5993 CHECKSTRSPACE(32, buf);
5994 len = sprintf(buf, "%d", num);
5995 STADJUST(len, buf);
5996 return buf;
5997}
Eric Andersencb57d552001-06-28 07:25:16 +00005998/*
5999 * Editline and history functions (and glue).
6000 */
6001static int histcmd(argc, argv)
6002 int argc;
6003 char **argv;
6004{
6005 error("not compiled with history support");
6006 /* NOTREACHED */
6007}
6008
6009
Eric Andersencb57d552001-06-28 07:25:16 +00006010struct redirtab {
6011 struct redirtab *next;
Russ Dill4db35642001-07-26 05:58:40 +00006012 short renamed[10]; /* Current ash support only 0-9 descriptors */
6013 /* char renamed[10]; */ /* char on arm (and others) can't be negative */
Eric Andersencb57d552001-06-28 07:25:16 +00006014};
6015
Eric Andersen2870d962001-07-02 17:27:21 +00006016static struct redirtab *redirlist;
Eric Andersencb57d552001-06-28 07:25:16 +00006017
6018extern char **environ;
6019
6020
6021
6022/*
6023 * Initialization code.
6024 */
6025
6026static void
Eric Andersen2870d962001-07-02 17:27:21 +00006027init(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00006028
6029 /* from cd.c: */
6030 {
6031 setpwd(0, 0);
6032 }
6033
6034 /* from input.c: */
6035 {
6036 basepf.nextc = basepf.buf = basebuf;
6037 }
6038
Eric Andersencb57d552001-06-28 07:25:16 +00006039 /* from var.c: */
6040 {
6041 char **envp;
6042 char ppid[32];
6043
6044 initvar();
6045 for (envp = environ ; *envp ; envp++) {
6046 if (strchr(*envp, '=')) {
6047 setvareq(*envp, VEXPORT|VTEXTFIXED);
6048 }
6049 }
6050
Eric Andersen3102ac42001-07-06 04:26:23 +00006051 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
Eric Andersencb57d552001-06-28 07:25:16 +00006052 setvar("PPID", ppid, 0);
6053 }
6054}
6055
6056
6057
6058/*
6059 * This routine is called when an error or an interrupt occurs in an
6060 * interactive shell and control is returned to the main command loop.
6061 */
6062
Eric Andersen2870d962001-07-02 17:27:21 +00006063/* 1 == check for aliases, 2 == also check for assignments */
Eric Andersen7467c8d2001-07-12 20:26:32 +00006064static int checkalias; /* also used in no alias mode for check assignments */
Eric Andersen2870d962001-07-02 17:27:21 +00006065
Eric Andersencb57d552001-06-28 07:25:16 +00006066static void
Eric Andersen2870d962001-07-02 17:27:21 +00006067reset(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00006068
6069 /* from eval.c: */
6070 {
6071 evalskip = 0;
6072 loopnest = 0;
6073 funcnest = 0;
6074 }
6075
6076 /* from input.c: */
6077 {
6078 if (exception != EXSHELLPROC)
Eric Andersen2870d962001-07-02 17:27:21 +00006079 parselleft = parsenleft = 0; /* clear input buffer */
Eric Andersencb57d552001-06-28 07:25:16 +00006080 popallfiles();
6081 }
6082
6083 /* from parser.c: */
6084 {
6085 tokpushback = 0;
6086 checkkwd = 0;
6087 checkalias = 0;
6088 }
6089
6090 /* from redir.c: */
6091 {
6092 while (redirlist)
6093 popredir();
6094 }
6095
Eric Andersencb57d552001-06-28 07:25:16 +00006096}
6097
6098
6099
6100/*
Eric Andersencb57d552001-06-28 07:25:16 +00006101 * This file implements the input routines used by the parser.
6102 */
6103
6104#ifdef BB_FEATURE_COMMAND_EDITING
Eric Andersencb57d552001-06-28 07:25:16 +00006105static const char * cmdedit_prompt;
6106static inline void putprompt(const char *s) {
6107 cmdedit_prompt = s;
6108}
6109#else
6110static inline void putprompt(const char *s) {
6111 out2str(s);
6112}
6113#endif
6114
Eric Andersen2870d962001-07-02 17:27:21 +00006115#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
Eric Andersencb57d552001-06-28 07:25:16 +00006116
Eric Andersencb57d552001-06-28 07:25:16 +00006117
Eric Andersencb57d552001-06-28 07:25:16 +00006118
Eric Andersen2870d962001-07-02 17:27:21 +00006119/*
6120 * Same as pgetc(), but ignores PEOA.
6121 */
Eric Andersencb57d552001-06-28 07:25:16 +00006122
Eric Andersen2870d962001-07-02 17:27:21 +00006123#ifdef ASH_ALIAS
6124static int
6125pgetc2()
6126{
6127 int c;
6128 do {
6129 c = pgetc_macro();
6130 } while (c == PEOA);
6131 return c;
Eric Andersencb57d552001-06-28 07:25:16 +00006132}
Eric Andersen2870d962001-07-02 17:27:21 +00006133#else
6134static inline int pgetc2() { return pgetc_macro(); }
Eric Andersencb57d552001-06-28 07:25:16 +00006135#endif
6136
Eric Andersencb57d552001-06-28 07:25:16 +00006137/*
6138 * Read a line from the script.
6139 */
6140
Eric Andersen62483552001-07-10 06:09:16 +00006141static inline char *
Eric Andersen2870d962001-07-02 17:27:21 +00006142pfgets(char *line, int len)
Eric Andersencb57d552001-06-28 07:25:16 +00006143{
6144 char *p = line;
6145 int nleft = len;
6146 int c;
6147
6148 while (--nleft > 0) {
6149 c = pgetc2();
6150 if (c == PEOF) {
6151 if (p == line)
6152 return NULL;
6153 break;
6154 }
6155 *p++ = c;
6156 if (c == '\n')
6157 break;
6158 }
6159 *p = '\0';
6160 return line;
6161}
6162
Eric Andersen62483552001-07-10 06:09:16 +00006163static inline int
Eric Andersen2870d962001-07-02 17:27:21 +00006164preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006165{
6166 int nr;
6167 char *buf = parsefile->buf;
6168 parsenextc = buf;
6169
6170retry:
6171#ifdef BB_FEATURE_COMMAND_EDITING
6172 {
Eric Andersenbc4c0302001-07-17 01:14:06 +00006173 if (parsefile->fd)
Eric Andersen7467c8d2001-07-12 20:26:32 +00006174 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersen2870d962001-07-02 17:27:21 +00006175 else {
Eric Andersen044228d2001-07-17 01:12:36 +00006176 nr = cmdedit_read_input((char*)cmdedit_prompt, buf);
Eric Andersencb57d552001-06-28 07:25:16 +00006177 }
6178 }
6179#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00006180 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006181#endif
6182
6183 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006184 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6185 int flags = fcntl(0, F_GETFL, 0);
6186 if (flags >= 0 && flags & O_NONBLOCK) {
6187 flags &=~ O_NONBLOCK;
6188 if (fcntl(0, F_SETFL, flags) >= 0) {
6189 out2str("sh: turning off NDELAY mode\n");
6190 goto retry;
6191 }
6192 }
6193 }
6194 }
6195 return nr;
6196}
6197
Eric Andersen2870d962001-07-02 17:27:21 +00006198static void
6199popstring(void)
6200{
6201 struct strpush *sp = parsefile->strpush;
6202
6203 INTOFF;
6204#ifdef ASH_ALIAS
6205 if (sp->ap) {
6206 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6207 if (!checkalias) {
6208 checkalias = 1;
6209 }
6210 }
6211 if (sp->string != sp->ap->val) {
6212 ckfree(sp->string);
6213 }
6214
6215 sp->ap->flag &= ~ALIASINUSE;
6216 if (sp->ap->flag & ALIASDEAD) {
6217 unalias(sp->ap->name);
6218 }
6219 }
6220#endif
6221 parsenextc = sp->prevstring;
6222 parsenleft = sp->prevnleft;
6223/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6224 parsefile->strpush = sp->prev;
6225 if (sp != &(parsefile->basestrpush))
6226 ckfree(sp);
6227 INTON;
6228}
6229
6230
Eric Andersencb57d552001-06-28 07:25:16 +00006231/*
6232 * Refill the input buffer and return the next input character:
6233 *
6234 * 1) If a string was pushed back on the input, pop it;
6235 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6236 * from a string so we can't refill the buffer, return EOF.
6237 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6238 * 4) Process input up to the next newline, deleting nul characters.
6239 */
6240
6241static int
Eric Andersen2870d962001-07-02 17:27:21 +00006242preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006243{
6244 char *p, *q;
6245 int more;
6246 char savec;
6247
6248 while (parsefile->strpush) {
Eric Andersen2870d962001-07-02 17:27:21 +00006249#ifdef ASH_ALIAS
6250 if (parsenleft == -1 && parsefile->strpush->ap &&
6251 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00006252 return PEOA;
6253 }
Eric Andersen2870d962001-07-02 17:27:21 +00006254#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006255 popstring();
6256 if (--parsenleft >= 0)
6257 return (*parsenextc++);
6258 }
6259 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6260 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00006261 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00006262
6263again:
6264 if (parselleft <= 0) {
6265 if ((parselleft = preadfd()) <= 0) {
6266 parselleft = parsenleft = EOF_NLEFT;
6267 return PEOF;
6268 }
6269 }
6270
6271 q = p = parsenextc;
6272
6273 /* delete nul characters */
6274 for (more = 1; more;) {
6275 switch (*p) {
6276 case '\0':
Eric Andersen2870d962001-07-02 17:27:21 +00006277 p++; /* Skip nul */
Eric Andersencb57d552001-06-28 07:25:16 +00006278 goto check;
6279
6280
6281 case '\n':
6282 parsenleft = q - parsenextc;
6283 more = 0; /* Stop processing here */
6284 break;
6285 }
6286
6287 *q++ = *p++;
6288check:
6289 if (--parselleft <= 0 && more) {
6290 parsenleft = q - parsenextc - 1;
6291 if (parsenleft < 0)
6292 goto again;
6293 more = 0;
6294 }
6295 }
6296
6297 savec = *q;
6298 *q = '\0';
6299
6300 if (vflag) {
6301 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00006302 }
6303
6304 *q = savec;
6305
6306 return *parsenextc++;
6307}
6308
Eric Andersencb57d552001-06-28 07:25:16 +00006309
6310/*
6311 * Push a string back onto the input at this current parsefile level.
6312 * We handle aliases this way.
6313 */
6314static void
Eric Andersen2870d962001-07-02 17:27:21 +00006315pushstring(char *s, int len, void *ap)
6316{
Eric Andersencb57d552001-06-28 07:25:16 +00006317 struct strpush *sp;
6318
6319 INTOFF;
6320/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6321 if (parsefile->strpush) {
6322 sp = ckmalloc(sizeof (struct strpush));
6323 sp->prev = parsefile->strpush;
6324 parsefile->strpush = sp;
6325 } else
6326 sp = parsefile->strpush = &(parsefile->basestrpush);
6327 sp->prevstring = parsenextc;
6328 sp->prevnleft = parsenleft;
Eric Andersen2870d962001-07-02 17:27:21 +00006329#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00006330 sp->ap = (struct alias *)ap;
6331 if (ap) {
6332 ((struct alias *)ap)->flag |= ALIASINUSE;
6333 sp->string = s;
6334 }
Eric Andersen2870d962001-07-02 17:27:21 +00006335#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006336 parsenextc = s;
6337 parsenleft = len;
6338 INTON;
6339}
6340
Eric Andersencb57d552001-06-28 07:25:16 +00006341
Eric Andersencb57d552001-06-28 07:25:16 +00006342/*
6343 * Like setinputfile, but takes input from a string.
6344 */
6345
6346static void
Eric Andersen62483552001-07-10 06:09:16 +00006347setinputstring(char *string)
6348{
Eric Andersencb57d552001-06-28 07:25:16 +00006349 INTOFF;
6350 pushfile();
6351 parsenextc = string;
6352 parsenleft = strlen(string);
6353 parsefile->buf = NULL;
6354 plinno = 1;
6355 INTON;
6356}
6357
6358
6359
6360/*
6361 * To handle the "." command, a stack of input files is used. Pushfile
6362 * adds a new entry to the stack and popfile restores the previous level.
6363 */
6364
6365static void
Eric Andersen2870d962001-07-02 17:27:21 +00006366pushfile(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00006367 struct parsefile *pf;
6368
6369 parsefile->nleft = parsenleft;
6370 parsefile->lleft = parselleft;
6371 parsefile->nextc = parsenextc;
6372 parsefile->linno = plinno;
6373 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6374 pf->prev = parsefile;
6375 pf->fd = -1;
6376 pf->strpush = NULL;
6377 pf->basestrpush.prev = NULL;
6378 parsefile = pf;
6379}
6380
Eric Andersen2870d962001-07-02 17:27:21 +00006381#ifdef JOBS
6382static void restartjob (struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00006383#endif
Eric Andersen2870d962001-07-02 17:27:21 +00006384static void freejob (struct job *);
6385static struct job *getjob (const char *);
6386static int dowait (int, struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00006387static void waitonint(int);
6388
6389
Eric Andersen2870d962001-07-02 17:27:21 +00006390/*
6391 * We keep track of whether or not fd0 has been redirected. This is for
6392 * background commands, where we want to redirect fd0 to /dev/null only
6393 * if it hasn't already been redirected.
6394*/
6395static int fd0_redirected = 0;
6396
6397/* Return true if fd 0 has already been redirected at least once. */
6398static inline int
6399fd0_redirected_p () {
6400 return fd0_redirected != 0;
6401}
6402
Eric Andersen62483552001-07-10 06:09:16 +00006403static void dupredirect (const union node *, int, int fd1dup);
Eric Andersen2870d962001-07-02 17:27:21 +00006404
6405#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006406/*
6407 * Turn job control on and off.
6408 *
6409 * Note: This code assumes that the third arg to ioctl is a character
6410 * pointer, which is true on Berkeley systems but not System V. Since
6411 * System V doesn't have job control yet, this isn't a problem now.
6412 */
6413
Eric Andersen2870d962001-07-02 17:27:21 +00006414
Eric Andersencb57d552001-06-28 07:25:16 +00006415
6416static void setjobctl(int enable)
6417{
6418#ifdef OLD_TTY_DRIVER
6419 int ldisc;
6420#endif
6421
6422 if (enable == jobctl || rootshell == 0)
6423 return;
6424 if (enable) {
6425 do { /* while we are in the background */
6426#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006427 if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006428#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006429 initialpgrp = tcgetpgrp(2);
Eric Andersencb57d552001-06-28 07:25:16 +00006430 if (initialpgrp < 0) {
6431#endif
Eric Andersen8c145dc2001-07-10 16:57:09 +00006432 out2str("sh: can't access tty; job control turned off\n");
Eric Andersencb57d552001-06-28 07:25:16 +00006433 mflag = 0;
6434 return;
6435 }
6436 if (initialpgrp == -1)
6437 initialpgrp = getpgrp();
6438 else if (initialpgrp != getpgrp()) {
6439 killpg(initialpgrp, SIGTTIN);
6440 continue;
6441 }
6442 } while (0);
6443#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006444 if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
Eric Andersen8c145dc2001-07-10 16:57:09 +00006445 out2str("sh: need new tty driver to run job control; job control turned off\n");
Eric Andersencb57d552001-06-28 07:25:16 +00006446 mflag = 0;
6447 return;
6448 }
6449#endif
6450 setsignal(SIGTSTP);
6451 setsignal(SIGTTOU);
6452 setsignal(SIGTTIN);
6453 setpgid(0, rootpid);
6454#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006455 ioctl(2, TIOCSPGRP, (char *)&rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00006456#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006457 tcsetpgrp(2, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00006458#endif
Eric Andersen8c145dc2001-07-10 16:57:09 +00006459 } else { /* turning job control off */
Eric Andersencb57d552001-06-28 07:25:16 +00006460 setpgid(0, initialpgrp);
6461#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006462 ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006463#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006464 tcsetpgrp(2, initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006465#endif
6466 setsignal(SIGTSTP);
6467 setsignal(SIGTTOU);
6468 setsignal(SIGTTIN);
6469 }
6470 jobctl = enable;
6471}
6472#endif
6473
6474
Eric Andersencb57d552001-06-28 07:25:16 +00006475/* A translation list so we can be polite to our users. */
6476static char *signal_names[NSIG + 2] = {
6477 "EXIT",
6478 "SIGHUP",
6479 "SIGINT",
6480 "SIGQUIT",
6481 "SIGILL",
6482 "SIGTRAP",
6483 "SIGABRT",
6484 "SIGBUS",
6485 "SIGFPE",
6486 "SIGKILL",
6487 "SIGUSR1",
6488 "SIGSEGV",
6489 "SIGUSR2",
6490 "SIGPIPE",
6491 "SIGALRM",
6492 "SIGTERM",
6493 "SIGJUNK(16)",
6494 "SIGCHLD",
6495 "SIGCONT",
6496 "SIGSTOP",
6497 "SIGTSTP",
6498 "SIGTTIN",
6499 "SIGTTOU",
6500 "SIGURG",
6501 "SIGXCPU",
6502 "SIGXFSZ",
6503 "SIGVTALRM",
6504 "SIGPROF",
6505 "SIGWINCH",
6506 "SIGIO",
6507 "SIGPWR",
6508 "SIGSYS",
Eric Andersen62483552001-07-10 06:09:16 +00006509#ifdef SIGRTMIN
Eric Andersencb57d552001-06-28 07:25:16 +00006510 "SIGRTMIN",
6511 "SIGRTMIN+1",
6512 "SIGRTMIN+2",
6513 "SIGRTMIN+3",
6514 "SIGRTMIN+4",
6515 "SIGRTMIN+5",
6516 "SIGRTMIN+6",
6517 "SIGRTMIN+7",
6518 "SIGRTMIN+8",
6519 "SIGRTMIN+9",
6520 "SIGRTMIN+10",
6521 "SIGRTMIN+11",
6522 "SIGRTMIN+12",
6523 "SIGRTMIN+13",
6524 "SIGRTMIN+14",
6525 "SIGRTMIN+15",
6526 "SIGRTMAX-15",
6527 "SIGRTMAX-14",
6528 "SIGRTMAX-13",
6529 "SIGRTMAX-12",
6530 "SIGRTMAX-11",
6531 "SIGRTMAX-10",
6532 "SIGRTMAX-9",
6533 "SIGRTMAX-8",
6534 "SIGRTMAX-7",
6535 "SIGRTMAX-6",
6536 "SIGRTMAX-5",
6537 "SIGRTMAX-4",
6538 "SIGRTMAX-3",
6539 "SIGRTMAX-2",
6540 "SIGRTMAX-1",
6541 "SIGRTMAX",
Eric Andersen62483552001-07-10 06:09:16 +00006542#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006543 "DEBUG",
6544 (char *)0x0,
6545};
6546
6547
6548
Eric Andersen2870d962001-07-02 17:27:21 +00006549#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006550static int
6551killcmd(argc, argv)
6552 int argc;
6553 char **argv;
6554{
6555 int signo = -1;
6556 int list = 0;
6557 int i;
6558 pid_t pid;
6559 struct job *jp;
6560
6561 if (argc <= 1) {
6562usage:
6563 error(
6564"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6565"kill -l [exitstatus]"
6566 );
6567 }
6568
6569 if (*argv[1] == '-') {
6570 signo = decode_signal(argv[1] + 1, 1);
6571 if (signo < 0) {
6572 int c;
6573
6574 while ((c = nextopt("ls:")) != '\0')
6575 switch (c) {
6576 case 'l':
6577 list = 1;
6578 break;
6579 case 's':
6580 signo = decode_signal(optionarg, 1);
6581 if (signo < 0) {
6582 error(
6583 "invalid signal number or name: %s",
6584 optionarg
6585 );
6586 }
Eric Andersen2870d962001-07-02 17:27:21 +00006587 break;
Eric Andersencb57d552001-06-28 07:25:16 +00006588#ifdef DEBUG
6589 default:
6590 error(
6591 "nextopt returned character code 0%o", c);
6592#endif
6593 }
6594 } else
6595 argptr++;
6596 }
6597
6598 if (!list && signo < 0)
6599 signo = SIGTERM;
6600
6601 if ((signo < 0 || !*argptr) ^ list) {
6602 goto usage;
6603 }
6604
6605 if (list) {
6606 if (!*argptr) {
6607 out1str("0\n");
6608 for (i = 1; i < NSIG; i++) {
Eric Andersen62483552001-07-10 06:09:16 +00006609 printf(snlfmt, signal_names[i] + 3);
Eric Andersencb57d552001-06-28 07:25:16 +00006610 }
6611 return 0;
6612 }
6613 signo = atoi(*argptr);
6614 if (signo > 128)
6615 signo -= 128;
6616 if (0 < signo && signo < NSIG)
Eric Andersen62483552001-07-10 06:09:16 +00006617 printf(snlfmt, signal_names[signo] + 3);
Eric Andersencb57d552001-06-28 07:25:16 +00006618 else
6619 error("invalid signal number or exit status: %s",
6620 *argptr);
6621 return 0;
6622 }
6623
6624 do {
6625 if (**argptr == '%') {
6626 jp = getjob(*argptr);
6627 if (jp->jobctl == 0)
6628 error("job %s not created under job control",
6629 *argptr);
6630 pid = -jp->ps[0].pid;
6631 } else
6632 pid = atoi(*argptr);
6633 if (kill(pid, signo) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00006634 error("%s: %m", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006635 } while (*++argptr);
6636
6637 return 0;
6638}
6639
6640static int
6641fgcmd(argc, argv)
6642 int argc;
6643 char **argv;
6644{
6645 struct job *jp;
6646 int pgrp;
6647 int status;
6648
6649 jp = getjob(argv[1]);
6650 if (jp->jobctl == 0)
6651 error("job not created under job control");
6652 pgrp = jp->ps[0].pid;
6653#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006654 ioctl(2, TIOCSPGRP, (char *)&pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006655#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006656 tcsetpgrp(2, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006657#endif
6658 restartjob(jp);
6659 INTOFF;
6660 status = waitforjob(jp);
6661 INTON;
6662 return status;
6663}
6664
6665
6666static int
6667bgcmd(argc, argv)
6668 int argc;
6669 char **argv;
6670{
6671 struct job *jp;
6672
6673 do {
6674 jp = getjob(*++argv);
6675 if (jp->jobctl == 0)
6676 error("job not created under job control");
6677 restartjob(jp);
6678 } while (--argc > 1);
6679 return 0;
6680}
6681
6682
6683static void
6684restartjob(jp)
6685 struct job *jp;
6686{
6687 struct procstat *ps;
6688 int i;
6689
6690 if (jp->state == JOBDONE)
6691 return;
6692 INTOFF;
6693 killpg(jp->ps[0].pid, SIGCONT);
6694 for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
6695 if (WIFSTOPPED(ps->status)) {
6696 ps->status = -1;
6697 jp->state = 0;
6698 }
6699 }
6700 INTON;
6701}
6702#endif
6703
Eric Andersen2870d962001-07-02 17:27:21 +00006704static void showjobs(int change);
6705
Eric Andersencb57d552001-06-28 07:25:16 +00006706
6707static int
6708jobscmd(argc, argv)
6709 int argc;
6710 char **argv;
6711{
6712 showjobs(0);
6713 return 0;
6714}
6715
6716
6717/*
6718 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6719 * statuses have changed since the last call to showjobs.
6720 *
6721 * If the shell is interrupted in the process of creating a job, the
6722 * result may be a job structure containing zero processes. Such structures
6723 * will be freed here.
6724 */
6725
6726static void
6727showjobs(change)
6728 int change;
6729{
6730 int jobno;
6731 int procno;
6732 int i;
6733 struct job *jp;
6734 struct procstat *ps;
6735 int col;
6736 char s[64];
6737
6738 TRACE(("showjobs(%d) called\n", change));
6739 while (dowait(0, (struct job *)NULL) > 0);
6740 for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
6741 if (! jp->used)
6742 continue;
6743 if (jp->nprocs == 0) {
6744 freejob(jp);
6745 continue;
6746 }
6747 if (change && ! jp->changed)
6748 continue;
6749 procno = jp->nprocs;
Eric Andersen2870d962001-07-02 17:27:21 +00006750 for (ps = jp->ps ; ; ps++) { /* for each process */
Eric Andersencb57d552001-06-28 07:25:16 +00006751 if (ps == jp->ps)
Eric Andersen3102ac42001-07-06 04:26:23 +00006752 snprintf(s, 64, "[%d] %ld ", jobno,
Eric Andersencb57d552001-06-28 07:25:16 +00006753 (long)ps->pid);
6754 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006755 snprintf(s, 64, " %ld ",
Eric Andersencb57d552001-06-28 07:25:16 +00006756 (long)ps->pid);
6757 out1str(s);
6758 col = strlen(s);
6759 s[0] = '\0';
6760 if (ps->status == -1) {
6761 /* don't print anything */
6762 } else if (WIFEXITED(ps->status)) {
Eric Andersen3102ac42001-07-06 04:26:23 +00006763 snprintf(s, 64, "Exit %d",
Eric Andersencb57d552001-06-28 07:25:16 +00006764 WEXITSTATUS(ps->status));
6765 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00006766#ifdef JOBS
6767 if (WIFSTOPPED(ps->status))
Eric Andersencb57d552001-06-28 07:25:16 +00006768 i = WSTOPSIG(ps->status);
6769 else /* WIFSIGNALED(ps->status) */
6770#endif
6771 i = WTERMSIG(ps->status);
6772 if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
Eric Andersen2870d962001-07-02 17:27:21 +00006773 strcpy(s, sys_siglist[i & 0x7F]);
Eric Andersencb57d552001-06-28 07:25:16 +00006774 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006775 snprintf(s, 64, "Signal %d", i & 0x7F);
Eric Andersencb57d552001-06-28 07:25:16 +00006776 if (WCOREDUMP(ps->status))
6777 strcat(s, " (core dumped)");
6778 }
6779 out1str(s);
6780 col += strlen(s);
Eric Andersen62483552001-07-10 06:09:16 +00006781 printf(
Eric Andersencb57d552001-06-28 07:25:16 +00006782 "%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ',
6783 ps->cmd
6784 );
6785 if (--procno <= 0)
6786 break;
6787 }
6788 jp->changed = 0;
6789 if (jp->state == JOBDONE) {
6790 freejob(jp);
6791 }
6792 }
6793}
6794
6795
6796/*
6797 * Mark a job structure as unused.
6798 */
6799
6800static void
Eric Andersen62483552001-07-10 06:09:16 +00006801freejob(struct job *jp)
6802{
6803 const struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006804 int i;
6805
6806 INTOFF;
6807 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6808 if (ps->cmd != nullstr)
6809 ckfree(ps->cmd);
6810 }
6811 if (jp->ps != &jp->ps0)
6812 ckfree(jp->ps);
6813 jp->used = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006814#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006815 if (curjob == jp - jobtab + 1)
6816 curjob = 0;
6817#endif
6818 INTON;
6819}
6820
6821
6822
6823static int
6824waitcmd(argc, argv)
6825 int argc;
6826 char **argv;
6827{
6828 struct job *job;
6829 int status, retval;
6830 struct job *jp;
6831
6832 if (--argc > 0) {
6833start:
6834 job = getjob(*++argv);
6835 } else {
6836 job = NULL;
6837 }
Eric Andersen2870d962001-07-02 17:27:21 +00006838 for (;;) { /* loop until process terminated or stopped */
Eric Andersencb57d552001-06-28 07:25:16 +00006839 if (job != NULL) {
6840 if (job->state) {
6841 status = job->ps[job->nprocs - 1].status;
6842 if (! iflag)
6843 freejob(job);
6844 if (--argc) {
6845 goto start;
6846 }
6847 if (WIFEXITED(status))
6848 retval = WEXITSTATUS(status);
Eric Andersen2870d962001-07-02 17:27:21 +00006849#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006850 else if (WIFSTOPPED(status))
6851 retval = WSTOPSIG(status) + 128;
6852#endif
6853 else {
6854 /* XXX: limits number of signals */
6855 retval = WTERMSIG(status) + 128;
6856 }
6857 return retval;
6858 }
6859 } else {
6860 for (jp = jobtab ; ; jp++) {
Eric Andersen2870d962001-07-02 17:27:21 +00006861 if (jp >= jobtab + njobs) { /* no running procs */
Eric Andersencb57d552001-06-28 07:25:16 +00006862 return 0;
6863 }
6864 if (jp->used && jp->state == 0)
6865 break;
6866 }
6867 }
6868 if (dowait(2, 0) < 0 && errno == EINTR) {
6869 return 129;
6870 }
6871 }
6872}
6873
6874
6875
6876/*
6877 * Convert a job name to a job structure.
6878 */
6879
6880static struct job *
Eric Andersen2870d962001-07-02 17:27:21 +00006881getjob(const char *name)
6882{
Eric Andersencb57d552001-06-28 07:25:16 +00006883 int jobno;
6884 struct job *jp;
6885 int pid;
6886 int i;
6887
6888 if (name == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00006889#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006890currentjob:
6891 if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
6892 error("No current job");
6893 return &jobtab[jobno - 1];
6894#else
6895 error("No current job");
6896#endif
6897 } else if (name[0] == '%') {
6898 if (is_digit(name[1])) {
6899 jobno = number(name + 1);
6900 if (jobno > 0 && jobno <= njobs
6901 && jobtab[jobno - 1].used != 0)
6902 return &jobtab[jobno - 1];
Eric Andersen2870d962001-07-02 17:27:21 +00006903#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006904 } else if (name[1] == '%' && name[2] == '\0') {
6905 goto currentjob;
6906#endif
6907 } else {
6908 struct job *found = NULL;
6909 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
6910 if (jp->used && jp->nprocs > 0
6911 && prefix(name + 1, jp->ps[0].cmd)) {
6912 if (found)
6913 error("%s: ambiguous", name);
6914 found = jp;
6915 }
6916 }
6917 if (found)
6918 return found;
6919 }
Eric Andersen2870d962001-07-02 17:27:21 +00006920 } else if (is_number(name, &pid)) {
Eric Andersencb57d552001-06-28 07:25:16 +00006921 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
6922 if (jp->used && jp->nprocs > 0
6923 && jp->ps[jp->nprocs - 1].pid == pid)
6924 return jp;
6925 }
6926 }
6927 error("No such job: %s", name);
6928 /* NOTREACHED */
6929}
6930
6931
6932
6933/*
6934 * Return a new job structure,
6935 */
6936
Eric Andersen2870d962001-07-02 17:27:21 +00006937static struct job *
Eric Andersen62483552001-07-10 06:09:16 +00006938makejob(const union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00006939{
6940 int i;
6941 struct job *jp;
6942
6943 for (i = njobs, jp = jobtab ; ; jp++) {
6944 if (--i < 0) {
6945 INTOFF;
6946 if (njobs == 0) {
6947 jobtab = ckmalloc(4 * sizeof jobtab[0]);
6948 } else {
6949 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
6950 memcpy(jp, jobtab, njobs * sizeof jp[0]);
6951 /* Relocate `ps' pointers */
6952 for (i = 0; i < njobs; i++)
6953 if (jp[i].ps == &jobtab[i].ps0)
6954 jp[i].ps = &jp[i].ps0;
6955 ckfree(jobtab);
6956 jobtab = jp;
6957 }
6958 jp = jobtab + njobs;
6959 for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
6960 INTON;
6961 break;
6962 }
6963 if (jp->used == 0)
6964 break;
6965 }
6966 INTOFF;
6967 jp->state = 0;
6968 jp->used = 1;
6969 jp->changed = 0;
6970 jp->nprocs = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006971#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006972 jp->jobctl = jobctl;
6973#endif
6974 if (nprocs > 1) {
6975 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
6976 } else {
6977 jp->ps = &jp->ps0;
6978 }
6979 INTON;
6980 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
6981 jp - jobtab + 1));
6982 return jp;
6983}
6984
6985
6986/*
6987 * Fork of a subshell. If we are doing job control, give the subshell its
6988 * own process group. Jp is a job structure that the job is to be added to.
6989 * N is the command that will be evaluated by the child. Both jp and n may
6990 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00006991 * FORK_FG - Fork off a foreground process.
6992 * FORK_BG - Fork off a background process.
6993 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
6994 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00006995 *
6996 * When job control is turned off, background processes have their standard
6997 * input redirected to /dev/null (except for the second and later processes
6998 * in a pipeline).
6999 */
7000
Eric Andersen2870d962001-07-02 17:27:21 +00007001
7002
Eric Andersencb57d552001-06-28 07:25:16 +00007003static int
Eric Andersen62483552001-07-10 06:09:16 +00007004forkshell(struct job *jp, const union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00007005{
7006 int pid;
Eric Andersen62483552001-07-10 06:09:16 +00007007#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007008 int pgrp;
Eric Andersen62483552001-07-10 06:09:16 +00007009#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007010 const char *devnull = _PATH_DEVNULL;
7011 const char *nullerr = "Can't open %s";
7012
7013 TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
7014 mode));
7015 INTOFF;
7016 pid = fork();
7017 if (pid == -1) {
7018 TRACE(("Fork failed, errno=%d\n", errno));
7019 INTON;
7020 error("Cannot fork");
7021 }
7022 if (pid == 0) {
7023 struct job *p;
7024 int wasroot;
7025 int i;
7026
7027 TRACE(("Child shell %d\n", getpid()));
7028 wasroot = rootshell;
7029 rootshell = 0;
7030 closescript();
7031 INTON;
7032 clear_traps();
Eric Andersen2870d962001-07-02 17:27:21 +00007033#ifdef JOBS
7034 jobctl = 0; /* do job control only in root shell */
Eric Andersencb57d552001-06-28 07:25:16 +00007035 if (wasroot && mode != FORK_NOJOB && mflag) {
7036 if (jp == NULL || jp->nprocs == 0)
7037 pgrp = getpid();
7038 else
7039 pgrp = jp->ps[0].pid;
7040 setpgid(0, pgrp);
7041 if (mode == FORK_FG) {
7042 /*** this causes superfluous TIOCSPGRPS ***/
7043#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00007044 if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007045 error("TIOCSPGRP failed, errno=%d", errno);
7046#else
Eric Andersen3102ac42001-07-06 04:26:23 +00007047 if (tcsetpgrp(2, pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007048 error("tcsetpgrp failed, errno=%d", errno);
7049#endif
7050 }
7051 setsignal(SIGTSTP);
7052 setsignal(SIGTTOU);
7053 } else if (mode == FORK_BG) {
7054 ignoresig(SIGINT);
7055 ignoresig(SIGQUIT);
7056 if ((jp == NULL || jp->nprocs == 0) &&
7057 ! fd0_redirected_p ()) {
7058 close(0);
7059 if (open(devnull, O_RDONLY) != 0)
7060 error(nullerr, devnull);
7061 }
7062 }
7063#else
7064 if (mode == FORK_BG) {
7065 ignoresig(SIGINT);
7066 ignoresig(SIGQUIT);
7067 if ((jp == NULL || jp->nprocs == 0) &&
7068 ! fd0_redirected_p ()) {
7069 close(0);
7070 if (open(devnull, O_RDONLY) != 0)
7071 error(nullerr, devnull);
7072 }
7073 }
7074#endif
7075 for (i = njobs, p = jobtab ; --i >= 0 ; p++)
7076 if (p->used)
7077 freejob(p);
7078 if (wasroot && iflag) {
7079 setsignal(SIGINT);
7080 setsignal(SIGQUIT);
7081 setsignal(SIGTERM);
7082 }
7083 return pid;
7084 }
Eric Andersen62483552001-07-10 06:09:16 +00007085#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007086 if (rootshell && mode != FORK_NOJOB && mflag) {
7087 if (jp == NULL || jp->nprocs == 0)
7088 pgrp = pid;
7089 else
7090 pgrp = jp->ps[0].pid;
7091 setpgid(pid, pgrp);
7092 }
Eric Andersen62483552001-07-10 06:09:16 +00007093#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007094 if (mode == FORK_BG)
Eric Andersen2870d962001-07-02 17:27:21 +00007095 backgndpid = pid; /* set $! */
Eric Andersencb57d552001-06-28 07:25:16 +00007096 if (jp) {
7097 struct procstat *ps = &jp->ps[jp->nprocs++];
7098 ps->pid = pid;
7099 ps->status = -1;
7100 ps->cmd = nullstr;
7101 if (iflag && rootshell && n)
7102 ps->cmd = commandtext(n);
7103 }
7104 INTON;
7105 TRACE(("In parent shell: child = %d\n", pid));
7106 return pid;
7107}
7108
7109
7110
7111/*
7112 * Wait for job to finish.
7113 *
7114 * Under job control we have the problem that while a child process is
7115 * running interrupts generated by the user are sent to the child but not
7116 * to the shell. This means that an infinite loop started by an inter-
7117 * active user may be hard to kill. With job control turned off, an
7118 * interactive user may place an interactive program inside a loop. If
7119 * the interactive program catches interrupts, the user doesn't want
7120 * these interrupts to also abort the loop. The approach we take here
7121 * is to have the shell ignore interrupt signals while waiting for a
7122 * forground process to terminate, and then send itself an interrupt
7123 * signal if the child process was terminated by an interrupt signal.
7124 * Unfortunately, some programs want to do a bit of cleanup and then
7125 * exit on interrupt; unless these processes terminate themselves by
7126 * sending a signal to themselves (instead of calling exit) they will
7127 * confuse this approach.
7128 */
7129
7130static int
Eric Andersen62483552001-07-10 06:09:16 +00007131waitforjob(struct job *jp)
7132{
Eric Andersen2870d962001-07-02 17:27:21 +00007133#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007134 int mypgrp = getpgrp();
7135#endif
7136 int status;
7137 int st;
7138 struct sigaction act, oact;
7139
7140 INTOFF;
7141 intreceived = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00007142#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007143 if (!jobctl) {
7144#else
7145 if (!iflag) {
7146#endif
7147 sigaction(SIGINT, 0, &act);
7148 act.sa_handler = waitonint;
7149 sigaction(SIGINT, &act, &oact);
7150 }
7151 TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
7152 while (jp->state == 0) {
7153 dowait(1, jp);
7154 }
Eric Andersen2870d962001-07-02 17:27:21 +00007155#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007156 if (!jobctl) {
7157#else
7158 if (!iflag) {
7159#endif
7160 sigaction(SIGINT, &oact, 0);
7161 if (intreceived && trap[SIGINT]) kill(getpid(), SIGINT);
7162 }
Eric Andersen2870d962001-07-02 17:27:21 +00007163#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007164 if (jp->jobctl) {
7165#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00007166 if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007167 error("TIOCSPGRP failed, errno=%d\n", errno);
7168#else
Eric Andersen3102ac42001-07-06 04:26:23 +00007169 if (tcsetpgrp(2, mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007170 error("tcsetpgrp failed, errno=%d\n", errno);
7171#endif
7172 }
7173 if (jp->state == JOBSTOPPED)
7174 curjob = jp - jobtab + 1;
7175#endif
7176 status = jp->ps[jp->nprocs - 1].status;
7177 /* convert to 8 bits */
7178 if (WIFEXITED(status))
7179 st = WEXITSTATUS(status);
Eric Andersen2870d962001-07-02 17:27:21 +00007180#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007181 else if (WIFSTOPPED(status))
7182 st = WSTOPSIG(status) + 128;
7183#endif
7184 else
7185 st = WTERMSIG(status) + 128;
Eric Andersen2870d962001-07-02 17:27:21 +00007186#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007187 if (jp->jobctl) {
7188 /*
7189 * This is truly gross.
7190 * If we're doing job control, then we did a TIOCSPGRP which
7191 * caused us (the shell) to no longer be in the controlling
7192 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7193 * intuit from the subprocess exit status whether a SIGINT
7194 * occured, and if so interrupt ourselves. Yuck. - mycroft
7195 */
7196 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
7197 raise(SIGINT);
7198 }
Eric Andersen2870d962001-07-02 17:27:21 +00007199 if (jp->state == JOBDONE)
7200
Eric Andersencb57d552001-06-28 07:25:16 +00007201#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007202 freejob(jp);
7203 INTON;
7204 return st;
7205}
7206
7207
7208
7209/*
7210 * Wait for a process to terminate.
7211 */
7212
Eric Andersen62483552001-07-10 06:09:16 +00007213/*
7214 * Do a wait system call. If job control is compiled in, we accept
7215 * stopped processes. If block is zero, we return a value of zero
7216 * rather than blocking.
7217 *
7218 * System V doesn't have a non-blocking wait system call. It does
7219 * have a SIGCLD signal that is sent to a process when one of it's
7220 * children dies. The obvious way to use SIGCLD would be to install
7221 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7222 * was received, and have waitproc bump another counter when it got
7223 * the status of a process. Waitproc would then know that a wait
7224 * system call would not block if the two counters were different.
7225 * This approach doesn't work because if a process has children that
7226 * have not been waited for, System V will send it a SIGCLD when it
7227 * installs a signal handler for SIGCLD. What this means is that when
7228 * a child exits, the shell will be sent SIGCLD signals continuously
7229 * until is runs out of stack space, unless it does a wait call before
7230 * restoring the signal handler. The code below takes advantage of
7231 * this (mis)feature by installing a signal handler for SIGCLD and
7232 * then checking to see whether it was called. If there are any
7233 * children to be waited for, it will be.
7234 *
7235 */
7236
7237static inline int
7238waitproc(int block, int *status)
7239{
7240 int flags;
7241
7242 flags = 0;
7243#ifdef JOBS
7244 if (jobctl)
7245 flags |= WUNTRACED;
7246#endif
7247 if (block == 0)
7248 flags |= WNOHANG;
7249 return wait3(status, flags, (struct rusage *)NULL);
7250}
7251
Eric Andersencb57d552001-06-28 07:25:16 +00007252static int
Eric Andersen62483552001-07-10 06:09:16 +00007253dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00007254{
7255 int pid;
7256 int status;
7257 struct procstat *sp;
7258 struct job *jp;
7259 struct job *thisjob;
7260 int done;
7261 int stopped;
7262 int core;
7263 int sig;
7264
7265 TRACE(("dowait(%d) called\n", block));
7266 do {
7267 pid = waitproc(block, &status);
7268 TRACE(("wait returns %d, status=%d\n", pid, status));
7269 } while (!(block & 2) && pid == -1 && errno == EINTR);
7270 if (pid <= 0)
7271 return pid;
7272 INTOFF;
7273 thisjob = NULL;
7274 for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
7275 if (jp->used) {
7276 done = 1;
7277 stopped = 1;
7278 for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
7279 if (sp->pid == -1)
7280 continue;
7281 if (sp->pid == pid) {
7282 TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
7283 sp->status = status;
7284 thisjob = jp;
7285 }
7286 if (sp->status == -1)
7287 stopped = 0;
7288 else if (WIFSTOPPED(sp->status))
7289 done = 0;
7290 }
Eric Andersen2870d962001-07-02 17:27:21 +00007291 if (stopped) { /* stopped or done */
Eric Andersencb57d552001-06-28 07:25:16 +00007292 int state = done? JOBDONE : JOBSTOPPED;
7293 if (jp->state != state) {
7294 TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
7295 jp->state = state;
Eric Andersen2870d962001-07-02 17:27:21 +00007296#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007297 if (done && curjob == jp - jobtab + 1)
Eric Andersen2870d962001-07-02 17:27:21 +00007298 curjob = 0; /* no current job */
Eric Andersencb57d552001-06-28 07:25:16 +00007299#endif
7300 }
7301 }
7302 }
7303 }
7304 INTON;
7305 if (! rootshell || ! iflag || (job && thisjob == job)) {
7306 core = WCOREDUMP(status);
Eric Andersen2870d962001-07-02 17:27:21 +00007307#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007308 if (WIFSTOPPED(status)) sig = WSTOPSIG(status);
7309 else
7310#endif
7311 if (WIFEXITED(status)) sig = 0;
7312 else sig = WTERMSIG(status);
7313
7314 if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
7315 if (thisjob != job)
Eric Andersen3102ac42001-07-06 04:26:23 +00007316 out2fmt("%d: ", pid);
Eric Andersen2870d962001-07-02 17:27:21 +00007317#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007318 if (sig == SIGTSTP && rootshell && iflag)
Eric Andersen3102ac42001-07-06 04:26:23 +00007319 out2fmt("%%%ld ",
Eric Andersencb57d552001-06-28 07:25:16 +00007320 (long)(job - jobtab + 1));
7321#endif
7322 if (sig < NSIG && sys_siglist[sig])
7323 out2str(sys_siglist[sig]);
7324 else
Eric Andersen3102ac42001-07-06 04:26:23 +00007325 out2fmt("Signal %d", sig);
Eric Andersencb57d552001-06-28 07:25:16 +00007326 if (core)
7327 out2str(" - core dumped");
7328 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00007329 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00007330 TRACE(("Not printing status: status=%d, sig=%d\n",
Eric Andersencb57d552001-06-28 07:25:16 +00007331 status, sig));
7332 }
7333 } else {
7334 TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
7335 if (thisjob)
7336 thisjob->changed = 1;
7337 }
7338 return pid;
7339}
7340
7341
7342
Eric Andersencb57d552001-06-28 07:25:16 +00007343
7344/*
7345 * return 1 if there are stopped jobs, otherwise 0
7346 */
Eric Andersencb57d552001-06-28 07:25:16 +00007347static int
Eric Andersen2870d962001-07-02 17:27:21 +00007348stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007349{
7350 int jobno;
7351 struct job *jp;
7352
7353 if (job_warning)
7354 return (0);
7355 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
7356 if (jp->used == 0)
7357 continue;
7358 if (jp->state == JOBSTOPPED) {
7359 out2str("You have stopped jobs.\n");
7360 job_warning = 2;
7361 return (1);
7362 }
7363 }
7364
7365 return (0);
7366}
7367
7368/*
7369 * Return a string identifying a command (to be printed by the
7370 * jobs command.
7371 */
7372
7373static char *cmdnextc;
7374static int cmdnleft;
Eric Andersen2870d962001-07-02 17:27:21 +00007375#define MAXCMDTEXT 200
Eric Andersencb57d552001-06-28 07:25:16 +00007376
Eric Andersen2870d962001-07-02 17:27:21 +00007377static void
7378cmdputs(const char *s)
7379{
7380 const char *p;
7381 char *q;
7382 char c;
7383 int subtype = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007384
Eric Andersen2870d962001-07-02 17:27:21 +00007385 if (cmdnleft <= 0)
7386 return;
7387 p = s;
7388 q = cmdnextc;
7389 while ((c = *p++) != '\0') {
7390 if (c == CTLESC)
7391 *q++ = *p++;
7392 else if (c == CTLVAR) {
7393 *q++ = '$';
7394 if (--cmdnleft > 0)
7395 *q++ = '{';
7396 subtype = *p++;
7397 } else if (c == '=' && subtype != 0) {
7398 *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
7399 subtype = 0;
7400 } else if (c == CTLENDVAR) {
7401 *q++ = '}';
7402 } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
7403 cmdnleft++; /* ignore it */
7404 else
7405 *q++ = c;
7406 if (--cmdnleft <= 0) {
7407 *q++ = '.';
7408 *q++ = '.';
7409 *q++ = '.';
7410 break;
7411 }
7412 }
7413 cmdnextc = q;
Eric Andersencb57d552001-06-28 07:25:16 +00007414}
7415
7416
7417static void
Eric Andersen2870d962001-07-02 17:27:21 +00007418cmdtxt(const union node *n)
7419{
Eric Andersencb57d552001-06-28 07:25:16 +00007420 union node *np;
7421 struct nodelist *lp;
7422 const char *p;
7423 int i;
7424 char s[2];
7425
7426 if (n == NULL)
7427 return;
7428 switch (n->type) {
7429 case NSEMI:
7430 cmdtxt(n->nbinary.ch1);
7431 cmdputs("; ");
7432 cmdtxt(n->nbinary.ch2);
7433 break;
7434 case NAND:
7435 cmdtxt(n->nbinary.ch1);
7436 cmdputs(" && ");
7437 cmdtxt(n->nbinary.ch2);
7438 break;
7439 case NOR:
7440 cmdtxt(n->nbinary.ch1);
7441 cmdputs(" || ");
7442 cmdtxt(n->nbinary.ch2);
7443 break;
7444 case NPIPE:
7445 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7446 cmdtxt(lp->n);
7447 if (lp->next)
7448 cmdputs(" | ");
7449 }
7450 break;
7451 case NSUBSHELL:
7452 cmdputs("(");
7453 cmdtxt(n->nredir.n);
7454 cmdputs(")");
7455 break;
7456 case NREDIR:
7457 case NBACKGND:
7458 cmdtxt(n->nredir.n);
7459 break;
7460 case NIF:
7461 cmdputs("if ");
7462 cmdtxt(n->nif.test);
7463 cmdputs("; then ");
7464 cmdtxt(n->nif.ifpart);
7465 cmdputs("...");
7466 break;
7467 case NWHILE:
7468 cmdputs("while ");
7469 goto until;
7470 case NUNTIL:
7471 cmdputs("until ");
7472until:
7473 cmdtxt(n->nbinary.ch1);
7474 cmdputs("; do ");
7475 cmdtxt(n->nbinary.ch2);
7476 cmdputs("; done");
7477 break;
7478 case NFOR:
7479 cmdputs("for ");
7480 cmdputs(n->nfor.var);
7481 cmdputs(" in ...");
7482 break;
7483 case NCASE:
7484 cmdputs("case ");
7485 cmdputs(n->ncase.expr->narg.text);
7486 cmdputs(" in ...");
7487 break;
7488 case NDEFUN:
7489 cmdputs(n->narg.text);
7490 cmdputs("() ...");
7491 break;
7492 case NCMD:
7493 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7494 cmdtxt(np);
7495 if (np->narg.next)
7496 cmdputs(spcstr);
7497 }
7498 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7499 cmdputs(spcstr);
7500 cmdtxt(np);
7501 }
7502 break;
7503 case NARG:
7504 cmdputs(n->narg.text);
7505 break;
7506 case NTO:
7507 p = ">"; i = 1; goto redir;
7508 case NAPPEND:
7509 p = ">>"; i = 1; goto redir;
7510 case NTOFD:
7511 p = ">&"; i = 1; goto redir;
7512 case NTOOV:
7513 p = ">|"; i = 1; goto redir;
7514 case NFROM:
7515 p = "<"; i = 0; goto redir;
7516 case NFROMFD:
7517 p = "<&"; i = 0; goto redir;
7518 case NFROMTO:
7519 p = "<>"; i = 0; goto redir;
7520redir:
7521 if (n->nfile.fd != i) {
7522 s[0] = n->nfile.fd + '0';
7523 s[1] = '\0';
7524 cmdputs(s);
7525 }
7526 cmdputs(p);
7527 if (n->type == NTOFD || n->type == NFROMFD) {
7528 s[0] = n->ndup.dupfd + '0';
7529 s[1] = '\0';
7530 cmdputs(s);
7531 } else {
7532 cmdtxt(n->nfile.fname);
7533 }
7534 break;
7535 case NHERE:
7536 case NXHERE:
7537 cmdputs("<<...");
7538 break;
7539 default:
7540 cmdputs("???");
7541 break;
7542 }
7543}
7544
7545
Eric Andersen2870d962001-07-02 17:27:21 +00007546static char *
7547commandtext(const union node *n)
7548{
7549 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007550
Eric Andersen2870d962001-07-02 17:27:21 +00007551 cmdnextc = name = ckmalloc(MAXCMDTEXT);
7552 cmdnleft = MAXCMDTEXT - 4;
7553 cmdtxt(n);
7554 *cmdnextc = '\0';
7555 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00007556}
7557
Eric Andersen2870d962001-07-02 17:27:21 +00007558
Eric Andersencb57d552001-06-28 07:25:16 +00007559static void waitonint(int sig) {
7560 intreceived = 1;
7561 return;
7562}
Eric Andersencb57d552001-06-28 07:25:16 +00007563/*
7564 * Routines to check for mail. (Perhaps make part of main.c?)
7565 */
7566
7567
7568#define MAXMBOXES 10
7569
7570
Eric Andersen2870d962001-07-02 17:27:21 +00007571static int nmboxes; /* number of mailboxes */
7572static time_t mailtime[MAXMBOXES]; /* times of mailboxes */
Eric Andersencb57d552001-06-28 07:25:16 +00007573
7574
7575
7576/*
7577 * Print appropriate message(s) if mail has arrived. If the argument is
7578 * nozero, then the value of MAIL has changed, so we just update the
7579 * values.
7580 */
7581
7582static void
Eric Andersen2870d962001-07-02 17:27:21 +00007583chkmail(int silent)
Eric Andersencb57d552001-06-28 07:25:16 +00007584{
7585 int i;
7586 const char *mpath;
7587 char *p;
7588 char *q;
7589 struct stackmark smark;
7590 struct stat statb;
7591
7592 if (silent)
7593 nmboxes = 10;
7594 if (nmboxes == 0)
7595 return;
7596 setstackmark(&smark);
7597 mpath = mpathset()? mpathval() : mailval();
7598 for (i = 0 ; i < nmboxes ; i++) {
7599 p = padvance(&mpath, nullstr);
7600 if (p == NULL)
7601 break;
7602 if (*p == '\0')
7603 continue;
7604 for (q = p ; *q ; q++);
7605#ifdef DEBUG
7606 if (q[-1] != '/')
7607 abort();
7608#endif
Eric Andersen2870d962001-07-02 17:27:21 +00007609 q[-1] = '\0'; /* delete trailing '/' */
Eric Andersencb57d552001-06-28 07:25:16 +00007610 if (stat(p, &statb) < 0)
7611 statb.st_size = 0;
7612 if (statb.st_size > mailtime[i] && ! silent) {
Eric Andersen3102ac42001-07-06 04:26:23 +00007613 out2fmt(snlfmt,
7614 pathopt? pathopt : "you have mail");
Eric Andersencb57d552001-06-28 07:25:16 +00007615 }
7616 mailtime[i] = statb.st_size;
Eric Andersencb57d552001-06-28 07:25:16 +00007617 }
7618 nmboxes = i;
7619 popstackmark(&smark);
7620}
Eric Andersencb57d552001-06-28 07:25:16 +00007621
7622#define PROFILE 0
7623
Eric Andersencb57d552001-06-28 07:25:16 +00007624#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007625static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007626extern int etext();
7627#endif
7628
Eric Andersen2870d962001-07-02 17:27:21 +00007629static void read_profile (const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007630static void cmdloop (int);
7631static void options (int);
Eric Andersen2870d962001-07-02 17:27:21 +00007632static void setoption (int, int);
7633static void procargs (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00007634
Eric Andersen2870d962001-07-02 17:27:21 +00007635
Eric Andersencb57d552001-06-28 07:25:16 +00007636/*
7637 * Main routine. We initialize things, parse the arguments, execute
7638 * profiles if we're a login shell, and then call cmdloop to execute
7639 * commands. The setjmp call sets up the location to jump to when an
7640 * exception occurs. When an exception occurs the variable "state"
7641 * is used to figure out how far we had gotten.
7642 */
7643
7644int
7645shell_main(argc, argv)
7646 int argc;
7647 char **argv;
7648{
7649 struct jmploc jmploc;
7650 struct stackmark smark;
7651 volatile int state;
Eric Andersen62483552001-07-10 06:09:16 +00007652 const char *shinit;
Eric Andersencb57d552001-06-28 07:25:16 +00007653
Eric Andersencb57d552001-06-28 07:25:16 +00007654 BLTINCMD = find_builtin("builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00007655 EXECCMD = find_builtin("exec");
7656 EVALCMD = find_builtin("eval");
7657
Eric Andersen1c039232001-07-07 00:05:55 +00007658#ifndef BB_FEATURE_SH_FANCY_PROMPT
7659 unsetenv("PS1");
7660 unsetenv("PS2");
7661#endif
7662
Eric Andersencb57d552001-06-28 07:25:16 +00007663#if PROFILE
7664 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7665#endif
7666#if defined(linux) || defined(__GNU__)
7667 signal(SIGCHLD, SIG_DFL);
7668#endif
7669 state = 0;
7670 if (setjmp(jmploc.loc)) {
7671 INTOFF;
7672 /*
7673 * When a shell procedure is executed, we raise the
7674 * exception EXSHELLPROC to clean up before executing
7675 * the shell procedure.
7676 */
7677 switch (exception) {
7678 case EXSHELLPROC:
7679 rootpid = getpid();
7680 rootshell = 1;
7681 minusc = NULL;
7682 state = 3;
7683 break;
7684
7685 case EXEXEC:
7686 exitstatus = exerrno;
7687 break;
7688
7689 case EXERROR:
7690 exitstatus = 2;
7691 break;
7692
7693 default:
7694 break;
7695 }
7696
7697 if (exception != EXSHELLPROC) {
7698 if (state == 0 || iflag == 0 || ! rootshell)
7699 exitshell(exitstatus);
7700 }
7701 reset();
Eric Andersen2870d962001-07-02 17:27:21 +00007702 if (exception == EXINT) {
Eric Andersencb57d552001-06-28 07:25:16 +00007703 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00007704 }
7705 popstackmark(&smark);
Eric Andersen2870d962001-07-02 17:27:21 +00007706 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007707 if (state == 1)
7708 goto state1;
7709 else if (state == 2)
7710 goto state2;
7711 else if (state == 3)
7712 goto state3;
7713 else
7714 goto state4;
7715 }
7716 handler = &jmploc;
7717#ifdef DEBUG
7718 opentrace();
7719 trputs("Shell args: "); trargs(argv);
7720#endif
7721 rootpid = getpid();
7722 rootshell = 1;
7723 init();
7724 setstackmark(&smark);
7725 procargs(argc, argv);
7726 if (argv[0] && argv[0][0] == '-') {
7727 state = 1;
7728 read_profile("/etc/profile");
7729state1:
7730 state = 2;
7731 read_profile(".profile");
7732 }
7733state2:
7734 state = 3;
7735#ifndef linux
7736 if (getuid() == geteuid() && getgid() == getegid()) {
7737#endif
7738 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7739 state = 3;
7740 read_profile(shinit);
7741 }
7742#ifndef linux
7743 }
7744#endif
7745state3:
7746 state = 4;
7747 if (sflag == 0 || minusc) {
7748 static int sigs[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00007749 SIGINT, SIGQUIT, SIGHUP,
Eric Andersencb57d552001-06-28 07:25:16 +00007750#ifdef SIGTSTP
7751 SIGTSTP,
7752#endif
7753 SIGPIPE
7754 };
7755#define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0]))
7756 int i;
7757
7758 for (i = 0; i < SIGSSIZE; i++)
7759 setsignal(sigs[i]);
7760 }
7761
7762 if (minusc)
7763 evalstring(minusc, 0);
7764
7765 if (sflag || minusc == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00007766state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007767 cmdloop(1);
7768 }
7769#if PROFILE
7770 monitor(0);
7771#endif
7772 exitshell(exitstatus);
7773 /* NOTREACHED */
7774}
7775
7776
7777/*
7778 * Read and execute commands. "Top" is nonzero for the top level command
7779 * loop; it turns on prompting if the shell is interactive.
7780 */
7781
7782static void
Eric Andersen2870d962001-07-02 17:27:21 +00007783cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00007784{
7785 union node *n;
7786 struct stackmark smark;
7787 int inter;
7788 int numeof = 0;
7789
7790 TRACE(("cmdloop(%d) called\n", top));
7791 setstackmark(&smark);
7792 for (;;) {
7793 if (pendingsigs)
7794 dotrap();
7795 inter = 0;
7796 if (iflag && top) {
7797 inter++;
7798 showjobs(1);
7799 chkmail(0);
Eric Andersen3102ac42001-07-06 04:26:23 +00007800 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00007801 }
7802 n = parsecmd(inter);
7803 /* showtree(n); DEBUG */
7804 if (n == NEOF) {
7805 if (!top || numeof >= 50)
7806 break;
7807 if (!stoppedjobs()) {
7808 if (!Iflag)
7809 break;
7810 out2str("\nUse \"exit\" to leave shell.\n");
7811 }
7812 numeof++;
7813 } else if (n != NULL && nflag == 0) {
7814 job_warning = (job_warning == 2) ? 1 : 0;
7815 numeof = 0;
7816 evaltree(n, 0);
7817 }
7818 popstackmark(&smark);
7819 setstackmark(&smark);
7820 if (evalskip == SKIPFILE) {
7821 evalskip = 0;
7822 break;
7823 }
7824 }
7825 popstackmark(&smark);
7826}
7827
7828
7829
7830/*
7831 * Read /etc/profile or .profile. Return on error.
7832 */
7833
7834static void
7835read_profile(name)
7836 const char *name;
7837{
7838 int fd;
7839 int xflag_set = 0;
7840 int vflag_set = 0;
7841
7842 INTOFF;
7843 if ((fd = open(name, O_RDONLY)) >= 0)
7844 setinputfd(fd, 1);
7845 INTON;
7846 if (fd < 0)
7847 return;
7848 /* -q turns off -x and -v just when executing init files */
7849 if (qflag) {
7850 if (xflag)
7851 xflag = 0, xflag_set = 1;
7852 if (vflag)
7853 vflag = 0, vflag_set = 1;
7854 }
7855 cmdloop(0);
7856 if (qflag) {
7857 if (xflag_set)
7858 xflag = 1;
7859 if (vflag_set)
7860 vflag = 1;
7861 }
7862 popfile();
7863}
7864
7865
7866
7867/*
7868 * Read a file containing shell functions.
7869 */
7870
7871static void
Eric Andersen2870d962001-07-02 17:27:21 +00007872readcmdfile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00007873{
7874 int fd;
7875
7876 INTOFF;
7877 if ((fd = open(name, O_RDONLY)) >= 0)
7878 setinputfd(fd, 1);
7879 else
7880 error("Can't open %s", name);
7881 INTON;
7882 cmdloop(0);
7883 popfile();
7884}
7885
7886
7887
7888/*
7889 * Take commands from a file. To be compatable we should do a path
7890 * search for the file, which is necessary to find sub-commands.
7891 */
7892
7893
Eric Andersen62483552001-07-10 06:09:16 +00007894static inline char *
Eric Andersencb57d552001-06-28 07:25:16 +00007895find_dot_file(mybasename)
7896 char *mybasename;
7897{
7898 char *fullname;
7899 const char *path = pathval();
7900 struct stat statb;
7901
7902 /* don't try this for absolute or relative paths */
7903 if (strchr(mybasename, '/'))
7904 return mybasename;
7905
7906 while ((fullname = padvance(&path, mybasename)) != NULL) {
7907 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
7908 /*
7909 * Don't bother freeing here, since it will
7910 * be freed by the caller.
7911 */
7912 return fullname;
7913 }
7914 stunalloc(fullname);
7915 }
7916
7917 /* not found in the PATH */
7918 error("%s: not found", mybasename);
7919 /* NOTREACHED */
7920}
7921
7922static int
7923dotcmd(argc, argv)
7924 int argc;
7925 char **argv;
7926{
7927 struct strlist *sp;
7928 exitstatus = 0;
7929
7930 for (sp = cmdenviron; sp ; sp = sp->next)
7931 setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
7932
Eric Andersen2870d962001-07-02 17:27:21 +00007933 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00007934 char *fullname;
7935 struct stackmark smark;
7936
7937 setstackmark(&smark);
7938 fullname = find_dot_file(argv[1]);
7939 setinputfile(fullname, 1);
7940 commandname = fullname;
7941 cmdloop(0);
7942 popfile();
7943 popstackmark(&smark);
7944 }
7945 return exitstatus;
7946}
7947
7948
7949static int
7950exitcmd(argc, argv)
7951 int argc;
7952 char **argv;
7953{
7954 if (stoppedjobs())
7955 return 0;
7956 if (argc > 1)
7957 exitstatus = number(argv[1]);
7958 else
7959 exitstatus = oexitstatus;
7960 exitshell(exitstatus);
7961 /* NOTREACHED */
7962}
Eric Andersen62483552001-07-10 06:09:16 +00007963
Eric Andersen2870d962001-07-02 17:27:21 +00007964static pointer
7965stalloc(int nbytes)
Eric Andersencb57d552001-06-28 07:25:16 +00007966{
7967 char *p;
7968
7969 nbytes = ALIGN(nbytes);
7970 if (nbytes > stacknleft) {
7971 int blocksize;
7972 struct stack_block *sp;
7973
7974 blocksize = nbytes;
7975 if (blocksize < MINSIZE)
7976 blocksize = MINSIZE;
7977 INTOFF;
7978 sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
7979 sp->prev = stackp;
7980 stacknxt = sp->space;
7981 stacknleft = blocksize;
7982 stackp = sp;
7983 INTON;
7984 }
7985 p = stacknxt;
7986 stacknxt += nbytes;
7987 stacknleft -= nbytes;
7988 return p;
7989}
7990
7991
7992static void
Eric Andersen2870d962001-07-02 17:27:21 +00007993stunalloc(pointer p)
7994{
Eric Andersencb57d552001-06-28 07:25:16 +00007995#ifdef DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +00007996 if (p == NULL) { /*DEBUG */
Eric Andersencb57d552001-06-28 07:25:16 +00007997 write(2, "stunalloc\n", 10);
7998 abort();
7999 }
8000#endif
8001 if (!(stacknxt >= (char *)p && (char *)p >= stackp->space)) {
8002 p = stackp->space;
8003 }
8004 stacknleft += stacknxt - (char *)p;
8005 stacknxt = p;
8006}
8007
8008
Eric Andersencb57d552001-06-28 07:25:16 +00008009static void
Eric Andersen2870d962001-07-02 17:27:21 +00008010setstackmark(struct stackmark *mark)
8011{
Eric Andersencb57d552001-06-28 07:25:16 +00008012 mark->stackp = stackp;
8013 mark->stacknxt = stacknxt;
8014 mark->stacknleft = stacknleft;
8015 mark->marknext = markp;
8016 markp = mark;
8017}
8018
8019
8020static void
Eric Andersen2870d962001-07-02 17:27:21 +00008021popstackmark(struct stackmark *mark)
8022{
Eric Andersencb57d552001-06-28 07:25:16 +00008023 struct stack_block *sp;
8024
8025 INTOFF;
8026 markp = mark->marknext;
8027 while (stackp != mark->stackp) {
8028 sp = stackp;
8029 stackp = sp->prev;
8030 ckfree(sp);
8031 }
8032 stacknxt = mark->stacknxt;
8033 stacknleft = mark->stacknleft;
8034 INTON;
8035}
8036
8037
8038/*
8039 * When the parser reads in a string, it wants to stick the string on the
8040 * stack and only adjust the stack pointer when it knows how big the
8041 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8042 * of space on top of the stack and stackblocklen returns the length of
8043 * this block. Growstackblock will grow this space by at least one byte,
8044 * possibly moving it (like realloc). Grabstackblock actually allocates the
8045 * part of the block that has been used.
8046 */
8047
8048static void
Eric Andersen2870d962001-07-02 17:27:21 +00008049growstackblock(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00008050 char *p;
8051 int newlen = ALIGN(stacknleft * 2 + 100);
8052 char *oldspace = stacknxt;
8053 int oldlen = stacknleft;
8054 struct stack_block *sp;
8055 struct stack_block *oldstackp;
8056
8057 if (stacknxt == stackp->space && stackp != &stackbase) {
8058 INTOFF;
8059 oldstackp = stackp;
8060 sp = stackp;
8061 stackp = sp->prev;
8062 sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen);
8063 sp->prev = stackp;
8064 stackp = sp;
8065 stacknxt = sp->space;
8066 stacknleft = newlen;
8067 {
8068 /* Stack marks pointing to the start of the old block
Eric Andersen2870d962001-07-02 17:27:21 +00008069 * must be relocated to point to the new block
Eric Andersencb57d552001-06-28 07:25:16 +00008070 */
8071 struct stackmark *xmark;
8072 xmark = markp;
8073 while (xmark != NULL && xmark->stackp == oldstackp) {
8074 xmark->stackp = stackp;
8075 xmark->stacknxt = stacknxt;
8076 xmark->stacknleft = stacknleft;
8077 xmark = xmark->marknext;
8078 }
8079 }
8080 INTON;
8081 } else {
8082 p = stalloc(newlen);
8083 memcpy(p, oldspace, oldlen);
Eric Andersen2870d962001-07-02 17:27:21 +00008084 stacknxt = p; /* free the space */
8085 stacknleft += newlen; /* we just allocated */
Eric Andersencb57d552001-06-28 07:25:16 +00008086 }
8087}
8088
8089
8090
Eric Andersen2870d962001-07-02 17:27:21 +00008091static inline void
8092grabstackblock(int len)
Eric Andersencb57d552001-06-28 07:25:16 +00008093{
8094 len = ALIGN(len);
8095 stacknxt += len;
8096 stacknleft -= len;
8097}
8098
8099
8100
8101/*
8102 * The following routines are somewhat easier to use that the above.
8103 * The user declares a variable of type STACKSTR, which may be declared
8104 * to be a register. The macro STARTSTACKSTR initializes things. Then
8105 * the user uses the macro STPUTC to add characters to the string. In
8106 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8107 * grown as necessary. When the user is done, she can just leave the
8108 * string there and refer to it using stackblock(). Or she can allocate
8109 * the space for it using grabstackstr(). If it is necessary to allow
8110 * someone else to use the stack temporarily and then continue to grow
8111 * the string, the user should use grabstack to allocate the space, and
8112 * then call ungrabstr(p) to return to the previous mode of operation.
8113 *
8114 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8115 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8116 * is space for at least one character.
8117 */
8118
8119
8120static char *
Eric Andersen2870d962001-07-02 17:27:21 +00008121growstackstr(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00008122 int len = stackblocksize();
8123 if (herefd >= 0 && len >= 1024) {
8124 xwrite(herefd, stackblock(), len);
8125 sstrnleft = len - 1;
8126 return stackblock();
8127 }
8128 growstackblock();
8129 sstrnleft = stackblocksize() - len - 1;
8130 return stackblock() + len;
8131}
8132
8133
8134/*
8135 * Called from CHECKSTRSPACE.
8136 */
8137
8138static char *
8139makestrspace(size_t newlen) {
8140 int len = stackblocksize() - sstrnleft;
8141 do {
8142 growstackblock();
8143 sstrnleft = stackblocksize() - len;
8144 } while (sstrnleft < newlen);
8145 return stackblock() + len;
8146}
8147
8148
8149
8150static void
Eric Andersen2870d962001-07-02 17:27:21 +00008151ungrabstackstr(char *s, char *p)
8152{
Eric Andersencb57d552001-06-28 07:25:16 +00008153 stacknleft += stacknxt - s;
8154 stacknxt = s;
8155 sstrnleft = stacknleft - (p - s);
8156}
Eric Andersencb57d552001-06-28 07:25:16 +00008157/*
8158 * Miscelaneous builtins.
8159 */
8160
8161
8162#undef rflag
8163
Eric Andersen62483552001-07-10 06:09:16 +00008164//#ifdef __GLIBC__
Eric Andersen2870d962001-07-02 17:27:21 +00008165static mode_t getmode(const void *, mode_t);
Eric Andersencb57d552001-06-28 07:25:16 +00008166static void *setmode(const char *);
Eric Andersen62483552001-07-10 06:09:16 +00008167//#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008168
8169#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersen62483552001-07-10 06:09:16 +00008170typedef long rlim_t;
Eric Andersencb57d552001-06-28 07:25:16 +00008171#endif
8172
8173
8174
8175/*
8176 * The read builtin. The -e option causes backslashes to escape the
8177 * following character.
8178 *
8179 * This uses unbuffered input, which may be avoidable in some cases.
8180 */
8181
8182static int
8183readcmd(argc, argv)
8184 int argc;
8185 char **argv;
8186{
8187 char **ap;
8188 int backslash;
8189 char c;
8190 int rflag;
8191 char *prompt;
8192 const char *ifs;
8193 char *p;
8194 int startword;
8195 int status;
8196 int i;
8197
8198 rflag = 0;
8199 prompt = NULL;
8200 while ((i = nextopt("p:r")) != '\0') {
8201 if (i == 'p')
8202 prompt = optionarg;
8203 else
8204 rflag = 1;
8205 }
8206 if (prompt && isatty(0)) {
8207 putprompt(prompt);
8208 flushall();
8209 }
8210 if (*(ap = argptr) == NULL)
8211 error("arg count");
8212 if ((ifs = bltinlookup("IFS")) == NULL)
8213 ifs = defifs;
8214 status = 0;
8215 startword = 1;
8216 backslash = 0;
8217 STARTSTACKSTR(p);
8218 for (;;) {
8219 if (read(0, &c, 1) != 1) {
8220 status = 1;
8221 break;
8222 }
8223 if (c == '\0')
8224 continue;
8225 if (backslash) {
8226 backslash = 0;
8227 if (c != '\n')
8228 STPUTC(c, p);
8229 continue;
8230 }
8231 if (!rflag && c == '\\') {
8232 backslash++;
8233 continue;
8234 }
8235 if (c == '\n')
8236 break;
8237 if (startword && *ifs == ' ' && strchr(ifs, c)) {
8238 continue;
8239 }
8240 startword = 0;
8241 if (backslash && c == '\\') {
8242 if (read(0, &c, 1) != 1) {
8243 status = 1;
8244 break;
8245 }
8246 STPUTC(c, p);
8247 } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
8248 STACKSTRNUL(p);
8249 setvar(*ap, stackblock(), 0);
8250 ap++;
8251 startword = 1;
8252 STARTSTACKSTR(p);
8253 } else {
8254 STPUTC(c, p);
8255 }
8256 }
8257 STACKSTRNUL(p);
8258 /* Remove trailing blanks */
8259 while (stackblock() <= --p && strchr(ifs, *p) != NULL)
8260 *p = '\0';
8261 setvar(*ap, stackblock(), 0);
8262 while (*++ap != NULL)
8263 setvar(*ap, nullstr, 0);
8264 return status;
8265}
8266
8267
8268
8269static int
8270umaskcmd(argc, argv)
8271 int argc;
8272 char **argv;
8273{
8274 char *ap;
8275 int mask;
8276 int i;
8277 int symbolic_mode = 0;
8278
Eric Andersen62483552001-07-10 06:09:16 +00008279 while (nextopt("S") != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00008280 symbolic_mode = 1;
8281 }
8282
8283 INTOFF;
8284 mask = umask(0);
8285 umask(mask);
8286 INTON;
8287
8288 if ((ap = *argptr) == NULL) {
8289 if (symbolic_mode) {
8290 char u[4], g[4], o[4];
8291
8292 i = 0;
8293 if ((mask & S_IRUSR) == 0)
8294 u[i++] = 'r';
8295 if ((mask & S_IWUSR) == 0)
8296 u[i++] = 'w';
8297 if ((mask & S_IXUSR) == 0)
8298 u[i++] = 'x';
8299 u[i] = '\0';
8300
8301 i = 0;
8302 if ((mask & S_IRGRP) == 0)
8303 g[i++] = 'r';
8304 if ((mask & S_IWGRP) == 0)
8305 g[i++] = 'w';
8306 if ((mask & S_IXGRP) == 0)
8307 g[i++] = 'x';
8308 g[i] = '\0';
8309
8310 i = 0;
8311 if ((mask & S_IROTH) == 0)
8312 o[i++] = 'r';
8313 if ((mask & S_IWOTH) == 0)
8314 o[i++] = 'w';
8315 if ((mask & S_IXOTH) == 0)
8316 o[i++] = 'x';
8317 o[i] = '\0';
8318
Eric Andersen62483552001-07-10 06:09:16 +00008319 printf("u=%s,g=%s,o=%s\n", u, g, o);
Eric Andersencb57d552001-06-28 07:25:16 +00008320 } else {
Eric Andersen62483552001-07-10 06:09:16 +00008321 printf("%.4o\n", mask);
Eric Andersencb57d552001-06-28 07:25:16 +00008322 }
8323 } else {
Eric Andersen62483552001-07-10 06:09:16 +00008324 if (is_digit((unsigned char)*ap)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008325 mask = 0;
8326 do {
8327 if (*ap >= '8' || *ap < '0')
8328 error("Illegal number: %s", argv[1]);
8329 mask = (mask << 3) + (*ap - '0');
8330 } while (*++ap != '\0');
8331 umask(mask);
8332 } else {
8333 void *set;
8334
8335 INTOFF;
8336 if ((set = setmode(ap)) != 0) {
8337 mask = getmode(set, ~mask & 0777);
8338 ckfree(set);
8339 }
8340 INTON;
8341 if (!set)
8342 error("Illegal mode: %s", ap);
8343
8344 umask(~mask & 0777);
8345 }
8346 }
8347 return 0;
8348}
8349
8350/*
8351 * ulimit builtin
8352 *
8353 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
8354 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
8355 * ash by J.T. Conklin.
8356 *
8357 * Public domain.
8358 */
8359
8360struct limits {
8361 const char *name;
Eric Andersen2870d962001-07-02 17:27:21 +00008362 int cmd;
8363 int factor; /* multiply by to get rlim_{cur,max} values */
8364 char option;
Eric Andersencb57d552001-06-28 07:25:16 +00008365};
8366
8367static const struct limits limits[] = {
8368#ifdef RLIMIT_CPU
Eric Andersen2870d962001-07-02 17:27:21 +00008369 { "time(seconds)", RLIMIT_CPU, 1, 't' },
Eric Andersencb57d552001-06-28 07:25:16 +00008370#endif
8371#ifdef RLIMIT_FSIZE
Eric Andersen2870d962001-07-02 17:27:21 +00008372 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
Eric Andersencb57d552001-06-28 07:25:16 +00008373#endif
8374#ifdef RLIMIT_DATA
Eric Andersen2870d962001-07-02 17:27:21 +00008375 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
Eric Andersencb57d552001-06-28 07:25:16 +00008376#endif
8377#ifdef RLIMIT_STACK
Eric Andersen2870d962001-07-02 17:27:21 +00008378 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
Eric Andersencb57d552001-06-28 07:25:16 +00008379#endif
8380#ifdef RLIMIT_CORE
Eric Andersen2870d962001-07-02 17:27:21 +00008381 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
Eric Andersencb57d552001-06-28 07:25:16 +00008382#endif
8383#ifdef RLIMIT_RSS
Eric Andersen2870d962001-07-02 17:27:21 +00008384 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
Eric Andersencb57d552001-06-28 07:25:16 +00008385#endif
8386#ifdef RLIMIT_MEMLOCK
Eric Andersen2870d962001-07-02 17:27:21 +00008387 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
Eric Andersencb57d552001-06-28 07:25:16 +00008388#endif
8389#ifdef RLIMIT_NPROC
Eric Andersen2870d962001-07-02 17:27:21 +00008390 { "process(processes)", RLIMIT_NPROC, 1, 'p' },
Eric Andersencb57d552001-06-28 07:25:16 +00008391#endif
8392#ifdef RLIMIT_NOFILE
Eric Andersen2870d962001-07-02 17:27:21 +00008393 { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
Eric Andersencb57d552001-06-28 07:25:16 +00008394#endif
8395#ifdef RLIMIT_VMEM
Eric Andersen2870d962001-07-02 17:27:21 +00008396 { "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' },
Eric Andersencb57d552001-06-28 07:25:16 +00008397#endif
8398#ifdef RLIMIT_SWAP
Eric Andersen2870d962001-07-02 17:27:21 +00008399 { "swap(kbytes)", RLIMIT_SWAP, 1024, 'w' },
Eric Andersencb57d552001-06-28 07:25:16 +00008400#endif
Eric Andersen2870d962001-07-02 17:27:21 +00008401 { (char *) 0, 0, 0, '\0' }
Eric Andersencb57d552001-06-28 07:25:16 +00008402};
8403
8404static int
8405ulimitcmd(argc, argv)
8406 int argc;
8407 char **argv;
8408{
Eric Andersen2870d962001-07-02 17:27:21 +00008409 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00008410 rlim_t val = 0;
8411 enum { SOFT = 0x1, HARD = 0x2 }
8412 how = SOFT | HARD;
Eric Andersen2870d962001-07-02 17:27:21 +00008413 const struct limits *l;
8414 int set, all = 0;
8415 int optc, what;
8416 struct rlimit limit;
Eric Andersencb57d552001-06-28 07:25:16 +00008417
8418 what = 'f';
8419 while ((optc = nextopt("HSatfdsmcnpl")) != '\0')
8420 switch (optc) {
8421 case 'H':
8422 how = HARD;
8423 break;
8424 case 'S':
8425 how = SOFT;
8426 break;
8427 case 'a':
8428 all = 1;
8429 break;
8430 default:
8431 what = optc;
8432 }
8433
8434 for (l = limits; l->name && l->option != what; l++)
8435 ;
8436 if (!l->name)
8437 error("internal error (%c)", what);
8438
8439 set = *argptr ? 1 : 0;
8440 if (set) {
8441 char *p = *argptr;
8442
8443 if (all || argptr[1])
8444 error("too many arguments");
8445 if (strcmp(p, "unlimited") == 0)
8446 val = RLIM_INFINITY;
8447 else {
8448 val = (rlim_t) 0;
8449
8450 while ((c = *p++) >= '0' && c <= '9')
8451 {
8452 val = (val * 10) + (long)(c - '0');
8453 if (val < (rlim_t) 0)
8454 break;
8455 }
8456 if (c)
8457 error("bad number");
8458 val *= l->factor;
8459 }
8460 }
8461 if (all) {
8462 for (l = limits; l->name; l++) {
8463 getrlimit(l->cmd, &limit);
8464 if (how & SOFT)
8465 val = limit.rlim_cur;
8466 else if (how & HARD)
8467 val = limit.rlim_max;
8468
Eric Andersen62483552001-07-10 06:09:16 +00008469 printf("%-20s ", l->name);
Eric Andersencb57d552001-06-28 07:25:16 +00008470 if (val == RLIM_INFINITY)
Eric Andersen62483552001-07-10 06:09:16 +00008471 printf("unlimited\n");
Eric Andersencb57d552001-06-28 07:25:16 +00008472 else
8473 {
8474 val /= l->factor;
Eric Andersen62483552001-07-10 06:09:16 +00008475 printf("%lld\n", (long long) val);
Eric Andersencb57d552001-06-28 07:25:16 +00008476 }
8477 }
8478 return 0;
8479 }
8480
8481 getrlimit(l->cmd, &limit);
8482 if (set) {
8483 if (how & HARD)
8484 limit.rlim_max = val;
8485 if (how & SOFT)
8486 limit.rlim_cur = val;
8487 if (setrlimit(l->cmd, &limit) < 0)
Eric Andersen2870d962001-07-02 17:27:21 +00008488 error("error setting limit (%m)");
Eric Andersencb57d552001-06-28 07:25:16 +00008489 } else {
8490 if (how & SOFT)
8491 val = limit.rlim_cur;
8492 else if (how & HARD)
8493 val = limit.rlim_max;
8494
8495 if (val == RLIM_INFINITY)
Eric Andersen62483552001-07-10 06:09:16 +00008496 printf("unlimited\n");
Eric Andersencb57d552001-06-28 07:25:16 +00008497 else
8498 {
8499 val /= l->factor;
Eric Andersen62483552001-07-10 06:09:16 +00008500 printf("%lld\n", (long long) val);
Eric Andersencb57d552001-06-28 07:25:16 +00008501 }
8502 }
8503 return 0;
8504}
Eric Andersencb57d552001-06-28 07:25:16 +00008505/*
8506 * prefix -- see if pfx is a prefix of string.
8507 */
8508
8509static int
Eric Andersen62483552001-07-10 06:09:16 +00008510prefix(char const *pfx, char const *string)
8511{
Eric Andersencb57d552001-06-28 07:25:16 +00008512 while (*pfx) {
8513 if (*pfx++ != *string++)
8514 return 0;
8515 }
8516 return 1;
8517}
8518
Eric Andersen2870d962001-07-02 17:27:21 +00008519/*
8520 * Return true if s is a string of digits, and save munber in intptr
8521 * nagative is bad
8522 */
8523
8524static int
8525is_number(const char *p, int *intptr)
8526{
8527 int ret = 0;
8528
8529 do {
8530 if (! is_digit(*p))
8531 return 0;
8532 ret *= 10;
8533 ret += digit_val(*p);
8534 p++;
8535 } while (*p != '\0');
8536
8537 *intptr = ret;
8538 return 1;
8539}
Eric Andersencb57d552001-06-28 07:25:16 +00008540
8541/*
8542 * Convert a string of digits to an integer, printing an error message on
8543 * failure.
8544 */
8545
8546static int
Eric Andersen2870d962001-07-02 17:27:21 +00008547number(const char *s)
8548{
8549 int i;
8550 if (! is_number(s, &i))
Eric Andersencb57d552001-06-28 07:25:16 +00008551 error("Illegal number: %s", s);
Eric Andersen2870d962001-07-02 17:27:21 +00008552 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00008553}
8554
Eric Andersencb57d552001-06-28 07:25:16 +00008555/*
8556 * Produce a possibly single quoted string suitable as input to the shell.
8557 * The return string is allocated on the stack.
8558 */
8559
8560static char *
8561single_quote(const char *s) {
8562 char *p;
8563
8564 STARTSTACKSTR(p);
8565
8566 do {
8567 char *q = p;
8568 size_t len1, len1p, len2, len2p;
8569
8570 len1 = strcspn(s, "'");
8571 len2 = strspn(s + len1, "'");
8572
8573 len1p = len1 ? len1 + 2 : len1;
8574 switch (len2) {
8575 case 0:
8576 len2p = 0;
8577 break;
8578 case 1:
8579 len2p = 2;
8580 break;
8581 default:
8582 len2p = len2 + 2;
8583 }
8584
8585 CHECKSTRSPACE(len1p + len2p + 1, p);
8586
8587 if (len1) {
8588 *p = '\'';
Eric Andersencb57d552001-06-28 07:25:16 +00008589 q = p + 1 + len1;
8590 memcpy(p + 1, s, len1);
Eric Andersencb57d552001-06-28 07:25:16 +00008591 *q++ = '\'';
8592 s += len1;
8593 }
8594
8595 switch (len2) {
8596 case 0:
8597 break;
8598 case 1:
8599 *q++ = '\\';
8600 *q = '\'';
8601 s++;
8602 break;
8603 default:
8604 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008605 q += 1 + len2;
8606 memcpy(q + 1, s, len2);
8607 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008608 s += len2;
8609 }
8610
8611 STADJUST(len1p + len2p, p);
8612 } while (*s);
8613
8614 USTPUTC(0, p);
8615
8616 return grabstackstr(p);
8617}
8618
8619/*
8620 * Like strdup but works with the ash stack.
8621 */
8622
8623static char *
8624sstrdup(const char *p)
8625{
8626 size_t len = strlen(p) + 1;
8627 return memcpy(stalloc(len), p, len);
8628}
8629
Eric Andersencb57d552001-06-28 07:25:16 +00008630
8631/*
Eric Andersencb57d552001-06-28 07:25:16 +00008632 * Routine for dealing with parsed shell commands.
8633 */
8634
8635
Eric Andersen62483552001-07-10 06:09:16 +00008636static void sizenodelist (const struct nodelist *);
8637static struct nodelist *copynodelist (const struct nodelist *);
8638static char *nodesavestr (const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00008639
8640static void
Eric Andersen62483552001-07-10 06:09:16 +00008641calcsize(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008642{
8643 if (n == NULL)
8644 return;
8645 funcblocksize += nodesize[n->type];
8646 switch (n->type) {
8647 case NSEMI:
8648 case NAND:
8649 case NOR:
8650 case NWHILE:
8651 case NUNTIL:
8652 calcsize(n->nbinary.ch2);
8653 calcsize(n->nbinary.ch1);
8654 break;
8655 case NCMD:
8656 calcsize(n->ncmd.redirect);
8657 calcsize(n->ncmd.args);
8658 calcsize(n->ncmd.assign);
8659 break;
8660 case NPIPE:
8661 sizenodelist(n->npipe.cmdlist);
8662 break;
8663 case NREDIR:
8664 case NBACKGND:
8665 case NSUBSHELL:
8666 calcsize(n->nredir.redirect);
8667 calcsize(n->nredir.n);
8668 break;
8669 case NIF:
8670 calcsize(n->nif.elsepart);
8671 calcsize(n->nif.ifpart);
8672 calcsize(n->nif.test);
8673 break;
8674 case NFOR:
8675 funcstringsize += strlen(n->nfor.var) + 1;
8676 calcsize(n->nfor.body);
8677 calcsize(n->nfor.args);
8678 break;
8679 case NCASE:
8680 calcsize(n->ncase.cases);
8681 calcsize(n->ncase.expr);
8682 break;
8683 case NCLIST:
8684 calcsize(n->nclist.body);
8685 calcsize(n->nclist.pattern);
8686 calcsize(n->nclist.next);
8687 break;
8688 case NDEFUN:
8689 case NARG:
8690 sizenodelist(n->narg.backquote);
8691 funcstringsize += strlen(n->narg.text) + 1;
8692 calcsize(n->narg.next);
8693 break;
8694 case NTO:
8695 case NFROM:
8696 case NFROMTO:
8697 case NAPPEND:
8698 case NTOOV:
8699 calcsize(n->nfile.fname);
8700 calcsize(n->nfile.next);
8701 break;
8702 case NTOFD:
8703 case NFROMFD:
8704 calcsize(n->ndup.vname);
8705 calcsize(n->ndup.next);
8706 break;
8707 case NHERE:
8708 case NXHERE:
8709 calcsize(n->nhere.doc);
8710 calcsize(n->nhere.next);
8711 break;
8712 case NNOT:
8713 calcsize(n->nnot.com);
8714 break;
8715 };
8716}
8717
Eric Andersencb57d552001-06-28 07:25:16 +00008718static void
Eric Andersen62483552001-07-10 06:09:16 +00008719sizenodelist(const struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008720{
8721 while (lp) {
8722 funcblocksize += ALIGN(sizeof(struct nodelist));
8723 calcsize(lp->n);
8724 lp = lp->next;
8725 }
8726}
8727
8728
Eric Andersencb57d552001-06-28 07:25:16 +00008729static union node *
Eric Andersen62483552001-07-10 06:09:16 +00008730copynode(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008731{
Eric Andersen62483552001-07-10 06:09:16 +00008732 union node *new;
Eric Andersencb57d552001-06-28 07:25:16 +00008733
8734 if (n == NULL)
8735 return NULL;
8736 new = funcblock;
8737 funcblock = (char *) funcblock + nodesize[n->type];
8738 switch (n->type) {
8739 case NSEMI:
8740 case NAND:
8741 case NOR:
8742 case NWHILE:
8743 case NUNTIL:
8744 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8745 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8746 break;
8747 case NCMD:
8748 new->ncmd.redirect = copynode(n->ncmd.redirect);
8749 new->ncmd.args = copynode(n->ncmd.args);
8750 new->ncmd.assign = copynode(n->ncmd.assign);
8751 new->ncmd.backgnd = n->ncmd.backgnd;
8752 break;
8753 case NPIPE:
8754 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8755 new->npipe.backgnd = n->npipe.backgnd;
8756 break;
8757 case NREDIR:
8758 case NBACKGND:
8759 case NSUBSHELL:
8760 new->nredir.redirect = copynode(n->nredir.redirect);
8761 new->nredir.n = copynode(n->nredir.n);
8762 break;
8763 case NIF:
8764 new->nif.elsepart = copynode(n->nif.elsepart);
8765 new->nif.ifpart = copynode(n->nif.ifpart);
8766 new->nif.test = copynode(n->nif.test);
8767 break;
8768 case NFOR:
8769 new->nfor.var = nodesavestr(n->nfor.var);
8770 new->nfor.body = copynode(n->nfor.body);
8771 new->nfor.args = copynode(n->nfor.args);
8772 break;
8773 case NCASE:
8774 new->ncase.cases = copynode(n->ncase.cases);
8775 new->ncase.expr = copynode(n->ncase.expr);
8776 break;
8777 case NCLIST:
8778 new->nclist.body = copynode(n->nclist.body);
8779 new->nclist.pattern = copynode(n->nclist.pattern);
8780 new->nclist.next = copynode(n->nclist.next);
8781 break;
8782 case NDEFUN:
8783 case NARG:
8784 new->narg.backquote = copynodelist(n->narg.backquote);
8785 new->narg.text = nodesavestr(n->narg.text);
8786 new->narg.next = copynode(n->narg.next);
8787 break;
8788 case NTO:
8789 case NFROM:
8790 case NFROMTO:
8791 case NAPPEND:
8792 case NTOOV:
8793 new->nfile.fname = copynode(n->nfile.fname);
8794 new->nfile.fd = n->nfile.fd;
8795 new->nfile.next = copynode(n->nfile.next);
8796 break;
8797 case NTOFD:
8798 case NFROMFD:
8799 new->ndup.vname = copynode(n->ndup.vname);
8800 new->ndup.dupfd = n->ndup.dupfd;
8801 new->ndup.fd = n->ndup.fd;
8802 new->ndup.next = copynode(n->ndup.next);
8803 break;
8804 case NHERE:
8805 case NXHERE:
8806 new->nhere.doc = copynode(n->nhere.doc);
8807 new->nhere.fd = n->nhere.fd;
8808 new->nhere.next = copynode(n->nhere.next);
8809 break;
8810 case NNOT:
8811 new->nnot.com = copynode(n->nnot.com);
8812 break;
8813 };
8814 new->type = n->type;
Eric Andersen62483552001-07-10 06:09:16 +00008815 return new;
Eric Andersencb57d552001-06-28 07:25:16 +00008816}
8817
8818
8819static struct nodelist *
Eric Andersen62483552001-07-10 06:09:16 +00008820copynodelist(const struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008821{
8822 struct nodelist *start;
8823 struct nodelist **lpp;
8824
8825 lpp = &start;
8826 while (lp) {
8827 *lpp = funcblock;
8828 funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist));
8829 (*lpp)->n = copynode(lp->n);
8830 lp = lp->next;
8831 lpp = &(*lpp)->next;
8832 }
8833 *lpp = NULL;
8834 return start;
8835}
8836
8837
Eric Andersencb57d552001-06-28 07:25:16 +00008838static char *
Eric Andersen62483552001-07-10 06:09:16 +00008839nodesavestr(const char *s)
Eric Andersencb57d552001-06-28 07:25:16 +00008840{
8841#ifdef _GNU_SOURCE
8842 char *rtn = funcstring;
8843
8844 funcstring = stpcpy(funcstring, s) + 1;
8845 return rtn;
8846#else
Eric Andersen62483552001-07-10 06:09:16 +00008847 const char *p = s;
8848 char *q = funcstring;
Eric Andersencb57d552001-06-28 07:25:16 +00008849 char *rtn = funcstring;
8850
8851 while ((*q++ = *p++) != '\0')
8852 continue;
8853 funcstring = q;
8854 return rtn;
8855#endif
8856}
8857
Eric Andersencb57d552001-06-28 07:25:16 +00008858#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00008859static int getopts (char *, char *, char **, int *, int *);
Eric Andersencb57d552001-06-28 07:25:16 +00008860#endif
8861
8862
8863/*
8864 * Process the shell command line arguments.
8865 */
8866
8867static void
8868procargs(argc, argv)
8869 int argc;
8870 char **argv;
8871{
8872 int i;
8873
8874 argptr = argv;
8875 if (argc > 0)
8876 argptr++;
8877 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00008878 optent_val(i) = 2;
Eric Andersencb57d552001-06-28 07:25:16 +00008879 options(1);
8880 if (*argptr == NULL && minusc == NULL)
8881 sflag = 1;
8882 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8883 iflag = 1;
8884 if (mflag == 2)
8885 mflag = iflag;
8886 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00008887 if (optent_val(i) == 2)
8888 optent_val(i) = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008889 arg0 = argv[0];
8890 if (sflag == 0 && minusc == NULL) {
8891 commandname = argv[0];
8892 arg0 = *argptr++;
8893 setinputfile(arg0, 0);
8894 commandname = arg0;
8895 }
8896 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8897 if (argptr && minusc && *argptr)
Eric Andersen2870d962001-07-02 17:27:21 +00008898 arg0 = *argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00008899
8900 shellparam.p = argptr;
8901 shellparam.optind = 1;
8902 shellparam.optoff = -1;
8903 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8904 while (*argptr) {
8905 shellparam.nparam++;
8906 argptr++;
8907 }
8908 optschanged();
8909}
8910
8911
Eric Andersencb57d552001-06-28 07:25:16 +00008912
8913/*
8914 * Process shell options. The global variable argptr contains a pointer
8915 * to the argument list; we advance it past the options.
8916 */
8917
Eric Andersen62483552001-07-10 06:09:16 +00008918static inline void
8919minus_o(const char *name, int val)
8920{
8921 int i;
8922
8923 if (name == NULL) {
8924 out1str("Current option settings\n");
8925 for (i = 0; i < NOPTS; i++)
8926 printf("%-16s%s\n", optent_name(optlist[i]),
8927 optent_val(i) ? "on" : "off");
8928 } else {
8929 for (i = 0; i < NOPTS; i++)
8930 if (equal(name, optent_name(optlist[i]))) {
8931 setoption(optent_letter(optlist[i]), val);
8932 return;
8933 }
8934 error("Illegal option -o %s", name);
8935 }
8936}
8937
8938
Eric Andersencb57d552001-06-28 07:25:16 +00008939static void
Eric Andersen62483552001-07-10 06:09:16 +00008940options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00008941{
8942 char *p;
8943 int val;
8944 int c;
8945
8946 if (cmdline)
8947 minusc = NULL;
8948 while ((p = *argptr) != NULL) {
8949 argptr++;
8950 if ((c = *p++) == '-') {
8951 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00008952 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8953 if (!cmdline) {
8954 /* "-" means turn off -x and -v */
8955 if (p[0] == '\0')
8956 xflag = vflag = 0;
8957 /* "--" means reset params */
8958 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00008959 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00008960 }
8961 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00008962 }
8963 } else if (c == '+') {
8964 val = 0;
8965 } else {
8966 argptr--;
8967 break;
8968 }
8969 while ((c = *p++) != '\0') {
8970 if (c == 'c' && cmdline) {
8971 char *q;
Eric Andersen2870d962001-07-02 17:27:21 +00008972#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */
Eric Andersencb57d552001-06-28 07:25:16 +00008973 if (*p == '\0')
8974#endif
8975 q = *argptr++;
8976 if (q == NULL || minusc != NULL)
8977 error("Bad -c option");
8978 minusc = q;
8979#ifdef NOHACK
8980 break;
8981#endif
8982 } else if (c == 'o') {
8983 minus_o(*argptr, val);
8984 if (*argptr)
8985 argptr++;
8986 } else {
8987 setoption(c, val);
8988 }
8989 }
8990 }
8991}
8992
Eric Andersencb57d552001-06-28 07:25:16 +00008993
8994static void
Eric Andersen2870d962001-07-02 17:27:21 +00008995setoption(int flag, int val)
8996{
Eric Andersencb57d552001-06-28 07:25:16 +00008997 int i;
8998
8999 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009000 if (optent_letter(optlist[i]) == flag) {
9001 optent_val(i) = val;
Eric Andersencb57d552001-06-28 07:25:16 +00009002 if (val) {
9003 /* #%$ hack for ksh semantics */
9004 if (flag == 'V')
9005 Eflag = 0;
9006 else if (flag == 'E')
9007 Vflag = 0;
9008 }
9009 return;
9010 }
9011 error("Illegal option -%c", flag);
9012 /* NOTREACHED */
9013}
9014
9015
9016
Eric Andersencb57d552001-06-28 07:25:16 +00009017/*
9018 * Set the shell parameters.
9019 */
9020
9021static void
Eric Andersen2870d962001-07-02 17:27:21 +00009022setparam(char **argv)
9023{
Eric Andersencb57d552001-06-28 07:25:16 +00009024 char **newparam;
9025 char **ap;
9026 int nparam;
9027
9028 for (nparam = 0 ; argv[nparam] ; nparam++);
9029 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
9030 while (*argv) {
9031 *ap++ = savestr(*argv++);
9032 }
9033 *ap = NULL;
9034 freeparam(&shellparam);
9035 shellparam.malloc = 1;
9036 shellparam.nparam = nparam;
9037 shellparam.p = newparam;
9038 shellparam.optind = 1;
9039 shellparam.optoff = -1;
9040}
9041
9042
9043/*
9044 * Free the list of positional parameters.
9045 */
9046
9047static void
Eric Andersen2870d962001-07-02 17:27:21 +00009048freeparam(volatile struct shparam *param)
9049{
Eric Andersencb57d552001-06-28 07:25:16 +00009050 char **ap;
9051
9052 if (param->malloc) {
9053 for (ap = param->p ; *ap ; ap++)
9054 ckfree(*ap);
9055 ckfree(param->p);
9056 }
9057}
9058
9059
9060
9061/*
9062 * The shift builtin command.
9063 */
9064
9065static int
9066shiftcmd(argc, argv)
9067 int argc;
9068 char **argv;
9069{
9070 int n;
9071 char **ap1, **ap2;
9072
9073 n = 1;
9074 if (argc > 1)
9075 n = number(argv[1]);
9076 if (n > shellparam.nparam)
9077 error("can't shift that many");
9078 INTOFF;
9079 shellparam.nparam -= n;
9080 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
9081 if (shellparam.malloc)
9082 ckfree(*ap1);
9083 }
9084 ap2 = shellparam.p;
9085 while ((*ap2++ = *ap1++) != NULL);
9086 shellparam.optind = 1;
9087 shellparam.optoff = -1;
9088 INTON;
9089 return 0;
9090}
9091
9092
9093
9094/*
9095 * The set command builtin.
9096 */
9097
9098static int
9099setcmd(argc, argv)
9100 int argc;
9101 char **argv;
9102{
9103 if (argc == 1)
9104 return showvarscmd(argc, argv);
9105 INTOFF;
9106 options(0);
9107 optschanged();
9108 if (*argptr != NULL) {
9109 setparam(argptr);
9110 }
9111 INTON;
9112 return 0;
9113}
9114
9115
9116static void
Eric Andersen2870d962001-07-02 17:27:21 +00009117getoptsreset(const char *value)
Eric Andersencb57d552001-06-28 07:25:16 +00009118{
9119 shellparam.optind = number(value);
9120 shellparam.optoff = -1;
9121}
9122
Eric Andersen2870d962001-07-02 17:27:21 +00009123#ifdef BB_LOCALE_SUPPORT
9124static void change_lc_all(const char *value)
9125{
9126 if(value != 0 && *value != 0)
9127 setlocale(LC_ALL, value);
9128}
9129
9130static void change_lc_ctype(const char *value)
9131{
9132 if(value != 0 && *value != 0)
9133 setlocale(LC_CTYPE, value);
9134}
9135
9136#endif
9137
Eric Andersencb57d552001-06-28 07:25:16 +00009138#ifdef ASH_GETOPTS
9139/*
9140 * The getopts builtin. Shellparam.optnext points to the next argument
9141 * to be processed. Shellparam.optptr points to the next character to
9142 * be processed in the current argument. If shellparam.optnext is NULL,
9143 * then it's the first time getopts has been called.
9144 */
9145
9146static int
9147getoptscmd(argc, argv)
9148 int argc;
9149 char **argv;
9150{
9151 char **optbase;
9152
9153 if (argc < 3)
9154 error("Usage: getopts optstring var [arg]");
9155 else if (argc == 3) {
9156 optbase = shellparam.p;
9157 if (shellparam.optind > shellparam.nparam + 1) {
9158 shellparam.optind = 1;
9159 shellparam.optoff = -1;
9160 }
9161 }
9162 else {
9163 optbase = &argv[3];
9164 if (shellparam.optind > argc - 2) {
9165 shellparam.optind = 1;
9166 shellparam.optoff = -1;
9167 }
9168 }
9169
9170 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9171 &shellparam.optoff);
9172}
9173
9174/*
9175 * Safe version of setvar, returns 1 on success 0 on failure.
9176 */
9177
9178static int
9179setvarsafe(name, val, flags)
9180 const char *name, *val;
9181 int flags;
9182{
9183 struct jmploc jmploc;
9184 struct jmploc *volatile savehandler = handler;
9185 int err = 0;
9186#ifdef __GNUC__
9187 (void) &err;
9188#endif
9189
9190 if (setjmp(jmploc.loc))
9191 err = 1;
9192 else {
9193 handler = &jmploc;
9194 setvar(name, val, flags);
9195 }
9196 handler = savehandler;
9197 return err;
9198}
9199
9200static int
9201getopts(optstr, optvar, optfirst, myoptind, optoff)
9202 char *optstr;
9203 char *optvar;
9204 char **optfirst;
9205 int *myoptind;
9206 int *optoff;
9207{
9208 char *p, *q;
9209 char c = '?';
9210 int done = 0;
9211 int err = 0;
9212 char s[10];
9213 char **optnext = optfirst + *myoptind - 1;
9214
9215 if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
9216 strlen(*(optnext - 1)) < *optoff)
9217 p = NULL;
9218 else
9219 p = *(optnext - 1) + *optoff;
9220 if (p == NULL || *p == '\0') {
9221 /* Current word is done, advance */
9222 if (optnext == NULL)
9223 return 1;
9224 p = *optnext;
9225 if (p == NULL || *p != '-' || *++p == '\0') {
9226atend:
9227 *myoptind = optnext - optfirst + 1;
9228 p = NULL;
9229 done = 1;
9230 goto out;
9231 }
9232 optnext++;
Eric Andersen2870d962001-07-02 17:27:21 +00009233 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009234 goto atend;
9235 }
9236
9237 c = *p++;
9238 for (q = optstr; *q != c; ) {
9239 if (*q == '\0') {
9240 if (optstr[0] == ':') {
9241 s[0] = c;
9242 s[1] = '\0';
9243 err |= setvarsafe("OPTARG", s, 0);
9244 }
9245 else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009246 out2fmt("Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009247 (void) unsetvar("OPTARG");
9248 }
9249 c = '?';
9250 goto bad;
9251 }
9252 if (*++q == ':')
9253 q++;
9254 }
9255
9256 if (*++q == ':') {
9257 if (*p == '\0' && (p = *optnext) == NULL) {
9258 if (optstr[0] == ':') {
9259 s[0] = c;
9260 s[1] = '\0';
9261 err |= setvarsafe("OPTARG", s, 0);
9262 c = ':';
9263 }
9264 else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009265 out2fmt("No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009266 (void) unsetvar("OPTARG");
9267 c = '?';
9268 }
9269 goto bad;
9270 }
9271
9272 if (p == *optnext)
9273 optnext++;
9274 setvarsafe("OPTARG", p, 0);
9275 p = NULL;
9276 }
9277 else
9278 setvarsafe("OPTARG", "", 0);
9279 *myoptind = optnext - optfirst + 1;
9280 goto out;
9281
9282bad:
9283 *myoptind = 1;
9284 p = NULL;
9285out:
9286 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersen3102ac42001-07-06 04:26:23 +00009287 snprintf(s, sizeof(s), "%d", *myoptind);
Eric Andersencb57d552001-06-28 07:25:16 +00009288 err |= setvarsafe("OPTIND", s, VNOFUNC);
9289 s[0] = c;
9290 s[1] = '\0';
9291 err |= setvarsafe(optvar, s, 0);
9292 if (err) {
9293 *myoptind = 1;
9294 *optoff = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00009295 exraise(EXERROR);
9296 }
9297 return done;
9298}
Eric Andersen2870d962001-07-02 17:27:21 +00009299#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009300
9301/*
9302 * XXX - should get rid of. have all builtins use getopt(3). the
9303 * library getopt must have the BSD extension static variable "optreset"
9304 * otherwise it can't be used within the shell safely.
9305 *
9306 * Standard option processing (a la getopt) for builtin routines. The
9307 * only argument that is passed to nextopt is the option string; the
9308 * other arguments are unnecessary. It return the character, or '\0' on
9309 * end of input.
9310 */
9311
9312static int
Eric Andersen62483552001-07-10 06:09:16 +00009313nextopt(const char *optstring)
9314{
Eric Andersencb57d552001-06-28 07:25:16 +00009315 char *p;
9316 const char *q;
9317 char c;
9318
9319 if ((p = optptr) == NULL || *p == '\0') {
9320 p = *argptr;
9321 if (p == NULL || *p != '-' || *++p == '\0')
9322 return '\0';
9323 argptr++;
Eric Andersen2870d962001-07-02 17:27:21 +00009324 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009325 return '\0';
9326 }
9327 c = *p++;
9328 for (q = optstring ; *q != c ; ) {
9329 if (*q == '\0')
9330 error("Illegal option -%c", c);
9331 if (*++q == ':')
9332 q++;
9333 }
9334 if (*++q == ':') {
9335 if (*p == '\0' && (p = *argptr++) == NULL)
9336 error("No arg for -%c option", c);
9337 optionarg = p;
9338 p = NULL;
9339 }
9340 optptr = p;
9341 return c;
9342}
9343
Eric Andersencb57d552001-06-28 07:25:16 +00009344static void
9345flushall() {
Eric Andersencb57d552001-06-28 07:25:16 +00009346 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009347 fflush(stdout);
Eric Andersencb57d552001-06-28 07:25:16 +00009348 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009349}
9350
9351
9352static void
Eric Andersen3102ac42001-07-06 04:26:23 +00009353out2fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009354{
9355 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00009356 va_start(ap, fmt);
Eric Andersen3102ac42001-07-06 04:26:23 +00009357 vfprintf(stderr, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009358 va_end(ap);
9359}
9360
Eric Andersencb57d552001-06-28 07:25:16 +00009361/*
9362 * Version of write which resumes after a signal is caught.
9363 */
9364
9365static int
Eric Andersen2870d962001-07-02 17:27:21 +00009366xwrite(int fd, const char *buf, int nbytes)
9367{
Eric Andersencb57d552001-06-28 07:25:16 +00009368 int ntry;
9369 int i;
9370 int n;
9371
9372 n = nbytes;
9373 ntry = 0;
9374 for (;;) {
9375 i = write(fd, buf, n);
9376 if (i > 0) {
9377 if ((n -= i) <= 0)
9378 return nbytes;
9379 buf += i;
9380 ntry = 0;
9381 } else if (i == 0) {
9382 if (++ntry > 10)
9383 return nbytes - n;
9384 } else if (errno != EINTR) {
9385 return -1;
9386 }
9387 }
9388}
9389
9390
Eric Andersencb57d552001-06-28 07:25:16 +00009391/*
9392 * Shell command parser.
9393 */
9394
9395#define EOFMARKLEN 79
9396
9397
9398
9399struct heredoc {
Eric Andersen2870d962001-07-02 17:27:21 +00009400 struct heredoc *next; /* next here document in list */
9401 union node *here; /* redirection node */
9402 char *eofmark; /* string indicating end of input */
9403 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009404};
9405
Eric Andersen2870d962001-07-02 17:27:21 +00009406static struct heredoc *heredoclist; /* list of here documents to read */
9407static int parsebackquote; /* nonzero if we are inside backquotes */
9408static int doprompt; /* if set, prompt the user */
9409static int needprompt; /* true if interactive and at start of line */
9410static int lasttoken; /* last token read */
Eric Andersencb57d552001-06-28 07:25:16 +00009411
Eric Andersen2870d962001-07-02 17:27:21 +00009412static char *wordtext; /* text of last word returned by readtoken */
Eric Andersencb57d552001-06-28 07:25:16 +00009413
Eric Andersen2870d962001-07-02 17:27:21 +00009414static struct nodelist *backquotelist;
9415static union node *redirnode;
Eric Andersen044228d2001-07-17 01:12:36 +00009416static struct heredoc *heredoc;
Eric Andersen2870d962001-07-02 17:27:21 +00009417static int quoteflag; /* set if (part of) last token was quoted */
9418static int startlinno; /* line # where last token started */
Eric Andersencb57d552001-06-28 07:25:16 +00009419
9420
Eric Andersen2870d962001-07-02 17:27:21 +00009421static union node *list (int);
9422static union node *andor (void);
9423static union node *pipeline (void);
9424static union node *command (void);
9425static union node *simplecmd (void);
9426static void parsefname (void);
9427static void parseheredoc (void);
9428static int peektoken (void);
9429static int readtoken (void);
9430static int xxreadtoken (void);
9431static int readtoken1 (int, char const *, char *, int);
9432static int noexpand (char *);
9433static void synexpect (int) __attribute__((noreturn));
9434static void synerror (const char *) __attribute__((noreturn));
9435static void setprompt (int);
Eric Andersencb57d552001-06-28 07:25:16 +00009436
9437
9438/*
9439 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9440 * valid parse tree indicating a blank line.)
9441 */
9442
Eric Andersen2870d962001-07-02 17:27:21 +00009443static union node *
Eric Andersencb57d552001-06-28 07:25:16 +00009444parsecmd(int interact)
9445{
9446 int t;
9447
9448 tokpushback = 0;
9449 doprompt = interact;
9450 if (doprompt)
9451 setprompt(1);
9452 else
9453 setprompt(0);
9454 needprompt = 0;
9455 t = readtoken();
9456 if (t == TEOF)
9457 return NEOF;
9458 if (t == TNL)
9459 return NULL;
9460 tokpushback++;
9461 return list(1);
9462}
9463
9464
9465static union node *
9466list(nlflag)
9467 int nlflag;
9468{
9469 union node *n1, *n2, *n3;
9470 int tok;
9471
9472 checkkwd = 2;
9473 if (nlflag == 0 && tokendlist[peektoken()])
9474 return NULL;
9475 n1 = NULL;
9476 for (;;) {
9477 n2 = andor();
9478 tok = readtoken();
9479 if (tok == TBACKGND) {
9480 if (n2->type == NCMD || n2->type == NPIPE) {
9481 n2->ncmd.backgnd = 1;
9482 } else if (n2->type == NREDIR) {
9483 n2->type = NBACKGND;
9484 } else {
9485 n3 = (union node *)stalloc(sizeof (struct nredir));
9486 n3->type = NBACKGND;
9487 n3->nredir.n = n2;
9488 n3->nredir.redirect = NULL;
9489 n2 = n3;
9490 }
9491 }
9492 if (n1 == NULL) {
9493 n1 = n2;
9494 }
9495 else {
9496 n3 = (union node *)stalloc(sizeof (struct nbinary));
9497 n3->type = NSEMI;
9498 n3->nbinary.ch1 = n1;
9499 n3->nbinary.ch2 = n2;
9500 n1 = n3;
9501 }
9502 switch (tok) {
9503 case TBACKGND:
9504 case TSEMI:
9505 tok = readtoken();
9506 /* fall through */
9507 case TNL:
9508 if (tok == TNL) {
9509 parseheredoc();
9510 if (nlflag)
9511 return n1;
9512 } else {
9513 tokpushback++;
9514 }
9515 checkkwd = 2;
9516 if (tokendlist[peektoken()])
9517 return n1;
9518 break;
9519 case TEOF:
9520 if (heredoclist)
9521 parseheredoc();
9522 else
Eric Andersen2870d962001-07-02 17:27:21 +00009523 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009524 return n1;
9525 default:
9526 if (nlflag)
9527 synexpect(-1);
9528 tokpushback++;
9529 return n1;
9530 }
9531 }
9532}
9533
9534
9535
9536static union node *
9537andor() {
9538 union node *n1, *n2, *n3;
9539 int t;
9540
9541 checkkwd = 1;
9542 n1 = pipeline();
9543 for (;;) {
9544 if ((t = readtoken()) == TAND) {
9545 t = NAND;
9546 } else if (t == TOR) {
9547 t = NOR;
9548 } else {
9549 tokpushback++;
9550 return n1;
9551 }
9552 checkkwd = 2;
9553 n2 = pipeline();
9554 n3 = (union node *)stalloc(sizeof (struct nbinary));
9555 n3->type = t;
9556 n3->nbinary.ch1 = n1;
9557 n3->nbinary.ch2 = n2;
9558 n1 = n3;
9559 }
9560}
9561
9562
9563
9564static union node *
9565pipeline() {
9566 union node *n1, *n2, *pipenode;
9567 struct nodelist *lp, *prev;
9568 int negate;
9569
9570 negate = 0;
9571 TRACE(("pipeline: entered\n"));
9572 if (readtoken() == TNOT) {
9573 negate = !negate;
9574 checkkwd = 1;
9575 } else
9576 tokpushback++;
9577 n1 = command();
9578 if (readtoken() == TPIPE) {
9579 pipenode = (union node *)stalloc(sizeof (struct npipe));
9580 pipenode->type = NPIPE;
9581 pipenode->npipe.backgnd = 0;
9582 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9583 pipenode->npipe.cmdlist = lp;
9584 lp->n = n1;
9585 do {
9586 prev = lp;
9587 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9588 checkkwd = 2;
9589 lp->n = command();
9590 prev->next = lp;
9591 } while (readtoken() == TPIPE);
9592 lp->next = NULL;
9593 n1 = pipenode;
9594 }
9595 tokpushback++;
9596 if (negate) {
9597 n2 = (union node *)stalloc(sizeof (struct nnot));
9598 n2->type = NNOT;
9599 n2->nnot.com = n1;
9600 return n2;
9601 } else
9602 return n1;
9603}
9604
9605
9606
9607static union node *
9608command() {
9609 union node *n1, *n2;
9610 union node *ap, **app;
9611 union node *cp, **cpp;
9612 union node *redir, **rpp;
9613 int t;
9614
9615 redir = NULL;
9616 n1 = NULL;
9617 rpp = &redir;
9618
9619 switch (readtoken()) {
9620 case TIF:
9621 n1 = (union node *)stalloc(sizeof (struct nif));
9622 n1->type = NIF;
9623 n1->nif.test = list(0);
9624 if (readtoken() != TTHEN)
9625 synexpect(TTHEN);
9626 n1->nif.ifpart = list(0);
9627 n2 = n1;
9628 while (readtoken() == TELIF) {
9629 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9630 n2 = n2->nif.elsepart;
9631 n2->type = NIF;
9632 n2->nif.test = list(0);
9633 if (readtoken() != TTHEN)
9634 synexpect(TTHEN);
9635 n2->nif.ifpart = list(0);
9636 }
9637 if (lasttoken == TELSE)
9638 n2->nif.elsepart = list(0);
9639 else {
9640 n2->nif.elsepart = NULL;
9641 tokpushback++;
9642 }
9643 if (readtoken() != TFI)
9644 synexpect(TFI);
9645 checkkwd = 1;
9646 break;
9647 case TWHILE:
9648 case TUNTIL: {
9649 int got;
9650 n1 = (union node *)stalloc(sizeof (struct nbinary));
9651 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9652 n1->nbinary.ch1 = list(0);
9653 if ((got=readtoken()) != TDO) {
9654TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
9655 synexpect(TDO);
9656 }
9657 n1->nbinary.ch2 = list(0);
9658 if (readtoken() != TDONE)
9659 synexpect(TDONE);
9660 checkkwd = 1;
9661 break;
9662 }
9663 case TFOR:
9664 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9665 synerror("Bad for loop variable");
9666 n1 = (union node *)stalloc(sizeof (struct nfor));
9667 n1->type = NFOR;
9668 n1->nfor.var = wordtext;
9669 checkkwd = 1;
9670 if (readtoken() == TIN) {
9671 app = &ap;
9672 while (readtoken() == TWORD) {
9673 n2 = (union node *)stalloc(sizeof (struct narg));
9674 n2->type = NARG;
9675 n2->narg.text = wordtext;
9676 n2->narg.backquote = backquotelist;
9677 *app = n2;
9678 app = &n2->narg.next;
9679 }
9680 *app = NULL;
9681 n1->nfor.args = ap;
9682 if (lasttoken != TNL && lasttoken != TSEMI)
9683 synexpect(-1);
9684 } else {
9685 static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
9686 '@', '=', '\0'};
9687 n2 = (union node *)stalloc(sizeof (struct narg));
9688 n2->type = NARG;
9689 n2->narg.text = argvars;
9690 n2->narg.backquote = NULL;
9691 n2->narg.next = NULL;
9692 n1->nfor.args = n2;
9693 /*
9694 * Newline or semicolon here is optional (but note
9695 * that the original Bourne shell only allowed NL).
9696 */
9697 if (lasttoken != TNL && lasttoken != TSEMI)
9698 tokpushback++;
9699 }
9700 checkkwd = 2;
9701 if (readtoken() != TDO)
9702 synexpect(TDO);
9703 n1->nfor.body = list(0);
9704 if (readtoken() != TDONE)
9705 synexpect(TDONE);
9706 checkkwd = 1;
9707 break;
9708 case TCASE:
9709 n1 = (union node *)stalloc(sizeof (struct ncase));
9710 n1->type = NCASE;
9711 if (readtoken() != TWORD)
9712 synexpect(TWORD);
9713 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9714 n2->type = NARG;
9715 n2->narg.text = wordtext;
9716 n2->narg.backquote = backquotelist;
9717 n2->narg.next = NULL;
9718 do {
9719 checkkwd = 1;
9720 } while (readtoken() == TNL);
9721 if (lasttoken != TIN)
9722 synerror("expecting \"in\"");
9723 cpp = &n1->ncase.cases;
9724 checkkwd = 2, readtoken();
9725 do {
9726 if (lasttoken == TLP)
9727 readtoken();
9728 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9729 cp->type = NCLIST;
9730 app = &cp->nclist.pattern;
9731 for (;;) {
9732 *app = ap = (union node *)stalloc(sizeof (struct narg));
9733 ap->type = NARG;
9734 ap->narg.text = wordtext;
9735 ap->narg.backquote = backquotelist;
9736 if (checkkwd = 2, readtoken() != TPIPE)
9737 break;
9738 app = &ap->narg.next;
9739 readtoken();
9740 }
9741 ap->narg.next = NULL;
9742 if (lasttoken != TRP)
9743 synexpect(TRP);
9744 cp->nclist.body = list(0);
9745
9746 checkkwd = 2;
9747 if ((t = readtoken()) != TESAC) {
9748 if (t != TENDCASE)
9749 synexpect(TENDCASE);
9750 else
9751 checkkwd = 2, readtoken();
9752 }
9753 cpp = &cp->nclist.next;
9754 } while(lasttoken != TESAC);
9755 *cpp = NULL;
9756 checkkwd = 1;
9757 break;
9758 case TLP:
9759 n1 = (union node *)stalloc(sizeof (struct nredir));
9760 n1->type = NSUBSHELL;
9761 n1->nredir.n = list(0);
9762 n1->nredir.redirect = NULL;
9763 if (readtoken() != TRP)
9764 synexpect(TRP);
9765 checkkwd = 1;
9766 break;
9767 case TBEGIN:
9768 n1 = list(0);
9769 if (readtoken() != TEND)
9770 synexpect(TEND);
9771 checkkwd = 1;
9772 break;
9773 /* Handle an empty command like other simple commands. */
9774 case TSEMI:
9775 case TAND:
9776 case TOR:
9777 case TNL:
9778 case TEOF:
9779 case TRP:
9780 case TBACKGND:
9781 /*
9782 * An empty command before a ; doesn't make much sense, and
9783 * should certainly be disallowed in the case of `if ;'.
9784 */
9785 if (!redir)
9786 synexpect(-1);
9787 case TWORD:
9788 case TREDIR:
9789 tokpushback++;
9790 n1 = simplecmd();
9791 return n1;
9792 default:
9793 synexpect(-1);
9794 /* NOTREACHED */
9795 }
9796
9797 /* Now check for redirection which may follow command */
9798 while (readtoken() == TREDIR) {
9799 *rpp = n2 = redirnode;
9800 rpp = &n2->nfile.next;
9801 parsefname();
9802 }
9803 tokpushback++;
9804 *rpp = NULL;
9805 if (redir) {
9806 if (n1->type != NSUBSHELL) {
9807 n2 = (union node *)stalloc(sizeof (struct nredir));
9808 n2->type = NREDIR;
9809 n2->nredir.n = n1;
9810 n1 = n2;
9811 }
9812 n1->nredir.redirect = redir;
9813 }
9814
9815 return n1;
9816}
9817
9818
9819static union node *
9820simplecmd() {
9821 union node *args, **app;
9822 union node *n = NULL;
9823 union node *vars, **vpp;
9824 union node **rpp, *redir;
9825
9826 args = NULL;
9827 app = &args;
9828 vars = NULL;
9829 vpp = &vars;
9830 redir = NULL;
9831 rpp = &redir;
9832
9833 checkalias = 2;
9834 for (;;) {
9835 switch (readtoken()) {
9836 case TWORD:
9837 case TASSIGN:
9838 n = (union node *)stalloc(sizeof (struct narg));
9839 n->type = NARG;
9840 n->narg.text = wordtext;
9841 n->narg.backquote = backquotelist;
9842 if (lasttoken == TWORD) {
9843 *app = n;
9844 app = &n->narg.next;
9845 } else {
9846 *vpp = n;
9847 vpp = &n->narg.next;
9848 }
9849 break;
9850 case TREDIR:
9851 *rpp = n = redirnode;
9852 rpp = &n->nfile.next;
Eric Andersen2870d962001-07-02 17:27:21 +00009853 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +00009854 break;
9855 case TLP:
9856 if (
9857 args && app == &args->narg.next &&
9858 !vars && !redir
9859 ) {
9860 /* We have a function */
9861 if (readtoken() != TRP)
9862 synexpect(TRP);
Eric Andersencb57d552001-06-28 07:25:16 +00009863 n->type = NDEFUN;
9864 checkkwd = 2;
9865 n->narg.next = command();
9866 return n;
9867 }
9868 /* fall through */
9869 default:
9870 tokpushback++;
9871 goto out;
9872 }
9873 }
9874out:
9875 *app = NULL;
9876 *vpp = NULL;
9877 *rpp = NULL;
9878 n = (union node *)stalloc(sizeof (struct ncmd));
9879 n->type = NCMD;
9880 n->ncmd.backgnd = 0;
9881 n->ncmd.args = args;
9882 n->ncmd.assign = vars;
9883 n->ncmd.redirect = redir;
9884 return n;
9885}
9886
9887static union node *
Eric Andersen2870d962001-07-02 17:27:21 +00009888makename(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009889 union node *n;
9890
9891 n = (union node *)stalloc(sizeof (struct narg));
9892 n->type = NARG;
9893 n->narg.next = NULL;
9894 n->narg.text = wordtext;
9895 n->narg.backquote = backquotelist;
9896 return n;
9897}
9898
9899static void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +00009900{
Eric Andersencb57d552001-06-28 07:25:16 +00009901 TRACE(("Fix redir %s %d\n", text, err));
9902 if (!err)
9903 n->ndup.vname = NULL;
9904
9905 if (is_digit(text[0]) && text[1] == '\0')
9906 n->ndup.dupfd = digit_val(text[0]);
9907 else if (text[0] == '-' && text[1] == '\0')
9908 n->ndup.dupfd = -1;
9909 else {
9910
9911 if (err)
9912 synerror("Bad fd number");
9913 else
9914 n->ndup.vname = makename();
9915 }
9916}
9917
9918
9919static void
Eric Andersen2870d962001-07-02 17:27:21 +00009920parsefname(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009921 union node *n = redirnode;
9922
9923 if (readtoken() != TWORD)
9924 synexpect(-1);
9925 if (n->type == NHERE) {
9926 struct heredoc *here = heredoc;
9927 struct heredoc *p;
9928 int i;
9929
9930 if (quoteflag == 0)
9931 n->type = NXHERE;
9932 TRACE(("Here document %d\n", n->type));
9933 if (here->striptabs) {
9934 while (*wordtext == '\t')
9935 wordtext++;
9936 }
9937 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9938 synerror("Illegal eof marker for << redirection");
9939 rmescapes(wordtext);
9940 here->eofmark = wordtext;
9941 here->next = NULL;
9942 if (heredoclist == NULL)
9943 heredoclist = here;
9944 else {
9945 for (p = heredoclist ; p->next ; p = p->next);
9946 p->next = here;
9947 }
9948 } else if (n->type == NTOFD || n->type == NFROMFD) {
9949 fixredir(n, wordtext, 0);
9950 } else {
9951 n->nfile.fname = makename();
9952 }
9953}
9954
9955
9956/*
9957 * Input any here documents.
9958 */
9959
9960static void
9961parseheredoc() {
9962 struct heredoc *here;
9963 union node *n;
9964
9965 while (heredoclist) {
9966 here = heredoclist;
9967 heredoclist = here->next;
9968 if (needprompt) {
9969 setprompt(2);
9970 needprompt = 0;
9971 }
9972 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9973 here->eofmark, here->striptabs);
9974 n = (union node *)stalloc(sizeof (struct narg));
9975 n->narg.type = NARG;
9976 n->narg.next = NULL;
9977 n->narg.text = wordtext;
9978 n->narg.backquote = backquotelist;
9979 here->here->nhere.doc = n;
9980 }
9981}
9982
9983static int
9984peektoken() {
9985 int t;
9986
9987 t = readtoken();
9988 tokpushback++;
9989 return (t);
9990}
9991
9992static int
9993readtoken() {
9994 int t;
Eric Andersen7467c8d2001-07-12 20:26:32 +00009995
Eric Andersen2870d962001-07-02 17:27:21 +00009996#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00009997 int savecheckalias = checkalias;
Eric Andersen7467c8d2001-07-12 20:26:32 +00009998 int savecheckkwd = checkkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009999 struct alias *ap;
Eric Andersen2870d962001-07-02 17:27:21 +000010000#endif
10001
Eric Andersencb57d552001-06-28 07:25:16 +000010002#ifdef DEBUG
10003 int alreadyseen = tokpushback;
10004#endif
10005
Eric Andersen2870d962001-07-02 17:27:21 +000010006#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010007top:
Eric Andersen2870d962001-07-02 17:27:21 +000010008#endif
10009
Eric Andersencb57d552001-06-28 07:25:16 +000010010 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +000010011
10012#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010013 checkalias = savecheckalias;
Eric Andersen2870d962001-07-02 17:27:21 +000010014#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010015
10016 if (checkkwd) {
10017 /*
10018 * eat newlines
10019 */
10020 if (checkkwd == 2) {
10021 checkkwd = 0;
10022 while (t == TNL) {
10023 parseheredoc();
10024 t = xxreadtoken();
10025 }
10026 }
10027 checkkwd = 0;
10028 /*
10029 * check for keywords
10030 */
10031 if (t == TWORD && !quoteflag)
10032 {
10033 const char *const *pp;
10034
10035 if ((pp = findkwd(wordtext))) {
10036 lasttoken = t = pp - parsekwd + KWDOFFSET;
10037 TRACE(("keyword %s recognized\n", tokname[t]));
10038 goto out;
10039 }
10040 }
10041 }
10042
Eric Andersen7467c8d2001-07-12 20:26:32 +000010043
Eric Andersencb57d552001-06-28 07:25:16 +000010044 if (t != TWORD) {
10045 if (t != TREDIR) {
10046 checkalias = 0;
10047 }
10048 } else if (checkalias == 2 && isassignment(wordtext)) {
10049 lasttoken = t = TASSIGN;
Eric Andersen7467c8d2001-07-12 20:26:32 +000010050#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010051 } else if (checkalias) {
10052 if (!quoteflag && (ap = lookupalias(wordtext, 1)) != NULL) {
10053 if (*ap->val) {
10054 pushstring(ap->val, strlen(ap->val), ap);
10055 }
10056 checkkwd = savecheckkwd;
10057 goto top;
10058 }
10059 checkalias = 0;
Eric Andersen2870d962001-07-02 17:27:21 +000010060#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +000010061 }
Eric Andersencb57d552001-06-28 07:25:16 +000010062out:
10063#ifdef DEBUG
10064 if (!alreadyseen)
10065 TRACE(("token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : ""));
10066 else
10067 TRACE(("reread token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : ""));
10068#endif
10069 return (t);
10070}
10071
10072
10073/*
10074 * Read the next input token.
10075 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +000010076 * backquotes. We set quoteflag to true if any part of the word was
10077 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +000010078 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +000010079 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +000010080 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +000010081 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +000010082 *
10083 * [Change comment: here documents and internal procedures]
10084 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10085 * word parsing code into a separate routine. In this case, readtoken
10086 * doesn't need to have any internal procedures, but parseword does.
10087 * We could also make parseoperator in essence the main routine, and
10088 * have parseword (readtoken1?) handle both words and redirection.]
10089 */
10090
Eric Andersen2870d962001-07-02 17:27:21 +000010091#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010092
10093static int
10094xxreadtoken() {
10095 int c;
10096
10097 if (tokpushback) {
10098 tokpushback = 0;
10099 return lasttoken;
10100 }
10101 if (needprompt) {
10102 setprompt(2);
10103 needprompt = 0;
10104 }
10105 startlinno = plinno;
Eric Andersen2870d962001-07-02 17:27:21 +000010106 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010107 c = pgetc_macro();
10108 switch (c) {
10109 case ' ': case '\t':
Eric Andersen3102ac42001-07-06 04:26:23 +000010110#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010111 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010112#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010113 continue;
10114 case '#':
10115 while ((c = pgetc()) != '\n' && c != PEOF);
10116 pungetc();
10117 continue;
10118 case '\\':
10119 if (pgetc() == '\n') {
10120 startlinno = ++plinno;
10121 if (doprompt)
10122 setprompt(2);
10123 else
10124 setprompt(0);
10125 continue;
10126 }
10127 pungetc();
10128 goto breakloop;
10129 case '\n':
10130 plinno++;
10131 needprompt = doprompt;
10132 RETURN(TNL);
10133 case PEOF:
10134 RETURN(TEOF);
10135 case '&':
10136 if (pgetc() == '&')
10137 RETURN(TAND);
10138 pungetc();
10139 RETURN(TBACKGND);
10140 case '|':
10141 if (pgetc() == '|')
10142 RETURN(TOR);
10143 pungetc();
10144 RETURN(TPIPE);
10145 case ';':
10146 if (pgetc() == ';')
10147 RETURN(TENDCASE);
10148 pungetc();
10149 RETURN(TSEMI);
10150 case '(':
10151 RETURN(TLP);
10152 case ')':
10153 RETURN(TRP);
10154 default:
10155 goto breakloop;
10156 }
10157 }
10158breakloop:
10159 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10160#undef RETURN
10161}
10162
10163
10164
10165/*
10166 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10167 * is not NULL, read a here document. In the latter case, eofmark is the
10168 * word which marks the end of the document and striptabs is true if
10169 * leading tabs should be stripped from the document. The argument firstc
10170 * is the first character of the input token or document.
10171 *
10172 * Because C does not have internal subroutines, I have simulated them
10173 * using goto's to implement the subroutine linkage. The following macros
10174 * will run code that appears at the end of readtoken1.
10175 */
10176
Eric Andersen2870d962001-07-02 17:27:21 +000010177#define CHECKEND() {goto checkend; checkend_return:;}
10178#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10179#define PARSESUB() {goto parsesub; parsesub_return:;}
10180#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10181#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10182#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010183
10184static int
10185readtoken1(firstc, syntax, eofmark, striptabs)
10186 int firstc;
10187 char const *syntax;
10188 char *eofmark;
10189 int striptabs;
10190 {
10191 int c = firstc;
10192 char *out;
10193 int len;
10194 char line[EOFMARKLEN + 1];
10195 struct nodelist *bqlist;
10196 int quotef;
10197 int dblquote;
Eric Andersen2870d962001-07-02 17:27:21 +000010198 int varnest; /* levels of variables expansion */
10199 int arinest; /* levels of arithmetic expansion */
10200 int parenlevel; /* levels of parens in arithmetic */
10201 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +000010202 int oldstyle;
Eric Andersen2870d962001-07-02 17:27:21 +000010203 char const *prevsyntax; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010204#if __GNUC__
10205 /* Avoid longjmp clobbering */
10206 (void) &out;
10207 (void) &quotef;
10208 (void) &dblquote;
10209 (void) &varnest;
10210 (void) &arinest;
10211 (void) &parenlevel;
10212 (void) &dqvarnest;
10213 (void) &oldstyle;
10214 (void) &prevsyntax;
10215 (void) &syntax;
10216#endif
10217
10218 startlinno = plinno;
10219 dblquote = 0;
10220 if (syntax == DQSYNTAX)
10221 dblquote = 1;
10222 quotef = 0;
10223 bqlist = NULL;
10224 varnest = 0;
10225 arinest = 0;
10226 parenlevel = 0;
10227 dqvarnest = 0;
10228
10229 STARTSTACKSTR(out);
Eric Andersen2870d962001-07-02 17:27:21 +000010230 loop: { /* for each line, until end of word */
10231 CHECKEND(); /* set c to PEOF if at end of here document */
10232 for (;;) { /* until end of line or end of word */
10233 CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
Eric Andersencb57d552001-06-28 07:25:16 +000010234 switch(syntax[c]) {
Eric Andersen2870d962001-07-02 17:27:21 +000010235 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010236 if (syntax == BASESYNTAX)
Eric Andersen2870d962001-07-02 17:27:21 +000010237 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010238 USTPUTC(c, out);
10239 plinno++;
10240 if (doprompt)
10241 setprompt(2);
10242 else
10243 setprompt(0);
10244 c = pgetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010245 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010246 case CWORD:
10247 USTPUTC(c, out);
10248 break;
10249 case CCTL:
10250 if ((eofmark == NULL || dblquote) &&
10251 dqvarnest == 0)
10252 USTPUTC(CTLESC, out);
10253 USTPUTC(c, out);
10254 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010255 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010256 c = pgetc2();
10257 if (c == PEOF) {
10258 USTPUTC('\\', out);
10259 pungetc();
10260 } else if (c == '\n') {
10261 if (doprompt)
10262 setprompt(2);
10263 else
10264 setprompt(0);
10265 } else {
10266 if (dblquote && c != '\\' && c != '`' && c != '$'
10267 && (c != '"' || eofmark != NULL))
10268 USTPUTC('\\', out);
10269 if (SQSYNTAX[c] == CCTL)
10270 USTPUTC(CTLESC, out);
10271 else if (eofmark == NULL)
10272 USTPUTC(CTLQUOTEMARK, out);
10273 USTPUTC(c, out);
10274 quotef++;
10275 }
10276 break;
10277 case CSQUOTE:
10278 if (eofmark == NULL)
10279 USTPUTC(CTLQUOTEMARK, out);
10280 syntax = SQSYNTAX;
10281 break;
10282 case CDQUOTE:
10283 if (eofmark == NULL)
10284 USTPUTC(CTLQUOTEMARK, out);
10285 syntax = DQSYNTAX;
10286 dblquote = 1;
10287 break;
10288 case CENDQUOTE:
10289 if (eofmark != NULL && arinest == 0 &&
10290 varnest == 0) {
10291 USTPUTC(c, out);
10292 } else {
10293 if (arinest) {
10294 syntax = ARISYNTAX;
10295 dblquote = 0;
10296 } else if (eofmark == NULL &&
10297 dqvarnest == 0) {
10298 syntax = BASESYNTAX;
10299 dblquote = 0;
10300 }
10301 quotef++;
10302 }
10303 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010304 case CVAR: /* '$' */
10305 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010306 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010307 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010308 if (varnest > 0) {
10309 varnest--;
10310 if (dqvarnest > 0) {
10311 dqvarnest--;
10312 }
10313 USTPUTC(CTLENDVAR, out);
10314 } else {
10315 USTPUTC(c, out);
10316 }
10317 break;
10318#ifdef ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +000010319 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010320 parenlevel++;
10321 USTPUTC(c, out);
10322 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010323 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010324 if (parenlevel > 0) {
10325 USTPUTC(c, out);
10326 --parenlevel;
10327 } else {
10328 if (pgetc() == ')') {
10329 if (--arinest == 0) {
10330 USTPUTC(CTLENDARI, out);
10331 syntax = prevsyntax;
10332 if (syntax == DQSYNTAX)
10333 dblquote = 1;
10334 else
10335 dblquote = 0;
10336 } else
10337 USTPUTC(')', out);
10338 } else {
10339 /*
10340 * unbalanced parens
10341 * (don't 2nd guess - no error)
10342 */
10343 pungetc();
10344 USTPUTC(')', out);
10345 }
10346 }
10347 break;
10348#endif
Eric Andersen2870d962001-07-02 17:27:21 +000010349 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010350 PARSEBACKQOLD();
10351 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010352 case CENDFILE:
10353 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010354 case CIGN:
10355 break;
10356 default:
10357 if (varnest == 0)
Eric Andersen2870d962001-07-02 17:27:21 +000010358 goto endword; /* exit outer loop */
Eric Andersen3102ac42001-07-06 04:26:23 +000010359#ifdef ASH_ALIAS
10360 if (c != PEOA)
10361#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010362 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010363
Eric Andersencb57d552001-06-28 07:25:16 +000010364 }
10365 c = pgetc_macro();
10366 }
10367 }
10368endword:
10369 if (syntax == ARISYNTAX)
10370 synerror("Missing '))'");
10371 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10372 synerror("Unterminated quoted string");
10373 if (varnest != 0) {
10374 startlinno = plinno;
10375 synerror("Missing '}'");
10376 }
10377 USTPUTC('\0', out);
10378 len = out - stackblock();
10379 out = stackblock();
10380 if (eofmark == NULL) {
10381 if ((c == '>' || c == '<')
10382 && quotef == 0
10383 && len <= 2
10384 && (*out == '\0' || is_digit(*out))) {
10385 PARSEREDIR();
10386 return lasttoken = TREDIR;
10387 } else {
10388 pungetc();
10389 }
10390 }
10391 quoteflag = quotef;
10392 backquotelist = bqlist;
10393 grabstackblock(len);
10394 wordtext = out;
10395 return lasttoken = TWORD;
10396/* end of readtoken routine */
10397
10398
10399
10400/*
10401 * Check to see whether we are at the end of the here document. When this
10402 * is called, c is set to the first character of the next input line. If
10403 * we are at the end of the here document, this routine sets the c to PEOF.
10404 */
10405
10406checkend: {
10407 if (eofmark) {
Eric Andersen2870d962001-07-02 17:27:21 +000010408#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010409 if (c == PEOA) {
10410 c = pgetc2();
10411 }
Eric Andersen2870d962001-07-02 17:27:21 +000010412#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010413 if (striptabs) {
10414 while (c == '\t') {
10415 c = pgetc2();
10416 }
10417 }
10418 if (c == *eofmark) {
10419 if (pfgets(line, sizeof line) != NULL) {
10420 char *p, *q;
10421
10422 p = line;
10423 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10424 if (*p == '\n' && *q == '\0') {
10425 c = PEOF;
10426 plinno++;
10427 needprompt = doprompt;
10428 } else {
10429 pushstring(line, strlen(line), NULL);
10430 }
10431 }
10432 }
10433 }
10434 goto checkend_return;
10435}
10436
10437
10438/*
10439 * Parse a redirection operator. The variable "out" points to a string
10440 * specifying the fd to be redirected. The variable "c" contains the
10441 * first character of the redirection operator.
10442 */
10443
10444parseredir: {
10445 char fd = *out;
10446 union node *np;
10447
10448 np = (union node *)stalloc(sizeof (struct nfile));
10449 if (c == '>') {
10450 np->nfile.fd = 1;
10451 c = pgetc();
10452 if (c == '>')
10453 np->type = NAPPEND;
10454 else if (c == '&')
10455 np->type = NTOFD;
10456 else if (c == '|')
10457 np->type = NTOOV;
10458 else {
10459 np->type = NTO;
10460 pungetc();
10461 }
Eric Andersen2870d962001-07-02 17:27:21 +000010462 } else { /* c == '<' */
Eric Andersencb57d552001-06-28 07:25:16 +000010463 np->nfile.fd = 0;
10464 switch (c = pgetc()) {
10465 case '<':
10466 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10467 np = (union node *)stalloc(sizeof (struct nhere));
10468 np->nfile.fd = 0;
10469 }
10470 np->type = NHERE;
10471 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10472 heredoc->here = np;
10473 if ((c = pgetc()) == '-') {
10474 heredoc->striptabs = 1;
10475 } else {
10476 heredoc->striptabs = 0;
10477 pungetc();
10478 }
10479 break;
10480
10481 case '&':
10482 np->type = NFROMFD;
10483 break;
10484
10485 case '>':
10486 np->type = NFROMTO;
10487 break;
10488
10489 default:
10490 np->type = NFROM;
10491 pungetc();
10492 break;
10493 }
10494 }
10495 if (fd != '\0')
10496 np->nfile.fd = digit_val(fd);
10497 redirnode = np;
10498 goto parseredir_return;
10499}
10500
10501
10502/*
10503 * Parse a substitution. At this point, we have read the dollar sign
10504 * and nothing else.
10505 */
10506
10507parsesub: {
10508 int subtype;
10509 int typeloc;
10510 int flags;
10511 char *p;
10512 static const char types[] = "}-+?=";
10513
10514 c = pgetc();
10515 if (
10516 c <= PEOA ||
10517 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10518 ) {
10519 USTPUTC('$', out);
10520 pungetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010521 } else if (c == '(') { /* $(command) or $((arith)) */
Eric Andersencb57d552001-06-28 07:25:16 +000010522 if (pgetc() == '(') {
10523 PARSEARITH();
10524 } else {
10525 pungetc();
10526 PARSEBACKQNEW();
10527 }
10528 } else {
10529 USTPUTC(CTLVAR, out);
10530 typeloc = out - stackblock();
10531 USTPUTC(VSNORMAL, out);
10532 subtype = VSNORMAL;
10533 if (c == '{') {
10534 c = pgetc();
10535 if (c == '#') {
10536 if ((c = pgetc()) == '}')
10537 c = '#';
10538 else
10539 subtype = VSLENGTH;
10540 }
10541 else
10542 subtype = 0;
10543 }
10544 if (c > PEOA && is_name(c)) {
10545 do {
10546 STPUTC(c, out);
10547 c = pgetc();
10548 } while (c > PEOA && is_in_name(c));
10549 } else if (is_digit(c)) {
10550 do {
10551 USTPUTC(c, out);
10552 c = pgetc();
10553 } while (is_digit(c));
10554 }
10555 else if (is_special(c)) {
10556 USTPUTC(c, out);
10557 c = pgetc();
10558 }
10559 else
Eric Andersen2870d962001-07-02 17:27:21 +000010560badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010561
10562 STPUTC('=', out);
10563 flags = 0;
10564 if (subtype == 0) {
10565 switch (c) {
10566 case ':':
10567 flags = VSNUL;
10568 c = pgetc();
10569 /*FALLTHROUGH*/
10570 default:
10571 p = strchr(types, c);
10572 if (p == NULL)
10573 goto badsub;
10574 subtype = p - types + VSNORMAL;
10575 break;
10576 case '%':
10577 case '#':
10578 {
10579 int cc = c;
10580 subtype = c == '#' ? VSTRIMLEFT :
10581 VSTRIMRIGHT;
10582 c = pgetc();
10583 if (c == cc)
10584 subtype++;
10585 else
10586 pungetc();
10587 break;
10588 }
10589 }
10590 } else {
10591 pungetc();
10592 }
10593 if (dblquote || arinest)
10594 flags |= VSQUOTE;
10595 *(stackblock() + typeloc) = subtype | flags;
10596 if (subtype != VSNORMAL) {
10597 varnest++;
10598 if (dblquote) {
10599 dqvarnest++;
10600 }
10601 }
10602 }
10603 goto parsesub_return;
10604}
10605
10606
10607/*
10608 * Called to parse command substitutions. Newstyle is set if the command
10609 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10610 * list of commands (passed by reference), and savelen is the number of
10611 * characters on the top of the stack which must be preserved.
10612 */
10613
10614parsebackq: {
10615 struct nodelist **nlpp;
10616 int savepbq;
10617 union node *n;
10618 char *volatile str;
10619 struct jmploc jmploc;
10620 struct jmploc *volatile savehandler;
10621 int savelen;
10622 int saveprompt;
10623#ifdef __GNUC__
10624 (void) &saveprompt;
10625#endif
10626
10627 savepbq = parsebackquote;
10628 if (setjmp(jmploc.loc)) {
10629 if (str)
10630 ckfree(str);
10631 parsebackquote = 0;
10632 handler = savehandler;
10633 longjmp(handler->loc, 1);
10634 }
10635 INTOFF;
10636 str = NULL;
10637 savelen = out - stackblock();
10638 if (savelen > 0) {
10639 str = ckmalloc(savelen);
10640 memcpy(str, stackblock(), savelen);
10641 }
10642 savehandler = handler;
10643 handler = &jmploc;
10644 INTON;
Eric Andersen2870d962001-07-02 17:27:21 +000010645 if (oldstyle) {
10646 /* We must read until the closing backquote, giving special
10647 treatment to some slashes, and then push the string and
10648 reread it as input, interpreting it normally. */
10649 char *pout;
10650 int pc;
10651 int psavelen;
10652 char *pstr;
Eric Andersencb57d552001-06-28 07:25:16 +000010653
10654
Eric Andersen2870d962001-07-02 17:27:21 +000010655 STARTSTACKSTR(pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010656 for (;;) {
10657 if (needprompt) {
10658 setprompt(2);
10659 needprompt = 0;
10660 }
10661 switch (pc = pgetc()) {
10662 case '`':
10663 goto done;
10664
10665 case '\\':
Eric Andersen2870d962001-07-02 17:27:21 +000010666 if ((pc = pgetc()) == '\n') {
Eric Andersencb57d552001-06-28 07:25:16 +000010667 plinno++;
10668 if (doprompt)
10669 setprompt(2);
10670 else
10671 setprompt(0);
10672 /*
10673 * If eating a newline, avoid putting
10674 * the newline into the new character
10675 * stream (via the STPUTC after the
10676 * switch).
10677 */
10678 continue;
10679 }
Eric Andersen2870d962001-07-02 17:27:21 +000010680 if (pc != '\\' && pc != '`' && pc != '$'
10681 && (!dblquote || pc != '"'))
10682 STPUTC('\\', pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010683 if (pc > PEOA) {
10684 break;
10685 }
10686 /* fall through */
10687
10688 case PEOF:
Eric Andersen2870d962001-07-02 17:27:21 +000010689#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010690 case PEOA:
Eric Andersen2870d962001-07-02 17:27:21 +000010691#endif
10692 startlinno = plinno;
Eric Andersencb57d552001-06-28 07:25:16 +000010693 synerror("EOF in backquote substitution");
10694
10695 case '\n':
10696 plinno++;
10697 needprompt = doprompt;
10698 break;
10699
10700 default:
10701 break;
10702 }
10703 STPUTC(pc, pout);
Eric Andersen2870d962001-07-02 17:27:21 +000010704 }
Eric Andersencb57d552001-06-28 07:25:16 +000010705done:
Eric Andersen2870d962001-07-02 17:27:21 +000010706 STPUTC('\0', pout);
10707 psavelen = pout - stackblock();
10708 if (psavelen > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010709 pstr = grabstackstr(pout);
10710 setinputstring(pstr);
Eric Andersen2870d962001-07-02 17:27:21 +000010711 }
10712 }
Eric Andersencb57d552001-06-28 07:25:16 +000010713 nlpp = &bqlist;
10714 while (*nlpp)
10715 nlpp = &(*nlpp)->next;
10716 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10717 (*nlpp)->next = NULL;
10718 parsebackquote = oldstyle;
10719
10720 if (oldstyle) {
10721 saveprompt = doprompt;
10722 doprompt = 0;
10723 }
10724
10725 n = list(0);
10726
10727 if (oldstyle)
10728 doprompt = saveprompt;
10729 else {
10730 if (readtoken() != TRP)
10731 synexpect(TRP);
10732 }
10733
10734 (*nlpp)->n = n;
Eric Andersen2870d962001-07-02 17:27:21 +000010735 if (oldstyle) {
Eric Andersencb57d552001-06-28 07:25:16 +000010736 /*
10737 * Start reading from old file again, ignoring any pushed back
10738 * tokens left from the backquote parsing
10739 */
Eric Andersen2870d962001-07-02 17:27:21 +000010740 popfile();
Eric Andersencb57d552001-06-28 07:25:16 +000010741 tokpushback = 0;
10742 }
10743 while (stackblocksize() <= savelen)
10744 growstackblock();
10745 STARTSTACKSTR(out);
10746 if (str) {
10747 memcpy(out, str, savelen);
10748 STADJUST(savelen, out);
10749 INTOFF;
10750 ckfree(str);
10751 str = NULL;
10752 INTON;
10753 }
10754 parsebackquote = savepbq;
10755 handler = savehandler;
10756 if (arinest || dblquote)
10757 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10758 else
10759 USTPUTC(CTLBACKQ, out);
10760 if (oldstyle)
10761 goto parsebackq_oldreturn;
10762 else
10763 goto parsebackq_newreturn;
10764}
10765
10766/*
10767 * Parse an arithmetic expansion (indicate start of one and set state)
10768 */
10769parsearith: {
10770
10771 if (++arinest == 1) {
10772 prevsyntax = syntax;
10773 syntax = ARISYNTAX;
10774 USTPUTC(CTLARI, out);
10775 if (dblquote)
10776 USTPUTC('"',out);
10777 else
10778 USTPUTC(' ',out);
10779 } else {
10780 /*
10781 * we collapse embedded arithmetic expansion to
10782 * parenthesis, which should be equivalent
10783 */
10784 USTPUTC('(', out);
10785 }
10786 goto parsearith_return;
10787}
10788
10789} /* end of readtoken */
10790
10791
Eric Andersencb57d552001-06-28 07:25:16 +000010792/*
10793 * Returns true if the text contains nothing to expand (no dollar signs
10794 * or backquotes).
10795 */
10796
10797static int
10798noexpand(text)
10799 char *text;
10800 {
10801 char *p;
10802 char c;
10803
10804 p = text;
10805 while ((c = *p++) != '\0') {
10806 if (c == CTLQUOTEMARK)
10807 continue;
10808 if (c == CTLESC)
10809 p++;
10810 else if (BASESYNTAX[(int)c] == CCTL)
10811 return 0;
10812 }
10813 return 1;
10814}
10815
10816
10817/*
10818 * Return true if the argument is a legal variable name (a letter or
10819 * underscore followed by zero or more letters, underscores, and digits).
10820 */
10821
10822static int
Eric Andersen2870d962001-07-02 17:27:21 +000010823goodname(const char *name)
10824{
10825 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000010826
10827 p = name;
10828 if (! is_name(*p))
10829 return 0;
10830 while (*++p) {
10831 if (! is_in_name(*p))
10832 return 0;
10833 }
10834 return 1;
10835}
10836
10837
10838/*
10839 * Called when an unexpected token is read during the parse. The argument
10840 * is the token that is expected, or -1 if more than one type of token can
10841 * occur at this point.
10842 */
10843
10844static void
10845synexpect(token)
10846 int token;
10847{
10848 char msg[64];
10849
10850 if (token >= 0) {
Eric Andersen3102ac42001-07-06 04:26:23 +000010851 snprintf(msg, 64, "%s unexpected (expecting %s)",
Eric Andersencb57d552001-06-28 07:25:16 +000010852 tokname[lasttoken], tokname[token]);
10853 } else {
Eric Andersen3102ac42001-07-06 04:26:23 +000010854 snprintf(msg, 64, "%s unexpected", tokname[lasttoken]);
Eric Andersencb57d552001-06-28 07:25:16 +000010855 }
10856 synerror(msg);
10857 /* NOTREACHED */
10858}
10859
10860
10861static void
Eric Andersen2870d962001-07-02 17:27:21 +000010862synerror(const char *msg)
10863{
Eric Andersencb57d552001-06-28 07:25:16 +000010864 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +000010865 out2fmt("%s: %d: ", commandname, startlinno);
10866 out2fmt("Syntax error: %s\n", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000010867 error((char *)NULL);
10868 /* NOTREACHED */
10869}
10870
Eric Andersencb57d552001-06-28 07:25:16 +000010871
10872/*
10873 * called by editline -- any expansions to the prompt
10874 * should be added here.
10875 */
Eric Andersen2870d962001-07-02 17:27:21 +000010876static void
Eric Andersen62483552001-07-10 06:09:16 +000010877setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000010878{
Eric Andersen62483552001-07-10 06:09:16 +000010879 char *prompt;
10880 switch (whichprompt) {
10881 case 1:
10882 prompt = ps1val();
10883 break;
10884 case 2:
10885 prompt = ps2val();
10886 break;
10887 default: /* 0 */
10888 prompt = "";
10889 }
10890 putprompt(prompt);
Eric Andersencb57d552001-06-28 07:25:16 +000010891}
10892
Eric Andersencb57d552001-06-28 07:25:16 +000010893
Eric Andersencb57d552001-06-28 07:25:16 +000010894/*
10895 * Code for dealing with input/output redirection.
10896 */
10897
Eric Andersen2870d962001-07-02 17:27:21 +000010898#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000010899#ifndef PIPE_BUF
Eric Andersen2870d962001-07-02 17:27:21 +000010900# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000010901#else
10902# define PIPESIZE PIPE_BUF
10903#endif
10904
10905
Eric Andersen62483552001-07-10 06:09:16 +000010906/*
10907 * Open a file in noclobber mode.
10908 * The code was copied from bash.
10909 */
10910static inline int
10911noclobberopen(const char *fname)
10912{
10913 int r, fd;
10914 struct stat finfo, finfo2;
10915
10916 /*
10917 * If the file exists and is a regular file, return an error
10918 * immediately.
10919 */
10920 r = stat(fname, &finfo);
10921 if (r == 0 && S_ISREG(finfo.st_mode)) {
10922 errno = EEXIST;
10923 return -1;
10924 }
10925
10926 /*
10927 * If the file was not present (r != 0), make sure we open it
10928 * exclusively so that if it is created before we open it, our open
10929 * will fail. Make sure that we do not truncate an existing file.
10930 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10931 * file was not a regular file, we leave O_EXCL off.
10932 */
10933 if (r != 0)
10934 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10935 fd = open(fname, O_WRONLY|O_CREAT, 0666);
10936
10937 /* If the open failed, return the file descriptor right away. */
10938 if (fd < 0)
10939 return fd;
10940
10941 /*
10942 * OK, the open succeeded, but the file may have been changed from a
10943 * non-regular file to a regular file between the stat and the open.
10944 * We are assuming that the O_EXCL open handles the case where FILENAME
10945 * did not exist and is symlinked to an existing file between the stat
10946 * and open.
10947 */
10948
10949 /*
10950 * If we can open it and fstat the file descriptor, and neither check
10951 * revealed that it was a regular file, and the file has not been
10952 * replaced, return the file descriptor.
10953 */
10954 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10955 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
10956 return fd;
10957
10958 /* The file has been replaced. badness. */
10959 close(fd);
10960 errno = EEXIST;
10961 return -1;
10962}
Eric Andersencb57d552001-06-28 07:25:16 +000010963
10964/*
Eric Andersen62483552001-07-10 06:09:16 +000010965 * Handle here documents. Normally we fork off a process to write the
10966 * data to a pipe. If the document is short, we can stuff the data in
10967 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000010968 */
10969
Eric Andersen62483552001-07-10 06:09:16 +000010970static inline int
10971openhere(const union node *redir)
10972{
10973 int pip[2];
10974 int len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010975
Eric Andersen62483552001-07-10 06:09:16 +000010976 if (pipe(pip) < 0)
10977 error("Pipe call failed");
10978 if (redir->type == NHERE) {
10979 len = strlen(redir->nhere.doc->narg.text);
10980 if (len <= PIPESIZE) {
10981 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10982 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010983 }
Eric Andersencb57d552001-06-28 07:25:16 +000010984 }
Eric Andersen62483552001-07-10 06:09:16 +000010985 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
10986 close(pip[0]);
10987 signal(SIGINT, SIG_IGN);
10988 signal(SIGQUIT, SIG_IGN);
10989 signal(SIGHUP, SIG_IGN);
10990#ifdef SIGTSTP
10991 signal(SIGTSTP, SIG_IGN);
10992#endif
10993 signal(SIGPIPE, SIG_DFL);
10994 if (redir->type == NHERE)
10995 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10996 else
10997 expandhere(redir->nhere.doc, pip[1]);
10998 _exit(0);
10999 }
11000out:
11001 close(pip[1]);
11002 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000011003}
11004
11005
Eric Andersen62483552001-07-10 06:09:16 +000011006static inline int
11007openredirect(const union node *redir)
11008{
Eric Andersencb57d552001-06-28 07:25:16 +000011009 char *fname;
11010 int f;
11011
11012 switch (redir->nfile.type) {
11013 case NFROM:
11014 fname = redir->nfile.expfname;
11015 if ((f = open(fname, O_RDONLY)) < 0)
11016 goto eopen;
11017 break;
11018 case NFROMTO:
11019 fname = redir->nfile.expfname;
11020 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
11021 goto ecreate;
11022 break;
11023 case NTO:
11024 /* Take care of noclobber mode. */
11025 if (Cflag) {
11026 fname = redir->nfile.expfname;
11027 if ((f = noclobberopen(fname)) < 0)
11028 goto ecreate;
11029 break;
11030 }
11031 case NTOOV:
11032 fname = redir->nfile.expfname;
11033#ifdef O_CREAT
11034 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
11035 goto ecreate;
11036#else
11037 if ((f = creat(fname, 0666)) < 0)
11038 goto ecreate;
11039#endif
11040 break;
11041 case NAPPEND:
11042 fname = redir->nfile.expfname;
11043#ifdef O_APPEND
11044 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
11045 goto ecreate;
11046#else
11047 if ((f = open(fname, O_WRONLY)) < 0
11048 && (f = creat(fname, 0666)) < 0)
11049 goto ecreate;
11050 lseek(f, (off_t)0, 2);
11051#endif
11052 break;
11053 default:
11054#ifdef DEBUG
11055 abort();
11056#endif
11057 /* Fall through to eliminate warning. */
11058 case NTOFD:
11059 case NFROMFD:
11060 f = -1;
11061 break;
11062 case NHERE:
11063 case NXHERE:
11064 f = openhere(redir);
11065 break;
11066 }
11067
11068 return f;
11069ecreate:
11070 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11071eopen:
11072 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11073}
11074
11075
Eric Andersen62483552001-07-10 06:09:16 +000011076/*
11077 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11078 * old file descriptors are stashed away so that the redirection can be
11079 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11080 * standard output, and the standard error if it becomes a duplicate of
11081 * stdout.
11082 */
11083
Eric Andersencb57d552001-06-28 07:25:16 +000011084static void
Eric Andersen62483552001-07-10 06:09:16 +000011085redirect(union node *redir, int flags)
11086{
11087 union node *n;
11088 struct redirtab *sv = NULL;
11089 int i;
11090 int fd;
11091 int newfd;
11092 int try;
11093 int fd1dup = flags & REDIR_BACKQ;; /* stdout `cmd` redir to pipe */
11094
11095 if (flags & REDIR_PUSH) {
11096 sv = ckmalloc(sizeof (struct redirtab));
11097 for (i = 0 ; i < 10 ; i++)
11098 sv->renamed[i] = EMPTY;
11099 sv->next = redirlist;
11100 redirlist = sv;
11101 }
11102 for (n = redir ; n ; n = n->nfile.next) {
11103 fd = n->nfile.fd;
11104 try = 0;
11105 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11106 n->ndup.dupfd == fd)
11107 continue; /* redirect from/to same file descriptor */
11108
11109 INTOFF;
11110 newfd = openredirect(n);
11111 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
11112 if (newfd == fd) {
11113 try++;
11114 } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
11115 switch (errno) {
11116 case EBADF:
11117 if (!try) {
11118 dupredirect(n, newfd, fd1dup);
11119 try++;
11120 break;
11121 }
11122 /* FALLTHROUGH*/
11123 default:
11124 if (newfd >= 0) {
11125 close(newfd);
11126 }
11127 INTON;
11128 error("%d: %m", fd);
11129 /* NOTREACHED */
11130 }
11131 }
11132 if (!try) {
11133 close(fd);
11134 if (flags & REDIR_PUSH) {
11135 sv->renamed[fd] = i;
11136 }
11137 }
11138 } else if (fd != newfd) {
11139 close(fd);
11140 }
11141 if (fd == 0)
11142 fd0_redirected++;
11143 if (!try)
11144 dupredirect(n, newfd, fd1dup);
11145 INTON;
11146 }
11147}
11148
11149
11150static void
11151dupredirect(const union node *redir, int f, int fd1dup)
Eric Andersen2870d962001-07-02 17:27:21 +000011152{
Eric Andersencb57d552001-06-28 07:25:16 +000011153 int fd = redir->nfile.fd;
11154
Eric Andersen62483552001-07-10 06:09:16 +000011155 if(fd==1)
11156 fd1dup = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011157 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Eric Andersen2870d962001-07-02 17:27:21 +000011158 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
Eric Andersen62483552001-07-10 06:09:16 +000011159 if (redir->ndup.dupfd!=1 || fd1dup!=1)
Eric Andersencb57d552001-06-28 07:25:16 +000011160 dup_as_newfd(redir->ndup.dupfd, fd);
11161 }
11162 return;
11163 }
11164
11165 if (f != fd) {
11166 dup_as_newfd(f, fd);
11167 close(f);
11168 }
11169 return;
11170}
11171
11172
Eric Andersencb57d552001-06-28 07:25:16 +000011173
Eric Andersencb57d552001-06-28 07:25:16 +000011174/*
11175 * Undo the effects of the last redirection.
11176 */
11177
11178static void
Eric Andersen2870d962001-07-02 17:27:21 +000011179popredir(void)
11180{
Eric Andersencb57d552001-06-28 07:25:16 +000011181 struct redirtab *rp = redirlist;
11182 int i;
11183
11184 INTOFF;
11185 for (i = 0 ; i < 10 ; i++) {
11186 if (rp->renamed[i] != EMPTY) {
Eric Andersen2870d962001-07-02 17:27:21 +000011187 if (i == 0)
11188 fd0_redirected--;
Eric Andersencb57d552001-06-28 07:25:16 +000011189 close(i);
11190 if (rp->renamed[i] >= 0) {
11191 dup_as_newfd(rp->renamed[i], i);
11192 close(rp->renamed[i]);
11193 }
Eric Andersencb57d552001-06-28 07:25:16 +000011194 }
11195 }
11196 redirlist = rp->next;
11197 ckfree(rp);
11198 INTON;
11199}
11200
11201/*
Eric Andersencb57d552001-06-28 07:25:16 +000011202 * Discard all saved file descriptors.
11203 */
11204
11205static void
Eric Andersen2870d962001-07-02 17:27:21 +000011206clearredir(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000011207 struct redirtab *rp;
11208 int i;
11209
11210 for (rp = redirlist ; rp ; rp = rp->next) {
11211 for (i = 0 ; i < 10 ; i++) {
11212 if (rp->renamed[i] >= 0) {
11213 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011214 }
11215 rp->renamed[i] = EMPTY;
11216 }
11217 }
Eric Andersencb57d552001-06-28 07:25:16 +000011218}
11219
11220
Eric Andersencb57d552001-06-28 07:25:16 +000011221/*
11222 * Copy a file descriptor to be >= to. Returns -1
11223 * if the source file descriptor is closed, EMPTY if there are no unused
11224 * file descriptors left.
11225 */
11226
11227static int
11228dup_as_newfd(from, to)
11229 int from;
11230 int to;
11231{
11232 int newfd;
11233
11234 newfd = fcntl(from, F_DUPFD, to);
11235 if (newfd < 0) {
11236 if (errno == EMFILE)
11237 return EMPTY;
11238 else
Eric Andersen2870d962001-07-02 17:27:21 +000011239 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011240 }
11241 return newfd;
11242}
11243
Eric Andersen2870d962001-07-02 17:27:21 +000011244/*#ifdef __weak_alias
Eric Andersencb57d552001-06-28 07:25:16 +000011245__weak_alias(getmode,_getmode)
11246__weak_alias(setmode,_setmode)
Eric Andersen2870d962001-07-02 17:27:21 +000011247#endif*/
Eric Andersencb57d552001-06-28 07:25:16 +000011248
Eric Andersen62483552001-07-10 06:09:16 +000011249#ifndef S_ISTXT
11250#if defined(__GLIBC__) && __GLIBC__ >= 2
Eric Andersencb57d552001-06-28 07:25:16 +000011251#define S_ISTXT __S_ISVTX
Eric Andersen62483552001-07-10 06:09:16 +000011252#else
11253#define S_ISTXT S_ISVTX
11254#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011255#endif
11256
Eric Andersen2870d962001-07-02 17:27:21 +000011257#define SET_LEN 6 /* initial # of bitcmd struct to malloc */
11258#define SET_LEN_INCR 4 /* # of bitcmd structs to add as needed */
Eric Andersencb57d552001-06-28 07:25:16 +000011259
11260typedef struct bitcmd {
Eric Andersen2870d962001-07-02 17:27:21 +000011261 char cmd;
11262 char cmd2;
11263 mode_t bits;
Eric Andersencb57d552001-06-28 07:25:16 +000011264} BITCMD;
11265
Eric Andersen2870d962001-07-02 17:27:21 +000011266#define CMD2_CLR 0x01
11267#define CMD2_SET 0x02
11268#define CMD2_GBITS 0x04
11269#define CMD2_OBITS 0x08
11270#define CMD2_UBITS 0x10
Eric Andersencb57d552001-06-28 07:25:16 +000011271
Eric Andersen2870d962001-07-02 17:27:21 +000011272static BITCMD *addcmd (BITCMD *, int, int, int, u_int);
11273static void compress_mode (BITCMD *);
Eric Andersencb57d552001-06-28 07:25:16 +000011274#ifdef SETMODE_DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +000011275static void dumpmode (BITCMD *);
Eric Andersencb57d552001-06-28 07:25:16 +000011276#endif
11277
11278/*
11279 * Given the old mode and an array of bitcmd structures, apply the operations
11280 * described in the bitcmd structures to the old mode, and return the new mode.
11281 * Note that there is no '=' command; a strict assignment is just a '-' (clear
11282 * bits) followed by a '+' (set bits).
11283 */
Eric Andersen2870d962001-07-02 17:27:21 +000011284static mode_t
Eric Andersencb57d552001-06-28 07:25:16 +000011285getmode(bbox, omode)
11286 const void *bbox;
11287 mode_t omode;
11288{
11289 const BITCMD *set;
11290 mode_t clrval, newmode, value;
11291
11292 _DIAGASSERT(bbox != NULL);
11293
11294 set = (const BITCMD *)bbox;
11295 newmode = omode;
11296 for (value = 0;; set++)
11297 switch(set->cmd) {
11298 /*
11299 * When copying the user, group or other bits around, we "know"
11300 * where the bits are in the mode so that we can do shifts to
11301 * copy them around. If we don't use shifts, it gets real
11302 * grundgy with lots of single bit checks and bit sets.
11303 */
11304 case 'u':
11305 value = (newmode & S_IRWXU) >> 6;
11306 goto common;
11307
11308 case 'g':
11309 value = (newmode & S_IRWXG) >> 3;
11310 goto common;
11311
11312 case 'o':
11313 value = newmode & S_IRWXO;
Eric Andersen2870d962001-07-02 17:27:21 +000011314common: if (set->cmd2 & CMD2_CLR) {
Eric Andersencb57d552001-06-28 07:25:16 +000011315 clrval =
11316 (set->cmd2 & CMD2_SET) ? S_IRWXO : value;
11317 if (set->cmd2 & CMD2_UBITS)
11318 newmode &= ~((clrval<<6) & set->bits);
11319 if (set->cmd2 & CMD2_GBITS)
11320 newmode &= ~((clrval<<3) & set->bits);
11321 if (set->cmd2 & CMD2_OBITS)
11322 newmode &= ~(clrval & set->bits);
11323 }
11324 if (set->cmd2 & CMD2_SET) {
11325 if (set->cmd2 & CMD2_UBITS)
11326 newmode |= (value<<6) & set->bits;
11327 if (set->cmd2 & CMD2_GBITS)
11328 newmode |= (value<<3) & set->bits;
11329 if (set->cmd2 & CMD2_OBITS)
11330 newmode |= value & set->bits;
11331 }
11332 break;
11333
11334 case '+':
11335 newmode |= set->bits;
11336 break;
11337
11338 case '-':
11339 newmode &= ~set->bits;
11340 break;
11341
11342 case 'X':
11343 if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
11344 newmode |= set->bits;
11345 break;
11346
11347 case '\0':
11348 default:
11349#ifdef SETMODE_DEBUG
11350 (void)printf("getmode:%04o -> %04o\n", omode, newmode);
11351#endif
11352 return (newmode);
11353 }
11354}
11355
Eric Andersen2870d962001-07-02 17:27:21 +000011356#define ADDCMD(a, b, c, d) do { \
11357 if (set >= endset) { \
11358 BITCMD *newset; \
11359 setlen += SET_LEN_INCR; \
11360 newset = realloc(saveset, sizeof(BITCMD) * setlen); \
11361 if (newset == NULL) { \
11362 free(saveset); \
11363 return (NULL); \
11364 } \
11365 set = newset + (set - saveset); \
11366 saveset = newset; \
11367 endset = newset + (setlen - 2); \
11368 } \
11369 set = addcmd(set, (a), (b), (c), (d)); \
Eric Andersencb57d552001-06-28 07:25:16 +000011370} while (/*CONSTCOND*/0)
11371
Eric Andersen2870d962001-07-02 17:27:21 +000011372#define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
Eric Andersencb57d552001-06-28 07:25:16 +000011373
11374static void *
11375setmode(p)
11376 const char *p;
11377{
11378 int perm, who;
11379 char op, *ep;
11380 BITCMD *set, *saveset, *endset;
11381 sigset_t mysigset, sigoset;
11382 mode_t mask;
Eric Andersen2870d962001-07-02 17:27:21 +000011383 int equalopdone = 0; /* pacify gcc */
Eric Andersencb57d552001-06-28 07:25:16 +000011384 int permXbits, setlen;
11385
11386 if (!*p)
11387 return (NULL);
11388
11389 /*
11390 * Get a copy of the mask for the permissions that are mask relative.
11391 * Flip the bits, we want what's not set. Since it's possible that
11392 * the caller is opening files inside a signal handler, protect them
11393 * as best we can.
11394 */
11395 sigfillset(&mysigset);
11396 (void)sigprocmask(SIG_BLOCK, &mysigset, &sigoset);
11397 (void)umask(mask = umask(0));
11398 mask = ~mask;
11399 (void)sigprocmask(SIG_SETMASK, &sigoset, NULL);
11400
11401 setlen = SET_LEN + 2;
Eric Andersen2870d962001-07-02 17:27:21 +000011402
Eric Andersencb57d552001-06-28 07:25:16 +000011403 if ((set = malloc((u_int)(sizeof(BITCMD) * setlen))) == NULL)
11404 return (NULL);
11405 saveset = set;
11406 endset = set + (setlen - 2);
11407
11408 /*
11409 * If an absolute number, get it and return; disallow non-octal digits
11410 * or illegal bits.
11411 */
Eric Andersen62483552001-07-10 06:09:16 +000011412 if (is_digit((unsigned char)*p)) {
Eric Andersencb57d552001-06-28 07:25:16 +000011413 perm = (mode_t)strtol(p, &ep, 8);
11414 if (*ep || perm & ~(STANDARD_BITS|S_ISTXT)) {
11415 free(saveset);
11416 return (NULL);
11417 }
11418 ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask);
11419 set->cmd = 0;
11420 return (saveset);
11421 }
11422
11423 /*
11424 * Build list of structures to set/clear/copy bits as described by
11425 * each clause of the symbolic mode.
11426 */
11427 for (;;) {
11428 /* First, find out which bits might be modified. */
11429 for (who = 0;; ++p) {
11430 switch (*p) {
11431 case 'a':
11432 who |= STANDARD_BITS;
11433 break;
11434 case 'u':
11435 who |= S_ISUID|S_IRWXU;
11436 break;
11437 case 'g':
11438 who |= S_ISGID|S_IRWXG;
11439 break;
11440 case 'o':
11441 who |= S_IRWXO;
11442 break;
11443 default:
11444 goto getop;
11445 }
11446 }
11447
Eric Andersen2870d962001-07-02 17:27:21 +000011448getop: if ((op = *p++) != '+' && op != '-' && op != '=') {
Eric Andersencb57d552001-06-28 07:25:16 +000011449 free(saveset);
11450 return (NULL);
11451 }
11452 if (op == '=')
11453 equalopdone = 0;
11454
11455 who &= ~S_ISTXT;
11456 for (perm = 0, permXbits = 0;; ++p) {
11457 switch (*p) {
11458 case 'r':
11459 perm |= S_IRUSR|S_IRGRP|S_IROTH;
11460 break;
11461 case 's':
11462 /*
Eric Andersen2870d962001-07-02 17:27:21 +000011463 * If specific bits where requested and
11464 * only "other" bits ignore set-id.
Eric Andersencb57d552001-06-28 07:25:16 +000011465 */
11466 if (who == 0 || (who & ~S_IRWXO))
11467 perm |= S_ISUID|S_ISGID;
11468 break;
11469 case 't':
11470 /*
Eric Andersen2870d962001-07-02 17:27:21 +000011471 * If specific bits where requested and
11472 * only "other" bits ignore set-id.
Eric Andersencb57d552001-06-28 07:25:16 +000011473 */
11474 if (who == 0 || (who & ~S_IRWXO)) {
11475 who |= S_ISTXT;
11476 perm |= S_ISTXT;
11477 }
11478 break;
11479 case 'w':
11480 perm |= S_IWUSR|S_IWGRP|S_IWOTH;
11481 break;
11482 case 'X':
11483 permXbits = S_IXUSR|S_IXGRP|S_IXOTH;
11484 break;
11485 case 'x':
11486 perm |= S_IXUSR|S_IXGRP|S_IXOTH;
11487 break;
11488 case 'u':
11489 case 'g':
11490 case 'o':
11491 /*
11492 * When ever we hit 'u', 'g', or 'o', we have
11493 * to flush out any partial mode that we have,
11494 * and then do the copying of the mode bits.
11495 */
11496 if (perm) {
11497 ADDCMD(op, who, perm, mask);
11498 perm = 0;
11499 }
11500 if (op == '=')
11501 equalopdone = 1;
11502 if (op == '+' && permXbits) {
11503 ADDCMD('X', who, permXbits, mask);
11504 permXbits = 0;
11505 }
11506 ADDCMD(*p, who, op, mask);
11507 break;
11508
11509 default:
11510 /*
11511 * Add any permissions that we haven't already
11512 * done.
11513 */
11514 if (perm || (op == '=' && !equalopdone)) {
11515 if (op == '=')
11516 equalopdone = 1;
11517 ADDCMD(op, who, perm, mask);
11518 perm = 0;
11519 }
11520 if (permXbits) {
11521 ADDCMD('X', who, permXbits, mask);
11522 permXbits = 0;
11523 }
11524 goto apply;
11525 }
11526 }
11527
Eric Andersen2870d962001-07-02 17:27:21 +000011528apply: if (!*p)
Eric Andersencb57d552001-06-28 07:25:16 +000011529 break;
11530 if (*p != ',')
11531 goto getop;
11532 ++p;
11533 }
11534 set->cmd = 0;
11535#ifdef SETMODE_DEBUG
11536 (void)printf("Before compress_mode()\n");
11537 dumpmode(saveset);
11538#endif
11539 compress_mode(saveset);
11540#ifdef SETMODE_DEBUG
11541 (void)printf("After compress_mode()\n");
11542 dumpmode(saveset);
11543#endif
11544 return (saveset);
11545}
11546
11547static BITCMD *
11548addcmd(set, op, who, oparg, mask)
11549 BITCMD *set;
11550 int oparg, who;
11551 int op;
11552 u_int mask;
11553{
11554
11555 _DIAGASSERT(set != NULL);
11556
11557 switch (op) {
11558 case '=':
11559 set->cmd = '-';
11560 set->bits = who ? who : STANDARD_BITS;
11561 set++;
11562
11563 op = '+';
11564 /* FALLTHROUGH */
11565 case '+':
11566 case '-':
11567 case 'X':
11568 set->cmd = op;
11569 set->bits = (who ? who : mask) & oparg;
11570 break;
11571
11572 case 'u':
11573 case 'g':
11574 case 'o':
11575 set->cmd = op;
11576 if (who) {
11577 set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) |
11578 ((who & S_IRGRP) ? CMD2_GBITS : 0) |
11579 ((who & S_IROTH) ? CMD2_OBITS : 0);
11580 set->bits = (mode_t)~0;
11581 } else {
11582 set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS;
11583 set->bits = mask;
11584 }
Eric Andersen2870d962001-07-02 17:27:21 +000011585
Eric Andersencb57d552001-06-28 07:25:16 +000011586 if (oparg == '+')
11587 set->cmd2 |= CMD2_SET;
11588 else if (oparg == '-')
11589 set->cmd2 |= CMD2_CLR;
11590 else if (oparg == '=')
11591 set->cmd2 |= CMD2_SET|CMD2_CLR;
11592 break;
11593 }
11594 return (set + 1);
11595}
11596
11597#ifdef SETMODE_DEBUG
11598static void
11599dumpmode(set)
11600 BITCMD *set;
11601{
11602
11603 _DIAGASSERT(set != NULL);
11604
11605 for (; set->cmd; ++set)
11606 (void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n",
11607 set->cmd, set->bits, set->cmd2 ? " cmd2:" : "",
11608 set->cmd2 & CMD2_CLR ? " CLR" : "",
11609 set->cmd2 & CMD2_SET ? " SET" : "",
11610 set->cmd2 & CMD2_UBITS ? " UBITS" : "",
11611 set->cmd2 & CMD2_GBITS ? " GBITS" : "",
11612 set->cmd2 & CMD2_OBITS ? " OBITS" : "");
11613}
11614#endif
11615
11616/*
11617 * Given an array of bitcmd structures, compress by compacting consecutive
11618 * '+', '-' and 'X' commands into at most 3 commands, one of each. The 'u',
Eric Andersen2870d962001-07-02 17:27:21 +000011619 * 'g' and 'o' commands continue to be separate. They could probably be
Eric Andersencb57d552001-06-28 07:25:16 +000011620 * compacted, but it's not worth the effort.
11621 */
11622static void
11623compress_mode(set)
11624 BITCMD *set;
11625{
11626 BITCMD *nset;
11627 int setbits, clrbits, Xbits, op;
11628
11629 _DIAGASSERT(set != NULL);
11630
11631 for (nset = set;;) {
11632 /* Copy over any 'u', 'g' and 'o' commands. */
11633 while ((op = nset->cmd) != '+' && op != '-' && op != 'X') {
11634 *set++ = *nset++;
11635 if (!op)
11636 return;
11637 }
11638
11639 for (setbits = clrbits = Xbits = 0;; nset++) {
11640 if ((op = nset->cmd) == '-') {
11641 clrbits |= nset->bits;
11642 setbits &= ~nset->bits;
11643 Xbits &= ~nset->bits;
11644 } else if (op == '+') {
11645 setbits |= nset->bits;
11646 clrbits &= ~nset->bits;
11647 Xbits &= ~nset->bits;
11648 } else if (op == 'X')
11649 Xbits |= nset->bits & ~setbits;
11650 else
11651 break;
11652 }
11653 if (clrbits) {
11654 set->cmd = '-';
11655 set->cmd2 = 0;
11656 set->bits = clrbits;
11657 set++;
11658 }
11659 if (setbits) {
11660 set->cmd = '+';
11661 set->cmd2 = 0;
11662 set->bits = setbits;
11663 set++;
11664 }
11665 if (Xbits) {
11666 set->cmd = 'X';
11667 set->cmd2 = 0;
11668 set->bits = Xbits;
11669 set++;
11670 }
11671 }
11672}
Eric Andersencb57d552001-06-28 07:25:16 +000011673#ifdef DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +000011674static void shtree (union node *, int, char *, FILE*);
11675static void shcmd (union node *, FILE *);
11676static void sharg (union node *, FILE *);
11677static void indent (int, char *, FILE *);
11678static void trstring (char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011679
11680
11681static void
11682showtree(n)
11683 union node *n;
11684{
11685 trputs("showtree called\n");
11686 shtree(n, 1, NULL, stdout);
11687}
11688
11689
11690static void
11691shtree(n, ind, pfx, fp)
11692 union node *n;
11693 int ind;
11694 char *pfx;
11695 FILE *fp;
11696{
11697 struct nodelist *lp;
11698 const char *s;
11699
11700 if (n == NULL)
11701 return;
11702
11703 indent(ind, pfx, fp);
11704 switch(n->type) {
11705 case NSEMI:
11706 s = "; ";
11707 goto binop;
11708 case NAND:
11709 s = " && ";
11710 goto binop;
11711 case NOR:
11712 s = " || ";
11713binop:
11714 shtree(n->nbinary.ch1, ind, NULL, fp);
11715 /* if (ind < 0) */
11716 fputs(s, fp);
11717 shtree(n->nbinary.ch2, ind, NULL, fp);
11718 break;
11719 case NCMD:
11720 shcmd(n, fp);
11721 if (ind >= 0)
11722 putc('\n', fp);
11723 break;
11724 case NPIPE:
11725 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11726 shcmd(lp->n, fp);
11727 if (lp->next)
11728 fputs(" | ", fp);
11729 }
11730 if (n->npipe.backgnd)
11731 fputs(" &", fp);
11732 if (ind >= 0)
11733 putc('\n', fp);
11734 break;
11735 default:
11736 fprintf(fp, "<node type %d>", n->type);
11737 if (ind >= 0)
11738 putc('\n', fp);
11739 break;
11740 }
11741}
11742
11743
11744
11745static void
11746shcmd(cmd, fp)
11747 union node *cmd;
11748 FILE *fp;
11749{
11750 union node *np;
11751 int first;
11752 const char *s;
11753 int dftfd;
11754
11755 first = 1;
11756 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11757 if (! first)
11758 putchar(' ');
11759 sharg(np, fp);
11760 first = 0;
11761 }
11762 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11763 if (! first)
11764 putchar(' ');
11765 switch (np->nfile.type) {
Eric Andersen2870d962001-07-02 17:27:21 +000011766 case NTO: s = ">"; dftfd = 1; break;
11767 case NAPPEND: s = ">>"; dftfd = 1; break;
11768 case NTOFD: s = ">&"; dftfd = 1; break;
11769 case NTOOV: s = ">|"; dftfd = 1; break;
11770 case NFROM: s = "<"; dftfd = 0; break;
11771 case NFROMFD: s = "<&"; dftfd = 0; break;
11772 case NFROMTO: s = "<>"; dftfd = 0; break;
11773 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011774 }
11775 if (np->nfile.fd != dftfd)
11776 fprintf(fp, "%d", np->nfile.fd);
11777 fputs(s, fp);
11778 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11779 fprintf(fp, "%d", np->ndup.dupfd);
11780 } else {
11781 sharg(np->nfile.fname, fp);
11782 }
11783 first = 0;
11784 }
11785}
11786
11787
11788
11789static void
11790sharg(arg, fp)
11791 union node *arg;
11792 FILE *fp;
11793 {
11794 char *p;
11795 struct nodelist *bqlist;
11796 int subtype;
11797
11798 if (arg->type != NARG) {
11799 printf("<node type %d>\n", arg->type);
11800 fflush(stdout);
11801 abort();
11802 }
11803 bqlist = arg->narg.backquote;
11804 for (p = arg->narg.text ; *p ; p++) {
11805 switch (*p) {
11806 case CTLESC:
11807 putc(*++p, fp);
11808 break;
11809 case CTLVAR:
11810 putc('$', fp);
11811 putc('{', fp);
11812 subtype = *++p;
11813 if (subtype == VSLENGTH)
11814 putc('#', fp);
11815
11816 while (*p != '=')
11817 putc(*p++, fp);
11818
11819 if (subtype & VSNUL)
11820 putc(':', fp);
11821
11822 switch (subtype & VSTYPE) {
11823 case VSNORMAL:
11824 putc('}', fp);
11825 break;
11826 case VSMINUS:
11827 putc('-', fp);
11828 break;
11829 case VSPLUS:
11830 putc('+', fp);
11831 break;
11832 case VSQUESTION:
11833 putc('?', fp);
11834 break;
11835 case VSASSIGN:
11836 putc('=', fp);
11837 break;
11838 case VSTRIMLEFT:
11839 putc('#', fp);
11840 break;
11841 case VSTRIMLEFTMAX:
11842 putc('#', fp);
11843 putc('#', fp);
11844 break;
11845 case VSTRIMRIGHT:
11846 putc('%', fp);
11847 break;
11848 case VSTRIMRIGHTMAX:
11849 putc('%', fp);
11850 putc('%', fp);
11851 break;
11852 case VSLENGTH:
11853 break;
11854 default:
11855 printf("<subtype %d>", subtype);
11856 }
11857 break;
11858 case CTLENDVAR:
11859 putc('}', fp);
11860 break;
11861 case CTLBACKQ:
11862 case CTLBACKQ|CTLQUOTE:
11863 putc('$', fp);
11864 putc('(', fp);
11865 shtree(bqlist->n, -1, NULL, fp);
11866 putc(')', fp);
11867 break;
11868 default:
11869 putc(*p, fp);
11870 break;
11871 }
11872 }
11873}
11874
11875
11876static void
11877indent(amount, pfx, fp)
11878 int amount;
11879 char *pfx;
11880 FILE *fp;
11881{
11882 int i;
11883
11884 for (i = 0 ; i < amount ; i++) {
11885 if (pfx && i == amount - 1)
11886 fputs(pfx, fp);
11887 putc('\t', fp);
11888 }
11889}
11890#endif
11891
11892
11893
11894/*
11895 * Debugging stuff.
11896 */
11897
11898
11899#ifdef DEBUG
11900FILE *tracefile;
11901
11902#if DEBUG == 2
11903static int debug = 1;
11904#else
11905static int debug = 0;
11906#endif
11907
11908
11909static void
11910trputc(c)
11911 int c;
11912{
11913 if (tracefile == NULL)
11914 return;
11915 putc(c, tracefile);
11916 if (c == '\n')
11917 fflush(tracefile);
11918}
11919
11920static void
11921trace(const char *fmt, ...)
11922{
11923 va_list va;
Eric Andersencb57d552001-06-28 07:25:16 +000011924 va_start(va, fmt);
Eric Andersencb57d552001-06-28 07:25:16 +000011925 if (tracefile != NULL) {
11926 (void) vfprintf(tracefile, fmt, va);
11927 if (strchr(fmt, '\n'))
11928 (void) fflush(tracefile);
11929 }
11930 va_end(va);
11931}
11932
11933
11934static void
11935trputs(s)
11936 const char *s;
11937{
11938 if (tracefile == NULL)
11939 return;
11940 fputs(s, tracefile);
11941 if (strchr(s, '\n'))
11942 fflush(tracefile);
11943}
11944
11945
11946static void
11947trstring(s)
11948 char *s;
11949{
11950 char *p;
11951 char c;
11952
11953 if (tracefile == NULL)
11954 return;
11955 putc('"', tracefile);
11956 for (p = s ; *p ; p++) {
11957 switch (*p) {
11958 case '\n': c = 'n'; goto backslash;
11959 case '\t': c = 't'; goto backslash;
11960 case '\r': c = 'r'; goto backslash;
11961 case '"': c = '"'; goto backslash;
11962 case '\\': c = '\\'; goto backslash;
11963 case CTLESC: c = 'e'; goto backslash;
11964 case CTLVAR: c = 'v'; goto backslash;
11965 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11966 case CTLBACKQ: c = 'q'; goto backslash;
11967 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
Eric Andersen2870d962001-07-02 17:27:21 +000011968backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011969 putc(c, tracefile);
11970 break;
11971 default:
11972 if (*p >= ' ' && *p <= '~')
11973 putc(*p, tracefile);
11974 else {
11975 putc('\\', tracefile);
11976 putc(*p >> 6 & 03, tracefile);
11977 putc(*p >> 3 & 07, tracefile);
11978 putc(*p & 07, tracefile);
11979 }
11980 break;
11981 }
11982 }
11983 putc('"', tracefile);
11984}
11985
11986
11987static void
11988trargs(ap)
11989 char **ap;
11990{
11991 if (tracefile == NULL)
11992 return;
11993 while (*ap) {
11994 trstring(*ap++);
11995 if (*ap)
11996 putc(' ', tracefile);
11997 else
11998 putc('\n', tracefile);
11999 }
12000 fflush(tracefile);
12001}
12002
12003
12004static void
12005opentrace() {
12006 char s[100];
12007#ifdef O_APPEND
12008 int flags;
12009#endif
12010
12011 if (!debug)
12012 return;
12013#ifdef not_this_way
12014 {
12015 char *p;
12016 if ((p = getenv("HOME")) == NULL) {
12017 if (geteuid() == 0)
12018 p = "/";
12019 else
12020 p = "/tmp";
12021 }
Eric Andersen2870d962001-07-02 17:27:21 +000012022 strcpy(s, p);
Eric Andersencb57d552001-06-28 07:25:16 +000012023 strcat(s, "/trace");
12024 }
12025#else
Eric Andersen2870d962001-07-02 17:27:21 +000012026 strcpy(s, "./trace");
Eric Andersencb57d552001-06-28 07:25:16 +000012027#endif /* not_this_way */
12028 if ((tracefile = fopen(s, "a")) == NULL) {
12029 fprintf(stderr, "Can't open %s\n", s);
12030 return;
12031 }
12032#ifdef O_APPEND
12033 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
12034 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
12035#endif
12036 fputs("\nTracing started.\n", tracefile);
12037 fflush(tracefile);
12038}
12039#endif /* DEBUG */
12040
12041
12042/*
Eric Andersencb57d552001-06-28 07:25:16 +000012043 * The trap builtin.
12044 */
12045
12046static int
12047trapcmd(argc, argv)
12048 int argc;
12049 char **argv;
12050{
12051 char *action;
12052 char **ap;
12053 int signo;
12054
12055 if (argc <= 1) {
12056 for (signo = 0 ; signo < NSIG ; signo++) {
12057 if (trap[signo] != NULL) {
12058 char *p;
12059
12060 p = single_quote(trap[signo]);
Eric Andersen62483552001-07-10 06:09:16 +000012061 printf("trap -- %s %s\n", p,
Eric Andersencb57d552001-06-28 07:25:16 +000012062 signal_names[signo] + (signo ? 3 : 0)
12063 );
12064 stunalloc(p);
12065 }
12066 }
12067 return 0;
12068 }
12069 ap = argv + 1;
12070 if (argc == 2)
12071 action = NULL;
12072 else
12073 action = *ap++;
12074 while (*ap) {
12075 if ((signo = decode_signal(*ap, 0)) < 0)
12076 error("%s: bad trap", *ap);
12077 INTOFF;
12078 if (action) {
12079 if (action[0] == '-' && action[1] == '\0')
12080 action = NULL;
12081 else
12082 action = savestr(action);
12083 }
12084 if (trap[signo])
12085 ckfree(trap[signo]);
12086 trap[signo] = action;
12087 if (signo != 0)
12088 setsignal(signo);
12089 INTON;
12090 ap++;
12091 }
12092 return 0;
12093}
12094
12095
12096
Eric Andersencb57d552001-06-28 07:25:16 +000012097
12098
12099
12100/*
12101 * Set the signal handler for the specified signal. The routine figures
12102 * out what it should be set to.
12103 */
12104
12105static void
Eric Andersen2870d962001-07-02 17:27:21 +000012106setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000012107{
12108 int action;
12109 char *t;
12110 struct sigaction act;
12111
12112 if ((t = trap[signo]) == NULL)
12113 action = S_DFL;
12114 else if (*t != '\0')
12115 action = S_CATCH;
12116 else
12117 action = S_IGN;
12118 if (rootshell && action == S_DFL) {
12119 switch (signo) {
12120 case SIGINT:
12121 if (iflag || minusc || sflag == 0)
12122 action = S_CATCH;
12123 break;
12124 case SIGQUIT:
12125#ifdef DEBUG
12126 {
Eric Andersencb57d552001-06-28 07:25:16 +000012127
12128 if (debug)
12129 break;
12130 }
12131#endif
12132 /* FALLTHROUGH */
12133 case SIGTERM:
12134 if (iflag)
12135 action = S_IGN;
12136 break;
Eric Andersen2870d962001-07-02 17:27:21 +000012137#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000012138 case SIGTSTP:
12139 case SIGTTOU:
12140 if (mflag)
12141 action = S_IGN;
12142 break;
12143#endif
12144 }
12145 }
12146
12147 t = &sigmode[signo - 1];
12148 if (*t == 0) {
12149 /*
12150 * current setting unknown
12151 */
12152 if (sigaction(signo, 0, &act) == -1) {
12153 /*
12154 * Pretend it worked; maybe we should give a warning
12155 * here, but other shells don't. We don't alter
12156 * sigmode, so that we retry every time.
12157 */
12158 return;
12159 }
12160 if (act.sa_handler == SIG_IGN) {
12161 if (mflag && (signo == SIGTSTP ||
12162 signo == SIGTTIN || signo == SIGTTOU)) {
Eric Andersen2870d962001-07-02 17:27:21 +000012163 *t = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000012164 } else
12165 *t = S_HARD_IGN;
12166 } else {
Eric Andersen2870d962001-07-02 17:27:21 +000012167 *t = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000012168 }
12169 }
12170 if (*t == S_HARD_IGN || *t == action)
12171 return;
12172 switch (action) {
12173 case S_CATCH:
12174 act.sa_handler = onsig;
12175 break;
12176 case S_IGN:
12177 act.sa_handler = SIG_IGN;
12178 break;
12179 default:
12180 act.sa_handler = SIG_DFL;
12181 }
12182 *t = action;
12183 act.sa_flags = 0;
12184 sigemptyset(&act.sa_mask);
12185 sigaction(signo, &act, 0);
12186}
12187
12188/*
12189 * Ignore a signal.
12190 */
12191
12192static void
12193ignoresig(signo)
12194 int signo;
12195{
12196 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
12197 signal(signo, SIG_IGN);
12198 }
12199 sigmode[signo - 1] = S_HARD_IGN;
12200}
12201
12202
Eric Andersencb57d552001-06-28 07:25:16 +000012203/*
12204 * Signal handler.
12205 */
12206
12207static void
Eric Andersen2870d962001-07-02 17:27:21 +000012208onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000012209{
12210 if (signo == SIGINT && trap[SIGINT] == NULL) {
12211 onint();
12212 return;
12213 }
12214 gotsig[signo - 1] = 1;
12215 pendingsigs++;
12216}
12217
12218
Eric Andersencb57d552001-06-28 07:25:16 +000012219/*
12220 * Called to execute a trap. Perhaps we should avoid entering new trap
12221 * handlers while we are executing a trap handler.
12222 */
12223
12224static void
Eric Andersen2870d962001-07-02 17:27:21 +000012225dotrap(void)
12226{
Eric Andersencb57d552001-06-28 07:25:16 +000012227 int i;
12228 int savestatus;
12229
12230 for (;;) {
12231 for (i = 1 ; ; i++) {
12232 if (gotsig[i - 1])
12233 break;
12234 if (i >= NSIG - 1)
12235 goto done;
12236 }
12237 gotsig[i - 1] = 0;
12238 savestatus=exitstatus;
12239 evalstring(trap[i], 0);
12240 exitstatus=savestatus;
12241 }
12242done:
12243 pendingsigs = 0;
12244}
12245
Eric Andersencb57d552001-06-28 07:25:16 +000012246/*
12247 * Called to exit the shell.
12248 */
12249
12250static void
Eric Andersen2870d962001-07-02 17:27:21 +000012251exitshell(int status)
Eric Andersencb57d552001-06-28 07:25:16 +000012252{
12253 struct jmploc loc1, loc2;
12254 char *p;
12255
12256 TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
12257 if (setjmp(loc1.loc)) {
12258 goto l1;
12259 }
12260 if (setjmp(loc2.loc)) {
12261 goto l2;
12262 }
12263 handler = &loc1;
12264 if ((p = trap[0]) != NULL && *p != '\0') {
12265 trap[0] = NULL;
12266 evalstring(p, 0);
12267 }
Eric Andersen2870d962001-07-02 17:27:21 +000012268l1: handler = &loc2; /* probably unnecessary */
Eric Andersencb57d552001-06-28 07:25:16 +000012269 flushall();
Eric Andersen2870d962001-07-02 17:27:21 +000012270#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000012271 setjobctl(0);
12272#endif
12273l2: _exit(status);
12274 /* NOTREACHED */
12275}
12276
12277static int decode_signal(const char *string, int minsig)
12278{
12279 int signo;
12280
Eric Andersen2870d962001-07-02 17:27:21 +000012281 if (is_number(string, &signo)) {
Eric Andersencb57d552001-06-28 07:25:16 +000012282 if (signo >= NSIG) {
12283 return -1;
12284 }
12285 return signo;
12286 }
12287
12288 signo = minsig;
12289 if (!signo) {
12290 goto zero;
12291 }
12292 for (; signo < NSIG; signo++) {
12293 if (!strcasecmp(string, &(signal_names[signo])[3])) {
12294 return signo;
12295 }
12296zero:
12297 if (!strcasecmp(string, signal_names[signo])) {
12298 return signo;
12299 }
12300 }
12301
12302 return -1;
12303}
Eric Andersen2870d962001-07-02 17:27:21 +000012304static struct var **hashvar (const char *);
12305static void showvars (const char *, int, int);
12306static struct var **findvar (struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000012307
12308/*
12309 * Initialize the varable symbol tables and import the environment
12310 */
12311
Eric Andersencb57d552001-06-28 07:25:16 +000012312/*
12313 * This routine initializes the builtin variables. It is called when the
12314 * shell is initialized and again when a shell procedure is spawned.
12315 */
12316
12317static void
12318initvar() {
12319 const struct varinit *ip;
12320 struct var *vp;
12321 struct var **vpp;
12322
12323 for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
12324 if ((vp->flags & VEXPORT) == 0) {
12325 vpp = hashvar(ip->text);
12326 vp->next = *vpp;
12327 *vpp = vp;
12328 vp->text = strdup(ip->text);
12329 vp->flags = ip->flags;
12330 vp->func = ip->func;
12331 }
12332 }
12333 /*
12334 * PS1 depends on uid
12335 */
12336 if ((vps1.flags & VEXPORT) == 0) {
12337 vpp = hashvar("PS1=");
12338 vps1.next = *vpp;
12339 *vpp = &vps1;
12340 vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# ");
12341 vps1.flags = VSTRFIXED|VTEXTFIXED;
12342 }
12343}
12344
12345/*
12346 * Set the value of a variable. The flags argument is ored with the
12347 * flags of the variable. If val is NULL, the variable is unset.
12348 */
12349
12350static void
12351setvar(name, val, flags)
12352 const char *name, *val;
12353 int flags;
12354{
12355 const char *p;
12356 int len;
12357 int namelen;
12358 char *nameeq;
12359 int isbad;
12360 int vallen = 0;
12361
12362 isbad = 0;
12363 p = name;
12364 if (! is_name(*p))
12365 isbad = 1;
12366 p++;
12367 for (;;) {
12368 if (! is_in_name(*p)) {
12369 if (*p == '\0' || *p == '=')
12370 break;
12371 isbad = 1;
12372 }
12373 p++;
12374 }
12375 namelen = p - name;
12376 if (isbad)
12377 error("%.*s: bad variable name", namelen, name);
Eric Andersen2870d962001-07-02 17:27:21 +000012378 len = namelen + 2; /* 2 is space for '=' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +000012379 if (val == NULL) {
12380 flags |= VUNSET;
12381 } else {
12382 len += vallen = strlen(val);
12383 }
12384 INTOFF;
12385 nameeq = ckmalloc(len);
12386 memcpy(nameeq, name, namelen);
12387 nameeq[namelen] = '=';
12388 if (val) {
12389 memcpy(nameeq + namelen + 1, val, vallen + 1);
12390 } else {
12391 nameeq[namelen + 1] = '\0';
12392 }
12393 setvareq(nameeq, flags);
12394 INTON;
12395}
12396
12397
12398
12399/*
12400 * Same as setvar except that the variable and value are passed in
12401 * the first argument as name=value. Since the first argument will
12402 * be actually stored in the table, it should not be a string that
12403 * will go away.
12404 */
12405
12406static void
12407setvareq(s, flags)
12408 char *s;
12409 int flags;
12410{
12411 struct var *vp, **vpp;
12412
12413 vpp = hashvar(s);
12414 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
12415 if ((vp = *findvar(vpp, s))) {
12416 if (vp->flags & VREADONLY) {
12417 size_t len = strchr(s, '=') - s;
12418 error("%.*s: is read only", len, s);
12419 }
12420 INTOFF;
12421
12422 if (vp->func && (flags & VNOFUNC) == 0)
12423 (*vp->func)(strchr(s, '=') + 1);
12424
12425 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12426 ckfree(vp->text);
12427
12428 vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
12429 vp->flags |= flags;
12430 vp->text = s;
12431
12432 /*
12433 * We could roll this to a function, to handle it as
12434 * a regular variable function callback, but why bother?
12435 */
12436 if (iflag && (vp == &vmpath || (vp == &vmail && !mpathset())))
12437 chkmail(1);
12438 INTON;
12439 return;
12440 }
12441 /* not found */
12442 vp = ckmalloc(sizeof (*vp));
12443 vp->flags = flags;
12444 vp->text = s;
12445 vp->next = *vpp;
12446 vp->func = NULL;
12447 *vpp = vp;
12448}
12449
12450
12451
12452/*
12453 * Process a linked list of variable assignments.
12454 */
12455
12456static void
12457listsetvar(mylist)
12458 struct strlist *mylist;
12459 {
12460 struct strlist *lp;
12461
12462 INTOFF;
12463 for (lp = mylist ; lp ; lp = lp->next) {
12464 setvareq(savestr(lp->text), 0);
12465 }
12466 INTON;
12467}
12468
12469
12470
12471/*
12472 * Find the value of a variable. Returns NULL if not set.
12473 */
12474
Eric Andersen62483552001-07-10 06:09:16 +000012475static const char *
Eric Andersencb57d552001-06-28 07:25:16 +000012476lookupvar(name)
12477 const char *name;
12478 {
12479 struct var *v;
12480
12481 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
12482 return strchr(v->text, '=') + 1;
12483 }
12484 return NULL;
12485}
12486
12487
12488
12489/*
12490 * Search the environment of a builtin command.
12491 */
12492
Eric Andersen62483552001-07-10 06:09:16 +000012493static const char *
12494bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012495{
Eric Andersen62483552001-07-10 06:09:16 +000012496 const struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012497
12498 for (sp = cmdenviron ; sp ; sp = sp->next) {
12499 if (varequal(sp->text, name))
12500 return strchr(sp->text, '=') + 1;
12501 }
12502 return lookupvar(name);
12503}
12504
12505
12506
12507/*
12508 * Generate a list of exported variables. This routine is used to construct
12509 * the third argument to execve when executing a program.
12510 */
12511
12512static char **
12513environment() {
12514 int nenv;
12515 struct var **vpp;
12516 struct var *vp;
12517 char **env;
12518 char **ep;
12519
12520 nenv = 0;
12521 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12522 for (vp = *vpp ; vp ; vp = vp->next)
12523 if (vp->flags & VEXPORT)
12524 nenv++;
12525 }
12526 ep = env = stalloc((nenv + 1) * sizeof *env);
12527 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12528 for (vp = *vpp ; vp ; vp = vp->next)
12529 if (vp->flags & VEXPORT)
12530 *ep++ = vp->text;
12531 }
12532 *ep = NULL;
12533 return env;
12534}
12535
12536
12537/*
12538 * Called when a shell procedure is invoked to clear out nonexported
12539 * variables. It is also necessary to reallocate variables of with
12540 * VSTACK set since these are currently allocated on the stack.
12541 */
12542
Eric Andersencb57d552001-06-28 07:25:16 +000012543static void
Eric Andersen2870d962001-07-02 17:27:21 +000012544shprocvar(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000012545 struct var **vpp;
12546 struct var *vp, **prev;
12547
12548 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12549 for (prev = vpp ; (vp = *prev) != NULL ; ) {
12550 if ((vp->flags & VEXPORT) == 0) {
12551 *prev = vp->next;
12552 if ((vp->flags & VTEXTFIXED) == 0)
12553 ckfree(vp->text);
12554 if ((vp->flags & VSTRFIXED) == 0)
12555 ckfree(vp);
12556 } else {
12557 if (vp->flags & VSTACK) {
12558 vp->text = savestr(vp->text);
12559 vp->flags &=~ VSTACK;
12560 }
12561 prev = &vp->next;
12562 }
12563 }
12564 }
12565 initvar();
12566}
12567
12568
12569
12570/*
12571 * Command to list all variables which are set. Currently this command
12572 * is invoked from the set command when the set command is called without
12573 * any variables.
12574 */
12575
12576static int
12577showvarscmd(argc, argv)
12578 int argc;
12579 char **argv;
12580{
12581 showvars(nullstr, VUNSET, VUNSET);
12582 return 0;
12583}
12584
12585
12586
12587/*
12588 * The export and readonly commands.
12589 */
12590
12591static int
12592exportcmd(argc, argv)
12593 int argc;
12594 char **argv;
12595{
12596 struct var *vp;
12597 char *name;
12598 const char *p;
12599 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12600 int pflag;
12601
12602 listsetvar(cmdenviron);
12603 pflag = (nextopt("p") == 'p');
12604 if (argc > 1 && !pflag) {
12605 while ((name = *argptr++) != NULL) {
12606 if ((p = strchr(name, '=')) != NULL) {
12607 p++;
12608 } else {
12609 if ((vp = *findvar(hashvar(name), name))) {
12610 vp->flags |= flag;
12611 goto found;
12612 }
12613 }
12614 setvar(name, p, flag);
12615found:;
12616 }
12617 } else {
12618 showvars(argv[0], flag, 0);
12619 }
12620 return 0;
12621}
12622
Eric Andersencb57d552001-06-28 07:25:16 +000012623/*
12624 * The "local" command.
12625 */
12626
Eric Andersen2870d962001-07-02 17:27:21 +000012627/* funcnest nonzero if we are currently evaluating a function */
12628
Eric Andersencb57d552001-06-28 07:25:16 +000012629static int
12630localcmd(argc, argv)
12631 int argc;
12632 char **argv;
12633{
12634 char *name;
12635
Eric Andersen2870d962001-07-02 17:27:21 +000012636 if (! funcnest)
Eric Andersencb57d552001-06-28 07:25:16 +000012637 error("Not in a function");
12638 while ((name = *argptr++) != NULL) {
12639 mklocal(name);
12640 }
12641 return 0;
12642}
12643
12644
12645/*
12646 * Make a variable a local variable. When a variable is made local, it's
12647 * value and flags are saved in a localvar structure. The saved values
12648 * will be restored when the shell function returns. We handle the name
12649 * "-" as a special case.
12650 */
12651
12652static void
12653mklocal(name)
12654 char *name;
12655 {
12656 struct localvar *lvp;
12657 struct var **vpp;
12658 struct var *vp;
12659
12660 INTOFF;
12661 lvp = ckmalloc(sizeof (struct localvar));
12662 if (name[0] == '-' && name[1] == '\0') {
12663 char *p;
Eric Andersen2870d962001-07-02 17:27:21 +000012664 p = ckmalloc(sizeof optet_vals);
12665 lvp->text = memcpy(p, optet_vals, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000012666 vp = NULL;
12667 } else {
12668 vpp = hashvar(name);
12669 vp = *findvar(vpp, name);
12670 if (vp == NULL) {
12671 if (strchr(name, '='))
12672 setvareq(savestr(name), VSTRFIXED);
12673 else
12674 setvar(name, NULL, VSTRFIXED);
Eric Andersen2870d962001-07-02 17:27:21 +000012675 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012676 lvp->text = NULL;
12677 lvp->flags = VUNSET;
12678 } else {
12679 lvp->text = vp->text;
12680 lvp->flags = vp->flags;
12681 vp->flags |= VSTRFIXED|VTEXTFIXED;
12682 if (strchr(name, '='))
12683 setvareq(savestr(name), 0);
12684 }
12685 }
12686 lvp->vp = vp;
12687 lvp->next = localvars;
12688 localvars = lvp;
12689 INTON;
12690}
12691
12692
12693/*
12694 * Called after a function returns.
12695 */
12696
12697static void
12698poplocalvars() {
12699 struct localvar *lvp;
12700 struct var *vp;
12701
12702 while ((lvp = localvars) != NULL) {
12703 localvars = lvp->next;
12704 vp = lvp->vp;
Eric Andersen2870d962001-07-02 17:27:21 +000012705 if (vp == NULL) { /* $- saved */
12706 memcpy(optet_vals, lvp->text, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000012707 ckfree(lvp->text);
12708 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12709 (void)unsetvar(vp->text);
12710 } else {
12711 if ((vp->flags & VTEXTFIXED) == 0)
12712 ckfree(vp->text);
12713 vp->flags = lvp->flags;
12714 vp->text = lvp->text;
12715 }
12716 ckfree(lvp);
12717 }
12718}
12719
12720
12721static int
12722setvarcmd(argc, argv)
12723 int argc;
12724 char **argv;
12725{
12726 if (argc <= 2)
12727 return unsetcmd(argc, argv);
12728 else if (argc == 3)
12729 setvar(argv[1], argv[2], 0);
12730 else
12731 error("List assignment not implemented");
12732 return 0;
12733}
12734
12735
12736/*
12737 * The unset builtin command. We unset the function before we unset the
12738 * variable to allow a function to be unset when there is a readonly variable
12739 * with the same name.
12740 */
12741
12742static int
12743unsetcmd(argc, argv)
12744 int argc;
12745 char **argv;
12746{
12747 char **ap;
12748 int i;
12749 int flg_func = 0;
12750 int flg_var = 0;
12751 int ret = 0;
12752
12753 while ((i = nextopt("vf")) != '\0') {
12754 if (i == 'f')
12755 flg_func = 1;
12756 else
12757 flg_var = 1;
12758 }
12759 if (flg_func == 0 && flg_var == 0)
12760 flg_var = 1;
12761
12762 for (ap = argptr; *ap ; ap++) {
12763 if (flg_func)
12764 unsetfunc(*ap);
12765 if (flg_var)
12766 ret |= unsetvar(*ap);
12767 }
12768 return ret;
12769}
12770
12771
12772/*
12773 * Unset the specified variable.
12774 */
12775
12776static int
Eric Andersen62483552001-07-10 06:09:16 +000012777unsetvar(const char *s)
12778{
Eric Andersencb57d552001-06-28 07:25:16 +000012779 struct var **vpp;
12780 struct var *vp;
12781
12782 vpp = findvar(hashvar(s), s);
12783 vp = *vpp;
12784 if (vp) {
12785 if (vp->flags & VREADONLY)
12786 return (1);
12787 INTOFF;
12788 if (*(strchr(vp->text, '=') + 1) != '\0')
12789 setvar(s, nullstr, 0);
12790 vp->flags &= ~VEXPORT;
12791 vp->flags |= VUNSET;
12792 if ((vp->flags & VSTRFIXED) == 0) {
12793 if ((vp->flags & VTEXTFIXED) == 0)
12794 ckfree(vp->text);
12795 *vpp = vp->next;
12796 ckfree(vp);
12797 }
12798 INTON;
12799 return (0);
12800 }
12801
12802 return (0);
12803}
12804
12805
12806
12807/*
12808 * Find the appropriate entry in the hash table from the name.
12809 */
12810
12811static struct var **
Eric Andersen62483552001-07-10 06:09:16 +000012812hashvar(const char *p)
12813{
Eric Andersencb57d552001-06-28 07:25:16 +000012814 unsigned int hashval;
12815
12816 hashval = ((unsigned char) *p) << 4;
12817 while (*p && *p != '=')
12818 hashval += (unsigned char) *p++;
12819 return &vartab[hashval % VTABSIZE];
12820}
12821
12822
12823
12824/*
12825 * Returns true if the two strings specify the same varable. The first
12826 * variable name is terminated by '='; the second may be terminated by
12827 * either '=' or '\0'.
12828 */
12829
12830static int
Eric Andersen62483552001-07-10 06:09:16 +000012831varequal(const char *p, const char *q)
12832{
Eric Andersencb57d552001-06-28 07:25:16 +000012833 while (*p == *q++) {
12834 if (*p++ == '=')
12835 return 1;
12836 }
12837 if (*p == '=' && *(q - 1) == '\0')
12838 return 1;
12839 return 0;
12840}
12841
12842static void
12843showvars(const char *myprefix, int mask, int xor)
12844{
12845 struct var **vpp;
12846 struct var *vp;
12847 const char *sep = myprefix == nullstr ? myprefix : spcstr;
12848
12849 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12850 for (vp = *vpp ; vp ; vp = vp->next) {
12851 if ((vp->flags & mask) ^ xor) {
12852 char *p;
12853 int len;
12854
12855 p = strchr(vp->text, '=') + 1;
12856 len = p - vp->text;
12857 p = single_quote(p);
12858
Eric Andersen62483552001-07-10 06:09:16 +000012859 printf("%s%s%.*s%s\n", myprefix, sep, len,
12860 vp->text, p);
Eric Andersencb57d552001-06-28 07:25:16 +000012861 stunalloc(p);
12862 }
12863 }
12864 }
12865}
12866
12867static struct var **
12868findvar(struct var **vpp, const char *name)
12869{
12870 for (; *vpp; vpp = &(*vpp)->next) {
12871 if (varequal((*vpp)->text, name)) {
12872 break;
12873 }
12874 }
12875 return vpp;
12876}
12877
12878/*
12879 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
12880 * This file contains code for the times builtin.
Eric Andersen74bcd162001-07-30 21:41:37 +000012881 * $Id: ash.c,v 1.14 2001/07/30 21:41:37 andersen Exp $
Eric Andersencb57d552001-06-28 07:25:16 +000012882 */
12883static int timescmd (int argc, char **argv)
12884{
12885 struct tms buf;
12886 long int clk_tck = sysconf(_SC_CLK_TCK);
12887
12888 times(&buf);
12889 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
12890 (int) (buf.tms_utime / clk_tck / 60),
12891 ((double) buf.tms_utime) / clk_tck,
12892 (int) (buf.tms_stime / clk_tck / 60),
12893 ((double) buf.tms_stime) / clk_tck,
12894 (int) (buf.tms_cutime / clk_tck / 60),
12895 ((double) buf.tms_cutime) / clk_tck,
12896 (int) (buf.tms_cstime / clk_tck / 60),
12897 ((double) buf.tms_cstime) / clk_tck);
12898 return 0;
12899}
12900
Eric Andersendf82f612001-06-28 07:46:40 +000012901
Eric Andersen74bcd162001-07-30 21:41:37 +000012902#ifdef ASH_MATH_SUPPORT
12903/* The exp(1) builtin. */
12904int expcmd(int argc, char **argv)
12905{
12906 const char *p;
12907 char *concat;
12908 char **ap;
12909 long i;
12910
12911 if (argc > 1) {
12912 p = argv[1];
12913 if (argc > 2) {
12914 /* concatenate arguments */
12915 STARTSTACKSTR(concat);
12916 ap = argv + 2;
12917 for (;;) {
12918 while (*p)
12919 STPUTC(*p++, concat);
12920 if ((p = *ap++) == NULL)
12921 break;
12922 STPUTC(' ', concat);
12923 }
12924 STPUTC('\0', concat);
12925 p = grabstackstr(concat);
12926 }
12927 } else
12928 p = "";
12929
12930 i = ash_arith(p);
12931
12932 printf("%ld\n", i);
12933 return (! i);
12934}
12935
12936static long ash_arith(const char *p)
12937{
12938 long i = arith(p);
12939 if (i <0)
12940 error("arith: syntax error: \"%s\"\n", p);
12941 return i;
12942}
12943#endif
12944
12945
12946
Eric Andersendf82f612001-06-28 07:46:40 +000012947/*-
12948 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000012949 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000012950 *
12951 * This code is derived from software contributed to Berkeley by
12952 * Kenneth Almquist.
12953 *
12954 * Redistribution and use in source and binary forms, with or without
12955 * modification, are permitted provided that the following conditions
12956 * are met:
12957 * 1. Redistributions of source code must retain the above copyright
12958 * notice, this list of conditions and the following disclaimer.
12959 * 2. Redistributions in binary form must reproduce the above copyright
12960 * notice, this list of conditions and the following disclaimer in the
12961 * documentation and/or other materials provided with the distribution.
12962 *
Eric Andersen2870d962001-07-02 17:27:21 +000012963 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
12964 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000012965 *
12966 * 4. Neither the name of the University nor the names of its contributors
12967 * may be used to endorse or promote products derived from this software
12968 * without specific prior written permission.
12969 *
12970 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
12971 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
12972 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
12973 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
12974 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
12975 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
12976 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
12977 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
12978 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
12979 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
12980 * SUCH DAMAGE.
12981 */