blob: d20618d3cbf5c74a63b1237ee6795f266d470b25 [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 */
Eric Andersencb57d552001-06-28 07:25:16 +00007359 cmdloop(1);
7360 }
7361#if PROFILE
7362 monitor(0);
7363#endif
7364 exitshell(exitstatus);
7365 /* NOTREACHED */
7366}
7367
7368
7369/*
7370 * Read and execute commands. "Top" is nonzero for the top level command
7371 * loop; it turns on prompting if the shell is interactive.
7372 */
7373
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007374static void cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00007375{
7376 union node *n;
7377 struct stackmark smark;
7378 int inter;
7379 int numeof = 0;
7380
7381 TRACE(("cmdloop(%d) called\n", top));
7382 setstackmark(&smark);
7383 for (;;) {
7384 if (pendingsigs)
7385 dotrap();
7386 inter = 0;
7387 if (iflag && top) {
7388 inter++;
7389 showjobs(1);
Eric Andersend35c5df2002-01-09 15:37:36 +00007390#ifdef CONFIG_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +00007391 chkmail(0);
Eric Andersenec074692001-10-31 11:05:49 +00007392#endif
Eric Andersen3102ac42001-07-06 04:26:23 +00007393 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00007394 }
7395 n = parsecmd(inter);
7396 /* showtree(n); DEBUG */
7397 if (n == NEOF) {
7398 if (!top || numeof >= 50)
7399 break;
7400 if (!stoppedjobs()) {
7401 if (!Iflag)
7402 break;
7403 out2str("\nUse \"exit\" to leave shell.\n");
7404 }
7405 numeof++;
7406 } else if (n != NULL && nflag == 0) {
7407 job_warning = (job_warning == 2) ? 1 : 0;
7408 numeof = 0;
7409 evaltree(n, 0);
7410 }
7411 popstackmark(&smark);
7412 setstackmark(&smark);
7413 if (evalskip == SKIPFILE) {
7414 evalskip = 0;
7415 break;
7416 }
7417 }
7418 popstackmark(&smark);
7419}
7420
7421
7422
7423/*
7424 * Read /etc/profile or .profile. Return on error.
7425 */
7426
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007427static void read_profile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00007428{
7429 int fd;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007430 int xflag_save;
7431 int vflag_save;
Eric Andersencb57d552001-06-28 07:25:16 +00007432
7433 INTOFF;
7434 if ((fd = open(name, O_RDONLY)) >= 0)
7435 setinputfd(fd, 1);
7436 INTON;
7437 if (fd < 0)
7438 return;
7439 /* -q turns off -x and -v just when executing init files */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007440 /* Note: Might do a little redundant work, but reduces code size. */
7441 xflag_save = xflag;
7442 vflag_save = vflag;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007443 if (qflag) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007444 vflag = xflag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007445 }
7446 cmdloop(0);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007447 xflag = xflag_save;
7448 vflag = vflag_save;
Eric Andersencb57d552001-06-28 07:25:16 +00007449 popfile();
7450}
7451
7452
7453
7454/*
7455 * Read a file containing shell functions.
7456 */
7457
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007458static void readcmdfile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00007459{
7460 int fd;
7461
7462 INTOFF;
7463 if ((fd = open(name, O_RDONLY)) >= 0)
7464 setinputfd(fd, 1);
7465 else
7466 error("Can't open %s", name);
7467 INTON;
7468 cmdloop(0);
7469 popfile();
7470}
7471
7472
7473
7474/*
7475 * Take commands from a file. To be compatable we should do a path
7476 * search for the file, which is necessary to find sub-commands.
7477 */
7478
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007479static inline char *find_dot_file(char *mybasename)
Eric Andersencb57d552001-06-28 07:25:16 +00007480{
7481 char *fullname;
7482 const char *path = pathval();
7483 struct stat statb;
7484
7485 /* don't try this for absolute or relative paths */
7486 if (strchr(mybasename, '/'))
7487 return mybasename;
7488
7489 while ((fullname = padvance(&path, mybasename)) != NULL) {
7490 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
7491 /*
7492 * Don't bother freeing here, since it will
7493 * be freed by the caller.
7494 */
7495 return fullname;
7496 }
7497 stunalloc(fullname);
7498 }
7499
7500 /* not found in the PATH */
7501 error("%s: not found", mybasename);
7502 /* NOTREACHED */
7503}
7504
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007505static int dotcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007506{
7507 struct strlist *sp;
Eric Andersen69a20f02001-10-31 10:40:37 +00007508 volatile struct shparam saveparam;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007509
Eric Andersencb57d552001-06-28 07:25:16 +00007510 exitstatus = 0;
7511
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007512 for (sp = cmdenviron; sp; sp = sp->next)
7513 setvareq(xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +00007514
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007515 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00007516 char *fullname;
7517 struct stackmark smark;
7518
7519 setstackmark(&smark);
7520 fullname = find_dot_file(argv[1]);
Eric Andersen69a20f02001-10-31 10:40:37 +00007521
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007522 if (argc > 2) {
Eric Andersen69a20f02001-10-31 10:40:37 +00007523 saveparam = shellparam;
7524 shellparam.malloc = 0;
7525 shellparam.nparam = argc - 2;
7526 shellparam.p = argv + 2;
7527 };
7528
Eric Andersencb57d552001-06-28 07:25:16 +00007529 setinputfile(fullname, 1);
7530 commandname = fullname;
7531 cmdloop(0);
7532 popfile();
Eric Andersen69a20f02001-10-31 10:40:37 +00007533
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007534 if (argc > 2) {
Eric Andersen69a20f02001-10-31 10:40:37 +00007535 freeparam(&shellparam);
7536 shellparam = saveparam;
7537 };
7538
Eric Andersencb57d552001-06-28 07:25:16 +00007539 popstackmark(&smark);
7540 }
7541 return exitstatus;
7542}
7543
7544
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007545static int exitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007546{
7547 if (stoppedjobs())
7548 return 0;
7549 if (argc > 1)
7550 exitstatus = number(argv[1]);
7551 else
7552 exitstatus = oexitstatus;
7553 exitshell(exitstatus);
7554 /* NOTREACHED */
7555}
Eric Andersen62483552001-07-10 06:09:16 +00007556
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007557static pointer stalloc(int nbytes)
Eric Andersencb57d552001-06-28 07:25:16 +00007558{
7559 char *p;
7560
7561 nbytes = ALIGN(nbytes);
7562 if (nbytes > stacknleft) {
7563 int blocksize;
7564 struct stack_block *sp;
7565
7566 blocksize = nbytes;
7567 if (blocksize < MINSIZE)
7568 blocksize = MINSIZE;
7569 INTOFF;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007570 sp = xmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
Eric Andersencb57d552001-06-28 07:25:16 +00007571 sp->prev = stackp;
7572 stacknxt = sp->space;
7573 stacknleft = blocksize;
7574 stackp = sp;
7575 INTON;
7576 }
7577 p = stacknxt;
7578 stacknxt += nbytes;
7579 stacknleft -= nbytes;
7580 return p;
7581}
7582
7583
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007584static void stunalloc(pointer p)
Eric Andersen2870d962001-07-02 17:27:21 +00007585{
Eric Andersencb57d552001-06-28 07:25:16 +00007586#ifdef DEBUG
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007587 if (p == NULL) { /*DEBUG */
Eric Andersencb57d552001-06-28 07:25:16 +00007588 write(2, "stunalloc\n", 10);
7589 abort();
7590 }
7591#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007592 if (!(stacknxt >= (char *) p && (char *) p >= stackp->space)) {
Eric Andersencb57d552001-06-28 07:25:16 +00007593 p = stackp->space;
7594 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007595 stacknleft += stacknxt - (char *) p;
Eric Andersencb57d552001-06-28 07:25:16 +00007596 stacknxt = p;
7597}
7598
7599
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007600static void setstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00007601{
Eric Andersencb57d552001-06-28 07:25:16 +00007602 mark->stackp = stackp;
7603 mark->stacknxt = stacknxt;
7604 mark->stacknleft = stacknleft;
7605 mark->marknext = markp;
7606 markp = mark;
7607}
7608
7609
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007610static void popstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00007611{
Eric Andersencb57d552001-06-28 07:25:16 +00007612 struct stack_block *sp;
7613
7614 INTOFF;
7615 markp = mark->marknext;
7616 while (stackp != mark->stackp) {
7617 sp = stackp;
7618 stackp = sp->prev;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00007619 free(sp);
Eric Andersencb57d552001-06-28 07:25:16 +00007620 }
7621 stacknxt = mark->stacknxt;
7622 stacknleft = mark->stacknleft;
7623 INTON;
7624}
7625
7626
7627/*
7628 * When the parser reads in a string, it wants to stick the string on the
7629 * stack and only adjust the stack pointer when it knows how big the
7630 * string is. Stackblock (defined in stack.h) returns a pointer to a block
7631 * of space on top of the stack and stackblocklen returns the length of
7632 * this block. Growstackblock will grow this space by at least one byte,
7633 * possibly moving it (like realloc). Grabstackblock actually allocates the
7634 * part of the block that has been used.
7635 */
7636
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007637static void growstackblock(void)
7638{
Eric Andersencb57d552001-06-28 07:25:16 +00007639 char *p;
7640 int newlen = ALIGN(stacknleft * 2 + 100);
7641 char *oldspace = stacknxt;
7642 int oldlen = stacknleft;
7643 struct stack_block *sp;
7644 struct stack_block *oldstackp;
7645
7646 if (stacknxt == stackp->space && stackp != &stackbase) {
7647 INTOFF;
7648 oldstackp = stackp;
7649 sp = stackp;
7650 stackp = sp->prev;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007651 sp = xrealloc((pointer) sp,
7652 sizeof(struct stack_block) - MINSIZE + newlen);
Eric Andersencb57d552001-06-28 07:25:16 +00007653 sp->prev = stackp;
7654 stackp = sp;
7655 stacknxt = sp->space;
7656 stacknleft = newlen;
7657 {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007658 /* Stack marks pointing to the start of the old block
7659 * must be relocated to point to the new block
7660 */
7661 struct stackmark *xmark;
7662
7663 xmark = markp;
7664 while (xmark != NULL && xmark->stackp == oldstackp) {
7665 xmark->stackp = stackp;
7666 xmark->stacknxt = stacknxt;
7667 xmark->stacknleft = stacknleft;
7668 xmark = xmark->marknext;
7669 }
Eric Andersencb57d552001-06-28 07:25:16 +00007670 }
7671 INTON;
7672 } else {
7673 p = stalloc(newlen);
7674 memcpy(p, oldspace, oldlen);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007675 stacknxt = p; /* free the space */
7676 stacknleft += newlen; /* we just allocated */
Eric Andersencb57d552001-06-28 07:25:16 +00007677 }
7678}
7679
7680
7681
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007682static inline void grabstackblock(int len)
Eric Andersencb57d552001-06-28 07:25:16 +00007683{
7684 len = ALIGN(len);
7685 stacknxt += len;
7686 stacknleft -= len;
7687}
7688
7689
7690
7691/*
7692 * The following routines are somewhat easier to use that the above.
7693 * The user declares a variable of type STACKSTR, which may be declared
7694 * to be a register. The macro STARTSTACKSTR initializes things. Then
7695 * the user uses the macro STPUTC to add characters to the string. In
7696 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
7697 * grown as necessary. When the user is done, she can just leave the
7698 * string there and refer to it using stackblock(). Or she can allocate
7699 * the space for it using grabstackstr(). If it is necessary to allow
7700 * someone else to use the stack temporarily and then continue to grow
7701 * the string, the user should use grabstack to allocate the space, and
7702 * then call ungrabstr(p) to return to the previous mode of operation.
7703 *
7704 * USTPUTC is like STPUTC except that it doesn't check for overflow.
7705 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
7706 * is space for at least one character.
7707 */
7708
7709
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007710static char *growstackstr(void)
7711{
Eric Andersencb57d552001-06-28 07:25:16 +00007712 int len = stackblocksize();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007713
Eric Andersencb57d552001-06-28 07:25:16 +00007714 if (herefd >= 0 && len >= 1024) {
7715 xwrite(herefd, stackblock(), len);
7716 sstrnleft = len - 1;
7717 return stackblock();
7718 }
7719 growstackblock();
7720 sstrnleft = stackblocksize() - len - 1;
7721 return stackblock() + len;
7722}
7723
7724
7725/*
7726 * Called from CHECKSTRSPACE.
7727 */
7728
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007729static char *makestrspace(size_t newlen)
7730{
Eric Andersencb57d552001-06-28 07:25:16 +00007731 int len = stackblocksize() - sstrnleft;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007732
Eric Andersencb57d552001-06-28 07:25:16 +00007733 do {
7734 growstackblock();
7735 sstrnleft = stackblocksize() - len;
7736 } while (sstrnleft < newlen);
7737 return stackblock() + len;
7738}
7739
7740
7741
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007742static void ungrabstackstr(char *s, char *p)
Eric Andersen2870d962001-07-02 17:27:21 +00007743{
Eric Andersencb57d552001-06-28 07:25:16 +00007744 stacknleft += stacknxt - s;
7745 stacknxt = s;
7746 sstrnleft = stacknleft - (p - s);
7747}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007748
Eric Andersencb57d552001-06-28 07:25:16 +00007749/*
7750 * Miscelaneous builtins.
7751 */
7752
7753
7754#undef rflag
7755
Eric Andersencb57d552001-06-28 07:25:16 +00007756#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersen62483552001-07-10 06:09:16 +00007757typedef long rlim_t;
Eric Andersencb57d552001-06-28 07:25:16 +00007758#endif
7759
7760
7761
7762/*
7763 * The read builtin. The -e option causes backslashes to escape the
7764 * following character.
7765 *
7766 * This uses unbuffered input, which may be avoidable in some cases.
7767 */
7768
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007769static int readcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007770{
7771 char **ap;
7772 int backslash;
7773 char c;
7774 int rflag;
7775 char *prompt;
7776 const char *ifs;
7777 char *p;
7778 int startword;
7779 int status;
7780 int i;
7781
7782 rflag = 0;
7783 prompt = NULL;
7784 while ((i = nextopt("p:r")) != '\0') {
7785 if (i == 'p')
7786 prompt = optionarg;
7787 else
7788 rflag = 1;
7789 }
7790 if (prompt && isatty(0)) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007791 out2str(prompt); /* read without cmdedit */
Eric Andersencb57d552001-06-28 07:25:16 +00007792 flushall();
7793 }
7794 if (*(ap = argptr) == NULL)
7795 error("arg count");
7796 if ((ifs = bltinlookup("IFS")) == NULL)
7797 ifs = defifs;
7798 status = 0;
7799 startword = 1;
7800 backslash = 0;
7801 STARTSTACKSTR(p);
7802 for (;;) {
7803 if (read(0, &c, 1) != 1) {
7804 status = 1;
7805 break;
7806 }
7807 if (c == '\0')
7808 continue;
7809 if (backslash) {
7810 backslash = 0;
7811 if (c != '\n')
7812 STPUTC(c, p);
7813 continue;
7814 }
7815 if (!rflag && c == '\\') {
7816 backslash++;
7817 continue;
7818 }
7819 if (c == '\n')
7820 break;
7821 if (startword && *ifs == ' ' && strchr(ifs, c)) {
7822 continue;
7823 }
7824 startword = 0;
7825 if (backslash && c == '\\') {
7826 if (read(0, &c, 1) != 1) {
7827 status = 1;
7828 break;
7829 }
7830 STPUTC(c, p);
7831 } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
7832 STACKSTRNUL(p);
7833 setvar(*ap, stackblock(), 0);
7834 ap++;
7835 startword = 1;
7836 STARTSTACKSTR(p);
7837 } else {
7838 STPUTC(c, p);
7839 }
7840 }
7841 STACKSTRNUL(p);
7842 /* Remove trailing blanks */
7843 while (stackblock() <= --p && strchr(ifs, *p) != NULL)
7844 *p = '\0';
7845 setvar(*ap, stackblock(), 0);
7846 while (*++ap != NULL)
7847 setvar(*ap, nullstr, 0);
7848 return status;
7849}
7850
7851
7852
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007853static int umaskcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007854{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007855 static const char permuser[3] = "ugo";
7856 static const char permmode[3] = "rwx";
7857 static const short int permmask[] = {
7858 S_IRUSR, S_IWUSR, S_IXUSR,
7859 S_IRGRP, S_IWGRP, S_IXGRP,
7860 S_IROTH, S_IWOTH, S_IXOTH
7861 };
7862
Eric Andersencb57d552001-06-28 07:25:16 +00007863 char *ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007864 mode_t mask;
Eric Andersencb57d552001-06-28 07:25:16 +00007865 int i;
7866 int symbolic_mode = 0;
7867
Eric Andersen62483552001-07-10 06:09:16 +00007868 while (nextopt("S") != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00007869 symbolic_mode = 1;
7870 }
7871
7872 INTOFF;
7873 mask = umask(0);
7874 umask(mask);
7875 INTON;
7876
7877 if ((ap = *argptr) == NULL) {
7878 if (symbolic_mode) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007879 char buf[18];
7880 char *p = buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007881
7882 for (i = 0; i < 3; i++) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007883 int j;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007884
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007885 *p++ = permuser[i];
7886 *p++ = '=';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007887 for (j = 0; j < 3; j++) {
7888 if ((mask & permmask[3 * i + j]) == 0) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007889 *p++ = permmode[j];
7890 }
7891 }
7892 *p++ = ',';
7893 }
7894 *--p = 0;
7895 puts(buf);
Eric Andersencb57d552001-06-28 07:25:16 +00007896 } else {
Eric Andersen62483552001-07-10 06:09:16 +00007897 printf("%.4o\n", mask);
Eric Andersencb57d552001-06-28 07:25:16 +00007898 }
7899 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007900 if (is_digit((unsigned char) *ap)) {
Eric Andersencb57d552001-06-28 07:25:16 +00007901 mask = 0;
7902 do {
7903 if (*ap >= '8' || *ap < '0')
7904 error("Illegal number: %s", argv[1]);
7905 mask = (mask << 3) + (*ap - '0');
7906 } while (*++ap != '\0');
7907 umask(mask);
7908 } else {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007909 mask = ~mask & 0777;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007910 if (!parse_mode(ap, &mask)) {
Eric Andersencb57d552001-06-28 07:25:16 +00007911 error("Illegal mode: %s", ap);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007912 }
Eric Andersencb57d552001-06-28 07:25:16 +00007913 umask(~mask & 0777);
7914 }
7915 }
7916 return 0;
7917}
7918
7919/*
7920 * ulimit builtin
7921 *
7922 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
7923 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
7924 * ash by J.T. Conklin.
7925 *
7926 * Public domain.
7927 */
7928
7929struct limits {
7930 const char *name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007931 short cmd;
7932 short factor; /* multiply by to get rlim_{cur,max} values */
Eric Andersencb57d552001-06-28 07:25:16 +00007933};
7934
7935static const struct limits limits[] = {
7936#ifdef RLIMIT_CPU
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007937 {"time(seconds)", RLIMIT_CPU, 1},
Eric Andersencb57d552001-06-28 07:25:16 +00007938#endif
7939#ifdef RLIMIT_FSIZE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007940 {"file(blocks)", RLIMIT_FSIZE, 512},
Eric Andersencb57d552001-06-28 07:25:16 +00007941#endif
7942#ifdef RLIMIT_DATA
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007943 {"data(kbytes)", RLIMIT_DATA, 1024},
Eric Andersencb57d552001-06-28 07:25:16 +00007944#endif
7945#ifdef RLIMIT_STACK
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007946 {"stack(kbytes)", RLIMIT_STACK, 1024},
Eric Andersencb57d552001-06-28 07:25:16 +00007947#endif
7948#ifdef RLIMIT_CORE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007949 {"coredump(blocks)", RLIMIT_CORE, 512},
Eric Andersencb57d552001-06-28 07:25:16 +00007950#endif
7951#ifdef RLIMIT_RSS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007952 {"memory(kbytes)", RLIMIT_RSS, 1024},
Eric Andersencb57d552001-06-28 07:25:16 +00007953#endif
7954#ifdef RLIMIT_MEMLOCK
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007955 {"locked memory(kbytes)", RLIMIT_MEMLOCK, 1024},
Eric Andersencb57d552001-06-28 07:25:16 +00007956#endif
7957#ifdef RLIMIT_NPROC
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007958 {"process(processes)", RLIMIT_NPROC, 1},
Eric Andersencb57d552001-06-28 07:25:16 +00007959#endif
7960#ifdef RLIMIT_NOFILE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007961 {"nofiles(descriptors)", RLIMIT_NOFILE, 1},
Eric Andersencb57d552001-06-28 07:25:16 +00007962#endif
7963#ifdef RLIMIT_VMEM
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007964 {"vmemory(kbytes)", RLIMIT_VMEM, 1024},
Eric Andersencb57d552001-06-28 07:25:16 +00007965#endif
7966#ifdef RLIMIT_SWAP
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007967 {"swap(kbytes)", RLIMIT_SWAP, 1024},
Eric Andersencb57d552001-06-28 07:25:16 +00007968#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007969 {NULL, 0, 0}
Eric Andersencb57d552001-06-28 07:25:16 +00007970};
7971
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007972static int ulimitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007973{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007974 static const char unlimited_string[] = "unlimited";
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007975 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00007976 rlim_t val = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007977 enum { SOFT = 0x1, HARD = 0x2 } how = SOFT | HARD;
7978 const struct limits *l;
7979 int set, all = 0;
7980 int optc, what;
7981 struct rlimit limit;
Eric Andersencb57d552001-06-28 07:25:16 +00007982
7983 what = 'f';
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007984
7985 while ((optc = nextopt("HSa"
7986#ifdef RLIMIT_CPU
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007987 "t"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007988#endif
7989#ifdef RLIMIT_FSIZE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007990 "f"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007991#endif
7992#ifdef RLIMIT_DATA
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007993 "d"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007994#endif
7995#ifdef RLIMIT_STACK
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007996 "s"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007997#endif
7998#ifdef RLIMIT_CORE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007999 "c"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008000#endif
8001#ifdef RLIMIT_RSS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008002 "m"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008003#endif
8004#ifdef RLIMIT_MEMLOCK
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008005 "l"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008006#endif
8007#ifdef RLIMIT_NPROC
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008008 "p"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008009#endif
8010#ifdef RLIMIT_NOFILE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008011 "n"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008012#endif
8013#ifdef RLIMIT_VMEM
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008014 "v"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008015#endif
8016#ifdef RLIMIT_SWAP
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008017 "w"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008018#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008019 )) != '\0') {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008020 if (optc == 'H') {
Eric Andersencb57d552001-06-28 07:25:16 +00008021 how = HARD;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008022 } else if (optc == 'S') {
Eric Andersencb57d552001-06-28 07:25:16 +00008023 how = SOFT;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008024 } else if (optc == 'a') {
Eric Andersencb57d552001-06-28 07:25:16 +00008025 all = 1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008026 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00008027 what = optc;
8028 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008029 }
Eric Andersencb57d552001-06-28 07:25:16 +00008030
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008031 for (l = limits; l->name; l++) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008032 if (l->name[0] == what)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008033 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008034 if (l->name[1] == 'w' && what == 'w')
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008035 break;
8036 }
Eric Andersencb57d552001-06-28 07:25:16 +00008037
8038 set = *argptr ? 1 : 0;
8039 if (set) {
8040 char *p = *argptr;
8041
8042 if (all || argptr[1])
8043 error("too many arguments");
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008044 if (strcmp(p, unlimited_string) == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00008045 val = RLIM_INFINITY;
8046 else {
8047 val = (rlim_t) 0;
8048
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008049 while ((c = *p++) >= '0' && c <= '9') {
8050 val = (val * 10) + (long) (c - '0');
Eric Andersencb57d552001-06-28 07:25:16 +00008051 if (val < (rlim_t) 0)
8052 break;
8053 }
8054 if (c)
8055 error("bad number");
8056 val *= l->factor;
8057 }
8058 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008059
Eric Andersencb57d552001-06-28 07:25:16 +00008060 if (all) {
8061 for (l = limits; l->name; l++) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008062 printf("%-20s ", l->name);
Eric Andersencb57d552001-06-28 07:25:16 +00008063 getrlimit(l->cmd, &limit);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008064 OUTPUT_LIMIT:
Eric Andersencb57d552001-06-28 07:25:16 +00008065 if (how & SOFT)
8066 val = limit.rlim_cur;
8067 else if (how & HARD)
8068 val = limit.rlim_max;
8069
Eric Andersencb57d552001-06-28 07:25:16 +00008070 if (val == RLIM_INFINITY)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008071 puts(unlimited_string);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008072 else {
Eric Andersencb57d552001-06-28 07:25:16 +00008073 val /= l->factor;
Eric Andersen62483552001-07-10 06:09:16 +00008074 printf("%lld\n", (long long) val);
Eric Andersencb57d552001-06-28 07:25:16 +00008075 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008076 if (!all) {
8077 break;
8078 }
Eric Andersencb57d552001-06-28 07:25:16 +00008079 }
8080 return 0;
8081 }
8082
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008083 if (!set) {
8084 goto OUTPUT_LIMIT;
Eric Andersencb57d552001-06-28 07:25:16 +00008085 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008086
8087 getrlimit(l->cmd, &limit);
8088 if (how & HARD)
8089 limit.rlim_max = val;
8090 if (how & SOFT)
8091 limit.rlim_cur = val;
8092 if (setrlimit(l->cmd, &limit) < 0)
8093 error("error setting limit (%m)");
Eric Andersencb57d552001-06-28 07:25:16 +00008094 return 0;
8095}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008096
Eric Andersencb57d552001-06-28 07:25:16 +00008097/*
8098 * prefix -- see if pfx is a prefix of string.
8099 */
8100
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008101static int prefix(char const *pfx, char const *string)
Eric Andersen62483552001-07-10 06:09:16 +00008102{
Eric Andersencb57d552001-06-28 07:25:16 +00008103 while (*pfx) {
8104 if (*pfx++ != *string++)
8105 return 0;
8106 }
8107 return 1;
8108}
8109
Eric Andersen2870d962001-07-02 17:27:21 +00008110/*
8111 * Return true if s is a string of digits, and save munber in intptr
8112 * nagative is bad
8113 */
8114
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008115static int is_number(const char *p, int *intptr)
Eric Andersen2870d962001-07-02 17:27:21 +00008116{
8117 int ret = 0;
8118
8119 do {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008120 if (!is_digit(*p))
Eric Andersen2870d962001-07-02 17:27:21 +00008121 return 0;
8122 ret *= 10;
8123 ret += digit_val(*p);
8124 p++;
8125 } while (*p != '\0');
8126
8127 *intptr = ret;
8128 return 1;
8129}
Eric Andersencb57d552001-06-28 07:25:16 +00008130
8131/*
8132 * Convert a string of digits to an integer, printing an error message on
8133 * failure.
8134 */
8135
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008136static int number(const char *s)
Eric Andersen2870d962001-07-02 17:27:21 +00008137{
8138 int i;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008139
8140 if (!is_number(s, &i))
Eric Andersencb57d552001-06-28 07:25:16 +00008141 error("Illegal number: %s", s);
Eric Andersen2870d962001-07-02 17:27:21 +00008142 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00008143}
8144
Eric Andersencb57d552001-06-28 07:25:16 +00008145/*
8146 * Produce a possibly single quoted string suitable as input to the shell.
8147 * The return string is allocated on the stack.
8148 */
8149
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008150static char *single_quote(const char *s)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008151{
Eric Andersencb57d552001-06-28 07:25:16 +00008152 char *p;
8153
8154 STARTSTACKSTR(p);
8155
8156 do {
8157 char *q = p;
8158 size_t len1, len1p, len2, len2p;
8159
8160 len1 = strcspn(s, "'");
8161 len2 = strspn(s + len1, "'");
8162
8163 len1p = len1 ? len1 + 2 : len1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008164 len2p = len2 + ((len2 < 2) ? len2 : 2);
Eric Andersencb57d552001-06-28 07:25:16 +00008165
8166 CHECKSTRSPACE(len1p + len2p + 1, p);
8167
8168 if (len1) {
8169 *p = '\'';
Eric Andersencb57d552001-06-28 07:25:16 +00008170 q = p + 1 + len1;
8171 memcpy(p + 1, s, len1);
Eric Andersencb57d552001-06-28 07:25:16 +00008172 *q++ = '\'';
8173 s += len1;
8174 }
8175
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008176 if (len2 > 1) {
Eric Andersencb57d552001-06-28 07:25:16 +00008177 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008178 q += 1 + len2;
8179 memcpy(q + 1, s, len2);
8180 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008181 s += len2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008182 } else if (len2 == 1) {
8183 *q++ = '\\';
8184 *q = '\'';
8185 s++;
Eric Andersencb57d552001-06-28 07:25:16 +00008186 }
8187
8188 STADJUST(len1p + len2p, p);
8189 } while (*s);
8190
8191 USTPUTC(0, p);
8192
8193 return grabstackstr(p);
8194}
8195
8196/*
Eric Andersencb57d552001-06-28 07:25:16 +00008197 * Routine for dealing with parsed shell commands.
8198 */
8199
8200
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008201static void sizenodelist(const struct nodelist *);
8202static struct nodelist *copynodelist(const struct nodelist *);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008203static char *nodesavestr(const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00008204
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00008205#define CALCSIZE_TABLE
8206#define COPYNODE_TABLE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008207#if defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE)
8208/*
8209 * To collect a lot of redundant code in case statements for copynode()
8210 * and calcsize(), we implement a mini language here. Each type of node
8211 * struct has an associated instruction sequence that operates on its
8212 * members via their offsets. The instruction are pack in unsigned chars
8213 * with format IIDDDDDE where the bits are
8214 * I : part of the instruction opcode, which are
8215 * 00 : member is a pointer to another node
8216 * 40 : member is an integer
8217 * 80 : member is a pointer to a nodelist
8218 * CC : member is a pointer to a char string
8219 * D : data - the actual offset of the member to operate on in the struct
8220 * (since we assume bit 0 is set, it is not shifted)
8221 * E : flag signaling end of instruction sequence
8222 *
8223 * WARNING: In order to handle larger offsets for 64bit archs, this code
8224 * assumes that no offset can be an odd number and stores the
8225 * end-of-instructions flag in bit 0.
8226 */
8227
8228#define NODE_INTEGER 0x40
8229#define NODE_NODELIST 0x80
8230#define NODE_CHARPTR 0xC0
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008231#define NODE_NOMORE 0x01 /* Note: no offset should be odd (aligned) */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008232#define NODE_MBRMASK 0xC0
8233#define NODE_OFFSETMASK 0x3E
8234
8235static const unsigned char copynode_ops[35] = {
8236#define COPYNODE_OPS0 0
8237 offsetof(union node, nbinary.ch2),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008238 offsetof(union node, nbinary.ch1) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008239#define COPYNODE_OPS1 (COPYNODE_OPS0 + 2)
8240 offsetof(union node, ncmd.redirect),
8241 offsetof(union node, ncmd.args),
8242 offsetof(union node, ncmd.assign),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008243 offsetof(union node, ncmd.backgnd) | NODE_INTEGER | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008244#define COPYNODE_OPS2 (COPYNODE_OPS1 + 4)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008245 offsetof(union node, npipe.cmdlist) | NODE_NODELIST,
8246 offsetof(union node, npipe.backgnd) | NODE_INTEGER | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008247#define COPYNODE_OPS3 (COPYNODE_OPS2 + 2)
8248 offsetof(union node, nredir.redirect),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008249 offsetof(union node, nredir.n) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008250#define COPYNODE_OPS4 (COPYNODE_OPS3 + 2)
8251 offsetof(union node, nif.elsepart),
8252 offsetof(union node, nif.ifpart),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008253 offsetof(union node, nif.test) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008254#define COPYNODE_OPS5 (COPYNODE_OPS4 + 3)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008255 offsetof(union node, nfor.var) | NODE_CHARPTR,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008256 offsetof(union node, nfor.body),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008257 offsetof(union node, nfor.args) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008258#define COPYNODE_OPS6 (COPYNODE_OPS5 + 3)
8259 offsetof(union node, ncase.cases),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008260 offsetof(union node, ncase.expr) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008261#define COPYNODE_OPS7 (COPYNODE_OPS6 + 2)
8262 offsetof(union node, nclist.body),
8263 offsetof(union node, nclist.pattern),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008264 offsetof(union node, nclist.next) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008265#define COPYNODE_OPS8 (COPYNODE_OPS7 + 3)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008266 offsetof(union node, narg.backquote) | NODE_NODELIST,
8267 offsetof(union node, narg.text) | NODE_CHARPTR,
8268 offsetof(union node, narg.next) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008269#define COPYNODE_OPS9 (COPYNODE_OPS8 + 3)
8270 offsetof(union node, nfile.fname),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008271 offsetof(union node, nfile.fd) | NODE_INTEGER,
8272 offsetof(union node, nfile.next) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008273#define COPYNODE_OPS10 (COPYNODE_OPS9 + 3)
8274 offsetof(union node, ndup.vname),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008275 offsetof(union node, ndup.dupfd) | NODE_INTEGER,
8276 offsetof(union node, ndup.fd) | NODE_INTEGER,
8277 offsetof(union node, ndup.next) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008278#define COPYNODE_OPS11 (COPYNODE_OPS10 + 4)
8279 offsetof(union node, nhere.doc),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008280 offsetof(union node, nhere.fd) | NODE_INTEGER,
8281 offsetof(union node, nhere.next) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008282#define COPYNODE_OPS12 (COPYNODE_OPS11 + 3)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008283 offsetof(union node, nnot.com) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008284};
8285
8286#if COPYNODE_OPS12 != 34
8287#error COPYNODE_OPS12 is incorrect
8288#endif
8289
8290static const unsigned char copynode_ops_index[26] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008291 COPYNODE_OPS0, /* NSEMI */
8292 COPYNODE_OPS1, /* NCMD */
8293 COPYNODE_OPS2, /* NPIPE */
8294 COPYNODE_OPS3, /* NREDIR */
8295 COPYNODE_OPS3, /* NBACKGND */
8296 COPYNODE_OPS3, /* NSUBSHELL */
8297 COPYNODE_OPS0, /* NAND */
8298 COPYNODE_OPS0, /* NOR */
8299 COPYNODE_OPS4, /* NIF */
8300 COPYNODE_OPS0, /* NWHILE */
8301 COPYNODE_OPS0, /* NUNTIL */
8302 COPYNODE_OPS5, /* NFOR */
8303 COPYNODE_OPS6, /* NCASE */
8304 COPYNODE_OPS7, /* NCLIST */
8305 COPYNODE_OPS8, /* NDEFUN */
8306 COPYNODE_OPS8, /* NARG */
8307 COPYNODE_OPS9, /* NTO */
8308 COPYNODE_OPS9, /* NFROM */
8309 COPYNODE_OPS9, /* NFROMTO */
8310 COPYNODE_OPS9, /* NAPPEND */
8311 COPYNODE_OPS9, /* NTOOV */
8312 COPYNODE_OPS10, /* NTOFD */
8313 COPYNODE_OPS10, /* NFROMFD */
8314 COPYNODE_OPS11, /* NHERE */
8315 COPYNODE_OPS11, /* NXHERE */
8316 COPYNODE_OPS12, /* NNOT */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008317};
8318
8319#if NODE_CHARPTR != NODE_MBRMASK
8320#error NODE_CHARPTR != NODE_MBRMASK!!!
8321#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008322#endif /* defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE) */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008323
8324#ifdef COPYNODE_TABLE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008325static union node *copynode(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008326{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008327 union node *new;
8328 const unsigned char *p;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008329
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008330 if (n == NULL) {
8331 return NULL;
8332 }
8333 new = funcblock;
8334 new->type = n->type;
8335 funcblock = (char *) funcblock + (int) nodesize[n->type];
8336 p = copynode_ops + (int) copynode_ops_index[n->type];
8337 do {
8338 char *nn = ((char *) new) + ((int) (*p & NODE_OFFSETMASK));
8339 const char *no = ((const char *) n) + ((int) (*p & NODE_OFFSETMASK));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008340
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008341 if (!(*p & NODE_MBRMASK)) { /* standard node */
8342 *((union node **) nn) = copynode(*((const union node **) no));
8343 } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008344 *((const char **) nn) = nodesavestr(*((const char **) no));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008345 } else if (*p & NODE_NODELIST) { /* nodelist */
8346 *((struct nodelist **) nn)
8347 = copynodelist(*((const struct nodelist **) no));
8348 } else { /* integer */
8349 *((int *) nn) = *((int *) no);
8350 }
8351 } while (!(*p++ & NODE_NOMORE));
8352 return new;
Eric Andersencb57d552001-06-28 07:25:16 +00008353}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008354#else /* COPYNODE_TABLE */
8355static union node *copynode(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008356{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008357 union node *new;
Eric Andersencb57d552001-06-28 07:25:16 +00008358
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008359 if (n == NULL)
8360 return NULL;
8361 new = funcblock;
8362 funcblock = (char *) funcblock + nodesize[n->type];
8363 switch (n->type) {
8364 case NSEMI:
8365 case NAND:
8366 case NOR:
8367 case NWHILE:
8368 case NUNTIL:
8369 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8370 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8371 break;
8372 case NCMD:
8373 new->ncmd.redirect = copynode(n->ncmd.redirect);
8374 new->ncmd.args = copynode(n->ncmd.args);
8375 new->ncmd.assign = copynode(n->ncmd.assign);
8376 new->ncmd.backgnd = n->ncmd.backgnd;
8377 break;
8378 case NPIPE:
8379 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8380 new->npipe.backgnd = n->npipe.backgnd;
8381 break;
8382 case NREDIR:
8383 case NBACKGND:
8384 case NSUBSHELL:
8385 new->nredir.redirect = copynode(n->nredir.redirect);
8386 new->nredir.n = copynode(n->nredir.n);
8387 break;
8388 case NIF:
8389 new->nif.elsepart = copynode(n->nif.elsepart);
8390 new->nif.ifpart = copynode(n->nif.ifpart);
8391 new->nif.test = copynode(n->nif.test);
8392 break;
8393 case NFOR:
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008394 new->nfor.var = nodesavestr(n->nfor.var);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008395 new->nfor.body = copynode(n->nfor.body);
8396 new->nfor.args = copynode(n->nfor.args);
8397 break;
8398 case NCASE:
8399 new->ncase.cases = copynode(n->ncase.cases);
8400 new->ncase.expr = copynode(n->ncase.expr);
8401 break;
8402 case NCLIST:
8403 new->nclist.body = copynode(n->nclist.body);
8404 new->nclist.pattern = copynode(n->nclist.pattern);
8405 new->nclist.next = copynode(n->nclist.next);
8406 break;
8407 case NDEFUN:
8408 case NARG:
8409 new->narg.backquote = copynodelist(n->narg.backquote);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008410 new->narg.text = nodesavestr(n->narg.text);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008411 new->narg.next = copynode(n->narg.next);
8412 break;
8413 case NTO:
8414 case NFROM:
8415 case NFROMTO:
8416 case NAPPEND:
8417 case NTOOV:
8418 new->nfile.fname = copynode(n->nfile.fname);
8419 new->nfile.fd = n->nfile.fd;
8420 new->nfile.next = copynode(n->nfile.next);
8421 break;
8422 case NTOFD:
8423 case NFROMFD:
8424 new->ndup.vname = copynode(n->ndup.vname);
8425 new->ndup.dupfd = n->ndup.dupfd;
8426 new->ndup.fd = n->ndup.fd;
8427 new->ndup.next = copynode(n->ndup.next);
8428 break;
8429 case NHERE:
8430 case NXHERE:
8431 new->nhere.doc = copynode(n->nhere.doc);
8432 new->nhere.fd = n->nhere.fd;
8433 new->nhere.next = copynode(n->nhere.next);
8434 break;
8435 case NNOT:
8436 new->nnot.com = copynode(n->nnot.com);
8437 break;
8438 };
8439 new->type = n->type;
8440 return new;
Eric Andersencb57d552001-06-28 07:25:16 +00008441}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008442#endif /* COPYNODE_TABLE */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008443
8444#ifdef CALCSIZE_TABLE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008445static void calcsize(const union node *n)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008446{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008447 const unsigned char *p;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008448
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008449 if (n == NULL)
8450 return;
8451 funcblocksize += (int) nodesize[n->type];
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008452
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008453 p = copynode_ops + (int) copynode_ops_index[n->type];
8454 do {
8455 const char *no = ((const char *) n) + ((int) (*p & NODE_OFFSETMASK));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008456
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008457 if (!(*p & NODE_MBRMASK)) { /* standard node */
8458 calcsize(*((const union node **) no));
8459 } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
8460 funcstringsize += strlen(*((const char **) no)) + 1;
8461 } else if (*p & NODE_NODELIST) { /* nodelist */
8462 sizenodelist(*((const struct nodelist **) no));
8463 } /* else integer -- ignore */
8464 } while (!(*p++ & NODE_NOMORE));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008465}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008466#else /* CALCSIZE_TABLE */
8467static void calcsize(const union node *n)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008468{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008469 if (n == NULL)
8470 return;
8471 funcblocksize += nodesize[n->type];
8472 switch (n->type) {
8473 case NSEMI:
8474 case NAND:
8475 case NOR:
8476 case NWHILE:
8477 case NUNTIL:
8478 calcsize(n->nbinary.ch2);
8479 calcsize(n->nbinary.ch1);
8480 break;
8481 case NCMD:
8482 calcsize(n->ncmd.redirect);
8483 calcsize(n->ncmd.args);
8484 calcsize(n->ncmd.assign);
8485 break;
8486 case NPIPE:
8487 sizenodelist(n->npipe.cmdlist);
8488 break;
8489 case NREDIR:
8490 case NBACKGND:
8491 case NSUBSHELL:
8492 calcsize(n->nredir.redirect);
8493 calcsize(n->nredir.n);
8494 break;
8495 case NIF:
8496 calcsize(n->nif.elsepart);
8497 calcsize(n->nif.ifpart);
8498 calcsize(n->nif.test);
8499 break;
8500 case NFOR:
8501 funcstringsize += strlen(n->nfor.var) + 1;
8502 calcsize(n->nfor.body);
8503 calcsize(n->nfor.args);
8504 break;
8505 case NCASE:
8506 calcsize(n->ncase.cases);
8507 calcsize(n->ncase.expr);
8508 break;
8509 case NCLIST:
8510 calcsize(n->nclist.body);
8511 calcsize(n->nclist.pattern);
8512 calcsize(n->nclist.next);
8513 break;
8514 case NDEFUN:
8515 case NARG:
8516 sizenodelist(n->narg.backquote);
8517 funcstringsize += strlen(n->narg.text) + 1;
8518 calcsize(n->narg.next);
8519 break;
8520 case NTO:
8521 case NFROM:
8522 case NFROMTO:
8523 case NAPPEND:
8524 case NTOOV:
8525 calcsize(n->nfile.fname);
8526 calcsize(n->nfile.next);
8527 break;
8528 case NTOFD:
8529 case NFROMFD:
8530 calcsize(n->ndup.vname);
8531 calcsize(n->ndup.next);
8532 break;
8533 case NHERE:
8534 case NXHERE:
8535 calcsize(n->nhere.doc);
8536 calcsize(n->nhere.next);
8537 break;
8538 case NNOT:
8539 calcsize(n->nnot.com);
8540 break;
8541 };
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008542}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008543#endif /* CALCSIZE_TABLE */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008544
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008545static void sizenodelist(const struct nodelist *lp)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008546{
8547 while (lp) {
8548 funcblocksize += ALIGN(sizeof(struct nodelist));
8549 calcsize(lp->n);
8550 lp = lp->next;
8551 }
8552}
Eric Andersencb57d552001-06-28 07:25:16 +00008553
8554
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008555static struct nodelist *copynodelist(const struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008556{
8557 struct nodelist *start;
8558 struct nodelist **lpp;
8559
8560 lpp = &start;
8561 while (lp) {
8562 *lpp = funcblock;
8563 funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist));
8564 (*lpp)->n = copynode(lp->n);
8565 lp = lp->next;
8566 lpp = &(*lpp)->next;
8567 }
8568 *lpp = NULL;
8569 return start;
8570}
8571
8572
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008573static char *nodesavestr(const char *s)
Eric Andersencb57d552001-06-28 07:25:16 +00008574{
Eric Andersen62483552001-07-10 06:09:16 +00008575 const char *p = s;
8576 char *q = funcstring;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008577 char *rtn = funcstring;
Eric Andersencb57d552001-06-28 07:25:16 +00008578
8579 while ((*q++ = *p++) != '\0')
8580 continue;
8581 funcstring = q;
8582 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00008583}
8584
Eric Andersend35c5df2002-01-09 15:37:36 +00008585#ifdef CONFIG_ASH_GETOPTS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008586static int getopts(char *, char *, char **, int *, int *);
Eric Andersencb57d552001-06-28 07:25:16 +00008587#endif
8588
Eric Andersencb57d552001-06-28 07:25:16 +00008589/*
8590 * Process the shell command line arguments.
8591 */
8592
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008593static void procargs(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008594{
8595 int i;
8596
8597 argptr = argv;
8598 if (argc > 0)
8599 argptr++;
8600 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00008601 optent_val(i) = 2;
Eric Andersencb57d552001-06-28 07:25:16 +00008602 options(1);
8603 if (*argptr == NULL && minusc == NULL)
8604 sflag = 1;
8605 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8606 iflag = 1;
8607 if (mflag == 2)
8608 mflag = iflag;
8609 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00008610 if (optent_val(i) == 2)
8611 optent_val(i) = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008612 arg0 = argv[0];
8613 if (sflag == 0 && minusc == NULL) {
8614 commandname = argv[0];
8615 arg0 = *argptr++;
8616 setinputfile(arg0, 0);
8617 commandname = arg0;
8618 }
8619 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8620 if (argptr && minusc && *argptr)
Eric Andersen2870d962001-07-02 17:27:21 +00008621 arg0 = *argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00008622
8623 shellparam.p = argptr;
8624 shellparam.optind = 1;
8625 shellparam.optoff = -1;
8626 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8627 while (*argptr) {
8628 shellparam.nparam++;
8629 argptr++;
8630 }
8631 optschanged();
8632}
8633
8634
Eric Andersencb57d552001-06-28 07:25:16 +00008635
8636/*
8637 * Process shell options. The global variable argptr contains a pointer
8638 * to the argument list; we advance it past the options.
8639 */
8640
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008641static inline void minus_o(const char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +00008642{
8643 int i;
8644
8645 if (name == NULL) {
8646 out1str("Current option settings\n");
8647 for (i = 0; i < NOPTS; i++)
8648 printf("%-16s%s\n", optent_name(optlist[i]),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008649 optent_val(i) ? "on" : "off");
Eric Andersen62483552001-07-10 06:09:16 +00008650 } else {
8651 for (i = 0; i < NOPTS; i++)
8652 if (equal(name, optent_name(optlist[i]))) {
8653 setoption(optent_letter(optlist[i]), val);
8654 return;
8655 }
8656 error("Illegal option -o %s", name);
8657 }
8658}
8659
8660
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008661static void options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00008662{
8663 char *p;
8664 int val;
8665 int c;
8666
8667 if (cmdline)
8668 minusc = NULL;
8669 while ((p = *argptr) != NULL) {
8670 argptr++;
8671 if ((c = *p++) == '-') {
8672 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00008673 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8674 if (!cmdline) {
8675 /* "-" means turn off -x and -v */
8676 if (p[0] == '\0')
8677 xflag = vflag = 0;
8678 /* "--" means reset params */
8679 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00008680 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00008681 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008682 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00008683 }
8684 } else if (c == '+') {
8685 val = 0;
8686 } else {
8687 argptr--;
8688 break;
8689 }
8690 while ((c = *p++) != '\0') {
8691 if (c == 'c' && cmdline) {
8692 char *q;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008693
8694#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */
Eric Andersencb57d552001-06-28 07:25:16 +00008695 if (*p == '\0')
8696#endif
8697 q = *argptr++;
8698 if (q == NULL || minusc != NULL)
8699 error("Bad -c option");
8700 minusc = q;
8701#ifdef NOHACK
8702 break;
8703#endif
8704 } else if (c == 'o') {
8705 minus_o(*argptr, val);
8706 if (*argptr)
8707 argptr++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008708 } else if (cmdline && (c == '-')) { // long options
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008709 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +00008710 isloginsh = 1;
8711 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008712 } else {
8713 setoption(c, val);
8714 }
8715 }
8716 }
8717}
8718
Eric Andersencb57d552001-06-28 07:25:16 +00008719
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008720static void setoption(int flag, int val)
Eric Andersen2870d962001-07-02 17:27:21 +00008721{
Eric Andersencb57d552001-06-28 07:25:16 +00008722 int i;
8723
8724 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00008725 if (optent_letter(optlist[i]) == flag) {
8726 optent_val(i) = val;
Eric Andersencb57d552001-06-28 07:25:16 +00008727 if (val) {
8728 /* #%$ hack for ksh semantics */
8729 if (flag == 'V')
8730 Eflag = 0;
8731 else if (flag == 'E')
8732 Vflag = 0;
8733 }
8734 return;
8735 }
8736 error("Illegal option -%c", flag);
8737 /* NOTREACHED */
8738}
8739
8740
8741
Eric Andersencb57d552001-06-28 07:25:16 +00008742/*
8743 * Set the shell parameters.
8744 */
8745
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008746static void setparam(char **argv)
Eric Andersen2870d962001-07-02 17:27:21 +00008747{
Eric Andersencb57d552001-06-28 07:25:16 +00008748 char **newparam;
8749 char **ap;
8750 int nparam;
8751
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008752 for (nparam = 0; argv[nparam]; nparam++);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008753 ap = newparam = xmalloc((nparam + 1) * sizeof *ap);
Eric Andersencb57d552001-06-28 07:25:16 +00008754 while (*argv) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008755 *ap++ = xstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +00008756 }
8757 *ap = NULL;
8758 freeparam(&shellparam);
8759 shellparam.malloc = 1;
8760 shellparam.nparam = nparam;
8761 shellparam.p = newparam;
8762 shellparam.optind = 1;
8763 shellparam.optoff = -1;
8764}
8765
8766
8767/*
8768 * Free the list of positional parameters.
8769 */
8770
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008771static void freeparam(volatile struct shparam *param)
Eric Andersen2870d962001-07-02 17:27:21 +00008772{
Eric Andersencb57d552001-06-28 07:25:16 +00008773 char **ap;
8774
8775 if (param->malloc) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008776 for (ap = param->p; *ap; ap++)
Aaron Lehmann49c024a2002-08-02 06:39:47 +00008777 free(*ap);
8778 free(param->p);
Eric Andersencb57d552001-06-28 07:25:16 +00008779 }
8780}
8781
8782
8783
8784/*
8785 * The shift builtin command.
8786 */
8787
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008788static int shiftcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008789{
8790 int n;
8791 char **ap1, **ap2;
8792
8793 n = 1;
8794 if (argc > 1)
8795 n = number(argv[1]);
8796 if (n > shellparam.nparam)
8797 error("can't shift that many");
8798 INTOFF;
8799 shellparam.nparam -= n;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008800 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Eric Andersencb57d552001-06-28 07:25:16 +00008801 if (shellparam.malloc)
Aaron Lehmann49c024a2002-08-02 06:39:47 +00008802 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +00008803 }
8804 ap2 = shellparam.p;
8805 while ((*ap2++ = *ap1++) != NULL);
8806 shellparam.optind = 1;
8807 shellparam.optoff = -1;
8808 INTON;
8809 return 0;
8810}
8811
8812
8813
8814/*
8815 * The set command builtin.
8816 */
8817
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008818static int setcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008819{
8820 if (argc == 1)
8821 return showvarscmd(argc, argv);
8822 INTOFF;
8823 options(0);
8824 optschanged();
8825 if (*argptr != NULL) {
8826 setparam(argptr);
8827 }
8828 INTON;
8829 return 0;
8830}
8831
8832
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008833static void getoptsreset(const char *value)
Eric Andersencb57d552001-06-28 07:25:16 +00008834{
8835 shellparam.optind = number(value);
8836 shellparam.optoff = -1;
8837}
8838
Eric Andersenbdfd0d72001-10-24 05:00:29 +00008839#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00008840static void change_lc_all(const char *value)
8841{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008842 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00008843 setlocale(LC_ALL, value);
8844}
8845
8846static void change_lc_ctype(const char *value)
8847{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008848 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00008849 setlocale(LC_CTYPE, value);
8850}
8851
8852#endif
8853
Eric Andersend35c5df2002-01-09 15:37:36 +00008854#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008855/*
8856 * The getopts builtin. Shellparam.optnext points to the next argument
8857 * to be processed. Shellparam.optptr points to the next character to
8858 * be processed in the current argument. If shellparam.optnext is NULL,
8859 * then it's the first time getopts has been called.
8860 */
8861
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008862static int getoptscmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008863{
8864 char **optbase;
8865
8866 if (argc < 3)
8867 error("Usage: getopts optstring var [arg]");
8868 else if (argc == 3) {
8869 optbase = shellparam.p;
8870 if (shellparam.optind > shellparam.nparam + 1) {
8871 shellparam.optind = 1;
8872 shellparam.optoff = -1;
8873 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008874 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00008875 optbase = &argv[3];
8876 if (shellparam.optind > argc - 2) {
8877 shellparam.optind = 1;
8878 shellparam.optoff = -1;
8879 }
8880 }
8881
8882 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008883 &shellparam.optoff);
Eric Andersencb57d552001-06-28 07:25:16 +00008884}
8885
8886/*
8887 * Safe version of setvar, returns 1 on success 0 on failure.
8888 */
8889
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008890static int setvarsafe(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008891{
8892 struct jmploc jmploc;
8893 struct jmploc *volatile savehandler = handler;
8894 int err = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008895
Eric Andersencb57d552001-06-28 07:25:16 +00008896#ifdef __GNUC__
8897 (void) &err;
8898#endif
8899
8900 if (setjmp(jmploc.loc))
8901 err = 1;
8902 else {
8903 handler = &jmploc;
8904 setvar(name, val, flags);
8905 }
8906 handler = savehandler;
8907 return err;
8908}
8909
8910static int
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008911getopts(char *optstr, char *optvar, char **optfirst, int *myoptind,
8912 int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00008913{
8914 char *p, *q;
8915 char c = '?';
8916 int done = 0;
8917 int err = 0;
8918 char s[10];
8919 char **optnext = optfirst + *myoptind - 1;
8920
8921 if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008922 strlen(*(optnext - 1)) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00008923 p = NULL;
8924 else
8925 p = *(optnext - 1) + *optoff;
8926 if (p == NULL || *p == '\0') {
8927 /* Current word is done, advance */
8928 if (optnext == NULL)
8929 return 1;
8930 p = *optnext;
8931 if (p == NULL || *p != '-' || *++p == '\0') {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008932 atend:
Eric Andersencb57d552001-06-28 07:25:16 +00008933 *myoptind = optnext - optfirst + 1;
8934 p = NULL;
8935 done = 1;
8936 goto out;
8937 }
8938 optnext++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008939 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00008940 goto atend;
8941 }
8942
8943 c = *p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008944 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +00008945 if (*q == '\0') {
8946 if (optstr[0] == ':') {
8947 s[0] = c;
8948 s[1] = '\0';
8949 err |= setvarsafe("OPTARG", s, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008950 } else {
Eric Andersen3102ac42001-07-06 04:26:23 +00008951 out2fmt("Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00008952 (void) unsetvar("OPTARG");
8953 }
8954 c = '?';
8955 goto bad;
8956 }
8957 if (*++q == ':')
8958 q++;
8959 }
8960
8961 if (*++q == ':') {
8962 if (*p == '\0' && (p = *optnext) == NULL) {
8963 if (optstr[0] == ':') {
8964 s[0] = c;
8965 s[1] = '\0';
8966 err |= setvarsafe("OPTARG", s, 0);
8967 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008968 } else {
Eric Andersen3102ac42001-07-06 04:26:23 +00008969 out2fmt("No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00008970 (void) unsetvar("OPTARG");
8971 c = '?';
8972 }
8973 goto bad;
8974 }
8975
8976 if (p == *optnext)
8977 optnext++;
8978 setvarsafe("OPTARG", p, 0);
8979 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008980 } else
Eric Andersencb57d552001-06-28 07:25:16 +00008981 setvarsafe("OPTARG", "", 0);
8982 *myoptind = optnext - optfirst + 1;
8983 goto out;
8984
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008985 bad:
Eric Andersencb57d552001-06-28 07:25:16 +00008986 *myoptind = 1;
8987 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008988 out:
Eric Andersencb57d552001-06-28 07:25:16 +00008989 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersen3102ac42001-07-06 04:26:23 +00008990 snprintf(s, sizeof(s), "%d", *myoptind);
Eric Andersencb57d552001-06-28 07:25:16 +00008991 err |= setvarsafe("OPTIND", s, VNOFUNC);
8992 s[0] = c;
8993 s[1] = '\0';
8994 err |= setvarsafe(optvar, s, 0);
8995 if (err) {
8996 *myoptind = 1;
8997 *optoff = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00008998 exraise(EXERROR);
8999 }
9000 return done;
9001}
Eric Andersen2870d962001-07-02 17:27:21 +00009002#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009003
9004/*
9005 * XXX - should get rid of. have all builtins use getopt(3). the
9006 * library getopt must have the BSD extension static variable "optreset"
9007 * otherwise it can't be used within the shell safely.
9008 *
9009 * Standard option processing (a la getopt) for builtin routines. The
9010 * only argument that is passed to nextopt is the option string; the
9011 * other arguments are unnecessary. It return the character, or '\0' on
9012 * end of input.
9013 */
9014
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009015static int nextopt(const char *optstring)
Eric Andersen62483552001-07-10 06:09:16 +00009016{
Eric Andersencb57d552001-06-28 07:25:16 +00009017 char *p;
9018 const char *q;
9019 char c;
9020
9021 if ((p = optptr) == NULL || *p == '\0') {
9022 p = *argptr;
9023 if (p == NULL || *p != '-' || *++p == '\0')
9024 return '\0';
9025 argptr++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009026 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009027 return '\0';
9028 }
9029 c = *p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009030 for (q = optstring; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +00009031 if (*q == '\0')
9032 error("Illegal option -%c", c);
9033 if (*++q == ':')
9034 q++;
9035 }
9036 if (*++q == ':') {
9037 if (*p == '\0' && (p = *argptr++) == NULL)
9038 error("No arg for -%c option", c);
9039 optionarg = p;
9040 p = NULL;
9041 }
9042 optptr = p;
9043 return c;
9044}
9045
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009046static void flushall()
9047{
Eric Andersencb57d552001-06-28 07:25:16 +00009048 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009049 fflush(stdout);
Eric Andersencb57d552001-06-28 07:25:16 +00009050 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009051}
9052
9053
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009054static void out2fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009055{
9056 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009057
Eric Andersencb57d552001-06-28 07:25:16 +00009058 va_start(ap, fmt);
Eric Andersen3102ac42001-07-06 04:26:23 +00009059 vfprintf(stderr, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009060 va_end(ap);
9061}
9062
Eric Andersencb57d552001-06-28 07:25:16 +00009063/*
9064 * Version of write which resumes after a signal is caught.
9065 */
9066
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009067static int xwrite(int fd, const char *buf, int nbytes)
Eric Andersen2870d962001-07-02 17:27:21 +00009068{
Eric Andersencb57d552001-06-28 07:25:16 +00009069 int ntry;
9070 int i;
9071 int n;
9072
9073 n = nbytes;
9074 ntry = 0;
9075 for (;;) {
9076 i = write(fd, buf, n);
9077 if (i > 0) {
9078 if ((n -= i) <= 0)
9079 return nbytes;
9080 buf += i;
9081 ntry = 0;
9082 } else if (i == 0) {
9083 if (++ntry > 10)
9084 return nbytes - n;
9085 } else if (errno != EINTR) {
9086 return -1;
9087 }
9088 }
9089}
9090
9091
Eric Andersencb57d552001-06-28 07:25:16 +00009092/*
9093 * Shell command parser.
9094 */
9095
9096#define EOFMARKLEN 79
9097
9098
9099
9100struct heredoc {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009101 struct heredoc *next; /* next here document in list */
9102 union node *here; /* redirection node */
9103 char *eofmark; /* string indicating end of input */
9104 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009105};
9106
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009107static struct heredoc *heredoclist; /* list of here documents to read */
9108static int parsebackquote; /* nonzero if we are inside backquotes */
9109static int doprompt; /* if set, prompt the user */
9110static int needprompt; /* true if interactive and at start of line */
9111static int lasttoken; /* last token read */
Eric Andersencb57d552001-06-28 07:25:16 +00009112
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009113static char *wordtext; /* text of last word returned by readtoken */
Eric Andersencb57d552001-06-28 07:25:16 +00009114
Eric Andersen2870d962001-07-02 17:27:21 +00009115static struct nodelist *backquotelist;
9116static union node *redirnode;
Eric Andersen044228d2001-07-17 01:12:36 +00009117static struct heredoc *heredoc;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009118static int quoteflag; /* set if (part of) last token was quoted */
9119static int startlinno; /* line # where last token started */
Eric Andersencb57d552001-06-28 07:25:16 +00009120
9121
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009122static union node *list(int);
9123static union node *andor(void);
9124static union node *pipeline(void);
9125static union node *command(void);
Eric Andersena3483db2001-10-24 08:01:06 +00009126static union node *simplecmd(union node **rpp, union node *redir);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009127static void parsefname(void);
9128static void parseheredoc(void);
9129static char peektoken(void);
9130static int readtoken(void);
9131static int xxreadtoken(void);
9132static int readtoken1(int, int, const char *, int);
9133static int noexpand(char *);
9134static void synexpect(int) __attribute__ ((noreturn));
9135static void synerror(const char *) __attribute__ ((noreturn));
9136static void setprompt(int);
Eric Andersencb57d552001-06-28 07:25:16 +00009137
9138
9139/*
9140 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9141 * valid parse tree indicating a blank line.)
9142 */
9143
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009144static union node *parsecmd(int interact)
Eric Andersencb57d552001-06-28 07:25:16 +00009145{
9146 int t;
9147
9148 tokpushback = 0;
9149 doprompt = interact;
9150 if (doprompt)
9151 setprompt(1);
9152 else
9153 setprompt(0);
9154 needprompt = 0;
9155 t = readtoken();
9156 if (t == TEOF)
9157 return NEOF;
9158 if (t == TNL)
9159 return NULL;
9160 tokpushback++;
9161 return list(1);
9162}
9163
9164
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009165static union node *list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +00009166{
9167 union node *n1, *n2, *n3;
9168 int tok;
9169
9170 checkkwd = 2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009171 if (nlflag == 0 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009172 return NULL;
9173 n1 = NULL;
9174 for (;;) {
9175 n2 = andor();
9176 tok = readtoken();
9177 if (tok == TBACKGND) {
9178 if (n2->type == NCMD || n2->type == NPIPE) {
9179 n2->ncmd.backgnd = 1;
9180 } else if (n2->type == NREDIR) {
9181 n2->type = NBACKGND;
9182 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009183 n3 = (union node *) stalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009184 n3->type = NBACKGND;
9185 n3->nredir.n = n2;
9186 n3->nredir.redirect = NULL;
9187 n2 = n3;
9188 }
9189 }
9190 if (n1 == NULL) {
9191 n1 = n2;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009192 } else {
9193 n3 = (union node *) stalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009194 n3->type = NSEMI;
9195 n3->nbinary.ch1 = n1;
9196 n3->nbinary.ch2 = n2;
9197 n1 = n3;
9198 }
9199 switch (tok) {
9200 case TBACKGND:
9201 case TSEMI:
9202 tok = readtoken();
9203 /* fall through */
9204 case TNL:
9205 if (tok == TNL) {
9206 parseheredoc();
9207 if (nlflag)
9208 return n1;
9209 } else {
9210 tokpushback++;
9211 }
9212 checkkwd = 2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009213 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009214 return n1;
9215 break;
9216 case TEOF:
9217 if (heredoclist)
9218 parseheredoc();
9219 else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009220 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009221 return n1;
9222 default:
9223 if (nlflag)
9224 synexpect(-1);
9225 tokpushback++;
9226 return n1;
9227 }
9228 }
9229}
9230
9231
9232
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009233static union node *andor()
9234{
Eric Andersencb57d552001-06-28 07:25:16 +00009235 union node *n1, *n2, *n3;
9236 int t;
9237
9238 checkkwd = 1;
9239 n1 = pipeline();
9240 for (;;) {
9241 if ((t = readtoken()) == TAND) {
9242 t = NAND;
9243 } else if (t == TOR) {
9244 t = NOR;
9245 } else {
9246 tokpushback++;
9247 return n1;
9248 }
9249 checkkwd = 2;
9250 n2 = pipeline();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009251 n3 = (union node *) stalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009252 n3->type = t;
9253 n3->nbinary.ch1 = n1;
9254 n3->nbinary.ch2 = n2;
9255 n1 = n3;
9256 }
9257}
9258
9259
9260
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009261static union node *pipeline()
9262{
Eric Andersencb57d552001-06-28 07:25:16 +00009263 union node *n1, *n2, *pipenode;
9264 struct nodelist *lp, *prev;
9265 int negate;
9266
9267 negate = 0;
9268 TRACE(("pipeline: entered\n"));
9269 if (readtoken() == TNOT) {
9270 negate = !negate;
9271 checkkwd = 1;
9272 } else
9273 tokpushback++;
9274 n1 = command();
9275 if (readtoken() == TPIPE) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009276 pipenode = (union node *) stalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +00009277 pipenode->type = NPIPE;
9278 pipenode->npipe.backgnd = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009279 lp = (struct nodelist *) stalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00009280 pipenode->npipe.cmdlist = lp;
9281 lp->n = n1;
9282 do {
9283 prev = lp;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009284 lp = (struct nodelist *) stalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00009285 checkkwd = 2;
9286 lp->n = command();
9287 prev->next = lp;
9288 } while (readtoken() == TPIPE);
9289 lp->next = NULL;
9290 n1 = pipenode;
9291 }
9292 tokpushback++;
9293 if (negate) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009294 n2 = (union node *) stalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +00009295 n2->type = NNOT;
9296 n2->nnot.com = n1;
9297 return n2;
9298 } else
9299 return n1;
9300}
9301
9302
9303
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009304static union node *command(void)
9305{
Eric Andersencb57d552001-06-28 07:25:16 +00009306 union node *n1, *n2;
9307 union node *ap, **app;
9308 union node *cp, **cpp;
9309 union node *redir, **rpp;
9310 int t;
9311
9312 redir = NULL;
9313 n1 = NULL;
9314 rpp = &redir;
9315
Eric Andersen88cec252001-09-06 17:35:20 +00009316 /* Check for redirection which may precede command */
9317 while (readtoken() == TREDIR) {
9318 *rpp = n2 = redirnode;
9319 rpp = &n2->nfile.next;
9320 parsefname();
9321 }
9322 tokpushback++;
9323
Eric Andersencb57d552001-06-28 07:25:16 +00009324 switch (readtoken()) {
9325 case TIF:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009326 n1 = (union node *) stalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009327 n1->type = NIF;
9328 n1->nif.test = list(0);
9329 if (readtoken() != TTHEN)
9330 synexpect(TTHEN);
9331 n1->nif.ifpart = list(0);
9332 n2 = n1;
9333 while (readtoken() == TELIF) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009334 n2->nif.elsepart = (union node *) stalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009335 n2 = n2->nif.elsepart;
9336 n2->type = NIF;
9337 n2->nif.test = list(0);
9338 if (readtoken() != TTHEN)
9339 synexpect(TTHEN);
9340 n2->nif.ifpart = list(0);
9341 }
9342 if (lasttoken == TELSE)
9343 n2->nif.elsepart = list(0);
9344 else {
9345 n2->nif.elsepart = NULL;
9346 tokpushback++;
9347 }
9348 if (readtoken() != TFI)
9349 synexpect(TFI);
9350 checkkwd = 1;
9351 break;
9352 case TWHILE:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009353 case TUNTIL:{
Eric Andersencb57d552001-06-28 07:25:16 +00009354 int got;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009355 n1 = (union node *) stalloc(sizeof(struct nbinary));
9356 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +00009357 n1->nbinary.ch1 = list(0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009358 if ((got = readtoken()) != TDO) {
9359 TRACE(("expecting DO got %s %s\n", tokname(got),
9360 got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009361 synexpect(TDO);
9362 }
9363 n1->nbinary.ch2 = list(0);
9364 if (readtoken() != TDONE)
9365 synexpect(TDONE);
9366 checkkwd = 1;
9367 break;
9368 }
9369 case TFOR:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009370 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Eric Andersencb57d552001-06-28 07:25:16 +00009371 synerror("Bad for loop variable");
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009372 n1 = (union node *) stalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +00009373 n1->type = NFOR;
9374 n1->nfor.var = wordtext;
9375 checkkwd = 1;
9376 if (readtoken() == TIN) {
9377 app = &ap;
9378 while (readtoken() == TWORD) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009379 n2 = (union node *) stalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009380 n2->type = NARG;
9381 n2->narg.text = wordtext;
9382 n2->narg.backquote = backquotelist;
9383 *app = n2;
9384 app = &n2->narg.next;
9385 }
9386 *app = NULL;
9387 n1->nfor.args = ap;
9388 if (lasttoken != TNL && lasttoken != TSEMI)
9389 synexpect(-1);
9390 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009391 static char argvars[5] = { CTLVAR, VSNORMAL | VSQUOTE,
9392 '@', '=', '\0'
9393 };
9394 n2 = (union node *) stalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009395 n2->type = NARG;
9396 n2->narg.text = argvars;
9397 n2->narg.backquote = NULL;
9398 n2->narg.next = NULL;
9399 n1->nfor.args = n2;
9400 /*
9401 * Newline or semicolon here is optional (but note
9402 * that the original Bourne shell only allowed NL).
9403 */
9404 if (lasttoken != TNL && lasttoken != TSEMI)
9405 tokpushback++;
9406 }
9407 checkkwd = 2;
9408 if (readtoken() != TDO)
9409 synexpect(TDO);
9410 n1->nfor.body = list(0);
9411 if (readtoken() != TDONE)
9412 synexpect(TDONE);
9413 checkkwd = 1;
9414 break;
9415 case TCASE:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009416 n1 = (union node *) stalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +00009417 n1->type = NCASE;
9418 if (readtoken() != TWORD)
9419 synexpect(TWORD);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009420 n1->ncase.expr = n2 = (union node *) stalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009421 n2->type = NARG;
9422 n2->narg.text = wordtext;
9423 n2->narg.backquote = backquotelist;
9424 n2->narg.next = NULL;
9425 do {
9426 checkkwd = 1;
9427 } while (readtoken() == TNL);
9428 if (lasttoken != TIN)
9429 synerror("expecting \"in\"");
9430 cpp = &n1->ncase.cases;
9431 checkkwd = 2, readtoken();
9432 do {
9433 if (lasttoken == TLP)
9434 readtoken();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009435 *cpp = cp = (union node *) stalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +00009436 cp->type = NCLIST;
9437 app = &cp->nclist.pattern;
9438 for (;;) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009439 *app = ap = (union node *) stalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009440 ap->type = NARG;
9441 ap->narg.text = wordtext;
9442 ap->narg.backquote = backquotelist;
9443 if (checkkwd = 2, readtoken() != TPIPE)
9444 break;
9445 app = &ap->narg.next;
9446 readtoken();
9447 }
9448 ap->narg.next = NULL;
9449 if (lasttoken != TRP)
9450 synexpect(TRP);
9451 cp->nclist.body = list(0);
9452
9453 checkkwd = 2;
9454 if ((t = readtoken()) != TESAC) {
9455 if (t != TENDCASE)
9456 synexpect(TENDCASE);
9457 else
9458 checkkwd = 2, readtoken();
9459 }
9460 cpp = &cp->nclist.next;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009461 } while (lasttoken != TESAC);
Eric Andersencb57d552001-06-28 07:25:16 +00009462 *cpp = NULL;
9463 checkkwd = 1;
9464 break;
9465 case TLP:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009466 n1 = (union node *) stalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009467 n1->type = NSUBSHELL;
9468 n1->nredir.n = list(0);
9469 n1->nredir.redirect = NULL;
9470 if (readtoken() != TRP)
9471 synexpect(TRP);
9472 checkkwd = 1;
9473 break;
9474 case TBEGIN:
9475 n1 = list(0);
9476 if (readtoken() != TEND)
9477 synexpect(TEND);
9478 checkkwd = 1;
9479 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009480 /* Handle an empty command like other simple commands. */
Eric Andersencb57d552001-06-28 07:25:16 +00009481 case TSEMI:
9482 case TAND:
9483 case TOR:
9484 case TNL:
9485 case TEOF:
9486 case TRP:
9487 case TBACKGND:
9488 /*
9489 * An empty command before a ; doesn't make much sense, and
9490 * should certainly be disallowed in the case of `if ;'.
9491 */
9492 if (!redir)
9493 synexpect(-1);
9494 case TWORD:
Eric Andersencb57d552001-06-28 07:25:16 +00009495 tokpushback++;
Eric Andersena3483db2001-10-24 08:01:06 +00009496 n1 = simplecmd(rpp, redir);
Eric Andersencb57d552001-06-28 07:25:16 +00009497 return n1;
9498 default:
9499 synexpect(-1);
9500 /* NOTREACHED */
9501 }
9502
9503 /* Now check for redirection which may follow command */
9504 while (readtoken() == TREDIR) {
9505 *rpp = n2 = redirnode;
9506 rpp = &n2->nfile.next;
9507 parsefname();
9508 }
9509 tokpushback++;
9510 *rpp = NULL;
9511 if (redir) {
9512 if (n1->type != NSUBSHELL) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009513 n2 = (union node *) stalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009514 n2->type = NREDIR;
9515 n2->nredir.n = n1;
9516 n1 = n2;
9517 }
9518 n1->nredir.redirect = redir;
9519 }
9520
9521 return n1;
9522}
9523
9524
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009525static union node *simplecmd(union node **rpp, union node *redir)
9526{
Eric Andersencb57d552001-06-28 07:25:16 +00009527 union node *args, **app;
9528 union node *n = NULL;
9529 union node *vars, **vpp;
Eric Andersena3483db2001-10-24 08:01:06 +00009530 union node **orig_rpp;
Eric Andersencb57d552001-06-28 07:25:16 +00009531
9532 args = NULL;
9533 app = &args;
9534 vars = NULL;
9535 vpp = &vars;
Eric Andersena3483db2001-10-24 08:01:06 +00009536
9537 /* If we don't have any redirections already, then we must reset
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009538 rpp to be the address of the local redir variable. */
Eric Andersena3483db2001-10-24 08:01:06 +00009539 if (redir == 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009540 rpp = &redir;
Eric Andersena3483db2001-10-24 08:01:06 +00009541 /* We save the incoming value, because we need this for shell
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009542 functions. There can not be a redirect or an argument between
9543 the function name and the open parenthesis. */
Eric Andersena3483db2001-10-24 08:01:06 +00009544 orig_rpp = rpp;
Eric Andersencb57d552001-06-28 07:25:16 +00009545
9546 checkalias = 2;
9547 for (;;) {
9548 switch (readtoken()) {
9549 case TWORD:
9550 case TASSIGN:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009551 n = (union node *) stalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009552 n->type = NARG;
9553 n->narg.text = wordtext;
9554 n->narg.backquote = backquotelist;
9555 if (lasttoken == TWORD) {
9556 *app = n;
9557 app = &n->narg.next;
9558 } else {
9559 *vpp = n;
9560 vpp = &n->narg.next;
9561 }
9562 break;
9563 case TREDIR:
9564 *rpp = n = redirnode;
9565 rpp = &n->nfile.next;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009566 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +00009567 break;
9568 case TLP:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009569 if (args && app == &args->narg.next && !vars && rpp == orig_rpp) {
Eric Andersencb57d552001-06-28 07:25:16 +00009570 /* We have a function */
9571 if (readtoken() != TRP)
9572 synexpect(TRP);
Eric Andersencb57d552001-06-28 07:25:16 +00009573 n->type = NDEFUN;
9574 checkkwd = 2;
9575 n->narg.next = command();
9576 return n;
9577 }
9578 /* fall through */
9579 default:
9580 tokpushback++;
9581 goto out;
9582 }
9583 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009584 out:
Eric Andersencb57d552001-06-28 07:25:16 +00009585 *app = NULL;
9586 *vpp = NULL;
9587 *rpp = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009588 n = (union node *) stalloc(sizeof(struct ncmd));
Eric Andersencb57d552001-06-28 07:25:16 +00009589 n->type = NCMD;
9590 n->ncmd.backgnd = 0;
9591 n->ncmd.args = args;
9592 n->ncmd.assign = vars;
9593 n->ncmd.redirect = redir;
9594 return n;
9595}
9596
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009597static union node *makename(void)
9598{
Eric Andersencb57d552001-06-28 07:25:16 +00009599 union node *n;
9600
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009601 n = (union node *) stalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009602 n->type = NARG;
9603 n->narg.next = NULL;
9604 n->narg.text = wordtext;
9605 n->narg.backquote = backquotelist;
9606 return n;
9607}
9608
9609static void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +00009610{
Eric Andersencb57d552001-06-28 07:25:16 +00009611 TRACE(("Fix redir %s %d\n", text, err));
9612 if (!err)
9613 n->ndup.vname = NULL;
9614
9615 if (is_digit(text[0]) && text[1] == '\0')
9616 n->ndup.dupfd = digit_val(text[0]);
9617 else if (text[0] == '-' && text[1] == '\0')
9618 n->ndup.dupfd = -1;
9619 else {
9620
9621 if (err)
9622 synerror("Bad fd number");
9623 else
9624 n->ndup.vname = makename();
9625 }
9626}
9627
9628
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009629static void parsefname(void)
9630{
Eric Andersencb57d552001-06-28 07:25:16 +00009631 union node *n = redirnode;
9632
9633 if (readtoken() != TWORD)
9634 synexpect(-1);
9635 if (n->type == NHERE) {
9636 struct heredoc *here = heredoc;
9637 struct heredoc *p;
9638 int i;
9639
9640 if (quoteflag == 0)
9641 n->type = NXHERE;
9642 TRACE(("Here document %d\n", n->type));
9643 if (here->striptabs) {
9644 while (*wordtext == '\t')
9645 wordtext++;
9646 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009647 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0
9648 || i > EOFMARKLEN)
Eric Andersencb57d552001-06-28 07:25:16 +00009649 synerror("Illegal eof marker for << redirection");
9650 rmescapes(wordtext);
9651 here->eofmark = wordtext;
9652 here->next = NULL;
9653 if (heredoclist == NULL)
9654 heredoclist = here;
9655 else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009656 for (p = heredoclist; p->next; p = p->next);
Eric Andersencb57d552001-06-28 07:25:16 +00009657 p->next = here;
9658 }
9659 } else if (n->type == NTOFD || n->type == NFROMFD) {
9660 fixredir(n, wordtext, 0);
9661 } else {
9662 n->nfile.fname = makename();
9663 }
9664}
9665
9666
9667/*
9668 * Input any here documents.
9669 */
9670
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009671static void parseheredoc()
9672{
Eric Andersencb57d552001-06-28 07:25:16 +00009673 struct heredoc *here;
9674 union node *n;
9675
9676 while (heredoclist) {
9677 here = heredoclist;
9678 heredoclist = here->next;
9679 if (needprompt) {
9680 setprompt(2);
9681 needprompt = 0;
9682 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009683 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
9684 here->eofmark, here->striptabs);
9685 n = (union node *) stalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009686 n->narg.type = NARG;
9687 n->narg.next = NULL;
9688 n->narg.text = wordtext;
9689 n->narg.backquote = backquotelist;
9690 here->here->nhere.doc = n;
9691 }
9692}
9693
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009694static char peektoken()
9695{
Eric Andersencb57d552001-06-28 07:25:16 +00009696 int t;
9697
9698 t = readtoken();
9699 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009700 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +00009701}
9702
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009703static int readtoken()
9704{
Eric Andersencb57d552001-06-28 07:25:16 +00009705 int t;
Eric Andersen7467c8d2001-07-12 20:26:32 +00009706
Eric Andersencb57d552001-06-28 07:25:16 +00009707 int savecheckalias = checkalias;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009708
Eric Andersen8e139872002-07-04 00:19:46 +00009709#ifdef CONFIG_ASH_ALIAS
Eric Andersen7467c8d2001-07-12 20:26:32 +00009710 int savecheckkwd = checkkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009711 struct alias *ap;
Eric Andersen2870d962001-07-02 17:27:21 +00009712#endif
9713
Eric Andersencb57d552001-06-28 07:25:16 +00009714#ifdef DEBUG
9715 int alreadyseen = tokpushback;
9716#endif
9717
Eric Andersend35c5df2002-01-09 15:37:36 +00009718#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009719 top:
Eric Andersen2870d962001-07-02 17:27:21 +00009720#endif
9721
Eric Andersencb57d552001-06-28 07:25:16 +00009722 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +00009723
Eric Andersencb57d552001-06-28 07:25:16 +00009724 checkalias = savecheckalias;
9725
9726 if (checkkwd) {
9727 /*
9728 * eat newlines
9729 */
9730 if (checkkwd == 2) {
9731 checkkwd = 0;
9732 while (t == TNL) {
9733 parseheredoc();
9734 t = xxreadtoken();
9735 }
9736 }
9737 checkkwd = 0;
9738 /*
9739 * check for keywords
9740 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009741 if (t == TWORD && !quoteflag) {
Eric Andersencb57d552001-06-28 07:25:16 +00009742 const char *const *pp;
9743
9744 if ((pp = findkwd(wordtext))) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009745 lasttoken = t = pp - tokname_array;
9746 TRACE(("keyword %s recognized\n", tokname(t)));
Eric Andersencb57d552001-06-28 07:25:16 +00009747 goto out;
9748 }
9749 }
9750 }
9751
Eric Andersen7467c8d2001-07-12 20:26:32 +00009752
Eric Andersencb57d552001-06-28 07:25:16 +00009753 if (t != TWORD) {
9754 if (t != TREDIR) {
9755 checkalias = 0;
9756 }
9757 } else if (checkalias == 2 && isassignment(wordtext)) {
9758 lasttoken = t = TASSIGN;
9759 } else if (checkalias) {
Eric Andersen8e139872002-07-04 00:19:46 +00009760#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009761 if (!quoteflag && (ap = *__lookupalias(wordtext)) != NULL
9762 && !(ap->flag & ALIASINUSE)) {
Eric Andersencb57d552001-06-28 07:25:16 +00009763 if (*ap->val) {
9764 pushstring(ap->val, strlen(ap->val), ap);
9765 }
9766 checkkwd = savecheckkwd;
9767 goto top;
9768 }
Eric Andersen2870d962001-07-02 17:27:21 +00009769#endif
Eric Andersen8e139872002-07-04 00:19:46 +00009770 checkalias = 0;
Eric Andersen7467c8d2001-07-12 20:26:32 +00009771 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009772 out:
Eric Andersencb57d552001-06-28 07:25:16 +00009773#ifdef DEBUG
9774 if (!alreadyseen)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009775 TRACE(("token %s %s\n", tokname(t), t == TWORD
9776 || t == TASSIGN ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009777 else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009778 TRACE(("reread token %s %s\n", tokname(t), t == TWORD
9779 || t == TASSIGN ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009780#endif
9781 return (t);
9782}
9783
9784
9785/*
9786 * Read the next input token.
9787 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +00009788 * backquotes. We set quoteflag to true if any part of the word was
9789 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +00009790 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +00009791 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +00009792 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +00009793 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +00009794 *
9795 * [Change comment: here documents and internal procedures]
9796 * [Readtoken shouldn't have any arguments. Perhaps we should make the
9797 * word parsing code into a separate routine. In this case, readtoken
9798 * doesn't need to have any internal procedures, but parseword does.
9799 * We could also make parseoperator in essence the main routine, and
9800 * have parseword (readtoken1?) handle both words and redirection.]
9801 */
9802
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009803#define NEW_xxreadtoken
9804#ifdef NEW_xxreadtoken
9805
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009806static const char xxreadtoken_chars[] = "\n()&|;"; /* singles must be first! */
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009807static const char xxreadtoken_tokens[] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009808 TNL, TLP, TRP, /* only single occurrence allowed */
9809 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
9810 TEOF, /* corresponds to trailing nul */
9811 TAND, TOR, TENDCASE, /* if double occurrence */
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009812};
9813
9814#define xxreadtoken_doubles \
9815 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
9816#define xxreadtoken_singles \
9817 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
9818
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009819static int xxreadtoken()
9820{
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009821 int c;
9822
9823 if (tokpushback) {
9824 tokpushback = 0;
9825 return lasttoken;
9826 }
9827 if (needprompt) {
9828 setprompt(2);
9829 needprompt = 0;
9830 }
9831 startlinno = plinno;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009832 for (;;) { /* until token or start of word found */
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009833 c = pgetc_macro();
9834
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009835 if ((c != ' ') && (c != '\t')
Eric Andersend35c5df2002-01-09 15:37:36 +00009836#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009837 && (c != PEOA)
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009838#endif
9839 ) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009840 if (c == '#') {
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009841 while ((c = pgetc()) != '\n' && c != PEOF);
9842 pungetc();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009843 } else if (c == '\\') {
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009844 if (pgetc() != '\n') {
9845 pungetc();
9846 goto READTOKEN1;
9847 }
9848 startlinno = ++plinno;
9849 setprompt(doprompt ? 2 : 0);
9850 } else {
9851 const char *p
9852 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
9853
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009854 if (c != PEOF) {
9855 if (c == '\n') {
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009856 plinno++;
9857 needprompt = doprompt;
9858 }
9859
9860 p = strchr(xxreadtoken_chars, c);
9861 if (p == NULL) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009862 READTOKEN1:
9863 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009864 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009865
9866 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
9867 if (pgetc() == *p) { /* double occurrence? */
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009868 p += xxreadtoken_doubles + 1;
9869 } else {
9870 pungetc();
9871 }
9872 }
9873 }
9874
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009875 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009876 }
9877 }
9878 }
9879}
9880
9881
9882#else
Eric Andersen2870d962001-07-02 17:27:21 +00009883#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +00009884
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009885static int xxreadtoken()
9886{
Eric Andersencb57d552001-06-28 07:25:16 +00009887 int c;
9888
9889 if (tokpushback) {
9890 tokpushback = 0;
9891 return lasttoken;
9892 }
9893 if (needprompt) {
9894 setprompt(2);
9895 needprompt = 0;
9896 }
9897 startlinno = plinno;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009898 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +00009899 c = pgetc_macro();
9900 switch (c) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009901 case ' ':
9902 case '\t':
Eric Andersend35c5df2002-01-09 15:37:36 +00009903#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00009904 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +00009905#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009906 continue;
9907 case '#':
9908 while ((c = pgetc()) != '\n' && c != PEOF);
9909 pungetc();
9910 continue;
9911 case '\\':
9912 if (pgetc() == '\n') {
9913 startlinno = ++plinno;
9914 if (doprompt)
9915 setprompt(2);
9916 else
9917 setprompt(0);
9918 continue;
9919 }
9920 pungetc();
9921 goto breakloop;
9922 case '\n':
9923 plinno++;
9924 needprompt = doprompt;
9925 RETURN(TNL);
9926 case PEOF:
9927 RETURN(TEOF);
9928 case '&':
9929 if (pgetc() == '&')
9930 RETURN(TAND);
9931 pungetc();
9932 RETURN(TBACKGND);
9933 case '|':
9934 if (pgetc() == '|')
9935 RETURN(TOR);
9936 pungetc();
9937 RETURN(TPIPE);
9938 case ';':
9939 if (pgetc() == ';')
9940 RETURN(TENDCASE);
9941 pungetc();
9942 RETURN(TSEMI);
9943 case '(':
9944 RETURN(TLP);
9945 case ')':
9946 RETURN(TRP);
9947 default:
9948 goto breakloop;
9949 }
9950 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009951 breakloop:
9952 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009953#undef RETURN
9954}
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009955#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009956
Eric Andersencb57d552001-06-28 07:25:16 +00009957/*
9958 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
9959 * is not NULL, read a here document. In the latter case, eofmark is the
9960 * word which marks the end of the document and striptabs is true if
9961 * leading tabs should be stripped from the document. The argument firstc
9962 * is the first character of the input token or document.
9963 *
9964 * Because C does not have internal subroutines, I have simulated them
9965 * using goto's to implement the subroutine linkage. The following macros
9966 * will run code that appears at the end of readtoken1.
9967 */
9968
Eric Andersen2870d962001-07-02 17:27:21 +00009969#define CHECKEND() {goto checkend; checkend_return:;}
9970#define PARSEREDIR() {goto parseredir; parseredir_return:;}
9971#define PARSESUB() {goto parsesub; parsesub_return:;}
9972#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
9973#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
9974#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +00009975
9976static int
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009977readtoken1(int firstc, int syntax, const char *eofmark, int striptabs)
9978{
Eric Andersencb57d552001-06-28 07:25:16 +00009979 int c = firstc;
9980 char *out;
9981 int len;
9982 char line[EOFMARKLEN + 1];
9983 struct nodelist *bqlist;
9984 int quotef;
9985 int dblquote;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009986 int varnest; /* levels of variables expansion */
9987 int arinest; /* levels of arithmetic expansion */
9988 int parenlevel; /* levels of parens in arithmetic */
9989 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00009990 int oldstyle;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009991 int prevsyntax; /* syntax before arithmetic */
9992
Eric Andersencb57d552001-06-28 07:25:16 +00009993#if __GNUC__
9994 /* Avoid longjmp clobbering */
9995 (void) &out;
9996 (void) &quotef;
9997 (void) &dblquote;
9998 (void) &varnest;
9999 (void) &arinest;
10000 (void) &parenlevel;
10001 (void) &dqvarnest;
10002 (void) &oldstyle;
10003 (void) &prevsyntax;
10004 (void) &syntax;
10005#endif
10006
10007 startlinno = plinno;
10008 dblquote = 0;
10009 if (syntax == DQSYNTAX)
10010 dblquote = 1;
10011 quotef = 0;
10012 bqlist = NULL;
10013 varnest = 0;
10014 arinest = 0;
10015 parenlevel = 0;
10016 dqvarnest = 0;
10017
10018 STARTSTACKSTR(out);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010019 loop:{ /* for each line, until end of word */
10020 CHECKEND(); /* set c to PEOF if at end of here document */
10021 for (;;) { /* until end of line or end of word */
10022 CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
10023 switch (SIT(c, syntax)) {
10024 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010025 if (syntax == BASESYNTAX)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010026 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010027 USTPUTC(c, out);
10028 plinno++;
10029 if (doprompt)
10030 setprompt(2);
10031 else
10032 setprompt(0);
10033 c = pgetc();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010034 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010035 case CWORD:
10036 USTPUTC(c, out);
10037 break;
10038 case CCTL:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010039 if ((eofmark == NULL || dblquote) && dqvarnest == 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010040 USTPUTC(CTLESC, out);
10041 USTPUTC(c, out);
10042 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010043 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010044 c = pgetc2();
10045 if (c == PEOF) {
10046 USTPUTC('\\', out);
10047 pungetc();
10048 } else if (c == '\n') {
10049 if (doprompt)
10050 setprompt(2);
10051 else
10052 setprompt(0);
10053 } else {
10054 if (dblquote && c != '\\' && c != '`' && c != '$'
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010055 && (c != '"' || eofmark != NULL))
Eric Andersencb57d552001-06-28 07:25:16 +000010056 USTPUTC('\\', out);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010057 if (SIT(c, SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010058 USTPUTC(CTLESC, out);
10059 else if (eofmark == NULL)
10060 USTPUTC(CTLQUOTEMARK, out);
10061 USTPUTC(c, out);
10062 quotef++;
10063 }
10064 break;
10065 case CSQUOTE:
10066 if (eofmark == NULL)
10067 USTPUTC(CTLQUOTEMARK, out);
10068 syntax = SQSYNTAX;
10069 break;
10070 case CDQUOTE:
10071 if (eofmark == NULL)
10072 USTPUTC(CTLQUOTEMARK, out);
10073 syntax = DQSYNTAX;
10074 dblquote = 1;
10075 break;
10076 case CENDQUOTE:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010077 if (eofmark != NULL && arinest == 0 && varnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010078 USTPUTC(c, out);
10079 } else {
10080 if (arinest) {
10081 syntax = ARISYNTAX;
10082 dblquote = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010083 } else if (eofmark == NULL && dqvarnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010084 syntax = BASESYNTAX;
10085 dblquote = 0;
10086 }
10087 quotef++;
10088 }
10089 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010090 case CVAR: /* '$' */
10091 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010092 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010093 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010094 if (varnest > 0) {
10095 varnest--;
10096 if (dqvarnest > 0) {
10097 dqvarnest--;
10098 }
10099 USTPUTC(CTLENDVAR, out);
10100 } else {
10101 USTPUTC(c, out);
10102 }
10103 break;
Eric Andersend35c5df2002-01-09 15:37:36 +000010104#ifdef CONFIG_ASH_MATH_SUPPORT
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010105 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010106 parenlevel++;
10107 USTPUTC(c, out);
10108 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010109 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010110 if (parenlevel > 0) {
10111 USTPUTC(c, out);
10112 --parenlevel;
10113 } else {
10114 if (pgetc() == ')') {
10115 if (--arinest == 0) {
10116 USTPUTC(CTLENDARI, out);
10117 syntax = prevsyntax;
10118 if (syntax == DQSYNTAX)
10119 dblquote = 1;
10120 else
10121 dblquote = 0;
10122 } else
10123 USTPUTC(')', out);
10124 } else {
10125 /*
10126 * unbalanced parens
10127 * (don't 2nd guess - no error)
10128 */
10129 pungetc();
10130 USTPUTC(')', out);
10131 }
10132 }
10133 break;
10134#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010135 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010136 PARSEBACKQOLD();
10137 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010138 case CENDFILE:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010139 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010140 case CIGN:
10141 break;
10142 default:
10143 if (varnest == 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010144 goto endword; /* exit outer loop */
Eric Andersend35c5df2002-01-09 15:37:36 +000010145#ifdef CONFIG_ASH_ALIAS
Eric Andersen3102ac42001-07-06 04:26:23 +000010146 if (c != PEOA)
10147#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010148 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010149
Eric Andersencb57d552001-06-28 07:25:16 +000010150 }
10151 c = pgetc_macro();
10152 }
10153 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010154 endword:
Eric Andersencb57d552001-06-28 07:25:16 +000010155 if (syntax == ARISYNTAX)
10156 synerror("Missing '))'");
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010157 if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010158 synerror("Unterminated quoted string");
10159 if (varnest != 0) {
10160 startlinno = plinno;
10161 synerror("Missing '}'");
10162 }
10163 USTPUTC('\0', out);
10164 len = out - stackblock();
10165 out = stackblock();
10166 if (eofmark == NULL) {
10167 if ((c == '>' || c == '<')
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010168 && quotef == 0 && len <= 2 && (*out == '\0' || is_digit(*out))) {
Eric Andersencb57d552001-06-28 07:25:16 +000010169 PARSEREDIR();
10170 return lasttoken = TREDIR;
10171 } else {
10172 pungetc();
10173 }
10174 }
10175 quoteflag = quotef;
10176 backquotelist = bqlist;
10177 grabstackblock(len);
10178 wordtext = out;
10179 return lasttoken = TWORD;
10180/* end of readtoken routine */
10181
10182
10183
10184/*
10185 * Check to see whether we are at the end of the here document. When this
10186 * is called, c is set to the first character of the next input line. If
10187 * we are at the end of the here document, this routine sets the c to PEOF.
10188 */
10189
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010190 checkend:{
10191 if (eofmark) {
Eric Andersend35c5df2002-01-09 15:37:36 +000010192#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010193 if (c == PEOA) {
Eric Andersencb57d552001-06-28 07:25:16 +000010194 c = pgetc2();
10195 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010196#endif
10197 if (striptabs) {
10198 while (c == '\t') {
10199 c = pgetc2();
10200 }
10201 }
10202 if (c == *eofmark) {
10203 if (pfgets(line, sizeof line) != NULL) {
10204 const char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010205
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010206 p = line;
10207 for (q = eofmark + 1; *q && *p == *q; p++, q++);
10208 if (*p == '\n' && *q == '\0') {
10209 c = PEOF;
10210 plinno++;
10211 needprompt = doprompt;
10212 } else {
10213 pushstring(line, strlen(line), NULL);
10214 }
Eric Andersencb57d552001-06-28 07:25:16 +000010215 }
10216 }
10217 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010218 goto checkend_return;
Eric Andersencb57d552001-06-28 07:25:16 +000010219 }
Eric Andersencb57d552001-06-28 07:25:16 +000010220
10221
10222/*
10223 * Parse a redirection operator. The variable "out" points to a string
10224 * specifying the fd to be redirected. The variable "c" contains the
10225 * first character of the redirection operator.
10226 */
10227
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010228 parseredir:{
10229 char fd = *out;
10230 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000010231
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010232 np = (union node *) stalloc(sizeof(struct nfile));
10233 if (c == '>') {
10234 np->nfile.fd = 1;
10235 c = pgetc();
10236 if (c == '>')
10237 np->type = NAPPEND;
10238 else if (c == '&')
10239 np->type = NTOFD;
10240 else if (c == '|')
10241 np->type = NTOOV;
10242 else {
10243 np->type = NTO;
Eric Andersencb57d552001-06-28 07:25:16 +000010244 pungetc();
10245 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010246 } else { /* c == '<' */
10247 np->nfile.fd = 0;
10248 switch (c = pgetc()) {
10249 case '<':
10250 if (sizeof(struct nfile) != sizeof(struct nhere)) {
10251 np = (union node *) stalloc(sizeof(struct nhere));
10252 np->nfile.fd = 0;
10253 }
10254 np->type = NHERE;
10255 heredoc = (struct heredoc *) stalloc(sizeof(struct heredoc));
10256 heredoc->here = np;
10257 if ((c = pgetc()) == '-') {
10258 heredoc->striptabs = 1;
10259 } else {
10260 heredoc->striptabs = 0;
10261 pungetc();
10262 }
10263 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010264
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010265 case '&':
10266 np->type = NFROMFD;
10267 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010268
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010269 case '>':
10270 np->type = NFROMTO;
10271 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010272
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010273 default:
10274 np->type = NFROM;
10275 pungetc();
10276 break;
10277 }
Eric Andersencb57d552001-06-28 07:25:16 +000010278 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010279 if (fd != '\0')
10280 np->nfile.fd = digit_val(fd);
10281 redirnode = np;
10282 goto parseredir_return;
Eric Andersencb57d552001-06-28 07:25:16 +000010283 }
Eric Andersencb57d552001-06-28 07:25:16 +000010284
10285
10286/*
10287 * Parse a substitution. At this point, we have read the dollar sign
10288 * and nothing else.
10289 */
10290
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010291 parsesub:{
10292 int subtype;
10293 int typeloc;
10294 int flags;
10295 char *p;
10296 static const char types[] = "}-+?=";
Eric Andersencb57d552001-06-28 07:25:16 +000010297
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010298 c = pgetc();
10299 if (c <= PEOA ||
10300 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10301 ) {
10302 USTPUTC('$', out);
Eric Andersencb57d552001-06-28 07:25:16 +000010303 pungetc();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010304 } else if (c == '(') { /* $(command) or $((arith)) */
10305 if (pgetc() == '(') {
10306 PARSEARITH();
10307 } else {
10308 pungetc();
10309 PARSEBACKQNEW();
Eric Andersencb57d552001-06-28 07:25:16 +000010310 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010311 } else {
10312 USTPUTC(CTLVAR, out);
10313 typeloc = out - stackblock();
10314 USTPUTC(VSNORMAL, out);
10315 subtype = VSNORMAL;
10316 if (c == '{') {
Eric Andersencb57d552001-06-28 07:25:16 +000010317 c = pgetc();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010318 if (c == '#') {
10319 if ((c = pgetc()) == '}')
10320 c = '#';
10321 else
10322 subtype = VSLENGTH;
10323 } else
10324 subtype = 0;
10325 }
10326 if (c > PEOA && is_name(c)) {
10327 do {
10328 STPUTC(c, out);
10329 c = pgetc();
10330 } while (c > PEOA && is_in_name(c));
10331 } else if (is_digit(c)) {
10332 do {
10333 USTPUTC(c, out);
10334 c = pgetc();
10335 } while (is_digit(c));
10336 } else if (is_special(c)) {
Eric Andersencb57d552001-06-28 07:25:16 +000010337 USTPUTC(c, out);
10338 c = pgetc();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010339 } else
10340 badsub:synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010341
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010342 STPUTC('=', out);
10343 flags = 0;
10344 if (subtype == 0) {
10345 switch (c) {
10346 case ':':
10347 flags = VSNUL;
10348 c = pgetc();
10349 /*FALLTHROUGH*/ default:
10350 p = strchr(types, c);
10351 if (p == NULL)
10352 goto badsub;
10353 subtype = p - types + VSNORMAL;
10354 break;
10355 case '%':
10356 case '#':
Eric Andersencb57d552001-06-28 07:25:16 +000010357 {
10358 int cc = c;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010359
10360 subtype = c == '#' ? VSTRIMLEFT : VSTRIMRIGHT;
Eric Andersencb57d552001-06-28 07:25:16 +000010361 c = pgetc();
10362 if (c == cc)
10363 subtype++;
10364 else
10365 pungetc();
10366 break;
10367 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010368 }
10369 } else {
10370 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010371 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010372 if (dblquote || arinest)
10373 flags |= VSQUOTE;
10374 *(stackblock() + typeloc) = subtype | flags;
10375 if (subtype != VSNORMAL) {
10376 varnest++;
10377 if (dblquote) {
10378 dqvarnest++;
10379 }
Eric Andersencb57d552001-06-28 07:25:16 +000010380 }
10381 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010382 goto parsesub_return;
Eric Andersencb57d552001-06-28 07:25:16 +000010383 }
Eric Andersencb57d552001-06-28 07:25:16 +000010384
10385
10386/*
10387 * Called to parse command substitutions. Newstyle is set if the command
10388 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10389 * list of commands (passed by reference), and savelen is the number of
10390 * characters on the top of the stack which must be preserved.
10391 */
10392
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010393 parsebackq:{
10394 struct nodelist **nlpp;
10395 int savepbq;
10396 union node *n;
10397 char *volatile str;
10398 struct jmploc jmploc;
10399 struct jmploc *volatile savehandler;
10400 int savelen;
10401 int saveprompt;
10402
Eric Andersencb57d552001-06-28 07:25:16 +000010403#ifdef __GNUC__
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010404 (void) &saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010405#endif
10406
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010407 savepbq = parsebackquote;
10408 if (setjmp(jmploc.loc)) {
10409 free(str);
10410 parsebackquote = 0;
10411 handler = savehandler;
10412 longjmp(handler->loc, 1);
10413 }
10414 INTOFF;
10415 str = NULL;
10416 savelen = out - stackblock();
10417 if (savelen > 0) {
10418 str = xmalloc(savelen);
10419 memcpy(str, stackblock(), savelen);
10420 }
10421 savehandler = handler;
10422 handler = &jmploc;
10423 INTON;
10424 if (oldstyle) {
10425 /* We must read until the closing backquote, giving special
10426 treatment to some slashes, and then push the string and
10427 reread it as input, interpreting it normally. */
10428 char *pout;
10429 int pc;
10430 int psavelen;
10431 char *pstr;
Eric Andersencb57d552001-06-28 07:25:16 +000010432
10433
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010434 STARTSTACKSTR(pout);
10435 for (;;) {
10436 if (needprompt) {
10437 setprompt(2);
10438 needprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010439 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010440 switch (pc = pgetc()) {
10441 case '`':
10442 goto done;
10443
10444 case '\\':
10445 if ((pc = pgetc()) == '\n') {
10446 plinno++;
10447 if (doprompt)
10448 setprompt(2);
10449 else
10450 setprompt(0);
10451 /*
10452 * If eating a newline, avoid putting
10453 * the newline into the new character
10454 * stream (via the STPUTC after the
10455 * switch).
10456 */
10457 continue;
10458 }
10459 if (pc != '\\' && pc != '`' && pc != '$'
10460 && (!dblquote || pc != '"'))
10461 STPUTC('\\', pout);
10462 if (pc > PEOA) {
10463 break;
10464 }
10465 /* fall through */
10466
10467 case PEOF:
10468#ifdef CONFIG_ASH_ALIAS
10469 case PEOA:
10470#endif
10471 startlinno = plinno;
10472 synerror("EOF in backquote substitution");
10473
10474 case '\n':
10475 plinno++;
10476 needprompt = doprompt;
10477 break;
10478
10479 default:
Eric Andersencb57d552001-06-28 07:25:16 +000010480 break;
10481 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010482 STPUTC(pc, pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010483 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010484 done:
10485 STPUTC('\0', pout);
10486 psavelen = pout - stackblock();
10487 if (psavelen > 0) {
10488 pstr = grabstackstr(pout);
10489 setinputstring(pstr);
10490 }
Eric Andersen2870d962001-07-02 17:27:21 +000010491 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010492 nlpp = &bqlist;
10493 while (*nlpp)
10494 nlpp = &(*nlpp)->next;
10495 *nlpp = (struct nodelist *) stalloc(sizeof(struct nodelist));
10496 (*nlpp)->next = NULL;
10497 parsebackquote = oldstyle;
10498
10499 if (oldstyle) {
10500 saveprompt = doprompt;
10501 doprompt = 0;
Eric Andersen2870d962001-07-02 17:27:21 +000010502 }
Eric Andersencb57d552001-06-28 07:25:16 +000010503
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010504 n = list(0);
Eric Andersencb57d552001-06-28 07:25:16 +000010505
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010506 if (oldstyle)
10507 doprompt = saveprompt;
10508 else {
10509 if (readtoken() != TRP)
10510 synexpect(TRP);
10511 }
Eric Andersencb57d552001-06-28 07:25:16 +000010512
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010513 (*nlpp)->n = n;
10514 if (oldstyle) {
10515 /*
10516 * Start reading from old file again, ignoring any pushed back
10517 * tokens left from the backquote parsing
10518 */
10519 popfile();
10520 tokpushback = 0;
10521 }
10522 while (stackblocksize() <= savelen)
10523 growstackblock();
10524 STARTSTACKSTR(out);
10525 if (str) {
10526 memcpy(out, str, savelen);
10527 STADJUST(savelen, out);
10528 INTOFF;
10529 free(str);
10530 str = NULL;
10531 INTON;
10532 }
10533 parsebackquote = savepbq;
10534 handler = savehandler;
10535 if (arinest || dblquote)
10536 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10537 else
10538 USTPUTC(CTLBACKQ, out);
10539 if (oldstyle)
10540 goto parsebackq_oldreturn;
10541 else
10542 goto parsebackq_newreturn;
Eric Andersencb57d552001-06-28 07:25:16 +000010543 }
10544
Eric Andersencb57d552001-06-28 07:25:16 +000010545/*
10546 * Parse an arithmetic expansion (indicate start of one and set state)
10547 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010548 parsearith:{
Eric Andersencb57d552001-06-28 07:25:16 +000010549
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010550 if (++arinest == 1) {
10551 prevsyntax = syntax;
10552 syntax = ARISYNTAX;
10553 USTPUTC(CTLARI, out);
10554 if (dblquote)
10555 USTPUTC('"', out);
10556 else
10557 USTPUTC(' ', out);
10558 } else {
10559 /*
10560 * we collapse embedded arithmetic expansion to
10561 * parenthesis, which should be equivalent
10562 */
10563 USTPUTC('(', out);
10564 }
10565 goto parsearith_return;
Eric Andersencb57d552001-06-28 07:25:16 +000010566 }
Eric Andersencb57d552001-06-28 07:25:16 +000010567
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010568} /* end of readtoken */
Eric Andersencb57d552001-06-28 07:25:16 +000010569
10570
Eric Andersencb57d552001-06-28 07:25:16 +000010571/*
10572 * Returns true if the text contains nothing to expand (no dollar signs
10573 * or backquotes).
10574 */
10575
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010576static int noexpand(char *text)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010577{
Eric Andersencb57d552001-06-28 07:25:16 +000010578 char *p;
10579 char c;
10580
10581 p = text;
10582 while ((c = *p++) != '\0') {
10583 if (c == CTLQUOTEMARK)
10584 continue;
10585 if (c == CTLESC)
10586 p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010587 else if (SIT(c, BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010588 return 0;
10589 }
10590 return 1;
10591}
10592
10593
10594/*
10595 * Return true if the argument is a legal variable name (a letter or
10596 * underscore followed by zero or more letters, underscores, and digits).
10597 */
10598
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010599static int goodname(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +000010600{
10601 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000010602
10603 p = name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010604 if (!is_name(*p))
Eric Andersencb57d552001-06-28 07:25:16 +000010605 return 0;
10606 while (*++p) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010607 if (!is_in_name(*p))
Eric Andersencb57d552001-06-28 07:25:16 +000010608 return 0;
10609 }
10610 return 1;
10611}
10612
10613
10614/*
10615 * Called when an unexpected token is read during the parse. The argument
10616 * is the token that is expected, or -1 if more than one type of token can
10617 * occur at this point.
10618 */
10619
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010620static void synexpect(int token)
Eric Andersencb57d552001-06-28 07:25:16 +000010621{
10622 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010623 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000010624
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010625 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10626 if (token >= 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010627 sprintf(msg + l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000010628 synerror(msg);
10629 /* NOTREACHED */
10630}
10631
10632
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010633static void synerror(const char *msg)
Eric Andersen2870d962001-07-02 17:27:21 +000010634{
Eric Andersencb57d552001-06-28 07:25:16 +000010635 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +000010636 out2fmt("%s: %d: ", commandname, startlinno);
10637 out2fmt("Syntax error: %s\n", msg);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010638 error((char *) NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000010639 /* NOTREACHED */
10640}
10641
Eric Andersencb57d552001-06-28 07:25:16 +000010642
10643/*
10644 * called by editline -- any expansions to the prompt
10645 * should be added here.
10646 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010647static void setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000010648{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010649 char *prompt;
10650
10651 switch (whichprompt) {
Eric Andersen62483552001-07-10 06:09:16 +000010652 case 1:
10653 prompt = ps1val();
10654 break;
10655 case 2:
10656 prompt = ps2val();
10657 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010658 default: /* 0 */
Eric Andersen62483552001-07-10 06:09:16 +000010659 prompt = "";
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010660 }
10661 putprompt(prompt);
Eric Andersencb57d552001-06-28 07:25:16 +000010662}
10663
Eric Andersencb57d552001-06-28 07:25:16 +000010664
Eric Andersencb57d552001-06-28 07:25:16 +000010665/*
10666 * Code for dealing with input/output redirection.
10667 */
10668
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010669#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000010670#ifndef PIPE_BUF
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010671# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000010672#else
10673# define PIPESIZE PIPE_BUF
10674#endif
10675
10676
Eric Andersen62483552001-07-10 06:09:16 +000010677/*
10678 * Open a file in noclobber mode.
10679 * The code was copied from bash.
10680 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010681static inline int noclobberopen(const char *fname)
Eric Andersen62483552001-07-10 06:09:16 +000010682{
10683 int r, fd;
10684 struct stat finfo, finfo2;
10685
10686 /*
10687 * If the file exists and is a regular file, return an error
10688 * immediately.
10689 */
10690 r = stat(fname, &finfo);
10691 if (r == 0 && S_ISREG(finfo.st_mode)) {
10692 errno = EEXIST;
10693 return -1;
10694 }
10695
10696 /*
10697 * If the file was not present (r != 0), make sure we open it
10698 * exclusively so that if it is created before we open it, our open
10699 * will fail. Make sure that we do not truncate an existing file.
10700 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10701 * file was not a regular file, we leave O_EXCL off.
10702 */
10703 if (r != 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010704 return open(fname, O_WRONLY | O_CREAT | O_EXCL, 0666);
10705 fd = open(fname, O_WRONLY | O_CREAT, 0666);
Eric Andersen62483552001-07-10 06:09:16 +000010706
10707 /* If the open failed, return the file descriptor right away. */
10708 if (fd < 0)
10709 return fd;
10710
10711 /*
10712 * OK, the open succeeded, but the file may have been changed from a
10713 * non-regular file to a regular file between the stat and the open.
10714 * We are assuming that the O_EXCL open handles the case where FILENAME
10715 * did not exist and is symlinked to an existing file between the stat
10716 * and open.
10717 */
10718
10719 /*
10720 * If we can open it and fstat the file descriptor, and neither check
10721 * revealed that it was a regular file, and the file has not been
10722 * replaced, return the file descriptor.
10723 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010724 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10725 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
Eric Andersen62483552001-07-10 06:09:16 +000010726 return fd;
10727
10728 /* The file has been replaced. badness. */
10729 close(fd);
10730 errno = EEXIST;
10731 return -1;
10732}
Eric Andersencb57d552001-06-28 07:25:16 +000010733
10734/*
Eric Andersen62483552001-07-10 06:09:16 +000010735 * Handle here documents. Normally we fork off a process to write the
10736 * data to a pipe. If the document is short, we can stuff the data in
10737 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000010738 */
10739
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010740static inline int openhere(const union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010741{
10742 int pip[2];
10743 int len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010744
Eric Andersen62483552001-07-10 06:09:16 +000010745 if (pipe(pip) < 0)
10746 error("Pipe call failed");
10747 if (redir->type == NHERE) {
10748 len = strlen(redir->nhere.doc->narg.text);
10749 if (len <= PIPESIZE) {
10750 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10751 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010752 }
Eric Andersencb57d552001-06-28 07:25:16 +000010753 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010754 if (forkshell((struct job *) NULL, (union node *) NULL, FORK_NOJOB) == 0) {
Eric Andersen62483552001-07-10 06:09:16 +000010755 close(pip[0]);
10756 signal(SIGINT, SIG_IGN);
10757 signal(SIGQUIT, SIG_IGN);
10758 signal(SIGHUP, SIG_IGN);
10759#ifdef SIGTSTP
10760 signal(SIGTSTP, SIG_IGN);
10761#endif
10762 signal(SIGPIPE, SIG_DFL);
10763 if (redir->type == NHERE)
10764 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10765 else
10766 expandhere(redir->nhere.doc, pip[1]);
10767 _exit(0);
10768 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010769 out:
Eric Andersen62483552001-07-10 06:09:16 +000010770 close(pip[1]);
10771 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000010772}
10773
10774
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010775static inline int openredirect(const union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010776{
Eric Andersencb57d552001-06-28 07:25:16 +000010777 char *fname;
10778 int f;
10779
10780 switch (redir->nfile.type) {
10781 case NFROM:
10782 fname = redir->nfile.expfname;
10783 if ((f = open(fname, O_RDONLY)) < 0)
10784 goto eopen;
10785 break;
10786 case NFROMTO:
10787 fname = redir->nfile.expfname;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010788 if ((f = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010789 goto ecreate;
10790 break;
10791 case NTO:
10792 /* Take care of noclobber mode. */
10793 if (Cflag) {
10794 fname = redir->nfile.expfname;
10795 if ((f = noclobberopen(fname)) < 0)
10796 goto ecreate;
10797 break;
10798 }
10799 case NTOOV:
10800 fname = redir->nfile.expfname;
10801#ifdef O_CREAT
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010802 if ((f = open(fname, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010803 goto ecreate;
10804#else
10805 if ((f = creat(fname, 0666)) < 0)
10806 goto ecreate;
10807#endif
10808 break;
10809 case NAPPEND:
10810 fname = redir->nfile.expfname;
10811#ifdef O_APPEND
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010812 if ((f = open(fname, O_WRONLY | O_CREAT | O_APPEND, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010813 goto ecreate;
10814#else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010815 if ((f = open(fname, O_WRONLY)) < 0 && (f = creat(fname, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010816 goto ecreate;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010817 lseek(f, (off_t) 0, 2);
Eric Andersencb57d552001-06-28 07:25:16 +000010818#endif
10819 break;
10820 default:
10821#ifdef DEBUG
10822 abort();
10823#endif
10824 /* Fall through to eliminate warning. */
10825 case NTOFD:
10826 case NFROMFD:
10827 f = -1;
10828 break;
10829 case NHERE:
10830 case NXHERE:
10831 f = openhere(redir);
10832 break;
10833 }
10834
10835 return f;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010836 ecreate:
Eric Andersencb57d552001-06-28 07:25:16 +000010837 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010838 eopen:
Eric Andersencb57d552001-06-28 07:25:16 +000010839 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
10840}
10841
10842
Eric Andersen62483552001-07-10 06:09:16 +000010843/*
10844 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
10845 * old file descriptors are stashed away so that the redirection can be
10846 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
10847 * standard output, and the standard error if it becomes a duplicate of
10848 * stdout.
10849 */
10850
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010851static void redirect(union node *redir, int flags)
Eric Andersen62483552001-07-10 06:09:16 +000010852{
10853 union node *n;
10854 struct redirtab *sv = NULL;
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010855 int i;
Eric Andersen62483552001-07-10 06:09:16 +000010856 int fd;
10857 int newfd;
10858 int try;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010859 int fd1dup = flags & REDIR_BACKQ;; /* stdout `cmd` redir to pipe */
Eric Andersen62483552001-07-10 06:09:16 +000010860
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010861 TRACE(("redirect(%s) called\n",
10862 flags & REDIR_PUSH ? "REDIR_PUSH" : "NO_REDIR_PUSH"));
Eric Andersen62483552001-07-10 06:09:16 +000010863 if (flags & REDIR_PUSH) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010864 sv = xmalloc(sizeof(struct redirtab));
10865 for (i = 0; i < 10; i++)
Eric Andersen62483552001-07-10 06:09:16 +000010866 sv->renamed[i] = EMPTY;
10867 sv->next = redirlist;
10868 redirlist = sv;
10869 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010870 for (n = redir; n; n = n->nfile.next) {
Eric Andersen62483552001-07-10 06:09:16 +000010871 fd = n->nfile.fd;
10872 try = 0;
10873 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010874 n->ndup.dupfd == fd)
10875 continue; /* redirect from/to same file descriptor */
Eric Andersen62483552001-07-10 06:09:16 +000010876
10877 INTOFF;
10878 newfd = openredirect(n);
10879 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
Eric Andersen09da6272002-10-22 22:15:33 +000010880 i = fd;
Eric Andersen62483552001-07-10 06:09:16 +000010881 if (newfd == fd) {
10882 try++;
10883 } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
10884 switch (errno) {
10885 case EBADF:
10886 if (!try) {
10887 dupredirect(n, newfd, fd1dup);
10888 try++;
10889 break;
10890 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010891 /* FALLTHROUGH */
Eric Andersen62483552001-07-10 06:09:16 +000010892 default:
10893 if (newfd >= 0) {
10894 close(newfd);
10895 }
10896 INTON;
10897 error("%d: %m", fd);
10898 /* NOTREACHED */
10899 }
10900 }
10901 if (!try) {
10902 close(fd);
10903 if (flags & REDIR_PUSH) {
10904 sv->renamed[fd] = i;
10905 }
10906 }
10907 } else if (fd != newfd) {
10908 close(fd);
10909 }
10910 if (fd == 0)
10911 fd0_redirected++;
10912 if (!try)
10913 dupredirect(n, newfd, fd1dup);
10914 INTON;
10915 }
10916}
10917
10918
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010919static void dupredirect(const union node *redir, int f, int fd1dup)
Eric Andersen2870d962001-07-02 17:27:21 +000010920{
Eric Andersencb57d552001-06-28 07:25:16 +000010921 int fd = redir->nfile.fd;
10922
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010923 if (fd == 1)
Eric Andersen62483552001-07-10 06:09:16 +000010924 fd1dup = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010925 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010926 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
10927 if (redir->ndup.dupfd != 1 || fd1dup != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000010928 dup_as_newfd(redir->ndup.dupfd, fd);
10929 }
10930 return;
10931 }
10932
10933 if (f != fd) {
10934 dup_as_newfd(f, fd);
10935 close(f);
10936 }
10937 return;
10938}
10939
10940
Eric Andersencb57d552001-06-28 07:25:16 +000010941
Eric Andersencb57d552001-06-28 07:25:16 +000010942/*
10943 * Undo the effects of the last redirection.
10944 */
10945
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010946static void popredir(void)
Eric Andersen2870d962001-07-02 17:27:21 +000010947{
Eric Andersencb57d552001-06-28 07:25:16 +000010948 struct redirtab *rp = redirlist;
10949 int i;
10950
10951 INTOFF;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010952 for (i = 0; i < 10; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000010953 if (rp->renamed[i] != EMPTY) {
Eric Andersen2870d962001-07-02 17:27:21 +000010954 if (i == 0)
10955 fd0_redirected--;
Eric Andersencb57d552001-06-28 07:25:16 +000010956 close(i);
10957 if (rp->renamed[i] >= 0) {
10958 dup_as_newfd(rp->renamed[i], i);
10959 close(rp->renamed[i]);
10960 }
Eric Andersencb57d552001-06-28 07:25:16 +000010961 }
10962 }
10963 redirlist = rp->next;
Aaron Lehmann49c024a2002-08-02 06:39:47 +000010964 free(rp);
Eric Andersencb57d552001-06-28 07:25:16 +000010965 INTON;
10966}
10967
10968/*
Eric Andersencb57d552001-06-28 07:25:16 +000010969 * Discard all saved file descriptors.
10970 */
10971
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010972static void clearredir(void)
10973{
Eric Andersencb57d552001-06-28 07:25:16 +000010974 struct redirtab *rp;
10975 int i;
10976
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010977 for (rp = redirlist; rp; rp = rp->next) {
10978 for (i = 0; i < 10; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000010979 if (rp->renamed[i] >= 0) {
10980 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000010981 }
10982 rp->renamed[i] = EMPTY;
10983 }
10984 }
Eric Andersencb57d552001-06-28 07:25:16 +000010985}
10986
10987
Eric Andersencb57d552001-06-28 07:25:16 +000010988/*
10989 * Copy a file descriptor to be >= to. Returns -1
10990 * if the source file descriptor is closed, EMPTY if there are no unused
10991 * file descriptors left.
10992 */
10993
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010994static int dup_as_newfd(int from, int to)
Eric Andersencb57d552001-06-28 07:25:16 +000010995{
10996 int newfd;
10997
10998 newfd = fcntl(from, F_DUPFD, to);
10999 if (newfd < 0) {
11000 if (errno == EMFILE)
11001 return EMPTY;
11002 else
Eric Andersen2870d962001-07-02 17:27:21 +000011003 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011004 }
11005 return newfd;
11006}
11007
Eric Andersencb57d552001-06-28 07:25:16 +000011008#ifdef DEBUG
Eric Andersenec074692001-10-31 11:05:49 +000011009/*
11010 * Debugging stuff.
11011 */
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011012
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011013static void shtree(union node *, int, char *, FILE *);
11014static void shcmd(union node *, FILE *);
11015static void sharg(union node *, FILE *);
11016static void indent(int, char *, FILE *);
11017static void trstring(char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011018
11019
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011020#if 0
11021static void showtree(node * n)
Eric Andersencb57d552001-06-28 07:25:16 +000011022{
11023 trputs("showtree called\n");
11024 shtree(n, 1, NULL, stdout);
11025}
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011026#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011027
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011028static void shtree(union node *n, int ind, char *pfx, FILE * fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011029{
11030 struct nodelist *lp;
11031 const char *s;
11032
11033 if (n == NULL)
11034 return;
11035
11036 indent(ind, pfx, fp);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011037 switch (n->type) {
Eric Andersencb57d552001-06-28 07:25:16 +000011038 case NSEMI:
11039 s = "; ";
11040 goto binop;
11041 case NAND:
11042 s = " && ";
11043 goto binop;
11044 case NOR:
11045 s = " || ";
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011046 binop:
Eric Andersencb57d552001-06-28 07:25:16 +000011047 shtree(n->nbinary.ch1, ind, NULL, fp);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011048 /* if (ind < 0) */
11049 fputs(s, fp);
Eric Andersencb57d552001-06-28 07:25:16 +000011050 shtree(n->nbinary.ch2, ind, NULL, fp);
11051 break;
11052 case NCMD:
11053 shcmd(n, fp);
11054 if (ind >= 0)
11055 putc('\n', fp);
11056 break;
11057 case NPIPE:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011058 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000011059 shcmd(lp->n, fp);
11060 if (lp->next)
11061 fputs(" | ", fp);
11062 }
11063 if (n->npipe.backgnd)
11064 fputs(" &", fp);
11065 if (ind >= 0)
11066 putc('\n', fp);
11067 break;
11068 default:
11069 fprintf(fp, "<node type %d>", n->type);
11070 if (ind >= 0)
11071 putc('\n', fp);
11072 break;
11073 }
11074}
11075
11076
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011077static void shcmd(union node *cmd, FILE * fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011078{
11079 union node *np;
11080 int first;
11081 const char *s;
11082 int dftfd;
11083
11084 first = 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011085 for (np = cmd->ncmd.args; np; np = np->narg.next) {
11086 if (!first)
Eric Andersencb57d552001-06-28 07:25:16 +000011087 putchar(' ');
11088 sharg(np, fp);
11089 first = 0;
11090 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011091 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
11092 if (!first)
Eric Andersencb57d552001-06-28 07:25:16 +000011093 putchar(' ');
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011094#if 1
11095 s = "*error*";
11096 dftfd = 0;
11097 if ((np->nfile.type <= NFROMFD) && (np->nfile.type >= NTO)) {
11098 s = redir_strings[np->nfile.type - NTO];
11099 if (*s == '>') {
11100 dftfd = 1;
11101 }
11102 }
11103#else
Eric Andersencb57d552001-06-28 07:25:16 +000011104 switch (np->nfile.type) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011105 case NTO:
11106 s = ">";
11107 dftfd = 1;
11108 break;
11109 case NAPPEND:
11110 s = ">>";
11111 dftfd = 1;
11112 break;
11113 case NTOFD:
11114 s = ">&";
11115 dftfd = 1;
11116 break;
11117 case NTOOV:
11118 s = ">|";
11119 dftfd = 1;
11120 break;
11121 case NFROM:
11122 s = "<";
11123 dftfd = 0;
11124 break;
11125 case NFROMFD:
11126 s = "<&";
11127 dftfd = 0;
11128 break;
11129 case NFROMTO:
11130 s = "<>";
11131 dftfd = 0;
11132 break;
11133 default:
11134 s = "*error*";
11135 dftfd = 0;
11136 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011137 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011138#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011139 if (np->nfile.fd != dftfd)
11140 fprintf(fp, "%d", np->nfile.fd);
11141 fputs(s, fp);
11142 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11143 fprintf(fp, "%d", np->ndup.dupfd);
11144 } else {
11145 sharg(np->nfile.fname, fp);
11146 }
11147 first = 0;
11148 }
11149}
11150
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011151
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011152static void sharg(union node *arg, FILE * fp)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011153{
Eric Andersencb57d552001-06-28 07:25:16 +000011154 char *p;
11155 struct nodelist *bqlist;
11156 int subtype;
11157
11158 if (arg->type != NARG) {
11159 printf("<node type %d>\n", arg->type);
11160 fflush(stdout);
11161 abort();
11162 }
11163 bqlist = arg->narg.backquote;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011164 for (p = arg->narg.text; *p; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011165 switch (*p) {
11166 case CTLESC:
11167 putc(*++p, fp);
11168 break;
11169 case CTLVAR:
11170 putc('$', fp);
11171 putc('{', fp);
11172 subtype = *++p;
11173 if (subtype == VSLENGTH)
11174 putc('#', fp);
11175
11176 while (*p != '=')
11177 putc(*p++, fp);
11178
11179 if (subtype & VSNUL)
11180 putc(':', fp);
11181
11182 switch (subtype & VSTYPE) {
11183 case VSNORMAL:
11184 putc('}', fp);
11185 break;
11186 case VSMINUS:
11187 putc('-', fp);
11188 break;
11189 case VSPLUS:
11190 putc('+', fp);
11191 break;
11192 case VSQUESTION:
11193 putc('?', fp);
11194 break;
11195 case VSASSIGN:
11196 putc('=', fp);
11197 break;
11198 case VSTRIMLEFT:
11199 putc('#', fp);
11200 break;
11201 case VSTRIMLEFTMAX:
11202 putc('#', fp);
11203 putc('#', fp);
11204 break;
11205 case VSTRIMRIGHT:
11206 putc('%', fp);
11207 break;
11208 case VSTRIMRIGHTMAX:
11209 putc('%', fp);
11210 putc('%', fp);
11211 break;
11212 case VSLENGTH:
11213 break;
11214 default:
11215 printf("<subtype %d>", subtype);
11216 }
11217 break;
11218 case CTLENDVAR:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011219 putc('}', fp);
11220 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011221 case CTLBACKQ:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011222 case CTLBACKQ | CTLQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000011223 putc('$', fp);
11224 putc('(', fp);
11225 shtree(bqlist->n, -1, NULL, fp);
11226 putc(')', fp);
11227 break;
11228 default:
11229 putc(*p, fp);
11230 break;
11231 }
11232 }
11233}
11234
11235
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011236static void indent(int amount, char *pfx, FILE * fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011237{
11238 int i;
11239
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011240 for (i = 0; i < amount; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011241 if (pfx && i == amount - 1)
11242 fputs(pfx, fp);
11243 putc('\t', fp);
11244 }
11245}
Eric Andersencb57d552001-06-28 07:25:16 +000011246
Eric Andersencb57d552001-06-28 07:25:16 +000011247FILE *tracefile;
11248
11249#if DEBUG == 2
11250static int debug = 1;
11251#else
11252static int debug = 0;
11253#endif
11254
11255
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011256static void trputc(int c)
Eric Andersencb57d552001-06-28 07:25:16 +000011257{
11258 if (tracefile == NULL)
11259 return;
11260 putc(c, tracefile);
11261 if (c == '\n')
11262 fflush(tracefile);
11263}
11264
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011265static void trace(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +000011266{
11267 va_list va;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011268
Eric Andersencb57d552001-06-28 07:25:16 +000011269 va_start(va, fmt);
Eric Andersencb57d552001-06-28 07:25:16 +000011270 if (tracefile != NULL) {
11271 (void) vfprintf(tracefile, fmt, va);
11272 if (strchr(fmt, '\n'))
11273 (void) fflush(tracefile);
11274 }
11275 va_end(va);
11276}
11277
11278
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011279static void trputs(const char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011280{
11281 if (tracefile == NULL)
11282 return;
11283 fputs(s, tracefile);
11284 if (strchr(s, '\n'))
11285 fflush(tracefile);
11286}
11287
11288
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011289static void trstring(char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011290{
11291 char *p;
11292 char c;
11293
11294 if (tracefile == NULL)
11295 return;
11296 putc('"', tracefile);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011297 for (p = s; *p; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011298 switch (*p) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011299 case '\n':
11300 c = 'n';
11301 goto backslash;
11302 case '\t':
11303 c = 't';
11304 goto backslash;
11305 case '\r':
11306 c = 'r';
11307 goto backslash;
11308 case '"':
11309 c = '"';
11310 goto backslash;
11311 case '\\':
11312 c = '\\';
11313 goto backslash;
11314 case CTLESC:
11315 c = 'e';
11316 goto backslash;
11317 case CTLVAR:
11318 c = 'v';
11319 goto backslash;
11320 case CTLVAR + CTLQUOTE:
11321 c = 'V';
11322 goto backslash;
11323 case CTLBACKQ:
11324 c = 'q';
11325 goto backslash;
11326 case CTLBACKQ + CTLQUOTE:
11327 c = 'Q';
11328 goto backslash;
11329 backslash:putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011330 putc(c, tracefile);
11331 break;
11332 default:
11333 if (*p >= ' ' && *p <= '~')
11334 putc(*p, tracefile);
11335 else {
11336 putc('\\', tracefile);
11337 putc(*p >> 6 & 03, tracefile);
11338 putc(*p >> 3 & 07, tracefile);
11339 putc(*p & 07, tracefile);
11340 }
11341 break;
11342 }
11343 }
11344 putc('"', tracefile);
11345}
11346
11347
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011348static void trargs(char **ap)
Eric Andersencb57d552001-06-28 07:25:16 +000011349{
11350 if (tracefile == NULL)
11351 return;
11352 while (*ap) {
11353 trstring(*ap++);
11354 if (*ap)
11355 putc(' ', tracefile);
11356 else
11357 putc('\n', tracefile);
11358 }
11359 fflush(tracefile);
11360}
11361
11362
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011363static void opentrace()
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011364{
Eric Andersencb57d552001-06-28 07:25:16 +000011365 char s[100];
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011366
Eric Andersencb57d552001-06-28 07:25:16 +000011367#ifdef O_APPEND
11368 int flags;
11369#endif
11370
11371 if (!debug)
11372 return;
11373#ifdef not_this_way
11374 {
11375 char *p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011376
Eric Andersencb57d552001-06-28 07:25:16 +000011377 if ((p = getenv("HOME")) == NULL) {
11378 if (geteuid() == 0)
11379 p = "/";
11380 else
11381 p = "/tmp";
11382 }
Eric Andersen2870d962001-07-02 17:27:21 +000011383 strcpy(s, p);
Eric Andersencb57d552001-06-28 07:25:16 +000011384 strcat(s, "/trace");
11385 }
11386#else
Eric Andersen2870d962001-07-02 17:27:21 +000011387 strcpy(s, "./trace");
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011388#endif /* not_this_way */
Matt Kraaia5f09c62001-11-12 16:44:55 +000011389 if ((tracefile = wfopen(s, "a")) == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000011390 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011391#ifdef O_APPEND
11392 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11393 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11394#endif
11395 fputs("\nTracing started.\n", tracefile);
11396 fflush(tracefile);
11397}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011398#endif /* DEBUG */
Eric Andersencb57d552001-06-28 07:25:16 +000011399
11400
11401/*
Eric Andersencb57d552001-06-28 07:25:16 +000011402 * The trap builtin.
11403 */
11404
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011405static int trapcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011406{
11407 char *action;
11408 char **ap;
11409 int signo;
11410
11411 if (argc <= 1) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011412 for (signo = 0; signo < NSIG; signo++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011413 if (trap[signo] != NULL) {
11414 char *p;
Eric Andersen34506362001-08-02 05:02:46 +000011415 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011416
11417 p = single_quote(trap[signo]);
Eric Andersen34506362001-08-02 05:02:46 +000011418 sn = sys_siglist[signo];
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011419 if (sn == NULL)
Eric Andersen34506362001-08-02 05:02:46 +000011420 sn = u_signal_names(0, &signo, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011421 if (sn == NULL)
Eric Andersen34506362001-08-02 05:02:46 +000011422 sn = "???";
11423 printf("trap -- %s %s\n", p, sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011424 stunalloc(p);
11425 }
11426 }
11427 return 0;
11428 }
11429 ap = argv + 1;
11430 if (argc == 2)
11431 action = NULL;
11432 else
11433 action = *ap++;
11434 while (*ap) {
11435 if ((signo = decode_signal(*ap, 0)) < 0)
11436 error("%s: bad trap", *ap);
11437 INTOFF;
11438 if (action) {
11439 if (action[0] == '-' && action[1] == '\0')
11440 action = NULL;
11441 else
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011442 action = xstrdup(action);
Eric Andersencb57d552001-06-28 07:25:16 +000011443 }
Aaron Lehmann49c024a2002-08-02 06:39:47 +000011444 free(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000011445 trap[signo] = action;
11446 if (signo != 0)
11447 setsignal(signo);
11448 INTON;
11449 ap++;
11450 }
11451 return 0;
11452}
11453
11454
Eric Andersencb57d552001-06-28 07:25:16 +000011455/*
11456 * Set the signal handler for the specified signal. The routine figures
11457 * out what it should be set to.
11458 */
11459
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011460static void setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011461{
11462 int action;
11463 char *t;
11464 struct sigaction act;
11465
11466 if ((t = trap[signo]) == NULL)
11467 action = S_DFL;
11468 else if (*t != '\0')
11469 action = S_CATCH;
11470 else
11471 action = S_IGN;
11472 if (rootshell && action == S_DFL) {
11473 switch (signo) {
11474 case SIGINT:
11475 if (iflag || minusc || sflag == 0)
11476 action = S_CATCH;
11477 break;
11478 case SIGQUIT:
11479#ifdef DEBUG
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011480 {
Eric Andersencb57d552001-06-28 07:25:16 +000011481
11482 if (debug)
11483 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011484 }
Eric Andersencb57d552001-06-28 07:25:16 +000011485#endif
11486 /* FALLTHROUGH */
11487 case SIGTERM:
11488 if (iflag)
11489 action = S_IGN;
11490 break;
Eric Andersend35c5df2002-01-09 15:37:36 +000011491#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +000011492 case SIGTSTP:
11493 case SIGTTOU:
11494 if (mflag)
11495 action = S_IGN;
11496 break;
11497#endif
11498 }
11499 }
11500
11501 t = &sigmode[signo - 1];
11502 if (*t == 0) {
11503 /*
11504 * current setting unknown
11505 */
11506 if (sigaction(signo, 0, &act) == -1) {
11507 /*
11508 * Pretend it worked; maybe we should give a warning
11509 * here, but other shells don't. We don't alter
11510 * sigmode, so that we retry every time.
11511 */
11512 return;
11513 }
11514 if (act.sa_handler == SIG_IGN) {
11515 if (mflag && (signo == SIGTSTP ||
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011516 signo == SIGTTIN || signo == SIGTTOU)) {
11517 *t = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000011518 } else
11519 *t = S_HARD_IGN;
11520 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011521 *t = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000011522 }
11523 }
11524 if (*t == S_HARD_IGN || *t == action)
11525 return;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011526 act.sa_handler = ((action == S_CATCH) ? onsig
11527 : ((action == S_IGN) ? SIG_IGN : SIG_DFL));
Eric Andersencb57d552001-06-28 07:25:16 +000011528 *t = action;
11529 act.sa_flags = 0;
11530 sigemptyset(&act.sa_mask);
11531 sigaction(signo, &act, 0);
11532}
11533
11534/*
11535 * Ignore a signal.
11536 */
11537
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011538static void ignoresig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011539{
11540 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11541 signal(signo, SIG_IGN);
11542 }
11543 sigmode[signo - 1] = S_HARD_IGN;
11544}
11545
11546
Eric Andersencb57d552001-06-28 07:25:16 +000011547/*
11548 * Signal handler.
11549 */
11550
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011551static void onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011552{
11553 if (signo == SIGINT && trap[SIGINT] == NULL) {
11554 onint();
11555 return;
11556 }
11557 gotsig[signo - 1] = 1;
11558 pendingsigs++;
11559}
11560
11561
Eric Andersencb57d552001-06-28 07:25:16 +000011562/*
11563 * Called to execute a trap. Perhaps we should avoid entering new trap
11564 * handlers while we are executing a trap handler.
11565 */
11566
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011567static void dotrap(void)
Eric Andersen2870d962001-07-02 17:27:21 +000011568{
Eric Andersencb57d552001-06-28 07:25:16 +000011569 int i;
11570 int savestatus;
11571
11572 for (;;) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011573 for (i = 1;; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011574 if (gotsig[i - 1])
11575 break;
11576 if (i >= NSIG - 1)
11577 goto done;
11578 }
11579 gotsig[i - 1] = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011580 savestatus = exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +000011581 evalstring(trap[i], 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011582 exitstatus = savestatus;
Eric Andersencb57d552001-06-28 07:25:16 +000011583 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011584 done:
Eric Andersencb57d552001-06-28 07:25:16 +000011585 pendingsigs = 0;
11586}
11587
Eric Andersencb57d552001-06-28 07:25:16 +000011588/*
11589 * Called to exit the shell.
11590 */
11591
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011592static void exitshell(int status)
Eric Andersencb57d552001-06-28 07:25:16 +000011593{
11594 struct jmploc loc1, loc2;
11595 char *p;
11596
11597 TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
11598 if (setjmp(loc1.loc)) {
11599 goto l1;
11600 }
11601 if (setjmp(loc2.loc)) {
11602 goto l2;
11603 }
11604 handler = &loc1;
11605 if ((p = trap[0]) != NULL && *p != '\0') {
11606 trap[0] = NULL;
11607 evalstring(p, 0);
11608 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011609 l1:handler = &loc2; /* probably unnecessary */
Eric Andersencb57d552001-06-28 07:25:16 +000011610 flushall();
Eric Andersend35c5df2002-01-09 15:37:36 +000011611#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +000011612 setjobctl(0);
11613#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011614 l2:_exit(status);
Eric Andersencb57d552001-06-28 07:25:16 +000011615 /* NOTREACHED */
11616}
11617
11618static int decode_signal(const char *string, int minsig)
11619{
11620 int signo;
Eric Andersen34506362001-08-02 05:02:46 +000011621 const char *name = u_signal_names(string, &signo, minsig);
Eric Andersencb57d552001-06-28 07:25:16 +000011622
Eric Andersen34506362001-08-02 05:02:46 +000011623 return name ? signo : -1;
Eric Andersencb57d552001-06-28 07:25:16 +000011624}
Eric Andersen34506362001-08-02 05:02:46 +000011625
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011626static struct var **hashvar(const char *);
11627static void showvars(const char *, int, int);
11628static struct var **findvar(struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011629
11630/*
11631 * Initialize the varable symbol tables and import the environment
11632 */
11633
Eric Andersencb57d552001-06-28 07:25:16 +000011634/*
11635 * This routine initializes the builtin variables. It is called when the
11636 * shell is initialized and again when a shell procedure is spawned.
11637 */
11638
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011639static void initvar()
11640{
Eric Andersencb57d552001-06-28 07:25:16 +000011641 const struct varinit *ip;
11642 struct var *vp;
11643 struct var **vpp;
11644
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011645 for (ip = varinit; (vp = ip->var) != NULL; ip++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011646 if ((vp->flags & VEXPORT) == 0) {
11647 vpp = hashvar(ip->text);
11648 vp->next = *vpp;
11649 *vpp = vp;
Matt Kraaic8227632001-11-12 16:57:27 +000011650 vp->text = xstrdup(ip->text);
Eric Andersencb57d552001-06-28 07:25:16 +000011651 vp->flags = ip->flags;
11652 vp->func = ip->func;
11653 }
11654 }
Tim Riker497a8852002-04-13 05:37:10 +000011655#if !defined(CONFIG_FEATURE_COMMAND_EDITING) || !defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
Eric Andersencb57d552001-06-28 07:25:16 +000011656 /*
11657 * PS1 depends on uid
11658 */
11659 if ((vps1.flags & VEXPORT) == 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011660 vpp = hashvar("PS1=$ ");
Eric Andersencb57d552001-06-28 07:25:16 +000011661 vps1.next = *vpp;
11662 *vpp = &vps1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011663 vps1.text = xstrdup(geteuid()? "PS1=$ " : "PS1=# ");
11664 vps1.flags = VSTRFIXED | VTEXTFIXED;
Eric Andersencb57d552001-06-28 07:25:16 +000011665 }
Tim Riker497a8852002-04-13 05:37:10 +000011666#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011667}
11668
11669/*
11670 * Set the value of a variable. The flags argument is ored with the
11671 * flags of the variable. If val is NULL, the variable is unset.
11672 */
11673
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011674static void setvar(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011675{
11676 const char *p;
11677 int len;
11678 int namelen;
11679 char *nameeq;
11680 int isbad;
11681 int vallen = 0;
11682
11683 isbad = 0;
11684 p = name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011685 if (!is_name(*p))
Eric Andersencb57d552001-06-28 07:25:16 +000011686 isbad = 1;
11687 p++;
11688 for (;;) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011689 if (!is_in_name(*p)) {
Eric Andersencb57d552001-06-28 07:25:16 +000011690 if (*p == '\0' || *p == '=')
11691 break;
11692 isbad = 1;
11693 }
11694 p++;
11695 }
11696 namelen = p - name;
11697 if (isbad)
11698 error("%.*s: bad variable name", namelen, name);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011699 len = namelen + 2; /* 2 is space for '=' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +000011700 if (val == NULL) {
11701 flags |= VUNSET;
11702 } else {
11703 len += vallen = strlen(val);
11704 }
11705 INTOFF;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011706 nameeq = xmalloc(len);
Eric Andersencb57d552001-06-28 07:25:16 +000011707 memcpy(nameeq, name, namelen);
11708 nameeq[namelen] = '=';
11709 if (val) {
11710 memcpy(nameeq + namelen + 1, val, vallen + 1);
11711 } else {
11712 nameeq[namelen + 1] = '\0';
11713 }
11714 setvareq(nameeq, flags);
11715 INTON;
11716}
11717
11718
11719
11720/*
11721 * Same as setvar except that the variable and value are passed in
11722 * the first argument as name=value. Since the first argument will
11723 * be actually stored in the table, it should not be a string that
11724 * will go away.
11725 */
11726
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011727static void setvareq(char *s, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011728{
11729 struct var *vp, **vpp;
11730
11731 vpp = hashvar(s);
11732 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
11733 if ((vp = *findvar(vpp, s))) {
11734 if (vp->flags & VREADONLY) {
11735 size_t len = strchr(s, '=') - s;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011736
Eric Andersencb57d552001-06-28 07:25:16 +000011737 error("%.*s: is read only", len, s);
11738 }
11739 INTOFF;
11740
11741 if (vp->func && (flags & VNOFUNC) == 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011742 (*vp->func) (strchr(s, '=') + 1);
Eric Andersencb57d552001-06-28 07:25:16 +000011743
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011744 if ((vp->flags & (VTEXTFIXED | VSTACK)) == 0)
Aaron Lehmann49c024a2002-08-02 06:39:47 +000011745 free(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000011746
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011747 vp->flags &= ~(VTEXTFIXED | VSTACK | VUNSET);
Eric Andersencb57d552001-06-28 07:25:16 +000011748 vp->flags |= flags;
11749 vp->text = s;
11750
Eric Andersend35c5df2002-01-09 15:37:36 +000011751#ifdef CONFIG_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000011752 /*
11753 * We could roll this to a function, to handle it as
11754 * a regular variable function callback, but why bother?
11755 */
11756 if (iflag && (vp == &vmpath || (vp == &vmail && !mpathset())))
11757 chkmail(1);
Eric Andersenec074692001-10-31 11:05:49 +000011758#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011759 INTON;
11760 return;
11761 }
11762 /* not found */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011763 vp = xmalloc(sizeof(*vp));
Eric Andersencb57d552001-06-28 07:25:16 +000011764 vp->flags = flags;
11765 vp->text = s;
11766 vp->next = *vpp;
11767 vp->func = NULL;
11768 *vpp = vp;
11769}
11770
11771
11772
11773/*
11774 * Process a linked list of variable assignments.
11775 */
11776
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011777static void listsetvar(struct strlist *mylist)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011778{
Eric Andersencb57d552001-06-28 07:25:16 +000011779 struct strlist *lp;
11780
11781 INTOFF;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011782 for (lp = mylist; lp; lp = lp->next) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011783 setvareq(xstrdup(lp->text), 0);
Eric Andersencb57d552001-06-28 07:25:16 +000011784 }
11785 INTON;
11786}
11787
11788
11789
11790/*
11791 * Find the value of a variable. Returns NULL if not set.
11792 */
11793
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011794static const char *lookupvar(const char *name)
Eric Andersenec074692001-10-31 11:05:49 +000011795{
Eric Andersencb57d552001-06-28 07:25:16 +000011796 struct var *v;
11797
11798 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
11799 return strchr(v->text, '=') + 1;
11800 }
11801 return NULL;
11802}
11803
11804
11805
11806/*
11807 * Search the environment of a builtin command.
11808 */
11809
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011810static const char *bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000011811{
Eric Andersen62483552001-07-10 06:09:16 +000011812 const struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000011813
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011814 for (sp = cmdenviron; sp; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000011815 if (varequal(sp->text, name))
11816 return strchr(sp->text, '=') + 1;
11817 }
11818 return lookupvar(name);
11819}
11820
11821
11822
11823/*
11824 * Generate a list of exported variables. This routine is used to construct
11825 * the third argument to execve when executing a program.
11826 */
11827
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011828static char **environment()
11829{
Eric Andersencb57d552001-06-28 07:25:16 +000011830 int nenv;
11831 struct var **vpp;
11832 struct var *vp;
11833 char **env;
11834 char **ep;
11835
11836 nenv = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011837 for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) {
11838 for (vp = *vpp; vp; vp = vp->next)
Eric Andersencb57d552001-06-28 07:25:16 +000011839 if (vp->flags & VEXPORT)
11840 nenv++;
11841 }
11842 ep = env = stalloc((nenv + 1) * sizeof *env);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011843 for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) {
11844 for (vp = *vpp; vp; vp = vp->next)
Eric Andersencb57d552001-06-28 07:25:16 +000011845 if (vp->flags & VEXPORT)
11846 *ep++ = vp->text;
11847 }
11848 *ep = NULL;
11849 return env;
11850}
11851
11852
11853/*
Eric Andersencb57d552001-06-28 07:25:16 +000011854 * Command to list all variables which are set. Currently this command
11855 * is invoked from the set command when the set command is called without
11856 * any variables.
11857 */
11858
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011859static int showvarscmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011860{
11861 showvars(nullstr, VUNSET, VUNSET);
11862 return 0;
11863}
11864
11865
11866
11867/*
11868 * The export and readonly commands.
11869 */
11870
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011871static int exportcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011872{
11873 struct var *vp;
11874 char *name;
11875 const char *p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011876 int flag = argv[0][0] == 'r' ? VREADONLY : VEXPORT;
Eric Andersencb57d552001-06-28 07:25:16 +000011877 int pflag;
11878
11879 listsetvar(cmdenviron);
11880 pflag = (nextopt("p") == 'p');
11881 if (argc > 1 && !pflag) {
11882 while ((name = *argptr++) != NULL) {
11883 if ((p = strchr(name, '=')) != NULL) {
11884 p++;
11885 } else {
11886 if ((vp = *findvar(hashvar(name), name))) {
11887 vp->flags |= flag;
11888 goto found;
11889 }
11890 }
11891 setvar(name, p, flag);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011892 found:;
Eric Andersencb57d552001-06-28 07:25:16 +000011893 }
11894 } else {
11895 showvars(argv[0], flag, 0);
11896 }
11897 return 0;
11898}
11899
Eric Andersen34506362001-08-02 05:02:46 +000011900
Eric Andersencb57d552001-06-28 07:25:16 +000011901/*
11902 * The "local" command.
11903 */
11904
Eric Andersen2870d962001-07-02 17:27:21 +000011905/* funcnest nonzero if we are currently evaluating a function */
11906
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011907static int localcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011908{
11909 char *name;
11910
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011911 if (!funcnest)
Eric Andersencb57d552001-06-28 07:25:16 +000011912 error("Not in a function");
11913 while ((name = *argptr++) != NULL) {
11914 mklocal(name);
11915 }
11916 return 0;
11917}
11918
11919
11920/*
11921 * Make a variable a local variable. When a variable is made local, it's
11922 * value and flags are saved in a localvar structure. The saved values
11923 * will be restored when the shell function returns. We handle the name
11924 * "-" as a special case.
11925 */
11926
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011927static void mklocal(char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011928{
Eric Andersencb57d552001-06-28 07:25:16 +000011929 struct localvar *lvp;
11930 struct var **vpp;
11931 struct var *vp;
11932
11933 INTOFF;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011934 lvp = xmalloc(sizeof(struct localvar));
Eric Andersencb57d552001-06-28 07:25:16 +000011935 if (name[0] == '-' && name[1] == '\0') {
11936 char *p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011937
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011938 p = xmalloc(sizeof optet_vals);
Eric Andersen2870d962001-07-02 17:27:21 +000011939 lvp->text = memcpy(p, optet_vals, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000011940 vp = NULL;
11941 } else {
11942 vpp = hashvar(name);
11943 vp = *findvar(vpp, name);
11944 if (vp == NULL) {
11945 if (strchr(name, '='))
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011946 setvareq(xstrdup(name), VSTRFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +000011947 else
11948 setvar(name, NULL, VSTRFIXED);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011949 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000011950 lvp->text = NULL;
11951 lvp->flags = VUNSET;
11952 } else {
11953 lvp->text = vp->text;
11954 lvp->flags = vp->flags;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011955 vp->flags |= VSTRFIXED | VTEXTFIXED;
Eric Andersencb57d552001-06-28 07:25:16 +000011956 if (strchr(name, '='))
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011957 setvareq(xstrdup(name), 0);
Eric Andersencb57d552001-06-28 07:25:16 +000011958 }
11959 }
11960 lvp->vp = vp;
11961 lvp->next = localvars;
11962 localvars = lvp;
11963 INTON;
11964}
11965
11966
11967/*
11968 * Called after a function returns.
11969 */
11970
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011971static void poplocalvars()
11972{
Eric Andersencb57d552001-06-28 07:25:16 +000011973 struct localvar *lvp;
11974 struct var *vp;
11975
11976 while ((lvp = localvars) != NULL) {
11977 localvars = lvp->next;
11978 vp = lvp->vp;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011979 if (vp == NULL) { /* $- saved */
Eric Andersen2870d962001-07-02 17:27:21 +000011980 memcpy(optet_vals, lvp->text, sizeof optet_vals);
Aaron Lehmann49c024a2002-08-02 06:39:47 +000011981 free(lvp->text);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011982 } else if ((lvp->flags & (VUNSET | VSTRFIXED)) == VUNSET) {
11983 (void) unsetvar(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000011984 } else {
11985 if ((vp->flags & VTEXTFIXED) == 0)
Aaron Lehmann49c024a2002-08-02 06:39:47 +000011986 free(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000011987 vp->flags = lvp->flags;
11988 vp->text = lvp->text;
11989 }
Aaron Lehmann49c024a2002-08-02 06:39:47 +000011990 free(lvp);
Eric Andersencb57d552001-06-28 07:25:16 +000011991 }
11992}
11993
11994
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011995static int setvarcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011996{
11997 if (argc <= 2)
11998 return unsetcmd(argc, argv);
11999 else if (argc == 3)
12000 setvar(argv[1], argv[2], 0);
12001 else
12002 error("List assignment not implemented");
12003 return 0;
12004}
12005
12006
12007/*
12008 * The unset builtin command. We unset the function before we unset the
12009 * variable to allow a function to be unset when there is a readonly variable
12010 * with the same name.
12011 */
12012
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012013static int unsetcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012014{
12015 char **ap;
12016 int i;
12017 int flg_func = 0;
12018 int flg_var = 0;
12019 int ret = 0;
12020
12021 while ((i = nextopt("vf")) != '\0') {
12022 if (i == 'f')
12023 flg_func = 1;
12024 else
12025 flg_var = 1;
12026 }
12027 if (flg_func == 0 && flg_var == 0)
12028 flg_var = 1;
12029
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012030 for (ap = argptr; *ap; ap++) {
Eric Andersencb57d552001-06-28 07:25:16 +000012031 if (flg_func)
12032 unsetfunc(*ap);
12033 if (flg_var)
12034 ret |= unsetvar(*ap);
12035 }
12036 return ret;
12037}
12038
12039
12040/*
12041 * Unset the specified variable.
12042 */
12043
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012044static int unsetvar(const char *s)
Eric Andersen62483552001-07-10 06:09:16 +000012045{
Eric Andersencb57d552001-06-28 07:25:16 +000012046 struct var **vpp;
12047 struct var *vp;
12048
12049 vpp = findvar(hashvar(s), s);
12050 vp = *vpp;
12051 if (vp) {
12052 if (vp->flags & VREADONLY)
12053 return (1);
12054 INTOFF;
12055 if (*(strchr(vp->text, '=') + 1) != '\0')
12056 setvar(s, nullstr, 0);
12057 vp->flags &= ~VEXPORT;
12058 vp->flags |= VUNSET;
12059 if ((vp->flags & VSTRFIXED) == 0) {
12060 if ((vp->flags & VTEXTFIXED) == 0)
Aaron Lehmann49c024a2002-08-02 06:39:47 +000012061 free(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012062 *vpp = vp->next;
Aaron Lehmann49c024a2002-08-02 06:39:47 +000012063 free(vp);
Eric Andersencb57d552001-06-28 07:25:16 +000012064 }
12065 INTON;
12066 return (0);
12067 }
12068
12069 return (0);
12070}
12071
12072
12073
12074/*
12075 * Find the appropriate entry in the hash table from the name.
12076 */
12077
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012078static struct var **hashvar(const char *p)
Eric Andersen62483552001-07-10 06:09:16 +000012079{
Eric Andersencb57d552001-06-28 07:25:16 +000012080 unsigned int hashval;
12081
12082 hashval = ((unsigned char) *p) << 4;
12083 while (*p && *p != '=')
12084 hashval += (unsigned char) *p++;
12085 return &vartab[hashval % VTABSIZE];
12086}
12087
12088
12089
12090/*
12091 * Returns true if the two strings specify the same varable. The first
12092 * variable name is terminated by '='; the second may be terminated by
12093 * either '=' or '\0'.
12094 */
12095
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012096static int varequal(const char *p, const char *q)
Eric Andersen62483552001-07-10 06:09:16 +000012097{
Eric Andersencb57d552001-06-28 07:25:16 +000012098 while (*p == *q++) {
12099 if (*p++ == '=')
12100 return 1;
12101 }
12102 if (*p == '=' && *(q - 1) == '\0')
12103 return 1;
12104 return 0;
12105}
12106
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012107static void showvars(const char *myprefix, int mask, int xor)
Eric Andersencb57d552001-06-28 07:25:16 +000012108{
12109 struct var **vpp;
12110 struct var *vp;
12111 const char *sep = myprefix == nullstr ? myprefix : spcstr;
12112
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012113 for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) {
12114 for (vp = *vpp; vp; vp = vp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000012115 if ((vp->flags & mask) ^ xor) {
12116 char *p;
12117 int len;
12118
12119 p = strchr(vp->text, '=') + 1;
12120 len = p - vp->text;
12121 p = single_quote(p);
12122
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012123 printf("%s%s%.*s%s\n", myprefix, sep, len, vp->text, p);
Eric Andersencb57d552001-06-28 07:25:16 +000012124 stunalloc(p);
12125 }
12126 }
12127 }
12128}
12129
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012130static struct var **findvar(struct var **vpp, const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012131{
12132 for (; *vpp; vpp = &(*vpp)->next) {
12133 if (varequal((*vpp)->text, name)) {
12134 break;
12135 }
12136 }
12137 return vpp;
12138}
12139
12140/*
12141 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
12142 * This file contains code for the times builtin.
Eric Andersencb57d552001-06-28 07:25:16 +000012143 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012144static int timescmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012145{
12146 struct tms buf;
12147 long int clk_tck = sysconf(_SC_CLK_TCK);
12148
12149 times(&buf);
12150 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012151 (int) (buf.tms_utime / clk_tck / 60),
12152 ((double) buf.tms_utime) / clk_tck,
12153 (int) (buf.tms_stime / clk_tck / 60),
12154 ((double) buf.tms_stime) / clk_tck,
12155 (int) (buf.tms_cutime / clk_tck / 60),
12156 ((double) buf.tms_cutime) / clk_tck,
12157 (int) (buf.tms_cstime / clk_tck / 60),
12158 ((double) buf.tms_cstime) / clk_tck);
Eric Andersencb57d552001-06-28 07:25:16 +000012159 return 0;
12160}
12161
Eric Andersend35c5df2002-01-09 15:37:36 +000012162#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012163/* The let builtin. */
12164int letcmd(int argc, char **argv)
Eric Andersen74bcd162001-07-30 21:41:37 +000012165{
Eric Andersen34506362001-08-02 05:02:46 +000012166 int errcode;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012167 long result = 0;
12168
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012169 if (argc == 2) {
12170 char *tmp, *expression, p[13];
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012171
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012172 expression = strchr(argv[1], '=');
12173 if (!expression) {
Eric Andersen34506362001-08-02 05:02:46 +000012174 /* Cannot use 'error()' here, or the return code
12175 * will be incorrect */
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012176 out2fmt("sh: let: syntax error: \"%s\"\n", argv[1]);
12177 return 0;
Eric Andersen74bcd162001-07-30 21:41:37 +000012178 }
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012179 *expression = '\0';
12180 tmp = ++expression;
Eric Andersen34506362001-08-02 05:02:46 +000012181 result = arith(tmp, &errcode);
12182 if (errcode < 0) {
12183 /* Cannot use 'error()' here, or the return code
12184 * will be incorrect */
12185 out2fmt("sh: let: ");
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012186 if (errcode == -2)
Eric Andersen34506362001-08-02 05:02:46 +000012187 out2fmt("divide by zero");
12188 else
12189 out2fmt("syntax error: \"%s=%s\"\n", argv[1], expression);
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012190 return 0;
12191 }
12192 snprintf(p, 12, "%ld", result);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012193 setvar(argv[1], xstrdup(p), 0);
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012194 } else if (argc >= 3)
12195 synerror("invalid operand");
12196 return !result;
Eric Andersen74bcd162001-07-30 21:41:37 +000012197}
12198#endif
12199
12200
12201
Eric Andersendf82f612001-06-28 07:46:40 +000012202/*-
12203 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000012204 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000012205 *
12206 * This code is derived from software contributed to Berkeley by
12207 * Kenneth Almquist.
12208 *
12209 * Redistribution and use in source and binary forms, with or without
12210 * modification, are permitted provided that the following conditions
12211 * are met:
12212 * 1. Redistributions of source code must retain the above copyright
12213 * notice, this list of conditions and the following disclaimer.
12214 * 2. Redistributions in binary form must reproduce the above copyright
12215 * notice, this list of conditions and the following disclaimer in the
12216 * documentation and/or other materials provided with the distribution.
12217 *
Eric Andersen2870d962001-07-02 17:27:21 +000012218 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
12219 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000012220 *
12221 * 4. Neither the name of the University nor the names of its contributors
12222 * may be used to endorse or promote products derived from this software
12223 * without specific prior written permission.
12224 *
12225 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
12226 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
12227 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
12228 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
12229 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
12230 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
12231 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
12232 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
12233 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
12234 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
12235 * SUCH DAMAGE.
12236 */