blob: bec37cfcc6f6b3fadc0b3b3bccc7933382380335 [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
Eric Andersen2870d962001-07-02 17:27:21 +000036/* Enable this to compile in extra debugging noise. When debugging is
37 * on, debugging info will be written to $HOME/trace and a quit signal
38 * will generate a core dump. */
39#undef DEBUG
40
Eric Andersen2870d962001-07-02 17:27:21 +000041/* These are here to work with glibc -- Don't change these... */
Eric Andersendf82f612001-06-28 07:46:40 +000042#undef FNMATCH_BROKEN
43#undef GLOB_BROKEN
Eric Andersen5bb16772001-09-06 18:00:41 +000044#define IFS_BROKEN
Eric Andersencb57d552001-06-28 07:25:16 +000045
46#include <assert.h>
Manuel Novoa III 16815d42001-08-10 19:36:07 +000047#include <stddef.h>
Eric Andersencb57d552001-06-28 07:25:16 +000048#include <ctype.h>
49#include <dirent.h>
50#include <errno.h>
51#include <fcntl.h>
52#include <limits.h>
53#include <paths.h>
Eric Andersencb57d552001-06-28 07:25:16 +000054#include <setjmp.h>
55#include <signal.h>
56#include <stdarg.h>
Eric Andersencb57d552001-06-28 07:25:16 +000057#include <stdio.h>
58#include <stdlib.h>
59#include <string.h>
60#include <sysexits.h>
61#include <unistd.h>
62#include <sys/stat.h>
63#include <sys/cdefs.h>
64#include <sys/ioctl.h>
65#include <sys/param.h>
66#include <sys/resource.h>
67#include <sys/time.h>
68#include <sys/times.h>
69#include <sys/types.h>
70#include <sys/wait.h>
Robert Grieblea1a63a2002-06-04 20:10:23 +000071#include "busybox.h"
Eric Andersen887ca792002-07-03 23:19:26 +000072#include "pwd_.h"
Eric Andersencb57d552001-06-28 07:25:16 +000073
74
75#if !defined(FNMATCH_BROKEN)
76#include <fnmatch.h>
77#endif
78#if !defined(GLOB_BROKEN)
79#include <glob.h>
80#endif
81
Eric Andersend35c5df2002-01-09 15:37:36 +000082#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +000083#include <termios.h>
Eric Andersencb57d552001-06-28 07:25:16 +000084#endif
85
Eric Andersen2870d962001-07-02 17:27:21 +000086#include "cmdedit.h"
87
Eric Andersenaa1d6cc2002-09-30 20:12:32 +000088#if defined(__uClinux__)
89#error "Do not even bother, ash will not run on uClinux"
90#endif
91
Eric Andersen2870d962001-07-02 17:27:21 +000092/*
93 * This file was generated by the mksyntax program.
94 */
95
96/* Syntax classes */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000097#define CWORD 0 /* character is nothing special */
98#define CNL 1 /* newline character */
99#define CBACK 2 /* a backslash character */
100#define CSQUOTE 3 /* single quote */
101#define CDQUOTE 4 /* double quote */
102#define CENDQUOTE 5 /* a terminating quote */
103#define CBQUOTE 6 /* backwards single quote */
104#define CVAR 7 /* a dollar sign */
105#define CENDVAR 8 /* a '}' character */
106#define CLP 9 /* a left paren in arithmetic */
107#define CRP 10 /* a right paren in arithmetic */
108#define CENDFILE 11 /* end of file */
109#define CCTL 12 /* like CWORD, except it must be escaped */
110#define CSPCL 13 /* these terminate a word */
111#define CIGN 14 /* character should be ignored */
Eric Andersen2870d962001-07-02 17:27:21 +0000112
Eric Andersen2870d962001-07-02 17:27:21 +0000113#define SYNBASE 130
114#define PEOF -130
115
116#define PEOA -129
117
118#define TEOF 0
119#define TNL 1
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000120#define TREDIR 2
121#define TWORD 3
122#define TASSIGN 4
123#define TSEMI 5
124#define TBACKGND 6
125#define TAND 7
126#define TOR 8
127#define TPIPE 9
128#define TLP 10
129#define TRP 11
130#define TENDCASE 12
131#define TENDBQUOTE 13
Eric Andersen2870d962001-07-02 17:27:21 +0000132#define TNOT 14
133#define TCASE 15
134#define TDO 16
135#define TDONE 17
136#define TELIF 18
137#define TELSE 19
138#define TESAC 20
139#define TFI 21
140#define TFOR 22
141#define TIF 23
142#define TIN 24
143#define TTHEN 25
144#define TUNTIL 26
145#define TWHILE 27
146#define TBEGIN 28
147#define TEND 29
148
149
Eric Andersen2870d962001-07-02 17:27:21 +0000150
151/* control characters in argument strings */
152#define CTLESC '\201'
153#define CTLVAR '\202'
154#define CTLENDVAR '\203'
155#define CTLBACKQ '\204'
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000156#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
Eric Andersen2870d962001-07-02 17:27:21 +0000157/* CTLBACKQ | CTLQUOTE == '\205' */
158#define CTLARI '\206'
159#define CTLENDARI '\207'
160#define CTLQUOTEMARK '\210'
161
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000162
Eric Andersen62483552001-07-10 06:09:16 +0000163#define is_digit(c) ((c)>='0' && (c)<='9')
Eric Andersen2870d962001-07-02 17:27:21 +0000164#define is_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalpha((unsigned char) (c))))
165#define is_in_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalnum((unsigned char) (c))))
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000166
167/*
168 * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
169 * (assuming ascii char codes, as the original implementation did)
170 */
171#define is_special(c) \
172 ( (((unsigned int)c) - 33 < 32) \
173 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
174
Eric Andersen2870d962001-07-02 17:27:21 +0000175#define digit_val(c) ((c) - '0')
Eric Andersencb57d552001-06-28 07:25:16 +0000176
177
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000178#define S_DFL 1 /* default signal handling (SIG_DFL) */
179#define S_CATCH 2 /* signal is caught */
180#define S_IGN 3 /* signal is ignored (SIG_IGN) */
181#define S_HARD_IGN 4 /* signal is ignored permenantly */
182#define S_RESET 5 /* temporary - to reset a hard ignored sig */
Eric Andersencb57d552001-06-28 07:25:16 +0000183
184
Eric Andersen2870d962001-07-02 17:27:21 +0000185/* variable substitution byte (follows CTLVAR) */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000186#define VSTYPE 0x0f /* type of variable substitution */
187#define VSNUL 0x10 /* colon--treat the empty string as unset */
188#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
Eric Andersencb57d552001-06-28 07:25:16 +0000189
Eric Andersen2870d962001-07-02 17:27:21 +0000190/* values of VSTYPE field */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000191#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
192#define VSMINUS 0x2 /* ${var-text} */
193#define VSPLUS 0x3 /* ${var+text} */
194#define VSQUESTION 0x4 /* ${var?message} */
195#define VSASSIGN 0x5 /* ${var=text} */
196#define VSTRIMLEFT 0x6 /* ${var#pattern} */
197#define VSTRIMLEFTMAX 0x7 /* ${var##pattern} */
198#define VSTRIMRIGHT 0x8 /* ${var%pattern} */
199#define VSTRIMRIGHTMAX 0x9 /* ${var%%pattern} */
200#define VSLENGTH 0xa /* ${#var} */
Eric Andersencb57d552001-06-28 07:25:16 +0000201
Eric Andersen2870d962001-07-02 17:27:21 +0000202/* flags passed to redirect */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000203#define REDIR_PUSH 01 /* save previous values of file descriptors */
204#define REDIR_BACKQ 02 /* save the command output to pipe */
Eric Andersencb57d552001-06-28 07:25:16 +0000205
Eric Andersen2870d962001-07-02 17:27:21 +0000206/*
207 * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
208 * so we use _setjmp instead.
209 */
210
Eric Andersen62483552001-07-10 06:09:16 +0000211#if defined(BSD)
Eric Andersen2870d962001-07-02 17:27:21 +0000212#define setjmp(jmploc) _setjmp(jmploc)
213#define longjmp(jmploc, val) _longjmp(jmploc, val)
214#endif
215
216/*
217 * Most machines require the value returned from malloc to be aligned
218 * in some way. The following macro will get this right on many machines.
219 */
220
221#ifndef ALIGN
222union align {
223 int i;
224 char *cp;
225};
226
227#define ALIGN(nbytes) (((nbytes) + sizeof(union align) - 1) & ~(sizeof(union align) - 1))
228#endif
229
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000230#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +0000231#include <locale.h>
232static void change_lc_all(const char *value);
233static void change_lc_ctype(const char *value);
234#endif
235
236/*
237 * These macros allow the user to suspend the handling of interrupt signals
238 * over a period of time. This is similar to SIGHOLD to or sigblock, but
239 * much more efficient and portable. (But hacking the kernel is so much
240 * more fun than worrying about efficiency and portability. :-))
241 */
242
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000243static void onint(void);
Eric Andersen2870d962001-07-02 17:27:21 +0000244static volatile int suppressint;
245static volatile int intpending;
246
247#define INTOFF suppressint++
Eric Andersend35c5df2002-01-09 15:37:36 +0000248#ifndef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Eric Andersen2870d962001-07-02 17:27:21 +0000249#define INTON { if (--suppressint == 0 && intpending) onint(); }
Eric Andersen3102ac42001-07-06 04:26:23 +0000250#define FORCEINTON {suppressint = 0; if (intpending) onint();}
Eric Andersen2870d962001-07-02 17:27:21 +0000251#else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000252static void __inton(void);
253static void forceinton(void);
254
Eric Andersen2870d962001-07-02 17:27:21 +0000255#define INTON __inton()
Eric Andersen3102ac42001-07-06 04:26:23 +0000256#define FORCEINTON forceinton()
Eric Andersen2870d962001-07-02 17:27:21 +0000257#endif
Eric Andersen3102ac42001-07-06 04:26:23 +0000258
Eric Andersen2870d962001-07-02 17:27:21 +0000259#define CLEAR_PENDING_INT intpending = 0
260#define int_pending() intpending
261
262
263typedef void *pointer;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000264
Eric Andersen2870d962001-07-02 17:27:21 +0000265#ifndef NULL
266#define NULL (void *)0
267#endif
268
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000269static pointer stalloc(int);
270static void stunalloc(pointer);
271static void ungrabstackstr(char *, char *);
272static char *growstackstr(void);
273static char *makestrspace(size_t newlen);
Eric Andersen2870d962001-07-02 17:27:21 +0000274
275/*
276 * Parse trees for commands are allocated in lifo order, so we use a stack
277 * to make this more efficient, and also to avoid all sorts of exception
278 * handling code to handle interrupts in the middle of a parse.
279 *
280 * The size 504 was chosen because the Ultrix malloc handles that size
281 * well.
282 */
283
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000284#define MINSIZE 504 /* minimum size of a block */
Eric Andersen2870d962001-07-02 17:27:21 +0000285
286
287struct stack_block {
288 struct stack_block *prev;
289 char space[MINSIZE];
290};
291
292static struct stack_block stackbase;
293static struct stack_block *stackp = &stackbase;
294static struct stackmark *markp;
295static char *stacknxt = stackbase.space;
296static int stacknleft = MINSIZE;
297
298
299#define equal(s1, s2) (strcmp(s1, s2) == 0)
300
301#define stackblock() stacknxt
302#define stackblocksize() stacknleft
303#define STARTSTACKSTR(p) p = stackblock(), sstrnleft = stackblocksize()
Eric Andersen3102ac42001-07-06 04:26:23 +0000304
Eric Andersen2870d962001-07-02 17:27:21 +0000305#define STPUTC(c, p) (--sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(), *p++ = (c)))
306#define CHECKSTRSPACE(n, p) { if (sstrnleft < n) p = makestrspace(n); }
Eric Andersen2870d962001-07-02 17:27:21 +0000307#define STACKSTRNUL(p) (sstrnleft == 0? (p = growstackstr(), *p = '\0') : (*p = '\0'))
Eric Andersen3102ac42001-07-06 04:26:23 +0000308
309
310#define USTPUTC(c, p) (--sstrnleft, *p++ = (c))
Eric Andersen2870d962001-07-02 17:27:21 +0000311#define STUNPUTC(p) (++sstrnleft, --p)
312#define STTOPC(p) p[-1]
313#define STADJUST(amount, p) (p += (amount), sstrnleft -= (amount))
314#define grabstackstr(p) stalloc(stackblocksize() - sstrnleft)
315
Eric Andersen2870d962001-07-02 17:27:21 +0000316
Eric Andersen2870d962001-07-02 17:27:21 +0000317#ifdef DEBUG
318#define TRACE(param) trace param
Eric Andersen69a20f02001-10-31 10:40:37 +0000319typedef union node unode;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000320static void trace(const char *, ...);
321static void trargs(char **);
322static void showtree(unode *);
323static void trputc(int);
324static void trputs(const char *);
325static void opentrace(void);
Eric Andersen2870d962001-07-02 17:27:21 +0000326#else
327#define TRACE(param)
328#endif
329
330#define NSEMI 0
331#define NCMD 1
332#define NPIPE 2
333#define NREDIR 3
334#define NBACKGND 4
335#define NSUBSHELL 5
336#define NAND 6
337#define NOR 7
338#define NIF 8
339#define NWHILE 9
340#define NUNTIL 10
341#define NFOR 11
342#define NCASE 12
343#define NCLIST 13
344#define NDEFUN 14
345#define NARG 15
346#define NTO 16
347#define NFROM 17
348#define NFROMTO 18
349#define NAPPEND 19
350#define NTOOV 20
351#define NTOFD 21
352#define NFROMFD 22
353#define NHERE 23
354#define NXHERE 24
355#define NNOT 25
356
357/*
358 * expandarg() flags
359 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000360#define EXP_FULL 0x1 /* perform word splitting & file globbing */
361#define EXP_TILDE 0x2 /* do normal tilde expansion */
362#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
363#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
364#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
365#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
Eric Andersen2870d962001-07-02 17:27:21 +0000366
367
368#define NOPTS 16
369
370static char optet_vals[NOPTS];
371
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000372static const char *const optlist[NOPTS] = {
Eric Andersen2870d962001-07-02 17:27:21 +0000373 "e" "errexit",
374 "f" "noglob",
375 "I" "ignoreeof",
376 "i" "interactive",
377 "m" "monitor",
378 "n" "noexec",
379 "s" "stdin",
380 "x" "xtrace",
381 "v" "verbose",
382 "V" "vi",
383 "E" "emacs",
384 "C" "noclobber",
385 "a" "allexport",
386 "b" "notify",
387 "u" "nounset",
388 "q" "quietprofile"
389};
390
391#define optent_name(optent) (optent+1)
392#define optent_letter(optent) optent[0]
393#define optent_val(optent) optet_vals[optent]
394
395#define eflag optent_val(0)
396#define fflag optent_val(1)
397#define Iflag optent_val(2)
398#define iflag optent_val(3)
399#define mflag optent_val(4)
400#define nflag optent_val(5)
401#define sflag optent_val(6)
402#define xflag optent_val(7)
403#define vflag optent_val(8)
404#define Vflag optent_val(9)
405#define Eflag optent_val(10)
406#define Cflag optent_val(11)
407#define aflag optent_val(12)
408#define bflag optent_val(13)
409#define uflag optent_val(14)
410#define qflag optent_val(15)
411
412
413/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
414#define FORK_FG 0
415#define FORK_BG 1
416#define FORK_NOJOB 2
417
418
419struct nbinary {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000420 int type;
421 union node *ch1;
422 union node *ch2;
Eric Andersen2870d962001-07-02 17:27:21 +0000423};
424
425
426struct ncmd {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000427 int type;
428 int backgnd;
429 union node *assign;
430 union node *args;
431 union node *redirect;
Eric Andersen2870d962001-07-02 17:27:21 +0000432};
433
434
435struct npipe {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000436 int type;
437 int backgnd;
438 struct nodelist *cmdlist;
Eric Andersen2870d962001-07-02 17:27:21 +0000439};
440
441
442struct nredir {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000443 int type;
444 union node *n;
445 union node *redirect;
Eric Andersen2870d962001-07-02 17:27:21 +0000446};
447
448
449struct nif {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000450 int type;
451 union node *test;
452 union node *ifpart;
453 union node *elsepart;
Eric Andersen2870d962001-07-02 17:27:21 +0000454};
455
456
457struct nfor {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000458 int type;
459 union node *args;
460 union node *body;
461 char *var;
Eric Andersen2870d962001-07-02 17:27:21 +0000462};
463
464
465struct ncase {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000466 int type;
467 union node *expr;
468 union node *cases;
Eric Andersen2870d962001-07-02 17:27:21 +0000469};
470
471
472struct nclist {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000473 int type;
474 union node *next;
475 union node *pattern;
476 union node *body;
Eric Andersen2870d962001-07-02 17:27:21 +0000477};
478
479
480struct narg {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000481 int type;
482 union node *next;
483 char *text;
484 struct nodelist *backquote;
Eric Andersen2870d962001-07-02 17:27:21 +0000485};
486
487
488struct nfile {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000489 int type;
490 union node *next;
491 int fd;
492 union node *fname;
493 char *expfname;
Eric Andersen2870d962001-07-02 17:27:21 +0000494};
495
496
497struct ndup {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000498 int type;
499 union node *next;
500 int fd;
501 int dupfd;
502 union node *vname;
Eric Andersen2870d962001-07-02 17:27:21 +0000503};
504
505
506struct nhere {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000507 int type;
508 union node *next;
509 int fd;
510 union node *doc;
Eric Andersen2870d962001-07-02 17:27:21 +0000511};
512
513
514struct nnot {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000515 int type;
516 union node *com;
Eric Andersen2870d962001-07-02 17:27:21 +0000517};
518
519
520union node {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000521 int type;
522 struct nbinary nbinary;
523 struct ncmd ncmd;
524 struct npipe npipe;
525 struct nredir nredir;
526 struct nif nif;
527 struct nfor nfor;
528 struct ncase ncase;
529 struct nclist nclist;
530 struct narg narg;
531 struct nfile nfile;
532 struct ndup ndup;
533 struct nhere nhere;
534 struct nnot nnot;
Eric Andersen2870d962001-07-02 17:27:21 +0000535};
536
537
538struct nodelist {
539 struct nodelist *next;
540 union node *n;
541};
542
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000543struct backcmd { /* result of evalbackcmd */
544 int fd; /* file descriptor to read from */
545 char *buf; /* buffer */
546 int nleft; /* number of chars in buffer */
547 struct job *jp; /* job structure for command */
Eric Andersen2870d962001-07-02 17:27:21 +0000548};
549
550struct cmdentry {
551 int cmdtype;
552 union param {
553 int index;
554 union node *func;
555 const struct builtincmd *cmd;
556 } u;
557};
558
559struct strlist {
560 struct strlist *next;
561 char *text;
562};
563
564
565struct arglist {
566 struct strlist *list;
567 struct strlist **lastp;
568};
569
570struct strpush {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000571 struct strpush *prev; /* preceding string on stack */
Eric Andersen2870d962001-07-02 17:27:21 +0000572 char *prevstring;
573 int prevnleft;
Eric Andersend35c5df2002-01-09 15:37:36 +0000574#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000575 struct alias *ap; /* if push was associated with an alias */
Eric Andersen2870d962001-07-02 17:27:21 +0000576#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000577 char *string; /* remember the string since it may change */
Eric Andersen2870d962001-07-02 17:27:21 +0000578};
579
580struct parsefile {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000581 struct parsefile *prev; /* preceding file on stack */
582 int linno; /* current line */
583 int fd; /* file descriptor (or -1 if string) */
584 int nleft; /* number of chars left in this line */
585 int lleft; /* number of chars left in this buffer */
586 char *nextc; /* next char in buffer */
587 char *buf; /* input buffer */
588 struct strpush *strpush; /* for pushing strings at this level */
589 struct strpush basestrpush; /* so pushing one is fast */
Eric Andersen2870d962001-07-02 17:27:21 +0000590};
591
592struct stackmark {
593 struct stack_block *stackp;
594 char *stacknxt;
595 int stacknleft;
596 struct stackmark *marknext;
597};
598
599struct shparam {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000600 int nparam; /* # of positional parameters (without $0) */
601 unsigned char malloc; /* if parameter list dynamically allocated */
602 char **p; /* parameter list */
603 int optind; /* next parameter to be processed by getopts */
604 int optoff; /* used by getopts */
Eric Andersen2870d962001-07-02 17:27:21 +0000605};
606
Eric Andersen62483552001-07-10 06:09:16 +0000607/*
608 * When commands are first encountered, they are entered in a hash table.
609 * This ensures that a full path search will not have to be done for them
610 * on each invocation.
611 *
612 * We should investigate converting to a linear search, even though that
613 * would make the command name "hash" a misnomer.
614 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000615#define CMDTABLESIZE 31 /* should be prime */
616#define ARB 1 /* actual size determined at run time */
Eric Andersen62483552001-07-10 06:09:16 +0000617
618
619
620struct tblentry {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000621 struct tblentry *next; /* next entry in hash chain */
622 union param param; /* definition of builtin function */
623 short cmdtype; /* index identifying command */
624 char rehash; /* if set, cd done since entry created */
625 char cmdname[ARB]; /* name of command */
Eric Andersen62483552001-07-10 06:09:16 +0000626};
627
628
629static struct tblentry *cmdtable[CMDTABLESIZE];
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000630static int builtinloc = -1; /* index in path of %builtin, or -1 */
631static int exerrno = 0; /* Last exec error */
Eric Andersen62483552001-07-10 06:09:16 +0000632
633
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000634static void tryexec(char *, char **, char **);
635static void printentry(struct tblentry *, int);
636static void clearcmdentry(int);
637static struct tblentry *cmdlookup(const char *, int);
638static void delete_cmd_entry(void);
639static int path_change(const char *, int *);
Eric Andersen62483552001-07-10 06:09:16 +0000640
641
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000642static void flushall(void);
643static void out2fmt(const char *, ...)
644 __attribute__ ((__format__(__printf__, 1, 2)));
645static int xwrite(int, const char *, int);
Eric Andersen2870d962001-07-02 17:27:21 +0000646
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000647static inline void outstr(const char *p, FILE * file)
648{
649 fputs(p, file);
650}
651static void out1str(const char *p)
652{
653 outstr(p, stdout);
654}
655static void out2str(const char *p)
656{
657 outstr(p, stderr);
658}
Eric Andersen2870d962001-07-02 17:27:21 +0000659
Eric Andersend35c5df2002-01-09 15:37:36 +0000660#ifndef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Eric Andersen3102ac42001-07-06 04:26:23 +0000661#define out2c(c) putc((c), stderr)
Eric Andersen62483552001-07-10 06:09:16 +0000662#else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000663static void out2c(int c)
664{
665 putc(c, stderr);
666}
Eric Andersen62483552001-07-10 06:09:16 +0000667#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000668
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000669
Eric Andersend35c5df2002-01-09 15:37:36 +0000670#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000671#define USE_SIT_FUNCTION
672#endif
673
674/* number syntax index */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000675#define BASESYNTAX 0 /* not in quotes */
676#define DQSYNTAX 1 /* in double quotes */
677#define SQSYNTAX 2 /* in single quotes */
678#define ARISYNTAX 3 /* in arithmetic */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000679
680static const char S_I_T[][4] = {
Glenn L McGrath50812ff2002-08-23 13:14:48 +0000681 {CSPCL, CIGN, CIGN, CIGN}, /* 0, PEOA */
682 {CSPCL, CWORD, CWORD, CWORD}, /* 1, ' ' */
683 {CNL, CNL, CNL, CNL}, /* 2, \n */
684 {CWORD, CCTL, CCTL, CWORD}, /* 3, !*-/:=?[]~ */
685 {CDQUOTE, CENDQUOTE, CWORD, CDQUOTE}, /* 4, '"' */
686 {CVAR, CVAR, CWORD, CVAR}, /* 5, $ */
687 {CSQUOTE, CWORD, CENDQUOTE, CSQUOTE}, /* 6, "'" */
688 {CSPCL, CWORD, CWORD, CLP}, /* 7, ( */
689 {CSPCL, CWORD, CWORD, CRP}, /* 8, ) */
690 {CBACK, CBACK, CCTL, CBACK}, /* 9, \ */
691 {CBQUOTE, CBQUOTE, CWORD, CBQUOTE}, /* 10, ` */
692 {CENDVAR, CENDVAR, CWORD, CENDVAR}, /* 11, } */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000693#ifndef USE_SIT_FUNCTION
Glenn L McGrath50812ff2002-08-23 13:14:48 +0000694 {CENDFILE, CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
695 {CWORD, CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
696 {CCTL, CCTL, CCTL, CCTL} /* 14, CTLESC ... */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000697#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000698};
699
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000700#ifdef USE_SIT_FUNCTION
701
702#define U_C(c) ((unsigned char)(c))
703
704static int SIT(int c, int syntax)
705{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000706 static const char spec_symbls[] = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
707 static const char syntax_index_table[] = {
708 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
709 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
710 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
711 11, 3
712 }; /* "}~" */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000713 const char *s;
714 int indx;
715
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000716 if (c == PEOF) /* 2^8+2 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000717 return CENDFILE;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000718 if (c == PEOA) /* 2^8+1 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000719 indx = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000720 else if (U_C(c) >= U_C(CTLESC) && U_C(c) <= U_C(CTLQUOTEMARK))
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000721 return CCTL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000722 else {
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000723 s = strchr(spec_symbls, c);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000724 if (s == 0)
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000725 return CWORD;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000726 indx = syntax_index_table[(s - spec_symbls)];
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000727 }
728 return S_I_T[indx][syntax];
729}
730
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000731#else /* USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000732
733#define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
734
735#define CSPCL_CIGN_CIGN_CIGN 0
736#define CSPCL_CWORD_CWORD_CWORD 1
737#define CNL_CNL_CNL_CNL 2
738#define CWORD_CCTL_CCTL_CWORD 3
739#define CDQUOTE_CENDQUOTE_CWORD_CDQUOTE 4
740#define CVAR_CVAR_CWORD_CVAR 5
741#define CSQUOTE_CWORD_CENDQUOTE_CSQUOTE 6
742#define CSPCL_CWORD_CWORD_CLP 7
743#define CSPCL_CWORD_CWORD_CRP 8
744#define CBACK_CBACK_CCTL_CBACK 9
745#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
746#define CENDVAR_CENDVAR_CWORD_CENDVAR 11
747#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
748#define CWORD_CWORD_CWORD_CWORD 13
749#define CCTL_CCTL_CCTL_CCTL 14
750
751static const char syntax_index_table[258] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000752 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
753 /* 0 -130 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
754 /* 1 -129 PEOA */ CSPCL_CIGN_CIGN_CIGN,
755 /* 2 -128 0xff */ CWORD_CWORD_CWORD_CWORD,
Glenn L McGrath50812ff2002-08-23 13:14:48 +0000756 /* 3 -127 */ CCTL_CCTL_CCTL_CCTL,
757 /* CTLQUOTEMARK */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000758 /* 4 -126 */ CCTL_CCTL_CCTL_CCTL,
759 /* 5 -125 */ CCTL_CCTL_CCTL_CCTL,
760 /* 6 -124 */ CCTL_CCTL_CCTL_CCTL,
761 /* 7 -123 */ CCTL_CCTL_CCTL_CCTL,
762 /* 8 -122 */ CCTL_CCTL_CCTL_CCTL,
763 /* 9 -121 */ CCTL_CCTL_CCTL_CCTL,
Glenn L McGrath50812ff2002-08-23 13:14:48 +0000764 /* 10 -120 */ CCTL_CCTL_CCTL_CCTL,
765 /* CTLESC */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000766 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
767 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
768 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
769 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
770 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
771 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
772 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
773 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
774 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
775 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
776 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
777 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
778 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
779 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
780 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
781 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
782 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
783 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
784 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
785 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
786 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
787 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
788 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
789 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
790 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
791 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
792 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
793 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
794 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
795 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
796 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
797 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
798 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
799 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
800 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
801 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
802 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
803 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
804 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
805 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
806 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
807 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
808 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
809 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
810 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
811 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
812 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
813 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
814 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
815 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
816 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
817 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
818 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
819 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
820 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
821 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
822 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
823 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
824 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
825 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
826 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
827 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
828 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
829 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
830 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
831 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
832 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
833 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
834 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
835 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
836 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
837 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
838 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
839 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
840 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
841 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
842 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
843 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
844 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
845 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
846 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
847 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
848 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
849 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
850 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
851 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
852 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
853 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
854 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
855 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
856 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
857 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
858 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
859 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
860 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
861 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
862 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
863 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
864 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
865 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
866 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
867 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
868 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
869 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
870 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
871 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
872 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
873 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
874 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
875 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
876 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
877 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
878 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
879 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
880 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
881 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
882 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
883 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
884 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
885 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
886 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
887 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
888 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
889 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
890 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
891 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
892 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
893 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
894 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
895 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
896 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
897 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
898 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
899 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
900 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
901 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
902 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
903 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
904 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
905 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
906 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
907 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
908 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
909 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
910 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
911 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
912 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
913 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
914 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
915 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
916 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
917 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
918 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
919 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CDQUOTE,
920 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
921 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
922 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
923 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
924 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CSQUOTE,
925 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
926 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
927 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
928 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
929 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
930 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
931 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
932 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
933 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
934 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
935 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
936 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
937 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
938 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
939 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
940 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
941 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
942 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
943 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
944 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
945 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
946 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
947 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
948 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
949 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
950 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
951 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
952 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
953 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
954 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
955 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
956 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
957 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
958 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
959 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
960 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
961 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
962 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
963 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
964 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
965 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
966 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
967 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
968 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
969 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
970 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
971 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
972 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
973 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
974 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
975 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
976 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
977 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
978 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
979 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
980 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
981 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
982 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
983 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
984 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
985 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
986 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
987 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
988 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
989 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
990 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
991 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
992 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
993 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
994 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
995 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
996 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
997 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
998 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
999 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
1000 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
1001 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
1002 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
1003 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
1004 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
1005 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
1006 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
1007 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
1008 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
1009 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
1010 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
1011 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
1012 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
Eric Andersen2870d962001-07-02 17:27:21 +00001013};
1014
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001015#endif /* USE_SIT_FUNCTION */
Eric Andersen2870d962001-07-02 17:27:21 +00001016
Eric Andersen2870d962001-07-02 17:27:21 +00001017
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001018/* first char is indicating which tokens mark the end of a list */
1019static const char *const tokname_array[] = {
1020 "\1end of file",
1021 "\0newline",
1022 "\0redirection",
1023 "\0word",
1024 "\0assignment",
1025 "\0;",
1026 "\0&",
1027 "\0&&",
1028 "\0||",
1029 "\0|",
1030 "\0(",
1031 "\1)",
1032 "\1;;",
1033 "\1`",
Eric Andersen2870d962001-07-02 17:27:21 +00001034#define KWDOFFSET 14
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001035 /* the following are keywords */
1036 "\0!",
1037 "\0case",
1038 "\1do",
1039 "\1done",
1040 "\1elif",
1041 "\1else",
1042 "\1esac",
1043 "\1fi",
1044 "\0for",
1045 "\0if",
1046 "\0in",
1047 "\1then",
1048 "\0until",
1049 "\0while",
1050 "\0{",
1051 "\1}",
Eric Andersen2870d962001-07-02 17:27:21 +00001052};
1053
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001054static const char *tokname(int tok)
1055{
1056 static char buf[16];
1057
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001058 if (tok >= TSEMI)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001059 buf[0] = '"';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001060 sprintf(buf + (tok >= TSEMI), "%s%c",
1061 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001062 return buf;
1063}
Eric Andersen2870d962001-07-02 17:27:21 +00001064
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001065static int plinno = 1; /* input line number */
Eric Andersen2870d962001-07-02 17:27:21 +00001066
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001067static int parselleft; /* copy of parsefile->lleft */
Eric Andersen2870d962001-07-02 17:27:21 +00001068
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001069static struct parsefile basepf; /* top level input file */
1070static char basebuf[BUFSIZ]; /* buffer for top level input file */
1071static struct parsefile *parsefile = &basepf; /* current input file */
Eric Andersen2870d962001-07-02 17:27:21 +00001072
1073/*
1074 * NEOF is returned by parsecmd when it encounters an end of file. It
1075 * must be distinct from NULL, so we use the address of a variable that
1076 * happens to be handy.
1077 */
1078
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001079static int tokpushback; /* last token pushed back */
1080
Eric Andersen2870d962001-07-02 17:27:21 +00001081#define NEOF ((union node *)&tokpushback)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001082static int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */
Eric Andersen2870d962001-07-02 17:27:21 +00001083
1084
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001085static void error(const char *, ...) __attribute__ ((__noreturn__));
1086static void exerror(int, const char *, ...) __attribute__ ((__noreturn__));
1087static void shellexec(char **, char **, const char *, int)
1088 __attribute__ ((noreturn));
1089static void exitshell(int) __attribute__ ((noreturn));
Eric Andersen2870d962001-07-02 17:27:21 +00001090
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001091static int goodname(const char *);
1092static void ignoresig(int);
1093static void onsig(int);
1094static void dotrap(void);
1095static int decode_signal(const char *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00001096
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001097static void setparam(char **);
1098static void freeparam(volatile struct shparam *);
Eric Andersen2870d962001-07-02 17:27:21 +00001099
1100/* reasons for skipping commands (see comment on breakcmd routine) */
1101#define SKIPBREAK 1
1102#define SKIPCONT 2
1103#define SKIPFUNC 3
1104#define SKIPFILE 4
1105
1106/* values of cmdtype */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001107#define CMDUNKNOWN -1 /* no entry in table for command */
1108#define CMDNORMAL 0 /* command is an executable program */
1109#define CMDBUILTIN 1 /* command is a shell builtin */
1110#define CMDFUNCTION 2 /* command is a shell function */
Eric Andersen2870d962001-07-02 17:27:21 +00001111
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001112#define DO_ERR 1 /* find_command prints errors */
1113#define DO_ABS 2 /* find_command checks absolute paths */
1114#define DO_NOFUN 4 /* find_command ignores functions */
1115#define DO_BRUTE 8 /* find_command ignores hash table */
Eric Andersen2870d962001-07-02 17:27:21 +00001116
1117/*
1118 * Shell variables.
1119 */
1120
1121/* flags */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001122#define VEXPORT 0x01 /* variable is exported */
1123#define VREADONLY 0x02 /* variable cannot be modified */
1124#define VSTRFIXED 0x04 /* variable struct is staticly allocated */
1125#define VTEXTFIXED 0x08 /* text is staticly allocated */
1126#define VSTACK 0x10 /* text is allocated on the stack */
1127#define VUNSET 0x20 /* the variable is not set */
1128#define VNOFUNC 0x40 /* don't call the callback function */
Eric Andersen2870d962001-07-02 17:27:21 +00001129
1130
1131struct var {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001132 struct var *next; /* next entry in hash list */
1133 int flags; /* flags are defined above */
1134 char *text; /* name=value */
Eric Andersen2870d962001-07-02 17:27:21 +00001135 void (*func) (const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001136 /* function to be called when */
1137 /* the variable gets set/unset */
Eric Andersen2870d962001-07-02 17:27:21 +00001138};
1139
1140struct localvar {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001141 struct localvar *next; /* next local variable in list */
1142 struct var *vp; /* the variable that was made local */
1143 int flags; /* saved flags */
1144 char *text; /* saved text */
Eric Andersen2870d962001-07-02 17:27:21 +00001145};
1146
1147
Eric Andersen62483552001-07-10 06:09:16 +00001148#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00001149#define rmescapes(p) _rmescapes((p), 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001150static char *_rmescapes(char *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00001151#else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001152static void rmescapes(char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001153#endif
1154
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001155static int casematch(union node *, const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001156static void clearredir(void);
1157static void popstring(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001158static void readcmdfile(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001159
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001160static int number(const char *);
1161static int is_number(const char *, int *num);
1162static char *single_quote(const char *);
1163static int nextopt(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001164
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001165static void redirect(union node *, int);
1166static void popredir(void);
1167static int dup_as_newfd(int, int);
Eric Andersen2870d962001-07-02 17:27:21 +00001168
1169static void changepath(const char *newval);
1170static void getoptsreset(const char *value);
1171
1172
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001173static int parsenleft; /* copy of parsefile->nleft */
1174static char *parsenextc; /* copy of parsefile->nextc */
1175static int rootpid; /* pid of main shell */
1176static int rootshell; /* true if we aren't a child of the main shell */
Eric Andersen2870d962001-07-02 17:27:21 +00001177
1178static const char spcstr[] = " ";
1179static const char snlfmt[] = "%s\n";
1180
1181static int sstrnleft;
1182static int herefd = -1;
1183
1184static struct localvar *localvars;
1185
1186static struct var vifs;
1187static struct var vmail;
1188static struct var vmpath;
1189static struct var vpath;
1190static struct var vps1;
1191static struct var vps2;
1192static struct var voptind;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001193
Eric Andersenbdfd0d72001-10-24 05:00:29 +00001194#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00001195static struct var vlc_all;
1196static struct var vlc_ctype;
1197#endif
1198
1199struct varinit {
1200 struct var *var;
1201 int flags;
1202 const char *text;
1203 void (*func) (const char *);
1204};
1205
1206static const char defpathvar[] =
1207 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
1208#define defpath (defpathvar + 5)
1209
1210#ifdef IFS_BROKEN
1211static const char defifsvar[] = "IFS= \t\n";
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001212
Eric Andersen2870d962001-07-02 17:27:21 +00001213#define defifs (defifsvar + 4)
1214#else
1215static const char defifs[] = " \t\n";
1216#endif
1217
1218static const struct varinit varinit[] = {
1219#ifdef IFS_BROKEN
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001220 {&vifs, VSTRFIXED | VTEXTFIXED, defifsvar,
Eric Andersen2870d962001-07-02 17:27:21 +00001221#else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001222 {&vifs, VSTRFIXED | VTEXTFIXED | VUNSET, "IFS=",
Eric Andersen2870d962001-07-02 17:27:21 +00001223#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001224 NULL},
1225 {&vmail, VSTRFIXED | VTEXTFIXED | VUNSET, "MAIL=",
1226 NULL},
1227 {&vmpath, VSTRFIXED | VTEXTFIXED | VUNSET, "MAILPATH=",
1228 NULL},
1229 {&vpath, VSTRFIXED | VTEXTFIXED, defpathvar,
1230 changepath},
Tim Riker497a8852002-04-13 05:37:10 +00001231#if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001232 {&vps1, VSTRFIXED | VTEXTFIXED, "PS1=\\w \\$ ",
1233 NULL},
1234#endif /* else vps1 depends on uid */
1235 {&vps2, VSTRFIXED | VTEXTFIXED, "PS2=> ",
1236 NULL},
1237 {&voptind, VSTRFIXED | VTEXTFIXED, "OPTIND=1",
1238 getoptsreset},
Eric Andersenbdfd0d72001-10-24 05:00:29 +00001239#ifdef CONFIG_LOCALE_SUPPORT
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001240 {&vlc_all, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL=",
1241 change_lc_all},
1242 {&vlc_ctype, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE=",
1243 change_lc_ctype},
Eric Andersen2870d962001-07-02 17:27:21 +00001244#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001245 {NULL, 0, NULL,
1246 NULL}
Eric Andersen2870d962001-07-02 17:27:21 +00001247};
1248
1249#define VTABSIZE 39
1250
1251static struct var *vartab[VTABSIZE];
1252
1253/*
1254 * The following macros access the values of the above variables.
1255 * They have to skip over the name. They return the null string
1256 * for unset variables.
1257 */
1258
1259#define ifsval() (vifs.text + 4)
1260#define ifsset() ((vifs.flags & VUNSET) == 0)
1261#define mailval() (vmail.text + 5)
1262#define mpathval() (vmpath.text + 9)
1263#define pathval() (vpath.text + 5)
1264#define ps1val() (vps1.text + 4)
1265#define ps2val() (vps2.text + 4)
1266#define optindval() (voptind.text + 7)
1267
1268#define mpathset() ((vmpath.flags & VUNSET) == 0)
1269
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001270static void initvar(void);
1271static void setvar(const char *, const char *, int);
1272static void setvareq(char *, int);
1273static void listsetvar(struct strlist *);
1274static const char *lookupvar(const char *);
1275static const char *bltinlookup(const char *);
1276static char **environment(void);
1277static int showvarscmd(int, char **);
1278static void mklocal(char *);
1279static void poplocalvars(void);
1280static int unsetvar(const char *);
1281static int varequal(const char *, const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001282
1283
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001284static char *arg0; /* value of $0 */
1285static struct shparam shellparam; /* current positional parameters */
1286static char **argptr; /* argument list for builtin commands */
1287static char *optionarg; /* set by nextopt (like getopt) */
1288static char *optptr; /* used by nextopt */
1289static char *minusc; /* argument to -c option */
Eric Andersen2870d962001-07-02 17:27:21 +00001290
1291
Eric Andersend35c5df2002-01-09 15:37:36 +00001292#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00001293
1294#define ALIASINUSE 1
1295#define ALIASDEAD 2
1296
Eric Andersen3102ac42001-07-06 04:26:23 +00001297#define ATABSIZE 39
1298
Eric Andersen2870d962001-07-02 17:27:21 +00001299struct alias {
1300 struct alias *next;
1301 char *name;
1302 char *val;
1303 int flag;
1304};
1305
1306static struct alias *atab[ATABSIZE];
1307
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001308static void setalias(char *, char *);
1309static struct alias **hashalias(const char *);
1310static struct alias *freealias(struct alias *);
1311static struct alias **__lookupalias(const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00001312
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001313static void setalias(char *name, char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00001314{
1315 struct alias *ap, **app;
1316
1317 app = __lookupalias(name);
1318 ap = *app;
1319 INTOFF;
1320 if (ap) {
1321 if (!(ap->flag & ALIASINUSE)) {
Aaron Lehmann49c024a2002-08-02 06:39:47 +00001322 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00001323 }
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001324 ap->val = xstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00001325 ap->flag &= ~ALIASDEAD;
1326 } else {
1327 /* not found */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001328 ap = xmalloc(sizeof(struct alias));
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001329 ap->name = xstrdup(name);
1330 ap->val = xstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00001331 ap->flag = 0;
1332 ap->next = 0;
1333 *app = ap;
1334 }
1335 INTON;
1336}
1337
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001338static int unalias(char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00001339{
Eric Andersencb57d552001-06-28 07:25:16 +00001340 struct alias **app;
1341
1342 app = __lookupalias(name);
1343
1344 if (*app) {
1345 INTOFF;
1346 *app = freealias(*app);
1347 INTON;
1348 return (0);
1349 }
1350
1351 return (1);
1352}
1353
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001354static void rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00001355{
Eric Andersencb57d552001-06-28 07:25:16 +00001356 struct alias *ap, **app;
1357 int i;
1358
1359 INTOFF;
1360 for (i = 0; i < ATABSIZE; i++) {
1361 app = &atab[i];
1362 for (ap = *app; ap; ap = *app) {
1363 *app = freealias(*app);
1364 if (ap == *app) {
1365 app = &ap->next;
1366 }
1367 }
1368 }
1369 INTON;
1370}
1371
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001372static void printalias(const struct alias *ap)
1373{
Eric Andersen2870d962001-07-02 17:27:21 +00001374 char *p;
1375
1376 p = single_quote(ap->val);
Eric Andersen62483552001-07-10 06:09:16 +00001377 printf("alias %s=%s\n", ap->name, p);
Eric Andersen2870d962001-07-02 17:27:21 +00001378 stunalloc(p);
1379}
1380
Eric Andersencb57d552001-06-28 07:25:16 +00001381
1382/*
1383 * TODO - sort output
1384 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001385static int aliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001386{
1387 char *n, *v;
1388 int ret = 0;
1389 struct alias *ap;
1390
1391 if (argc == 1) {
1392 int i;
1393
1394 for (i = 0; i < ATABSIZE; i++)
1395 for (ap = atab[i]; ap; ap = ap->next) {
1396 printalias(ap);
1397 }
1398 return (0);
1399 }
1400 while ((n = *++argv) != NULL) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001401 if ((v = strchr(n + 1, '=')) == NULL) { /* n+1: funny ksh stuff */
Eric Andersencb57d552001-06-28 07:25:16 +00001402 if ((ap = *__lookupalias(n)) == NULL) {
Eric Andersen3102ac42001-07-06 04:26:23 +00001403 out2fmt("%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00001404 ret = 1;
1405 } else
1406 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001407 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00001408 *v++ = '\0';
1409 setalias(n, v);
1410 }
1411 }
1412
1413 return (ret);
1414}
1415
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001416static int unaliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001417{
1418 int i;
1419
1420 while ((i = nextopt("a")) != '\0') {
1421 if (i == 'a') {
1422 rmaliases();
1423 return (0);
1424 }
1425 }
1426 for (i = 0; *argptr; argptr++) {
1427 if (unalias(*argptr)) {
Eric Andersen3102ac42001-07-06 04:26:23 +00001428 out2fmt("%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00001429 i = 1;
1430 }
1431 }
1432
1433 return (i);
1434}
1435
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001436static struct alias **hashalias(const char *p)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001437{
Eric Andersencb57d552001-06-28 07:25:16 +00001438 unsigned int hashval;
1439
1440 hashval = *p << 4;
1441 while (*p)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001442 hashval += *p++;
Eric Andersencb57d552001-06-28 07:25:16 +00001443 return &atab[hashval % ATABSIZE];
1444}
1445
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001446static struct alias *freealias(struct alias *ap)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001447{
Eric Andersencb57d552001-06-28 07:25:16 +00001448 struct alias *next;
1449
1450 if (ap->flag & ALIASINUSE) {
1451 ap->flag |= ALIASDEAD;
1452 return ap;
1453 }
1454
1455 next = ap->next;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00001456 free(ap->name);
1457 free(ap->val);
1458 free(ap);
Eric Andersencb57d552001-06-28 07:25:16 +00001459 return next;
1460}
1461
Eric Andersencb57d552001-06-28 07:25:16 +00001462
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001463static struct alias **__lookupalias(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001464{
Eric Andersencb57d552001-06-28 07:25:16 +00001465 struct alias **app = hashalias(name);
1466
1467 for (; *app; app = &(*app)->next) {
1468 if (equal(name, (*app)->name)) {
1469 break;
1470 }
1471 }
1472
1473 return app;
1474}
Eric Andersen2870d962001-07-02 17:27:21 +00001475#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001476
Eric Andersend35c5df2002-01-09 15:37:36 +00001477#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersen74bcd162001-07-30 21:41:37 +00001478/* The generated file arith.c has been replaced with a custom hand
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001479 * written implementation written by Aaron Lehmann <aaronl@vitelus.com>.
1480 * This is now part of libbb, so that it can be used by all the shells
Eric Andersen74bcd162001-07-30 21:41:37 +00001481 * in busybox. */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001482static void expari(int);
Eric Andersencb57d552001-06-28 07:25:16 +00001483#endif
1484
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001485static char *trap[NSIG]; /* trap handler commands */
1486static char sigmode[NSIG - 1]; /* current value of signal */
1487static char gotsig[NSIG - 1]; /* indicates specified signal received */
1488static int pendingsigs; /* indicates some signal received */
Eric Andersen2870d962001-07-02 17:27:21 +00001489
Eric Andersencb57d552001-06-28 07:25:16 +00001490/*
1491 * This file was generated by the mkbuiltins program.
1492 */
1493
Eric Andersend35c5df2002-01-09 15:37:36 +00001494#ifdef CONFIG_ASH_JOB_CONTROL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001495static int bgcmd(int, char **);
1496static int fgcmd(int, char **);
1497static int killcmd(int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001498#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001499static int bltincmd(int, char **);
1500static int cdcmd(int, char **);
1501static int breakcmd(int, char **);
1502
Eric Andersend35c5df2002-01-09 15:37:36 +00001503#ifdef CONFIG_ASH_CMDCMD
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001504static int commandcmd(int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001505#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001506static int dotcmd(int, char **);
1507static int evalcmd(int, char **);
1508static int execcmd(int, char **);
1509static int exitcmd(int, char **);
1510static int exportcmd(int, char **);
1511static int histcmd(int, char **);
1512static int hashcmd(int, char **);
1513static int helpcmd(int, char **);
1514static int jobscmd(int, char **);
1515static int localcmd(int, char **);
1516static int pwdcmd(int, char **);
1517static int readcmd(int, char **);
1518static int returncmd(int, char **);
1519static int setcmd(int, char **);
1520static int setvarcmd(int, char **);
1521static int shiftcmd(int, char **);
1522static int trapcmd(int, char **);
1523static int umaskcmd(int, char **);
1524
Eric Andersend35c5df2002-01-09 15:37:36 +00001525#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001526static int aliascmd(int, char **);
1527static int unaliascmd(int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001528#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001529static int unsetcmd(int, char **);
1530static int waitcmd(int, char **);
1531static int ulimitcmd(int, char **);
1532static int timescmd(int, char **);
1533
Eric Andersend35c5df2002-01-09 15:37:36 +00001534#ifdef CONFIG_ASH_MATH_SUPPORT
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001535static int letcmd(int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001536#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001537static int typecmd(int, char **);
1538
Eric Andersend35c5df2002-01-09 15:37:36 +00001539#ifdef CONFIG_ASH_GETOPTS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001540static int getoptscmd(int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001541#endif
1542
Eric Andersen69a20f02001-10-31 10:40:37 +00001543#ifndef CONFIG_TRUE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001544static int true_main(int, char **);
Eric Andersen69a20f02001-10-31 10:40:37 +00001545#endif
1546#ifndef CONFIG_FALSE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001547static int false_main(int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001548#endif
1549
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001550static void setpwd(const char *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00001551
1552
1553#define BUILTIN_NOSPEC "0"
1554#define BUILTIN_SPECIAL "1"
1555#define BUILTIN_REGULAR "2"
1556#define BUILTIN_ASSIGN "4"
1557#define BUILTIN_SPEC_ASSG "5"
1558#define BUILTIN_REG_ASSG "6"
1559
1560#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1561#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1562#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
1563
1564struct builtincmd {
1565 const char *name;
1566 int (*const builtinfunc) (int, char **);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00001567 //unsigned flags;
Eric Andersen2870d962001-07-02 17:27:21 +00001568};
1569
Eric Andersencb57d552001-06-28 07:25:16 +00001570
1571/* It is CRUCIAL that this listing be kept in ascii order, otherwise
1572 * the binary search in find_builtin() will stop working. If you value
1573 * your kneecaps, you'll be sure to *make sure* that any changes made
1574 * to this array result in the listing remaining in ascii order. You
1575 * have been warned.
1576 */
1577static const struct builtincmd builtincmds[] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001578 {BUILTIN_SPECIAL ".", dotcmd}, /* first, see declare DOTCMD */
1579 {BUILTIN_SPECIAL ":", true_main},
Eric Andersend35c5df2002-01-09 15:37:36 +00001580#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001581 {BUILTIN_REG_ASSG "alias", aliascmd},
Eric Andersencb57d552001-06-28 07:25:16 +00001582#endif
Eric Andersend35c5df2002-01-09 15:37:36 +00001583#ifdef CONFIG_ASH_JOB_CONTROL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001584 {BUILTIN_REGULAR "bg", bgcmd},
Eric Andersen2870d962001-07-02 17:27:21 +00001585#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001586 {BUILTIN_SPECIAL "break", breakcmd},
1587 {BUILTIN_SPECIAL "builtin", bltincmd},
1588 {BUILTIN_REGULAR "cd", cdcmd},
1589 {BUILTIN_NOSPEC "chdir", cdcmd},
Eric Andersend35c5df2002-01-09 15:37:36 +00001590#ifdef CONFIG_ASH_CMDCMD
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001591 {BUILTIN_REGULAR "command", commandcmd},
Eric Andersen2870d962001-07-02 17:27:21 +00001592#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001593 {BUILTIN_SPECIAL "continue", breakcmd},
1594 {BUILTIN_SPECIAL "eval", evalcmd},
1595 {BUILTIN_SPECIAL "exec", execcmd},
1596 {BUILTIN_SPECIAL "exit", exitcmd},
1597 {BUILTIN_SPEC_ASSG "export", exportcmd},
1598 {BUILTIN_REGULAR "false", false_main},
1599 {BUILTIN_REGULAR "fc", histcmd},
Eric Andersend35c5df2002-01-09 15:37:36 +00001600#ifdef CONFIG_ASH_JOB_CONTROL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001601 {BUILTIN_REGULAR "fg", fgcmd},
Eric Andersen2870d962001-07-02 17:27:21 +00001602#endif
Eric Andersend35c5df2002-01-09 15:37:36 +00001603#ifdef CONFIG_ASH_GETOPTS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001604 {BUILTIN_REGULAR "getopts", getoptscmd},
Eric Andersen2870d962001-07-02 17:27:21 +00001605#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001606 {BUILTIN_NOSPEC "hash", hashcmd},
1607 {BUILTIN_NOSPEC "help", helpcmd},
1608 {BUILTIN_REGULAR "jobs", jobscmd},
Eric Andersend35c5df2002-01-09 15:37:36 +00001609#ifdef CONFIG_ASH_JOB_CONTROL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001610 {BUILTIN_REGULAR "kill", killcmd},
Eric Andersen2870d962001-07-02 17:27:21 +00001611#endif
Eric Andersend35c5df2002-01-09 15:37:36 +00001612#ifdef CONFIG_ASH_MATH_SUPPORT
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001613 {BUILTIN_REGULAR "let", letcmd},
Eric Andersencb57d552001-06-28 07:25:16 +00001614#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001615 {BUILTIN_ASSIGN "local", localcmd},
1616 {BUILTIN_NOSPEC "pwd", pwdcmd},
1617 {BUILTIN_REGULAR "read", readcmd},
1618 {BUILTIN_SPEC_ASSG "readonly", exportcmd},
1619 {BUILTIN_SPECIAL "return", returncmd},
1620 {BUILTIN_SPECIAL "set", setcmd},
1621 {BUILTIN_NOSPEC "setvar", setvarcmd},
1622 {BUILTIN_SPECIAL "shift", shiftcmd},
1623 {BUILTIN_SPECIAL "times", timescmd},
1624 {BUILTIN_SPECIAL "trap", trapcmd},
1625 {BUILTIN_REGULAR "true", true_main},
1626 {BUILTIN_NOSPEC "type", typecmd},
1627 {BUILTIN_NOSPEC "ulimit", ulimitcmd},
1628 {BUILTIN_REGULAR "umask", umaskcmd},
Eric Andersend35c5df2002-01-09 15:37:36 +00001629#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001630 {BUILTIN_REGULAR "unalias", unaliascmd},
Eric Andersen2870d962001-07-02 17:27:21 +00001631#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001632 {BUILTIN_SPECIAL "unset", unsetcmd},
1633 {BUILTIN_REGULAR "wait", waitcmd},
Eric Andersencb57d552001-06-28 07:25:16 +00001634};
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001635
Eric Andersencb57d552001-06-28 07:25:16 +00001636#define NUMBUILTINS (sizeof (builtincmds) / sizeof (struct builtincmd) )
1637
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001638#define DOTCMD &builtincmds[0]
Eric Andersen2870d962001-07-02 17:27:21 +00001639static struct builtincmd *BLTINCMD;
1640static struct builtincmd *EXECCMD;
1641static struct builtincmd *EVALCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00001642
Eric Andersen2870d962001-07-02 17:27:21 +00001643/* states */
Glenn L McGrath50812ff2002-08-23 13:14:48 +00001644#define JOBSTOPPED 1 /* all procs are stopped */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001645#define JOBDONE 2 /* all procs are completed */
Eric Andersencb57d552001-06-28 07:25:16 +00001646
Eric Andersen2870d962001-07-02 17:27:21 +00001647/*
1648 * A job structure contains information about a job. A job is either a
1649 * single process or a set of processes contained in a pipeline. In the
1650 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1651 * array of pids.
1652 */
Eric Andersencb57d552001-06-28 07:25:16 +00001653
Eric Andersen2870d962001-07-02 17:27:21 +00001654struct procstat {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001655 pid_t pid; /* process id */
1656 int status; /* status flags (defined above) */
1657 char *cmd; /* text of command being run */
Eric Andersen2870d962001-07-02 17:27:21 +00001658};
Eric Andersencb57d552001-06-28 07:25:16 +00001659
Eric Andersen2870d962001-07-02 17:27:21 +00001660
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001661static int job_warning; /* user was warned about stopped jobs */
Eric Andersen2870d962001-07-02 17:27:21 +00001662
Eric Andersend35c5df2002-01-09 15:37:36 +00001663#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen2870d962001-07-02 17:27:21 +00001664static void setjobctl(int enable);
1665#else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001666#define setjobctl(on) /* do nothing */
Eric Andersencb57d552001-06-28 07:25:16 +00001667#endif
1668
Eric Andersen2870d962001-07-02 17:27:21 +00001669
1670struct job {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001671 struct procstat ps0; /* status of process */
1672 struct procstat *ps; /* status or processes when more than one */
1673 short nprocs; /* number of processes */
1674 short pgrp; /* process group of this job */
1675 char state; /* true if job is finished */
1676 char used; /* true if this entry is in used */
1677 char changed; /* true if status has changed */
Eric Andersend35c5df2002-01-09 15:37:36 +00001678#ifdef CONFIG_ASH_JOB_CONTROL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001679 char jobctl; /* job running under job control */
Eric Andersen2870d962001-07-02 17:27:21 +00001680#endif
1681};
1682
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001683static struct job *jobtab; /* array of jobs */
1684static int njobs; /* size of array */
1685static int backgndpid = -1; /* pid of last background process */
1686
Eric Andersend35c5df2002-01-09 15:37:36 +00001687#ifdef CONFIG_ASH_JOB_CONTROL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001688static int initialpgrp; /* pgrp of shell on invocation */
1689static int curjob; /* current job */
Eric Andersen2870d962001-07-02 17:27:21 +00001690static int jobctl;
1691#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001692
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001693static struct job *makejob(const union node *, int);
1694static int forkshell(struct job *, const union node *, int);
1695static int waitforjob(struct job *);
Eric Andersen2870d962001-07-02 17:27:21 +00001696
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001697static int docd(char *, int);
1698static void getpwd(void);
Eric Andersen2870d962001-07-02 17:27:21 +00001699
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001700static char *padvance(const char **, const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001701
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001702static char nullstr[1]; /* zero length string */
1703static char *curdir = nullstr; /* current working directory */
Eric Andersen2870d962001-07-02 17:27:21 +00001704
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001705static int cdcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001706{
1707 const char *dest;
1708 const char *path;
1709 char *p;
1710 struct stat statb;
1711 int print = 0;
1712
1713 nextopt(nullstr);
1714 if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME")) == NULL)
1715 error("HOME not set");
1716 if (*dest == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00001717 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001718 if (dest[0] == '-' && dest[1] == '\0') {
1719 dest = bltinlookup("OLDPWD");
1720 if (!dest || !*dest) {
1721 dest = curdir;
1722 }
1723 print = 1;
1724 if (dest)
Eric Andersen2870d962001-07-02 17:27:21 +00001725 print = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00001726 else
Eric Andersen2870d962001-07-02 17:27:21 +00001727 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001728 }
1729 if (*dest == '/' || (path = bltinlookup("CDPATH")) == NULL)
1730 path = nullstr;
1731 while ((p = padvance(&path, dest)) != NULL) {
1732 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
1733 if (!print) {
1734 /*
1735 * XXX - rethink
1736 */
1737 if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
1738 p += 2;
1739 print = strcmp(p, dest);
1740 }
1741 if (docd(p, print) >= 0)
1742 return 0;
1743
1744 }
1745 }
1746 error("can't cd to %s", dest);
1747 /* NOTREACHED */
1748}
1749
1750
1751/*
Glenn L McGrath50812ff2002-08-23 13:14:48 +00001752 * Update curdir (the name of the current directory) in response to a
1753 * cd command. We also call hashcd to let the routines in exec.c know
1754 * that the current directory has changed.
1755 */
1756
1757static void hashcd(void);
1758
1759static inline void updatepwd(const char *dir)
1760{
1761 hashcd(); /* update command hash table */
1762
1763 /*
1764 * If our argument is NULL, we don't know the current directory
1765 */
1766 if (dir == NULL || curdir == nullstr) {
1767 setpwd(0, 1);
1768 } else {
1769 setpwd(dir, 1);
1770 }
1771}
1772
1773/*
Eric Andersencb57d552001-06-28 07:25:16 +00001774 * Actually do the chdir. In an interactive shell, print the
1775 * directory name if "print" is nonzero.
1776 */
1777
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001778static int docd(char *dest, int print)
Eric Andersencb57d552001-06-28 07:25:16 +00001779{
Eric Andersencb57d552001-06-28 07:25:16 +00001780 TRACE(("docd(\"%s\", %d) called\n", dest, print));
Eric Andersencb57d552001-06-28 07:25:16 +00001781 INTOFF;
1782 if (chdir(dest) < 0) {
1783 INTON;
1784 return -1;
1785 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00001786 updatepwd(dest);
Eric Andersencb57d552001-06-28 07:25:16 +00001787 INTON;
1788 if (print && iflag)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001789 puts(curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00001790 return 0;
1791}
1792
1793
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001794static int pwdcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001795{
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001796 puts(curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00001797 return 0;
1798}
Eric Andersencb57d552001-06-28 07:25:16 +00001799
Eric Andersena3483db2001-10-24 08:01:06 +00001800/* Ask system the current directory */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001801static void getpwd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00001802{
Eric Andersen2870d962001-07-02 17:27:21 +00001803 curdir = xgetcwd(0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001804 if (curdir == 0)
Eric Andersen2870d962001-07-02 17:27:21 +00001805 curdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00001806}
1807
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001808static void setpwd(const char *val, int setold)
Eric Andersencb57d552001-06-28 07:25:16 +00001809{
Eric Andersena3483db2001-10-24 08:01:06 +00001810 char *cated = NULL;
1811
Eric Andersencb57d552001-06-28 07:25:16 +00001812 if (setold) {
1813 setvar("OLDPWD", curdir, VEXPORT);
1814 }
1815 INTOFF;
1816 if (curdir != nullstr) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001817 if (val != NULL && *val != '/')
Eric Andersena3483db2001-10-24 08:01:06 +00001818 val = cated = concat_path_file(curdir, val);
Eric Andersencb57d552001-06-28 07:25:16 +00001819 free(curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00001820 }
Eric Andersena3483db2001-10-24 08:01:06 +00001821 if (!val)
Eric Andersencb57d552001-06-28 07:25:16 +00001822 getpwd();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001823 else
Eric Andersena3483db2001-10-24 08:01:06 +00001824 curdir = simplify_path(val);
1825 free(cated);
Eric Andersencb57d552001-06-28 07:25:16 +00001826 INTON;
1827 setvar("PWD", curdir, VEXPORT);
1828}
1829
Eric Andersencb57d552001-06-28 07:25:16 +00001830/*
1831 * Errors and exceptions.
1832 */
1833
1834/*
1835 * Code to handle exceptions in C.
1836 */
1837
Eric Andersen2870d962001-07-02 17:27:21 +00001838/*
1839 * We enclose jmp_buf in a structure so that we can declare pointers to
1840 * jump locations. The global variable handler contains the location to
1841 * jump to when an exception occurs, and the global variable exception
1842 * contains a code identifying the exeception. To implement nested
1843 * exception handlers, the user should save the value of handler on entry
1844 * to an inner scope, set handler to point to a jmploc structure for the
1845 * inner scope, and restore handler on exit from the scope.
1846 */
1847
1848struct jmploc {
1849 jmp_buf loc;
1850};
1851
1852/* exceptions */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001853#define EXINT 0 /* SIGINT received */
1854#define EXERROR 1 /* a generic error */
1855#define EXSHELLPROC 2 /* execute a shell procedure */
1856#define EXEXEC 3 /* command execution failed */
Glenn L McGrath50812ff2002-08-23 13:14:48 +00001857#define EXREDIR 4 /* redirection error */
Eric Andersen2870d962001-07-02 17:27:21 +00001858
1859static struct jmploc *handler;
Eric Andersencb57d552001-06-28 07:25:16 +00001860static int exception;
Eric Andersencb57d552001-06-28 07:25:16 +00001861
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001862static void exverror(int, const char *, va_list)
1863 __attribute__ ((__noreturn__));
Eric Andersencb57d552001-06-28 07:25:16 +00001864
1865/*
1866 * Called to raise an exception. Since C doesn't include exceptions, we
1867 * just do a longjmp to the exception handler. The type of exception is
1868 * stored in the global variable "exception".
1869 */
1870
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001871static void exraise(int) __attribute__ ((__noreturn__));
Eric Andersen2870d962001-07-02 17:27:21 +00001872
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001873static void exraise(int e)
Eric Andersencb57d552001-06-28 07:25:16 +00001874{
1875#ifdef DEBUG
1876 if (handler == NULL)
1877 abort();
1878#endif
Eric Andersen62483552001-07-10 06:09:16 +00001879 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00001880 exception = e;
1881 longjmp(handler->loc, 1);
1882}
1883
1884
1885/*
1886 * Called from trap.c when a SIGINT is received. (If the user specifies
1887 * that SIGINT is to be trapped or ignored using the trap builtin, then
1888 * this routine is not called.) Suppressint is nonzero when interrupts
1889 * are held using the INTOFF macro. The call to _exit is necessary because
1890 * there is a short period after a fork before the signal handlers are
1891 * set to the appropriate value for the child. (The test for iflag is
1892 * just defensive programming.)
1893 */
1894
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001895static void onint(void)
1896{
Eric Andersencb57d552001-06-28 07:25:16 +00001897 sigset_t mysigset;
1898
1899 if (suppressint) {
1900 intpending++;
1901 return;
1902 }
1903 intpending = 0;
1904 sigemptyset(&mysigset);
1905 sigprocmask(SIG_SETMASK, &mysigset, NULL);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00001906 if (!(rootshell && iflag)) {
Eric Andersencb57d552001-06-28 07:25:16 +00001907 signal(SIGINT, SIG_DFL);
1908 raise(SIGINT);
1909 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00001910 exraise(EXINT);
Eric Andersencb57d552001-06-28 07:25:16 +00001911 /* NOTREACHED */
1912}
1913
1914
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001915static char *commandname; /* currently executing command */
Eric Andersen2870d962001-07-02 17:27:21 +00001916
Eric Andersencb57d552001-06-28 07:25:16 +00001917/*
1918 * Exverror is called to raise the error exception. If the first argument
1919 * is not NULL then error prints an error message using printf style
1920 * formatting. It then raises the error exception.
1921 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001922static void exverror(int cond, const char *msg, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00001923{
1924 CLEAR_PENDING_INT;
1925 INTOFF;
1926
1927#ifdef DEBUG
1928 if (msg)
1929 TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
1930 else
1931 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
1932#endif
1933 if (msg) {
1934 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +00001935 out2fmt("%s: ", commandname);
1936 vfprintf(stderr, msg, ap);
1937 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00001938 }
Eric Andersencb57d552001-06-28 07:25:16 +00001939 exraise(cond);
1940 /* NOTREACHED */
1941}
1942
1943
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001944static void error(const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00001945{
Eric Andersencb57d552001-06-28 07:25:16 +00001946 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001947
Eric Andersencb57d552001-06-28 07:25:16 +00001948 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00001949 exverror(EXERROR, msg, ap);
1950 /* NOTREACHED */
1951 va_end(ap);
1952}
1953
1954
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001955static void exerror(int cond, const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00001956{
Eric Andersencb57d552001-06-28 07:25:16 +00001957 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001958
Eric Andersencb57d552001-06-28 07:25:16 +00001959 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00001960 exverror(cond, msg, ap);
1961 /* NOTREACHED */
1962 va_end(ap);
1963}
1964
1965
1966
1967/*
1968 * Table of error messages.
1969 */
1970
1971struct errname {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001972 short errcode; /* error number */
1973 short action; /* operation which encountered the error */
Eric Andersencb57d552001-06-28 07:25:16 +00001974};
1975
Eric Andersen2870d962001-07-02 17:27:21 +00001976/*
1977 * Types of operations (passed to the errmsg routine).
1978 */
1979
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001980#define E_OPEN 01 /* opening a file */
1981#define E_CREAT 02 /* creating a file */
1982#define E_EXEC 04 /* executing a program */
Eric Andersencb57d552001-06-28 07:25:16 +00001983
1984#define ALL (E_OPEN|E_CREAT|E_EXEC)
1985
1986static const struct errname errormsg[] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001987 {EINTR, ALL},
1988 {EACCES, ALL},
1989 {EIO, ALL},
1990 {ENOENT, E_OPEN},
1991 {ENOENT, E_CREAT},
1992 {ENOENT, E_EXEC},
1993 {ENOTDIR, E_OPEN},
1994 {ENOTDIR, E_CREAT},
1995 {ENOTDIR, E_EXEC},
1996 {EISDIR, ALL},
1997 {EEXIST, E_CREAT},
Eric Andersen2870d962001-07-02 17:27:21 +00001998#ifdef EMFILE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001999 {EMFILE, ALL},
Eric Andersencb57d552001-06-28 07:25:16 +00002000#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002001 {ENFILE, ALL},
2002 {ENOSPC, ALL},
Eric Andersencb57d552001-06-28 07:25:16 +00002003#ifdef EDQUOT
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002004 {EDQUOT, ALL},
Eric Andersencb57d552001-06-28 07:25:16 +00002005#endif
2006#ifdef ENOSR
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002007 {ENOSR, ALL},
Eric Andersencb57d552001-06-28 07:25:16 +00002008#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002009 {ENXIO, ALL},
2010 {EROFS, ALL},
2011 {ETXTBSY, ALL},
Eric Andersen2870d962001-07-02 17:27:21 +00002012#ifdef EAGAIN
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002013 {EAGAIN, E_EXEC},
Eric Andersencb57d552001-06-28 07:25:16 +00002014#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002015 {ENOMEM, ALL},
Eric Andersencb57d552001-06-28 07:25:16 +00002016#ifdef ENOLINK
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002017 {ENOLINK, ALL},
Eric Andersencb57d552001-06-28 07:25:16 +00002018#endif
2019#ifdef EMULTIHOP
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002020 {EMULTIHOP, ALL},
Eric Andersencb57d552001-06-28 07:25:16 +00002021#endif
2022#ifdef ECOMM
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002023 {ECOMM, ALL},
Eric Andersencb57d552001-06-28 07:25:16 +00002024#endif
2025#ifdef ESTALE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002026 {ESTALE, ALL},
Eric Andersencb57d552001-06-28 07:25:16 +00002027#endif
2028#ifdef ETIMEDOUT
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002029 {ETIMEDOUT, ALL},
Eric Andersencb57d552001-06-28 07:25:16 +00002030#endif
2031#ifdef ELOOP
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002032 {ELOOP, ALL},
Eric Andersencb57d552001-06-28 07:25:16 +00002033#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002034 {E2BIG, E_EXEC},
Eric Andersencb57d552001-06-28 07:25:16 +00002035#ifdef ELIBACC
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002036 {ELIBACC, E_EXEC},
Eric Andersencb57d552001-06-28 07:25:16 +00002037#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002038};
2039
Eric Andersen2870d962001-07-02 17:27:21 +00002040#define ERRNAME_SIZE (sizeof(errormsg)/sizeof(struct errname))
Eric Andersencb57d552001-06-28 07:25:16 +00002041
2042/*
2043 * Return a string describing an error. The returned string may be a
2044 * pointer to a static buffer that will be overwritten on the next call.
2045 * Action describes the operation that got the error.
2046 */
2047
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002048static const char *errmsg(int e, int action)
Eric Andersencb57d552001-06-28 07:25:16 +00002049{
2050 struct errname const *ep;
2051 static char buf[12];
2052
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002053 for (ep = errormsg; ep < errormsg + ERRNAME_SIZE; ep++) {
Eric Andersencb57d552001-06-28 07:25:16 +00002054 if (ep->errcode == e && (ep->action & action) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00002055 return strerror(e);
Eric Andersencb57d552001-06-28 07:25:16 +00002056 }
Eric Andersen2870d962001-07-02 17:27:21 +00002057
Eric Andersen3102ac42001-07-06 04:26:23 +00002058 snprintf(buf, sizeof buf, "error %d", e);
Eric Andersencb57d552001-06-28 07:25:16 +00002059 return buf;
2060}
2061
2062
Eric Andersend35c5df2002-01-09 15:37:36 +00002063#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002064static void __inton()
2065{
Eric Andersencb57d552001-06-28 07:25:16 +00002066 if (--suppressint == 0 && intpending) {
2067 onint();
2068 }
2069}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002070static void forceinton(void)
2071{
Eric Andersen3102ac42001-07-06 04:26:23 +00002072 suppressint = 0;
2073 if (intpending)
2074 onint();
2075}
Eric Andersencb57d552001-06-28 07:25:16 +00002076#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002077
2078/* flags in argument to evaltree */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002079#define EV_EXIT 01 /* exit after evaluating tree */
2080#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2081#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00002082
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002083static int evalskip; /* set if we are skipping commands */
2084static int skipcount; /* number of levels to skip */
2085static int loopnest; /* current loop nesting level */
2086static int funcnest; /* depth of function calls */
Eric Andersencb57d552001-06-28 07:25:16 +00002087
2088
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002089static struct strlist *cmdenviron; /* environment for builtin command */
2090static int exitstatus; /* exit status of last command */
2091static int oexitstatus; /* saved exit status */
Eric Andersencb57d552001-06-28 07:25:16 +00002092
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002093static void evalsubshell(const union node *, int);
2094static void expredir(union node *);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002095static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002096static void eprintlist(struct strlist *);
Eric Andersencb57d552001-06-28 07:25:16 +00002097
Eric Andersen2870d962001-07-02 17:27:21 +00002098static union node *parsecmd(int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002099
Eric Andersencb57d552001-06-28 07:25:16 +00002100/*
2101 * Called to reset things after an exception.
2102 */
2103
Eric Andersencb57d552001-06-28 07:25:16 +00002104/*
2105 * The eval commmand.
2106 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002107static void evalstring(char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00002108
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002109static int evalcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002110{
Eric Andersen2870d962001-07-02 17:27:21 +00002111 char *p;
2112 char *concat;
2113 char **ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002114
Eric Andersen2870d962001-07-02 17:27:21 +00002115 if (argc > 1) {
2116 p = argv[1];
2117 if (argc > 2) {
2118 STARTSTACKSTR(concat);
2119 ap = argv + 2;
2120 for (;;) {
2121 while (*p)
2122 STPUTC(*p++, concat);
2123 if ((p = *ap++) == NULL)
2124 break;
2125 STPUTC(' ', concat);
2126 }
2127 STPUTC('\0', concat);
2128 p = grabstackstr(concat);
2129 }
2130 evalstring(p, EV_TESTED);
2131 }
2132 return exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002133}
2134
Eric Andersencb57d552001-06-28 07:25:16 +00002135/*
2136 * Execute a command or commands contained in a string.
2137 */
2138
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002139static void evaltree(union node *, int);
2140static void setinputstring(char *);
2141static void popfile(void);
Eric Andersen2870d962001-07-02 17:27:21 +00002142static void setstackmark(struct stackmark *mark);
2143static void popstackmark(struct stackmark *mark);
2144
2145
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002146static void evalstring(char *s, int flag)
Eric Andersen2870d962001-07-02 17:27:21 +00002147{
Eric Andersencb57d552001-06-28 07:25:16 +00002148 union node *n;
2149 struct stackmark smark;
2150
2151 setstackmark(&smark);
2152 setinputstring(s);
2153 while ((n = parsecmd(0)) != NEOF) {
2154 evaltree(n, flag);
2155 popstackmark(&smark);
2156 }
2157 popfile();
2158 popstackmark(&smark);
2159}
2160
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002161static struct builtincmd *find_builtin(const char *);
2162static void expandarg(union node *, struct arglist *, int);
2163static void calcsize(const union node *);
2164static union node *copynode(const union node *);
Eric Andersen62483552001-07-10 06:09:16 +00002165
2166/*
2167 * Make a copy of a parse tree.
2168 */
2169
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002170static int funcblocksize; /* size of structures in function */
2171static int funcstringsize; /* size of strings in node */
2172static pointer funcblock; /* block to allocate function from */
2173static char *funcstring; /* block to allocate strings from */
Eric Andersen62483552001-07-10 06:09:16 +00002174
2175
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002176static inline union node *copyfunc(union node *n)
Eric Andersen62483552001-07-10 06:09:16 +00002177{
2178 if (n == NULL)
2179 return NULL;
2180 funcblocksize = 0;
2181 funcstringsize = 0;
2182 calcsize(n);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00002183 funcblock = xmalloc(funcblocksize + funcstringsize);
Eric Andersen62483552001-07-10 06:09:16 +00002184 funcstring = (char *) funcblock + funcblocksize;
2185 return copynode(n);
2186}
2187
2188/*
Eric Andersen62483552001-07-10 06:09:16 +00002189 * Add a new command entry, replacing any existing command entry for
2190 * the same name.
2191 */
2192
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002193static inline void addcmdentry(char *name, struct cmdentry *entry)
Eric Andersen62483552001-07-10 06:09:16 +00002194{
2195 struct tblentry *cmdp;
2196
2197 INTOFF;
2198 cmdp = cmdlookup(name, 1);
2199 if (cmdp->cmdtype == CMDFUNCTION) {
Aaron Lehmann49c024a2002-08-02 06:39:47 +00002200 free(cmdp->param.func);
Eric Andersen62483552001-07-10 06:09:16 +00002201 }
2202 cmdp->cmdtype = entry->cmdtype;
2203 cmdp->param = entry->u;
2204 INTON;
2205}
2206
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002207static inline void evalloop(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002208{
2209 int status;
2210
2211 loopnest++;
2212 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002213 flags &= EV_TESTED;
Eric Andersencb57d552001-06-28 07:25:16 +00002214 for (;;) {
2215 evaltree(n->nbinary.ch1, EV_TESTED);
2216 if (evalskip) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002217 skipping:if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002218 evalskip = 0;
2219 continue;
2220 }
2221 if (evalskip == SKIPBREAK && --skipcount <= 0)
2222 evalskip = 0;
2223 break;
2224 }
2225 if (n->type == NWHILE) {
2226 if (exitstatus != 0)
2227 break;
2228 } else {
2229 if (exitstatus == 0)
2230 break;
2231 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002232 evaltree(n->nbinary.ch2, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002233 status = exitstatus;
2234 if (evalskip)
2235 goto skipping;
2236 }
2237 loopnest--;
2238 exitstatus = status;
2239}
2240
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002241static void evalfor(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002242{
2243 struct arglist arglist;
2244 union node *argp;
2245 struct strlist *sp;
2246 struct stackmark smark;
2247
2248 setstackmark(&smark);
2249 arglist.lastp = &arglist.list;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002250 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002251 oexitstatus = exitstatus;
2252 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2253 if (evalskip)
2254 goto out;
2255 }
2256 *arglist.lastp = NULL;
2257
2258 exitstatus = 0;
2259 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002260 flags &= EV_TESTED;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002261 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002262 setvar(n->nfor.var, sp->text, 0);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002263 evaltree(n->nfor.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002264 if (evalskip) {
2265 if (evalskip == SKIPCONT && --skipcount <= 0) {
2266 evalskip = 0;
2267 continue;
2268 }
2269 if (evalskip == SKIPBREAK && --skipcount <= 0)
2270 evalskip = 0;
2271 break;
2272 }
2273 }
2274 loopnest--;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002275 out:
Eric Andersencb57d552001-06-28 07:25:16 +00002276 popstackmark(&smark);
2277}
2278
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002279static inline void evalcase(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002280{
2281 union node *cp;
2282 union node *patp;
2283 struct arglist arglist;
2284 struct stackmark smark;
2285
2286 setstackmark(&smark);
2287 arglist.lastp = &arglist.list;
2288 oexitstatus = exitstatus;
2289 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002290 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
2291 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002292 if (casematch(patp, arglist.list->text)) {
2293 if (evalskip == 0) {
2294 evaltree(cp->nclist.body, flags);
2295 }
2296 goto out;
2297 }
2298 }
2299 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002300 out:
Eric Andersencb57d552001-06-28 07:25:16 +00002301 popstackmark(&smark);
2302}
2303
Eric Andersencb57d552001-06-28 07:25:16 +00002304/*
Eric Andersencb57d552001-06-28 07:25:16 +00002305 * Evaluate a pipeline. All the processes in the pipeline are children
2306 * of the process creating the pipeline. (This differs from some versions
2307 * of the shell, which make the last process in a pipeline the parent
2308 * of all the rest.)
2309 */
2310
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002311static inline void evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002312{
2313 struct job *jp;
2314 struct nodelist *lp;
2315 int pipelen;
2316 int prevfd;
2317 int pip[2];
2318
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002319 TRACE(("evalpipe(0x%lx) called\n", (long) n));
Eric Andersencb57d552001-06-28 07:25:16 +00002320 pipelen = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002321 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00002322 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002323 flags |= EV_EXIT;
Eric Andersencb57d552001-06-28 07:25:16 +00002324 INTOFF;
2325 jp = makejob(n, pipelen);
2326 prevfd = -1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002327 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002328 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00002329 pip[1] = -1;
2330 if (lp->next) {
2331 if (pipe(pip) < 0) {
2332 close(prevfd);
2333 error("Pipe call failed");
2334 }
2335 }
2336 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
2337 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00002338 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002339 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00002340 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002341 if (prevfd > 0) {
2342 dup2(prevfd, 0);
2343 close(prevfd);
2344 }
2345 if (pip[1] > 1) {
2346 dup2(pip[1], 1);
2347 close(pip[1]);
2348 }
2349 evaltree(lp->n, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002350 }
2351 if (prevfd >= 0)
2352 close(prevfd);
2353 prevfd = pip[0];
2354 close(pip[1]);
2355 }
Eric Andersencb57d552001-06-28 07:25:16 +00002356 if (n->npipe.backgnd == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002357 exitstatus = waitforjob(jp);
2358 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
Eric Andersencb57d552001-06-28 07:25:16 +00002359 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002360 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00002361}
2362
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002363static void find_command(const char *, struct cmdentry *, int, const char *);
2364
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002365static int isassignment(const char *word)
2366{
Eric Andersen2870d962001-07-02 17:27:21 +00002367 if (!is_name(*word)) {
2368 return 0;
2369 }
2370 do {
2371 word++;
2372 } while (is_in_name(*word));
2373 return *word == '=';
2374}
2375
Eric Andersen62483552001-07-10 06:09:16 +00002376
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002377static void evalcommand(union node *cmd, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002378{
2379 struct stackmark smark;
2380 union node *argp;
2381 struct arglist arglist;
2382 struct arglist varlist;
2383 char **argv;
2384 int argc;
2385 char **envp;
2386 struct strlist *sp;
2387 int mode;
Eric Andersencb57d552001-06-28 07:25:16 +00002388 struct cmdentry cmdentry;
2389 struct job *jp;
2390 char *volatile savecmdname;
2391 volatile struct shparam saveparam;
2392 struct localvar *volatile savelocalvars;
2393 volatile int e;
2394 char *lastarg;
2395 const char *path;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002396 int spclbltin;
Eric Andersencb57d552001-06-28 07:25:16 +00002397 struct jmploc *volatile savehandler;
2398 struct jmploc jmploc;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002399
Eric Andersencb57d552001-06-28 07:25:16 +00002400#if __GNUC__
2401 /* Avoid longjmp clobbering */
2402 (void) &argv;
2403 (void) &argc;
2404 (void) &lastarg;
2405 (void) &flags;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002406 (void) &spclbltin;
Eric Andersencb57d552001-06-28 07:25:16 +00002407#endif
2408
2409 /* First expand the arguments. */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002410 TRACE(("evalcommand(0x%lx, %d) called\n", (long) cmd, flags));
Eric Andersencb57d552001-06-28 07:25:16 +00002411 setstackmark(&smark);
2412 arglist.lastp = &arglist.list;
2413 varlist.lastp = &varlist.list;
2414 arglist.list = 0;
2415 oexitstatus = exitstatus;
2416 exitstatus = 0;
2417 path = pathval();
2418 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
2419 expandarg(argp, &varlist, EXP_VARTILDE);
2420 }
Eric Andersen1887b042002-10-22 11:58:59 +00002421 for (argp = cmd->ncmd.args; argp && !arglist.list; argp = argp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002422 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2423 }
Eric Andersen1887b042002-10-22 11:58:59 +00002424 if (argp) {
2425 struct builtincmd *bcmd;
2426 int pseudovarflag;
2427
2428 bcmd = find_builtin(arglist.list->text);
2429 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
2430 for (; argp; argp = argp->narg.next) {
2431 if (pseudovarflag && isassignment(argp->narg.text)) {
2432 expandarg(argp, &arglist, EXP_VARTILDE);
2433 continue;
2434 }
2435 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2436 }
2437 }
Eric Andersencb57d552001-06-28 07:25:16 +00002438 *arglist.lastp = NULL;
2439 *varlist.lastp = NULL;
2440 expredir(cmd->ncmd.redirect);
2441 argc = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002442 for (sp = arglist.list; sp; sp = sp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00002443 argc++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002444 argv = stalloc(sizeof(char *) * (argc + 1));
Eric Andersencb57d552001-06-28 07:25:16 +00002445
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002446 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002447 TRACE(("evalcommand arg: %s\n", sp->text));
2448 *argv++ = sp->text;
2449 }
2450 *argv = NULL;
2451 lastarg = NULL;
2452 if (iflag && funcnest == 0 && argc > 0)
2453 lastarg = argv[-1];
2454 argv -= argc;
2455
2456 /* Print the command if xflag is set. */
2457 if (xflag) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002458 out2c('+');
Eric Andersencb57d552001-06-28 07:25:16 +00002459 eprintlist(varlist.list);
2460 eprintlist(arglist.list);
Eric Andersen3102ac42001-07-06 04:26:23 +00002461 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00002462 }
2463
2464 /* Now locate the command. */
2465 if (argc == 0) {
2466 cmdentry.cmdtype = CMDBUILTIN;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002467 cmdentry.u.cmd = BLTINCMD;
2468 spclbltin = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00002469 } else {
2470 const char *oldpath;
2471 int findflag = DO_ERR;
2472 int oldfindflag;
2473
2474 /*
2475 * Modify the command lookup path, if a PATH= assignment
2476 * is present
2477 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002478 for (sp = varlist.list; sp; sp = sp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00002479 if (varequal(sp->text, defpathvar)) {
2480 path = sp->text + 5;
2481 findflag |= DO_BRUTE;
2482 }
2483 oldpath = path;
2484 oldfindflag = findflag;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002485 spclbltin = -1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002486 for (;;) {
Eric Andersencb57d552001-06-28 07:25:16 +00002487 find_command(argv[0], &cmdentry, findflag, path);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002488 if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */
Eric Andersencb57d552001-06-28 07:25:16 +00002489 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002490 goto out;
2491 }
2492 /* implement bltin and command here */
2493 if (cmdentry.cmdtype != CMDBUILTIN) {
2494 break;
2495 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002496 if (spclbltin < 0) {
2497 spclbltin = !!(IS_BUILTIN_SPECIAL(cmdentry.u.cmd)) * 2;
Eric Andersencb57d552001-06-28 07:25:16 +00002498 }
2499 if (cmdentry.u.cmd == BLTINCMD) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002500 for (;;) {
Eric Andersencb57d552001-06-28 07:25:16 +00002501 struct builtincmd *bcmd;
2502
2503 argv++;
2504 if (--argc == 0)
2505 goto found;
2506 if (!(bcmd = find_builtin(*argv))) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002507 out2fmt("%s: not found\n", *argv);
Eric Andersencb57d552001-06-28 07:25:16 +00002508 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002509 goto out;
2510 }
2511 cmdentry.u.cmd = bcmd;
2512 if (bcmd != BLTINCMD)
2513 break;
2514 }
2515 }
Eric Andersen2870d962001-07-02 17:27:21 +00002516 if (cmdentry.u.cmd == find_builtin("command")) {
Eric Andersencb57d552001-06-28 07:25:16 +00002517 argv++;
2518 if (--argc == 0) {
2519 goto found;
2520 }
2521 if (*argv[0] == '-') {
2522 if (!equal(argv[0], "-p")) {
2523 argv--;
2524 argc++;
2525 break;
2526 }
2527 argv++;
2528 if (--argc == 0) {
2529 goto found;
2530 }
2531 path = defpath;
2532 findflag |= DO_BRUTE;
2533 } else {
2534 path = oldpath;
2535 findflag = oldfindflag;
2536 }
2537 findflag |= DO_NOFUN;
2538 continue;
2539 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002540 found:
Eric Andersencb57d552001-06-28 07:25:16 +00002541 break;
2542 }
2543 }
2544
2545 /* Fork off a child process if necessary. */
2546 if (cmd->ncmd.backgnd
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002547 || (cmdentry.cmdtype == CMDNORMAL && (!(flags & EV_EXIT) || trap[0]))
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002548 ) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002549 INTOFF;
Eric Andersencb57d552001-06-28 07:25:16 +00002550 jp = makejob(cmd, 1);
2551 mode = cmd->ncmd.backgnd;
Eric Andersencb57d552001-06-28 07:25:16 +00002552 if (forkshell(jp, cmd, mode) != 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002553 goto parent; /* at end of routine */
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002554 FORCEINTON;
Eric Andersencb57d552001-06-28 07:25:16 +00002555 flags |= EV_EXIT;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002556 } else {
2557 flags &= ~EV_EXIT;
Eric Andersencb57d552001-06-28 07:25:16 +00002558 }
2559
2560 /* This is the child process if a fork occurred. */
2561 /* Execute the command. */
2562 if (cmdentry.cmdtype == CMDFUNCTION) {
2563#ifdef DEBUG
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002564 trputs("Shell function: ");
2565 trargs(argv);
Eric Andersencb57d552001-06-28 07:25:16 +00002566#endif
2567 exitstatus = oexitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002568 saveparam = shellparam;
2569 shellparam.malloc = 0;
2570 shellparam.nparam = argc - 1;
2571 shellparam.p = argv + 1;
2572 INTOFF;
2573 savelocalvars = localvars;
2574 localvars = NULL;
2575 INTON;
2576 if (setjmp(jmploc.loc)) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002577 if (exception == EXREDIR) {
2578 exitstatus = 2;
2579 goto funcdone;
Eric Andersencb57d552001-06-28 07:25:16 +00002580 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002581 saveparam.optind = shellparam.optind;
2582 saveparam.optoff = shellparam.optoff;
2583 freeparam(&shellparam);
2584 shellparam = saveparam;
Eric Andersencb57d552001-06-28 07:25:16 +00002585 poplocalvars();
2586 localvars = savelocalvars;
2587 handler = savehandler;
2588 longjmp(handler->loc, 1);
2589 }
2590 savehandler = handler;
2591 handler = &jmploc;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002592 redirect(cmd->ncmd.redirect, REDIR_PUSH);
2593 listsetvar(varlist.list);
Eric Andersencb57d552001-06-28 07:25:16 +00002594 funcnest++;
2595 evaltree(cmdentry.u.func, flags & EV_TESTED);
2596 funcnest--;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002597 funcdone:
Eric Andersencb57d552001-06-28 07:25:16 +00002598 INTOFF;
2599 poplocalvars();
2600 localvars = savelocalvars;
2601 saveparam.optind = shellparam.optind;
2602 saveparam.optoff = shellparam.optoff;
2603 freeparam(&shellparam);
2604 shellparam = saveparam;
2605 handler = savehandler;
2606 popredir();
2607 INTON;
2608 if (evalskip == SKIPFUNC) {
2609 evalskip = 0;
2610 skipcount = 0;
2611 }
Eric Andersencb57d552001-06-28 07:25:16 +00002612 } else if (cmdentry.cmdtype == CMDBUILTIN) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002613 int redir;
2614
Eric Andersencb57d552001-06-28 07:25:16 +00002615#ifdef DEBUG
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002616 trputs("builtin command: ");
2617 trargs(argv);
Eric Andersencb57d552001-06-28 07:25:16 +00002618#endif
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002619 redir = (cmdentry.u.cmd == EXECCMD) ? 0 : REDIR_PUSH;
Eric Andersencb57d552001-06-28 07:25:16 +00002620 savecmdname = commandname;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002621 if (spclbltin) {
Eric Andersencb57d552001-06-28 07:25:16 +00002622 listsetvar(varlist.list);
2623 } else {
2624 cmdenviron = varlist.list;
2625 }
2626 e = -1;
2627 if (setjmp(jmploc.loc)) {
2628 e = exception;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002629 exitstatus = (e == EXINT) ? SIGINT + 128 : 2;
Eric Andersencb57d552001-06-28 07:25:16 +00002630 goto cmddone;
2631 }
2632 savehandler = handler;
2633 handler = &jmploc;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002634 redirect(cmd->ncmd.redirect, redir);
Eric Andersencb57d552001-06-28 07:25:16 +00002635 commandname = argv[0];
2636 argptr = argv + 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002637 optptr = NULL; /* initialize nextopt */
2638 exitstatus = (*cmdentry.u.cmd->builtinfunc) (argc, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00002639 flushall();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002640 cmddone:
Eric Andersencb57d552001-06-28 07:25:16 +00002641 cmdenviron = NULL;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002642 commandname = savecmdname;
Eric Andersencb57d552001-06-28 07:25:16 +00002643 handler = savehandler;
2644 if (e != -1) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002645 if (e == EXINT || spclbltin & 2) {
2646 if (e == EXREDIR)
2647 exraise(e);
2648 }
Eric Andersencb57d552001-06-28 07:25:16 +00002649 FORCEINTON;
2650 }
2651 if (cmdentry.u.cmd != EXECCMD)
2652 popredir();
Eric Andersencb57d552001-06-28 07:25:16 +00002653 } else {
2654#ifdef DEBUG
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002655 trputs("normal command: ");
2656 trargs(argv);
Eric Andersencb57d552001-06-28 07:25:16 +00002657#endif
2658 redirect(cmd->ncmd.redirect, 0);
2659 clearredir();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002660 for (sp = varlist.list; sp; sp = sp->next)
2661 setvareq(sp->text, VEXPORT | VSTACK);
Eric Andersencb57d552001-06-28 07:25:16 +00002662 envp = environment();
2663 shellexec(argv, envp, path, cmdentry.u.index);
2664 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002665 if (flags & EV_EXIT)
2666 exitshell(exitstatus);
Eric Andersencb57d552001-06-28 07:25:16 +00002667 goto out;
2668
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002669 parent: /* parent process gets here (if we forked) */
2670 if (mode == 0) { /* argument to fork */
Eric Andersencb57d552001-06-28 07:25:16 +00002671 exitstatus = waitforjob(jp);
Eric Andersencb57d552001-06-28 07:25:16 +00002672 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002673 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00002674
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002675 out:
Eric Andersencb57d552001-06-28 07:25:16 +00002676 if (lastarg)
2677 setvar("_", lastarg, 0);
2678 popstackmark(&smark);
2679}
2680
Eric Andersen62483552001-07-10 06:09:16 +00002681/*
2682 * Evaluate a parse tree. The value is left in the global variable
2683 * exitstatus.
2684 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002685static void evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00002686{
2687 int checkexit = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002688
Eric Andersen62483552001-07-10 06:09:16 +00002689 if (n == NULL) {
2690 TRACE(("evaltree(NULL) called\n"));
2691 goto out;
2692 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002693 TRACE(("evaltree(0x%lx: %d) called\n", (long) n, n->type));
Eric Andersen62483552001-07-10 06:09:16 +00002694 switch (n->type) {
2695 case NSEMI:
2696 evaltree(n->nbinary.ch1, flags & EV_TESTED);
2697 if (evalskip)
2698 goto out;
2699 evaltree(n->nbinary.ch2, flags);
2700 break;
2701 case NAND:
2702 evaltree(n->nbinary.ch1, EV_TESTED);
2703 if (evalskip || exitstatus != 0)
2704 goto out;
2705 evaltree(n->nbinary.ch2, flags);
2706 break;
2707 case NOR:
2708 evaltree(n->nbinary.ch1, EV_TESTED);
2709 if (evalskip || exitstatus == 0)
2710 goto out;
2711 evaltree(n->nbinary.ch2, flags);
2712 break;
2713 case NREDIR:
2714 expredir(n->nredir.redirect);
2715 redirect(n->nredir.redirect, REDIR_PUSH);
2716 evaltree(n->nredir.n, flags);
2717 popredir();
2718 break;
2719 case NSUBSHELL:
2720 evalsubshell(n, flags);
2721 break;
2722 case NBACKGND:
2723 evalsubshell(n, flags);
2724 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002725 case NIF:{
Eric Andersen62483552001-07-10 06:09:16 +00002726 evaltree(n->nif.test, EV_TESTED);
2727 if (evalskip)
2728 goto out;
2729 if (exitstatus == 0)
2730 evaltree(n->nif.ifpart, flags);
2731 else if (n->nif.elsepart)
2732 evaltree(n->nif.elsepart, flags);
2733 else
2734 exitstatus = 0;
2735 break;
2736 }
2737 case NWHILE:
2738 case NUNTIL:
2739 evalloop(n, flags);
2740 break;
2741 case NFOR:
2742 evalfor(n, flags);
2743 break;
2744 case NCASE:
2745 evalcase(n, flags);
2746 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002747 case NDEFUN:{
Eric Andersen62483552001-07-10 06:09:16 +00002748 struct builtincmd *bcmd;
2749 struct cmdentry entry;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002750
2751 if ((bcmd = find_builtin(n->narg.text)) && IS_BUILTIN_SPECIAL(bcmd)
2752 ) {
Eric Andersen62483552001-07-10 06:09:16 +00002753 out2fmt("%s is a special built-in\n", n->narg.text);
2754 exitstatus = 1;
2755 break;
2756 }
2757 entry.cmdtype = CMDFUNCTION;
2758 entry.u.func = copyfunc(n->narg.next);
2759 addcmdentry(n->narg.text, &entry);
2760 exitstatus = 0;
2761 break;
2762 }
2763 case NNOT:
2764 evaltree(n->nnot.com, EV_TESTED);
2765 exitstatus = !exitstatus;
2766 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002767
Eric Andersen62483552001-07-10 06:09:16 +00002768 case NPIPE:
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002769 evalpipe(n, flags);
Eric Andersen62483552001-07-10 06:09:16 +00002770 checkexit = 1;
2771 break;
2772 case NCMD:
2773 evalcommand(n, flags);
2774 checkexit = 1;
2775 break;
2776#ifdef DEBUG
2777 default:
2778 printf("Node type = %d\n", n->type);
2779 break;
2780#endif
2781 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002782 out:
Eric Andersen62483552001-07-10 06:09:16 +00002783 if (pendingsigs)
2784 dotrap();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002785 if (flags & EV_EXIT ||
Eric Andersen62483552001-07-10 06:09:16 +00002786 (checkexit && eflag && exitstatus && !(flags & EV_TESTED))
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002787 )
Eric Andersen62483552001-07-10 06:09:16 +00002788 exitshell(exitstatus);
2789}
2790
2791/*
2792 * Kick off a subshell to evaluate a tree.
2793 */
2794
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002795static void evalsubshell(const union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00002796{
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002797 struct job *jp = 0;
Eric Andersen62483552001-07-10 06:09:16 +00002798 int backgnd = (n->type == NBACKGND);
2799
2800 expredir(n->nredir.redirect);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002801 if (!backgnd && flags & EV_EXIT && !trap[0])
2802 goto nofork;
2803 INTOFF;
Eric Andersen62483552001-07-10 06:09:16 +00002804 jp = makejob(n, 1);
2805 if (forkshell(jp, n, backgnd) == 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002806 INTON;
2807 flags |= EV_EXIT;
Eric Andersen62483552001-07-10 06:09:16 +00002808 if (backgnd)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002809 flags &= ~EV_TESTED;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002810 nofork:
Eric Andersen62483552001-07-10 06:09:16 +00002811 redirect(n->nredir.redirect, 0);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002812 evaltree(n->nredir.n, flags); /* never returns */
Eric Andersen62483552001-07-10 06:09:16 +00002813 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002814 if (!backgnd) {
Eric Andersen62483552001-07-10 06:09:16 +00002815 exitstatus = waitforjob(jp);
Eric Andersen62483552001-07-10 06:09:16 +00002816 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002817 INTON;
Eric Andersen62483552001-07-10 06:09:16 +00002818}
2819
2820/*
2821 * Compute the names of the files in a redirection list.
2822 */
2823
2824static void fixredir(union node *n, const char *text, int err);
2825
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002826static void expredir(union node *n)
Eric Andersen62483552001-07-10 06:09:16 +00002827{
2828 union node *redir;
2829
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002830 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersen62483552001-07-10 06:09:16 +00002831 struct arglist fn;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002832
Eric Andersen62483552001-07-10 06:09:16 +00002833 fn.lastp = &fn.list;
2834 oexitstatus = exitstatus;
2835 switch (redir->type) {
2836 case NFROMTO:
2837 case NFROM:
2838 case NTO:
2839 case NAPPEND:
2840 case NTOOV:
2841 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
2842 redir->nfile.expfname = fn.list->text;
2843 break;
2844 case NFROMFD:
2845 case NTOFD:
2846 if (redir->ndup.vname) {
2847 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
2848 fixredir(redir, fn.list->text, 1);
2849 }
2850 break;
2851 }
2852 }
2853}
2854
2855
2856/*
2857 * Execute a command inside back quotes. If it's a builtin command, we
2858 * want to save its output in a block obtained from malloc. Otherwise
2859 * we fork off a subprocess and get the output of the command via a pipe.
2860 * Should be called with interrupts off.
2861 */
2862
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002863static void evalbackcmd(union node *n, struct backcmd *result)
Eric Andersen62483552001-07-10 06:09:16 +00002864{
2865 int pip[2];
2866 struct job *jp;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002867 struct stackmark smark; /* unnecessary */
Eric Andersen62483552001-07-10 06:09:16 +00002868
2869 setstackmark(&smark);
2870 result->fd = -1;
2871 result->buf = NULL;
2872 result->nleft = 0;
2873 result->jp = NULL;
2874 if (n == NULL) {
2875 exitstatus = 0;
2876 goto out;
2877 }
2878 exitstatus = 0;
2879 if (pipe(pip) < 0)
2880 error("Pipe call failed");
2881 jp = makejob(n, 1);
2882 if (forkshell(jp, n, FORK_NOJOB) == 0) {
2883 FORCEINTON;
2884 close(pip[0]);
2885 if (pip[1] != 1) {
2886 close(1);
2887 dup_as_newfd(pip[1], 1);
2888 close(pip[1]);
2889 }
2890 eflag = 0;
2891 evaltree(n, EV_EXIT);
2892 }
2893 close(pip[1]);
2894 result->fd = pip[0];
2895 result->jp = jp;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002896 out:
Eric Andersen62483552001-07-10 06:09:16 +00002897 popstackmark(&smark);
2898 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002899 result->fd, result->buf, result->nleft, result->jp));
Eric Andersen62483552001-07-10 06:09:16 +00002900}
2901
2902
2903/*
2904 * Execute a simple command.
2905 */
Eric Andersencb57d552001-06-28 07:25:16 +00002906
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002907/*
2908 * Search for a command. This is called before we fork so that the
2909 * location of the command will be available in the parent as well as
2910 * the child. The check for "goodname" is an overly conservative
2911 * check that the name will not be subject to expansion.
2912 */
2913
2914static void prehash(union node *n)
2915{
2916 struct cmdentry entry;
2917
2918 if (n->type == NCMD && n->ncmd.args)
2919 if (goodname(n->ncmd.args->narg.text))
2920 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
2921}
2922
Eric Andersencb57d552001-06-28 07:25:16 +00002923
Eric Andersencb57d552001-06-28 07:25:16 +00002924/*
2925 * Builtin commands. Builtin commands whose functions are closely
2926 * tied to evaluation are implemented here.
2927 */
2928
2929/*
2930 * No command given, or a bltin command with no arguments. Set the
2931 * specified variables.
2932 */
2933
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002934int bltincmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002935{
2936 /*
2937 * Preserve exitstatus of a previous possible redirection
2938 * as POSIX mandates
2939 */
2940 return exitstatus;
2941}
2942
2943
2944/*
2945 * Handle break and continue commands. Break, continue, and return are
2946 * all handled by setting the evalskip flag. The evaluation routines
2947 * above all check this flag, and if it is set they start skipping
2948 * commands rather than executing them. The variable skipcount is
2949 * the number of loops to break/continue, or the number of function
2950 * levels to return. (The latter is always 1.) It should probably
2951 * be an error to break out of more loops than exist, but it isn't
2952 * in the standard shell so we don't make it one here.
2953 */
2954
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002955static int breakcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002956{
2957 int n = argc > 1 ? number(argv[1]) : 1;
2958
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00002959 if (n <= 0)
2960 error("Illegal number: %s", argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00002961 if (n > loopnest)
2962 n = loopnest;
2963 if (n > 0) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002964 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00002965 skipcount = n;
2966 }
2967 return 0;
2968}
2969
2970
2971/*
2972 * The return command.
2973 */
2974
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002975static int returncmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002976{
2977 int ret = argc > 1 ? number(argv[1]) : oexitstatus;
2978
2979 if (funcnest) {
2980 evalskip = SKIPFUNC;
2981 skipcount = 1;
2982 return ret;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002983 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00002984 /* Do what ksh does; skip the rest of the file */
2985 evalskip = SKIPFILE;
2986 skipcount = 1;
2987 return ret;
2988 }
2989}
2990
2991
Eric Andersen69a20f02001-10-31 10:40:37 +00002992#ifndef CONFIG_FALSE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002993static int false_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002994{
2995 return 1;
2996}
Eric Andersen69a20f02001-10-31 10:40:37 +00002997#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002998
Eric Andersen69a20f02001-10-31 10:40:37 +00002999#ifndef CONFIG_TRUE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003000static int true_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003001{
3002 return 0;
3003}
3004#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003005
3006/*
3007 * Controls whether the shell is interactive or not.
3008 */
3009
3010static void setsignal(int signo);
Eric Andersen2870d962001-07-02 17:27:21 +00003011
Eric Andersend35c5df2002-01-09 15:37:36 +00003012#ifdef CONFIG_ASH_MAIL
Eric Andersenec074692001-10-31 11:05:49 +00003013static void chkmail(int silent);
3014#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003015
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003016static void setinteractive(int on)
Eric Andersen2870d962001-07-02 17:27:21 +00003017{
3018 static int is_interactive;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003019 static int do_banner = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00003020
3021 if (on == is_interactive)
3022 return;
3023 setsignal(SIGINT);
3024 setsignal(SIGQUIT);
3025 setsignal(SIGTERM);
Eric Andersend35c5df2002-01-09 15:37:36 +00003026#ifdef CONFIG_ASH_MAIL
Eric Andersen2870d962001-07-02 17:27:21 +00003027 chkmail(1);
Eric Andersenec074692001-10-31 11:05:49 +00003028#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003029 is_interactive = on;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003030 if (do_banner == 0 && is_interactive) {
Eric Andersen1c039232001-07-07 00:05:55 +00003031 /* Looks like they want an interactive shell */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003032#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
3033 printf("\n\n" BB_BANNER " Built-in shell (ash)\n");
3034 printf("Enter 'help' for a list of built-in commands.\n\n");
Eric Andersend63dee42001-10-19 00:22:23 +00003035#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003036 do_banner = 1;
Eric Andersen1c039232001-07-07 00:05:55 +00003037 }
Eric Andersen2870d962001-07-02 17:27:21 +00003038}
3039
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003040static void optschanged(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003041{
3042 setinteractive(iflag);
3043 setjobctl(mflag);
3044}
3045
Eric Andersencb57d552001-06-28 07:25:16 +00003046
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003047static int execcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003048{
3049 if (argc > 1) {
3050 struct strlist *sp;
3051
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003052 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003053 mflag = 0;
3054 optschanged();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003055 for (sp = cmdenviron; sp; sp = sp->next)
3056 setvareq(sp->text, VEXPORT | VSTACK);
Eric Andersencb57d552001-06-28 07:25:16 +00003057 shellexec(argv + 1, environment(), pathval(), 0);
3058 }
3059 return 0;
3060}
3061
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003062static void eprintlist(struct strlist *sp)
Eric Andersencb57d552001-06-28 07:25:16 +00003063{
3064 for (; sp; sp = sp->next) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003065 out2fmt(" %s", sp->text);
Eric Andersencb57d552001-06-28 07:25:16 +00003066 }
3067}
Eric Andersencb57d552001-06-28 07:25:16 +00003068
3069/*
3070 * Exec a program. Never returns. If you change this routine, you may
3071 * have to change the find_command routine as well.
3072 */
3073
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003074static const char *pathopt; /* set by padvance */
Eric Andersen2870d962001-07-02 17:27:21 +00003075
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003076static void shellexec(char **argv, char **envp, const char *path, int idx)
Eric Andersencb57d552001-06-28 07:25:16 +00003077{
3078 char *cmdname;
3079 int e;
3080
Eric Andersenbf8bf102002-09-17 08:41:08 +00003081 if (strchr(argv[0], '/') != NULL
3082#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3083 || find_applet_by_name(argv[0])
3084#endif
3085 )
3086 {
Eric Andersencb57d552001-06-28 07:25:16 +00003087 tryexec(argv[0], argv, envp);
3088 e = errno;
3089 } else {
3090 e = ENOENT;
3091 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3092 if (--idx < 0 && pathopt == NULL) {
3093 tryexec(cmdname, argv, envp);
3094 if (errno != ENOENT && errno != ENOTDIR)
3095 e = errno;
3096 }
3097 stunalloc(cmdname);
3098 }
3099 }
3100
3101 /* Map to POSIX errors */
3102 switch (e) {
3103 case EACCES:
3104 exerrno = 126;
3105 break;
3106 case ENOENT:
3107 exerrno = 127;
3108 break;
3109 default:
3110 exerrno = 2;
3111 break;
3112 }
3113 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3114 /* NOTREACHED */
3115}
3116
Eric Andersen2870d962001-07-02 17:27:21 +00003117/*
3118 * Clear traps on a fork.
3119 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003120static void clear_traps(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003121{
Eric Andersen2870d962001-07-02 17:27:21 +00003122 char **tp;
3123
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003124 for (tp = trap; tp < &trap[NSIG]; tp++) {
3125 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
Eric Andersen2870d962001-07-02 17:27:21 +00003126 INTOFF;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00003127 free(*tp);
Eric Andersen2870d962001-07-02 17:27:21 +00003128 *tp = NULL;
3129 if (tp != &trap[0])
3130 setsignal(tp - trap);
3131 INTON;
3132 }
3133 }
3134}
3135
3136
Eric Andersen2870d962001-07-02 17:27:21 +00003137static int preadbuffer(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003138static void pushfile(void);
Eric Andersen2870d962001-07-02 17:27:21 +00003139
3140/*
3141 * Read a character from the script, returning PEOF on end of file.
3142 * Nul characters in the input are silently discarded.
3143 */
3144
Eric Andersend35c5df2002-01-09 15:37:36 +00003145#ifndef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Eric Andersen2870d962001-07-02 17:27:21 +00003146#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003147static int pgetc(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003148{
3149 return pgetc_macro();
3150}
3151#else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003152static int pgetc_macro(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003153{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003154 return --parsenleft >= 0 ? *parsenextc++ : preadbuffer();
Eric Andersen2870d962001-07-02 17:27:21 +00003155}
3156
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003157static inline int pgetc(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003158{
3159 return pgetc_macro();
3160}
3161#endif
3162
3163
3164/*
3165 * Undo the last call to pgetc. Only one character may be pushed back.
3166 * PEOF may be pushed back.
3167 */
3168
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003169static void pungetc(void)
Eric Andersen74400cc2001-10-18 04:11:39 +00003170{
Eric Andersen2870d962001-07-02 17:27:21 +00003171 parsenleft++;
3172 parsenextc--;
3173}
3174
3175
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003176static void popfile(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003177{
Eric Andersen2870d962001-07-02 17:27:21 +00003178 struct parsefile *pf = parsefile;
3179
3180 INTOFF;
3181 if (pf->fd >= 0)
3182 close(pf->fd);
Aaron Lehmann49c024a2002-08-02 06:39:47 +00003183 free(pf->buf);
Eric Andersen2870d962001-07-02 17:27:21 +00003184 while (pf->strpush)
3185 popstring();
3186 parsefile = pf->prev;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00003187 free(pf);
Eric Andersen2870d962001-07-02 17:27:21 +00003188 parsenleft = parsefile->nleft;
3189 parselleft = parsefile->lleft;
3190 parsenextc = parsefile->nextc;
3191 plinno = parsefile->linno;
3192 INTON;
3193}
3194
3195
3196/*
3197 * Return to top level.
3198 */
3199
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003200static void popallfiles(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003201{
Eric Andersen2870d962001-07-02 17:27:21 +00003202 while (parsefile != &basepf)
3203 popfile();
3204}
3205
3206/*
3207 * Close the file(s) that the shell is reading commands from. Called
3208 * after a fork is done.
3209 */
3210
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003211static void closescript(void)
Eric Andersen74400cc2001-10-18 04:11:39 +00003212{
Eric Andersen2870d962001-07-02 17:27:21 +00003213 popallfiles();
3214 if (parsefile->fd > 0) {
3215 close(parsefile->fd);
3216 parsefile->fd = 0;
3217 }
3218}
3219
3220
3221/*
3222 * Like setinputfile, but takes an open file descriptor. Call this with
3223 * interrupts off.
3224 */
3225
Eric Andersen74400cc2001-10-18 04:11:39 +00003226static void setinputfd(int fd, int push)
Eric Andersen2870d962001-07-02 17:27:21 +00003227{
3228 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
3229 if (push) {
3230 pushfile();
3231 parsefile->buf = 0;
3232 } else {
3233 closescript();
3234 while (parsefile->strpush)
3235 popstring();
3236 }
3237 parsefile->fd = fd;
3238 if (parsefile->buf == NULL)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003239 parsefile->buf = xmalloc(BUFSIZ);
Eric Andersen2870d962001-07-02 17:27:21 +00003240 parselleft = parsenleft = 0;
3241 plinno = 1;
3242}
3243
3244
3245/*
3246 * Set the input to take input from a file. If push is set, push the
3247 * old input onto the stack first.
3248 */
3249
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003250static void setinputfile(const char *fname, int push)
Eric Andersen2870d962001-07-02 17:27:21 +00003251{
3252 int fd;
3253 int myfileno2;
3254
3255 INTOFF;
3256 if ((fd = open(fname, O_RDONLY)) < 0)
3257 error("Can't open %s", fname);
3258 if (fd < 10) {
3259 myfileno2 = dup_as_newfd(fd, 10);
3260 close(fd);
3261 if (myfileno2 < 0)
3262 error("Out of file descriptors");
3263 fd = myfileno2;
3264 }
3265 setinputfd(fd, push);
3266 INTON;
3267}
3268
Eric Andersencb57d552001-06-28 07:25:16 +00003269
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003270static void tryexec(char *cmd, char **argv, char **envp)
Eric Andersen62483552001-07-10 06:09:16 +00003271{
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003272 int repeated = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003273
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003274#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Eric Andersen3102ac42001-07-06 04:26:23 +00003275 char *name = cmd;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003276 char **argv_l = argv;
Eric Andersen3102ac42001-07-06 04:26:23 +00003277 int argc_l;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003278
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003279#ifdef CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
Eric Andersen3102ac42001-07-06 04:26:23 +00003280 name = get_last_path_component(name);
3281#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003282 argv_l = envp;
3283 for (argc_l = 0; *argv_l != NULL; argv_l++, argc_l++)
Eric Andersen3102ac42001-07-06 04:26:23 +00003284 putenv(*argv_l);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003285 argv_l = argv;
3286 for (argc_l = 0; *argv_l != NULL; argv_l++, argc_l++)
3287 optind = 1;
Eric Andersen3102ac42001-07-06 04:26:23 +00003288 run_applet_by_name(name, argc_l, argv);
3289#endif
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003290 repeat:
Eric Andersencb57d552001-06-28 07:25:16 +00003291 execve(cmd, argv, envp);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003292 if (repeated++) {
3293 free(argv);
3294 } else if (errno == ENOEXEC) {
3295 char **ap;
3296 char **new;
3297
3298 for (ap = argv; *ap; ap++);
3299 ap = new = xmalloc((ap - argv + 2) * sizeof(char *));
3300 *ap++ = cmd = "/bin/sh";
3301 while ((*ap++ = *argv++));
3302 argv = new;
3303 goto repeat;
Eric Andersencb57d552001-06-28 07:25:16 +00003304 }
Eric Andersencb57d552001-06-28 07:25:16 +00003305}
3306
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003307static char *commandtext(const union node *);
Eric Andersencb57d552001-06-28 07:25:16 +00003308
3309/*
3310 * Do a path search. The variable path (passed by reference) should be
3311 * set to the start of the path before the first call; padvance will update
3312 * this value as it proceeds. Successive calls to padvance will return
3313 * the possible path expansions in sequence. If an option (indicated by
3314 * a percent sign) appears in the path entry then the global variable
3315 * pathopt will be set to point to it; otherwise pathopt will be set to
3316 * NULL.
3317 */
3318
3319static const char *pathopt;
3320
Eric Andersen2870d962001-07-02 17:27:21 +00003321static void growstackblock(void);
3322
3323
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003324static char *padvance(const char **path, const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003325{
Eric Andersencb57d552001-06-28 07:25:16 +00003326 const char *p;
3327 char *q;
3328 const char *start;
3329 int len;
3330
3331 if (*path == NULL)
3332 return NULL;
3333 start = *path;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003334 for (p = start; *p && *p != ':' && *p != '%'; p++);
3335 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003336 while (stackblocksize() < len)
3337 growstackblock();
3338 q = stackblock();
3339 if (p != start) {
3340 memcpy(q, start, p - start);
3341 q += p - start;
3342 *q++ = '/';
3343 }
3344 strcpy(q, name);
3345 pathopt = NULL;
3346 if (*p == '%') {
3347 pathopt = ++p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003348 while (*p && *p != ':')
3349 p++;
Eric Andersencb57d552001-06-28 07:25:16 +00003350 }
3351 if (*p == ':')
3352 *path = p + 1;
3353 else
3354 *path = NULL;
3355 return stalloc(len);
3356}
3357
Eric Andersen62483552001-07-10 06:09:16 +00003358/*
3359 * Wrapper around strcmp for qsort/bsearch/...
3360 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003361static int pstrcmp(const void *a, const void *b)
Eric Andersen62483552001-07-10 06:09:16 +00003362{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003363 return strcmp((const char *) a, (*(const char *const *) b) + 1);
Eric Andersen62483552001-07-10 06:09:16 +00003364}
3365
3366/*
3367 * Find a keyword is in a sorted array.
3368 */
3369
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003370static const char *const *findkwd(const char *s)
Eric Andersen62483552001-07-10 06:09:16 +00003371{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003372 return bsearch(s, tokname_array + KWDOFFSET,
3373 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
3374 sizeof(const char *), pstrcmp);
Eric Andersen62483552001-07-10 06:09:16 +00003375}
Eric Andersencb57d552001-06-28 07:25:16 +00003376
3377
3378/*** Command hashing code ***/
3379
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003380static int hashcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003381{
3382 struct tblentry **pp;
3383 struct tblentry *cmdp;
3384 int c;
3385 int verbose;
3386 struct cmdentry entry;
3387 char *name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003388
Eric Andersend35c5df2002-01-09 15:37:36 +00003389#ifdef CONFIG_ASH_ALIAS
Eric Andersen62483552001-07-10 06:09:16 +00003390 const struct alias *ap;
3391#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003392
3393 verbose = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003394 while ((c = nextopt("rvV")) != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00003395 if (c == 'r') {
3396 clearcmdentry(0);
3397 return 0;
Eric Andersen62483552001-07-10 06:09:16 +00003398 } else if (c == 'v' || c == 'V') {
3399 verbose = c;
Eric Andersencb57d552001-06-28 07:25:16 +00003400 }
3401 }
3402 if (*argptr == NULL) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003403 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
3404 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00003405 if (cmdp->cmdtype != CMDBUILTIN) {
3406 printentry(cmdp, verbose);
3407 }
3408 }
3409 }
3410 return 0;
3411 }
3412 c = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003413 while ((name = *argptr++) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00003414 if ((cmdp = cmdlookup(name, 0)) != NULL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003415 && (cmdp->cmdtype == CMDNORMAL
3416 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
Eric Andersencb57d552001-06-28 07:25:16 +00003417 delete_cmd_entry();
Eric Andersend35c5df2002-01-09 15:37:36 +00003418#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003419 /* Then look at the aliases */
Eric Andersenec074692001-10-31 11:05:49 +00003420 if ((ap = *__lookupalias(name)) != NULL) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003421 if (verbose == 'v')
Eric Andersen62483552001-07-10 06:09:16 +00003422 printf("%s is an alias for %s\n", name, ap->val);
3423 else
3424 printalias(ap);
3425 continue;
3426 }
3427#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003428 /* First look at the keywords */
3429 if (findkwd(name) != 0) {
3430 if (verbose == 'v')
Eric Andersen62483552001-07-10 06:09:16 +00003431 printf("%s is a shell keyword\n", name);
3432 else
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003433 puts(name);
Eric Andersen62483552001-07-10 06:09:16 +00003434 continue;
3435 }
3436
Eric Andersencb57d552001-06-28 07:25:16 +00003437 find_command(name, &entry, DO_ERR, pathval());
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003438 if (entry.cmdtype == CMDUNKNOWN)
3439 c = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00003440 else if (verbose) {
3441 cmdp = cmdlookup(name, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003442 if (cmdp)
3443 printentry(cmdp, verbose == 'v');
Eric Andersencb57d552001-06-28 07:25:16 +00003444 flushall();
3445 }
Eric Andersencb57d552001-06-28 07:25:16 +00003446 }
3447 return c;
3448}
3449
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003450static void printentry(struct tblentry *cmdp, int verbose)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003451{
Eric Andersencb57d552001-06-28 07:25:16 +00003452 int idx;
3453 const char *path;
3454 char *name;
3455
Eric Andersen62483552001-07-10 06:09:16 +00003456 printf("%s%s", cmdp->cmdname, (verbose ? " is " : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00003457 if (cmdp->cmdtype == CMDNORMAL) {
3458 idx = cmdp->param.index;
3459 path = pathval();
3460 do {
3461 name = padvance(&path, cmdp->cmdname);
3462 stunalloc(name);
3463 } while (--idx >= 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003464 if (verbose)
Eric Andersen62483552001-07-10 06:09:16 +00003465 out1str(name);
Eric Andersencb57d552001-06-28 07:25:16 +00003466 } else if (cmdp->cmdtype == CMDBUILTIN) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003467 if (verbose)
Eric Andersen62483552001-07-10 06:09:16 +00003468 out1str("a shell builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00003469 } else if (cmdp->cmdtype == CMDFUNCTION) {
Eric Andersencb57d552001-06-28 07:25:16 +00003470 if (verbose) {
3471 INTOFF;
Eric Andersen62483552001-07-10 06:09:16 +00003472 out1str("a function\n");
Eric Andersencb57d552001-06-28 07:25:16 +00003473 name = commandtext(cmdp->param.func);
Eric Andersen62483552001-07-10 06:09:16 +00003474 printf("%s() {\n %s\n}", cmdp->cmdname, name);
Aaron Lehmann49c024a2002-08-02 06:39:47 +00003475 free(name);
Eric Andersencb57d552001-06-28 07:25:16 +00003476 INTON;
3477 }
3478#ifdef DEBUG
3479 } else {
3480 error("internal error: cmdtype %d", cmdp->cmdtype);
3481#endif
3482 }
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003483 puts(cmdp->rehash ? "*" : nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +00003484}
3485
3486
3487
Eric Andersen1c039232001-07-07 00:05:55 +00003488/*** List the available builtins ***/
3489
3490
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003491static int helpcmd(int argc, char **argv)
Eric Andersen1c039232001-07-07 00:05:55 +00003492{
3493 int col, i;
Eric Andersen1c039232001-07-07 00:05:55 +00003494
Eric Andersen62483552001-07-10 06:09:16 +00003495 printf("\nBuilt-in commands:\n-------------------\n");
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003496 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
Eric Andersen62483552001-07-10 06:09:16 +00003497 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003498 builtincmds[i].name + 1);
Eric Andersen1c039232001-07-07 00:05:55 +00003499 if (col > 60) {
3500 printf("\n");
3501 col = 0;
3502 }
3503 }
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003504#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Eric Andersen1c039232001-07-07 00:05:55 +00003505 {
Eric Andersen1c039232001-07-07 00:05:55 +00003506 extern const struct BB_applet applets[];
3507 extern const size_t NUM_APPLETS;
3508
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003509 for (i = 0; i < NUM_APPLETS; i++) {
Eric Andersen62483552001-07-10 06:09:16 +00003510
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003511 col += printf("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
Eric Andersen1c039232001-07-07 00:05:55 +00003512 if (col > 60) {
3513 printf("\n");
3514 col = 0;
3515 }
3516 }
3517 }
3518#endif
3519 printf("\n\n");
3520 return EXIT_SUCCESS;
3521}
3522
Eric Andersencb57d552001-06-28 07:25:16 +00003523/*
3524 * Resolve a command name. If you change this routine, you may have to
3525 * change the shellexec routine as well.
3526 */
3527
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003528static int prefix(const char *, const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00003529
Eric Andersencb57d552001-06-28 07:25:16 +00003530static void
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003531find_command(const char *name, struct cmdentry *entry, int act,
3532 const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003533{
3534 struct tblentry *cmdp;
3535 int idx;
3536 int prev;
3537 char *fullname;
3538 struct stat statb;
3539 int e;
3540 int bltin;
3541 int firstchange;
3542 int updatetbl;
Eric Andersen62483552001-07-10 06:09:16 +00003543 int regular;
Eric Andersencb57d552001-06-28 07:25:16 +00003544 struct builtincmd *bcmd;
3545
3546 /* If name contains a slash, don't use the hash table */
3547 if (strchr(name, '/') != NULL) {
3548 if (act & DO_ABS) {
3549 while (stat(name, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003550 if (errno != ENOENT && errno != ENOTDIR)
3551 e = errno;
3552 entry->cmdtype = CMDUNKNOWN;
3553 entry->u.index = -1;
3554 return;
3555 }
3556 entry->cmdtype = CMDNORMAL;
3557 entry->u.index = -1;
3558 return;
3559 }
3560 entry->cmdtype = CMDNORMAL;
3561 entry->u.index = 0;
3562 return;
3563 }
3564
Eric Andersenbf8bf102002-09-17 08:41:08 +00003565#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3566 if (find_applet_by_name(name)) {
3567 entry->cmdtype = CMDNORMAL;
3568 entry->u.index = -1;
3569 return;
3570 }
3571#endif
3572
Eric Andersencb57d552001-06-28 07:25:16 +00003573 updatetbl = 1;
3574 if (act & DO_BRUTE) {
3575 firstchange = path_change(path, &bltin);
3576 } else {
3577 bltin = builtinloc;
3578 firstchange = 9999;
3579 }
3580
3581 /* If name is in the table, and not invalidated by cd, we're done */
3582 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
3583 if (cmdp->cmdtype == CMDFUNCTION) {
3584 if (act & DO_NOFUN) {
3585 updatetbl = 0;
3586 } else {
3587 goto success;
3588 }
3589 } else if (act & DO_BRUTE) {
3590 if ((cmdp->cmdtype == CMDNORMAL &&
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003591 cmdp->param.index >= firstchange) ||
3592 (cmdp->cmdtype == CMDBUILTIN &&
3593 ((builtinloc < 0 && bltin >= 0) ?
3594 bltin : builtinloc) >= firstchange)) {
Eric Andersencb57d552001-06-28 07:25:16 +00003595 /* need to recompute the entry */
3596 } else {
3597 goto success;
3598 }
3599 } else {
3600 goto success;
3601 }
3602 }
3603
3604 bcmd = find_builtin(name);
Eric Andersen2870d962001-07-02 17:27:21 +00003605 regular = bcmd && IS_BUILTIN_REGULAR(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00003606
3607 if (regular) {
3608 if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) {
Eric Andersen2870d962001-07-02 17:27:21 +00003609 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003610 }
3611 } else if (act & DO_BRUTE) {
3612 if (firstchange == 0) {
3613 updatetbl = 0;
3614 }
3615 }
3616
3617 /* If %builtin not in path, check for builtin next */
3618 if (regular || (bltin < 0 && bcmd)) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003619 builtin:
Eric Andersencb57d552001-06-28 07:25:16 +00003620 if (!updatetbl) {
3621 entry->cmdtype = CMDBUILTIN;
3622 entry->u.cmd = bcmd;
3623 return;
3624 }
3625 INTOFF;
3626 cmdp = cmdlookup(name, 1);
3627 cmdp->cmdtype = CMDBUILTIN;
3628 cmdp->param.cmd = bcmd;
3629 INTON;
3630 goto success;
3631 }
3632
3633 /* We have to search path. */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003634 prev = -1; /* where to start */
3635 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00003636 if (cmdp->cmdtype == CMDBUILTIN)
3637 prev = builtinloc;
3638 else
3639 prev = cmdp->param.index;
3640 }
3641
3642 e = ENOENT;
3643 idx = -1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003644 loop:
Eric Andersencb57d552001-06-28 07:25:16 +00003645 while ((fullname = padvance(&path, name)) != NULL) {
3646 stunalloc(fullname);
3647 idx++;
3648 if (idx >= firstchange) {
3649 updatetbl = 0;
3650 }
3651 if (pathopt) {
3652 if (prefix("builtin", pathopt)) {
3653 if ((bcmd = find_builtin(name))) {
3654 goto builtin;
3655 }
3656 continue;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003657 } else if (!(act & DO_NOFUN) && prefix("func", pathopt)) {
Eric Andersencb57d552001-06-28 07:25:16 +00003658 /* handled below */
3659 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003660 continue; /* ignore unimplemented options */
Eric Andersencb57d552001-06-28 07:25:16 +00003661 }
3662 }
3663 /* if rehash, don't redo absolute path names */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003664 if (fullname[0] == '/' && idx <= prev && idx < firstchange) {
Eric Andersencb57d552001-06-28 07:25:16 +00003665 if (idx < prev)
3666 continue;
3667 TRACE(("searchexec \"%s\": no change\n", name));
3668 goto success;
3669 }
3670 while (stat(fullname, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003671 if (errno != ENOENT && errno != ENOTDIR)
3672 e = errno;
3673 goto loop;
3674 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003675 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00003676 if (!S_ISREG(statb.st_mode))
3677 continue;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003678 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00003679 stalloc(strlen(fullname) + 1);
3680 readcmdfile(fullname);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003681 if ((cmdp = cmdlookup(name, 0)) == NULL
3682 || cmdp->cmdtype != CMDFUNCTION)
Eric Andersencb57d552001-06-28 07:25:16 +00003683 error("%s not defined in %s", name, fullname);
3684 stunalloc(fullname);
3685 goto success;
3686 }
Eric Andersencb57d552001-06-28 07:25:16 +00003687 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
3688 /* If we aren't called with DO_BRUTE and cmdp is set, it must
3689 be a function and we're being called with DO_NOFUN */
3690 if (!updatetbl) {
3691 entry->cmdtype = CMDNORMAL;
3692 entry->u.index = idx;
3693 return;
3694 }
3695 INTOFF;
3696 cmdp = cmdlookup(name, 1);
3697 cmdp->cmdtype = CMDNORMAL;
3698 cmdp->param.index = idx;
3699 INTON;
3700 goto success;
3701 }
3702
3703 /* We failed. If there was an entry for this command, delete it */
3704 if (cmdp && updatetbl)
3705 delete_cmd_entry();
3706 if (act & DO_ERR)
Eric Andersen3102ac42001-07-06 04:26:23 +00003707 out2fmt("%s: %s\n", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00003708 entry->cmdtype = CMDUNKNOWN;
3709 return;
3710
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003711 success:
Eric Andersencb57d552001-06-28 07:25:16 +00003712 cmdp->rehash = 0;
3713 entry->cmdtype = cmdp->cmdtype;
3714 entry->u = cmdp->param;
3715}
3716
3717
3718
3719/*
3720 * Search the table of builtin commands.
3721 */
3722
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003723static struct builtincmd *find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00003724{
3725 struct builtincmd *bp;
3726
Eric Andersen2870d962001-07-02 17:27:21 +00003727 bp = bsearch(name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd),
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003728 pstrcmp);
Eric Andersencb57d552001-06-28 07:25:16 +00003729 return bp;
3730}
3731
3732
3733/*
3734 * Called when a cd is done. Marks all commands so the next time they
3735 * are executed they will be rehashed.
3736 */
3737
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003738static void hashcd(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003739{
Eric Andersencb57d552001-06-28 07:25:16 +00003740 struct tblentry **pp;
3741 struct tblentry *cmdp;
3742
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003743 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
3744 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00003745 if (cmdp->cmdtype == CMDNORMAL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003746 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
Eric Andersencb57d552001-06-28 07:25:16 +00003747 cmdp->rehash = 1;
3748 }
3749 }
3750}
3751
3752
3753
3754/*
3755 * Called before PATH is changed. The argument is the new value of PATH;
3756 * pathval() still returns the old value at this point. Called with
3757 * interrupts off.
3758 */
3759
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003760static void changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00003761{
3762 int firstchange;
3763 int bltin;
3764
3765 firstchange = path_change(newval, &bltin);
3766 if (builtinloc < 0 && bltin >= 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003767 builtinloc = bltin; /* zap builtins */
Eric Andersencb57d552001-06-28 07:25:16 +00003768 clearcmdentry(firstchange);
3769 builtinloc = bltin;
Eric Andersen1a923762002-06-06 12:07:28 +00003770 /* Ensure that getenv("PATH") stays current */
3771 setenv("PATH", newval, 1);
Eric Andersencb57d552001-06-28 07:25:16 +00003772}
3773
3774
3775/*
3776 * Clear out command entries. The argument specifies the first entry in
3777 * PATH which has changed.
3778 */
3779
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003780static void clearcmdentry(int firstchange)
Eric Andersencb57d552001-06-28 07:25:16 +00003781{
3782 struct tblentry **tblp;
3783 struct tblentry **pp;
3784 struct tblentry *cmdp;
3785
3786 INTOFF;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003787 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00003788 pp = tblp;
3789 while ((cmdp = *pp) != NULL) {
3790 if ((cmdp->cmdtype == CMDNORMAL &&
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003791 cmdp->param.index >= firstchange)
3792 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= firstchange)) {
Eric Andersencb57d552001-06-28 07:25:16 +00003793 *pp = cmdp->next;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00003794 free(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00003795 } else {
3796 pp = &cmdp->next;
3797 }
3798 }
3799 }
3800 INTON;
3801}
3802
3803
3804/*
Eric Andersencb57d552001-06-28 07:25:16 +00003805 * Locate a command in the command hash table. If "add" is nonzero,
3806 * add the command to the table if it is not already present. The
3807 * variable "lastcmdentry" is set to point to the address of the link
3808 * pointing to the entry, so that delete_cmd_entry can delete the
3809 * entry.
3810 */
3811
Eric Andersen2870d962001-07-02 17:27:21 +00003812static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00003813
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003814static struct tblentry *cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00003815{
3816 int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00003817 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00003818 struct tblentry *cmdp;
3819 struct tblentry **pp;
3820
3821 p = name;
3822 hashval = *p << 4;
3823 while (*p)
3824 hashval += *p++;
3825 hashval &= 0x7FFF;
3826 pp = &cmdtable[hashval % CMDTABLESIZE];
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003827 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00003828 if (equal(cmdp->cmdname, name))
3829 break;
3830 pp = &cmdp->next;
3831 }
3832 if (add && cmdp == NULL) {
3833 INTOFF;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003834 cmdp = *pp = xmalloc(sizeof(struct tblentry) - ARB
3835 + strlen(name) + 1);
Eric Andersencb57d552001-06-28 07:25:16 +00003836 cmdp->next = NULL;
3837 cmdp->cmdtype = CMDUNKNOWN;
3838 cmdp->rehash = 0;
3839 strcpy(cmdp->cmdname, name);
3840 INTON;
3841 }
3842 lastcmdentry = pp;
3843 return cmdp;
3844}
3845
3846/*
3847 * Delete the command entry returned on the last lookup.
3848 */
3849
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003850static void delete_cmd_entry(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003851{
Eric Andersencb57d552001-06-28 07:25:16 +00003852 struct tblentry *cmdp;
3853
3854 INTOFF;
3855 cmdp = *lastcmdentry;
3856 *lastcmdentry = cmdp->next;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00003857 free(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00003858 INTON;
3859}
3860
3861
3862
Eric Andersencb57d552001-06-28 07:25:16 +00003863
3864
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003865static const unsigned char nodesize[26] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003866 ALIGN(sizeof(struct nbinary)),
3867 ALIGN(sizeof(struct ncmd)),
3868 ALIGN(sizeof(struct npipe)),
3869 ALIGN(sizeof(struct nredir)),
3870 ALIGN(sizeof(struct nredir)),
3871 ALIGN(sizeof(struct nredir)),
3872 ALIGN(sizeof(struct nbinary)),
3873 ALIGN(sizeof(struct nbinary)),
3874 ALIGN(sizeof(struct nif)),
3875 ALIGN(sizeof(struct nbinary)),
3876 ALIGN(sizeof(struct nbinary)),
3877 ALIGN(sizeof(struct nfor)),
3878 ALIGN(sizeof(struct ncase)),
3879 ALIGN(sizeof(struct nclist)),
3880 ALIGN(sizeof(struct narg)),
3881 ALIGN(sizeof(struct narg)),
3882 ALIGN(sizeof(struct nfile)),
3883 ALIGN(sizeof(struct nfile)),
3884 ALIGN(sizeof(struct nfile)),
3885 ALIGN(sizeof(struct nfile)),
3886 ALIGN(sizeof(struct nfile)),
3887 ALIGN(sizeof(struct ndup)),
3888 ALIGN(sizeof(struct ndup)),
3889 ALIGN(sizeof(struct nhere)),
3890 ALIGN(sizeof(struct nhere)),
3891 ALIGN(sizeof(struct nnot)),
Eric Andersen62483552001-07-10 06:09:16 +00003892};
Eric Andersencb57d552001-06-28 07:25:16 +00003893
Eric Andersencb57d552001-06-28 07:25:16 +00003894
3895
3896/*
3897 * Delete a function if it exists.
3898 */
3899
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003900static void unsetfunc(char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003901{
Eric Andersencb57d552001-06-28 07:25:16 +00003902 struct tblentry *cmdp;
3903
3904 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
Aaron Lehmann49c024a2002-08-02 06:39:47 +00003905 free(cmdp->param.func);
Eric Andersencb57d552001-06-28 07:25:16 +00003906 delete_cmd_entry();
3907 }
3908}
3909
Eric Andersen2870d962001-07-02 17:27:21 +00003910
3911/*
Eric Andersencb57d552001-06-28 07:25:16 +00003912 * Locate and print what a word is...
3913 */
3914
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003915static int typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003916{
3917 int i;
3918 int err = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003919 char *argv_a[2];
3920
3921 argv_a[1] = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003922
3923 for (i = 1; i < argc; i++) {
Eric Andersen62483552001-07-10 06:09:16 +00003924 argv_a[0] = argv[i];
3925 argptr = argv_a;
3926 optptr = "v";
3927 err |= hashcmd(argc, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00003928 }
3929 return err;
3930}
3931
Eric Andersend35c5df2002-01-09 15:37:36 +00003932#ifdef CONFIG_ASH_CMDCMD
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003933static int commandcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003934{
3935 int c;
3936 int default_path = 0;
3937 int verify_only = 0;
3938 int verbose_verify_only = 0;
3939
3940 while ((c = nextopt("pvV")) != '\0')
3941 switch (c) {
3942 case 'p':
3943 default_path = 1;
3944 break;
3945 case 'v':
3946 verify_only = 1;
3947 break;
3948 case 'V':
3949 verbose_verify_only = 1;
3950 break;
Eric Andersencb57d552001-06-28 07:25:16 +00003951 }
3952
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003953 if (default_path + verify_only + verbose_verify_only > 1 || !*argptr) {
3954 out2str("command [-p] command [arg ...]\n"
Eric Andersen62483552001-07-10 06:09:16 +00003955 "command {-v|-V} command\n");
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003956 return EX_USAGE;
Eric Andersencb57d552001-06-28 07:25:16 +00003957 }
3958
Eric Andersencb57d552001-06-28 07:25:16 +00003959 if (verify_only || verbose_verify_only) {
Eric Andersen62483552001-07-10 06:09:16 +00003960 char *argv_a[2];
3961
3962 argv_a[1] = 0;
3963 argv_a[0] = *argptr;
3964 argptr = argv_a;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003965 optptr = verbose_verify_only ? "v" : "V"; /* reverse special */
Eric Andersen62483552001-07-10 06:09:16 +00003966 return hashcmd(argc, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00003967 }
Eric Andersencb57d552001-06-28 07:25:16 +00003968
3969 return 0;
3970}
Eric Andersen2870d962001-07-02 17:27:21 +00003971#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003972
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003973static int path_change(const char *newval, int *bltin)
Eric Andersencb57d552001-06-28 07:25:16 +00003974{
3975 const char *old, *new;
3976 int idx;
3977 int firstchange;
3978
3979 old = pathval();
3980 new = newval;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003981 firstchange = 9999; /* assume no change */
Eric Andersencb57d552001-06-28 07:25:16 +00003982 idx = 0;
3983 *bltin = -1;
3984 for (;;) {
3985 if (*old != *new) {
3986 firstchange = idx;
3987 if ((*old == '\0' && *new == ':')
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003988 || (*old == ':' && *new == '\0'))
Eric Andersencb57d552001-06-28 07:25:16 +00003989 firstchange++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003990 old = new; /* ignore subsequent differences */
Eric Andersencb57d552001-06-28 07:25:16 +00003991 }
3992 if (*new == '\0')
3993 break;
3994 if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1))
3995 *bltin = idx;
3996 if (*new == ':') {
3997 idx++;
3998 }
3999 new++, old++;
4000 }
4001 if (builtinloc >= 0 && *bltin < 0)
4002 firstchange = 0;
4003 return firstchange;
4004}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004005
Eric Andersencb57d552001-06-28 07:25:16 +00004006/*
4007 * Routines to expand arguments to commands. We have to deal with
4008 * backquotes, shell variables, and file metacharacters.
4009 */
4010/*
4011 * _rmescape() flags
4012 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004013#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4014#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Eric Andersencb57d552001-06-28 07:25:16 +00004015
4016/*
4017 * Structure specifying which parts of the string should be searched
4018 * for IFS characters.
4019 */
4020
4021struct ifsregion {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004022 struct ifsregion *next; /* next region in list */
4023 int begoff; /* offset of start of region */
4024 int endoff; /* offset of end of region */
4025 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004026};
4027
4028
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004029static char *expdest; /* output of current string */
4030static struct nodelist *argbackq; /* list of back quote expressions */
4031static struct ifsregion ifsfirst; /* first struct in list of ifs regions */
4032static struct ifsregion *ifslastp; /* last struct in list */
4033static struct arglist exparg; /* holds expanded arg list */
Eric Andersencb57d552001-06-28 07:25:16 +00004034
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004035static void argstr(char *, int);
4036static char *exptilde(char *, int);
4037static void expbackq(union node *, int, int);
4038static int subevalvar(char *, char *, int, int, int, int, int);
4039static int varisset(char *, int);
4040static void strtodest(const char *, int, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00004041static void varvalue(char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004042static void recordregion(int, int, int);
4043static void removerecordregions(int);
4044static void ifsbreakup(char *, struct arglist *);
4045static void ifsfree(void);
4046static void expandmeta(struct strlist *, int);
4047
Eric Andersen62483552001-07-10 06:09:16 +00004048#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00004049#define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB)
4050#if !defined(GLOB_BROKEN)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00004051static void addglob(const glob_t *);
Eric Andersencb57d552001-06-28 07:25:16 +00004052#endif
4053#endif
Eric Andersen62483552001-07-10 06:09:16 +00004054#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004055static void expmeta(char *, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004056#endif
Eric Andersen62483552001-07-10 06:09:16 +00004057#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004058static struct strlist *expsort(struct strlist *);
4059static struct strlist *msort(struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004060#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004061static int patmatch(char *, char *, int);
4062
Eric Andersen62483552001-07-10 06:09:16 +00004063#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004064static int patmatch2(char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004065#else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004066static int pmatch(char *, char *, int);
4067
Eric Andersencb57d552001-06-28 07:25:16 +00004068#define patmatch2 patmatch
4069#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004070static char *cvtnum(int, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004071
4072/*
4073 * Expand shell variables and backquotes inside a here document.
4074 */
4075
Eric Andersen2870d962001-07-02 17:27:21 +00004076/* arg: the document, fd: where to write the expanded version */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004077static inline void expandhere(union node *arg, int fd)
Eric Andersen2870d962001-07-02 17:27:21 +00004078{
Eric Andersencb57d552001-06-28 07:25:16 +00004079 herefd = fd;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004080 expandarg(arg, (struct arglist *) NULL, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00004081 xwrite(fd, stackblock(), expdest - stackblock());
4082}
4083
4084
4085/*
4086 * Perform variable substitution and command substitution on an argument,
4087 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4088 * perform splitting and file name expansion. When arglist is NULL, perform
4089 * here document expansion.
4090 */
4091
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004092static void expandarg(union node *arg, struct arglist *arglist, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004093{
4094 struct strlist *sp;
4095 char *p;
4096
4097 argbackq = arg->narg.backquote;
4098 STARTSTACKSTR(expdest);
4099 ifsfirst.next = NULL;
4100 ifslastp = NULL;
4101 argstr(arg->narg.text, flag);
4102 if (arglist == NULL) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004103 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004104 }
4105 STPUTC('\0', expdest);
4106 p = grabstackstr(expdest);
4107 exparg.lastp = &exparg.list;
4108 /*
4109 * TODO - EXP_REDIR
4110 */
4111 if (flag & EXP_FULL) {
4112 ifsbreakup(p, &exparg);
4113 *exparg.lastp = NULL;
4114 exparg.lastp = &exparg.list;
4115 expandmeta(exparg.list, flag);
4116 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004117 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
Eric Andersencb57d552001-06-28 07:25:16 +00004118 rmescapes(p);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004119 sp = (struct strlist *) stalloc(sizeof(struct strlist));
Eric Andersencb57d552001-06-28 07:25:16 +00004120 sp->text = p;
4121 *exparg.lastp = sp;
4122 exparg.lastp = &sp->next;
4123 }
4124 ifsfree();
4125 *exparg.lastp = NULL;
4126 if (exparg.list) {
4127 *arglist->lastp = exparg.list;
4128 arglist->lastp = exparg.lastp;
4129 }
4130}
4131
4132
Eric Andersen62483552001-07-10 06:09:16 +00004133/*
4134 * Expand a variable, and return a pointer to the next character in the
4135 * input string.
4136 */
4137
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004138static inline char *evalvar(char *p, int flag)
Eric Andersen62483552001-07-10 06:09:16 +00004139{
4140 int subtype;
4141 int varflags;
4142 char *var;
4143 const char *val;
4144 int patloc;
4145 int c;
4146 int set;
4147 int special;
4148 int startloc;
4149 int varlen;
4150 int easy;
4151 int quotes = flag & (EXP_FULL | EXP_CASE);
4152
4153 varflags = *p++;
4154 subtype = varflags & VSTYPE;
4155 var = p;
4156 special = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004157 if (!is_name(*p))
Eric Andersen62483552001-07-10 06:09:16 +00004158 special = 1;
4159 p = strchr(p, '=') + 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004160 again: /* jump here after setting a variable with ${var=text} */
Eric Andersen62483552001-07-10 06:09:16 +00004161 if (special) {
4162 set = varisset(var, varflags & VSNUL);
4163 val = NULL;
4164 } else {
4165 val = lookupvar(var);
4166 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
4167 val = NULL;
4168 set = 0;
4169 } else
4170 set = 1;
4171 }
4172 varlen = 0;
4173 startloc = expdest - stackblock();
4174 if (set && subtype != VSPLUS) {
4175 /* insert the value of the variable */
4176 if (special) {
4177 varvalue(var, varflags & VSQUOTE, flag);
4178 if (subtype == VSLENGTH) {
4179 varlen = expdest - stackblock() - startloc;
4180 STADJUST(-varlen, expdest);
4181 }
4182 } else {
4183 if (subtype == VSLENGTH) {
4184 varlen = strlen(val);
4185 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004186 strtodest(val,
4187 varflags & VSQUOTE ? DQSYNTAX : BASESYNTAX, quotes);
Eric Andersen62483552001-07-10 06:09:16 +00004188 }
4189 }
4190 }
4191
4192 if (subtype == VSPLUS)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004193 set = !set;
Eric Andersen62483552001-07-10 06:09:16 +00004194
4195 easy = ((varflags & VSQUOTE) == 0 ||
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004196 (*var == '@' && shellparam.nparam != 1));
Eric Andersen62483552001-07-10 06:09:16 +00004197
4198
4199 switch (subtype) {
4200 case VSLENGTH:
4201 expdest = cvtnum(varlen, expdest);
4202 goto record;
4203
4204 case VSNORMAL:
4205 if (!easy)
4206 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004207 record:
4208 recordregion(startloc, expdest - stackblock(), varflags & VSQUOTE);
Eric Andersen62483552001-07-10 06:09:16 +00004209 break;
4210
4211 case VSPLUS:
4212 case VSMINUS:
4213 if (!set) {
4214 argstr(p, flag);
4215 break;
4216 }
4217 if (easy)
4218 goto record;
4219 break;
4220
4221 case VSTRIMLEFT:
4222 case VSTRIMLEFTMAX:
4223 case VSTRIMRIGHT:
4224 case VSTRIMRIGHTMAX:
4225 if (!set)
4226 break;
4227 /*
4228 * Terminate the string and start recording the pattern
4229 * right after it
4230 */
4231 STPUTC('\0', expdest);
4232 patloc = expdest - stackblock();
4233 if (subevalvar(p, NULL, patloc, subtype,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004234 startloc, varflags, quotes) == 0) {
Eric Andersen62483552001-07-10 06:09:16 +00004235 int amount = (expdest - stackblock() - patloc) + 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004236
Eric Andersen62483552001-07-10 06:09:16 +00004237 STADJUST(-amount, expdest);
4238 }
4239 /* Remove any recorded regions beyond start of variable */
4240 removerecordregions(startloc);
4241 goto record;
4242
4243 case VSASSIGN:
4244 case VSQUESTION:
4245 if (!set) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004246 if (subevalvar(p, var, 0, subtype, startloc, varflags, quotes)) {
Eric Andersen62483552001-07-10 06:09:16 +00004247 varflags &= ~VSNUL;
4248 /*
4249 * Remove any recorded regions beyond
4250 * start of variable
4251 */
4252 removerecordregions(startloc);
4253 goto again;
4254 }
4255 break;
4256 }
4257 if (easy)
4258 goto record;
4259 break;
4260
4261#ifdef DEBUG
4262 default:
4263 abort();
4264#endif
4265 }
4266
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004267 if (subtype != VSNORMAL) { /* skip to end of alternative */
Eric Andersen62483552001-07-10 06:09:16 +00004268 int nesting = 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004269
Eric Andersen62483552001-07-10 06:09:16 +00004270 for (;;) {
4271 if ((c = *p++) == CTLESC)
4272 p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004273 else if (c == CTLBACKQ || c == (CTLBACKQ | CTLQUOTE)) {
Eric Andersen62483552001-07-10 06:09:16 +00004274 if (set)
4275 argbackq = argbackq->next;
4276 } else if (c == CTLVAR) {
4277 if ((*p++ & VSTYPE) != VSNORMAL)
4278 nesting++;
4279 } else if (c == CTLENDVAR) {
4280 if (--nesting == 0)
4281 break;
4282 }
4283 }
4284 }
4285 return p;
4286}
4287
Eric Andersencb57d552001-06-28 07:25:16 +00004288
4289/*
4290 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4291 * characters to allow for further processing. Otherwise treat
4292 * $@ like $* since no splitting will be performed.
4293 */
4294
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004295static void argstr(char *p, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004296{
4297 char c;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004298 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
Eric Andersencb57d552001-06-28 07:25:16 +00004299 int firsteq = 1;
4300
4301 if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
4302 p = exptilde(p, flag);
4303 for (;;) {
4304 switch (c = *p++) {
4305 case '\0':
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004306 case CTLENDVAR: /* ??? */
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004307 return;
Eric Andersencb57d552001-06-28 07:25:16 +00004308 case CTLQUOTEMARK:
4309 /* "$@" syntax adherence hack */
4310 if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
4311 break;
4312 if ((flag & EXP_FULL) != 0)
4313 STPUTC(c, expdest);
4314 break;
4315 case CTLESC:
4316 if (quotes)
4317 STPUTC(c, expdest);
4318 c = *p++;
4319 STPUTC(c, expdest);
4320 break;
4321 case CTLVAR:
4322 p = evalvar(p, flag);
4323 break;
4324 case CTLBACKQ:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004325 case CTLBACKQ | CTLQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +00004326 expbackq(argbackq->n, c & CTLQUOTE, flag);
4327 argbackq = argbackq->next;
4328 break;
Eric Andersend35c5df2002-01-09 15:37:36 +00004329#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +00004330 case CTLENDARI:
4331 expari(flag);
4332 break;
Eric Andersen2870d962001-07-02 17:27:21 +00004333#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004334 case ':':
4335 case '=':
4336 /*
4337 * sort of a hack - expand tildes in variable
4338 * assignments (after the first '=' and after ':'s).
4339 */
4340 STPUTC(c, expdest);
4341 if (flag & EXP_VARTILDE && *p == '~') {
4342 if (c == '=') {
4343 if (firsteq)
4344 firsteq = 0;
4345 else
4346 break;
4347 }
4348 p = exptilde(p, flag);
4349 }
4350 break;
4351 default:
4352 STPUTC(c, expdest);
4353 }
4354 }
Eric Andersencb57d552001-06-28 07:25:16 +00004355}
4356
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004357static char *exptilde(char *p, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004358{
4359 char c, *startp = p;
4360 struct passwd *pw;
4361 const char *home;
4362 int quotes = flag & (EXP_FULL | EXP_CASE);
4363
4364 while ((c = *p) != '\0') {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004365 switch (c) {
Eric Andersencb57d552001-06-28 07:25:16 +00004366 case CTLESC:
4367 return (startp);
4368 case CTLQUOTEMARK:
4369 return (startp);
4370 case ':':
4371 if (flag & EXP_VARTILDE)
4372 goto done;
4373 break;
4374 case '/':
4375 goto done;
4376 }
4377 p++;
4378 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004379 done:
Eric Andersencb57d552001-06-28 07:25:16 +00004380 *p = '\0';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004381 if (*(startp + 1) == '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00004382 if ((home = lookupvar("HOME")) == NULL)
4383 goto lose;
4384 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004385 if ((pw = getpwnam(startp + 1)) == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00004386 goto lose;
4387 home = pw->pw_dir;
4388 }
4389 if (*home == '\0')
4390 goto lose;
4391 *p = c;
4392 strtodest(home, SQSYNTAX, quotes);
4393 return (p);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004394 lose:
Eric Andersencb57d552001-06-28 07:25:16 +00004395 *p = c;
4396 return (startp);
4397}
4398
4399
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004400static void removerecordregions(int endoff)
Eric Andersencb57d552001-06-28 07:25:16 +00004401{
4402 if (ifslastp == NULL)
4403 return;
4404
4405 if (ifsfirst.endoff > endoff) {
4406 while (ifsfirst.next != NULL) {
4407 struct ifsregion *ifsp;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004408
Eric Andersencb57d552001-06-28 07:25:16 +00004409 INTOFF;
4410 ifsp = ifsfirst.next->next;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00004411 free(ifsfirst.next);
Eric Andersencb57d552001-06-28 07:25:16 +00004412 ifsfirst.next = ifsp;
4413 INTON;
4414 }
4415 if (ifsfirst.begoff > endoff)
4416 ifslastp = NULL;
4417 else {
4418 ifslastp = &ifsfirst;
4419 ifsfirst.endoff = endoff;
4420 }
4421 return;
4422 }
Eric Andersen2870d962001-07-02 17:27:21 +00004423
Eric Andersencb57d552001-06-28 07:25:16 +00004424 ifslastp = &ifsfirst;
4425 while (ifslastp->next && ifslastp->next->begoff < endoff)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004426 ifslastp = ifslastp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00004427 while (ifslastp->next != NULL) {
4428 struct ifsregion *ifsp;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004429
Eric Andersencb57d552001-06-28 07:25:16 +00004430 INTOFF;
4431 ifsp = ifslastp->next->next;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00004432 free(ifslastp->next);
Eric Andersencb57d552001-06-28 07:25:16 +00004433 ifslastp->next = ifsp;
4434 INTON;
4435 }
4436 if (ifslastp->endoff > endoff)
4437 ifslastp->endoff = endoff;
4438}
4439
4440
Eric Andersend35c5df2002-01-09 15:37:36 +00004441#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +00004442/*
4443 * Expand arithmetic expression. Backup to start of expression,
4444 * evaluate, place result in (backed up) result, adjust string position.
4445 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004446static void expari(int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004447{
4448 char *p, *start;
Eric Andersen34506362001-08-02 05:02:46 +00004449 int errcode;
Eric Andersencb57d552001-06-28 07:25:16 +00004450 int result;
4451 int begoff;
4452 int quotes = flag & (EXP_FULL | EXP_CASE);
4453 int quoted;
4454
Eric Andersen2870d962001-07-02 17:27:21 +00004455 /* ifsfree(); */
Eric Andersencb57d552001-06-28 07:25:16 +00004456
4457 /*
4458 * This routine is slightly over-complicated for
4459 * efficiency. First we make sure there is
4460 * enough space for the result, which may be bigger
4461 * than the expression if we add exponentation. Next we
4462 * scan backwards looking for the start of arithmetic. If the
4463 * next previous character is a CTLESC character, then we
4464 * have to rescan starting from the beginning since CTLESC
4465 * characters have to be processed left to right.
4466 */
4467 CHECKSTRSPACE(10, expdest);
4468 USTPUTC('\0', expdest);
4469 start = stackblock();
4470 p = expdest - 1;
4471 while (*p != CTLARI && p >= start)
4472 --p;
4473 if (*p != CTLARI)
4474 error("missing CTLARI (shouldn't happen)");
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004475 if (p > start && *(p - 1) == CTLESC)
Eric Andersencb57d552001-06-28 07:25:16 +00004476 for (p = start; *p != CTLARI; p++)
4477 if (*p == CTLESC)
4478 p++;
4479
4480 if (p[1] == '"')
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004481 quoted = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00004482 else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004483 quoted = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004484 begoff = p - start;
4485 removerecordregions(begoff);
4486 if (quotes)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004487 rmescapes(p + 2);
4488 result = arith(p + 2, &errcode);
Eric Andersen34506362001-08-02 05:02:46 +00004489 if (errcode < 0) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004490 if (errcode == -2)
Eric Andersen34506362001-08-02 05:02:46 +00004491 error("divide by zero");
4492 else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004493 error("syntax error: \"%s\"\n", p + 2);
Eric Andersen34506362001-08-02 05:02:46 +00004494 }
Eric Andersen3102ac42001-07-06 04:26:23 +00004495 snprintf(p, 12, "%d", result);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004496 while (*p++);
Eric Andersencb57d552001-06-28 07:25:16 +00004497
4498 if (quoted == 0)
4499 recordregion(begoff, p - 1 - start, 0);
4500 result = expdest - p + 1;
4501 STADJUST(-result, expdest);
4502}
Eric Andersen2870d962001-07-02 17:27:21 +00004503#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004504
4505/*
4506 * Expand stuff in backwards quotes.
4507 */
4508
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004509static void expbackq(union node *cmd, int quoted, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004510{
4511 volatile struct backcmd in;
4512 int i;
4513 char buf[128];
4514 char *p;
4515 char *dest = expdest;
4516 volatile struct ifsregion saveifs;
4517 struct ifsregion *volatile savelastp;
4518 struct nodelist *volatile saveargbackq;
4519 char lastc;
4520 int startloc = dest - stackblock();
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004521 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +00004522 volatile int saveherefd;
4523 int quotes = flag & (EXP_FULL | EXP_CASE);
4524 struct jmploc jmploc;
4525 struct jmploc *volatile savehandler;
4526 int ex;
4527
4528#if __GNUC__
4529 /* Avoid longjmp clobbering */
4530 (void) &dest;
4531 (void) &syntax;
4532#endif
4533
4534 in.fd = -1;
4535 in.buf = 0;
4536 in.jp = 0;
4537
4538 INTOFF;
4539 saveifs = ifsfirst;
4540 savelastp = ifslastp;
4541 saveargbackq = argbackq;
4542 saveherefd = herefd;
4543 herefd = -1;
4544 if ((ex = setjmp(jmploc.loc))) {
4545 goto err1;
4546 }
4547 savehandler = handler;
4548 handler = &jmploc;
4549 INTON;
4550 p = grabstackstr(dest);
4551 evalbackcmd(cmd, (struct backcmd *) &in);
4552 ungrabstackstr(p, dest);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004553 err1:
Eric Andersencb57d552001-06-28 07:25:16 +00004554 INTOFF;
4555 ifsfirst = saveifs;
4556 ifslastp = savelastp;
4557 argbackq = saveargbackq;
4558 herefd = saveherefd;
4559 if (ex) {
4560 goto err2;
4561 }
4562
4563 p = in.buf;
4564 lastc = '\0';
4565 for (;;) {
4566 if (--in.nleft < 0) {
4567 if (in.fd < 0)
4568 break;
Eric Andersen7467c8d2001-07-12 20:26:32 +00004569 i = safe_read(in.fd, buf, sizeof buf);
Eric Andersencb57d552001-06-28 07:25:16 +00004570 TRACE(("expbackq: read returns %d\n", i));
4571 if (i <= 0)
4572 break;
4573 p = buf;
4574 in.nleft = i - 1;
4575 }
4576 lastc = *p++;
4577 if (lastc != '\0') {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004578 if (quotes && SIT(lastc, syntax) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +00004579 STPUTC(CTLESC, dest);
4580 STPUTC(lastc, dest);
4581 }
4582 }
4583
4584 /* Eat all trailing newlines */
4585 for (; dest > stackblock() && dest[-1] == '\n';)
4586 STUNPUTC(dest);
4587
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004588 err2:
Eric Andersencb57d552001-06-28 07:25:16 +00004589 if (in.fd >= 0)
4590 close(in.fd);
Aaron Lehmann49c024a2002-08-02 06:39:47 +00004591 free(in.buf);
Eric Andersencb57d552001-06-28 07:25:16 +00004592 if (in.jp)
4593 exitstatus = waitforjob(in.jp);
4594 handler = savehandler;
4595 if (ex) {
4596 longjmp(handler->loc, 1);
4597 }
4598 if (quoted == 0)
4599 recordregion(startloc, dest - stackblock(), 0);
4600 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004601 (dest - stackblock()) - startloc,
4602 (dest - stackblock()) - startloc, stackblock() + startloc));
Eric Andersencb57d552001-06-28 07:25:16 +00004603 expdest = dest;
4604 INTON;
4605}
4606
Eric Andersencb57d552001-06-28 07:25:16 +00004607static int
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004608subevalvar(char *p, char *str, int strloc, int subtype, int startloc,
4609 int varflags, int quotes)
Eric Andersencb57d552001-06-28 07:25:16 +00004610{
4611 char *startp;
4612 char *loc = NULL;
4613 char *q;
4614 int c = 0;
4615 int saveherefd = herefd;
4616 struct nodelist *saveargbackq = argbackq;
4617 int amount;
4618
4619 herefd = -1;
4620 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
4621 STACKSTRNUL(expdest);
4622 herefd = saveherefd;
4623 argbackq = saveargbackq;
4624 startp = stackblock() + startloc;
4625 if (str == NULL)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004626 str = stackblock() + strloc;
Eric Andersencb57d552001-06-28 07:25:16 +00004627
4628 switch (subtype) {
4629 case VSASSIGN:
4630 setvar(str, startp, 0);
4631 amount = startp - expdest;
4632 STADJUST(amount, expdest);
4633 varflags &= ~VSNUL;
4634 if (c != 0)
4635 *loc = c;
4636 return 1;
4637
4638 case VSQUESTION:
4639 if (*p != CTLENDVAR) {
Eric Andersen3102ac42001-07-06 04:26:23 +00004640 out2fmt(snlfmt, startp);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004641 error((char *) NULL);
Eric Andersencb57d552001-06-28 07:25:16 +00004642 }
4643 error("%.*s: parameter %snot set", p - str - 1,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004644 str, (varflags & VSNUL) ? "null or " : nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +00004645 /* NOTREACHED */
4646
4647 case VSTRIMLEFT:
4648 for (loc = startp; loc < str; loc++) {
4649 c = *loc;
4650 *loc = '\0';
4651 if (patmatch2(str, startp, quotes))
4652 goto recordleft;
4653 *loc = c;
4654 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00004655 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00004656 }
4657 return 0;
4658
4659 case VSTRIMLEFTMAX:
4660 for (loc = str - 1; loc >= startp;) {
4661 c = *loc;
4662 *loc = '\0';
4663 if (patmatch2(str, startp, quotes))
4664 goto recordleft;
4665 *loc = c;
4666 loc--;
4667 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
4668 for (q = startp; q < loc; q++)
4669 if (*q == CTLESC)
4670 q++;
4671 if (q > loc)
4672 loc--;
4673 }
4674 }
4675 return 0;
4676
4677 case VSTRIMRIGHT:
Eric Andersen2870d962001-07-02 17:27:21 +00004678 for (loc = str - 1; loc >= startp;) {
Eric Andersencb57d552001-06-28 07:25:16 +00004679 if (patmatch2(str, loc, quotes))
4680 goto recordright;
4681 loc--;
Eric Andersen2870d962001-07-02 17:27:21 +00004682 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
Eric Andersencb57d552001-06-28 07:25:16 +00004683 for (q = startp; q < loc; q++)
4684 if (*q == CTLESC)
4685 q++;
4686 if (q > loc)
4687 loc--;
4688 }
4689 }
4690 return 0;
4691
4692 case VSTRIMRIGHTMAX:
4693 for (loc = startp; loc < str - 1; loc++) {
4694 if (patmatch2(str, loc, quotes))
4695 goto recordright;
4696 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00004697 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00004698 }
4699 return 0;
4700
4701#ifdef DEBUG
4702 default:
4703 abort();
4704#endif
4705 }
4706
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004707 recordleft:
Eric Andersencb57d552001-06-28 07:25:16 +00004708 *loc = c;
4709 amount = ((str - 1) - (loc - startp)) - expdest;
4710 STADJUST(amount, expdest);
4711 while (loc != str - 1)
4712 *startp++ = *loc++;
4713 return 1;
4714
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004715 recordright:
Eric Andersencb57d552001-06-28 07:25:16 +00004716 amount = loc - expdest;
4717 STADJUST(amount, expdest);
4718 STPUTC('\0', expdest);
4719 STADJUST(-1, expdest);
4720 return 1;
4721}
4722
4723
4724/*
Eric Andersencb57d552001-06-28 07:25:16 +00004725 * Test whether a specialized variable is set.
4726 */
4727
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004728static int varisset(char *name, int nulok)
Eric Andersencb57d552001-06-28 07:25:16 +00004729{
4730 if (*name == '!')
4731 return backgndpid != -1;
4732 else if (*name == '@' || *name == '*') {
4733 if (*shellparam.p == NULL)
4734 return 0;
4735
4736 if (nulok) {
4737 char **av;
4738
4739 for (av = shellparam.p; *av; av++)
4740 if (**av != '\0')
4741 return 1;
4742 return 0;
4743 }
4744 } else if (is_digit(*name)) {
4745 char *ap;
4746 int num = atoi(name);
4747
4748 if (num > shellparam.nparam)
4749 return 0;
4750
4751 if (num == 0)
4752 ap = arg0;
4753 else
4754 ap = shellparam.p[num - 1];
4755
4756 if (nulok && (ap == NULL || *ap == '\0'))
4757 return 0;
4758 }
4759 return 1;
4760}
4761
Eric Andersencb57d552001-06-28 07:25:16 +00004762/*
4763 * Put a string on the stack.
4764 */
4765
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004766static void strtodest(const char *p, int syntax, int quotes)
Eric Andersencb57d552001-06-28 07:25:16 +00004767{
4768 while (*p) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004769 if (quotes && SIT(*p, syntax) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +00004770 STPUTC(CTLESC, expdest);
4771 STPUTC(*p++, expdest);
4772 }
4773}
4774
Eric Andersencb57d552001-06-28 07:25:16 +00004775/*
4776 * Add the value of a specialized variable to the stack string.
4777 */
4778
Glenn L McGrath50812ff2002-08-23 13:14:48 +00004779static void varvalue(char *name, int quoted, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00004780{
4781 int num;
4782 char *p;
4783 int i;
4784 int sep;
4785 int sepq = 0;
4786 char **ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004787 int syntax;
Eric Andersencb57d552001-06-28 07:25:16 +00004788 int allow_split = flags & EXP_FULL;
4789 int quotes = flags & (EXP_FULL | EXP_CASE);
4790
4791 syntax = quoted ? DQSYNTAX : BASESYNTAX;
4792 switch (*name) {
4793 case '$':
4794 num = rootpid;
4795 goto numvar;
4796 case '?':
4797 num = oexitstatus;
4798 goto numvar;
4799 case '#':
4800 num = shellparam.nparam;
4801 goto numvar;
4802 case '!':
4803 num = backgndpid;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004804 numvar:
Eric Andersencb57d552001-06-28 07:25:16 +00004805 expdest = cvtnum(num, expdest);
4806 break;
4807 case '-':
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004808 for (i = 0; i < NOPTS; i++) {
Eric Andersen2870d962001-07-02 17:27:21 +00004809 if (optent_val(i))
4810 STPUTC(optent_letter(optlist[i]), expdest);
Eric Andersencb57d552001-06-28 07:25:16 +00004811 }
4812 break;
4813 case '@':
4814 if (allow_split && quoted) {
4815 sep = 1 << CHAR_BIT;
4816 goto param;
4817 }
4818 /* fall through */
4819 case '*':
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004820 sep = ifsset()? ifsval()[0] : ' ';
Eric Andersencb57d552001-06-28 07:25:16 +00004821 if (quotes) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004822 sepq = SIT(sep, syntax) == CCTL;
Eric Andersencb57d552001-06-28 07:25:16 +00004823 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004824 param:
4825 for (ap = shellparam.p; (p = *ap++) != NULL;) {
Eric Andersencb57d552001-06-28 07:25:16 +00004826 strtodest(p, syntax, quotes);
4827 if (*ap && sep) {
4828 if (sepq)
4829 STPUTC(CTLESC, expdest);
4830 STPUTC(sep, expdest);
4831 }
4832 }
4833 break;
4834 case '0':
4835 strtodest(arg0, syntax, quotes);
4836 break;
4837 default:
4838 num = atoi(name);
4839 if (num > 0 && num <= shellparam.nparam) {
4840 strtodest(shellparam.p[num - 1], syntax, quotes);
4841 }
4842 break;
4843 }
4844}
4845
4846
Eric Andersencb57d552001-06-28 07:25:16 +00004847/*
4848 * Record the fact that we have to scan this region of the
4849 * string for IFS characters.
4850 */
4851
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004852static void recordregion(int start, int end, int nulonly)
Eric Andersencb57d552001-06-28 07:25:16 +00004853{
4854 struct ifsregion *ifsp;
4855
4856 if (ifslastp == NULL) {
4857 ifsp = &ifsfirst;
4858 } else {
4859 INTOFF;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004860 ifsp = (struct ifsregion *) xmalloc(sizeof(struct ifsregion));
Eric Andersencb57d552001-06-28 07:25:16 +00004861 ifsp->next = NULL;
4862 ifslastp->next = ifsp;
4863 INTON;
4864 }
4865 ifslastp = ifsp;
4866 ifslastp->begoff = start;
4867 ifslastp->endoff = end;
4868 ifslastp->nulonly = nulonly;
4869}
4870
4871
4872
4873/*
4874 * Break the argument string into pieces based upon IFS and add the
4875 * strings to the argument list. The regions of the string to be
4876 * searched for IFS characters have been stored by recordregion.
4877 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004878static void ifsbreakup(char *string, struct arglist *arglist)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004879{
Eric Andersencb57d552001-06-28 07:25:16 +00004880 struct ifsregion *ifsp;
4881 struct strlist *sp;
4882 char *start;
4883 char *p;
4884 char *q;
4885 const char *ifs, *realifs;
4886 int ifsspc;
4887 int nulonly;
4888
4889
4890 start = string;
4891 ifsspc = 0;
4892 nulonly = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004893 realifs = ifsset()? ifsval() : defifs;
Eric Andersencb57d552001-06-28 07:25:16 +00004894 if (ifslastp != NULL) {
4895 ifsp = &ifsfirst;
4896 do {
4897 p = string + ifsp->begoff;
4898 nulonly = ifsp->nulonly;
4899 ifs = nulonly ? nullstr : realifs;
4900 ifsspc = 0;
4901 while (p < string + ifsp->endoff) {
4902 q = p;
4903 if (*p == CTLESC)
4904 p++;
4905 if (strchr(ifs, *p)) {
4906 if (!nulonly)
4907 ifsspc = (strchr(defifs, *p) != NULL);
4908 /* Ignore IFS whitespace at start */
4909 if (q == start && ifsspc) {
4910 p++;
4911 start = p;
4912 continue;
4913 }
4914 *q = '\0';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004915 sp = (struct strlist *) stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00004916 sp->text = start;
4917 *arglist->lastp = sp;
4918 arglist->lastp = &sp->next;
4919 p++;
4920 if (!nulonly) {
4921 for (;;) {
4922 if (p >= string + ifsp->endoff) {
4923 break;
4924 }
4925 q = p;
4926 if (*p == CTLESC)
4927 p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004928 if (strchr(ifs, *p) == NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00004929 p = q;
4930 break;
4931 } else if (strchr(defifs, *p) == NULL) {
4932 if (ifsspc) {
4933 p++;
4934 ifsspc = 0;
4935 } else {
4936 p = q;
4937 break;
4938 }
4939 } else
4940 p++;
4941 }
4942 }
4943 start = p;
4944 } else
4945 p++;
4946 }
4947 } while ((ifsp = ifsp->next) != NULL);
4948 if (!(*start || (!ifsspc && start > string && nulonly))) {
4949 return;
4950 }
4951 }
4952
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004953 sp = (struct strlist *) stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00004954 sp->text = start;
4955 *arglist->lastp = sp;
4956 arglist->lastp = &sp->next;
4957}
4958
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004959static void ifsfree(void)
Eric Andersencb57d552001-06-28 07:25:16 +00004960{
4961 while (ifsfirst.next != NULL) {
4962 struct ifsregion *ifsp;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004963
Eric Andersencb57d552001-06-28 07:25:16 +00004964 INTOFF;
4965 ifsp = ifsfirst.next->next;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00004966 free(ifsfirst.next);
Eric Andersencb57d552001-06-28 07:25:16 +00004967 ifsfirst.next = ifsp;
4968 INTON;
4969 }
4970 ifslastp = NULL;
4971 ifsfirst.next = NULL;
4972}
4973
Eric Andersen2870d962001-07-02 17:27:21 +00004974/*
4975 * Add a file name to the list.
4976 */
Eric Andersencb57d552001-06-28 07:25:16 +00004977
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004978static void addfname(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00004979{
Eric Andersen2870d962001-07-02 17:27:21 +00004980 struct strlist *sp;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00004981 size_t len = strlen(name) + 1;
Eric Andersen2870d962001-07-02 17:27:21 +00004982
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004983 sp = (struct strlist *) stalloc(sizeof *sp);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00004984 sp->text = memcpy(stalloc(len), name, len);
Eric Andersen2870d962001-07-02 17:27:21 +00004985 *exparg.lastp = sp;
4986 exparg.lastp = &sp->next;
4987}
Eric Andersencb57d552001-06-28 07:25:16 +00004988
4989/*
4990 * Expand shell metacharacters. At this point, the only control characters
4991 * should be escapes. The results are stored in the list exparg.
4992 */
4993
Eric Andersen62483552001-07-10 06:09:16 +00004994#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004995static void expandmeta(struct strlist *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004996{
4997 const char *p;
4998 glob_t pglob;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004999
Eric Andersencb57d552001-06-28 07:25:16 +00005000 /* TODO - EXP_REDIR */
5001
5002 while (str) {
5003 if (fflag)
5004 goto nometa;
5005 p = preglob(str->text);
5006 INTOFF;
Eric Andersen34506362001-08-02 05:02:46 +00005007 switch (glob(p, 0, 0, &pglob)) {
Eric Andersencb57d552001-06-28 07:25:16 +00005008 case 0:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005009 if (pglob.gl_pathv[1] == 0 && !strcmp(p, pglob.gl_pathv[0]))
Eric Andersencb57d552001-06-28 07:25:16 +00005010 goto nometa2;
5011 addglob(&pglob);
5012 globfree(&pglob);
5013 INTON;
5014 break;
5015 case GLOB_NOMATCH:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005016 nometa2:
Eric Andersencb57d552001-06-28 07:25:16 +00005017 globfree(&pglob);
5018 INTON;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005019 nometa:
Eric Andersencb57d552001-06-28 07:25:16 +00005020 *exparg.lastp = str;
5021 rmescapes(str->text);
5022 exparg.lastp = &str->next;
5023 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005024 default: /* GLOB_NOSPACE */
Eric Andersencb57d552001-06-28 07:25:16 +00005025 error("Out of space");
5026 }
5027 str = str->next;
5028 }
5029}
5030
5031
5032/*
5033 * Add the result of glob(3) to the list.
5034 */
5035
Glenn L McGrath50812ff2002-08-23 13:14:48 +00005036static void addglob(const glob_t * pglob)
Eric Andersencb57d552001-06-28 07:25:16 +00005037{
5038 char **p = pglob->gl_pathv;
5039
5040 do {
5041 addfname(*p);
5042 } while (*++p);
5043}
5044
5045
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005046#else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005047static char *expdir;
5048
5049
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005050static void expandmeta(struct strlist *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005051{
5052 char *p;
5053 struct strlist **savelastp;
5054 struct strlist *sp;
5055 char c;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005056
Eric Andersencb57d552001-06-28 07:25:16 +00005057 /* TODO - EXP_REDIR */
5058
5059 while (str) {
5060 if (fflag)
5061 goto nometa;
5062 p = str->text;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005063 for (;;) { /* fast check for meta chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005064 if ((c = *p++) == '\0')
5065 goto nometa;
5066 if (c == '*' || c == '?' || c == '[' || c == '!')
5067 break;
5068 }
5069 savelastp = exparg.lastp;
5070 INTOFF;
5071 if (expdir == NULL) {
5072 int i = strlen(str->text);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005073
5074 expdir = xmalloc(i < 2048 ? 2048 : i); /* XXX */
Eric Andersencb57d552001-06-28 07:25:16 +00005075 }
5076
5077 expmeta(expdir, str->text);
Aaron Lehmann49c024a2002-08-02 06:39:47 +00005078 free(expdir);
Eric Andersencb57d552001-06-28 07:25:16 +00005079 expdir = NULL;
5080 INTON;
5081 if (exparg.lastp == savelastp) {
5082 /*
5083 * no matches
5084 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005085 nometa:
Eric Andersencb57d552001-06-28 07:25:16 +00005086 *exparg.lastp = str;
5087 rmescapes(str->text);
5088 exparg.lastp = &str->next;
5089 } else {
5090 *exparg.lastp = NULL;
5091 *savelastp = sp = expsort(*savelastp);
5092 while (sp->next != NULL)
5093 sp = sp->next;
5094 exparg.lastp = &sp->next;
5095 }
5096 str = str->next;
5097 }
5098}
5099
5100
5101/*
5102 * Do metacharacter (i.e. *, ?, [...]) expansion.
5103 */
5104
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005105static void expmeta(char *enddir, char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005106{
Eric Andersencb57d552001-06-28 07:25:16 +00005107 char *p;
5108 const char *cp;
5109 char *q;
5110 char *start;
5111 char *endname;
5112 int metaflag;
5113 struct stat statb;
5114 DIR *dirp;
5115 struct dirent *dp;
5116 int atend;
5117 int matchdot;
5118
5119 metaflag = 0;
5120 start = name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005121 for (p = name;; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +00005122 if (*p == '*' || *p == '?')
5123 metaflag = 1;
5124 else if (*p == '[') {
5125 q = p + 1;
5126 if (*q == '!')
5127 q++;
5128 for (;;) {
5129 while (*q == CTLQUOTEMARK)
5130 q++;
5131 if (*q == CTLESC)
5132 q++;
5133 if (*q == '/' || *q == '\0')
5134 break;
5135 if (*++q == ']') {
5136 metaflag = 1;
5137 break;
5138 }
5139 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005140 } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) {
Eric Andersencb57d552001-06-28 07:25:16 +00005141 metaflag = 1;
5142 } else if (*p == '\0')
5143 break;
5144 else if (*p == CTLQUOTEMARK)
5145 continue;
5146 else if (*p == CTLESC)
5147 p++;
5148 if (*p == '/') {
5149 if (metaflag)
5150 break;
5151 start = p + 1;
5152 }
5153 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005154 if (metaflag == 0) { /* we've reached the end of the file name */
Eric Andersencb57d552001-06-28 07:25:16 +00005155 if (enddir != expdir)
5156 metaflag++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005157 for (p = name;; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +00005158 if (*p == CTLQUOTEMARK)
5159 continue;
5160 if (*p == CTLESC)
5161 p++;
5162 *enddir++ = *p;
5163 if (*p == '\0')
5164 break;
5165 }
5166 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5167 addfname(expdir);
5168 return;
5169 }
5170 endname = p;
5171 if (start != name) {
5172 p = name;
5173 while (p < start) {
5174 while (*p == CTLQUOTEMARK)
5175 p++;
5176 if (*p == CTLESC)
5177 p++;
5178 *enddir++ = *p++;
5179 }
5180 }
5181 if (enddir == expdir) {
5182 cp = ".";
5183 } else if (enddir == expdir + 1 && *expdir == '/') {
5184 cp = "/";
5185 } else {
5186 cp = expdir;
5187 enddir[-1] = '\0';
5188 }
5189 if ((dirp = opendir(cp)) == NULL)
5190 return;
5191 if (enddir != expdir)
5192 enddir[-1] = '/';
5193 if (*endname == 0) {
5194 atend = 1;
5195 } else {
5196 atend = 0;
5197 *endname++ = '\0';
5198 }
5199 matchdot = 0;
5200 p = start;
5201 while (*p == CTLQUOTEMARK)
5202 p++;
5203 if (*p == CTLESC)
5204 p++;
5205 if (*p == '.')
5206 matchdot++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005207 while (!int_pending() && (dp = readdir(dirp)) != NULL) {
5208 if (dp->d_name[0] == '.' && !matchdot)
Eric Andersencb57d552001-06-28 07:25:16 +00005209 continue;
5210 if (patmatch(start, dp->d_name, 0)) {
5211 if (atend) {
Eric Andersen2870d962001-07-02 17:27:21 +00005212 strcpy(enddir, dp->d_name);
Eric Andersencb57d552001-06-28 07:25:16 +00005213 addfname(expdir);
5214 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005215 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
Eric Andersencb57d552001-06-28 07:25:16 +00005216 continue;
5217 p[-1] = '/';
5218 expmeta(p, endname);
5219 }
5220 }
5221 }
5222 closedir(dirp);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005223 if (!atend)
Eric Andersencb57d552001-06-28 07:25:16 +00005224 endname[-1] = '/';
5225}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005226#endif /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005227
5228
Eric Andersencb57d552001-06-28 07:25:16 +00005229
Eric Andersen62483552001-07-10 06:09:16 +00005230#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersencb57d552001-06-28 07:25:16 +00005231/*
5232 * Sort the results of file name expansion. It calculates the number of
5233 * strings to sort and then calls msort (short for merge sort) to do the
5234 * work.
5235 */
5236
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005237static struct strlist *expsort(struct strlist *str)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005238{
Eric Andersencb57d552001-06-28 07:25:16 +00005239 int len;
5240 struct strlist *sp;
5241
5242 len = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005243 for (sp = str; sp; sp = sp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00005244 len++;
5245 return msort(str, len);
5246}
5247
5248
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005249static struct strlist *msort(struct strlist *list, int len)
Eric Andersencb57d552001-06-28 07:25:16 +00005250{
5251 struct strlist *p, *q = NULL;
5252 struct strlist **lpp;
5253 int half;
5254 int n;
5255
5256 if (len <= 1)
5257 return list;
5258 half = len >> 1;
5259 p = list;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005260 for (n = half; --n >= 0;) {
Eric Andersencb57d552001-06-28 07:25:16 +00005261 q = p;
5262 p = p->next;
5263 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005264 q->next = NULL; /* terminate first half of list */
5265 q = msort(list, half); /* sort first half of list */
5266 p = msort(p, len - half); /* sort second half */
Eric Andersencb57d552001-06-28 07:25:16 +00005267 lpp = &list;
5268 for (;;) {
5269 if (strcmp(p->text, q->text) < 0) {
5270 *lpp = p;
5271 lpp = &p->next;
5272 if ((p = *lpp) == NULL) {
5273 *lpp = q;
5274 break;
5275 }
5276 } else {
5277 *lpp = q;
5278 lpp = &q->next;
5279 if ((q = *lpp) == NULL) {
5280 *lpp = p;
5281 break;
5282 }
5283 }
5284 }
5285 return list;
5286}
5287#endif
5288
5289
5290
5291/*
5292 * Returns true if the pattern matches the string.
5293 */
5294
Eric Andersen62483552001-07-10 06:09:16 +00005295#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00005296/* squoted: string might have quote chars */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005297static int patmatch(char *pattern, char *string, int squoted)
Eric Andersen2870d962001-07-02 17:27:21 +00005298{
Eric Andersencb57d552001-06-28 07:25:16 +00005299 const char *p;
5300 char *q;
5301
5302 p = preglob(pattern);
5303 q = squoted ? _rmescapes(string, RMESCAPE_ALLOC) : string;
5304
5305 return !fnmatch(p, q, 0);
5306}
5307
5308
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005309static int patmatch2(char *pattern, char *string, int squoted)
Eric Andersen2870d962001-07-02 17:27:21 +00005310{
Eric Andersencb57d552001-06-28 07:25:16 +00005311 char *p;
5312 int res;
5313
5314 sstrnleft--;
5315 p = grabstackstr(expdest);
5316 res = patmatch(pattern, string, squoted);
5317 ungrabstackstr(p, expdest);
5318 return res;
5319}
5320#else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005321static int patmatch(char *pattern, char *string, int squoted)
5322{
Eric Andersen2870d962001-07-02 17:27:21 +00005323 return pmatch(pattern, string, squoted);
Eric Andersencb57d552001-06-28 07:25:16 +00005324}
5325
5326
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005327static int pmatch(char *pattern, char *string, int squoted)
Eric Andersen2870d962001-07-02 17:27:21 +00005328{
Eric Andersencb57d552001-06-28 07:25:16 +00005329 char *p, *q;
5330 char c;
5331
5332 p = pattern;
5333 q = string;
5334 for (;;) {
5335 switch (c = *p++) {
5336 case '\0':
5337 goto breakloop;
5338 case CTLESC:
5339 if (squoted && *q == CTLESC)
5340 q++;
5341 if (*q++ != *p++)
5342 return 0;
5343 break;
5344 case CTLQUOTEMARK:
5345 continue;
5346 case '?':
5347 if (squoted && *q == CTLESC)
5348 q++;
5349 if (*q++ == '\0')
5350 return 0;
5351 break;
5352 case '*':
5353 c = *p;
5354 while (c == CTLQUOTEMARK || c == '*')
5355 c = *++p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005356 if (c != CTLESC && c != CTLQUOTEMARK &&
5357 c != '?' && c != '*' && c != '[') {
Eric Andersencb57d552001-06-28 07:25:16 +00005358 while (*q != c) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005359 if (squoted && *q == CTLESC && q[1] == c)
Eric Andersencb57d552001-06-28 07:25:16 +00005360 break;
5361 if (*q == '\0')
5362 return 0;
5363 if (squoted && *q == CTLESC)
5364 q++;
5365 q++;
5366 }
5367 }
5368 do {
5369 if (pmatch(p, q, squoted))
5370 return 1;
5371 if (squoted && *q == CTLESC)
5372 q++;
5373 } while (*q++ != '\0');
5374 return 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005375 case '[':{
Eric Andersencb57d552001-06-28 07:25:16 +00005376 char *endp;
5377 int invert, found;
5378 char chr;
5379
5380 endp = p;
5381 if (*endp == '!')
5382 endp++;
5383 for (;;) {
5384 while (*endp == CTLQUOTEMARK)
5385 endp++;
5386 if (*endp == '\0')
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005387 goto dft; /* no matching ] */
Eric Andersencb57d552001-06-28 07:25:16 +00005388 if (*endp == CTLESC)
5389 endp++;
5390 if (*++endp == ']')
5391 break;
5392 }
5393 invert = 0;
5394 if (*p == '!') {
5395 invert++;
5396 p++;
5397 }
5398 found = 0;
5399 chr = *q++;
5400 if (squoted && chr == CTLESC)
5401 chr = *q++;
5402 if (chr == '\0')
5403 return 0;
5404 c = *p++;
5405 do {
5406 if (c == CTLQUOTEMARK)
5407 continue;
5408 if (c == CTLESC)
5409 c = *p++;
5410 if (*p == '-' && p[1] != ']') {
5411 p++;
5412 while (*p == CTLQUOTEMARK)
5413 p++;
5414 if (*p == CTLESC)
5415 p++;
5416 if (chr >= c && chr <= *p)
5417 found = 1;
5418 p++;
5419 } else {
5420 if (chr == c)
5421 found = 1;
5422 }
5423 } while ((c = *p++) != ']');
5424 if (found == invert)
5425 return 0;
5426 break;
5427 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005428 dft: default:
Eric Andersencb57d552001-06-28 07:25:16 +00005429 if (squoted && *q == CTLESC)
5430 q++;
5431 if (*q++ != c)
5432 return 0;
5433 break;
5434 }
5435 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005436 breakloop:
Eric Andersencb57d552001-06-28 07:25:16 +00005437 if (*q != '\0')
5438 return 0;
5439 return 1;
5440}
5441#endif
5442
5443
5444
5445/*
5446 * Remove any CTLESC characters from a string.
5447 */
5448
Eric Andersen62483552001-07-10 06:09:16 +00005449#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005450static char *_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005451{
5452 char *p, *q, *r;
5453 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5454
5455 p = strpbrk(str, qchars);
5456 if (!p) {
5457 return str;
5458 }
5459 q = p;
5460 r = str;
5461 if (flag & RMESCAPE_ALLOC) {
5462 size_t len = p - str;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005463
Eric Andersencb57d552001-06-28 07:25:16 +00005464 q = r = stalloc(strlen(p) + len + 1);
5465 if (len > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00005466 memcpy(q, str, len);
5467 q += len;
Eric Andersencb57d552001-06-28 07:25:16 +00005468 }
5469 }
5470 while (*p) {
5471 if (*p == CTLQUOTEMARK) {
5472 p++;
5473 continue;
5474 }
5475 if (*p == CTLESC) {
5476 p++;
5477 if (flag & RMESCAPE_GLOB && *p != '/') {
5478 *q++ = '\\';
5479 }
5480 }
5481 *q++ = *p++;
5482 }
5483 *q = '\0';
5484 return r;
5485}
5486#else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005487static void rmescapes(char *str)
Eric Andersencb57d552001-06-28 07:25:16 +00005488{
5489 char *p, *q;
5490
5491 p = str;
5492 while (*p != CTLESC && *p != CTLQUOTEMARK) {
5493 if (*p++ == '\0')
5494 return;
5495 }
5496 q = p;
5497 while (*p) {
5498 if (*p == CTLQUOTEMARK) {
5499 p++;
5500 continue;
5501 }
5502 if (*p == CTLESC)
5503 p++;
5504 *q++ = *p++;
5505 }
5506 *q = '\0';
5507}
5508#endif
5509
5510
5511
5512/*
5513 * See if a pattern matches in a case statement.
5514 */
5515
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005516static int casematch(union node *pattern, const char *val)
Eric Andersen2870d962001-07-02 17:27:21 +00005517{
Eric Andersencb57d552001-06-28 07:25:16 +00005518 struct stackmark smark;
5519 int result;
5520 char *p;
5521
5522 setstackmark(&smark);
5523 argbackq = pattern->narg.backquote;
5524 STARTSTACKSTR(expdest);
5525 ifslastp = NULL;
5526 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5527 STPUTC('\0', expdest);
5528 p = grabstackstr(expdest);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005529 result = patmatch(p, (char *) val, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00005530 popstackmark(&smark);
5531 return result;
5532}
5533
5534/*
5535 * Our own itoa().
5536 */
5537
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005538static char *cvtnum(int num, char *buf)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005539{
Eric Andersencb57d552001-06-28 07:25:16 +00005540 int len;
5541
5542 CHECKSTRSPACE(32, buf);
5543 len = sprintf(buf, "%d", num);
5544 STADJUST(len, buf);
5545 return buf;
5546}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005547
Eric Andersencb57d552001-06-28 07:25:16 +00005548/*
5549 * Editline and history functions (and glue).
5550 */
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005551static int histcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00005552{
5553 error("not compiled with history support");
5554 /* NOTREACHED */
5555}
5556
5557
Eric Andersencb57d552001-06-28 07:25:16 +00005558struct redirtab {
5559 struct redirtab *next;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005560 short renamed[10]; /* Current ash support only 0-9 descriptors */
Eric Andersen34506362001-08-02 05:02:46 +00005561 /* char on arm (and others) can't be negative */
Eric Andersencb57d552001-06-28 07:25:16 +00005562};
5563
Eric Andersen2870d962001-07-02 17:27:21 +00005564static struct redirtab *redirlist;
Eric Andersencb57d552001-06-28 07:25:16 +00005565
5566extern char **environ;
5567
5568
5569
5570/*
5571 * Initialization code.
5572 */
5573
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005574static void init(void)
5575{
Eric Andersencb57d552001-06-28 07:25:16 +00005576
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005577 /* from cd.c: */
5578 {
5579 curdir = nullstr;
5580 setpwd(0, 0);
5581 }
Eric Andersencb57d552001-06-28 07:25:16 +00005582
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005583 /* from input.c: */
5584 {
5585 basepf.nextc = basepf.buf = basebuf;
5586 }
Eric Andersencb57d552001-06-28 07:25:16 +00005587
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005588 /* from var.c: */
5589 {
5590 char **envp;
5591 char ppid[32];
Eric Andersencb57d552001-06-28 07:25:16 +00005592
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005593 initvar();
5594 for (envp = environ; *envp; envp++) {
5595 if (strchr(*envp, '=')) {
5596 setvareq(*envp, VEXPORT | VTEXTFIXED);
5597 }
5598 }
Eric Andersencb57d552001-06-28 07:25:16 +00005599
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005600 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
5601 setvar("PPID", ppid, 0);
5602 }
Eric Andersencb57d552001-06-28 07:25:16 +00005603}
5604
5605
5606
5607/*
5608 * This routine is called when an error or an interrupt occurs in an
5609 * interactive shell and control is returned to the main command loop.
5610 */
5611
Eric Andersen2870d962001-07-02 17:27:21 +00005612/* 1 == check for aliases, 2 == also check for assignments */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005613static int checkalias; /* also used in no alias mode for check assignments */
Eric Andersen2870d962001-07-02 17:27:21 +00005614
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005615static void reset(void)
5616{
Eric Andersencb57d552001-06-28 07:25:16 +00005617
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005618 /* from eval.c: */
5619 {
5620 evalskip = 0;
5621 loopnest = 0;
5622 funcnest = 0;
5623 }
Eric Andersencb57d552001-06-28 07:25:16 +00005624
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005625 /* from input.c: */
5626 {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00005627 parselleft = parsenleft = 0; /* clear input buffer */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005628 popallfiles();
5629 }
Eric Andersencb57d552001-06-28 07:25:16 +00005630
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005631 /* from parser.c: */
5632 {
5633 tokpushback = 0;
5634 checkkwd = 0;
5635 checkalias = 0;
5636 }
Eric Andersencb57d552001-06-28 07:25:16 +00005637
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005638 /* from redir.c: */
5639 {
5640 while (redirlist)
5641 popredir();
5642 }
Eric Andersencb57d552001-06-28 07:25:16 +00005643
Eric Andersencb57d552001-06-28 07:25:16 +00005644}
5645
5646
5647
5648/*
Eric Andersencb57d552001-06-28 07:25:16 +00005649 * This file implements the input routines used by the parser.
5650 */
5651
Eric Andersenbdfd0d72001-10-24 05:00:29 +00005652#ifdef CONFIG_FEATURE_COMMAND_EDITING
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005653static const char *cmdedit_prompt;
5654static inline void putprompt(const char *s)
5655{
5656 cmdedit_prompt = s;
Eric Andersencb57d552001-06-28 07:25:16 +00005657}
5658#else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005659static inline void putprompt(const char *s)
5660{
5661 out2str(s);
Eric Andersencb57d552001-06-28 07:25:16 +00005662}
5663#endif
5664
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005665#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
Eric Andersencb57d552001-06-28 07:25:16 +00005666
Eric Andersencb57d552001-06-28 07:25:16 +00005667
Eric Andersencb57d552001-06-28 07:25:16 +00005668
Eric Andersen2870d962001-07-02 17:27:21 +00005669/*
5670 * Same as pgetc(), but ignores PEOA.
5671 */
Eric Andersencb57d552001-06-28 07:25:16 +00005672
Eric Andersend35c5df2002-01-09 15:37:36 +00005673#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005674static int pgetc2(void)
Eric Andersen2870d962001-07-02 17:27:21 +00005675{
5676 int c;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005677
Eric Andersen2870d962001-07-02 17:27:21 +00005678 do {
5679 c = pgetc_macro();
5680 } while (c == PEOA);
5681 return c;
Eric Andersencb57d552001-06-28 07:25:16 +00005682}
Eric Andersen2870d962001-07-02 17:27:21 +00005683#else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005684static inline int pgetc2(void)
5685{
5686 return pgetc_macro();
5687}
Eric Andersencb57d552001-06-28 07:25:16 +00005688#endif
5689
Eric Andersencb57d552001-06-28 07:25:16 +00005690/*
5691 * Read a line from the script.
5692 */
5693
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005694static inline char *pfgets(char *line, int len)
Eric Andersencb57d552001-06-28 07:25:16 +00005695{
5696 char *p = line;
5697 int nleft = len;
5698 int c;
5699
5700 while (--nleft > 0) {
5701 c = pgetc2();
5702 if (c == PEOF) {
5703 if (p == line)
5704 return NULL;
5705 break;
5706 }
5707 *p++ = c;
5708 if (c == '\n')
5709 break;
5710 }
5711 *p = '\0';
5712 return line;
5713}
5714
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005715static inline int preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005716{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005717 int nr;
5718 char *buf = parsefile->buf;
Eric Andersencb57d552001-06-28 07:25:16 +00005719
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005720 parsenextc = buf;
5721
5722 retry:
Eric Andersenbdfd0d72001-10-24 05:00:29 +00005723#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersencb57d552001-06-28 07:25:16 +00005724 {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005725 if (!iflag || parsefile->fd)
5726 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
5727 else {
5728 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
5729 }
Eric Andersencb57d552001-06-28 07:25:16 +00005730 }
5731#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00005732 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00005733#endif
5734
5735 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00005736 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
5737 int flags = fcntl(0, F_GETFL, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005738
Eric Andersencb57d552001-06-28 07:25:16 +00005739 if (flags >= 0 && flags & O_NONBLOCK) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005740 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00005741 if (fcntl(0, F_SETFL, flags) >= 0) {
5742 out2str("sh: turning off NDELAY mode\n");
5743 goto retry;
5744 }
5745 }
5746 }
5747 }
5748 return nr;
5749}
5750
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005751static void popstring(void)
Eric Andersen2870d962001-07-02 17:27:21 +00005752{
5753 struct strpush *sp = parsefile->strpush;
5754
5755 INTOFF;
Eric Andersend35c5df2002-01-09 15:37:36 +00005756#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00005757 if (sp->ap) {
5758 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
5759 if (!checkalias) {
5760 checkalias = 1;
5761 }
5762 }
5763 if (sp->string != sp->ap->val) {
Aaron Lehmann49c024a2002-08-02 06:39:47 +00005764 free(sp->string);
Eric Andersen2870d962001-07-02 17:27:21 +00005765 }
5766
5767 sp->ap->flag &= ~ALIASINUSE;
5768 if (sp->ap->flag & ALIASDEAD) {
5769 unalias(sp->ap->name);
5770 }
5771 }
5772#endif
5773 parsenextc = sp->prevstring;
5774 parsenleft = sp->prevnleft;
5775/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
5776 parsefile->strpush = sp->prev;
5777 if (sp != &(parsefile->basestrpush))
Aaron Lehmann49c024a2002-08-02 06:39:47 +00005778 free(sp);
Eric Andersen2870d962001-07-02 17:27:21 +00005779 INTON;
5780}
5781
5782
Eric Andersencb57d552001-06-28 07:25:16 +00005783/*
5784 * Refill the input buffer and return the next input character:
5785 *
5786 * 1) If a string was pushed back on the input, pop it;
5787 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
5788 * from a string so we can't refill the buffer, return EOF.
5789 * 3) If the is more stuff in this buffer, use it else call read to fill it.
5790 * 4) Process input up to the next newline, deleting nul characters.
5791 */
5792
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005793static int preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005794{
5795 char *p, *q;
5796 int more;
5797 char savec;
5798
5799 while (parsefile->strpush) {
Eric Andersend35c5df2002-01-09 15:37:36 +00005800#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00005801 if (parsenleft == -1 && parsefile->strpush->ap &&
5802 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00005803 return PEOA;
5804 }
Eric Andersen2870d962001-07-02 17:27:21 +00005805#endif
Eric Andersencb57d552001-06-28 07:25:16 +00005806 popstring();
5807 if (--parsenleft >= 0)
5808 return (*parsenextc++);
5809 }
5810 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
5811 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00005812 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00005813
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005814 again:
Eric Andersencb57d552001-06-28 07:25:16 +00005815 if (parselleft <= 0) {
5816 if ((parselleft = preadfd()) <= 0) {
5817 parselleft = parsenleft = EOF_NLEFT;
5818 return PEOF;
5819 }
5820 }
5821
5822 q = p = parsenextc;
5823
5824 /* delete nul characters */
5825 for (more = 1; more;) {
5826 switch (*p) {
5827 case '\0':
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005828 p++; /* Skip nul */
Eric Andersencb57d552001-06-28 07:25:16 +00005829 goto check;
5830
5831
5832 case '\n':
5833 parsenleft = q - parsenextc;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005834 more = 0; /* Stop processing here */
Eric Andersencb57d552001-06-28 07:25:16 +00005835 break;
5836 }
5837
5838 *q++ = *p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005839 check:
Eric Andersencb57d552001-06-28 07:25:16 +00005840 if (--parselleft <= 0 && more) {
5841 parsenleft = q - parsenextc - 1;
5842 if (parsenleft < 0)
5843 goto again;
5844 more = 0;
5845 }
5846 }
5847
5848 savec = *q;
5849 *q = '\0';
5850
5851 if (vflag) {
5852 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00005853 }
5854
5855 *q = savec;
5856
5857 return *parsenextc++;
5858}
5859
Eric Andersencb57d552001-06-28 07:25:16 +00005860
5861/*
5862 * Push a string back onto the input at this current parsefile level.
5863 * We handle aliases this way.
5864 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005865static void pushstring(char *s, int len, void *ap)
Eric Andersen2870d962001-07-02 17:27:21 +00005866{
Eric Andersencb57d552001-06-28 07:25:16 +00005867 struct strpush *sp;
5868
5869 INTOFF;
5870/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
5871 if (parsefile->strpush) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005872 sp = xmalloc(sizeof(struct strpush));
Eric Andersencb57d552001-06-28 07:25:16 +00005873 sp->prev = parsefile->strpush;
5874 parsefile->strpush = sp;
5875 } else
5876 sp = parsefile->strpush = &(parsefile->basestrpush);
5877 sp->prevstring = parsenextc;
5878 sp->prevnleft = parsenleft;
Eric Andersend35c5df2002-01-09 15:37:36 +00005879#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005880 sp->ap = (struct alias *) ap;
Eric Andersencb57d552001-06-28 07:25:16 +00005881 if (ap) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005882 ((struct alias *) ap)->flag |= ALIASINUSE;
Eric Andersencb57d552001-06-28 07:25:16 +00005883 sp->string = s;
5884 }
Eric Andersen2870d962001-07-02 17:27:21 +00005885#endif
Eric Andersencb57d552001-06-28 07:25:16 +00005886 parsenextc = s;
5887 parsenleft = len;
5888 INTON;
5889}
5890
Eric Andersencb57d552001-06-28 07:25:16 +00005891
Eric Andersencb57d552001-06-28 07:25:16 +00005892/*
5893 * Like setinputfile, but takes input from a string.
5894 */
5895
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005896static void setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +00005897{
Eric Andersencb57d552001-06-28 07:25:16 +00005898 INTOFF;
5899 pushfile();
5900 parsenextc = string;
5901 parsenleft = strlen(string);
5902 parsefile->buf = NULL;
5903 plinno = 1;
5904 INTON;
5905}
5906
5907
5908
5909/*
5910 * To handle the "." command, a stack of input files is used. Pushfile
5911 * adds a new entry to the stack and popfile restores the previous level.
5912 */
5913
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005914static void pushfile(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005915{
Eric Andersencb57d552001-06-28 07:25:16 +00005916 struct parsefile *pf;
5917
5918 parsefile->nleft = parsenleft;
5919 parsefile->lleft = parselleft;
5920 parsefile->nextc = parsenextc;
5921 parsefile->linno = plinno;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005922 pf = (struct parsefile *) xmalloc(sizeof(struct parsefile));
Eric Andersencb57d552001-06-28 07:25:16 +00005923 pf->prev = parsefile;
5924 pf->fd = -1;
5925 pf->strpush = NULL;
5926 pf->basestrpush.prev = NULL;
5927 parsefile = pf;
5928}
5929
Eric Andersend35c5df2002-01-09 15:37:36 +00005930#ifdef CONFIG_ASH_JOB_CONTROL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005931static void restartjob(struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00005932#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005933static void freejob(struct job *);
5934static struct job *getjob(const char *);
5935static int dowait(int, struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00005936
5937
Eric Andersen2870d962001-07-02 17:27:21 +00005938/*
5939 * We keep track of whether or not fd0 has been redirected. This is for
5940 * background commands, where we want to redirect fd0 to /dev/null only
5941 * if it hasn't already been redirected.
5942*/
5943static int fd0_redirected = 0;
5944
5945/* Return true if fd 0 has already been redirected at least once. */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005946static inline int fd0_redirected_p(void)
Eric Andersen74400cc2001-10-18 04:11:39 +00005947{
Eric Andersen2870d962001-07-02 17:27:21 +00005948 return fd0_redirected != 0;
5949}
5950
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005951static void dupredirect(const union node *, int, int fd1dup);
Eric Andersen2870d962001-07-02 17:27:21 +00005952
Eric Andersend35c5df2002-01-09 15:37:36 +00005953#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00005954/*
5955 * Turn job control on and off.
5956 *
5957 * Note: This code assumes that the third arg to ioctl is a character
5958 * pointer, which is true on Berkeley systems but not System V. Since
5959 * System V doesn't have job control yet, this isn't a problem now.
5960 */
5961
Eric Andersen2870d962001-07-02 17:27:21 +00005962
Eric Andersencb57d552001-06-28 07:25:16 +00005963
5964static void setjobctl(int enable)
5965{
Eric Andersencb57d552001-06-28 07:25:16 +00005966 if (enable == jobctl || rootshell == 0)
5967 return;
5968 if (enable) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005969 do { /* while we are in the background */
Eric Andersen3102ac42001-07-06 04:26:23 +00005970 initialpgrp = tcgetpgrp(2);
Eric Andersencb57d552001-06-28 07:25:16 +00005971 if (initialpgrp < 0) {
Eric Andersen8c145dc2001-07-10 16:57:09 +00005972 out2str("sh: can't access tty; job control turned off\n");
Eric Andersencb57d552001-06-28 07:25:16 +00005973 mflag = 0;
5974 return;
5975 }
5976 if (initialpgrp == -1)
5977 initialpgrp = getpgrp();
5978 else if (initialpgrp != getpgrp()) {
5979 killpg(initialpgrp, SIGTTIN);
5980 continue;
5981 }
5982 } while (0);
Eric Andersencb57d552001-06-28 07:25:16 +00005983 setsignal(SIGTSTP);
5984 setsignal(SIGTTOU);
5985 setsignal(SIGTTIN);
5986 setpgid(0, rootpid);
Eric Andersen3102ac42001-07-06 04:26:23 +00005987 tcsetpgrp(2, rootpid);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005988 } else { /* turning job control off */
Eric Andersencb57d552001-06-28 07:25:16 +00005989 setpgid(0, initialpgrp);
Eric Andersen3102ac42001-07-06 04:26:23 +00005990 tcsetpgrp(2, initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00005991 setsignal(SIGTSTP);
5992 setsignal(SIGTTOU);
5993 setsignal(SIGTTIN);
5994 }
5995 jobctl = enable;
5996}
5997#endif
5998
5999
Eric Andersend35c5df2002-01-09 15:37:36 +00006000#ifdef CONFIG_ASH_JOB_CONTROL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006001static int killcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006002{
6003 int signo = -1;
6004 int list = 0;
6005 int i;
6006 pid_t pid;
6007 struct job *jp;
6008
6009 if (argc <= 1) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006010 usage:
6011 error
6012 ("Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6013 "kill -l [exitstatus]");
Eric Andersencb57d552001-06-28 07:25:16 +00006014 }
6015
6016 if (*argv[1] == '-') {
6017 signo = decode_signal(argv[1] + 1, 1);
6018 if (signo < 0) {
6019 int c;
6020
6021 while ((c = nextopt("ls:")) != '\0')
6022 switch (c) {
6023 case 'l':
6024 list = 1;
6025 break;
6026 case 's':
6027 signo = decode_signal(optionarg, 1);
6028 if (signo < 0) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006029 error("invalid signal number or name: %s", optionarg);
Eric Andersencb57d552001-06-28 07:25:16 +00006030 }
Eric Andersen2870d962001-07-02 17:27:21 +00006031 break;
Eric Andersencb57d552001-06-28 07:25:16 +00006032#ifdef DEBUG
6033 default:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006034 error("nextopt returned character code 0%o", c);
Eric Andersencb57d552001-06-28 07:25:16 +00006035#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006036 }
Eric Andersencb57d552001-06-28 07:25:16 +00006037 } else
6038 argptr++;
6039 }
6040
6041 if (!list && signo < 0)
6042 signo = SIGTERM;
6043
6044 if ((signo < 0 || !*argptr) ^ list) {
6045 goto usage;
6046 }
6047
6048 if (list) {
Eric Andersen34506362001-08-02 05:02:46 +00006049 const char *name;
6050
Eric Andersencb57d552001-06-28 07:25:16 +00006051 if (!*argptr) {
6052 out1str("0\n");
6053 for (i = 1; i < NSIG; i++) {
Eric Andersen34506362001-08-02 05:02:46 +00006054 name = u_signal_names(0, &i, 1);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006055 if (name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006056 puts(name);
Eric Andersencb57d552001-06-28 07:25:16 +00006057 }
6058 return 0;
6059 }
Eric Andersen34506362001-08-02 05:02:46 +00006060 name = u_signal_names(*argptr, &signo, -1);
6061 if (name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006062 puts(name);
Eric Andersencb57d552001-06-28 07:25:16 +00006063 else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006064 error("invalid signal number or exit status: %s", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006065 return 0;
6066 }
6067
6068 do {
6069 if (**argptr == '%') {
6070 jp = getjob(*argptr);
6071 if (jp->jobctl == 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006072 error("job %s not created under job control", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006073 pid = -jp->ps[0].pid;
6074 } else
6075 pid = atoi(*argptr);
6076 if (kill(pid, signo) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00006077 error("%s: %m", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006078 } while (*++argptr);
6079
6080 return 0;
6081}
6082
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006083static int fgcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006084{
6085 struct job *jp;
6086 int pgrp;
6087 int status;
6088
6089 jp = getjob(argv[1]);
6090 if (jp->jobctl == 0)
6091 error("job not created under job control");
6092 pgrp = jp->ps[0].pid;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006093 ioctl(2, TIOCSPGRP, (char *) &pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006094 restartjob(jp);
Eric Andersencb57d552001-06-28 07:25:16 +00006095 status = waitforjob(jp);
Eric Andersencb57d552001-06-28 07:25:16 +00006096 return status;
6097}
6098
6099
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006100static int bgcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006101{
6102 struct job *jp;
6103
6104 do {
6105 jp = getjob(*++argv);
6106 if (jp->jobctl == 0)
6107 error("job not created under job control");
6108 restartjob(jp);
6109 } while (--argc > 1);
6110 return 0;
6111}
6112
6113
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006114static void restartjob(struct job *jp)
Eric Andersencb57d552001-06-28 07:25:16 +00006115{
6116 struct procstat *ps;
6117 int i;
6118
6119 if (jp->state == JOBDONE)
6120 return;
6121 INTOFF;
6122 killpg(jp->ps[0].pid, SIGCONT);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006123 for (ps = jp->ps, i = jp->nprocs; --i >= 0; ps++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006124 if (WIFSTOPPED(ps->status)) {
6125 ps->status = -1;
6126 jp->state = 0;
6127 }
6128 }
6129 INTON;
6130}
6131#endif
6132
Eric Andersen2870d962001-07-02 17:27:21 +00006133static void showjobs(int change);
6134
Eric Andersencb57d552001-06-28 07:25:16 +00006135
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006136static int jobscmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006137{
6138 showjobs(0);
6139 return 0;
6140}
6141
6142
6143/*
6144 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6145 * statuses have changed since the last call to showjobs.
6146 *
6147 * If the shell is interrupted in the process of creating a job, the
6148 * result may be a job structure containing zero processes. Such structures
6149 * will be freed here.
6150 */
6151
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006152static void showjobs(int change)
Eric Andersencb57d552001-06-28 07:25:16 +00006153{
6154 int jobno;
6155 int procno;
6156 int i;
6157 struct job *jp;
6158 struct procstat *ps;
6159 int col;
6160 char s[64];
6161
6162 TRACE(("showjobs(%d) called\n", change));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006163 while (dowait(0, (struct job *) NULL) > 0);
6164 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
6165 if (!jp->used)
Eric Andersencb57d552001-06-28 07:25:16 +00006166 continue;
6167 if (jp->nprocs == 0) {
6168 freejob(jp);
6169 continue;
6170 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006171 if (change && !jp->changed)
Eric Andersencb57d552001-06-28 07:25:16 +00006172 continue;
6173 procno = jp->nprocs;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006174 for (ps = jp->ps;; ps++) { /* for each process */
Eric Andersencb57d552001-06-28 07:25:16 +00006175 if (ps == jp->ps)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006176 snprintf(s, 64, "[%d] %ld ", jobno, (long) ps->pid);
Eric Andersencb57d552001-06-28 07:25:16 +00006177 else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006178 snprintf(s, 64, " %ld ", (long) ps->pid);
Eric Andersencb57d552001-06-28 07:25:16 +00006179 out1str(s);
6180 col = strlen(s);
6181 s[0] = '\0';
6182 if (ps->status == -1) {
6183 /* don't print anything */
6184 } else if (WIFEXITED(ps->status)) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006185 snprintf(s, 64, "Exit %d", WEXITSTATUS(ps->status));
Eric Andersencb57d552001-06-28 07:25:16 +00006186 } else {
Eric Andersend35c5df2002-01-09 15:37:36 +00006187#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen2870d962001-07-02 17:27:21 +00006188 if (WIFSTOPPED(ps->status))
Eric Andersencb57d552001-06-28 07:25:16 +00006189 i = WSTOPSIG(ps->status);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006190 else /* WIFSIGNALED(ps->status) */
Eric Andersencb57d552001-06-28 07:25:16 +00006191#endif
6192 i = WTERMSIG(ps->status);
6193 if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
Eric Andersen2870d962001-07-02 17:27:21 +00006194 strcpy(s, sys_siglist[i & 0x7F]);
Eric Andersencb57d552001-06-28 07:25:16 +00006195 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006196 snprintf(s, 64, "Signal %d", i & 0x7F);
Eric Andersencb57d552001-06-28 07:25:16 +00006197 if (WCOREDUMP(ps->status))
6198 strcat(s, " (core dumped)");
6199 }
6200 out1str(s);
6201 col += strlen(s);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006202 printf("%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ', ps->cmd);
Eric Andersencb57d552001-06-28 07:25:16 +00006203 if (--procno <= 0)
6204 break;
6205 }
6206 jp->changed = 0;
6207 if (jp->state == JOBDONE) {
6208 freejob(jp);
6209 }
6210 }
6211}
6212
6213
6214/*
6215 * Mark a job structure as unused.
6216 */
6217
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006218static void freejob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00006219{
6220 const struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006221 int i;
6222
6223 INTOFF;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006224 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006225 if (ps->cmd != nullstr)
Aaron Lehmann49c024a2002-08-02 06:39:47 +00006226 free(ps->cmd);
Eric Andersencb57d552001-06-28 07:25:16 +00006227 }
6228 if (jp->ps != &jp->ps0)
Aaron Lehmann49c024a2002-08-02 06:39:47 +00006229 free(jp->ps);
Eric Andersencb57d552001-06-28 07:25:16 +00006230 jp->used = 0;
Eric Andersend35c5df2002-01-09 15:37:36 +00006231#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006232 if (curjob == jp - jobtab + 1)
6233 curjob = 0;
6234#endif
6235 INTON;
6236}
6237
6238
6239
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006240static int waitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006241{
6242 struct job *job;
6243 int status, retval;
6244 struct job *jp;
6245
6246 if (--argc > 0) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006247 start:
Eric Andersencb57d552001-06-28 07:25:16 +00006248 job = getjob(*++argv);
6249 } else {
6250 job = NULL;
6251 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006252 for (;;) { /* loop until process terminated or stopped */
Eric Andersencb57d552001-06-28 07:25:16 +00006253 if (job != NULL) {
6254 if (job->state) {
6255 status = job->ps[job->nprocs - 1].status;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006256 if (!iflag)
Eric Andersencb57d552001-06-28 07:25:16 +00006257 freejob(job);
6258 if (--argc) {
6259 goto start;
6260 }
6261 if (WIFEXITED(status))
6262 retval = WEXITSTATUS(status);
Eric Andersend35c5df2002-01-09 15:37:36 +00006263#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006264 else if (WIFSTOPPED(status))
6265 retval = WSTOPSIG(status) + 128;
6266#endif
6267 else {
6268 /* XXX: limits number of signals */
6269 retval = WTERMSIG(status) + 128;
6270 }
6271 return retval;
6272 }
6273 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006274 for (jp = jobtab;; jp++) {
6275 if (jp >= jobtab + njobs) { /* no running procs */
Eric Andersencb57d552001-06-28 07:25:16 +00006276 return 0;
6277 }
6278 if (jp->used && jp->state == 0)
6279 break;
6280 }
6281 }
6282 if (dowait(2, 0) < 0 && errno == EINTR) {
6283 return 129;
6284 }
6285 }
6286}
6287
6288
6289
6290/*
6291 * Convert a job name to a job structure.
6292 */
6293
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006294static struct job *getjob(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00006295{
Eric Andersencb57d552001-06-28 07:25:16 +00006296 int jobno;
6297 struct job *jp;
6298 int pid;
6299 int i;
6300
6301 if (name == NULL) {
Eric Andersend35c5df2002-01-09 15:37:36 +00006302#ifdef CONFIG_ASH_JOB_CONTROL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006303 currentjob:
Eric Andersencb57d552001-06-28 07:25:16 +00006304 if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
6305 error("No current job");
6306 return &jobtab[jobno - 1];
6307#else
6308 error("No current job");
6309#endif
6310 } else if (name[0] == '%') {
6311 if (is_digit(name[1])) {
6312 jobno = number(name + 1);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006313 if (jobno > 0 && jobno <= njobs && jobtab[jobno - 1].used != 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006314 return &jobtab[jobno - 1];
Eric Andersend35c5df2002-01-09 15:37:36 +00006315#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006316 } else if (name[1] == '%' && name[2] == '\0') {
6317 goto currentjob;
6318#endif
6319 } else {
6320 struct job *found = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006321
6322 for (jp = jobtab, i = njobs; --i >= 0; jp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006323 if (jp->used && jp->nprocs > 0
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006324 && prefix(name + 1, jp->ps[0].cmd)) {
Eric Andersencb57d552001-06-28 07:25:16 +00006325 if (found)
6326 error("%s: ambiguous", name);
6327 found = jp;
6328 }
6329 }
6330 if (found)
6331 return found;
6332 }
Eric Andersen2870d962001-07-02 17:27:21 +00006333 } else if (is_number(name, &pid)) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006334 for (jp = jobtab, i = njobs; --i >= 0; jp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006335 if (jp->used && jp->nprocs > 0
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006336 && jp->ps[jp->nprocs - 1].pid == pid)
Eric Andersencb57d552001-06-28 07:25:16 +00006337 return jp;
6338 }
6339 }
6340 error("No such job: %s", name);
6341 /* NOTREACHED */
6342}
6343
6344
6345
6346/*
6347 * Return a new job structure,
6348 */
6349
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006350static struct job *makejob(const union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00006351{
6352 int i;
6353 struct job *jp;
6354
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006355 for (i = njobs, jp = jobtab;; jp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006356 if (--i < 0) {
6357 INTOFF;
6358 if (njobs == 0) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006359 jobtab = xmalloc(4 * sizeof jobtab[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00006360 } else {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006361 jp = xmalloc((njobs + 4) * sizeof jobtab[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00006362 memcpy(jp, jobtab, njobs * sizeof jp[0]);
6363 /* Relocate `ps' pointers */
6364 for (i = 0; i < njobs; i++)
6365 if (jp[i].ps == &jobtab[i].ps0)
6366 jp[i].ps = &jp[i].ps0;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00006367 free(jobtab);
Eric Andersencb57d552001-06-28 07:25:16 +00006368 jobtab = jp;
6369 }
6370 jp = jobtab + njobs;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006371 for (i = 4; --i >= 0; jobtab[njobs++].used = 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006372 INTON;
6373 break;
6374 }
6375 if (jp->used == 0)
6376 break;
6377 }
6378 INTOFF;
6379 jp->state = 0;
6380 jp->used = 1;
6381 jp->changed = 0;
6382 jp->nprocs = 0;
Eric Andersend35c5df2002-01-09 15:37:36 +00006383#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006384 jp->jobctl = jobctl;
6385#endif
6386 if (nprocs > 1) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006387 jp->ps = xmalloc(nprocs * sizeof(struct procstat));
Eric Andersencb57d552001-06-28 07:25:16 +00006388 } else {
6389 jp->ps = &jp->ps0;
6390 }
6391 INTON;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006392 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long) node, nprocs,
6393 jp - jobtab + 1));
Eric Andersencb57d552001-06-28 07:25:16 +00006394 return jp;
6395}
6396
6397
6398/*
6399 * Fork of a subshell. If we are doing job control, give the subshell its
6400 * own process group. Jp is a job structure that the job is to be added to.
6401 * N is the command that will be evaluated by the child. Both jp and n may
6402 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00006403 * FORK_FG - Fork off a foreground process.
6404 * FORK_BG - Fork off a background process.
6405 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
6406 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00006407 *
6408 * When job control is turned off, background processes have their standard
6409 * input redirected to /dev/null (except for the second and later processes
6410 * in a pipeline).
6411 */
6412
Eric Andersen2870d962001-07-02 17:27:21 +00006413
6414
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006415static int forkshell(struct job *jp, const union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00006416{
6417 int pid;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006418
Eric Andersend35c5df2002-01-09 15:37:36 +00006419#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006420 int pgrp;
Eric Andersen62483552001-07-10 06:09:16 +00006421#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006422 const char *devnull = _PATH_DEVNULL;
6423 const char *nullerr = "Can't open %s";
6424
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006425 TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long) n,
6426 mode));
Eric Andersencb57d552001-06-28 07:25:16 +00006427 INTOFF;
6428 pid = fork();
6429 if (pid == -1) {
6430 TRACE(("Fork failed, errno=%d\n", errno));
6431 INTON;
6432 error("Cannot fork");
6433 }
6434 if (pid == 0) {
6435 struct job *p;
6436 int wasroot;
6437 int i;
6438
6439 TRACE(("Child shell %d\n", getpid()));
6440 wasroot = rootshell;
6441 rootshell = 0;
6442 closescript();
6443 INTON;
6444 clear_traps();
Eric Andersend35c5df2002-01-09 15:37:36 +00006445#ifdef CONFIG_ASH_JOB_CONTROL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006446 jobctl = 0; /* do job control only in root shell */
Eric Andersencb57d552001-06-28 07:25:16 +00006447 if (wasroot && mode != FORK_NOJOB && mflag) {
6448 if (jp == NULL || jp->nprocs == 0)
6449 pgrp = getpid();
6450 else
6451 pgrp = jp->ps[0].pid;
6452 setpgid(0, pgrp);
6453 if (mode == FORK_FG) {
6454 /*** this causes superfluous TIOCSPGRPS ***/
Eric Andersen3102ac42001-07-06 04:26:23 +00006455 if (tcsetpgrp(2, pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006456 error("tcsetpgrp failed, errno=%d", errno);
Eric Andersencb57d552001-06-28 07:25:16 +00006457 }
6458 setsignal(SIGTSTP);
6459 setsignal(SIGTTOU);
6460 } else if (mode == FORK_BG) {
Eric Andersencb57d552001-06-28 07:25:16 +00006461#else
6462 if (mode == FORK_BG) {
Aaron Lehmann1a698662001-12-31 06:12:48 +00006463#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006464 ignoresig(SIGINT);
6465 ignoresig(SIGQUIT);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006466 if ((jp == NULL || jp->nprocs == 0) && !fd0_redirected_p()) {
Eric Andersencb57d552001-06-28 07:25:16 +00006467 close(0);
6468 if (open(devnull, O_RDONLY) != 0)
6469 error(nullerr, devnull);
6470 }
6471 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006472 for (i = njobs, p = jobtab; --i >= 0; p++)
Eric Andersencb57d552001-06-28 07:25:16 +00006473 if (p->used)
6474 freejob(p);
6475 if (wasroot && iflag) {
6476 setsignal(SIGINT);
6477 setsignal(SIGQUIT);
6478 setsignal(SIGTERM);
6479 }
6480 return pid;
6481 }
Eric Andersend35c5df2002-01-09 15:37:36 +00006482#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006483 if (rootshell && mode != FORK_NOJOB && mflag) {
6484 if (jp == NULL || jp->nprocs == 0)
6485 pgrp = pid;
6486 else
6487 pgrp = jp->ps[0].pid;
6488 setpgid(pid, pgrp);
6489 }
Eric Andersen62483552001-07-10 06:09:16 +00006490#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006491 if (mode == FORK_BG)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006492 backgndpid = pid; /* set $! */
Eric Andersencb57d552001-06-28 07:25:16 +00006493 if (jp) {
6494 struct procstat *ps = &jp->ps[jp->nprocs++];
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006495
Eric Andersencb57d552001-06-28 07:25:16 +00006496 ps->pid = pid;
6497 ps->status = -1;
6498 ps->cmd = nullstr;
6499 if (iflag && rootshell && n)
6500 ps->cmd = commandtext(n);
6501 }
6502 INTON;
6503 TRACE(("In parent shell: child = %d\n", pid));
6504 return pid;
6505}
6506
6507
6508
6509/*
6510 * Wait for job to finish.
6511 *
6512 * Under job control we have the problem that while a child process is
6513 * running interrupts generated by the user are sent to the child but not
6514 * to the shell. This means that an infinite loop started by an inter-
6515 * active user may be hard to kill. With job control turned off, an
6516 * interactive user may place an interactive program inside a loop. If
6517 * the interactive program catches interrupts, the user doesn't want
6518 * these interrupts to also abort the loop. The approach we take here
6519 * is to have the shell ignore interrupt signals while waiting for a
6520 * forground process to terminate, and then send itself an interrupt
6521 * signal if the child process was terminated by an interrupt signal.
6522 * Unfortunately, some programs want to do a bit of cleanup and then
6523 * exit on interrupt; unless these processes terminate themselves by
6524 * sending a signal to themselves (instead of calling exit) they will
6525 * confuse this approach.
6526 */
6527
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006528static int waitforjob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00006529{
Eric Andersend35c5df2002-01-09 15:37:36 +00006530#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006531 int mypgrp = getpgrp();
6532#endif
6533 int status;
6534 int st;
Eric Andersencb57d552001-06-28 07:25:16 +00006535
6536 INTOFF;
Eric Andersencb57d552001-06-28 07:25:16 +00006537 TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
6538 while (jp->state == 0) {
6539 dowait(1, jp);
6540 }
Eric Andersend35c5df2002-01-09 15:37:36 +00006541#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006542 if (jp->jobctl) {
Eric Andersen3102ac42001-07-06 04:26:23 +00006543 if (tcsetpgrp(2, mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006544 error("tcsetpgrp failed, errno=%d\n", errno);
Eric Andersencb57d552001-06-28 07:25:16 +00006545 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00006546 if (jp->state == JOBSTOPPED)
Eric Andersencb57d552001-06-28 07:25:16 +00006547 curjob = jp - jobtab + 1;
6548#endif
6549 status = jp->ps[jp->nprocs - 1].status;
6550 /* convert to 8 bits */
6551 if (WIFEXITED(status))
6552 st = WEXITSTATUS(status);
Eric Andersend35c5df2002-01-09 15:37:36 +00006553#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006554 else if (WIFSTOPPED(status))
6555 st = WSTOPSIG(status) + 128;
6556#endif
6557 else
6558 st = WTERMSIG(status) + 128;
Eric Andersend35c5df2002-01-09 15:37:36 +00006559#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006560 if (jp->jobctl) {
6561 /*
6562 * This is truly gross.
6563 * If we're doing job control, then we did a TIOCSPGRP which
6564 * caused us (the shell) to no longer be in the controlling
6565 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
6566 * intuit from the subprocess exit status whether a SIGINT
6567 * occured, and if so interrupt ourselves. Yuck. - mycroft
6568 */
6569 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
6570 raise(SIGINT);
6571 }
Eric Andersen2870d962001-07-02 17:27:21 +00006572 if (jp->state == JOBDONE)
Eric Andersencb57d552001-06-28 07:25:16 +00006573#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006574 freejob(jp);
6575 INTON;
6576 return st;
6577}
6578
6579
6580
6581/*
6582 * Wait for a process to terminate.
6583 */
6584
Eric Andersen62483552001-07-10 06:09:16 +00006585/*
6586 * Do a wait system call. If job control is compiled in, we accept
6587 * stopped processes. If block is zero, we return a value of zero
6588 * rather than blocking.
6589 *
6590 * System V doesn't have a non-blocking wait system call. It does
6591 * have a SIGCLD signal that is sent to a process when one of it's
6592 * children dies. The obvious way to use SIGCLD would be to install
6593 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
6594 * was received, and have waitproc bump another counter when it got
6595 * the status of a process. Waitproc would then know that a wait
6596 * system call would not block if the two counters were different.
6597 * This approach doesn't work because if a process has children that
6598 * have not been waited for, System V will send it a SIGCLD when it
6599 * installs a signal handler for SIGCLD. What this means is that when
6600 * a child exits, the shell will be sent SIGCLD signals continuously
6601 * until is runs out of stack space, unless it does a wait call before
6602 * restoring the signal handler. The code below takes advantage of
6603 * this (mis)feature by installing a signal handler for SIGCLD and
6604 * then checking to see whether it was called. If there are any
6605 * children to be waited for, it will be.
6606 *
6607 */
6608
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006609static inline int waitproc(int block, int *status)
Eric Andersen62483552001-07-10 06:09:16 +00006610{
6611 int flags;
6612
6613 flags = 0;
Eric Andersend35c5df2002-01-09 15:37:36 +00006614#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen62483552001-07-10 06:09:16 +00006615 if (jobctl)
6616 flags |= WUNTRACED;
6617#endif
6618 if (block == 0)
6619 flags |= WNOHANG;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006620 return wait3(status, flags, (struct rusage *) NULL);
Eric Andersen62483552001-07-10 06:09:16 +00006621}
6622
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006623static int dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00006624{
6625 int pid;
6626 int status;
6627 struct procstat *sp;
6628 struct job *jp;
6629 struct job *thisjob;
6630 int done;
6631 int stopped;
6632 int core;
6633 int sig;
6634
6635 TRACE(("dowait(%d) called\n", block));
6636 do {
6637 pid = waitproc(block, &status);
6638 TRACE(("wait returns %d, status=%d\n", pid, status));
6639 } while (!(block & 2) && pid == -1 && errno == EINTR);
6640 if (pid <= 0)
6641 return pid;
6642 INTOFF;
6643 thisjob = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006644 for (jp = jobtab; jp < jobtab + njobs; jp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006645 if (jp->used) {
6646 done = 1;
6647 stopped = 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006648 for (sp = jp->ps; sp < jp->ps + jp->nprocs; sp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006649 if (sp->pid == -1)
6650 continue;
6651 if (sp->pid == pid) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006652 TRACE(("Changing status of proc %d from 0x%x to 0x%x\n",
6653 pid, sp->status, status));
Eric Andersencb57d552001-06-28 07:25:16 +00006654 sp->status = status;
6655 thisjob = jp;
6656 }
6657 if (sp->status == -1)
6658 stopped = 0;
6659 else if (WIFSTOPPED(sp->status))
6660 done = 0;
6661 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006662 if (stopped) { /* stopped or done */
Glenn L McGrath50812ff2002-08-23 13:14:48 +00006663 int state = done ? JOBDONE : JOBSTOPPED;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006664
Eric Andersencb57d552001-06-28 07:25:16 +00006665 if (jp->state != state) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006666 TRACE(("Job %d: changing state from %d to %d\n",
6667 jp - jobtab + 1, jp->state, state));
Eric Andersencb57d552001-06-28 07:25:16 +00006668 jp->state = state;
Eric Andersend35c5df2002-01-09 15:37:36 +00006669#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006670 if (done && curjob == jp - jobtab + 1)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006671 curjob = 0; /* no current job */
Eric Andersencb57d552001-06-28 07:25:16 +00006672#endif
6673 }
6674 }
6675 }
6676 }
6677 INTON;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006678 if (!rootshell || !iflag || (job && thisjob == job)) {
Eric Andersencb57d552001-06-28 07:25:16 +00006679 core = WCOREDUMP(status);
Eric Andersend35c5df2002-01-09 15:37:36 +00006680#ifdef CONFIG_ASH_JOB_CONTROL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006681 if (WIFSTOPPED(status))
6682 sig = WSTOPSIG(status);
Eric Andersencb57d552001-06-28 07:25:16 +00006683 else
6684#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006685 if (WIFEXITED(status))
6686 sig = 0;
6687 else
6688 sig = WTERMSIG(status);
Eric Andersencb57d552001-06-28 07:25:16 +00006689
6690 if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
6691 if (thisjob != job)
Eric Andersen3102ac42001-07-06 04:26:23 +00006692 out2fmt("%d: ", pid);
Eric Andersend35c5df2002-01-09 15:37:36 +00006693#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006694 if (sig == SIGTSTP && rootshell && iflag)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006695 out2fmt("%%%ld ", (long) (job - jobtab + 1));
Eric Andersencb57d552001-06-28 07:25:16 +00006696#endif
6697 if (sig < NSIG && sys_siglist[sig])
6698 out2str(sys_siglist[sig]);
6699 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006700 out2fmt("Signal %d", sig);
Eric Andersencb57d552001-06-28 07:25:16 +00006701 if (core)
6702 out2str(" - core dumped");
6703 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00006704 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006705 TRACE(("Not printing status: status=%d, sig=%d\n", status, sig));
Eric Andersencb57d552001-06-28 07:25:16 +00006706 }
6707 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006708 TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell,
6709 job));
Eric Andersencb57d552001-06-28 07:25:16 +00006710 if (thisjob)
6711 thisjob->changed = 1;
6712 }
6713 return pid;
6714}
6715
6716
6717
Eric Andersencb57d552001-06-28 07:25:16 +00006718
6719/*
6720 * return 1 if there are stopped jobs, otherwise 0
6721 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006722static int stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006723{
6724 int jobno;
6725 struct job *jp;
6726
6727 if (job_warning)
6728 return (0);
6729 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
6730 if (jp->used == 0)
6731 continue;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00006732 if (jp->state == JOBSTOPPED) {
Eric Andersencb57d552001-06-28 07:25:16 +00006733 out2str("You have stopped jobs.\n");
6734 job_warning = 2;
6735 return (1);
6736 }
6737 }
6738
6739 return (0);
6740}
6741
6742/*
6743 * Return a string identifying a command (to be printed by the
6744 * jobs command.
6745 */
6746
6747static char *cmdnextc;
6748static int cmdnleft;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006749
Eric Andersen2870d962001-07-02 17:27:21 +00006750#define MAXCMDTEXT 200
Eric Andersencb57d552001-06-28 07:25:16 +00006751
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006752static void cmdputs(const char *s)
Eric Andersen2870d962001-07-02 17:27:21 +00006753{
6754 const char *p;
6755 char *q;
6756 char c;
6757 int subtype = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00006758
Eric Andersen2870d962001-07-02 17:27:21 +00006759 if (cmdnleft <= 0)
6760 return;
6761 p = s;
6762 q = cmdnextc;
6763 while ((c = *p++) != '\0') {
6764 if (c == CTLESC)
6765 *q++ = *p++;
6766 else if (c == CTLVAR) {
6767 *q++ = '$';
6768 if (--cmdnleft > 0)
6769 *q++ = '{';
6770 subtype = *p++;
6771 } else if (c == '=' && subtype != 0) {
6772 *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
6773 subtype = 0;
6774 } else if (c == CTLENDVAR) {
6775 *q++ = '}';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006776 } else if (c == CTLBACKQ || c == CTLBACKQ + CTLQUOTE)
6777 cmdnleft++; /* ignore it */
Eric Andersen2870d962001-07-02 17:27:21 +00006778 else
6779 *q++ = c;
6780 if (--cmdnleft <= 0) {
6781 *q++ = '.';
6782 *q++ = '.';
6783 *q++ = '.';
6784 break;
6785 }
6786 }
6787 cmdnextc = q;
Eric Andersencb57d552001-06-28 07:25:16 +00006788}
6789
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00006790#define CMDTXT_TABLE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006791#ifdef CMDTXT_TABLE
6792/*
6793 * To collect a lot of redundant code in cmdtxt() case statements, we
6794 * implement a mini language here. Each type of node struct has an
6795 * associated instruction sequence that operates on its members via
6796 * their offsets. The instruction are pack in unsigned chars with
6797 * format IIDDDDDE where the bits are
6798 * I : part of the instruction opcode, which are
6799 * 00 : member is a pointer to another node -- process it recursively
6800 * 40 : member is a pointer to a char string -- output it
6801 * 80 : output the string whose index is stored in the data field
6802 * CC : flag signaling that this case needs external processing
6803 * D : data - either the (shifted) index of a fixed string to output or
6804 * the actual offset of the member to operate on in the struct
6805 * (since we assume bit 0 is set, the offset is not shifted)
6806 * E : flag signaling end of instruction sequence
6807 *
6808 * WARNING: In order to handle larger offsets for 64bit archs, this code
6809 * assumes that no offset can be an odd number and stores the
6810 * end-of-instructions flag in bit 0.
6811 */
Eric Andersencb57d552001-06-28 07:25:16 +00006812
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006813#define CMDTXT_NOMORE 0x01 /* NOTE: no offset should be odd */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006814#define CMDTXT_CHARPTR 0x40
6815#define CMDTXT_STRING 0x80
6816#define CMDTXT_SPECIAL 0xC0
6817#define CMDTXT_OFFSETMASK 0x3E
6818
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006819static const char *const cmdtxt_strings[] = {
6820 /* 0 1 2 3 4 5 6 7 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006821 "; ", "(", ")", " && ", " || ", "if ", "; then ", "...",
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006822 /* 8 9 10 11 12 13 */
6823 "while ", "; do ", "; done", "until ", "for ", " in ...",
6824 /* 14 15 16 17 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006825 "case ", "???", "() ...", "<<..."
6826};
6827
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006828static const char *const redir_strings[] = {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006829 ">", "<", "<>", ">>", ">|", ">&", "<&"
6830};
6831
6832static const unsigned char cmdtxt_ops[] = {
6833#define CMDTXT_NSEMI 0
6834 offsetof(union node, nbinary.ch1),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006835 0 | CMDTXT_STRING,
6836 offsetof(union node, nbinary.ch2) | CMDTXT_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006837#define CMDTXT_NCMD (CMDTXT_NSEMI + 3)
6838#define CMDTXT_NPIPE (CMDTXT_NCMD)
6839#define CMDTXT_NCASE (CMDTXT_NCMD)
6840#define CMDTXT_NTO (CMDTXT_NCMD)
6841#define CMDTXT_NFROM (CMDTXT_NCMD)
6842#define CMDTXT_NFROMTO (CMDTXT_NCMD)
6843#define CMDTXT_NAPPEND (CMDTXT_NCMD)
6844#define CMDTXT_NTOOV (CMDTXT_NCMD)
6845#define CMDTXT_NTOFD (CMDTXT_NCMD)
6846#define CMDTXT_NFROMFD (CMDTXT_NCMD)
6847 CMDTXT_SPECIAL,
6848#define CMDTXT_NREDIR (CMDTXT_NPIPE + 1)
6849#define CMDTXT_NBACKGND (CMDTXT_NREDIR)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006850 offsetof(union node, nredir.n) | CMDTXT_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006851#define CMDTXT_NSUBSHELL (CMDTXT_NBACKGND + 1)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006852 (1 * 2) | CMDTXT_STRING,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006853 offsetof(union node, nredir.n),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006854 (2 * 2) | CMDTXT_STRING | CMDTXT_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006855#define CMDTXT_NAND (CMDTXT_NSUBSHELL + 3)
6856 offsetof(union node, nbinary.ch1),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006857 (3 * 2) | CMDTXT_STRING,
6858 offsetof(union node, nbinary.ch2) | CMDTXT_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006859#define CMDTXT_NOR (CMDTXT_NAND + 3)
6860 offsetof(union node, nbinary.ch1),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006861 (4 * 2) | CMDTXT_STRING,
6862 offsetof(union node, nbinary.ch2) | CMDTXT_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006863#define CMDTXT_NIF (CMDTXT_NOR + 3)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006864 (5 * 2) | CMDTXT_STRING,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006865 offsetof(union node, nif.test),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006866 (6 * 2) | CMDTXT_STRING,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006867 offsetof(union node, nif.ifpart),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006868 (7 * 2) | CMDTXT_STRING | CMDTXT_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006869#define CMDTXT_NWHILE (CMDTXT_NIF + 5)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006870 (8 * 2) | CMDTXT_STRING,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006871 offsetof(union node, nbinary.ch1),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006872 (9 * 2) | CMDTXT_STRING,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006873 offsetof(union node, nbinary.ch2),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006874 (10 * 2) | CMDTXT_STRING | CMDTXT_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006875#define CMDTXT_NUNTIL (CMDTXT_NWHILE + 5)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006876 (11 * 2) | CMDTXT_STRING,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006877 offsetof(union node, nbinary.ch1),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006878 (9 * 2) | CMDTXT_STRING,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006879 offsetof(union node, nbinary.ch2),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006880 (10 * 2) | CMDTXT_STRING | CMDTXT_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006881#define CMDTXT_NFOR (CMDTXT_NUNTIL + 5)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006882 (12 * 2) | CMDTXT_STRING,
6883 offsetof(union node, nfor.var) | CMDTXT_CHARPTR,
6884 (13 * 2) | CMDTXT_STRING | CMDTXT_NOMORE,
6885#define CMDTXT_NCLIST (CMDTXT_NFOR + 3) /* TODO: IS THIS CORRECT??? */
6886#define CMDTXT_NNOT (CMDTXT_NCLIST) /* TODO: IS THIS CORRECT??? */
6887 (15 * 2) | CMDTXT_STRING | CMDTXT_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006888#define CMDTXT_NDEFUN (CMDTXT_NCLIST + 1)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006889 offsetof(union node, narg.text) | CMDTXT_CHARPTR,
6890 (16 * 2) | CMDTXT_STRING | CMDTXT_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006891#define CMDTXT_NARG (CMDTXT_NDEFUN + 2)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006892 offsetof(union node, narg.text) | CMDTXT_CHARPTR | CMDTXT_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006893#define CMDTXT_NHERE (CMDTXT_NARG + 1)
6894#define CMDTXT_NXHERE (CMDTXT_NHERE)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006895 (17 * 2) | CMDTXT_STRING | CMDTXT_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006896};
6897
6898#if CMDTXT_NXHERE != 36
6899#error CMDTXT_NXHERE
6900#endif
6901
6902static const unsigned char cmdtxt_ops_index[26] = {
6903 CMDTXT_NSEMI,
6904 CMDTXT_NCMD,
6905 CMDTXT_NPIPE,
6906 CMDTXT_NREDIR,
6907 CMDTXT_NBACKGND,
6908 CMDTXT_NSUBSHELL,
6909 CMDTXT_NAND,
6910 CMDTXT_NOR,
6911 CMDTXT_NIF,
6912 CMDTXT_NWHILE,
6913 CMDTXT_NUNTIL,
6914 CMDTXT_NFOR,
6915 CMDTXT_NCASE,
6916 CMDTXT_NCLIST,
6917 CMDTXT_NDEFUN,
6918 CMDTXT_NARG,
6919 CMDTXT_NTO,
6920 CMDTXT_NFROM,
6921 CMDTXT_NFROMTO,
6922 CMDTXT_NAPPEND,
6923 CMDTXT_NTOOV,
6924 CMDTXT_NTOFD,
6925 CMDTXT_NFROMFD,
6926 CMDTXT_NHERE,
6927 CMDTXT_NXHERE,
6928 CMDTXT_NNOT,
6929};
6930
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006931static void cmdtxt(const union node *n)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006932{
6933 const char *p;
6934
6935 if (n == NULL)
6936 return;
6937
6938 p = cmdtxt_ops + (int) cmdtxt_ops_index[n->type];
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006939 if ((*p & CMDTXT_SPECIAL) != CMDTXT_SPECIAL) { /* normal case */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006940 do {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006941 if (*p & CMDTXT_STRING) { /* output fixed string */
6942 cmdputs(cmdtxt_strings
6943 [((int) (*p & CMDTXT_OFFSETMASK) >> 1)]);
Manuel Novoa III c639a352001-08-12 17:32:56 +00006944 } else {
6945 const char *pf = ((const char *) n)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006946 + ((int) (*p & CMDTXT_OFFSETMASK));
6947
6948 if (*p & CMDTXT_CHARPTR) { /* output dynamic string */
Manuel Novoa III c639a352001-08-12 17:32:56 +00006949 cmdputs(*((const char **) pf));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006950 } else { /* output field */
Manuel Novoa III c639a352001-08-12 17:32:56 +00006951 cmdtxt(*((const union node **) pf));
6952 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006953 }
6954 } while (!(*p++ & CMDTXT_NOMORE));
6955 } else if (n->type == NCMD) {
6956 union node *np;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006957
6958 for (np = n->ncmd.args; np; np = np->narg.next) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006959 cmdtxt(np);
6960 if (np->narg.next)
6961 cmdputs(spcstr);
6962 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006963 for (np = n->ncmd.redirect; np; np = np->nfile.next) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006964 cmdputs(spcstr);
6965 cmdtxt(np);
6966 }
6967 } else if (n->type == NPIPE) {
6968 struct nodelist *lp;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006969
6970 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006971 cmdtxt(lp->n);
6972 if (lp->next)
6973 cmdputs(" | ");
6974 }
6975 } else if (n->type == NCASE) {
6976 cmdputs(cmdtxt_strings[14]);
6977 cmdputs(n->ncase.expr->narg.text);
6978 cmdputs(cmdtxt_strings[13]);
6979 } else {
6980#if (NTO != 16) || (NFROM != 17) || (NFROMTO != 18) || (NAPPEND != 19) || (NTOOV != 20) || (NTOFD != 21) || (NFROMFD != 22)
6981#error Assumption violated regarding range and ordering of NTO ... NFROMFD!
6982#endif
6983 char s[2];
6984
6985#ifdef DEBUG
6986 assert((n->type >= NTO) && (n->type <= NFROMFD));
6987#endif
6988
6989 p = redir_strings[n->type - NTO];
6990 if (n->nfile.fd != ('>' == *p)) {
6991 s[0] = n->nfile.fd + '0';
6992 s[1] = '\0';
6993 cmdputs(s);
6994 }
6995 cmdputs(p);
6996 if (n->type >= NTOFD) {
6997 s[0] = n->ndup.dupfd + '0';
6998 s[1] = '\0';
6999 cmdputs(s);
7000 } else {
7001 cmdtxt(n->nfile.fname);
7002 }
7003 }
7004}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007005#else /* CMDTXT_TABLE */
7006static void cmdtxt(const union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007007{
Eric Andersencb57d552001-06-28 07:25:16 +00007008 union node *np;
7009 struct nodelist *lp;
7010 const char *p;
7011 int i;
7012 char s[2];
7013
7014 if (n == NULL)
7015 return;
7016 switch (n->type) {
7017 case NSEMI:
7018 cmdtxt(n->nbinary.ch1);
7019 cmdputs("; ");
7020 cmdtxt(n->nbinary.ch2);
7021 break;
7022 case NAND:
7023 cmdtxt(n->nbinary.ch1);
7024 cmdputs(" && ");
7025 cmdtxt(n->nbinary.ch2);
7026 break;
7027 case NOR:
7028 cmdtxt(n->nbinary.ch1);
7029 cmdputs(" || ");
7030 cmdtxt(n->nbinary.ch2);
7031 break;
7032 case NPIPE:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007033 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00007034 cmdtxt(lp->n);
7035 if (lp->next)
7036 cmdputs(" | ");
7037 }
7038 break;
7039 case NSUBSHELL:
7040 cmdputs("(");
7041 cmdtxt(n->nredir.n);
7042 cmdputs(")");
7043 break;
7044 case NREDIR:
7045 case NBACKGND:
7046 cmdtxt(n->nredir.n);
7047 break;
7048 case NIF:
7049 cmdputs("if ");
7050 cmdtxt(n->nif.test);
7051 cmdputs("; then ");
7052 cmdtxt(n->nif.ifpart);
7053 cmdputs("...");
7054 break;
7055 case NWHILE:
7056 cmdputs("while ");
7057 goto until;
7058 case NUNTIL:
7059 cmdputs("until ");
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007060 until:
Eric Andersencb57d552001-06-28 07:25:16 +00007061 cmdtxt(n->nbinary.ch1);
7062 cmdputs("; do ");
7063 cmdtxt(n->nbinary.ch2);
7064 cmdputs("; done");
7065 break;
7066 case NFOR:
7067 cmdputs("for ");
7068 cmdputs(n->nfor.var);
7069 cmdputs(" in ...");
7070 break;
7071 case NCASE:
7072 cmdputs("case ");
7073 cmdputs(n->ncase.expr->narg.text);
7074 cmdputs(" in ...");
7075 break;
7076 case NDEFUN:
7077 cmdputs(n->narg.text);
7078 cmdputs("() ...");
7079 break;
7080 case NCMD:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007081 for (np = n->ncmd.args; np; np = np->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00007082 cmdtxt(np);
7083 if (np->narg.next)
7084 cmdputs(spcstr);
7085 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007086 for (np = n->ncmd.redirect; np; np = np->nfile.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00007087 cmdputs(spcstr);
7088 cmdtxt(np);
7089 }
7090 break;
7091 case NARG:
7092 cmdputs(n->narg.text);
7093 break;
7094 case NTO:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007095 p = ">";
7096 i = 1;
7097 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00007098 case NAPPEND:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007099 p = ">>";
7100 i = 1;
7101 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00007102 case NTOFD:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007103 p = ">&";
7104 i = 1;
7105 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00007106 case NTOOV:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007107 p = ">|";
7108 i = 1;
7109 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00007110 case NFROM:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007111 p = "<";
7112 i = 0;
7113 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00007114 case NFROMFD:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007115 p = "<&";
7116 i = 0;
7117 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00007118 case NFROMTO:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007119 p = "<>";
7120 i = 0;
7121 goto redir;
7122 redir:
Eric Andersencb57d552001-06-28 07:25:16 +00007123 if (n->nfile.fd != i) {
7124 s[0] = n->nfile.fd + '0';
7125 s[1] = '\0';
7126 cmdputs(s);
7127 }
7128 cmdputs(p);
7129 if (n->type == NTOFD || n->type == NFROMFD) {
7130 s[0] = n->ndup.dupfd + '0';
7131 s[1] = '\0';
7132 cmdputs(s);
7133 } else {
7134 cmdtxt(n->nfile.fname);
7135 }
7136 break;
7137 case NHERE:
7138 case NXHERE:
7139 cmdputs("<<...");
7140 break;
7141 default:
7142 cmdputs("???");
7143 break;
7144 }
7145}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007146#endif /* CMDTXT_TABLE */
Eric Andersencb57d552001-06-28 07:25:16 +00007147
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007148static char *commandtext(const union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007149{
7150 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007151
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007152 cmdnextc = name = xmalloc(MAXCMDTEXT);
Eric Andersen2870d962001-07-02 17:27:21 +00007153 cmdnleft = MAXCMDTEXT - 4;
7154 cmdtxt(n);
7155 *cmdnextc = '\0';
7156 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00007157}
7158
Eric Andersen2870d962001-07-02 17:27:21 +00007159
Eric Andersend35c5df2002-01-09 15:37:36 +00007160#ifdef CONFIG_ASH_MAIL
Eric Andersenec074692001-10-31 11:05:49 +00007161
Eric Andersencb57d552001-06-28 07:25:16 +00007162/*
Eric Andersenec074692001-10-31 11:05:49 +00007163 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +00007164 */
7165
7166
7167#define MAXMBOXES 10
7168
7169
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007170static int nmboxes; /* number of mailboxes */
7171static time_t mailtime[MAXMBOXES]; /* times of mailboxes */
Eric Andersencb57d552001-06-28 07:25:16 +00007172
7173
7174
7175/*
7176 * Print appropriate message(s) if mail has arrived. If the argument is
7177 * nozero, then the value of MAIL has changed, so we just update the
7178 * values.
7179 */
7180
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007181static void chkmail(int silent)
Eric Andersencb57d552001-06-28 07:25:16 +00007182{
7183 int i;
7184 const char *mpath;
7185 char *p;
7186 char *q;
7187 struct stackmark smark;
7188 struct stat statb;
7189
7190 if (silent)
7191 nmboxes = 10;
7192 if (nmboxes == 0)
7193 return;
7194 setstackmark(&smark);
7195 mpath = mpathset()? mpathval() : mailval();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007196 for (i = 0; i < nmboxes; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007197 p = padvance(&mpath, nullstr);
7198 if (p == NULL)
7199 break;
7200 if (*p == '\0')
7201 continue;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007202 for (q = p; *q; q++);
Eric Andersencb57d552001-06-28 07:25:16 +00007203#ifdef DEBUG
7204 if (q[-1] != '/')
7205 abort();
7206#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007207 q[-1] = '\0'; /* delete trailing '/' */
Eric Andersencb57d552001-06-28 07:25:16 +00007208 if (stat(p, &statb) < 0)
7209 statb.st_size = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007210 if (statb.st_size > mailtime[i] && !silent) {
7211 out2fmt(snlfmt, pathopt ? pathopt : "you have mail");
Eric Andersencb57d552001-06-28 07:25:16 +00007212 }
7213 mailtime[i] = statb.st_size;
Eric Andersencb57d552001-06-28 07:25:16 +00007214 }
7215 nmboxes = i;
7216 popstackmark(&smark);
7217}
Eric Andersencb57d552001-06-28 07:25:16 +00007218
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007219#endif /* CONFIG_ASH_MAIL */
Eric Andersenec074692001-10-31 11:05:49 +00007220
Eric Andersencb57d552001-06-28 07:25:16 +00007221#define PROFILE 0
7222
Eric Andersencb57d552001-06-28 07:25:16 +00007223#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007224static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007225extern int etext();
7226#endif
7227
Robert Griebl64f70cc2002-05-14 23:22:06 +00007228static int isloginsh = 0;
7229
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007230static void read_profile(const char *);
7231static void cmdloop(int);
7232static void options(int);
7233static void setoption(int, int);
7234static void procargs(int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00007235
Eric Andersen2870d962001-07-02 17:27:21 +00007236
Eric Andersencb57d552001-06-28 07:25:16 +00007237/*
7238 * Main routine. We initialize things, parse the arguments, execute
7239 * profiles if we're a login shell, and then call cmdloop to execute
7240 * commands. The setjmp call sets up the location to jump to when an
7241 * exception occurs. When an exception occurs the variable "state"
7242 * is used to figure out how far we had gotten.
7243 */
7244
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007245int ash_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007246{
7247 struct jmploc jmploc;
7248 struct stackmark smark;
7249 volatile int state;
Eric Andersen62483552001-07-10 06:09:16 +00007250 const char *shinit;
Eric Andersencb57d552001-06-28 07:25:16 +00007251
Eric Andersencb57d552001-06-28 07:25:16 +00007252 BLTINCMD = find_builtin("builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00007253 EXECCMD = find_builtin("exec");
7254 EVALCMD = find_builtin("eval");
7255
Eric Andersenbdfd0d72001-10-24 05:00:29 +00007256#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
Eric Andersen1c039232001-07-07 00:05:55 +00007257 unsetenv("PS1");
7258 unsetenv("PS2");
7259#endif
7260
Eric Andersencb57d552001-06-28 07:25:16 +00007261#if PROFILE
7262 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7263#endif
7264#if defined(linux) || defined(__GNU__)
7265 signal(SIGCHLD, SIG_DFL);
7266#endif
7267 state = 0;
7268 if (setjmp(jmploc.loc)) {
7269 INTOFF;
7270 /*
7271 * When a shell procedure is executed, we raise the
7272 * exception EXSHELLPROC to clean up before executing
7273 * the shell procedure.
7274 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007275 if (exception == EXSHELLPROC) {
Eric Andersencb57d552001-06-28 07:25:16 +00007276 rootpid = getpid();
7277 rootshell = 1;
7278 minusc = NULL;
7279 state = 3;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007280 } else {
7281 if (exception == EXEXEC) {
7282 exitstatus = exerrno;
7283 } else if (exception == EXERROR) {
7284 exitstatus = 2;
7285 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007286 if (state == 0 || iflag == 0 || !rootshell)
7287 exitshell(exitstatus);
Eric Andersencb57d552001-06-28 07:25:16 +00007288 }
7289 reset();
Eric Andersen2870d962001-07-02 17:27:21 +00007290 if (exception == EXINT) {
Eric Andersencb57d552001-06-28 07:25:16 +00007291 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00007292 }
7293 popstackmark(&smark);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007294 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007295 if (state == 1)
7296 goto state1;
7297 else if (state == 2)
7298 goto state2;
7299 else if (state == 3)
7300 goto state3;
7301 else
7302 goto state4;
7303 }
7304 handler = &jmploc;
7305#ifdef DEBUG
7306 opentrace();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007307 trputs("Shell args: ");
7308 trargs(argv);
Eric Andersencb57d552001-06-28 07:25:16 +00007309#endif
7310 rootpid = getpid();
7311 rootshell = 1;
7312 init();
7313 setstackmark(&smark);
7314 procargs(argc, argv);
Robert Griebl64f70cc2002-05-14 23:22:06 +00007315 if (argv[0] && argv[0][0] == '-')
7316 isloginsh = 1;
7317 if (isloginsh) {
Eric Andersencb57d552001-06-28 07:25:16 +00007318 state = 1;
7319 read_profile("/etc/profile");
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007320 state1:
Eric Andersencb57d552001-06-28 07:25:16 +00007321 state = 2;
7322 read_profile(".profile");
7323 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007324 state2:
Eric Andersencb57d552001-06-28 07:25:16 +00007325 state = 3;
7326#ifndef linux
7327 if (getuid() == geteuid() && getgid() == getegid()) {
7328#endif
7329 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7330 state = 3;
7331 read_profile(shinit);
7332 }
7333#ifndef linux
7334 }
7335#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007336 state3:
Eric Andersencb57d552001-06-28 07:25:16 +00007337 state = 4;
7338 if (sflag == 0 || minusc) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007339 static const char sigs[] = {
7340 SIGINT, SIGQUIT, SIGHUP,
Eric Andersencb57d552001-06-28 07:25:16 +00007341#ifdef SIGTSTP
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007342 SIGTSTP,
Eric Andersencb57d552001-06-28 07:25:16 +00007343#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007344 SIGPIPE
Eric Andersencb57d552001-06-28 07:25:16 +00007345 };
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007346
Glenn L McGrath50812ff2002-08-23 13:14:48 +00007347#define SIGSSIZE ((sizeof(sigs)/sizeof(sigs[0])))
Eric Andersencb57d552001-06-28 07:25:16 +00007348 int i;
7349
7350 for (i = 0; i < SIGSSIZE; i++)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007351 setsignal(sigs[i]);
Eric Andersencb57d552001-06-28 07:25:16 +00007352 }
7353
7354 if (minusc)
7355 evalstring(minusc, 0);
7356
7357 if (sflag || minusc == NULL) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007358 state4: /* XXX ??? - why isn't this before the "if" statement */
Robert Griebl350d26b2002-12-03 22:45:46 +00007359#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7360 if ( iflag )
7361 load_history ( ".ash_history" );
7362#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007363 cmdloop(1);
7364 }
7365#if PROFILE
7366 monitor(0);
7367#endif
7368 exitshell(exitstatus);
7369 /* NOTREACHED */
7370}
7371
7372
7373/*
7374 * Read and execute commands. "Top" is nonzero for the top level command
7375 * loop; it turns on prompting if the shell is interactive.
7376 */
7377
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007378static void cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00007379{
7380 union node *n;
7381 struct stackmark smark;
7382 int inter;
7383 int numeof = 0;
7384
7385 TRACE(("cmdloop(%d) called\n", top));
7386 setstackmark(&smark);
7387 for (;;) {
7388 if (pendingsigs)
7389 dotrap();
7390 inter = 0;
7391 if (iflag && top) {
7392 inter++;
7393 showjobs(1);
Eric Andersend35c5df2002-01-09 15:37:36 +00007394#ifdef CONFIG_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +00007395 chkmail(0);
Eric Andersenec074692001-10-31 11:05:49 +00007396#endif
Eric Andersen3102ac42001-07-06 04:26:23 +00007397 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00007398 }
7399 n = parsecmd(inter);
7400 /* showtree(n); DEBUG */
7401 if (n == NEOF) {
7402 if (!top || numeof >= 50)
7403 break;
7404 if (!stoppedjobs()) {
7405 if (!Iflag)
7406 break;
7407 out2str("\nUse \"exit\" to leave shell.\n");
7408 }
7409 numeof++;
7410 } else if (n != NULL && nflag == 0) {
7411 job_warning = (job_warning == 2) ? 1 : 0;
7412 numeof = 0;
7413 evaltree(n, 0);
7414 }
7415 popstackmark(&smark);
7416 setstackmark(&smark);
7417 if (evalskip == SKIPFILE) {
7418 evalskip = 0;
7419 break;
7420 }
7421 }
7422 popstackmark(&smark);
7423}
7424
7425
7426
7427/*
7428 * Read /etc/profile or .profile. Return on error.
7429 */
7430
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007431static void read_profile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00007432{
7433 int fd;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007434 int xflag_save;
7435 int vflag_save;
Eric Andersencb57d552001-06-28 07:25:16 +00007436
7437 INTOFF;
7438 if ((fd = open(name, O_RDONLY)) >= 0)
7439 setinputfd(fd, 1);
7440 INTON;
7441 if (fd < 0)
7442 return;
7443 /* -q turns off -x and -v just when executing init files */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007444 /* Note: Might do a little redundant work, but reduces code size. */
7445 xflag_save = xflag;
7446 vflag_save = vflag;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007447 if (qflag) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007448 vflag = xflag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007449 }
7450 cmdloop(0);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007451 xflag = xflag_save;
7452 vflag = vflag_save;
Eric Andersencb57d552001-06-28 07:25:16 +00007453 popfile();
7454}
7455
7456
7457
7458/*
7459 * Read a file containing shell functions.
7460 */
7461
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007462static void readcmdfile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00007463{
7464 int fd;
7465
7466 INTOFF;
7467 if ((fd = open(name, O_RDONLY)) >= 0)
7468 setinputfd(fd, 1);
7469 else
7470 error("Can't open %s", name);
7471 INTON;
7472 cmdloop(0);
7473 popfile();
7474}
7475
7476
7477
7478/*
7479 * Take commands from a file. To be compatable we should do a path
7480 * search for the file, which is necessary to find sub-commands.
7481 */
7482
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007483static inline char *find_dot_file(char *mybasename)
Eric Andersencb57d552001-06-28 07:25:16 +00007484{
7485 char *fullname;
7486 const char *path = pathval();
7487 struct stat statb;
7488
7489 /* don't try this for absolute or relative paths */
7490 if (strchr(mybasename, '/'))
7491 return mybasename;
7492
7493 while ((fullname = padvance(&path, mybasename)) != NULL) {
7494 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
7495 /*
7496 * Don't bother freeing here, since it will
7497 * be freed by the caller.
7498 */
7499 return fullname;
7500 }
7501 stunalloc(fullname);
7502 }
7503
7504 /* not found in the PATH */
7505 error("%s: not found", mybasename);
7506 /* NOTREACHED */
7507}
7508
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007509static int dotcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007510{
7511 struct strlist *sp;
Eric Andersen69a20f02001-10-31 10:40:37 +00007512 volatile struct shparam saveparam;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007513
Eric Andersencb57d552001-06-28 07:25:16 +00007514 exitstatus = 0;
7515
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007516 for (sp = cmdenviron; sp; sp = sp->next)
7517 setvareq(xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +00007518
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007519 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00007520 char *fullname;
7521 struct stackmark smark;
7522
7523 setstackmark(&smark);
7524 fullname = find_dot_file(argv[1]);
Eric Andersen69a20f02001-10-31 10:40:37 +00007525
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007526 if (argc > 2) {
Eric Andersen69a20f02001-10-31 10:40:37 +00007527 saveparam = shellparam;
7528 shellparam.malloc = 0;
7529 shellparam.nparam = argc - 2;
7530 shellparam.p = argv + 2;
7531 };
7532
Eric Andersencb57d552001-06-28 07:25:16 +00007533 setinputfile(fullname, 1);
7534 commandname = fullname;
7535 cmdloop(0);
7536 popfile();
Eric Andersen69a20f02001-10-31 10:40:37 +00007537
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007538 if (argc > 2) {
Eric Andersen69a20f02001-10-31 10:40:37 +00007539 freeparam(&shellparam);
7540 shellparam = saveparam;
7541 };
7542
Eric Andersencb57d552001-06-28 07:25:16 +00007543 popstackmark(&smark);
7544 }
7545 return exitstatus;
7546}
7547
7548
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007549static int exitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007550{
7551 if (stoppedjobs())
7552 return 0;
Robert Griebl350d26b2002-12-03 22:45:46 +00007553#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7554 if ( iflag )
7555 save_history ( ".ash_history" );
7556#endif
7557
Eric Andersencb57d552001-06-28 07:25:16 +00007558 if (argc > 1)
7559 exitstatus = number(argv[1]);
7560 else
7561 exitstatus = oexitstatus;
7562 exitshell(exitstatus);
7563 /* NOTREACHED */
7564}
Eric Andersen62483552001-07-10 06:09:16 +00007565
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007566static pointer stalloc(int nbytes)
Eric Andersencb57d552001-06-28 07:25:16 +00007567{
7568 char *p;
7569
7570 nbytes = ALIGN(nbytes);
7571 if (nbytes > stacknleft) {
7572 int blocksize;
7573 struct stack_block *sp;
7574
7575 blocksize = nbytes;
7576 if (blocksize < MINSIZE)
7577 blocksize = MINSIZE;
7578 INTOFF;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007579 sp = xmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
Eric Andersencb57d552001-06-28 07:25:16 +00007580 sp->prev = stackp;
7581 stacknxt = sp->space;
7582 stacknleft = blocksize;
7583 stackp = sp;
7584 INTON;
7585 }
7586 p = stacknxt;
7587 stacknxt += nbytes;
7588 stacknleft -= nbytes;
7589 return p;
7590}
7591
7592
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007593static void stunalloc(pointer p)
Eric Andersen2870d962001-07-02 17:27:21 +00007594{
Eric Andersencb57d552001-06-28 07:25:16 +00007595#ifdef DEBUG
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007596 if (p == NULL) { /*DEBUG */
Eric Andersencb57d552001-06-28 07:25:16 +00007597 write(2, "stunalloc\n", 10);
7598 abort();
7599 }
7600#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007601 if (!(stacknxt >= (char *) p && (char *) p >= stackp->space)) {
Eric Andersencb57d552001-06-28 07:25:16 +00007602 p = stackp->space;
7603 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007604 stacknleft += stacknxt - (char *) p;
Eric Andersencb57d552001-06-28 07:25:16 +00007605 stacknxt = p;
7606}
7607
7608
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007609static void setstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00007610{
Eric Andersencb57d552001-06-28 07:25:16 +00007611 mark->stackp = stackp;
7612 mark->stacknxt = stacknxt;
7613 mark->stacknleft = stacknleft;
7614 mark->marknext = markp;
7615 markp = mark;
7616}
7617
7618
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007619static void popstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00007620{
Eric Andersencb57d552001-06-28 07:25:16 +00007621 struct stack_block *sp;
7622
7623 INTOFF;
7624 markp = mark->marknext;
7625 while (stackp != mark->stackp) {
7626 sp = stackp;
7627 stackp = sp->prev;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00007628 free(sp);
Eric Andersencb57d552001-06-28 07:25:16 +00007629 }
7630 stacknxt = mark->stacknxt;
7631 stacknleft = mark->stacknleft;
7632 INTON;
7633}
7634
7635
7636/*
7637 * When the parser reads in a string, it wants to stick the string on the
7638 * stack and only adjust the stack pointer when it knows how big the
7639 * string is. Stackblock (defined in stack.h) returns a pointer to a block
7640 * of space on top of the stack and stackblocklen returns the length of
7641 * this block. Growstackblock will grow this space by at least one byte,
7642 * possibly moving it (like realloc). Grabstackblock actually allocates the
7643 * part of the block that has been used.
7644 */
7645
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007646static void growstackblock(void)
7647{
Eric Andersencb57d552001-06-28 07:25:16 +00007648 char *p;
7649 int newlen = ALIGN(stacknleft * 2 + 100);
7650 char *oldspace = stacknxt;
7651 int oldlen = stacknleft;
7652 struct stack_block *sp;
7653 struct stack_block *oldstackp;
7654
7655 if (stacknxt == stackp->space && stackp != &stackbase) {
7656 INTOFF;
7657 oldstackp = stackp;
7658 sp = stackp;
7659 stackp = sp->prev;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007660 sp = xrealloc((pointer) sp,
7661 sizeof(struct stack_block) - MINSIZE + newlen);
Eric Andersencb57d552001-06-28 07:25:16 +00007662 sp->prev = stackp;
7663 stackp = sp;
7664 stacknxt = sp->space;
7665 stacknleft = newlen;
7666 {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007667 /* Stack marks pointing to the start of the old block
7668 * must be relocated to point to the new block
7669 */
7670 struct stackmark *xmark;
7671
7672 xmark = markp;
7673 while (xmark != NULL && xmark->stackp == oldstackp) {
7674 xmark->stackp = stackp;
7675 xmark->stacknxt = stacknxt;
7676 xmark->stacknleft = stacknleft;
7677 xmark = xmark->marknext;
7678 }
Eric Andersencb57d552001-06-28 07:25:16 +00007679 }
7680 INTON;
7681 } else {
7682 p = stalloc(newlen);
7683 memcpy(p, oldspace, oldlen);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007684 stacknxt = p; /* free the space */
7685 stacknleft += newlen; /* we just allocated */
Eric Andersencb57d552001-06-28 07:25:16 +00007686 }
7687}
7688
7689
7690
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007691static inline void grabstackblock(int len)
Eric Andersencb57d552001-06-28 07:25:16 +00007692{
7693 len = ALIGN(len);
7694 stacknxt += len;
7695 stacknleft -= len;
7696}
7697
7698
7699
7700/*
7701 * The following routines are somewhat easier to use that the above.
7702 * The user declares a variable of type STACKSTR, which may be declared
7703 * to be a register. The macro STARTSTACKSTR initializes things. Then
7704 * the user uses the macro STPUTC to add characters to the string. In
7705 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
7706 * grown as necessary. When the user is done, she can just leave the
7707 * string there and refer to it using stackblock(). Or she can allocate
7708 * the space for it using grabstackstr(). If it is necessary to allow
7709 * someone else to use the stack temporarily and then continue to grow
7710 * the string, the user should use grabstack to allocate the space, and
7711 * then call ungrabstr(p) to return to the previous mode of operation.
7712 *
7713 * USTPUTC is like STPUTC except that it doesn't check for overflow.
7714 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
7715 * is space for at least one character.
7716 */
7717
7718
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007719static char *growstackstr(void)
7720{
Eric Andersencb57d552001-06-28 07:25:16 +00007721 int len = stackblocksize();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007722
Eric Andersencb57d552001-06-28 07:25:16 +00007723 if (herefd >= 0 && len >= 1024) {
7724 xwrite(herefd, stackblock(), len);
7725 sstrnleft = len - 1;
7726 return stackblock();
7727 }
7728 growstackblock();
7729 sstrnleft = stackblocksize() - len - 1;
7730 return stackblock() + len;
7731}
7732
7733
7734/*
7735 * Called from CHECKSTRSPACE.
7736 */
7737
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007738static char *makestrspace(size_t newlen)
7739{
Eric Andersencb57d552001-06-28 07:25:16 +00007740 int len = stackblocksize() - sstrnleft;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007741
Eric Andersencb57d552001-06-28 07:25:16 +00007742 do {
7743 growstackblock();
7744 sstrnleft = stackblocksize() - len;
7745 } while (sstrnleft < newlen);
7746 return stackblock() + len;
7747}
7748
7749
7750
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007751static void ungrabstackstr(char *s, char *p)
Eric Andersen2870d962001-07-02 17:27:21 +00007752{
Eric Andersencb57d552001-06-28 07:25:16 +00007753 stacknleft += stacknxt - s;
7754 stacknxt = s;
7755 sstrnleft = stacknleft - (p - s);
7756}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007757
Eric Andersencb57d552001-06-28 07:25:16 +00007758/*
7759 * Miscelaneous builtins.
7760 */
7761
7762
7763#undef rflag
7764
Eric Andersencb57d552001-06-28 07:25:16 +00007765#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersen62483552001-07-10 06:09:16 +00007766typedef long rlim_t;
Eric Andersencb57d552001-06-28 07:25:16 +00007767#endif
7768
7769
7770
7771/*
7772 * The read builtin. The -e option causes backslashes to escape the
7773 * following character.
7774 *
7775 * This uses unbuffered input, which may be avoidable in some cases.
7776 */
7777
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007778static int readcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007779{
7780 char **ap;
7781 int backslash;
7782 char c;
7783 int rflag;
7784 char *prompt;
7785 const char *ifs;
7786 char *p;
7787 int startword;
7788 int status;
7789 int i;
7790
7791 rflag = 0;
7792 prompt = NULL;
7793 while ((i = nextopt("p:r")) != '\0') {
7794 if (i == 'p')
7795 prompt = optionarg;
7796 else
7797 rflag = 1;
7798 }
7799 if (prompt && isatty(0)) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007800 out2str(prompt); /* read without cmdedit */
Eric Andersencb57d552001-06-28 07:25:16 +00007801 flushall();
7802 }
7803 if (*(ap = argptr) == NULL)
7804 error("arg count");
7805 if ((ifs = bltinlookup("IFS")) == NULL)
7806 ifs = defifs;
7807 status = 0;
7808 startword = 1;
7809 backslash = 0;
7810 STARTSTACKSTR(p);
7811 for (;;) {
7812 if (read(0, &c, 1) != 1) {
7813 status = 1;
7814 break;
7815 }
7816 if (c == '\0')
7817 continue;
7818 if (backslash) {
7819 backslash = 0;
7820 if (c != '\n')
7821 STPUTC(c, p);
7822 continue;
7823 }
7824 if (!rflag && c == '\\') {
7825 backslash++;
7826 continue;
7827 }
7828 if (c == '\n')
7829 break;
7830 if (startword && *ifs == ' ' && strchr(ifs, c)) {
7831 continue;
7832 }
7833 startword = 0;
7834 if (backslash && c == '\\') {
7835 if (read(0, &c, 1) != 1) {
7836 status = 1;
7837 break;
7838 }
7839 STPUTC(c, p);
7840 } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
7841 STACKSTRNUL(p);
7842 setvar(*ap, stackblock(), 0);
7843 ap++;
7844 startword = 1;
7845 STARTSTACKSTR(p);
7846 } else {
7847 STPUTC(c, p);
7848 }
7849 }
7850 STACKSTRNUL(p);
7851 /* Remove trailing blanks */
7852 while (stackblock() <= --p && strchr(ifs, *p) != NULL)
7853 *p = '\0';
7854 setvar(*ap, stackblock(), 0);
7855 while (*++ap != NULL)
7856 setvar(*ap, nullstr, 0);
7857 return status;
7858}
7859
7860
7861
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007862static int umaskcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007863{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007864 static const char permuser[3] = "ugo";
7865 static const char permmode[3] = "rwx";
7866 static const short int permmask[] = {
7867 S_IRUSR, S_IWUSR, S_IXUSR,
7868 S_IRGRP, S_IWGRP, S_IXGRP,
7869 S_IROTH, S_IWOTH, S_IXOTH
7870 };
7871
Eric Andersencb57d552001-06-28 07:25:16 +00007872 char *ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007873 mode_t mask;
Eric Andersencb57d552001-06-28 07:25:16 +00007874 int i;
7875 int symbolic_mode = 0;
7876
Eric Andersen62483552001-07-10 06:09:16 +00007877 while (nextopt("S") != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00007878 symbolic_mode = 1;
7879 }
7880
7881 INTOFF;
7882 mask = umask(0);
7883 umask(mask);
7884 INTON;
7885
7886 if ((ap = *argptr) == NULL) {
7887 if (symbolic_mode) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007888 char buf[18];
7889 char *p = buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007890
7891 for (i = 0; i < 3; i++) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007892 int j;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007893
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007894 *p++ = permuser[i];
7895 *p++ = '=';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007896 for (j = 0; j < 3; j++) {
7897 if ((mask & permmask[3 * i + j]) == 0) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007898 *p++ = permmode[j];
7899 }
7900 }
7901 *p++ = ',';
7902 }
7903 *--p = 0;
7904 puts(buf);
Eric Andersencb57d552001-06-28 07:25:16 +00007905 } else {
Eric Andersen62483552001-07-10 06:09:16 +00007906 printf("%.4o\n", mask);
Eric Andersencb57d552001-06-28 07:25:16 +00007907 }
7908 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007909 if (is_digit((unsigned char) *ap)) {
Eric Andersencb57d552001-06-28 07:25:16 +00007910 mask = 0;
7911 do {
7912 if (*ap >= '8' || *ap < '0')
7913 error("Illegal number: %s", argv[1]);
7914 mask = (mask << 3) + (*ap - '0');
7915 } while (*++ap != '\0');
7916 umask(mask);
7917 } else {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007918 mask = ~mask & 0777;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007919 if (!parse_mode(ap, &mask)) {
Eric Andersencb57d552001-06-28 07:25:16 +00007920 error("Illegal mode: %s", ap);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007921 }
Eric Andersencb57d552001-06-28 07:25:16 +00007922 umask(~mask & 0777);
7923 }
7924 }
7925 return 0;
7926}
7927
7928/*
7929 * ulimit builtin
7930 *
7931 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
7932 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
7933 * ash by J.T. Conklin.
7934 *
7935 * Public domain.
7936 */
7937
7938struct limits {
7939 const char *name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007940 short cmd;
7941 short factor; /* multiply by to get rlim_{cur,max} values */
Eric Andersencb57d552001-06-28 07:25:16 +00007942};
7943
7944static const struct limits limits[] = {
7945#ifdef RLIMIT_CPU
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007946 {"time(seconds)", RLIMIT_CPU, 1},
Eric Andersencb57d552001-06-28 07:25:16 +00007947#endif
7948#ifdef RLIMIT_FSIZE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007949 {"file(blocks)", RLIMIT_FSIZE, 512},
Eric Andersencb57d552001-06-28 07:25:16 +00007950#endif
7951#ifdef RLIMIT_DATA
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007952 {"data(kbytes)", RLIMIT_DATA, 1024},
Eric Andersencb57d552001-06-28 07:25:16 +00007953#endif
7954#ifdef RLIMIT_STACK
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007955 {"stack(kbytes)", RLIMIT_STACK, 1024},
Eric Andersencb57d552001-06-28 07:25:16 +00007956#endif
7957#ifdef RLIMIT_CORE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007958 {"coredump(blocks)", RLIMIT_CORE, 512},
Eric Andersencb57d552001-06-28 07:25:16 +00007959#endif
7960#ifdef RLIMIT_RSS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007961 {"memory(kbytes)", RLIMIT_RSS, 1024},
Eric Andersencb57d552001-06-28 07:25:16 +00007962#endif
7963#ifdef RLIMIT_MEMLOCK
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007964 {"locked memory(kbytes)", RLIMIT_MEMLOCK, 1024},
Eric Andersencb57d552001-06-28 07:25:16 +00007965#endif
7966#ifdef RLIMIT_NPROC
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007967 {"process(processes)", RLIMIT_NPROC, 1},
Eric Andersencb57d552001-06-28 07:25:16 +00007968#endif
7969#ifdef RLIMIT_NOFILE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007970 {"nofiles(descriptors)", RLIMIT_NOFILE, 1},
Eric Andersencb57d552001-06-28 07:25:16 +00007971#endif
7972#ifdef RLIMIT_VMEM
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007973 {"vmemory(kbytes)", RLIMIT_VMEM, 1024},
Eric Andersencb57d552001-06-28 07:25:16 +00007974#endif
7975#ifdef RLIMIT_SWAP
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007976 {"swap(kbytes)", RLIMIT_SWAP, 1024},
Eric Andersencb57d552001-06-28 07:25:16 +00007977#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007978 {NULL, 0, 0}
Eric Andersencb57d552001-06-28 07:25:16 +00007979};
7980
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007981static int ulimitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007982{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007983 static const char unlimited_string[] = "unlimited";
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007984 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00007985 rlim_t val = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007986 enum { SOFT = 0x1, HARD = 0x2 } how = SOFT | HARD;
7987 const struct limits *l;
7988 int set, all = 0;
7989 int optc, what;
7990 struct rlimit limit;
Eric Andersencb57d552001-06-28 07:25:16 +00007991
7992 what = 'f';
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007993
7994 while ((optc = nextopt("HSa"
7995#ifdef RLIMIT_CPU
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007996 "t"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007997#endif
7998#ifdef RLIMIT_FSIZE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007999 "f"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008000#endif
8001#ifdef RLIMIT_DATA
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008002 "d"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008003#endif
8004#ifdef RLIMIT_STACK
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008005 "s"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008006#endif
8007#ifdef RLIMIT_CORE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008008 "c"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008009#endif
8010#ifdef RLIMIT_RSS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008011 "m"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008012#endif
8013#ifdef RLIMIT_MEMLOCK
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008014 "l"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008015#endif
8016#ifdef RLIMIT_NPROC
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008017 "p"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008018#endif
8019#ifdef RLIMIT_NOFILE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008020 "n"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008021#endif
8022#ifdef RLIMIT_VMEM
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008023 "v"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008024#endif
8025#ifdef RLIMIT_SWAP
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008026 "w"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008027#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008028 )) != '\0') {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008029 if (optc == 'H') {
Eric Andersencb57d552001-06-28 07:25:16 +00008030 how = HARD;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008031 } else if (optc == 'S') {
Eric Andersencb57d552001-06-28 07:25:16 +00008032 how = SOFT;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008033 } else if (optc == 'a') {
Eric Andersencb57d552001-06-28 07:25:16 +00008034 all = 1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008035 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00008036 what = optc;
8037 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008038 }
Eric Andersencb57d552001-06-28 07:25:16 +00008039
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008040 for (l = limits; l->name; l++) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008041 if (l->name[0] == what)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008042 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008043 if (l->name[1] == 'w' && what == 'w')
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008044 break;
8045 }
Eric Andersencb57d552001-06-28 07:25:16 +00008046
8047 set = *argptr ? 1 : 0;
8048 if (set) {
8049 char *p = *argptr;
8050
8051 if (all || argptr[1])
8052 error("too many arguments");
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008053 if (strcmp(p, unlimited_string) == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00008054 val = RLIM_INFINITY;
8055 else {
8056 val = (rlim_t) 0;
8057
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008058 while ((c = *p++) >= '0' && c <= '9') {
8059 val = (val * 10) + (long) (c - '0');
Eric Andersencb57d552001-06-28 07:25:16 +00008060 if (val < (rlim_t) 0)
8061 break;
8062 }
8063 if (c)
8064 error("bad number");
8065 val *= l->factor;
8066 }
8067 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008068
Eric Andersencb57d552001-06-28 07:25:16 +00008069 if (all) {
8070 for (l = limits; l->name; l++) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008071 printf("%-20s ", l->name);
Eric Andersencb57d552001-06-28 07:25:16 +00008072 getrlimit(l->cmd, &limit);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008073 OUTPUT_LIMIT:
Eric Andersencb57d552001-06-28 07:25:16 +00008074 if (how & SOFT)
8075 val = limit.rlim_cur;
8076 else if (how & HARD)
8077 val = limit.rlim_max;
8078
Eric Andersencb57d552001-06-28 07:25:16 +00008079 if (val == RLIM_INFINITY)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008080 puts(unlimited_string);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008081 else {
Eric Andersencb57d552001-06-28 07:25:16 +00008082 val /= l->factor;
Eric Andersen62483552001-07-10 06:09:16 +00008083 printf("%lld\n", (long long) val);
Eric Andersencb57d552001-06-28 07:25:16 +00008084 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008085 if (!all) {
8086 break;
8087 }
Eric Andersencb57d552001-06-28 07:25:16 +00008088 }
8089 return 0;
8090 }
8091
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008092 if (!set) {
8093 goto OUTPUT_LIMIT;
Eric Andersencb57d552001-06-28 07:25:16 +00008094 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008095
8096 getrlimit(l->cmd, &limit);
8097 if (how & HARD)
8098 limit.rlim_max = val;
8099 if (how & SOFT)
8100 limit.rlim_cur = val;
8101 if (setrlimit(l->cmd, &limit) < 0)
8102 error("error setting limit (%m)");
Eric Andersencb57d552001-06-28 07:25:16 +00008103 return 0;
8104}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008105
Eric Andersencb57d552001-06-28 07:25:16 +00008106/*
8107 * prefix -- see if pfx is a prefix of string.
8108 */
8109
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008110static int prefix(char const *pfx, char const *string)
Eric Andersen62483552001-07-10 06:09:16 +00008111{
Eric Andersencb57d552001-06-28 07:25:16 +00008112 while (*pfx) {
8113 if (*pfx++ != *string++)
8114 return 0;
8115 }
8116 return 1;
8117}
8118
Eric Andersen2870d962001-07-02 17:27:21 +00008119/*
8120 * Return true if s is a string of digits, and save munber in intptr
8121 * nagative is bad
8122 */
8123
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008124static int is_number(const char *p, int *intptr)
Eric Andersen2870d962001-07-02 17:27:21 +00008125{
8126 int ret = 0;
8127
8128 do {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008129 if (!is_digit(*p))
Eric Andersen2870d962001-07-02 17:27:21 +00008130 return 0;
8131 ret *= 10;
8132 ret += digit_val(*p);
8133 p++;
8134 } while (*p != '\0');
8135
8136 *intptr = ret;
8137 return 1;
8138}
Eric Andersencb57d552001-06-28 07:25:16 +00008139
8140/*
8141 * Convert a string of digits to an integer, printing an error message on
8142 * failure.
8143 */
8144
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008145static int number(const char *s)
Eric Andersen2870d962001-07-02 17:27:21 +00008146{
8147 int i;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008148
8149 if (!is_number(s, &i))
Eric Andersencb57d552001-06-28 07:25:16 +00008150 error("Illegal number: %s", s);
Eric Andersen2870d962001-07-02 17:27:21 +00008151 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00008152}
8153
Eric Andersencb57d552001-06-28 07:25:16 +00008154/*
8155 * Produce a possibly single quoted string suitable as input to the shell.
8156 * The return string is allocated on the stack.
8157 */
8158
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008159static char *single_quote(const char *s)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008160{
Eric Andersencb57d552001-06-28 07:25:16 +00008161 char *p;
8162
8163 STARTSTACKSTR(p);
8164
8165 do {
8166 char *q = p;
8167 size_t len1, len1p, len2, len2p;
8168
8169 len1 = strcspn(s, "'");
8170 len2 = strspn(s + len1, "'");
8171
8172 len1p = len1 ? len1 + 2 : len1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008173 len2p = len2 + ((len2 < 2) ? len2 : 2);
Eric Andersencb57d552001-06-28 07:25:16 +00008174
8175 CHECKSTRSPACE(len1p + len2p + 1, p);
8176
8177 if (len1) {
8178 *p = '\'';
Eric Andersencb57d552001-06-28 07:25:16 +00008179 q = p + 1 + len1;
8180 memcpy(p + 1, s, len1);
Eric Andersencb57d552001-06-28 07:25:16 +00008181 *q++ = '\'';
8182 s += len1;
8183 }
8184
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008185 if (len2 > 1) {
Eric Andersencb57d552001-06-28 07:25:16 +00008186 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008187 q += 1 + len2;
8188 memcpy(q + 1, s, len2);
8189 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008190 s += len2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008191 } else if (len2 == 1) {
8192 *q++ = '\\';
8193 *q = '\'';
8194 s++;
Eric Andersencb57d552001-06-28 07:25:16 +00008195 }
8196
8197 STADJUST(len1p + len2p, p);
8198 } while (*s);
8199
8200 USTPUTC(0, p);
8201
8202 return grabstackstr(p);
8203}
8204
8205/*
Eric Andersencb57d552001-06-28 07:25:16 +00008206 * Routine for dealing with parsed shell commands.
8207 */
8208
8209
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008210static void sizenodelist(const struct nodelist *);
8211static struct nodelist *copynodelist(const struct nodelist *);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008212static char *nodesavestr(const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00008213
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00008214#define CALCSIZE_TABLE
8215#define COPYNODE_TABLE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008216#if defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE)
8217/*
8218 * To collect a lot of redundant code in case statements for copynode()
8219 * and calcsize(), we implement a mini language here. Each type of node
8220 * struct has an associated instruction sequence that operates on its
8221 * members via their offsets. The instruction are pack in unsigned chars
8222 * with format IIDDDDDE where the bits are
8223 * I : part of the instruction opcode, which are
8224 * 00 : member is a pointer to another node
8225 * 40 : member is an integer
8226 * 80 : member is a pointer to a nodelist
8227 * CC : member is a pointer to a char string
8228 * D : data - the actual offset of the member to operate on in the struct
8229 * (since we assume bit 0 is set, it is not shifted)
8230 * E : flag signaling end of instruction sequence
8231 *
8232 * WARNING: In order to handle larger offsets for 64bit archs, this code
8233 * assumes that no offset can be an odd number and stores the
8234 * end-of-instructions flag in bit 0.
8235 */
8236
8237#define NODE_INTEGER 0x40
8238#define NODE_NODELIST 0x80
8239#define NODE_CHARPTR 0xC0
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008240#define NODE_NOMORE 0x01 /* Note: no offset should be odd (aligned) */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008241#define NODE_MBRMASK 0xC0
8242#define NODE_OFFSETMASK 0x3E
8243
8244static const unsigned char copynode_ops[35] = {
8245#define COPYNODE_OPS0 0
8246 offsetof(union node, nbinary.ch2),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008247 offsetof(union node, nbinary.ch1) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008248#define COPYNODE_OPS1 (COPYNODE_OPS0 + 2)
8249 offsetof(union node, ncmd.redirect),
8250 offsetof(union node, ncmd.args),
8251 offsetof(union node, ncmd.assign),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008252 offsetof(union node, ncmd.backgnd) | NODE_INTEGER | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008253#define COPYNODE_OPS2 (COPYNODE_OPS1 + 4)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008254 offsetof(union node, npipe.cmdlist) | NODE_NODELIST,
8255 offsetof(union node, npipe.backgnd) | NODE_INTEGER | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008256#define COPYNODE_OPS3 (COPYNODE_OPS2 + 2)
8257 offsetof(union node, nredir.redirect),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008258 offsetof(union node, nredir.n) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008259#define COPYNODE_OPS4 (COPYNODE_OPS3 + 2)
8260 offsetof(union node, nif.elsepart),
8261 offsetof(union node, nif.ifpart),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008262 offsetof(union node, nif.test) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008263#define COPYNODE_OPS5 (COPYNODE_OPS4 + 3)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008264 offsetof(union node, nfor.var) | NODE_CHARPTR,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008265 offsetof(union node, nfor.body),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008266 offsetof(union node, nfor.args) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008267#define COPYNODE_OPS6 (COPYNODE_OPS5 + 3)
8268 offsetof(union node, ncase.cases),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008269 offsetof(union node, ncase.expr) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008270#define COPYNODE_OPS7 (COPYNODE_OPS6 + 2)
8271 offsetof(union node, nclist.body),
8272 offsetof(union node, nclist.pattern),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008273 offsetof(union node, nclist.next) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008274#define COPYNODE_OPS8 (COPYNODE_OPS7 + 3)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008275 offsetof(union node, narg.backquote) | NODE_NODELIST,
8276 offsetof(union node, narg.text) | NODE_CHARPTR,
8277 offsetof(union node, narg.next) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008278#define COPYNODE_OPS9 (COPYNODE_OPS8 + 3)
8279 offsetof(union node, nfile.fname),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008280 offsetof(union node, nfile.fd) | NODE_INTEGER,
8281 offsetof(union node, nfile.next) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008282#define COPYNODE_OPS10 (COPYNODE_OPS9 + 3)
8283 offsetof(union node, ndup.vname),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008284 offsetof(union node, ndup.dupfd) | NODE_INTEGER,
8285 offsetof(union node, ndup.fd) | NODE_INTEGER,
8286 offsetof(union node, ndup.next) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008287#define COPYNODE_OPS11 (COPYNODE_OPS10 + 4)
8288 offsetof(union node, nhere.doc),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008289 offsetof(union node, nhere.fd) | NODE_INTEGER,
8290 offsetof(union node, nhere.next) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008291#define COPYNODE_OPS12 (COPYNODE_OPS11 + 3)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008292 offsetof(union node, nnot.com) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008293};
8294
8295#if COPYNODE_OPS12 != 34
8296#error COPYNODE_OPS12 is incorrect
8297#endif
8298
8299static const unsigned char copynode_ops_index[26] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008300 COPYNODE_OPS0, /* NSEMI */
8301 COPYNODE_OPS1, /* NCMD */
8302 COPYNODE_OPS2, /* NPIPE */
8303 COPYNODE_OPS3, /* NREDIR */
8304 COPYNODE_OPS3, /* NBACKGND */
8305 COPYNODE_OPS3, /* NSUBSHELL */
8306 COPYNODE_OPS0, /* NAND */
8307 COPYNODE_OPS0, /* NOR */
8308 COPYNODE_OPS4, /* NIF */
8309 COPYNODE_OPS0, /* NWHILE */
8310 COPYNODE_OPS0, /* NUNTIL */
8311 COPYNODE_OPS5, /* NFOR */
8312 COPYNODE_OPS6, /* NCASE */
8313 COPYNODE_OPS7, /* NCLIST */
8314 COPYNODE_OPS8, /* NDEFUN */
8315 COPYNODE_OPS8, /* NARG */
8316 COPYNODE_OPS9, /* NTO */
8317 COPYNODE_OPS9, /* NFROM */
8318 COPYNODE_OPS9, /* NFROMTO */
8319 COPYNODE_OPS9, /* NAPPEND */
8320 COPYNODE_OPS9, /* NTOOV */
8321 COPYNODE_OPS10, /* NTOFD */
8322 COPYNODE_OPS10, /* NFROMFD */
8323 COPYNODE_OPS11, /* NHERE */
8324 COPYNODE_OPS11, /* NXHERE */
8325 COPYNODE_OPS12, /* NNOT */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008326};
8327
8328#if NODE_CHARPTR != NODE_MBRMASK
8329#error NODE_CHARPTR != NODE_MBRMASK!!!
8330#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008331#endif /* defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE) */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008332
8333#ifdef COPYNODE_TABLE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008334static union node *copynode(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008335{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008336 union node *new;
8337 const unsigned char *p;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008338
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008339 if (n == NULL) {
8340 return NULL;
8341 }
8342 new = funcblock;
8343 new->type = n->type;
8344 funcblock = (char *) funcblock + (int) nodesize[n->type];
8345 p = copynode_ops + (int) copynode_ops_index[n->type];
8346 do {
8347 char *nn = ((char *) new) + ((int) (*p & NODE_OFFSETMASK));
8348 const char *no = ((const char *) n) + ((int) (*p & NODE_OFFSETMASK));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008349
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008350 if (!(*p & NODE_MBRMASK)) { /* standard node */
8351 *((union node **) nn) = copynode(*((const union node **) no));
8352 } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008353 *((const char **) nn) = nodesavestr(*((const char **) no));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008354 } else if (*p & NODE_NODELIST) { /* nodelist */
8355 *((struct nodelist **) nn)
8356 = copynodelist(*((const struct nodelist **) no));
8357 } else { /* integer */
8358 *((int *) nn) = *((int *) no);
8359 }
8360 } while (!(*p++ & NODE_NOMORE));
8361 return new;
Eric Andersencb57d552001-06-28 07:25:16 +00008362}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008363#else /* COPYNODE_TABLE */
8364static union node *copynode(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008365{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008366 union node *new;
Eric Andersencb57d552001-06-28 07:25:16 +00008367
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008368 if (n == NULL)
8369 return NULL;
8370 new = funcblock;
8371 funcblock = (char *) funcblock + nodesize[n->type];
8372 switch (n->type) {
8373 case NSEMI:
8374 case NAND:
8375 case NOR:
8376 case NWHILE:
8377 case NUNTIL:
8378 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8379 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8380 break;
8381 case NCMD:
8382 new->ncmd.redirect = copynode(n->ncmd.redirect);
8383 new->ncmd.args = copynode(n->ncmd.args);
8384 new->ncmd.assign = copynode(n->ncmd.assign);
8385 new->ncmd.backgnd = n->ncmd.backgnd;
8386 break;
8387 case NPIPE:
8388 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8389 new->npipe.backgnd = n->npipe.backgnd;
8390 break;
8391 case NREDIR:
8392 case NBACKGND:
8393 case NSUBSHELL:
8394 new->nredir.redirect = copynode(n->nredir.redirect);
8395 new->nredir.n = copynode(n->nredir.n);
8396 break;
8397 case NIF:
8398 new->nif.elsepart = copynode(n->nif.elsepart);
8399 new->nif.ifpart = copynode(n->nif.ifpart);
8400 new->nif.test = copynode(n->nif.test);
8401 break;
8402 case NFOR:
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008403 new->nfor.var = nodesavestr(n->nfor.var);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008404 new->nfor.body = copynode(n->nfor.body);
8405 new->nfor.args = copynode(n->nfor.args);
8406 break;
8407 case NCASE:
8408 new->ncase.cases = copynode(n->ncase.cases);
8409 new->ncase.expr = copynode(n->ncase.expr);
8410 break;
8411 case NCLIST:
8412 new->nclist.body = copynode(n->nclist.body);
8413 new->nclist.pattern = copynode(n->nclist.pattern);
8414 new->nclist.next = copynode(n->nclist.next);
8415 break;
8416 case NDEFUN:
8417 case NARG:
8418 new->narg.backquote = copynodelist(n->narg.backquote);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008419 new->narg.text = nodesavestr(n->narg.text);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008420 new->narg.next = copynode(n->narg.next);
8421 break;
8422 case NTO:
8423 case NFROM:
8424 case NFROMTO:
8425 case NAPPEND:
8426 case NTOOV:
8427 new->nfile.fname = copynode(n->nfile.fname);
8428 new->nfile.fd = n->nfile.fd;
8429 new->nfile.next = copynode(n->nfile.next);
8430 break;
8431 case NTOFD:
8432 case NFROMFD:
8433 new->ndup.vname = copynode(n->ndup.vname);
8434 new->ndup.dupfd = n->ndup.dupfd;
8435 new->ndup.fd = n->ndup.fd;
8436 new->ndup.next = copynode(n->ndup.next);
8437 break;
8438 case NHERE:
8439 case NXHERE:
8440 new->nhere.doc = copynode(n->nhere.doc);
8441 new->nhere.fd = n->nhere.fd;
8442 new->nhere.next = copynode(n->nhere.next);
8443 break;
8444 case NNOT:
8445 new->nnot.com = copynode(n->nnot.com);
8446 break;
8447 };
8448 new->type = n->type;
8449 return new;
Eric Andersencb57d552001-06-28 07:25:16 +00008450}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008451#endif /* COPYNODE_TABLE */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008452
8453#ifdef CALCSIZE_TABLE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008454static void calcsize(const union node *n)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008455{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008456 const unsigned char *p;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008457
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008458 if (n == NULL)
8459 return;
8460 funcblocksize += (int) nodesize[n->type];
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008461
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008462 p = copynode_ops + (int) copynode_ops_index[n->type];
8463 do {
8464 const char *no = ((const char *) n) + ((int) (*p & NODE_OFFSETMASK));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008465
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008466 if (!(*p & NODE_MBRMASK)) { /* standard node */
8467 calcsize(*((const union node **) no));
8468 } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
8469 funcstringsize += strlen(*((const char **) no)) + 1;
8470 } else if (*p & NODE_NODELIST) { /* nodelist */
8471 sizenodelist(*((const struct nodelist **) no));
8472 } /* else integer -- ignore */
8473 } while (!(*p++ & NODE_NOMORE));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008474}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008475#else /* CALCSIZE_TABLE */
8476static void calcsize(const union node *n)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008477{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008478 if (n == NULL)
8479 return;
8480 funcblocksize += nodesize[n->type];
8481 switch (n->type) {
8482 case NSEMI:
8483 case NAND:
8484 case NOR:
8485 case NWHILE:
8486 case NUNTIL:
8487 calcsize(n->nbinary.ch2);
8488 calcsize(n->nbinary.ch1);
8489 break;
8490 case NCMD:
8491 calcsize(n->ncmd.redirect);
8492 calcsize(n->ncmd.args);
8493 calcsize(n->ncmd.assign);
8494 break;
8495 case NPIPE:
8496 sizenodelist(n->npipe.cmdlist);
8497 break;
8498 case NREDIR:
8499 case NBACKGND:
8500 case NSUBSHELL:
8501 calcsize(n->nredir.redirect);
8502 calcsize(n->nredir.n);
8503 break;
8504 case NIF:
8505 calcsize(n->nif.elsepart);
8506 calcsize(n->nif.ifpart);
8507 calcsize(n->nif.test);
8508 break;
8509 case NFOR:
8510 funcstringsize += strlen(n->nfor.var) + 1;
8511 calcsize(n->nfor.body);
8512 calcsize(n->nfor.args);
8513 break;
8514 case NCASE:
8515 calcsize(n->ncase.cases);
8516 calcsize(n->ncase.expr);
8517 break;
8518 case NCLIST:
8519 calcsize(n->nclist.body);
8520 calcsize(n->nclist.pattern);
8521 calcsize(n->nclist.next);
8522 break;
8523 case NDEFUN:
8524 case NARG:
8525 sizenodelist(n->narg.backquote);
8526 funcstringsize += strlen(n->narg.text) + 1;
8527 calcsize(n->narg.next);
8528 break;
8529 case NTO:
8530 case NFROM:
8531 case NFROMTO:
8532 case NAPPEND:
8533 case NTOOV:
8534 calcsize(n->nfile.fname);
8535 calcsize(n->nfile.next);
8536 break;
8537 case NTOFD:
8538 case NFROMFD:
8539 calcsize(n->ndup.vname);
8540 calcsize(n->ndup.next);
8541 break;
8542 case NHERE:
8543 case NXHERE:
8544 calcsize(n->nhere.doc);
8545 calcsize(n->nhere.next);
8546 break;
8547 case NNOT:
8548 calcsize(n->nnot.com);
8549 break;
8550 };
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008551}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008552#endif /* CALCSIZE_TABLE */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008553
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008554static void sizenodelist(const struct nodelist *lp)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008555{
8556 while (lp) {
8557 funcblocksize += ALIGN(sizeof(struct nodelist));
8558 calcsize(lp->n);
8559 lp = lp->next;
8560 }
8561}
Eric Andersencb57d552001-06-28 07:25:16 +00008562
8563
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008564static struct nodelist *copynodelist(const struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008565{
8566 struct nodelist *start;
8567 struct nodelist **lpp;
8568
8569 lpp = &start;
8570 while (lp) {
8571 *lpp = funcblock;
8572 funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist));
8573 (*lpp)->n = copynode(lp->n);
8574 lp = lp->next;
8575 lpp = &(*lpp)->next;
8576 }
8577 *lpp = NULL;
8578 return start;
8579}
8580
8581
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008582static char *nodesavestr(const char *s)
Eric Andersencb57d552001-06-28 07:25:16 +00008583{
Eric Andersen62483552001-07-10 06:09:16 +00008584 const char *p = s;
8585 char *q = funcstring;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008586 char *rtn = funcstring;
Eric Andersencb57d552001-06-28 07:25:16 +00008587
8588 while ((*q++ = *p++) != '\0')
8589 continue;
8590 funcstring = q;
8591 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00008592}
8593
Eric Andersend35c5df2002-01-09 15:37:36 +00008594#ifdef CONFIG_ASH_GETOPTS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008595static int getopts(char *, char *, char **, int *, int *);
Eric Andersencb57d552001-06-28 07:25:16 +00008596#endif
8597
Eric Andersencb57d552001-06-28 07:25:16 +00008598/*
8599 * Process the shell command line arguments.
8600 */
8601
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008602static void procargs(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008603{
8604 int i;
8605
8606 argptr = argv;
8607 if (argc > 0)
8608 argptr++;
8609 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00008610 optent_val(i) = 2;
Eric Andersencb57d552001-06-28 07:25:16 +00008611 options(1);
8612 if (*argptr == NULL && minusc == NULL)
8613 sflag = 1;
8614 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8615 iflag = 1;
8616 if (mflag == 2)
8617 mflag = iflag;
8618 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00008619 if (optent_val(i) == 2)
8620 optent_val(i) = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008621 arg0 = argv[0];
8622 if (sflag == 0 && minusc == NULL) {
8623 commandname = argv[0];
8624 arg0 = *argptr++;
8625 setinputfile(arg0, 0);
8626 commandname = arg0;
8627 }
8628 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8629 if (argptr && minusc && *argptr)
Eric Andersen2870d962001-07-02 17:27:21 +00008630 arg0 = *argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00008631
8632 shellparam.p = argptr;
8633 shellparam.optind = 1;
8634 shellparam.optoff = -1;
8635 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8636 while (*argptr) {
8637 shellparam.nparam++;
8638 argptr++;
8639 }
8640 optschanged();
8641}
8642
8643
Eric Andersencb57d552001-06-28 07:25:16 +00008644
8645/*
8646 * Process shell options. The global variable argptr contains a pointer
8647 * to the argument list; we advance it past the options.
8648 */
8649
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008650static inline void minus_o(const char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +00008651{
8652 int i;
8653
8654 if (name == NULL) {
8655 out1str("Current option settings\n");
8656 for (i = 0; i < NOPTS; i++)
8657 printf("%-16s%s\n", optent_name(optlist[i]),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008658 optent_val(i) ? "on" : "off");
Eric Andersen62483552001-07-10 06:09:16 +00008659 } else {
8660 for (i = 0; i < NOPTS; i++)
8661 if (equal(name, optent_name(optlist[i]))) {
8662 setoption(optent_letter(optlist[i]), val);
8663 return;
8664 }
8665 error("Illegal option -o %s", name);
8666 }
8667}
8668
8669
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008670static void options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00008671{
8672 char *p;
8673 int val;
8674 int c;
8675
8676 if (cmdline)
8677 minusc = NULL;
8678 while ((p = *argptr) != NULL) {
8679 argptr++;
8680 if ((c = *p++) == '-') {
8681 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00008682 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8683 if (!cmdline) {
8684 /* "-" means turn off -x and -v */
8685 if (p[0] == '\0')
8686 xflag = vflag = 0;
8687 /* "--" means reset params */
8688 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00008689 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00008690 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008691 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00008692 }
8693 } else if (c == '+') {
8694 val = 0;
8695 } else {
8696 argptr--;
8697 break;
8698 }
8699 while ((c = *p++) != '\0') {
8700 if (c == 'c' && cmdline) {
8701 char *q;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008702
8703#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */
Eric Andersencb57d552001-06-28 07:25:16 +00008704 if (*p == '\0')
8705#endif
8706 q = *argptr++;
8707 if (q == NULL || minusc != NULL)
8708 error("Bad -c option");
8709 minusc = q;
8710#ifdef NOHACK
8711 break;
8712#endif
8713 } else if (c == 'o') {
8714 minus_o(*argptr, val);
8715 if (*argptr)
8716 argptr++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008717 } else if (cmdline && (c == '-')) { // long options
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008718 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +00008719 isloginsh = 1;
8720 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008721 } else {
8722 setoption(c, val);
8723 }
8724 }
8725 }
8726}
8727
Eric Andersencb57d552001-06-28 07:25:16 +00008728
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008729static void setoption(int flag, int val)
Eric Andersen2870d962001-07-02 17:27:21 +00008730{
Eric Andersencb57d552001-06-28 07:25:16 +00008731 int i;
8732
8733 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00008734 if (optent_letter(optlist[i]) == flag) {
8735 optent_val(i) = val;
Eric Andersencb57d552001-06-28 07:25:16 +00008736 if (val) {
8737 /* #%$ hack for ksh semantics */
8738 if (flag == 'V')
8739 Eflag = 0;
8740 else if (flag == 'E')
8741 Vflag = 0;
8742 }
8743 return;
8744 }
8745 error("Illegal option -%c", flag);
8746 /* NOTREACHED */
8747}
8748
8749
8750
Eric Andersencb57d552001-06-28 07:25:16 +00008751/*
8752 * Set the shell parameters.
8753 */
8754
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008755static void setparam(char **argv)
Eric Andersen2870d962001-07-02 17:27:21 +00008756{
Eric Andersencb57d552001-06-28 07:25:16 +00008757 char **newparam;
8758 char **ap;
8759 int nparam;
8760
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008761 for (nparam = 0; argv[nparam]; nparam++);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008762 ap = newparam = xmalloc((nparam + 1) * sizeof *ap);
Eric Andersencb57d552001-06-28 07:25:16 +00008763 while (*argv) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008764 *ap++ = xstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +00008765 }
8766 *ap = NULL;
8767 freeparam(&shellparam);
8768 shellparam.malloc = 1;
8769 shellparam.nparam = nparam;
8770 shellparam.p = newparam;
8771 shellparam.optind = 1;
8772 shellparam.optoff = -1;
8773}
8774
8775
8776/*
8777 * Free the list of positional parameters.
8778 */
8779
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008780static void freeparam(volatile struct shparam *param)
Eric Andersen2870d962001-07-02 17:27:21 +00008781{
Eric Andersencb57d552001-06-28 07:25:16 +00008782 char **ap;
8783
8784 if (param->malloc) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008785 for (ap = param->p; *ap; ap++)
Aaron Lehmann49c024a2002-08-02 06:39:47 +00008786 free(*ap);
8787 free(param->p);
Eric Andersencb57d552001-06-28 07:25:16 +00008788 }
8789}
8790
8791
8792
8793/*
8794 * The shift builtin command.
8795 */
8796
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008797static int shiftcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008798{
8799 int n;
8800 char **ap1, **ap2;
8801
8802 n = 1;
8803 if (argc > 1)
8804 n = number(argv[1]);
8805 if (n > shellparam.nparam)
8806 error("can't shift that many");
8807 INTOFF;
8808 shellparam.nparam -= n;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008809 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Eric Andersencb57d552001-06-28 07:25:16 +00008810 if (shellparam.malloc)
Aaron Lehmann49c024a2002-08-02 06:39:47 +00008811 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +00008812 }
8813 ap2 = shellparam.p;
8814 while ((*ap2++ = *ap1++) != NULL);
8815 shellparam.optind = 1;
8816 shellparam.optoff = -1;
8817 INTON;
8818 return 0;
8819}
8820
8821
8822
8823/*
8824 * The set command builtin.
8825 */
8826
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008827static int setcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008828{
8829 if (argc == 1)
8830 return showvarscmd(argc, argv);
8831 INTOFF;
8832 options(0);
8833 optschanged();
8834 if (*argptr != NULL) {
8835 setparam(argptr);
8836 }
8837 INTON;
8838 return 0;
8839}
8840
8841
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008842static void getoptsreset(const char *value)
Eric Andersencb57d552001-06-28 07:25:16 +00008843{
8844 shellparam.optind = number(value);
8845 shellparam.optoff = -1;
8846}
8847
Eric Andersenbdfd0d72001-10-24 05:00:29 +00008848#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00008849static void change_lc_all(const char *value)
8850{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008851 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00008852 setlocale(LC_ALL, value);
8853}
8854
8855static void change_lc_ctype(const char *value)
8856{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008857 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00008858 setlocale(LC_CTYPE, value);
8859}
8860
8861#endif
8862
Eric Andersend35c5df2002-01-09 15:37:36 +00008863#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008864/*
8865 * The getopts builtin. Shellparam.optnext points to the next argument
8866 * to be processed. Shellparam.optptr points to the next character to
8867 * be processed in the current argument. If shellparam.optnext is NULL,
8868 * then it's the first time getopts has been called.
8869 */
8870
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008871static int getoptscmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008872{
8873 char **optbase;
8874
8875 if (argc < 3)
8876 error("Usage: getopts optstring var [arg]");
8877 else if (argc == 3) {
8878 optbase = shellparam.p;
8879 if (shellparam.optind > shellparam.nparam + 1) {
8880 shellparam.optind = 1;
8881 shellparam.optoff = -1;
8882 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008883 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00008884 optbase = &argv[3];
8885 if (shellparam.optind > argc - 2) {
8886 shellparam.optind = 1;
8887 shellparam.optoff = -1;
8888 }
8889 }
8890
8891 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008892 &shellparam.optoff);
Eric Andersencb57d552001-06-28 07:25:16 +00008893}
8894
8895/*
8896 * Safe version of setvar, returns 1 on success 0 on failure.
8897 */
8898
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008899static int setvarsafe(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008900{
8901 struct jmploc jmploc;
8902 struct jmploc *volatile savehandler = handler;
8903 int err = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008904
Eric Andersencb57d552001-06-28 07:25:16 +00008905#ifdef __GNUC__
8906 (void) &err;
8907#endif
8908
8909 if (setjmp(jmploc.loc))
8910 err = 1;
8911 else {
8912 handler = &jmploc;
8913 setvar(name, val, flags);
8914 }
8915 handler = savehandler;
8916 return err;
8917}
8918
8919static int
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008920getopts(char *optstr, char *optvar, char **optfirst, int *myoptind,
8921 int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00008922{
8923 char *p, *q;
8924 char c = '?';
8925 int done = 0;
8926 int err = 0;
8927 char s[10];
8928 char **optnext = optfirst + *myoptind - 1;
8929
8930 if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008931 strlen(*(optnext - 1)) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00008932 p = NULL;
8933 else
8934 p = *(optnext - 1) + *optoff;
8935 if (p == NULL || *p == '\0') {
8936 /* Current word is done, advance */
8937 if (optnext == NULL)
8938 return 1;
8939 p = *optnext;
8940 if (p == NULL || *p != '-' || *++p == '\0') {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008941 atend:
Eric Andersencb57d552001-06-28 07:25:16 +00008942 *myoptind = optnext - optfirst + 1;
8943 p = NULL;
8944 done = 1;
8945 goto out;
8946 }
8947 optnext++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008948 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00008949 goto atend;
8950 }
8951
8952 c = *p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008953 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +00008954 if (*q == '\0') {
8955 if (optstr[0] == ':') {
8956 s[0] = c;
8957 s[1] = '\0';
8958 err |= setvarsafe("OPTARG", s, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008959 } else {
Eric Andersen3102ac42001-07-06 04:26:23 +00008960 out2fmt("Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00008961 (void) unsetvar("OPTARG");
8962 }
8963 c = '?';
8964 goto bad;
8965 }
8966 if (*++q == ':')
8967 q++;
8968 }
8969
8970 if (*++q == ':') {
8971 if (*p == '\0' && (p = *optnext) == NULL) {
8972 if (optstr[0] == ':') {
8973 s[0] = c;
8974 s[1] = '\0';
8975 err |= setvarsafe("OPTARG", s, 0);
8976 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008977 } else {
Eric Andersen3102ac42001-07-06 04:26:23 +00008978 out2fmt("No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00008979 (void) unsetvar("OPTARG");
8980 c = '?';
8981 }
8982 goto bad;
8983 }
8984
8985 if (p == *optnext)
8986 optnext++;
8987 setvarsafe("OPTARG", p, 0);
8988 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008989 } else
Eric Andersencb57d552001-06-28 07:25:16 +00008990 setvarsafe("OPTARG", "", 0);
8991 *myoptind = optnext - optfirst + 1;
8992 goto out;
8993
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008994 bad:
Eric Andersencb57d552001-06-28 07:25:16 +00008995 *myoptind = 1;
8996 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008997 out:
Eric Andersencb57d552001-06-28 07:25:16 +00008998 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersen3102ac42001-07-06 04:26:23 +00008999 snprintf(s, sizeof(s), "%d", *myoptind);
Eric Andersencb57d552001-06-28 07:25:16 +00009000 err |= setvarsafe("OPTIND", s, VNOFUNC);
9001 s[0] = c;
9002 s[1] = '\0';
9003 err |= setvarsafe(optvar, s, 0);
9004 if (err) {
9005 *myoptind = 1;
9006 *optoff = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00009007 exraise(EXERROR);
9008 }
9009 return done;
9010}
Eric Andersen2870d962001-07-02 17:27:21 +00009011#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009012
9013/*
9014 * XXX - should get rid of. have all builtins use getopt(3). the
9015 * library getopt must have the BSD extension static variable "optreset"
9016 * otherwise it can't be used within the shell safely.
9017 *
9018 * Standard option processing (a la getopt) for builtin routines. The
9019 * only argument that is passed to nextopt is the option string; the
9020 * other arguments are unnecessary. It return the character, or '\0' on
9021 * end of input.
9022 */
9023
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009024static int nextopt(const char *optstring)
Eric Andersen62483552001-07-10 06:09:16 +00009025{
Eric Andersencb57d552001-06-28 07:25:16 +00009026 char *p;
9027 const char *q;
9028 char c;
9029
9030 if ((p = optptr) == NULL || *p == '\0') {
9031 p = *argptr;
9032 if (p == NULL || *p != '-' || *++p == '\0')
9033 return '\0';
9034 argptr++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009035 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009036 return '\0';
9037 }
9038 c = *p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009039 for (q = optstring; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +00009040 if (*q == '\0')
9041 error("Illegal option -%c", c);
9042 if (*++q == ':')
9043 q++;
9044 }
9045 if (*++q == ':') {
9046 if (*p == '\0' && (p = *argptr++) == NULL)
9047 error("No arg for -%c option", c);
9048 optionarg = p;
9049 p = NULL;
9050 }
9051 optptr = p;
9052 return c;
9053}
9054
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009055static void flushall()
9056{
Eric Andersencb57d552001-06-28 07:25:16 +00009057 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009058 fflush(stdout);
Eric Andersencb57d552001-06-28 07:25:16 +00009059 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009060}
9061
9062
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009063static void out2fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009064{
9065 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009066
Eric Andersencb57d552001-06-28 07:25:16 +00009067 va_start(ap, fmt);
Eric Andersen3102ac42001-07-06 04:26:23 +00009068 vfprintf(stderr, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009069 va_end(ap);
9070}
9071
Eric Andersencb57d552001-06-28 07:25:16 +00009072/*
9073 * Version of write which resumes after a signal is caught.
9074 */
9075
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009076static int xwrite(int fd, const char *buf, int nbytes)
Eric Andersen2870d962001-07-02 17:27:21 +00009077{
Eric Andersencb57d552001-06-28 07:25:16 +00009078 int ntry;
9079 int i;
9080 int n;
9081
9082 n = nbytes;
9083 ntry = 0;
9084 for (;;) {
9085 i = write(fd, buf, n);
9086 if (i > 0) {
9087 if ((n -= i) <= 0)
9088 return nbytes;
9089 buf += i;
9090 ntry = 0;
9091 } else if (i == 0) {
9092 if (++ntry > 10)
9093 return nbytes - n;
9094 } else if (errno != EINTR) {
9095 return -1;
9096 }
9097 }
9098}
9099
9100
Eric Andersencb57d552001-06-28 07:25:16 +00009101/*
9102 * Shell command parser.
9103 */
9104
9105#define EOFMARKLEN 79
9106
9107
9108
9109struct heredoc {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009110 struct heredoc *next; /* next here document in list */
9111 union node *here; /* redirection node */
9112 char *eofmark; /* string indicating end of input */
9113 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009114};
9115
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009116static struct heredoc *heredoclist; /* list of here documents to read */
9117static int parsebackquote; /* nonzero if we are inside backquotes */
9118static int doprompt; /* if set, prompt the user */
9119static int needprompt; /* true if interactive and at start of line */
9120static int lasttoken; /* last token read */
Eric Andersencb57d552001-06-28 07:25:16 +00009121
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009122static char *wordtext; /* text of last word returned by readtoken */
Eric Andersencb57d552001-06-28 07:25:16 +00009123
Eric Andersen2870d962001-07-02 17:27:21 +00009124static struct nodelist *backquotelist;
9125static union node *redirnode;
Eric Andersen044228d2001-07-17 01:12:36 +00009126static struct heredoc *heredoc;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009127static int quoteflag; /* set if (part of) last token was quoted */
9128static int startlinno; /* line # where last token started */
Eric Andersencb57d552001-06-28 07:25:16 +00009129
9130
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009131static union node *list(int);
9132static union node *andor(void);
9133static union node *pipeline(void);
9134static union node *command(void);
Eric Andersena3483db2001-10-24 08:01:06 +00009135static union node *simplecmd(union node **rpp, union node *redir);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009136static void parsefname(void);
9137static void parseheredoc(void);
9138static char peektoken(void);
9139static int readtoken(void);
9140static int xxreadtoken(void);
9141static int readtoken1(int, int, const char *, int);
9142static int noexpand(char *);
9143static void synexpect(int) __attribute__ ((noreturn));
9144static void synerror(const char *) __attribute__ ((noreturn));
9145static void setprompt(int);
Eric Andersencb57d552001-06-28 07:25:16 +00009146
9147
9148/*
9149 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9150 * valid parse tree indicating a blank line.)
9151 */
9152
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009153static union node *parsecmd(int interact)
Eric Andersencb57d552001-06-28 07:25:16 +00009154{
9155 int t;
9156
9157 tokpushback = 0;
9158 doprompt = interact;
9159 if (doprompt)
9160 setprompt(1);
9161 else
9162 setprompt(0);
9163 needprompt = 0;
9164 t = readtoken();
9165 if (t == TEOF)
9166 return NEOF;
9167 if (t == TNL)
9168 return NULL;
9169 tokpushback++;
9170 return list(1);
9171}
9172
9173
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009174static union node *list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +00009175{
9176 union node *n1, *n2, *n3;
9177 int tok;
9178
9179 checkkwd = 2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009180 if (nlflag == 0 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009181 return NULL;
9182 n1 = NULL;
9183 for (;;) {
9184 n2 = andor();
9185 tok = readtoken();
9186 if (tok == TBACKGND) {
9187 if (n2->type == NCMD || n2->type == NPIPE) {
9188 n2->ncmd.backgnd = 1;
9189 } else if (n2->type == NREDIR) {
9190 n2->type = NBACKGND;
9191 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009192 n3 = (union node *) stalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009193 n3->type = NBACKGND;
9194 n3->nredir.n = n2;
9195 n3->nredir.redirect = NULL;
9196 n2 = n3;
9197 }
9198 }
9199 if (n1 == NULL) {
9200 n1 = n2;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009201 } else {
9202 n3 = (union node *) stalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009203 n3->type = NSEMI;
9204 n3->nbinary.ch1 = n1;
9205 n3->nbinary.ch2 = n2;
9206 n1 = n3;
9207 }
9208 switch (tok) {
9209 case TBACKGND:
9210 case TSEMI:
9211 tok = readtoken();
9212 /* fall through */
9213 case TNL:
9214 if (tok == TNL) {
9215 parseheredoc();
9216 if (nlflag)
9217 return n1;
9218 } else {
9219 tokpushback++;
9220 }
9221 checkkwd = 2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009222 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009223 return n1;
9224 break;
9225 case TEOF:
9226 if (heredoclist)
9227 parseheredoc();
9228 else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009229 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009230 return n1;
9231 default:
9232 if (nlflag)
9233 synexpect(-1);
9234 tokpushback++;
9235 return n1;
9236 }
9237 }
9238}
9239
9240
9241
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009242static union node *andor()
9243{
Eric Andersencb57d552001-06-28 07:25:16 +00009244 union node *n1, *n2, *n3;
9245 int t;
9246
9247 checkkwd = 1;
9248 n1 = pipeline();
9249 for (;;) {
9250 if ((t = readtoken()) == TAND) {
9251 t = NAND;
9252 } else if (t == TOR) {
9253 t = NOR;
9254 } else {
9255 tokpushback++;
9256 return n1;
9257 }
9258 checkkwd = 2;
9259 n2 = pipeline();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009260 n3 = (union node *) stalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009261 n3->type = t;
9262 n3->nbinary.ch1 = n1;
9263 n3->nbinary.ch2 = n2;
9264 n1 = n3;
9265 }
9266}
9267
9268
9269
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009270static union node *pipeline()
9271{
Eric Andersencb57d552001-06-28 07:25:16 +00009272 union node *n1, *n2, *pipenode;
9273 struct nodelist *lp, *prev;
9274 int negate;
9275
9276 negate = 0;
9277 TRACE(("pipeline: entered\n"));
9278 if (readtoken() == TNOT) {
9279 negate = !negate;
9280 checkkwd = 1;
9281 } else
9282 tokpushback++;
9283 n1 = command();
9284 if (readtoken() == TPIPE) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009285 pipenode = (union node *) stalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +00009286 pipenode->type = NPIPE;
9287 pipenode->npipe.backgnd = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009288 lp = (struct nodelist *) stalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00009289 pipenode->npipe.cmdlist = lp;
9290 lp->n = n1;
9291 do {
9292 prev = lp;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009293 lp = (struct nodelist *) stalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00009294 checkkwd = 2;
9295 lp->n = command();
9296 prev->next = lp;
9297 } while (readtoken() == TPIPE);
9298 lp->next = NULL;
9299 n1 = pipenode;
9300 }
9301 tokpushback++;
9302 if (negate) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009303 n2 = (union node *) stalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +00009304 n2->type = NNOT;
9305 n2->nnot.com = n1;
9306 return n2;
9307 } else
9308 return n1;
9309}
9310
9311
9312
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009313static union node *command(void)
9314{
Eric Andersencb57d552001-06-28 07:25:16 +00009315 union node *n1, *n2;
9316 union node *ap, **app;
9317 union node *cp, **cpp;
9318 union node *redir, **rpp;
9319 int t;
9320
9321 redir = NULL;
9322 n1 = NULL;
9323 rpp = &redir;
9324
Eric Andersen88cec252001-09-06 17:35:20 +00009325 /* Check for redirection which may precede command */
9326 while (readtoken() == TREDIR) {
9327 *rpp = n2 = redirnode;
9328 rpp = &n2->nfile.next;
9329 parsefname();
9330 }
9331 tokpushback++;
9332
Eric Andersencb57d552001-06-28 07:25:16 +00009333 switch (readtoken()) {
9334 case TIF:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009335 n1 = (union node *) stalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009336 n1->type = NIF;
9337 n1->nif.test = list(0);
9338 if (readtoken() != TTHEN)
9339 synexpect(TTHEN);
9340 n1->nif.ifpart = list(0);
9341 n2 = n1;
9342 while (readtoken() == TELIF) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009343 n2->nif.elsepart = (union node *) stalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009344 n2 = n2->nif.elsepart;
9345 n2->type = NIF;
9346 n2->nif.test = list(0);
9347 if (readtoken() != TTHEN)
9348 synexpect(TTHEN);
9349 n2->nif.ifpart = list(0);
9350 }
9351 if (lasttoken == TELSE)
9352 n2->nif.elsepart = list(0);
9353 else {
9354 n2->nif.elsepart = NULL;
9355 tokpushback++;
9356 }
9357 if (readtoken() != TFI)
9358 synexpect(TFI);
9359 checkkwd = 1;
9360 break;
9361 case TWHILE:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009362 case TUNTIL:{
Eric Andersencb57d552001-06-28 07:25:16 +00009363 int got;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009364 n1 = (union node *) stalloc(sizeof(struct nbinary));
9365 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +00009366 n1->nbinary.ch1 = list(0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009367 if ((got = readtoken()) != TDO) {
9368 TRACE(("expecting DO got %s %s\n", tokname(got),
9369 got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009370 synexpect(TDO);
9371 }
9372 n1->nbinary.ch2 = list(0);
9373 if (readtoken() != TDONE)
9374 synexpect(TDONE);
9375 checkkwd = 1;
9376 break;
9377 }
9378 case TFOR:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009379 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Eric Andersencb57d552001-06-28 07:25:16 +00009380 synerror("Bad for loop variable");
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009381 n1 = (union node *) stalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +00009382 n1->type = NFOR;
9383 n1->nfor.var = wordtext;
9384 checkkwd = 1;
9385 if (readtoken() == TIN) {
9386 app = &ap;
9387 while (readtoken() == TWORD) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009388 n2 = (union node *) stalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009389 n2->type = NARG;
9390 n2->narg.text = wordtext;
9391 n2->narg.backquote = backquotelist;
9392 *app = n2;
9393 app = &n2->narg.next;
9394 }
9395 *app = NULL;
9396 n1->nfor.args = ap;
9397 if (lasttoken != TNL && lasttoken != TSEMI)
9398 synexpect(-1);
9399 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009400 static char argvars[5] = { CTLVAR, VSNORMAL | VSQUOTE,
9401 '@', '=', '\0'
9402 };
9403 n2 = (union node *) stalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009404 n2->type = NARG;
9405 n2->narg.text = argvars;
9406 n2->narg.backquote = NULL;
9407 n2->narg.next = NULL;
9408 n1->nfor.args = n2;
9409 /*
9410 * Newline or semicolon here is optional (but note
9411 * that the original Bourne shell only allowed NL).
9412 */
9413 if (lasttoken != TNL && lasttoken != TSEMI)
9414 tokpushback++;
9415 }
9416 checkkwd = 2;
9417 if (readtoken() != TDO)
9418 synexpect(TDO);
9419 n1->nfor.body = list(0);
9420 if (readtoken() != TDONE)
9421 synexpect(TDONE);
9422 checkkwd = 1;
9423 break;
9424 case TCASE:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009425 n1 = (union node *) stalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +00009426 n1->type = NCASE;
9427 if (readtoken() != TWORD)
9428 synexpect(TWORD);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009429 n1->ncase.expr = n2 = (union node *) stalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009430 n2->type = NARG;
9431 n2->narg.text = wordtext;
9432 n2->narg.backquote = backquotelist;
9433 n2->narg.next = NULL;
9434 do {
9435 checkkwd = 1;
9436 } while (readtoken() == TNL);
9437 if (lasttoken != TIN)
9438 synerror("expecting \"in\"");
9439 cpp = &n1->ncase.cases;
9440 checkkwd = 2, readtoken();
9441 do {
9442 if (lasttoken == TLP)
9443 readtoken();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009444 *cpp = cp = (union node *) stalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +00009445 cp->type = NCLIST;
9446 app = &cp->nclist.pattern;
9447 for (;;) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009448 *app = ap = (union node *) stalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009449 ap->type = NARG;
9450 ap->narg.text = wordtext;
9451 ap->narg.backquote = backquotelist;
9452 if (checkkwd = 2, readtoken() != TPIPE)
9453 break;
9454 app = &ap->narg.next;
9455 readtoken();
9456 }
9457 ap->narg.next = NULL;
9458 if (lasttoken != TRP)
9459 synexpect(TRP);
9460 cp->nclist.body = list(0);
9461
9462 checkkwd = 2;
9463 if ((t = readtoken()) != TESAC) {
9464 if (t != TENDCASE)
9465 synexpect(TENDCASE);
9466 else
9467 checkkwd = 2, readtoken();
9468 }
9469 cpp = &cp->nclist.next;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009470 } while (lasttoken != TESAC);
Eric Andersencb57d552001-06-28 07:25:16 +00009471 *cpp = NULL;
9472 checkkwd = 1;
9473 break;
9474 case TLP:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009475 n1 = (union node *) stalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009476 n1->type = NSUBSHELL;
9477 n1->nredir.n = list(0);
9478 n1->nredir.redirect = NULL;
9479 if (readtoken() != TRP)
9480 synexpect(TRP);
9481 checkkwd = 1;
9482 break;
9483 case TBEGIN:
9484 n1 = list(0);
9485 if (readtoken() != TEND)
9486 synexpect(TEND);
9487 checkkwd = 1;
9488 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009489 /* Handle an empty command like other simple commands. */
Eric Andersencb57d552001-06-28 07:25:16 +00009490 case TSEMI:
9491 case TAND:
9492 case TOR:
9493 case TNL:
9494 case TEOF:
9495 case TRP:
9496 case TBACKGND:
9497 /*
9498 * An empty command before a ; doesn't make much sense, and
9499 * should certainly be disallowed in the case of `if ;'.
9500 */
9501 if (!redir)
9502 synexpect(-1);
9503 case TWORD:
Eric Andersencb57d552001-06-28 07:25:16 +00009504 tokpushback++;
Eric Andersena3483db2001-10-24 08:01:06 +00009505 n1 = simplecmd(rpp, redir);
Eric Andersencb57d552001-06-28 07:25:16 +00009506 return n1;
9507 default:
9508 synexpect(-1);
9509 /* NOTREACHED */
9510 }
9511
9512 /* Now check for redirection which may follow command */
9513 while (readtoken() == TREDIR) {
9514 *rpp = n2 = redirnode;
9515 rpp = &n2->nfile.next;
9516 parsefname();
9517 }
9518 tokpushback++;
9519 *rpp = NULL;
9520 if (redir) {
9521 if (n1->type != NSUBSHELL) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009522 n2 = (union node *) stalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009523 n2->type = NREDIR;
9524 n2->nredir.n = n1;
9525 n1 = n2;
9526 }
9527 n1->nredir.redirect = redir;
9528 }
9529
9530 return n1;
9531}
9532
9533
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009534static union node *simplecmd(union node **rpp, union node *redir)
9535{
Eric Andersencb57d552001-06-28 07:25:16 +00009536 union node *args, **app;
9537 union node *n = NULL;
9538 union node *vars, **vpp;
Eric Andersena3483db2001-10-24 08:01:06 +00009539 union node **orig_rpp;
Eric Andersencb57d552001-06-28 07:25:16 +00009540
9541 args = NULL;
9542 app = &args;
9543 vars = NULL;
9544 vpp = &vars;
Eric Andersena3483db2001-10-24 08:01:06 +00009545
9546 /* If we don't have any redirections already, then we must reset
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009547 rpp to be the address of the local redir variable. */
Eric Andersena3483db2001-10-24 08:01:06 +00009548 if (redir == 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009549 rpp = &redir;
Eric Andersena3483db2001-10-24 08:01:06 +00009550 /* We save the incoming value, because we need this for shell
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009551 functions. There can not be a redirect or an argument between
9552 the function name and the open parenthesis. */
Eric Andersena3483db2001-10-24 08:01:06 +00009553 orig_rpp = rpp;
Eric Andersencb57d552001-06-28 07:25:16 +00009554
9555 checkalias = 2;
9556 for (;;) {
9557 switch (readtoken()) {
9558 case TWORD:
9559 case TASSIGN:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009560 n = (union node *) stalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009561 n->type = NARG;
9562 n->narg.text = wordtext;
9563 n->narg.backquote = backquotelist;
9564 if (lasttoken == TWORD) {
9565 *app = n;
9566 app = &n->narg.next;
9567 } else {
9568 *vpp = n;
9569 vpp = &n->narg.next;
9570 }
9571 break;
9572 case TREDIR:
9573 *rpp = n = redirnode;
9574 rpp = &n->nfile.next;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009575 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +00009576 break;
9577 case TLP:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009578 if (args && app == &args->narg.next && !vars && rpp == orig_rpp) {
Eric Andersencb57d552001-06-28 07:25:16 +00009579 /* We have a function */
9580 if (readtoken() != TRP)
9581 synexpect(TRP);
Eric Andersencb57d552001-06-28 07:25:16 +00009582 n->type = NDEFUN;
9583 checkkwd = 2;
9584 n->narg.next = command();
9585 return n;
9586 }
9587 /* fall through */
9588 default:
9589 tokpushback++;
9590 goto out;
9591 }
9592 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009593 out:
Eric Andersencb57d552001-06-28 07:25:16 +00009594 *app = NULL;
9595 *vpp = NULL;
9596 *rpp = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009597 n = (union node *) stalloc(sizeof(struct ncmd));
Eric Andersencb57d552001-06-28 07:25:16 +00009598 n->type = NCMD;
9599 n->ncmd.backgnd = 0;
9600 n->ncmd.args = args;
9601 n->ncmd.assign = vars;
9602 n->ncmd.redirect = redir;
9603 return n;
9604}
9605
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009606static union node *makename(void)
9607{
Eric Andersencb57d552001-06-28 07:25:16 +00009608 union node *n;
9609
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009610 n = (union node *) stalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009611 n->type = NARG;
9612 n->narg.next = NULL;
9613 n->narg.text = wordtext;
9614 n->narg.backquote = backquotelist;
9615 return n;
9616}
9617
9618static void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +00009619{
Eric Andersencb57d552001-06-28 07:25:16 +00009620 TRACE(("Fix redir %s %d\n", text, err));
9621 if (!err)
9622 n->ndup.vname = NULL;
9623
9624 if (is_digit(text[0]) && text[1] == '\0')
9625 n->ndup.dupfd = digit_val(text[0]);
9626 else if (text[0] == '-' && text[1] == '\0')
9627 n->ndup.dupfd = -1;
9628 else {
9629
9630 if (err)
9631 synerror("Bad fd number");
9632 else
9633 n->ndup.vname = makename();
9634 }
9635}
9636
9637
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009638static void parsefname(void)
9639{
Eric Andersencb57d552001-06-28 07:25:16 +00009640 union node *n = redirnode;
9641
9642 if (readtoken() != TWORD)
9643 synexpect(-1);
9644 if (n->type == NHERE) {
9645 struct heredoc *here = heredoc;
9646 struct heredoc *p;
9647 int i;
9648
9649 if (quoteflag == 0)
9650 n->type = NXHERE;
9651 TRACE(("Here document %d\n", n->type));
9652 if (here->striptabs) {
9653 while (*wordtext == '\t')
9654 wordtext++;
9655 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009656 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0
9657 || i > EOFMARKLEN)
Eric Andersencb57d552001-06-28 07:25:16 +00009658 synerror("Illegal eof marker for << redirection");
9659 rmescapes(wordtext);
9660 here->eofmark = wordtext;
9661 here->next = NULL;
9662 if (heredoclist == NULL)
9663 heredoclist = here;
9664 else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009665 for (p = heredoclist; p->next; p = p->next);
Eric Andersencb57d552001-06-28 07:25:16 +00009666 p->next = here;
9667 }
9668 } else if (n->type == NTOFD || n->type == NFROMFD) {
9669 fixredir(n, wordtext, 0);
9670 } else {
9671 n->nfile.fname = makename();
9672 }
9673}
9674
9675
9676/*
9677 * Input any here documents.
9678 */
9679
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009680static void parseheredoc()
9681{
Eric Andersencb57d552001-06-28 07:25:16 +00009682 struct heredoc *here;
9683 union node *n;
9684
9685 while (heredoclist) {
9686 here = heredoclist;
9687 heredoclist = here->next;
9688 if (needprompt) {
9689 setprompt(2);
9690 needprompt = 0;
9691 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009692 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
9693 here->eofmark, here->striptabs);
9694 n = (union node *) stalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009695 n->narg.type = NARG;
9696 n->narg.next = NULL;
9697 n->narg.text = wordtext;
9698 n->narg.backquote = backquotelist;
9699 here->here->nhere.doc = n;
9700 }
9701}
9702
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009703static char peektoken()
9704{
Eric Andersencb57d552001-06-28 07:25:16 +00009705 int t;
9706
9707 t = readtoken();
9708 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009709 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +00009710}
9711
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009712static int readtoken()
9713{
Eric Andersencb57d552001-06-28 07:25:16 +00009714 int t;
Eric Andersen7467c8d2001-07-12 20:26:32 +00009715
Eric Andersencb57d552001-06-28 07:25:16 +00009716 int savecheckalias = checkalias;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009717
Eric Andersen8e139872002-07-04 00:19:46 +00009718#ifdef CONFIG_ASH_ALIAS
Eric Andersen7467c8d2001-07-12 20:26:32 +00009719 int savecheckkwd = checkkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009720 struct alias *ap;
Eric Andersen2870d962001-07-02 17:27:21 +00009721#endif
9722
Eric Andersencb57d552001-06-28 07:25:16 +00009723#ifdef DEBUG
9724 int alreadyseen = tokpushback;
9725#endif
9726
Eric Andersend35c5df2002-01-09 15:37:36 +00009727#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009728 top:
Eric Andersen2870d962001-07-02 17:27:21 +00009729#endif
9730
Eric Andersencb57d552001-06-28 07:25:16 +00009731 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +00009732
Eric Andersencb57d552001-06-28 07:25:16 +00009733 checkalias = savecheckalias;
9734
9735 if (checkkwd) {
9736 /*
9737 * eat newlines
9738 */
9739 if (checkkwd == 2) {
9740 checkkwd = 0;
9741 while (t == TNL) {
9742 parseheredoc();
9743 t = xxreadtoken();
9744 }
9745 }
9746 checkkwd = 0;
9747 /*
9748 * check for keywords
9749 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009750 if (t == TWORD && !quoteflag) {
Eric Andersencb57d552001-06-28 07:25:16 +00009751 const char *const *pp;
9752
9753 if ((pp = findkwd(wordtext))) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009754 lasttoken = t = pp - tokname_array;
9755 TRACE(("keyword %s recognized\n", tokname(t)));
Eric Andersencb57d552001-06-28 07:25:16 +00009756 goto out;
9757 }
9758 }
9759 }
9760
Eric Andersen7467c8d2001-07-12 20:26:32 +00009761
Eric Andersencb57d552001-06-28 07:25:16 +00009762 if (t != TWORD) {
9763 if (t != TREDIR) {
9764 checkalias = 0;
9765 }
9766 } else if (checkalias == 2 && isassignment(wordtext)) {
9767 lasttoken = t = TASSIGN;
9768 } else if (checkalias) {
Eric Andersen8e139872002-07-04 00:19:46 +00009769#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009770 if (!quoteflag && (ap = *__lookupalias(wordtext)) != NULL
9771 && !(ap->flag & ALIASINUSE)) {
Eric Andersencb57d552001-06-28 07:25:16 +00009772 if (*ap->val) {
9773 pushstring(ap->val, strlen(ap->val), ap);
9774 }
9775 checkkwd = savecheckkwd;
9776 goto top;
9777 }
Eric Andersen2870d962001-07-02 17:27:21 +00009778#endif
Eric Andersen8e139872002-07-04 00:19:46 +00009779 checkalias = 0;
Eric Andersen7467c8d2001-07-12 20:26:32 +00009780 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009781 out:
Eric Andersencb57d552001-06-28 07:25:16 +00009782#ifdef DEBUG
9783 if (!alreadyseen)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009784 TRACE(("token %s %s\n", tokname(t), t == TWORD
9785 || t == TASSIGN ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009786 else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009787 TRACE(("reread token %s %s\n", tokname(t), t == TWORD
9788 || t == TASSIGN ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009789#endif
9790 return (t);
9791}
9792
9793
9794/*
9795 * Read the next input token.
9796 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +00009797 * backquotes. We set quoteflag to true if any part of the word was
9798 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +00009799 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +00009800 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +00009801 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +00009802 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +00009803 *
9804 * [Change comment: here documents and internal procedures]
9805 * [Readtoken shouldn't have any arguments. Perhaps we should make the
9806 * word parsing code into a separate routine. In this case, readtoken
9807 * doesn't need to have any internal procedures, but parseword does.
9808 * We could also make parseoperator in essence the main routine, and
9809 * have parseword (readtoken1?) handle both words and redirection.]
9810 */
9811
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009812#define NEW_xxreadtoken
9813#ifdef NEW_xxreadtoken
9814
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009815static const char xxreadtoken_chars[] = "\n()&|;"; /* singles must be first! */
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009816static const char xxreadtoken_tokens[] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009817 TNL, TLP, TRP, /* only single occurrence allowed */
9818 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
9819 TEOF, /* corresponds to trailing nul */
9820 TAND, TOR, TENDCASE, /* if double occurrence */
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009821};
9822
9823#define xxreadtoken_doubles \
9824 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
9825#define xxreadtoken_singles \
9826 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
9827
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009828static int xxreadtoken()
9829{
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009830 int c;
9831
9832 if (tokpushback) {
9833 tokpushback = 0;
9834 return lasttoken;
9835 }
9836 if (needprompt) {
9837 setprompt(2);
9838 needprompt = 0;
9839 }
9840 startlinno = plinno;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009841 for (;;) { /* until token or start of word found */
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009842 c = pgetc_macro();
9843
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009844 if ((c != ' ') && (c != '\t')
Eric Andersend35c5df2002-01-09 15:37:36 +00009845#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009846 && (c != PEOA)
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009847#endif
9848 ) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009849 if (c == '#') {
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009850 while ((c = pgetc()) != '\n' && c != PEOF);
9851 pungetc();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009852 } else if (c == '\\') {
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009853 if (pgetc() != '\n') {
9854 pungetc();
9855 goto READTOKEN1;
9856 }
9857 startlinno = ++plinno;
9858 setprompt(doprompt ? 2 : 0);
9859 } else {
9860 const char *p
9861 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
9862
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009863 if (c != PEOF) {
9864 if (c == '\n') {
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009865 plinno++;
9866 needprompt = doprompt;
9867 }
9868
9869 p = strchr(xxreadtoken_chars, c);
9870 if (p == NULL) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009871 READTOKEN1:
9872 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009873 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009874
9875 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
9876 if (pgetc() == *p) { /* double occurrence? */
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009877 p += xxreadtoken_doubles + 1;
9878 } else {
9879 pungetc();
9880 }
9881 }
9882 }
9883
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009884 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009885 }
9886 }
9887 }
9888}
9889
9890
9891#else
Eric Andersen2870d962001-07-02 17:27:21 +00009892#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +00009893
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009894static int xxreadtoken()
9895{
Eric Andersencb57d552001-06-28 07:25:16 +00009896 int c;
9897
9898 if (tokpushback) {
9899 tokpushback = 0;
9900 return lasttoken;
9901 }
9902 if (needprompt) {
9903 setprompt(2);
9904 needprompt = 0;
9905 }
9906 startlinno = plinno;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009907 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +00009908 c = pgetc_macro();
9909 switch (c) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009910 case ' ':
9911 case '\t':
Eric Andersend35c5df2002-01-09 15:37:36 +00009912#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00009913 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +00009914#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009915 continue;
9916 case '#':
9917 while ((c = pgetc()) != '\n' && c != PEOF);
9918 pungetc();
9919 continue;
9920 case '\\':
9921 if (pgetc() == '\n') {
9922 startlinno = ++plinno;
9923 if (doprompt)
9924 setprompt(2);
9925 else
9926 setprompt(0);
9927 continue;
9928 }
9929 pungetc();
9930 goto breakloop;
9931 case '\n':
9932 plinno++;
9933 needprompt = doprompt;
9934 RETURN(TNL);
9935 case PEOF:
9936 RETURN(TEOF);
9937 case '&':
9938 if (pgetc() == '&')
9939 RETURN(TAND);
9940 pungetc();
9941 RETURN(TBACKGND);
9942 case '|':
9943 if (pgetc() == '|')
9944 RETURN(TOR);
9945 pungetc();
9946 RETURN(TPIPE);
9947 case ';':
9948 if (pgetc() == ';')
9949 RETURN(TENDCASE);
9950 pungetc();
9951 RETURN(TSEMI);
9952 case '(':
9953 RETURN(TLP);
9954 case ')':
9955 RETURN(TRP);
9956 default:
9957 goto breakloop;
9958 }
9959 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009960 breakloop:
9961 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009962#undef RETURN
9963}
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009964#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009965
Eric Andersencb57d552001-06-28 07:25:16 +00009966/*
9967 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
9968 * is not NULL, read a here document. In the latter case, eofmark is the
9969 * word which marks the end of the document and striptabs is true if
9970 * leading tabs should be stripped from the document. The argument firstc
9971 * is the first character of the input token or document.
9972 *
9973 * Because C does not have internal subroutines, I have simulated them
9974 * using goto's to implement the subroutine linkage. The following macros
9975 * will run code that appears at the end of readtoken1.
9976 */
9977
Eric Andersen2870d962001-07-02 17:27:21 +00009978#define CHECKEND() {goto checkend; checkend_return:;}
9979#define PARSEREDIR() {goto parseredir; parseredir_return:;}
9980#define PARSESUB() {goto parsesub; parsesub_return:;}
9981#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
9982#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
9983#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +00009984
9985static int
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009986readtoken1(int firstc, int syntax, const char *eofmark, int striptabs)
9987{
Eric Andersencb57d552001-06-28 07:25:16 +00009988 int c = firstc;
9989 char *out;
9990 int len;
9991 char line[EOFMARKLEN + 1];
9992 struct nodelist *bqlist;
9993 int quotef;
9994 int dblquote;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009995 int varnest; /* levels of variables expansion */
9996 int arinest; /* levels of arithmetic expansion */
9997 int parenlevel; /* levels of parens in arithmetic */
9998 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00009999 int oldstyle;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010000 int prevsyntax; /* syntax before arithmetic */
10001
Eric Andersencb57d552001-06-28 07:25:16 +000010002#if __GNUC__
10003 /* Avoid longjmp clobbering */
10004 (void) &out;
10005 (void) &quotef;
10006 (void) &dblquote;
10007 (void) &varnest;
10008 (void) &arinest;
10009 (void) &parenlevel;
10010 (void) &dqvarnest;
10011 (void) &oldstyle;
10012 (void) &prevsyntax;
10013 (void) &syntax;
10014#endif
10015
10016 startlinno = plinno;
10017 dblquote = 0;
10018 if (syntax == DQSYNTAX)
10019 dblquote = 1;
10020 quotef = 0;
10021 bqlist = NULL;
10022 varnest = 0;
10023 arinest = 0;
10024 parenlevel = 0;
10025 dqvarnest = 0;
10026
10027 STARTSTACKSTR(out);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010028 loop:{ /* for each line, until end of word */
10029 CHECKEND(); /* set c to PEOF if at end of here document */
10030 for (;;) { /* until end of line or end of word */
10031 CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
10032 switch (SIT(c, syntax)) {
10033 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010034 if (syntax == BASESYNTAX)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010035 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010036 USTPUTC(c, out);
10037 plinno++;
10038 if (doprompt)
10039 setprompt(2);
10040 else
10041 setprompt(0);
10042 c = pgetc();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010043 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010044 case CWORD:
10045 USTPUTC(c, out);
10046 break;
10047 case CCTL:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010048 if ((eofmark == NULL || dblquote) && dqvarnest == 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010049 USTPUTC(CTLESC, out);
10050 USTPUTC(c, out);
10051 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010052 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010053 c = pgetc2();
10054 if (c == PEOF) {
10055 USTPUTC('\\', out);
10056 pungetc();
10057 } else if (c == '\n') {
10058 if (doprompt)
10059 setprompt(2);
10060 else
10061 setprompt(0);
10062 } else {
10063 if (dblquote && c != '\\' && c != '`' && c != '$'
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010064 && (c != '"' || eofmark != NULL))
Eric Andersencb57d552001-06-28 07:25:16 +000010065 USTPUTC('\\', out);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010066 if (SIT(c, SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010067 USTPUTC(CTLESC, out);
10068 else if (eofmark == NULL)
10069 USTPUTC(CTLQUOTEMARK, out);
10070 USTPUTC(c, out);
10071 quotef++;
10072 }
10073 break;
10074 case CSQUOTE:
10075 if (eofmark == NULL)
10076 USTPUTC(CTLQUOTEMARK, out);
10077 syntax = SQSYNTAX;
10078 break;
10079 case CDQUOTE:
10080 if (eofmark == NULL)
10081 USTPUTC(CTLQUOTEMARK, out);
10082 syntax = DQSYNTAX;
10083 dblquote = 1;
10084 break;
10085 case CENDQUOTE:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010086 if (eofmark != NULL && arinest == 0 && varnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010087 USTPUTC(c, out);
10088 } else {
10089 if (arinest) {
10090 syntax = ARISYNTAX;
10091 dblquote = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010092 } else if (eofmark == NULL && dqvarnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010093 syntax = BASESYNTAX;
10094 dblquote = 0;
10095 }
10096 quotef++;
10097 }
10098 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010099 case CVAR: /* '$' */
10100 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010101 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010102 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010103 if (varnest > 0) {
10104 varnest--;
10105 if (dqvarnest > 0) {
10106 dqvarnest--;
10107 }
10108 USTPUTC(CTLENDVAR, out);
10109 } else {
10110 USTPUTC(c, out);
10111 }
10112 break;
Eric Andersend35c5df2002-01-09 15:37:36 +000010113#ifdef CONFIG_ASH_MATH_SUPPORT
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010114 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010115 parenlevel++;
10116 USTPUTC(c, out);
10117 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010118 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010119 if (parenlevel > 0) {
10120 USTPUTC(c, out);
10121 --parenlevel;
10122 } else {
10123 if (pgetc() == ')') {
10124 if (--arinest == 0) {
10125 USTPUTC(CTLENDARI, out);
10126 syntax = prevsyntax;
10127 if (syntax == DQSYNTAX)
10128 dblquote = 1;
10129 else
10130 dblquote = 0;
10131 } else
10132 USTPUTC(')', out);
10133 } else {
10134 /*
10135 * unbalanced parens
10136 * (don't 2nd guess - no error)
10137 */
10138 pungetc();
10139 USTPUTC(')', out);
10140 }
10141 }
10142 break;
10143#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010144 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010145 PARSEBACKQOLD();
10146 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010147 case CENDFILE:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010148 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010149 case CIGN:
10150 break;
10151 default:
10152 if (varnest == 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010153 goto endword; /* exit outer loop */
Eric Andersend35c5df2002-01-09 15:37:36 +000010154#ifdef CONFIG_ASH_ALIAS
Eric Andersen3102ac42001-07-06 04:26:23 +000010155 if (c != PEOA)
10156#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010157 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010158
Eric Andersencb57d552001-06-28 07:25:16 +000010159 }
10160 c = pgetc_macro();
10161 }
10162 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010163 endword:
Eric Andersencb57d552001-06-28 07:25:16 +000010164 if (syntax == ARISYNTAX)
10165 synerror("Missing '))'");
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010166 if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010167 synerror("Unterminated quoted string");
10168 if (varnest != 0) {
10169 startlinno = plinno;
10170 synerror("Missing '}'");
10171 }
10172 USTPUTC('\0', out);
10173 len = out - stackblock();
10174 out = stackblock();
10175 if (eofmark == NULL) {
10176 if ((c == '>' || c == '<')
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010177 && quotef == 0 && len <= 2 && (*out == '\0' || is_digit(*out))) {
Eric Andersencb57d552001-06-28 07:25:16 +000010178 PARSEREDIR();
10179 return lasttoken = TREDIR;
10180 } else {
10181 pungetc();
10182 }
10183 }
10184 quoteflag = quotef;
10185 backquotelist = bqlist;
10186 grabstackblock(len);
10187 wordtext = out;
10188 return lasttoken = TWORD;
10189/* end of readtoken routine */
10190
10191
10192
10193/*
10194 * Check to see whether we are at the end of the here document. When this
10195 * is called, c is set to the first character of the next input line. If
10196 * we are at the end of the here document, this routine sets the c to PEOF.
10197 */
10198
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010199 checkend:{
10200 if (eofmark) {
Eric Andersend35c5df2002-01-09 15:37:36 +000010201#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010202 if (c == PEOA) {
Eric Andersencb57d552001-06-28 07:25:16 +000010203 c = pgetc2();
10204 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010205#endif
10206 if (striptabs) {
10207 while (c == '\t') {
10208 c = pgetc2();
10209 }
10210 }
10211 if (c == *eofmark) {
10212 if (pfgets(line, sizeof line) != NULL) {
10213 const char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010214
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010215 p = line;
10216 for (q = eofmark + 1; *q && *p == *q; p++, q++);
10217 if (*p == '\n' && *q == '\0') {
10218 c = PEOF;
10219 plinno++;
10220 needprompt = doprompt;
10221 } else {
10222 pushstring(line, strlen(line), NULL);
10223 }
Eric Andersencb57d552001-06-28 07:25:16 +000010224 }
10225 }
10226 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010227 goto checkend_return;
Eric Andersencb57d552001-06-28 07:25:16 +000010228 }
Eric Andersencb57d552001-06-28 07:25:16 +000010229
10230
10231/*
10232 * Parse a redirection operator. The variable "out" points to a string
10233 * specifying the fd to be redirected. The variable "c" contains the
10234 * first character of the redirection operator.
10235 */
10236
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010237 parseredir:{
10238 char fd = *out;
10239 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000010240
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010241 np = (union node *) stalloc(sizeof(struct nfile));
10242 if (c == '>') {
10243 np->nfile.fd = 1;
10244 c = pgetc();
10245 if (c == '>')
10246 np->type = NAPPEND;
10247 else if (c == '&')
10248 np->type = NTOFD;
10249 else if (c == '|')
10250 np->type = NTOOV;
10251 else {
10252 np->type = NTO;
Eric Andersencb57d552001-06-28 07:25:16 +000010253 pungetc();
10254 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010255 } else { /* c == '<' */
10256 np->nfile.fd = 0;
10257 switch (c = pgetc()) {
10258 case '<':
10259 if (sizeof(struct nfile) != sizeof(struct nhere)) {
10260 np = (union node *) stalloc(sizeof(struct nhere));
10261 np->nfile.fd = 0;
10262 }
10263 np->type = NHERE;
10264 heredoc = (struct heredoc *) stalloc(sizeof(struct heredoc));
10265 heredoc->here = np;
10266 if ((c = pgetc()) == '-') {
10267 heredoc->striptabs = 1;
10268 } else {
10269 heredoc->striptabs = 0;
10270 pungetc();
10271 }
10272 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010273
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010274 case '&':
10275 np->type = NFROMFD;
10276 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010277
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010278 case '>':
10279 np->type = NFROMTO;
10280 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010281
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010282 default:
10283 np->type = NFROM;
10284 pungetc();
10285 break;
10286 }
Eric Andersencb57d552001-06-28 07:25:16 +000010287 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010288 if (fd != '\0')
10289 np->nfile.fd = digit_val(fd);
10290 redirnode = np;
10291 goto parseredir_return;
Eric Andersencb57d552001-06-28 07:25:16 +000010292 }
Eric Andersencb57d552001-06-28 07:25:16 +000010293
10294
10295/*
10296 * Parse a substitution. At this point, we have read the dollar sign
10297 * and nothing else.
10298 */
10299
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010300 parsesub:{
10301 int subtype;
10302 int typeloc;
10303 int flags;
10304 char *p;
10305 static const char types[] = "}-+?=";
Eric Andersencb57d552001-06-28 07:25:16 +000010306
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010307 c = pgetc();
10308 if (c <= PEOA ||
10309 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10310 ) {
10311 USTPUTC('$', out);
Eric Andersencb57d552001-06-28 07:25:16 +000010312 pungetc();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010313 } else if (c == '(') { /* $(command) or $((arith)) */
10314 if (pgetc() == '(') {
10315 PARSEARITH();
10316 } else {
10317 pungetc();
10318 PARSEBACKQNEW();
Eric Andersencb57d552001-06-28 07:25:16 +000010319 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010320 } else {
10321 USTPUTC(CTLVAR, out);
10322 typeloc = out - stackblock();
10323 USTPUTC(VSNORMAL, out);
10324 subtype = VSNORMAL;
10325 if (c == '{') {
Eric Andersencb57d552001-06-28 07:25:16 +000010326 c = pgetc();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010327 if (c == '#') {
10328 if ((c = pgetc()) == '}')
10329 c = '#';
10330 else
10331 subtype = VSLENGTH;
10332 } else
10333 subtype = 0;
10334 }
10335 if (c > PEOA && is_name(c)) {
10336 do {
10337 STPUTC(c, out);
10338 c = pgetc();
10339 } while (c > PEOA && is_in_name(c));
10340 } else if (is_digit(c)) {
10341 do {
10342 USTPUTC(c, out);
10343 c = pgetc();
10344 } while (is_digit(c));
10345 } else if (is_special(c)) {
Eric Andersencb57d552001-06-28 07:25:16 +000010346 USTPUTC(c, out);
10347 c = pgetc();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010348 } else
10349 badsub:synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010350
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010351 STPUTC('=', out);
10352 flags = 0;
10353 if (subtype == 0) {
10354 switch (c) {
10355 case ':':
10356 flags = VSNUL;
10357 c = pgetc();
10358 /*FALLTHROUGH*/ default:
10359 p = strchr(types, c);
10360 if (p == NULL)
10361 goto badsub;
10362 subtype = p - types + VSNORMAL;
10363 break;
10364 case '%':
10365 case '#':
Eric Andersencb57d552001-06-28 07:25:16 +000010366 {
10367 int cc = c;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010368
10369 subtype = c == '#' ? VSTRIMLEFT : VSTRIMRIGHT;
Eric Andersencb57d552001-06-28 07:25:16 +000010370 c = pgetc();
10371 if (c == cc)
10372 subtype++;
10373 else
10374 pungetc();
10375 break;
10376 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010377 }
10378 } else {
10379 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010380 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010381 if (dblquote || arinest)
10382 flags |= VSQUOTE;
10383 *(stackblock() + typeloc) = subtype | flags;
10384 if (subtype != VSNORMAL) {
10385 varnest++;
10386 if (dblquote) {
10387 dqvarnest++;
10388 }
Eric Andersencb57d552001-06-28 07:25:16 +000010389 }
10390 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010391 goto parsesub_return;
Eric Andersencb57d552001-06-28 07:25:16 +000010392 }
Eric Andersencb57d552001-06-28 07:25:16 +000010393
10394
10395/*
10396 * Called to parse command substitutions. Newstyle is set if the command
10397 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10398 * list of commands (passed by reference), and savelen is the number of
10399 * characters on the top of the stack which must be preserved.
10400 */
10401
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010402 parsebackq:{
10403 struct nodelist **nlpp;
10404 int savepbq;
10405 union node *n;
10406 char *volatile str;
10407 struct jmploc jmploc;
10408 struct jmploc *volatile savehandler;
10409 int savelen;
10410 int saveprompt;
10411
Eric Andersencb57d552001-06-28 07:25:16 +000010412#ifdef __GNUC__
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010413 (void) &saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010414#endif
10415
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010416 savepbq = parsebackquote;
10417 if (setjmp(jmploc.loc)) {
10418 free(str);
10419 parsebackquote = 0;
10420 handler = savehandler;
10421 longjmp(handler->loc, 1);
10422 }
10423 INTOFF;
10424 str = NULL;
10425 savelen = out - stackblock();
10426 if (savelen > 0) {
10427 str = xmalloc(savelen);
10428 memcpy(str, stackblock(), savelen);
10429 }
10430 savehandler = handler;
10431 handler = &jmploc;
10432 INTON;
10433 if (oldstyle) {
10434 /* We must read until the closing backquote, giving special
10435 treatment to some slashes, and then push the string and
10436 reread it as input, interpreting it normally. */
10437 char *pout;
10438 int pc;
10439 int psavelen;
10440 char *pstr;
Eric Andersencb57d552001-06-28 07:25:16 +000010441
10442
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010443 STARTSTACKSTR(pout);
10444 for (;;) {
10445 if (needprompt) {
10446 setprompt(2);
10447 needprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010448 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010449 switch (pc = pgetc()) {
10450 case '`':
10451 goto done;
10452
10453 case '\\':
10454 if ((pc = pgetc()) == '\n') {
10455 plinno++;
10456 if (doprompt)
10457 setprompt(2);
10458 else
10459 setprompt(0);
10460 /*
10461 * If eating a newline, avoid putting
10462 * the newline into the new character
10463 * stream (via the STPUTC after the
10464 * switch).
10465 */
10466 continue;
10467 }
10468 if (pc != '\\' && pc != '`' && pc != '$'
10469 && (!dblquote || pc != '"'))
10470 STPUTC('\\', pout);
10471 if (pc > PEOA) {
10472 break;
10473 }
10474 /* fall through */
10475
10476 case PEOF:
10477#ifdef CONFIG_ASH_ALIAS
10478 case PEOA:
10479#endif
10480 startlinno = plinno;
10481 synerror("EOF in backquote substitution");
10482
10483 case '\n':
10484 plinno++;
10485 needprompt = doprompt;
10486 break;
10487
10488 default:
Eric Andersencb57d552001-06-28 07:25:16 +000010489 break;
10490 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010491 STPUTC(pc, pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010492 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010493 done:
10494 STPUTC('\0', pout);
10495 psavelen = pout - stackblock();
10496 if (psavelen > 0) {
10497 pstr = grabstackstr(pout);
10498 setinputstring(pstr);
10499 }
Eric Andersen2870d962001-07-02 17:27:21 +000010500 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010501 nlpp = &bqlist;
10502 while (*nlpp)
10503 nlpp = &(*nlpp)->next;
10504 *nlpp = (struct nodelist *) stalloc(sizeof(struct nodelist));
10505 (*nlpp)->next = NULL;
10506 parsebackquote = oldstyle;
10507
10508 if (oldstyle) {
10509 saveprompt = doprompt;
10510 doprompt = 0;
Eric Andersen2870d962001-07-02 17:27:21 +000010511 }
Eric Andersencb57d552001-06-28 07:25:16 +000010512
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010513 n = list(0);
Eric Andersencb57d552001-06-28 07:25:16 +000010514
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010515 if (oldstyle)
10516 doprompt = saveprompt;
10517 else {
10518 if (readtoken() != TRP)
10519 synexpect(TRP);
10520 }
Eric Andersencb57d552001-06-28 07:25:16 +000010521
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010522 (*nlpp)->n = n;
10523 if (oldstyle) {
10524 /*
10525 * Start reading from old file again, ignoring any pushed back
10526 * tokens left from the backquote parsing
10527 */
10528 popfile();
10529 tokpushback = 0;
10530 }
10531 while (stackblocksize() <= savelen)
10532 growstackblock();
10533 STARTSTACKSTR(out);
10534 if (str) {
10535 memcpy(out, str, savelen);
10536 STADJUST(savelen, out);
10537 INTOFF;
10538 free(str);
10539 str = NULL;
10540 INTON;
10541 }
10542 parsebackquote = savepbq;
10543 handler = savehandler;
10544 if (arinest || dblquote)
10545 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10546 else
10547 USTPUTC(CTLBACKQ, out);
10548 if (oldstyle)
10549 goto parsebackq_oldreturn;
10550 else
10551 goto parsebackq_newreturn;
Eric Andersencb57d552001-06-28 07:25:16 +000010552 }
10553
Eric Andersencb57d552001-06-28 07:25:16 +000010554/*
10555 * Parse an arithmetic expansion (indicate start of one and set state)
10556 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010557 parsearith:{
Eric Andersencb57d552001-06-28 07:25:16 +000010558
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010559 if (++arinest == 1) {
10560 prevsyntax = syntax;
10561 syntax = ARISYNTAX;
10562 USTPUTC(CTLARI, out);
10563 if (dblquote)
10564 USTPUTC('"', out);
10565 else
10566 USTPUTC(' ', out);
10567 } else {
10568 /*
10569 * we collapse embedded arithmetic expansion to
10570 * parenthesis, which should be equivalent
10571 */
10572 USTPUTC('(', out);
10573 }
10574 goto parsearith_return;
Eric Andersencb57d552001-06-28 07:25:16 +000010575 }
Eric Andersencb57d552001-06-28 07:25:16 +000010576
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010577} /* end of readtoken */
Eric Andersencb57d552001-06-28 07:25:16 +000010578
10579
Eric Andersencb57d552001-06-28 07:25:16 +000010580/*
10581 * Returns true if the text contains nothing to expand (no dollar signs
10582 * or backquotes).
10583 */
10584
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010585static int noexpand(char *text)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010586{
Eric Andersencb57d552001-06-28 07:25:16 +000010587 char *p;
10588 char c;
10589
10590 p = text;
10591 while ((c = *p++) != '\0') {
10592 if (c == CTLQUOTEMARK)
10593 continue;
10594 if (c == CTLESC)
10595 p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010596 else if (SIT(c, BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010597 return 0;
10598 }
10599 return 1;
10600}
10601
10602
10603/*
10604 * Return true if the argument is a legal variable name (a letter or
10605 * underscore followed by zero or more letters, underscores, and digits).
10606 */
10607
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010608static int goodname(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +000010609{
10610 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000010611
10612 p = name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010613 if (!is_name(*p))
Eric Andersencb57d552001-06-28 07:25:16 +000010614 return 0;
10615 while (*++p) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010616 if (!is_in_name(*p))
Eric Andersencb57d552001-06-28 07:25:16 +000010617 return 0;
10618 }
10619 return 1;
10620}
10621
10622
10623/*
10624 * Called when an unexpected token is read during the parse. The argument
10625 * is the token that is expected, or -1 if more than one type of token can
10626 * occur at this point.
10627 */
10628
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010629static void synexpect(int token)
Eric Andersencb57d552001-06-28 07:25:16 +000010630{
10631 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010632 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000010633
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010634 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10635 if (token >= 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010636 sprintf(msg + l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000010637 synerror(msg);
10638 /* NOTREACHED */
10639}
10640
10641
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010642static void synerror(const char *msg)
Eric Andersen2870d962001-07-02 17:27:21 +000010643{
Eric Andersencb57d552001-06-28 07:25:16 +000010644 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +000010645 out2fmt("%s: %d: ", commandname, startlinno);
10646 out2fmt("Syntax error: %s\n", msg);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010647 error((char *) NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000010648 /* NOTREACHED */
10649}
10650
Eric Andersencb57d552001-06-28 07:25:16 +000010651
10652/*
10653 * called by editline -- any expansions to the prompt
10654 * should be added here.
10655 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010656static void setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000010657{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010658 char *prompt;
10659
10660 switch (whichprompt) {
Eric Andersen62483552001-07-10 06:09:16 +000010661 case 1:
10662 prompt = ps1val();
10663 break;
10664 case 2:
10665 prompt = ps2val();
10666 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010667 default: /* 0 */
Eric Andersen62483552001-07-10 06:09:16 +000010668 prompt = "";
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010669 }
10670 putprompt(prompt);
Eric Andersencb57d552001-06-28 07:25:16 +000010671}
10672
Eric Andersencb57d552001-06-28 07:25:16 +000010673
Eric Andersencb57d552001-06-28 07:25:16 +000010674/*
10675 * Code for dealing with input/output redirection.
10676 */
10677
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010678#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000010679#ifndef PIPE_BUF
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010680# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000010681#else
10682# define PIPESIZE PIPE_BUF
10683#endif
10684
10685
Eric Andersen62483552001-07-10 06:09:16 +000010686/*
10687 * Open a file in noclobber mode.
10688 * The code was copied from bash.
10689 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010690static inline int noclobberopen(const char *fname)
Eric Andersen62483552001-07-10 06:09:16 +000010691{
10692 int r, fd;
10693 struct stat finfo, finfo2;
10694
10695 /*
10696 * If the file exists and is a regular file, return an error
10697 * immediately.
10698 */
10699 r = stat(fname, &finfo);
10700 if (r == 0 && S_ISREG(finfo.st_mode)) {
10701 errno = EEXIST;
10702 return -1;
10703 }
10704
10705 /*
10706 * If the file was not present (r != 0), make sure we open it
10707 * exclusively so that if it is created before we open it, our open
10708 * will fail. Make sure that we do not truncate an existing file.
10709 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10710 * file was not a regular file, we leave O_EXCL off.
10711 */
10712 if (r != 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010713 return open(fname, O_WRONLY | O_CREAT | O_EXCL, 0666);
10714 fd = open(fname, O_WRONLY | O_CREAT, 0666);
Eric Andersen62483552001-07-10 06:09:16 +000010715
10716 /* If the open failed, return the file descriptor right away. */
10717 if (fd < 0)
10718 return fd;
10719
10720 /*
10721 * OK, the open succeeded, but the file may have been changed from a
10722 * non-regular file to a regular file between the stat and the open.
10723 * We are assuming that the O_EXCL open handles the case where FILENAME
10724 * did not exist and is symlinked to an existing file between the stat
10725 * and open.
10726 */
10727
10728 /*
10729 * If we can open it and fstat the file descriptor, and neither check
10730 * revealed that it was a regular file, and the file has not been
10731 * replaced, return the file descriptor.
10732 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010733 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10734 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
Eric Andersen62483552001-07-10 06:09:16 +000010735 return fd;
10736
10737 /* The file has been replaced. badness. */
10738 close(fd);
10739 errno = EEXIST;
10740 return -1;
10741}
Eric Andersencb57d552001-06-28 07:25:16 +000010742
10743/*
Eric Andersen62483552001-07-10 06:09:16 +000010744 * Handle here documents. Normally we fork off a process to write the
10745 * data to a pipe. If the document is short, we can stuff the data in
10746 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000010747 */
10748
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010749static inline int openhere(const union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010750{
10751 int pip[2];
10752 int len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010753
Eric Andersen62483552001-07-10 06:09:16 +000010754 if (pipe(pip) < 0)
10755 error("Pipe call failed");
10756 if (redir->type == NHERE) {
10757 len = strlen(redir->nhere.doc->narg.text);
10758 if (len <= PIPESIZE) {
10759 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10760 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010761 }
Eric Andersencb57d552001-06-28 07:25:16 +000010762 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010763 if (forkshell((struct job *) NULL, (union node *) NULL, FORK_NOJOB) == 0) {
Eric Andersen62483552001-07-10 06:09:16 +000010764 close(pip[0]);
10765 signal(SIGINT, SIG_IGN);
10766 signal(SIGQUIT, SIG_IGN);
10767 signal(SIGHUP, SIG_IGN);
10768#ifdef SIGTSTP
10769 signal(SIGTSTP, SIG_IGN);
10770#endif
10771 signal(SIGPIPE, SIG_DFL);
10772 if (redir->type == NHERE)
10773 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10774 else
10775 expandhere(redir->nhere.doc, pip[1]);
10776 _exit(0);
10777 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010778 out:
Eric Andersen62483552001-07-10 06:09:16 +000010779 close(pip[1]);
10780 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000010781}
10782
10783
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010784static inline int openredirect(const union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010785{
Eric Andersencb57d552001-06-28 07:25:16 +000010786 char *fname;
10787 int f;
10788
10789 switch (redir->nfile.type) {
10790 case NFROM:
10791 fname = redir->nfile.expfname;
10792 if ((f = open(fname, O_RDONLY)) < 0)
10793 goto eopen;
10794 break;
10795 case NFROMTO:
10796 fname = redir->nfile.expfname;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010797 if ((f = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010798 goto ecreate;
10799 break;
10800 case NTO:
10801 /* Take care of noclobber mode. */
10802 if (Cflag) {
10803 fname = redir->nfile.expfname;
10804 if ((f = noclobberopen(fname)) < 0)
10805 goto ecreate;
10806 break;
10807 }
10808 case NTOOV:
10809 fname = redir->nfile.expfname;
10810#ifdef O_CREAT
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010811 if ((f = open(fname, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010812 goto ecreate;
10813#else
10814 if ((f = creat(fname, 0666)) < 0)
10815 goto ecreate;
10816#endif
10817 break;
10818 case NAPPEND:
10819 fname = redir->nfile.expfname;
10820#ifdef O_APPEND
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010821 if ((f = open(fname, O_WRONLY | O_CREAT | O_APPEND, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010822 goto ecreate;
10823#else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010824 if ((f = open(fname, O_WRONLY)) < 0 && (f = creat(fname, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010825 goto ecreate;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010826 lseek(f, (off_t) 0, 2);
Eric Andersencb57d552001-06-28 07:25:16 +000010827#endif
10828 break;
10829 default:
10830#ifdef DEBUG
10831 abort();
10832#endif
10833 /* Fall through to eliminate warning. */
10834 case NTOFD:
10835 case NFROMFD:
10836 f = -1;
10837 break;
10838 case NHERE:
10839 case NXHERE:
10840 f = openhere(redir);
10841 break;
10842 }
10843
10844 return f;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010845 ecreate:
Eric Andersencb57d552001-06-28 07:25:16 +000010846 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010847 eopen:
Eric Andersencb57d552001-06-28 07:25:16 +000010848 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
10849}
10850
10851
Eric Andersen62483552001-07-10 06:09:16 +000010852/*
10853 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
10854 * old file descriptors are stashed away so that the redirection can be
10855 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
10856 * standard output, and the standard error if it becomes a duplicate of
10857 * stdout.
10858 */
10859
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010860static void redirect(union node *redir, int flags)
Eric Andersen62483552001-07-10 06:09:16 +000010861{
10862 union node *n;
10863 struct redirtab *sv = NULL;
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010864 int i;
Eric Andersen62483552001-07-10 06:09:16 +000010865 int fd;
10866 int newfd;
10867 int try;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010868 int fd1dup = flags & REDIR_BACKQ;; /* stdout `cmd` redir to pipe */
Eric Andersen62483552001-07-10 06:09:16 +000010869
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010870 TRACE(("redirect(%s) called\n",
10871 flags & REDIR_PUSH ? "REDIR_PUSH" : "NO_REDIR_PUSH"));
Eric Andersen62483552001-07-10 06:09:16 +000010872 if (flags & REDIR_PUSH) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010873 sv = xmalloc(sizeof(struct redirtab));
10874 for (i = 0; i < 10; i++)
Eric Andersen62483552001-07-10 06:09:16 +000010875 sv->renamed[i] = EMPTY;
10876 sv->next = redirlist;
10877 redirlist = sv;
10878 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010879 for (n = redir; n; n = n->nfile.next) {
Eric Andersen62483552001-07-10 06:09:16 +000010880 fd = n->nfile.fd;
10881 try = 0;
10882 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010883 n->ndup.dupfd == fd)
10884 continue; /* redirect from/to same file descriptor */
Eric Andersen62483552001-07-10 06:09:16 +000010885
10886 INTOFF;
10887 newfd = openredirect(n);
10888 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
Eric Andersen09da6272002-10-22 22:15:33 +000010889 i = fd;
Eric Andersen62483552001-07-10 06:09:16 +000010890 if (newfd == fd) {
10891 try++;
10892 } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
10893 switch (errno) {
10894 case EBADF:
10895 if (!try) {
10896 dupredirect(n, newfd, fd1dup);
10897 try++;
10898 break;
10899 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010900 /* FALLTHROUGH */
Eric Andersen62483552001-07-10 06:09:16 +000010901 default:
10902 if (newfd >= 0) {
10903 close(newfd);
10904 }
10905 INTON;
10906 error("%d: %m", fd);
10907 /* NOTREACHED */
10908 }
10909 }
10910 if (!try) {
10911 close(fd);
10912 if (flags & REDIR_PUSH) {
10913 sv->renamed[fd] = i;
10914 }
10915 }
10916 } else if (fd != newfd) {
10917 close(fd);
10918 }
10919 if (fd == 0)
10920 fd0_redirected++;
10921 if (!try)
10922 dupredirect(n, newfd, fd1dup);
10923 INTON;
10924 }
10925}
10926
10927
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010928static void dupredirect(const union node *redir, int f, int fd1dup)
Eric Andersen2870d962001-07-02 17:27:21 +000010929{
Eric Andersencb57d552001-06-28 07:25:16 +000010930 int fd = redir->nfile.fd;
10931
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010932 if (fd == 1)
Eric Andersen62483552001-07-10 06:09:16 +000010933 fd1dup = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010934 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010935 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
10936 if (redir->ndup.dupfd != 1 || fd1dup != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000010937 dup_as_newfd(redir->ndup.dupfd, fd);
10938 }
10939 return;
10940 }
10941
10942 if (f != fd) {
10943 dup_as_newfd(f, fd);
10944 close(f);
10945 }
10946 return;
10947}
10948
10949
Eric Andersencb57d552001-06-28 07:25:16 +000010950
Eric Andersencb57d552001-06-28 07:25:16 +000010951/*
10952 * Undo the effects of the last redirection.
10953 */
10954
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010955static void popredir(void)
Eric Andersen2870d962001-07-02 17:27:21 +000010956{
Eric Andersencb57d552001-06-28 07:25:16 +000010957 struct redirtab *rp = redirlist;
10958 int i;
10959
10960 INTOFF;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010961 for (i = 0; i < 10; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000010962 if (rp->renamed[i] != EMPTY) {
Eric Andersen2870d962001-07-02 17:27:21 +000010963 if (i == 0)
10964 fd0_redirected--;
Eric Andersencb57d552001-06-28 07:25:16 +000010965 close(i);
10966 if (rp->renamed[i] >= 0) {
10967 dup_as_newfd(rp->renamed[i], i);
10968 close(rp->renamed[i]);
10969 }
Eric Andersencb57d552001-06-28 07:25:16 +000010970 }
10971 }
10972 redirlist = rp->next;
Aaron Lehmann49c024a2002-08-02 06:39:47 +000010973 free(rp);
Eric Andersencb57d552001-06-28 07:25:16 +000010974 INTON;
10975}
10976
10977/*
Eric Andersencb57d552001-06-28 07:25:16 +000010978 * Discard all saved file descriptors.
10979 */
10980
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010981static void clearredir(void)
10982{
Eric Andersencb57d552001-06-28 07:25:16 +000010983 struct redirtab *rp;
10984 int i;
10985
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010986 for (rp = redirlist; rp; rp = rp->next) {
10987 for (i = 0; i < 10; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000010988 if (rp->renamed[i] >= 0) {
10989 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000010990 }
10991 rp->renamed[i] = EMPTY;
10992 }
10993 }
Eric Andersencb57d552001-06-28 07:25:16 +000010994}
10995
10996
Eric Andersencb57d552001-06-28 07:25:16 +000010997/*
10998 * Copy a file descriptor to be >= to. Returns -1
10999 * if the source file descriptor is closed, EMPTY if there are no unused
11000 * file descriptors left.
11001 */
11002
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011003static int dup_as_newfd(int from, int to)
Eric Andersencb57d552001-06-28 07:25:16 +000011004{
11005 int newfd;
11006
11007 newfd = fcntl(from, F_DUPFD, to);
11008 if (newfd < 0) {
11009 if (errno == EMFILE)
11010 return EMPTY;
11011 else
Eric Andersen2870d962001-07-02 17:27:21 +000011012 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011013 }
11014 return newfd;
11015}
11016
Eric Andersencb57d552001-06-28 07:25:16 +000011017#ifdef DEBUG
Eric Andersenec074692001-10-31 11:05:49 +000011018/*
11019 * Debugging stuff.
11020 */
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011021
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011022static void shtree(union node *, int, char *, FILE *);
11023static void shcmd(union node *, FILE *);
11024static void sharg(union node *, FILE *);
11025static void indent(int, char *, FILE *);
11026static void trstring(char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011027
11028
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011029#if 0
11030static void showtree(node * n)
Eric Andersencb57d552001-06-28 07:25:16 +000011031{
11032 trputs("showtree called\n");
11033 shtree(n, 1, NULL, stdout);
11034}
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011035#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011036
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011037static void shtree(union node *n, int ind, char *pfx, FILE * fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011038{
11039 struct nodelist *lp;
11040 const char *s;
11041
11042 if (n == NULL)
11043 return;
11044
11045 indent(ind, pfx, fp);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011046 switch (n->type) {
Eric Andersencb57d552001-06-28 07:25:16 +000011047 case NSEMI:
11048 s = "; ";
11049 goto binop;
11050 case NAND:
11051 s = " && ";
11052 goto binop;
11053 case NOR:
11054 s = " || ";
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011055 binop:
Eric Andersencb57d552001-06-28 07:25:16 +000011056 shtree(n->nbinary.ch1, ind, NULL, fp);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011057 /* if (ind < 0) */
11058 fputs(s, fp);
Eric Andersencb57d552001-06-28 07:25:16 +000011059 shtree(n->nbinary.ch2, ind, NULL, fp);
11060 break;
11061 case NCMD:
11062 shcmd(n, fp);
11063 if (ind >= 0)
11064 putc('\n', fp);
11065 break;
11066 case NPIPE:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011067 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000011068 shcmd(lp->n, fp);
11069 if (lp->next)
11070 fputs(" | ", fp);
11071 }
11072 if (n->npipe.backgnd)
11073 fputs(" &", fp);
11074 if (ind >= 0)
11075 putc('\n', fp);
11076 break;
11077 default:
11078 fprintf(fp, "<node type %d>", n->type);
11079 if (ind >= 0)
11080 putc('\n', fp);
11081 break;
11082 }
11083}
11084
11085
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011086static void shcmd(union node *cmd, FILE * fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011087{
11088 union node *np;
11089 int first;
11090 const char *s;
11091 int dftfd;
11092
11093 first = 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011094 for (np = cmd->ncmd.args; np; np = np->narg.next) {
11095 if (!first)
Eric Andersencb57d552001-06-28 07:25:16 +000011096 putchar(' ');
11097 sharg(np, fp);
11098 first = 0;
11099 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011100 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
11101 if (!first)
Eric Andersencb57d552001-06-28 07:25:16 +000011102 putchar(' ');
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011103#if 1
11104 s = "*error*";
11105 dftfd = 0;
11106 if ((np->nfile.type <= NFROMFD) && (np->nfile.type >= NTO)) {
11107 s = redir_strings[np->nfile.type - NTO];
11108 if (*s == '>') {
11109 dftfd = 1;
11110 }
11111 }
11112#else
Eric Andersencb57d552001-06-28 07:25:16 +000011113 switch (np->nfile.type) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011114 case NTO:
11115 s = ">";
11116 dftfd = 1;
11117 break;
11118 case NAPPEND:
11119 s = ">>";
11120 dftfd = 1;
11121 break;
11122 case NTOFD:
11123 s = ">&";
11124 dftfd = 1;
11125 break;
11126 case NTOOV:
11127 s = ">|";
11128 dftfd = 1;
11129 break;
11130 case NFROM:
11131 s = "<";
11132 dftfd = 0;
11133 break;
11134 case NFROMFD:
11135 s = "<&";
11136 dftfd = 0;
11137 break;
11138 case NFROMTO:
11139 s = "<>";
11140 dftfd = 0;
11141 break;
11142 default:
11143 s = "*error*";
11144 dftfd = 0;
11145 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011146 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011147#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011148 if (np->nfile.fd != dftfd)
11149 fprintf(fp, "%d", np->nfile.fd);
11150 fputs(s, fp);
11151 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11152 fprintf(fp, "%d", np->ndup.dupfd);
11153 } else {
11154 sharg(np->nfile.fname, fp);
11155 }
11156 first = 0;
11157 }
11158}
11159
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011160
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011161static void sharg(union node *arg, FILE * fp)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011162{
Eric Andersencb57d552001-06-28 07:25:16 +000011163 char *p;
11164 struct nodelist *bqlist;
11165 int subtype;
11166
11167 if (arg->type != NARG) {
11168 printf("<node type %d>\n", arg->type);
11169 fflush(stdout);
11170 abort();
11171 }
11172 bqlist = arg->narg.backquote;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011173 for (p = arg->narg.text; *p; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011174 switch (*p) {
11175 case CTLESC:
11176 putc(*++p, fp);
11177 break;
11178 case CTLVAR:
11179 putc('$', fp);
11180 putc('{', fp);
11181 subtype = *++p;
11182 if (subtype == VSLENGTH)
11183 putc('#', fp);
11184
11185 while (*p != '=')
11186 putc(*p++, fp);
11187
11188 if (subtype & VSNUL)
11189 putc(':', fp);
11190
11191 switch (subtype & VSTYPE) {
11192 case VSNORMAL:
11193 putc('}', fp);
11194 break;
11195 case VSMINUS:
11196 putc('-', fp);
11197 break;
11198 case VSPLUS:
11199 putc('+', fp);
11200 break;
11201 case VSQUESTION:
11202 putc('?', fp);
11203 break;
11204 case VSASSIGN:
11205 putc('=', fp);
11206 break;
11207 case VSTRIMLEFT:
11208 putc('#', fp);
11209 break;
11210 case VSTRIMLEFTMAX:
11211 putc('#', fp);
11212 putc('#', fp);
11213 break;
11214 case VSTRIMRIGHT:
11215 putc('%', fp);
11216 break;
11217 case VSTRIMRIGHTMAX:
11218 putc('%', fp);
11219 putc('%', fp);
11220 break;
11221 case VSLENGTH:
11222 break;
11223 default:
11224 printf("<subtype %d>", subtype);
11225 }
11226 break;
11227 case CTLENDVAR:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011228 putc('}', fp);
11229 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011230 case CTLBACKQ:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011231 case CTLBACKQ | CTLQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000011232 putc('$', fp);
11233 putc('(', fp);
11234 shtree(bqlist->n, -1, NULL, fp);
11235 putc(')', fp);
11236 break;
11237 default:
11238 putc(*p, fp);
11239 break;
11240 }
11241 }
11242}
11243
11244
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011245static void indent(int amount, char *pfx, FILE * fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011246{
11247 int i;
11248
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011249 for (i = 0; i < amount; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011250 if (pfx && i == amount - 1)
11251 fputs(pfx, fp);
11252 putc('\t', fp);
11253 }
11254}
Eric Andersencb57d552001-06-28 07:25:16 +000011255
Eric Andersencb57d552001-06-28 07:25:16 +000011256FILE *tracefile;
11257
11258#if DEBUG == 2
11259static int debug = 1;
11260#else
11261static int debug = 0;
11262#endif
11263
11264
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011265static void trputc(int c)
Eric Andersencb57d552001-06-28 07:25:16 +000011266{
11267 if (tracefile == NULL)
11268 return;
11269 putc(c, tracefile);
11270 if (c == '\n')
11271 fflush(tracefile);
11272}
11273
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011274static void trace(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +000011275{
11276 va_list va;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011277
Eric Andersencb57d552001-06-28 07:25:16 +000011278 va_start(va, fmt);
Eric Andersencb57d552001-06-28 07:25:16 +000011279 if (tracefile != NULL) {
11280 (void) vfprintf(tracefile, fmt, va);
11281 if (strchr(fmt, '\n'))
11282 (void) fflush(tracefile);
11283 }
11284 va_end(va);
11285}
11286
11287
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011288static void trputs(const char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011289{
11290 if (tracefile == NULL)
11291 return;
11292 fputs(s, tracefile);
11293 if (strchr(s, '\n'))
11294 fflush(tracefile);
11295}
11296
11297
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011298static void trstring(char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011299{
11300 char *p;
11301 char c;
11302
11303 if (tracefile == NULL)
11304 return;
11305 putc('"', tracefile);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011306 for (p = s; *p; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011307 switch (*p) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011308 case '\n':
11309 c = 'n';
11310 goto backslash;
11311 case '\t':
11312 c = 't';
11313 goto backslash;
11314 case '\r':
11315 c = 'r';
11316 goto backslash;
11317 case '"':
11318 c = '"';
11319 goto backslash;
11320 case '\\':
11321 c = '\\';
11322 goto backslash;
11323 case CTLESC:
11324 c = 'e';
11325 goto backslash;
11326 case CTLVAR:
11327 c = 'v';
11328 goto backslash;
11329 case CTLVAR + CTLQUOTE:
11330 c = 'V';
11331 goto backslash;
11332 case CTLBACKQ:
11333 c = 'q';
11334 goto backslash;
11335 case CTLBACKQ + CTLQUOTE:
11336 c = 'Q';
11337 goto backslash;
11338 backslash:putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011339 putc(c, tracefile);
11340 break;
11341 default:
11342 if (*p >= ' ' && *p <= '~')
11343 putc(*p, tracefile);
11344 else {
11345 putc('\\', tracefile);
11346 putc(*p >> 6 & 03, tracefile);
11347 putc(*p >> 3 & 07, tracefile);
11348 putc(*p & 07, tracefile);
11349 }
11350 break;
11351 }
11352 }
11353 putc('"', tracefile);
11354}
11355
11356
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011357static void trargs(char **ap)
Eric Andersencb57d552001-06-28 07:25:16 +000011358{
11359 if (tracefile == NULL)
11360 return;
11361 while (*ap) {
11362 trstring(*ap++);
11363 if (*ap)
11364 putc(' ', tracefile);
11365 else
11366 putc('\n', tracefile);
11367 }
11368 fflush(tracefile);
11369}
11370
11371
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011372static void opentrace()
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011373{
Eric Andersencb57d552001-06-28 07:25:16 +000011374 char s[100];
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011375
Eric Andersencb57d552001-06-28 07:25:16 +000011376#ifdef O_APPEND
11377 int flags;
11378#endif
11379
11380 if (!debug)
11381 return;
11382#ifdef not_this_way
11383 {
11384 char *p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011385
Eric Andersencb57d552001-06-28 07:25:16 +000011386 if ((p = getenv("HOME")) == NULL) {
11387 if (geteuid() == 0)
11388 p = "/";
11389 else
11390 p = "/tmp";
11391 }
Eric Andersen2870d962001-07-02 17:27:21 +000011392 strcpy(s, p);
Eric Andersencb57d552001-06-28 07:25:16 +000011393 strcat(s, "/trace");
11394 }
11395#else
Eric Andersen2870d962001-07-02 17:27:21 +000011396 strcpy(s, "./trace");
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011397#endif /* not_this_way */
Matt Kraaia5f09c62001-11-12 16:44:55 +000011398 if ((tracefile = wfopen(s, "a")) == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000011399 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011400#ifdef O_APPEND
11401 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11402 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11403#endif
11404 fputs("\nTracing started.\n", tracefile);
11405 fflush(tracefile);
11406}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011407#endif /* DEBUG */
Eric Andersencb57d552001-06-28 07:25:16 +000011408
11409
11410/*
Eric Andersencb57d552001-06-28 07:25:16 +000011411 * The trap builtin.
11412 */
11413
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011414static int trapcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011415{
11416 char *action;
11417 char **ap;
11418 int signo;
11419
11420 if (argc <= 1) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011421 for (signo = 0; signo < NSIG; signo++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011422 if (trap[signo] != NULL) {
11423 char *p;
Eric Andersen34506362001-08-02 05:02:46 +000011424 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011425
11426 p = single_quote(trap[signo]);
Eric Andersen34506362001-08-02 05:02:46 +000011427 sn = sys_siglist[signo];
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011428 if (sn == NULL)
Eric Andersen34506362001-08-02 05:02:46 +000011429 sn = u_signal_names(0, &signo, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011430 if (sn == NULL)
Eric Andersen34506362001-08-02 05:02:46 +000011431 sn = "???";
11432 printf("trap -- %s %s\n", p, sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011433 stunalloc(p);
11434 }
11435 }
11436 return 0;
11437 }
11438 ap = argv + 1;
11439 if (argc == 2)
11440 action = NULL;
11441 else
11442 action = *ap++;
11443 while (*ap) {
11444 if ((signo = decode_signal(*ap, 0)) < 0)
11445 error("%s: bad trap", *ap);
11446 INTOFF;
11447 if (action) {
11448 if (action[0] == '-' && action[1] == '\0')
11449 action = NULL;
11450 else
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011451 action = xstrdup(action);
Eric Andersencb57d552001-06-28 07:25:16 +000011452 }
Aaron Lehmann49c024a2002-08-02 06:39:47 +000011453 free(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000011454 trap[signo] = action;
11455 if (signo != 0)
11456 setsignal(signo);
11457 INTON;
11458 ap++;
11459 }
11460 return 0;
11461}
11462
11463
Eric Andersencb57d552001-06-28 07:25:16 +000011464/*
11465 * Set the signal handler for the specified signal. The routine figures
11466 * out what it should be set to.
11467 */
11468
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011469static void setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011470{
11471 int action;
11472 char *t;
11473 struct sigaction act;
11474
11475 if ((t = trap[signo]) == NULL)
11476 action = S_DFL;
11477 else if (*t != '\0')
11478 action = S_CATCH;
11479 else
11480 action = S_IGN;
11481 if (rootshell && action == S_DFL) {
11482 switch (signo) {
11483 case SIGINT:
11484 if (iflag || minusc || sflag == 0)
11485 action = S_CATCH;
11486 break;
11487 case SIGQUIT:
11488#ifdef DEBUG
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011489 {
Eric Andersencb57d552001-06-28 07:25:16 +000011490
11491 if (debug)
11492 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011493 }
Eric Andersencb57d552001-06-28 07:25:16 +000011494#endif
11495 /* FALLTHROUGH */
11496 case SIGTERM:
11497 if (iflag)
11498 action = S_IGN;
11499 break;
Eric Andersend35c5df2002-01-09 15:37:36 +000011500#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +000011501 case SIGTSTP:
11502 case SIGTTOU:
11503 if (mflag)
11504 action = S_IGN;
11505 break;
11506#endif
11507 }
11508 }
11509
11510 t = &sigmode[signo - 1];
11511 if (*t == 0) {
11512 /*
11513 * current setting unknown
11514 */
11515 if (sigaction(signo, 0, &act) == -1) {
11516 /*
11517 * Pretend it worked; maybe we should give a warning
11518 * here, but other shells don't. We don't alter
11519 * sigmode, so that we retry every time.
11520 */
11521 return;
11522 }
11523 if (act.sa_handler == SIG_IGN) {
11524 if (mflag && (signo == SIGTSTP ||
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011525 signo == SIGTTIN || signo == SIGTTOU)) {
11526 *t = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000011527 } else
11528 *t = S_HARD_IGN;
11529 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011530 *t = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000011531 }
11532 }
11533 if (*t == S_HARD_IGN || *t == action)
11534 return;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011535 act.sa_handler = ((action == S_CATCH) ? onsig
11536 : ((action == S_IGN) ? SIG_IGN : SIG_DFL));
Eric Andersencb57d552001-06-28 07:25:16 +000011537 *t = action;
11538 act.sa_flags = 0;
11539 sigemptyset(&act.sa_mask);
11540 sigaction(signo, &act, 0);
11541}
11542
11543/*
11544 * Ignore a signal.
11545 */
11546
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011547static void ignoresig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011548{
11549 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11550 signal(signo, SIG_IGN);
11551 }
11552 sigmode[signo - 1] = S_HARD_IGN;
11553}
11554
11555
Eric Andersencb57d552001-06-28 07:25:16 +000011556/*
11557 * Signal handler.
11558 */
11559
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011560static void onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011561{
11562 if (signo == SIGINT && trap[SIGINT] == NULL) {
11563 onint();
11564 return;
11565 }
11566 gotsig[signo - 1] = 1;
11567 pendingsigs++;
11568}
11569
11570
Eric Andersencb57d552001-06-28 07:25:16 +000011571/*
11572 * Called to execute a trap. Perhaps we should avoid entering new trap
11573 * handlers while we are executing a trap handler.
11574 */
11575
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011576static void dotrap(void)
Eric Andersen2870d962001-07-02 17:27:21 +000011577{
Eric Andersencb57d552001-06-28 07:25:16 +000011578 int i;
11579 int savestatus;
11580
11581 for (;;) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011582 for (i = 1;; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011583 if (gotsig[i - 1])
11584 break;
11585 if (i >= NSIG - 1)
11586 goto done;
11587 }
11588 gotsig[i - 1] = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011589 savestatus = exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +000011590 evalstring(trap[i], 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011591 exitstatus = savestatus;
Eric Andersencb57d552001-06-28 07:25:16 +000011592 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011593 done:
Eric Andersencb57d552001-06-28 07:25:16 +000011594 pendingsigs = 0;
11595}
11596
Eric Andersencb57d552001-06-28 07:25:16 +000011597/*
11598 * Called to exit the shell.
11599 */
11600
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011601static void exitshell(int status)
Eric Andersencb57d552001-06-28 07:25:16 +000011602{
11603 struct jmploc loc1, loc2;
11604 char *p;
11605
11606 TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
11607 if (setjmp(loc1.loc)) {
11608 goto l1;
11609 }
11610 if (setjmp(loc2.loc)) {
11611 goto l2;
11612 }
11613 handler = &loc1;
11614 if ((p = trap[0]) != NULL && *p != '\0') {
11615 trap[0] = NULL;
11616 evalstring(p, 0);
11617 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011618 l1:handler = &loc2; /* probably unnecessary */
Eric Andersencb57d552001-06-28 07:25:16 +000011619 flushall();
Eric Andersend35c5df2002-01-09 15:37:36 +000011620#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +000011621 setjobctl(0);
11622#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011623 l2:_exit(status);
Eric Andersencb57d552001-06-28 07:25:16 +000011624 /* NOTREACHED */
11625}
11626
11627static int decode_signal(const char *string, int minsig)
11628{
11629 int signo;
Eric Andersen34506362001-08-02 05:02:46 +000011630 const char *name = u_signal_names(string, &signo, minsig);
Eric Andersencb57d552001-06-28 07:25:16 +000011631
Eric Andersen34506362001-08-02 05:02:46 +000011632 return name ? signo : -1;
Eric Andersencb57d552001-06-28 07:25:16 +000011633}
Eric Andersen34506362001-08-02 05:02:46 +000011634
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011635static struct var **hashvar(const char *);
11636static void showvars(const char *, int, int);
11637static struct var **findvar(struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011638
11639/*
11640 * Initialize the varable symbol tables and import the environment
11641 */
11642
Eric Andersencb57d552001-06-28 07:25:16 +000011643/*
11644 * This routine initializes the builtin variables. It is called when the
11645 * shell is initialized and again when a shell procedure is spawned.
11646 */
11647
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011648static void initvar()
11649{
Eric Andersencb57d552001-06-28 07:25:16 +000011650 const struct varinit *ip;
11651 struct var *vp;
11652 struct var **vpp;
11653
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011654 for (ip = varinit; (vp = ip->var) != NULL; ip++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011655 if ((vp->flags & VEXPORT) == 0) {
11656 vpp = hashvar(ip->text);
11657 vp->next = *vpp;
11658 *vpp = vp;
Matt Kraaic8227632001-11-12 16:57:27 +000011659 vp->text = xstrdup(ip->text);
Eric Andersencb57d552001-06-28 07:25:16 +000011660 vp->flags = ip->flags;
11661 vp->func = ip->func;
11662 }
11663 }
Tim Riker497a8852002-04-13 05:37:10 +000011664#if !defined(CONFIG_FEATURE_COMMAND_EDITING) || !defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
Eric Andersencb57d552001-06-28 07:25:16 +000011665 /*
11666 * PS1 depends on uid
11667 */
11668 if ((vps1.flags & VEXPORT) == 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011669 vpp = hashvar("PS1=$ ");
Eric Andersencb57d552001-06-28 07:25:16 +000011670 vps1.next = *vpp;
11671 *vpp = &vps1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011672 vps1.text = xstrdup(geteuid()? "PS1=$ " : "PS1=# ");
11673 vps1.flags = VSTRFIXED | VTEXTFIXED;
Eric Andersencb57d552001-06-28 07:25:16 +000011674 }
Tim Riker497a8852002-04-13 05:37:10 +000011675#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011676}
11677
11678/*
11679 * Set the value of a variable. The flags argument is ored with the
11680 * flags of the variable. If val is NULL, the variable is unset.
11681 */
11682
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011683static void setvar(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011684{
11685 const char *p;
11686 int len;
11687 int namelen;
11688 char *nameeq;
11689 int isbad;
11690 int vallen = 0;
11691
11692 isbad = 0;
11693 p = name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011694 if (!is_name(*p))
Eric Andersencb57d552001-06-28 07:25:16 +000011695 isbad = 1;
11696 p++;
11697 for (;;) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011698 if (!is_in_name(*p)) {
Eric Andersencb57d552001-06-28 07:25:16 +000011699 if (*p == '\0' || *p == '=')
11700 break;
11701 isbad = 1;
11702 }
11703 p++;
11704 }
11705 namelen = p - name;
11706 if (isbad)
11707 error("%.*s: bad variable name", namelen, name);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011708 len = namelen + 2; /* 2 is space for '=' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +000011709 if (val == NULL) {
11710 flags |= VUNSET;
11711 } else {
11712 len += vallen = strlen(val);
11713 }
11714 INTOFF;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011715 nameeq = xmalloc(len);
Eric Andersencb57d552001-06-28 07:25:16 +000011716 memcpy(nameeq, name, namelen);
11717 nameeq[namelen] = '=';
11718 if (val) {
11719 memcpy(nameeq + namelen + 1, val, vallen + 1);
11720 } else {
11721 nameeq[namelen + 1] = '\0';
11722 }
11723 setvareq(nameeq, flags);
11724 INTON;
11725}
11726
11727
11728
11729/*
11730 * Same as setvar except that the variable and value are passed in
11731 * the first argument as name=value. Since the first argument will
11732 * be actually stored in the table, it should not be a string that
11733 * will go away.
11734 */
11735
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011736static void setvareq(char *s, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011737{
11738 struct var *vp, **vpp;
11739
11740 vpp = hashvar(s);
11741 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
11742 if ((vp = *findvar(vpp, s))) {
11743 if (vp->flags & VREADONLY) {
11744 size_t len = strchr(s, '=') - s;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011745
Eric Andersencb57d552001-06-28 07:25:16 +000011746 error("%.*s: is read only", len, s);
11747 }
11748 INTOFF;
11749
11750 if (vp->func && (flags & VNOFUNC) == 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011751 (*vp->func) (strchr(s, '=') + 1);
Eric Andersencb57d552001-06-28 07:25:16 +000011752
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011753 if ((vp->flags & (VTEXTFIXED | VSTACK)) == 0)
Aaron Lehmann49c024a2002-08-02 06:39:47 +000011754 free(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000011755
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011756 vp->flags &= ~(VTEXTFIXED | VSTACK | VUNSET);
Eric Andersencb57d552001-06-28 07:25:16 +000011757 vp->flags |= flags;
11758 vp->text = s;
11759
Eric Andersend35c5df2002-01-09 15:37:36 +000011760#ifdef CONFIG_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000011761 /*
11762 * We could roll this to a function, to handle it as
11763 * a regular variable function callback, but why bother?
11764 */
11765 if (iflag && (vp == &vmpath || (vp == &vmail && !mpathset())))
11766 chkmail(1);
Eric Andersenec074692001-10-31 11:05:49 +000011767#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011768 INTON;
11769 return;
11770 }
11771 /* not found */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011772 vp = xmalloc(sizeof(*vp));
Eric Andersencb57d552001-06-28 07:25:16 +000011773 vp->flags = flags;
11774 vp->text = s;
11775 vp->next = *vpp;
11776 vp->func = NULL;
11777 *vpp = vp;
11778}
11779
11780
11781
11782/*
11783 * Process a linked list of variable assignments.
11784 */
11785
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011786static void listsetvar(struct strlist *mylist)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011787{
Eric Andersencb57d552001-06-28 07:25:16 +000011788 struct strlist *lp;
11789
11790 INTOFF;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011791 for (lp = mylist; lp; lp = lp->next) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011792 setvareq(xstrdup(lp->text), 0);
Eric Andersencb57d552001-06-28 07:25:16 +000011793 }
11794 INTON;
11795}
11796
11797
11798
11799/*
11800 * Find the value of a variable. Returns NULL if not set.
11801 */
11802
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011803static const char *lookupvar(const char *name)
Eric Andersenec074692001-10-31 11:05:49 +000011804{
Eric Andersencb57d552001-06-28 07:25:16 +000011805 struct var *v;
11806
11807 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
11808 return strchr(v->text, '=') + 1;
11809 }
11810 return NULL;
11811}
11812
11813
11814
11815/*
11816 * Search the environment of a builtin command.
11817 */
11818
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011819static const char *bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000011820{
Eric Andersen62483552001-07-10 06:09:16 +000011821 const struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000011822
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011823 for (sp = cmdenviron; sp; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000011824 if (varequal(sp->text, name))
11825 return strchr(sp->text, '=') + 1;
11826 }
11827 return lookupvar(name);
11828}
11829
11830
11831
11832/*
11833 * Generate a list of exported variables. This routine is used to construct
11834 * the third argument to execve when executing a program.
11835 */
11836
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011837static char **environment()
11838{
Eric Andersencb57d552001-06-28 07:25:16 +000011839 int nenv;
11840 struct var **vpp;
11841 struct var *vp;
11842 char **env;
11843 char **ep;
11844
11845 nenv = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011846 for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) {
11847 for (vp = *vpp; vp; vp = vp->next)
Eric Andersencb57d552001-06-28 07:25:16 +000011848 if (vp->flags & VEXPORT)
11849 nenv++;
11850 }
11851 ep = env = stalloc((nenv + 1) * sizeof *env);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011852 for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) {
11853 for (vp = *vpp; vp; vp = vp->next)
Eric Andersencb57d552001-06-28 07:25:16 +000011854 if (vp->flags & VEXPORT)
11855 *ep++ = vp->text;
11856 }
11857 *ep = NULL;
11858 return env;
11859}
11860
11861
11862/*
Eric Andersencb57d552001-06-28 07:25:16 +000011863 * Command to list all variables which are set. Currently this command
11864 * is invoked from the set command when the set command is called without
11865 * any variables.
11866 */
11867
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011868static int showvarscmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011869{
11870 showvars(nullstr, VUNSET, VUNSET);
11871 return 0;
11872}
11873
11874
11875
11876/*
11877 * The export and readonly commands.
11878 */
11879
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011880static int exportcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011881{
11882 struct var *vp;
11883 char *name;
11884 const char *p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011885 int flag = argv[0][0] == 'r' ? VREADONLY : VEXPORT;
Eric Andersencb57d552001-06-28 07:25:16 +000011886 int pflag;
11887
11888 listsetvar(cmdenviron);
11889 pflag = (nextopt("p") == 'p');
11890 if (argc > 1 && !pflag) {
11891 while ((name = *argptr++) != NULL) {
11892 if ((p = strchr(name, '=')) != NULL) {
11893 p++;
11894 } else {
11895 if ((vp = *findvar(hashvar(name), name))) {
11896 vp->flags |= flag;
11897 goto found;
11898 }
11899 }
11900 setvar(name, p, flag);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011901 found:;
Eric Andersencb57d552001-06-28 07:25:16 +000011902 }
11903 } else {
11904 showvars(argv[0], flag, 0);
11905 }
11906 return 0;
11907}
11908
Eric Andersen34506362001-08-02 05:02:46 +000011909
Eric Andersencb57d552001-06-28 07:25:16 +000011910/*
11911 * The "local" command.
11912 */
11913
Eric Andersen2870d962001-07-02 17:27:21 +000011914/* funcnest nonzero if we are currently evaluating a function */
11915
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011916static int localcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011917{
11918 char *name;
11919
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011920 if (!funcnest)
Eric Andersencb57d552001-06-28 07:25:16 +000011921 error("Not in a function");
11922 while ((name = *argptr++) != NULL) {
11923 mklocal(name);
11924 }
11925 return 0;
11926}
11927
11928
11929/*
11930 * Make a variable a local variable. When a variable is made local, it's
11931 * value and flags are saved in a localvar structure. The saved values
11932 * will be restored when the shell function returns. We handle the name
11933 * "-" as a special case.
11934 */
11935
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011936static void mklocal(char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011937{
Eric Andersencb57d552001-06-28 07:25:16 +000011938 struct localvar *lvp;
11939 struct var **vpp;
11940 struct var *vp;
11941
11942 INTOFF;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011943 lvp = xmalloc(sizeof(struct localvar));
Eric Andersencb57d552001-06-28 07:25:16 +000011944 if (name[0] == '-' && name[1] == '\0') {
11945 char *p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011946
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011947 p = xmalloc(sizeof optet_vals);
Eric Andersen2870d962001-07-02 17:27:21 +000011948 lvp->text = memcpy(p, optet_vals, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000011949 vp = NULL;
11950 } else {
11951 vpp = hashvar(name);
11952 vp = *findvar(vpp, name);
11953 if (vp == NULL) {
11954 if (strchr(name, '='))
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011955 setvareq(xstrdup(name), VSTRFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +000011956 else
11957 setvar(name, NULL, VSTRFIXED);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011958 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000011959 lvp->text = NULL;
11960 lvp->flags = VUNSET;
11961 } else {
11962 lvp->text = vp->text;
11963 lvp->flags = vp->flags;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011964 vp->flags |= VSTRFIXED | VTEXTFIXED;
Eric Andersencb57d552001-06-28 07:25:16 +000011965 if (strchr(name, '='))
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011966 setvareq(xstrdup(name), 0);
Eric Andersencb57d552001-06-28 07:25:16 +000011967 }
11968 }
11969 lvp->vp = vp;
11970 lvp->next = localvars;
11971 localvars = lvp;
11972 INTON;
11973}
11974
11975
11976/*
11977 * Called after a function returns.
11978 */
11979
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011980static void poplocalvars()
11981{
Eric Andersencb57d552001-06-28 07:25:16 +000011982 struct localvar *lvp;
11983 struct var *vp;
11984
11985 while ((lvp = localvars) != NULL) {
11986 localvars = lvp->next;
11987 vp = lvp->vp;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011988 if (vp == NULL) { /* $- saved */
Eric Andersen2870d962001-07-02 17:27:21 +000011989 memcpy(optet_vals, lvp->text, sizeof optet_vals);
Aaron Lehmann49c024a2002-08-02 06:39:47 +000011990 free(lvp->text);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011991 } else if ((lvp->flags & (VUNSET | VSTRFIXED)) == VUNSET) {
11992 (void) unsetvar(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000011993 } else {
11994 if ((vp->flags & VTEXTFIXED) == 0)
Aaron Lehmann49c024a2002-08-02 06:39:47 +000011995 free(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000011996 vp->flags = lvp->flags;
11997 vp->text = lvp->text;
11998 }
Aaron Lehmann49c024a2002-08-02 06:39:47 +000011999 free(lvp);
Eric Andersencb57d552001-06-28 07:25:16 +000012000 }
12001}
12002
12003
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012004static int setvarcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012005{
12006 if (argc <= 2)
12007 return unsetcmd(argc, argv);
12008 else if (argc == 3)
12009 setvar(argv[1], argv[2], 0);
12010 else
12011 error("List assignment not implemented");
12012 return 0;
12013}
12014
12015
12016/*
12017 * The unset builtin command. We unset the function before we unset the
12018 * variable to allow a function to be unset when there is a readonly variable
12019 * with the same name.
12020 */
12021
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012022static int unsetcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012023{
12024 char **ap;
12025 int i;
12026 int flg_func = 0;
12027 int flg_var = 0;
12028 int ret = 0;
12029
12030 while ((i = nextopt("vf")) != '\0') {
12031 if (i == 'f')
12032 flg_func = 1;
12033 else
12034 flg_var = 1;
12035 }
12036 if (flg_func == 0 && flg_var == 0)
12037 flg_var = 1;
12038
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012039 for (ap = argptr; *ap; ap++) {
Eric Andersencb57d552001-06-28 07:25:16 +000012040 if (flg_func)
12041 unsetfunc(*ap);
12042 if (flg_var)
12043 ret |= unsetvar(*ap);
12044 }
12045 return ret;
12046}
12047
12048
12049/*
12050 * Unset the specified variable.
12051 */
12052
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012053static int unsetvar(const char *s)
Eric Andersen62483552001-07-10 06:09:16 +000012054{
Eric Andersencb57d552001-06-28 07:25:16 +000012055 struct var **vpp;
12056 struct var *vp;
12057
12058 vpp = findvar(hashvar(s), s);
12059 vp = *vpp;
12060 if (vp) {
12061 if (vp->flags & VREADONLY)
12062 return (1);
12063 INTOFF;
12064 if (*(strchr(vp->text, '=') + 1) != '\0')
12065 setvar(s, nullstr, 0);
12066 vp->flags &= ~VEXPORT;
12067 vp->flags |= VUNSET;
12068 if ((vp->flags & VSTRFIXED) == 0) {
12069 if ((vp->flags & VTEXTFIXED) == 0)
Aaron Lehmann49c024a2002-08-02 06:39:47 +000012070 free(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012071 *vpp = vp->next;
Aaron Lehmann49c024a2002-08-02 06:39:47 +000012072 free(vp);
Eric Andersencb57d552001-06-28 07:25:16 +000012073 }
12074 INTON;
12075 return (0);
12076 }
12077
12078 return (0);
12079}
12080
12081
12082
12083/*
12084 * Find the appropriate entry in the hash table from the name.
12085 */
12086
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012087static struct var **hashvar(const char *p)
Eric Andersen62483552001-07-10 06:09:16 +000012088{
Eric Andersencb57d552001-06-28 07:25:16 +000012089 unsigned int hashval;
12090
12091 hashval = ((unsigned char) *p) << 4;
12092 while (*p && *p != '=')
12093 hashval += (unsigned char) *p++;
12094 return &vartab[hashval % VTABSIZE];
12095}
12096
12097
12098
12099/*
12100 * Returns true if the two strings specify the same varable. The first
12101 * variable name is terminated by '='; the second may be terminated by
12102 * either '=' or '\0'.
12103 */
12104
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012105static int varequal(const char *p, const char *q)
Eric Andersen62483552001-07-10 06:09:16 +000012106{
Eric Andersencb57d552001-06-28 07:25:16 +000012107 while (*p == *q++) {
12108 if (*p++ == '=')
12109 return 1;
12110 }
12111 if (*p == '=' && *(q - 1) == '\0')
12112 return 1;
12113 return 0;
12114}
12115
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012116static void showvars(const char *myprefix, int mask, int xor)
Eric Andersencb57d552001-06-28 07:25:16 +000012117{
12118 struct var **vpp;
12119 struct var *vp;
12120 const char *sep = myprefix == nullstr ? myprefix : spcstr;
12121
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012122 for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) {
12123 for (vp = *vpp; vp; vp = vp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000012124 if ((vp->flags & mask) ^ xor) {
12125 char *p;
12126 int len;
12127
12128 p = strchr(vp->text, '=') + 1;
12129 len = p - vp->text;
12130 p = single_quote(p);
12131
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012132 printf("%s%s%.*s%s\n", myprefix, sep, len, vp->text, p);
Eric Andersencb57d552001-06-28 07:25:16 +000012133 stunalloc(p);
12134 }
12135 }
12136 }
12137}
12138
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012139static struct var **findvar(struct var **vpp, const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012140{
12141 for (; *vpp; vpp = &(*vpp)->next) {
12142 if (varequal((*vpp)->text, name)) {
12143 break;
12144 }
12145 }
12146 return vpp;
12147}
12148
12149/*
12150 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
12151 * This file contains code for the times builtin.
Eric Andersencb57d552001-06-28 07:25:16 +000012152 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012153static int timescmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012154{
12155 struct tms buf;
12156 long int clk_tck = sysconf(_SC_CLK_TCK);
12157
12158 times(&buf);
12159 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012160 (int) (buf.tms_utime / clk_tck / 60),
12161 ((double) buf.tms_utime) / clk_tck,
12162 (int) (buf.tms_stime / clk_tck / 60),
12163 ((double) buf.tms_stime) / clk_tck,
12164 (int) (buf.tms_cutime / clk_tck / 60),
12165 ((double) buf.tms_cutime) / clk_tck,
12166 (int) (buf.tms_cstime / clk_tck / 60),
12167 ((double) buf.tms_cstime) / clk_tck);
Eric Andersencb57d552001-06-28 07:25:16 +000012168 return 0;
12169}
12170
Eric Andersend35c5df2002-01-09 15:37:36 +000012171#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012172/* The let builtin. */
12173int letcmd(int argc, char **argv)
Eric Andersen74bcd162001-07-30 21:41:37 +000012174{
Eric Andersen34506362001-08-02 05:02:46 +000012175 int errcode;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012176 long result = 0;
12177
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012178 if (argc == 2) {
12179 char *tmp, *expression, p[13];
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012180
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012181 expression = strchr(argv[1], '=');
12182 if (!expression) {
Eric Andersen34506362001-08-02 05:02:46 +000012183 /* Cannot use 'error()' here, or the return code
12184 * will be incorrect */
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012185 out2fmt("sh: let: syntax error: \"%s\"\n", argv[1]);
12186 return 0;
Eric Andersen74bcd162001-07-30 21:41:37 +000012187 }
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012188 *expression = '\0';
12189 tmp = ++expression;
Eric Andersen34506362001-08-02 05:02:46 +000012190 result = arith(tmp, &errcode);
12191 if (errcode < 0) {
12192 /* Cannot use 'error()' here, or the return code
12193 * will be incorrect */
12194 out2fmt("sh: let: ");
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012195 if (errcode == -2)
Eric Andersen34506362001-08-02 05:02:46 +000012196 out2fmt("divide by zero");
12197 else
12198 out2fmt("syntax error: \"%s=%s\"\n", argv[1], expression);
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012199 return 0;
12200 }
12201 snprintf(p, 12, "%ld", result);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012202 setvar(argv[1], xstrdup(p), 0);
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012203 } else if (argc >= 3)
12204 synerror("invalid operand");
12205 return !result;
Eric Andersen74bcd162001-07-30 21:41:37 +000012206}
12207#endif
12208
12209
12210
Eric Andersendf82f612001-06-28 07:46:40 +000012211/*-
12212 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000012213 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000012214 *
12215 * This code is derived from software contributed to Berkeley by
12216 * Kenneth Almquist.
12217 *
12218 * Redistribution and use in source and binary forms, with or without
12219 * modification, are permitted provided that the following conditions
12220 * are met:
12221 * 1. Redistributions of source code must retain the above copyright
12222 * notice, this list of conditions and the following disclaimer.
12223 * 2. Redistributions in binary form must reproduce the above copyright
12224 * notice, this list of conditions and the following disclaimer in the
12225 * documentation and/or other materials provided with the distribution.
12226 *
Eric Andersen2870d962001-07-02 17:27:21 +000012227 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
12228 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000012229 *
12230 * 4. Neither the name of the University nor the names of its contributors
12231 * may be used to endorse or promote products derived from this software
12232 * without specific prior written permission.
12233 *
12234 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
12235 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
12236 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
12237 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
12238 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
12239 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
12240 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
12241 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
12242 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
12243 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
12244 * SUCH DAMAGE.
12245 */