blob: 216780c9d8599a114ac16201cb38c6fbd183276c [file] [log] [blame]
Eric Andersendf82f612001-06-28 07:46:40 +00001/* vi: set sw=4 ts=4: */
2/*
3 * ash shell port for busybox
4 *
5 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +00006 * The Regents of the University of California. All rights reserved.
Eric Andersencb57d552001-06-28 07:25:16 +00007 *
8 * This code is derived from software contributed to Berkeley by
9 * Kenneth Almquist.
10 *
Eric Andersendf82f612001-06-28 07:46:40 +000011 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
Eric Andersencb57d552001-06-28 07:25:16 +000015 *
Eric Andersendf82f612001-06-28 07:46:40 +000016 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
Eric Andersen2870d962001-07-02 17:27:21 +000025 * This version of ash is adapted from the source in Debian's ash 0.3.8-5
26 * package.
Eric Andersendf82f612001-06-28 07:46:40 +000027 *
Eric Andersen2870d962001-07-02 17:27:21 +000028 * Modified by Erik Andersen <andersee@debian.org> and
Eric Andersen7467c8d2001-07-12 20:26:32 +000029 * Vladimir Oleynik <dzo@simtreas.ru> to be used in busybox
Eric Andersen2870d962001-07-02 17:27:21 +000030 *
Eric Andersendf82f612001-06-28 07:46:40 +000031 *
32 * Original copyright notice is retained at the end of this file.
Eric Andersencb57d552001-06-28 07:25:16 +000033 */
34
Eric Andersen2870d962001-07-02 17:27:21 +000035
Eric Andersen2870d962001-07-02 17:27:21 +000036/* Enable this to compile in extra debugging noise. When debugging is
37 * on, debugging info will be written to $HOME/trace and a quit signal
38 * will generate a core dump. */
39#undef DEBUG
40
Eric Andersen2870d962001-07-02 17:27:21 +000041/* These are here to work with glibc -- Don't change these... */
Eric Andersendf82f612001-06-28 07:46:40 +000042#undef FNMATCH_BROKEN
43#undef GLOB_BROKEN
Eric Andersen5bb16772001-09-06 18:00:41 +000044#define IFS_BROKEN
Eric Andersencb57d552001-06-28 07:25:16 +000045
46#include <assert.h>
Manuel Novoa III 16815d42001-08-10 19:36:07 +000047#include <stddef.h>
Eric Andersencb57d552001-06-28 07:25:16 +000048#include <ctype.h>
49#include <dirent.h>
50#include <errno.h>
51#include <fcntl.h>
52#include <limits.h>
53#include <paths.h>
Eric Andersencb57d552001-06-28 07:25:16 +000054#include <setjmp.h>
55#include <signal.h>
56#include <stdarg.h>
Eric Andersencb57d552001-06-28 07:25:16 +000057#include <stdio.h>
58#include <stdlib.h>
59#include <string.h>
60#include <sysexits.h>
61#include <unistd.h>
62#include <sys/stat.h>
63#include <sys/cdefs.h>
64#include <sys/ioctl.h>
65#include <sys/param.h>
66#include <sys/resource.h>
67#include <sys/time.h>
68#include <sys/times.h>
69#include <sys/types.h>
70#include <sys/wait.h>
Robert Grieblea1a63a2002-06-04 20:10:23 +000071#include "busybox.h"
Eric Andersen887ca792002-07-03 23:19:26 +000072#include "pwd_.h"
Eric Andersencb57d552001-06-28 07:25:16 +000073
74
75#if !defined(FNMATCH_BROKEN)
76#include <fnmatch.h>
77#endif
78#if !defined(GLOB_BROKEN)
79#include <glob.h>
80#endif
81
Eric Andersend35c5df2002-01-09 15:37:36 +000082#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +000083#include <termios.h>
Eric Andersencb57d552001-06-28 07:25:16 +000084#endif
85
Eric Andersen2870d962001-07-02 17:27:21 +000086#include "cmdedit.h"
87
Eric Andersenaa1d6cc2002-09-30 20:12:32 +000088#if defined(__uClinux__)
89#error "Do not even bother, ash will not run on uClinux"
90#endif
91
Eric Andersen2870d962001-07-02 17:27:21 +000092/*
93 * This file was generated by the mksyntax program.
94 */
95
96/* Syntax classes */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000097#define CWORD 0 /* character is nothing special */
98#define CNL 1 /* newline character */
99#define CBACK 2 /* a backslash character */
100#define CSQUOTE 3 /* single quote */
101#define CDQUOTE 4 /* double quote */
102#define CENDQUOTE 5 /* a terminating quote */
103#define CBQUOTE 6 /* backwards single quote */
104#define CVAR 7 /* a dollar sign */
105#define CENDVAR 8 /* a '}' character */
106#define CLP 9 /* a left paren in arithmetic */
107#define CRP 10 /* a right paren in arithmetic */
108#define CENDFILE 11 /* end of file */
109#define CCTL 12 /* like CWORD, except it must be escaped */
110#define CSPCL 13 /* these terminate a word */
111#define CIGN 14 /* character should be ignored */
Eric Andersen2870d962001-07-02 17:27:21 +0000112
Eric Andersen2870d962001-07-02 17:27:21 +0000113#define SYNBASE 130
114#define PEOF -130
115
116#define PEOA -129
117
118#define TEOF 0
119#define TNL 1
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000120#define TREDIR 2
121#define TWORD 3
122#define TASSIGN 4
123#define TSEMI 5
124#define TBACKGND 6
125#define TAND 7
126#define TOR 8
127#define TPIPE 9
128#define TLP 10
129#define TRP 11
130#define TENDCASE 12
131#define TENDBQUOTE 13
Eric Andersen2870d962001-07-02 17:27:21 +0000132#define TNOT 14
133#define TCASE 15
134#define TDO 16
135#define TDONE 17
136#define TELIF 18
137#define TELSE 19
138#define TESAC 20
139#define TFI 21
140#define TFOR 22
141#define TIF 23
142#define TIN 24
143#define TTHEN 25
144#define TUNTIL 26
145#define TWHILE 27
146#define TBEGIN 28
147#define TEND 29
148
149
Eric Andersen2870d962001-07-02 17:27:21 +0000150
151/* control characters in argument strings */
152#define CTLESC '\201'
153#define CTLVAR '\202'
154#define CTLENDVAR '\203'
155#define CTLBACKQ '\204'
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000156#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
Eric Andersen2870d962001-07-02 17:27:21 +0000157/* CTLBACKQ | CTLQUOTE == '\205' */
158#define CTLARI '\206'
159#define CTLENDARI '\207'
160#define CTLQUOTEMARK '\210'
161
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000162
Eric Andersen62483552001-07-10 06:09:16 +0000163#define is_digit(c) ((c)>='0' && (c)<='9')
Eric Andersen2870d962001-07-02 17:27:21 +0000164#define is_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalpha((unsigned char) (c))))
165#define is_in_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalnum((unsigned char) (c))))
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000166
167/*
168 * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
169 * (assuming ascii char codes, as the original implementation did)
170 */
171#define is_special(c) \
172 ( (((unsigned int)c) - 33 < 32) \
173 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
174
Eric Andersen2870d962001-07-02 17:27:21 +0000175#define digit_val(c) ((c) - '0')
Eric Andersencb57d552001-06-28 07:25:16 +0000176
177
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000178#define S_DFL 1 /* default signal handling (SIG_DFL) */
179#define S_CATCH 2 /* signal is caught */
180#define S_IGN 3 /* signal is ignored (SIG_IGN) */
181#define S_HARD_IGN 4 /* signal is ignored permenantly */
182#define S_RESET 5 /* temporary - to reset a hard ignored sig */
Eric Andersencb57d552001-06-28 07:25:16 +0000183
184
Eric Andersen2870d962001-07-02 17:27:21 +0000185/* variable substitution byte (follows CTLVAR) */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000186#define VSTYPE 0x0f /* type of variable substitution */
187#define VSNUL 0x10 /* colon--treat the empty string as unset */
188#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
Eric Andersencb57d552001-06-28 07:25:16 +0000189
Eric Andersen2870d962001-07-02 17:27:21 +0000190/* values of VSTYPE field */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000191#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
192#define VSMINUS 0x2 /* ${var-text} */
193#define VSPLUS 0x3 /* ${var+text} */
194#define VSQUESTION 0x4 /* ${var?message} */
195#define VSASSIGN 0x5 /* ${var=text} */
196#define VSTRIMLEFT 0x6 /* ${var#pattern} */
197#define VSTRIMLEFTMAX 0x7 /* ${var##pattern} */
198#define VSTRIMRIGHT 0x8 /* ${var%pattern} */
199#define VSTRIMRIGHTMAX 0x9 /* ${var%%pattern} */
200#define VSLENGTH 0xa /* ${#var} */
Eric Andersencb57d552001-06-28 07:25:16 +0000201
Eric Andersen2870d962001-07-02 17:27:21 +0000202/* flags passed to redirect */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000203#define REDIR_PUSH 01 /* save previous values of file descriptors */
204#define REDIR_BACKQ 02 /* save the command output to pipe */
Eric Andersencb57d552001-06-28 07:25:16 +0000205
Eric Andersen2870d962001-07-02 17:27:21 +0000206/*
207 * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
208 * so we use _setjmp instead.
209 */
210
Eric Andersen62483552001-07-10 06:09:16 +0000211#if defined(BSD)
Eric Andersen2870d962001-07-02 17:27:21 +0000212#define setjmp(jmploc) _setjmp(jmploc)
213#define longjmp(jmploc, val) _longjmp(jmploc, val)
214#endif
215
216/*
217 * Most machines require the value returned from malloc to be aligned
218 * in some way. The following macro will get this right on many machines.
219 */
220
221#ifndef ALIGN
222union align {
223 int i;
224 char *cp;
225};
226
227#define ALIGN(nbytes) (((nbytes) + sizeof(union align) - 1) & ~(sizeof(union align) - 1))
228#endif
229
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000230#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +0000231#include <locale.h>
232static void change_lc_all(const char *value);
233static void change_lc_ctype(const char *value);
234#endif
235
236/*
237 * These macros allow the user to suspend the handling of interrupt signals
238 * over a period of time. This is similar to SIGHOLD to or sigblock, but
239 * much more efficient and portable. (But hacking the kernel is so much
240 * more fun than worrying about efficiency and portability. :-))
241 */
242
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000243static void onint(void);
Eric Andersen2870d962001-07-02 17:27:21 +0000244static volatile int suppressint;
245static volatile int intpending;
246
247#define INTOFF suppressint++
Eric Andersend35c5df2002-01-09 15:37:36 +0000248#ifndef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Eric Andersen2870d962001-07-02 17:27:21 +0000249#define INTON { if (--suppressint == 0 && intpending) onint(); }
Eric Andersen3102ac42001-07-06 04:26:23 +0000250#define FORCEINTON {suppressint = 0; if (intpending) onint();}
Eric Andersen2870d962001-07-02 17:27:21 +0000251#else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000252static void __inton(void);
253static void forceinton(void);
254
Eric Andersen2870d962001-07-02 17:27:21 +0000255#define INTON __inton()
Eric Andersen3102ac42001-07-06 04:26:23 +0000256#define FORCEINTON forceinton()
Eric Andersen2870d962001-07-02 17:27:21 +0000257#endif
Eric Andersen3102ac42001-07-06 04:26:23 +0000258
Eric Andersen2870d962001-07-02 17:27:21 +0000259#define CLEAR_PENDING_INT intpending = 0
260#define int_pending() intpending
261
262
263typedef void *pointer;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000264
Eric Andersen2870d962001-07-02 17:27:21 +0000265#ifndef NULL
266#define NULL (void *)0
267#endif
268
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000269static pointer stalloc(int);
270static void stunalloc(pointer);
271static void ungrabstackstr(char *, char *);
272static char *growstackstr(void);
273static char *makestrspace(size_t newlen);
Eric Andersen2870d962001-07-02 17:27:21 +0000274
275/*
276 * Parse trees for commands are allocated in lifo order, so we use a stack
277 * to make this more efficient, and also to avoid all sorts of exception
278 * handling code to handle interrupts in the middle of a parse.
279 *
280 * The size 504 was chosen because the Ultrix malloc handles that size
281 * well.
282 */
283
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000284#define MINSIZE 504 /* minimum size of a block */
Eric Andersen2870d962001-07-02 17:27:21 +0000285
286
287struct stack_block {
288 struct stack_block *prev;
289 char space[MINSIZE];
290};
291
292static struct stack_block stackbase;
293static struct stack_block *stackp = &stackbase;
294static struct stackmark *markp;
295static char *stacknxt = stackbase.space;
296static int stacknleft = MINSIZE;
297
298
299#define equal(s1, s2) (strcmp(s1, s2) == 0)
300
301#define stackblock() stacknxt
302#define stackblocksize() stacknleft
303#define STARTSTACKSTR(p) p = stackblock(), sstrnleft = stackblocksize()
Eric Andersen3102ac42001-07-06 04:26:23 +0000304
Eric Andersen2870d962001-07-02 17:27:21 +0000305#define STPUTC(c, p) (--sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(), *p++ = (c)))
306#define CHECKSTRSPACE(n, p) { if (sstrnleft < n) p = makestrspace(n); }
Eric Andersen2870d962001-07-02 17:27:21 +0000307#define STACKSTRNUL(p) (sstrnleft == 0? (p = growstackstr(), *p = '\0') : (*p = '\0'))
Eric Andersen3102ac42001-07-06 04:26:23 +0000308
309
310#define USTPUTC(c, p) (--sstrnleft, *p++ = (c))
Eric Andersen2870d962001-07-02 17:27:21 +0000311#define STUNPUTC(p) (++sstrnleft, --p)
312#define STTOPC(p) p[-1]
313#define STADJUST(amount, p) (p += (amount), sstrnleft -= (amount))
314#define grabstackstr(p) stalloc(stackblocksize() - sstrnleft)
315
Eric Andersen2870d962001-07-02 17:27:21 +0000316
Eric Andersen2870d962001-07-02 17:27:21 +0000317#ifdef DEBUG
318#define TRACE(param) trace param
Eric Andersen69a20f02001-10-31 10:40:37 +0000319typedef union node unode;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000320static void trace(const char *, ...);
321static void trargs(char **);
322static void showtree(unode *);
323static void trputc(int);
324static void trputs(const char *);
325static void opentrace(void);
Eric Andersen2870d962001-07-02 17:27:21 +0000326#else
327#define TRACE(param)
328#endif
329
330#define NSEMI 0
331#define NCMD 1
332#define NPIPE 2
333#define NREDIR 3
334#define NBACKGND 4
335#define NSUBSHELL 5
336#define NAND 6
337#define NOR 7
338#define NIF 8
339#define NWHILE 9
340#define NUNTIL 10
341#define NFOR 11
342#define NCASE 12
343#define NCLIST 13
344#define NDEFUN 14
345#define NARG 15
346#define NTO 16
347#define NFROM 17
348#define NFROMTO 18
349#define NAPPEND 19
350#define NTOOV 20
351#define NTOFD 21
352#define NFROMFD 22
353#define NHERE 23
354#define NXHERE 24
355#define NNOT 25
356
357/*
358 * expandarg() flags
359 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000360#define EXP_FULL 0x1 /* perform word splitting & file globbing */
361#define EXP_TILDE 0x2 /* do normal tilde expansion */
362#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
363#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
364#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
365#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
Eric Andersen2870d962001-07-02 17:27:21 +0000366
367
368#define NOPTS 16
369
370static char optet_vals[NOPTS];
371
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000372static const char *const optlist[NOPTS] = {
Eric Andersen2870d962001-07-02 17:27:21 +0000373 "e" "errexit",
374 "f" "noglob",
375 "I" "ignoreeof",
376 "i" "interactive",
377 "m" "monitor",
378 "n" "noexec",
379 "s" "stdin",
380 "x" "xtrace",
381 "v" "verbose",
382 "V" "vi",
383 "E" "emacs",
384 "C" "noclobber",
385 "a" "allexport",
386 "b" "notify",
387 "u" "nounset",
388 "q" "quietprofile"
389};
390
391#define optent_name(optent) (optent+1)
392#define optent_letter(optent) optent[0]
393#define optent_val(optent) optet_vals[optent]
394
395#define eflag optent_val(0)
396#define fflag optent_val(1)
397#define Iflag optent_val(2)
398#define iflag optent_val(3)
399#define mflag optent_val(4)
400#define nflag optent_val(5)
401#define sflag optent_val(6)
402#define xflag optent_val(7)
403#define vflag optent_val(8)
404#define Vflag optent_val(9)
405#define Eflag optent_val(10)
406#define Cflag optent_val(11)
407#define aflag optent_val(12)
408#define bflag optent_val(13)
409#define uflag optent_val(14)
410#define qflag optent_val(15)
411
412
413/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
414#define FORK_FG 0
415#define FORK_BG 1
416#define FORK_NOJOB 2
417
418
419struct nbinary {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000420 int type;
421 union node *ch1;
422 union node *ch2;
Eric Andersen2870d962001-07-02 17:27:21 +0000423};
424
425
426struct ncmd {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000427 int type;
428 int backgnd;
429 union node *assign;
430 union node *args;
431 union node *redirect;
Eric Andersen2870d962001-07-02 17:27:21 +0000432};
433
434
435struct npipe {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000436 int type;
437 int backgnd;
438 struct nodelist *cmdlist;
Eric Andersen2870d962001-07-02 17:27:21 +0000439};
440
441
442struct nredir {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000443 int type;
444 union node *n;
445 union node *redirect;
Eric Andersen2870d962001-07-02 17:27:21 +0000446};
447
448
449struct nif {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000450 int type;
451 union node *test;
452 union node *ifpart;
453 union node *elsepart;
Eric Andersen2870d962001-07-02 17:27:21 +0000454};
455
456
457struct nfor {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000458 int type;
459 union node *args;
460 union node *body;
461 char *var;
Eric Andersen2870d962001-07-02 17:27:21 +0000462};
463
464
465struct ncase {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000466 int type;
467 union node *expr;
468 union node *cases;
Eric Andersen2870d962001-07-02 17:27:21 +0000469};
470
471
472struct nclist {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000473 int type;
474 union node *next;
475 union node *pattern;
476 union node *body;
Eric Andersen2870d962001-07-02 17:27:21 +0000477};
478
479
480struct narg {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000481 int type;
482 union node *next;
483 char *text;
484 struct nodelist *backquote;
Eric Andersen2870d962001-07-02 17:27:21 +0000485};
486
487
488struct nfile {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000489 int type;
490 union node *next;
491 int fd;
492 union node *fname;
493 char *expfname;
Eric Andersen2870d962001-07-02 17:27:21 +0000494};
495
496
497struct ndup {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000498 int type;
499 union node *next;
500 int fd;
501 int dupfd;
502 union node *vname;
Eric Andersen2870d962001-07-02 17:27:21 +0000503};
504
505
506struct nhere {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000507 int type;
508 union node *next;
509 int fd;
510 union node *doc;
Eric Andersen2870d962001-07-02 17:27:21 +0000511};
512
513
514struct nnot {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000515 int type;
516 union node *com;
Eric Andersen2870d962001-07-02 17:27:21 +0000517};
518
519
520union node {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000521 int type;
522 struct nbinary nbinary;
523 struct ncmd ncmd;
524 struct npipe npipe;
525 struct nredir nredir;
526 struct nif nif;
527 struct nfor nfor;
528 struct ncase ncase;
529 struct nclist nclist;
530 struct narg narg;
531 struct nfile nfile;
532 struct ndup ndup;
533 struct nhere nhere;
534 struct nnot nnot;
Eric Andersen2870d962001-07-02 17:27:21 +0000535};
536
537
538struct nodelist {
539 struct nodelist *next;
540 union node *n;
541};
542
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000543struct backcmd { /* result of evalbackcmd */
544 int fd; /* file descriptor to read from */
545 char *buf; /* buffer */
546 int nleft; /* number of chars in buffer */
547 struct job *jp; /* job structure for command */
Eric Andersen2870d962001-07-02 17:27:21 +0000548};
549
550struct cmdentry {
551 int cmdtype;
552 union param {
553 int index;
554 union node *func;
555 const struct builtincmd *cmd;
556 } u;
557};
558
559struct strlist {
560 struct strlist *next;
561 char *text;
562};
563
564
565struct arglist {
566 struct strlist *list;
567 struct strlist **lastp;
568};
569
570struct strpush {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000571 struct strpush *prev; /* preceding string on stack */
Eric Andersen2870d962001-07-02 17:27:21 +0000572 char *prevstring;
573 int prevnleft;
Eric Andersend35c5df2002-01-09 15:37:36 +0000574#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000575 struct alias *ap; /* if push was associated with an alias */
Eric Andersen2870d962001-07-02 17:27:21 +0000576#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000577 char *string; /* remember the string since it may change */
Eric Andersen2870d962001-07-02 17:27:21 +0000578};
579
580struct parsefile {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000581 struct parsefile *prev; /* preceding file on stack */
582 int linno; /* current line */
583 int fd; /* file descriptor (or -1 if string) */
584 int nleft; /* number of chars left in this line */
585 int lleft; /* number of chars left in this buffer */
586 char *nextc; /* next char in buffer */
587 char *buf; /* input buffer */
588 struct strpush *strpush; /* for pushing strings at this level */
589 struct strpush basestrpush; /* so pushing one is fast */
Eric Andersen2870d962001-07-02 17:27:21 +0000590};
591
592struct stackmark {
593 struct stack_block *stackp;
594 char *stacknxt;
595 int stacknleft;
596 struct stackmark *marknext;
597};
598
599struct shparam {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000600 int nparam; /* # of positional parameters (without $0) */
601 unsigned char malloc; /* if parameter list dynamically allocated */
602 char **p; /* parameter list */
603 int optind; /* next parameter to be processed by getopts */
604 int optoff; /* used by getopts */
Eric Andersen2870d962001-07-02 17:27:21 +0000605};
606
Eric Andersen62483552001-07-10 06:09:16 +0000607/*
608 * When commands are first encountered, they are entered in a hash table.
609 * This ensures that a full path search will not have to be done for them
610 * on each invocation.
611 *
612 * We should investigate converting to a linear search, even though that
613 * would make the command name "hash" a misnomer.
614 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000615#define CMDTABLESIZE 31 /* should be prime */
616#define ARB 1 /* actual size determined at run time */
Eric Andersen62483552001-07-10 06:09:16 +0000617
618
619
620struct tblentry {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000621 struct tblentry *next; /* next entry in hash chain */
622 union param param; /* definition of builtin function */
623 short cmdtype; /* index identifying command */
624 char rehash; /* if set, cd done since entry created */
625 char cmdname[ARB]; /* name of command */
Eric Andersen62483552001-07-10 06:09:16 +0000626};
627
628
629static struct tblentry *cmdtable[CMDTABLESIZE];
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000630static int builtinloc = -1; /* index in path of %builtin, or -1 */
631static int exerrno = 0; /* Last exec error */
Eric Andersen62483552001-07-10 06:09:16 +0000632
633
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000634static void tryexec(char *, char **, char **);
635static void printentry(struct tblentry *, int);
636static void clearcmdentry(int);
637static struct tblentry *cmdlookup(const char *, int);
638static void delete_cmd_entry(void);
639static int path_change(const char *, int *);
Eric Andersen62483552001-07-10 06:09:16 +0000640
641
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000642static void flushall(void);
643static void out2fmt(const char *, ...)
644 __attribute__ ((__format__(__printf__, 1, 2)));
645static int xwrite(int, const char *, int);
Eric Andersen2870d962001-07-02 17:27:21 +0000646
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000647static inline void outstr(const char *p, FILE * file)
648{
649 fputs(p, file);
650}
651static void out1str(const char *p)
652{
653 outstr(p, stdout);
654}
655static void out2str(const char *p)
656{
657 outstr(p, stderr);
658}
Eric Andersen2870d962001-07-02 17:27:21 +0000659
Eric Andersend35c5df2002-01-09 15:37:36 +0000660#ifndef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Eric Andersen3102ac42001-07-06 04:26:23 +0000661#define out2c(c) putc((c), stderr)
Eric Andersen62483552001-07-10 06:09:16 +0000662#else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000663static void out2c(int c)
664{
665 putc(c, stderr);
666}
Eric Andersen62483552001-07-10 06:09:16 +0000667#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000668
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000669
Eric Andersend35c5df2002-01-09 15:37:36 +0000670#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000671#define USE_SIT_FUNCTION
672#endif
673
674/* number syntax index */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000675#define BASESYNTAX 0 /* not in quotes */
676#define DQSYNTAX 1 /* in double quotes */
677#define SQSYNTAX 2 /* in single quotes */
678#define ARISYNTAX 3 /* in arithmetic */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000679
680static const char S_I_T[][4] = {
Glenn L McGrath50812ff2002-08-23 13:14:48 +0000681 {CSPCL, CIGN, CIGN, CIGN}, /* 0, PEOA */
682 {CSPCL, CWORD, CWORD, CWORD}, /* 1, ' ' */
683 {CNL, CNL, CNL, CNL}, /* 2, \n */
684 {CWORD, CCTL, CCTL, CWORD}, /* 3, !*-/:=?[]~ */
685 {CDQUOTE, CENDQUOTE, CWORD, CDQUOTE}, /* 4, '"' */
686 {CVAR, CVAR, CWORD, CVAR}, /* 5, $ */
687 {CSQUOTE, CWORD, CENDQUOTE, CSQUOTE}, /* 6, "'" */
688 {CSPCL, CWORD, CWORD, CLP}, /* 7, ( */
689 {CSPCL, CWORD, CWORD, CRP}, /* 8, ) */
690 {CBACK, CBACK, CCTL, CBACK}, /* 9, \ */
691 {CBQUOTE, CBQUOTE, CWORD, CBQUOTE}, /* 10, ` */
692 {CENDVAR, CENDVAR, CWORD, CENDVAR}, /* 11, } */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000693#ifndef USE_SIT_FUNCTION
Glenn L McGrath50812ff2002-08-23 13:14:48 +0000694 {CENDFILE, CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
695 {CWORD, CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
696 {CCTL, CCTL, CCTL, CCTL} /* 14, CTLESC ... */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000697#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000698};
699
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000700#ifdef USE_SIT_FUNCTION
701
702#define U_C(c) ((unsigned char)(c))
703
704static int SIT(int c, int syntax)
705{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000706 static const char spec_symbls[] = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
707 static const char syntax_index_table[] = {
708 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
709 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
710 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
711 11, 3
712 }; /* "}~" */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000713 const char *s;
714 int indx;
715
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000716 if (c == PEOF) /* 2^8+2 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000717 return CENDFILE;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000718 if (c == PEOA) /* 2^8+1 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000719 indx = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000720 else if (U_C(c) >= U_C(CTLESC) && U_C(c) <= U_C(CTLQUOTEMARK))
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000721 return CCTL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000722 else {
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000723 s = strchr(spec_symbls, c);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000724 if (s == 0)
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000725 return CWORD;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000726 indx = syntax_index_table[(s - spec_symbls)];
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000727 }
728 return S_I_T[indx][syntax];
729}
730
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000731#else /* USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000732
733#define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
734
735#define CSPCL_CIGN_CIGN_CIGN 0
736#define CSPCL_CWORD_CWORD_CWORD 1
737#define CNL_CNL_CNL_CNL 2
738#define CWORD_CCTL_CCTL_CWORD 3
739#define CDQUOTE_CENDQUOTE_CWORD_CDQUOTE 4
740#define CVAR_CVAR_CWORD_CVAR 5
741#define CSQUOTE_CWORD_CENDQUOTE_CSQUOTE 6
742#define CSPCL_CWORD_CWORD_CLP 7
743#define CSPCL_CWORD_CWORD_CRP 8
744#define CBACK_CBACK_CCTL_CBACK 9
745#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
746#define CENDVAR_CENDVAR_CWORD_CENDVAR 11
747#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
748#define CWORD_CWORD_CWORD_CWORD 13
749#define CCTL_CCTL_CCTL_CCTL 14
750
751static const char syntax_index_table[258] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000752 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
753 /* 0 -130 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
754 /* 1 -129 PEOA */ CSPCL_CIGN_CIGN_CIGN,
755 /* 2 -128 0xff */ CWORD_CWORD_CWORD_CWORD,
Glenn L McGrath50812ff2002-08-23 13:14:48 +0000756 /* 3 -127 */ CCTL_CCTL_CCTL_CCTL,
757 /* CTLQUOTEMARK */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000758 /* 4 -126 */ CCTL_CCTL_CCTL_CCTL,
759 /* 5 -125 */ CCTL_CCTL_CCTL_CCTL,
760 /* 6 -124 */ CCTL_CCTL_CCTL_CCTL,
761 /* 7 -123 */ CCTL_CCTL_CCTL_CCTL,
762 /* 8 -122 */ CCTL_CCTL_CCTL_CCTL,
763 /* 9 -121 */ CCTL_CCTL_CCTL_CCTL,
Glenn L McGrath50812ff2002-08-23 13:14:48 +0000764 /* 10 -120 */ CCTL_CCTL_CCTL_CCTL,
765 /* CTLESC */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000766 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
767 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
768 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
769 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
770 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
771 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
772 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
773 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
774 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
775 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
776 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
777 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
778 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
779 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
780 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
781 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
782 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
783 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
784 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
785 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
786 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
787 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
788 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
789 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
790 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
791 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
792 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
793 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
794 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
795 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
796 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
797 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
798 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
799 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
800 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
801 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
802 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
803 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
804 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
805 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
806 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
807 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
808 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
809 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
810 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
811 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
812 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
813 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
814 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
815 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
816 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
817 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
818 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
819 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
820 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
821 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
822 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
823 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
824 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
825 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
826 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
827 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
828 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
829 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
830 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
831 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
832 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
833 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
834 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
835 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
836 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
837 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
838 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
839 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
840 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
841 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
842 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
843 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
844 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
845 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
846 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
847 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
848 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
849 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
850 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
851 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
852 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
853 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
854 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
855 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
856 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
857 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
858 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
859 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
860 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
861 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
862 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
863 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
864 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
865 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
866 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
867 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
868 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
869 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
870 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
871 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
872 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
873 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
874 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
875 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
876 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
877 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
878 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
879 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
880 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
881 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
882 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
883 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
884 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
885 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
886 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
887 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
888 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
889 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
890 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
891 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
892 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
893 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
894 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
895 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
896 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
897 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
898 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
899 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
900 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
901 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
902 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
903 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
904 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
905 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
906 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
907 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
908 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
909 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
910 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
911 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
912 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
913 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
914 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
915 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
916 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
917 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
918 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
919 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CDQUOTE,
920 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
921 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
922 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
923 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
924 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CSQUOTE,
925 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
926 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
927 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
928 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
929 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
930 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
931 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
932 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
933 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
934 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
935 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
936 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
937 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
938 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
939 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
940 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
941 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
942 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
943 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
944 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
945 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
946 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
947 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
948 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
949 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
950 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
951 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
952 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
953 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
954 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
955 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
956 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
957 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
958 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
959 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
960 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
961 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
962 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
963 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
964 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
965 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
966 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
967 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
968 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
969 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
970 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
971 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
972 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
973 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
974 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
975 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
976 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
977 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
978 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
979 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
980 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
981 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
982 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
983 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
984 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
985 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
986 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
987 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
988 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
989 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
990 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
991 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
992 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
993 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
994 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
995 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
996 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
997 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
998 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
999 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
1000 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
1001 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
1002 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
1003 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
1004 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
1005 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
1006 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
1007 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
1008 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
1009 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
1010 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
1011 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
1012 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
Eric Andersen2870d962001-07-02 17:27:21 +00001013};
1014
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001015#endif /* USE_SIT_FUNCTION */
Eric Andersen2870d962001-07-02 17:27:21 +00001016
Eric Andersen2870d962001-07-02 17:27:21 +00001017
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001018/* first char is indicating which tokens mark the end of a list */
1019static const char *const tokname_array[] = {
1020 "\1end of file",
1021 "\0newline",
1022 "\0redirection",
1023 "\0word",
1024 "\0assignment",
1025 "\0;",
1026 "\0&",
1027 "\0&&",
1028 "\0||",
1029 "\0|",
1030 "\0(",
1031 "\1)",
1032 "\1;;",
1033 "\1`",
Eric Andersen2870d962001-07-02 17:27:21 +00001034#define KWDOFFSET 14
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001035 /* the following are keywords */
1036 "\0!",
1037 "\0case",
1038 "\1do",
1039 "\1done",
1040 "\1elif",
1041 "\1else",
1042 "\1esac",
1043 "\1fi",
1044 "\0for",
1045 "\0if",
1046 "\0in",
1047 "\1then",
1048 "\0until",
1049 "\0while",
1050 "\0{",
1051 "\1}",
Eric Andersen2870d962001-07-02 17:27:21 +00001052};
1053
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001054static const char *tokname(int tok)
1055{
1056 static char buf[16];
1057
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001058 if (tok >= TSEMI)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001059 buf[0] = '"';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001060 sprintf(buf + (tok >= TSEMI), "%s%c",
1061 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001062 return buf;
1063}
Eric Andersen2870d962001-07-02 17:27:21 +00001064
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001065static int plinno = 1; /* input line number */
Eric Andersen2870d962001-07-02 17:27:21 +00001066
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001067static int parselleft; /* copy of parsefile->lleft */
Eric Andersen2870d962001-07-02 17:27:21 +00001068
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001069static struct parsefile basepf; /* top level input file */
1070static char basebuf[BUFSIZ]; /* buffer for top level input file */
1071static struct parsefile *parsefile = &basepf; /* current input file */
Eric Andersen2870d962001-07-02 17:27:21 +00001072
1073/*
1074 * NEOF is returned by parsecmd when it encounters an end of file. It
1075 * must be distinct from NULL, so we use the address of a variable that
1076 * happens to be handy.
1077 */
1078
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001079static int tokpushback; /* last token pushed back */
1080
Eric Andersen2870d962001-07-02 17:27:21 +00001081#define NEOF ((union node *)&tokpushback)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001082static int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */
Eric Andersen2870d962001-07-02 17:27:21 +00001083
1084
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001085static void error(const char *, ...) __attribute__ ((__noreturn__));
1086static void exerror(int, const char *, ...) __attribute__ ((__noreturn__));
1087static void shellexec(char **, char **, const char *, int)
1088 __attribute__ ((noreturn));
1089static void exitshell(int) __attribute__ ((noreturn));
Eric Andersen2870d962001-07-02 17:27:21 +00001090
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001091static int goodname(const char *);
1092static void ignoresig(int);
1093static void onsig(int);
1094static void dotrap(void);
1095static int decode_signal(const char *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00001096
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001097static void setparam(char **);
1098static void freeparam(volatile struct shparam *);
Eric Andersen2870d962001-07-02 17:27:21 +00001099
1100/* reasons for skipping commands (see comment on breakcmd routine) */
1101#define SKIPBREAK 1
1102#define SKIPCONT 2
1103#define SKIPFUNC 3
1104#define SKIPFILE 4
1105
1106/* values of cmdtype */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001107#define CMDUNKNOWN -1 /* no entry in table for command */
1108#define CMDNORMAL 0 /* command is an executable program */
1109#define CMDBUILTIN 1 /* command is a shell builtin */
1110#define CMDFUNCTION 2 /* command is a shell function */
Eric Andersen2870d962001-07-02 17:27:21 +00001111
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001112#define DO_ERR 1 /* find_command prints errors */
1113#define DO_ABS 2 /* find_command checks absolute paths */
1114#define DO_NOFUN 4 /* find_command ignores functions */
1115#define DO_BRUTE 8 /* find_command ignores hash table */
Eric Andersen2870d962001-07-02 17:27:21 +00001116
1117/*
1118 * Shell variables.
1119 */
1120
1121/* flags */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001122#define VEXPORT 0x01 /* variable is exported */
1123#define VREADONLY 0x02 /* variable cannot be modified */
1124#define VSTRFIXED 0x04 /* variable struct is staticly allocated */
1125#define VTEXTFIXED 0x08 /* text is staticly allocated */
1126#define VSTACK 0x10 /* text is allocated on the stack */
1127#define VUNSET 0x20 /* the variable is not set */
1128#define VNOFUNC 0x40 /* don't call the callback function */
Eric Andersen2870d962001-07-02 17:27:21 +00001129
1130
1131struct var {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001132 struct var *next; /* next entry in hash list */
1133 int flags; /* flags are defined above */
1134 char *text; /* name=value */
Eric Andersen2870d962001-07-02 17:27:21 +00001135 void (*func) (const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001136 /* function to be called when */
1137 /* the variable gets set/unset */
Eric Andersen2870d962001-07-02 17:27:21 +00001138};
1139
1140struct localvar {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001141 struct localvar *next; /* next local variable in list */
1142 struct var *vp; /* the variable that was made local */
1143 int flags; /* saved flags */
1144 char *text; /* saved text */
Eric Andersen2870d962001-07-02 17:27:21 +00001145};
1146
1147
Eric Andersen62483552001-07-10 06:09:16 +00001148#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00001149#define rmescapes(p) _rmescapes((p), 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001150static char *_rmescapes(char *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00001151#else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001152static void rmescapes(char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001153#endif
1154
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001155static int casematch(union node *, const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001156static void clearredir(void);
1157static void popstring(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001158static void readcmdfile(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001159
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001160static int number(const char *);
1161static int is_number(const char *, int *num);
1162static char *single_quote(const char *);
1163static int nextopt(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001164
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001165static void redirect(union node *, int);
1166static void popredir(void);
1167static int dup_as_newfd(int, int);
Eric Andersen2870d962001-07-02 17:27:21 +00001168
1169static void changepath(const char *newval);
1170static void getoptsreset(const char *value);
1171
1172
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001173static int parsenleft; /* copy of parsefile->nleft */
1174static char *parsenextc; /* copy of parsefile->nextc */
1175static int rootpid; /* pid of main shell */
1176static int rootshell; /* true if we aren't a child of the main shell */
Eric Andersen2870d962001-07-02 17:27:21 +00001177
1178static const char spcstr[] = " ";
1179static const char snlfmt[] = "%s\n";
1180
1181static int sstrnleft;
1182static int herefd = -1;
1183
1184static struct localvar *localvars;
1185
1186static struct var vifs;
1187static struct var vmail;
1188static struct var vmpath;
1189static struct var vpath;
1190static struct var vps1;
1191static struct var vps2;
1192static struct var voptind;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001193
Eric Andersenbdfd0d72001-10-24 05:00:29 +00001194#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00001195static struct var vlc_all;
1196static struct var vlc_ctype;
1197#endif
1198
1199struct varinit {
1200 struct var *var;
1201 int flags;
1202 const char *text;
1203 void (*func) (const char *);
1204};
1205
1206static const char defpathvar[] =
1207 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
1208#define defpath (defpathvar + 5)
1209
1210#ifdef IFS_BROKEN
1211static const char defifsvar[] = "IFS= \t\n";
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001212
Eric Andersen2870d962001-07-02 17:27:21 +00001213#define defifs (defifsvar + 4)
1214#else
1215static const char defifs[] = " \t\n";
1216#endif
1217
1218static const struct varinit varinit[] = {
1219#ifdef IFS_BROKEN
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001220 {&vifs, VSTRFIXED | VTEXTFIXED, defifsvar,
Eric Andersen2870d962001-07-02 17:27:21 +00001221#else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001222 {&vifs, VSTRFIXED | VTEXTFIXED | VUNSET, "IFS=",
Eric Andersen2870d962001-07-02 17:27:21 +00001223#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001224 NULL},
1225 {&vmail, VSTRFIXED | VTEXTFIXED | VUNSET, "MAIL=",
1226 NULL},
1227 {&vmpath, VSTRFIXED | VTEXTFIXED | VUNSET, "MAILPATH=",
1228 NULL},
1229 {&vpath, VSTRFIXED | VTEXTFIXED, defpathvar,
1230 changepath},
Tim Riker497a8852002-04-13 05:37:10 +00001231#if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001232 {&vps1, VSTRFIXED | VTEXTFIXED, "PS1=\\w \\$ ",
1233 NULL},
1234#endif /* else vps1 depends on uid */
1235 {&vps2, VSTRFIXED | VTEXTFIXED, "PS2=> ",
1236 NULL},
1237 {&voptind, VSTRFIXED | VTEXTFIXED, "OPTIND=1",
1238 getoptsreset},
Eric Andersenbdfd0d72001-10-24 05:00:29 +00001239#ifdef CONFIG_LOCALE_SUPPORT
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001240 {&vlc_all, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL=",
1241 change_lc_all},
1242 {&vlc_ctype, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE=",
1243 change_lc_ctype},
Eric Andersen2870d962001-07-02 17:27:21 +00001244#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001245 {NULL, 0, NULL,
1246 NULL}
Eric Andersen2870d962001-07-02 17:27:21 +00001247};
1248
1249#define VTABSIZE 39
1250
1251static struct var *vartab[VTABSIZE];
1252
1253/*
1254 * The following macros access the values of the above variables.
1255 * They have to skip over the name. They return the null string
1256 * for unset variables.
1257 */
1258
1259#define ifsval() (vifs.text + 4)
1260#define ifsset() ((vifs.flags & VUNSET) == 0)
1261#define mailval() (vmail.text + 5)
1262#define mpathval() (vmpath.text + 9)
1263#define pathval() (vpath.text + 5)
1264#define ps1val() (vps1.text + 4)
1265#define ps2val() (vps2.text + 4)
1266#define optindval() (voptind.text + 7)
1267
1268#define mpathset() ((vmpath.flags & VUNSET) == 0)
1269
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001270static void initvar(void);
1271static void setvar(const char *, const char *, int);
1272static void setvareq(char *, int);
1273static void listsetvar(struct strlist *);
1274static const char *lookupvar(const char *);
1275static const char *bltinlookup(const char *);
1276static char **environment(void);
1277static int showvarscmd(int, char **);
1278static void mklocal(char *);
1279static void poplocalvars(void);
1280static int unsetvar(const char *);
1281static int varequal(const char *, const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001282
1283
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001284static char *arg0; /* value of $0 */
1285static struct shparam shellparam; /* current positional parameters */
1286static char **argptr; /* argument list for builtin commands */
1287static char *optionarg; /* set by nextopt (like getopt) */
1288static char *optptr; /* used by nextopt */
1289static char *minusc; /* argument to -c option */
Eric Andersen2870d962001-07-02 17:27:21 +00001290
1291
Eric Andersend35c5df2002-01-09 15:37:36 +00001292#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00001293
1294#define ALIASINUSE 1
1295#define ALIASDEAD 2
1296
Eric Andersen3102ac42001-07-06 04:26:23 +00001297#define ATABSIZE 39
1298
Eric Andersen2870d962001-07-02 17:27:21 +00001299struct alias {
1300 struct alias *next;
1301 char *name;
1302 char *val;
1303 int flag;
1304};
1305
1306static struct alias *atab[ATABSIZE];
1307
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001308static void setalias(char *, char *);
1309static struct alias **hashalias(const char *);
1310static struct alias *freealias(struct alias *);
1311static struct alias **__lookupalias(const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00001312
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001313static void setalias(char *name, char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00001314{
1315 struct alias *ap, **app;
1316
1317 app = __lookupalias(name);
1318 ap = *app;
1319 INTOFF;
1320 if (ap) {
1321 if (!(ap->flag & ALIASINUSE)) {
Aaron Lehmann49c024a2002-08-02 06:39:47 +00001322 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00001323 }
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001324 ap->val = xstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00001325 ap->flag &= ~ALIASDEAD;
1326 } else {
1327 /* not found */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001328 ap = xmalloc(sizeof(struct alias));
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001329 ap->name = xstrdup(name);
1330 ap->val = xstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00001331 ap->flag = 0;
1332 ap->next = 0;
1333 *app = ap;
1334 }
1335 INTON;
1336}
1337
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001338static int unalias(char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00001339{
Eric Andersencb57d552001-06-28 07:25:16 +00001340 struct alias **app;
1341
1342 app = __lookupalias(name);
1343
1344 if (*app) {
1345 INTOFF;
1346 *app = freealias(*app);
1347 INTON;
1348 return (0);
1349 }
1350
1351 return (1);
1352}
1353
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001354static void rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00001355{
Eric Andersencb57d552001-06-28 07:25:16 +00001356 struct alias *ap, **app;
1357 int i;
1358
1359 INTOFF;
1360 for (i = 0; i < ATABSIZE; i++) {
1361 app = &atab[i];
1362 for (ap = *app; ap; ap = *app) {
1363 *app = freealias(*app);
1364 if (ap == *app) {
1365 app = &ap->next;
1366 }
1367 }
1368 }
1369 INTON;
1370}
1371
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001372static void printalias(const struct alias *ap)
1373{
Eric Andersen2870d962001-07-02 17:27:21 +00001374 char *p;
1375
1376 p = single_quote(ap->val);
Eric Andersen62483552001-07-10 06:09:16 +00001377 printf("alias %s=%s\n", ap->name, p);
Eric Andersen2870d962001-07-02 17:27:21 +00001378 stunalloc(p);
1379}
1380
Eric Andersencb57d552001-06-28 07:25:16 +00001381
1382/*
1383 * TODO - sort output
1384 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001385static int aliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001386{
1387 char *n, *v;
1388 int ret = 0;
1389 struct alias *ap;
1390
1391 if (argc == 1) {
1392 int i;
1393
1394 for (i = 0; i < ATABSIZE; i++)
1395 for (ap = atab[i]; ap; ap = ap->next) {
1396 printalias(ap);
1397 }
1398 return (0);
1399 }
1400 while ((n = *++argv) != NULL) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001401 if ((v = strchr(n + 1, '=')) == NULL) { /* n+1: funny ksh stuff */
Eric Andersencb57d552001-06-28 07:25:16 +00001402 if ((ap = *__lookupalias(n)) == NULL) {
Eric Andersen3102ac42001-07-06 04:26:23 +00001403 out2fmt("%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00001404 ret = 1;
1405 } else
1406 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001407 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00001408 *v++ = '\0';
1409 setalias(n, v);
1410 }
1411 }
1412
1413 return (ret);
1414}
1415
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001416static int unaliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001417{
1418 int i;
1419
1420 while ((i = nextopt("a")) != '\0') {
1421 if (i == 'a') {
1422 rmaliases();
1423 return (0);
1424 }
1425 }
1426 for (i = 0; *argptr; argptr++) {
1427 if (unalias(*argptr)) {
Eric Andersen3102ac42001-07-06 04:26:23 +00001428 out2fmt("%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00001429 i = 1;
1430 }
1431 }
1432
1433 return (i);
1434}
1435
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001436static struct alias **hashalias(const char *p)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001437{
Eric Andersencb57d552001-06-28 07:25:16 +00001438 unsigned int hashval;
1439
1440 hashval = *p << 4;
1441 while (*p)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001442 hashval += *p++;
Eric Andersencb57d552001-06-28 07:25:16 +00001443 return &atab[hashval % ATABSIZE];
1444}
1445
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001446static struct alias *freealias(struct alias *ap)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001447{
Eric Andersencb57d552001-06-28 07:25:16 +00001448 struct alias *next;
1449
1450 if (ap->flag & ALIASINUSE) {
1451 ap->flag |= ALIASDEAD;
1452 return ap;
1453 }
1454
1455 next = ap->next;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00001456 free(ap->name);
1457 free(ap->val);
1458 free(ap);
Eric Andersencb57d552001-06-28 07:25:16 +00001459 return next;
1460}
1461
Eric Andersencb57d552001-06-28 07:25:16 +00001462
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001463static struct alias **__lookupalias(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001464{
Eric Andersencb57d552001-06-28 07:25:16 +00001465 struct alias **app = hashalias(name);
1466
1467 for (; *app; app = &(*app)->next) {
1468 if (equal(name, (*app)->name)) {
1469 break;
1470 }
1471 }
1472
1473 return app;
1474}
Eric Andersen2870d962001-07-02 17:27:21 +00001475#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001476
Eric Andersend35c5df2002-01-09 15:37:36 +00001477#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersen74bcd162001-07-30 21:41:37 +00001478/* The generated file arith.c has been replaced with a custom hand
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001479 * written implementation written by Aaron Lehmann <aaronl@vitelus.com>.
1480 * This is now part of libbb, so that it can be used by all the shells
Eric Andersen74bcd162001-07-30 21:41:37 +00001481 * in busybox. */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001482static void expari(int);
Eric Andersencb57d552001-06-28 07:25:16 +00001483#endif
1484
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001485static char *trap[NSIG]; /* trap handler commands */
1486static char sigmode[NSIG - 1]; /* current value of signal */
1487static char gotsig[NSIG - 1]; /* indicates specified signal received */
1488static int pendingsigs; /* indicates some signal received */
Eric Andersen2870d962001-07-02 17:27:21 +00001489
Eric Andersencb57d552001-06-28 07:25:16 +00001490/*
1491 * This file was generated by the mkbuiltins program.
1492 */
1493
Eric Andersend35c5df2002-01-09 15:37:36 +00001494#ifdef CONFIG_ASH_JOB_CONTROL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001495static int bgcmd(int, char **);
1496static int fgcmd(int, char **);
1497static int killcmd(int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001498#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001499static int bltincmd(int, char **);
1500static int cdcmd(int, char **);
1501static int breakcmd(int, char **);
1502
Eric Andersend35c5df2002-01-09 15:37:36 +00001503#ifdef CONFIG_ASH_CMDCMD
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001504static int commandcmd(int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001505#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001506static int dotcmd(int, char **);
1507static int evalcmd(int, char **);
1508static int execcmd(int, char **);
1509static int exitcmd(int, char **);
1510static int exportcmd(int, char **);
1511static int histcmd(int, char **);
1512static int hashcmd(int, char **);
1513static int helpcmd(int, char **);
1514static int jobscmd(int, char **);
1515static int localcmd(int, char **);
1516static int pwdcmd(int, char **);
1517static int readcmd(int, char **);
1518static int returncmd(int, char **);
1519static int setcmd(int, char **);
1520static int setvarcmd(int, char **);
1521static int shiftcmd(int, char **);
1522static int trapcmd(int, char **);
1523static int umaskcmd(int, char **);
1524
Eric Andersend35c5df2002-01-09 15:37:36 +00001525#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001526static int aliascmd(int, char **);
1527static int unaliascmd(int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001528#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001529static int unsetcmd(int, char **);
1530static int waitcmd(int, char **);
1531static int ulimitcmd(int, char **);
1532static int timescmd(int, char **);
1533
Eric Andersend35c5df2002-01-09 15:37:36 +00001534#ifdef CONFIG_ASH_MATH_SUPPORT
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001535static int letcmd(int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001536#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001537static int typecmd(int, char **);
1538
Eric Andersend35c5df2002-01-09 15:37:36 +00001539#ifdef CONFIG_ASH_GETOPTS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001540static int getoptscmd(int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001541#endif
1542
Eric Andersen69a20f02001-10-31 10:40:37 +00001543#ifndef CONFIG_TRUE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001544static int true_main(int, char **);
Eric Andersen69a20f02001-10-31 10:40:37 +00001545#endif
1546#ifndef CONFIG_FALSE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001547static int false_main(int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001548#endif
1549
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001550static void setpwd(const char *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00001551
1552
1553#define BUILTIN_NOSPEC "0"
1554#define BUILTIN_SPECIAL "1"
1555#define BUILTIN_REGULAR "2"
1556#define BUILTIN_ASSIGN "4"
1557#define BUILTIN_SPEC_ASSG "5"
1558#define BUILTIN_REG_ASSG "6"
1559
1560#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1561#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1562#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
1563
1564struct builtincmd {
1565 const char *name;
1566 int (*const builtinfunc) (int, char **);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00001567 //unsigned flags;
Eric Andersen2870d962001-07-02 17:27:21 +00001568};
1569
Eric Andersencb57d552001-06-28 07:25:16 +00001570
1571/* It is CRUCIAL that this listing be kept in ascii order, otherwise
1572 * the binary search in find_builtin() will stop working. If you value
1573 * your kneecaps, you'll be sure to *make sure* that any changes made
1574 * to this array result in the listing remaining in ascii order. You
1575 * have been warned.
1576 */
1577static const struct builtincmd builtincmds[] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001578 {BUILTIN_SPECIAL ".", dotcmd}, /* first, see declare DOTCMD */
1579 {BUILTIN_SPECIAL ":", true_main},
Eric Andersend35c5df2002-01-09 15:37:36 +00001580#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001581 {BUILTIN_REG_ASSG "alias", aliascmd},
Eric Andersencb57d552001-06-28 07:25:16 +00001582#endif
Eric Andersend35c5df2002-01-09 15:37:36 +00001583#ifdef CONFIG_ASH_JOB_CONTROL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001584 {BUILTIN_REGULAR "bg", bgcmd},
Eric Andersen2870d962001-07-02 17:27:21 +00001585#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001586 {BUILTIN_SPECIAL "break", breakcmd},
1587 {BUILTIN_SPECIAL "builtin", bltincmd},
1588 {BUILTIN_REGULAR "cd", cdcmd},
1589 {BUILTIN_NOSPEC "chdir", cdcmd},
Eric Andersend35c5df2002-01-09 15:37:36 +00001590#ifdef CONFIG_ASH_CMDCMD
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001591 {BUILTIN_REGULAR "command", commandcmd},
Eric Andersen2870d962001-07-02 17:27:21 +00001592#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001593 {BUILTIN_SPECIAL "continue", breakcmd},
1594 {BUILTIN_SPECIAL "eval", evalcmd},
1595 {BUILTIN_SPECIAL "exec", execcmd},
1596 {BUILTIN_SPECIAL "exit", exitcmd},
1597 {BUILTIN_SPEC_ASSG "export", exportcmd},
1598 {BUILTIN_REGULAR "false", false_main},
1599 {BUILTIN_REGULAR "fc", histcmd},
Eric Andersend35c5df2002-01-09 15:37:36 +00001600#ifdef CONFIG_ASH_JOB_CONTROL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001601 {BUILTIN_REGULAR "fg", fgcmd},
Eric Andersen2870d962001-07-02 17:27:21 +00001602#endif
Eric Andersend35c5df2002-01-09 15:37:36 +00001603#ifdef CONFIG_ASH_GETOPTS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001604 {BUILTIN_REGULAR "getopts", getoptscmd},
Eric Andersen2870d962001-07-02 17:27:21 +00001605#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001606 {BUILTIN_NOSPEC "hash", hashcmd},
1607 {BUILTIN_NOSPEC "help", helpcmd},
1608 {BUILTIN_REGULAR "jobs", jobscmd},
Eric Andersend35c5df2002-01-09 15:37:36 +00001609#ifdef CONFIG_ASH_JOB_CONTROL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001610 {BUILTIN_REGULAR "kill", killcmd},
Eric Andersen2870d962001-07-02 17:27:21 +00001611#endif
Eric Andersend35c5df2002-01-09 15:37:36 +00001612#ifdef CONFIG_ASH_MATH_SUPPORT
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001613 {BUILTIN_REGULAR "let", letcmd},
Eric Andersencb57d552001-06-28 07:25:16 +00001614#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001615 {BUILTIN_ASSIGN "local", localcmd},
1616 {BUILTIN_NOSPEC "pwd", pwdcmd},
1617 {BUILTIN_REGULAR "read", readcmd},
1618 {BUILTIN_SPEC_ASSG "readonly", exportcmd},
1619 {BUILTIN_SPECIAL "return", returncmd},
1620 {BUILTIN_SPECIAL "set", setcmd},
1621 {BUILTIN_NOSPEC "setvar", setvarcmd},
1622 {BUILTIN_SPECIAL "shift", shiftcmd},
1623 {BUILTIN_SPECIAL "times", timescmd},
1624 {BUILTIN_SPECIAL "trap", trapcmd},
1625 {BUILTIN_REGULAR "true", true_main},
1626 {BUILTIN_NOSPEC "type", typecmd},
1627 {BUILTIN_NOSPEC "ulimit", ulimitcmd},
1628 {BUILTIN_REGULAR "umask", umaskcmd},
Eric Andersend35c5df2002-01-09 15:37:36 +00001629#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001630 {BUILTIN_REGULAR "unalias", unaliascmd},
Eric Andersen2870d962001-07-02 17:27:21 +00001631#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001632 {BUILTIN_SPECIAL "unset", unsetcmd},
1633 {BUILTIN_REGULAR "wait", waitcmd},
Eric Andersencb57d552001-06-28 07:25:16 +00001634};
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001635
Eric Andersencb57d552001-06-28 07:25:16 +00001636#define NUMBUILTINS (sizeof (builtincmds) / sizeof (struct builtincmd) )
1637
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001638#define DOTCMD &builtincmds[0]
Eric Andersen2870d962001-07-02 17:27:21 +00001639static struct builtincmd *BLTINCMD;
1640static struct builtincmd *EXECCMD;
1641static struct builtincmd *EVALCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00001642
Eric Andersen2870d962001-07-02 17:27:21 +00001643/* states */
Glenn L McGrath50812ff2002-08-23 13:14:48 +00001644#define JOBSTOPPED 1 /* all procs are stopped */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001645#define JOBDONE 2 /* all procs are completed */
Eric Andersencb57d552001-06-28 07:25:16 +00001646
Eric Andersen2870d962001-07-02 17:27:21 +00001647/*
1648 * A job structure contains information about a job. A job is either a
1649 * single process or a set of processes contained in a pipeline. In the
1650 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1651 * array of pids.
1652 */
Eric Andersencb57d552001-06-28 07:25:16 +00001653
Eric Andersen2870d962001-07-02 17:27:21 +00001654struct procstat {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001655 pid_t pid; /* process id */
1656 int status; /* status flags (defined above) */
1657 char *cmd; /* text of command being run */
Eric Andersen2870d962001-07-02 17:27:21 +00001658};
Eric Andersencb57d552001-06-28 07:25:16 +00001659
Eric Andersen2870d962001-07-02 17:27:21 +00001660
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001661static int job_warning; /* user was warned about stopped jobs */
Eric Andersen2870d962001-07-02 17:27:21 +00001662
Eric Andersend35c5df2002-01-09 15:37:36 +00001663#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen2870d962001-07-02 17:27:21 +00001664static void setjobctl(int enable);
1665#else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001666#define setjobctl(on) /* do nothing */
Eric Andersencb57d552001-06-28 07:25:16 +00001667#endif
1668
Eric Andersen2870d962001-07-02 17:27:21 +00001669
1670struct job {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001671 struct procstat ps0; /* status of process */
1672 struct procstat *ps; /* status or processes when more than one */
1673 short nprocs; /* number of processes */
1674 short pgrp; /* process group of this job */
1675 char state; /* true if job is finished */
1676 char used; /* true if this entry is in used */
1677 char changed; /* true if status has changed */
Eric Andersend35c5df2002-01-09 15:37:36 +00001678#ifdef CONFIG_ASH_JOB_CONTROL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001679 char jobctl; /* job running under job control */
Eric Andersen2870d962001-07-02 17:27:21 +00001680#endif
1681};
1682
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001683static struct job *jobtab; /* array of jobs */
1684static int njobs; /* size of array */
1685static int backgndpid = -1; /* pid of last background process */
1686
Eric Andersend35c5df2002-01-09 15:37:36 +00001687#ifdef CONFIG_ASH_JOB_CONTROL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001688static int initialpgrp; /* pgrp of shell on invocation */
1689static int curjob; /* current job */
Eric Andersen2870d962001-07-02 17:27:21 +00001690static int jobctl;
1691#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001692
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001693static struct job *makejob(const union node *, int);
1694static int forkshell(struct job *, const union node *, int);
1695static int waitforjob(struct job *);
Eric Andersen2870d962001-07-02 17:27:21 +00001696
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001697static int docd(char *, int);
1698static void getpwd(void);
Eric Andersen2870d962001-07-02 17:27:21 +00001699
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001700static char *padvance(const char **, const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001701
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001702static char nullstr[1]; /* zero length string */
1703static char *curdir = nullstr; /* current working directory */
Eric Andersen2870d962001-07-02 17:27:21 +00001704
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001705static int cdcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001706{
1707 const char *dest;
1708 const char *path;
1709 char *p;
1710 struct stat statb;
1711 int print = 0;
1712
1713 nextopt(nullstr);
1714 if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME")) == NULL)
1715 error("HOME not set");
1716 if (*dest == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00001717 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001718 if (dest[0] == '-' && dest[1] == '\0') {
1719 dest = bltinlookup("OLDPWD");
1720 if (!dest || !*dest) {
1721 dest = curdir;
1722 }
1723 print = 1;
1724 if (dest)
Eric Andersen2870d962001-07-02 17:27:21 +00001725 print = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00001726 else
Eric Andersen2870d962001-07-02 17:27:21 +00001727 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001728 }
1729 if (*dest == '/' || (path = bltinlookup("CDPATH")) == NULL)
1730 path = nullstr;
1731 while ((p = padvance(&path, dest)) != NULL) {
1732 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
1733 if (!print) {
1734 /*
1735 * XXX - rethink
1736 */
1737 if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
1738 p += 2;
1739 print = strcmp(p, dest);
1740 }
1741 if (docd(p, print) >= 0)
1742 return 0;
1743
1744 }
1745 }
1746 error("can't cd to %s", dest);
1747 /* NOTREACHED */
1748}
1749
1750
1751/*
Glenn L McGrath50812ff2002-08-23 13:14:48 +00001752 * Update curdir (the name of the current directory) in response to a
1753 * cd command. We also call hashcd to let the routines in exec.c know
1754 * that the current directory has changed.
1755 */
1756
1757static void hashcd(void);
1758
1759static inline void updatepwd(const char *dir)
1760{
1761 hashcd(); /* update command hash table */
1762
1763 /*
1764 * If our argument is NULL, we don't know the current directory
1765 */
1766 if (dir == NULL || curdir == nullstr) {
1767 setpwd(0, 1);
1768 } else {
1769 setpwd(dir, 1);
1770 }
1771}
1772
1773/*
Eric Andersencb57d552001-06-28 07:25:16 +00001774 * Actually do the chdir. In an interactive shell, print the
1775 * directory name if "print" is nonzero.
1776 */
1777
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001778static int docd(char *dest, int print)
Eric Andersencb57d552001-06-28 07:25:16 +00001779{
Eric Andersencb57d552001-06-28 07:25:16 +00001780 TRACE(("docd(\"%s\", %d) called\n", dest, print));
Eric Andersencb57d552001-06-28 07:25:16 +00001781 INTOFF;
1782 if (chdir(dest) < 0) {
1783 INTON;
1784 return -1;
1785 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00001786 updatepwd(dest);
Eric Andersencb57d552001-06-28 07:25:16 +00001787 INTON;
1788 if (print && iflag)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001789 puts(curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00001790 return 0;
1791}
1792
1793
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001794static int pwdcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001795{
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001796 puts(curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00001797 return 0;
1798}
Eric Andersencb57d552001-06-28 07:25:16 +00001799
Eric Andersena3483db2001-10-24 08:01:06 +00001800/* Ask system the current directory */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001801static void getpwd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00001802{
Eric Andersen2870d962001-07-02 17:27:21 +00001803 curdir = xgetcwd(0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001804 if (curdir == 0)
Eric Andersen2870d962001-07-02 17:27:21 +00001805 curdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00001806}
1807
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001808static void setpwd(const char *val, int setold)
Eric Andersencb57d552001-06-28 07:25:16 +00001809{
Eric Andersena3483db2001-10-24 08:01:06 +00001810 char *cated = NULL;
1811
Eric Andersencb57d552001-06-28 07:25:16 +00001812 if (setold) {
1813 setvar("OLDPWD", curdir, VEXPORT);
1814 }
1815 INTOFF;
1816 if (curdir != nullstr) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001817 if (val != NULL && *val != '/')
Eric Andersena3483db2001-10-24 08:01:06 +00001818 val = cated = concat_path_file(curdir, val);
Eric Andersencb57d552001-06-28 07:25:16 +00001819 free(curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00001820 }
Eric Andersena3483db2001-10-24 08:01:06 +00001821 if (!val)
Eric Andersencb57d552001-06-28 07:25:16 +00001822 getpwd();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001823 else
Eric Andersena3483db2001-10-24 08:01:06 +00001824 curdir = simplify_path(val);
1825 free(cated);
Eric Andersencb57d552001-06-28 07:25:16 +00001826 INTON;
1827 setvar("PWD", curdir, VEXPORT);
1828}
1829
Eric Andersencb57d552001-06-28 07:25:16 +00001830/*
1831 * Errors and exceptions.
1832 */
1833
1834/*
1835 * Code to handle exceptions in C.
1836 */
1837
Eric Andersen2870d962001-07-02 17:27:21 +00001838/*
1839 * We enclose jmp_buf in a structure so that we can declare pointers to
1840 * jump locations. The global variable handler contains the location to
1841 * jump to when an exception occurs, and the global variable exception
1842 * contains a code identifying the exeception. To implement nested
1843 * exception handlers, the user should save the value of handler on entry
1844 * to an inner scope, set handler to point to a jmploc structure for the
1845 * inner scope, and restore handler on exit from the scope.
1846 */
1847
1848struct jmploc {
1849 jmp_buf loc;
1850};
1851
1852/* exceptions */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001853#define EXINT 0 /* SIGINT received */
1854#define EXERROR 1 /* a generic error */
1855#define EXSHELLPROC 2 /* execute a shell procedure */
1856#define EXEXEC 3 /* command execution failed */
Glenn L McGrath50812ff2002-08-23 13:14:48 +00001857#define EXREDIR 4 /* redirection error */
Eric Andersen2870d962001-07-02 17:27:21 +00001858
1859static struct jmploc *handler;
Eric Andersencb57d552001-06-28 07:25:16 +00001860static int exception;
Eric Andersencb57d552001-06-28 07:25:16 +00001861
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001862static void exverror(int, const char *, va_list)
1863 __attribute__ ((__noreturn__));
Eric Andersencb57d552001-06-28 07:25:16 +00001864
1865/*
1866 * Called to raise an exception. Since C doesn't include exceptions, we
1867 * just do a longjmp to the exception handler. The type of exception is
1868 * stored in the global variable "exception".
1869 */
1870
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001871static void exraise(int) __attribute__ ((__noreturn__));
Eric Andersen2870d962001-07-02 17:27:21 +00001872
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001873static void exraise(int e)
Eric Andersencb57d552001-06-28 07:25:16 +00001874{
1875#ifdef DEBUG
1876 if (handler == NULL)
1877 abort();
1878#endif
Eric Andersen62483552001-07-10 06:09:16 +00001879 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00001880 exception = e;
1881 longjmp(handler->loc, 1);
1882}
1883
1884
1885/*
1886 * Called from trap.c when a SIGINT is received. (If the user specifies
1887 * that SIGINT is to be trapped or ignored using the trap builtin, then
1888 * this routine is not called.) Suppressint is nonzero when interrupts
1889 * are held using the INTOFF macro. The call to _exit is necessary because
1890 * there is a short period after a fork before the signal handlers are
1891 * set to the appropriate value for the child. (The test for iflag is
1892 * just defensive programming.)
1893 */
1894
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001895static void onint(void)
1896{
Eric Andersencb57d552001-06-28 07:25:16 +00001897 sigset_t mysigset;
1898
1899 if (suppressint) {
1900 intpending++;
1901 return;
1902 }
1903 intpending = 0;
1904 sigemptyset(&mysigset);
1905 sigprocmask(SIG_SETMASK, &mysigset, NULL);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00001906 if (!(rootshell && iflag)) {
Eric Andersencb57d552001-06-28 07:25:16 +00001907 signal(SIGINT, SIG_DFL);
1908 raise(SIGINT);
1909 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00001910 exraise(EXINT);
Eric Andersencb57d552001-06-28 07:25:16 +00001911 /* NOTREACHED */
1912}
1913
1914
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001915static char *commandname; /* currently executing command */
Eric Andersen2870d962001-07-02 17:27:21 +00001916
Eric Andersencb57d552001-06-28 07:25:16 +00001917/*
1918 * Exverror is called to raise the error exception. If the first argument
1919 * is not NULL then error prints an error message using printf style
1920 * formatting. It then raises the error exception.
1921 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001922static void exverror(int cond, const char *msg, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00001923{
1924 CLEAR_PENDING_INT;
1925 INTOFF;
1926
1927#ifdef DEBUG
1928 if (msg)
1929 TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
1930 else
1931 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
1932#endif
1933 if (msg) {
1934 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +00001935 out2fmt("%s: ", commandname);
1936 vfprintf(stderr, msg, ap);
1937 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00001938 }
Eric Andersencb57d552001-06-28 07:25:16 +00001939 exraise(cond);
1940 /* NOTREACHED */
1941}
1942
1943
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001944static void error(const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00001945{
Eric Andersencb57d552001-06-28 07:25:16 +00001946 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001947
Eric Andersencb57d552001-06-28 07:25:16 +00001948 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00001949 exverror(EXERROR, msg, ap);
1950 /* NOTREACHED */
1951 va_end(ap);
1952}
1953
1954
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001955static void exerror(int cond, const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00001956{
Eric Andersencb57d552001-06-28 07:25:16 +00001957 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001958
Eric Andersencb57d552001-06-28 07:25:16 +00001959 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00001960 exverror(cond, msg, ap);
1961 /* NOTREACHED */
1962 va_end(ap);
1963}
1964
1965
1966
1967/*
1968 * Table of error messages.
1969 */
1970
1971struct errname {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001972 short errcode; /* error number */
1973 short action; /* operation which encountered the error */
Eric Andersencb57d552001-06-28 07:25:16 +00001974};
1975
Eric Andersen2870d962001-07-02 17:27:21 +00001976/*
1977 * Types of operations (passed to the errmsg routine).
1978 */
1979
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001980#define E_OPEN 01 /* opening a file */
1981#define E_CREAT 02 /* creating a file */
1982#define E_EXEC 04 /* executing a program */
Eric Andersencb57d552001-06-28 07:25:16 +00001983
1984#define ALL (E_OPEN|E_CREAT|E_EXEC)
1985
1986static const struct errname errormsg[] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001987 {EINTR, ALL},
1988 {EACCES, ALL},
1989 {EIO, ALL},
1990 {ENOENT, E_OPEN},
1991 {ENOENT, E_CREAT},
1992 {ENOENT, E_EXEC},
1993 {ENOTDIR, E_OPEN},
1994 {ENOTDIR, E_CREAT},
1995 {ENOTDIR, E_EXEC},
1996 {EISDIR, ALL},
1997 {EEXIST, E_CREAT},
Eric Andersen2870d962001-07-02 17:27:21 +00001998#ifdef EMFILE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001999 {EMFILE, ALL},
Eric Andersencb57d552001-06-28 07:25:16 +00002000#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002001 {ENFILE, ALL},
2002 {ENOSPC, ALL},
Eric Andersencb57d552001-06-28 07:25:16 +00002003#ifdef EDQUOT
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002004 {EDQUOT, ALL},
Eric Andersencb57d552001-06-28 07:25:16 +00002005#endif
2006#ifdef ENOSR
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002007 {ENOSR, ALL},
Eric Andersencb57d552001-06-28 07:25:16 +00002008#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002009 {ENXIO, ALL},
2010 {EROFS, ALL},
2011 {ETXTBSY, ALL},
Eric Andersen2870d962001-07-02 17:27:21 +00002012#ifdef EAGAIN
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002013 {EAGAIN, E_EXEC},
Eric Andersencb57d552001-06-28 07:25:16 +00002014#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002015 {ENOMEM, ALL},
Eric Andersencb57d552001-06-28 07:25:16 +00002016#ifdef ENOLINK
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002017 {ENOLINK, ALL},
Eric Andersencb57d552001-06-28 07:25:16 +00002018#endif
2019#ifdef EMULTIHOP
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002020 {EMULTIHOP, ALL},
Eric Andersencb57d552001-06-28 07:25:16 +00002021#endif
2022#ifdef ECOMM
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002023 {ECOMM, ALL},
Eric Andersencb57d552001-06-28 07:25:16 +00002024#endif
2025#ifdef ESTALE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002026 {ESTALE, ALL},
Eric Andersencb57d552001-06-28 07:25:16 +00002027#endif
2028#ifdef ETIMEDOUT
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002029 {ETIMEDOUT, ALL},
Eric Andersencb57d552001-06-28 07:25:16 +00002030#endif
2031#ifdef ELOOP
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002032 {ELOOP, ALL},
Eric Andersencb57d552001-06-28 07:25:16 +00002033#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002034 {E2BIG, E_EXEC},
Eric Andersencb57d552001-06-28 07:25:16 +00002035#ifdef ELIBACC
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002036 {ELIBACC, E_EXEC},
Eric Andersencb57d552001-06-28 07:25:16 +00002037#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002038};
2039
Eric Andersen2870d962001-07-02 17:27:21 +00002040#define ERRNAME_SIZE (sizeof(errormsg)/sizeof(struct errname))
Eric Andersencb57d552001-06-28 07:25:16 +00002041
2042/*
2043 * Return a string describing an error. The returned string may be a
2044 * pointer to a static buffer that will be overwritten on the next call.
2045 * Action describes the operation that got the error.
2046 */
2047
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002048static const char *errmsg(int e, int action)
Eric Andersencb57d552001-06-28 07:25:16 +00002049{
2050 struct errname const *ep;
2051 static char buf[12];
2052
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002053 for (ep = errormsg; ep < errormsg + ERRNAME_SIZE; ep++) {
Eric Andersencb57d552001-06-28 07:25:16 +00002054 if (ep->errcode == e && (ep->action & action) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00002055 return strerror(e);
Eric Andersencb57d552001-06-28 07:25:16 +00002056 }
Eric Andersen2870d962001-07-02 17:27:21 +00002057
Eric Andersen3102ac42001-07-06 04:26:23 +00002058 snprintf(buf, sizeof buf, "error %d", e);
Eric Andersencb57d552001-06-28 07:25:16 +00002059 return buf;
2060}
2061
2062
Eric Andersend35c5df2002-01-09 15:37:36 +00002063#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002064static void __inton()
2065{
Eric Andersencb57d552001-06-28 07:25:16 +00002066 if (--suppressint == 0 && intpending) {
2067 onint();
2068 }
2069}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002070static void forceinton(void)
2071{
Eric Andersen3102ac42001-07-06 04:26:23 +00002072 suppressint = 0;
2073 if (intpending)
2074 onint();
2075}
Eric Andersencb57d552001-06-28 07:25:16 +00002076#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002077
2078/* flags in argument to evaltree */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002079#define EV_EXIT 01 /* exit after evaluating tree */
2080#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2081#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00002082
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002083static int evalskip; /* set if we are skipping commands */
2084static int skipcount; /* number of levels to skip */
2085static int loopnest; /* current loop nesting level */
2086static int funcnest; /* depth of function calls */
Eric Andersencb57d552001-06-28 07:25:16 +00002087
2088
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002089static struct strlist *cmdenviron; /* environment for builtin command */
2090static int exitstatus; /* exit status of last command */
2091static int oexitstatus; /* saved exit status */
Eric Andersencb57d552001-06-28 07:25:16 +00002092
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002093static void evalsubshell(const union node *, int);
2094static void expredir(union node *);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002095static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002096static void eprintlist(struct strlist *);
Eric Andersencb57d552001-06-28 07:25:16 +00002097
Eric Andersen2870d962001-07-02 17:27:21 +00002098static union node *parsecmd(int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002099
Eric Andersencb57d552001-06-28 07:25:16 +00002100/*
2101 * Called to reset things after an exception.
2102 */
2103
Eric Andersencb57d552001-06-28 07:25:16 +00002104/*
2105 * The eval commmand.
2106 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002107static void evalstring(char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00002108
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002109static int evalcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002110{
Eric Andersen2870d962001-07-02 17:27:21 +00002111 char *p;
2112 char *concat;
2113 char **ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002114
Eric Andersen2870d962001-07-02 17:27:21 +00002115 if (argc > 1) {
2116 p = argv[1];
2117 if (argc > 2) {
2118 STARTSTACKSTR(concat);
2119 ap = argv + 2;
2120 for (;;) {
2121 while (*p)
2122 STPUTC(*p++, concat);
2123 if ((p = *ap++) == NULL)
2124 break;
2125 STPUTC(' ', concat);
2126 }
2127 STPUTC('\0', concat);
2128 p = grabstackstr(concat);
2129 }
2130 evalstring(p, EV_TESTED);
2131 }
2132 return exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002133}
2134
Eric Andersencb57d552001-06-28 07:25:16 +00002135/*
2136 * Execute a command or commands contained in a string.
2137 */
2138
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002139static void evaltree(union node *, int);
2140static void setinputstring(char *);
2141static void popfile(void);
Eric Andersen2870d962001-07-02 17:27:21 +00002142static void setstackmark(struct stackmark *mark);
2143static void popstackmark(struct stackmark *mark);
2144
2145
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002146static void evalstring(char *s, int flag)
Eric Andersen2870d962001-07-02 17:27:21 +00002147{
Eric Andersencb57d552001-06-28 07:25:16 +00002148 union node *n;
2149 struct stackmark smark;
2150
2151 setstackmark(&smark);
2152 setinputstring(s);
2153 while ((n = parsecmd(0)) != NEOF) {
2154 evaltree(n, flag);
2155 popstackmark(&smark);
2156 }
2157 popfile();
2158 popstackmark(&smark);
2159}
2160
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002161static struct builtincmd *find_builtin(const char *);
2162static void expandarg(union node *, struct arglist *, int);
2163static void calcsize(const union node *);
2164static union node *copynode(const union node *);
Eric Andersen62483552001-07-10 06:09:16 +00002165
2166/*
2167 * Make a copy of a parse tree.
2168 */
2169
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002170static int funcblocksize; /* size of structures in function */
2171static int funcstringsize; /* size of strings in node */
2172static pointer funcblock; /* block to allocate function from */
2173static char *funcstring; /* block to allocate strings from */
Eric Andersen62483552001-07-10 06:09:16 +00002174
2175
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002176static inline union node *copyfunc(union node *n)
Eric Andersen62483552001-07-10 06:09:16 +00002177{
2178 if (n == NULL)
2179 return NULL;
2180 funcblocksize = 0;
2181 funcstringsize = 0;
2182 calcsize(n);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00002183 funcblock = xmalloc(funcblocksize + funcstringsize);
Eric Andersen62483552001-07-10 06:09:16 +00002184 funcstring = (char *) funcblock + funcblocksize;
2185 return copynode(n);
2186}
2187
2188/*
Eric Andersen62483552001-07-10 06:09:16 +00002189 * Add a new command entry, replacing any existing command entry for
2190 * the same name.
2191 */
2192
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002193static inline void addcmdentry(char *name, struct cmdentry *entry)
Eric Andersen62483552001-07-10 06:09:16 +00002194{
2195 struct tblentry *cmdp;
2196
2197 INTOFF;
2198 cmdp = cmdlookup(name, 1);
2199 if (cmdp->cmdtype == CMDFUNCTION) {
Aaron Lehmann49c024a2002-08-02 06:39:47 +00002200 free(cmdp->param.func);
Eric Andersen62483552001-07-10 06:09:16 +00002201 }
2202 cmdp->cmdtype = entry->cmdtype;
2203 cmdp->param = entry->u;
2204 INTON;
2205}
2206
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002207static inline void evalloop(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002208{
2209 int status;
2210
2211 loopnest++;
2212 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002213 flags &= EV_TESTED;
Eric Andersencb57d552001-06-28 07:25:16 +00002214 for (;;) {
2215 evaltree(n->nbinary.ch1, EV_TESTED);
2216 if (evalskip) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002217 skipping:if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002218 evalskip = 0;
2219 continue;
2220 }
2221 if (evalskip == SKIPBREAK && --skipcount <= 0)
2222 evalskip = 0;
2223 break;
2224 }
2225 if (n->type == NWHILE) {
2226 if (exitstatus != 0)
2227 break;
2228 } else {
2229 if (exitstatus == 0)
2230 break;
2231 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002232 evaltree(n->nbinary.ch2, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002233 status = exitstatus;
2234 if (evalskip)
2235 goto skipping;
2236 }
2237 loopnest--;
2238 exitstatus = status;
2239}
2240
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002241static void evalfor(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002242{
2243 struct arglist arglist;
2244 union node *argp;
2245 struct strlist *sp;
2246 struct stackmark smark;
2247
2248 setstackmark(&smark);
2249 arglist.lastp = &arglist.list;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002250 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002251 oexitstatus = exitstatus;
2252 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2253 if (evalskip)
2254 goto out;
2255 }
2256 *arglist.lastp = NULL;
2257
2258 exitstatus = 0;
2259 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002260 flags &= EV_TESTED;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002261 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002262 setvar(n->nfor.var, sp->text, 0);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002263 evaltree(n->nfor.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002264 if (evalskip) {
2265 if (evalskip == SKIPCONT && --skipcount <= 0) {
2266 evalskip = 0;
2267 continue;
2268 }
2269 if (evalskip == SKIPBREAK && --skipcount <= 0)
2270 evalskip = 0;
2271 break;
2272 }
2273 }
2274 loopnest--;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002275 out:
Eric Andersencb57d552001-06-28 07:25:16 +00002276 popstackmark(&smark);
2277}
2278
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002279static inline void evalcase(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002280{
2281 union node *cp;
2282 union node *patp;
2283 struct arglist arglist;
2284 struct stackmark smark;
2285
2286 setstackmark(&smark);
2287 arglist.lastp = &arglist.list;
2288 oexitstatus = exitstatus;
2289 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002290 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
2291 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002292 if (casematch(patp, arglist.list->text)) {
2293 if (evalskip == 0) {
2294 evaltree(cp->nclist.body, flags);
2295 }
2296 goto out;
2297 }
2298 }
2299 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002300 out:
Eric Andersencb57d552001-06-28 07:25:16 +00002301 popstackmark(&smark);
2302}
2303
Eric Andersencb57d552001-06-28 07:25:16 +00002304/*
Eric Andersencb57d552001-06-28 07:25:16 +00002305 * Evaluate a pipeline. All the processes in the pipeline are children
2306 * of the process creating the pipeline. (This differs from some versions
2307 * of the shell, which make the last process in a pipeline the parent
2308 * of all the rest.)
2309 */
2310
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002311static inline void evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002312{
2313 struct job *jp;
2314 struct nodelist *lp;
2315 int pipelen;
2316 int prevfd;
2317 int pip[2];
2318
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002319 TRACE(("evalpipe(0x%lx) called\n", (long) n));
Eric Andersencb57d552001-06-28 07:25:16 +00002320 pipelen = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002321 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00002322 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002323 flags |= EV_EXIT;
Eric Andersencb57d552001-06-28 07:25:16 +00002324 INTOFF;
2325 jp = makejob(n, pipelen);
2326 prevfd = -1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002327 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002328 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00002329 pip[1] = -1;
2330 if (lp->next) {
2331 if (pipe(pip) < 0) {
2332 close(prevfd);
2333 error("Pipe call failed");
2334 }
2335 }
2336 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
2337 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00002338 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002339 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00002340 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002341 if (prevfd > 0) {
2342 dup2(prevfd, 0);
2343 close(prevfd);
2344 }
2345 if (pip[1] > 1) {
2346 dup2(pip[1], 1);
2347 close(pip[1]);
2348 }
2349 evaltree(lp->n, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002350 }
2351 if (prevfd >= 0)
2352 close(prevfd);
2353 prevfd = pip[0];
2354 close(pip[1]);
2355 }
Eric Andersencb57d552001-06-28 07:25:16 +00002356 if (n->npipe.backgnd == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002357 exitstatus = waitforjob(jp);
2358 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
Eric Andersencb57d552001-06-28 07:25:16 +00002359 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002360 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00002361}
2362
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002363static void find_command(const char *, struct cmdentry *, int, const char *);
2364
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002365static int isassignment(const char *word)
2366{
Eric Andersen2870d962001-07-02 17:27:21 +00002367 if (!is_name(*word)) {
2368 return 0;
2369 }
2370 do {
2371 word++;
2372 } while (is_in_name(*word));
2373 return *word == '=';
2374}
2375
Eric Andersen62483552001-07-10 06:09:16 +00002376
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002377static void evalcommand(union node *cmd, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002378{
2379 struct stackmark smark;
2380 union node *argp;
2381 struct arglist arglist;
2382 struct arglist varlist;
2383 char **argv;
2384 int argc;
2385 char **envp;
2386 struct strlist *sp;
2387 int mode;
Eric Andersencb57d552001-06-28 07:25:16 +00002388 struct cmdentry cmdentry;
2389 struct job *jp;
2390 char *volatile savecmdname;
2391 volatile struct shparam saveparam;
2392 struct localvar *volatile savelocalvars;
2393 volatile int e;
2394 char *lastarg;
2395 const char *path;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002396 int spclbltin;
Eric Andersencb57d552001-06-28 07:25:16 +00002397 struct jmploc *volatile savehandler;
2398 struct jmploc jmploc;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002399
Eric Andersencb57d552001-06-28 07:25:16 +00002400#if __GNUC__
2401 /* Avoid longjmp clobbering */
2402 (void) &argv;
2403 (void) &argc;
2404 (void) &lastarg;
2405 (void) &flags;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002406 (void) &spclbltin;
Eric Andersencb57d552001-06-28 07:25:16 +00002407#endif
2408
2409 /* First expand the arguments. */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002410 TRACE(("evalcommand(0x%lx, %d) called\n", (long) cmd, flags));
Eric Andersencb57d552001-06-28 07:25:16 +00002411 setstackmark(&smark);
2412 arglist.lastp = &arglist.list;
2413 varlist.lastp = &varlist.list;
2414 arglist.list = 0;
2415 oexitstatus = exitstatus;
2416 exitstatus = 0;
2417 path = pathval();
2418 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
2419 expandarg(argp, &varlist, EXP_VARTILDE);
2420 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002421 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002422 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2423 }
Eric Andersencb57d552001-06-28 07:25:16 +00002424 *arglist.lastp = NULL;
2425 *varlist.lastp = NULL;
2426 expredir(cmd->ncmd.redirect);
2427 argc = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002428 for (sp = arglist.list; sp; sp = sp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00002429 argc++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002430 argv = stalloc(sizeof(char *) * (argc + 1));
Eric Andersencb57d552001-06-28 07:25:16 +00002431
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002432 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002433 TRACE(("evalcommand arg: %s\n", sp->text));
2434 *argv++ = sp->text;
2435 }
2436 *argv = NULL;
2437 lastarg = NULL;
2438 if (iflag && funcnest == 0 && argc > 0)
2439 lastarg = argv[-1];
2440 argv -= argc;
2441
2442 /* Print the command if xflag is set. */
2443 if (xflag) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002444 out2c('+');
Eric Andersencb57d552001-06-28 07:25:16 +00002445 eprintlist(varlist.list);
2446 eprintlist(arglist.list);
Eric Andersen3102ac42001-07-06 04:26:23 +00002447 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00002448 }
2449
2450 /* Now locate the command. */
2451 if (argc == 0) {
2452 cmdentry.cmdtype = CMDBUILTIN;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002453 cmdentry.u.cmd = BLTINCMD;
2454 spclbltin = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00002455 } else {
2456 const char *oldpath;
2457 int findflag = DO_ERR;
2458 int oldfindflag;
2459
2460 /*
2461 * Modify the command lookup path, if a PATH= assignment
2462 * is present
2463 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002464 for (sp = varlist.list; sp; sp = sp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00002465 if (varequal(sp->text, defpathvar)) {
2466 path = sp->text + 5;
2467 findflag |= DO_BRUTE;
2468 }
2469 oldpath = path;
2470 oldfindflag = findflag;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002471 spclbltin = -1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002472 for (;;) {
Eric Andersencb57d552001-06-28 07:25:16 +00002473 find_command(argv[0], &cmdentry, findflag, path);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002474 if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */
Eric Andersencb57d552001-06-28 07:25:16 +00002475 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002476 goto out;
2477 }
2478 /* implement bltin and command here */
2479 if (cmdentry.cmdtype != CMDBUILTIN) {
2480 break;
2481 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002482 if (spclbltin < 0) {
2483 spclbltin = !!(IS_BUILTIN_SPECIAL(cmdentry.u.cmd)) * 2;
Eric Andersencb57d552001-06-28 07:25:16 +00002484 }
2485 if (cmdentry.u.cmd == BLTINCMD) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002486 for (;;) {
Eric Andersencb57d552001-06-28 07:25:16 +00002487 struct builtincmd *bcmd;
2488
2489 argv++;
2490 if (--argc == 0)
2491 goto found;
2492 if (!(bcmd = find_builtin(*argv))) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002493 out2fmt("%s: not found\n", *argv);
Eric Andersencb57d552001-06-28 07:25:16 +00002494 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002495 goto out;
2496 }
2497 cmdentry.u.cmd = bcmd;
2498 if (bcmd != BLTINCMD)
2499 break;
2500 }
2501 }
Eric Andersen2870d962001-07-02 17:27:21 +00002502 if (cmdentry.u.cmd == find_builtin("command")) {
Eric Andersencb57d552001-06-28 07:25:16 +00002503 argv++;
2504 if (--argc == 0) {
2505 goto found;
2506 }
2507 if (*argv[0] == '-') {
2508 if (!equal(argv[0], "-p")) {
2509 argv--;
2510 argc++;
2511 break;
2512 }
2513 argv++;
2514 if (--argc == 0) {
2515 goto found;
2516 }
2517 path = defpath;
2518 findflag |= DO_BRUTE;
2519 } else {
2520 path = oldpath;
2521 findflag = oldfindflag;
2522 }
2523 findflag |= DO_NOFUN;
2524 continue;
2525 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002526 found:
Eric Andersencb57d552001-06-28 07:25:16 +00002527 break;
2528 }
2529 }
2530
2531 /* Fork off a child process if necessary. */
2532 if (cmd->ncmd.backgnd
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002533 || (cmdentry.cmdtype == CMDNORMAL && (!(flags & EV_EXIT) || trap[0]))
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002534 ) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002535 INTOFF;
Eric Andersencb57d552001-06-28 07:25:16 +00002536 jp = makejob(cmd, 1);
2537 mode = cmd->ncmd.backgnd;
Eric Andersencb57d552001-06-28 07:25:16 +00002538 if (forkshell(jp, cmd, mode) != 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002539 goto parent; /* at end of routine */
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002540 FORCEINTON;
Eric Andersencb57d552001-06-28 07:25:16 +00002541 flags |= EV_EXIT;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002542 } else {
2543 flags &= ~EV_EXIT;
Eric Andersencb57d552001-06-28 07:25:16 +00002544 }
2545
2546 /* This is the child process if a fork occurred. */
2547 /* Execute the command. */
2548 if (cmdentry.cmdtype == CMDFUNCTION) {
2549#ifdef DEBUG
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002550 trputs("Shell function: ");
2551 trargs(argv);
Eric Andersencb57d552001-06-28 07:25:16 +00002552#endif
2553 exitstatus = oexitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002554 saveparam = shellparam;
2555 shellparam.malloc = 0;
2556 shellparam.nparam = argc - 1;
2557 shellparam.p = argv + 1;
2558 INTOFF;
2559 savelocalvars = localvars;
2560 localvars = NULL;
2561 INTON;
2562 if (setjmp(jmploc.loc)) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002563 if (exception == EXREDIR) {
2564 exitstatus = 2;
2565 goto funcdone;
Eric Andersencb57d552001-06-28 07:25:16 +00002566 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002567 saveparam.optind = shellparam.optind;
2568 saveparam.optoff = shellparam.optoff;
2569 freeparam(&shellparam);
2570 shellparam = saveparam;
Eric Andersencb57d552001-06-28 07:25:16 +00002571 poplocalvars();
2572 localvars = savelocalvars;
2573 handler = savehandler;
2574 longjmp(handler->loc, 1);
2575 }
2576 savehandler = handler;
2577 handler = &jmploc;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002578 redirect(cmd->ncmd.redirect, REDIR_PUSH);
2579 listsetvar(varlist.list);
Eric Andersencb57d552001-06-28 07:25:16 +00002580 funcnest++;
2581 evaltree(cmdentry.u.func, flags & EV_TESTED);
2582 funcnest--;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002583 funcdone:
Eric Andersencb57d552001-06-28 07:25:16 +00002584 INTOFF;
2585 poplocalvars();
2586 localvars = savelocalvars;
2587 saveparam.optind = shellparam.optind;
2588 saveparam.optoff = shellparam.optoff;
2589 freeparam(&shellparam);
2590 shellparam = saveparam;
2591 handler = savehandler;
2592 popredir();
2593 INTON;
2594 if (evalskip == SKIPFUNC) {
2595 evalskip = 0;
2596 skipcount = 0;
2597 }
Eric Andersencb57d552001-06-28 07:25:16 +00002598 } else if (cmdentry.cmdtype == CMDBUILTIN) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002599 int redir;
2600
Eric Andersencb57d552001-06-28 07:25:16 +00002601#ifdef DEBUG
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002602 trputs("builtin command: ");
2603 trargs(argv);
Eric Andersencb57d552001-06-28 07:25:16 +00002604#endif
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002605 redir = (cmdentry.u.cmd == EXECCMD) ? 0 : REDIR_PUSH;
Eric Andersencb57d552001-06-28 07:25:16 +00002606 savecmdname = commandname;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002607 if (spclbltin) {
Eric Andersencb57d552001-06-28 07:25:16 +00002608 listsetvar(varlist.list);
2609 } else {
2610 cmdenviron = varlist.list;
2611 }
2612 e = -1;
2613 if (setjmp(jmploc.loc)) {
2614 e = exception;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002615 exitstatus = (e == EXINT) ? SIGINT + 128 : 2;
Eric Andersencb57d552001-06-28 07:25:16 +00002616 goto cmddone;
2617 }
2618 savehandler = handler;
2619 handler = &jmploc;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002620 redirect(cmd->ncmd.redirect, redir);
Eric Andersencb57d552001-06-28 07:25:16 +00002621 commandname = argv[0];
2622 argptr = argv + 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002623 optptr = NULL; /* initialize nextopt */
2624 exitstatus = (*cmdentry.u.cmd->builtinfunc) (argc, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00002625 flushall();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002626 cmddone:
Eric Andersencb57d552001-06-28 07:25:16 +00002627 cmdenviron = NULL;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002628 commandname = savecmdname;
Eric Andersencb57d552001-06-28 07:25:16 +00002629 handler = savehandler;
2630 if (e != -1) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002631 if (e == EXINT || spclbltin & 2) {
2632 if (e == EXREDIR)
2633 exraise(e);
2634 }
Eric Andersencb57d552001-06-28 07:25:16 +00002635 FORCEINTON;
2636 }
2637 if (cmdentry.u.cmd != EXECCMD)
2638 popredir();
Eric Andersencb57d552001-06-28 07:25:16 +00002639 } else {
2640#ifdef DEBUG
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002641 trputs("normal command: ");
2642 trargs(argv);
Eric Andersencb57d552001-06-28 07:25:16 +00002643#endif
2644 redirect(cmd->ncmd.redirect, 0);
2645 clearredir();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002646 for (sp = varlist.list; sp; sp = sp->next)
2647 setvareq(sp->text, VEXPORT | VSTACK);
Eric Andersencb57d552001-06-28 07:25:16 +00002648 envp = environment();
2649 shellexec(argv, envp, path, cmdentry.u.index);
2650 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002651 if (flags & EV_EXIT)
2652 exitshell(exitstatus);
Eric Andersencb57d552001-06-28 07:25:16 +00002653 goto out;
2654
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002655 parent: /* parent process gets here (if we forked) */
2656 if (mode == 0) { /* argument to fork */
Eric Andersencb57d552001-06-28 07:25:16 +00002657 exitstatus = waitforjob(jp);
Eric Andersencb57d552001-06-28 07:25:16 +00002658 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002659 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00002660
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002661 out:
Eric Andersencb57d552001-06-28 07:25:16 +00002662 if (lastarg)
2663 setvar("_", lastarg, 0);
2664 popstackmark(&smark);
2665}
2666
Eric Andersen62483552001-07-10 06:09:16 +00002667/*
2668 * Evaluate a parse tree. The value is left in the global variable
2669 * exitstatus.
2670 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002671static void evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00002672{
2673 int checkexit = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002674
Eric Andersen62483552001-07-10 06:09:16 +00002675 if (n == NULL) {
2676 TRACE(("evaltree(NULL) called\n"));
2677 goto out;
2678 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002679 TRACE(("evaltree(0x%lx: %d) called\n", (long) n, n->type));
Eric Andersen62483552001-07-10 06:09:16 +00002680 switch (n->type) {
2681 case NSEMI:
2682 evaltree(n->nbinary.ch1, flags & EV_TESTED);
2683 if (evalskip)
2684 goto out;
2685 evaltree(n->nbinary.ch2, flags);
2686 break;
2687 case NAND:
2688 evaltree(n->nbinary.ch1, EV_TESTED);
2689 if (evalskip || exitstatus != 0)
2690 goto out;
2691 evaltree(n->nbinary.ch2, flags);
2692 break;
2693 case NOR:
2694 evaltree(n->nbinary.ch1, EV_TESTED);
2695 if (evalskip || exitstatus == 0)
2696 goto out;
2697 evaltree(n->nbinary.ch2, flags);
2698 break;
2699 case NREDIR:
2700 expredir(n->nredir.redirect);
2701 redirect(n->nredir.redirect, REDIR_PUSH);
2702 evaltree(n->nredir.n, flags);
2703 popredir();
2704 break;
2705 case NSUBSHELL:
2706 evalsubshell(n, flags);
2707 break;
2708 case NBACKGND:
2709 evalsubshell(n, flags);
2710 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002711 case NIF:{
Eric Andersen62483552001-07-10 06:09:16 +00002712 evaltree(n->nif.test, EV_TESTED);
2713 if (evalskip)
2714 goto out;
2715 if (exitstatus == 0)
2716 evaltree(n->nif.ifpart, flags);
2717 else if (n->nif.elsepart)
2718 evaltree(n->nif.elsepart, flags);
2719 else
2720 exitstatus = 0;
2721 break;
2722 }
2723 case NWHILE:
2724 case NUNTIL:
2725 evalloop(n, flags);
2726 break;
2727 case NFOR:
2728 evalfor(n, flags);
2729 break;
2730 case NCASE:
2731 evalcase(n, flags);
2732 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002733 case NDEFUN:{
Eric Andersen62483552001-07-10 06:09:16 +00002734 struct builtincmd *bcmd;
2735 struct cmdentry entry;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002736
2737 if ((bcmd = find_builtin(n->narg.text)) && IS_BUILTIN_SPECIAL(bcmd)
2738 ) {
Eric Andersen62483552001-07-10 06:09:16 +00002739 out2fmt("%s is a special built-in\n", n->narg.text);
2740 exitstatus = 1;
2741 break;
2742 }
2743 entry.cmdtype = CMDFUNCTION;
2744 entry.u.func = copyfunc(n->narg.next);
2745 addcmdentry(n->narg.text, &entry);
2746 exitstatus = 0;
2747 break;
2748 }
2749 case NNOT:
2750 evaltree(n->nnot.com, EV_TESTED);
2751 exitstatus = !exitstatus;
2752 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002753
Eric Andersen62483552001-07-10 06:09:16 +00002754 case NPIPE:
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002755 evalpipe(n, flags);
Eric Andersen62483552001-07-10 06:09:16 +00002756 checkexit = 1;
2757 break;
2758 case NCMD:
2759 evalcommand(n, flags);
2760 checkexit = 1;
2761 break;
2762#ifdef DEBUG
2763 default:
2764 printf("Node type = %d\n", n->type);
2765 break;
2766#endif
2767 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002768 out:
Eric Andersen62483552001-07-10 06:09:16 +00002769 if (pendingsigs)
2770 dotrap();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002771 if (flags & EV_EXIT ||
Eric Andersen62483552001-07-10 06:09:16 +00002772 (checkexit && eflag && exitstatus && !(flags & EV_TESTED))
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002773 )
Eric Andersen62483552001-07-10 06:09:16 +00002774 exitshell(exitstatus);
2775}
2776
2777/*
2778 * Kick off a subshell to evaluate a tree.
2779 */
2780
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002781static void evalsubshell(const union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00002782{
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002783 struct job *jp = 0;
Eric Andersen62483552001-07-10 06:09:16 +00002784 int backgnd = (n->type == NBACKGND);
2785
2786 expredir(n->nredir.redirect);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002787 if (!backgnd && flags & EV_EXIT && !trap[0])
2788 goto nofork;
2789 INTOFF;
Eric Andersen62483552001-07-10 06:09:16 +00002790 jp = makejob(n, 1);
2791 if (forkshell(jp, n, backgnd) == 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002792 INTON;
2793 flags |= EV_EXIT;
Eric Andersen62483552001-07-10 06:09:16 +00002794 if (backgnd)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002795 flags &= ~EV_TESTED;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002796 nofork:
Eric Andersen62483552001-07-10 06:09:16 +00002797 redirect(n->nredir.redirect, 0);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002798 evaltree(n->nredir.n, flags); /* never returns */
Eric Andersen62483552001-07-10 06:09:16 +00002799 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002800 if (!backgnd) {
Eric Andersen62483552001-07-10 06:09:16 +00002801 exitstatus = waitforjob(jp);
Eric Andersen62483552001-07-10 06:09:16 +00002802 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002803 INTON;
Eric Andersen62483552001-07-10 06:09:16 +00002804}
2805
2806/*
2807 * Compute the names of the files in a redirection list.
2808 */
2809
2810static void fixredir(union node *n, const char *text, int err);
2811
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002812static void expredir(union node *n)
Eric Andersen62483552001-07-10 06:09:16 +00002813{
2814 union node *redir;
2815
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002816 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersen62483552001-07-10 06:09:16 +00002817 struct arglist fn;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002818
Eric Andersen62483552001-07-10 06:09:16 +00002819 fn.lastp = &fn.list;
2820 oexitstatus = exitstatus;
2821 switch (redir->type) {
2822 case NFROMTO:
2823 case NFROM:
2824 case NTO:
2825 case NAPPEND:
2826 case NTOOV:
2827 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
2828 redir->nfile.expfname = fn.list->text;
2829 break;
2830 case NFROMFD:
2831 case NTOFD:
2832 if (redir->ndup.vname) {
2833 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
2834 fixredir(redir, fn.list->text, 1);
2835 }
2836 break;
2837 }
2838 }
2839}
2840
2841
2842/*
2843 * Execute a command inside back quotes. If it's a builtin command, we
2844 * want to save its output in a block obtained from malloc. Otherwise
2845 * we fork off a subprocess and get the output of the command via a pipe.
2846 * Should be called with interrupts off.
2847 */
2848
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002849static void evalbackcmd(union node *n, struct backcmd *result)
Eric Andersen62483552001-07-10 06:09:16 +00002850{
2851 int pip[2];
2852 struct job *jp;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002853 struct stackmark smark; /* unnecessary */
Eric Andersen62483552001-07-10 06:09:16 +00002854
2855 setstackmark(&smark);
2856 result->fd = -1;
2857 result->buf = NULL;
2858 result->nleft = 0;
2859 result->jp = NULL;
2860 if (n == NULL) {
2861 exitstatus = 0;
2862 goto out;
2863 }
2864 exitstatus = 0;
2865 if (pipe(pip) < 0)
2866 error("Pipe call failed");
2867 jp = makejob(n, 1);
2868 if (forkshell(jp, n, FORK_NOJOB) == 0) {
2869 FORCEINTON;
2870 close(pip[0]);
2871 if (pip[1] != 1) {
2872 close(1);
2873 dup_as_newfd(pip[1], 1);
2874 close(pip[1]);
2875 }
2876 eflag = 0;
2877 evaltree(n, EV_EXIT);
2878 }
2879 close(pip[1]);
2880 result->fd = pip[0];
2881 result->jp = jp;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002882 out:
Eric Andersen62483552001-07-10 06:09:16 +00002883 popstackmark(&smark);
2884 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002885 result->fd, result->buf, result->nleft, result->jp));
Eric Andersen62483552001-07-10 06:09:16 +00002886}
2887
2888
2889/*
2890 * Execute a simple command.
2891 */
Eric Andersencb57d552001-06-28 07:25:16 +00002892
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002893/*
2894 * Search for a command. This is called before we fork so that the
2895 * location of the command will be available in the parent as well as
2896 * the child. The check for "goodname" is an overly conservative
2897 * check that the name will not be subject to expansion.
2898 */
2899
2900static void prehash(union node *n)
2901{
2902 struct cmdentry entry;
2903
2904 if (n->type == NCMD && n->ncmd.args)
2905 if (goodname(n->ncmd.args->narg.text))
2906 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
2907}
2908
Eric Andersencb57d552001-06-28 07:25:16 +00002909
Eric Andersencb57d552001-06-28 07:25:16 +00002910/*
2911 * Builtin commands. Builtin commands whose functions are closely
2912 * tied to evaluation are implemented here.
2913 */
2914
2915/*
2916 * No command given, or a bltin command with no arguments. Set the
2917 * specified variables.
2918 */
2919
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002920int bltincmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002921{
2922 /*
2923 * Preserve exitstatus of a previous possible redirection
2924 * as POSIX mandates
2925 */
2926 return exitstatus;
2927}
2928
2929
2930/*
2931 * Handle break and continue commands. Break, continue, and return are
2932 * all handled by setting the evalskip flag. The evaluation routines
2933 * above all check this flag, and if it is set they start skipping
2934 * commands rather than executing them. The variable skipcount is
2935 * the number of loops to break/continue, or the number of function
2936 * levels to return. (The latter is always 1.) It should probably
2937 * be an error to break out of more loops than exist, but it isn't
2938 * in the standard shell so we don't make it one here.
2939 */
2940
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002941static int breakcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002942{
2943 int n = argc > 1 ? number(argv[1]) : 1;
2944
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00002945 if (n <= 0)
2946 error("Illegal number: %s", argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00002947 if (n > loopnest)
2948 n = loopnest;
2949 if (n > 0) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002950 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00002951 skipcount = n;
2952 }
2953 return 0;
2954}
2955
2956
2957/*
2958 * The return command.
2959 */
2960
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002961static int returncmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002962{
2963 int ret = argc > 1 ? number(argv[1]) : oexitstatus;
2964
2965 if (funcnest) {
2966 evalskip = SKIPFUNC;
2967 skipcount = 1;
2968 return ret;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002969 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00002970 /* Do what ksh does; skip the rest of the file */
2971 evalskip = SKIPFILE;
2972 skipcount = 1;
2973 return ret;
2974 }
2975}
2976
2977
Eric Andersen69a20f02001-10-31 10:40:37 +00002978#ifndef CONFIG_FALSE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002979static int false_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002980{
2981 return 1;
2982}
Eric Andersen69a20f02001-10-31 10:40:37 +00002983#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002984
Eric Andersen69a20f02001-10-31 10:40:37 +00002985#ifndef CONFIG_TRUE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002986static int true_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002987{
2988 return 0;
2989}
2990#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002991
2992/*
2993 * Controls whether the shell is interactive or not.
2994 */
2995
2996static void setsignal(int signo);
Eric Andersen2870d962001-07-02 17:27:21 +00002997
Eric Andersend35c5df2002-01-09 15:37:36 +00002998#ifdef CONFIG_ASH_MAIL
Eric Andersenec074692001-10-31 11:05:49 +00002999static void chkmail(int silent);
3000#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003001
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003002static void setinteractive(int on)
Eric Andersen2870d962001-07-02 17:27:21 +00003003{
3004 static int is_interactive;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003005 static int do_banner = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00003006
3007 if (on == is_interactive)
3008 return;
3009 setsignal(SIGINT);
3010 setsignal(SIGQUIT);
3011 setsignal(SIGTERM);
Eric Andersend35c5df2002-01-09 15:37:36 +00003012#ifdef CONFIG_ASH_MAIL
Eric Andersen2870d962001-07-02 17:27:21 +00003013 chkmail(1);
Eric Andersenec074692001-10-31 11:05:49 +00003014#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003015 is_interactive = on;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003016 if (do_banner == 0 && is_interactive) {
Eric Andersen1c039232001-07-07 00:05:55 +00003017 /* Looks like they want an interactive shell */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003018#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
3019 printf("\n\n" BB_BANNER " Built-in shell (ash)\n");
3020 printf("Enter 'help' for a list of built-in commands.\n\n");
Eric Andersend63dee42001-10-19 00:22:23 +00003021#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003022 do_banner = 1;
Eric Andersen1c039232001-07-07 00:05:55 +00003023 }
Eric Andersen2870d962001-07-02 17:27:21 +00003024}
3025
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003026static void optschanged(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003027{
3028 setinteractive(iflag);
3029 setjobctl(mflag);
3030}
3031
Eric Andersencb57d552001-06-28 07:25:16 +00003032
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003033static int execcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003034{
3035 if (argc > 1) {
3036 struct strlist *sp;
3037
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003038 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003039 mflag = 0;
3040 optschanged();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003041 for (sp = cmdenviron; sp; sp = sp->next)
3042 setvareq(sp->text, VEXPORT | VSTACK);
Eric Andersencb57d552001-06-28 07:25:16 +00003043 shellexec(argv + 1, environment(), pathval(), 0);
3044 }
3045 return 0;
3046}
3047
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003048static void eprintlist(struct strlist *sp)
Eric Andersencb57d552001-06-28 07:25:16 +00003049{
3050 for (; sp; sp = sp->next) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003051 out2fmt(" %s", sp->text);
Eric Andersencb57d552001-06-28 07:25:16 +00003052 }
3053}
Eric Andersencb57d552001-06-28 07:25:16 +00003054
3055/*
3056 * Exec a program. Never returns. If you change this routine, you may
3057 * have to change the find_command routine as well.
3058 */
3059
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003060static const char *pathopt; /* set by padvance */
Eric Andersen2870d962001-07-02 17:27:21 +00003061
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003062static void shellexec(char **argv, char **envp, const char *path, int idx)
Eric Andersencb57d552001-06-28 07:25:16 +00003063{
3064 char *cmdname;
3065 int e;
3066
Eric Andersenbf8bf102002-09-17 08:41:08 +00003067 if (strchr(argv[0], '/') != NULL
3068#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3069 || find_applet_by_name(argv[0])
3070#endif
3071 )
3072 {
Eric Andersencb57d552001-06-28 07:25:16 +00003073 tryexec(argv[0], argv, envp);
3074 e = errno;
3075 } else {
3076 e = ENOENT;
3077 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3078 if (--idx < 0 && pathopt == NULL) {
3079 tryexec(cmdname, argv, envp);
3080 if (errno != ENOENT && errno != ENOTDIR)
3081 e = errno;
3082 }
3083 stunalloc(cmdname);
3084 }
3085 }
3086
3087 /* Map to POSIX errors */
3088 switch (e) {
3089 case EACCES:
3090 exerrno = 126;
3091 break;
3092 case ENOENT:
3093 exerrno = 127;
3094 break;
3095 default:
3096 exerrno = 2;
3097 break;
3098 }
3099 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3100 /* NOTREACHED */
3101}
3102
Eric Andersen2870d962001-07-02 17:27:21 +00003103/*
3104 * Clear traps on a fork.
3105 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003106static void clear_traps(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003107{
Eric Andersen2870d962001-07-02 17:27:21 +00003108 char **tp;
3109
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003110 for (tp = trap; tp < &trap[NSIG]; tp++) {
3111 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
Eric Andersen2870d962001-07-02 17:27:21 +00003112 INTOFF;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00003113 free(*tp);
Eric Andersen2870d962001-07-02 17:27:21 +00003114 *tp = NULL;
3115 if (tp != &trap[0])
3116 setsignal(tp - trap);
3117 INTON;
3118 }
3119 }
3120}
3121
3122
Eric Andersen2870d962001-07-02 17:27:21 +00003123static int preadbuffer(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003124static void pushfile(void);
Eric Andersen2870d962001-07-02 17:27:21 +00003125
3126/*
3127 * Read a character from the script, returning PEOF on end of file.
3128 * Nul characters in the input are silently discarded.
3129 */
3130
Eric Andersend35c5df2002-01-09 15:37:36 +00003131#ifndef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Eric Andersen2870d962001-07-02 17:27:21 +00003132#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003133static int pgetc(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003134{
3135 return pgetc_macro();
3136}
3137#else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003138static int pgetc_macro(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003139{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003140 return --parsenleft >= 0 ? *parsenextc++ : preadbuffer();
Eric Andersen2870d962001-07-02 17:27:21 +00003141}
3142
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003143static inline int pgetc(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003144{
3145 return pgetc_macro();
3146}
3147#endif
3148
3149
3150/*
3151 * Undo the last call to pgetc. Only one character may be pushed back.
3152 * PEOF may be pushed back.
3153 */
3154
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003155static void pungetc(void)
Eric Andersen74400cc2001-10-18 04:11:39 +00003156{
Eric Andersen2870d962001-07-02 17:27:21 +00003157 parsenleft++;
3158 parsenextc--;
3159}
3160
3161
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003162static void popfile(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003163{
Eric Andersen2870d962001-07-02 17:27:21 +00003164 struct parsefile *pf = parsefile;
3165
3166 INTOFF;
3167 if (pf->fd >= 0)
3168 close(pf->fd);
Aaron Lehmann49c024a2002-08-02 06:39:47 +00003169 free(pf->buf);
Eric Andersen2870d962001-07-02 17:27:21 +00003170 while (pf->strpush)
3171 popstring();
3172 parsefile = pf->prev;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00003173 free(pf);
Eric Andersen2870d962001-07-02 17:27:21 +00003174 parsenleft = parsefile->nleft;
3175 parselleft = parsefile->lleft;
3176 parsenextc = parsefile->nextc;
3177 plinno = parsefile->linno;
3178 INTON;
3179}
3180
3181
3182/*
3183 * Return to top level.
3184 */
3185
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003186static void popallfiles(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003187{
Eric Andersen2870d962001-07-02 17:27:21 +00003188 while (parsefile != &basepf)
3189 popfile();
3190}
3191
3192/*
3193 * Close the file(s) that the shell is reading commands from. Called
3194 * after a fork is done.
3195 */
3196
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003197static void closescript(void)
Eric Andersen74400cc2001-10-18 04:11:39 +00003198{
Eric Andersen2870d962001-07-02 17:27:21 +00003199 popallfiles();
3200 if (parsefile->fd > 0) {
3201 close(parsefile->fd);
3202 parsefile->fd = 0;
3203 }
3204}
3205
3206
3207/*
3208 * Like setinputfile, but takes an open file descriptor. Call this with
3209 * interrupts off.
3210 */
3211
Eric Andersen74400cc2001-10-18 04:11:39 +00003212static void setinputfd(int fd, int push)
Eric Andersen2870d962001-07-02 17:27:21 +00003213{
3214 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
3215 if (push) {
3216 pushfile();
3217 parsefile->buf = 0;
3218 } else {
3219 closescript();
3220 while (parsefile->strpush)
3221 popstring();
3222 }
3223 parsefile->fd = fd;
3224 if (parsefile->buf == NULL)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003225 parsefile->buf = xmalloc(BUFSIZ);
Eric Andersen2870d962001-07-02 17:27:21 +00003226 parselleft = parsenleft = 0;
3227 plinno = 1;
3228}
3229
3230
3231/*
3232 * Set the input to take input from a file. If push is set, push the
3233 * old input onto the stack first.
3234 */
3235
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003236static void setinputfile(const char *fname, int push)
Eric Andersen2870d962001-07-02 17:27:21 +00003237{
3238 int fd;
3239 int myfileno2;
3240
3241 INTOFF;
3242 if ((fd = open(fname, O_RDONLY)) < 0)
3243 error("Can't open %s", fname);
3244 if (fd < 10) {
3245 myfileno2 = dup_as_newfd(fd, 10);
3246 close(fd);
3247 if (myfileno2 < 0)
3248 error("Out of file descriptors");
3249 fd = myfileno2;
3250 }
3251 setinputfd(fd, push);
3252 INTON;
3253}
3254
Eric Andersencb57d552001-06-28 07:25:16 +00003255
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003256static void tryexec(char *cmd, char **argv, char **envp)
Eric Andersen62483552001-07-10 06:09:16 +00003257{
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003258 int repeated = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003259
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003260#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Eric Andersen3102ac42001-07-06 04:26:23 +00003261 char *name = cmd;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003262 char **argv_l = argv;
Eric Andersen3102ac42001-07-06 04:26:23 +00003263 int argc_l;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003264
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003265#ifdef CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
Eric Andersen3102ac42001-07-06 04:26:23 +00003266 name = get_last_path_component(name);
3267#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003268 argv_l = envp;
3269 for (argc_l = 0; *argv_l != NULL; argv_l++, argc_l++)
Eric Andersen3102ac42001-07-06 04:26:23 +00003270 putenv(*argv_l);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003271 argv_l = argv;
3272 for (argc_l = 0; *argv_l != NULL; argv_l++, argc_l++)
3273 optind = 1;
Eric Andersen3102ac42001-07-06 04:26:23 +00003274 run_applet_by_name(name, argc_l, argv);
3275#endif
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003276 repeat:
Eric Andersencb57d552001-06-28 07:25:16 +00003277 execve(cmd, argv, envp);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003278 if (repeated++) {
3279 free(argv);
3280 } else if (errno == ENOEXEC) {
3281 char **ap;
3282 char **new;
3283
3284 for (ap = argv; *ap; ap++);
3285 ap = new = xmalloc((ap - argv + 2) * sizeof(char *));
3286 *ap++ = cmd = "/bin/sh";
3287 while ((*ap++ = *argv++));
3288 argv = new;
3289 goto repeat;
Eric Andersencb57d552001-06-28 07:25:16 +00003290 }
Eric Andersencb57d552001-06-28 07:25:16 +00003291}
3292
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003293static char *commandtext(const union node *);
Eric Andersencb57d552001-06-28 07:25:16 +00003294
3295/*
3296 * Do a path search. The variable path (passed by reference) should be
3297 * set to the start of the path before the first call; padvance will update
3298 * this value as it proceeds. Successive calls to padvance will return
3299 * the possible path expansions in sequence. If an option (indicated by
3300 * a percent sign) appears in the path entry then the global variable
3301 * pathopt will be set to point to it; otherwise pathopt will be set to
3302 * NULL.
3303 */
3304
3305static const char *pathopt;
3306
Eric Andersen2870d962001-07-02 17:27:21 +00003307static void growstackblock(void);
3308
3309
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003310static char *padvance(const char **path, const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003311{
Eric Andersencb57d552001-06-28 07:25:16 +00003312 const char *p;
3313 char *q;
3314 const char *start;
3315 int len;
3316
3317 if (*path == NULL)
3318 return NULL;
3319 start = *path;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003320 for (p = start; *p && *p != ':' && *p != '%'; p++);
3321 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003322 while (stackblocksize() < len)
3323 growstackblock();
3324 q = stackblock();
3325 if (p != start) {
3326 memcpy(q, start, p - start);
3327 q += p - start;
3328 *q++ = '/';
3329 }
3330 strcpy(q, name);
3331 pathopt = NULL;
3332 if (*p == '%') {
3333 pathopt = ++p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003334 while (*p && *p != ':')
3335 p++;
Eric Andersencb57d552001-06-28 07:25:16 +00003336 }
3337 if (*p == ':')
3338 *path = p + 1;
3339 else
3340 *path = NULL;
3341 return stalloc(len);
3342}
3343
Eric Andersen62483552001-07-10 06:09:16 +00003344/*
3345 * Wrapper around strcmp for qsort/bsearch/...
3346 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003347static int pstrcmp(const void *a, const void *b)
Eric Andersen62483552001-07-10 06:09:16 +00003348{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003349 return strcmp((const char *) a, (*(const char *const *) b) + 1);
Eric Andersen62483552001-07-10 06:09:16 +00003350}
3351
3352/*
3353 * Find a keyword is in a sorted array.
3354 */
3355
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003356static const char *const *findkwd(const char *s)
Eric Andersen62483552001-07-10 06:09:16 +00003357{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003358 return bsearch(s, tokname_array + KWDOFFSET,
3359 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
3360 sizeof(const char *), pstrcmp);
Eric Andersen62483552001-07-10 06:09:16 +00003361}
Eric Andersencb57d552001-06-28 07:25:16 +00003362
3363
3364/*** Command hashing code ***/
3365
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003366static int hashcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003367{
3368 struct tblentry **pp;
3369 struct tblentry *cmdp;
3370 int c;
3371 int verbose;
3372 struct cmdentry entry;
3373 char *name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003374
Eric Andersend35c5df2002-01-09 15:37:36 +00003375#ifdef CONFIG_ASH_ALIAS
Eric Andersen62483552001-07-10 06:09:16 +00003376 const struct alias *ap;
3377#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003378
3379 verbose = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003380 while ((c = nextopt("rvV")) != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00003381 if (c == 'r') {
3382 clearcmdentry(0);
3383 return 0;
Eric Andersen62483552001-07-10 06:09:16 +00003384 } else if (c == 'v' || c == 'V') {
3385 verbose = c;
Eric Andersencb57d552001-06-28 07:25:16 +00003386 }
3387 }
3388 if (*argptr == NULL) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003389 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
3390 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00003391 if (cmdp->cmdtype != CMDBUILTIN) {
3392 printentry(cmdp, verbose);
3393 }
3394 }
3395 }
3396 return 0;
3397 }
3398 c = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003399 while ((name = *argptr++) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00003400 if ((cmdp = cmdlookup(name, 0)) != NULL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003401 && (cmdp->cmdtype == CMDNORMAL
3402 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
Eric Andersencb57d552001-06-28 07:25:16 +00003403 delete_cmd_entry();
Eric Andersend35c5df2002-01-09 15:37:36 +00003404#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003405 /* Then look at the aliases */
Eric Andersenec074692001-10-31 11:05:49 +00003406 if ((ap = *__lookupalias(name)) != NULL) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003407 if (verbose == 'v')
Eric Andersen62483552001-07-10 06:09:16 +00003408 printf("%s is an alias for %s\n", name, ap->val);
3409 else
3410 printalias(ap);
3411 continue;
3412 }
3413#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003414 /* First look at the keywords */
3415 if (findkwd(name) != 0) {
3416 if (verbose == 'v')
Eric Andersen62483552001-07-10 06:09:16 +00003417 printf("%s is a shell keyword\n", name);
3418 else
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003419 puts(name);
Eric Andersen62483552001-07-10 06:09:16 +00003420 continue;
3421 }
3422
Eric Andersencb57d552001-06-28 07:25:16 +00003423 find_command(name, &entry, DO_ERR, pathval());
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003424 if (entry.cmdtype == CMDUNKNOWN)
3425 c = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00003426 else if (verbose) {
3427 cmdp = cmdlookup(name, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003428 if (cmdp)
3429 printentry(cmdp, verbose == 'v');
Eric Andersencb57d552001-06-28 07:25:16 +00003430 flushall();
3431 }
Eric Andersencb57d552001-06-28 07:25:16 +00003432 }
3433 return c;
3434}
3435
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003436static void printentry(struct tblentry *cmdp, int verbose)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003437{
Eric Andersencb57d552001-06-28 07:25:16 +00003438 int idx;
3439 const char *path;
3440 char *name;
3441
Eric Andersen62483552001-07-10 06:09:16 +00003442 printf("%s%s", cmdp->cmdname, (verbose ? " is " : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00003443 if (cmdp->cmdtype == CMDNORMAL) {
3444 idx = cmdp->param.index;
3445 path = pathval();
3446 do {
3447 name = padvance(&path, cmdp->cmdname);
3448 stunalloc(name);
3449 } while (--idx >= 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003450 if (verbose)
Eric Andersen62483552001-07-10 06:09:16 +00003451 out1str(name);
Eric Andersencb57d552001-06-28 07:25:16 +00003452 } else if (cmdp->cmdtype == CMDBUILTIN) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003453 if (verbose)
Eric Andersen62483552001-07-10 06:09:16 +00003454 out1str("a shell builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00003455 } else if (cmdp->cmdtype == CMDFUNCTION) {
Eric Andersencb57d552001-06-28 07:25:16 +00003456 if (verbose) {
3457 INTOFF;
Eric Andersen62483552001-07-10 06:09:16 +00003458 out1str("a function\n");
Eric Andersencb57d552001-06-28 07:25:16 +00003459 name = commandtext(cmdp->param.func);
Eric Andersen62483552001-07-10 06:09:16 +00003460 printf("%s() {\n %s\n}", cmdp->cmdname, name);
Aaron Lehmann49c024a2002-08-02 06:39:47 +00003461 free(name);
Eric Andersencb57d552001-06-28 07:25:16 +00003462 INTON;
3463 }
3464#ifdef DEBUG
3465 } else {
3466 error("internal error: cmdtype %d", cmdp->cmdtype);
3467#endif
3468 }
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003469 puts(cmdp->rehash ? "*" : nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +00003470}
3471
3472
3473
Eric Andersen1c039232001-07-07 00:05:55 +00003474/*** List the available builtins ***/
3475
3476
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003477static int helpcmd(int argc, char **argv)
Eric Andersen1c039232001-07-07 00:05:55 +00003478{
3479 int col, i;
Eric Andersen1c039232001-07-07 00:05:55 +00003480
Eric Andersen62483552001-07-10 06:09:16 +00003481 printf("\nBuilt-in commands:\n-------------------\n");
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003482 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
Eric Andersen62483552001-07-10 06:09:16 +00003483 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003484 builtincmds[i].name + 1);
Eric Andersen1c039232001-07-07 00:05:55 +00003485 if (col > 60) {
3486 printf("\n");
3487 col = 0;
3488 }
3489 }
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003490#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Eric Andersen1c039232001-07-07 00:05:55 +00003491 {
Eric Andersen1c039232001-07-07 00:05:55 +00003492 extern const struct BB_applet applets[];
3493 extern const size_t NUM_APPLETS;
3494
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003495 for (i = 0; i < NUM_APPLETS; i++) {
Eric Andersen62483552001-07-10 06:09:16 +00003496
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003497 col += printf("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
Eric Andersen1c039232001-07-07 00:05:55 +00003498 if (col > 60) {
3499 printf("\n");
3500 col = 0;
3501 }
3502 }
3503 }
3504#endif
3505 printf("\n\n");
3506 return EXIT_SUCCESS;
3507}
3508
Eric Andersencb57d552001-06-28 07:25:16 +00003509/*
3510 * Resolve a command name. If you change this routine, you may have to
3511 * change the shellexec routine as well.
3512 */
3513
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003514static int prefix(const char *, const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00003515
Eric Andersencb57d552001-06-28 07:25:16 +00003516static void
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003517find_command(const char *name, struct cmdentry *entry, int act,
3518 const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003519{
3520 struct tblentry *cmdp;
3521 int idx;
3522 int prev;
3523 char *fullname;
3524 struct stat statb;
3525 int e;
3526 int bltin;
3527 int firstchange;
3528 int updatetbl;
Eric Andersen62483552001-07-10 06:09:16 +00003529 int regular;
Eric Andersencb57d552001-06-28 07:25:16 +00003530 struct builtincmd *bcmd;
3531
3532 /* If name contains a slash, don't use the hash table */
3533 if (strchr(name, '/') != NULL) {
3534 if (act & DO_ABS) {
3535 while (stat(name, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003536 if (errno != ENOENT && errno != ENOTDIR)
3537 e = errno;
3538 entry->cmdtype = CMDUNKNOWN;
3539 entry->u.index = -1;
3540 return;
3541 }
3542 entry->cmdtype = CMDNORMAL;
3543 entry->u.index = -1;
3544 return;
3545 }
3546 entry->cmdtype = CMDNORMAL;
3547 entry->u.index = 0;
3548 return;
3549 }
3550
Eric Andersenbf8bf102002-09-17 08:41:08 +00003551#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3552 if (find_applet_by_name(name)) {
3553 entry->cmdtype = CMDNORMAL;
3554 entry->u.index = -1;
3555 return;
3556 }
3557#endif
3558
Eric Andersencb57d552001-06-28 07:25:16 +00003559 updatetbl = 1;
3560 if (act & DO_BRUTE) {
3561 firstchange = path_change(path, &bltin);
3562 } else {
3563 bltin = builtinloc;
3564 firstchange = 9999;
3565 }
3566
3567 /* If name is in the table, and not invalidated by cd, we're done */
3568 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
3569 if (cmdp->cmdtype == CMDFUNCTION) {
3570 if (act & DO_NOFUN) {
3571 updatetbl = 0;
3572 } else {
3573 goto success;
3574 }
3575 } else if (act & DO_BRUTE) {
3576 if ((cmdp->cmdtype == CMDNORMAL &&
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003577 cmdp->param.index >= firstchange) ||
3578 (cmdp->cmdtype == CMDBUILTIN &&
3579 ((builtinloc < 0 && bltin >= 0) ?
3580 bltin : builtinloc) >= firstchange)) {
Eric Andersencb57d552001-06-28 07:25:16 +00003581 /* need to recompute the entry */
3582 } else {
3583 goto success;
3584 }
3585 } else {
3586 goto success;
3587 }
3588 }
3589
3590 bcmd = find_builtin(name);
Eric Andersen2870d962001-07-02 17:27:21 +00003591 regular = bcmd && IS_BUILTIN_REGULAR(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00003592
3593 if (regular) {
3594 if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) {
Eric Andersen2870d962001-07-02 17:27:21 +00003595 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003596 }
3597 } else if (act & DO_BRUTE) {
3598 if (firstchange == 0) {
3599 updatetbl = 0;
3600 }
3601 }
3602
3603 /* If %builtin not in path, check for builtin next */
3604 if (regular || (bltin < 0 && bcmd)) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003605 builtin:
Eric Andersencb57d552001-06-28 07:25:16 +00003606 if (!updatetbl) {
3607 entry->cmdtype = CMDBUILTIN;
3608 entry->u.cmd = bcmd;
3609 return;
3610 }
3611 INTOFF;
3612 cmdp = cmdlookup(name, 1);
3613 cmdp->cmdtype = CMDBUILTIN;
3614 cmdp->param.cmd = bcmd;
3615 INTON;
3616 goto success;
3617 }
3618
3619 /* We have to search path. */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003620 prev = -1; /* where to start */
3621 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00003622 if (cmdp->cmdtype == CMDBUILTIN)
3623 prev = builtinloc;
3624 else
3625 prev = cmdp->param.index;
3626 }
3627
3628 e = ENOENT;
3629 idx = -1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003630 loop:
Eric Andersencb57d552001-06-28 07:25:16 +00003631 while ((fullname = padvance(&path, name)) != NULL) {
3632 stunalloc(fullname);
3633 idx++;
3634 if (idx >= firstchange) {
3635 updatetbl = 0;
3636 }
3637 if (pathopt) {
3638 if (prefix("builtin", pathopt)) {
3639 if ((bcmd = find_builtin(name))) {
3640 goto builtin;
3641 }
3642 continue;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003643 } else if (!(act & DO_NOFUN) && prefix("func", pathopt)) {
Eric Andersencb57d552001-06-28 07:25:16 +00003644 /* handled below */
3645 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003646 continue; /* ignore unimplemented options */
Eric Andersencb57d552001-06-28 07:25:16 +00003647 }
3648 }
3649 /* if rehash, don't redo absolute path names */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003650 if (fullname[0] == '/' && idx <= prev && idx < firstchange) {
Eric Andersencb57d552001-06-28 07:25:16 +00003651 if (idx < prev)
3652 continue;
3653 TRACE(("searchexec \"%s\": no change\n", name));
3654 goto success;
3655 }
3656 while (stat(fullname, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003657 if (errno != ENOENT && errno != ENOTDIR)
3658 e = errno;
3659 goto loop;
3660 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003661 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00003662 if (!S_ISREG(statb.st_mode))
3663 continue;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003664 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00003665 stalloc(strlen(fullname) + 1);
3666 readcmdfile(fullname);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003667 if ((cmdp = cmdlookup(name, 0)) == NULL
3668 || cmdp->cmdtype != CMDFUNCTION)
Eric Andersencb57d552001-06-28 07:25:16 +00003669 error("%s not defined in %s", name, fullname);
3670 stunalloc(fullname);
3671 goto success;
3672 }
Eric Andersencb57d552001-06-28 07:25:16 +00003673 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
3674 /* If we aren't called with DO_BRUTE and cmdp is set, it must
3675 be a function and we're being called with DO_NOFUN */
3676 if (!updatetbl) {
3677 entry->cmdtype = CMDNORMAL;
3678 entry->u.index = idx;
3679 return;
3680 }
3681 INTOFF;
3682 cmdp = cmdlookup(name, 1);
3683 cmdp->cmdtype = CMDNORMAL;
3684 cmdp->param.index = idx;
3685 INTON;
3686 goto success;
3687 }
3688
3689 /* We failed. If there was an entry for this command, delete it */
3690 if (cmdp && updatetbl)
3691 delete_cmd_entry();
3692 if (act & DO_ERR)
Eric Andersen3102ac42001-07-06 04:26:23 +00003693 out2fmt("%s: %s\n", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00003694 entry->cmdtype = CMDUNKNOWN;
3695 return;
3696
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003697 success:
Eric Andersencb57d552001-06-28 07:25:16 +00003698 cmdp->rehash = 0;
3699 entry->cmdtype = cmdp->cmdtype;
3700 entry->u = cmdp->param;
3701}
3702
3703
3704
3705/*
3706 * Search the table of builtin commands.
3707 */
3708
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003709static struct builtincmd *find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00003710{
3711 struct builtincmd *bp;
3712
Eric Andersen2870d962001-07-02 17:27:21 +00003713 bp = bsearch(name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd),
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003714 pstrcmp);
Eric Andersencb57d552001-06-28 07:25:16 +00003715 return bp;
3716}
3717
3718
3719/*
3720 * Called when a cd is done. Marks all commands so the next time they
3721 * are executed they will be rehashed.
3722 */
3723
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003724static void hashcd(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003725{
Eric Andersencb57d552001-06-28 07:25:16 +00003726 struct tblentry **pp;
3727 struct tblentry *cmdp;
3728
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003729 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
3730 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00003731 if (cmdp->cmdtype == CMDNORMAL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003732 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
Eric Andersencb57d552001-06-28 07:25:16 +00003733 cmdp->rehash = 1;
3734 }
3735 }
3736}
3737
3738
3739
3740/*
3741 * Called before PATH is changed. The argument is the new value of PATH;
3742 * pathval() still returns the old value at this point. Called with
3743 * interrupts off.
3744 */
3745
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003746static void changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00003747{
3748 int firstchange;
3749 int bltin;
3750
3751 firstchange = path_change(newval, &bltin);
3752 if (builtinloc < 0 && bltin >= 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003753 builtinloc = bltin; /* zap builtins */
Eric Andersencb57d552001-06-28 07:25:16 +00003754 clearcmdentry(firstchange);
3755 builtinloc = bltin;
Eric Andersen1a923762002-06-06 12:07:28 +00003756 /* Ensure that getenv("PATH") stays current */
3757 setenv("PATH", newval, 1);
Eric Andersencb57d552001-06-28 07:25:16 +00003758}
3759
3760
3761/*
3762 * Clear out command entries. The argument specifies the first entry in
3763 * PATH which has changed.
3764 */
3765
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003766static void clearcmdentry(int firstchange)
Eric Andersencb57d552001-06-28 07:25:16 +00003767{
3768 struct tblentry **tblp;
3769 struct tblentry **pp;
3770 struct tblentry *cmdp;
3771
3772 INTOFF;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003773 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00003774 pp = tblp;
3775 while ((cmdp = *pp) != NULL) {
3776 if ((cmdp->cmdtype == CMDNORMAL &&
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003777 cmdp->param.index >= firstchange)
3778 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= firstchange)) {
Eric Andersencb57d552001-06-28 07:25:16 +00003779 *pp = cmdp->next;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00003780 free(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00003781 } else {
3782 pp = &cmdp->next;
3783 }
3784 }
3785 }
3786 INTON;
3787}
3788
3789
3790/*
Eric Andersencb57d552001-06-28 07:25:16 +00003791 * Locate a command in the command hash table. If "add" is nonzero,
3792 * add the command to the table if it is not already present. The
3793 * variable "lastcmdentry" is set to point to the address of the link
3794 * pointing to the entry, so that delete_cmd_entry can delete the
3795 * entry.
3796 */
3797
Eric Andersen2870d962001-07-02 17:27:21 +00003798static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00003799
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003800static struct tblentry *cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00003801{
3802 int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00003803 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00003804 struct tblentry *cmdp;
3805 struct tblentry **pp;
3806
3807 p = name;
3808 hashval = *p << 4;
3809 while (*p)
3810 hashval += *p++;
3811 hashval &= 0x7FFF;
3812 pp = &cmdtable[hashval % CMDTABLESIZE];
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003813 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00003814 if (equal(cmdp->cmdname, name))
3815 break;
3816 pp = &cmdp->next;
3817 }
3818 if (add && cmdp == NULL) {
3819 INTOFF;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003820 cmdp = *pp = xmalloc(sizeof(struct tblentry) - ARB
3821 + strlen(name) + 1);
Eric Andersencb57d552001-06-28 07:25:16 +00003822 cmdp->next = NULL;
3823 cmdp->cmdtype = CMDUNKNOWN;
3824 cmdp->rehash = 0;
3825 strcpy(cmdp->cmdname, name);
3826 INTON;
3827 }
3828 lastcmdentry = pp;
3829 return cmdp;
3830}
3831
3832/*
3833 * Delete the command entry returned on the last lookup.
3834 */
3835
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003836static void delete_cmd_entry(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003837{
Eric Andersencb57d552001-06-28 07:25:16 +00003838 struct tblentry *cmdp;
3839
3840 INTOFF;
3841 cmdp = *lastcmdentry;
3842 *lastcmdentry = cmdp->next;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00003843 free(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00003844 INTON;
3845}
3846
3847
3848
Eric Andersencb57d552001-06-28 07:25:16 +00003849
3850
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003851static const unsigned char nodesize[26] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003852 ALIGN(sizeof(struct nbinary)),
3853 ALIGN(sizeof(struct ncmd)),
3854 ALIGN(sizeof(struct npipe)),
3855 ALIGN(sizeof(struct nredir)),
3856 ALIGN(sizeof(struct nredir)),
3857 ALIGN(sizeof(struct nredir)),
3858 ALIGN(sizeof(struct nbinary)),
3859 ALIGN(sizeof(struct nbinary)),
3860 ALIGN(sizeof(struct nif)),
3861 ALIGN(sizeof(struct nbinary)),
3862 ALIGN(sizeof(struct nbinary)),
3863 ALIGN(sizeof(struct nfor)),
3864 ALIGN(sizeof(struct ncase)),
3865 ALIGN(sizeof(struct nclist)),
3866 ALIGN(sizeof(struct narg)),
3867 ALIGN(sizeof(struct narg)),
3868 ALIGN(sizeof(struct nfile)),
3869 ALIGN(sizeof(struct nfile)),
3870 ALIGN(sizeof(struct nfile)),
3871 ALIGN(sizeof(struct nfile)),
3872 ALIGN(sizeof(struct nfile)),
3873 ALIGN(sizeof(struct ndup)),
3874 ALIGN(sizeof(struct ndup)),
3875 ALIGN(sizeof(struct nhere)),
3876 ALIGN(sizeof(struct nhere)),
3877 ALIGN(sizeof(struct nnot)),
Eric Andersen62483552001-07-10 06:09:16 +00003878};
Eric Andersencb57d552001-06-28 07:25:16 +00003879
Eric Andersencb57d552001-06-28 07:25:16 +00003880
3881
3882/*
3883 * Delete a function if it exists.
3884 */
3885
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003886static void unsetfunc(char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003887{
Eric Andersencb57d552001-06-28 07:25:16 +00003888 struct tblentry *cmdp;
3889
3890 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
Aaron Lehmann49c024a2002-08-02 06:39:47 +00003891 free(cmdp->param.func);
Eric Andersencb57d552001-06-28 07:25:16 +00003892 delete_cmd_entry();
3893 }
3894}
3895
Eric Andersen2870d962001-07-02 17:27:21 +00003896
3897/*
Eric Andersencb57d552001-06-28 07:25:16 +00003898 * Locate and print what a word is...
3899 */
3900
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003901static int typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003902{
3903 int i;
3904 int err = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003905 char *argv_a[2];
3906
3907 argv_a[1] = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003908
3909 for (i = 1; i < argc; i++) {
Eric Andersen62483552001-07-10 06:09:16 +00003910 argv_a[0] = argv[i];
3911 argptr = argv_a;
3912 optptr = "v";
3913 err |= hashcmd(argc, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00003914 }
3915 return err;
3916}
3917
Eric Andersend35c5df2002-01-09 15:37:36 +00003918#ifdef CONFIG_ASH_CMDCMD
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003919static int commandcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003920{
3921 int c;
3922 int default_path = 0;
3923 int verify_only = 0;
3924 int verbose_verify_only = 0;
3925
3926 while ((c = nextopt("pvV")) != '\0')
3927 switch (c) {
3928 case 'p':
3929 default_path = 1;
3930 break;
3931 case 'v':
3932 verify_only = 1;
3933 break;
3934 case 'V':
3935 verbose_verify_only = 1;
3936 break;
Eric Andersencb57d552001-06-28 07:25:16 +00003937 }
3938
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003939 if (default_path + verify_only + verbose_verify_only > 1 || !*argptr) {
3940 out2str("command [-p] command [arg ...]\n"
Eric Andersen62483552001-07-10 06:09:16 +00003941 "command {-v|-V} command\n");
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003942 return EX_USAGE;
Eric Andersencb57d552001-06-28 07:25:16 +00003943 }
3944
Eric Andersencb57d552001-06-28 07:25:16 +00003945 if (verify_only || verbose_verify_only) {
Eric Andersen62483552001-07-10 06:09:16 +00003946 char *argv_a[2];
3947
3948 argv_a[1] = 0;
3949 argv_a[0] = *argptr;
3950 argptr = argv_a;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003951 optptr = verbose_verify_only ? "v" : "V"; /* reverse special */
Eric Andersen62483552001-07-10 06:09:16 +00003952 return hashcmd(argc, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00003953 }
Eric Andersencb57d552001-06-28 07:25:16 +00003954
3955 return 0;
3956}
Eric Andersen2870d962001-07-02 17:27:21 +00003957#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003958
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003959static int path_change(const char *newval, int *bltin)
Eric Andersencb57d552001-06-28 07:25:16 +00003960{
3961 const char *old, *new;
3962 int idx;
3963 int firstchange;
3964
3965 old = pathval();
3966 new = newval;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003967 firstchange = 9999; /* assume no change */
Eric Andersencb57d552001-06-28 07:25:16 +00003968 idx = 0;
3969 *bltin = -1;
3970 for (;;) {
3971 if (*old != *new) {
3972 firstchange = idx;
3973 if ((*old == '\0' && *new == ':')
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003974 || (*old == ':' && *new == '\0'))
Eric Andersencb57d552001-06-28 07:25:16 +00003975 firstchange++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003976 old = new; /* ignore subsequent differences */
Eric Andersencb57d552001-06-28 07:25:16 +00003977 }
3978 if (*new == '\0')
3979 break;
3980 if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1))
3981 *bltin = idx;
3982 if (*new == ':') {
3983 idx++;
3984 }
3985 new++, old++;
3986 }
3987 if (builtinloc >= 0 && *bltin < 0)
3988 firstchange = 0;
3989 return firstchange;
3990}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003991
Eric Andersencb57d552001-06-28 07:25:16 +00003992/*
3993 * Routines to expand arguments to commands. We have to deal with
3994 * backquotes, shell variables, and file metacharacters.
3995 */
3996/*
3997 * _rmescape() flags
3998 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003999#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4000#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Eric Andersencb57d552001-06-28 07:25:16 +00004001
4002/*
4003 * Structure specifying which parts of the string should be searched
4004 * for IFS characters.
4005 */
4006
4007struct ifsregion {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004008 struct ifsregion *next; /* next region in list */
4009 int begoff; /* offset of start of region */
4010 int endoff; /* offset of end of region */
4011 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004012};
4013
4014
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004015static char *expdest; /* output of current string */
4016static struct nodelist *argbackq; /* list of back quote expressions */
4017static struct ifsregion ifsfirst; /* first struct in list of ifs regions */
4018static struct ifsregion *ifslastp; /* last struct in list */
4019static struct arglist exparg; /* holds expanded arg list */
Eric Andersencb57d552001-06-28 07:25:16 +00004020
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004021static void argstr(char *, int);
4022static char *exptilde(char *, int);
4023static void expbackq(union node *, int, int);
4024static int subevalvar(char *, char *, int, int, int, int, int);
4025static int varisset(char *, int);
4026static void strtodest(const char *, int, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00004027static void varvalue(char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004028static void recordregion(int, int, int);
4029static void removerecordregions(int);
4030static void ifsbreakup(char *, struct arglist *);
4031static void ifsfree(void);
4032static void expandmeta(struct strlist *, int);
4033
Eric Andersen62483552001-07-10 06:09:16 +00004034#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00004035#define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB)
4036#if !defined(GLOB_BROKEN)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00004037static void addglob(const glob_t *);
Eric Andersencb57d552001-06-28 07:25:16 +00004038#endif
4039#endif
Eric Andersen62483552001-07-10 06:09:16 +00004040#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004041static void expmeta(char *, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004042#endif
Eric Andersen62483552001-07-10 06:09:16 +00004043#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004044static struct strlist *expsort(struct strlist *);
4045static struct strlist *msort(struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004046#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004047static int patmatch(char *, char *, int);
4048
Eric Andersen62483552001-07-10 06:09:16 +00004049#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004050static int patmatch2(char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004051#else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004052static int pmatch(char *, char *, int);
4053
Eric Andersencb57d552001-06-28 07:25:16 +00004054#define patmatch2 patmatch
4055#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004056static char *cvtnum(int, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004057
4058/*
4059 * Expand shell variables and backquotes inside a here document.
4060 */
4061
Eric Andersen2870d962001-07-02 17:27:21 +00004062/* arg: the document, fd: where to write the expanded version */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004063static inline void expandhere(union node *arg, int fd)
Eric Andersen2870d962001-07-02 17:27:21 +00004064{
Eric Andersencb57d552001-06-28 07:25:16 +00004065 herefd = fd;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004066 expandarg(arg, (struct arglist *) NULL, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00004067 xwrite(fd, stackblock(), expdest - stackblock());
4068}
4069
4070
4071/*
4072 * Perform variable substitution and command substitution on an argument,
4073 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4074 * perform splitting and file name expansion. When arglist is NULL, perform
4075 * here document expansion.
4076 */
4077
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004078static void expandarg(union node *arg, struct arglist *arglist, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004079{
4080 struct strlist *sp;
4081 char *p;
4082
4083 argbackq = arg->narg.backquote;
4084 STARTSTACKSTR(expdest);
4085 ifsfirst.next = NULL;
4086 ifslastp = NULL;
4087 argstr(arg->narg.text, flag);
4088 if (arglist == NULL) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004089 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004090 }
4091 STPUTC('\0', expdest);
4092 p = grabstackstr(expdest);
4093 exparg.lastp = &exparg.list;
4094 /*
4095 * TODO - EXP_REDIR
4096 */
4097 if (flag & EXP_FULL) {
4098 ifsbreakup(p, &exparg);
4099 *exparg.lastp = NULL;
4100 exparg.lastp = &exparg.list;
4101 expandmeta(exparg.list, flag);
4102 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004103 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
Eric Andersencb57d552001-06-28 07:25:16 +00004104 rmescapes(p);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004105 sp = (struct strlist *) stalloc(sizeof(struct strlist));
Eric Andersencb57d552001-06-28 07:25:16 +00004106 sp->text = p;
4107 *exparg.lastp = sp;
4108 exparg.lastp = &sp->next;
4109 }
4110 ifsfree();
4111 *exparg.lastp = NULL;
4112 if (exparg.list) {
4113 *arglist->lastp = exparg.list;
4114 arglist->lastp = exparg.lastp;
4115 }
4116}
4117
4118
Eric Andersen62483552001-07-10 06:09:16 +00004119/*
4120 * Expand a variable, and return a pointer to the next character in the
4121 * input string.
4122 */
4123
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004124static inline char *evalvar(char *p, int flag)
Eric Andersen62483552001-07-10 06:09:16 +00004125{
4126 int subtype;
4127 int varflags;
4128 char *var;
4129 const char *val;
4130 int patloc;
4131 int c;
4132 int set;
4133 int special;
4134 int startloc;
4135 int varlen;
4136 int easy;
4137 int quotes = flag & (EXP_FULL | EXP_CASE);
4138
4139 varflags = *p++;
4140 subtype = varflags & VSTYPE;
4141 var = p;
4142 special = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004143 if (!is_name(*p))
Eric Andersen62483552001-07-10 06:09:16 +00004144 special = 1;
4145 p = strchr(p, '=') + 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004146 again: /* jump here after setting a variable with ${var=text} */
Eric Andersen62483552001-07-10 06:09:16 +00004147 if (special) {
4148 set = varisset(var, varflags & VSNUL);
4149 val = NULL;
4150 } else {
4151 val = lookupvar(var);
4152 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
4153 val = NULL;
4154 set = 0;
4155 } else
4156 set = 1;
4157 }
4158 varlen = 0;
4159 startloc = expdest - stackblock();
4160 if (set && subtype != VSPLUS) {
4161 /* insert the value of the variable */
4162 if (special) {
4163 varvalue(var, varflags & VSQUOTE, flag);
4164 if (subtype == VSLENGTH) {
4165 varlen = expdest - stackblock() - startloc;
4166 STADJUST(-varlen, expdest);
4167 }
4168 } else {
4169 if (subtype == VSLENGTH) {
4170 varlen = strlen(val);
4171 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004172 strtodest(val,
4173 varflags & VSQUOTE ? DQSYNTAX : BASESYNTAX, quotes);
Eric Andersen62483552001-07-10 06:09:16 +00004174 }
4175 }
4176 }
4177
4178 if (subtype == VSPLUS)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004179 set = !set;
Eric Andersen62483552001-07-10 06:09:16 +00004180
4181 easy = ((varflags & VSQUOTE) == 0 ||
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004182 (*var == '@' && shellparam.nparam != 1));
Eric Andersen62483552001-07-10 06:09:16 +00004183
4184
4185 switch (subtype) {
4186 case VSLENGTH:
4187 expdest = cvtnum(varlen, expdest);
4188 goto record;
4189
4190 case VSNORMAL:
4191 if (!easy)
4192 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004193 record:
4194 recordregion(startloc, expdest - stackblock(), varflags & VSQUOTE);
Eric Andersen62483552001-07-10 06:09:16 +00004195 break;
4196
4197 case VSPLUS:
4198 case VSMINUS:
4199 if (!set) {
4200 argstr(p, flag);
4201 break;
4202 }
4203 if (easy)
4204 goto record;
4205 break;
4206
4207 case VSTRIMLEFT:
4208 case VSTRIMLEFTMAX:
4209 case VSTRIMRIGHT:
4210 case VSTRIMRIGHTMAX:
4211 if (!set)
4212 break;
4213 /*
4214 * Terminate the string and start recording the pattern
4215 * right after it
4216 */
4217 STPUTC('\0', expdest);
4218 patloc = expdest - stackblock();
4219 if (subevalvar(p, NULL, patloc, subtype,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004220 startloc, varflags, quotes) == 0) {
Eric Andersen62483552001-07-10 06:09:16 +00004221 int amount = (expdest - stackblock() - patloc) + 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004222
Eric Andersen62483552001-07-10 06:09:16 +00004223 STADJUST(-amount, expdest);
4224 }
4225 /* Remove any recorded regions beyond start of variable */
4226 removerecordregions(startloc);
4227 goto record;
4228
4229 case VSASSIGN:
4230 case VSQUESTION:
4231 if (!set) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004232 if (subevalvar(p, var, 0, subtype, startloc, varflags, quotes)) {
Eric Andersen62483552001-07-10 06:09:16 +00004233 varflags &= ~VSNUL;
4234 /*
4235 * Remove any recorded regions beyond
4236 * start of variable
4237 */
4238 removerecordregions(startloc);
4239 goto again;
4240 }
4241 break;
4242 }
4243 if (easy)
4244 goto record;
4245 break;
4246
4247#ifdef DEBUG
4248 default:
4249 abort();
4250#endif
4251 }
4252
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004253 if (subtype != VSNORMAL) { /* skip to end of alternative */
Eric Andersen62483552001-07-10 06:09:16 +00004254 int nesting = 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004255
Eric Andersen62483552001-07-10 06:09:16 +00004256 for (;;) {
4257 if ((c = *p++) == CTLESC)
4258 p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004259 else if (c == CTLBACKQ || c == (CTLBACKQ | CTLQUOTE)) {
Eric Andersen62483552001-07-10 06:09:16 +00004260 if (set)
4261 argbackq = argbackq->next;
4262 } else if (c == CTLVAR) {
4263 if ((*p++ & VSTYPE) != VSNORMAL)
4264 nesting++;
4265 } else if (c == CTLENDVAR) {
4266 if (--nesting == 0)
4267 break;
4268 }
4269 }
4270 }
4271 return p;
4272}
4273
Eric Andersencb57d552001-06-28 07:25:16 +00004274
4275/*
4276 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4277 * characters to allow for further processing. Otherwise treat
4278 * $@ like $* since no splitting will be performed.
4279 */
4280
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004281static void argstr(char *p, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004282{
4283 char c;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004284 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
Eric Andersencb57d552001-06-28 07:25:16 +00004285 int firsteq = 1;
4286
4287 if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
4288 p = exptilde(p, flag);
4289 for (;;) {
4290 switch (c = *p++) {
4291 case '\0':
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004292 case CTLENDVAR: /* ??? */
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004293 return;
Eric Andersencb57d552001-06-28 07:25:16 +00004294 case CTLQUOTEMARK:
4295 /* "$@" syntax adherence hack */
4296 if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
4297 break;
4298 if ((flag & EXP_FULL) != 0)
4299 STPUTC(c, expdest);
4300 break;
4301 case CTLESC:
4302 if (quotes)
4303 STPUTC(c, expdest);
4304 c = *p++;
4305 STPUTC(c, expdest);
4306 break;
4307 case CTLVAR:
4308 p = evalvar(p, flag);
4309 break;
4310 case CTLBACKQ:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004311 case CTLBACKQ | CTLQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +00004312 expbackq(argbackq->n, c & CTLQUOTE, flag);
4313 argbackq = argbackq->next;
4314 break;
Eric Andersend35c5df2002-01-09 15:37:36 +00004315#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +00004316 case CTLENDARI:
4317 expari(flag);
4318 break;
Eric Andersen2870d962001-07-02 17:27:21 +00004319#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004320 case ':':
4321 case '=':
4322 /*
4323 * sort of a hack - expand tildes in variable
4324 * assignments (after the first '=' and after ':'s).
4325 */
4326 STPUTC(c, expdest);
4327 if (flag & EXP_VARTILDE && *p == '~') {
4328 if (c == '=') {
4329 if (firsteq)
4330 firsteq = 0;
4331 else
4332 break;
4333 }
4334 p = exptilde(p, flag);
4335 }
4336 break;
4337 default:
4338 STPUTC(c, expdest);
4339 }
4340 }
Eric Andersencb57d552001-06-28 07:25:16 +00004341}
4342
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004343static char *exptilde(char *p, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004344{
4345 char c, *startp = p;
4346 struct passwd *pw;
4347 const char *home;
4348 int quotes = flag & (EXP_FULL | EXP_CASE);
4349
4350 while ((c = *p) != '\0') {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004351 switch (c) {
Eric Andersencb57d552001-06-28 07:25:16 +00004352 case CTLESC:
4353 return (startp);
4354 case CTLQUOTEMARK:
4355 return (startp);
4356 case ':':
4357 if (flag & EXP_VARTILDE)
4358 goto done;
4359 break;
4360 case '/':
4361 goto done;
4362 }
4363 p++;
4364 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004365 done:
Eric Andersencb57d552001-06-28 07:25:16 +00004366 *p = '\0';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004367 if (*(startp + 1) == '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00004368 if ((home = lookupvar("HOME")) == NULL)
4369 goto lose;
4370 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004371 if ((pw = getpwnam(startp + 1)) == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00004372 goto lose;
4373 home = pw->pw_dir;
4374 }
4375 if (*home == '\0')
4376 goto lose;
4377 *p = c;
4378 strtodest(home, SQSYNTAX, quotes);
4379 return (p);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004380 lose:
Eric Andersencb57d552001-06-28 07:25:16 +00004381 *p = c;
4382 return (startp);
4383}
4384
4385
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004386static void removerecordregions(int endoff)
Eric Andersencb57d552001-06-28 07:25:16 +00004387{
4388 if (ifslastp == NULL)
4389 return;
4390
4391 if (ifsfirst.endoff > endoff) {
4392 while (ifsfirst.next != NULL) {
4393 struct ifsregion *ifsp;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004394
Eric Andersencb57d552001-06-28 07:25:16 +00004395 INTOFF;
4396 ifsp = ifsfirst.next->next;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00004397 free(ifsfirst.next);
Eric Andersencb57d552001-06-28 07:25:16 +00004398 ifsfirst.next = ifsp;
4399 INTON;
4400 }
4401 if (ifsfirst.begoff > endoff)
4402 ifslastp = NULL;
4403 else {
4404 ifslastp = &ifsfirst;
4405 ifsfirst.endoff = endoff;
4406 }
4407 return;
4408 }
Eric Andersen2870d962001-07-02 17:27:21 +00004409
Eric Andersencb57d552001-06-28 07:25:16 +00004410 ifslastp = &ifsfirst;
4411 while (ifslastp->next && ifslastp->next->begoff < endoff)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004412 ifslastp = ifslastp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00004413 while (ifslastp->next != NULL) {
4414 struct ifsregion *ifsp;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004415
Eric Andersencb57d552001-06-28 07:25:16 +00004416 INTOFF;
4417 ifsp = ifslastp->next->next;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00004418 free(ifslastp->next);
Eric Andersencb57d552001-06-28 07:25:16 +00004419 ifslastp->next = ifsp;
4420 INTON;
4421 }
4422 if (ifslastp->endoff > endoff)
4423 ifslastp->endoff = endoff;
4424}
4425
4426
Eric Andersend35c5df2002-01-09 15:37:36 +00004427#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +00004428/*
4429 * Expand arithmetic expression. Backup to start of expression,
4430 * evaluate, place result in (backed up) result, adjust string position.
4431 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004432static void expari(int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004433{
4434 char *p, *start;
Eric Andersen34506362001-08-02 05:02:46 +00004435 int errcode;
Eric Andersencb57d552001-06-28 07:25:16 +00004436 int result;
4437 int begoff;
4438 int quotes = flag & (EXP_FULL | EXP_CASE);
4439 int quoted;
4440
Eric Andersen2870d962001-07-02 17:27:21 +00004441 /* ifsfree(); */
Eric Andersencb57d552001-06-28 07:25:16 +00004442
4443 /*
4444 * This routine is slightly over-complicated for
4445 * efficiency. First we make sure there is
4446 * enough space for the result, which may be bigger
4447 * than the expression if we add exponentation. Next we
4448 * scan backwards looking for the start of arithmetic. If the
4449 * next previous character is a CTLESC character, then we
4450 * have to rescan starting from the beginning since CTLESC
4451 * characters have to be processed left to right.
4452 */
4453 CHECKSTRSPACE(10, expdest);
4454 USTPUTC('\0', expdest);
4455 start = stackblock();
4456 p = expdest - 1;
4457 while (*p != CTLARI && p >= start)
4458 --p;
4459 if (*p != CTLARI)
4460 error("missing CTLARI (shouldn't happen)");
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004461 if (p > start && *(p - 1) == CTLESC)
Eric Andersencb57d552001-06-28 07:25:16 +00004462 for (p = start; *p != CTLARI; p++)
4463 if (*p == CTLESC)
4464 p++;
4465
4466 if (p[1] == '"')
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004467 quoted = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00004468 else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004469 quoted = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004470 begoff = p - start;
4471 removerecordregions(begoff);
4472 if (quotes)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004473 rmescapes(p + 2);
4474 result = arith(p + 2, &errcode);
Eric Andersen34506362001-08-02 05:02:46 +00004475 if (errcode < 0) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004476 if (errcode == -2)
Eric Andersen34506362001-08-02 05:02:46 +00004477 error("divide by zero");
4478 else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004479 error("syntax error: \"%s\"\n", p + 2);
Eric Andersen34506362001-08-02 05:02:46 +00004480 }
Eric Andersen3102ac42001-07-06 04:26:23 +00004481 snprintf(p, 12, "%d", result);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004482 while (*p++);
Eric Andersencb57d552001-06-28 07:25:16 +00004483
4484 if (quoted == 0)
4485 recordregion(begoff, p - 1 - start, 0);
4486 result = expdest - p + 1;
4487 STADJUST(-result, expdest);
4488}
Eric Andersen2870d962001-07-02 17:27:21 +00004489#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004490
4491/*
4492 * Expand stuff in backwards quotes.
4493 */
4494
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004495static void expbackq(union node *cmd, int quoted, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004496{
4497 volatile struct backcmd in;
4498 int i;
4499 char buf[128];
4500 char *p;
4501 char *dest = expdest;
4502 volatile struct ifsregion saveifs;
4503 struct ifsregion *volatile savelastp;
4504 struct nodelist *volatile saveargbackq;
4505 char lastc;
4506 int startloc = dest - stackblock();
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004507 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +00004508 volatile int saveherefd;
4509 int quotes = flag & (EXP_FULL | EXP_CASE);
4510 struct jmploc jmploc;
4511 struct jmploc *volatile savehandler;
4512 int ex;
4513
4514#if __GNUC__
4515 /* Avoid longjmp clobbering */
4516 (void) &dest;
4517 (void) &syntax;
4518#endif
4519
4520 in.fd = -1;
4521 in.buf = 0;
4522 in.jp = 0;
4523
4524 INTOFF;
4525 saveifs = ifsfirst;
4526 savelastp = ifslastp;
4527 saveargbackq = argbackq;
4528 saveherefd = herefd;
4529 herefd = -1;
4530 if ((ex = setjmp(jmploc.loc))) {
4531 goto err1;
4532 }
4533 savehandler = handler;
4534 handler = &jmploc;
4535 INTON;
4536 p = grabstackstr(dest);
4537 evalbackcmd(cmd, (struct backcmd *) &in);
4538 ungrabstackstr(p, dest);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004539 err1:
Eric Andersencb57d552001-06-28 07:25:16 +00004540 INTOFF;
4541 ifsfirst = saveifs;
4542 ifslastp = savelastp;
4543 argbackq = saveargbackq;
4544 herefd = saveherefd;
4545 if (ex) {
4546 goto err2;
4547 }
4548
4549 p = in.buf;
4550 lastc = '\0';
4551 for (;;) {
4552 if (--in.nleft < 0) {
4553 if (in.fd < 0)
4554 break;
Eric Andersen7467c8d2001-07-12 20:26:32 +00004555 i = safe_read(in.fd, buf, sizeof buf);
Eric Andersencb57d552001-06-28 07:25:16 +00004556 TRACE(("expbackq: read returns %d\n", i));
4557 if (i <= 0)
4558 break;
4559 p = buf;
4560 in.nleft = i - 1;
4561 }
4562 lastc = *p++;
4563 if (lastc != '\0') {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004564 if (quotes && SIT(lastc, syntax) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +00004565 STPUTC(CTLESC, dest);
4566 STPUTC(lastc, dest);
4567 }
4568 }
4569
4570 /* Eat all trailing newlines */
4571 for (; dest > stackblock() && dest[-1] == '\n';)
4572 STUNPUTC(dest);
4573
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004574 err2:
Eric Andersencb57d552001-06-28 07:25:16 +00004575 if (in.fd >= 0)
4576 close(in.fd);
Aaron Lehmann49c024a2002-08-02 06:39:47 +00004577 free(in.buf);
Eric Andersencb57d552001-06-28 07:25:16 +00004578 if (in.jp)
4579 exitstatus = waitforjob(in.jp);
4580 handler = savehandler;
4581 if (ex) {
4582 longjmp(handler->loc, 1);
4583 }
4584 if (quoted == 0)
4585 recordregion(startloc, dest - stackblock(), 0);
4586 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004587 (dest - stackblock()) - startloc,
4588 (dest - stackblock()) - startloc, stackblock() + startloc));
Eric Andersencb57d552001-06-28 07:25:16 +00004589 expdest = dest;
4590 INTON;
4591}
4592
Eric Andersencb57d552001-06-28 07:25:16 +00004593static int
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004594subevalvar(char *p, char *str, int strloc, int subtype, int startloc,
4595 int varflags, int quotes)
Eric Andersencb57d552001-06-28 07:25:16 +00004596{
4597 char *startp;
4598 char *loc = NULL;
4599 char *q;
4600 int c = 0;
4601 int saveherefd = herefd;
4602 struct nodelist *saveargbackq = argbackq;
4603 int amount;
4604
4605 herefd = -1;
4606 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
4607 STACKSTRNUL(expdest);
4608 herefd = saveherefd;
4609 argbackq = saveargbackq;
4610 startp = stackblock() + startloc;
4611 if (str == NULL)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004612 str = stackblock() + strloc;
Eric Andersencb57d552001-06-28 07:25:16 +00004613
4614 switch (subtype) {
4615 case VSASSIGN:
4616 setvar(str, startp, 0);
4617 amount = startp - expdest;
4618 STADJUST(amount, expdest);
4619 varflags &= ~VSNUL;
4620 if (c != 0)
4621 *loc = c;
4622 return 1;
4623
4624 case VSQUESTION:
4625 if (*p != CTLENDVAR) {
Eric Andersen3102ac42001-07-06 04:26:23 +00004626 out2fmt(snlfmt, startp);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004627 error((char *) NULL);
Eric Andersencb57d552001-06-28 07:25:16 +00004628 }
4629 error("%.*s: parameter %snot set", p - str - 1,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004630 str, (varflags & VSNUL) ? "null or " : nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +00004631 /* NOTREACHED */
4632
4633 case VSTRIMLEFT:
4634 for (loc = startp; loc < str; loc++) {
4635 c = *loc;
4636 *loc = '\0';
4637 if (patmatch2(str, startp, quotes))
4638 goto recordleft;
4639 *loc = c;
4640 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00004641 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00004642 }
4643 return 0;
4644
4645 case VSTRIMLEFTMAX:
4646 for (loc = str - 1; loc >= startp;) {
4647 c = *loc;
4648 *loc = '\0';
4649 if (patmatch2(str, startp, quotes))
4650 goto recordleft;
4651 *loc = c;
4652 loc--;
4653 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
4654 for (q = startp; q < loc; q++)
4655 if (*q == CTLESC)
4656 q++;
4657 if (q > loc)
4658 loc--;
4659 }
4660 }
4661 return 0;
4662
4663 case VSTRIMRIGHT:
Eric Andersen2870d962001-07-02 17:27:21 +00004664 for (loc = str - 1; loc >= startp;) {
Eric Andersencb57d552001-06-28 07:25:16 +00004665 if (patmatch2(str, loc, quotes))
4666 goto recordright;
4667 loc--;
Eric Andersen2870d962001-07-02 17:27:21 +00004668 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
Eric Andersencb57d552001-06-28 07:25:16 +00004669 for (q = startp; q < loc; q++)
4670 if (*q == CTLESC)
4671 q++;
4672 if (q > loc)
4673 loc--;
4674 }
4675 }
4676 return 0;
4677
4678 case VSTRIMRIGHTMAX:
4679 for (loc = startp; loc < str - 1; loc++) {
4680 if (patmatch2(str, loc, quotes))
4681 goto recordright;
4682 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00004683 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00004684 }
4685 return 0;
4686
4687#ifdef DEBUG
4688 default:
4689 abort();
4690#endif
4691 }
4692
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004693 recordleft:
Eric Andersencb57d552001-06-28 07:25:16 +00004694 *loc = c;
4695 amount = ((str - 1) - (loc - startp)) - expdest;
4696 STADJUST(amount, expdest);
4697 while (loc != str - 1)
4698 *startp++ = *loc++;
4699 return 1;
4700
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004701 recordright:
Eric Andersencb57d552001-06-28 07:25:16 +00004702 amount = loc - expdest;
4703 STADJUST(amount, expdest);
4704 STPUTC('\0', expdest);
4705 STADJUST(-1, expdest);
4706 return 1;
4707}
4708
4709
4710/*
Eric Andersencb57d552001-06-28 07:25:16 +00004711 * Test whether a specialized variable is set.
4712 */
4713
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004714static int varisset(char *name, int nulok)
Eric Andersencb57d552001-06-28 07:25:16 +00004715{
4716 if (*name == '!')
4717 return backgndpid != -1;
4718 else if (*name == '@' || *name == '*') {
4719 if (*shellparam.p == NULL)
4720 return 0;
4721
4722 if (nulok) {
4723 char **av;
4724
4725 for (av = shellparam.p; *av; av++)
4726 if (**av != '\0')
4727 return 1;
4728 return 0;
4729 }
4730 } else if (is_digit(*name)) {
4731 char *ap;
4732 int num = atoi(name);
4733
4734 if (num > shellparam.nparam)
4735 return 0;
4736
4737 if (num == 0)
4738 ap = arg0;
4739 else
4740 ap = shellparam.p[num - 1];
4741
4742 if (nulok && (ap == NULL || *ap == '\0'))
4743 return 0;
4744 }
4745 return 1;
4746}
4747
Eric Andersencb57d552001-06-28 07:25:16 +00004748/*
4749 * Put a string on the stack.
4750 */
4751
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004752static void strtodest(const char *p, int syntax, int quotes)
Eric Andersencb57d552001-06-28 07:25:16 +00004753{
4754 while (*p) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004755 if (quotes && SIT(*p, syntax) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +00004756 STPUTC(CTLESC, expdest);
4757 STPUTC(*p++, expdest);
4758 }
4759}
4760
Eric Andersencb57d552001-06-28 07:25:16 +00004761/*
4762 * Add the value of a specialized variable to the stack string.
4763 */
4764
Glenn L McGrath50812ff2002-08-23 13:14:48 +00004765static void varvalue(char *name, int quoted, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00004766{
4767 int num;
4768 char *p;
4769 int i;
4770 int sep;
4771 int sepq = 0;
4772 char **ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004773 int syntax;
Eric Andersencb57d552001-06-28 07:25:16 +00004774 int allow_split = flags & EXP_FULL;
4775 int quotes = flags & (EXP_FULL | EXP_CASE);
4776
4777 syntax = quoted ? DQSYNTAX : BASESYNTAX;
4778 switch (*name) {
4779 case '$':
4780 num = rootpid;
4781 goto numvar;
4782 case '?':
4783 num = oexitstatus;
4784 goto numvar;
4785 case '#':
4786 num = shellparam.nparam;
4787 goto numvar;
4788 case '!':
4789 num = backgndpid;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004790 numvar:
Eric Andersencb57d552001-06-28 07:25:16 +00004791 expdest = cvtnum(num, expdest);
4792 break;
4793 case '-':
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004794 for (i = 0; i < NOPTS; i++) {
Eric Andersen2870d962001-07-02 17:27:21 +00004795 if (optent_val(i))
4796 STPUTC(optent_letter(optlist[i]), expdest);
Eric Andersencb57d552001-06-28 07:25:16 +00004797 }
4798 break;
4799 case '@':
4800 if (allow_split && quoted) {
4801 sep = 1 << CHAR_BIT;
4802 goto param;
4803 }
4804 /* fall through */
4805 case '*':
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004806 sep = ifsset()? ifsval()[0] : ' ';
Eric Andersencb57d552001-06-28 07:25:16 +00004807 if (quotes) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004808 sepq = SIT(sep, syntax) == CCTL;
Eric Andersencb57d552001-06-28 07:25:16 +00004809 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004810 param:
4811 for (ap = shellparam.p; (p = *ap++) != NULL;) {
Eric Andersencb57d552001-06-28 07:25:16 +00004812 strtodest(p, syntax, quotes);
4813 if (*ap && sep) {
4814 if (sepq)
4815 STPUTC(CTLESC, expdest);
4816 STPUTC(sep, expdest);
4817 }
4818 }
4819 break;
4820 case '0':
4821 strtodest(arg0, syntax, quotes);
4822 break;
4823 default:
4824 num = atoi(name);
4825 if (num > 0 && num <= shellparam.nparam) {
4826 strtodest(shellparam.p[num - 1], syntax, quotes);
4827 }
4828 break;
4829 }
4830}
4831
4832
Eric Andersencb57d552001-06-28 07:25:16 +00004833/*
4834 * Record the fact that we have to scan this region of the
4835 * string for IFS characters.
4836 */
4837
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004838static void recordregion(int start, int end, int nulonly)
Eric Andersencb57d552001-06-28 07:25:16 +00004839{
4840 struct ifsregion *ifsp;
4841
4842 if (ifslastp == NULL) {
4843 ifsp = &ifsfirst;
4844 } else {
4845 INTOFF;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004846 ifsp = (struct ifsregion *) xmalloc(sizeof(struct ifsregion));
Eric Andersencb57d552001-06-28 07:25:16 +00004847 ifsp->next = NULL;
4848 ifslastp->next = ifsp;
4849 INTON;
4850 }
4851 ifslastp = ifsp;
4852 ifslastp->begoff = start;
4853 ifslastp->endoff = end;
4854 ifslastp->nulonly = nulonly;
4855}
4856
4857
4858
4859/*
4860 * Break the argument string into pieces based upon IFS and add the
4861 * strings to the argument list. The regions of the string to be
4862 * searched for IFS characters have been stored by recordregion.
4863 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004864static void ifsbreakup(char *string, struct arglist *arglist)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004865{
Eric Andersencb57d552001-06-28 07:25:16 +00004866 struct ifsregion *ifsp;
4867 struct strlist *sp;
4868 char *start;
4869 char *p;
4870 char *q;
4871 const char *ifs, *realifs;
4872 int ifsspc;
4873 int nulonly;
4874
4875
4876 start = string;
4877 ifsspc = 0;
4878 nulonly = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004879 realifs = ifsset()? ifsval() : defifs;
Eric Andersencb57d552001-06-28 07:25:16 +00004880 if (ifslastp != NULL) {
4881 ifsp = &ifsfirst;
4882 do {
4883 p = string + ifsp->begoff;
4884 nulonly = ifsp->nulonly;
4885 ifs = nulonly ? nullstr : realifs;
4886 ifsspc = 0;
4887 while (p < string + ifsp->endoff) {
4888 q = p;
4889 if (*p == CTLESC)
4890 p++;
4891 if (strchr(ifs, *p)) {
4892 if (!nulonly)
4893 ifsspc = (strchr(defifs, *p) != NULL);
4894 /* Ignore IFS whitespace at start */
4895 if (q == start && ifsspc) {
4896 p++;
4897 start = p;
4898 continue;
4899 }
4900 *q = '\0';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004901 sp = (struct strlist *) stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00004902 sp->text = start;
4903 *arglist->lastp = sp;
4904 arglist->lastp = &sp->next;
4905 p++;
4906 if (!nulonly) {
4907 for (;;) {
4908 if (p >= string + ifsp->endoff) {
4909 break;
4910 }
4911 q = p;
4912 if (*p == CTLESC)
4913 p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004914 if (strchr(ifs, *p) == NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00004915 p = q;
4916 break;
4917 } else if (strchr(defifs, *p) == NULL) {
4918 if (ifsspc) {
4919 p++;
4920 ifsspc = 0;
4921 } else {
4922 p = q;
4923 break;
4924 }
4925 } else
4926 p++;
4927 }
4928 }
4929 start = p;
4930 } else
4931 p++;
4932 }
4933 } while ((ifsp = ifsp->next) != NULL);
4934 if (!(*start || (!ifsspc && start > string && nulonly))) {
4935 return;
4936 }
4937 }
4938
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004939 sp = (struct strlist *) stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00004940 sp->text = start;
4941 *arglist->lastp = sp;
4942 arglist->lastp = &sp->next;
4943}
4944
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004945static void ifsfree(void)
Eric Andersencb57d552001-06-28 07:25:16 +00004946{
4947 while (ifsfirst.next != NULL) {
4948 struct ifsregion *ifsp;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004949
Eric Andersencb57d552001-06-28 07:25:16 +00004950 INTOFF;
4951 ifsp = ifsfirst.next->next;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00004952 free(ifsfirst.next);
Eric Andersencb57d552001-06-28 07:25:16 +00004953 ifsfirst.next = ifsp;
4954 INTON;
4955 }
4956 ifslastp = NULL;
4957 ifsfirst.next = NULL;
4958}
4959
Eric Andersen2870d962001-07-02 17:27:21 +00004960/*
4961 * Add a file name to the list.
4962 */
Eric Andersencb57d552001-06-28 07:25:16 +00004963
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004964static void addfname(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00004965{
Eric Andersen2870d962001-07-02 17:27:21 +00004966 struct strlist *sp;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00004967 size_t len = strlen(name) + 1;
Eric Andersen2870d962001-07-02 17:27:21 +00004968
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004969 sp = (struct strlist *) stalloc(sizeof *sp);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00004970 sp->text = memcpy(stalloc(len), name, len);
Eric Andersen2870d962001-07-02 17:27:21 +00004971 *exparg.lastp = sp;
4972 exparg.lastp = &sp->next;
4973}
Eric Andersencb57d552001-06-28 07:25:16 +00004974
4975/*
4976 * Expand shell metacharacters. At this point, the only control characters
4977 * should be escapes. The results are stored in the list exparg.
4978 */
4979
Eric Andersen62483552001-07-10 06:09:16 +00004980#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004981static void expandmeta(struct strlist *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004982{
4983 const char *p;
4984 glob_t pglob;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004985
Eric Andersencb57d552001-06-28 07:25:16 +00004986 /* TODO - EXP_REDIR */
4987
4988 while (str) {
4989 if (fflag)
4990 goto nometa;
4991 p = preglob(str->text);
4992 INTOFF;
Eric Andersen34506362001-08-02 05:02:46 +00004993 switch (glob(p, 0, 0, &pglob)) {
Eric Andersencb57d552001-06-28 07:25:16 +00004994 case 0:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004995 if (pglob.gl_pathv[1] == 0 && !strcmp(p, pglob.gl_pathv[0]))
Eric Andersencb57d552001-06-28 07:25:16 +00004996 goto nometa2;
4997 addglob(&pglob);
4998 globfree(&pglob);
4999 INTON;
5000 break;
5001 case GLOB_NOMATCH:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005002 nometa2:
Eric Andersencb57d552001-06-28 07:25:16 +00005003 globfree(&pglob);
5004 INTON;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005005 nometa:
Eric Andersencb57d552001-06-28 07:25:16 +00005006 *exparg.lastp = str;
5007 rmescapes(str->text);
5008 exparg.lastp = &str->next;
5009 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005010 default: /* GLOB_NOSPACE */
Eric Andersencb57d552001-06-28 07:25:16 +00005011 error("Out of space");
5012 }
5013 str = str->next;
5014 }
5015}
5016
5017
5018/*
5019 * Add the result of glob(3) to the list.
5020 */
5021
Glenn L McGrath50812ff2002-08-23 13:14:48 +00005022static void addglob(const glob_t * pglob)
Eric Andersencb57d552001-06-28 07:25:16 +00005023{
5024 char **p = pglob->gl_pathv;
5025
5026 do {
5027 addfname(*p);
5028 } while (*++p);
5029}
5030
5031
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005032#else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005033static char *expdir;
5034
5035
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005036static void expandmeta(struct strlist *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005037{
5038 char *p;
5039 struct strlist **savelastp;
5040 struct strlist *sp;
5041 char c;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005042
Eric Andersencb57d552001-06-28 07:25:16 +00005043 /* TODO - EXP_REDIR */
5044
5045 while (str) {
5046 if (fflag)
5047 goto nometa;
5048 p = str->text;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005049 for (;;) { /* fast check for meta chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005050 if ((c = *p++) == '\0')
5051 goto nometa;
5052 if (c == '*' || c == '?' || c == '[' || c == '!')
5053 break;
5054 }
5055 savelastp = exparg.lastp;
5056 INTOFF;
5057 if (expdir == NULL) {
5058 int i = strlen(str->text);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005059
5060 expdir = xmalloc(i < 2048 ? 2048 : i); /* XXX */
Eric Andersencb57d552001-06-28 07:25:16 +00005061 }
5062
5063 expmeta(expdir, str->text);
Aaron Lehmann49c024a2002-08-02 06:39:47 +00005064 free(expdir);
Eric Andersencb57d552001-06-28 07:25:16 +00005065 expdir = NULL;
5066 INTON;
5067 if (exparg.lastp == savelastp) {
5068 /*
5069 * no matches
5070 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005071 nometa:
Eric Andersencb57d552001-06-28 07:25:16 +00005072 *exparg.lastp = str;
5073 rmescapes(str->text);
5074 exparg.lastp = &str->next;
5075 } else {
5076 *exparg.lastp = NULL;
5077 *savelastp = sp = expsort(*savelastp);
5078 while (sp->next != NULL)
5079 sp = sp->next;
5080 exparg.lastp = &sp->next;
5081 }
5082 str = str->next;
5083 }
5084}
5085
5086
5087/*
5088 * Do metacharacter (i.e. *, ?, [...]) expansion.
5089 */
5090
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005091static void expmeta(char *enddir, char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005092{
Eric Andersencb57d552001-06-28 07:25:16 +00005093 char *p;
5094 const char *cp;
5095 char *q;
5096 char *start;
5097 char *endname;
5098 int metaflag;
5099 struct stat statb;
5100 DIR *dirp;
5101 struct dirent *dp;
5102 int atend;
5103 int matchdot;
5104
5105 metaflag = 0;
5106 start = name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005107 for (p = name;; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +00005108 if (*p == '*' || *p == '?')
5109 metaflag = 1;
5110 else if (*p == '[') {
5111 q = p + 1;
5112 if (*q == '!')
5113 q++;
5114 for (;;) {
5115 while (*q == CTLQUOTEMARK)
5116 q++;
5117 if (*q == CTLESC)
5118 q++;
5119 if (*q == '/' || *q == '\0')
5120 break;
5121 if (*++q == ']') {
5122 metaflag = 1;
5123 break;
5124 }
5125 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005126 } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) {
Eric Andersencb57d552001-06-28 07:25:16 +00005127 metaflag = 1;
5128 } else if (*p == '\0')
5129 break;
5130 else if (*p == CTLQUOTEMARK)
5131 continue;
5132 else if (*p == CTLESC)
5133 p++;
5134 if (*p == '/') {
5135 if (metaflag)
5136 break;
5137 start = p + 1;
5138 }
5139 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005140 if (metaflag == 0) { /* we've reached the end of the file name */
Eric Andersencb57d552001-06-28 07:25:16 +00005141 if (enddir != expdir)
5142 metaflag++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005143 for (p = name;; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +00005144 if (*p == CTLQUOTEMARK)
5145 continue;
5146 if (*p == CTLESC)
5147 p++;
5148 *enddir++ = *p;
5149 if (*p == '\0')
5150 break;
5151 }
5152 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5153 addfname(expdir);
5154 return;
5155 }
5156 endname = p;
5157 if (start != name) {
5158 p = name;
5159 while (p < start) {
5160 while (*p == CTLQUOTEMARK)
5161 p++;
5162 if (*p == CTLESC)
5163 p++;
5164 *enddir++ = *p++;
5165 }
5166 }
5167 if (enddir == expdir) {
5168 cp = ".";
5169 } else if (enddir == expdir + 1 && *expdir == '/') {
5170 cp = "/";
5171 } else {
5172 cp = expdir;
5173 enddir[-1] = '\0';
5174 }
5175 if ((dirp = opendir(cp)) == NULL)
5176 return;
5177 if (enddir != expdir)
5178 enddir[-1] = '/';
5179 if (*endname == 0) {
5180 atend = 1;
5181 } else {
5182 atend = 0;
5183 *endname++ = '\0';
5184 }
5185 matchdot = 0;
5186 p = start;
5187 while (*p == CTLQUOTEMARK)
5188 p++;
5189 if (*p == CTLESC)
5190 p++;
5191 if (*p == '.')
5192 matchdot++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005193 while (!int_pending() && (dp = readdir(dirp)) != NULL) {
5194 if (dp->d_name[0] == '.' && !matchdot)
Eric Andersencb57d552001-06-28 07:25:16 +00005195 continue;
5196 if (patmatch(start, dp->d_name, 0)) {
5197 if (atend) {
Eric Andersen2870d962001-07-02 17:27:21 +00005198 strcpy(enddir, dp->d_name);
Eric Andersencb57d552001-06-28 07:25:16 +00005199 addfname(expdir);
5200 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005201 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
Eric Andersencb57d552001-06-28 07:25:16 +00005202 continue;
5203 p[-1] = '/';
5204 expmeta(p, endname);
5205 }
5206 }
5207 }
5208 closedir(dirp);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005209 if (!atend)
Eric Andersencb57d552001-06-28 07:25:16 +00005210 endname[-1] = '/';
5211}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005212#endif /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005213
5214
Eric Andersencb57d552001-06-28 07:25:16 +00005215
Eric Andersen62483552001-07-10 06:09:16 +00005216#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersencb57d552001-06-28 07:25:16 +00005217/*
5218 * Sort the results of file name expansion. It calculates the number of
5219 * strings to sort and then calls msort (short for merge sort) to do the
5220 * work.
5221 */
5222
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005223static struct strlist *expsort(struct strlist *str)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005224{
Eric Andersencb57d552001-06-28 07:25:16 +00005225 int len;
5226 struct strlist *sp;
5227
5228 len = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005229 for (sp = str; sp; sp = sp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00005230 len++;
5231 return msort(str, len);
5232}
5233
5234
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005235static struct strlist *msort(struct strlist *list, int len)
Eric Andersencb57d552001-06-28 07:25:16 +00005236{
5237 struct strlist *p, *q = NULL;
5238 struct strlist **lpp;
5239 int half;
5240 int n;
5241
5242 if (len <= 1)
5243 return list;
5244 half = len >> 1;
5245 p = list;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005246 for (n = half; --n >= 0;) {
Eric Andersencb57d552001-06-28 07:25:16 +00005247 q = p;
5248 p = p->next;
5249 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005250 q->next = NULL; /* terminate first half of list */
5251 q = msort(list, half); /* sort first half of list */
5252 p = msort(p, len - half); /* sort second half */
Eric Andersencb57d552001-06-28 07:25:16 +00005253 lpp = &list;
5254 for (;;) {
5255 if (strcmp(p->text, q->text) < 0) {
5256 *lpp = p;
5257 lpp = &p->next;
5258 if ((p = *lpp) == NULL) {
5259 *lpp = q;
5260 break;
5261 }
5262 } else {
5263 *lpp = q;
5264 lpp = &q->next;
5265 if ((q = *lpp) == NULL) {
5266 *lpp = p;
5267 break;
5268 }
5269 }
5270 }
5271 return list;
5272}
5273#endif
5274
5275
5276
5277/*
5278 * Returns true if the pattern matches the string.
5279 */
5280
Eric Andersen62483552001-07-10 06:09:16 +00005281#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00005282/* squoted: string might have quote chars */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005283static int patmatch(char *pattern, char *string, int squoted)
Eric Andersen2870d962001-07-02 17:27:21 +00005284{
Eric Andersencb57d552001-06-28 07:25:16 +00005285 const char *p;
5286 char *q;
5287
5288 p = preglob(pattern);
5289 q = squoted ? _rmescapes(string, RMESCAPE_ALLOC) : string;
5290
5291 return !fnmatch(p, q, 0);
5292}
5293
5294
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005295static int patmatch2(char *pattern, char *string, int squoted)
Eric Andersen2870d962001-07-02 17:27:21 +00005296{
Eric Andersencb57d552001-06-28 07:25:16 +00005297 char *p;
5298 int res;
5299
5300 sstrnleft--;
5301 p = grabstackstr(expdest);
5302 res = patmatch(pattern, string, squoted);
5303 ungrabstackstr(p, expdest);
5304 return res;
5305}
5306#else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005307static int patmatch(char *pattern, char *string, int squoted)
5308{
Eric Andersen2870d962001-07-02 17:27:21 +00005309 return pmatch(pattern, string, squoted);
Eric Andersencb57d552001-06-28 07:25:16 +00005310}
5311
5312
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005313static int pmatch(char *pattern, char *string, int squoted)
Eric Andersen2870d962001-07-02 17:27:21 +00005314{
Eric Andersencb57d552001-06-28 07:25:16 +00005315 char *p, *q;
5316 char c;
5317
5318 p = pattern;
5319 q = string;
5320 for (;;) {
5321 switch (c = *p++) {
5322 case '\0':
5323 goto breakloop;
5324 case CTLESC:
5325 if (squoted && *q == CTLESC)
5326 q++;
5327 if (*q++ != *p++)
5328 return 0;
5329 break;
5330 case CTLQUOTEMARK:
5331 continue;
5332 case '?':
5333 if (squoted && *q == CTLESC)
5334 q++;
5335 if (*q++ == '\0')
5336 return 0;
5337 break;
5338 case '*':
5339 c = *p;
5340 while (c == CTLQUOTEMARK || c == '*')
5341 c = *++p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005342 if (c != CTLESC && c != CTLQUOTEMARK &&
5343 c != '?' && c != '*' && c != '[') {
Eric Andersencb57d552001-06-28 07:25:16 +00005344 while (*q != c) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005345 if (squoted && *q == CTLESC && q[1] == c)
Eric Andersencb57d552001-06-28 07:25:16 +00005346 break;
5347 if (*q == '\0')
5348 return 0;
5349 if (squoted && *q == CTLESC)
5350 q++;
5351 q++;
5352 }
5353 }
5354 do {
5355 if (pmatch(p, q, squoted))
5356 return 1;
5357 if (squoted && *q == CTLESC)
5358 q++;
5359 } while (*q++ != '\0');
5360 return 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005361 case '[':{
Eric Andersencb57d552001-06-28 07:25:16 +00005362 char *endp;
5363 int invert, found;
5364 char chr;
5365
5366 endp = p;
5367 if (*endp == '!')
5368 endp++;
5369 for (;;) {
5370 while (*endp == CTLQUOTEMARK)
5371 endp++;
5372 if (*endp == '\0')
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005373 goto dft; /* no matching ] */
Eric Andersencb57d552001-06-28 07:25:16 +00005374 if (*endp == CTLESC)
5375 endp++;
5376 if (*++endp == ']')
5377 break;
5378 }
5379 invert = 0;
5380 if (*p == '!') {
5381 invert++;
5382 p++;
5383 }
5384 found = 0;
5385 chr = *q++;
5386 if (squoted && chr == CTLESC)
5387 chr = *q++;
5388 if (chr == '\0')
5389 return 0;
5390 c = *p++;
5391 do {
5392 if (c == CTLQUOTEMARK)
5393 continue;
5394 if (c == CTLESC)
5395 c = *p++;
5396 if (*p == '-' && p[1] != ']') {
5397 p++;
5398 while (*p == CTLQUOTEMARK)
5399 p++;
5400 if (*p == CTLESC)
5401 p++;
5402 if (chr >= c && chr <= *p)
5403 found = 1;
5404 p++;
5405 } else {
5406 if (chr == c)
5407 found = 1;
5408 }
5409 } while ((c = *p++) != ']');
5410 if (found == invert)
5411 return 0;
5412 break;
5413 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005414 dft: default:
Eric Andersencb57d552001-06-28 07:25:16 +00005415 if (squoted && *q == CTLESC)
5416 q++;
5417 if (*q++ != c)
5418 return 0;
5419 break;
5420 }
5421 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005422 breakloop:
Eric Andersencb57d552001-06-28 07:25:16 +00005423 if (*q != '\0')
5424 return 0;
5425 return 1;
5426}
5427#endif
5428
5429
5430
5431/*
5432 * Remove any CTLESC characters from a string.
5433 */
5434
Eric Andersen62483552001-07-10 06:09:16 +00005435#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005436static char *_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005437{
5438 char *p, *q, *r;
5439 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5440
5441 p = strpbrk(str, qchars);
5442 if (!p) {
5443 return str;
5444 }
5445 q = p;
5446 r = str;
5447 if (flag & RMESCAPE_ALLOC) {
5448 size_t len = p - str;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005449
Eric Andersencb57d552001-06-28 07:25:16 +00005450 q = r = stalloc(strlen(p) + len + 1);
5451 if (len > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00005452 memcpy(q, str, len);
5453 q += len;
Eric Andersencb57d552001-06-28 07:25:16 +00005454 }
5455 }
5456 while (*p) {
5457 if (*p == CTLQUOTEMARK) {
5458 p++;
5459 continue;
5460 }
5461 if (*p == CTLESC) {
5462 p++;
5463 if (flag & RMESCAPE_GLOB && *p != '/') {
5464 *q++ = '\\';
5465 }
5466 }
5467 *q++ = *p++;
5468 }
5469 *q = '\0';
5470 return r;
5471}
5472#else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005473static void rmescapes(char *str)
Eric Andersencb57d552001-06-28 07:25:16 +00005474{
5475 char *p, *q;
5476
5477 p = str;
5478 while (*p != CTLESC && *p != CTLQUOTEMARK) {
5479 if (*p++ == '\0')
5480 return;
5481 }
5482 q = p;
5483 while (*p) {
5484 if (*p == CTLQUOTEMARK) {
5485 p++;
5486 continue;
5487 }
5488 if (*p == CTLESC)
5489 p++;
5490 *q++ = *p++;
5491 }
5492 *q = '\0';
5493}
5494#endif
5495
5496
5497
5498/*
5499 * See if a pattern matches in a case statement.
5500 */
5501
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005502static int casematch(union node *pattern, const char *val)
Eric Andersen2870d962001-07-02 17:27:21 +00005503{
Eric Andersencb57d552001-06-28 07:25:16 +00005504 struct stackmark smark;
5505 int result;
5506 char *p;
5507
5508 setstackmark(&smark);
5509 argbackq = pattern->narg.backquote;
5510 STARTSTACKSTR(expdest);
5511 ifslastp = NULL;
5512 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5513 STPUTC('\0', expdest);
5514 p = grabstackstr(expdest);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005515 result = patmatch(p, (char *) val, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00005516 popstackmark(&smark);
5517 return result;
5518}
5519
5520/*
5521 * Our own itoa().
5522 */
5523
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005524static char *cvtnum(int num, char *buf)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005525{
Eric Andersencb57d552001-06-28 07:25:16 +00005526 int len;
5527
5528 CHECKSTRSPACE(32, buf);
5529 len = sprintf(buf, "%d", num);
5530 STADJUST(len, buf);
5531 return buf;
5532}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005533
Eric Andersencb57d552001-06-28 07:25:16 +00005534/*
5535 * Editline and history functions (and glue).
5536 */
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005537static int histcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00005538{
5539 error("not compiled with history support");
5540 /* NOTREACHED */
5541}
5542
5543
Eric Andersencb57d552001-06-28 07:25:16 +00005544struct redirtab {
5545 struct redirtab *next;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005546 short renamed[10]; /* Current ash support only 0-9 descriptors */
Eric Andersen34506362001-08-02 05:02:46 +00005547 /* char on arm (and others) can't be negative */
Eric Andersencb57d552001-06-28 07:25:16 +00005548};
5549
Eric Andersen2870d962001-07-02 17:27:21 +00005550static struct redirtab *redirlist;
Eric Andersencb57d552001-06-28 07:25:16 +00005551
5552extern char **environ;
5553
5554
5555
5556/*
5557 * Initialization code.
5558 */
5559
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005560static void init(void)
5561{
Eric Andersencb57d552001-06-28 07:25:16 +00005562
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005563 /* from cd.c: */
5564 {
5565 curdir = nullstr;
5566 setpwd(0, 0);
5567 }
Eric Andersencb57d552001-06-28 07:25:16 +00005568
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005569 /* from input.c: */
5570 {
5571 basepf.nextc = basepf.buf = basebuf;
5572 }
Eric Andersencb57d552001-06-28 07:25:16 +00005573
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005574 /* from var.c: */
5575 {
5576 char **envp;
5577 char ppid[32];
Eric Andersencb57d552001-06-28 07:25:16 +00005578
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005579 initvar();
5580 for (envp = environ; *envp; envp++) {
5581 if (strchr(*envp, '=')) {
5582 setvareq(*envp, VEXPORT | VTEXTFIXED);
5583 }
5584 }
Eric Andersencb57d552001-06-28 07:25:16 +00005585
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005586 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
5587 setvar("PPID", ppid, 0);
5588 }
Eric Andersencb57d552001-06-28 07:25:16 +00005589}
5590
5591
5592
5593/*
5594 * This routine is called when an error or an interrupt occurs in an
5595 * interactive shell and control is returned to the main command loop.
5596 */
5597
Eric Andersen2870d962001-07-02 17:27:21 +00005598/* 1 == check for aliases, 2 == also check for assignments */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005599static int checkalias; /* also used in no alias mode for check assignments */
Eric Andersen2870d962001-07-02 17:27:21 +00005600
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005601static void reset(void)
5602{
Eric Andersencb57d552001-06-28 07:25:16 +00005603
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005604 /* from eval.c: */
5605 {
5606 evalskip = 0;
5607 loopnest = 0;
5608 funcnest = 0;
5609 }
Eric Andersencb57d552001-06-28 07:25:16 +00005610
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005611 /* from input.c: */
5612 {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00005613 parselleft = parsenleft = 0; /* clear input buffer */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005614 popallfiles();
5615 }
Eric Andersencb57d552001-06-28 07:25:16 +00005616
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005617 /* from parser.c: */
5618 {
5619 tokpushback = 0;
5620 checkkwd = 0;
5621 checkalias = 0;
5622 }
Eric Andersencb57d552001-06-28 07:25:16 +00005623
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005624 /* from redir.c: */
5625 {
5626 while (redirlist)
5627 popredir();
5628 }
Eric Andersencb57d552001-06-28 07:25:16 +00005629
Eric Andersencb57d552001-06-28 07:25:16 +00005630}
5631
5632
5633
5634/*
Eric Andersencb57d552001-06-28 07:25:16 +00005635 * This file implements the input routines used by the parser.
5636 */
5637
Eric Andersenbdfd0d72001-10-24 05:00:29 +00005638#ifdef CONFIG_FEATURE_COMMAND_EDITING
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005639static const char *cmdedit_prompt;
5640static inline void putprompt(const char *s)
5641{
5642 cmdedit_prompt = s;
Eric Andersencb57d552001-06-28 07:25:16 +00005643}
5644#else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005645static inline void putprompt(const char *s)
5646{
5647 out2str(s);
Eric Andersencb57d552001-06-28 07:25:16 +00005648}
5649#endif
5650
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005651#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
Eric Andersencb57d552001-06-28 07:25:16 +00005652
Eric Andersencb57d552001-06-28 07:25:16 +00005653
Eric Andersencb57d552001-06-28 07:25:16 +00005654
Eric Andersen2870d962001-07-02 17:27:21 +00005655/*
5656 * Same as pgetc(), but ignores PEOA.
5657 */
Eric Andersencb57d552001-06-28 07:25:16 +00005658
Eric Andersend35c5df2002-01-09 15:37:36 +00005659#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005660static int pgetc2(void)
Eric Andersen2870d962001-07-02 17:27:21 +00005661{
5662 int c;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005663
Eric Andersen2870d962001-07-02 17:27:21 +00005664 do {
5665 c = pgetc_macro();
5666 } while (c == PEOA);
5667 return c;
Eric Andersencb57d552001-06-28 07:25:16 +00005668}
Eric Andersen2870d962001-07-02 17:27:21 +00005669#else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005670static inline int pgetc2(void)
5671{
5672 return pgetc_macro();
5673}
Eric Andersencb57d552001-06-28 07:25:16 +00005674#endif
5675
Eric Andersencb57d552001-06-28 07:25:16 +00005676/*
5677 * Read a line from the script.
5678 */
5679
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005680static inline char *pfgets(char *line, int len)
Eric Andersencb57d552001-06-28 07:25:16 +00005681{
5682 char *p = line;
5683 int nleft = len;
5684 int c;
5685
5686 while (--nleft > 0) {
5687 c = pgetc2();
5688 if (c == PEOF) {
5689 if (p == line)
5690 return NULL;
5691 break;
5692 }
5693 *p++ = c;
5694 if (c == '\n')
5695 break;
5696 }
5697 *p = '\0';
5698 return line;
5699}
5700
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005701static inline int preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005702{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005703 int nr;
5704 char *buf = parsefile->buf;
Eric Andersencb57d552001-06-28 07:25:16 +00005705
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005706 parsenextc = buf;
5707
5708 retry:
Eric Andersenbdfd0d72001-10-24 05:00:29 +00005709#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersencb57d552001-06-28 07:25:16 +00005710 {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005711 if (!iflag || parsefile->fd)
5712 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
5713 else {
5714 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
5715 }
Eric Andersencb57d552001-06-28 07:25:16 +00005716 }
5717#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00005718 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00005719#endif
5720
5721 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00005722 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
5723 int flags = fcntl(0, F_GETFL, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005724
Eric Andersencb57d552001-06-28 07:25:16 +00005725 if (flags >= 0 && flags & O_NONBLOCK) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005726 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00005727 if (fcntl(0, F_SETFL, flags) >= 0) {
5728 out2str("sh: turning off NDELAY mode\n");
5729 goto retry;
5730 }
5731 }
5732 }
5733 }
5734 return nr;
5735}
5736
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005737static void popstring(void)
Eric Andersen2870d962001-07-02 17:27:21 +00005738{
5739 struct strpush *sp = parsefile->strpush;
5740
5741 INTOFF;
Eric Andersend35c5df2002-01-09 15:37:36 +00005742#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00005743 if (sp->ap) {
5744 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
5745 if (!checkalias) {
5746 checkalias = 1;
5747 }
5748 }
5749 if (sp->string != sp->ap->val) {
Aaron Lehmann49c024a2002-08-02 06:39:47 +00005750 free(sp->string);
Eric Andersen2870d962001-07-02 17:27:21 +00005751 }
5752
5753 sp->ap->flag &= ~ALIASINUSE;
5754 if (sp->ap->flag & ALIASDEAD) {
5755 unalias(sp->ap->name);
5756 }
5757 }
5758#endif
5759 parsenextc = sp->prevstring;
5760 parsenleft = sp->prevnleft;
5761/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
5762 parsefile->strpush = sp->prev;
5763 if (sp != &(parsefile->basestrpush))
Aaron Lehmann49c024a2002-08-02 06:39:47 +00005764 free(sp);
Eric Andersen2870d962001-07-02 17:27:21 +00005765 INTON;
5766}
5767
5768
Eric Andersencb57d552001-06-28 07:25:16 +00005769/*
5770 * Refill the input buffer and return the next input character:
5771 *
5772 * 1) If a string was pushed back on the input, pop it;
5773 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
5774 * from a string so we can't refill the buffer, return EOF.
5775 * 3) If the is more stuff in this buffer, use it else call read to fill it.
5776 * 4) Process input up to the next newline, deleting nul characters.
5777 */
5778
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005779static int preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005780{
5781 char *p, *q;
5782 int more;
5783 char savec;
5784
5785 while (parsefile->strpush) {
Eric Andersend35c5df2002-01-09 15:37:36 +00005786#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00005787 if (parsenleft == -1 && parsefile->strpush->ap &&
5788 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00005789 return PEOA;
5790 }
Eric Andersen2870d962001-07-02 17:27:21 +00005791#endif
Eric Andersencb57d552001-06-28 07:25:16 +00005792 popstring();
5793 if (--parsenleft >= 0)
5794 return (*parsenextc++);
5795 }
5796 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
5797 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00005798 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00005799
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005800 again:
Eric Andersencb57d552001-06-28 07:25:16 +00005801 if (parselleft <= 0) {
5802 if ((parselleft = preadfd()) <= 0) {
5803 parselleft = parsenleft = EOF_NLEFT;
5804 return PEOF;
5805 }
5806 }
5807
5808 q = p = parsenextc;
5809
5810 /* delete nul characters */
5811 for (more = 1; more;) {
5812 switch (*p) {
5813 case '\0':
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005814 p++; /* Skip nul */
Eric Andersencb57d552001-06-28 07:25:16 +00005815 goto check;
5816
5817
5818 case '\n':
5819 parsenleft = q - parsenextc;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005820 more = 0; /* Stop processing here */
Eric Andersencb57d552001-06-28 07:25:16 +00005821 break;
5822 }
5823
5824 *q++ = *p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005825 check:
Eric Andersencb57d552001-06-28 07:25:16 +00005826 if (--parselleft <= 0 && more) {
5827 parsenleft = q - parsenextc - 1;
5828 if (parsenleft < 0)
5829 goto again;
5830 more = 0;
5831 }
5832 }
5833
5834 savec = *q;
5835 *q = '\0';
5836
5837 if (vflag) {
5838 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00005839 }
5840
5841 *q = savec;
5842
5843 return *parsenextc++;
5844}
5845
Eric Andersencb57d552001-06-28 07:25:16 +00005846
5847/*
5848 * Push a string back onto the input at this current parsefile level.
5849 * We handle aliases this way.
5850 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005851static void pushstring(char *s, int len, void *ap)
Eric Andersen2870d962001-07-02 17:27:21 +00005852{
Eric Andersencb57d552001-06-28 07:25:16 +00005853 struct strpush *sp;
5854
5855 INTOFF;
5856/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
5857 if (parsefile->strpush) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005858 sp = xmalloc(sizeof(struct strpush));
Eric Andersencb57d552001-06-28 07:25:16 +00005859 sp->prev = parsefile->strpush;
5860 parsefile->strpush = sp;
5861 } else
5862 sp = parsefile->strpush = &(parsefile->basestrpush);
5863 sp->prevstring = parsenextc;
5864 sp->prevnleft = parsenleft;
Eric Andersend35c5df2002-01-09 15:37:36 +00005865#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005866 sp->ap = (struct alias *) ap;
Eric Andersencb57d552001-06-28 07:25:16 +00005867 if (ap) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005868 ((struct alias *) ap)->flag |= ALIASINUSE;
Eric Andersencb57d552001-06-28 07:25:16 +00005869 sp->string = s;
5870 }
Eric Andersen2870d962001-07-02 17:27:21 +00005871#endif
Eric Andersencb57d552001-06-28 07:25:16 +00005872 parsenextc = s;
5873 parsenleft = len;
5874 INTON;
5875}
5876
Eric Andersencb57d552001-06-28 07:25:16 +00005877
Eric Andersencb57d552001-06-28 07:25:16 +00005878/*
5879 * Like setinputfile, but takes input from a string.
5880 */
5881
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005882static void setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +00005883{
Eric Andersencb57d552001-06-28 07:25:16 +00005884 INTOFF;
5885 pushfile();
5886 parsenextc = string;
5887 parsenleft = strlen(string);
5888 parsefile->buf = NULL;
5889 plinno = 1;
5890 INTON;
5891}
5892
5893
5894
5895/*
5896 * To handle the "." command, a stack of input files is used. Pushfile
5897 * adds a new entry to the stack and popfile restores the previous level.
5898 */
5899
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005900static void pushfile(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005901{
Eric Andersencb57d552001-06-28 07:25:16 +00005902 struct parsefile *pf;
5903
5904 parsefile->nleft = parsenleft;
5905 parsefile->lleft = parselleft;
5906 parsefile->nextc = parsenextc;
5907 parsefile->linno = plinno;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005908 pf = (struct parsefile *) xmalloc(sizeof(struct parsefile));
Eric Andersencb57d552001-06-28 07:25:16 +00005909 pf->prev = parsefile;
5910 pf->fd = -1;
5911 pf->strpush = NULL;
5912 pf->basestrpush.prev = NULL;
5913 parsefile = pf;
5914}
5915
Eric Andersend35c5df2002-01-09 15:37:36 +00005916#ifdef CONFIG_ASH_JOB_CONTROL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005917static void restartjob(struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00005918#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005919static void freejob(struct job *);
5920static struct job *getjob(const char *);
5921static int dowait(int, struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00005922
5923
Eric Andersen2870d962001-07-02 17:27:21 +00005924/*
5925 * We keep track of whether or not fd0 has been redirected. This is for
5926 * background commands, where we want to redirect fd0 to /dev/null only
5927 * if it hasn't already been redirected.
5928*/
5929static int fd0_redirected = 0;
5930
5931/* Return true if fd 0 has already been redirected at least once. */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005932static inline int fd0_redirected_p(void)
Eric Andersen74400cc2001-10-18 04:11:39 +00005933{
Eric Andersen2870d962001-07-02 17:27:21 +00005934 return fd0_redirected != 0;
5935}
5936
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005937static void dupredirect(const union node *, int, int fd1dup);
Eric Andersen2870d962001-07-02 17:27:21 +00005938
Eric Andersend35c5df2002-01-09 15:37:36 +00005939#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00005940/*
5941 * Turn job control on and off.
5942 *
5943 * Note: This code assumes that the third arg to ioctl is a character
5944 * pointer, which is true on Berkeley systems but not System V. Since
5945 * System V doesn't have job control yet, this isn't a problem now.
5946 */
5947
Eric Andersen2870d962001-07-02 17:27:21 +00005948
Eric Andersencb57d552001-06-28 07:25:16 +00005949
5950static void setjobctl(int enable)
5951{
Eric Andersencb57d552001-06-28 07:25:16 +00005952 if (enable == jobctl || rootshell == 0)
5953 return;
5954 if (enable) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005955 do { /* while we are in the background */
Eric Andersen3102ac42001-07-06 04:26:23 +00005956 initialpgrp = tcgetpgrp(2);
Eric Andersencb57d552001-06-28 07:25:16 +00005957 if (initialpgrp < 0) {
Eric Andersen8c145dc2001-07-10 16:57:09 +00005958 out2str("sh: can't access tty; job control turned off\n");
Eric Andersencb57d552001-06-28 07:25:16 +00005959 mflag = 0;
5960 return;
5961 }
5962 if (initialpgrp == -1)
5963 initialpgrp = getpgrp();
5964 else if (initialpgrp != getpgrp()) {
5965 killpg(initialpgrp, SIGTTIN);
5966 continue;
5967 }
5968 } while (0);
Eric Andersencb57d552001-06-28 07:25:16 +00005969 setsignal(SIGTSTP);
5970 setsignal(SIGTTOU);
5971 setsignal(SIGTTIN);
5972 setpgid(0, rootpid);
Eric Andersen3102ac42001-07-06 04:26:23 +00005973 tcsetpgrp(2, rootpid);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005974 } else { /* turning job control off */
Eric Andersencb57d552001-06-28 07:25:16 +00005975 setpgid(0, initialpgrp);
Eric Andersen3102ac42001-07-06 04:26:23 +00005976 tcsetpgrp(2, initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00005977 setsignal(SIGTSTP);
5978 setsignal(SIGTTOU);
5979 setsignal(SIGTTIN);
5980 }
5981 jobctl = enable;
5982}
5983#endif
5984
5985
Eric Andersend35c5df2002-01-09 15:37:36 +00005986#ifdef CONFIG_ASH_JOB_CONTROL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005987static int killcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00005988{
5989 int signo = -1;
5990 int list = 0;
5991 int i;
5992 pid_t pid;
5993 struct job *jp;
5994
5995 if (argc <= 1) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005996 usage:
5997 error
5998 ("Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
5999 "kill -l [exitstatus]");
Eric Andersencb57d552001-06-28 07:25:16 +00006000 }
6001
6002 if (*argv[1] == '-') {
6003 signo = decode_signal(argv[1] + 1, 1);
6004 if (signo < 0) {
6005 int c;
6006
6007 while ((c = nextopt("ls:")) != '\0')
6008 switch (c) {
6009 case 'l':
6010 list = 1;
6011 break;
6012 case 's':
6013 signo = decode_signal(optionarg, 1);
6014 if (signo < 0) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006015 error("invalid signal number or name: %s", optionarg);
Eric Andersencb57d552001-06-28 07:25:16 +00006016 }
Eric Andersen2870d962001-07-02 17:27:21 +00006017 break;
Eric Andersencb57d552001-06-28 07:25:16 +00006018#ifdef DEBUG
6019 default:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006020 error("nextopt returned character code 0%o", c);
Eric Andersencb57d552001-06-28 07:25:16 +00006021#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006022 }
Eric Andersencb57d552001-06-28 07:25:16 +00006023 } else
6024 argptr++;
6025 }
6026
6027 if (!list && signo < 0)
6028 signo = SIGTERM;
6029
6030 if ((signo < 0 || !*argptr) ^ list) {
6031 goto usage;
6032 }
6033
6034 if (list) {
Eric Andersen34506362001-08-02 05:02:46 +00006035 const char *name;
6036
Eric Andersencb57d552001-06-28 07:25:16 +00006037 if (!*argptr) {
6038 out1str("0\n");
6039 for (i = 1; i < NSIG; i++) {
Eric Andersen34506362001-08-02 05:02:46 +00006040 name = u_signal_names(0, &i, 1);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006041 if (name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006042 puts(name);
Eric Andersencb57d552001-06-28 07:25:16 +00006043 }
6044 return 0;
6045 }
Eric Andersen34506362001-08-02 05:02:46 +00006046 name = u_signal_names(*argptr, &signo, -1);
6047 if (name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006048 puts(name);
Eric Andersencb57d552001-06-28 07:25:16 +00006049 else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006050 error("invalid signal number or exit status: %s", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006051 return 0;
6052 }
6053
6054 do {
6055 if (**argptr == '%') {
6056 jp = getjob(*argptr);
6057 if (jp->jobctl == 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006058 error("job %s not created under job control", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006059 pid = -jp->ps[0].pid;
6060 } else
6061 pid = atoi(*argptr);
6062 if (kill(pid, signo) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00006063 error("%s: %m", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006064 } while (*++argptr);
6065
6066 return 0;
6067}
6068
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006069static int fgcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006070{
6071 struct job *jp;
6072 int pgrp;
6073 int status;
6074
6075 jp = getjob(argv[1]);
6076 if (jp->jobctl == 0)
6077 error("job not created under job control");
6078 pgrp = jp->ps[0].pid;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006079 ioctl(2, TIOCSPGRP, (char *) &pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006080 restartjob(jp);
Eric Andersencb57d552001-06-28 07:25:16 +00006081 status = waitforjob(jp);
Eric Andersencb57d552001-06-28 07:25:16 +00006082 return status;
6083}
6084
6085
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006086static int bgcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006087{
6088 struct job *jp;
6089
6090 do {
6091 jp = getjob(*++argv);
6092 if (jp->jobctl == 0)
6093 error("job not created under job control");
6094 restartjob(jp);
6095 } while (--argc > 1);
6096 return 0;
6097}
6098
6099
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006100static void restartjob(struct job *jp)
Eric Andersencb57d552001-06-28 07:25:16 +00006101{
6102 struct procstat *ps;
6103 int i;
6104
6105 if (jp->state == JOBDONE)
6106 return;
6107 INTOFF;
6108 killpg(jp->ps[0].pid, SIGCONT);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006109 for (ps = jp->ps, i = jp->nprocs; --i >= 0; ps++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006110 if (WIFSTOPPED(ps->status)) {
6111 ps->status = -1;
6112 jp->state = 0;
6113 }
6114 }
6115 INTON;
6116}
6117#endif
6118
Eric Andersen2870d962001-07-02 17:27:21 +00006119static void showjobs(int change);
6120
Eric Andersencb57d552001-06-28 07:25:16 +00006121
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006122static int jobscmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006123{
6124 showjobs(0);
6125 return 0;
6126}
6127
6128
6129/*
6130 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6131 * statuses have changed since the last call to showjobs.
6132 *
6133 * If the shell is interrupted in the process of creating a job, the
6134 * result may be a job structure containing zero processes. Such structures
6135 * will be freed here.
6136 */
6137
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006138static void showjobs(int change)
Eric Andersencb57d552001-06-28 07:25:16 +00006139{
6140 int jobno;
6141 int procno;
6142 int i;
6143 struct job *jp;
6144 struct procstat *ps;
6145 int col;
6146 char s[64];
6147
6148 TRACE(("showjobs(%d) called\n", change));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006149 while (dowait(0, (struct job *) NULL) > 0);
6150 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
6151 if (!jp->used)
Eric Andersencb57d552001-06-28 07:25:16 +00006152 continue;
6153 if (jp->nprocs == 0) {
6154 freejob(jp);
6155 continue;
6156 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006157 if (change && !jp->changed)
Eric Andersencb57d552001-06-28 07:25:16 +00006158 continue;
6159 procno = jp->nprocs;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006160 for (ps = jp->ps;; ps++) { /* for each process */
Eric Andersencb57d552001-06-28 07:25:16 +00006161 if (ps == jp->ps)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006162 snprintf(s, 64, "[%d] %ld ", jobno, (long) ps->pid);
Eric Andersencb57d552001-06-28 07:25:16 +00006163 else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006164 snprintf(s, 64, " %ld ", (long) ps->pid);
Eric Andersencb57d552001-06-28 07:25:16 +00006165 out1str(s);
6166 col = strlen(s);
6167 s[0] = '\0';
6168 if (ps->status == -1) {
6169 /* don't print anything */
6170 } else if (WIFEXITED(ps->status)) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006171 snprintf(s, 64, "Exit %d", WEXITSTATUS(ps->status));
Eric Andersencb57d552001-06-28 07:25:16 +00006172 } else {
Eric Andersend35c5df2002-01-09 15:37:36 +00006173#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen2870d962001-07-02 17:27:21 +00006174 if (WIFSTOPPED(ps->status))
Eric Andersencb57d552001-06-28 07:25:16 +00006175 i = WSTOPSIG(ps->status);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006176 else /* WIFSIGNALED(ps->status) */
Eric Andersencb57d552001-06-28 07:25:16 +00006177#endif
6178 i = WTERMSIG(ps->status);
6179 if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
Eric Andersen2870d962001-07-02 17:27:21 +00006180 strcpy(s, sys_siglist[i & 0x7F]);
Eric Andersencb57d552001-06-28 07:25:16 +00006181 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006182 snprintf(s, 64, "Signal %d", i & 0x7F);
Eric Andersencb57d552001-06-28 07:25:16 +00006183 if (WCOREDUMP(ps->status))
6184 strcat(s, " (core dumped)");
6185 }
6186 out1str(s);
6187 col += strlen(s);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006188 printf("%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ', ps->cmd);
Eric Andersencb57d552001-06-28 07:25:16 +00006189 if (--procno <= 0)
6190 break;
6191 }
6192 jp->changed = 0;
6193 if (jp->state == JOBDONE) {
6194 freejob(jp);
6195 }
6196 }
6197}
6198
6199
6200/*
6201 * Mark a job structure as unused.
6202 */
6203
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006204static void freejob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00006205{
6206 const struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006207 int i;
6208
6209 INTOFF;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006210 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006211 if (ps->cmd != nullstr)
Aaron Lehmann49c024a2002-08-02 06:39:47 +00006212 free(ps->cmd);
Eric Andersencb57d552001-06-28 07:25:16 +00006213 }
6214 if (jp->ps != &jp->ps0)
Aaron Lehmann49c024a2002-08-02 06:39:47 +00006215 free(jp->ps);
Eric Andersencb57d552001-06-28 07:25:16 +00006216 jp->used = 0;
Eric Andersend35c5df2002-01-09 15:37:36 +00006217#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006218 if (curjob == jp - jobtab + 1)
6219 curjob = 0;
6220#endif
6221 INTON;
6222}
6223
6224
6225
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006226static int waitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006227{
6228 struct job *job;
6229 int status, retval;
6230 struct job *jp;
6231
6232 if (--argc > 0) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006233 start:
Eric Andersencb57d552001-06-28 07:25:16 +00006234 job = getjob(*++argv);
6235 } else {
6236 job = NULL;
6237 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006238 for (;;) { /* loop until process terminated or stopped */
Eric Andersencb57d552001-06-28 07:25:16 +00006239 if (job != NULL) {
6240 if (job->state) {
6241 status = job->ps[job->nprocs - 1].status;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006242 if (!iflag)
Eric Andersencb57d552001-06-28 07:25:16 +00006243 freejob(job);
6244 if (--argc) {
6245 goto start;
6246 }
6247 if (WIFEXITED(status))
6248 retval = WEXITSTATUS(status);
Eric Andersend35c5df2002-01-09 15:37:36 +00006249#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006250 else if (WIFSTOPPED(status))
6251 retval = WSTOPSIG(status) + 128;
6252#endif
6253 else {
6254 /* XXX: limits number of signals */
6255 retval = WTERMSIG(status) + 128;
6256 }
6257 return retval;
6258 }
6259 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006260 for (jp = jobtab;; jp++) {
6261 if (jp >= jobtab + njobs) { /* no running procs */
Eric Andersencb57d552001-06-28 07:25:16 +00006262 return 0;
6263 }
6264 if (jp->used && jp->state == 0)
6265 break;
6266 }
6267 }
6268 if (dowait(2, 0) < 0 && errno == EINTR) {
6269 return 129;
6270 }
6271 }
6272}
6273
6274
6275
6276/*
6277 * Convert a job name to a job structure.
6278 */
6279
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006280static struct job *getjob(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00006281{
Eric Andersencb57d552001-06-28 07:25:16 +00006282 int jobno;
6283 struct job *jp;
6284 int pid;
6285 int i;
6286
6287 if (name == NULL) {
Eric Andersend35c5df2002-01-09 15:37:36 +00006288#ifdef CONFIG_ASH_JOB_CONTROL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006289 currentjob:
Eric Andersencb57d552001-06-28 07:25:16 +00006290 if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
6291 error("No current job");
6292 return &jobtab[jobno - 1];
6293#else
6294 error("No current job");
6295#endif
6296 } else if (name[0] == '%') {
6297 if (is_digit(name[1])) {
6298 jobno = number(name + 1);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006299 if (jobno > 0 && jobno <= njobs && jobtab[jobno - 1].used != 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006300 return &jobtab[jobno - 1];
Eric Andersend35c5df2002-01-09 15:37:36 +00006301#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006302 } else if (name[1] == '%' && name[2] == '\0') {
6303 goto currentjob;
6304#endif
6305 } else {
6306 struct job *found = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006307
6308 for (jp = jobtab, i = njobs; --i >= 0; jp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006309 if (jp->used && jp->nprocs > 0
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006310 && prefix(name + 1, jp->ps[0].cmd)) {
Eric Andersencb57d552001-06-28 07:25:16 +00006311 if (found)
6312 error("%s: ambiguous", name);
6313 found = jp;
6314 }
6315 }
6316 if (found)
6317 return found;
6318 }
Eric Andersen2870d962001-07-02 17:27:21 +00006319 } else if (is_number(name, &pid)) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006320 for (jp = jobtab, i = njobs; --i >= 0; jp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006321 if (jp->used && jp->nprocs > 0
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006322 && jp->ps[jp->nprocs - 1].pid == pid)
Eric Andersencb57d552001-06-28 07:25:16 +00006323 return jp;
6324 }
6325 }
6326 error("No such job: %s", name);
6327 /* NOTREACHED */
6328}
6329
6330
6331
6332/*
6333 * Return a new job structure,
6334 */
6335
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006336static struct job *makejob(const union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00006337{
6338 int i;
6339 struct job *jp;
6340
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006341 for (i = njobs, jp = jobtab;; jp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006342 if (--i < 0) {
6343 INTOFF;
6344 if (njobs == 0) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006345 jobtab = xmalloc(4 * sizeof jobtab[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00006346 } else {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006347 jp = xmalloc((njobs + 4) * sizeof jobtab[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00006348 memcpy(jp, jobtab, njobs * sizeof jp[0]);
6349 /* Relocate `ps' pointers */
6350 for (i = 0; i < njobs; i++)
6351 if (jp[i].ps == &jobtab[i].ps0)
6352 jp[i].ps = &jp[i].ps0;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00006353 free(jobtab);
Eric Andersencb57d552001-06-28 07:25:16 +00006354 jobtab = jp;
6355 }
6356 jp = jobtab + njobs;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006357 for (i = 4; --i >= 0; jobtab[njobs++].used = 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006358 INTON;
6359 break;
6360 }
6361 if (jp->used == 0)
6362 break;
6363 }
6364 INTOFF;
6365 jp->state = 0;
6366 jp->used = 1;
6367 jp->changed = 0;
6368 jp->nprocs = 0;
Eric Andersend35c5df2002-01-09 15:37:36 +00006369#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006370 jp->jobctl = jobctl;
6371#endif
6372 if (nprocs > 1) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006373 jp->ps = xmalloc(nprocs * sizeof(struct procstat));
Eric Andersencb57d552001-06-28 07:25:16 +00006374 } else {
6375 jp->ps = &jp->ps0;
6376 }
6377 INTON;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006378 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long) node, nprocs,
6379 jp - jobtab + 1));
Eric Andersencb57d552001-06-28 07:25:16 +00006380 return jp;
6381}
6382
6383
6384/*
6385 * Fork of a subshell. If we are doing job control, give the subshell its
6386 * own process group. Jp is a job structure that the job is to be added to.
6387 * N is the command that will be evaluated by the child. Both jp and n may
6388 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00006389 * FORK_FG - Fork off a foreground process.
6390 * FORK_BG - Fork off a background process.
6391 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
6392 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00006393 *
6394 * When job control is turned off, background processes have their standard
6395 * input redirected to /dev/null (except for the second and later processes
6396 * in a pipeline).
6397 */
6398
Eric Andersen2870d962001-07-02 17:27:21 +00006399
6400
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006401static int forkshell(struct job *jp, const union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00006402{
6403 int pid;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006404
Eric Andersend35c5df2002-01-09 15:37:36 +00006405#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006406 int pgrp;
Eric Andersen62483552001-07-10 06:09:16 +00006407#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006408 const char *devnull = _PATH_DEVNULL;
6409 const char *nullerr = "Can't open %s";
6410
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006411 TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long) n,
6412 mode));
Eric Andersencb57d552001-06-28 07:25:16 +00006413 INTOFF;
6414 pid = fork();
6415 if (pid == -1) {
6416 TRACE(("Fork failed, errno=%d\n", errno));
6417 INTON;
6418 error("Cannot fork");
6419 }
6420 if (pid == 0) {
6421 struct job *p;
6422 int wasroot;
6423 int i;
6424
6425 TRACE(("Child shell %d\n", getpid()));
6426 wasroot = rootshell;
6427 rootshell = 0;
6428 closescript();
6429 INTON;
6430 clear_traps();
Eric Andersend35c5df2002-01-09 15:37:36 +00006431#ifdef CONFIG_ASH_JOB_CONTROL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006432 jobctl = 0; /* do job control only in root shell */
Eric Andersencb57d552001-06-28 07:25:16 +00006433 if (wasroot && mode != FORK_NOJOB && mflag) {
6434 if (jp == NULL || jp->nprocs == 0)
6435 pgrp = getpid();
6436 else
6437 pgrp = jp->ps[0].pid;
6438 setpgid(0, pgrp);
6439 if (mode == FORK_FG) {
6440 /*** this causes superfluous TIOCSPGRPS ***/
Eric Andersen3102ac42001-07-06 04:26:23 +00006441 if (tcsetpgrp(2, pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006442 error("tcsetpgrp failed, errno=%d", errno);
Eric Andersencb57d552001-06-28 07:25:16 +00006443 }
6444 setsignal(SIGTSTP);
6445 setsignal(SIGTTOU);
6446 } else if (mode == FORK_BG) {
Eric Andersencb57d552001-06-28 07:25:16 +00006447#else
6448 if (mode == FORK_BG) {
Aaron Lehmann1a698662001-12-31 06:12:48 +00006449#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006450 ignoresig(SIGINT);
6451 ignoresig(SIGQUIT);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006452 if ((jp == NULL || jp->nprocs == 0) && !fd0_redirected_p()) {
Eric Andersencb57d552001-06-28 07:25:16 +00006453 close(0);
6454 if (open(devnull, O_RDONLY) != 0)
6455 error(nullerr, devnull);
6456 }
6457 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006458 for (i = njobs, p = jobtab; --i >= 0; p++)
Eric Andersencb57d552001-06-28 07:25:16 +00006459 if (p->used)
6460 freejob(p);
6461 if (wasroot && iflag) {
6462 setsignal(SIGINT);
6463 setsignal(SIGQUIT);
6464 setsignal(SIGTERM);
6465 }
6466 return pid;
6467 }
Eric Andersend35c5df2002-01-09 15:37:36 +00006468#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006469 if (rootshell && mode != FORK_NOJOB && mflag) {
6470 if (jp == NULL || jp->nprocs == 0)
6471 pgrp = pid;
6472 else
6473 pgrp = jp->ps[0].pid;
6474 setpgid(pid, pgrp);
6475 }
Eric Andersen62483552001-07-10 06:09:16 +00006476#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006477 if (mode == FORK_BG)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006478 backgndpid = pid; /* set $! */
Eric Andersencb57d552001-06-28 07:25:16 +00006479 if (jp) {
6480 struct procstat *ps = &jp->ps[jp->nprocs++];
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006481
Eric Andersencb57d552001-06-28 07:25:16 +00006482 ps->pid = pid;
6483 ps->status = -1;
6484 ps->cmd = nullstr;
6485 if (iflag && rootshell && n)
6486 ps->cmd = commandtext(n);
6487 }
6488 INTON;
6489 TRACE(("In parent shell: child = %d\n", pid));
6490 return pid;
6491}
6492
6493
6494
6495/*
6496 * Wait for job to finish.
6497 *
6498 * Under job control we have the problem that while a child process is
6499 * running interrupts generated by the user are sent to the child but not
6500 * to the shell. This means that an infinite loop started by an inter-
6501 * active user may be hard to kill. With job control turned off, an
6502 * interactive user may place an interactive program inside a loop. If
6503 * the interactive program catches interrupts, the user doesn't want
6504 * these interrupts to also abort the loop. The approach we take here
6505 * is to have the shell ignore interrupt signals while waiting for a
6506 * forground process to terminate, and then send itself an interrupt
6507 * signal if the child process was terminated by an interrupt signal.
6508 * Unfortunately, some programs want to do a bit of cleanup and then
6509 * exit on interrupt; unless these processes terminate themselves by
6510 * sending a signal to themselves (instead of calling exit) they will
6511 * confuse this approach.
6512 */
6513
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006514static int waitforjob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00006515{
Eric Andersend35c5df2002-01-09 15:37:36 +00006516#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006517 int mypgrp = getpgrp();
6518#endif
6519 int status;
6520 int st;
Eric Andersencb57d552001-06-28 07:25:16 +00006521
6522 INTOFF;
Eric Andersencb57d552001-06-28 07:25:16 +00006523 TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
6524 while (jp->state == 0) {
6525 dowait(1, jp);
6526 }
Eric Andersend35c5df2002-01-09 15:37:36 +00006527#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006528 if (jp->jobctl) {
Eric Andersen3102ac42001-07-06 04:26:23 +00006529 if (tcsetpgrp(2, mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006530 error("tcsetpgrp failed, errno=%d\n", errno);
Eric Andersencb57d552001-06-28 07:25:16 +00006531 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00006532 if (jp->state == JOBSTOPPED)
Eric Andersencb57d552001-06-28 07:25:16 +00006533 curjob = jp - jobtab + 1;
6534#endif
6535 status = jp->ps[jp->nprocs - 1].status;
6536 /* convert to 8 bits */
6537 if (WIFEXITED(status))
6538 st = WEXITSTATUS(status);
Eric Andersend35c5df2002-01-09 15:37:36 +00006539#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006540 else if (WIFSTOPPED(status))
6541 st = WSTOPSIG(status) + 128;
6542#endif
6543 else
6544 st = WTERMSIG(status) + 128;
Eric Andersend35c5df2002-01-09 15:37:36 +00006545#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006546 if (jp->jobctl) {
6547 /*
6548 * This is truly gross.
6549 * If we're doing job control, then we did a TIOCSPGRP which
6550 * caused us (the shell) to no longer be in the controlling
6551 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
6552 * intuit from the subprocess exit status whether a SIGINT
6553 * occured, and if so interrupt ourselves. Yuck. - mycroft
6554 */
6555 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
6556 raise(SIGINT);
6557 }
Eric Andersen2870d962001-07-02 17:27:21 +00006558 if (jp->state == JOBDONE)
Eric Andersencb57d552001-06-28 07:25:16 +00006559#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006560 freejob(jp);
6561 INTON;
6562 return st;
6563}
6564
6565
6566
6567/*
6568 * Wait for a process to terminate.
6569 */
6570
Eric Andersen62483552001-07-10 06:09:16 +00006571/*
6572 * Do a wait system call. If job control is compiled in, we accept
6573 * stopped processes. If block is zero, we return a value of zero
6574 * rather than blocking.
6575 *
6576 * System V doesn't have a non-blocking wait system call. It does
6577 * have a SIGCLD signal that is sent to a process when one of it's
6578 * children dies. The obvious way to use SIGCLD would be to install
6579 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
6580 * was received, and have waitproc bump another counter when it got
6581 * the status of a process. Waitproc would then know that a wait
6582 * system call would not block if the two counters were different.
6583 * This approach doesn't work because if a process has children that
6584 * have not been waited for, System V will send it a SIGCLD when it
6585 * installs a signal handler for SIGCLD. What this means is that when
6586 * a child exits, the shell will be sent SIGCLD signals continuously
6587 * until is runs out of stack space, unless it does a wait call before
6588 * restoring the signal handler. The code below takes advantage of
6589 * this (mis)feature by installing a signal handler for SIGCLD and
6590 * then checking to see whether it was called. If there are any
6591 * children to be waited for, it will be.
6592 *
6593 */
6594
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006595static inline int waitproc(int block, int *status)
Eric Andersen62483552001-07-10 06:09:16 +00006596{
6597 int flags;
6598
6599 flags = 0;
Eric Andersend35c5df2002-01-09 15:37:36 +00006600#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen62483552001-07-10 06:09:16 +00006601 if (jobctl)
6602 flags |= WUNTRACED;
6603#endif
6604 if (block == 0)
6605 flags |= WNOHANG;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006606 return wait3(status, flags, (struct rusage *) NULL);
Eric Andersen62483552001-07-10 06:09:16 +00006607}
6608
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006609static int dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00006610{
6611 int pid;
6612 int status;
6613 struct procstat *sp;
6614 struct job *jp;
6615 struct job *thisjob;
6616 int done;
6617 int stopped;
6618 int core;
6619 int sig;
6620
6621 TRACE(("dowait(%d) called\n", block));
6622 do {
6623 pid = waitproc(block, &status);
6624 TRACE(("wait returns %d, status=%d\n", pid, status));
6625 } while (!(block & 2) && pid == -1 && errno == EINTR);
6626 if (pid <= 0)
6627 return pid;
6628 INTOFF;
6629 thisjob = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006630 for (jp = jobtab; jp < jobtab + njobs; jp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006631 if (jp->used) {
6632 done = 1;
6633 stopped = 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006634 for (sp = jp->ps; sp < jp->ps + jp->nprocs; sp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006635 if (sp->pid == -1)
6636 continue;
6637 if (sp->pid == pid) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006638 TRACE(("Changing status of proc %d from 0x%x to 0x%x\n",
6639 pid, sp->status, status));
Eric Andersencb57d552001-06-28 07:25:16 +00006640 sp->status = status;
6641 thisjob = jp;
6642 }
6643 if (sp->status == -1)
6644 stopped = 0;
6645 else if (WIFSTOPPED(sp->status))
6646 done = 0;
6647 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006648 if (stopped) { /* stopped or done */
Glenn L McGrath50812ff2002-08-23 13:14:48 +00006649 int state = done ? JOBDONE : JOBSTOPPED;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006650
Eric Andersencb57d552001-06-28 07:25:16 +00006651 if (jp->state != state) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006652 TRACE(("Job %d: changing state from %d to %d\n",
6653 jp - jobtab + 1, jp->state, state));
Eric Andersencb57d552001-06-28 07:25:16 +00006654 jp->state = state;
Eric Andersend35c5df2002-01-09 15:37:36 +00006655#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006656 if (done && curjob == jp - jobtab + 1)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006657 curjob = 0; /* no current job */
Eric Andersencb57d552001-06-28 07:25:16 +00006658#endif
6659 }
6660 }
6661 }
6662 }
6663 INTON;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006664 if (!rootshell || !iflag || (job && thisjob == job)) {
Eric Andersencb57d552001-06-28 07:25:16 +00006665 core = WCOREDUMP(status);
Eric Andersend35c5df2002-01-09 15:37:36 +00006666#ifdef CONFIG_ASH_JOB_CONTROL
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006667 if (WIFSTOPPED(status))
6668 sig = WSTOPSIG(status);
Eric Andersencb57d552001-06-28 07:25:16 +00006669 else
6670#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006671 if (WIFEXITED(status))
6672 sig = 0;
6673 else
6674 sig = WTERMSIG(status);
Eric Andersencb57d552001-06-28 07:25:16 +00006675
6676 if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
6677 if (thisjob != job)
Eric Andersen3102ac42001-07-06 04:26:23 +00006678 out2fmt("%d: ", pid);
Eric Andersend35c5df2002-01-09 15:37:36 +00006679#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006680 if (sig == SIGTSTP && rootshell && iflag)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006681 out2fmt("%%%ld ", (long) (job - jobtab + 1));
Eric Andersencb57d552001-06-28 07:25:16 +00006682#endif
6683 if (sig < NSIG && sys_siglist[sig])
6684 out2str(sys_siglist[sig]);
6685 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006686 out2fmt("Signal %d", sig);
Eric Andersencb57d552001-06-28 07:25:16 +00006687 if (core)
6688 out2str(" - core dumped");
6689 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00006690 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006691 TRACE(("Not printing status: status=%d, sig=%d\n", status, sig));
Eric Andersencb57d552001-06-28 07:25:16 +00006692 }
6693 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006694 TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell,
6695 job));
Eric Andersencb57d552001-06-28 07:25:16 +00006696 if (thisjob)
6697 thisjob->changed = 1;
6698 }
6699 return pid;
6700}
6701
6702
6703
Eric Andersencb57d552001-06-28 07:25:16 +00006704
6705/*
6706 * return 1 if there are stopped jobs, otherwise 0
6707 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006708static int stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006709{
6710 int jobno;
6711 struct job *jp;
6712
6713 if (job_warning)
6714 return (0);
6715 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
6716 if (jp->used == 0)
6717 continue;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00006718 if (jp->state == JOBSTOPPED) {
Eric Andersencb57d552001-06-28 07:25:16 +00006719 out2str("You have stopped jobs.\n");
6720 job_warning = 2;
6721 return (1);
6722 }
6723 }
6724
6725 return (0);
6726}
6727
6728/*
6729 * Return a string identifying a command (to be printed by the
6730 * jobs command.
6731 */
6732
6733static char *cmdnextc;
6734static int cmdnleft;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006735
Eric Andersen2870d962001-07-02 17:27:21 +00006736#define MAXCMDTEXT 200
Eric Andersencb57d552001-06-28 07:25:16 +00006737
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006738static void cmdputs(const char *s)
Eric Andersen2870d962001-07-02 17:27:21 +00006739{
6740 const char *p;
6741 char *q;
6742 char c;
6743 int subtype = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00006744
Eric Andersen2870d962001-07-02 17:27:21 +00006745 if (cmdnleft <= 0)
6746 return;
6747 p = s;
6748 q = cmdnextc;
6749 while ((c = *p++) != '\0') {
6750 if (c == CTLESC)
6751 *q++ = *p++;
6752 else if (c == CTLVAR) {
6753 *q++ = '$';
6754 if (--cmdnleft > 0)
6755 *q++ = '{';
6756 subtype = *p++;
6757 } else if (c == '=' && subtype != 0) {
6758 *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
6759 subtype = 0;
6760 } else if (c == CTLENDVAR) {
6761 *q++ = '}';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006762 } else if (c == CTLBACKQ || c == CTLBACKQ + CTLQUOTE)
6763 cmdnleft++; /* ignore it */
Eric Andersen2870d962001-07-02 17:27:21 +00006764 else
6765 *q++ = c;
6766 if (--cmdnleft <= 0) {
6767 *q++ = '.';
6768 *q++ = '.';
6769 *q++ = '.';
6770 break;
6771 }
6772 }
6773 cmdnextc = q;
Eric Andersencb57d552001-06-28 07:25:16 +00006774}
6775
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00006776#define CMDTXT_TABLE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006777#ifdef CMDTXT_TABLE
6778/*
6779 * To collect a lot of redundant code in cmdtxt() case statements, we
6780 * implement a mini language here. Each type of node struct has an
6781 * associated instruction sequence that operates on its members via
6782 * their offsets. The instruction are pack in unsigned chars with
6783 * format IIDDDDDE where the bits are
6784 * I : part of the instruction opcode, which are
6785 * 00 : member is a pointer to another node -- process it recursively
6786 * 40 : member is a pointer to a char string -- output it
6787 * 80 : output the string whose index is stored in the data field
6788 * CC : flag signaling that this case needs external processing
6789 * D : data - either the (shifted) index of a fixed string to output or
6790 * the actual offset of the member to operate on in the struct
6791 * (since we assume bit 0 is set, the offset is not shifted)
6792 * E : flag signaling end of instruction sequence
6793 *
6794 * WARNING: In order to handle larger offsets for 64bit archs, this code
6795 * assumes that no offset can be an odd number and stores the
6796 * end-of-instructions flag in bit 0.
6797 */
Eric Andersencb57d552001-06-28 07:25:16 +00006798
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006799#define CMDTXT_NOMORE 0x01 /* NOTE: no offset should be odd */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006800#define CMDTXT_CHARPTR 0x40
6801#define CMDTXT_STRING 0x80
6802#define CMDTXT_SPECIAL 0xC0
6803#define CMDTXT_OFFSETMASK 0x3E
6804
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006805static const char *const cmdtxt_strings[] = {
6806 /* 0 1 2 3 4 5 6 7 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006807 "; ", "(", ")", " && ", " || ", "if ", "; then ", "...",
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006808 /* 8 9 10 11 12 13 */
6809 "while ", "; do ", "; done", "until ", "for ", " in ...",
6810 /* 14 15 16 17 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006811 "case ", "???", "() ...", "<<..."
6812};
6813
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006814static const char *const redir_strings[] = {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006815 ">", "<", "<>", ">>", ">|", ">&", "<&"
6816};
6817
6818static const unsigned char cmdtxt_ops[] = {
6819#define CMDTXT_NSEMI 0
6820 offsetof(union node, nbinary.ch1),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006821 0 | CMDTXT_STRING,
6822 offsetof(union node, nbinary.ch2) | CMDTXT_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006823#define CMDTXT_NCMD (CMDTXT_NSEMI + 3)
6824#define CMDTXT_NPIPE (CMDTXT_NCMD)
6825#define CMDTXT_NCASE (CMDTXT_NCMD)
6826#define CMDTXT_NTO (CMDTXT_NCMD)
6827#define CMDTXT_NFROM (CMDTXT_NCMD)
6828#define CMDTXT_NFROMTO (CMDTXT_NCMD)
6829#define CMDTXT_NAPPEND (CMDTXT_NCMD)
6830#define CMDTXT_NTOOV (CMDTXT_NCMD)
6831#define CMDTXT_NTOFD (CMDTXT_NCMD)
6832#define CMDTXT_NFROMFD (CMDTXT_NCMD)
6833 CMDTXT_SPECIAL,
6834#define CMDTXT_NREDIR (CMDTXT_NPIPE + 1)
6835#define CMDTXT_NBACKGND (CMDTXT_NREDIR)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006836 offsetof(union node, nredir.n) | CMDTXT_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006837#define CMDTXT_NSUBSHELL (CMDTXT_NBACKGND + 1)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006838 (1 * 2) | CMDTXT_STRING,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006839 offsetof(union node, nredir.n),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006840 (2 * 2) | CMDTXT_STRING | CMDTXT_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006841#define CMDTXT_NAND (CMDTXT_NSUBSHELL + 3)
6842 offsetof(union node, nbinary.ch1),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006843 (3 * 2) | CMDTXT_STRING,
6844 offsetof(union node, nbinary.ch2) | CMDTXT_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006845#define CMDTXT_NOR (CMDTXT_NAND + 3)
6846 offsetof(union node, nbinary.ch1),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006847 (4 * 2) | CMDTXT_STRING,
6848 offsetof(union node, nbinary.ch2) | CMDTXT_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006849#define CMDTXT_NIF (CMDTXT_NOR + 3)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006850 (5 * 2) | CMDTXT_STRING,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006851 offsetof(union node, nif.test),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006852 (6 * 2) | CMDTXT_STRING,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006853 offsetof(union node, nif.ifpart),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006854 (7 * 2) | CMDTXT_STRING | CMDTXT_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006855#define CMDTXT_NWHILE (CMDTXT_NIF + 5)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006856 (8 * 2) | CMDTXT_STRING,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006857 offsetof(union node, nbinary.ch1),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006858 (9 * 2) | CMDTXT_STRING,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006859 offsetof(union node, nbinary.ch2),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006860 (10 * 2) | CMDTXT_STRING | CMDTXT_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006861#define CMDTXT_NUNTIL (CMDTXT_NWHILE + 5)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006862 (11 * 2) | CMDTXT_STRING,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006863 offsetof(union node, nbinary.ch1),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006864 (9 * 2) | CMDTXT_STRING,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006865 offsetof(union node, nbinary.ch2),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006866 (10 * 2) | CMDTXT_STRING | CMDTXT_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006867#define CMDTXT_NFOR (CMDTXT_NUNTIL + 5)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006868 (12 * 2) | CMDTXT_STRING,
6869 offsetof(union node, nfor.var) | CMDTXT_CHARPTR,
6870 (13 * 2) | CMDTXT_STRING | CMDTXT_NOMORE,
6871#define CMDTXT_NCLIST (CMDTXT_NFOR + 3) /* TODO: IS THIS CORRECT??? */
6872#define CMDTXT_NNOT (CMDTXT_NCLIST) /* TODO: IS THIS CORRECT??? */
6873 (15 * 2) | CMDTXT_STRING | CMDTXT_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006874#define CMDTXT_NDEFUN (CMDTXT_NCLIST + 1)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006875 offsetof(union node, narg.text) | CMDTXT_CHARPTR,
6876 (16 * 2) | CMDTXT_STRING | CMDTXT_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006877#define CMDTXT_NARG (CMDTXT_NDEFUN + 2)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006878 offsetof(union node, narg.text) | CMDTXT_CHARPTR | CMDTXT_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006879#define CMDTXT_NHERE (CMDTXT_NARG + 1)
6880#define CMDTXT_NXHERE (CMDTXT_NHERE)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006881 (17 * 2) | CMDTXT_STRING | CMDTXT_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006882};
6883
6884#if CMDTXT_NXHERE != 36
6885#error CMDTXT_NXHERE
6886#endif
6887
6888static const unsigned char cmdtxt_ops_index[26] = {
6889 CMDTXT_NSEMI,
6890 CMDTXT_NCMD,
6891 CMDTXT_NPIPE,
6892 CMDTXT_NREDIR,
6893 CMDTXT_NBACKGND,
6894 CMDTXT_NSUBSHELL,
6895 CMDTXT_NAND,
6896 CMDTXT_NOR,
6897 CMDTXT_NIF,
6898 CMDTXT_NWHILE,
6899 CMDTXT_NUNTIL,
6900 CMDTXT_NFOR,
6901 CMDTXT_NCASE,
6902 CMDTXT_NCLIST,
6903 CMDTXT_NDEFUN,
6904 CMDTXT_NARG,
6905 CMDTXT_NTO,
6906 CMDTXT_NFROM,
6907 CMDTXT_NFROMTO,
6908 CMDTXT_NAPPEND,
6909 CMDTXT_NTOOV,
6910 CMDTXT_NTOFD,
6911 CMDTXT_NFROMFD,
6912 CMDTXT_NHERE,
6913 CMDTXT_NXHERE,
6914 CMDTXT_NNOT,
6915};
6916
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006917static void cmdtxt(const union node *n)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006918{
6919 const char *p;
6920
6921 if (n == NULL)
6922 return;
6923
6924 p = cmdtxt_ops + (int) cmdtxt_ops_index[n->type];
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006925 if ((*p & CMDTXT_SPECIAL) != CMDTXT_SPECIAL) { /* normal case */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006926 do {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006927 if (*p & CMDTXT_STRING) { /* output fixed string */
6928 cmdputs(cmdtxt_strings
6929 [((int) (*p & CMDTXT_OFFSETMASK) >> 1)]);
Manuel Novoa III c639a352001-08-12 17:32:56 +00006930 } else {
6931 const char *pf = ((const char *) n)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006932 + ((int) (*p & CMDTXT_OFFSETMASK));
6933
6934 if (*p & CMDTXT_CHARPTR) { /* output dynamic string */
Manuel Novoa III c639a352001-08-12 17:32:56 +00006935 cmdputs(*((const char **) pf));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006936 } else { /* output field */
Manuel Novoa III c639a352001-08-12 17:32:56 +00006937 cmdtxt(*((const union node **) pf));
6938 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006939 }
6940 } while (!(*p++ & CMDTXT_NOMORE));
6941 } else if (n->type == NCMD) {
6942 union node *np;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006943
6944 for (np = n->ncmd.args; np; np = np->narg.next) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006945 cmdtxt(np);
6946 if (np->narg.next)
6947 cmdputs(spcstr);
6948 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006949 for (np = n->ncmd.redirect; np; np = np->nfile.next) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006950 cmdputs(spcstr);
6951 cmdtxt(np);
6952 }
6953 } else if (n->type == NPIPE) {
6954 struct nodelist *lp;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006955
6956 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00006957 cmdtxt(lp->n);
6958 if (lp->next)
6959 cmdputs(" | ");
6960 }
6961 } else if (n->type == NCASE) {
6962 cmdputs(cmdtxt_strings[14]);
6963 cmdputs(n->ncase.expr->narg.text);
6964 cmdputs(cmdtxt_strings[13]);
6965 } else {
6966#if (NTO != 16) || (NFROM != 17) || (NFROMTO != 18) || (NAPPEND != 19) || (NTOOV != 20) || (NTOFD != 21) || (NFROMFD != 22)
6967#error Assumption violated regarding range and ordering of NTO ... NFROMFD!
6968#endif
6969 char s[2];
6970
6971#ifdef DEBUG
6972 assert((n->type >= NTO) && (n->type <= NFROMFD));
6973#endif
6974
6975 p = redir_strings[n->type - NTO];
6976 if (n->nfile.fd != ('>' == *p)) {
6977 s[0] = n->nfile.fd + '0';
6978 s[1] = '\0';
6979 cmdputs(s);
6980 }
6981 cmdputs(p);
6982 if (n->type >= NTOFD) {
6983 s[0] = n->ndup.dupfd + '0';
6984 s[1] = '\0';
6985 cmdputs(s);
6986 } else {
6987 cmdtxt(n->nfile.fname);
6988 }
6989 }
6990}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006991#else /* CMDTXT_TABLE */
6992static void cmdtxt(const union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00006993{
Eric Andersencb57d552001-06-28 07:25:16 +00006994 union node *np;
6995 struct nodelist *lp;
6996 const char *p;
6997 int i;
6998 char s[2];
6999
7000 if (n == NULL)
7001 return;
7002 switch (n->type) {
7003 case NSEMI:
7004 cmdtxt(n->nbinary.ch1);
7005 cmdputs("; ");
7006 cmdtxt(n->nbinary.ch2);
7007 break;
7008 case NAND:
7009 cmdtxt(n->nbinary.ch1);
7010 cmdputs(" && ");
7011 cmdtxt(n->nbinary.ch2);
7012 break;
7013 case NOR:
7014 cmdtxt(n->nbinary.ch1);
7015 cmdputs(" || ");
7016 cmdtxt(n->nbinary.ch2);
7017 break;
7018 case NPIPE:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007019 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00007020 cmdtxt(lp->n);
7021 if (lp->next)
7022 cmdputs(" | ");
7023 }
7024 break;
7025 case NSUBSHELL:
7026 cmdputs("(");
7027 cmdtxt(n->nredir.n);
7028 cmdputs(")");
7029 break;
7030 case NREDIR:
7031 case NBACKGND:
7032 cmdtxt(n->nredir.n);
7033 break;
7034 case NIF:
7035 cmdputs("if ");
7036 cmdtxt(n->nif.test);
7037 cmdputs("; then ");
7038 cmdtxt(n->nif.ifpart);
7039 cmdputs("...");
7040 break;
7041 case NWHILE:
7042 cmdputs("while ");
7043 goto until;
7044 case NUNTIL:
7045 cmdputs("until ");
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007046 until:
Eric Andersencb57d552001-06-28 07:25:16 +00007047 cmdtxt(n->nbinary.ch1);
7048 cmdputs("; do ");
7049 cmdtxt(n->nbinary.ch2);
7050 cmdputs("; done");
7051 break;
7052 case NFOR:
7053 cmdputs("for ");
7054 cmdputs(n->nfor.var);
7055 cmdputs(" in ...");
7056 break;
7057 case NCASE:
7058 cmdputs("case ");
7059 cmdputs(n->ncase.expr->narg.text);
7060 cmdputs(" in ...");
7061 break;
7062 case NDEFUN:
7063 cmdputs(n->narg.text);
7064 cmdputs("() ...");
7065 break;
7066 case NCMD:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007067 for (np = n->ncmd.args; np; np = np->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00007068 cmdtxt(np);
7069 if (np->narg.next)
7070 cmdputs(spcstr);
7071 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007072 for (np = n->ncmd.redirect; np; np = np->nfile.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00007073 cmdputs(spcstr);
7074 cmdtxt(np);
7075 }
7076 break;
7077 case NARG:
7078 cmdputs(n->narg.text);
7079 break;
7080 case NTO:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007081 p = ">";
7082 i = 1;
7083 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00007084 case NAPPEND:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007085 p = ">>";
7086 i = 1;
7087 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00007088 case NTOFD:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007089 p = ">&";
7090 i = 1;
7091 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00007092 case NTOOV:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007093 p = ">|";
7094 i = 1;
7095 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00007096 case NFROM:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007097 p = "<";
7098 i = 0;
7099 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00007100 case NFROMFD:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007101 p = "<&";
7102 i = 0;
7103 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00007104 case NFROMTO:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007105 p = "<>";
7106 i = 0;
7107 goto redir;
7108 redir:
Eric Andersencb57d552001-06-28 07:25:16 +00007109 if (n->nfile.fd != i) {
7110 s[0] = n->nfile.fd + '0';
7111 s[1] = '\0';
7112 cmdputs(s);
7113 }
7114 cmdputs(p);
7115 if (n->type == NTOFD || n->type == NFROMFD) {
7116 s[0] = n->ndup.dupfd + '0';
7117 s[1] = '\0';
7118 cmdputs(s);
7119 } else {
7120 cmdtxt(n->nfile.fname);
7121 }
7122 break;
7123 case NHERE:
7124 case NXHERE:
7125 cmdputs("<<...");
7126 break;
7127 default:
7128 cmdputs("???");
7129 break;
7130 }
7131}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007132#endif /* CMDTXT_TABLE */
Eric Andersencb57d552001-06-28 07:25:16 +00007133
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007134static char *commandtext(const union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007135{
7136 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007137
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007138 cmdnextc = name = xmalloc(MAXCMDTEXT);
Eric Andersen2870d962001-07-02 17:27:21 +00007139 cmdnleft = MAXCMDTEXT - 4;
7140 cmdtxt(n);
7141 *cmdnextc = '\0';
7142 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00007143}
7144
Eric Andersen2870d962001-07-02 17:27:21 +00007145
Eric Andersend35c5df2002-01-09 15:37:36 +00007146#ifdef CONFIG_ASH_MAIL
Eric Andersenec074692001-10-31 11:05:49 +00007147
Eric Andersencb57d552001-06-28 07:25:16 +00007148/*
Eric Andersenec074692001-10-31 11:05:49 +00007149 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +00007150 */
7151
7152
7153#define MAXMBOXES 10
7154
7155
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007156static int nmboxes; /* number of mailboxes */
7157static time_t mailtime[MAXMBOXES]; /* times of mailboxes */
Eric Andersencb57d552001-06-28 07:25:16 +00007158
7159
7160
7161/*
7162 * Print appropriate message(s) if mail has arrived. If the argument is
7163 * nozero, then the value of MAIL has changed, so we just update the
7164 * values.
7165 */
7166
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007167static void chkmail(int silent)
Eric Andersencb57d552001-06-28 07:25:16 +00007168{
7169 int i;
7170 const char *mpath;
7171 char *p;
7172 char *q;
7173 struct stackmark smark;
7174 struct stat statb;
7175
7176 if (silent)
7177 nmboxes = 10;
7178 if (nmboxes == 0)
7179 return;
7180 setstackmark(&smark);
7181 mpath = mpathset()? mpathval() : mailval();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007182 for (i = 0; i < nmboxes; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007183 p = padvance(&mpath, nullstr);
7184 if (p == NULL)
7185 break;
7186 if (*p == '\0')
7187 continue;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007188 for (q = p; *q; q++);
Eric Andersencb57d552001-06-28 07:25:16 +00007189#ifdef DEBUG
7190 if (q[-1] != '/')
7191 abort();
7192#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007193 q[-1] = '\0'; /* delete trailing '/' */
Eric Andersencb57d552001-06-28 07:25:16 +00007194 if (stat(p, &statb) < 0)
7195 statb.st_size = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007196 if (statb.st_size > mailtime[i] && !silent) {
7197 out2fmt(snlfmt, pathopt ? pathopt : "you have mail");
Eric Andersencb57d552001-06-28 07:25:16 +00007198 }
7199 mailtime[i] = statb.st_size;
Eric Andersencb57d552001-06-28 07:25:16 +00007200 }
7201 nmboxes = i;
7202 popstackmark(&smark);
7203}
Eric Andersencb57d552001-06-28 07:25:16 +00007204
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007205#endif /* CONFIG_ASH_MAIL */
Eric Andersenec074692001-10-31 11:05:49 +00007206
Eric Andersencb57d552001-06-28 07:25:16 +00007207#define PROFILE 0
7208
Eric Andersencb57d552001-06-28 07:25:16 +00007209#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007210static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007211extern int etext();
7212#endif
7213
Robert Griebl64f70cc2002-05-14 23:22:06 +00007214static int isloginsh = 0;
7215
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007216static void read_profile(const char *);
7217static void cmdloop(int);
7218static void options(int);
7219static void setoption(int, int);
7220static void procargs(int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00007221
Eric Andersen2870d962001-07-02 17:27:21 +00007222
Eric Andersencb57d552001-06-28 07:25:16 +00007223/*
7224 * Main routine. We initialize things, parse the arguments, execute
7225 * profiles if we're a login shell, and then call cmdloop to execute
7226 * commands. The setjmp call sets up the location to jump to when an
7227 * exception occurs. When an exception occurs the variable "state"
7228 * is used to figure out how far we had gotten.
7229 */
7230
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007231int ash_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007232{
7233 struct jmploc jmploc;
7234 struct stackmark smark;
7235 volatile int state;
Eric Andersen62483552001-07-10 06:09:16 +00007236 const char *shinit;
Eric Andersencb57d552001-06-28 07:25:16 +00007237
Eric Andersencb57d552001-06-28 07:25:16 +00007238 BLTINCMD = find_builtin("builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00007239 EXECCMD = find_builtin("exec");
7240 EVALCMD = find_builtin("eval");
7241
Eric Andersenbdfd0d72001-10-24 05:00:29 +00007242#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
Eric Andersen1c039232001-07-07 00:05:55 +00007243 unsetenv("PS1");
7244 unsetenv("PS2");
7245#endif
7246
Eric Andersencb57d552001-06-28 07:25:16 +00007247#if PROFILE
7248 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7249#endif
7250#if defined(linux) || defined(__GNU__)
7251 signal(SIGCHLD, SIG_DFL);
7252#endif
7253 state = 0;
7254 if (setjmp(jmploc.loc)) {
7255 INTOFF;
7256 /*
7257 * When a shell procedure is executed, we raise the
7258 * exception EXSHELLPROC to clean up before executing
7259 * the shell procedure.
7260 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007261 if (exception == EXSHELLPROC) {
Eric Andersencb57d552001-06-28 07:25:16 +00007262 rootpid = getpid();
7263 rootshell = 1;
7264 minusc = NULL;
7265 state = 3;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007266 } else {
7267 if (exception == EXEXEC) {
7268 exitstatus = exerrno;
7269 } else if (exception == EXERROR) {
7270 exitstatus = 2;
7271 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007272 if (state == 0 || iflag == 0 || !rootshell)
7273 exitshell(exitstatus);
Eric Andersencb57d552001-06-28 07:25:16 +00007274 }
7275 reset();
Eric Andersen2870d962001-07-02 17:27:21 +00007276 if (exception == EXINT) {
Eric Andersencb57d552001-06-28 07:25:16 +00007277 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00007278 }
7279 popstackmark(&smark);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007280 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007281 if (state == 1)
7282 goto state1;
7283 else if (state == 2)
7284 goto state2;
7285 else if (state == 3)
7286 goto state3;
7287 else
7288 goto state4;
7289 }
7290 handler = &jmploc;
7291#ifdef DEBUG
7292 opentrace();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007293 trputs("Shell args: ");
7294 trargs(argv);
Eric Andersencb57d552001-06-28 07:25:16 +00007295#endif
7296 rootpid = getpid();
7297 rootshell = 1;
7298 init();
7299 setstackmark(&smark);
7300 procargs(argc, argv);
Robert Griebl64f70cc2002-05-14 23:22:06 +00007301 if (argv[0] && argv[0][0] == '-')
7302 isloginsh = 1;
7303 if (isloginsh) {
Eric Andersencb57d552001-06-28 07:25:16 +00007304 state = 1;
7305 read_profile("/etc/profile");
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007306 state1:
Eric Andersencb57d552001-06-28 07:25:16 +00007307 state = 2;
7308 read_profile(".profile");
7309 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007310 state2:
Eric Andersencb57d552001-06-28 07:25:16 +00007311 state = 3;
7312#ifndef linux
7313 if (getuid() == geteuid() && getgid() == getegid()) {
7314#endif
7315 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7316 state = 3;
7317 read_profile(shinit);
7318 }
7319#ifndef linux
7320 }
7321#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007322 state3:
Eric Andersencb57d552001-06-28 07:25:16 +00007323 state = 4;
7324 if (sflag == 0 || minusc) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007325 static const char sigs[] = {
7326 SIGINT, SIGQUIT, SIGHUP,
Eric Andersencb57d552001-06-28 07:25:16 +00007327#ifdef SIGTSTP
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007328 SIGTSTP,
Eric Andersencb57d552001-06-28 07:25:16 +00007329#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007330 SIGPIPE
Eric Andersencb57d552001-06-28 07:25:16 +00007331 };
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007332
Glenn L McGrath50812ff2002-08-23 13:14:48 +00007333#define SIGSSIZE ((sizeof(sigs)/sizeof(sigs[0])))
Eric Andersencb57d552001-06-28 07:25:16 +00007334 int i;
7335
7336 for (i = 0; i < SIGSSIZE; i++)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007337 setsignal(sigs[i]);
Eric Andersencb57d552001-06-28 07:25:16 +00007338 }
7339
7340 if (minusc)
7341 evalstring(minusc, 0);
7342
7343 if (sflag || minusc == NULL) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007344 state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007345 cmdloop(1);
7346 }
7347#if PROFILE
7348 monitor(0);
7349#endif
7350 exitshell(exitstatus);
7351 /* NOTREACHED */
7352}
7353
7354
7355/*
7356 * Read and execute commands. "Top" is nonzero for the top level command
7357 * loop; it turns on prompting if the shell is interactive.
7358 */
7359
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007360static void cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00007361{
7362 union node *n;
7363 struct stackmark smark;
7364 int inter;
7365 int numeof = 0;
7366
7367 TRACE(("cmdloop(%d) called\n", top));
7368 setstackmark(&smark);
7369 for (;;) {
7370 if (pendingsigs)
7371 dotrap();
7372 inter = 0;
7373 if (iflag && top) {
7374 inter++;
7375 showjobs(1);
Eric Andersend35c5df2002-01-09 15:37:36 +00007376#ifdef CONFIG_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +00007377 chkmail(0);
Eric Andersenec074692001-10-31 11:05:49 +00007378#endif
Eric Andersen3102ac42001-07-06 04:26:23 +00007379 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00007380 }
7381 n = parsecmd(inter);
7382 /* showtree(n); DEBUG */
7383 if (n == NEOF) {
7384 if (!top || numeof >= 50)
7385 break;
7386 if (!stoppedjobs()) {
7387 if (!Iflag)
7388 break;
7389 out2str("\nUse \"exit\" to leave shell.\n");
7390 }
7391 numeof++;
7392 } else if (n != NULL && nflag == 0) {
7393 job_warning = (job_warning == 2) ? 1 : 0;
7394 numeof = 0;
7395 evaltree(n, 0);
7396 }
7397 popstackmark(&smark);
7398 setstackmark(&smark);
7399 if (evalskip == SKIPFILE) {
7400 evalskip = 0;
7401 break;
7402 }
7403 }
7404 popstackmark(&smark);
7405}
7406
7407
7408
7409/*
7410 * Read /etc/profile or .profile. Return on error.
7411 */
7412
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007413static void read_profile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00007414{
7415 int fd;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007416 int xflag_save;
7417 int vflag_save;
Eric Andersencb57d552001-06-28 07:25:16 +00007418
7419 INTOFF;
7420 if ((fd = open(name, O_RDONLY)) >= 0)
7421 setinputfd(fd, 1);
7422 INTON;
7423 if (fd < 0)
7424 return;
7425 /* -q turns off -x and -v just when executing init files */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007426 /* Note: Might do a little redundant work, but reduces code size. */
7427 xflag_save = xflag;
7428 vflag_save = vflag;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007429 if (qflag) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007430 vflag = xflag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007431 }
7432 cmdloop(0);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007433 xflag = xflag_save;
7434 vflag = vflag_save;
Eric Andersencb57d552001-06-28 07:25:16 +00007435 popfile();
7436}
7437
7438
7439
7440/*
7441 * Read a file containing shell functions.
7442 */
7443
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007444static void readcmdfile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00007445{
7446 int fd;
7447
7448 INTOFF;
7449 if ((fd = open(name, O_RDONLY)) >= 0)
7450 setinputfd(fd, 1);
7451 else
7452 error("Can't open %s", name);
7453 INTON;
7454 cmdloop(0);
7455 popfile();
7456}
7457
7458
7459
7460/*
7461 * Take commands from a file. To be compatable we should do a path
7462 * search for the file, which is necessary to find sub-commands.
7463 */
7464
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007465static inline char *find_dot_file(char *mybasename)
Eric Andersencb57d552001-06-28 07:25:16 +00007466{
7467 char *fullname;
7468 const char *path = pathval();
7469 struct stat statb;
7470
7471 /* don't try this for absolute or relative paths */
7472 if (strchr(mybasename, '/'))
7473 return mybasename;
7474
7475 while ((fullname = padvance(&path, mybasename)) != NULL) {
7476 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
7477 /*
7478 * Don't bother freeing here, since it will
7479 * be freed by the caller.
7480 */
7481 return fullname;
7482 }
7483 stunalloc(fullname);
7484 }
7485
7486 /* not found in the PATH */
7487 error("%s: not found", mybasename);
7488 /* NOTREACHED */
7489}
7490
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007491static int dotcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007492{
7493 struct strlist *sp;
Eric Andersen69a20f02001-10-31 10:40:37 +00007494 volatile struct shparam saveparam;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007495
Eric Andersencb57d552001-06-28 07:25:16 +00007496 exitstatus = 0;
7497
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007498 for (sp = cmdenviron; sp; sp = sp->next)
7499 setvareq(xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +00007500
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007501 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00007502 char *fullname;
7503 struct stackmark smark;
7504
7505 setstackmark(&smark);
7506 fullname = find_dot_file(argv[1]);
Eric Andersen69a20f02001-10-31 10:40:37 +00007507
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007508 if (argc > 2) {
Eric Andersen69a20f02001-10-31 10:40:37 +00007509 saveparam = shellparam;
7510 shellparam.malloc = 0;
7511 shellparam.nparam = argc - 2;
7512 shellparam.p = argv + 2;
7513 };
7514
Eric Andersencb57d552001-06-28 07:25:16 +00007515 setinputfile(fullname, 1);
7516 commandname = fullname;
7517 cmdloop(0);
7518 popfile();
Eric Andersen69a20f02001-10-31 10:40:37 +00007519
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007520 if (argc > 2) {
Eric Andersen69a20f02001-10-31 10:40:37 +00007521 freeparam(&shellparam);
7522 shellparam = saveparam;
7523 };
7524
Eric Andersencb57d552001-06-28 07:25:16 +00007525 popstackmark(&smark);
7526 }
7527 return exitstatus;
7528}
7529
7530
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007531static int exitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007532{
7533 if (stoppedjobs())
7534 return 0;
7535 if (argc > 1)
7536 exitstatus = number(argv[1]);
7537 else
7538 exitstatus = oexitstatus;
7539 exitshell(exitstatus);
7540 /* NOTREACHED */
7541}
Eric Andersen62483552001-07-10 06:09:16 +00007542
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007543static pointer stalloc(int nbytes)
Eric Andersencb57d552001-06-28 07:25:16 +00007544{
7545 char *p;
7546
7547 nbytes = ALIGN(nbytes);
7548 if (nbytes > stacknleft) {
7549 int blocksize;
7550 struct stack_block *sp;
7551
7552 blocksize = nbytes;
7553 if (blocksize < MINSIZE)
7554 blocksize = MINSIZE;
7555 INTOFF;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007556 sp = xmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
Eric Andersencb57d552001-06-28 07:25:16 +00007557 sp->prev = stackp;
7558 stacknxt = sp->space;
7559 stacknleft = blocksize;
7560 stackp = sp;
7561 INTON;
7562 }
7563 p = stacknxt;
7564 stacknxt += nbytes;
7565 stacknleft -= nbytes;
7566 return p;
7567}
7568
7569
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007570static void stunalloc(pointer p)
Eric Andersen2870d962001-07-02 17:27:21 +00007571{
Eric Andersencb57d552001-06-28 07:25:16 +00007572#ifdef DEBUG
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007573 if (p == NULL) { /*DEBUG */
Eric Andersencb57d552001-06-28 07:25:16 +00007574 write(2, "stunalloc\n", 10);
7575 abort();
7576 }
7577#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007578 if (!(stacknxt >= (char *) p && (char *) p >= stackp->space)) {
Eric Andersencb57d552001-06-28 07:25:16 +00007579 p = stackp->space;
7580 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007581 stacknleft += stacknxt - (char *) p;
Eric Andersencb57d552001-06-28 07:25:16 +00007582 stacknxt = p;
7583}
7584
7585
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007586static void setstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00007587{
Eric Andersencb57d552001-06-28 07:25:16 +00007588 mark->stackp = stackp;
7589 mark->stacknxt = stacknxt;
7590 mark->stacknleft = stacknleft;
7591 mark->marknext = markp;
7592 markp = mark;
7593}
7594
7595
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007596static void popstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00007597{
Eric Andersencb57d552001-06-28 07:25:16 +00007598 struct stack_block *sp;
7599
7600 INTOFF;
7601 markp = mark->marknext;
7602 while (stackp != mark->stackp) {
7603 sp = stackp;
7604 stackp = sp->prev;
Aaron Lehmann49c024a2002-08-02 06:39:47 +00007605 free(sp);
Eric Andersencb57d552001-06-28 07:25:16 +00007606 }
7607 stacknxt = mark->stacknxt;
7608 stacknleft = mark->stacknleft;
7609 INTON;
7610}
7611
7612
7613/*
7614 * When the parser reads in a string, it wants to stick the string on the
7615 * stack and only adjust the stack pointer when it knows how big the
7616 * string is. Stackblock (defined in stack.h) returns a pointer to a block
7617 * of space on top of the stack and stackblocklen returns the length of
7618 * this block. Growstackblock will grow this space by at least one byte,
7619 * possibly moving it (like realloc). Grabstackblock actually allocates the
7620 * part of the block that has been used.
7621 */
7622
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007623static void growstackblock(void)
7624{
Eric Andersencb57d552001-06-28 07:25:16 +00007625 char *p;
7626 int newlen = ALIGN(stacknleft * 2 + 100);
7627 char *oldspace = stacknxt;
7628 int oldlen = stacknleft;
7629 struct stack_block *sp;
7630 struct stack_block *oldstackp;
7631
7632 if (stacknxt == stackp->space && stackp != &stackbase) {
7633 INTOFF;
7634 oldstackp = stackp;
7635 sp = stackp;
7636 stackp = sp->prev;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007637 sp = xrealloc((pointer) sp,
7638 sizeof(struct stack_block) - MINSIZE + newlen);
Eric Andersencb57d552001-06-28 07:25:16 +00007639 sp->prev = stackp;
7640 stackp = sp;
7641 stacknxt = sp->space;
7642 stacknleft = newlen;
7643 {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007644 /* Stack marks pointing to the start of the old block
7645 * must be relocated to point to the new block
7646 */
7647 struct stackmark *xmark;
7648
7649 xmark = markp;
7650 while (xmark != NULL && xmark->stackp == oldstackp) {
7651 xmark->stackp = stackp;
7652 xmark->stacknxt = stacknxt;
7653 xmark->stacknleft = stacknleft;
7654 xmark = xmark->marknext;
7655 }
Eric Andersencb57d552001-06-28 07:25:16 +00007656 }
7657 INTON;
7658 } else {
7659 p = stalloc(newlen);
7660 memcpy(p, oldspace, oldlen);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007661 stacknxt = p; /* free the space */
7662 stacknleft += newlen; /* we just allocated */
Eric Andersencb57d552001-06-28 07:25:16 +00007663 }
7664}
7665
7666
7667
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007668static inline void grabstackblock(int len)
Eric Andersencb57d552001-06-28 07:25:16 +00007669{
7670 len = ALIGN(len);
7671 stacknxt += len;
7672 stacknleft -= len;
7673}
7674
7675
7676
7677/*
7678 * The following routines are somewhat easier to use that the above.
7679 * The user declares a variable of type STACKSTR, which may be declared
7680 * to be a register. The macro STARTSTACKSTR initializes things. Then
7681 * the user uses the macro STPUTC to add characters to the string. In
7682 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
7683 * grown as necessary. When the user is done, she can just leave the
7684 * string there and refer to it using stackblock(). Or she can allocate
7685 * the space for it using grabstackstr(). If it is necessary to allow
7686 * someone else to use the stack temporarily and then continue to grow
7687 * the string, the user should use grabstack to allocate the space, and
7688 * then call ungrabstr(p) to return to the previous mode of operation.
7689 *
7690 * USTPUTC is like STPUTC except that it doesn't check for overflow.
7691 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
7692 * is space for at least one character.
7693 */
7694
7695
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007696static char *growstackstr(void)
7697{
Eric Andersencb57d552001-06-28 07:25:16 +00007698 int len = stackblocksize();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007699
Eric Andersencb57d552001-06-28 07:25:16 +00007700 if (herefd >= 0 && len >= 1024) {
7701 xwrite(herefd, stackblock(), len);
7702 sstrnleft = len - 1;
7703 return stackblock();
7704 }
7705 growstackblock();
7706 sstrnleft = stackblocksize() - len - 1;
7707 return stackblock() + len;
7708}
7709
7710
7711/*
7712 * Called from CHECKSTRSPACE.
7713 */
7714
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007715static char *makestrspace(size_t newlen)
7716{
Eric Andersencb57d552001-06-28 07:25:16 +00007717 int len = stackblocksize() - sstrnleft;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007718
Eric Andersencb57d552001-06-28 07:25:16 +00007719 do {
7720 growstackblock();
7721 sstrnleft = stackblocksize() - len;
7722 } while (sstrnleft < newlen);
7723 return stackblock() + len;
7724}
7725
7726
7727
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007728static void ungrabstackstr(char *s, char *p)
Eric Andersen2870d962001-07-02 17:27:21 +00007729{
Eric Andersencb57d552001-06-28 07:25:16 +00007730 stacknleft += stacknxt - s;
7731 stacknxt = s;
7732 sstrnleft = stacknleft - (p - s);
7733}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007734
Eric Andersencb57d552001-06-28 07:25:16 +00007735/*
7736 * Miscelaneous builtins.
7737 */
7738
7739
7740#undef rflag
7741
Eric Andersencb57d552001-06-28 07:25:16 +00007742#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersen62483552001-07-10 06:09:16 +00007743typedef long rlim_t;
Eric Andersencb57d552001-06-28 07:25:16 +00007744#endif
7745
7746
7747
7748/*
7749 * The read builtin. The -e option causes backslashes to escape the
7750 * following character.
7751 *
7752 * This uses unbuffered input, which may be avoidable in some cases.
7753 */
7754
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007755static int readcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007756{
7757 char **ap;
7758 int backslash;
7759 char c;
7760 int rflag;
7761 char *prompt;
7762 const char *ifs;
7763 char *p;
7764 int startword;
7765 int status;
7766 int i;
7767
7768 rflag = 0;
7769 prompt = NULL;
7770 while ((i = nextopt("p:r")) != '\0') {
7771 if (i == 'p')
7772 prompt = optionarg;
7773 else
7774 rflag = 1;
7775 }
7776 if (prompt && isatty(0)) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007777 out2str(prompt); /* read without cmdedit */
Eric Andersencb57d552001-06-28 07:25:16 +00007778 flushall();
7779 }
7780 if (*(ap = argptr) == NULL)
7781 error("arg count");
7782 if ((ifs = bltinlookup("IFS")) == NULL)
7783 ifs = defifs;
7784 status = 0;
7785 startword = 1;
7786 backslash = 0;
7787 STARTSTACKSTR(p);
7788 for (;;) {
7789 if (read(0, &c, 1) != 1) {
7790 status = 1;
7791 break;
7792 }
7793 if (c == '\0')
7794 continue;
7795 if (backslash) {
7796 backslash = 0;
7797 if (c != '\n')
7798 STPUTC(c, p);
7799 continue;
7800 }
7801 if (!rflag && c == '\\') {
7802 backslash++;
7803 continue;
7804 }
7805 if (c == '\n')
7806 break;
7807 if (startword && *ifs == ' ' && strchr(ifs, c)) {
7808 continue;
7809 }
7810 startword = 0;
7811 if (backslash && c == '\\') {
7812 if (read(0, &c, 1) != 1) {
7813 status = 1;
7814 break;
7815 }
7816 STPUTC(c, p);
7817 } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
7818 STACKSTRNUL(p);
7819 setvar(*ap, stackblock(), 0);
7820 ap++;
7821 startword = 1;
7822 STARTSTACKSTR(p);
7823 } else {
7824 STPUTC(c, p);
7825 }
7826 }
7827 STACKSTRNUL(p);
7828 /* Remove trailing blanks */
7829 while (stackblock() <= --p && strchr(ifs, *p) != NULL)
7830 *p = '\0';
7831 setvar(*ap, stackblock(), 0);
7832 while (*++ap != NULL)
7833 setvar(*ap, nullstr, 0);
7834 return status;
7835}
7836
7837
7838
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007839static int umaskcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007840{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007841 static const char permuser[3] = "ugo";
7842 static const char permmode[3] = "rwx";
7843 static const short int permmask[] = {
7844 S_IRUSR, S_IWUSR, S_IXUSR,
7845 S_IRGRP, S_IWGRP, S_IXGRP,
7846 S_IROTH, S_IWOTH, S_IXOTH
7847 };
7848
Eric Andersencb57d552001-06-28 07:25:16 +00007849 char *ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007850 mode_t mask;
Eric Andersencb57d552001-06-28 07:25:16 +00007851 int i;
7852 int symbolic_mode = 0;
7853
Eric Andersen62483552001-07-10 06:09:16 +00007854 while (nextopt("S") != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00007855 symbolic_mode = 1;
7856 }
7857
7858 INTOFF;
7859 mask = umask(0);
7860 umask(mask);
7861 INTON;
7862
7863 if ((ap = *argptr) == NULL) {
7864 if (symbolic_mode) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007865 char buf[18];
7866 char *p = buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007867
7868 for (i = 0; i < 3; i++) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007869 int j;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007870
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007871 *p++ = permuser[i];
7872 *p++ = '=';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007873 for (j = 0; j < 3; j++) {
7874 if ((mask & permmask[3 * i + j]) == 0) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007875 *p++ = permmode[j];
7876 }
7877 }
7878 *p++ = ',';
7879 }
7880 *--p = 0;
7881 puts(buf);
Eric Andersencb57d552001-06-28 07:25:16 +00007882 } else {
Eric Andersen62483552001-07-10 06:09:16 +00007883 printf("%.4o\n", mask);
Eric Andersencb57d552001-06-28 07:25:16 +00007884 }
7885 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007886 if (is_digit((unsigned char) *ap)) {
Eric Andersencb57d552001-06-28 07:25:16 +00007887 mask = 0;
7888 do {
7889 if (*ap >= '8' || *ap < '0')
7890 error("Illegal number: %s", argv[1]);
7891 mask = (mask << 3) + (*ap - '0');
7892 } while (*++ap != '\0');
7893 umask(mask);
7894 } else {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007895 mask = ~mask & 0777;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007896 if (!parse_mode(ap, &mask)) {
Eric Andersencb57d552001-06-28 07:25:16 +00007897 error("Illegal mode: %s", ap);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007898 }
Eric Andersencb57d552001-06-28 07:25:16 +00007899 umask(~mask & 0777);
7900 }
7901 }
7902 return 0;
7903}
7904
7905/*
7906 * ulimit builtin
7907 *
7908 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
7909 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
7910 * ash by J.T. Conklin.
7911 *
7912 * Public domain.
7913 */
7914
7915struct limits {
7916 const char *name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007917 short cmd;
7918 short factor; /* multiply by to get rlim_{cur,max} values */
Eric Andersencb57d552001-06-28 07:25:16 +00007919};
7920
7921static const struct limits limits[] = {
7922#ifdef RLIMIT_CPU
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007923 {"time(seconds)", RLIMIT_CPU, 1},
Eric Andersencb57d552001-06-28 07:25:16 +00007924#endif
7925#ifdef RLIMIT_FSIZE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007926 {"file(blocks)", RLIMIT_FSIZE, 512},
Eric Andersencb57d552001-06-28 07:25:16 +00007927#endif
7928#ifdef RLIMIT_DATA
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007929 {"data(kbytes)", RLIMIT_DATA, 1024},
Eric Andersencb57d552001-06-28 07:25:16 +00007930#endif
7931#ifdef RLIMIT_STACK
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007932 {"stack(kbytes)", RLIMIT_STACK, 1024},
Eric Andersencb57d552001-06-28 07:25:16 +00007933#endif
7934#ifdef RLIMIT_CORE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007935 {"coredump(blocks)", RLIMIT_CORE, 512},
Eric Andersencb57d552001-06-28 07:25:16 +00007936#endif
7937#ifdef RLIMIT_RSS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007938 {"memory(kbytes)", RLIMIT_RSS, 1024},
Eric Andersencb57d552001-06-28 07:25:16 +00007939#endif
7940#ifdef RLIMIT_MEMLOCK
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007941 {"locked memory(kbytes)", RLIMIT_MEMLOCK, 1024},
Eric Andersencb57d552001-06-28 07:25:16 +00007942#endif
7943#ifdef RLIMIT_NPROC
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007944 {"process(processes)", RLIMIT_NPROC, 1},
Eric Andersencb57d552001-06-28 07:25:16 +00007945#endif
7946#ifdef RLIMIT_NOFILE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007947 {"nofiles(descriptors)", RLIMIT_NOFILE, 1},
Eric Andersencb57d552001-06-28 07:25:16 +00007948#endif
7949#ifdef RLIMIT_VMEM
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007950 {"vmemory(kbytes)", RLIMIT_VMEM, 1024},
Eric Andersencb57d552001-06-28 07:25:16 +00007951#endif
7952#ifdef RLIMIT_SWAP
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007953 {"swap(kbytes)", RLIMIT_SWAP, 1024},
Eric Andersencb57d552001-06-28 07:25:16 +00007954#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007955 {NULL, 0, 0}
Eric Andersencb57d552001-06-28 07:25:16 +00007956};
7957
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007958static int ulimitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007959{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007960 static const char unlimited_string[] = "unlimited";
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007961 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00007962 rlim_t val = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007963 enum { SOFT = 0x1, HARD = 0x2 } how = SOFT | HARD;
7964 const struct limits *l;
7965 int set, all = 0;
7966 int optc, what;
7967 struct rlimit limit;
Eric Andersencb57d552001-06-28 07:25:16 +00007968
7969 what = 'f';
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007970
7971 while ((optc = nextopt("HSa"
7972#ifdef RLIMIT_CPU
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007973 "t"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007974#endif
7975#ifdef RLIMIT_FSIZE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007976 "f"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007977#endif
7978#ifdef RLIMIT_DATA
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007979 "d"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007980#endif
7981#ifdef RLIMIT_STACK
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007982 "s"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007983#endif
7984#ifdef RLIMIT_CORE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007985 "c"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007986#endif
7987#ifdef RLIMIT_RSS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007988 "m"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007989#endif
7990#ifdef RLIMIT_MEMLOCK
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007991 "l"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007992#endif
7993#ifdef RLIMIT_NPROC
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007994 "p"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007995#endif
7996#ifdef RLIMIT_NOFILE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007997 "n"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007998#endif
7999#ifdef RLIMIT_VMEM
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008000 "v"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008001#endif
8002#ifdef RLIMIT_SWAP
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008003 "w"
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008004#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008005 )) != '\0') {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008006 if (optc == 'H') {
Eric Andersencb57d552001-06-28 07:25:16 +00008007 how = HARD;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008008 } else if (optc == 'S') {
Eric Andersencb57d552001-06-28 07:25:16 +00008009 how = SOFT;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008010 } else if (optc == 'a') {
Eric Andersencb57d552001-06-28 07:25:16 +00008011 all = 1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008012 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00008013 what = optc;
8014 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008015 }
Eric Andersencb57d552001-06-28 07:25:16 +00008016
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008017 for (l = limits; l->name; l++) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008018 if (l->name[0] == what)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008019 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008020 if (l->name[1] == 'w' && what == 'w')
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008021 break;
8022 }
Eric Andersencb57d552001-06-28 07:25:16 +00008023
8024 set = *argptr ? 1 : 0;
8025 if (set) {
8026 char *p = *argptr;
8027
8028 if (all || argptr[1])
8029 error("too many arguments");
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008030 if (strcmp(p, unlimited_string) == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00008031 val = RLIM_INFINITY;
8032 else {
8033 val = (rlim_t) 0;
8034
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008035 while ((c = *p++) >= '0' && c <= '9') {
8036 val = (val * 10) + (long) (c - '0');
Eric Andersencb57d552001-06-28 07:25:16 +00008037 if (val < (rlim_t) 0)
8038 break;
8039 }
8040 if (c)
8041 error("bad number");
8042 val *= l->factor;
8043 }
8044 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008045
Eric Andersencb57d552001-06-28 07:25:16 +00008046 if (all) {
8047 for (l = limits; l->name; l++) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008048 printf("%-20s ", l->name);
Eric Andersencb57d552001-06-28 07:25:16 +00008049 getrlimit(l->cmd, &limit);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008050 OUTPUT_LIMIT:
Eric Andersencb57d552001-06-28 07:25:16 +00008051 if (how & SOFT)
8052 val = limit.rlim_cur;
8053 else if (how & HARD)
8054 val = limit.rlim_max;
8055
Eric Andersencb57d552001-06-28 07:25:16 +00008056 if (val == RLIM_INFINITY)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008057 puts(unlimited_string);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008058 else {
Eric Andersencb57d552001-06-28 07:25:16 +00008059 val /= l->factor;
Eric Andersen62483552001-07-10 06:09:16 +00008060 printf("%lld\n", (long long) val);
Eric Andersencb57d552001-06-28 07:25:16 +00008061 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008062 if (!all) {
8063 break;
8064 }
Eric Andersencb57d552001-06-28 07:25:16 +00008065 }
8066 return 0;
8067 }
8068
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008069 if (!set) {
8070 goto OUTPUT_LIMIT;
Eric Andersencb57d552001-06-28 07:25:16 +00008071 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008072
8073 getrlimit(l->cmd, &limit);
8074 if (how & HARD)
8075 limit.rlim_max = val;
8076 if (how & SOFT)
8077 limit.rlim_cur = val;
8078 if (setrlimit(l->cmd, &limit) < 0)
8079 error("error setting limit (%m)");
Eric Andersencb57d552001-06-28 07:25:16 +00008080 return 0;
8081}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008082
Eric Andersencb57d552001-06-28 07:25:16 +00008083/*
8084 * prefix -- see if pfx is a prefix of string.
8085 */
8086
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008087static int prefix(char const *pfx, char const *string)
Eric Andersen62483552001-07-10 06:09:16 +00008088{
Eric Andersencb57d552001-06-28 07:25:16 +00008089 while (*pfx) {
8090 if (*pfx++ != *string++)
8091 return 0;
8092 }
8093 return 1;
8094}
8095
Eric Andersen2870d962001-07-02 17:27:21 +00008096/*
8097 * Return true if s is a string of digits, and save munber in intptr
8098 * nagative is bad
8099 */
8100
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008101static int is_number(const char *p, int *intptr)
Eric Andersen2870d962001-07-02 17:27:21 +00008102{
8103 int ret = 0;
8104
8105 do {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008106 if (!is_digit(*p))
Eric Andersen2870d962001-07-02 17:27:21 +00008107 return 0;
8108 ret *= 10;
8109 ret += digit_val(*p);
8110 p++;
8111 } while (*p != '\0');
8112
8113 *intptr = ret;
8114 return 1;
8115}
Eric Andersencb57d552001-06-28 07:25:16 +00008116
8117/*
8118 * Convert a string of digits to an integer, printing an error message on
8119 * failure.
8120 */
8121
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008122static int number(const char *s)
Eric Andersen2870d962001-07-02 17:27:21 +00008123{
8124 int i;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008125
8126 if (!is_number(s, &i))
Eric Andersencb57d552001-06-28 07:25:16 +00008127 error("Illegal number: %s", s);
Eric Andersen2870d962001-07-02 17:27:21 +00008128 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00008129}
8130
Eric Andersencb57d552001-06-28 07:25:16 +00008131/*
8132 * Produce a possibly single quoted string suitable as input to the shell.
8133 * The return string is allocated on the stack.
8134 */
8135
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008136static char *single_quote(const char *s)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008137{
Eric Andersencb57d552001-06-28 07:25:16 +00008138 char *p;
8139
8140 STARTSTACKSTR(p);
8141
8142 do {
8143 char *q = p;
8144 size_t len1, len1p, len2, len2p;
8145
8146 len1 = strcspn(s, "'");
8147 len2 = strspn(s + len1, "'");
8148
8149 len1p = len1 ? len1 + 2 : len1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008150 len2p = len2 + ((len2 < 2) ? len2 : 2);
Eric Andersencb57d552001-06-28 07:25:16 +00008151
8152 CHECKSTRSPACE(len1p + len2p + 1, p);
8153
8154 if (len1) {
8155 *p = '\'';
Eric Andersencb57d552001-06-28 07:25:16 +00008156 q = p + 1 + len1;
8157 memcpy(p + 1, s, len1);
Eric Andersencb57d552001-06-28 07:25:16 +00008158 *q++ = '\'';
8159 s += len1;
8160 }
8161
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008162 if (len2 > 1) {
Eric Andersencb57d552001-06-28 07:25:16 +00008163 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008164 q += 1 + len2;
8165 memcpy(q + 1, s, len2);
8166 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008167 s += len2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008168 } else if (len2 == 1) {
8169 *q++ = '\\';
8170 *q = '\'';
8171 s++;
Eric Andersencb57d552001-06-28 07:25:16 +00008172 }
8173
8174 STADJUST(len1p + len2p, p);
8175 } while (*s);
8176
8177 USTPUTC(0, p);
8178
8179 return grabstackstr(p);
8180}
8181
8182/*
Eric Andersencb57d552001-06-28 07:25:16 +00008183 * Routine for dealing with parsed shell commands.
8184 */
8185
8186
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008187static void sizenodelist(const struct nodelist *);
8188static struct nodelist *copynodelist(const struct nodelist *);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008189static char *nodesavestr(const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00008190
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00008191#define CALCSIZE_TABLE
8192#define COPYNODE_TABLE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008193#if defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE)
8194/*
8195 * To collect a lot of redundant code in case statements for copynode()
8196 * and calcsize(), we implement a mini language here. Each type of node
8197 * struct has an associated instruction sequence that operates on its
8198 * members via their offsets. The instruction are pack in unsigned chars
8199 * with format IIDDDDDE where the bits are
8200 * I : part of the instruction opcode, which are
8201 * 00 : member is a pointer to another node
8202 * 40 : member is an integer
8203 * 80 : member is a pointer to a nodelist
8204 * CC : member is a pointer to a char string
8205 * D : data - the actual offset of the member to operate on in the struct
8206 * (since we assume bit 0 is set, it is not shifted)
8207 * E : flag signaling end of instruction sequence
8208 *
8209 * WARNING: In order to handle larger offsets for 64bit archs, this code
8210 * assumes that no offset can be an odd number and stores the
8211 * end-of-instructions flag in bit 0.
8212 */
8213
8214#define NODE_INTEGER 0x40
8215#define NODE_NODELIST 0x80
8216#define NODE_CHARPTR 0xC0
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008217#define NODE_NOMORE 0x01 /* Note: no offset should be odd (aligned) */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008218#define NODE_MBRMASK 0xC0
8219#define NODE_OFFSETMASK 0x3E
8220
8221static const unsigned char copynode_ops[35] = {
8222#define COPYNODE_OPS0 0
8223 offsetof(union node, nbinary.ch2),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008224 offsetof(union node, nbinary.ch1) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008225#define COPYNODE_OPS1 (COPYNODE_OPS0 + 2)
8226 offsetof(union node, ncmd.redirect),
8227 offsetof(union node, ncmd.args),
8228 offsetof(union node, ncmd.assign),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008229 offsetof(union node, ncmd.backgnd) | NODE_INTEGER | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008230#define COPYNODE_OPS2 (COPYNODE_OPS1 + 4)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008231 offsetof(union node, npipe.cmdlist) | NODE_NODELIST,
8232 offsetof(union node, npipe.backgnd) | NODE_INTEGER | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008233#define COPYNODE_OPS3 (COPYNODE_OPS2 + 2)
8234 offsetof(union node, nredir.redirect),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008235 offsetof(union node, nredir.n) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008236#define COPYNODE_OPS4 (COPYNODE_OPS3 + 2)
8237 offsetof(union node, nif.elsepart),
8238 offsetof(union node, nif.ifpart),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008239 offsetof(union node, nif.test) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008240#define COPYNODE_OPS5 (COPYNODE_OPS4 + 3)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008241 offsetof(union node, nfor.var) | NODE_CHARPTR,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008242 offsetof(union node, nfor.body),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008243 offsetof(union node, nfor.args) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008244#define COPYNODE_OPS6 (COPYNODE_OPS5 + 3)
8245 offsetof(union node, ncase.cases),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008246 offsetof(union node, ncase.expr) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008247#define COPYNODE_OPS7 (COPYNODE_OPS6 + 2)
8248 offsetof(union node, nclist.body),
8249 offsetof(union node, nclist.pattern),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008250 offsetof(union node, nclist.next) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008251#define COPYNODE_OPS8 (COPYNODE_OPS7 + 3)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008252 offsetof(union node, narg.backquote) | NODE_NODELIST,
8253 offsetof(union node, narg.text) | NODE_CHARPTR,
8254 offsetof(union node, narg.next) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008255#define COPYNODE_OPS9 (COPYNODE_OPS8 + 3)
8256 offsetof(union node, nfile.fname),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008257 offsetof(union node, nfile.fd) | NODE_INTEGER,
8258 offsetof(union node, nfile.next) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008259#define COPYNODE_OPS10 (COPYNODE_OPS9 + 3)
8260 offsetof(union node, ndup.vname),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008261 offsetof(union node, ndup.dupfd) | NODE_INTEGER,
8262 offsetof(union node, ndup.fd) | NODE_INTEGER,
8263 offsetof(union node, ndup.next) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008264#define COPYNODE_OPS11 (COPYNODE_OPS10 + 4)
8265 offsetof(union node, nhere.doc),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008266 offsetof(union node, nhere.fd) | NODE_INTEGER,
8267 offsetof(union node, nhere.next) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008268#define COPYNODE_OPS12 (COPYNODE_OPS11 + 3)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008269 offsetof(union node, nnot.com) | NODE_NOMORE,
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008270};
8271
8272#if COPYNODE_OPS12 != 34
8273#error COPYNODE_OPS12 is incorrect
8274#endif
8275
8276static const unsigned char copynode_ops_index[26] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008277 COPYNODE_OPS0, /* NSEMI */
8278 COPYNODE_OPS1, /* NCMD */
8279 COPYNODE_OPS2, /* NPIPE */
8280 COPYNODE_OPS3, /* NREDIR */
8281 COPYNODE_OPS3, /* NBACKGND */
8282 COPYNODE_OPS3, /* NSUBSHELL */
8283 COPYNODE_OPS0, /* NAND */
8284 COPYNODE_OPS0, /* NOR */
8285 COPYNODE_OPS4, /* NIF */
8286 COPYNODE_OPS0, /* NWHILE */
8287 COPYNODE_OPS0, /* NUNTIL */
8288 COPYNODE_OPS5, /* NFOR */
8289 COPYNODE_OPS6, /* NCASE */
8290 COPYNODE_OPS7, /* NCLIST */
8291 COPYNODE_OPS8, /* NDEFUN */
8292 COPYNODE_OPS8, /* NARG */
8293 COPYNODE_OPS9, /* NTO */
8294 COPYNODE_OPS9, /* NFROM */
8295 COPYNODE_OPS9, /* NFROMTO */
8296 COPYNODE_OPS9, /* NAPPEND */
8297 COPYNODE_OPS9, /* NTOOV */
8298 COPYNODE_OPS10, /* NTOFD */
8299 COPYNODE_OPS10, /* NFROMFD */
8300 COPYNODE_OPS11, /* NHERE */
8301 COPYNODE_OPS11, /* NXHERE */
8302 COPYNODE_OPS12, /* NNOT */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008303};
8304
8305#if NODE_CHARPTR != NODE_MBRMASK
8306#error NODE_CHARPTR != NODE_MBRMASK!!!
8307#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008308#endif /* defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE) */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008309
8310#ifdef COPYNODE_TABLE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008311static union node *copynode(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008312{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008313 union node *new;
8314 const unsigned char *p;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008315
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008316 if (n == NULL) {
8317 return NULL;
8318 }
8319 new = funcblock;
8320 new->type = n->type;
8321 funcblock = (char *) funcblock + (int) nodesize[n->type];
8322 p = copynode_ops + (int) copynode_ops_index[n->type];
8323 do {
8324 char *nn = ((char *) new) + ((int) (*p & NODE_OFFSETMASK));
8325 const char *no = ((const char *) n) + ((int) (*p & NODE_OFFSETMASK));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008326
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008327 if (!(*p & NODE_MBRMASK)) { /* standard node */
8328 *((union node **) nn) = copynode(*((const union node **) no));
8329 } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008330 *((const char **) nn) = nodesavestr(*((const char **) no));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008331 } else if (*p & NODE_NODELIST) { /* nodelist */
8332 *((struct nodelist **) nn)
8333 = copynodelist(*((const struct nodelist **) no));
8334 } else { /* integer */
8335 *((int *) nn) = *((int *) no);
8336 }
8337 } while (!(*p++ & NODE_NOMORE));
8338 return new;
Eric Andersencb57d552001-06-28 07:25:16 +00008339}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008340#else /* COPYNODE_TABLE */
8341static union node *copynode(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008342{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008343 union node *new;
Eric Andersencb57d552001-06-28 07:25:16 +00008344
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008345 if (n == NULL)
8346 return NULL;
8347 new = funcblock;
8348 funcblock = (char *) funcblock + nodesize[n->type];
8349 switch (n->type) {
8350 case NSEMI:
8351 case NAND:
8352 case NOR:
8353 case NWHILE:
8354 case NUNTIL:
8355 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8356 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8357 break;
8358 case NCMD:
8359 new->ncmd.redirect = copynode(n->ncmd.redirect);
8360 new->ncmd.args = copynode(n->ncmd.args);
8361 new->ncmd.assign = copynode(n->ncmd.assign);
8362 new->ncmd.backgnd = n->ncmd.backgnd;
8363 break;
8364 case NPIPE:
8365 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8366 new->npipe.backgnd = n->npipe.backgnd;
8367 break;
8368 case NREDIR:
8369 case NBACKGND:
8370 case NSUBSHELL:
8371 new->nredir.redirect = copynode(n->nredir.redirect);
8372 new->nredir.n = copynode(n->nredir.n);
8373 break;
8374 case NIF:
8375 new->nif.elsepart = copynode(n->nif.elsepart);
8376 new->nif.ifpart = copynode(n->nif.ifpart);
8377 new->nif.test = copynode(n->nif.test);
8378 break;
8379 case NFOR:
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008380 new->nfor.var = nodesavestr(n->nfor.var);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008381 new->nfor.body = copynode(n->nfor.body);
8382 new->nfor.args = copynode(n->nfor.args);
8383 break;
8384 case NCASE:
8385 new->ncase.cases = copynode(n->ncase.cases);
8386 new->ncase.expr = copynode(n->ncase.expr);
8387 break;
8388 case NCLIST:
8389 new->nclist.body = copynode(n->nclist.body);
8390 new->nclist.pattern = copynode(n->nclist.pattern);
8391 new->nclist.next = copynode(n->nclist.next);
8392 break;
8393 case NDEFUN:
8394 case NARG:
8395 new->narg.backquote = copynodelist(n->narg.backquote);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008396 new->narg.text = nodesavestr(n->narg.text);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008397 new->narg.next = copynode(n->narg.next);
8398 break;
8399 case NTO:
8400 case NFROM:
8401 case NFROMTO:
8402 case NAPPEND:
8403 case NTOOV:
8404 new->nfile.fname = copynode(n->nfile.fname);
8405 new->nfile.fd = n->nfile.fd;
8406 new->nfile.next = copynode(n->nfile.next);
8407 break;
8408 case NTOFD:
8409 case NFROMFD:
8410 new->ndup.vname = copynode(n->ndup.vname);
8411 new->ndup.dupfd = n->ndup.dupfd;
8412 new->ndup.fd = n->ndup.fd;
8413 new->ndup.next = copynode(n->ndup.next);
8414 break;
8415 case NHERE:
8416 case NXHERE:
8417 new->nhere.doc = copynode(n->nhere.doc);
8418 new->nhere.fd = n->nhere.fd;
8419 new->nhere.next = copynode(n->nhere.next);
8420 break;
8421 case NNOT:
8422 new->nnot.com = copynode(n->nnot.com);
8423 break;
8424 };
8425 new->type = n->type;
8426 return new;
Eric Andersencb57d552001-06-28 07:25:16 +00008427}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008428#endif /* COPYNODE_TABLE */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008429
8430#ifdef CALCSIZE_TABLE
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008431static void calcsize(const union node *n)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008432{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008433 const unsigned char *p;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008434
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008435 if (n == NULL)
8436 return;
8437 funcblocksize += (int) nodesize[n->type];
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008438
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008439 p = copynode_ops + (int) copynode_ops_index[n->type];
8440 do {
8441 const char *no = ((const char *) n) + ((int) (*p & NODE_OFFSETMASK));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008442
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008443 if (!(*p & NODE_MBRMASK)) { /* standard node */
8444 calcsize(*((const union node **) no));
8445 } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
8446 funcstringsize += strlen(*((const char **) no)) + 1;
8447 } else if (*p & NODE_NODELIST) { /* nodelist */
8448 sizenodelist(*((const struct nodelist **) no));
8449 } /* else integer -- ignore */
8450 } while (!(*p++ & NODE_NOMORE));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008451}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008452#else /* CALCSIZE_TABLE */
8453static void calcsize(const union node *n)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008454{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008455 if (n == NULL)
8456 return;
8457 funcblocksize += nodesize[n->type];
8458 switch (n->type) {
8459 case NSEMI:
8460 case NAND:
8461 case NOR:
8462 case NWHILE:
8463 case NUNTIL:
8464 calcsize(n->nbinary.ch2);
8465 calcsize(n->nbinary.ch1);
8466 break;
8467 case NCMD:
8468 calcsize(n->ncmd.redirect);
8469 calcsize(n->ncmd.args);
8470 calcsize(n->ncmd.assign);
8471 break;
8472 case NPIPE:
8473 sizenodelist(n->npipe.cmdlist);
8474 break;
8475 case NREDIR:
8476 case NBACKGND:
8477 case NSUBSHELL:
8478 calcsize(n->nredir.redirect);
8479 calcsize(n->nredir.n);
8480 break;
8481 case NIF:
8482 calcsize(n->nif.elsepart);
8483 calcsize(n->nif.ifpart);
8484 calcsize(n->nif.test);
8485 break;
8486 case NFOR:
8487 funcstringsize += strlen(n->nfor.var) + 1;
8488 calcsize(n->nfor.body);
8489 calcsize(n->nfor.args);
8490 break;
8491 case NCASE:
8492 calcsize(n->ncase.cases);
8493 calcsize(n->ncase.expr);
8494 break;
8495 case NCLIST:
8496 calcsize(n->nclist.body);
8497 calcsize(n->nclist.pattern);
8498 calcsize(n->nclist.next);
8499 break;
8500 case NDEFUN:
8501 case NARG:
8502 sizenodelist(n->narg.backquote);
8503 funcstringsize += strlen(n->narg.text) + 1;
8504 calcsize(n->narg.next);
8505 break;
8506 case NTO:
8507 case NFROM:
8508 case NFROMTO:
8509 case NAPPEND:
8510 case NTOOV:
8511 calcsize(n->nfile.fname);
8512 calcsize(n->nfile.next);
8513 break;
8514 case NTOFD:
8515 case NFROMFD:
8516 calcsize(n->ndup.vname);
8517 calcsize(n->ndup.next);
8518 break;
8519 case NHERE:
8520 case NXHERE:
8521 calcsize(n->nhere.doc);
8522 calcsize(n->nhere.next);
8523 break;
8524 case NNOT:
8525 calcsize(n->nnot.com);
8526 break;
8527 };
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008528}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008529#endif /* CALCSIZE_TABLE */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008530
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008531static void sizenodelist(const struct nodelist *lp)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008532{
8533 while (lp) {
8534 funcblocksize += ALIGN(sizeof(struct nodelist));
8535 calcsize(lp->n);
8536 lp = lp->next;
8537 }
8538}
Eric Andersencb57d552001-06-28 07:25:16 +00008539
8540
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008541static struct nodelist *copynodelist(const struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008542{
8543 struct nodelist *start;
8544 struct nodelist **lpp;
8545
8546 lpp = &start;
8547 while (lp) {
8548 *lpp = funcblock;
8549 funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist));
8550 (*lpp)->n = copynode(lp->n);
8551 lp = lp->next;
8552 lpp = &(*lpp)->next;
8553 }
8554 *lpp = NULL;
8555 return start;
8556}
8557
8558
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008559static char *nodesavestr(const char *s)
Eric Andersencb57d552001-06-28 07:25:16 +00008560{
Eric Andersen62483552001-07-10 06:09:16 +00008561 const char *p = s;
8562 char *q = funcstring;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008563 char *rtn = funcstring;
Eric Andersencb57d552001-06-28 07:25:16 +00008564
8565 while ((*q++ = *p++) != '\0')
8566 continue;
8567 funcstring = q;
8568 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00008569}
8570
Eric Andersend35c5df2002-01-09 15:37:36 +00008571#ifdef CONFIG_ASH_GETOPTS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008572static int getopts(char *, char *, char **, int *, int *);
Eric Andersencb57d552001-06-28 07:25:16 +00008573#endif
8574
Eric Andersencb57d552001-06-28 07:25:16 +00008575/*
8576 * Process the shell command line arguments.
8577 */
8578
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008579static void procargs(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008580{
8581 int i;
8582
8583 argptr = argv;
8584 if (argc > 0)
8585 argptr++;
8586 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00008587 optent_val(i) = 2;
Eric Andersencb57d552001-06-28 07:25:16 +00008588 options(1);
8589 if (*argptr == NULL && minusc == NULL)
8590 sflag = 1;
8591 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8592 iflag = 1;
8593 if (mflag == 2)
8594 mflag = iflag;
8595 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00008596 if (optent_val(i) == 2)
8597 optent_val(i) = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008598 arg0 = argv[0];
8599 if (sflag == 0 && minusc == NULL) {
8600 commandname = argv[0];
8601 arg0 = *argptr++;
8602 setinputfile(arg0, 0);
8603 commandname = arg0;
8604 }
8605 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8606 if (argptr && minusc && *argptr)
Eric Andersen2870d962001-07-02 17:27:21 +00008607 arg0 = *argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00008608
8609 shellparam.p = argptr;
8610 shellparam.optind = 1;
8611 shellparam.optoff = -1;
8612 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8613 while (*argptr) {
8614 shellparam.nparam++;
8615 argptr++;
8616 }
8617 optschanged();
8618}
8619
8620
Eric Andersencb57d552001-06-28 07:25:16 +00008621
8622/*
8623 * Process shell options. The global variable argptr contains a pointer
8624 * to the argument list; we advance it past the options.
8625 */
8626
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008627static inline void minus_o(const char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +00008628{
8629 int i;
8630
8631 if (name == NULL) {
8632 out1str("Current option settings\n");
8633 for (i = 0; i < NOPTS; i++)
8634 printf("%-16s%s\n", optent_name(optlist[i]),
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008635 optent_val(i) ? "on" : "off");
Eric Andersen62483552001-07-10 06:09:16 +00008636 } else {
8637 for (i = 0; i < NOPTS; i++)
8638 if (equal(name, optent_name(optlist[i]))) {
8639 setoption(optent_letter(optlist[i]), val);
8640 return;
8641 }
8642 error("Illegal option -o %s", name);
8643 }
8644}
8645
8646
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008647static void options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00008648{
8649 char *p;
8650 int val;
8651 int c;
8652
8653 if (cmdline)
8654 minusc = NULL;
8655 while ((p = *argptr) != NULL) {
8656 argptr++;
8657 if ((c = *p++) == '-') {
8658 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00008659 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8660 if (!cmdline) {
8661 /* "-" means turn off -x and -v */
8662 if (p[0] == '\0')
8663 xflag = vflag = 0;
8664 /* "--" means reset params */
8665 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00008666 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00008667 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008668 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00008669 }
8670 } else if (c == '+') {
8671 val = 0;
8672 } else {
8673 argptr--;
8674 break;
8675 }
8676 while ((c = *p++) != '\0') {
8677 if (c == 'c' && cmdline) {
8678 char *q;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008679
8680#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */
Eric Andersencb57d552001-06-28 07:25:16 +00008681 if (*p == '\0')
8682#endif
8683 q = *argptr++;
8684 if (q == NULL || minusc != NULL)
8685 error("Bad -c option");
8686 minusc = q;
8687#ifdef NOHACK
8688 break;
8689#endif
8690 } else if (c == 'o') {
8691 minus_o(*argptr, val);
8692 if (*argptr)
8693 argptr++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008694 } else if (cmdline && (c == '-')) { // long options
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008695 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +00008696 isloginsh = 1;
8697 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008698 } else {
8699 setoption(c, val);
8700 }
8701 }
8702 }
8703}
8704
Eric Andersencb57d552001-06-28 07:25:16 +00008705
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008706static void setoption(int flag, int val)
Eric Andersen2870d962001-07-02 17:27:21 +00008707{
Eric Andersencb57d552001-06-28 07:25:16 +00008708 int i;
8709
8710 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00008711 if (optent_letter(optlist[i]) == flag) {
8712 optent_val(i) = val;
Eric Andersencb57d552001-06-28 07:25:16 +00008713 if (val) {
8714 /* #%$ hack for ksh semantics */
8715 if (flag == 'V')
8716 Eflag = 0;
8717 else if (flag == 'E')
8718 Vflag = 0;
8719 }
8720 return;
8721 }
8722 error("Illegal option -%c", flag);
8723 /* NOTREACHED */
8724}
8725
8726
8727
Eric Andersencb57d552001-06-28 07:25:16 +00008728/*
8729 * Set the shell parameters.
8730 */
8731
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008732static void setparam(char **argv)
Eric Andersen2870d962001-07-02 17:27:21 +00008733{
Eric Andersencb57d552001-06-28 07:25:16 +00008734 char **newparam;
8735 char **ap;
8736 int nparam;
8737
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008738 for (nparam = 0; argv[nparam]; nparam++);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008739 ap = newparam = xmalloc((nparam + 1) * sizeof *ap);
Eric Andersencb57d552001-06-28 07:25:16 +00008740 while (*argv) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008741 *ap++ = xstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +00008742 }
8743 *ap = NULL;
8744 freeparam(&shellparam);
8745 shellparam.malloc = 1;
8746 shellparam.nparam = nparam;
8747 shellparam.p = newparam;
8748 shellparam.optind = 1;
8749 shellparam.optoff = -1;
8750}
8751
8752
8753/*
8754 * Free the list of positional parameters.
8755 */
8756
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008757static void freeparam(volatile struct shparam *param)
Eric Andersen2870d962001-07-02 17:27:21 +00008758{
Eric Andersencb57d552001-06-28 07:25:16 +00008759 char **ap;
8760
8761 if (param->malloc) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008762 for (ap = param->p; *ap; ap++)
Aaron Lehmann49c024a2002-08-02 06:39:47 +00008763 free(*ap);
8764 free(param->p);
Eric Andersencb57d552001-06-28 07:25:16 +00008765 }
8766}
8767
8768
8769
8770/*
8771 * The shift builtin command.
8772 */
8773
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008774static int shiftcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008775{
8776 int n;
8777 char **ap1, **ap2;
8778
8779 n = 1;
8780 if (argc > 1)
8781 n = number(argv[1]);
8782 if (n > shellparam.nparam)
8783 error("can't shift that many");
8784 INTOFF;
8785 shellparam.nparam -= n;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008786 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Eric Andersencb57d552001-06-28 07:25:16 +00008787 if (shellparam.malloc)
Aaron Lehmann49c024a2002-08-02 06:39:47 +00008788 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +00008789 }
8790 ap2 = shellparam.p;
8791 while ((*ap2++ = *ap1++) != NULL);
8792 shellparam.optind = 1;
8793 shellparam.optoff = -1;
8794 INTON;
8795 return 0;
8796}
8797
8798
8799
8800/*
8801 * The set command builtin.
8802 */
8803
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008804static int setcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008805{
8806 if (argc == 1)
8807 return showvarscmd(argc, argv);
8808 INTOFF;
8809 options(0);
8810 optschanged();
8811 if (*argptr != NULL) {
8812 setparam(argptr);
8813 }
8814 INTON;
8815 return 0;
8816}
8817
8818
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008819static void getoptsreset(const char *value)
Eric Andersencb57d552001-06-28 07:25:16 +00008820{
8821 shellparam.optind = number(value);
8822 shellparam.optoff = -1;
8823}
8824
Eric Andersenbdfd0d72001-10-24 05:00:29 +00008825#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00008826static void change_lc_all(const char *value)
8827{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008828 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00008829 setlocale(LC_ALL, value);
8830}
8831
8832static void change_lc_ctype(const char *value)
8833{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008834 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00008835 setlocale(LC_CTYPE, value);
8836}
8837
8838#endif
8839
Eric Andersend35c5df2002-01-09 15:37:36 +00008840#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008841/*
8842 * The getopts builtin. Shellparam.optnext points to the next argument
8843 * to be processed. Shellparam.optptr points to the next character to
8844 * be processed in the current argument. If shellparam.optnext is NULL,
8845 * then it's the first time getopts has been called.
8846 */
8847
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008848static int getoptscmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008849{
8850 char **optbase;
8851
8852 if (argc < 3)
8853 error("Usage: getopts optstring var [arg]");
8854 else if (argc == 3) {
8855 optbase = shellparam.p;
8856 if (shellparam.optind > shellparam.nparam + 1) {
8857 shellparam.optind = 1;
8858 shellparam.optoff = -1;
8859 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008860 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00008861 optbase = &argv[3];
8862 if (shellparam.optind > argc - 2) {
8863 shellparam.optind = 1;
8864 shellparam.optoff = -1;
8865 }
8866 }
8867
8868 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008869 &shellparam.optoff);
Eric Andersencb57d552001-06-28 07:25:16 +00008870}
8871
8872/*
8873 * Safe version of setvar, returns 1 on success 0 on failure.
8874 */
8875
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008876static int setvarsafe(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008877{
8878 struct jmploc jmploc;
8879 struct jmploc *volatile savehandler = handler;
8880 int err = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008881
Eric Andersencb57d552001-06-28 07:25:16 +00008882#ifdef __GNUC__
8883 (void) &err;
8884#endif
8885
8886 if (setjmp(jmploc.loc))
8887 err = 1;
8888 else {
8889 handler = &jmploc;
8890 setvar(name, val, flags);
8891 }
8892 handler = savehandler;
8893 return err;
8894}
8895
8896static int
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008897getopts(char *optstr, char *optvar, char **optfirst, int *myoptind,
8898 int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00008899{
8900 char *p, *q;
8901 char c = '?';
8902 int done = 0;
8903 int err = 0;
8904 char s[10];
8905 char **optnext = optfirst + *myoptind - 1;
8906
8907 if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008908 strlen(*(optnext - 1)) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00008909 p = NULL;
8910 else
8911 p = *(optnext - 1) + *optoff;
8912 if (p == NULL || *p == '\0') {
8913 /* Current word is done, advance */
8914 if (optnext == NULL)
8915 return 1;
8916 p = *optnext;
8917 if (p == NULL || *p != '-' || *++p == '\0') {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008918 atend:
Eric Andersencb57d552001-06-28 07:25:16 +00008919 *myoptind = optnext - optfirst + 1;
8920 p = NULL;
8921 done = 1;
8922 goto out;
8923 }
8924 optnext++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008925 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00008926 goto atend;
8927 }
8928
8929 c = *p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008930 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +00008931 if (*q == '\0') {
8932 if (optstr[0] == ':') {
8933 s[0] = c;
8934 s[1] = '\0';
8935 err |= setvarsafe("OPTARG", s, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008936 } else {
Eric Andersen3102ac42001-07-06 04:26:23 +00008937 out2fmt("Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00008938 (void) unsetvar("OPTARG");
8939 }
8940 c = '?';
8941 goto bad;
8942 }
8943 if (*++q == ':')
8944 q++;
8945 }
8946
8947 if (*++q == ':') {
8948 if (*p == '\0' && (p = *optnext) == NULL) {
8949 if (optstr[0] == ':') {
8950 s[0] = c;
8951 s[1] = '\0';
8952 err |= setvarsafe("OPTARG", s, 0);
8953 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008954 } else {
Eric Andersen3102ac42001-07-06 04:26:23 +00008955 out2fmt("No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00008956 (void) unsetvar("OPTARG");
8957 c = '?';
8958 }
8959 goto bad;
8960 }
8961
8962 if (p == *optnext)
8963 optnext++;
8964 setvarsafe("OPTARG", p, 0);
8965 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008966 } else
Eric Andersencb57d552001-06-28 07:25:16 +00008967 setvarsafe("OPTARG", "", 0);
8968 *myoptind = optnext - optfirst + 1;
8969 goto out;
8970
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008971 bad:
Eric Andersencb57d552001-06-28 07:25:16 +00008972 *myoptind = 1;
8973 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008974 out:
Eric Andersencb57d552001-06-28 07:25:16 +00008975 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersen3102ac42001-07-06 04:26:23 +00008976 snprintf(s, sizeof(s), "%d", *myoptind);
Eric Andersencb57d552001-06-28 07:25:16 +00008977 err |= setvarsafe("OPTIND", s, VNOFUNC);
8978 s[0] = c;
8979 s[1] = '\0';
8980 err |= setvarsafe(optvar, s, 0);
8981 if (err) {
8982 *myoptind = 1;
8983 *optoff = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00008984 exraise(EXERROR);
8985 }
8986 return done;
8987}
Eric Andersen2870d962001-07-02 17:27:21 +00008988#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008989
8990/*
8991 * XXX - should get rid of. have all builtins use getopt(3). the
8992 * library getopt must have the BSD extension static variable "optreset"
8993 * otherwise it can't be used within the shell safely.
8994 *
8995 * Standard option processing (a la getopt) for builtin routines. The
8996 * only argument that is passed to nextopt is the option string; the
8997 * other arguments are unnecessary. It return the character, or '\0' on
8998 * end of input.
8999 */
9000
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009001static int nextopt(const char *optstring)
Eric Andersen62483552001-07-10 06:09:16 +00009002{
Eric Andersencb57d552001-06-28 07:25:16 +00009003 char *p;
9004 const char *q;
9005 char c;
9006
9007 if ((p = optptr) == NULL || *p == '\0') {
9008 p = *argptr;
9009 if (p == NULL || *p != '-' || *++p == '\0')
9010 return '\0';
9011 argptr++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009012 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009013 return '\0';
9014 }
9015 c = *p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009016 for (q = optstring; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +00009017 if (*q == '\0')
9018 error("Illegal option -%c", c);
9019 if (*++q == ':')
9020 q++;
9021 }
9022 if (*++q == ':') {
9023 if (*p == '\0' && (p = *argptr++) == NULL)
9024 error("No arg for -%c option", c);
9025 optionarg = p;
9026 p = NULL;
9027 }
9028 optptr = p;
9029 return c;
9030}
9031
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009032static void flushall()
9033{
Eric Andersencb57d552001-06-28 07:25:16 +00009034 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009035 fflush(stdout);
Eric Andersencb57d552001-06-28 07:25:16 +00009036 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009037}
9038
9039
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009040static void out2fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009041{
9042 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009043
Eric Andersencb57d552001-06-28 07:25:16 +00009044 va_start(ap, fmt);
Eric Andersen3102ac42001-07-06 04:26:23 +00009045 vfprintf(stderr, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009046 va_end(ap);
9047}
9048
Eric Andersencb57d552001-06-28 07:25:16 +00009049/*
9050 * Version of write which resumes after a signal is caught.
9051 */
9052
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009053static int xwrite(int fd, const char *buf, int nbytes)
Eric Andersen2870d962001-07-02 17:27:21 +00009054{
Eric Andersencb57d552001-06-28 07:25:16 +00009055 int ntry;
9056 int i;
9057 int n;
9058
9059 n = nbytes;
9060 ntry = 0;
9061 for (;;) {
9062 i = write(fd, buf, n);
9063 if (i > 0) {
9064 if ((n -= i) <= 0)
9065 return nbytes;
9066 buf += i;
9067 ntry = 0;
9068 } else if (i == 0) {
9069 if (++ntry > 10)
9070 return nbytes - n;
9071 } else if (errno != EINTR) {
9072 return -1;
9073 }
9074 }
9075}
9076
9077
Eric Andersencb57d552001-06-28 07:25:16 +00009078/*
9079 * Shell command parser.
9080 */
9081
9082#define EOFMARKLEN 79
9083
9084
9085
9086struct heredoc {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009087 struct heredoc *next; /* next here document in list */
9088 union node *here; /* redirection node */
9089 char *eofmark; /* string indicating end of input */
9090 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009091};
9092
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009093static struct heredoc *heredoclist; /* list of here documents to read */
9094static int parsebackquote; /* nonzero if we are inside backquotes */
9095static int doprompt; /* if set, prompt the user */
9096static int needprompt; /* true if interactive and at start of line */
9097static int lasttoken; /* last token read */
Eric Andersencb57d552001-06-28 07:25:16 +00009098
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009099static char *wordtext; /* text of last word returned by readtoken */
Eric Andersencb57d552001-06-28 07:25:16 +00009100
Eric Andersen2870d962001-07-02 17:27:21 +00009101static struct nodelist *backquotelist;
9102static union node *redirnode;
Eric Andersen044228d2001-07-17 01:12:36 +00009103static struct heredoc *heredoc;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009104static int quoteflag; /* set if (part of) last token was quoted */
9105static int startlinno; /* line # where last token started */
Eric Andersencb57d552001-06-28 07:25:16 +00009106
9107
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009108static union node *list(int);
9109static union node *andor(void);
9110static union node *pipeline(void);
9111static union node *command(void);
Eric Andersena3483db2001-10-24 08:01:06 +00009112static union node *simplecmd(union node **rpp, union node *redir);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009113static void parsefname(void);
9114static void parseheredoc(void);
9115static char peektoken(void);
9116static int readtoken(void);
9117static int xxreadtoken(void);
9118static int readtoken1(int, int, const char *, int);
9119static int noexpand(char *);
9120static void synexpect(int) __attribute__ ((noreturn));
9121static void synerror(const char *) __attribute__ ((noreturn));
9122static void setprompt(int);
Eric Andersencb57d552001-06-28 07:25:16 +00009123
9124
9125/*
9126 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9127 * valid parse tree indicating a blank line.)
9128 */
9129
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009130static union node *parsecmd(int interact)
Eric Andersencb57d552001-06-28 07:25:16 +00009131{
9132 int t;
9133
9134 tokpushback = 0;
9135 doprompt = interact;
9136 if (doprompt)
9137 setprompt(1);
9138 else
9139 setprompt(0);
9140 needprompt = 0;
9141 t = readtoken();
9142 if (t == TEOF)
9143 return NEOF;
9144 if (t == TNL)
9145 return NULL;
9146 tokpushback++;
9147 return list(1);
9148}
9149
9150
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009151static union node *list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +00009152{
9153 union node *n1, *n2, *n3;
9154 int tok;
9155
9156 checkkwd = 2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009157 if (nlflag == 0 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009158 return NULL;
9159 n1 = NULL;
9160 for (;;) {
9161 n2 = andor();
9162 tok = readtoken();
9163 if (tok == TBACKGND) {
9164 if (n2->type == NCMD || n2->type == NPIPE) {
9165 n2->ncmd.backgnd = 1;
9166 } else if (n2->type == NREDIR) {
9167 n2->type = NBACKGND;
9168 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009169 n3 = (union node *) stalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009170 n3->type = NBACKGND;
9171 n3->nredir.n = n2;
9172 n3->nredir.redirect = NULL;
9173 n2 = n3;
9174 }
9175 }
9176 if (n1 == NULL) {
9177 n1 = n2;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009178 } else {
9179 n3 = (union node *) stalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009180 n3->type = NSEMI;
9181 n3->nbinary.ch1 = n1;
9182 n3->nbinary.ch2 = n2;
9183 n1 = n3;
9184 }
9185 switch (tok) {
9186 case TBACKGND:
9187 case TSEMI:
9188 tok = readtoken();
9189 /* fall through */
9190 case TNL:
9191 if (tok == TNL) {
9192 parseheredoc();
9193 if (nlflag)
9194 return n1;
9195 } else {
9196 tokpushback++;
9197 }
9198 checkkwd = 2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009199 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009200 return n1;
9201 break;
9202 case TEOF:
9203 if (heredoclist)
9204 parseheredoc();
9205 else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009206 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009207 return n1;
9208 default:
9209 if (nlflag)
9210 synexpect(-1);
9211 tokpushback++;
9212 return n1;
9213 }
9214 }
9215}
9216
9217
9218
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009219static union node *andor()
9220{
Eric Andersencb57d552001-06-28 07:25:16 +00009221 union node *n1, *n2, *n3;
9222 int t;
9223
9224 checkkwd = 1;
9225 n1 = pipeline();
9226 for (;;) {
9227 if ((t = readtoken()) == TAND) {
9228 t = NAND;
9229 } else if (t == TOR) {
9230 t = NOR;
9231 } else {
9232 tokpushback++;
9233 return n1;
9234 }
9235 checkkwd = 2;
9236 n2 = pipeline();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009237 n3 = (union node *) stalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009238 n3->type = t;
9239 n3->nbinary.ch1 = n1;
9240 n3->nbinary.ch2 = n2;
9241 n1 = n3;
9242 }
9243}
9244
9245
9246
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009247static union node *pipeline()
9248{
Eric Andersencb57d552001-06-28 07:25:16 +00009249 union node *n1, *n2, *pipenode;
9250 struct nodelist *lp, *prev;
9251 int negate;
9252
9253 negate = 0;
9254 TRACE(("pipeline: entered\n"));
9255 if (readtoken() == TNOT) {
9256 negate = !negate;
9257 checkkwd = 1;
9258 } else
9259 tokpushback++;
9260 n1 = command();
9261 if (readtoken() == TPIPE) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009262 pipenode = (union node *) stalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +00009263 pipenode->type = NPIPE;
9264 pipenode->npipe.backgnd = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009265 lp = (struct nodelist *) stalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00009266 pipenode->npipe.cmdlist = lp;
9267 lp->n = n1;
9268 do {
9269 prev = lp;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009270 lp = (struct nodelist *) stalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00009271 checkkwd = 2;
9272 lp->n = command();
9273 prev->next = lp;
9274 } while (readtoken() == TPIPE);
9275 lp->next = NULL;
9276 n1 = pipenode;
9277 }
9278 tokpushback++;
9279 if (negate) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009280 n2 = (union node *) stalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +00009281 n2->type = NNOT;
9282 n2->nnot.com = n1;
9283 return n2;
9284 } else
9285 return n1;
9286}
9287
9288
9289
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009290static union node *command(void)
9291{
Eric Andersencb57d552001-06-28 07:25:16 +00009292 union node *n1, *n2;
9293 union node *ap, **app;
9294 union node *cp, **cpp;
9295 union node *redir, **rpp;
9296 int t;
9297
9298 redir = NULL;
9299 n1 = NULL;
9300 rpp = &redir;
9301
Eric Andersen88cec252001-09-06 17:35:20 +00009302 /* Check for redirection which may precede command */
9303 while (readtoken() == TREDIR) {
9304 *rpp = n2 = redirnode;
9305 rpp = &n2->nfile.next;
9306 parsefname();
9307 }
9308 tokpushback++;
9309
Eric Andersencb57d552001-06-28 07:25:16 +00009310 switch (readtoken()) {
9311 case TIF:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009312 n1 = (union node *) stalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009313 n1->type = NIF;
9314 n1->nif.test = list(0);
9315 if (readtoken() != TTHEN)
9316 synexpect(TTHEN);
9317 n1->nif.ifpart = list(0);
9318 n2 = n1;
9319 while (readtoken() == TELIF) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009320 n2->nif.elsepart = (union node *) stalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009321 n2 = n2->nif.elsepart;
9322 n2->type = NIF;
9323 n2->nif.test = list(0);
9324 if (readtoken() != TTHEN)
9325 synexpect(TTHEN);
9326 n2->nif.ifpart = list(0);
9327 }
9328 if (lasttoken == TELSE)
9329 n2->nif.elsepart = list(0);
9330 else {
9331 n2->nif.elsepart = NULL;
9332 tokpushback++;
9333 }
9334 if (readtoken() != TFI)
9335 synexpect(TFI);
9336 checkkwd = 1;
9337 break;
9338 case TWHILE:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009339 case TUNTIL:{
Eric Andersencb57d552001-06-28 07:25:16 +00009340 int got;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009341 n1 = (union node *) stalloc(sizeof(struct nbinary));
9342 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +00009343 n1->nbinary.ch1 = list(0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009344 if ((got = readtoken()) != TDO) {
9345 TRACE(("expecting DO got %s %s\n", tokname(got),
9346 got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009347 synexpect(TDO);
9348 }
9349 n1->nbinary.ch2 = list(0);
9350 if (readtoken() != TDONE)
9351 synexpect(TDONE);
9352 checkkwd = 1;
9353 break;
9354 }
9355 case TFOR:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009356 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Eric Andersencb57d552001-06-28 07:25:16 +00009357 synerror("Bad for loop variable");
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009358 n1 = (union node *) stalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +00009359 n1->type = NFOR;
9360 n1->nfor.var = wordtext;
9361 checkkwd = 1;
9362 if (readtoken() == TIN) {
9363 app = &ap;
9364 while (readtoken() == TWORD) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009365 n2 = (union node *) stalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009366 n2->type = NARG;
9367 n2->narg.text = wordtext;
9368 n2->narg.backquote = backquotelist;
9369 *app = n2;
9370 app = &n2->narg.next;
9371 }
9372 *app = NULL;
9373 n1->nfor.args = ap;
9374 if (lasttoken != TNL && lasttoken != TSEMI)
9375 synexpect(-1);
9376 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009377 static char argvars[5] = { CTLVAR, VSNORMAL | VSQUOTE,
9378 '@', '=', '\0'
9379 };
9380 n2 = (union node *) stalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009381 n2->type = NARG;
9382 n2->narg.text = argvars;
9383 n2->narg.backquote = NULL;
9384 n2->narg.next = NULL;
9385 n1->nfor.args = n2;
9386 /*
9387 * Newline or semicolon here is optional (but note
9388 * that the original Bourne shell only allowed NL).
9389 */
9390 if (lasttoken != TNL && lasttoken != TSEMI)
9391 tokpushback++;
9392 }
9393 checkkwd = 2;
9394 if (readtoken() != TDO)
9395 synexpect(TDO);
9396 n1->nfor.body = list(0);
9397 if (readtoken() != TDONE)
9398 synexpect(TDONE);
9399 checkkwd = 1;
9400 break;
9401 case TCASE:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009402 n1 = (union node *) stalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +00009403 n1->type = NCASE;
9404 if (readtoken() != TWORD)
9405 synexpect(TWORD);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009406 n1->ncase.expr = n2 = (union node *) stalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009407 n2->type = NARG;
9408 n2->narg.text = wordtext;
9409 n2->narg.backquote = backquotelist;
9410 n2->narg.next = NULL;
9411 do {
9412 checkkwd = 1;
9413 } while (readtoken() == TNL);
9414 if (lasttoken != TIN)
9415 synerror("expecting \"in\"");
9416 cpp = &n1->ncase.cases;
9417 checkkwd = 2, readtoken();
9418 do {
9419 if (lasttoken == TLP)
9420 readtoken();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009421 *cpp = cp = (union node *) stalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +00009422 cp->type = NCLIST;
9423 app = &cp->nclist.pattern;
9424 for (;;) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009425 *app = ap = (union node *) stalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009426 ap->type = NARG;
9427 ap->narg.text = wordtext;
9428 ap->narg.backquote = backquotelist;
9429 if (checkkwd = 2, readtoken() != TPIPE)
9430 break;
9431 app = &ap->narg.next;
9432 readtoken();
9433 }
9434 ap->narg.next = NULL;
9435 if (lasttoken != TRP)
9436 synexpect(TRP);
9437 cp->nclist.body = list(0);
9438
9439 checkkwd = 2;
9440 if ((t = readtoken()) != TESAC) {
9441 if (t != TENDCASE)
9442 synexpect(TENDCASE);
9443 else
9444 checkkwd = 2, readtoken();
9445 }
9446 cpp = &cp->nclist.next;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009447 } while (lasttoken != TESAC);
Eric Andersencb57d552001-06-28 07:25:16 +00009448 *cpp = NULL;
9449 checkkwd = 1;
9450 break;
9451 case TLP:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009452 n1 = (union node *) stalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009453 n1->type = NSUBSHELL;
9454 n1->nredir.n = list(0);
9455 n1->nredir.redirect = NULL;
9456 if (readtoken() != TRP)
9457 synexpect(TRP);
9458 checkkwd = 1;
9459 break;
9460 case TBEGIN:
9461 n1 = list(0);
9462 if (readtoken() != TEND)
9463 synexpect(TEND);
9464 checkkwd = 1;
9465 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009466 /* Handle an empty command like other simple commands. */
Eric Andersencb57d552001-06-28 07:25:16 +00009467 case TSEMI:
9468 case TAND:
9469 case TOR:
9470 case TNL:
9471 case TEOF:
9472 case TRP:
9473 case TBACKGND:
9474 /*
9475 * An empty command before a ; doesn't make much sense, and
9476 * should certainly be disallowed in the case of `if ;'.
9477 */
9478 if (!redir)
9479 synexpect(-1);
9480 case TWORD:
Eric Andersencb57d552001-06-28 07:25:16 +00009481 tokpushback++;
Eric Andersena3483db2001-10-24 08:01:06 +00009482 n1 = simplecmd(rpp, redir);
Eric Andersencb57d552001-06-28 07:25:16 +00009483 return n1;
9484 default:
9485 synexpect(-1);
9486 /* NOTREACHED */
9487 }
9488
9489 /* Now check for redirection which may follow command */
9490 while (readtoken() == TREDIR) {
9491 *rpp = n2 = redirnode;
9492 rpp = &n2->nfile.next;
9493 parsefname();
9494 }
9495 tokpushback++;
9496 *rpp = NULL;
9497 if (redir) {
9498 if (n1->type != NSUBSHELL) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009499 n2 = (union node *) stalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009500 n2->type = NREDIR;
9501 n2->nredir.n = n1;
9502 n1 = n2;
9503 }
9504 n1->nredir.redirect = redir;
9505 }
9506
9507 return n1;
9508}
9509
9510
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009511static union node *simplecmd(union node **rpp, union node *redir)
9512{
Eric Andersencb57d552001-06-28 07:25:16 +00009513 union node *args, **app;
9514 union node *n = NULL;
9515 union node *vars, **vpp;
Eric Andersena3483db2001-10-24 08:01:06 +00009516 union node **orig_rpp;
Eric Andersencb57d552001-06-28 07:25:16 +00009517
9518 args = NULL;
9519 app = &args;
9520 vars = NULL;
9521 vpp = &vars;
Eric Andersena3483db2001-10-24 08:01:06 +00009522
9523 /* If we don't have any redirections already, then we must reset
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009524 rpp to be the address of the local redir variable. */
Eric Andersena3483db2001-10-24 08:01:06 +00009525 if (redir == 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009526 rpp = &redir;
Eric Andersena3483db2001-10-24 08:01:06 +00009527 /* We save the incoming value, because we need this for shell
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009528 functions. There can not be a redirect or an argument between
9529 the function name and the open parenthesis. */
Eric Andersena3483db2001-10-24 08:01:06 +00009530 orig_rpp = rpp;
Eric Andersencb57d552001-06-28 07:25:16 +00009531
9532 checkalias = 2;
9533 for (;;) {
9534 switch (readtoken()) {
9535 case TWORD:
9536 case TASSIGN:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009537 n = (union node *) stalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009538 n->type = NARG;
9539 n->narg.text = wordtext;
9540 n->narg.backquote = backquotelist;
9541 if (lasttoken == TWORD) {
9542 *app = n;
9543 app = &n->narg.next;
9544 } else {
9545 *vpp = n;
9546 vpp = &n->narg.next;
9547 }
9548 break;
9549 case TREDIR:
9550 *rpp = n = redirnode;
9551 rpp = &n->nfile.next;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009552 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +00009553 break;
9554 case TLP:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009555 if (args && app == &args->narg.next && !vars && rpp == orig_rpp) {
Eric Andersencb57d552001-06-28 07:25:16 +00009556 /* We have a function */
9557 if (readtoken() != TRP)
9558 synexpect(TRP);
Eric Andersencb57d552001-06-28 07:25:16 +00009559 n->type = NDEFUN;
9560 checkkwd = 2;
9561 n->narg.next = command();
9562 return n;
9563 }
9564 /* fall through */
9565 default:
9566 tokpushback++;
9567 goto out;
9568 }
9569 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009570 out:
Eric Andersencb57d552001-06-28 07:25:16 +00009571 *app = NULL;
9572 *vpp = NULL;
9573 *rpp = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009574 n = (union node *) stalloc(sizeof(struct ncmd));
Eric Andersencb57d552001-06-28 07:25:16 +00009575 n->type = NCMD;
9576 n->ncmd.backgnd = 0;
9577 n->ncmd.args = args;
9578 n->ncmd.assign = vars;
9579 n->ncmd.redirect = redir;
9580 return n;
9581}
9582
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009583static union node *makename(void)
9584{
Eric Andersencb57d552001-06-28 07:25:16 +00009585 union node *n;
9586
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009587 n = (union node *) stalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009588 n->type = NARG;
9589 n->narg.next = NULL;
9590 n->narg.text = wordtext;
9591 n->narg.backquote = backquotelist;
9592 return n;
9593}
9594
9595static void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +00009596{
Eric Andersencb57d552001-06-28 07:25:16 +00009597 TRACE(("Fix redir %s %d\n", text, err));
9598 if (!err)
9599 n->ndup.vname = NULL;
9600
9601 if (is_digit(text[0]) && text[1] == '\0')
9602 n->ndup.dupfd = digit_val(text[0]);
9603 else if (text[0] == '-' && text[1] == '\0')
9604 n->ndup.dupfd = -1;
9605 else {
9606
9607 if (err)
9608 synerror("Bad fd number");
9609 else
9610 n->ndup.vname = makename();
9611 }
9612}
9613
9614
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009615static void parsefname(void)
9616{
Eric Andersencb57d552001-06-28 07:25:16 +00009617 union node *n = redirnode;
9618
9619 if (readtoken() != TWORD)
9620 synexpect(-1);
9621 if (n->type == NHERE) {
9622 struct heredoc *here = heredoc;
9623 struct heredoc *p;
9624 int i;
9625
9626 if (quoteflag == 0)
9627 n->type = NXHERE;
9628 TRACE(("Here document %d\n", n->type));
9629 if (here->striptabs) {
9630 while (*wordtext == '\t')
9631 wordtext++;
9632 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009633 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0
9634 || i > EOFMARKLEN)
Eric Andersencb57d552001-06-28 07:25:16 +00009635 synerror("Illegal eof marker for << redirection");
9636 rmescapes(wordtext);
9637 here->eofmark = wordtext;
9638 here->next = NULL;
9639 if (heredoclist == NULL)
9640 heredoclist = here;
9641 else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009642 for (p = heredoclist; p->next; p = p->next);
Eric Andersencb57d552001-06-28 07:25:16 +00009643 p->next = here;
9644 }
9645 } else if (n->type == NTOFD || n->type == NFROMFD) {
9646 fixredir(n, wordtext, 0);
9647 } else {
9648 n->nfile.fname = makename();
9649 }
9650}
9651
9652
9653/*
9654 * Input any here documents.
9655 */
9656
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009657static void parseheredoc()
9658{
Eric Andersencb57d552001-06-28 07:25:16 +00009659 struct heredoc *here;
9660 union node *n;
9661
9662 while (heredoclist) {
9663 here = heredoclist;
9664 heredoclist = here->next;
9665 if (needprompt) {
9666 setprompt(2);
9667 needprompt = 0;
9668 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009669 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
9670 here->eofmark, here->striptabs);
9671 n = (union node *) stalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009672 n->narg.type = NARG;
9673 n->narg.next = NULL;
9674 n->narg.text = wordtext;
9675 n->narg.backquote = backquotelist;
9676 here->here->nhere.doc = n;
9677 }
9678}
9679
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009680static char peektoken()
9681{
Eric Andersencb57d552001-06-28 07:25:16 +00009682 int t;
9683
9684 t = readtoken();
9685 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009686 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +00009687}
9688
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009689static int readtoken()
9690{
Eric Andersencb57d552001-06-28 07:25:16 +00009691 int t;
Eric Andersen7467c8d2001-07-12 20:26:32 +00009692
Eric Andersencb57d552001-06-28 07:25:16 +00009693 int savecheckalias = checkalias;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009694
Eric Andersen8e139872002-07-04 00:19:46 +00009695#ifdef CONFIG_ASH_ALIAS
Eric Andersen7467c8d2001-07-12 20:26:32 +00009696 int savecheckkwd = checkkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009697 struct alias *ap;
Eric Andersen2870d962001-07-02 17:27:21 +00009698#endif
9699
Eric Andersencb57d552001-06-28 07:25:16 +00009700#ifdef DEBUG
9701 int alreadyseen = tokpushback;
9702#endif
9703
Eric Andersend35c5df2002-01-09 15:37:36 +00009704#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009705 top:
Eric Andersen2870d962001-07-02 17:27:21 +00009706#endif
9707
Eric Andersencb57d552001-06-28 07:25:16 +00009708 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +00009709
Eric Andersencb57d552001-06-28 07:25:16 +00009710 checkalias = savecheckalias;
9711
9712 if (checkkwd) {
9713 /*
9714 * eat newlines
9715 */
9716 if (checkkwd == 2) {
9717 checkkwd = 0;
9718 while (t == TNL) {
9719 parseheredoc();
9720 t = xxreadtoken();
9721 }
9722 }
9723 checkkwd = 0;
9724 /*
9725 * check for keywords
9726 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009727 if (t == TWORD && !quoteflag) {
Eric Andersencb57d552001-06-28 07:25:16 +00009728 const char *const *pp;
9729
9730 if ((pp = findkwd(wordtext))) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009731 lasttoken = t = pp - tokname_array;
9732 TRACE(("keyword %s recognized\n", tokname(t)));
Eric Andersencb57d552001-06-28 07:25:16 +00009733 goto out;
9734 }
9735 }
9736 }
9737
Eric Andersen7467c8d2001-07-12 20:26:32 +00009738
Eric Andersencb57d552001-06-28 07:25:16 +00009739 if (t != TWORD) {
9740 if (t != TREDIR) {
9741 checkalias = 0;
9742 }
9743 } else if (checkalias == 2 && isassignment(wordtext)) {
9744 lasttoken = t = TASSIGN;
9745 } else if (checkalias) {
Eric Andersen8e139872002-07-04 00:19:46 +00009746#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009747 if (!quoteflag && (ap = *__lookupalias(wordtext)) != NULL
9748 && !(ap->flag & ALIASINUSE)) {
Eric Andersencb57d552001-06-28 07:25:16 +00009749 if (*ap->val) {
9750 pushstring(ap->val, strlen(ap->val), ap);
9751 }
9752 checkkwd = savecheckkwd;
9753 goto top;
9754 }
Eric Andersen2870d962001-07-02 17:27:21 +00009755#endif
Eric Andersen8e139872002-07-04 00:19:46 +00009756 checkalias = 0;
Eric Andersen7467c8d2001-07-12 20:26:32 +00009757 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009758 out:
Eric Andersencb57d552001-06-28 07:25:16 +00009759#ifdef DEBUG
9760 if (!alreadyseen)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009761 TRACE(("token %s %s\n", tokname(t), t == TWORD
9762 || t == TASSIGN ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009763 else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009764 TRACE(("reread token %s %s\n", tokname(t), t == TWORD
9765 || t == TASSIGN ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009766#endif
9767 return (t);
9768}
9769
9770
9771/*
9772 * Read the next input token.
9773 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +00009774 * backquotes. We set quoteflag to true if any part of the word was
9775 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +00009776 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +00009777 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +00009778 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +00009779 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +00009780 *
9781 * [Change comment: here documents and internal procedures]
9782 * [Readtoken shouldn't have any arguments. Perhaps we should make the
9783 * word parsing code into a separate routine. In this case, readtoken
9784 * doesn't need to have any internal procedures, but parseword does.
9785 * We could also make parseoperator in essence the main routine, and
9786 * have parseword (readtoken1?) handle both words and redirection.]
9787 */
9788
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009789#define NEW_xxreadtoken
9790#ifdef NEW_xxreadtoken
9791
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009792static const char xxreadtoken_chars[] = "\n()&|;"; /* singles must be first! */
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009793static const char xxreadtoken_tokens[] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009794 TNL, TLP, TRP, /* only single occurrence allowed */
9795 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
9796 TEOF, /* corresponds to trailing nul */
9797 TAND, TOR, TENDCASE, /* if double occurrence */
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009798};
9799
9800#define xxreadtoken_doubles \
9801 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
9802#define xxreadtoken_singles \
9803 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
9804
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009805static int xxreadtoken()
9806{
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009807 int c;
9808
9809 if (tokpushback) {
9810 tokpushback = 0;
9811 return lasttoken;
9812 }
9813 if (needprompt) {
9814 setprompt(2);
9815 needprompt = 0;
9816 }
9817 startlinno = plinno;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009818 for (;;) { /* until token or start of word found */
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009819 c = pgetc_macro();
9820
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009821 if ((c != ' ') && (c != '\t')
Eric Andersend35c5df2002-01-09 15:37:36 +00009822#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009823 && (c != PEOA)
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009824#endif
9825 ) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009826 if (c == '#') {
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009827 while ((c = pgetc()) != '\n' && c != PEOF);
9828 pungetc();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009829 } else if (c == '\\') {
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009830 if (pgetc() != '\n') {
9831 pungetc();
9832 goto READTOKEN1;
9833 }
9834 startlinno = ++plinno;
9835 setprompt(doprompt ? 2 : 0);
9836 } else {
9837 const char *p
9838 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
9839
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009840 if (c != PEOF) {
9841 if (c == '\n') {
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009842 plinno++;
9843 needprompt = doprompt;
9844 }
9845
9846 p = strchr(xxreadtoken_chars, c);
9847 if (p == NULL) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009848 READTOKEN1:
9849 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009850 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009851
9852 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
9853 if (pgetc() == *p) { /* double occurrence? */
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009854 p += xxreadtoken_doubles + 1;
9855 } else {
9856 pungetc();
9857 }
9858 }
9859 }
9860
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009861 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009862 }
9863 }
9864 }
9865}
9866
9867
9868#else
Eric Andersen2870d962001-07-02 17:27:21 +00009869#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +00009870
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009871static int xxreadtoken()
9872{
Eric Andersencb57d552001-06-28 07:25:16 +00009873 int c;
9874
9875 if (tokpushback) {
9876 tokpushback = 0;
9877 return lasttoken;
9878 }
9879 if (needprompt) {
9880 setprompt(2);
9881 needprompt = 0;
9882 }
9883 startlinno = plinno;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009884 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +00009885 c = pgetc_macro();
9886 switch (c) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009887 case ' ':
9888 case '\t':
Eric Andersend35c5df2002-01-09 15:37:36 +00009889#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00009890 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +00009891#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009892 continue;
9893 case '#':
9894 while ((c = pgetc()) != '\n' && c != PEOF);
9895 pungetc();
9896 continue;
9897 case '\\':
9898 if (pgetc() == '\n') {
9899 startlinno = ++plinno;
9900 if (doprompt)
9901 setprompt(2);
9902 else
9903 setprompt(0);
9904 continue;
9905 }
9906 pungetc();
9907 goto breakloop;
9908 case '\n':
9909 plinno++;
9910 needprompt = doprompt;
9911 RETURN(TNL);
9912 case PEOF:
9913 RETURN(TEOF);
9914 case '&':
9915 if (pgetc() == '&')
9916 RETURN(TAND);
9917 pungetc();
9918 RETURN(TBACKGND);
9919 case '|':
9920 if (pgetc() == '|')
9921 RETURN(TOR);
9922 pungetc();
9923 RETURN(TPIPE);
9924 case ';':
9925 if (pgetc() == ';')
9926 RETURN(TENDCASE);
9927 pungetc();
9928 RETURN(TSEMI);
9929 case '(':
9930 RETURN(TLP);
9931 case ')':
9932 RETURN(TRP);
9933 default:
9934 goto breakloop;
9935 }
9936 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009937 breakloop:
9938 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009939#undef RETURN
9940}
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00009941#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009942
Eric Andersencb57d552001-06-28 07:25:16 +00009943/*
9944 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
9945 * is not NULL, read a here document. In the latter case, eofmark is the
9946 * word which marks the end of the document and striptabs is true if
9947 * leading tabs should be stripped from the document. The argument firstc
9948 * is the first character of the input token or document.
9949 *
9950 * Because C does not have internal subroutines, I have simulated them
9951 * using goto's to implement the subroutine linkage. The following macros
9952 * will run code that appears at the end of readtoken1.
9953 */
9954
Eric Andersen2870d962001-07-02 17:27:21 +00009955#define CHECKEND() {goto checkend; checkend_return:;}
9956#define PARSEREDIR() {goto parseredir; parseredir_return:;}
9957#define PARSESUB() {goto parsesub; parsesub_return:;}
9958#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
9959#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
9960#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +00009961
9962static int
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009963readtoken1(int firstc, int syntax, const char *eofmark, int striptabs)
9964{
Eric Andersencb57d552001-06-28 07:25:16 +00009965 int c = firstc;
9966 char *out;
9967 int len;
9968 char line[EOFMARKLEN + 1];
9969 struct nodelist *bqlist;
9970 int quotef;
9971 int dblquote;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009972 int varnest; /* levels of variables expansion */
9973 int arinest; /* levels of arithmetic expansion */
9974 int parenlevel; /* levels of parens in arithmetic */
9975 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00009976 int oldstyle;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009977 int prevsyntax; /* syntax before arithmetic */
9978
Eric Andersencb57d552001-06-28 07:25:16 +00009979#if __GNUC__
9980 /* Avoid longjmp clobbering */
9981 (void) &out;
9982 (void) &quotef;
9983 (void) &dblquote;
9984 (void) &varnest;
9985 (void) &arinest;
9986 (void) &parenlevel;
9987 (void) &dqvarnest;
9988 (void) &oldstyle;
9989 (void) &prevsyntax;
9990 (void) &syntax;
9991#endif
9992
9993 startlinno = plinno;
9994 dblquote = 0;
9995 if (syntax == DQSYNTAX)
9996 dblquote = 1;
9997 quotef = 0;
9998 bqlist = NULL;
9999 varnest = 0;
10000 arinest = 0;
10001 parenlevel = 0;
10002 dqvarnest = 0;
10003
10004 STARTSTACKSTR(out);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010005 loop:{ /* for each line, until end of word */
10006 CHECKEND(); /* set c to PEOF if at end of here document */
10007 for (;;) { /* until end of line or end of word */
10008 CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
10009 switch (SIT(c, syntax)) {
10010 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010011 if (syntax == BASESYNTAX)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010012 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010013 USTPUTC(c, out);
10014 plinno++;
10015 if (doprompt)
10016 setprompt(2);
10017 else
10018 setprompt(0);
10019 c = pgetc();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010020 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010021 case CWORD:
10022 USTPUTC(c, out);
10023 break;
10024 case CCTL:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010025 if ((eofmark == NULL || dblquote) && dqvarnest == 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010026 USTPUTC(CTLESC, out);
10027 USTPUTC(c, out);
10028 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010029 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010030 c = pgetc2();
10031 if (c == PEOF) {
10032 USTPUTC('\\', out);
10033 pungetc();
10034 } else if (c == '\n') {
10035 if (doprompt)
10036 setprompt(2);
10037 else
10038 setprompt(0);
10039 } else {
10040 if (dblquote && c != '\\' && c != '`' && c != '$'
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010041 && (c != '"' || eofmark != NULL))
Eric Andersencb57d552001-06-28 07:25:16 +000010042 USTPUTC('\\', out);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010043 if (SIT(c, SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010044 USTPUTC(CTLESC, out);
10045 else if (eofmark == NULL)
10046 USTPUTC(CTLQUOTEMARK, out);
10047 USTPUTC(c, out);
10048 quotef++;
10049 }
10050 break;
10051 case CSQUOTE:
10052 if (eofmark == NULL)
10053 USTPUTC(CTLQUOTEMARK, out);
10054 syntax = SQSYNTAX;
10055 break;
10056 case CDQUOTE:
10057 if (eofmark == NULL)
10058 USTPUTC(CTLQUOTEMARK, out);
10059 syntax = DQSYNTAX;
10060 dblquote = 1;
10061 break;
10062 case CENDQUOTE:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010063 if (eofmark != NULL && arinest == 0 && varnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010064 USTPUTC(c, out);
10065 } else {
10066 if (arinest) {
10067 syntax = ARISYNTAX;
10068 dblquote = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010069 } else if (eofmark == NULL && dqvarnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010070 syntax = BASESYNTAX;
10071 dblquote = 0;
10072 }
10073 quotef++;
10074 }
10075 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010076 case CVAR: /* '$' */
10077 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010078 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010079 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010080 if (varnest > 0) {
10081 varnest--;
10082 if (dqvarnest > 0) {
10083 dqvarnest--;
10084 }
10085 USTPUTC(CTLENDVAR, out);
10086 } else {
10087 USTPUTC(c, out);
10088 }
10089 break;
Eric Andersend35c5df2002-01-09 15:37:36 +000010090#ifdef CONFIG_ASH_MATH_SUPPORT
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010091 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010092 parenlevel++;
10093 USTPUTC(c, out);
10094 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010095 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010096 if (parenlevel > 0) {
10097 USTPUTC(c, out);
10098 --parenlevel;
10099 } else {
10100 if (pgetc() == ')') {
10101 if (--arinest == 0) {
10102 USTPUTC(CTLENDARI, out);
10103 syntax = prevsyntax;
10104 if (syntax == DQSYNTAX)
10105 dblquote = 1;
10106 else
10107 dblquote = 0;
10108 } else
10109 USTPUTC(')', out);
10110 } else {
10111 /*
10112 * unbalanced parens
10113 * (don't 2nd guess - no error)
10114 */
10115 pungetc();
10116 USTPUTC(')', out);
10117 }
10118 }
10119 break;
10120#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010121 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010122 PARSEBACKQOLD();
10123 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010124 case CENDFILE:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010125 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010126 case CIGN:
10127 break;
10128 default:
10129 if (varnest == 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010130 goto endword; /* exit outer loop */
Eric Andersend35c5df2002-01-09 15:37:36 +000010131#ifdef CONFIG_ASH_ALIAS
Eric Andersen3102ac42001-07-06 04:26:23 +000010132 if (c != PEOA)
10133#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010134 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010135
Eric Andersencb57d552001-06-28 07:25:16 +000010136 }
10137 c = pgetc_macro();
10138 }
10139 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010140 endword:
Eric Andersencb57d552001-06-28 07:25:16 +000010141 if (syntax == ARISYNTAX)
10142 synerror("Missing '))'");
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010143 if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010144 synerror("Unterminated quoted string");
10145 if (varnest != 0) {
10146 startlinno = plinno;
10147 synerror("Missing '}'");
10148 }
10149 USTPUTC('\0', out);
10150 len = out - stackblock();
10151 out = stackblock();
10152 if (eofmark == NULL) {
10153 if ((c == '>' || c == '<')
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010154 && quotef == 0 && len <= 2 && (*out == '\0' || is_digit(*out))) {
Eric Andersencb57d552001-06-28 07:25:16 +000010155 PARSEREDIR();
10156 return lasttoken = TREDIR;
10157 } else {
10158 pungetc();
10159 }
10160 }
10161 quoteflag = quotef;
10162 backquotelist = bqlist;
10163 grabstackblock(len);
10164 wordtext = out;
10165 return lasttoken = TWORD;
10166/* end of readtoken routine */
10167
10168
10169
10170/*
10171 * Check to see whether we are at the end of the here document. When this
10172 * is called, c is set to the first character of the next input line. If
10173 * we are at the end of the here document, this routine sets the c to PEOF.
10174 */
10175
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010176 checkend:{
10177 if (eofmark) {
Eric Andersend35c5df2002-01-09 15:37:36 +000010178#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010179 if (c == PEOA) {
Eric Andersencb57d552001-06-28 07:25:16 +000010180 c = pgetc2();
10181 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010182#endif
10183 if (striptabs) {
10184 while (c == '\t') {
10185 c = pgetc2();
10186 }
10187 }
10188 if (c == *eofmark) {
10189 if (pfgets(line, sizeof line) != NULL) {
10190 const char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010191
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010192 p = line;
10193 for (q = eofmark + 1; *q && *p == *q; p++, q++);
10194 if (*p == '\n' && *q == '\0') {
10195 c = PEOF;
10196 plinno++;
10197 needprompt = doprompt;
10198 } else {
10199 pushstring(line, strlen(line), NULL);
10200 }
Eric Andersencb57d552001-06-28 07:25:16 +000010201 }
10202 }
10203 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010204 goto checkend_return;
Eric Andersencb57d552001-06-28 07:25:16 +000010205 }
Eric Andersencb57d552001-06-28 07:25:16 +000010206
10207
10208/*
10209 * Parse a redirection operator. The variable "out" points to a string
10210 * specifying the fd to be redirected. The variable "c" contains the
10211 * first character of the redirection operator.
10212 */
10213
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010214 parseredir:{
10215 char fd = *out;
10216 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000010217
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010218 np = (union node *) stalloc(sizeof(struct nfile));
10219 if (c == '>') {
10220 np->nfile.fd = 1;
10221 c = pgetc();
10222 if (c == '>')
10223 np->type = NAPPEND;
10224 else if (c == '&')
10225 np->type = NTOFD;
10226 else if (c == '|')
10227 np->type = NTOOV;
10228 else {
10229 np->type = NTO;
Eric Andersencb57d552001-06-28 07:25:16 +000010230 pungetc();
10231 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010232 } else { /* c == '<' */
10233 np->nfile.fd = 0;
10234 switch (c = pgetc()) {
10235 case '<':
10236 if (sizeof(struct nfile) != sizeof(struct nhere)) {
10237 np = (union node *) stalloc(sizeof(struct nhere));
10238 np->nfile.fd = 0;
10239 }
10240 np->type = NHERE;
10241 heredoc = (struct heredoc *) stalloc(sizeof(struct heredoc));
10242 heredoc->here = np;
10243 if ((c = pgetc()) == '-') {
10244 heredoc->striptabs = 1;
10245 } else {
10246 heredoc->striptabs = 0;
10247 pungetc();
10248 }
10249 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010250
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010251 case '&':
10252 np->type = NFROMFD;
10253 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010254
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010255 case '>':
10256 np->type = NFROMTO;
10257 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010258
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010259 default:
10260 np->type = NFROM;
10261 pungetc();
10262 break;
10263 }
Eric Andersencb57d552001-06-28 07:25:16 +000010264 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010265 if (fd != '\0')
10266 np->nfile.fd = digit_val(fd);
10267 redirnode = np;
10268 goto parseredir_return;
Eric Andersencb57d552001-06-28 07:25:16 +000010269 }
Eric Andersencb57d552001-06-28 07:25:16 +000010270
10271
10272/*
10273 * Parse a substitution. At this point, we have read the dollar sign
10274 * and nothing else.
10275 */
10276
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010277 parsesub:{
10278 int subtype;
10279 int typeloc;
10280 int flags;
10281 char *p;
10282 static const char types[] = "}-+?=";
Eric Andersencb57d552001-06-28 07:25:16 +000010283
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010284 c = pgetc();
10285 if (c <= PEOA ||
10286 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10287 ) {
10288 USTPUTC('$', out);
Eric Andersencb57d552001-06-28 07:25:16 +000010289 pungetc();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010290 } else if (c == '(') { /* $(command) or $((arith)) */
10291 if (pgetc() == '(') {
10292 PARSEARITH();
10293 } else {
10294 pungetc();
10295 PARSEBACKQNEW();
Eric Andersencb57d552001-06-28 07:25:16 +000010296 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010297 } else {
10298 USTPUTC(CTLVAR, out);
10299 typeloc = out - stackblock();
10300 USTPUTC(VSNORMAL, out);
10301 subtype = VSNORMAL;
10302 if (c == '{') {
Eric Andersencb57d552001-06-28 07:25:16 +000010303 c = pgetc();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010304 if (c == '#') {
10305 if ((c = pgetc()) == '}')
10306 c = '#';
10307 else
10308 subtype = VSLENGTH;
10309 } else
10310 subtype = 0;
10311 }
10312 if (c > PEOA && is_name(c)) {
10313 do {
10314 STPUTC(c, out);
10315 c = pgetc();
10316 } while (c > PEOA && is_in_name(c));
10317 } else if (is_digit(c)) {
10318 do {
10319 USTPUTC(c, out);
10320 c = pgetc();
10321 } while (is_digit(c));
10322 } else if (is_special(c)) {
Eric Andersencb57d552001-06-28 07:25:16 +000010323 USTPUTC(c, out);
10324 c = pgetc();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010325 } else
10326 badsub:synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010327
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010328 STPUTC('=', out);
10329 flags = 0;
10330 if (subtype == 0) {
10331 switch (c) {
10332 case ':':
10333 flags = VSNUL;
10334 c = pgetc();
10335 /*FALLTHROUGH*/ default:
10336 p = strchr(types, c);
10337 if (p == NULL)
10338 goto badsub;
10339 subtype = p - types + VSNORMAL;
10340 break;
10341 case '%':
10342 case '#':
Eric Andersencb57d552001-06-28 07:25:16 +000010343 {
10344 int cc = c;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010345
10346 subtype = c == '#' ? VSTRIMLEFT : VSTRIMRIGHT;
Eric Andersencb57d552001-06-28 07:25:16 +000010347 c = pgetc();
10348 if (c == cc)
10349 subtype++;
10350 else
10351 pungetc();
10352 break;
10353 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010354 }
10355 } else {
10356 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010357 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010358 if (dblquote || arinest)
10359 flags |= VSQUOTE;
10360 *(stackblock() + typeloc) = subtype | flags;
10361 if (subtype != VSNORMAL) {
10362 varnest++;
10363 if (dblquote) {
10364 dqvarnest++;
10365 }
Eric Andersencb57d552001-06-28 07:25:16 +000010366 }
10367 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010368 goto parsesub_return;
Eric Andersencb57d552001-06-28 07:25:16 +000010369 }
Eric Andersencb57d552001-06-28 07:25:16 +000010370
10371
10372/*
10373 * Called to parse command substitutions. Newstyle is set if the command
10374 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10375 * list of commands (passed by reference), and savelen is the number of
10376 * characters on the top of the stack which must be preserved.
10377 */
10378
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010379 parsebackq:{
10380 struct nodelist **nlpp;
10381 int savepbq;
10382 union node *n;
10383 char *volatile str;
10384 struct jmploc jmploc;
10385 struct jmploc *volatile savehandler;
10386 int savelen;
10387 int saveprompt;
10388
Eric Andersencb57d552001-06-28 07:25:16 +000010389#ifdef __GNUC__
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010390 (void) &saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010391#endif
10392
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010393 savepbq = parsebackquote;
10394 if (setjmp(jmploc.loc)) {
10395 free(str);
10396 parsebackquote = 0;
10397 handler = savehandler;
10398 longjmp(handler->loc, 1);
10399 }
10400 INTOFF;
10401 str = NULL;
10402 savelen = out - stackblock();
10403 if (savelen > 0) {
10404 str = xmalloc(savelen);
10405 memcpy(str, stackblock(), savelen);
10406 }
10407 savehandler = handler;
10408 handler = &jmploc;
10409 INTON;
10410 if (oldstyle) {
10411 /* We must read until the closing backquote, giving special
10412 treatment to some slashes, and then push the string and
10413 reread it as input, interpreting it normally. */
10414 char *pout;
10415 int pc;
10416 int psavelen;
10417 char *pstr;
Eric Andersencb57d552001-06-28 07:25:16 +000010418
10419
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010420 STARTSTACKSTR(pout);
10421 for (;;) {
10422 if (needprompt) {
10423 setprompt(2);
10424 needprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010425 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010426 switch (pc = pgetc()) {
10427 case '`':
10428 goto done;
10429
10430 case '\\':
10431 if ((pc = pgetc()) == '\n') {
10432 plinno++;
10433 if (doprompt)
10434 setprompt(2);
10435 else
10436 setprompt(0);
10437 /*
10438 * If eating a newline, avoid putting
10439 * the newline into the new character
10440 * stream (via the STPUTC after the
10441 * switch).
10442 */
10443 continue;
10444 }
10445 if (pc != '\\' && pc != '`' && pc != '$'
10446 && (!dblquote || pc != '"'))
10447 STPUTC('\\', pout);
10448 if (pc > PEOA) {
10449 break;
10450 }
10451 /* fall through */
10452
10453 case PEOF:
10454#ifdef CONFIG_ASH_ALIAS
10455 case PEOA:
10456#endif
10457 startlinno = plinno;
10458 synerror("EOF in backquote substitution");
10459
10460 case '\n':
10461 plinno++;
10462 needprompt = doprompt;
10463 break;
10464
10465 default:
Eric Andersencb57d552001-06-28 07:25:16 +000010466 break;
10467 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010468 STPUTC(pc, pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010469 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010470 done:
10471 STPUTC('\0', pout);
10472 psavelen = pout - stackblock();
10473 if (psavelen > 0) {
10474 pstr = grabstackstr(pout);
10475 setinputstring(pstr);
10476 }
Eric Andersen2870d962001-07-02 17:27:21 +000010477 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010478 nlpp = &bqlist;
10479 while (*nlpp)
10480 nlpp = &(*nlpp)->next;
10481 *nlpp = (struct nodelist *) stalloc(sizeof(struct nodelist));
10482 (*nlpp)->next = NULL;
10483 parsebackquote = oldstyle;
10484
10485 if (oldstyle) {
10486 saveprompt = doprompt;
10487 doprompt = 0;
Eric Andersen2870d962001-07-02 17:27:21 +000010488 }
Eric Andersencb57d552001-06-28 07:25:16 +000010489
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010490 n = list(0);
Eric Andersencb57d552001-06-28 07:25:16 +000010491
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010492 if (oldstyle)
10493 doprompt = saveprompt;
10494 else {
10495 if (readtoken() != TRP)
10496 synexpect(TRP);
10497 }
Eric Andersencb57d552001-06-28 07:25:16 +000010498
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010499 (*nlpp)->n = n;
10500 if (oldstyle) {
10501 /*
10502 * Start reading from old file again, ignoring any pushed back
10503 * tokens left from the backquote parsing
10504 */
10505 popfile();
10506 tokpushback = 0;
10507 }
10508 while (stackblocksize() <= savelen)
10509 growstackblock();
10510 STARTSTACKSTR(out);
10511 if (str) {
10512 memcpy(out, str, savelen);
10513 STADJUST(savelen, out);
10514 INTOFF;
10515 free(str);
10516 str = NULL;
10517 INTON;
10518 }
10519 parsebackquote = savepbq;
10520 handler = savehandler;
10521 if (arinest || dblquote)
10522 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10523 else
10524 USTPUTC(CTLBACKQ, out);
10525 if (oldstyle)
10526 goto parsebackq_oldreturn;
10527 else
10528 goto parsebackq_newreturn;
Eric Andersencb57d552001-06-28 07:25:16 +000010529 }
10530
Eric Andersencb57d552001-06-28 07:25:16 +000010531/*
10532 * Parse an arithmetic expansion (indicate start of one and set state)
10533 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010534 parsearith:{
Eric Andersencb57d552001-06-28 07:25:16 +000010535
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010536 if (++arinest == 1) {
10537 prevsyntax = syntax;
10538 syntax = ARISYNTAX;
10539 USTPUTC(CTLARI, out);
10540 if (dblquote)
10541 USTPUTC('"', out);
10542 else
10543 USTPUTC(' ', out);
10544 } else {
10545 /*
10546 * we collapse embedded arithmetic expansion to
10547 * parenthesis, which should be equivalent
10548 */
10549 USTPUTC('(', out);
10550 }
10551 goto parsearith_return;
Eric Andersencb57d552001-06-28 07:25:16 +000010552 }
Eric Andersencb57d552001-06-28 07:25:16 +000010553
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010554} /* end of readtoken */
Eric Andersencb57d552001-06-28 07:25:16 +000010555
10556
Eric Andersencb57d552001-06-28 07:25:16 +000010557/*
10558 * Returns true if the text contains nothing to expand (no dollar signs
10559 * or backquotes).
10560 */
10561
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010562static int noexpand(char *text)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010563{
Eric Andersencb57d552001-06-28 07:25:16 +000010564 char *p;
10565 char c;
10566
10567 p = text;
10568 while ((c = *p++) != '\0') {
10569 if (c == CTLQUOTEMARK)
10570 continue;
10571 if (c == CTLESC)
10572 p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010573 else if (SIT(c, BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010574 return 0;
10575 }
10576 return 1;
10577}
10578
10579
10580/*
10581 * Return true if the argument is a legal variable name (a letter or
10582 * underscore followed by zero or more letters, underscores, and digits).
10583 */
10584
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010585static int goodname(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +000010586{
10587 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000010588
10589 p = name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010590 if (!is_name(*p))
Eric Andersencb57d552001-06-28 07:25:16 +000010591 return 0;
10592 while (*++p) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010593 if (!is_in_name(*p))
Eric Andersencb57d552001-06-28 07:25:16 +000010594 return 0;
10595 }
10596 return 1;
10597}
10598
10599
10600/*
10601 * Called when an unexpected token is read during the parse. The argument
10602 * is the token that is expected, or -1 if more than one type of token can
10603 * occur at this point.
10604 */
10605
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010606static void synexpect(int token)
Eric Andersencb57d552001-06-28 07:25:16 +000010607{
10608 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010609 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000010610
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010611 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10612 if (token >= 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010613 sprintf(msg + l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000010614 synerror(msg);
10615 /* NOTREACHED */
10616}
10617
10618
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010619static void synerror(const char *msg)
Eric Andersen2870d962001-07-02 17:27:21 +000010620{
Eric Andersencb57d552001-06-28 07:25:16 +000010621 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +000010622 out2fmt("%s: %d: ", commandname, startlinno);
10623 out2fmt("Syntax error: %s\n", msg);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010624 error((char *) NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000010625 /* NOTREACHED */
10626}
10627
Eric Andersencb57d552001-06-28 07:25:16 +000010628
10629/*
10630 * called by editline -- any expansions to the prompt
10631 * should be added here.
10632 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010633static void setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000010634{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010635 char *prompt;
10636
10637 switch (whichprompt) {
Eric Andersen62483552001-07-10 06:09:16 +000010638 case 1:
10639 prompt = ps1val();
10640 break;
10641 case 2:
10642 prompt = ps2val();
10643 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010644 default: /* 0 */
Eric Andersen62483552001-07-10 06:09:16 +000010645 prompt = "";
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010646 }
10647 putprompt(prompt);
Eric Andersencb57d552001-06-28 07:25:16 +000010648}
10649
Eric Andersencb57d552001-06-28 07:25:16 +000010650
Eric Andersencb57d552001-06-28 07:25:16 +000010651/*
10652 * Code for dealing with input/output redirection.
10653 */
10654
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010655#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000010656#ifndef PIPE_BUF
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010657# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000010658#else
10659# define PIPESIZE PIPE_BUF
10660#endif
10661
10662
Eric Andersen62483552001-07-10 06:09:16 +000010663/*
10664 * Open a file in noclobber mode.
10665 * The code was copied from bash.
10666 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010667static inline int noclobberopen(const char *fname)
Eric Andersen62483552001-07-10 06:09:16 +000010668{
10669 int r, fd;
10670 struct stat finfo, finfo2;
10671
10672 /*
10673 * If the file exists and is a regular file, return an error
10674 * immediately.
10675 */
10676 r = stat(fname, &finfo);
10677 if (r == 0 && S_ISREG(finfo.st_mode)) {
10678 errno = EEXIST;
10679 return -1;
10680 }
10681
10682 /*
10683 * If the file was not present (r != 0), make sure we open it
10684 * exclusively so that if it is created before we open it, our open
10685 * will fail. Make sure that we do not truncate an existing file.
10686 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10687 * file was not a regular file, we leave O_EXCL off.
10688 */
10689 if (r != 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010690 return open(fname, O_WRONLY | O_CREAT | O_EXCL, 0666);
10691 fd = open(fname, O_WRONLY | O_CREAT, 0666);
Eric Andersen62483552001-07-10 06:09:16 +000010692
10693 /* If the open failed, return the file descriptor right away. */
10694 if (fd < 0)
10695 return fd;
10696
10697 /*
10698 * OK, the open succeeded, but the file may have been changed from a
10699 * non-regular file to a regular file between the stat and the open.
10700 * We are assuming that the O_EXCL open handles the case where FILENAME
10701 * did not exist and is symlinked to an existing file between the stat
10702 * and open.
10703 */
10704
10705 /*
10706 * If we can open it and fstat the file descriptor, and neither check
10707 * revealed that it was a regular file, and the file has not been
10708 * replaced, return the file descriptor.
10709 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010710 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10711 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
Eric Andersen62483552001-07-10 06:09:16 +000010712 return fd;
10713
10714 /* The file has been replaced. badness. */
10715 close(fd);
10716 errno = EEXIST;
10717 return -1;
10718}
Eric Andersencb57d552001-06-28 07:25:16 +000010719
10720/*
Eric Andersen62483552001-07-10 06:09:16 +000010721 * Handle here documents. Normally we fork off a process to write the
10722 * data to a pipe. If the document is short, we can stuff the data in
10723 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000010724 */
10725
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010726static inline int openhere(const union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010727{
10728 int pip[2];
10729 int len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010730
Eric Andersen62483552001-07-10 06:09:16 +000010731 if (pipe(pip) < 0)
10732 error("Pipe call failed");
10733 if (redir->type == NHERE) {
10734 len = strlen(redir->nhere.doc->narg.text);
10735 if (len <= PIPESIZE) {
10736 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10737 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010738 }
Eric Andersencb57d552001-06-28 07:25:16 +000010739 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010740 if (forkshell((struct job *) NULL, (union node *) NULL, FORK_NOJOB) == 0) {
Eric Andersen62483552001-07-10 06:09:16 +000010741 close(pip[0]);
10742 signal(SIGINT, SIG_IGN);
10743 signal(SIGQUIT, SIG_IGN);
10744 signal(SIGHUP, SIG_IGN);
10745#ifdef SIGTSTP
10746 signal(SIGTSTP, SIG_IGN);
10747#endif
10748 signal(SIGPIPE, SIG_DFL);
10749 if (redir->type == NHERE)
10750 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10751 else
10752 expandhere(redir->nhere.doc, pip[1]);
10753 _exit(0);
10754 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010755 out:
Eric Andersen62483552001-07-10 06:09:16 +000010756 close(pip[1]);
10757 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000010758}
10759
10760
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010761static inline int openredirect(const union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010762{
Eric Andersencb57d552001-06-28 07:25:16 +000010763 char *fname;
10764 int f;
10765
10766 switch (redir->nfile.type) {
10767 case NFROM:
10768 fname = redir->nfile.expfname;
10769 if ((f = open(fname, O_RDONLY)) < 0)
10770 goto eopen;
10771 break;
10772 case NFROMTO:
10773 fname = redir->nfile.expfname;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010774 if ((f = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010775 goto ecreate;
10776 break;
10777 case NTO:
10778 /* Take care of noclobber mode. */
10779 if (Cflag) {
10780 fname = redir->nfile.expfname;
10781 if ((f = noclobberopen(fname)) < 0)
10782 goto ecreate;
10783 break;
10784 }
10785 case NTOOV:
10786 fname = redir->nfile.expfname;
10787#ifdef O_CREAT
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010788 if ((f = open(fname, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010789 goto ecreate;
10790#else
10791 if ((f = creat(fname, 0666)) < 0)
10792 goto ecreate;
10793#endif
10794 break;
10795 case NAPPEND:
10796 fname = redir->nfile.expfname;
10797#ifdef O_APPEND
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010798 if ((f = open(fname, O_WRONLY | O_CREAT | O_APPEND, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010799 goto ecreate;
10800#else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010801 if ((f = open(fname, O_WRONLY)) < 0 && (f = creat(fname, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010802 goto ecreate;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010803 lseek(f, (off_t) 0, 2);
Eric Andersencb57d552001-06-28 07:25:16 +000010804#endif
10805 break;
10806 default:
10807#ifdef DEBUG
10808 abort();
10809#endif
10810 /* Fall through to eliminate warning. */
10811 case NTOFD:
10812 case NFROMFD:
10813 f = -1;
10814 break;
10815 case NHERE:
10816 case NXHERE:
10817 f = openhere(redir);
10818 break;
10819 }
10820
10821 return f;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010822 ecreate:
Eric Andersencb57d552001-06-28 07:25:16 +000010823 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010824 eopen:
Eric Andersencb57d552001-06-28 07:25:16 +000010825 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
10826}
10827
10828
Eric Andersen62483552001-07-10 06:09:16 +000010829/*
10830 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
10831 * old file descriptors are stashed away so that the redirection can be
10832 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
10833 * standard output, and the standard error if it becomes a duplicate of
10834 * stdout.
10835 */
10836
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010837static void redirect(union node *redir, int flags)
Eric Andersen62483552001-07-10 06:09:16 +000010838{
10839 union node *n;
10840 struct redirtab *sv = NULL;
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010841 int i;
Eric Andersen62483552001-07-10 06:09:16 +000010842 int fd;
10843 int newfd;
10844 int try;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010845 int fd1dup = flags & REDIR_BACKQ;; /* stdout `cmd` redir to pipe */
Eric Andersen62483552001-07-10 06:09:16 +000010846
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010847 TRACE(("redirect(%s) called\n",
10848 flags & REDIR_PUSH ? "REDIR_PUSH" : "NO_REDIR_PUSH"));
Eric Andersen62483552001-07-10 06:09:16 +000010849 if (flags & REDIR_PUSH) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010850 sv = xmalloc(sizeof(struct redirtab));
10851 for (i = 0; i < 10; i++)
Eric Andersen62483552001-07-10 06:09:16 +000010852 sv->renamed[i] = EMPTY;
10853 sv->next = redirlist;
10854 redirlist = sv;
10855 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010856 for (n = redir; n; n = n->nfile.next) {
Eric Andersen62483552001-07-10 06:09:16 +000010857 fd = n->nfile.fd;
10858 try = 0;
10859 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010860 n->ndup.dupfd == fd)
10861 continue; /* redirect from/to same file descriptor */
Eric Andersen62483552001-07-10 06:09:16 +000010862
10863 INTOFF;
10864 newfd = openredirect(n);
10865 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
10866 if (newfd == fd) {
10867 try++;
10868 } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
10869 switch (errno) {
10870 case EBADF:
10871 if (!try) {
10872 dupredirect(n, newfd, fd1dup);
10873 try++;
10874 break;
10875 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010876 /* FALLTHROUGH */
Eric Andersen62483552001-07-10 06:09:16 +000010877 default:
10878 if (newfd >= 0) {
10879 close(newfd);
10880 }
10881 INTON;
10882 error("%d: %m", fd);
10883 /* NOTREACHED */
10884 }
10885 }
10886 if (!try) {
10887 close(fd);
10888 if (flags & REDIR_PUSH) {
10889 sv->renamed[fd] = i;
10890 }
10891 }
10892 } else if (fd != newfd) {
10893 close(fd);
10894 }
10895 if (fd == 0)
10896 fd0_redirected++;
10897 if (!try)
10898 dupredirect(n, newfd, fd1dup);
10899 INTON;
10900 }
10901}
10902
10903
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010904static void dupredirect(const union node *redir, int f, int fd1dup)
Eric Andersen2870d962001-07-02 17:27:21 +000010905{
Eric Andersencb57d552001-06-28 07:25:16 +000010906 int fd = redir->nfile.fd;
10907
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010908 if (fd == 1)
Eric Andersen62483552001-07-10 06:09:16 +000010909 fd1dup = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010910 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010911 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
10912 if (redir->ndup.dupfd != 1 || fd1dup != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000010913 dup_as_newfd(redir->ndup.dupfd, fd);
10914 }
10915 return;
10916 }
10917
10918 if (f != fd) {
10919 dup_as_newfd(f, fd);
10920 close(f);
10921 }
10922 return;
10923}
10924
10925
Eric Andersencb57d552001-06-28 07:25:16 +000010926
Eric Andersencb57d552001-06-28 07:25:16 +000010927/*
10928 * Undo the effects of the last redirection.
10929 */
10930
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010931static void popredir(void)
Eric Andersen2870d962001-07-02 17:27:21 +000010932{
Eric Andersencb57d552001-06-28 07:25:16 +000010933 struct redirtab *rp = redirlist;
10934 int i;
10935
10936 INTOFF;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010937 for (i = 0; i < 10; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000010938 if (rp->renamed[i] != EMPTY) {
Eric Andersen2870d962001-07-02 17:27:21 +000010939 if (i == 0)
10940 fd0_redirected--;
Eric Andersencb57d552001-06-28 07:25:16 +000010941 close(i);
10942 if (rp->renamed[i] >= 0) {
10943 dup_as_newfd(rp->renamed[i], i);
10944 close(rp->renamed[i]);
10945 }
Eric Andersencb57d552001-06-28 07:25:16 +000010946 }
10947 }
10948 redirlist = rp->next;
Aaron Lehmann49c024a2002-08-02 06:39:47 +000010949 free(rp);
Eric Andersencb57d552001-06-28 07:25:16 +000010950 INTON;
10951}
10952
10953/*
Eric Andersencb57d552001-06-28 07:25:16 +000010954 * Discard all saved file descriptors.
10955 */
10956
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010957static void clearredir(void)
10958{
Eric Andersencb57d552001-06-28 07:25:16 +000010959 struct redirtab *rp;
10960 int i;
10961
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010962 for (rp = redirlist; rp; rp = rp->next) {
10963 for (i = 0; i < 10; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000010964 if (rp->renamed[i] >= 0) {
10965 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000010966 }
10967 rp->renamed[i] = EMPTY;
10968 }
10969 }
Eric Andersencb57d552001-06-28 07:25:16 +000010970}
10971
10972
Eric Andersencb57d552001-06-28 07:25:16 +000010973/*
10974 * Copy a file descriptor to be >= to. Returns -1
10975 * if the source file descriptor is closed, EMPTY if there are no unused
10976 * file descriptors left.
10977 */
10978
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010979static int dup_as_newfd(int from, int to)
Eric Andersencb57d552001-06-28 07:25:16 +000010980{
10981 int newfd;
10982
10983 newfd = fcntl(from, F_DUPFD, to);
10984 if (newfd < 0) {
10985 if (errno == EMFILE)
10986 return EMPTY;
10987 else
Eric Andersen2870d962001-07-02 17:27:21 +000010988 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000010989 }
10990 return newfd;
10991}
10992
Eric Andersencb57d552001-06-28 07:25:16 +000010993#ifdef DEBUG
Eric Andersenec074692001-10-31 11:05:49 +000010994/*
10995 * Debugging stuff.
10996 */
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010997
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010998static void shtree(union node *, int, char *, FILE *);
10999static void shcmd(union node *, FILE *);
11000static void sharg(union node *, FILE *);
11001static void indent(int, char *, FILE *);
11002static void trstring(char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011003
11004
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011005#if 0
11006static void showtree(node * n)
Eric Andersencb57d552001-06-28 07:25:16 +000011007{
11008 trputs("showtree called\n");
11009 shtree(n, 1, NULL, stdout);
11010}
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011011#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011012
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011013static void shtree(union node *n, int ind, char *pfx, FILE * fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011014{
11015 struct nodelist *lp;
11016 const char *s;
11017
11018 if (n == NULL)
11019 return;
11020
11021 indent(ind, pfx, fp);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011022 switch (n->type) {
Eric Andersencb57d552001-06-28 07:25:16 +000011023 case NSEMI:
11024 s = "; ";
11025 goto binop;
11026 case NAND:
11027 s = " && ";
11028 goto binop;
11029 case NOR:
11030 s = " || ";
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011031 binop:
Eric Andersencb57d552001-06-28 07:25:16 +000011032 shtree(n->nbinary.ch1, ind, NULL, fp);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011033 /* if (ind < 0) */
11034 fputs(s, fp);
Eric Andersencb57d552001-06-28 07:25:16 +000011035 shtree(n->nbinary.ch2, ind, NULL, fp);
11036 break;
11037 case NCMD:
11038 shcmd(n, fp);
11039 if (ind >= 0)
11040 putc('\n', fp);
11041 break;
11042 case NPIPE:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011043 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000011044 shcmd(lp->n, fp);
11045 if (lp->next)
11046 fputs(" | ", fp);
11047 }
11048 if (n->npipe.backgnd)
11049 fputs(" &", fp);
11050 if (ind >= 0)
11051 putc('\n', fp);
11052 break;
11053 default:
11054 fprintf(fp, "<node type %d>", n->type);
11055 if (ind >= 0)
11056 putc('\n', fp);
11057 break;
11058 }
11059}
11060
11061
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011062static void shcmd(union node *cmd, FILE * fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011063{
11064 union node *np;
11065 int first;
11066 const char *s;
11067 int dftfd;
11068
11069 first = 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011070 for (np = cmd->ncmd.args; np; np = np->narg.next) {
11071 if (!first)
Eric Andersencb57d552001-06-28 07:25:16 +000011072 putchar(' ');
11073 sharg(np, fp);
11074 first = 0;
11075 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011076 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
11077 if (!first)
Eric Andersencb57d552001-06-28 07:25:16 +000011078 putchar(' ');
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011079#if 1
11080 s = "*error*";
11081 dftfd = 0;
11082 if ((np->nfile.type <= NFROMFD) && (np->nfile.type >= NTO)) {
11083 s = redir_strings[np->nfile.type - NTO];
11084 if (*s == '>') {
11085 dftfd = 1;
11086 }
11087 }
11088#else
Eric Andersencb57d552001-06-28 07:25:16 +000011089 switch (np->nfile.type) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011090 case NTO:
11091 s = ">";
11092 dftfd = 1;
11093 break;
11094 case NAPPEND:
11095 s = ">>";
11096 dftfd = 1;
11097 break;
11098 case NTOFD:
11099 s = ">&";
11100 dftfd = 1;
11101 break;
11102 case NTOOV:
11103 s = ">|";
11104 dftfd = 1;
11105 break;
11106 case NFROM:
11107 s = "<";
11108 dftfd = 0;
11109 break;
11110 case NFROMFD:
11111 s = "<&";
11112 dftfd = 0;
11113 break;
11114 case NFROMTO:
11115 s = "<>";
11116 dftfd = 0;
11117 break;
11118 default:
11119 s = "*error*";
11120 dftfd = 0;
11121 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011122 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011123#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011124 if (np->nfile.fd != dftfd)
11125 fprintf(fp, "%d", np->nfile.fd);
11126 fputs(s, fp);
11127 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11128 fprintf(fp, "%d", np->ndup.dupfd);
11129 } else {
11130 sharg(np->nfile.fname, fp);
11131 }
11132 first = 0;
11133 }
11134}
11135
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011136
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011137static void sharg(union node *arg, FILE * fp)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011138{
Eric Andersencb57d552001-06-28 07:25:16 +000011139 char *p;
11140 struct nodelist *bqlist;
11141 int subtype;
11142
11143 if (arg->type != NARG) {
11144 printf("<node type %d>\n", arg->type);
11145 fflush(stdout);
11146 abort();
11147 }
11148 bqlist = arg->narg.backquote;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011149 for (p = arg->narg.text; *p; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011150 switch (*p) {
11151 case CTLESC:
11152 putc(*++p, fp);
11153 break;
11154 case CTLVAR:
11155 putc('$', fp);
11156 putc('{', fp);
11157 subtype = *++p;
11158 if (subtype == VSLENGTH)
11159 putc('#', fp);
11160
11161 while (*p != '=')
11162 putc(*p++, fp);
11163
11164 if (subtype & VSNUL)
11165 putc(':', fp);
11166
11167 switch (subtype & VSTYPE) {
11168 case VSNORMAL:
11169 putc('}', fp);
11170 break;
11171 case VSMINUS:
11172 putc('-', fp);
11173 break;
11174 case VSPLUS:
11175 putc('+', fp);
11176 break;
11177 case VSQUESTION:
11178 putc('?', fp);
11179 break;
11180 case VSASSIGN:
11181 putc('=', fp);
11182 break;
11183 case VSTRIMLEFT:
11184 putc('#', fp);
11185 break;
11186 case VSTRIMLEFTMAX:
11187 putc('#', fp);
11188 putc('#', fp);
11189 break;
11190 case VSTRIMRIGHT:
11191 putc('%', fp);
11192 break;
11193 case VSTRIMRIGHTMAX:
11194 putc('%', fp);
11195 putc('%', fp);
11196 break;
11197 case VSLENGTH:
11198 break;
11199 default:
11200 printf("<subtype %d>", subtype);
11201 }
11202 break;
11203 case CTLENDVAR:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011204 putc('}', fp);
11205 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011206 case CTLBACKQ:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011207 case CTLBACKQ | CTLQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000011208 putc('$', fp);
11209 putc('(', fp);
11210 shtree(bqlist->n, -1, NULL, fp);
11211 putc(')', fp);
11212 break;
11213 default:
11214 putc(*p, fp);
11215 break;
11216 }
11217 }
11218}
11219
11220
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011221static void indent(int amount, char *pfx, FILE * fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011222{
11223 int i;
11224
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011225 for (i = 0; i < amount; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011226 if (pfx && i == amount - 1)
11227 fputs(pfx, fp);
11228 putc('\t', fp);
11229 }
11230}
Eric Andersencb57d552001-06-28 07:25:16 +000011231
Eric Andersencb57d552001-06-28 07:25:16 +000011232FILE *tracefile;
11233
11234#if DEBUG == 2
11235static int debug = 1;
11236#else
11237static int debug = 0;
11238#endif
11239
11240
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011241static void trputc(int c)
Eric Andersencb57d552001-06-28 07:25:16 +000011242{
11243 if (tracefile == NULL)
11244 return;
11245 putc(c, tracefile);
11246 if (c == '\n')
11247 fflush(tracefile);
11248}
11249
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011250static void trace(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +000011251{
11252 va_list va;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011253
Eric Andersencb57d552001-06-28 07:25:16 +000011254 va_start(va, fmt);
Eric Andersencb57d552001-06-28 07:25:16 +000011255 if (tracefile != NULL) {
11256 (void) vfprintf(tracefile, fmt, va);
11257 if (strchr(fmt, '\n'))
11258 (void) fflush(tracefile);
11259 }
11260 va_end(va);
11261}
11262
11263
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011264static void trputs(const char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011265{
11266 if (tracefile == NULL)
11267 return;
11268 fputs(s, tracefile);
11269 if (strchr(s, '\n'))
11270 fflush(tracefile);
11271}
11272
11273
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011274static void trstring(char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011275{
11276 char *p;
11277 char c;
11278
11279 if (tracefile == NULL)
11280 return;
11281 putc('"', tracefile);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011282 for (p = s; *p; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011283 switch (*p) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011284 case '\n':
11285 c = 'n';
11286 goto backslash;
11287 case '\t':
11288 c = 't';
11289 goto backslash;
11290 case '\r':
11291 c = 'r';
11292 goto backslash;
11293 case '"':
11294 c = '"';
11295 goto backslash;
11296 case '\\':
11297 c = '\\';
11298 goto backslash;
11299 case CTLESC:
11300 c = 'e';
11301 goto backslash;
11302 case CTLVAR:
11303 c = 'v';
11304 goto backslash;
11305 case CTLVAR + CTLQUOTE:
11306 c = 'V';
11307 goto backslash;
11308 case CTLBACKQ:
11309 c = 'q';
11310 goto backslash;
11311 case CTLBACKQ + CTLQUOTE:
11312 c = 'Q';
11313 goto backslash;
11314 backslash:putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011315 putc(c, tracefile);
11316 break;
11317 default:
11318 if (*p >= ' ' && *p <= '~')
11319 putc(*p, tracefile);
11320 else {
11321 putc('\\', tracefile);
11322 putc(*p >> 6 & 03, tracefile);
11323 putc(*p >> 3 & 07, tracefile);
11324 putc(*p & 07, tracefile);
11325 }
11326 break;
11327 }
11328 }
11329 putc('"', tracefile);
11330}
11331
11332
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011333static void trargs(char **ap)
Eric Andersencb57d552001-06-28 07:25:16 +000011334{
11335 if (tracefile == NULL)
11336 return;
11337 while (*ap) {
11338 trstring(*ap++);
11339 if (*ap)
11340 putc(' ', tracefile);
11341 else
11342 putc('\n', tracefile);
11343 }
11344 fflush(tracefile);
11345}
11346
11347
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011348static void opentrace()
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011349{
Eric Andersencb57d552001-06-28 07:25:16 +000011350 char s[100];
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011351
Eric Andersencb57d552001-06-28 07:25:16 +000011352#ifdef O_APPEND
11353 int flags;
11354#endif
11355
11356 if (!debug)
11357 return;
11358#ifdef not_this_way
11359 {
11360 char *p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011361
Eric Andersencb57d552001-06-28 07:25:16 +000011362 if ((p = getenv("HOME")) == NULL) {
11363 if (geteuid() == 0)
11364 p = "/";
11365 else
11366 p = "/tmp";
11367 }
Eric Andersen2870d962001-07-02 17:27:21 +000011368 strcpy(s, p);
Eric Andersencb57d552001-06-28 07:25:16 +000011369 strcat(s, "/trace");
11370 }
11371#else
Eric Andersen2870d962001-07-02 17:27:21 +000011372 strcpy(s, "./trace");
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011373#endif /* not_this_way */
Matt Kraaia5f09c62001-11-12 16:44:55 +000011374 if ((tracefile = wfopen(s, "a")) == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000011375 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011376#ifdef O_APPEND
11377 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11378 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11379#endif
11380 fputs("\nTracing started.\n", tracefile);
11381 fflush(tracefile);
11382}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011383#endif /* DEBUG */
Eric Andersencb57d552001-06-28 07:25:16 +000011384
11385
11386/*
Eric Andersencb57d552001-06-28 07:25:16 +000011387 * The trap builtin.
11388 */
11389
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011390static int trapcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011391{
11392 char *action;
11393 char **ap;
11394 int signo;
11395
11396 if (argc <= 1) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011397 for (signo = 0; signo < NSIG; signo++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011398 if (trap[signo] != NULL) {
11399 char *p;
Eric Andersen34506362001-08-02 05:02:46 +000011400 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011401
11402 p = single_quote(trap[signo]);
Eric Andersen34506362001-08-02 05:02:46 +000011403 sn = sys_siglist[signo];
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011404 if (sn == NULL)
Eric Andersen34506362001-08-02 05:02:46 +000011405 sn = u_signal_names(0, &signo, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011406 if (sn == NULL)
Eric Andersen34506362001-08-02 05:02:46 +000011407 sn = "???";
11408 printf("trap -- %s %s\n", p, sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011409 stunalloc(p);
11410 }
11411 }
11412 return 0;
11413 }
11414 ap = argv + 1;
11415 if (argc == 2)
11416 action = NULL;
11417 else
11418 action = *ap++;
11419 while (*ap) {
11420 if ((signo = decode_signal(*ap, 0)) < 0)
11421 error("%s: bad trap", *ap);
11422 INTOFF;
11423 if (action) {
11424 if (action[0] == '-' && action[1] == '\0')
11425 action = NULL;
11426 else
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011427 action = xstrdup(action);
Eric Andersencb57d552001-06-28 07:25:16 +000011428 }
Aaron Lehmann49c024a2002-08-02 06:39:47 +000011429 free(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000011430 trap[signo] = action;
11431 if (signo != 0)
11432 setsignal(signo);
11433 INTON;
11434 ap++;
11435 }
11436 return 0;
11437}
11438
11439
Eric Andersencb57d552001-06-28 07:25:16 +000011440/*
11441 * Set the signal handler for the specified signal. The routine figures
11442 * out what it should be set to.
11443 */
11444
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011445static void setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011446{
11447 int action;
11448 char *t;
11449 struct sigaction act;
11450
11451 if ((t = trap[signo]) == NULL)
11452 action = S_DFL;
11453 else if (*t != '\0')
11454 action = S_CATCH;
11455 else
11456 action = S_IGN;
11457 if (rootshell && action == S_DFL) {
11458 switch (signo) {
11459 case SIGINT:
11460 if (iflag || minusc || sflag == 0)
11461 action = S_CATCH;
11462 break;
11463 case SIGQUIT:
11464#ifdef DEBUG
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011465 {
Eric Andersencb57d552001-06-28 07:25:16 +000011466
11467 if (debug)
11468 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011469 }
Eric Andersencb57d552001-06-28 07:25:16 +000011470#endif
11471 /* FALLTHROUGH */
11472 case SIGTERM:
11473 if (iflag)
11474 action = S_IGN;
11475 break;
Eric Andersend35c5df2002-01-09 15:37:36 +000011476#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +000011477 case SIGTSTP:
11478 case SIGTTOU:
11479 if (mflag)
11480 action = S_IGN;
11481 break;
11482#endif
11483 }
11484 }
11485
11486 t = &sigmode[signo - 1];
11487 if (*t == 0) {
11488 /*
11489 * current setting unknown
11490 */
11491 if (sigaction(signo, 0, &act) == -1) {
11492 /*
11493 * Pretend it worked; maybe we should give a warning
11494 * here, but other shells don't. We don't alter
11495 * sigmode, so that we retry every time.
11496 */
11497 return;
11498 }
11499 if (act.sa_handler == SIG_IGN) {
11500 if (mflag && (signo == SIGTSTP ||
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011501 signo == SIGTTIN || signo == SIGTTOU)) {
11502 *t = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000011503 } else
11504 *t = S_HARD_IGN;
11505 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011506 *t = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000011507 }
11508 }
11509 if (*t == S_HARD_IGN || *t == action)
11510 return;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011511 act.sa_handler = ((action == S_CATCH) ? onsig
11512 : ((action == S_IGN) ? SIG_IGN : SIG_DFL));
Eric Andersencb57d552001-06-28 07:25:16 +000011513 *t = action;
11514 act.sa_flags = 0;
11515 sigemptyset(&act.sa_mask);
11516 sigaction(signo, &act, 0);
11517}
11518
11519/*
11520 * Ignore a signal.
11521 */
11522
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011523static void ignoresig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011524{
11525 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11526 signal(signo, SIG_IGN);
11527 }
11528 sigmode[signo - 1] = S_HARD_IGN;
11529}
11530
11531
Eric Andersencb57d552001-06-28 07:25:16 +000011532/*
11533 * Signal handler.
11534 */
11535
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011536static void onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011537{
11538 if (signo == SIGINT && trap[SIGINT] == NULL) {
11539 onint();
11540 return;
11541 }
11542 gotsig[signo - 1] = 1;
11543 pendingsigs++;
11544}
11545
11546
Eric Andersencb57d552001-06-28 07:25:16 +000011547/*
11548 * Called to execute a trap. Perhaps we should avoid entering new trap
11549 * handlers while we are executing a trap handler.
11550 */
11551
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011552static void dotrap(void)
Eric Andersen2870d962001-07-02 17:27:21 +000011553{
Eric Andersencb57d552001-06-28 07:25:16 +000011554 int i;
11555 int savestatus;
11556
11557 for (;;) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011558 for (i = 1;; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011559 if (gotsig[i - 1])
11560 break;
11561 if (i >= NSIG - 1)
11562 goto done;
11563 }
11564 gotsig[i - 1] = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011565 savestatus = exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +000011566 evalstring(trap[i], 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011567 exitstatus = savestatus;
Eric Andersencb57d552001-06-28 07:25:16 +000011568 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011569 done:
Eric Andersencb57d552001-06-28 07:25:16 +000011570 pendingsigs = 0;
11571}
11572
Eric Andersencb57d552001-06-28 07:25:16 +000011573/*
11574 * Called to exit the shell.
11575 */
11576
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011577static void exitshell(int status)
Eric Andersencb57d552001-06-28 07:25:16 +000011578{
11579 struct jmploc loc1, loc2;
11580 char *p;
11581
11582 TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
11583 if (setjmp(loc1.loc)) {
11584 goto l1;
11585 }
11586 if (setjmp(loc2.loc)) {
11587 goto l2;
11588 }
11589 handler = &loc1;
11590 if ((p = trap[0]) != NULL && *p != '\0') {
11591 trap[0] = NULL;
11592 evalstring(p, 0);
11593 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011594 l1:handler = &loc2; /* probably unnecessary */
Eric Andersencb57d552001-06-28 07:25:16 +000011595 flushall();
Eric Andersend35c5df2002-01-09 15:37:36 +000011596#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +000011597 setjobctl(0);
11598#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011599 l2:_exit(status);
Eric Andersencb57d552001-06-28 07:25:16 +000011600 /* NOTREACHED */
11601}
11602
11603static int decode_signal(const char *string, int minsig)
11604{
11605 int signo;
Eric Andersen34506362001-08-02 05:02:46 +000011606 const char *name = u_signal_names(string, &signo, minsig);
Eric Andersencb57d552001-06-28 07:25:16 +000011607
Eric Andersen34506362001-08-02 05:02:46 +000011608 return name ? signo : -1;
Eric Andersencb57d552001-06-28 07:25:16 +000011609}
Eric Andersen34506362001-08-02 05:02:46 +000011610
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011611static struct var **hashvar(const char *);
11612static void showvars(const char *, int, int);
11613static struct var **findvar(struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011614
11615/*
11616 * Initialize the varable symbol tables and import the environment
11617 */
11618
Eric Andersencb57d552001-06-28 07:25:16 +000011619/*
11620 * This routine initializes the builtin variables. It is called when the
11621 * shell is initialized and again when a shell procedure is spawned.
11622 */
11623
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011624static void initvar()
11625{
Eric Andersencb57d552001-06-28 07:25:16 +000011626 const struct varinit *ip;
11627 struct var *vp;
11628 struct var **vpp;
11629
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011630 for (ip = varinit; (vp = ip->var) != NULL; ip++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011631 if ((vp->flags & VEXPORT) == 0) {
11632 vpp = hashvar(ip->text);
11633 vp->next = *vpp;
11634 *vpp = vp;
Matt Kraaic8227632001-11-12 16:57:27 +000011635 vp->text = xstrdup(ip->text);
Eric Andersencb57d552001-06-28 07:25:16 +000011636 vp->flags = ip->flags;
11637 vp->func = ip->func;
11638 }
11639 }
Tim Riker497a8852002-04-13 05:37:10 +000011640#if !defined(CONFIG_FEATURE_COMMAND_EDITING) || !defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
Eric Andersencb57d552001-06-28 07:25:16 +000011641 /*
11642 * PS1 depends on uid
11643 */
11644 if ((vps1.flags & VEXPORT) == 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011645 vpp = hashvar("PS1=$ ");
Eric Andersencb57d552001-06-28 07:25:16 +000011646 vps1.next = *vpp;
11647 *vpp = &vps1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011648 vps1.text = xstrdup(geteuid()? "PS1=$ " : "PS1=# ");
11649 vps1.flags = VSTRFIXED | VTEXTFIXED;
Eric Andersencb57d552001-06-28 07:25:16 +000011650 }
Tim Riker497a8852002-04-13 05:37:10 +000011651#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011652}
11653
11654/*
11655 * Set the value of a variable. The flags argument is ored with the
11656 * flags of the variable. If val is NULL, the variable is unset.
11657 */
11658
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011659static void setvar(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011660{
11661 const char *p;
11662 int len;
11663 int namelen;
11664 char *nameeq;
11665 int isbad;
11666 int vallen = 0;
11667
11668 isbad = 0;
11669 p = name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011670 if (!is_name(*p))
Eric Andersencb57d552001-06-28 07:25:16 +000011671 isbad = 1;
11672 p++;
11673 for (;;) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011674 if (!is_in_name(*p)) {
Eric Andersencb57d552001-06-28 07:25:16 +000011675 if (*p == '\0' || *p == '=')
11676 break;
11677 isbad = 1;
11678 }
11679 p++;
11680 }
11681 namelen = p - name;
11682 if (isbad)
11683 error("%.*s: bad variable name", namelen, name);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011684 len = namelen + 2; /* 2 is space for '=' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +000011685 if (val == NULL) {
11686 flags |= VUNSET;
11687 } else {
11688 len += vallen = strlen(val);
11689 }
11690 INTOFF;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011691 nameeq = xmalloc(len);
Eric Andersencb57d552001-06-28 07:25:16 +000011692 memcpy(nameeq, name, namelen);
11693 nameeq[namelen] = '=';
11694 if (val) {
11695 memcpy(nameeq + namelen + 1, val, vallen + 1);
11696 } else {
11697 nameeq[namelen + 1] = '\0';
11698 }
11699 setvareq(nameeq, flags);
11700 INTON;
11701}
11702
11703
11704
11705/*
11706 * Same as setvar except that the variable and value are passed in
11707 * the first argument as name=value. Since the first argument will
11708 * be actually stored in the table, it should not be a string that
11709 * will go away.
11710 */
11711
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011712static void setvareq(char *s, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011713{
11714 struct var *vp, **vpp;
11715
11716 vpp = hashvar(s);
11717 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
11718 if ((vp = *findvar(vpp, s))) {
11719 if (vp->flags & VREADONLY) {
11720 size_t len = strchr(s, '=') - s;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011721
Eric Andersencb57d552001-06-28 07:25:16 +000011722 error("%.*s: is read only", len, s);
11723 }
11724 INTOFF;
11725
11726 if (vp->func && (flags & VNOFUNC) == 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011727 (*vp->func) (strchr(s, '=') + 1);
Eric Andersencb57d552001-06-28 07:25:16 +000011728
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011729 if ((vp->flags & (VTEXTFIXED | VSTACK)) == 0)
Aaron Lehmann49c024a2002-08-02 06:39:47 +000011730 free(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000011731
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011732 vp->flags &= ~(VTEXTFIXED | VSTACK | VUNSET);
Eric Andersencb57d552001-06-28 07:25:16 +000011733 vp->flags |= flags;
11734 vp->text = s;
11735
Eric Andersend35c5df2002-01-09 15:37:36 +000011736#ifdef CONFIG_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000011737 /*
11738 * We could roll this to a function, to handle it as
11739 * a regular variable function callback, but why bother?
11740 */
11741 if (iflag && (vp == &vmpath || (vp == &vmail && !mpathset())))
11742 chkmail(1);
Eric Andersenec074692001-10-31 11:05:49 +000011743#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011744 INTON;
11745 return;
11746 }
11747 /* not found */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011748 vp = xmalloc(sizeof(*vp));
Eric Andersencb57d552001-06-28 07:25:16 +000011749 vp->flags = flags;
11750 vp->text = s;
11751 vp->next = *vpp;
11752 vp->func = NULL;
11753 *vpp = vp;
11754}
11755
11756
11757
11758/*
11759 * Process a linked list of variable assignments.
11760 */
11761
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011762static void listsetvar(struct strlist *mylist)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011763{
Eric Andersencb57d552001-06-28 07:25:16 +000011764 struct strlist *lp;
11765
11766 INTOFF;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011767 for (lp = mylist; lp; lp = lp->next) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011768 setvareq(xstrdup(lp->text), 0);
Eric Andersencb57d552001-06-28 07:25:16 +000011769 }
11770 INTON;
11771}
11772
11773
11774
11775/*
11776 * Find the value of a variable. Returns NULL if not set.
11777 */
11778
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011779static const char *lookupvar(const char *name)
Eric Andersenec074692001-10-31 11:05:49 +000011780{
Eric Andersencb57d552001-06-28 07:25:16 +000011781 struct var *v;
11782
11783 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
11784 return strchr(v->text, '=') + 1;
11785 }
11786 return NULL;
11787}
11788
11789
11790
11791/*
11792 * Search the environment of a builtin command.
11793 */
11794
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011795static const char *bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000011796{
Eric Andersen62483552001-07-10 06:09:16 +000011797 const struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000011798
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011799 for (sp = cmdenviron; sp; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000011800 if (varequal(sp->text, name))
11801 return strchr(sp->text, '=') + 1;
11802 }
11803 return lookupvar(name);
11804}
11805
11806
11807
11808/*
11809 * Generate a list of exported variables. This routine is used to construct
11810 * the third argument to execve when executing a program.
11811 */
11812
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011813static char **environment()
11814{
Eric Andersencb57d552001-06-28 07:25:16 +000011815 int nenv;
11816 struct var **vpp;
11817 struct var *vp;
11818 char **env;
11819 char **ep;
11820
11821 nenv = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011822 for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) {
11823 for (vp = *vpp; vp; vp = vp->next)
Eric Andersencb57d552001-06-28 07:25:16 +000011824 if (vp->flags & VEXPORT)
11825 nenv++;
11826 }
11827 ep = env = stalloc((nenv + 1) * sizeof *env);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011828 for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) {
11829 for (vp = *vpp; vp; vp = vp->next)
Eric Andersencb57d552001-06-28 07:25:16 +000011830 if (vp->flags & VEXPORT)
11831 *ep++ = vp->text;
11832 }
11833 *ep = NULL;
11834 return env;
11835}
11836
11837
11838/*
Eric Andersencb57d552001-06-28 07:25:16 +000011839 * Command to list all variables which are set. Currently this command
11840 * is invoked from the set command when the set command is called without
11841 * any variables.
11842 */
11843
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011844static int showvarscmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011845{
11846 showvars(nullstr, VUNSET, VUNSET);
11847 return 0;
11848}
11849
11850
11851
11852/*
11853 * The export and readonly commands.
11854 */
11855
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011856static int exportcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011857{
11858 struct var *vp;
11859 char *name;
11860 const char *p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011861 int flag = argv[0][0] == 'r' ? VREADONLY : VEXPORT;
Eric Andersencb57d552001-06-28 07:25:16 +000011862 int pflag;
11863
11864 listsetvar(cmdenviron);
11865 pflag = (nextopt("p") == 'p');
11866 if (argc > 1 && !pflag) {
11867 while ((name = *argptr++) != NULL) {
11868 if ((p = strchr(name, '=')) != NULL) {
11869 p++;
11870 } else {
11871 if ((vp = *findvar(hashvar(name), name))) {
11872 vp->flags |= flag;
11873 goto found;
11874 }
11875 }
11876 setvar(name, p, flag);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011877 found:;
Eric Andersencb57d552001-06-28 07:25:16 +000011878 }
11879 } else {
11880 showvars(argv[0], flag, 0);
11881 }
11882 return 0;
11883}
11884
Eric Andersen34506362001-08-02 05:02:46 +000011885
Eric Andersencb57d552001-06-28 07:25:16 +000011886/*
11887 * The "local" command.
11888 */
11889
Eric Andersen2870d962001-07-02 17:27:21 +000011890/* funcnest nonzero if we are currently evaluating a function */
11891
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011892static int localcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011893{
11894 char *name;
11895
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011896 if (!funcnest)
Eric Andersencb57d552001-06-28 07:25:16 +000011897 error("Not in a function");
11898 while ((name = *argptr++) != NULL) {
11899 mklocal(name);
11900 }
11901 return 0;
11902}
11903
11904
11905/*
11906 * Make a variable a local variable. When a variable is made local, it's
11907 * value and flags are saved in a localvar structure. The saved values
11908 * will be restored when the shell function returns. We handle the name
11909 * "-" as a special case.
11910 */
11911
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011912static void mklocal(char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011913{
Eric Andersencb57d552001-06-28 07:25:16 +000011914 struct localvar *lvp;
11915 struct var **vpp;
11916 struct var *vp;
11917
11918 INTOFF;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011919 lvp = xmalloc(sizeof(struct localvar));
Eric Andersencb57d552001-06-28 07:25:16 +000011920 if (name[0] == '-' && name[1] == '\0') {
11921 char *p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011922
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011923 p = xmalloc(sizeof optet_vals);
Eric Andersen2870d962001-07-02 17:27:21 +000011924 lvp->text = memcpy(p, optet_vals, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000011925 vp = NULL;
11926 } else {
11927 vpp = hashvar(name);
11928 vp = *findvar(vpp, name);
11929 if (vp == NULL) {
11930 if (strchr(name, '='))
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011931 setvareq(xstrdup(name), VSTRFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +000011932 else
11933 setvar(name, NULL, VSTRFIXED);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011934 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000011935 lvp->text = NULL;
11936 lvp->flags = VUNSET;
11937 } else {
11938 lvp->text = vp->text;
11939 lvp->flags = vp->flags;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011940 vp->flags |= VSTRFIXED | VTEXTFIXED;
Eric Andersencb57d552001-06-28 07:25:16 +000011941 if (strchr(name, '='))
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011942 setvareq(xstrdup(name), 0);
Eric Andersencb57d552001-06-28 07:25:16 +000011943 }
11944 }
11945 lvp->vp = vp;
11946 lvp->next = localvars;
11947 localvars = lvp;
11948 INTON;
11949}
11950
11951
11952/*
11953 * Called after a function returns.
11954 */
11955
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011956static void poplocalvars()
11957{
Eric Andersencb57d552001-06-28 07:25:16 +000011958 struct localvar *lvp;
11959 struct var *vp;
11960
11961 while ((lvp = localvars) != NULL) {
11962 localvars = lvp->next;
11963 vp = lvp->vp;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011964 if (vp == NULL) { /* $- saved */
Eric Andersen2870d962001-07-02 17:27:21 +000011965 memcpy(optet_vals, lvp->text, sizeof optet_vals);
Aaron Lehmann49c024a2002-08-02 06:39:47 +000011966 free(lvp->text);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011967 } else if ((lvp->flags & (VUNSET | VSTRFIXED)) == VUNSET) {
11968 (void) unsetvar(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000011969 } else {
11970 if ((vp->flags & VTEXTFIXED) == 0)
Aaron Lehmann49c024a2002-08-02 06:39:47 +000011971 free(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000011972 vp->flags = lvp->flags;
11973 vp->text = lvp->text;
11974 }
Aaron Lehmann49c024a2002-08-02 06:39:47 +000011975 free(lvp);
Eric Andersencb57d552001-06-28 07:25:16 +000011976 }
11977}
11978
11979
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011980static int setvarcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011981{
11982 if (argc <= 2)
11983 return unsetcmd(argc, argv);
11984 else if (argc == 3)
11985 setvar(argv[1], argv[2], 0);
11986 else
11987 error("List assignment not implemented");
11988 return 0;
11989}
11990
11991
11992/*
11993 * The unset builtin command. We unset the function before we unset the
11994 * variable to allow a function to be unset when there is a readonly variable
11995 * with the same name.
11996 */
11997
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011998static int unsetcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011999{
12000 char **ap;
12001 int i;
12002 int flg_func = 0;
12003 int flg_var = 0;
12004 int ret = 0;
12005
12006 while ((i = nextopt("vf")) != '\0') {
12007 if (i == 'f')
12008 flg_func = 1;
12009 else
12010 flg_var = 1;
12011 }
12012 if (flg_func == 0 && flg_var == 0)
12013 flg_var = 1;
12014
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012015 for (ap = argptr; *ap; ap++) {
Eric Andersencb57d552001-06-28 07:25:16 +000012016 if (flg_func)
12017 unsetfunc(*ap);
12018 if (flg_var)
12019 ret |= unsetvar(*ap);
12020 }
12021 return ret;
12022}
12023
12024
12025/*
12026 * Unset the specified variable.
12027 */
12028
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012029static int unsetvar(const char *s)
Eric Andersen62483552001-07-10 06:09:16 +000012030{
Eric Andersencb57d552001-06-28 07:25:16 +000012031 struct var **vpp;
12032 struct var *vp;
12033
12034 vpp = findvar(hashvar(s), s);
12035 vp = *vpp;
12036 if (vp) {
12037 if (vp->flags & VREADONLY)
12038 return (1);
12039 INTOFF;
12040 if (*(strchr(vp->text, '=') + 1) != '\0')
12041 setvar(s, nullstr, 0);
12042 vp->flags &= ~VEXPORT;
12043 vp->flags |= VUNSET;
12044 if ((vp->flags & VSTRFIXED) == 0) {
12045 if ((vp->flags & VTEXTFIXED) == 0)
Aaron Lehmann49c024a2002-08-02 06:39:47 +000012046 free(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012047 *vpp = vp->next;
Aaron Lehmann49c024a2002-08-02 06:39:47 +000012048 free(vp);
Eric Andersencb57d552001-06-28 07:25:16 +000012049 }
12050 INTON;
12051 return (0);
12052 }
12053
12054 return (0);
12055}
12056
12057
12058
12059/*
12060 * Find the appropriate entry in the hash table from the name.
12061 */
12062
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012063static struct var **hashvar(const char *p)
Eric Andersen62483552001-07-10 06:09:16 +000012064{
Eric Andersencb57d552001-06-28 07:25:16 +000012065 unsigned int hashval;
12066
12067 hashval = ((unsigned char) *p) << 4;
12068 while (*p && *p != '=')
12069 hashval += (unsigned char) *p++;
12070 return &vartab[hashval % VTABSIZE];
12071}
12072
12073
12074
12075/*
12076 * Returns true if the two strings specify the same varable. The first
12077 * variable name is terminated by '='; the second may be terminated by
12078 * either '=' or '\0'.
12079 */
12080
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012081static int varequal(const char *p, const char *q)
Eric Andersen62483552001-07-10 06:09:16 +000012082{
Eric Andersencb57d552001-06-28 07:25:16 +000012083 while (*p == *q++) {
12084 if (*p++ == '=')
12085 return 1;
12086 }
12087 if (*p == '=' && *(q - 1) == '\0')
12088 return 1;
12089 return 0;
12090}
12091
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012092static void showvars(const char *myprefix, int mask, int xor)
Eric Andersencb57d552001-06-28 07:25:16 +000012093{
12094 struct var **vpp;
12095 struct var *vp;
12096 const char *sep = myprefix == nullstr ? myprefix : spcstr;
12097
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012098 for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) {
12099 for (vp = *vpp; vp; vp = vp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000012100 if ((vp->flags & mask) ^ xor) {
12101 char *p;
12102 int len;
12103
12104 p = strchr(vp->text, '=') + 1;
12105 len = p - vp->text;
12106 p = single_quote(p);
12107
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012108 printf("%s%s%.*s%s\n", myprefix, sep, len, vp->text, p);
Eric Andersencb57d552001-06-28 07:25:16 +000012109 stunalloc(p);
12110 }
12111 }
12112 }
12113}
12114
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012115static struct var **findvar(struct var **vpp, const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012116{
12117 for (; *vpp; vpp = &(*vpp)->next) {
12118 if (varequal((*vpp)->text, name)) {
12119 break;
12120 }
12121 }
12122 return vpp;
12123}
12124
12125/*
12126 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
12127 * This file contains code for the times builtin.
Eric Andersencb57d552001-06-28 07:25:16 +000012128 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012129static int timescmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012130{
12131 struct tms buf;
12132 long int clk_tck = sysconf(_SC_CLK_TCK);
12133
12134 times(&buf);
12135 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012136 (int) (buf.tms_utime / clk_tck / 60),
12137 ((double) buf.tms_utime) / clk_tck,
12138 (int) (buf.tms_stime / clk_tck / 60),
12139 ((double) buf.tms_stime) / clk_tck,
12140 (int) (buf.tms_cutime / clk_tck / 60),
12141 ((double) buf.tms_cutime) / clk_tck,
12142 (int) (buf.tms_cstime / clk_tck / 60),
12143 ((double) buf.tms_cstime) / clk_tck);
Eric Andersencb57d552001-06-28 07:25:16 +000012144 return 0;
12145}
12146
Eric Andersend35c5df2002-01-09 15:37:36 +000012147#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012148/* The let builtin. */
12149int letcmd(int argc, char **argv)
Eric Andersen74bcd162001-07-30 21:41:37 +000012150{
Eric Andersen34506362001-08-02 05:02:46 +000012151 int errcode;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012152 long result = 0;
12153
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012154 if (argc == 2) {
12155 char *tmp, *expression, p[13];
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012156
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012157 expression = strchr(argv[1], '=');
12158 if (!expression) {
Eric Andersen34506362001-08-02 05:02:46 +000012159 /* Cannot use 'error()' here, or the return code
12160 * will be incorrect */
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012161 out2fmt("sh: let: syntax error: \"%s\"\n", argv[1]);
12162 return 0;
Eric Andersen74bcd162001-07-30 21:41:37 +000012163 }
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012164 *expression = '\0';
12165 tmp = ++expression;
Eric Andersen34506362001-08-02 05:02:46 +000012166 result = arith(tmp, &errcode);
12167 if (errcode < 0) {
12168 /* Cannot use 'error()' here, or the return code
12169 * will be incorrect */
12170 out2fmt("sh: let: ");
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012171 if (errcode == -2)
Eric Andersen34506362001-08-02 05:02:46 +000012172 out2fmt("divide by zero");
12173 else
12174 out2fmt("syntax error: \"%s=%s\"\n", argv[1], expression);
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012175 return 0;
12176 }
12177 snprintf(p, 12, "%ld", result);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012178 setvar(argv[1], xstrdup(p), 0);
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012179 } else if (argc >= 3)
12180 synerror("invalid operand");
12181 return !result;
Eric Andersen74bcd162001-07-30 21:41:37 +000012182}
12183#endif
12184
12185
12186
Eric Andersendf82f612001-06-28 07:46:40 +000012187/*-
12188 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000012189 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000012190 *
12191 * This code is derived from software contributed to Berkeley by
12192 * Kenneth Almquist.
12193 *
12194 * Redistribution and use in source and binary forms, with or without
12195 * modification, are permitted provided that the following conditions
12196 * are met:
12197 * 1. Redistributions of source code must retain the above copyright
12198 * notice, this list of conditions and the following disclaimer.
12199 * 2. Redistributions in binary form must reproduce the above copyright
12200 * notice, this list of conditions and the following disclaimer in the
12201 * documentation and/or other materials provided with the distribution.
12202 *
Eric Andersen2870d962001-07-02 17:27:21 +000012203 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
12204 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000012205 *
12206 * 4. Neither the name of the University nor the names of its contributors
12207 * may be used to endorse or promote products derived from this software
12208 * without specific prior written permission.
12209 *
12210 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
12211 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
12212 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
12213 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
12214 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
12215 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
12216 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
12217 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
12218 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
12219 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
12220 * SUCH DAMAGE.
12221 */