blob: fb65c2da06208d8880f9cdd0fa1a6f12e3e3135c [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
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00001199#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
1200static struct var vhistfile;
1201#endif
1202
Eric Andersen2870d962001-07-02 17:27:21 +00001203struct varinit {
1204 struct var *var;
1205 int flags;
1206 const char *text;
1207 void (*func) (const char *);
1208};
1209
1210static const char defpathvar[] =
1211 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
1212#define defpath (defpathvar + 5)
1213
1214#ifdef IFS_BROKEN
1215static const char defifsvar[] = "IFS= \t\n";
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001216
Eric Andersen2870d962001-07-02 17:27:21 +00001217#define defifs (defifsvar + 4)
1218#else
1219static const char defifs[] = " \t\n";
1220#endif
1221
1222static const struct varinit varinit[] = {
1223#ifdef IFS_BROKEN
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001224 {&vifs, VSTRFIXED | VTEXTFIXED, defifsvar,
Eric Andersen2870d962001-07-02 17:27:21 +00001225#else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001226 {&vifs, VSTRFIXED | VTEXTFIXED | VUNSET, "IFS=",
Eric Andersen2870d962001-07-02 17:27:21 +00001227#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001228 NULL},
1229 {&vmail, VSTRFIXED | VTEXTFIXED | VUNSET, "MAIL=",
1230 NULL},
1231 {&vmpath, VSTRFIXED | VTEXTFIXED | VUNSET, "MAILPATH=",
1232 NULL},
1233 {&vpath, VSTRFIXED | VTEXTFIXED, defpathvar,
1234 changepath},
Tim Riker497a8852002-04-13 05:37:10 +00001235#if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001236 {&vps1, VSTRFIXED | VTEXTFIXED, "PS1=\\w \\$ ",
1237 NULL},
1238#endif /* else vps1 depends on uid */
1239 {&vps2, VSTRFIXED | VTEXTFIXED, "PS2=> ",
1240 NULL},
1241 {&voptind, VSTRFIXED | VTEXTFIXED, "OPTIND=1",
1242 getoptsreset},
Eric Andersenbdfd0d72001-10-24 05:00:29 +00001243#ifdef CONFIG_LOCALE_SUPPORT
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001244 {&vlc_all, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL=",
1245 change_lc_all},
1246 {&vlc_ctype, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE=",
1247 change_lc_ctype},
Eric Andersen2870d962001-07-02 17:27:21 +00001248#endif
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00001249#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
1250 {&vhistfile, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE=",
1251 NULL},
1252#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001253 {NULL, 0, NULL,
1254 NULL}
Eric Andersen2870d962001-07-02 17:27:21 +00001255};
1256
1257#define VTABSIZE 39
1258
1259static struct var *vartab[VTABSIZE];
1260
1261/*
1262 * The following macros access the values of the above variables.
1263 * They have to skip over the name. They return the null string
1264 * for unset variables.
1265 */
1266
1267#define ifsval() (vifs.text + 4)
1268#define ifsset() ((vifs.flags & VUNSET) == 0)
1269#define mailval() (vmail.text + 5)
1270#define mpathval() (vmpath.text + 9)
1271#define pathval() (vpath.text + 5)
1272#define ps1val() (vps1.text + 4)
1273#define ps2val() (vps2.text + 4)
1274#define optindval() (voptind.text + 7)
1275
1276#define mpathset() ((vmpath.flags & VUNSET) == 0)
1277
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001278static void initvar(void);
1279static void setvar(const char *, const char *, int);
1280static void setvareq(char *, int);
1281static void listsetvar(struct strlist *);
1282static const char *lookupvar(const char *);
1283static const char *bltinlookup(const char *);
1284static char **environment(void);
1285static int showvarscmd(int, char **);
1286static void mklocal(char *);
1287static void poplocalvars(void);
1288static int unsetvar(const char *);
1289static int varequal(const char *, const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001290
1291
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001292static char *arg0; /* value of $0 */
1293static struct shparam shellparam; /* current positional parameters */
1294static char **argptr; /* argument list for builtin commands */
1295static char *optionarg; /* set by nextopt (like getopt) */
1296static char *optptr; /* used by nextopt */
1297static char *minusc; /* argument to -c option */
Eric Andersen2870d962001-07-02 17:27:21 +00001298
1299
Eric Andersend35c5df2002-01-09 15:37:36 +00001300#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00001301
1302#define ALIASINUSE 1
1303#define ALIASDEAD 2
1304
Eric Andersen3102ac42001-07-06 04:26:23 +00001305#define ATABSIZE 39
1306
Eric Andersen2870d962001-07-02 17:27:21 +00001307struct alias {
1308 struct alias *next;
1309 char *name;
1310 char *val;
1311 int flag;
1312};
1313
1314static struct alias *atab[ATABSIZE];
1315
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001316static void setalias(char *, char *);
1317static struct alias **hashalias(const char *);
1318static struct alias *freealias(struct alias *);
1319static struct alias **__lookupalias(const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00001320
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001321static void setalias(char *name, char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00001322{
1323 struct alias *ap, **app;
1324
1325 app = __lookupalias(name);
1326 ap = *app;
1327 INTOFF;
1328 if (ap) {
1329 if (!(ap->flag & ALIASINUSE)) {
Aaron Lehmann49c024a2002-08-02 06:39:47 +00001330 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00001331 }
Manuel Novoa III cad53642003-03-19 09:13:01 +00001332 ap->val = bb_xstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00001333 ap->flag &= ~ALIASDEAD;
1334 } else {
1335 /* not found */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001336 ap = xmalloc(sizeof(struct alias));
Manuel Novoa III cad53642003-03-19 09:13:01 +00001337 ap->name = bb_xstrdup(name);
1338 ap->val = bb_xstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00001339 ap->flag = 0;
1340 ap->next = 0;
1341 *app = ap;
1342 }
1343 INTON;
1344}
1345
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001346static int unalias(char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00001347{
Eric Andersencb57d552001-06-28 07:25:16 +00001348 struct alias **app;
1349
1350 app = __lookupalias(name);
1351
1352 if (*app) {
1353 INTOFF;
1354 *app = freealias(*app);
1355 INTON;
1356 return (0);
1357 }
1358
1359 return (1);
1360}
1361
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001362static void rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00001363{
Eric Andersencb57d552001-06-28 07:25:16 +00001364 struct alias *ap, **app;
1365 int i;
1366
1367 INTOFF;
1368 for (i = 0; i < ATABSIZE; i++) {
1369 app = &atab[i];
1370 for (ap = *app; ap; ap = *app) {
1371 *app = freealias(*app);
1372 if (ap == *app) {
1373 app = &ap->next;
1374 }
1375 }
1376 }
1377 INTON;
1378}
1379
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001380static void printalias(const struct alias *ap)
1381{
Eric Andersen2870d962001-07-02 17:27:21 +00001382 char *p;
1383
1384 p = single_quote(ap->val);
Eric Andersen62483552001-07-10 06:09:16 +00001385 printf("alias %s=%s\n", ap->name, p);
Eric Andersen2870d962001-07-02 17:27:21 +00001386 stunalloc(p);
1387}
1388
Eric Andersencb57d552001-06-28 07:25:16 +00001389
1390/*
1391 * TODO - sort output
1392 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001393static int aliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001394{
1395 char *n, *v;
1396 int ret = 0;
1397 struct alias *ap;
1398
1399 if (argc == 1) {
1400 int i;
1401
1402 for (i = 0; i < ATABSIZE; i++)
1403 for (ap = atab[i]; ap; ap = ap->next) {
1404 printalias(ap);
1405 }
1406 return (0);
1407 }
1408 while ((n = *++argv) != NULL) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001409 if ((v = strchr(n + 1, '=')) == NULL) { /* n+1: funny ksh stuff */
Eric Andersencb57d552001-06-28 07:25:16 +00001410 if ((ap = *__lookupalias(n)) == NULL) {
Eric Andersen3102ac42001-07-06 04:26:23 +00001411 out2fmt("%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00001412 ret = 1;
1413 } else
1414 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001415 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00001416 *v++ = '\0';
1417 setalias(n, v);
1418 }
1419 }
1420
1421 return (ret);
1422}
1423
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001424static int unaliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001425{
1426 int i;
1427
1428 while ((i = nextopt("a")) != '\0') {
1429 if (i == 'a') {
1430 rmaliases();
1431 return (0);
1432 }
1433 }
1434 for (i = 0; *argptr; argptr++) {
1435 if (unalias(*argptr)) {
Eric Andersen3102ac42001-07-06 04:26:23 +00001436 out2fmt("%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00001437 i = 1;
1438 }
1439 }
1440
1441 return (i);
1442}
1443
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001444static struct alias **hashalias(const char *p)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001445{
Eric Andersencb57d552001-06-28 07:25:16 +00001446 unsigned int hashval;
1447
1448 hashval = *p << 4;
1449 while (*p)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001450 hashval += *p++;
Eric Andersencb57d552001-06-28 07:25:16 +00001451 return &atab[hashval % ATABSIZE];
1452}
1453
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001454static struct alias *freealias(struct alias *ap)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001455{
Eric Andersencb57d552001-06-28 07:25:16 +00001456 struct alias *next;
1457
1458 if (ap->flag & ALIASINUSE) {
1459 ap->flag |= ALIASDEAD;
1460 return ap;
1461 }
1462
1463 next = ap->next;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00001464 free(ap->name);
1465 free(ap->val);
1466 free(ap);
Eric Andersencb57d552001-06-28 07:25:16 +00001467 return next;
1468}
1469
Eric Andersencb57d552001-06-28 07:25:16 +00001470
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001471static struct alias **__lookupalias(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001472{
Eric Andersencb57d552001-06-28 07:25:16 +00001473 struct alias **app = hashalias(name);
1474
1475 for (; *app; app = &(*app)->next) {
1476 if (equal(name, (*app)->name)) {
1477 break;
1478 }
1479 }
1480
1481 return app;
1482}
Eric Andersen2870d962001-07-02 17:27:21 +00001483#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001484
Eric Andersend35c5df2002-01-09 15:37:36 +00001485#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersen74bcd162001-07-30 21:41:37 +00001486/* The generated file arith.c has been replaced with a custom hand
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001487 * written implementation written by Aaron Lehmann <aaronl@vitelus.com>.
1488 * This is now part of libbb, so that it can be used by all the shells
Eric Andersen74bcd162001-07-30 21:41:37 +00001489 * in busybox. */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001490static void expari(int);
Eric Andersencb57d552001-06-28 07:25:16 +00001491#endif
1492
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001493static char *trap[NSIG]; /* trap handler commands */
1494static char sigmode[NSIG - 1]; /* current value of signal */
1495static char gotsig[NSIG - 1]; /* indicates specified signal received */
1496static int pendingsigs; /* indicates some signal received */
Eric Andersen2870d962001-07-02 17:27:21 +00001497
Eric Andersencb57d552001-06-28 07:25:16 +00001498/*
1499 * This file was generated by the mkbuiltins program.
1500 */
1501
Eric Andersend35c5df2002-01-09 15:37:36 +00001502#ifdef CONFIG_ASH_JOB_CONTROL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001503static int bgcmd(int, char **);
1504static int fgcmd(int, char **);
1505static int killcmd(int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001506#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001507static int bltincmd(int, char **);
1508static int cdcmd(int, char **);
1509static int breakcmd(int, char **);
1510
Eric Andersend35c5df2002-01-09 15:37:36 +00001511#ifdef CONFIG_ASH_CMDCMD
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001512static int commandcmd(int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001513#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001514static int dotcmd(int, char **);
1515static int evalcmd(int, char **);
1516static int execcmd(int, char **);
1517static int exitcmd(int, char **);
1518static int exportcmd(int, char **);
1519static int histcmd(int, char **);
1520static int hashcmd(int, char **);
1521static int helpcmd(int, char **);
1522static int jobscmd(int, char **);
1523static int localcmd(int, char **);
1524static int pwdcmd(int, char **);
1525static int readcmd(int, char **);
1526static int returncmd(int, char **);
1527static int setcmd(int, char **);
1528static int setvarcmd(int, char **);
1529static int shiftcmd(int, char **);
1530static int trapcmd(int, char **);
1531static int umaskcmd(int, char **);
1532
Eric Andersend35c5df2002-01-09 15:37:36 +00001533#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001534static int aliascmd(int, char **);
1535static int unaliascmd(int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001536#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001537static int unsetcmd(int, char **);
1538static int waitcmd(int, char **);
1539static int ulimitcmd(int, char **);
1540static int timescmd(int, char **);
1541
Eric Andersend35c5df2002-01-09 15:37:36 +00001542#ifdef CONFIG_ASH_MATH_SUPPORT
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001543static int letcmd(int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001544#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001545static int typecmd(int, char **);
1546
Eric Andersend35c5df2002-01-09 15:37:36 +00001547#ifdef CONFIG_ASH_GETOPTS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001548static int getoptscmd(int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001549#endif
1550
Eric Andersen69a20f02001-10-31 10:40:37 +00001551#ifndef CONFIG_TRUE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001552static int true_main(int, char **);
Eric Andersen69a20f02001-10-31 10:40:37 +00001553#endif
1554#ifndef CONFIG_FALSE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001555static int false_main(int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001556#endif
1557
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001558static void setpwd(const char *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00001559
1560
1561#define BUILTIN_NOSPEC "0"
1562#define BUILTIN_SPECIAL "1"
1563#define BUILTIN_REGULAR "2"
1564#define BUILTIN_ASSIGN "4"
1565#define BUILTIN_SPEC_ASSG "5"
1566#define BUILTIN_REG_ASSG "6"
1567
1568#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1569#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1570#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
1571
1572struct builtincmd {
1573 const char *name;
1574 int (*const builtinfunc) (int, char **);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00001575 //unsigned flags;
Eric Andersen2870d962001-07-02 17:27:21 +00001576};
1577
Eric Andersencb57d552001-06-28 07:25:16 +00001578
1579/* It is CRUCIAL that this listing be kept in ascii order, otherwise
1580 * the binary search in find_builtin() will stop working. If you value
1581 * your kneecaps, you'll be sure to *make sure* that any changes made
1582 * to this array result in the listing remaining in ascii order. You
1583 * have been warned.
1584 */
1585static const struct builtincmd builtincmds[] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001586 {BUILTIN_SPECIAL ".", dotcmd}, /* first, see declare DOTCMD */
1587 {BUILTIN_SPECIAL ":", true_main},
Eric Andersend35c5df2002-01-09 15:37:36 +00001588#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001589 {BUILTIN_REG_ASSG "alias", aliascmd},
Eric Andersencb57d552001-06-28 07:25:16 +00001590#endif
Eric Andersend35c5df2002-01-09 15:37:36 +00001591#ifdef CONFIG_ASH_JOB_CONTROL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001592 {BUILTIN_REGULAR "bg", bgcmd},
Eric Andersen2870d962001-07-02 17:27:21 +00001593#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001594 {BUILTIN_SPECIAL "break", breakcmd},
1595 {BUILTIN_SPECIAL "builtin", bltincmd},
1596 {BUILTIN_REGULAR "cd", cdcmd},
1597 {BUILTIN_NOSPEC "chdir", cdcmd},
Eric Andersend35c5df2002-01-09 15:37:36 +00001598#ifdef CONFIG_ASH_CMDCMD
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001599 {BUILTIN_REGULAR "command", commandcmd},
Eric Andersen2870d962001-07-02 17:27:21 +00001600#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001601 {BUILTIN_SPECIAL "continue", breakcmd},
1602 {BUILTIN_SPECIAL "eval", evalcmd},
1603 {BUILTIN_SPECIAL "exec", execcmd},
1604 {BUILTIN_SPECIAL "exit", exitcmd},
1605 {BUILTIN_SPEC_ASSG "export", exportcmd},
1606 {BUILTIN_REGULAR "false", false_main},
1607 {BUILTIN_REGULAR "fc", histcmd},
Eric Andersend35c5df2002-01-09 15:37:36 +00001608#ifdef CONFIG_ASH_JOB_CONTROL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001609 {BUILTIN_REGULAR "fg", fgcmd},
Eric Andersen2870d962001-07-02 17:27:21 +00001610#endif
Eric Andersend35c5df2002-01-09 15:37:36 +00001611#ifdef CONFIG_ASH_GETOPTS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001612 {BUILTIN_REGULAR "getopts", getoptscmd},
Eric Andersen2870d962001-07-02 17:27:21 +00001613#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001614 {BUILTIN_NOSPEC "hash", hashcmd},
1615 {BUILTIN_NOSPEC "help", helpcmd},
1616 {BUILTIN_REGULAR "jobs", jobscmd},
Eric Andersend35c5df2002-01-09 15:37:36 +00001617#ifdef CONFIG_ASH_JOB_CONTROL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001618 {BUILTIN_REGULAR "kill", killcmd},
Eric Andersen2870d962001-07-02 17:27:21 +00001619#endif
Eric Andersend35c5df2002-01-09 15:37:36 +00001620#ifdef CONFIG_ASH_MATH_SUPPORT
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001621 {BUILTIN_REGULAR "let", letcmd},
Eric Andersencb57d552001-06-28 07:25:16 +00001622#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001623 {BUILTIN_ASSIGN "local", localcmd},
1624 {BUILTIN_NOSPEC "pwd", pwdcmd},
1625 {BUILTIN_REGULAR "read", readcmd},
1626 {BUILTIN_SPEC_ASSG "readonly", exportcmd},
1627 {BUILTIN_SPECIAL "return", returncmd},
1628 {BUILTIN_SPECIAL "set", setcmd},
1629 {BUILTIN_NOSPEC "setvar", setvarcmd},
1630 {BUILTIN_SPECIAL "shift", shiftcmd},
1631 {BUILTIN_SPECIAL "times", timescmd},
1632 {BUILTIN_SPECIAL "trap", trapcmd},
1633 {BUILTIN_REGULAR "true", true_main},
1634 {BUILTIN_NOSPEC "type", typecmd},
1635 {BUILTIN_NOSPEC "ulimit", ulimitcmd},
1636 {BUILTIN_REGULAR "umask", umaskcmd},
Eric Andersend35c5df2002-01-09 15:37:36 +00001637#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001638 {BUILTIN_REGULAR "unalias", unaliascmd},
Eric Andersen2870d962001-07-02 17:27:21 +00001639#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001640 {BUILTIN_SPECIAL "unset", unsetcmd},
1641 {BUILTIN_REGULAR "wait", waitcmd},
Eric Andersencb57d552001-06-28 07:25:16 +00001642};
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001643
Eric Andersencb57d552001-06-28 07:25:16 +00001644#define NUMBUILTINS (sizeof (builtincmds) / sizeof (struct builtincmd) )
1645
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001646#define DOTCMD &builtincmds[0]
Eric Andersen2870d962001-07-02 17:27:21 +00001647static struct builtincmd *BLTINCMD;
1648static struct builtincmd *EXECCMD;
1649static struct builtincmd *EVALCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00001650
Eric Andersen2870d962001-07-02 17:27:21 +00001651/* states */
Glenn L McGrath50812ff2002-08-23 13:14:48 +00001652#define JOBSTOPPED 1 /* all procs are stopped */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001653#define JOBDONE 2 /* all procs are completed */
Eric Andersencb57d552001-06-28 07:25:16 +00001654
Eric Andersen2870d962001-07-02 17:27:21 +00001655/*
1656 * A job structure contains information about a job. A job is either a
1657 * single process or a set of processes contained in a pipeline. In the
1658 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1659 * array of pids.
1660 */
Eric Andersencb57d552001-06-28 07:25:16 +00001661
Eric Andersen2870d962001-07-02 17:27:21 +00001662struct procstat {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001663 pid_t pid; /* process id */
1664 int status; /* status flags (defined above) */
1665 char *cmd; /* text of command being run */
Eric Andersen2870d962001-07-02 17:27:21 +00001666};
Eric Andersencb57d552001-06-28 07:25:16 +00001667
Eric Andersen2870d962001-07-02 17:27:21 +00001668
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001669static int job_warning; /* user was warned about stopped jobs */
Eric Andersen2870d962001-07-02 17:27:21 +00001670
Eric Andersend35c5df2002-01-09 15:37:36 +00001671#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen2870d962001-07-02 17:27:21 +00001672static void setjobctl(int enable);
1673#else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001674#define setjobctl(on) /* do nothing */
Eric Andersencb57d552001-06-28 07:25:16 +00001675#endif
1676
Eric Andersen2870d962001-07-02 17:27:21 +00001677
1678struct job {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001679 struct procstat ps0; /* status of process */
1680 struct procstat *ps; /* status or processes when more than one */
1681 short nprocs; /* number of processes */
1682 short pgrp; /* process group of this job */
1683 char state; /* true if job is finished */
1684 char used; /* true if this entry is in used */
1685 char changed; /* true if status has changed */
Eric Andersend35c5df2002-01-09 15:37:36 +00001686#ifdef CONFIG_ASH_JOB_CONTROL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001687 char jobctl; /* job running under job control */
Eric Andersen2870d962001-07-02 17:27:21 +00001688#endif
1689};
1690
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001691static struct job *jobtab; /* array of jobs */
1692static int njobs; /* size of array */
1693static int backgndpid = -1; /* pid of last background process */
1694
Eric Andersend35c5df2002-01-09 15:37:36 +00001695#ifdef CONFIG_ASH_JOB_CONTROL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001696static int initialpgrp; /* pgrp of shell on invocation */
1697static int curjob; /* current job */
Eric Andersen2870d962001-07-02 17:27:21 +00001698static int jobctl;
1699#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001700
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001701static struct job *makejob(const union node *, int);
1702static int forkshell(struct job *, const union node *, int);
1703static int waitforjob(struct job *);
Eric Andersen2870d962001-07-02 17:27:21 +00001704
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001705static int docd(char *, int);
1706static void getpwd(void);
Eric Andersen2870d962001-07-02 17:27:21 +00001707
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001708static char *padvance(const char **, const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001709
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001710static char nullstr[1]; /* zero length string */
1711static char *curdir = nullstr; /* current working directory */
Eric Andersen2870d962001-07-02 17:27:21 +00001712
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001713static int cdcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001714{
1715 const char *dest;
1716 const char *path;
1717 char *p;
1718 struct stat statb;
1719 int print = 0;
1720
1721 nextopt(nullstr);
1722 if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME")) == NULL)
1723 error("HOME not set");
1724 if (*dest == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00001725 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001726 if (dest[0] == '-' && dest[1] == '\0') {
1727 dest = bltinlookup("OLDPWD");
1728 if (!dest || !*dest) {
1729 dest = curdir;
1730 }
1731 print = 1;
1732 if (dest)
Eric Andersen2870d962001-07-02 17:27:21 +00001733 print = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00001734 else
Eric Andersen2870d962001-07-02 17:27:21 +00001735 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001736 }
1737 if (*dest == '/' || (path = bltinlookup("CDPATH")) == NULL)
1738 path = nullstr;
1739 while ((p = padvance(&path, dest)) != NULL) {
1740 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
1741 if (!print) {
1742 /*
1743 * XXX - rethink
1744 */
1745 if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
1746 p += 2;
1747 print = strcmp(p, dest);
1748 }
1749 if (docd(p, print) >= 0)
1750 return 0;
1751
1752 }
1753 }
1754 error("can't cd to %s", dest);
1755 /* NOTREACHED */
1756}
1757
1758
1759/*
Glenn L McGrath50812ff2002-08-23 13:14:48 +00001760 * Update curdir (the name of the current directory) in response to a
1761 * cd command. We also call hashcd to let the routines in exec.c know
1762 * that the current directory has changed.
1763 */
1764
1765static void hashcd(void);
1766
1767static inline void updatepwd(const char *dir)
1768{
1769 hashcd(); /* update command hash table */
1770
1771 /*
1772 * If our argument is NULL, we don't know the current directory
1773 */
1774 if (dir == NULL || curdir == nullstr) {
1775 setpwd(0, 1);
1776 } else {
1777 setpwd(dir, 1);
1778 }
1779}
1780
1781/*
Eric Andersencb57d552001-06-28 07:25:16 +00001782 * Actually do the chdir. In an interactive shell, print the
1783 * directory name if "print" is nonzero.
1784 */
1785
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001786static int docd(char *dest, int print)
Eric Andersencb57d552001-06-28 07:25:16 +00001787{
Eric Andersencb57d552001-06-28 07:25:16 +00001788 TRACE(("docd(\"%s\", %d) called\n", dest, print));
Eric Andersencb57d552001-06-28 07:25:16 +00001789 INTOFF;
1790 if (chdir(dest) < 0) {
1791 INTON;
1792 return -1;
1793 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00001794 updatepwd(dest);
Eric Andersencb57d552001-06-28 07:25:16 +00001795 INTON;
1796 if (print && iflag)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001797 puts(curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00001798 return 0;
1799}
1800
1801
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001802static int pwdcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001803{
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001804 puts(curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00001805 return 0;
1806}
Eric Andersencb57d552001-06-28 07:25:16 +00001807
Eric Andersena3483db2001-10-24 08:01:06 +00001808/* Ask system the current directory */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001809static void getpwd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00001810{
Eric Andersen2870d962001-07-02 17:27:21 +00001811 curdir = xgetcwd(0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001812 if (curdir == 0)
Eric Andersen2870d962001-07-02 17:27:21 +00001813 curdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00001814}
1815
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001816static void setpwd(const char *val, int setold)
Eric Andersencb57d552001-06-28 07:25:16 +00001817{
Eric Andersena3483db2001-10-24 08:01:06 +00001818 char *cated = NULL;
1819
Eric Andersencb57d552001-06-28 07:25:16 +00001820 if (setold) {
1821 setvar("OLDPWD", curdir, VEXPORT);
1822 }
1823 INTOFF;
1824 if (curdir != nullstr) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001825 if (val != NULL && *val != '/')
Eric Andersena3483db2001-10-24 08:01:06 +00001826 val = cated = concat_path_file(curdir, val);
Eric Andersencb57d552001-06-28 07:25:16 +00001827 free(curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00001828 }
Eric Andersena3483db2001-10-24 08:01:06 +00001829 if (!val)
Eric Andersencb57d552001-06-28 07:25:16 +00001830 getpwd();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001831 else
Manuel Novoa III cad53642003-03-19 09:13:01 +00001832 curdir = bb_simplify_path(val);
Eric Andersen4b525ad2003-01-14 06:40:11 +00001833 if (cated)
1834 free(cated);
Eric Andersencb57d552001-06-28 07:25:16 +00001835 INTON;
1836 setvar("PWD", curdir, VEXPORT);
1837}
1838
Eric Andersencb57d552001-06-28 07:25:16 +00001839/*
1840 * Errors and exceptions.
1841 */
1842
1843/*
1844 * Code to handle exceptions in C.
1845 */
1846
Eric Andersen2870d962001-07-02 17:27:21 +00001847/*
1848 * We enclose jmp_buf in a structure so that we can declare pointers to
1849 * jump locations. The global variable handler contains the location to
1850 * jump to when an exception occurs, and the global variable exception
1851 * contains a code identifying the exeception. To implement nested
1852 * exception handlers, the user should save the value of handler on entry
1853 * to an inner scope, set handler to point to a jmploc structure for the
1854 * inner scope, and restore handler on exit from the scope.
1855 */
1856
1857struct jmploc {
1858 jmp_buf loc;
1859};
1860
1861/* exceptions */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001862#define EXINT 0 /* SIGINT received */
1863#define EXERROR 1 /* a generic error */
1864#define EXSHELLPROC 2 /* execute a shell procedure */
1865#define EXEXEC 3 /* command execution failed */
Glenn L McGrath50812ff2002-08-23 13:14:48 +00001866#define EXREDIR 4 /* redirection error */
Eric Andersen2870d962001-07-02 17:27:21 +00001867
1868static struct jmploc *handler;
Eric Andersencb57d552001-06-28 07:25:16 +00001869static int exception;
Eric Andersencb57d552001-06-28 07:25:16 +00001870
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001871static void exverror(int, const char *, va_list)
1872 __attribute__ ((__noreturn__));
Eric Andersencb57d552001-06-28 07:25:16 +00001873
1874/*
1875 * Called to raise an exception. Since C doesn't include exceptions, we
1876 * just do a longjmp to the exception handler. The type of exception is
1877 * stored in the global variable "exception".
1878 */
1879
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001880static void exraise(int) __attribute__ ((__noreturn__));
Eric Andersen2870d962001-07-02 17:27:21 +00001881
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001882static void exraise(int e)
Eric Andersencb57d552001-06-28 07:25:16 +00001883{
1884#ifdef DEBUG
1885 if (handler == NULL)
1886 abort();
1887#endif
Eric Andersen62483552001-07-10 06:09:16 +00001888 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00001889 exception = e;
1890 longjmp(handler->loc, 1);
1891}
1892
1893
1894/*
1895 * Called from trap.c when a SIGINT is received. (If the user specifies
1896 * that SIGINT is to be trapped or ignored using the trap builtin, then
1897 * this routine is not called.) Suppressint is nonzero when interrupts
1898 * are held using the INTOFF macro. The call to _exit is necessary because
1899 * there is a short period after a fork before the signal handlers are
1900 * set to the appropriate value for the child. (The test for iflag is
1901 * just defensive programming.)
1902 */
1903
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001904static void onint(void)
1905{
Eric Andersencb57d552001-06-28 07:25:16 +00001906 sigset_t mysigset;
1907
1908 if (suppressint) {
1909 intpending++;
1910 return;
1911 }
1912 intpending = 0;
1913 sigemptyset(&mysigset);
1914 sigprocmask(SIG_SETMASK, &mysigset, NULL);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00001915 if (!(rootshell && iflag)) {
Eric Andersencb57d552001-06-28 07:25:16 +00001916 signal(SIGINT, SIG_DFL);
1917 raise(SIGINT);
1918 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00001919 exraise(EXINT);
Eric Andersencb57d552001-06-28 07:25:16 +00001920 /* NOTREACHED */
1921}
1922
1923
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001924static char *commandname; /* currently executing command */
Eric Andersen2870d962001-07-02 17:27:21 +00001925
Eric Andersencb57d552001-06-28 07:25:16 +00001926/*
1927 * Exverror is called to raise the error exception. If the first argument
1928 * is not NULL then error prints an error message using printf style
1929 * formatting. It then raises the error exception.
1930 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001931static void exverror(int cond, const char *msg, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00001932{
1933 CLEAR_PENDING_INT;
1934 INTOFF;
1935
1936#ifdef DEBUG
1937 if (msg)
1938 TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
1939 else
1940 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
1941#endif
1942 if (msg) {
1943 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +00001944 out2fmt("%s: ", commandname);
1945 vfprintf(stderr, msg, ap);
1946 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00001947 }
Eric Andersencb57d552001-06-28 07:25:16 +00001948 exraise(cond);
1949 /* NOTREACHED */
1950}
1951
1952
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001953static void error(const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00001954{
Eric Andersencb57d552001-06-28 07:25:16 +00001955 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001956
Eric Andersencb57d552001-06-28 07:25:16 +00001957 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00001958 exverror(EXERROR, msg, ap);
1959 /* NOTREACHED */
1960 va_end(ap);
1961}
1962
1963
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001964static void exerror(int cond, const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00001965{
Eric Andersencb57d552001-06-28 07:25:16 +00001966 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001967
Eric Andersencb57d552001-06-28 07:25:16 +00001968 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00001969 exverror(cond, msg, ap);
1970 /* NOTREACHED */
1971 va_end(ap);
1972}
1973
1974
1975
1976/*
1977 * Table of error messages.
1978 */
1979
1980struct errname {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001981 short errcode; /* error number */
1982 short action; /* operation which encountered the error */
Eric Andersencb57d552001-06-28 07:25:16 +00001983};
1984
Eric Andersen2870d962001-07-02 17:27:21 +00001985/*
1986 * Types of operations (passed to the errmsg routine).
1987 */
1988
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001989#define E_OPEN 01 /* opening a file */
1990#define E_CREAT 02 /* creating a file */
1991#define E_EXEC 04 /* executing a program */
Eric Andersencb57d552001-06-28 07:25:16 +00001992
1993#define ALL (E_OPEN|E_CREAT|E_EXEC)
1994
1995static const struct errname errormsg[] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001996 {EINTR, ALL},
1997 {EACCES, ALL},
1998 {EIO, ALL},
1999 {ENOENT, E_OPEN},
2000 {ENOENT, E_CREAT},
2001 {ENOENT, E_EXEC},
2002 {ENOTDIR, E_OPEN},
2003 {ENOTDIR, E_CREAT},
2004 {ENOTDIR, E_EXEC},
2005 {EISDIR, ALL},
2006 {EEXIST, E_CREAT},
Eric Andersen2870d962001-07-02 17:27:21 +00002007#ifdef EMFILE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002008 {EMFILE, ALL},
Eric Andersencb57d552001-06-28 07:25:16 +00002009#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002010 {ENFILE, ALL},
2011 {ENOSPC, ALL},
Eric Andersencb57d552001-06-28 07:25:16 +00002012#ifdef EDQUOT
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002013 {EDQUOT, ALL},
Eric Andersencb57d552001-06-28 07:25:16 +00002014#endif
2015#ifdef ENOSR
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002016 {ENOSR, ALL},
Eric Andersencb57d552001-06-28 07:25:16 +00002017#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002018 {ENXIO, ALL},
2019 {EROFS, ALL},
2020 {ETXTBSY, ALL},
Eric Andersen2870d962001-07-02 17:27:21 +00002021#ifdef EAGAIN
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002022 {EAGAIN, E_EXEC},
Eric Andersencb57d552001-06-28 07:25:16 +00002023#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002024 {ENOMEM, ALL},
Eric Andersencb57d552001-06-28 07:25:16 +00002025#ifdef ENOLINK
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002026 {ENOLINK, ALL},
Eric Andersencb57d552001-06-28 07:25:16 +00002027#endif
2028#ifdef EMULTIHOP
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002029 {EMULTIHOP, ALL},
Eric Andersencb57d552001-06-28 07:25:16 +00002030#endif
2031#ifdef ECOMM
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002032 {ECOMM, ALL},
Eric Andersencb57d552001-06-28 07:25:16 +00002033#endif
2034#ifdef ESTALE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002035 {ESTALE, ALL},
Eric Andersencb57d552001-06-28 07:25:16 +00002036#endif
2037#ifdef ETIMEDOUT
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002038 {ETIMEDOUT, ALL},
Eric Andersencb57d552001-06-28 07:25:16 +00002039#endif
2040#ifdef ELOOP
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002041 {ELOOP, ALL},
Eric Andersencb57d552001-06-28 07:25:16 +00002042#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002043 {E2BIG, E_EXEC},
Eric Andersencb57d552001-06-28 07:25:16 +00002044#ifdef ELIBACC
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002045 {ELIBACC, E_EXEC},
Eric Andersencb57d552001-06-28 07:25:16 +00002046#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002047};
2048
Eric Andersen2870d962001-07-02 17:27:21 +00002049#define ERRNAME_SIZE (sizeof(errormsg)/sizeof(struct errname))
Eric Andersencb57d552001-06-28 07:25:16 +00002050
2051/*
2052 * Return a string describing an error. The returned string may be a
2053 * pointer to a static buffer that will be overwritten on the next call.
2054 * Action describes the operation that got the error.
2055 */
2056
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002057static const char *errmsg(int e, int action)
Eric Andersencb57d552001-06-28 07:25:16 +00002058{
2059 struct errname const *ep;
2060 static char buf[12];
2061
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002062 for (ep = errormsg; ep < errormsg + ERRNAME_SIZE; ep++) {
Eric Andersencb57d552001-06-28 07:25:16 +00002063 if (ep->errcode == e && (ep->action & action) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00002064 return strerror(e);
Eric Andersencb57d552001-06-28 07:25:16 +00002065 }
Eric Andersen2870d962001-07-02 17:27:21 +00002066
Eric Andersen3102ac42001-07-06 04:26:23 +00002067 snprintf(buf, sizeof buf, "error %d", e);
Eric Andersencb57d552001-06-28 07:25:16 +00002068 return buf;
2069}
2070
2071
Eric Andersend35c5df2002-01-09 15:37:36 +00002072#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002073static void __inton()
2074{
Eric Andersencb57d552001-06-28 07:25:16 +00002075 if (--suppressint == 0 && intpending) {
2076 onint();
2077 }
2078}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002079static void forceinton(void)
2080{
Eric Andersen3102ac42001-07-06 04:26:23 +00002081 suppressint = 0;
2082 if (intpending)
2083 onint();
2084}
Eric Andersencb57d552001-06-28 07:25:16 +00002085#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002086
2087/* flags in argument to evaltree */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002088#define EV_EXIT 01 /* exit after evaluating tree */
2089#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2090#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00002091
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002092static int evalskip; /* set if we are skipping commands */
2093static int skipcount; /* number of levels to skip */
2094static int loopnest; /* current loop nesting level */
2095static int funcnest; /* depth of function calls */
Eric Andersencb57d552001-06-28 07:25:16 +00002096
2097
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002098static struct strlist *cmdenviron; /* environment for builtin command */
2099static int exitstatus; /* exit status of last command */
2100static int oexitstatus; /* saved exit status */
Eric Andersencb57d552001-06-28 07:25:16 +00002101
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002102static void evalsubshell(const union node *, int);
2103static void expredir(union node *);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002104static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002105static void eprintlist(struct strlist *);
Eric Andersencb57d552001-06-28 07:25:16 +00002106
Eric Andersen2870d962001-07-02 17:27:21 +00002107static union node *parsecmd(int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002108
Eric Andersencb57d552001-06-28 07:25:16 +00002109/*
2110 * Called to reset things after an exception.
2111 */
2112
Eric Andersencb57d552001-06-28 07:25:16 +00002113/*
2114 * The eval commmand.
2115 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002116static void evalstring(char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00002117
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002118static int evalcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002119{
Eric Andersen2870d962001-07-02 17:27:21 +00002120 char *p;
2121 char *concat;
2122 char **ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002123
Eric Andersen2870d962001-07-02 17:27:21 +00002124 if (argc > 1) {
2125 p = argv[1];
2126 if (argc > 2) {
2127 STARTSTACKSTR(concat);
2128 ap = argv + 2;
2129 for (;;) {
2130 while (*p)
2131 STPUTC(*p++, concat);
2132 if ((p = *ap++) == NULL)
2133 break;
2134 STPUTC(' ', concat);
2135 }
2136 STPUTC('\0', concat);
2137 p = grabstackstr(concat);
2138 }
2139 evalstring(p, EV_TESTED);
2140 }
2141 return exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002142}
2143
Eric Andersencb57d552001-06-28 07:25:16 +00002144/*
2145 * Execute a command or commands contained in a string.
2146 */
2147
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002148static void evaltree(union node *, int);
2149static void setinputstring(char *);
2150static void popfile(void);
Eric Andersen2870d962001-07-02 17:27:21 +00002151static void setstackmark(struct stackmark *mark);
2152static void popstackmark(struct stackmark *mark);
2153
2154
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002155static void evalstring(char *s, int flag)
Eric Andersen2870d962001-07-02 17:27:21 +00002156{
Eric Andersencb57d552001-06-28 07:25:16 +00002157 union node *n;
2158 struct stackmark smark;
2159
2160 setstackmark(&smark);
2161 setinputstring(s);
2162 while ((n = parsecmd(0)) != NEOF) {
2163 evaltree(n, flag);
2164 popstackmark(&smark);
2165 }
2166 popfile();
2167 popstackmark(&smark);
2168}
2169
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002170static struct builtincmd *find_builtin(const char *);
2171static void expandarg(union node *, struct arglist *, int);
2172static void calcsize(const union node *);
2173static union node *copynode(const union node *);
Eric Andersen62483552001-07-10 06:09:16 +00002174
2175/*
2176 * Make a copy of a parse tree.
2177 */
2178
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002179static int funcblocksize; /* size of structures in function */
2180static int funcstringsize; /* size of strings in node */
2181static pointer funcblock; /* block to allocate function from */
2182static char *funcstring; /* block to allocate strings from */
Eric Andersen62483552001-07-10 06:09:16 +00002183
2184
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002185static inline union node *copyfunc(union node *n)
Eric Andersen62483552001-07-10 06:09:16 +00002186{
2187 if (n == NULL)
2188 return NULL;
2189 funcblocksize = 0;
2190 funcstringsize = 0;
2191 calcsize(n);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00002192 funcblock = xmalloc(funcblocksize + funcstringsize);
Eric Andersen62483552001-07-10 06:09:16 +00002193 funcstring = (char *) funcblock + funcblocksize;
2194 return copynode(n);
2195}
2196
2197/*
Eric Andersen62483552001-07-10 06:09:16 +00002198 * Add a new command entry, replacing any existing command entry for
2199 * the same name.
2200 */
2201
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002202static inline void addcmdentry(char *name, struct cmdentry *entry)
Eric Andersen62483552001-07-10 06:09:16 +00002203{
2204 struct tblentry *cmdp;
2205
2206 INTOFF;
2207 cmdp = cmdlookup(name, 1);
2208 if (cmdp->cmdtype == CMDFUNCTION) {
Aaron Lehmann49c024a2002-08-02 06:39:47 +00002209 free(cmdp->param.func);
Eric Andersen62483552001-07-10 06:09:16 +00002210 }
2211 cmdp->cmdtype = entry->cmdtype;
2212 cmdp->param = entry->u;
2213 INTON;
2214}
2215
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002216static inline void evalloop(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002217{
2218 int status;
2219
2220 loopnest++;
2221 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002222 flags &= EV_TESTED;
Eric Andersencb57d552001-06-28 07:25:16 +00002223 for (;;) {
2224 evaltree(n->nbinary.ch1, EV_TESTED);
2225 if (evalskip) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002226 skipping:if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002227 evalskip = 0;
2228 continue;
2229 }
2230 if (evalskip == SKIPBREAK && --skipcount <= 0)
2231 evalskip = 0;
2232 break;
2233 }
2234 if (n->type == NWHILE) {
2235 if (exitstatus != 0)
2236 break;
2237 } else {
2238 if (exitstatus == 0)
2239 break;
2240 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002241 evaltree(n->nbinary.ch2, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002242 status = exitstatus;
2243 if (evalskip)
2244 goto skipping;
2245 }
2246 loopnest--;
2247 exitstatus = status;
2248}
2249
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002250static void evalfor(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002251{
2252 struct arglist arglist;
2253 union node *argp;
2254 struct strlist *sp;
2255 struct stackmark smark;
2256
2257 setstackmark(&smark);
2258 arglist.lastp = &arglist.list;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002259 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002260 oexitstatus = exitstatus;
2261 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2262 if (evalskip)
2263 goto out;
2264 }
2265 *arglist.lastp = NULL;
2266
2267 exitstatus = 0;
2268 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002269 flags &= EV_TESTED;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002270 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002271 setvar(n->nfor.var, sp->text, 0);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002272 evaltree(n->nfor.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002273 if (evalskip) {
2274 if (evalskip == SKIPCONT && --skipcount <= 0) {
2275 evalskip = 0;
2276 continue;
2277 }
2278 if (evalskip == SKIPBREAK && --skipcount <= 0)
2279 evalskip = 0;
2280 break;
2281 }
2282 }
2283 loopnest--;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002284 out:
Eric Andersencb57d552001-06-28 07:25:16 +00002285 popstackmark(&smark);
2286}
2287
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002288static inline void evalcase(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002289{
2290 union node *cp;
2291 union node *patp;
2292 struct arglist arglist;
2293 struct stackmark smark;
2294
2295 setstackmark(&smark);
2296 arglist.lastp = &arglist.list;
2297 oexitstatus = exitstatus;
2298 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002299 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
2300 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002301 if (casematch(patp, arglist.list->text)) {
2302 if (evalskip == 0) {
2303 evaltree(cp->nclist.body, flags);
2304 }
2305 goto out;
2306 }
2307 }
2308 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002309 out:
Eric Andersencb57d552001-06-28 07:25:16 +00002310 popstackmark(&smark);
2311}
2312
Eric Andersencb57d552001-06-28 07:25:16 +00002313/*
Eric Andersencb57d552001-06-28 07:25:16 +00002314 * Evaluate a pipeline. All the processes in the pipeline are children
2315 * of the process creating the pipeline. (This differs from some versions
2316 * of the shell, which make the last process in a pipeline the parent
2317 * of all the rest.)
2318 */
2319
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002320static inline void evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002321{
2322 struct job *jp;
2323 struct nodelist *lp;
2324 int pipelen;
2325 int prevfd;
2326 int pip[2];
2327
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002328 TRACE(("evalpipe(0x%lx) called\n", (long) n));
Eric Andersencb57d552001-06-28 07:25:16 +00002329 pipelen = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002330 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00002331 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002332 flags |= EV_EXIT;
Eric Andersencb57d552001-06-28 07:25:16 +00002333 INTOFF;
2334 jp = makejob(n, pipelen);
2335 prevfd = -1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002336 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002337 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00002338 pip[1] = -1;
2339 if (lp->next) {
2340 if (pipe(pip) < 0) {
2341 close(prevfd);
2342 error("Pipe call failed");
2343 }
2344 }
2345 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
2346 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00002347 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002348 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00002349 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002350 if (prevfd > 0) {
2351 dup2(prevfd, 0);
2352 close(prevfd);
2353 }
2354 if (pip[1] > 1) {
2355 dup2(pip[1], 1);
2356 close(pip[1]);
2357 }
2358 evaltree(lp->n, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002359 }
2360 if (prevfd >= 0)
2361 close(prevfd);
2362 prevfd = pip[0];
2363 close(pip[1]);
2364 }
Eric Andersencb57d552001-06-28 07:25:16 +00002365 if (n->npipe.backgnd == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002366 exitstatus = waitforjob(jp);
2367 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
Eric Andersencb57d552001-06-28 07:25:16 +00002368 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002369 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00002370}
2371
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002372static void find_command(const char *, struct cmdentry *, int, const char *);
2373
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002374static int isassignment(const char *word)
2375{
Eric Andersen2870d962001-07-02 17:27:21 +00002376 if (!is_name(*word)) {
2377 return 0;
2378 }
2379 do {
2380 word++;
2381 } while (is_in_name(*word));
2382 return *word == '=';
2383}
2384
Eric Andersen62483552001-07-10 06:09:16 +00002385
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002386static void evalcommand(union node *cmd, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002387{
2388 struct stackmark smark;
2389 union node *argp;
2390 struct arglist arglist;
2391 struct arglist varlist;
2392 char **argv;
2393 int argc;
2394 char **envp;
2395 struct strlist *sp;
2396 int mode;
Eric Andersencb57d552001-06-28 07:25:16 +00002397 struct cmdentry cmdentry;
2398 struct job *jp;
2399 char *volatile savecmdname;
2400 volatile struct shparam saveparam;
2401 struct localvar *volatile savelocalvars;
2402 volatile int e;
2403 char *lastarg;
2404 const char *path;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002405 int spclbltin;
Eric Andersencb57d552001-06-28 07:25:16 +00002406 struct jmploc *volatile savehandler;
2407 struct jmploc jmploc;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002408
Eric Andersencb57d552001-06-28 07:25:16 +00002409#if __GNUC__
2410 /* Avoid longjmp clobbering */
2411 (void) &argv;
2412 (void) &argc;
2413 (void) &lastarg;
2414 (void) &flags;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002415 (void) &spclbltin;
Eric Andersencb57d552001-06-28 07:25:16 +00002416#endif
2417
2418 /* First expand the arguments. */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002419 TRACE(("evalcommand(0x%lx, %d) called\n", (long) cmd, flags));
Eric Andersencb57d552001-06-28 07:25:16 +00002420 setstackmark(&smark);
2421 arglist.lastp = &arglist.list;
2422 varlist.lastp = &varlist.list;
2423 arglist.list = 0;
2424 oexitstatus = exitstatus;
2425 exitstatus = 0;
2426 path = pathval();
2427 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
2428 expandarg(argp, &varlist, EXP_VARTILDE);
2429 }
Eric Andersen1887b042002-10-22 11:58:59 +00002430 for (argp = cmd->ncmd.args; argp && !arglist.list; argp = argp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002431 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2432 }
Eric Andersen1887b042002-10-22 11:58:59 +00002433 if (argp) {
2434 struct builtincmd *bcmd;
2435 int pseudovarflag;
2436
2437 bcmd = find_builtin(arglist.list->text);
2438 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
2439 for (; argp; argp = argp->narg.next) {
2440 if (pseudovarflag && isassignment(argp->narg.text)) {
2441 expandarg(argp, &arglist, EXP_VARTILDE);
2442 continue;
2443 }
2444 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2445 }
2446 }
Eric Andersencb57d552001-06-28 07:25:16 +00002447 *arglist.lastp = NULL;
2448 *varlist.lastp = NULL;
2449 expredir(cmd->ncmd.redirect);
2450 argc = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002451 for (sp = arglist.list; sp; sp = sp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00002452 argc++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002453 argv = stalloc(sizeof(char *) * (argc + 1));
Eric Andersencb57d552001-06-28 07:25:16 +00002454
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002455 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002456 TRACE(("evalcommand arg: %s\n", sp->text));
2457 *argv++ = sp->text;
2458 }
2459 *argv = NULL;
2460 lastarg = NULL;
2461 if (iflag && funcnest == 0 && argc > 0)
2462 lastarg = argv[-1];
2463 argv -= argc;
2464
2465 /* Print the command if xflag is set. */
2466 if (xflag) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002467 out2c('+');
Eric Andersencb57d552001-06-28 07:25:16 +00002468 eprintlist(varlist.list);
2469 eprintlist(arglist.list);
Eric Andersen3102ac42001-07-06 04:26:23 +00002470 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00002471 }
2472
2473 /* Now locate the command. */
2474 if (argc == 0) {
2475 cmdentry.cmdtype = CMDBUILTIN;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002476 cmdentry.u.cmd = BLTINCMD;
2477 spclbltin = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00002478 } else {
2479 const char *oldpath;
2480 int findflag = DO_ERR;
2481 int oldfindflag;
2482
2483 /*
2484 * Modify the command lookup path, if a PATH= assignment
2485 * is present
2486 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002487 for (sp = varlist.list; sp; sp = sp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00002488 if (varequal(sp->text, defpathvar)) {
2489 path = sp->text + 5;
2490 findflag |= DO_BRUTE;
2491 }
2492 oldpath = path;
2493 oldfindflag = findflag;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002494 spclbltin = -1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002495 for (;;) {
Eric Andersencb57d552001-06-28 07:25:16 +00002496 find_command(argv[0], &cmdentry, findflag, path);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002497 if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */
Eric Andersencb57d552001-06-28 07:25:16 +00002498 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002499 goto out;
2500 }
2501 /* implement bltin and command here */
2502 if (cmdentry.cmdtype != CMDBUILTIN) {
2503 break;
2504 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002505 if (spclbltin < 0) {
2506 spclbltin = !!(IS_BUILTIN_SPECIAL(cmdentry.u.cmd)) * 2;
Eric Andersencb57d552001-06-28 07:25:16 +00002507 }
2508 if (cmdentry.u.cmd == BLTINCMD) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002509 for (;;) {
Eric Andersencb57d552001-06-28 07:25:16 +00002510 struct builtincmd *bcmd;
2511
2512 argv++;
2513 if (--argc == 0)
2514 goto found;
2515 if (!(bcmd = find_builtin(*argv))) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002516 out2fmt("%s: not found\n", *argv);
Eric Andersencb57d552001-06-28 07:25:16 +00002517 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002518 goto out;
2519 }
2520 cmdentry.u.cmd = bcmd;
2521 if (bcmd != BLTINCMD)
2522 break;
2523 }
2524 }
Eric Andersen2870d962001-07-02 17:27:21 +00002525 if (cmdentry.u.cmd == find_builtin("command")) {
Eric Andersencb57d552001-06-28 07:25:16 +00002526 argv++;
2527 if (--argc == 0) {
2528 goto found;
2529 }
2530 if (*argv[0] == '-') {
2531 if (!equal(argv[0], "-p")) {
2532 argv--;
2533 argc++;
2534 break;
2535 }
2536 argv++;
2537 if (--argc == 0) {
2538 goto found;
2539 }
2540 path = defpath;
2541 findflag |= DO_BRUTE;
2542 } else {
2543 path = oldpath;
2544 findflag = oldfindflag;
2545 }
2546 findflag |= DO_NOFUN;
2547 continue;
2548 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002549 found:
Eric Andersencb57d552001-06-28 07:25:16 +00002550 break;
2551 }
2552 }
2553
2554 /* Fork off a child process if necessary. */
2555 if (cmd->ncmd.backgnd
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002556 || (cmdentry.cmdtype == CMDNORMAL && (!(flags & EV_EXIT) || trap[0]))
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002557 ) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002558 INTOFF;
Eric Andersencb57d552001-06-28 07:25:16 +00002559 jp = makejob(cmd, 1);
2560 mode = cmd->ncmd.backgnd;
Eric Andersencb57d552001-06-28 07:25:16 +00002561 if (forkshell(jp, cmd, mode) != 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002562 goto parent; /* at end of routine */
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002563 FORCEINTON;
Eric Andersencb57d552001-06-28 07:25:16 +00002564 flags |= EV_EXIT;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002565 } else {
2566 flags &= ~EV_EXIT;
Eric Andersencb57d552001-06-28 07:25:16 +00002567 }
2568
2569 /* This is the child process if a fork occurred. */
2570 /* Execute the command. */
2571 if (cmdentry.cmdtype == CMDFUNCTION) {
2572#ifdef DEBUG
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002573 trputs("Shell function: ");
2574 trargs(argv);
Eric Andersencb57d552001-06-28 07:25:16 +00002575#endif
2576 exitstatus = oexitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002577 saveparam = shellparam;
2578 shellparam.malloc = 0;
2579 shellparam.nparam = argc - 1;
2580 shellparam.p = argv + 1;
2581 INTOFF;
2582 savelocalvars = localvars;
2583 localvars = NULL;
2584 INTON;
2585 if (setjmp(jmploc.loc)) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002586 if (exception == EXREDIR) {
2587 exitstatus = 2;
2588 goto funcdone;
Eric Andersencb57d552001-06-28 07:25:16 +00002589 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002590 saveparam.optind = shellparam.optind;
2591 saveparam.optoff = shellparam.optoff;
2592 freeparam(&shellparam);
2593 shellparam = saveparam;
Eric Andersencb57d552001-06-28 07:25:16 +00002594 poplocalvars();
2595 localvars = savelocalvars;
2596 handler = savehandler;
2597 longjmp(handler->loc, 1);
2598 }
2599 savehandler = handler;
2600 handler = &jmploc;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002601 redirect(cmd->ncmd.redirect, REDIR_PUSH);
2602 listsetvar(varlist.list);
Eric Andersencb57d552001-06-28 07:25:16 +00002603 funcnest++;
2604 evaltree(cmdentry.u.func, flags & EV_TESTED);
2605 funcnest--;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002606 funcdone:
Eric Andersencb57d552001-06-28 07:25:16 +00002607 INTOFF;
2608 poplocalvars();
2609 localvars = savelocalvars;
2610 saveparam.optind = shellparam.optind;
2611 saveparam.optoff = shellparam.optoff;
2612 freeparam(&shellparam);
2613 shellparam = saveparam;
2614 handler = savehandler;
2615 popredir();
2616 INTON;
2617 if (evalskip == SKIPFUNC) {
2618 evalskip = 0;
2619 skipcount = 0;
2620 }
Eric Andersencb57d552001-06-28 07:25:16 +00002621 } else if (cmdentry.cmdtype == CMDBUILTIN) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002622 int redir;
2623
Eric Andersencb57d552001-06-28 07:25:16 +00002624#ifdef DEBUG
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002625 trputs("builtin command: ");
2626 trargs(argv);
Eric Andersencb57d552001-06-28 07:25:16 +00002627#endif
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002628 redir = (cmdentry.u.cmd == EXECCMD) ? 0 : REDIR_PUSH;
Eric Andersencb57d552001-06-28 07:25:16 +00002629 savecmdname = commandname;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002630 if (spclbltin) {
Eric Andersencb57d552001-06-28 07:25:16 +00002631 listsetvar(varlist.list);
2632 } else {
2633 cmdenviron = varlist.list;
2634 }
2635 e = -1;
2636 if (setjmp(jmploc.loc)) {
2637 e = exception;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002638 exitstatus = (e == EXINT) ? SIGINT + 128 : 2;
Eric Andersencb57d552001-06-28 07:25:16 +00002639 goto cmddone;
2640 }
2641 savehandler = handler;
2642 handler = &jmploc;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002643 redirect(cmd->ncmd.redirect, redir);
Eric Andersencb57d552001-06-28 07:25:16 +00002644 commandname = argv[0];
2645 argptr = argv + 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002646 optptr = NULL; /* initialize nextopt */
2647 exitstatus = (*cmdentry.u.cmd->builtinfunc) (argc, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00002648 flushall();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002649 cmddone:
Eric Andersencb57d552001-06-28 07:25:16 +00002650 cmdenviron = NULL;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002651 commandname = savecmdname;
Eric Andersencb57d552001-06-28 07:25:16 +00002652 handler = savehandler;
2653 if (e != -1) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002654 if (e == EXINT || spclbltin & 2) {
2655 if (e == EXREDIR)
2656 exraise(e);
2657 }
Eric Andersencb57d552001-06-28 07:25:16 +00002658 FORCEINTON;
2659 }
2660 if (cmdentry.u.cmd != EXECCMD)
2661 popredir();
Eric Andersencb57d552001-06-28 07:25:16 +00002662 } else {
2663#ifdef DEBUG
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002664 trputs("normal command: ");
2665 trargs(argv);
Eric Andersencb57d552001-06-28 07:25:16 +00002666#endif
2667 redirect(cmd->ncmd.redirect, 0);
2668 clearredir();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002669 for (sp = varlist.list; sp; sp = sp->next)
2670 setvareq(sp->text, VEXPORT | VSTACK);
Eric Andersencb57d552001-06-28 07:25:16 +00002671 envp = environment();
2672 shellexec(argv, envp, path, cmdentry.u.index);
2673 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002674 if (flags & EV_EXIT)
2675 exitshell(exitstatus);
Eric Andersencb57d552001-06-28 07:25:16 +00002676 goto out;
2677
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002678 parent: /* parent process gets here (if we forked) */
2679 if (mode == 0) { /* argument to fork */
Eric Andersencb57d552001-06-28 07:25:16 +00002680 exitstatus = waitforjob(jp);
Eric Andersencb57d552001-06-28 07:25:16 +00002681 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002682 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00002683
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002684 out:
Eric Andersencb57d552001-06-28 07:25:16 +00002685 if (lastarg)
2686 setvar("_", lastarg, 0);
2687 popstackmark(&smark);
2688}
2689
Eric Andersen62483552001-07-10 06:09:16 +00002690/*
2691 * Evaluate a parse tree. The value is left in the global variable
2692 * exitstatus.
2693 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002694static void evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00002695{
2696 int checkexit = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002697
Eric Andersen62483552001-07-10 06:09:16 +00002698 if (n == NULL) {
2699 TRACE(("evaltree(NULL) called\n"));
2700 goto out;
2701 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002702 TRACE(("evaltree(0x%lx: %d) called\n", (long) n, n->type));
Eric Andersen62483552001-07-10 06:09:16 +00002703 switch (n->type) {
2704 case NSEMI:
2705 evaltree(n->nbinary.ch1, flags & EV_TESTED);
2706 if (evalskip)
2707 goto out;
2708 evaltree(n->nbinary.ch2, flags);
2709 break;
2710 case NAND:
2711 evaltree(n->nbinary.ch1, EV_TESTED);
2712 if (evalskip || exitstatus != 0)
2713 goto out;
2714 evaltree(n->nbinary.ch2, flags);
2715 break;
2716 case NOR:
2717 evaltree(n->nbinary.ch1, EV_TESTED);
2718 if (evalskip || exitstatus == 0)
2719 goto out;
2720 evaltree(n->nbinary.ch2, flags);
2721 break;
2722 case NREDIR:
2723 expredir(n->nredir.redirect);
2724 redirect(n->nredir.redirect, REDIR_PUSH);
2725 evaltree(n->nredir.n, flags);
2726 popredir();
2727 break;
2728 case NSUBSHELL:
2729 evalsubshell(n, flags);
2730 break;
2731 case NBACKGND:
2732 evalsubshell(n, flags);
2733 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002734 case NIF:{
Eric Andersen62483552001-07-10 06:09:16 +00002735 evaltree(n->nif.test, EV_TESTED);
2736 if (evalskip)
2737 goto out;
2738 if (exitstatus == 0)
2739 evaltree(n->nif.ifpart, flags);
2740 else if (n->nif.elsepart)
2741 evaltree(n->nif.elsepart, flags);
2742 else
2743 exitstatus = 0;
2744 break;
2745 }
2746 case NWHILE:
2747 case NUNTIL:
2748 evalloop(n, flags);
2749 break;
2750 case NFOR:
2751 evalfor(n, flags);
2752 break;
2753 case NCASE:
2754 evalcase(n, flags);
2755 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002756 case NDEFUN:{
Eric Andersen62483552001-07-10 06:09:16 +00002757 struct builtincmd *bcmd;
2758 struct cmdentry entry;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002759
2760 if ((bcmd = find_builtin(n->narg.text)) && IS_BUILTIN_SPECIAL(bcmd)
2761 ) {
Eric Andersen62483552001-07-10 06:09:16 +00002762 out2fmt("%s is a special built-in\n", n->narg.text);
2763 exitstatus = 1;
2764 break;
2765 }
2766 entry.cmdtype = CMDFUNCTION;
2767 entry.u.func = copyfunc(n->narg.next);
2768 addcmdentry(n->narg.text, &entry);
2769 exitstatus = 0;
2770 break;
2771 }
2772 case NNOT:
2773 evaltree(n->nnot.com, EV_TESTED);
2774 exitstatus = !exitstatus;
2775 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002776
Eric Andersen62483552001-07-10 06:09:16 +00002777 case NPIPE:
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002778 evalpipe(n, flags);
Eric Andersen62483552001-07-10 06:09:16 +00002779 checkexit = 1;
2780 break;
2781 case NCMD:
2782 evalcommand(n, flags);
2783 checkexit = 1;
2784 break;
2785#ifdef DEBUG
2786 default:
2787 printf("Node type = %d\n", n->type);
2788 break;
2789#endif
2790 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002791 out:
Eric Andersen62483552001-07-10 06:09:16 +00002792 if (pendingsigs)
2793 dotrap();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002794 if (flags & EV_EXIT ||
Eric Andersen62483552001-07-10 06:09:16 +00002795 (checkexit && eflag && exitstatus && !(flags & EV_TESTED))
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002796 )
Eric Andersen62483552001-07-10 06:09:16 +00002797 exitshell(exitstatus);
2798}
2799
2800/*
2801 * Kick off a subshell to evaluate a tree.
2802 */
2803
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002804static void evalsubshell(const union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00002805{
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002806 struct job *jp = 0;
Eric Andersen62483552001-07-10 06:09:16 +00002807 int backgnd = (n->type == NBACKGND);
2808
2809 expredir(n->nredir.redirect);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002810 if (!backgnd && flags & EV_EXIT && !trap[0])
2811 goto nofork;
2812 INTOFF;
Eric Andersen62483552001-07-10 06:09:16 +00002813 jp = makejob(n, 1);
2814 if (forkshell(jp, n, backgnd) == 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002815 INTON;
2816 flags |= EV_EXIT;
Eric Andersen62483552001-07-10 06:09:16 +00002817 if (backgnd)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002818 flags &= ~EV_TESTED;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002819 nofork:
Eric Andersen62483552001-07-10 06:09:16 +00002820 redirect(n->nredir.redirect, 0);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002821 evaltree(n->nredir.n, flags); /* never returns */
Eric Andersen62483552001-07-10 06:09:16 +00002822 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002823 if (!backgnd) {
Eric Andersen62483552001-07-10 06:09:16 +00002824 exitstatus = waitforjob(jp);
Eric Andersen62483552001-07-10 06:09:16 +00002825 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002826 INTON;
Eric Andersen62483552001-07-10 06:09:16 +00002827}
2828
2829/*
2830 * Compute the names of the files in a redirection list.
2831 */
2832
2833static void fixredir(union node *n, const char *text, int err);
2834
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002835static void expredir(union node *n)
Eric Andersen62483552001-07-10 06:09:16 +00002836{
2837 union node *redir;
2838
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002839 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersen62483552001-07-10 06:09:16 +00002840 struct arglist fn;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002841
Eric Andersen62483552001-07-10 06:09:16 +00002842 fn.lastp = &fn.list;
2843 oexitstatus = exitstatus;
2844 switch (redir->type) {
2845 case NFROMTO:
2846 case NFROM:
2847 case NTO:
2848 case NAPPEND:
2849 case NTOOV:
2850 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
2851 redir->nfile.expfname = fn.list->text;
2852 break;
2853 case NFROMFD:
2854 case NTOFD:
2855 if (redir->ndup.vname) {
2856 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
2857 fixredir(redir, fn.list->text, 1);
2858 }
2859 break;
2860 }
2861 }
2862}
2863
2864
2865/*
2866 * Execute a command inside back quotes. If it's a builtin command, we
2867 * want to save its output in a block obtained from malloc. Otherwise
2868 * we fork off a subprocess and get the output of the command via a pipe.
2869 * Should be called with interrupts off.
2870 */
2871
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002872static void evalbackcmd(union node *n, struct backcmd *result)
Eric Andersen62483552001-07-10 06:09:16 +00002873{
2874 int pip[2];
2875 struct job *jp;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002876 struct stackmark smark; /* unnecessary */
Eric Andersen62483552001-07-10 06:09:16 +00002877
2878 setstackmark(&smark);
2879 result->fd = -1;
2880 result->buf = NULL;
2881 result->nleft = 0;
2882 result->jp = NULL;
2883 if (n == NULL) {
2884 exitstatus = 0;
2885 goto out;
2886 }
2887 exitstatus = 0;
2888 if (pipe(pip) < 0)
2889 error("Pipe call failed");
2890 jp = makejob(n, 1);
2891 if (forkshell(jp, n, FORK_NOJOB) == 0) {
2892 FORCEINTON;
2893 close(pip[0]);
2894 if (pip[1] != 1) {
2895 close(1);
2896 dup_as_newfd(pip[1], 1);
2897 close(pip[1]);
2898 }
2899 eflag = 0;
2900 evaltree(n, EV_EXIT);
2901 }
2902 close(pip[1]);
2903 result->fd = pip[0];
2904 result->jp = jp;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002905 out:
Eric Andersen62483552001-07-10 06:09:16 +00002906 popstackmark(&smark);
2907 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002908 result->fd, result->buf, result->nleft, result->jp));
Eric Andersen62483552001-07-10 06:09:16 +00002909}
2910
2911
2912/*
2913 * Execute a simple command.
2914 */
Eric Andersencb57d552001-06-28 07:25:16 +00002915
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002916/*
2917 * Search for a command. This is called before we fork so that the
2918 * location of the command will be available in the parent as well as
2919 * the child. The check for "goodname" is an overly conservative
2920 * check that the name will not be subject to expansion.
2921 */
2922
2923static void prehash(union node *n)
2924{
2925 struct cmdentry entry;
2926
2927 if (n->type == NCMD && n->ncmd.args)
2928 if (goodname(n->ncmd.args->narg.text))
2929 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
2930}
2931
Eric Andersencb57d552001-06-28 07:25:16 +00002932
Eric Andersencb57d552001-06-28 07:25:16 +00002933/*
2934 * Builtin commands. Builtin commands whose functions are closely
2935 * tied to evaluation are implemented here.
2936 */
2937
2938/*
2939 * No command given, or a bltin command with no arguments. Set the
2940 * specified variables.
2941 */
2942
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002943int bltincmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002944{
2945 /*
2946 * Preserve exitstatus of a previous possible redirection
2947 * as POSIX mandates
2948 */
2949 return exitstatus;
2950}
2951
2952
2953/*
2954 * Handle break and continue commands. Break, continue, and return are
2955 * all handled by setting the evalskip flag. The evaluation routines
2956 * above all check this flag, and if it is set they start skipping
2957 * commands rather than executing them. The variable skipcount is
2958 * the number of loops to break/continue, or the number of function
2959 * levels to return. (The latter is always 1.) It should probably
2960 * be an error to break out of more loops than exist, but it isn't
2961 * in the standard shell so we don't make it one here.
2962 */
2963
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002964static int breakcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002965{
2966 int n = argc > 1 ? number(argv[1]) : 1;
2967
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00002968 if (n <= 0)
2969 error("Illegal number: %s", argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00002970 if (n > loopnest)
2971 n = loopnest;
2972 if (n > 0) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002973 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00002974 skipcount = n;
2975 }
2976 return 0;
2977}
2978
2979
2980/*
2981 * The return command.
2982 */
2983
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002984static int returncmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002985{
2986 int ret = argc > 1 ? number(argv[1]) : oexitstatus;
2987
2988 if (funcnest) {
2989 evalskip = SKIPFUNC;
2990 skipcount = 1;
2991 return ret;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002992 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00002993 /* Do what ksh does; skip the rest of the file */
2994 evalskip = SKIPFILE;
2995 skipcount = 1;
2996 return ret;
2997 }
2998}
2999
3000
Eric Andersen69a20f02001-10-31 10:40:37 +00003001#ifndef CONFIG_FALSE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003002static int false_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003003{
3004 return 1;
3005}
Eric Andersen69a20f02001-10-31 10:40:37 +00003006#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003007
Eric Andersen69a20f02001-10-31 10:40:37 +00003008#ifndef CONFIG_TRUE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003009static int true_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003010{
3011 return 0;
3012}
3013#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003014
3015/*
3016 * Controls whether the shell is interactive or not.
3017 */
3018
3019static void setsignal(int signo);
Eric Andersen2870d962001-07-02 17:27:21 +00003020
Eric Andersend35c5df2002-01-09 15:37:36 +00003021#ifdef CONFIG_ASH_MAIL
Eric Andersenec074692001-10-31 11:05:49 +00003022static void chkmail(int silent);
3023#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003024
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003025static void setinteractive(int on)
Eric Andersen2870d962001-07-02 17:27:21 +00003026{
3027 static int is_interactive;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003028 static int do_banner = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00003029
3030 if (on == is_interactive)
3031 return;
3032 setsignal(SIGINT);
3033 setsignal(SIGQUIT);
3034 setsignal(SIGTERM);
Eric Andersend35c5df2002-01-09 15:37:36 +00003035#ifdef CONFIG_ASH_MAIL
Eric Andersen2870d962001-07-02 17:27:21 +00003036 chkmail(1);
Eric Andersenec074692001-10-31 11:05:49 +00003037#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003038 is_interactive = on;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003039 if (do_banner == 0 && is_interactive) {
Eric Andersen1c039232001-07-07 00:05:55 +00003040 /* Looks like they want an interactive shell */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003041#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
3042 printf("\n\n" BB_BANNER " Built-in shell (ash)\n");
3043 printf("Enter 'help' for a list of built-in commands.\n\n");
Eric Andersend63dee42001-10-19 00:22:23 +00003044#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003045 do_banner = 1;
Eric Andersen1c039232001-07-07 00:05:55 +00003046 }
Eric Andersen2870d962001-07-02 17:27:21 +00003047}
3048
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003049static void optschanged(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003050{
3051 setinteractive(iflag);
3052 setjobctl(mflag);
3053}
3054
Eric Andersencb57d552001-06-28 07:25:16 +00003055
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003056static int execcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003057{
3058 if (argc > 1) {
3059 struct strlist *sp;
3060
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003061 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003062 mflag = 0;
3063 optschanged();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003064 for (sp = cmdenviron; sp; sp = sp->next)
3065 setvareq(sp->text, VEXPORT | VSTACK);
Eric Andersencb57d552001-06-28 07:25:16 +00003066 shellexec(argv + 1, environment(), pathval(), 0);
3067 }
3068 return 0;
3069}
3070
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003071static void eprintlist(struct strlist *sp)
Eric Andersencb57d552001-06-28 07:25:16 +00003072{
3073 for (; sp; sp = sp->next) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003074 out2fmt(" %s", sp->text);
Eric Andersencb57d552001-06-28 07:25:16 +00003075 }
3076}
Eric Andersencb57d552001-06-28 07:25:16 +00003077
3078/*
3079 * Exec a program. Never returns. If you change this routine, you may
3080 * have to change the find_command routine as well.
3081 */
3082
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003083static const char *pathopt; /* set by padvance */
Eric Andersen2870d962001-07-02 17:27:21 +00003084
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003085static void shellexec(char **argv, char **envp, const char *path, int idx)
Eric Andersencb57d552001-06-28 07:25:16 +00003086{
3087 char *cmdname;
3088 int e;
3089
Eric Andersenbf8bf102002-09-17 08:41:08 +00003090 if (strchr(argv[0], '/') != NULL
3091#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3092 || find_applet_by_name(argv[0])
3093#endif
3094 )
3095 {
Eric Andersencb57d552001-06-28 07:25:16 +00003096 tryexec(argv[0], argv, envp);
3097 e = errno;
3098 } else {
3099 e = ENOENT;
3100 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3101 if (--idx < 0 && pathopt == NULL) {
3102 tryexec(cmdname, argv, envp);
3103 if (errno != ENOENT && errno != ENOTDIR)
3104 e = errno;
3105 }
3106 stunalloc(cmdname);
3107 }
3108 }
3109
3110 /* Map to POSIX errors */
3111 switch (e) {
3112 case EACCES:
3113 exerrno = 126;
3114 break;
3115 case ENOENT:
3116 exerrno = 127;
3117 break;
3118 default:
3119 exerrno = 2;
3120 break;
3121 }
3122 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3123 /* NOTREACHED */
3124}
3125
Eric Andersen2870d962001-07-02 17:27:21 +00003126/*
3127 * Clear traps on a fork.
3128 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003129static void clear_traps(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003130{
Eric Andersen2870d962001-07-02 17:27:21 +00003131 char **tp;
3132
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003133 for (tp = trap; tp < &trap[NSIG]; tp++) {
3134 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
Eric Andersen2870d962001-07-02 17:27:21 +00003135 INTOFF;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00003136 free(*tp);
Eric Andersen2870d962001-07-02 17:27:21 +00003137 *tp = NULL;
3138 if (tp != &trap[0])
3139 setsignal(tp - trap);
3140 INTON;
3141 }
3142 }
3143}
3144
3145
Eric Andersen2870d962001-07-02 17:27:21 +00003146static int preadbuffer(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003147static void pushfile(void);
Eric Andersen2870d962001-07-02 17:27:21 +00003148
3149/*
3150 * Read a character from the script, returning PEOF on end of file.
3151 * Nul characters in the input are silently discarded.
3152 */
3153
Eric Andersend35c5df2002-01-09 15:37:36 +00003154#ifndef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Eric Andersen2870d962001-07-02 17:27:21 +00003155#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003156static int pgetc(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003157{
3158 return pgetc_macro();
3159}
3160#else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003161static int pgetc_macro(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003162{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003163 return --parsenleft >= 0 ? *parsenextc++ : preadbuffer();
Eric Andersen2870d962001-07-02 17:27:21 +00003164}
3165
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003166static inline int pgetc(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003167{
3168 return pgetc_macro();
3169}
3170#endif
3171
3172
3173/*
3174 * Undo the last call to pgetc. Only one character may be pushed back.
3175 * PEOF may be pushed back.
3176 */
3177
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003178static void pungetc(void)
Eric Andersen74400cc2001-10-18 04:11:39 +00003179{
Eric Andersen2870d962001-07-02 17:27:21 +00003180 parsenleft++;
3181 parsenextc--;
3182}
3183
3184
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003185static void popfile(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003186{
Eric Andersen2870d962001-07-02 17:27:21 +00003187 struct parsefile *pf = parsefile;
3188
3189 INTOFF;
3190 if (pf->fd >= 0)
3191 close(pf->fd);
Aaron Lehmann49c024a2002-08-02 06:39:47 +00003192 free(pf->buf);
Eric Andersen2870d962001-07-02 17:27:21 +00003193 while (pf->strpush)
3194 popstring();
3195 parsefile = pf->prev;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00003196 free(pf);
Eric Andersen2870d962001-07-02 17:27:21 +00003197 parsenleft = parsefile->nleft;
3198 parselleft = parsefile->lleft;
3199 parsenextc = parsefile->nextc;
3200 plinno = parsefile->linno;
3201 INTON;
3202}
3203
3204
3205/*
3206 * Return to top level.
3207 */
3208
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003209static void popallfiles(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003210{
Eric Andersen2870d962001-07-02 17:27:21 +00003211 while (parsefile != &basepf)
3212 popfile();
3213}
3214
3215/*
3216 * Close the file(s) that the shell is reading commands from. Called
3217 * after a fork is done.
3218 */
3219
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003220static void closescript(void)
Eric Andersen74400cc2001-10-18 04:11:39 +00003221{
Eric Andersen2870d962001-07-02 17:27:21 +00003222 popallfiles();
3223 if (parsefile->fd > 0) {
3224 close(parsefile->fd);
3225 parsefile->fd = 0;
3226 }
3227}
3228
3229
3230/*
3231 * Like setinputfile, but takes an open file descriptor. Call this with
3232 * interrupts off.
3233 */
3234
Eric Andersen74400cc2001-10-18 04:11:39 +00003235static void setinputfd(int fd, int push)
Eric Andersen2870d962001-07-02 17:27:21 +00003236{
3237 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
3238 if (push) {
3239 pushfile();
3240 parsefile->buf = 0;
3241 } else {
3242 closescript();
3243 while (parsefile->strpush)
3244 popstring();
3245 }
3246 parsefile->fd = fd;
3247 if (parsefile->buf == NULL)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003248 parsefile->buf = xmalloc(BUFSIZ);
Eric Andersen2870d962001-07-02 17:27:21 +00003249 parselleft = parsenleft = 0;
3250 plinno = 1;
3251}
3252
3253
3254/*
3255 * Set the input to take input from a file. If push is set, push the
3256 * old input onto the stack first.
3257 */
3258
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003259static void setinputfile(const char *fname, int push)
Eric Andersen2870d962001-07-02 17:27:21 +00003260{
3261 int fd;
3262 int myfileno2;
3263
3264 INTOFF;
3265 if ((fd = open(fname, O_RDONLY)) < 0)
3266 error("Can't open %s", fname);
3267 if (fd < 10) {
3268 myfileno2 = dup_as_newfd(fd, 10);
3269 close(fd);
3270 if (myfileno2 < 0)
3271 error("Out of file descriptors");
3272 fd = myfileno2;
3273 }
3274 setinputfd(fd, push);
3275 INTON;
3276}
3277
Eric Andersencb57d552001-06-28 07:25:16 +00003278
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003279static void tryexec(char *cmd, char **argv, char **envp)
Eric Andersen62483552001-07-10 06:09:16 +00003280{
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003281 int repeated = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003282
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003283#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Glenn L McGrathc00c56e2002-12-23 10:23:10 +00003284 int flg_bb = 0;
Eric Andersen3102ac42001-07-06 04:26:23 +00003285 char *name = cmd;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003286
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003287#ifdef CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
Manuel Novoa III cad53642003-03-19 09:13:01 +00003288 name = bb_get_last_path_component(name);
Glenn L McGrathc00c56e2002-12-23 10:23:10 +00003289 if(find_applet_by_name(name) != NULL)
3290 flg_bb = 1;
3291#else
3292 if(strchr(name, '/') == NULL && find_applet_by_name(name) != NULL) {
3293 flg_bb = 1;
3294 }
Eric Andersen3102ac42001-07-06 04:26:23 +00003295#endif
Glenn L McGrathc00c56e2002-12-23 10:23:10 +00003296 if(flg_bb) {
3297 char **ap;
3298 char **new;
3299
3300 *argv = name;
3301 if(strcmp(name, "busybox")) {
3302 for (ap = argv; *ap; ap++);
3303 ap = new = xmalloc((ap - argv + 2) * sizeof(char *));
3304 *ap++ = cmd = "/bin/busybox";
3305 while ((*ap++ = *argv++));
3306 argv = new;
3307 repeated++;
3308 } else {
3309 cmd = "/bin/busybox";
3310 }
3311 }
Eric Andersen3102ac42001-07-06 04:26:23 +00003312#endif
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003313 repeat:
Eric Andersencb57d552001-06-28 07:25:16 +00003314 execve(cmd, argv, envp);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003315 if (repeated++) {
3316 free(argv);
3317 } else if (errno == ENOEXEC) {
3318 char **ap;
3319 char **new;
3320
3321 for (ap = argv; *ap; ap++);
3322 ap = new = xmalloc((ap - argv + 2) * sizeof(char *));
3323 *ap++ = cmd = "/bin/sh";
3324 while ((*ap++ = *argv++));
3325 argv = new;
3326 goto repeat;
Eric Andersencb57d552001-06-28 07:25:16 +00003327 }
Eric Andersencb57d552001-06-28 07:25:16 +00003328}
3329
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003330static char *commandtext(const union node *);
Eric Andersencb57d552001-06-28 07:25:16 +00003331
3332/*
3333 * Do a path search. The variable path (passed by reference) should be
3334 * set to the start of the path before the first call; padvance will update
3335 * this value as it proceeds. Successive calls to padvance will return
3336 * the possible path expansions in sequence. If an option (indicated by
3337 * a percent sign) appears in the path entry then the global variable
3338 * pathopt will be set to point to it; otherwise pathopt will be set to
3339 * NULL.
3340 */
3341
3342static const char *pathopt;
3343
Eric Andersen2870d962001-07-02 17:27:21 +00003344static void growstackblock(void);
3345
3346
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003347static char *padvance(const char **path, const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003348{
Eric Andersencb57d552001-06-28 07:25:16 +00003349 const char *p;
3350 char *q;
3351 const char *start;
3352 int len;
3353
3354 if (*path == NULL)
3355 return NULL;
3356 start = *path;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003357 for (p = start; *p && *p != ':' && *p != '%'; p++);
3358 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003359 while (stackblocksize() < len)
3360 growstackblock();
3361 q = stackblock();
3362 if (p != start) {
3363 memcpy(q, start, p - start);
3364 q += p - start;
3365 *q++ = '/';
3366 }
3367 strcpy(q, name);
3368 pathopt = NULL;
3369 if (*p == '%') {
3370 pathopt = ++p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003371 while (*p && *p != ':')
3372 p++;
Eric Andersencb57d552001-06-28 07:25:16 +00003373 }
3374 if (*p == ':')
3375 *path = p + 1;
3376 else
3377 *path = NULL;
3378 return stalloc(len);
3379}
3380
Eric Andersen62483552001-07-10 06:09:16 +00003381/*
3382 * Wrapper around strcmp for qsort/bsearch/...
3383 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003384static int pstrcmp(const void *a, const void *b)
Eric Andersen62483552001-07-10 06:09:16 +00003385{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003386 return strcmp((const char *) a, (*(const char *const *) b) + 1);
Eric Andersen62483552001-07-10 06:09:16 +00003387}
3388
3389/*
3390 * Find a keyword is in a sorted array.
3391 */
3392
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003393static const char *const *findkwd(const char *s)
Eric Andersen62483552001-07-10 06:09:16 +00003394{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003395 return bsearch(s, tokname_array + KWDOFFSET,
3396 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
3397 sizeof(const char *), pstrcmp);
Eric Andersen62483552001-07-10 06:09:16 +00003398}
Eric Andersencb57d552001-06-28 07:25:16 +00003399
3400
3401/*** Command hashing code ***/
3402
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003403static int hashcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003404{
3405 struct tblentry **pp;
3406 struct tblentry *cmdp;
3407 int c;
3408 int verbose;
3409 struct cmdentry entry;
3410 char *name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003411
Eric Andersend35c5df2002-01-09 15:37:36 +00003412#ifdef CONFIG_ASH_ALIAS
Eric Andersen62483552001-07-10 06:09:16 +00003413 const struct alias *ap;
3414#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003415
3416 verbose = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003417 while ((c = nextopt("rvV")) != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00003418 if (c == 'r') {
3419 clearcmdentry(0);
3420 return 0;
Eric Andersen62483552001-07-10 06:09:16 +00003421 } else if (c == 'v' || c == 'V') {
3422 verbose = c;
Eric Andersencb57d552001-06-28 07:25:16 +00003423 }
3424 }
3425 if (*argptr == NULL) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003426 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
3427 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00003428 if (cmdp->cmdtype != CMDBUILTIN) {
3429 printentry(cmdp, verbose);
3430 }
3431 }
3432 }
3433 return 0;
3434 }
3435 c = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003436 while ((name = *argptr++) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00003437 if ((cmdp = cmdlookup(name, 0)) != NULL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003438 && (cmdp->cmdtype == CMDNORMAL
3439 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
Eric Andersencb57d552001-06-28 07:25:16 +00003440 delete_cmd_entry();
Eric Andersend35c5df2002-01-09 15:37:36 +00003441#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003442 /* Then look at the aliases */
Eric Andersenec074692001-10-31 11:05:49 +00003443 if ((ap = *__lookupalias(name)) != NULL) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003444 if (verbose == 'v')
Eric Andersen62483552001-07-10 06:09:16 +00003445 printf("%s is an alias for %s\n", name, ap->val);
3446 else
3447 printalias(ap);
3448 continue;
3449 }
3450#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003451 /* First look at the keywords */
3452 if (findkwd(name) != 0) {
3453 if (verbose == 'v')
Eric Andersen62483552001-07-10 06:09:16 +00003454 printf("%s is a shell keyword\n", name);
3455 else
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003456 puts(name);
Eric Andersen62483552001-07-10 06:09:16 +00003457 continue;
3458 }
3459
Eric Andersencb57d552001-06-28 07:25:16 +00003460 find_command(name, &entry, DO_ERR, pathval());
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003461 if (entry.cmdtype == CMDUNKNOWN)
3462 c = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00003463 else if (verbose) {
3464 cmdp = cmdlookup(name, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003465 if (cmdp)
3466 printentry(cmdp, verbose == 'v');
Eric Andersencb57d552001-06-28 07:25:16 +00003467 flushall();
3468 }
Eric Andersencb57d552001-06-28 07:25:16 +00003469 }
3470 return c;
3471}
3472
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003473static void printentry(struct tblentry *cmdp, int verbose)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003474{
Eric Andersencb57d552001-06-28 07:25:16 +00003475 int idx;
3476 const char *path;
3477 char *name;
3478
Eric Andersen62483552001-07-10 06:09:16 +00003479 printf("%s%s", cmdp->cmdname, (verbose ? " is " : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00003480 if (cmdp->cmdtype == CMDNORMAL) {
3481 idx = cmdp->param.index;
3482 path = pathval();
3483 do {
3484 name = padvance(&path, cmdp->cmdname);
3485 stunalloc(name);
3486 } while (--idx >= 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003487 if (verbose)
Eric Andersen62483552001-07-10 06:09:16 +00003488 out1str(name);
Eric Andersencb57d552001-06-28 07:25:16 +00003489 } else if (cmdp->cmdtype == CMDBUILTIN) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003490 if (verbose)
Eric Andersen62483552001-07-10 06:09:16 +00003491 out1str("a shell builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00003492 } else if (cmdp->cmdtype == CMDFUNCTION) {
Eric Andersencb57d552001-06-28 07:25:16 +00003493 if (verbose) {
3494 INTOFF;
Eric Andersen62483552001-07-10 06:09:16 +00003495 out1str("a function\n");
Eric Andersencb57d552001-06-28 07:25:16 +00003496 name = commandtext(cmdp->param.func);
Eric Andersen62483552001-07-10 06:09:16 +00003497 printf("%s() {\n %s\n}", cmdp->cmdname, name);
Aaron Lehmann49c024a2002-08-02 06:39:47 +00003498 free(name);
Eric Andersencb57d552001-06-28 07:25:16 +00003499 INTON;
3500 }
3501#ifdef DEBUG
3502 } else {
3503 error("internal error: cmdtype %d", cmdp->cmdtype);
3504#endif
3505 }
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003506 puts(cmdp->rehash ? "*" : nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +00003507}
3508
3509
3510
Eric Andersen1c039232001-07-07 00:05:55 +00003511/*** List the available builtins ***/
3512
3513
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003514static int helpcmd(int argc, char **argv)
Eric Andersen1c039232001-07-07 00:05:55 +00003515{
3516 int col, i;
Eric Andersen1c039232001-07-07 00:05:55 +00003517
Eric Andersen62483552001-07-10 06:09:16 +00003518 printf("\nBuilt-in commands:\n-------------------\n");
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003519 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
Eric Andersen62483552001-07-10 06:09:16 +00003520 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003521 builtincmds[i].name + 1);
Eric Andersen1c039232001-07-07 00:05:55 +00003522 if (col > 60) {
3523 printf("\n");
3524 col = 0;
3525 }
3526 }
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003527#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Eric Andersen1c039232001-07-07 00:05:55 +00003528 {
Eric Andersen1c039232001-07-07 00:05:55 +00003529 extern const struct BB_applet applets[];
3530 extern const size_t NUM_APPLETS;
3531
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003532 for (i = 0; i < NUM_APPLETS; i++) {
Eric Andersen62483552001-07-10 06:09:16 +00003533
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003534 col += printf("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
Eric Andersen1c039232001-07-07 00:05:55 +00003535 if (col > 60) {
3536 printf("\n");
3537 col = 0;
3538 }
3539 }
3540 }
3541#endif
3542 printf("\n\n");
3543 return EXIT_SUCCESS;
3544}
3545
Eric Andersencb57d552001-06-28 07:25:16 +00003546/*
3547 * Resolve a command name. If you change this routine, you may have to
3548 * change the shellexec routine as well.
3549 */
3550
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003551static int prefix(const char *, const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00003552
Eric Andersencb57d552001-06-28 07:25:16 +00003553static void
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003554find_command(const char *name, struct cmdentry *entry, int act,
3555 const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003556{
3557 struct tblentry *cmdp;
3558 int idx;
3559 int prev;
3560 char *fullname;
3561 struct stat statb;
3562 int e;
3563 int bltin;
3564 int firstchange;
3565 int updatetbl;
Eric Andersen62483552001-07-10 06:09:16 +00003566 int regular;
Eric Andersencb57d552001-06-28 07:25:16 +00003567 struct builtincmd *bcmd;
3568
3569 /* If name contains a slash, don't use the hash table */
3570 if (strchr(name, '/') != NULL) {
3571 if (act & DO_ABS) {
3572 while (stat(name, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003573 if (errno != ENOENT && errno != ENOTDIR)
3574 e = errno;
3575 entry->cmdtype = CMDUNKNOWN;
3576 entry->u.index = -1;
3577 return;
3578 }
3579 entry->cmdtype = CMDNORMAL;
3580 entry->u.index = -1;
3581 return;
3582 }
3583 entry->cmdtype = CMDNORMAL;
3584 entry->u.index = 0;
3585 return;
3586 }
3587
Eric Andersenbf8bf102002-09-17 08:41:08 +00003588#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3589 if (find_applet_by_name(name)) {
3590 entry->cmdtype = CMDNORMAL;
3591 entry->u.index = -1;
3592 return;
3593 }
3594#endif
3595
Eric Andersencb57d552001-06-28 07:25:16 +00003596 updatetbl = 1;
3597 if (act & DO_BRUTE) {
3598 firstchange = path_change(path, &bltin);
3599 } else {
3600 bltin = builtinloc;
3601 firstchange = 9999;
3602 }
3603
3604 /* If name is in the table, and not invalidated by cd, we're done */
3605 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
3606 if (cmdp->cmdtype == CMDFUNCTION) {
3607 if (act & DO_NOFUN) {
3608 updatetbl = 0;
3609 } else {
3610 goto success;
3611 }
3612 } else if (act & DO_BRUTE) {
3613 if ((cmdp->cmdtype == CMDNORMAL &&
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003614 cmdp->param.index >= firstchange) ||
3615 (cmdp->cmdtype == CMDBUILTIN &&
3616 ((builtinloc < 0 && bltin >= 0) ?
3617 bltin : builtinloc) >= firstchange)) {
Eric Andersencb57d552001-06-28 07:25:16 +00003618 /* need to recompute the entry */
3619 } else {
3620 goto success;
3621 }
3622 } else {
3623 goto success;
3624 }
3625 }
3626
3627 bcmd = find_builtin(name);
Eric Andersen2870d962001-07-02 17:27:21 +00003628 regular = bcmd && IS_BUILTIN_REGULAR(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00003629
3630 if (regular) {
3631 if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) {
Eric Andersen2870d962001-07-02 17:27:21 +00003632 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003633 }
3634 } else if (act & DO_BRUTE) {
3635 if (firstchange == 0) {
3636 updatetbl = 0;
3637 }
3638 }
3639
3640 /* If %builtin not in path, check for builtin next */
3641 if (regular || (bltin < 0 && bcmd)) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003642 builtin:
Eric Andersencb57d552001-06-28 07:25:16 +00003643 if (!updatetbl) {
3644 entry->cmdtype = CMDBUILTIN;
3645 entry->u.cmd = bcmd;
3646 return;
3647 }
3648 INTOFF;
3649 cmdp = cmdlookup(name, 1);
3650 cmdp->cmdtype = CMDBUILTIN;
3651 cmdp->param.cmd = bcmd;
3652 INTON;
3653 goto success;
3654 }
3655
3656 /* We have to search path. */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003657 prev = -1; /* where to start */
3658 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00003659 if (cmdp->cmdtype == CMDBUILTIN)
3660 prev = builtinloc;
3661 else
3662 prev = cmdp->param.index;
3663 }
3664
3665 e = ENOENT;
3666 idx = -1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003667 loop:
Eric Andersencb57d552001-06-28 07:25:16 +00003668 while ((fullname = padvance(&path, name)) != NULL) {
3669 stunalloc(fullname);
3670 idx++;
3671 if (idx >= firstchange) {
3672 updatetbl = 0;
3673 }
3674 if (pathopt) {
3675 if (prefix("builtin", pathopt)) {
3676 if ((bcmd = find_builtin(name))) {
3677 goto builtin;
3678 }
3679 continue;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003680 } else if (!(act & DO_NOFUN) && prefix("func", pathopt)) {
Eric Andersencb57d552001-06-28 07:25:16 +00003681 /* handled below */
3682 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003683 continue; /* ignore unimplemented options */
Eric Andersencb57d552001-06-28 07:25:16 +00003684 }
3685 }
3686 /* if rehash, don't redo absolute path names */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003687 if (fullname[0] == '/' && idx <= prev && idx < firstchange) {
Eric Andersencb57d552001-06-28 07:25:16 +00003688 if (idx < prev)
3689 continue;
3690 TRACE(("searchexec \"%s\": no change\n", name));
3691 goto success;
3692 }
3693 while (stat(fullname, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003694 if (errno != ENOENT && errno != ENOTDIR)
3695 e = errno;
3696 goto loop;
3697 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003698 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00003699 if (!S_ISREG(statb.st_mode))
3700 continue;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003701 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00003702 stalloc(strlen(fullname) + 1);
3703 readcmdfile(fullname);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003704 if ((cmdp = cmdlookup(name, 0)) == NULL
3705 || cmdp->cmdtype != CMDFUNCTION)
Eric Andersencb57d552001-06-28 07:25:16 +00003706 error("%s not defined in %s", name, fullname);
3707 stunalloc(fullname);
3708 goto success;
3709 }
Eric Andersencb57d552001-06-28 07:25:16 +00003710 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
3711 /* If we aren't called with DO_BRUTE and cmdp is set, it must
3712 be a function and we're being called with DO_NOFUN */
3713 if (!updatetbl) {
3714 entry->cmdtype = CMDNORMAL;
3715 entry->u.index = idx;
3716 return;
3717 }
3718 INTOFF;
3719 cmdp = cmdlookup(name, 1);
3720 cmdp->cmdtype = CMDNORMAL;
3721 cmdp->param.index = idx;
3722 INTON;
3723 goto success;
3724 }
3725
3726 /* We failed. If there was an entry for this command, delete it */
3727 if (cmdp && updatetbl)
3728 delete_cmd_entry();
3729 if (act & DO_ERR)
Eric Andersen3102ac42001-07-06 04:26:23 +00003730 out2fmt("%s: %s\n", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00003731 entry->cmdtype = CMDUNKNOWN;
3732 return;
3733
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003734 success:
Eric Andersencb57d552001-06-28 07:25:16 +00003735 cmdp->rehash = 0;
3736 entry->cmdtype = cmdp->cmdtype;
3737 entry->u = cmdp->param;
3738}
3739
3740
3741
3742/*
3743 * Search the table of builtin commands.
3744 */
3745
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003746static struct builtincmd *find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00003747{
3748 struct builtincmd *bp;
3749
Eric Andersen2870d962001-07-02 17:27:21 +00003750 bp = bsearch(name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd),
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003751 pstrcmp);
Eric Andersencb57d552001-06-28 07:25:16 +00003752 return bp;
3753}
3754
3755
3756/*
3757 * Called when a cd is done. Marks all commands so the next time they
3758 * are executed they will be rehashed.
3759 */
3760
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003761static void hashcd(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003762{
Eric Andersencb57d552001-06-28 07:25:16 +00003763 struct tblentry **pp;
3764 struct tblentry *cmdp;
3765
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003766 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
3767 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00003768 if (cmdp->cmdtype == CMDNORMAL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003769 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
Eric Andersencb57d552001-06-28 07:25:16 +00003770 cmdp->rehash = 1;
3771 }
3772 }
3773}
3774
3775
3776
3777/*
3778 * Called before PATH is changed. The argument is the new value of PATH;
3779 * pathval() still returns the old value at this point. Called with
3780 * interrupts off.
3781 */
3782
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003783static void changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00003784{
3785 int firstchange;
3786 int bltin;
3787
3788 firstchange = path_change(newval, &bltin);
3789 if (builtinloc < 0 && bltin >= 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003790 builtinloc = bltin; /* zap builtins */
Eric Andersencb57d552001-06-28 07:25:16 +00003791 clearcmdentry(firstchange);
3792 builtinloc = bltin;
Eric Andersen1a923762002-06-06 12:07:28 +00003793 /* Ensure that getenv("PATH") stays current */
3794 setenv("PATH", newval, 1);
Eric Andersencb57d552001-06-28 07:25:16 +00003795}
3796
3797
3798/*
3799 * Clear out command entries. The argument specifies the first entry in
3800 * PATH which has changed.
3801 */
3802
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003803static void clearcmdentry(int firstchange)
Eric Andersencb57d552001-06-28 07:25:16 +00003804{
3805 struct tblentry **tblp;
3806 struct tblentry **pp;
3807 struct tblentry *cmdp;
3808
3809 INTOFF;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003810 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00003811 pp = tblp;
3812 while ((cmdp = *pp) != NULL) {
3813 if ((cmdp->cmdtype == CMDNORMAL &&
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003814 cmdp->param.index >= firstchange)
3815 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= firstchange)) {
Eric Andersencb57d552001-06-28 07:25:16 +00003816 *pp = cmdp->next;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00003817 free(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00003818 } else {
3819 pp = &cmdp->next;
3820 }
3821 }
3822 }
3823 INTON;
3824}
3825
3826
3827/*
Eric Andersencb57d552001-06-28 07:25:16 +00003828 * Locate a command in the command hash table. If "add" is nonzero,
3829 * add the command to the table if it is not already present. The
3830 * variable "lastcmdentry" is set to point to the address of the link
3831 * pointing to the entry, so that delete_cmd_entry can delete the
3832 * entry.
3833 */
3834
Eric Andersen2870d962001-07-02 17:27:21 +00003835static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00003836
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003837static struct tblentry *cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00003838{
3839 int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00003840 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00003841 struct tblentry *cmdp;
3842 struct tblentry **pp;
3843
3844 p = name;
3845 hashval = *p << 4;
3846 while (*p)
3847 hashval += *p++;
3848 hashval &= 0x7FFF;
3849 pp = &cmdtable[hashval % CMDTABLESIZE];
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003850 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00003851 if (equal(cmdp->cmdname, name))
3852 break;
3853 pp = &cmdp->next;
3854 }
3855 if (add && cmdp == NULL) {
3856 INTOFF;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003857 cmdp = *pp = xmalloc(sizeof(struct tblentry) - ARB
3858 + strlen(name) + 1);
Eric Andersencb57d552001-06-28 07:25:16 +00003859 cmdp->next = NULL;
3860 cmdp->cmdtype = CMDUNKNOWN;
3861 cmdp->rehash = 0;
3862 strcpy(cmdp->cmdname, name);
3863 INTON;
3864 }
3865 lastcmdentry = pp;
3866 return cmdp;
3867}
3868
3869/*
3870 * Delete the command entry returned on the last lookup.
3871 */
3872
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003873static void delete_cmd_entry(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003874{
Eric Andersencb57d552001-06-28 07:25:16 +00003875 struct tblentry *cmdp;
3876
3877 INTOFF;
3878 cmdp = *lastcmdentry;
3879 *lastcmdentry = cmdp->next;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00003880 free(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00003881 INTON;
3882}
3883
3884
3885
Eric Andersencb57d552001-06-28 07:25:16 +00003886
3887
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003888static const unsigned char nodesize[26] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003889 ALIGN(sizeof(struct nbinary)),
3890 ALIGN(sizeof(struct ncmd)),
3891 ALIGN(sizeof(struct npipe)),
3892 ALIGN(sizeof(struct nredir)),
3893 ALIGN(sizeof(struct nredir)),
3894 ALIGN(sizeof(struct nredir)),
3895 ALIGN(sizeof(struct nbinary)),
3896 ALIGN(sizeof(struct nbinary)),
3897 ALIGN(sizeof(struct nif)),
3898 ALIGN(sizeof(struct nbinary)),
3899 ALIGN(sizeof(struct nbinary)),
3900 ALIGN(sizeof(struct nfor)),
3901 ALIGN(sizeof(struct ncase)),
3902 ALIGN(sizeof(struct nclist)),
3903 ALIGN(sizeof(struct narg)),
3904 ALIGN(sizeof(struct narg)),
3905 ALIGN(sizeof(struct nfile)),
3906 ALIGN(sizeof(struct nfile)),
3907 ALIGN(sizeof(struct nfile)),
3908 ALIGN(sizeof(struct nfile)),
3909 ALIGN(sizeof(struct nfile)),
3910 ALIGN(sizeof(struct ndup)),
3911 ALIGN(sizeof(struct ndup)),
3912 ALIGN(sizeof(struct nhere)),
3913 ALIGN(sizeof(struct nhere)),
3914 ALIGN(sizeof(struct nnot)),
Eric Andersen62483552001-07-10 06:09:16 +00003915};
Eric Andersencb57d552001-06-28 07:25:16 +00003916
Eric Andersencb57d552001-06-28 07:25:16 +00003917
3918
3919/*
3920 * Delete a function if it exists.
3921 */
3922
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003923static void unsetfunc(char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003924{
Eric Andersencb57d552001-06-28 07:25:16 +00003925 struct tblentry *cmdp;
3926
3927 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
Aaron Lehmann49c024a2002-08-02 06:39:47 +00003928 free(cmdp->param.func);
Eric Andersencb57d552001-06-28 07:25:16 +00003929 delete_cmd_entry();
3930 }
3931}
3932
Eric Andersen2870d962001-07-02 17:27:21 +00003933
3934/*
Eric Andersencb57d552001-06-28 07:25:16 +00003935 * Locate and print what a word is...
3936 */
3937
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003938static int typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003939{
3940 int i;
3941 int err = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003942 char *argv_a[2];
3943
3944 argv_a[1] = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003945
3946 for (i = 1; i < argc; i++) {
Eric Andersen62483552001-07-10 06:09:16 +00003947 argv_a[0] = argv[i];
3948 argptr = argv_a;
3949 optptr = "v";
Glenn L McGrath4501dbe2002-12-11 21:13:00 +00003950 err |= hashcmd(2, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00003951 }
3952 return err;
3953}
3954
Eric Andersend35c5df2002-01-09 15:37:36 +00003955#ifdef CONFIG_ASH_CMDCMD
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003956static int commandcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003957{
3958 int c;
3959 int default_path = 0;
3960 int verify_only = 0;
3961 int verbose_verify_only = 0;
3962
3963 while ((c = nextopt("pvV")) != '\0')
3964 switch (c) {
3965 case 'p':
3966 default_path = 1;
3967 break;
3968 case 'v':
3969 verify_only = 1;
3970 break;
3971 case 'V':
3972 verbose_verify_only = 1;
3973 break;
Eric Andersencb57d552001-06-28 07:25:16 +00003974 }
3975
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003976 if (default_path + verify_only + verbose_verify_only > 1 || !*argptr) {
3977 out2str("command [-p] command [arg ...]\n"
Eric Andersen62483552001-07-10 06:09:16 +00003978 "command {-v|-V} command\n");
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003979 return EX_USAGE;
Eric Andersencb57d552001-06-28 07:25:16 +00003980 }
3981
Eric Andersencb57d552001-06-28 07:25:16 +00003982 if (verify_only || verbose_verify_only) {
Eric Andersen62483552001-07-10 06:09:16 +00003983 char *argv_a[2];
3984
3985 argv_a[1] = 0;
3986 argv_a[0] = *argptr;
3987 argptr = argv_a;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003988 optptr = verbose_verify_only ? "v" : "V"; /* reverse special */
Eric Andersen62483552001-07-10 06:09:16 +00003989 return hashcmd(argc, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00003990 }
Eric Andersencb57d552001-06-28 07:25:16 +00003991
3992 return 0;
3993}
Eric Andersen2870d962001-07-02 17:27:21 +00003994#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003995
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003996static int path_change(const char *newval, int *bltin)
Eric Andersencb57d552001-06-28 07:25:16 +00003997{
3998 const char *old, *new;
3999 int idx;
4000 int firstchange;
4001
4002 old = pathval();
4003 new = newval;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004004 firstchange = 9999; /* assume no change */
Eric Andersencb57d552001-06-28 07:25:16 +00004005 idx = 0;
4006 *bltin = -1;
4007 for (;;) {
4008 if (*old != *new) {
4009 firstchange = idx;
4010 if ((*old == '\0' && *new == ':')
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004011 || (*old == ':' && *new == '\0'))
Eric Andersencb57d552001-06-28 07:25:16 +00004012 firstchange++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004013 old = new; /* ignore subsequent differences */
Eric Andersencb57d552001-06-28 07:25:16 +00004014 }
4015 if (*new == '\0')
4016 break;
4017 if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1))
4018 *bltin = idx;
4019 if (*new == ':') {
4020 idx++;
4021 }
4022 new++, old++;
4023 }
4024 if (builtinloc >= 0 && *bltin < 0)
4025 firstchange = 0;
4026 return firstchange;
4027}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004028
Eric Andersencb57d552001-06-28 07:25:16 +00004029/*
4030 * Routines to expand arguments to commands. We have to deal with
4031 * backquotes, shell variables, and file metacharacters.
4032 */
4033/*
4034 * _rmescape() flags
4035 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004036#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4037#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Eric Andersencb57d552001-06-28 07:25:16 +00004038
4039/*
4040 * Structure specifying which parts of the string should be searched
4041 * for IFS characters.
4042 */
4043
4044struct ifsregion {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004045 struct ifsregion *next; /* next region in list */
4046 int begoff; /* offset of start of region */
4047 int endoff; /* offset of end of region */
4048 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004049};
4050
4051
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004052static char *expdest; /* output of current string */
4053static struct nodelist *argbackq; /* list of back quote expressions */
4054static struct ifsregion ifsfirst; /* first struct in list of ifs regions */
4055static struct ifsregion *ifslastp; /* last struct in list */
4056static struct arglist exparg; /* holds expanded arg list */
Eric Andersencb57d552001-06-28 07:25:16 +00004057
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004058static void argstr(char *, int);
4059static char *exptilde(char *, int);
4060static void expbackq(union node *, int, int);
4061static int subevalvar(char *, char *, int, int, int, int, int);
4062static int varisset(char *, int);
4063static void strtodest(const char *, int, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00004064static void varvalue(char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004065static void recordregion(int, int, int);
4066static void removerecordregions(int);
4067static void ifsbreakup(char *, struct arglist *);
4068static void ifsfree(void);
4069static void expandmeta(struct strlist *, int);
4070
Eric Andersen62483552001-07-10 06:09:16 +00004071#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00004072#define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB)
4073#if !defined(GLOB_BROKEN)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00004074static void addglob(const glob_t *);
Eric Andersencb57d552001-06-28 07:25:16 +00004075#endif
4076#endif
Eric Andersen62483552001-07-10 06:09:16 +00004077#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004078static void expmeta(char *, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004079#endif
Eric Andersen62483552001-07-10 06:09:16 +00004080#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004081static struct strlist *expsort(struct strlist *);
4082static struct strlist *msort(struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004083#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004084static int patmatch(char *, char *, int);
4085
Eric Andersen62483552001-07-10 06:09:16 +00004086#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004087static int patmatch2(char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004088#else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004089static int pmatch(char *, char *, int);
4090
Eric Andersencb57d552001-06-28 07:25:16 +00004091#define patmatch2 patmatch
4092#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004093static char *cvtnum(int, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004094
4095/*
4096 * Expand shell variables and backquotes inside a here document.
4097 */
4098
Eric Andersen2870d962001-07-02 17:27:21 +00004099/* arg: the document, fd: where to write the expanded version */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004100static inline void expandhere(union node *arg, int fd)
Eric Andersen2870d962001-07-02 17:27:21 +00004101{
Eric Andersencb57d552001-06-28 07:25:16 +00004102 herefd = fd;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004103 expandarg(arg, (struct arglist *) NULL, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00004104 xwrite(fd, stackblock(), expdest - stackblock());
4105}
4106
4107
4108/*
4109 * Perform variable substitution and command substitution on an argument,
4110 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4111 * perform splitting and file name expansion. When arglist is NULL, perform
4112 * here document expansion.
4113 */
4114
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004115static void expandarg(union node *arg, struct arglist *arglist, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004116{
4117 struct strlist *sp;
4118 char *p;
4119
4120 argbackq = arg->narg.backquote;
4121 STARTSTACKSTR(expdest);
4122 ifsfirst.next = NULL;
4123 ifslastp = NULL;
4124 argstr(arg->narg.text, flag);
4125 if (arglist == NULL) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004126 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004127 }
4128 STPUTC('\0', expdest);
4129 p = grabstackstr(expdest);
4130 exparg.lastp = &exparg.list;
4131 /*
4132 * TODO - EXP_REDIR
4133 */
4134 if (flag & EXP_FULL) {
4135 ifsbreakup(p, &exparg);
4136 *exparg.lastp = NULL;
4137 exparg.lastp = &exparg.list;
4138 expandmeta(exparg.list, flag);
4139 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004140 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
Eric Andersencb57d552001-06-28 07:25:16 +00004141 rmescapes(p);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004142 sp = (struct strlist *) stalloc(sizeof(struct strlist));
Eric Andersencb57d552001-06-28 07:25:16 +00004143 sp->text = p;
4144 *exparg.lastp = sp;
4145 exparg.lastp = &sp->next;
4146 }
4147 ifsfree();
4148 *exparg.lastp = NULL;
4149 if (exparg.list) {
4150 *arglist->lastp = exparg.list;
4151 arglist->lastp = exparg.lastp;
4152 }
4153}
4154
4155
Eric Andersen62483552001-07-10 06:09:16 +00004156/*
4157 * Expand a variable, and return a pointer to the next character in the
4158 * input string.
4159 */
4160
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004161static inline char *evalvar(char *p, int flag)
Eric Andersen62483552001-07-10 06:09:16 +00004162{
4163 int subtype;
4164 int varflags;
4165 char *var;
4166 const char *val;
4167 int patloc;
4168 int c;
4169 int set;
4170 int special;
4171 int startloc;
4172 int varlen;
4173 int easy;
4174 int quotes = flag & (EXP_FULL | EXP_CASE);
4175
4176 varflags = *p++;
4177 subtype = varflags & VSTYPE;
4178 var = p;
4179 special = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004180 if (!is_name(*p))
Eric Andersen62483552001-07-10 06:09:16 +00004181 special = 1;
4182 p = strchr(p, '=') + 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004183 again: /* jump here after setting a variable with ${var=text} */
Eric Andersen62483552001-07-10 06:09:16 +00004184 if (special) {
4185 set = varisset(var, varflags & VSNUL);
4186 val = NULL;
4187 } else {
4188 val = lookupvar(var);
4189 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
4190 val = NULL;
4191 set = 0;
4192 } else
4193 set = 1;
4194 }
4195 varlen = 0;
4196 startloc = expdest - stackblock();
4197 if (set && subtype != VSPLUS) {
4198 /* insert the value of the variable */
4199 if (special) {
4200 varvalue(var, varflags & VSQUOTE, flag);
4201 if (subtype == VSLENGTH) {
4202 varlen = expdest - stackblock() - startloc;
4203 STADJUST(-varlen, expdest);
4204 }
4205 } else {
4206 if (subtype == VSLENGTH) {
4207 varlen = strlen(val);
4208 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004209 strtodest(val,
4210 varflags & VSQUOTE ? DQSYNTAX : BASESYNTAX, quotes);
Eric Andersen62483552001-07-10 06:09:16 +00004211 }
4212 }
4213 }
4214
4215 if (subtype == VSPLUS)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004216 set = !set;
Eric Andersen62483552001-07-10 06:09:16 +00004217
4218 easy = ((varflags & VSQUOTE) == 0 ||
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004219 (*var == '@' && shellparam.nparam != 1));
Eric Andersen62483552001-07-10 06:09:16 +00004220
4221
4222 switch (subtype) {
4223 case VSLENGTH:
4224 expdest = cvtnum(varlen, expdest);
4225 goto record;
4226
4227 case VSNORMAL:
4228 if (!easy)
4229 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004230 record:
4231 recordregion(startloc, expdest - stackblock(), varflags & VSQUOTE);
Eric Andersen62483552001-07-10 06:09:16 +00004232 break;
4233
4234 case VSPLUS:
4235 case VSMINUS:
4236 if (!set) {
4237 argstr(p, flag);
4238 break;
4239 }
4240 if (easy)
4241 goto record;
4242 break;
4243
4244 case VSTRIMLEFT:
4245 case VSTRIMLEFTMAX:
4246 case VSTRIMRIGHT:
4247 case VSTRIMRIGHTMAX:
4248 if (!set)
4249 break;
4250 /*
4251 * Terminate the string and start recording the pattern
4252 * right after it
4253 */
4254 STPUTC('\0', expdest);
4255 patloc = expdest - stackblock();
4256 if (subevalvar(p, NULL, patloc, subtype,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004257 startloc, varflags, quotes) == 0) {
Eric Andersen62483552001-07-10 06:09:16 +00004258 int amount = (expdest - stackblock() - patloc) + 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004259
Eric Andersen62483552001-07-10 06:09:16 +00004260 STADJUST(-amount, expdest);
4261 }
4262 /* Remove any recorded regions beyond start of variable */
4263 removerecordregions(startloc);
4264 goto record;
4265
4266 case VSASSIGN:
4267 case VSQUESTION:
4268 if (!set) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004269 if (subevalvar(p, var, 0, subtype, startloc, varflags, quotes)) {
Eric Andersen62483552001-07-10 06:09:16 +00004270 varflags &= ~VSNUL;
4271 /*
4272 * Remove any recorded regions beyond
4273 * start of variable
4274 */
4275 removerecordregions(startloc);
4276 goto again;
4277 }
4278 break;
4279 }
4280 if (easy)
4281 goto record;
4282 break;
4283
4284#ifdef DEBUG
4285 default:
4286 abort();
4287#endif
4288 }
4289
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004290 if (subtype != VSNORMAL) { /* skip to end of alternative */
Eric Andersen62483552001-07-10 06:09:16 +00004291 int nesting = 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004292
Eric Andersen62483552001-07-10 06:09:16 +00004293 for (;;) {
4294 if ((c = *p++) == CTLESC)
4295 p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004296 else if (c == CTLBACKQ || c == (CTLBACKQ | CTLQUOTE)) {
Eric Andersen62483552001-07-10 06:09:16 +00004297 if (set)
4298 argbackq = argbackq->next;
4299 } else if (c == CTLVAR) {
4300 if ((*p++ & VSTYPE) != VSNORMAL)
4301 nesting++;
4302 } else if (c == CTLENDVAR) {
4303 if (--nesting == 0)
4304 break;
4305 }
4306 }
4307 }
4308 return p;
4309}
4310
Eric Andersencb57d552001-06-28 07:25:16 +00004311
4312/*
4313 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4314 * characters to allow for further processing. Otherwise treat
4315 * $@ like $* since no splitting will be performed.
4316 */
4317
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004318static void argstr(char *p, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004319{
4320 char c;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004321 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
Eric Andersencb57d552001-06-28 07:25:16 +00004322 int firsteq = 1;
4323
4324 if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
4325 p = exptilde(p, flag);
4326 for (;;) {
4327 switch (c = *p++) {
4328 case '\0':
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004329 case CTLENDVAR: /* ??? */
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004330 return;
Eric Andersencb57d552001-06-28 07:25:16 +00004331 case CTLQUOTEMARK:
4332 /* "$@" syntax adherence hack */
4333 if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
4334 break;
4335 if ((flag & EXP_FULL) != 0)
4336 STPUTC(c, expdest);
4337 break;
4338 case CTLESC:
4339 if (quotes)
4340 STPUTC(c, expdest);
4341 c = *p++;
4342 STPUTC(c, expdest);
4343 break;
4344 case CTLVAR:
4345 p = evalvar(p, flag);
4346 break;
4347 case CTLBACKQ:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004348 case CTLBACKQ | CTLQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +00004349 expbackq(argbackq->n, c & CTLQUOTE, flag);
4350 argbackq = argbackq->next;
4351 break;
Eric Andersend35c5df2002-01-09 15:37:36 +00004352#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +00004353 case CTLENDARI:
4354 expari(flag);
4355 break;
Eric Andersen2870d962001-07-02 17:27:21 +00004356#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004357 case ':':
4358 case '=':
4359 /*
4360 * sort of a hack - expand tildes in variable
4361 * assignments (after the first '=' and after ':'s).
4362 */
4363 STPUTC(c, expdest);
4364 if (flag & EXP_VARTILDE && *p == '~') {
4365 if (c == '=') {
4366 if (firsteq)
4367 firsteq = 0;
4368 else
4369 break;
4370 }
4371 p = exptilde(p, flag);
4372 }
4373 break;
4374 default:
4375 STPUTC(c, expdest);
4376 }
4377 }
Eric Andersencb57d552001-06-28 07:25:16 +00004378}
4379
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004380static char *exptilde(char *p, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004381{
4382 char c, *startp = p;
4383 struct passwd *pw;
4384 const char *home;
4385 int quotes = flag & (EXP_FULL | EXP_CASE);
4386
4387 while ((c = *p) != '\0') {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004388 switch (c) {
Eric Andersencb57d552001-06-28 07:25:16 +00004389 case CTLESC:
4390 return (startp);
4391 case CTLQUOTEMARK:
4392 return (startp);
4393 case ':':
4394 if (flag & EXP_VARTILDE)
4395 goto done;
4396 break;
4397 case '/':
4398 goto done;
4399 }
4400 p++;
4401 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004402 done:
Eric Andersencb57d552001-06-28 07:25:16 +00004403 *p = '\0';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004404 if (*(startp + 1) == '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00004405 if ((home = lookupvar("HOME")) == NULL)
4406 goto lose;
4407 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004408 if ((pw = getpwnam(startp + 1)) == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00004409 goto lose;
4410 home = pw->pw_dir;
4411 }
4412 if (*home == '\0')
4413 goto lose;
4414 *p = c;
4415 strtodest(home, SQSYNTAX, quotes);
4416 return (p);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004417 lose:
Eric Andersencb57d552001-06-28 07:25:16 +00004418 *p = c;
4419 return (startp);
4420}
4421
4422
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004423static void removerecordregions(int endoff)
Eric Andersencb57d552001-06-28 07:25:16 +00004424{
4425 if (ifslastp == NULL)
4426 return;
4427
4428 if (ifsfirst.endoff > endoff) {
4429 while (ifsfirst.next != NULL) {
4430 struct ifsregion *ifsp;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004431
Eric Andersencb57d552001-06-28 07:25:16 +00004432 INTOFF;
4433 ifsp = ifsfirst.next->next;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00004434 free(ifsfirst.next);
Eric Andersencb57d552001-06-28 07:25:16 +00004435 ifsfirst.next = ifsp;
4436 INTON;
4437 }
4438 if (ifsfirst.begoff > endoff)
4439 ifslastp = NULL;
4440 else {
4441 ifslastp = &ifsfirst;
4442 ifsfirst.endoff = endoff;
4443 }
4444 return;
4445 }
Eric Andersen2870d962001-07-02 17:27:21 +00004446
Eric Andersencb57d552001-06-28 07:25:16 +00004447 ifslastp = &ifsfirst;
4448 while (ifslastp->next && ifslastp->next->begoff < endoff)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004449 ifslastp = ifslastp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00004450 while (ifslastp->next != NULL) {
4451 struct ifsregion *ifsp;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004452
Eric Andersencb57d552001-06-28 07:25:16 +00004453 INTOFF;
4454 ifsp = ifslastp->next->next;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00004455 free(ifslastp->next);
Eric Andersencb57d552001-06-28 07:25:16 +00004456 ifslastp->next = ifsp;
4457 INTON;
4458 }
4459 if (ifslastp->endoff > endoff)
4460 ifslastp->endoff = endoff;
4461}
4462
4463
Eric Andersend35c5df2002-01-09 15:37:36 +00004464#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +00004465/*
4466 * Expand arithmetic expression. Backup to start of expression,
4467 * evaluate, place result in (backed up) result, adjust string position.
4468 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004469static void expari(int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004470{
4471 char *p, *start;
Eric Andersen34506362001-08-02 05:02:46 +00004472 int errcode;
Eric Andersencb57d552001-06-28 07:25:16 +00004473 int result;
4474 int begoff;
4475 int quotes = flag & (EXP_FULL | EXP_CASE);
4476 int quoted;
4477
Eric Andersen2870d962001-07-02 17:27:21 +00004478 /* ifsfree(); */
Eric Andersencb57d552001-06-28 07:25:16 +00004479
4480 /*
4481 * This routine is slightly over-complicated for
4482 * efficiency. First we make sure there is
4483 * enough space for the result, which may be bigger
4484 * than the expression if we add exponentation. Next we
4485 * scan backwards looking for the start of arithmetic. If the
4486 * next previous character is a CTLESC character, then we
4487 * have to rescan starting from the beginning since CTLESC
4488 * characters have to be processed left to right.
4489 */
4490 CHECKSTRSPACE(10, expdest);
4491 USTPUTC('\0', expdest);
4492 start = stackblock();
4493 p = expdest - 1;
4494 while (*p != CTLARI && p >= start)
4495 --p;
4496 if (*p != CTLARI)
4497 error("missing CTLARI (shouldn't happen)");
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004498 if (p > start && *(p - 1) == CTLESC)
Eric Andersencb57d552001-06-28 07:25:16 +00004499 for (p = start; *p != CTLARI; p++)
4500 if (*p == CTLESC)
4501 p++;
4502
4503 if (p[1] == '"')
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004504 quoted = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00004505 else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004506 quoted = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004507 begoff = p - start;
4508 removerecordregions(begoff);
4509 if (quotes)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004510 rmescapes(p + 2);
4511 result = arith(p + 2, &errcode);
Eric Andersen34506362001-08-02 05:02:46 +00004512 if (errcode < 0) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004513 if (errcode == -2)
Eric Andersen34506362001-08-02 05:02:46 +00004514 error("divide by zero");
4515 else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004516 error("syntax error: \"%s\"\n", p + 2);
Eric Andersen34506362001-08-02 05:02:46 +00004517 }
Eric Andersen3102ac42001-07-06 04:26:23 +00004518 snprintf(p, 12, "%d", result);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004519 while (*p++);
Eric Andersencb57d552001-06-28 07:25:16 +00004520
4521 if (quoted == 0)
4522 recordregion(begoff, p - 1 - start, 0);
4523 result = expdest - p + 1;
4524 STADJUST(-result, expdest);
4525}
Eric Andersen2870d962001-07-02 17:27:21 +00004526#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004527
4528/*
4529 * Expand stuff in backwards quotes.
4530 */
4531
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004532static void expbackq(union node *cmd, int quoted, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004533{
4534 volatile struct backcmd in;
4535 int i;
4536 char buf[128];
4537 char *p;
4538 char *dest = expdest;
4539 volatile struct ifsregion saveifs;
4540 struct ifsregion *volatile savelastp;
4541 struct nodelist *volatile saveargbackq;
4542 char lastc;
4543 int startloc = dest - stackblock();
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004544 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +00004545 volatile int saveherefd;
4546 int quotes = flag & (EXP_FULL | EXP_CASE);
4547 struct jmploc jmploc;
4548 struct jmploc *volatile savehandler;
4549 int ex;
4550
4551#if __GNUC__
4552 /* Avoid longjmp clobbering */
4553 (void) &dest;
4554 (void) &syntax;
4555#endif
4556
4557 in.fd = -1;
4558 in.buf = 0;
4559 in.jp = 0;
4560
4561 INTOFF;
4562 saveifs = ifsfirst;
4563 savelastp = ifslastp;
4564 saveargbackq = argbackq;
4565 saveherefd = herefd;
4566 herefd = -1;
4567 if ((ex = setjmp(jmploc.loc))) {
4568 goto err1;
4569 }
4570 savehandler = handler;
4571 handler = &jmploc;
4572 INTON;
4573 p = grabstackstr(dest);
4574 evalbackcmd(cmd, (struct backcmd *) &in);
4575 ungrabstackstr(p, dest);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004576 err1:
Eric Andersencb57d552001-06-28 07:25:16 +00004577 INTOFF;
4578 ifsfirst = saveifs;
4579 ifslastp = savelastp;
4580 argbackq = saveargbackq;
4581 herefd = saveherefd;
4582 if (ex) {
4583 goto err2;
4584 }
4585
4586 p = in.buf;
4587 lastc = '\0';
4588 for (;;) {
4589 if (--in.nleft < 0) {
4590 if (in.fd < 0)
4591 break;
Eric Andersen7467c8d2001-07-12 20:26:32 +00004592 i = safe_read(in.fd, buf, sizeof buf);
Eric Andersencb57d552001-06-28 07:25:16 +00004593 TRACE(("expbackq: read returns %d\n", i));
4594 if (i <= 0)
4595 break;
4596 p = buf;
4597 in.nleft = i - 1;
4598 }
4599 lastc = *p++;
4600 if (lastc != '\0') {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004601 if (quotes && SIT(lastc, syntax) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +00004602 STPUTC(CTLESC, dest);
4603 STPUTC(lastc, dest);
4604 }
4605 }
4606
4607 /* Eat all trailing newlines */
4608 for (; dest > stackblock() && dest[-1] == '\n';)
4609 STUNPUTC(dest);
4610
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004611 err2:
Eric Andersencb57d552001-06-28 07:25:16 +00004612 if (in.fd >= 0)
4613 close(in.fd);
Aaron Lehmann49c024a2002-08-02 06:39:47 +00004614 free(in.buf);
Eric Andersencb57d552001-06-28 07:25:16 +00004615 if (in.jp)
4616 exitstatus = waitforjob(in.jp);
4617 handler = savehandler;
4618 if (ex) {
4619 longjmp(handler->loc, 1);
4620 }
4621 if (quoted == 0)
4622 recordregion(startloc, dest - stackblock(), 0);
4623 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004624 (dest - stackblock()) - startloc,
4625 (dest - stackblock()) - startloc, stackblock() + startloc));
Eric Andersencb57d552001-06-28 07:25:16 +00004626 expdest = dest;
4627 INTON;
4628}
4629
Eric Andersencb57d552001-06-28 07:25:16 +00004630static int
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004631subevalvar(char *p, char *str, int strloc, int subtype, int startloc,
4632 int varflags, int quotes)
Eric Andersencb57d552001-06-28 07:25:16 +00004633{
4634 char *startp;
4635 char *loc = NULL;
4636 char *q;
4637 int c = 0;
4638 int saveherefd = herefd;
4639 struct nodelist *saveargbackq = argbackq;
4640 int amount;
4641
4642 herefd = -1;
4643 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
4644 STACKSTRNUL(expdest);
4645 herefd = saveherefd;
4646 argbackq = saveargbackq;
4647 startp = stackblock() + startloc;
4648 if (str == NULL)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004649 str = stackblock() + strloc;
Eric Andersencb57d552001-06-28 07:25:16 +00004650
4651 switch (subtype) {
4652 case VSASSIGN:
4653 setvar(str, startp, 0);
4654 amount = startp - expdest;
4655 STADJUST(amount, expdest);
4656 varflags &= ~VSNUL;
4657 if (c != 0)
4658 *loc = c;
4659 return 1;
4660
4661 case VSQUESTION:
4662 if (*p != CTLENDVAR) {
Eric Andersen3102ac42001-07-06 04:26:23 +00004663 out2fmt(snlfmt, startp);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004664 error((char *) NULL);
Eric Andersencb57d552001-06-28 07:25:16 +00004665 }
4666 error("%.*s: parameter %snot set", p - str - 1,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004667 str, (varflags & VSNUL) ? "null or " : nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +00004668 /* NOTREACHED */
4669
4670 case VSTRIMLEFT:
4671 for (loc = startp; loc < str; loc++) {
4672 c = *loc;
4673 *loc = '\0';
4674 if (patmatch2(str, startp, quotes))
4675 goto recordleft;
4676 *loc = c;
4677 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00004678 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00004679 }
4680 return 0;
4681
4682 case VSTRIMLEFTMAX:
4683 for (loc = str - 1; loc >= startp;) {
4684 c = *loc;
4685 *loc = '\0';
4686 if (patmatch2(str, startp, quotes))
4687 goto recordleft;
4688 *loc = c;
4689 loc--;
4690 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
4691 for (q = startp; q < loc; q++)
4692 if (*q == CTLESC)
4693 q++;
4694 if (q > loc)
4695 loc--;
4696 }
4697 }
4698 return 0;
4699
4700 case VSTRIMRIGHT:
Eric Andersen2870d962001-07-02 17:27:21 +00004701 for (loc = str - 1; loc >= startp;) {
Eric Andersencb57d552001-06-28 07:25:16 +00004702 if (patmatch2(str, loc, quotes))
4703 goto recordright;
4704 loc--;
Eric Andersen2870d962001-07-02 17:27:21 +00004705 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
Eric Andersencb57d552001-06-28 07:25:16 +00004706 for (q = startp; q < loc; q++)
4707 if (*q == CTLESC)
4708 q++;
4709 if (q > loc)
4710 loc--;
4711 }
4712 }
4713 return 0;
4714
4715 case VSTRIMRIGHTMAX:
4716 for (loc = startp; loc < str - 1; loc++) {
4717 if (patmatch2(str, loc, quotes))
4718 goto recordright;
4719 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00004720 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00004721 }
4722 return 0;
4723
4724#ifdef DEBUG
4725 default:
4726 abort();
4727#endif
4728 }
4729
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004730 recordleft:
Eric Andersencb57d552001-06-28 07:25:16 +00004731 *loc = c;
4732 amount = ((str - 1) - (loc - startp)) - expdest;
4733 STADJUST(amount, expdest);
4734 while (loc != str - 1)
4735 *startp++ = *loc++;
4736 return 1;
4737
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004738 recordright:
Eric Andersencb57d552001-06-28 07:25:16 +00004739 amount = loc - expdest;
4740 STADJUST(amount, expdest);
4741 STPUTC('\0', expdest);
4742 STADJUST(-1, expdest);
4743 return 1;
4744}
4745
4746
4747/*
Eric Andersencb57d552001-06-28 07:25:16 +00004748 * Test whether a specialized variable is set.
4749 */
4750
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004751static int varisset(char *name, int nulok)
Eric Andersencb57d552001-06-28 07:25:16 +00004752{
4753 if (*name == '!')
4754 return backgndpid != -1;
4755 else if (*name == '@' || *name == '*') {
4756 if (*shellparam.p == NULL)
4757 return 0;
4758
4759 if (nulok) {
4760 char **av;
4761
4762 for (av = shellparam.p; *av; av++)
4763 if (**av != '\0')
4764 return 1;
4765 return 0;
4766 }
4767 } else if (is_digit(*name)) {
4768 char *ap;
4769 int num = atoi(name);
4770
4771 if (num > shellparam.nparam)
4772 return 0;
4773
4774 if (num == 0)
4775 ap = arg0;
4776 else
4777 ap = shellparam.p[num - 1];
4778
4779 if (nulok && (ap == NULL || *ap == '\0'))
4780 return 0;
4781 }
4782 return 1;
4783}
4784
Eric Andersencb57d552001-06-28 07:25:16 +00004785/*
4786 * Put a string on the stack.
4787 */
4788
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004789static void strtodest(const char *p, int syntax, int quotes)
Eric Andersencb57d552001-06-28 07:25:16 +00004790{
4791 while (*p) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004792 if (quotes && SIT(*p, syntax) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +00004793 STPUTC(CTLESC, expdest);
4794 STPUTC(*p++, expdest);
4795 }
4796}
4797
Eric Andersencb57d552001-06-28 07:25:16 +00004798/*
4799 * Add the value of a specialized variable to the stack string.
4800 */
4801
Glenn L McGrath50812ff2002-08-23 13:14:48 +00004802static void varvalue(char *name, int quoted, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00004803{
4804 int num;
4805 char *p;
4806 int i;
4807 int sep;
4808 int sepq = 0;
4809 char **ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004810 int syntax;
Eric Andersencb57d552001-06-28 07:25:16 +00004811 int allow_split = flags & EXP_FULL;
4812 int quotes = flags & (EXP_FULL | EXP_CASE);
4813
4814 syntax = quoted ? DQSYNTAX : BASESYNTAX;
4815 switch (*name) {
4816 case '$':
4817 num = rootpid;
4818 goto numvar;
4819 case '?':
4820 num = oexitstatus;
4821 goto numvar;
4822 case '#':
4823 num = shellparam.nparam;
4824 goto numvar;
4825 case '!':
4826 num = backgndpid;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004827 numvar:
Eric Andersencb57d552001-06-28 07:25:16 +00004828 expdest = cvtnum(num, expdest);
4829 break;
4830 case '-':
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004831 for (i = 0; i < NOPTS; i++) {
Eric Andersen2870d962001-07-02 17:27:21 +00004832 if (optent_val(i))
4833 STPUTC(optent_letter(optlist[i]), expdest);
Eric Andersencb57d552001-06-28 07:25:16 +00004834 }
4835 break;
4836 case '@':
4837 if (allow_split && quoted) {
4838 sep = 1 << CHAR_BIT;
4839 goto param;
4840 }
4841 /* fall through */
4842 case '*':
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004843 sep = ifsset()? ifsval()[0] : ' ';
Eric Andersencb57d552001-06-28 07:25:16 +00004844 if (quotes) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004845 sepq = SIT(sep, syntax) == CCTL;
Eric Andersencb57d552001-06-28 07:25:16 +00004846 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004847 param:
4848 for (ap = shellparam.p; (p = *ap++) != NULL;) {
Eric Andersencb57d552001-06-28 07:25:16 +00004849 strtodest(p, syntax, quotes);
4850 if (*ap && sep) {
4851 if (sepq)
4852 STPUTC(CTLESC, expdest);
4853 STPUTC(sep, expdest);
4854 }
4855 }
4856 break;
4857 case '0':
4858 strtodest(arg0, syntax, quotes);
4859 break;
4860 default:
4861 num = atoi(name);
4862 if (num > 0 && num <= shellparam.nparam) {
4863 strtodest(shellparam.p[num - 1], syntax, quotes);
4864 }
4865 break;
4866 }
4867}
4868
4869
Eric Andersencb57d552001-06-28 07:25:16 +00004870/*
4871 * Record the fact that we have to scan this region of the
4872 * string for IFS characters.
4873 */
4874
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004875static void recordregion(int start, int end, int nulonly)
Eric Andersencb57d552001-06-28 07:25:16 +00004876{
4877 struct ifsregion *ifsp;
4878
4879 if (ifslastp == NULL) {
4880 ifsp = &ifsfirst;
4881 } else {
4882 INTOFF;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004883 ifsp = (struct ifsregion *) xmalloc(sizeof(struct ifsregion));
Eric Andersencb57d552001-06-28 07:25:16 +00004884 ifsp->next = NULL;
4885 ifslastp->next = ifsp;
4886 INTON;
4887 }
4888 ifslastp = ifsp;
4889 ifslastp->begoff = start;
4890 ifslastp->endoff = end;
4891 ifslastp->nulonly = nulonly;
4892}
4893
4894
4895
4896/*
4897 * Break the argument string into pieces based upon IFS and add the
4898 * strings to the argument list. The regions of the string to be
4899 * searched for IFS characters have been stored by recordregion.
4900 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004901static void ifsbreakup(char *string, struct arglist *arglist)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004902{
Eric Andersencb57d552001-06-28 07:25:16 +00004903 struct ifsregion *ifsp;
4904 struct strlist *sp;
4905 char *start;
4906 char *p;
4907 char *q;
4908 const char *ifs, *realifs;
4909 int ifsspc;
4910 int nulonly;
4911
4912
4913 start = string;
4914 ifsspc = 0;
4915 nulonly = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004916 realifs = ifsset()? ifsval() : defifs;
Eric Andersencb57d552001-06-28 07:25:16 +00004917 if (ifslastp != NULL) {
4918 ifsp = &ifsfirst;
4919 do {
4920 p = string + ifsp->begoff;
4921 nulonly = ifsp->nulonly;
4922 ifs = nulonly ? nullstr : realifs;
4923 ifsspc = 0;
4924 while (p < string + ifsp->endoff) {
4925 q = p;
4926 if (*p == CTLESC)
4927 p++;
4928 if (strchr(ifs, *p)) {
4929 if (!nulonly)
4930 ifsspc = (strchr(defifs, *p) != NULL);
4931 /* Ignore IFS whitespace at start */
4932 if (q == start && ifsspc) {
4933 p++;
4934 start = p;
4935 continue;
4936 }
4937 *q = '\0';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004938 sp = (struct strlist *) stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00004939 sp->text = start;
4940 *arglist->lastp = sp;
4941 arglist->lastp = &sp->next;
4942 p++;
4943 if (!nulonly) {
4944 for (;;) {
4945 if (p >= string + ifsp->endoff) {
4946 break;
4947 }
4948 q = p;
4949 if (*p == CTLESC)
4950 p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004951 if (strchr(ifs, *p) == NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00004952 p = q;
4953 break;
4954 } else if (strchr(defifs, *p) == NULL) {
4955 if (ifsspc) {
4956 p++;
4957 ifsspc = 0;
4958 } else {
4959 p = q;
4960 break;
4961 }
4962 } else
4963 p++;
4964 }
4965 }
4966 start = p;
4967 } else
4968 p++;
4969 }
4970 } while ((ifsp = ifsp->next) != NULL);
4971 if (!(*start || (!ifsspc && start > string && nulonly))) {
4972 return;
4973 }
4974 }
4975
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004976 sp = (struct strlist *) stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00004977 sp->text = start;
4978 *arglist->lastp = sp;
4979 arglist->lastp = &sp->next;
4980}
4981
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004982static void ifsfree(void)
Eric Andersencb57d552001-06-28 07:25:16 +00004983{
4984 while (ifsfirst.next != NULL) {
4985 struct ifsregion *ifsp;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004986
Eric Andersencb57d552001-06-28 07:25:16 +00004987 INTOFF;
4988 ifsp = ifsfirst.next->next;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00004989 free(ifsfirst.next);
Eric Andersencb57d552001-06-28 07:25:16 +00004990 ifsfirst.next = ifsp;
4991 INTON;
4992 }
4993 ifslastp = NULL;
4994 ifsfirst.next = NULL;
4995}
4996
Eric Andersen2870d962001-07-02 17:27:21 +00004997/*
4998 * Add a file name to the list.
4999 */
Eric Andersencb57d552001-06-28 07:25:16 +00005000
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005001static void addfname(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00005002{
Eric Andersen2870d962001-07-02 17:27:21 +00005003 struct strlist *sp;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00005004 size_t len = strlen(name) + 1;
Eric Andersen2870d962001-07-02 17:27:21 +00005005
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005006 sp = (struct strlist *) stalloc(sizeof *sp);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00005007 sp->text = memcpy(stalloc(len), name, len);
Eric Andersen2870d962001-07-02 17:27:21 +00005008 *exparg.lastp = sp;
5009 exparg.lastp = &sp->next;
5010}
Eric Andersencb57d552001-06-28 07:25:16 +00005011
5012/*
5013 * Expand shell metacharacters. At this point, the only control characters
5014 * should be escapes. The results are stored in the list exparg.
5015 */
5016
Eric Andersen62483552001-07-10 06:09:16 +00005017#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005018static void expandmeta(struct strlist *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005019{
5020 const char *p;
5021 glob_t pglob;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005022
Eric Andersencb57d552001-06-28 07:25:16 +00005023 /* TODO - EXP_REDIR */
5024
5025 while (str) {
5026 if (fflag)
5027 goto nometa;
5028 p = preglob(str->text);
5029 INTOFF;
Eric Andersen34506362001-08-02 05:02:46 +00005030 switch (glob(p, 0, 0, &pglob)) {
Eric Andersencb57d552001-06-28 07:25:16 +00005031 case 0:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005032 if (pglob.gl_pathv[1] == 0 && !strcmp(p, pglob.gl_pathv[0]))
Eric Andersencb57d552001-06-28 07:25:16 +00005033 goto nometa2;
5034 addglob(&pglob);
5035 globfree(&pglob);
5036 INTON;
5037 break;
5038 case GLOB_NOMATCH:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005039 nometa2:
Eric Andersencb57d552001-06-28 07:25:16 +00005040 globfree(&pglob);
5041 INTON;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005042 nometa:
Eric Andersencb57d552001-06-28 07:25:16 +00005043 *exparg.lastp = str;
5044 rmescapes(str->text);
5045 exparg.lastp = &str->next;
5046 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005047 default: /* GLOB_NOSPACE */
Eric Andersencb57d552001-06-28 07:25:16 +00005048 error("Out of space");
5049 }
5050 str = str->next;
5051 }
5052}
5053
5054
5055/*
5056 * Add the result of glob(3) to the list.
5057 */
5058
Glenn L McGrath50812ff2002-08-23 13:14:48 +00005059static void addglob(const glob_t * pglob)
Eric Andersencb57d552001-06-28 07:25:16 +00005060{
5061 char **p = pglob->gl_pathv;
5062
5063 do {
5064 addfname(*p);
5065 } while (*++p);
5066}
5067
5068
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005069#else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005070static char *expdir;
5071
5072
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005073static void expandmeta(struct strlist *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005074{
5075 char *p;
5076 struct strlist **savelastp;
5077 struct strlist *sp;
5078 char c;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005079
Eric Andersencb57d552001-06-28 07:25:16 +00005080 /* TODO - EXP_REDIR */
5081
5082 while (str) {
5083 if (fflag)
5084 goto nometa;
5085 p = str->text;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005086 for (;;) { /* fast check for meta chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005087 if ((c = *p++) == '\0')
5088 goto nometa;
5089 if (c == '*' || c == '?' || c == '[' || c == '!')
5090 break;
5091 }
5092 savelastp = exparg.lastp;
5093 INTOFF;
5094 if (expdir == NULL) {
5095 int i = strlen(str->text);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005096
5097 expdir = xmalloc(i < 2048 ? 2048 : i); /* XXX */
Eric Andersencb57d552001-06-28 07:25:16 +00005098 }
5099
5100 expmeta(expdir, str->text);
Aaron Lehmann49c024a2002-08-02 06:39:47 +00005101 free(expdir);
Eric Andersencb57d552001-06-28 07:25:16 +00005102 expdir = NULL;
5103 INTON;
5104 if (exparg.lastp == savelastp) {
5105 /*
5106 * no matches
5107 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005108 nometa:
Eric Andersencb57d552001-06-28 07:25:16 +00005109 *exparg.lastp = str;
5110 rmescapes(str->text);
5111 exparg.lastp = &str->next;
5112 } else {
5113 *exparg.lastp = NULL;
5114 *savelastp = sp = expsort(*savelastp);
5115 while (sp->next != NULL)
5116 sp = sp->next;
5117 exparg.lastp = &sp->next;
5118 }
5119 str = str->next;
5120 }
5121}
5122
5123
5124/*
5125 * Do metacharacter (i.e. *, ?, [...]) expansion.
5126 */
5127
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005128static void expmeta(char *enddir, char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005129{
Eric Andersencb57d552001-06-28 07:25:16 +00005130 char *p;
5131 const char *cp;
5132 char *q;
5133 char *start;
5134 char *endname;
5135 int metaflag;
5136 struct stat statb;
5137 DIR *dirp;
5138 struct dirent *dp;
5139 int atend;
5140 int matchdot;
5141
5142 metaflag = 0;
5143 start = name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005144 for (p = name;; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +00005145 if (*p == '*' || *p == '?')
5146 metaflag = 1;
5147 else if (*p == '[') {
5148 q = p + 1;
5149 if (*q == '!')
5150 q++;
5151 for (;;) {
5152 while (*q == CTLQUOTEMARK)
5153 q++;
5154 if (*q == CTLESC)
5155 q++;
5156 if (*q == '/' || *q == '\0')
5157 break;
5158 if (*++q == ']') {
5159 metaflag = 1;
5160 break;
5161 }
5162 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005163 } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) {
Eric Andersencb57d552001-06-28 07:25:16 +00005164 metaflag = 1;
5165 } else if (*p == '\0')
5166 break;
5167 else if (*p == CTLQUOTEMARK)
5168 continue;
5169 else if (*p == CTLESC)
5170 p++;
5171 if (*p == '/') {
5172 if (metaflag)
5173 break;
5174 start = p + 1;
5175 }
5176 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005177 if (metaflag == 0) { /* we've reached the end of the file name */
Eric Andersencb57d552001-06-28 07:25:16 +00005178 if (enddir != expdir)
5179 metaflag++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005180 for (p = name;; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +00005181 if (*p == CTLQUOTEMARK)
5182 continue;
5183 if (*p == CTLESC)
5184 p++;
5185 *enddir++ = *p;
5186 if (*p == '\0')
5187 break;
5188 }
5189 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5190 addfname(expdir);
5191 return;
5192 }
5193 endname = p;
5194 if (start != name) {
5195 p = name;
5196 while (p < start) {
5197 while (*p == CTLQUOTEMARK)
5198 p++;
5199 if (*p == CTLESC)
5200 p++;
5201 *enddir++ = *p++;
5202 }
5203 }
5204 if (enddir == expdir) {
5205 cp = ".";
5206 } else if (enddir == expdir + 1 && *expdir == '/') {
5207 cp = "/";
5208 } else {
5209 cp = expdir;
5210 enddir[-1] = '\0';
5211 }
5212 if ((dirp = opendir(cp)) == NULL)
5213 return;
5214 if (enddir != expdir)
5215 enddir[-1] = '/';
5216 if (*endname == 0) {
5217 atend = 1;
5218 } else {
5219 atend = 0;
5220 *endname++ = '\0';
5221 }
5222 matchdot = 0;
5223 p = start;
5224 while (*p == CTLQUOTEMARK)
5225 p++;
5226 if (*p == CTLESC)
5227 p++;
5228 if (*p == '.')
5229 matchdot++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005230 while (!int_pending() && (dp = readdir(dirp)) != NULL) {
5231 if (dp->d_name[0] == '.' && !matchdot)
Eric Andersencb57d552001-06-28 07:25:16 +00005232 continue;
5233 if (patmatch(start, dp->d_name, 0)) {
5234 if (atend) {
Eric Andersen2870d962001-07-02 17:27:21 +00005235 strcpy(enddir, dp->d_name);
Eric Andersencb57d552001-06-28 07:25:16 +00005236 addfname(expdir);
5237 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005238 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
Eric Andersencb57d552001-06-28 07:25:16 +00005239 continue;
5240 p[-1] = '/';
5241 expmeta(p, endname);
5242 }
5243 }
5244 }
5245 closedir(dirp);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005246 if (!atend)
Eric Andersencb57d552001-06-28 07:25:16 +00005247 endname[-1] = '/';
5248}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005249#endif /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005250
5251
Eric Andersencb57d552001-06-28 07:25:16 +00005252
Eric Andersen62483552001-07-10 06:09:16 +00005253#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersencb57d552001-06-28 07:25:16 +00005254/*
5255 * Sort the results of file name expansion. It calculates the number of
5256 * strings to sort and then calls msort (short for merge sort) to do the
5257 * work.
5258 */
5259
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005260static struct strlist *expsort(struct strlist *str)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005261{
Eric Andersencb57d552001-06-28 07:25:16 +00005262 int len;
5263 struct strlist *sp;
5264
5265 len = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005266 for (sp = str; sp; sp = sp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00005267 len++;
5268 return msort(str, len);
5269}
5270
5271
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005272static struct strlist *msort(struct strlist *list, int len)
Eric Andersencb57d552001-06-28 07:25:16 +00005273{
5274 struct strlist *p, *q = NULL;
5275 struct strlist **lpp;
5276 int half;
5277 int n;
5278
5279 if (len <= 1)
5280 return list;
5281 half = len >> 1;
5282 p = list;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005283 for (n = half; --n >= 0;) {
Eric Andersencb57d552001-06-28 07:25:16 +00005284 q = p;
5285 p = p->next;
5286 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005287 q->next = NULL; /* terminate first half of list */
5288 q = msort(list, half); /* sort first half of list */
5289 p = msort(p, len - half); /* sort second half */
Eric Andersencb57d552001-06-28 07:25:16 +00005290 lpp = &list;
5291 for (;;) {
5292 if (strcmp(p->text, q->text) < 0) {
5293 *lpp = p;
5294 lpp = &p->next;
5295 if ((p = *lpp) == NULL) {
5296 *lpp = q;
5297 break;
5298 }
5299 } else {
5300 *lpp = q;
5301 lpp = &q->next;
5302 if ((q = *lpp) == NULL) {
5303 *lpp = p;
5304 break;
5305 }
5306 }
5307 }
5308 return list;
5309}
5310#endif
5311
5312
5313
5314/*
5315 * Returns true if the pattern matches the string.
5316 */
5317
Eric Andersen62483552001-07-10 06:09:16 +00005318#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00005319/* squoted: string might have quote chars */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005320static int patmatch(char *pattern, char *string, int squoted)
Eric Andersen2870d962001-07-02 17:27:21 +00005321{
Eric Andersencb57d552001-06-28 07:25:16 +00005322 const char *p;
5323 char *q;
5324
5325 p = preglob(pattern);
5326 q = squoted ? _rmescapes(string, RMESCAPE_ALLOC) : string;
5327
5328 return !fnmatch(p, q, 0);
5329}
5330
5331
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005332static int patmatch2(char *pattern, char *string, int squoted)
Eric Andersen2870d962001-07-02 17:27:21 +00005333{
Eric Andersencb57d552001-06-28 07:25:16 +00005334 char *p;
5335 int res;
5336
5337 sstrnleft--;
5338 p = grabstackstr(expdest);
5339 res = patmatch(pattern, string, squoted);
5340 ungrabstackstr(p, expdest);
5341 return res;
5342}
5343#else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005344static int patmatch(char *pattern, char *string, int squoted)
5345{
Eric Andersen2870d962001-07-02 17:27:21 +00005346 return pmatch(pattern, string, squoted);
Eric Andersencb57d552001-06-28 07:25:16 +00005347}
5348
5349
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005350static int pmatch(char *pattern, char *string, int squoted)
Eric Andersen2870d962001-07-02 17:27:21 +00005351{
Eric Andersencb57d552001-06-28 07:25:16 +00005352 char *p, *q;
5353 char c;
5354
5355 p = pattern;
5356 q = string;
5357 for (;;) {
5358 switch (c = *p++) {
5359 case '\0':
5360 goto breakloop;
5361 case CTLESC:
5362 if (squoted && *q == CTLESC)
5363 q++;
5364 if (*q++ != *p++)
5365 return 0;
5366 break;
5367 case CTLQUOTEMARK:
5368 continue;
5369 case '?':
5370 if (squoted && *q == CTLESC)
5371 q++;
5372 if (*q++ == '\0')
5373 return 0;
5374 break;
5375 case '*':
5376 c = *p;
5377 while (c == CTLQUOTEMARK || c == '*')
5378 c = *++p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005379 if (c != CTLESC && c != CTLQUOTEMARK &&
5380 c != '?' && c != '*' && c != '[') {
Eric Andersencb57d552001-06-28 07:25:16 +00005381 while (*q != c) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005382 if (squoted && *q == CTLESC && q[1] == c)
Eric Andersencb57d552001-06-28 07:25:16 +00005383 break;
5384 if (*q == '\0')
5385 return 0;
5386 if (squoted && *q == CTLESC)
5387 q++;
5388 q++;
5389 }
5390 }
5391 do {
5392 if (pmatch(p, q, squoted))
5393 return 1;
5394 if (squoted && *q == CTLESC)
5395 q++;
5396 } while (*q++ != '\0');
5397 return 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005398 case '[':{
Eric Andersencb57d552001-06-28 07:25:16 +00005399 char *endp;
5400 int invert, found;
5401 char chr;
5402
5403 endp = p;
5404 if (*endp == '!')
5405 endp++;
5406 for (;;) {
5407 while (*endp == CTLQUOTEMARK)
5408 endp++;
5409 if (*endp == '\0')
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005410 goto dft; /* no matching ] */
Eric Andersencb57d552001-06-28 07:25:16 +00005411 if (*endp == CTLESC)
5412 endp++;
5413 if (*++endp == ']')
5414 break;
5415 }
5416 invert = 0;
5417 if (*p == '!') {
5418 invert++;
5419 p++;
5420 }
5421 found = 0;
5422 chr = *q++;
5423 if (squoted && chr == CTLESC)
5424 chr = *q++;
5425 if (chr == '\0')
5426 return 0;
5427 c = *p++;
5428 do {
5429 if (c == CTLQUOTEMARK)
5430 continue;
5431 if (c == CTLESC)
5432 c = *p++;
5433 if (*p == '-' && p[1] != ']') {
5434 p++;
5435 while (*p == CTLQUOTEMARK)
5436 p++;
5437 if (*p == CTLESC)
5438 p++;
5439 if (chr >= c && chr <= *p)
5440 found = 1;
5441 p++;
5442 } else {
5443 if (chr == c)
5444 found = 1;
5445 }
5446 } while ((c = *p++) != ']');
5447 if (found == invert)
5448 return 0;
5449 break;
5450 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005451 dft: default:
Eric Andersencb57d552001-06-28 07:25:16 +00005452 if (squoted && *q == CTLESC)
5453 q++;
5454 if (*q++ != c)
5455 return 0;
5456 break;
5457 }
5458 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005459 breakloop:
Eric Andersencb57d552001-06-28 07:25:16 +00005460 if (*q != '\0')
5461 return 0;
5462 return 1;
5463}
5464#endif
5465
5466
5467
5468/*
5469 * Remove any CTLESC characters from a string.
5470 */
5471
Eric Andersen62483552001-07-10 06:09:16 +00005472#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005473static char *_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005474{
5475 char *p, *q, *r;
5476 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5477
5478 p = strpbrk(str, qchars);
5479 if (!p) {
5480 return str;
5481 }
5482 q = p;
5483 r = str;
5484 if (flag & RMESCAPE_ALLOC) {
5485 size_t len = p - str;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005486
Eric Andersencb57d552001-06-28 07:25:16 +00005487 q = r = stalloc(strlen(p) + len + 1);
5488 if (len > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00005489 memcpy(q, str, len);
5490 q += len;
Eric Andersencb57d552001-06-28 07:25:16 +00005491 }
5492 }
5493 while (*p) {
5494 if (*p == CTLQUOTEMARK) {
5495 p++;
5496 continue;
5497 }
5498 if (*p == CTLESC) {
5499 p++;
5500 if (flag & RMESCAPE_GLOB && *p != '/') {
5501 *q++ = '\\';
5502 }
5503 }
5504 *q++ = *p++;
5505 }
5506 *q = '\0';
5507 return r;
5508}
5509#else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005510static void rmescapes(char *str)
Eric Andersencb57d552001-06-28 07:25:16 +00005511{
5512 char *p, *q;
5513
5514 p = str;
5515 while (*p != CTLESC && *p != CTLQUOTEMARK) {
5516 if (*p++ == '\0')
5517 return;
5518 }
5519 q = p;
5520 while (*p) {
5521 if (*p == CTLQUOTEMARK) {
5522 p++;
5523 continue;
5524 }
5525 if (*p == CTLESC)
5526 p++;
5527 *q++ = *p++;
5528 }
5529 *q = '\0';
5530}
5531#endif
5532
5533
5534
5535/*
5536 * See if a pattern matches in a case statement.
5537 */
5538
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005539static int casematch(union node *pattern, const char *val)
Eric Andersen2870d962001-07-02 17:27:21 +00005540{
Eric Andersencb57d552001-06-28 07:25:16 +00005541 struct stackmark smark;
5542 int result;
5543 char *p;
5544
5545 setstackmark(&smark);
5546 argbackq = pattern->narg.backquote;
5547 STARTSTACKSTR(expdest);
5548 ifslastp = NULL;
5549 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5550 STPUTC('\0', expdest);
5551 p = grabstackstr(expdest);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005552 result = patmatch(p, (char *) val, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00005553 popstackmark(&smark);
5554 return result;
5555}
5556
5557/*
5558 * Our own itoa().
5559 */
5560
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005561static char *cvtnum(int num, char *buf)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005562{
Eric Andersencb57d552001-06-28 07:25:16 +00005563 int len;
5564
5565 CHECKSTRSPACE(32, buf);
5566 len = sprintf(buf, "%d", num);
5567 STADJUST(len, buf);
5568 return buf;
5569}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005570
Eric Andersencb57d552001-06-28 07:25:16 +00005571/*
5572 * Editline and history functions (and glue).
5573 */
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005574static int histcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00005575{
5576 error("not compiled with history support");
5577 /* NOTREACHED */
5578}
5579
5580
Eric Andersencb57d552001-06-28 07:25:16 +00005581struct redirtab {
5582 struct redirtab *next;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005583 short renamed[10]; /* Current ash support only 0-9 descriptors */
Eric Andersen34506362001-08-02 05:02:46 +00005584 /* char on arm (and others) can't be negative */
Eric Andersencb57d552001-06-28 07:25:16 +00005585};
5586
Eric Andersen2870d962001-07-02 17:27:21 +00005587static struct redirtab *redirlist;
Eric Andersencb57d552001-06-28 07:25:16 +00005588
5589extern char **environ;
5590
5591
5592
5593/*
5594 * Initialization code.
5595 */
5596
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005597static void init(void)
5598{
Eric Andersencb57d552001-06-28 07:25:16 +00005599
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005600 /* from cd.c: */
5601 {
5602 curdir = nullstr;
5603 setpwd(0, 0);
5604 }
Eric Andersencb57d552001-06-28 07:25:16 +00005605
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005606 /* from input.c: */
5607 {
5608 basepf.nextc = basepf.buf = basebuf;
5609 }
Eric Andersencb57d552001-06-28 07:25:16 +00005610
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005611 /* from var.c: */
5612 {
5613 char **envp;
5614 char ppid[32];
Eric Andersencb57d552001-06-28 07:25:16 +00005615
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005616 initvar();
5617 for (envp = environ; *envp; envp++) {
5618 if (strchr(*envp, '=')) {
5619 setvareq(*envp, VEXPORT | VTEXTFIXED);
5620 }
5621 }
Eric Andersencb57d552001-06-28 07:25:16 +00005622
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005623 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
5624 setvar("PPID", ppid, 0);
5625 }
Eric Andersencb57d552001-06-28 07:25:16 +00005626}
5627
5628
5629
5630/*
5631 * This routine is called when an error or an interrupt occurs in an
5632 * interactive shell and control is returned to the main command loop.
5633 */
5634
Eric Andersen2870d962001-07-02 17:27:21 +00005635/* 1 == check for aliases, 2 == also check for assignments */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005636static int checkalias; /* also used in no alias mode for check assignments */
Eric Andersen2870d962001-07-02 17:27:21 +00005637
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005638static void reset(void)
5639{
Eric Andersencb57d552001-06-28 07:25:16 +00005640
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005641 /* from eval.c: */
5642 {
5643 evalskip = 0;
5644 loopnest = 0;
5645 funcnest = 0;
5646 }
Eric Andersencb57d552001-06-28 07:25:16 +00005647
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005648 /* from input.c: */
5649 {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00005650 parselleft = parsenleft = 0; /* clear input buffer */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005651 popallfiles();
5652 }
Eric Andersencb57d552001-06-28 07:25:16 +00005653
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005654 /* from parser.c: */
5655 {
5656 tokpushback = 0;
5657 checkkwd = 0;
5658 checkalias = 0;
5659 }
Eric Andersencb57d552001-06-28 07:25:16 +00005660
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005661 /* from redir.c: */
5662 {
5663 while (redirlist)
5664 popredir();
5665 }
Eric Andersencb57d552001-06-28 07:25:16 +00005666
Eric Andersencb57d552001-06-28 07:25:16 +00005667}
5668
5669
5670
5671/*
Eric Andersencb57d552001-06-28 07:25:16 +00005672 * This file implements the input routines used by the parser.
5673 */
5674
Eric Andersenbdfd0d72001-10-24 05:00:29 +00005675#ifdef CONFIG_FEATURE_COMMAND_EDITING
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005676static const char *cmdedit_prompt;
5677static inline void putprompt(const char *s)
5678{
5679 cmdedit_prompt = s;
Eric Andersencb57d552001-06-28 07:25:16 +00005680}
5681#else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005682static inline void putprompt(const char *s)
5683{
5684 out2str(s);
Eric Andersencb57d552001-06-28 07:25:16 +00005685}
5686#endif
5687
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005688#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
Eric Andersencb57d552001-06-28 07:25:16 +00005689
Eric Andersencb57d552001-06-28 07:25:16 +00005690
Eric Andersencb57d552001-06-28 07:25:16 +00005691
Eric Andersen2870d962001-07-02 17:27:21 +00005692/*
5693 * Same as pgetc(), but ignores PEOA.
5694 */
Eric Andersencb57d552001-06-28 07:25:16 +00005695
Eric Andersend35c5df2002-01-09 15:37:36 +00005696#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005697static int pgetc2(void)
Eric Andersen2870d962001-07-02 17:27:21 +00005698{
5699 int c;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005700
Eric Andersen2870d962001-07-02 17:27:21 +00005701 do {
5702 c = pgetc_macro();
5703 } while (c == PEOA);
5704 return c;
Eric Andersencb57d552001-06-28 07:25:16 +00005705}
Eric Andersen2870d962001-07-02 17:27:21 +00005706#else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005707static inline int pgetc2(void)
5708{
5709 return pgetc_macro();
5710}
Eric Andersencb57d552001-06-28 07:25:16 +00005711#endif
5712
Eric Andersencb57d552001-06-28 07:25:16 +00005713/*
5714 * Read a line from the script.
5715 */
5716
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005717static inline char *pfgets(char *line, int len)
Eric Andersencb57d552001-06-28 07:25:16 +00005718{
5719 char *p = line;
5720 int nleft = len;
5721 int c;
5722
5723 while (--nleft > 0) {
5724 c = pgetc2();
5725 if (c == PEOF) {
5726 if (p == line)
5727 return NULL;
5728 break;
5729 }
5730 *p++ = c;
5731 if (c == '\n')
5732 break;
5733 }
5734 *p = '\0';
5735 return line;
5736}
5737
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005738static inline int preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005739{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005740 int nr;
5741 char *buf = parsefile->buf;
Eric Andersencb57d552001-06-28 07:25:16 +00005742
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005743 parsenextc = buf;
5744
5745 retry:
Eric Andersenbdfd0d72001-10-24 05:00:29 +00005746#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersencb57d552001-06-28 07:25:16 +00005747 {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005748 if (!iflag || parsefile->fd)
5749 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
5750 else {
5751 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
5752 }
Eric Andersencb57d552001-06-28 07:25:16 +00005753 }
5754#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00005755 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00005756#endif
5757
5758 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00005759 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
5760 int flags = fcntl(0, F_GETFL, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005761
Eric Andersencb57d552001-06-28 07:25:16 +00005762 if (flags >= 0 && flags & O_NONBLOCK) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005763 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00005764 if (fcntl(0, F_SETFL, flags) >= 0) {
5765 out2str("sh: turning off NDELAY mode\n");
5766 goto retry;
5767 }
5768 }
5769 }
5770 }
5771 return nr;
5772}
5773
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005774static void popstring(void)
Eric Andersen2870d962001-07-02 17:27:21 +00005775{
5776 struct strpush *sp = parsefile->strpush;
5777
5778 INTOFF;
Eric Andersend35c5df2002-01-09 15:37:36 +00005779#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00005780 if (sp->ap) {
5781 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
5782 if (!checkalias) {
5783 checkalias = 1;
5784 }
5785 }
5786 if (sp->string != sp->ap->val) {
Aaron Lehmann49c024a2002-08-02 06:39:47 +00005787 free(sp->string);
Eric Andersen2870d962001-07-02 17:27:21 +00005788 }
5789
5790 sp->ap->flag &= ~ALIASINUSE;
5791 if (sp->ap->flag & ALIASDEAD) {
5792 unalias(sp->ap->name);
5793 }
5794 }
5795#endif
5796 parsenextc = sp->prevstring;
5797 parsenleft = sp->prevnleft;
5798/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
5799 parsefile->strpush = sp->prev;
5800 if (sp != &(parsefile->basestrpush))
Aaron Lehmann49c024a2002-08-02 06:39:47 +00005801 free(sp);
Eric Andersen2870d962001-07-02 17:27:21 +00005802 INTON;
5803}
5804
5805
Eric Andersencb57d552001-06-28 07:25:16 +00005806/*
5807 * Refill the input buffer and return the next input character:
5808 *
5809 * 1) If a string was pushed back on the input, pop it;
5810 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
5811 * from a string so we can't refill the buffer, return EOF.
5812 * 3) If the is more stuff in this buffer, use it else call read to fill it.
5813 * 4) Process input up to the next newline, deleting nul characters.
5814 */
5815
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005816static int preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005817{
5818 char *p, *q;
5819 int more;
5820 char savec;
5821
5822 while (parsefile->strpush) {
Eric Andersend35c5df2002-01-09 15:37:36 +00005823#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00005824 if (parsenleft == -1 && parsefile->strpush->ap &&
5825 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00005826 return PEOA;
5827 }
Eric Andersen2870d962001-07-02 17:27:21 +00005828#endif
Eric Andersencb57d552001-06-28 07:25:16 +00005829 popstring();
5830 if (--parsenleft >= 0)
5831 return (*parsenextc++);
5832 }
5833 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
5834 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00005835 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00005836
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005837 again:
Eric Andersencb57d552001-06-28 07:25:16 +00005838 if (parselleft <= 0) {
5839 if ((parselleft = preadfd()) <= 0) {
5840 parselleft = parsenleft = EOF_NLEFT;
5841 return PEOF;
5842 }
5843 }
5844
5845 q = p = parsenextc;
5846
5847 /* delete nul characters */
5848 for (more = 1; more;) {
5849 switch (*p) {
5850 case '\0':
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005851 p++; /* Skip nul */
Eric Andersencb57d552001-06-28 07:25:16 +00005852 goto check;
5853
5854
5855 case '\n':
5856 parsenleft = q - parsenextc;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005857 more = 0; /* Stop processing here */
Eric Andersencb57d552001-06-28 07:25:16 +00005858 break;
5859 }
5860
5861 *q++ = *p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005862 check:
Eric Andersencb57d552001-06-28 07:25:16 +00005863 if (--parselleft <= 0 && more) {
5864 parsenleft = q - parsenextc - 1;
5865 if (parsenleft < 0)
5866 goto again;
5867 more = 0;
5868 }
5869 }
5870
5871 savec = *q;
5872 *q = '\0';
5873
5874 if (vflag) {
5875 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00005876 }
5877
5878 *q = savec;
5879
5880 return *parsenextc++;
5881}
5882
Eric Andersencb57d552001-06-28 07:25:16 +00005883
5884/*
5885 * Push a string back onto the input at this current parsefile level.
5886 * We handle aliases this way.
5887 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005888static void pushstring(char *s, int len, void *ap)
Eric Andersen2870d962001-07-02 17:27:21 +00005889{
Eric Andersencb57d552001-06-28 07:25:16 +00005890 struct strpush *sp;
5891
5892 INTOFF;
5893/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
5894 if (parsefile->strpush) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005895 sp = xmalloc(sizeof(struct strpush));
Eric Andersencb57d552001-06-28 07:25:16 +00005896 sp->prev = parsefile->strpush;
5897 parsefile->strpush = sp;
5898 } else
5899 sp = parsefile->strpush = &(parsefile->basestrpush);
5900 sp->prevstring = parsenextc;
5901 sp->prevnleft = parsenleft;
Eric Andersend35c5df2002-01-09 15:37:36 +00005902#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005903 sp->ap = (struct alias *) ap;
Eric Andersencb57d552001-06-28 07:25:16 +00005904 if (ap) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005905 ((struct alias *) ap)->flag |= ALIASINUSE;
Eric Andersencb57d552001-06-28 07:25:16 +00005906 sp->string = s;
5907 }
Eric Andersen2870d962001-07-02 17:27:21 +00005908#endif
Eric Andersencb57d552001-06-28 07:25:16 +00005909 parsenextc = s;
5910 parsenleft = len;
5911 INTON;
5912}
5913
Eric Andersencb57d552001-06-28 07:25:16 +00005914
Eric Andersencb57d552001-06-28 07:25:16 +00005915/*
5916 * Like setinputfile, but takes input from a string.
5917 */
5918
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005919static void setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +00005920{
Eric Andersencb57d552001-06-28 07:25:16 +00005921 INTOFF;
5922 pushfile();
5923 parsenextc = string;
5924 parsenleft = strlen(string);
5925 parsefile->buf = NULL;
5926 plinno = 1;
5927 INTON;
5928}
5929
5930
5931
5932/*
5933 * To handle the "." command, a stack of input files is used. Pushfile
5934 * adds a new entry to the stack and popfile restores the previous level.
5935 */
5936
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005937static void pushfile(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005938{
Eric Andersencb57d552001-06-28 07:25:16 +00005939 struct parsefile *pf;
5940
5941 parsefile->nleft = parsenleft;
5942 parsefile->lleft = parselleft;
5943 parsefile->nextc = parsenextc;
5944 parsefile->linno = plinno;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005945 pf = (struct parsefile *) xmalloc(sizeof(struct parsefile));
Eric Andersencb57d552001-06-28 07:25:16 +00005946 pf->prev = parsefile;
5947 pf->fd = -1;
5948 pf->strpush = NULL;
5949 pf->basestrpush.prev = NULL;
5950 parsefile = pf;
5951}
5952
Eric Andersend35c5df2002-01-09 15:37:36 +00005953#ifdef CONFIG_ASH_JOB_CONTROL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005954static void restartjob(struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00005955#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005956static void freejob(struct job *);
5957static struct job *getjob(const char *);
5958static int dowait(int, struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00005959
5960
Eric Andersen2870d962001-07-02 17:27:21 +00005961/*
5962 * We keep track of whether or not fd0 has been redirected. This is for
5963 * background commands, where we want to redirect fd0 to /dev/null only
5964 * if it hasn't already been redirected.
5965*/
5966static int fd0_redirected = 0;
5967
5968/* Return true if fd 0 has already been redirected at least once. */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005969static inline int fd0_redirected_p(void)
Eric Andersen74400cc2001-10-18 04:11:39 +00005970{
Eric Andersen2870d962001-07-02 17:27:21 +00005971 return fd0_redirected != 0;
5972}
5973
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005974static void dupredirect(const union node *, int, int fd1dup);
Eric Andersen2870d962001-07-02 17:27:21 +00005975
Eric Andersend35c5df2002-01-09 15:37:36 +00005976#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00005977/*
5978 * Turn job control on and off.
5979 *
5980 * Note: This code assumes that the third arg to ioctl is a character
5981 * pointer, which is true on Berkeley systems but not System V. Since
5982 * System V doesn't have job control yet, this isn't a problem now.
5983 */
5984
Eric Andersen2870d962001-07-02 17:27:21 +00005985
Eric Andersencb57d552001-06-28 07:25:16 +00005986
5987static void setjobctl(int enable)
5988{
Eric Andersencb57d552001-06-28 07:25:16 +00005989 if (enable == jobctl || rootshell == 0)
5990 return;
5991 if (enable) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005992 do { /* while we are in the background */
Eric Andersen3102ac42001-07-06 04:26:23 +00005993 initialpgrp = tcgetpgrp(2);
Eric Andersencb57d552001-06-28 07:25:16 +00005994 if (initialpgrp < 0) {
Eric Andersen8c145dc2001-07-10 16:57:09 +00005995 out2str("sh: can't access tty; job control turned off\n");
Eric Andersencb57d552001-06-28 07:25:16 +00005996 mflag = 0;
5997 return;
5998 }
Glenn L McGrath7040ecc2003-01-06 16:27:07 +00005999 if (initialpgrp == getpgrp())
6000 break;
6001 killpg(0, SIGTTIN);
6002 } while (1);
Eric Andersencb57d552001-06-28 07:25:16 +00006003 setsignal(SIGTSTP);
6004 setsignal(SIGTTOU);
6005 setsignal(SIGTTIN);
6006 setpgid(0, rootpid);
Eric Andersen3102ac42001-07-06 04:26:23 +00006007 tcsetpgrp(2, rootpid);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006008 } else { /* turning job control off */
Eric Andersencb57d552001-06-28 07:25:16 +00006009 setpgid(0, initialpgrp);
Eric Andersen3102ac42001-07-06 04:26:23 +00006010 tcsetpgrp(2, initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006011 setsignal(SIGTSTP);
6012 setsignal(SIGTTOU);
6013 setsignal(SIGTTIN);
6014 }
6015 jobctl = enable;
6016}
6017#endif
6018
6019
Eric Andersend35c5df2002-01-09 15:37:36 +00006020#ifdef CONFIG_ASH_JOB_CONTROL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006021static int killcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006022{
6023 int signo = -1;
6024 int list = 0;
6025 int i;
6026 pid_t pid;
6027 struct job *jp;
6028
6029 if (argc <= 1) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006030 usage:
6031 error
6032 ("Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6033 "kill -l [exitstatus]");
Eric Andersencb57d552001-06-28 07:25:16 +00006034 }
6035
6036 if (*argv[1] == '-') {
6037 signo = decode_signal(argv[1] + 1, 1);
6038 if (signo < 0) {
6039 int c;
6040
6041 while ((c = nextopt("ls:")) != '\0')
6042 switch (c) {
6043 case 'l':
6044 list = 1;
6045 break;
6046 case 's':
6047 signo = decode_signal(optionarg, 1);
6048 if (signo < 0) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006049 error("invalid signal number or name: %s", optionarg);
Eric Andersencb57d552001-06-28 07:25:16 +00006050 }
Eric Andersen2870d962001-07-02 17:27:21 +00006051 break;
Eric Andersencb57d552001-06-28 07:25:16 +00006052#ifdef DEBUG
6053 default:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006054 error("nextopt returned character code 0%o", c);
Eric Andersencb57d552001-06-28 07:25:16 +00006055#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006056 }
Eric Andersencb57d552001-06-28 07:25:16 +00006057 } else
6058 argptr++;
6059 }
6060
6061 if (!list && signo < 0)
6062 signo = SIGTERM;
6063
6064 if ((signo < 0 || !*argptr) ^ list) {
6065 goto usage;
6066 }
6067
6068 if (list) {
Eric Andersen34506362001-08-02 05:02:46 +00006069 const char *name;
6070
Eric Andersencb57d552001-06-28 07:25:16 +00006071 if (!*argptr) {
6072 out1str("0\n");
6073 for (i = 1; i < NSIG; i++) {
Eric Andersen34506362001-08-02 05:02:46 +00006074 name = u_signal_names(0, &i, 1);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006075 if (name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006076 puts(name);
Eric Andersencb57d552001-06-28 07:25:16 +00006077 }
6078 return 0;
6079 }
Eric Andersen34506362001-08-02 05:02:46 +00006080 name = u_signal_names(*argptr, &signo, -1);
6081 if (name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006082 puts(name);
Eric Andersencb57d552001-06-28 07:25:16 +00006083 else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006084 error("invalid signal number or exit status: %s", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006085 return 0;
6086 }
6087
6088 do {
6089 if (**argptr == '%') {
6090 jp = getjob(*argptr);
6091 if (jp->jobctl == 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006092 error("job %s not created under job control", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006093 pid = -jp->ps[0].pid;
6094 } else
6095 pid = atoi(*argptr);
6096 if (kill(pid, signo) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00006097 error("%s: %m", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006098 } while (*++argptr);
6099
6100 return 0;
6101}
6102
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006103static int fgcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006104{
6105 struct job *jp;
6106 int pgrp;
6107 int status;
6108
6109 jp = getjob(argv[1]);
6110 if (jp->jobctl == 0)
6111 error("job not created under job control");
6112 pgrp = jp->ps[0].pid;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006113 ioctl(2, TIOCSPGRP, (char *) &pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006114 restartjob(jp);
Eric Andersencb57d552001-06-28 07:25:16 +00006115 status = waitforjob(jp);
Eric Andersencb57d552001-06-28 07:25:16 +00006116 return status;
6117}
6118
6119
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006120static int bgcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006121{
6122 struct job *jp;
6123
6124 do {
6125 jp = getjob(*++argv);
6126 if (jp->jobctl == 0)
6127 error("job not created under job control");
6128 restartjob(jp);
6129 } while (--argc > 1);
6130 return 0;
6131}
6132
6133
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006134static void restartjob(struct job *jp)
Eric Andersencb57d552001-06-28 07:25:16 +00006135{
6136 struct procstat *ps;
6137 int i;
6138
6139 if (jp->state == JOBDONE)
6140 return;
6141 INTOFF;
6142 killpg(jp->ps[0].pid, SIGCONT);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006143 for (ps = jp->ps, i = jp->nprocs; --i >= 0; ps++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006144 if (WIFSTOPPED(ps->status)) {
6145 ps->status = -1;
6146 jp->state = 0;
6147 }
6148 }
6149 INTON;
6150}
6151#endif
6152
Eric Andersen2870d962001-07-02 17:27:21 +00006153static void showjobs(int change);
6154
Eric Andersencb57d552001-06-28 07:25:16 +00006155
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006156static int jobscmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006157{
6158 showjobs(0);
6159 return 0;
6160}
6161
6162
6163/*
6164 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6165 * statuses have changed since the last call to showjobs.
6166 *
6167 * If the shell is interrupted in the process of creating a job, the
6168 * result may be a job structure containing zero processes. Such structures
6169 * will be freed here.
6170 */
6171
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006172static void showjobs(int change)
Eric Andersencb57d552001-06-28 07:25:16 +00006173{
6174 int jobno;
6175 int procno;
6176 int i;
6177 struct job *jp;
6178 struct procstat *ps;
6179 int col;
6180 char s[64];
6181
6182 TRACE(("showjobs(%d) called\n", change));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006183 while (dowait(0, (struct job *) NULL) > 0);
6184 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
6185 if (!jp->used)
Eric Andersencb57d552001-06-28 07:25:16 +00006186 continue;
6187 if (jp->nprocs == 0) {
6188 freejob(jp);
6189 continue;
6190 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006191 if (change && !jp->changed)
Eric Andersencb57d552001-06-28 07:25:16 +00006192 continue;
6193 procno = jp->nprocs;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006194 for (ps = jp->ps;; ps++) { /* for each process */
Eric Andersencb57d552001-06-28 07:25:16 +00006195 if (ps == jp->ps)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006196 snprintf(s, 64, "[%d] %ld ", jobno, (long) ps->pid);
Eric Andersencb57d552001-06-28 07:25:16 +00006197 else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006198 snprintf(s, 64, " %ld ", (long) ps->pid);
Eric Andersencb57d552001-06-28 07:25:16 +00006199 out1str(s);
6200 col = strlen(s);
6201 s[0] = '\0';
6202 if (ps->status == -1) {
6203 /* don't print anything */
6204 } else if (WIFEXITED(ps->status)) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006205 snprintf(s, 64, "Exit %d", WEXITSTATUS(ps->status));
Eric Andersencb57d552001-06-28 07:25:16 +00006206 } else {
Eric Andersend35c5df2002-01-09 15:37:36 +00006207#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen2870d962001-07-02 17:27:21 +00006208 if (WIFSTOPPED(ps->status))
Eric Andersencb57d552001-06-28 07:25:16 +00006209 i = WSTOPSIG(ps->status);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006210 else /* WIFSIGNALED(ps->status) */
Eric Andersencb57d552001-06-28 07:25:16 +00006211#endif
6212 i = WTERMSIG(ps->status);
6213 if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
Eric Andersen2870d962001-07-02 17:27:21 +00006214 strcpy(s, sys_siglist[i & 0x7F]);
Eric Andersencb57d552001-06-28 07:25:16 +00006215 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006216 snprintf(s, 64, "Signal %d", i & 0x7F);
Eric Andersencb57d552001-06-28 07:25:16 +00006217 if (WCOREDUMP(ps->status))
6218 strcat(s, " (core dumped)");
6219 }
6220 out1str(s);
6221 col += strlen(s);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006222 printf("%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ', ps->cmd);
Eric Andersencb57d552001-06-28 07:25:16 +00006223 if (--procno <= 0)
6224 break;
6225 }
6226 jp->changed = 0;
6227 if (jp->state == JOBDONE) {
6228 freejob(jp);
6229 }
6230 }
6231}
6232
6233
6234/*
6235 * Mark a job structure as unused.
6236 */
6237
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006238static void freejob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00006239{
6240 const struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006241 int i;
6242
6243 INTOFF;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006244 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006245 if (ps->cmd != nullstr)
Aaron Lehmann49c024a2002-08-02 06:39:47 +00006246 free(ps->cmd);
Eric Andersencb57d552001-06-28 07:25:16 +00006247 }
6248 if (jp->ps != &jp->ps0)
Aaron Lehmann49c024a2002-08-02 06:39:47 +00006249 free(jp->ps);
Eric Andersencb57d552001-06-28 07:25:16 +00006250 jp->used = 0;
Eric Andersend35c5df2002-01-09 15:37:36 +00006251#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006252 if (curjob == jp - jobtab + 1)
6253 curjob = 0;
6254#endif
6255 INTON;
6256}
6257
6258
6259
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006260static int waitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006261{
6262 struct job *job;
6263 int status, retval;
6264 struct job *jp;
6265
6266 if (--argc > 0) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006267 start:
Eric Andersencb57d552001-06-28 07:25:16 +00006268 job = getjob(*++argv);
6269 } else {
6270 job = NULL;
6271 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006272 for (;;) { /* loop until process terminated or stopped */
Eric Andersencb57d552001-06-28 07:25:16 +00006273 if (job != NULL) {
6274 if (job->state) {
6275 status = job->ps[job->nprocs - 1].status;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006276 if (!iflag)
Eric Andersencb57d552001-06-28 07:25:16 +00006277 freejob(job);
6278 if (--argc) {
6279 goto start;
6280 }
6281 if (WIFEXITED(status))
6282 retval = WEXITSTATUS(status);
Eric Andersend35c5df2002-01-09 15:37:36 +00006283#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006284 else if (WIFSTOPPED(status))
6285 retval = WSTOPSIG(status) + 128;
6286#endif
6287 else {
6288 /* XXX: limits number of signals */
6289 retval = WTERMSIG(status) + 128;
6290 }
6291 return retval;
6292 }
6293 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006294 for (jp = jobtab;; jp++) {
6295 if (jp >= jobtab + njobs) { /* no running procs */
Eric Andersencb57d552001-06-28 07:25:16 +00006296 return 0;
6297 }
6298 if (jp->used && jp->state == 0)
6299 break;
6300 }
6301 }
6302 if (dowait(2, 0) < 0 && errno == EINTR) {
6303 return 129;
6304 }
6305 }
6306}
6307
6308
6309
6310/*
6311 * Convert a job name to a job structure.
6312 */
6313
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006314static struct job *getjob(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00006315{
Eric Andersencb57d552001-06-28 07:25:16 +00006316 int jobno;
6317 struct job *jp;
6318 int pid;
6319 int i;
6320
6321 if (name == NULL) {
Eric Andersend35c5df2002-01-09 15:37:36 +00006322#ifdef CONFIG_ASH_JOB_CONTROL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006323 currentjob:
Eric Andersencb57d552001-06-28 07:25:16 +00006324 if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
6325 error("No current job");
6326 return &jobtab[jobno - 1];
6327#else
6328 error("No current job");
6329#endif
6330 } else if (name[0] == '%') {
6331 if (is_digit(name[1])) {
6332 jobno = number(name + 1);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006333 if (jobno > 0 && jobno <= njobs && jobtab[jobno - 1].used != 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006334 return &jobtab[jobno - 1];
Eric Andersend35c5df2002-01-09 15:37:36 +00006335#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006336 } else if (name[1] == '%' && name[2] == '\0') {
6337 goto currentjob;
6338#endif
6339 } else {
6340 struct job *found = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006341
6342 for (jp = jobtab, i = njobs; --i >= 0; jp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006343 if (jp->used && jp->nprocs > 0
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006344 && prefix(name + 1, jp->ps[0].cmd)) {
Eric Andersencb57d552001-06-28 07:25:16 +00006345 if (found)
6346 error("%s: ambiguous", name);
6347 found = jp;
6348 }
6349 }
6350 if (found)
6351 return found;
6352 }
Eric Andersen2870d962001-07-02 17:27:21 +00006353 } else if (is_number(name, &pid)) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006354 for (jp = jobtab, i = njobs; --i >= 0; jp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006355 if (jp->used && jp->nprocs > 0
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006356 && jp->ps[jp->nprocs - 1].pid == pid)
Eric Andersencb57d552001-06-28 07:25:16 +00006357 return jp;
6358 }
6359 }
6360 error("No such job: %s", name);
6361 /* NOTREACHED */
6362}
6363
6364
6365
6366/*
6367 * Return a new job structure,
6368 */
6369
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006370static struct job *makejob(const union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00006371{
6372 int i;
6373 struct job *jp;
6374
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006375 for (i = njobs, jp = jobtab;; jp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006376 if (--i < 0) {
6377 INTOFF;
6378 if (njobs == 0) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006379 jobtab = xmalloc(4 * sizeof jobtab[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00006380 } else {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006381 jp = xmalloc((njobs + 4) * sizeof jobtab[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00006382 memcpy(jp, jobtab, njobs * sizeof jp[0]);
6383 /* Relocate `ps' pointers */
6384 for (i = 0; i < njobs; i++)
6385 if (jp[i].ps == &jobtab[i].ps0)
6386 jp[i].ps = &jp[i].ps0;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00006387 free(jobtab);
Eric Andersencb57d552001-06-28 07:25:16 +00006388 jobtab = jp;
6389 }
6390 jp = jobtab + njobs;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006391 for (i = 4; --i >= 0; jobtab[njobs++].used = 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006392 INTON;
6393 break;
6394 }
6395 if (jp->used == 0)
6396 break;
6397 }
6398 INTOFF;
6399 jp->state = 0;
6400 jp->used = 1;
6401 jp->changed = 0;
6402 jp->nprocs = 0;
Eric Andersend35c5df2002-01-09 15:37:36 +00006403#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006404 jp->jobctl = jobctl;
6405#endif
6406 if (nprocs > 1) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006407 jp->ps = xmalloc(nprocs * sizeof(struct procstat));
Eric Andersencb57d552001-06-28 07:25:16 +00006408 } else {
6409 jp->ps = &jp->ps0;
6410 }
6411 INTON;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006412 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long) node, nprocs,
6413 jp - jobtab + 1));
Eric Andersencb57d552001-06-28 07:25:16 +00006414 return jp;
6415}
6416
6417
6418/*
6419 * Fork of a subshell. If we are doing job control, give the subshell its
6420 * own process group. Jp is a job structure that the job is to be added to.
6421 * N is the command that will be evaluated by the child. Both jp and n may
6422 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00006423 * FORK_FG - Fork off a foreground process.
6424 * FORK_BG - Fork off a background process.
6425 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
6426 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00006427 *
6428 * When job control is turned off, background processes have their standard
6429 * input redirected to /dev/null (except for the second and later processes
6430 * in a pipeline).
6431 */
6432
Eric Andersen2870d962001-07-02 17:27:21 +00006433
6434
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006435static int forkshell(struct job *jp, const union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00006436{
6437 int pid;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006438
Eric Andersend35c5df2002-01-09 15:37:36 +00006439#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006440 int pgrp;
Eric Andersen62483552001-07-10 06:09:16 +00006441#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006442 const char *devnull = _PATH_DEVNULL;
6443 const char *nullerr = "Can't open %s";
6444
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006445 TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long) n,
6446 mode));
Eric Andersencb57d552001-06-28 07:25:16 +00006447 INTOFF;
6448 pid = fork();
6449 if (pid == -1) {
6450 TRACE(("Fork failed, errno=%d\n", errno));
6451 INTON;
6452 error("Cannot fork");
6453 }
6454 if (pid == 0) {
6455 struct job *p;
6456 int wasroot;
6457 int i;
6458
6459 TRACE(("Child shell %d\n", getpid()));
6460 wasroot = rootshell;
6461 rootshell = 0;
6462 closescript();
6463 INTON;
6464 clear_traps();
Eric Andersend35c5df2002-01-09 15:37:36 +00006465#ifdef CONFIG_ASH_JOB_CONTROL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006466 jobctl = 0; /* do job control only in root shell */
Eric Andersencb57d552001-06-28 07:25:16 +00006467 if (wasroot && mode != FORK_NOJOB && mflag) {
6468 if (jp == NULL || jp->nprocs == 0)
6469 pgrp = getpid();
6470 else
6471 pgrp = jp->ps[0].pid;
6472 setpgid(0, pgrp);
6473 if (mode == FORK_FG) {
6474 /*** this causes superfluous TIOCSPGRPS ***/
Eric Andersen3102ac42001-07-06 04:26:23 +00006475 if (tcsetpgrp(2, pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006476 error("tcsetpgrp failed, errno=%d", errno);
Eric Andersencb57d552001-06-28 07:25:16 +00006477 }
6478 setsignal(SIGTSTP);
6479 setsignal(SIGTTOU);
6480 } else if (mode == FORK_BG) {
Eric Andersencb57d552001-06-28 07:25:16 +00006481#else
6482 if (mode == FORK_BG) {
Aaron Lehmann1a698662001-12-31 06:12:48 +00006483#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006484 ignoresig(SIGINT);
6485 ignoresig(SIGQUIT);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006486 if ((jp == NULL || jp->nprocs == 0) && !fd0_redirected_p()) {
Eric Andersencb57d552001-06-28 07:25:16 +00006487 close(0);
6488 if (open(devnull, O_RDONLY) != 0)
6489 error(nullerr, devnull);
6490 }
6491 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006492 for (i = njobs, p = jobtab; --i >= 0; p++)
Eric Andersencb57d552001-06-28 07:25:16 +00006493 if (p->used)
6494 freejob(p);
6495 if (wasroot && iflag) {
6496 setsignal(SIGINT);
6497 setsignal(SIGQUIT);
6498 setsignal(SIGTERM);
6499 }
6500 return pid;
6501 }
Eric Andersend35c5df2002-01-09 15:37:36 +00006502#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006503 if (rootshell && mode != FORK_NOJOB && mflag) {
6504 if (jp == NULL || jp->nprocs == 0)
6505 pgrp = pid;
6506 else
6507 pgrp = jp->ps[0].pid;
6508 setpgid(pid, pgrp);
6509 }
Eric Andersen62483552001-07-10 06:09:16 +00006510#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006511 if (mode == FORK_BG)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006512 backgndpid = pid; /* set $! */
Eric Andersencb57d552001-06-28 07:25:16 +00006513 if (jp) {
6514 struct procstat *ps = &jp->ps[jp->nprocs++];
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006515
Eric Andersencb57d552001-06-28 07:25:16 +00006516 ps->pid = pid;
6517 ps->status = -1;
6518 ps->cmd = nullstr;
6519 if (iflag && rootshell && n)
6520 ps->cmd = commandtext(n);
6521 }
6522 INTON;
6523 TRACE(("In parent shell: child = %d\n", pid));
6524 return pid;
6525}
6526
6527
6528
6529/*
6530 * Wait for job to finish.
6531 *
6532 * Under job control we have the problem that while a child process is
6533 * running interrupts generated by the user are sent to the child but not
6534 * to the shell. This means that an infinite loop started by an inter-
6535 * active user may be hard to kill. With job control turned off, an
6536 * interactive user may place an interactive program inside a loop. If
6537 * the interactive program catches interrupts, the user doesn't want
6538 * these interrupts to also abort the loop. The approach we take here
6539 * is to have the shell ignore interrupt signals while waiting for a
6540 * forground process to terminate, and then send itself an interrupt
6541 * signal if the child process was terminated by an interrupt signal.
6542 * Unfortunately, some programs want to do a bit of cleanup and then
6543 * exit on interrupt; unless these processes terminate themselves by
6544 * sending a signal to themselves (instead of calling exit) they will
6545 * confuse this approach.
6546 */
6547
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006548static int waitforjob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00006549{
Eric Andersend35c5df2002-01-09 15:37:36 +00006550#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006551 int mypgrp = getpgrp();
6552#endif
6553 int status;
6554 int st;
Eric Andersencb57d552001-06-28 07:25:16 +00006555
6556 INTOFF;
Eric Andersencb57d552001-06-28 07:25:16 +00006557 TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
6558 while (jp->state == 0) {
6559 dowait(1, jp);
6560 }
Eric Andersend35c5df2002-01-09 15:37:36 +00006561#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006562 if (jp->jobctl) {
Eric Andersen3102ac42001-07-06 04:26:23 +00006563 if (tcsetpgrp(2, mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006564 error("tcsetpgrp failed, errno=%d\n", errno);
Eric Andersencb57d552001-06-28 07:25:16 +00006565 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00006566 if (jp->state == JOBSTOPPED)
Eric Andersencb57d552001-06-28 07:25:16 +00006567 curjob = jp - jobtab + 1;
6568#endif
6569 status = jp->ps[jp->nprocs - 1].status;
6570 /* convert to 8 bits */
6571 if (WIFEXITED(status))
6572 st = WEXITSTATUS(status);
Eric Andersend35c5df2002-01-09 15:37:36 +00006573#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006574 else if (WIFSTOPPED(status))
6575 st = WSTOPSIG(status) + 128;
6576#endif
6577 else
6578 st = WTERMSIG(status) + 128;
Eric Andersend35c5df2002-01-09 15:37:36 +00006579#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006580 if (jp->jobctl) {
6581 /*
6582 * This is truly gross.
6583 * If we're doing job control, then we did a TIOCSPGRP which
6584 * caused us (the shell) to no longer be in the controlling
6585 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
6586 * intuit from the subprocess exit status whether a SIGINT
6587 * occured, and if so interrupt ourselves. Yuck. - mycroft
6588 */
6589 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
6590 raise(SIGINT);
6591 }
Eric Andersen2870d962001-07-02 17:27:21 +00006592 if (jp->state == JOBDONE)
Eric Andersencb57d552001-06-28 07:25:16 +00006593#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006594 freejob(jp);
6595 INTON;
6596 return st;
6597}
6598
6599
6600
6601/*
6602 * Wait for a process to terminate.
6603 */
6604
Eric Andersen62483552001-07-10 06:09:16 +00006605/*
6606 * Do a wait system call. If job control is compiled in, we accept
6607 * stopped processes. If block is zero, we return a value of zero
6608 * rather than blocking.
6609 *
6610 * System V doesn't have a non-blocking wait system call. It does
6611 * have a SIGCLD signal that is sent to a process when one of it's
6612 * children dies. The obvious way to use SIGCLD would be to install
6613 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
6614 * was received, and have waitproc bump another counter when it got
6615 * the status of a process. Waitproc would then know that a wait
6616 * system call would not block if the two counters were different.
6617 * This approach doesn't work because if a process has children that
6618 * have not been waited for, System V will send it a SIGCLD when it
6619 * installs a signal handler for SIGCLD. What this means is that when
6620 * a child exits, the shell will be sent SIGCLD signals continuously
6621 * until is runs out of stack space, unless it does a wait call before
6622 * restoring the signal handler. The code below takes advantage of
6623 * this (mis)feature by installing a signal handler for SIGCLD and
6624 * then checking to see whether it was called. If there are any
6625 * children to be waited for, it will be.
6626 *
6627 */
6628
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006629static inline int waitproc(int block, int *status)
Eric Andersen62483552001-07-10 06:09:16 +00006630{
6631 int flags;
6632
6633 flags = 0;
Eric Andersend35c5df2002-01-09 15:37:36 +00006634#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen62483552001-07-10 06:09:16 +00006635 if (jobctl)
6636 flags |= WUNTRACED;
6637#endif
6638 if (block == 0)
6639 flags |= WNOHANG;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006640 return wait3(status, flags, (struct rusage *) NULL);
Eric Andersen62483552001-07-10 06:09:16 +00006641}
6642
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006643static int dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00006644{
6645 int pid;
6646 int status;
6647 struct procstat *sp;
6648 struct job *jp;
6649 struct job *thisjob;
6650 int done;
6651 int stopped;
6652 int core;
6653 int sig;
6654
6655 TRACE(("dowait(%d) called\n", block));
6656 do {
6657 pid = waitproc(block, &status);
6658 TRACE(("wait returns %d, status=%d\n", pid, status));
6659 } while (!(block & 2) && pid == -1 && errno == EINTR);
6660 if (pid <= 0)
6661 return pid;
6662 INTOFF;
6663 thisjob = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006664 for (jp = jobtab; jp < jobtab + njobs; jp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006665 if (jp->used) {
6666 done = 1;
6667 stopped = 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006668 for (sp = jp->ps; sp < jp->ps + jp->nprocs; sp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006669 if (sp->pid == -1)
6670 continue;
6671 if (sp->pid == pid) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006672 TRACE(("Changing status of proc %d from 0x%x to 0x%x\n",
6673 pid, sp->status, status));
Eric Andersencb57d552001-06-28 07:25:16 +00006674 sp->status = status;
6675 thisjob = jp;
6676 }
6677 if (sp->status == -1)
6678 stopped = 0;
6679 else if (WIFSTOPPED(sp->status))
6680 done = 0;
6681 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006682 if (stopped) { /* stopped or done */
Glenn L McGrath50812ff2002-08-23 13:14:48 +00006683 int state = done ? JOBDONE : JOBSTOPPED;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006684
Eric Andersencb57d552001-06-28 07:25:16 +00006685 if (jp->state != state) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006686 TRACE(("Job %d: changing state from %d to %d\n",
6687 jp - jobtab + 1, jp->state, state));
Eric Andersencb57d552001-06-28 07:25:16 +00006688 jp->state = state;
Eric Andersend35c5df2002-01-09 15:37:36 +00006689#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006690 if (done && curjob == jp - jobtab + 1)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006691 curjob = 0; /* no current job */
Eric Andersencb57d552001-06-28 07:25:16 +00006692#endif
6693 }
6694 }
6695 }
6696 }
6697 INTON;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006698 if (!rootshell || !iflag || (job && thisjob == job)) {
Eric Andersencb57d552001-06-28 07:25:16 +00006699 core = WCOREDUMP(status);
Eric Andersend35c5df2002-01-09 15:37:36 +00006700#ifdef CONFIG_ASH_JOB_CONTROL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006701 if (WIFSTOPPED(status))
6702 sig = WSTOPSIG(status);
Eric Andersencb57d552001-06-28 07:25:16 +00006703 else
6704#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006705 if (WIFEXITED(status))
6706 sig = 0;
6707 else
6708 sig = WTERMSIG(status);
Eric Andersencb57d552001-06-28 07:25:16 +00006709
6710 if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
6711 if (thisjob != job)
Eric Andersen3102ac42001-07-06 04:26:23 +00006712 out2fmt("%d: ", pid);
Eric Andersend35c5df2002-01-09 15:37:36 +00006713#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006714 if (sig == SIGTSTP && rootshell && iflag)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006715 out2fmt("%%%ld ", (long) (job - jobtab + 1));
Eric Andersencb57d552001-06-28 07:25:16 +00006716#endif
6717 if (sig < NSIG && sys_siglist[sig])
6718 out2str(sys_siglist[sig]);
6719 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006720 out2fmt("Signal %d", sig);
Eric Andersencb57d552001-06-28 07:25:16 +00006721 if (core)
6722 out2str(" - core dumped");
6723 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00006724 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006725 TRACE(("Not printing status: status=%d, sig=%d\n", status, sig));
Eric Andersencb57d552001-06-28 07:25:16 +00006726 }
6727 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006728 TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell,
6729 job));
Eric Andersencb57d552001-06-28 07:25:16 +00006730 if (thisjob)
6731 thisjob->changed = 1;
6732 }
6733 return pid;
6734}
6735
6736
6737
Eric Andersencb57d552001-06-28 07:25:16 +00006738
6739/*
6740 * return 1 if there are stopped jobs, otherwise 0
6741 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006742static int stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006743{
6744 int jobno;
6745 struct job *jp;
6746
6747 if (job_warning)
6748 return (0);
6749 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
6750 if (jp->used == 0)
6751 continue;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00006752 if (jp->state == JOBSTOPPED) {
Eric Andersencb57d552001-06-28 07:25:16 +00006753 out2str("You have stopped jobs.\n");
6754 job_warning = 2;
6755 return (1);
6756 }
6757 }
6758
6759 return (0);
6760}
6761
6762/*
6763 * Return a string identifying a command (to be printed by the
6764 * jobs command.
6765 */
6766
6767static char *cmdnextc;
6768static int cmdnleft;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006769
Eric Andersen2870d962001-07-02 17:27:21 +00006770#define MAXCMDTEXT 200
Eric Andersencb57d552001-06-28 07:25:16 +00006771
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006772static void cmdputs(const char *s)
Eric Andersen2870d962001-07-02 17:27:21 +00006773{
6774 const char *p;
6775 char *q;
6776 char c;
6777 int subtype = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00006778
Eric Andersen2870d962001-07-02 17:27:21 +00006779 if (cmdnleft <= 0)
6780 return;
6781 p = s;
6782 q = cmdnextc;
6783 while ((c = *p++) != '\0') {
6784 if (c == CTLESC)
6785 *q++ = *p++;
6786 else if (c == CTLVAR) {
6787 *q++ = '$';
6788 if (--cmdnleft > 0)
6789 *q++ = '{';
6790 subtype = *p++;
6791 } else if (c == '=' && subtype != 0) {
6792 *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
6793 subtype = 0;
6794 } else if (c == CTLENDVAR) {
6795 *q++ = '}';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006796 } else if (c == CTLBACKQ || c == CTLBACKQ + CTLQUOTE)
6797 cmdnleft++; /* ignore it */
Eric Andersen2870d962001-07-02 17:27:21 +00006798 else
6799 *q++ = c;
6800 if (--cmdnleft <= 0) {
6801 *q++ = '.';
6802 *q++ = '.';
6803 *q++ = '.';
6804 break;
6805 }
6806 }
6807 cmdnextc = q;
Eric Andersencb57d552001-06-28 07:25:16 +00006808}
6809
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00006810#define CMDTXT_TABLE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006811#ifdef CMDTXT_TABLE
6812/*
6813 * To collect a lot of redundant code in cmdtxt() case statements, we
6814 * implement a mini language here. Each type of node struct has an
6815 * associated instruction sequence that operates on its members via
6816 * their offsets. The instruction are pack in unsigned chars with
6817 * format IIDDDDDE where the bits are
6818 * I : part of the instruction opcode, which are
6819 * 00 : member is a pointer to another node -- process it recursively
6820 * 40 : member is a pointer to a char string -- output it
6821 * 80 : output the string whose index is stored in the data field
6822 * CC : flag signaling that this case needs external processing
6823 * D : data - either the (shifted) index of a fixed string to output or
6824 * the actual offset of the member to operate on in the struct
6825 * (since we assume bit 0 is set, the offset is not shifted)
6826 * E : flag signaling end of instruction sequence
6827 *
6828 * WARNING: In order to handle larger offsets for 64bit archs, this code
6829 * assumes that no offset can be an odd number and stores the
6830 * end-of-instructions flag in bit 0.
6831 */
Eric Andersencb57d552001-06-28 07:25:16 +00006832
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006833#define CMDTXT_NOMORE 0x01 /* NOTE: no offset should be odd */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006834#define CMDTXT_CHARPTR 0x40
6835#define CMDTXT_STRING 0x80
6836#define CMDTXT_SPECIAL 0xC0
6837#define CMDTXT_OFFSETMASK 0x3E
6838
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006839static const char *const cmdtxt_strings[] = {
6840 /* 0 1 2 3 4 5 6 7 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006841 "; ", "(", ")", " && ", " || ", "if ", "; then ", "...",
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006842 /* 8 9 10 11 12 13 */
6843 "while ", "; do ", "; done", "until ", "for ", " in ...",
6844 /* 14 15 16 17 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006845 "case ", "???", "() ...", "<<..."
6846};
6847
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006848static const char *const redir_strings[] = {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006849 ">", "<", "<>", ">>", ">|", ">&", "<&"
6850};
6851
6852static const unsigned char cmdtxt_ops[] = {
6853#define CMDTXT_NSEMI 0
6854 offsetof(union node, nbinary.ch1),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006855 0 | CMDTXT_STRING,
6856 offsetof(union node, nbinary.ch2) | CMDTXT_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006857#define CMDTXT_NCMD (CMDTXT_NSEMI + 3)
6858#define CMDTXT_NPIPE (CMDTXT_NCMD)
6859#define CMDTXT_NCASE (CMDTXT_NCMD)
6860#define CMDTXT_NTO (CMDTXT_NCMD)
6861#define CMDTXT_NFROM (CMDTXT_NCMD)
6862#define CMDTXT_NFROMTO (CMDTXT_NCMD)
6863#define CMDTXT_NAPPEND (CMDTXT_NCMD)
6864#define CMDTXT_NTOOV (CMDTXT_NCMD)
6865#define CMDTXT_NTOFD (CMDTXT_NCMD)
6866#define CMDTXT_NFROMFD (CMDTXT_NCMD)
6867 CMDTXT_SPECIAL,
6868#define CMDTXT_NREDIR (CMDTXT_NPIPE + 1)
6869#define CMDTXT_NBACKGND (CMDTXT_NREDIR)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006870 offsetof(union node, nredir.n) | CMDTXT_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006871#define CMDTXT_NSUBSHELL (CMDTXT_NBACKGND + 1)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006872 (1 * 2) | CMDTXT_STRING,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006873 offsetof(union node, nredir.n),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006874 (2 * 2) | CMDTXT_STRING | CMDTXT_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006875#define CMDTXT_NAND (CMDTXT_NSUBSHELL + 3)
6876 offsetof(union node, nbinary.ch1),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006877 (3 * 2) | CMDTXT_STRING,
6878 offsetof(union node, nbinary.ch2) | CMDTXT_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006879#define CMDTXT_NOR (CMDTXT_NAND + 3)
6880 offsetof(union node, nbinary.ch1),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006881 (4 * 2) | CMDTXT_STRING,
6882 offsetof(union node, nbinary.ch2) | CMDTXT_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006883#define CMDTXT_NIF (CMDTXT_NOR + 3)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006884 (5 * 2) | CMDTXT_STRING,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006885 offsetof(union node, nif.test),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006886 (6 * 2) | CMDTXT_STRING,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006887 offsetof(union node, nif.ifpart),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006888 (7 * 2) | CMDTXT_STRING | CMDTXT_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006889#define CMDTXT_NWHILE (CMDTXT_NIF + 5)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006890 (8 * 2) | CMDTXT_STRING,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006891 offsetof(union node, nbinary.ch1),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006892 (9 * 2) | CMDTXT_STRING,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006893 offsetof(union node, nbinary.ch2),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006894 (10 * 2) | CMDTXT_STRING | CMDTXT_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006895#define CMDTXT_NUNTIL (CMDTXT_NWHILE + 5)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006896 (11 * 2) | CMDTXT_STRING,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006897 offsetof(union node, nbinary.ch1),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006898 (9 * 2) | CMDTXT_STRING,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006899 offsetof(union node, nbinary.ch2),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006900 (10 * 2) | CMDTXT_STRING | CMDTXT_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006901#define CMDTXT_NFOR (CMDTXT_NUNTIL + 5)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006902 (12 * 2) | CMDTXT_STRING,
6903 offsetof(union node, nfor.var) | CMDTXT_CHARPTR,
6904 (13 * 2) | CMDTXT_STRING | CMDTXT_NOMORE,
6905#define CMDTXT_NCLIST (CMDTXT_NFOR + 3) /* TODO: IS THIS CORRECT??? */
6906#define CMDTXT_NNOT (CMDTXT_NCLIST) /* TODO: IS THIS CORRECT??? */
6907 (15 * 2) | CMDTXT_STRING | CMDTXT_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006908#define CMDTXT_NDEFUN (CMDTXT_NCLIST + 1)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006909 offsetof(union node, narg.text) | CMDTXT_CHARPTR,
6910 (16 * 2) | CMDTXT_STRING | CMDTXT_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006911#define CMDTXT_NARG (CMDTXT_NDEFUN + 2)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006912 offsetof(union node, narg.text) | CMDTXT_CHARPTR | CMDTXT_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006913#define CMDTXT_NHERE (CMDTXT_NARG + 1)
6914#define CMDTXT_NXHERE (CMDTXT_NHERE)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006915 (17 * 2) | CMDTXT_STRING | CMDTXT_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006916};
6917
6918#if CMDTXT_NXHERE != 36
6919#error CMDTXT_NXHERE
6920#endif
6921
6922static const unsigned char cmdtxt_ops_index[26] = {
6923 CMDTXT_NSEMI,
6924 CMDTXT_NCMD,
6925 CMDTXT_NPIPE,
6926 CMDTXT_NREDIR,
6927 CMDTXT_NBACKGND,
6928 CMDTXT_NSUBSHELL,
6929 CMDTXT_NAND,
6930 CMDTXT_NOR,
6931 CMDTXT_NIF,
6932 CMDTXT_NWHILE,
6933 CMDTXT_NUNTIL,
6934 CMDTXT_NFOR,
6935 CMDTXT_NCASE,
6936 CMDTXT_NCLIST,
6937 CMDTXT_NDEFUN,
6938 CMDTXT_NARG,
6939 CMDTXT_NTO,
6940 CMDTXT_NFROM,
6941 CMDTXT_NFROMTO,
6942 CMDTXT_NAPPEND,
6943 CMDTXT_NTOOV,
6944 CMDTXT_NTOFD,
6945 CMDTXT_NFROMFD,
6946 CMDTXT_NHERE,
6947 CMDTXT_NXHERE,
6948 CMDTXT_NNOT,
6949};
6950
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006951static void cmdtxt(const union node *n)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006952{
6953 const char *p;
6954
6955 if (n == NULL)
6956 return;
6957
6958 p = cmdtxt_ops + (int) cmdtxt_ops_index[n->type];
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006959 if ((*p & CMDTXT_SPECIAL) != CMDTXT_SPECIAL) { /* normal case */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006960 do {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006961 if (*p & CMDTXT_STRING) { /* output fixed string */
6962 cmdputs(cmdtxt_strings
6963 [((int) (*p & CMDTXT_OFFSETMASK) >> 1)]);
Manuel Novoa III c639a352001-08-12 17:32:56 +00006964 } else {
6965 const char *pf = ((const char *) n)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006966 + ((int) (*p & CMDTXT_OFFSETMASK));
6967
6968 if (*p & CMDTXT_CHARPTR) { /* output dynamic string */
Manuel Novoa III c639a352001-08-12 17:32:56 +00006969 cmdputs(*((const char **) pf));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006970 } else { /* output field */
Manuel Novoa III c639a352001-08-12 17:32:56 +00006971 cmdtxt(*((const union node **) pf));
6972 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006973 }
6974 } while (!(*p++ & CMDTXT_NOMORE));
6975 } else if (n->type == NCMD) {
6976 union node *np;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006977
6978 for (np = n->ncmd.args; np; np = np->narg.next) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006979 cmdtxt(np);
6980 if (np->narg.next)
6981 cmdputs(spcstr);
6982 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006983 for (np = n->ncmd.redirect; np; np = np->nfile.next) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006984 cmdputs(spcstr);
6985 cmdtxt(np);
6986 }
6987 } else if (n->type == NPIPE) {
6988 struct nodelist *lp;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006989
6990 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006991 cmdtxt(lp->n);
6992 if (lp->next)
6993 cmdputs(" | ");
6994 }
6995 } else if (n->type == NCASE) {
6996 cmdputs(cmdtxt_strings[14]);
6997 cmdputs(n->ncase.expr->narg.text);
6998 cmdputs(cmdtxt_strings[13]);
6999 } else {
7000#if (NTO != 16) || (NFROM != 17) || (NFROMTO != 18) || (NAPPEND != 19) || (NTOOV != 20) || (NTOFD != 21) || (NFROMFD != 22)
7001#error Assumption violated regarding range and ordering of NTO ... NFROMFD!
7002#endif
7003 char s[2];
7004
7005#ifdef DEBUG
7006 assert((n->type >= NTO) && (n->type <= NFROMFD));
7007#endif
7008
7009 p = redir_strings[n->type - NTO];
7010 if (n->nfile.fd != ('>' == *p)) {
7011 s[0] = n->nfile.fd + '0';
7012 s[1] = '\0';
7013 cmdputs(s);
7014 }
7015 cmdputs(p);
7016 if (n->type >= NTOFD) {
7017 s[0] = n->ndup.dupfd + '0';
7018 s[1] = '\0';
7019 cmdputs(s);
7020 } else {
7021 cmdtxt(n->nfile.fname);
7022 }
7023 }
7024}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007025#else /* CMDTXT_TABLE */
7026static void cmdtxt(const union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007027{
Eric Andersencb57d552001-06-28 07:25:16 +00007028 union node *np;
7029 struct nodelist *lp;
7030 const char *p;
7031 int i;
7032 char s[2];
7033
7034 if (n == NULL)
7035 return;
7036 switch (n->type) {
7037 case NSEMI:
7038 cmdtxt(n->nbinary.ch1);
7039 cmdputs("; ");
7040 cmdtxt(n->nbinary.ch2);
7041 break;
7042 case NAND:
7043 cmdtxt(n->nbinary.ch1);
7044 cmdputs(" && ");
7045 cmdtxt(n->nbinary.ch2);
7046 break;
7047 case NOR:
7048 cmdtxt(n->nbinary.ch1);
7049 cmdputs(" || ");
7050 cmdtxt(n->nbinary.ch2);
7051 break;
7052 case NPIPE:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007053 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00007054 cmdtxt(lp->n);
7055 if (lp->next)
7056 cmdputs(" | ");
7057 }
7058 break;
7059 case NSUBSHELL:
7060 cmdputs("(");
7061 cmdtxt(n->nredir.n);
7062 cmdputs(")");
7063 break;
7064 case NREDIR:
7065 case NBACKGND:
7066 cmdtxt(n->nredir.n);
7067 break;
7068 case NIF:
7069 cmdputs("if ");
7070 cmdtxt(n->nif.test);
7071 cmdputs("; then ");
7072 cmdtxt(n->nif.ifpart);
7073 cmdputs("...");
7074 break;
7075 case NWHILE:
7076 cmdputs("while ");
7077 goto until;
7078 case NUNTIL:
7079 cmdputs("until ");
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007080 until:
Eric Andersencb57d552001-06-28 07:25:16 +00007081 cmdtxt(n->nbinary.ch1);
7082 cmdputs("; do ");
7083 cmdtxt(n->nbinary.ch2);
7084 cmdputs("; done");
7085 break;
7086 case NFOR:
7087 cmdputs("for ");
7088 cmdputs(n->nfor.var);
7089 cmdputs(" in ...");
7090 break;
7091 case NCASE:
7092 cmdputs("case ");
7093 cmdputs(n->ncase.expr->narg.text);
7094 cmdputs(" in ...");
7095 break;
7096 case NDEFUN:
7097 cmdputs(n->narg.text);
7098 cmdputs("() ...");
7099 break;
7100 case NCMD:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007101 for (np = n->ncmd.args; np; np = np->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00007102 cmdtxt(np);
7103 if (np->narg.next)
7104 cmdputs(spcstr);
7105 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007106 for (np = n->ncmd.redirect; np; np = np->nfile.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00007107 cmdputs(spcstr);
7108 cmdtxt(np);
7109 }
7110 break;
7111 case NARG:
7112 cmdputs(n->narg.text);
7113 break;
7114 case NTO:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007115 p = ">";
7116 i = 1;
7117 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00007118 case NAPPEND:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007119 p = ">>";
7120 i = 1;
7121 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00007122 case NTOFD:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007123 p = ">&";
7124 i = 1;
7125 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00007126 case NTOOV:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007127 p = ">|";
7128 i = 1;
7129 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00007130 case NFROM:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007131 p = "<";
7132 i = 0;
7133 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00007134 case NFROMFD:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007135 p = "<&";
7136 i = 0;
7137 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00007138 case NFROMTO:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007139 p = "<>";
7140 i = 0;
7141 goto redir;
7142 redir:
Eric Andersencb57d552001-06-28 07:25:16 +00007143 if (n->nfile.fd != i) {
7144 s[0] = n->nfile.fd + '0';
7145 s[1] = '\0';
7146 cmdputs(s);
7147 }
7148 cmdputs(p);
7149 if (n->type == NTOFD || n->type == NFROMFD) {
7150 s[0] = n->ndup.dupfd + '0';
7151 s[1] = '\0';
7152 cmdputs(s);
7153 } else {
7154 cmdtxt(n->nfile.fname);
7155 }
7156 break;
7157 case NHERE:
7158 case NXHERE:
7159 cmdputs("<<...");
7160 break;
7161 default:
7162 cmdputs("???");
7163 break;
7164 }
7165}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007166#endif /* CMDTXT_TABLE */
Eric Andersencb57d552001-06-28 07:25:16 +00007167
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007168static char *commandtext(const union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007169{
7170 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007171
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007172 cmdnextc = name = xmalloc(MAXCMDTEXT);
Eric Andersen2870d962001-07-02 17:27:21 +00007173 cmdnleft = MAXCMDTEXT - 4;
7174 cmdtxt(n);
7175 *cmdnextc = '\0';
7176 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00007177}
7178
Eric Andersen2870d962001-07-02 17:27:21 +00007179
Eric Andersend35c5df2002-01-09 15:37:36 +00007180#ifdef CONFIG_ASH_MAIL
Eric Andersenec074692001-10-31 11:05:49 +00007181
Eric Andersencb57d552001-06-28 07:25:16 +00007182/*
Eric Andersenec074692001-10-31 11:05:49 +00007183 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +00007184 */
7185
7186
7187#define MAXMBOXES 10
7188
7189
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007190static int nmboxes; /* number of mailboxes */
7191static time_t mailtime[MAXMBOXES]; /* times of mailboxes */
Eric Andersencb57d552001-06-28 07:25:16 +00007192
7193
7194
7195/*
7196 * Print appropriate message(s) if mail has arrived. If the argument is
7197 * nozero, then the value of MAIL has changed, so we just update the
7198 * values.
7199 */
7200
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007201static void chkmail(int silent)
Eric Andersencb57d552001-06-28 07:25:16 +00007202{
7203 int i;
7204 const char *mpath;
7205 char *p;
7206 char *q;
7207 struct stackmark smark;
7208 struct stat statb;
7209
7210 if (silent)
7211 nmboxes = 10;
7212 if (nmboxes == 0)
7213 return;
7214 setstackmark(&smark);
7215 mpath = mpathset()? mpathval() : mailval();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007216 for (i = 0; i < nmboxes; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007217 p = padvance(&mpath, nullstr);
7218 if (p == NULL)
7219 break;
7220 if (*p == '\0')
7221 continue;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007222 for (q = p; *q; q++);
Eric Andersencb57d552001-06-28 07:25:16 +00007223#ifdef DEBUG
7224 if (q[-1] != '/')
7225 abort();
7226#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007227 q[-1] = '\0'; /* delete trailing '/' */
Eric Andersencb57d552001-06-28 07:25:16 +00007228 if (stat(p, &statb) < 0)
7229 statb.st_size = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007230 if (statb.st_size > mailtime[i] && !silent) {
7231 out2fmt(snlfmt, pathopt ? pathopt : "you have mail");
Eric Andersencb57d552001-06-28 07:25:16 +00007232 }
7233 mailtime[i] = statb.st_size;
Eric Andersencb57d552001-06-28 07:25:16 +00007234 }
7235 nmboxes = i;
7236 popstackmark(&smark);
7237}
Eric Andersencb57d552001-06-28 07:25:16 +00007238
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007239#endif /* CONFIG_ASH_MAIL */
Eric Andersenec074692001-10-31 11:05:49 +00007240
Eric Andersencb57d552001-06-28 07:25:16 +00007241#define PROFILE 0
7242
Eric Andersencb57d552001-06-28 07:25:16 +00007243#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007244static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007245extern int etext();
7246#endif
7247
Robert Griebl64f70cc2002-05-14 23:22:06 +00007248static int isloginsh = 0;
7249
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007250static void read_profile(const char *);
7251static void cmdloop(int);
7252static void options(int);
7253static void setoption(int, int);
7254static void procargs(int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00007255
Eric Andersen2870d962001-07-02 17:27:21 +00007256
Eric Andersencb57d552001-06-28 07:25:16 +00007257/*
7258 * Main routine. We initialize things, parse the arguments, execute
7259 * profiles if we're a login shell, and then call cmdloop to execute
7260 * commands. The setjmp call sets up the location to jump to when an
7261 * exception occurs. When an exception occurs the variable "state"
7262 * is used to figure out how far we had gotten.
7263 */
7264
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007265int ash_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007266{
7267 struct jmploc jmploc;
7268 struct stackmark smark;
7269 volatile int state;
Eric Andersen62483552001-07-10 06:09:16 +00007270 const char *shinit;
Eric Andersencb57d552001-06-28 07:25:16 +00007271
Eric Andersencb57d552001-06-28 07:25:16 +00007272 BLTINCMD = find_builtin("builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00007273 EXECCMD = find_builtin("exec");
7274 EVALCMD = find_builtin("eval");
7275
Eric Andersenbdfd0d72001-10-24 05:00:29 +00007276#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
Eric Andersen1c039232001-07-07 00:05:55 +00007277 unsetenv("PS1");
7278 unsetenv("PS2");
7279#endif
7280
Eric Andersencb57d552001-06-28 07:25:16 +00007281#if PROFILE
7282 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7283#endif
7284#if defined(linux) || defined(__GNU__)
7285 signal(SIGCHLD, SIG_DFL);
7286#endif
7287 state = 0;
7288 if (setjmp(jmploc.loc)) {
7289 INTOFF;
7290 /*
7291 * When a shell procedure is executed, we raise the
7292 * exception EXSHELLPROC to clean up before executing
7293 * the shell procedure.
7294 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007295 if (exception == EXSHELLPROC) {
Eric Andersencb57d552001-06-28 07:25:16 +00007296 rootpid = getpid();
7297 rootshell = 1;
7298 minusc = NULL;
7299 state = 3;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007300 } else {
7301 if (exception == EXEXEC) {
7302 exitstatus = exerrno;
7303 } else if (exception == EXERROR) {
7304 exitstatus = 2;
7305 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007306 if (state == 0 || iflag == 0 || !rootshell)
7307 exitshell(exitstatus);
Eric Andersencb57d552001-06-28 07:25:16 +00007308 }
7309 reset();
Eric Andersen2870d962001-07-02 17:27:21 +00007310 if (exception == EXINT) {
Eric Andersencb57d552001-06-28 07:25:16 +00007311 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00007312 }
7313 popstackmark(&smark);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007314 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007315 if (state == 1)
7316 goto state1;
7317 else if (state == 2)
7318 goto state2;
7319 else if (state == 3)
7320 goto state3;
7321 else
7322 goto state4;
7323 }
7324 handler = &jmploc;
7325#ifdef DEBUG
7326 opentrace();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007327 trputs("Shell args: ");
7328 trargs(argv);
Eric Andersencb57d552001-06-28 07:25:16 +00007329#endif
7330 rootpid = getpid();
7331 rootshell = 1;
7332 init();
7333 setstackmark(&smark);
7334 procargs(argc, argv);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007335#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7336 if ( iflag ) {
7337 const char *hp = lookupvar("HISTFILE");
7338
7339 if(hp == NULL ) {
7340 hp = lookupvar("HOME");
7341 if(hp != NULL) {
7342 char *defhp = concat_path_file(hp, ".ash_history");
7343 setvar("HISTFILE", defhp, 0);
7344 free(defhp);
7345 }
7346 }
7347 }
7348#endif
Robert Griebl64f70cc2002-05-14 23:22:06 +00007349 if (argv[0] && argv[0][0] == '-')
7350 isloginsh = 1;
7351 if (isloginsh) {
Eric Andersencb57d552001-06-28 07:25:16 +00007352 state = 1;
7353 read_profile("/etc/profile");
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007354 state1:
Eric Andersencb57d552001-06-28 07:25:16 +00007355 state = 2;
7356 read_profile(".profile");
7357 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007358 state2:
Eric Andersencb57d552001-06-28 07:25:16 +00007359 state = 3;
7360#ifndef linux
7361 if (getuid() == geteuid() && getgid() == getegid()) {
7362#endif
7363 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7364 state = 3;
7365 read_profile(shinit);
7366 }
7367#ifndef linux
7368 }
7369#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007370 state3:
Eric Andersencb57d552001-06-28 07:25:16 +00007371 state = 4;
7372 if (sflag == 0 || minusc) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007373 static const char sigs[] = {
7374 SIGINT, SIGQUIT, SIGHUP,
Eric Andersencb57d552001-06-28 07:25:16 +00007375#ifdef SIGTSTP
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007376 SIGTSTP,
Eric Andersencb57d552001-06-28 07:25:16 +00007377#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007378 SIGPIPE
Eric Andersencb57d552001-06-28 07:25:16 +00007379 };
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007380
Glenn L McGrath50812ff2002-08-23 13:14:48 +00007381#define SIGSSIZE ((sizeof(sigs)/sizeof(sigs[0])))
Eric Andersencb57d552001-06-28 07:25:16 +00007382 int i;
7383
7384 for (i = 0; i < SIGSSIZE; i++)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007385 setsignal(sigs[i]);
Eric Andersencb57d552001-06-28 07:25:16 +00007386 }
7387
7388 if (minusc)
7389 evalstring(minusc, 0);
7390
7391 if (sflag || minusc == NULL) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007392 state4: /* XXX ??? - why isn't this before the "if" statement */
Robert Griebl350d26b2002-12-03 22:45:46 +00007393#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007394 if ( iflag ) {
7395 const char *hp = lookupvar("HISTFILE");
7396
7397 if(hp != NULL )
7398 load_history ( hp );
7399 }
Robert Griebl350d26b2002-12-03 22:45:46 +00007400#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007401 cmdloop(1);
7402 }
7403#if PROFILE
7404 monitor(0);
7405#endif
7406 exitshell(exitstatus);
7407 /* NOTREACHED */
7408}
7409
7410
7411/*
7412 * Read and execute commands. "Top" is nonzero for the top level command
7413 * loop; it turns on prompting if the shell is interactive.
7414 */
7415
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007416static void cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00007417{
7418 union node *n;
7419 struct stackmark smark;
7420 int inter;
7421 int numeof = 0;
7422
7423 TRACE(("cmdloop(%d) called\n", top));
7424 setstackmark(&smark);
7425 for (;;) {
7426 if (pendingsigs)
7427 dotrap();
7428 inter = 0;
7429 if (iflag && top) {
7430 inter++;
7431 showjobs(1);
Eric Andersend35c5df2002-01-09 15:37:36 +00007432#ifdef CONFIG_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +00007433 chkmail(0);
Eric Andersenec074692001-10-31 11:05:49 +00007434#endif
Eric Andersen3102ac42001-07-06 04:26:23 +00007435 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00007436 }
7437 n = parsecmd(inter);
7438 /* showtree(n); DEBUG */
7439 if (n == NEOF) {
7440 if (!top || numeof >= 50)
7441 break;
7442 if (!stoppedjobs()) {
7443 if (!Iflag)
7444 break;
7445 out2str("\nUse \"exit\" to leave shell.\n");
7446 }
7447 numeof++;
7448 } else if (n != NULL && nflag == 0) {
7449 job_warning = (job_warning == 2) ? 1 : 0;
7450 numeof = 0;
7451 evaltree(n, 0);
7452 }
7453 popstackmark(&smark);
7454 setstackmark(&smark);
7455 if (evalskip == SKIPFILE) {
7456 evalskip = 0;
7457 break;
7458 }
7459 }
7460 popstackmark(&smark);
7461}
7462
7463
7464
7465/*
7466 * Read /etc/profile or .profile. Return on error.
7467 */
7468
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007469static void read_profile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00007470{
7471 int fd;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007472 int xflag_save;
7473 int vflag_save;
Eric Andersencb57d552001-06-28 07:25:16 +00007474
7475 INTOFF;
7476 if ((fd = open(name, O_RDONLY)) >= 0)
7477 setinputfd(fd, 1);
7478 INTON;
7479 if (fd < 0)
7480 return;
7481 /* -q turns off -x and -v just when executing init files */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007482 /* Note: Might do a little redundant work, but reduces code size. */
7483 xflag_save = xflag;
7484 vflag_save = vflag;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007485 if (qflag) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007486 vflag = xflag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007487 }
7488 cmdloop(0);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007489 xflag = xflag_save;
7490 vflag = vflag_save;
Eric Andersencb57d552001-06-28 07:25:16 +00007491 popfile();
7492}
7493
7494
7495
7496/*
7497 * Read a file containing shell functions.
7498 */
7499
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007500static void readcmdfile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00007501{
7502 int fd;
7503
7504 INTOFF;
7505 if ((fd = open(name, O_RDONLY)) >= 0)
7506 setinputfd(fd, 1);
7507 else
7508 error("Can't open %s", name);
7509 INTON;
7510 cmdloop(0);
7511 popfile();
7512}
7513
7514
7515
7516/*
7517 * Take commands from a file. To be compatable we should do a path
7518 * search for the file, which is necessary to find sub-commands.
7519 */
7520
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007521static inline char *find_dot_file(char *mybasename)
Eric Andersencb57d552001-06-28 07:25:16 +00007522{
7523 char *fullname;
7524 const char *path = pathval();
7525 struct stat statb;
7526
7527 /* don't try this for absolute or relative paths */
7528 if (strchr(mybasename, '/'))
7529 return mybasename;
7530
7531 while ((fullname = padvance(&path, mybasename)) != NULL) {
7532 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
7533 /*
7534 * Don't bother freeing here, since it will
7535 * be freed by the caller.
7536 */
7537 return fullname;
7538 }
7539 stunalloc(fullname);
7540 }
7541
7542 /* not found in the PATH */
7543 error("%s: not found", mybasename);
7544 /* NOTREACHED */
7545}
7546
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007547static int dotcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007548{
7549 struct strlist *sp;
Eric Andersen69a20f02001-10-31 10:40:37 +00007550 volatile struct shparam saveparam;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007551
Eric Andersencb57d552001-06-28 07:25:16 +00007552 exitstatus = 0;
7553
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007554 for (sp = cmdenviron; sp; sp = sp->next)
Manuel Novoa III cad53642003-03-19 09:13:01 +00007555 setvareq(bb_xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +00007556
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007557 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00007558 char *fullname;
7559 struct stackmark smark;
7560
7561 setstackmark(&smark);
7562 fullname = find_dot_file(argv[1]);
Eric Andersen69a20f02001-10-31 10:40:37 +00007563
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007564 if (argc > 2) {
Eric Andersen69a20f02001-10-31 10:40:37 +00007565 saveparam = shellparam;
7566 shellparam.malloc = 0;
7567 shellparam.nparam = argc - 2;
7568 shellparam.p = argv + 2;
7569 };
7570
Eric Andersencb57d552001-06-28 07:25:16 +00007571 setinputfile(fullname, 1);
7572 commandname = fullname;
7573 cmdloop(0);
7574 popfile();
Eric Andersen69a20f02001-10-31 10:40:37 +00007575
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007576 if (argc > 2) {
Eric Andersen69a20f02001-10-31 10:40:37 +00007577 freeparam(&shellparam);
7578 shellparam = saveparam;
7579 };
7580
Eric Andersencb57d552001-06-28 07:25:16 +00007581 popstackmark(&smark);
7582 }
7583 return exitstatus;
7584}
7585
7586
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007587static int exitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007588{
7589 if (stoppedjobs())
7590 return 0;
Robert Griebl350d26b2002-12-03 22:45:46 +00007591
Eric Andersencb57d552001-06-28 07:25:16 +00007592 if (argc > 1)
7593 exitstatus = number(argv[1]);
7594 else
7595 exitstatus = oexitstatus;
7596 exitshell(exitstatus);
7597 /* NOTREACHED */
7598}
Eric Andersen62483552001-07-10 06:09:16 +00007599
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007600static pointer stalloc(int nbytes)
Eric Andersencb57d552001-06-28 07:25:16 +00007601{
7602 char *p;
7603
7604 nbytes = ALIGN(nbytes);
7605 if (nbytes > stacknleft) {
7606 int blocksize;
7607 struct stack_block *sp;
7608
7609 blocksize = nbytes;
7610 if (blocksize < MINSIZE)
7611 blocksize = MINSIZE;
7612 INTOFF;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007613 sp = xmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
Eric Andersencb57d552001-06-28 07:25:16 +00007614 sp->prev = stackp;
7615 stacknxt = sp->space;
7616 stacknleft = blocksize;
7617 stackp = sp;
7618 INTON;
7619 }
7620 p = stacknxt;
7621 stacknxt += nbytes;
7622 stacknleft -= nbytes;
7623 return p;
7624}
7625
7626
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007627static void stunalloc(pointer p)
Eric Andersen2870d962001-07-02 17:27:21 +00007628{
Eric Andersencb57d552001-06-28 07:25:16 +00007629#ifdef DEBUG
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007630 if (p == NULL) { /*DEBUG */
Eric Andersencb57d552001-06-28 07:25:16 +00007631 write(2, "stunalloc\n", 10);
7632 abort();
7633 }
7634#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007635 if (!(stacknxt >= (char *) p && (char *) p >= stackp->space)) {
Eric Andersencb57d552001-06-28 07:25:16 +00007636 p = stackp->space;
7637 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007638 stacknleft += stacknxt - (char *) p;
Eric Andersencb57d552001-06-28 07:25:16 +00007639 stacknxt = p;
7640}
7641
7642
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007643static void setstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00007644{
Eric Andersencb57d552001-06-28 07:25:16 +00007645 mark->stackp = stackp;
7646 mark->stacknxt = stacknxt;
7647 mark->stacknleft = stacknleft;
7648 mark->marknext = markp;
7649 markp = mark;
7650}
7651
7652
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007653static void popstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00007654{
Eric Andersencb57d552001-06-28 07:25:16 +00007655 struct stack_block *sp;
7656
7657 INTOFF;
7658 markp = mark->marknext;
7659 while (stackp != mark->stackp) {
7660 sp = stackp;
7661 stackp = sp->prev;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00007662 free(sp);
Eric Andersencb57d552001-06-28 07:25:16 +00007663 }
7664 stacknxt = mark->stacknxt;
7665 stacknleft = mark->stacknleft;
7666 INTON;
7667}
7668
7669
7670/*
7671 * When the parser reads in a string, it wants to stick the string on the
7672 * stack and only adjust the stack pointer when it knows how big the
7673 * string is. Stackblock (defined in stack.h) returns a pointer to a block
7674 * of space on top of the stack and stackblocklen returns the length of
7675 * this block. Growstackblock will grow this space by at least one byte,
7676 * possibly moving it (like realloc). Grabstackblock actually allocates the
7677 * part of the block that has been used.
7678 */
7679
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007680static void growstackblock(void)
7681{
Eric Andersencb57d552001-06-28 07:25:16 +00007682 char *p;
7683 int newlen = ALIGN(stacknleft * 2 + 100);
7684 char *oldspace = stacknxt;
7685 int oldlen = stacknleft;
7686 struct stack_block *sp;
7687 struct stack_block *oldstackp;
7688
7689 if (stacknxt == stackp->space && stackp != &stackbase) {
7690 INTOFF;
7691 oldstackp = stackp;
7692 sp = stackp;
7693 stackp = sp->prev;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007694 sp = xrealloc((pointer) sp,
7695 sizeof(struct stack_block) - MINSIZE + newlen);
Eric Andersencb57d552001-06-28 07:25:16 +00007696 sp->prev = stackp;
7697 stackp = sp;
7698 stacknxt = sp->space;
7699 stacknleft = newlen;
7700 {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007701 /* Stack marks pointing to the start of the old block
7702 * must be relocated to point to the new block
7703 */
7704 struct stackmark *xmark;
7705
7706 xmark = markp;
7707 while (xmark != NULL && xmark->stackp == oldstackp) {
7708 xmark->stackp = stackp;
7709 xmark->stacknxt = stacknxt;
7710 xmark->stacknleft = stacknleft;
7711 xmark = xmark->marknext;
7712 }
Eric Andersencb57d552001-06-28 07:25:16 +00007713 }
7714 INTON;
7715 } else {
7716 p = stalloc(newlen);
7717 memcpy(p, oldspace, oldlen);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007718 stacknxt = p; /* free the space */
7719 stacknleft += newlen; /* we just allocated */
Eric Andersencb57d552001-06-28 07:25:16 +00007720 }
7721}
7722
7723
7724
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007725static inline void grabstackblock(int len)
Eric Andersencb57d552001-06-28 07:25:16 +00007726{
7727 len = ALIGN(len);
7728 stacknxt += len;
7729 stacknleft -= len;
7730}
7731
7732
7733
7734/*
7735 * The following routines are somewhat easier to use that the above.
7736 * The user declares a variable of type STACKSTR, which may be declared
7737 * to be a register. The macro STARTSTACKSTR initializes things. Then
7738 * the user uses the macro STPUTC to add characters to the string. In
7739 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
7740 * grown as necessary. When the user is done, she can just leave the
7741 * string there and refer to it using stackblock(). Or she can allocate
7742 * the space for it using grabstackstr(). If it is necessary to allow
7743 * someone else to use the stack temporarily and then continue to grow
7744 * the string, the user should use grabstack to allocate the space, and
7745 * then call ungrabstr(p) to return to the previous mode of operation.
7746 *
7747 * USTPUTC is like STPUTC except that it doesn't check for overflow.
7748 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
7749 * is space for at least one character.
7750 */
7751
7752
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007753static char *growstackstr(void)
7754{
Eric Andersencb57d552001-06-28 07:25:16 +00007755 int len = stackblocksize();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007756
Eric Andersencb57d552001-06-28 07:25:16 +00007757 if (herefd >= 0 && len >= 1024) {
7758 xwrite(herefd, stackblock(), len);
7759 sstrnleft = len - 1;
7760 return stackblock();
7761 }
7762 growstackblock();
7763 sstrnleft = stackblocksize() - len - 1;
7764 return stackblock() + len;
7765}
7766
7767
7768/*
7769 * Called from CHECKSTRSPACE.
7770 */
7771
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007772static char *makestrspace(size_t newlen)
7773{
Eric Andersencb57d552001-06-28 07:25:16 +00007774 int len = stackblocksize() - sstrnleft;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007775
Eric Andersencb57d552001-06-28 07:25:16 +00007776 do {
7777 growstackblock();
7778 sstrnleft = stackblocksize() - len;
7779 } while (sstrnleft < newlen);
7780 return stackblock() + len;
7781}
7782
7783
7784
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007785static void ungrabstackstr(char *s, char *p)
Eric Andersen2870d962001-07-02 17:27:21 +00007786{
Eric Andersencb57d552001-06-28 07:25:16 +00007787 stacknleft += stacknxt - s;
7788 stacknxt = s;
7789 sstrnleft = stacknleft - (p - s);
7790}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007791
Eric Andersencb57d552001-06-28 07:25:16 +00007792/*
7793 * Miscelaneous builtins.
7794 */
7795
7796
7797#undef rflag
7798
Eric Andersencb57d552001-06-28 07:25:16 +00007799#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersen62483552001-07-10 06:09:16 +00007800typedef long rlim_t;
Eric Andersencb57d552001-06-28 07:25:16 +00007801#endif
7802
7803
7804
7805/*
7806 * The read builtin. The -e option causes backslashes to escape the
7807 * following character.
7808 *
7809 * This uses unbuffered input, which may be avoidable in some cases.
7810 */
7811
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007812static int readcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007813{
7814 char **ap;
7815 int backslash;
7816 char c;
7817 int rflag;
7818 char *prompt;
7819 const char *ifs;
7820 char *p;
7821 int startword;
7822 int status;
7823 int i;
7824
7825 rflag = 0;
7826 prompt = NULL;
7827 while ((i = nextopt("p:r")) != '\0') {
7828 if (i == 'p')
7829 prompt = optionarg;
7830 else
7831 rflag = 1;
7832 }
7833 if (prompt && isatty(0)) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007834 out2str(prompt); /* read without cmdedit */
Eric Andersencb57d552001-06-28 07:25:16 +00007835 flushall();
7836 }
7837 if (*(ap = argptr) == NULL)
7838 error("arg count");
7839 if ((ifs = bltinlookup("IFS")) == NULL)
7840 ifs = defifs;
7841 status = 0;
7842 startword = 1;
7843 backslash = 0;
7844 STARTSTACKSTR(p);
7845 for (;;) {
7846 if (read(0, &c, 1) != 1) {
7847 status = 1;
7848 break;
7849 }
7850 if (c == '\0')
7851 continue;
7852 if (backslash) {
7853 backslash = 0;
7854 if (c != '\n')
7855 STPUTC(c, p);
7856 continue;
7857 }
7858 if (!rflag && c == '\\') {
7859 backslash++;
7860 continue;
7861 }
7862 if (c == '\n')
7863 break;
7864 if (startword && *ifs == ' ' && strchr(ifs, c)) {
7865 continue;
7866 }
7867 startword = 0;
7868 if (backslash && c == '\\') {
7869 if (read(0, &c, 1) != 1) {
7870 status = 1;
7871 break;
7872 }
7873 STPUTC(c, p);
7874 } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
7875 STACKSTRNUL(p);
7876 setvar(*ap, stackblock(), 0);
7877 ap++;
7878 startword = 1;
7879 STARTSTACKSTR(p);
7880 } else {
7881 STPUTC(c, p);
7882 }
7883 }
7884 STACKSTRNUL(p);
7885 /* Remove trailing blanks */
7886 while (stackblock() <= --p && strchr(ifs, *p) != NULL)
7887 *p = '\0';
7888 setvar(*ap, stackblock(), 0);
7889 while (*++ap != NULL)
7890 setvar(*ap, nullstr, 0);
7891 return status;
7892}
7893
7894
7895
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007896static int umaskcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007897{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007898 static const char permuser[3] = "ugo";
7899 static const char permmode[3] = "rwx";
7900 static const short int permmask[] = {
7901 S_IRUSR, S_IWUSR, S_IXUSR,
7902 S_IRGRP, S_IWGRP, S_IXGRP,
7903 S_IROTH, S_IWOTH, S_IXOTH
7904 };
7905
Eric Andersencb57d552001-06-28 07:25:16 +00007906 char *ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007907 mode_t mask;
Eric Andersencb57d552001-06-28 07:25:16 +00007908 int i;
7909 int symbolic_mode = 0;
7910
Eric Andersen62483552001-07-10 06:09:16 +00007911 while (nextopt("S") != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00007912 symbolic_mode = 1;
7913 }
7914
7915 INTOFF;
7916 mask = umask(0);
7917 umask(mask);
7918 INTON;
7919
7920 if ((ap = *argptr) == NULL) {
7921 if (symbolic_mode) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007922 char buf[18];
7923 char *p = buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007924
7925 for (i = 0; i < 3; i++) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007926 int j;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007927
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007928 *p++ = permuser[i];
7929 *p++ = '=';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007930 for (j = 0; j < 3; j++) {
7931 if ((mask & permmask[3 * i + j]) == 0) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007932 *p++ = permmode[j];
7933 }
7934 }
7935 *p++ = ',';
7936 }
7937 *--p = 0;
7938 puts(buf);
Eric Andersencb57d552001-06-28 07:25:16 +00007939 } else {
Eric Andersen62483552001-07-10 06:09:16 +00007940 printf("%.4o\n", mask);
Eric Andersencb57d552001-06-28 07:25:16 +00007941 }
7942 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007943 if (is_digit((unsigned char) *ap)) {
Eric Andersencb57d552001-06-28 07:25:16 +00007944 mask = 0;
7945 do {
7946 if (*ap >= '8' || *ap < '0')
7947 error("Illegal number: %s", argv[1]);
7948 mask = (mask << 3) + (*ap - '0');
7949 } while (*++ap != '\0');
7950 umask(mask);
7951 } else {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007952 mask = ~mask & 0777;
Manuel Novoa III cad53642003-03-19 09:13:01 +00007953 if (!bb_parse_mode(ap, &mask)) {
Eric Andersencb57d552001-06-28 07:25:16 +00007954 error("Illegal mode: %s", ap);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007955 }
Eric Andersencb57d552001-06-28 07:25:16 +00007956 umask(~mask & 0777);
7957 }
7958 }
7959 return 0;
7960}
7961
7962/*
7963 * ulimit builtin
7964 *
7965 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
7966 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
7967 * ash by J.T. Conklin.
7968 *
7969 * Public domain.
7970 */
7971
7972struct limits {
7973 const char *name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007974 short cmd;
7975 short factor; /* multiply by to get rlim_{cur,max} values */
Eric Andersencb57d552001-06-28 07:25:16 +00007976};
7977
7978static const struct limits limits[] = {
7979#ifdef RLIMIT_CPU
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007980 {"time(seconds)", RLIMIT_CPU, 1},
Eric Andersencb57d552001-06-28 07:25:16 +00007981#endif
7982#ifdef RLIMIT_FSIZE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007983 {"file(blocks)", RLIMIT_FSIZE, 512},
Eric Andersencb57d552001-06-28 07:25:16 +00007984#endif
7985#ifdef RLIMIT_DATA
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007986 {"data(kbytes)", RLIMIT_DATA, 1024},
Eric Andersencb57d552001-06-28 07:25:16 +00007987#endif
7988#ifdef RLIMIT_STACK
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007989 {"stack(kbytes)", RLIMIT_STACK, 1024},
Eric Andersencb57d552001-06-28 07:25:16 +00007990#endif
7991#ifdef RLIMIT_CORE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007992 {"coredump(blocks)", RLIMIT_CORE, 512},
Eric Andersencb57d552001-06-28 07:25:16 +00007993#endif
7994#ifdef RLIMIT_RSS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007995 {"memory(kbytes)", RLIMIT_RSS, 1024},
Eric Andersencb57d552001-06-28 07:25:16 +00007996#endif
7997#ifdef RLIMIT_MEMLOCK
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007998 {"locked memory(kbytes)", RLIMIT_MEMLOCK, 1024},
Eric Andersencb57d552001-06-28 07:25:16 +00007999#endif
8000#ifdef RLIMIT_NPROC
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008001 {"process(processes)", RLIMIT_NPROC, 1},
Eric Andersencb57d552001-06-28 07:25:16 +00008002#endif
8003#ifdef RLIMIT_NOFILE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008004 {"nofiles(descriptors)", RLIMIT_NOFILE, 1},
Eric Andersencb57d552001-06-28 07:25:16 +00008005#endif
8006#ifdef RLIMIT_VMEM
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008007 {"vmemory(kbytes)", RLIMIT_VMEM, 1024},
Eric Andersencb57d552001-06-28 07:25:16 +00008008#endif
8009#ifdef RLIMIT_SWAP
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008010 {"swap(kbytes)", RLIMIT_SWAP, 1024},
Eric Andersencb57d552001-06-28 07:25:16 +00008011#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008012 {NULL, 0, 0}
Eric Andersencb57d552001-06-28 07:25:16 +00008013};
8014
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008015static int ulimitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008016{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008017 static const char unlimited_string[] = "unlimited";
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008018 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00008019 rlim_t val = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008020 enum { SOFT = 0x1, HARD = 0x2 } how = SOFT | HARD;
8021 const struct limits *l;
8022 int set, all = 0;
8023 int optc, what;
8024 struct rlimit limit;
Eric Andersencb57d552001-06-28 07:25:16 +00008025
8026 what = 'f';
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008027
8028 while ((optc = nextopt("HSa"
8029#ifdef RLIMIT_CPU
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008030 "t"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008031#endif
8032#ifdef RLIMIT_FSIZE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008033 "f"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008034#endif
8035#ifdef RLIMIT_DATA
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008036 "d"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008037#endif
8038#ifdef RLIMIT_STACK
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008039 "s"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008040#endif
8041#ifdef RLIMIT_CORE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008042 "c"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008043#endif
8044#ifdef RLIMIT_RSS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008045 "m"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008046#endif
8047#ifdef RLIMIT_MEMLOCK
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008048 "l"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008049#endif
8050#ifdef RLIMIT_NPROC
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008051 "p"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008052#endif
8053#ifdef RLIMIT_NOFILE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008054 "n"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008055#endif
8056#ifdef RLIMIT_VMEM
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008057 "v"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008058#endif
8059#ifdef RLIMIT_SWAP
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008060 "w"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008061#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008062 )) != '\0') {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008063 if (optc == 'H') {
Eric Andersencb57d552001-06-28 07:25:16 +00008064 how = HARD;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008065 } else if (optc == 'S') {
Eric Andersencb57d552001-06-28 07:25:16 +00008066 how = SOFT;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008067 } else if (optc == 'a') {
Eric Andersencb57d552001-06-28 07:25:16 +00008068 all = 1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008069 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00008070 what = optc;
8071 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008072 }
Eric Andersencb57d552001-06-28 07:25:16 +00008073
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008074 for (l = limits; l->name; l++) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008075 if (l->name[0] == what)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008076 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008077 if (l->name[1] == 'w' && what == 'w')
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008078 break;
8079 }
Eric Andersencb57d552001-06-28 07:25:16 +00008080
8081 set = *argptr ? 1 : 0;
8082 if (set) {
8083 char *p = *argptr;
8084
8085 if (all || argptr[1])
8086 error("too many arguments");
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008087 if (strcmp(p, unlimited_string) == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00008088 val = RLIM_INFINITY;
8089 else {
8090 val = (rlim_t) 0;
8091
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008092 while ((c = *p++) >= '0' && c <= '9') {
8093 val = (val * 10) + (long) (c - '0');
Eric Andersencb57d552001-06-28 07:25:16 +00008094 if (val < (rlim_t) 0)
8095 break;
8096 }
8097 if (c)
8098 error("bad number");
8099 val *= l->factor;
8100 }
8101 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008102
Eric Andersencb57d552001-06-28 07:25:16 +00008103 if (all) {
8104 for (l = limits; l->name; l++) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008105 printf("%-20s ", l->name);
Eric Andersencb57d552001-06-28 07:25:16 +00008106 getrlimit(l->cmd, &limit);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008107 OUTPUT_LIMIT:
Eric Andersencb57d552001-06-28 07:25:16 +00008108 if (how & SOFT)
8109 val = limit.rlim_cur;
8110 else if (how & HARD)
8111 val = limit.rlim_max;
8112
Eric Andersencb57d552001-06-28 07:25:16 +00008113 if (val == RLIM_INFINITY)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008114 puts(unlimited_string);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008115 else {
Eric Andersencb57d552001-06-28 07:25:16 +00008116 val /= l->factor;
Eric Andersen62483552001-07-10 06:09:16 +00008117 printf("%lld\n", (long long) val);
Eric Andersencb57d552001-06-28 07:25:16 +00008118 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008119 if (!all) {
8120 break;
8121 }
Eric Andersencb57d552001-06-28 07:25:16 +00008122 }
8123 return 0;
8124 }
8125
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008126 if (!set) {
8127 goto OUTPUT_LIMIT;
Eric Andersencb57d552001-06-28 07:25:16 +00008128 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008129
8130 getrlimit(l->cmd, &limit);
8131 if (how & HARD)
8132 limit.rlim_max = val;
8133 if (how & SOFT)
8134 limit.rlim_cur = val;
8135 if (setrlimit(l->cmd, &limit) < 0)
8136 error("error setting limit (%m)");
Eric Andersencb57d552001-06-28 07:25:16 +00008137 return 0;
8138}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008139
Eric Andersencb57d552001-06-28 07:25:16 +00008140/*
8141 * prefix -- see if pfx is a prefix of string.
8142 */
8143
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008144static int prefix(char const *pfx, char const *string)
Eric Andersen62483552001-07-10 06:09:16 +00008145{
Eric Andersencb57d552001-06-28 07:25:16 +00008146 while (*pfx) {
8147 if (*pfx++ != *string++)
8148 return 0;
8149 }
8150 return 1;
8151}
8152
Eric Andersen2870d962001-07-02 17:27:21 +00008153/*
8154 * Return true if s is a string of digits, and save munber in intptr
8155 * nagative is bad
8156 */
8157
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008158static int is_number(const char *p, int *intptr)
Eric Andersen2870d962001-07-02 17:27:21 +00008159{
8160 int ret = 0;
8161
8162 do {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008163 if (!is_digit(*p))
Eric Andersen2870d962001-07-02 17:27:21 +00008164 return 0;
8165 ret *= 10;
8166 ret += digit_val(*p);
8167 p++;
8168 } while (*p != '\0');
8169
8170 *intptr = ret;
8171 return 1;
8172}
Eric Andersencb57d552001-06-28 07:25:16 +00008173
8174/*
8175 * Convert a string of digits to an integer, printing an error message on
8176 * failure.
8177 */
8178
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008179static int number(const char *s)
Eric Andersen2870d962001-07-02 17:27:21 +00008180{
8181 int i;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008182
8183 if (!is_number(s, &i))
Eric Andersencb57d552001-06-28 07:25:16 +00008184 error("Illegal number: %s", s);
Eric Andersen2870d962001-07-02 17:27:21 +00008185 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00008186}
8187
Eric Andersencb57d552001-06-28 07:25:16 +00008188/*
8189 * Produce a possibly single quoted string suitable as input to the shell.
8190 * The return string is allocated on the stack.
8191 */
8192
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008193static char *single_quote(const char *s)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008194{
Eric Andersencb57d552001-06-28 07:25:16 +00008195 char *p;
8196
8197 STARTSTACKSTR(p);
8198
8199 do {
8200 char *q = p;
8201 size_t len1, len1p, len2, len2p;
8202
8203 len1 = strcspn(s, "'");
8204 len2 = strspn(s + len1, "'");
8205
8206 len1p = len1 ? len1 + 2 : len1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008207 len2p = len2 + ((len2 < 2) ? len2 : 2);
Eric Andersencb57d552001-06-28 07:25:16 +00008208
8209 CHECKSTRSPACE(len1p + len2p + 1, p);
8210
8211 if (len1) {
8212 *p = '\'';
Eric Andersencb57d552001-06-28 07:25:16 +00008213 q = p + 1 + len1;
8214 memcpy(p + 1, s, len1);
Eric Andersencb57d552001-06-28 07:25:16 +00008215 *q++ = '\'';
8216 s += len1;
8217 }
8218
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008219 if (len2 > 1) {
Eric Andersencb57d552001-06-28 07:25:16 +00008220 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008221 q += 1 + len2;
8222 memcpy(q + 1, s, len2);
8223 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008224 s += len2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008225 } else if (len2 == 1) {
8226 *q++ = '\\';
8227 *q = '\'';
8228 s++;
Eric Andersencb57d552001-06-28 07:25:16 +00008229 }
8230
8231 STADJUST(len1p + len2p, p);
8232 } while (*s);
8233
8234 USTPUTC(0, p);
8235
8236 return grabstackstr(p);
8237}
8238
8239/*
Eric Andersencb57d552001-06-28 07:25:16 +00008240 * Routine for dealing with parsed shell commands.
8241 */
8242
8243
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008244static void sizenodelist(const struct nodelist *);
8245static struct nodelist *copynodelist(const struct nodelist *);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008246static char *nodesavestr(const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00008247
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00008248#define CALCSIZE_TABLE
8249#define COPYNODE_TABLE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008250#if defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE)
8251/*
8252 * To collect a lot of redundant code in case statements for copynode()
8253 * and calcsize(), we implement a mini language here. Each type of node
8254 * struct has an associated instruction sequence that operates on its
8255 * members via their offsets. The instruction are pack in unsigned chars
8256 * with format IIDDDDDE where the bits are
8257 * I : part of the instruction opcode, which are
8258 * 00 : member is a pointer to another node
8259 * 40 : member is an integer
8260 * 80 : member is a pointer to a nodelist
8261 * CC : member is a pointer to a char string
8262 * D : data - the actual offset of the member to operate on in the struct
8263 * (since we assume bit 0 is set, it is not shifted)
8264 * E : flag signaling end of instruction sequence
8265 *
8266 * WARNING: In order to handle larger offsets for 64bit archs, this code
8267 * assumes that no offset can be an odd number and stores the
8268 * end-of-instructions flag in bit 0.
8269 */
8270
8271#define NODE_INTEGER 0x40
8272#define NODE_NODELIST 0x80
8273#define NODE_CHARPTR 0xC0
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008274#define NODE_NOMORE 0x01 /* Note: no offset should be odd (aligned) */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008275#define NODE_MBRMASK 0xC0
8276#define NODE_OFFSETMASK 0x3E
8277
8278static const unsigned char copynode_ops[35] = {
8279#define COPYNODE_OPS0 0
8280 offsetof(union node, nbinary.ch2),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008281 offsetof(union node, nbinary.ch1) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008282#define COPYNODE_OPS1 (COPYNODE_OPS0 + 2)
8283 offsetof(union node, ncmd.redirect),
8284 offsetof(union node, ncmd.args),
8285 offsetof(union node, ncmd.assign),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008286 offsetof(union node, ncmd.backgnd) | NODE_INTEGER | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008287#define COPYNODE_OPS2 (COPYNODE_OPS1 + 4)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008288 offsetof(union node, npipe.cmdlist) | NODE_NODELIST,
8289 offsetof(union node, npipe.backgnd) | NODE_INTEGER | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008290#define COPYNODE_OPS3 (COPYNODE_OPS2 + 2)
8291 offsetof(union node, nredir.redirect),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008292 offsetof(union node, nredir.n) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008293#define COPYNODE_OPS4 (COPYNODE_OPS3 + 2)
8294 offsetof(union node, nif.elsepart),
8295 offsetof(union node, nif.ifpart),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008296 offsetof(union node, nif.test) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008297#define COPYNODE_OPS5 (COPYNODE_OPS4 + 3)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008298 offsetof(union node, nfor.var) | NODE_CHARPTR,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008299 offsetof(union node, nfor.body),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008300 offsetof(union node, nfor.args) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008301#define COPYNODE_OPS6 (COPYNODE_OPS5 + 3)
8302 offsetof(union node, ncase.cases),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008303 offsetof(union node, ncase.expr) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008304#define COPYNODE_OPS7 (COPYNODE_OPS6 + 2)
8305 offsetof(union node, nclist.body),
8306 offsetof(union node, nclist.pattern),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008307 offsetof(union node, nclist.next) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008308#define COPYNODE_OPS8 (COPYNODE_OPS7 + 3)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008309 offsetof(union node, narg.backquote) | NODE_NODELIST,
8310 offsetof(union node, narg.text) | NODE_CHARPTR,
8311 offsetof(union node, narg.next) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008312#define COPYNODE_OPS9 (COPYNODE_OPS8 + 3)
8313 offsetof(union node, nfile.fname),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008314 offsetof(union node, nfile.fd) | NODE_INTEGER,
8315 offsetof(union node, nfile.next) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008316#define COPYNODE_OPS10 (COPYNODE_OPS9 + 3)
8317 offsetof(union node, ndup.vname),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008318 offsetof(union node, ndup.dupfd) | NODE_INTEGER,
8319 offsetof(union node, ndup.fd) | NODE_INTEGER,
8320 offsetof(union node, ndup.next) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008321#define COPYNODE_OPS11 (COPYNODE_OPS10 + 4)
8322 offsetof(union node, nhere.doc),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008323 offsetof(union node, nhere.fd) | NODE_INTEGER,
8324 offsetof(union node, nhere.next) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008325#define COPYNODE_OPS12 (COPYNODE_OPS11 + 3)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008326 offsetof(union node, nnot.com) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008327};
8328
8329#if COPYNODE_OPS12 != 34
8330#error COPYNODE_OPS12 is incorrect
8331#endif
8332
8333static const unsigned char copynode_ops_index[26] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008334 COPYNODE_OPS0, /* NSEMI */
8335 COPYNODE_OPS1, /* NCMD */
8336 COPYNODE_OPS2, /* NPIPE */
8337 COPYNODE_OPS3, /* NREDIR */
8338 COPYNODE_OPS3, /* NBACKGND */
8339 COPYNODE_OPS3, /* NSUBSHELL */
8340 COPYNODE_OPS0, /* NAND */
8341 COPYNODE_OPS0, /* NOR */
8342 COPYNODE_OPS4, /* NIF */
8343 COPYNODE_OPS0, /* NWHILE */
8344 COPYNODE_OPS0, /* NUNTIL */
8345 COPYNODE_OPS5, /* NFOR */
8346 COPYNODE_OPS6, /* NCASE */
8347 COPYNODE_OPS7, /* NCLIST */
8348 COPYNODE_OPS8, /* NDEFUN */
8349 COPYNODE_OPS8, /* NARG */
8350 COPYNODE_OPS9, /* NTO */
8351 COPYNODE_OPS9, /* NFROM */
8352 COPYNODE_OPS9, /* NFROMTO */
8353 COPYNODE_OPS9, /* NAPPEND */
8354 COPYNODE_OPS9, /* NTOOV */
8355 COPYNODE_OPS10, /* NTOFD */
8356 COPYNODE_OPS10, /* NFROMFD */
8357 COPYNODE_OPS11, /* NHERE */
8358 COPYNODE_OPS11, /* NXHERE */
8359 COPYNODE_OPS12, /* NNOT */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008360};
8361
8362#if NODE_CHARPTR != NODE_MBRMASK
8363#error NODE_CHARPTR != NODE_MBRMASK!!!
8364#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008365#endif /* defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE) */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008366
8367#ifdef COPYNODE_TABLE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008368static union node *copynode(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008369{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008370 union node *new;
8371 const unsigned char *p;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008372
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008373 if (n == NULL) {
8374 return NULL;
8375 }
8376 new = funcblock;
8377 new->type = n->type;
8378 funcblock = (char *) funcblock + (int) nodesize[n->type];
8379 p = copynode_ops + (int) copynode_ops_index[n->type];
8380 do {
8381 char *nn = ((char *) new) + ((int) (*p & NODE_OFFSETMASK));
8382 const char *no = ((const char *) n) + ((int) (*p & NODE_OFFSETMASK));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008383
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008384 if (!(*p & NODE_MBRMASK)) { /* standard node */
8385 *((union node **) nn) = copynode(*((const union node **) no));
8386 } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008387 *((const char **) nn) = nodesavestr(*((const char **) no));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008388 } else if (*p & NODE_NODELIST) { /* nodelist */
8389 *((struct nodelist **) nn)
8390 = copynodelist(*((const struct nodelist **) no));
8391 } else { /* integer */
8392 *((int *) nn) = *((int *) no);
8393 }
8394 } while (!(*p++ & NODE_NOMORE));
8395 return new;
Eric Andersencb57d552001-06-28 07:25:16 +00008396}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008397#else /* COPYNODE_TABLE */
8398static union node *copynode(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008399{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008400 union node *new;
Eric Andersencb57d552001-06-28 07:25:16 +00008401
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008402 if (n == NULL)
8403 return NULL;
8404 new = funcblock;
8405 funcblock = (char *) funcblock + nodesize[n->type];
8406 switch (n->type) {
8407 case NSEMI:
8408 case NAND:
8409 case NOR:
8410 case NWHILE:
8411 case NUNTIL:
8412 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8413 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8414 break;
8415 case NCMD:
8416 new->ncmd.redirect = copynode(n->ncmd.redirect);
8417 new->ncmd.args = copynode(n->ncmd.args);
8418 new->ncmd.assign = copynode(n->ncmd.assign);
8419 new->ncmd.backgnd = n->ncmd.backgnd;
8420 break;
8421 case NPIPE:
8422 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8423 new->npipe.backgnd = n->npipe.backgnd;
8424 break;
8425 case NREDIR:
8426 case NBACKGND:
8427 case NSUBSHELL:
8428 new->nredir.redirect = copynode(n->nredir.redirect);
8429 new->nredir.n = copynode(n->nredir.n);
8430 break;
8431 case NIF:
8432 new->nif.elsepart = copynode(n->nif.elsepart);
8433 new->nif.ifpart = copynode(n->nif.ifpart);
8434 new->nif.test = copynode(n->nif.test);
8435 break;
8436 case NFOR:
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008437 new->nfor.var = nodesavestr(n->nfor.var);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008438 new->nfor.body = copynode(n->nfor.body);
8439 new->nfor.args = copynode(n->nfor.args);
8440 break;
8441 case NCASE:
8442 new->ncase.cases = copynode(n->ncase.cases);
8443 new->ncase.expr = copynode(n->ncase.expr);
8444 break;
8445 case NCLIST:
8446 new->nclist.body = copynode(n->nclist.body);
8447 new->nclist.pattern = copynode(n->nclist.pattern);
8448 new->nclist.next = copynode(n->nclist.next);
8449 break;
8450 case NDEFUN:
8451 case NARG:
8452 new->narg.backquote = copynodelist(n->narg.backquote);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008453 new->narg.text = nodesavestr(n->narg.text);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008454 new->narg.next = copynode(n->narg.next);
8455 break;
8456 case NTO:
8457 case NFROM:
8458 case NFROMTO:
8459 case NAPPEND:
8460 case NTOOV:
8461 new->nfile.fname = copynode(n->nfile.fname);
8462 new->nfile.fd = n->nfile.fd;
8463 new->nfile.next = copynode(n->nfile.next);
8464 break;
8465 case NTOFD:
8466 case NFROMFD:
8467 new->ndup.vname = copynode(n->ndup.vname);
8468 new->ndup.dupfd = n->ndup.dupfd;
8469 new->ndup.fd = n->ndup.fd;
8470 new->ndup.next = copynode(n->ndup.next);
8471 break;
8472 case NHERE:
8473 case NXHERE:
8474 new->nhere.doc = copynode(n->nhere.doc);
8475 new->nhere.fd = n->nhere.fd;
8476 new->nhere.next = copynode(n->nhere.next);
8477 break;
8478 case NNOT:
8479 new->nnot.com = copynode(n->nnot.com);
8480 break;
8481 };
8482 new->type = n->type;
8483 return new;
Eric Andersencb57d552001-06-28 07:25:16 +00008484}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008485#endif /* COPYNODE_TABLE */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008486
8487#ifdef CALCSIZE_TABLE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008488static void calcsize(const union node *n)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008489{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008490 const unsigned char *p;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008491
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008492 if (n == NULL)
8493 return;
8494 funcblocksize += (int) nodesize[n->type];
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008495
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008496 p = copynode_ops + (int) copynode_ops_index[n->type];
8497 do {
8498 const char *no = ((const char *) n) + ((int) (*p & NODE_OFFSETMASK));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008499
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008500 if (!(*p & NODE_MBRMASK)) { /* standard node */
8501 calcsize(*((const union node **) no));
8502 } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
8503 funcstringsize += strlen(*((const char **) no)) + 1;
8504 } else if (*p & NODE_NODELIST) { /* nodelist */
8505 sizenodelist(*((const struct nodelist **) no));
8506 } /* else integer -- ignore */
8507 } while (!(*p++ & NODE_NOMORE));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008508}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008509#else /* CALCSIZE_TABLE */
8510static void calcsize(const union node *n)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008511{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008512 if (n == NULL)
8513 return;
8514 funcblocksize += nodesize[n->type];
8515 switch (n->type) {
8516 case NSEMI:
8517 case NAND:
8518 case NOR:
8519 case NWHILE:
8520 case NUNTIL:
8521 calcsize(n->nbinary.ch2);
8522 calcsize(n->nbinary.ch1);
8523 break;
8524 case NCMD:
8525 calcsize(n->ncmd.redirect);
8526 calcsize(n->ncmd.args);
8527 calcsize(n->ncmd.assign);
8528 break;
8529 case NPIPE:
8530 sizenodelist(n->npipe.cmdlist);
8531 break;
8532 case NREDIR:
8533 case NBACKGND:
8534 case NSUBSHELL:
8535 calcsize(n->nredir.redirect);
8536 calcsize(n->nredir.n);
8537 break;
8538 case NIF:
8539 calcsize(n->nif.elsepart);
8540 calcsize(n->nif.ifpart);
8541 calcsize(n->nif.test);
8542 break;
8543 case NFOR:
8544 funcstringsize += strlen(n->nfor.var) + 1;
8545 calcsize(n->nfor.body);
8546 calcsize(n->nfor.args);
8547 break;
8548 case NCASE:
8549 calcsize(n->ncase.cases);
8550 calcsize(n->ncase.expr);
8551 break;
8552 case NCLIST:
8553 calcsize(n->nclist.body);
8554 calcsize(n->nclist.pattern);
8555 calcsize(n->nclist.next);
8556 break;
8557 case NDEFUN:
8558 case NARG:
8559 sizenodelist(n->narg.backquote);
8560 funcstringsize += strlen(n->narg.text) + 1;
8561 calcsize(n->narg.next);
8562 break;
8563 case NTO:
8564 case NFROM:
8565 case NFROMTO:
8566 case NAPPEND:
8567 case NTOOV:
8568 calcsize(n->nfile.fname);
8569 calcsize(n->nfile.next);
8570 break;
8571 case NTOFD:
8572 case NFROMFD:
8573 calcsize(n->ndup.vname);
8574 calcsize(n->ndup.next);
8575 break;
8576 case NHERE:
8577 case NXHERE:
8578 calcsize(n->nhere.doc);
8579 calcsize(n->nhere.next);
8580 break;
8581 case NNOT:
8582 calcsize(n->nnot.com);
8583 break;
8584 };
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008585}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008586#endif /* CALCSIZE_TABLE */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008587
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008588static void sizenodelist(const struct nodelist *lp)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008589{
8590 while (lp) {
8591 funcblocksize += ALIGN(sizeof(struct nodelist));
8592 calcsize(lp->n);
8593 lp = lp->next;
8594 }
8595}
Eric Andersencb57d552001-06-28 07:25:16 +00008596
8597
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008598static struct nodelist *copynodelist(const struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008599{
8600 struct nodelist *start;
8601 struct nodelist **lpp;
8602
8603 lpp = &start;
8604 while (lp) {
8605 *lpp = funcblock;
8606 funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist));
8607 (*lpp)->n = copynode(lp->n);
8608 lp = lp->next;
8609 lpp = &(*lpp)->next;
8610 }
8611 *lpp = NULL;
8612 return start;
8613}
8614
8615
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008616static char *nodesavestr(const char *s)
Eric Andersencb57d552001-06-28 07:25:16 +00008617{
Eric Andersen62483552001-07-10 06:09:16 +00008618 const char *p = s;
8619 char *q = funcstring;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008620 char *rtn = funcstring;
Eric Andersencb57d552001-06-28 07:25:16 +00008621
8622 while ((*q++ = *p++) != '\0')
8623 continue;
8624 funcstring = q;
8625 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00008626}
8627
Eric Andersend35c5df2002-01-09 15:37:36 +00008628#ifdef CONFIG_ASH_GETOPTS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008629static int getopts(char *, char *, char **, int *, int *);
Eric Andersencb57d552001-06-28 07:25:16 +00008630#endif
8631
Eric Andersencb57d552001-06-28 07:25:16 +00008632/*
8633 * Process the shell command line arguments.
8634 */
8635
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008636static void procargs(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008637{
8638 int i;
8639
8640 argptr = argv;
8641 if (argc > 0)
8642 argptr++;
8643 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00008644 optent_val(i) = 2;
Eric Andersencb57d552001-06-28 07:25:16 +00008645 options(1);
8646 if (*argptr == NULL && minusc == NULL)
8647 sflag = 1;
8648 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8649 iflag = 1;
8650 if (mflag == 2)
8651 mflag = iflag;
8652 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00008653 if (optent_val(i) == 2)
8654 optent_val(i) = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008655 arg0 = argv[0];
8656 if (sflag == 0 && minusc == NULL) {
8657 commandname = argv[0];
8658 arg0 = *argptr++;
8659 setinputfile(arg0, 0);
8660 commandname = arg0;
8661 }
8662 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8663 if (argptr && minusc && *argptr)
Eric Andersen2870d962001-07-02 17:27:21 +00008664 arg0 = *argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00008665
8666 shellparam.p = argptr;
8667 shellparam.optind = 1;
8668 shellparam.optoff = -1;
8669 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8670 while (*argptr) {
8671 shellparam.nparam++;
8672 argptr++;
8673 }
8674 optschanged();
8675}
8676
8677
Eric Andersencb57d552001-06-28 07:25:16 +00008678
8679/*
8680 * Process shell options. The global variable argptr contains a pointer
8681 * to the argument list; we advance it past the options.
8682 */
8683
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008684static inline void minus_o(const char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +00008685{
8686 int i;
8687
8688 if (name == NULL) {
8689 out1str("Current option settings\n");
8690 for (i = 0; i < NOPTS; i++)
8691 printf("%-16s%s\n", optent_name(optlist[i]),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008692 optent_val(i) ? "on" : "off");
Eric Andersen62483552001-07-10 06:09:16 +00008693 } else {
8694 for (i = 0; i < NOPTS; i++)
8695 if (equal(name, optent_name(optlist[i]))) {
8696 setoption(optent_letter(optlist[i]), val);
8697 return;
8698 }
8699 error("Illegal option -o %s", name);
8700 }
8701}
8702
8703
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008704static void options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00008705{
8706 char *p;
8707 int val;
8708 int c;
8709
8710 if (cmdline)
8711 minusc = NULL;
8712 while ((p = *argptr) != NULL) {
8713 argptr++;
8714 if ((c = *p++) == '-') {
8715 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00008716 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8717 if (!cmdline) {
8718 /* "-" means turn off -x and -v */
8719 if (p[0] == '\0')
8720 xflag = vflag = 0;
8721 /* "--" means reset params */
8722 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00008723 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00008724 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008725 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00008726 }
8727 } else if (c == '+') {
8728 val = 0;
8729 } else {
8730 argptr--;
8731 break;
8732 }
8733 while ((c = *p++) != '\0') {
8734 if (c == 'c' && cmdline) {
8735 char *q;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008736
8737#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */
Eric Andersencb57d552001-06-28 07:25:16 +00008738 if (*p == '\0')
8739#endif
8740 q = *argptr++;
8741 if (q == NULL || minusc != NULL)
8742 error("Bad -c option");
8743 minusc = q;
8744#ifdef NOHACK
8745 break;
8746#endif
8747 } else if (c == 'o') {
8748 minus_o(*argptr, val);
8749 if (*argptr)
8750 argptr++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008751 } else if (cmdline && (c == '-')) { // long options
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008752 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +00008753 isloginsh = 1;
8754 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008755 } else {
8756 setoption(c, val);
8757 }
8758 }
8759 }
8760}
8761
Eric Andersencb57d552001-06-28 07:25:16 +00008762
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008763static void setoption(int flag, int val)
Eric Andersen2870d962001-07-02 17:27:21 +00008764{
Eric Andersencb57d552001-06-28 07:25:16 +00008765 int i;
8766
8767 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00008768 if (optent_letter(optlist[i]) == flag) {
8769 optent_val(i) = val;
Eric Andersencb57d552001-06-28 07:25:16 +00008770 if (val) {
8771 /* #%$ hack for ksh semantics */
8772 if (flag == 'V')
8773 Eflag = 0;
8774 else if (flag == 'E')
8775 Vflag = 0;
8776 }
8777 return;
8778 }
8779 error("Illegal option -%c", flag);
8780 /* NOTREACHED */
8781}
8782
8783
8784
Eric Andersencb57d552001-06-28 07:25:16 +00008785/*
8786 * Set the shell parameters.
8787 */
8788
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008789static void setparam(char **argv)
Eric Andersen2870d962001-07-02 17:27:21 +00008790{
Eric Andersencb57d552001-06-28 07:25:16 +00008791 char **newparam;
8792 char **ap;
8793 int nparam;
8794
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008795 for (nparam = 0; argv[nparam]; nparam++);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008796 ap = newparam = xmalloc((nparam + 1) * sizeof *ap);
Eric Andersencb57d552001-06-28 07:25:16 +00008797 while (*argv) {
Manuel Novoa III cad53642003-03-19 09:13:01 +00008798 *ap++ = bb_xstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +00008799 }
8800 *ap = NULL;
8801 freeparam(&shellparam);
8802 shellparam.malloc = 1;
8803 shellparam.nparam = nparam;
8804 shellparam.p = newparam;
8805 shellparam.optind = 1;
8806 shellparam.optoff = -1;
8807}
8808
8809
8810/*
8811 * Free the list of positional parameters.
8812 */
8813
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008814static void freeparam(volatile struct shparam *param)
Eric Andersen2870d962001-07-02 17:27:21 +00008815{
Eric Andersencb57d552001-06-28 07:25:16 +00008816 char **ap;
8817
8818 if (param->malloc) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008819 for (ap = param->p; *ap; ap++)
Aaron Lehmann49c024a2002-08-02 06:39:47 +00008820 free(*ap);
8821 free(param->p);
Eric Andersencb57d552001-06-28 07:25:16 +00008822 }
8823}
8824
8825
8826
8827/*
8828 * The shift builtin command.
8829 */
8830
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008831static int shiftcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008832{
8833 int n;
8834 char **ap1, **ap2;
8835
8836 n = 1;
8837 if (argc > 1)
8838 n = number(argv[1]);
8839 if (n > shellparam.nparam)
8840 error("can't shift that many");
8841 INTOFF;
8842 shellparam.nparam -= n;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008843 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Eric Andersencb57d552001-06-28 07:25:16 +00008844 if (shellparam.malloc)
Aaron Lehmann49c024a2002-08-02 06:39:47 +00008845 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +00008846 }
8847 ap2 = shellparam.p;
8848 while ((*ap2++ = *ap1++) != NULL);
8849 shellparam.optind = 1;
8850 shellparam.optoff = -1;
8851 INTON;
8852 return 0;
8853}
8854
8855
8856
8857/*
8858 * The set command builtin.
8859 */
8860
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008861static int setcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008862{
8863 if (argc == 1)
8864 return showvarscmd(argc, argv);
8865 INTOFF;
8866 options(0);
8867 optschanged();
8868 if (*argptr != NULL) {
8869 setparam(argptr);
8870 }
8871 INTON;
8872 return 0;
8873}
8874
8875
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008876static void getoptsreset(const char *value)
Eric Andersencb57d552001-06-28 07:25:16 +00008877{
8878 shellparam.optind = number(value);
8879 shellparam.optoff = -1;
8880}
8881
Eric Andersenbdfd0d72001-10-24 05:00:29 +00008882#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00008883static void change_lc_all(const char *value)
8884{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008885 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00008886 setlocale(LC_ALL, value);
8887}
8888
8889static void change_lc_ctype(const char *value)
8890{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008891 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00008892 setlocale(LC_CTYPE, value);
8893}
8894
8895#endif
8896
Eric Andersend35c5df2002-01-09 15:37:36 +00008897#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008898/*
8899 * The getopts builtin. Shellparam.optnext points to the next argument
8900 * to be processed. Shellparam.optptr points to the next character to
8901 * be processed in the current argument. If shellparam.optnext is NULL,
8902 * then it's the first time getopts has been called.
8903 */
8904
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008905static int getoptscmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008906{
8907 char **optbase;
8908
8909 if (argc < 3)
8910 error("Usage: getopts optstring var [arg]");
8911 else if (argc == 3) {
8912 optbase = shellparam.p;
8913 if (shellparam.optind > shellparam.nparam + 1) {
8914 shellparam.optind = 1;
8915 shellparam.optoff = -1;
8916 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008917 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00008918 optbase = &argv[3];
8919 if (shellparam.optind > argc - 2) {
8920 shellparam.optind = 1;
8921 shellparam.optoff = -1;
8922 }
8923 }
8924
8925 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008926 &shellparam.optoff);
Eric Andersencb57d552001-06-28 07:25:16 +00008927}
8928
8929/*
8930 * Safe version of setvar, returns 1 on success 0 on failure.
8931 */
8932
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008933static int setvarsafe(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008934{
8935 struct jmploc jmploc;
8936 struct jmploc *volatile savehandler = handler;
8937 int err = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008938
Eric Andersencb57d552001-06-28 07:25:16 +00008939#ifdef __GNUC__
8940 (void) &err;
8941#endif
8942
8943 if (setjmp(jmploc.loc))
8944 err = 1;
8945 else {
8946 handler = &jmploc;
8947 setvar(name, val, flags);
8948 }
8949 handler = savehandler;
8950 return err;
8951}
8952
8953static int
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008954getopts(char *optstr, char *optvar, char **optfirst, int *myoptind,
8955 int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00008956{
8957 char *p, *q;
8958 char c = '?';
8959 int done = 0;
8960 int err = 0;
8961 char s[10];
8962 char **optnext = optfirst + *myoptind - 1;
8963
8964 if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008965 strlen(*(optnext - 1)) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00008966 p = NULL;
8967 else
8968 p = *(optnext - 1) + *optoff;
8969 if (p == NULL || *p == '\0') {
8970 /* Current word is done, advance */
8971 if (optnext == NULL)
8972 return 1;
8973 p = *optnext;
8974 if (p == NULL || *p != '-' || *++p == '\0') {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008975 atend:
Eric Andersencb57d552001-06-28 07:25:16 +00008976 *myoptind = optnext - optfirst + 1;
8977 p = NULL;
8978 done = 1;
8979 goto out;
8980 }
8981 optnext++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008982 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00008983 goto atend;
8984 }
8985
8986 c = *p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008987 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +00008988 if (*q == '\0') {
8989 if (optstr[0] == ':') {
8990 s[0] = c;
8991 s[1] = '\0';
8992 err |= setvarsafe("OPTARG", s, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008993 } else {
Eric Andersen3102ac42001-07-06 04:26:23 +00008994 out2fmt("Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00008995 (void) unsetvar("OPTARG");
8996 }
8997 c = '?';
8998 goto bad;
8999 }
9000 if (*++q == ':')
9001 q++;
9002 }
9003
9004 if (*++q == ':') {
9005 if (*p == '\0' && (p = *optnext) == NULL) {
9006 if (optstr[0] == ':') {
9007 s[0] = c;
9008 s[1] = '\0';
9009 err |= setvarsafe("OPTARG", s, 0);
9010 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009011 } else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009012 out2fmt("No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009013 (void) unsetvar("OPTARG");
9014 c = '?';
9015 }
9016 goto bad;
9017 }
9018
9019 if (p == *optnext)
9020 optnext++;
9021 setvarsafe("OPTARG", p, 0);
9022 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009023 } else
Eric Andersencb57d552001-06-28 07:25:16 +00009024 setvarsafe("OPTARG", "", 0);
9025 *myoptind = optnext - optfirst + 1;
9026 goto out;
9027
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009028 bad:
Eric Andersencb57d552001-06-28 07:25:16 +00009029 *myoptind = 1;
9030 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009031 out:
Eric Andersencb57d552001-06-28 07:25:16 +00009032 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersen3102ac42001-07-06 04:26:23 +00009033 snprintf(s, sizeof(s), "%d", *myoptind);
Eric Andersencb57d552001-06-28 07:25:16 +00009034 err |= setvarsafe("OPTIND", s, VNOFUNC);
9035 s[0] = c;
9036 s[1] = '\0';
9037 err |= setvarsafe(optvar, s, 0);
9038 if (err) {
9039 *myoptind = 1;
9040 *optoff = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00009041 exraise(EXERROR);
9042 }
9043 return done;
9044}
Eric Andersen2870d962001-07-02 17:27:21 +00009045#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009046
9047/*
9048 * XXX - should get rid of. have all builtins use getopt(3). the
9049 * library getopt must have the BSD extension static variable "optreset"
9050 * otherwise it can't be used within the shell safely.
9051 *
9052 * Standard option processing (a la getopt) for builtin routines. The
9053 * only argument that is passed to nextopt is the option string; the
9054 * other arguments are unnecessary. It return the character, or '\0' on
9055 * end of input.
9056 */
9057
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009058static int nextopt(const char *optstring)
Eric Andersen62483552001-07-10 06:09:16 +00009059{
Eric Andersencb57d552001-06-28 07:25:16 +00009060 char *p;
9061 const char *q;
9062 char c;
9063
9064 if ((p = optptr) == NULL || *p == '\0') {
9065 p = *argptr;
9066 if (p == NULL || *p != '-' || *++p == '\0')
9067 return '\0';
9068 argptr++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009069 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009070 return '\0';
9071 }
9072 c = *p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009073 for (q = optstring; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +00009074 if (*q == '\0')
9075 error("Illegal option -%c", c);
9076 if (*++q == ':')
9077 q++;
9078 }
9079 if (*++q == ':') {
9080 if (*p == '\0' && (p = *argptr++) == NULL)
9081 error("No arg for -%c option", c);
9082 optionarg = p;
9083 p = NULL;
9084 }
9085 optptr = p;
9086 return c;
9087}
9088
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009089static void flushall()
9090{
Eric Andersencb57d552001-06-28 07:25:16 +00009091 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009092 fflush(stdout);
Eric Andersencb57d552001-06-28 07:25:16 +00009093 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009094}
9095
9096
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009097static void out2fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009098{
9099 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009100
Eric Andersencb57d552001-06-28 07:25:16 +00009101 va_start(ap, fmt);
Eric Andersen3102ac42001-07-06 04:26:23 +00009102 vfprintf(stderr, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009103 va_end(ap);
9104}
9105
Eric Andersencb57d552001-06-28 07:25:16 +00009106/*
9107 * Version of write which resumes after a signal is caught.
9108 */
9109
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009110static int xwrite(int fd, const char *buf, int nbytes)
Eric Andersen2870d962001-07-02 17:27:21 +00009111{
Eric Andersencb57d552001-06-28 07:25:16 +00009112 int ntry;
9113 int i;
9114 int n;
9115
9116 n = nbytes;
9117 ntry = 0;
9118 for (;;) {
9119 i = write(fd, buf, n);
9120 if (i > 0) {
9121 if ((n -= i) <= 0)
9122 return nbytes;
9123 buf += i;
9124 ntry = 0;
9125 } else if (i == 0) {
9126 if (++ntry > 10)
9127 return nbytes - n;
9128 } else if (errno != EINTR) {
9129 return -1;
9130 }
9131 }
9132}
9133
9134
Eric Andersencb57d552001-06-28 07:25:16 +00009135/*
9136 * Shell command parser.
9137 */
9138
9139#define EOFMARKLEN 79
9140
9141
9142
9143struct heredoc {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009144 struct heredoc *next; /* next here document in list */
9145 union node *here; /* redirection node */
9146 char *eofmark; /* string indicating end of input */
9147 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009148};
9149
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009150static struct heredoc *heredoclist; /* list of here documents to read */
9151static int parsebackquote; /* nonzero if we are inside backquotes */
9152static int doprompt; /* if set, prompt the user */
9153static int needprompt; /* true if interactive and at start of line */
9154static int lasttoken; /* last token read */
Eric Andersencb57d552001-06-28 07:25:16 +00009155
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009156static char *wordtext; /* text of last word returned by readtoken */
Eric Andersencb57d552001-06-28 07:25:16 +00009157
Eric Andersen2870d962001-07-02 17:27:21 +00009158static struct nodelist *backquotelist;
9159static union node *redirnode;
Eric Andersen044228d2001-07-17 01:12:36 +00009160static struct heredoc *heredoc;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009161static int quoteflag; /* set if (part of) last token was quoted */
9162static int startlinno; /* line # where last token started */
Eric Andersencb57d552001-06-28 07:25:16 +00009163
9164
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009165static union node *list(int);
9166static union node *andor(void);
9167static union node *pipeline(void);
9168static union node *command(void);
Eric Andersena3483db2001-10-24 08:01:06 +00009169static union node *simplecmd(union node **rpp, union node *redir);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009170static void parsefname(void);
9171static void parseheredoc(void);
9172static char peektoken(void);
9173static int readtoken(void);
9174static int xxreadtoken(void);
9175static int readtoken1(int, int, const char *, int);
9176static int noexpand(char *);
9177static void synexpect(int) __attribute__ ((noreturn));
9178static void synerror(const char *) __attribute__ ((noreturn));
9179static void setprompt(int);
Eric Andersencb57d552001-06-28 07:25:16 +00009180
9181
9182/*
9183 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9184 * valid parse tree indicating a blank line.)
9185 */
9186
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009187static union node *parsecmd(int interact)
Eric Andersencb57d552001-06-28 07:25:16 +00009188{
9189 int t;
9190
9191 tokpushback = 0;
9192 doprompt = interact;
9193 if (doprompt)
9194 setprompt(1);
9195 else
9196 setprompt(0);
9197 needprompt = 0;
9198 t = readtoken();
9199 if (t == TEOF)
9200 return NEOF;
9201 if (t == TNL)
9202 return NULL;
9203 tokpushback++;
9204 return list(1);
9205}
9206
9207
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009208static union node *list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +00009209{
9210 union node *n1, *n2, *n3;
9211 int tok;
9212
9213 checkkwd = 2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009214 if (nlflag == 0 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009215 return NULL;
9216 n1 = NULL;
9217 for (;;) {
9218 n2 = andor();
9219 tok = readtoken();
9220 if (tok == TBACKGND) {
9221 if (n2->type == NCMD || n2->type == NPIPE) {
9222 n2->ncmd.backgnd = 1;
9223 } else if (n2->type == NREDIR) {
9224 n2->type = NBACKGND;
9225 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009226 n3 = (union node *) stalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009227 n3->type = NBACKGND;
9228 n3->nredir.n = n2;
9229 n3->nredir.redirect = NULL;
9230 n2 = n3;
9231 }
9232 }
9233 if (n1 == NULL) {
9234 n1 = n2;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009235 } else {
9236 n3 = (union node *) stalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009237 n3->type = NSEMI;
9238 n3->nbinary.ch1 = n1;
9239 n3->nbinary.ch2 = n2;
9240 n1 = n3;
9241 }
9242 switch (tok) {
9243 case TBACKGND:
9244 case TSEMI:
9245 tok = readtoken();
9246 /* fall through */
9247 case TNL:
9248 if (tok == TNL) {
9249 parseheredoc();
9250 if (nlflag)
9251 return n1;
9252 } else {
9253 tokpushback++;
9254 }
9255 checkkwd = 2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009256 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009257 return n1;
9258 break;
9259 case TEOF:
9260 if (heredoclist)
9261 parseheredoc();
9262 else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009263 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009264 return n1;
9265 default:
9266 if (nlflag)
9267 synexpect(-1);
9268 tokpushback++;
9269 return n1;
9270 }
9271 }
9272}
9273
9274
9275
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009276static union node *andor()
9277{
Eric Andersencb57d552001-06-28 07:25:16 +00009278 union node *n1, *n2, *n3;
9279 int t;
9280
9281 checkkwd = 1;
9282 n1 = pipeline();
9283 for (;;) {
9284 if ((t = readtoken()) == TAND) {
9285 t = NAND;
9286 } else if (t == TOR) {
9287 t = NOR;
9288 } else {
9289 tokpushback++;
9290 return n1;
9291 }
9292 checkkwd = 2;
9293 n2 = pipeline();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009294 n3 = (union node *) stalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009295 n3->type = t;
9296 n3->nbinary.ch1 = n1;
9297 n3->nbinary.ch2 = n2;
9298 n1 = n3;
9299 }
9300}
9301
9302
9303
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009304static union node *pipeline()
9305{
Eric Andersencb57d552001-06-28 07:25:16 +00009306 union node *n1, *n2, *pipenode;
9307 struct nodelist *lp, *prev;
9308 int negate;
9309
9310 negate = 0;
9311 TRACE(("pipeline: entered\n"));
9312 if (readtoken() == TNOT) {
9313 negate = !negate;
9314 checkkwd = 1;
9315 } else
9316 tokpushback++;
9317 n1 = command();
9318 if (readtoken() == TPIPE) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009319 pipenode = (union node *) stalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +00009320 pipenode->type = NPIPE;
9321 pipenode->npipe.backgnd = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009322 lp = (struct nodelist *) stalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00009323 pipenode->npipe.cmdlist = lp;
9324 lp->n = n1;
9325 do {
9326 prev = lp;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009327 lp = (struct nodelist *) stalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00009328 checkkwd = 2;
9329 lp->n = command();
9330 prev->next = lp;
9331 } while (readtoken() == TPIPE);
9332 lp->next = NULL;
9333 n1 = pipenode;
9334 }
9335 tokpushback++;
9336 if (negate) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009337 n2 = (union node *) stalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +00009338 n2->type = NNOT;
9339 n2->nnot.com = n1;
9340 return n2;
9341 } else
9342 return n1;
9343}
9344
9345
9346
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009347static union node *command(void)
9348{
Eric Andersencb57d552001-06-28 07:25:16 +00009349 union node *n1, *n2;
9350 union node *ap, **app;
9351 union node *cp, **cpp;
9352 union node *redir, **rpp;
9353 int t;
9354
9355 redir = NULL;
9356 n1 = NULL;
9357 rpp = &redir;
9358
Eric Andersen88cec252001-09-06 17:35:20 +00009359 /* Check for redirection which may precede command */
9360 while (readtoken() == TREDIR) {
9361 *rpp = n2 = redirnode;
9362 rpp = &n2->nfile.next;
9363 parsefname();
9364 }
9365 tokpushback++;
9366
Eric Andersencb57d552001-06-28 07:25:16 +00009367 switch (readtoken()) {
9368 case TIF:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009369 n1 = (union node *) stalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009370 n1->type = NIF;
9371 n1->nif.test = list(0);
9372 if (readtoken() != TTHEN)
9373 synexpect(TTHEN);
9374 n1->nif.ifpart = list(0);
9375 n2 = n1;
9376 while (readtoken() == TELIF) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009377 n2->nif.elsepart = (union node *) stalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009378 n2 = n2->nif.elsepart;
9379 n2->type = NIF;
9380 n2->nif.test = list(0);
9381 if (readtoken() != TTHEN)
9382 synexpect(TTHEN);
9383 n2->nif.ifpart = list(0);
9384 }
9385 if (lasttoken == TELSE)
9386 n2->nif.elsepart = list(0);
9387 else {
9388 n2->nif.elsepart = NULL;
9389 tokpushback++;
9390 }
9391 if (readtoken() != TFI)
9392 synexpect(TFI);
9393 checkkwd = 1;
9394 break;
9395 case TWHILE:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009396 case TUNTIL:{
Eric Andersencb57d552001-06-28 07:25:16 +00009397 int got;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009398 n1 = (union node *) stalloc(sizeof(struct nbinary));
9399 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +00009400 n1->nbinary.ch1 = list(0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009401 if ((got = readtoken()) != TDO) {
9402 TRACE(("expecting DO got %s %s\n", tokname(got),
9403 got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009404 synexpect(TDO);
9405 }
9406 n1->nbinary.ch2 = list(0);
9407 if (readtoken() != TDONE)
9408 synexpect(TDONE);
9409 checkkwd = 1;
9410 break;
9411 }
9412 case TFOR:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009413 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Eric Andersencb57d552001-06-28 07:25:16 +00009414 synerror("Bad for loop variable");
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009415 n1 = (union node *) stalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +00009416 n1->type = NFOR;
9417 n1->nfor.var = wordtext;
9418 checkkwd = 1;
9419 if (readtoken() == TIN) {
9420 app = &ap;
9421 while (readtoken() == TWORD) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009422 n2 = (union node *) stalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009423 n2->type = NARG;
9424 n2->narg.text = wordtext;
9425 n2->narg.backquote = backquotelist;
9426 *app = n2;
9427 app = &n2->narg.next;
9428 }
9429 *app = NULL;
9430 n1->nfor.args = ap;
9431 if (lasttoken != TNL && lasttoken != TSEMI)
9432 synexpect(-1);
9433 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009434 static char argvars[5] = { CTLVAR, VSNORMAL | VSQUOTE,
9435 '@', '=', '\0'
9436 };
9437 n2 = (union node *) stalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009438 n2->type = NARG;
9439 n2->narg.text = argvars;
9440 n2->narg.backquote = NULL;
9441 n2->narg.next = NULL;
9442 n1->nfor.args = n2;
9443 /*
9444 * Newline or semicolon here is optional (but note
9445 * that the original Bourne shell only allowed NL).
9446 */
9447 if (lasttoken != TNL && lasttoken != TSEMI)
9448 tokpushback++;
9449 }
9450 checkkwd = 2;
9451 if (readtoken() != TDO)
9452 synexpect(TDO);
9453 n1->nfor.body = list(0);
9454 if (readtoken() != TDONE)
9455 synexpect(TDONE);
9456 checkkwd = 1;
9457 break;
9458 case TCASE:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009459 n1 = (union node *) stalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +00009460 n1->type = NCASE;
9461 if (readtoken() != TWORD)
9462 synexpect(TWORD);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009463 n1->ncase.expr = n2 = (union node *) stalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009464 n2->type = NARG;
9465 n2->narg.text = wordtext;
9466 n2->narg.backquote = backquotelist;
9467 n2->narg.next = NULL;
9468 do {
9469 checkkwd = 1;
9470 } while (readtoken() == TNL);
9471 if (lasttoken != TIN)
9472 synerror("expecting \"in\"");
9473 cpp = &n1->ncase.cases;
9474 checkkwd = 2, readtoken();
9475 do {
9476 if (lasttoken == TLP)
9477 readtoken();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009478 *cpp = cp = (union node *) stalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +00009479 cp->type = NCLIST;
9480 app = &cp->nclist.pattern;
9481 for (;;) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009482 *app = ap = (union node *) stalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009483 ap->type = NARG;
9484 ap->narg.text = wordtext;
9485 ap->narg.backquote = backquotelist;
9486 if (checkkwd = 2, readtoken() != TPIPE)
9487 break;
9488 app = &ap->narg.next;
9489 readtoken();
9490 }
9491 ap->narg.next = NULL;
9492 if (lasttoken != TRP)
9493 synexpect(TRP);
9494 cp->nclist.body = list(0);
9495
9496 checkkwd = 2;
9497 if ((t = readtoken()) != TESAC) {
9498 if (t != TENDCASE)
9499 synexpect(TENDCASE);
9500 else
9501 checkkwd = 2, readtoken();
9502 }
9503 cpp = &cp->nclist.next;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009504 } while (lasttoken != TESAC);
Eric Andersencb57d552001-06-28 07:25:16 +00009505 *cpp = NULL;
9506 checkkwd = 1;
9507 break;
9508 case TLP:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009509 n1 = (union node *) stalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009510 n1->type = NSUBSHELL;
9511 n1->nredir.n = list(0);
9512 n1->nredir.redirect = NULL;
9513 if (readtoken() != TRP)
9514 synexpect(TRP);
9515 checkkwd = 1;
9516 break;
9517 case TBEGIN:
9518 n1 = list(0);
9519 if (readtoken() != TEND)
9520 synexpect(TEND);
9521 checkkwd = 1;
9522 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009523 /* Handle an empty command like other simple commands. */
Eric Andersencb57d552001-06-28 07:25:16 +00009524 case TSEMI:
9525 case TAND:
9526 case TOR:
9527 case TNL:
9528 case TEOF:
9529 case TRP:
9530 case TBACKGND:
9531 /*
9532 * An empty command before a ; doesn't make much sense, and
9533 * should certainly be disallowed in the case of `if ;'.
9534 */
9535 if (!redir)
9536 synexpect(-1);
9537 case TWORD:
Eric Andersencb57d552001-06-28 07:25:16 +00009538 tokpushback++;
Eric Andersena3483db2001-10-24 08:01:06 +00009539 n1 = simplecmd(rpp, redir);
Eric Andersencb57d552001-06-28 07:25:16 +00009540 return n1;
9541 default:
9542 synexpect(-1);
9543 /* NOTREACHED */
9544 }
9545
9546 /* Now check for redirection which may follow command */
9547 while (readtoken() == TREDIR) {
9548 *rpp = n2 = redirnode;
9549 rpp = &n2->nfile.next;
9550 parsefname();
9551 }
9552 tokpushback++;
9553 *rpp = NULL;
9554 if (redir) {
9555 if (n1->type != NSUBSHELL) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009556 n2 = (union node *) stalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009557 n2->type = NREDIR;
9558 n2->nredir.n = n1;
9559 n1 = n2;
9560 }
9561 n1->nredir.redirect = redir;
9562 }
9563
9564 return n1;
9565}
9566
9567
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009568static union node *simplecmd(union node **rpp, union node *redir)
9569{
Eric Andersencb57d552001-06-28 07:25:16 +00009570 union node *args, **app;
9571 union node *n = NULL;
9572 union node *vars, **vpp;
Eric Andersena3483db2001-10-24 08:01:06 +00009573 union node **orig_rpp;
Eric Andersencb57d552001-06-28 07:25:16 +00009574
9575 args = NULL;
9576 app = &args;
9577 vars = NULL;
9578 vpp = &vars;
Eric Andersena3483db2001-10-24 08:01:06 +00009579
9580 /* If we don't have any redirections already, then we must reset
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009581 rpp to be the address of the local redir variable. */
Eric Andersena3483db2001-10-24 08:01:06 +00009582 if (redir == 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009583 rpp = &redir;
Eric Andersena3483db2001-10-24 08:01:06 +00009584 /* We save the incoming value, because we need this for shell
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009585 functions. There can not be a redirect or an argument between
9586 the function name and the open parenthesis. */
Eric Andersena3483db2001-10-24 08:01:06 +00009587 orig_rpp = rpp;
Eric Andersencb57d552001-06-28 07:25:16 +00009588
9589 checkalias = 2;
9590 for (;;) {
9591 switch (readtoken()) {
9592 case TWORD:
9593 case TASSIGN:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009594 n = (union node *) stalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009595 n->type = NARG;
9596 n->narg.text = wordtext;
9597 n->narg.backquote = backquotelist;
9598 if (lasttoken == TWORD) {
9599 *app = n;
9600 app = &n->narg.next;
9601 } else {
9602 *vpp = n;
9603 vpp = &n->narg.next;
9604 }
9605 break;
9606 case TREDIR:
9607 *rpp = n = redirnode;
9608 rpp = &n->nfile.next;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009609 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +00009610 break;
9611 case TLP:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009612 if (args && app == &args->narg.next && !vars && rpp == orig_rpp) {
Eric Andersencb57d552001-06-28 07:25:16 +00009613 /* We have a function */
9614 if (readtoken() != TRP)
9615 synexpect(TRP);
Eric Andersencb57d552001-06-28 07:25:16 +00009616 n->type = NDEFUN;
9617 checkkwd = 2;
9618 n->narg.next = command();
9619 return n;
9620 }
9621 /* fall through */
9622 default:
9623 tokpushback++;
9624 goto out;
9625 }
9626 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009627 out:
Eric Andersencb57d552001-06-28 07:25:16 +00009628 *app = NULL;
9629 *vpp = NULL;
9630 *rpp = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009631 n = (union node *) stalloc(sizeof(struct ncmd));
Eric Andersencb57d552001-06-28 07:25:16 +00009632 n->type = NCMD;
9633 n->ncmd.backgnd = 0;
9634 n->ncmd.args = args;
9635 n->ncmd.assign = vars;
9636 n->ncmd.redirect = redir;
9637 return n;
9638}
9639
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009640static union node *makename(void)
9641{
Eric Andersencb57d552001-06-28 07:25:16 +00009642 union node *n;
9643
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009644 n = (union node *) stalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009645 n->type = NARG;
9646 n->narg.next = NULL;
9647 n->narg.text = wordtext;
9648 n->narg.backquote = backquotelist;
9649 return n;
9650}
9651
9652static void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +00009653{
Eric Andersencb57d552001-06-28 07:25:16 +00009654 TRACE(("Fix redir %s %d\n", text, err));
9655 if (!err)
9656 n->ndup.vname = NULL;
9657
9658 if (is_digit(text[0]) && text[1] == '\0')
9659 n->ndup.dupfd = digit_val(text[0]);
9660 else if (text[0] == '-' && text[1] == '\0')
9661 n->ndup.dupfd = -1;
9662 else {
9663
9664 if (err)
9665 synerror("Bad fd number");
9666 else
9667 n->ndup.vname = makename();
9668 }
9669}
9670
9671
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009672static void parsefname(void)
9673{
Eric Andersencb57d552001-06-28 07:25:16 +00009674 union node *n = redirnode;
9675
9676 if (readtoken() != TWORD)
9677 synexpect(-1);
9678 if (n->type == NHERE) {
9679 struct heredoc *here = heredoc;
9680 struct heredoc *p;
9681 int i;
9682
9683 if (quoteflag == 0)
9684 n->type = NXHERE;
9685 TRACE(("Here document %d\n", n->type));
9686 if (here->striptabs) {
9687 while (*wordtext == '\t')
9688 wordtext++;
9689 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009690 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0
9691 || i > EOFMARKLEN)
Eric Andersencb57d552001-06-28 07:25:16 +00009692 synerror("Illegal eof marker for << redirection");
9693 rmescapes(wordtext);
9694 here->eofmark = wordtext;
9695 here->next = NULL;
9696 if (heredoclist == NULL)
9697 heredoclist = here;
9698 else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009699 for (p = heredoclist; p->next; p = p->next);
Eric Andersencb57d552001-06-28 07:25:16 +00009700 p->next = here;
9701 }
9702 } else if (n->type == NTOFD || n->type == NFROMFD) {
9703 fixredir(n, wordtext, 0);
9704 } else {
9705 n->nfile.fname = makename();
9706 }
9707}
9708
9709
9710/*
9711 * Input any here documents.
9712 */
9713
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009714static void parseheredoc()
9715{
Eric Andersencb57d552001-06-28 07:25:16 +00009716 struct heredoc *here;
9717 union node *n;
9718
9719 while (heredoclist) {
9720 here = heredoclist;
9721 heredoclist = here->next;
9722 if (needprompt) {
9723 setprompt(2);
9724 needprompt = 0;
9725 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009726 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
9727 here->eofmark, here->striptabs);
9728 n = (union node *) stalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009729 n->narg.type = NARG;
9730 n->narg.next = NULL;
9731 n->narg.text = wordtext;
9732 n->narg.backquote = backquotelist;
9733 here->here->nhere.doc = n;
9734 }
9735}
9736
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009737static char peektoken()
9738{
Eric Andersencb57d552001-06-28 07:25:16 +00009739 int t;
9740
9741 t = readtoken();
9742 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009743 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +00009744}
9745
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009746static int readtoken()
9747{
Eric Andersencb57d552001-06-28 07:25:16 +00009748 int t;
Eric Andersen7467c8d2001-07-12 20:26:32 +00009749
Eric Andersencb57d552001-06-28 07:25:16 +00009750 int savecheckalias = checkalias;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009751
Eric Andersen8e139872002-07-04 00:19:46 +00009752#ifdef CONFIG_ASH_ALIAS
Eric Andersen7467c8d2001-07-12 20:26:32 +00009753 int savecheckkwd = checkkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009754 struct alias *ap;
Eric Andersen2870d962001-07-02 17:27:21 +00009755#endif
9756
Eric Andersencb57d552001-06-28 07:25:16 +00009757#ifdef DEBUG
9758 int alreadyseen = tokpushback;
9759#endif
9760
Eric Andersend35c5df2002-01-09 15:37:36 +00009761#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009762 top:
Eric Andersen2870d962001-07-02 17:27:21 +00009763#endif
9764
Eric Andersencb57d552001-06-28 07:25:16 +00009765 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +00009766
Eric Andersencb57d552001-06-28 07:25:16 +00009767 checkalias = savecheckalias;
9768
9769 if (checkkwd) {
9770 /*
9771 * eat newlines
9772 */
9773 if (checkkwd == 2) {
9774 checkkwd = 0;
9775 while (t == TNL) {
9776 parseheredoc();
9777 t = xxreadtoken();
9778 }
9779 }
9780 checkkwd = 0;
9781 /*
9782 * check for keywords
9783 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009784 if (t == TWORD && !quoteflag) {
Eric Andersencb57d552001-06-28 07:25:16 +00009785 const char *const *pp;
9786
9787 if ((pp = findkwd(wordtext))) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009788 lasttoken = t = pp - tokname_array;
9789 TRACE(("keyword %s recognized\n", tokname(t)));
Eric Andersencb57d552001-06-28 07:25:16 +00009790 goto out;
9791 }
9792 }
9793 }
9794
Eric Andersen7467c8d2001-07-12 20:26:32 +00009795
Eric Andersencb57d552001-06-28 07:25:16 +00009796 if (t != TWORD) {
9797 if (t != TREDIR) {
9798 checkalias = 0;
9799 }
9800 } else if (checkalias == 2 && isassignment(wordtext)) {
9801 lasttoken = t = TASSIGN;
9802 } else if (checkalias) {
Eric Andersen8e139872002-07-04 00:19:46 +00009803#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009804 if (!quoteflag && (ap = *__lookupalias(wordtext)) != NULL
9805 && !(ap->flag & ALIASINUSE)) {
Eric Andersencb57d552001-06-28 07:25:16 +00009806 if (*ap->val) {
9807 pushstring(ap->val, strlen(ap->val), ap);
9808 }
9809 checkkwd = savecheckkwd;
9810 goto top;
9811 }
Eric Andersen2870d962001-07-02 17:27:21 +00009812#endif
Eric Andersen8e139872002-07-04 00:19:46 +00009813 checkalias = 0;
Eric Andersen7467c8d2001-07-12 20:26:32 +00009814 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009815 out:
Eric Andersencb57d552001-06-28 07:25:16 +00009816#ifdef DEBUG
9817 if (!alreadyseen)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009818 TRACE(("token %s %s\n", tokname(t), t == TWORD
9819 || t == TASSIGN ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009820 else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009821 TRACE(("reread token %s %s\n", tokname(t), t == TWORD
9822 || t == TASSIGN ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009823#endif
9824 return (t);
9825}
9826
9827
9828/*
9829 * Read the next input token.
9830 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +00009831 * backquotes. We set quoteflag to true if any part of the word was
9832 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +00009833 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +00009834 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +00009835 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +00009836 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +00009837 *
9838 * [Change comment: here documents and internal procedures]
9839 * [Readtoken shouldn't have any arguments. Perhaps we should make the
9840 * word parsing code into a separate routine. In this case, readtoken
9841 * doesn't need to have any internal procedures, but parseword does.
9842 * We could also make parseoperator in essence the main routine, and
9843 * have parseword (readtoken1?) handle both words and redirection.]
9844 */
9845
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009846#define NEW_xxreadtoken
9847#ifdef NEW_xxreadtoken
9848
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009849static const char xxreadtoken_chars[] = "\n()&|;"; /* singles must be first! */
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009850static const char xxreadtoken_tokens[] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009851 TNL, TLP, TRP, /* only single occurrence allowed */
9852 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
9853 TEOF, /* corresponds to trailing nul */
9854 TAND, TOR, TENDCASE, /* if double occurrence */
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009855};
9856
9857#define xxreadtoken_doubles \
9858 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
9859#define xxreadtoken_singles \
9860 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
9861
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009862static int xxreadtoken()
9863{
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009864 int c;
9865
9866 if (tokpushback) {
9867 tokpushback = 0;
9868 return lasttoken;
9869 }
9870 if (needprompt) {
9871 setprompt(2);
9872 needprompt = 0;
9873 }
9874 startlinno = plinno;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009875 for (;;) { /* until token or start of word found */
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009876 c = pgetc_macro();
9877
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009878 if ((c != ' ') && (c != '\t')
Eric Andersend35c5df2002-01-09 15:37:36 +00009879#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009880 && (c != PEOA)
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009881#endif
9882 ) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009883 if (c == '#') {
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009884 while ((c = pgetc()) != '\n' && c != PEOF);
9885 pungetc();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009886 } else if (c == '\\') {
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009887 if (pgetc() != '\n') {
9888 pungetc();
9889 goto READTOKEN1;
9890 }
9891 startlinno = ++plinno;
9892 setprompt(doprompt ? 2 : 0);
9893 } else {
9894 const char *p
9895 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
9896
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009897 if (c != PEOF) {
9898 if (c == '\n') {
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009899 plinno++;
9900 needprompt = doprompt;
9901 }
9902
9903 p = strchr(xxreadtoken_chars, c);
9904 if (p == NULL) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009905 READTOKEN1:
9906 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009907 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009908
9909 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
9910 if (pgetc() == *p) { /* double occurrence? */
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009911 p += xxreadtoken_doubles + 1;
9912 } else {
9913 pungetc();
9914 }
9915 }
9916 }
9917
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009918 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009919 }
9920 }
9921 }
9922}
9923
9924
9925#else
Eric Andersen2870d962001-07-02 17:27:21 +00009926#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +00009927
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009928static int xxreadtoken()
9929{
Eric Andersencb57d552001-06-28 07:25:16 +00009930 int c;
9931
9932 if (tokpushback) {
9933 tokpushback = 0;
9934 return lasttoken;
9935 }
9936 if (needprompt) {
9937 setprompt(2);
9938 needprompt = 0;
9939 }
9940 startlinno = plinno;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009941 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +00009942 c = pgetc_macro();
9943 switch (c) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009944 case ' ':
9945 case '\t':
Eric Andersend35c5df2002-01-09 15:37:36 +00009946#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00009947 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +00009948#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009949 continue;
9950 case '#':
9951 while ((c = pgetc()) != '\n' && c != PEOF);
9952 pungetc();
9953 continue;
9954 case '\\':
9955 if (pgetc() == '\n') {
9956 startlinno = ++plinno;
9957 if (doprompt)
9958 setprompt(2);
9959 else
9960 setprompt(0);
9961 continue;
9962 }
9963 pungetc();
9964 goto breakloop;
9965 case '\n':
9966 plinno++;
9967 needprompt = doprompt;
9968 RETURN(TNL);
9969 case PEOF:
9970 RETURN(TEOF);
9971 case '&':
9972 if (pgetc() == '&')
9973 RETURN(TAND);
9974 pungetc();
9975 RETURN(TBACKGND);
9976 case '|':
9977 if (pgetc() == '|')
9978 RETURN(TOR);
9979 pungetc();
9980 RETURN(TPIPE);
9981 case ';':
9982 if (pgetc() == ';')
9983 RETURN(TENDCASE);
9984 pungetc();
9985 RETURN(TSEMI);
9986 case '(':
9987 RETURN(TLP);
9988 case ')':
9989 RETURN(TRP);
9990 default:
9991 goto breakloop;
9992 }
9993 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009994 breakloop:
9995 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009996#undef RETURN
9997}
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009998#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009999
Eric Andersencb57d552001-06-28 07:25:16 +000010000/*
10001 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10002 * is not NULL, read a here document. In the latter case, eofmark is the
10003 * word which marks the end of the document and striptabs is true if
10004 * leading tabs should be stripped from the document. The argument firstc
10005 * is the first character of the input token or document.
10006 *
10007 * Because C does not have internal subroutines, I have simulated them
10008 * using goto's to implement the subroutine linkage. The following macros
10009 * will run code that appears at the end of readtoken1.
10010 */
10011
Eric Andersen2870d962001-07-02 17:27:21 +000010012#define CHECKEND() {goto checkend; checkend_return:;}
10013#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10014#define PARSESUB() {goto parsesub; parsesub_return:;}
10015#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10016#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10017#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010018
10019static int
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010020readtoken1(int firstc, int syntax, const char *eofmark, int striptabs)
10021{
Eric Andersencb57d552001-06-28 07:25:16 +000010022 int c = firstc;
10023 char *out;
10024 int len;
10025 char line[EOFMARKLEN + 1];
10026 struct nodelist *bqlist;
10027 int quotef;
10028 int dblquote;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010029 int varnest; /* levels of variables expansion */
10030 int arinest; /* levels of arithmetic expansion */
10031 int parenlevel; /* levels of parens in arithmetic */
10032 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +000010033 int oldstyle;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010034 int prevsyntax; /* syntax before arithmetic */
10035
Eric Andersencb57d552001-06-28 07:25:16 +000010036#if __GNUC__
10037 /* Avoid longjmp clobbering */
10038 (void) &out;
10039 (void) &quotef;
10040 (void) &dblquote;
10041 (void) &varnest;
10042 (void) &arinest;
10043 (void) &parenlevel;
10044 (void) &dqvarnest;
10045 (void) &oldstyle;
10046 (void) &prevsyntax;
10047 (void) &syntax;
10048#endif
10049
10050 startlinno = plinno;
10051 dblquote = 0;
10052 if (syntax == DQSYNTAX)
10053 dblquote = 1;
10054 quotef = 0;
10055 bqlist = NULL;
10056 varnest = 0;
10057 arinest = 0;
10058 parenlevel = 0;
10059 dqvarnest = 0;
10060
10061 STARTSTACKSTR(out);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010062 loop:{ /* for each line, until end of word */
10063 CHECKEND(); /* set c to PEOF if at end of here document */
10064 for (;;) { /* until end of line or end of word */
10065 CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
10066 switch (SIT(c, syntax)) {
10067 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010068 if (syntax == BASESYNTAX)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010069 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010070 USTPUTC(c, out);
10071 plinno++;
10072 if (doprompt)
10073 setprompt(2);
10074 else
10075 setprompt(0);
10076 c = pgetc();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010077 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010078 case CWORD:
10079 USTPUTC(c, out);
10080 break;
10081 case CCTL:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010082 if ((eofmark == NULL || dblquote) && dqvarnest == 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010083 USTPUTC(CTLESC, out);
10084 USTPUTC(c, out);
10085 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010086 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010087 c = pgetc2();
10088 if (c == PEOF) {
10089 USTPUTC('\\', out);
10090 pungetc();
10091 } else if (c == '\n') {
10092 if (doprompt)
10093 setprompt(2);
10094 else
10095 setprompt(0);
10096 } else {
10097 if (dblquote && c != '\\' && c != '`' && c != '$'
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010098 && (c != '"' || eofmark != NULL))
Eric Andersencb57d552001-06-28 07:25:16 +000010099 USTPUTC('\\', out);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010100 if (SIT(c, SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010101 USTPUTC(CTLESC, out);
10102 else if (eofmark == NULL)
10103 USTPUTC(CTLQUOTEMARK, out);
10104 USTPUTC(c, out);
10105 quotef++;
10106 }
10107 break;
10108 case CSQUOTE:
10109 if (eofmark == NULL)
10110 USTPUTC(CTLQUOTEMARK, out);
10111 syntax = SQSYNTAX;
10112 break;
10113 case CDQUOTE:
10114 if (eofmark == NULL)
10115 USTPUTC(CTLQUOTEMARK, out);
10116 syntax = DQSYNTAX;
10117 dblquote = 1;
10118 break;
10119 case CENDQUOTE:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010120 if (eofmark != NULL && arinest == 0 && varnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010121 USTPUTC(c, out);
10122 } else {
10123 if (arinest) {
10124 syntax = ARISYNTAX;
10125 dblquote = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010126 } else if (eofmark == NULL && dqvarnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010127 syntax = BASESYNTAX;
10128 dblquote = 0;
10129 }
10130 quotef++;
10131 }
10132 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010133 case CVAR: /* '$' */
10134 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010135 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010136 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010137 if (varnest > 0) {
10138 varnest--;
10139 if (dqvarnest > 0) {
10140 dqvarnest--;
10141 }
10142 USTPUTC(CTLENDVAR, out);
10143 } else {
10144 USTPUTC(c, out);
10145 }
10146 break;
Eric Andersend35c5df2002-01-09 15:37:36 +000010147#ifdef CONFIG_ASH_MATH_SUPPORT
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010148 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010149 parenlevel++;
10150 USTPUTC(c, out);
10151 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010152 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010153 if (parenlevel > 0) {
10154 USTPUTC(c, out);
10155 --parenlevel;
10156 } else {
10157 if (pgetc() == ')') {
10158 if (--arinest == 0) {
10159 USTPUTC(CTLENDARI, out);
10160 syntax = prevsyntax;
10161 if (syntax == DQSYNTAX)
10162 dblquote = 1;
10163 else
10164 dblquote = 0;
10165 } else
10166 USTPUTC(')', out);
10167 } else {
10168 /*
10169 * unbalanced parens
10170 * (don't 2nd guess - no error)
10171 */
10172 pungetc();
10173 USTPUTC(')', out);
10174 }
10175 }
10176 break;
10177#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010178 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010179 PARSEBACKQOLD();
10180 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010181 case CENDFILE:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010182 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010183 case CIGN:
10184 break;
10185 default:
10186 if (varnest == 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010187 goto endword; /* exit outer loop */
Eric Andersend35c5df2002-01-09 15:37:36 +000010188#ifdef CONFIG_ASH_ALIAS
Eric Andersen3102ac42001-07-06 04:26:23 +000010189 if (c != PEOA)
10190#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010191 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010192
Eric Andersencb57d552001-06-28 07:25:16 +000010193 }
10194 c = pgetc_macro();
10195 }
10196 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010197 endword:
Eric Andersencb57d552001-06-28 07:25:16 +000010198 if (syntax == ARISYNTAX)
10199 synerror("Missing '))'");
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010200 if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010201 synerror("Unterminated quoted string");
10202 if (varnest != 0) {
10203 startlinno = plinno;
10204 synerror("Missing '}'");
10205 }
10206 USTPUTC('\0', out);
10207 len = out - stackblock();
10208 out = stackblock();
10209 if (eofmark == NULL) {
10210 if ((c == '>' || c == '<')
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010211 && quotef == 0 && len <= 2 && (*out == '\0' || is_digit(*out))) {
Eric Andersencb57d552001-06-28 07:25:16 +000010212 PARSEREDIR();
10213 return lasttoken = TREDIR;
10214 } else {
10215 pungetc();
10216 }
10217 }
10218 quoteflag = quotef;
10219 backquotelist = bqlist;
10220 grabstackblock(len);
10221 wordtext = out;
10222 return lasttoken = TWORD;
10223/* end of readtoken routine */
10224
10225
10226
10227/*
10228 * Check to see whether we are at the end of the here document. When this
10229 * is called, c is set to the first character of the next input line. If
10230 * we are at the end of the here document, this routine sets the c to PEOF.
10231 */
10232
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010233 checkend:{
10234 if (eofmark) {
Eric Andersend35c5df2002-01-09 15:37:36 +000010235#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010236 if (c == PEOA) {
Eric Andersencb57d552001-06-28 07:25:16 +000010237 c = pgetc2();
10238 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010239#endif
10240 if (striptabs) {
10241 while (c == '\t') {
10242 c = pgetc2();
10243 }
10244 }
10245 if (c == *eofmark) {
10246 if (pfgets(line, sizeof line) != NULL) {
10247 const char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010248
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010249 p = line;
10250 for (q = eofmark + 1; *q && *p == *q; p++, q++);
10251 if (*p == '\n' && *q == '\0') {
10252 c = PEOF;
10253 plinno++;
10254 needprompt = doprompt;
10255 } else {
10256 pushstring(line, strlen(line), NULL);
10257 }
Eric Andersencb57d552001-06-28 07:25:16 +000010258 }
10259 }
10260 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010261 goto checkend_return;
Eric Andersencb57d552001-06-28 07:25:16 +000010262 }
Eric Andersencb57d552001-06-28 07:25:16 +000010263
10264
10265/*
10266 * Parse a redirection operator. The variable "out" points to a string
10267 * specifying the fd to be redirected. The variable "c" contains the
10268 * first character of the redirection operator.
10269 */
10270
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010271 parseredir:{
10272 char fd = *out;
10273 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000010274
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010275 np = (union node *) stalloc(sizeof(struct nfile));
10276 if (c == '>') {
10277 np->nfile.fd = 1;
10278 c = pgetc();
10279 if (c == '>')
10280 np->type = NAPPEND;
10281 else if (c == '&')
10282 np->type = NTOFD;
10283 else if (c == '|')
10284 np->type = NTOOV;
10285 else {
10286 np->type = NTO;
Eric Andersencb57d552001-06-28 07:25:16 +000010287 pungetc();
10288 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010289 } else { /* c == '<' */
10290 np->nfile.fd = 0;
10291 switch (c = pgetc()) {
10292 case '<':
10293 if (sizeof(struct nfile) != sizeof(struct nhere)) {
10294 np = (union node *) stalloc(sizeof(struct nhere));
10295 np->nfile.fd = 0;
10296 }
10297 np->type = NHERE;
10298 heredoc = (struct heredoc *) stalloc(sizeof(struct heredoc));
10299 heredoc->here = np;
10300 if ((c = pgetc()) == '-') {
10301 heredoc->striptabs = 1;
10302 } else {
10303 heredoc->striptabs = 0;
10304 pungetc();
10305 }
10306 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010307
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010308 case '&':
10309 np->type = NFROMFD;
10310 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010311
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010312 case '>':
10313 np->type = NFROMTO;
10314 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010315
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010316 default:
10317 np->type = NFROM;
10318 pungetc();
10319 break;
10320 }
Eric Andersencb57d552001-06-28 07:25:16 +000010321 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010322 if (fd != '\0')
10323 np->nfile.fd = digit_val(fd);
10324 redirnode = np;
10325 goto parseredir_return;
Eric Andersencb57d552001-06-28 07:25:16 +000010326 }
Eric Andersencb57d552001-06-28 07:25:16 +000010327
10328
10329/*
10330 * Parse a substitution. At this point, we have read the dollar sign
10331 * and nothing else.
10332 */
10333
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010334 parsesub:{
10335 int subtype;
10336 int typeloc;
10337 int flags;
10338 char *p;
10339 static const char types[] = "}-+?=";
Eric Andersencb57d552001-06-28 07:25:16 +000010340
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010341 c = pgetc();
10342 if (c <= PEOA ||
10343 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10344 ) {
10345 USTPUTC('$', out);
Eric Andersencb57d552001-06-28 07:25:16 +000010346 pungetc();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010347 } else if (c == '(') { /* $(command) or $((arith)) */
10348 if (pgetc() == '(') {
10349 PARSEARITH();
10350 } else {
10351 pungetc();
10352 PARSEBACKQNEW();
Eric Andersencb57d552001-06-28 07:25:16 +000010353 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010354 } else {
10355 USTPUTC(CTLVAR, out);
10356 typeloc = out - stackblock();
10357 USTPUTC(VSNORMAL, out);
10358 subtype = VSNORMAL;
10359 if (c == '{') {
Eric Andersencb57d552001-06-28 07:25:16 +000010360 c = pgetc();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010361 if (c == '#') {
10362 if ((c = pgetc()) == '}')
10363 c = '#';
10364 else
10365 subtype = VSLENGTH;
10366 } else
10367 subtype = 0;
10368 }
10369 if (c > PEOA && is_name(c)) {
10370 do {
10371 STPUTC(c, out);
10372 c = pgetc();
10373 } while (c > PEOA && is_in_name(c));
10374 } else if (is_digit(c)) {
10375 do {
10376 USTPUTC(c, out);
10377 c = pgetc();
10378 } while (is_digit(c));
10379 } else if (is_special(c)) {
Eric Andersencb57d552001-06-28 07:25:16 +000010380 USTPUTC(c, out);
10381 c = pgetc();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010382 } else
10383 badsub:synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010384
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010385 STPUTC('=', out);
10386 flags = 0;
10387 if (subtype == 0) {
10388 switch (c) {
10389 case ':':
10390 flags = VSNUL;
10391 c = pgetc();
10392 /*FALLTHROUGH*/ default:
10393 p = strchr(types, c);
10394 if (p == NULL)
10395 goto badsub;
10396 subtype = p - types + VSNORMAL;
10397 break;
10398 case '%':
10399 case '#':
Eric Andersencb57d552001-06-28 07:25:16 +000010400 {
10401 int cc = c;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010402
10403 subtype = c == '#' ? VSTRIMLEFT : VSTRIMRIGHT;
Eric Andersencb57d552001-06-28 07:25:16 +000010404 c = pgetc();
10405 if (c == cc)
10406 subtype++;
10407 else
10408 pungetc();
10409 break;
10410 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010411 }
10412 } else {
10413 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010414 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010415 if (dblquote || arinest)
10416 flags |= VSQUOTE;
10417 *(stackblock() + typeloc) = subtype | flags;
10418 if (subtype != VSNORMAL) {
10419 varnest++;
10420 if (dblquote) {
10421 dqvarnest++;
10422 }
Eric Andersencb57d552001-06-28 07:25:16 +000010423 }
10424 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010425 goto parsesub_return;
Eric Andersencb57d552001-06-28 07:25:16 +000010426 }
Eric Andersencb57d552001-06-28 07:25:16 +000010427
10428
10429/*
10430 * Called to parse command substitutions. Newstyle is set if the command
10431 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10432 * list of commands (passed by reference), and savelen is the number of
10433 * characters on the top of the stack which must be preserved.
10434 */
10435
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010436 parsebackq:{
10437 struct nodelist **nlpp;
10438 int savepbq;
10439 union node *n;
10440 char *volatile str;
10441 struct jmploc jmploc;
10442 struct jmploc *volatile savehandler;
10443 int savelen;
10444 int saveprompt;
10445
Eric Andersencb57d552001-06-28 07:25:16 +000010446#ifdef __GNUC__
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010447 (void) &saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010448#endif
10449
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010450 savepbq = parsebackquote;
10451 if (setjmp(jmploc.loc)) {
10452 free(str);
10453 parsebackquote = 0;
10454 handler = savehandler;
10455 longjmp(handler->loc, 1);
10456 }
10457 INTOFF;
10458 str = NULL;
10459 savelen = out - stackblock();
10460 if (savelen > 0) {
10461 str = xmalloc(savelen);
10462 memcpy(str, stackblock(), savelen);
10463 }
10464 savehandler = handler;
10465 handler = &jmploc;
10466 INTON;
10467 if (oldstyle) {
10468 /* We must read until the closing backquote, giving special
10469 treatment to some slashes, and then push the string and
10470 reread it as input, interpreting it normally. */
10471 char *pout;
10472 int pc;
10473 int psavelen;
10474 char *pstr;
Eric Andersencb57d552001-06-28 07:25:16 +000010475
10476
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010477 STARTSTACKSTR(pout);
10478 for (;;) {
10479 if (needprompt) {
10480 setprompt(2);
10481 needprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010482 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010483 switch (pc = pgetc()) {
10484 case '`':
10485 goto done;
10486
10487 case '\\':
10488 if ((pc = pgetc()) == '\n') {
10489 plinno++;
10490 if (doprompt)
10491 setprompt(2);
10492 else
10493 setprompt(0);
10494 /*
10495 * If eating a newline, avoid putting
10496 * the newline into the new character
10497 * stream (via the STPUTC after the
10498 * switch).
10499 */
10500 continue;
10501 }
10502 if (pc != '\\' && pc != '`' && pc != '$'
10503 && (!dblquote || pc != '"'))
10504 STPUTC('\\', pout);
10505 if (pc > PEOA) {
10506 break;
10507 }
10508 /* fall through */
10509
10510 case PEOF:
10511#ifdef CONFIG_ASH_ALIAS
10512 case PEOA:
10513#endif
10514 startlinno = plinno;
10515 synerror("EOF in backquote substitution");
10516
10517 case '\n':
10518 plinno++;
10519 needprompt = doprompt;
10520 break;
10521
10522 default:
Eric Andersencb57d552001-06-28 07:25:16 +000010523 break;
10524 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010525 STPUTC(pc, pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010526 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010527 done:
10528 STPUTC('\0', pout);
10529 psavelen = pout - stackblock();
10530 if (psavelen > 0) {
10531 pstr = grabstackstr(pout);
10532 setinputstring(pstr);
10533 }
Eric Andersen2870d962001-07-02 17:27:21 +000010534 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010535 nlpp = &bqlist;
10536 while (*nlpp)
10537 nlpp = &(*nlpp)->next;
10538 *nlpp = (struct nodelist *) stalloc(sizeof(struct nodelist));
10539 (*nlpp)->next = NULL;
10540 parsebackquote = oldstyle;
10541
10542 if (oldstyle) {
10543 saveprompt = doprompt;
10544 doprompt = 0;
Eric Andersen2870d962001-07-02 17:27:21 +000010545 }
Eric Andersencb57d552001-06-28 07:25:16 +000010546
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010547 n = list(0);
Eric Andersencb57d552001-06-28 07:25:16 +000010548
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010549 if (oldstyle)
10550 doprompt = saveprompt;
10551 else {
10552 if (readtoken() != TRP)
10553 synexpect(TRP);
10554 }
Eric Andersencb57d552001-06-28 07:25:16 +000010555
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010556 (*nlpp)->n = n;
10557 if (oldstyle) {
10558 /*
10559 * Start reading from old file again, ignoring any pushed back
10560 * tokens left from the backquote parsing
10561 */
10562 popfile();
10563 tokpushback = 0;
10564 }
10565 while (stackblocksize() <= savelen)
10566 growstackblock();
10567 STARTSTACKSTR(out);
10568 if (str) {
10569 memcpy(out, str, savelen);
10570 STADJUST(savelen, out);
10571 INTOFF;
10572 free(str);
10573 str = NULL;
10574 INTON;
10575 }
10576 parsebackquote = savepbq;
10577 handler = savehandler;
10578 if (arinest || dblquote)
10579 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10580 else
10581 USTPUTC(CTLBACKQ, out);
10582 if (oldstyle)
10583 goto parsebackq_oldreturn;
10584 else
10585 goto parsebackq_newreturn;
Eric Andersencb57d552001-06-28 07:25:16 +000010586 }
10587
Eric Andersencb57d552001-06-28 07:25:16 +000010588/*
10589 * Parse an arithmetic expansion (indicate start of one and set state)
10590 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010591 parsearith:{
Eric Andersencb57d552001-06-28 07:25:16 +000010592
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010593 if (++arinest == 1) {
10594 prevsyntax = syntax;
10595 syntax = ARISYNTAX;
10596 USTPUTC(CTLARI, out);
10597 if (dblquote)
10598 USTPUTC('"', out);
10599 else
10600 USTPUTC(' ', out);
10601 } else {
10602 /*
10603 * we collapse embedded arithmetic expansion to
10604 * parenthesis, which should be equivalent
10605 */
10606 USTPUTC('(', out);
10607 }
10608 goto parsearith_return;
Eric Andersencb57d552001-06-28 07:25:16 +000010609 }
Eric Andersencb57d552001-06-28 07:25:16 +000010610
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010611} /* end of readtoken */
Eric Andersencb57d552001-06-28 07:25:16 +000010612
10613
Eric Andersencb57d552001-06-28 07:25:16 +000010614/*
10615 * Returns true if the text contains nothing to expand (no dollar signs
10616 * or backquotes).
10617 */
10618
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010619static int noexpand(char *text)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010620{
Eric Andersencb57d552001-06-28 07:25:16 +000010621 char *p;
10622 char c;
10623
10624 p = text;
10625 while ((c = *p++) != '\0') {
10626 if (c == CTLQUOTEMARK)
10627 continue;
10628 if (c == CTLESC)
10629 p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010630 else if (SIT(c, BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010631 return 0;
10632 }
10633 return 1;
10634}
10635
10636
10637/*
10638 * Return true if the argument is a legal variable name (a letter or
10639 * underscore followed by zero or more letters, underscores, and digits).
10640 */
10641
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010642static int goodname(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +000010643{
10644 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000010645
10646 p = name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010647 if (!is_name(*p))
Eric Andersencb57d552001-06-28 07:25:16 +000010648 return 0;
10649 while (*++p) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010650 if (!is_in_name(*p))
Eric Andersencb57d552001-06-28 07:25:16 +000010651 return 0;
10652 }
10653 return 1;
10654}
10655
10656
10657/*
10658 * Called when an unexpected token is read during the parse. The argument
10659 * is the token that is expected, or -1 if more than one type of token can
10660 * occur at this point.
10661 */
10662
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010663static void synexpect(int token)
Eric Andersencb57d552001-06-28 07:25:16 +000010664{
10665 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010666 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000010667
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010668 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10669 if (token >= 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010670 sprintf(msg + l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000010671 synerror(msg);
10672 /* NOTREACHED */
10673}
10674
10675
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010676static void synerror(const char *msg)
Eric Andersen2870d962001-07-02 17:27:21 +000010677{
Eric Andersencb57d552001-06-28 07:25:16 +000010678 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +000010679 out2fmt("%s: %d: ", commandname, startlinno);
10680 out2fmt("Syntax error: %s\n", msg);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010681 error((char *) NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000010682 /* NOTREACHED */
10683}
10684
Eric Andersencb57d552001-06-28 07:25:16 +000010685
10686/*
10687 * called by editline -- any expansions to the prompt
10688 * should be added here.
10689 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010690static void setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000010691{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010692 char *prompt;
10693
10694 switch (whichprompt) {
Eric Andersen62483552001-07-10 06:09:16 +000010695 case 1:
10696 prompt = ps1val();
10697 break;
10698 case 2:
10699 prompt = ps2val();
10700 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010701 default: /* 0 */
Eric Andersen62483552001-07-10 06:09:16 +000010702 prompt = "";
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010703 }
10704 putprompt(prompt);
Eric Andersencb57d552001-06-28 07:25:16 +000010705}
10706
Eric Andersencb57d552001-06-28 07:25:16 +000010707
Eric Andersencb57d552001-06-28 07:25:16 +000010708/*
10709 * Code for dealing with input/output redirection.
10710 */
10711
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010712#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000010713#ifndef PIPE_BUF
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010714# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000010715#else
10716# define PIPESIZE PIPE_BUF
10717#endif
10718
10719
Eric Andersen62483552001-07-10 06:09:16 +000010720/*
10721 * Open a file in noclobber mode.
10722 * The code was copied from bash.
10723 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010724static inline int noclobberopen(const char *fname)
Eric Andersen62483552001-07-10 06:09:16 +000010725{
10726 int r, fd;
10727 struct stat finfo, finfo2;
10728
10729 /*
10730 * If the file exists and is a regular file, return an error
10731 * immediately.
10732 */
10733 r = stat(fname, &finfo);
10734 if (r == 0 && S_ISREG(finfo.st_mode)) {
10735 errno = EEXIST;
10736 return -1;
10737 }
10738
10739 /*
10740 * If the file was not present (r != 0), make sure we open it
10741 * exclusively so that if it is created before we open it, our open
10742 * will fail. Make sure that we do not truncate an existing file.
10743 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10744 * file was not a regular file, we leave O_EXCL off.
10745 */
10746 if (r != 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010747 return open(fname, O_WRONLY | O_CREAT | O_EXCL, 0666);
10748 fd = open(fname, O_WRONLY | O_CREAT, 0666);
Eric Andersen62483552001-07-10 06:09:16 +000010749
10750 /* If the open failed, return the file descriptor right away. */
10751 if (fd < 0)
10752 return fd;
10753
10754 /*
10755 * OK, the open succeeded, but the file may have been changed from a
10756 * non-regular file to a regular file between the stat and the open.
10757 * We are assuming that the O_EXCL open handles the case where FILENAME
10758 * did not exist and is symlinked to an existing file between the stat
10759 * and open.
10760 */
10761
10762 /*
10763 * If we can open it and fstat the file descriptor, and neither check
10764 * revealed that it was a regular file, and the file has not been
10765 * replaced, return the file descriptor.
10766 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010767 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10768 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
Eric Andersen62483552001-07-10 06:09:16 +000010769 return fd;
10770
10771 /* The file has been replaced. badness. */
10772 close(fd);
10773 errno = EEXIST;
10774 return -1;
10775}
Eric Andersencb57d552001-06-28 07:25:16 +000010776
10777/*
Eric Andersen62483552001-07-10 06:09:16 +000010778 * Handle here documents. Normally we fork off a process to write the
10779 * data to a pipe. If the document is short, we can stuff the data in
10780 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000010781 */
10782
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010783static inline int openhere(const union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010784{
10785 int pip[2];
10786 int len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010787
Eric Andersen62483552001-07-10 06:09:16 +000010788 if (pipe(pip) < 0)
10789 error("Pipe call failed");
10790 if (redir->type == NHERE) {
10791 len = strlen(redir->nhere.doc->narg.text);
10792 if (len <= PIPESIZE) {
10793 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10794 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010795 }
Eric Andersencb57d552001-06-28 07:25:16 +000010796 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010797 if (forkshell((struct job *) NULL, (union node *) NULL, FORK_NOJOB) == 0) {
Eric Andersen62483552001-07-10 06:09:16 +000010798 close(pip[0]);
10799 signal(SIGINT, SIG_IGN);
10800 signal(SIGQUIT, SIG_IGN);
10801 signal(SIGHUP, SIG_IGN);
10802#ifdef SIGTSTP
10803 signal(SIGTSTP, SIG_IGN);
10804#endif
10805 signal(SIGPIPE, SIG_DFL);
10806 if (redir->type == NHERE)
10807 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10808 else
10809 expandhere(redir->nhere.doc, pip[1]);
10810 _exit(0);
10811 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010812 out:
Eric Andersen62483552001-07-10 06:09:16 +000010813 close(pip[1]);
10814 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000010815}
10816
10817
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010818static inline int openredirect(const union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010819{
Eric Andersencb57d552001-06-28 07:25:16 +000010820 char *fname;
10821 int f;
10822
10823 switch (redir->nfile.type) {
10824 case NFROM:
10825 fname = redir->nfile.expfname;
10826 if ((f = open(fname, O_RDONLY)) < 0)
10827 goto eopen;
10828 break;
10829 case NFROMTO:
10830 fname = redir->nfile.expfname;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010831 if ((f = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010832 goto ecreate;
10833 break;
10834 case NTO:
10835 /* Take care of noclobber mode. */
10836 if (Cflag) {
10837 fname = redir->nfile.expfname;
10838 if ((f = noclobberopen(fname)) < 0)
10839 goto ecreate;
10840 break;
10841 }
10842 case NTOOV:
10843 fname = redir->nfile.expfname;
10844#ifdef O_CREAT
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010845 if ((f = open(fname, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010846 goto ecreate;
10847#else
10848 if ((f = creat(fname, 0666)) < 0)
10849 goto ecreate;
10850#endif
10851 break;
10852 case NAPPEND:
10853 fname = redir->nfile.expfname;
10854#ifdef O_APPEND
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010855 if ((f = open(fname, O_WRONLY | O_CREAT | O_APPEND, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010856 goto ecreate;
10857#else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010858 if ((f = open(fname, O_WRONLY)) < 0 && (f = creat(fname, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010859 goto ecreate;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010860 lseek(f, (off_t) 0, 2);
Eric Andersencb57d552001-06-28 07:25:16 +000010861#endif
10862 break;
10863 default:
10864#ifdef DEBUG
10865 abort();
10866#endif
10867 /* Fall through to eliminate warning. */
10868 case NTOFD:
10869 case NFROMFD:
10870 f = -1;
10871 break;
10872 case NHERE:
10873 case NXHERE:
10874 f = openhere(redir);
10875 break;
10876 }
10877
10878 return f;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010879 ecreate:
Eric Andersencb57d552001-06-28 07:25:16 +000010880 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010881 eopen:
Eric Andersencb57d552001-06-28 07:25:16 +000010882 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
10883}
10884
10885
Eric Andersen62483552001-07-10 06:09:16 +000010886/*
10887 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
10888 * old file descriptors are stashed away so that the redirection can be
10889 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
10890 * standard output, and the standard error if it becomes a duplicate of
10891 * stdout.
10892 */
10893
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010894static void redirect(union node *redir, int flags)
Eric Andersen62483552001-07-10 06:09:16 +000010895{
10896 union node *n;
10897 struct redirtab *sv = NULL;
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010898 int i;
Eric Andersen62483552001-07-10 06:09:16 +000010899 int fd;
10900 int newfd;
10901 int try;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010902 int fd1dup = flags & REDIR_BACKQ;; /* stdout `cmd` redir to pipe */
Eric Andersen62483552001-07-10 06:09:16 +000010903
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010904 TRACE(("redirect(%s) called\n",
10905 flags & REDIR_PUSH ? "REDIR_PUSH" : "NO_REDIR_PUSH"));
Eric Andersen62483552001-07-10 06:09:16 +000010906 if (flags & REDIR_PUSH) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010907 sv = xmalloc(sizeof(struct redirtab));
10908 for (i = 0; i < 10; i++)
Eric Andersen62483552001-07-10 06:09:16 +000010909 sv->renamed[i] = EMPTY;
10910 sv->next = redirlist;
10911 redirlist = sv;
10912 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010913 for (n = redir; n; n = n->nfile.next) {
Eric Andersen62483552001-07-10 06:09:16 +000010914 fd = n->nfile.fd;
10915 try = 0;
10916 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010917 n->ndup.dupfd == fd)
10918 continue; /* redirect from/to same file descriptor */
Eric Andersen62483552001-07-10 06:09:16 +000010919
10920 INTOFF;
10921 newfd = openredirect(n);
10922 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
Eric Andersen09da6272002-10-22 22:15:33 +000010923 i = fd;
Eric Andersen62483552001-07-10 06:09:16 +000010924 if (newfd == fd) {
10925 try++;
10926 } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
10927 switch (errno) {
10928 case EBADF:
10929 if (!try) {
10930 dupredirect(n, newfd, fd1dup);
10931 try++;
10932 break;
10933 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010934 /* FALLTHROUGH */
Eric Andersen62483552001-07-10 06:09:16 +000010935 default:
10936 if (newfd >= 0) {
10937 close(newfd);
10938 }
10939 INTON;
10940 error("%d: %m", fd);
10941 /* NOTREACHED */
10942 }
10943 }
10944 if (!try) {
10945 close(fd);
10946 if (flags & REDIR_PUSH) {
10947 sv->renamed[fd] = i;
10948 }
10949 }
10950 } else if (fd != newfd) {
10951 close(fd);
10952 }
10953 if (fd == 0)
10954 fd0_redirected++;
10955 if (!try)
10956 dupredirect(n, newfd, fd1dup);
10957 INTON;
10958 }
10959}
10960
10961
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010962static void dupredirect(const union node *redir, int f, int fd1dup)
Eric Andersen2870d962001-07-02 17:27:21 +000010963{
Eric Andersencb57d552001-06-28 07:25:16 +000010964 int fd = redir->nfile.fd;
10965
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010966 if (fd == 1)
Eric Andersen62483552001-07-10 06:09:16 +000010967 fd1dup = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010968 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010969 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
10970 if (redir->ndup.dupfd != 1 || fd1dup != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000010971 dup_as_newfd(redir->ndup.dupfd, fd);
10972 }
10973 return;
10974 }
10975
10976 if (f != fd) {
10977 dup_as_newfd(f, fd);
10978 close(f);
10979 }
10980 return;
10981}
10982
10983
Eric Andersencb57d552001-06-28 07:25:16 +000010984
Eric Andersencb57d552001-06-28 07:25:16 +000010985/*
10986 * Undo the effects of the last redirection.
10987 */
10988
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010989static void popredir(void)
Eric Andersen2870d962001-07-02 17:27:21 +000010990{
Eric Andersencb57d552001-06-28 07:25:16 +000010991 struct redirtab *rp = redirlist;
10992 int i;
10993
10994 INTOFF;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010995 for (i = 0; i < 10; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000010996 if (rp->renamed[i] != EMPTY) {
Eric Andersen2870d962001-07-02 17:27:21 +000010997 if (i == 0)
10998 fd0_redirected--;
Eric Andersencb57d552001-06-28 07:25:16 +000010999 close(i);
11000 if (rp->renamed[i] >= 0) {
11001 dup_as_newfd(rp->renamed[i], i);
11002 close(rp->renamed[i]);
11003 }
Eric Andersencb57d552001-06-28 07:25:16 +000011004 }
11005 }
11006 redirlist = rp->next;
Aaron Lehmann49c024a2002-08-02 06:39:47 +000011007 free(rp);
Eric Andersencb57d552001-06-28 07:25:16 +000011008 INTON;
11009}
11010
11011/*
Eric Andersencb57d552001-06-28 07:25:16 +000011012 * Discard all saved file descriptors.
11013 */
11014
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011015static void clearredir(void)
11016{
Eric Andersencb57d552001-06-28 07:25:16 +000011017 struct redirtab *rp;
11018 int i;
11019
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011020 for (rp = redirlist; rp; rp = rp->next) {
11021 for (i = 0; i < 10; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011022 if (rp->renamed[i] >= 0) {
11023 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011024 }
11025 rp->renamed[i] = EMPTY;
11026 }
11027 }
Eric Andersencb57d552001-06-28 07:25:16 +000011028}
11029
11030
Eric Andersencb57d552001-06-28 07:25:16 +000011031/*
11032 * Copy a file descriptor to be >= to. Returns -1
11033 * if the source file descriptor is closed, EMPTY if there are no unused
11034 * file descriptors left.
11035 */
11036
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011037static int dup_as_newfd(int from, int to)
Eric Andersencb57d552001-06-28 07:25:16 +000011038{
11039 int newfd;
11040
11041 newfd = fcntl(from, F_DUPFD, to);
11042 if (newfd < 0) {
11043 if (errno == EMFILE)
11044 return EMPTY;
11045 else
Eric Andersen2870d962001-07-02 17:27:21 +000011046 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011047 }
11048 return newfd;
11049}
11050
Eric Andersencb57d552001-06-28 07:25:16 +000011051#ifdef DEBUG
Eric Andersenec074692001-10-31 11:05:49 +000011052/*
11053 * Debugging stuff.
11054 */
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011055
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011056static void shtree(union node *, int, char *, FILE *);
11057static void shcmd(union node *, FILE *);
11058static void sharg(union node *, FILE *);
11059static void indent(int, char *, FILE *);
11060static void trstring(char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011061
11062
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011063#if 0
11064static void showtree(node * n)
Eric Andersencb57d552001-06-28 07:25:16 +000011065{
11066 trputs("showtree called\n");
11067 shtree(n, 1, NULL, stdout);
11068}
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011069#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011070
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011071static void shtree(union node *n, int ind, char *pfx, FILE * fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011072{
11073 struct nodelist *lp;
11074 const char *s;
11075
11076 if (n == NULL)
11077 return;
11078
11079 indent(ind, pfx, fp);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011080 switch (n->type) {
Eric Andersencb57d552001-06-28 07:25:16 +000011081 case NSEMI:
11082 s = "; ";
11083 goto binop;
11084 case NAND:
11085 s = " && ";
11086 goto binop;
11087 case NOR:
11088 s = " || ";
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011089 binop:
Eric Andersencb57d552001-06-28 07:25:16 +000011090 shtree(n->nbinary.ch1, ind, NULL, fp);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011091 /* if (ind < 0) */
11092 fputs(s, fp);
Eric Andersencb57d552001-06-28 07:25:16 +000011093 shtree(n->nbinary.ch2, ind, NULL, fp);
11094 break;
11095 case NCMD:
11096 shcmd(n, fp);
11097 if (ind >= 0)
11098 putc('\n', fp);
11099 break;
11100 case NPIPE:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011101 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000011102 shcmd(lp->n, fp);
11103 if (lp->next)
11104 fputs(" | ", fp);
11105 }
11106 if (n->npipe.backgnd)
11107 fputs(" &", fp);
11108 if (ind >= 0)
11109 putc('\n', fp);
11110 break;
11111 default:
11112 fprintf(fp, "<node type %d>", n->type);
11113 if (ind >= 0)
11114 putc('\n', fp);
11115 break;
11116 }
11117}
11118
11119
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011120static void shcmd(union node *cmd, FILE * fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011121{
11122 union node *np;
11123 int first;
11124 const char *s;
11125 int dftfd;
11126
11127 first = 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011128 for (np = cmd->ncmd.args; np; np = np->narg.next) {
11129 if (!first)
Eric Andersencb57d552001-06-28 07:25:16 +000011130 putchar(' ');
11131 sharg(np, fp);
11132 first = 0;
11133 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011134 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
11135 if (!first)
Eric Andersencb57d552001-06-28 07:25:16 +000011136 putchar(' ');
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011137#if 1
11138 s = "*error*";
11139 dftfd = 0;
11140 if ((np->nfile.type <= NFROMFD) && (np->nfile.type >= NTO)) {
11141 s = redir_strings[np->nfile.type - NTO];
11142 if (*s == '>') {
11143 dftfd = 1;
11144 }
11145 }
11146#else
Eric Andersencb57d552001-06-28 07:25:16 +000011147 switch (np->nfile.type) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011148 case NTO:
11149 s = ">";
11150 dftfd = 1;
11151 break;
11152 case NAPPEND:
11153 s = ">>";
11154 dftfd = 1;
11155 break;
11156 case NTOFD:
11157 s = ">&";
11158 dftfd = 1;
11159 break;
11160 case NTOOV:
11161 s = ">|";
11162 dftfd = 1;
11163 break;
11164 case NFROM:
11165 s = "<";
11166 dftfd = 0;
11167 break;
11168 case NFROMFD:
11169 s = "<&";
11170 dftfd = 0;
11171 break;
11172 case NFROMTO:
11173 s = "<>";
11174 dftfd = 0;
11175 break;
11176 default:
11177 s = "*error*";
11178 dftfd = 0;
11179 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011180 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011181#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011182 if (np->nfile.fd != dftfd)
11183 fprintf(fp, "%d", np->nfile.fd);
11184 fputs(s, fp);
11185 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11186 fprintf(fp, "%d", np->ndup.dupfd);
11187 } else {
11188 sharg(np->nfile.fname, fp);
11189 }
11190 first = 0;
11191 }
11192}
11193
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011194
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011195static void sharg(union node *arg, FILE * fp)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011196{
Eric Andersencb57d552001-06-28 07:25:16 +000011197 char *p;
11198 struct nodelist *bqlist;
11199 int subtype;
11200
11201 if (arg->type != NARG) {
11202 printf("<node type %d>\n", arg->type);
11203 fflush(stdout);
11204 abort();
11205 }
11206 bqlist = arg->narg.backquote;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011207 for (p = arg->narg.text; *p; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011208 switch (*p) {
11209 case CTLESC:
11210 putc(*++p, fp);
11211 break;
11212 case CTLVAR:
11213 putc('$', fp);
11214 putc('{', fp);
11215 subtype = *++p;
11216 if (subtype == VSLENGTH)
11217 putc('#', fp);
11218
11219 while (*p != '=')
11220 putc(*p++, fp);
11221
11222 if (subtype & VSNUL)
11223 putc(':', fp);
11224
11225 switch (subtype & VSTYPE) {
11226 case VSNORMAL:
11227 putc('}', fp);
11228 break;
11229 case VSMINUS:
11230 putc('-', fp);
11231 break;
11232 case VSPLUS:
11233 putc('+', fp);
11234 break;
11235 case VSQUESTION:
11236 putc('?', fp);
11237 break;
11238 case VSASSIGN:
11239 putc('=', fp);
11240 break;
11241 case VSTRIMLEFT:
11242 putc('#', fp);
11243 break;
11244 case VSTRIMLEFTMAX:
11245 putc('#', fp);
11246 putc('#', fp);
11247 break;
11248 case VSTRIMRIGHT:
11249 putc('%', fp);
11250 break;
11251 case VSTRIMRIGHTMAX:
11252 putc('%', fp);
11253 putc('%', fp);
11254 break;
11255 case VSLENGTH:
11256 break;
11257 default:
11258 printf("<subtype %d>", subtype);
11259 }
11260 break;
11261 case CTLENDVAR:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011262 putc('}', fp);
11263 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011264 case CTLBACKQ:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011265 case CTLBACKQ | CTLQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000011266 putc('$', fp);
11267 putc('(', fp);
11268 shtree(bqlist->n, -1, NULL, fp);
11269 putc(')', fp);
11270 break;
11271 default:
11272 putc(*p, fp);
11273 break;
11274 }
11275 }
11276}
11277
11278
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011279static void indent(int amount, char *pfx, FILE * fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011280{
11281 int i;
11282
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011283 for (i = 0; i < amount; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011284 if (pfx && i == amount - 1)
11285 fputs(pfx, fp);
11286 putc('\t', fp);
11287 }
11288}
Eric Andersencb57d552001-06-28 07:25:16 +000011289
Eric Andersencb57d552001-06-28 07:25:16 +000011290FILE *tracefile;
11291
11292#if DEBUG == 2
11293static int debug = 1;
11294#else
11295static int debug = 0;
11296#endif
11297
11298
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011299static void trputc(int c)
Eric Andersencb57d552001-06-28 07:25:16 +000011300{
11301 if (tracefile == NULL)
11302 return;
11303 putc(c, tracefile);
11304 if (c == '\n')
11305 fflush(tracefile);
11306}
11307
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011308static void trace(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +000011309{
11310 va_list va;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011311
Eric Andersencb57d552001-06-28 07:25:16 +000011312 va_start(va, fmt);
Eric Andersencb57d552001-06-28 07:25:16 +000011313 if (tracefile != NULL) {
11314 (void) vfprintf(tracefile, fmt, va);
11315 if (strchr(fmt, '\n'))
11316 (void) fflush(tracefile);
11317 }
11318 va_end(va);
11319}
11320
11321
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011322static void trputs(const char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011323{
11324 if (tracefile == NULL)
11325 return;
11326 fputs(s, tracefile);
11327 if (strchr(s, '\n'))
11328 fflush(tracefile);
11329}
11330
11331
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011332static void trstring(char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011333{
11334 char *p;
11335 char c;
11336
11337 if (tracefile == NULL)
11338 return;
11339 putc('"', tracefile);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011340 for (p = s; *p; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011341 switch (*p) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011342 case '\n':
11343 c = 'n';
11344 goto backslash;
11345 case '\t':
11346 c = 't';
11347 goto backslash;
11348 case '\r':
11349 c = 'r';
11350 goto backslash;
11351 case '"':
11352 c = '"';
11353 goto backslash;
11354 case '\\':
11355 c = '\\';
11356 goto backslash;
11357 case CTLESC:
11358 c = 'e';
11359 goto backslash;
11360 case CTLVAR:
11361 c = 'v';
11362 goto backslash;
11363 case CTLVAR + CTLQUOTE:
11364 c = 'V';
11365 goto backslash;
11366 case CTLBACKQ:
11367 c = 'q';
11368 goto backslash;
11369 case CTLBACKQ + CTLQUOTE:
11370 c = 'Q';
11371 goto backslash;
11372 backslash:putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011373 putc(c, tracefile);
11374 break;
11375 default:
11376 if (*p >= ' ' && *p <= '~')
11377 putc(*p, tracefile);
11378 else {
11379 putc('\\', tracefile);
11380 putc(*p >> 6 & 03, tracefile);
11381 putc(*p >> 3 & 07, tracefile);
11382 putc(*p & 07, tracefile);
11383 }
11384 break;
11385 }
11386 }
11387 putc('"', tracefile);
11388}
11389
11390
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011391static void trargs(char **ap)
Eric Andersencb57d552001-06-28 07:25:16 +000011392{
11393 if (tracefile == NULL)
11394 return;
11395 while (*ap) {
11396 trstring(*ap++);
11397 if (*ap)
11398 putc(' ', tracefile);
11399 else
11400 putc('\n', tracefile);
11401 }
11402 fflush(tracefile);
11403}
11404
11405
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011406static void opentrace()
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011407{
Eric Andersencb57d552001-06-28 07:25:16 +000011408 char s[100];
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011409
Eric Andersencb57d552001-06-28 07:25:16 +000011410#ifdef O_APPEND
11411 int flags;
11412#endif
11413
11414 if (!debug)
11415 return;
11416#ifdef not_this_way
11417 {
11418 char *p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011419
Eric Andersencb57d552001-06-28 07:25:16 +000011420 if ((p = getenv("HOME")) == NULL) {
11421 if (geteuid() == 0)
11422 p = "/";
11423 else
11424 p = "/tmp";
11425 }
Eric Andersen2870d962001-07-02 17:27:21 +000011426 strcpy(s, p);
Eric Andersencb57d552001-06-28 07:25:16 +000011427 strcat(s, "/trace");
11428 }
11429#else
Eric Andersen2870d962001-07-02 17:27:21 +000011430 strcpy(s, "./trace");
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011431#endif /* not_this_way */
Manuel Novoa III cad53642003-03-19 09:13:01 +000011432 if ((tracefile = bb_wfopen(s, "a")) == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000011433 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011434#ifdef O_APPEND
11435 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11436 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11437#endif
11438 fputs("\nTracing started.\n", tracefile);
11439 fflush(tracefile);
11440}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011441#endif /* DEBUG */
Eric Andersencb57d552001-06-28 07:25:16 +000011442
11443
11444/*
Eric Andersencb57d552001-06-28 07:25:16 +000011445 * The trap builtin.
11446 */
11447
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011448static int trapcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011449{
11450 char *action;
11451 char **ap;
11452 int signo;
11453
11454 if (argc <= 1) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011455 for (signo = 0; signo < NSIG; signo++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011456 if (trap[signo] != NULL) {
11457 char *p;
Eric Andersen34506362001-08-02 05:02:46 +000011458 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011459
11460 p = single_quote(trap[signo]);
Eric Andersen34506362001-08-02 05:02:46 +000011461 sn = sys_siglist[signo];
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011462 if (sn == NULL)
Eric Andersen34506362001-08-02 05:02:46 +000011463 sn = u_signal_names(0, &signo, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011464 if (sn == NULL)
Eric Andersen34506362001-08-02 05:02:46 +000011465 sn = "???";
11466 printf("trap -- %s %s\n", p, sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011467 stunalloc(p);
11468 }
11469 }
11470 return 0;
11471 }
11472 ap = argv + 1;
11473 if (argc == 2)
11474 action = NULL;
11475 else
11476 action = *ap++;
11477 while (*ap) {
11478 if ((signo = decode_signal(*ap, 0)) < 0)
11479 error("%s: bad trap", *ap);
11480 INTOFF;
11481 if (action) {
11482 if (action[0] == '-' && action[1] == '\0')
11483 action = NULL;
11484 else
Manuel Novoa III cad53642003-03-19 09:13:01 +000011485 action = bb_xstrdup(action);
Eric Andersencb57d552001-06-28 07:25:16 +000011486 }
Aaron Lehmann49c024a2002-08-02 06:39:47 +000011487 free(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000011488 trap[signo] = action;
11489 if (signo != 0)
11490 setsignal(signo);
11491 INTON;
11492 ap++;
11493 }
11494 return 0;
11495}
11496
11497
Eric Andersencb57d552001-06-28 07:25:16 +000011498/*
11499 * Set the signal handler for the specified signal. The routine figures
11500 * out what it should be set to.
11501 */
11502
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011503static void setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011504{
11505 int action;
11506 char *t;
11507 struct sigaction act;
11508
11509 if ((t = trap[signo]) == NULL)
11510 action = S_DFL;
11511 else if (*t != '\0')
11512 action = S_CATCH;
11513 else
11514 action = S_IGN;
11515 if (rootshell && action == S_DFL) {
11516 switch (signo) {
11517 case SIGINT:
11518 if (iflag || minusc || sflag == 0)
11519 action = S_CATCH;
11520 break;
11521 case SIGQUIT:
11522#ifdef DEBUG
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011523 {
Eric Andersencb57d552001-06-28 07:25:16 +000011524
11525 if (debug)
11526 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011527 }
Eric Andersencb57d552001-06-28 07:25:16 +000011528#endif
11529 /* FALLTHROUGH */
11530 case SIGTERM:
11531 if (iflag)
11532 action = S_IGN;
11533 break;
Eric Andersend35c5df2002-01-09 15:37:36 +000011534#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +000011535 case SIGTSTP:
11536 case SIGTTOU:
11537 if (mflag)
11538 action = S_IGN;
11539 break;
11540#endif
11541 }
11542 }
11543
11544 t = &sigmode[signo - 1];
11545 if (*t == 0) {
11546 /*
11547 * current setting unknown
11548 */
11549 if (sigaction(signo, 0, &act) == -1) {
11550 /*
11551 * Pretend it worked; maybe we should give a warning
11552 * here, but other shells don't. We don't alter
11553 * sigmode, so that we retry every time.
11554 */
11555 return;
11556 }
11557 if (act.sa_handler == SIG_IGN) {
11558 if (mflag && (signo == SIGTSTP ||
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011559 signo == SIGTTIN || signo == SIGTTOU)) {
11560 *t = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000011561 } else
11562 *t = S_HARD_IGN;
11563 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011564 *t = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000011565 }
11566 }
11567 if (*t == S_HARD_IGN || *t == action)
11568 return;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011569 act.sa_handler = ((action == S_CATCH) ? onsig
11570 : ((action == S_IGN) ? SIG_IGN : SIG_DFL));
Eric Andersencb57d552001-06-28 07:25:16 +000011571 *t = action;
11572 act.sa_flags = 0;
11573 sigemptyset(&act.sa_mask);
11574 sigaction(signo, &act, 0);
11575}
11576
11577/*
11578 * Ignore a signal.
11579 */
11580
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011581static void ignoresig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011582{
11583 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11584 signal(signo, SIG_IGN);
11585 }
11586 sigmode[signo - 1] = S_HARD_IGN;
11587}
11588
11589
Eric Andersencb57d552001-06-28 07:25:16 +000011590/*
11591 * Signal handler.
11592 */
11593
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011594static void onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011595{
11596 if (signo == SIGINT && trap[SIGINT] == NULL) {
11597 onint();
11598 return;
11599 }
11600 gotsig[signo - 1] = 1;
11601 pendingsigs++;
11602}
11603
11604
Eric Andersencb57d552001-06-28 07:25:16 +000011605/*
11606 * Called to execute a trap. Perhaps we should avoid entering new trap
11607 * handlers while we are executing a trap handler.
11608 */
11609
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011610static void dotrap(void)
Eric Andersen2870d962001-07-02 17:27:21 +000011611{
Eric Andersencb57d552001-06-28 07:25:16 +000011612 int i;
11613 int savestatus;
11614
11615 for (;;) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011616 for (i = 1;; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011617 if (gotsig[i - 1])
11618 break;
11619 if (i >= NSIG - 1)
11620 goto done;
11621 }
11622 gotsig[i - 1] = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011623 savestatus = exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +000011624 evalstring(trap[i], 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011625 exitstatus = savestatus;
Eric Andersencb57d552001-06-28 07:25:16 +000011626 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011627 done:
Eric Andersencb57d552001-06-28 07:25:16 +000011628 pendingsigs = 0;
11629}
11630
Eric Andersencb57d552001-06-28 07:25:16 +000011631/*
11632 * Called to exit the shell.
11633 */
11634
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011635static void exitshell(int status)
Eric Andersencb57d552001-06-28 07:25:16 +000011636{
11637 struct jmploc loc1, loc2;
11638 char *p;
11639
11640 TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
11641 if (setjmp(loc1.loc)) {
11642 goto l1;
11643 }
11644 if (setjmp(loc2.loc)) {
11645 goto l2;
11646 }
11647 handler = &loc1;
11648 if ((p = trap[0]) != NULL && *p != '\0') {
11649 trap[0] = NULL;
11650 evalstring(p, 0);
11651 }
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011652l1:
11653 handler = &loc2; /* probably unnecessary */
Eric Andersencb57d552001-06-28 07:25:16 +000011654 flushall();
Eric Andersend35c5df2002-01-09 15:37:36 +000011655#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +000011656 setjobctl(0);
11657#endif
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011658#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11659 if (iflag && rootshell) {
11660 const char *hp = lookupvar("HISTFILE");
11661
11662 if(hp != NULL )
11663 save_history ( hp );
11664 }
11665#endif
11666l2:
11667 _exit(status);
Eric Andersencb57d552001-06-28 07:25:16 +000011668 /* NOTREACHED */
11669}
11670
11671static int decode_signal(const char *string, int minsig)
11672{
11673 int signo;
Eric Andersen34506362001-08-02 05:02:46 +000011674 const char *name = u_signal_names(string, &signo, minsig);
Eric Andersencb57d552001-06-28 07:25:16 +000011675
Eric Andersen34506362001-08-02 05:02:46 +000011676 return name ? signo : -1;
Eric Andersencb57d552001-06-28 07:25:16 +000011677}
Eric Andersen34506362001-08-02 05:02:46 +000011678
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011679static struct var **hashvar(const char *);
11680static void showvars(const char *, int, int);
11681static struct var **findvar(struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011682
11683/*
11684 * Initialize the varable symbol tables and import the environment
11685 */
11686
Eric Andersencb57d552001-06-28 07:25:16 +000011687/*
11688 * This routine initializes the builtin variables. It is called when the
11689 * shell is initialized and again when a shell procedure is spawned.
11690 */
11691
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011692static void initvar()
11693{
Eric Andersencb57d552001-06-28 07:25:16 +000011694 const struct varinit *ip;
11695 struct var *vp;
11696 struct var **vpp;
11697
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011698 for (ip = varinit; (vp = ip->var) != NULL; ip++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011699 if ((vp->flags & VEXPORT) == 0) {
11700 vpp = hashvar(ip->text);
11701 vp->next = *vpp;
11702 *vpp = vp;
Manuel Novoa III cad53642003-03-19 09:13:01 +000011703 vp->text = bb_xstrdup(ip->text);
Eric Andersencb57d552001-06-28 07:25:16 +000011704 vp->flags = ip->flags;
11705 vp->func = ip->func;
11706 }
11707 }
Tim Riker497a8852002-04-13 05:37:10 +000011708#if !defined(CONFIG_FEATURE_COMMAND_EDITING) || !defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
Eric Andersencb57d552001-06-28 07:25:16 +000011709 /*
11710 * PS1 depends on uid
11711 */
11712 if ((vps1.flags & VEXPORT) == 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011713 vpp = hashvar("PS1=$ ");
Eric Andersencb57d552001-06-28 07:25:16 +000011714 vps1.next = *vpp;
11715 *vpp = &vps1;
Manuel Novoa III cad53642003-03-19 09:13:01 +000011716 vps1.text = bb_xstrdup(geteuid()? "PS1=$ " : "PS1=# ");
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011717 vps1.flags = VSTRFIXED | VTEXTFIXED;
Eric Andersencb57d552001-06-28 07:25:16 +000011718 }
Tim Riker497a8852002-04-13 05:37:10 +000011719#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011720}
11721
11722/*
11723 * Set the value of a variable. The flags argument is ored with the
11724 * flags of the variable. If val is NULL, the variable is unset.
11725 */
11726
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011727static void setvar(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011728{
11729 const char *p;
11730 int len;
11731 int namelen;
11732 char *nameeq;
11733 int isbad;
11734 int vallen = 0;
11735
11736 isbad = 0;
11737 p = name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011738 if (!is_name(*p))
Eric Andersencb57d552001-06-28 07:25:16 +000011739 isbad = 1;
11740 p++;
11741 for (;;) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011742 if (!is_in_name(*p)) {
Eric Andersencb57d552001-06-28 07:25:16 +000011743 if (*p == '\0' || *p == '=')
11744 break;
11745 isbad = 1;
11746 }
11747 p++;
11748 }
11749 namelen = p - name;
11750 if (isbad)
11751 error("%.*s: bad variable name", namelen, name);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011752 len = namelen + 2; /* 2 is space for '=' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +000011753 if (val == NULL) {
11754 flags |= VUNSET;
11755 } else {
11756 len += vallen = strlen(val);
11757 }
11758 INTOFF;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011759 nameeq = xmalloc(len);
Eric Andersencb57d552001-06-28 07:25:16 +000011760 memcpy(nameeq, name, namelen);
11761 nameeq[namelen] = '=';
11762 if (val) {
11763 memcpy(nameeq + namelen + 1, val, vallen + 1);
11764 } else {
11765 nameeq[namelen + 1] = '\0';
11766 }
11767 setvareq(nameeq, flags);
11768 INTON;
11769}
11770
11771
11772
11773/*
11774 * Same as setvar except that the variable and value are passed in
11775 * the first argument as name=value. Since the first argument will
11776 * be actually stored in the table, it should not be a string that
11777 * will go away.
11778 */
11779
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011780static void setvareq(char *s, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011781{
11782 struct var *vp, **vpp;
11783
11784 vpp = hashvar(s);
11785 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
11786 if ((vp = *findvar(vpp, s))) {
11787 if (vp->flags & VREADONLY) {
11788 size_t len = strchr(s, '=') - s;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011789
Eric Andersencb57d552001-06-28 07:25:16 +000011790 error("%.*s: is read only", len, s);
11791 }
11792 INTOFF;
11793
11794 if (vp->func && (flags & VNOFUNC) == 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011795 (*vp->func) (strchr(s, '=') + 1);
Eric Andersencb57d552001-06-28 07:25:16 +000011796
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011797 if ((vp->flags & (VTEXTFIXED | VSTACK)) == 0)
Aaron Lehmann49c024a2002-08-02 06:39:47 +000011798 free(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000011799
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011800 vp->flags &= ~(VTEXTFIXED | VSTACK | VUNSET);
Eric Andersencb57d552001-06-28 07:25:16 +000011801 vp->flags |= flags;
11802 vp->text = s;
11803
Eric Andersend35c5df2002-01-09 15:37:36 +000011804#ifdef CONFIG_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000011805 /*
11806 * We could roll this to a function, to handle it as
11807 * a regular variable function callback, but why bother?
11808 */
11809 if (iflag && (vp == &vmpath || (vp == &vmail && !mpathset())))
11810 chkmail(1);
Eric Andersenec074692001-10-31 11:05:49 +000011811#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011812 INTON;
11813 return;
11814 }
11815 /* not found */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011816 vp = xmalloc(sizeof(*vp));
Eric Andersencb57d552001-06-28 07:25:16 +000011817 vp->flags = flags;
11818 vp->text = s;
11819 vp->next = *vpp;
11820 vp->func = NULL;
11821 *vpp = vp;
11822}
11823
11824
11825
11826/*
11827 * Process a linked list of variable assignments.
11828 */
11829
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011830static void listsetvar(struct strlist *mylist)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011831{
Eric Andersencb57d552001-06-28 07:25:16 +000011832 struct strlist *lp;
11833
11834 INTOFF;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011835 for (lp = mylist; lp; lp = lp->next) {
Manuel Novoa III cad53642003-03-19 09:13:01 +000011836 setvareq(bb_xstrdup(lp->text), 0);
Eric Andersencb57d552001-06-28 07:25:16 +000011837 }
11838 INTON;
11839}
11840
11841
11842
11843/*
11844 * Find the value of a variable. Returns NULL if not set.
11845 */
11846
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011847static const char *lookupvar(const char *name)
Eric Andersenec074692001-10-31 11:05:49 +000011848{
Eric Andersencb57d552001-06-28 07:25:16 +000011849 struct var *v;
11850
11851 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
11852 return strchr(v->text, '=') + 1;
11853 }
11854 return NULL;
11855}
11856
11857
11858
11859/*
11860 * Search the environment of a builtin command.
11861 */
11862
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011863static const char *bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000011864{
Eric Andersen62483552001-07-10 06:09:16 +000011865 const struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000011866
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011867 for (sp = cmdenviron; sp; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000011868 if (varequal(sp->text, name))
11869 return strchr(sp->text, '=') + 1;
11870 }
11871 return lookupvar(name);
11872}
11873
11874
11875
11876/*
11877 * Generate a list of exported variables. This routine is used to construct
11878 * the third argument to execve when executing a program.
11879 */
11880
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011881static char **environment()
11882{
Eric Andersencb57d552001-06-28 07:25:16 +000011883 int nenv;
11884 struct var **vpp;
11885 struct var *vp;
11886 char **env;
11887 char **ep;
11888
11889 nenv = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011890 for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) {
11891 for (vp = *vpp; vp; vp = vp->next)
Eric Andersencb57d552001-06-28 07:25:16 +000011892 if (vp->flags & VEXPORT)
11893 nenv++;
11894 }
11895 ep = env = stalloc((nenv + 1) * sizeof *env);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011896 for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) {
11897 for (vp = *vpp; vp; vp = vp->next)
Eric Andersencb57d552001-06-28 07:25:16 +000011898 if (vp->flags & VEXPORT)
11899 *ep++ = vp->text;
11900 }
11901 *ep = NULL;
11902 return env;
11903}
11904
11905
11906/*
Eric Andersencb57d552001-06-28 07:25:16 +000011907 * Command to list all variables which are set. Currently this command
11908 * is invoked from the set command when the set command is called without
11909 * any variables.
11910 */
11911
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011912static int showvarscmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011913{
11914 showvars(nullstr, VUNSET, VUNSET);
11915 return 0;
11916}
11917
11918
11919
11920/*
11921 * The export and readonly commands.
11922 */
11923
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011924static int exportcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011925{
11926 struct var *vp;
11927 char *name;
11928 const char *p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011929 int flag = argv[0][0] == 'r' ? VREADONLY : VEXPORT;
Eric Andersencb57d552001-06-28 07:25:16 +000011930 int pflag;
11931
11932 listsetvar(cmdenviron);
11933 pflag = (nextopt("p") == 'p');
11934 if (argc > 1 && !pflag) {
11935 while ((name = *argptr++) != NULL) {
11936 if ((p = strchr(name, '=')) != NULL) {
11937 p++;
11938 } else {
11939 if ((vp = *findvar(hashvar(name), name))) {
11940 vp->flags |= flag;
11941 goto found;
11942 }
11943 }
11944 setvar(name, p, flag);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011945 found:;
Eric Andersencb57d552001-06-28 07:25:16 +000011946 }
11947 } else {
11948 showvars(argv[0], flag, 0);
11949 }
11950 return 0;
11951}
11952
Eric Andersen34506362001-08-02 05:02:46 +000011953
Eric Andersencb57d552001-06-28 07:25:16 +000011954/*
11955 * The "local" command.
11956 */
11957
Eric Andersen2870d962001-07-02 17:27:21 +000011958/* funcnest nonzero if we are currently evaluating a function */
11959
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011960static int localcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011961{
11962 char *name;
11963
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011964 if (!funcnest)
Eric Andersencb57d552001-06-28 07:25:16 +000011965 error("Not in a function");
11966 while ((name = *argptr++) != NULL) {
11967 mklocal(name);
11968 }
11969 return 0;
11970}
11971
11972
11973/*
11974 * Make a variable a local variable. When a variable is made local, it's
11975 * value and flags are saved in a localvar structure. The saved values
11976 * will be restored when the shell function returns. We handle the name
11977 * "-" as a special case.
11978 */
11979
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011980static void mklocal(char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011981{
Eric Andersencb57d552001-06-28 07:25:16 +000011982 struct localvar *lvp;
11983 struct var **vpp;
11984 struct var *vp;
11985
11986 INTOFF;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011987 lvp = xmalloc(sizeof(struct localvar));
Eric Andersencb57d552001-06-28 07:25:16 +000011988 if (name[0] == '-' && name[1] == '\0') {
11989 char *p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011990
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011991 p = xmalloc(sizeof optet_vals);
Eric Andersen2870d962001-07-02 17:27:21 +000011992 lvp->text = memcpy(p, optet_vals, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000011993 vp = NULL;
11994 } else {
11995 vpp = hashvar(name);
11996 vp = *findvar(vpp, name);
11997 if (vp == NULL) {
11998 if (strchr(name, '='))
Manuel Novoa III cad53642003-03-19 09:13:01 +000011999 setvareq(bb_xstrdup(name), VSTRFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +000012000 else
12001 setvar(name, NULL, VSTRFIXED);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012002 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012003 lvp->text = NULL;
12004 lvp->flags = VUNSET;
12005 } else {
12006 lvp->text = vp->text;
12007 lvp->flags = vp->flags;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012008 vp->flags |= VSTRFIXED | VTEXTFIXED;
Eric Andersencb57d552001-06-28 07:25:16 +000012009 if (strchr(name, '='))
Manuel Novoa III cad53642003-03-19 09:13:01 +000012010 setvareq(bb_xstrdup(name), 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012011 }
12012 }
12013 lvp->vp = vp;
12014 lvp->next = localvars;
12015 localvars = lvp;
12016 INTON;
12017}
12018
12019
12020/*
12021 * Called after a function returns.
12022 */
12023
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012024static void poplocalvars()
12025{
Eric Andersencb57d552001-06-28 07:25:16 +000012026 struct localvar *lvp;
12027 struct var *vp;
12028
12029 while ((lvp = localvars) != NULL) {
12030 localvars = lvp->next;
12031 vp = lvp->vp;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012032 if (vp == NULL) { /* $- saved */
Eric Andersen2870d962001-07-02 17:27:21 +000012033 memcpy(optet_vals, lvp->text, sizeof optet_vals);
Aaron Lehmann49c024a2002-08-02 06:39:47 +000012034 free(lvp->text);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012035 } else if ((lvp->flags & (VUNSET | VSTRFIXED)) == VUNSET) {
12036 (void) unsetvar(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012037 } else {
12038 if ((vp->flags & VTEXTFIXED) == 0)
Aaron Lehmann49c024a2002-08-02 06:39:47 +000012039 free(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012040 vp->flags = lvp->flags;
12041 vp->text = lvp->text;
12042 }
Aaron Lehmann49c024a2002-08-02 06:39:47 +000012043 free(lvp);
Eric Andersencb57d552001-06-28 07:25:16 +000012044 }
12045}
12046
12047
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012048static int setvarcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012049{
12050 if (argc <= 2)
12051 return unsetcmd(argc, argv);
12052 else if (argc == 3)
12053 setvar(argv[1], argv[2], 0);
12054 else
12055 error("List assignment not implemented");
12056 return 0;
12057}
12058
12059
12060/*
12061 * The unset builtin command. We unset the function before we unset the
12062 * variable to allow a function to be unset when there is a readonly variable
12063 * with the same name.
12064 */
12065
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012066static int unsetcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012067{
12068 char **ap;
12069 int i;
12070 int flg_func = 0;
12071 int flg_var = 0;
12072 int ret = 0;
12073
12074 while ((i = nextopt("vf")) != '\0') {
12075 if (i == 'f')
12076 flg_func = 1;
12077 else
12078 flg_var = 1;
12079 }
12080 if (flg_func == 0 && flg_var == 0)
12081 flg_var = 1;
12082
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012083 for (ap = argptr; *ap; ap++) {
Eric Andersencb57d552001-06-28 07:25:16 +000012084 if (flg_func)
12085 unsetfunc(*ap);
12086 if (flg_var)
12087 ret |= unsetvar(*ap);
12088 }
12089 return ret;
12090}
12091
12092
12093/*
12094 * Unset the specified variable.
12095 */
12096
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012097static int unsetvar(const char *s)
Eric Andersen62483552001-07-10 06:09:16 +000012098{
Eric Andersencb57d552001-06-28 07:25:16 +000012099 struct var **vpp;
12100 struct var *vp;
12101
12102 vpp = findvar(hashvar(s), s);
12103 vp = *vpp;
12104 if (vp) {
12105 if (vp->flags & VREADONLY)
12106 return (1);
12107 INTOFF;
12108 if (*(strchr(vp->text, '=') + 1) != '\0')
12109 setvar(s, nullstr, 0);
12110 vp->flags &= ~VEXPORT;
12111 vp->flags |= VUNSET;
12112 if ((vp->flags & VSTRFIXED) == 0) {
12113 if ((vp->flags & VTEXTFIXED) == 0)
Aaron Lehmann49c024a2002-08-02 06:39:47 +000012114 free(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012115 *vpp = vp->next;
Aaron Lehmann49c024a2002-08-02 06:39:47 +000012116 free(vp);
Eric Andersencb57d552001-06-28 07:25:16 +000012117 }
12118 INTON;
12119 return (0);
12120 }
12121
12122 return (0);
12123}
12124
12125
12126
12127/*
12128 * Find the appropriate entry in the hash table from the name.
12129 */
12130
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012131static struct var **hashvar(const char *p)
Eric Andersen62483552001-07-10 06:09:16 +000012132{
Eric Andersencb57d552001-06-28 07:25:16 +000012133 unsigned int hashval;
12134
12135 hashval = ((unsigned char) *p) << 4;
12136 while (*p && *p != '=')
12137 hashval += (unsigned char) *p++;
12138 return &vartab[hashval % VTABSIZE];
12139}
12140
12141
12142
12143/*
12144 * Returns true if the two strings specify the same varable. The first
12145 * variable name is terminated by '='; the second may be terminated by
12146 * either '=' or '\0'.
12147 */
12148
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012149static int varequal(const char *p, const char *q)
Eric Andersen62483552001-07-10 06:09:16 +000012150{
Eric Andersencb57d552001-06-28 07:25:16 +000012151 while (*p == *q++) {
12152 if (*p++ == '=')
12153 return 1;
12154 }
12155 if (*p == '=' && *(q - 1) == '\0')
12156 return 1;
12157 return 0;
12158}
12159
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012160static void showvars(const char *myprefix, int mask, int xor)
Eric Andersencb57d552001-06-28 07:25:16 +000012161{
12162 struct var **vpp;
12163 struct var *vp;
12164 const char *sep = myprefix == nullstr ? myprefix : spcstr;
12165
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012166 for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) {
12167 for (vp = *vpp; vp; vp = vp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000012168 if ((vp->flags & mask) ^ xor) {
12169 char *p;
12170 int len;
12171
12172 p = strchr(vp->text, '=') + 1;
12173 len = p - vp->text;
12174 p = single_quote(p);
12175
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012176 printf("%s%s%.*s%s\n", myprefix, sep, len, vp->text, p);
Eric Andersencb57d552001-06-28 07:25:16 +000012177 stunalloc(p);
12178 }
12179 }
12180 }
12181}
12182
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012183static struct var **findvar(struct var **vpp, const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012184{
12185 for (; *vpp; vpp = &(*vpp)->next) {
12186 if (varequal((*vpp)->text, name)) {
12187 break;
12188 }
12189 }
12190 return vpp;
12191}
12192
12193/*
12194 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
12195 * This file contains code for the times builtin.
Eric Andersencb57d552001-06-28 07:25:16 +000012196 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012197static int timescmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012198{
12199 struct tms buf;
12200 long int clk_tck = sysconf(_SC_CLK_TCK);
12201
12202 times(&buf);
12203 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012204 (int) (buf.tms_utime / clk_tck / 60),
12205 ((double) buf.tms_utime) / clk_tck,
12206 (int) (buf.tms_stime / clk_tck / 60),
12207 ((double) buf.tms_stime) / clk_tck,
12208 (int) (buf.tms_cutime / clk_tck / 60),
12209 ((double) buf.tms_cutime) / clk_tck,
12210 (int) (buf.tms_cstime / clk_tck / 60),
12211 ((double) buf.tms_cstime) / clk_tck);
Eric Andersencb57d552001-06-28 07:25:16 +000012212 return 0;
12213}
12214
Eric Andersend35c5df2002-01-09 15:37:36 +000012215#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012216/* The let builtin. */
12217int letcmd(int argc, char **argv)
Eric Andersen74bcd162001-07-30 21:41:37 +000012218{
Eric Andersen34506362001-08-02 05:02:46 +000012219 int errcode;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012220 long result = 0;
12221
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012222 if (argc == 2) {
12223 char *tmp, *expression, p[13];
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012224
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012225 expression = strchr(argv[1], '=');
12226 if (!expression) {
Eric Andersen34506362001-08-02 05:02:46 +000012227 /* Cannot use 'error()' here, or the return code
12228 * will be incorrect */
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012229 out2fmt("sh: let: syntax error: \"%s\"\n", argv[1]);
12230 return 0;
Eric Andersen74bcd162001-07-30 21:41:37 +000012231 }
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012232 *expression = '\0';
12233 tmp = ++expression;
Eric Andersen34506362001-08-02 05:02:46 +000012234 result = arith(tmp, &errcode);
12235 if (errcode < 0) {
12236 /* Cannot use 'error()' here, or the return code
12237 * will be incorrect */
12238 out2fmt("sh: let: ");
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012239 if (errcode == -2)
Eric Andersen34506362001-08-02 05:02:46 +000012240 out2fmt("divide by zero");
12241 else
12242 out2fmt("syntax error: \"%s=%s\"\n", argv[1], expression);
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012243 return 0;
12244 }
12245 snprintf(p, 12, "%ld", result);
Manuel Novoa III cad53642003-03-19 09:13:01 +000012246 setvar(argv[1], bb_xstrdup(p), 0);
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012247 } else if (argc >= 3)
12248 synerror("invalid operand");
12249 return !result;
Eric Andersen74bcd162001-07-30 21:41:37 +000012250}
12251#endif
12252
12253
12254
Eric Andersendf82f612001-06-28 07:46:40 +000012255/*-
12256 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000012257 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000012258 *
12259 * This code is derived from software contributed to Berkeley by
12260 * Kenneth Almquist.
12261 *
12262 * Redistribution and use in source and binary forms, with or without
12263 * modification, are permitted provided that the following conditions
12264 * are met:
12265 * 1. Redistributions of source code must retain the above copyright
12266 * notice, this list of conditions and the following disclaimer.
12267 * 2. Redistributions in binary form must reproduce the above copyright
12268 * notice, this list of conditions and the following disclaimer in the
12269 * documentation and/or other materials provided with the distribution.
12270 *
Eric Andersen2870d962001-07-02 17:27:21 +000012271 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
12272 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000012273 *
12274 * 4. Neither the name of the University nor the names of its contributors
12275 * may be used to endorse or promote products derived from this software
12276 * without specific prior written permission.
12277 *
12278 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
12279 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
12280 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
12281 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
12282 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
12283 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
12284 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
12285 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
12286 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
12287 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
12288 * SUCH DAMAGE.
12289 */