blob: a65275893e9a021902de6290e14c0210c045c627 [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 +00001526#define ARITH_NUM 257
1527#define ARITH_LPAREN 258
1528#define ARITH_RPAREN 259
1529#define ARITH_OR 260
1530#define ARITH_AND 261
1531#define ARITH_BOR 262
1532#define ARITH_BXOR 263
1533#define ARITH_BAND 264
1534#define ARITH_EQ 265
1535#define ARITH_NE 266
1536#define ARITH_LT 267
1537#define ARITH_GT 268
1538#define ARITH_GE 269
1539#define ARITH_LE 270
1540#define ARITH_LSHIFT 271
1541#define ARITH_RSHIFT 272
1542#define ARITH_ADD 273
1543#define ARITH_SUB 274
1544#define ARITH_MUL 275
1545#define ARITH_DIV 276
1546#define ARITH_REM 277
1547#define ARITH_UNARYMINUS 278
1548#define ARITH_UNARYPLUS 279
1549#define ARITH_NOT 280
1550#define ARITH_BNOT 281
1551
1552static void expari (int);
Eric Andersencb57d552001-06-28 07:25:16 +00001553#endif
1554
Eric Andersen2870d962001-07-02 17:27:21 +00001555static char *trap[NSIG]; /* trap handler commands */
1556static char sigmode[NSIG - 1]; /* current value of signal */
1557static char gotsig[NSIG - 1]; /* indicates specified signal received */
1558static int pendingsigs; /* indicates some signal received */
1559
Eric Andersencb57d552001-06-28 07:25:16 +00001560/*
1561 * This file was generated by the mkbuiltins program.
1562 */
1563
Eric Andersen2870d962001-07-02 17:27:21 +00001564#ifdef JOBS
1565static int bgcmd (int, char **);
1566static int fgcmd (int, char **);
1567static int killcmd (int, char **);
1568#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001569static int bltincmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001570static int cdcmd (int, char **);
1571static int breakcmd (int, char **);
1572#ifdef ASH_CMDCMD
1573static int commandcmd (int, char **);
1574#endif
1575static int dotcmd (int, char **);
1576static int evalcmd (int, char **);
1577static int execcmd (int, char **);
1578static int exitcmd (int, char **);
1579static int exportcmd (int, char **);
1580static int histcmd (int, char **);
1581static int hashcmd (int, char **);
Eric Andersen1c039232001-07-07 00:05:55 +00001582static int helpcmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001583static int jobscmd (int, char **);
1584static int localcmd (int, char **);
Eric Andersen3102ac42001-07-06 04:26:23 +00001585#ifndef BB_PWD
Eric Andersen2870d962001-07-02 17:27:21 +00001586static int pwdcmd (int, char **);
1587#endif
1588static int readcmd (int, char **);
1589static int returncmd (int, char **);
1590static int setcmd (int, char **);
1591static int setvarcmd (int, char **);
1592static int shiftcmd (int, char **);
1593static int trapcmd (int, char **);
1594static int umaskcmd (int, char **);
1595#ifdef ASH_ALIAS
1596static int aliascmd (int, char **);
1597static int unaliascmd (int, char **);
1598#endif
1599static int unsetcmd (int, char **);
1600static int waitcmd (int, char **);
1601static int ulimitcmd (int, char **);
1602static int timescmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001603#ifdef ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +00001604static int letcmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001605#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001606static int typecmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001607#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00001608static int getoptscmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001609#endif
1610
Eric Andersen2870d962001-07-02 17:27:21 +00001611#ifndef BB_TRUE_FALSE
Eric Andersen2870d962001-07-02 17:27:21 +00001612static int true_main (int, char **);
1613static int false_main (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001614#endif
1615
1616static void setpwd (const char *, int);
1617
1618
1619#define BUILTIN_NOSPEC "0"
1620#define BUILTIN_SPECIAL "1"
1621#define BUILTIN_REGULAR "2"
1622#define BUILTIN_ASSIGN "4"
1623#define BUILTIN_SPEC_ASSG "5"
1624#define BUILTIN_REG_ASSG "6"
1625
1626#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1627#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1628#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
1629
1630struct builtincmd {
1631 const char *name;
1632 int (*const builtinfunc) (int, char **);
1633 //unsigned flags;
1634};
1635
Eric Andersencb57d552001-06-28 07:25:16 +00001636
1637/* It is CRUCIAL that this listing be kept in ascii order, otherwise
1638 * the binary search in find_builtin() will stop working. If you value
1639 * your kneecaps, you'll be sure to *make sure* that any changes made
1640 * to this array result in the listing remaining in ascii order. You
1641 * have been warned.
1642 */
1643static const struct builtincmd builtincmds[] = {
Eric Andersen62483552001-07-10 06:09:16 +00001644 { BUILTIN_SPECIAL ".", dotcmd }, /* first, see declare DOTCMD */
Eric Andersen2870d962001-07-02 17:27:21 +00001645 { BUILTIN_SPECIAL ":", true_main },
1646#ifdef ASH_ALIAS
1647 { BUILTIN_REG_ASSG "alias", aliascmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001648#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001649#ifdef JOBS
1650 { BUILTIN_REGULAR "bg", bgcmd },
1651#endif
1652 { BUILTIN_SPECIAL "break", breakcmd },
Eric Andersen3102ac42001-07-06 04:26:23 +00001653 { BUILTIN_SPECIAL "builtin", bltincmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001654 { BUILTIN_REGULAR "cd", cdcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001655 { BUILTIN_NOSPEC "chdir", cdcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001656#ifdef ASH_CMDCMD
1657 { BUILTIN_REGULAR "command", commandcmd },
1658#endif
1659 { BUILTIN_SPECIAL "continue", breakcmd },
1660 { BUILTIN_SPECIAL "eval", evalcmd },
1661 { BUILTIN_SPECIAL "exec", execcmd },
1662 { BUILTIN_SPECIAL "exit", exitcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001663 { BUILTIN_SPEC_ASSG "export", exportcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001664 { BUILTIN_REGULAR "false", false_main },
Eric Andersen2870d962001-07-02 17:27:21 +00001665 { BUILTIN_REGULAR "fc", histcmd },
1666#ifdef JOBS
1667 { BUILTIN_REGULAR "fg", fgcmd },
1668#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001669#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00001670 { BUILTIN_REGULAR "getopts", getoptscmd },
1671#endif
1672 { BUILTIN_NOSPEC "hash", hashcmd },
Eric Andersen1c039232001-07-07 00:05:55 +00001673 { BUILTIN_NOSPEC "help", helpcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001674 { BUILTIN_REGULAR "jobs", jobscmd },
1675#ifdef JOBS
1676 { BUILTIN_REGULAR "kill", killcmd },
1677#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001678#ifdef ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +00001679 { BUILTIN_REGULAR "let", letcmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001680#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001681 { BUILTIN_ASSIGN "local", localcmd },
Eric Andersen3102ac42001-07-06 04:26:23 +00001682#ifndef BB_PWD
Eric Andersen2870d962001-07-02 17:27:21 +00001683 { BUILTIN_NOSPEC "pwd", pwdcmd },
1684#endif
1685 { BUILTIN_REGULAR "read", readcmd },
1686 { BUILTIN_SPEC_ASSG "readonly", exportcmd },
1687 { BUILTIN_SPECIAL "return", returncmd },
1688 { BUILTIN_SPECIAL "set", setcmd },
1689 { BUILTIN_NOSPEC "setvar", setvarcmd },
1690 { BUILTIN_SPECIAL "shift", shiftcmd },
1691 { BUILTIN_SPECIAL "times", timescmd },
1692 { BUILTIN_SPECIAL "trap", trapcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001693 { BUILTIN_REGULAR "true", true_main },
Eric Andersen2870d962001-07-02 17:27:21 +00001694 { BUILTIN_NOSPEC "type", typecmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001695 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1696 { BUILTIN_REGULAR "umask", umaskcmd },
1697#ifdef ASH_ALIAS
1698 { BUILTIN_REGULAR "unalias", unaliascmd },
1699#endif
1700 { BUILTIN_SPECIAL "unset", unsetcmd },
1701 { BUILTIN_REGULAR "wait", waitcmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001702};
1703#define NUMBUILTINS (sizeof (builtincmds) / sizeof (struct builtincmd) )
1704
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001705#define DOTCMD &builtincmds[0]
Eric Andersen2870d962001-07-02 17:27:21 +00001706static struct builtincmd *BLTINCMD;
1707static struct builtincmd *EXECCMD;
1708static struct builtincmd *EVALCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00001709
Eric Andersen2870d962001-07-02 17:27:21 +00001710/* states */
1711#define JOBSTOPPED 1 /* all procs are stopped */
1712#define JOBDONE 2 /* all procs are completed */
Eric Andersencb57d552001-06-28 07:25:16 +00001713
Eric Andersen2870d962001-07-02 17:27:21 +00001714/*
1715 * A job structure contains information about a job. A job is either a
1716 * single process or a set of processes contained in a pipeline. In the
1717 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1718 * array of pids.
1719 */
Eric Andersencb57d552001-06-28 07:25:16 +00001720
Eric Andersen2870d962001-07-02 17:27:21 +00001721struct procstat {
1722 pid_t pid; /* process id */
1723 int status; /* status flags (defined above) */
1724 char *cmd; /* text of command being run */
1725};
Eric Andersencb57d552001-06-28 07:25:16 +00001726
Eric Andersen2870d962001-07-02 17:27:21 +00001727
1728static int job_warning; /* user was warned about stopped jobs */
1729
1730#ifdef JOBS
1731static void setjobctl(int enable);
1732#else
1733#define setjobctl(on) /* do nothing */
Eric Andersencb57d552001-06-28 07:25:16 +00001734#endif
1735
Eric Andersen2870d962001-07-02 17:27:21 +00001736
1737struct job {
1738 struct procstat ps0; /* status of process */
1739 struct procstat *ps; /* status or processes when more than one */
1740 short nprocs; /* number of processes */
1741 short pgrp; /* process group of this job */
1742 char state; /* true if job is finished */
1743 char used; /* true if this entry is in used */
1744 char changed; /* true if status has changed */
1745#ifdef JOBS
1746 char jobctl; /* job running under job control */
1747#endif
1748};
1749
1750static struct job *jobtab; /* array of jobs */
1751static int njobs; /* size of array */
1752static int backgndpid = -1; /* pid of last background process */
1753#ifdef JOBS
1754static int initialpgrp; /* pgrp of shell on invocation */
1755static int curjob; /* current job */
1756static int jobctl;
1757#endif
1758static int intreceived;
1759
Eric Andersen62483552001-07-10 06:09:16 +00001760static struct job *makejob (const union node *, int);
1761static int forkshell (struct job *, const union node *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00001762static int waitforjob (struct job *);
1763
1764static int docd (char *, int);
1765static char *getcomponent (void);
1766static void updatepwd (const char *);
1767static void getpwd (void);
1768
1769static char *padvance (const char **, const char *);
1770
1771static char nullstr[1]; /* zero length string */
1772static char *curdir = nullstr; /* current working directory */
1773static char *cdcomppath;
1774
Eric Andersencb57d552001-06-28 07:25:16 +00001775static int
1776cdcmd(argc, argv)
1777 int argc;
1778 char **argv;
1779{
1780 const char *dest;
1781 const char *path;
1782 char *p;
1783 struct stat statb;
1784 int print = 0;
1785
1786 nextopt(nullstr);
1787 if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME")) == NULL)
1788 error("HOME not set");
1789 if (*dest == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00001790 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001791 if (dest[0] == '-' && dest[1] == '\0') {
1792 dest = bltinlookup("OLDPWD");
1793 if (!dest || !*dest) {
1794 dest = curdir;
1795 }
1796 print = 1;
1797 if (dest)
Eric Andersen2870d962001-07-02 17:27:21 +00001798 print = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00001799 else
Eric Andersen2870d962001-07-02 17:27:21 +00001800 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001801 }
1802 if (*dest == '/' || (path = bltinlookup("CDPATH")) == NULL)
1803 path = nullstr;
1804 while ((p = padvance(&path, dest)) != NULL) {
1805 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
1806 if (!print) {
1807 /*
1808 * XXX - rethink
1809 */
1810 if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
1811 p += 2;
1812 print = strcmp(p, dest);
1813 }
1814 if (docd(p, print) >= 0)
1815 return 0;
1816
1817 }
1818 }
1819 error("can't cd to %s", dest);
1820 /* NOTREACHED */
1821}
1822
1823
1824/*
1825 * Actually do the chdir. In an interactive shell, print the
1826 * directory name if "print" is nonzero.
1827 */
1828
1829static int
1830docd(dest, print)
1831 char *dest;
1832 int print;
1833{
1834 char *p;
1835 char *q;
1836 char *component;
1837 struct stat statb;
1838 int first;
1839 int badstat;
1840
1841 TRACE(("docd(\"%s\", %d) called\n", dest, print));
1842
1843 /*
1844 * Check each component of the path. If we find a symlink or
1845 * something we can't stat, clear curdir to force a getcwd()
1846 * next time we get the value of the current directory.
1847 */
1848 badstat = 0;
1849 cdcomppath = sstrdup(dest);
1850 STARTSTACKSTR(p);
1851 if (*dest == '/') {
1852 STPUTC('/', p);
1853 cdcomppath++;
1854 }
1855 first = 1;
1856 while ((q = getcomponent()) != NULL) {
1857 if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0'))
1858 continue;
1859 if (! first)
1860 STPUTC('/', p);
1861 first = 0;
1862 component = q;
1863 while (*q)
1864 STPUTC(*q++, p);
1865 if (equal(component, ".."))
1866 continue;
1867 STACKSTRNUL(p);
1868 if ((lstat(stackblock(), &statb) < 0)
1869 || (S_ISLNK(statb.st_mode))) {
1870 /* print = 1; */
1871 badstat = 1;
1872 break;
1873 }
1874 }
1875
1876 INTOFF;
1877 if (chdir(dest) < 0) {
1878 INTON;
1879 return -1;
1880 }
1881 updatepwd(badstat ? NULL : dest);
1882 INTON;
1883 if (print && iflag)
Eric Andersen62483552001-07-10 06:09:16 +00001884 printf(snlfmt, curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00001885 return 0;
1886}
1887
1888
1889/*
1890 * Get the next component of the path name pointed to by cdcomppath.
1891 * This routine overwrites the string pointed to by cdcomppath.
1892 */
1893
1894static char *
1895getcomponent() {
1896 char *p;
1897 char *start;
1898
1899 if ((p = cdcomppath) == NULL)
1900 return NULL;
1901 start = cdcomppath;
1902 while (*p != '/' && *p != '\0')
1903 p++;
1904 if (*p == '\0') {
1905 cdcomppath = NULL;
1906 } else {
1907 *p++ = '\0';
1908 cdcomppath = p;
1909 }
1910 return start;
1911}
1912
1913
1914
1915/*
1916 * Update curdir (the name of the current directory) in response to a
1917 * cd command. We also call hashcd to let the routines in exec.c know
1918 * that the current directory has changed.
1919 */
1920
Eric Andersen2870d962001-07-02 17:27:21 +00001921static void hashcd (void);
1922
Eric Andersencb57d552001-06-28 07:25:16 +00001923static void
Eric Andersen2870d962001-07-02 17:27:21 +00001924updatepwd(const char *dir)
1925{
Eric Andersencb57d552001-06-28 07:25:16 +00001926 char *new;
1927 char *p;
1928 size_t len;
1929
Eric Andersen2870d962001-07-02 17:27:21 +00001930 hashcd(); /* update command hash table */
Eric Andersencb57d552001-06-28 07:25:16 +00001931
1932 /*
1933 * If our argument is NULL, we don't know the current directory
1934 * any more because we traversed a symbolic link or something
1935 * we couldn't stat().
1936 */
1937 if (dir == NULL || curdir == nullstr) {
1938 setpwd(0, 1);
1939 return;
1940 }
1941 len = strlen(dir);
1942 cdcomppath = sstrdup(dir);
1943 STARTSTACKSTR(new);
1944 if (*dir != '/') {
1945 p = curdir;
1946 while (*p)
1947 STPUTC(*p++, new);
1948 if (p[-1] == '/')
1949 STUNPUTC(new);
1950 }
1951 while ((p = getcomponent()) != NULL) {
1952 if (equal(p, "..")) {
1953 while (new > stackblock() && (STUNPUTC(new), *new) != '/');
1954 } else if (*p != '\0' && ! equal(p, ".")) {
1955 STPUTC('/', new);
1956 while (*p)
1957 STPUTC(*p++, new);
1958 }
1959 }
1960 if (new == stackblock())
1961 STPUTC('/', new);
1962 STACKSTRNUL(new);
1963 setpwd(stackblock(), 1);
1964}
1965
1966
Eric Andersen3102ac42001-07-06 04:26:23 +00001967#ifndef BB_PWD
Eric Andersencb57d552001-06-28 07:25:16 +00001968static int
1969pwdcmd(argc, argv)
1970 int argc;
1971 char **argv;
1972{
Eric Andersen62483552001-07-10 06:09:16 +00001973 printf(snlfmt, curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00001974 return 0;
1975}
Eric Andersen2870d962001-07-02 17:27:21 +00001976#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001977
1978/*
1979 * Find out what the current directory is. If we already know the current
1980 * directory, this routine returns immediately.
1981 */
1982static void
Eric Andersen2870d962001-07-02 17:27:21 +00001983getpwd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00001984{
Eric Andersen2870d962001-07-02 17:27:21 +00001985 curdir = xgetcwd(0);
1986 if(curdir==0)
1987 curdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00001988}
1989
1990static void
1991setpwd(const char *val, int setold)
1992{
1993 if (setold) {
1994 setvar("OLDPWD", curdir, VEXPORT);
1995 }
1996 INTOFF;
1997 if (curdir != nullstr) {
1998 free(curdir);
1999 curdir = nullstr;
2000 }
2001 if (!val) {
2002 getpwd();
2003 } else {
2004 curdir = savestr(val);
2005 }
2006 INTON;
2007 setvar("PWD", curdir, VEXPORT);
2008}
2009
Eric Andersencb57d552001-06-28 07:25:16 +00002010/*
2011 * Errors and exceptions.
2012 */
2013
2014/*
2015 * Code to handle exceptions in C.
2016 */
2017
Eric Andersen2870d962001-07-02 17:27:21 +00002018/*
2019 * We enclose jmp_buf in a structure so that we can declare pointers to
2020 * jump locations. The global variable handler contains the location to
2021 * jump to when an exception occurs, and the global variable exception
2022 * contains a code identifying the exeception. To implement nested
2023 * exception handlers, the user should save the value of handler on entry
2024 * to an inner scope, set handler to point to a jmploc structure for the
2025 * inner scope, and restore handler on exit from the scope.
2026 */
2027
2028struct jmploc {
2029 jmp_buf loc;
2030};
2031
2032/* exceptions */
2033#define EXINT 0 /* SIGINT received */
2034#define EXERROR 1 /* a generic error */
2035#define EXSHELLPROC 2 /* execute a shell procedure */
2036#define EXEXEC 3 /* command execution failed */
2037
2038static struct jmploc *handler;
Eric Andersencb57d552001-06-28 07:25:16 +00002039static int exception;
Eric Andersencb57d552001-06-28 07:25:16 +00002040
Eric Andersen2870d962001-07-02 17:27:21 +00002041static void exverror (int, const char *, va_list)
Eric Andersencb57d552001-06-28 07:25:16 +00002042 __attribute__((__noreturn__));
2043
2044/*
2045 * Called to raise an exception. Since C doesn't include exceptions, we
2046 * just do a longjmp to the exception handler. The type of exception is
2047 * stored in the global variable "exception".
2048 */
2049
Eric Andersen2870d962001-07-02 17:27:21 +00002050static void exraise (int) __attribute__((__noreturn__));
2051
Eric Andersencb57d552001-06-28 07:25:16 +00002052static void
Eric Andersen2870d962001-07-02 17:27:21 +00002053exraise(int e)
Eric Andersencb57d552001-06-28 07:25:16 +00002054{
2055#ifdef DEBUG
2056 if (handler == NULL)
2057 abort();
2058#endif
Eric Andersen62483552001-07-10 06:09:16 +00002059 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00002060 exception = e;
2061 longjmp(handler->loc, 1);
2062}
2063
2064
2065/*
2066 * Called from trap.c when a SIGINT is received. (If the user specifies
2067 * that SIGINT is to be trapped or ignored using the trap builtin, then
2068 * this routine is not called.) Suppressint is nonzero when interrupts
2069 * are held using the INTOFF macro. The call to _exit is necessary because
2070 * there is a short period after a fork before the signal handlers are
2071 * set to the appropriate value for the child. (The test for iflag is
2072 * just defensive programming.)
2073 */
2074
2075static void
Eric Andersen2870d962001-07-02 17:27:21 +00002076onint(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00002077 sigset_t mysigset;
2078
2079 if (suppressint) {
2080 intpending++;
2081 return;
2082 }
2083 intpending = 0;
2084 sigemptyset(&mysigset);
2085 sigprocmask(SIG_SETMASK, &mysigset, NULL);
2086 if (rootshell && iflag)
2087 exraise(EXINT);
2088 else {
2089 signal(SIGINT, SIG_DFL);
2090 raise(SIGINT);
2091 }
2092 /* NOTREACHED */
2093}
2094
2095
Eric Andersen2870d962001-07-02 17:27:21 +00002096static char *commandname; /* currently executing command */
2097
Eric Andersencb57d552001-06-28 07:25:16 +00002098/*
2099 * Exverror is called to raise the error exception. If the first argument
2100 * is not NULL then error prints an error message using printf style
2101 * formatting. It then raises the error exception.
2102 */
2103static void
Eric Andersen2870d962001-07-02 17:27:21 +00002104exverror(int cond, const char *msg, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00002105{
2106 CLEAR_PENDING_INT;
2107 INTOFF;
2108
2109#ifdef DEBUG
2110 if (msg)
2111 TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
2112 else
2113 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2114#endif
2115 if (msg) {
2116 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +00002117 out2fmt("%s: ", commandname);
2118 vfprintf(stderr, msg, ap);
2119 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00002120 }
Eric Andersencb57d552001-06-28 07:25:16 +00002121 exraise(cond);
2122 /* NOTREACHED */
2123}
2124
2125
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002126static void
Eric Andersencb57d552001-06-28 07:25:16 +00002127error(const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002128{
Eric Andersencb57d552001-06-28 07:25:16 +00002129 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002130 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002131 exverror(EXERROR, msg, ap);
2132 /* NOTREACHED */
2133 va_end(ap);
2134}
2135
2136
Eric Andersencb57d552001-06-28 07:25:16 +00002137static void
2138exerror(int cond, const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002139{
Eric Andersencb57d552001-06-28 07:25:16 +00002140 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002141 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002142 exverror(cond, msg, ap);
2143 /* NOTREACHED */
2144 va_end(ap);
2145}
2146
2147
2148
2149/*
2150 * Table of error messages.
2151 */
2152
2153struct errname {
Eric Andersen2870d962001-07-02 17:27:21 +00002154 short errcode; /* error number */
Eric Andersen62483552001-07-10 06:09:16 +00002155 char action; /* operation which encountered the error */
Eric Andersencb57d552001-06-28 07:25:16 +00002156};
2157
Eric Andersen2870d962001-07-02 17:27:21 +00002158/*
2159 * Types of operations (passed to the errmsg routine).
2160 */
2161
2162#define E_OPEN 01 /* opening a file */
2163#define E_CREAT 02 /* creating a file */
2164#define E_EXEC 04 /* executing a program */
Eric Andersencb57d552001-06-28 07:25:16 +00002165
2166#define ALL (E_OPEN|E_CREAT|E_EXEC)
2167
2168static const struct errname errormsg[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00002169 { EINTR, ALL },
2170 { EACCES, ALL },
2171 { EIO, ALL },
2172 { ENOENT, E_OPEN },
2173 { ENOENT, E_CREAT },
2174 { ENOENT, E_EXEC },
2175 { ENOTDIR, E_OPEN },
2176 { ENOTDIR, E_CREAT },
2177 { ENOTDIR, E_EXEC },
2178 { EISDIR, ALL },
2179 { EEXIST, E_CREAT },
2180#ifdef EMFILE
2181 { EMFILE, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002182#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002183 { ENFILE, ALL },
2184 { ENOSPC, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002185#ifdef EDQUOT
Eric Andersen2870d962001-07-02 17:27:21 +00002186 { EDQUOT, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002187#endif
2188#ifdef ENOSR
Eric Andersen2870d962001-07-02 17:27:21 +00002189 { ENOSR, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002190#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002191 { ENXIO, ALL },
2192 { EROFS, ALL },
2193 { ETXTBSY, ALL },
2194#ifdef EAGAIN
2195 { EAGAIN, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002196#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002197 { ENOMEM, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002198#ifdef ENOLINK
Eric Andersen2870d962001-07-02 17:27:21 +00002199 { ENOLINK, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002200#endif
2201#ifdef EMULTIHOP
Eric Andersen2870d962001-07-02 17:27:21 +00002202 { EMULTIHOP, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002203#endif
2204#ifdef ECOMM
Eric Andersen2870d962001-07-02 17:27:21 +00002205 { ECOMM, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002206#endif
2207#ifdef ESTALE
Eric Andersen2870d962001-07-02 17:27:21 +00002208 { ESTALE, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002209#endif
2210#ifdef ETIMEDOUT
Eric Andersen2870d962001-07-02 17:27:21 +00002211 { ETIMEDOUT, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002212#endif
2213#ifdef ELOOP
Eric Andersen2870d962001-07-02 17:27:21 +00002214 { ELOOP, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002215#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002216 { E2BIG, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002217#ifdef ELIBACC
Eric Andersen2870d962001-07-02 17:27:21 +00002218 { ELIBACC, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002219#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002220};
2221
Eric Andersen2870d962001-07-02 17:27:21 +00002222#define ERRNAME_SIZE (sizeof(errormsg)/sizeof(struct errname))
Eric Andersencb57d552001-06-28 07:25:16 +00002223
2224/*
2225 * Return a string describing an error. The returned string may be a
2226 * pointer to a static buffer that will be overwritten on the next call.
2227 * Action describes the operation that got the error.
2228 */
2229
2230static const char *
Eric Andersen2870d962001-07-02 17:27:21 +00002231errmsg(int e, int action)
Eric Andersencb57d552001-06-28 07:25:16 +00002232{
2233 struct errname const *ep;
2234 static char buf[12];
2235
Eric Andersen2870d962001-07-02 17:27:21 +00002236 for (ep = errormsg ; ep < errormsg+ERRNAME_SIZE; ep++) {
Eric Andersencb57d552001-06-28 07:25:16 +00002237 if (ep->errcode == e && (ep->action & action) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00002238 return strerror(e);
Eric Andersencb57d552001-06-28 07:25:16 +00002239 }
Eric Andersen2870d962001-07-02 17:27:21 +00002240
Eric Andersen3102ac42001-07-06 04:26:23 +00002241 snprintf(buf, sizeof buf, "error %d", e);
Eric Andersencb57d552001-06-28 07:25:16 +00002242 return buf;
2243}
2244
2245
Eric Andersen3102ac42001-07-06 04:26:23 +00002246#ifdef ASH_OPTIMIZE_FOR_SIZE
Eric Andersencb57d552001-06-28 07:25:16 +00002247static void
2248__inton() {
2249 if (--suppressint == 0 && intpending) {
2250 onint();
2251 }
2252}
Eric Andersen3102ac42001-07-06 04:26:23 +00002253static void forceinton (void) {
2254 suppressint = 0;
2255 if (intpending)
2256 onint();
2257}
Eric Andersencb57d552001-06-28 07:25:16 +00002258#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002259
2260/* flags in argument to evaltree */
Eric Andersen2870d962001-07-02 17:27:21 +00002261#define EV_EXIT 01 /* exit after evaluating tree */
2262#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2263#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00002264
Eric Andersen2870d962001-07-02 17:27:21 +00002265static int evalskip; /* set if we are skipping commands */
2266static int skipcount; /* number of levels to skip */
2267static int loopnest; /* current loop nesting level */
2268static int funcnest; /* depth of function calls */
Eric Andersencb57d552001-06-28 07:25:16 +00002269
2270
Eric Andersen2870d962001-07-02 17:27:21 +00002271static struct strlist *cmdenviron; /* environment for builtin command */
2272static int exitstatus; /* exit status of last command */
2273static int oexitstatus; /* saved exit status */
Eric Andersencb57d552001-06-28 07:25:16 +00002274
Eric Andersen62483552001-07-10 06:09:16 +00002275static void evalsubshell (const union node *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00002276static void expredir (union node *);
Eric Andersen2870d962001-07-02 17:27:21 +00002277static void prehash (union node *);
2278static void eprintlist (struct strlist *);
Eric Andersencb57d552001-06-28 07:25:16 +00002279
Eric Andersen2870d962001-07-02 17:27:21 +00002280static union node *parsecmd(int);
Eric Andersencb57d552001-06-28 07:25:16 +00002281/*
2282 * Called to reset things after an exception.
2283 */
2284
Eric Andersencb57d552001-06-28 07:25:16 +00002285/*
2286 * The eval commmand.
2287 */
Eric Andersen2870d962001-07-02 17:27:21 +00002288static void evalstring (char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00002289
2290static int
2291evalcmd(argc, argv)
2292 int argc;
2293 char **argv;
2294{
Eric Andersen2870d962001-07-02 17:27:21 +00002295 char *p;
2296 char *concat;
2297 char **ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002298
Eric Andersen2870d962001-07-02 17:27:21 +00002299 if (argc > 1) {
2300 p = argv[1];
2301 if (argc > 2) {
2302 STARTSTACKSTR(concat);
2303 ap = argv + 2;
2304 for (;;) {
2305 while (*p)
2306 STPUTC(*p++, concat);
2307 if ((p = *ap++) == NULL)
2308 break;
2309 STPUTC(' ', concat);
2310 }
2311 STPUTC('\0', concat);
2312 p = grabstackstr(concat);
2313 }
2314 evalstring(p, EV_TESTED);
2315 }
2316 return exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002317}
2318
Eric Andersencb57d552001-06-28 07:25:16 +00002319/*
2320 * Execute a command or commands contained in a string.
2321 */
2322
Eric Andersen2870d962001-07-02 17:27:21 +00002323static void evaltree (union node *, int);
2324static void setinputstring (char *);
2325static void popfile (void);
2326static void setstackmark(struct stackmark *mark);
2327static void popstackmark(struct stackmark *mark);
2328
2329
Eric Andersencb57d552001-06-28 07:25:16 +00002330static void
Eric Andersen2870d962001-07-02 17:27:21 +00002331evalstring(char *s, int flag)
2332{
Eric Andersencb57d552001-06-28 07:25:16 +00002333 union node *n;
2334 struct stackmark smark;
2335
2336 setstackmark(&smark);
2337 setinputstring(s);
2338 while ((n = parsecmd(0)) != NEOF) {
2339 evaltree(n, flag);
2340 popstackmark(&smark);
2341 }
2342 popfile();
2343 popstackmark(&smark);
2344}
2345
Eric Andersen2870d962001-07-02 17:27:21 +00002346static struct builtincmd *find_builtin (const char *);
Eric Andersen62483552001-07-10 06:09:16 +00002347static void expandarg (union node *, struct arglist *, int);
2348static void calcsize (const union node *);
2349static union node *copynode (const union node *);
2350
2351/*
2352 * Make a copy of a parse tree.
2353 */
2354
2355static int funcblocksize; /* size of structures in function */
2356static int funcstringsize; /* size of strings in node */
2357static pointer funcblock; /* block to allocate function from */
2358static char *funcstring; /* block to allocate strings from */
2359
2360
2361static inline union node *
2362copyfunc(union node *n)
2363{
2364 if (n == NULL)
2365 return NULL;
2366 funcblocksize = 0;
2367 funcstringsize = 0;
2368 calcsize(n);
2369 funcblock = ckmalloc(funcblocksize + funcstringsize);
2370 funcstring = (char *) funcblock + funcblocksize;
2371 return copynode(n);
2372}
2373
2374/*
2375 * Free a parse tree.
2376 */
Eric Andersencb57d552001-06-28 07:25:16 +00002377
2378static void
Eric Andersen62483552001-07-10 06:09:16 +00002379freefunc(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00002380{
Eric Andersen62483552001-07-10 06:09:16 +00002381 if (n)
2382 ckfree(n);
Eric Andersencb57d552001-06-28 07:25:16 +00002383}
2384
2385
Eric Andersen62483552001-07-10 06:09:16 +00002386/*
2387 * Add a new command entry, replacing any existing command entry for
2388 * the same name.
2389 */
2390
2391static inline void
2392addcmdentry(char *name, struct cmdentry *entry)
2393{
2394 struct tblentry *cmdp;
2395
2396 INTOFF;
2397 cmdp = cmdlookup(name, 1);
2398 if (cmdp->cmdtype == CMDFUNCTION) {
2399 freefunc(cmdp->param.func);
2400 }
2401 cmdp->cmdtype = entry->cmdtype;
2402 cmdp->param = entry->u;
2403 INTON;
2404}
2405
2406static inline void
2407evalloop(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002408{
2409 int status;
2410
2411 loopnest++;
2412 status = 0;
2413 for (;;) {
2414 evaltree(n->nbinary.ch1, EV_TESTED);
2415 if (evalskip) {
Eric Andersen2870d962001-07-02 17:27:21 +00002416skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002417 evalskip = 0;
2418 continue;
2419 }
2420 if (evalskip == SKIPBREAK && --skipcount <= 0)
2421 evalskip = 0;
2422 break;
2423 }
2424 if (n->type == NWHILE) {
2425 if (exitstatus != 0)
2426 break;
2427 } else {
2428 if (exitstatus == 0)
2429 break;
2430 }
2431 evaltree(n->nbinary.ch2, flags & EV_TESTED);
2432 status = exitstatus;
2433 if (evalskip)
2434 goto skipping;
2435 }
2436 loopnest--;
2437 exitstatus = status;
2438}
2439
Eric Andersencb57d552001-06-28 07:25:16 +00002440static void
Eric Andersen62483552001-07-10 06:09:16 +00002441evalfor(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002442{
2443 struct arglist arglist;
2444 union node *argp;
2445 struct strlist *sp;
2446 struct stackmark smark;
2447
2448 setstackmark(&smark);
2449 arglist.lastp = &arglist.list;
2450 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2451 oexitstatus = exitstatus;
2452 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2453 if (evalskip)
2454 goto out;
2455 }
2456 *arglist.lastp = NULL;
2457
2458 exitstatus = 0;
2459 loopnest++;
2460 for (sp = arglist.list ; sp ; sp = sp->next) {
2461 setvar(n->nfor.var, sp->text, 0);
2462 evaltree(n->nfor.body, flags & EV_TESTED);
2463 if (evalskip) {
2464 if (evalskip == SKIPCONT && --skipcount <= 0) {
2465 evalskip = 0;
2466 continue;
2467 }
2468 if (evalskip == SKIPBREAK && --skipcount <= 0)
2469 evalskip = 0;
2470 break;
2471 }
2472 }
2473 loopnest--;
2474out:
2475 popstackmark(&smark);
2476}
2477
Eric Andersen62483552001-07-10 06:09:16 +00002478static inline void
2479evalcase(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002480{
2481 union node *cp;
2482 union node *patp;
2483 struct arglist arglist;
2484 struct stackmark smark;
2485
2486 setstackmark(&smark);
2487 arglist.lastp = &arglist.list;
2488 oexitstatus = exitstatus;
2489 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2490 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2491 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2492 if (casematch(patp, arglist.list->text)) {
2493 if (evalskip == 0) {
2494 evaltree(cp->nclist.body, flags);
2495 }
2496 goto out;
2497 }
2498 }
2499 }
2500out:
2501 popstackmark(&smark);
2502}
2503
Eric Andersencb57d552001-06-28 07:25:16 +00002504/*
Eric Andersencb57d552001-06-28 07:25:16 +00002505 * Evaluate a pipeline. All the processes in the pipeline are children
2506 * of the process creating the pipeline. (This differs from some versions
2507 * of the shell, which make the last process in a pipeline the parent
2508 * of all the rest.)
2509 */
2510
Eric Andersen74400cc2001-10-18 04:11:39 +00002511static inline void evalpipe(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00002512{
2513 struct job *jp;
2514 struct nodelist *lp;
2515 int pipelen;
2516 int prevfd;
2517 int pip[2];
2518
2519 TRACE(("evalpipe(0x%lx) called\n", (long)n));
2520 pipelen = 0;
2521 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
2522 pipelen++;
2523 INTOFF;
2524 jp = makejob(n, pipelen);
2525 prevfd = -1;
2526 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
2527 prehash(lp->n);
2528 pip[1] = -1;
2529 if (lp->next) {
2530 if (pipe(pip) < 0) {
2531 close(prevfd);
2532 error("Pipe call failed");
2533 }
2534 }
2535 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
2536 INTON;
2537 if (prevfd > 0) {
2538 close(0);
2539 dup_as_newfd(prevfd, 0);
2540 close(prevfd);
2541 if (pip[0] == 0) {
2542 pip[0] = -1;
2543 }
2544 }
2545 if (pip[1] >= 0) {
2546 if (pip[0] >= 0) {
2547 close(pip[0]);
2548 }
2549 if (pip[1] != 1) {
2550 close(1);
2551 dup_as_newfd(pip[1], 1);
2552 close(pip[1]);
2553 }
2554 }
2555 evaltree(lp->n, EV_EXIT);
2556 }
2557 if (prevfd >= 0)
2558 close(prevfd);
2559 prevfd = pip[0];
2560 close(pip[1]);
2561 }
2562 INTON;
2563 if (n->npipe.backgnd == 0) {
2564 INTOFF;
2565 exitstatus = waitforjob(jp);
2566 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
2567 INTON;
2568 }
2569}
2570
Eric Andersen2870d962001-07-02 17:27:21 +00002571static void find_command (const char *, struct cmdentry *, int, const char *);
2572
2573static int
2574isassignment(const char *word) {
2575 if (!is_name(*word)) {
2576 return 0;
2577 }
2578 do {
2579 word++;
2580 } while (is_in_name(*word));
2581 return *word == '=';
2582}
2583
Eric Andersen62483552001-07-10 06:09:16 +00002584
Eric Andersencb57d552001-06-28 07:25:16 +00002585static void
Eric Andersen3102ac42001-07-06 04:26:23 +00002586evalcommand(union node *cmd, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002587{
2588 struct stackmark smark;
2589 union node *argp;
2590 struct arglist arglist;
2591 struct arglist varlist;
2592 char **argv;
2593 int argc;
2594 char **envp;
2595 struct strlist *sp;
2596 int mode;
Eric Andersencb57d552001-06-28 07:25:16 +00002597 struct cmdentry cmdentry;
2598 struct job *jp;
2599 char *volatile savecmdname;
2600 volatile struct shparam saveparam;
2601 struct localvar *volatile savelocalvars;
2602 volatile int e;
2603 char *lastarg;
2604 const char *path;
2605 const struct builtincmd *firstbltin;
2606 struct jmploc *volatile savehandler;
2607 struct jmploc jmploc;
2608#if __GNUC__
2609 /* Avoid longjmp clobbering */
2610 (void) &argv;
2611 (void) &argc;
2612 (void) &lastarg;
2613 (void) &flags;
2614#endif
2615
2616 /* First expand the arguments. */
2617 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
2618 setstackmark(&smark);
2619 arglist.lastp = &arglist.list;
2620 varlist.lastp = &varlist.list;
2621 arglist.list = 0;
2622 oexitstatus = exitstatus;
2623 exitstatus = 0;
2624 path = pathval();
2625 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
2626 expandarg(argp, &varlist, EXP_VARTILDE);
2627 }
2628 for (
2629 argp = cmd->ncmd.args; argp && !arglist.list;
2630 argp = argp->narg.next
2631 ) {
2632 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2633 }
2634 if (argp) {
2635 struct builtincmd *bcmd;
Eric Andersen62483552001-07-10 06:09:16 +00002636 int pseudovarflag;
Eric Andersencb57d552001-06-28 07:25:16 +00002637 bcmd = find_builtin(arglist.list->text);
Eric Andersen2870d962001-07-02 17:27:21 +00002638 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00002639 for (; argp; argp = argp->narg.next) {
2640 if (pseudovarflag && isassignment(argp->narg.text)) {
2641 expandarg(argp, &arglist, EXP_VARTILDE);
2642 continue;
2643 }
2644 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2645 }
2646 }
2647 *arglist.lastp = NULL;
2648 *varlist.lastp = NULL;
2649 expredir(cmd->ncmd.redirect);
2650 argc = 0;
2651 for (sp = arglist.list ; sp ; sp = sp->next)
2652 argc++;
2653 argv = stalloc(sizeof (char *) * (argc + 1));
2654
2655 for (sp = arglist.list ; sp ; sp = sp->next) {
2656 TRACE(("evalcommand arg: %s\n", sp->text));
2657 *argv++ = sp->text;
2658 }
2659 *argv = NULL;
2660 lastarg = NULL;
2661 if (iflag && funcnest == 0 && argc > 0)
2662 lastarg = argv[-1];
2663 argv -= argc;
2664
2665 /* Print the command if xflag is set. */
2666 if (xflag) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002667 out2c('+');
Eric Andersencb57d552001-06-28 07:25:16 +00002668 eprintlist(varlist.list);
2669 eprintlist(arglist.list);
Eric Andersen3102ac42001-07-06 04:26:23 +00002670 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00002671 }
2672
2673 /* Now locate the command. */
2674 if (argc == 0) {
2675 cmdentry.cmdtype = CMDBUILTIN;
2676 firstbltin = cmdentry.u.cmd = BLTINCMD;
2677 } else {
2678 const char *oldpath;
2679 int findflag = DO_ERR;
2680 int oldfindflag;
2681
2682 /*
2683 * Modify the command lookup path, if a PATH= assignment
2684 * is present
2685 */
2686 for (sp = varlist.list ; sp ; sp = sp->next)
2687 if (varequal(sp->text, defpathvar)) {
2688 path = sp->text + 5;
2689 findflag |= DO_BRUTE;
2690 }
2691 oldpath = path;
2692 oldfindflag = findflag;
2693 firstbltin = 0;
2694 for(;;) {
2695 find_command(argv[0], &cmdentry, findflag, path);
Eric Andersen2870d962001-07-02 17:27:21 +00002696 if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */
Eric Andersencb57d552001-06-28 07:25:16 +00002697 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002698 goto out;
2699 }
2700 /* implement bltin and command here */
2701 if (cmdentry.cmdtype != CMDBUILTIN) {
2702 break;
2703 }
2704 if (!firstbltin) {
2705 firstbltin = cmdentry.u.cmd;
2706 }
2707 if (cmdentry.u.cmd == BLTINCMD) {
2708 for(;;) {
2709 struct builtincmd *bcmd;
2710
2711 argv++;
2712 if (--argc == 0)
2713 goto found;
2714 if (!(bcmd = find_builtin(*argv))) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002715 out2fmt("%s: not found\n", *argv);
Eric Andersencb57d552001-06-28 07:25:16 +00002716 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002717 goto out;
2718 }
2719 cmdentry.u.cmd = bcmd;
2720 if (bcmd != BLTINCMD)
2721 break;
2722 }
2723 }
Eric Andersen2870d962001-07-02 17:27:21 +00002724 if (cmdentry.u.cmd == find_builtin("command")) {
Eric Andersencb57d552001-06-28 07:25:16 +00002725 argv++;
2726 if (--argc == 0) {
2727 goto found;
2728 }
2729 if (*argv[0] == '-') {
2730 if (!equal(argv[0], "-p")) {
2731 argv--;
2732 argc++;
2733 break;
2734 }
2735 argv++;
2736 if (--argc == 0) {
2737 goto found;
2738 }
2739 path = defpath;
2740 findflag |= DO_BRUTE;
2741 } else {
2742 path = oldpath;
2743 findflag = oldfindflag;
2744 }
2745 findflag |= DO_NOFUN;
2746 continue;
2747 }
2748found:
2749 break;
2750 }
2751 }
2752
2753 /* Fork off a child process if necessary. */
2754 if (cmd->ncmd.backgnd
2755 || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00002756 ) {
2757 jp = makejob(cmd, 1);
2758 mode = cmd->ncmd.backgnd;
Eric Andersencb57d552001-06-28 07:25:16 +00002759 if (forkshell(jp, cmd, mode) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00002760 goto parent; /* at end of routine */
Eric Andersencb57d552001-06-28 07:25:16 +00002761 flags |= EV_EXIT;
2762 }
2763
2764 /* This is the child process if a fork occurred. */
2765 /* Execute the command. */
2766 if (cmdentry.cmdtype == CMDFUNCTION) {
2767#ifdef DEBUG
2768 trputs("Shell function: "); trargs(argv);
2769#endif
2770 exitstatus = oexitstatus;
2771 redirect(cmd->ncmd.redirect, REDIR_PUSH);
2772 saveparam = shellparam;
2773 shellparam.malloc = 0;
2774 shellparam.nparam = argc - 1;
2775 shellparam.p = argv + 1;
2776 INTOFF;
2777 savelocalvars = localvars;
2778 localvars = NULL;
2779 INTON;
2780 if (setjmp(jmploc.loc)) {
2781 if (exception == EXSHELLPROC) {
2782 freeparam((volatile struct shparam *)
2783 &saveparam);
2784 } else {
2785 saveparam.optind = shellparam.optind;
2786 saveparam.optoff = shellparam.optoff;
2787 freeparam(&shellparam);
2788 shellparam = saveparam;
2789 }
2790 poplocalvars();
2791 localvars = savelocalvars;
2792 handler = savehandler;
2793 longjmp(handler->loc, 1);
2794 }
2795 savehandler = handler;
2796 handler = &jmploc;
2797 for (sp = varlist.list ; sp ; sp = sp->next)
2798 mklocal(sp->text);
2799 funcnest++;
2800 evaltree(cmdentry.u.func, flags & EV_TESTED);
2801 funcnest--;
2802 INTOFF;
2803 poplocalvars();
2804 localvars = savelocalvars;
2805 saveparam.optind = shellparam.optind;
2806 saveparam.optoff = shellparam.optoff;
2807 freeparam(&shellparam);
2808 shellparam = saveparam;
2809 handler = savehandler;
2810 popredir();
2811 INTON;
2812 if (evalskip == SKIPFUNC) {
2813 evalskip = 0;
2814 skipcount = 0;
2815 }
2816 if (flags & EV_EXIT)
2817 exitshell(exitstatus);
2818 } else if (cmdentry.cmdtype == CMDBUILTIN) {
2819#ifdef DEBUG
2820 trputs("builtin command: "); trargs(argv);
2821#endif
2822 mode = (cmdentry.u.cmd == EXECCMD)? 0 : REDIR_PUSH;
Eric Andersencb57d552001-06-28 07:25:16 +00002823 redirect(cmd->ncmd.redirect, mode);
2824 savecmdname = commandname;
Eric Andersen2870d962001-07-02 17:27:21 +00002825 if (IS_BUILTIN_SPECIAL(firstbltin)) {
Eric Andersencb57d552001-06-28 07:25:16 +00002826 listsetvar(varlist.list);
2827 } else {
2828 cmdenviron = varlist.list;
2829 }
2830 e = -1;
2831 if (setjmp(jmploc.loc)) {
2832 e = exception;
2833 exitstatus = (e == EXINT)? SIGINT+128 : 2;
2834 goto cmddone;
2835 }
2836 savehandler = handler;
2837 handler = &jmploc;
2838 commandname = argv[0];
2839 argptr = argv + 1;
Eric Andersen2870d962001-07-02 17:27:21 +00002840 optptr = NULL; /* initialize nextopt */
Eric Andersencb57d552001-06-28 07:25:16 +00002841 exitstatus = (*cmdentry.u.cmd->builtinfunc)(argc, argv);
2842 flushall();
2843cmddone:
Eric Andersencb57d552001-06-28 07:25:16 +00002844 cmdenviron = NULL;
2845 if (e != EXSHELLPROC) {
2846 commandname = savecmdname;
2847 if (flags & EV_EXIT)
2848 exitshell(exitstatus);
2849 }
2850 handler = savehandler;
2851 if (e != -1) {
2852 if ((e != EXERROR && e != EXEXEC)
2853 || cmdentry.u.cmd == BLTINCMD
2854 || cmdentry.u.cmd == DOTCMD
2855 || cmdentry.u.cmd == EVALCMD
2856 || cmdentry.u.cmd == EXECCMD)
2857 exraise(e);
2858 FORCEINTON;
2859 }
2860 if (cmdentry.u.cmd != EXECCMD)
2861 popredir();
Eric Andersencb57d552001-06-28 07:25:16 +00002862 } else {
2863#ifdef DEBUG
2864 trputs("normal command: "); trargs(argv);
2865#endif
2866 redirect(cmd->ncmd.redirect, 0);
2867 clearredir();
2868 for (sp = varlist.list ; sp ; sp = sp->next)
2869 setvareq(sp->text, VEXPORT|VSTACK);
2870 envp = environment();
2871 shellexec(argv, envp, path, cmdentry.u.index);
2872 }
2873 goto out;
2874
Eric Andersen2870d962001-07-02 17:27:21 +00002875parent: /* parent process gets here (if we forked) */
2876 if (mode == 0) { /* argument to fork */
Eric Andersencb57d552001-06-28 07:25:16 +00002877 INTOFF;
2878 exitstatus = waitforjob(jp);
2879 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00002880 }
2881
2882out:
2883 if (lastarg)
2884 setvar("_", lastarg, 0);
2885 popstackmark(&smark);
2886}
2887
Eric Andersen62483552001-07-10 06:09:16 +00002888/*
2889 * Evaluate a parse tree. The value is left in the global variable
2890 * exitstatus.
2891 */
2892static void
2893evaltree(n, flags)
2894 union node *n;
2895 int flags;
2896{
2897 int checkexit = 0;
2898 if (n == NULL) {
2899 TRACE(("evaltree(NULL) called\n"));
2900 goto out;
2901 }
2902 TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
2903 switch (n->type) {
2904 case NSEMI:
2905 evaltree(n->nbinary.ch1, flags & EV_TESTED);
2906 if (evalskip)
2907 goto out;
2908 evaltree(n->nbinary.ch2, flags);
2909 break;
2910 case NAND:
2911 evaltree(n->nbinary.ch1, EV_TESTED);
2912 if (evalskip || exitstatus != 0)
2913 goto out;
2914 evaltree(n->nbinary.ch2, flags);
2915 break;
2916 case NOR:
2917 evaltree(n->nbinary.ch1, EV_TESTED);
2918 if (evalskip || exitstatus == 0)
2919 goto out;
2920 evaltree(n->nbinary.ch2, flags);
2921 break;
2922 case NREDIR:
2923 expredir(n->nredir.redirect);
2924 redirect(n->nredir.redirect, REDIR_PUSH);
2925 evaltree(n->nredir.n, flags);
2926 popredir();
2927 break;
2928 case NSUBSHELL:
2929 evalsubshell(n, flags);
2930 break;
2931 case NBACKGND:
2932 evalsubshell(n, flags);
2933 break;
2934 case NIF: {
2935 evaltree(n->nif.test, EV_TESTED);
2936 if (evalskip)
2937 goto out;
2938 if (exitstatus == 0)
2939 evaltree(n->nif.ifpart, flags);
2940 else if (n->nif.elsepart)
2941 evaltree(n->nif.elsepart, flags);
2942 else
2943 exitstatus = 0;
2944 break;
2945 }
2946 case NWHILE:
2947 case NUNTIL:
2948 evalloop(n, flags);
2949 break;
2950 case NFOR:
2951 evalfor(n, flags);
2952 break;
2953 case NCASE:
2954 evalcase(n, flags);
2955 break;
2956 case NDEFUN: {
2957 struct builtincmd *bcmd;
2958 struct cmdentry entry;
2959 if (
2960 (bcmd = find_builtin(n->narg.text)) &&
2961 IS_BUILTIN_SPECIAL(bcmd)
2962 ) {
2963 out2fmt("%s is a special built-in\n", n->narg.text);
2964 exitstatus = 1;
2965 break;
2966 }
2967 entry.cmdtype = CMDFUNCTION;
2968 entry.u.func = copyfunc(n->narg.next);
2969 addcmdentry(n->narg.text, &entry);
2970 exitstatus = 0;
2971 break;
2972 }
2973 case NNOT:
2974 evaltree(n->nnot.com, EV_TESTED);
2975 exitstatus = !exitstatus;
2976 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002977
Eric Andersen62483552001-07-10 06:09:16 +00002978 case NPIPE:
2979 evalpipe(n);
2980 checkexit = 1;
2981 break;
2982 case NCMD:
2983 evalcommand(n, flags);
2984 checkexit = 1;
2985 break;
2986#ifdef DEBUG
2987 default:
2988 printf("Node type = %d\n", n->type);
2989 break;
2990#endif
2991 }
2992out:
2993 if (pendingsigs)
2994 dotrap();
2995 if (
2996 flags & EV_EXIT ||
2997 (checkexit && eflag && exitstatus && !(flags & EV_TESTED))
2998 )
2999 exitshell(exitstatus);
3000}
3001
3002/*
3003 * Kick off a subshell to evaluate a tree.
3004 */
3005
3006static void
3007evalsubshell(const union node *n, int flags)
3008{
3009 struct job *jp;
3010 int backgnd = (n->type == NBACKGND);
3011
3012 expredir(n->nredir.redirect);
3013 jp = makejob(n, 1);
3014 if (forkshell(jp, n, backgnd) == 0) {
3015 if (backgnd)
3016 flags &=~ EV_TESTED;
3017 redirect(n->nredir.redirect, 0);
3018 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
3019 }
3020 if (! backgnd) {
3021 INTOFF;
3022 exitstatus = waitforjob(jp);
3023 INTON;
3024 }
3025}
3026
3027/*
3028 * Compute the names of the files in a redirection list.
3029 */
3030
3031static void fixredir(union node *n, const char *text, int err);
3032
3033static void
3034expredir(union node *n)
3035{
3036 union node *redir;
3037
3038 for (redir = n ; redir ; redir = redir->nfile.next) {
3039 struct arglist fn;
3040 fn.lastp = &fn.list;
3041 oexitstatus = exitstatus;
3042 switch (redir->type) {
3043 case NFROMTO:
3044 case NFROM:
3045 case NTO:
3046 case NAPPEND:
3047 case NTOOV:
3048 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3049 redir->nfile.expfname = fn.list->text;
3050 break;
3051 case NFROMFD:
3052 case NTOFD:
3053 if (redir->ndup.vname) {
3054 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3055 fixredir(redir, fn.list->text, 1);
3056 }
3057 break;
3058 }
3059 }
3060}
3061
3062
3063/*
3064 * Execute a command inside back quotes. If it's a builtin command, we
3065 * want to save its output in a block obtained from malloc. Otherwise
3066 * we fork off a subprocess and get the output of the command via a pipe.
3067 * Should be called with interrupts off.
3068 */
3069
3070static void
3071evalbackcmd(union node *n, struct backcmd *result)
3072{
3073 int pip[2];
3074 struct job *jp;
3075 struct stackmark smark; /* unnecessary */
3076
3077 setstackmark(&smark);
3078 result->fd = -1;
3079 result->buf = NULL;
3080 result->nleft = 0;
3081 result->jp = NULL;
3082 if (n == NULL) {
3083 exitstatus = 0;
3084 goto out;
3085 }
3086 exitstatus = 0;
3087 if (pipe(pip) < 0)
3088 error("Pipe call failed");
3089 jp = makejob(n, 1);
3090 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3091 FORCEINTON;
3092 close(pip[0]);
3093 if (pip[1] != 1) {
3094 close(1);
3095 dup_as_newfd(pip[1], 1);
3096 close(pip[1]);
3097 }
3098 eflag = 0;
3099 evaltree(n, EV_EXIT);
3100 }
3101 close(pip[1]);
3102 result->fd = pip[0];
3103 result->jp = jp;
3104out:
3105 popstackmark(&smark);
3106 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
3107 result->fd, result->buf, result->nleft, result->jp));
3108}
3109
3110
3111/*
3112 * Execute a simple command.
3113 */
Eric Andersencb57d552001-06-28 07:25:16 +00003114
3115/*
3116 * Search for a command. This is called before we fork so that the
3117 * location of the command will be available in the parent as well as
3118 * the child. The check for "goodname" is an overly conservative
3119 * check that the name will not be subject to expansion.
3120 */
3121
3122static void
3123prehash(n)
3124 union node *n;
3125{
3126 struct cmdentry entry;
3127
3128 if (n->type == NCMD && n->ncmd.args)
3129 if (goodname(n->ncmd.args->narg.text))
3130 find_command(n->ncmd.args->narg.text, &entry, 0,
3131 pathval());
3132}
3133
3134
Eric Andersencb57d552001-06-28 07:25:16 +00003135/*
3136 * Builtin commands. Builtin commands whose functions are closely
3137 * tied to evaluation are implemented here.
3138 */
3139
3140/*
3141 * No command given, or a bltin command with no arguments. Set the
3142 * specified variables.
3143 */
3144
3145int
3146bltincmd(argc, argv)
3147 int argc;
3148 char **argv;
3149{
3150 /*
3151 * Preserve exitstatus of a previous possible redirection
3152 * as POSIX mandates
3153 */
3154 return exitstatus;
3155}
3156
3157
3158/*
3159 * Handle break and continue commands. Break, continue, and return are
3160 * all handled by setting the evalskip flag. The evaluation routines
3161 * above all check this flag, and if it is set they start skipping
3162 * commands rather than executing them. The variable skipcount is
3163 * the number of loops to break/continue, or the number of function
3164 * levels to return. (The latter is always 1.) It should probably
3165 * be an error to break out of more loops than exist, but it isn't
3166 * in the standard shell so we don't make it one here.
3167 */
3168
3169static int
3170breakcmd(argc, argv)
3171 int argc;
3172 char **argv;
3173{
3174 int n = argc > 1 ? number(argv[1]) : 1;
3175
3176 if (n > loopnest)
3177 n = loopnest;
3178 if (n > 0) {
3179 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
3180 skipcount = n;
3181 }
3182 return 0;
3183}
3184
3185
3186/*
3187 * The return command.
3188 */
3189
3190static int
3191returncmd(argc, argv)
3192 int argc;
3193 char **argv;
3194{
3195 int ret = argc > 1 ? number(argv[1]) : oexitstatus;
3196
3197 if (funcnest) {
3198 evalskip = SKIPFUNC;
3199 skipcount = 1;
3200 return ret;
3201 }
3202 else {
3203 /* Do what ksh does; skip the rest of the file */
3204 evalskip = SKIPFILE;
3205 skipcount = 1;
3206 return ret;
3207 }
3208}
3209
3210
3211#ifndef BB_TRUE_FALSE
3212static int
3213false_main(argc, argv)
3214 int argc;
3215 char **argv;
3216{
3217 return 1;
3218}
3219
3220
3221static int
3222true_main(argc, argv)
3223 int argc;
3224 char **argv;
3225{
3226 return 0;
3227}
3228#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003229
3230/*
3231 * Controls whether the shell is interactive or not.
3232 */
3233
3234static void setsignal(int signo);
3235static void chkmail(int silent);
3236
3237
3238static void
3239setinteractive(int on)
3240{
3241 static int is_interactive;
Eric Andersen1c039232001-07-07 00:05:55 +00003242 static int do_banner=0;
Eric Andersen2870d962001-07-02 17:27:21 +00003243
3244 if (on == is_interactive)
3245 return;
3246 setsignal(SIGINT);
3247 setsignal(SIGQUIT);
3248 setsignal(SIGTERM);
3249 chkmail(1);
3250 is_interactive = on;
Eric Andersen1c039232001-07-07 00:05:55 +00003251 if (do_banner==0 && is_interactive) {
3252 /* Looks like they want an interactive shell */
3253 printf( "\n\n" BB_BANNER " Built-in shell (ash)\n");
3254 printf( "Enter 'help' for a list of built-in commands.\n\n");
3255 do_banner=1;
3256 }
Eric Andersen2870d962001-07-02 17:27:21 +00003257}
3258
3259static void
3260optschanged(void)
3261{
3262 setinteractive(iflag);
3263 setjobctl(mflag);
3264}
3265
Eric Andersencb57d552001-06-28 07:25:16 +00003266
3267static int
3268execcmd(argc, argv)
3269 int argc;
3270 char **argv;
3271{
3272 if (argc > 1) {
3273 struct strlist *sp;
3274
Eric Andersen2870d962001-07-02 17:27:21 +00003275 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003276 mflag = 0;
3277 optschanged();
3278 for (sp = cmdenviron; sp ; sp = sp->next)
3279 setvareq(sp->text, VEXPORT|VSTACK);
3280 shellexec(argv + 1, environment(), pathval(), 0);
3281 }
3282 return 0;
3283}
3284
3285static void
3286eprintlist(struct strlist *sp)
3287{
3288 for (; sp; sp = sp->next) {
Eric Andersen3102ac42001-07-06 04:26:23 +00003289 out2fmt(" %s",sp->text);
Eric Andersencb57d552001-06-28 07:25:16 +00003290 }
3291}
Eric Andersencb57d552001-06-28 07:25:16 +00003292
3293/*
3294 * Exec a program. Never returns. If you change this routine, you may
3295 * have to change the find_command routine as well.
3296 */
3297
Eric Andersen2870d962001-07-02 17:27:21 +00003298static const char *pathopt; /* set by padvance */
3299
Eric Andersencb57d552001-06-28 07:25:16 +00003300static void
3301shellexec(argv, envp, path, idx)
3302 char **argv, **envp;
3303 const char *path;
3304 int idx;
3305{
3306 char *cmdname;
3307 int e;
3308
3309 if (strchr(argv[0], '/') != NULL) {
3310 tryexec(argv[0], argv, envp);
3311 e = errno;
3312 } else {
3313 e = ENOENT;
3314 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3315 if (--idx < 0 && pathopt == NULL) {
3316 tryexec(cmdname, argv, envp);
3317 if (errno != ENOENT && errno != ENOTDIR)
3318 e = errno;
3319 }
3320 stunalloc(cmdname);
3321 }
3322 }
3323
3324 /* Map to POSIX errors */
3325 switch (e) {
3326 case EACCES:
3327 exerrno = 126;
3328 break;
3329 case ENOENT:
3330 exerrno = 127;
3331 break;
3332 default:
3333 exerrno = 2;
3334 break;
3335 }
3336 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3337 /* NOTREACHED */
3338}
3339
Eric Andersen2870d962001-07-02 17:27:21 +00003340/*
3341 * Clear traps on a fork.
3342 */
3343static void
3344clear_traps(void) {
3345 char **tp;
3346
3347 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
3348 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
3349 INTOFF;
3350 ckfree(*tp);
3351 *tp = NULL;
3352 if (tp != &trap[0])
3353 setsignal(tp - trap);
3354 INTON;
3355 }
3356 }
3357}
3358
3359
3360static void
3361initshellproc(void) {
3362
3363#ifdef ASH_ALIAS
3364 /* from alias.c: */
3365 {
3366 rmaliases();
3367 }
3368#endif
3369 /* from eval.c: */
3370 {
3371 exitstatus = 0;
3372 }
3373
3374 /* from exec.c: */
3375 {
3376 deletefuncs();
3377 }
3378
3379 /* from jobs.c: */
3380 {
3381 backgndpid = -1;
3382#ifdef JOBS
3383 jobctl = 0;
3384#endif
3385 }
3386
3387 /* from options.c: */
3388 {
3389 int i;
3390
3391 for (i = 0; i < NOPTS; i++)
3392 optent_val(i) = 0;
3393 optschanged();
3394
3395 }
3396
3397 /* from redir.c: */
3398 {
3399 clearredir();
3400 }
3401
3402 /* from trap.c: */
3403 {
3404 char *sm;
3405
3406 clear_traps();
3407 for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) {
3408 if (*sm == S_IGN)
3409 *sm = S_HARD_IGN;
3410 }
3411 }
3412
3413 /* from var.c: */
3414 {
3415 shprocvar();
3416 }
3417}
3418
3419static int preadbuffer(void);
3420static void pushfile (void);
Eric Andersen2870d962001-07-02 17:27:21 +00003421
3422/*
3423 * Read a character from the script, returning PEOF on end of file.
3424 * Nul characters in the input are silently discarded.
3425 */
3426
Eric Andersen3102ac42001-07-06 04:26:23 +00003427#ifndef ASH_OPTIMIZE_FOR_SIZE
Eric Andersen2870d962001-07-02 17:27:21 +00003428#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
3429static int
3430pgetc(void)
3431{
3432 return pgetc_macro();
3433}
3434#else
3435static int
3436pgetc_macro(void)
3437{
3438 return --parsenleft >= 0? *parsenextc++ : preadbuffer();
3439}
3440
3441static inline int
3442pgetc(void)
3443{
3444 return pgetc_macro();
3445}
3446#endif
3447
3448
3449/*
3450 * Undo the last call to pgetc. Only one character may be pushed back.
3451 * PEOF may be pushed back.
3452 */
3453
Eric Andersen74400cc2001-10-18 04:11:39 +00003454static void pungetc(void)
3455{
Eric Andersen2870d962001-07-02 17:27:21 +00003456 parsenleft++;
3457 parsenextc--;
3458}
3459
3460
3461static void
3462popfile(void) {
3463 struct parsefile *pf = parsefile;
3464
3465 INTOFF;
3466 if (pf->fd >= 0)
3467 close(pf->fd);
3468 if (pf->buf)
3469 ckfree(pf->buf);
3470 while (pf->strpush)
3471 popstring();
3472 parsefile = pf->prev;
3473 ckfree(pf);
3474 parsenleft = parsefile->nleft;
3475 parselleft = parsefile->lleft;
3476 parsenextc = parsefile->nextc;
3477 plinno = parsefile->linno;
3478 INTON;
3479}
3480
3481
3482/*
3483 * Return to top level.
3484 */
3485
3486static void
3487popallfiles(void) {
3488 while (parsefile != &basepf)
3489 popfile();
3490}
3491
3492/*
3493 * Close the file(s) that the shell is reading commands from. Called
3494 * after a fork is done.
3495 */
3496
Eric Andersen74400cc2001-10-18 04:11:39 +00003497static void closescript(void)
3498{
Eric Andersen2870d962001-07-02 17:27:21 +00003499 popallfiles();
3500 if (parsefile->fd > 0) {
3501 close(parsefile->fd);
3502 parsefile->fd = 0;
3503 }
3504}
3505
3506
3507/*
3508 * Like setinputfile, but takes an open file descriptor. Call this with
3509 * interrupts off.
3510 */
3511
Eric Andersen74400cc2001-10-18 04:11:39 +00003512static void setinputfd(int fd, int push)
Eric Andersen2870d962001-07-02 17:27:21 +00003513{
3514 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
3515 if (push) {
3516 pushfile();
3517 parsefile->buf = 0;
3518 } else {
3519 closescript();
3520 while (parsefile->strpush)
3521 popstring();
3522 }
3523 parsefile->fd = fd;
3524 if (parsefile->buf == NULL)
3525 parsefile->buf = ckmalloc(BUFSIZ);
3526 parselleft = parsenleft = 0;
3527 plinno = 1;
3528}
3529
3530
3531/*
3532 * Set the input to take input from a file. If push is set, push the
3533 * old input onto the stack first.
3534 */
3535
3536static void
3537setinputfile(const char *fname, int push)
3538{
3539 int fd;
3540 int myfileno2;
3541
3542 INTOFF;
3543 if ((fd = open(fname, O_RDONLY)) < 0)
3544 error("Can't open %s", fname);
3545 if (fd < 10) {
3546 myfileno2 = dup_as_newfd(fd, 10);
3547 close(fd);
3548 if (myfileno2 < 0)
3549 error("Out of file descriptors");
3550 fd = myfileno2;
3551 }
3552 setinputfd(fd, push);
3553 INTON;
3554}
3555
Eric Andersencb57d552001-06-28 07:25:16 +00003556
3557static void
Eric Andersen62483552001-07-10 06:09:16 +00003558tryexec(char *cmd, char **argv, char **envp)
3559{
Eric Andersencb57d552001-06-28 07:25:16 +00003560 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003561
Eric Andersen3102ac42001-07-06 04:26:23 +00003562#ifdef BB_FEATURE_SH_STANDALONE_SHELL
3563 char *name = cmd;
3564 char** argv_l=argv;
3565 int argc_l;
3566#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
3567 name = get_last_path_component(name);
3568#endif
3569 argv_l=envp;
3570 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
3571 putenv(*argv_l);
3572 argv_l=argv;
Eric Andersen62483552001-07-10 06:09:16 +00003573 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
Eric Andersen3102ac42001-07-06 04:26:23 +00003574 optind = 1;
3575 run_applet_by_name(name, argc_l, argv);
3576#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003577 execve(cmd, argv, envp);
Eric Andersencb57d552001-06-28 07:25:16 +00003578 e = errno;
3579 if (e == ENOEXEC) {
3580 INTOFF;
3581 initshellproc();
3582 setinputfile(cmd, 0);
3583 commandname = arg0 = savestr(argv[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00003584 setparam(argv + 1);
3585 exraise(EXSHELLPROC);
3586 }
3587 errno = e;
3588}
3589
Eric Andersen2870d962001-07-02 17:27:21 +00003590static char *commandtext (const union node *);
Eric Andersencb57d552001-06-28 07:25:16 +00003591
3592/*
3593 * Do a path search. The variable path (passed by reference) should be
3594 * set to the start of the path before the first call; padvance will update
3595 * this value as it proceeds. Successive calls to padvance will return
3596 * the possible path expansions in sequence. If an option (indicated by
3597 * a percent sign) appears in the path entry then the global variable
3598 * pathopt will be set to point to it; otherwise pathopt will be set to
3599 * NULL.
3600 */
3601
3602static const char *pathopt;
3603
Eric Andersen2870d962001-07-02 17:27:21 +00003604static void growstackblock(void);
3605
3606
Eric Andersencb57d552001-06-28 07:25:16 +00003607static char *
Eric Andersen2870d962001-07-02 17:27:21 +00003608padvance(const char **path, const char *name)
3609{
Eric Andersencb57d552001-06-28 07:25:16 +00003610 const char *p;
3611 char *q;
3612 const char *start;
3613 int len;
3614
3615 if (*path == NULL)
3616 return NULL;
3617 start = *path;
3618 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
Eric Andersen2870d962001-07-02 17:27:21 +00003619 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003620 while (stackblocksize() < len)
3621 growstackblock();
3622 q = stackblock();
3623 if (p != start) {
3624 memcpy(q, start, p - start);
3625 q += p - start;
3626 *q++ = '/';
3627 }
3628 strcpy(q, name);
3629 pathopt = NULL;
3630 if (*p == '%') {
3631 pathopt = ++p;
3632 while (*p && *p != ':') p++;
3633 }
3634 if (*p == ':')
3635 *path = p + 1;
3636 else
3637 *path = NULL;
3638 return stalloc(len);
3639}
3640
Eric Andersen62483552001-07-10 06:09:16 +00003641/*
3642 * Wrapper around strcmp for qsort/bsearch/...
3643 */
3644static int
3645pstrcmp(const void *a, const void *b)
3646{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003647 return strcmp((const char *) a, (*(const char *const *) b) + 1);
Eric Andersen62483552001-07-10 06:09:16 +00003648}
3649
3650/*
3651 * Find a keyword is in a sorted array.
3652 */
3653
3654static const char *const *
3655findkwd(const char *s)
3656{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003657 return bsearch(s, tokname_array + KWDOFFSET,
3658 (sizeof(tokname_array)/sizeof(const char *)) - KWDOFFSET,
3659 sizeof(const char *), pstrcmp);
Eric Andersen62483552001-07-10 06:09:16 +00003660}
Eric Andersencb57d552001-06-28 07:25:16 +00003661
3662
3663/*** Command hashing code ***/
3664
3665
3666static int
3667hashcmd(argc, argv)
3668 int argc;
3669 char **argv;
3670{
3671 struct tblentry **pp;
3672 struct tblentry *cmdp;
3673 int c;
3674 int verbose;
3675 struct cmdentry entry;
3676 char *name;
Eric Andersen62483552001-07-10 06:09:16 +00003677#ifdef ASH_ALIAS
3678 const struct alias *ap;
3679#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003680
3681 verbose = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003682 while ((c = nextopt("rvV")) != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00003683 if (c == 'r') {
3684 clearcmdentry(0);
3685 return 0;
Eric Andersen62483552001-07-10 06:09:16 +00003686 } else if (c == 'v' || c == 'V') {
3687 verbose = c;
Eric Andersencb57d552001-06-28 07:25:16 +00003688 }
3689 }
3690 if (*argptr == NULL) {
3691 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3692 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3693 if (cmdp->cmdtype != CMDBUILTIN) {
3694 printentry(cmdp, verbose);
3695 }
3696 }
3697 }
3698 return 0;
3699 }
3700 c = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003701 while ((name = *argptr++) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00003702 if ((cmdp = cmdlookup(name, 0)) != NULL
3703 && (cmdp->cmdtype == CMDNORMAL
3704 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3705 delete_cmd_entry();
Eric Andersen62483552001-07-10 06:09:16 +00003706#ifdef ASH_ALIAS
3707 /* Then look at the aliases */
3708 if ((ap = lookupalias(name, 0)) != NULL) {
3709 if (verbose=='v')
3710 printf("%s is an alias for %s\n", name, ap->val);
3711 else
3712 printalias(ap);
3713 continue;
3714 }
3715#endif
3716 /* First look at the keywords */
3717 if (findkwd(name)!=0) {
3718 if (verbose=='v')
3719 printf("%s is a shell keyword\n", name);
3720 else
3721 printf(snlfmt, name);
3722 continue;
3723 }
3724
Eric Andersencb57d552001-06-28 07:25:16 +00003725 find_command(name, &entry, DO_ERR, pathval());
3726 if (entry.cmdtype == CMDUNKNOWN) c = 1;
3727 else if (verbose) {
3728 cmdp = cmdlookup(name, 0);
Eric Andersen62483552001-07-10 06:09:16 +00003729 if (cmdp) printentry(cmdp, verbose=='v');
Eric Andersencb57d552001-06-28 07:25:16 +00003730 flushall();
3731 }
Eric Andersencb57d552001-06-28 07:25:16 +00003732 }
3733 return c;
3734}
3735
Eric Andersencb57d552001-06-28 07:25:16 +00003736static void
3737printentry(cmdp, verbose)
3738 struct tblentry *cmdp;
3739 int verbose;
3740 {
3741 int idx;
3742 const char *path;
3743 char *name;
3744
Eric Andersen62483552001-07-10 06:09:16 +00003745 printf("%s%s", cmdp->cmdname, (verbose ? " is " : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00003746 if (cmdp->cmdtype == CMDNORMAL) {
3747 idx = cmdp->param.index;
3748 path = pathval();
3749 do {
3750 name = padvance(&path, cmdp->cmdname);
3751 stunalloc(name);
3752 } while (--idx >= 0);
Eric Andersen62483552001-07-10 06:09:16 +00003753 if(verbose)
3754 out1str(name);
Eric Andersencb57d552001-06-28 07:25:16 +00003755 } else if (cmdp->cmdtype == CMDBUILTIN) {
Eric Andersen62483552001-07-10 06:09:16 +00003756 if(verbose)
3757 out1str("a shell builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00003758 } else if (cmdp->cmdtype == CMDFUNCTION) {
Eric Andersencb57d552001-06-28 07:25:16 +00003759 if (verbose) {
3760 INTOFF;
Eric Andersen62483552001-07-10 06:09:16 +00003761 out1str("a function\n");
Eric Andersencb57d552001-06-28 07:25:16 +00003762 name = commandtext(cmdp->param.func);
Eric Andersen62483552001-07-10 06:09:16 +00003763 printf("%s() {\n %s\n}", cmdp->cmdname, name);
Eric Andersencb57d552001-06-28 07:25:16 +00003764 ckfree(name);
3765 INTON;
3766 }
3767#ifdef DEBUG
3768 } else {
3769 error("internal error: cmdtype %d", cmdp->cmdtype);
3770#endif
3771 }
Eric Andersen62483552001-07-10 06:09:16 +00003772 printf(snlfmt, cmdp->rehash ? "*" : nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +00003773}
3774
3775
3776
Eric Andersen1c039232001-07-07 00:05:55 +00003777/*** List the available builtins ***/
3778
3779
3780static int helpcmd(int argc, char** argv)
3781{
3782 int col, i;
Eric Andersen1c039232001-07-07 00:05:55 +00003783
Eric Andersen62483552001-07-10 06:09:16 +00003784 printf("\nBuilt-in commands:\n-------------------\n");
3785 for (col=0, i=0; i < NUMBUILTINS; i++) {
3786 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3787 builtincmds[i].name+1);
Eric Andersen1c039232001-07-07 00:05:55 +00003788 if (col > 60) {
3789 printf("\n");
3790 col = 0;
3791 }
3792 }
3793#ifdef BB_FEATURE_SH_STANDALONE_SHELL
3794 {
Eric Andersen1c039232001-07-07 00:05:55 +00003795 extern const struct BB_applet applets[];
3796 extern const size_t NUM_APPLETS;
3797
Eric Andersen62483552001-07-10 06:09:16 +00003798 for (i=0; i < NUM_APPLETS; i++) {
3799
3800 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3801 applets[i].name);
Eric Andersen1c039232001-07-07 00:05:55 +00003802 if (col > 60) {
3803 printf("\n");
3804 col = 0;
3805 }
3806 }
3807 }
3808#endif
3809 printf("\n\n");
3810 return EXIT_SUCCESS;
3811}
3812
Eric Andersencb57d552001-06-28 07:25:16 +00003813/*
3814 * Resolve a command name. If you change this routine, you may have to
3815 * change the shellexec routine as well.
3816 */
3817
Eric Andersen2870d962001-07-02 17:27:21 +00003818static int prefix (const char *, const char *);
3819
Eric Andersencb57d552001-06-28 07:25:16 +00003820static void
Eric Andersen2870d962001-07-02 17:27:21 +00003821find_command(const char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003822{
3823 struct tblentry *cmdp;
3824 int idx;
3825 int prev;
3826 char *fullname;
3827 struct stat statb;
3828 int e;
3829 int bltin;
3830 int firstchange;
3831 int updatetbl;
Eric Andersen62483552001-07-10 06:09:16 +00003832 int regular;
Eric Andersencb57d552001-06-28 07:25:16 +00003833 struct builtincmd *bcmd;
3834
3835 /* If name contains a slash, don't use the hash table */
3836 if (strchr(name, '/') != NULL) {
3837 if (act & DO_ABS) {
3838 while (stat(name, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003839 if (errno != ENOENT && errno != ENOTDIR)
3840 e = errno;
3841 entry->cmdtype = CMDUNKNOWN;
3842 entry->u.index = -1;
3843 return;
3844 }
3845 entry->cmdtype = CMDNORMAL;
3846 entry->u.index = -1;
3847 return;
3848 }
3849 entry->cmdtype = CMDNORMAL;
3850 entry->u.index = 0;
3851 return;
3852 }
3853
3854 updatetbl = 1;
3855 if (act & DO_BRUTE) {
3856 firstchange = path_change(path, &bltin);
3857 } else {
3858 bltin = builtinloc;
3859 firstchange = 9999;
3860 }
3861
3862 /* If name is in the table, and not invalidated by cd, we're done */
3863 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
3864 if (cmdp->cmdtype == CMDFUNCTION) {
3865 if (act & DO_NOFUN) {
3866 updatetbl = 0;
3867 } else {
3868 goto success;
3869 }
3870 } else if (act & DO_BRUTE) {
3871 if ((cmdp->cmdtype == CMDNORMAL &&
3872 cmdp->param.index >= firstchange) ||
3873 (cmdp->cmdtype == CMDBUILTIN &&
3874 ((builtinloc < 0 && bltin >= 0) ?
3875 bltin : builtinloc) >= firstchange)) {
3876 /* need to recompute the entry */
3877 } else {
3878 goto success;
3879 }
3880 } else {
3881 goto success;
3882 }
3883 }
3884
3885 bcmd = find_builtin(name);
Eric Andersen2870d962001-07-02 17:27:21 +00003886 regular = bcmd && IS_BUILTIN_REGULAR(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00003887
3888 if (regular) {
3889 if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) {
Eric Andersen2870d962001-07-02 17:27:21 +00003890 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003891 }
3892 } else if (act & DO_BRUTE) {
3893 if (firstchange == 0) {
3894 updatetbl = 0;
3895 }
3896 }
3897
3898 /* If %builtin not in path, check for builtin next */
3899 if (regular || (bltin < 0 && bcmd)) {
3900builtin:
3901 if (!updatetbl) {
3902 entry->cmdtype = CMDBUILTIN;
3903 entry->u.cmd = bcmd;
3904 return;
3905 }
3906 INTOFF;
3907 cmdp = cmdlookup(name, 1);
3908 cmdp->cmdtype = CMDBUILTIN;
3909 cmdp->param.cmd = bcmd;
3910 INTON;
3911 goto success;
3912 }
3913
3914 /* We have to search path. */
Eric Andersen2870d962001-07-02 17:27:21 +00003915 prev = -1; /* where to start */
3916 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00003917 if (cmdp->cmdtype == CMDBUILTIN)
3918 prev = builtinloc;
3919 else
3920 prev = cmdp->param.index;
3921 }
3922
3923 e = ENOENT;
3924 idx = -1;
3925loop:
3926 while ((fullname = padvance(&path, name)) != NULL) {
3927 stunalloc(fullname);
3928 idx++;
3929 if (idx >= firstchange) {
3930 updatetbl = 0;
3931 }
3932 if (pathopt) {
3933 if (prefix("builtin", pathopt)) {
3934 if ((bcmd = find_builtin(name))) {
3935 goto builtin;
3936 }
3937 continue;
3938 } else if (!(act & DO_NOFUN) &&
3939 prefix("func", pathopt)) {
3940 /* handled below */
3941 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00003942 continue; /* ignore unimplemented options */
Eric Andersencb57d552001-06-28 07:25:16 +00003943 }
3944 }
3945 /* if rehash, don't redo absolute path names */
3946 if (fullname[0] == '/' && idx <= prev &&
3947 idx < firstchange) {
3948 if (idx < prev)
3949 continue;
3950 TRACE(("searchexec \"%s\": no change\n", name));
3951 goto success;
3952 }
3953 while (stat(fullname, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003954 if (errno != ENOENT && errno != ENOTDIR)
3955 e = errno;
3956 goto loop;
3957 }
Eric Andersen2870d962001-07-02 17:27:21 +00003958 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00003959 if (!S_ISREG(statb.st_mode))
3960 continue;
Eric Andersen2870d962001-07-02 17:27:21 +00003961 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00003962 stalloc(strlen(fullname) + 1);
3963 readcmdfile(fullname);
3964 if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
3965 error("%s not defined in %s", name, fullname);
3966 stunalloc(fullname);
3967 goto success;
3968 }
Eric Andersencb57d552001-06-28 07:25:16 +00003969 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
3970 /* If we aren't called with DO_BRUTE and cmdp is set, it must
3971 be a function and we're being called with DO_NOFUN */
3972 if (!updatetbl) {
3973 entry->cmdtype = CMDNORMAL;
3974 entry->u.index = idx;
3975 return;
3976 }
3977 INTOFF;
3978 cmdp = cmdlookup(name, 1);
3979 cmdp->cmdtype = CMDNORMAL;
3980 cmdp->param.index = idx;
3981 INTON;
3982 goto success;
3983 }
3984
3985 /* We failed. If there was an entry for this command, delete it */
3986 if (cmdp && updatetbl)
3987 delete_cmd_entry();
3988 if (act & DO_ERR)
Eric Andersen3102ac42001-07-06 04:26:23 +00003989 out2fmt("%s: %s\n", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00003990 entry->cmdtype = CMDUNKNOWN;
3991 return;
3992
3993success:
3994 cmdp->rehash = 0;
3995 entry->cmdtype = cmdp->cmdtype;
3996 entry->u = cmdp->param;
3997}
3998
3999
4000
4001/*
4002 * Search the table of builtin commands.
4003 */
4004
Eric Andersen2870d962001-07-02 17:27:21 +00004005static int
4006bstrcmp(const void *name, const void *b)
4007{
4008 return strcmp((const char *)name, (*(const char *const *) b)+1);
4009}
4010
4011static struct builtincmd *
4012find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00004013{
4014 struct builtincmd *bp;
4015
Eric Andersen2870d962001-07-02 17:27:21 +00004016 bp = bsearch(name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd),
4017 bstrcmp
Eric Andersencb57d552001-06-28 07:25:16 +00004018 );
4019 return bp;
4020}
4021
4022
4023/*
4024 * Called when a cd is done. Marks all commands so the next time they
4025 * are executed they will be rehashed.
4026 */
4027
4028static void
Eric Andersen2870d962001-07-02 17:27:21 +00004029hashcd(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00004030 struct tblentry **pp;
4031 struct tblentry *cmdp;
4032
4033 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4034 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4035 if (cmdp->cmdtype == CMDNORMAL
4036 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
4037 cmdp->rehash = 1;
4038 }
4039 }
4040}
4041
4042
4043
4044/*
4045 * Called before PATH is changed. The argument is the new value of PATH;
4046 * pathval() still returns the old value at this point. Called with
4047 * interrupts off.
4048 */
4049
4050static void
Eric Andersen2870d962001-07-02 17:27:21 +00004051changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00004052{
4053 int firstchange;
4054 int bltin;
4055
4056 firstchange = path_change(newval, &bltin);
4057 if (builtinloc < 0 && bltin >= 0)
Eric Andersen2870d962001-07-02 17:27:21 +00004058 builtinloc = bltin; /* zap builtins */
Eric Andersencb57d552001-06-28 07:25:16 +00004059 clearcmdentry(firstchange);
4060 builtinloc = bltin;
4061}
4062
4063
4064/*
4065 * Clear out command entries. The argument specifies the first entry in
4066 * PATH which has changed.
4067 */
4068
4069static void
4070clearcmdentry(firstchange)
4071 int firstchange;
4072{
4073 struct tblentry **tblp;
4074 struct tblentry **pp;
4075 struct tblentry *cmdp;
4076
4077 INTOFF;
4078 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4079 pp = tblp;
4080 while ((cmdp = *pp) != NULL) {
4081 if ((cmdp->cmdtype == CMDNORMAL &&
4082 cmdp->param.index >= firstchange)
4083 || (cmdp->cmdtype == CMDBUILTIN &&
4084 builtinloc >= firstchange)) {
4085 *pp = cmdp->next;
4086 ckfree(cmdp);
4087 } else {
4088 pp = &cmdp->next;
4089 }
4090 }
4091 }
4092 INTON;
4093}
4094
4095
4096/*
4097 * Delete all functions.
4098 */
4099
Eric Andersencb57d552001-06-28 07:25:16 +00004100static void
Eric Andersen2870d962001-07-02 17:27:21 +00004101deletefuncs(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00004102 struct tblentry **tblp;
4103 struct tblentry **pp;
4104 struct tblentry *cmdp;
4105
4106 INTOFF;
4107 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4108 pp = tblp;
4109 while ((cmdp = *pp) != NULL) {
4110 if (cmdp->cmdtype == CMDFUNCTION) {
4111 *pp = cmdp->next;
4112 freefunc(cmdp->param.func);
4113 ckfree(cmdp);
4114 } else {
4115 pp = &cmdp->next;
4116 }
4117 }
4118 }
4119 INTON;
4120}
4121
4122
4123
4124/*
4125 * Locate a command in the command hash table. If "add" is nonzero,
4126 * add the command to the table if it is not already present. The
4127 * variable "lastcmdentry" is set to point to the address of the link
4128 * pointing to the entry, so that delete_cmd_entry can delete the
4129 * entry.
4130 */
4131
Eric Andersen2870d962001-07-02 17:27:21 +00004132static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00004133
4134static struct tblentry *
Eric Andersen2870d962001-07-02 17:27:21 +00004135cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00004136{
4137 int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00004138 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00004139 struct tblentry *cmdp;
4140 struct tblentry **pp;
4141
4142 p = name;
4143 hashval = *p << 4;
4144 while (*p)
4145 hashval += *p++;
4146 hashval &= 0x7FFF;
4147 pp = &cmdtable[hashval % CMDTABLESIZE];
4148 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4149 if (equal(cmdp->cmdname, name))
4150 break;
4151 pp = &cmdp->next;
4152 }
4153 if (add && cmdp == NULL) {
4154 INTOFF;
4155 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4156 + strlen(name) + 1);
4157 cmdp->next = NULL;
4158 cmdp->cmdtype = CMDUNKNOWN;
4159 cmdp->rehash = 0;
4160 strcpy(cmdp->cmdname, name);
4161 INTON;
4162 }
4163 lastcmdentry = pp;
4164 return cmdp;
4165}
4166
4167/*
4168 * Delete the command entry returned on the last lookup.
4169 */
4170
4171static void
4172delete_cmd_entry() {
4173 struct tblentry *cmdp;
4174
4175 INTOFF;
4176 cmdp = *lastcmdentry;
4177 *lastcmdentry = cmdp->next;
4178 ckfree(cmdp);
4179 INTON;
4180}
4181
4182
4183
Eric Andersencb57d552001-06-28 07:25:16 +00004184
4185
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004186static const unsigned char nodesize[26] = {
Eric Andersen62483552001-07-10 06:09:16 +00004187 ALIGN(sizeof (struct nbinary)),
4188 ALIGN(sizeof (struct ncmd)),
4189 ALIGN(sizeof (struct npipe)),
4190 ALIGN(sizeof (struct nredir)),
4191 ALIGN(sizeof (struct nredir)),
4192 ALIGN(sizeof (struct nredir)),
4193 ALIGN(sizeof (struct nbinary)),
4194 ALIGN(sizeof (struct nbinary)),
4195 ALIGN(sizeof (struct nif)),
4196 ALIGN(sizeof (struct nbinary)),
4197 ALIGN(sizeof (struct nbinary)),
4198 ALIGN(sizeof (struct nfor)),
4199 ALIGN(sizeof (struct ncase)),
4200 ALIGN(sizeof (struct nclist)),
4201 ALIGN(sizeof (struct narg)),
4202 ALIGN(sizeof (struct narg)),
4203 ALIGN(sizeof (struct nfile)),
4204 ALIGN(sizeof (struct nfile)),
4205 ALIGN(sizeof (struct nfile)),
4206 ALIGN(sizeof (struct nfile)),
4207 ALIGN(sizeof (struct nfile)),
4208 ALIGN(sizeof (struct ndup)),
4209 ALIGN(sizeof (struct ndup)),
4210 ALIGN(sizeof (struct nhere)),
4211 ALIGN(sizeof (struct nhere)),
4212 ALIGN(sizeof (struct nnot)),
4213};
Eric Andersencb57d552001-06-28 07:25:16 +00004214
Eric Andersencb57d552001-06-28 07:25:16 +00004215
4216
4217/*
4218 * Delete a function if it exists.
4219 */
4220
4221static void
Eric Andersen2870d962001-07-02 17:27:21 +00004222unsetfunc(char *name)
4223{
Eric Andersencb57d552001-06-28 07:25:16 +00004224 struct tblentry *cmdp;
4225
4226 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
4227 freefunc(cmdp->param.func);
4228 delete_cmd_entry();
4229 }
4230}
4231
Eric Andersen2870d962001-07-02 17:27:21 +00004232
4233/*
Eric Andersencb57d552001-06-28 07:25:16 +00004234 * Locate and print what a word is...
4235 */
4236
4237static int
Eric Andersen62483552001-07-10 06:09:16 +00004238typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004239{
4240 int i;
4241 int err = 0;
Eric Andersen62483552001-07-10 06:09:16 +00004242 char *argv_a[2];
4243
4244 argv_a[1] = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004245
4246 for (i = 1; i < argc; i++) {
Eric Andersen62483552001-07-10 06:09:16 +00004247 argv_a[0] = argv[i];
4248 argptr = argv_a;
4249 optptr = "v";
4250 err |= hashcmd(argc, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00004251 }
4252 return err;
4253}
4254
Eric Andersen2870d962001-07-02 17:27:21 +00004255#ifdef ASH_CMDCMD
Eric Andersencb57d552001-06-28 07:25:16 +00004256static int
4257commandcmd(argc, argv)
4258 int argc;
4259 char **argv;
4260{
4261 int c;
4262 int default_path = 0;
4263 int verify_only = 0;
4264 int verbose_verify_only = 0;
4265
4266 while ((c = nextopt("pvV")) != '\0')
4267 switch (c) {
4268 case 'p':
4269 default_path = 1;
4270 break;
4271 case 'v':
4272 verify_only = 1;
4273 break;
4274 case 'V':
4275 verbose_verify_only = 1;
4276 break;
Eric Andersencb57d552001-06-28 07:25:16 +00004277 }
4278
4279 if (default_path + verify_only + verbose_verify_only > 1 ||
4280 !*argptr) {
Eric Andersen62483552001-07-10 06:09:16 +00004281 out2str(
4282 "command [-p] command [arg ...]\n"
4283 "command {-v|-V} command\n");
Eric Andersencb57d552001-06-28 07:25:16 +00004284 return EX_USAGE;
4285 }
4286
Eric Andersencb57d552001-06-28 07:25:16 +00004287 if (verify_only || verbose_verify_only) {
Eric Andersen62483552001-07-10 06:09:16 +00004288 char *argv_a[2];
4289
4290 argv_a[1] = 0;
4291 argv_a[0] = *argptr;
4292 argptr = argv_a;
4293 optptr = verbose_verify_only ? "v" : "V"; /* reverse special */
4294 return hashcmd(argc, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00004295 }
Eric Andersencb57d552001-06-28 07:25:16 +00004296
4297 return 0;
4298}
Eric Andersen2870d962001-07-02 17:27:21 +00004299#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004300
4301static int
4302path_change(newval, bltin)
4303 const char *newval;
4304 int *bltin;
4305{
4306 const char *old, *new;
4307 int idx;
4308 int firstchange;
4309
4310 old = pathval();
4311 new = newval;
Eric Andersen2870d962001-07-02 17:27:21 +00004312 firstchange = 9999; /* assume no change */
Eric Andersencb57d552001-06-28 07:25:16 +00004313 idx = 0;
4314 *bltin = -1;
4315 for (;;) {
4316 if (*old != *new) {
4317 firstchange = idx;
4318 if ((*old == '\0' && *new == ':')
4319 || (*old == ':' && *new == '\0'))
4320 firstchange++;
Eric Andersen2870d962001-07-02 17:27:21 +00004321 old = new; /* ignore subsequent differences */
Eric Andersencb57d552001-06-28 07:25:16 +00004322 }
4323 if (*new == '\0')
4324 break;
4325 if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1))
4326 *bltin = idx;
4327 if (*new == ':') {
4328 idx++;
4329 }
4330 new++, old++;
4331 }
4332 if (builtinloc >= 0 && *bltin < 0)
4333 firstchange = 0;
4334 return firstchange;
4335}
Eric Andersencb57d552001-06-28 07:25:16 +00004336/*
4337 * Routines to expand arguments to commands. We have to deal with
4338 * backquotes, shell variables, and file metacharacters.
4339 */
4340/*
4341 * _rmescape() flags
4342 */
Eric Andersen2870d962001-07-02 17:27:21 +00004343#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4344#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Eric Andersencb57d552001-06-28 07:25:16 +00004345
4346/*
4347 * Structure specifying which parts of the string should be searched
4348 * for IFS characters.
4349 */
4350
4351struct ifsregion {
Eric Andersen2870d962001-07-02 17:27:21 +00004352 struct ifsregion *next; /* next region in list */
4353 int begoff; /* offset of start of region */
4354 int endoff; /* offset of end of region */
4355 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004356};
4357
4358
Eric Andersen2870d962001-07-02 17:27:21 +00004359static char *expdest; /* output of current string */
4360static struct nodelist *argbackq; /* list of back quote expressions */
4361static struct ifsregion ifsfirst; /* first struct in list of ifs regions */
4362static struct ifsregion *ifslastp; /* last struct in list */
4363static struct arglist exparg; /* holds expanded arg list */
Eric Andersencb57d552001-06-28 07:25:16 +00004364
Eric Andersen2870d962001-07-02 17:27:21 +00004365static void argstr (char *, int);
4366static char *exptilde (char *, int);
4367static void expbackq (union node *, int, int);
4368static int subevalvar (char *, char *, int, int, int, int, int);
Eric Andersen2870d962001-07-02 17:27:21 +00004369static int varisset (char *, int);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004370static void strtodest (const char *, int, int);
Eric Andersen2870d962001-07-02 17:27:21 +00004371static void varvalue (char *, int, int);
4372static void recordregion (int, int, int);
4373static void removerecordregions (int);
4374static void ifsbreakup (char *, struct arglist *);
4375static void ifsfree (void);
4376static void expandmeta (struct strlist *, int);
Eric Andersen62483552001-07-10 06:09:16 +00004377#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00004378#define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB)
4379#if !defined(GLOB_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00004380static void addglob (const glob_t *);
Eric Andersencb57d552001-06-28 07:25:16 +00004381#endif
4382#endif
Eric Andersen62483552001-07-10 06:09:16 +00004383#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersen2870d962001-07-02 17:27:21 +00004384static void expmeta (char *, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004385#endif
Eric Andersen62483552001-07-10 06:09:16 +00004386#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersen2870d962001-07-02 17:27:21 +00004387static struct strlist *expsort (struct strlist *);
4388static struct strlist *msort (struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004389#endif
Eric Andersen2870d962001-07-02 17:27:21 +00004390static int patmatch (char *, char *, int);
Eric Andersen62483552001-07-10 06:09:16 +00004391#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00004392static int patmatch2 (char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004393#else
Eric Andersen2870d962001-07-02 17:27:21 +00004394static int pmatch (char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004395#define patmatch2 patmatch
4396#endif
Eric Andersen2870d962001-07-02 17:27:21 +00004397static char *cvtnum (int, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004398
4399/*
4400 * Expand shell variables and backquotes inside a here document.
4401 */
4402
Eric Andersen2870d962001-07-02 17:27:21 +00004403/* arg: the document, fd: where to write the expanded version */
Eric Andersen62483552001-07-10 06:09:16 +00004404static inline void
Eric Andersen2870d962001-07-02 17:27:21 +00004405expandhere(union node *arg, int fd)
4406{
Eric Andersencb57d552001-06-28 07:25:16 +00004407 herefd = fd;
4408 expandarg(arg, (struct arglist *)NULL, 0);
4409 xwrite(fd, stackblock(), expdest - stackblock());
4410}
4411
4412
4413/*
4414 * Perform variable substitution and command substitution on an argument,
4415 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4416 * perform splitting and file name expansion. When arglist is NULL, perform
4417 * here document expansion.
4418 */
4419
4420static void
4421expandarg(arg, arglist, flag)
4422 union node *arg;
4423 struct arglist *arglist;
4424 int flag;
4425{
4426 struct strlist *sp;
4427 char *p;
4428
4429 argbackq = arg->narg.backquote;
4430 STARTSTACKSTR(expdest);
4431 ifsfirst.next = NULL;
4432 ifslastp = NULL;
4433 argstr(arg->narg.text, flag);
4434 if (arglist == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00004435 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004436 }
4437 STPUTC('\0', expdest);
4438 p = grabstackstr(expdest);
4439 exparg.lastp = &exparg.list;
4440 /*
4441 * TODO - EXP_REDIR
4442 */
4443 if (flag & EXP_FULL) {
4444 ifsbreakup(p, &exparg);
4445 *exparg.lastp = NULL;
4446 exparg.lastp = &exparg.list;
4447 expandmeta(exparg.list, flag);
4448 } else {
4449 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4450 rmescapes(p);
4451 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4452 sp->text = p;
4453 *exparg.lastp = sp;
4454 exparg.lastp = &sp->next;
4455 }
4456 ifsfree();
4457 *exparg.lastp = NULL;
4458 if (exparg.list) {
4459 *arglist->lastp = exparg.list;
4460 arglist->lastp = exparg.lastp;
4461 }
4462}
4463
4464
Eric Andersen62483552001-07-10 06:09:16 +00004465/*
4466 * Expand a variable, and return a pointer to the next character in the
4467 * input string.
4468 */
4469
Eric Andersen74400cc2001-10-18 04:11:39 +00004470static inline char * evalvar(char *p, int flag)
Eric Andersen62483552001-07-10 06:09:16 +00004471{
4472 int subtype;
4473 int varflags;
4474 char *var;
4475 const char *val;
4476 int patloc;
4477 int c;
4478 int set;
4479 int special;
4480 int startloc;
4481 int varlen;
4482 int easy;
4483 int quotes = flag & (EXP_FULL | EXP_CASE);
4484
4485 varflags = *p++;
4486 subtype = varflags & VSTYPE;
4487 var = p;
4488 special = 0;
4489 if (! is_name(*p))
4490 special = 1;
4491 p = strchr(p, '=') + 1;
4492again: /* jump here after setting a variable with ${var=text} */
4493 if (special) {
4494 set = varisset(var, varflags & VSNUL);
4495 val = NULL;
4496 } else {
4497 val = lookupvar(var);
4498 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
4499 val = NULL;
4500 set = 0;
4501 } else
4502 set = 1;
4503 }
4504 varlen = 0;
4505 startloc = expdest - stackblock();
4506 if (set && subtype != VSPLUS) {
4507 /* insert the value of the variable */
4508 if (special) {
4509 varvalue(var, varflags & VSQUOTE, flag);
4510 if (subtype == VSLENGTH) {
4511 varlen = expdest - stackblock() - startloc;
4512 STADJUST(-varlen, expdest);
4513 }
4514 } else {
4515 if (subtype == VSLENGTH) {
4516 varlen = strlen(val);
4517 } else {
4518 strtodest(
4519 val,
4520 varflags & VSQUOTE ?
4521 DQSYNTAX : BASESYNTAX,
4522 quotes
4523 );
4524 }
4525 }
4526 }
4527
4528 if (subtype == VSPLUS)
4529 set = ! set;
4530
4531 easy = ((varflags & VSQUOTE) == 0 ||
4532 (*var == '@' && shellparam.nparam != 1));
4533
4534
4535 switch (subtype) {
4536 case VSLENGTH:
4537 expdest = cvtnum(varlen, expdest);
4538 goto record;
4539
4540 case VSNORMAL:
4541 if (!easy)
4542 break;
4543record:
4544 recordregion(startloc, expdest - stackblock(),
4545 varflags & VSQUOTE);
4546 break;
4547
4548 case VSPLUS:
4549 case VSMINUS:
4550 if (!set) {
4551 argstr(p, flag);
4552 break;
4553 }
4554 if (easy)
4555 goto record;
4556 break;
4557
4558 case VSTRIMLEFT:
4559 case VSTRIMLEFTMAX:
4560 case VSTRIMRIGHT:
4561 case VSTRIMRIGHTMAX:
4562 if (!set)
4563 break;
4564 /*
4565 * Terminate the string and start recording the pattern
4566 * right after it
4567 */
4568 STPUTC('\0', expdest);
4569 patloc = expdest - stackblock();
4570 if (subevalvar(p, NULL, patloc, subtype,
4571 startloc, varflags, quotes) == 0) {
4572 int amount = (expdest - stackblock() - patloc) + 1;
4573 STADJUST(-amount, expdest);
4574 }
4575 /* Remove any recorded regions beyond start of variable */
4576 removerecordregions(startloc);
4577 goto record;
4578
4579 case VSASSIGN:
4580 case VSQUESTION:
4581 if (!set) {
4582 if (subevalvar(p, var, 0, subtype, startloc,
4583 varflags, quotes)) {
4584 varflags &= ~VSNUL;
4585 /*
4586 * Remove any recorded regions beyond
4587 * start of variable
4588 */
4589 removerecordregions(startloc);
4590 goto again;
4591 }
4592 break;
4593 }
4594 if (easy)
4595 goto record;
4596 break;
4597
4598#ifdef DEBUG
4599 default:
4600 abort();
4601#endif
4602 }
4603
4604 if (subtype != VSNORMAL) { /* skip to end of alternative */
4605 int nesting = 1;
4606 for (;;) {
4607 if ((c = *p++) == CTLESC)
4608 p++;
4609 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
4610 if (set)
4611 argbackq = argbackq->next;
4612 } else if (c == CTLVAR) {
4613 if ((*p++ & VSTYPE) != VSNORMAL)
4614 nesting++;
4615 } else if (c == CTLENDVAR) {
4616 if (--nesting == 0)
4617 break;
4618 }
4619 }
4620 }
4621 return p;
4622}
4623
Eric Andersencb57d552001-06-28 07:25:16 +00004624
4625/*
4626 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4627 * characters to allow for further processing. Otherwise treat
4628 * $@ like $* since no splitting will be performed.
4629 */
4630
4631static void
4632argstr(p, flag)
4633 char *p;
4634 int flag;
4635{
4636 char c;
Eric Andersen2870d962001-07-02 17:27:21 +00004637 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
Eric Andersencb57d552001-06-28 07:25:16 +00004638 int firsteq = 1;
4639
4640 if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
4641 p = exptilde(p, flag);
4642 for (;;) {
4643 switch (c = *p++) {
4644 case '\0':
4645 case CTLENDVAR: /* ??? */
4646 goto breakloop;
4647 case CTLQUOTEMARK:
4648 /* "$@" syntax adherence hack */
4649 if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
4650 break;
4651 if ((flag & EXP_FULL) != 0)
4652 STPUTC(c, expdest);
4653 break;
4654 case CTLESC:
4655 if (quotes)
4656 STPUTC(c, expdest);
4657 c = *p++;
4658 STPUTC(c, expdest);
4659 break;
4660 case CTLVAR:
4661 p = evalvar(p, flag);
4662 break;
4663 case CTLBACKQ:
4664 case CTLBACKQ|CTLQUOTE:
4665 expbackq(argbackq->n, c & CTLQUOTE, flag);
4666 argbackq = argbackq->next;
4667 break;
4668#ifdef ASH_MATH_SUPPORT
4669 case CTLENDARI:
4670 expari(flag);
4671 break;
Eric Andersen2870d962001-07-02 17:27:21 +00004672#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004673 case ':':
4674 case '=':
4675 /*
4676 * sort of a hack - expand tildes in variable
4677 * assignments (after the first '=' and after ':'s).
4678 */
4679 STPUTC(c, expdest);
4680 if (flag & EXP_VARTILDE && *p == '~') {
4681 if (c == '=') {
4682 if (firsteq)
4683 firsteq = 0;
4684 else
4685 break;
4686 }
4687 p = exptilde(p, flag);
4688 }
4689 break;
4690 default:
4691 STPUTC(c, expdest);
4692 }
4693 }
4694breakloop:;
4695 return;
4696}
4697
4698static char *
4699exptilde(p, flag)
4700 char *p;
4701 int flag;
4702{
4703 char c, *startp = p;
4704 struct passwd *pw;
4705 const char *home;
4706 int quotes = flag & (EXP_FULL | EXP_CASE);
4707
4708 while ((c = *p) != '\0') {
4709 switch(c) {
4710 case CTLESC:
4711 return (startp);
4712 case CTLQUOTEMARK:
4713 return (startp);
4714 case ':':
4715 if (flag & EXP_VARTILDE)
4716 goto done;
4717 break;
4718 case '/':
4719 goto done;
4720 }
4721 p++;
4722 }
4723done:
4724 *p = '\0';
4725 if (*(startp+1) == '\0') {
4726 if ((home = lookupvar("HOME")) == NULL)
4727 goto lose;
4728 } else {
4729 if ((pw = getpwnam(startp+1)) == NULL)
4730 goto lose;
4731 home = pw->pw_dir;
4732 }
4733 if (*home == '\0')
4734 goto lose;
4735 *p = c;
4736 strtodest(home, SQSYNTAX, quotes);
4737 return (p);
4738lose:
4739 *p = c;
4740 return (startp);
4741}
4742
4743
Eric Andersen2870d962001-07-02 17:27:21 +00004744static void
4745removerecordregions(int endoff)
Eric Andersencb57d552001-06-28 07:25:16 +00004746{
4747 if (ifslastp == NULL)
4748 return;
4749
4750 if (ifsfirst.endoff > endoff) {
4751 while (ifsfirst.next != NULL) {
4752 struct ifsregion *ifsp;
4753 INTOFF;
4754 ifsp = ifsfirst.next->next;
4755 ckfree(ifsfirst.next);
4756 ifsfirst.next = ifsp;
4757 INTON;
4758 }
4759 if (ifsfirst.begoff > endoff)
4760 ifslastp = NULL;
4761 else {
4762 ifslastp = &ifsfirst;
4763 ifsfirst.endoff = endoff;
4764 }
4765 return;
4766 }
Eric Andersen2870d962001-07-02 17:27:21 +00004767
Eric Andersencb57d552001-06-28 07:25:16 +00004768 ifslastp = &ifsfirst;
4769 while (ifslastp->next && ifslastp->next->begoff < endoff)
4770 ifslastp=ifslastp->next;
4771 while (ifslastp->next != NULL) {
4772 struct ifsregion *ifsp;
4773 INTOFF;
4774 ifsp = ifslastp->next->next;
4775 ckfree(ifslastp->next);
4776 ifslastp->next = ifsp;
4777 INTON;
4778 }
4779 if (ifslastp->endoff > endoff)
4780 ifslastp->endoff = endoff;
4781}
4782
4783
4784#ifdef ASH_MATH_SUPPORT
4785/*
4786 * Expand arithmetic expression. Backup to start of expression,
4787 * evaluate, place result in (backed up) result, adjust string position.
4788 */
4789static void
Eric Andersen2870d962001-07-02 17:27:21 +00004790expari(int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004791{
4792 char *p, *start;
Eric Andersen34506362001-08-02 05:02:46 +00004793 int errcode;
Eric Andersencb57d552001-06-28 07:25:16 +00004794 int result;
4795 int begoff;
4796 int quotes = flag & (EXP_FULL | EXP_CASE);
4797 int quoted;
4798
Eric Andersen2870d962001-07-02 17:27:21 +00004799 /* ifsfree(); */
Eric Andersencb57d552001-06-28 07:25:16 +00004800
4801 /*
4802 * This routine is slightly over-complicated for
4803 * efficiency. First we make sure there is
4804 * enough space for the result, which may be bigger
4805 * than the expression if we add exponentation. Next we
4806 * scan backwards looking for the start of arithmetic. If the
4807 * next previous character is a CTLESC character, then we
4808 * have to rescan starting from the beginning since CTLESC
4809 * characters have to be processed left to right.
4810 */
4811 CHECKSTRSPACE(10, expdest);
4812 USTPUTC('\0', expdest);
4813 start = stackblock();
4814 p = expdest - 1;
4815 while (*p != CTLARI && p >= start)
4816 --p;
4817 if (*p != CTLARI)
4818 error("missing CTLARI (shouldn't happen)");
4819 if (p > start && *(p-1) == CTLESC)
4820 for (p = start; *p != CTLARI; p++)
4821 if (*p == CTLESC)
4822 p++;
4823
4824 if (p[1] == '"')
4825 quoted=1;
4826 else
4827 quoted=0;
4828 begoff = p - start;
4829 removerecordregions(begoff);
4830 if (quotes)
4831 rmescapes(p+2);
Eric Andersen34506362001-08-02 05:02:46 +00004832 result = arith(p+2, &errcode);
4833 if (errcode < 0) {
4834 if(errcode == -2)
4835 error("divide by zero");
4836 else
4837 error("syntax error: \"%s\"\n", p+2);
4838 }
Eric Andersen3102ac42001-07-06 04:26:23 +00004839 snprintf(p, 12, "%d", result);
Eric Andersencb57d552001-06-28 07:25:16 +00004840
4841 while (*p++)
4842 ;
4843
4844 if (quoted == 0)
4845 recordregion(begoff, p - 1 - start, 0);
4846 result = expdest - p + 1;
4847 STADJUST(-result, expdest);
4848}
Eric Andersen2870d962001-07-02 17:27:21 +00004849#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004850
4851/*
4852 * Expand stuff in backwards quotes.
4853 */
4854
4855static void
4856expbackq(cmd, quoted, flag)
4857 union node *cmd;
4858 int quoted;
4859 int flag;
4860{
4861 volatile struct backcmd in;
4862 int i;
4863 char buf[128];
4864 char *p;
4865 char *dest = expdest;
4866 volatile struct ifsregion saveifs;
4867 struct ifsregion *volatile savelastp;
4868 struct nodelist *volatile saveargbackq;
4869 char lastc;
4870 int startloc = dest - stackblock();
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004871 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +00004872 volatile int saveherefd;
4873 int quotes = flag & (EXP_FULL | EXP_CASE);
4874 struct jmploc jmploc;
4875 struct jmploc *volatile savehandler;
4876 int ex;
4877
4878#if __GNUC__
4879 /* Avoid longjmp clobbering */
4880 (void) &dest;
4881 (void) &syntax;
4882#endif
4883
4884 in.fd = -1;
4885 in.buf = 0;
4886 in.jp = 0;
4887
4888 INTOFF;
4889 saveifs = ifsfirst;
4890 savelastp = ifslastp;
4891 saveargbackq = argbackq;
4892 saveherefd = herefd;
4893 herefd = -1;
4894 if ((ex = setjmp(jmploc.loc))) {
4895 goto err1;
4896 }
4897 savehandler = handler;
4898 handler = &jmploc;
4899 INTON;
4900 p = grabstackstr(dest);
4901 evalbackcmd(cmd, (struct backcmd *) &in);
4902 ungrabstackstr(p, dest);
4903err1:
4904 INTOFF;
4905 ifsfirst = saveifs;
4906 ifslastp = savelastp;
4907 argbackq = saveargbackq;
4908 herefd = saveherefd;
4909 if (ex) {
4910 goto err2;
4911 }
4912
4913 p = in.buf;
4914 lastc = '\0';
4915 for (;;) {
4916 if (--in.nleft < 0) {
4917 if (in.fd < 0)
4918 break;
Eric Andersen7467c8d2001-07-12 20:26:32 +00004919 i = safe_read(in.fd, buf, sizeof buf);
Eric Andersencb57d552001-06-28 07:25:16 +00004920 TRACE(("expbackq: read returns %d\n", i));
4921 if (i <= 0)
4922 break;
4923 p = buf;
4924 in.nleft = i - 1;
4925 }
4926 lastc = *p++;
4927 if (lastc != '\0') {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004928 if (quotes && SIT(lastc, syntax) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +00004929 STPUTC(CTLESC, dest);
4930 STPUTC(lastc, dest);
4931 }
4932 }
4933
4934 /* Eat all trailing newlines */
4935 for (; dest > stackblock() && dest[-1] == '\n';)
4936 STUNPUTC(dest);
4937
4938err2:
4939 if (in.fd >= 0)
4940 close(in.fd);
4941 if (in.buf)
4942 ckfree(in.buf);
4943 if (in.jp)
4944 exitstatus = waitforjob(in.jp);
4945 handler = savehandler;
4946 if (ex) {
4947 longjmp(handler->loc, 1);
4948 }
4949 if (quoted == 0)
4950 recordregion(startloc, dest - stackblock(), 0);
4951 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4952 (dest - stackblock()) - startloc,
4953 (dest - stackblock()) - startloc,
4954 stackblock() + startloc));
4955 expdest = dest;
4956 INTON;
4957}
4958
Eric Andersencb57d552001-06-28 07:25:16 +00004959static int
4960subevalvar(p, str, strloc, subtype, startloc, varflags, quotes)
4961 char *p;
4962 char *str;
4963 int strloc;
4964 int subtype;
4965 int startloc;
4966 int varflags;
4967 int quotes;
4968{
4969 char *startp;
4970 char *loc = NULL;
4971 char *q;
4972 int c = 0;
4973 int saveherefd = herefd;
4974 struct nodelist *saveargbackq = argbackq;
4975 int amount;
4976
4977 herefd = -1;
4978 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
4979 STACKSTRNUL(expdest);
4980 herefd = saveherefd;
4981 argbackq = saveargbackq;
4982 startp = stackblock() + startloc;
4983 if (str == NULL)
4984 str = stackblock() + strloc;
4985
4986 switch (subtype) {
4987 case VSASSIGN:
4988 setvar(str, startp, 0);
4989 amount = startp - expdest;
4990 STADJUST(amount, expdest);
4991 varflags &= ~VSNUL;
4992 if (c != 0)
4993 *loc = c;
4994 return 1;
4995
4996 case VSQUESTION:
4997 if (*p != CTLENDVAR) {
Eric Andersen3102ac42001-07-06 04:26:23 +00004998 out2fmt(snlfmt, startp);
Eric Andersencb57d552001-06-28 07:25:16 +00004999 error((char *)NULL);
5000 }
5001 error("%.*s: parameter %snot set", p - str - 1,
5002 str, (varflags & VSNUL) ? "null or "
5003 : nullstr);
5004 /* NOTREACHED */
5005
5006 case VSTRIMLEFT:
5007 for (loc = startp; loc < str; loc++) {
5008 c = *loc;
5009 *loc = '\0';
5010 if (patmatch2(str, startp, quotes))
5011 goto recordleft;
5012 *loc = c;
5013 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00005014 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00005015 }
5016 return 0;
5017
5018 case VSTRIMLEFTMAX:
5019 for (loc = str - 1; loc >= startp;) {
5020 c = *loc;
5021 *loc = '\0';
5022 if (patmatch2(str, startp, quotes))
5023 goto recordleft;
5024 *loc = c;
5025 loc--;
5026 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
5027 for (q = startp; q < loc; q++)
5028 if (*q == CTLESC)
5029 q++;
5030 if (q > loc)
5031 loc--;
5032 }
5033 }
5034 return 0;
5035
5036 case VSTRIMRIGHT:
Eric Andersen2870d962001-07-02 17:27:21 +00005037 for (loc = str - 1; loc >= startp;) {
Eric Andersencb57d552001-06-28 07:25:16 +00005038 if (patmatch2(str, loc, quotes))
5039 goto recordright;
5040 loc--;
Eric Andersen2870d962001-07-02 17:27:21 +00005041 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
Eric Andersencb57d552001-06-28 07:25:16 +00005042 for (q = startp; q < loc; q++)
5043 if (*q == CTLESC)
5044 q++;
5045 if (q > loc)
5046 loc--;
5047 }
5048 }
5049 return 0;
5050
5051 case VSTRIMRIGHTMAX:
5052 for (loc = startp; loc < str - 1; loc++) {
5053 if (patmatch2(str, loc, quotes))
5054 goto recordright;
5055 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00005056 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00005057 }
5058 return 0;
5059
5060#ifdef DEBUG
5061 default:
5062 abort();
5063#endif
5064 }
5065
5066recordleft:
5067 *loc = c;
5068 amount = ((str - 1) - (loc - startp)) - expdest;
5069 STADJUST(amount, expdest);
5070 while (loc != str - 1)
5071 *startp++ = *loc++;
5072 return 1;
5073
5074recordright:
5075 amount = loc - expdest;
5076 STADJUST(amount, expdest);
5077 STPUTC('\0', expdest);
5078 STADJUST(-1, expdest);
5079 return 1;
5080}
5081
5082
5083/*
Eric Andersencb57d552001-06-28 07:25:16 +00005084 * Test whether a specialized variable is set.
5085 */
5086
5087static int
5088varisset(name, nulok)
5089 char *name;
5090 int nulok;
5091{
5092 if (*name == '!')
5093 return backgndpid != -1;
5094 else if (*name == '@' || *name == '*') {
5095 if (*shellparam.p == NULL)
5096 return 0;
5097
5098 if (nulok) {
5099 char **av;
5100
5101 for (av = shellparam.p; *av; av++)
5102 if (**av != '\0')
5103 return 1;
5104 return 0;
5105 }
5106 } else if (is_digit(*name)) {
5107 char *ap;
5108 int num = atoi(name);
5109
5110 if (num > shellparam.nparam)
5111 return 0;
5112
5113 if (num == 0)
5114 ap = arg0;
5115 else
5116 ap = shellparam.p[num - 1];
5117
5118 if (nulok && (ap == NULL || *ap == '\0'))
5119 return 0;
5120 }
5121 return 1;
5122}
5123
Eric Andersencb57d552001-06-28 07:25:16 +00005124/*
5125 * Put a string on the stack.
5126 */
5127
5128static void
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005129strtodest(const char *p, int syntax, int quotes)
Eric Andersencb57d552001-06-28 07:25:16 +00005130{
5131 while (*p) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005132 if (quotes && SIT(*p,syntax) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +00005133 STPUTC(CTLESC, expdest);
5134 STPUTC(*p++, expdest);
5135 }
5136}
5137
Eric Andersencb57d552001-06-28 07:25:16 +00005138/*
5139 * Add the value of a specialized variable to the stack string.
5140 */
5141
5142static void
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005143varvalue(char *name, int quoted, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00005144{
5145 int num;
5146 char *p;
5147 int i;
5148 int sep;
5149 int sepq = 0;
5150 char **ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005151 int syntax;
Eric Andersencb57d552001-06-28 07:25:16 +00005152 int allow_split = flags & EXP_FULL;
5153 int quotes = flags & (EXP_FULL | EXP_CASE);
5154
5155 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5156 switch (*name) {
5157 case '$':
5158 num = rootpid;
5159 goto numvar;
5160 case '?':
5161 num = oexitstatus;
5162 goto numvar;
5163 case '#':
5164 num = shellparam.nparam;
5165 goto numvar;
5166 case '!':
5167 num = backgndpid;
5168numvar:
5169 expdest = cvtnum(num, expdest);
5170 break;
5171 case '-':
5172 for (i = 0 ; i < NOPTS ; i++) {
Eric Andersen2870d962001-07-02 17:27:21 +00005173 if (optent_val(i))
5174 STPUTC(optent_letter(optlist[i]), expdest);
Eric Andersencb57d552001-06-28 07:25:16 +00005175 }
5176 break;
5177 case '@':
5178 if (allow_split && quoted) {
5179 sep = 1 << CHAR_BIT;
5180 goto param;
5181 }
5182 /* fall through */
5183 case '*':
5184 sep = ifsset() ? ifsval()[0] : ' ';
5185 if (quotes) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005186 sepq = SIT(sep,syntax) == CCTL;
Eric Andersencb57d552001-06-28 07:25:16 +00005187 }
5188param:
5189 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
5190 strtodest(p, syntax, quotes);
5191 if (*ap && sep) {
5192 if (sepq)
5193 STPUTC(CTLESC, expdest);
5194 STPUTC(sep, expdest);
5195 }
5196 }
5197 break;
5198 case '0':
5199 strtodest(arg0, syntax, quotes);
5200 break;
5201 default:
5202 num = atoi(name);
5203 if (num > 0 && num <= shellparam.nparam) {
5204 strtodest(shellparam.p[num - 1], syntax, quotes);
5205 }
5206 break;
5207 }
5208}
5209
5210
Eric Andersencb57d552001-06-28 07:25:16 +00005211/*
5212 * Record the fact that we have to scan this region of the
5213 * string for IFS characters.
5214 */
5215
5216static void
5217recordregion(start, end, nulonly)
5218 int start;
5219 int end;
5220 int nulonly;
5221{
5222 struct ifsregion *ifsp;
5223
5224 if (ifslastp == NULL) {
5225 ifsp = &ifsfirst;
5226 } else {
5227 INTOFF;
5228 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
5229 ifsp->next = NULL;
5230 ifslastp->next = ifsp;
5231 INTON;
5232 }
5233 ifslastp = ifsp;
5234 ifslastp->begoff = start;
5235 ifslastp->endoff = end;
5236 ifslastp->nulonly = nulonly;
5237}
5238
5239
5240
5241/*
5242 * Break the argument string into pieces based upon IFS and add the
5243 * strings to the argument list. The regions of the string to be
5244 * searched for IFS characters have been stored by recordregion.
5245 */
5246static void
5247ifsbreakup(string, arglist)
5248 char *string;
5249 struct arglist *arglist;
5250 {
5251 struct ifsregion *ifsp;
5252 struct strlist *sp;
5253 char *start;
5254 char *p;
5255 char *q;
5256 const char *ifs, *realifs;
5257 int ifsspc;
5258 int nulonly;
5259
5260
5261 start = string;
5262 ifsspc = 0;
5263 nulonly = 0;
5264 realifs = ifsset() ? ifsval() : defifs;
5265 if (ifslastp != NULL) {
5266 ifsp = &ifsfirst;
5267 do {
5268 p = string + ifsp->begoff;
5269 nulonly = ifsp->nulonly;
5270 ifs = nulonly ? nullstr : realifs;
5271 ifsspc = 0;
5272 while (p < string + ifsp->endoff) {
5273 q = p;
5274 if (*p == CTLESC)
5275 p++;
5276 if (strchr(ifs, *p)) {
5277 if (!nulonly)
5278 ifsspc = (strchr(defifs, *p) != NULL);
5279 /* Ignore IFS whitespace at start */
5280 if (q == start && ifsspc) {
5281 p++;
5282 start = p;
5283 continue;
5284 }
5285 *q = '\0';
5286 sp = (struct strlist *)stalloc(sizeof *sp);
5287 sp->text = start;
5288 *arglist->lastp = sp;
5289 arglist->lastp = &sp->next;
5290 p++;
5291 if (!nulonly) {
5292 for (;;) {
5293 if (p >= string + ifsp->endoff) {
5294 break;
5295 }
5296 q = p;
5297 if (*p == CTLESC)
5298 p++;
5299 if (strchr(ifs, *p) == NULL ) {
5300 p = q;
5301 break;
5302 } else if (strchr(defifs, *p) == NULL) {
5303 if (ifsspc) {
5304 p++;
5305 ifsspc = 0;
5306 } else {
5307 p = q;
5308 break;
5309 }
5310 } else
5311 p++;
5312 }
5313 }
5314 start = p;
5315 } else
5316 p++;
5317 }
5318 } while ((ifsp = ifsp->next) != NULL);
5319 if (!(*start || (!ifsspc && start > string && nulonly))) {
5320 return;
5321 }
5322 }
5323
5324 sp = (struct strlist *)stalloc(sizeof *sp);
5325 sp->text = start;
5326 *arglist->lastp = sp;
5327 arglist->lastp = &sp->next;
5328}
5329
5330static void
5331ifsfree()
5332{
5333 while (ifsfirst.next != NULL) {
5334 struct ifsregion *ifsp;
5335 INTOFF;
5336 ifsp = ifsfirst.next->next;
5337 ckfree(ifsfirst.next);
5338 ifsfirst.next = ifsp;
5339 INTON;
5340 }
5341 ifslastp = NULL;
5342 ifsfirst.next = NULL;
5343}
5344
Eric Andersen2870d962001-07-02 17:27:21 +00005345/*
5346 * Add a file name to the list.
5347 */
Eric Andersencb57d552001-06-28 07:25:16 +00005348
Eric Andersen2870d962001-07-02 17:27:21 +00005349static void
5350addfname(const char *name)
5351{
5352 char *p;
5353 struct strlist *sp;
5354
5355 p = sstrdup(name);
5356 sp = (struct strlist *)stalloc(sizeof *sp);
5357 sp->text = p;
5358 *exparg.lastp = sp;
5359 exparg.lastp = &sp->next;
5360}
Eric Andersencb57d552001-06-28 07:25:16 +00005361
5362/*
5363 * Expand shell metacharacters. At this point, the only control characters
5364 * should be escapes. The results are stored in the list exparg.
5365 */
5366
Eric Andersen62483552001-07-10 06:09:16 +00005367#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00005368static void
5369expandmeta(str, flag)
5370 struct strlist *str;
5371 int flag;
5372{
5373 const char *p;
5374 glob_t pglob;
5375 /* TODO - EXP_REDIR */
5376
5377 while (str) {
5378 if (fflag)
5379 goto nometa;
5380 p = preglob(str->text);
5381 INTOFF;
Eric Andersen34506362001-08-02 05:02:46 +00005382 switch (glob(p, 0, 0, &pglob)) {
Eric Andersencb57d552001-06-28 07:25:16 +00005383 case 0:
Eric Andersen34506362001-08-02 05:02:46 +00005384 if(pglob.gl_pathv[1]==0 && !strcmp(p, pglob.gl_pathv[0]))
Eric Andersencb57d552001-06-28 07:25:16 +00005385 goto nometa2;
5386 addglob(&pglob);
5387 globfree(&pglob);
5388 INTON;
5389 break;
5390 case GLOB_NOMATCH:
5391nometa2:
5392 globfree(&pglob);
5393 INTON;
5394nometa:
5395 *exparg.lastp = str;
5396 rmescapes(str->text);
5397 exparg.lastp = &str->next;
5398 break;
Eric Andersen2870d962001-07-02 17:27:21 +00005399 default: /* GLOB_NOSPACE */
Eric Andersencb57d552001-06-28 07:25:16 +00005400 error("Out of space");
5401 }
5402 str = str->next;
5403 }
5404}
5405
5406
5407/*
5408 * Add the result of glob(3) to the list.
5409 */
5410
5411static void
5412addglob(pglob)
5413 const glob_t *pglob;
5414{
5415 char **p = pglob->gl_pathv;
5416
5417 do {
5418 addfname(*p);
5419 } while (*++p);
5420}
5421
5422
Eric Andersen2870d962001-07-02 17:27:21 +00005423#else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005424static char *expdir;
5425
5426
5427static void
5428expandmeta(str, flag)
5429 struct strlist *str;
5430 int flag;
5431{
5432 char *p;
5433 struct strlist **savelastp;
5434 struct strlist *sp;
5435 char c;
5436 /* TODO - EXP_REDIR */
5437
5438 while (str) {
5439 if (fflag)
5440 goto nometa;
5441 p = str->text;
Eric Andersen2870d962001-07-02 17:27:21 +00005442 for (;;) { /* fast check for meta chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005443 if ((c = *p++) == '\0')
5444 goto nometa;
5445 if (c == '*' || c == '?' || c == '[' || c == '!')
5446 break;
5447 }
5448 savelastp = exparg.lastp;
5449 INTOFF;
5450 if (expdir == NULL) {
5451 int i = strlen(str->text);
5452 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5453 }
5454
5455 expmeta(expdir, str->text);
5456 ckfree(expdir);
5457 expdir = NULL;
5458 INTON;
5459 if (exparg.lastp == savelastp) {
5460 /*
5461 * no matches
5462 */
5463nometa:
5464 *exparg.lastp = str;
5465 rmescapes(str->text);
5466 exparg.lastp = &str->next;
5467 } else {
5468 *exparg.lastp = NULL;
5469 *savelastp = sp = expsort(*savelastp);
5470 while (sp->next != NULL)
5471 sp = sp->next;
5472 exparg.lastp = &sp->next;
5473 }
5474 str = str->next;
5475 }
5476}
5477
5478
5479/*
5480 * Do metacharacter (i.e. *, ?, [...]) expansion.
5481 */
5482
5483static void
5484expmeta(enddir, name)
5485 char *enddir;
5486 char *name;
5487 {
5488 char *p;
5489 const char *cp;
5490 char *q;
5491 char *start;
5492 char *endname;
5493 int metaflag;
5494 struct stat statb;
5495 DIR *dirp;
5496 struct dirent *dp;
5497 int atend;
5498 int matchdot;
5499
5500 metaflag = 0;
5501 start = name;
5502 for (p = name ; ; p++) {
5503 if (*p == '*' || *p == '?')
5504 metaflag = 1;
5505 else if (*p == '[') {
5506 q = p + 1;
5507 if (*q == '!')
5508 q++;
5509 for (;;) {
5510 while (*q == CTLQUOTEMARK)
5511 q++;
5512 if (*q == CTLESC)
5513 q++;
5514 if (*q == '/' || *q == '\0')
5515 break;
5516 if (*++q == ']') {
5517 metaflag = 1;
5518 break;
5519 }
5520 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005521 } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) {
Eric Andersencb57d552001-06-28 07:25:16 +00005522 metaflag = 1;
5523 } else if (*p == '\0')
5524 break;
5525 else if (*p == CTLQUOTEMARK)
5526 continue;
5527 else if (*p == CTLESC)
5528 p++;
5529 if (*p == '/') {
5530 if (metaflag)
5531 break;
5532 start = p + 1;
5533 }
5534 }
Eric Andersen2870d962001-07-02 17:27:21 +00005535 if (metaflag == 0) { /* we've reached the end of the file name */
Eric Andersencb57d552001-06-28 07:25:16 +00005536 if (enddir != expdir)
5537 metaflag++;
5538 for (p = name ; ; p++) {
5539 if (*p == CTLQUOTEMARK)
5540 continue;
5541 if (*p == CTLESC)
5542 p++;
5543 *enddir++ = *p;
5544 if (*p == '\0')
5545 break;
5546 }
5547 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5548 addfname(expdir);
5549 return;
5550 }
5551 endname = p;
5552 if (start != name) {
5553 p = name;
5554 while (p < start) {
5555 while (*p == CTLQUOTEMARK)
5556 p++;
5557 if (*p == CTLESC)
5558 p++;
5559 *enddir++ = *p++;
5560 }
5561 }
5562 if (enddir == expdir) {
5563 cp = ".";
5564 } else if (enddir == expdir + 1 && *expdir == '/') {
5565 cp = "/";
5566 } else {
5567 cp = expdir;
5568 enddir[-1] = '\0';
5569 }
5570 if ((dirp = opendir(cp)) == NULL)
5571 return;
5572 if (enddir != expdir)
5573 enddir[-1] = '/';
5574 if (*endname == 0) {
5575 atend = 1;
5576 } else {
5577 atend = 0;
5578 *endname++ = '\0';
5579 }
5580 matchdot = 0;
5581 p = start;
5582 while (*p == CTLQUOTEMARK)
5583 p++;
5584 if (*p == CTLESC)
5585 p++;
5586 if (*p == '.')
5587 matchdot++;
5588 while (! int_pending() && (dp = readdir(dirp)) != NULL) {
5589 if (dp->d_name[0] == '.' && ! matchdot)
5590 continue;
5591 if (patmatch(start, dp->d_name, 0)) {
5592 if (atend) {
Eric Andersen2870d962001-07-02 17:27:21 +00005593 strcpy(enddir, dp->d_name);
Eric Andersencb57d552001-06-28 07:25:16 +00005594 addfname(expdir);
5595 } else {
5596 for (p = enddir, cp = dp->d_name;
5597 (*p++ = *cp++) != '\0';)
5598 continue;
5599 p[-1] = '/';
5600 expmeta(p, endname);
5601 }
5602 }
5603 }
5604 closedir(dirp);
5605 if (! atend)
5606 endname[-1] = '/';
5607}
Eric Andersen2870d962001-07-02 17:27:21 +00005608#endif /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005609
5610
Eric Andersencb57d552001-06-28 07:25:16 +00005611
Eric Andersen62483552001-07-10 06:09:16 +00005612#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersencb57d552001-06-28 07:25:16 +00005613/*
5614 * Sort the results of file name expansion. It calculates the number of
5615 * strings to sort and then calls msort (short for merge sort) to do the
5616 * work.
5617 */
5618
5619static struct strlist *
5620expsort(str)
5621 struct strlist *str;
5622 {
5623 int len;
5624 struct strlist *sp;
5625
5626 len = 0;
5627 for (sp = str ; sp ; sp = sp->next)
5628 len++;
5629 return msort(str, len);
5630}
5631
5632
5633static struct strlist *
5634msort(list, len)
5635 struct strlist *list;
5636 int len;
5637{
5638 struct strlist *p, *q = NULL;
5639 struct strlist **lpp;
5640 int half;
5641 int n;
5642
5643 if (len <= 1)
5644 return list;
5645 half = len >> 1;
5646 p = list;
5647 for (n = half ; --n >= 0 ; ) {
5648 q = p;
5649 p = p->next;
5650 }
Eric Andersen2870d962001-07-02 17:27:21 +00005651 q->next = NULL; /* terminate first half of list */
5652 q = msort(list, half); /* sort first half of list */
5653 p = msort(p, len - half); /* sort second half */
Eric Andersencb57d552001-06-28 07:25:16 +00005654 lpp = &list;
5655 for (;;) {
5656 if (strcmp(p->text, q->text) < 0) {
5657 *lpp = p;
5658 lpp = &p->next;
5659 if ((p = *lpp) == NULL) {
5660 *lpp = q;
5661 break;
5662 }
5663 } else {
5664 *lpp = q;
5665 lpp = &q->next;
5666 if ((q = *lpp) == NULL) {
5667 *lpp = p;
5668 break;
5669 }
5670 }
5671 }
5672 return list;
5673}
5674#endif
5675
5676
5677
5678/*
5679 * Returns true if the pattern matches the string.
5680 */
5681
Eric Andersen62483552001-07-10 06:09:16 +00005682#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00005683/* squoted: string might have quote chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005684static int
Eric Andersen2870d962001-07-02 17:27:21 +00005685patmatch(char *pattern, char *string, int squoted)
5686{
Eric Andersencb57d552001-06-28 07:25:16 +00005687 const char *p;
5688 char *q;
5689
5690 p = preglob(pattern);
5691 q = squoted ? _rmescapes(string, RMESCAPE_ALLOC) : string;
5692
5693 return !fnmatch(p, q, 0);
5694}
5695
5696
5697static int
Eric Andersen2870d962001-07-02 17:27:21 +00005698patmatch2(char *pattern, char *string, int squoted)
5699{
Eric Andersencb57d552001-06-28 07:25:16 +00005700 char *p;
5701 int res;
5702
5703 sstrnleft--;
5704 p = grabstackstr(expdest);
5705 res = patmatch(pattern, string, squoted);
5706 ungrabstackstr(p, expdest);
5707 return res;
5708}
5709#else
5710static int
Eric Andersen2870d962001-07-02 17:27:21 +00005711patmatch(char *pattern, char *string, int squoted) {
5712 return pmatch(pattern, string, squoted);
Eric Andersencb57d552001-06-28 07:25:16 +00005713}
5714
5715
5716static int
Eric Andersen2870d962001-07-02 17:27:21 +00005717pmatch(char *pattern, char *string, int squoted)
5718{
Eric Andersencb57d552001-06-28 07:25:16 +00005719 char *p, *q;
5720 char c;
5721
5722 p = pattern;
5723 q = string;
5724 for (;;) {
5725 switch (c = *p++) {
5726 case '\0':
5727 goto breakloop;
5728 case CTLESC:
5729 if (squoted && *q == CTLESC)
5730 q++;
5731 if (*q++ != *p++)
5732 return 0;
5733 break;
5734 case CTLQUOTEMARK:
5735 continue;
5736 case '?':
5737 if (squoted && *q == CTLESC)
5738 q++;
5739 if (*q++ == '\0')
5740 return 0;
5741 break;
5742 case '*':
5743 c = *p;
5744 while (c == CTLQUOTEMARK || c == '*')
5745 c = *++p;
5746 if (c != CTLESC && c != CTLQUOTEMARK &&
5747 c != '?' && c != '*' && c != '[') {
5748 while (*q != c) {
5749 if (squoted && *q == CTLESC &&
5750 q[1] == c)
5751 break;
5752 if (*q == '\0')
5753 return 0;
5754 if (squoted && *q == CTLESC)
5755 q++;
5756 q++;
5757 }
5758 }
5759 do {
5760 if (pmatch(p, q, squoted))
5761 return 1;
5762 if (squoted && *q == CTLESC)
5763 q++;
5764 } while (*q++ != '\0');
5765 return 0;
5766 case '[': {
5767 char *endp;
5768 int invert, found;
5769 char chr;
5770
5771 endp = p;
5772 if (*endp == '!')
5773 endp++;
5774 for (;;) {
5775 while (*endp == CTLQUOTEMARK)
5776 endp++;
5777 if (*endp == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00005778 goto dft; /* no matching ] */
Eric Andersencb57d552001-06-28 07:25:16 +00005779 if (*endp == CTLESC)
5780 endp++;
5781 if (*++endp == ']')
5782 break;
5783 }
5784 invert = 0;
5785 if (*p == '!') {
5786 invert++;
5787 p++;
5788 }
5789 found = 0;
5790 chr = *q++;
5791 if (squoted && chr == CTLESC)
5792 chr = *q++;
5793 if (chr == '\0')
5794 return 0;
5795 c = *p++;
5796 do {
5797 if (c == CTLQUOTEMARK)
5798 continue;
5799 if (c == CTLESC)
5800 c = *p++;
5801 if (*p == '-' && p[1] != ']') {
5802 p++;
5803 while (*p == CTLQUOTEMARK)
5804 p++;
5805 if (*p == CTLESC)
5806 p++;
5807 if (chr >= c && chr <= *p)
5808 found = 1;
5809 p++;
5810 } else {
5811 if (chr == c)
5812 found = 1;
5813 }
5814 } while ((c = *p++) != ']');
5815 if (found == invert)
5816 return 0;
5817 break;
5818 }
Eric Andersen2870d962001-07-02 17:27:21 +00005819dft: default:
Eric Andersencb57d552001-06-28 07:25:16 +00005820 if (squoted && *q == CTLESC)
5821 q++;
5822 if (*q++ != c)
5823 return 0;
5824 break;
5825 }
5826 }
5827breakloop:
5828 if (*q != '\0')
5829 return 0;
5830 return 1;
5831}
5832#endif
5833
5834
5835
5836/*
5837 * Remove any CTLESC characters from a string.
5838 */
5839
Eric Andersen62483552001-07-10 06:09:16 +00005840#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00005841static char *
Eric Andersen2870d962001-07-02 17:27:21 +00005842_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005843{
5844 char *p, *q, *r;
5845 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5846
5847 p = strpbrk(str, qchars);
5848 if (!p) {
5849 return str;
5850 }
5851 q = p;
5852 r = str;
5853 if (flag & RMESCAPE_ALLOC) {
5854 size_t len = p - str;
5855 q = r = stalloc(strlen(p) + len + 1);
5856 if (len > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00005857 memcpy(q, str, len);
5858 q += len;
Eric Andersencb57d552001-06-28 07:25:16 +00005859 }
5860 }
5861 while (*p) {
5862 if (*p == CTLQUOTEMARK) {
5863 p++;
5864 continue;
5865 }
5866 if (*p == CTLESC) {
5867 p++;
5868 if (flag & RMESCAPE_GLOB && *p != '/') {
5869 *q++ = '\\';
5870 }
5871 }
5872 *q++ = *p++;
5873 }
5874 *q = '\0';
5875 return r;
5876}
5877#else
5878static void
5879rmescapes(str)
5880 char *str;
5881{
5882 char *p, *q;
5883
5884 p = str;
5885 while (*p != CTLESC && *p != CTLQUOTEMARK) {
5886 if (*p++ == '\0')
5887 return;
5888 }
5889 q = p;
5890 while (*p) {
5891 if (*p == CTLQUOTEMARK) {
5892 p++;
5893 continue;
5894 }
5895 if (*p == CTLESC)
5896 p++;
5897 *q++ = *p++;
5898 }
5899 *q = '\0';
5900}
5901#endif
5902
5903
5904
5905/*
5906 * See if a pattern matches in a case statement.
5907 */
5908
5909static int
Eric Andersen2870d962001-07-02 17:27:21 +00005910casematch(union node *pattern, const char *val)
5911{
Eric Andersencb57d552001-06-28 07:25:16 +00005912 struct stackmark smark;
5913 int result;
5914 char *p;
5915
5916 setstackmark(&smark);
5917 argbackq = pattern->narg.backquote;
5918 STARTSTACKSTR(expdest);
5919 ifslastp = NULL;
5920 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5921 STPUTC('\0', expdest);
5922 p = grabstackstr(expdest);
Eric Andersen2870d962001-07-02 17:27:21 +00005923 result = patmatch(p, (char *)val, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00005924 popstackmark(&smark);
5925 return result;
5926}
5927
5928/*
5929 * Our own itoa().
5930 */
5931
5932static char *
5933cvtnum(num, buf)
5934 int num;
5935 char *buf;
5936 {
5937 int len;
5938
5939 CHECKSTRSPACE(32, buf);
5940 len = sprintf(buf, "%d", num);
5941 STADJUST(len, buf);
5942 return buf;
5943}
Eric Andersencb57d552001-06-28 07:25:16 +00005944/*
5945 * Editline and history functions (and glue).
5946 */
5947static int histcmd(argc, argv)
5948 int argc;
5949 char **argv;
5950{
5951 error("not compiled with history support");
5952 /* NOTREACHED */
5953}
5954
5955
Eric Andersencb57d552001-06-28 07:25:16 +00005956struct redirtab {
5957 struct redirtab *next;
Russ Dill4db35642001-07-26 05:58:40 +00005958 short renamed[10]; /* Current ash support only 0-9 descriptors */
Eric Andersen34506362001-08-02 05:02:46 +00005959 /* char on arm (and others) can't be negative */
Eric Andersencb57d552001-06-28 07:25:16 +00005960};
5961
Eric Andersen2870d962001-07-02 17:27:21 +00005962static struct redirtab *redirlist;
Eric Andersencb57d552001-06-28 07:25:16 +00005963
5964extern char **environ;
5965
5966
5967
5968/*
5969 * Initialization code.
5970 */
5971
5972static void
Eric Andersen2870d962001-07-02 17:27:21 +00005973init(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00005974
5975 /* from cd.c: */
5976 {
5977 setpwd(0, 0);
5978 }
5979
5980 /* from input.c: */
5981 {
5982 basepf.nextc = basepf.buf = basebuf;
5983 }
5984
Eric Andersencb57d552001-06-28 07:25:16 +00005985 /* from var.c: */
5986 {
5987 char **envp;
5988 char ppid[32];
5989
5990 initvar();
5991 for (envp = environ ; *envp ; envp++) {
5992 if (strchr(*envp, '=')) {
5993 setvareq(*envp, VEXPORT|VTEXTFIXED);
5994 }
5995 }
5996
Eric Andersen3102ac42001-07-06 04:26:23 +00005997 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
Eric Andersencb57d552001-06-28 07:25:16 +00005998 setvar("PPID", ppid, 0);
5999 }
6000}
6001
6002
6003
6004/*
6005 * This routine is called when an error or an interrupt occurs in an
6006 * interactive shell and control is returned to the main command loop.
6007 */
6008
Eric Andersen2870d962001-07-02 17:27:21 +00006009/* 1 == check for aliases, 2 == also check for assignments */
Eric Andersen7467c8d2001-07-12 20:26:32 +00006010static int checkalias; /* also used in no alias mode for check assignments */
Eric Andersen2870d962001-07-02 17:27:21 +00006011
Eric Andersencb57d552001-06-28 07:25:16 +00006012static void
Eric Andersen2870d962001-07-02 17:27:21 +00006013reset(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00006014
6015 /* from eval.c: */
6016 {
6017 evalskip = 0;
6018 loopnest = 0;
6019 funcnest = 0;
6020 }
6021
6022 /* from input.c: */
6023 {
6024 if (exception != EXSHELLPROC)
Eric Andersen2870d962001-07-02 17:27:21 +00006025 parselleft = parsenleft = 0; /* clear input buffer */
Eric Andersencb57d552001-06-28 07:25:16 +00006026 popallfiles();
6027 }
6028
6029 /* from parser.c: */
6030 {
6031 tokpushback = 0;
6032 checkkwd = 0;
6033 checkalias = 0;
6034 }
6035
6036 /* from redir.c: */
6037 {
6038 while (redirlist)
6039 popredir();
6040 }
6041
Eric Andersencb57d552001-06-28 07:25:16 +00006042}
6043
6044
6045
6046/*
Eric Andersencb57d552001-06-28 07:25:16 +00006047 * This file implements the input routines used by the parser.
6048 */
6049
6050#ifdef BB_FEATURE_COMMAND_EDITING
Eric Andersencb57d552001-06-28 07:25:16 +00006051static const char * cmdedit_prompt;
6052static inline void putprompt(const char *s) {
6053 cmdedit_prompt = s;
6054}
6055#else
6056static inline void putprompt(const char *s) {
6057 out2str(s);
6058}
6059#endif
6060
Eric Andersen2870d962001-07-02 17:27:21 +00006061#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
Eric Andersencb57d552001-06-28 07:25:16 +00006062
Eric Andersencb57d552001-06-28 07:25:16 +00006063
Eric Andersencb57d552001-06-28 07:25:16 +00006064
Eric Andersen2870d962001-07-02 17:27:21 +00006065/*
6066 * Same as pgetc(), but ignores PEOA.
6067 */
Eric Andersencb57d552001-06-28 07:25:16 +00006068
Eric Andersen2870d962001-07-02 17:27:21 +00006069#ifdef ASH_ALIAS
6070static int
Eric Andersen74400cc2001-10-18 04:11:39 +00006071pgetc2(void)
Eric Andersen2870d962001-07-02 17:27:21 +00006072{
6073 int c;
6074 do {
6075 c = pgetc_macro();
6076 } while (c == PEOA);
6077 return c;
Eric Andersencb57d552001-06-28 07:25:16 +00006078}
Eric Andersen2870d962001-07-02 17:27:21 +00006079#else
6080static inline int pgetc2() { return pgetc_macro(); }
Eric Andersencb57d552001-06-28 07:25:16 +00006081#endif
6082
Eric Andersencb57d552001-06-28 07:25:16 +00006083/*
6084 * Read a line from the script.
6085 */
6086
Eric Andersen62483552001-07-10 06:09:16 +00006087static inline char *
Eric Andersen2870d962001-07-02 17:27:21 +00006088pfgets(char *line, int len)
Eric Andersencb57d552001-06-28 07:25:16 +00006089{
6090 char *p = line;
6091 int nleft = len;
6092 int c;
6093
6094 while (--nleft > 0) {
6095 c = pgetc2();
6096 if (c == PEOF) {
6097 if (p == line)
6098 return NULL;
6099 break;
6100 }
6101 *p++ = c;
6102 if (c == '\n')
6103 break;
6104 }
6105 *p = '\0';
6106 return line;
6107}
6108
Eric Andersen62483552001-07-10 06:09:16 +00006109static inline int
Eric Andersen2870d962001-07-02 17:27:21 +00006110preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006111{
6112 int nr;
6113 char *buf = parsefile->buf;
6114 parsenextc = buf;
6115
6116retry:
6117#ifdef BB_FEATURE_COMMAND_EDITING
6118 {
Eric Andersen34506362001-08-02 05:02:46 +00006119 if (!iflag || parsefile->fd)
Eric Andersen7467c8d2001-07-12 20:26:32 +00006120 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersen2870d962001-07-02 17:27:21 +00006121 else {
Eric Andersen044228d2001-07-17 01:12:36 +00006122 nr = cmdedit_read_input((char*)cmdedit_prompt, buf);
Eric Andersencb57d552001-06-28 07:25:16 +00006123 }
6124 }
6125#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00006126 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006127#endif
6128
6129 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006130 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6131 int flags = fcntl(0, F_GETFL, 0);
6132 if (flags >= 0 && flags & O_NONBLOCK) {
6133 flags &=~ O_NONBLOCK;
6134 if (fcntl(0, F_SETFL, flags) >= 0) {
6135 out2str("sh: turning off NDELAY mode\n");
6136 goto retry;
6137 }
6138 }
6139 }
6140 }
6141 return nr;
6142}
6143
Eric Andersen2870d962001-07-02 17:27:21 +00006144static void
6145popstring(void)
6146{
6147 struct strpush *sp = parsefile->strpush;
6148
6149 INTOFF;
6150#ifdef ASH_ALIAS
6151 if (sp->ap) {
6152 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6153 if (!checkalias) {
6154 checkalias = 1;
6155 }
6156 }
6157 if (sp->string != sp->ap->val) {
6158 ckfree(sp->string);
6159 }
6160
6161 sp->ap->flag &= ~ALIASINUSE;
6162 if (sp->ap->flag & ALIASDEAD) {
6163 unalias(sp->ap->name);
6164 }
6165 }
6166#endif
6167 parsenextc = sp->prevstring;
6168 parsenleft = sp->prevnleft;
6169/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6170 parsefile->strpush = sp->prev;
6171 if (sp != &(parsefile->basestrpush))
6172 ckfree(sp);
6173 INTON;
6174}
6175
6176
Eric Andersencb57d552001-06-28 07:25:16 +00006177/*
6178 * Refill the input buffer and return the next input character:
6179 *
6180 * 1) If a string was pushed back on the input, pop it;
6181 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6182 * from a string so we can't refill the buffer, return EOF.
6183 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6184 * 4) Process input up to the next newline, deleting nul characters.
6185 */
6186
6187static int
Eric Andersen2870d962001-07-02 17:27:21 +00006188preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006189{
6190 char *p, *q;
6191 int more;
6192 char savec;
6193
6194 while (parsefile->strpush) {
Eric Andersen2870d962001-07-02 17:27:21 +00006195#ifdef ASH_ALIAS
6196 if (parsenleft == -1 && parsefile->strpush->ap &&
6197 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00006198 return PEOA;
6199 }
Eric Andersen2870d962001-07-02 17:27:21 +00006200#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006201 popstring();
6202 if (--parsenleft >= 0)
6203 return (*parsenextc++);
6204 }
6205 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6206 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00006207 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00006208
6209again:
6210 if (parselleft <= 0) {
6211 if ((parselleft = preadfd()) <= 0) {
6212 parselleft = parsenleft = EOF_NLEFT;
6213 return PEOF;
6214 }
6215 }
6216
6217 q = p = parsenextc;
6218
6219 /* delete nul characters */
6220 for (more = 1; more;) {
6221 switch (*p) {
6222 case '\0':
Eric Andersen2870d962001-07-02 17:27:21 +00006223 p++; /* Skip nul */
Eric Andersencb57d552001-06-28 07:25:16 +00006224 goto check;
6225
6226
6227 case '\n':
6228 parsenleft = q - parsenextc;
6229 more = 0; /* Stop processing here */
6230 break;
6231 }
6232
6233 *q++ = *p++;
6234check:
6235 if (--parselleft <= 0 && more) {
6236 parsenleft = q - parsenextc - 1;
6237 if (parsenleft < 0)
6238 goto again;
6239 more = 0;
6240 }
6241 }
6242
6243 savec = *q;
6244 *q = '\0';
6245
6246 if (vflag) {
6247 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00006248 }
6249
6250 *q = savec;
6251
6252 return *parsenextc++;
6253}
6254
Eric Andersencb57d552001-06-28 07:25:16 +00006255
6256/*
6257 * Push a string back onto the input at this current parsefile level.
6258 * We handle aliases this way.
6259 */
6260static void
Eric Andersen2870d962001-07-02 17:27:21 +00006261pushstring(char *s, int len, void *ap)
6262{
Eric Andersencb57d552001-06-28 07:25:16 +00006263 struct strpush *sp;
6264
6265 INTOFF;
6266/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6267 if (parsefile->strpush) {
6268 sp = ckmalloc(sizeof (struct strpush));
6269 sp->prev = parsefile->strpush;
6270 parsefile->strpush = sp;
6271 } else
6272 sp = parsefile->strpush = &(parsefile->basestrpush);
6273 sp->prevstring = parsenextc;
6274 sp->prevnleft = parsenleft;
Eric Andersen2870d962001-07-02 17:27:21 +00006275#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00006276 sp->ap = (struct alias *)ap;
6277 if (ap) {
6278 ((struct alias *)ap)->flag |= ALIASINUSE;
6279 sp->string = s;
6280 }
Eric Andersen2870d962001-07-02 17:27:21 +00006281#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006282 parsenextc = s;
6283 parsenleft = len;
6284 INTON;
6285}
6286
Eric Andersencb57d552001-06-28 07:25:16 +00006287
Eric Andersencb57d552001-06-28 07:25:16 +00006288/*
6289 * Like setinputfile, but takes input from a string.
6290 */
6291
6292static void
Eric Andersen62483552001-07-10 06:09:16 +00006293setinputstring(char *string)
6294{
Eric Andersencb57d552001-06-28 07:25:16 +00006295 INTOFF;
6296 pushfile();
6297 parsenextc = string;
6298 parsenleft = strlen(string);
6299 parsefile->buf = NULL;
6300 plinno = 1;
6301 INTON;
6302}
6303
6304
6305
6306/*
6307 * To handle the "." command, a stack of input files is used. Pushfile
6308 * adds a new entry to the stack and popfile restores the previous level.
6309 */
6310
6311static void
Eric Andersen2870d962001-07-02 17:27:21 +00006312pushfile(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00006313 struct parsefile *pf;
6314
6315 parsefile->nleft = parsenleft;
6316 parsefile->lleft = parselleft;
6317 parsefile->nextc = parsenextc;
6318 parsefile->linno = plinno;
6319 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6320 pf->prev = parsefile;
6321 pf->fd = -1;
6322 pf->strpush = NULL;
6323 pf->basestrpush.prev = NULL;
6324 parsefile = pf;
6325}
6326
Eric Andersen2870d962001-07-02 17:27:21 +00006327#ifdef JOBS
6328static void restartjob (struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00006329#endif
Eric Andersen2870d962001-07-02 17:27:21 +00006330static void freejob (struct job *);
6331static struct job *getjob (const char *);
6332static int dowait (int, struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00006333static void waitonint(int);
6334
6335
Eric Andersen2870d962001-07-02 17:27:21 +00006336/*
6337 * We keep track of whether or not fd0 has been redirected. This is for
6338 * background commands, where we want to redirect fd0 to /dev/null only
6339 * if it hasn't already been redirected.
6340*/
6341static int fd0_redirected = 0;
6342
6343/* Return true if fd 0 has already been redirected at least once. */
6344static inline int
Eric Andersen74400cc2001-10-18 04:11:39 +00006345fd0_redirected_p (void)
6346{
Eric Andersen2870d962001-07-02 17:27:21 +00006347 return fd0_redirected != 0;
6348}
6349
Eric Andersen62483552001-07-10 06:09:16 +00006350static void dupredirect (const union node *, int, int fd1dup);
Eric Andersen2870d962001-07-02 17:27:21 +00006351
6352#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006353/*
6354 * Turn job control on and off.
6355 *
6356 * Note: This code assumes that the third arg to ioctl is a character
6357 * pointer, which is true on Berkeley systems but not System V. Since
6358 * System V doesn't have job control yet, this isn't a problem now.
6359 */
6360
Eric Andersen2870d962001-07-02 17:27:21 +00006361
Eric Andersencb57d552001-06-28 07:25:16 +00006362
6363static void setjobctl(int enable)
6364{
6365#ifdef OLD_TTY_DRIVER
6366 int ldisc;
6367#endif
6368
6369 if (enable == jobctl || rootshell == 0)
6370 return;
6371 if (enable) {
6372 do { /* while we are in the background */
6373#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006374 if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006375#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006376 initialpgrp = tcgetpgrp(2);
Eric Andersencb57d552001-06-28 07:25:16 +00006377 if (initialpgrp < 0) {
6378#endif
Eric Andersen8c145dc2001-07-10 16:57:09 +00006379 out2str("sh: can't access tty; job control turned off\n");
Eric Andersencb57d552001-06-28 07:25:16 +00006380 mflag = 0;
6381 return;
6382 }
6383 if (initialpgrp == -1)
6384 initialpgrp = getpgrp();
6385 else if (initialpgrp != getpgrp()) {
6386 killpg(initialpgrp, SIGTTIN);
6387 continue;
6388 }
6389 } while (0);
6390#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006391 if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
Eric Andersen8c145dc2001-07-10 16:57:09 +00006392 out2str("sh: need new tty driver to run job control; job control turned off\n");
Eric Andersencb57d552001-06-28 07:25:16 +00006393 mflag = 0;
6394 return;
6395 }
6396#endif
6397 setsignal(SIGTSTP);
6398 setsignal(SIGTTOU);
6399 setsignal(SIGTTIN);
6400 setpgid(0, rootpid);
6401#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006402 ioctl(2, TIOCSPGRP, (char *)&rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00006403#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006404 tcsetpgrp(2, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00006405#endif
Eric Andersen8c145dc2001-07-10 16:57:09 +00006406 } else { /* turning job control off */
Eric Andersencb57d552001-06-28 07:25:16 +00006407 setpgid(0, initialpgrp);
6408#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006409 ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006410#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006411 tcsetpgrp(2, initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006412#endif
6413 setsignal(SIGTSTP);
6414 setsignal(SIGTTOU);
6415 setsignal(SIGTTIN);
6416 }
6417 jobctl = enable;
6418}
6419#endif
6420
6421
Eric Andersen2870d962001-07-02 17:27:21 +00006422#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006423static int
6424killcmd(argc, argv)
6425 int argc;
6426 char **argv;
6427{
6428 int signo = -1;
6429 int list = 0;
6430 int i;
6431 pid_t pid;
6432 struct job *jp;
6433
6434 if (argc <= 1) {
6435usage:
6436 error(
6437"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6438"kill -l [exitstatus]"
6439 );
6440 }
6441
6442 if (*argv[1] == '-') {
6443 signo = decode_signal(argv[1] + 1, 1);
6444 if (signo < 0) {
6445 int c;
6446
6447 while ((c = nextopt("ls:")) != '\0')
6448 switch (c) {
6449 case 'l':
6450 list = 1;
6451 break;
6452 case 's':
6453 signo = decode_signal(optionarg, 1);
6454 if (signo < 0) {
6455 error(
6456 "invalid signal number or name: %s",
6457 optionarg
6458 );
6459 }
Eric Andersen2870d962001-07-02 17:27:21 +00006460 break;
Eric Andersencb57d552001-06-28 07:25:16 +00006461#ifdef DEBUG
6462 default:
6463 error(
6464 "nextopt returned character code 0%o", c);
6465#endif
6466 }
6467 } else
6468 argptr++;
6469 }
6470
6471 if (!list && signo < 0)
6472 signo = SIGTERM;
6473
6474 if ((signo < 0 || !*argptr) ^ list) {
6475 goto usage;
6476 }
6477
6478 if (list) {
Eric Andersen34506362001-08-02 05:02:46 +00006479 const char *name;
6480
Eric Andersencb57d552001-06-28 07:25:16 +00006481 if (!*argptr) {
6482 out1str("0\n");
6483 for (i = 1; i < NSIG; i++) {
Eric Andersen34506362001-08-02 05:02:46 +00006484 name = u_signal_names(0, &i, 1);
6485 if(name)
6486 printf(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006487 }
6488 return 0;
6489 }
Eric Andersen34506362001-08-02 05:02:46 +00006490 name = u_signal_names(*argptr, &signo, -1);
6491 if (name)
6492 printf(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006493 else
6494 error("invalid signal number or exit status: %s",
6495 *argptr);
6496 return 0;
6497 }
6498
6499 do {
6500 if (**argptr == '%') {
6501 jp = getjob(*argptr);
6502 if (jp->jobctl == 0)
6503 error("job %s not created under job control",
6504 *argptr);
6505 pid = -jp->ps[0].pid;
6506 } else
6507 pid = atoi(*argptr);
6508 if (kill(pid, signo) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00006509 error("%s: %m", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006510 } while (*++argptr);
6511
6512 return 0;
6513}
6514
6515static int
6516fgcmd(argc, argv)
6517 int argc;
6518 char **argv;
6519{
6520 struct job *jp;
6521 int pgrp;
6522 int status;
6523
6524 jp = getjob(argv[1]);
6525 if (jp->jobctl == 0)
6526 error("job not created under job control");
6527 pgrp = jp->ps[0].pid;
6528#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006529 ioctl(2, TIOCSPGRP, (char *)&pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006530#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006531 tcsetpgrp(2, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006532#endif
6533 restartjob(jp);
6534 INTOFF;
6535 status = waitforjob(jp);
6536 INTON;
6537 return status;
6538}
6539
6540
6541static int
6542bgcmd(argc, argv)
6543 int argc;
6544 char **argv;
6545{
6546 struct job *jp;
6547
6548 do {
6549 jp = getjob(*++argv);
6550 if (jp->jobctl == 0)
6551 error("job not created under job control");
6552 restartjob(jp);
6553 } while (--argc > 1);
6554 return 0;
6555}
6556
6557
6558static void
6559restartjob(jp)
6560 struct job *jp;
6561{
6562 struct procstat *ps;
6563 int i;
6564
6565 if (jp->state == JOBDONE)
6566 return;
6567 INTOFF;
6568 killpg(jp->ps[0].pid, SIGCONT);
6569 for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
6570 if (WIFSTOPPED(ps->status)) {
6571 ps->status = -1;
6572 jp->state = 0;
6573 }
6574 }
6575 INTON;
6576}
6577#endif
6578
Eric Andersen2870d962001-07-02 17:27:21 +00006579static void showjobs(int change);
6580
Eric Andersencb57d552001-06-28 07:25:16 +00006581
6582static int
6583jobscmd(argc, argv)
6584 int argc;
6585 char **argv;
6586{
6587 showjobs(0);
6588 return 0;
6589}
6590
6591
6592/*
6593 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6594 * statuses have changed since the last call to showjobs.
6595 *
6596 * If the shell is interrupted in the process of creating a job, the
6597 * result may be a job structure containing zero processes. Such structures
6598 * will be freed here.
6599 */
6600
6601static void
6602showjobs(change)
6603 int change;
6604{
6605 int jobno;
6606 int procno;
6607 int i;
6608 struct job *jp;
6609 struct procstat *ps;
6610 int col;
6611 char s[64];
6612
6613 TRACE(("showjobs(%d) called\n", change));
6614 while (dowait(0, (struct job *)NULL) > 0);
6615 for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
6616 if (! jp->used)
6617 continue;
6618 if (jp->nprocs == 0) {
6619 freejob(jp);
6620 continue;
6621 }
6622 if (change && ! jp->changed)
6623 continue;
6624 procno = jp->nprocs;
Eric Andersen2870d962001-07-02 17:27:21 +00006625 for (ps = jp->ps ; ; ps++) { /* for each process */
Eric Andersencb57d552001-06-28 07:25:16 +00006626 if (ps == jp->ps)
Eric Andersen3102ac42001-07-06 04:26:23 +00006627 snprintf(s, 64, "[%d] %ld ", jobno,
Eric Andersencb57d552001-06-28 07:25:16 +00006628 (long)ps->pid);
6629 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006630 snprintf(s, 64, " %ld ",
Eric Andersencb57d552001-06-28 07:25:16 +00006631 (long)ps->pid);
6632 out1str(s);
6633 col = strlen(s);
6634 s[0] = '\0';
6635 if (ps->status == -1) {
6636 /* don't print anything */
6637 } else if (WIFEXITED(ps->status)) {
Eric Andersen3102ac42001-07-06 04:26:23 +00006638 snprintf(s, 64, "Exit %d",
Eric Andersencb57d552001-06-28 07:25:16 +00006639 WEXITSTATUS(ps->status));
6640 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00006641#ifdef JOBS
6642 if (WIFSTOPPED(ps->status))
Eric Andersencb57d552001-06-28 07:25:16 +00006643 i = WSTOPSIG(ps->status);
6644 else /* WIFSIGNALED(ps->status) */
6645#endif
6646 i = WTERMSIG(ps->status);
6647 if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
Eric Andersen2870d962001-07-02 17:27:21 +00006648 strcpy(s, sys_siglist[i & 0x7F]);
Eric Andersencb57d552001-06-28 07:25:16 +00006649 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006650 snprintf(s, 64, "Signal %d", i & 0x7F);
Eric Andersencb57d552001-06-28 07:25:16 +00006651 if (WCOREDUMP(ps->status))
6652 strcat(s, " (core dumped)");
6653 }
6654 out1str(s);
6655 col += strlen(s);
Eric Andersen62483552001-07-10 06:09:16 +00006656 printf(
Eric Andersencb57d552001-06-28 07:25:16 +00006657 "%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ',
6658 ps->cmd
6659 );
6660 if (--procno <= 0)
6661 break;
6662 }
6663 jp->changed = 0;
6664 if (jp->state == JOBDONE) {
6665 freejob(jp);
6666 }
6667 }
6668}
6669
6670
6671/*
6672 * Mark a job structure as unused.
6673 */
6674
6675static void
Eric Andersen62483552001-07-10 06:09:16 +00006676freejob(struct job *jp)
6677{
6678 const struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006679 int i;
6680
6681 INTOFF;
6682 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6683 if (ps->cmd != nullstr)
6684 ckfree(ps->cmd);
6685 }
6686 if (jp->ps != &jp->ps0)
6687 ckfree(jp->ps);
6688 jp->used = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006689#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006690 if (curjob == jp - jobtab + 1)
6691 curjob = 0;
6692#endif
6693 INTON;
6694}
6695
6696
6697
6698static int
6699waitcmd(argc, argv)
6700 int argc;
6701 char **argv;
6702{
6703 struct job *job;
6704 int status, retval;
6705 struct job *jp;
6706
6707 if (--argc > 0) {
6708start:
6709 job = getjob(*++argv);
6710 } else {
6711 job = NULL;
6712 }
Eric Andersen2870d962001-07-02 17:27:21 +00006713 for (;;) { /* loop until process terminated or stopped */
Eric Andersencb57d552001-06-28 07:25:16 +00006714 if (job != NULL) {
6715 if (job->state) {
6716 status = job->ps[job->nprocs - 1].status;
6717 if (! iflag)
6718 freejob(job);
6719 if (--argc) {
6720 goto start;
6721 }
6722 if (WIFEXITED(status))
6723 retval = WEXITSTATUS(status);
Eric Andersen2870d962001-07-02 17:27:21 +00006724#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006725 else if (WIFSTOPPED(status))
6726 retval = WSTOPSIG(status) + 128;
6727#endif
6728 else {
6729 /* XXX: limits number of signals */
6730 retval = WTERMSIG(status) + 128;
6731 }
6732 return retval;
6733 }
6734 } else {
6735 for (jp = jobtab ; ; jp++) {
Eric Andersen2870d962001-07-02 17:27:21 +00006736 if (jp >= jobtab + njobs) { /* no running procs */
Eric Andersencb57d552001-06-28 07:25:16 +00006737 return 0;
6738 }
6739 if (jp->used && jp->state == 0)
6740 break;
6741 }
6742 }
6743 if (dowait(2, 0) < 0 && errno == EINTR) {
6744 return 129;
6745 }
6746 }
6747}
6748
6749
6750
6751/*
6752 * Convert a job name to a job structure.
6753 */
6754
6755static struct job *
Eric Andersen2870d962001-07-02 17:27:21 +00006756getjob(const char *name)
6757{
Eric Andersencb57d552001-06-28 07:25:16 +00006758 int jobno;
6759 struct job *jp;
6760 int pid;
6761 int i;
6762
6763 if (name == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00006764#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006765currentjob:
6766 if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
6767 error("No current job");
6768 return &jobtab[jobno - 1];
6769#else
6770 error("No current job");
6771#endif
6772 } else if (name[0] == '%') {
6773 if (is_digit(name[1])) {
6774 jobno = number(name + 1);
6775 if (jobno > 0 && jobno <= njobs
6776 && jobtab[jobno - 1].used != 0)
6777 return &jobtab[jobno - 1];
Eric Andersen2870d962001-07-02 17:27:21 +00006778#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006779 } else if (name[1] == '%' && name[2] == '\0') {
6780 goto currentjob;
6781#endif
6782 } else {
6783 struct job *found = NULL;
6784 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
6785 if (jp->used && jp->nprocs > 0
6786 && prefix(name + 1, jp->ps[0].cmd)) {
6787 if (found)
6788 error("%s: ambiguous", name);
6789 found = jp;
6790 }
6791 }
6792 if (found)
6793 return found;
6794 }
Eric Andersen2870d962001-07-02 17:27:21 +00006795 } else if (is_number(name, &pid)) {
Eric Andersencb57d552001-06-28 07:25:16 +00006796 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
6797 if (jp->used && jp->nprocs > 0
6798 && jp->ps[jp->nprocs - 1].pid == pid)
6799 return jp;
6800 }
6801 }
6802 error("No such job: %s", name);
6803 /* NOTREACHED */
6804}
6805
6806
6807
6808/*
6809 * Return a new job structure,
6810 */
6811
Eric Andersen2870d962001-07-02 17:27:21 +00006812static struct job *
Eric Andersen62483552001-07-10 06:09:16 +00006813makejob(const union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00006814{
6815 int i;
6816 struct job *jp;
6817
6818 for (i = njobs, jp = jobtab ; ; jp++) {
6819 if (--i < 0) {
6820 INTOFF;
6821 if (njobs == 0) {
6822 jobtab = ckmalloc(4 * sizeof jobtab[0]);
6823 } else {
6824 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
6825 memcpy(jp, jobtab, njobs * sizeof jp[0]);
6826 /* Relocate `ps' pointers */
6827 for (i = 0; i < njobs; i++)
6828 if (jp[i].ps == &jobtab[i].ps0)
6829 jp[i].ps = &jp[i].ps0;
6830 ckfree(jobtab);
6831 jobtab = jp;
6832 }
6833 jp = jobtab + njobs;
6834 for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
6835 INTON;
6836 break;
6837 }
6838 if (jp->used == 0)
6839 break;
6840 }
6841 INTOFF;
6842 jp->state = 0;
6843 jp->used = 1;
6844 jp->changed = 0;
6845 jp->nprocs = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006846#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006847 jp->jobctl = jobctl;
6848#endif
6849 if (nprocs > 1) {
6850 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
6851 } else {
6852 jp->ps = &jp->ps0;
6853 }
6854 INTON;
6855 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
6856 jp - jobtab + 1));
6857 return jp;
6858}
6859
6860
6861/*
6862 * Fork of a subshell. If we are doing job control, give the subshell its
6863 * own process group. Jp is a job structure that the job is to be added to.
6864 * N is the command that will be evaluated by the child. Both jp and n may
6865 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00006866 * FORK_FG - Fork off a foreground process.
6867 * FORK_BG - Fork off a background process.
6868 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
6869 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00006870 *
6871 * When job control is turned off, background processes have their standard
6872 * input redirected to /dev/null (except for the second and later processes
6873 * in a pipeline).
6874 */
6875
Eric Andersen2870d962001-07-02 17:27:21 +00006876
6877
Eric Andersencb57d552001-06-28 07:25:16 +00006878static int
Eric Andersen62483552001-07-10 06:09:16 +00006879forkshell(struct job *jp, const union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00006880{
6881 int pid;
Eric Andersen62483552001-07-10 06:09:16 +00006882#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006883 int pgrp;
Eric Andersen62483552001-07-10 06:09:16 +00006884#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006885 const char *devnull = _PATH_DEVNULL;
6886 const char *nullerr = "Can't open %s";
6887
6888 TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
6889 mode));
6890 INTOFF;
6891 pid = fork();
6892 if (pid == -1) {
6893 TRACE(("Fork failed, errno=%d\n", errno));
6894 INTON;
6895 error("Cannot fork");
6896 }
6897 if (pid == 0) {
6898 struct job *p;
6899 int wasroot;
6900 int i;
6901
6902 TRACE(("Child shell %d\n", getpid()));
6903 wasroot = rootshell;
6904 rootshell = 0;
6905 closescript();
6906 INTON;
6907 clear_traps();
Eric Andersen2870d962001-07-02 17:27:21 +00006908#ifdef JOBS
6909 jobctl = 0; /* do job control only in root shell */
Eric Andersencb57d552001-06-28 07:25:16 +00006910 if (wasroot && mode != FORK_NOJOB && mflag) {
6911 if (jp == NULL || jp->nprocs == 0)
6912 pgrp = getpid();
6913 else
6914 pgrp = jp->ps[0].pid;
6915 setpgid(0, pgrp);
6916 if (mode == FORK_FG) {
6917 /*** this causes superfluous TIOCSPGRPS ***/
6918#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006919 if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006920 error("TIOCSPGRP failed, errno=%d", errno);
6921#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006922 if (tcsetpgrp(2, pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006923 error("tcsetpgrp failed, errno=%d", errno);
6924#endif
6925 }
6926 setsignal(SIGTSTP);
6927 setsignal(SIGTTOU);
6928 } else if (mode == FORK_BG) {
6929 ignoresig(SIGINT);
6930 ignoresig(SIGQUIT);
6931 if ((jp == NULL || jp->nprocs == 0) &&
6932 ! fd0_redirected_p ()) {
6933 close(0);
6934 if (open(devnull, O_RDONLY) != 0)
6935 error(nullerr, devnull);
6936 }
6937 }
6938#else
6939 if (mode == FORK_BG) {
6940 ignoresig(SIGINT);
6941 ignoresig(SIGQUIT);
6942 if ((jp == NULL || jp->nprocs == 0) &&
6943 ! fd0_redirected_p ()) {
6944 close(0);
6945 if (open(devnull, O_RDONLY) != 0)
6946 error(nullerr, devnull);
6947 }
6948 }
6949#endif
6950 for (i = njobs, p = jobtab ; --i >= 0 ; p++)
6951 if (p->used)
6952 freejob(p);
6953 if (wasroot && iflag) {
6954 setsignal(SIGINT);
6955 setsignal(SIGQUIT);
6956 setsignal(SIGTERM);
6957 }
6958 return pid;
6959 }
Eric Andersen62483552001-07-10 06:09:16 +00006960#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006961 if (rootshell && mode != FORK_NOJOB && mflag) {
6962 if (jp == NULL || jp->nprocs == 0)
6963 pgrp = pid;
6964 else
6965 pgrp = jp->ps[0].pid;
6966 setpgid(pid, pgrp);
6967 }
Eric Andersen62483552001-07-10 06:09:16 +00006968#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006969 if (mode == FORK_BG)
Eric Andersen2870d962001-07-02 17:27:21 +00006970 backgndpid = pid; /* set $! */
Eric Andersencb57d552001-06-28 07:25:16 +00006971 if (jp) {
6972 struct procstat *ps = &jp->ps[jp->nprocs++];
6973 ps->pid = pid;
6974 ps->status = -1;
6975 ps->cmd = nullstr;
6976 if (iflag && rootshell && n)
6977 ps->cmd = commandtext(n);
6978 }
6979 INTON;
6980 TRACE(("In parent shell: child = %d\n", pid));
6981 return pid;
6982}
6983
6984
6985
6986/*
6987 * Wait for job to finish.
6988 *
6989 * Under job control we have the problem that while a child process is
6990 * running interrupts generated by the user are sent to the child but not
6991 * to the shell. This means that an infinite loop started by an inter-
6992 * active user may be hard to kill. With job control turned off, an
6993 * interactive user may place an interactive program inside a loop. If
6994 * the interactive program catches interrupts, the user doesn't want
6995 * these interrupts to also abort the loop. The approach we take here
6996 * is to have the shell ignore interrupt signals while waiting for a
6997 * forground process to terminate, and then send itself an interrupt
6998 * signal if the child process was terminated by an interrupt signal.
6999 * Unfortunately, some programs want to do a bit of cleanup and then
7000 * exit on interrupt; unless these processes terminate themselves by
7001 * sending a signal to themselves (instead of calling exit) they will
7002 * confuse this approach.
7003 */
7004
7005static int
Eric Andersen62483552001-07-10 06:09:16 +00007006waitforjob(struct job *jp)
7007{
Eric Andersen2870d962001-07-02 17:27:21 +00007008#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007009 int mypgrp = getpgrp();
7010#endif
7011 int status;
7012 int st;
7013 struct sigaction act, oact;
7014
7015 INTOFF;
7016 intreceived = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00007017#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007018 if (!jobctl) {
7019#else
7020 if (!iflag) {
7021#endif
7022 sigaction(SIGINT, 0, &act);
7023 act.sa_handler = waitonint;
7024 sigaction(SIGINT, &act, &oact);
7025 }
7026 TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
7027 while (jp->state == 0) {
7028 dowait(1, jp);
7029 }
Eric Andersen2870d962001-07-02 17:27:21 +00007030#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007031 if (!jobctl) {
7032#else
7033 if (!iflag) {
7034#endif
7035 sigaction(SIGINT, &oact, 0);
7036 if (intreceived && trap[SIGINT]) kill(getpid(), SIGINT);
7037 }
Eric Andersen2870d962001-07-02 17:27:21 +00007038#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007039 if (jp->jobctl) {
7040#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00007041 if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007042 error("TIOCSPGRP failed, errno=%d\n", errno);
7043#else
Eric Andersen3102ac42001-07-06 04:26:23 +00007044 if (tcsetpgrp(2, mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007045 error("tcsetpgrp failed, errno=%d\n", errno);
7046#endif
7047 }
7048 if (jp->state == JOBSTOPPED)
7049 curjob = jp - jobtab + 1;
7050#endif
7051 status = jp->ps[jp->nprocs - 1].status;
7052 /* convert to 8 bits */
7053 if (WIFEXITED(status))
7054 st = WEXITSTATUS(status);
Eric Andersen2870d962001-07-02 17:27:21 +00007055#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007056 else if (WIFSTOPPED(status))
7057 st = WSTOPSIG(status) + 128;
7058#endif
7059 else
7060 st = WTERMSIG(status) + 128;
Eric Andersen2870d962001-07-02 17:27:21 +00007061#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007062 if (jp->jobctl) {
7063 /*
7064 * This is truly gross.
7065 * If we're doing job control, then we did a TIOCSPGRP which
7066 * caused us (the shell) to no longer be in the controlling
7067 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7068 * intuit from the subprocess exit status whether a SIGINT
7069 * occured, and if so interrupt ourselves. Yuck. - mycroft
7070 */
7071 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
7072 raise(SIGINT);
7073 }
Eric Andersen2870d962001-07-02 17:27:21 +00007074 if (jp->state == JOBDONE)
7075
Eric Andersencb57d552001-06-28 07:25:16 +00007076#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007077 freejob(jp);
7078 INTON;
7079 return st;
7080}
7081
7082
7083
7084/*
7085 * Wait for a process to terminate.
7086 */
7087
Eric Andersen62483552001-07-10 06:09:16 +00007088/*
7089 * Do a wait system call. If job control is compiled in, we accept
7090 * stopped processes. If block is zero, we return a value of zero
7091 * rather than blocking.
7092 *
7093 * System V doesn't have a non-blocking wait system call. It does
7094 * have a SIGCLD signal that is sent to a process when one of it's
7095 * children dies. The obvious way to use SIGCLD would be to install
7096 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7097 * was received, and have waitproc bump another counter when it got
7098 * the status of a process. Waitproc would then know that a wait
7099 * system call would not block if the two counters were different.
7100 * This approach doesn't work because if a process has children that
7101 * have not been waited for, System V will send it a SIGCLD when it
7102 * installs a signal handler for SIGCLD. What this means is that when
7103 * a child exits, the shell will be sent SIGCLD signals continuously
7104 * until is runs out of stack space, unless it does a wait call before
7105 * restoring the signal handler. The code below takes advantage of
7106 * this (mis)feature by installing a signal handler for SIGCLD and
7107 * then checking to see whether it was called. If there are any
7108 * children to be waited for, it will be.
7109 *
7110 */
7111
7112static inline int
7113waitproc(int block, int *status)
7114{
7115 int flags;
7116
7117 flags = 0;
7118#ifdef JOBS
7119 if (jobctl)
7120 flags |= WUNTRACED;
7121#endif
7122 if (block == 0)
7123 flags |= WNOHANG;
7124 return wait3(status, flags, (struct rusage *)NULL);
7125}
7126
Eric Andersencb57d552001-06-28 07:25:16 +00007127static int
Eric Andersen62483552001-07-10 06:09:16 +00007128dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00007129{
7130 int pid;
7131 int status;
7132 struct procstat *sp;
7133 struct job *jp;
7134 struct job *thisjob;
7135 int done;
7136 int stopped;
7137 int core;
7138 int sig;
7139
7140 TRACE(("dowait(%d) called\n", block));
7141 do {
7142 pid = waitproc(block, &status);
7143 TRACE(("wait returns %d, status=%d\n", pid, status));
7144 } while (!(block & 2) && pid == -1 && errno == EINTR);
7145 if (pid <= 0)
7146 return pid;
7147 INTOFF;
7148 thisjob = NULL;
7149 for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
7150 if (jp->used) {
7151 done = 1;
7152 stopped = 1;
7153 for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
7154 if (sp->pid == -1)
7155 continue;
7156 if (sp->pid == pid) {
7157 TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
7158 sp->status = status;
7159 thisjob = jp;
7160 }
7161 if (sp->status == -1)
7162 stopped = 0;
7163 else if (WIFSTOPPED(sp->status))
7164 done = 0;
7165 }
Eric Andersen2870d962001-07-02 17:27:21 +00007166 if (stopped) { /* stopped or done */
Eric Andersencb57d552001-06-28 07:25:16 +00007167 int state = done? JOBDONE : JOBSTOPPED;
7168 if (jp->state != state) {
7169 TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
7170 jp->state = state;
Eric Andersen2870d962001-07-02 17:27:21 +00007171#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007172 if (done && curjob == jp - jobtab + 1)
Eric Andersen2870d962001-07-02 17:27:21 +00007173 curjob = 0; /* no current job */
Eric Andersencb57d552001-06-28 07:25:16 +00007174#endif
7175 }
7176 }
7177 }
7178 }
7179 INTON;
7180 if (! rootshell || ! iflag || (job && thisjob == job)) {
7181 core = WCOREDUMP(status);
Eric Andersen2870d962001-07-02 17:27:21 +00007182#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007183 if (WIFSTOPPED(status)) sig = WSTOPSIG(status);
7184 else
7185#endif
7186 if (WIFEXITED(status)) sig = 0;
7187 else sig = WTERMSIG(status);
7188
7189 if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
7190 if (thisjob != job)
Eric Andersen3102ac42001-07-06 04:26:23 +00007191 out2fmt("%d: ", pid);
Eric Andersen2870d962001-07-02 17:27:21 +00007192#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007193 if (sig == SIGTSTP && rootshell && iflag)
Eric Andersen3102ac42001-07-06 04:26:23 +00007194 out2fmt("%%%ld ",
Eric Andersencb57d552001-06-28 07:25:16 +00007195 (long)(job - jobtab + 1));
7196#endif
7197 if (sig < NSIG && sys_siglist[sig])
7198 out2str(sys_siglist[sig]);
7199 else
Eric Andersen3102ac42001-07-06 04:26:23 +00007200 out2fmt("Signal %d", sig);
Eric Andersencb57d552001-06-28 07:25:16 +00007201 if (core)
7202 out2str(" - core dumped");
7203 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00007204 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00007205 TRACE(("Not printing status: status=%d, sig=%d\n",
Eric Andersencb57d552001-06-28 07:25:16 +00007206 status, sig));
7207 }
7208 } else {
7209 TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
7210 if (thisjob)
7211 thisjob->changed = 1;
7212 }
7213 return pid;
7214}
7215
7216
7217
Eric Andersencb57d552001-06-28 07:25:16 +00007218
7219/*
7220 * return 1 if there are stopped jobs, otherwise 0
7221 */
Eric Andersencb57d552001-06-28 07:25:16 +00007222static int
Eric Andersen2870d962001-07-02 17:27:21 +00007223stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007224{
7225 int jobno;
7226 struct job *jp;
7227
7228 if (job_warning)
7229 return (0);
7230 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
7231 if (jp->used == 0)
7232 continue;
7233 if (jp->state == JOBSTOPPED) {
7234 out2str("You have stopped jobs.\n");
7235 job_warning = 2;
7236 return (1);
7237 }
7238 }
7239
7240 return (0);
7241}
7242
7243/*
7244 * Return a string identifying a command (to be printed by the
7245 * jobs command.
7246 */
7247
7248static char *cmdnextc;
7249static int cmdnleft;
Eric Andersen2870d962001-07-02 17:27:21 +00007250#define MAXCMDTEXT 200
Eric Andersencb57d552001-06-28 07:25:16 +00007251
Eric Andersen2870d962001-07-02 17:27:21 +00007252static void
7253cmdputs(const char *s)
7254{
7255 const char *p;
7256 char *q;
7257 char c;
7258 int subtype = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007259
Eric Andersen2870d962001-07-02 17:27:21 +00007260 if (cmdnleft <= 0)
7261 return;
7262 p = s;
7263 q = cmdnextc;
7264 while ((c = *p++) != '\0') {
7265 if (c == CTLESC)
7266 *q++ = *p++;
7267 else if (c == CTLVAR) {
7268 *q++ = '$';
7269 if (--cmdnleft > 0)
7270 *q++ = '{';
7271 subtype = *p++;
7272 } else if (c == '=' && subtype != 0) {
7273 *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
7274 subtype = 0;
7275 } else if (c == CTLENDVAR) {
7276 *q++ = '}';
7277 } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
7278 cmdnleft++; /* ignore it */
7279 else
7280 *q++ = c;
7281 if (--cmdnleft <= 0) {
7282 *q++ = '.';
7283 *q++ = '.';
7284 *q++ = '.';
7285 break;
7286 }
7287 }
7288 cmdnextc = q;
Eric Andersencb57d552001-06-28 07:25:16 +00007289}
7290
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00007291#define CMDTXT_TABLE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007292#ifdef CMDTXT_TABLE
7293/*
7294 * To collect a lot of redundant code in cmdtxt() case statements, we
7295 * implement a mini language here. Each type of node struct has an
7296 * associated instruction sequence that operates on its members via
7297 * their offsets. The instruction are pack in unsigned chars with
7298 * format IIDDDDDE where the bits are
7299 * I : part of the instruction opcode, which are
7300 * 00 : member is a pointer to another node -- process it recursively
7301 * 40 : member is a pointer to a char string -- output it
7302 * 80 : output the string whose index is stored in the data field
7303 * CC : flag signaling that this case needs external processing
7304 * D : data - either the (shifted) index of a fixed string to output or
7305 * the actual offset of the member to operate on in the struct
7306 * (since we assume bit 0 is set, the offset is not shifted)
7307 * E : flag signaling end of instruction sequence
7308 *
7309 * WARNING: In order to handle larger offsets for 64bit archs, this code
7310 * assumes that no offset can be an odd number and stores the
7311 * end-of-instructions flag in bit 0.
7312 */
Eric Andersencb57d552001-06-28 07:25:16 +00007313
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007314#define CMDTXT_NOMORE 0x01 /* NOTE: no offset should be odd */
7315#define CMDTXT_CHARPTR 0x40
7316#define CMDTXT_STRING 0x80
7317#define CMDTXT_SPECIAL 0xC0
7318#define CMDTXT_OFFSETMASK 0x3E
7319
7320static const char * const cmdtxt_strings[] = {
7321 /* 0 1 2 3 4 5 6 7 */
7322 "; ", "(", ")", " && ", " || ", "if ", "; then ", "...",
7323 /* 8 9 10 11 12 13 */
7324 "while ", "; do ", "; done", "until ", "for ", " in ...",
7325 /* 14 15 16 17 */
7326 "case ", "???", "() ...", "<<..."
7327};
7328
7329static const char * const redir_strings[] = {
7330 ">", "<", "<>", ">>", ">|", ">&", "<&"
7331};
7332
7333static const unsigned char cmdtxt_ops[] = {
7334#define CMDTXT_NSEMI 0
7335 offsetof(union node, nbinary.ch1),
7336 0|CMDTXT_STRING,
7337 offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7338#define CMDTXT_NCMD (CMDTXT_NSEMI + 3)
7339#define CMDTXT_NPIPE (CMDTXT_NCMD)
7340#define CMDTXT_NCASE (CMDTXT_NCMD)
7341#define CMDTXT_NTO (CMDTXT_NCMD)
7342#define CMDTXT_NFROM (CMDTXT_NCMD)
7343#define CMDTXT_NFROMTO (CMDTXT_NCMD)
7344#define CMDTXT_NAPPEND (CMDTXT_NCMD)
7345#define CMDTXT_NTOOV (CMDTXT_NCMD)
7346#define CMDTXT_NTOFD (CMDTXT_NCMD)
7347#define CMDTXT_NFROMFD (CMDTXT_NCMD)
7348 CMDTXT_SPECIAL,
7349#define CMDTXT_NREDIR (CMDTXT_NPIPE + 1)
7350#define CMDTXT_NBACKGND (CMDTXT_NREDIR)
7351 offsetof(union node, nredir.n)|CMDTXT_NOMORE,
7352#define CMDTXT_NSUBSHELL (CMDTXT_NBACKGND + 1)
7353 (1*2)|CMDTXT_STRING,
7354 offsetof(union node, nredir.n),
7355 (2*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7356#define CMDTXT_NAND (CMDTXT_NSUBSHELL + 3)
7357 offsetof(union node, nbinary.ch1),
7358 (3*2)|CMDTXT_STRING,
7359 offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7360#define CMDTXT_NOR (CMDTXT_NAND + 3)
7361 offsetof(union node, nbinary.ch1),
7362 (4*2)|CMDTXT_STRING,
7363 offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7364#define CMDTXT_NIF (CMDTXT_NOR + 3)
7365 (5*2)|CMDTXT_STRING,
7366 offsetof(union node, nif.test),
7367 (6*2)|CMDTXT_STRING,
7368 offsetof(union node, nif.ifpart),
7369 (7*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7370#define CMDTXT_NWHILE (CMDTXT_NIF + 5)
7371 (8*2)|CMDTXT_STRING,
7372 offsetof(union node, nbinary.ch1),
7373 (9*2)|CMDTXT_STRING,
7374 offsetof(union node, nbinary.ch2),
7375 (10*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7376#define CMDTXT_NUNTIL (CMDTXT_NWHILE + 5)
7377 (11*2)|CMDTXT_STRING,
7378 offsetof(union node, nbinary.ch1),
7379 (9*2)|CMDTXT_STRING,
7380 offsetof(union node, nbinary.ch2),
7381 (10*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7382#define CMDTXT_NFOR (CMDTXT_NUNTIL + 5)
7383 (12*2)|CMDTXT_STRING,
7384 offsetof(union node, nfor.var)|CMDTXT_CHARPTR,
7385 (13*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7386#define CMDTXT_NCLIST (CMDTXT_NFOR + 3) /* TODO: IS THIS CORRECT??? */
7387#define CMDTXT_NNOT (CMDTXT_NCLIST) /* TODO: IS THIS CORRECT??? */
7388 (15*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7389#define CMDTXT_NDEFUN (CMDTXT_NCLIST + 1)
7390 offsetof(union node, narg.text)|CMDTXT_CHARPTR,
7391 (16*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7392#define CMDTXT_NARG (CMDTXT_NDEFUN + 2)
7393 offsetof(union node, narg.text)|CMDTXT_CHARPTR|CMDTXT_NOMORE,
7394#define CMDTXT_NHERE (CMDTXT_NARG + 1)
7395#define CMDTXT_NXHERE (CMDTXT_NHERE)
7396 (17*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7397};
7398
7399#if CMDTXT_NXHERE != 36
7400#error CMDTXT_NXHERE
7401#endif
7402
7403static const unsigned char cmdtxt_ops_index[26] = {
7404 CMDTXT_NSEMI,
7405 CMDTXT_NCMD,
7406 CMDTXT_NPIPE,
7407 CMDTXT_NREDIR,
7408 CMDTXT_NBACKGND,
7409 CMDTXT_NSUBSHELL,
7410 CMDTXT_NAND,
7411 CMDTXT_NOR,
7412 CMDTXT_NIF,
7413 CMDTXT_NWHILE,
7414 CMDTXT_NUNTIL,
7415 CMDTXT_NFOR,
7416 CMDTXT_NCASE,
7417 CMDTXT_NCLIST,
7418 CMDTXT_NDEFUN,
7419 CMDTXT_NARG,
7420 CMDTXT_NTO,
7421 CMDTXT_NFROM,
7422 CMDTXT_NFROMTO,
7423 CMDTXT_NAPPEND,
7424 CMDTXT_NTOOV,
7425 CMDTXT_NTOFD,
7426 CMDTXT_NFROMFD,
7427 CMDTXT_NHERE,
7428 CMDTXT_NXHERE,
7429 CMDTXT_NNOT,
7430};
7431
7432static void
7433cmdtxt(const union node *n)
7434{
7435 const char *p;
7436
7437 if (n == NULL)
7438 return;
7439
7440 p = cmdtxt_ops + (int) cmdtxt_ops_index[n->type];
7441 if ((*p & CMDTXT_SPECIAL) != CMDTXT_SPECIAL) { /* normal case */
7442 do {
7443 if (*p & CMDTXT_STRING) { /* output fixed string */
7444 cmdputs(cmdtxt_strings[((int)(*p & CMDTXT_OFFSETMASK) >> 1)]);
Manuel Novoa III c639a352001-08-12 17:32:56 +00007445 } else {
7446 const char *pf = ((const char *) n)
7447 + ((int)(*p & CMDTXT_OFFSETMASK));
7448 if (*p & CMDTXT_CHARPTR) { /* output dynamic string */
7449 cmdputs(*((const char **) pf));
7450 } else { /* output field */
7451 cmdtxt(*((const union node **) pf));
7452 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007453 }
7454 } while (!(*p++ & CMDTXT_NOMORE));
7455 } else if (n->type == NCMD) {
7456 union node *np;
7457 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7458 cmdtxt(np);
7459 if (np->narg.next)
7460 cmdputs(spcstr);
7461 }
7462 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7463 cmdputs(spcstr);
7464 cmdtxt(np);
7465 }
7466 } else if (n->type == NPIPE) {
7467 struct nodelist *lp;
7468 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7469 cmdtxt(lp->n);
7470 if (lp->next)
7471 cmdputs(" | ");
7472 }
7473 } else if (n->type == NCASE) {
7474 cmdputs(cmdtxt_strings[14]);
7475 cmdputs(n->ncase.expr->narg.text);
7476 cmdputs(cmdtxt_strings[13]);
7477 } else {
7478#if (NTO != 16) || (NFROM != 17) || (NFROMTO != 18) || (NAPPEND != 19) || (NTOOV != 20) || (NTOFD != 21) || (NFROMFD != 22)
7479#error Assumption violated regarding range and ordering of NTO ... NFROMFD!
7480#endif
7481 char s[2];
7482
7483#ifdef DEBUG
7484 assert((n->type >= NTO) && (n->type <= NFROMFD));
7485#endif
7486
7487 p = redir_strings[n->type - NTO];
7488 if (n->nfile.fd != ('>' == *p)) {
7489 s[0] = n->nfile.fd + '0';
7490 s[1] = '\0';
7491 cmdputs(s);
7492 }
7493 cmdputs(p);
7494 if (n->type >= NTOFD) {
7495 s[0] = n->ndup.dupfd + '0';
7496 s[1] = '\0';
7497 cmdputs(s);
7498 } else {
7499 cmdtxt(n->nfile.fname);
7500 }
7501 }
7502}
7503#else /* CMDTXT_TABLE */
Eric Andersencb57d552001-06-28 07:25:16 +00007504static void
Eric Andersen2870d962001-07-02 17:27:21 +00007505cmdtxt(const union node *n)
7506{
Eric Andersencb57d552001-06-28 07:25:16 +00007507 union node *np;
7508 struct nodelist *lp;
7509 const char *p;
7510 int i;
7511 char s[2];
7512
7513 if (n == NULL)
7514 return;
7515 switch (n->type) {
7516 case NSEMI:
7517 cmdtxt(n->nbinary.ch1);
7518 cmdputs("; ");
7519 cmdtxt(n->nbinary.ch2);
7520 break;
7521 case NAND:
7522 cmdtxt(n->nbinary.ch1);
7523 cmdputs(" && ");
7524 cmdtxt(n->nbinary.ch2);
7525 break;
7526 case NOR:
7527 cmdtxt(n->nbinary.ch1);
7528 cmdputs(" || ");
7529 cmdtxt(n->nbinary.ch2);
7530 break;
7531 case NPIPE:
7532 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7533 cmdtxt(lp->n);
7534 if (lp->next)
7535 cmdputs(" | ");
7536 }
7537 break;
7538 case NSUBSHELL:
7539 cmdputs("(");
7540 cmdtxt(n->nredir.n);
7541 cmdputs(")");
7542 break;
7543 case NREDIR:
7544 case NBACKGND:
7545 cmdtxt(n->nredir.n);
7546 break;
7547 case NIF:
7548 cmdputs("if ");
7549 cmdtxt(n->nif.test);
7550 cmdputs("; then ");
7551 cmdtxt(n->nif.ifpart);
7552 cmdputs("...");
7553 break;
7554 case NWHILE:
7555 cmdputs("while ");
7556 goto until;
7557 case NUNTIL:
7558 cmdputs("until ");
7559until:
7560 cmdtxt(n->nbinary.ch1);
7561 cmdputs("; do ");
7562 cmdtxt(n->nbinary.ch2);
7563 cmdputs("; done");
7564 break;
7565 case NFOR:
7566 cmdputs("for ");
7567 cmdputs(n->nfor.var);
7568 cmdputs(" in ...");
7569 break;
7570 case NCASE:
7571 cmdputs("case ");
7572 cmdputs(n->ncase.expr->narg.text);
7573 cmdputs(" in ...");
7574 break;
7575 case NDEFUN:
7576 cmdputs(n->narg.text);
7577 cmdputs("() ...");
7578 break;
7579 case NCMD:
7580 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7581 cmdtxt(np);
7582 if (np->narg.next)
7583 cmdputs(spcstr);
7584 }
7585 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7586 cmdputs(spcstr);
7587 cmdtxt(np);
7588 }
7589 break;
7590 case NARG:
7591 cmdputs(n->narg.text);
7592 break;
7593 case NTO:
7594 p = ">"; i = 1; goto redir;
7595 case NAPPEND:
7596 p = ">>"; i = 1; goto redir;
7597 case NTOFD:
7598 p = ">&"; i = 1; goto redir;
7599 case NTOOV:
7600 p = ">|"; i = 1; goto redir;
7601 case NFROM:
7602 p = "<"; i = 0; goto redir;
7603 case NFROMFD:
7604 p = "<&"; i = 0; goto redir;
7605 case NFROMTO:
7606 p = "<>"; i = 0; goto redir;
7607redir:
7608 if (n->nfile.fd != i) {
7609 s[0] = n->nfile.fd + '0';
7610 s[1] = '\0';
7611 cmdputs(s);
7612 }
7613 cmdputs(p);
7614 if (n->type == NTOFD || n->type == NFROMFD) {
7615 s[0] = n->ndup.dupfd + '0';
7616 s[1] = '\0';
7617 cmdputs(s);
7618 } else {
7619 cmdtxt(n->nfile.fname);
7620 }
7621 break;
7622 case NHERE:
7623 case NXHERE:
7624 cmdputs("<<...");
7625 break;
7626 default:
7627 cmdputs("???");
7628 break;
7629 }
7630}
Manuel Novoa III c639a352001-08-12 17:32:56 +00007631#endif /* CMDTXT_TABLE */
Eric Andersencb57d552001-06-28 07:25:16 +00007632
Eric Andersen2870d962001-07-02 17:27:21 +00007633static char *
7634commandtext(const union node *n)
7635{
7636 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007637
Eric Andersen2870d962001-07-02 17:27:21 +00007638 cmdnextc = name = ckmalloc(MAXCMDTEXT);
7639 cmdnleft = MAXCMDTEXT - 4;
7640 cmdtxt(n);
7641 *cmdnextc = '\0';
7642 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00007643}
7644
Eric Andersen2870d962001-07-02 17:27:21 +00007645
Eric Andersencb57d552001-06-28 07:25:16 +00007646static void waitonint(int sig) {
7647 intreceived = 1;
7648 return;
7649}
Eric Andersencb57d552001-06-28 07:25:16 +00007650/*
7651 * Routines to check for mail. (Perhaps make part of main.c?)
7652 */
7653
7654
7655#define MAXMBOXES 10
7656
7657
Eric Andersen2870d962001-07-02 17:27:21 +00007658static int nmboxes; /* number of mailboxes */
7659static time_t mailtime[MAXMBOXES]; /* times of mailboxes */
Eric Andersencb57d552001-06-28 07:25:16 +00007660
7661
7662
7663/*
7664 * Print appropriate message(s) if mail has arrived. If the argument is
7665 * nozero, then the value of MAIL has changed, so we just update the
7666 * values.
7667 */
7668
7669static void
Eric Andersen2870d962001-07-02 17:27:21 +00007670chkmail(int silent)
Eric Andersencb57d552001-06-28 07:25:16 +00007671{
7672 int i;
7673 const char *mpath;
7674 char *p;
7675 char *q;
7676 struct stackmark smark;
7677 struct stat statb;
7678
7679 if (silent)
7680 nmboxes = 10;
7681 if (nmboxes == 0)
7682 return;
7683 setstackmark(&smark);
7684 mpath = mpathset()? mpathval() : mailval();
7685 for (i = 0 ; i < nmboxes ; i++) {
7686 p = padvance(&mpath, nullstr);
7687 if (p == NULL)
7688 break;
7689 if (*p == '\0')
7690 continue;
7691 for (q = p ; *q ; q++);
7692#ifdef DEBUG
7693 if (q[-1] != '/')
7694 abort();
7695#endif
Eric Andersen2870d962001-07-02 17:27:21 +00007696 q[-1] = '\0'; /* delete trailing '/' */
Eric Andersencb57d552001-06-28 07:25:16 +00007697 if (stat(p, &statb) < 0)
7698 statb.st_size = 0;
7699 if (statb.st_size > mailtime[i] && ! silent) {
Eric Andersen3102ac42001-07-06 04:26:23 +00007700 out2fmt(snlfmt,
7701 pathopt? pathopt : "you have mail");
Eric Andersencb57d552001-06-28 07:25:16 +00007702 }
7703 mailtime[i] = statb.st_size;
Eric Andersencb57d552001-06-28 07:25:16 +00007704 }
7705 nmboxes = i;
7706 popstackmark(&smark);
7707}
Eric Andersencb57d552001-06-28 07:25:16 +00007708
7709#define PROFILE 0
7710
Eric Andersencb57d552001-06-28 07:25:16 +00007711#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007712static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007713extern int etext();
7714#endif
7715
Eric Andersen2870d962001-07-02 17:27:21 +00007716static void read_profile (const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007717static void cmdloop (int);
7718static void options (int);
Eric Andersen2870d962001-07-02 17:27:21 +00007719static void setoption (int, int);
7720static void procargs (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00007721
Eric Andersen2870d962001-07-02 17:27:21 +00007722
Eric Andersencb57d552001-06-28 07:25:16 +00007723/*
7724 * Main routine. We initialize things, parse the arguments, execute
7725 * profiles if we're a login shell, and then call cmdloop to execute
7726 * commands. The setjmp call sets up the location to jump to when an
7727 * exception occurs. When an exception occurs the variable "state"
7728 * is used to figure out how far we had gotten.
7729 */
7730
7731int
Matt Kraai2d91deb2001-08-01 17:21:35 +00007732ash_main(argc, argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007733 int argc;
7734 char **argv;
7735{
7736 struct jmploc jmploc;
7737 struct stackmark smark;
7738 volatile int state;
Eric Andersen62483552001-07-10 06:09:16 +00007739 const char *shinit;
Eric Andersencb57d552001-06-28 07:25:16 +00007740
Eric Andersencb57d552001-06-28 07:25:16 +00007741 BLTINCMD = find_builtin("builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00007742 EXECCMD = find_builtin("exec");
7743 EVALCMD = find_builtin("eval");
7744
Eric Andersen1c039232001-07-07 00:05:55 +00007745#ifndef BB_FEATURE_SH_FANCY_PROMPT
7746 unsetenv("PS1");
7747 unsetenv("PS2");
7748#endif
7749
Eric Andersencb57d552001-06-28 07:25:16 +00007750#if PROFILE
7751 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7752#endif
7753#if defined(linux) || defined(__GNU__)
7754 signal(SIGCHLD, SIG_DFL);
7755#endif
7756 state = 0;
7757 if (setjmp(jmploc.loc)) {
7758 INTOFF;
7759 /*
7760 * When a shell procedure is executed, we raise the
7761 * exception EXSHELLPROC to clean up before executing
7762 * the shell procedure.
7763 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007764 if (exception == EXSHELLPROC) {
Eric Andersencb57d552001-06-28 07:25:16 +00007765 rootpid = getpid();
7766 rootshell = 1;
7767 minusc = NULL;
7768 state = 3;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007769 } else {
7770 if (exception == EXEXEC) {
7771 exitstatus = exerrno;
7772 } else if (exception == EXERROR) {
7773 exitstatus = 2;
7774 }
Eric Andersencb57d552001-06-28 07:25:16 +00007775 if (state == 0 || iflag == 0 || ! rootshell)
7776 exitshell(exitstatus);
7777 }
7778 reset();
Eric Andersen2870d962001-07-02 17:27:21 +00007779 if (exception == EXINT) {
Eric Andersencb57d552001-06-28 07:25:16 +00007780 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00007781 }
7782 popstackmark(&smark);
Eric Andersen2870d962001-07-02 17:27:21 +00007783 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007784 if (state == 1)
7785 goto state1;
7786 else if (state == 2)
7787 goto state2;
7788 else if (state == 3)
7789 goto state3;
7790 else
7791 goto state4;
7792 }
7793 handler = &jmploc;
7794#ifdef DEBUG
7795 opentrace();
7796 trputs("Shell args: "); trargs(argv);
7797#endif
7798 rootpid = getpid();
7799 rootshell = 1;
7800 init();
7801 setstackmark(&smark);
7802 procargs(argc, argv);
7803 if (argv[0] && argv[0][0] == '-') {
7804 state = 1;
7805 read_profile("/etc/profile");
7806state1:
7807 state = 2;
7808 read_profile(".profile");
7809 }
7810state2:
7811 state = 3;
7812#ifndef linux
7813 if (getuid() == geteuid() && getgid() == getegid()) {
7814#endif
7815 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7816 state = 3;
7817 read_profile(shinit);
7818 }
7819#ifndef linux
7820 }
7821#endif
7822state3:
7823 state = 4;
7824 if (sflag == 0 || minusc) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007825 static const char sigs[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00007826 SIGINT, SIGQUIT, SIGHUP,
Eric Andersencb57d552001-06-28 07:25:16 +00007827#ifdef SIGTSTP
7828 SIGTSTP,
7829#endif
7830 SIGPIPE
7831 };
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007832#define SIGSSIZE ((sizeof(sigs)/sizeof(sigs[0])) - 1) /* trailing nul */
Eric Andersencb57d552001-06-28 07:25:16 +00007833 int i;
7834
7835 for (i = 0; i < SIGSSIZE; i++)
7836 setsignal(sigs[i]);
7837 }
7838
7839 if (minusc)
7840 evalstring(minusc, 0);
7841
7842 if (sflag || minusc == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00007843state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007844 cmdloop(1);
7845 }
7846#if PROFILE
7847 monitor(0);
7848#endif
7849 exitshell(exitstatus);
7850 /* NOTREACHED */
7851}
7852
7853
7854/*
7855 * Read and execute commands. "Top" is nonzero for the top level command
7856 * loop; it turns on prompting if the shell is interactive.
7857 */
7858
7859static void
Eric Andersen2870d962001-07-02 17:27:21 +00007860cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00007861{
7862 union node *n;
7863 struct stackmark smark;
7864 int inter;
7865 int numeof = 0;
7866
7867 TRACE(("cmdloop(%d) called\n", top));
7868 setstackmark(&smark);
7869 for (;;) {
7870 if (pendingsigs)
7871 dotrap();
7872 inter = 0;
7873 if (iflag && top) {
7874 inter++;
7875 showjobs(1);
7876 chkmail(0);
Eric Andersen3102ac42001-07-06 04:26:23 +00007877 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00007878 }
7879 n = parsecmd(inter);
7880 /* showtree(n); DEBUG */
7881 if (n == NEOF) {
7882 if (!top || numeof >= 50)
7883 break;
7884 if (!stoppedjobs()) {
7885 if (!Iflag)
7886 break;
7887 out2str("\nUse \"exit\" to leave shell.\n");
7888 }
7889 numeof++;
7890 } else if (n != NULL && nflag == 0) {
7891 job_warning = (job_warning == 2) ? 1 : 0;
7892 numeof = 0;
7893 evaltree(n, 0);
7894 }
7895 popstackmark(&smark);
7896 setstackmark(&smark);
7897 if (evalskip == SKIPFILE) {
7898 evalskip = 0;
7899 break;
7900 }
7901 }
7902 popstackmark(&smark);
7903}
7904
7905
7906
7907/*
7908 * Read /etc/profile or .profile. Return on error.
7909 */
7910
7911static void
7912read_profile(name)
7913 const char *name;
7914{
7915 int fd;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007916 int xflag_save;
7917 int vflag_save;
Eric Andersencb57d552001-06-28 07:25:16 +00007918
7919 INTOFF;
7920 if ((fd = open(name, O_RDONLY)) >= 0)
7921 setinputfd(fd, 1);
7922 INTON;
7923 if (fd < 0)
7924 return;
7925 /* -q turns off -x and -v just when executing init files */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007926 /* Note: Might do a little redundant work, but reduces code size. */
7927 xflag_save = xflag;
7928 vflag_save = vflag;
Eric Andersencb57d552001-06-28 07:25:16 +00007929 if (qflag) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007930 vflag = xflag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007931 }
7932 cmdloop(0);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007933 xflag = xflag_save;
7934 vflag = vflag_save;
Eric Andersencb57d552001-06-28 07:25:16 +00007935 popfile();
7936}
7937
7938
7939
7940/*
7941 * Read a file containing shell functions.
7942 */
7943
7944static void
Eric Andersen2870d962001-07-02 17:27:21 +00007945readcmdfile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00007946{
7947 int fd;
7948
7949 INTOFF;
7950 if ((fd = open(name, O_RDONLY)) >= 0)
7951 setinputfd(fd, 1);
7952 else
7953 error("Can't open %s", name);
7954 INTON;
7955 cmdloop(0);
7956 popfile();
7957}
7958
7959
7960
7961/*
7962 * Take commands from a file. To be compatable we should do a path
7963 * search for the file, which is necessary to find sub-commands.
7964 */
7965
7966
Eric Andersen62483552001-07-10 06:09:16 +00007967static inline char *
Eric Andersen74400cc2001-10-18 04:11:39 +00007968find_dot_file(char *mybasename)
Eric Andersencb57d552001-06-28 07:25:16 +00007969{
7970 char *fullname;
7971 const char *path = pathval();
7972 struct stat statb;
7973
7974 /* don't try this for absolute or relative paths */
7975 if (strchr(mybasename, '/'))
7976 return mybasename;
7977
7978 while ((fullname = padvance(&path, mybasename)) != NULL) {
7979 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
7980 /*
7981 * Don't bother freeing here, since it will
7982 * be freed by the caller.
7983 */
7984 return fullname;
7985 }
7986 stunalloc(fullname);
7987 }
7988
7989 /* not found in the PATH */
7990 error("%s: not found", mybasename);
7991 /* NOTREACHED */
7992}
7993
7994static int
7995dotcmd(argc, argv)
7996 int argc;
7997 char **argv;
7998{
7999 struct strlist *sp;
8000 exitstatus = 0;
8001
8002 for (sp = cmdenviron; sp ; sp = sp->next)
8003 setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
8004
Eric Andersen2870d962001-07-02 17:27:21 +00008005 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00008006 char *fullname;
8007 struct stackmark smark;
8008
8009 setstackmark(&smark);
8010 fullname = find_dot_file(argv[1]);
8011 setinputfile(fullname, 1);
8012 commandname = fullname;
8013 cmdloop(0);
8014 popfile();
8015 popstackmark(&smark);
8016 }
8017 return exitstatus;
8018}
8019
8020
8021static int
8022exitcmd(argc, argv)
8023 int argc;
8024 char **argv;
8025{
8026 if (stoppedjobs())
8027 return 0;
8028 if (argc > 1)
8029 exitstatus = number(argv[1]);
8030 else
8031 exitstatus = oexitstatus;
8032 exitshell(exitstatus);
8033 /* NOTREACHED */
8034}
Eric Andersen62483552001-07-10 06:09:16 +00008035
Eric Andersen2870d962001-07-02 17:27:21 +00008036static pointer
8037stalloc(int nbytes)
Eric Andersencb57d552001-06-28 07:25:16 +00008038{
8039 char *p;
8040
8041 nbytes = ALIGN(nbytes);
8042 if (nbytes > stacknleft) {
8043 int blocksize;
8044 struct stack_block *sp;
8045
8046 blocksize = nbytes;
8047 if (blocksize < MINSIZE)
8048 blocksize = MINSIZE;
8049 INTOFF;
8050 sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
8051 sp->prev = stackp;
8052 stacknxt = sp->space;
8053 stacknleft = blocksize;
8054 stackp = sp;
8055 INTON;
8056 }
8057 p = stacknxt;
8058 stacknxt += nbytes;
8059 stacknleft -= nbytes;
8060 return p;
8061}
8062
8063
8064static void
Eric Andersen2870d962001-07-02 17:27:21 +00008065stunalloc(pointer p)
8066{
Eric Andersencb57d552001-06-28 07:25:16 +00008067#ifdef DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +00008068 if (p == NULL) { /*DEBUG */
Eric Andersencb57d552001-06-28 07:25:16 +00008069 write(2, "stunalloc\n", 10);
8070 abort();
8071 }
8072#endif
8073 if (!(stacknxt >= (char *)p && (char *)p >= stackp->space)) {
8074 p = stackp->space;
8075 }
8076 stacknleft += stacknxt - (char *)p;
8077 stacknxt = p;
8078}
8079
8080
Eric Andersencb57d552001-06-28 07:25:16 +00008081static void
Eric Andersen2870d962001-07-02 17:27:21 +00008082setstackmark(struct stackmark *mark)
8083{
Eric Andersencb57d552001-06-28 07:25:16 +00008084 mark->stackp = stackp;
8085 mark->stacknxt = stacknxt;
8086 mark->stacknleft = stacknleft;
8087 mark->marknext = markp;
8088 markp = mark;
8089}
8090
8091
8092static void
Eric Andersen2870d962001-07-02 17:27:21 +00008093popstackmark(struct stackmark *mark)
8094{
Eric Andersencb57d552001-06-28 07:25:16 +00008095 struct stack_block *sp;
8096
8097 INTOFF;
8098 markp = mark->marknext;
8099 while (stackp != mark->stackp) {
8100 sp = stackp;
8101 stackp = sp->prev;
8102 ckfree(sp);
8103 }
8104 stacknxt = mark->stacknxt;
8105 stacknleft = mark->stacknleft;
8106 INTON;
8107}
8108
8109
8110/*
8111 * When the parser reads in a string, it wants to stick the string on the
8112 * stack and only adjust the stack pointer when it knows how big the
8113 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8114 * of space on top of the stack and stackblocklen returns the length of
8115 * this block. Growstackblock will grow this space by at least one byte,
8116 * possibly moving it (like realloc). Grabstackblock actually allocates the
8117 * part of the block that has been used.
8118 */
8119
8120static void
Eric Andersen2870d962001-07-02 17:27:21 +00008121growstackblock(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00008122 char *p;
8123 int newlen = ALIGN(stacknleft * 2 + 100);
8124 char *oldspace = stacknxt;
8125 int oldlen = stacknleft;
8126 struct stack_block *sp;
8127 struct stack_block *oldstackp;
8128
8129 if (stacknxt == stackp->space && stackp != &stackbase) {
8130 INTOFF;
8131 oldstackp = stackp;
8132 sp = stackp;
8133 stackp = sp->prev;
8134 sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen);
8135 sp->prev = stackp;
8136 stackp = sp;
8137 stacknxt = sp->space;
8138 stacknleft = newlen;
8139 {
8140 /* Stack marks pointing to the start of the old block
Eric Andersen2870d962001-07-02 17:27:21 +00008141 * must be relocated to point to the new block
Eric Andersencb57d552001-06-28 07:25:16 +00008142 */
8143 struct stackmark *xmark;
8144 xmark = markp;
8145 while (xmark != NULL && xmark->stackp == oldstackp) {
8146 xmark->stackp = stackp;
8147 xmark->stacknxt = stacknxt;
8148 xmark->stacknleft = stacknleft;
8149 xmark = xmark->marknext;
8150 }
8151 }
8152 INTON;
8153 } else {
8154 p = stalloc(newlen);
8155 memcpy(p, oldspace, oldlen);
Eric Andersen2870d962001-07-02 17:27:21 +00008156 stacknxt = p; /* free the space */
8157 stacknleft += newlen; /* we just allocated */
Eric Andersencb57d552001-06-28 07:25:16 +00008158 }
8159}
8160
8161
8162
Eric Andersen2870d962001-07-02 17:27:21 +00008163static inline void
8164grabstackblock(int len)
Eric Andersencb57d552001-06-28 07:25:16 +00008165{
8166 len = ALIGN(len);
8167 stacknxt += len;
8168 stacknleft -= len;
8169}
8170
8171
8172
8173/*
8174 * The following routines are somewhat easier to use that the above.
8175 * The user declares a variable of type STACKSTR, which may be declared
8176 * to be a register. The macro STARTSTACKSTR initializes things. Then
8177 * the user uses the macro STPUTC to add characters to the string. In
8178 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8179 * grown as necessary. When the user is done, she can just leave the
8180 * string there and refer to it using stackblock(). Or she can allocate
8181 * the space for it using grabstackstr(). If it is necessary to allow
8182 * someone else to use the stack temporarily and then continue to grow
8183 * the string, the user should use grabstack to allocate the space, and
8184 * then call ungrabstr(p) to return to the previous mode of operation.
8185 *
8186 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8187 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8188 * is space for at least one character.
8189 */
8190
8191
8192static char *
Eric Andersen2870d962001-07-02 17:27:21 +00008193growstackstr(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00008194 int len = stackblocksize();
8195 if (herefd >= 0 && len >= 1024) {
8196 xwrite(herefd, stackblock(), len);
8197 sstrnleft = len - 1;
8198 return stackblock();
8199 }
8200 growstackblock();
8201 sstrnleft = stackblocksize() - len - 1;
8202 return stackblock() + len;
8203}
8204
8205
8206/*
8207 * Called from CHECKSTRSPACE.
8208 */
8209
8210static char *
8211makestrspace(size_t newlen) {
8212 int len = stackblocksize() - sstrnleft;
8213 do {
8214 growstackblock();
8215 sstrnleft = stackblocksize() - len;
8216 } while (sstrnleft < newlen);
8217 return stackblock() + len;
8218}
8219
8220
8221
8222static void
Eric Andersen2870d962001-07-02 17:27:21 +00008223ungrabstackstr(char *s, char *p)
8224{
Eric Andersencb57d552001-06-28 07:25:16 +00008225 stacknleft += stacknxt - s;
8226 stacknxt = s;
8227 sstrnleft = stacknleft - (p - s);
8228}
Eric Andersencb57d552001-06-28 07:25:16 +00008229/*
8230 * Miscelaneous builtins.
8231 */
8232
8233
8234#undef rflag
8235
Eric Andersencb57d552001-06-28 07:25:16 +00008236#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersen62483552001-07-10 06:09:16 +00008237typedef long rlim_t;
Eric Andersencb57d552001-06-28 07:25:16 +00008238#endif
8239
8240
8241
8242/*
8243 * The read builtin. The -e option causes backslashes to escape the
8244 * following character.
8245 *
8246 * This uses unbuffered input, which may be avoidable in some cases.
8247 */
8248
8249static int
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008250readcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008251{
8252 char **ap;
8253 int backslash;
8254 char c;
8255 int rflag;
8256 char *prompt;
8257 const char *ifs;
8258 char *p;
8259 int startword;
8260 int status;
8261 int i;
8262
8263 rflag = 0;
8264 prompt = NULL;
8265 while ((i = nextopt("p:r")) != '\0') {
8266 if (i == 'p')
8267 prompt = optionarg;
8268 else
8269 rflag = 1;
8270 }
8271 if (prompt && isatty(0)) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008272 out2str(prompt); /* read without cmdedit */
Eric Andersencb57d552001-06-28 07:25:16 +00008273 flushall();
8274 }
8275 if (*(ap = argptr) == NULL)
8276 error("arg count");
8277 if ((ifs = bltinlookup("IFS")) == NULL)
8278 ifs = defifs;
8279 status = 0;
8280 startword = 1;
8281 backslash = 0;
8282 STARTSTACKSTR(p);
8283 for (;;) {
8284 if (read(0, &c, 1) != 1) {
8285 status = 1;
8286 break;
8287 }
8288 if (c == '\0')
8289 continue;
8290 if (backslash) {
8291 backslash = 0;
8292 if (c != '\n')
8293 STPUTC(c, p);
8294 continue;
8295 }
8296 if (!rflag && c == '\\') {
8297 backslash++;
8298 continue;
8299 }
8300 if (c == '\n')
8301 break;
8302 if (startword && *ifs == ' ' && strchr(ifs, c)) {
8303 continue;
8304 }
8305 startword = 0;
8306 if (backslash && c == '\\') {
8307 if (read(0, &c, 1) != 1) {
8308 status = 1;
8309 break;
8310 }
8311 STPUTC(c, p);
8312 } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
8313 STACKSTRNUL(p);
8314 setvar(*ap, stackblock(), 0);
8315 ap++;
8316 startword = 1;
8317 STARTSTACKSTR(p);
8318 } else {
8319 STPUTC(c, p);
8320 }
8321 }
8322 STACKSTRNUL(p);
8323 /* Remove trailing blanks */
8324 while (stackblock() <= --p && strchr(ifs, *p) != NULL)
8325 *p = '\0';
8326 setvar(*ap, stackblock(), 0);
8327 while (*++ap != NULL)
8328 setvar(*ap, nullstr, 0);
8329 return status;
8330}
8331
8332
8333
8334static int
8335umaskcmd(argc, argv)
8336 int argc;
8337 char **argv;
8338{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008339 static const char permuser[3] = "ugo";
8340 static const char permmode[3] = "rwx";
8341 static const short int permmask[] = {
8342 S_IRUSR, S_IWUSR, S_IXUSR,
8343 S_IRGRP, S_IWGRP, S_IXGRP,
8344 S_IROTH, S_IWOTH, S_IXOTH
8345 };
8346
Eric Andersencb57d552001-06-28 07:25:16 +00008347 char *ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008348 mode_t mask;
Eric Andersencb57d552001-06-28 07:25:16 +00008349 int i;
8350 int symbolic_mode = 0;
8351
Eric Andersen62483552001-07-10 06:09:16 +00008352 while (nextopt("S") != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00008353 symbolic_mode = 1;
8354 }
8355
8356 INTOFF;
8357 mask = umask(0);
8358 umask(mask);
8359 INTON;
8360
8361 if ((ap = *argptr) == NULL) {
8362 if (symbolic_mode) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008363 char buf[18];
8364 char *p = buf;
8365 for (i=0 ; i<3 ; i++) {
8366 int j;
8367 *p++ = permuser[i];
8368 *p++ = '=';
8369 for (j=0 ; j<3 ; j++) {
8370 if ((mask & permmask[3*i+j]) == 0) {
8371 *p++ = permmode[j];
8372 }
8373 }
8374 *p++ = ',';
8375 }
8376 *--p = 0;
8377 puts(buf);
Eric Andersencb57d552001-06-28 07:25:16 +00008378 } else {
Eric Andersen62483552001-07-10 06:09:16 +00008379 printf("%.4o\n", mask);
Eric Andersencb57d552001-06-28 07:25:16 +00008380 }
8381 } else {
Eric Andersen62483552001-07-10 06:09:16 +00008382 if (is_digit((unsigned char)*ap)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008383 mask = 0;
8384 do {
8385 if (*ap >= '8' || *ap < '0')
8386 error("Illegal number: %s", argv[1]);
8387 mask = (mask << 3) + (*ap - '0');
8388 } while (*++ap != '\0');
8389 umask(mask);
8390 } else {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008391 mask = ~mask & 0777;
8392 if (parse_mode(ap, &mask) == FALSE) {
Eric Andersencb57d552001-06-28 07:25:16 +00008393 error("Illegal mode: %s", ap);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008394 }
Eric Andersencb57d552001-06-28 07:25:16 +00008395 umask(~mask & 0777);
8396 }
8397 }
8398 return 0;
8399}
8400
8401/*
8402 * ulimit builtin
8403 *
8404 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
8405 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
8406 * ash by J.T. Conklin.
8407 *
8408 * Public domain.
8409 */
8410
8411struct limits {
8412 const char *name;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008413 short cmd;
8414 short factor; /* multiply by to get rlim_{cur,max} values */
Eric Andersencb57d552001-06-28 07:25:16 +00008415};
8416
8417static const struct limits limits[] = {
8418#ifdef RLIMIT_CPU
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008419 { "time(seconds)", RLIMIT_CPU, 1 },
Eric Andersencb57d552001-06-28 07:25:16 +00008420#endif
8421#ifdef RLIMIT_FSIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008422 { "file(blocks)", RLIMIT_FSIZE, 512 },
Eric Andersencb57d552001-06-28 07:25:16 +00008423#endif
8424#ifdef RLIMIT_DATA
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008425 { "data(kbytes)", RLIMIT_DATA, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008426#endif
8427#ifdef RLIMIT_STACK
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008428 { "stack(kbytes)", RLIMIT_STACK, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008429#endif
8430#ifdef RLIMIT_CORE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008431 { "coredump(blocks)", RLIMIT_CORE, 512 },
Eric Andersencb57d552001-06-28 07:25:16 +00008432#endif
8433#ifdef RLIMIT_RSS
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008434 { "memory(kbytes)", RLIMIT_RSS, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008435#endif
8436#ifdef RLIMIT_MEMLOCK
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008437 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008438#endif
8439#ifdef RLIMIT_NPROC
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008440 { "process(processes)", RLIMIT_NPROC, 1 },
Eric Andersencb57d552001-06-28 07:25:16 +00008441#endif
8442#ifdef RLIMIT_NOFILE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008443 { "nofiles(descriptors)", RLIMIT_NOFILE, 1 },
Eric Andersencb57d552001-06-28 07:25:16 +00008444#endif
8445#ifdef RLIMIT_VMEM
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008446 { "vmemory(kbytes)", RLIMIT_VMEM, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008447#endif
8448#ifdef RLIMIT_SWAP
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008449 { "swap(kbytes)", RLIMIT_SWAP, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008450#endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008451 { NULL, 0, 0 }
Eric Andersencb57d552001-06-28 07:25:16 +00008452};
8453
8454static int
8455ulimitcmd(argc, argv)
8456 int argc;
8457 char **argv;
8458{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008459 static const char unlimited_string[] = "unlimited";
Eric Andersen2870d962001-07-02 17:27:21 +00008460 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00008461 rlim_t val = 0;
8462 enum { SOFT = 0x1, HARD = 0x2 }
8463 how = SOFT | HARD;
Eric Andersen2870d962001-07-02 17:27:21 +00008464 const struct limits *l;
8465 int set, all = 0;
8466 int optc, what;
8467 struct rlimit limit;
Eric Andersencb57d552001-06-28 07:25:16 +00008468
8469 what = 'f';
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008470
8471 while ((optc = nextopt("HSa"
8472#ifdef RLIMIT_CPU
8473 "t"
8474#endif
8475#ifdef RLIMIT_FSIZE
8476 "f"
8477#endif
8478#ifdef RLIMIT_DATA
8479 "d"
8480#endif
8481#ifdef RLIMIT_STACK
8482 "s"
8483#endif
8484#ifdef RLIMIT_CORE
8485 "c"
8486#endif
8487#ifdef RLIMIT_RSS
8488 "m"
8489#endif
8490#ifdef RLIMIT_MEMLOCK
8491 "l"
8492#endif
8493#ifdef RLIMIT_NPROC
8494 "p"
8495#endif
8496#ifdef RLIMIT_NOFILE
8497 "n"
8498#endif
8499#ifdef RLIMIT_VMEM
8500 "v"
8501#endif
8502#ifdef RLIMIT_SWAP
8503 "w"
8504#endif
8505 )) != '\0') {
8506 if (optc == 'H') {
Eric Andersencb57d552001-06-28 07:25:16 +00008507 how = HARD;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008508 } else if (optc == 'S') {
Eric Andersencb57d552001-06-28 07:25:16 +00008509 how = SOFT;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008510 } else if (optc == 'a') {
Eric Andersencb57d552001-06-28 07:25:16 +00008511 all = 1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008512 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00008513 what = optc;
8514 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008515 }
Eric Andersencb57d552001-06-28 07:25:16 +00008516
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008517 for (l = limits; l->name; l++) {
8518 if(l->name[0] == what)
8519 break;
8520 if(l->name[1]=='w' && what=='w')
8521 break;
8522 }
Eric Andersencb57d552001-06-28 07:25:16 +00008523
8524 set = *argptr ? 1 : 0;
8525 if (set) {
8526 char *p = *argptr;
8527
8528 if (all || argptr[1])
8529 error("too many arguments");
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008530 if (strcmp(p, unlimited_string) == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00008531 val = RLIM_INFINITY;
8532 else {
8533 val = (rlim_t) 0;
8534
8535 while ((c = *p++) >= '0' && c <= '9')
8536 {
8537 val = (val * 10) + (long)(c - '0');
8538 if (val < (rlim_t) 0)
8539 break;
8540 }
8541 if (c)
8542 error("bad number");
8543 val *= l->factor;
8544 }
8545 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008546
Eric Andersencb57d552001-06-28 07:25:16 +00008547 if (all) {
8548 for (l = limits; l->name; l++) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008549 printf("%-20s ", l->name);
Eric Andersencb57d552001-06-28 07:25:16 +00008550 getrlimit(l->cmd, &limit);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008551 OUTPUT_LIMIT:
Eric Andersencb57d552001-06-28 07:25:16 +00008552 if (how & SOFT)
8553 val = limit.rlim_cur;
8554 else if (how & HARD)
8555 val = limit.rlim_max;
8556
Eric Andersencb57d552001-06-28 07:25:16 +00008557 if (val == RLIM_INFINITY)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008558 puts(unlimited_string);
Eric Andersencb57d552001-06-28 07:25:16 +00008559 else
8560 {
8561 val /= l->factor;
Eric Andersen62483552001-07-10 06:09:16 +00008562 printf("%lld\n", (long long) val);
Eric Andersencb57d552001-06-28 07:25:16 +00008563 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008564 if (!all) {
8565 break;
8566 }
Eric Andersencb57d552001-06-28 07:25:16 +00008567 }
8568 return 0;
8569 }
8570
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008571 if (!set) {
8572 goto OUTPUT_LIMIT;
Eric Andersencb57d552001-06-28 07:25:16 +00008573 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008574
8575 getrlimit(l->cmd, &limit);
8576 if (how & HARD)
8577 limit.rlim_max = val;
8578 if (how & SOFT)
8579 limit.rlim_cur = val;
8580 if (setrlimit(l->cmd, &limit) < 0)
8581 error("error setting limit (%m)");
Eric Andersencb57d552001-06-28 07:25:16 +00008582 return 0;
8583}
Eric Andersencb57d552001-06-28 07:25:16 +00008584/*
8585 * prefix -- see if pfx is a prefix of string.
8586 */
8587
8588static int
Eric Andersen62483552001-07-10 06:09:16 +00008589prefix(char const *pfx, char const *string)
8590{
Eric Andersencb57d552001-06-28 07:25:16 +00008591 while (*pfx) {
8592 if (*pfx++ != *string++)
8593 return 0;
8594 }
8595 return 1;
8596}
8597
Eric Andersen2870d962001-07-02 17:27:21 +00008598/*
8599 * Return true if s is a string of digits, and save munber in intptr
8600 * nagative is bad
8601 */
8602
8603static int
8604is_number(const char *p, int *intptr)
8605{
8606 int ret = 0;
8607
8608 do {
8609 if (! is_digit(*p))
8610 return 0;
8611 ret *= 10;
8612 ret += digit_val(*p);
8613 p++;
8614 } while (*p != '\0');
8615
8616 *intptr = ret;
8617 return 1;
8618}
Eric Andersencb57d552001-06-28 07:25:16 +00008619
8620/*
8621 * Convert a string of digits to an integer, printing an error message on
8622 * failure.
8623 */
8624
8625static int
Eric Andersen2870d962001-07-02 17:27:21 +00008626number(const char *s)
8627{
8628 int i;
8629 if (! is_number(s, &i))
Eric Andersencb57d552001-06-28 07:25:16 +00008630 error("Illegal number: %s", s);
Eric Andersen2870d962001-07-02 17:27:21 +00008631 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00008632}
8633
Eric Andersencb57d552001-06-28 07:25:16 +00008634/*
8635 * Produce a possibly single quoted string suitable as input to the shell.
8636 * The return string is allocated on the stack.
8637 */
8638
8639static char *
8640single_quote(const char *s) {
8641 char *p;
8642
8643 STARTSTACKSTR(p);
8644
8645 do {
8646 char *q = p;
8647 size_t len1, len1p, len2, len2p;
8648
8649 len1 = strcspn(s, "'");
8650 len2 = strspn(s + len1, "'");
8651
8652 len1p = len1 ? len1 + 2 : len1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008653 len2p = len2 + ((len2 < 2) ? len2 : 2);
Eric Andersencb57d552001-06-28 07:25:16 +00008654
8655 CHECKSTRSPACE(len1p + len2p + 1, p);
8656
8657 if (len1) {
8658 *p = '\'';
Eric Andersencb57d552001-06-28 07:25:16 +00008659 q = p + 1 + len1;
8660 memcpy(p + 1, s, len1);
Eric Andersencb57d552001-06-28 07:25:16 +00008661 *q++ = '\'';
8662 s += len1;
8663 }
8664
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008665 if (len2 > 1) {
Eric Andersencb57d552001-06-28 07:25:16 +00008666 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008667 q += 1 + len2;
8668 memcpy(q + 1, s, len2);
8669 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008670 s += len2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008671 } else if (len2 == 1) {
8672 *q++ = '\\';
8673 *q = '\'';
8674 s++;
Eric Andersencb57d552001-06-28 07:25:16 +00008675 }
8676
8677 STADJUST(len1p + len2p, p);
8678 } while (*s);
8679
8680 USTPUTC(0, p);
8681
8682 return grabstackstr(p);
8683}
8684
8685/*
8686 * Like strdup but works with the ash stack.
8687 */
8688
8689static char *
8690sstrdup(const char *p)
8691{
8692 size_t len = strlen(p) + 1;
8693 return memcpy(stalloc(len), p, len);
8694}
8695
Eric Andersencb57d552001-06-28 07:25:16 +00008696
8697/*
Eric Andersencb57d552001-06-28 07:25:16 +00008698 * Routine for dealing with parsed shell commands.
8699 */
8700
8701
Eric Andersen62483552001-07-10 06:09:16 +00008702static void sizenodelist (const struct nodelist *);
8703static struct nodelist *copynodelist (const struct nodelist *);
8704static char *nodesavestr (const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00008705
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00008706#define CALCSIZE_TABLE
8707#define COPYNODE_TABLE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008708#if defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE)
8709/*
8710 * To collect a lot of redundant code in case statements for copynode()
8711 * and calcsize(), we implement a mini language here. Each type of node
8712 * struct has an associated instruction sequence that operates on its
8713 * members via their offsets. The instruction are pack in unsigned chars
8714 * with format IIDDDDDE where the bits are
8715 * I : part of the instruction opcode, which are
8716 * 00 : member is a pointer to another node
8717 * 40 : member is an integer
8718 * 80 : member is a pointer to a nodelist
8719 * CC : member is a pointer to a char string
8720 * D : data - the actual offset of the member to operate on in the struct
8721 * (since we assume bit 0 is set, it is not shifted)
8722 * E : flag signaling end of instruction sequence
8723 *
8724 * WARNING: In order to handle larger offsets for 64bit archs, this code
8725 * assumes that no offset can be an odd number and stores the
8726 * end-of-instructions flag in bit 0.
8727 */
8728
8729#define NODE_INTEGER 0x40
8730#define NODE_NODELIST 0x80
8731#define NODE_CHARPTR 0xC0
8732#define NODE_NOMORE 0x01 /* Note: no offset should be odd (aligned)*/
8733#define NODE_MBRMASK 0xC0
8734#define NODE_OFFSETMASK 0x3E
8735
8736static const unsigned char copynode_ops[35] = {
8737#define COPYNODE_OPS0 0
8738 offsetof(union node, nbinary.ch2),
8739 offsetof(union node, nbinary.ch1)|NODE_NOMORE,
8740#define COPYNODE_OPS1 (COPYNODE_OPS0 + 2)
8741 offsetof(union node, ncmd.redirect),
8742 offsetof(union node, ncmd.args),
8743 offsetof(union node, ncmd.assign),
8744 offsetof(union node, ncmd.backgnd)|NODE_INTEGER|NODE_NOMORE,
8745#define COPYNODE_OPS2 (COPYNODE_OPS1 + 4)
8746 offsetof(union node, npipe.cmdlist)|NODE_NODELIST,
8747 offsetof(union node, npipe.backgnd)|NODE_INTEGER|NODE_NOMORE,
8748#define COPYNODE_OPS3 (COPYNODE_OPS2 + 2)
8749 offsetof(union node, nredir.redirect),
8750 offsetof(union node, nredir.n)|NODE_NOMORE,
8751#define COPYNODE_OPS4 (COPYNODE_OPS3 + 2)
8752 offsetof(union node, nif.elsepart),
8753 offsetof(union node, nif.ifpart),
8754 offsetof(union node, nif.test)|NODE_NOMORE,
8755#define COPYNODE_OPS5 (COPYNODE_OPS4 + 3)
8756 offsetof(union node, nfor.var)|NODE_CHARPTR,
8757 offsetof(union node, nfor.body),
8758 offsetof(union node, nfor.args)|NODE_NOMORE,
8759#define COPYNODE_OPS6 (COPYNODE_OPS5 + 3)
8760 offsetof(union node, ncase.cases),
8761 offsetof(union node, ncase.expr)|NODE_NOMORE,
8762#define COPYNODE_OPS7 (COPYNODE_OPS6 + 2)
8763 offsetof(union node, nclist.body),
8764 offsetof(union node, nclist.pattern),
8765 offsetof(union node, nclist.next)|NODE_NOMORE,
8766#define COPYNODE_OPS8 (COPYNODE_OPS7 + 3)
8767 offsetof(union node, narg.backquote)|NODE_NODELIST,
8768 offsetof(union node, narg.text)|NODE_CHARPTR,
8769 offsetof(union node, narg.next)|NODE_NOMORE,
8770#define COPYNODE_OPS9 (COPYNODE_OPS8 + 3)
8771 offsetof(union node, nfile.fname),
8772 offsetof(union node, nfile.fd)|NODE_INTEGER,
8773 offsetof(union node, nfile.next)|NODE_NOMORE,
8774#define COPYNODE_OPS10 (COPYNODE_OPS9 + 3)
8775 offsetof(union node, ndup.vname),
8776 offsetof(union node, ndup.dupfd)|NODE_INTEGER,
8777 offsetof(union node, ndup.fd)|NODE_INTEGER,
8778 offsetof(union node, ndup.next)|NODE_NOMORE,
8779#define COPYNODE_OPS11 (COPYNODE_OPS10 + 4)
8780 offsetof(union node, nhere.doc),
8781 offsetof(union node, nhere.fd)|NODE_INTEGER,
8782 offsetof(union node, nhere.next)|NODE_NOMORE,
8783#define COPYNODE_OPS12 (COPYNODE_OPS11 + 3)
8784 offsetof(union node, nnot.com)|NODE_NOMORE,
8785};
8786
8787#if COPYNODE_OPS12 != 34
8788#error COPYNODE_OPS12 is incorrect
8789#endif
8790
8791static const unsigned char copynode_ops_index[26] = {
8792 COPYNODE_OPS0, /* NSEMI */
8793 COPYNODE_OPS1, /* NCMD */
8794 COPYNODE_OPS2, /* NPIPE */
8795 COPYNODE_OPS3, /* NREDIR */
8796 COPYNODE_OPS3, /* NBACKGND */
8797 COPYNODE_OPS3, /* NSUBSHELL */
8798 COPYNODE_OPS0, /* NAND */
8799 COPYNODE_OPS0, /* NOR */
8800 COPYNODE_OPS4, /* NIF */
8801 COPYNODE_OPS0, /* NWHILE */
8802 COPYNODE_OPS0, /* NUNTIL */
8803 COPYNODE_OPS5, /* NFOR */
8804 COPYNODE_OPS6, /* NCASE */
8805 COPYNODE_OPS7, /* NCLIST */
8806 COPYNODE_OPS8, /* NDEFUN */
8807 COPYNODE_OPS8, /* NARG */
8808 COPYNODE_OPS9, /* NTO */
8809 COPYNODE_OPS9, /* NFROM */
8810 COPYNODE_OPS9, /* NFROMTO */
8811 COPYNODE_OPS9, /* NAPPEND */
8812 COPYNODE_OPS9, /* NTOOV */
8813 COPYNODE_OPS10, /* NTOFD */
8814 COPYNODE_OPS10, /* NFROMFD */
8815 COPYNODE_OPS11, /* NHERE */
8816 COPYNODE_OPS11, /* NXHERE */
8817 COPYNODE_OPS12, /* NNOT */
8818};
8819
8820#if NODE_CHARPTR != NODE_MBRMASK
8821#error NODE_CHARPTR != NODE_MBRMASK!!!
8822#endif
8823#endif /* defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE) */
8824
8825#ifdef COPYNODE_TABLE
8826static union node *
8827copynode(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008828{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008829 union node *new;
8830 const unsigned char *p;
8831
Manuel Novoa III c639a352001-08-12 17:32:56 +00008832 if (n == NULL) {
8833 return NULL;
8834 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008835 new = funcblock;
8836 new->type = n->type;
8837 funcblock = (char *) funcblock + (int) nodesize[n->type];
8838 p = copynode_ops + (int) copynode_ops_index[n->type];
8839 do {
8840 char *nn = ((char *) new) + ((int)(*p & NODE_OFFSETMASK));
8841 const char *no = ((const char *) n) + ((int)(*p & NODE_OFFSETMASK));
8842
8843 if (!(*p & NODE_MBRMASK)) { /* standard node */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008844 *((union node **)nn) = copynode(*((const union node **) no));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008845 } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008846 *((const char **)nn) = nodesavestr(*((const char **)no));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008847 } else if (*p & NODE_NODELIST) { /* nodelist */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008848 *((struct nodelist **)nn)
8849 = copynodelist(*((const struct nodelist **) no));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008850 } else { /* integer */
8851 *((int *) nn) = *((int *) no);
8852 }
8853 } while (!(*p++ & NODE_NOMORE));
8854 return new;
Eric Andersencb57d552001-06-28 07:25:16 +00008855}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008856#else /* COPYNODE_TABLE */
Eric Andersencb57d552001-06-28 07:25:16 +00008857static union node *
Eric Andersen62483552001-07-10 06:09:16 +00008858copynode(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008859{
Eric Andersen62483552001-07-10 06:09:16 +00008860 union node *new;
Eric Andersencb57d552001-06-28 07:25:16 +00008861
8862 if (n == NULL)
Manuel Novoa III c639a352001-08-12 17:32:56 +00008863 return NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008864 new = funcblock;
8865 funcblock = (char *) funcblock + nodesize[n->type];
8866 switch (n->type) {
8867 case NSEMI:
8868 case NAND:
8869 case NOR:
8870 case NWHILE:
8871 case NUNTIL:
8872 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8873 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8874 break;
8875 case NCMD:
8876 new->ncmd.redirect = copynode(n->ncmd.redirect);
8877 new->ncmd.args = copynode(n->ncmd.args);
8878 new->ncmd.assign = copynode(n->ncmd.assign);
8879 new->ncmd.backgnd = n->ncmd.backgnd;
8880 break;
8881 case NPIPE:
8882 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8883 new->npipe.backgnd = n->npipe.backgnd;
8884 break;
8885 case NREDIR:
8886 case NBACKGND:
8887 case NSUBSHELL:
8888 new->nredir.redirect = copynode(n->nredir.redirect);
8889 new->nredir.n = copynode(n->nredir.n);
8890 break;
8891 case NIF:
8892 new->nif.elsepart = copynode(n->nif.elsepart);
8893 new->nif.ifpart = copynode(n->nif.ifpart);
8894 new->nif.test = copynode(n->nif.test);
8895 break;
8896 case NFOR:
8897 new->nfor.var = nodesavestr(n->nfor.var);
8898 new->nfor.body = copynode(n->nfor.body);
8899 new->nfor.args = copynode(n->nfor.args);
8900 break;
8901 case NCASE:
8902 new->ncase.cases = copynode(n->ncase.cases);
8903 new->ncase.expr = copynode(n->ncase.expr);
8904 break;
8905 case NCLIST:
8906 new->nclist.body = copynode(n->nclist.body);
8907 new->nclist.pattern = copynode(n->nclist.pattern);
8908 new->nclist.next = copynode(n->nclist.next);
8909 break;
8910 case NDEFUN:
8911 case NARG:
8912 new->narg.backquote = copynodelist(n->narg.backquote);
8913 new->narg.text = nodesavestr(n->narg.text);
8914 new->narg.next = copynode(n->narg.next);
8915 break;
8916 case NTO:
8917 case NFROM:
8918 case NFROMTO:
8919 case NAPPEND:
8920 case NTOOV:
8921 new->nfile.fname = copynode(n->nfile.fname);
8922 new->nfile.fd = n->nfile.fd;
8923 new->nfile.next = copynode(n->nfile.next);
8924 break;
8925 case NTOFD:
8926 case NFROMFD:
8927 new->ndup.vname = copynode(n->ndup.vname);
8928 new->ndup.dupfd = n->ndup.dupfd;
8929 new->ndup.fd = n->ndup.fd;
8930 new->ndup.next = copynode(n->ndup.next);
8931 break;
8932 case NHERE:
8933 case NXHERE:
8934 new->nhere.doc = copynode(n->nhere.doc);
8935 new->nhere.fd = n->nhere.fd;
8936 new->nhere.next = copynode(n->nhere.next);
8937 break;
8938 case NNOT:
8939 new->nnot.com = copynode(n->nnot.com);
8940 break;
8941 };
8942 new->type = n->type;
Eric Andersen62483552001-07-10 06:09:16 +00008943 return new;
Eric Andersencb57d552001-06-28 07:25:16 +00008944}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008945#endif /* COPYNODE_TABLE */
8946
8947#ifdef CALCSIZE_TABLE
8948static void
8949calcsize(const union node *n)
8950{
8951 const unsigned char *p;
8952
8953 if (n == NULL)
8954 return;
8955 funcblocksize += (int) nodesize[n->type];
8956
8957 p = copynode_ops + (int) copynode_ops_index[n->type];
8958 do {
8959 const char *no = ((const char *) n) + ((int)(*p & NODE_OFFSETMASK));
8960
8961 if (!(*p & NODE_MBRMASK)) { /* standard node */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008962 calcsize(*((const union node **) no));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008963 } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008964 funcstringsize += strlen(*((const char **)no)) + 1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008965 } else if (*p & NODE_NODELIST) { /* nodelist */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008966 sizenodelist(*((const struct nodelist **) no));
8967 } /* else integer -- ignore */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008968 } while (!(*p++ & NODE_NOMORE));
8969}
8970#else /* CALCSIZE_TABLE */
8971static void
8972calcsize(const union node *n)
8973{
8974 if (n == NULL)
8975 return;
8976 funcblocksize += nodesize[n->type];
8977 switch (n->type) {
8978 case NSEMI:
8979 case NAND:
8980 case NOR:
8981 case NWHILE:
8982 case NUNTIL:
8983 calcsize(n->nbinary.ch2);
8984 calcsize(n->nbinary.ch1);
8985 break;
8986 case NCMD:
8987 calcsize(n->ncmd.redirect);
8988 calcsize(n->ncmd.args);
8989 calcsize(n->ncmd.assign);
8990 break;
8991 case NPIPE:
8992 sizenodelist(n->npipe.cmdlist);
8993 break;
8994 case NREDIR:
8995 case NBACKGND:
8996 case NSUBSHELL:
8997 calcsize(n->nredir.redirect);
8998 calcsize(n->nredir.n);
8999 break;
9000 case NIF:
9001 calcsize(n->nif.elsepart);
9002 calcsize(n->nif.ifpart);
9003 calcsize(n->nif.test);
9004 break;
9005 case NFOR:
9006 funcstringsize += strlen(n->nfor.var) + 1;
9007 calcsize(n->nfor.body);
9008 calcsize(n->nfor.args);
9009 break;
9010 case NCASE:
9011 calcsize(n->ncase.cases);
9012 calcsize(n->ncase.expr);
9013 break;
9014 case NCLIST:
9015 calcsize(n->nclist.body);
9016 calcsize(n->nclist.pattern);
9017 calcsize(n->nclist.next);
9018 break;
9019 case NDEFUN:
9020 case NARG:
9021 sizenodelist(n->narg.backquote);
9022 funcstringsize += strlen(n->narg.text) + 1;
9023 calcsize(n->narg.next);
9024 break;
9025 case NTO:
9026 case NFROM:
9027 case NFROMTO:
9028 case NAPPEND:
9029 case NTOOV:
9030 calcsize(n->nfile.fname);
9031 calcsize(n->nfile.next);
9032 break;
9033 case NTOFD:
9034 case NFROMFD:
9035 calcsize(n->ndup.vname);
9036 calcsize(n->ndup.next);
9037 break;
9038 case NHERE:
9039 case NXHERE:
9040 calcsize(n->nhere.doc);
9041 calcsize(n->nhere.next);
9042 break;
9043 case NNOT:
9044 calcsize(n->nnot.com);
9045 break;
9046 };
9047}
9048#endif /* CALCSIZE_TABLE */
9049
9050static void
9051sizenodelist(const struct nodelist *lp)
9052{
9053 while (lp) {
9054 funcblocksize += ALIGN(sizeof(struct nodelist));
9055 calcsize(lp->n);
9056 lp = lp->next;
9057 }
9058}
Eric Andersencb57d552001-06-28 07:25:16 +00009059
9060
9061static struct nodelist *
Eric Andersen62483552001-07-10 06:09:16 +00009062copynodelist(const struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00009063{
9064 struct nodelist *start;
9065 struct nodelist **lpp;
9066
9067 lpp = &start;
9068 while (lp) {
9069 *lpp = funcblock;
9070 funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist));
9071 (*lpp)->n = copynode(lp->n);
9072 lp = lp->next;
9073 lpp = &(*lpp)->next;
9074 }
9075 *lpp = NULL;
9076 return start;
9077}
9078
9079
Eric Andersencb57d552001-06-28 07:25:16 +00009080static char *
Eric Andersen62483552001-07-10 06:09:16 +00009081nodesavestr(const char *s)
Eric Andersencb57d552001-06-28 07:25:16 +00009082{
Eric Andersen62483552001-07-10 06:09:16 +00009083 const char *p = s;
9084 char *q = funcstring;
Eric Andersencb57d552001-06-28 07:25:16 +00009085 char *rtn = funcstring;
9086
9087 while ((*q++ = *p++) != '\0')
9088 continue;
9089 funcstring = q;
9090 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00009091}
9092
Eric Andersencb57d552001-06-28 07:25:16 +00009093#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00009094static int getopts (char *, char *, char **, int *, int *);
Eric Andersencb57d552001-06-28 07:25:16 +00009095#endif
9096
9097
9098/*
9099 * Process the shell command line arguments.
9100 */
9101
9102static void
9103procargs(argc, argv)
9104 int argc;
9105 char **argv;
9106{
9107 int i;
9108
9109 argptr = argv;
9110 if (argc > 0)
9111 argptr++;
9112 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009113 optent_val(i) = 2;
Eric Andersencb57d552001-06-28 07:25:16 +00009114 options(1);
9115 if (*argptr == NULL && minusc == NULL)
9116 sflag = 1;
9117 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
9118 iflag = 1;
9119 if (mflag == 2)
9120 mflag = iflag;
9121 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009122 if (optent_val(i) == 2)
9123 optent_val(i) = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009124 arg0 = argv[0];
9125 if (sflag == 0 && minusc == NULL) {
9126 commandname = argv[0];
9127 arg0 = *argptr++;
9128 setinputfile(arg0, 0);
9129 commandname = arg0;
9130 }
9131 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
9132 if (argptr && minusc && *argptr)
Eric Andersen2870d962001-07-02 17:27:21 +00009133 arg0 = *argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00009134
9135 shellparam.p = argptr;
9136 shellparam.optind = 1;
9137 shellparam.optoff = -1;
9138 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
9139 while (*argptr) {
9140 shellparam.nparam++;
9141 argptr++;
9142 }
9143 optschanged();
9144}
9145
9146
Eric Andersencb57d552001-06-28 07:25:16 +00009147
9148/*
9149 * Process shell options. The global variable argptr contains a pointer
9150 * to the argument list; we advance it past the options.
9151 */
9152
Eric Andersen62483552001-07-10 06:09:16 +00009153static inline void
9154minus_o(const char *name, int val)
9155{
9156 int i;
9157
9158 if (name == NULL) {
9159 out1str("Current option settings\n");
9160 for (i = 0; i < NOPTS; i++)
9161 printf("%-16s%s\n", optent_name(optlist[i]),
9162 optent_val(i) ? "on" : "off");
9163 } else {
9164 for (i = 0; i < NOPTS; i++)
9165 if (equal(name, optent_name(optlist[i]))) {
9166 setoption(optent_letter(optlist[i]), val);
9167 return;
9168 }
9169 error("Illegal option -o %s", name);
9170 }
9171}
9172
9173
Eric Andersencb57d552001-06-28 07:25:16 +00009174static void
Eric Andersen62483552001-07-10 06:09:16 +00009175options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00009176{
9177 char *p;
9178 int val;
9179 int c;
9180
9181 if (cmdline)
9182 minusc = NULL;
9183 while ((p = *argptr) != NULL) {
9184 argptr++;
9185 if ((c = *p++) == '-') {
9186 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00009187 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
9188 if (!cmdline) {
9189 /* "-" means turn off -x and -v */
9190 if (p[0] == '\0')
9191 xflag = vflag = 0;
9192 /* "--" means reset params */
9193 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00009194 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00009195 }
9196 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00009197 }
9198 } else if (c == '+') {
9199 val = 0;
9200 } else {
9201 argptr--;
9202 break;
9203 }
9204 while ((c = *p++) != '\0') {
9205 if (c == 'c' && cmdline) {
9206 char *q;
Eric Andersen2870d962001-07-02 17:27:21 +00009207#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */
Eric Andersencb57d552001-06-28 07:25:16 +00009208 if (*p == '\0')
9209#endif
9210 q = *argptr++;
9211 if (q == NULL || minusc != NULL)
9212 error("Bad -c option");
9213 minusc = q;
9214#ifdef NOHACK
9215 break;
9216#endif
9217 } else if (c == 'o') {
9218 minus_o(*argptr, val);
9219 if (*argptr)
9220 argptr++;
9221 } else {
9222 setoption(c, val);
9223 }
9224 }
9225 }
9226}
9227
Eric Andersencb57d552001-06-28 07:25:16 +00009228
9229static void
Eric Andersen2870d962001-07-02 17:27:21 +00009230setoption(int flag, int val)
9231{
Eric Andersencb57d552001-06-28 07:25:16 +00009232 int i;
9233
9234 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009235 if (optent_letter(optlist[i]) == flag) {
9236 optent_val(i) = val;
Eric Andersencb57d552001-06-28 07:25:16 +00009237 if (val) {
9238 /* #%$ hack for ksh semantics */
9239 if (flag == 'V')
9240 Eflag = 0;
9241 else if (flag == 'E')
9242 Vflag = 0;
9243 }
9244 return;
9245 }
9246 error("Illegal option -%c", flag);
9247 /* NOTREACHED */
9248}
9249
9250
9251
Eric Andersencb57d552001-06-28 07:25:16 +00009252/*
9253 * Set the shell parameters.
9254 */
9255
9256static void
Eric Andersen2870d962001-07-02 17:27:21 +00009257setparam(char **argv)
9258{
Eric Andersencb57d552001-06-28 07:25:16 +00009259 char **newparam;
9260 char **ap;
9261 int nparam;
9262
9263 for (nparam = 0 ; argv[nparam] ; nparam++);
9264 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
9265 while (*argv) {
9266 *ap++ = savestr(*argv++);
9267 }
9268 *ap = NULL;
9269 freeparam(&shellparam);
9270 shellparam.malloc = 1;
9271 shellparam.nparam = nparam;
9272 shellparam.p = newparam;
9273 shellparam.optind = 1;
9274 shellparam.optoff = -1;
9275}
9276
9277
9278/*
9279 * Free the list of positional parameters.
9280 */
9281
9282static void
Eric Andersen2870d962001-07-02 17:27:21 +00009283freeparam(volatile struct shparam *param)
9284{
Eric Andersencb57d552001-06-28 07:25:16 +00009285 char **ap;
9286
9287 if (param->malloc) {
9288 for (ap = param->p ; *ap ; ap++)
9289 ckfree(*ap);
9290 ckfree(param->p);
9291 }
9292}
9293
9294
9295
9296/*
9297 * The shift builtin command.
9298 */
9299
9300static int
9301shiftcmd(argc, argv)
9302 int argc;
9303 char **argv;
9304{
9305 int n;
9306 char **ap1, **ap2;
9307
9308 n = 1;
9309 if (argc > 1)
9310 n = number(argv[1]);
9311 if (n > shellparam.nparam)
9312 error("can't shift that many");
9313 INTOFF;
9314 shellparam.nparam -= n;
9315 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
9316 if (shellparam.malloc)
9317 ckfree(*ap1);
9318 }
9319 ap2 = shellparam.p;
9320 while ((*ap2++ = *ap1++) != NULL);
9321 shellparam.optind = 1;
9322 shellparam.optoff = -1;
9323 INTON;
9324 return 0;
9325}
9326
9327
9328
9329/*
9330 * The set command builtin.
9331 */
9332
9333static int
9334setcmd(argc, argv)
9335 int argc;
9336 char **argv;
9337{
9338 if (argc == 1)
9339 return showvarscmd(argc, argv);
9340 INTOFF;
9341 options(0);
9342 optschanged();
9343 if (*argptr != NULL) {
9344 setparam(argptr);
9345 }
9346 INTON;
9347 return 0;
9348}
9349
9350
9351static void
Eric Andersen2870d962001-07-02 17:27:21 +00009352getoptsreset(const char *value)
Eric Andersencb57d552001-06-28 07:25:16 +00009353{
9354 shellparam.optind = number(value);
9355 shellparam.optoff = -1;
9356}
9357
Eric Andersen2870d962001-07-02 17:27:21 +00009358#ifdef BB_LOCALE_SUPPORT
9359static void change_lc_all(const char *value)
9360{
9361 if(value != 0 && *value != 0)
9362 setlocale(LC_ALL, value);
9363}
9364
9365static void change_lc_ctype(const char *value)
9366{
9367 if(value != 0 && *value != 0)
9368 setlocale(LC_CTYPE, value);
9369}
9370
9371#endif
9372
Eric Andersencb57d552001-06-28 07:25:16 +00009373#ifdef ASH_GETOPTS
9374/*
9375 * The getopts builtin. Shellparam.optnext points to the next argument
9376 * to be processed. Shellparam.optptr points to the next character to
9377 * be processed in the current argument. If shellparam.optnext is NULL,
9378 * then it's the first time getopts has been called.
9379 */
9380
9381static int
9382getoptscmd(argc, argv)
9383 int argc;
9384 char **argv;
9385{
9386 char **optbase;
9387
9388 if (argc < 3)
9389 error("Usage: getopts optstring var [arg]");
9390 else if (argc == 3) {
9391 optbase = shellparam.p;
9392 if (shellparam.optind > shellparam.nparam + 1) {
9393 shellparam.optind = 1;
9394 shellparam.optoff = -1;
9395 }
9396 }
9397 else {
9398 optbase = &argv[3];
9399 if (shellparam.optind > argc - 2) {
9400 shellparam.optind = 1;
9401 shellparam.optoff = -1;
9402 }
9403 }
9404
9405 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9406 &shellparam.optoff);
9407}
9408
9409/*
9410 * Safe version of setvar, returns 1 on success 0 on failure.
9411 */
9412
9413static int
9414setvarsafe(name, val, flags)
9415 const char *name, *val;
9416 int flags;
9417{
9418 struct jmploc jmploc;
9419 struct jmploc *volatile savehandler = handler;
9420 int err = 0;
9421#ifdef __GNUC__
9422 (void) &err;
9423#endif
9424
9425 if (setjmp(jmploc.loc))
9426 err = 1;
9427 else {
9428 handler = &jmploc;
9429 setvar(name, val, flags);
9430 }
9431 handler = savehandler;
9432 return err;
9433}
9434
9435static int
9436getopts(optstr, optvar, optfirst, myoptind, optoff)
9437 char *optstr;
9438 char *optvar;
9439 char **optfirst;
9440 int *myoptind;
9441 int *optoff;
9442{
9443 char *p, *q;
9444 char c = '?';
9445 int done = 0;
9446 int err = 0;
9447 char s[10];
9448 char **optnext = optfirst + *myoptind - 1;
9449
9450 if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
9451 strlen(*(optnext - 1)) < *optoff)
9452 p = NULL;
9453 else
9454 p = *(optnext - 1) + *optoff;
9455 if (p == NULL || *p == '\0') {
9456 /* Current word is done, advance */
9457 if (optnext == NULL)
9458 return 1;
9459 p = *optnext;
9460 if (p == NULL || *p != '-' || *++p == '\0') {
9461atend:
9462 *myoptind = optnext - optfirst + 1;
9463 p = NULL;
9464 done = 1;
9465 goto out;
9466 }
9467 optnext++;
Eric Andersen2870d962001-07-02 17:27:21 +00009468 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009469 goto atend;
9470 }
9471
9472 c = *p++;
9473 for (q = optstr; *q != c; ) {
9474 if (*q == '\0') {
9475 if (optstr[0] == ':') {
9476 s[0] = c;
9477 s[1] = '\0';
9478 err |= setvarsafe("OPTARG", s, 0);
9479 }
9480 else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009481 out2fmt("Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009482 (void) unsetvar("OPTARG");
9483 }
9484 c = '?';
9485 goto bad;
9486 }
9487 if (*++q == ':')
9488 q++;
9489 }
9490
9491 if (*++q == ':') {
9492 if (*p == '\0' && (p = *optnext) == NULL) {
9493 if (optstr[0] == ':') {
9494 s[0] = c;
9495 s[1] = '\0';
9496 err |= setvarsafe("OPTARG", s, 0);
9497 c = ':';
9498 }
9499 else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009500 out2fmt("No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009501 (void) unsetvar("OPTARG");
9502 c = '?';
9503 }
9504 goto bad;
9505 }
9506
9507 if (p == *optnext)
9508 optnext++;
9509 setvarsafe("OPTARG", p, 0);
9510 p = NULL;
9511 }
9512 else
9513 setvarsafe("OPTARG", "", 0);
9514 *myoptind = optnext - optfirst + 1;
9515 goto out;
9516
9517bad:
9518 *myoptind = 1;
9519 p = NULL;
9520out:
9521 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersen3102ac42001-07-06 04:26:23 +00009522 snprintf(s, sizeof(s), "%d", *myoptind);
Eric Andersencb57d552001-06-28 07:25:16 +00009523 err |= setvarsafe("OPTIND", s, VNOFUNC);
9524 s[0] = c;
9525 s[1] = '\0';
9526 err |= setvarsafe(optvar, s, 0);
9527 if (err) {
9528 *myoptind = 1;
9529 *optoff = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00009530 exraise(EXERROR);
9531 }
9532 return done;
9533}
Eric Andersen2870d962001-07-02 17:27:21 +00009534#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009535
9536/*
9537 * XXX - should get rid of. have all builtins use getopt(3). the
9538 * library getopt must have the BSD extension static variable "optreset"
9539 * otherwise it can't be used within the shell safely.
9540 *
9541 * Standard option processing (a la getopt) for builtin routines. The
9542 * only argument that is passed to nextopt is the option string; the
9543 * other arguments are unnecessary. It return the character, or '\0' on
9544 * end of input.
9545 */
9546
9547static int
Eric Andersen62483552001-07-10 06:09:16 +00009548nextopt(const char *optstring)
9549{
Eric Andersencb57d552001-06-28 07:25:16 +00009550 char *p;
9551 const char *q;
9552 char c;
9553
9554 if ((p = optptr) == NULL || *p == '\0') {
9555 p = *argptr;
9556 if (p == NULL || *p != '-' || *++p == '\0')
9557 return '\0';
9558 argptr++;
Eric Andersen2870d962001-07-02 17:27:21 +00009559 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009560 return '\0';
9561 }
9562 c = *p++;
9563 for (q = optstring ; *q != c ; ) {
9564 if (*q == '\0')
9565 error("Illegal option -%c", c);
9566 if (*++q == ':')
9567 q++;
9568 }
9569 if (*++q == ':') {
9570 if (*p == '\0' && (p = *argptr++) == NULL)
9571 error("No arg for -%c option", c);
9572 optionarg = p;
9573 p = NULL;
9574 }
9575 optptr = p;
9576 return c;
9577}
9578
Eric Andersencb57d552001-06-28 07:25:16 +00009579static void
9580flushall() {
Eric Andersencb57d552001-06-28 07:25:16 +00009581 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009582 fflush(stdout);
Eric Andersencb57d552001-06-28 07:25:16 +00009583 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009584}
9585
9586
9587static void
Eric Andersen3102ac42001-07-06 04:26:23 +00009588out2fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009589{
9590 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00009591 va_start(ap, fmt);
Eric Andersen3102ac42001-07-06 04:26:23 +00009592 vfprintf(stderr, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009593 va_end(ap);
9594}
9595
Eric Andersencb57d552001-06-28 07:25:16 +00009596/*
9597 * Version of write which resumes after a signal is caught.
9598 */
9599
9600static int
Eric Andersen2870d962001-07-02 17:27:21 +00009601xwrite(int fd, const char *buf, int nbytes)
9602{
Eric Andersencb57d552001-06-28 07:25:16 +00009603 int ntry;
9604 int i;
9605 int n;
9606
9607 n = nbytes;
9608 ntry = 0;
9609 for (;;) {
9610 i = write(fd, buf, n);
9611 if (i > 0) {
9612 if ((n -= i) <= 0)
9613 return nbytes;
9614 buf += i;
9615 ntry = 0;
9616 } else if (i == 0) {
9617 if (++ntry > 10)
9618 return nbytes - n;
9619 } else if (errno != EINTR) {
9620 return -1;
9621 }
9622 }
9623}
9624
9625
Eric Andersencb57d552001-06-28 07:25:16 +00009626/*
9627 * Shell command parser.
9628 */
9629
9630#define EOFMARKLEN 79
9631
9632
9633
9634struct heredoc {
Eric Andersen2870d962001-07-02 17:27:21 +00009635 struct heredoc *next; /* next here document in list */
9636 union node *here; /* redirection node */
9637 char *eofmark; /* string indicating end of input */
9638 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009639};
9640
Eric Andersen2870d962001-07-02 17:27:21 +00009641static struct heredoc *heredoclist; /* list of here documents to read */
9642static int parsebackquote; /* nonzero if we are inside backquotes */
9643static int doprompt; /* if set, prompt the user */
9644static int needprompt; /* true if interactive and at start of line */
9645static int lasttoken; /* last token read */
Eric Andersencb57d552001-06-28 07:25:16 +00009646
Eric Andersen2870d962001-07-02 17:27:21 +00009647static char *wordtext; /* text of last word returned by readtoken */
Eric Andersencb57d552001-06-28 07:25:16 +00009648
Eric Andersen2870d962001-07-02 17:27:21 +00009649static struct nodelist *backquotelist;
9650static union node *redirnode;
Eric Andersen044228d2001-07-17 01:12:36 +00009651static struct heredoc *heredoc;
Eric Andersen2870d962001-07-02 17:27:21 +00009652static int quoteflag; /* set if (part of) last token was quoted */
9653static int startlinno; /* line # where last token started */
Eric Andersencb57d552001-06-28 07:25:16 +00009654
9655
Eric Andersen2870d962001-07-02 17:27:21 +00009656static union node *list (int);
9657static union node *andor (void);
9658static union node *pipeline (void);
9659static union node *command (void);
9660static union node *simplecmd (void);
9661static void parsefname (void);
9662static void parseheredoc (void);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009663static char peektoken (void);
Eric Andersen2870d962001-07-02 17:27:21 +00009664static int readtoken (void);
9665static int xxreadtoken (void);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009666static int readtoken1 (int, int, const char *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00009667static int noexpand (char *);
9668static void synexpect (int) __attribute__((noreturn));
9669static void synerror (const char *) __attribute__((noreturn));
9670static void setprompt (int);
Eric Andersencb57d552001-06-28 07:25:16 +00009671
9672
9673/*
9674 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9675 * valid parse tree indicating a blank line.)
9676 */
9677
Eric Andersen2870d962001-07-02 17:27:21 +00009678static union node *
Eric Andersencb57d552001-06-28 07:25:16 +00009679parsecmd(int interact)
9680{
9681 int t;
9682
9683 tokpushback = 0;
9684 doprompt = interact;
9685 if (doprompt)
9686 setprompt(1);
9687 else
9688 setprompt(0);
9689 needprompt = 0;
9690 t = readtoken();
9691 if (t == TEOF)
9692 return NEOF;
9693 if (t == TNL)
9694 return NULL;
9695 tokpushback++;
9696 return list(1);
9697}
9698
9699
9700static union node *
9701list(nlflag)
9702 int nlflag;
9703{
9704 union node *n1, *n2, *n3;
9705 int tok;
9706
9707 checkkwd = 2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009708 if (nlflag == 0 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009709 return NULL;
9710 n1 = NULL;
9711 for (;;) {
9712 n2 = andor();
9713 tok = readtoken();
9714 if (tok == TBACKGND) {
9715 if (n2->type == NCMD || n2->type == NPIPE) {
9716 n2->ncmd.backgnd = 1;
9717 } else if (n2->type == NREDIR) {
9718 n2->type = NBACKGND;
9719 } else {
9720 n3 = (union node *)stalloc(sizeof (struct nredir));
9721 n3->type = NBACKGND;
9722 n3->nredir.n = n2;
9723 n3->nredir.redirect = NULL;
9724 n2 = n3;
9725 }
9726 }
9727 if (n1 == NULL) {
9728 n1 = n2;
9729 }
9730 else {
9731 n3 = (union node *)stalloc(sizeof (struct nbinary));
9732 n3->type = NSEMI;
9733 n3->nbinary.ch1 = n1;
9734 n3->nbinary.ch2 = n2;
9735 n1 = n3;
9736 }
9737 switch (tok) {
9738 case TBACKGND:
9739 case TSEMI:
9740 tok = readtoken();
9741 /* fall through */
9742 case TNL:
9743 if (tok == TNL) {
9744 parseheredoc();
9745 if (nlflag)
9746 return n1;
9747 } else {
9748 tokpushback++;
9749 }
9750 checkkwd = 2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009751 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009752 return n1;
9753 break;
9754 case TEOF:
9755 if (heredoclist)
9756 parseheredoc();
9757 else
Eric Andersen2870d962001-07-02 17:27:21 +00009758 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009759 return n1;
9760 default:
9761 if (nlflag)
9762 synexpect(-1);
9763 tokpushback++;
9764 return n1;
9765 }
9766 }
9767}
9768
9769
9770
9771static union node *
9772andor() {
9773 union node *n1, *n2, *n3;
9774 int t;
9775
9776 checkkwd = 1;
9777 n1 = pipeline();
9778 for (;;) {
9779 if ((t = readtoken()) == TAND) {
9780 t = NAND;
9781 } else if (t == TOR) {
9782 t = NOR;
9783 } else {
9784 tokpushback++;
9785 return n1;
9786 }
9787 checkkwd = 2;
9788 n2 = pipeline();
9789 n3 = (union node *)stalloc(sizeof (struct nbinary));
9790 n3->type = t;
9791 n3->nbinary.ch1 = n1;
9792 n3->nbinary.ch2 = n2;
9793 n1 = n3;
9794 }
9795}
9796
9797
9798
9799static union node *
9800pipeline() {
9801 union node *n1, *n2, *pipenode;
9802 struct nodelist *lp, *prev;
9803 int negate;
9804
9805 negate = 0;
9806 TRACE(("pipeline: entered\n"));
9807 if (readtoken() == TNOT) {
9808 negate = !negate;
9809 checkkwd = 1;
9810 } else
9811 tokpushback++;
9812 n1 = command();
9813 if (readtoken() == TPIPE) {
9814 pipenode = (union node *)stalloc(sizeof (struct npipe));
9815 pipenode->type = NPIPE;
9816 pipenode->npipe.backgnd = 0;
9817 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9818 pipenode->npipe.cmdlist = lp;
9819 lp->n = n1;
9820 do {
9821 prev = lp;
9822 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9823 checkkwd = 2;
9824 lp->n = command();
9825 prev->next = lp;
9826 } while (readtoken() == TPIPE);
9827 lp->next = NULL;
9828 n1 = pipenode;
9829 }
9830 tokpushback++;
9831 if (negate) {
9832 n2 = (union node *)stalloc(sizeof (struct nnot));
9833 n2->type = NNOT;
9834 n2->nnot.com = n1;
9835 return n2;
9836 } else
9837 return n1;
9838}
9839
9840
9841
9842static union node *
9843command() {
9844 union node *n1, *n2;
9845 union node *ap, **app;
9846 union node *cp, **cpp;
9847 union node *redir, **rpp;
9848 int t;
9849
9850 redir = NULL;
9851 n1 = NULL;
9852 rpp = &redir;
9853
Eric Andersen88cec252001-09-06 17:35:20 +00009854 /* Check for redirection which may precede command */
9855 while (readtoken() == TREDIR) {
9856 *rpp = n2 = redirnode;
9857 rpp = &n2->nfile.next;
9858 parsefname();
9859 }
9860 tokpushback++;
9861
Eric Andersencb57d552001-06-28 07:25:16 +00009862 switch (readtoken()) {
9863 case TIF:
9864 n1 = (union node *)stalloc(sizeof (struct nif));
9865 n1->type = NIF;
9866 n1->nif.test = list(0);
9867 if (readtoken() != TTHEN)
9868 synexpect(TTHEN);
9869 n1->nif.ifpart = list(0);
9870 n2 = n1;
9871 while (readtoken() == TELIF) {
9872 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9873 n2 = n2->nif.elsepart;
9874 n2->type = NIF;
9875 n2->nif.test = list(0);
9876 if (readtoken() != TTHEN)
9877 synexpect(TTHEN);
9878 n2->nif.ifpart = list(0);
9879 }
9880 if (lasttoken == TELSE)
9881 n2->nif.elsepart = list(0);
9882 else {
9883 n2->nif.elsepart = NULL;
9884 tokpushback++;
9885 }
9886 if (readtoken() != TFI)
9887 synexpect(TFI);
9888 checkkwd = 1;
9889 break;
9890 case TWHILE:
9891 case TUNTIL: {
9892 int got;
9893 n1 = (union node *)stalloc(sizeof (struct nbinary));
9894 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9895 n1->nbinary.ch1 = list(0);
9896 if ((got=readtoken()) != TDO) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009897TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009898 synexpect(TDO);
9899 }
9900 n1->nbinary.ch2 = list(0);
9901 if (readtoken() != TDONE)
9902 synexpect(TDONE);
9903 checkkwd = 1;
9904 break;
9905 }
9906 case TFOR:
9907 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9908 synerror("Bad for loop variable");
9909 n1 = (union node *)stalloc(sizeof (struct nfor));
9910 n1->type = NFOR;
9911 n1->nfor.var = wordtext;
9912 checkkwd = 1;
9913 if (readtoken() == TIN) {
9914 app = &ap;
9915 while (readtoken() == TWORD) {
9916 n2 = (union node *)stalloc(sizeof (struct narg));
9917 n2->type = NARG;
9918 n2->narg.text = wordtext;
9919 n2->narg.backquote = backquotelist;
9920 *app = n2;
9921 app = &n2->narg.next;
9922 }
9923 *app = NULL;
9924 n1->nfor.args = ap;
9925 if (lasttoken != TNL && lasttoken != TSEMI)
9926 synexpect(-1);
9927 } else {
9928 static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
9929 '@', '=', '\0'};
9930 n2 = (union node *)stalloc(sizeof (struct narg));
9931 n2->type = NARG;
9932 n2->narg.text = argvars;
9933 n2->narg.backquote = NULL;
9934 n2->narg.next = NULL;
9935 n1->nfor.args = n2;
9936 /*
9937 * Newline or semicolon here is optional (but note
9938 * that the original Bourne shell only allowed NL).
9939 */
9940 if (lasttoken != TNL && lasttoken != TSEMI)
9941 tokpushback++;
9942 }
9943 checkkwd = 2;
9944 if (readtoken() != TDO)
9945 synexpect(TDO);
9946 n1->nfor.body = list(0);
9947 if (readtoken() != TDONE)
9948 synexpect(TDONE);
9949 checkkwd = 1;
9950 break;
9951 case TCASE:
9952 n1 = (union node *)stalloc(sizeof (struct ncase));
9953 n1->type = NCASE;
9954 if (readtoken() != TWORD)
9955 synexpect(TWORD);
9956 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9957 n2->type = NARG;
9958 n2->narg.text = wordtext;
9959 n2->narg.backquote = backquotelist;
9960 n2->narg.next = NULL;
9961 do {
9962 checkkwd = 1;
9963 } while (readtoken() == TNL);
9964 if (lasttoken != TIN)
9965 synerror("expecting \"in\"");
9966 cpp = &n1->ncase.cases;
9967 checkkwd = 2, readtoken();
9968 do {
9969 if (lasttoken == TLP)
9970 readtoken();
9971 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9972 cp->type = NCLIST;
9973 app = &cp->nclist.pattern;
9974 for (;;) {
9975 *app = ap = (union node *)stalloc(sizeof (struct narg));
9976 ap->type = NARG;
9977 ap->narg.text = wordtext;
9978 ap->narg.backquote = backquotelist;
9979 if (checkkwd = 2, readtoken() != TPIPE)
9980 break;
9981 app = &ap->narg.next;
9982 readtoken();
9983 }
9984 ap->narg.next = NULL;
9985 if (lasttoken != TRP)
9986 synexpect(TRP);
9987 cp->nclist.body = list(0);
9988
9989 checkkwd = 2;
9990 if ((t = readtoken()) != TESAC) {
9991 if (t != TENDCASE)
9992 synexpect(TENDCASE);
9993 else
9994 checkkwd = 2, readtoken();
9995 }
9996 cpp = &cp->nclist.next;
9997 } while(lasttoken != TESAC);
9998 *cpp = NULL;
9999 checkkwd = 1;
10000 break;
10001 case TLP:
10002 n1 = (union node *)stalloc(sizeof (struct nredir));
10003 n1->type = NSUBSHELL;
10004 n1->nredir.n = list(0);
10005 n1->nredir.redirect = NULL;
10006 if (readtoken() != TRP)
10007 synexpect(TRP);
10008 checkkwd = 1;
10009 break;
10010 case TBEGIN:
10011 n1 = list(0);
10012 if (readtoken() != TEND)
10013 synexpect(TEND);
10014 checkkwd = 1;
10015 break;
10016 /* Handle an empty command like other simple commands. */
10017 case TSEMI:
10018 case TAND:
10019 case TOR:
10020 case TNL:
10021 case TEOF:
10022 case TRP:
10023 case TBACKGND:
10024 /*
10025 * An empty command before a ; doesn't make much sense, and
10026 * should certainly be disallowed in the case of `if ;'.
10027 */
10028 if (!redir)
10029 synexpect(-1);
10030 case TWORD:
Eric Andersencb57d552001-06-28 07:25:16 +000010031 tokpushback++;
10032 n1 = simplecmd();
10033 return n1;
10034 default:
10035 synexpect(-1);
10036 /* NOTREACHED */
10037 }
10038
10039 /* Now check for redirection which may follow command */
10040 while (readtoken() == TREDIR) {
10041 *rpp = n2 = redirnode;
10042 rpp = &n2->nfile.next;
10043 parsefname();
10044 }
10045 tokpushback++;
10046 *rpp = NULL;
10047 if (redir) {
10048 if (n1->type != NSUBSHELL) {
10049 n2 = (union node *)stalloc(sizeof (struct nredir));
10050 n2->type = NREDIR;
10051 n2->nredir.n = n1;
10052 n1 = n2;
10053 }
10054 n1->nredir.redirect = redir;
10055 }
10056
10057 return n1;
10058}
10059
10060
10061static union node *
10062simplecmd() {
10063 union node *args, **app;
10064 union node *n = NULL;
10065 union node *vars, **vpp;
10066 union node **rpp, *redir;
10067
10068 args = NULL;
10069 app = &args;
10070 vars = NULL;
10071 vpp = &vars;
10072 redir = NULL;
10073 rpp = &redir;
10074
10075 checkalias = 2;
10076 for (;;) {
10077 switch (readtoken()) {
10078 case TWORD:
10079 case TASSIGN:
10080 n = (union node *)stalloc(sizeof (struct narg));
10081 n->type = NARG;
10082 n->narg.text = wordtext;
10083 n->narg.backquote = backquotelist;
10084 if (lasttoken == TWORD) {
10085 *app = n;
10086 app = &n->narg.next;
10087 } else {
10088 *vpp = n;
10089 vpp = &n->narg.next;
10090 }
10091 break;
10092 case TREDIR:
10093 *rpp = n = redirnode;
10094 rpp = &n->nfile.next;
Eric Andersen2870d962001-07-02 17:27:21 +000010095 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +000010096 break;
10097 case TLP:
10098 if (
10099 args && app == &args->narg.next &&
10100 !vars && !redir
10101 ) {
10102 /* We have a function */
10103 if (readtoken() != TRP)
10104 synexpect(TRP);
Eric Andersencb57d552001-06-28 07:25:16 +000010105 n->type = NDEFUN;
10106 checkkwd = 2;
10107 n->narg.next = command();
10108 return n;
10109 }
10110 /* fall through */
10111 default:
10112 tokpushback++;
10113 goto out;
10114 }
10115 }
10116out:
10117 *app = NULL;
10118 *vpp = NULL;
10119 *rpp = NULL;
10120 n = (union node *)stalloc(sizeof (struct ncmd));
10121 n->type = NCMD;
10122 n->ncmd.backgnd = 0;
10123 n->ncmd.args = args;
10124 n->ncmd.assign = vars;
10125 n->ncmd.redirect = redir;
10126 return n;
10127}
10128
10129static union node *
Eric Andersen2870d962001-07-02 17:27:21 +000010130makename(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000010131 union node *n;
10132
10133 n = (union node *)stalloc(sizeof (struct narg));
10134 n->type = NARG;
10135 n->narg.next = NULL;
10136 n->narg.text = wordtext;
10137 n->narg.backquote = backquotelist;
10138 return n;
10139}
10140
10141static void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +000010142{
Eric Andersencb57d552001-06-28 07:25:16 +000010143 TRACE(("Fix redir %s %d\n", text, err));
10144 if (!err)
10145 n->ndup.vname = NULL;
10146
10147 if (is_digit(text[0]) && text[1] == '\0')
10148 n->ndup.dupfd = digit_val(text[0]);
10149 else if (text[0] == '-' && text[1] == '\0')
10150 n->ndup.dupfd = -1;
10151 else {
10152
10153 if (err)
10154 synerror("Bad fd number");
10155 else
10156 n->ndup.vname = makename();
10157 }
10158}
10159
10160
10161static void
Eric Andersen2870d962001-07-02 17:27:21 +000010162parsefname(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000010163 union node *n = redirnode;
10164
10165 if (readtoken() != TWORD)
10166 synexpect(-1);
10167 if (n->type == NHERE) {
10168 struct heredoc *here = heredoc;
10169 struct heredoc *p;
10170 int i;
10171
10172 if (quoteflag == 0)
10173 n->type = NXHERE;
10174 TRACE(("Here document %d\n", n->type));
10175 if (here->striptabs) {
10176 while (*wordtext == '\t')
10177 wordtext++;
10178 }
10179 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
10180 synerror("Illegal eof marker for << redirection");
10181 rmescapes(wordtext);
10182 here->eofmark = wordtext;
10183 here->next = NULL;
10184 if (heredoclist == NULL)
10185 heredoclist = here;
10186 else {
10187 for (p = heredoclist ; p->next ; p = p->next);
10188 p->next = here;
10189 }
10190 } else if (n->type == NTOFD || n->type == NFROMFD) {
10191 fixredir(n, wordtext, 0);
10192 } else {
10193 n->nfile.fname = makename();
10194 }
10195}
10196
10197
10198/*
10199 * Input any here documents.
10200 */
10201
10202static void
10203parseheredoc() {
10204 struct heredoc *here;
10205 union node *n;
10206
10207 while (heredoclist) {
10208 here = heredoclist;
10209 heredoclist = here->next;
10210 if (needprompt) {
10211 setprompt(2);
10212 needprompt = 0;
10213 }
10214 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
10215 here->eofmark, here->striptabs);
10216 n = (union node *)stalloc(sizeof (struct narg));
10217 n->narg.type = NARG;
10218 n->narg.next = NULL;
10219 n->narg.text = wordtext;
10220 n->narg.backquote = backquotelist;
10221 here->here->nhere.doc = n;
10222 }
10223}
10224
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010225static char
Eric Andersencb57d552001-06-28 07:25:16 +000010226peektoken() {
10227 int t;
10228
10229 t = readtoken();
10230 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010231 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +000010232}
10233
10234static int
10235readtoken() {
10236 int t;
Eric Andersen7467c8d2001-07-12 20:26:32 +000010237
Eric Andersen2870d962001-07-02 17:27:21 +000010238#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010239 int savecheckalias = checkalias;
Eric Andersen7467c8d2001-07-12 20:26:32 +000010240 int savecheckkwd = checkkwd;
Eric Andersencb57d552001-06-28 07:25:16 +000010241 struct alias *ap;
Eric Andersen2870d962001-07-02 17:27:21 +000010242#endif
10243
Eric Andersencb57d552001-06-28 07:25:16 +000010244#ifdef DEBUG
10245 int alreadyseen = tokpushback;
10246#endif
10247
Eric Andersen2870d962001-07-02 17:27:21 +000010248#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010249top:
Eric Andersen2870d962001-07-02 17:27:21 +000010250#endif
10251
Eric Andersencb57d552001-06-28 07:25:16 +000010252 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +000010253
10254#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010255 checkalias = savecheckalias;
Eric Andersen2870d962001-07-02 17:27:21 +000010256#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010257
10258 if (checkkwd) {
10259 /*
10260 * eat newlines
10261 */
10262 if (checkkwd == 2) {
10263 checkkwd = 0;
10264 while (t == TNL) {
10265 parseheredoc();
10266 t = xxreadtoken();
10267 }
10268 }
10269 checkkwd = 0;
10270 /*
10271 * check for keywords
10272 */
10273 if (t == TWORD && !quoteflag)
10274 {
10275 const char *const *pp;
10276
10277 if ((pp = findkwd(wordtext))) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010278 lasttoken = t = pp - tokname_array;
10279 TRACE(("keyword %s recognized\n", tokname(t)));
Eric Andersencb57d552001-06-28 07:25:16 +000010280 goto out;
10281 }
10282 }
10283 }
10284
Eric Andersen7467c8d2001-07-12 20:26:32 +000010285
Eric Andersencb57d552001-06-28 07:25:16 +000010286 if (t != TWORD) {
10287 if (t != TREDIR) {
10288 checkalias = 0;
10289 }
10290 } else if (checkalias == 2 && isassignment(wordtext)) {
10291 lasttoken = t = TASSIGN;
Eric Andersen7467c8d2001-07-12 20:26:32 +000010292#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010293 } else if (checkalias) {
10294 if (!quoteflag && (ap = lookupalias(wordtext, 1)) != NULL) {
10295 if (*ap->val) {
10296 pushstring(ap->val, strlen(ap->val), ap);
10297 }
10298 checkkwd = savecheckkwd;
10299 goto top;
10300 }
10301 checkalias = 0;
Eric Andersen2870d962001-07-02 17:27:21 +000010302#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +000010303 }
Eric Andersencb57d552001-06-28 07:25:16 +000010304out:
10305#ifdef DEBUG
10306 if (!alreadyseen)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010307 TRACE(("token %s %s\n", tokname(t), t == TWORD || t == TASSIGN ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +000010308 else
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010309 TRACE(("reread token %s %s\n", tokname(t), t == TWORD || t == TASSIGN ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +000010310#endif
10311 return (t);
10312}
10313
10314
10315/*
10316 * Read the next input token.
10317 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +000010318 * backquotes. We set quoteflag to true if any part of the word was
10319 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +000010320 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +000010321 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +000010322 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +000010323 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +000010324 *
10325 * [Change comment: here documents and internal procedures]
10326 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10327 * word parsing code into a separate routine. In this case, readtoken
10328 * doesn't need to have any internal procedures, but parseword does.
10329 * We could also make parseoperator in essence the main routine, and
10330 * have parseword (readtoken1?) handle both words and redirection.]
10331 */
10332
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +000010333#define NEW_xxreadtoken
10334#ifdef NEW_xxreadtoken
10335
10336static const char xxreadtoken_chars[] = "\n()&|;"; /* singles must be first! */
10337static const char xxreadtoken_tokens[] = {
10338 TNL, TLP, TRP, /* only single occurrence allowed */
10339 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10340 TEOF, /* corresponds to trailing nul */
10341 TAND, TOR, TENDCASE, /* if double occurrence */
10342};
10343
10344#define xxreadtoken_doubles \
10345 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10346#define xxreadtoken_singles \
10347 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10348
10349static int
10350xxreadtoken() {
10351 int c;
10352
10353 if (tokpushback) {
10354 tokpushback = 0;
10355 return lasttoken;
10356 }
10357 if (needprompt) {
10358 setprompt(2);
10359 needprompt = 0;
10360 }
10361 startlinno = plinno;
10362 for (;;) { /* until token or start of word found */
10363 c = pgetc_macro();
10364
10365 if ((c!=' ') && (c!='\t')
10366#ifdef ASH_ALIAS
10367 && (c!=PEOA)
10368#endif
10369 ) {
10370 if (c=='#') {
10371 while ((c = pgetc()) != '\n' && c != PEOF);
10372 pungetc();
10373 } else if (c=='\\') {
10374 if (pgetc() != '\n') {
10375 pungetc();
10376 goto READTOKEN1;
10377 }
10378 startlinno = ++plinno;
10379 setprompt(doprompt ? 2 : 0);
10380 } else {
10381 const char *p
10382 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10383
10384 if (c!=PEOF) {
10385 if (c=='\n') {
10386 plinno++;
10387 needprompt = doprompt;
10388 }
10389
10390 p = strchr(xxreadtoken_chars, c);
10391 if (p == NULL) {
10392 READTOKEN1:
10393 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10394 }
10395
10396 if (p-xxreadtoken_chars >= xxreadtoken_singles) {
10397 if (pgetc() == *p) { /* double occurrence? */
10398 p += xxreadtoken_doubles + 1;
10399 } else {
10400 pungetc();
10401 }
10402 }
10403 }
10404
10405 return lasttoken = xxreadtoken_tokens[p-xxreadtoken_chars];
10406 }
10407 }
10408 }
10409}
10410
10411
10412#else
Eric Andersen2870d962001-07-02 17:27:21 +000010413#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010414
10415static int
10416xxreadtoken() {
10417 int c;
10418
10419 if (tokpushback) {
10420 tokpushback = 0;
10421 return lasttoken;
10422 }
10423 if (needprompt) {
10424 setprompt(2);
10425 needprompt = 0;
10426 }
10427 startlinno = plinno;
Eric Andersen2870d962001-07-02 17:27:21 +000010428 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010429 c = pgetc_macro();
10430 switch (c) {
10431 case ' ': case '\t':
Eric Andersen3102ac42001-07-06 04:26:23 +000010432#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010433 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010434#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010435 continue;
10436 case '#':
10437 while ((c = pgetc()) != '\n' && c != PEOF);
10438 pungetc();
10439 continue;
10440 case '\\':
10441 if (pgetc() == '\n') {
10442 startlinno = ++plinno;
10443 if (doprompt)
10444 setprompt(2);
10445 else
10446 setprompt(0);
10447 continue;
10448 }
10449 pungetc();
10450 goto breakloop;
10451 case '\n':
10452 plinno++;
10453 needprompt = doprompt;
10454 RETURN(TNL);
10455 case PEOF:
10456 RETURN(TEOF);
10457 case '&':
10458 if (pgetc() == '&')
10459 RETURN(TAND);
10460 pungetc();
10461 RETURN(TBACKGND);
10462 case '|':
10463 if (pgetc() == '|')
10464 RETURN(TOR);
10465 pungetc();
10466 RETURN(TPIPE);
10467 case ';':
10468 if (pgetc() == ';')
10469 RETURN(TENDCASE);
10470 pungetc();
10471 RETURN(TSEMI);
10472 case '(':
10473 RETURN(TLP);
10474 case ')':
10475 RETURN(TRP);
10476 default:
10477 goto breakloop;
10478 }
10479 }
10480breakloop:
10481 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10482#undef RETURN
10483}
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +000010484#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010485
10486
10487/*
10488 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10489 * is not NULL, read a here document. In the latter case, eofmark is the
10490 * word which marks the end of the document and striptabs is true if
10491 * leading tabs should be stripped from the document. The argument firstc
10492 * is the first character of the input token or document.
10493 *
10494 * Because C does not have internal subroutines, I have simulated them
10495 * using goto's to implement the subroutine linkage. The following macros
10496 * will run code that appears at the end of readtoken1.
10497 */
10498
Eric Andersen2870d962001-07-02 17:27:21 +000010499#define CHECKEND() {goto checkend; checkend_return:;}
10500#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10501#define PARSESUB() {goto parsesub; parsesub_return:;}
10502#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10503#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10504#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010505
10506static int
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010507readtoken1(int firstc, int syntax, const char *eofmark, int striptabs)
10508{
Eric Andersencb57d552001-06-28 07:25:16 +000010509 int c = firstc;
10510 char *out;
10511 int len;
10512 char line[EOFMARKLEN + 1];
10513 struct nodelist *bqlist;
10514 int quotef;
10515 int dblquote;
Eric Andersen2870d962001-07-02 17:27:21 +000010516 int varnest; /* levels of variables expansion */
10517 int arinest; /* levels of arithmetic expansion */
10518 int parenlevel; /* levels of parens in arithmetic */
10519 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +000010520 int oldstyle;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010521 int prevsyntax; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010522#if __GNUC__
10523 /* Avoid longjmp clobbering */
10524 (void) &out;
10525 (void) &quotef;
10526 (void) &dblquote;
10527 (void) &varnest;
10528 (void) &arinest;
10529 (void) &parenlevel;
10530 (void) &dqvarnest;
10531 (void) &oldstyle;
10532 (void) &prevsyntax;
10533 (void) &syntax;
10534#endif
10535
10536 startlinno = plinno;
10537 dblquote = 0;
10538 if (syntax == DQSYNTAX)
10539 dblquote = 1;
10540 quotef = 0;
10541 bqlist = NULL;
10542 varnest = 0;
10543 arinest = 0;
10544 parenlevel = 0;
10545 dqvarnest = 0;
10546
10547 STARTSTACKSTR(out);
Eric Andersen2870d962001-07-02 17:27:21 +000010548 loop: { /* for each line, until end of word */
10549 CHECKEND(); /* set c to PEOF if at end of here document */
10550 for (;;) { /* until end of line or end of word */
10551 CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010552 switch(SIT(c,syntax)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010553 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010554 if (syntax == BASESYNTAX)
Eric Andersen2870d962001-07-02 17:27:21 +000010555 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010556 USTPUTC(c, out);
10557 plinno++;
10558 if (doprompt)
10559 setprompt(2);
10560 else
10561 setprompt(0);
10562 c = pgetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010563 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010564 case CWORD:
10565 USTPUTC(c, out);
10566 break;
10567 case CCTL:
10568 if ((eofmark == NULL || dblquote) &&
10569 dqvarnest == 0)
10570 USTPUTC(CTLESC, out);
10571 USTPUTC(c, out);
10572 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010573 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010574 c = pgetc2();
10575 if (c == PEOF) {
10576 USTPUTC('\\', out);
10577 pungetc();
10578 } else if (c == '\n') {
10579 if (doprompt)
10580 setprompt(2);
10581 else
10582 setprompt(0);
10583 } else {
10584 if (dblquote && c != '\\' && c != '`' && c != '$'
10585 && (c != '"' || eofmark != NULL))
10586 USTPUTC('\\', out);
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010587 if (SIT(c,SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010588 USTPUTC(CTLESC, out);
10589 else if (eofmark == NULL)
10590 USTPUTC(CTLQUOTEMARK, out);
10591 USTPUTC(c, out);
10592 quotef++;
10593 }
10594 break;
10595 case CSQUOTE:
10596 if (eofmark == NULL)
10597 USTPUTC(CTLQUOTEMARK, out);
10598 syntax = SQSYNTAX;
10599 break;
10600 case CDQUOTE:
10601 if (eofmark == NULL)
10602 USTPUTC(CTLQUOTEMARK, out);
10603 syntax = DQSYNTAX;
10604 dblquote = 1;
10605 break;
10606 case CENDQUOTE:
10607 if (eofmark != NULL && arinest == 0 &&
10608 varnest == 0) {
10609 USTPUTC(c, out);
10610 } else {
10611 if (arinest) {
10612 syntax = ARISYNTAX;
10613 dblquote = 0;
10614 } else if (eofmark == NULL &&
10615 dqvarnest == 0) {
10616 syntax = BASESYNTAX;
10617 dblquote = 0;
10618 }
10619 quotef++;
10620 }
10621 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010622 case CVAR: /* '$' */
10623 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010624 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010625 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010626 if (varnest > 0) {
10627 varnest--;
10628 if (dqvarnest > 0) {
10629 dqvarnest--;
10630 }
10631 USTPUTC(CTLENDVAR, out);
10632 } else {
10633 USTPUTC(c, out);
10634 }
10635 break;
10636#ifdef ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +000010637 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010638 parenlevel++;
10639 USTPUTC(c, out);
10640 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010641 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010642 if (parenlevel > 0) {
10643 USTPUTC(c, out);
10644 --parenlevel;
10645 } else {
10646 if (pgetc() == ')') {
10647 if (--arinest == 0) {
10648 USTPUTC(CTLENDARI, out);
10649 syntax = prevsyntax;
10650 if (syntax == DQSYNTAX)
10651 dblquote = 1;
10652 else
10653 dblquote = 0;
10654 } else
10655 USTPUTC(')', out);
10656 } else {
10657 /*
10658 * unbalanced parens
10659 * (don't 2nd guess - no error)
10660 */
10661 pungetc();
10662 USTPUTC(')', out);
10663 }
10664 }
10665 break;
10666#endif
Eric Andersen2870d962001-07-02 17:27:21 +000010667 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010668 PARSEBACKQOLD();
10669 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010670 case CENDFILE:
10671 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010672 case CIGN:
10673 break;
10674 default:
10675 if (varnest == 0)
Eric Andersen2870d962001-07-02 17:27:21 +000010676 goto endword; /* exit outer loop */
Eric Andersen3102ac42001-07-06 04:26:23 +000010677#ifdef ASH_ALIAS
10678 if (c != PEOA)
10679#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010680 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010681
Eric Andersencb57d552001-06-28 07:25:16 +000010682 }
10683 c = pgetc_macro();
10684 }
10685 }
10686endword:
10687 if (syntax == ARISYNTAX)
10688 synerror("Missing '))'");
10689 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10690 synerror("Unterminated quoted string");
10691 if (varnest != 0) {
10692 startlinno = plinno;
10693 synerror("Missing '}'");
10694 }
10695 USTPUTC('\0', out);
10696 len = out - stackblock();
10697 out = stackblock();
10698 if (eofmark == NULL) {
10699 if ((c == '>' || c == '<')
10700 && quotef == 0
10701 && len <= 2
10702 && (*out == '\0' || is_digit(*out))) {
10703 PARSEREDIR();
10704 return lasttoken = TREDIR;
10705 } else {
10706 pungetc();
10707 }
10708 }
10709 quoteflag = quotef;
10710 backquotelist = bqlist;
10711 grabstackblock(len);
10712 wordtext = out;
10713 return lasttoken = TWORD;
10714/* end of readtoken routine */
10715
10716
10717
10718/*
10719 * Check to see whether we are at the end of the here document. When this
10720 * is called, c is set to the first character of the next input line. If
10721 * we are at the end of the here document, this routine sets the c to PEOF.
10722 */
10723
10724checkend: {
10725 if (eofmark) {
Eric Andersen2870d962001-07-02 17:27:21 +000010726#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010727 if (c == PEOA) {
10728 c = pgetc2();
10729 }
Eric Andersen2870d962001-07-02 17:27:21 +000010730#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010731 if (striptabs) {
10732 while (c == '\t') {
10733 c = pgetc2();
10734 }
10735 }
10736 if (c == *eofmark) {
10737 if (pfgets(line, sizeof line) != NULL) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010738 const char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010739
10740 p = line;
10741 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10742 if (*p == '\n' && *q == '\0') {
10743 c = PEOF;
10744 plinno++;
10745 needprompt = doprompt;
10746 } else {
10747 pushstring(line, strlen(line), NULL);
10748 }
10749 }
10750 }
10751 }
10752 goto checkend_return;
10753}
10754
10755
10756/*
10757 * Parse a redirection operator. The variable "out" points to a string
10758 * specifying the fd to be redirected. The variable "c" contains the
10759 * first character of the redirection operator.
10760 */
10761
10762parseredir: {
10763 char fd = *out;
10764 union node *np;
10765
10766 np = (union node *)stalloc(sizeof (struct nfile));
10767 if (c == '>') {
10768 np->nfile.fd = 1;
10769 c = pgetc();
10770 if (c == '>')
10771 np->type = NAPPEND;
10772 else if (c == '&')
10773 np->type = NTOFD;
10774 else if (c == '|')
10775 np->type = NTOOV;
10776 else {
10777 np->type = NTO;
10778 pungetc();
10779 }
Eric Andersen2870d962001-07-02 17:27:21 +000010780 } else { /* c == '<' */
Eric Andersencb57d552001-06-28 07:25:16 +000010781 np->nfile.fd = 0;
10782 switch (c = pgetc()) {
10783 case '<':
10784 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10785 np = (union node *)stalloc(sizeof (struct nhere));
10786 np->nfile.fd = 0;
10787 }
10788 np->type = NHERE;
10789 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10790 heredoc->here = np;
10791 if ((c = pgetc()) == '-') {
10792 heredoc->striptabs = 1;
10793 } else {
10794 heredoc->striptabs = 0;
10795 pungetc();
10796 }
10797 break;
10798
10799 case '&':
10800 np->type = NFROMFD;
10801 break;
10802
10803 case '>':
10804 np->type = NFROMTO;
10805 break;
10806
10807 default:
10808 np->type = NFROM;
10809 pungetc();
10810 break;
10811 }
10812 }
10813 if (fd != '\0')
10814 np->nfile.fd = digit_val(fd);
10815 redirnode = np;
10816 goto parseredir_return;
10817}
10818
10819
10820/*
10821 * Parse a substitution. At this point, we have read the dollar sign
10822 * and nothing else.
10823 */
10824
10825parsesub: {
10826 int subtype;
10827 int typeloc;
10828 int flags;
10829 char *p;
10830 static const char types[] = "}-+?=";
10831
10832 c = pgetc();
10833 if (
10834 c <= PEOA ||
10835 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10836 ) {
10837 USTPUTC('$', out);
10838 pungetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010839 } else if (c == '(') { /* $(command) or $((arith)) */
Eric Andersencb57d552001-06-28 07:25:16 +000010840 if (pgetc() == '(') {
10841 PARSEARITH();
10842 } else {
10843 pungetc();
10844 PARSEBACKQNEW();
10845 }
10846 } else {
10847 USTPUTC(CTLVAR, out);
10848 typeloc = out - stackblock();
10849 USTPUTC(VSNORMAL, out);
10850 subtype = VSNORMAL;
10851 if (c == '{') {
10852 c = pgetc();
10853 if (c == '#') {
10854 if ((c = pgetc()) == '}')
10855 c = '#';
10856 else
10857 subtype = VSLENGTH;
10858 }
10859 else
10860 subtype = 0;
10861 }
10862 if (c > PEOA && is_name(c)) {
10863 do {
10864 STPUTC(c, out);
10865 c = pgetc();
10866 } while (c > PEOA && is_in_name(c));
10867 } else if (is_digit(c)) {
10868 do {
10869 USTPUTC(c, out);
10870 c = pgetc();
10871 } while (is_digit(c));
10872 }
10873 else if (is_special(c)) {
10874 USTPUTC(c, out);
10875 c = pgetc();
10876 }
10877 else
Eric Andersen2870d962001-07-02 17:27:21 +000010878badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010879
10880 STPUTC('=', out);
10881 flags = 0;
10882 if (subtype == 0) {
10883 switch (c) {
10884 case ':':
10885 flags = VSNUL;
10886 c = pgetc();
10887 /*FALLTHROUGH*/
10888 default:
10889 p = strchr(types, c);
10890 if (p == NULL)
10891 goto badsub;
10892 subtype = p - types + VSNORMAL;
10893 break;
10894 case '%':
10895 case '#':
10896 {
10897 int cc = c;
10898 subtype = c == '#' ? VSTRIMLEFT :
10899 VSTRIMRIGHT;
10900 c = pgetc();
10901 if (c == cc)
10902 subtype++;
10903 else
10904 pungetc();
10905 break;
10906 }
10907 }
10908 } else {
10909 pungetc();
10910 }
10911 if (dblquote || arinest)
10912 flags |= VSQUOTE;
10913 *(stackblock() + typeloc) = subtype | flags;
10914 if (subtype != VSNORMAL) {
10915 varnest++;
10916 if (dblquote) {
10917 dqvarnest++;
10918 }
10919 }
10920 }
10921 goto parsesub_return;
10922}
10923
10924
10925/*
10926 * Called to parse command substitutions. Newstyle is set if the command
10927 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10928 * list of commands (passed by reference), and savelen is the number of
10929 * characters on the top of the stack which must be preserved.
10930 */
10931
10932parsebackq: {
10933 struct nodelist **nlpp;
10934 int savepbq;
10935 union node *n;
10936 char *volatile str;
10937 struct jmploc jmploc;
10938 struct jmploc *volatile savehandler;
10939 int savelen;
10940 int saveprompt;
10941#ifdef __GNUC__
10942 (void) &saveprompt;
10943#endif
10944
10945 savepbq = parsebackquote;
10946 if (setjmp(jmploc.loc)) {
10947 if (str)
10948 ckfree(str);
10949 parsebackquote = 0;
10950 handler = savehandler;
10951 longjmp(handler->loc, 1);
10952 }
10953 INTOFF;
10954 str = NULL;
10955 savelen = out - stackblock();
10956 if (savelen > 0) {
10957 str = ckmalloc(savelen);
10958 memcpy(str, stackblock(), savelen);
10959 }
10960 savehandler = handler;
10961 handler = &jmploc;
10962 INTON;
Eric Andersen2870d962001-07-02 17:27:21 +000010963 if (oldstyle) {
10964 /* We must read until the closing backquote, giving special
10965 treatment to some slashes, and then push the string and
10966 reread it as input, interpreting it normally. */
10967 char *pout;
10968 int pc;
10969 int psavelen;
10970 char *pstr;
Eric Andersencb57d552001-06-28 07:25:16 +000010971
10972
Eric Andersen2870d962001-07-02 17:27:21 +000010973 STARTSTACKSTR(pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010974 for (;;) {
10975 if (needprompt) {
10976 setprompt(2);
10977 needprompt = 0;
10978 }
10979 switch (pc = pgetc()) {
10980 case '`':
10981 goto done;
10982
10983 case '\\':
Eric Andersen2870d962001-07-02 17:27:21 +000010984 if ((pc = pgetc()) == '\n') {
Eric Andersencb57d552001-06-28 07:25:16 +000010985 plinno++;
10986 if (doprompt)
10987 setprompt(2);
10988 else
10989 setprompt(0);
10990 /*
10991 * If eating a newline, avoid putting
10992 * the newline into the new character
10993 * stream (via the STPUTC after the
10994 * switch).
10995 */
10996 continue;
10997 }
Eric Andersen2870d962001-07-02 17:27:21 +000010998 if (pc != '\\' && pc != '`' && pc != '$'
10999 && (!dblquote || pc != '"'))
11000 STPUTC('\\', pout);
Eric Andersencb57d552001-06-28 07:25:16 +000011001 if (pc > PEOA) {
11002 break;
11003 }
11004 /* fall through */
11005
11006 case PEOF:
Eric Andersen2870d962001-07-02 17:27:21 +000011007#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000011008 case PEOA:
Eric Andersen2870d962001-07-02 17:27:21 +000011009#endif
11010 startlinno = plinno;
Eric Andersencb57d552001-06-28 07:25:16 +000011011 synerror("EOF in backquote substitution");
11012
11013 case '\n':
11014 plinno++;
11015 needprompt = doprompt;
11016 break;
11017
11018 default:
11019 break;
11020 }
11021 STPUTC(pc, pout);
Eric Andersen2870d962001-07-02 17:27:21 +000011022 }
Eric Andersencb57d552001-06-28 07:25:16 +000011023done:
Eric Andersen2870d962001-07-02 17:27:21 +000011024 STPUTC('\0', pout);
11025 psavelen = pout - stackblock();
11026 if (psavelen > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000011027 pstr = grabstackstr(pout);
11028 setinputstring(pstr);
Eric Andersen2870d962001-07-02 17:27:21 +000011029 }
11030 }
Eric Andersencb57d552001-06-28 07:25:16 +000011031 nlpp = &bqlist;
11032 while (*nlpp)
11033 nlpp = &(*nlpp)->next;
11034 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
11035 (*nlpp)->next = NULL;
11036 parsebackquote = oldstyle;
11037
11038 if (oldstyle) {
11039 saveprompt = doprompt;
11040 doprompt = 0;
11041 }
11042
11043 n = list(0);
11044
11045 if (oldstyle)
11046 doprompt = saveprompt;
11047 else {
11048 if (readtoken() != TRP)
11049 synexpect(TRP);
11050 }
11051
11052 (*nlpp)->n = n;
Eric Andersen2870d962001-07-02 17:27:21 +000011053 if (oldstyle) {
Eric Andersencb57d552001-06-28 07:25:16 +000011054 /*
11055 * Start reading from old file again, ignoring any pushed back
11056 * tokens left from the backquote parsing
11057 */
Eric Andersen2870d962001-07-02 17:27:21 +000011058 popfile();
Eric Andersencb57d552001-06-28 07:25:16 +000011059 tokpushback = 0;
11060 }
11061 while (stackblocksize() <= savelen)
11062 growstackblock();
11063 STARTSTACKSTR(out);
11064 if (str) {
11065 memcpy(out, str, savelen);
11066 STADJUST(savelen, out);
11067 INTOFF;
11068 ckfree(str);
11069 str = NULL;
11070 INTON;
11071 }
11072 parsebackquote = savepbq;
11073 handler = savehandler;
11074 if (arinest || dblquote)
11075 USTPUTC(CTLBACKQ | CTLQUOTE, out);
11076 else
11077 USTPUTC(CTLBACKQ, out);
11078 if (oldstyle)
11079 goto parsebackq_oldreturn;
11080 else
11081 goto parsebackq_newreturn;
11082}
11083
11084/*
11085 * Parse an arithmetic expansion (indicate start of one and set state)
11086 */
11087parsearith: {
11088
11089 if (++arinest == 1) {
11090 prevsyntax = syntax;
11091 syntax = ARISYNTAX;
11092 USTPUTC(CTLARI, out);
11093 if (dblquote)
11094 USTPUTC('"',out);
11095 else
11096 USTPUTC(' ',out);
11097 } else {
11098 /*
11099 * we collapse embedded arithmetic expansion to
11100 * parenthesis, which should be equivalent
11101 */
11102 USTPUTC('(', out);
11103 }
11104 goto parsearith_return;
11105}
11106
11107} /* end of readtoken */
11108
11109
Eric Andersencb57d552001-06-28 07:25:16 +000011110/*
11111 * Returns true if the text contains nothing to expand (no dollar signs
11112 * or backquotes).
11113 */
11114
11115static int
11116noexpand(text)
11117 char *text;
11118 {
11119 char *p;
11120 char c;
11121
11122 p = text;
11123 while ((c = *p++) != '\0') {
11124 if (c == CTLQUOTEMARK)
11125 continue;
11126 if (c == CTLESC)
11127 p++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011128 else if (SIT(c,BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000011129 return 0;
11130 }
11131 return 1;
11132}
11133
11134
11135/*
11136 * Return true if the argument is a legal variable name (a letter or
11137 * underscore followed by zero or more letters, underscores, and digits).
11138 */
11139
11140static int
Eric Andersen2870d962001-07-02 17:27:21 +000011141goodname(const char *name)
11142{
11143 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000011144
11145 p = name;
11146 if (! is_name(*p))
11147 return 0;
11148 while (*++p) {
11149 if (! is_in_name(*p))
11150 return 0;
11151 }
11152 return 1;
11153}
11154
11155
11156/*
11157 * Called when an unexpected token is read during the parse. The argument
11158 * is the token that is expected, or -1 if more than one type of token can
11159 * occur at this point.
11160 */
11161
11162static void
11163synexpect(token)
11164 int token;
11165{
11166 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011167 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000011168
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011169 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
11170 if (token >= 0)
11171 sprintf(msg+l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000011172 synerror(msg);
11173 /* NOTREACHED */
11174}
11175
11176
11177static void
Eric Andersen2870d962001-07-02 17:27:21 +000011178synerror(const char *msg)
11179{
Eric Andersencb57d552001-06-28 07:25:16 +000011180 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +000011181 out2fmt("%s: %d: ", commandname, startlinno);
11182 out2fmt("Syntax error: %s\n", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000011183 error((char *)NULL);
11184 /* NOTREACHED */
11185}
11186
Eric Andersencb57d552001-06-28 07:25:16 +000011187
11188/*
11189 * called by editline -- any expansions to the prompt
11190 * should be added here.
11191 */
Eric Andersen2870d962001-07-02 17:27:21 +000011192static void
Eric Andersen62483552001-07-10 06:09:16 +000011193setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000011194{
Eric Andersen62483552001-07-10 06:09:16 +000011195 char *prompt;
11196 switch (whichprompt) {
11197 case 1:
11198 prompt = ps1val();
11199 break;
11200 case 2:
11201 prompt = ps2val();
11202 break;
11203 default: /* 0 */
11204 prompt = "";
11205 }
11206 putprompt(prompt);
Eric Andersencb57d552001-06-28 07:25:16 +000011207}
11208
Eric Andersencb57d552001-06-28 07:25:16 +000011209
Eric Andersencb57d552001-06-28 07:25:16 +000011210/*
11211 * Code for dealing with input/output redirection.
11212 */
11213
Eric Andersen2870d962001-07-02 17:27:21 +000011214#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000011215#ifndef PIPE_BUF
Eric Andersen2870d962001-07-02 17:27:21 +000011216# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000011217#else
11218# define PIPESIZE PIPE_BUF
11219#endif
11220
11221
Eric Andersen62483552001-07-10 06:09:16 +000011222/*
11223 * Open a file in noclobber mode.
11224 * The code was copied from bash.
11225 */
11226static inline int
11227noclobberopen(const char *fname)
11228{
11229 int r, fd;
11230 struct stat finfo, finfo2;
11231
11232 /*
11233 * If the file exists and is a regular file, return an error
11234 * immediately.
11235 */
11236 r = stat(fname, &finfo);
11237 if (r == 0 && S_ISREG(finfo.st_mode)) {
11238 errno = EEXIST;
11239 return -1;
11240 }
11241
11242 /*
11243 * If the file was not present (r != 0), make sure we open it
11244 * exclusively so that if it is created before we open it, our open
11245 * will fail. Make sure that we do not truncate an existing file.
11246 * Note that we don't turn on O_EXCL unless the stat failed -- if the
11247 * file was not a regular file, we leave O_EXCL off.
11248 */
11249 if (r != 0)
11250 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
11251 fd = open(fname, O_WRONLY|O_CREAT, 0666);
11252
11253 /* If the open failed, return the file descriptor right away. */
11254 if (fd < 0)
11255 return fd;
11256
11257 /*
11258 * OK, the open succeeded, but the file may have been changed from a
11259 * non-regular file to a regular file between the stat and the open.
11260 * We are assuming that the O_EXCL open handles the case where FILENAME
11261 * did not exist and is symlinked to an existing file between the stat
11262 * and open.
11263 */
11264
11265 /*
11266 * If we can open it and fstat the file descriptor, and neither check
11267 * revealed that it was a regular file, and the file has not been
11268 * replaced, return the file descriptor.
11269 */
11270 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
11271 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
11272 return fd;
11273
11274 /* The file has been replaced. badness. */
11275 close(fd);
11276 errno = EEXIST;
11277 return -1;
11278}
Eric Andersencb57d552001-06-28 07:25:16 +000011279
11280/*
Eric Andersen62483552001-07-10 06:09:16 +000011281 * Handle here documents. Normally we fork off a process to write the
11282 * data to a pipe. If the document is short, we can stuff the data in
11283 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000011284 */
11285
Eric Andersen62483552001-07-10 06:09:16 +000011286static inline int
11287openhere(const union node *redir)
11288{
11289 int pip[2];
11290 int len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011291
Eric Andersen62483552001-07-10 06:09:16 +000011292 if (pipe(pip) < 0)
11293 error("Pipe call failed");
11294 if (redir->type == NHERE) {
11295 len = strlen(redir->nhere.doc->narg.text);
11296 if (len <= PIPESIZE) {
11297 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11298 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011299 }
Eric Andersencb57d552001-06-28 07:25:16 +000011300 }
Eric Andersen62483552001-07-10 06:09:16 +000011301 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
11302 close(pip[0]);
11303 signal(SIGINT, SIG_IGN);
11304 signal(SIGQUIT, SIG_IGN);
11305 signal(SIGHUP, SIG_IGN);
11306#ifdef SIGTSTP
11307 signal(SIGTSTP, SIG_IGN);
11308#endif
11309 signal(SIGPIPE, SIG_DFL);
11310 if (redir->type == NHERE)
11311 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11312 else
11313 expandhere(redir->nhere.doc, pip[1]);
11314 _exit(0);
11315 }
11316out:
11317 close(pip[1]);
11318 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000011319}
11320
11321
Eric Andersen62483552001-07-10 06:09:16 +000011322static inline int
11323openredirect(const union node *redir)
11324{
Eric Andersencb57d552001-06-28 07:25:16 +000011325 char *fname;
11326 int f;
11327
11328 switch (redir->nfile.type) {
11329 case NFROM:
11330 fname = redir->nfile.expfname;
11331 if ((f = open(fname, O_RDONLY)) < 0)
11332 goto eopen;
11333 break;
11334 case NFROMTO:
11335 fname = redir->nfile.expfname;
11336 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
11337 goto ecreate;
11338 break;
11339 case NTO:
11340 /* Take care of noclobber mode. */
11341 if (Cflag) {
11342 fname = redir->nfile.expfname;
11343 if ((f = noclobberopen(fname)) < 0)
11344 goto ecreate;
11345 break;
11346 }
11347 case NTOOV:
11348 fname = redir->nfile.expfname;
11349#ifdef O_CREAT
11350 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
11351 goto ecreate;
11352#else
11353 if ((f = creat(fname, 0666)) < 0)
11354 goto ecreate;
11355#endif
11356 break;
11357 case NAPPEND:
11358 fname = redir->nfile.expfname;
11359#ifdef O_APPEND
11360 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
11361 goto ecreate;
11362#else
11363 if ((f = open(fname, O_WRONLY)) < 0
11364 && (f = creat(fname, 0666)) < 0)
11365 goto ecreate;
11366 lseek(f, (off_t)0, 2);
11367#endif
11368 break;
11369 default:
11370#ifdef DEBUG
11371 abort();
11372#endif
11373 /* Fall through to eliminate warning. */
11374 case NTOFD:
11375 case NFROMFD:
11376 f = -1;
11377 break;
11378 case NHERE:
11379 case NXHERE:
11380 f = openhere(redir);
11381 break;
11382 }
11383
11384 return f;
11385ecreate:
11386 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11387eopen:
11388 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11389}
11390
11391
Eric Andersen62483552001-07-10 06:09:16 +000011392/*
11393 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11394 * old file descriptors are stashed away so that the redirection can be
11395 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11396 * standard output, and the standard error if it becomes a duplicate of
11397 * stdout.
11398 */
11399
Eric Andersencb57d552001-06-28 07:25:16 +000011400static void
Eric Andersen62483552001-07-10 06:09:16 +000011401redirect(union node *redir, int flags)
11402{
11403 union node *n;
11404 struct redirtab *sv = NULL;
11405 int i;
11406 int fd;
11407 int newfd;
11408 int try;
11409 int fd1dup = flags & REDIR_BACKQ;; /* stdout `cmd` redir to pipe */
11410
11411 if (flags & REDIR_PUSH) {
11412 sv = ckmalloc(sizeof (struct redirtab));
11413 for (i = 0 ; i < 10 ; i++)
11414 sv->renamed[i] = EMPTY;
11415 sv->next = redirlist;
11416 redirlist = sv;
11417 }
11418 for (n = redir ; n ; n = n->nfile.next) {
11419 fd = n->nfile.fd;
11420 try = 0;
11421 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11422 n->ndup.dupfd == fd)
11423 continue; /* redirect from/to same file descriptor */
11424
11425 INTOFF;
11426 newfd = openredirect(n);
11427 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
11428 if (newfd == fd) {
11429 try++;
11430 } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
11431 switch (errno) {
11432 case EBADF:
11433 if (!try) {
11434 dupredirect(n, newfd, fd1dup);
11435 try++;
11436 break;
11437 }
11438 /* FALLTHROUGH*/
11439 default:
11440 if (newfd >= 0) {
11441 close(newfd);
11442 }
11443 INTON;
11444 error("%d: %m", fd);
11445 /* NOTREACHED */
11446 }
11447 }
11448 if (!try) {
11449 close(fd);
11450 if (flags & REDIR_PUSH) {
11451 sv->renamed[fd] = i;
11452 }
11453 }
11454 } else if (fd != newfd) {
11455 close(fd);
11456 }
11457 if (fd == 0)
11458 fd0_redirected++;
11459 if (!try)
11460 dupredirect(n, newfd, fd1dup);
11461 INTON;
11462 }
11463}
11464
11465
11466static void
11467dupredirect(const union node *redir, int f, int fd1dup)
Eric Andersen2870d962001-07-02 17:27:21 +000011468{
Eric Andersencb57d552001-06-28 07:25:16 +000011469 int fd = redir->nfile.fd;
11470
Eric Andersen62483552001-07-10 06:09:16 +000011471 if(fd==1)
11472 fd1dup = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011473 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Eric Andersen2870d962001-07-02 17:27:21 +000011474 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
Eric Andersen62483552001-07-10 06:09:16 +000011475 if (redir->ndup.dupfd!=1 || fd1dup!=1)
Eric Andersencb57d552001-06-28 07:25:16 +000011476 dup_as_newfd(redir->ndup.dupfd, fd);
11477 }
11478 return;
11479 }
11480
11481 if (f != fd) {
11482 dup_as_newfd(f, fd);
11483 close(f);
11484 }
11485 return;
11486}
11487
11488
Eric Andersencb57d552001-06-28 07:25:16 +000011489
Eric Andersencb57d552001-06-28 07:25:16 +000011490/*
11491 * Undo the effects of the last redirection.
11492 */
11493
11494static void
Eric Andersen2870d962001-07-02 17:27:21 +000011495popredir(void)
11496{
Eric Andersencb57d552001-06-28 07:25:16 +000011497 struct redirtab *rp = redirlist;
11498 int i;
11499
11500 INTOFF;
11501 for (i = 0 ; i < 10 ; i++) {
11502 if (rp->renamed[i] != EMPTY) {
Eric Andersen2870d962001-07-02 17:27:21 +000011503 if (i == 0)
11504 fd0_redirected--;
Eric Andersencb57d552001-06-28 07:25:16 +000011505 close(i);
11506 if (rp->renamed[i] >= 0) {
11507 dup_as_newfd(rp->renamed[i], i);
11508 close(rp->renamed[i]);
11509 }
Eric Andersencb57d552001-06-28 07:25:16 +000011510 }
11511 }
11512 redirlist = rp->next;
11513 ckfree(rp);
11514 INTON;
11515}
11516
11517/*
Eric Andersencb57d552001-06-28 07:25:16 +000011518 * Discard all saved file descriptors.
11519 */
11520
11521static void
Eric Andersen2870d962001-07-02 17:27:21 +000011522clearredir(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000011523 struct redirtab *rp;
11524 int i;
11525
11526 for (rp = redirlist ; rp ; rp = rp->next) {
11527 for (i = 0 ; i < 10 ; i++) {
11528 if (rp->renamed[i] >= 0) {
11529 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011530 }
11531 rp->renamed[i] = EMPTY;
11532 }
11533 }
Eric Andersencb57d552001-06-28 07:25:16 +000011534}
11535
11536
Eric Andersencb57d552001-06-28 07:25:16 +000011537/*
11538 * Copy a file descriptor to be >= to. Returns -1
11539 * if the source file descriptor is closed, EMPTY if there are no unused
11540 * file descriptors left.
11541 */
11542
11543static int
11544dup_as_newfd(from, to)
11545 int from;
11546 int to;
11547{
11548 int newfd;
11549
11550 newfd = fcntl(from, F_DUPFD, to);
11551 if (newfd < 0) {
11552 if (errno == EMFILE)
11553 return EMPTY;
11554 else
Eric Andersen2870d962001-07-02 17:27:21 +000011555 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011556 }
11557 return newfd;
11558}
11559
Eric Andersencb57d552001-06-28 07:25:16 +000011560#ifdef DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +000011561static void shtree (union node *, int, char *, FILE*);
11562static void shcmd (union node *, FILE *);
11563static void sharg (union node *, FILE *);
11564static void indent (int, char *, FILE *);
11565static void trstring (char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011566
11567
11568static void
11569showtree(n)
11570 union node *n;
11571{
11572 trputs("showtree called\n");
11573 shtree(n, 1, NULL, stdout);
11574}
11575
11576
11577static void
11578shtree(n, ind, pfx, fp)
11579 union node *n;
11580 int ind;
11581 char *pfx;
11582 FILE *fp;
11583{
11584 struct nodelist *lp;
11585 const char *s;
11586
11587 if (n == NULL)
11588 return;
11589
11590 indent(ind, pfx, fp);
11591 switch(n->type) {
11592 case NSEMI:
11593 s = "; ";
11594 goto binop;
11595 case NAND:
11596 s = " && ";
11597 goto binop;
11598 case NOR:
11599 s = " || ";
11600binop:
11601 shtree(n->nbinary.ch1, ind, NULL, fp);
11602 /* if (ind < 0) */
11603 fputs(s, fp);
11604 shtree(n->nbinary.ch2, ind, NULL, fp);
11605 break;
11606 case NCMD:
11607 shcmd(n, fp);
11608 if (ind >= 0)
11609 putc('\n', fp);
11610 break;
11611 case NPIPE:
11612 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11613 shcmd(lp->n, fp);
11614 if (lp->next)
11615 fputs(" | ", fp);
11616 }
11617 if (n->npipe.backgnd)
11618 fputs(" &", fp);
11619 if (ind >= 0)
11620 putc('\n', fp);
11621 break;
11622 default:
11623 fprintf(fp, "<node type %d>", n->type);
11624 if (ind >= 0)
11625 putc('\n', fp);
11626 break;
11627 }
11628}
11629
11630
11631
11632static void
11633shcmd(cmd, fp)
11634 union node *cmd;
11635 FILE *fp;
11636{
11637 union node *np;
11638 int first;
11639 const char *s;
11640 int dftfd;
11641
11642 first = 1;
11643 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11644 if (! first)
11645 putchar(' ');
11646 sharg(np, fp);
11647 first = 0;
11648 }
11649 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11650 if (! first)
11651 putchar(' ');
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011652#if 1
11653 s = "*error*";
11654 dftfd = 0;
11655 if ((np->nfile.type <= NFROMFD) && (np->nfile.type >= NTO)) {
11656 s = redir_strings[np->nfile.type - NTO];
11657 if (*s == '>') {
11658 dftfd = 1;
11659 }
11660 }
11661#else
Eric Andersencb57d552001-06-28 07:25:16 +000011662 switch (np->nfile.type) {
Eric Andersen2870d962001-07-02 17:27:21 +000011663 case NTO: s = ">"; dftfd = 1; break;
11664 case NAPPEND: s = ">>"; dftfd = 1; break;
11665 case NTOFD: s = ">&"; dftfd = 1; break;
11666 case NTOOV: s = ">|"; dftfd = 1; break;
11667 case NFROM: s = "<"; dftfd = 0; break;
11668 case NFROMFD: s = "<&"; dftfd = 0; break;
11669 case NFROMTO: s = "<>"; dftfd = 0; break;
11670 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011671 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011672#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011673 if (np->nfile.fd != dftfd)
11674 fprintf(fp, "%d", np->nfile.fd);
11675 fputs(s, fp);
11676 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11677 fprintf(fp, "%d", np->ndup.dupfd);
11678 } else {
11679 sharg(np->nfile.fname, fp);
11680 }
11681 first = 0;
11682 }
11683}
11684
11685
11686
11687static void
11688sharg(arg, fp)
11689 union node *arg;
11690 FILE *fp;
11691 {
11692 char *p;
11693 struct nodelist *bqlist;
11694 int subtype;
11695
11696 if (arg->type != NARG) {
11697 printf("<node type %d>\n", arg->type);
11698 fflush(stdout);
11699 abort();
11700 }
11701 bqlist = arg->narg.backquote;
11702 for (p = arg->narg.text ; *p ; p++) {
11703 switch (*p) {
11704 case CTLESC:
11705 putc(*++p, fp);
11706 break;
11707 case CTLVAR:
11708 putc('$', fp);
11709 putc('{', fp);
11710 subtype = *++p;
11711 if (subtype == VSLENGTH)
11712 putc('#', fp);
11713
11714 while (*p != '=')
11715 putc(*p++, fp);
11716
11717 if (subtype & VSNUL)
11718 putc(':', fp);
11719
11720 switch (subtype & VSTYPE) {
11721 case VSNORMAL:
11722 putc('}', fp);
11723 break;
11724 case VSMINUS:
11725 putc('-', fp);
11726 break;
11727 case VSPLUS:
11728 putc('+', fp);
11729 break;
11730 case VSQUESTION:
11731 putc('?', fp);
11732 break;
11733 case VSASSIGN:
11734 putc('=', fp);
11735 break;
11736 case VSTRIMLEFT:
11737 putc('#', fp);
11738 break;
11739 case VSTRIMLEFTMAX:
11740 putc('#', fp);
11741 putc('#', fp);
11742 break;
11743 case VSTRIMRIGHT:
11744 putc('%', fp);
11745 break;
11746 case VSTRIMRIGHTMAX:
11747 putc('%', fp);
11748 putc('%', fp);
11749 break;
11750 case VSLENGTH:
11751 break;
11752 default:
11753 printf("<subtype %d>", subtype);
11754 }
11755 break;
11756 case CTLENDVAR:
11757 putc('}', fp);
11758 break;
11759 case CTLBACKQ:
11760 case CTLBACKQ|CTLQUOTE:
11761 putc('$', fp);
11762 putc('(', fp);
11763 shtree(bqlist->n, -1, NULL, fp);
11764 putc(')', fp);
11765 break;
11766 default:
11767 putc(*p, fp);
11768 break;
11769 }
11770 }
11771}
11772
11773
11774static void
11775indent(amount, pfx, fp)
11776 int amount;
11777 char *pfx;
11778 FILE *fp;
11779{
11780 int i;
11781
11782 for (i = 0 ; i < amount ; i++) {
11783 if (pfx && i == amount - 1)
11784 fputs(pfx, fp);
11785 putc('\t', fp);
11786 }
11787}
11788#endif
11789
11790
11791
11792/*
11793 * Debugging stuff.
11794 */
11795
11796
11797#ifdef DEBUG
11798FILE *tracefile;
11799
11800#if DEBUG == 2
11801static int debug = 1;
11802#else
11803static int debug = 0;
11804#endif
11805
11806
11807static void
11808trputc(c)
11809 int c;
11810{
11811 if (tracefile == NULL)
11812 return;
11813 putc(c, tracefile);
11814 if (c == '\n')
11815 fflush(tracefile);
11816}
11817
11818static void
11819trace(const char *fmt, ...)
11820{
11821 va_list va;
Eric Andersencb57d552001-06-28 07:25:16 +000011822 va_start(va, fmt);
Eric Andersencb57d552001-06-28 07:25:16 +000011823 if (tracefile != NULL) {
11824 (void) vfprintf(tracefile, fmt, va);
11825 if (strchr(fmt, '\n'))
11826 (void) fflush(tracefile);
11827 }
11828 va_end(va);
11829}
11830
11831
11832static void
11833trputs(s)
11834 const char *s;
11835{
11836 if (tracefile == NULL)
11837 return;
11838 fputs(s, tracefile);
11839 if (strchr(s, '\n'))
11840 fflush(tracefile);
11841}
11842
11843
11844static void
11845trstring(s)
11846 char *s;
11847{
11848 char *p;
11849 char c;
11850
11851 if (tracefile == NULL)
11852 return;
11853 putc('"', tracefile);
11854 for (p = s ; *p ; p++) {
11855 switch (*p) {
11856 case '\n': c = 'n'; goto backslash;
11857 case '\t': c = 't'; goto backslash;
11858 case '\r': c = 'r'; goto backslash;
11859 case '"': c = '"'; goto backslash;
11860 case '\\': c = '\\'; goto backslash;
11861 case CTLESC: c = 'e'; goto backslash;
11862 case CTLVAR: c = 'v'; goto backslash;
11863 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11864 case CTLBACKQ: c = 'q'; goto backslash;
11865 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
Eric Andersen2870d962001-07-02 17:27:21 +000011866backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011867 putc(c, tracefile);
11868 break;
11869 default:
11870 if (*p >= ' ' && *p <= '~')
11871 putc(*p, tracefile);
11872 else {
11873 putc('\\', tracefile);
11874 putc(*p >> 6 & 03, tracefile);
11875 putc(*p >> 3 & 07, tracefile);
11876 putc(*p & 07, tracefile);
11877 }
11878 break;
11879 }
11880 }
11881 putc('"', tracefile);
11882}
11883
11884
11885static void
11886trargs(ap)
11887 char **ap;
11888{
11889 if (tracefile == NULL)
11890 return;
11891 while (*ap) {
11892 trstring(*ap++);
11893 if (*ap)
11894 putc(' ', tracefile);
11895 else
11896 putc('\n', tracefile);
11897 }
11898 fflush(tracefile);
11899}
11900
11901
11902static void
11903opentrace() {
11904 char s[100];
11905#ifdef O_APPEND
11906 int flags;
11907#endif
11908
11909 if (!debug)
11910 return;
11911#ifdef not_this_way
11912 {
11913 char *p;
11914 if ((p = getenv("HOME")) == NULL) {
11915 if (geteuid() == 0)
11916 p = "/";
11917 else
11918 p = "/tmp";
11919 }
Eric Andersen2870d962001-07-02 17:27:21 +000011920 strcpy(s, p);
Eric Andersencb57d552001-06-28 07:25:16 +000011921 strcat(s, "/trace");
11922 }
11923#else
Eric Andersen2870d962001-07-02 17:27:21 +000011924 strcpy(s, "./trace");
Eric Andersencb57d552001-06-28 07:25:16 +000011925#endif /* not_this_way */
11926 if ((tracefile = fopen(s, "a")) == NULL) {
11927 fprintf(stderr, "Can't open %s\n", s);
11928 return;
11929 }
11930#ifdef O_APPEND
11931 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11932 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11933#endif
11934 fputs("\nTracing started.\n", tracefile);
11935 fflush(tracefile);
11936}
11937#endif /* DEBUG */
11938
11939
11940/*
Eric Andersencb57d552001-06-28 07:25:16 +000011941 * The trap builtin.
11942 */
11943
11944static int
11945trapcmd(argc, argv)
11946 int argc;
11947 char **argv;
11948{
11949 char *action;
11950 char **ap;
11951 int signo;
11952
11953 if (argc <= 1) {
11954 for (signo = 0 ; signo < NSIG ; signo++) {
11955 if (trap[signo] != NULL) {
11956 char *p;
Eric Andersen34506362001-08-02 05:02:46 +000011957 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011958
11959 p = single_quote(trap[signo]);
Eric Andersen34506362001-08-02 05:02:46 +000011960 sn = sys_siglist[signo];
11961 if(sn==NULL)
11962 sn = u_signal_names(0, &signo, 0);
11963 if(sn==NULL)
11964 sn = "???";
11965 printf("trap -- %s %s\n", p, sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011966 stunalloc(p);
11967 }
11968 }
11969 return 0;
11970 }
11971 ap = argv + 1;
11972 if (argc == 2)
11973 action = NULL;
11974 else
11975 action = *ap++;
11976 while (*ap) {
11977 if ((signo = decode_signal(*ap, 0)) < 0)
11978 error("%s: bad trap", *ap);
11979 INTOFF;
11980 if (action) {
11981 if (action[0] == '-' && action[1] == '\0')
11982 action = NULL;
11983 else
11984 action = savestr(action);
11985 }
11986 if (trap[signo])
11987 ckfree(trap[signo]);
11988 trap[signo] = action;
11989 if (signo != 0)
11990 setsignal(signo);
11991 INTON;
11992 ap++;
11993 }
11994 return 0;
11995}
11996
11997
11998
Eric Andersencb57d552001-06-28 07:25:16 +000011999
12000
12001
12002/*
12003 * Set the signal handler for the specified signal. The routine figures
12004 * out what it should be set to.
12005 */
12006
12007static void
Eric Andersen2870d962001-07-02 17:27:21 +000012008setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000012009{
12010 int action;
12011 char *t;
12012 struct sigaction act;
12013
12014 if ((t = trap[signo]) == NULL)
12015 action = S_DFL;
12016 else if (*t != '\0')
12017 action = S_CATCH;
12018 else
12019 action = S_IGN;
12020 if (rootshell && action == S_DFL) {
12021 switch (signo) {
12022 case SIGINT:
12023 if (iflag || minusc || sflag == 0)
12024 action = S_CATCH;
12025 break;
12026 case SIGQUIT:
12027#ifdef DEBUG
12028 {
Eric Andersencb57d552001-06-28 07:25:16 +000012029
12030 if (debug)
12031 break;
12032 }
12033#endif
12034 /* FALLTHROUGH */
12035 case SIGTERM:
12036 if (iflag)
12037 action = S_IGN;
12038 break;
Eric Andersen2870d962001-07-02 17:27:21 +000012039#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000012040 case SIGTSTP:
12041 case SIGTTOU:
12042 if (mflag)
12043 action = S_IGN;
12044 break;
12045#endif
12046 }
12047 }
12048
12049 t = &sigmode[signo - 1];
12050 if (*t == 0) {
12051 /*
12052 * current setting unknown
12053 */
12054 if (sigaction(signo, 0, &act) == -1) {
12055 /*
12056 * Pretend it worked; maybe we should give a warning
12057 * here, but other shells don't. We don't alter
12058 * sigmode, so that we retry every time.
12059 */
12060 return;
12061 }
12062 if (act.sa_handler == SIG_IGN) {
12063 if (mflag && (signo == SIGTSTP ||
12064 signo == SIGTTIN || signo == SIGTTOU)) {
Eric Andersen2870d962001-07-02 17:27:21 +000012065 *t = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000012066 } else
12067 *t = S_HARD_IGN;
12068 } else {
Eric Andersen2870d962001-07-02 17:27:21 +000012069 *t = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000012070 }
12071 }
12072 if (*t == S_HARD_IGN || *t == action)
12073 return;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000012074 act.sa_handler = ((action == S_CATCH) ? onsig
12075 : ((action == S_IGN) ? SIG_IGN : SIG_DFL));
Eric Andersencb57d552001-06-28 07:25:16 +000012076 *t = action;
12077 act.sa_flags = 0;
12078 sigemptyset(&act.sa_mask);
12079 sigaction(signo, &act, 0);
12080}
12081
12082/*
12083 * Ignore a signal.
12084 */
12085
12086static void
12087ignoresig(signo)
12088 int signo;
12089{
12090 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
12091 signal(signo, SIG_IGN);
12092 }
12093 sigmode[signo - 1] = S_HARD_IGN;
12094}
12095
12096
Eric Andersencb57d552001-06-28 07:25:16 +000012097/*
12098 * Signal handler.
12099 */
12100
12101static void
Eric Andersen2870d962001-07-02 17:27:21 +000012102onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000012103{
12104 if (signo == SIGINT && trap[SIGINT] == NULL) {
12105 onint();
12106 return;
12107 }
12108 gotsig[signo - 1] = 1;
12109 pendingsigs++;
12110}
12111
12112
Eric Andersencb57d552001-06-28 07:25:16 +000012113/*
12114 * Called to execute a trap. Perhaps we should avoid entering new trap
12115 * handlers while we are executing a trap handler.
12116 */
12117
12118static void
Eric Andersen2870d962001-07-02 17:27:21 +000012119dotrap(void)
12120{
Eric Andersencb57d552001-06-28 07:25:16 +000012121 int i;
12122 int savestatus;
12123
12124 for (;;) {
12125 for (i = 1 ; ; i++) {
12126 if (gotsig[i - 1])
12127 break;
12128 if (i >= NSIG - 1)
12129 goto done;
12130 }
12131 gotsig[i - 1] = 0;
12132 savestatus=exitstatus;
12133 evalstring(trap[i], 0);
12134 exitstatus=savestatus;
12135 }
12136done:
12137 pendingsigs = 0;
12138}
12139
Eric Andersencb57d552001-06-28 07:25:16 +000012140/*
12141 * Called to exit the shell.
12142 */
12143
12144static void
Eric Andersen2870d962001-07-02 17:27:21 +000012145exitshell(int status)
Eric Andersencb57d552001-06-28 07:25:16 +000012146{
12147 struct jmploc loc1, loc2;
12148 char *p;
12149
12150 TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
12151 if (setjmp(loc1.loc)) {
12152 goto l1;
12153 }
12154 if (setjmp(loc2.loc)) {
12155 goto l2;
12156 }
12157 handler = &loc1;
12158 if ((p = trap[0]) != NULL && *p != '\0') {
12159 trap[0] = NULL;
12160 evalstring(p, 0);
12161 }
Eric Andersen2870d962001-07-02 17:27:21 +000012162l1: handler = &loc2; /* probably unnecessary */
Eric Andersencb57d552001-06-28 07:25:16 +000012163 flushall();
Eric Andersen2870d962001-07-02 17:27:21 +000012164#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000012165 setjobctl(0);
12166#endif
12167l2: _exit(status);
12168 /* NOTREACHED */
12169}
12170
12171static int decode_signal(const char *string, int minsig)
12172{
12173 int signo;
Eric Andersen34506362001-08-02 05:02:46 +000012174 const char *name = u_signal_names(string, &signo, minsig);
Eric Andersencb57d552001-06-28 07:25:16 +000012175
Eric Andersen34506362001-08-02 05:02:46 +000012176 return name ? signo : -1;
Eric Andersencb57d552001-06-28 07:25:16 +000012177}
Eric Andersen34506362001-08-02 05:02:46 +000012178
Eric Andersen2870d962001-07-02 17:27:21 +000012179static struct var **hashvar (const char *);
12180static void showvars (const char *, int, int);
12181static struct var **findvar (struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000012182
12183/*
12184 * Initialize the varable symbol tables and import the environment
12185 */
12186
Eric Andersencb57d552001-06-28 07:25:16 +000012187/*
12188 * This routine initializes the builtin variables. It is called when the
12189 * shell is initialized and again when a shell procedure is spawned.
12190 */
12191
12192static void
12193initvar() {
12194 const struct varinit *ip;
12195 struct var *vp;
12196 struct var **vpp;
12197
12198 for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
12199 if ((vp->flags & VEXPORT) == 0) {
12200 vpp = hashvar(ip->text);
12201 vp->next = *vpp;
12202 *vpp = vp;
12203 vp->text = strdup(ip->text);
12204 vp->flags = ip->flags;
12205 vp->func = ip->func;
12206 }
12207 }
12208 /*
12209 * PS1 depends on uid
12210 */
12211 if ((vps1.flags & VEXPORT) == 0) {
12212 vpp = hashvar("PS1=");
12213 vps1.next = *vpp;
12214 *vpp = &vps1;
12215 vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# ");
12216 vps1.flags = VSTRFIXED|VTEXTFIXED;
12217 }
12218}
12219
12220/*
12221 * Set the value of a variable. The flags argument is ored with the
12222 * flags of the variable. If val is NULL, the variable is unset.
12223 */
12224
12225static void
12226setvar(name, val, flags)
12227 const char *name, *val;
12228 int flags;
12229{
12230 const char *p;
12231 int len;
12232 int namelen;
12233 char *nameeq;
12234 int isbad;
12235 int vallen = 0;
12236
12237 isbad = 0;
12238 p = name;
12239 if (! is_name(*p))
12240 isbad = 1;
12241 p++;
12242 for (;;) {
12243 if (! is_in_name(*p)) {
12244 if (*p == '\0' || *p == '=')
12245 break;
12246 isbad = 1;
12247 }
12248 p++;
12249 }
12250 namelen = p - name;
12251 if (isbad)
12252 error("%.*s: bad variable name", namelen, name);
Eric Andersen2870d962001-07-02 17:27:21 +000012253 len = namelen + 2; /* 2 is space for '=' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +000012254 if (val == NULL) {
12255 flags |= VUNSET;
12256 } else {
12257 len += vallen = strlen(val);
12258 }
12259 INTOFF;
12260 nameeq = ckmalloc(len);
12261 memcpy(nameeq, name, namelen);
12262 nameeq[namelen] = '=';
12263 if (val) {
12264 memcpy(nameeq + namelen + 1, val, vallen + 1);
12265 } else {
12266 nameeq[namelen + 1] = '\0';
12267 }
12268 setvareq(nameeq, flags);
12269 INTON;
12270}
12271
12272
12273
12274/*
12275 * Same as setvar except that the variable and value are passed in
12276 * the first argument as name=value. Since the first argument will
12277 * be actually stored in the table, it should not be a string that
12278 * will go away.
12279 */
12280
12281static void
12282setvareq(s, flags)
12283 char *s;
12284 int flags;
12285{
12286 struct var *vp, **vpp;
12287
12288 vpp = hashvar(s);
12289 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
12290 if ((vp = *findvar(vpp, s))) {
12291 if (vp->flags & VREADONLY) {
12292 size_t len = strchr(s, '=') - s;
12293 error("%.*s: is read only", len, s);
12294 }
12295 INTOFF;
12296
12297 if (vp->func && (flags & VNOFUNC) == 0)
12298 (*vp->func)(strchr(s, '=') + 1);
12299
12300 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12301 ckfree(vp->text);
12302
12303 vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
12304 vp->flags |= flags;
12305 vp->text = s;
12306
12307 /*
12308 * We could roll this to a function, to handle it as
12309 * a regular variable function callback, but why bother?
12310 */
12311 if (iflag && (vp == &vmpath || (vp == &vmail && !mpathset())))
12312 chkmail(1);
12313 INTON;
12314 return;
12315 }
12316 /* not found */
12317 vp = ckmalloc(sizeof (*vp));
12318 vp->flags = flags;
12319 vp->text = s;
12320 vp->next = *vpp;
12321 vp->func = NULL;
12322 *vpp = vp;
12323}
12324
12325
12326
12327/*
12328 * Process a linked list of variable assignments.
12329 */
12330
12331static void
12332listsetvar(mylist)
12333 struct strlist *mylist;
12334 {
12335 struct strlist *lp;
12336
12337 INTOFF;
12338 for (lp = mylist ; lp ; lp = lp->next) {
12339 setvareq(savestr(lp->text), 0);
12340 }
12341 INTON;
12342}
12343
12344
12345
12346/*
12347 * Find the value of a variable. Returns NULL if not set.
12348 */
12349
Eric Andersen62483552001-07-10 06:09:16 +000012350static const char *
Eric Andersencb57d552001-06-28 07:25:16 +000012351lookupvar(name)
12352 const char *name;
12353 {
12354 struct var *v;
12355
12356 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
12357 return strchr(v->text, '=') + 1;
12358 }
12359 return NULL;
12360}
12361
12362
12363
12364/*
12365 * Search the environment of a builtin command.
12366 */
12367
Eric Andersen62483552001-07-10 06:09:16 +000012368static const char *
12369bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012370{
Eric Andersen62483552001-07-10 06:09:16 +000012371 const struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012372
12373 for (sp = cmdenviron ; sp ; sp = sp->next) {
12374 if (varequal(sp->text, name))
12375 return strchr(sp->text, '=') + 1;
12376 }
12377 return lookupvar(name);
12378}
12379
12380
12381
12382/*
12383 * Generate a list of exported variables. This routine is used to construct
12384 * the third argument to execve when executing a program.
12385 */
12386
12387static char **
12388environment() {
12389 int nenv;
12390 struct var **vpp;
12391 struct var *vp;
12392 char **env;
12393 char **ep;
12394
12395 nenv = 0;
12396 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12397 for (vp = *vpp ; vp ; vp = vp->next)
12398 if (vp->flags & VEXPORT)
12399 nenv++;
12400 }
12401 ep = env = stalloc((nenv + 1) * sizeof *env);
12402 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12403 for (vp = *vpp ; vp ; vp = vp->next)
12404 if (vp->flags & VEXPORT)
12405 *ep++ = vp->text;
12406 }
12407 *ep = NULL;
12408 return env;
12409}
12410
12411
12412/*
12413 * Called when a shell procedure is invoked to clear out nonexported
12414 * variables. It is also necessary to reallocate variables of with
12415 * VSTACK set since these are currently allocated on the stack.
12416 */
12417
Eric Andersencb57d552001-06-28 07:25:16 +000012418static void
Eric Andersen2870d962001-07-02 17:27:21 +000012419shprocvar(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000012420 struct var **vpp;
12421 struct var *vp, **prev;
12422
12423 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12424 for (prev = vpp ; (vp = *prev) != NULL ; ) {
12425 if ((vp->flags & VEXPORT) == 0) {
12426 *prev = vp->next;
12427 if ((vp->flags & VTEXTFIXED) == 0)
12428 ckfree(vp->text);
12429 if ((vp->flags & VSTRFIXED) == 0)
12430 ckfree(vp);
12431 } else {
12432 if (vp->flags & VSTACK) {
12433 vp->text = savestr(vp->text);
12434 vp->flags &=~ VSTACK;
12435 }
12436 prev = &vp->next;
12437 }
12438 }
12439 }
12440 initvar();
12441}
12442
12443
12444
12445/*
12446 * Command to list all variables which are set. Currently this command
12447 * is invoked from the set command when the set command is called without
12448 * any variables.
12449 */
12450
12451static int
12452showvarscmd(argc, argv)
12453 int argc;
12454 char **argv;
12455{
12456 showvars(nullstr, VUNSET, VUNSET);
12457 return 0;
12458}
12459
12460
12461
12462/*
12463 * The export and readonly commands.
12464 */
12465
12466static int
12467exportcmd(argc, argv)
12468 int argc;
12469 char **argv;
12470{
12471 struct var *vp;
12472 char *name;
12473 const char *p;
12474 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12475 int pflag;
12476
12477 listsetvar(cmdenviron);
12478 pflag = (nextopt("p") == 'p');
12479 if (argc > 1 && !pflag) {
12480 while ((name = *argptr++) != NULL) {
12481 if ((p = strchr(name, '=')) != NULL) {
12482 p++;
12483 } else {
12484 if ((vp = *findvar(hashvar(name), name))) {
12485 vp->flags |= flag;
12486 goto found;
12487 }
12488 }
12489 setvar(name, p, flag);
12490found:;
12491 }
12492 } else {
12493 showvars(argv[0], flag, 0);
12494 }
12495 return 0;
12496}
12497
Eric Andersen34506362001-08-02 05:02:46 +000012498
Eric Andersencb57d552001-06-28 07:25:16 +000012499/*
12500 * The "local" command.
12501 */
12502
Eric Andersen2870d962001-07-02 17:27:21 +000012503/* funcnest nonzero if we are currently evaluating a function */
12504
Eric Andersencb57d552001-06-28 07:25:16 +000012505static int
12506localcmd(argc, argv)
12507 int argc;
12508 char **argv;
12509{
12510 char *name;
12511
Eric Andersen2870d962001-07-02 17:27:21 +000012512 if (! funcnest)
Eric Andersencb57d552001-06-28 07:25:16 +000012513 error("Not in a function");
12514 while ((name = *argptr++) != NULL) {
12515 mklocal(name);
12516 }
12517 return 0;
12518}
12519
12520
12521/*
12522 * Make a variable a local variable. When a variable is made local, it's
12523 * value and flags are saved in a localvar structure. The saved values
12524 * will be restored when the shell function returns. We handle the name
12525 * "-" as a special case.
12526 */
12527
12528static void
12529mklocal(name)
12530 char *name;
12531 {
12532 struct localvar *lvp;
12533 struct var **vpp;
12534 struct var *vp;
12535
12536 INTOFF;
12537 lvp = ckmalloc(sizeof (struct localvar));
12538 if (name[0] == '-' && name[1] == '\0') {
12539 char *p;
Eric Andersen2870d962001-07-02 17:27:21 +000012540 p = ckmalloc(sizeof optet_vals);
12541 lvp->text = memcpy(p, optet_vals, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000012542 vp = NULL;
12543 } else {
12544 vpp = hashvar(name);
12545 vp = *findvar(vpp, name);
12546 if (vp == NULL) {
12547 if (strchr(name, '='))
12548 setvareq(savestr(name), VSTRFIXED);
12549 else
12550 setvar(name, NULL, VSTRFIXED);
Eric Andersen2870d962001-07-02 17:27:21 +000012551 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012552 lvp->text = NULL;
12553 lvp->flags = VUNSET;
12554 } else {
12555 lvp->text = vp->text;
12556 lvp->flags = vp->flags;
12557 vp->flags |= VSTRFIXED|VTEXTFIXED;
12558 if (strchr(name, '='))
12559 setvareq(savestr(name), 0);
12560 }
12561 }
12562 lvp->vp = vp;
12563 lvp->next = localvars;
12564 localvars = lvp;
12565 INTON;
12566}
12567
12568
12569/*
12570 * Called after a function returns.
12571 */
12572
12573static void
12574poplocalvars() {
12575 struct localvar *lvp;
12576 struct var *vp;
12577
12578 while ((lvp = localvars) != NULL) {
12579 localvars = lvp->next;
12580 vp = lvp->vp;
Eric Andersen2870d962001-07-02 17:27:21 +000012581 if (vp == NULL) { /* $- saved */
12582 memcpy(optet_vals, lvp->text, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000012583 ckfree(lvp->text);
12584 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12585 (void)unsetvar(vp->text);
12586 } else {
12587 if ((vp->flags & VTEXTFIXED) == 0)
12588 ckfree(vp->text);
12589 vp->flags = lvp->flags;
12590 vp->text = lvp->text;
12591 }
12592 ckfree(lvp);
12593 }
12594}
12595
12596
12597static int
12598setvarcmd(argc, argv)
12599 int argc;
12600 char **argv;
12601{
12602 if (argc <= 2)
12603 return unsetcmd(argc, argv);
12604 else if (argc == 3)
12605 setvar(argv[1], argv[2], 0);
12606 else
12607 error("List assignment not implemented");
12608 return 0;
12609}
12610
12611
12612/*
12613 * The unset builtin command. We unset the function before we unset the
12614 * variable to allow a function to be unset when there is a readonly variable
12615 * with the same name.
12616 */
12617
12618static int
12619unsetcmd(argc, argv)
12620 int argc;
12621 char **argv;
12622{
12623 char **ap;
12624 int i;
12625 int flg_func = 0;
12626 int flg_var = 0;
12627 int ret = 0;
12628
12629 while ((i = nextopt("vf")) != '\0') {
12630 if (i == 'f')
12631 flg_func = 1;
12632 else
12633 flg_var = 1;
12634 }
12635 if (flg_func == 0 && flg_var == 0)
12636 flg_var = 1;
12637
12638 for (ap = argptr; *ap ; ap++) {
12639 if (flg_func)
12640 unsetfunc(*ap);
12641 if (flg_var)
12642 ret |= unsetvar(*ap);
12643 }
12644 return ret;
12645}
12646
12647
12648/*
12649 * Unset the specified variable.
12650 */
12651
12652static int
Eric Andersen62483552001-07-10 06:09:16 +000012653unsetvar(const char *s)
12654{
Eric Andersencb57d552001-06-28 07:25:16 +000012655 struct var **vpp;
12656 struct var *vp;
12657
12658 vpp = findvar(hashvar(s), s);
12659 vp = *vpp;
12660 if (vp) {
12661 if (vp->flags & VREADONLY)
12662 return (1);
12663 INTOFF;
12664 if (*(strchr(vp->text, '=') + 1) != '\0')
12665 setvar(s, nullstr, 0);
12666 vp->flags &= ~VEXPORT;
12667 vp->flags |= VUNSET;
12668 if ((vp->flags & VSTRFIXED) == 0) {
12669 if ((vp->flags & VTEXTFIXED) == 0)
12670 ckfree(vp->text);
12671 *vpp = vp->next;
12672 ckfree(vp);
12673 }
12674 INTON;
12675 return (0);
12676 }
12677
12678 return (0);
12679}
12680
12681
12682
12683/*
12684 * Find the appropriate entry in the hash table from the name.
12685 */
12686
12687static struct var **
Eric Andersen62483552001-07-10 06:09:16 +000012688hashvar(const char *p)
12689{
Eric Andersencb57d552001-06-28 07:25:16 +000012690 unsigned int hashval;
12691
12692 hashval = ((unsigned char) *p) << 4;
12693 while (*p && *p != '=')
12694 hashval += (unsigned char) *p++;
12695 return &vartab[hashval % VTABSIZE];
12696}
12697
12698
12699
12700/*
12701 * Returns true if the two strings specify the same varable. The first
12702 * variable name is terminated by '='; the second may be terminated by
12703 * either '=' or '\0'.
12704 */
12705
12706static int
Eric Andersen62483552001-07-10 06:09:16 +000012707varequal(const char *p, const char *q)
12708{
Eric Andersencb57d552001-06-28 07:25:16 +000012709 while (*p == *q++) {
12710 if (*p++ == '=')
12711 return 1;
12712 }
12713 if (*p == '=' && *(q - 1) == '\0')
12714 return 1;
12715 return 0;
12716}
12717
12718static void
12719showvars(const char *myprefix, int mask, int xor)
12720{
12721 struct var **vpp;
12722 struct var *vp;
12723 const char *sep = myprefix == nullstr ? myprefix : spcstr;
12724
12725 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12726 for (vp = *vpp ; vp ; vp = vp->next) {
12727 if ((vp->flags & mask) ^ xor) {
12728 char *p;
12729 int len;
12730
12731 p = strchr(vp->text, '=') + 1;
12732 len = p - vp->text;
12733 p = single_quote(p);
12734
Eric Andersen62483552001-07-10 06:09:16 +000012735 printf("%s%s%.*s%s\n", myprefix, sep, len,
12736 vp->text, p);
Eric Andersencb57d552001-06-28 07:25:16 +000012737 stunalloc(p);
12738 }
12739 }
12740 }
12741}
12742
12743static struct var **
12744findvar(struct var **vpp, const char *name)
12745{
12746 for (; *vpp; vpp = &(*vpp)->next) {
12747 if (varequal((*vpp)->text, name)) {
12748 break;
12749 }
12750 }
12751 return vpp;
12752}
12753
12754/*
12755 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
12756 * This file contains code for the times builtin.
Eric Andersen74400cc2001-10-18 04:11:39 +000012757 * $Id: ash.c,v 1.26 2001/10/18 04:11:38 andersen Exp $
Eric Andersencb57d552001-06-28 07:25:16 +000012758 */
12759static int timescmd (int argc, char **argv)
12760{
12761 struct tms buf;
12762 long int clk_tck = sysconf(_SC_CLK_TCK);
12763
12764 times(&buf);
12765 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
12766 (int) (buf.tms_utime / clk_tck / 60),
12767 ((double) buf.tms_utime) / clk_tck,
12768 (int) (buf.tms_stime / clk_tck / 60),
12769 ((double) buf.tms_stime) / clk_tck,
12770 (int) (buf.tms_cutime / clk_tck / 60),
12771 ((double) buf.tms_cutime) / clk_tck,
12772 (int) (buf.tms_cstime / clk_tck / 60),
12773 ((double) buf.tms_cstime) / clk_tck);
12774 return 0;
12775}
12776
Eric Andersen74bcd162001-07-30 21:41:37 +000012777#ifdef ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012778/* The let builtin. */
12779int letcmd(int argc, char **argv)
Eric Andersen74bcd162001-07-30 21:41:37 +000012780{
Eric Andersen34506362001-08-02 05:02:46 +000012781 int errcode;
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012782 long result=0;
12783 if (argc == 2) {
12784 char *tmp, *expression, p[13];
12785 expression = strchr(argv[1], '=');
12786 if (!expression) {
Eric Andersen34506362001-08-02 05:02:46 +000012787 /* Cannot use 'error()' here, or the return code
12788 * will be incorrect */
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012789 out2fmt("sh: let: syntax error: \"%s\"\n", argv[1]);
12790 return 0;
Eric Andersen74bcd162001-07-30 21:41:37 +000012791 }
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012792 *expression = '\0';
12793 tmp = ++expression;
Eric Andersen34506362001-08-02 05:02:46 +000012794 result = arith(tmp, &errcode);
12795 if (errcode < 0) {
12796 /* Cannot use 'error()' here, or the return code
12797 * will be incorrect */
12798 out2fmt("sh: let: ");
12799 if(errcode == -2)
12800 out2fmt("divide by zero");
12801 else
12802 out2fmt("syntax error: \"%s=%s\"\n", argv[1], expression);
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012803 return 0;
12804 }
12805 snprintf(p, 12, "%ld", result);
12806 setvar(argv[1], savestr(p), 0);
12807 } else if (argc >= 3)
12808 synerror("invalid operand");
12809 return !result;
Eric Andersen74bcd162001-07-30 21:41:37 +000012810}
12811#endif
12812
12813
12814
Eric Andersendf82f612001-06-28 07:46:40 +000012815/*-
12816 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000012817 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000012818 *
12819 * This code is derived from software contributed to Berkeley by
12820 * Kenneth Almquist.
12821 *
12822 * Redistribution and use in source and binary forms, with or without
12823 * modification, are permitted provided that the following conditions
12824 * are met:
12825 * 1. Redistributions of source code must retain the above copyright
12826 * notice, this list of conditions and the following disclaimer.
12827 * 2. Redistributions in binary form must reproduce the above copyright
12828 * notice, this list of conditions and the following disclaimer in the
12829 * documentation and/or other materials provided with the distribution.
12830 *
Eric Andersen2870d962001-07-02 17:27:21 +000012831 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
12832 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000012833 *
12834 * 4. Neither the name of the University nor the names of its contributors
12835 * may be used to endorse or promote products derived from this software
12836 * without specific prior written permission.
12837 *
12838 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
12839 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
12840 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
12841 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
12842 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
12843 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
12844 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
12845 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
12846 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
12847 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
12848 * SUCH DAMAGE.
12849 */