blob: 486386a257a38ed4d45936de18e9b4b89a637183 [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. */
Eric Andersen34506362001-08-02 05:02:46 +000055//#undef ASH_MATH_SUPPORT
Eric Andersen74bcd162001-07-30 21:41:37 +000056#define ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +000057
Eric Andersen2870d962001-07-02 17:27:21 +000058/* Getopts is used by shell procedures to parse positional parameters.
59 * You probably want to leave this disabled, and use the busybox getopt
60 * applet if you want to do this sort of thing. There are some scripts
Manuel Novoa III 16815d42001-08-10 19:36:07 +000061 * out there that use it, so it you need it, enable. Most people will
Eric Andersen2870d962001-07-02 17:27:21 +000062 * leave this disabled. This adds 1k on an x86 system. */
63#undef ASH_GETOPTS
64
65/* This allows you to override shell builtins and use whatever is on
66 * the filesystem. This is most useful when ash is acting as a
Eric Andersen62483552001-07-10 06:09:16 +000067 * standalone shell. Adds about 272 bytes. */
Eric Andersen2870d962001-07-02 17:27:21 +000068#undef ASH_CMDCMD
69
Eric Andersen2870d962001-07-02 17:27:21 +000070
Eric Andersen3102ac42001-07-06 04:26:23 +000071/* Optimize size vs speed as size */
72#define ASH_OPTIMIZE_FOR_SIZE
73
Eric Andersen2870d962001-07-02 17:27:21 +000074/* Enable this to compile in extra debugging noise. When debugging is
75 * on, debugging info will be written to $HOME/trace and a quit signal
76 * will generate a core dump. */
77#undef DEBUG
78
Eric Andersen2870d962001-07-02 17:27:21 +000079/* These are here to work with glibc -- Don't change these... */
Eric Andersendf82f612001-06-28 07:46:40 +000080#undef FNMATCH_BROKEN
81#undef GLOB_BROKEN
Eric Andersen5bb16772001-09-06 18:00:41 +000082#define IFS_BROKEN
Eric Andersencb57d552001-06-28 07:25:16 +000083
84#include <assert.h>
Manuel Novoa III 16815d42001-08-10 19:36:07 +000085#include <stddef.h>
Eric Andersencb57d552001-06-28 07:25:16 +000086#include <ctype.h>
87#include <dirent.h>
88#include <errno.h>
89#include <fcntl.h>
90#include <limits.h>
91#include <paths.h>
92#include <pwd.h>
93#include <setjmp.h>
94#include <signal.h>
95#include <stdarg.h>
Eric Andersencb57d552001-06-28 07:25:16 +000096#include <stdio.h>
97#include <stdlib.h>
98#include <string.h>
99#include <sysexits.h>
100#include <unistd.h>
101#include <sys/stat.h>
102#include <sys/cdefs.h>
103#include <sys/ioctl.h>
104#include <sys/param.h>
105#include <sys/resource.h>
106#include <sys/time.h>
107#include <sys/times.h>
108#include <sys/types.h>
109#include <sys/wait.h>
110
111
112#if !defined(FNMATCH_BROKEN)
113#include <fnmatch.h>
114#endif
115#if !defined(GLOB_BROKEN)
116#include <glob.h>
117#endif
118
Eric Andersen2870d962001-07-02 17:27:21 +0000119#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +0000120#include <termios.h>
Eric Andersencb57d552001-06-28 07:25:16 +0000121#endif
122
Eric Andersencb57d552001-06-28 07:25:16 +0000123#include "busybox.h"
Eric Andersen2870d962001-07-02 17:27:21 +0000124#include "cmdedit.h"
125
Eric Andersen2870d962001-07-02 17:27:21 +0000126/*
127 * This file was generated by the mksyntax program.
128 */
129
130/* Syntax classes */
131#define CWORD 0 /* character is nothing special */
132#define CNL 1 /* newline character */
133#define CBACK 2 /* a backslash character */
134#define CSQUOTE 3 /* single quote */
135#define CDQUOTE 4 /* double quote */
136#define CENDQUOTE 5 /* a terminating quote */
137#define CBQUOTE 6 /* backwards single quote */
138#define CVAR 7 /* a dollar sign */
139#define CENDVAR 8 /* a '}' character */
140#define CLP 9 /* a left paren in arithmetic */
141#define CRP 10 /* a right paren in arithmetic */
142#define CENDFILE 11 /* end of file */
143#define CCTL 12 /* like CWORD, except it must be escaped */
144#define CSPCL 13 /* these terminate a word */
145#define CIGN 14 /* character should be ignored */
146
Eric Andersen2870d962001-07-02 17:27:21 +0000147#define SYNBASE 130
148#define PEOF -130
149
150#define PEOA -129
151
152#define TEOF 0
153#define TNL 1
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000154#define TREDIR 2
155#define TWORD 3
156#define TASSIGN 4
157#define TSEMI 5
158#define TBACKGND 6
159#define TAND 7
160#define TOR 8
161#define TPIPE 9
162#define TLP 10
163#define TRP 11
164#define TENDCASE 12
165#define TENDBQUOTE 13
Eric Andersen2870d962001-07-02 17:27:21 +0000166#define TNOT 14
167#define TCASE 15
168#define TDO 16
169#define TDONE 17
170#define TELIF 18
171#define TELSE 19
172#define TESAC 20
173#define TFI 21
174#define TFOR 22
175#define TIF 23
176#define TIN 24
177#define TTHEN 25
178#define TUNTIL 26
179#define TWHILE 27
180#define TBEGIN 28
181#define TEND 29
182
183
Eric Andersen2870d962001-07-02 17:27:21 +0000184
185/* control characters in argument strings */
186#define CTLESC '\201'
187#define CTLVAR '\202'
188#define CTLENDVAR '\203'
189#define CTLBACKQ '\204'
190#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
191/* CTLBACKQ | CTLQUOTE == '\205' */
192#define CTLARI '\206'
193#define CTLENDARI '\207'
194#define CTLQUOTEMARK '\210'
195
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000196
Eric Andersen62483552001-07-10 06:09:16 +0000197#define is_digit(c) ((c)>='0' && (c)<='9')
Eric Andersen2870d962001-07-02 17:27:21 +0000198#define is_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalpha((unsigned char) (c))))
199#define is_in_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalnum((unsigned char) (c))))
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000200
201/*
202 * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
203 * (assuming ascii char codes, as the original implementation did)
204 */
205#define is_special(c) \
206 ( (((unsigned int)c) - 33 < 32) \
207 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
208
Eric Andersen2870d962001-07-02 17:27:21 +0000209#define digit_val(c) ((c) - '0')
Eric Andersencb57d552001-06-28 07:25:16 +0000210
211
212#define _DIAGASSERT(x)
213
Eric Andersen3102ac42001-07-06 04:26:23 +0000214
Eric Andersencb57d552001-06-28 07:25:16 +0000215
Eric Andersen2870d962001-07-02 17:27:21 +0000216#define S_DFL 1 /* default signal handling (SIG_DFL) */
217#define S_CATCH 2 /* signal is caught */
218#define S_IGN 3 /* signal is ignored (SIG_IGN) */
219#define S_HARD_IGN 4 /* signal is ignored permenantly */
220#define S_RESET 5 /* temporary - to reset a hard ignored sig */
Eric Andersencb57d552001-06-28 07:25:16 +0000221
222
Eric Andersen2870d962001-07-02 17:27:21 +0000223/* variable substitution byte (follows CTLVAR) */
224#define VSTYPE 0x0f /* type of variable substitution */
225#define VSNUL 0x10 /* colon--treat the empty string as unset */
226#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
Eric Andersencb57d552001-06-28 07:25:16 +0000227
Eric Andersen2870d962001-07-02 17:27:21 +0000228/* values of VSTYPE field */
229#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
230#define VSMINUS 0x2 /* ${var-text} */
231#define VSPLUS 0x3 /* ${var+text} */
232#define VSQUESTION 0x4 /* ${var?message} */
233#define VSASSIGN 0x5 /* ${var=text} */
234#define VSTRIMLEFT 0x6 /* ${var#pattern} */
235#define VSTRIMLEFTMAX 0x7 /* ${var##pattern} */
236#define VSTRIMRIGHT 0x8 /* ${var%pattern} */
237#define VSTRIMRIGHTMAX 0x9 /* ${var%%pattern} */
238#define VSLENGTH 0xa /* ${#var} */
Eric Andersencb57d552001-06-28 07:25:16 +0000239
Eric Andersen2870d962001-07-02 17:27:21 +0000240/* flags passed to redirect */
241#define REDIR_PUSH 01 /* save previous values of file descriptors */
Eric Andersen3102ac42001-07-06 04:26:23 +0000242#define REDIR_BACKQ 02 /* save the command output to pipe */
Eric Andersencb57d552001-06-28 07:25:16 +0000243
Eric Andersen2870d962001-07-02 17:27:21 +0000244/*
245 * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
246 * so we use _setjmp instead.
247 */
248
Eric Andersen62483552001-07-10 06:09:16 +0000249#if defined(BSD)
Eric Andersen2870d962001-07-02 17:27:21 +0000250#define setjmp(jmploc) _setjmp(jmploc)
251#define longjmp(jmploc, val) _longjmp(jmploc, val)
252#endif
253
254/*
255 * Most machines require the value returned from malloc to be aligned
256 * in some way. The following macro will get this right on many machines.
257 */
258
259#ifndef ALIGN
260union align {
261 int i;
262 char *cp;
263};
264
265#define ALIGN(nbytes) (((nbytes) + sizeof(union align) - 1) & ~(sizeof(union align) - 1))
266#endif
267
268#ifdef BB_LOCALE_SUPPORT
269#include <locale.h>
270static void change_lc_all(const char *value);
271static void change_lc_ctype(const char *value);
272#endif
273
274/*
275 * These macros allow the user to suspend the handling of interrupt signals
276 * over a period of time. This is similar to SIGHOLD to or sigblock, but
277 * much more efficient and portable. (But hacking the kernel is so much
278 * more fun than worrying about efficiency and portability. :-))
279 */
280
281static void onint (void);
282static volatile int suppressint;
283static volatile int intpending;
284
285#define INTOFF suppressint++
Eric Andersen3102ac42001-07-06 04:26:23 +0000286#ifndef ASH_OPTIMIZE_FOR_SIZE
Eric Andersen2870d962001-07-02 17:27:21 +0000287#define INTON { if (--suppressint == 0 && intpending) onint(); }
Eric Andersen3102ac42001-07-06 04:26:23 +0000288#define FORCEINTON {suppressint = 0; if (intpending) onint();}
Eric Andersen2870d962001-07-02 17:27:21 +0000289#else
290static void __inton (void);
Eric Andersen3102ac42001-07-06 04:26:23 +0000291static void forceinton (void);
Eric Andersen2870d962001-07-02 17:27:21 +0000292#define INTON __inton()
Eric Andersen3102ac42001-07-06 04:26:23 +0000293#define FORCEINTON forceinton()
Eric Andersen2870d962001-07-02 17:27:21 +0000294#endif
Eric Andersen3102ac42001-07-06 04:26:23 +0000295
Eric Andersen2870d962001-07-02 17:27:21 +0000296#define CLEAR_PENDING_INT intpending = 0
297#define int_pending() intpending
298
299
300typedef void *pointer;
301#ifndef NULL
302#define NULL (void *)0
303#endif
304
305static inline pointer ckmalloc (int sz) { return xmalloc(sz); }
306static inline pointer ckrealloc(void *p, int sz) { return xrealloc(p, sz); }
307static inline char * savestr (const char *s) { return xstrdup(s); }
308
309static pointer stalloc (int);
310static void stunalloc (pointer);
311static void ungrabstackstr (char *, char *);
312static char * growstackstr(void);
Eric Andersen3102ac42001-07-06 04:26:23 +0000313static char * makestrspace(size_t newlen);
Eric Andersen2870d962001-07-02 17:27:21 +0000314static char *sstrdup (const char *);
315
316/*
317 * Parse trees for commands are allocated in lifo order, so we use a stack
318 * to make this more efficient, and also to avoid all sorts of exception
319 * handling code to handle interrupts in the middle of a parse.
320 *
321 * The size 504 was chosen because the Ultrix malloc handles that size
322 * well.
323 */
324
325#define MINSIZE 504 /* minimum size of a block */
326
327
328struct stack_block {
329 struct stack_block *prev;
330 char space[MINSIZE];
331};
332
333static struct stack_block stackbase;
334static struct stack_block *stackp = &stackbase;
335static struct stackmark *markp;
336static char *stacknxt = stackbase.space;
337static int stacknleft = MINSIZE;
338
339
340#define equal(s1, s2) (strcmp(s1, s2) == 0)
341
342#define stackblock() stacknxt
343#define stackblocksize() stacknleft
344#define STARTSTACKSTR(p) p = stackblock(), sstrnleft = stackblocksize()
Eric Andersen3102ac42001-07-06 04:26:23 +0000345
Eric Andersen2870d962001-07-02 17:27:21 +0000346#define STPUTC(c, p) (--sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(), *p++ = (c)))
347#define CHECKSTRSPACE(n, p) { if (sstrnleft < n) p = makestrspace(n); }
Eric Andersen2870d962001-07-02 17:27:21 +0000348#define STACKSTRNUL(p) (sstrnleft == 0? (p = growstackstr(), *p = '\0') : (*p = '\0'))
Eric Andersen3102ac42001-07-06 04:26:23 +0000349
350
351#define USTPUTC(c, p) (--sstrnleft, *p++ = (c))
Eric Andersen2870d962001-07-02 17:27:21 +0000352#define STUNPUTC(p) (++sstrnleft, --p)
353#define STTOPC(p) p[-1]
354#define STADJUST(amount, p) (p += (amount), sstrnleft -= (amount))
355#define grabstackstr(p) stalloc(stackblocksize() - sstrnleft)
356
357#define ckfree(p) free((pointer)(p))
358
Eric Andersen2870d962001-07-02 17:27:21 +0000359
360#ifdef DEBUG
361#define TRACE(param) trace param
362static void trace (const char *, ...);
363static void trargs (char **);
364static void showtree (union node *);
365static void trputc (int);
366static void trputs (const char *);
367static void opentrace (void);
368#else
369#define TRACE(param)
370#endif
371
372#define NSEMI 0
373#define NCMD 1
374#define NPIPE 2
375#define NREDIR 3
376#define NBACKGND 4
377#define NSUBSHELL 5
378#define NAND 6
379#define NOR 7
380#define NIF 8
381#define NWHILE 9
382#define NUNTIL 10
383#define NFOR 11
384#define NCASE 12
385#define NCLIST 13
386#define NDEFUN 14
387#define NARG 15
388#define NTO 16
389#define NFROM 17
390#define NFROMTO 18
391#define NAPPEND 19
392#define NTOOV 20
393#define NTOFD 21
394#define NFROMFD 22
395#define NHERE 23
396#define NXHERE 24
397#define NNOT 25
398
399/*
400 * expandarg() flags
401 */
402#define EXP_FULL 0x1 /* perform word splitting & file globbing */
403#define EXP_TILDE 0x2 /* do normal tilde expansion */
404#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
405#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
406#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
407#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
408
409
410#define NOPTS 16
411
412static char optet_vals[NOPTS];
413
414static const char * const optlist[NOPTS] = {
415 "e" "errexit",
416 "f" "noglob",
417 "I" "ignoreeof",
418 "i" "interactive",
419 "m" "monitor",
420 "n" "noexec",
421 "s" "stdin",
422 "x" "xtrace",
423 "v" "verbose",
424 "V" "vi",
425 "E" "emacs",
426 "C" "noclobber",
427 "a" "allexport",
428 "b" "notify",
429 "u" "nounset",
430 "q" "quietprofile"
431};
432
433#define optent_name(optent) (optent+1)
434#define optent_letter(optent) optent[0]
435#define optent_val(optent) optet_vals[optent]
436
437#define eflag optent_val(0)
438#define fflag optent_val(1)
439#define Iflag optent_val(2)
440#define iflag optent_val(3)
441#define mflag optent_val(4)
442#define nflag optent_val(5)
443#define sflag optent_val(6)
444#define xflag optent_val(7)
445#define vflag optent_val(8)
446#define Vflag optent_val(9)
447#define Eflag optent_val(10)
448#define Cflag optent_val(11)
449#define aflag optent_val(12)
450#define bflag optent_val(13)
451#define uflag optent_val(14)
452#define qflag optent_val(15)
453
454
455/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
456#define FORK_FG 0
457#define FORK_BG 1
458#define FORK_NOJOB 2
459
460
461struct nbinary {
462 int type;
463 union node *ch1;
464 union node *ch2;
465};
466
467
468struct ncmd {
469 int type;
470 int backgnd;
471 union node *assign;
472 union node *args;
473 union node *redirect;
474};
475
476
477struct npipe {
478 int type;
479 int backgnd;
480 struct nodelist *cmdlist;
481};
482
483
484struct nredir {
485 int type;
486 union node *n;
487 union node *redirect;
488};
489
490
491struct nif {
492 int type;
493 union node *test;
494 union node *ifpart;
495 union node *elsepart;
496};
497
498
499struct nfor {
500 int type;
501 union node *args;
502 union node *body;
503 char *var;
504};
505
506
507struct ncase {
508 int type;
509 union node *expr;
510 union node *cases;
511};
512
513
514struct nclist {
515 int type;
516 union node *next;
517 union node *pattern;
518 union node *body;
519};
520
521
522struct narg {
523 int type;
524 union node *next;
525 char *text;
526 struct nodelist *backquote;
527};
528
529
530struct nfile {
531 int type;
532 union node *next;
533 int fd;
534 union node *fname;
535 char *expfname;
536};
537
538
539struct ndup {
540 int type;
541 union node *next;
542 int fd;
543 int dupfd;
544 union node *vname;
545};
546
547
548struct nhere {
549 int type;
550 union node *next;
551 int fd;
552 union node *doc;
553};
554
555
556struct nnot {
557 int type;
558 union node *com;
559};
560
561
562union node {
563 int type;
564 struct nbinary nbinary;
565 struct ncmd ncmd;
566 struct npipe npipe;
567 struct nredir nredir;
568 struct nif nif;
569 struct nfor nfor;
570 struct ncase ncase;
571 struct nclist nclist;
572 struct narg narg;
573 struct nfile nfile;
574 struct ndup ndup;
575 struct nhere nhere;
576 struct nnot nnot;
577};
578
579
580struct nodelist {
581 struct nodelist *next;
582 union node *n;
583};
584
585struct backcmd { /* result of evalbackcmd */
586 int fd; /* file descriptor to read from */
587 char *buf; /* buffer */
588 int nleft; /* number of chars in buffer */
589 struct job *jp; /* job structure for command */
590};
591
592struct cmdentry {
593 int cmdtype;
594 union param {
595 int index;
596 union node *func;
597 const struct builtincmd *cmd;
598 } u;
599};
600
601struct strlist {
602 struct strlist *next;
603 char *text;
604};
605
606
607struct arglist {
608 struct strlist *list;
609 struct strlist **lastp;
610};
611
612struct strpush {
613 struct strpush *prev; /* preceding string on stack */
614 char *prevstring;
615 int prevnleft;
616#ifdef ASH_ALIAS
617 struct alias *ap; /* if push was associated with an alias */
618#endif
619 char *string; /* remember the string since it may change */
620};
621
622struct parsefile {
623 struct parsefile *prev; /* preceding file on stack */
624 int linno; /* current line */
625 int fd; /* file descriptor (or -1 if string) */
626 int nleft; /* number of chars left in this line */
627 int lleft; /* number of chars left in this buffer */
628 char *nextc; /* next char in buffer */
629 char *buf; /* input buffer */
630 struct strpush *strpush; /* for pushing strings at this level */
631 struct strpush basestrpush; /* so pushing one is fast */
632};
633
634struct stackmark {
635 struct stack_block *stackp;
636 char *stacknxt;
637 int stacknleft;
638 struct stackmark *marknext;
639};
640
641struct shparam {
642 int nparam; /* # of positional parameters (without $0) */
643 unsigned char malloc; /* if parameter list dynamically allocated */
644 char **p; /* parameter list */
645 int optind; /* next parameter to be processed by getopts */
646 int optoff; /* used by getopts */
647};
648
Eric Andersen62483552001-07-10 06:09:16 +0000649/*
650 * When commands are first encountered, they are entered in a hash table.
651 * This ensures that a full path search will not have to be done for them
652 * on each invocation.
653 *
654 * We should investigate converting to a linear search, even though that
655 * would make the command name "hash" a misnomer.
656 */
657#define CMDTABLESIZE 31 /* should be prime */
658#define ARB 1 /* actual size determined at run time */
659
660
661
662struct tblentry {
663 struct tblentry *next; /* next entry in hash chain */
664 union param param; /* definition of builtin function */
665 short cmdtype; /* index identifying command */
666 char rehash; /* if set, cd done since entry created */
667 char cmdname[ARB]; /* name of command */
668};
669
670
671static struct tblentry *cmdtable[CMDTABLESIZE];
672static int builtinloc = -1; /* index in path of %builtin, or -1 */
673static int exerrno = 0; /* Last exec error */
674
675
676static void tryexec (char *, char **, char **);
677static void printentry (struct tblentry *, int);
678static void clearcmdentry (int);
679static struct tblentry *cmdlookup (const char *, int);
680static void delete_cmd_entry (void);
681static int path_change (const char *, int *);
682
683
Eric Andersen2870d962001-07-02 17:27:21 +0000684static void flushall (void);
Eric Andersen3102ac42001-07-06 04:26:23 +0000685static void out2fmt (const char *, ...)
686 __attribute__((__format__(__printf__,1,2)));
Eric Andersen2870d962001-07-02 17:27:21 +0000687static int xwrite (int, const char *, int);
Eric Andersen2870d962001-07-02 17:27:21 +0000688
Manuel Novoa III c639a352001-08-12 17:32:56 +0000689static inline void outstr (const char *p, FILE *file) { fputs(p, file); }
Eric Andersen3102ac42001-07-06 04:26:23 +0000690static void out1str(const char *p) { outstr(p, stdout); }
691static void out2str(const char *p) { outstr(p, stderr); }
Eric Andersen2870d962001-07-02 17:27:21 +0000692
Eric Andersen62483552001-07-10 06:09:16 +0000693#ifndef ASH_OPTIMIZE_FOR_SIZE
Eric Andersen3102ac42001-07-06 04:26:23 +0000694#define out2c(c) putc((c), stderr)
Eric Andersen62483552001-07-10 06:09:16 +0000695#else
696static void out2c(int c) { putc(c, stderr); }
697#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000698
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000699
700#ifdef ASH_OPTIMIZE_FOR_SIZE
701#define USE_SIT_FUNCTION
702#endif
703
704/* number syntax index */
705#define BASESYNTAX 0 /* not in quotes */
706#define DQSYNTAX 1 /* in double quotes */
707#define SQSYNTAX 2 /* in single quotes */
708#define ARISYNTAX 3 /* in arithmetic */
709
710static const char S_I_T[][4] = {
711 /* 0 */ { CSPCL, CIGN, CIGN, CIGN }, /* PEOA */
712 /* 1 */ { CSPCL, CWORD, CWORD, CWORD }, /* ' ' */
713 /* 2 */ { CNL, CNL, CNL, CNL }, /* \n */
714 /* 3 */ { CWORD, CCTL, CCTL, CWORD }, /* !*-/:=?[]~ */
715 /* 4 */ { CDQUOTE, CENDQUOTE, CWORD, CDQUOTE }, /* '"' */
716 /* 5 */ { CVAR, CVAR, CWORD, CVAR }, /* $ */
717 /* 6 */ { CSQUOTE, CWORD, CENDQUOTE, CSQUOTE }, /* "'" */
718 /* 7 */ { CSPCL, CWORD, CWORD, CLP }, /* ( */
719 /* 8 */ { CSPCL, CWORD, CWORD, CRP }, /* ) */
720 /* 9 */ { CBACK, CBACK, CCTL, CBACK }, /* \ */
721 /* 10 */ { CBQUOTE, CBQUOTE, CWORD, CBQUOTE }, /* ` */
722 /* 11 */ { CENDVAR, CENDVAR, CWORD, CENDVAR }, /* } */
723#ifndef USE_SIT_FUNCTION
724 /* 12 */ { CENDFILE, CENDFILE, CENDFILE, CENDFILE }, /* PEOF */
725 /* 13 */ { CWORD, CWORD, CWORD, CWORD }, /* 0-9A-Za-z */
726 /* 14 */ { CCTL, CCTL, CCTL, CCTL } /* CTLESC ... */
727#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000728};
729
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000730#ifdef USE_SIT_FUNCTION
731
732#define U_C(c) ((unsigned char)(c))
733
734static int SIT(int c, int syntax)
735{
736 static const char spec_symbls[]="\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
737 static const char syntax_index_table [] = {
738 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
739 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
740 3, 1, 3, 3, 9, 3,10, 1, /* "=>?[\\]`|" */
741 11,3 }; /* "}~" */
742 const char *s;
743 int indx;
744
745 if(c==PEOF) /* 2^8+2 */
746 return CENDFILE;
747 if(c==PEOA) /* 2^8+1 */
748 indx = 0;
749 else if(U_C(c)>=U_C(CTLESC) && U_C(c)<=U_C(CTLQUOTEMARK))
750 return CCTL;
751 else {
752 s = strchr(spec_symbls, c);
753 if(s==0)
754 return CWORD;
755 indx = syntax_index_table[(s-spec_symbls)];
756 }
757 return S_I_T[indx][syntax];
758}
759
760#else /* USE_SIT_FUNCTION */
761
762#define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
763
764#define CSPCL_CIGN_CIGN_CIGN 0
765#define CSPCL_CWORD_CWORD_CWORD 1
766#define CNL_CNL_CNL_CNL 2
767#define CWORD_CCTL_CCTL_CWORD 3
768#define CDQUOTE_CENDQUOTE_CWORD_CDQUOTE 4
769#define CVAR_CVAR_CWORD_CVAR 5
770#define CSQUOTE_CWORD_CENDQUOTE_CSQUOTE 6
771#define CSPCL_CWORD_CWORD_CLP 7
772#define CSPCL_CWORD_CWORD_CRP 8
773#define CBACK_CBACK_CCTL_CBACK 9
774#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
775#define CENDVAR_CENDVAR_CWORD_CENDVAR 11
776#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
777#define CWORD_CWORD_CWORD_CWORD 13
778#define CCTL_CCTL_CCTL_CCTL 14
779
780static const char syntax_index_table[258] = {
781 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
782 /* 0 -130 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
783 /* 1 -129 PEOA */ CSPCL_CIGN_CIGN_CIGN,
784 /* 2 -128 0xff */ CWORD_CWORD_CWORD_CWORD,
785 /* 3 -127 */ CCTL_CCTL_CCTL_CCTL, /* CTLQUOTEMARK */
786 /* 4 -126 */ CCTL_CCTL_CCTL_CCTL,
787 /* 5 -125 */ CCTL_CCTL_CCTL_CCTL,
788 /* 6 -124 */ CCTL_CCTL_CCTL_CCTL,
789 /* 7 -123 */ CCTL_CCTL_CCTL_CCTL,
790 /* 8 -122 */ CCTL_CCTL_CCTL_CCTL,
791 /* 9 -121 */ CCTL_CCTL_CCTL_CCTL,
792 /* 10 -120 */ CCTL_CCTL_CCTL_CCTL, /* CTLESC */
793 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
794 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
795 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
796 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
797 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
798 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
799 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
800 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
801 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
802 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
803 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
804 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
805 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
806 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
807 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
808 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
809 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
810 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
811 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
812 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
813 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
814 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
815 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
816 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
817 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
818 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
819 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
820 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
821 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
822 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
823 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
824 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
825 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
826 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
827 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
828 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
829 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
830 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
831 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
832 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
833 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
834 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
835 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
836 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
837 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
838 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
839 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
840 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
841 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
842 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
843 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
844 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
845 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
846 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
847 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
848 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
849 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
850 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
851 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
852 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
853 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
854 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
855 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
856 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
857 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
858 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
859 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
860 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
861 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
862 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
863 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
864 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
865 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
866 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
867 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
868 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
869 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
870 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
871 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
872 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
873 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
874 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
875 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
876 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
877 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
878 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
879 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
880 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
881 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
882 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
883 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
884 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
885 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
886 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
887 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
888 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
889 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
890 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
891 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
892 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
893 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
894 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
895 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
896 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
897 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
898 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
899 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
900 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
901 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
902 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
903 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
904 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
905 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
906 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
907 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
908 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
909 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
910 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
911 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
912 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
913 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
914 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
915 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
916 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
917 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
918 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
919 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
920 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
921 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
922 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
923 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
924 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
925 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
926 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
927 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
928 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
929 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
930 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
931 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
932 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
933 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
934 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
935 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
936 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
937 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
938 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
939 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
940 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
941 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
942 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
943 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
944 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
945 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
946 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CDQUOTE,
947 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
948 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
949 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
950 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
951 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CSQUOTE,
952 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
953 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
954 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
955 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
956 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
957 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
958 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
959 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
960 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
961 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
962 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
963 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
964 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
965 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
966 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
967 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
968 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
969 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
970 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
971 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
972 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
973 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
974 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
975 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
976 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
977 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
978 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
979 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
980 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
981 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
982 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
983 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
984 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
985 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
986 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
987 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
988 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
989 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
990 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
991 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
992 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
993 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
994 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
995 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
996 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
997 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
998 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
999 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
1000 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
1001 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
1002 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
1003 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
1004 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
1005 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
1006 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
1007 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
1008 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
1009 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
1010 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
1011 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
1012 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
1013 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
1014 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
1015 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
1016 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
1017 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
1018 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
1019 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
1020 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
1021 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
1022 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
1023 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
1024 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
1025 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
1026 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
1027 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
1028 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
1029 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
1030 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
1031 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
1032 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
1033 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
1034 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
1035 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
1036 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
1037 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
1038 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
1039 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
Eric Andersen2870d962001-07-02 17:27:21 +00001040};
1041
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001042#endif /* USE_SIT_FUNCTION */
Eric Andersen2870d962001-07-02 17:27:21 +00001043
Eric Andersen2870d962001-07-02 17:27:21 +00001044
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001045/* first char is indicating which tokens mark the end of a list */
1046static const char *const tokname_array[] = {
1047 "\1end of file",
1048 "\0newline",
1049 "\0redirection",
1050 "\0word",
1051 "\0assignment",
1052 "\0;",
1053 "\0&",
1054 "\0&&",
1055 "\0||",
1056 "\0|",
1057 "\0(",
1058 "\1)",
1059 "\1;;",
1060 "\1`",
Eric Andersen2870d962001-07-02 17:27:21 +00001061#define KWDOFFSET 14
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001062 /* the following are keywords */
1063 "\0!",
1064 "\0case",
1065 "\1do",
1066 "\1done",
1067 "\1elif",
1068 "\1else",
1069 "\1esac",
1070 "\1fi",
1071 "\0for",
1072 "\0if",
1073 "\0in",
1074 "\1then",
1075 "\0until",
1076 "\0while",
1077 "\0{",
1078 "\1}",
Eric Andersen2870d962001-07-02 17:27:21 +00001079};
1080
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001081static const char *tokname(int tok)
1082{
1083 static char buf[16];
1084
1085 if(tok>=TSEMI)
1086 buf[0] = '"';
1087 sprintf(buf+(tok>=TSEMI), "%s%c",
1088 tokname_array[tok]+1, (tok>=TSEMI ? '"' : 0));
1089 return buf;
1090}
Eric Andersen2870d962001-07-02 17:27:21 +00001091
1092static int plinno = 1; /* input line number */
1093
1094static int parselleft; /* copy of parsefile->lleft */
1095
1096static struct parsefile basepf; /* top level input file */
1097static char basebuf[BUFSIZ]; /* buffer for top level input file */
1098static struct parsefile *parsefile = &basepf; /* current input file */
1099
1100/*
1101 * NEOF is returned by parsecmd when it encounters an end of file. It
1102 * must be distinct from NULL, so we use the address of a variable that
1103 * happens to be handy.
1104 */
1105
1106static int tokpushback; /* last token pushed back */
1107#define NEOF ((union node *)&tokpushback)
1108static int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */
1109
1110
1111static void error (const char *, ...) __attribute__((__noreturn__));
1112static void exerror (int, const char *, ...) __attribute__((__noreturn__));
1113static void shellexec (char **, char **, const char *, int)
1114 __attribute__((noreturn));
1115static void exitshell (int) __attribute__((noreturn));
1116
1117static int goodname(const char *);
1118static void ignoresig (int);
1119static void onsig (int);
1120static void dotrap (void);
1121static int decode_signal (const char *, int);
1122
1123static void shprocvar(void);
1124static void deletefuncs(void);
1125static void setparam (char **);
1126static void freeparam (volatile struct shparam *);
1127
1128/* reasons for skipping commands (see comment on breakcmd routine) */
1129#define SKIPBREAK 1
1130#define SKIPCONT 2
1131#define SKIPFUNC 3
1132#define SKIPFILE 4
1133
1134/* values of cmdtype */
1135#define CMDUNKNOWN -1 /* no entry in table for command */
1136#define CMDNORMAL 0 /* command is an executable program */
1137#define CMDBUILTIN 1 /* command is a shell builtin */
1138#define CMDFUNCTION 2 /* command is a shell function */
1139
1140#define DO_ERR 1 /* find_command prints errors */
1141#define DO_ABS 2 /* find_command checks absolute paths */
1142#define DO_NOFUN 4 /* find_command ignores functions */
1143#define DO_BRUTE 8 /* find_command ignores hash table */
1144
1145/*
1146 * Shell variables.
1147 */
1148
1149/* flags */
1150#define VEXPORT 0x01 /* variable is exported */
1151#define VREADONLY 0x02 /* variable cannot be modified */
1152#define VSTRFIXED 0x04 /* variable struct is staticly allocated */
1153#define VTEXTFIXED 0x08 /* text is staticly allocated */
1154#define VSTACK 0x10 /* text is allocated on the stack */
1155#define VUNSET 0x20 /* the variable is not set */
1156#define VNOFUNC 0x40 /* don't call the callback function */
1157
1158
1159struct var {
1160 struct var *next; /* next entry in hash list */
1161 int flags; /* flags are defined above */
1162 char *text; /* name=value */
1163 void (*func) (const char *);
1164 /* function to be called when */
1165 /* the variable gets set/unset */
1166};
1167
1168struct localvar {
1169 struct localvar *next; /* next local variable in list */
1170 struct var *vp; /* the variable that was made local */
1171 int flags; /* saved flags */
1172 char *text; /* saved text */
1173};
1174
1175
Eric Andersen62483552001-07-10 06:09:16 +00001176#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00001177#define rmescapes(p) _rmescapes((p), 0)
1178static char *_rmescapes (char *, int);
1179#else
1180static void rmescapes (char *);
1181#endif
1182
1183static int casematch (union node *, const char *);
1184static void clearredir(void);
1185static void popstring(void);
1186static void readcmdfile (const char *);
1187
1188static int number (const char *);
1189static int is_number (const char *, int *num);
1190static char *single_quote (const char *);
1191static int nextopt (const char *);
1192
1193static void redirect (union node *, int);
1194static void popredir (void);
1195static int dup_as_newfd (int, int);
1196
1197static void changepath(const char *newval);
1198static void getoptsreset(const char *value);
1199
1200
1201static int parsenleft; /* copy of parsefile->nleft */
1202static char *parsenextc; /* copy of parsefile->nextc */
1203static int rootpid; /* pid of main shell */
1204static int rootshell; /* true if we aren't a child of the main shell */
1205
1206static const char spcstr[] = " ";
1207static const char snlfmt[] = "%s\n";
1208
1209static int sstrnleft;
1210static int herefd = -1;
1211
1212static struct localvar *localvars;
1213
1214static struct var vifs;
1215static struct var vmail;
1216static struct var vmpath;
1217static struct var vpath;
1218static struct var vps1;
1219static struct var vps2;
1220static struct var voptind;
1221#ifdef BB_LOCALE_SUPPORT
1222static struct var vlc_all;
1223static struct var vlc_ctype;
1224#endif
1225
1226struct varinit {
1227 struct var *var;
1228 int flags;
1229 const char *text;
1230 void (*func) (const char *);
1231};
1232
1233static const char defpathvar[] =
1234 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
1235#define defpath (defpathvar + 5)
1236
1237#ifdef IFS_BROKEN
1238static const char defifsvar[] = "IFS= \t\n";
1239#define defifs (defifsvar + 4)
1240#else
1241static const char defifs[] = " \t\n";
1242#endif
1243
1244static const struct varinit varinit[] = {
1245#ifdef IFS_BROKEN
1246 { &vifs, VSTRFIXED|VTEXTFIXED, defifsvar,
1247#else
1248 { &vifs, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS=",
1249#endif
1250 NULL },
1251 { &vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=",
1252 NULL },
1253 { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=",
1254 NULL },
1255 { &vpath, VSTRFIXED|VTEXTFIXED, defpathvar,
1256 changepath },
1257 /*
1258 * vps1 depends on uid
1259 */
1260 { &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ",
1261 NULL },
1262 { &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1",
1263 getoptsreset },
1264#ifdef BB_LOCALE_SUPPORT
1265 { &vlc_all, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL=",
1266 change_lc_all },
1267 { &vlc_ctype, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE=",
1268 change_lc_ctype },
1269#endif
1270 { NULL, 0, NULL,
1271 NULL }
1272};
1273
1274#define VTABSIZE 39
1275
1276static struct var *vartab[VTABSIZE];
1277
1278/*
1279 * The following macros access the values of the above variables.
1280 * They have to skip over the name. They return the null string
1281 * for unset variables.
1282 */
1283
1284#define ifsval() (vifs.text + 4)
1285#define ifsset() ((vifs.flags & VUNSET) == 0)
1286#define mailval() (vmail.text + 5)
1287#define mpathval() (vmpath.text + 9)
1288#define pathval() (vpath.text + 5)
1289#define ps1val() (vps1.text + 4)
1290#define ps2val() (vps2.text + 4)
1291#define optindval() (voptind.text + 7)
1292
1293#define mpathset() ((vmpath.flags & VUNSET) == 0)
1294
1295static void initvar (void);
1296static void setvar (const char *, const char *, int);
1297static void setvareq (char *, int);
1298static void listsetvar (struct strlist *);
Eric Andersen62483552001-07-10 06:09:16 +00001299static const char *lookupvar (const char *);
1300static const char *bltinlookup (const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001301static char **environment (void);
1302static int showvarscmd (int, char **);
1303static void mklocal (char *);
1304static void poplocalvars (void);
1305static int unsetvar (const char *);
1306static int varequal (const char *, const char *);
1307
1308
1309static char *arg0; /* value of $0 */
1310static struct shparam shellparam; /* current positional parameters */
1311static char **argptr; /* argument list for builtin commands */
1312static char *optionarg; /* set by nextopt (like getopt) */
1313static char *optptr; /* used by nextopt */
1314static char *minusc; /* argument to -c option */
1315
1316
1317#ifdef ASH_ALIAS
1318
1319#define ALIASINUSE 1
1320#define ALIASDEAD 2
1321
Eric Andersen3102ac42001-07-06 04:26:23 +00001322#define ATABSIZE 39
1323
Eric Andersen2870d962001-07-02 17:27:21 +00001324struct alias {
1325 struct alias *next;
1326 char *name;
1327 char *val;
1328 int flag;
1329};
1330
1331static struct alias *atab[ATABSIZE];
1332
1333static void setalias (char *, char *);
1334static struct alias **hashalias (const char *);
1335static struct alias *freealias (struct alias *);
1336static struct alias **__lookupalias (const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00001337
1338static void
1339setalias(name, val)
1340 char *name, *val;
1341{
1342 struct alias *ap, **app;
1343
1344 app = __lookupalias(name);
1345 ap = *app;
1346 INTOFF;
1347 if (ap) {
1348 if (!(ap->flag & ALIASINUSE)) {
1349 ckfree(ap->val);
1350 }
Eric Andersen2870d962001-07-02 17:27:21 +00001351 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00001352 ap->flag &= ~ALIASDEAD;
1353 } else {
1354 /* not found */
1355 ap = ckmalloc(sizeof (struct alias));
1356 ap->name = savestr(name);
1357 ap->val = savestr(val);
1358 ap->flag = 0;
1359 ap->next = 0;
1360 *app = ap;
1361 }
1362 INTON;
1363}
1364
1365static int
Eric Andersen2870d962001-07-02 17:27:21 +00001366unalias(char *name)
1367{
Eric Andersencb57d552001-06-28 07:25:16 +00001368 struct alias **app;
1369
1370 app = __lookupalias(name);
1371
1372 if (*app) {
1373 INTOFF;
1374 *app = freealias(*app);
1375 INTON;
1376 return (0);
1377 }
1378
1379 return (1);
1380}
1381
Eric Andersencb57d552001-06-28 07:25:16 +00001382static void
Eric Andersen2870d962001-07-02 17:27:21 +00001383rmaliases(void)
1384{
Eric Andersencb57d552001-06-28 07:25:16 +00001385 struct alias *ap, **app;
1386 int i;
1387
1388 INTOFF;
1389 for (i = 0; i < ATABSIZE; i++) {
1390 app = &atab[i];
1391 for (ap = *app; ap; ap = *app) {
1392 *app = freealias(*app);
1393 if (ap == *app) {
1394 app = &ap->next;
1395 }
1396 }
1397 }
1398 INTON;
1399}
1400
Eric Andersen2870d962001-07-02 17:27:21 +00001401static struct alias *
1402lookupalias(const char *name, int check)
Eric Andersencb57d552001-06-28 07:25:16 +00001403{
1404 struct alias *ap = *__lookupalias(name);
1405
1406 if (check && ap && (ap->flag & ALIASINUSE))
1407 return (NULL);
1408 return (ap);
1409}
1410
Eric Andersen2870d962001-07-02 17:27:21 +00001411static void
1412printalias(const struct alias *ap) {
1413 char *p;
1414
1415 p = single_quote(ap->val);
Eric Andersen62483552001-07-10 06:09:16 +00001416 printf("alias %s=%s\n", ap->name, p);
Eric Andersen2870d962001-07-02 17:27:21 +00001417 stunalloc(p);
1418}
1419
Eric Andersencb57d552001-06-28 07:25:16 +00001420
1421/*
1422 * TODO - sort output
1423 */
1424static int
Eric Andersen2870d962001-07-02 17:27:21 +00001425aliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001426{
1427 char *n, *v;
1428 int ret = 0;
1429 struct alias *ap;
1430
1431 if (argc == 1) {
1432 int i;
1433
1434 for (i = 0; i < ATABSIZE; i++)
1435 for (ap = atab[i]; ap; ap = ap->next) {
1436 printalias(ap);
1437 }
1438 return (0);
1439 }
1440 while ((n = *++argv) != NULL) {
1441 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
1442 if ((ap = *__lookupalias(n)) == NULL) {
Eric Andersen3102ac42001-07-06 04:26:23 +00001443 out2fmt("%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00001444 ret = 1;
1445 } else
1446 printalias(ap);
1447 }
1448 else {
1449 *v++ = '\0';
1450 setalias(n, v);
1451 }
1452 }
1453
1454 return (ret);
1455}
1456
1457static int
Eric Andersen2870d962001-07-02 17:27:21 +00001458unaliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001459{
1460 int i;
1461
1462 while ((i = nextopt("a")) != '\0') {
1463 if (i == 'a') {
1464 rmaliases();
1465 return (0);
1466 }
1467 }
1468 for (i = 0; *argptr; argptr++) {
1469 if (unalias(*argptr)) {
Eric Andersen3102ac42001-07-06 04:26:23 +00001470 out2fmt("%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00001471 i = 1;
1472 }
1473 }
1474
1475 return (i);
1476}
1477
1478static struct alias **
1479hashalias(p)
1480 const char *p;
1481 {
1482 unsigned int hashval;
1483
1484 hashval = *p << 4;
1485 while (*p)
1486 hashval+= *p++;
1487 return &atab[hashval % ATABSIZE];
1488}
1489
1490static struct alias *
1491freealias(struct alias *ap) {
1492 struct alias *next;
1493
1494 if (ap->flag & ALIASINUSE) {
1495 ap->flag |= ALIASDEAD;
1496 return ap;
1497 }
1498
1499 next = ap->next;
1500 ckfree(ap->name);
1501 ckfree(ap->val);
1502 ckfree(ap);
1503 return next;
1504}
1505
Eric Andersencb57d552001-06-28 07:25:16 +00001506
1507static struct alias **
1508__lookupalias(const char *name) {
1509 struct alias **app = hashalias(name);
1510
1511 for (; *app; app = &(*app)->next) {
1512 if (equal(name, (*app)->name)) {
1513 break;
1514 }
1515 }
1516
1517 return app;
1518}
Eric Andersen2870d962001-07-02 17:27:21 +00001519#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001520
1521#ifdef ASH_MATH_SUPPORT
Eric Andersen74bcd162001-07-30 21:41:37 +00001522/* The generated file arith.c has been replaced with a custom hand
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001523 * written implementation written by Aaron Lehmann <aaronl@vitelus.com>.
1524 * This is now part of libbb, so that it can be used by all the shells
Eric Andersen74bcd162001-07-30 21:41:37 +00001525 * in busybox. */
Eric Andersen2870d962001-07-02 17:27:21 +00001526static void expari (int);
Eric Andersencb57d552001-06-28 07:25:16 +00001527#endif
1528
Eric Andersen2870d962001-07-02 17:27:21 +00001529static char *trap[NSIG]; /* trap handler commands */
1530static char sigmode[NSIG - 1]; /* current value of signal */
1531static char gotsig[NSIG - 1]; /* indicates specified signal received */
1532static int pendingsigs; /* indicates some signal received */
1533
Eric Andersencb57d552001-06-28 07:25:16 +00001534/*
1535 * This file was generated by the mkbuiltins program.
1536 */
1537
Eric Andersen2870d962001-07-02 17:27:21 +00001538#ifdef JOBS
1539static int bgcmd (int, char **);
1540static int fgcmd (int, char **);
1541static int killcmd (int, char **);
1542#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001543static int bltincmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001544static int cdcmd (int, char **);
1545static int breakcmd (int, char **);
1546#ifdef ASH_CMDCMD
1547static int commandcmd (int, char **);
1548#endif
1549static int dotcmd (int, char **);
1550static int evalcmd (int, char **);
1551static int execcmd (int, char **);
1552static int exitcmd (int, char **);
1553static int exportcmd (int, char **);
1554static int histcmd (int, char **);
1555static int hashcmd (int, char **);
Eric Andersen1c039232001-07-07 00:05:55 +00001556static int helpcmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001557static int jobscmd (int, char **);
1558static int localcmd (int, char **);
Eric Andersen3102ac42001-07-06 04:26:23 +00001559#ifndef BB_PWD
Eric Andersen2870d962001-07-02 17:27:21 +00001560static int pwdcmd (int, char **);
1561#endif
1562static int readcmd (int, char **);
1563static int returncmd (int, char **);
1564static int setcmd (int, char **);
1565static int setvarcmd (int, char **);
1566static int shiftcmd (int, char **);
1567static int trapcmd (int, char **);
1568static int umaskcmd (int, char **);
1569#ifdef ASH_ALIAS
1570static int aliascmd (int, char **);
1571static int unaliascmd (int, char **);
1572#endif
1573static int unsetcmd (int, char **);
1574static int waitcmd (int, char **);
1575static int ulimitcmd (int, char **);
1576static int timescmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001577#ifdef ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +00001578static int letcmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001579#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001580static int typecmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001581#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00001582static int getoptscmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001583#endif
1584
Eric Andersen2870d962001-07-02 17:27:21 +00001585#ifndef BB_TRUE_FALSE
Eric Andersen2870d962001-07-02 17:27:21 +00001586static int true_main (int, char **);
1587static int false_main (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001588#endif
1589
1590static void setpwd (const char *, int);
1591
1592
1593#define BUILTIN_NOSPEC "0"
1594#define BUILTIN_SPECIAL "1"
1595#define BUILTIN_REGULAR "2"
1596#define BUILTIN_ASSIGN "4"
1597#define BUILTIN_SPEC_ASSG "5"
1598#define BUILTIN_REG_ASSG "6"
1599
1600#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1601#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1602#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
1603
1604struct builtincmd {
1605 const char *name;
1606 int (*const builtinfunc) (int, char **);
1607 //unsigned flags;
1608};
1609
Eric Andersencb57d552001-06-28 07:25:16 +00001610
1611/* It is CRUCIAL that this listing be kept in ascii order, otherwise
1612 * the binary search in find_builtin() will stop working. If you value
1613 * your kneecaps, you'll be sure to *make sure* that any changes made
1614 * to this array result in the listing remaining in ascii order. You
1615 * have been warned.
1616 */
1617static const struct builtincmd builtincmds[] = {
Eric Andersen62483552001-07-10 06:09:16 +00001618 { BUILTIN_SPECIAL ".", dotcmd }, /* first, see declare DOTCMD */
Eric Andersen2870d962001-07-02 17:27:21 +00001619 { BUILTIN_SPECIAL ":", true_main },
1620#ifdef ASH_ALIAS
1621 { BUILTIN_REG_ASSG "alias", aliascmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001622#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001623#ifdef JOBS
1624 { BUILTIN_REGULAR "bg", bgcmd },
1625#endif
1626 { BUILTIN_SPECIAL "break", breakcmd },
Eric Andersen3102ac42001-07-06 04:26:23 +00001627 { BUILTIN_SPECIAL "builtin", bltincmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001628 { BUILTIN_REGULAR "cd", cdcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001629 { BUILTIN_NOSPEC "chdir", cdcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001630#ifdef ASH_CMDCMD
1631 { BUILTIN_REGULAR "command", commandcmd },
1632#endif
1633 { BUILTIN_SPECIAL "continue", breakcmd },
1634 { BUILTIN_SPECIAL "eval", evalcmd },
1635 { BUILTIN_SPECIAL "exec", execcmd },
1636 { BUILTIN_SPECIAL "exit", exitcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001637 { BUILTIN_SPEC_ASSG "export", exportcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001638 { BUILTIN_REGULAR "false", false_main },
Eric Andersen2870d962001-07-02 17:27:21 +00001639 { BUILTIN_REGULAR "fc", histcmd },
1640#ifdef JOBS
1641 { BUILTIN_REGULAR "fg", fgcmd },
1642#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001643#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00001644 { BUILTIN_REGULAR "getopts", getoptscmd },
1645#endif
1646 { BUILTIN_NOSPEC "hash", hashcmd },
Eric Andersen1c039232001-07-07 00:05:55 +00001647 { BUILTIN_NOSPEC "help", helpcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001648 { BUILTIN_REGULAR "jobs", jobscmd },
1649#ifdef JOBS
1650 { BUILTIN_REGULAR "kill", killcmd },
1651#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001652#ifdef ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +00001653 { BUILTIN_REGULAR "let", letcmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001654#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001655 { BUILTIN_ASSIGN "local", localcmd },
Eric Andersen3102ac42001-07-06 04:26:23 +00001656#ifndef BB_PWD
Eric Andersen2870d962001-07-02 17:27:21 +00001657 { BUILTIN_NOSPEC "pwd", pwdcmd },
1658#endif
1659 { BUILTIN_REGULAR "read", readcmd },
1660 { BUILTIN_SPEC_ASSG "readonly", exportcmd },
1661 { BUILTIN_SPECIAL "return", returncmd },
1662 { BUILTIN_SPECIAL "set", setcmd },
1663 { BUILTIN_NOSPEC "setvar", setvarcmd },
1664 { BUILTIN_SPECIAL "shift", shiftcmd },
1665 { BUILTIN_SPECIAL "times", timescmd },
1666 { BUILTIN_SPECIAL "trap", trapcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001667 { BUILTIN_REGULAR "true", true_main },
Eric Andersen2870d962001-07-02 17:27:21 +00001668 { BUILTIN_NOSPEC "type", typecmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001669 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1670 { BUILTIN_REGULAR "umask", umaskcmd },
1671#ifdef ASH_ALIAS
1672 { BUILTIN_REGULAR "unalias", unaliascmd },
1673#endif
1674 { BUILTIN_SPECIAL "unset", unsetcmd },
1675 { BUILTIN_REGULAR "wait", waitcmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001676};
1677#define NUMBUILTINS (sizeof (builtincmds) / sizeof (struct builtincmd) )
1678
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001679#define DOTCMD &builtincmds[0]
Eric Andersen2870d962001-07-02 17:27:21 +00001680static struct builtincmd *BLTINCMD;
1681static struct builtincmd *EXECCMD;
1682static struct builtincmd *EVALCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00001683
Eric Andersen2870d962001-07-02 17:27:21 +00001684/* states */
1685#define JOBSTOPPED 1 /* all procs are stopped */
1686#define JOBDONE 2 /* all procs are completed */
Eric Andersencb57d552001-06-28 07:25:16 +00001687
Eric Andersen2870d962001-07-02 17:27:21 +00001688/*
1689 * A job structure contains information about a job. A job is either a
1690 * single process or a set of processes contained in a pipeline. In the
1691 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1692 * array of pids.
1693 */
Eric Andersencb57d552001-06-28 07:25:16 +00001694
Eric Andersen2870d962001-07-02 17:27:21 +00001695struct procstat {
1696 pid_t pid; /* process id */
1697 int status; /* status flags (defined above) */
1698 char *cmd; /* text of command being run */
1699};
Eric Andersencb57d552001-06-28 07:25:16 +00001700
Eric Andersen2870d962001-07-02 17:27:21 +00001701
1702static int job_warning; /* user was warned about stopped jobs */
1703
1704#ifdef JOBS
1705static void setjobctl(int enable);
1706#else
1707#define setjobctl(on) /* do nothing */
Eric Andersencb57d552001-06-28 07:25:16 +00001708#endif
1709
Eric Andersen2870d962001-07-02 17:27:21 +00001710
1711struct job {
1712 struct procstat ps0; /* status of process */
1713 struct procstat *ps; /* status or processes when more than one */
1714 short nprocs; /* number of processes */
1715 short pgrp; /* process group of this job */
1716 char state; /* true if job is finished */
1717 char used; /* true if this entry is in used */
1718 char changed; /* true if status has changed */
1719#ifdef JOBS
1720 char jobctl; /* job running under job control */
1721#endif
1722};
1723
1724static struct job *jobtab; /* array of jobs */
1725static int njobs; /* size of array */
1726static int backgndpid = -1; /* pid of last background process */
1727#ifdef JOBS
1728static int initialpgrp; /* pgrp of shell on invocation */
1729static int curjob; /* current job */
1730static int jobctl;
1731#endif
1732static int intreceived;
1733
Eric Andersen62483552001-07-10 06:09:16 +00001734static struct job *makejob (const union node *, int);
1735static int forkshell (struct job *, const union node *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00001736static int waitforjob (struct job *);
1737
1738static int docd (char *, int);
1739static char *getcomponent (void);
1740static void updatepwd (const char *);
1741static void getpwd (void);
1742
1743static char *padvance (const char **, const char *);
1744
1745static char nullstr[1]; /* zero length string */
1746static char *curdir = nullstr; /* current working directory */
1747static char *cdcomppath;
1748
Eric Andersencb57d552001-06-28 07:25:16 +00001749static int
1750cdcmd(argc, argv)
1751 int argc;
1752 char **argv;
1753{
1754 const char *dest;
1755 const char *path;
1756 char *p;
1757 struct stat statb;
1758 int print = 0;
1759
1760 nextopt(nullstr);
1761 if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME")) == NULL)
1762 error("HOME not set");
1763 if (*dest == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00001764 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001765 if (dest[0] == '-' && dest[1] == '\0') {
1766 dest = bltinlookup("OLDPWD");
1767 if (!dest || !*dest) {
1768 dest = curdir;
1769 }
1770 print = 1;
1771 if (dest)
Eric Andersen2870d962001-07-02 17:27:21 +00001772 print = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00001773 else
Eric Andersen2870d962001-07-02 17:27:21 +00001774 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001775 }
1776 if (*dest == '/' || (path = bltinlookup("CDPATH")) == NULL)
1777 path = nullstr;
1778 while ((p = padvance(&path, dest)) != NULL) {
1779 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
1780 if (!print) {
1781 /*
1782 * XXX - rethink
1783 */
1784 if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
1785 p += 2;
1786 print = strcmp(p, dest);
1787 }
1788 if (docd(p, print) >= 0)
1789 return 0;
1790
1791 }
1792 }
1793 error("can't cd to %s", dest);
1794 /* NOTREACHED */
1795}
1796
1797
1798/*
1799 * Actually do the chdir. In an interactive shell, print the
1800 * directory name if "print" is nonzero.
1801 */
1802
1803static int
1804docd(dest, print)
1805 char *dest;
1806 int print;
1807{
1808 char *p;
1809 char *q;
1810 char *component;
1811 struct stat statb;
1812 int first;
1813 int badstat;
1814
1815 TRACE(("docd(\"%s\", %d) called\n", dest, print));
1816
1817 /*
1818 * Check each component of the path. If we find a symlink or
1819 * something we can't stat, clear curdir to force a getcwd()
1820 * next time we get the value of the current directory.
1821 */
1822 badstat = 0;
1823 cdcomppath = sstrdup(dest);
1824 STARTSTACKSTR(p);
1825 if (*dest == '/') {
1826 STPUTC('/', p);
1827 cdcomppath++;
1828 }
1829 first = 1;
1830 while ((q = getcomponent()) != NULL) {
1831 if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0'))
1832 continue;
1833 if (! first)
1834 STPUTC('/', p);
1835 first = 0;
1836 component = q;
1837 while (*q)
1838 STPUTC(*q++, p);
1839 if (equal(component, ".."))
1840 continue;
1841 STACKSTRNUL(p);
1842 if ((lstat(stackblock(), &statb) < 0)
1843 || (S_ISLNK(statb.st_mode))) {
1844 /* print = 1; */
1845 badstat = 1;
1846 break;
1847 }
1848 }
1849
1850 INTOFF;
1851 if (chdir(dest) < 0) {
1852 INTON;
1853 return -1;
1854 }
1855 updatepwd(badstat ? NULL : dest);
1856 INTON;
1857 if (print && iflag)
Eric Andersen62483552001-07-10 06:09:16 +00001858 printf(snlfmt, curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00001859 return 0;
1860}
1861
1862
1863/*
1864 * Get the next component of the path name pointed to by cdcomppath.
1865 * This routine overwrites the string pointed to by cdcomppath.
1866 */
1867
1868static char *
1869getcomponent() {
1870 char *p;
1871 char *start;
1872
1873 if ((p = cdcomppath) == NULL)
1874 return NULL;
1875 start = cdcomppath;
1876 while (*p != '/' && *p != '\0')
1877 p++;
1878 if (*p == '\0') {
1879 cdcomppath = NULL;
1880 } else {
1881 *p++ = '\0';
1882 cdcomppath = p;
1883 }
1884 return start;
1885}
1886
1887
1888
1889/*
1890 * Update curdir (the name of the current directory) in response to a
1891 * cd command. We also call hashcd to let the routines in exec.c know
1892 * that the current directory has changed.
1893 */
1894
Eric Andersen2870d962001-07-02 17:27:21 +00001895static void hashcd (void);
1896
Eric Andersencb57d552001-06-28 07:25:16 +00001897static void
Eric Andersen2870d962001-07-02 17:27:21 +00001898updatepwd(const char *dir)
1899{
Eric Andersencb57d552001-06-28 07:25:16 +00001900 char *new;
1901 char *p;
1902 size_t len;
1903
Eric Andersen2870d962001-07-02 17:27:21 +00001904 hashcd(); /* update command hash table */
Eric Andersencb57d552001-06-28 07:25:16 +00001905
1906 /*
1907 * If our argument is NULL, we don't know the current directory
1908 * any more because we traversed a symbolic link or something
1909 * we couldn't stat().
1910 */
1911 if (dir == NULL || curdir == nullstr) {
1912 setpwd(0, 1);
1913 return;
1914 }
1915 len = strlen(dir);
1916 cdcomppath = sstrdup(dir);
1917 STARTSTACKSTR(new);
1918 if (*dir != '/') {
1919 p = curdir;
1920 while (*p)
1921 STPUTC(*p++, new);
1922 if (p[-1] == '/')
1923 STUNPUTC(new);
1924 }
1925 while ((p = getcomponent()) != NULL) {
1926 if (equal(p, "..")) {
1927 while (new > stackblock() && (STUNPUTC(new), *new) != '/');
1928 } else if (*p != '\0' && ! equal(p, ".")) {
1929 STPUTC('/', new);
1930 while (*p)
1931 STPUTC(*p++, new);
1932 }
1933 }
1934 if (new == stackblock())
1935 STPUTC('/', new);
1936 STACKSTRNUL(new);
1937 setpwd(stackblock(), 1);
1938}
1939
1940
Eric Andersen3102ac42001-07-06 04:26:23 +00001941#ifndef BB_PWD
Eric Andersencb57d552001-06-28 07:25:16 +00001942static int
1943pwdcmd(argc, argv)
1944 int argc;
1945 char **argv;
1946{
Eric Andersen62483552001-07-10 06:09:16 +00001947 printf(snlfmt, curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00001948 return 0;
1949}
Eric Andersen2870d962001-07-02 17:27:21 +00001950#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001951
1952/*
1953 * Find out what the current directory is. If we already know the current
1954 * directory, this routine returns immediately.
1955 */
1956static void
Eric Andersen2870d962001-07-02 17:27:21 +00001957getpwd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00001958{
Eric Andersen2870d962001-07-02 17:27:21 +00001959 curdir = xgetcwd(0);
1960 if(curdir==0)
1961 curdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00001962}
1963
1964static void
1965setpwd(const char *val, int setold)
1966{
1967 if (setold) {
1968 setvar("OLDPWD", curdir, VEXPORT);
1969 }
1970 INTOFF;
1971 if (curdir != nullstr) {
1972 free(curdir);
1973 curdir = nullstr;
1974 }
1975 if (!val) {
1976 getpwd();
1977 } else {
1978 curdir = savestr(val);
1979 }
1980 INTON;
1981 setvar("PWD", curdir, VEXPORT);
1982}
1983
Eric Andersencb57d552001-06-28 07:25:16 +00001984/*
1985 * Errors and exceptions.
1986 */
1987
1988/*
1989 * Code to handle exceptions in C.
1990 */
1991
Eric Andersen2870d962001-07-02 17:27:21 +00001992/*
1993 * We enclose jmp_buf in a structure so that we can declare pointers to
1994 * jump locations. The global variable handler contains the location to
1995 * jump to when an exception occurs, and the global variable exception
1996 * contains a code identifying the exeception. To implement nested
1997 * exception handlers, the user should save the value of handler on entry
1998 * to an inner scope, set handler to point to a jmploc structure for the
1999 * inner scope, and restore handler on exit from the scope.
2000 */
2001
2002struct jmploc {
2003 jmp_buf loc;
2004};
2005
2006/* exceptions */
2007#define EXINT 0 /* SIGINT received */
2008#define EXERROR 1 /* a generic error */
2009#define EXSHELLPROC 2 /* execute a shell procedure */
2010#define EXEXEC 3 /* command execution failed */
2011
2012static struct jmploc *handler;
Eric Andersencb57d552001-06-28 07:25:16 +00002013static int exception;
Eric Andersencb57d552001-06-28 07:25:16 +00002014
Eric Andersen2870d962001-07-02 17:27:21 +00002015static void exverror (int, const char *, va_list)
Eric Andersencb57d552001-06-28 07:25:16 +00002016 __attribute__((__noreturn__));
2017
2018/*
2019 * Called to raise an exception. Since C doesn't include exceptions, we
2020 * just do a longjmp to the exception handler. The type of exception is
2021 * stored in the global variable "exception".
2022 */
2023
Eric Andersen2870d962001-07-02 17:27:21 +00002024static void exraise (int) __attribute__((__noreturn__));
2025
Eric Andersencb57d552001-06-28 07:25:16 +00002026static void
Eric Andersen2870d962001-07-02 17:27:21 +00002027exraise(int e)
Eric Andersencb57d552001-06-28 07:25:16 +00002028{
2029#ifdef DEBUG
2030 if (handler == NULL)
2031 abort();
2032#endif
Eric Andersen62483552001-07-10 06:09:16 +00002033 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00002034 exception = e;
2035 longjmp(handler->loc, 1);
2036}
2037
2038
2039/*
2040 * Called from trap.c when a SIGINT is received. (If the user specifies
2041 * that SIGINT is to be trapped or ignored using the trap builtin, then
2042 * this routine is not called.) Suppressint is nonzero when interrupts
2043 * are held using the INTOFF macro. The call to _exit is necessary because
2044 * there is a short period after a fork before the signal handlers are
2045 * set to the appropriate value for the child. (The test for iflag is
2046 * just defensive programming.)
2047 */
2048
2049static void
Eric Andersen2870d962001-07-02 17:27:21 +00002050onint(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00002051 sigset_t mysigset;
2052
2053 if (suppressint) {
2054 intpending++;
2055 return;
2056 }
2057 intpending = 0;
2058 sigemptyset(&mysigset);
2059 sigprocmask(SIG_SETMASK, &mysigset, NULL);
2060 if (rootshell && iflag)
2061 exraise(EXINT);
2062 else {
2063 signal(SIGINT, SIG_DFL);
2064 raise(SIGINT);
2065 }
2066 /* NOTREACHED */
2067}
2068
2069
Eric Andersen2870d962001-07-02 17:27:21 +00002070static char *commandname; /* currently executing command */
2071
Eric Andersencb57d552001-06-28 07:25:16 +00002072/*
2073 * Exverror is called to raise the error exception. If the first argument
2074 * is not NULL then error prints an error message using printf style
2075 * formatting. It then raises the error exception.
2076 */
2077static void
Eric Andersen2870d962001-07-02 17:27:21 +00002078exverror(int cond, const char *msg, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00002079{
2080 CLEAR_PENDING_INT;
2081 INTOFF;
2082
2083#ifdef DEBUG
2084 if (msg)
2085 TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
2086 else
2087 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2088#endif
2089 if (msg) {
2090 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +00002091 out2fmt("%s: ", commandname);
2092 vfprintf(stderr, msg, ap);
2093 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00002094 }
Eric Andersencb57d552001-06-28 07:25:16 +00002095 exraise(cond);
2096 /* NOTREACHED */
2097}
2098
2099
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002100static void
Eric Andersencb57d552001-06-28 07:25:16 +00002101error(const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002102{
Eric Andersencb57d552001-06-28 07:25:16 +00002103 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002104 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002105 exverror(EXERROR, msg, ap);
2106 /* NOTREACHED */
2107 va_end(ap);
2108}
2109
2110
Eric Andersencb57d552001-06-28 07:25:16 +00002111static void
2112exerror(int cond, const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002113{
Eric Andersencb57d552001-06-28 07:25:16 +00002114 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002115 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002116 exverror(cond, msg, ap);
2117 /* NOTREACHED */
2118 va_end(ap);
2119}
2120
2121
2122
2123/*
2124 * Table of error messages.
2125 */
2126
2127struct errname {
Eric Andersen2870d962001-07-02 17:27:21 +00002128 short errcode; /* error number */
Eric Andersen62483552001-07-10 06:09:16 +00002129 char action; /* operation which encountered the error */
Eric Andersencb57d552001-06-28 07:25:16 +00002130};
2131
Eric Andersen2870d962001-07-02 17:27:21 +00002132/*
2133 * Types of operations (passed to the errmsg routine).
2134 */
2135
2136#define E_OPEN 01 /* opening a file */
2137#define E_CREAT 02 /* creating a file */
2138#define E_EXEC 04 /* executing a program */
Eric Andersencb57d552001-06-28 07:25:16 +00002139
2140#define ALL (E_OPEN|E_CREAT|E_EXEC)
2141
2142static const struct errname errormsg[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00002143 { EINTR, ALL },
2144 { EACCES, ALL },
2145 { EIO, ALL },
2146 { ENOENT, E_OPEN },
2147 { ENOENT, E_CREAT },
2148 { ENOENT, E_EXEC },
2149 { ENOTDIR, E_OPEN },
2150 { ENOTDIR, E_CREAT },
2151 { ENOTDIR, E_EXEC },
2152 { EISDIR, ALL },
2153 { EEXIST, E_CREAT },
2154#ifdef EMFILE
2155 { EMFILE, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002156#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002157 { ENFILE, ALL },
2158 { ENOSPC, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002159#ifdef EDQUOT
Eric Andersen2870d962001-07-02 17:27:21 +00002160 { EDQUOT, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002161#endif
2162#ifdef ENOSR
Eric Andersen2870d962001-07-02 17:27:21 +00002163 { ENOSR, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002164#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002165 { ENXIO, ALL },
2166 { EROFS, ALL },
2167 { ETXTBSY, ALL },
2168#ifdef EAGAIN
2169 { EAGAIN, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002170#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002171 { ENOMEM, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002172#ifdef ENOLINK
Eric Andersen2870d962001-07-02 17:27:21 +00002173 { ENOLINK, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002174#endif
2175#ifdef EMULTIHOP
Eric Andersen2870d962001-07-02 17:27:21 +00002176 { EMULTIHOP, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002177#endif
2178#ifdef ECOMM
Eric Andersen2870d962001-07-02 17:27:21 +00002179 { ECOMM, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002180#endif
2181#ifdef ESTALE
Eric Andersen2870d962001-07-02 17:27:21 +00002182 { ESTALE, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002183#endif
2184#ifdef ETIMEDOUT
Eric Andersen2870d962001-07-02 17:27:21 +00002185 { ETIMEDOUT, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002186#endif
2187#ifdef ELOOP
Eric Andersen2870d962001-07-02 17:27:21 +00002188 { ELOOP, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002189#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002190 { E2BIG, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002191#ifdef ELIBACC
Eric Andersen2870d962001-07-02 17:27:21 +00002192 { ELIBACC, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002193#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002194};
2195
Eric Andersen2870d962001-07-02 17:27:21 +00002196#define ERRNAME_SIZE (sizeof(errormsg)/sizeof(struct errname))
Eric Andersencb57d552001-06-28 07:25:16 +00002197
2198/*
2199 * Return a string describing an error. The returned string may be a
2200 * pointer to a static buffer that will be overwritten on the next call.
2201 * Action describes the operation that got the error.
2202 */
2203
2204static const char *
Eric Andersen2870d962001-07-02 17:27:21 +00002205errmsg(int e, int action)
Eric Andersencb57d552001-06-28 07:25:16 +00002206{
2207 struct errname const *ep;
2208 static char buf[12];
2209
Eric Andersen2870d962001-07-02 17:27:21 +00002210 for (ep = errormsg ; ep < errormsg+ERRNAME_SIZE; ep++) {
Eric Andersencb57d552001-06-28 07:25:16 +00002211 if (ep->errcode == e && (ep->action & action) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00002212 return strerror(e);
Eric Andersencb57d552001-06-28 07:25:16 +00002213 }
Eric Andersen2870d962001-07-02 17:27:21 +00002214
Eric Andersen3102ac42001-07-06 04:26:23 +00002215 snprintf(buf, sizeof buf, "error %d", e);
Eric Andersencb57d552001-06-28 07:25:16 +00002216 return buf;
2217}
2218
2219
Eric Andersen3102ac42001-07-06 04:26:23 +00002220#ifdef ASH_OPTIMIZE_FOR_SIZE
Eric Andersencb57d552001-06-28 07:25:16 +00002221static void
2222__inton() {
2223 if (--suppressint == 0 && intpending) {
2224 onint();
2225 }
2226}
Eric Andersen3102ac42001-07-06 04:26:23 +00002227static void forceinton (void) {
2228 suppressint = 0;
2229 if (intpending)
2230 onint();
2231}
Eric Andersencb57d552001-06-28 07:25:16 +00002232#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002233
2234/* flags in argument to evaltree */
Eric Andersen2870d962001-07-02 17:27:21 +00002235#define EV_EXIT 01 /* exit after evaluating tree */
2236#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2237#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00002238
Eric Andersen2870d962001-07-02 17:27:21 +00002239static int evalskip; /* set if we are skipping commands */
2240static int skipcount; /* number of levels to skip */
2241static int loopnest; /* current loop nesting level */
2242static int funcnest; /* depth of function calls */
Eric Andersencb57d552001-06-28 07:25:16 +00002243
2244
Eric Andersen2870d962001-07-02 17:27:21 +00002245static struct strlist *cmdenviron; /* environment for builtin command */
2246static int exitstatus; /* exit status of last command */
2247static int oexitstatus; /* saved exit status */
Eric Andersencb57d552001-06-28 07:25:16 +00002248
Eric Andersen62483552001-07-10 06:09:16 +00002249static void evalsubshell (const union node *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00002250static void expredir (union node *);
Eric Andersen2870d962001-07-02 17:27:21 +00002251static void prehash (union node *);
2252static void eprintlist (struct strlist *);
Eric Andersencb57d552001-06-28 07:25:16 +00002253
Eric Andersen2870d962001-07-02 17:27:21 +00002254static union node *parsecmd(int);
Eric Andersencb57d552001-06-28 07:25:16 +00002255/*
2256 * Called to reset things after an exception.
2257 */
2258
Eric Andersencb57d552001-06-28 07:25:16 +00002259/*
2260 * The eval commmand.
2261 */
Eric Andersen2870d962001-07-02 17:27:21 +00002262static void evalstring (char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00002263
2264static int
2265evalcmd(argc, argv)
2266 int argc;
2267 char **argv;
2268{
Eric Andersen2870d962001-07-02 17:27:21 +00002269 char *p;
2270 char *concat;
2271 char **ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002272
Eric Andersen2870d962001-07-02 17:27:21 +00002273 if (argc > 1) {
2274 p = argv[1];
2275 if (argc > 2) {
2276 STARTSTACKSTR(concat);
2277 ap = argv + 2;
2278 for (;;) {
2279 while (*p)
2280 STPUTC(*p++, concat);
2281 if ((p = *ap++) == NULL)
2282 break;
2283 STPUTC(' ', concat);
2284 }
2285 STPUTC('\0', concat);
2286 p = grabstackstr(concat);
2287 }
2288 evalstring(p, EV_TESTED);
2289 }
2290 return exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002291}
2292
Eric Andersencb57d552001-06-28 07:25:16 +00002293/*
2294 * Execute a command or commands contained in a string.
2295 */
2296
Eric Andersen2870d962001-07-02 17:27:21 +00002297static void evaltree (union node *, int);
2298static void setinputstring (char *);
2299static void popfile (void);
2300static void setstackmark(struct stackmark *mark);
2301static void popstackmark(struct stackmark *mark);
2302
2303
Eric Andersencb57d552001-06-28 07:25:16 +00002304static void
Eric Andersen2870d962001-07-02 17:27:21 +00002305evalstring(char *s, int flag)
2306{
Eric Andersencb57d552001-06-28 07:25:16 +00002307 union node *n;
2308 struct stackmark smark;
2309
2310 setstackmark(&smark);
2311 setinputstring(s);
2312 while ((n = parsecmd(0)) != NEOF) {
2313 evaltree(n, flag);
2314 popstackmark(&smark);
2315 }
2316 popfile();
2317 popstackmark(&smark);
2318}
2319
Eric Andersen2870d962001-07-02 17:27:21 +00002320static struct builtincmd *find_builtin (const char *);
Eric Andersen62483552001-07-10 06:09:16 +00002321static void expandarg (union node *, struct arglist *, int);
2322static void calcsize (const union node *);
2323static union node *copynode (const union node *);
2324
2325/*
2326 * Make a copy of a parse tree.
2327 */
2328
2329static int funcblocksize; /* size of structures in function */
2330static int funcstringsize; /* size of strings in node */
2331static pointer funcblock; /* block to allocate function from */
2332static char *funcstring; /* block to allocate strings from */
2333
2334
2335static inline union node *
2336copyfunc(union node *n)
2337{
2338 if (n == NULL)
2339 return NULL;
2340 funcblocksize = 0;
2341 funcstringsize = 0;
2342 calcsize(n);
2343 funcblock = ckmalloc(funcblocksize + funcstringsize);
2344 funcstring = (char *) funcblock + funcblocksize;
2345 return copynode(n);
2346}
2347
2348/*
2349 * Free a parse tree.
2350 */
Eric Andersencb57d552001-06-28 07:25:16 +00002351
2352static void
Eric Andersen62483552001-07-10 06:09:16 +00002353freefunc(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00002354{
Eric Andersen62483552001-07-10 06:09:16 +00002355 if (n)
2356 ckfree(n);
Eric Andersencb57d552001-06-28 07:25:16 +00002357}
2358
2359
Eric Andersen62483552001-07-10 06:09:16 +00002360/*
2361 * Add a new command entry, replacing any existing command entry for
2362 * the same name.
2363 */
2364
2365static inline void
2366addcmdentry(char *name, struct cmdentry *entry)
2367{
2368 struct tblentry *cmdp;
2369
2370 INTOFF;
2371 cmdp = cmdlookup(name, 1);
2372 if (cmdp->cmdtype == CMDFUNCTION) {
2373 freefunc(cmdp->param.func);
2374 }
2375 cmdp->cmdtype = entry->cmdtype;
2376 cmdp->param = entry->u;
2377 INTON;
2378}
2379
2380static inline void
2381evalloop(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002382{
2383 int status;
2384
2385 loopnest++;
2386 status = 0;
2387 for (;;) {
2388 evaltree(n->nbinary.ch1, EV_TESTED);
2389 if (evalskip) {
Eric Andersen2870d962001-07-02 17:27:21 +00002390skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002391 evalskip = 0;
2392 continue;
2393 }
2394 if (evalskip == SKIPBREAK && --skipcount <= 0)
2395 evalskip = 0;
2396 break;
2397 }
2398 if (n->type == NWHILE) {
2399 if (exitstatus != 0)
2400 break;
2401 } else {
2402 if (exitstatus == 0)
2403 break;
2404 }
2405 evaltree(n->nbinary.ch2, flags & EV_TESTED);
2406 status = exitstatus;
2407 if (evalskip)
2408 goto skipping;
2409 }
2410 loopnest--;
2411 exitstatus = status;
2412}
2413
Eric Andersencb57d552001-06-28 07:25:16 +00002414static void
Eric Andersen62483552001-07-10 06:09:16 +00002415evalfor(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002416{
2417 struct arglist arglist;
2418 union node *argp;
2419 struct strlist *sp;
2420 struct stackmark smark;
2421
2422 setstackmark(&smark);
2423 arglist.lastp = &arglist.list;
2424 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2425 oexitstatus = exitstatus;
2426 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2427 if (evalskip)
2428 goto out;
2429 }
2430 *arglist.lastp = NULL;
2431
2432 exitstatus = 0;
2433 loopnest++;
2434 for (sp = arglist.list ; sp ; sp = sp->next) {
2435 setvar(n->nfor.var, sp->text, 0);
2436 evaltree(n->nfor.body, flags & EV_TESTED);
2437 if (evalskip) {
2438 if (evalskip == SKIPCONT && --skipcount <= 0) {
2439 evalskip = 0;
2440 continue;
2441 }
2442 if (evalskip == SKIPBREAK && --skipcount <= 0)
2443 evalskip = 0;
2444 break;
2445 }
2446 }
2447 loopnest--;
2448out:
2449 popstackmark(&smark);
2450}
2451
Eric Andersen62483552001-07-10 06:09:16 +00002452static inline void
2453evalcase(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002454{
2455 union node *cp;
2456 union node *patp;
2457 struct arglist arglist;
2458 struct stackmark smark;
2459
2460 setstackmark(&smark);
2461 arglist.lastp = &arglist.list;
2462 oexitstatus = exitstatus;
2463 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2464 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2465 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2466 if (casematch(patp, arglist.list->text)) {
2467 if (evalskip == 0) {
2468 evaltree(cp->nclist.body, flags);
2469 }
2470 goto out;
2471 }
2472 }
2473 }
2474out:
2475 popstackmark(&smark);
2476}
2477
Eric Andersencb57d552001-06-28 07:25:16 +00002478/*
Eric Andersencb57d552001-06-28 07:25:16 +00002479 * Evaluate a pipeline. All the processes in the pipeline are children
2480 * of the process creating the pipeline. (This differs from some versions
2481 * of the shell, which make the last process in a pipeline the parent
2482 * of all the rest.)
2483 */
2484
Eric Andersen74400cc2001-10-18 04:11:39 +00002485static inline void evalpipe(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00002486{
2487 struct job *jp;
2488 struct nodelist *lp;
2489 int pipelen;
2490 int prevfd;
2491 int pip[2];
2492
2493 TRACE(("evalpipe(0x%lx) called\n", (long)n));
2494 pipelen = 0;
2495 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
2496 pipelen++;
2497 INTOFF;
2498 jp = makejob(n, pipelen);
2499 prevfd = -1;
2500 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
2501 prehash(lp->n);
2502 pip[1] = -1;
2503 if (lp->next) {
2504 if (pipe(pip) < 0) {
2505 close(prevfd);
2506 error("Pipe call failed");
2507 }
2508 }
2509 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
2510 INTON;
2511 if (prevfd > 0) {
2512 close(0);
2513 dup_as_newfd(prevfd, 0);
2514 close(prevfd);
2515 if (pip[0] == 0) {
2516 pip[0] = -1;
2517 }
2518 }
2519 if (pip[1] >= 0) {
2520 if (pip[0] >= 0) {
2521 close(pip[0]);
2522 }
2523 if (pip[1] != 1) {
2524 close(1);
2525 dup_as_newfd(pip[1], 1);
2526 close(pip[1]);
2527 }
2528 }
2529 evaltree(lp->n, EV_EXIT);
2530 }
2531 if (prevfd >= 0)
2532 close(prevfd);
2533 prevfd = pip[0];
2534 close(pip[1]);
2535 }
2536 INTON;
2537 if (n->npipe.backgnd == 0) {
2538 INTOFF;
2539 exitstatus = waitforjob(jp);
2540 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
2541 INTON;
2542 }
2543}
2544
Eric Andersen2870d962001-07-02 17:27:21 +00002545static void find_command (const char *, struct cmdentry *, int, const char *);
2546
2547static int
2548isassignment(const char *word) {
2549 if (!is_name(*word)) {
2550 return 0;
2551 }
2552 do {
2553 word++;
2554 } while (is_in_name(*word));
2555 return *word == '=';
2556}
2557
Eric Andersen62483552001-07-10 06:09:16 +00002558
Eric Andersencb57d552001-06-28 07:25:16 +00002559static void
Eric Andersen3102ac42001-07-06 04:26:23 +00002560evalcommand(union node *cmd, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002561{
2562 struct stackmark smark;
2563 union node *argp;
2564 struct arglist arglist;
2565 struct arglist varlist;
2566 char **argv;
2567 int argc;
2568 char **envp;
2569 struct strlist *sp;
2570 int mode;
Eric Andersencb57d552001-06-28 07:25:16 +00002571 struct cmdentry cmdentry;
2572 struct job *jp;
2573 char *volatile savecmdname;
2574 volatile struct shparam saveparam;
2575 struct localvar *volatile savelocalvars;
2576 volatile int e;
2577 char *lastarg;
2578 const char *path;
2579 const struct builtincmd *firstbltin;
2580 struct jmploc *volatile savehandler;
2581 struct jmploc jmploc;
2582#if __GNUC__
2583 /* Avoid longjmp clobbering */
2584 (void) &argv;
2585 (void) &argc;
2586 (void) &lastarg;
2587 (void) &flags;
2588#endif
2589
2590 /* First expand the arguments. */
2591 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
2592 setstackmark(&smark);
2593 arglist.lastp = &arglist.list;
2594 varlist.lastp = &varlist.list;
2595 arglist.list = 0;
2596 oexitstatus = exitstatus;
2597 exitstatus = 0;
2598 path = pathval();
2599 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
2600 expandarg(argp, &varlist, EXP_VARTILDE);
2601 }
2602 for (
2603 argp = cmd->ncmd.args; argp && !arglist.list;
2604 argp = argp->narg.next
2605 ) {
2606 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2607 }
2608 if (argp) {
2609 struct builtincmd *bcmd;
Eric Andersen62483552001-07-10 06:09:16 +00002610 int pseudovarflag;
Eric Andersencb57d552001-06-28 07:25:16 +00002611 bcmd = find_builtin(arglist.list->text);
Eric Andersen2870d962001-07-02 17:27:21 +00002612 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00002613 for (; argp; argp = argp->narg.next) {
2614 if (pseudovarflag && isassignment(argp->narg.text)) {
2615 expandarg(argp, &arglist, EXP_VARTILDE);
2616 continue;
2617 }
2618 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2619 }
2620 }
2621 *arglist.lastp = NULL;
2622 *varlist.lastp = NULL;
2623 expredir(cmd->ncmd.redirect);
2624 argc = 0;
2625 for (sp = arglist.list ; sp ; sp = sp->next)
2626 argc++;
2627 argv = stalloc(sizeof (char *) * (argc + 1));
2628
2629 for (sp = arglist.list ; sp ; sp = sp->next) {
2630 TRACE(("evalcommand arg: %s\n", sp->text));
2631 *argv++ = sp->text;
2632 }
2633 *argv = NULL;
2634 lastarg = NULL;
2635 if (iflag && funcnest == 0 && argc > 0)
2636 lastarg = argv[-1];
2637 argv -= argc;
2638
2639 /* Print the command if xflag is set. */
2640 if (xflag) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002641 out2c('+');
Eric Andersencb57d552001-06-28 07:25:16 +00002642 eprintlist(varlist.list);
2643 eprintlist(arglist.list);
Eric Andersen3102ac42001-07-06 04:26:23 +00002644 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00002645 }
2646
2647 /* Now locate the command. */
2648 if (argc == 0) {
2649 cmdentry.cmdtype = CMDBUILTIN;
2650 firstbltin = cmdentry.u.cmd = BLTINCMD;
2651 } else {
2652 const char *oldpath;
2653 int findflag = DO_ERR;
2654 int oldfindflag;
2655
2656 /*
2657 * Modify the command lookup path, if a PATH= assignment
2658 * is present
2659 */
2660 for (sp = varlist.list ; sp ; sp = sp->next)
2661 if (varequal(sp->text, defpathvar)) {
2662 path = sp->text + 5;
2663 findflag |= DO_BRUTE;
2664 }
2665 oldpath = path;
2666 oldfindflag = findflag;
2667 firstbltin = 0;
2668 for(;;) {
2669 find_command(argv[0], &cmdentry, findflag, path);
Eric Andersen2870d962001-07-02 17:27:21 +00002670 if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */
Eric Andersencb57d552001-06-28 07:25:16 +00002671 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002672 goto out;
2673 }
2674 /* implement bltin and command here */
2675 if (cmdentry.cmdtype != CMDBUILTIN) {
2676 break;
2677 }
2678 if (!firstbltin) {
2679 firstbltin = cmdentry.u.cmd;
2680 }
2681 if (cmdentry.u.cmd == BLTINCMD) {
2682 for(;;) {
2683 struct builtincmd *bcmd;
2684
2685 argv++;
2686 if (--argc == 0)
2687 goto found;
2688 if (!(bcmd = find_builtin(*argv))) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002689 out2fmt("%s: not found\n", *argv);
Eric Andersencb57d552001-06-28 07:25:16 +00002690 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002691 goto out;
2692 }
2693 cmdentry.u.cmd = bcmd;
2694 if (bcmd != BLTINCMD)
2695 break;
2696 }
2697 }
Eric Andersen2870d962001-07-02 17:27:21 +00002698 if (cmdentry.u.cmd == find_builtin("command")) {
Eric Andersencb57d552001-06-28 07:25:16 +00002699 argv++;
2700 if (--argc == 0) {
2701 goto found;
2702 }
2703 if (*argv[0] == '-') {
2704 if (!equal(argv[0], "-p")) {
2705 argv--;
2706 argc++;
2707 break;
2708 }
2709 argv++;
2710 if (--argc == 0) {
2711 goto found;
2712 }
2713 path = defpath;
2714 findflag |= DO_BRUTE;
2715 } else {
2716 path = oldpath;
2717 findflag = oldfindflag;
2718 }
2719 findflag |= DO_NOFUN;
2720 continue;
2721 }
2722found:
2723 break;
2724 }
2725 }
2726
2727 /* Fork off a child process if necessary. */
2728 if (cmd->ncmd.backgnd
2729 || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00002730 ) {
2731 jp = makejob(cmd, 1);
2732 mode = cmd->ncmd.backgnd;
Eric Andersencb57d552001-06-28 07:25:16 +00002733 if (forkshell(jp, cmd, mode) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00002734 goto parent; /* at end of routine */
Eric Andersencb57d552001-06-28 07:25:16 +00002735 flags |= EV_EXIT;
2736 }
2737
2738 /* This is the child process if a fork occurred. */
2739 /* Execute the command. */
2740 if (cmdentry.cmdtype == CMDFUNCTION) {
2741#ifdef DEBUG
2742 trputs("Shell function: "); trargs(argv);
2743#endif
2744 exitstatus = oexitstatus;
2745 redirect(cmd->ncmd.redirect, REDIR_PUSH);
2746 saveparam = shellparam;
2747 shellparam.malloc = 0;
2748 shellparam.nparam = argc - 1;
2749 shellparam.p = argv + 1;
2750 INTOFF;
2751 savelocalvars = localvars;
2752 localvars = NULL;
2753 INTON;
2754 if (setjmp(jmploc.loc)) {
2755 if (exception == EXSHELLPROC) {
2756 freeparam((volatile struct shparam *)
2757 &saveparam);
2758 } else {
2759 saveparam.optind = shellparam.optind;
2760 saveparam.optoff = shellparam.optoff;
2761 freeparam(&shellparam);
2762 shellparam = saveparam;
2763 }
2764 poplocalvars();
2765 localvars = savelocalvars;
2766 handler = savehandler;
2767 longjmp(handler->loc, 1);
2768 }
2769 savehandler = handler;
2770 handler = &jmploc;
2771 for (sp = varlist.list ; sp ; sp = sp->next)
2772 mklocal(sp->text);
2773 funcnest++;
2774 evaltree(cmdentry.u.func, flags & EV_TESTED);
2775 funcnest--;
2776 INTOFF;
2777 poplocalvars();
2778 localvars = savelocalvars;
2779 saveparam.optind = shellparam.optind;
2780 saveparam.optoff = shellparam.optoff;
2781 freeparam(&shellparam);
2782 shellparam = saveparam;
2783 handler = savehandler;
2784 popredir();
2785 INTON;
2786 if (evalskip == SKIPFUNC) {
2787 evalskip = 0;
2788 skipcount = 0;
2789 }
2790 if (flags & EV_EXIT)
2791 exitshell(exitstatus);
2792 } else if (cmdentry.cmdtype == CMDBUILTIN) {
2793#ifdef DEBUG
2794 trputs("builtin command: "); trargs(argv);
2795#endif
2796 mode = (cmdentry.u.cmd == EXECCMD)? 0 : REDIR_PUSH;
Eric Andersencb57d552001-06-28 07:25:16 +00002797 redirect(cmd->ncmd.redirect, mode);
2798 savecmdname = commandname;
Eric Andersen2870d962001-07-02 17:27:21 +00002799 if (IS_BUILTIN_SPECIAL(firstbltin)) {
Eric Andersencb57d552001-06-28 07:25:16 +00002800 listsetvar(varlist.list);
2801 } else {
2802 cmdenviron = varlist.list;
2803 }
2804 e = -1;
2805 if (setjmp(jmploc.loc)) {
2806 e = exception;
2807 exitstatus = (e == EXINT)? SIGINT+128 : 2;
2808 goto cmddone;
2809 }
2810 savehandler = handler;
2811 handler = &jmploc;
2812 commandname = argv[0];
2813 argptr = argv + 1;
Eric Andersen2870d962001-07-02 17:27:21 +00002814 optptr = NULL; /* initialize nextopt */
Eric Andersencb57d552001-06-28 07:25:16 +00002815 exitstatus = (*cmdentry.u.cmd->builtinfunc)(argc, argv);
2816 flushall();
2817cmddone:
Eric Andersencb57d552001-06-28 07:25:16 +00002818 cmdenviron = NULL;
2819 if (e != EXSHELLPROC) {
2820 commandname = savecmdname;
2821 if (flags & EV_EXIT)
2822 exitshell(exitstatus);
2823 }
2824 handler = savehandler;
2825 if (e != -1) {
2826 if ((e != EXERROR && e != EXEXEC)
2827 || cmdentry.u.cmd == BLTINCMD
2828 || cmdentry.u.cmd == DOTCMD
2829 || cmdentry.u.cmd == EVALCMD
2830 || cmdentry.u.cmd == EXECCMD)
2831 exraise(e);
2832 FORCEINTON;
2833 }
2834 if (cmdentry.u.cmd != EXECCMD)
2835 popredir();
Eric Andersencb57d552001-06-28 07:25:16 +00002836 } else {
2837#ifdef DEBUG
2838 trputs("normal command: "); trargs(argv);
2839#endif
2840 redirect(cmd->ncmd.redirect, 0);
2841 clearredir();
2842 for (sp = varlist.list ; sp ; sp = sp->next)
2843 setvareq(sp->text, VEXPORT|VSTACK);
2844 envp = environment();
2845 shellexec(argv, envp, path, cmdentry.u.index);
2846 }
2847 goto out;
2848
Eric Andersen2870d962001-07-02 17:27:21 +00002849parent: /* parent process gets here (if we forked) */
2850 if (mode == 0) { /* argument to fork */
Eric Andersencb57d552001-06-28 07:25:16 +00002851 INTOFF;
2852 exitstatus = waitforjob(jp);
2853 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00002854 }
2855
2856out:
2857 if (lastarg)
2858 setvar("_", lastarg, 0);
2859 popstackmark(&smark);
2860}
2861
Eric Andersen62483552001-07-10 06:09:16 +00002862/*
2863 * Evaluate a parse tree. The value is left in the global variable
2864 * exitstatus.
2865 */
2866static void
2867evaltree(n, flags)
2868 union node *n;
2869 int flags;
2870{
2871 int checkexit = 0;
2872 if (n == NULL) {
2873 TRACE(("evaltree(NULL) called\n"));
2874 goto out;
2875 }
2876 TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
2877 switch (n->type) {
2878 case NSEMI:
2879 evaltree(n->nbinary.ch1, flags & EV_TESTED);
2880 if (evalskip)
2881 goto out;
2882 evaltree(n->nbinary.ch2, flags);
2883 break;
2884 case NAND:
2885 evaltree(n->nbinary.ch1, EV_TESTED);
2886 if (evalskip || exitstatus != 0)
2887 goto out;
2888 evaltree(n->nbinary.ch2, flags);
2889 break;
2890 case NOR:
2891 evaltree(n->nbinary.ch1, EV_TESTED);
2892 if (evalskip || exitstatus == 0)
2893 goto out;
2894 evaltree(n->nbinary.ch2, flags);
2895 break;
2896 case NREDIR:
2897 expredir(n->nredir.redirect);
2898 redirect(n->nredir.redirect, REDIR_PUSH);
2899 evaltree(n->nredir.n, flags);
2900 popredir();
2901 break;
2902 case NSUBSHELL:
2903 evalsubshell(n, flags);
2904 break;
2905 case NBACKGND:
2906 evalsubshell(n, flags);
2907 break;
2908 case NIF: {
2909 evaltree(n->nif.test, EV_TESTED);
2910 if (evalskip)
2911 goto out;
2912 if (exitstatus == 0)
2913 evaltree(n->nif.ifpart, flags);
2914 else if (n->nif.elsepart)
2915 evaltree(n->nif.elsepart, flags);
2916 else
2917 exitstatus = 0;
2918 break;
2919 }
2920 case NWHILE:
2921 case NUNTIL:
2922 evalloop(n, flags);
2923 break;
2924 case NFOR:
2925 evalfor(n, flags);
2926 break;
2927 case NCASE:
2928 evalcase(n, flags);
2929 break;
2930 case NDEFUN: {
2931 struct builtincmd *bcmd;
2932 struct cmdentry entry;
2933 if (
2934 (bcmd = find_builtin(n->narg.text)) &&
2935 IS_BUILTIN_SPECIAL(bcmd)
2936 ) {
2937 out2fmt("%s is a special built-in\n", n->narg.text);
2938 exitstatus = 1;
2939 break;
2940 }
2941 entry.cmdtype = CMDFUNCTION;
2942 entry.u.func = copyfunc(n->narg.next);
2943 addcmdentry(n->narg.text, &entry);
2944 exitstatus = 0;
2945 break;
2946 }
2947 case NNOT:
2948 evaltree(n->nnot.com, EV_TESTED);
2949 exitstatus = !exitstatus;
2950 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002951
Eric Andersen62483552001-07-10 06:09:16 +00002952 case NPIPE:
2953 evalpipe(n);
2954 checkexit = 1;
2955 break;
2956 case NCMD:
2957 evalcommand(n, flags);
2958 checkexit = 1;
2959 break;
2960#ifdef DEBUG
2961 default:
2962 printf("Node type = %d\n", n->type);
2963 break;
2964#endif
2965 }
2966out:
2967 if (pendingsigs)
2968 dotrap();
2969 if (
2970 flags & EV_EXIT ||
2971 (checkexit && eflag && exitstatus && !(flags & EV_TESTED))
2972 )
2973 exitshell(exitstatus);
2974}
2975
2976/*
2977 * Kick off a subshell to evaluate a tree.
2978 */
2979
2980static void
2981evalsubshell(const union node *n, int flags)
2982{
2983 struct job *jp;
2984 int backgnd = (n->type == NBACKGND);
2985
2986 expredir(n->nredir.redirect);
2987 jp = makejob(n, 1);
2988 if (forkshell(jp, n, backgnd) == 0) {
2989 if (backgnd)
2990 flags &=~ EV_TESTED;
2991 redirect(n->nredir.redirect, 0);
2992 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
2993 }
2994 if (! backgnd) {
2995 INTOFF;
2996 exitstatus = waitforjob(jp);
2997 INTON;
2998 }
2999}
3000
3001/*
3002 * Compute the names of the files in a redirection list.
3003 */
3004
3005static void fixredir(union node *n, const char *text, int err);
3006
3007static void
3008expredir(union node *n)
3009{
3010 union node *redir;
3011
3012 for (redir = n ; redir ; redir = redir->nfile.next) {
3013 struct arglist fn;
3014 fn.lastp = &fn.list;
3015 oexitstatus = exitstatus;
3016 switch (redir->type) {
3017 case NFROMTO:
3018 case NFROM:
3019 case NTO:
3020 case NAPPEND:
3021 case NTOOV:
3022 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3023 redir->nfile.expfname = fn.list->text;
3024 break;
3025 case NFROMFD:
3026 case NTOFD:
3027 if (redir->ndup.vname) {
3028 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3029 fixredir(redir, fn.list->text, 1);
3030 }
3031 break;
3032 }
3033 }
3034}
3035
3036
3037/*
3038 * Execute a command inside back quotes. If it's a builtin command, we
3039 * want to save its output in a block obtained from malloc. Otherwise
3040 * we fork off a subprocess and get the output of the command via a pipe.
3041 * Should be called with interrupts off.
3042 */
3043
3044static void
3045evalbackcmd(union node *n, struct backcmd *result)
3046{
3047 int pip[2];
3048 struct job *jp;
3049 struct stackmark smark; /* unnecessary */
3050
3051 setstackmark(&smark);
3052 result->fd = -1;
3053 result->buf = NULL;
3054 result->nleft = 0;
3055 result->jp = NULL;
3056 if (n == NULL) {
3057 exitstatus = 0;
3058 goto out;
3059 }
3060 exitstatus = 0;
3061 if (pipe(pip) < 0)
3062 error("Pipe call failed");
3063 jp = makejob(n, 1);
3064 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3065 FORCEINTON;
3066 close(pip[0]);
3067 if (pip[1] != 1) {
3068 close(1);
3069 dup_as_newfd(pip[1], 1);
3070 close(pip[1]);
3071 }
3072 eflag = 0;
3073 evaltree(n, EV_EXIT);
3074 }
3075 close(pip[1]);
3076 result->fd = pip[0];
3077 result->jp = jp;
3078out:
3079 popstackmark(&smark);
3080 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
3081 result->fd, result->buf, result->nleft, result->jp));
3082}
3083
3084
3085/*
3086 * Execute a simple command.
3087 */
Eric Andersencb57d552001-06-28 07:25:16 +00003088
3089/*
3090 * Search for a command. This is called before we fork so that the
3091 * location of the command will be available in the parent as well as
3092 * the child. The check for "goodname" is an overly conservative
3093 * check that the name will not be subject to expansion.
3094 */
3095
3096static void
3097prehash(n)
3098 union node *n;
3099{
3100 struct cmdentry entry;
3101
3102 if (n->type == NCMD && n->ncmd.args)
3103 if (goodname(n->ncmd.args->narg.text))
3104 find_command(n->ncmd.args->narg.text, &entry, 0,
3105 pathval());
3106}
3107
3108
Eric Andersencb57d552001-06-28 07:25:16 +00003109/*
3110 * Builtin commands. Builtin commands whose functions are closely
3111 * tied to evaluation are implemented here.
3112 */
3113
3114/*
3115 * No command given, or a bltin command with no arguments. Set the
3116 * specified variables.
3117 */
3118
3119int
3120bltincmd(argc, argv)
3121 int argc;
3122 char **argv;
3123{
3124 /*
3125 * Preserve exitstatus of a previous possible redirection
3126 * as POSIX mandates
3127 */
3128 return exitstatus;
3129}
3130
3131
3132/*
3133 * Handle break and continue commands. Break, continue, and return are
3134 * all handled by setting the evalskip flag. The evaluation routines
3135 * above all check this flag, and if it is set they start skipping
3136 * commands rather than executing them. The variable skipcount is
3137 * the number of loops to break/continue, or the number of function
3138 * levels to return. (The latter is always 1.) It should probably
3139 * be an error to break out of more loops than exist, but it isn't
3140 * in the standard shell so we don't make it one here.
3141 */
3142
3143static int
3144breakcmd(argc, argv)
3145 int argc;
3146 char **argv;
3147{
3148 int n = argc > 1 ? number(argv[1]) : 1;
3149
3150 if (n > loopnest)
3151 n = loopnest;
3152 if (n > 0) {
3153 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
3154 skipcount = n;
3155 }
3156 return 0;
3157}
3158
3159
3160/*
3161 * The return command.
3162 */
3163
3164static int
3165returncmd(argc, argv)
3166 int argc;
3167 char **argv;
3168{
3169 int ret = argc > 1 ? number(argv[1]) : oexitstatus;
3170
3171 if (funcnest) {
3172 evalskip = SKIPFUNC;
3173 skipcount = 1;
3174 return ret;
3175 }
3176 else {
3177 /* Do what ksh does; skip the rest of the file */
3178 evalskip = SKIPFILE;
3179 skipcount = 1;
3180 return ret;
3181 }
3182}
3183
3184
3185#ifndef BB_TRUE_FALSE
3186static int
3187false_main(argc, argv)
3188 int argc;
3189 char **argv;
3190{
3191 return 1;
3192}
3193
3194
3195static int
3196true_main(argc, argv)
3197 int argc;
3198 char **argv;
3199{
3200 return 0;
3201}
3202#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003203
3204/*
3205 * Controls whether the shell is interactive or not.
3206 */
3207
3208static void setsignal(int signo);
3209static void chkmail(int silent);
3210
3211
3212static void
3213setinteractive(int on)
3214{
3215 static int is_interactive;
Eric Andersen1c039232001-07-07 00:05:55 +00003216 static int do_banner=0;
Eric Andersen2870d962001-07-02 17:27:21 +00003217
3218 if (on == is_interactive)
3219 return;
3220 setsignal(SIGINT);
3221 setsignal(SIGQUIT);
3222 setsignal(SIGTERM);
3223 chkmail(1);
3224 is_interactive = on;
Eric Andersen1c039232001-07-07 00:05:55 +00003225 if (do_banner==0 && is_interactive) {
3226 /* Looks like they want an interactive shell */
Eric Andersend63dee42001-10-19 00:22:23 +00003227#ifndef BB_FEATURE_SH_EXTRA_QUIET
Eric Andersen1c039232001-07-07 00:05:55 +00003228 printf( "\n\n" BB_BANNER " Built-in shell (ash)\n");
3229 printf( "Enter 'help' for a list of built-in commands.\n\n");
Eric Andersend63dee42001-10-19 00:22:23 +00003230#endif
Eric Andersen1c039232001-07-07 00:05:55 +00003231 do_banner=1;
3232 }
Eric Andersen2870d962001-07-02 17:27:21 +00003233}
3234
3235static void
3236optschanged(void)
3237{
3238 setinteractive(iflag);
3239 setjobctl(mflag);
3240}
3241
Eric Andersencb57d552001-06-28 07:25:16 +00003242
3243static int
3244execcmd(argc, argv)
3245 int argc;
3246 char **argv;
3247{
3248 if (argc > 1) {
3249 struct strlist *sp;
3250
Eric Andersen2870d962001-07-02 17:27:21 +00003251 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003252 mflag = 0;
3253 optschanged();
3254 for (sp = cmdenviron; sp ; sp = sp->next)
3255 setvareq(sp->text, VEXPORT|VSTACK);
3256 shellexec(argv + 1, environment(), pathval(), 0);
3257 }
3258 return 0;
3259}
3260
3261static void
3262eprintlist(struct strlist *sp)
3263{
3264 for (; sp; sp = sp->next) {
Eric Andersen3102ac42001-07-06 04:26:23 +00003265 out2fmt(" %s",sp->text);
Eric Andersencb57d552001-06-28 07:25:16 +00003266 }
3267}
Eric Andersencb57d552001-06-28 07:25:16 +00003268
3269/*
3270 * Exec a program. Never returns. If you change this routine, you may
3271 * have to change the find_command routine as well.
3272 */
3273
Eric Andersen2870d962001-07-02 17:27:21 +00003274static const char *pathopt; /* set by padvance */
3275
Eric Andersencb57d552001-06-28 07:25:16 +00003276static void
3277shellexec(argv, envp, path, idx)
3278 char **argv, **envp;
3279 const char *path;
3280 int idx;
3281{
3282 char *cmdname;
3283 int e;
3284
3285 if (strchr(argv[0], '/') != NULL) {
3286 tryexec(argv[0], argv, envp);
3287 e = errno;
3288 } else {
3289 e = ENOENT;
3290 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3291 if (--idx < 0 && pathopt == NULL) {
3292 tryexec(cmdname, argv, envp);
3293 if (errno != ENOENT && errno != ENOTDIR)
3294 e = errno;
3295 }
3296 stunalloc(cmdname);
3297 }
3298 }
3299
3300 /* Map to POSIX errors */
3301 switch (e) {
3302 case EACCES:
3303 exerrno = 126;
3304 break;
3305 case ENOENT:
3306 exerrno = 127;
3307 break;
3308 default:
3309 exerrno = 2;
3310 break;
3311 }
3312 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3313 /* NOTREACHED */
3314}
3315
Eric Andersen2870d962001-07-02 17:27:21 +00003316/*
3317 * Clear traps on a fork.
3318 */
3319static void
3320clear_traps(void) {
3321 char **tp;
3322
3323 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
3324 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
3325 INTOFF;
3326 ckfree(*tp);
3327 *tp = NULL;
3328 if (tp != &trap[0])
3329 setsignal(tp - trap);
3330 INTON;
3331 }
3332 }
3333}
3334
3335
3336static void
3337initshellproc(void) {
3338
3339#ifdef ASH_ALIAS
3340 /* from alias.c: */
3341 {
3342 rmaliases();
3343 }
3344#endif
3345 /* from eval.c: */
3346 {
3347 exitstatus = 0;
3348 }
3349
3350 /* from exec.c: */
3351 {
3352 deletefuncs();
3353 }
3354
3355 /* from jobs.c: */
3356 {
3357 backgndpid = -1;
3358#ifdef JOBS
3359 jobctl = 0;
3360#endif
3361 }
3362
3363 /* from options.c: */
3364 {
3365 int i;
3366
3367 for (i = 0; i < NOPTS; i++)
3368 optent_val(i) = 0;
3369 optschanged();
3370
3371 }
3372
3373 /* from redir.c: */
3374 {
3375 clearredir();
3376 }
3377
3378 /* from trap.c: */
3379 {
3380 char *sm;
3381
3382 clear_traps();
3383 for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) {
3384 if (*sm == S_IGN)
3385 *sm = S_HARD_IGN;
3386 }
3387 }
3388
3389 /* from var.c: */
3390 {
3391 shprocvar();
3392 }
3393}
3394
3395static int preadbuffer(void);
3396static void pushfile (void);
Eric Andersen2870d962001-07-02 17:27:21 +00003397
3398/*
3399 * Read a character from the script, returning PEOF on end of file.
3400 * Nul characters in the input are silently discarded.
3401 */
3402
Eric Andersen3102ac42001-07-06 04:26:23 +00003403#ifndef ASH_OPTIMIZE_FOR_SIZE
Eric Andersen2870d962001-07-02 17:27:21 +00003404#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
3405static int
3406pgetc(void)
3407{
3408 return pgetc_macro();
3409}
3410#else
3411static int
3412pgetc_macro(void)
3413{
3414 return --parsenleft >= 0? *parsenextc++ : preadbuffer();
3415}
3416
3417static inline int
3418pgetc(void)
3419{
3420 return pgetc_macro();
3421}
3422#endif
3423
3424
3425/*
3426 * Undo the last call to pgetc. Only one character may be pushed back.
3427 * PEOF may be pushed back.
3428 */
3429
Eric Andersen74400cc2001-10-18 04:11:39 +00003430static void pungetc(void)
3431{
Eric Andersen2870d962001-07-02 17:27:21 +00003432 parsenleft++;
3433 parsenextc--;
3434}
3435
3436
3437static void
3438popfile(void) {
3439 struct parsefile *pf = parsefile;
3440
3441 INTOFF;
3442 if (pf->fd >= 0)
3443 close(pf->fd);
3444 if (pf->buf)
3445 ckfree(pf->buf);
3446 while (pf->strpush)
3447 popstring();
3448 parsefile = pf->prev;
3449 ckfree(pf);
3450 parsenleft = parsefile->nleft;
3451 parselleft = parsefile->lleft;
3452 parsenextc = parsefile->nextc;
3453 plinno = parsefile->linno;
3454 INTON;
3455}
3456
3457
3458/*
3459 * Return to top level.
3460 */
3461
3462static void
3463popallfiles(void) {
3464 while (parsefile != &basepf)
3465 popfile();
3466}
3467
3468/*
3469 * Close the file(s) that the shell is reading commands from. Called
3470 * after a fork is done.
3471 */
3472
Eric Andersen74400cc2001-10-18 04:11:39 +00003473static void closescript(void)
3474{
Eric Andersen2870d962001-07-02 17:27:21 +00003475 popallfiles();
3476 if (parsefile->fd > 0) {
3477 close(parsefile->fd);
3478 parsefile->fd = 0;
3479 }
3480}
3481
3482
3483/*
3484 * Like setinputfile, but takes an open file descriptor. Call this with
3485 * interrupts off.
3486 */
3487
Eric Andersen74400cc2001-10-18 04:11:39 +00003488static void setinputfd(int fd, int push)
Eric Andersen2870d962001-07-02 17:27:21 +00003489{
3490 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
3491 if (push) {
3492 pushfile();
3493 parsefile->buf = 0;
3494 } else {
3495 closescript();
3496 while (parsefile->strpush)
3497 popstring();
3498 }
3499 parsefile->fd = fd;
3500 if (parsefile->buf == NULL)
3501 parsefile->buf = ckmalloc(BUFSIZ);
3502 parselleft = parsenleft = 0;
3503 plinno = 1;
3504}
3505
3506
3507/*
3508 * Set the input to take input from a file. If push is set, push the
3509 * old input onto the stack first.
3510 */
3511
3512static void
3513setinputfile(const char *fname, int push)
3514{
3515 int fd;
3516 int myfileno2;
3517
3518 INTOFF;
3519 if ((fd = open(fname, O_RDONLY)) < 0)
3520 error("Can't open %s", fname);
3521 if (fd < 10) {
3522 myfileno2 = dup_as_newfd(fd, 10);
3523 close(fd);
3524 if (myfileno2 < 0)
3525 error("Out of file descriptors");
3526 fd = myfileno2;
3527 }
3528 setinputfd(fd, push);
3529 INTON;
3530}
3531
Eric Andersencb57d552001-06-28 07:25:16 +00003532
3533static void
Eric Andersen62483552001-07-10 06:09:16 +00003534tryexec(char *cmd, char **argv, char **envp)
3535{
Eric Andersencb57d552001-06-28 07:25:16 +00003536 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003537
Eric Andersen3102ac42001-07-06 04:26:23 +00003538#ifdef BB_FEATURE_SH_STANDALONE_SHELL
3539 char *name = cmd;
3540 char** argv_l=argv;
3541 int argc_l;
3542#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
3543 name = get_last_path_component(name);
3544#endif
3545 argv_l=envp;
3546 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
3547 putenv(*argv_l);
3548 argv_l=argv;
Eric Andersen62483552001-07-10 06:09:16 +00003549 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
Eric Andersen3102ac42001-07-06 04:26:23 +00003550 optind = 1;
3551 run_applet_by_name(name, argc_l, argv);
3552#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003553 execve(cmd, argv, envp);
Eric Andersencb57d552001-06-28 07:25:16 +00003554 e = errno;
3555 if (e == ENOEXEC) {
3556 INTOFF;
3557 initshellproc();
3558 setinputfile(cmd, 0);
3559 commandname = arg0 = savestr(argv[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00003560 setparam(argv + 1);
3561 exraise(EXSHELLPROC);
3562 }
3563 errno = e;
3564}
3565
Eric Andersen2870d962001-07-02 17:27:21 +00003566static char *commandtext (const union node *);
Eric Andersencb57d552001-06-28 07:25:16 +00003567
3568/*
3569 * Do a path search. The variable path (passed by reference) should be
3570 * set to the start of the path before the first call; padvance will update
3571 * this value as it proceeds. Successive calls to padvance will return
3572 * the possible path expansions in sequence. If an option (indicated by
3573 * a percent sign) appears in the path entry then the global variable
3574 * pathopt will be set to point to it; otherwise pathopt will be set to
3575 * NULL.
3576 */
3577
3578static const char *pathopt;
3579
Eric Andersen2870d962001-07-02 17:27:21 +00003580static void growstackblock(void);
3581
3582
Eric Andersencb57d552001-06-28 07:25:16 +00003583static char *
Eric Andersen2870d962001-07-02 17:27:21 +00003584padvance(const char **path, const char *name)
3585{
Eric Andersencb57d552001-06-28 07:25:16 +00003586 const char *p;
3587 char *q;
3588 const char *start;
3589 int len;
3590
3591 if (*path == NULL)
3592 return NULL;
3593 start = *path;
3594 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
Eric Andersen2870d962001-07-02 17:27:21 +00003595 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003596 while (stackblocksize() < len)
3597 growstackblock();
3598 q = stackblock();
3599 if (p != start) {
3600 memcpy(q, start, p - start);
3601 q += p - start;
3602 *q++ = '/';
3603 }
3604 strcpy(q, name);
3605 pathopt = NULL;
3606 if (*p == '%') {
3607 pathopt = ++p;
3608 while (*p && *p != ':') p++;
3609 }
3610 if (*p == ':')
3611 *path = p + 1;
3612 else
3613 *path = NULL;
3614 return stalloc(len);
3615}
3616
Eric Andersen62483552001-07-10 06:09:16 +00003617/*
3618 * Wrapper around strcmp for qsort/bsearch/...
3619 */
3620static int
3621pstrcmp(const void *a, const void *b)
3622{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003623 return strcmp((const char *) a, (*(const char *const *) b) + 1);
Eric Andersen62483552001-07-10 06:09:16 +00003624}
3625
3626/*
3627 * Find a keyword is in a sorted array.
3628 */
3629
3630static const char *const *
3631findkwd(const char *s)
3632{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003633 return bsearch(s, tokname_array + KWDOFFSET,
3634 (sizeof(tokname_array)/sizeof(const char *)) - KWDOFFSET,
3635 sizeof(const char *), pstrcmp);
Eric Andersen62483552001-07-10 06:09:16 +00003636}
Eric Andersencb57d552001-06-28 07:25:16 +00003637
3638
3639/*** Command hashing code ***/
3640
3641
3642static int
3643hashcmd(argc, argv)
3644 int argc;
3645 char **argv;
3646{
3647 struct tblentry **pp;
3648 struct tblentry *cmdp;
3649 int c;
3650 int verbose;
3651 struct cmdentry entry;
3652 char *name;
Eric Andersen62483552001-07-10 06:09:16 +00003653#ifdef ASH_ALIAS
3654 const struct alias *ap;
3655#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003656
3657 verbose = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003658 while ((c = nextopt("rvV")) != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00003659 if (c == 'r') {
3660 clearcmdentry(0);
3661 return 0;
Eric Andersen62483552001-07-10 06:09:16 +00003662 } else if (c == 'v' || c == 'V') {
3663 verbose = c;
Eric Andersencb57d552001-06-28 07:25:16 +00003664 }
3665 }
3666 if (*argptr == NULL) {
3667 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3668 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3669 if (cmdp->cmdtype != CMDBUILTIN) {
3670 printentry(cmdp, verbose);
3671 }
3672 }
3673 }
3674 return 0;
3675 }
3676 c = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003677 while ((name = *argptr++) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00003678 if ((cmdp = cmdlookup(name, 0)) != NULL
3679 && (cmdp->cmdtype == CMDNORMAL
3680 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3681 delete_cmd_entry();
Eric Andersen62483552001-07-10 06:09:16 +00003682#ifdef ASH_ALIAS
3683 /* Then look at the aliases */
3684 if ((ap = lookupalias(name, 0)) != NULL) {
3685 if (verbose=='v')
3686 printf("%s is an alias for %s\n", name, ap->val);
3687 else
3688 printalias(ap);
3689 continue;
3690 }
3691#endif
3692 /* First look at the keywords */
3693 if (findkwd(name)!=0) {
3694 if (verbose=='v')
3695 printf("%s is a shell keyword\n", name);
3696 else
3697 printf(snlfmt, name);
3698 continue;
3699 }
3700
Eric Andersencb57d552001-06-28 07:25:16 +00003701 find_command(name, &entry, DO_ERR, pathval());
3702 if (entry.cmdtype == CMDUNKNOWN) c = 1;
3703 else if (verbose) {
3704 cmdp = cmdlookup(name, 0);
Eric Andersen62483552001-07-10 06:09:16 +00003705 if (cmdp) printentry(cmdp, verbose=='v');
Eric Andersencb57d552001-06-28 07:25:16 +00003706 flushall();
3707 }
Eric Andersencb57d552001-06-28 07:25:16 +00003708 }
3709 return c;
3710}
3711
Eric Andersencb57d552001-06-28 07:25:16 +00003712static void
3713printentry(cmdp, verbose)
3714 struct tblentry *cmdp;
3715 int verbose;
3716 {
3717 int idx;
3718 const char *path;
3719 char *name;
3720
Eric Andersen62483552001-07-10 06:09:16 +00003721 printf("%s%s", cmdp->cmdname, (verbose ? " is " : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00003722 if (cmdp->cmdtype == CMDNORMAL) {
3723 idx = cmdp->param.index;
3724 path = pathval();
3725 do {
3726 name = padvance(&path, cmdp->cmdname);
3727 stunalloc(name);
3728 } while (--idx >= 0);
Eric Andersen62483552001-07-10 06:09:16 +00003729 if(verbose)
3730 out1str(name);
Eric Andersencb57d552001-06-28 07:25:16 +00003731 } else if (cmdp->cmdtype == CMDBUILTIN) {
Eric Andersen62483552001-07-10 06:09:16 +00003732 if(verbose)
3733 out1str("a shell builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00003734 } else if (cmdp->cmdtype == CMDFUNCTION) {
Eric Andersencb57d552001-06-28 07:25:16 +00003735 if (verbose) {
3736 INTOFF;
Eric Andersen62483552001-07-10 06:09:16 +00003737 out1str("a function\n");
Eric Andersencb57d552001-06-28 07:25:16 +00003738 name = commandtext(cmdp->param.func);
Eric Andersen62483552001-07-10 06:09:16 +00003739 printf("%s() {\n %s\n}", cmdp->cmdname, name);
Eric Andersencb57d552001-06-28 07:25:16 +00003740 ckfree(name);
3741 INTON;
3742 }
3743#ifdef DEBUG
3744 } else {
3745 error("internal error: cmdtype %d", cmdp->cmdtype);
3746#endif
3747 }
Eric Andersen62483552001-07-10 06:09:16 +00003748 printf(snlfmt, cmdp->rehash ? "*" : nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +00003749}
3750
3751
3752
Eric Andersen1c039232001-07-07 00:05:55 +00003753/*** List the available builtins ***/
3754
3755
3756static int helpcmd(int argc, char** argv)
3757{
3758 int col, i;
Eric Andersen1c039232001-07-07 00:05:55 +00003759
Eric Andersen62483552001-07-10 06:09:16 +00003760 printf("\nBuilt-in commands:\n-------------------\n");
3761 for (col=0, i=0; i < NUMBUILTINS; i++) {
3762 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3763 builtincmds[i].name+1);
Eric Andersen1c039232001-07-07 00:05:55 +00003764 if (col > 60) {
3765 printf("\n");
3766 col = 0;
3767 }
3768 }
3769#ifdef BB_FEATURE_SH_STANDALONE_SHELL
3770 {
Eric Andersen1c039232001-07-07 00:05:55 +00003771 extern const struct BB_applet applets[];
3772 extern const size_t NUM_APPLETS;
3773
Eric Andersen62483552001-07-10 06:09:16 +00003774 for (i=0; i < NUM_APPLETS; i++) {
3775
3776 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3777 applets[i].name);
Eric Andersen1c039232001-07-07 00:05:55 +00003778 if (col > 60) {
3779 printf("\n");
3780 col = 0;
3781 }
3782 }
3783 }
3784#endif
3785 printf("\n\n");
3786 return EXIT_SUCCESS;
3787}
3788
Eric Andersencb57d552001-06-28 07:25:16 +00003789/*
3790 * Resolve a command name. If you change this routine, you may have to
3791 * change the shellexec routine as well.
3792 */
3793
Eric Andersen2870d962001-07-02 17:27:21 +00003794static int prefix (const char *, const char *);
3795
Eric Andersencb57d552001-06-28 07:25:16 +00003796static void
Eric Andersen2870d962001-07-02 17:27:21 +00003797find_command(const char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003798{
3799 struct tblentry *cmdp;
3800 int idx;
3801 int prev;
3802 char *fullname;
3803 struct stat statb;
3804 int e;
3805 int bltin;
3806 int firstchange;
3807 int updatetbl;
Eric Andersen62483552001-07-10 06:09:16 +00003808 int regular;
Eric Andersencb57d552001-06-28 07:25:16 +00003809 struct builtincmd *bcmd;
3810
3811 /* If name contains a slash, don't use the hash table */
3812 if (strchr(name, '/') != NULL) {
3813 if (act & DO_ABS) {
3814 while (stat(name, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003815 if (errno != ENOENT && errno != ENOTDIR)
3816 e = errno;
3817 entry->cmdtype = CMDUNKNOWN;
3818 entry->u.index = -1;
3819 return;
3820 }
3821 entry->cmdtype = CMDNORMAL;
3822 entry->u.index = -1;
3823 return;
3824 }
3825 entry->cmdtype = CMDNORMAL;
3826 entry->u.index = 0;
3827 return;
3828 }
3829
3830 updatetbl = 1;
3831 if (act & DO_BRUTE) {
3832 firstchange = path_change(path, &bltin);
3833 } else {
3834 bltin = builtinloc;
3835 firstchange = 9999;
3836 }
3837
3838 /* If name is in the table, and not invalidated by cd, we're done */
3839 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
3840 if (cmdp->cmdtype == CMDFUNCTION) {
3841 if (act & DO_NOFUN) {
3842 updatetbl = 0;
3843 } else {
3844 goto success;
3845 }
3846 } else if (act & DO_BRUTE) {
3847 if ((cmdp->cmdtype == CMDNORMAL &&
3848 cmdp->param.index >= firstchange) ||
3849 (cmdp->cmdtype == CMDBUILTIN &&
3850 ((builtinloc < 0 && bltin >= 0) ?
3851 bltin : builtinloc) >= firstchange)) {
3852 /* need to recompute the entry */
3853 } else {
3854 goto success;
3855 }
3856 } else {
3857 goto success;
3858 }
3859 }
3860
3861 bcmd = find_builtin(name);
Eric Andersen2870d962001-07-02 17:27:21 +00003862 regular = bcmd && IS_BUILTIN_REGULAR(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00003863
3864 if (regular) {
3865 if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) {
Eric Andersen2870d962001-07-02 17:27:21 +00003866 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003867 }
3868 } else if (act & DO_BRUTE) {
3869 if (firstchange == 0) {
3870 updatetbl = 0;
3871 }
3872 }
3873
3874 /* If %builtin not in path, check for builtin next */
3875 if (regular || (bltin < 0 && bcmd)) {
3876builtin:
3877 if (!updatetbl) {
3878 entry->cmdtype = CMDBUILTIN;
3879 entry->u.cmd = bcmd;
3880 return;
3881 }
3882 INTOFF;
3883 cmdp = cmdlookup(name, 1);
3884 cmdp->cmdtype = CMDBUILTIN;
3885 cmdp->param.cmd = bcmd;
3886 INTON;
3887 goto success;
3888 }
3889
3890 /* We have to search path. */
Eric Andersen2870d962001-07-02 17:27:21 +00003891 prev = -1; /* where to start */
3892 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00003893 if (cmdp->cmdtype == CMDBUILTIN)
3894 prev = builtinloc;
3895 else
3896 prev = cmdp->param.index;
3897 }
3898
3899 e = ENOENT;
3900 idx = -1;
3901loop:
3902 while ((fullname = padvance(&path, name)) != NULL) {
3903 stunalloc(fullname);
3904 idx++;
3905 if (idx >= firstchange) {
3906 updatetbl = 0;
3907 }
3908 if (pathopt) {
3909 if (prefix("builtin", pathopt)) {
3910 if ((bcmd = find_builtin(name))) {
3911 goto builtin;
3912 }
3913 continue;
3914 } else if (!(act & DO_NOFUN) &&
3915 prefix("func", pathopt)) {
3916 /* handled below */
3917 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00003918 continue; /* ignore unimplemented options */
Eric Andersencb57d552001-06-28 07:25:16 +00003919 }
3920 }
3921 /* if rehash, don't redo absolute path names */
3922 if (fullname[0] == '/' && idx <= prev &&
3923 idx < firstchange) {
3924 if (idx < prev)
3925 continue;
3926 TRACE(("searchexec \"%s\": no change\n", name));
3927 goto success;
3928 }
3929 while (stat(fullname, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003930 if (errno != ENOENT && errno != ENOTDIR)
3931 e = errno;
3932 goto loop;
3933 }
Eric Andersen2870d962001-07-02 17:27:21 +00003934 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00003935 if (!S_ISREG(statb.st_mode))
3936 continue;
Eric Andersen2870d962001-07-02 17:27:21 +00003937 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00003938 stalloc(strlen(fullname) + 1);
3939 readcmdfile(fullname);
3940 if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
3941 error("%s not defined in %s", name, fullname);
3942 stunalloc(fullname);
3943 goto success;
3944 }
Eric Andersencb57d552001-06-28 07:25:16 +00003945 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
3946 /* If we aren't called with DO_BRUTE and cmdp is set, it must
3947 be a function and we're being called with DO_NOFUN */
3948 if (!updatetbl) {
3949 entry->cmdtype = CMDNORMAL;
3950 entry->u.index = idx;
3951 return;
3952 }
3953 INTOFF;
3954 cmdp = cmdlookup(name, 1);
3955 cmdp->cmdtype = CMDNORMAL;
3956 cmdp->param.index = idx;
3957 INTON;
3958 goto success;
3959 }
3960
3961 /* We failed. If there was an entry for this command, delete it */
3962 if (cmdp && updatetbl)
3963 delete_cmd_entry();
3964 if (act & DO_ERR)
Eric Andersen3102ac42001-07-06 04:26:23 +00003965 out2fmt("%s: %s\n", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00003966 entry->cmdtype = CMDUNKNOWN;
3967 return;
3968
3969success:
3970 cmdp->rehash = 0;
3971 entry->cmdtype = cmdp->cmdtype;
3972 entry->u = cmdp->param;
3973}
3974
3975
3976
3977/*
3978 * Search the table of builtin commands.
3979 */
3980
Eric Andersen2870d962001-07-02 17:27:21 +00003981static int
3982bstrcmp(const void *name, const void *b)
3983{
3984 return strcmp((const char *)name, (*(const char *const *) b)+1);
3985}
3986
3987static struct builtincmd *
3988find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00003989{
3990 struct builtincmd *bp;
3991
Eric Andersen2870d962001-07-02 17:27:21 +00003992 bp = bsearch(name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd),
3993 bstrcmp
Eric Andersencb57d552001-06-28 07:25:16 +00003994 );
3995 return bp;
3996}
3997
3998
3999/*
4000 * Called when a cd is done. Marks all commands so the next time they
4001 * are executed they will be rehashed.
4002 */
4003
4004static void
Eric Andersen2870d962001-07-02 17:27:21 +00004005hashcd(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00004006 struct tblentry **pp;
4007 struct tblentry *cmdp;
4008
4009 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4010 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4011 if (cmdp->cmdtype == CMDNORMAL
4012 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
4013 cmdp->rehash = 1;
4014 }
4015 }
4016}
4017
4018
4019
4020/*
4021 * Called before PATH is changed. The argument is the new value of PATH;
4022 * pathval() still returns the old value at this point. Called with
4023 * interrupts off.
4024 */
4025
4026static void
Eric Andersen2870d962001-07-02 17:27:21 +00004027changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00004028{
4029 int firstchange;
4030 int bltin;
4031
4032 firstchange = path_change(newval, &bltin);
4033 if (builtinloc < 0 && bltin >= 0)
Eric Andersen2870d962001-07-02 17:27:21 +00004034 builtinloc = bltin; /* zap builtins */
Eric Andersencb57d552001-06-28 07:25:16 +00004035 clearcmdentry(firstchange);
4036 builtinloc = bltin;
4037}
4038
4039
4040/*
4041 * Clear out command entries. The argument specifies the first entry in
4042 * PATH which has changed.
4043 */
4044
4045static void
4046clearcmdentry(firstchange)
4047 int firstchange;
4048{
4049 struct tblentry **tblp;
4050 struct tblentry **pp;
4051 struct tblentry *cmdp;
4052
4053 INTOFF;
4054 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4055 pp = tblp;
4056 while ((cmdp = *pp) != NULL) {
4057 if ((cmdp->cmdtype == CMDNORMAL &&
4058 cmdp->param.index >= firstchange)
4059 || (cmdp->cmdtype == CMDBUILTIN &&
4060 builtinloc >= firstchange)) {
4061 *pp = cmdp->next;
4062 ckfree(cmdp);
4063 } else {
4064 pp = &cmdp->next;
4065 }
4066 }
4067 }
4068 INTON;
4069}
4070
4071
4072/*
4073 * Delete all functions.
4074 */
4075
Eric Andersencb57d552001-06-28 07:25:16 +00004076static void
Eric Andersen2870d962001-07-02 17:27:21 +00004077deletefuncs(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00004078 struct tblentry **tblp;
4079 struct tblentry **pp;
4080 struct tblentry *cmdp;
4081
4082 INTOFF;
4083 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4084 pp = tblp;
4085 while ((cmdp = *pp) != NULL) {
4086 if (cmdp->cmdtype == CMDFUNCTION) {
4087 *pp = cmdp->next;
4088 freefunc(cmdp->param.func);
4089 ckfree(cmdp);
4090 } else {
4091 pp = &cmdp->next;
4092 }
4093 }
4094 }
4095 INTON;
4096}
4097
4098
4099
4100/*
4101 * Locate a command in the command hash table. If "add" is nonzero,
4102 * add the command to the table if it is not already present. The
4103 * variable "lastcmdentry" is set to point to the address of the link
4104 * pointing to the entry, so that delete_cmd_entry can delete the
4105 * entry.
4106 */
4107
Eric Andersen2870d962001-07-02 17:27:21 +00004108static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00004109
4110static struct tblentry *
Eric Andersen2870d962001-07-02 17:27:21 +00004111cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00004112{
4113 int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00004114 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00004115 struct tblentry *cmdp;
4116 struct tblentry **pp;
4117
4118 p = name;
4119 hashval = *p << 4;
4120 while (*p)
4121 hashval += *p++;
4122 hashval &= 0x7FFF;
4123 pp = &cmdtable[hashval % CMDTABLESIZE];
4124 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4125 if (equal(cmdp->cmdname, name))
4126 break;
4127 pp = &cmdp->next;
4128 }
4129 if (add && cmdp == NULL) {
4130 INTOFF;
4131 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4132 + strlen(name) + 1);
4133 cmdp->next = NULL;
4134 cmdp->cmdtype = CMDUNKNOWN;
4135 cmdp->rehash = 0;
4136 strcpy(cmdp->cmdname, name);
4137 INTON;
4138 }
4139 lastcmdentry = pp;
4140 return cmdp;
4141}
4142
4143/*
4144 * Delete the command entry returned on the last lookup.
4145 */
4146
4147static void
4148delete_cmd_entry() {
4149 struct tblentry *cmdp;
4150
4151 INTOFF;
4152 cmdp = *lastcmdentry;
4153 *lastcmdentry = cmdp->next;
4154 ckfree(cmdp);
4155 INTON;
4156}
4157
4158
4159
Eric Andersencb57d552001-06-28 07:25:16 +00004160
4161
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004162static const unsigned char nodesize[26] = {
Eric Andersen62483552001-07-10 06:09:16 +00004163 ALIGN(sizeof (struct nbinary)),
4164 ALIGN(sizeof (struct ncmd)),
4165 ALIGN(sizeof (struct npipe)),
4166 ALIGN(sizeof (struct nredir)),
4167 ALIGN(sizeof (struct nredir)),
4168 ALIGN(sizeof (struct nredir)),
4169 ALIGN(sizeof (struct nbinary)),
4170 ALIGN(sizeof (struct nbinary)),
4171 ALIGN(sizeof (struct nif)),
4172 ALIGN(sizeof (struct nbinary)),
4173 ALIGN(sizeof (struct nbinary)),
4174 ALIGN(sizeof (struct nfor)),
4175 ALIGN(sizeof (struct ncase)),
4176 ALIGN(sizeof (struct nclist)),
4177 ALIGN(sizeof (struct narg)),
4178 ALIGN(sizeof (struct narg)),
4179 ALIGN(sizeof (struct nfile)),
4180 ALIGN(sizeof (struct nfile)),
4181 ALIGN(sizeof (struct nfile)),
4182 ALIGN(sizeof (struct nfile)),
4183 ALIGN(sizeof (struct nfile)),
4184 ALIGN(sizeof (struct ndup)),
4185 ALIGN(sizeof (struct ndup)),
4186 ALIGN(sizeof (struct nhere)),
4187 ALIGN(sizeof (struct nhere)),
4188 ALIGN(sizeof (struct nnot)),
4189};
Eric Andersencb57d552001-06-28 07:25:16 +00004190
Eric Andersencb57d552001-06-28 07:25:16 +00004191
4192
4193/*
4194 * Delete a function if it exists.
4195 */
4196
4197static void
Eric Andersen2870d962001-07-02 17:27:21 +00004198unsetfunc(char *name)
4199{
Eric Andersencb57d552001-06-28 07:25:16 +00004200 struct tblentry *cmdp;
4201
4202 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
4203 freefunc(cmdp->param.func);
4204 delete_cmd_entry();
4205 }
4206}
4207
Eric Andersen2870d962001-07-02 17:27:21 +00004208
4209/*
Eric Andersencb57d552001-06-28 07:25:16 +00004210 * Locate and print what a word is...
4211 */
4212
4213static int
Eric Andersen62483552001-07-10 06:09:16 +00004214typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004215{
4216 int i;
4217 int err = 0;
Eric Andersen62483552001-07-10 06:09:16 +00004218 char *argv_a[2];
4219
4220 argv_a[1] = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004221
4222 for (i = 1; i < argc; i++) {
Eric Andersen62483552001-07-10 06:09:16 +00004223 argv_a[0] = argv[i];
4224 argptr = argv_a;
4225 optptr = "v";
4226 err |= hashcmd(argc, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00004227 }
4228 return err;
4229}
4230
Eric Andersen2870d962001-07-02 17:27:21 +00004231#ifdef ASH_CMDCMD
Eric Andersencb57d552001-06-28 07:25:16 +00004232static int
4233commandcmd(argc, argv)
4234 int argc;
4235 char **argv;
4236{
4237 int c;
4238 int default_path = 0;
4239 int verify_only = 0;
4240 int verbose_verify_only = 0;
4241
4242 while ((c = nextopt("pvV")) != '\0')
4243 switch (c) {
4244 case 'p':
4245 default_path = 1;
4246 break;
4247 case 'v':
4248 verify_only = 1;
4249 break;
4250 case 'V':
4251 verbose_verify_only = 1;
4252 break;
Eric Andersencb57d552001-06-28 07:25:16 +00004253 }
4254
4255 if (default_path + verify_only + verbose_verify_only > 1 ||
4256 !*argptr) {
Eric Andersen62483552001-07-10 06:09:16 +00004257 out2str(
4258 "command [-p] command [arg ...]\n"
4259 "command {-v|-V} command\n");
Eric Andersencb57d552001-06-28 07:25:16 +00004260 return EX_USAGE;
4261 }
4262
Eric Andersencb57d552001-06-28 07:25:16 +00004263 if (verify_only || verbose_verify_only) {
Eric Andersen62483552001-07-10 06:09:16 +00004264 char *argv_a[2];
4265
4266 argv_a[1] = 0;
4267 argv_a[0] = *argptr;
4268 argptr = argv_a;
4269 optptr = verbose_verify_only ? "v" : "V"; /* reverse special */
4270 return hashcmd(argc, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00004271 }
Eric Andersencb57d552001-06-28 07:25:16 +00004272
4273 return 0;
4274}
Eric Andersen2870d962001-07-02 17:27:21 +00004275#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004276
4277static int
4278path_change(newval, bltin)
4279 const char *newval;
4280 int *bltin;
4281{
4282 const char *old, *new;
4283 int idx;
4284 int firstchange;
4285
4286 old = pathval();
4287 new = newval;
Eric Andersen2870d962001-07-02 17:27:21 +00004288 firstchange = 9999; /* assume no change */
Eric Andersencb57d552001-06-28 07:25:16 +00004289 idx = 0;
4290 *bltin = -1;
4291 for (;;) {
4292 if (*old != *new) {
4293 firstchange = idx;
4294 if ((*old == '\0' && *new == ':')
4295 || (*old == ':' && *new == '\0'))
4296 firstchange++;
Eric Andersen2870d962001-07-02 17:27:21 +00004297 old = new; /* ignore subsequent differences */
Eric Andersencb57d552001-06-28 07:25:16 +00004298 }
4299 if (*new == '\0')
4300 break;
4301 if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1))
4302 *bltin = idx;
4303 if (*new == ':') {
4304 idx++;
4305 }
4306 new++, old++;
4307 }
4308 if (builtinloc >= 0 && *bltin < 0)
4309 firstchange = 0;
4310 return firstchange;
4311}
Eric Andersencb57d552001-06-28 07:25:16 +00004312/*
4313 * Routines to expand arguments to commands. We have to deal with
4314 * backquotes, shell variables, and file metacharacters.
4315 */
4316/*
4317 * _rmescape() flags
4318 */
Eric Andersen2870d962001-07-02 17:27:21 +00004319#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4320#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Eric Andersencb57d552001-06-28 07:25:16 +00004321
4322/*
4323 * Structure specifying which parts of the string should be searched
4324 * for IFS characters.
4325 */
4326
4327struct ifsregion {
Eric Andersen2870d962001-07-02 17:27:21 +00004328 struct ifsregion *next; /* next region in list */
4329 int begoff; /* offset of start of region */
4330 int endoff; /* offset of end of region */
4331 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004332};
4333
4334
Eric Andersen2870d962001-07-02 17:27:21 +00004335static char *expdest; /* output of current string */
4336static struct nodelist *argbackq; /* list of back quote expressions */
4337static struct ifsregion ifsfirst; /* first struct in list of ifs regions */
4338static struct ifsregion *ifslastp; /* last struct in list */
4339static struct arglist exparg; /* holds expanded arg list */
Eric Andersencb57d552001-06-28 07:25:16 +00004340
Eric Andersen2870d962001-07-02 17:27:21 +00004341static void argstr (char *, int);
4342static char *exptilde (char *, int);
4343static void expbackq (union node *, int, int);
4344static int subevalvar (char *, char *, int, int, int, int, int);
Eric Andersen2870d962001-07-02 17:27:21 +00004345static int varisset (char *, int);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004346static void strtodest (const char *, int, int);
Eric Andersen2870d962001-07-02 17:27:21 +00004347static void varvalue (char *, int, int);
4348static void recordregion (int, int, int);
4349static void removerecordregions (int);
4350static void ifsbreakup (char *, struct arglist *);
4351static void ifsfree (void);
4352static void expandmeta (struct strlist *, int);
Eric Andersen62483552001-07-10 06:09:16 +00004353#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00004354#define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB)
4355#if !defined(GLOB_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00004356static void addglob (const glob_t *);
Eric Andersencb57d552001-06-28 07:25:16 +00004357#endif
4358#endif
Eric Andersen62483552001-07-10 06:09:16 +00004359#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersen2870d962001-07-02 17:27:21 +00004360static void expmeta (char *, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004361#endif
Eric Andersen62483552001-07-10 06:09:16 +00004362#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersen2870d962001-07-02 17:27:21 +00004363static struct strlist *expsort (struct strlist *);
4364static struct strlist *msort (struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004365#endif
Eric Andersen2870d962001-07-02 17:27:21 +00004366static int patmatch (char *, char *, int);
Eric Andersen62483552001-07-10 06:09:16 +00004367#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00004368static int patmatch2 (char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004369#else
Eric Andersen2870d962001-07-02 17:27:21 +00004370static int pmatch (char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004371#define patmatch2 patmatch
4372#endif
Eric Andersen2870d962001-07-02 17:27:21 +00004373static char *cvtnum (int, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004374
4375/*
4376 * Expand shell variables and backquotes inside a here document.
4377 */
4378
Eric Andersen2870d962001-07-02 17:27:21 +00004379/* arg: the document, fd: where to write the expanded version */
Eric Andersen62483552001-07-10 06:09:16 +00004380static inline void
Eric Andersen2870d962001-07-02 17:27:21 +00004381expandhere(union node *arg, int fd)
4382{
Eric Andersencb57d552001-06-28 07:25:16 +00004383 herefd = fd;
4384 expandarg(arg, (struct arglist *)NULL, 0);
4385 xwrite(fd, stackblock(), expdest - stackblock());
4386}
4387
4388
4389/*
4390 * Perform variable substitution and command substitution on an argument,
4391 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4392 * perform splitting and file name expansion. When arglist is NULL, perform
4393 * here document expansion.
4394 */
4395
4396static void
4397expandarg(arg, arglist, flag)
4398 union node *arg;
4399 struct arglist *arglist;
4400 int flag;
4401{
4402 struct strlist *sp;
4403 char *p;
4404
4405 argbackq = arg->narg.backquote;
4406 STARTSTACKSTR(expdest);
4407 ifsfirst.next = NULL;
4408 ifslastp = NULL;
4409 argstr(arg->narg.text, flag);
4410 if (arglist == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00004411 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004412 }
4413 STPUTC('\0', expdest);
4414 p = grabstackstr(expdest);
4415 exparg.lastp = &exparg.list;
4416 /*
4417 * TODO - EXP_REDIR
4418 */
4419 if (flag & EXP_FULL) {
4420 ifsbreakup(p, &exparg);
4421 *exparg.lastp = NULL;
4422 exparg.lastp = &exparg.list;
4423 expandmeta(exparg.list, flag);
4424 } else {
4425 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4426 rmescapes(p);
4427 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4428 sp->text = p;
4429 *exparg.lastp = sp;
4430 exparg.lastp = &sp->next;
4431 }
4432 ifsfree();
4433 *exparg.lastp = NULL;
4434 if (exparg.list) {
4435 *arglist->lastp = exparg.list;
4436 arglist->lastp = exparg.lastp;
4437 }
4438}
4439
4440
Eric Andersen62483552001-07-10 06:09:16 +00004441/*
4442 * Expand a variable, and return a pointer to the next character in the
4443 * input string.
4444 */
4445
Eric Andersen74400cc2001-10-18 04:11:39 +00004446static inline char * evalvar(char *p, int flag)
Eric Andersen62483552001-07-10 06:09:16 +00004447{
4448 int subtype;
4449 int varflags;
4450 char *var;
4451 const char *val;
4452 int patloc;
4453 int c;
4454 int set;
4455 int special;
4456 int startloc;
4457 int varlen;
4458 int easy;
4459 int quotes = flag & (EXP_FULL | EXP_CASE);
4460
4461 varflags = *p++;
4462 subtype = varflags & VSTYPE;
4463 var = p;
4464 special = 0;
4465 if (! is_name(*p))
4466 special = 1;
4467 p = strchr(p, '=') + 1;
4468again: /* jump here after setting a variable with ${var=text} */
4469 if (special) {
4470 set = varisset(var, varflags & VSNUL);
4471 val = NULL;
4472 } else {
4473 val = lookupvar(var);
4474 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
4475 val = NULL;
4476 set = 0;
4477 } else
4478 set = 1;
4479 }
4480 varlen = 0;
4481 startloc = expdest - stackblock();
4482 if (set && subtype != VSPLUS) {
4483 /* insert the value of the variable */
4484 if (special) {
4485 varvalue(var, varflags & VSQUOTE, flag);
4486 if (subtype == VSLENGTH) {
4487 varlen = expdest - stackblock() - startloc;
4488 STADJUST(-varlen, expdest);
4489 }
4490 } else {
4491 if (subtype == VSLENGTH) {
4492 varlen = strlen(val);
4493 } else {
4494 strtodest(
4495 val,
4496 varflags & VSQUOTE ?
4497 DQSYNTAX : BASESYNTAX,
4498 quotes
4499 );
4500 }
4501 }
4502 }
4503
4504 if (subtype == VSPLUS)
4505 set = ! set;
4506
4507 easy = ((varflags & VSQUOTE) == 0 ||
4508 (*var == '@' && shellparam.nparam != 1));
4509
4510
4511 switch (subtype) {
4512 case VSLENGTH:
4513 expdest = cvtnum(varlen, expdest);
4514 goto record;
4515
4516 case VSNORMAL:
4517 if (!easy)
4518 break;
4519record:
4520 recordregion(startloc, expdest - stackblock(),
4521 varflags & VSQUOTE);
4522 break;
4523
4524 case VSPLUS:
4525 case VSMINUS:
4526 if (!set) {
4527 argstr(p, flag);
4528 break;
4529 }
4530 if (easy)
4531 goto record;
4532 break;
4533
4534 case VSTRIMLEFT:
4535 case VSTRIMLEFTMAX:
4536 case VSTRIMRIGHT:
4537 case VSTRIMRIGHTMAX:
4538 if (!set)
4539 break;
4540 /*
4541 * Terminate the string and start recording the pattern
4542 * right after it
4543 */
4544 STPUTC('\0', expdest);
4545 patloc = expdest - stackblock();
4546 if (subevalvar(p, NULL, patloc, subtype,
4547 startloc, varflags, quotes) == 0) {
4548 int amount = (expdest - stackblock() - patloc) + 1;
4549 STADJUST(-amount, expdest);
4550 }
4551 /* Remove any recorded regions beyond start of variable */
4552 removerecordregions(startloc);
4553 goto record;
4554
4555 case VSASSIGN:
4556 case VSQUESTION:
4557 if (!set) {
4558 if (subevalvar(p, var, 0, subtype, startloc,
4559 varflags, quotes)) {
4560 varflags &= ~VSNUL;
4561 /*
4562 * Remove any recorded regions beyond
4563 * start of variable
4564 */
4565 removerecordregions(startloc);
4566 goto again;
4567 }
4568 break;
4569 }
4570 if (easy)
4571 goto record;
4572 break;
4573
4574#ifdef DEBUG
4575 default:
4576 abort();
4577#endif
4578 }
4579
4580 if (subtype != VSNORMAL) { /* skip to end of alternative */
4581 int nesting = 1;
4582 for (;;) {
4583 if ((c = *p++) == CTLESC)
4584 p++;
4585 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
4586 if (set)
4587 argbackq = argbackq->next;
4588 } else if (c == CTLVAR) {
4589 if ((*p++ & VSTYPE) != VSNORMAL)
4590 nesting++;
4591 } else if (c == CTLENDVAR) {
4592 if (--nesting == 0)
4593 break;
4594 }
4595 }
4596 }
4597 return p;
4598}
4599
Eric Andersencb57d552001-06-28 07:25:16 +00004600
4601/*
4602 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4603 * characters to allow for further processing. Otherwise treat
4604 * $@ like $* since no splitting will be performed.
4605 */
4606
4607static void
4608argstr(p, flag)
4609 char *p;
4610 int flag;
4611{
4612 char c;
Eric Andersen2870d962001-07-02 17:27:21 +00004613 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
Eric Andersencb57d552001-06-28 07:25:16 +00004614 int firsteq = 1;
4615
4616 if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
4617 p = exptilde(p, flag);
4618 for (;;) {
4619 switch (c = *p++) {
4620 case '\0':
4621 case CTLENDVAR: /* ??? */
4622 goto breakloop;
4623 case CTLQUOTEMARK:
4624 /* "$@" syntax adherence hack */
4625 if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
4626 break;
4627 if ((flag & EXP_FULL) != 0)
4628 STPUTC(c, expdest);
4629 break;
4630 case CTLESC:
4631 if (quotes)
4632 STPUTC(c, expdest);
4633 c = *p++;
4634 STPUTC(c, expdest);
4635 break;
4636 case CTLVAR:
4637 p = evalvar(p, flag);
4638 break;
4639 case CTLBACKQ:
4640 case CTLBACKQ|CTLQUOTE:
4641 expbackq(argbackq->n, c & CTLQUOTE, flag);
4642 argbackq = argbackq->next;
4643 break;
4644#ifdef ASH_MATH_SUPPORT
4645 case CTLENDARI:
4646 expari(flag);
4647 break;
Eric Andersen2870d962001-07-02 17:27:21 +00004648#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004649 case ':':
4650 case '=':
4651 /*
4652 * sort of a hack - expand tildes in variable
4653 * assignments (after the first '=' and after ':'s).
4654 */
4655 STPUTC(c, expdest);
4656 if (flag & EXP_VARTILDE && *p == '~') {
4657 if (c == '=') {
4658 if (firsteq)
4659 firsteq = 0;
4660 else
4661 break;
4662 }
4663 p = exptilde(p, flag);
4664 }
4665 break;
4666 default:
4667 STPUTC(c, expdest);
4668 }
4669 }
4670breakloop:;
4671 return;
4672}
4673
4674static char *
4675exptilde(p, flag)
4676 char *p;
4677 int flag;
4678{
4679 char c, *startp = p;
4680 struct passwd *pw;
4681 const char *home;
4682 int quotes = flag & (EXP_FULL | EXP_CASE);
4683
4684 while ((c = *p) != '\0') {
4685 switch(c) {
4686 case CTLESC:
4687 return (startp);
4688 case CTLQUOTEMARK:
4689 return (startp);
4690 case ':':
4691 if (flag & EXP_VARTILDE)
4692 goto done;
4693 break;
4694 case '/':
4695 goto done;
4696 }
4697 p++;
4698 }
4699done:
4700 *p = '\0';
4701 if (*(startp+1) == '\0') {
4702 if ((home = lookupvar("HOME")) == NULL)
4703 goto lose;
4704 } else {
4705 if ((pw = getpwnam(startp+1)) == NULL)
4706 goto lose;
4707 home = pw->pw_dir;
4708 }
4709 if (*home == '\0')
4710 goto lose;
4711 *p = c;
4712 strtodest(home, SQSYNTAX, quotes);
4713 return (p);
4714lose:
4715 *p = c;
4716 return (startp);
4717}
4718
4719
Eric Andersen2870d962001-07-02 17:27:21 +00004720static void
4721removerecordregions(int endoff)
Eric Andersencb57d552001-06-28 07:25:16 +00004722{
4723 if (ifslastp == NULL)
4724 return;
4725
4726 if (ifsfirst.endoff > endoff) {
4727 while (ifsfirst.next != NULL) {
4728 struct ifsregion *ifsp;
4729 INTOFF;
4730 ifsp = ifsfirst.next->next;
4731 ckfree(ifsfirst.next);
4732 ifsfirst.next = ifsp;
4733 INTON;
4734 }
4735 if (ifsfirst.begoff > endoff)
4736 ifslastp = NULL;
4737 else {
4738 ifslastp = &ifsfirst;
4739 ifsfirst.endoff = endoff;
4740 }
4741 return;
4742 }
Eric Andersen2870d962001-07-02 17:27:21 +00004743
Eric Andersencb57d552001-06-28 07:25:16 +00004744 ifslastp = &ifsfirst;
4745 while (ifslastp->next && ifslastp->next->begoff < endoff)
4746 ifslastp=ifslastp->next;
4747 while (ifslastp->next != NULL) {
4748 struct ifsregion *ifsp;
4749 INTOFF;
4750 ifsp = ifslastp->next->next;
4751 ckfree(ifslastp->next);
4752 ifslastp->next = ifsp;
4753 INTON;
4754 }
4755 if (ifslastp->endoff > endoff)
4756 ifslastp->endoff = endoff;
4757}
4758
4759
4760#ifdef ASH_MATH_SUPPORT
4761/*
4762 * Expand arithmetic expression. Backup to start of expression,
4763 * evaluate, place result in (backed up) result, adjust string position.
4764 */
4765static void
Eric Andersen2870d962001-07-02 17:27:21 +00004766expari(int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004767{
4768 char *p, *start;
Eric Andersen34506362001-08-02 05:02:46 +00004769 int errcode;
Eric Andersencb57d552001-06-28 07:25:16 +00004770 int result;
4771 int begoff;
4772 int quotes = flag & (EXP_FULL | EXP_CASE);
4773 int quoted;
4774
Eric Andersen2870d962001-07-02 17:27:21 +00004775 /* ifsfree(); */
Eric Andersencb57d552001-06-28 07:25:16 +00004776
4777 /*
4778 * This routine is slightly over-complicated for
4779 * efficiency. First we make sure there is
4780 * enough space for the result, which may be bigger
4781 * than the expression if we add exponentation. Next we
4782 * scan backwards looking for the start of arithmetic. If the
4783 * next previous character is a CTLESC character, then we
4784 * have to rescan starting from the beginning since CTLESC
4785 * characters have to be processed left to right.
4786 */
4787 CHECKSTRSPACE(10, expdest);
4788 USTPUTC('\0', expdest);
4789 start = stackblock();
4790 p = expdest - 1;
4791 while (*p != CTLARI && p >= start)
4792 --p;
4793 if (*p != CTLARI)
4794 error("missing CTLARI (shouldn't happen)");
4795 if (p > start && *(p-1) == CTLESC)
4796 for (p = start; *p != CTLARI; p++)
4797 if (*p == CTLESC)
4798 p++;
4799
4800 if (p[1] == '"')
4801 quoted=1;
4802 else
4803 quoted=0;
4804 begoff = p - start;
4805 removerecordregions(begoff);
4806 if (quotes)
4807 rmescapes(p+2);
Eric Andersen34506362001-08-02 05:02:46 +00004808 result = arith(p+2, &errcode);
4809 if (errcode < 0) {
4810 if(errcode == -2)
4811 error("divide by zero");
4812 else
4813 error("syntax error: \"%s\"\n", p+2);
4814 }
Eric Andersen3102ac42001-07-06 04:26:23 +00004815 snprintf(p, 12, "%d", result);
Eric Andersencb57d552001-06-28 07:25:16 +00004816
4817 while (*p++)
4818 ;
4819
4820 if (quoted == 0)
4821 recordregion(begoff, p - 1 - start, 0);
4822 result = expdest - p + 1;
4823 STADJUST(-result, expdest);
4824}
Eric Andersen2870d962001-07-02 17:27:21 +00004825#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004826
4827/*
4828 * Expand stuff in backwards quotes.
4829 */
4830
4831static void
4832expbackq(cmd, quoted, flag)
4833 union node *cmd;
4834 int quoted;
4835 int flag;
4836{
4837 volatile struct backcmd in;
4838 int i;
4839 char buf[128];
4840 char *p;
4841 char *dest = expdest;
4842 volatile struct ifsregion saveifs;
4843 struct ifsregion *volatile savelastp;
4844 struct nodelist *volatile saveargbackq;
4845 char lastc;
4846 int startloc = dest - stackblock();
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004847 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +00004848 volatile int saveherefd;
4849 int quotes = flag & (EXP_FULL | EXP_CASE);
4850 struct jmploc jmploc;
4851 struct jmploc *volatile savehandler;
4852 int ex;
4853
4854#if __GNUC__
4855 /* Avoid longjmp clobbering */
4856 (void) &dest;
4857 (void) &syntax;
4858#endif
4859
4860 in.fd = -1;
4861 in.buf = 0;
4862 in.jp = 0;
4863
4864 INTOFF;
4865 saveifs = ifsfirst;
4866 savelastp = ifslastp;
4867 saveargbackq = argbackq;
4868 saveherefd = herefd;
4869 herefd = -1;
4870 if ((ex = setjmp(jmploc.loc))) {
4871 goto err1;
4872 }
4873 savehandler = handler;
4874 handler = &jmploc;
4875 INTON;
4876 p = grabstackstr(dest);
4877 evalbackcmd(cmd, (struct backcmd *) &in);
4878 ungrabstackstr(p, dest);
4879err1:
4880 INTOFF;
4881 ifsfirst = saveifs;
4882 ifslastp = savelastp;
4883 argbackq = saveargbackq;
4884 herefd = saveherefd;
4885 if (ex) {
4886 goto err2;
4887 }
4888
4889 p = in.buf;
4890 lastc = '\0';
4891 for (;;) {
4892 if (--in.nleft < 0) {
4893 if (in.fd < 0)
4894 break;
Eric Andersen7467c8d2001-07-12 20:26:32 +00004895 i = safe_read(in.fd, buf, sizeof buf);
Eric Andersencb57d552001-06-28 07:25:16 +00004896 TRACE(("expbackq: read returns %d\n", i));
4897 if (i <= 0)
4898 break;
4899 p = buf;
4900 in.nleft = i - 1;
4901 }
4902 lastc = *p++;
4903 if (lastc != '\0') {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004904 if (quotes && SIT(lastc, syntax) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +00004905 STPUTC(CTLESC, dest);
4906 STPUTC(lastc, dest);
4907 }
4908 }
4909
4910 /* Eat all trailing newlines */
4911 for (; dest > stackblock() && dest[-1] == '\n';)
4912 STUNPUTC(dest);
4913
4914err2:
4915 if (in.fd >= 0)
4916 close(in.fd);
4917 if (in.buf)
4918 ckfree(in.buf);
4919 if (in.jp)
4920 exitstatus = waitforjob(in.jp);
4921 handler = savehandler;
4922 if (ex) {
4923 longjmp(handler->loc, 1);
4924 }
4925 if (quoted == 0)
4926 recordregion(startloc, dest - stackblock(), 0);
4927 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4928 (dest - stackblock()) - startloc,
4929 (dest - stackblock()) - startloc,
4930 stackblock() + startloc));
4931 expdest = dest;
4932 INTON;
4933}
4934
Eric Andersencb57d552001-06-28 07:25:16 +00004935static int
4936subevalvar(p, str, strloc, subtype, startloc, varflags, quotes)
4937 char *p;
4938 char *str;
4939 int strloc;
4940 int subtype;
4941 int startloc;
4942 int varflags;
4943 int quotes;
4944{
4945 char *startp;
4946 char *loc = NULL;
4947 char *q;
4948 int c = 0;
4949 int saveherefd = herefd;
4950 struct nodelist *saveargbackq = argbackq;
4951 int amount;
4952
4953 herefd = -1;
4954 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
4955 STACKSTRNUL(expdest);
4956 herefd = saveherefd;
4957 argbackq = saveargbackq;
4958 startp = stackblock() + startloc;
4959 if (str == NULL)
4960 str = stackblock() + strloc;
4961
4962 switch (subtype) {
4963 case VSASSIGN:
4964 setvar(str, startp, 0);
4965 amount = startp - expdest;
4966 STADJUST(amount, expdest);
4967 varflags &= ~VSNUL;
4968 if (c != 0)
4969 *loc = c;
4970 return 1;
4971
4972 case VSQUESTION:
4973 if (*p != CTLENDVAR) {
Eric Andersen3102ac42001-07-06 04:26:23 +00004974 out2fmt(snlfmt, startp);
Eric Andersencb57d552001-06-28 07:25:16 +00004975 error((char *)NULL);
4976 }
4977 error("%.*s: parameter %snot set", p - str - 1,
4978 str, (varflags & VSNUL) ? "null or "
4979 : nullstr);
4980 /* NOTREACHED */
4981
4982 case VSTRIMLEFT:
4983 for (loc = startp; loc < str; loc++) {
4984 c = *loc;
4985 *loc = '\0';
4986 if (patmatch2(str, startp, quotes))
4987 goto recordleft;
4988 *loc = c;
4989 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00004990 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00004991 }
4992 return 0;
4993
4994 case VSTRIMLEFTMAX:
4995 for (loc = str - 1; loc >= startp;) {
4996 c = *loc;
4997 *loc = '\0';
4998 if (patmatch2(str, startp, quotes))
4999 goto recordleft;
5000 *loc = c;
5001 loc--;
5002 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
5003 for (q = startp; q < loc; q++)
5004 if (*q == CTLESC)
5005 q++;
5006 if (q > loc)
5007 loc--;
5008 }
5009 }
5010 return 0;
5011
5012 case VSTRIMRIGHT:
Eric Andersen2870d962001-07-02 17:27:21 +00005013 for (loc = str - 1; loc >= startp;) {
Eric Andersencb57d552001-06-28 07:25:16 +00005014 if (patmatch2(str, loc, quotes))
5015 goto recordright;
5016 loc--;
Eric Andersen2870d962001-07-02 17:27:21 +00005017 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
Eric Andersencb57d552001-06-28 07:25:16 +00005018 for (q = startp; q < loc; q++)
5019 if (*q == CTLESC)
5020 q++;
5021 if (q > loc)
5022 loc--;
5023 }
5024 }
5025 return 0;
5026
5027 case VSTRIMRIGHTMAX:
5028 for (loc = startp; loc < str - 1; loc++) {
5029 if (patmatch2(str, loc, quotes))
5030 goto recordright;
5031 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00005032 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00005033 }
5034 return 0;
5035
5036#ifdef DEBUG
5037 default:
5038 abort();
5039#endif
5040 }
5041
5042recordleft:
5043 *loc = c;
5044 amount = ((str - 1) - (loc - startp)) - expdest;
5045 STADJUST(amount, expdest);
5046 while (loc != str - 1)
5047 *startp++ = *loc++;
5048 return 1;
5049
5050recordright:
5051 amount = loc - expdest;
5052 STADJUST(amount, expdest);
5053 STPUTC('\0', expdest);
5054 STADJUST(-1, expdest);
5055 return 1;
5056}
5057
5058
5059/*
Eric Andersencb57d552001-06-28 07:25:16 +00005060 * Test whether a specialized variable is set.
5061 */
5062
5063static int
5064varisset(name, nulok)
5065 char *name;
5066 int nulok;
5067{
5068 if (*name == '!')
5069 return backgndpid != -1;
5070 else if (*name == '@' || *name == '*') {
5071 if (*shellparam.p == NULL)
5072 return 0;
5073
5074 if (nulok) {
5075 char **av;
5076
5077 for (av = shellparam.p; *av; av++)
5078 if (**av != '\0')
5079 return 1;
5080 return 0;
5081 }
5082 } else if (is_digit(*name)) {
5083 char *ap;
5084 int num = atoi(name);
5085
5086 if (num > shellparam.nparam)
5087 return 0;
5088
5089 if (num == 0)
5090 ap = arg0;
5091 else
5092 ap = shellparam.p[num - 1];
5093
5094 if (nulok && (ap == NULL || *ap == '\0'))
5095 return 0;
5096 }
5097 return 1;
5098}
5099
Eric Andersencb57d552001-06-28 07:25:16 +00005100/*
5101 * Put a string on the stack.
5102 */
5103
5104static void
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005105strtodest(const char *p, int syntax, int quotes)
Eric Andersencb57d552001-06-28 07:25:16 +00005106{
5107 while (*p) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005108 if (quotes && SIT(*p,syntax) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +00005109 STPUTC(CTLESC, expdest);
5110 STPUTC(*p++, expdest);
5111 }
5112}
5113
Eric Andersencb57d552001-06-28 07:25:16 +00005114/*
5115 * Add the value of a specialized variable to the stack string.
5116 */
5117
5118static void
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005119varvalue(char *name, int quoted, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00005120{
5121 int num;
5122 char *p;
5123 int i;
5124 int sep;
5125 int sepq = 0;
5126 char **ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005127 int syntax;
Eric Andersencb57d552001-06-28 07:25:16 +00005128 int allow_split = flags & EXP_FULL;
5129 int quotes = flags & (EXP_FULL | EXP_CASE);
5130
5131 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5132 switch (*name) {
5133 case '$':
5134 num = rootpid;
5135 goto numvar;
5136 case '?':
5137 num = oexitstatus;
5138 goto numvar;
5139 case '#':
5140 num = shellparam.nparam;
5141 goto numvar;
5142 case '!':
5143 num = backgndpid;
5144numvar:
5145 expdest = cvtnum(num, expdest);
5146 break;
5147 case '-':
5148 for (i = 0 ; i < NOPTS ; i++) {
Eric Andersen2870d962001-07-02 17:27:21 +00005149 if (optent_val(i))
5150 STPUTC(optent_letter(optlist[i]), expdest);
Eric Andersencb57d552001-06-28 07:25:16 +00005151 }
5152 break;
5153 case '@':
5154 if (allow_split && quoted) {
5155 sep = 1 << CHAR_BIT;
5156 goto param;
5157 }
5158 /* fall through */
5159 case '*':
5160 sep = ifsset() ? ifsval()[0] : ' ';
5161 if (quotes) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005162 sepq = SIT(sep,syntax) == CCTL;
Eric Andersencb57d552001-06-28 07:25:16 +00005163 }
5164param:
5165 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
5166 strtodest(p, syntax, quotes);
5167 if (*ap && sep) {
5168 if (sepq)
5169 STPUTC(CTLESC, expdest);
5170 STPUTC(sep, expdest);
5171 }
5172 }
5173 break;
5174 case '0':
5175 strtodest(arg0, syntax, quotes);
5176 break;
5177 default:
5178 num = atoi(name);
5179 if (num > 0 && num <= shellparam.nparam) {
5180 strtodest(shellparam.p[num - 1], syntax, quotes);
5181 }
5182 break;
5183 }
5184}
5185
5186
Eric Andersencb57d552001-06-28 07:25:16 +00005187/*
5188 * Record the fact that we have to scan this region of the
5189 * string for IFS characters.
5190 */
5191
5192static void
5193recordregion(start, end, nulonly)
5194 int start;
5195 int end;
5196 int nulonly;
5197{
5198 struct ifsregion *ifsp;
5199
5200 if (ifslastp == NULL) {
5201 ifsp = &ifsfirst;
5202 } else {
5203 INTOFF;
5204 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
5205 ifsp->next = NULL;
5206 ifslastp->next = ifsp;
5207 INTON;
5208 }
5209 ifslastp = ifsp;
5210 ifslastp->begoff = start;
5211 ifslastp->endoff = end;
5212 ifslastp->nulonly = nulonly;
5213}
5214
5215
5216
5217/*
5218 * Break the argument string into pieces based upon IFS and add the
5219 * strings to the argument list. The regions of the string to be
5220 * searched for IFS characters have been stored by recordregion.
5221 */
5222static void
5223ifsbreakup(string, arglist)
5224 char *string;
5225 struct arglist *arglist;
5226 {
5227 struct ifsregion *ifsp;
5228 struct strlist *sp;
5229 char *start;
5230 char *p;
5231 char *q;
5232 const char *ifs, *realifs;
5233 int ifsspc;
5234 int nulonly;
5235
5236
5237 start = string;
5238 ifsspc = 0;
5239 nulonly = 0;
5240 realifs = ifsset() ? ifsval() : defifs;
5241 if (ifslastp != NULL) {
5242 ifsp = &ifsfirst;
5243 do {
5244 p = string + ifsp->begoff;
5245 nulonly = ifsp->nulonly;
5246 ifs = nulonly ? nullstr : realifs;
5247 ifsspc = 0;
5248 while (p < string + ifsp->endoff) {
5249 q = p;
5250 if (*p == CTLESC)
5251 p++;
5252 if (strchr(ifs, *p)) {
5253 if (!nulonly)
5254 ifsspc = (strchr(defifs, *p) != NULL);
5255 /* Ignore IFS whitespace at start */
5256 if (q == start && ifsspc) {
5257 p++;
5258 start = p;
5259 continue;
5260 }
5261 *q = '\0';
5262 sp = (struct strlist *)stalloc(sizeof *sp);
5263 sp->text = start;
5264 *arglist->lastp = sp;
5265 arglist->lastp = &sp->next;
5266 p++;
5267 if (!nulonly) {
5268 for (;;) {
5269 if (p >= string + ifsp->endoff) {
5270 break;
5271 }
5272 q = p;
5273 if (*p == CTLESC)
5274 p++;
5275 if (strchr(ifs, *p) == NULL ) {
5276 p = q;
5277 break;
5278 } else if (strchr(defifs, *p) == NULL) {
5279 if (ifsspc) {
5280 p++;
5281 ifsspc = 0;
5282 } else {
5283 p = q;
5284 break;
5285 }
5286 } else
5287 p++;
5288 }
5289 }
5290 start = p;
5291 } else
5292 p++;
5293 }
5294 } while ((ifsp = ifsp->next) != NULL);
5295 if (!(*start || (!ifsspc && start > string && nulonly))) {
5296 return;
5297 }
5298 }
5299
5300 sp = (struct strlist *)stalloc(sizeof *sp);
5301 sp->text = start;
5302 *arglist->lastp = sp;
5303 arglist->lastp = &sp->next;
5304}
5305
5306static void
5307ifsfree()
5308{
5309 while (ifsfirst.next != NULL) {
5310 struct ifsregion *ifsp;
5311 INTOFF;
5312 ifsp = ifsfirst.next->next;
5313 ckfree(ifsfirst.next);
5314 ifsfirst.next = ifsp;
5315 INTON;
5316 }
5317 ifslastp = NULL;
5318 ifsfirst.next = NULL;
5319}
5320
Eric Andersen2870d962001-07-02 17:27:21 +00005321/*
5322 * Add a file name to the list.
5323 */
Eric Andersencb57d552001-06-28 07:25:16 +00005324
Eric Andersen2870d962001-07-02 17:27:21 +00005325static void
5326addfname(const char *name)
5327{
5328 char *p;
5329 struct strlist *sp;
5330
5331 p = sstrdup(name);
5332 sp = (struct strlist *)stalloc(sizeof *sp);
5333 sp->text = p;
5334 *exparg.lastp = sp;
5335 exparg.lastp = &sp->next;
5336}
Eric Andersencb57d552001-06-28 07:25:16 +00005337
5338/*
5339 * Expand shell metacharacters. At this point, the only control characters
5340 * should be escapes. The results are stored in the list exparg.
5341 */
5342
Eric Andersen62483552001-07-10 06:09:16 +00005343#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00005344static void
5345expandmeta(str, flag)
5346 struct strlist *str;
5347 int flag;
5348{
5349 const char *p;
5350 glob_t pglob;
5351 /* TODO - EXP_REDIR */
5352
5353 while (str) {
5354 if (fflag)
5355 goto nometa;
5356 p = preglob(str->text);
5357 INTOFF;
Eric Andersen34506362001-08-02 05:02:46 +00005358 switch (glob(p, 0, 0, &pglob)) {
Eric Andersencb57d552001-06-28 07:25:16 +00005359 case 0:
Eric Andersen34506362001-08-02 05:02:46 +00005360 if(pglob.gl_pathv[1]==0 && !strcmp(p, pglob.gl_pathv[0]))
Eric Andersencb57d552001-06-28 07:25:16 +00005361 goto nometa2;
5362 addglob(&pglob);
5363 globfree(&pglob);
5364 INTON;
5365 break;
5366 case GLOB_NOMATCH:
5367nometa2:
5368 globfree(&pglob);
5369 INTON;
5370nometa:
5371 *exparg.lastp = str;
5372 rmescapes(str->text);
5373 exparg.lastp = &str->next;
5374 break;
Eric Andersen2870d962001-07-02 17:27:21 +00005375 default: /* GLOB_NOSPACE */
Eric Andersencb57d552001-06-28 07:25:16 +00005376 error("Out of space");
5377 }
5378 str = str->next;
5379 }
5380}
5381
5382
5383/*
5384 * Add the result of glob(3) to the list.
5385 */
5386
5387static void
5388addglob(pglob)
5389 const glob_t *pglob;
5390{
5391 char **p = pglob->gl_pathv;
5392
5393 do {
5394 addfname(*p);
5395 } while (*++p);
5396}
5397
5398
Eric Andersen2870d962001-07-02 17:27:21 +00005399#else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005400static char *expdir;
5401
5402
5403static void
5404expandmeta(str, flag)
5405 struct strlist *str;
5406 int flag;
5407{
5408 char *p;
5409 struct strlist **savelastp;
5410 struct strlist *sp;
5411 char c;
5412 /* TODO - EXP_REDIR */
5413
5414 while (str) {
5415 if (fflag)
5416 goto nometa;
5417 p = str->text;
Eric Andersen2870d962001-07-02 17:27:21 +00005418 for (;;) { /* fast check for meta chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005419 if ((c = *p++) == '\0')
5420 goto nometa;
5421 if (c == '*' || c == '?' || c == '[' || c == '!')
5422 break;
5423 }
5424 savelastp = exparg.lastp;
5425 INTOFF;
5426 if (expdir == NULL) {
5427 int i = strlen(str->text);
5428 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5429 }
5430
5431 expmeta(expdir, str->text);
5432 ckfree(expdir);
5433 expdir = NULL;
5434 INTON;
5435 if (exparg.lastp == savelastp) {
5436 /*
5437 * no matches
5438 */
5439nometa:
5440 *exparg.lastp = str;
5441 rmescapes(str->text);
5442 exparg.lastp = &str->next;
5443 } else {
5444 *exparg.lastp = NULL;
5445 *savelastp = sp = expsort(*savelastp);
5446 while (sp->next != NULL)
5447 sp = sp->next;
5448 exparg.lastp = &sp->next;
5449 }
5450 str = str->next;
5451 }
5452}
5453
5454
5455/*
5456 * Do metacharacter (i.e. *, ?, [...]) expansion.
5457 */
5458
5459static void
5460expmeta(enddir, name)
5461 char *enddir;
5462 char *name;
5463 {
5464 char *p;
5465 const char *cp;
5466 char *q;
5467 char *start;
5468 char *endname;
5469 int metaflag;
5470 struct stat statb;
5471 DIR *dirp;
5472 struct dirent *dp;
5473 int atend;
5474 int matchdot;
5475
5476 metaflag = 0;
5477 start = name;
5478 for (p = name ; ; p++) {
5479 if (*p == '*' || *p == '?')
5480 metaflag = 1;
5481 else if (*p == '[') {
5482 q = p + 1;
5483 if (*q == '!')
5484 q++;
5485 for (;;) {
5486 while (*q == CTLQUOTEMARK)
5487 q++;
5488 if (*q == CTLESC)
5489 q++;
5490 if (*q == '/' || *q == '\0')
5491 break;
5492 if (*++q == ']') {
5493 metaflag = 1;
5494 break;
5495 }
5496 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005497 } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) {
Eric Andersencb57d552001-06-28 07:25:16 +00005498 metaflag = 1;
5499 } else if (*p == '\0')
5500 break;
5501 else if (*p == CTLQUOTEMARK)
5502 continue;
5503 else if (*p == CTLESC)
5504 p++;
5505 if (*p == '/') {
5506 if (metaflag)
5507 break;
5508 start = p + 1;
5509 }
5510 }
Eric Andersen2870d962001-07-02 17:27:21 +00005511 if (metaflag == 0) { /* we've reached the end of the file name */
Eric Andersencb57d552001-06-28 07:25:16 +00005512 if (enddir != expdir)
5513 metaflag++;
5514 for (p = name ; ; p++) {
5515 if (*p == CTLQUOTEMARK)
5516 continue;
5517 if (*p == CTLESC)
5518 p++;
5519 *enddir++ = *p;
5520 if (*p == '\0')
5521 break;
5522 }
5523 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5524 addfname(expdir);
5525 return;
5526 }
5527 endname = p;
5528 if (start != name) {
5529 p = name;
5530 while (p < start) {
5531 while (*p == CTLQUOTEMARK)
5532 p++;
5533 if (*p == CTLESC)
5534 p++;
5535 *enddir++ = *p++;
5536 }
5537 }
5538 if (enddir == expdir) {
5539 cp = ".";
5540 } else if (enddir == expdir + 1 && *expdir == '/') {
5541 cp = "/";
5542 } else {
5543 cp = expdir;
5544 enddir[-1] = '\0';
5545 }
5546 if ((dirp = opendir(cp)) == NULL)
5547 return;
5548 if (enddir != expdir)
5549 enddir[-1] = '/';
5550 if (*endname == 0) {
5551 atend = 1;
5552 } else {
5553 atend = 0;
5554 *endname++ = '\0';
5555 }
5556 matchdot = 0;
5557 p = start;
5558 while (*p == CTLQUOTEMARK)
5559 p++;
5560 if (*p == CTLESC)
5561 p++;
5562 if (*p == '.')
5563 matchdot++;
5564 while (! int_pending() && (dp = readdir(dirp)) != NULL) {
5565 if (dp->d_name[0] == '.' && ! matchdot)
5566 continue;
5567 if (patmatch(start, dp->d_name, 0)) {
5568 if (atend) {
Eric Andersen2870d962001-07-02 17:27:21 +00005569 strcpy(enddir, dp->d_name);
Eric Andersencb57d552001-06-28 07:25:16 +00005570 addfname(expdir);
5571 } else {
5572 for (p = enddir, cp = dp->d_name;
5573 (*p++ = *cp++) != '\0';)
5574 continue;
5575 p[-1] = '/';
5576 expmeta(p, endname);
5577 }
5578 }
5579 }
5580 closedir(dirp);
5581 if (! atend)
5582 endname[-1] = '/';
5583}
Eric Andersen2870d962001-07-02 17:27:21 +00005584#endif /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005585
5586
Eric Andersencb57d552001-06-28 07:25:16 +00005587
Eric Andersen62483552001-07-10 06:09:16 +00005588#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersencb57d552001-06-28 07:25:16 +00005589/*
5590 * Sort the results of file name expansion. It calculates the number of
5591 * strings to sort and then calls msort (short for merge sort) to do the
5592 * work.
5593 */
5594
5595static struct strlist *
5596expsort(str)
5597 struct strlist *str;
5598 {
5599 int len;
5600 struct strlist *sp;
5601
5602 len = 0;
5603 for (sp = str ; sp ; sp = sp->next)
5604 len++;
5605 return msort(str, len);
5606}
5607
5608
5609static struct strlist *
5610msort(list, len)
5611 struct strlist *list;
5612 int len;
5613{
5614 struct strlist *p, *q = NULL;
5615 struct strlist **lpp;
5616 int half;
5617 int n;
5618
5619 if (len <= 1)
5620 return list;
5621 half = len >> 1;
5622 p = list;
5623 for (n = half ; --n >= 0 ; ) {
5624 q = p;
5625 p = p->next;
5626 }
Eric Andersen2870d962001-07-02 17:27:21 +00005627 q->next = NULL; /* terminate first half of list */
5628 q = msort(list, half); /* sort first half of list */
5629 p = msort(p, len - half); /* sort second half */
Eric Andersencb57d552001-06-28 07:25:16 +00005630 lpp = &list;
5631 for (;;) {
5632 if (strcmp(p->text, q->text) < 0) {
5633 *lpp = p;
5634 lpp = &p->next;
5635 if ((p = *lpp) == NULL) {
5636 *lpp = q;
5637 break;
5638 }
5639 } else {
5640 *lpp = q;
5641 lpp = &q->next;
5642 if ((q = *lpp) == NULL) {
5643 *lpp = p;
5644 break;
5645 }
5646 }
5647 }
5648 return list;
5649}
5650#endif
5651
5652
5653
5654/*
5655 * Returns true if the pattern matches the string.
5656 */
5657
Eric Andersen62483552001-07-10 06:09:16 +00005658#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00005659/* squoted: string might have quote chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005660static int
Eric Andersen2870d962001-07-02 17:27:21 +00005661patmatch(char *pattern, char *string, int squoted)
5662{
Eric Andersencb57d552001-06-28 07:25:16 +00005663 const char *p;
5664 char *q;
5665
5666 p = preglob(pattern);
5667 q = squoted ? _rmescapes(string, RMESCAPE_ALLOC) : string;
5668
5669 return !fnmatch(p, q, 0);
5670}
5671
5672
5673static int
Eric Andersen2870d962001-07-02 17:27:21 +00005674patmatch2(char *pattern, char *string, int squoted)
5675{
Eric Andersencb57d552001-06-28 07:25:16 +00005676 char *p;
5677 int res;
5678
5679 sstrnleft--;
5680 p = grabstackstr(expdest);
5681 res = patmatch(pattern, string, squoted);
5682 ungrabstackstr(p, expdest);
5683 return res;
5684}
5685#else
5686static int
Eric Andersen2870d962001-07-02 17:27:21 +00005687patmatch(char *pattern, char *string, int squoted) {
5688 return pmatch(pattern, string, squoted);
Eric Andersencb57d552001-06-28 07:25:16 +00005689}
5690
5691
5692static int
Eric Andersen2870d962001-07-02 17:27:21 +00005693pmatch(char *pattern, char *string, int squoted)
5694{
Eric Andersencb57d552001-06-28 07:25:16 +00005695 char *p, *q;
5696 char c;
5697
5698 p = pattern;
5699 q = string;
5700 for (;;) {
5701 switch (c = *p++) {
5702 case '\0':
5703 goto breakloop;
5704 case CTLESC:
5705 if (squoted && *q == CTLESC)
5706 q++;
5707 if (*q++ != *p++)
5708 return 0;
5709 break;
5710 case CTLQUOTEMARK:
5711 continue;
5712 case '?':
5713 if (squoted && *q == CTLESC)
5714 q++;
5715 if (*q++ == '\0')
5716 return 0;
5717 break;
5718 case '*':
5719 c = *p;
5720 while (c == CTLQUOTEMARK || c == '*')
5721 c = *++p;
5722 if (c != CTLESC && c != CTLQUOTEMARK &&
5723 c != '?' && c != '*' && c != '[') {
5724 while (*q != c) {
5725 if (squoted && *q == CTLESC &&
5726 q[1] == c)
5727 break;
5728 if (*q == '\0')
5729 return 0;
5730 if (squoted && *q == CTLESC)
5731 q++;
5732 q++;
5733 }
5734 }
5735 do {
5736 if (pmatch(p, q, squoted))
5737 return 1;
5738 if (squoted && *q == CTLESC)
5739 q++;
5740 } while (*q++ != '\0');
5741 return 0;
5742 case '[': {
5743 char *endp;
5744 int invert, found;
5745 char chr;
5746
5747 endp = p;
5748 if (*endp == '!')
5749 endp++;
5750 for (;;) {
5751 while (*endp == CTLQUOTEMARK)
5752 endp++;
5753 if (*endp == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00005754 goto dft; /* no matching ] */
Eric Andersencb57d552001-06-28 07:25:16 +00005755 if (*endp == CTLESC)
5756 endp++;
5757 if (*++endp == ']')
5758 break;
5759 }
5760 invert = 0;
5761 if (*p == '!') {
5762 invert++;
5763 p++;
5764 }
5765 found = 0;
5766 chr = *q++;
5767 if (squoted && chr == CTLESC)
5768 chr = *q++;
5769 if (chr == '\0')
5770 return 0;
5771 c = *p++;
5772 do {
5773 if (c == CTLQUOTEMARK)
5774 continue;
5775 if (c == CTLESC)
5776 c = *p++;
5777 if (*p == '-' && p[1] != ']') {
5778 p++;
5779 while (*p == CTLQUOTEMARK)
5780 p++;
5781 if (*p == CTLESC)
5782 p++;
5783 if (chr >= c && chr <= *p)
5784 found = 1;
5785 p++;
5786 } else {
5787 if (chr == c)
5788 found = 1;
5789 }
5790 } while ((c = *p++) != ']');
5791 if (found == invert)
5792 return 0;
5793 break;
5794 }
Eric Andersen2870d962001-07-02 17:27:21 +00005795dft: default:
Eric Andersencb57d552001-06-28 07:25:16 +00005796 if (squoted && *q == CTLESC)
5797 q++;
5798 if (*q++ != c)
5799 return 0;
5800 break;
5801 }
5802 }
5803breakloop:
5804 if (*q != '\0')
5805 return 0;
5806 return 1;
5807}
5808#endif
5809
5810
5811
5812/*
5813 * Remove any CTLESC characters from a string.
5814 */
5815
Eric Andersen62483552001-07-10 06:09:16 +00005816#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00005817static char *
Eric Andersen2870d962001-07-02 17:27:21 +00005818_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005819{
5820 char *p, *q, *r;
5821 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5822
5823 p = strpbrk(str, qchars);
5824 if (!p) {
5825 return str;
5826 }
5827 q = p;
5828 r = str;
5829 if (flag & RMESCAPE_ALLOC) {
5830 size_t len = p - str;
5831 q = r = stalloc(strlen(p) + len + 1);
5832 if (len > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00005833 memcpy(q, str, len);
5834 q += len;
Eric Andersencb57d552001-06-28 07:25:16 +00005835 }
5836 }
5837 while (*p) {
5838 if (*p == CTLQUOTEMARK) {
5839 p++;
5840 continue;
5841 }
5842 if (*p == CTLESC) {
5843 p++;
5844 if (flag & RMESCAPE_GLOB && *p != '/') {
5845 *q++ = '\\';
5846 }
5847 }
5848 *q++ = *p++;
5849 }
5850 *q = '\0';
5851 return r;
5852}
5853#else
5854static void
5855rmescapes(str)
5856 char *str;
5857{
5858 char *p, *q;
5859
5860 p = str;
5861 while (*p != CTLESC && *p != CTLQUOTEMARK) {
5862 if (*p++ == '\0')
5863 return;
5864 }
5865 q = p;
5866 while (*p) {
5867 if (*p == CTLQUOTEMARK) {
5868 p++;
5869 continue;
5870 }
5871 if (*p == CTLESC)
5872 p++;
5873 *q++ = *p++;
5874 }
5875 *q = '\0';
5876}
5877#endif
5878
5879
5880
5881/*
5882 * See if a pattern matches in a case statement.
5883 */
5884
5885static int
Eric Andersen2870d962001-07-02 17:27:21 +00005886casematch(union node *pattern, const char *val)
5887{
Eric Andersencb57d552001-06-28 07:25:16 +00005888 struct stackmark smark;
5889 int result;
5890 char *p;
5891
5892 setstackmark(&smark);
5893 argbackq = pattern->narg.backquote;
5894 STARTSTACKSTR(expdest);
5895 ifslastp = NULL;
5896 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5897 STPUTC('\0', expdest);
5898 p = grabstackstr(expdest);
Eric Andersen2870d962001-07-02 17:27:21 +00005899 result = patmatch(p, (char *)val, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00005900 popstackmark(&smark);
5901 return result;
5902}
5903
5904/*
5905 * Our own itoa().
5906 */
5907
5908static char *
5909cvtnum(num, buf)
5910 int num;
5911 char *buf;
5912 {
5913 int len;
5914
5915 CHECKSTRSPACE(32, buf);
5916 len = sprintf(buf, "%d", num);
5917 STADJUST(len, buf);
5918 return buf;
5919}
Eric Andersencb57d552001-06-28 07:25:16 +00005920/*
5921 * Editline and history functions (and glue).
5922 */
5923static int histcmd(argc, argv)
5924 int argc;
5925 char **argv;
5926{
5927 error("not compiled with history support");
5928 /* NOTREACHED */
5929}
5930
5931
Eric Andersencb57d552001-06-28 07:25:16 +00005932struct redirtab {
5933 struct redirtab *next;
Russ Dill4db35642001-07-26 05:58:40 +00005934 short renamed[10]; /* Current ash support only 0-9 descriptors */
Eric Andersen34506362001-08-02 05:02:46 +00005935 /* char on arm (and others) can't be negative */
Eric Andersencb57d552001-06-28 07:25:16 +00005936};
5937
Eric Andersen2870d962001-07-02 17:27:21 +00005938static struct redirtab *redirlist;
Eric Andersencb57d552001-06-28 07:25:16 +00005939
5940extern char **environ;
5941
5942
5943
5944/*
5945 * Initialization code.
5946 */
5947
5948static void
Eric Andersen2870d962001-07-02 17:27:21 +00005949init(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00005950
5951 /* from cd.c: */
5952 {
5953 setpwd(0, 0);
5954 }
5955
5956 /* from input.c: */
5957 {
5958 basepf.nextc = basepf.buf = basebuf;
5959 }
5960
Eric Andersencb57d552001-06-28 07:25:16 +00005961 /* from var.c: */
5962 {
5963 char **envp;
5964 char ppid[32];
5965
5966 initvar();
5967 for (envp = environ ; *envp ; envp++) {
5968 if (strchr(*envp, '=')) {
5969 setvareq(*envp, VEXPORT|VTEXTFIXED);
5970 }
5971 }
5972
Eric Andersen3102ac42001-07-06 04:26:23 +00005973 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
Eric Andersencb57d552001-06-28 07:25:16 +00005974 setvar("PPID", ppid, 0);
5975 }
5976}
5977
5978
5979
5980/*
5981 * This routine is called when an error or an interrupt occurs in an
5982 * interactive shell and control is returned to the main command loop.
5983 */
5984
Eric Andersen2870d962001-07-02 17:27:21 +00005985/* 1 == check for aliases, 2 == also check for assignments */
Eric Andersen7467c8d2001-07-12 20:26:32 +00005986static int checkalias; /* also used in no alias mode for check assignments */
Eric Andersen2870d962001-07-02 17:27:21 +00005987
Eric Andersencb57d552001-06-28 07:25:16 +00005988static void
Eric Andersen2870d962001-07-02 17:27:21 +00005989reset(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00005990
5991 /* from eval.c: */
5992 {
5993 evalskip = 0;
5994 loopnest = 0;
5995 funcnest = 0;
5996 }
5997
5998 /* from input.c: */
5999 {
6000 if (exception != EXSHELLPROC)
Eric Andersen2870d962001-07-02 17:27:21 +00006001 parselleft = parsenleft = 0; /* clear input buffer */
Eric Andersencb57d552001-06-28 07:25:16 +00006002 popallfiles();
6003 }
6004
6005 /* from parser.c: */
6006 {
6007 tokpushback = 0;
6008 checkkwd = 0;
6009 checkalias = 0;
6010 }
6011
6012 /* from redir.c: */
6013 {
6014 while (redirlist)
6015 popredir();
6016 }
6017
Eric Andersencb57d552001-06-28 07:25:16 +00006018}
6019
6020
6021
6022/*
Eric Andersencb57d552001-06-28 07:25:16 +00006023 * This file implements the input routines used by the parser.
6024 */
6025
6026#ifdef BB_FEATURE_COMMAND_EDITING
Eric Andersencb57d552001-06-28 07:25:16 +00006027static const char * cmdedit_prompt;
6028static inline void putprompt(const char *s) {
6029 cmdedit_prompt = s;
6030}
6031#else
6032static inline void putprompt(const char *s) {
6033 out2str(s);
6034}
6035#endif
6036
Eric Andersen2870d962001-07-02 17:27:21 +00006037#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
Eric Andersencb57d552001-06-28 07:25:16 +00006038
Eric Andersencb57d552001-06-28 07:25:16 +00006039
Eric Andersencb57d552001-06-28 07:25:16 +00006040
Eric Andersen2870d962001-07-02 17:27:21 +00006041/*
6042 * Same as pgetc(), but ignores PEOA.
6043 */
Eric Andersencb57d552001-06-28 07:25:16 +00006044
Eric Andersen2870d962001-07-02 17:27:21 +00006045#ifdef ASH_ALIAS
6046static int
Eric Andersen74400cc2001-10-18 04:11:39 +00006047pgetc2(void)
Eric Andersen2870d962001-07-02 17:27:21 +00006048{
6049 int c;
6050 do {
6051 c = pgetc_macro();
6052 } while (c == PEOA);
6053 return c;
Eric Andersencb57d552001-06-28 07:25:16 +00006054}
Eric Andersen2870d962001-07-02 17:27:21 +00006055#else
6056static inline int pgetc2() { return pgetc_macro(); }
Eric Andersencb57d552001-06-28 07:25:16 +00006057#endif
6058
Eric Andersencb57d552001-06-28 07:25:16 +00006059/*
6060 * Read a line from the script.
6061 */
6062
Eric Andersen62483552001-07-10 06:09:16 +00006063static inline char *
Eric Andersen2870d962001-07-02 17:27:21 +00006064pfgets(char *line, int len)
Eric Andersencb57d552001-06-28 07:25:16 +00006065{
6066 char *p = line;
6067 int nleft = len;
6068 int c;
6069
6070 while (--nleft > 0) {
6071 c = pgetc2();
6072 if (c == PEOF) {
6073 if (p == line)
6074 return NULL;
6075 break;
6076 }
6077 *p++ = c;
6078 if (c == '\n')
6079 break;
6080 }
6081 *p = '\0';
6082 return line;
6083}
6084
Eric Andersen62483552001-07-10 06:09:16 +00006085static inline int
Eric Andersen2870d962001-07-02 17:27:21 +00006086preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006087{
6088 int nr;
6089 char *buf = parsefile->buf;
6090 parsenextc = buf;
6091
6092retry:
6093#ifdef BB_FEATURE_COMMAND_EDITING
6094 {
Eric Andersen34506362001-08-02 05:02:46 +00006095 if (!iflag || parsefile->fd)
Eric Andersen7467c8d2001-07-12 20:26:32 +00006096 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersen2870d962001-07-02 17:27:21 +00006097 else {
Eric Andersen044228d2001-07-17 01:12:36 +00006098 nr = cmdedit_read_input((char*)cmdedit_prompt, buf);
Eric Andersencb57d552001-06-28 07:25:16 +00006099 }
6100 }
6101#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00006102 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006103#endif
6104
6105 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006106 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6107 int flags = fcntl(0, F_GETFL, 0);
6108 if (flags >= 0 && flags & O_NONBLOCK) {
6109 flags &=~ O_NONBLOCK;
6110 if (fcntl(0, F_SETFL, flags) >= 0) {
6111 out2str("sh: turning off NDELAY mode\n");
6112 goto retry;
6113 }
6114 }
6115 }
6116 }
6117 return nr;
6118}
6119
Eric Andersen2870d962001-07-02 17:27:21 +00006120static void
6121popstring(void)
6122{
6123 struct strpush *sp = parsefile->strpush;
6124
6125 INTOFF;
6126#ifdef ASH_ALIAS
6127 if (sp->ap) {
6128 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6129 if (!checkalias) {
6130 checkalias = 1;
6131 }
6132 }
6133 if (sp->string != sp->ap->val) {
6134 ckfree(sp->string);
6135 }
6136
6137 sp->ap->flag &= ~ALIASINUSE;
6138 if (sp->ap->flag & ALIASDEAD) {
6139 unalias(sp->ap->name);
6140 }
6141 }
6142#endif
6143 parsenextc = sp->prevstring;
6144 parsenleft = sp->prevnleft;
6145/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6146 parsefile->strpush = sp->prev;
6147 if (sp != &(parsefile->basestrpush))
6148 ckfree(sp);
6149 INTON;
6150}
6151
6152
Eric Andersencb57d552001-06-28 07:25:16 +00006153/*
6154 * Refill the input buffer and return the next input character:
6155 *
6156 * 1) If a string was pushed back on the input, pop it;
6157 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6158 * from a string so we can't refill the buffer, return EOF.
6159 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6160 * 4) Process input up to the next newline, deleting nul characters.
6161 */
6162
6163static int
Eric Andersen2870d962001-07-02 17:27:21 +00006164preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006165{
6166 char *p, *q;
6167 int more;
6168 char savec;
6169
6170 while (parsefile->strpush) {
Eric Andersen2870d962001-07-02 17:27:21 +00006171#ifdef ASH_ALIAS
6172 if (parsenleft == -1 && parsefile->strpush->ap &&
6173 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00006174 return PEOA;
6175 }
Eric Andersen2870d962001-07-02 17:27:21 +00006176#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006177 popstring();
6178 if (--parsenleft >= 0)
6179 return (*parsenextc++);
6180 }
6181 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6182 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00006183 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00006184
6185again:
6186 if (parselleft <= 0) {
6187 if ((parselleft = preadfd()) <= 0) {
6188 parselleft = parsenleft = EOF_NLEFT;
6189 return PEOF;
6190 }
6191 }
6192
6193 q = p = parsenextc;
6194
6195 /* delete nul characters */
6196 for (more = 1; more;) {
6197 switch (*p) {
6198 case '\0':
Eric Andersen2870d962001-07-02 17:27:21 +00006199 p++; /* Skip nul */
Eric Andersencb57d552001-06-28 07:25:16 +00006200 goto check;
6201
6202
6203 case '\n':
6204 parsenleft = q - parsenextc;
6205 more = 0; /* Stop processing here */
6206 break;
6207 }
6208
6209 *q++ = *p++;
6210check:
6211 if (--parselleft <= 0 && more) {
6212 parsenleft = q - parsenextc - 1;
6213 if (parsenleft < 0)
6214 goto again;
6215 more = 0;
6216 }
6217 }
6218
6219 savec = *q;
6220 *q = '\0';
6221
6222 if (vflag) {
6223 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00006224 }
6225
6226 *q = savec;
6227
6228 return *parsenextc++;
6229}
6230
Eric Andersencb57d552001-06-28 07:25:16 +00006231
6232/*
6233 * Push a string back onto the input at this current parsefile level.
6234 * We handle aliases this way.
6235 */
6236static void
Eric Andersen2870d962001-07-02 17:27:21 +00006237pushstring(char *s, int len, void *ap)
6238{
Eric Andersencb57d552001-06-28 07:25:16 +00006239 struct strpush *sp;
6240
6241 INTOFF;
6242/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6243 if (parsefile->strpush) {
6244 sp = ckmalloc(sizeof (struct strpush));
6245 sp->prev = parsefile->strpush;
6246 parsefile->strpush = sp;
6247 } else
6248 sp = parsefile->strpush = &(parsefile->basestrpush);
6249 sp->prevstring = parsenextc;
6250 sp->prevnleft = parsenleft;
Eric Andersen2870d962001-07-02 17:27:21 +00006251#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00006252 sp->ap = (struct alias *)ap;
6253 if (ap) {
6254 ((struct alias *)ap)->flag |= ALIASINUSE;
6255 sp->string = s;
6256 }
Eric Andersen2870d962001-07-02 17:27:21 +00006257#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006258 parsenextc = s;
6259 parsenleft = len;
6260 INTON;
6261}
6262
Eric Andersencb57d552001-06-28 07:25:16 +00006263
Eric Andersencb57d552001-06-28 07:25:16 +00006264/*
6265 * Like setinputfile, but takes input from a string.
6266 */
6267
6268static void
Eric Andersen62483552001-07-10 06:09:16 +00006269setinputstring(char *string)
6270{
Eric Andersencb57d552001-06-28 07:25:16 +00006271 INTOFF;
6272 pushfile();
6273 parsenextc = string;
6274 parsenleft = strlen(string);
6275 parsefile->buf = NULL;
6276 plinno = 1;
6277 INTON;
6278}
6279
6280
6281
6282/*
6283 * To handle the "." command, a stack of input files is used. Pushfile
6284 * adds a new entry to the stack and popfile restores the previous level.
6285 */
6286
6287static void
Eric Andersen2870d962001-07-02 17:27:21 +00006288pushfile(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00006289 struct parsefile *pf;
6290
6291 parsefile->nleft = parsenleft;
6292 parsefile->lleft = parselleft;
6293 parsefile->nextc = parsenextc;
6294 parsefile->linno = plinno;
6295 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6296 pf->prev = parsefile;
6297 pf->fd = -1;
6298 pf->strpush = NULL;
6299 pf->basestrpush.prev = NULL;
6300 parsefile = pf;
6301}
6302
Eric Andersen2870d962001-07-02 17:27:21 +00006303#ifdef JOBS
6304static void restartjob (struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00006305#endif
Eric Andersen2870d962001-07-02 17:27:21 +00006306static void freejob (struct job *);
6307static struct job *getjob (const char *);
6308static int dowait (int, struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00006309static void waitonint(int);
6310
6311
Eric Andersen2870d962001-07-02 17:27:21 +00006312/*
6313 * We keep track of whether or not fd0 has been redirected. This is for
6314 * background commands, where we want to redirect fd0 to /dev/null only
6315 * if it hasn't already been redirected.
6316*/
6317static int fd0_redirected = 0;
6318
6319/* Return true if fd 0 has already been redirected at least once. */
6320static inline int
Eric Andersen74400cc2001-10-18 04:11:39 +00006321fd0_redirected_p (void)
6322{
Eric Andersen2870d962001-07-02 17:27:21 +00006323 return fd0_redirected != 0;
6324}
6325
Eric Andersen62483552001-07-10 06:09:16 +00006326static void dupredirect (const union node *, int, int fd1dup);
Eric Andersen2870d962001-07-02 17:27:21 +00006327
6328#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006329/*
6330 * Turn job control on and off.
6331 *
6332 * Note: This code assumes that the third arg to ioctl is a character
6333 * pointer, which is true on Berkeley systems but not System V. Since
6334 * System V doesn't have job control yet, this isn't a problem now.
6335 */
6336
Eric Andersen2870d962001-07-02 17:27:21 +00006337
Eric Andersencb57d552001-06-28 07:25:16 +00006338
6339static void setjobctl(int enable)
6340{
6341#ifdef OLD_TTY_DRIVER
6342 int ldisc;
6343#endif
6344
6345 if (enable == jobctl || rootshell == 0)
6346 return;
6347 if (enable) {
6348 do { /* while we are in the background */
6349#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006350 if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006351#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006352 initialpgrp = tcgetpgrp(2);
Eric Andersencb57d552001-06-28 07:25:16 +00006353 if (initialpgrp < 0) {
6354#endif
Eric Andersen8c145dc2001-07-10 16:57:09 +00006355 out2str("sh: can't access tty; job control turned off\n");
Eric Andersencb57d552001-06-28 07:25:16 +00006356 mflag = 0;
6357 return;
6358 }
6359 if (initialpgrp == -1)
6360 initialpgrp = getpgrp();
6361 else if (initialpgrp != getpgrp()) {
6362 killpg(initialpgrp, SIGTTIN);
6363 continue;
6364 }
6365 } while (0);
6366#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006367 if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
Eric Andersen8c145dc2001-07-10 16:57:09 +00006368 out2str("sh: need new tty driver to run job control; job control turned off\n");
Eric Andersencb57d552001-06-28 07:25:16 +00006369 mflag = 0;
6370 return;
6371 }
6372#endif
6373 setsignal(SIGTSTP);
6374 setsignal(SIGTTOU);
6375 setsignal(SIGTTIN);
6376 setpgid(0, rootpid);
6377#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006378 ioctl(2, TIOCSPGRP, (char *)&rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00006379#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006380 tcsetpgrp(2, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00006381#endif
Eric Andersen8c145dc2001-07-10 16:57:09 +00006382 } else { /* turning job control off */
Eric Andersencb57d552001-06-28 07:25:16 +00006383 setpgid(0, initialpgrp);
6384#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006385 ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006386#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006387 tcsetpgrp(2, initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006388#endif
6389 setsignal(SIGTSTP);
6390 setsignal(SIGTTOU);
6391 setsignal(SIGTTIN);
6392 }
6393 jobctl = enable;
6394}
6395#endif
6396
6397
Eric Andersen2870d962001-07-02 17:27:21 +00006398#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006399static int
6400killcmd(argc, argv)
6401 int argc;
6402 char **argv;
6403{
6404 int signo = -1;
6405 int list = 0;
6406 int i;
6407 pid_t pid;
6408 struct job *jp;
6409
6410 if (argc <= 1) {
6411usage:
6412 error(
6413"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6414"kill -l [exitstatus]"
6415 );
6416 }
6417
6418 if (*argv[1] == '-') {
6419 signo = decode_signal(argv[1] + 1, 1);
6420 if (signo < 0) {
6421 int c;
6422
6423 while ((c = nextopt("ls:")) != '\0')
6424 switch (c) {
6425 case 'l':
6426 list = 1;
6427 break;
6428 case 's':
6429 signo = decode_signal(optionarg, 1);
6430 if (signo < 0) {
6431 error(
6432 "invalid signal number or name: %s",
6433 optionarg
6434 );
6435 }
Eric Andersen2870d962001-07-02 17:27:21 +00006436 break;
Eric Andersencb57d552001-06-28 07:25:16 +00006437#ifdef DEBUG
6438 default:
6439 error(
6440 "nextopt returned character code 0%o", c);
6441#endif
6442 }
6443 } else
6444 argptr++;
6445 }
6446
6447 if (!list && signo < 0)
6448 signo = SIGTERM;
6449
6450 if ((signo < 0 || !*argptr) ^ list) {
6451 goto usage;
6452 }
6453
6454 if (list) {
Eric Andersen34506362001-08-02 05:02:46 +00006455 const char *name;
6456
Eric Andersencb57d552001-06-28 07:25:16 +00006457 if (!*argptr) {
6458 out1str("0\n");
6459 for (i = 1; i < NSIG; i++) {
Eric Andersen34506362001-08-02 05:02:46 +00006460 name = u_signal_names(0, &i, 1);
6461 if(name)
6462 printf(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006463 }
6464 return 0;
6465 }
Eric Andersen34506362001-08-02 05:02:46 +00006466 name = u_signal_names(*argptr, &signo, -1);
6467 if (name)
6468 printf(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006469 else
6470 error("invalid signal number or exit status: %s",
6471 *argptr);
6472 return 0;
6473 }
6474
6475 do {
6476 if (**argptr == '%') {
6477 jp = getjob(*argptr);
6478 if (jp->jobctl == 0)
6479 error("job %s not created under job control",
6480 *argptr);
6481 pid = -jp->ps[0].pid;
6482 } else
6483 pid = atoi(*argptr);
6484 if (kill(pid, signo) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00006485 error("%s: %m", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006486 } while (*++argptr);
6487
6488 return 0;
6489}
6490
6491static int
6492fgcmd(argc, argv)
6493 int argc;
6494 char **argv;
6495{
6496 struct job *jp;
6497 int pgrp;
6498 int status;
6499
6500 jp = getjob(argv[1]);
6501 if (jp->jobctl == 0)
6502 error("job not created under job control");
6503 pgrp = jp->ps[0].pid;
6504#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006505 ioctl(2, TIOCSPGRP, (char *)&pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006506#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006507 tcsetpgrp(2, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006508#endif
6509 restartjob(jp);
6510 INTOFF;
6511 status = waitforjob(jp);
6512 INTON;
6513 return status;
6514}
6515
6516
6517static int
6518bgcmd(argc, argv)
6519 int argc;
6520 char **argv;
6521{
6522 struct job *jp;
6523
6524 do {
6525 jp = getjob(*++argv);
6526 if (jp->jobctl == 0)
6527 error("job not created under job control");
6528 restartjob(jp);
6529 } while (--argc > 1);
6530 return 0;
6531}
6532
6533
6534static void
6535restartjob(jp)
6536 struct job *jp;
6537{
6538 struct procstat *ps;
6539 int i;
6540
6541 if (jp->state == JOBDONE)
6542 return;
6543 INTOFF;
6544 killpg(jp->ps[0].pid, SIGCONT);
6545 for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
6546 if (WIFSTOPPED(ps->status)) {
6547 ps->status = -1;
6548 jp->state = 0;
6549 }
6550 }
6551 INTON;
6552}
6553#endif
6554
Eric Andersen2870d962001-07-02 17:27:21 +00006555static void showjobs(int change);
6556
Eric Andersencb57d552001-06-28 07:25:16 +00006557
6558static int
6559jobscmd(argc, argv)
6560 int argc;
6561 char **argv;
6562{
6563 showjobs(0);
6564 return 0;
6565}
6566
6567
6568/*
6569 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6570 * statuses have changed since the last call to showjobs.
6571 *
6572 * If the shell is interrupted in the process of creating a job, the
6573 * result may be a job structure containing zero processes. Such structures
6574 * will be freed here.
6575 */
6576
6577static void
6578showjobs(change)
6579 int change;
6580{
6581 int jobno;
6582 int procno;
6583 int i;
6584 struct job *jp;
6585 struct procstat *ps;
6586 int col;
6587 char s[64];
6588
6589 TRACE(("showjobs(%d) called\n", change));
6590 while (dowait(0, (struct job *)NULL) > 0);
6591 for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
6592 if (! jp->used)
6593 continue;
6594 if (jp->nprocs == 0) {
6595 freejob(jp);
6596 continue;
6597 }
6598 if (change && ! jp->changed)
6599 continue;
6600 procno = jp->nprocs;
Eric Andersen2870d962001-07-02 17:27:21 +00006601 for (ps = jp->ps ; ; ps++) { /* for each process */
Eric Andersencb57d552001-06-28 07:25:16 +00006602 if (ps == jp->ps)
Eric Andersen3102ac42001-07-06 04:26:23 +00006603 snprintf(s, 64, "[%d] %ld ", jobno,
Eric Andersencb57d552001-06-28 07:25:16 +00006604 (long)ps->pid);
6605 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006606 snprintf(s, 64, " %ld ",
Eric Andersencb57d552001-06-28 07:25:16 +00006607 (long)ps->pid);
6608 out1str(s);
6609 col = strlen(s);
6610 s[0] = '\0';
6611 if (ps->status == -1) {
6612 /* don't print anything */
6613 } else if (WIFEXITED(ps->status)) {
Eric Andersen3102ac42001-07-06 04:26:23 +00006614 snprintf(s, 64, "Exit %d",
Eric Andersencb57d552001-06-28 07:25:16 +00006615 WEXITSTATUS(ps->status));
6616 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00006617#ifdef JOBS
6618 if (WIFSTOPPED(ps->status))
Eric Andersencb57d552001-06-28 07:25:16 +00006619 i = WSTOPSIG(ps->status);
6620 else /* WIFSIGNALED(ps->status) */
6621#endif
6622 i = WTERMSIG(ps->status);
6623 if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
Eric Andersen2870d962001-07-02 17:27:21 +00006624 strcpy(s, sys_siglist[i & 0x7F]);
Eric Andersencb57d552001-06-28 07:25:16 +00006625 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006626 snprintf(s, 64, "Signal %d", i & 0x7F);
Eric Andersencb57d552001-06-28 07:25:16 +00006627 if (WCOREDUMP(ps->status))
6628 strcat(s, " (core dumped)");
6629 }
6630 out1str(s);
6631 col += strlen(s);
Eric Andersen62483552001-07-10 06:09:16 +00006632 printf(
Eric Andersencb57d552001-06-28 07:25:16 +00006633 "%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ',
6634 ps->cmd
6635 );
6636 if (--procno <= 0)
6637 break;
6638 }
6639 jp->changed = 0;
6640 if (jp->state == JOBDONE) {
6641 freejob(jp);
6642 }
6643 }
6644}
6645
6646
6647/*
6648 * Mark a job structure as unused.
6649 */
6650
6651static void
Eric Andersen62483552001-07-10 06:09:16 +00006652freejob(struct job *jp)
6653{
6654 const struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006655 int i;
6656
6657 INTOFF;
6658 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6659 if (ps->cmd != nullstr)
6660 ckfree(ps->cmd);
6661 }
6662 if (jp->ps != &jp->ps0)
6663 ckfree(jp->ps);
6664 jp->used = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006665#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006666 if (curjob == jp - jobtab + 1)
6667 curjob = 0;
6668#endif
6669 INTON;
6670}
6671
6672
6673
6674static int
6675waitcmd(argc, argv)
6676 int argc;
6677 char **argv;
6678{
6679 struct job *job;
6680 int status, retval;
6681 struct job *jp;
6682
6683 if (--argc > 0) {
6684start:
6685 job = getjob(*++argv);
6686 } else {
6687 job = NULL;
6688 }
Eric Andersen2870d962001-07-02 17:27:21 +00006689 for (;;) { /* loop until process terminated or stopped */
Eric Andersencb57d552001-06-28 07:25:16 +00006690 if (job != NULL) {
6691 if (job->state) {
6692 status = job->ps[job->nprocs - 1].status;
6693 if (! iflag)
6694 freejob(job);
6695 if (--argc) {
6696 goto start;
6697 }
6698 if (WIFEXITED(status))
6699 retval = WEXITSTATUS(status);
Eric Andersen2870d962001-07-02 17:27:21 +00006700#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006701 else if (WIFSTOPPED(status))
6702 retval = WSTOPSIG(status) + 128;
6703#endif
6704 else {
6705 /* XXX: limits number of signals */
6706 retval = WTERMSIG(status) + 128;
6707 }
6708 return retval;
6709 }
6710 } else {
6711 for (jp = jobtab ; ; jp++) {
Eric Andersen2870d962001-07-02 17:27:21 +00006712 if (jp >= jobtab + njobs) { /* no running procs */
Eric Andersencb57d552001-06-28 07:25:16 +00006713 return 0;
6714 }
6715 if (jp->used && jp->state == 0)
6716 break;
6717 }
6718 }
6719 if (dowait(2, 0) < 0 && errno == EINTR) {
6720 return 129;
6721 }
6722 }
6723}
6724
6725
6726
6727/*
6728 * Convert a job name to a job structure.
6729 */
6730
6731static struct job *
Eric Andersen2870d962001-07-02 17:27:21 +00006732getjob(const char *name)
6733{
Eric Andersencb57d552001-06-28 07:25:16 +00006734 int jobno;
6735 struct job *jp;
6736 int pid;
6737 int i;
6738
6739 if (name == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00006740#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006741currentjob:
6742 if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
6743 error("No current job");
6744 return &jobtab[jobno - 1];
6745#else
6746 error("No current job");
6747#endif
6748 } else if (name[0] == '%') {
6749 if (is_digit(name[1])) {
6750 jobno = number(name + 1);
6751 if (jobno > 0 && jobno <= njobs
6752 && jobtab[jobno - 1].used != 0)
6753 return &jobtab[jobno - 1];
Eric Andersen2870d962001-07-02 17:27:21 +00006754#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006755 } else if (name[1] == '%' && name[2] == '\0') {
6756 goto currentjob;
6757#endif
6758 } else {
6759 struct job *found = NULL;
6760 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
6761 if (jp->used && jp->nprocs > 0
6762 && prefix(name + 1, jp->ps[0].cmd)) {
6763 if (found)
6764 error("%s: ambiguous", name);
6765 found = jp;
6766 }
6767 }
6768 if (found)
6769 return found;
6770 }
Eric Andersen2870d962001-07-02 17:27:21 +00006771 } else if (is_number(name, &pid)) {
Eric Andersencb57d552001-06-28 07:25:16 +00006772 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
6773 if (jp->used && jp->nprocs > 0
6774 && jp->ps[jp->nprocs - 1].pid == pid)
6775 return jp;
6776 }
6777 }
6778 error("No such job: %s", name);
6779 /* NOTREACHED */
6780}
6781
6782
6783
6784/*
6785 * Return a new job structure,
6786 */
6787
Eric Andersen2870d962001-07-02 17:27:21 +00006788static struct job *
Eric Andersen62483552001-07-10 06:09:16 +00006789makejob(const union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00006790{
6791 int i;
6792 struct job *jp;
6793
6794 for (i = njobs, jp = jobtab ; ; jp++) {
6795 if (--i < 0) {
6796 INTOFF;
6797 if (njobs == 0) {
6798 jobtab = ckmalloc(4 * sizeof jobtab[0]);
6799 } else {
6800 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
6801 memcpy(jp, jobtab, njobs * sizeof jp[0]);
6802 /* Relocate `ps' pointers */
6803 for (i = 0; i < njobs; i++)
6804 if (jp[i].ps == &jobtab[i].ps0)
6805 jp[i].ps = &jp[i].ps0;
6806 ckfree(jobtab);
6807 jobtab = jp;
6808 }
6809 jp = jobtab + njobs;
6810 for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
6811 INTON;
6812 break;
6813 }
6814 if (jp->used == 0)
6815 break;
6816 }
6817 INTOFF;
6818 jp->state = 0;
6819 jp->used = 1;
6820 jp->changed = 0;
6821 jp->nprocs = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006822#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006823 jp->jobctl = jobctl;
6824#endif
6825 if (nprocs > 1) {
6826 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
6827 } else {
6828 jp->ps = &jp->ps0;
6829 }
6830 INTON;
6831 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
6832 jp - jobtab + 1));
6833 return jp;
6834}
6835
6836
6837/*
6838 * Fork of a subshell. If we are doing job control, give the subshell its
6839 * own process group. Jp is a job structure that the job is to be added to.
6840 * N is the command that will be evaluated by the child. Both jp and n may
6841 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00006842 * FORK_FG - Fork off a foreground process.
6843 * FORK_BG - Fork off a background process.
6844 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
6845 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00006846 *
6847 * When job control is turned off, background processes have their standard
6848 * input redirected to /dev/null (except for the second and later processes
6849 * in a pipeline).
6850 */
6851
Eric Andersen2870d962001-07-02 17:27:21 +00006852
6853
Eric Andersencb57d552001-06-28 07:25:16 +00006854static int
Eric Andersen62483552001-07-10 06:09:16 +00006855forkshell(struct job *jp, const union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00006856{
6857 int pid;
Eric Andersen62483552001-07-10 06:09:16 +00006858#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006859 int pgrp;
Eric Andersen62483552001-07-10 06:09:16 +00006860#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006861 const char *devnull = _PATH_DEVNULL;
6862 const char *nullerr = "Can't open %s";
6863
6864 TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
6865 mode));
6866 INTOFF;
6867 pid = fork();
6868 if (pid == -1) {
6869 TRACE(("Fork failed, errno=%d\n", errno));
6870 INTON;
6871 error("Cannot fork");
6872 }
6873 if (pid == 0) {
6874 struct job *p;
6875 int wasroot;
6876 int i;
6877
6878 TRACE(("Child shell %d\n", getpid()));
6879 wasroot = rootshell;
6880 rootshell = 0;
6881 closescript();
6882 INTON;
6883 clear_traps();
Eric Andersen2870d962001-07-02 17:27:21 +00006884#ifdef JOBS
6885 jobctl = 0; /* do job control only in root shell */
Eric Andersencb57d552001-06-28 07:25:16 +00006886 if (wasroot && mode != FORK_NOJOB && mflag) {
6887 if (jp == NULL || jp->nprocs == 0)
6888 pgrp = getpid();
6889 else
6890 pgrp = jp->ps[0].pid;
6891 setpgid(0, pgrp);
6892 if (mode == FORK_FG) {
6893 /*** this causes superfluous TIOCSPGRPS ***/
6894#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006895 if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006896 error("TIOCSPGRP failed, errno=%d", errno);
6897#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006898 if (tcsetpgrp(2, pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006899 error("tcsetpgrp failed, errno=%d", errno);
6900#endif
6901 }
6902 setsignal(SIGTSTP);
6903 setsignal(SIGTTOU);
6904 } else if (mode == FORK_BG) {
6905 ignoresig(SIGINT);
6906 ignoresig(SIGQUIT);
6907 if ((jp == NULL || jp->nprocs == 0) &&
6908 ! fd0_redirected_p ()) {
6909 close(0);
6910 if (open(devnull, O_RDONLY) != 0)
6911 error(nullerr, devnull);
6912 }
6913 }
6914#else
6915 if (mode == FORK_BG) {
6916 ignoresig(SIGINT);
6917 ignoresig(SIGQUIT);
6918 if ((jp == NULL || jp->nprocs == 0) &&
6919 ! fd0_redirected_p ()) {
6920 close(0);
6921 if (open(devnull, O_RDONLY) != 0)
6922 error(nullerr, devnull);
6923 }
6924 }
6925#endif
6926 for (i = njobs, p = jobtab ; --i >= 0 ; p++)
6927 if (p->used)
6928 freejob(p);
6929 if (wasroot && iflag) {
6930 setsignal(SIGINT);
6931 setsignal(SIGQUIT);
6932 setsignal(SIGTERM);
6933 }
6934 return pid;
6935 }
Eric Andersen62483552001-07-10 06:09:16 +00006936#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006937 if (rootshell && mode != FORK_NOJOB && mflag) {
6938 if (jp == NULL || jp->nprocs == 0)
6939 pgrp = pid;
6940 else
6941 pgrp = jp->ps[0].pid;
6942 setpgid(pid, pgrp);
6943 }
Eric Andersen62483552001-07-10 06:09:16 +00006944#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006945 if (mode == FORK_BG)
Eric Andersen2870d962001-07-02 17:27:21 +00006946 backgndpid = pid; /* set $! */
Eric Andersencb57d552001-06-28 07:25:16 +00006947 if (jp) {
6948 struct procstat *ps = &jp->ps[jp->nprocs++];
6949 ps->pid = pid;
6950 ps->status = -1;
6951 ps->cmd = nullstr;
6952 if (iflag && rootshell && n)
6953 ps->cmd = commandtext(n);
6954 }
6955 INTON;
6956 TRACE(("In parent shell: child = %d\n", pid));
6957 return pid;
6958}
6959
6960
6961
6962/*
6963 * Wait for job to finish.
6964 *
6965 * Under job control we have the problem that while a child process is
6966 * running interrupts generated by the user are sent to the child but not
6967 * to the shell. This means that an infinite loop started by an inter-
6968 * active user may be hard to kill. With job control turned off, an
6969 * interactive user may place an interactive program inside a loop. If
6970 * the interactive program catches interrupts, the user doesn't want
6971 * these interrupts to also abort the loop. The approach we take here
6972 * is to have the shell ignore interrupt signals while waiting for a
6973 * forground process to terminate, and then send itself an interrupt
6974 * signal if the child process was terminated by an interrupt signal.
6975 * Unfortunately, some programs want to do a bit of cleanup and then
6976 * exit on interrupt; unless these processes terminate themselves by
6977 * sending a signal to themselves (instead of calling exit) they will
6978 * confuse this approach.
6979 */
6980
6981static int
Eric Andersen62483552001-07-10 06:09:16 +00006982waitforjob(struct job *jp)
6983{
Eric Andersen2870d962001-07-02 17:27:21 +00006984#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006985 int mypgrp = getpgrp();
6986#endif
6987 int status;
6988 int st;
6989 struct sigaction act, oact;
6990
6991 INTOFF;
6992 intreceived = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006993#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006994 if (!jobctl) {
6995#else
6996 if (!iflag) {
6997#endif
6998 sigaction(SIGINT, 0, &act);
6999 act.sa_handler = waitonint;
7000 sigaction(SIGINT, &act, &oact);
7001 }
7002 TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
7003 while (jp->state == 0) {
7004 dowait(1, jp);
7005 }
Eric Andersen2870d962001-07-02 17:27:21 +00007006#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007007 if (!jobctl) {
7008#else
7009 if (!iflag) {
7010#endif
7011 sigaction(SIGINT, &oact, 0);
7012 if (intreceived && trap[SIGINT]) kill(getpid(), SIGINT);
7013 }
Eric Andersen2870d962001-07-02 17:27:21 +00007014#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007015 if (jp->jobctl) {
7016#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00007017 if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007018 error("TIOCSPGRP failed, errno=%d\n", errno);
7019#else
Eric Andersen3102ac42001-07-06 04:26:23 +00007020 if (tcsetpgrp(2, mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007021 error("tcsetpgrp failed, errno=%d\n", errno);
7022#endif
7023 }
7024 if (jp->state == JOBSTOPPED)
7025 curjob = jp - jobtab + 1;
7026#endif
7027 status = jp->ps[jp->nprocs - 1].status;
7028 /* convert to 8 bits */
7029 if (WIFEXITED(status))
7030 st = WEXITSTATUS(status);
Eric Andersen2870d962001-07-02 17:27:21 +00007031#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007032 else if (WIFSTOPPED(status))
7033 st = WSTOPSIG(status) + 128;
7034#endif
7035 else
7036 st = WTERMSIG(status) + 128;
Eric Andersen2870d962001-07-02 17:27:21 +00007037#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007038 if (jp->jobctl) {
7039 /*
7040 * This is truly gross.
7041 * If we're doing job control, then we did a TIOCSPGRP which
7042 * caused us (the shell) to no longer be in the controlling
7043 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7044 * intuit from the subprocess exit status whether a SIGINT
7045 * occured, and if so interrupt ourselves. Yuck. - mycroft
7046 */
7047 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
7048 raise(SIGINT);
7049 }
Eric Andersen2870d962001-07-02 17:27:21 +00007050 if (jp->state == JOBDONE)
7051
Eric Andersencb57d552001-06-28 07:25:16 +00007052#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007053 freejob(jp);
7054 INTON;
7055 return st;
7056}
7057
7058
7059
7060/*
7061 * Wait for a process to terminate.
7062 */
7063
Eric Andersen62483552001-07-10 06:09:16 +00007064/*
7065 * Do a wait system call. If job control is compiled in, we accept
7066 * stopped processes. If block is zero, we return a value of zero
7067 * rather than blocking.
7068 *
7069 * System V doesn't have a non-blocking wait system call. It does
7070 * have a SIGCLD signal that is sent to a process when one of it's
7071 * children dies. The obvious way to use SIGCLD would be to install
7072 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7073 * was received, and have waitproc bump another counter when it got
7074 * the status of a process. Waitproc would then know that a wait
7075 * system call would not block if the two counters were different.
7076 * This approach doesn't work because if a process has children that
7077 * have not been waited for, System V will send it a SIGCLD when it
7078 * installs a signal handler for SIGCLD. What this means is that when
7079 * a child exits, the shell will be sent SIGCLD signals continuously
7080 * until is runs out of stack space, unless it does a wait call before
7081 * restoring the signal handler. The code below takes advantage of
7082 * this (mis)feature by installing a signal handler for SIGCLD and
7083 * then checking to see whether it was called. If there are any
7084 * children to be waited for, it will be.
7085 *
7086 */
7087
7088static inline int
7089waitproc(int block, int *status)
7090{
7091 int flags;
7092
7093 flags = 0;
7094#ifdef JOBS
7095 if (jobctl)
7096 flags |= WUNTRACED;
7097#endif
7098 if (block == 0)
7099 flags |= WNOHANG;
7100 return wait3(status, flags, (struct rusage *)NULL);
7101}
7102
Eric Andersencb57d552001-06-28 07:25:16 +00007103static int
Eric Andersen62483552001-07-10 06:09:16 +00007104dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00007105{
7106 int pid;
7107 int status;
7108 struct procstat *sp;
7109 struct job *jp;
7110 struct job *thisjob;
7111 int done;
7112 int stopped;
7113 int core;
7114 int sig;
7115
7116 TRACE(("dowait(%d) called\n", block));
7117 do {
7118 pid = waitproc(block, &status);
7119 TRACE(("wait returns %d, status=%d\n", pid, status));
7120 } while (!(block & 2) && pid == -1 && errno == EINTR);
7121 if (pid <= 0)
7122 return pid;
7123 INTOFF;
7124 thisjob = NULL;
7125 for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
7126 if (jp->used) {
7127 done = 1;
7128 stopped = 1;
7129 for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
7130 if (sp->pid == -1)
7131 continue;
7132 if (sp->pid == pid) {
7133 TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
7134 sp->status = status;
7135 thisjob = jp;
7136 }
7137 if (sp->status == -1)
7138 stopped = 0;
7139 else if (WIFSTOPPED(sp->status))
7140 done = 0;
7141 }
Eric Andersen2870d962001-07-02 17:27:21 +00007142 if (stopped) { /* stopped or done */
Eric Andersencb57d552001-06-28 07:25:16 +00007143 int state = done? JOBDONE : JOBSTOPPED;
7144 if (jp->state != state) {
7145 TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
7146 jp->state = state;
Eric Andersen2870d962001-07-02 17:27:21 +00007147#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007148 if (done && curjob == jp - jobtab + 1)
Eric Andersen2870d962001-07-02 17:27:21 +00007149 curjob = 0; /* no current job */
Eric Andersencb57d552001-06-28 07:25:16 +00007150#endif
7151 }
7152 }
7153 }
7154 }
7155 INTON;
7156 if (! rootshell || ! iflag || (job && thisjob == job)) {
7157 core = WCOREDUMP(status);
Eric Andersen2870d962001-07-02 17:27:21 +00007158#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007159 if (WIFSTOPPED(status)) sig = WSTOPSIG(status);
7160 else
7161#endif
7162 if (WIFEXITED(status)) sig = 0;
7163 else sig = WTERMSIG(status);
7164
7165 if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
7166 if (thisjob != job)
Eric Andersen3102ac42001-07-06 04:26:23 +00007167 out2fmt("%d: ", pid);
Eric Andersen2870d962001-07-02 17:27:21 +00007168#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007169 if (sig == SIGTSTP && rootshell && iflag)
Eric Andersen3102ac42001-07-06 04:26:23 +00007170 out2fmt("%%%ld ",
Eric Andersencb57d552001-06-28 07:25:16 +00007171 (long)(job - jobtab + 1));
7172#endif
7173 if (sig < NSIG && sys_siglist[sig])
7174 out2str(sys_siglist[sig]);
7175 else
Eric Andersen3102ac42001-07-06 04:26:23 +00007176 out2fmt("Signal %d", sig);
Eric Andersencb57d552001-06-28 07:25:16 +00007177 if (core)
7178 out2str(" - core dumped");
7179 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00007180 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00007181 TRACE(("Not printing status: status=%d, sig=%d\n",
Eric Andersencb57d552001-06-28 07:25:16 +00007182 status, sig));
7183 }
7184 } else {
7185 TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
7186 if (thisjob)
7187 thisjob->changed = 1;
7188 }
7189 return pid;
7190}
7191
7192
7193
Eric Andersencb57d552001-06-28 07:25:16 +00007194
7195/*
7196 * return 1 if there are stopped jobs, otherwise 0
7197 */
Eric Andersencb57d552001-06-28 07:25:16 +00007198static int
Eric Andersen2870d962001-07-02 17:27:21 +00007199stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007200{
7201 int jobno;
7202 struct job *jp;
7203
7204 if (job_warning)
7205 return (0);
7206 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
7207 if (jp->used == 0)
7208 continue;
7209 if (jp->state == JOBSTOPPED) {
7210 out2str("You have stopped jobs.\n");
7211 job_warning = 2;
7212 return (1);
7213 }
7214 }
7215
7216 return (0);
7217}
7218
7219/*
7220 * Return a string identifying a command (to be printed by the
7221 * jobs command.
7222 */
7223
7224static char *cmdnextc;
7225static int cmdnleft;
Eric Andersen2870d962001-07-02 17:27:21 +00007226#define MAXCMDTEXT 200
Eric Andersencb57d552001-06-28 07:25:16 +00007227
Eric Andersen2870d962001-07-02 17:27:21 +00007228static void
7229cmdputs(const char *s)
7230{
7231 const char *p;
7232 char *q;
7233 char c;
7234 int subtype = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007235
Eric Andersen2870d962001-07-02 17:27:21 +00007236 if (cmdnleft <= 0)
7237 return;
7238 p = s;
7239 q = cmdnextc;
7240 while ((c = *p++) != '\0') {
7241 if (c == CTLESC)
7242 *q++ = *p++;
7243 else if (c == CTLVAR) {
7244 *q++ = '$';
7245 if (--cmdnleft > 0)
7246 *q++ = '{';
7247 subtype = *p++;
7248 } else if (c == '=' && subtype != 0) {
7249 *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
7250 subtype = 0;
7251 } else if (c == CTLENDVAR) {
7252 *q++ = '}';
7253 } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
7254 cmdnleft++; /* ignore it */
7255 else
7256 *q++ = c;
7257 if (--cmdnleft <= 0) {
7258 *q++ = '.';
7259 *q++ = '.';
7260 *q++ = '.';
7261 break;
7262 }
7263 }
7264 cmdnextc = q;
Eric Andersencb57d552001-06-28 07:25:16 +00007265}
7266
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00007267#define CMDTXT_TABLE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007268#ifdef CMDTXT_TABLE
7269/*
7270 * To collect a lot of redundant code in cmdtxt() case statements, we
7271 * implement a mini language here. Each type of node struct has an
7272 * associated instruction sequence that operates on its members via
7273 * their offsets. The instruction are pack in unsigned chars with
7274 * format IIDDDDDE where the bits are
7275 * I : part of the instruction opcode, which are
7276 * 00 : member is a pointer to another node -- process it recursively
7277 * 40 : member is a pointer to a char string -- output it
7278 * 80 : output the string whose index is stored in the data field
7279 * CC : flag signaling that this case needs external processing
7280 * D : data - either the (shifted) index of a fixed string to output or
7281 * the actual offset of the member to operate on in the struct
7282 * (since we assume bit 0 is set, the offset is not shifted)
7283 * E : flag signaling end of instruction sequence
7284 *
7285 * WARNING: In order to handle larger offsets for 64bit archs, this code
7286 * assumes that no offset can be an odd number and stores the
7287 * end-of-instructions flag in bit 0.
7288 */
Eric Andersencb57d552001-06-28 07:25:16 +00007289
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007290#define CMDTXT_NOMORE 0x01 /* NOTE: no offset should be odd */
7291#define CMDTXT_CHARPTR 0x40
7292#define CMDTXT_STRING 0x80
7293#define CMDTXT_SPECIAL 0xC0
7294#define CMDTXT_OFFSETMASK 0x3E
7295
7296static const char * const cmdtxt_strings[] = {
7297 /* 0 1 2 3 4 5 6 7 */
7298 "; ", "(", ")", " && ", " || ", "if ", "; then ", "...",
7299 /* 8 9 10 11 12 13 */
7300 "while ", "; do ", "; done", "until ", "for ", " in ...",
7301 /* 14 15 16 17 */
7302 "case ", "???", "() ...", "<<..."
7303};
7304
7305static const char * const redir_strings[] = {
7306 ">", "<", "<>", ">>", ">|", ">&", "<&"
7307};
7308
7309static const unsigned char cmdtxt_ops[] = {
7310#define CMDTXT_NSEMI 0
7311 offsetof(union node, nbinary.ch1),
7312 0|CMDTXT_STRING,
7313 offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7314#define CMDTXT_NCMD (CMDTXT_NSEMI + 3)
7315#define CMDTXT_NPIPE (CMDTXT_NCMD)
7316#define CMDTXT_NCASE (CMDTXT_NCMD)
7317#define CMDTXT_NTO (CMDTXT_NCMD)
7318#define CMDTXT_NFROM (CMDTXT_NCMD)
7319#define CMDTXT_NFROMTO (CMDTXT_NCMD)
7320#define CMDTXT_NAPPEND (CMDTXT_NCMD)
7321#define CMDTXT_NTOOV (CMDTXT_NCMD)
7322#define CMDTXT_NTOFD (CMDTXT_NCMD)
7323#define CMDTXT_NFROMFD (CMDTXT_NCMD)
7324 CMDTXT_SPECIAL,
7325#define CMDTXT_NREDIR (CMDTXT_NPIPE + 1)
7326#define CMDTXT_NBACKGND (CMDTXT_NREDIR)
7327 offsetof(union node, nredir.n)|CMDTXT_NOMORE,
7328#define CMDTXT_NSUBSHELL (CMDTXT_NBACKGND + 1)
7329 (1*2)|CMDTXT_STRING,
7330 offsetof(union node, nredir.n),
7331 (2*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7332#define CMDTXT_NAND (CMDTXT_NSUBSHELL + 3)
7333 offsetof(union node, nbinary.ch1),
7334 (3*2)|CMDTXT_STRING,
7335 offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7336#define CMDTXT_NOR (CMDTXT_NAND + 3)
7337 offsetof(union node, nbinary.ch1),
7338 (4*2)|CMDTXT_STRING,
7339 offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7340#define CMDTXT_NIF (CMDTXT_NOR + 3)
7341 (5*2)|CMDTXT_STRING,
7342 offsetof(union node, nif.test),
7343 (6*2)|CMDTXT_STRING,
7344 offsetof(union node, nif.ifpart),
7345 (7*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7346#define CMDTXT_NWHILE (CMDTXT_NIF + 5)
7347 (8*2)|CMDTXT_STRING,
7348 offsetof(union node, nbinary.ch1),
7349 (9*2)|CMDTXT_STRING,
7350 offsetof(union node, nbinary.ch2),
7351 (10*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7352#define CMDTXT_NUNTIL (CMDTXT_NWHILE + 5)
7353 (11*2)|CMDTXT_STRING,
7354 offsetof(union node, nbinary.ch1),
7355 (9*2)|CMDTXT_STRING,
7356 offsetof(union node, nbinary.ch2),
7357 (10*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7358#define CMDTXT_NFOR (CMDTXT_NUNTIL + 5)
7359 (12*2)|CMDTXT_STRING,
7360 offsetof(union node, nfor.var)|CMDTXT_CHARPTR,
7361 (13*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7362#define CMDTXT_NCLIST (CMDTXT_NFOR + 3) /* TODO: IS THIS CORRECT??? */
7363#define CMDTXT_NNOT (CMDTXT_NCLIST) /* TODO: IS THIS CORRECT??? */
7364 (15*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7365#define CMDTXT_NDEFUN (CMDTXT_NCLIST + 1)
7366 offsetof(union node, narg.text)|CMDTXT_CHARPTR,
7367 (16*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7368#define CMDTXT_NARG (CMDTXT_NDEFUN + 2)
7369 offsetof(union node, narg.text)|CMDTXT_CHARPTR|CMDTXT_NOMORE,
7370#define CMDTXT_NHERE (CMDTXT_NARG + 1)
7371#define CMDTXT_NXHERE (CMDTXT_NHERE)
7372 (17*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7373};
7374
7375#if CMDTXT_NXHERE != 36
7376#error CMDTXT_NXHERE
7377#endif
7378
7379static const unsigned char cmdtxt_ops_index[26] = {
7380 CMDTXT_NSEMI,
7381 CMDTXT_NCMD,
7382 CMDTXT_NPIPE,
7383 CMDTXT_NREDIR,
7384 CMDTXT_NBACKGND,
7385 CMDTXT_NSUBSHELL,
7386 CMDTXT_NAND,
7387 CMDTXT_NOR,
7388 CMDTXT_NIF,
7389 CMDTXT_NWHILE,
7390 CMDTXT_NUNTIL,
7391 CMDTXT_NFOR,
7392 CMDTXT_NCASE,
7393 CMDTXT_NCLIST,
7394 CMDTXT_NDEFUN,
7395 CMDTXT_NARG,
7396 CMDTXT_NTO,
7397 CMDTXT_NFROM,
7398 CMDTXT_NFROMTO,
7399 CMDTXT_NAPPEND,
7400 CMDTXT_NTOOV,
7401 CMDTXT_NTOFD,
7402 CMDTXT_NFROMFD,
7403 CMDTXT_NHERE,
7404 CMDTXT_NXHERE,
7405 CMDTXT_NNOT,
7406};
7407
7408static void
7409cmdtxt(const union node *n)
7410{
7411 const char *p;
7412
7413 if (n == NULL)
7414 return;
7415
7416 p = cmdtxt_ops + (int) cmdtxt_ops_index[n->type];
7417 if ((*p & CMDTXT_SPECIAL) != CMDTXT_SPECIAL) { /* normal case */
7418 do {
7419 if (*p & CMDTXT_STRING) { /* output fixed string */
7420 cmdputs(cmdtxt_strings[((int)(*p & CMDTXT_OFFSETMASK) >> 1)]);
Manuel Novoa III c639a352001-08-12 17:32:56 +00007421 } else {
7422 const char *pf = ((const char *) n)
7423 + ((int)(*p & CMDTXT_OFFSETMASK));
7424 if (*p & CMDTXT_CHARPTR) { /* output dynamic string */
7425 cmdputs(*((const char **) pf));
7426 } else { /* output field */
7427 cmdtxt(*((const union node **) pf));
7428 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007429 }
7430 } while (!(*p++ & CMDTXT_NOMORE));
7431 } else if (n->type == NCMD) {
7432 union node *np;
7433 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7434 cmdtxt(np);
7435 if (np->narg.next)
7436 cmdputs(spcstr);
7437 }
7438 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7439 cmdputs(spcstr);
7440 cmdtxt(np);
7441 }
7442 } else if (n->type == NPIPE) {
7443 struct nodelist *lp;
7444 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7445 cmdtxt(lp->n);
7446 if (lp->next)
7447 cmdputs(" | ");
7448 }
7449 } else if (n->type == NCASE) {
7450 cmdputs(cmdtxt_strings[14]);
7451 cmdputs(n->ncase.expr->narg.text);
7452 cmdputs(cmdtxt_strings[13]);
7453 } else {
7454#if (NTO != 16) || (NFROM != 17) || (NFROMTO != 18) || (NAPPEND != 19) || (NTOOV != 20) || (NTOFD != 21) || (NFROMFD != 22)
7455#error Assumption violated regarding range and ordering of NTO ... NFROMFD!
7456#endif
7457 char s[2];
7458
7459#ifdef DEBUG
7460 assert((n->type >= NTO) && (n->type <= NFROMFD));
7461#endif
7462
7463 p = redir_strings[n->type - NTO];
7464 if (n->nfile.fd != ('>' == *p)) {
7465 s[0] = n->nfile.fd + '0';
7466 s[1] = '\0';
7467 cmdputs(s);
7468 }
7469 cmdputs(p);
7470 if (n->type >= NTOFD) {
7471 s[0] = n->ndup.dupfd + '0';
7472 s[1] = '\0';
7473 cmdputs(s);
7474 } else {
7475 cmdtxt(n->nfile.fname);
7476 }
7477 }
7478}
7479#else /* CMDTXT_TABLE */
Eric Andersencb57d552001-06-28 07:25:16 +00007480static void
Eric Andersen2870d962001-07-02 17:27:21 +00007481cmdtxt(const union node *n)
7482{
Eric Andersencb57d552001-06-28 07:25:16 +00007483 union node *np;
7484 struct nodelist *lp;
7485 const char *p;
7486 int i;
7487 char s[2];
7488
7489 if (n == NULL)
7490 return;
7491 switch (n->type) {
7492 case NSEMI:
7493 cmdtxt(n->nbinary.ch1);
7494 cmdputs("; ");
7495 cmdtxt(n->nbinary.ch2);
7496 break;
7497 case NAND:
7498 cmdtxt(n->nbinary.ch1);
7499 cmdputs(" && ");
7500 cmdtxt(n->nbinary.ch2);
7501 break;
7502 case NOR:
7503 cmdtxt(n->nbinary.ch1);
7504 cmdputs(" || ");
7505 cmdtxt(n->nbinary.ch2);
7506 break;
7507 case NPIPE:
7508 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7509 cmdtxt(lp->n);
7510 if (lp->next)
7511 cmdputs(" | ");
7512 }
7513 break;
7514 case NSUBSHELL:
7515 cmdputs("(");
7516 cmdtxt(n->nredir.n);
7517 cmdputs(")");
7518 break;
7519 case NREDIR:
7520 case NBACKGND:
7521 cmdtxt(n->nredir.n);
7522 break;
7523 case NIF:
7524 cmdputs("if ");
7525 cmdtxt(n->nif.test);
7526 cmdputs("; then ");
7527 cmdtxt(n->nif.ifpart);
7528 cmdputs("...");
7529 break;
7530 case NWHILE:
7531 cmdputs("while ");
7532 goto until;
7533 case NUNTIL:
7534 cmdputs("until ");
7535until:
7536 cmdtxt(n->nbinary.ch1);
7537 cmdputs("; do ");
7538 cmdtxt(n->nbinary.ch2);
7539 cmdputs("; done");
7540 break;
7541 case NFOR:
7542 cmdputs("for ");
7543 cmdputs(n->nfor.var);
7544 cmdputs(" in ...");
7545 break;
7546 case NCASE:
7547 cmdputs("case ");
7548 cmdputs(n->ncase.expr->narg.text);
7549 cmdputs(" in ...");
7550 break;
7551 case NDEFUN:
7552 cmdputs(n->narg.text);
7553 cmdputs("() ...");
7554 break;
7555 case NCMD:
7556 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7557 cmdtxt(np);
7558 if (np->narg.next)
7559 cmdputs(spcstr);
7560 }
7561 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7562 cmdputs(spcstr);
7563 cmdtxt(np);
7564 }
7565 break;
7566 case NARG:
7567 cmdputs(n->narg.text);
7568 break;
7569 case NTO:
7570 p = ">"; i = 1; goto redir;
7571 case NAPPEND:
7572 p = ">>"; i = 1; goto redir;
7573 case NTOFD:
7574 p = ">&"; i = 1; goto redir;
7575 case NTOOV:
7576 p = ">|"; i = 1; goto redir;
7577 case NFROM:
7578 p = "<"; i = 0; goto redir;
7579 case NFROMFD:
7580 p = "<&"; i = 0; goto redir;
7581 case NFROMTO:
7582 p = "<>"; i = 0; goto redir;
7583redir:
7584 if (n->nfile.fd != i) {
7585 s[0] = n->nfile.fd + '0';
7586 s[1] = '\0';
7587 cmdputs(s);
7588 }
7589 cmdputs(p);
7590 if (n->type == NTOFD || n->type == NFROMFD) {
7591 s[0] = n->ndup.dupfd + '0';
7592 s[1] = '\0';
7593 cmdputs(s);
7594 } else {
7595 cmdtxt(n->nfile.fname);
7596 }
7597 break;
7598 case NHERE:
7599 case NXHERE:
7600 cmdputs("<<...");
7601 break;
7602 default:
7603 cmdputs("???");
7604 break;
7605 }
7606}
Manuel Novoa III c639a352001-08-12 17:32:56 +00007607#endif /* CMDTXT_TABLE */
Eric Andersencb57d552001-06-28 07:25:16 +00007608
Eric Andersen2870d962001-07-02 17:27:21 +00007609static char *
7610commandtext(const union node *n)
7611{
7612 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007613
Eric Andersen2870d962001-07-02 17:27:21 +00007614 cmdnextc = name = ckmalloc(MAXCMDTEXT);
7615 cmdnleft = MAXCMDTEXT - 4;
7616 cmdtxt(n);
7617 *cmdnextc = '\0';
7618 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00007619}
7620
Eric Andersen2870d962001-07-02 17:27:21 +00007621
Eric Andersencb57d552001-06-28 07:25:16 +00007622static void waitonint(int sig) {
7623 intreceived = 1;
7624 return;
7625}
Eric Andersencb57d552001-06-28 07:25:16 +00007626/*
7627 * Routines to check for mail. (Perhaps make part of main.c?)
7628 */
7629
7630
7631#define MAXMBOXES 10
7632
7633
Eric Andersen2870d962001-07-02 17:27:21 +00007634static int nmboxes; /* number of mailboxes */
7635static time_t mailtime[MAXMBOXES]; /* times of mailboxes */
Eric Andersencb57d552001-06-28 07:25:16 +00007636
7637
7638
7639/*
7640 * Print appropriate message(s) if mail has arrived. If the argument is
7641 * nozero, then the value of MAIL has changed, so we just update the
7642 * values.
7643 */
7644
7645static void
Eric Andersen2870d962001-07-02 17:27:21 +00007646chkmail(int silent)
Eric Andersencb57d552001-06-28 07:25:16 +00007647{
7648 int i;
7649 const char *mpath;
7650 char *p;
7651 char *q;
7652 struct stackmark smark;
7653 struct stat statb;
7654
7655 if (silent)
7656 nmboxes = 10;
7657 if (nmboxes == 0)
7658 return;
7659 setstackmark(&smark);
7660 mpath = mpathset()? mpathval() : mailval();
7661 for (i = 0 ; i < nmboxes ; i++) {
7662 p = padvance(&mpath, nullstr);
7663 if (p == NULL)
7664 break;
7665 if (*p == '\0')
7666 continue;
7667 for (q = p ; *q ; q++);
7668#ifdef DEBUG
7669 if (q[-1] != '/')
7670 abort();
7671#endif
Eric Andersen2870d962001-07-02 17:27:21 +00007672 q[-1] = '\0'; /* delete trailing '/' */
Eric Andersencb57d552001-06-28 07:25:16 +00007673 if (stat(p, &statb) < 0)
7674 statb.st_size = 0;
7675 if (statb.st_size > mailtime[i] && ! silent) {
Eric Andersen3102ac42001-07-06 04:26:23 +00007676 out2fmt(snlfmt,
7677 pathopt? pathopt : "you have mail");
Eric Andersencb57d552001-06-28 07:25:16 +00007678 }
7679 mailtime[i] = statb.st_size;
Eric Andersencb57d552001-06-28 07:25:16 +00007680 }
7681 nmboxes = i;
7682 popstackmark(&smark);
7683}
Eric Andersencb57d552001-06-28 07:25:16 +00007684
7685#define PROFILE 0
7686
Eric Andersencb57d552001-06-28 07:25:16 +00007687#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007688static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007689extern int etext();
7690#endif
7691
Eric Andersen2870d962001-07-02 17:27:21 +00007692static void read_profile (const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007693static void cmdloop (int);
7694static void options (int);
Eric Andersen2870d962001-07-02 17:27:21 +00007695static void setoption (int, int);
7696static void procargs (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00007697
Eric Andersen2870d962001-07-02 17:27:21 +00007698
Eric Andersencb57d552001-06-28 07:25:16 +00007699/*
7700 * Main routine. We initialize things, parse the arguments, execute
7701 * profiles if we're a login shell, and then call cmdloop to execute
7702 * commands. The setjmp call sets up the location to jump to when an
7703 * exception occurs. When an exception occurs the variable "state"
7704 * is used to figure out how far we had gotten.
7705 */
7706
7707int
Matt Kraai2d91deb2001-08-01 17:21:35 +00007708ash_main(argc, argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007709 int argc;
7710 char **argv;
7711{
7712 struct jmploc jmploc;
7713 struct stackmark smark;
7714 volatile int state;
Eric Andersen62483552001-07-10 06:09:16 +00007715 const char *shinit;
Eric Andersencb57d552001-06-28 07:25:16 +00007716
Eric Andersencb57d552001-06-28 07:25:16 +00007717 BLTINCMD = find_builtin("builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00007718 EXECCMD = find_builtin("exec");
7719 EVALCMD = find_builtin("eval");
7720
Eric Andersen1c039232001-07-07 00:05:55 +00007721#ifndef BB_FEATURE_SH_FANCY_PROMPT
7722 unsetenv("PS1");
7723 unsetenv("PS2");
7724#endif
7725
Eric Andersencb57d552001-06-28 07:25:16 +00007726#if PROFILE
7727 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7728#endif
7729#if defined(linux) || defined(__GNU__)
7730 signal(SIGCHLD, SIG_DFL);
7731#endif
7732 state = 0;
7733 if (setjmp(jmploc.loc)) {
7734 INTOFF;
7735 /*
7736 * When a shell procedure is executed, we raise the
7737 * exception EXSHELLPROC to clean up before executing
7738 * the shell procedure.
7739 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007740 if (exception == EXSHELLPROC) {
Eric Andersencb57d552001-06-28 07:25:16 +00007741 rootpid = getpid();
7742 rootshell = 1;
7743 minusc = NULL;
7744 state = 3;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007745 } else {
7746 if (exception == EXEXEC) {
7747 exitstatus = exerrno;
7748 } else if (exception == EXERROR) {
7749 exitstatus = 2;
7750 }
Eric Andersencb57d552001-06-28 07:25:16 +00007751 if (state == 0 || iflag == 0 || ! rootshell)
7752 exitshell(exitstatus);
7753 }
7754 reset();
Eric Andersen2870d962001-07-02 17:27:21 +00007755 if (exception == EXINT) {
Eric Andersencb57d552001-06-28 07:25:16 +00007756 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00007757 }
7758 popstackmark(&smark);
Eric Andersen2870d962001-07-02 17:27:21 +00007759 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007760 if (state == 1)
7761 goto state1;
7762 else if (state == 2)
7763 goto state2;
7764 else if (state == 3)
7765 goto state3;
7766 else
7767 goto state4;
7768 }
7769 handler = &jmploc;
7770#ifdef DEBUG
7771 opentrace();
7772 trputs("Shell args: "); trargs(argv);
7773#endif
7774 rootpid = getpid();
7775 rootshell = 1;
7776 init();
7777 setstackmark(&smark);
7778 procargs(argc, argv);
7779 if (argv[0] && argv[0][0] == '-') {
7780 state = 1;
7781 read_profile("/etc/profile");
7782state1:
7783 state = 2;
7784 read_profile(".profile");
7785 }
7786state2:
7787 state = 3;
7788#ifndef linux
7789 if (getuid() == geteuid() && getgid() == getegid()) {
7790#endif
7791 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7792 state = 3;
7793 read_profile(shinit);
7794 }
7795#ifndef linux
7796 }
7797#endif
7798state3:
7799 state = 4;
7800 if (sflag == 0 || minusc) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007801 static const char sigs[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00007802 SIGINT, SIGQUIT, SIGHUP,
Eric Andersencb57d552001-06-28 07:25:16 +00007803#ifdef SIGTSTP
7804 SIGTSTP,
7805#endif
7806 SIGPIPE
7807 };
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007808#define SIGSSIZE ((sizeof(sigs)/sizeof(sigs[0])) - 1) /* trailing nul */
Eric Andersencb57d552001-06-28 07:25:16 +00007809 int i;
7810
7811 for (i = 0; i < SIGSSIZE; i++)
7812 setsignal(sigs[i]);
7813 }
7814
7815 if (minusc)
7816 evalstring(minusc, 0);
7817
7818 if (sflag || minusc == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00007819state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007820 cmdloop(1);
7821 }
7822#if PROFILE
7823 monitor(0);
7824#endif
7825 exitshell(exitstatus);
7826 /* NOTREACHED */
7827}
7828
7829
7830/*
7831 * Read and execute commands. "Top" is nonzero for the top level command
7832 * loop; it turns on prompting if the shell is interactive.
7833 */
7834
7835static void
Eric Andersen2870d962001-07-02 17:27:21 +00007836cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00007837{
7838 union node *n;
7839 struct stackmark smark;
7840 int inter;
7841 int numeof = 0;
7842
7843 TRACE(("cmdloop(%d) called\n", top));
7844 setstackmark(&smark);
7845 for (;;) {
7846 if (pendingsigs)
7847 dotrap();
7848 inter = 0;
7849 if (iflag && top) {
7850 inter++;
7851 showjobs(1);
7852 chkmail(0);
Eric Andersen3102ac42001-07-06 04:26:23 +00007853 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00007854 }
7855 n = parsecmd(inter);
7856 /* showtree(n); DEBUG */
7857 if (n == NEOF) {
7858 if (!top || numeof >= 50)
7859 break;
7860 if (!stoppedjobs()) {
7861 if (!Iflag)
7862 break;
7863 out2str("\nUse \"exit\" to leave shell.\n");
7864 }
7865 numeof++;
7866 } else if (n != NULL && nflag == 0) {
7867 job_warning = (job_warning == 2) ? 1 : 0;
7868 numeof = 0;
7869 evaltree(n, 0);
7870 }
7871 popstackmark(&smark);
7872 setstackmark(&smark);
7873 if (evalskip == SKIPFILE) {
7874 evalskip = 0;
7875 break;
7876 }
7877 }
7878 popstackmark(&smark);
7879}
7880
7881
7882
7883/*
7884 * Read /etc/profile or .profile. Return on error.
7885 */
7886
7887static void
7888read_profile(name)
7889 const char *name;
7890{
7891 int fd;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007892 int xflag_save;
7893 int vflag_save;
Eric Andersencb57d552001-06-28 07:25:16 +00007894
7895 INTOFF;
7896 if ((fd = open(name, O_RDONLY)) >= 0)
7897 setinputfd(fd, 1);
7898 INTON;
7899 if (fd < 0)
7900 return;
7901 /* -q turns off -x and -v just when executing init files */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007902 /* Note: Might do a little redundant work, but reduces code size. */
7903 xflag_save = xflag;
7904 vflag_save = vflag;
Eric Andersencb57d552001-06-28 07:25:16 +00007905 if (qflag) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007906 vflag = xflag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007907 }
7908 cmdloop(0);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007909 xflag = xflag_save;
7910 vflag = vflag_save;
Eric Andersencb57d552001-06-28 07:25:16 +00007911 popfile();
7912}
7913
7914
7915
7916/*
7917 * Read a file containing shell functions.
7918 */
7919
7920static void
Eric Andersen2870d962001-07-02 17:27:21 +00007921readcmdfile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00007922{
7923 int fd;
7924
7925 INTOFF;
7926 if ((fd = open(name, O_RDONLY)) >= 0)
7927 setinputfd(fd, 1);
7928 else
7929 error("Can't open %s", name);
7930 INTON;
7931 cmdloop(0);
7932 popfile();
7933}
7934
7935
7936
7937/*
7938 * Take commands from a file. To be compatable we should do a path
7939 * search for the file, which is necessary to find sub-commands.
7940 */
7941
7942
Eric Andersen62483552001-07-10 06:09:16 +00007943static inline char *
Eric Andersen74400cc2001-10-18 04:11:39 +00007944find_dot_file(char *mybasename)
Eric Andersencb57d552001-06-28 07:25:16 +00007945{
7946 char *fullname;
7947 const char *path = pathval();
7948 struct stat statb;
7949
7950 /* don't try this for absolute or relative paths */
7951 if (strchr(mybasename, '/'))
7952 return mybasename;
7953
7954 while ((fullname = padvance(&path, mybasename)) != NULL) {
7955 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
7956 /*
7957 * Don't bother freeing here, since it will
7958 * be freed by the caller.
7959 */
7960 return fullname;
7961 }
7962 stunalloc(fullname);
7963 }
7964
7965 /* not found in the PATH */
7966 error("%s: not found", mybasename);
7967 /* NOTREACHED */
7968}
7969
7970static int
7971dotcmd(argc, argv)
7972 int argc;
7973 char **argv;
7974{
7975 struct strlist *sp;
7976 exitstatus = 0;
7977
7978 for (sp = cmdenviron; sp ; sp = sp->next)
7979 setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
7980
Eric Andersen2870d962001-07-02 17:27:21 +00007981 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00007982 char *fullname;
7983 struct stackmark smark;
7984
7985 setstackmark(&smark);
7986 fullname = find_dot_file(argv[1]);
7987 setinputfile(fullname, 1);
7988 commandname = fullname;
7989 cmdloop(0);
7990 popfile();
7991 popstackmark(&smark);
7992 }
7993 return exitstatus;
7994}
7995
7996
7997static int
7998exitcmd(argc, argv)
7999 int argc;
8000 char **argv;
8001{
8002 if (stoppedjobs())
8003 return 0;
8004 if (argc > 1)
8005 exitstatus = number(argv[1]);
8006 else
8007 exitstatus = oexitstatus;
8008 exitshell(exitstatus);
8009 /* NOTREACHED */
8010}
Eric Andersen62483552001-07-10 06:09:16 +00008011
Eric Andersen2870d962001-07-02 17:27:21 +00008012static pointer
8013stalloc(int nbytes)
Eric Andersencb57d552001-06-28 07:25:16 +00008014{
8015 char *p;
8016
8017 nbytes = ALIGN(nbytes);
8018 if (nbytes > stacknleft) {
8019 int blocksize;
8020 struct stack_block *sp;
8021
8022 blocksize = nbytes;
8023 if (blocksize < MINSIZE)
8024 blocksize = MINSIZE;
8025 INTOFF;
8026 sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
8027 sp->prev = stackp;
8028 stacknxt = sp->space;
8029 stacknleft = blocksize;
8030 stackp = sp;
8031 INTON;
8032 }
8033 p = stacknxt;
8034 stacknxt += nbytes;
8035 stacknleft -= nbytes;
8036 return p;
8037}
8038
8039
8040static void
Eric Andersen2870d962001-07-02 17:27:21 +00008041stunalloc(pointer p)
8042{
Eric Andersencb57d552001-06-28 07:25:16 +00008043#ifdef DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +00008044 if (p == NULL) { /*DEBUG */
Eric Andersencb57d552001-06-28 07:25:16 +00008045 write(2, "stunalloc\n", 10);
8046 abort();
8047 }
8048#endif
8049 if (!(stacknxt >= (char *)p && (char *)p >= stackp->space)) {
8050 p = stackp->space;
8051 }
8052 stacknleft += stacknxt - (char *)p;
8053 stacknxt = p;
8054}
8055
8056
Eric Andersencb57d552001-06-28 07:25:16 +00008057static void
Eric Andersen2870d962001-07-02 17:27:21 +00008058setstackmark(struct stackmark *mark)
8059{
Eric Andersencb57d552001-06-28 07:25:16 +00008060 mark->stackp = stackp;
8061 mark->stacknxt = stacknxt;
8062 mark->stacknleft = stacknleft;
8063 mark->marknext = markp;
8064 markp = mark;
8065}
8066
8067
8068static void
Eric Andersen2870d962001-07-02 17:27:21 +00008069popstackmark(struct stackmark *mark)
8070{
Eric Andersencb57d552001-06-28 07:25:16 +00008071 struct stack_block *sp;
8072
8073 INTOFF;
8074 markp = mark->marknext;
8075 while (stackp != mark->stackp) {
8076 sp = stackp;
8077 stackp = sp->prev;
8078 ckfree(sp);
8079 }
8080 stacknxt = mark->stacknxt;
8081 stacknleft = mark->stacknleft;
8082 INTON;
8083}
8084
8085
8086/*
8087 * When the parser reads in a string, it wants to stick the string on the
8088 * stack and only adjust the stack pointer when it knows how big the
8089 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8090 * of space on top of the stack and stackblocklen returns the length of
8091 * this block. Growstackblock will grow this space by at least one byte,
8092 * possibly moving it (like realloc). Grabstackblock actually allocates the
8093 * part of the block that has been used.
8094 */
8095
8096static void
Eric Andersen2870d962001-07-02 17:27:21 +00008097growstackblock(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00008098 char *p;
8099 int newlen = ALIGN(stacknleft * 2 + 100);
8100 char *oldspace = stacknxt;
8101 int oldlen = stacknleft;
8102 struct stack_block *sp;
8103 struct stack_block *oldstackp;
8104
8105 if (stacknxt == stackp->space && stackp != &stackbase) {
8106 INTOFF;
8107 oldstackp = stackp;
8108 sp = stackp;
8109 stackp = sp->prev;
8110 sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen);
8111 sp->prev = stackp;
8112 stackp = sp;
8113 stacknxt = sp->space;
8114 stacknleft = newlen;
8115 {
8116 /* Stack marks pointing to the start of the old block
Eric Andersen2870d962001-07-02 17:27:21 +00008117 * must be relocated to point to the new block
Eric Andersencb57d552001-06-28 07:25:16 +00008118 */
8119 struct stackmark *xmark;
8120 xmark = markp;
8121 while (xmark != NULL && xmark->stackp == oldstackp) {
8122 xmark->stackp = stackp;
8123 xmark->stacknxt = stacknxt;
8124 xmark->stacknleft = stacknleft;
8125 xmark = xmark->marknext;
8126 }
8127 }
8128 INTON;
8129 } else {
8130 p = stalloc(newlen);
8131 memcpy(p, oldspace, oldlen);
Eric Andersen2870d962001-07-02 17:27:21 +00008132 stacknxt = p; /* free the space */
8133 stacknleft += newlen; /* we just allocated */
Eric Andersencb57d552001-06-28 07:25:16 +00008134 }
8135}
8136
8137
8138
Eric Andersen2870d962001-07-02 17:27:21 +00008139static inline void
8140grabstackblock(int len)
Eric Andersencb57d552001-06-28 07:25:16 +00008141{
8142 len = ALIGN(len);
8143 stacknxt += len;
8144 stacknleft -= len;
8145}
8146
8147
8148
8149/*
8150 * The following routines are somewhat easier to use that the above.
8151 * The user declares a variable of type STACKSTR, which may be declared
8152 * to be a register. The macro STARTSTACKSTR initializes things. Then
8153 * the user uses the macro STPUTC to add characters to the string. In
8154 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8155 * grown as necessary. When the user is done, she can just leave the
8156 * string there and refer to it using stackblock(). Or she can allocate
8157 * the space for it using grabstackstr(). If it is necessary to allow
8158 * someone else to use the stack temporarily and then continue to grow
8159 * the string, the user should use grabstack to allocate the space, and
8160 * then call ungrabstr(p) to return to the previous mode of operation.
8161 *
8162 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8163 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8164 * is space for at least one character.
8165 */
8166
8167
8168static char *
Eric Andersen2870d962001-07-02 17:27:21 +00008169growstackstr(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00008170 int len = stackblocksize();
8171 if (herefd >= 0 && len >= 1024) {
8172 xwrite(herefd, stackblock(), len);
8173 sstrnleft = len - 1;
8174 return stackblock();
8175 }
8176 growstackblock();
8177 sstrnleft = stackblocksize() - len - 1;
8178 return stackblock() + len;
8179}
8180
8181
8182/*
8183 * Called from CHECKSTRSPACE.
8184 */
8185
8186static char *
8187makestrspace(size_t newlen) {
8188 int len = stackblocksize() - sstrnleft;
8189 do {
8190 growstackblock();
8191 sstrnleft = stackblocksize() - len;
8192 } while (sstrnleft < newlen);
8193 return stackblock() + len;
8194}
8195
8196
8197
8198static void
Eric Andersen2870d962001-07-02 17:27:21 +00008199ungrabstackstr(char *s, char *p)
8200{
Eric Andersencb57d552001-06-28 07:25:16 +00008201 stacknleft += stacknxt - s;
8202 stacknxt = s;
8203 sstrnleft = stacknleft - (p - s);
8204}
Eric Andersencb57d552001-06-28 07:25:16 +00008205/*
8206 * Miscelaneous builtins.
8207 */
8208
8209
8210#undef rflag
8211
Eric Andersencb57d552001-06-28 07:25:16 +00008212#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersen62483552001-07-10 06:09:16 +00008213typedef long rlim_t;
Eric Andersencb57d552001-06-28 07:25:16 +00008214#endif
8215
8216
8217
8218/*
8219 * The read builtin. The -e option causes backslashes to escape the
8220 * following character.
8221 *
8222 * This uses unbuffered input, which may be avoidable in some cases.
8223 */
8224
8225static int
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008226readcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008227{
8228 char **ap;
8229 int backslash;
8230 char c;
8231 int rflag;
8232 char *prompt;
8233 const char *ifs;
8234 char *p;
8235 int startword;
8236 int status;
8237 int i;
8238
8239 rflag = 0;
8240 prompt = NULL;
8241 while ((i = nextopt("p:r")) != '\0') {
8242 if (i == 'p')
8243 prompt = optionarg;
8244 else
8245 rflag = 1;
8246 }
8247 if (prompt && isatty(0)) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008248 out2str(prompt); /* read without cmdedit */
Eric Andersencb57d552001-06-28 07:25:16 +00008249 flushall();
8250 }
8251 if (*(ap = argptr) == NULL)
8252 error("arg count");
8253 if ((ifs = bltinlookup("IFS")) == NULL)
8254 ifs = defifs;
8255 status = 0;
8256 startword = 1;
8257 backslash = 0;
8258 STARTSTACKSTR(p);
8259 for (;;) {
8260 if (read(0, &c, 1) != 1) {
8261 status = 1;
8262 break;
8263 }
8264 if (c == '\0')
8265 continue;
8266 if (backslash) {
8267 backslash = 0;
8268 if (c != '\n')
8269 STPUTC(c, p);
8270 continue;
8271 }
8272 if (!rflag && c == '\\') {
8273 backslash++;
8274 continue;
8275 }
8276 if (c == '\n')
8277 break;
8278 if (startword && *ifs == ' ' && strchr(ifs, c)) {
8279 continue;
8280 }
8281 startword = 0;
8282 if (backslash && c == '\\') {
8283 if (read(0, &c, 1) != 1) {
8284 status = 1;
8285 break;
8286 }
8287 STPUTC(c, p);
8288 } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
8289 STACKSTRNUL(p);
8290 setvar(*ap, stackblock(), 0);
8291 ap++;
8292 startword = 1;
8293 STARTSTACKSTR(p);
8294 } else {
8295 STPUTC(c, p);
8296 }
8297 }
8298 STACKSTRNUL(p);
8299 /* Remove trailing blanks */
8300 while (stackblock() <= --p && strchr(ifs, *p) != NULL)
8301 *p = '\0';
8302 setvar(*ap, stackblock(), 0);
8303 while (*++ap != NULL)
8304 setvar(*ap, nullstr, 0);
8305 return status;
8306}
8307
8308
8309
8310static int
8311umaskcmd(argc, argv)
8312 int argc;
8313 char **argv;
8314{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008315 static const char permuser[3] = "ugo";
8316 static const char permmode[3] = "rwx";
8317 static const short int permmask[] = {
8318 S_IRUSR, S_IWUSR, S_IXUSR,
8319 S_IRGRP, S_IWGRP, S_IXGRP,
8320 S_IROTH, S_IWOTH, S_IXOTH
8321 };
8322
Eric Andersencb57d552001-06-28 07:25:16 +00008323 char *ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008324 mode_t mask;
Eric Andersencb57d552001-06-28 07:25:16 +00008325 int i;
8326 int symbolic_mode = 0;
8327
Eric Andersen62483552001-07-10 06:09:16 +00008328 while (nextopt("S") != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00008329 symbolic_mode = 1;
8330 }
8331
8332 INTOFF;
8333 mask = umask(0);
8334 umask(mask);
8335 INTON;
8336
8337 if ((ap = *argptr) == NULL) {
8338 if (symbolic_mode) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008339 char buf[18];
8340 char *p = buf;
8341 for (i=0 ; i<3 ; i++) {
8342 int j;
8343 *p++ = permuser[i];
8344 *p++ = '=';
8345 for (j=0 ; j<3 ; j++) {
8346 if ((mask & permmask[3*i+j]) == 0) {
8347 *p++ = permmode[j];
8348 }
8349 }
8350 *p++ = ',';
8351 }
8352 *--p = 0;
8353 puts(buf);
Eric Andersencb57d552001-06-28 07:25:16 +00008354 } else {
Eric Andersen62483552001-07-10 06:09:16 +00008355 printf("%.4o\n", mask);
Eric Andersencb57d552001-06-28 07:25:16 +00008356 }
8357 } else {
Eric Andersen62483552001-07-10 06:09:16 +00008358 if (is_digit((unsigned char)*ap)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008359 mask = 0;
8360 do {
8361 if (*ap >= '8' || *ap < '0')
8362 error("Illegal number: %s", argv[1]);
8363 mask = (mask << 3) + (*ap - '0');
8364 } while (*++ap != '\0');
8365 umask(mask);
8366 } else {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008367 mask = ~mask & 0777;
8368 if (parse_mode(ap, &mask) == FALSE) {
Eric Andersencb57d552001-06-28 07:25:16 +00008369 error("Illegal mode: %s", ap);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008370 }
Eric Andersencb57d552001-06-28 07:25:16 +00008371 umask(~mask & 0777);
8372 }
8373 }
8374 return 0;
8375}
8376
8377/*
8378 * ulimit builtin
8379 *
8380 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
8381 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
8382 * ash by J.T. Conklin.
8383 *
8384 * Public domain.
8385 */
8386
8387struct limits {
8388 const char *name;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008389 short cmd;
8390 short factor; /* multiply by to get rlim_{cur,max} values */
Eric Andersencb57d552001-06-28 07:25:16 +00008391};
8392
8393static const struct limits limits[] = {
8394#ifdef RLIMIT_CPU
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008395 { "time(seconds)", RLIMIT_CPU, 1 },
Eric Andersencb57d552001-06-28 07:25:16 +00008396#endif
8397#ifdef RLIMIT_FSIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008398 { "file(blocks)", RLIMIT_FSIZE, 512 },
Eric Andersencb57d552001-06-28 07:25:16 +00008399#endif
8400#ifdef RLIMIT_DATA
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008401 { "data(kbytes)", RLIMIT_DATA, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008402#endif
8403#ifdef RLIMIT_STACK
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008404 { "stack(kbytes)", RLIMIT_STACK, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008405#endif
8406#ifdef RLIMIT_CORE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008407 { "coredump(blocks)", RLIMIT_CORE, 512 },
Eric Andersencb57d552001-06-28 07:25:16 +00008408#endif
8409#ifdef RLIMIT_RSS
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008410 { "memory(kbytes)", RLIMIT_RSS, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008411#endif
8412#ifdef RLIMIT_MEMLOCK
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008413 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008414#endif
8415#ifdef RLIMIT_NPROC
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008416 { "process(processes)", RLIMIT_NPROC, 1 },
Eric Andersencb57d552001-06-28 07:25:16 +00008417#endif
8418#ifdef RLIMIT_NOFILE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008419 { "nofiles(descriptors)", RLIMIT_NOFILE, 1 },
Eric Andersencb57d552001-06-28 07:25:16 +00008420#endif
8421#ifdef RLIMIT_VMEM
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008422 { "vmemory(kbytes)", RLIMIT_VMEM, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008423#endif
8424#ifdef RLIMIT_SWAP
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008425 { "swap(kbytes)", RLIMIT_SWAP, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008426#endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008427 { NULL, 0, 0 }
Eric Andersencb57d552001-06-28 07:25:16 +00008428};
8429
8430static int
8431ulimitcmd(argc, argv)
8432 int argc;
8433 char **argv;
8434{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008435 static const char unlimited_string[] = "unlimited";
Eric Andersen2870d962001-07-02 17:27:21 +00008436 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00008437 rlim_t val = 0;
8438 enum { SOFT = 0x1, HARD = 0x2 }
8439 how = SOFT | HARD;
Eric Andersen2870d962001-07-02 17:27:21 +00008440 const struct limits *l;
8441 int set, all = 0;
8442 int optc, what;
8443 struct rlimit limit;
Eric Andersencb57d552001-06-28 07:25:16 +00008444
8445 what = 'f';
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008446
8447 while ((optc = nextopt("HSa"
8448#ifdef RLIMIT_CPU
8449 "t"
8450#endif
8451#ifdef RLIMIT_FSIZE
8452 "f"
8453#endif
8454#ifdef RLIMIT_DATA
8455 "d"
8456#endif
8457#ifdef RLIMIT_STACK
8458 "s"
8459#endif
8460#ifdef RLIMIT_CORE
8461 "c"
8462#endif
8463#ifdef RLIMIT_RSS
8464 "m"
8465#endif
8466#ifdef RLIMIT_MEMLOCK
8467 "l"
8468#endif
8469#ifdef RLIMIT_NPROC
8470 "p"
8471#endif
8472#ifdef RLIMIT_NOFILE
8473 "n"
8474#endif
8475#ifdef RLIMIT_VMEM
8476 "v"
8477#endif
8478#ifdef RLIMIT_SWAP
8479 "w"
8480#endif
8481 )) != '\0') {
8482 if (optc == 'H') {
Eric Andersencb57d552001-06-28 07:25:16 +00008483 how = HARD;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008484 } else if (optc == 'S') {
Eric Andersencb57d552001-06-28 07:25:16 +00008485 how = SOFT;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008486 } else if (optc == 'a') {
Eric Andersencb57d552001-06-28 07:25:16 +00008487 all = 1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008488 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00008489 what = optc;
8490 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008491 }
Eric Andersencb57d552001-06-28 07:25:16 +00008492
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008493 for (l = limits; l->name; l++) {
8494 if(l->name[0] == what)
8495 break;
8496 if(l->name[1]=='w' && what=='w')
8497 break;
8498 }
Eric Andersencb57d552001-06-28 07:25:16 +00008499
8500 set = *argptr ? 1 : 0;
8501 if (set) {
8502 char *p = *argptr;
8503
8504 if (all || argptr[1])
8505 error("too many arguments");
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008506 if (strcmp(p, unlimited_string) == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00008507 val = RLIM_INFINITY;
8508 else {
8509 val = (rlim_t) 0;
8510
8511 while ((c = *p++) >= '0' && c <= '9')
8512 {
8513 val = (val * 10) + (long)(c - '0');
8514 if (val < (rlim_t) 0)
8515 break;
8516 }
8517 if (c)
8518 error("bad number");
8519 val *= l->factor;
8520 }
8521 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008522
Eric Andersencb57d552001-06-28 07:25:16 +00008523 if (all) {
8524 for (l = limits; l->name; l++) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008525 printf("%-20s ", l->name);
Eric Andersencb57d552001-06-28 07:25:16 +00008526 getrlimit(l->cmd, &limit);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008527 OUTPUT_LIMIT:
Eric Andersencb57d552001-06-28 07:25:16 +00008528 if (how & SOFT)
8529 val = limit.rlim_cur;
8530 else if (how & HARD)
8531 val = limit.rlim_max;
8532
Eric Andersencb57d552001-06-28 07:25:16 +00008533 if (val == RLIM_INFINITY)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008534 puts(unlimited_string);
Eric Andersencb57d552001-06-28 07:25:16 +00008535 else
8536 {
8537 val /= l->factor;
Eric Andersen62483552001-07-10 06:09:16 +00008538 printf("%lld\n", (long long) val);
Eric Andersencb57d552001-06-28 07:25:16 +00008539 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008540 if (!all) {
8541 break;
8542 }
Eric Andersencb57d552001-06-28 07:25:16 +00008543 }
8544 return 0;
8545 }
8546
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008547 if (!set) {
8548 goto OUTPUT_LIMIT;
Eric Andersencb57d552001-06-28 07:25:16 +00008549 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008550
8551 getrlimit(l->cmd, &limit);
8552 if (how & HARD)
8553 limit.rlim_max = val;
8554 if (how & SOFT)
8555 limit.rlim_cur = val;
8556 if (setrlimit(l->cmd, &limit) < 0)
8557 error("error setting limit (%m)");
Eric Andersencb57d552001-06-28 07:25:16 +00008558 return 0;
8559}
Eric Andersencb57d552001-06-28 07:25:16 +00008560/*
8561 * prefix -- see if pfx is a prefix of string.
8562 */
8563
8564static int
Eric Andersen62483552001-07-10 06:09:16 +00008565prefix(char const *pfx, char const *string)
8566{
Eric Andersencb57d552001-06-28 07:25:16 +00008567 while (*pfx) {
8568 if (*pfx++ != *string++)
8569 return 0;
8570 }
8571 return 1;
8572}
8573
Eric Andersen2870d962001-07-02 17:27:21 +00008574/*
8575 * Return true if s is a string of digits, and save munber in intptr
8576 * nagative is bad
8577 */
8578
8579static int
8580is_number(const char *p, int *intptr)
8581{
8582 int ret = 0;
8583
8584 do {
8585 if (! is_digit(*p))
8586 return 0;
8587 ret *= 10;
8588 ret += digit_val(*p);
8589 p++;
8590 } while (*p != '\0');
8591
8592 *intptr = ret;
8593 return 1;
8594}
Eric Andersencb57d552001-06-28 07:25:16 +00008595
8596/*
8597 * Convert a string of digits to an integer, printing an error message on
8598 * failure.
8599 */
8600
8601static int
Eric Andersen2870d962001-07-02 17:27:21 +00008602number(const char *s)
8603{
8604 int i;
8605 if (! is_number(s, &i))
Eric Andersencb57d552001-06-28 07:25:16 +00008606 error("Illegal number: %s", s);
Eric Andersen2870d962001-07-02 17:27:21 +00008607 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00008608}
8609
Eric Andersencb57d552001-06-28 07:25:16 +00008610/*
8611 * Produce a possibly single quoted string suitable as input to the shell.
8612 * The return string is allocated on the stack.
8613 */
8614
8615static char *
8616single_quote(const char *s) {
8617 char *p;
8618
8619 STARTSTACKSTR(p);
8620
8621 do {
8622 char *q = p;
8623 size_t len1, len1p, len2, len2p;
8624
8625 len1 = strcspn(s, "'");
8626 len2 = strspn(s + len1, "'");
8627
8628 len1p = len1 ? len1 + 2 : len1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008629 len2p = len2 + ((len2 < 2) ? len2 : 2);
Eric Andersencb57d552001-06-28 07:25:16 +00008630
8631 CHECKSTRSPACE(len1p + len2p + 1, p);
8632
8633 if (len1) {
8634 *p = '\'';
Eric Andersencb57d552001-06-28 07:25:16 +00008635 q = p + 1 + len1;
8636 memcpy(p + 1, s, len1);
Eric Andersencb57d552001-06-28 07:25:16 +00008637 *q++ = '\'';
8638 s += len1;
8639 }
8640
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008641 if (len2 > 1) {
Eric Andersencb57d552001-06-28 07:25:16 +00008642 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008643 q += 1 + len2;
8644 memcpy(q + 1, s, len2);
8645 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008646 s += len2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008647 } else if (len2 == 1) {
8648 *q++ = '\\';
8649 *q = '\'';
8650 s++;
Eric Andersencb57d552001-06-28 07:25:16 +00008651 }
8652
8653 STADJUST(len1p + len2p, p);
8654 } while (*s);
8655
8656 USTPUTC(0, p);
8657
8658 return grabstackstr(p);
8659}
8660
8661/*
8662 * Like strdup but works with the ash stack.
8663 */
8664
8665static char *
8666sstrdup(const char *p)
8667{
8668 size_t len = strlen(p) + 1;
8669 return memcpy(stalloc(len), p, len);
8670}
8671
Eric Andersencb57d552001-06-28 07:25:16 +00008672
8673/*
Eric Andersencb57d552001-06-28 07:25:16 +00008674 * Routine for dealing with parsed shell commands.
8675 */
8676
8677
Eric Andersen62483552001-07-10 06:09:16 +00008678static void sizenodelist (const struct nodelist *);
8679static struct nodelist *copynodelist (const struct nodelist *);
8680static char *nodesavestr (const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00008681
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00008682#define CALCSIZE_TABLE
8683#define COPYNODE_TABLE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008684#if defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE)
8685/*
8686 * To collect a lot of redundant code in case statements for copynode()
8687 * and calcsize(), we implement a mini language here. Each type of node
8688 * struct has an associated instruction sequence that operates on its
8689 * members via their offsets. The instruction are pack in unsigned chars
8690 * with format IIDDDDDE where the bits are
8691 * I : part of the instruction opcode, which are
8692 * 00 : member is a pointer to another node
8693 * 40 : member is an integer
8694 * 80 : member is a pointer to a nodelist
8695 * CC : member is a pointer to a char string
8696 * D : data - the actual offset of the member to operate on in the struct
8697 * (since we assume bit 0 is set, it is not shifted)
8698 * E : flag signaling end of instruction sequence
8699 *
8700 * WARNING: In order to handle larger offsets for 64bit archs, this code
8701 * assumes that no offset can be an odd number and stores the
8702 * end-of-instructions flag in bit 0.
8703 */
8704
8705#define NODE_INTEGER 0x40
8706#define NODE_NODELIST 0x80
8707#define NODE_CHARPTR 0xC0
8708#define NODE_NOMORE 0x01 /* Note: no offset should be odd (aligned)*/
8709#define NODE_MBRMASK 0xC0
8710#define NODE_OFFSETMASK 0x3E
8711
8712static const unsigned char copynode_ops[35] = {
8713#define COPYNODE_OPS0 0
8714 offsetof(union node, nbinary.ch2),
8715 offsetof(union node, nbinary.ch1)|NODE_NOMORE,
8716#define COPYNODE_OPS1 (COPYNODE_OPS0 + 2)
8717 offsetof(union node, ncmd.redirect),
8718 offsetof(union node, ncmd.args),
8719 offsetof(union node, ncmd.assign),
8720 offsetof(union node, ncmd.backgnd)|NODE_INTEGER|NODE_NOMORE,
8721#define COPYNODE_OPS2 (COPYNODE_OPS1 + 4)
8722 offsetof(union node, npipe.cmdlist)|NODE_NODELIST,
8723 offsetof(union node, npipe.backgnd)|NODE_INTEGER|NODE_NOMORE,
8724#define COPYNODE_OPS3 (COPYNODE_OPS2 + 2)
8725 offsetof(union node, nredir.redirect),
8726 offsetof(union node, nredir.n)|NODE_NOMORE,
8727#define COPYNODE_OPS4 (COPYNODE_OPS3 + 2)
8728 offsetof(union node, nif.elsepart),
8729 offsetof(union node, nif.ifpart),
8730 offsetof(union node, nif.test)|NODE_NOMORE,
8731#define COPYNODE_OPS5 (COPYNODE_OPS4 + 3)
8732 offsetof(union node, nfor.var)|NODE_CHARPTR,
8733 offsetof(union node, nfor.body),
8734 offsetof(union node, nfor.args)|NODE_NOMORE,
8735#define COPYNODE_OPS6 (COPYNODE_OPS5 + 3)
8736 offsetof(union node, ncase.cases),
8737 offsetof(union node, ncase.expr)|NODE_NOMORE,
8738#define COPYNODE_OPS7 (COPYNODE_OPS6 + 2)
8739 offsetof(union node, nclist.body),
8740 offsetof(union node, nclist.pattern),
8741 offsetof(union node, nclist.next)|NODE_NOMORE,
8742#define COPYNODE_OPS8 (COPYNODE_OPS7 + 3)
8743 offsetof(union node, narg.backquote)|NODE_NODELIST,
8744 offsetof(union node, narg.text)|NODE_CHARPTR,
8745 offsetof(union node, narg.next)|NODE_NOMORE,
8746#define COPYNODE_OPS9 (COPYNODE_OPS8 + 3)
8747 offsetof(union node, nfile.fname),
8748 offsetof(union node, nfile.fd)|NODE_INTEGER,
8749 offsetof(union node, nfile.next)|NODE_NOMORE,
8750#define COPYNODE_OPS10 (COPYNODE_OPS9 + 3)
8751 offsetof(union node, ndup.vname),
8752 offsetof(union node, ndup.dupfd)|NODE_INTEGER,
8753 offsetof(union node, ndup.fd)|NODE_INTEGER,
8754 offsetof(union node, ndup.next)|NODE_NOMORE,
8755#define COPYNODE_OPS11 (COPYNODE_OPS10 + 4)
8756 offsetof(union node, nhere.doc),
8757 offsetof(union node, nhere.fd)|NODE_INTEGER,
8758 offsetof(union node, nhere.next)|NODE_NOMORE,
8759#define COPYNODE_OPS12 (COPYNODE_OPS11 + 3)
8760 offsetof(union node, nnot.com)|NODE_NOMORE,
8761};
8762
8763#if COPYNODE_OPS12 != 34
8764#error COPYNODE_OPS12 is incorrect
8765#endif
8766
8767static const unsigned char copynode_ops_index[26] = {
8768 COPYNODE_OPS0, /* NSEMI */
8769 COPYNODE_OPS1, /* NCMD */
8770 COPYNODE_OPS2, /* NPIPE */
8771 COPYNODE_OPS3, /* NREDIR */
8772 COPYNODE_OPS3, /* NBACKGND */
8773 COPYNODE_OPS3, /* NSUBSHELL */
8774 COPYNODE_OPS0, /* NAND */
8775 COPYNODE_OPS0, /* NOR */
8776 COPYNODE_OPS4, /* NIF */
8777 COPYNODE_OPS0, /* NWHILE */
8778 COPYNODE_OPS0, /* NUNTIL */
8779 COPYNODE_OPS5, /* NFOR */
8780 COPYNODE_OPS6, /* NCASE */
8781 COPYNODE_OPS7, /* NCLIST */
8782 COPYNODE_OPS8, /* NDEFUN */
8783 COPYNODE_OPS8, /* NARG */
8784 COPYNODE_OPS9, /* NTO */
8785 COPYNODE_OPS9, /* NFROM */
8786 COPYNODE_OPS9, /* NFROMTO */
8787 COPYNODE_OPS9, /* NAPPEND */
8788 COPYNODE_OPS9, /* NTOOV */
8789 COPYNODE_OPS10, /* NTOFD */
8790 COPYNODE_OPS10, /* NFROMFD */
8791 COPYNODE_OPS11, /* NHERE */
8792 COPYNODE_OPS11, /* NXHERE */
8793 COPYNODE_OPS12, /* NNOT */
8794};
8795
8796#if NODE_CHARPTR != NODE_MBRMASK
8797#error NODE_CHARPTR != NODE_MBRMASK!!!
8798#endif
8799#endif /* defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE) */
8800
8801#ifdef COPYNODE_TABLE
8802static union node *
8803copynode(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008804{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008805 union node *new;
8806 const unsigned char *p;
8807
Manuel Novoa III c639a352001-08-12 17:32:56 +00008808 if (n == NULL) {
8809 return NULL;
8810 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008811 new = funcblock;
8812 new->type = n->type;
8813 funcblock = (char *) funcblock + (int) nodesize[n->type];
8814 p = copynode_ops + (int) copynode_ops_index[n->type];
8815 do {
8816 char *nn = ((char *) new) + ((int)(*p & NODE_OFFSETMASK));
8817 const char *no = ((const char *) n) + ((int)(*p & NODE_OFFSETMASK));
8818
8819 if (!(*p & NODE_MBRMASK)) { /* standard node */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008820 *((union node **)nn) = copynode(*((const union node **) no));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008821 } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008822 *((const char **)nn) = nodesavestr(*((const char **)no));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008823 } else if (*p & NODE_NODELIST) { /* nodelist */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008824 *((struct nodelist **)nn)
8825 = copynodelist(*((const struct nodelist **) no));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008826 } else { /* integer */
8827 *((int *) nn) = *((int *) no);
8828 }
8829 } while (!(*p++ & NODE_NOMORE));
8830 return new;
Eric Andersencb57d552001-06-28 07:25:16 +00008831}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008832#else /* COPYNODE_TABLE */
Eric Andersencb57d552001-06-28 07:25:16 +00008833static union node *
Eric Andersen62483552001-07-10 06:09:16 +00008834copynode(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008835{
Eric Andersen62483552001-07-10 06:09:16 +00008836 union node *new;
Eric Andersencb57d552001-06-28 07:25:16 +00008837
8838 if (n == NULL)
Manuel Novoa III c639a352001-08-12 17:32:56 +00008839 return NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008840 new = funcblock;
8841 funcblock = (char *) funcblock + nodesize[n->type];
8842 switch (n->type) {
8843 case NSEMI:
8844 case NAND:
8845 case NOR:
8846 case NWHILE:
8847 case NUNTIL:
8848 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8849 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8850 break;
8851 case NCMD:
8852 new->ncmd.redirect = copynode(n->ncmd.redirect);
8853 new->ncmd.args = copynode(n->ncmd.args);
8854 new->ncmd.assign = copynode(n->ncmd.assign);
8855 new->ncmd.backgnd = n->ncmd.backgnd;
8856 break;
8857 case NPIPE:
8858 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8859 new->npipe.backgnd = n->npipe.backgnd;
8860 break;
8861 case NREDIR:
8862 case NBACKGND:
8863 case NSUBSHELL:
8864 new->nredir.redirect = copynode(n->nredir.redirect);
8865 new->nredir.n = copynode(n->nredir.n);
8866 break;
8867 case NIF:
8868 new->nif.elsepart = copynode(n->nif.elsepart);
8869 new->nif.ifpart = copynode(n->nif.ifpart);
8870 new->nif.test = copynode(n->nif.test);
8871 break;
8872 case NFOR:
8873 new->nfor.var = nodesavestr(n->nfor.var);
8874 new->nfor.body = copynode(n->nfor.body);
8875 new->nfor.args = copynode(n->nfor.args);
8876 break;
8877 case NCASE:
8878 new->ncase.cases = copynode(n->ncase.cases);
8879 new->ncase.expr = copynode(n->ncase.expr);
8880 break;
8881 case NCLIST:
8882 new->nclist.body = copynode(n->nclist.body);
8883 new->nclist.pattern = copynode(n->nclist.pattern);
8884 new->nclist.next = copynode(n->nclist.next);
8885 break;
8886 case NDEFUN:
8887 case NARG:
8888 new->narg.backquote = copynodelist(n->narg.backquote);
8889 new->narg.text = nodesavestr(n->narg.text);
8890 new->narg.next = copynode(n->narg.next);
8891 break;
8892 case NTO:
8893 case NFROM:
8894 case NFROMTO:
8895 case NAPPEND:
8896 case NTOOV:
8897 new->nfile.fname = copynode(n->nfile.fname);
8898 new->nfile.fd = n->nfile.fd;
8899 new->nfile.next = copynode(n->nfile.next);
8900 break;
8901 case NTOFD:
8902 case NFROMFD:
8903 new->ndup.vname = copynode(n->ndup.vname);
8904 new->ndup.dupfd = n->ndup.dupfd;
8905 new->ndup.fd = n->ndup.fd;
8906 new->ndup.next = copynode(n->ndup.next);
8907 break;
8908 case NHERE:
8909 case NXHERE:
8910 new->nhere.doc = copynode(n->nhere.doc);
8911 new->nhere.fd = n->nhere.fd;
8912 new->nhere.next = copynode(n->nhere.next);
8913 break;
8914 case NNOT:
8915 new->nnot.com = copynode(n->nnot.com);
8916 break;
8917 };
8918 new->type = n->type;
Eric Andersen62483552001-07-10 06:09:16 +00008919 return new;
Eric Andersencb57d552001-06-28 07:25:16 +00008920}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008921#endif /* COPYNODE_TABLE */
8922
8923#ifdef CALCSIZE_TABLE
8924static void
8925calcsize(const union node *n)
8926{
8927 const unsigned char *p;
8928
8929 if (n == NULL)
8930 return;
8931 funcblocksize += (int) nodesize[n->type];
8932
8933 p = copynode_ops + (int) copynode_ops_index[n->type];
8934 do {
8935 const char *no = ((const char *) n) + ((int)(*p & NODE_OFFSETMASK));
8936
8937 if (!(*p & NODE_MBRMASK)) { /* standard node */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008938 calcsize(*((const union node **) no));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008939 } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008940 funcstringsize += strlen(*((const char **)no)) + 1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008941 } else if (*p & NODE_NODELIST) { /* nodelist */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008942 sizenodelist(*((const struct nodelist **) no));
8943 } /* else integer -- ignore */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008944 } while (!(*p++ & NODE_NOMORE));
8945}
8946#else /* CALCSIZE_TABLE */
8947static void
8948calcsize(const union node *n)
8949{
8950 if (n == NULL)
8951 return;
8952 funcblocksize += nodesize[n->type];
8953 switch (n->type) {
8954 case NSEMI:
8955 case NAND:
8956 case NOR:
8957 case NWHILE:
8958 case NUNTIL:
8959 calcsize(n->nbinary.ch2);
8960 calcsize(n->nbinary.ch1);
8961 break;
8962 case NCMD:
8963 calcsize(n->ncmd.redirect);
8964 calcsize(n->ncmd.args);
8965 calcsize(n->ncmd.assign);
8966 break;
8967 case NPIPE:
8968 sizenodelist(n->npipe.cmdlist);
8969 break;
8970 case NREDIR:
8971 case NBACKGND:
8972 case NSUBSHELL:
8973 calcsize(n->nredir.redirect);
8974 calcsize(n->nredir.n);
8975 break;
8976 case NIF:
8977 calcsize(n->nif.elsepart);
8978 calcsize(n->nif.ifpart);
8979 calcsize(n->nif.test);
8980 break;
8981 case NFOR:
8982 funcstringsize += strlen(n->nfor.var) + 1;
8983 calcsize(n->nfor.body);
8984 calcsize(n->nfor.args);
8985 break;
8986 case NCASE:
8987 calcsize(n->ncase.cases);
8988 calcsize(n->ncase.expr);
8989 break;
8990 case NCLIST:
8991 calcsize(n->nclist.body);
8992 calcsize(n->nclist.pattern);
8993 calcsize(n->nclist.next);
8994 break;
8995 case NDEFUN:
8996 case NARG:
8997 sizenodelist(n->narg.backquote);
8998 funcstringsize += strlen(n->narg.text) + 1;
8999 calcsize(n->narg.next);
9000 break;
9001 case NTO:
9002 case NFROM:
9003 case NFROMTO:
9004 case NAPPEND:
9005 case NTOOV:
9006 calcsize(n->nfile.fname);
9007 calcsize(n->nfile.next);
9008 break;
9009 case NTOFD:
9010 case NFROMFD:
9011 calcsize(n->ndup.vname);
9012 calcsize(n->ndup.next);
9013 break;
9014 case NHERE:
9015 case NXHERE:
9016 calcsize(n->nhere.doc);
9017 calcsize(n->nhere.next);
9018 break;
9019 case NNOT:
9020 calcsize(n->nnot.com);
9021 break;
9022 };
9023}
9024#endif /* CALCSIZE_TABLE */
9025
9026static void
9027sizenodelist(const struct nodelist *lp)
9028{
9029 while (lp) {
9030 funcblocksize += ALIGN(sizeof(struct nodelist));
9031 calcsize(lp->n);
9032 lp = lp->next;
9033 }
9034}
Eric Andersencb57d552001-06-28 07:25:16 +00009035
9036
9037static struct nodelist *
Eric Andersen62483552001-07-10 06:09:16 +00009038copynodelist(const struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00009039{
9040 struct nodelist *start;
9041 struct nodelist **lpp;
9042
9043 lpp = &start;
9044 while (lp) {
9045 *lpp = funcblock;
9046 funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist));
9047 (*lpp)->n = copynode(lp->n);
9048 lp = lp->next;
9049 lpp = &(*lpp)->next;
9050 }
9051 *lpp = NULL;
9052 return start;
9053}
9054
9055
Eric Andersencb57d552001-06-28 07:25:16 +00009056static char *
Eric Andersen62483552001-07-10 06:09:16 +00009057nodesavestr(const char *s)
Eric Andersencb57d552001-06-28 07:25:16 +00009058{
Eric Andersen62483552001-07-10 06:09:16 +00009059 const char *p = s;
9060 char *q = funcstring;
Eric Andersencb57d552001-06-28 07:25:16 +00009061 char *rtn = funcstring;
9062
9063 while ((*q++ = *p++) != '\0')
9064 continue;
9065 funcstring = q;
9066 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00009067}
9068
Eric Andersencb57d552001-06-28 07:25:16 +00009069#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00009070static int getopts (char *, char *, char **, int *, int *);
Eric Andersencb57d552001-06-28 07:25:16 +00009071#endif
9072
9073
9074/*
9075 * Process the shell command line arguments.
9076 */
9077
9078static void
9079procargs(argc, argv)
9080 int argc;
9081 char **argv;
9082{
9083 int i;
9084
9085 argptr = argv;
9086 if (argc > 0)
9087 argptr++;
9088 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009089 optent_val(i) = 2;
Eric Andersencb57d552001-06-28 07:25:16 +00009090 options(1);
9091 if (*argptr == NULL && minusc == NULL)
9092 sflag = 1;
9093 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
9094 iflag = 1;
9095 if (mflag == 2)
9096 mflag = iflag;
9097 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009098 if (optent_val(i) == 2)
9099 optent_val(i) = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009100 arg0 = argv[0];
9101 if (sflag == 0 && minusc == NULL) {
9102 commandname = argv[0];
9103 arg0 = *argptr++;
9104 setinputfile(arg0, 0);
9105 commandname = arg0;
9106 }
9107 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
9108 if (argptr && minusc && *argptr)
Eric Andersen2870d962001-07-02 17:27:21 +00009109 arg0 = *argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00009110
9111 shellparam.p = argptr;
9112 shellparam.optind = 1;
9113 shellparam.optoff = -1;
9114 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
9115 while (*argptr) {
9116 shellparam.nparam++;
9117 argptr++;
9118 }
9119 optschanged();
9120}
9121
9122
Eric Andersencb57d552001-06-28 07:25:16 +00009123
9124/*
9125 * Process shell options. The global variable argptr contains a pointer
9126 * to the argument list; we advance it past the options.
9127 */
9128
Eric Andersen62483552001-07-10 06:09:16 +00009129static inline void
9130minus_o(const char *name, int val)
9131{
9132 int i;
9133
9134 if (name == NULL) {
9135 out1str("Current option settings\n");
9136 for (i = 0; i < NOPTS; i++)
9137 printf("%-16s%s\n", optent_name(optlist[i]),
9138 optent_val(i) ? "on" : "off");
9139 } else {
9140 for (i = 0; i < NOPTS; i++)
9141 if (equal(name, optent_name(optlist[i]))) {
9142 setoption(optent_letter(optlist[i]), val);
9143 return;
9144 }
9145 error("Illegal option -o %s", name);
9146 }
9147}
9148
9149
Eric Andersencb57d552001-06-28 07:25:16 +00009150static void
Eric Andersen62483552001-07-10 06:09:16 +00009151options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00009152{
9153 char *p;
9154 int val;
9155 int c;
9156
9157 if (cmdline)
9158 minusc = NULL;
9159 while ((p = *argptr) != NULL) {
9160 argptr++;
9161 if ((c = *p++) == '-') {
9162 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00009163 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
9164 if (!cmdline) {
9165 /* "-" means turn off -x and -v */
9166 if (p[0] == '\0')
9167 xflag = vflag = 0;
9168 /* "--" means reset params */
9169 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00009170 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00009171 }
9172 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00009173 }
9174 } else if (c == '+') {
9175 val = 0;
9176 } else {
9177 argptr--;
9178 break;
9179 }
9180 while ((c = *p++) != '\0') {
9181 if (c == 'c' && cmdline) {
9182 char *q;
Eric Andersen2870d962001-07-02 17:27:21 +00009183#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */
Eric Andersencb57d552001-06-28 07:25:16 +00009184 if (*p == '\0')
9185#endif
9186 q = *argptr++;
9187 if (q == NULL || minusc != NULL)
9188 error("Bad -c option");
9189 minusc = q;
9190#ifdef NOHACK
9191 break;
9192#endif
9193 } else if (c == 'o') {
9194 minus_o(*argptr, val);
9195 if (*argptr)
9196 argptr++;
9197 } else {
9198 setoption(c, val);
9199 }
9200 }
9201 }
9202}
9203
Eric Andersencb57d552001-06-28 07:25:16 +00009204
9205static void
Eric Andersen2870d962001-07-02 17:27:21 +00009206setoption(int flag, int val)
9207{
Eric Andersencb57d552001-06-28 07:25:16 +00009208 int i;
9209
9210 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009211 if (optent_letter(optlist[i]) == flag) {
9212 optent_val(i) = val;
Eric Andersencb57d552001-06-28 07:25:16 +00009213 if (val) {
9214 /* #%$ hack for ksh semantics */
9215 if (flag == 'V')
9216 Eflag = 0;
9217 else if (flag == 'E')
9218 Vflag = 0;
9219 }
9220 return;
9221 }
9222 error("Illegal option -%c", flag);
9223 /* NOTREACHED */
9224}
9225
9226
9227
Eric Andersencb57d552001-06-28 07:25:16 +00009228/*
9229 * Set the shell parameters.
9230 */
9231
9232static void
Eric Andersen2870d962001-07-02 17:27:21 +00009233setparam(char **argv)
9234{
Eric Andersencb57d552001-06-28 07:25:16 +00009235 char **newparam;
9236 char **ap;
9237 int nparam;
9238
9239 for (nparam = 0 ; argv[nparam] ; nparam++);
9240 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
9241 while (*argv) {
9242 *ap++ = savestr(*argv++);
9243 }
9244 *ap = NULL;
9245 freeparam(&shellparam);
9246 shellparam.malloc = 1;
9247 shellparam.nparam = nparam;
9248 shellparam.p = newparam;
9249 shellparam.optind = 1;
9250 shellparam.optoff = -1;
9251}
9252
9253
9254/*
9255 * Free the list of positional parameters.
9256 */
9257
9258static void
Eric Andersen2870d962001-07-02 17:27:21 +00009259freeparam(volatile struct shparam *param)
9260{
Eric Andersencb57d552001-06-28 07:25:16 +00009261 char **ap;
9262
9263 if (param->malloc) {
9264 for (ap = param->p ; *ap ; ap++)
9265 ckfree(*ap);
9266 ckfree(param->p);
9267 }
9268}
9269
9270
9271
9272/*
9273 * The shift builtin command.
9274 */
9275
9276static int
9277shiftcmd(argc, argv)
9278 int argc;
9279 char **argv;
9280{
9281 int n;
9282 char **ap1, **ap2;
9283
9284 n = 1;
9285 if (argc > 1)
9286 n = number(argv[1]);
9287 if (n > shellparam.nparam)
9288 error("can't shift that many");
9289 INTOFF;
9290 shellparam.nparam -= n;
9291 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
9292 if (shellparam.malloc)
9293 ckfree(*ap1);
9294 }
9295 ap2 = shellparam.p;
9296 while ((*ap2++ = *ap1++) != NULL);
9297 shellparam.optind = 1;
9298 shellparam.optoff = -1;
9299 INTON;
9300 return 0;
9301}
9302
9303
9304
9305/*
9306 * The set command builtin.
9307 */
9308
9309static int
9310setcmd(argc, argv)
9311 int argc;
9312 char **argv;
9313{
9314 if (argc == 1)
9315 return showvarscmd(argc, argv);
9316 INTOFF;
9317 options(0);
9318 optschanged();
9319 if (*argptr != NULL) {
9320 setparam(argptr);
9321 }
9322 INTON;
9323 return 0;
9324}
9325
9326
9327static void
Eric Andersen2870d962001-07-02 17:27:21 +00009328getoptsreset(const char *value)
Eric Andersencb57d552001-06-28 07:25:16 +00009329{
9330 shellparam.optind = number(value);
9331 shellparam.optoff = -1;
9332}
9333
Eric Andersen2870d962001-07-02 17:27:21 +00009334#ifdef BB_LOCALE_SUPPORT
9335static void change_lc_all(const char *value)
9336{
9337 if(value != 0 && *value != 0)
9338 setlocale(LC_ALL, value);
9339}
9340
9341static void change_lc_ctype(const char *value)
9342{
9343 if(value != 0 && *value != 0)
9344 setlocale(LC_CTYPE, value);
9345}
9346
9347#endif
9348
Eric Andersencb57d552001-06-28 07:25:16 +00009349#ifdef ASH_GETOPTS
9350/*
9351 * The getopts builtin. Shellparam.optnext points to the next argument
9352 * to be processed. Shellparam.optptr points to the next character to
9353 * be processed in the current argument. If shellparam.optnext is NULL,
9354 * then it's the first time getopts has been called.
9355 */
9356
9357static int
9358getoptscmd(argc, argv)
9359 int argc;
9360 char **argv;
9361{
9362 char **optbase;
9363
9364 if (argc < 3)
9365 error("Usage: getopts optstring var [arg]");
9366 else if (argc == 3) {
9367 optbase = shellparam.p;
9368 if (shellparam.optind > shellparam.nparam + 1) {
9369 shellparam.optind = 1;
9370 shellparam.optoff = -1;
9371 }
9372 }
9373 else {
9374 optbase = &argv[3];
9375 if (shellparam.optind > argc - 2) {
9376 shellparam.optind = 1;
9377 shellparam.optoff = -1;
9378 }
9379 }
9380
9381 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9382 &shellparam.optoff);
9383}
9384
9385/*
9386 * Safe version of setvar, returns 1 on success 0 on failure.
9387 */
9388
9389static int
9390setvarsafe(name, val, flags)
9391 const char *name, *val;
9392 int flags;
9393{
9394 struct jmploc jmploc;
9395 struct jmploc *volatile savehandler = handler;
9396 int err = 0;
9397#ifdef __GNUC__
9398 (void) &err;
9399#endif
9400
9401 if (setjmp(jmploc.loc))
9402 err = 1;
9403 else {
9404 handler = &jmploc;
9405 setvar(name, val, flags);
9406 }
9407 handler = savehandler;
9408 return err;
9409}
9410
9411static int
9412getopts(optstr, optvar, optfirst, myoptind, optoff)
9413 char *optstr;
9414 char *optvar;
9415 char **optfirst;
9416 int *myoptind;
9417 int *optoff;
9418{
9419 char *p, *q;
9420 char c = '?';
9421 int done = 0;
9422 int err = 0;
9423 char s[10];
9424 char **optnext = optfirst + *myoptind - 1;
9425
9426 if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
9427 strlen(*(optnext - 1)) < *optoff)
9428 p = NULL;
9429 else
9430 p = *(optnext - 1) + *optoff;
9431 if (p == NULL || *p == '\0') {
9432 /* Current word is done, advance */
9433 if (optnext == NULL)
9434 return 1;
9435 p = *optnext;
9436 if (p == NULL || *p != '-' || *++p == '\0') {
9437atend:
9438 *myoptind = optnext - optfirst + 1;
9439 p = NULL;
9440 done = 1;
9441 goto out;
9442 }
9443 optnext++;
Eric Andersen2870d962001-07-02 17:27:21 +00009444 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009445 goto atend;
9446 }
9447
9448 c = *p++;
9449 for (q = optstr; *q != c; ) {
9450 if (*q == '\0') {
9451 if (optstr[0] == ':') {
9452 s[0] = c;
9453 s[1] = '\0';
9454 err |= setvarsafe("OPTARG", s, 0);
9455 }
9456 else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009457 out2fmt("Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009458 (void) unsetvar("OPTARG");
9459 }
9460 c = '?';
9461 goto bad;
9462 }
9463 if (*++q == ':')
9464 q++;
9465 }
9466
9467 if (*++q == ':') {
9468 if (*p == '\0' && (p = *optnext) == NULL) {
9469 if (optstr[0] == ':') {
9470 s[0] = c;
9471 s[1] = '\0';
9472 err |= setvarsafe("OPTARG", s, 0);
9473 c = ':';
9474 }
9475 else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009476 out2fmt("No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009477 (void) unsetvar("OPTARG");
9478 c = '?';
9479 }
9480 goto bad;
9481 }
9482
9483 if (p == *optnext)
9484 optnext++;
9485 setvarsafe("OPTARG", p, 0);
9486 p = NULL;
9487 }
9488 else
9489 setvarsafe("OPTARG", "", 0);
9490 *myoptind = optnext - optfirst + 1;
9491 goto out;
9492
9493bad:
9494 *myoptind = 1;
9495 p = NULL;
9496out:
9497 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersen3102ac42001-07-06 04:26:23 +00009498 snprintf(s, sizeof(s), "%d", *myoptind);
Eric Andersencb57d552001-06-28 07:25:16 +00009499 err |= setvarsafe("OPTIND", s, VNOFUNC);
9500 s[0] = c;
9501 s[1] = '\0';
9502 err |= setvarsafe(optvar, s, 0);
9503 if (err) {
9504 *myoptind = 1;
9505 *optoff = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00009506 exraise(EXERROR);
9507 }
9508 return done;
9509}
Eric Andersen2870d962001-07-02 17:27:21 +00009510#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009511
9512/*
9513 * XXX - should get rid of. have all builtins use getopt(3). the
9514 * library getopt must have the BSD extension static variable "optreset"
9515 * otherwise it can't be used within the shell safely.
9516 *
9517 * Standard option processing (a la getopt) for builtin routines. The
9518 * only argument that is passed to nextopt is the option string; the
9519 * other arguments are unnecessary. It return the character, or '\0' on
9520 * end of input.
9521 */
9522
9523static int
Eric Andersen62483552001-07-10 06:09:16 +00009524nextopt(const char *optstring)
9525{
Eric Andersencb57d552001-06-28 07:25:16 +00009526 char *p;
9527 const char *q;
9528 char c;
9529
9530 if ((p = optptr) == NULL || *p == '\0') {
9531 p = *argptr;
9532 if (p == NULL || *p != '-' || *++p == '\0')
9533 return '\0';
9534 argptr++;
Eric Andersen2870d962001-07-02 17:27:21 +00009535 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009536 return '\0';
9537 }
9538 c = *p++;
9539 for (q = optstring ; *q != c ; ) {
9540 if (*q == '\0')
9541 error("Illegal option -%c", c);
9542 if (*++q == ':')
9543 q++;
9544 }
9545 if (*++q == ':') {
9546 if (*p == '\0' && (p = *argptr++) == NULL)
9547 error("No arg for -%c option", c);
9548 optionarg = p;
9549 p = NULL;
9550 }
9551 optptr = p;
9552 return c;
9553}
9554
Eric Andersencb57d552001-06-28 07:25:16 +00009555static void
9556flushall() {
Eric Andersencb57d552001-06-28 07:25:16 +00009557 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009558 fflush(stdout);
Eric Andersencb57d552001-06-28 07:25:16 +00009559 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009560}
9561
9562
9563static void
Eric Andersen3102ac42001-07-06 04:26:23 +00009564out2fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009565{
9566 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00009567 va_start(ap, fmt);
Eric Andersen3102ac42001-07-06 04:26:23 +00009568 vfprintf(stderr, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009569 va_end(ap);
9570}
9571
Eric Andersencb57d552001-06-28 07:25:16 +00009572/*
9573 * Version of write which resumes after a signal is caught.
9574 */
9575
9576static int
Eric Andersen2870d962001-07-02 17:27:21 +00009577xwrite(int fd, const char *buf, int nbytes)
9578{
Eric Andersencb57d552001-06-28 07:25:16 +00009579 int ntry;
9580 int i;
9581 int n;
9582
9583 n = nbytes;
9584 ntry = 0;
9585 for (;;) {
9586 i = write(fd, buf, n);
9587 if (i > 0) {
9588 if ((n -= i) <= 0)
9589 return nbytes;
9590 buf += i;
9591 ntry = 0;
9592 } else if (i == 0) {
9593 if (++ntry > 10)
9594 return nbytes - n;
9595 } else if (errno != EINTR) {
9596 return -1;
9597 }
9598 }
9599}
9600
9601
Eric Andersencb57d552001-06-28 07:25:16 +00009602/*
9603 * Shell command parser.
9604 */
9605
9606#define EOFMARKLEN 79
9607
9608
9609
9610struct heredoc {
Eric Andersen2870d962001-07-02 17:27:21 +00009611 struct heredoc *next; /* next here document in list */
9612 union node *here; /* redirection node */
9613 char *eofmark; /* string indicating end of input */
9614 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009615};
9616
Eric Andersen2870d962001-07-02 17:27:21 +00009617static struct heredoc *heredoclist; /* list of here documents to read */
9618static int parsebackquote; /* nonzero if we are inside backquotes */
9619static int doprompt; /* if set, prompt the user */
9620static int needprompt; /* true if interactive and at start of line */
9621static int lasttoken; /* last token read */
Eric Andersencb57d552001-06-28 07:25:16 +00009622
Eric Andersen2870d962001-07-02 17:27:21 +00009623static char *wordtext; /* text of last word returned by readtoken */
Eric Andersencb57d552001-06-28 07:25:16 +00009624
Eric Andersen2870d962001-07-02 17:27:21 +00009625static struct nodelist *backquotelist;
9626static union node *redirnode;
Eric Andersen044228d2001-07-17 01:12:36 +00009627static struct heredoc *heredoc;
Eric Andersen2870d962001-07-02 17:27:21 +00009628static int quoteflag; /* set if (part of) last token was quoted */
9629static int startlinno; /* line # where last token started */
Eric Andersencb57d552001-06-28 07:25:16 +00009630
9631
Eric Andersen2870d962001-07-02 17:27:21 +00009632static union node *list (int);
9633static union node *andor (void);
9634static union node *pipeline (void);
9635static union node *command (void);
9636static union node *simplecmd (void);
9637static void parsefname (void);
9638static void parseheredoc (void);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009639static char peektoken (void);
Eric Andersen2870d962001-07-02 17:27:21 +00009640static int readtoken (void);
9641static int xxreadtoken (void);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009642static int readtoken1 (int, int, const char *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00009643static int noexpand (char *);
9644static void synexpect (int) __attribute__((noreturn));
9645static void synerror (const char *) __attribute__((noreturn));
9646static void setprompt (int);
Eric Andersencb57d552001-06-28 07:25:16 +00009647
9648
9649/*
9650 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9651 * valid parse tree indicating a blank line.)
9652 */
9653
Eric Andersen2870d962001-07-02 17:27:21 +00009654static union node *
Eric Andersencb57d552001-06-28 07:25:16 +00009655parsecmd(int interact)
9656{
9657 int t;
9658
9659 tokpushback = 0;
9660 doprompt = interact;
9661 if (doprompt)
9662 setprompt(1);
9663 else
9664 setprompt(0);
9665 needprompt = 0;
9666 t = readtoken();
9667 if (t == TEOF)
9668 return NEOF;
9669 if (t == TNL)
9670 return NULL;
9671 tokpushback++;
9672 return list(1);
9673}
9674
9675
9676static union node *
9677list(nlflag)
9678 int nlflag;
9679{
9680 union node *n1, *n2, *n3;
9681 int tok;
9682
9683 checkkwd = 2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009684 if (nlflag == 0 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009685 return NULL;
9686 n1 = NULL;
9687 for (;;) {
9688 n2 = andor();
9689 tok = readtoken();
9690 if (tok == TBACKGND) {
9691 if (n2->type == NCMD || n2->type == NPIPE) {
9692 n2->ncmd.backgnd = 1;
9693 } else if (n2->type == NREDIR) {
9694 n2->type = NBACKGND;
9695 } else {
9696 n3 = (union node *)stalloc(sizeof (struct nredir));
9697 n3->type = NBACKGND;
9698 n3->nredir.n = n2;
9699 n3->nredir.redirect = NULL;
9700 n2 = n3;
9701 }
9702 }
9703 if (n1 == NULL) {
9704 n1 = n2;
9705 }
9706 else {
9707 n3 = (union node *)stalloc(sizeof (struct nbinary));
9708 n3->type = NSEMI;
9709 n3->nbinary.ch1 = n1;
9710 n3->nbinary.ch2 = n2;
9711 n1 = n3;
9712 }
9713 switch (tok) {
9714 case TBACKGND:
9715 case TSEMI:
9716 tok = readtoken();
9717 /* fall through */
9718 case TNL:
9719 if (tok == TNL) {
9720 parseheredoc();
9721 if (nlflag)
9722 return n1;
9723 } else {
9724 tokpushback++;
9725 }
9726 checkkwd = 2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009727 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009728 return n1;
9729 break;
9730 case TEOF:
9731 if (heredoclist)
9732 parseheredoc();
9733 else
Eric Andersen2870d962001-07-02 17:27:21 +00009734 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009735 return n1;
9736 default:
9737 if (nlflag)
9738 synexpect(-1);
9739 tokpushback++;
9740 return n1;
9741 }
9742 }
9743}
9744
9745
9746
9747static union node *
9748andor() {
9749 union node *n1, *n2, *n3;
9750 int t;
9751
9752 checkkwd = 1;
9753 n1 = pipeline();
9754 for (;;) {
9755 if ((t = readtoken()) == TAND) {
9756 t = NAND;
9757 } else if (t == TOR) {
9758 t = NOR;
9759 } else {
9760 tokpushback++;
9761 return n1;
9762 }
9763 checkkwd = 2;
9764 n2 = pipeline();
9765 n3 = (union node *)stalloc(sizeof (struct nbinary));
9766 n3->type = t;
9767 n3->nbinary.ch1 = n1;
9768 n3->nbinary.ch2 = n2;
9769 n1 = n3;
9770 }
9771}
9772
9773
9774
9775static union node *
9776pipeline() {
9777 union node *n1, *n2, *pipenode;
9778 struct nodelist *lp, *prev;
9779 int negate;
9780
9781 negate = 0;
9782 TRACE(("pipeline: entered\n"));
9783 if (readtoken() == TNOT) {
9784 negate = !negate;
9785 checkkwd = 1;
9786 } else
9787 tokpushback++;
9788 n1 = command();
9789 if (readtoken() == TPIPE) {
9790 pipenode = (union node *)stalloc(sizeof (struct npipe));
9791 pipenode->type = NPIPE;
9792 pipenode->npipe.backgnd = 0;
9793 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9794 pipenode->npipe.cmdlist = lp;
9795 lp->n = n1;
9796 do {
9797 prev = lp;
9798 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9799 checkkwd = 2;
9800 lp->n = command();
9801 prev->next = lp;
9802 } while (readtoken() == TPIPE);
9803 lp->next = NULL;
9804 n1 = pipenode;
9805 }
9806 tokpushback++;
9807 if (negate) {
9808 n2 = (union node *)stalloc(sizeof (struct nnot));
9809 n2->type = NNOT;
9810 n2->nnot.com = n1;
9811 return n2;
9812 } else
9813 return n1;
9814}
9815
9816
9817
9818static union node *
9819command() {
9820 union node *n1, *n2;
9821 union node *ap, **app;
9822 union node *cp, **cpp;
9823 union node *redir, **rpp;
9824 int t;
9825
9826 redir = NULL;
9827 n1 = NULL;
9828 rpp = &redir;
9829
Eric Andersen88cec252001-09-06 17:35:20 +00009830 /* Check for redirection which may precede command */
9831 while (readtoken() == TREDIR) {
9832 *rpp = n2 = redirnode;
9833 rpp = &n2->nfile.next;
9834 parsefname();
9835 }
9836 tokpushback++;
9837
Eric Andersencb57d552001-06-28 07:25:16 +00009838 switch (readtoken()) {
9839 case TIF:
9840 n1 = (union node *)stalloc(sizeof (struct nif));
9841 n1->type = NIF;
9842 n1->nif.test = list(0);
9843 if (readtoken() != TTHEN)
9844 synexpect(TTHEN);
9845 n1->nif.ifpart = list(0);
9846 n2 = n1;
9847 while (readtoken() == TELIF) {
9848 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9849 n2 = n2->nif.elsepart;
9850 n2->type = NIF;
9851 n2->nif.test = list(0);
9852 if (readtoken() != TTHEN)
9853 synexpect(TTHEN);
9854 n2->nif.ifpart = list(0);
9855 }
9856 if (lasttoken == TELSE)
9857 n2->nif.elsepart = list(0);
9858 else {
9859 n2->nif.elsepart = NULL;
9860 tokpushback++;
9861 }
9862 if (readtoken() != TFI)
9863 synexpect(TFI);
9864 checkkwd = 1;
9865 break;
9866 case TWHILE:
9867 case TUNTIL: {
9868 int got;
9869 n1 = (union node *)stalloc(sizeof (struct nbinary));
9870 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9871 n1->nbinary.ch1 = list(0);
9872 if ((got=readtoken()) != TDO) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009873TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009874 synexpect(TDO);
9875 }
9876 n1->nbinary.ch2 = list(0);
9877 if (readtoken() != TDONE)
9878 synexpect(TDONE);
9879 checkkwd = 1;
9880 break;
9881 }
9882 case TFOR:
9883 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9884 synerror("Bad for loop variable");
9885 n1 = (union node *)stalloc(sizeof (struct nfor));
9886 n1->type = NFOR;
9887 n1->nfor.var = wordtext;
9888 checkkwd = 1;
9889 if (readtoken() == TIN) {
9890 app = &ap;
9891 while (readtoken() == TWORD) {
9892 n2 = (union node *)stalloc(sizeof (struct narg));
9893 n2->type = NARG;
9894 n2->narg.text = wordtext;
9895 n2->narg.backquote = backquotelist;
9896 *app = n2;
9897 app = &n2->narg.next;
9898 }
9899 *app = NULL;
9900 n1->nfor.args = ap;
9901 if (lasttoken != TNL && lasttoken != TSEMI)
9902 synexpect(-1);
9903 } else {
9904 static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
9905 '@', '=', '\0'};
9906 n2 = (union node *)stalloc(sizeof (struct narg));
9907 n2->type = NARG;
9908 n2->narg.text = argvars;
9909 n2->narg.backquote = NULL;
9910 n2->narg.next = NULL;
9911 n1->nfor.args = n2;
9912 /*
9913 * Newline or semicolon here is optional (but note
9914 * that the original Bourne shell only allowed NL).
9915 */
9916 if (lasttoken != TNL && lasttoken != TSEMI)
9917 tokpushback++;
9918 }
9919 checkkwd = 2;
9920 if (readtoken() != TDO)
9921 synexpect(TDO);
9922 n1->nfor.body = list(0);
9923 if (readtoken() != TDONE)
9924 synexpect(TDONE);
9925 checkkwd = 1;
9926 break;
9927 case TCASE:
9928 n1 = (union node *)stalloc(sizeof (struct ncase));
9929 n1->type = NCASE;
9930 if (readtoken() != TWORD)
9931 synexpect(TWORD);
9932 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9933 n2->type = NARG;
9934 n2->narg.text = wordtext;
9935 n2->narg.backquote = backquotelist;
9936 n2->narg.next = NULL;
9937 do {
9938 checkkwd = 1;
9939 } while (readtoken() == TNL);
9940 if (lasttoken != TIN)
9941 synerror("expecting \"in\"");
9942 cpp = &n1->ncase.cases;
9943 checkkwd = 2, readtoken();
9944 do {
9945 if (lasttoken == TLP)
9946 readtoken();
9947 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9948 cp->type = NCLIST;
9949 app = &cp->nclist.pattern;
9950 for (;;) {
9951 *app = ap = (union node *)stalloc(sizeof (struct narg));
9952 ap->type = NARG;
9953 ap->narg.text = wordtext;
9954 ap->narg.backquote = backquotelist;
9955 if (checkkwd = 2, readtoken() != TPIPE)
9956 break;
9957 app = &ap->narg.next;
9958 readtoken();
9959 }
9960 ap->narg.next = NULL;
9961 if (lasttoken != TRP)
9962 synexpect(TRP);
9963 cp->nclist.body = list(0);
9964
9965 checkkwd = 2;
9966 if ((t = readtoken()) != TESAC) {
9967 if (t != TENDCASE)
9968 synexpect(TENDCASE);
9969 else
9970 checkkwd = 2, readtoken();
9971 }
9972 cpp = &cp->nclist.next;
9973 } while(lasttoken != TESAC);
9974 *cpp = NULL;
9975 checkkwd = 1;
9976 break;
9977 case TLP:
9978 n1 = (union node *)stalloc(sizeof (struct nredir));
9979 n1->type = NSUBSHELL;
9980 n1->nredir.n = list(0);
9981 n1->nredir.redirect = NULL;
9982 if (readtoken() != TRP)
9983 synexpect(TRP);
9984 checkkwd = 1;
9985 break;
9986 case TBEGIN:
9987 n1 = list(0);
9988 if (readtoken() != TEND)
9989 synexpect(TEND);
9990 checkkwd = 1;
9991 break;
9992 /* Handle an empty command like other simple commands. */
9993 case TSEMI:
9994 case TAND:
9995 case TOR:
9996 case TNL:
9997 case TEOF:
9998 case TRP:
9999 case TBACKGND:
10000 /*
10001 * An empty command before a ; doesn't make much sense, and
10002 * should certainly be disallowed in the case of `if ;'.
10003 */
10004 if (!redir)
10005 synexpect(-1);
10006 case TWORD:
Eric Andersencb57d552001-06-28 07:25:16 +000010007 tokpushback++;
10008 n1 = simplecmd();
10009 return n1;
10010 default:
10011 synexpect(-1);
10012 /* NOTREACHED */
10013 }
10014
10015 /* Now check for redirection which may follow command */
10016 while (readtoken() == TREDIR) {
10017 *rpp = n2 = redirnode;
10018 rpp = &n2->nfile.next;
10019 parsefname();
10020 }
10021 tokpushback++;
10022 *rpp = NULL;
10023 if (redir) {
10024 if (n1->type != NSUBSHELL) {
10025 n2 = (union node *)stalloc(sizeof (struct nredir));
10026 n2->type = NREDIR;
10027 n2->nredir.n = n1;
10028 n1 = n2;
10029 }
10030 n1->nredir.redirect = redir;
10031 }
10032
10033 return n1;
10034}
10035
10036
10037static union node *
10038simplecmd() {
10039 union node *args, **app;
10040 union node *n = NULL;
10041 union node *vars, **vpp;
10042 union node **rpp, *redir;
10043
10044 args = NULL;
10045 app = &args;
10046 vars = NULL;
10047 vpp = &vars;
10048 redir = NULL;
10049 rpp = &redir;
10050
10051 checkalias = 2;
10052 for (;;) {
10053 switch (readtoken()) {
10054 case TWORD:
10055 case TASSIGN:
10056 n = (union node *)stalloc(sizeof (struct narg));
10057 n->type = NARG;
10058 n->narg.text = wordtext;
10059 n->narg.backquote = backquotelist;
10060 if (lasttoken == TWORD) {
10061 *app = n;
10062 app = &n->narg.next;
10063 } else {
10064 *vpp = n;
10065 vpp = &n->narg.next;
10066 }
10067 break;
10068 case TREDIR:
10069 *rpp = n = redirnode;
10070 rpp = &n->nfile.next;
Eric Andersen2870d962001-07-02 17:27:21 +000010071 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +000010072 break;
10073 case TLP:
10074 if (
10075 args && app == &args->narg.next &&
10076 !vars && !redir
10077 ) {
10078 /* We have a function */
10079 if (readtoken() != TRP)
10080 synexpect(TRP);
Eric Andersencb57d552001-06-28 07:25:16 +000010081 n->type = NDEFUN;
10082 checkkwd = 2;
10083 n->narg.next = command();
10084 return n;
10085 }
10086 /* fall through */
10087 default:
10088 tokpushback++;
10089 goto out;
10090 }
10091 }
10092out:
10093 *app = NULL;
10094 *vpp = NULL;
10095 *rpp = NULL;
10096 n = (union node *)stalloc(sizeof (struct ncmd));
10097 n->type = NCMD;
10098 n->ncmd.backgnd = 0;
10099 n->ncmd.args = args;
10100 n->ncmd.assign = vars;
10101 n->ncmd.redirect = redir;
10102 return n;
10103}
10104
10105static union node *
Eric Andersen2870d962001-07-02 17:27:21 +000010106makename(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000010107 union node *n;
10108
10109 n = (union node *)stalloc(sizeof (struct narg));
10110 n->type = NARG;
10111 n->narg.next = NULL;
10112 n->narg.text = wordtext;
10113 n->narg.backquote = backquotelist;
10114 return n;
10115}
10116
10117static void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +000010118{
Eric Andersencb57d552001-06-28 07:25:16 +000010119 TRACE(("Fix redir %s %d\n", text, err));
10120 if (!err)
10121 n->ndup.vname = NULL;
10122
10123 if (is_digit(text[0]) && text[1] == '\0')
10124 n->ndup.dupfd = digit_val(text[0]);
10125 else if (text[0] == '-' && text[1] == '\0')
10126 n->ndup.dupfd = -1;
10127 else {
10128
10129 if (err)
10130 synerror("Bad fd number");
10131 else
10132 n->ndup.vname = makename();
10133 }
10134}
10135
10136
10137static void
Eric Andersen2870d962001-07-02 17:27:21 +000010138parsefname(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000010139 union node *n = redirnode;
10140
10141 if (readtoken() != TWORD)
10142 synexpect(-1);
10143 if (n->type == NHERE) {
10144 struct heredoc *here = heredoc;
10145 struct heredoc *p;
10146 int i;
10147
10148 if (quoteflag == 0)
10149 n->type = NXHERE;
10150 TRACE(("Here document %d\n", n->type));
10151 if (here->striptabs) {
10152 while (*wordtext == '\t')
10153 wordtext++;
10154 }
10155 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
10156 synerror("Illegal eof marker for << redirection");
10157 rmescapes(wordtext);
10158 here->eofmark = wordtext;
10159 here->next = NULL;
10160 if (heredoclist == NULL)
10161 heredoclist = here;
10162 else {
10163 for (p = heredoclist ; p->next ; p = p->next);
10164 p->next = here;
10165 }
10166 } else if (n->type == NTOFD || n->type == NFROMFD) {
10167 fixredir(n, wordtext, 0);
10168 } else {
10169 n->nfile.fname = makename();
10170 }
10171}
10172
10173
10174/*
10175 * Input any here documents.
10176 */
10177
10178static void
10179parseheredoc() {
10180 struct heredoc *here;
10181 union node *n;
10182
10183 while (heredoclist) {
10184 here = heredoclist;
10185 heredoclist = here->next;
10186 if (needprompt) {
10187 setprompt(2);
10188 needprompt = 0;
10189 }
10190 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
10191 here->eofmark, here->striptabs);
10192 n = (union node *)stalloc(sizeof (struct narg));
10193 n->narg.type = NARG;
10194 n->narg.next = NULL;
10195 n->narg.text = wordtext;
10196 n->narg.backquote = backquotelist;
10197 here->here->nhere.doc = n;
10198 }
10199}
10200
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010201static char
Eric Andersencb57d552001-06-28 07:25:16 +000010202peektoken() {
10203 int t;
10204
10205 t = readtoken();
10206 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010207 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +000010208}
10209
10210static int
10211readtoken() {
10212 int t;
Eric Andersen7467c8d2001-07-12 20:26:32 +000010213
Eric Andersen2870d962001-07-02 17:27:21 +000010214#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010215 int savecheckalias = checkalias;
Eric Andersen7467c8d2001-07-12 20:26:32 +000010216 int savecheckkwd = checkkwd;
Eric Andersencb57d552001-06-28 07:25:16 +000010217 struct alias *ap;
Eric Andersen2870d962001-07-02 17:27:21 +000010218#endif
10219
Eric Andersencb57d552001-06-28 07:25:16 +000010220#ifdef DEBUG
10221 int alreadyseen = tokpushback;
10222#endif
10223
Eric Andersen2870d962001-07-02 17:27:21 +000010224#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010225top:
Eric Andersen2870d962001-07-02 17:27:21 +000010226#endif
10227
Eric Andersencb57d552001-06-28 07:25:16 +000010228 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +000010229
10230#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010231 checkalias = savecheckalias;
Eric Andersen2870d962001-07-02 17:27:21 +000010232#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010233
10234 if (checkkwd) {
10235 /*
10236 * eat newlines
10237 */
10238 if (checkkwd == 2) {
10239 checkkwd = 0;
10240 while (t == TNL) {
10241 parseheredoc();
10242 t = xxreadtoken();
10243 }
10244 }
10245 checkkwd = 0;
10246 /*
10247 * check for keywords
10248 */
10249 if (t == TWORD && !quoteflag)
10250 {
10251 const char *const *pp;
10252
10253 if ((pp = findkwd(wordtext))) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010254 lasttoken = t = pp - tokname_array;
10255 TRACE(("keyword %s recognized\n", tokname(t)));
Eric Andersencb57d552001-06-28 07:25:16 +000010256 goto out;
10257 }
10258 }
10259 }
10260
Eric Andersen7467c8d2001-07-12 20:26:32 +000010261
Eric Andersencb57d552001-06-28 07:25:16 +000010262 if (t != TWORD) {
10263 if (t != TREDIR) {
10264 checkalias = 0;
10265 }
10266 } else if (checkalias == 2 && isassignment(wordtext)) {
10267 lasttoken = t = TASSIGN;
Eric Andersen7467c8d2001-07-12 20:26:32 +000010268#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010269 } else if (checkalias) {
10270 if (!quoteflag && (ap = lookupalias(wordtext, 1)) != NULL) {
10271 if (*ap->val) {
10272 pushstring(ap->val, strlen(ap->val), ap);
10273 }
10274 checkkwd = savecheckkwd;
10275 goto top;
10276 }
10277 checkalias = 0;
Eric Andersen2870d962001-07-02 17:27:21 +000010278#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +000010279 }
Eric Andersencb57d552001-06-28 07:25:16 +000010280out:
10281#ifdef DEBUG
10282 if (!alreadyseen)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010283 TRACE(("token %s %s\n", tokname(t), t == TWORD || t == TASSIGN ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +000010284 else
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010285 TRACE(("reread token %s %s\n", tokname(t), t == TWORD || t == TASSIGN ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +000010286#endif
10287 return (t);
10288}
10289
10290
10291/*
10292 * Read the next input token.
10293 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +000010294 * backquotes. We set quoteflag to true if any part of the word was
10295 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +000010296 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +000010297 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +000010298 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +000010299 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +000010300 *
10301 * [Change comment: here documents and internal procedures]
10302 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10303 * word parsing code into a separate routine. In this case, readtoken
10304 * doesn't need to have any internal procedures, but parseword does.
10305 * We could also make parseoperator in essence the main routine, and
10306 * have parseword (readtoken1?) handle both words and redirection.]
10307 */
10308
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +000010309#define NEW_xxreadtoken
10310#ifdef NEW_xxreadtoken
10311
10312static const char xxreadtoken_chars[] = "\n()&|;"; /* singles must be first! */
10313static const char xxreadtoken_tokens[] = {
10314 TNL, TLP, TRP, /* only single occurrence allowed */
10315 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10316 TEOF, /* corresponds to trailing nul */
10317 TAND, TOR, TENDCASE, /* if double occurrence */
10318};
10319
10320#define xxreadtoken_doubles \
10321 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10322#define xxreadtoken_singles \
10323 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10324
10325static int
10326xxreadtoken() {
10327 int c;
10328
10329 if (tokpushback) {
10330 tokpushback = 0;
10331 return lasttoken;
10332 }
10333 if (needprompt) {
10334 setprompt(2);
10335 needprompt = 0;
10336 }
10337 startlinno = plinno;
10338 for (;;) { /* until token or start of word found */
10339 c = pgetc_macro();
10340
10341 if ((c!=' ') && (c!='\t')
10342#ifdef ASH_ALIAS
10343 && (c!=PEOA)
10344#endif
10345 ) {
10346 if (c=='#') {
10347 while ((c = pgetc()) != '\n' && c != PEOF);
10348 pungetc();
10349 } else if (c=='\\') {
10350 if (pgetc() != '\n') {
10351 pungetc();
10352 goto READTOKEN1;
10353 }
10354 startlinno = ++plinno;
10355 setprompt(doprompt ? 2 : 0);
10356 } else {
10357 const char *p
10358 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10359
10360 if (c!=PEOF) {
10361 if (c=='\n') {
10362 plinno++;
10363 needprompt = doprompt;
10364 }
10365
10366 p = strchr(xxreadtoken_chars, c);
10367 if (p == NULL) {
10368 READTOKEN1:
10369 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10370 }
10371
10372 if (p-xxreadtoken_chars >= xxreadtoken_singles) {
10373 if (pgetc() == *p) { /* double occurrence? */
10374 p += xxreadtoken_doubles + 1;
10375 } else {
10376 pungetc();
10377 }
10378 }
10379 }
10380
10381 return lasttoken = xxreadtoken_tokens[p-xxreadtoken_chars];
10382 }
10383 }
10384 }
10385}
10386
10387
10388#else
Eric Andersen2870d962001-07-02 17:27:21 +000010389#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010390
10391static int
10392xxreadtoken() {
10393 int c;
10394
10395 if (tokpushback) {
10396 tokpushback = 0;
10397 return lasttoken;
10398 }
10399 if (needprompt) {
10400 setprompt(2);
10401 needprompt = 0;
10402 }
10403 startlinno = plinno;
Eric Andersen2870d962001-07-02 17:27:21 +000010404 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010405 c = pgetc_macro();
10406 switch (c) {
10407 case ' ': case '\t':
Eric Andersen3102ac42001-07-06 04:26:23 +000010408#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010409 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010410#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010411 continue;
10412 case '#':
10413 while ((c = pgetc()) != '\n' && c != PEOF);
10414 pungetc();
10415 continue;
10416 case '\\':
10417 if (pgetc() == '\n') {
10418 startlinno = ++plinno;
10419 if (doprompt)
10420 setprompt(2);
10421 else
10422 setprompt(0);
10423 continue;
10424 }
10425 pungetc();
10426 goto breakloop;
10427 case '\n':
10428 plinno++;
10429 needprompt = doprompt;
10430 RETURN(TNL);
10431 case PEOF:
10432 RETURN(TEOF);
10433 case '&':
10434 if (pgetc() == '&')
10435 RETURN(TAND);
10436 pungetc();
10437 RETURN(TBACKGND);
10438 case '|':
10439 if (pgetc() == '|')
10440 RETURN(TOR);
10441 pungetc();
10442 RETURN(TPIPE);
10443 case ';':
10444 if (pgetc() == ';')
10445 RETURN(TENDCASE);
10446 pungetc();
10447 RETURN(TSEMI);
10448 case '(':
10449 RETURN(TLP);
10450 case ')':
10451 RETURN(TRP);
10452 default:
10453 goto breakloop;
10454 }
10455 }
10456breakloop:
10457 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10458#undef RETURN
10459}
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +000010460#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010461
10462
10463/*
10464 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10465 * is not NULL, read a here document. In the latter case, eofmark is the
10466 * word which marks the end of the document and striptabs is true if
10467 * leading tabs should be stripped from the document. The argument firstc
10468 * is the first character of the input token or document.
10469 *
10470 * Because C does not have internal subroutines, I have simulated them
10471 * using goto's to implement the subroutine linkage. The following macros
10472 * will run code that appears at the end of readtoken1.
10473 */
10474
Eric Andersen2870d962001-07-02 17:27:21 +000010475#define CHECKEND() {goto checkend; checkend_return:;}
10476#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10477#define PARSESUB() {goto parsesub; parsesub_return:;}
10478#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10479#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10480#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010481
10482static int
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010483readtoken1(int firstc, int syntax, const char *eofmark, int striptabs)
10484{
Eric Andersencb57d552001-06-28 07:25:16 +000010485 int c = firstc;
10486 char *out;
10487 int len;
10488 char line[EOFMARKLEN + 1];
10489 struct nodelist *bqlist;
10490 int quotef;
10491 int dblquote;
Eric Andersen2870d962001-07-02 17:27:21 +000010492 int varnest; /* levels of variables expansion */
10493 int arinest; /* levels of arithmetic expansion */
10494 int parenlevel; /* levels of parens in arithmetic */
10495 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +000010496 int oldstyle;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010497 int prevsyntax; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010498#if __GNUC__
10499 /* Avoid longjmp clobbering */
10500 (void) &out;
10501 (void) &quotef;
10502 (void) &dblquote;
10503 (void) &varnest;
10504 (void) &arinest;
10505 (void) &parenlevel;
10506 (void) &dqvarnest;
10507 (void) &oldstyle;
10508 (void) &prevsyntax;
10509 (void) &syntax;
10510#endif
10511
10512 startlinno = plinno;
10513 dblquote = 0;
10514 if (syntax == DQSYNTAX)
10515 dblquote = 1;
10516 quotef = 0;
10517 bqlist = NULL;
10518 varnest = 0;
10519 arinest = 0;
10520 parenlevel = 0;
10521 dqvarnest = 0;
10522
10523 STARTSTACKSTR(out);
Eric Andersen2870d962001-07-02 17:27:21 +000010524 loop: { /* for each line, until end of word */
10525 CHECKEND(); /* set c to PEOF if at end of here document */
10526 for (;;) { /* until end of line or end of word */
10527 CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010528 switch(SIT(c,syntax)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010529 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010530 if (syntax == BASESYNTAX)
Eric Andersen2870d962001-07-02 17:27:21 +000010531 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010532 USTPUTC(c, out);
10533 plinno++;
10534 if (doprompt)
10535 setprompt(2);
10536 else
10537 setprompt(0);
10538 c = pgetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010539 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010540 case CWORD:
10541 USTPUTC(c, out);
10542 break;
10543 case CCTL:
10544 if ((eofmark == NULL || dblquote) &&
10545 dqvarnest == 0)
10546 USTPUTC(CTLESC, out);
10547 USTPUTC(c, out);
10548 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010549 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010550 c = pgetc2();
10551 if (c == PEOF) {
10552 USTPUTC('\\', out);
10553 pungetc();
10554 } else if (c == '\n') {
10555 if (doprompt)
10556 setprompt(2);
10557 else
10558 setprompt(0);
10559 } else {
10560 if (dblquote && c != '\\' && c != '`' && c != '$'
10561 && (c != '"' || eofmark != NULL))
10562 USTPUTC('\\', out);
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010563 if (SIT(c,SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010564 USTPUTC(CTLESC, out);
10565 else if (eofmark == NULL)
10566 USTPUTC(CTLQUOTEMARK, out);
10567 USTPUTC(c, out);
10568 quotef++;
10569 }
10570 break;
10571 case CSQUOTE:
10572 if (eofmark == NULL)
10573 USTPUTC(CTLQUOTEMARK, out);
10574 syntax = SQSYNTAX;
10575 break;
10576 case CDQUOTE:
10577 if (eofmark == NULL)
10578 USTPUTC(CTLQUOTEMARK, out);
10579 syntax = DQSYNTAX;
10580 dblquote = 1;
10581 break;
10582 case CENDQUOTE:
10583 if (eofmark != NULL && arinest == 0 &&
10584 varnest == 0) {
10585 USTPUTC(c, out);
10586 } else {
10587 if (arinest) {
10588 syntax = ARISYNTAX;
10589 dblquote = 0;
10590 } else if (eofmark == NULL &&
10591 dqvarnest == 0) {
10592 syntax = BASESYNTAX;
10593 dblquote = 0;
10594 }
10595 quotef++;
10596 }
10597 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010598 case CVAR: /* '$' */
10599 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010600 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010601 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010602 if (varnest > 0) {
10603 varnest--;
10604 if (dqvarnest > 0) {
10605 dqvarnest--;
10606 }
10607 USTPUTC(CTLENDVAR, out);
10608 } else {
10609 USTPUTC(c, out);
10610 }
10611 break;
10612#ifdef ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +000010613 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010614 parenlevel++;
10615 USTPUTC(c, out);
10616 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010617 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010618 if (parenlevel > 0) {
10619 USTPUTC(c, out);
10620 --parenlevel;
10621 } else {
10622 if (pgetc() == ')') {
10623 if (--arinest == 0) {
10624 USTPUTC(CTLENDARI, out);
10625 syntax = prevsyntax;
10626 if (syntax == DQSYNTAX)
10627 dblquote = 1;
10628 else
10629 dblquote = 0;
10630 } else
10631 USTPUTC(')', out);
10632 } else {
10633 /*
10634 * unbalanced parens
10635 * (don't 2nd guess - no error)
10636 */
10637 pungetc();
10638 USTPUTC(')', out);
10639 }
10640 }
10641 break;
10642#endif
Eric Andersen2870d962001-07-02 17:27:21 +000010643 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010644 PARSEBACKQOLD();
10645 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010646 case CENDFILE:
10647 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010648 case CIGN:
10649 break;
10650 default:
10651 if (varnest == 0)
Eric Andersen2870d962001-07-02 17:27:21 +000010652 goto endword; /* exit outer loop */
Eric Andersen3102ac42001-07-06 04:26:23 +000010653#ifdef ASH_ALIAS
10654 if (c != PEOA)
10655#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010656 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010657
Eric Andersencb57d552001-06-28 07:25:16 +000010658 }
10659 c = pgetc_macro();
10660 }
10661 }
10662endword:
10663 if (syntax == ARISYNTAX)
10664 synerror("Missing '))'");
10665 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10666 synerror("Unterminated quoted string");
10667 if (varnest != 0) {
10668 startlinno = plinno;
10669 synerror("Missing '}'");
10670 }
10671 USTPUTC('\0', out);
10672 len = out - stackblock();
10673 out = stackblock();
10674 if (eofmark == NULL) {
10675 if ((c == '>' || c == '<')
10676 && quotef == 0
10677 && len <= 2
10678 && (*out == '\0' || is_digit(*out))) {
10679 PARSEREDIR();
10680 return lasttoken = TREDIR;
10681 } else {
10682 pungetc();
10683 }
10684 }
10685 quoteflag = quotef;
10686 backquotelist = bqlist;
10687 grabstackblock(len);
10688 wordtext = out;
10689 return lasttoken = TWORD;
10690/* end of readtoken routine */
10691
10692
10693
10694/*
10695 * Check to see whether we are at the end of the here document. When this
10696 * is called, c is set to the first character of the next input line. If
10697 * we are at the end of the here document, this routine sets the c to PEOF.
10698 */
10699
10700checkend: {
10701 if (eofmark) {
Eric Andersen2870d962001-07-02 17:27:21 +000010702#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010703 if (c == PEOA) {
10704 c = pgetc2();
10705 }
Eric Andersen2870d962001-07-02 17:27:21 +000010706#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010707 if (striptabs) {
10708 while (c == '\t') {
10709 c = pgetc2();
10710 }
10711 }
10712 if (c == *eofmark) {
10713 if (pfgets(line, sizeof line) != NULL) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010714 const char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010715
10716 p = line;
10717 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10718 if (*p == '\n' && *q == '\0') {
10719 c = PEOF;
10720 plinno++;
10721 needprompt = doprompt;
10722 } else {
10723 pushstring(line, strlen(line), NULL);
10724 }
10725 }
10726 }
10727 }
10728 goto checkend_return;
10729}
10730
10731
10732/*
10733 * Parse a redirection operator. The variable "out" points to a string
10734 * specifying the fd to be redirected. The variable "c" contains the
10735 * first character of the redirection operator.
10736 */
10737
10738parseredir: {
10739 char fd = *out;
10740 union node *np;
10741
10742 np = (union node *)stalloc(sizeof (struct nfile));
10743 if (c == '>') {
10744 np->nfile.fd = 1;
10745 c = pgetc();
10746 if (c == '>')
10747 np->type = NAPPEND;
10748 else if (c == '&')
10749 np->type = NTOFD;
10750 else if (c == '|')
10751 np->type = NTOOV;
10752 else {
10753 np->type = NTO;
10754 pungetc();
10755 }
Eric Andersen2870d962001-07-02 17:27:21 +000010756 } else { /* c == '<' */
Eric Andersencb57d552001-06-28 07:25:16 +000010757 np->nfile.fd = 0;
10758 switch (c = pgetc()) {
10759 case '<':
10760 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10761 np = (union node *)stalloc(sizeof (struct nhere));
10762 np->nfile.fd = 0;
10763 }
10764 np->type = NHERE;
10765 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10766 heredoc->here = np;
10767 if ((c = pgetc()) == '-') {
10768 heredoc->striptabs = 1;
10769 } else {
10770 heredoc->striptabs = 0;
10771 pungetc();
10772 }
10773 break;
10774
10775 case '&':
10776 np->type = NFROMFD;
10777 break;
10778
10779 case '>':
10780 np->type = NFROMTO;
10781 break;
10782
10783 default:
10784 np->type = NFROM;
10785 pungetc();
10786 break;
10787 }
10788 }
10789 if (fd != '\0')
10790 np->nfile.fd = digit_val(fd);
10791 redirnode = np;
10792 goto parseredir_return;
10793}
10794
10795
10796/*
10797 * Parse a substitution. At this point, we have read the dollar sign
10798 * and nothing else.
10799 */
10800
10801parsesub: {
10802 int subtype;
10803 int typeloc;
10804 int flags;
10805 char *p;
10806 static const char types[] = "}-+?=";
10807
10808 c = pgetc();
10809 if (
10810 c <= PEOA ||
10811 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10812 ) {
10813 USTPUTC('$', out);
10814 pungetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010815 } else if (c == '(') { /* $(command) or $((arith)) */
Eric Andersencb57d552001-06-28 07:25:16 +000010816 if (pgetc() == '(') {
10817 PARSEARITH();
10818 } else {
10819 pungetc();
10820 PARSEBACKQNEW();
10821 }
10822 } else {
10823 USTPUTC(CTLVAR, out);
10824 typeloc = out - stackblock();
10825 USTPUTC(VSNORMAL, out);
10826 subtype = VSNORMAL;
10827 if (c == '{') {
10828 c = pgetc();
10829 if (c == '#') {
10830 if ((c = pgetc()) == '}')
10831 c = '#';
10832 else
10833 subtype = VSLENGTH;
10834 }
10835 else
10836 subtype = 0;
10837 }
10838 if (c > PEOA && is_name(c)) {
10839 do {
10840 STPUTC(c, out);
10841 c = pgetc();
10842 } while (c > PEOA && is_in_name(c));
10843 } else if (is_digit(c)) {
10844 do {
10845 USTPUTC(c, out);
10846 c = pgetc();
10847 } while (is_digit(c));
10848 }
10849 else if (is_special(c)) {
10850 USTPUTC(c, out);
10851 c = pgetc();
10852 }
10853 else
Eric Andersen2870d962001-07-02 17:27:21 +000010854badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010855
10856 STPUTC('=', out);
10857 flags = 0;
10858 if (subtype == 0) {
10859 switch (c) {
10860 case ':':
10861 flags = VSNUL;
10862 c = pgetc();
10863 /*FALLTHROUGH*/
10864 default:
10865 p = strchr(types, c);
10866 if (p == NULL)
10867 goto badsub;
10868 subtype = p - types + VSNORMAL;
10869 break;
10870 case '%':
10871 case '#':
10872 {
10873 int cc = c;
10874 subtype = c == '#' ? VSTRIMLEFT :
10875 VSTRIMRIGHT;
10876 c = pgetc();
10877 if (c == cc)
10878 subtype++;
10879 else
10880 pungetc();
10881 break;
10882 }
10883 }
10884 } else {
10885 pungetc();
10886 }
10887 if (dblquote || arinest)
10888 flags |= VSQUOTE;
10889 *(stackblock() + typeloc) = subtype | flags;
10890 if (subtype != VSNORMAL) {
10891 varnest++;
10892 if (dblquote) {
10893 dqvarnest++;
10894 }
10895 }
10896 }
10897 goto parsesub_return;
10898}
10899
10900
10901/*
10902 * Called to parse command substitutions. Newstyle is set if the command
10903 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10904 * list of commands (passed by reference), and savelen is the number of
10905 * characters on the top of the stack which must be preserved.
10906 */
10907
10908parsebackq: {
10909 struct nodelist **nlpp;
10910 int savepbq;
10911 union node *n;
10912 char *volatile str;
10913 struct jmploc jmploc;
10914 struct jmploc *volatile savehandler;
10915 int savelen;
10916 int saveprompt;
10917#ifdef __GNUC__
10918 (void) &saveprompt;
10919#endif
10920
10921 savepbq = parsebackquote;
10922 if (setjmp(jmploc.loc)) {
10923 if (str)
10924 ckfree(str);
10925 parsebackquote = 0;
10926 handler = savehandler;
10927 longjmp(handler->loc, 1);
10928 }
10929 INTOFF;
10930 str = NULL;
10931 savelen = out - stackblock();
10932 if (savelen > 0) {
10933 str = ckmalloc(savelen);
10934 memcpy(str, stackblock(), savelen);
10935 }
10936 savehandler = handler;
10937 handler = &jmploc;
10938 INTON;
Eric Andersen2870d962001-07-02 17:27:21 +000010939 if (oldstyle) {
10940 /* We must read until the closing backquote, giving special
10941 treatment to some slashes, and then push the string and
10942 reread it as input, interpreting it normally. */
10943 char *pout;
10944 int pc;
10945 int psavelen;
10946 char *pstr;
Eric Andersencb57d552001-06-28 07:25:16 +000010947
10948
Eric Andersen2870d962001-07-02 17:27:21 +000010949 STARTSTACKSTR(pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010950 for (;;) {
10951 if (needprompt) {
10952 setprompt(2);
10953 needprompt = 0;
10954 }
10955 switch (pc = pgetc()) {
10956 case '`':
10957 goto done;
10958
10959 case '\\':
Eric Andersen2870d962001-07-02 17:27:21 +000010960 if ((pc = pgetc()) == '\n') {
Eric Andersencb57d552001-06-28 07:25:16 +000010961 plinno++;
10962 if (doprompt)
10963 setprompt(2);
10964 else
10965 setprompt(0);
10966 /*
10967 * If eating a newline, avoid putting
10968 * the newline into the new character
10969 * stream (via the STPUTC after the
10970 * switch).
10971 */
10972 continue;
10973 }
Eric Andersen2870d962001-07-02 17:27:21 +000010974 if (pc != '\\' && pc != '`' && pc != '$'
10975 && (!dblquote || pc != '"'))
10976 STPUTC('\\', pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010977 if (pc > PEOA) {
10978 break;
10979 }
10980 /* fall through */
10981
10982 case PEOF:
Eric Andersen2870d962001-07-02 17:27:21 +000010983#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010984 case PEOA:
Eric Andersen2870d962001-07-02 17:27:21 +000010985#endif
10986 startlinno = plinno;
Eric Andersencb57d552001-06-28 07:25:16 +000010987 synerror("EOF in backquote substitution");
10988
10989 case '\n':
10990 plinno++;
10991 needprompt = doprompt;
10992 break;
10993
10994 default:
10995 break;
10996 }
10997 STPUTC(pc, pout);
Eric Andersen2870d962001-07-02 17:27:21 +000010998 }
Eric Andersencb57d552001-06-28 07:25:16 +000010999done:
Eric Andersen2870d962001-07-02 17:27:21 +000011000 STPUTC('\0', pout);
11001 psavelen = pout - stackblock();
11002 if (psavelen > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000011003 pstr = grabstackstr(pout);
11004 setinputstring(pstr);
Eric Andersen2870d962001-07-02 17:27:21 +000011005 }
11006 }
Eric Andersencb57d552001-06-28 07:25:16 +000011007 nlpp = &bqlist;
11008 while (*nlpp)
11009 nlpp = &(*nlpp)->next;
11010 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
11011 (*nlpp)->next = NULL;
11012 parsebackquote = oldstyle;
11013
11014 if (oldstyle) {
11015 saveprompt = doprompt;
11016 doprompt = 0;
11017 }
11018
11019 n = list(0);
11020
11021 if (oldstyle)
11022 doprompt = saveprompt;
11023 else {
11024 if (readtoken() != TRP)
11025 synexpect(TRP);
11026 }
11027
11028 (*nlpp)->n = n;
Eric Andersen2870d962001-07-02 17:27:21 +000011029 if (oldstyle) {
Eric Andersencb57d552001-06-28 07:25:16 +000011030 /*
11031 * Start reading from old file again, ignoring any pushed back
11032 * tokens left from the backquote parsing
11033 */
Eric Andersen2870d962001-07-02 17:27:21 +000011034 popfile();
Eric Andersencb57d552001-06-28 07:25:16 +000011035 tokpushback = 0;
11036 }
11037 while (stackblocksize() <= savelen)
11038 growstackblock();
11039 STARTSTACKSTR(out);
11040 if (str) {
11041 memcpy(out, str, savelen);
11042 STADJUST(savelen, out);
11043 INTOFF;
11044 ckfree(str);
11045 str = NULL;
11046 INTON;
11047 }
11048 parsebackquote = savepbq;
11049 handler = savehandler;
11050 if (arinest || dblquote)
11051 USTPUTC(CTLBACKQ | CTLQUOTE, out);
11052 else
11053 USTPUTC(CTLBACKQ, out);
11054 if (oldstyle)
11055 goto parsebackq_oldreturn;
11056 else
11057 goto parsebackq_newreturn;
11058}
11059
11060/*
11061 * Parse an arithmetic expansion (indicate start of one and set state)
11062 */
11063parsearith: {
11064
11065 if (++arinest == 1) {
11066 prevsyntax = syntax;
11067 syntax = ARISYNTAX;
11068 USTPUTC(CTLARI, out);
11069 if (dblquote)
11070 USTPUTC('"',out);
11071 else
11072 USTPUTC(' ',out);
11073 } else {
11074 /*
11075 * we collapse embedded arithmetic expansion to
11076 * parenthesis, which should be equivalent
11077 */
11078 USTPUTC('(', out);
11079 }
11080 goto parsearith_return;
11081}
11082
11083} /* end of readtoken */
11084
11085
Eric Andersencb57d552001-06-28 07:25:16 +000011086/*
11087 * Returns true if the text contains nothing to expand (no dollar signs
11088 * or backquotes).
11089 */
11090
11091static int
11092noexpand(text)
11093 char *text;
11094 {
11095 char *p;
11096 char c;
11097
11098 p = text;
11099 while ((c = *p++) != '\0') {
11100 if (c == CTLQUOTEMARK)
11101 continue;
11102 if (c == CTLESC)
11103 p++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011104 else if (SIT(c,BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000011105 return 0;
11106 }
11107 return 1;
11108}
11109
11110
11111/*
11112 * Return true if the argument is a legal variable name (a letter or
11113 * underscore followed by zero or more letters, underscores, and digits).
11114 */
11115
11116static int
Eric Andersen2870d962001-07-02 17:27:21 +000011117goodname(const char *name)
11118{
11119 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000011120
11121 p = name;
11122 if (! is_name(*p))
11123 return 0;
11124 while (*++p) {
11125 if (! is_in_name(*p))
11126 return 0;
11127 }
11128 return 1;
11129}
11130
11131
11132/*
11133 * Called when an unexpected token is read during the parse. The argument
11134 * is the token that is expected, or -1 if more than one type of token can
11135 * occur at this point.
11136 */
11137
11138static void
11139synexpect(token)
11140 int token;
11141{
11142 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011143 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000011144
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011145 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
11146 if (token >= 0)
11147 sprintf(msg+l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000011148 synerror(msg);
11149 /* NOTREACHED */
11150}
11151
11152
11153static void
Eric Andersen2870d962001-07-02 17:27:21 +000011154synerror(const char *msg)
11155{
Eric Andersencb57d552001-06-28 07:25:16 +000011156 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +000011157 out2fmt("%s: %d: ", commandname, startlinno);
11158 out2fmt("Syntax error: %s\n", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000011159 error((char *)NULL);
11160 /* NOTREACHED */
11161}
11162
Eric Andersencb57d552001-06-28 07:25:16 +000011163
11164/*
11165 * called by editline -- any expansions to the prompt
11166 * should be added here.
11167 */
Eric Andersen2870d962001-07-02 17:27:21 +000011168static void
Eric Andersen62483552001-07-10 06:09:16 +000011169setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000011170{
Eric Andersen62483552001-07-10 06:09:16 +000011171 char *prompt;
11172 switch (whichprompt) {
11173 case 1:
11174 prompt = ps1val();
11175 break;
11176 case 2:
11177 prompt = ps2val();
11178 break;
11179 default: /* 0 */
11180 prompt = "";
11181 }
11182 putprompt(prompt);
Eric Andersencb57d552001-06-28 07:25:16 +000011183}
11184
Eric Andersencb57d552001-06-28 07:25:16 +000011185
Eric Andersencb57d552001-06-28 07:25:16 +000011186/*
11187 * Code for dealing with input/output redirection.
11188 */
11189
Eric Andersen2870d962001-07-02 17:27:21 +000011190#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000011191#ifndef PIPE_BUF
Eric Andersen2870d962001-07-02 17:27:21 +000011192# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000011193#else
11194# define PIPESIZE PIPE_BUF
11195#endif
11196
11197
Eric Andersen62483552001-07-10 06:09:16 +000011198/*
11199 * Open a file in noclobber mode.
11200 * The code was copied from bash.
11201 */
11202static inline int
11203noclobberopen(const char *fname)
11204{
11205 int r, fd;
11206 struct stat finfo, finfo2;
11207
11208 /*
11209 * If the file exists and is a regular file, return an error
11210 * immediately.
11211 */
11212 r = stat(fname, &finfo);
11213 if (r == 0 && S_ISREG(finfo.st_mode)) {
11214 errno = EEXIST;
11215 return -1;
11216 }
11217
11218 /*
11219 * If the file was not present (r != 0), make sure we open it
11220 * exclusively so that if it is created before we open it, our open
11221 * will fail. Make sure that we do not truncate an existing file.
11222 * Note that we don't turn on O_EXCL unless the stat failed -- if the
11223 * file was not a regular file, we leave O_EXCL off.
11224 */
11225 if (r != 0)
11226 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
11227 fd = open(fname, O_WRONLY|O_CREAT, 0666);
11228
11229 /* If the open failed, return the file descriptor right away. */
11230 if (fd < 0)
11231 return fd;
11232
11233 /*
11234 * OK, the open succeeded, but the file may have been changed from a
11235 * non-regular file to a regular file between the stat and the open.
11236 * We are assuming that the O_EXCL open handles the case where FILENAME
11237 * did not exist and is symlinked to an existing file between the stat
11238 * and open.
11239 */
11240
11241 /*
11242 * If we can open it and fstat the file descriptor, and neither check
11243 * revealed that it was a regular file, and the file has not been
11244 * replaced, return the file descriptor.
11245 */
11246 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
11247 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
11248 return fd;
11249
11250 /* The file has been replaced. badness. */
11251 close(fd);
11252 errno = EEXIST;
11253 return -1;
11254}
Eric Andersencb57d552001-06-28 07:25:16 +000011255
11256/*
Eric Andersen62483552001-07-10 06:09:16 +000011257 * Handle here documents. Normally we fork off a process to write the
11258 * data to a pipe. If the document is short, we can stuff the data in
11259 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000011260 */
11261
Eric Andersen62483552001-07-10 06:09:16 +000011262static inline int
11263openhere(const union node *redir)
11264{
11265 int pip[2];
11266 int len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011267
Eric Andersen62483552001-07-10 06:09:16 +000011268 if (pipe(pip) < 0)
11269 error("Pipe call failed");
11270 if (redir->type == NHERE) {
11271 len = strlen(redir->nhere.doc->narg.text);
11272 if (len <= PIPESIZE) {
11273 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11274 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011275 }
Eric Andersencb57d552001-06-28 07:25:16 +000011276 }
Eric Andersen62483552001-07-10 06:09:16 +000011277 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
11278 close(pip[0]);
11279 signal(SIGINT, SIG_IGN);
11280 signal(SIGQUIT, SIG_IGN);
11281 signal(SIGHUP, SIG_IGN);
11282#ifdef SIGTSTP
11283 signal(SIGTSTP, SIG_IGN);
11284#endif
11285 signal(SIGPIPE, SIG_DFL);
11286 if (redir->type == NHERE)
11287 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11288 else
11289 expandhere(redir->nhere.doc, pip[1]);
11290 _exit(0);
11291 }
11292out:
11293 close(pip[1]);
11294 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000011295}
11296
11297
Eric Andersen62483552001-07-10 06:09:16 +000011298static inline int
11299openredirect(const union node *redir)
11300{
Eric Andersencb57d552001-06-28 07:25:16 +000011301 char *fname;
11302 int f;
11303
11304 switch (redir->nfile.type) {
11305 case NFROM:
11306 fname = redir->nfile.expfname;
11307 if ((f = open(fname, O_RDONLY)) < 0)
11308 goto eopen;
11309 break;
11310 case NFROMTO:
11311 fname = redir->nfile.expfname;
11312 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
11313 goto ecreate;
11314 break;
11315 case NTO:
11316 /* Take care of noclobber mode. */
11317 if (Cflag) {
11318 fname = redir->nfile.expfname;
11319 if ((f = noclobberopen(fname)) < 0)
11320 goto ecreate;
11321 break;
11322 }
11323 case NTOOV:
11324 fname = redir->nfile.expfname;
11325#ifdef O_CREAT
11326 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
11327 goto ecreate;
11328#else
11329 if ((f = creat(fname, 0666)) < 0)
11330 goto ecreate;
11331#endif
11332 break;
11333 case NAPPEND:
11334 fname = redir->nfile.expfname;
11335#ifdef O_APPEND
11336 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
11337 goto ecreate;
11338#else
11339 if ((f = open(fname, O_WRONLY)) < 0
11340 && (f = creat(fname, 0666)) < 0)
11341 goto ecreate;
11342 lseek(f, (off_t)0, 2);
11343#endif
11344 break;
11345 default:
11346#ifdef DEBUG
11347 abort();
11348#endif
11349 /* Fall through to eliminate warning. */
11350 case NTOFD:
11351 case NFROMFD:
11352 f = -1;
11353 break;
11354 case NHERE:
11355 case NXHERE:
11356 f = openhere(redir);
11357 break;
11358 }
11359
11360 return f;
11361ecreate:
11362 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11363eopen:
11364 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11365}
11366
11367
Eric Andersen62483552001-07-10 06:09:16 +000011368/*
11369 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11370 * old file descriptors are stashed away so that the redirection can be
11371 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11372 * standard output, and the standard error if it becomes a duplicate of
11373 * stdout.
11374 */
11375
Eric Andersencb57d552001-06-28 07:25:16 +000011376static void
Eric Andersen62483552001-07-10 06:09:16 +000011377redirect(union node *redir, int flags)
11378{
11379 union node *n;
11380 struct redirtab *sv = NULL;
11381 int i;
11382 int fd;
11383 int newfd;
11384 int try;
11385 int fd1dup = flags & REDIR_BACKQ;; /* stdout `cmd` redir to pipe */
11386
11387 if (flags & REDIR_PUSH) {
11388 sv = ckmalloc(sizeof (struct redirtab));
11389 for (i = 0 ; i < 10 ; i++)
11390 sv->renamed[i] = EMPTY;
11391 sv->next = redirlist;
11392 redirlist = sv;
11393 }
11394 for (n = redir ; n ; n = n->nfile.next) {
11395 fd = n->nfile.fd;
11396 try = 0;
11397 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11398 n->ndup.dupfd == fd)
11399 continue; /* redirect from/to same file descriptor */
11400
11401 INTOFF;
11402 newfd = openredirect(n);
11403 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
11404 if (newfd == fd) {
11405 try++;
11406 } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
11407 switch (errno) {
11408 case EBADF:
11409 if (!try) {
11410 dupredirect(n, newfd, fd1dup);
11411 try++;
11412 break;
11413 }
11414 /* FALLTHROUGH*/
11415 default:
11416 if (newfd >= 0) {
11417 close(newfd);
11418 }
11419 INTON;
11420 error("%d: %m", fd);
11421 /* NOTREACHED */
11422 }
11423 }
11424 if (!try) {
11425 close(fd);
11426 if (flags & REDIR_PUSH) {
11427 sv->renamed[fd] = i;
11428 }
11429 }
11430 } else if (fd != newfd) {
11431 close(fd);
11432 }
11433 if (fd == 0)
11434 fd0_redirected++;
11435 if (!try)
11436 dupredirect(n, newfd, fd1dup);
11437 INTON;
11438 }
11439}
11440
11441
11442static void
11443dupredirect(const union node *redir, int f, int fd1dup)
Eric Andersen2870d962001-07-02 17:27:21 +000011444{
Eric Andersencb57d552001-06-28 07:25:16 +000011445 int fd = redir->nfile.fd;
11446
Eric Andersen62483552001-07-10 06:09:16 +000011447 if(fd==1)
11448 fd1dup = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011449 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Eric Andersen2870d962001-07-02 17:27:21 +000011450 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
Eric Andersen62483552001-07-10 06:09:16 +000011451 if (redir->ndup.dupfd!=1 || fd1dup!=1)
Eric Andersencb57d552001-06-28 07:25:16 +000011452 dup_as_newfd(redir->ndup.dupfd, fd);
11453 }
11454 return;
11455 }
11456
11457 if (f != fd) {
11458 dup_as_newfd(f, fd);
11459 close(f);
11460 }
11461 return;
11462}
11463
11464
Eric Andersencb57d552001-06-28 07:25:16 +000011465
Eric Andersencb57d552001-06-28 07:25:16 +000011466/*
11467 * Undo the effects of the last redirection.
11468 */
11469
11470static void
Eric Andersen2870d962001-07-02 17:27:21 +000011471popredir(void)
11472{
Eric Andersencb57d552001-06-28 07:25:16 +000011473 struct redirtab *rp = redirlist;
11474 int i;
11475
11476 INTOFF;
11477 for (i = 0 ; i < 10 ; i++) {
11478 if (rp->renamed[i] != EMPTY) {
Eric Andersen2870d962001-07-02 17:27:21 +000011479 if (i == 0)
11480 fd0_redirected--;
Eric Andersencb57d552001-06-28 07:25:16 +000011481 close(i);
11482 if (rp->renamed[i] >= 0) {
11483 dup_as_newfd(rp->renamed[i], i);
11484 close(rp->renamed[i]);
11485 }
Eric Andersencb57d552001-06-28 07:25:16 +000011486 }
11487 }
11488 redirlist = rp->next;
11489 ckfree(rp);
11490 INTON;
11491}
11492
11493/*
Eric Andersencb57d552001-06-28 07:25:16 +000011494 * Discard all saved file descriptors.
11495 */
11496
11497static void
Eric Andersen2870d962001-07-02 17:27:21 +000011498clearredir(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000011499 struct redirtab *rp;
11500 int i;
11501
11502 for (rp = redirlist ; rp ; rp = rp->next) {
11503 for (i = 0 ; i < 10 ; i++) {
11504 if (rp->renamed[i] >= 0) {
11505 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011506 }
11507 rp->renamed[i] = EMPTY;
11508 }
11509 }
Eric Andersencb57d552001-06-28 07:25:16 +000011510}
11511
11512
Eric Andersencb57d552001-06-28 07:25:16 +000011513/*
11514 * Copy a file descriptor to be >= to. Returns -1
11515 * if the source file descriptor is closed, EMPTY if there are no unused
11516 * file descriptors left.
11517 */
11518
11519static int
11520dup_as_newfd(from, to)
11521 int from;
11522 int to;
11523{
11524 int newfd;
11525
11526 newfd = fcntl(from, F_DUPFD, to);
11527 if (newfd < 0) {
11528 if (errno == EMFILE)
11529 return EMPTY;
11530 else
Eric Andersen2870d962001-07-02 17:27:21 +000011531 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011532 }
11533 return newfd;
11534}
11535
Eric Andersencb57d552001-06-28 07:25:16 +000011536#ifdef DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +000011537static void shtree (union node *, int, char *, FILE*);
11538static void shcmd (union node *, FILE *);
11539static void sharg (union node *, FILE *);
11540static void indent (int, char *, FILE *);
11541static void trstring (char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011542
11543
11544static void
11545showtree(n)
11546 union node *n;
11547{
11548 trputs("showtree called\n");
11549 shtree(n, 1, NULL, stdout);
11550}
11551
11552
11553static void
11554shtree(n, ind, pfx, fp)
11555 union node *n;
11556 int ind;
11557 char *pfx;
11558 FILE *fp;
11559{
11560 struct nodelist *lp;
11561 const char *s;
11562
11563 if (n == NULL)
11564 return;
11565
11566 indent(ind, pfx, fp);
11567 switch(n->type) {
11568 case NSEMI:
11569 s = "; ";
11570 goto binop;
11571 case NAND:
11572 s = " && ";
11573 goto binop;
11574 case NOR:
11575 s = " || ";
11576binop:
11577 shtree(n->nbinary.ch1, ind, NULL, fp);
11578 /* if (ind < 0) */
11579 fputs(s, fp);
11580 shtree(n->nbinary.ch2, ind, NULL, fp);
11581 break;
11582 case NCMD:
11583 shcmd(n, fp);
11584 if (ind >= 0)
11585 putc('\n', fp);
11586 break;
11587 case NPIPE:
11588 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11589 shcmd(lp->n, fp);
11590 if (lp->next)
11591 fputs(" | ", fp);
11592 }
11593 if (n->npipe.backgnd)
11594 fputs(" &", fp);
11595 if (ind >= 0)
11596 putc('\n', fp);
11597 break;
11598 default:
11599 fprintf(fp, "<node type %d>", n->type);
11600 if (ind >= 0)
11601 putc('\n', fp);
11602 break;
11603 }
11604}
11605
11606
11607
11608static void
11609shcmd(cmd, fp)
11610 union node *cmd;
11611 FILE *fp;
11612{
11613 union node *np;
11614 int first;
11615 const char *s;
11616 int dftfd;
11617
11618 first = 1;
11619 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11620 if (! first)
11621 putchar(' ');
11622 sharg(np, fp);
11623 first = 0;
11624 }
11625 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11626 if (! first)
11627 putchar(' ');
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011628#if 1
11629 s = "*error*";
11630 dftfd = 0;
11631 if ((np->nfile.type <= NFROMFD) && (np->nfile.type >= NTO)) {
11632 s = redir_strings[np->nfile.type - NTO];
11633 if (*s == '>') {
11634 dftfd = 1;
11635 }
11636 }
11637#else
Eric Andersencb57d552001-06-28 07:25:16 +000011638 switch (np->nfile.type) {
Eric Andersen2870d962001-07-02 17:27:21 +000011639 case NTO: s = ">"; dftfd = 1; break;
11640 case NAPPEND: s = ">>"; dftfd = 1; break;
11641 case NTOFD: s = ">&"; dftfd = 1; break;
11642 case NTOOV: s = ">|"; dftfd = 1; break;
11643 case NFROM: s = "<"; dftfd = 0; break;
11644 case NFROMFD: s = "<&"; dftfd = 0; break;
11645 case NFROMTO: s = "<>"; dftfd = 0; break;
11646 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011647 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011648#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011649 if (np->nfile.fd != dftfd)
11650 fprintf(fp, "%d", np->nfile.fd);
11651 fputs(s, fp);
11652 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11653 fprintf(fp, "%d", np->ndup.dupfd);
11654 } else {
11655 sharg(np->nfile.fname, fp);
11656 }
11657 first = 0;
11658 }
11659}
11660
11661
11662
11663static void
11664sharg(arg, fp)
11665 union node *arg;
11666 FILE *fp;
11667 {
11668 char *p;
11669 struct nodelist *bqlist;
11670 int subtype;
11671
11672 if (arg->type != NARG) {
11673 printf("<node type %d>\n", arg->type);
11674 fflush(stdout);
11675 abort();
11676 }
11677 bqlist = arg->narg.backquote;
11678 for (p = arg->narg.text ; *p ; p++) {
11679 switch (*p) {
11680 case CTLESC:
11681 putc(*++p, fp);
11682 break;
11683 case CTLVAR:
11684 putc('$', fp);
11685 putc('{', fp);
11686 subtype = *++p;
11687 if (subtype == VSLENGTH)
11688 putc('#', fp);
11689
11690 while (*p != '=')
11691 putc(*p++, fp);
11692
11693 if (subtype & VSNUL)
11694 putc(':', fp);
11695
11696 switch (subtype & VSTYPE) {
11697 case VSNORMAL:
11698 putc('}', fp);
11699 break;
11700 case VSMINUS:
11701 putc('-', fp);
11702 break;
11703 case VSPLUS:
11704 putc('+', fp);
11705 break;
11706 case VSQUESTION:
11707 putc('?', fp);
11708 break;
11709 case VSASSIGN:
11710 putc('=', fp);
11711 break;
11712 case VSTRIMLEFT:
11713 putc('#', fp);
11714 break;
11715 case VSTRIMLEFTMAX:
11716 putc('#', fp);
11717 putc('#', fp);
11718 break;
11719 case VSTRIMRIGHT:
11720 putc('%', fp);
11721 break;
11722 case VSTRIMRIGHTMAX:
11723 putc('%', fp);
11724 putc('%', fp);
11725 break;
11726 case VSLENGTH:
11727 break;
11728 default:
11729 printf("<subtype %d>", subtype);
11730 }
11731 break;
11732 case CTLENDVAR:
11733 putc('}', fp);
11734 break;
11735 case CTLBACKQ:
11736 case CTLBACKQ|CTLQUOTE:
11737 putc('$', fp);
11738 putc('(', fp);
11739 shtree(bqlist->n, -1, NULL, fp);
11740 putc(')', fp);
11741 break;
11742 default:
11743 putc(*p, fp);
11744 break;
11745 }
11746 }
11747}
11748
11749
11750static void
11751indent(amount, pfx, fp)
11752 int amount;
11753 char *pfx;
11754 FILE *fp;
11755{
11756 int i;
11757
11758 for (i = 0 ; i < amount ; i++) {
11759 if (pfx && i == amount - 1)
11760 fputs(pfx, fp);
11761 putc('\t', fp);
11762 }
11763}
11764#endif
11765
11766
11767
11768/*
11769 * Debugging stuff.
11770 */
11771
11772
11773#ifdef DEBUG
11774FILE *tracefile;
11775
11776#if DEBUG == 2
11777static int debug = 1;
11778#else
11779static int debug = 0;
11780#endif
11781
11782
11783static void
11784trputc(c)
11785 int c;
11786{
11787 if (tracefile == NULL)
11788 return;
11789 putc(c, tracefile);
11790 if (c == '\n')
11791 fflush(tracefile);
11792}
11793
11794static void
11795trace(const char *fmt, ...)
11796{
11797 va_list va;
Eric Andersencb57d552001-06-28 07:25:16 +000011798 va_start(va, fmt);
Eric Andersencb57d552001-06-28 07:25:16 +000011799 if (tracefile != NULL) {
11800 (void) vfprintf(tracefile, fmt, va);
11801 if (strchr(fmt, '\n'))
11802 (void) fflush(tracefile);
11803 }
11804 va_end(va);
11805}
11806
11807
11808static void
11809trputs(s)
11810 const char *s;
11811{
11812 if (tracefile == NULL)
11813 return;
11814 fputs(s, tracefile);
11815 if (strchr(s, '\n'))
11816 fflush(tracefile);
11817}
11818
11819
11820static void
11821trstring(s)
11822 char *s;
11823{
11824 char *p;
11825 char c;
11826
11827 if (tracefile == NULL)
11828 return;
11829 putc('"', tracefile);
11830 for (p = s ; *p ; p++) {
11831 switch (*p) {
11832 case '\n': c = 'n'; goto backslash;
11833 case '\t': c = 't'; goto backslash;
11834 case '\r': c = 'r'; goto backslash;
11835 case '"': c = '"'; goto backslash;
11836 case '\\': c = '\\'; goto backslash;
11837 case CTLESC: c = 'e'; goto backslash;
11838 case CTLVAR: c = 'v'; goto backslash;
11839 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11840 case CTLBACKQ: c = 'q'; goto backslash;
11841 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
Eric Andersen2870d962001-07-02 17:27:21 +000011842backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011843 putc(c, tracefile);
11844 break;
11845 default:
11846 if (*p >= ' ' && *p <= '~')
11847 putc(*p, tracefile);
11848 else {
11849 putc('\\', tracefile);
11850 putc(*p >> 6 & 03, tracefile);
11851 putc(*p >> 3 & 07, tracefile);
11852 putc(*p & 07, tracefile);
11853 }
11854 break;
11855 }
11856 }
11857 putc('"', tracefile);
11858}
11859
11860
11861static void
11862trargs(ap)
11863 char **ap;
11864{
11865 if (tracefile == NULL)
11866 return;
11867 while (*ap) {
11868 trstring(*ap++);
11869 if (*ap)
11870 putc(' ', tracefile);
11871 else
11872 putc('\n', tracefile);
11873 }
11874 fflush(tracefile);
11875}
11876
11877
11878static void
11879opentrace() {
11880 char s[100];
11881#ifdef O_APPEND
11882 int flags;
11883#endif
11884
11885 if (!debug)
11886 return;
11887#ifdef not_this_way
11888 {
11889 char *p;
11890 if ((p = getenv("HOME")) == NULL) {
11891 if (geteuid() == 0)
11892 p = "/";
11893 else
11894 p = "/tmp";
11895 }
Eric Andersen2870d962001-07-02 17:27:21 +000011896 strcpy(s, p);
Eric Andersencb57d552001-06-28 07:25:16 +000011897 strcat(s, "/trace");
11898 }
11899#else
Eric Andersen2870d962001-07-02 17:27:21 +000011900 strcpy(s, "./trace");
Eric Andersencb57d552001-06-28 07:25:16 +000011901#endif /* not_this_way */
11902 if ((tracefile = fopen(s, "a")) == NULL) {
11903 fprintf(stderr, "Can't open %s\n", s);
11904 return;
11905 }
11906#ifdef O_APPEND
11907 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11908 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11909#endif
11910 fputs("\nTracing started.\n", tracefile);
11911 fflush(tracefile);
11912}
11913#endif /* DEBUG */
11914
11915
11916/*
Eric Andersencb57d552001-06-28 07:25:16 +000011917 * The trap builtin.
11918 */
11919
11920static int
11921trapcmd(argc, argv)
11922 int argc;
11923 char **argv;
11924{
11925 char *action;
11926 char **ap;
11927 int signo;
11928
11929 if (argc <= 1) {
11930 for (signo = 0 ; signo < NSIG ; signo++) {
11931 if (trap[signo] != NULL) {
11932 char *p;
Eric Andersen34506362001-08-02 05:02:46 +000011933 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011934
11935 p = single_quote(trap[signo]);
Eric Andersen34506362001-08-02 05:02:46 +000011936 sn = sys_siglist[signo];
11937 if(sn==NULL)
11938 sn = u_signal_names(0, &signo, 0);
11939 if(sn==NULL)
11940 sn = "???";
11941 printf("trap -- %s %s\n", p, sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011942 stunalloc(p);
11943 }
11944 }
11945 return 0;
11946 }
11947 ap = argv + 1;
11948 if (argc == 2)
11949 action = NULL;
11950 else
11951 action = *ap++;
11952 while (*ap) {
11953 if ((signo = decode_signal(*ap, 0)) < 0)
11954 error("%s: bad trap", *ap);
11955 INTOFF;
11956 if (action) {
11957 if (action[0] == '-' && action[1] == '\0')
11958 action = NULL;
11959 else
11960 action = savestr(action);
11961 }
11962 if (trap[signo])
11963 ckfree(trap[signo]);
11964 trap[signo] = action;
11965 if (signo != 0)
11966 setsignal(signo);
11967 INTON;
11968 ap++;
11969 }
11970 return 0;
11971}
11972
11973
11974
Eric Andersencb57d552001-06-28 07:25:16 +000011975
11976
11977
11978/*
11979 * Set the signal handler for the specified signal. The routine figures
11980 * out what it should be set to.
11981 */
11982
11983static void
Eric Andersen2870d962001-07-02 17:27:21 +000011984setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011985{
11986 int action;
11987 char *t;
11988 struct sigaction act;
11989
11990 if ((t = trap[signo]) == NULL)
11991 action = S_DFL;
11992 else if (*t != '\0')
11993 action = S_CATCH;
11994 else
11995 action = S_IGN;
11996 if (rootshell && action == S_DFL) {
11997 switch (signo) {
11998 case SIGINT:
11999 if (iflag || minusc || sflag == 0)
12000 action = S_CATCH;
12001 break;
12002 case SIGQUIT:
12003#ifdef DEBUG
12004 {
Eric Andersencb57d552001-06-28 07:25:16 +000012005
12006 if (debug)
12007 break;
12008 }
12009#endif
12010 /* FALLTHROUGH */
12011 case SIGTERM:
12012 if (iflag)
12013 action = S_IGN;
12014 break;
Eric Andersen2870d962001-07-02 17:27:21 +000012015#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000012016 case SIGTSTP:
12017 case SIGTTOU:
12018 if (mflag)
12019 action = S_IGN;
12020 break;
12021#endif
12022 }
12023 }
12024
12025 t = &sigmode[signo - 1];
12026 if (*t == 0) {
12027 /*
12028 * current setting unknown
12029 */
12030 if (sigaction(signo, 0, &act) == -1) {
12031 /*
12032 * Pretend it worked; maybe we should give a warning
12033 * here, but other shells don't. We don't alter
12034 * sigmode, so that we retry every time.
12035 */
12036 return;
12037 }
12038 if (act.sa_handler == SIG_IGN) {
12039 if (mflag && (signo == SIGTSTP ||
12040 signo == SIGTTIN || signo == SIGTTOU)) {
Eric Andersen2870d962001-07-02 17:27:21 +000012041 *t = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000012042 } else
12043 *t = S_HARD_IGN;
12044 } else {
Eric Andersen2870d962001-07-02 17:27:21 +000012045 *t = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000012046 }
12047 }
12048 if (*t == S_HARD_IGN || *t == action)
12049 return;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000012050 act.sa_handler = ((action == S_CATCH) ? onsig
12051 : ((action == S_IGN) ? SIG_IGN : SIG_DFL));
Eric Andersencb57d552001-06-28 07:25:16 +000012052 *t = action;
12053 act.sa_flags = 0;
12054 sigemptyset(&act.sa_mask);
12055 sigaction(signo, &act, 0);
12056}
12057
12058/*
12059 * Ignore a signal.
12060 */
12061
12062static void
12063ignoresig(signo)
12064 int signo;
12065{
12066 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
12067 signal(signo, SIG_IGN);
12068 }
12069 sigmode[signo - 1] = S_HARD_IGN;
12070}
12071
12072
Eric Andersencb57d552001-06-28 07:25:16 +000012073/*
12074 * Signal handler.
12075 */
12076
12077static void
Eric Andersen2870d962001-07-02 17:27:21 +000012078onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000012079{
12080 if (signo == SIGINT && trap[SIGINT] == NULL) {
12081 onint();
12082 return;
12083 }
12084 gotsig[signo - 1] = 1;
12085 pendingsigs++;
12086}
12087
12088
Eric Andersencb57d552001-06-28 07:25:16 +000012089/*
12090 * Called to execute a trap. Perhaps we should avoid entering new trap
12091 * handlers while we are executing a trap handler.
12092 */
12093
12094static void
Eric Andersen2870d962001-07-02 17:27:21 +000012095dotrap(void)
12096{
Eric Andersencb57d552001-06-28 07:25:16 +000012097 int i;
12098 int savestatus;
12099
12100 for (;;) {
12101 for (i = 1 ; ; i++) {
12102 if (gotsig[i - 1])
12103 break;
12104 if (i >= NSIG - 1)
12105 goto done;
12106 }
12107 gotsig[i - 1] = 0;
12108 savestatus=exitstatus;
12109 evalstring(trap[i], 0);
12110 exitstatus=savestatus;
12111 }
12112done:
12113 pendingsigs = 0;
12114}
12115
Eric Andersencb57d552001-06-28 07:25:16 +000012116/*
12117 * Called to exit the shell.
12118 */
12119
12120static void
Eric Andersen2870d962001-07-02 17:27:21 +000012121exitshell(int status)
Eric Andersencb57d552001-06-28 07:25:16 +000012122{
12123 struct jmploc loc1, loc2;
12124 char *p;
12125
12126 TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
12127 if (setjmp(loc1.loc)) {
12128 goto l1;
12129 }
12130 if (setjmp(loc2.loc)) {
12131 goto l2;
12132 }
12133 handler = &loc1;
12134 if ((p = trap[0]) != NULL && *p != '\0') {
12135 trap[0] = NULL;
12136 evalstring(p, 0);
12137 }
Eric Andersen2870d962001-07-02 17:27:21 +000012138l1: handler = &loc2; /* probably unnecessary */
Eric Andersencb57d552001-06-28 07:25:16 +000012139 flushall();
Eric Andersen2870d962001-07-02 17:27:21 +000012140#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000012141 setjobctl(0);
12142#endif
12143l2: _exit(status);
12144 /* NOTREACHED */
12145}
12146
12147static int decode_signal(const char *string, int minsig)
12148{
12149 int signo;
Eric Andersen34506362001-08-02 05:02:46 +000012150 const char *name = u_signal_names(string, &signo, minsig);
Eric Andersencb57d552001-06-28 07:25:16 +000012151
Eric Andersen34506362001-08-02 05:02:46 +000012152 return name ? signo : -1;
Eric Andersencb57d552001-06-28 07:25:16 +000012153}
Eric Andersen34506362001-08-02 05:02:46 +000012154
Eric Andersen2870d962001-07-02 17:27:21 +000012155static struct var **hashvar (const char *);
12156static void showvars (const char *, int, int);
12157static struct var **findvar (struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000012158
12159/*
12160 * Initialize the varable symbol tables and import the environment
12161 */
12162
Eric Andersencb57d552001-06-28 07:25:16 +000012163/*
12164 * This routine initializes the builtin variables. It is called when the
12165 * shell is initialized and again when a shell procedure is spawned.
12166 */
12167
12168static void
12169initvar() {
12170 const struct varinit *ip;
12171 struct var *vp;
12172 struct var **vpp;
12173
12174 for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
12175 if ((vp->flags & VEXPORT) == 0) {
12176 vpp = hashvar(ip->text);
12177 vp->next = *vpp;
12178 *vpp = vp;
12179 vp->text = strdup(ip->text);
12180 vp->flags = ip->flags;
12181 vp->func = ip->func;
12182 }
12183 }
12184 /*
12185 * PS1 depends on uid
12186 */
12187 if ((vps1.flags & VEXPORT) == 0) {
12188 vpp = hashvar("PS1=");
12189 vps1.next = *vpp;
12190 *vpp = &vps1;
12191 vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# ");
12192 vps1.flags = VSTRFIXED|VTEXTFIXED;
12193 }
12194}
12195
12196/*
12197 * Set the value of a variable. The flags argument is ored with the
12198 * flags of the variable. If val is NULL, the variable is unset.
12199 */
12200
12201static void
12202setvar(name, val, flags)
12203 const char *name, *val;
12204 int flags;
12205{
12206 const char *p;
12207 int len;
12208 int namelen;
12209 char *nameeq;
12210 int isbad;
12211 int vallen = 0;
12212
12213 isbad = 0;
12214 p = name;
12215 if (! is_name(*p))
12216 isbad = 1;
12217 p++;
12218 for (;;) {
12219 if (! is_in_name(*p)) {
12220 if (*p == '\0' || *p == '=')
12221 break;
12222 isbad = 1;
12223 }
12224 p++;
12225 }
12226 namelen = p - name;
12227 if (isbad)
12228 error("%.*s: bad variable name", namelen, name);
Eric Andersen2870d962001-07-02 17:27:21 +000012229 len = namelen + 2; /* 2 is space for '=' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +000012230 if (val == NULL) {
12231 flags |= VUNSET;
12232 } else {
12233 len += vallen = strlen(val);
12234 }
12235 INTOFF;
12236 nameeq = ckmalloc(len);
12237 memcpy(nameeq, name, namelen);
12238 nameeq[namelen] = '=';
12239 if (val) {
12240 memcpy(nameeq + namelen + 1, val, vallen + 1);
12241 } else {
12242 nameeq[namelen + 1] = '\0';
12243 }
12244 setvareq(nameeq, flags);
12245 INTON;
12246}
12247
12248
12249
12250/*
12251 * Same as setvar except that the variable and value are passed in
12252 * the first argument as name=value. Since the first argument will
12253 * be actually stored in the table, it should not be a string that
12254 * will go away.
12255 */
12256
12257static void
12258setvareq(s, flags)
12259 char *s;
12260 int flags;
12261{
12262 struct var *vp, **vpp;
12263
12264 vpp = hashvar(s);
12265 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
12266 if ((vp = *findvar(vpp, s))) {
12267 if (vp->flags & VREADONLY) {
12268 size_t len = strchr(s, '=') - s;
12269 error("%.*s: is read only", len, s);
12270 }
12271 INTOFF;
12272
12273 if (vp->func && (flags & VNOFUNC) == 0)
12274 (*vp->func)(strchr(s, '=') + 1);
12275
12276 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12277 ckfree(vp->text);
12278
12279 vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
12280 vp->flags |= flags;
12281 vp->text = s;
12282
12283 /*
12284 * We could roll this to a function, to handle it as
12285 * a regular variable function callback, but why bother?
12286 */
12287 if (iflag && (vp == &vmpath || (vp == &vmail && !mpathset())))
12288 chkmail(1);
12289 INTON;
12290 return;
12291 }
12292 /* not found */
12293 vp = ckmalloc(sizeof (*vp));
12294 vp->flags = flags;
12295 vp->text = s;
12296 vp->next = *vpp;
12297 vp->func = NULL;
12298 *vpp = vp;
12299}
12300
12301
12302
12303/*
12304 * Process a linked list of variable assignments.
12305 */
12306
12307static void
12308listsetvar(mylist)
12309 struct strlist *mylist;
12310 {
12311 struct strlist *lp;
12312
12313 INTOFF;
12314 for (lp = mylist ; lp ; lp = lp->next) {
12315 setvareq(savestr(lp->text), 0);
12316 }
12317 INTON;
12318}
12319
12320
12321
12322/*
12323 * Find the value of a variable. Returns NULL if not set.
12324 */
12325
Eric Andersen62483552001-07-10 06:09:16 +000012326static const char *
Eric Andersencb57d552001-06-28 07:25:16 +000012327lookupvar(name)
12328 const char *name;
12329 {
12330 struct var *v;
12331
12332 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
12333 return strchr(v->text, '=') + 1;
12334 }
12335 return NULL;
12336}
12337
12338
12339
12340/*
12341 * Search the environment of a builtin command.
12342 */
12343
Eric Andersen62483552001-07-10 06:09:16 +000012344static const char *
12345bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012346{
Eric Andersen62483552001-07-10 06:09:16 +000012347 const struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012348
12349 for (sp = cmdenviron ; sp ; sp = sp->next) {
12350 if (varequal(sp->text, name))
12351 return strchr(sp->text, '=') + 1;
12352 }
12353 return lookupvar(name);
12354}
12355
12356
12357
12358/*
12359 * Generate a list of exported variables. This routine is used to construct
12360 * the third argument to execve when executing a program.
12361 */
12362
12363static char **
12364environment() {
12365 int nenv;
12366 struct var **vpp;
12367 struct var *vp;
12368 char **env;
12369 char **ep;
12370
12371 nenv = 0;
12372 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12373 for (vp = *vpp ; vp ; vp = vp->next)
12374 if (vp->flags & VEXPORT)
12375 nenv++;
12376 }
12377 ep = env = stalloc((nenv + 1) * sizeof *env);
12378 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12379 for (vp = *vpp ; vp ; vp = vp->next)
12380 if (vp->flags & VEXPORT)
12381 *ep++ = vp->text;
12382 }
12383 *ep = NULL;
12384 return env;
12385}
12386
12387
12388/*
12389 * Called when a shell procedure is invoked to clear out nonexported
12390 * variables. It is also necessary to reallocate variables of with
12391 * VSTACK set since these are currently allocated on the stack.
12392 */
12393
Eric Andersencb57d552001-06-28 07:25:16 +000012394static void
Eric Andersen2870d962001-07-02 17:27:21 +000012395shprocvar(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000012396 struct var **vpp;
12397 struct var *vp, **prev;
12398
12399 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12400 for (prev = vpp ; (vp = *prev) != NULL ; ) {
12401 if ((vp->flags & VEXPORT) == 0) {
12402 *prev = vp->next;
12403 if ((vp->flags & VTEXTFIXED) == 0)
12404 ckfree(vp->text);
12405 if ((vp->flags & VSTRFIXED) == 0)
12406 ckfree(vp);
12407 } else {
12408 if (vp->flags & VSTACK) {
12409 vp->text = savestr(vp->text);
12410 vp->flags &=~ VSTACK;
12411 }
12412 prev = &vp->next;
12413 }
12414 }
12415 }
12416 initvar();
12417}
12418
12419
12420
12421/*
12422 * Command to list all variables which are set. Currently this command
12423 * is invoked from the set command when the set command is called without
12424 * any variables.
12425 */
12426
12427static int
12428showvarscmd(argc, argv)
12429 int argc;
12430 char **argv;
12431{
12432 showvars(nullstr, VUNSET, VUNSET);
12433 return 0;
12434}
12435
12436
12437
12438/*
12439 * The export and readonly commands.
12440 */
12441
12442static int
12443exportcmd(argc, argv)
12444 int argc;
12445 char **argv;
12446{
12447 struct var *vp;
12448 char *name;
12449 const char *p;
12450 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12451 int pflag;
12452
12453 listsetvar(cmdenviron);
12454 pflag = (nextopt("p") == 'p');
12455 if (argc > 1 && !pflag) {
12456 while ((name = *argptr++) != NULL) {
12457 if ((p = strchr(name, '=')) != NULL) {
12458 p++;
12459 } else {
12460 if ((vp = *findvar(hashvar(name), name))) {
12461 vp->flags |= flag;
12462 goto found;
12463 }
12464 }
12465 setvar(name, p, flag);
12466found:;
12467 }
12468 } else {
12469 showvars(argv[0], flag, 0);
12470 }
12471 return 0;
12472}
12473
Eric Andersen34506362001-08-02 05:02:46 +000012474
Eric Andersencb57d552001-06-28 07:25:16 +000012475/*
12476 * The "local" command.
12477 */
12478
Eric Andersen2870d962001-07-02 17:27:21 +000012479/* funcnest nonzero if we are currently evaluating a function */
12480
Eric Andersencb57d552001-06-28 07:25:16 +000012481static int
12482localcmd(argc, argv)
12483 int argc;
12484 char **argv;
12485{
12486 char *name;
12487
Eric Andersen2870d962001-07-02 17:27:21 +000012488 if (! funcnest)
Eric Andersencb57d552001-06-28 07:25:16 +000012489 error("Not in a function");
12490 while ((name = *argptr++) != NULL) {
12491 mklocal(name);
12492 }
12493 return 0;
12494}
12495
12496
12497/*
12498 * Make a variable a local variable. When a variable is made local, it's
12499 * value and flags are saved in a localvar structure. The saved values
12500 * will be restored when the shell function returns. We handle the name
12501 * "-" as a special case.
12502 */
12503
12504static void
12505mklocal(name)
12506 char *name;
12507 {
12508 struct localvar *lvp;
12509 struct var **vpp;
12510 struct var *vp;
12511
12512 INTOFF;
12513 lvp = ckmalloc(sizeof (struct localvar));
12514 if (name[0] == '-' && name[1] == '\0') {
12515 char *p;
Eric Andersen2870d962001-07-02 17:27:21 +000012516 p = ckmalloc(sizeof optet_vals);
12517 lvp->text = memcpy(p, optet_vals, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000012518 vp = NULL;
12519 } else {
12520 vpp = hashvar(name);
12521 vp = *findvar(vpp, name);
12522 if (vp == NULL) {
12523 if (strchr(name, '='))
12524 setvareq(savestr(name), VSTRFIXED);
12525 else
12526 setvar(name, NULL, VSTRFIXED);
Eric Andersen2870d962001-07-02 17:27:21 +000012527 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012528 lvp->text = NULL;
12529 lvp->flags = VUNSET;
12530 } else {
12531 lvp->text = vp->text;
12532 lvp->flags = vp->flags;
12533 vp->flags |= VSTRFIXED|VTEXTFIXED;
12534 if (strchr(name, '='))
12535 setvareq(savestr(name), 0);
12536 }
12537 }
12538 lvp->vp = vp;
12539 lvp->next = localvars;
12540 localvars = lvp;
12541 INTON;
12542}
12543
12544
12545/*
12546 * Called after a function returns.
12547 */
12548
12549static void
12550poplocalvars() {
12551 struct localvar *lvp;
12552 struct var *vp;
12553
12554 while ((lvp = localvars) != NULL) {
12555 localvars = lvp->next;
12556 vp = lvp->vp;
Eric Andersen2870d962001-07-02 17:27:21 +000012557 if (vp == NULL) { /* $- saved */
12558 memcpy(optet_vals, lvp->text, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000012559 ckfree(lvp->text);
12560 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12561 (void)unsetvar(vp->text);
12562 } else {
12563 if ((vp->flags & VTEXTFIXED) == 0)
12564 ckfree(vp->text);
12565 vp->flags = lvp->flags;
12566 vp->text = lvp->text;
12567 }
12568 ckfree(lvp);
12569 }
12570}
12571
12572
12573static int
12574setvarcmd(argc, argv)
12575 int argc;
12576 char **argv;
12577{
12578 if (argc <= 2)
12579 return unsetcmd(argc, argv);
12580 else if (argc == 3)
12581 setvar(argv[1], argv[2], 0);
12582 else
12583 error("List assignment not implemented");
12584 return 0;
12585}
12586
12587
12588/*
12589 * The unset builtin command. We unset the function before we unset the
12590 * variable to allow a function to be unset when there is a readonly variable
12591 * with the same name.
12592 */
12593
12594static int
12595unsetcmd(argc, argv)
12596 int argc;
12597 char **argv;
12598{
12599 char **ap;
12600 int i;
12601 int flg_func = 0;
12602 int flg_var = 0;
12603 int ret = 0;
12604
12605 while ((i = nextopt("vf")) != '\0') {
12606 if (i == 'f')
12607 flg_func = 1;
12608 else
12609 flg_var = 1;
12610 }
12611 if (flg_func == 0 && flg_var == 0)
12612 flg_var = 1;
12613
12614 for (ap = argptr; *ap ; ap++) {
12615 if (flg_func)
12616 unsetfunc(*ap);
12617 if (flg_var)
12618 ret |= unsetvar(*ap);
12619 }
12620 return ret;
12621}
12622
12623
12624/*
12625 * Unset the specified variable.
12626 */
12627
12628static int
Eric Andersen62483552001-07-10 06:09:16 +000012629unsetvar(const char *s)
12630{
Eric Andersencb57d552001-06-28 07:25:16 +000012631 struct var **vpp;
12632 struct var *vp;
12633
12634 vpp = findvar(hashvar(s), s);
12635 vp = *vpp;
12636 if (vp) {
12637 if (vp->flags & VREADONLY)
12638 return (1);
12639 INTOFF;
12640 if (*(strchr(vp->text, '=') + 1) != '\0')
12641 setvar(s, nullstr, 0);
12642 vp->flags &= ~VEXPORT;
12643 vp->flags |= VUNSET;
12644 if ((vp->flags & VSTRFIXED) == 0) {
12645 if ((vp->flags & VTEXTFIXED) == 0)
12646 ckfree(vp->text);
12647 *vpp = vp->next;
12648 ckfree(vp);
12649 }
12650 INTON;
12651 return (0);
12652 }
12653
12654 return (0);
12655}
12656
12657
12658
12659/*
12660 * Find the appropriate entry in the hash table from the name.
12661 */
12662
12663static struct var **
Eric Andersen62483552001-07-10 06:09:16 +000012664hashvar(const char *p)
12665{
Eric Andersencb57d552001-06-28 07:25:16 +000012666 unsigned int hashval;
12667
12668 hashval = ((unsigned char) *p) << 4;
12669 while (*p && *p != '=')
12670 hashval += (unsigned char) *p++;
12671 return &vartab[hashval % VTABSIZE];
12672}
12673
12674
12675
12676/*
12677 * Returns true if the two strings specify the same varable. The first
12678 * variable name is terminated by '='; the second may be terminated by
12679 * either '=' or '\0'.
12680 */
12681
12682static int
Eric Andersen62483552001-07-10 06:09:16 +000012683varequal(const char *p, const char *q)
12684{
Eric Andersencb57d552001-06-28 07:25:16 +000012685 while (*p == *q++) {
12686 if (*p++ == '=')
12687 return 1;
12688 }
12689 if (*p == '=' && *(q - 1) == '\0')
12690 return 1;
12691 return 0;
12692}
12693
12694static void
12695showvars(const char *myprefix, int mask, int xor)
12696{
12697 struct var **vpp;
12698 struct var *vp;
12699 const char *sep = myprefix == nullstr ? myprefix : spcstr;
12700
12701 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12702 for (vp = *vpp ; vp ; vp = vp->next) {
12703 if ((vp->flags & mask) ^ xor) {
12704 char *p;
12705 int len;
12706
12707 p = strchr(vp->text, '=') + 1;
12708 len = p - vp->text;
12709 p = single_quote(p);
12710
Eric Andersen62483552001-07-10 06:09:16 +000012711 printf("%s%s%.*s%s\n", myprefix, sep, len,
12712 vp->text, p);
Eric Andersencb57d552001-06-28 07:25:16 +000012713 stunalloc(p);
12714 }
12715 }
12716 }
12717}
12718
12719static struct var **
12720findvar(struct var **vpp, const char *name)
12721{
12722 for (; *vpp; vpp = &(*vpp)->next) {
12723 if (varequal((*vpp)->text, name)) {
12724 break;
12725 }
12726 }
12727 return vpp;
12728}
12729
12730/*
12731 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
12732 * This file contains code for the times builtin.
Eric Andersend63dee42001-10-19 00:22:23 +000012733 * $Id: ash.c,v 1.28 2001/10/19 00:22:22 andersen Exp $
Eric Andersencb57d552001-06-28 07:25:16 +000012734 */
12735static int timescmd (int argc, char **argv)
12736{
12737 struct tms buf;
12738 long int clk_tck = sysconf(_SC_CLK_TCK);
12739
12740 times(&buf);
12741 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
12742 (int) (buf.tms_utime / clk_tck / 60),
12743 ((double) buf.tms_utime) / clk_tck,
12744 (int) (buf.tms_stime / clk_tck / 60),
12745 ((double) buf.tms_stime) / clk_tck,
12746 (int) (buf.tms_cutime / clk_tck / 60),
12747 ((double) buf.tms_cutime) / clk_tck,
12748 (int) (buf.tms_cstime / clk_tck / 60),
12749 ((double) buf.tms_cstime) / clk_tck);
12750 return 0;
12751}
12752
Eric Andersen74bcd162001-07-30 21:41:37 +000012753#ifdef ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012754/* The let builtin. */
12755int letcmd(int argc, char **argv)
Eric Andersen74bcd162001-07-30 21:41:37 +000012756{
Eric Andersen34506362001-08-02 05:02:46 +000012757 int errcode;
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012758 long result=0;
12759 if (argc == 2) {
12760 char *tmp, *expression, p[13];
12761 expression = strchr(argv[1], '=');
12762 if (!expression) {
Eric Andersen34506362001-08-02 05:02:46 +000012763 /* Cannot use 'error()' here, or the return code
12764 * will be incorrect */
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012765 out2fmt("sh: let: syntax error: \"%s\"\n", argv[1]);
12766 return 0;
Eric Andersen74bcd162001-07-30 21:41:37 +000012767 }
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012768 *expression = '\0';
12769 tmp = ++expression;
Eric Andersen34506362001-08-02 05:02:46 +000012770 result = arith(tmp, &errcode);
12771 if (errcode < 0) {
12772 /* Cannot use 'error()' here, or the return code
12773 * will be incorrect */
12774 out2fmt("sh: let: ");
12775 if(errcode == -2)
12776 out2fmt("divide by zero");
12777 else
12778 out2fmt("syntax error: \"%s=%s\"\n", argv[1], expression);
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012779 return 0;
12780 }
12781 snprintf(p, 12, "%ld", result);
12782 setvar(argv[1], savestr(p), 0);
12783 } else if (argc >= 3)
12784 synerror("invalid operand");
12785 return !result;
Eric Andersen74bcd162001-07-30 21:41:37 +000012786}
12787#endif
12788
12789
12790
Eric Andersendf82f612001-06-28 07:46:40 +000012791/*-
12792 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000012793 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000012794 *
12795 * This code is derived from software contributed to Berkeley by
12796 * Kenneth Almquist.
12797 *
12798 * Redistribution and use in source and binary forms, with or without
12799 * modification, are permitted provided that the following conditions
12800 * are met:
12801 * 1. Redistributions of source code must retain the above copyright
12802 * notice, this list of conditions and the following disclaimer.
12803 * 2. Redistributions in binary form must reproduce the above copyright
12804 * notice, this list of conditions and the following disclaimer in the
12805 * documentation and/or other materials provided with the distribution.
12806 *
Eric Andersen2870d962001-07-02 17:27:21 +000012807 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
12808 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000012809 *
12810 * 4. Neither the name of the University nor the names of its contributors
12811 * may be used to endorse or promote products derived from this software
12812 * without specific prior written permission.
12813 *
12814 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
12815 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
12816 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
12817 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
12818 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
12819 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
12820 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
12821 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
12822 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
12823 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
12824 * SUCH DAMAGE.
12825 */