blob: c1603d79046656c36f1e43837627f1cb04103273 [file] [log] [blame]
Eric Andersendf82f612001-06-28 07:46:40 +00001/* vi: set sw=4 ts=4: */
2/*
3 * ash shell port for busybox
4 *
5 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +00006 * The Regents of the University of California. All rights reserved.
Eric Andersencb57d552001-06-28 07:25:16 +00007 *
8 * This code is derived from software contributed to Berkeley by
9 * Kenneth Almquist.
10 *
Eric Andersendf82f612001-06-28 07:46:40 +000011 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
Eric Andersencb57d552001-06-28 07:25:16 +000015 *
Eric Andersendf82f612001-06-28 07:46:40 +000016 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
Eric Andersen2870d962001-07-02 17:27:21 +000025 * This version of ash is adapted from the source in Debian's ash 0.3.8-5
26 * package.
Eric Andersendf82f612001-06-28 07:46:40 +000027 *
Eric Andersen2870d962001-07-02 17:27:21 +000028 * Modified by Erik Andersen <andersee@debian.org> and
Eric Andersen7467c8d2001-07-12 20:26:32 +000029 * Vladimir Oleynik <dzo@simtreas.ru> to be used in busybox
Eric Andersen2870d962001-07-02 17:27:21 +000030 *
Eric Andersendf82f612001-06-28 07:46:40 +000031 *
32 * Original copyright notice is retained at the end of this file.
Eric Andersencb57d552001-06-28 07:25:16 +000033 */
34
Eric Andersen2870d962001-07-02 17:27:21 +000035
36/* These defines allow you to adjust the feature set to be compiled
37 * into the ash shell. As a rule, enabling these options will make
38 * ash get bigger... With all of these options off, ash adds about
Eric Andersen62483552001-07-10 06:09:16 +000039 * 60k to busybox on an x86 system.*/
Eric Andersen2870d962001-07-02 17:27:21 +000040
41
42/* Enable job control. This allows you to run jobs in the background,
43 * which is great when ash is being used as an interactive shell, but
Eric Andersen3102ac42001-07-06 04:26:23 +000044 * it completely useless for is all you are doing is running scripts.
Eric Andersen2870d962001-07-02 17:27:21 +000045 * This adds about 2.5k on an x86 system. */
Eric Andersen62483552001-07-10 06:09:16 +000046#undef JOBS
Eric Andersen2870d962001-07-02 17:27:21 +000047
48/* This enables alias support in ash. If you want to support things
49 * like "alias ls='ls -l'" with ash, enable this. This is only useful
50 * when ash is used as an intractive shell. This adds about 1.5k */
51#define ASH_ALIAS
52
53/* If you need ash to act as a full Posix shell, with full math
Eric Andersen74bcd162001-07-30 21:41:37 +000054 * support, enable this. This adds a bit over 2k an x86 system. */
Eric Andersen34506362001-08-02 05:02:46 +000055//#undef ASH_MATH_SUPPORT
Eric Andersen74bcd162001-07-30 21:41:37 +000056#define ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +000057
Eric Andersen2870d962001-07-02 17:27:21 +000058/* Getopts is used by shell procedures to parse positional parameters.
59 * You probably want to leave this disabled, and use the busybox getopt
60 * applet if you want to do this sort of thing. There are some scripts
Manuel Novoa III 16815d42001-08-10 19:36:07 +000061 * out there that use it, so it you need it, enable. Most people will
Eric Andersen2870d962001-07-02 17:27:21 +000062 * leave this disabled. This adds 1k on an x86 system. */
63#undef ASH_GETOPTS
64
65/* This allows you to override shell builtins and use whatever is on
66 * the filesystem. This is most useful when ash is acting as a
Eric Andersen62483552001-07-10 06:09:16 +000067 * standalone shell. Adds about 272 bytes. */
Eric Andersen2870d962001-07-02 17:27:21 +000068#undef ASH_CMDCMD
69
Eric Andersenec074692001-10-31 11:05:49 +000070/* Check for new mail on interactive shells? */
71#undef ASH_MAIL
Eric Andersen2870d962001-07-02 17:27:21 +000072
Eric Andersen3102ac42001-07-06 04:26:23 +000073/* Optimize size vs speed as size */
74#define ASH_OPTIMIZE_FOR_SIZE
75
Eric Andersen2870d962001-07-02 17:27:21 +000076/* Enable this to compile in extra debugging noise. When debugging is
77 * on, debugging info will be written to $HOME/trace and a quit signal
78 * will generate a core dump. */
79#undef DEBUG
80
Eric Andersen2870d962001-07-02 17:27:21 +000081/* These are here to work with glibc -- Don't change these... */
Eric Andersendf82f612001-06-28 07:46:40 +000082#undef FNMATCH_BROKEN
83#undef GLOB_BROKEN
Eric Andersen5bb16772001-09-06 18:00:41 +000084#define IFS_BROKEN
Eric Andersencb57d552001-06-28 07:25:16 +000085
86#include <assert.h>
Manuel Novoa III 16815d42001-08-10 19:36:07 +000087#include <stddef.h>
Eric Andersencb57d552001-06-28 07:25:16 +000088#include <ctype.h>
89#include <dirent.h>
90#include <errno.h>
91#include <fcntl.h>
92#include <limits.h>
93#include <paths.h>
Eric Andersencb57d552001-06-28 07:25:16 +000094#include <setjmp.h>
95#include <signal.h>
96#include <stdarg.h>
Eric Andersencb57d552001-06-28 07:25:16 +000097#include <stdio.h>
98#include <stdlib.h>
99#include <string.h>
100#include <sysexits.h>
101#include <unistd.h>
102#include <sys/stat.h>
103#include <sys/cdefs.h>
104#include <sys/ioctl.h>
105#include <sys/param.h>
106#include <sys/resource.h>
107#include <sys/time.h>
108#include <sys/times.h>
109#include <sys/types.h>
110#include <sys/wait.h>
Eric Andersen1a10eec2001-10-24 17:19:38 +0000111#include "pwd.h"
Eric Andersencb57d552001-06-28 07:25:16 +0000112
113
114#if !defined(FNMATCH_BROKEN)
115#include <fnmatch.h>
116#endif
117#if !defined(GLOB_BROKEN)
118#include <glob.h>
119#endif
120
Eric Andersen2870d962001-07-02 17:27:21 +0000121#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +0000122#include <termios.h>
Eric Andersencb57d552001-06-28 07:25:16 +0000123#endif
124
Eric Andersencb57d552001-06-28 07:25:16 +0000125#include "busybox.h"
Eric Andersen2870d962001-07-02 17:27:21 +0000126#include "cmdedit.h"
127
Eric Andersen2870d962001-07-02 17:27:21 +0000128/*
129 * This file was generated by the mksyntax program.
130 */
131
132/* Syntax classes */
133#define CWORD 0 /* character is nothing special */
134#define CNL 1 /* newline character */
135#define CBACK 2 /* a backslash character */
136#define CSQUOTE 3 /* single quote */
137#define CDQUOTE 4 /* double quote */
138#define CENDQUOTE 5 /* a terminating quote */
139#define CBQUOTE 6 /* backwards single quote */
140#define CVAR 7 /* a dollar sign */
141#define CENDVAR 8 /* a '}' character */
142#define CLP 9 /* a left paren in arithmetic */
143#define CRP 10 /* a right paren in arithmetic */
144#define CENDFILE 11 /* end of file */
145#define CCTL 12 /* like CWORD, except it must be escaped */
146#define CSPCL 13 /* these terminate a word */
147#define CIGN 14 /* character should be ignored */
148
Eric Andersen2870d962001-07-02 17:27:21 +0000149#define SYNBASE 130
150#define PEOF -130
151
152#define PEOA -129
153
154#define TEOF 0
155#define TNL 1
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000156#define TREDIR 2
157#define TWORD 3
158#define TASSIGN 4
159#define TSEMI 5
160#define TBACKGND 6
161#define TAND 7
162#define TOR 8
163#define TPIPE 9
164#define TLP 10
165#define TRP 11
166#define TENDCASE 12
167#define TENDBQUOTE 13
Eric Andersen2870d962001-07-02 17:27:21 +0000168#define TNOT 14
169#define TCASE 15
170#define TDO 16
171#define TDONE 17
172#define TELIF 18
173#define TELSE 19
174#define TESAC 20
175#define TFI 21
176#define TFOR 22
177#define TIF 23
178#define TIN 24
179#define TTHEN 25
180#define TUNTIL 26
181#define TWHILE 27
182#define TBEGIN 28
183#define TEND 29
184
185
Eric Andersen2870d962001-07-02 17:27:21 +0000186
187/* control characters in argument strings */
188#define CTLESC '\201'
189#define CTLVAR '\202'
190#define CTLENDVAR '\203'
191#define CTLBACKQ '\204'
192#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
193/* CTLBACKQ | CTLQUOTE == '\205' */
194#define CTLARI '\206'
195#define CTLENDARI '\207'
196#define CTLQUOTEMARK '\210'
197
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000198
Eric Andersen62483552001-07-10 06:09:16 +0000199#define is_digit(c) ((c)>='0' && (c)<='9')
Eric Andersen2870d962001-07-02 17:27:21 +0000200#define is_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalpha((unsigned char) (c))))
201#define is_in_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalnum((unsigned char) (c))))
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000202
203/*
204 * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
205 * (assuming ascii char codes, as the original implementation did)
206 */
207#define is_special(c) \
208 ( (((unsigned int)c) - 33 < 32) \
209 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
210
Eric Andersen2870d962001-07-02 17:27:21 +0000211#define digit_val(c) ((c) - '0')
Eric Andersencb57d552001-06-28 07:25:16 +0000212
213
214#define _DIAGASSERT(x)
215
Eric Andersen3102ac42001-07-06 04:26:23 +0000216
Eric Andersencb57d552001-06-28 07:25:16 +0000217
Eric Andersen2870d962001-07-02 17:27:21 +0000218#define S_DFL 1 /* default signal handling (SIG_DFL) */
219#define S_CATCH 2 /* signal is caught */
220#define S_IGN 3 /* signal is ignored (SIG_IGN) */
221#define S_HARD_IGN 4 /* signal is ignored permenantly */
222#define S_RESET 5 /* temporary - to reset a hard ignored sig */
Eric Andersencb57d552001-06-28 07:25:16 +0000223
224
Eric Andersen2870d962001-07-02 17:27:21 +0000225/* variable substitution byte (follows CTLVAR) */
226#define VSTYPE 0x0f /* type of variable substitution */
227#define VSNUL 0x10 /* colon--treat the empty string as unset */
228#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
Eric Andersencb57d552001-06-28 07:25:16 +0000229
Eric Andersen2870d962001-07-02 17:27:21 +0000230/* values of VSTYPE field */
231#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
232#define VSMINUS 0x2 /* ${var-text} */
233#define VSPLUS 0x3 /* ${var+text} */
234#define VSQUESTION 0x4 /* ${var?message} */
235#define VSASSIGN 0x5 /* ${var=text} */
236#define VSTRIMLEFT 0x6 /* ${var#pattern} */
237#define VSTRIMLEFTMAX 0x7 /* ${var##pattern} */
238#define VSTRIMRIGHT 0x8 /* ${var%pattern} */
239#define VSTRIMRIGHTMAX 0x9 /* ${var%%pattern} */
240#define VSLENGTH 0xa /* ${#var} */
Eric Andersencb57d552001-06-28 07:25:16 +0000241
Eric Andersen2870d962001-07-02 17:27:21 +0000242/* flags passed to redirect */
243#define REDIR_PUSH 01 /* save previous values of file descriptors */
Eric Andersen3102ac42001-07-06 04:26:23 +0000244#define REDIR_BACKQ 02 /* save the command output to pipe */
Eric Andersencb57d552001-06-28 07:25:16 +0000245
Eric Andersen2870d962001-07-02 17:27:21 +0000246/*
247 * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
248 * so we use _setjmp instead.
249 */
250
Eric Andersen62483552001-07-10 06:09:16 +0000251#if defined(BSD)
Eric Andersen2870d962001-07-02 17:27:21 +0000252#define setjmp(jmploc) _setjmp(jmploc)
253#define longjmp(jmploc, val) _longjmp(jmploc, val)
254#endif
255
256/*
257 * Most machines require the value returned from malloc to be aligned
258 * in some way. The following macro will get this right on many machines.
259 */
260
261#ifndef ALIGN
262union align {
263 int i;
264 char *cp;
265};
266
267#define ALIGN(nbytes) (((nbytes) + sizeof(union align) - 1) & ~(sizeof(union align) - 1))
268#endif
269
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000270#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +0000271#include <locale.h>
272static void change_lc_all(const char *value);
273static void change_lc_ctype(const char *value);
274#endif
275
276/*
277 * These macros allow the user to suspend the handling of interrupt signals
278 * over a period of time. This is similar to SIGHOLD to or sigblock, but
279 * much more efficient and portable. (But hacking the kernel is so much
280 * more fun than worrying about efficiency and portability. :-))
281 */
282
283static void onint (void);
284static volatile int suppressint;
285static volatile int intpending;
286
287#define INTOFF suppressint++
Eric Andersen3102ac42001-07-06 04:26:23 +0000288#ifndef ASH_OPTIMIZE_FOR_SIZE
Eric Andersen2870d962001-07-02 17:27:21 +0000289#define INTON { if (--suppressint == 0 && intpending) onint(); }
Eric Andersen3102ac42001-07-06 04:26:23 +0000290#define FORCEINTON {suppressint = 0; if (intpending) onint();}
Eric Andersen2870d962001-07-02 17:27:21 +0000291#else
292static void __inton (void);
Eric Andersen3102ac42001-07-06 04:26:23 +0000293static void forceinton (void);
Eric Andersen2870d962001-07-02 17:27:21 +0000294#define INTON __inton()
Eric Andersen3102ac42001-07-06 04:26:23 +0000295#define FORCEINTON forceinton()
Eric Andersen2870d962001-07-02 17:27:21 +0000296#endif
Eric Andersen3102ac42001-07-06 04:26:23 +0000297
Eric Andersen2870d962001-07-02 17:27:21 +0000298#define CLEAR_PENDING_INT intpending = 0
299#define int_pending() intpending
300
301
302typedef void *pointer;
303#ifndef NULL
304#define NULL (void *)0
305#endif
306
307static inline pointer ckmalloc (int sz) { return xmalloc(sz); }
308static inline pointer ckrealloc(void *p, int sz) { return xrealloc(p, sz); }
309static inline char * savestr (const char *s) { return xstrdup(s); }
310
311static pointer stalloc (int);
312static void stunalloc (pointer);
313static void ungrabstackstr (char *, char *);
314static char * growstackstr(void);
Eric Andersen3102ac42001-07-06 04:26:23 +0000315static char * makestrspace(size_t newlen);
Eric Andersen2870d962001-07-02 17:27:21 +0000316static char *sstrdup (const char *);
317
318/*
319 * Parse trees for commands are allocated in lifo order, so we use a stack
320 * to make this more efficient, and also to avoid all sorts of exception
321 * handling code to handle interrupts in the middle of a parse.
322 *
323 * The size 504 was chosen because the Ultrix malloc handles that size
324 * well.
325 */
326
327#define MINSIZE 504 /* minimum size of a block */
328
329
330struct stack_block {
331 struct stack_block *prev;
332 char space[MINSIZE];
333};
334
335static struct stack_block stackbase;
336static struct stack_block *stackp = &stackbase;
337static struct stackmark *markp;
338static char *stacknxt = stackbase.space;
339static int stacknleft = MINSIZE;
340
341
342#define equal(s1, s2) (strcmp(s1, s2) == 0)
343
344#define stackblock() stacknxt
345#define stackblocksize() stacknleft
346#define STARTSTACKSTR(p) p = stackblock(), sstrnleft = stackblocksize()
Eric Andersen3102ac42001-07-06 04:26:23 +0000347
Eric Andersen2870d962001-07-02 17:27:21 +0000348#define STPUTC(c, p) (--sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(), *p++ = (c)))
349#define CHECKSTRSPACE(n, p) { if (sstrnleft < n) p = makestrspace(n); }
Eric Andersen2870d962001-07-02 17:27:21 +0000350#define STACKSTRNUL(p) (sstrnleft == 0? (p = growstackstr(), *p = '\0') : (*p = '\0'))
Eric Andersen3102ac42001-07-06 04:26:23 +0000351
352
353#define USTPUTC(c, p) (--sstrnleft, *p++ = (c))
Eric Andersen2870d962001-07-02 17:27:21 +0000354#define STUNPUTC(p) (++sstrnleft, --p)
355#define STTOPC(p) p[-1]
356#define STADJUST(amount, p) (p += (amount), sstrnleft -= (amount))
357#define grabstackstr(p) stalloc(stackblocksize() - sstrnleft)
358
359#define ckfree(p) free((pointer)(p))
360
Eric Andersen2870d962001-07-02 17:27:21 +0000361
362#ifdef DEBUG
363#define TRACE(param) trace param
Eric Andersen69a20f02001-10-31 10:40:37 +0000364typedef union node unode;
Eric Andersen2870d962001-07-02 17:27:21 +0000365static void trace (const char *, ...);
366static void trargs (char **);
Eric Andersen69a20f02001-10-31 10:40:37 +0000367static void showtree (unode *);
Eric Andersen2870d962001-07-02 17:27:21 +0000368static void trputc (int);
369static void trputs (const char *);
370static void opentrace (void);
371#else
372#define TRACE(param)
373#endif
374
375#define NSEMI 0
376#define NCMD 1
377#define NPIPE 2
378#define NREDIR 3
379#define NBACKGND 4
380#define NSUBSHELL 5
381#define NAND 6
382#define NOR 7
383#define NIF 8
384#define NWHILE 9
385#define NUNTIL 10
386#define NFOR 11
387#define NCASE 12
388#define NCLIST 13
389#define NDEFUN 14
390#define NARG 15
391#define NTO 16
392#define NFROM 17
393#define NFROMTO 18
394#define NAPPEND 19
395#define NTOOV 20
396#define NTOFD 21
397#define NFROMFD 22
398#define NHERE 23
399#define NXHERE 24
400#define NNOT 25
401
402/*
403 * expandarg() flags
404 */
405#define EXP_FULL 0x1 /* perform word splitting & file globbing */
406#define EXP_TILDE 0x2 /* do normal tilde expansion */
407#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
408#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
409#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
410#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
411
412
413#define NOPTS 16
414
415static char optet_vals[NOPTS];
416
417static const char * const optlist[NOPTS] = {
418 "e" "errexit",
419 "f" "noglob",
420 "I" "ignoreeof",
421 "i" "interactive",
422 "m" "monitor",
423 "n" "noexec",
424 "s" "stdin",
425 "x" "xtrace",
426 "v" "verbose",
427 "V" "vi",
428 "E" "emacs",
429 "C" "noclobber",
430 "a" "allexport",
431 "b" "notify",
432 "u" "nounset",
433 "q" "quietprofile"
434};
435
436#define optent_name(optent) (optent+1)
437#define optent_letter(optent) optent[0]
438#define optent_val(optent) optet_vals[optent]
439
440#define eflag optent_val(0)
441#define fflag optent_val(1)
442#define Iflag optent_val(2)
443#define iflag optent_val(3)
444#define mflag optent_val(4)
445#define nflag optent_val(5)
446#define sflag optent_val(6)
447#define xflag optent_val(7)
448#define vflag optent_val(8)
449#define Vflag optent_val(9)
450#define Eflag optent_val(10)
451#define Cflag optent_val(11)
452#define aflag optent_val(12)
453#define bflag optent_val(13)
454#define uflag optent_val(14)
455#define qflag optent_val(15)
456
457
458/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
459#define FORK_FG 0
460#define FORK_BG 1
461#define FORK_NOJOB 2
462
463
464struct nbinary {
465 int type;
466 union node *ch1;
467 union node *ch2;
468};
469
470
471struct ncmd {
472 int type;
473 int backgnd;
474 union node *assign;
475 union node *args;
476 union node *redirect;
477};
478
479
480struct npipe {
481 int type;
482 int backgnd;
483 struct nodelist *cmdlist;
484};
485
486
487struct nredir {
488 int type;
489 union node *n;
490 union node *redirect;
491};
492
493
494struct nif {
495 int type;
496 union node *test;
497 union node *ifpart;
498 union node *elsepart;
499};
500
501
502struct nfor {
503 int type;
504 union node *args;
505 union node *body;
506 char *var;
507};
508
509
510struct ncase {
511 int type;
512 union node *expr;
513 union node *cases;
514};
515
516
517struct nclist {
518 int type;
519 union node *next;
520 union node *pattern;
521 union node *body;
522};
523
524
525struct narg {
526 int type;
527 union node *next;
528 char *text;
529 struct nodelist *backquote;
530};
531
532
533struct nfile {
534 int type;
535 union node *next;
536 int fd;
537 union node *fname;
538 char *expfname;
539};
540
541
542struct ndup {
543 int type;
544 union node *next;
545 int fd;
546 int dupfd;
547 union node *vname;
548};
549
550
551struct nhere {
552 int type;
553 union node *next;
554 int fd;
555 union node *doc;
556};
557
558
559struct nnot {
560 int type;
561 union node *com;
562};
563
564
565union node {
566 int type;
567 struct nbinary nbinary;
568 struct ncmd ncmd;
569 struct npipe npipe;
570 struct nredir nredir;
571 struct nif nif;
572 struct nfor nfor;
573 struct ncase ncase;
574 struct nclist nclist;
575 struct narg narg;
576 struct nfile nfile;
577 struct ndup ndup;
578 struct nhere nhere;
579 struct nnot nnot;
580};
581
582
583struct nodelist {
584 struct nodelist *next;
585 union node *n;
586};
587
588struct backcmd { /* result of evalbackcmd */
589 int fd; /* file descriptor to read from */
590 char *buf; /* buffer */
591 int nleft; /* number of chars in buffer */
592 struct job *jp; /* job structure for command */
593};
594
595struct cmdentry {
596 int cmdtype;
597 union param {
598 int index;
599 union node *func;
600 const struct builtincmd *cmd;
601 } u;
602};
603
604struct strlist {
605 struct strlist *next;
606 char *text;
607};
608
609
610struct arglist {
611 struct strlist *list;
612 struct strlist **lastp;
613};
614
615struct strpush {
616 struct strpush *prev; /* preceding string on stack */
617 char *prevstring;
618 int prevnleft;
619#ifdef ASH_ALIAS
620 struct alias *ap; /* if push was associated with an alias */
621#endif
622 char *string; /* remember the string since it may change */
623};
624
625struct parsefile {
626 struct parsefile *prev; /* preceding file on stack */
627 int linno; /* current line */
628 int fd; /* file descriptor (or -1 if string) */
629 int nleft; /* number of chars left in this line */
630 int lleft; /* number of chars left in this buffer */
631 char *nextc; /* next char in buffer */
632 char *buf; /* input buffer */
633 struct strpush *strpush; /* for pushing strings at this level */
634 struct strpush basestrpush; /* so pushing one is fast */
635};
636
637struct stackmark {
638 struct stack_block *stackp;
639 char *stacknxt;
640 int stacknleft;
641 struct stackmark *marknext;
642};
643
644struct shparam {
645 int nparam; /* # of positional parameters (without $0) */
646 unsigned char malloc; /* if parameter list dynamically allocated */
647 char **p; /* parameter list */
648 int optind; /* next parameter to be processed by getopts */
649 int optoff; /* used by getopts */
650};
651
Eric Andersen62483552001-07-10 06:09:16 +0000652/*
653 * When commands are first encountered, they are entered in a hash table.
654 * This ensures that a full path search will not have to be done for them
655 * on each invocation.
656 *
657 * We should investigate converting to a linear search, even though that
658 * would make the command name "hash" a misnomer.
659 */
660#define CMDTABLESIZE 31 /* should be prime */
661#define ARB 1 /* actual size determined at run time */
662
663
664
665struct tblentry {
666 struct tblentry *next; /* next entry in hash chain */
667 union param param; /* definition of builtin function */
668 short cmdtype; /* index identifying command */
669 char rehash; /* if set, cd done since entry created */
670 char cmdname[ARB]; /* name of command */
671};
672
673
674static struct tblentry *cmdtable[CMDTABLESIZE];
675static int builtinloc = -1; /* index in path of %builtin, or -1 */
676static int exerrno = 0; /* Last exec error */
677
678
679static void tryexec (char *, char **, char **);
680static void printentry (struct tblentry *, int);
681static void clearcmdentry (int);
682static struct tblentry *cmdlookup (const char *, int);
683static void delete_cmd_entry (void);
684static int path_change (const char *, int *);
685
686
Eric Andersen2870d962001-07-02 17:27:21 +0000687static void flushall (void);
Eric Andersen3102ac42001-07-06 04:26:23 +0000688static void out2fmt (const char *, ...)
689 __attribute__((__format__(__printf__,1,2)));
Eric Andersen2870d962001-07-02 17:27:21 +0000690static int xwrite (int, const char *, int);
Eric Andersen2870d962001-07-02 17:27:21 +0000691
Manuel Novoa III c639a352001-08-12 17:32:56 +0000692static inline void outstr (const char *p, FILE *file) { fputs(p, file); }
Eric Andersen3102ac42001-07-06 04:26:23 +0000693static void out1str(const char *p) { outstr(p, stdout); }
694static void out2str(const char *p) { outstr(p, stderr); }
Eric Andersen2870d962001-07-02 17:27:21 +0000695
Eric Andersen62483552001-07-10 06:09:16 +0000696#ifndef ASH_OPTIMIZE_FOR_SIZE
Eric Andersen3102ac42001-07-06 04:26:23 +0000697#define out2c(c) putc((c), stderr)
Eric Andersen62483552001-07-10 06:09:16 +0000698#else
699static void out2c(int c) { putc(c, stderr); }
700#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000701
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000702
703#ifdef ASH_OPTIMIZE_FOR_SIZE
704#define USE_SIT_FUNCTION
705#endif
706
707/* number syntax index */
708#define BASESYNTAX 0 /* not in quotes */
709#define DQSYNTAX 1 /* in double quotes */
710#define SQSYNTAX 2 /* in single quotes */
711#define ARISYNTAX 3 /* in arithmetic */
712
713static const char S_I_T[][4] = {
714 /* 0 */ { CSPCL, CIGN, CIGN, CIGN }, /* PEOA */
715 /* 1 */ { CSPCL, CWORD, CWORD, CWORD }, /* ' ' */
716 /* 2 */ { CNL, CNL, CNL, CNL }, /* \n */
717 /* 3 */ { CWORD, CCTL, CCTL, CWORD }, /* !*-/:=?[]~ */
718 /* 4 */ { CDQUOTE, CENDQUOTE, CWORD, CDQUOTE }, /* '"' */
719 /* 5 */ { CVAR, CVAR, CWORD, CVAR }, /* $ */
720 /* 6 */ { CSQUOTE, CWORD, CENDQUOTE, CSQUOTE }, /* "'" */
721 /* 7 */ { CSPCL, CWORD, CWORD, CLP }, /* ( */
722 /* 8 */ { CSPCL, CWORD, CWORD, CRP }, /* ) */
723 /* 9 */ { CBACK, CBACK, CCTL, CBACK }, /* \ */
724 /* 10 */ { CBQUOTE, CBQUOTE, CWORD, CBQUOTE }, /* ` */
725 /* 11 */ { CENDVAR, CENDVAR, CWORD, CENDVAR }, /* } */
726#ifndef USE_SIT_FUNCTION
727 /* 12 */ { CENDFILE, CENDFILE, CENDFILE, CENDFILE }, /* PEOF */
728 /* 13 */ { CWORD, CWORD, CWORD, CWORD }, /* 0-9A-Za-z */
729 /* 14 */ { CCTL, CCTL, CCTL, CCTL } /* CTLESC ... */
730#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000731};
732
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000733#ifdef USE_SIT_FUNCTION
734
735#define U_C(c) ((unsigned char)(c))
736
737static int SIT(int c, int syntax)
738{
739 static const char spec_symbls[]="\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
740 static const char syntax_index_table [] = {
741 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
742 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
743 3, 1, 3, 3, 9, 3,10, 1, /* "=>?[\\]`|" */
744 11,3 }; /* "}~" */
745 const char *s;
746 int indx;
747
748 if(c==PEOF) /* 2^8+2 */
749 return CENDFILE;
750 if(c==PEOA) /* 2^8+1 */
751 indx = 0;
752 else if(U_C(c)>=U_C(CTLESC) && U_C(c)<=U_C(CTLQUOTEMARK))
753 return CCTL;
754 else {
755 s = strchr(spec_symbls, c);
756 if(s==0)
757 return CWORD;
758 indx = syntax_index_table[(s-spec_symbls)];
759 }
760 return S_I_T[indx][syntax];
761}
762
763#else /* USE_SIT_FUNCTION */
764
765#define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
766
767#define CSPCL_CIGN_CIGN_CIGN 0
768#define CSPCL_CWORD_CWORD_CWORD 1
769#define CNL_CNL_CNL_CNL 2
770#define CWORD_CCTL_CCTL_CWORD 3
771#define CDQUOTE_CENDQUOTE_CWORD_CDQUOTE 4
772#define CVAR_CVAR_CWORD_CVAR 5
773#define CSQUOTE_CWORD_CENDQUOTE_CSQUOTE 6
774#define CSPCL_CWORD_CWORD_CLP 7
775#define CSPCL_CWORD_CWORD_CRP 8
776#define CBACK_CBACK_CCTL_CBACK 9
777#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
778#define CENDVAR_CENDVAR_CWORD_CENDVAR 11
779#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
780#define CWORD_CWORD_CWORD_CWORD 13
781#define CCTL_CCTL_CCTL_CCTL 14
782
783static const char syntax_index_table[258] = {
784 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
785 /* 0 -130 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
786 /* 1 -129 PEOA */ CSPCL_CIGN_CIGN_CIGN,
787 /* 2 -128 0xff */ CWORD_CWORD_CWORD_CWORD,
788 /* 3 -127 */ CCTL_CCTL_CCTL_CCTL, /* CTLQUOTEMARK */
789 /* 4 -126 */ CCTL_CCTL_CCTL_CCTL,
790 /* 5 -125 */ CCTL_CCTL_CCTL_CCTL,
791 /* 6 -124 */ CCTL_CCTL_CCTL_CCTL,
792 /* 7 -123 */ CCTL_CCTL_CCTL_CCTL,
793 /* 8 -122 */ CCTL_CCTL_CCTL_CCTL,
794 /* 9 -121 */ CCTL_CCTL_CCTL_CCTL,
795 /* 10 -120 */ CCTL_CCTL_CCTL_CCTL, /* CTLESC */
796 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
797 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
798 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
799 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
800 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
801 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
802 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
803 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
804 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
805 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
806 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
807 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
808 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
809 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
810 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
811 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
812 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
813 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
814 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
815 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
816 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
817 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
818 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
819 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
820 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
821 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
822 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
823 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
824 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
825 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
826 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
827 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
828 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
829 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
830 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
831 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
832 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
833 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
834 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
835 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
836 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
837 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
838 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
839 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
840 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
841 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
842 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
843 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
844 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
845 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
846 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
847 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
848 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
849 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
850 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
851 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
852 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
853 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
854 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
855 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
856 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
857 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
858 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
859 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
860 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
861 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
862 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
863 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
864 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
865 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
866 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
867 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
868 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
869 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
870 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
871 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
872 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
873 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
874 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
875 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
876 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
877 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
878 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
879 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
880 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
881 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
882 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
883 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
884 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
885 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
886 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
887 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
888 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
889 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
890 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
891 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
892 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
893 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
894 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
895 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
896 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
897 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
898 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
899 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
900 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
901 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
902 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
903 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
904 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
905 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
906 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
907 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
908 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
909 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
910 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
911 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
912 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
913 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
914 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
915 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
916 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
917 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
918 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
919 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
920 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
921 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
922 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
923 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
924 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
925 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
926 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
927 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
928 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
929 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
930 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
931 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
932 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
933 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
934 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
935 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
936 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
937 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
938 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
939 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
940 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
941 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
942 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
943 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
944 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
945 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
946 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
947 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
948 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
949 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CDQUOTE,
950 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
951 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
952 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
953 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
954 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CSQUOTE,
955 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
956 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
957 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
958 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
959 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
960 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
961 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
962 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
963 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
964 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
965 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
966 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
967 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
968 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
969 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
970 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
971 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
972 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
973 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
974 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
975 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
976 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
977 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
978 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
979 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
980 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
981 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
982 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
983 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
984 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
985 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
986 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
987 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
988 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
989 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
990 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
991 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
992 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
993 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
994 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
995 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
996 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
997 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
998 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
999 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
1000 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
1001 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
1002 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
1003 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
1004 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
1005 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
1006 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
1007 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
1008 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
1009 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
1010 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
1011 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
1012 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
1013 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
1014 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
1015 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
1016 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
1017 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
1018 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
1019 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
1020 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
1021 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
1022 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
1023 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
1024 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
1025 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
1026 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
1027 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
1028 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
1029 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
1030 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
1031 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
1032 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
1033 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
1034 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
1035 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
1036 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
1037 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
1038 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
1039 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
1040 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
1041 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
1042 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
Eric Andersen2870d962001-07-02 17:27:21 +00001043};
1044
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001045#endif /* USE_SIT_FUNCTION */
Eric Andersen2870d962001-07-02 17:27:21 +00001046
Eric Andersen2870d962001-07-02 17:27:21 +00001047
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001048/* first char is indicating which tokens mark the end of a list */
1049static const char *const tokname_array[] = {
1050 "\1end of file",
1051 "\0newline",
1052 "\0redirection",
1053 "\0word",
1054 "\0assignment",
1055 "\0;",
1056 "\0&",
1057 "\0&&",
1058 "\0||",
1059 "\0|",
1060 "\0(",
1061 "\1)",
1062 "\1;;",
1063 "\1`",
Eric Andersen2870d962001-07-02 17:27:21 +00001064#define KWDOFFSET 14
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001065 /* the following are keywords */
1066 "\0!",
1067 "\0case",
1068 "\1do",
1069 "\1done",
1070 "\1elif",
1071 "\1else",
1072 "\1esac",
1073 "\1fi",
1074 "\0for",
1075 "\0if",
1076 "\0in",
1077 "\1then",
1078 "\0until",
1079 "\0while",
1080 "\0{",
1081 "\1}",
Eric Andersen2870d962001-07-02 17:27:21 +00001082};
1083
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001084static const char *tokname(int tok)
1085{
1086 static char buf[16];
1087
1088 if(tok>=TSEMI)
1089 buf[0] = '"';
1090 sprintf(buf+(tok>=TSEMI), "%s%c",
1091 tokname_array[tok]+1, (tok>=TSEMI ? '"' : 0));
1092 return buf;
1093}
Eric Andersen2870d962001-07-02 17:27:21 +00001094
1095static int plinno = 1; /* input line number */
1096
1097static int parselleft; /* copy of parsefile->lleft */
1098
1099static struct parsefile basepf; /* top level input file */
1100static char basebuf[BUFSIZ]; /* buffer for top level input file */
1101static struct parsefile *parsefile = &basepf; /* current input file */
1102
1103/*
1104 * NEOF is returned by parsecmd when it encounters an end of file. It
1105 * must be distinct from NULL, so we use the address of a variable that
1106 * happens to be handy.
1107 */
1108
1109static int tokpushback; /* last token pushed back */
1110#define NEOF ((union node *)&tokpushback)
1111static int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */
1112
1113
1114static void error (const char *, ...) __attribute__((__noreturn__));
1115static void exerror (int, const char *, ...) __attribute__((__noreturn__));
1116static void shellexec (char **, char **, const char *, int)
1117 __attribute__((noreturn));
1118static void exitshell (int) __attribute__((noreturn));
1119
1120static int goodname(const char *);
1121static void ignoresig (int);
1122static void onsig (int);
1123static void dotrap (void);
1124static int decode_signal (const char *, int);
1125
1126static void shprocvar(void);
1127static void deletefuncs(void);
1128static void setparam (char **);
1129static void freeparam (volatile struct shparam *);
1130
1131/* reasons for skipping commands (see comment on breakcmd routine) */
1132#define SKIPBREAK 1
1133#define SKIPCONT 2
1134#define SKIPFUNC 3
1135#define SKIPFILE 4
1136
1137/* values of cmdtype */
1138#define CMDUNKNOWN -1 /* no entry in table for command */
1139#define CMDNORMAL 0 /* command is an executable program */
1140#define CMDBUILTIN 1 /* command is a shell builtin */
1141#define CMDFUNCTION 2 /* command is a shell function */
1142
1143#define DO_ERR 1 /* find_command prints errors */
1144#define DO_ABS 2 /* find_command checks absolute paths */
1145#define DO_NOFUN 4 /* find_command ignores functions */
1146#define DO_BRUTE 8 /* find_command ignores hash table */
1147
1148/*
1149 * Shell variables.
1150 */
1151
1152/* flags */
1153#define VEXPORT 0x01 /* variable is exported */
1154#define VREADONLY 0x02 /* variable cannot be modified */
1155#define VSTRFIXED 0x04 /* variable struct is staticly allocated */
1156#define VTEXTFIXED 0x08 /* text is staticly allocated */
1157#define VSTACK 0x10 /* text is allocated on the stack */
1158#define VUNSET 0x20 /* the variable is not set */
1159#define VNOFUNC 0x40 /* don't call the callback function */
1160
1161
1162struct var {
1163 struct var *next; /* next entry in hash list */
1164 int flags; /* flags are defined above */
1165 char *text; /* name=value */
1166 void (*func) (const char *);
1167 /* function to be called when */
1168 /* the variable gets set/unset */
1169};
1170
1171struct localvar {
1172 struct localvar *next; /* next local variable in list */
1173 struct var *vp; /* the variable that was made local */
1174 int flags; /* saved flags */
1175 char *text; /* saved text */
1176};
1177
1178
Eric Andersen62483552001-07-10 06:09:16 +00001179#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00001180#define rmescapes(p) _rmescapes((p), 0)
1181static char *_rmescapes (char *, int);
1182#else
1183static void rmescapes (char *);
1184#endif
1185
1186static int casematch (union node *, const char *);
1187static void clearredir(void);
1188static void popstring(void);
1189static void readcmdfile (const char *);
1190
1191static int number (const char *);
1192static int is_number (const char *, int *num);
1193static char *single_quote (const char *);
1194static int nextopt (const char *);
1195
1196static void redirect (union node *, int);
1197static void popredir (void);
1198static int dup_as_newfd (int, int);
1199
1200static void changepath(const char *newval);
1201static void getoptsreset(const char *value);
1202
1203
1204static int parsenleft; /* copy of parsefile->nleft */
1205static char *parsenextc; /* copy of parsefile->nextc */
1206static int rootpid; /* pid of main shell */
1207static int rootshell; /* true if we aren't a child of the main shell */
1208
1209static const char spcstr[] = " ";
1210static const char snlfmt[] = "%s\n";
1211
1212static int sstrnleft;
1213static int herefd = -1;
1214
1215static struct localvar *localvars;
1216
1217static struct var vifs;
1218static struct var vmail;
1219static struct var vmpath;
1220static struct var vpath;
1221static struct var vps1;
1222static struct var vps2;
1223static struct var voptind;
Eric Andersenbdfd0d72001-10-24 05:00:29 +00001224#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00001225static struct var vlc_all;
1226static struct var vlc_ctype;
1227#endif
1228
1229struct varinit {
1230 struct var *var;
1231 int flags;
1232 const char *text;
1233 void (*func) (const char *);
1234};
1235
1236static const char defpathvar[] =
1237 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
1238#define defpath (defpathvar + 5)
1239
1240#ifdef IFS_BROKEN
1241static const char defifsvar[] = "IFS= \t\n";
1242#define defifs (defifsvar + 4)
1243#else
1244static const char defifs[] = " \t\n";
1245#endif
1246
1247static const struct varinit varinit[] = {
1248#ifdef IFS_BROKEN
1249 { &vifs, VSTRFIXED|VTEXTFIXED, defifsvar,
1250#else
1251 { &vifs, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS=",
1252#endif
1253 NULL },
1254 { &vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=",
1255 NULL },
1256 { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=",
1257 NULL },
1258 { &vpath, VSTRFIXED|VTEXTFIXED, defpathvar,
1259 changepath },
1260 /*
1261 * vps1 depends on uid
1262 */
1263 { &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ",
1264 NULL },
1265 { &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1",
1266 getoptsreset },
Eric Andersenbdfd0d72001-10-24 05:00:29 +00001267#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00001268 { &vlc_all, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL=",
1269 change_lc_all },
1270 { &vlc_ctype, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE=",
1271 change_lc_ctype },
1272#endif
1273 { NULL, 0, NULL,
1274 NULL }
1275};
1276
1277#define VTABSIZE 39
1278
1279static struct var *vartab[VTABSIZE];
1280
1281/*
1282 * The following macros access the values of the above variables.
1283 * They have to skip over the name. They return the null string
1284 * for unset variables.
1285 */
1286
1287#define ifsval() (vifs.text + 4)
1288#define ifsset() ((vifs.flags & VUNSET) == 0)
1289#define mailval() (vmail.text + 5)
1290#define mpathval() (vmpath.text + 9)
1291#define pathval() (vpath.text + 5)
1292#define ps1val() (vps1.text + 4)
1293#define ps2val() (vps2.text + 4)
1294#define optindval() (voptind.text + 7)
1295
1296#define mpathset() ((vmpath.flags & VUNSET) == 0)
1297
1298static void initvar (void);
1299static void setvar (const char *, const char *, int);
1300static void setvareq (char *, int);
1301static void listsetvar (struct strlist *);
Eric Andersen62483552001-07-10 06:09:16 +00001302static const char *lookupvar (const char *);
1303static const char *bltinlookup (const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001304static char **environment (void);
1305static int showvarscmd (int, char **);
1306static void mklocal (char *);
1307static void poplocalvars (void);
1308static int unsetvar (const char *);
1309static int varequal (const char *, const char *);
1310
1311
1312static char *arg0; /* value of $0 */
1313static struct shparam shellparam; /* current positional parameters */
1314static char **argptr; /* argument list for builtin commands */
1315static char *optionarg; /* set by nextopt (like getopt) */
1316static char *optptr; /* used by nextopt */
1317static char *minusc; /* argument to -c option */
1318
1319
1320#ifdef ASH_ALIAS
1321
1322#define ALIASINUSE 1
1323#define ALIASDEAD 2
1324
Eric Andersen3102ac42001-07-06 04:26:23 +00001325#define ATABSIZE 39
1326
Eric Andersen2870d962001-07-02 17:27:21 +00001327struct alias {
1328 struct alias *next;
1329 char *name;
1330 char *val;
1331 int flag;
1332};
1333
1334static struct alias *atab[ATABSIZE];
1335
1336static void setalias (char *, char *);
1337static struct alias **hashalias (const char *);
1338static struct alias *freealias (struct alias *);
1339static struct alias **__lookupalias (const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00001340
1341static void
1342setalias(name, val)
1343 char *name, *val;
1344{
1345 struct alias *ap, **app;
1346
1347 app = __lookupalias(name);
1348 ap = *app;
1349 INTOFF;
1350 if (ap) {
1351 if (!(ap->flag & ALIASINUSE)) {
1352 ckfree(ap->val);
1353 }
Eric Andersen2870d962001-07-02 17:27:21 +00001354 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00001355 ap->flag &= ~ALIASDEAD;
1356 } else {
1357 /* not found */
1358 ap = ckmalloc(sizeof (struct alias));
1359 ap->name = savestr(name);
1360 ap->val = savestr(val);
1361 ap->flag = 0;
1362 ap->next = 0;
1363 *app = ap;
1364 }
1365 INTON;
1366}
1367
1368static int
Eric Andersen2870d962001-07-02 17:27:21 +00001369unalias(char *name)
1370{
Eric Andersencb57d552001-06-28 07:25:16 +00001371 struct alias **app;
1372
1373 app = __lookupalias(name);
1374
1375 if (*app) {
1376 INTOFF;
1377 *app = freealias(*app);
1378 INTON;
1379 return (0);
1380 }
1381
1382 return (1);
1383}
1384
Eric Andersencb57d552001-06-28 07:25:16 +00001385static void
Eric Andersen2870d962001-07-02 17:27:21 +00001386rmaliases(void)
1387{
Eric Andersencb57d552001-06-28 07:25:16 +00001388 struct alias *ap, **app;
1389 int i;
1390
1391 INTOFF;
1392 for (i = 0; i < ATABSIZE; i++) {
1393 app = &atab[i];
1394 for (ap = *app; ap; ap = *app) {
1395 *app = freealias(*app);
1396 if (ap == *app) {
1397 app = &ap->next;
1398 }
1399 }
1400 }
1401 INTON;
1402}
1403
Eric Andersen2870d962001-07-02 17:27:21 +00001404static void
1405printalias(const struct alias *ap) {
1406 char *p;
1407
1408 p = single_quote(ap->val);
Eric Andersen62483552001-07-10 06:09:16 +00001409 printf("alias %s=%s\n", ap->name, p);
Eric Andersen2870d962001-07-02 17:27:21 +00001410 stunalloc(p);
1411}
1412
Eric Andersencb57d552001-06-28 07:25:16 +00001413
1414/*
1415 * TODO - sort output
1416 */
1417static int
Eric Andersen2870d962001-07-02 17:27:21 +00001418aliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001419{
1420 char *n, *v;
1421 int ret = 0;
1422 struct alias *ap;
1423
1424 if (argc == 1) {
1425 int i;
1426
1427 for (i = 0; i < ATABSIZE; i++)
1428 for (ap = atab[i]; ap; ap = ap->next) {
1429 printalias(ap);
1430 }
1431 return (0);
1432 }
1433 while ((n = *++argv) != NULL) {
1434 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
1435 if ((ap = *__lookupalias(n)) == NULL) {
Eric Andersen3102ac42001-07-06 04:26:23 +00001436 out2fmt("%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00001437 ret = 1;
1438 } else
1439 printalias(ap);
1440 }
1441 else {
1442 *v++ = '\0';
1443 setalias(n, v);
1444 }
1445 }
1446
1447 return (ret);
1448}
1449
1450static int
Eric Andersen2870d962001-07-02 17:27:21 +00001451unaliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001452{
1453 int i;
1454
1455 while ((i = nextopt("a")) != '\0') {
1456 if (i == 'a') {
1457 rmaliases();
1458 return (0);
1459 }
1460 }
1461 for (i = 0; *argptr; argptr++) {
1462 if (unalias(*argptr)) {
Eric Andersen3102ac42001-07-06 04:26:23 +00001463 out2fmt("%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00001464 i = 1;
1465 }
1466 }
1467
1468 return (i);
1469}
1470
1471static struct alias **
1472hashalias(p)
1473 const char *p;
1474 {
1475 unsigned int hashval;
1476
1477 hashval = *p << 4;
1478 while (*p)
1479 hashval+= *p++;
1480 return &atab[hashval % ATABSIZE];
1481}
1482
1483static struct alias *
1484freealias(struct alias *ap) {
1485 struct alias *next;
1486
1487 if (ap->flag & ALIASINUSE) {
1488 ap->flag |= ALIASDEAD;
1489 return ap;
1490 }
1491
1492 next = ap->next;
1493 ckfree(ap->name);
1494 ckfree(ap->val);
1495 ckfree(ap);
1496 return next;
1497}
1498
Eric Andersencb57d552001-06-28 07:25:16 +00001499
1500static struct alias **
1501__lookupalias(const char *name) {
1502 struct alias **app = hashalias(name);
1503
1504 for (; *app; app = &(*app)->next) {
1505 if (equal(name, (*app)->name)) {
1506 break;
1507 }
1508 }
1509
1510 return app;
1511}
Eric Andersen2870d962001-07-02 17:27:21 +00001512#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001513
1514#ifdef ASH_MATH_SUPPORT
Eric Andersen74bcd162001-07-30 21:41:37 +00001515/* The generated file arith.c has been replaced with a custom hand
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001516 * written implementation written by Aaron Lehmann <aaronl@vitelus.com>.
1517 * This is now part of libbb, so that it can be used by all the shells
Eric Andersen74bcd162001-07-30 21:41:37 +00001518 * in busybox. */
Eric Andersen2870d962001-07-02 17:27:21 +00001519static void expari (int);
Eric Andersencb57d552001-06-28 07:25:16 +00001520#endif
1521
Eric Andersen2870d962001-07-02 17:27:21 +00001522static char *trap[NSIG]; /* trap handler commands */
1523static char sigmode[NSIG - 1]; /* current value of signal */
1524static char gotsig[NSIG - 1]; /* indicates specified signal received */
1525static int pendingsigs; /* indicates some signal received */
1526
Eric Andersencb57d552001-06-28 07:25:16 +00001527/*
1528 * This file was generated by the mkbuiltins program.
1529 */
1530
Eric Andersen2870d962001-07-02 17:27:21 +00001531#ifdef JOBS
1532static int bgcmd (int, char **);
1533static int fgcmd (int, char **);
1534static int killcmd (int, char **);
1535#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001536static int bltincmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001537static int cdcmd (int, char **);
1538static int breakcmd (int, char **);
1539#ifdef ASH_CMDCMD
1540static int commandcmd (int, char **);
1541#endif
1542static int dotcmd (int, char **);
1543static int evalcmd (int, char **);
1544static int execcmd (int, char **);
1545static int exitcmd (int, char **);
1546static int exportcmd (int, char **);
1547static int histcmd (int, char **);
1548static int hashcmd (int, char **);
Eric Andersen1c039232001-07-07 00:05:55 +00001549static int helpcmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001550static int jobscmd (int, char **);
1551static int localcmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001552static int pwdcmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001553static int readcmd (int, char **);
1554static int returncmd (int, char **);
1555static int setcmd (int, char **);
1556static int setvarcmd (int, char **);
1557static int shiftcmd (int, char **);
1558static int trapcmd (int, char **);
1559static int umaskcmd (int, char **);
1560#ifdef ASH_ALIAS
1561static int aliascmd (int, char **);
1562static int unaliascmd (int, char **);
1563#endif
1564static int unsetcmd (int, char **);
1565static int waitcmd (int, char **);
1566static int ulimitcmd (int, char **);
1567static int timescmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001568#ifdef ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +00001569static int letcmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001570#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001571static int typecmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001572#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00001573static int getoptscmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001574#endif
1575
Eric Andersen69a20f02001-10-31 10:40:37 +00001576#ifndef CONFIG_TRUE
Eric Andersen2870d962001-07-02 17:27:21 +00001577static int true_main (int, char **);
Eric Andersen69a20f02001-10-31 10:40:37 +00001578#endif
1579#ifndef CONFIG_FALSE
Eric Andersen2870d962001-07-02 17:27:21 +00001580static int false_main (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001581#endif
1582
1583static void setpwd (const char *, int);
1584
1585
1586#define BUILTIN_NOSPEC "0"
1587#define BUILTIN_SPECIAL "1"
1588#define BUILTIN_REGULAR "2"
1589#define BUILTIN_ASSIGN "4"
1590#define BUILTIN_SPEC_ASSG "5"
1591#define BUILTIN_REG_ASSG "6"
1592
1593#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1594#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1595#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
1596
1597struct builtincmd {
1598 const char *name;
1599 int (*const builtinfunc) (int, char **);
1600 //unsigned flags;
1601};
1602
Eric Andersencb57d552001-06-28 07:25:16 +00001603
1604/* It is CRUCIAL that this listing be kept in ascii order, otherwise
1605 * the binary search in find_builtin() will stop working. If you value
1606 * your kneecaps, you'll be sure to *make sure* that any changes made
1607 * to this array result in the listing remaining in ascii order. You
1608 * have been warned.
1609 */
1610static const struct builtincmd builtincmds[] = {
Eric Andersen62483552001-07-10 06:09:16 +00001611 { BUILTIN_SPECIAL ".", dotcmd }, /* first, see declare DOTCMD */
Eric Andersen2870d962001-07-02 17:27:21 +00001612 { BUILTIN_SPECIAL ":", true_main },
1613#ifdef ASH_ALIAS
1614 { BUILTIN_REG_ASSG "alias", aliascmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001615#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001616#ifdef JOBS
1617 { BUILTIN_REGULAR "bg", bgcmd },
1618#endif
1619 { BUILTIN_SPECIAL "break", breakcmd },
Eric Andersen3102ac42001-07-06 04:26:23 +00001620 { BUILTIN_SPECIAL "builtin", bltincmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001621 { BUILTIN_REGULAR "cd", cdcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001622 { BUILTIN_NOSPEC "chdir", cdcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001623#ifdef ASH_CMDCMD
1624 { BUILTIN_REGULAR "command", commandcmd },
1625#endif
1626 { BUILTIN_SPECIAL "continue", breakcmd },
1627 { BUILTIN_SPECIAL "eval", evalcmd },
1628 { BUILTIN_SPECIAL "exec", execcmd },
1629 { BUILTIN_SPECIAL "exit", exitcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001630 { BUILTIN_SPEC_ASSG "export", exportcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001631 { BUILTIN_REGULAR "false", false_main },
Eric Andersen2870d962001-07-02 17:27:21 +00001632 { BUILTIN_REGULAR "fc", histcmd },
1633#ifdef JOBS
1634 { BUILTIN_REGULAR "fg", fgcmd },
1635#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001636#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00001637 { BUILTIN_REGULAR "getopts", getoptscmd },
1638#endif
1639 { BUILTIN_NOSPEC "hash", hashcmd },
Eric Andersen1c039232001-07-07 00:05:55 +00001640 { BUILTIN_NOSPEC "help", helpcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001641 { BUILTIN_REGULAR "jobs", jobscmd },
1642#ifdef JOBS
1643 { BUILTIN_REGULAR "kill", killcmd },
1644#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001645#ifdef ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +00001646 { BUILTIN_REGULAR "let", letcmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001647#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001648 { BUILTIN_ASSIGN "local", localcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001649 { BUILTIN_NOSPEC "pwd", pwdcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001650 { BUILTIN_REGULAR "read", readcmd },
1651 { BUILTIN_SPEC_ASSG "readonly", exportcmd },
1652 { BUILTIN_SPECIAL "return", returncmd },
1653 { BUILTIN_SPECIAL "set", setcmd },
1654 { BUILTIN_NOSPEC "setvar", setvarcmd },
1655 { BUILTIN_SPECIAL "shift", shiftcmd },
1656 { BUILTIN_SPECIAL "times", timescmd },
1657 { BUILTIN_SPECIAL "trap", trapcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001658 { BUILTIN_REGULAR "true", true_main },
Eric Andersen2870d962001-07-02 17:27:21 +00001659 { BUILTIN_NOSPEC "type", typecmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001660 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1661 { BUILTIN_REGULAR "umask", umaskcmd },
1662#ifdef ASH_ALIAS
1663 { BUILTIN_REGULAR "unalias", unaliascmd },
1664#endif
1665 { BUILTIN_SPECIAL "unset", unsetcmd },
1666 { BUILTIN_REGULAR "wait", waitcmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001667};
1668#define NUMBUILTINS (sizeof (builtincmds) / sizeof (struct builtincmd) )
1669
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001670#define DOTCMD &builtincmds[0]
Eric Andersen2870d962001-07-02 17:27:21 +00001671static struct builtincmd *BLTINCMD;
1672static struct builtincmd *EXECCMD;
1673static struct builtincmd *EVALCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00001674
Eric Andersen2870d962001-07-02 17:27:21 +00001675/* states */
1676#define JOBSTOPPED 1 /* all procs are stopped */
1677#define JOBDONE 2 /* all procs are completed */
Eric Andersencb57d552001-06-28 07:25:16 +00001678
Eric Andersen2870d962001-07-02 17:27:21 +00001679/*
1680 * A job structure contains information about a job. A job is either a
1681 * single process or a set of processes contained in a pipeline. In the
1682 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1683 * array of pids.
1684 */
Eric Andersencb57d552001-06-28 07:25:16 +00001685
Eric Andersen2870d962001-07-02 17:27:21 +00001686struct procstat {
1687 pid_t pid; /* process id */
1688 int status; /* status flags (defined above) */
1689 char *cmd; /* text of command being run */
1690};
Eric Andersencb57d552001-06-28 07:25:16 +00001691
Eric Andersen2870d962001-07-02 17:27:21 +00001692
1693static int job_warning; /* user was warned about stopped jobs */
1694
1695#ifdef JOBS
1696static void setjobctl(int enable);
1697#else
1698#define setjobctl(on) /* do nothing */
Eric Andersencb57d552001-06-28 07:25:16 +00001699#endif
1700
Eric Andersen2870d962001-07-02 17:27:21 +00001701
1702struct job {
1703 struct procstat ps0; /* status of process */
1704 struct procstat *ps; /* status or processes when more than one */
1705 short nprocs; /* number of processes */
1706 short pgrp; /* process group of this job */
1707 char state; /* true if job is finished */
1708 char used; /* true if this entry is in used */
1709 char changed; /* true if status has changed */
1710#ifdef JOBS
1711 char jobctl; /* job running under job control */
1712#endif
1713};
1714
1715static struct job *jobtab; /* array of jobs */
1716static int njobs; /* size of array */
1717static int backgndpid = -1; /* pid of last background process */
1718#ifdef JOBS
1719static int initialpgrp; /* pgrp of shell on invocation */
1720static int curjob; /* current job */
1721static int jobctl;
1722#endif
1723static int intreceived;
1724
Eric Andersen62483552001-07-10 06:09:16 +00001725static struct job *makejob (const union node *, int);
1726static int forkshell (struct job *, const union node *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00001727static int waitforjob (struct job *);
1728
1729static int docd (char *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00001730static void updatepwd (const char *);
1731static void getpwd (void);
1732
1733static char *padvance (const char **, const char *);
1734
1735static char nullstr[1]; /* zero length string */
1736static char *curdir = nullstr; /* current working directory */
Eric Andersen2870d962001-07-02 17:27:21 +00001737
Eric Andersencb57d552001-06-28 07:25:16 +00001738static int
1739cdcmd(argc, argv)
1740 int argc;
1741 char **argv;
1742{
1743 const char *dest;
1744 const char *path;
1745 char *p;
1746 struct stat statb;
1747 int print = 0;
1748
1749 nextopt(nullstr);
1750 if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME")) == NULL)
1751 error("HOME not set");
1752 if (*dest == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00001753 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001754 if (dest[0] == '-' && dest[1] == '\0') {
1755 dest = bltinlookup("OLDPWD");
1756 if (!dest || !*dest) {
1757 dest = curdir;
1758 }
1759 print = 1;
1760 if (dest)
Eric Andersen2870d962001-07-02 17:27:21 +00001761 print = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00001762 else
Eric Andersen2870d962001-07-02 17:27:21 +00001763 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001764 }
1765 if (*dest == '/' || (path = bltinlookup("CDPATH")) == NULL)
1766 path = nullstr;
1767 while ((p = padvance(&path, dest)) != NULL) {
1768 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
1769 if (!print) {
1770 /*
1771 * XXX - rethink
1772 */
1773 if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
1774 p += 2;
1775 print = strcmp(p, dest);
1776 }
1777 if (docd(p, print) >= 0)
1778 return 0;
1779
1780 }
1781 }
1782 error("can't cd to %s", dest);
1783 /* NOTREACHED */
1784}
1785
1786
1787/*
1788 * Actually do the chdir. In an interactive shell, print the
1789 * directory name if "print" is nonzero.
1790 */
1791
1792static int
Eric Andersena3483db2001-10-24 08:01:06 +00001793docd(char *dest, int print)
Eric Andersencb57d552001-06-28 07:25:16 +00001794{
Eric Andersencb57d552001-06-28 07:25:16 +00001795 TRACE(("docd(\"%s\", %d) called\n", dest, print));
Eric Andersencb57d552001-06-28 07:25:16 +00001796 INTOFF;
1797 if (chdir(dest) < 0) {
1798 INTON;
1799 return -1;
1800 }
Eric Andersena3483db2001-10-24 08:01:06 +00001801 updatepwd(dest);
Eric Andersencb57d552001-06-28 07:25:16 +00001802 INTON;
1803 if (print && iflag)
Eric Andersen62483552001-07-10 06:09:16 +00001804 printf(snlfmt, curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00001805 return 0;
1806}
1807
1808
1809/*
Eric Andersencb57d552001-06-28 07:25:16 +00001810 * Update curdir (the name of the current directory) in response to a
1811 * cd command. We also call hashcd to let the routines in exec.c know
1812 * that the current directory has changed.
1813 */
1814
Eric Andersen2870d962001-07-02 17:27:21 +00001815static void hashcd (void);
1816
Eric Andersencb57d552001-06-28 07:25:16 +00001817static void
Eric Andersen2870d962001-07-02 17:27:21 +00001818updatepwd(const char *dir)
1819{
Eric Andersen2870d962001-07-02 17:27:21 +00001820 hashcd(); /* update command hash table */
Eric Andersencb57d552001-06-28 07:25:16 +00001821
Eric Andersena3483db2001-10-24 08:01:06 +00001822 /* If our argument is NULL, we don't know the current directory */
Eric Andersencb57d552001-06-28 07:25:16 +00001823 if (dir == NULL || curdir == nullstr) {
1824 setpwd(0, 1);
1825 return;
1826 }
Eric Andersena3483db2001-10-24 08:01:06 +00001827 setpwd(dir, 1);
Eric Andersencb57d552001-06-28 07:25:16 +00001828}
1829
1830
Eric Andersencb57d552001-06-28 07:25:16 +00001831static int
Eric Andersena3483db2001-10-24 08:01:06 +00001832pwdcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001833{
Eric Andersen62483552001-07-10 06:09:16 +00001834 printf(snlfmt, curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00001835 return 0;
1836}
Eric Andersencb57d552001-06-28 07:25:16 +00001837
Eric Andersena3483db2001-10-24 08:01:06 +00001838/* Ask system the current directory */
Eric Andersencb57d552001-06-28 07:25:16 +00001839static void
Eric Andersen2870d962001-07-02 17:27:21 +00001840getpwd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00001841{
Eric Andersen2870d962001-07-02 17:27:21 +00001842 curdir = xgetcwd(0);
1843 if(curdir==0)
1844 curdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00001845}
1846
1847static void
1848setpwd(const char *val, int setold)
1849{
Eric Andersena3483db2001-10-24 08:01:06 +00001850 char *cated = NULL;
1851
Eric Andersencb57d552001-06-28 07:25:16 +00001852 if (setold) {
1853 setvar("OLDPWD", curdir, VEXPORT);
1854 }
1855 INTOFF;
1856 if (curdir != nullstr) {
Eric Andersena3483db2001-10-24 08:01:06 +00001857 if(val!=NULL && *val != '/')
1858 val = cated = concat_path_file(curdir, val);
Eric Andersencb57d552001-06-28 07:25:16 +00001859 free(curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00001860 }
Eric Andersena3483db2001-10-24 08:01:06 +00001861 if (!val)
Eric Andersencb57d552001-06-28 07:25:16 +00001862 getpwd();
Eric Andersena3483db2001-10-24 08:01:06 +00001863 else
1864 curdir = simplify_path(val);
1865 free(cated);
Eric Andersencb57d552001-06-28 07:25:16 +00001866 INTON;
1867 setvar("PWD", curdir, VEXPORT);
1868}
1869
Eric Andersencb57d552001-06-28 07:25:16 +00001870/*
1871 * Errors and exceptions.
1872 */
1873
1874/*
1875 * Code to handle exceptions in C.
1876 */
1877
Eric Andersen2870d962001-07-02 17:27:21 +00001878/*
1879 * We enclose jmp_buf in a structure so that we can declare pointers to
1880 * jump locations. The global variable handler contains the location to
1881 * jump to when an exception occurs, and the global variable exception
1882 * contains a code identifying the exeception. To implement nested
1883 * exception handlers, the user should save the value of handler on entry
1884 * to an inner scope, set handler to point to a jmploc structure for the
1885 * inner scope, and restore handler on exit from the scope.
1886 */
1887
1888struct jmploc {
1889 jmp_buf loc;
1890};
1891
1892/* exceptions */
1893#define EXINT 0 /* SIGINT received */
1894#define EXERROR 1 /* a generic error */
1895#define EXSHELLPROC 2 /* execute a shell procedure */
1896#define EXEXEC 3 /* command execution failed */
1897
1898static struct jmploc *handler;
Eric Andersencb57d552001-06-28 07:25:16 +00001899static int exception;
Eric Andersencb57d552001-06-28 07:25:16 +00001900
Eric Andersen2870d962001-07-02 17:27:21 +00001901static void exverror (int, const char *, va_list)
Eric Andersencb57d552001-06-28 07:25:16 +00001902 __attribute__((__noreturn__));
1903
1904/*
1905 * Called to raise an exception. Since C doesn't include exceptions, we
1906 * just do a longjmp to the exception handler. The type of exception is
1907 * stored in the global variable "exception".
1908 */
1909
Eric Andersen2870d962001-07-02 17:27:21 +00001910static void exraise (int) __attribute__((__noreturn__));
1911
Eric Andersencb57d552001-06-28 07:25:16 +00001912static void
Eric Andersen2870d962001-07-02 17:27:21 +00001913exraise(int e)
Eric Andersencb57d552001-06-28 07:25:16 +00001914{
1915#ifdef DEBUG
1916 if (handler == NULL)
1917 abort();
1918#endif
Eric Andersen62483552001-07-10 06:09:16 +00001919 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00001920 exception = e;
1921 longjmp(handler->loc, 1);
1922}
1923
1924
1925/*
1926 * Called from trap.c when a SIGINT is received. (If the user specifies
1927 * that SIGINT is to be trapped or ignored using the trap builtin, then
1928 * this routine is not called.) Suppressint is nonzero when interrupts
1929 * are held using the INTOFF macro. The call to _exit is necessary because
1930 * there is a short period after a fork before the signal handlers are
1931 * set to the appropriate value for the child. (The test for iflag is
1932 * just defensive programming.)
1933 */
1934
1935static void
Eric Andersen2870d962001-07-02 17:27:21 +00001936onint(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00001937 sigset_t mysigset;
1938
1939 if (suppressint) {
1940 intpending++;
1941 return;
1942 }
1943 intpending = 0;
1944 sigemptyset(&mysigset);
1945 sigprocmask(SIG_SETMASK, &mysigset, NULL);
1946 if (rootshell && iflag)
1947 exraise(EXINT);
1948 else {
1949 signal(SIGINT, SIG_DFL);
1950 raise(SIGINT);
1951 }
1952 /* NOTREACHED */
1953}
1954
1955
Eric Andersen2870d962001-07-02 17:27:21 +00001956static char *commandname; /* currently executing command */
1957
Eric Andersencb57d552001-06-28 07:25:16 +00001958/*
1959 * Exverror is called to raise the error exception. If the first argument
1960 * is not NULL then error prints an error message using printf style
1961 * formatting. It then raises the error exception.
1962 */
1963static void
Eric Andersen2870d962001-07-02 17:27:21 +00001964exverror(int cond, const char *msg, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00001965{
1966 CLEAR_PENDING_INT;
1967 INTOFF;
1968
1969#ifdef DEBUG
1970 if (msg)
1971 TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
1972 else
1973 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
1974#endif
1975 if (msg) {
1976 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +00001977 out2fmt("%s: ", commandname);
1978 vfprintf(stderr, msg, ap);
1979 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00001980 }
Eric Andersencb57d552001-06-28 07:25:16 +00001981 exraise(cond);
1982 /* NOTREACHED */
1983}
1984
1985
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001986static void
Eric Andersencb57d552001-06-28 07:25:16 +00001987error(const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00001988{
Eric Andersencb57d552001-06-28 07:25:16 +00001989 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00001990 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00001991 exverror(EXERROR, msg, ap);
1992 /* NOTREACHED */
1993 va_end(ap);
1994}
1995
1996
Eric Andersencb57d552001-06-28 07:25:16 +00001997static void
1998exerror(int cond, const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00001999{
Eric Andersencb57d552001-06-28 07:25:16 +00002000 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002001 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002002 exverror(cond, msg, ap);
2003 /* NOTREACHED */
2004 va_end(ap);
2005}
2006
2007
2008
2009/*
2010 * Table of error messages.
2011 */
2012
2013struct errname {
Eric Andersen2870d962001-07-02 17:27:21 +00002014 short errcode; /* error number */
Eric Andersen62483552001-07-10 06:09:16 +00002015 char action; /* operation which encountered the error */
Eric Andersencb57d552001-06-28 07:25:16 +00002016};
2017
Eric Andersen2870d962001-07-02 17:27:21 +00002018/*
2019 * Types of operations (passed to the errmsg routine).
2020 */
2021
2022#define E_OPEN 01 /* opening a file */
2023#define E_CREAT 02 /* creating a file */
2024#define E_EXEC 04 /* executing a program */
Eric Andersencb57d552001-06-28 07:25:16 +00002025
2026#define ALL (E_OPEN|E_CREAT|E_EXEC)
2027
2028static const struct errname errormsg[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00002029 { EINTR, ALL },
2030 { EACCES, ALL },
2031 { EIO, ALL },
2032 { ENOENT, E_OPEN },
2033 { ENOENT, E_CREAT },
2034 { ENOENT, E_EXEC },
2035 { ENOTDIR, E_OPEN },
2036 { ENOTDIR, E_CREAT },
2037 { ENOTDIR, E_EXEC },
2038 { EISDIR, ALL },
2039 { EEXIST, E_CREAT },
2040#ifdef EMFILE
2041 { EMFILE, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002042#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002043 { ENFILE, ALL },
2044 { ENOSPC, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002045#ifdef EDQUOT
Eric Andersen2870d962001-07-02 17:27:21 +00002046 { EDQUOT, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002047#endif
2048#ifdef ENOSR
Eric Andersen2870d962001-07-02 17:27:21 +00002049 { ENOSR, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002050#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002051 { ENXIO, ALL },
2052 { EROFS, ALL },
2053 { ETXTBSY, ALL },
2054#ifdef EAGAIN
2055 { EAGAIN, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002056#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002057 { ENOMEM, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002058#ifdef ENOLINK
Eric Andersen2870d962001-07-02 17:27:21 +00002059 { ENOLINK, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002060#endif
2061#ifdef EMULTIHOP
Eric Andersen2870d962001-07-02 17:27:21 +00002062 { EMULTIHOP, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002063#endif
2064#ifdef ECOMM
Eric Andersen2870d962001-07-02 17:27:21 +00002065 { ECOMM, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002066#endif
2067#ifdef ESTALE
Eric Andersen2870d962001-07-02 17:27:21 +00002068 { ESTALE, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002069#endif
2070#ifdef ETIMEDOUT
Eric Andersen2870d962001-07-02 17:27:21 +00002071 { ETIMEDOUT, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002072#endif
2073#ifdef ELOOP
Eric Andersen2870d962001-07-02 17:27:21 +00002074 { ELOOP, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002075#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002076 { E2BIG, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002077#ifdef ELIBACC
Eric Andersen2870d962001-07-02 17:27:21 +00002078 { ELIBACC, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002079#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002080};
2081
Eric Andersen2870d962001-07-02 17:27:21 +00002082#define ERRNAME_SIZE (sizeof(errormsg)/sizeof(struct errname))
Eric Andersencb57d552001-06-28 07:25:16 +00002083
2084/*
2085 * Return a string describing an error. The returned string may be a
2086 * pointer to a static buffer that will be overwritten on the next call.
2087 * Action describes the operation that got the error.
2088 */
2089
2090static const char *
Eric Andersen2870d962001-07-02 17:27:21 +00002091errmsg(int e, int action)
Eric Andersencb57d552001-06-28 07:25:16 +00002092{
2093 struct errname const *ep;
2094 static char buf[12];
2095
Eric Andersen2870d962001-07-02 17:27:21 +00002096 for (ep = errormsg ; ep < errormsg+ERRNAME_SIZE; ep++) {
Eric Andersencb57d552001-06-28 07:25:16 +00002097 if (ep->errcode == e && (ep->action & action) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00002098 return strerror(e);
Eric Andersencb57d552001-06-28 07:25:16 +00002099 }
Eric Andersen2870d962001-07-02 17:27:21 +00002100
Eric Andersen3102ac42001-07-06 04:26:23 +00002101 snprintf(buf, sizeof buf, "error %d", e);
Eric Andersencb57d552001-06-28 07:25:16 +00002102 return buf;
2103}
2104
2105
Eric Andersen3102ac42001-07-06 04:26:23 +00002106#ifdef ASH_OPTIMIZE_FOR_SIZE
Eric Andersencb57d552001-06-28 07:25:16 +00002107static void
2108__inton() {
2109 if (--suppressint == 0 && intpending) {
2110 onint();
2111 }
2112}
Eric Andersen3102ac42001-07-06 04:26:23 +00002113static void forceinton (void) {
2114 suppressint = 0;
2115 if (intpending)
2116 onint();
2117}
Eric Andersencb57d552001-06-28 07:25:16 +00002118#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002119
2120/* flags in argument to evaltree */
Eric Andersen2870d962001-07-02 17:27:21 +00002121#define EV_EXIT 01 /* exit after evaluating tree */
2122#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2123#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00002124
Eric Andersen2870d962001-07-02 17:27:21 +00002125static int evalskip; /* set if we are skipping commands */
2126static int skipcount; /* number of levels to skip */
2127static int loopnest; /* current loop nesting level */
2128static int funcnest; /* depth of function calls */
Eric Andersencb57d552001-06-28 07:25:16 +00002129
2130
Eric Andersen2870d962001-07-02 17:27:21 +00002131static struct strlist *cmdenviron; /* environment for builtin command */
2132static int exitstatus; /* exit status of last command */
2133static int oexitstatus; /* saved exit status */
Eric Andersencb57d552001-06-28 07:25:16 +00002134
Eric Andersen62483552001-07-10 06:09:16 +00002135static void evalsubshell (const union node *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00002136static void expredir (union node *);
Eric Andersen2870d962001-07-02 17:27:21 +00002137static void prehash (union node *);
2138static void eprintlist (struct strlist *);
Eric Andersencb57d552001-06-28 07:25:16 +00002139
Eric Andersen2870d962001-07-02 17:27:21 +00002140static union node *parsecmd(int);
Eric Andersencb57d552001-06-28 07:25:16 +00002141/*
2142 * Called to reset things after an exception.
2143 */
2144
Eric Andersencb57d552001-06-28 07:25:16 +00002145/*
2146 * The eval commmand.
2147 */
Eric Andersen2870d962001-07-02 17:27:21 +00002148static void evalstring (char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00002149
2150static int
2151evalcmd(argc, argv)
2152 int argc;
2153 char **argv;
2154{
Eric Andersen2870d962001-07-02 17:27:21 +00002155 char *p;
2156 char *concat;
2157 char **ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002158
Eric Andersen2870d962001-07-02 17:27:21 +00002159 if (argc > 1) {
2160 p = argv[1];
2161 if (argc > 2) {
2162 STARTSTACKSTR(concat);
2163 ap = argv + 2;
2164 for (;;) {
2165 while (*p)
2166 STPUTC(*p++, concat);
2167 if ((p = *ap++) == NULL)
2168 break;
2169 STPUTC(' ', concat);
2170 }
2171 STPUTC('\0', concat);
2172 p = grabstackstr(concat);
2173 }
2174 evalstring(p, EV_TESTED);
2175 }
2176 return exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002177}
2178
Eric Andersencb57d552001-06-28 07:25:16 +00002179/*
2180 * Execute a command or commands contained in a string.
2181 */
2182
Eric Andersen2870d962001-07-02 17:27:21 +00002183static void evaltree (union node *, int);
2184static void setinputstring (char *);
2185static void popfile (void);
2186static void setstackmark(struct stackmark *mark);
2187static void popstackmark(struct stackmark *mark);
2188
2189
Eric Andersencb57d552001-06-28 07:25:16 +00002190static void
Eric Andersen2870d962001-07-02 17:27:21 +00002191evalstring(char *s, int flag)
2192{
Eric Andersencb57d552001-06-28 07:25:16 +00002193 union node *n;
2194 struct stackmark smark;
2195
2196 setstackmark(&smark);
2197 setinputstring(s);
2198 while ((n = parsecmd(0)) != NEOF) {
2199 evaltree(n, flag);
2200 popstackmark(&smark);
2201 }
2202 popfile();
2203 popstackmark(&smark);
2204}
2205
Eric Andersen2870d962001-07-02 17:27:21 +00002206static struct builtincmd *find_builtin (const char *);
Eric Andersen62483552001-07-10 06:09:16 +00002207static void expandarg (union node *, struct arglist *, int);
2208static void calcsize (const union node *);
2209static union node *copynode (const union node *);
2210
2211/*
2212 * Make a copy of a parse tree.
2213 */
2214
2215static int funcblocksize; /* size of structures in function */
2216static int funcstringsize; /* size of strings in node */
2217static pointer funcblock; /* block to allocate function from */
2218static char *funcstring; /* block to allocate strings from */
2219
2220
2221static inline union node *
2222copyfunc(union node *n)
2223{
2224 if (n == NULL)
2225 return NULL;
2226 funcblocksize = 0;
2227 funcstringsize = 0;
2228 calcsize(n);
2229 funcblock = ckmalloc(funcblocksize + funcstringsize);
2230 funcstring = (char *) funcblock + funcblocksize;
2231 return copynode(n);
2232}
2233
2234/*
2235 * Free a parse tree.
2236 */
Eric Andersencb57d552001-06-28 07:25:16 +00002237
2238static void
Eric Andersen62483552001-07-10 06:09:16 +00002239freefunc(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00002240{
Eric Andersen62483552001-07-10 06:09:16 +00002241 if (n)
2242 ckfree(n);
Eric Andersencb57d552001-06-28 07:25:16 +00002243}
2244
2245
Eric Andersen62483552001-07-10 06:09:16 +00002246/*
2247 * Add a new command entry, replacing any existing command entry for
2248 * the same name.
2249 */
2250
2251static inline void
2252addcmdentry(char *name, struct cmdentry *entry)
2253{
2254 struct tblentry *cmdp;
2255
2256 INTOFF;
2257 cmdp = cmdlookup(name, 1);
2258 if (cmdp->cmdtype == CMDFUNCTION) {
2259 freefunc(cmdp->param.func);
2260 }
2261 cmdp->cmdtype = entry->cmdtype;
2262 cmdp->param = entry->u;
2263 INTON;
2264}
2265
2266static inline void
2267evalloop(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002268{
2269 int status;
2270
2271 loopnest++;
2272 status = 0;
2273 for (;;) {
2274 evaltree(n->nbinary.ch1, EV_TESTED);
2275 if (evalskip) {
Eric Andersen2870d962001-07-02 17:27:21 +00002276skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002277 evalskip = 0;
2278 continue;
2279 }
2280 if (evalskip == SKIPBREAK && --skipcount <= 0)
2281 evalskip = 0;
2282 break;
2283 }
2284 if (n->type == NWHILE) {
2285 if (exitstatus != 0)
2286 break;
2287 } else {
2288 if (exitstatus == 0)
2289 break;
2290 }
2291 evaltree(n->nbinary.ch2, flags & EV_TESTED);
2292 status = exitstatus;
2293 if (evalskip)
2294 goto skipping;
2295 }
2296 loopnest--;
2297 exitstatus = status;
2298}
2299
Eric Andersencb57d552001-06-28 07:25:16 +00002300static void
Eric Andersen62483552001-07-10 06:09:16 +00002301evalfor(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002302{
2303 struct arglist arglist;
2304 union node *argp;
2305 struct strlist *sp;
2306 struct stackmark smark;
2307
2308 setstackmark(&smark);
2309 arglist.lastp = &arglist.list;
2310 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2311 oexitstatus = exitstatus;
2312 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2313 if (evalskip)
2314 goto out;
2315 }
2316 *arglist.lastp = NULL;
2317
2318 exitstatus = 0;
2319 loopnest++;
2320 for (sp = arglist.list ; sp ; sp = sp->next) {
2321 setvar(n->nfor.var, sp->text, 0);
2322 evaltree(n->nfor.body, flags & EV_TESTED);
2323 if (evalskip) {
2324 if (evalskip == SKIPCONT && --skipcount <= 0) {
2325 evalskip = 0;
2326 continue;
2327 }
2328 if (evalskip == SKIPBREAK && --skipcount <= 0)
2329 evalskip = 0;
2330 break;
2331 }
2332 }
2333 loopnest--;
2334out:
2335 popstackmark(&smark);
2336}
2337
Eric Andersen62483552001-07-10 06:09:16 +00002338static inline void
2339evalcase(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002340{
2341 union node *cp;
2342 union node *patp;
2343 struct arglist arglist;
2344 struct stackmark smark;
2345
2346 setstackmark(&smark);
2347 arglist.lastp = &arglist.list;
2348 oexitstatus = exitstatus;
2349 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2350 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2351 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2352 if (casematch(patp, arglist.list->text)) {
2353 if (evalskip == 0) {
2354 evaltree(cp->nclist.body, flags);
2355 }
2356 goto out;
2357 }
2358 }
2359 }
2360out:
2361 popstackmark(&smark);
2362}
2363
Eric Andersencb57d552001-06-28 07:25:16 +00002364/*
Eric Andersencb57d552001-06-28 07:25:16 +00002365 * Evaluate a pipeline. All the processes in the pipeline are children
2366 * of the process creating the pipeline. (This differs from some versions
2367 * of the shell, which make the last process in a pipeline the parent
2368 * of all the rest.)
2369 */
2370
Eric Andersen74400cc2001-10-18 04:11:39 +00002371static inline void evalpipe(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00002372{
2373 struct job *jp;
2374 struct nodelist *lp;
2375 int pipelen;
2376 int prevfd;
2377 int pip[2];
2378
2379 TRACE(("evalpipe(0x%lx) called\n", (long)n));
2380 pipelen = 0;
2381 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
2382 pipelen++;
2383 INTOFF;
2384 jp = makejob(n, pipelen);
2385 prevfd = -1;
2386 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
2387 prehash(lp->n);
2388 pip[1] = -1;
2389 if (lp->next) {
2390 if (pipe(pip) < 0) {
2391 close(prevfd);
2392 error("Pipe call failed");
2393 }
2394 }
2395 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
2396 INTON;
2397 if (prevfd > 0) {
2398 close(0);
2399 dup_as_newfd(prevfd, 0);
2400 close(prevfd);
2401 if (pip[0] == 0) {
2402 pip[0] = -1;
2403 }
2404 }
2405 if (pip[1] >= 0) {
2406 if (pip[0] >= 0) {
2407 close(pip[0]);
2408 }
2409 if (pip[1] != 1) {
2410 close(1);
2411 dup_as_newfd(pip[1], 1);
2412 close(pip[1]);
2413 }
2414 }
2415 evaltree(lp->n, EV_EXIT);
2416 }
2417 if (prevfd >= 0)
2418 close(prevfd);
2419 prevfd = pip[0];
2420 close(pip[1]);
2421 }
2422 INTON;
2423 if (n->npipe.backgnd == 0) {
2424 INTOFF;
2425 exitstatus = waitforjob(jp);
2426 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
2427 INTON;
2428 }
2429}
2430
Eric Andersen2870d962001-07-02 17:27:21 +00002431static void find_command (const char *, struct cmdentry *, int, const char *);
2432
2433static int
2434isassignment(const char *word) {
2435 if (!is_name(*word)) {
2436 return 0;
2437 }
2438 do {
2439 word++;
2440 } while (is_in_name(*word));
2441 return *word == '=';
2442}
2443
Eric Andersen62483552001-07-10 06:09:16 +00002444
Eric Andersencb57d552001-06-28 07:25:16 +00002445static void
Eric Andersen3102ac42001-07-06 04:26:23 +00002446evalcommand(union node *cmd, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002447{
2448 struct stackmark smark;
2449 union node *argp;
2450 struct arglist arglist;
2451 struct arglist varlist;
2452 char **argv;
2453 int argc;
2454 char **envp;
2455 struct strlist *sp;
2456 int mode;
Eric Andersencb57d552001-06-28 07:25:16 +00002457 struct cmdentry cmdentry;
2458 struct job *jp;
2459 char *volatile savecmdname;
2460 volatile struct shparam saveparam;
2461 struct localvar *volatile savelocalvars;
2462 volatile int e;
2463 char *lastarg;
2464 const char *path;
2465 const struct builtincmd *firstbltin;
2466 struct jmploc *volatile savehandler;
2467 struct jmploc jmploc;
2468#if __GNUC__
2469 /* Avoid longjmp clobbering */
2470 (void) &argv;
2471 (void) &argc;
2472 (void) &lastarg;
2473 (void) &flags;
2474#endif
2475
2476 /* First expand the arguments. */
2477 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
2478 setstackmark(&smark);
2479 arglist.lastp = &arglist.list;
2480 varlist.lastp = &varlist.list;
2481 arglist.list = 0;
2482 oexitstatus = exitstatus;
2483 exitstatus = 0;
2484 path = pathval();
2485 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
2486 expandarg(argp, &varlist, EXP_VARTILDE);
2487 }
2488 for (
2489 argp = cmd->ncmd.args; argp && !arglist.list;
2490 argp = argp->narg.next
2491 ) {
2492 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2493 }
2494 if (argp) {
2495 struct builtincmd *bcmd;
Eric Andersen62483552001-07-10 06:09:16 +00002496 int pseudovarflag;
Eric Andersencb57d552001-06-28 07:25:16 +00002497 bcmd = find_builtin(arglist.list->text);
Eric Andersen2870d962001-07-02 17:27:21 +00002498 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00002499 for (; argp; argp = argp->narg.next) {
2500 if (pseudovarflag && isassignment(argp->narg.text)) {
2501 expandarg(argp, &arglist, EXP_VARTILDE);
2502 continue;
2503 }
2504 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2505 }
2506 }
2507 *arglist.lastp = NULL;
2508 *varlist.lastp = NULL;
2509 expredir(cmd->ncmd.redirect);
2510 argc = 0;
2511 for (sp = arglist.list ; sp ; sp = sp->next)
2512 argc++;
2513 argv = stalloc(sizeof (char *) * (argc + 1));
2514
2515 for (sp = arglist.list ; sp ; sp = sp->next) {
2516 TRACE(("evalcommand arg: %s\n", sp->text));
2517 *argv++ = sp->text;
2518 }
2519 *argv = NULL;
2520 lastarg = NULL;
2521 if (iflag && funcnest == 0 && argc > 0)
2522 lastarg = argv[-1];
2523 argv -= argc;
2524
2525 /* Print the command if xflag is set. */
2526 if (xflag) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002527 out2c('+');
Eric Andersencb57d552001-06-28 07:25:16 +00002528 eprintlist(varlist.list);
2529 eprintlist(arglist.list);
Eric Andersen3102ac42001-07-06 04:26:23 +00002530 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00002531 }
2532
2533 /* Now locate the command. */
2534 if (argc == 0) {
2535 cmdentry.cmdtype = CMDBUILTIN;
2536 firstbltin = cmdentry.u.cmd = BLTINCMD;
2537 } else {
2538 const char *oldpath;
2539 int findflag = DO_ERR;
2540 int oldfindflag;
2541
2542 /*
2543 * Modify the command lookup path, if a PATH= assignment
2544 * is present
2545 */
2546 for (sp = varlist.list ; sp ; sp = sp->next)
2547 if (varequal(sp->text, defpathvar)) {
2548 path = sp->text + 5;
2549 findflag |= DO_BRUTE;
2550 }
2551 oldpath = path;
2552 oldfindflag = findflag;
2553 firstbltin = 0;
2554 for(;;) {
2555 find_command(argv[0], &cmdentry, findflag, path);
Eric Andersen2870d962001-07-02 17:27:21 +00002556 if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */
Eric Andersencb57d552001-06-28 07:25:16 +00002557 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002558 goto out;
2559 }
2560 /* implement bltin and command here */
2561 if (cmdentry.cmdtype != CMDBUILTIN) {
2562 break;
2563 }
2564 if (!firstbltin) {
2565 firstbltin = cmdentry.u.cmd;
2566 }
2567 if (cmdentry.u.cmd == BLTINCMD) {
2568 for(;;) {
2569 struct builtincmd *bcmd;
2570
2571 argv++;
2572 if (--argc == 0)
2573 goto found;
2574 if (!(bcmd = find_builtin(*argv))) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002575 out2fmt("%s: not found\n", *argv);
Eric Andersencb57d552001-06-28 07:25:16 +00002576 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002577 goto out;
2578 }
2579 cmdentry.u.cmd = bcmd;
2580 if (bcmd != BLTINCMD)
2581 break;
2582 }
2583 }
Eric Andersen2870d962001-07-02 17:27:21 +00002584 if (cmdentry.u.cmd == find_builtin("command")) {
Eric Andersencb57d552001-06-28 07:25:16 +00002585 argv++;
2586 if (--argc == 0) {
2587 goto found;
2588 }
2589 if (*argv[0] == '-') {
2590 if (!equal(argv[0], "-p")) {
2591 argv--;
2592 argc++;
2593 break;
2594 }
2595 argv++;
2596 if (--argc == 0) {
2597 goto found;
2598 }
2599 path = defpath;
2600 findflag |= DO_BRUTE;
2601 } else {
2602 path = oldpath;
2603 findflag = oldfindflag;
2604 }
2605 findflag |= DO_NOFUN;
2606 continue;
2607 }
2608found:
2609 break;
2610 }
2611 }
2612
2613 /* Fork off a child process if necessary. */
2614 if (cmd->ncmd.backgnd
2615 || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00002616 ) {
2617 jp = makejob(cmd, 1);
2618 mode = cmd->ncmd.backgnd;
Eric Andersencb57d552001-06-28 07:25:16 +00002619 if (forkshell(jp, cmd, mode) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00002620 goto parent; /* at end of routine */
Eric Andersencb57d552001-06-28 07:25:16 +00002621 flags |= EV_EXIT;
2622 }
2623
2624 /* This is the child process if a fork occurred. */
2625 /* Execute the command. */
2626 if (cmdentry.cmdtype == CMDFUNCTION) {
2627#ifdef DEBUG
2628 trputs("Shell function: "); trargs(argv);
2629#endif
2630 exitstatus = oexitstatus;
2631 redirect(cmd->ncmd.redirect, REDIR_PUSH);
2632 saveparam = shellparam;
2633 shellparam.malloc = 0;
2634 shellparam.nparam = argc - 1;
2635 shellparam.p = argv + 1;
2636 INTOFF;
2637 savelocalvars = localvars;
2638 localvars = NULL;
2639 INTON;
2640 if (setjmp(jmploc.loc)) {
2641 if (exception == EXSHELLPROC) {
2642 freeparam((volatile struct shparam *)
2643 &saveparam);
2644 } else {
2645 saveparam.optind = shellparam.optind;
2646 saveparam.optoff = shellparam.optoff;
2647 freeparam(&shellparam);
2648 shellparam = saveparam;
2649 }
2650 poplocalvars();
2651 localvars = savelocalvars;
2652 handler = savehandler;
2653 longjmp(handler->loc, 1);
2654 }
2655 savehandler = handler;
2656 handler = &jmploc;
2657 for (sp = varlist.list ; sp ; sp = sp->next)
2658 mklocal(sp->text);
2659 funcnest++;
2660 evaltree(cmdentry.u.func, flags & EV_TESTED);
2661 funcnest--;
2662 INTOFF;
2663 poplocalvars();
2664 localvars = savelocalvars;
2665 saveparam.optind = shellparam.optind;
2666 saveparam.optoff = shellparam.optoff;
2667 freeparam(&shellparam);
2668 shellparam = saveparam;
2669 handler = savehandler;
2670 popredir();
2671 INTON;
2672 if (evalskip == SKIPFUNC) {
2673 evalskip = 0;
2674 skipcount = 0;
2675 }
2676 if (flags & EV_EXIT)
2677 exitshell(exitstatus);
2678 } else if (cmdentry.cmdtype == CMDBUILTIN) {
2679#ifdef DEBUG
2680 trputs("builtin command: "); trargs(argv);
2681#endif
2682 mode = (cmdentry.u.cmd == EXECCMD)? 0 : REDIR_PUSH;
Eric Andersencb57d552001-06-28 07:25:16 +00002683 redirect(cmd->ncmd.redirect, mode);
2684 savecmdname = commandname;
Eric Andersen2870d962001-07-02 17:27:21 +00002685 if (IS_BUILTIN_SPECIAL(firstbltin)) {
Eric Andersencb57d552001-06-28 07:25:16 +00002686 listsetvar(varlist.list);
2687 } else {
2688 cmdenviron = varlist.list;
2689 }
2690 e = -1;
2691 if (setjmp(jmploc.loc)) {
2692 e = exception;
2693 exitstatus = (e == EXINT)? SIGINT+128 : 2;
2694 goto cmddone;
2695 }
2696 savehandler = handler;
2697 handler = &jmploc;
2698 commandname = argv[0];
2699 argptr = argv + 1;
Eric Andersen2870d962001-07-02 17:27:21 +00002700 optptr = NULL; /* initialize nextopt */
Eric Andersencb57d552001-06-28 07:25:16 +00002701 exitstatus = (*cmdentry.u.cmd->builtinfunc)(argc, argv);
2702 flushall();
2703cmddone:
Eric Andersencb57d552001-06-28 07:25:16 +00002704 cmdenviron = NULL;
2705 if (e != EXSHELLPROC) {
2706 commandname = savecmdname;
2707 if (flags & EV_EXIT)
2708 exitshell(exitstatus);
2709 }
2710 handler = savehandler;
2711 if (e != -1) {
2712 if ((e != EXERROR && e != EXEXEC)
2713 || cmdentry.u.cmd == BLTINCMD
2714 || cmdentry.u.cmd == DOTCMD
2715 || cmdentry.u.cmd == EVALCMD
2716 || cmdentry.u.cmd == EXECCMD)
2717 exraise(e);
2718 FORCEINTON;
2719 }
2720 if (cmdentry.u.cmd != EXECCMD)
2721 popredir();
Eric Andersencb57d552001-06-28 07:25:16 +00002722 } else {
2723#ifdef DEBUG
2724 trputs("normal command: "); trargs(argv);
2725#endif
2726 redirect(cmd->ncmd.redirect, 0);
2727 clearredir();
2728 for (sp = varlist.list ; sp ; sp = sp->next)
2729 setvareq(sp->text, VEXPORT|VSTACK);
2730 envp = environment();
2731 shellexec(argv, envp, path, cmdentry.u.index);
2732 }
2733 goto out;
2734
Eric Andersen2870d962001-07-02 17:27:21 +00002735parent: /* parent process gets here (if we forked) */
2736 if (mode == 0) { /* argument to fork */
Eric Andersencb57d552001-06-28 07:25:16 +00002737 INTOFF;
2738 exitstatus = waitforjob(jp);
2739 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00002740 }
2741
2742out:
2743 if (lastarg)
2744 setvar("_", lastarg, 0);
2745 popstackmark(&smark);
2746}
2747
Eric Andersen62483552001-07-10 06:09:16 +00002748/*
2749 * Evaluate a parse tree. The value is left in the global variable
2750 * exitstatus.
2751 */
2752static void
2753evaltree(n, flags)
2754 union node *n;
2755 int flags;
2756{
2757 int checkexit = 0;
2758 if (n == NULL) {
2759 TRACE(("evaltree(NULL) called\n"));
2760 goto out;
2761 }
2762 TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
2763 switch (n->type) {
2764 case NSEMI:
2765 evaltree(n->nbinary.ch1, flags & EV_TESTED);
2766 if (evalskip)
2767 goto out;
2768 evaltree(n->nbinary.ch2, flags);
2769 break;
2770 case NAND:
2771 evaltree(n->nbinary.ch1, EV_TESTED);
2772 if (evalskip || exitstatus != 0)
2773 goto out;
2774 evaltree(n->nbinary.ch2, flags);
2775 break;
2776 case NOR:
2777 evaltree(n->nbinary.ch1, EV_TESTED);
2778 if (evalskip || exitstatus == 0)
2779 goto out;
2780 evaltree(n->nbinary.ch2, flags);
2781 break;
2782 case NREDIR:
2783 expredir(n->nredir.redirect);
2784 redirect(n->nredir.redirect, REDIR_PUSH);
2785 evaltree(n->nredir.n, flags);
2786 popredir();
2787 break;
2788 case NSUBSHELL:
2789 evalsubshell(n, flags);
2790 break;
2791 case NBACKGND:
2792 evalsubshell(n, flags);
2793 break;
2794 case NIF: {
2795 evaltree(n->nif.test, EV_TESTED);
2796 if (evalskip)
2797 goto out;
2798 if (exitstatus == 0)
2799 evaltree(n->nif.ifpart, flags);
2800 else if (n->nif.elsepart)
2801 evaltree(n->nif.elsepart, flags);
2802 else
2803 exitstatus = 0;
2804 break;
2805 }
2806 case NWHILE:
2807 case NUNTIL:
2808 evalloop(n, flags);
2809 break;
2810 case NFOR:
2811 evalfor(n, flags);
2812 break;
2813 case NCASE:
2814 evalcase(n, flags);
2815 break;
2816 case NDEFUN: {
2817 struct builtincmd *bcmd;
2818 struct cmdentry entry;
2819 if (
2820 (bcmd = find_builtin(n->narg.text)) &&
2821 IS_BUILTIN_SPECIAL(bcmd)
2822 ) {
2823 out2fmt("%s is a special built-in\n", n->narg.text);
2824 exitstatus = 1;
2825 break;
2826 }
2827 entry.cmdtype = CMDFUNCTION;
2828 entry.u.func = copyfunc(n->narg.next);
2829 addcmdentry(n->narg.text, &entry);
2830 exitstatus = 0;
2831 break;
2832 }
2833 case NNOT:
2834 evaltree(n->nnot.com, EV_TESTED);
2835 exitstatus = !exitstatus;
2836 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002837
Eric Andersen62483552001-07-10 06:09:16 +00002838 case NPIPE:
2839 evalpipe(n);
2840 checkexit = 1;
2841 break;
2842 case NCMD:
2843 evalcommand(n, flags);
2844 checkexit = 1;
2845 break;
2846#ifdef DEBUG
2847 default:
2848 printf("Node type = %d\n", n->type);
2849 break;
2850#endif
2851 }
2852out:
2853 if (pendingsigs)
2854 dotrap();
2855 if (
2856 flags & EV_EXIT ||
2857 (checkexit && eflag && exitstatus && !(flags & EV_TESTED))
2858 )
2859 exitshell(exitstatus);
2860}
2861
2862/*
2863 * Kick off a subshell to evaluate a tree.
2864 */
2865
2866static void
2867evalsubshell(const union node *n, int flags)
2868{
2869 struct job *jp;
2870 int backgnd = (n->type == NBACKGND);
2871
2872 expredir(n->nredir.redirect);
2873 jp = makejob(n, 1);
2874 if (forkshell(jp, n, backgnd) == 0) {
2875 if (backgnd)
2876 flags &=~ EV_TESTED;
2877 redirect(n->nredir.redirect, 0);
2878 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
2879 }
2880 if (! backgnd) {
2881 INTOFF;
2882 exitstatus = waitforjob(jp);
2883 INTON;
2884 }
2885}
2886
2887/*
2888 * Compute the names of the files in a redirection list.
2889 */
2890
2891static void fixredir(union node *n, const char *text, int err);
2892
2893static void
2894expredir(union node *n)
2895{
2896 union node *redir;
2897
2898 for (redir = n ; redir ; redir = redir->nfile.next) {
2899 struct arglist fn;
2900 fn.lastp = &fn.list;
2901 oexitstatus = exitstatus;
2902 switch (redir->type) {
2903 case NFROMTO:
2904 case NFROM:
2905 case NTO:
2906 case NAPPEND:
2907 case NTOOV:
2908 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
2909 redir->nfile.expfname = fn.list->text;
2910 break;
2911 case NFROMFD:
2912 case NTOFD:
2913 if (redir->ndup.vname) {
2914 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
2915 fixredir(redir, fn.list->text, 1);
2916 }
2917 break;
2918 }
2919 }
2920}
2921
2922
2923/*
2924 * Execute a command inside back quotes. If it's a builtin command, we
2925 * want to save its output in a block obtained from malloc. Otherwise
2926 * we fork off a subprocess and get the output of the command via a pipe.
2927 * Should be called with interrupts off.
2928 */
2929
2930static void
2931evalbackcmd(union node *n, struct backcmd *result)
2932{
2933 int pip[2];
2934 struct job *jp;
2935 struct stackmark smark; /* unnecessary */
2936
2937 setstackmark(&smark);
2938 result->fd = -1;
2939 result->buf = NULL;
2940 result->nleft = 0;
2941 result->jp = NULL;
2942 if (n == NULL) {
2943 exitstatus = 0;
2944 goto out;
2945 }
2946 exitstatus = 0;
2947 if (pipe(pip) < 0)
2948 error("Pipe call failed");
2949 jp = makejob(n, 1);
2950 if (forkshell(jp, n, FORK_NOJOB) == 0) {
2951 FORCEINTON;
2952 close(pip[0]);
2953 if (pip[1] != 1) {
2954 close(1);
2955 dup_as_newfd(pip[1], 1);
2956 close(pip[1]);
2957 }
2958 eflag = 0;
2959 evaltree(n, EV_EXIT);
2960 }
2961 close(pip[1]);
2962 result->fd = pip[0];
2963 result->jp = jp;
2964out:
2965 popstackmark(&smark);
2966 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
2967 result->fd, result->buf, result->nleft, result->jp));
2968}
2969
2970
2971/*
2972 * Execute a simple command.
2973 */
Eric Andersencb57d552001-06-28 07:25:16 +00002974
2975/*
2976 * Search for a command. This is called before we fork so that the
2977 * location of the command will be available in the parent as well as
2978 * the child. The check for "goodname" is an overly conservative
2979 * check that the name will not be subject to expansion.
2980 */
2981
2982static void
2983prehash(n)
2984 union node *n;
2985{
2986 struct cmdentry entry;
2987
2988 if (n->type == NCMD && n->ncmd.args)
2989 if (goodname(n->ncmd.args->narg.text))
2990 find_command(n->ncmd.args->narg.text, &entry, 0,
2991 pathval());
2992}
2993
2994
Eric Andersencb57d552001-06-28 07:25:16 +00002995/*
2996 * Builtin commands. Builtin commands whose functions are closely
2997 * tied to evaluation are implemented here.
2998 */
2999
3000/*
3001 * No command given, or a bltin command with no arguments. Set the
3002 * specified variables.
3003 */
3004
3005int
3006bltincmd(argc, argv)
3007 int argc;
3008 char **argv;
3009{
3010 /*
3011 * Preserve exitstatus of a previous possible redirection
3012 * as POSIX mandates
3013 */
3014 return exitstatus;
3015}
3016
3017
3018/*
3019 * Handle break and continue commands. Break, continue, and return are
3020 * all handled by setting the evalskip flag. The evaluation routines
3021 * above all check this flag, and if it is set they start skipping
3022 * commands rather than executing them. The variable skipcount is
3023 * the number of loops to break/continue, or the number of function
3024 * levels to return. (The latter is always 1.) It should probably
3025 * be an error to break out of more loops than exist, but it isn't
3026 * in the standard shell so we don't make it one here.
3027 */
3028
3029static int
3030breakcmd(argc, argv)
3031 int argc;
3032 char **argv;
3033{
3034 int n = argc > 1 ? number(argv[1]) : 1;
3035
3036 if (n > loopnest)
3037 n = loopnest;
3038 if (n > 0) {
3039 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
3040 skipcount = n;
3041 }
3042 return 0;
3043}
3044
3045
3046/*
3047 * The return command.
3048 */
3049
3050static int
3051returncmd(argc, argv)
3052 int argc;
3053 char **argv;
3054{
3055 int ret = argc > 1 ? number(argv[1]) : oexitstatus;
3056
3057 if (funcnest) {
3058 evalskip = SKIPFUNC;
3059 skipcount = 1;
3060 return ret;
3061 }
3062 else {
3063 /* Do what ksh does; skip the rest of the file */
3064 evalskip = SKIPFILE;
3065 skipcount = 1;
3066 return ret;
3067 }
3068}
3069
3070
Eric Andersen69a20f02001-10-31 10:40:37 +00003071#ifndef CONFIG_FALSE
Eric Andersencb57d552001-06-28 07:25:16 +00003072static int
3073false_main(argc, argv)
3074 int argc;
3075 char **argv;
3076{
3077 return 1;
3078}
Eric Andersen69a20f02001-10-31 10:40:37 +00003079#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003080
Eric Andersen69a20f02001-10-31 10:40:37 +00003081#ifndef CONFIG_TRUE
Eric Andersencb57d552001-06-28 07:25:16 +00003082static int
3083true_main(argc, argv)
3084 int argc;
3085 char **argv;
3086{
3087 return 0;
3088}
3089#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003090
3091/*
3092 * Controls whether the shell is interactive or not.
3093 */
3094
3095static void setsignal(int signo);
Eric Andersen2870d962001-07-02 17:27:21 +00003096
Eric Andersenec074692001-10-31 11:05:49 +00003097#ifdef ASH_MAIL
3098static void chkmail(int silent);
3099#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003100
3101static void
3102setinteractive(int on)
3103{
3104 static int is_interactive;
Eric Andersen1c039232001-07-07 00:05:55 +00003105 static int do_banner=0;
Eric Andersen2870d962001-07-02 17:27:21 +00003106
3107 if (on == is_interactive)
3108 return;
3109 setsignal(SIGINT);
3110 setsignal(SIGQUIT);
3111 setsignal(SIGTERM);
Eric Andersenec074692001-10-31 11:05:49 +00003112#ifdef ASH_MAIL
Eric Andersen2870d962001-07-02 17:27:21 +00003113 chkmail(1);
Eric Andersenec074692001-10-31 11:05:49 +00003114#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003115 is_interactive = on;
Eric Andersen1c039232001-07-07 00:05:55 +00003116 if (do_banner==0 && is_interactive) {
3117 /* Looks like they want an interactive shell */
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003118#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
Eric Andersen1c039232001-07-07 00:05:55 +00003119 printf( "\n\n" BB_BANNER " Built-in shell (ash)\n");
3120 printf( "Enter 'help' for a list of built-in commands.\n\n");
Eric Andersend63dee42001-10-19 00:22:23 +00003121#endif
Eric Andersen1c039232001-07-07 00:05:55 +00003122 do_banner=1;
3123 }
Eric Andersen2870d962001-07-02 17:27:21 +00003124}
3125
3126static void
3127optschanged(void)
3128{
3129 setinteractive(iflag);
3130 setjobctl(mflag);
3131}
3132
Eric Andersencb57d552001-06-28 07:25:16 +00003133
3134static int
3135execcmd(argc, argv)
3136 int argc;
3137 char **argv;
3138{
3139 if (argc > 1) {
3140 struct strlist *sp;
3141
Eric Andersen2870d962001-07-02 17:27:21 +00003142 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003143 mflag = 0;
3144 optschanged();
3145 for (sp = cmdenviron; sp ; sp = sp->next)
3146 setvareq(sp->text, VEXPORT|VSTACK);
3147 shellexec(argv + 1, environment(), pathval(), 0);
3148 }
3149 return 0;
3150}
3151
3152static void
3153eprintlist(struct strlist *sp)
3154{
3155 for (; sp; sp = sp->next) {
Eric Andersen3102ac42001-07-06 04:26:23 +00003156 out2fmt(" %s",sp->text);
Eric Andersencb57d552001-06-28 07:25:16 +00003157 }
3158}
Eric Andersencb57d552001-06-28 07:25:16 +00003159
3160/*
3161 * Exec a program. Never returns. If you change this routine, you may
3162 * have to change the find_command routine as well.
3163 */
3164
Eric Andersen2870d962001-07-02 17:27:21 +00003165static const char *pathopt; /* set by padvance */
3166
Eric Andersencb57d552001-06-28 07:25:16 +00003167static void
3168shellexec(argv, envp, path, idx)
3169 char **argv, **envp;
3170 const char *path;
3171 int idx;
3172{
3173 char *cmdname;
3174 int e;
3175
3176 if (strchr(argv[0], '/') != NULL) {
3177 tryexec(argv[0], argv, envp);
3178 e = errno;
3179 } else {
3180 e = ENOENT;
3181 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3182 if (--idx < 0 && pathopt == NULL) {
3183 tryexec(cmdname, argv, envp);
3184 if (errno != ENOENT && errno != ENOTDIR)
3185 e = errno;
3186 }
3187 stunalloc(cmdname);
3188 }
3189 }
3190
3191 /* Map to POSIX errors */
3192 switch (e) {
3193 case EACCES:
3194 exerrno = 126;
3195 break;
3196 case ENOENT:
3197 exerrno = 127;
3198 break;
3199 default:
3200 exerrno = 2;
3201 break;
3202 }
3203 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3204 /* NOTREACHED */
3205}
3206
Eric Andersen2870d962001-07-02 17:27:21 +00003207/*
3208 * Clear traps on a fork.
3209 */
3210static void
3211clear_traps(void) {
3212 char **tp;
3213
3214 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
3215 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
3216 INTOFF;
3217 ckfree(*tp);
3218 *tp = NULL;
3219 if (tp != &trap[0])
3220 setsignal(tp - trap);
3221 INTON;
3222 }
3223 }
3224}
3225
3226
3227static void
3228initshellproc(void) {
3229
3230#ifdef ASH_ALIAS
3231 /* from alias.c: */
3232 {
3233 rmaliases();
3234 }
3235#endif
3236 /* from eval.c: */
3237 {
3238 exitstatus = 0;
3239 }
3240
3241 /* from exec.c: */
3242 {
3243 deletefuncs();
3244 }
3245
3246 /* from jobs.c: */
3247 {
3248 backgndpid = -1;
3249#ifdef JOBS
3250 jobctl = 0;
3251#endif
3252 }
3253
3254 /* from options.c: */
3255 {
3256 int i;
3257
3258 for (i = 0; i < NOPTS; i++)
3259 optent_val(i) = 0;
3260 optschanged();
3261
3262 }
3263
3264 /* from redir.c: */
3265 {
3266 clearredir();
3267 }
3268
3269 /* from trap.c: */
3270 {
3271 char *sm;
3272
3273 clear_traps();
3274 for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) {
3275 if (*sm == S_IGN)
3276 *sm = S_HARD_IGN;
3277 }
3278 }
3279
3280 /* from var.c: */
3281 {
3282 shprocvar();
3283 }
3284}
3285
3286static int preadbuffer(void);
3287static void pushfile (void);
Eric Andersen2870d962001-07-02 17:27:21 +00003288
3289/*
3290 * Read a character from the script, returning PEOF on end of file.
3291 * Nul characters in the input are silently discarded.
3292 */
3293
Eric Andersen3102ac42001-07-06 04:26:23 +00003294#ifndef ASH_OPTIMIZE_FOR_SIZE
Eric Andersen2870d962001-07-02 17:27:21 +00003295#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
3296static int
3297pgetc(void)
3298{
3299 return pgetc_macro();
3300}
3301#else
3302static int
3303pgetc_macro(void)
3304{
3305 return --parsenleft >= 0? *parsenextc++ : preadbuffer();
3306}
3307
3308static inline int
3309pgetc(void)
3310{
3311 return pgetc_macro();
3312}
3313#endif
3314
3315
3316/*
3317 * Undo the last call to pgetc. Only one character may be pushed back.
3318 * PEOF may be pushed back.
3319 */
3320
Eric Andersen74400cc2001-10-18 04:11:39 +00003321static void pungetc(void)
3322{
Eric Andersen2870d962001-07-02 17:27:21 +00003323 parsenleft++;
3324 parsenextc--;
3325}
3326
3327
3328static void
3329popfile(void) {
3330 struct parsefile *pf = parsefile;
3331
3332 INTOFF;
3333 if (pf->fd >= 0)
3334 close(pf->fd);
3335 if (pf->buf)
3336 ckfree(pf->buf);
3337 while (pf->strpush)
3338 popstring();
3339 parsefile = pf->prev;
3340 ckfree(pf);
3341 parsenleft = parsefile->nleft;
3342 parselleft = parsefile->lleft;
3343 parsenextc = parsefile->nextc;
3344 plinno = parsefile->linno;
3345 INTON;
3346}
3347
3348
3349/*
3350 * Return to top level.
3351 */
3352
3353static void
3354popallfiles(void) {
3355 while (parsefile != &basepf)
3356 popfile();
3357}
3358
3359/*
3360 * Close the file(s) that the shell is reading commands from. Called
3361 * after a fork is done.
3362 */
3363
Eric Andersen74400cc2001-10-18 04:11:39 +00003364static void closescript(void)
3365{
Eric Andersen2870d962001-07-02 17:27:21 +00003366 popallfiles();
3367 if (parsefile->fd > 0) {
3368 close(parsefile->fd);
3369 parsefile->fd = 0;
3370 }
3371}
3372
3373
3374/*
3375 * Like setinputfile, but takes an open file descriptor. Call this with
3376 * interrupts off.
3377 */
3378
Eric Andersen74400cc2001-10-18 04:11:39 +00003379static void setinputfd(int fd, int push)
Eric Andersen2870d962001-07-02 17:27:21 +00003380{
3381 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
3382 if (push) {
3383 pushfile();
3384 parsefile->buf = 0;
3385 } else {
3386 closescript();
3387 while (parsefile->strpush)
3388 popstring();
3389 }
3390 parsefile->fd = fd;
3391 if (parsefile->buf == NULL)
3392 parsefile->buf = ckmalloc(BUFSIZ);
3393 parselleft = parsenleft = 0;
3394 plinno = 1;
3395}
3396
3397
3398/*
3399 * Set the input to take input from a file. If push is set, push the
3400 * old input onto the stack first.
3401 */
3402
3403static void
3404setinputfile(const char *fname, int push)
3405{
3406 int fd;
3407 int myfileno2;
3408
3409 INTOFF;
3410 if ((fd = open(fname, O_RDONLY)) < 0)
3411 error("Can't open %s", fname);
3412 if (fd < 10) {
3413 myfileno2 = dup_as_newfd(fd, 10);
3414 close(fd);
3415 if (myfileno2 < 0)
3416 error("Out of file descriptors");
3417 fd = myfileno2;
3418 }
3419 setinputfd(fd, push);
3420 INTON;
3421}
3422
Eric Andersencb57d552001-06-28 07:25:16 +00003423
3424static void
Eric Andersen62483552001-07-10 06:09:16 +00003425tryexec(char *cmd, char **argv, char **envp)
3426{
Eric Andersencb57d552001-06-28 07:25:16 +00003427 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003428
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003429#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Eric Andersen3102ac42001-07-06 04:26:23 +00003430 char *name = cmd;
3431 char** argv_l=argv;
3432 int argc_l;
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003433#ifdef CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
Eric Andersen3102ac42001-07-06 04:26:23 +00003434 name = get_last_path_component(name);
3435#endif
3436 argv_l=envp;
3437 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
3438 putenv(*argv_l);
3439 argv_l=argv;
Eric Andersen62483552001-07-10 06:09:16 +00003440 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
Eric Andersen3102ac42001-07-06 04:26:23 +00003441 optind = 1;
3442 run_applet_by_name(name, argc_l, argv);
3443#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003444 execve(cmd, argv, envp);
Eric Andersencb57d552001-06-28 07:25:16 +00003445 e = errno;
3446 if (e == ENOEXEC) {
3447 INTOFF;
3448 initshellproc();
3449 setinputfile(cmd, 0);
3450 commandname = arg0 = savestr(argv[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00003451 setparam(argv + 1);
3452 exraise(EXSHELLPROC);
3453 }
3454 errno = e;
3455}
3456
Eric Andersen2870d962001-07-02 17:27:21 +00003457static char *commandtext (const union node *);
Eric Andersencb57d552001-06-28 07:25:16 +00003458
3459/*
3460 * Do a path search. The variable path (passed by reference) should be
3461 * set to the start of the path before the first call; padvance will update
3462 * this value as it proceeds. Successive calls to padvance will return
3463 * the possible path expansions in sequence. If an option (indicated by
3464 * a percent sign) appears in the path entry then the global variable
3465 * pathopt will be set to point to it; otherwise pathopt will be set to
3466 * NULL.
3467 */
3468
3469static const char *pathopt;
3470
Eric Andersen2870d962001-07-02 17:27:21 +00003471static void growstackblock(void);
3472
3473
Eric Andersencb57d552001-06-28 07:25:16 +00003474static char *
Eric Andersen2870d962001-07-02 17:27:21 +00003475padvance(const char **path, const char *name)
3476{
Eric Andersencb57d552001-06-28 07:25:16 +00003477 const char *p;
3478 char *q;
3479 const char *start;
3480 int len;
3481
3482 if (*path == NULL)
3483 return NULL;
3484 start = *path;
3485 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
Eric Andersen2870d962001-07-02 17:27:21 +00003486 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003487 while (stackblocksize() < len)
3488 growstackblock();
3489 q = stackblock();
3490 if (p != start) {
3491 memcpy(q, start, p - start);
3492 q += p - start;
3493 *q++ = '/';
3494 }
3495 strcpy(q, name);
3496 pathopt = NULL;
3497 if (*p == '%') {
3498 pathopt = ++p;
3499 while (*p && *p != ':') p++;
3500 }
3501 if (*p == ':')
3502 *path = p + 1;
3503 else
3504 *path = NULL;
3505 return stalloc(len);
3506}
3507
Eric Andersen62483552001-07-10 06:09:16 +00003508/*
3509 * Wrapper around strcmp for qsort/bsearch/...
3510 */
3511static int
3512pstrcmp(const void *a, const void *b)
3513{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003514 return strcmp((const char *) a, (*(const char *const *) b) + 1);
Eric Andersen62483552001-07-10 06:09:16 +00003515}
3516
3517/*
3518 * Find a keyword is in a sorted array.
3519 */
3520
3521static const char *const *
3522findkwd(const char *s)
3523{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003524 return bsearch(s, tokname_array + KWDOFFSET,
3525 (sizeof(tokname_array)/sizeof(const char *)) - KWDOFFSET,
3526 sizeof(const char *), pstrcmp);
Eric Andersen62483552001-07-10 06:09:16 +00003527}
Eric Andersencb57d552001-06-28 07:25:16 +00003528
3529
3530/*** Command hashing code ***/
3531
3532
3533static int
3534hashcmd(argc, argv)
3535 int argc;
3536 char **argv;
3537{
3538 struct tblentry **pp;
3539 struct tblentry *cmdp;
3540 int c;
3541 int verbose;
3542 struct cmdentry entry;
3543 char *name;
Eric Andersen62483552001-07-10 06:09:16 +00003544#ifdef ASH_ALIAS
3545 const struct alias *ap;
3546#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003547
3548 verbose = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003549 while ((c = nextopt("rvV")) != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00003550 if (c == 'r') {
3551 clearcmdentry(0);
3552 return 0;
Eric Andersen62483552001-07-10 06:09:16 +00003553 } else if (c == 'v' || c == 'V') {
3554 verbose = c;
Eric Andersencb57d552001-06-28 07:25:16 +00003555 }
3556 }
3557 if (*argptr == NULL) {
3558 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3559 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3560 if (cmdp->cmdtype != CMDBUILTIN) {
3561 printentry(cmdp, verbose);
3562 }
3563 }
3564 }
3565 return 0;
3566 }
3567 c = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003568 while ((name = *argptr++) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00003569 if ((cmdp = cmdlookup(name, 0)) != NULL
3570 && (cmdp->cmdtype == CMDNORMAL
3571 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3572 delete_cmd_entry();
Eric Andersen62483552001-07-10 06:09:16 +00003573#ifdef ASH_ALIAS
3574 /* Then look at the aliases */
Eric Andersenec074692001-10-31 11:05:49 +00003575 if ((ap = *__lookupalias(name)) != NULL) {
Eric Andersen62483552001-07-10 06:09:16 +00003576 if (verbose=='v')
3577 printf("%s is an alias for %s\n", name, ap->val);
3578 else
3579 printalias(ap);
3580 continue;
3581 }
3582#endif
3583 /* First look at the keywords */
3584 if (findkwd(name)!=0) {
3585 if (verbose=='v')
3586 printf("%s is a shell keyword\n", name);
3587 else
3588 printf(snlfmt, name);
3589 continue;
3590 }
3591
Eric Andersencb57d552001-06-28 07:25:16 +00003592 find_command(name, &entry, DO_ERR, pathval());
3593 if (entry.cmdtype == CMDUNKNOWN) c = 1;
3594 else if (verbose) {
3595 cmdp = cmdlookup(name, 0);
Eric Andersen62483552001-07-10 06:09:16 +00003596 if (cmdp) printentry(cmdp, verbose=='v');
Eric Andersencb57d552001-06-28 07:25:16 +00003597 flushall();
3598 }
Eric Andersencb57d552001-06-28 07:25:16 +00003599 }
3600 return c;
3601}
3602
Eric Andersencb57d552001-06-28 07:25:16 +00003603static void
3604printentry(cmdp, verbose)
3605 struct tblentry *cmdp;
3606 int verbose;
3607 {
3608 int idx;
3609 const char *path;
3610 char *name;
3611
Eric Andersen62483552001-07-10 06:09:16 +00003612 printf("%s%s", cmdp->cmdname, (verbose ? " is " : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00003613 if (cmdp->cmdtype == CMDNORMAL) {
3614 idx = cmdp->param.index;
3615 path = pathval();
3616 do {
3617 name = padvance(&path, cmdp->cmdname);
3618 stunalloc(name);
3619 } while (--idx >= 0);
Eric Andersen62483552001-07-10 06:09:16 +00003620 if(verbose)
3621 out1str(name);
Eric Andersencb57d552001-06-28 07:25:16 +00003622 } else if (cmdp->cmdtype == CMDBUILTIN) {
Eric Andersen62483552001-07-10 06:09:16 +00003623 if(verbose)
3624 out1str("a shell builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00003625 } else if (cmdp->cmdtype == CMDFUNCTION) {
Eric Andersencb57d552001-06-28 07:25:16 +00003626 if (verbose) {
3627 INTOFF;
Eric Andersen62483552001-07-10 06:09:16 +00003628 out1str("a function\n");
Eric Andersencb57d552001-06-28 07:25:16 +00003629 name = commandtext(cmdp->param.func);
Eric Andersen62483552001-07-10 06:09:16 +00003630 printf("%s() {\n %s\n}", cmdp->cmdname, name);
Eric Andersencb57d552001-06-28 07:25:16 +00003631 ckfree(name);
3632 INTON;
3633 }
3634#ifdef DEBUG
3635 } else {
3636 error("internal error: cmdtype %d", cmdp->cmdtype);
3637#endif
3638 }
Eric Andersen62483552001-07-10 06:09:16 +00003639 printf(snlfmt, cmdp->rehash ? "*" : nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +00003640}
3641
3642
3643
Eric Andersen1c039232001-07-07 00:05:55 +00003644/*** List the available builtins ***/
3645
3646
3647static int helpcmd(int argc, char** argv)
3648{
3649 int col, i;
Eric Andersen1c039232001-07-07 00:05:55 +00003650
Eric Andersen62483552001-07-10 06:09:16 +00003651 printf("\nBuilt-in commands:\n-------------------\n");
3652 for (col=0, i=0; i < NUMBUILTINS; i++) {
3653 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3654 builtincmds[i].name+1);
Eric Andersen1c039232001-07-07 00:05:55 +00003655 if (col > 60) {
3656 printf("\n");
3657 col = 0;
3658 }
3659 }
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003660#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Eric Andersen1c039232001-07-07 00:05:55 +00003661 {
Eric Andersen1c039232001-07-07 00:05:55 +00003662 extern const struct BB_applet applets[];
3663 extern const size_t NUM_APPLETS;
3664
Eric Andersen62483552001-07-10 06:09:16 +00003665 for (i=0; i < NUM_APPLETS; i++) {
3666
3667 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3668 applets[i].name);
Eric Andersen1c039232001-07-07 00:05:55 +00003669 if (col > 60) {
3670 printf("\n");
3671 col = 0;
3672 }
3673 }
3674 }
3675#endif
3676 printf("\n\n");
3677 return EXIT_SUCCESS;
3678}
3679
Eric Andersencb57d552001-06-28 07:25:16 +00003680/*
3681 * Resolve a command name. If you change this routine, you may have to
3682 * change the shellexec routine as well.
3683 */
3684
Eric Andersen2870d962001-07-02 17:27:21 +00003685static int prefix (const char *, const char *);
3686
Eric Andersencb57d552001-06-28 07:25:16 +00003687static void
Eric Andersen2870d962001-07-02 17:27:21 +00003688find_command(const char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003689{
3690 struct tblentry *cmdp;
3691 int idx;
3692 int prev;
3693 char *fullname;
3694 struct stat statb;
3695 int e;
3696 int bltin;
3697 int firstchange;
3698 int updatetbl;
Eric Andersen62483552001-07-10 06:09:16 +00003699 int regular;
Eric Andersencb57d552001-06-28 07:25:16 +00003700 struct builtincmd *bcmd;
3701
3702 /* If name contains a slash, don't use the hash table */
3703 if (strchr(name, '/') != NULL) {
3704 if (act & DO_ABS) {
3705 while (stat(name, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003706 if (errno != ENOENT && errno != ENOTDIR)
3707 e = errno;
3708 entry->cmdtype = CMDUNKNOWN;
3709 entry->u.index = -1;
3710 return;
3711 }
3712 entry->cmdtype = CMDNORMAL;
3713 entry->u.index = -1;
3714 return;
3715 }
3716 entry->cmdtype = CMDNORMAL;
3717 entry->u.index = 0;
3718 return;
3719 }
3720
3721 updatetbl = 1;
3722 if (act & DO_BRUTE) {
3723 firstchange = path_change(path, &bltin);
3724 } else {
3725 bltin = builtinloc;
3726 firstchange = 9999;
3727 }
3728
3729 /* If name is in the table, and not invalidated by cd, we're done */
3730 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
3731 if (cmdp->cmdtype == CMDFUNCTION) {
3732 if (act & DO_NOFUN) {
3733 updatetbl = 0;
3734 } else {
3735 goto success;
3736 }
3737 } else if (act & DO_BRUTE) {
3738 if ((cmdp->cmdtype == CMDNORMAL &&
3739 cmdp->param.index >= firstchange) ||
3740 (cmdp->cmdtype == CMDBUILTIN &&
3741 ((builtinloc < 0 && bltin >= 0) ?
3742 bltin : builtinloc) >= firstchange)) {
3743 /* need to recompute the entry */
3744 } else {
3745 goto success;
3746 }
3747 } else {
3748 goto success;
3749 }
3750 }
3751
3752 bcmd = find_builtin(name);
Eric Andersen2870d962001-07-02 17:27:21 +00003753 regular = bcmd && IS_BUILTIN_REGULAR(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00003754
3755 if (regular) {
3756 if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) {
Eric Andersen2870d962001-07-02 17:27:21 +00003757 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003758 }
3759 } else if (act & DO_BRUTE) {
3760 if (firstchange == 0) {
3761 updatetbl = 0;
3762 }
3763 }
3764
3765 /* If %builtin not in path, check for builtin next */
3766 if (regular || (bltin < 0 && bcmd)) {
3767builtin:
3768 if (!updatetbl) {
3769 entry->cmdtype = CMDBUILTIN;
3770 entry->u.cmd = bcmd;
3771 return;
3772 }
3773 INTOFF;
3774 cmdp = cmdlookup(name, 1);
3775 cmdp->cmdtype = CMDBUILTIN;
3776 cmdp->param.cmd = bcmd;
3777 INTON;
3778 goto success;
3779 }
3780
3781 /* We have to search path. */
Eric Andersen2870d962001-07-02 17:27:21 +00003782 prev = -1; /* where to start */
3783 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00003784 if (cmdp->cmdtype == CMDBUILTIN)
3785 prev = builtinloc;
3786 else
3787 prev = cmdp->param.index;
3788 }
3789
3790 e = ENOENT;
3791 idx = -1;
3792loop:
3793 while ((fullname = padvance(&path, name)) != NULL) {
3794 stunalloc(fullname);
3795 idx++;
3796 if (idx >= firstchange) {
3797 updatetbl = 0;
3798 }
3799 if (pathopt) {
3800 if (prefix("builtin", pathopt)) {
3801 if ((bcmd = find_builtin(name))) {
3802 goto builtin;
3803 }
3804 continue;
3805 } else if (!(act & DO_NOFUN) &&
3806 prefix("func", pathopt)) {
3807 /* handled below */
3808 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00003809 continue; /* ignore unimplemented options */
Eric Andersencb57d552001-06-28 07:25:16 +00003810 }
3811 }
3812 /* if rehash, don't redo absolute path names */
3813 if (fullname[0] == '/' && idx <= prev &&
3814 idx < firstchange) {
3815 if (idx < prev)
3816 continue;
3817 TRACE(("searchexec \"%s\": no change\n", name));
3818 goto success;
3819 }
3820 while (stat(fullname, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003821 if (errno != ENOENT && errno != ENOTDIR)
3822 e = errno;
3823 goto loop;
3824 }
Eric Andersen2870d962001-07-02 17:27:21 +00003825 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00003826 if (!S_ISREG(statb.st_mode))
3827 continue;
Eric Andersen2870d962001-07-02 17:27:21 +00003828 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00003829 stalloc(strlen(fullname) + 1);
3830 readcmdfile(fullname);
3831 if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
3832 error("%s not defined in %s", name, fullname);
3833 stunalloc(fullname);
3834 goto success;
3835 }
Eric Andersencb57d552001-06-28 07:25:16 +00003836 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
3837 /* If we aren't called with DO_BRUTE and cmdp is set, it must
3838 be a function and we're being called with DO_NOFUN */
3839 if (!updatetbl) {
3840 entry->cmdtype = CMDNORMAL;
3841 entry->u.index = idx;
3842 return;
3843 }
3844 INTOFF;
3845 cmdp = cmdlookup(name, 1);
3846 cmdp->cmdtype = CMDNORMAL;
3847 cmdp->param.index = idx;
3848 INTON;
3849 goto success;
3850 }
3851
3852 /* We failed. If there was an entry for this command, delete it */
3853 if (cmdp && updatetbl)
3854 delete_cmd_entry();
3855 if (act & DO_ERR)
Eric Andersen3102ac42001-07-06 04:26:23 +00003856 out2fmt("%s: %s\n", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00003857 entry->cmdtype = CMDUNKNOWN;
3858 return;
3859
3860success:
3861 cmdp->rehash = 0;
3862 entry->cmdtype = cmdp->cmdtype;
3863 entry->u = cmdp->param;
3864}
3865
3866
3867
3868/*
3869 * Search the table of builtin commands.
3870 */
3871
Eric Andersen2870d962001-07-02 17:27:21 +00003872static int
3873bstrcmp(const void *name, const void *b)
3874{
3875 return strcmp((const char *)name, (*(const char *const *) b)+1);
3876}
3877
3878static struct builtincmd *
3879find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00003880{
3881 struct builtincmd *bp;
3882
Eric Andersen2870d962001-07-02 17:27:21 +00003883 bp = bsearch(name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd),
3884 bstrcmp
Eric Andersencb57d552001-06-28 07:25:16 +00003885 );
3886 return bp;
3887}
3888
3889
3890/*
3891 * Called when a cd is done. Marks all commands so the next time they
3892 * are executed they will be rehashed.
3893 */
3894
3895static void
Eric Andersen2870d962001-07-02 17:27:21 +00003896hashcd(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00003897 struct tblentry **pp;
3898 struct tblentry *cmdp;
3899
3900 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3901 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3902 if (cmdp->cmdtype == CMDNORMAL
3903 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
3904 cmdp->rehash = 1;
3905 }
3906 }
3907}
3908
3909
3910
3911/*
3912 * Called before PATH is changed. The argument is the new value of PATH;
3913 * pathval() still returns the old value at this point. Called with
3914 * interrupts off.
3915 */
3916
3917static void
Eric Andersen2870d962001-07-02 17:27:21 +00003918changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00003919{
3920 int firstchange;
3921 int bltin;
3922
3923 firstchange = path_change(newval, &bltin);
3924 if (builtinloc < 0 && bltin >= 0)
Eric Andersen2870d962001-07-02 17:27:21 +00003925 builtinloc = bltin; /* zap builtins */
Eric Andersencb57d552001-06-28 07:25:16 +00003926 clearcmdentry(firstchange);
3927 builtinloc = bltin;
3928}
3929
3930
3931/*
3932 * Clear out command entries. The argument specifies the first entry in
3933 * PATH which has changed.
3934 */
3935
3936static void
3937clearcmdentry(firstchange)
3938 int firstchange;
3939{
3940 struct tblentry **tblp;
3941 struct tblentry **pp;
3942 struct tblentry *cmdp;
3943
3944 INTOFF;
3945 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
3946 pp = tblp;
3947 while ((cmdp = *pp) != NULL) {
3948 if ((cmdp->cmdtype == CMDNORMAL &&
3949 cmdp->param.index >= firstchange)
3950 || (cmdp->cmdtype == CMDBUILTIN &&
3951 builtinloc >= firstchange)) {
3952 *pp = cmdp->next;
3953 ckfree(cmdp);
3954 } else {
3955 pp = &cmdp->next;
3956 }
3957 }
3958 }
3959 INTON;
3960}
3961
3962
3963/*
3964 * Delete all functions.
3965 */
3966
Eric Andersencb57d552001-06-28 07:25:16 +00003967static void
Eric Andersen2870d962001-07-02 17:27:21 +00003968deletefuncs(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00003969 struct tblentry **tblp;
3970 struct tblentry **pp;
3971 struct tblentry *cmdp;
3972
3973 INTOFF;
3974 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
3975 pp = tblp;
3976 while ((cmdp = *pp) != NULL) {
3977 if (cmdp->cmdtype == CMDFUNCTION) {
3978 *pp = cmdp->next;
3979 freefunc(cmdp->param.func);
3980 ckfree(cmdp);
3981 } else {
3982 pp = &cmdp->next;
3983 }
3984 }
3985 }
3986 INTON;
3987}
3988
3989
3990
3991/*
3992 * Locate a command in the command hash table. If "add" is nonzero,
3993 * add the command to the table if it is not already present. The
3994 * variable "lastcmdentry" is set to point to the address of the link
3995 * pointing to the entry, so that delete_cmd_entry can delete the
3996 * entry.
3997 */
3998
Eric Andersen2870d962001-07-02 17:27:21 +00003999static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00004000
4001static struct tblentry *
Eric Andersen2870d962001-07-02 17:27:21 +00004002cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00004003{
4004 int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00004005 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00004006 struct tblentry *cmdp;
4007 struct tblentry **pp;
4008
4009 p = name;
4010 hashval = *p << 4;
4011 while (*p)
4012 hashval += *p++;
4013 hashval &= 0x7FFF;
4014 pp = &cmdtable[hashval % CMDTABLESIZE];
4015 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4016 if (equal(cmdp->cmdname, name))
4017 break;
4018 pp = &cmdp->next;
4019 }
4020 if (add && cmdp == NULL) {
4021 INTOFF;
4022 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4023 + strlen(name) + 1);
4024 cmdp->next = NULL;
4025 cmdp->cmdtype = CMDUNKNOWN;
4026 cmdp->rehash = 0;
4027 strcpy(cmdp->cmdname, name);
4028 INTON;
4029 }
4030 lastcmdentry = pp;
4031 return cmdp;
4032}
4033
4034/*
4035 * Delete the command entry returned on the last lookup.
4036 */
4037
4038static void
4039delete_cmd_entry() {
4040 struct tblentry *cmdp;
4041
4042 INTOFF;
4043 cmdp = *lastcmdentry;
4044 *lastcmdentry = cmdp->next;
4045 ckfree(cmdp);
4046 INTON;
4047}
4048
4049
4050
Eric Andersencb57d552001-06-28 07:25:16 +00004051
4052
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004053static const unsigned char nodesize[26] = {
Eric Andersen62483552001-07-10 06:09:16 +00004054 ALIGN(sizeof (struct nbinary)),
4055 ALIGN(sizeof (struct ncmd)),
4056 ALIGN(sizeof (struct npipe)),
4057 ALIGN(sizeof (struct nredir)),
4058 ALIGN(sizeof (struct nredir)),
4059 ALIGN(sizeof (struct nredir)),
4060 ALIGN(sizeof (struct nbinary)),
4061 ALIGN(sizeof (struct nbinary)),
4062 ALIGN(sizeof (struct nif)),
4063 ALIGN(sizeof (struct nbinary)),
4064 ALIGN(sizeof (struct nbinary)),
4065 ALIGN(sizeof (struct nfor)),
4066 ALIGN(sizeof (struct ncase)),
4067 ALIGN(sizeof (struct nclist)),
4068 ALIGN(sizeof (struct narg)),
4069 ALIGN(sizeof (struct narg)),
4070 ALIGN(sizeof (struct nfile)),
4071 ALIGN(sizeof (struct nfile)),
4072 ALIGN(sizeof (struct nfile)),
4073 ALIGN(sizeof (struct nfile)),
4074 ALIGN(sizeof (struct nfile)),
4075 ALIGN(sizeof (struct ndup)),
4076 ALIGN(sizeof (struct ndup)),
4077 ALIGN(sizeof (struct nhere)),
4078 ALIGN(sizeof (struct nhere)),
4079 ALIGN(sizeof (struct nnot)),
4080};
Eric Andersencb57d552001-06-28 07:25:16 +00004081
Eric Andersencb57d552001-06-28 07:25:16 +00004082
4083
4084/*
4085 * Delete a function if it exists.
4086 */
4087
4088static void
Eric Andersen2870d962001-07-02 17:27:21 +00004089unsetfunc(char *name)
4090{
Eric Andersencb57d552001-06-28 07:25:16 +00004091 struct tblentry *cmdp;
4092
4093 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
4094 freefunc(cmdp->param.func);
4095 delete_cmd_entry();
4096 }
4097}
4098
Eric Andersen2870d962001-07-02 17:27:21 +00004099
4100/*
Eric Andersencb57d552001-06-28 07:25:16 +00004101 * Locate and print what a word is...
4102 */
4103
4104static int
Eric Andersen62483552001-07-10 06:09:16 +00004105typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004106{
4107 int i;
4108 int err = 0;
Eric Andersen62483552001-07-10 06:09:16 +00004109 char *argv_a[2];
4110
4111 argv_a[1] = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004112
4113 for (i = 1; i < argc; i++) {
Eric Andersen62483552001-07-10 06:09:16 +00004114 argv_a[0] = argv[i];
4115 argptr = argv_a;
4116 optptr = "v";
4117 err |= hashcmd(argc, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00004118 }
4119 return err;
4120}
4121
Eric Andersen2870d962001-07-02 17:27:21 +00004122#ifdef ASH_CMDCMD
Eric Andersencb57d552001-06-28 07:25:16 +00004123static int
4124commandcmd(argc, argv)
4125 int argc;
4126 char **argv;
4127{
4128 int c;
4129 int default_path = 0;
4130 int verify_only = 0;
4131 int verbose_verify_only = 0;
4132
4133 while ((c = nextopt("pvV")) != '\0')
4134 switch (c) {
4135 case 'p':
4136 default_path = 1;
4137 break;
4138 case 'v':
4139 verify_only = 1;
4140 break;
4141 case 'V':
4142 verbose_verify_only = 1;
4143 break;
Eric Andersencb57d552001-06-28 07:25:16 +00004144 }
4145
4146 if (default_path + verify_only + verbose_verify_only > 1 ||
4147 !*argptr) {
Eric Andersen62483552001-07-10 06:09:16 +00004148 out2str(
4149 "command [-p] command [arg ...]\n"
4150 "command {-v|-V} command\n");
Eric Andersencb57d552001-06-28 07:25:16 +00004151 return EX_USAGE;
4152 }
4153
Eric Andersencb57d552001-06-28 07:25:16 +00004154 if (verify_only || verbose_verify_only) {
Eric Andersen62483552001-07-10 06:09:16 +00004155 char *argv_a[2];
4156
4157 argv_a[1] = 0;
4158 argv_a[0] = *argptr;
4159 argptr = argv_a;
4160 optptr = verbose_verify_only ? "v" : "V"; /* reverse special */
4161 return hashcmd(argc, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00004162 }
Eric Andersencb57d552001-06-28 07:25:16 +00004163
4164 return 0;
4165}
Eric Andersen2870d962001-07-02 17:27:21 +00004166#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004167
4168static int
4169path_change(newval, bltin)
4170 const char *newval;
4171 int *bltin;
4172{
4173 const char *old, *new;
4174 int idx;
4175 int firstchange;
4176
4177 old = pathval();
4178 new = newval;
Eric Andersen2870d962001-07-02 17:27:21 +00004179 firstchange = 9999; /* assume no change */
Eric Andersencb57d552001-06-28 07:25:16 +00004180 idx = 0;
4181 *bltin = -1;
4182 for (;;) {
4183 if (*old != *new) {
4184 firstchange = idx;
4185 if ((*old == '\0' && *new == ':')
4186 || (*old == ':' && *new == '\0'))
4187 firstchange++;
Eric Andersen2870d962001-07-02 17:27:21 +00004188 old = new; /* ignore subsequent differences */
Eric Andersencb57d552001-06-28 07:25:16 +00004189 }
4190 if (*new == '\0')
4191 break;
4192 if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1))
4193 *bltin = idx;
4194 if (*new == ':') {
4195 idx++;
4196 }
4197 new++, old++;
4198 }
4199 if (builtinloc >= 0 && *bltin < 0)
4200 firstchange = 0;
4201 return firstchange;
4202}
Eric Andersencb57d552001-06-28 07:25:16 +00004203/*
4204 * Routines to expand arguments to commands. We have to deal with
4205 * backquotes, shell variables, and file metacharacters.
4206 */
4207/*
4208 * _rmescape() flags
4209 */
Eric Andersen2870d962001-07-02 17:27:21 +00004210#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4211#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Eric Andersencb57d552001-06-28 07:25:16 +00004212
4213/*
4214 * Structure specifying which parts of the string should be searched
4215 * for IFS characters.
4216 */
4217
4218struct ifsregion {
Eric Andersen2870d962001-07-02 17:27:21 +00004219 struct ifsregion *next; /* next region in list */
4220 int begoff; /* offset of start of region */
4221 int endoff; /* offset of end of region */
4222 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004223};
4224
4225
Eric Andersen2870d962001-07-02 17:27:21 +00004226static char *expdest; /* output of current string */
4227static struct nodelist *argbackq; /* list of back quote expressions */
4228static struct ifsregion ifsfirst; /* first struct in list of ifs regions */
4229static struct ifsregion *ifslastp; /* last struct in list */
4230static struct arglist exparg; /* holds expanded arg list */
Eric Andersencb57d552001-06-28 07:25:16 +00004231
Eric Andersen2870d962001-07-02 17:27:21 +00004232static void argstr (char *, int);
4233static char *exptilde (char *, int);
4234static void expbackq (union node *, int, int);
4235static int subevalvar (char *, char *, int, int, int, int, int);
Eric Andersen2870d962001-07-02 17:27:21 +00004236static int varisset (char *, int);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004237static void strtodest (const char *, int, int);
Eric Andersen2870d962001-07-02 17:27:21 +00004238static void varvalue (char *, int, int);
4239static void recordregion (int, int, int);
4240static void removerecordregions (int);
4241static void ifsbreakup (char *, struct arglist *);
4242static void ifsfree (void);
4243static void expandmeta (struct strlist *, int);
Eric Andersen62483552001-07-10 06:09:16 +00004244#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00004245#define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB)
4246#if !defined(GLOB_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00004247static void addglob (const glob_t *);
Eric Andersencb57d552001-06-28 07:25:16 +00004248#endif
4249#endif
Eric Andersen62483552001-07-10 06:09:16 +00004250#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersen2870d962001-07-02 17:27:21 +00004251static void expmeta (char *, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004252#endif
Eric Andersen62483552001-07-10 06:09:16 +00004253#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersen2870d962001-07-02 17:27:21 +00004254static struct strlist *expsort (struct strlist *);
4255static struct strlist *msort (struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004256#endif
Eric Andersen2870d962001-07-02 17:27:21 +00004257static int patmatch (char *, char *, int);
Eric Andersen62483552001-07-10 06:09:16 +00004258#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00004259static int patmatch2 (char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004260#else
Eric Andersen2870d962001-07-02 17:27:21 +00004261static int pmatch (char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004262#define patmatch2 patmatch
4263#endif
Eric Andersen2870d962001-07-02 17:27:21 +00004264static char *cvtnum (int, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004265
4266/*
4267 * Expand shell variables and backquotes inside a here document.
4268 */
4269
Eric Andersen2870d962001-07-02 17:27:21 +00004270/* arg: the document, fd: where to write the expanded version */
Eric Andersen62483552001-07-10 06:09:16 +00004271static inline void
Eric Andersen2870d962001-07-02 17:27:21 +00004272expandhere(union node *arg, int fd)
4273{
Eric Andersencb57d552001-06-28 07:25:16 +00004274 herefd = fd;
4275 expandarg(arg, (struct arglist *)NULL, 0);
4276 xwrite(fd, stackblock(), expdest - stackblock());
4277}
4278
4279
4280/*
4281 * Perform variable substitution and command substitution on an argument,
4282 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4283 * perform splitting and file name expansion. When arglist is NULL, perform
4284 * here document expansion.
4285 */
4286
4287static void
4288expandarg(arg, arglist, flag)
4289 union node *arg;
4290 struct arglist *arglist;
4291 int flag;
4292{
4293 struct strlist *sp;
4294 char *p;
4295
4296 argbackq = arg->narg.backquote;
4297 STARTSTACKSTR(expdest);
4298 ifsfirst.next = NULL;
4299 ifslastp = NULL;
4300 argstr(arg->narg.text, flag);
4301 if (arglist == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00004302 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004303 }
4304 STPUTC('\0', expdest);
4305 p = grabstackstr(expdest);
4306 exparg.lastp = &exparg.list;
4307 /*
4308 * TODO - EXP_REDIR
4309 */
4310 if (flag & EXP_FULL) {
4311 ifsbreakup(p, &exparg);
4312 *exparg.lastp = NULL;
4313 exparg.lastp = &exparg.list;
4314 expandmeta(exparg.list, flag);
4315 } else {
4316 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4317 rmescapes(p);
4318 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4319 sp->text = p;
4320 *exparg.lastp = sp;
4321 exparg.lastp = &sp->next;
4322 }
4323 ifsfree();
4324 *exparg.lastp = NULL;
4325 if (exparg.list) {
4326 *arglist->lastp = exparg.list;
4327 arglist->lastp = exparg.lastp;
4328 }
4329}
4330
4331
Eric Andersen62483552001-07-10 06:09:16 +00004332/*
4333 * Expand a variable, and return a pointer to the next character in the
4334 * input string.
4335 */
4336
Eric Andersen74400cc2001-10-18 04:11:39 +00004337static inline char * evalvar(char *p, int flag)
Eric Andersen62483552001-07-10 06:09:16 +00004338{
4339 int subtype;
4340 int varflags;
4341 char *var;
4342 const char *val;
4343 int patloc;
4344 int c;
4345 int set;
4346 int special;
4347 int startloc;
4348 int varlen;
4349 int easy;
4350 int quotes = flag & (EXP_FULL | EXP_CASE);
4351
4352 varflags = *p++;
4353 subtype = varflags & VSTYPE;
4354 var = p;
4355 special = 0;
4356 if (! is_name(*p))
4357 special = 1;
4358 p = strchr(p, '=') + 1;
4359again: /* jump here after setting a variable with ${var=text} */
4360 if (special) {
4361 set = varisset(var, varflags & VSNUL);
4362 val = NULL;
4363 } else {
4364 val = lookupvar(var);
4365 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
4366 val = NULL;
4367 set = 0;
4368 } else
4369 set = 1;
4370 }
4371 varlen = 0;
4372 startloc = expdest - stackblock();
4373 if (set && subtype != VSPLUS) {
4374 /* insert the value of the variable */
4375 if (special) {
4376 varvalue(var, varflags & VSQUOTE, flag);
4377 if (subtype == VSLENGTH) {
4378 varlen = expdest - stackblock() - startloc;
4379 STADJUST(-varlen, expdest);
4380 }
4381 } else {
4382 if (subtype == VSLENGTH) {
4383 varlen = strlen(val);
4384 } else {
4385 strtodest(
4386 val,
4387 varflags & VSQUOTE ?
4388 DQSYNTAX : BASESYNTAX,
4389 quotes
4390 );
4391 }
4392 }
4393 }
4394
4395 if (subtype == VSPLUS)
4396 set = ! set;
4397
4398 easy = ((varflags & VSQUOTE) == 0 ||
4399 (*var == '@' && shellparam.nparam != 1));
4400
4401
4402 switch (subtype) {
4403 case VSLENGTH:
4404 expdest = cvtnum(varlen, expdest);
4405 goto record;
4406
4407 case VSNORMAL:
4408 if (!easy)
4409 break;
4410record:
4411 recordregion(startloc, expdest - stackblock(),
4412 varflags & VSQUOTE);
4413 break;
4414
4415 case VSPLUS:
4416 case VSMINUS:
4417 if (!set) {
4418 argstr(p, flag);
4419 break;
4420 }
4421 if (easy)
4422 goto record;
4423 break;
4424
4425 case VSTRIMLEFT:
4426 case VSTRIMLEFTMAX:
4427 case VSTRIMRIGHT:
4428 case VSTRIMRIGHTMAX:
4429 if (!set)
4430 break;
4431 /*
4432 * Terminate the string and start recording the pattern
4433 * right after it
4434 */
4435 STPUTC('\0', expdest);
4436 patloc = expdest - stackblock();
4437 if (subevalvar(p, NULL, patloc, subtype,
4438 startloc, varflags, quotes) == 0) {
4439 int amount = (expdest - stackblock() - patloc) + 1;
4440 STADJUST(-amount, expdest);
4441 }
4442 /* Remove any recorded regions beyond start of variable */
4443 removerecordregions(startloc);
4444 goto record;
4445
4446 case VSASSIGN:
4447 case VSQUESTION:
4448 if (!set) {
4449 if (subevalvar(p, var, 0, subtype, startloc,
4450 varflags, quotes)) {
4451 varflags &= ~VSNUL;
4452 /*
4453 * Remove any recorded regions beyond
4454 * start of variable
4455 */
4456 removerecordregions(startloc);
4457 goto again;
4458 }
4459 break;
4460 }
4461 if (easy)
4462 goto record;
4463 break;
4464
4465#ifdef DEBUG
4466 default:
4467 abort();
4468#endif
4469 }
4470
4471 if (subtype != VSNORMAL) { /* skip to end of alternative */
4472 int nesting = 1;
4473 for (;;) {
4474 if ((c = *p++) == CTLESC)
4475 p++;
4476 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
4477 if (set)
4478 argbackq = argbackq->next;
4479 } else if (c == CTLVAR) {
4480 if ((*p++ & VSTYPE) != VSNORMAL)
4481 nesting++;
4482 } else if (c == CTLENDVAR) {
4483 if (--nesting == 0)
4484 break;
4485 }
4486 }
4487 }
4488 return p;
4489}
4490
Eric Andersencb57d552001-06-28 07:25:16 +00004491
4492/*
4493 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4494 * characters to allow for further processing. Otherwise treat
4495 * $@ like $* since no splitting will be performed.
4496 */
4497
4498static void
4499argstr(p, flag)
4500 char *p;
4501 int flag;
4502{
4503 char c;
Eric Andersen2870d962001-07-02 17:27:21 +00004504 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
Eric Andersencb57d552001-06-28 07:25:16 +00004505 int firsteq = 1;
4506
4507 if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
4508 p = exptilde(p, flag);
4509 for (;;) {
4510 switch (c = *p++) {
4511 case '\0':
4512 case CTLENDVAR: /* ??? */
4513 goto breakloop;
4514 case CTLQUOTEMARK:
4515 /* "$@" syntax adherence hack */
4516 if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
4517 break;
4518 if ((flag & EXP_FULL) != 0)
4519 STPUTC(c, expdest);
4520 break;
4521 case CTLESC:
4522 if (quotes)
4523 STPUTC(c, expdest);
4524 c = *p++;
4525 STPUTC(c, expdest);
4526 break;
4527 case CTLVAR:
4528 p = evalvar(p, flag);
4529 break;
4530 case CTLBACKQ:
4531 case CTLBACKQ|CTLQUOTE:
4532 expbackq(argbackq->n, c & CTLQUOTE, flag);
4533 argbackq = argbackq->next;
4534 break;
4535#ifdef ASH_MATH_SUPPORT
4536 case CTLENDARI:
4537 expari(flag);
4538 break;
Eric Andersen2870d962001-07-02 17:27:21 +00004539#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004540 case ':':
4541 case '=':
4542 /*
4543 * sort of a hack - expand tildes in variable
4544 * assignments (after the first '=' and after ':'s).
4545 */
4546 STPUTC(c, expdest);
4547 if (flag & EXP_VARTILDE && *p == '~') {
4548 if (c == '=') {
4549 if (firsteq)
4550 firsteq = 0;
4551 else
4552 break;
4553 }
4554 p = exptilde(p, flag);
4555 }
4556 break;
4557 default:
4558 STPUTC(c, expdest);
4559 }
4560 }
4561breakloop:;
4562 return;
4563}
4564
4565static char *
4566exptilde(p, flag)
4567 char *p;
4568 int flag;
4569{
4570 char c, *startp = p;
4571 struct passwd *pw;
4572 const char *home;
4573 int quotes = flag & (EXP_FULL | EXP_CASE);
4574
4575 while ((c = *p) != '\0') {
4576 switch(c) {
4577 case CTLESC:
4578 return (startp);
4579 case CTLQUOTEMARK:
4580 return (startp);
4581 case ':':
4582 if (flag & EXP_VARTILDE)
4583 goto done;
4584 break;
4585 case '/':
4586 goto done;
4587 }
4588 p++;
4589 }
4590done:
4591 *p = '\0';
4592 if (*(startp+1) == '\0') {
4593 if ((home = lookupvar("HOME")) == NULL)
4594 goto lose;
4595 } else {
4596 if ((pw = getpwnam(startp+1)) == NULL)
4597 goto lose;
4598 home = pw->pw_dir;
4599 }
4600 if (*home == '\0')
4601 goto lose;
4602 *p = c;
4603 strtodest(home, SQSYNTAX, quotes);
4604 return (p);
4605lose:
4606 *p = c;
4607 return (startp);
4608}
4609
4610
Eric Andersen2870d962001-07-02 17:27:21 +00004611static void
4612removerecordregions(int endoff)
Eric Andersencb57d552001-06-28 07:25:16 +00004613{
4614 if (ifslastp == NULL)
4615 return;
4616
4617 if (ifsfirst.endoff > endoff) {
4618 while (ifsfirst.next != NULL) {
4619 struct ifsregion *ifsp;
4620 INTOFF;
4621 ifsp = ifsfirst.next->next;
4622 ckfree(ifsfirst.next);
4623 ifsfirst.next = ifsp;
4624 INTON;
4625 }
4626 if (ifsfirst.begoff > endoff)
4627 ifslastp = NULL;
4628 else {
4629 ifslastp = &ifsfirst;
4630 ifsfirst.endoff = endoff;
4631 }
4632 return;
4633 }
Eric Andersen2870d962001-07-02 17:27:21 +00004634
Eric Andersencb57d552001-06-28 07:25:16 +00004635 ifslastp = &ifsfirst;
4636 while (ifslastp->next && ifslastp->next->begoff < endoff)
4637 ifslastp=ifslastp->next;
4638 while (ifslastp->next != NULL) {
4639 struct ifsregion *ifsp;
4640 INTOFF;
4641 ifsp = ifslastp->next->next;
4642 ckfree(ifslastp->next);
4643 ifslastp->next = ifsp;
4644 INTON;
4645 }
4646 if (ifslastp->endoff > endoff)
4647 ifslastp->endoff = endoff;
4648}
4649
4650
4651#ifdef ASH_MATH_SUPPORT
4652/*
4653 * Expand arithmetic expression. Backup to start of expression,
4654 * evaluate, place result in (backed up) result, adjust string position.
4655 */
4656static void
Eric Andersen2870d962001-07-02 17:27:21 +00004657expari(int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004658{
4659 char *p, *start;
Eric Andersen34506362001-08-02 05:02:46 +00004660 int errcode;
Eric Andersencb57d552001-06-28 07:25:16 +00004661 int result;
4662 int begoff;
4663 int quotes = flag & (EXP_FULL | EXP_CASE);
4664 int quoted;
4665
Eric Andersen2870d962001-07-02 17:27:21 +00004666 /* ifsfree(); */
Eric Andersencb57d552001-06-28 07:25:16 +00004667
4668 /*
4669 * This routine is slightly over-complicated for
4670 * efficiency. First we make sure there is
4671 * enough space for the result, which may be bigger
4672 * than the expression if we add exponentation. Next we
4673 * scan backwards looking for the start of arithmetic. If the
4674 * next previous character is a CTLESC character, then we
4675 * have to rescan starting from the beginning since CTLESC
4676 * characters have to be processed left to right.
4677 */
4678 CHECKSTRSPACE(10, expdest);
4679 USTPUTC('\0', expdest);
4680 start = stackblock();
4681 p = expdest - 1;
4682 while (*p != CTLARI && p >= start)
4683 --p;
4684 if (*p != CTLARI)
4685 error("missing CTLARI (shouldn't happen)");
4686 if (p > start && *(p-1) == CTLESC)
4687 for (p = start; *p != CTLARI; p++)
4688 if (*p == CTLESC)
4689 p++;
4690
4691 if (p[1] == '"')
4692 quoted=1;
4693 else
4694 quoted=0;
4695 begoff = p - start;
4696 removerecordregions(begoff);
4697 if (quotes)
4698 rmescapes(p+2);
Eric Andersen34506362001-08-02 05:02:46 +00004699 result = arith(p+2, &errcode);
4700 if (errcode < 0) {
4701 if(errcode == -2)
4702 error("divide by zero");
4703 else
4704 error("syntax error: \"%s\"\n", p+2);
4705 }
Eric Andersen3102ac42001-07-06 04:26:23 +00004706 snprintf(p, 12, "%d", result);
Eric Andersencb57d552001-06-28 07:25:16 +00004707
4708 while (*p++)
4709 ;
4710
4711 if (quoted == 0)
4712 recordregion(begoff, p - 1 - start, 0);
4713 result = expdest - p + 1;
4714 STADJUST(-result, expdest);
4715}
Eric Andersen2870d962001-07-02 17:27:21 +00004716#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004717
4718/*
4719 * Expand stuff in backwards quotes.
4720 */
4721
4722static void
4723expbackq(cmd, quoted, flag)
4724 union node *cmd;
4725 int quoted;
4726 int flag;
4727{
4728 volatile struct backcmd in;
4729 int i;
4730 char buf[128];
4731 char *p;
4732 char *dest = expdest;
4733 volatile struct ifsregion saveifs;
4734 struct ifsregion *volatile savelastp;
4735 struct nodelist *volatile saveargbackq;
4736 char lastc;
4737 int startloc = dest - stackblock();
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004738 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +00004739 volatile int saveherefd;
4740 int quotes = flag & (EXP_FULL | EXP_CASE);
4741 struct jmploc jmploc;
4742 struct jmploc *volatile savehandler;
4743 int ex;
4744
4745#if __GNUC__
4746 /* Avoid longjmp clobbering */
4747 (void) &dest;
4748 (void) &syntax;
4749#endif
4750
4751 in.fd = -1;
4752 in.buf = 0;
4753 in.jp = 0;
4754
4755 INTOFF;
4756 saveifs = ifsfirst;
4757 savelastp = ifslastp;
4758 saveargbackq = argbackq;
4759 saveherefd = herefd;
4760 herefd = -1;
4761 if ((ex = setjmp(jmploc.loc))) {
4762 goto err1;
4763 }
4764 savehandler = handler;
4765 handler = &jmploc;
4766 INTON;
4767 p = grabstackstr(dest);
4768 evalbackcmd(cmd, (struct backcmd *) &in);
4769 ungrabstackstr(p, dest);
4770err1:
4771 INTOFF;
4772 ifsfirst = saveifs;
4773 ifslastp = savelastp;
4774 argbackq = saveargbackq;
4775 herefd = saveherefd;
4776 if (ex) {
4777 goto err2;
4778 }
4779
4780 p = in.buf;
4781 lastc = '\0';
4782 for (;;) {
4783 if (--in.nleft < 0) {
4784 if (in.fd < 0)
4785 break;
Eric Andersen7467c8d2001-07-12 20:26:32 +00004786 i = safe_read(in.fd, buf, sizeof buf);
Eric Andersencb57d552001-06-28 07:25:16 +00004787 TRACE(("expbackq: read returns %d\n", i));
4788 if (i <= 0)
4789 break;
4790 p = buf;
4791 in.nleft = i - 1;
4792 }
4793 lastc = *p++;
4794 if (lastc != '\0') {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004795 if (quotes && SIT(lastc, syntax) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +00004796 STPUTC(CTLESC, dest);
4797 STPUTC(lastc, dest);
4798 }
4799 }
4800
4801 /* Eat all trailing newlines */
4802 for (; dest > stackblock() && dest[-1] == '\n';)
4803 STUNPUTC(dest);
4804
4805err2:
4806 if (in.fd >= 0)
4807 close(in.fd);
4808 if (in.buf)
4809 ckfree(in.buf);
4810 if (in.jp)
4811 exitstatus = waitforjob(in.jp);
4812 handler = savehandler;
4813 if (ex) {
4814 longjmp(handler->loc, 1);
4815 }
4816 if (quoted == 0)
4817 recordregion(startloc, dest - stackblock(), 0);
4818 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4819 (dest - stackblock()) - startloc,
4820 (dest - stackblock()) - startloc,
4821 stackblock() + startloc));
4822 expdest = dest;
4823 INTON;
4824}
4825
Eric Andersencb57d552001-06-28 07:25:16 +00004826static int
4827subevalvar(p, str, strloc, subtype, startloc, varflags, quotes)
4828 char *p;
4829 char *str;
4830 int strloc;
4831 int subtype;
4832 int startloc;
4833 int varflags;
4834 int quotes;
4835{
4836 char *startp;
4837 char *loc = NULL;
4838 char *q;
4839 int c = 0;
4840 int saveherefd = herefd;
4841 struct nodelist *saveargbackq = argbackq;
4842 int amount;
4843
4844 herefd = -1;
4845 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
4846 STACKSTRNUL(expdest);
4847 herefd = saveherefd;
4848 argbackq = saveargbackq;
4849 startp = stackblock() + startloc;
4850 if (str == NULL)
4851 str = stackblock() + strloc;
4852
4853 switch (subtype) {
4854 case VSASSIGN:
4855 setvar(str, startp, 0);
4856 amount = startp - expdest;
4857 STADJUST(amount, expdest);
4858 varflags &= ~VSNUL;
4859 if (c != 0)
4860 *loc = c;
4861 return 1;
4862
4863 case VSQUESTION:
4864 if (*p != CTLENDVAR) {
Eric Andersen3102ac42001-07-06 04:26:23 +00004865 out2fmt(snlfmt, startp);
Eric Andersencb57d552001-06-28 07:25:16 +00004866 error((char *)NULL);
4867 }
4868 error("%.*s: parameter %snot set", p - str - 1,
4869 str, (varflags & VSNUL) ? "null or "
4870 : nullstr);
4871 /* NOTREACHED */
4872
4873 case VSTRIMLEFT:
4874 for (loc = startp; loc < str; loc++) {
4875 c = *loc;
4876 *loc = '\0';
4877 if (patmatch2(str, startp, quotes))
4878 goto recordleft;
4879 *loc = c;
4880 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00004881 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00004882 }
4883 return 0;
4884
4885 case VSTRIMLEFTMAX:
4886 for (loc = str - 1; loc >= startp;) {
4887 c = *loc;
4888 *loc = '\0';
4889 if (patmatch2(str, startp, quotes))
4890 goto recordleft;
4891 *loc = c;
4892 loc--;
4893 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
4894 for (q = startp; q < loc; q++)
4895 if (*q == CTLESC)
4896 q++;
4897 if (q > loc)
4898 loc--;
4899 }
4900 }
4901 return 0;
4902
4903 case VSTRIMRIGHT:
Eric Andersen2870d962001-07-02 17:27:21 +00004904 for (loc = str - 1; loc >= startp;) {
Eric Andersencb57d552001-06-28 07:25:16 +00004905 if (patmatch2(str, loc, quotes))
4906 goto recordright;
4907 loc--;
Eric Andersen2870d962001-07-02 17:27:21 +00004908 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
Eric Andersencb57d552001-06-28 07:25:16 +00004909 for (q = startp; q < loc; q++)
4910 if (*q == CTLESC)
4911 q++;
4912 if (q > loc)
4913 loc--;
4914 }
4915 }
4916 return 0;
4917
4918 case VSTRIMRIGHTMAX:
4919 for (loc = startp; loc < str - 1; loc++) {
4920 if (patmatch2(str, loc, quotes))
4921 goto recordright;
4922 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00004923 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00004924 }
4925 return 0;
4926
4927#ifdef DEBUG
4928 default:
4929 abort();
4930#endif
4931 }
4932
4933recordleft:
4934 *loc = c;
4935 amount = ((str - 1) - (loc - startp)) - expdest;
4936 STADJUST(amount, expdest);
4937 while (loc != str - 1)
4938 *startp++ = *loc++;
4939 return 1;
4940
4941recordright:
4942 amount = loc - expdest;
4943 STADJUST(amount, expdest);
4944 STPUTC('\0', expdest);
4945 STADJUST(-1, expdest);
4946 return 1;
4947}
4948
4949
4950/*
Eric Andersencb57d552001-06-28 07:25:16 +00004951 * Test whether a specialized variable is set.
4952 */
4953
4954static int
4955varisset(name, nulok)
4956 char *name;
4957 int nulok;
4958{
4959 if (*name == '!')
4960 return backgndpid != -1;
4961 else if (*name == '@' || *name == '*') {
4962 if (*shellparam.p == NULL)
4963 return 0;
4964
4965 if (nulok) {
4966 char **av;
4967
4968 for (av = shellparam.p; *av; av++)
4969 if (**av != '\0')
4970 return 1;
4971 return 0;
4972 }
4973 } else if (is_digit(*name)) {
4974 char *ap;
4975 int num = atoi(name);
4976
4977 if (num > shellparam.nparam)
4978 return 0;
4979
4980 if (num == 0)
4981 ap = arg0;
4982 else
4983 ap = shellparam.p[num - 1];
4984
4985 if (nulok && (ap == NULL || *ap == '\0'))
4986 return 0;
4987 }
4988 return 1;
4989}
4990
Eric Andersencb57d552001-06-28 07:25:16 +00004991/*
4992 * Put a string on the stack.
4993 */
4994
4995static void
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004996strtodest(const char *p, int syntax, int quotes)
Eric Andersencb57d552001-06-28 07:25:16 +00004997{
4998 while (*p) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004999 if (quotes && SIT(*p,syntax) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +00005000 STPUTC(CTLESC, expdest);
5001 STPUTC(*p++, expdest);
5002 }
5003}
5004
Eric Andersencb57d552001-06-28 07:25:16 +00005005/*
5006 * Add the value of a specialized variable to the stack string.
5007 */
5008
5009static void
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005010varvalue(char *name, int quoted, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00005011{
5012 int num;
5013 char *p;
5014 int i;
5015 int sep;
5016 int sepq = 0;
5017 char **ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005018 int syntax;
Eric Andersencb57d552001-06-28 07:25:16 +00005019 int allow_split = flags & EXP_FULL;
5020 int quotes = flags & (EXP_FULL | EXP_CASE);
5021
5022 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5023 switch (*name) {
5024 case '$':
5025 num = rootpid;
5026 goto numvar;
5027 case '?':
5028 num = oexitstatus;
5029 goto numvar;
5030 case '#':
5031 num = shellparam.nparam;
5032 goto numvar;
5033 case '!':
5034 num = backgndpid;
5035numvar:
5036 expdest = cvtnum(num, expdest);
5037 break;
5038 case '-':
5039 for (i = 0 ; i < NOPTS ; i++) {
Eric Andersen2870d962001-07-02 17:27:21 +00005040 if (optent_val(i))
5041 STPUTC(optent_letter(optlist[i]), expdest);
Eric Andersencb57d552001-06-28 07:25:16 +00005042 }
5043 break;
5044 case '@':
5045 if (allow_split && quoted) {
5046 sep = 1 << CHAR_BIT;
5047 goto param;
5048 }
5049 /* fall through */
5050 case '*':
5051 sep = ifsset() ? ifsval()[0] : ' ';
5052 if (quotes) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005053 sepq = SIT(sep,syntax) == CCTL;
Eric Andersencb57d552001-06-28 07:25:16 +00005054 }
5055param:
5056 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
5057 strtodest(p, syntax, quotes);
5058 if (*ap && sep) {
5059 if (sepq)
5060 STPUTC(CTLESC, expdest);
5061 STPUTC(sep, expdest);
5062 }
5063 }
5064 break;
5065 case '0':
5066 strtodest(arg0, syntax, quotes);
5067 break;
5068 default:
5069 num = atoi(name);
5070 if (num > 0 && num <= shellparam.nparam) {
5071 strtodest(shellparam.p[num - 1], syntax, quotes);
5072 }
5073 break;
5074 }
5075}
5076
5077
Eric Andersencb57d552001-06-28 07:25:16 +00005078/*
5079 * Record the fact that we have to scan this region of the
5080 * string for IFS characters.
5081 */
5082
5083static void
5084recordregion(start, end, nulonly)
5085 int start;
5086 int end;
5087 int nulonly;
5088{
5089 struct ifsregion *ifsp;
5090
5091 if (ifslastp == NULL) {
5092 ifsp = &ifsfirst;
5093 } else {
5094 INTOFF;
5095 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
5096 ifsp->next = NULL;
5097 ifslastp->next = ifsp;
5098 INTON;
5099 }
5100 ifslastp = ifsp;
5101 ifslastp->begoff = start;
5102 ifslastp->endoff = end;
5103 ifslastp->nulonly = nulonly;
5104}
5105
5106
5107
5108/*
5109 * Break the argument string into pieces based upon IFS and add the
5110 * strings to the argument list. The regions of the string to be
5111 * searched for IFS characters have been stored by recordregion.
5112 */
5113static void
5114ifsbreakup(string, arglist)
5115 char *string;
5116 struct arglist *arglist;
5117 {
5118 struct ifsregion *ifsp;
5119 struct strlist *sp;
5120 char *start;
5121 char *p;
5122 char *q;
5123 const char *ifs, *realifs;
5124 int ifsspc;
5125 int nulonly;
5126
5127
5128 start = string;
5129 ifsspc = 0;
5130 nulonly = 0;
5131 realifs = ifsset() ? ifsval() : defifs;
5132 if (ifslastp != NULL) {
5133 ifsp = &ifsfirst;
5134 do {
5135 p = string + ifsp->begoff;
5136 nulonly = ifsp->nulonly;
5137 ifs = nulonly ? nullstr : realifs;
5138 ifsspc = 0;
5139 while (p < string + ifsp->endoff) {
5140 q = p;
5141 if (*p == CTLESC)
5142 p++;
5143 if (strchr(ifs, *p)) {
5144 if (!nulonly)
5145 ifsspc = (strchr(defifs, *p) != NULL);
5146 /* Ignore IFS whitespace at start */
5147 if (q == start && ifsspc) {
5148 p++;
5149 start = p;
5150 continue;
5151 }
5152 *q = '\0';
5153 sp = (struct strlist *)stalloc(sizeof *sp);
5154 sp->text = start;
5155 *arglist->lastp = sp;
5156 arglist->lastp = &sp->next;
5157 p++;
5158 if (!nulonly) {
5159 for (;;) {
5160 if (p >= string + ifsp->endoff) {
5161 break;
5162 }
5163 q = p;
5164 if (*p == CTLESC)
5165 p++;
5166 if (strchr(ifs, *p) == NULL ) {
5167 p = q;
5168 break;
5169 } else if (strchr(defifs, *p) == NULL) {
5170 if (ifsspc) {
5171 p++;
5172 ifsspc = 0;
5173 } else {
5174 p = q;
5175 break;
5176 }
5177 } else
5178 p++;
5179 }
5180 }
5181 start = p;
5182 } else
5183 p++;
5184 }
5185 } while ((ifsp = ifsp->next) != NULL);
5186 if (!(*start || (!ifsspc && start > string && nulonly))) {
5187 return;
5188 }
5189 }
5190
5191 sp = (struct strlist *)stalloc(sizeof *sp);
5192 sp->text = start;
5193 *arglist->lastp = sp;
5194 arglist->lastp = &sp->next;
5195}
5196
5197static void
5198ifsfree()
5199{
5200 while (ifsfirst.next != NULL) {
5201 struct ifsregion *ifsp;
5202 INTOFF;
5203 ifsp = ifsfirst.next->next;
5204 ckfree(ifsfirst.next);
5205 ifsfirst.next = ifsp;
5206 INTON;
5207 }
5208 ifslastp = NULL;
5209 ifsfirst.next = NULL;
5210}
5211
Eric Andersen2870d962001-07-02 17:27:21 +00005212/*
5213 * Add a file name to the list.
5214 */
Eric Andersencb57d552001-06-28 07:25:16 +00005215
Eric Andersen2870d962001-07-02 17:27:21 +00005216static void
5217addfname(const char *name)
5218{
5219 char *p;
5220 struct strlist *sp;
5221
5222 p = sstrdup(name);
5223 sp = (struct strlist *)stalloc(sizeof *sp);
5224 sp->text = p;
5225 *exparg.lastp = sp;
5226 exparg.lastp = &sp->next;
5227}
Eric Andersencb57d552001-06-28 07:25:16 +00005228
5229/*
5230 * Expand shell metacharacters. At this point, the only control characters
5231 * should be escapes. The results are stored in the list exparg.
5232 */
5233
Eric Andersen62483552001-07-10 06:09:16 +00005234#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00005235static void
5236expandmeta(str, flag)
5237 struct strlist *str;
5238 int flag;
5239{
5240 const char *p;
5241 glob_t pglob;
5242 /* TODO - EXP_REDIR */
5243
5244 while (str) {
5245 if (fflag)
5246 goto nometa;
5247 p = preglob(str->text);
5248 INTOFF;
Eric Andersen34506362001-08-02 05:02:46 +00005249 switch (glob(p, 0, 0, &pglob)) {
Eric Andersencb57d552001-06-28 07:25:16 +00005250 case 0:
Eric Andersen34506362001-08-02 05:02:46 +00005251 if(pglob.gl_pathv[1]==0 && !strcmp(p, pglob.gl_pathv[0]))
Eric Andersencb57d552001-06-28 07:25:16 +00005252 goto nometa2;
5253 addglob(&pglob);
5254 globfree(&pglob);
5255 INTON;
5256 break;
5257 case GLOB_NOMATCH:
5258nometa2:
5259 globfree(&pglob);
5260 INTON;
5261nometa:
5262 *exparg.lastp = str;
5263 rmescapes(str->text);
5264 exparg.lastp = &str->next;
5265 break;
Eric Andersen2870d962001-07-02 17:27:21 +00005266 default: /* GLOB_NOSPACE */
Eric Andersencb57d552001-06-28 07:25:16 +00005267 error("Out of space");
5268 }
5269 str = str->next;
5270 }
5271}
5272
5273
5274/*
5275 * Add the result of glob(3) to the list.
5276 */
5277
5278static void
5279addglob(pglob)
5280 const glob_t *pglob;
5281{
5282 char **p = pglob->gl_pathv;
5283
5284 do {
5285 addfname(*p);
5286 } while (*++p);
5287}
5288
5289
Eric Andersen2870d962001-07-02 17:27:21 +00005290#else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005291static char *expdir;
5292
5293
5294static void
5295expandmeta(str, flag)
5296 struct strlist *str;
5297 int flag;
5298{
5299 char *p;
5300 struct strlist **savelastp;
5301 struct strlist *sp;
5302 char c;
5303 /* TODO - EXP_REDIR */
5304
5305 while (str) {
5306 if (fflag)
5307 goto nometa;
5308 p = str->text;
Eric Andersen2870d962001-07-02 17:27:21 +00005309 for (;;) { /* fast check for meta chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005310 if ((c = *p++) == '\0')
5311 goto nometa;
5312 if (c == '*' || c == '?' || c == '[' || c == '!')
5313 break;
5314 }
5315 savelastp = exparg.lastp;
5316 INTOFF;
5317 if (expdir == NULL) {
5318 int i = strlen(str->text);
5319 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5320 }
5321
5322 expmeta(expdir, str->text);
5323 ckfree(expdir);
5324 expdir = NULL;
5325 INTON;
5326 if (exparg.lastp == savelastp) {
5327 /*
5328 * no matches
5329 */
5330nometa:
5331 *exparg.lastp = str;
5332 rmescapes(str->text);
5333 exparg.lastp = &str->next;
5334 } else {
5335 *exparg.lastp = NULL;
5336 *savelastp = sp = expsort(*savelastp);
5337 while (sp->next != NULL)
5338 sp = sp->next;
5339 exparg.lastp = &sp->next;
5340 }
5341 str = str->next;
5342 }
5343}
5344
5345
5346/*
5347 * Do metacharacter (i.e. *, ?, [...]) expansion.
5348 */
5349
5350static void
5351expmeta(enddir, name)
5352 char *enddir;
5353 char *name;
5354 {
5355 char *p;
5356 const char *cp;
5357 char *q;
5358 char *start;
5359 char *endname;
5360 int metaflag;
5361 struct stat statb;
5362 DIR *dirp;
5363 struct dirent *dp;
5364 int atend;
5365 int matchdot;
5366
5367 metaflag = 0;
5368 start = name;
5369 for (p = name ; ; p++) {
5370 if (*p == '*' || *p == '?')
5371 metaflag = 1;
5372 else if (*p == '[') {
5373 q = p + 1;
5374 if (*q == '!')
5375 q++;
5376 for (;;) {
5377 while (*q == CTLQUOTEMARK)
5378 q++;
5379 if (*q == CTLESC)
5380 q++;
5381 if (*q == '/' || *q == '\0')
5382 break;
5383 if (*++q == ']') {
5384 metaflag = 1;
5385 break;
5386 }
5387 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005388 } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) {
Eric Andersencb57d552001-06-28 07:25:16 +00005389 metaflag = 1;
5390 } else if (*p == '\0')
5391 break;
5392 else if (*p == CTLQUOTEMARK)
5393 continue;
5394 else if (*p == CTLESC)
5395 p++;
5396 if (*p == '/') {
5397 if (metaflag)
5398 break;
5399 start = p + 1;
5400 }
5401 }
Eric Andersen2870d962001-07-02 17:27:21 +00005402 if (metaflag == 0) { /* we've reached the end of the file name */
Eric Andersencb57d552001-06-28 07:25:16 +00005403 if (enddir != expdir)
5404 metaflag++;
5405 for (p = name ; ; p++) {
5406 if (*p == CTLQUOTEMARK)
5407 continue;
5408 if (*p == CTLESC)
5409 p++;
5410 *enddir++ = *p;
5411 if (*p == '\0')
5412 break;
5413 }
5414 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5415 addfname(expdir);
5416 return;
5417 }
5418 endname = p;
5419 if (start != name) {
5420 p = name;
5421 while (p < start) {
5422 while (*p == CTLQUOTEMARK)
5423 p++;
5424 if (*p == CTLESC)
5425 p++;
5426 *enddir++ = *p++;
5427 }
5428 }
5429 if (enddir == expdir) {
5430 cp = ".";
5431 } else if (enddir == expdir + 1 && *expdir == '/') {
5432 cp = "/";
5433 } else {
5434 cp = expdir;
5435 enddir[-1] = '\0';
5436 }
5437 if ((dirp = opendir(cp)) == NULL)
5438 return;
5439 if (enddir != expdir)
5440 enddir[-1] = '/';
5441 if (*endname == 0) {
5442 atend = 1;
5443 } else {
5444 atend = 0;
5445 *endname++ = '\0';
5446 }
5447 matchdot = 0;
5448 p = start;
5449 while (*p == CTLQUOTEMARK)
5450 p++;
5451 if (*p == CTLESC)
5452 p++;
5453 if (*p == '.')
5454 matchdot++;
5455 while (! int_pending() && (dp = readdir(dirp)) != NULL) {
5456 if (dp->d_name[0] == '.' && ! matchdot)
5457 continue;
5458 if (patmatch(start, dp->d_name, 0)) {
5459 if (atend) {
Eric Andersen2870d962001-07-02 17:27:21 +00005460 strcpy(enddir, dp->d_name);
Eric Andersencb57d552001-06-28 07:25:16 +00005461 addfname(expdir);
5462 } else {
5463 for (p = enddir, cp = dp->d_name;
5464 (*p++ = *cp++) != '\0';)
5465 continue;
5466 p[-1] = '/';
5467 expmeta(p, endname);
5468 }
5469 }
5470 }
5471 closedir(dirp);
5472 if (! atend)
5473 endname[-1] = '/';
5474}
Eric Andersen2870d962001-07-02 17:27:21 +00005475#endif /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005476
5477
Eric Andersencb57d552001-06-28 07:25:16 +00005478
Eric Andersen62483552001-07-10 06:09:16 +00005479#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersencb57d552001-06-28 07:25:16 +00005480/*
5481 * Sort the results of file name expansion. It calculates the number of
5482 * strings to sort and then calls msort (short for merge sort) to do the
5483 * work.
5484 */
5485
5486static struct strlist *
5487expsort(str)
5488 struct strlist *str;
5489 {
5490 int len;
5491 struct strlist *sp;
5492
5493 len = 0;
5494 for (sp = str ; sp ; sp = sp->next)
5495 len++;
5496 return msort(str, len);
5497}
5498
5499
5500static struct strlist *
5501msort(list, len)
5502 struct strlist *list;
5503 int len;
5504{
5505 struct strlist *p, *q = NULL;
5506 struct strlist **lpp;
5507 int half;
5508 int n;
5509
5510 if (len <= 1)
5511 return list;
5512 half = len >> 1;
5513 p = list;
5514 for (n = half ; --n >= 0 ; ) {
5515 q = p;
5516 p = p->next;
5517 }
Eric Andersen2870d962001-07-02 17:27:21 +00005518 q->next = NULL; /* terminate first half of list */
5519 q = msort(list, half); /* sort first half of list */
5520 p = msort(p, len - half); /* sort second half */
Eric Andersencb57d552001-06-28 07:25:16 +00005521 lpp = &list;
5522 for (;;) {
5523 if (strcmp(p->text, q->text) < 0) {
5524 *lpp = p;
5525 lpp = &p->next;
5526 if ((p = *lpp) == NULL) {
5527 *lpp = q;
5528 break;
5529 }
5530 } else {
5531 *lpp = q;
5532 lpp = &q->next;
5533 if ((q = *lpp) == NULL) {
5534 *lpp = p;
5535 break;
5536 }
5537 }
5538 }
5539 return list;
5540}
5541#endif
5542
5543
5544
5545/*
5546 * Returns true if the pattern matches the string.
5547 */
5548
Eric Andersen62483552001-07-10 06:09:16 +00005549#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00005550/* squoted: string might have quote chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005551static int
Eric Andersen2870d962001-07-02 17:27:21 +00005552patmatch(char *pattern, char *string, int squoted)
5553{
Eric Andersencb57d552001-06-28 07:25:16 +00005554 const char *p;
5555 char *q;
5556
5557 p = preglob(pattern);
5558 q = squoted ? _rmescapes(string, RMESCAPE_ALLOC) : string;
5559
5560 return !fnmatch(p, q, 0);
5561}
5562
5563
5564static int
Eric Andersen2870d962001-07-02 17:27:21 +00005565patmatch2(char *pattern, char *string, int squoted)
5566{
Eric Andersencb57d552001-06-28 07:25:16 +00005567 char *p;
5568 int res;
5569
5570 sstrnleft--;
5571 p = grabstackstr(expdest);
5572 res = patmatch(pattern, string, squoted);
5573 ungrabstackstr(p, expdest);
5574 return res;
5575}
5576#else
5577static int
Eric Andersen2870d962001-07-02 17:27:21 +00005578patmatch(char *pattern, char *string, int squoted) {
5579 return pmatch(pattern, string, squoted);
Eric Andersencb57d552001-06-28 07:25:16 +00005580}
5581
5582
5583static int
Eric Andersen2870d962001-07-02 17:27:21 +00005584pmatch(char *pattern, char *string, int squoted)
5585{
Eric Andersencb57d552001-06-28 07:25:16 +00005586 char *p, *q;
5587 char c;
5588
5589 p = pattern;
5590 q = string;
5591 for (;;) {
5592 switch (c = *p++) {
5593 case '\0':
5594 goto breakloop;
5595 case CTLESC:
5596 if (squoted && *q == CTLESC)
5597 q++;
5598 if (*q++ != *p++)
5599 return 0;
5600 break;
5601 case CTLQUOTEMARK:
5602 continue;
5603 case '?':
5604 if (squoted && *q == CTLESC)
5605 q++;
5606 if (*q++ == '\0')
5607 return 0;
5608 break;
5609 case '*':
5610 c = *p;
5611 while (c == CTLQUOTEMARK || c == '*')
5612 c = *++p;
5613 if (c != CTLESC && c != CTLQUOTEMARK &&
5614 c != '?' && c != '*' && c != '[') {
5615 while (*q != c) {
5616 if (squoted && *q == CTLESC &&
5617 q[1] == c)
5618 break;
5619 if (*q == '\0')
5620 return 0;
5621 if (squoted && *q == CTLESC)
5622 q++;
5623 q++;
5624 }
5625 }
5626 do {
5627 if (pmatch(p, q, squoted))
5628 return 1;
5629 if (squoted && *q == CTLESC)
5630 q++;
5631 } while (*q++ != '\0');
5632 return 0;
5633 case '[': {
5634 char *endp;
5635 int invert, found;
5636 char chr;
5637
5638 endp = p;
5639 if (*endp == '!')
5640 endp++;
5641 for (;;) {
5642 while (*endp == CTLQUOTEMARK)
5643 endp++;
5644 if (*endp == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00005645 goto dft; /* no matching ] */
Eric Andersencb57d552001-06-28 07:25:16 +00005646 if (*endp == CTLESC)
5647 endp++;
5648 if (*++endp == ']')
5649 break;
5650 }
5651 invert = 0;
5652 if (*p == '!') {
5653 invert++;
5654 p++;
5655 }
5656 found = 0;
5657 chr = *q++;
5658 if (squoted && chr == CTLESC)
5659 chr = *q++;
5660 if (chr == '\0')
5661 return 0;
5662 c = *p++;
5663 do {
5664 if (c == CTLQUOTEMARK)
5665 continue;
5666 if (c == CTLESC)
5667 c = *p++;
5668 if (*p == '-' && p[1] != ']') {
5669 p++;
5670 while (*p == CTLQUOTEMARK)
5671 p++;
5672 if (*p == CTLESC)
5673 p++;
5674 if (chr >= c && chr <= *p)
5675 found = 1;
5676 p++;
5677 } else {
5678 if (chr == c)
5679 found = 1;
5680 }
5681 } while ((c = *p++) != ']');
5682 if (found == invert)
5683 return 0;
5684 break;
5685 }
Eric Andersen2870d962001-07-02 17:27:21 +00005686dft: default:
Eric Andersencb57d552001-06-28 07:25:16 +00005687 if (squoted && *q == CTLESC)
5688 q++;
5689 if (*q++ != c)
5690 return 0;
5691 break;
5692 }
5693 }
5694breakloop:
5695 if (*q != '\0')
5696 return 0;
5697 return 1;
5698}
5699#endif
5700
5701
5702
5703/*
5704 * Remove any CTLESC characters from a string.
5705 */
5706
Eric Andersen62483552001-07-10 06:09:16 +00005707#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00005708static char *
Eric Andersen2870d962001-07-02 17:27:21 +00005709_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005710{
5711 char *p, *q, *r;
5712 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5713
5714 p = strpbrk(str, qchars);
5715 if (!p) {
5716 return str;
5717 }
5718 q = p;
5719 r = str;
5720 if (flag & RMESCAPE_ALLOC) {
5721 size_t len = p - str;
5722 q = r = stalloc(strlen(p) + len + 1);
5723 if (len > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00005724 memcpy(q, str, len);
5725 q += len;
Eric Andersencb57d552001-06-28 07:25:16 +00005726 }
5727 }
5728 while (*p) {
5729 if (*p == CTLQUOTEMARK) {
5730 p++;
5731 continue;
5732 }
5733 if (*p == CTLESC) {
5734 p++;
5735 if (flag & RMESCAPE_GLOB && *p != '/') {
5736 *q++ = '\\';
5737 }
5738 }
5739 *q++ = *p++;
5740 }
5741 *q = '\0';
5742 return r;
5743}
5744#else
5745static void
5746rmescapes(str)
5747 char *str;
5748{
5749 char *p, *q;
5750
5751 p = str;
5752 while (*p != CTLESC && *p != CTLQUOTEMARK) {
5753 if (*p++ == '\0')
5754 return;
5755 }
5756 q = p;
5757 while (*p) {
5758 if (*p == CTLQUOTEMARK) {
5759 p++;
5760 continue;
5761 }
5762 if (*p == CTLESC)
5763 p++;
5764 *q++ = *p++;
5765 }
5766 *q = '\0';
5767}
5768#endif
5769
5770
5771
5772/*
5773 * See if a pattern matches in a case statement.
5774 */
5775
5776static int
Eric Andersen2870d962001-07-02 17:27:21 +00005777casematch(union node *pattern, const char *val)
5778{
Eric Andersencb57d552001-06-28 07:25:16 +00005779 struct stackmark smark;
5780 int result;
5781 char *p;
5782
5783 setstackmark(&smark);
5784 argbackq = pattern->narg.backquote;
5785 STARTSTACKSTR(expdest);
5786 ifslastp = NULL;
5787 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5788 STPUTC('\0', expdest);
5789 p = grabstackstr(expdest);
Eric Andersen2870d962001-07-02 17:27:21 +00005790 result = patmatch(p, (char *)val, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00005791 popstackmark(&smark);
5792 return result;
5793}
5794
5795/*
5796 * Our own itoa().
5797 */
5798
5799static char *
5800cvtnum(num, buf)
5801 int num;
5802 char *buf;
5803 {
5804 int len;
5805
5806 CHECKSTRSPACE(32, buf);
5807 len = sprintf(buf, "%d", num);
5808 STADJUST(len, buf);
5809 return buf;
5810}
Eric Andersencb57d552001-06-28 07:25:16 +00005811/*
5812 * Editline and history functions (and glue).
5813 */
5814static int histcmd(argc, argv)
5815 int argc;
5816 char **argv;
5817{
5818 error("not compiled with history support");
5819 /* NOTREACHED */
5820}
5821
5822
Eric Andersencb57d552001-06-28 07:25:16 +00005823struct redirtab {
5824 struct redirtab *next;
Russ Dill4db35642001-07-26 05:58:40 +00005825 short renamed[10]; /* Current ash support only 0-9 descriptors */
Eric Andersen34506362001-08-02 05:02:46 +00005826 /* char on arm (and others) can't be negative */
Eric Andersencb57d552001-06-28 07:25:16 +00005827};
5828
Eric Andersen2870d962001-07-02 17:27:21 +00005829static struct redirtab *redirlist;
Eric Andersencb57d552001-06-28 07:25:16 +00005830
5831extern char **environ;
5832
5833
5834
5835/*
5836 * Initialization code.
5837 */
5838
5839static void
Eric Andersen2870d962001-07-02 17:27:21 +00005840init(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00005841
5842 /* from cd.c: */
5843 {
Eric Andersena3483db2001-10-24 08:01:06 +00005844 curdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00005845 setpwd(0, 0);
5846 }
5847
5848 /* from input.c: */
5849 {
5850 basepf.nextc = basepf.buf = basebuf;
5851 }
5852
Eric Andersencb57d552001-06-28 07:25:16 +00005853 /* from var.c: */
5854 {
5855 char **envp;
5856 char ppid[32];
5857
5858 initvar();
5859 for (envp = environ ; *envp ; envp++) {
5860 if (strchr(*envp, '=')) {
5861 setvareq(*envp, VEXPORT|VTEXTFIXED);
5862 }
5863 }
5864
Eric Andersen3102ac42001-07-06 04:26:23 +00005865 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
Eric Andersencb57d552001-06-28 07:25:16 +00005866 setvar("PPID", ppid, 0);
5867 }
5868}
5869
5870
5871
5872/*
5873 * This routine is called when an error or an interrupt occurs in an
5874 * interactive shell and control is returned to the main command loop.
5875 */
5876
Eric Andersen2870d962001-07-02 17:27:21 +00005877/* 1 == check for aliases, 2 == also check for assignments */
Eric Andersen7467c8d2001-07-12 20:26:32 +00005878static int checkalias; /* also used in no alias mode for check assignments */
Eric Andersen2870d962001-07-02 17:27:21 +00005879
Eric Andersencb57d552001-06-28 07:25:16 +00005880static void
Eric Andersen2870d962001-07-02 17:27:21 +00005881reset(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00005882
5883 /* from eval.c: */
5884 {
5885 evalskip = 0;
5886 loopnest = 0;
5887 funcnest = 0;
5888 }
5889
5890 /* from input.c: */
5891 {
5892 if (exception != EXSHELLPROC)
Eric Andersen2870d962001-07-02 17:27:21 +00005893 parselleft = parsenleft = 0; /* clear input buffer */
Eric Andersencb57d552001-06-28 07:25:16 +00005894 popallfiles();
5895 }
5896
5897 /* from parser.c: */
5898 {
5899 tokpushback = 0;
5900 checkkwd = 0;
5901 checkalias = 0;
5902 }
5903
5904 /* from redir.c: */
5905 {
5906 while (redirlist)
5907 popredir();
5908 }
5909
Eric Andersencb57d552001-06-28 07:25:16 +00005910}
5911
5912
5913
5914/*
Eric Andersencb57d552001-06-28 07:25:16 +00005915 * This file implements the input routines used by the parser.
5916 */
5917
Eric Andersenbdfd0d72001-10-24 05:00:29 +00005918#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersencb57d552001-06-28 07:25:16 +00005919static const char * cmdedit_prompt;
5920static inline void putprompt(const char *s) {
5921 cmdedit_prompt = s;
5922}
5923#else
5924static inline void putprompt(const char *s) {
5925 out2str(s);
5926}
5927#endif
5928
Eric Andersen2870d962001-07-02 17:27:21 +00005929#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
Eric Andersencb57d552001-06-28 07:25:16 +00005930
Eric Andersencb57d552001-06-28 07:25:16 +00005931
Eric Andersencb57d552001-06-28 07:25:16 +00005932
Eric Andersen2870d962001-07-02 17:27:21 +00005933/*
5934 * Same as pgetc(), but ignores PEOA.
5935 */
Eric Andersencb57d552001-06-28 07:25:16 +00005936
Eric Andersen2870d962001-07-02 17:27:21 +00005937#ifdef ASH_ALIAS
5938static int
Eric Andersen74400cc2001-10-18 04:11:39 +00005939pgetc2(void)
Eric Andersen2870d962001-07-02 17:27:21 +00005940{
5941 int c;
5942 do {
5943 c = pgetc_macro();
5944 } while (c == PEOA);
5945 return c;
Eric Andersencb57d552001-06-28 07:25:16 +00005946}
Eric Andersen2870d962001-07-02 17:27:21 +00005947#else
5948static inline int pgetc2() { return pgetc_macro(); }
Eric Andersencb57d552001-06-28 07:25:16 +00005949#endif
5950
Eric Andersencb57d552001-06-28 07:25:16 +00005951/*
5952 * Read a line from the script.
5953 */
5954
Eric Andersen62483552001-07-10 06:09:16 +00005955static inline char *
Eric Andersen2870d962001-07-02 17:27:21 +00005956pfgets(char *line, int len)
Eric Andersencb57d552001-06-28 07:25:16 +00005957{
5958 char *p = line;
5959 int nleft = len;
5960 int c;
5961
5962 while (--nleft > 0) {
5963 c = pgetc2();
5964 if (c == PEOF) {
5965 if (p == line)
5966 return NULL;
5967 break;
5968 }
5969 *p++ = c;
5970 if (c == '\n')
5971 break;
5972 }
5973 *p = '\0';
5974 return line;
5975}
5976
Eric Andersen62483552001-07-10 06:09:16 +00005977static inline int
Eric Andersen2870d962001-07-02 17:27:21 +00005978preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005979{
5980 int nr;
5981 char *buf = parsefile->buf;
5982 parsenextc = buf;
5983
5984retry:
Eric Andersenbdfd0d72001-10-24 05:00:29 +00005985#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersencb57d552001-06-28 07:25:16 +00005986 {
Eric Andersen34506362001-08-02 05:02:46 +00005987 if (!iflag || parsefile->fd)
Eric Andersen7467c8d2001-07-12 20:26:32 +00005988 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersen2870d962001-07-02 17:27:21 +00005989 else {
Eric Andersen044228d2001-07-17 01:12:36 +00005990 nr = cmdedit_read_input((char*)cmdedit_prompt, buf);
Eric Andersencb57d552001-06-28 07:25:16 +00005991 }
5992 }
5993#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00005994 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00005995#endif
5996
5997 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00005998 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
5999 int flags = fcntl(0, F_GETFL, 0);
6000 if (flags >= 0 && flags & O_NONBLOCK) {
6001 flags &=~ O_NONBLOCK;
6002 if (fcntl(0, F_SETFL, flags) >= 0) {
6003 out2str("sh: turning off NDELAY mode\n");
6004 goto retry;
6005 }
6006 }
6007 }
6008 }
6009 return nr;
6010}
6011
Eric Andersen2870d962001-07-02 17:27:21 +00006012static void
6013popstring(void)
6014{
6015 struct strpush *sp = parsefile->strpush;
6016
6017 INTOFF;
6018#ifdef ASH_ALIAS
6019 if (sp->ap) {
6020 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6021 if (!checkalias) {
6022 checkalias = 1;
6023 }
6024 }
6025 if (sp->string != sp->ap->val) {
6026 ckfree(sp->string);
6027 }
6028
6029 sp->ap->flag &= ~ALIASINUSE;
6030 if (sp->ap->flag & ALIASDEAD) {
6031 unalias(sp->ap->name);
6032 }
6033 }
6034#endif
6035 parsenextc = sp->prevstring;
6036 parsenleft = sp->prevnleft;
6037/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6038 parsefile->strpush = sp->prev;
6039 if (sp != &(parsefile->basestrpush))
6040 ckfree(sp);
6041 INTON;
6042}
6043
6044
Eric Andersencb57d552001-06-28 07:25:16 +00006045/*
6046 * Refill the input buffer and return the next input character:
6047 *
6048 * 1) If a string was pushed back on the input, pop it;
6049 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6050 * from a string so we can't refill the buffer, return EOF.
6051 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6052 * 4) Process input up to the next newline, deleting nul characters.
6053 */
6054
6055static int
Eric Andersen2870d962001-07-02 17:27:21 +00006056preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006057{
6058 char *p, *q;
6059 int more;
6060 char savec;
6061
6062 while (parsefile->strpush) {
Eric Andersen2870d962001-07-02 17:27:21 +00006063#ifdef ASH_ALIAS
6064 if (parsenleft == -1 && parsefile->strpush->ap &&
6065 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00006066 return PEOA;
6067 }
Eric Andersen2870d962001-07-02 17:27:21 +00006068#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006069 popstring();
6070 if (--parsenleft >= 0)
6071 return (*parsenextc++);
6072 }
6073 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6074 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00006075 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00006076
6077again:
6078 if (parselleft <= 0) {
6079 if ((parselleft = preadfd()) <= 0) {
6080 parselleft = parsenleft = EOF_NLEFT;
6081 return PEOF;
6082 }
6083 }
6084
6085 q = p = parsenextc;
6086
6087 /* delete nul characters */
6088 for (more = 1; more;) {
6089 switch (*p) {
6090 case '\0':
Eric Andersen2870d962001-07-02 17:27:21 +00006091 p++; /* Skip nul */
Eric Andersencb57d552001-06-28 07:25:16 +00006092 goto check;
6093
6094
6095 case '\n':
6096 parsenleft = q - parsenextc;
6097 more = 0; /* Stop processing here */
6098 break;
6099 }
6100
6101 *q++ = *p++;
6102check:
6103 if (--parselleft <= 0 && more) {
6104 parsenleft = q - parsenextc - 1;
6105 if (parsenleft < 0)
6106 goto again;
6107 more = 0;
6108 }
6109 }
6110
6111 savec = *q;
6112 *q = '\0';
6113
6114 if (vflag) {
6115 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00006116 }
6117
6118 *q = savec;
6119
6120 return *parsenextc++;
6121}
6122
Eric Andersencb57d552001-06-28 07:25:16 +00006123
6124/*
6125 * Push a string back onto the input at this current parsefile level.
6126 * We handle aliases this way.
6127 */
6128static void
Eric Andersen2870d962001-07-02 17:27:21 +00006129pushstring(char *s, int len, void *ap)
6130{
Eric Andersencb57d552001-06-28 07:25:16 +00006131 struct strpush *sp;
6132
6133 INTOFF;
6134/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6135 if (parsefile->strpush) {
6136 sp = ckmalloc(sizeof (struct strpush));
6137 sp->prev = parsefile->strpush;
6138 parsefile->strpush = sp;
6139 } else
6140 sp = parsefile->strpush = &(parsefile->basestrpush);
6141 sp->prevstring = parsenextc;
6142 sp->prevnleft = parsenleft;
Eric Andersen2870d962001-07-02 17:27:21 +00006143#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00006144 sp->ap = (struct alias *)ap;
6145 if (ap) {
6146 ((struct alias *)ap)->flag |= ALIASINUSE;
6147 sp->string = s;
6148 }
Eric Andersen2870d962001-07-02 17:27:21 +00006149#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006150 parsenextc = s;
6151 parsenleft = len;
6152 INTON;
6153}
6154
Eric Andersencb57d552001-06-28 07:25:16 +00006155
Eric Andersencb57d552001-06-28 07:25:16 +00006156/*
6157 * Like setinputfile, but takes input from a string.
6158 */
6159
6160static void
Eric Andersen62483552001-07-10 06:09:16 +00006161setinputstring(char *string)
6162{
Eric Andersencb57d552001-06-28 07:25:16 +00006163 INTOFF;
6164 pushfile();
6165 parsenextc = string;
6166 parsenleft = strlen(string);
6167 parsefile->buf = NULL;
6168 plinno = 1;
6169 INTON;
6170}
6171
6172
6173
6174/*
6175 * To handle the "." command, a stack of input files is used. Pushfile
6176 * adds a new entry to the stack and popfile restores the previous level.
6177 */
6178
6179static void
Eric Andersen2870d962001-07-02 17:27:21 +00006180pushfile(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00006181 struct parsefile *pf;
6182
6183 parsefile->nleft = parsenleft;
6184 parsefile->lleft = parselleft;
6185 parsefile->nextc = parsenextc;
6186 parsefile->linno = plinno;
6187 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6188 pf->prev = parsefile;
6189 pf->fd = -1;
6190 pf->strpush = NULL;
6191 pf->basestrpush.prev = NULL;
6192 parsefile = pf;
6193}
6194
Eric Andersen2870d962001-07-02 17:27:21 +00006195#ifdef JOBS
6196static void restartjob (struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00006197#endif
Eric Andersen2870d962001-07-02 17:27:21 +00006198static void freejob (struct job *);
6199static struct job *getjob (const char *);
6200static int dowait (int, struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00006201static void waitonint(int);
6202
6203
Eric Andersen2870d962001-07-02 17:27:21 +00006204/*
6205 * We keep track of whether or not fd0 has been redirected. This is for
6206 * background commands, where we want to redirect fd0 to /dev/null only
6207 * if it hasn't already been redirected.
6208*/
6209static int fd0_redirected = 0;
6210
6211/* Return true if fd 0 has already been redirected at least once. */
6212static inline int
Eric Andersen74400cc2001-10-18 04:11:39 +00006213fd0_redirected_p (void)
6214{
Eric Andersen2870d962001-07-02 17:27:21 +00006215 return fd0_redirected != 0;
6216}
6217
Eric Andersen62483552001-07-10 06:09:16 +00006218static void dupredirect (const union node *, int, int fd1dup);
Eric Andersen2870d962001-07-02 17:27:21 +00006219
6220#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006221/*
6222 * Turn job control on and off.
6223 *
6224 * Note: This code assumes that the third arg to ioctl is a character
6225 * pointer, which is true on Berkeley systems but not System V. Since
6226 * System V doesn't have job control yet, this isn't a problem now.
6227 */
6228
Eric Andersen2870d962001-07-02 17:27:21 +00006229
Eric Andersencb57d552001-06-28 07:25:16 +00006230
6231static void setjobctl(int enable)
6232{
6233#ifdef OLD_TTY_DRIVER
6234 int ldisc;
6235#endif
6236
6237 if (enable == jobctl || rootshell == 0)
6238 return;
6239 if (enable) {
6240 do { /* while we are in the background */
6241#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006242 if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006243#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006244 initialpgrp = tcgetpgrp(2);
Eric Andersencb57d552001-06-28 07:25:16 +00006245 if (initialpgrp < 0) {
6246#endif
Eric Andersen8c145dc2001-07-10 16:57:09 +00006247 out2str("sh: can't access tty; job control turned off\n");
Eric Andersencb57d552001-06-28 07:25:16 +00006248 mflag = 0;
6249 return;
6250 }
6251 if (initialpgrp == -1)
6252 initialpgrp = getpgrp();
6253 else if (initialpgrp != getpgrp()) {
6254 killpg(initialpgrp, SIGTTIN);
6255 continue;
6256 }
6257 } while (0);
6258#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006259 if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
Eric Andersen8c145dc2001-07-10 16:57:09 +00006260 out2str("sh: need new tty driver to run job control; job control turned off\n");
Eric Andersencb57d552001-06-28 07:25:16 +00006261 mflag = 0;
6262 return;
6263 }
6264#endif
6265 setsignal(SIGTSTP);
6266 setsignal(SIGTTOU);
6267 setsignal(SIGTTIN);
6268 setpgid(0, rootpid);
6269#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006270 ioctl(2, TIOCSPGRP, (char *)&rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00006271#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006272 tcsetpgrp(2, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00006273#endif
Eric Andersen8c145dc2001-07-10 16:57:09 +00006274 } else { /* turning job control off */
Eric Andersencb57d552001-06-28 07:25:16 +00006275 setpgid(0, initialpgrp);
6276#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006277 ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006278#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006279 tcsetpgrp(2, initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006280#endif
6281 setsignal(SIGTSTP);
6282 setsignal(SIGTTOU);
6283 setsignal(SIGTTIN);
6284 }
6285 jobctl = enable;
6286}
6287#endif
6288
6289
Eric Andersen2870d962001-07-02 17:27:21 +00006290#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006291static int
6292killcmd(argc, argv)
6293 int argc;
6294 char **argv;
6295{
6296 int signo = -1;
6297 int list = 0;
6298 int i;
6299 pid_t pid;
6300 struct job *jp;
6301
6302 if (argc <= 1) {
6303usage:
6304 error(
6305"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6306"kill -l [exitstatus]"
6307 );
6308 }
6309
6310 if (*argv[1] == '-') {
6311 signo = decode_signal(argv[1] + 1, 1);
6312 if (signo < 0) {
6313 int c;
6314
6315 while ((c = nextopt("ls:")) != '\0')
6316 switch (c) {
6317 case 'l':
6318 list = 1;
6319 break;
6320 case 's':
6321 signo = decode_signal(optionarg, 1);
6322 if (signo < 0) {
6323 error(
6324 "invalid signal number or name: %s",
6325 optionarg
6326 );
6327 }
Eric Andersen2870d962001-07-02 17:27:21 +00006328 break;
Eric Andersencb57d552001-06-28 07:25:16 +00006329#ifdef DEBUG
6330 default:
6331 error(
6332 "nextopt returned character code 0%o", c);
6333#endif
6334 }
6335 } else
6336 argptr++;
6337 }
6338
6339 if (!list && signo < 0)
6340 signo = SIGTERM;
6341
6342 if ((signo < 0 || !*argptr) ^ list) {
6343 goto usage;
6344 }
6345
6346 if (list) {
Eric Andersen34506362001-08-02 05:02:46 +00006347 const char *name;
6348
Eric Andersencb57d552001-06-28 07:25:16 +00006349 if (!*argptr) {
6350 out1str("0\n");
6351 for (i = 1; i < NSIG; i++) {
Eric Andersen34506362001-08-02 05:02:46 +00006352 name = u_signal_names(0, &i, 1);
6353 if(name)
6354 printf(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006355 }
6356 return 0;
6357 }
Eric Andersen34506362001-08-02 05:02:46 +00006358 name = u_signal_names(*argptr, &signo, -1);
6359 if (name)
6360 printf(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006361 else
6362 error("invalid signal number or exit status: %s",
6363 *argptr);
6364 return 0;
6365 }
6366
6367 do {
6368 if (**argptr == '%') {
6369 jp = getjob(*argptr);
6370 if (jp->jobctl == 0)
6371 error("job %s not created under job control",
6372 *argptr);
6373 pid = -jp->ps[0].pid;
6374 } else
6375 pid = atoi(*argptr);
6376 if (kill(pid, signo) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00006377 error("%s: %m", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006378 } while (*++argptr);
6379
6380 return 0;
6381}
6382
6383static int
6384fgcmd(argc, argv)
6385 int argc;
6386 char **argv;
6387{
6388 struct job *jp;
6389 int pgrp;
6390 int status;
6391
6392 jp = getjob(argv[1]);
6393 if (jp->jobctl == 0)
6394 error("job not created under job control");
6395 pgrp = jp->ps[0].pid;
6396#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006397 ioctl(2, TIOCSPGRP, (char *)&pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006398#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006399 tcsetpgrp(2, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006400#endif
6401 restartjob(jp);
6402 INTOFF;
6403 status = waitforjob(jp);
6404 INTON;
6405 return status;
6406}
6407
6408
6409static int
6410bgcmd(argc, argv)
6411 int argc;
6412 char **argv;
6413{
6414 struct job *jp;
6415
6416 do {
6417 jp = getjob(*++argv);
6418 if (jp->jobctl == 0)
6419 error("job not created under job control");
6420 restartjob(jp);
6421 } while (--argc > 1);
6422 return 0;
6423}
6424
6425
6426static void
6427restartjob(jp)
6428 struct job *jp;
6429{
6430 struct procstat *ps;
6431 int i;
6432
6433 if (jp->state == JOBDONE)
6434 return;
6435 INTOFF;
6436 killpg(jp->ps[0].pid, SIGCONT);
6437 for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
6438 if (WIFSTOPPED(ps->status)) {
6439 ps->status = -1;
6440 jp->state = 0;
6441 }
6442 }
6443 INTON;
6444}
6445#endif
6446
Eric Andersen2870d962001-07-02 17:27:21 +00006447static void showjobs(int change);
6448
Eric Andersencb57d552001-06-28 07:25:16 +00006449
6450static int
6451jobscmd(argc, argv)
6452 int argc;
6453 char **argv;
6454{
6455 showjobs(0);
6456 return 0;
6457}
6458
6459
6460/*
6461 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6462 * statuses have changed since the last call to showjobs.
6463 *
6464 * If the shell is interrupted in the process of creating a job, the
6465 * result may be a job structure containing zero processes. Such structures
6466 * will be freed here.
6467 */
6468
6469static void
6470showjobs(change)
6471 int change;
6472{
6473 int jobno;
6474 int procno;
6475 int i;
6476 struct job *jp;
6477 struct procstat *ps;
6478 int col;
6479 char s[64];
6480
6481 TRACE(("showjobs(%d) called\n", change));
6482 while (dowait(0, (struct job *)NULL) > 0);
6483 for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
6484 if (! jp->used)
6485 continue;
6486 if (jp->nprocs == 0) {
6487 freejob(jp);
6488 continue;
6489 }
6490 if (change && ! jp->changed)
6491 continue;
6492 procno = jp->nprocs;
Eric Andersen2870d962001-07-02 17:27:21 +00006493 for (ps = jp->ps ; ; ps++) { /* for each process */
Eric Andersencb57d552001-06-28 07:25:16 +00006494 if (ps == jp->ps)
Eric Andersen3102ac42001-07-06 04:26:23 +00006495 snprintf(s, 64, "[%d] %ld ", jobno,
Eric Andersencb57d552001-06-28 07:25:16 +00006496 (long)ps->pid);
6497 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006498 snprintf(s, 64, " %ld ",
Eric Andersencb57d552001-06-28 07:25:16 +00006499 (long)ps->pid);
6500 out1str(s);
6501 col = strlen(s);
6502 s[0] = '\0';
6503 if (ps->status == -1) {
6504 /* don't print anything */
6505 } else if (WIFEXITED(ps->status)) {
Eric Andersen3102ac42001-07-06 04:26:23 +00006506 snprintf(s, 64, "Exit %d",
Eric Andersencb57d552001-06-28 07:25:16 +00006507 WEXITSTATUS(ps->status));
6508 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00006509#ifdef JOBS
6510 if (WIFSTOPPED(ps->status))
Eric Andersencb57d552001-06-28 07:25:16 +00006511 i = WSTOPSIG(ps->status);
6512 else /* WIFSIGNALED(ps->status) */
6513#endif
6514 i = WTERMSIG(ps->status);
6515 if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
Eric Andersen2870d962001-07-02 17:27:21 +00006516 strcpy(s, sys_siglist[i & 0x7F]);
Eric Andersencb57d552001-06-28 07:25:16 +00006517 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006518 snprintf(s, 64, "Signal %d", i & 0x7F);
Eric Andersencb57d552001-06-28 07:25:16 +00006519 if (WCOREDUMP(ps->status))
6520 strcat(s, " (core dumped)");
6521 }
6522 out1str(s);
6523 col += strlen(s);
Eric Andersen62483552001-07-10 06:09:16 +00006524 printf(
Eric Andersencb57d552001-06-28 07:25:16 +00006525 "%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ',
6526 ps->cmd
6527 );
6528 if (--procno <= 0)
6529 break;
6530 }
6531 jp->changed = 0;
6532 if (jp->state == JOBDONE) {
6533 freejob(jp);
6534 }
6535 }
6536}
6537
6538
6539/*
6540 * Mark a job structure as unused.
6541 */
6542
6543static void
Eric Andersen62483552001-07-10 06:09:16 +00006544freejob(struct job *jp)
6545{
6546 const struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006547 int i;
6548
6549 INTOFF;
6550 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6551 if (ps->cmd != nullstr)
6552 ckfree(ps->cmd);
6553 }
6554 if (jp->ps != &jp->ps0)
6555 ckfree(jp->ps);
6556 jp->used = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006557#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006558 if (curjob == jp - jobtab + 1)
6559 curjob = 0;
6560#endif
6561 INTON;
6562}
6563
6564
6565
6566static int
6567waitcmd(argc, argv)
6568 int argc;
6569 char **argv;
6570{
6571 struct job *job;
6572 int status, retval;
6573 struct job *jp;
6574
6575 if (--argc > 0) {
6576start:
6577 job = getjob(*++argv);
6578 } else {
6579 job = NULL;
6580 }
Eric Andersen2870d962001-07-02 17:27:21 +00006581 for (;;) { /* loop until process terminated or stopped */
Eric Andersencb57d552001-06-28 07:25:16 +00006582 if (job != NULL) {
6583 if (job->state) {
6584 status = job->ps[job->nprocs - 1].status;
6585 if (! iflag)
6586 freejob(job);
6587 if (--argc) {
6588 goto start;
6589 }
6590 if (WIFEXITED(status))
6591 retval = WEXITSTATUS(status);
Eric Andersen2870d962001-07-02 17:27:21 +00006592#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006593 else if (WIFSTOPPED(status))
6594 retval = WSTOPSIG(status) + 128;
6595#endif
6596 else {
6597 /* XXX: limits number of signals */
6598 retval = WTERMSIG(status) + 128;
6599 }
6600 return retval;
6601 }
6602 } else {
6603 for (jp = jobtab ; ; jp++) {
Eric Andersen2870d962001-07-02 17:27:21 +00006604 if (jp >= jobtab + njobs) { /* no running procs */
Eric Andersencb57d552001-06-28 07:25:16 +00006605 return 0;
6606 }
6607 if (jp->used && jp->state == 0)
6608 break;
6609 }
6610 }
6611 if (dowait(2, 0) < 0 && errno == EINTR) {
6612 return 129;
6613 }
6614 }
6615}
6616
6617
6618
6619/*
6620 * Convert a job name to a job structure.
6621 */
6622
6623static struct job *
Eric Andersen2870d962001-07-02 17:27:21 +00006624getjob(const char *name)
6625{
Eric Andersencb57d552001-06-28 07:25:16 +00006626 int jobno;
6627 struct job *jp;
6628 int pid;
6629 int i;
6630
6631 if (name == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00006632#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006633currentjob:
6634 if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
6635 error("No current job");
6636 return &jobtab[jobno - 1];
6637#else
6638 error("No current job");
6639#endif
6640 } else if (name[0] == '%') {
6641 if (is_digit(name[1])) {
6642 jobno = number(name + 1);
6643 if (jobno > 0 && jobno <= njobs
6644 && jobtab[jobno - 1].used != 0)
6645 return &jobtab[jobno - 1];
Eric Andersen2870d962001-07-02 17:27:21 +00006646#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006647 } else if (name[1] == '%' && name[2] == '\0') {
6648 goto currentjob;
6649#endif
6650 } else {
6651 struct job *found = NULL;
6652 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
6653 if (jp->used && jp->nprocs > 0
6654 && prefix(name + 1, jp->ps[0].cmd)) {
6655 if (found)
6656 error("%s: ambiguous", name);
6657 found = jp;
6658 }
6659 }
6660 if (found)
6661 return found;
6662 }
Eric Andersen2870d962001-07-02 17:27:21 +00006663 } else if (is_number(name, &pid)) {
Eric Andersencb57d552001-06-28 07:25:16 +00006664 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
6665 if (jp->used && jp->nprocs > 0
6666 && jp->ps[jp->nprocs - 1].pid == pid)
6667 return jp;
6668 }
6669 }
6670 error("No such job: %s", name);
6671 /* NOTREACHED */
6672}
6673
6674
6675
6676/*
6677 * Return a new job structure,
6678 */
6679
Eric Andersen2870d962001-07-02 17:27:21 +00006680static struct job *
Eric Andersen62483552001-07-10 06:09:16 +00006681makejob(const union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00006682{
6683 int i;
6684 struct job *jp;
6685
6686 for (i = njobs, jp = jobtab ; ; jp++) {
6687 if (--i < 0) {
6688 INTOFF;
6689 if (njobs == 0) {
6690 jobtab = ckmalloc(4 * sizeof jobtab[0]);
6691 } else {
6692 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
6693 memcpy(jp, jobtab, njobs * sizeof jp[0]);
6694 /* Relocate `ps' pointers */
6695 for (i = 0; i < njobs; i++)
6696 if (jp[i].ps == &jobtab[i].ps0)
6697 jp[i].ps = &jp[i].ps0;
6698 ckfree(jobtab);
6699 jobtab = jp;
6700 }
6701 jp = jobtab + njobs;
6702 for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
6703 INTON;
6704 break;
6705 }
6706 if (jp->used == 0)
6707 break;
6708 }
6709 INTOFF;
6710 jp->state = 0;
6711 jp->used = 1;
6712 jp->changed = 0;
6713 jp->nprocs = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006714#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006715 jp->jobctl = jobctl;
6716#endif
6717 if (nprocs > 1) {
6718 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
6719 } else {
6720 jp->ps = &jp->ps0;
6721 }
6722 INTON;
6723 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
6724 jp - jobtab + 1));
6725 return jp;
6726}
6727
6728
6729/*
6730 * Fork of a subshell. If we are doing job control, give the subshell its
6731 * own process group. Jp is a job structure that the job is to be added to.
6732 * N is the command that will be evaluated by the child. Both jp and n may
6733 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00006734 * FORK_FG - Fork off a foreground process.
6735 * FORK_BG - Fork off a background process.
6736 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
6737 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00006738 *
6739 * When job control is turned off, background processes have their standard
6740 * input redirected to /dev/null (except for the second and later processes
6741 * in a pipeline).
6742 */
6743
Eric Andersen2870d962001-07-02 17:27:21 +00006744
6745
Eric Andersencb57d552001-06-28 07:25:16 +00006746static int
Eric Andersen62483552001-07-10 06:09:16 +00006747forkshell(struct job *jp, const union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00006748{
6749 int pid;
Eric Andersen62483552001-07-10 06:09:16 +00006750#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006751 int pgrp;
Eric Andersen62483552001-07-10 06:09:16 +00006752#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006753 const char *devnull = _PATH_DEVNULL;
6754 const char *nullerr = "Can't open %s";
6755
6756 TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
6757 mode));
6758 INTOFF;
Eric Andersen72f9a422001-10-28 05:12:20 +00006759#if !defined(__UCLIBC__) || defined(__UCLIBC_HAS_MMU__)
Eric Andersencb57d552001-06-28 07:25:16 +00006760 pid = fork();
Eric Andersen72f9a422001-10-28 05:12:20 +00006761#else
6762 pid = vfork();
6763#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006764 if (pid == -1) {
6765 TRACE(("Fork failed, errno=%d\n", errno));
6766 INTON;
6767 error("Cannot fork");
6768 }
6769 if (pid == 0) {
6770 struct job *p;
6771 int wasroot;
6772 int i;
6773
6774 TRACE(("Child shell %d\n", getpid()));
6775 wasroot = rootshell;
6776 rootshell = 0;
6777 closescript();
6778 INTON;
6779 clear_traps();
Eric Andersen2870d962001-07-02 17:27:21 +00006780#ifdef JOBS
6781 jobctl = 0; /* do job control only in root shell */
Eric Andersencb57d552001-06-28 07:25:16 +00006782 if (wasroot && mode != FORK_NOJOB && mflag) {
6783 if (jp == NULL || jp->nprocs == 0)
6784 pgrp = getpid();
6785 else
6786 pgrp = jp->ps[0].pid;
6787 setpgid(0, pgrp);
6788 if (mode == FORK_FG) {
6789 /*** this causes superfluous TIOCSPGRPS ***/
6790#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006791 if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006792 error("TIOCSPGRP failed, errno=%d", errno);
6793#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006794 if (tcsetpgrp(2, pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006795 error("tcsetpgrp failed, errno=%d", errno);
6796#endif
6797 }
6798 setsignal(SIGTSTP);
6799 setsignal(SIGTTOU);
6800 } else if (mode == FORK_BG) {
6801 ignoresig(SIGINT);
6802 ignoresig(SIGQUIT);
6803 if ((jp == NULL || jp->nprocs == 0) &&
6804 ! fd0_redirected_p ()) {
6805 close(0);
6806 if (open(devnull, O_RDONLY) != 0)
6807 error(nullerr, devnull);
6808 }
6809 }
6810#else
6811 if (mode == FORK_BG) {
6812 ignoresig(SIGINT);
6813 ignoresig(SIGQUIT);
6814 if ((jp == NULL || jp->nprocs == 0) &&
6815 ! fd0_redirected_p ()) {
6816 close(0);
6817 if (open(devnull, O_RDONLY) != 0)
6818 error(nullerr, devnull);
6819 }
6820 }
6821#endif
6822 for (i = njobs, p = jobtab ; --i >= 0 ; p++)
6823 if (p->used)
6824 freejob(p);
6825 if (wasroot && iflag) {
6826 setsignal(SIGINT);
6827 setsignal(SIGQUIT);
6828 setsignal(SIGTERM);
6829 }
6830 return pid;
6831 }
Eric Andersen62483552001-07-10 06:09:16 +00006832#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006833 if (rootshell && mode != FORK_NOJOB && mflag) {
6834 if (jp == NULL || jp->nprocs == 0)
6835 pgrp = pid;
6836 else
6837 pgrp = jp->ps[0].pid;
6838 setpgid(pid, pgrp);
6839 }
Eric Andersen62483552001-07-10 06:09:16 +00006840#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006841 if (mode == FORK_BG)
Eric Andersen2870d962001-07-02 17:27:21 +00006842 backgndpid = pid; /* set $! */
Eric Andersencb57d552001-06-28 07:25:16 +00006843 if (jp) {
6844 struct procstat *ps = &jp->ps[jp->nprocs++];
6845 ps->pid = pid;
6846 ps->status = -1;
6847 ps->cmd = nullstr;
6848 if (iflag && rootshell && n)
6849 ps->cmd = commandtext(n);
6850 }
6851 INTON;
6852 TRACE(("In parent shell: child = %d\n", pid));
6853 return pid;
6854}
6855
6856
6857
6858/*
6859 * Wait for job to finish.
6860 *
6861 * Under job control we have the problem that while a child process is
6862 * running interrupts generated by the user are sent to the child but not
6863 * to the shell. This means that an infinite loop started by an inter-
6864 * active user may be hard to kill. With job control turned off, an
6865 * interactive user may place an interactive program inside a loop. If
6866 * the interactive program catches interrupts, the user doesn't want
6867 * these interrupts to also abort the loop. The approach we take here
6868 * is to have the shell ignore interrupt signals while waiting for a
6869 * forground process to terminate, and then send itself an interrupt
6870 * signal if the child process was terminated by an interrupt signal.
6871 * Unfortunately, some programs want to do a bit of cleanup and then
6872 * exit on interrupt; unless these processes terminate themselves by
6873 * sending a signal to themselves (instead of calling exit) they will
6874 * confuse this approach.
6875 */
6876
6877static int
Eric Andersen62483552001-07-10 06:09:16 +00006878waitforjob(struct job *jp)
6879{
Eric Andersen2870d962001-07-02 17:27:21 +00006880#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006881 int mypgrp = getpgrp();
6882#endif
6883 int status;
6884 int st;
6885 struct sigaction act, oact;
6886
6887 INTOFF;
6888 intreceived = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006889#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006890 if (!jobctl) {
6891#else
6892 if (!iflag) {
6893#endif
6894 sigaction(SIGINT, 0, &act);
6895 act.sa_handler = waitonint;
6896 sigaction(SIGINT, &act, &oact);
6897 }
6898 TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
6899 while (jp->state == 0) {
6900 dowait(1, jp);
6901 }
Eric Andersen2870d962001-07-02 17:27:21 +00006902#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006903 if (!jobctl) {
6904#else
6905 if (!iflag) {
6906#endif
6907 sigaction(SIGINT, &oact, 0);
6908 if (intreceived && trap[SIGINT]) kill(getpid(), SIGINT);
6909 }
Eric Andersen2870d962001-07-02 17:27:21 +00006910#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006911 if (jp->jobctl) {
6912#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006913 if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006914 error("TIOCSPGRP failed, errno=%d\n", errno);
6915#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006916 if (tcsetpgrp(2, mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006917 error("tcsetpgrp failed, errno=%d\n", errno);
6918#endif
6919 }
6920 if (jp->state == JOBSTOPPED)
6921 curjob = jp - jobtab + 1;
6922#endif
6923 status = jp->ps[jp->nprocs - 1].status;
6924 /* convert to 8 bits */
6925 if (WIFEXITED(status))
6926 st = WEXITSTATUS(status);
Eric Andersen2870d962001-07-02 17:27:21 +00006927#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006928 else if (WIFSTOPPED(status))
6929 st = WSTOPSIG(status) + 128;
6930#endif
6931 else
6932 st = WTERMSIG(status) + 128;
Eric Andersen2870d962001-07-02 17:27:21 +00006933#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006934 if (jp->jobctl) {
6935 /*
6936 * This is truly gross.
6937 * If we're doing job control, then we did a TIOCSPGRP which
6938 * caused us (the shell) to no longer be in the controlling
6939 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
6940 * intuit from the subprocess exit status whether a SIGINT
6941 * occured, and if so interrupt ourselves. Yuck. - mycroft
6942 */
6943 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
6944 raise(SIGINT);
6945 }
Eric Andersen2870d962001-07-02 17:27:21 +00006946 if (jp->state == JOBDONE)
6947
Eric Andersencb57d552001-06-28 07:25:16 +00006948#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006949 freejob(jp);
6950 INTON;
6951 return st;
6952}
6953
6954
6955
6956/*
6957 * Wait for a process to terminate.
6958 */
6959
Eric Andersen62483552001-07-10 06:09:16 +00006960/*
6961 * Do a wait system call. If job control is compiled in, we accept
6962 * stopped processes. If block is zero, we return a value of zero
6963 * rather than blocking.
6964 *
6965 * System V doesn't have a non-blocking wait system call. It does
6966 * have a SIGCLD signal that is sent to a process when one of it's
6967 * children dies. The obvious way to use SIGCLD would be to install
6968 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
6969 * was received, and have waitproc bump another counter when it got
6970 * the status of a process. Waitproc would then know that a wait
6971 * system call would not block if the two counters were different.
6972 * This approach doesn't work because if a process has children that
6973 * have not been waited for, System V will send it a SIGCLD when it
6974 * installs a signal handler for SIGCLD. What this means is that when
6975 * a child exits, the shell will be sent SIGCLD signals continuously
6976 * until is runs out of stack space, unless it does a wait call before
6977 * restoring the signal handler. The code below takes advantage of
6978 * this (mis)feature by installing a signal handler for SIGCLD and
6979 * then checking to see whether it was called. If there are any
6980 * children to be waited for, it will be.
6981 *
6982 */
6983
6984static inline int
6985waitproc(int block, int *status)
6986{
6987 int flags;
6988
6989 flags = 0;
6990#ifdef JOBS
6991 if (jobctl)
6992 flags |= WUNTRACED;
6993#endif
6994 if (block == 0)
6995 flags |= WNOHANG;
6996 return wait3(status, flags, (struct rusage *)NULL);
6997}
6998
Eric Andersencb57d552001-06-28 07:25:16 +00006999static int
Eric Andersen62483552001-07-10 06:09:16 +00007000dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00007001{
7002 int pid;
7003 int status;
7004 struct procstat *sp;
7005 struct job *jp;
7006 struct job *thisjob;
7007 int done;
7008 int stopped;
7009 int core;
7010 int sig;
7011
7012 TRACE(("dowait(%d) called\n", block));
7013 do {
7014 pid = waitproc(block, &status);
7015 TRACE(("wait returns %d, status=%d\n", pid, status));
7016 } while (!(block & 2) && pid == -1 && errno == EINTR);
7017 if (pid <= 0)
7018 return pid;
7019 INTOFF;
7020 thisjob = NULL;
7021 for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
7022 if (jp->used) {
7023 done = 1;
7024 stopped = 1;
7025 for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
7026 if (sp->pid == -1)
7027 continue;
7028 if (sp->pid == pid) {
7029 TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
7030 sp->status = status;
7031 thisjob = jp;
7032 }
7033 if (sp->status == -1)
7034 stopped = 0;
7035 else if (WIFSTOPPED(sp->status))
7036 done = 0;
7037 }
Eric Andersen2870d962001-07-02 17:27:21 +00007038 if (stopped) { /* stopped or done */
Eric Andersencb57d552001-06-28 07:25:16 +00007039 int state = done? JOBDONE : JOBSTOPPED;
7040 if (jp->state != state) {
7041 TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
7042 jp->state = state;
Eric Andersen2870d962001-07-02 17:27:21 +00007043#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007044 if (done && curjob == jp - jobtab + 1)
Eric Andersen2870d962001-07-02 17:27:21 +00007045 curjob = 0; /* no current job */
Eric Andersencb57d552001-06-28 07:25:16 +00007046#endif
7047 }
7048 }
7049 }
7050 }
7051 INTON;
7052 if (! rootshell || ! iflag || (job && thisjob == job)) {
7053 core = WCOREDUMP(status);
Eric Andersen2870d962001-07-02 17:27:21 +00007054#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007055 if (WIFSTOPPED(status)) sig = WSTOPSIG(status);
7056 else
7057#endif
7058 if (WIFEXITED(status)) sig = 0;
7059 else sig = WTERMSIG(status);
7060
7061 if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
7062 if (thisjob != job)
Eric Andersen3102ac42001-07-06 04:26:23 +00007063 out2fmt("%d: ", pid);
Eric Andersen2870d962001-07-02 17:27:21 +00007064#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007065 if (sig == SIGTSTP && rootshell && iflag)
Eric Andersen3102ac42001-07-06 04:26:23 +00007066 out2fmt("%%%ld ",
Eric Andersencb57d552001-06-28 07:25:16 +00007067 (long)(job - jobtab + 1));
7068#endif
7069 if (sig < NSIG && sys_siglist[sig])
7070 out2str(sys_siglist[sig]);
7071 else
Eric Andersen3102ac42001-07-06 04:26:23 +00007072 out2fmt("Signal %d", sig);
Eric Andersencb57d552001-06-28 07:25:16 +00007073 if (core)
7074 out2str(" - core dumped");
7075 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00007076 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00007077 TRACE(("Not printing status: status=%d, sig=%d\n",
Eric Andersencb57d552001-06-28 07:25:16 +00007078 status, sig));
7079 }
7080 } else {
7081 TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
7082 if (thisjob)
7083 thisjob->changed = 1;
7084 }
7085 return pid;
7086}
7087
7088
7089
Eric Andersencb57d552001-06-28 07:25:16 +00007090
7091/*
7092 * return 1 if there are stopped jobs, otherwise 0
7093 */
Eric Andersencb57d552001-06-28 07:25:16 +00007094static int
Eric Andersen2870d962001-07-02 17:27:21 +00007095stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007096{
7097 int jobno;
7098 struct job *jp;
7099
7100 if (job_warning)
7101 return (0);
7102 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
7103 if (jp->used == 0)
7104 continue;
7105 if (jp->state == JOBSTOPPED) {
7106 out2str("You have stopped jobs.\n");
7107 job_warning = 2;
7108 return (1);
7109 }
7110 }
7111
7112 return (0);
7113}
7114
7115/*
7116 * Return a string identifying a command (to be printed by the
7117 * jobs command.
7118 */
7119
7120static char *cmdnextc;
7121static int cmdnleft;
Eric Andersen2870d962001-07-02 17:27:21 +00007122#define MAXCMDTEXT 200
Eric Andersencb57d552001-06-28 07:25:16 +00007123
Eric Andersen2870d962001-07-02 17:27:21 +00007124static void
7125cmdputs(const char *s)
7126{
7127 const char *p;
7128 char *q;
7129 char c;
7130 int subtype = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007131
Eric Andersen2870d962001-07-02 17:27:21 +00007132 if (cmdnleft <= 0)
7133 return;
7134 p = s;
7135 q = cmdnextc;
7136 while ((c = *p++) != '\0') {
7137 if (c == CTLESC)
7138 *q++ = *p++;
7139 else if (c == CTLVAR) {
7140 *q++ = '$';
7141 if (--cmdnleft > 0)
7142 *q++ = '{';
7143 subtype = *p++;
7144 } else if (c == '=' && subtype != 0) {
7145 *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
7146 subtype = 0;
7147 } else if (c == CTLENDVAR) {
7148 *q++ = '}';
7149 } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
7150 cmdnleft++; /* ignore it */
7151 else
7152 *q++ = c;
7153 if (--cmdnleft <= 0) {
7154 *q++ = '.';
7155 *q++ = '.';
7156 *q++ = '.';
7157 break;
7158 }
7159 }
7160 cmdnextc = q;
Eric Andersencb57d552001-06-28 07:25:16 +00007161}
7162
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00007163#define CMDTXT_TABLE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007164#ifdef CMDTXT_TABLE
7165/*
7166 * To collect a lot of redundant code in cmdtxt() case statements, we
7167 * implement a mini language here. Each type of node struct has an
7168 * associated instruction sequence that operates on its members via
7169 * their offsets. The instruction are pack in unsigned chars with
7170 * format IIDDDDDE where the bits are
7171 * I : part of the instruction opcode, which are
7172 * 00 : member is a pointer to another node -- process it recursively
7173 * 40 : member is a pointer to a char string -- output it
7174 * 80 : output the string whose index is stored in the data field
7175 * CC : flag signaling that this case needs external processing
7176 * D : data - either the (shifted) index of a fixed string to output or
7177 * the actual offset of the member to operate on in the struct
7178 * (since we assume bit 0 is set, the offset is not shifted)
7179 * E : flag signaling end of instruction sequence
7180 *
7181 * WARNING: In order to handle larger offsets for 64bit archs, this code
7182 * assumes that no offset can be an odd number and stores the
7183 * end-of-instructions flag in bit 0.
7184 */
Eric Andersencb57d552001-06-28 07:25:16 +00007185
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007186#define CMDTXT_NOMORE 0x01 /* NOTE: no offset should be odd */
7187#define CMDTXT_CHARPTR 0x40
7188#define CMDTXT_STRING 0x80
7189#define CMDTXT_SPECIAL 0xC0
7190#define CMDTXT_OFFSETMASK 0x3E
7191
7192static const char * const cmdtxt_strings[] = {
7193 /* 0 1 2 3 4 5 6 7 */
7194 "; ", "(", ")", " && ", " || ", "if ", "; then ", "...",
7195 /* 8 9 10 11 12 13 */
7196 "while ", "; do ", "; done", "until ", "for ", " in ...",
7197 /* 14 15 16 17 */
7198 "case ", "???", "() ...", "<<..."
7199};
7200
7201static const char * const redir_strings[] = {
7202 ">", "<", "<>", ">>", ">|", ">&", "<&"
7203};
7204
7205static const unsigned char cmdtxt_ops[] = {
7206#define CMDTXT_NSEMI 0
7207 offsetof(union node, nbinary.ch1),
7208 0|CMDTXT_STRING,
7209 offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7210#define CMDTXT_NCMD (CMDTXT_NSEMI + 3)
7211#define CMDTXT_NPIPE (CMDTXT_NCMD)
7212#define CMDTXT_NCASE (CMDTXT_NCMD)
7213#define CMDTXT_NTO (CMDTXT_NCMD)
7214#define CMDTXT_NFROM (CMDTXT_NCMD)
7215#define CMDTXT_NFROMTO (CMDTXT_NCMD)
7216#define CMDTXT_NAPPEND (CMDTXT_NCMD)
7217#define CMDTXT_NTOOV (CMDTXT_NCMD)
7218#define CMDTXT_NTOFD (CMDTXT_NCMD)
7219#define CMDTXT_NFROMFD (CMDTXT_NCMD)
7220 CMDTXT_SPECIAL,
7221#define CMDTXT_NREDIR (CMDTXT_NPIPE + 1)
7222#define CMDTXT_NBACKGND (CMDTXT_NREDIR)
7223 offsetof(union node, nredir.n)|CMDTXT_NOMORE,
7224#define CMDTXT_NSUBSHELL (CMDTXT_NBACKGND + 1)
7225 (1*2)|CMDTXT_STRING,
7226 offsetof(union node, nredir.n),
7227 (2*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7228#define CMDTXT_NAND (CMDTXT_NSUBSHELL + 3)
7229 offsetof(union node, nbinary.ch1),
7230 (3*2)|CMDTXT_STRING,
7231 offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7232#define CMDTXT_NOR (CMDTXT_NAND + 3)
7233 offsetof(union node, nbinary.ch1),
7234 (4*2)|CMDTXT_STRING,
7235 offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7236#define CMDTXT_NIF (CMDTXT_NOR + 3)
7237 (5*2)|CMDTXT_STRING,
7238 offsetof(union node, nif.test),
7239 (6*2)|CMDTXT_STRING,
7240 offsetof(union node, nif.ifpart),
7241 (7*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7242#define CMDTXT_NWHILE (CMDTXT_NIF + 5)
7243 (8*2)|CMDTXT_STRING,
7244 offsetof(union node, nbinary.ch1),
7245 (9*2)|CMDTXT_STRING,
7246 offsetof(union node, nbinary.ch2),
7247 (10*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7248#define CMDTXT_NUNTIL (CMDTXT_NWHILE + 5)
7249 (11*2)|CMDTXT_STRING,
7250 offsetof(union node, nbinary.ch1),
7251 (9*2)|CMDTXT_STRING,
7252 offsetof(union node, nbinary.ch2),
7253 (10*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7254#define CMDTXT_NFOR (CMDTXT_NUNTIL + 5)
7255 (12*2)|CMDTXT_STRING,
7256 offsetof(union node, nfor.var)|CMDTXT_CHARPTR,
7257 (13*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7258#define CMDTXT_NCLIST (CMDTXT_NFOR + 3) /* TODO: IS THIS CORRECT??? */
7259#define CMDTXT_NNOT (CMDTXT_NCLIST) /* TODO: IS THIS CORRECT??? */
7260 (15*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7261#define CMDTXT_NDEFUN (CMDTXT_NCLIST + 1)
7262 offsetof(union node, narg.text)|CMDTXT_CHARPTR,
7263 (16*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7264#define CMDTXT_NARG (CMDTXT_NDEFUN + 2)
7265 offsetof(union node, narg.text)|CMDTXT_CHARPTR|CMDTXT_NOMORE,
7266#define CMDTXT_NHERE (CMDTXT_NARG + 1)
7267#define CMDTXT_NXHERE (CMDTXT_NHERE)
7268 (17*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7269};
7270
7271#if CMDTXT_NXHERE != 36
7272#error CMDTXT_NXHERE
7273#endif
7274
7275static const unsigned char cmdtxt_ops_index[26] = {
7276 CMDTXT_NSEMI,
7277 CMDTXT_NCMD,
7278 CMDTXT_NPIPE,
7279 CMDTXT_NREDIR,
7280 CMDTXT_NBACKGND,
7281 CMDTXT_NSUBSHELL,
7282 CMDTXT_NAND,
7283 CMDTXT_NOR,
7284 CMDTXT_NIF,
7285 CMDTXT_NWHILE,
7286 CMDTXT_NUNTIL,
7287 CMDTXT_NFOR,
7288 CMDTXT_NCASE,
7289 CMDTXT_NCLIST,
7290 CMDTXT_NDEFUN,
7291 CMDTXT_NARG,
7292 CMDTXT_NTO,
7293 CMDTXT_NFROM,
7294 CMDTXT_NFROMTO,
7295 CMDTXT_NAPPEND,
7296 CMDTXT_NTOOV,
7297 CMDTXT_NTOFD,
7298 CMDTXT_NFROMFD,
7299 CMDTXT_NHERE,
7300 CMDTXT_NXHERE,
7301 CMDTXT_NNOT,
7302};
7303
7304static void
7305cmdtxt(const union node *n)
7306{
7307 const char *p;
7308
7309 if (n == NULL)
7310 return;
7311
7312 p = cmdtxt_ops + (int) cmdtxt_ops_index[n->type];
7313 if ((*p & CMDTXT_SPECIAL) != CMDTXT_SPECIAL) { /* normal case */
7314 do {
7315 if (*p & CMDTXT_STRING) { /* output fixed string */
7316 cmdputs(cmdtxt_strings[((int)(*p & CMDTXT_OFFSETMASK) >> 1)]);
Manuel Novoa III c639a352001-08-12 17:32:56 +00007317 } else {
7318 const char *pf = ((const char *) n)
7319 + ((int)(*p & CMDTXT_OFFSETMASK));
7320 if (*p & CMDTXT_CHARPTR) { /* output dynamic string */
7321 cmdputs(*((const char **) pf));
7322 } else { /* output field */
7323 cmdtxt(*((const union node **) pf));
7324 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007325 }
7326 } while (!(*p++ & CMDTXT_NOMORE));
7327 } else if (n->type == NCMD) {
7328 union node *np;
7329 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7330 cmdtxt(np);
7331 if (np->narg.next)
7332 cmdputs(spcstr);
7333 }
7334 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7335 cmdputs(spcstr);
7336 cmdtxt(np);
7337 }
7338 } else if (n->type == NPIPE) {
7339 struct nodelist *lp;
7340 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7341 cmdtxt(lp->n);
7342 if (lp->next)
7343 cmdputs(" | ");
7344 }
7345 } else if (n->type == NCASE) {
7346 cmdputs(cmdtxt_strings[14]);
7347 cmdputs(n->ncase.expr->narg.text);
7348 cmdputs(cmdtxt_strings[13]);
7349 } else {
7350#if (NTO != 16) || (NFROM != 17) || (NFROMTO != 18) || (NAPPEND != 19) || (NTOOV != 20) || (NTOFD != 21) || (NFROMFD != 22)
7351#error Assumption violated regarding range and ordering of NTO ... NFROMFD!
7352#endif
7353 char s[2];
7354
7355#ifdef DEBUG
7356 assert((n->type >= NTO) && (n->type <= NFROMFD));
7357#endif
7358
7359 p = redir_strings[n->type - NTO];
7360 if (n->nfile.fd != ('>' == *p)) {
7361 s[0] = n->nfile.fd + '0';
7362 s[1] = '\0';
7363 cmdputs(s);
7364 }
7365 cmdputs(p);
7366 if (n->type >= NTOFD) {
7367 s[0] = n->ndup.dupfd + '0';
7368 s[1] = '\0';
7369 cmdputs(s);
7370 } else {
7371 cmdtxt(n->nfile.fname);
7372 }
7373 }
7374}
7375#else /* CMDTXT_TABLE */
Eric Andersencb57d552001-06-28 07:25:16 +00007376static void
Eric Andersen2870d962001-07-02 17:27:21 +00007377cmdtxt(const union node *n)
7378{
Eric Andersencb57d552001-06-28 07:25:16 +00007379 union node *np;
7380 struct nodelist *lp;
7381 const char *p;
7382 int i;
7383 char s[2];
7384
7385 if (n == NULL)
7386 return;
7387 switch (n->type) {
7388 case NSEMI:
7389 cmdtxt(n->nbinary.ch1);
7390 cmdputs("; ");
7391 cmdtxt(n->nbinary.ch2);
7392 break;
7393 case NAND:
7394 cmdtxt(n->nbinary.ch1);
7395 cmdputs(" && ");
7396 cmdtxt(n->nbinary.ch2);
7397 break;
7398 case NOR:
7399 cmdtxt(n->nbinary.ch1);
7400 cmdputs(" || ");
7401 cmdtxt(n->nbinary.ch2);
7402 break;
7403 case NPIPE:
7404 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7405 cmdtxt(lp->n);
7406 if (lp->next)
7407 cmdputs(" | ");
7408 }
7409 break;
7410 case NSUBSHELL:
7411 cmdputs("(");
7412 cmdtxt(n->nredir.n);
7413 cmdputs(")");
7414 break;
7415 case NREDIR:
7416 case NBACKGND:
7417 cmdtxt(n->nredir.n);
7418 break;
7419 case NIF:
7420 cmdputs("if ");
7421 cmdtxt(n->nif.test);
7422 cmdputs("; then ");
7423 cmdtxt(n->nif.ifpart);
7424 cmdputs("...");
7425 break;
7426 case NWHILE:
7427 cmdputs("while ");
7428 goto until;
7429 case NUNTIL:
7430 cmdputs("until ");
7431until:
7432 cmdtxt(n->nbinary.ch1);
7433 cmdputs("; do ");
7434 cmdtxt(n->nbinary.ch2);
7435 cmdputs("; done");
7436 break;
7437 case NFOR:
7438 cmdputs("for ");
7439 cmdputs(n->nfor.var);
7440 cmdputs(" in ...");
7441 break;
7442 case NCASE:
7443 cmdputs("case ");
7444 cmdputs(n->ncase.expr->narg.text);
7445 cmdputs(" in ...");
7446 break;
7447 case NDEFUN:
7448 cmdputs(n->narg.text);
7449 cmdputs("() ...");
7450 break;
7451 case NCMD:
7452 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7453 cmdtxt(np);
7454 if (np->narg.next)
7455 cmdputs(spcstr);
7456 }
7457 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7458 cmdputs(spcstr);
7459 cmdtxt(np);
7460 }
7461 break;
7462 case NARG:
7463 cmdputs(n->narg.text);
7464 break;
7465 case NTO:
7466 p = ">"; i = 1; goto redir;
7467 case NAPPEND:
7468 p = ">>"; i = 1; goto redir;
7469 case NTOFD:
7470 p = ">&"; i = 1; goto redir;
7471 case NTOOV:
7472 p = ">|"; i = 1; goto redir;
7473 case NFROM:
7474 p = "<"; i = 0; goto redir;
7475 case NFROMFD:
7476 p = "<&"; i = 0; goto redir;
7477 case NFROMTO:
7478 p = "<>"; i = 0; goto redir;
7479redir:
7480 if (n->nfile.fd != i) {
7481 s[0] = n->nfile.fd + '0';
7482 s[1] = '\0';
7483 cmdputs(s);
7484 }
7485 cmdputs(p);
7486 if (n->type == NTOFD || n->type == NFROMFD) {
7487 s[0] = n->ndup.dupfd + '0';
7488 s[1] = '\0';
7489 cmdputs(s);
7490 } else {
7491 cmdtxt(n->nfile.fname);
7492 }
7493 break;
7494 case NHERE:
7495 case NXHERE:
7496 cmdputs("<<...");
7497 break;
7498 default:
7499 cmdputs("???");
7500 break;
7501 }
7502}
Manuel Novoa III c639a352001-08-12 17:32:56 +00007503#endif /* CMDTXT_TABLE */
Eric Andersencb57d552001-06-28 07:25:16 +00007504
Eric Andersen2870d962001-07-02 17:27:21 +00007505static char *
7506commandtext(const union node *n)
7507{
7508 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007509
Eric Andersen2870d962001-07-02 17:27:21 +00007510 cmdnextc = name = ckmalloc(MAXCMDTEXT);
7511 cmdnleft = MAXCMDTEXT - 4;
7512 cmdtxt(n);
7513 *cmdnextc = '\0';
7514 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00007515}
7516
Eric Andersen2870d962001-07-02 17:27:21 +00007517
Eric Andersencb57d552001-06-28 07:25:16 +00007518static void waitonint(int sig) {
7519 intreceived = 1;
7520 return;
7521}
Eric Andersenec074692001-10-31 11:05:49 +00007522
7523#ifdef ASH_MAIL
7524
Eric Andersencb57d552001-06-28 07:25:16 +00007525/*
Eric Andersenec074692001-10-31 11:05:49 +00007526 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +00007527 */
7528
7529
7530#define MAXMBOXES 10
7531
7532
Eric Andersen2870d962001-07-02 17:27:21 +00007533static int nmboxes; /* number of mailboxes */
7534static time_t mailtime[MAXMBOXES]; /* times of mailboxes */
Eric Andersencb57d552001-06-28 07:25:16 +00007535
7536
7537
7538/*
7539 * Print appropriate message(s) if mail has arrived. If the argument is
7540 * nozero, then the value of MAIL has changed, so we just update the
7541 * values.
7542 */
7543
7544static void
Eric Andersen2870d962001-07-02 17:27:21 +00007545chkmail(int silent)
Eric Andersencb57d552001-06-28 07:25:16 +00007546{
7547 int i;
7548 const char *mpath;
7549 char *p;
7550 char *q;
7551 struct stackmark smark;
7552 struct stat statb;
7553
7554 if (silent)
7555 nmboxes = 10;
7556 if (nmboxes == 0)
7557 return;
7558 setstackmark(&smark);
7559 mpath = mpathset()? mpathval() : mailval();
7560 for (i = 0 ; i < nmboxes ; i++) {
7561 p = padvance(&mpath, nullstr);
7562 if (p == NULL)
7563 break;
7564 if (*p == '\0')
7565 continue;
7566 for (q = p ; *q ; q++);
7567#ifdef DEBUG
7568 if (q[-1] != '/')
7569 abort();
7570#endif
Eric Andersen2870d962001-07-02 17:27:21 +00007571 q[-1] = '\0'; /* delete trailing '/' */
Eric Andersencb57d552001-06-28 07:25:16 +00007572 if (stat(p, &statb) < 0)
7573 statb.st_size = 0;
7574 if (statb.st_size > mailtime[i] && ! silent) {
Eric Andersen3102ac42001-07-06 04:26:23 +00007575 out2fmt(snlfmt,
7576 pathopt? pathopt : "you have mail");
Eric Andersencb57d552001-06-28 07:25:16 +00007577 }
7578 mailtime[i] = statb.st_size;
Eric Andersencb57d552001-06-28 07:25:16 +00007579 }
7580 nmboxes = i;
7581 popstackmark(&smark);
7582}
Eric Andersencb57d552001-06-28 07:25:16 +00007583
Eric Andersenec074692001-10-31 11:05:49 +00007584#endif /* ASH_MAIL */
7585
Eric Andersencb57d552001-06-28 07:25:16 +00007586#define PROFILE 0
7587
Eric Andersencb57d552001-06-28 07:25:16 +00007588#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007589static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007590extern int etext();
7591#endif
7592
Eric Andersen2870d962001-07-02 17:27:21 +00007593static void read_profile (const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007594static void cmdloop (int);
7595static void options (int);
Eric Andersen2870d962001-07-02 17:27:21 +00007596static void setoption (int, int);
7597static void procargs (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00007598
Eric Andersen2870d962001-07-02 17:27:21 +00007599
Eric Andersencb57d552001-06-28 07:25:16 +00007600/*
7601 * Main routine. We initialize things, parse the arguments, execute
7602 * profiles if we're a login shell, and then call cmdloop to execute
7603 * commands. The setjmp call sets up the location to jump to when an
7604 * exception occurs. When an exception occurs the variable "state"
7605 * is used to figure out how far we had gotten.
7606 */
7607
7608int
Matt Kraai2d91deb2001-08-01 17:21:35 +00007609ash_main(argc, argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007610 int argc;
7611 char **argv;
7612{
7613 struct jmploc jmploc;
7614 struct stackmark smark;
7615 volatile int state;
Eric Andersen62483552001-07-10 06:09:16 +00007616 const char *shinit;
Eric Andersencb57d552001-06-28 07:25:16 +00007617
Eric Andersencb57d552001-06-28 07:25:16 +00007618 BLTINCMD = find_builtin("builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00007619 EXECCMD = find_builtin("exec");
7620 EVALCMD = find_builtin("eval");
7621
Eric Andersenbdfd0d72001-10-24 05:00:29 +00007622#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
Eric Andersen1c039232001-07-07 00:05:55 +00007623 unsetenv("PS1");
7624 unsetenv("PS2");
7625#endif
7626
Eric Andersencb57d552001-06-28 07:25:16 +00007627#if PROFILE
7628 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7629#endif
7630#if defined(linux) || defined(__GNU__)
7631 signal(SIGCHLD, SIG_DFL);
7632#endif
7633 state = 0;
7634 if (setjmp(jmploc.loc)) {
7635 INTOFF;
7636 /*
7637 * When a shell procedure is executed, we raise the
7638 * exception EXSHELLPROC to clean up before executing
7639 * the shell procedure.
7640 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007641 if (exception == EXSHELLPROC) {
Eric Andersencb57d552001-06-28 07:25:16 +00007642 rootpid = getpid();
7643 rootshell = 1;
7644 minusc = NULL;
7645 state = 3;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007646 } else {
7647 if (exception == EXEXEC) {
7648 exitstatus = exerrno;
7649 } else if (exception == EXERROR) {
7650 exitstatus = 2;
7651 }
Eric Andersencb57d552001-06-28 07:25:16 +00007652 if (state == 0 || iflag == 0 || ! rootshell)
7653 exitshell(exitstatus);
7654 }
7655 reset();
Eric Andersen2870d962001-07-02 17:27:21 +00007656 if (exception == EXINT) {
Eric Andersencb57d552001-06-28 07:25:16 +00007657 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00007658 }
7659 popstackmark(&smark);
Eric Andersen2870d962001-07-02 17:27:21 +00007660 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007661 if (state == 1)
7662 goto state1;
7663 else if (state == 2)
7664 goto state2;
7665 else if (state == 3)
7666 goto state3;
7667 else
7668 goto state4;
7669 }
7670 handler = &jmploc;
7671#ifdef DEBUG
7672 opentrace();
7673 trputs("Shell args: "); trargs(argv);
7674#endif
7675 rootpid = getpid();
7676 rootshell = 1;
7677 init();
7678 setstackmark(&smark);
7679 procargs(argc, argv);
7680 if (argv[0] && argv[0][0] == '-') {
7681 state = 1;
7682 read_profile("/etc/profile");
7683state1:
7684 state = 2;
7685 read_profile(".profile");
7686 }
7687state2:
7688 state = 3;
7689#ifndef linux
7690 if (getuid() == geteuid() && getgid() == getegid()) {
7691#endif
7692 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7693 state = 3;
7694 read_profile(shinit);
7695 }
7696#ifndef linux
7697 }
7698#endif
7699state3:
7700 state = 4;
7701 if (sflag == 0 || minusc) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007702 static const char sigs[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00007703 SIGINT, SIGQUIT, SIGHUP,
Eric Andersencb57d552001-06-28 07:25:16 +00007704#ifdef SIGTSTP
7705 SIGTSTP,
7706#endif
7707 SIGPIPE
7708 };
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007709#define SIGSSIZE ((sizeof(sigs)/sizeof(sigs[0])) - 1) /* trailing nul */
Eric Andersencb57d552001-06-28 07:25:16 +00007710 int i;
7711
7712 for (i = 0; i < SIGSSIZE; i++)
7713 setsignal(sigs[i]);
7714 }
7715
7716 if (minusc)
7717 evalstring(minusc, 0);
7718
7719 if (sflag || minusc == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00007720state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007721 cmdloop(1);
7722 }
7723#if PROFILE
7724 monitor(0);
7725#endif
7726 exitshell(exitstatus);
7727 /* NOTREACHED */
7728}
7729
7730
7731/*
7732 * Read and execute commands. "Top" is nonzero for the top level command
7733 * loop; it turns on prompting if the shell is interactive.
7734 */
7735
7736static void
Eric Andersen2870d962001-07-02 17:27:21 +00007737cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00007738{
7739 union node *n;
7740 struct stackmark smark;
7741 int inter;
7742 int numeof = 0;
7743
7744 TRACE(("cmdloop(%d) called\n", top));
7745 setstackmark(&smark);
7746 for (;;) {
7747 if (pendingsigs)
7748 dotrap();
7749 inter = 0;
7750 if (iflag && top) {
7751 inter++;
7752 showjobs(1);
Eric Andersenec074692001-10-31 11:05:49 +00007753#ifdef ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +00007754 chkmail(0);
Eric Andersenec074692001-10-31 11:05:49 +00007755#endif
Eric Andersen3102ac42001-07-06 04:26:23 +00007756 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00007757 }
7758 n = parsecmd(inter);
7759 /* showtree(n); DEBUG */
7760 if (n == NEOF) {
7761 if (!top || numeof >= 50)
7762 break;
7763 if (!stoppedjobs()) {
7764 if (!Iflag)
7765 break;
7766 out2str("\nUse \"exit\" to leave shell.\n");
7767 }
7768 numeof++;
7769 } else if (n != NULL && nflag == 0) {
7770 job_warning = (job_warning == 2) ? 1 : 0;
7771 numeof = 0;
7772 evaltree(n, 0);
7773 }
7774 popstackmark(&smark);
7775 setstackmark(&smark);
7776 if (evalskip == SKIPFILE) {
7777 evalskip = 0;
7778 break;
7779 }
7780 }
7781 popstackmark(&smark);
7782}
7783
7784
7785
7786/*
7787 * Read /etc/profile or .profile. Return on error.
7788 */
7789
7790static void
7791read_profile(name)
7792 const char *name;
7793{
7794 int fd;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007795 int xflag_save;
7796 int vflag_save;
Eric Andersencb57d552001-06-28 07:25:16 +00007797
7798 INTOFF;
7799 if ((fd = open(name, O_RDONLY)) >= 0)
7800 setinputfd(fd, 1);
7801 INTON;
7802 if (fd < 0)
7803 return;
7804 /* -q turns off -x and -v just when executing init files */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007805 /* Note: Might do a little redundant work, but reduces code size. */
7806 xflag_save = xflag;
7807 vflag_save = vflag;
Eric Andersencb57d552001-06-28 07:25:16 +00007808 if (qflag) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007809 vflag = xflag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007810 }
7811 cmdloop(0);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007812 xflag = xflag_save;
7813 vflag = vflag_save;
Eric Andersencb57d552001-06-28 07:25:16 +00007814 popfile();
7815}
7816
7817
7818
7819/*
7820 * Read a file containing shell functions.
7821 */
7822
7823static void
Eric Andersen2870d962001-07-02 17:27:21 +00007824readcmdfile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00007825{
7826 int fd;
7827
7828 INTOFF;
7829 if ((fd = open(name, O_RDONLY)) >= 0)
7830 setinputfd(fd, 1);
7831 else
7832 error("Can't open %s", name);
7833 INTON;
7834 cmdloop(0);
7835 popfile();
7836}
7837
7838
7839
7840/*
7841 * Take commands from a file. To be compatable we should do a path
7842 * search for the file, which is necessary to find sub-commands.
7843 */
7844
Eric Andersen62483552001-07-10 06:09:16 +00007845static inline char *
Eric Andersen74400cc2001-10-18 04:11:39 +00007846find_dot_file(char *mybasename)
Eric Andersencb57d552001-06-28 07:25:16 +00007847{
7848 char *fullname;
7849 const char *path = pathval();
7850 struct stat statb;
7851
7852 /* don't try this for absolute or relative paths */
7853 if (strchr(mybasename, '/'))
7854 return mybasename;
7855
7856 while ((fullname = padvance(&path, mybasename)) != NULL) {
7857 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
7858 /*
7859 * Don't bother freeing here, since it will
7860 * be freed by the caller.
7861 */
7862 return fullname;
7863 }
7864 stunalloc(fullname);
7865 }
7866
7867 /* not found in the PATH */
7868 error("%s: not found", mybasename);
7869 /* NOTREACHED */
7870}
7871
7872static int
7873dotcmd(argc, argv)
7874 int argc;
7875 char **argv;
7876{
7877 struct strlist *sp;
Eric Andersen69a20f02001-10-31 10:40:37 +00007878 volatile struct shparam saveparam;
Eric Andersencb57d552001-06-28 07:25:16 +00007879 exitstatus = 0;
7880
7881 for (sp = cmdenviron; sp ; sp = sp->next)
7882 setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
7883
Eric Andersen2870d962001-07-02 17:27:21 +00007884 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00007885 char *fullname;
7886 struct stackmark smark;
7887
7888 setstackmark(&smark);
7889 fullname = find_dot_file(argv[1]);
Eric Andersen69a20f02001-10-31 10:40:37 +00007890
7891 if (argc>2) {
7892 saveparam = shellparam;
7893 shellparam.malloc = 0;
7894 shellparam.nparam = argc - 2;
7895 shellparam.p = argv + 2;
7896 };
7897
Eric Andersencb57d552001-06-28 07:25:16 +00007898 setinputfile(fullname, 1);
7899 commandname = fullname;
7900 cmdloop(0);
7901 popfile();
Eric Andersen69a20f02001-10-31 10:40:37 +00007902
7903 if (argc>2) {
7904 freeparam(&shellparam);
7905 shellparam = saveparam;
7906 };
7907
Eric Andersencb57d552001-06-28 07:25:16 +00007908 popstackmark(&smark);
7909 }
7910 return exitstatus;
7911}
7912
7913
7914static int
7915exitcmd(argc, argv)
7916 int argc;
7917 char **argv;
7918{
7919 if (stoppedjobs())
7920 return 0;
7921 if (argc > 1)
7922 exitstatus = number(argv[1]);
7923 else
7924 exitstatus = oexitstatus;
7925 exitshell(exitstatus);
7926 /* NOTREACHED */
7927}
Eric Andersen62483552001-07-10 06:09:16 +00007928
Eric Andersen2870d962001-07-02 17:27:21 +00007929static pointer
7930stalloc(int nbytes)
Eric Andersencb57d552001-06-28 07:25:16 +00007931{
7932 char *p;
7933
7934 nbytes = ALIGN(nbytes);
7935 if (nbytes > stacknleft) {
7936 int blocksize;
7937 struct stack_block *sp;
7938
7939 blocksize = nbytes;
7940 if (blocksize < MINSIZE)
7941 blocksize = MINSIZE;
7942 INTOFF;
7943 sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
7944 sp->prev = stackp;
7945 stacknxt = sp->space;
7946 stacknleft = blocksize;
7947 stackp = sp;
7948 INTON;
7949 }
7950 p = stacknxt;
7951 stacknxt += nbytes;
7952 stacknleft -= nbytes;
7953 return p;
7954}
7955
7956
7957static void
Eric Andersen2870d962001-07-02 17:27:21 +00007958stunalloc(pointer p)
7959{
Eric Andersencb57d552001-06-28 07:25:16 +00007960#ifdef DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +00007961 if (p == NULL) { /*DEBUG */
Eric Andersencb57d552001-06-28 07:25:16 +00007962 write(2, "stunalloc\n", 10);
7963 abort();
7964 }
7965#endif
7966 if (!(stacknxt >= (char *)p && (char *)p >= stackp->space)) {
7967 p = stackp->space;
7968 }
7969 stacknleft += stacknxt - (char *)p;
7970 stacknxt = p;
7971}
7972
7973
Eric Andersencb57d552001-06-28 07:25:16 +00007974static void
Eric Andersen2870d962001-07-02 17:27:21 +00007975setstackmark(struct stackmark *mark)
7976{
Eric Andersencb57d552001-06-28 07:25:16 +00007977 mark->stackp = stackp;
7978 mark->stacknxt = stacknxt;
7979 mark->stacknleft = stacknleft;
7980 mark->marknext = markp;
7981 markp = mark;
7982}
7983
7984
7985static void
Eric Andersen2870d962001-07-02 17:27:21 +00007986popstackmark(struct stackmark *mark)
7987{
Eric Andersencb57d552001-06-28 07:25:16 +00007988 struct stack_block *sp;
7989
7990 INTOFF;
7991 markp = mark->marknext;
7992 while (stackp != mark->stackp) {
7993 sp = stackp;
7994 stackp = sp->prev;
7995 ckfree(sp);
7996 }
7997 stacknxt = mark->stacknxt;
7998 stacknleft = mark->stacknleft;
7999 INTON;
8000}
8001
8002
8003/*
8004 * When the parser reads in a string, it wants to stick the string on the
8005 * stack and only adjust the stack pointer when it knows how big the
8006 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8007 * of space on top of the stack and stackblocklen returns the length of
8008 * this block. Growstackblock will grow this space by at least one byte,
8009 * possibly moving it (like realloc). Grabstackblock actually allocates the
8010 * part of the block that has been used.
8011 */
8012
8013static void
Eric Andersen2870d962001-07-02 17:27:21 +00008014growstackblock(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00008015 char *p;
8016 int newlen = ALIGN(stacknleft * 2 + 100);
8017 char *oldspace = stacknxt;
8018 int oldlen = stacknleft;
8019 struct stack_block *sp;
8020 struct stack_block *oldstackp;
8021
8022 if (stacknxt == stackp->space && stackp != &stackbase) {
8023 INTOFF;
8024 oldstackp = stackp;
8025 sp = stackp;
8026 stackp = sp->prev;
8027 sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen);
8028 sp->prev = stackp;
8029 stackp = sp;
8030 stacknxt = sp->space;
8031 stacknleft = newlen;
8032 {
8033 /* Stack marks pointing to the start of the old block
Eric Andersen2870d962001-07-02 17:27:21 +00008034 * must be relocated to point to the new block
Eric Andersencb57d552001-06-28 07:25:16 +00008035 */
8036 struct stackmark *xmark;
8037 xmark = markp;
8038 while (xmark != NULL && xmark->stackp == oldstackp) {
8039 xmark->stackp = stackp;
8040 xmark->stacknxt = stacknxt;
8041 xmark->stacknleft = stacknleft;
8042 xmark = xmark->marknext;
8043 }
8044 }
8045 INTON;
8046 } else {
8047 p = stalloc(newlen);
8048 memcpy(p, oldspace, oldlen);
Eric Andersen2870d962001-07-02 17:27:21 +00008049 stacknxt = p; /* free the space */
8050 stacknleft += newlen; /* we just allocated */
Eric Andersencb57d552001-06-28 07:25:16 +00008051 }
8052}
8053
8054
8055
Eric Andersen2870d962001-07-02 17:27:21 +00008056static inline void
8057grabstackblock(int len)
Eric Andersencb57d552001-06-28 07:25:16 +00008058{
8059 len = ALIGN(len);
8060 stacknxt += len;
8061 stacknleft -= len;
8062}
8063
8064
8065
8066/*
8067 * The following routines are somewhat easier to use that the above.
8068 * The user declares a variable of type STACKSTR, which may be declared
8069 * to be a register. The macro STARTSTACKSTR initializes things. Then
8070 * the user uses the macro STPUTC to add characters to the string. In
8071 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8072 * grown as necessary. When the user is done, she can just leave the
8073 * string there and refer to it using stackblock(). Or she can allocate
8074 * the space for it using grabstackstr(). If it is necessary to allow
8075 * someone else to use the stack temporarily and then continue to grow
8076 * the string, the user should use grabstack to allocate the space, and
8077 * then call ungrabstr(p) to return to the previous mode of operation.
8078 *
8079 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8080 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8081 * is space for at least one character.
8082 */
8083
8084
8085static char *
Eric Andersen2870d962001-07-02 17:27:21 +00008086growstackstr(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00008087 int len = stackblocksize();
8088 if (herefd >= 0 && len >= 1024) {
8089 xwrite(herefd, stackblock(), len);
8090 sstrnleft = len - 1;
8091 return stackblock();
8092 }
8093 growstackblock();
8094 sstrnleft = stackblocksize() - len - 1;
8095 return stackblock() + len;
8096}
8097
8098
8099/*
8100 * Called from CHECKSTRSPACE.
8101 */
8102
8103static char *
8104makestrspace(size_t newlen) {
8105 int len = stackblocksize() - sstrnleft;
8106 do {
8107 growstackblock();
8108 sstrnleft = stackblocksize() - len;
8109 } while (sstrnleft < newlen);
8110 return stackblock() + len;
8111}
8112
8113
8114
8115static void
Eric Andersen2870d962001-07-02 17:27:21 +00008116ungrabstackstr(char *s, char *p)
8117{
Eric Andersencb57d552001-06-28 07:25:16 +00008118 stacknleft += stacknxt - s;
8119 stacknxt = s;
8120 sstrnleft = stacknleft - (p - s);
8121}
Eric Andersencb57d552001-06-28 07:25:16 +00008122/*
8123 * Miscelaneous builtins.
8124 */
8125
8126
8127#undef rflag
8128
Eric Andersencb57d552001-06-28 07:25:16 +00008129#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersen62483552001-07-10 06:09:16 +00008130typedef long rlim_t;
Eric Andersencb57d552001-06-28 07:25:16 +00008131#endif
8132
8133
8134
8135/*
8136 * The read builtin. The -e option causes backslashes to escape the
8137 * following character.
8138 *
8139 * This uses unbuffered input, which may be avoidable in some cases.
8140 */
8141
8142static int
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008143readcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008144{
8145 char **ap;
8146 int backslash;
8147 char c;
8148 int rflag;
8149 char *prompt;
8150 const char *ifs;
8151 char *p;
8152 int startword;
8153 int status;
8154 int i;
8155
8156 rflag = 0;
8157 prompt = NULL;
8158 while ((i = nextopt("p:r")) != '\0') {
8159 if (i == 'p')
8160 prompt = optionarg;
8161 else
8162 rflag = 1;
8163 }
8164 if (prompt && isatty(0)) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008165 out2str(prompt); /* read without cmdedit */
Eric Andersencb57d552001-06-28 07:25:16 +00008166 flushall();
8167 }
8168 if (*(ap = argptr) == NULL)
8169 error("arg count");
8170 if ((ifs = bltinlookup("IFS")) == NULL)
8171 ifs = defifs;
8172 status = 0;
8173 startword = 1;
8174 backslash = 0;
8175 STARTSTACKSTR(p);
8176 for (;;) {
8177 if (read(0, &c, 1) != 1) {
8178 status = 1;
8179 break;
8180 }
8181 if (c == '\0')
8182 continue;
8183 if (backslash) {
8184 backslash = 0;
8185 if (c != '\n')
8186 STPUTC(c, p);
8187 continue;
8188 }
8189 if (!rflag && c == '\\') {
8190 backslash++;
8191 continue;
8192 }
8193 if (c == '\n')
8194 break;
8195 if (startword && *ifs == ' ' && strchr(ifs, c)) {
8196 continue;
8197 }
8198 startword = 0;
8199 if (backslash && c == '\\') {
8200 if (read(0, &c, 1) != 1) {
8201 status = 1;
8202 break;
8203 }
8204 STPUTC(c, p);
8205 } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
8206 STACKSTRNUL(p);
8207 setvar(*ap, stackblock(), 0);
8208 ap++;
8209 startword = 1;
8210 STARTSTACKSTR(p);
8211 } else {
8212 STPUTC(c, p);
8213 }
8214 }
8215 STACKSTRNUL(p);
8216 /* Remove trailing blanks */
8217 while (stackblock() <= --p && strchr(ifs, *p) != NULL)
8218 *p = '\0';
8219 setvar(*ap, stackblock(), 0);
8220 while (*++ap != NULL)
8221 setvar(*ap, nullstr, 0);
8222 return status;
8223}
8224
8225
8226
8227static int
8228umaskcmd(argc, argv)
8229 int argc;
8230 char **argv;
8231{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008232 static const char permuser[3] = "ugo";
8233 static const char permmode[3] = "rwx";
8234 static const short int permmask[] = {
8235 S_IRUSR, S_IWUSR, S_IXUSR,
8236 S_IRGRP, S_IWGRP, S_IXGRP,
8237 S_IROTH, S_IWOTH, S_IXOTH
8238 };
8239
Eric Andersencb57d552001-06-28 07:25:16 +00008240 char *ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008241 mode_t mask;
Eric Andersencb57d552001-06-28 07:25:16 +00008242 int i;
8243 int symbolic_mode = 0;
8244
Eric Andersen62483552001-07-10 06:09:16 +00008245 while (nextopt("S") != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00008246 symbolic_mode = 1;
8247 }
8248
8249 INTOFF;
8250 mask = umask(0);
8251 umask(mask);
8252 INTON;
8253
8254 if ((ap = *argptr) == NULL) {
8255 if (symbolic_mode) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008256 char buf[18];
8257 char *p = buf;
8258 for (i=0 ; i<3 ; i++) {
8259 int j;
8260 *p++ = permuser[i];
8261 *p++ = '=';
8262 for (j=0 ; j<3 ; j++) {
8263 if ((mask & permmask[3*i+j]) == 0) {
8264 *p++ = permmode[j];
8265 }
8266 }
8267 *p++ = ',';
8268 }
8269 *--p = 0;
8270 puts(buf);
Eric Andersencb57d552001-06-28 07:25:16 +00008271 } else {
Eric Andersen62483552001-07-10 06:09:16 +00008272 printf("%.4o\n", mask);
Eric Andersencb57d552001-06-28 07:25:16 +00008273 }
8274 } else {
Eric Andersen62483552001-07-10 06:09:16 +00008275 if (is_digit((unsigned char)*ap)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008276 mask = 0;
8277 do {
8278 if (*ap >= '8' || *ap < '0')
8279 error("Illegal number: %s", argv[1]);
8280 mask = (mask << 3) + (*ap - '0');
8281 } while (*++ap != '\0');
8282 umask(mask);
8283 } else {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008284 mask = ~mask & 0777;
8285 if (parse_mode(ap, &mask) == FALSE) {
Eric Andersencb57d552001-06-28 07:25:16 +00008286 error("Illegal mode: %s", ap);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008287 }
Eric Andersencb57d552001-06-28 07:25:16 +00008288 umask(~mask & 0777);
8289 }
8290 }
8291 return 0;
8292}
8293
8294/*
8295 * ulimit builtin
8296 *
8297 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
8298 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
8299 * ash by J.T. Conklin.
8300 *
8301 * Public domain.
8302 */
8303
8304struct limits {
8305 const char *name;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008306 short cmd;
8307 short factor; /* multiply by to get rlim_{cur,max} values */
Eric Andersencb57d552001-06-28 07:25:16 +00008308};
8309
8310static const struct limits limits[] = {
8311#ifdef RLIMIT_CPU
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008312 { "time(seconds)", RLIMIT_CPU, 1 },
Eric Andersencb57d552001-06-28 07:25:16 +00008313#endif
8314#ifdef RLIMIT_FSIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008315 { "file(blocks)", RLIMIT_FSIZE, 512 },
Eric Andersencb57d552001-06-28 07:25:16 +00008316#endif
8317#ifdef RLIMIT_DATA
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008318 { "data(kbytes)", RLIMIT_DATA, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008319#endif
8320#ifdef RLIMIT_STACK
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008321 { "stack(kbytes)", RLIMIT_STACK, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008322#endif
8323#ifdef RLIMIT_CORE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008324 { "coredump(blocks)", RLIMIT_CORE, 512 },
Eric Andersencb57d552001-06-28 07:25:16 +00008325#endif
8326#ifdef RLIMIT_RSS
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008327 { "memory(kbytes)", RLIMIT_RSS, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008328#endif
8329#ifdef RLIMIT_MEMLOCK
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008330 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008331#endif
8332#ifdef RLIMIT_NPROC
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008333 { "process(processes)", RLIMIT_NPROC, 1 },
Eric Andersencb57d552001-06-28 07:25:16 +00008334#endif
8335#ifdef RLIMIT_NOFILE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008336 { "nofiles(descriptors)", RLIMIT_NOFILE, 1 },
Eric Andersencb57d552001-06-28 07:25:16 +00008337#endif
8338#ifdef RLIMIT_VMEM
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008339 { "vmemory(kbytes)", RLIMIT_VMEM, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008340#endif
8341#ifdef RLIMIT_SWAP
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008342 { "swap(kbytes)", RLIMIT_SWAP, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008343#endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008344 { NULL, 0, 0 }
Eric Andersencb57d552001-06-28 07:25:16 +00008345};
8346
8347static int
8348ulimitcmd(argc, argv)
8349 int argc;
8350 char **argv;
8351{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008352 static const char unlimited_string[] = "unlimited";
Eric Andersen2870d962001-07-02 17:27:21 +00008353 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00008354 rlim_t val = 0;
8355 enum { SOFT = 0x1, HARD = 0x2 }
8356 how = SOFT | HARD;
Eric Andersen2870d962001-07-02 17:27:21 +00008357 const struct limits *l;
8358 int set, all = 0;
8359 int optc, what;
8360 struct rlimit limit;
Eric Andersencb57d552001-06-28 07:25:16 +00008361
8362 what = 'f';
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008363
8364 while ((optc = nextopt("HSa"
8365#ifdef RLIMIT_CPU
8366 "t"
8367#endif
8368#ifdef RLIMIT_FSIZE
8369 "f"
8370#endif
8371#ifdef RLIMIT_DATA
8372 "d"
8373#endif
8374#ifdef RLIMIT_STACK
8375 "s"
8376#endif
8377#ifdef RLIMIT_CORE
8378 "c"
8379#endif
8380#ifdef RLIMIT_RSS
8381 "m"
8382#endif
8383#ifdef RLIMIT_MEMLOCK
8384 "l"
8385#endif
8386#ifdef RLIMIT_NPROC
8387 "p"
8388#endif
8389#ifdef RLIMIT_NOFILE
8390 "n"
8391#endif
8392#ifdef RLIMIT_VMEM
8393 "v"
8394#endif
8395#ifdef RLIMIT_SWAP
8396 "w"
8397#endif
8398 )) != '\0') {
8399 if (optc == 'H') {
Eric Andersencb57d552001-06-28 07:25:16 +00008400 how = HARD;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008401 } else if (optc == 'S') {
Eric Andersencb57d552001-06-28 07:25:16 +00008402 how = SOFT;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008403 } else if (optc == 'a') {
Eric Andersencb57d552001-06-28 07:25:16 +00008404 all = 1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008405 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00008406 what = optc;
8407 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008408 }
Eric Andersencb57d552001-06-28 07:25:16 +00008409
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008410 for (l = limits; l->name; l++) {
8411 if(l->name[0] == what)
8412 break;
8413 if(l->name[1]=='w' && what=='w')
8414 break;
8415 }
Eric Andersencb57d552001-06-28 07:25:16 +00008416
8417 set = *argptr ? 1 : 0;
8418 if (set) {
8419 char *p = *argptr;
8420
8421 if (all || argptr[1])
8422 error("too many arguments");
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008423 if (strcmp(p, unlimited_string) == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00008424 val = RLIM_INFINITY;
8425 else {
8426 val = (rlim_t) 0;
8427
8428 while ((c = *p++) >= '0' && c <= '9')
8429 {
8430 val = (val * 10) + (long)(c - '0');
8431 if (val < (rlim_t) 0)
8432 break;
8433 }
8434 if (c)
8435 error("bad number");
8436 val *= l->factor;
8437 }
8438 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008439
Eric Andersencb57d552001-06-28 07:25:16 +00008440 if (all) {
8441 for (l = limits; l->name; l++) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008442 printf("%-20s ", l->name);
Eric Andersencb57d552001-06-28 07:25:16 +00008443 getrlimit(l->cmd, &limit);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008444 OUTPUT_LIMIT:
Eric Andersencb57d552001-06-28 07:25:16 +00008445 if (how & SOFT)
8446 val = limit.rlim_cur;
8447 else if (how & HARD)
8448 val = limit.rlim_max;
8449
Eric Andersencb57d552001-06-28 07:25:16 +00008450 if (val == RLIM_INFINITY)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008451 puts(unlimited_string);
Eric Andersencb57d552001-06-28 07:25:16 +00008452 else
8453 {
8454 val /= l->factor;
Eric Andersen62483552001-07-10 06:09:16 +00008455 printf("%lld\n", (long long) val);
Eric Andersencb57d552001-06-28 07:25:16 +00008456 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008457 if (!all) {
8458 break;
8459 }
Eric Andersencb57d552001-06-28 07:25:16 +00008460 }
8461 return 0;
8462 }
8463
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008464 if (!set) {
8465 goto OUTPUT_LIMIT;
Eric Andersencb57d552001-06-28 07:25:16 +00008466 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008467
8468 getrlimit(l->cmd, &limit);
8469 if (how & HARD)
8470 limit.rlim_max = val;
8471 if (how & SOFT)
8472 limit.rlim_cur = val;
8473 if (setrlimit(l->cmd, &limit) < 0)
8474 error("error setting limit (%m)");
Eric Andersencb57d552001-06-28 07:25:16 +00008475 return 0;
8476}
Eric Andersencb57d552001-06-28 07:25:16 +00008477/*
8478 * prefix -- see if pfx is a prefix of string.
8479 */
8480
8481static int
Eric Andersen62483552001-07-10 06:09:16 +00008482prefix(char const *pfx, char const *string)
8483{
Eric Andersencb57d552001-06-28 07:25:16 +00008484 while (*pfx) {
8485 if (*pfx++ != *string++)
8486 return 0;
8487 }
8488 return 1;
8489}
8490
Eric Andersen2870d962001-07-02 17:27:21 +00008491/*
8492 * Return true if s is a string of digits, and save munber in intptr
8493 * nagative is bad
8494 */
8495
8496static int
8497is_number(const char *p, int *intptr)
8498{
8499 int ret = 0;
8500
8501 do {
8502 if (! is_digit(*p))
8503 return 0;
8504 ret *= 10;
8505 ret += digit_val(*p);
8506 p++;
8507 } while (*p != '\0');
8508
8509 *intptr = ret;
8510 return 1;
8511}
Eric Andersencb57d552001-06-28 07:25:16 +00008512
8513/*
8514 * Convert a string of digits to an integer, printing an error message on
8515 * failure.
8516 */
8517
8518static int
Eric Andersen2870d962001-07-02 17:27:21 +00008519number(const char *s)
8520{
8521 int i;
8522 if (! is_number(s, &i))
Eric Andersencb57d552001-06-28 07:25:16 +00008523 error("Illegal number: %s", s);
Eric Andersen2870d962001-07-02 17:27:21 +00008524 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00008525}
8526
Eric Andersencb57d552001-06-28 07:25:16 +00008527/*
8528 * Produce a possibly single quoted string suitable as input to the shell.
8529 * The return string is allocated on the stack.
8530 */
8531
8532static char *
8533single_quote(const char *s) {
8534 char *p;
8535
8536 STARTSTACKSTR(p);
8537
8538 do {
8539 char *q = p;
8540 size_t len1, len1p, len2, len2p;
8541
8542 len1 = strcspn(s, "'");
8543 len2 = strspn(s + len1, "'");
8544
8545 len1p = len1 ? len1 + 2 : len1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008546 len2p = len2 + ((len2 < 2) ? len2 : 2);
Eric Andersencb57d552001-06-28 07:25:16 +00008547
8548 CHECKSTRSPACE(len1p + len2p + 1, p);
8549
8550 if (len1) {
8551 *p = '\'';
Eric Andersencb57d552001-06-28 07:25:16 +00008552 q = p + 1 + len1;
8553 memcpy(p + 1, s, len1);
Eric Andersencb57d552001-06-28 07:25:16 +00008554 *q++ = '\'';
8555 s += len1;
8556 }
8557
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008558 if (len2 > 1) {
Eric Andersencb57d552001-06-28 07:25:16 +00008559 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008560 q += 1 + len2;
8561 memcpy(q + 1, s, len2);
8562 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008563 s += len2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008564 } else if (len2 == 1) {
8565 *q++ = '\\';
8566 *q = '\'';
8567 s++;
Eric Andersencb57d552001-06-28 07:25:16 +00008568 }
8569
8570 STADJUST(len1p + len2p, p);
8571 } while (*s);
8572
8573 USTPUTC(0, p);
8574
8575 return grabstackstr(p);
8576}
8577
8578/*
8579 * Like strdup but works with the ash stack.
8580 */
8581
8582static char *
8583sstrdup(const char *p)
8584{
8585 size_t len = strlen(p) + 1;
8586 return memcpy(stalloc(len), p, len);
8587}
8588
Eric Andersencb57d552001-06-28 07:25:16 +00008589
8590/*
Eric Andersencb57d552001-06-28 07:25:16 +00008591 * Routine for dealing with parsed shell commands.
8592 */
8593
8594
Eric Andersen62483552001-07-10 06:09:16 +00008595static void sizenodelist (const struct nodelist *);
8596static struct nodelist *copynodelist (const struct nodelist *);
8597static char *nodesavestr (const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00008598
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00008599#define CALCSIZE_TABLE
8600#define COPYNODE_TABLE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008601#if defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE)
8602/*
8603 * To collect a lot of redundant code in case statements for copynode()
8604 * and calcsize(), we implement a mini language here. Each type of node
8605 * struct has an associated instruction sequence that operates on its
8606 * members via their offsets. The instruction are pack in unsigned chars
8607 * with format IIDDDDDE where the bits are
8608 * I : part of the instruction opcode, which are
8609 * 00 : member is a pointer to another node
8610 * 40 : member is an integer
8611 * 80 : member is a pointer to a nodelist
8612 * CC : member is a pointer to a char string
8613 * D : data - the actual offset of the member to operate on in the struct
8614 * (since we assume bit 0 is set, it is not shifted)
8615 * E : flag signaling end of instruction sequence
8616 *
8617 * WARNING: In order to handle larger offsets for 64bit archs, this code
8618 * assumes that no offset can be an odd number and stores the
8619 * end-of-instructions flag in bit 0.
8620 */
8621
8622#define NODE_INTEGER 0x40
8623#define NODE_NODELIST 0x80
8624#define NODE_CHARPTR 0xC0
8625#define NODE_NOMORE 0x01 /* Note: no offset should be odd (aligned)*/
8626#define NODE_MBRMASK 0xC0
8627#define NODE_OFFSETMASK 0x3E
8628
8629static const unsigned char copynode_ops[35] = {
8630#define COPYNODE_OPS0 0
8631 offsetof(union node, nbinary.ch2),
8632 offsetof(union node, nbinary.ch1)|NODE_NOMORE,
8633#define COPYNODE_OPS1 (COPYNODE_OPS0 + 2)
8634 offsetof(union node, ncmd.redirect),
8635 offsetof(union node, ncmd.args),
8636 offsetof(union node, ncmd.assign),
8637 offsetof(union node, ncmd.backgnd)|NODE_INTEGER|NODE_NOMORE,
8638#define COPYNODE_OPS2 (COPYNODE_OPS1 + 4)
8639 offsetof(union node, npipe.cmdlist)|NODE_NODELIST,
8640 offsetof(union node, npipe.backgnd)|NODE_INTEGER|NODE_NOMORE,
8641#define COPYNODE_OPS3 (COPYNODE_OPS2 + 2)
8642 offsetof(union node, nredir.redirect),
8643 offsetof(union node, nredir.n)|NODE_NOMORE,
8644#define COPYNODE_OPS4 (COPYNODE_OPS3 + 2)
8645 offsetof(union node, nif.elsepart),
8646 offsetof(union node, nif.ifpart),
8647 offsetof(union node, nif.test)|NODE_NOMORE,
8648#define COPYNODE_OPS5 (COPYNODE_OPS4 + 3)
8649 offsetof(union node, nfor.var)|NODE_CHARPTR,
8650 offsetof(union node, nfor.body),
8651 offsetof(union node, nfor.args)|NODE_NOMORE,
8652#define COPYNODE_OPS6 (COPYNODE_OPS5 + 3)
8653 offsetof(union node, ncase.cases),
8654 offsetof(union node, ncase.expr)|NODE_NOMORE,
8655#define COPYNODE_OPS7 (COPYNODE_OPS6 + 2)
8656 offsetof(union node, nclist.body),
8657 offsetof(union node, nclist.pattern),
8658 offsetof(union node, nclist.next)|NODE_NOMORE,
8659#define COPYNODE_OPS8 (COPYNODE_OPS7 + 3)
8660 offsetof(union node, narg.backquote)|NODE_NODELIST,
8661 offsetof(union node, narg.text)|NODE_CHARPTR,
8662 offsetof(union node, narg.next)|NODE_NOMORE,
8663#define COPYNODE_OPS9 (COPYNODE_OPS8 + 3)
8664 offsetof(union node, nfile.fname),
8665 offsetof(union node, nfile.fd)|NODE_INTEGER,
8666 offsetof(union node, nfile.next)|NODE_NOMORE,
8667#define COPYNODE_OPS10 (COPYNODE_OPS9 + 3)
8668 offsetof(union node, ndup.vname),
8669 offsetof(union node, ndup.dupfd)|NODE_INTEGER,
8670 offsetof(union node, ndup.fd)|NODE_INTEGER,
8671 offsetof(union node, ndup.next)|NODE_NOMORE,
8672#define COPYNODE_OPS11 (COPYNODE_OPS10 + 4)
8673 offsetof(union node, nhere.doc),
8674 offsetof(union node, nhere.fd)|NODE_INTEGER,
8675 offsetof(union node, nhere.next)|NODE_NOMORE,
8676#define COPYNODE_OPS12 (COPYNODE_OPS11 + 3)
8677 offsetof(union node, nnot.com)|NODE_NOMORE,
8678};
8679
8680#if COPYNODE_OPS12 != 34
8681#error COPYNODE_OPS12 is incorrect
8682#endif
8683
8684static const unsigned char copynode_ops_index[26] = {
8685 COPYNODE_OPS0, /* NSEMI */
8686 COPYNODE_OPS1, /* NCMD */
8687 COPYNODE_OPS2, /* NPIPE */
8688 COPYNODE_OPS3, /* NREDIR */
8689 COPYNODE_OPS3, /* NBACKGND */
8690 COPYNODE_OPS3, /* NSUBSHELL */
8691 COPYNODE_OPS0, /* NAND */
8692 COPYNODE_OPS0, /* NOR */
8693 COPYNODE_OPS4, /* NIF */
8694 COPYNODE_OPS0, /* NWHILE */
8695 COPYNODE_OPS0, /* NUNTIL */
8696 COPYNODE_OPS5, /* NFOR */
8697 COPYNODE_OPS6, /* NCASE */
8698 COPYNODE_OPS7, /* NCLIST */
8699 COPYNODE_OPS8, /* NDEFUN */
8700 COPYNODE_OPS8, /* NARG */
8701 COPYNODE_OPS9, /* NTO */
8702 COPYNODE_OPS9, /* NFROM */
8703 COPYNODE_OPS9, /* NFROMTO */
8704 COPYNODE_OPS9, /* NAPPEND */
8705 COPYNODE_OPS9, /* NTOOV */
8706 COPYNODE_OPS10, /* NTOFD */
8707 COPYNODE_OPS10, /* NFROMFD */
8708 COPYNODE_OPS11, /* NHERE */
8709 COPYNODE_OPS11, /* NXHERE */
8710 COPYNODE_OPS12, /* NNOT */
8711};
8712
8713#if NODE_CHARPTR != NODE_MBRMASK
8714#error NODE_CHARPTR != NODE_MBRMASK!!!
8715#endif
8716#endif /* defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE) */
8717
8718#ifdef COPYNODE_TABLE
8719static union node *
8720copynode(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008721{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008722 union node *new;
8723 const unsigned char *p;
8724
Manuel Novoa III c639a352001-08-12 17:32:56 +00008725 if (n == NULL) {
8726 return NULL;
8727 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008728 new = funcblock;
8729 new->type = n->type;
8730 funcblock = (char *) funcblock + (int) nodesize[n->type];
8731 p = copynode_ops + (int) copynode_ops_index[n->type];
8732 do {
8733 char *nn = ((char *) new) + ((int)(*p & NODE_OFFSETMASK));
8734 const char *no = ((const char *) n) + ((int)(*p & NODE_OFFSETMASK));
8735
8736 if (!(*p & NODE_MBRMASK)) { /* standard node */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008737 *((union node **)nn) = copynode(*((const union node **) no));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008738 } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008739 *((const char **)nn) = nodesavestr(*((const char **)no));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008740 } else if (*p & NODE_NODELIST) { /* nodelist */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008741 *((struct nodelist **)nn)
8742 = copynodelist(*((const struct nodelist **) no));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008743 } else { /* integer */
8744 *((int *) nn) = *((int *) no);
8745 }
8746 } while (!(*p++ & NODE_NOMORE));
8747 return new;
Eric Andersencb57d552001-06-28 07:25:16 +00008748}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008749#else /* COPYNODE_TABLE */
Eric Andersencb57d552001-06-28 07:25:16 +00008750static union node *
Eric Andersen62483552001-07-10 06:09:16 +00008751copynode(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008752{
Eric Andersen62483552001-07-10 06:09:16 +00008753 union node *new;
Eric Andersencb57d552001-06-28 07:25:16 +00008754
8755 if (n == NULL)
Manuel Novoa III c639a352001-08-12 17:32:56 +00008756 return NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008757 new = funcblock;
8758 funcblock = (char *) funcblock + nodesize[n->type];
8759 switch (n->type) {
8760 case NSEMI:
8761 case NAND:
8762 case NOR:
8763 case NWHILE:
8764 case NUNTIL:
8765 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8766 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8767 break;
8768 case NCMD:
8769 new->ncmd.redirect = copynode(n->ncmd.redirect);
8770 new->ncmd.args = copynode(n->ncmd.args);
8771 new->ncmd.assign = copynode(n->ncmd.assign);
8772 new->ncmd.backgnd = n->ncmd.backgnd;
8773 break;
8774 case NPIPE:
8775 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8776 new->npipe.backgnd = n->npipe.backgnd;
8777 break;
8778 case NREDIR:
8779 case NBACKGND:
8780 case NSUBSHELL:
8781 new->nredir.redirect = copynode(n->nredir.redirect);
8782 new->nredir.n = copynode(n->nredir.n);
8783 break;
8784 case NIF:
8785 new->nif.elsepart = copynode(n->nif.elsepart);
8786 new->nif.ifpart = copynode(n->nif.ifpart);
8787 new->nif.test = copynode(n->nif.test);
8788 break;
8789 case NFOR:
8790 new->nfor.var = nodesavestr(n->nfor.var);
8791 new->nfor.body = copynode(n->nfor.body);
8792 new->nfor.args = copynode(n->nfor.args);
8793 break;
8794 case NCASE:
8795 new->ncase.cases = copynode(n->ncase.cases);
8796 new->ncase.expr = copynode(n->ncase.expr);
8797 break;
8798 case NCLIST:
8799 new->nclist.body = copynode(n->nclist.body);
8800 new->nclist.pattern = copynode(n->nclist.pattern);
8801 new->nclist.next = copynode(n->nclist.next);
8802 break;
8803 case NDEFUN:
8804 case NARG:
8805 new->narg.backquote = copynodelist(n->narg.backquote);
8806 new->narg.text = nodesavestr(n->narg.text);
8807 new->narg.next = copynode(n->narg.next);
8808 break;
8809 case NTO:
8810 case NFROM:
8811 case NFROMTO:
8812 case NAPPEND:
8813 case NTOOV:
8814 new->nfile.fname = copynode(n->nfile.fname);
8815 new->nfile.fd = n->nfile.fd;
8816 new->nfile.next = copynode(n->nfile.next);
8817 break;
8818 case NTOFD:
8819 case NFROMFD:
8820 new->ndup.vname = copynode(n->ndup.vname);
8821 new->ndup.dupfd = n->ndup.dupfd;
8822 new->ndup.fd = n->ndup.fd;
8823 new->ndup.next = copynode(n->ndup.next);
8824 break;
8825 case NHERE:
8826 case NXHERE:
8827 new->nhere.doc = copynode(n->nhere.doc);
8828 new->nhere.fd = n->nhere.fd;
8829 new->nhere.next = copynode(n->nhere.next);
8830 break;
8831 case NNOT:
8832 new->nnot.com = copynode(n->nnot.com);
8833 break;
8834 };
8835 new->type = n->type;
Eric Andersen62483552001-07-10 06:09:16 +00008836 return new;
Eric Andersencb57d552001-06-28 07:25:16 +00008837}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008838#endif /* COPYNODE_TABLE */
8839
8840#ifdef CALCSIZE_TABLE
8841static void
8842calcsize(const union node *n)
8843{
8844 const unsigned char *p;
8845
8846 if (n == NULL)
8847 return;
8848 funcblocksize += (int) nodesize[n->type];
8849
8850 p = copynode_ops + (int) copynode_ops_index[n->type];
8851 do {
8852 const char *no = ((const char *) n) + ((int)(*p & NODE_OFFSETMASK));
8853
8854 if (!(*p & NODE_MBRMASK)) { /* standard node */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008855 calcsize(*((const union node **) no));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008856 } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008857 funcstringsize += strlen(*((const char **)no)) + 1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008858 } else if (*p & NODE_NODELIST) { /* nodelist */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008859 sizenodelist(*((const struct nodelist **) no));
8860 } /* else integer -- ignore */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008861 } while (!(*p++ & NODE_NOMORE));
8862}
8863#else /* CALCSIZE_TABLE */
8864static void
8865calcsize(const union node *n)
8866{
8867 if (n == NULL)
8868 return;
8869 funcblocksize += nodesize[n->type];
8870 switch (n->type) {
8871 case NSEMI:
8872 case NAND:
8873 case NOR:
8874 case NWHILE:
8875 case NUNTIL:
8876 calcsize(n->nbinary.ch2);
8877 calcsize(n->nbinary.ch1);
8878 break;
8879 case NCMD:
8880 calcsize(n->ncmd.redirect);
8881 calcsize(n->ncmd.args);
8882 calcsize(n->ncmd.assign);
8883 break;
8884 case NPIPE:
8885 sizenodelist(n->npipe.cmdlist);
8886 break;
8887 case NREDIR:
8888 case NBACKGND:
8889 case NSUBSHELL:
8890 calcsize(n->nredir.redirect);
8891 calcsize(n->nredir.n);
8892 break;
8893 case NIF:
8894 calcsize(n->nif.elsepart);
8895 calcsize(n->nif.ifpart);
8896 calcsize(n->nif.test);
8897 break;
8898 case NFOR:
8899 funcstringsize += strlen(n->nfor.var) + 1;
8900 calcsize(n->nfor.body);
8901 calcsize(n->nfor.args);
8902 break;
8903 case NCASE:
8904 calcsize(n->ncase.cases);
8905 calcsize(n->ncase.expr);
8906 break;
8907 case NCLIST:
8908 calcsize(n->nclist.body);
8909 calcsize(n->nclist.pattern);
8910 calcsize(n->nclist.next);
8911 break;
8912 case NDEFUN:
8913 case NARG:
8914 sizenodelist(n->narg.backquote);
8915 funcstringsize += strlen(n->narg.text) + 1;
8916 calcsize(n->narg.next);
8917 break;
8918 case NTO:
8919 case NFROM:
8920 case NFROMTO:
8921 case NAPPEND:
8922 case NTOOV:
8923 calcsize(n->nfile.fname);
8924 calcsize(n->nfile.next);
8925 break;
8926 case NTOFD:
8927 case NFROMFD:
8928 calcsize(n->ndup.vname);
8929 calcsize(n->ndup.next);
8930 break;
8931 case NHERE:
8932 case NXHERE:
8933 calcsize(n->nhere.doc);
8934 calcsize(n->nhere.next);
8935 break;
8936 case NNOT:
8937 calcsize(n->nnot.com);
8938 break;
8939 };
8940}
8941#endif /* CALCSIZE_TABLE */
8942
8943static void
8944sizenodelist(const struct nodelist *lp)
8945{
8946 while (lp) {
8947 funcblocksize += ALIGN(sizeof(struct nodelist));
8948 calcsize(lp->n);
8949 lp = lp->next;
8950 }
8951}
Eric Andersencb57d552001-06-28 07:25:16 +00008952
8953
8954static struct nodelist *
Eric Andersen62483552001-07-10 06:09:16 +00008955copynodelist(const struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008956{
8957 struct nodelist *start;
8958 struct nodelist **lpp;
8959
8960 lpp = &start;
8961 while (lp) {
8962 *lpp = funcblock;
8963 funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist));
8964 (*lpp)->n = copynode(lp->n);
8965 lp = lp->next;
8966 lpp = &(*lpp)->next;
8967 }
8968 *lpp = NULL;
8969 return start;
8970}
8971
8972
Eric Andersencb57d552001-06-28 07:25:16 +00008973static char *
Eric Andersen62483552001-07-10 06:09:16 +00008974nodesavestr(const char *s)
Eric Andersencb57d552001-06-28 07:25:16 +00008975{
Eric Andersen62483552001-07-10 06:09:16 +00008976 const char *p = s;
8977 char *q = funcstring;
Eric Andersencb57d552001-06-28 07:25:16 +00008978 char *rtn = funcstring;
8979
8980 while ((*q++ = *p++) != '\0')
8981 continue;
8982 funcstring = q;
8983 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00008984}
8985
Eric Andersencb57d552001-06-28 07:25:16 +00008986#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00008987static int getopts (char *, char *, char **, int *, int *);
Eric Andersencb57d552001-06-28 07:25:16 +00008988#endif
8989
8990
8991/*
8992 * Process the shell command line arguments.
8993 */
8994
8995static void
8996procargs(argc, argv)
8997 int argc;
8998 char **argv;
8999{
9000 int i;
9001
9002 argptr = argv;
9003 if (argc > 0)
9004 argptr++;
9005 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009006 optent_val(i) = 2;
Eric Andersencb57d552001-06-28 07:25:16 +00009007 options(1);
9008 if (*argptr == NULL && minusc == NULL)
9009 sflag = 1;
9010 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
9011 iflag = 1;
9012 if (mflag == 2)
9013 mflag = iflag;
9014 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009015 if (optent_val(i) == 2)
9016 optent_val(i) = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009017 arg0 = argv[0];
9018 if (sflag == 0 && minusc == NULL) {
9019 commandname = argv[0];
9020 arg0 = *argptr++;
9021 setinputfile(arg0, 0);
9022 commandname = arg0;
9023 }
9024 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
9025 if (argptr && minusc && *argptr)
Eric Andersen2870d962001-07-02 17:27:21 +00009026 arg0 = *argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00009027
9028 shellparam.p = argptr;
9029 shellparam.optind = 1;
9030 shellparam.optoff = -1;
9031 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
9032 while (*argptr) {
9033 shellparam.nparam++;
9034 argptr++;
9035 }
9036 optschanged();
9037}
9038
9039
Eric Andersencb57d552001-06-28 07:25:16 +00009040
9041/*
9042 * Process shell options. The global variable argptr contains a pointer
9043 * to the argument list; we advance it past the options.
9044 */
9045
Eric Andersen62483552001-07-10 06:09:16 +00009046static inline void
9047minus_o(const char *name, int val)
9048{
9049 int i;
9050
9051 if (name == NULL) {
9052 out1str("Current option settings\n");
9053 for (i = 0; i < NOPTS; i++)
9054 printf("%-16s%s\n", optent_name(optlist[i]),
9055 optent_val(i) ? "on" : "off");
9056 } else {
9057 for (i = 0; i < NOPTS; i++)
9058 if (equal(name, optent_name(optlist[i]))) {
9059 setoption(optent_letter(optlist[i]), val);
9060 return;
9061 }
9062 error("Illegal option -o %s", name);
9063 }
9064}
9065
9066
Eric Andersencb57d552001-06-28 07:25:16 +00009067static void
Eric Andersen62483552001-07-10 06:09:16 +00009068options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00009069{
9070 char *p;
9071 int val;
9072 int c;
9073
9074 if (cmdline)
9075 minusc = NULL;
9076 while ((p = *argptr) != NULL) {
9077 argptr++;
9078 if ((c = *p++) == '-') {
9079 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00009080 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
9081 if (!cmdline) {
9082 /* "-" means turn off -x and -v */
9083 if (p[0] == '\0')
9084 xflag = vflag = 0;
9085 /* "--" means reset params */
9086 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00009087 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00009088 }
9089 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00009090 }
9091 } else if (c == '+') {
9092 val = 0;
9093 } else {
9094 argptr--;
9095 break;
9096 }
9097 while ((c = *p++) != '\0') {
9098 if (c == 'c' && cmdline) {
9099 char *q;
Eric Andersen2870d962001-07-02 17:27:21 +00009100#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */
Eric Andersencb57d552001-06-28 07:25:16 +00009101 if (*p == '\0')
9102#endif
9103 q = *argptr++;
9104 if (q == NULL || minusc != NULL)
9105 error("Bad -c option");
9106 minusc = q;
9107#ifdef NOHACK
9108 break;
9109#endif
9110 } else if (c == 'o') {
9111 minus_o(*argptr, val);
9112 if (*argptr)
9113 argptr++;
9114 } else {
9115 setoption(c, val);
9116 }
9117 }
9118 }
9119}
9120
Eric Andersencb57d552001-06-28 07:25:16 +00009121
9122static void
Eric Andersen2870d962001-07-02 17:27:21 +00009123setoption(int flag, int val)
9124{
Eric Andersencb57d552001-06-28 07:25:16 +00009125 int i;
9126
9127 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009128 if (optent_letter(optlist[i]) == flag) {
9129 optent_val(i) = val;
Eric Andersencb57d552001-06-28 07:25:16 +00009130 if (val) {
9131 /* #%$ hack for ksh semantics */
9132 if (flag == 'V')
9133 Eflag = 0;
9134 else if (flag == 'E')
9135 Vflag = 0;
9136 }
9137 return;
9138 }
9139 error("Illegal option -%c", flag);
9140 /* NOTREACHED */
9141}
9142
9143
9144
Eric Andersencb57d552001-06-28 07:25:16 +00009145/*
9146 * Set the shell parameters.
9147 */
9148
9149static void
Eric Andersen2870d962001-07-02 17:27:21 +00009150setparam(char **argv)
9151{
Eric Andersencb57d552001-06-28 07:25:16 +00009152 char **newparam;
9153 char **ap;
9154 int nparam;
9155
9156 for (nparam = 0 ; argv[nparam] ; nparam++);
9157 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
9158 while (*argv) {
9159 *ap++ = savestr(*argv++);
9160 }
9161 *ap = NULL;
9162 freeparam(&shellparam);
9163 shellparam.malloc = 1;
9164 shellparam.nparam = nparam;
9165 shellparam.p = newparam;
9166 shellparam.optind = 1;
9167 shellparam.optoff = -1;
9168}
9169
9170
9171/*
9172 * Free the list of positional parameters.
9173 */
9174
9175static void
Eric Andersen2870d962001-07-02 17:27:21 +00009176freeparam(volatile struct shparam *param)
9177{
Eric Andersencb57d552001-06-28 07:25:16 +00009178 char **ap;
9179
9180 if (param->malloc) {
9181 for (ap = param->p ; *ap ; ap++)
9182 ckfree(*ap);
9183 ckfree(param->p);
9184 }
9185}
9186
9187
9188
9189/*
9190 * The shift builtin command.
9191 */
9192
9193static int
9194shiftcmd(argc, argv)
9195 int argc;
9196 char **argv;
9197{
9198 int n;
9199 char **ap1, **ap2;
9200
9201 n = 1;
9202 if (argc > 1)
9203 n = number(argv[1]);
9204 if (n > shellparam.nparam)
9205 error("can't shift that many");
9206 INTOFF;
9207 shellparam.nparam -= n;
9208 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
9209 if (shellparam.malloc)
9210 ckfree(*ap1);
9211 }
9212 ap2 = shellparam.p;
9213 while ((*ap2++ = *ap1++) != NULL);
9214 shellparam.optind = 1;
9215 shellparam.optoff = -1;
9216 INTON;
9217 return 0;
9218}
9219
9220
9221
9222/*
9223 * The set command builtin.
9224 */
9225
9226static int
9227setcmd(argc, argv)
9228 int argc;
9229 char **argv;
9230{
9231 if (argc == 1)
9232 return showvarscmd(argc, argv);
9233 INTOFF;
9234 options(0);
9235 optschanged();
9236 if (*argptr != NULL) {
9237 setparam(argptr);
9238 }
9239 INTON;
9240 return 0;
9241}
9242
9243
9244static void
Eric Andersen2870d962001-07-02 17:27:21 +00009245getoptsreset(const char *value)
Eric Andersencb57d552001-06-28 07:25:16 +00009246{
9247 shellparam.optind = number(value);
9248 shellparam.optoff = -1;
9249}
9250
Eric Andersenbdfd0d72001-10-24 05:00:29 +00009251#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00009252static void change_lc_all(const char *value)
9253{
9254 if(value != 0 && *value != 0)
9255 setlocale(LC_ALL, value);
9256}
9257
9258static void change_lc_ctype(const char *value)
9259{
9260 if(value != 0 && *value != 0)
9261 setlocale(LC_CTYPE, value);
9262}
9263
9264#endif
9265
Eric Andersencb57d552001-06-28 07:25:16 +00009266#ifdef ASH_GETOPTS
9267/*
9268 * The getopts builtin. Shellparam.optnext points to the next argument
9269 * to be processed. Shellparam.optptr points to the next character to
9270 * be processed in the current argument. If shellparam.optnext is NULL,
9271 * then it's the first time getopts has been called.
9272 */
9273
9274static int
9275getoptscmd(argc, argv)
9276 int argc;
9277 char **argv;
9278{
9279 char **optbase;
9280
9281 if (argc < 3)
9282 error("Usage: getopts optstring var [arg]");
9283 else if (argc == 3) {
9284 optbase = shellparam.p;
9285 if (shellparam.optind > shellparam.nparam + 1) {
9286 shellparam.optind = 1;
9287 shellparam.optoff = -1;
9288 }
9289 }
9290 else {
9291 optbase = &argv[3];
9292 if (shellparam.optind > argc - 2) {
9293 shellparam.optind = 1;
9294 shellparam.optoff = -1;
9295 }
9296 }
9297
9298 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9299 &shellparam.optoff);
9300}
9301
9302/*
9303 * Safe version of setvar, returns 1 on success 0 on failure.
9304 */
9305
9306static int
9307setvarsafe(name, val, flags)
9308 const char *name, *val;
9309 int flags;
9310{
9311 struct jmploc jmploc;
9312 struct jmploc *volatile savehandler = handler;
9313 int err = 0;
9314#ifdef __GNUC__
9315 (void) &err;
9316#endif
9317
9318 if (setjmp(jmploc.loc))
9319 err = 1;
9320 else {
9321 handler = &jmploc;
9322 setvar(name, val, flags);
9323 }
9324 handler = savehandler;
9325 return err;
9326}
9327
9328static int
9329getopts(optstr, optvar, optfirst, myoptind, optoff)
9330 char *optstr;
9331 char *optvar;
9332 char **optfirst;
9333 int *myoptind;
9334 int *optoff;
9335{
9336 char *p, *q;
9337 char c = '?';
9338 int done = 0;
9339 int err = 0;
9340 char s[10];
9341 char **optnext = optfirst + *myoptind - 1;
9342
9343 if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
9344 strlen(*(optnext - 1)) < *optoff)
9345 p = NULL;
9346 else
9347 p = *(optnext - 1) + *optoff;
9348 if (p == NULL || *p == '\0') {
9349 /* Current word is done, advance */
9350 if (optnext == NULL)
9351 return 1;
9352 p = *optnext;
9353 if (p == NULL || *p != '-' || *++p == '\0') {
9354atend:
9355 *myoptind = optnext - optfirst + 1;
9356 p = NULL;
9357 done = 1;
9358 goto out;
9359 }
9360 optnext++;
Eric Andersen2870d962001-07-02 17:27:21 +00009361 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009362 goto atend;
9363 }
9364
9365 c = *p++;
9366 for (q = optstr; *q != c; ) {
9367 if (*q == '\0') {
9368 if (optstr[0] == ':') {
9369 s[0] = c;
9370 s[1] = '\0';
9371 err |= setvarsafe("OPTARG", s, 0);
9372 }
9373 else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009374 out2fmt("Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009375 (void) unsetvar("OPTARG");
9376 }
9377 c = '?';
9378 goto bad;
9379 }
9380 if (*++q == ':')
9381 q++;
9382 }
9383
9384 if (*++q == ':') {
9385 if (*p == '\0' && (p = *optnext) == NULL) {
9386 if (optstr[0] == ':') {
9387 s[0] = c;
9388 s[1] = '\0';
9389 err |= setvarsafe("OPTARG", s, 0);
9390 c = ':';
9391 }
9392 else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009393 out2fmt("No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009394 (void) unsetvar("OPTARG");
9395 c = '?';
9396 }
9397 goto bad;
9398 }
9399
9400 if (p == *optnext)
9401 optnext++;
9402 setvarsafe("OPTARG", p, 0);
9403 p = NULL;
9404 }
9405 else
9406 setvarsafe("OPTARG", "", 0);
9407 *myoptind = optnext - optfirst + 1;
9408 goto out;
9409
9410bad:
9411 *myoptind = 1;
9412 p = NULL;
9413out:
9414 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersen3102ac42001-07-06 04:26:23 +00009415 snprintf(s, sizeof(s), "%d", *myoptind);
Eric Andersencb57d552001-06-28 07:25:16 +00009416 err |= setvarsafe("OPTIND", s, VNOFUNC);
9417 s[0] = c;
9418 s[1] = '\0';
9419 err |= setvarsafe(optvar, s, 0);
9420 if (err) {
9421 *myoptind = 1;
9422 *optoff = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00009423 exraise(EXERROR);
9424 }
9425 return done;
9426}
Eric Andersen2870d962001-07-02 17:27:21 +00009427#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009428
9429/*
9430 * XXX - should get rid of. have all builtins use getopt(3). the
9431 * library getopt must have the BSD extension static variable "optreset"
9432 * otherwise it can't be used within the shell safely.
9433 *
9434 * Standard option processing (a la getopt) for builtin routines. The
9435 * only argument that is passed to nextopt is the option string; the
9436 * other arguments are unnecessary. It return the character, or '\0' on
9437 * end of input.
9438 */
9439
9440static int
Eric Andersen62483552001-07-10 06:09:16 +00009441nextopt(const char *optstring)
9442{
Eric Andersencb57d552001-06-28 07:25:16 +00009443 char *p;
9444 const char *q;
9445 char c;
9446
9447 if ((p = optptr) == NULL || *p == '\0') {
9448 p = *argptr;
9449 if (p == NULL || *p != '-' || *++p == '\0')
9450 return '\0';
9451 argptr++;
Eric Andersen2870d962001-07-02 17:27:21 +00009452 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009453 return '\0';
9454 }
9455 c = *p++;
9456 for (q = optstring ; *q != c ; ) {
9457 if (*q == '\0')
9458 error("Illegal option -%c", c);
9459 if (*++q == ':')
9460 q++;
9461 }
9462 if (*++q == ':') {
9463 if (*p == '\0' && (p = *argptr++) == NULL)
9464 error("No arg for -%c option", c);
9465 optionarg = p;
9466 p = NULL;
9467 }
9468 optptr = p;
9469 return c;
9470}
9471
Eric Andersencb57d552001-06-28 07:25:16 +00009472static void
9473flushall() {
Eric Andersencb57d552001-06-28 07:25:16 +00009474 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009475 fflush(stdout);
Eric Andersencb57d552001-06-28 07:25:16 +00009476 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009477}
9478
9479
9480static void
Eric Andersen3102ac42001-07-06 04:26:23 +00009481out2fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009482{
9483 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00009484 va_start(ap, fmt);
Eric Andersen3102ac42001-07-06 04:26:23 +00009485 vfprintf(stderr, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009486 va_end(ap);
9487}
9488
Eric Andersencb57d552001-06-28 07:25:16 +00009489/*
9490 * Version of write which resumes after a signal is caught.
9491 */
9492
9493static int
Eric Andersen2870d962001-07-02 17:27:21 +00009494xwrite(int fd, const char *buf, int nbytes)
9495{
Eric Andersencb57d552001-06-28 07:25:16 +00009496 int ntry;
9497 int i;
9498 int n;
9499
9500 n = nbytes;
9501 ntry = 0;
9502 for (;;) {
9503 i = write(fd, buf, n);
9504 if (i > 0) {
9505 if ((n -= i) <= 0)
9506 return nbytes;
9507 buf += i;
9508 ntry = 0;
9509 } else if (i == 0) {
9510 if (++ntry > 10)
9511 return nbytes - n;
9512 } else if (errno != EINTR) {
9513 return -1;
9514 }
9515 }
9516}
9517
9518
Eric Andersencb57d552001-06-28 07:25:16 +00009519/*
9520 * Shell command parser.
9521 */
9522
9523#define EOFMARKLEN 79
9524
9525
9526
9527struct heredoc {
Eric Andersen2870d962001-07-02 17:27:21 +00009528 struct heredoc *next; /* next here document in list */
9529 union node *here; /* redirection node */
9530 char *eofmark; /* string indicating end of input */
9531 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009532};
9533
Eric Andersen2870d962001-07-02 17:27:21 +00009534static struct heredoc *heredoclist; /* list of here documents to read */
9535static int parsebackquote; /* nonzero if we are inside backquotes */
9536static int doprompt; /* if set, prompt the user */
9537static int needprompt; /* true if interactive and at start of line */
9538static int lasttoken; /* last token read */
Eric Andersencb57d552001-06-28 07:25:16 +00009539
Eric Andersen2870d962001-07-02 17:27:21 +00009540static char *wordtext; /* text of last word returned by readtoken */
Eric Andersencb57d552001-06-28 07:25:16 +00009541
Eric Andersen2870d962001-07-02 17:27:21 +00009542static struct nodelist *backquotelist;
9543static union node *redirnode;
Eric Andersen044228d2001-07-17 01:12:36 +00009544static struct heredoc *heredoc;
Eric Andersen2870d962001-07-02 17:27:21 +00009545static int quoteflag; /* set if (part of) last token was quoted */
9546static int startlinno; /* line # where last token started */
Eric Andersencb57d552001-06-28 07:25:16 +00009547
9548
Eric Andersen2870d962001-07-02 17:27:21 +00009549static union node *list (int);
9550static union node *andor (void);
9551static union node *pipeline (void);
9552static union node *command (void);
Eric Andersena3483db2001-10-24 08:01:06 +00009553static union node *simplecmd(union node **rpp, union node *redir);
Eric Andersen2870d962001-07-02 17:27:21 +00009554static void parsefname (void);
9555static void parseheredoc (void);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009556static char peektoken (void);
Eric Andersen2870d962001-07-02 17:27:21 +00009557static int readtoken (void);
9558static int xxreadtoken (void);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009559static int readtoken1 (int, int, const char *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00009560static int noexpand (char *);
9561static void synexpect (int) __attribute__((noreturn));
9562static void synerror (const char *) __attribute__((noreturn));
9563static void setprompt (int);
Eric Andersencb57d552001-06-28 07:25:16 +00009564
9565
9566/*
9567 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9568 * valid parse tree indicating a blank line.)
9569 */
9570
Eric Andersen2870d962001-07-02 17:27:21 +00009571static union node *
Eric Andersencb57d552001-06-28 07:25:16 +00009572parsecmd(int interact)
9573{
9574 int t;
9575
9576 tokpushback = 0;
9577 doprompt = interact;
9578 if (doprompt)
9579 setprompt(1);
9580 else
9581 setprompt(0);
9582 needprompt = 0;
9583 t = readtoken();
9584 if (t == TEOF)
9585 return NEOF;
9586 if (t == TNL)
9587 return NULL;
9588 tokpushback++;
9589 return list(1);
9590}
9591
9592
9593static union node *
9594list(nlflag)
9595 int nlflag;
9596{
9597 union node *n1, *n2, *n3;
9598 int tok;
9599
9600 checkkwd = 2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009601 if (nlflag == 0 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009602 return NULL;
9603 n1 = NULL;
9604 for (;;) {
9605 n2 = andor();
9606 tok = readtoken();
9607 if (tok == TBACKGND) {
9608 if (n2->type == NCMD || n2->type == NPIPE) {
9609 n2->ncmd.backgnd = 1;
9610 } else if (n2->type == NREDIR) {
9611 n2->type = NBACKGND;
9612 } else {
9613 n3 = (union node *)stalloc(sizeof (struct nredir));
9614 n3->type = NBACKGND;
9615 n3->nredir.n = n2;
9616 n3->nredir.redirect = NULL;
9617 n2 = n3;
9618 }
9619 }
9620 if (n1 == NULL) {
9621 n1 = n2;
9622 }
9623 else {
9624 n3 = (union node *)stalloc(sizeof (struct nbinary));
9625 n3->type = NSEMI;
9626 n3->nbinary.ch1 = n1;
9627 n3->nbinary.ch2 = n2;
9628 n1 = n3;
9629 }
9630 switch (tok) {
9631 case TBACKGND:
9632 case TSEMI:
9633 tok = readtoken();
9634 /* fall through */
9635 case TNL:
9636 if (tok == TNL) {
9637 parseheredoc();
9638 if (nlflag)
9639 return n1;
9640 } else {
9641 tokpushback++;
9642 }
9643 checkkwd = 2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009644 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009645 return n1;
9646 break;
9647 case TEOF:
9648 if (heredoclist)
9649 parseheredoc();
9650 else
Eric Andersen2870d962001-07-02 17:27:21 +00009651 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009652 return n1;
9653 default:
9654 if (nlflag)
9655 synexpect(-1);
9656 tokpushback++;
9657 return n1;
9658 }
9659 }
9660}
9661
9662
9663
9664static union node *
9665andor() {
9666 union node *n1, *n2, *n3;
9667 int t;
9668
9669 checkkwd = 1;
9670 n1 = pipeline();
9671 for (;;) {
9672 if ((t = readtoken()) == TAND) {
9673 t = NAND;
9674 } else if (t == TOR) {
9675 t = NOR;
9676 } else {
9677 tokpushback++;
9678 return n1;
9679 }
9680 checkkwd = 2;
9681 n2 = pipeline();
9682 n3 = (union node *)stalloc(sizeof (struct nbinary));
9683 n3->type = t;
9684 n3->nbinary.ch1 = n1;
9685 n3->nbinary.ch2 = n2;
9686 n1 = n3;
9687 }
9688}
9689
9690
9691
9692static union node *
9693pipeline() {
9694 union node *n1, *n2, *pipenode;
9695 struct nodelist *lp, *prev;
9696 int negate;
9697
9698 negate = 0;
9699 TRACE(("pipeline: entered\n"));
9700 if (readtoken() == TNOT) {
9701 negate = !negate;
9702 checkkwd = 1;
9703 } else
9704 tokpushback++;
9705 n1 = command();
9706 if (readtoken() == TPIPE) {
9707 pipenode = (union node *)stalloc(sizeof (struct npipe));
9708 pipenode->type = NPIPE;
9709 pipenode->npipe.backgnd = 0;
9710 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9711 pipenode->npipe.cmdlist = lp;
9712 lp->n = n1;
9713 do {
9714 prev = lp;
9715 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9716 checkkwd = 2;
9717 lp->n = command();
9718 prev->next = lp;
9719 } while (readtoken() == TPIPE);
9720 lp->next = NULL;
9721 n1 = pipenode;
9722 }
9723 tokpushback++;
9724 if (negate) {
9725 n2 = (union node *)stalloc(sizeof (struct nnot));
9726 n2->type = NNOT;
9727 n2->nnot.com = n1;
9728 return n2;
9729 } else
9730 return n1;
9731}
9732
9733
9734
9735static union node *
Eric Andersena3483db2001-10-24 08:01:06 +00009736command(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009737 union node *n1, *n2;
9738 union node *ap, **app;
9739 union node *cp, **cpp;
9740 union node *redir, **rpp;
9741 int t;
9742
9743 redir = NULL;
9744 n1 = NULL;
9745 rpp = &redir;
9746
Eric Andersen88cec252001-09-06 17:35:20 +00009747 /* Check for redirection which may precede command */
9748 while (readtoken() == TREDIR) {
9749 *rpp = n2 = redirnode;
9750 rpp = &n2->nfile.next;
9751 parsefname();
9752 }
9753 tokpushback++;
9754
Eric Andersencb57d552001-06-28 07:25:16 +00009755 switch (readtoken()) {
9756 case TIF:
9757 n1 = (union node *)stalloc(sizeof (struct nif));
9758 n1->type = NIF;
9759 n1->nif.test = list(0);
9760 if (readtoken() != TTHEN)
9761 synexpect(TTHEN);
9762 n1->nif.ifpart = list(0);
9763 n2 = n1;
9764 while (readtoken() == TELIF) {
9765 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9766 n2 = n2->nif.elsepart;
9767 n2->type = NIF;
9768 n2->nif.test = list(0);
9769 if (readtoken() != TTHEN)
9770 synexpect(TTHEN);
9771 n2->nif.ifpart = list(0);
9772 }
9773 if (lasttoken == TELSE)
9774 n2->nif.elsepart = list(0);
9775 else {
9776 n2->nif.elsepart = NULL;
9777 tokpushback++;
9778 }
9779 if (readtoken() != TFI)
9780 synexpect(TFI);
9781 checkkwd = 1;
9782 break;
9783 case TWHILE:
9784 case TUNTIL: {
9785 int got;
9786 n1 = (union node *)stalloc(sizeof (struct nbinary));
9787 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9788 n1->nbinary.ch1 = list(0);
9789 if ((got=readtoken()) != TDO) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009790TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009791 synexpect(TDO);
9792 }
9793 n1->nbinary.ch2 = list(0);
9794 if (readtoken() != TDONE)
9795 synexpect(TDONE);
9796 checkkwd = 1;
9797 break;
9798 }
9799 case TFOR:
9800 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9801 synerror("Bad for loop variable");
9802 n1 = (union node *)stalloc(sizeof (struct nfor));
9803 n1->type = NFOR;
9804 n1->nfor.var = wordtext;
9805 checkkwd = 1;
9806 if (readtoken() == TIN) {
9807 app = &ap;
9808 while (readtoken() == TWORD) {
9809 n2 = (union node *)stalloc(sizeof (struct narg));
9810 n2->type = NARG;
9811 n2->narg.text = wordtext;
9812 n2->narg.backquote = backquotelist;
9813 *app = n2;
9814 app = &n2->narg.next;
9815 }
9816 *app = NULL;
9817 n1->nfor.args = ap;
9818 if (lasttoken != TNL && lasttoken != TSEMI)
9819 synexpect(-1);
9820 } else {
9821 static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
9822 '@', '=', '\0'};
9823 n2 = (union node *)stalloc(sizeof (struct narg));
9824 n2->type = NARG;
9825 n2->narg.text = argvars;
9826 n2->narg.backquote = NULL;
9827 n2->narg.next = NULL;
9828 n1->nfor.args = n2;
9829 /*
9830 * Newline or semicolon here is optional (but note
9831 * that the original Bourne shell only allowed NL).
9832 */
9833 if (lasttoken != TNL && lasttoken != TSEMI)
9834 tokpushback++;
9835 }
9836 checkkwd = 2;
9837 if (readtoken() != TDO)
9838 synexpect(TDO);
9839 n1->nfor.body = list(0);
9840 if (readtoken() != TDONE)
9841 synexpect(TDONE);
9842 checkkwd = 1;
9843 break;
9844 case TCASE:
9845 n1 = (union node *)stalloc(sizeof (struct ncase));
9846 n1->type = NCASE;
9847 if (readtoken() != TWORD)
9848 synexpect(TWORD);
9849 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9850 n2->type = NARG;
9851 n2->narg.text = wordtext;
9852 n2->narg.backquote = backquotelist;
9853 n2->narg.next = NULL;
9854 do {
9855 checkkwd = 1;
9856 } while (readtoken() == TNL);
9857 if (lasttoken != TIN)
9858 synerror("expecting \"in\"");
9859 cpp = &n1->ncase.cases;
9860 checkkwd = 2, readtoken();
9861 do {
9862 if (lasttoken == TLP)
9863 readtoken();
9864 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9865 cp->type = NCLIST;
9866 app = &cp->nclist.pattern;
9867 for (;;) {
9868 *app = ap = (union node *)stalloc(sizeof (struct narg));
9869 ap->type = NARG;
9870 ap->narg.text = wordtext;
9871 ap->narg.backquote = backquotelist;
9872 if (checkkwd = 2, readtoken() != TPIPE)
9873 break;
9874 app = &ap->narg.next;
9875 readtoken();
9876 }
9877 ap->narg.next = NULL;
9878 if (lasttoken != TRP)
9879 synexpect(TRP);
9880 cp->nclist.body = list(0);
9881
9882 checkkwd = 2;
9883 if ((t = readtoken()) != TESAC) {
9884 if (t != TENDCASE)
9885 synexpect(TENDCASE);
9886 else
9887 checkkwd = 2, readtoken();
9888 }
9889 cpp = &cp->nclist.next;
9890 } while(lasttoken != TESAC);
9891 *cpp = NULL;
9892 checkkwd = 1;
9893 break;
9894 case TLP:
9895 n1 = (union node *)stalloc(sizeof (struct nredir));
9896 n1->type = NSUBSHELL;
9897 n1->nredir.n = list(0);
9898 n1->nredir.redirect = NULL;
9899 if (readtoken() != TRP)
9900 synexpect(TRP);
9901 checkkwd = 1;
9902 break;
9903 case TBEGIN:
9904 n1 = list(0);
9905 if (readtoken() != TEND)
9906 synexpect(TEND);
9907 checkkwd = 1;
9908 break;
9909 /* Handle an empty command like other simple commands. */
9910 case TSEMI:
9911 case TAND:
9912 case TOR:
9913 case TNL:
9914 case TEOF:
9915 case TRP:
9916 case TBACKGND:
9917 /*
9918 * An empty command before a ; doesn't make much sense, and
9919 * should certainly be disallowed in the case of `if ;'.
9920 */
9921 if (!redir)
9922 synexpect(-1);
9923 case TWORD:
Eric Andersencb57d552001-06-28 07:25:16 +00009924 tokpushback++;
Eric Andersena3483db2001-10-24 08:01:06 +00009925 n1 = simplecmd(rpp, redir);
Eric Andersencb57d552001-06-28 07:25:16 +00009926 return n1;
9927 default:
9928 synexpect(-1);
9929 /* NOTREACHED */
9930 }
9931
9932 /* Now check for redirection which may follow command */
9933 while (readtoken() == TREDIR) {
9934 *rpp = n2 = redirnode;
9935 rpp = &n2->nfile.next;
9936 parsefname();
9937 }
9938 tokpushback++;
9939 *rpp = NULL;
9940 if (redir) {
9941 if (n1->type != NSUBSHELL) {
9942 n2 = (union node *)stalloc(sizeof (struct nredir));
9943 n2->type = NREDIR;
9944 n2->nredir.n = n1;
9945 n1 = n2;
9946 }
9947 n1->nredir.redirect = redir;
9948 }
9949
9950 return n1;
9951}
9952
9953
9954static union node *
Eric Andersena3483db2001-10-24 08:01:06 +00009955simplecmd(union node **rpp, union node *redir) {
Eric Andersencb57d552001-06-28 07:25:16 +00009956 union node *args, **app;
9957 union node *n = NULL;
9958 union node *vars, **vpp;
Eric Andersena3483db2001-10-24 08:01:06 +00009959 union node **orig_rpp;
Eric Andersencb57d552001-06-28 07:25:16 +00009960
9961 args = NULL;
9962 app = &args;
9963 vars = NULL;
9964 vpp = &vars;
Eric Andersena3483db2001-10-24 08:01:06 +00009965
9966 /* If we don't have any redirections already, then we must reset
9967 rpp to be the address of the local redir variable. */
9968 if (redir == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00009969 rpp = &redir;
Eric Andersena3483db2001-10-24 08:01:06 +00009970 /* We save the incoming value, because we need this for shell
9971 functions. There can not be a redirect or an argument between
9972 the function name and the open parenthesis. */
9973 orig_rpp = rpp;
Eric Andersencb57d552001-06-28 07:25:16 +00009974
9975 checkalias = 2;
9976 for (;;) {
9977 switch (readtoken()) {
9978 case TWORD:
9979 case TASSIGN:
9980 n = (union node *)stalloc(sizeof (struct narg));
9981 n->type = NARG;
9982 n->narg.text = wordtext;
9983 n->narg.backquote = backquotelist;
9984 if (lasttoken == TWORD) {
9985 *app = n;
9986 app = &n->narg.next;
9987 } else {
9988 *vpp = n;
9989 vpp = &n->narg.next;
9990 }
9991 break;
9992 case TREDIR:
9993 *rpp = n = redirnode;
9994 rpp = &n->nfile.next;
Eric Andersen2870d962001-07-02 17:27:21 +00009995 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +00009996 break;
9997 case TLP:
9998 if (
9999 args && app == &args->narg.next &&
Eric Andersena3483db2001-10-24 08:01:06 +000010000 !vars && rpp == orig_rpp
Eric Andersencb57d552001-06-28 07:25:16 +000010001 ) {
10002 /* We have a function */
10003 if (readtoken() != TRP)
10004 synexpect(TRP);
Eric Andersencb57d552001-06-28 07:25:16 +000010005 n->type = NDEFUN;
10006 checkkwd = 2;
10007 n->narg.next = command();
10008 return n;
10009 }
10010 /* fall through */
10011 default:
10012 tokpushback++;
10013 goto out;
10014 }
10015 }
10016out:
10017 *app = NULL;
10018 *vpp = NULL;
10019 *rpp = NULL;
10020 n = (union node *)stalloc(sizeof (struct ncmd));
10021 n->type = NCMD;
10022 n->ncmd.backgnd = 0;
10023 n->ncmd.args = args;
10024 n->ncmd.assign = vars;
10025 n->ncmd.redirect = redir;
10026 return n;
10027}
10028
10029static union node *
Eric Andersen2870d962001-07-02 17:27:21 +000010030makename(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000010031 union node *n;
10032
10033 n = (union node *)stalloc(sizeof (struct narg));
10034 n->type = NARG;
10035 n->narg.next = NULL;
10036 n->narg.text = wordtext;
10037 n->narg.backquote = backquotelist;
10038 return n;
10039}
10040
10041static void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +000010042{
Eric Andersencb57d552001-06-28 07:25:16 +000010043 TRACE(("Fix redir %s %d\n", text, err));
10044 if (!err)
10045 n->ndup.vname = NULL;
10046
10047 if (is_digit(text[0]) && text[1] == '\0')
10048 n->ndup.dupfd = digit_val(text[0]);
10049 else if (text[0] == '-' && text[1] == '\0')
10050 n->ndup.dupfd = -1;
10051 else {
10052
10053 if (err)
10054 synerror("Bad fd number");
10055 else
10056 n->ndup.vname = makename();
10057 }
10058}
10059
10060
10061static void
Eric Andersen2870d962001-07-02 17:27:21 +000010062parsefname(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000010063 union node *n = redirnode;
10064
10065 if (readtoken() != TWORD)
10066 synexpect(-1);
10067 if (n->type == NHERE) {
10068 struct heredoc *here = heredoc;
10069 struct heredoc *p;
10070 int i;
10071
10072 if (quoteflag == 0)
10073 n->type = NXHERE;
10074 TRACE(("Here document %d\n", n->type));
10075 if (here->striptabs) {
10076 while (*wordtext == '\t')
10077 wordtext++;
10078 }
10079 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
10080 synerror("Illegal eof marker for << redirection");
10081 rmescapes(wordtext);
10082 here->eofmark = wordtext;
10083 here->next = NULL;
10084 if (heredoclist == NULL)
10085 heredoclist = here;
10086 else {
10087 for (p = heredoclist ; p->next ; p = p->next);
10088 p->next = here;
10089 }
10090 } else if (n->type == NTOFD || n->type == NFROMFD) {
10091 fixredir(n, wordtext, 0);
10092 } else {
10093 n->nfile.fname = makename();
10094 }
10095}
10096
10097
10098/*
10099 * Input any here documents.
10100 */
10101
10102static void
10103parseheredoc() {
10104 struct heredoc *here;
10105 union node *n;
10106
10107 while (heredoclist) {
10108 here = heredoclist;
10109 heredoclist = here->next;
10110 if (needprompt) {
10111 setprompt(2);
10112 needprompt = 0;
10113 }
10114 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
10115 here->eofmark, here->striptabs);
10116 n = (union node *)stalloc(sizeof (struct narg));
10117 n->narg.type = NARG;
10118 n->narg.next = NULL;
10119 n->narg.text = wordtext;
10120 n->narg.backquote = backquotelist;
10121 here->here->nhere.doc = n;
10122 }
10123}
10124
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010125static char
Eric Andersencb57d552001-06-28 07:25:16 +000010126peektoken() {
10127 int t;
10128
10129 t = readtoken();
10130 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010131 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +000010132}
10133
10134static int
10135readtoken() {
10136 int t;
Eric Andersen7467c8d2001-07-12 20:26:32 +000010137
Eric Andersen2870d962001-07-02 17:27:21 +000010138#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010139 int savecheckalias = checkalias;
Eric Andersen7467c8d2001-07-12 20:26:32 +000010140 int savecheckkwd = checkkwd;
Eric Andersencb57d552001-06-28 07:25:16 +000010141 struct alias *ap;
Eric Andersen2870d962001-07-02 17:27:21 +000010142#endif
10143
Eric Andersencb57d552001-06-28 07:25:16 +000010144#ifdef DEBUG
10145 int alreadyseen = tokpushback;
10146#endif
10147
Eric Andersen2870d962001-07-02 17:27:21 +000010148#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010149top:
Eric Andersen2870d962001-07-02 17:27:21 +000010150#endif
10151
Eric Andersencb57d552001-06-28 07:25:16 +000010152 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +000010153
10154#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010155 checkalias = savecheckalias;
Eric Andersen2870d962001-07-02 17:27:21 +000010156#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010157
10158 if (checkkwd) {
10159 /*
10160 * eat newlines
10161 */
10162 if (checkkwd == 2) {
10163 checkkwd = 0;
10164 while (t == TNL) {
10165 parseheredoc();
10166 t = xxreadtoken();
10167 }
10168 }
10169 checkkwd = 0;
10170 /*
10171 * check for keywords
10172 */
10173 if (t == TWORD && !quoteflag)
10174 {
10175 const char *const *pp;
10176
10177 if ((pp = findkwd(wordtext))) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010178 lasttoken = t = pp - tokname_array;
10179 TRACE(("keyword %s recognized\n", tokname(t)));
Eric Andersencb57d552001-06-28 07:25:16 +000010180 goto out;
10181 }
10182 }
10183 }
10184
Eric Andersen7467c8d2001-07-12 20:26:32 +000010185
Eric Andersencb57d552001-06-28 07:25:16 +000010186 if (t != TWORD) {
10187 if (t != TREDIR) {
10188 checkalias = 0;
10189 }
10190 } else if (checkalias == 2 && isassignment(wordtext)) {
10191 lasttoken = t = TASSIGN;
Eric Andersen7467c8d2001-07-12 20:26:32 +000010192#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010193 } else if (checkalias) {
Eric Andersenec074692001-10-31 11:05:49 +000010194 if (!quoteflag && (ap = *__lookupalias(wordtext)) != NULL && !(ap->flag & ALIASINUSE)) {
Eric Andersencb57d552001-06-28 07:25:16 +000010195 if (*ap->val) {
10196 pushstring(ap->val, strlen(ap->val), ap);
10197 }
10198 checkkwd = savecheckkwd;
10199 goto top;
10200 }
10201 checkalias = 0;
Eric Andersen2870d962001-07-02 17:27:21 +000010202#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +000010203 }
Eric Andersencb57d552001-06-28 07:25:16 +000010204out:
10205#ifdef DEBUG
10206 if (!alreadyseen)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010207 TRACE(("token %s %s\n", tokname(t), t == TWORD || t == TASSIGN ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +000010208 else
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010209 TRACE(("reread token %s %s\n", tokname(t), t == TWORD || t == TASSIGN ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +000010210#endif
10211 return (t);
10212}
10213
10214
10215/*
10216 * Read the next input token.
10217 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +000010218 * backquotes. We set quoteflag to true if any part of the word was
10219 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +000010220 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +000010221 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +000010222 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +000010223 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +000010224 *
10225 * [Change comment: here documents and internal procedures]
10226 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10227 * word parsing code into a separate routine. In this case, readtoken
10228 * doesn't need to have any internal procedures, but parseword does.
10229 * We could also make parseoperator in essence the main routine, and
10230 * have parseword (readtoken1?) handle both words and redirection.]
10231 */
10232
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +000010233#define NEW_xxreadtoken
10234#ifdef NEW_xxreadtoken
10235
10236static const char xxreadtoken_chars[] = "\n()&|;"; /* singles must be first! */
10237static const char xxreadtoken_tokens[] = {
10238 TNL, TLP, TRP, /* only single occurrence allowed */
10239 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10240 TEOF, /* corresponds to trailing nul */
10241 TAND, TOR, TENDCASE, /* if double occurrence */
10242};
10243
10244#define xxreadtoken_doubles \
10245 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10246#define xxreadtoken_singles \
10247 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10248
10249static int
10250xxreadtoken() {
10251 int c;
10252
10253 if (tokpushback) {
10254 tokpushback = 0;
10255 return lasttoken;
10256 }
10257 if (needprompt) {
10258 setprompt(2);
10259 needprompt = 0;
10260 }
10261 startlinno = plinno;
10262 for (;;) { /* until token or start of word found */
10263 c = pgetc_macro();
10264
10265 if ((c!=' ') && (c!='\t')
10266#ifdef ASH_ALIAS
10267 && (c!=PEOA)
10268#endif
10269 ) {
10270 if (c=='#') {
10271 while ((c = pgetc()) != '\n' && c != PEOF);
10272 pungetc();
10273 } else if (c=='\\') {
10274 if (pgetc() != '\n') {
10275 pungetc();
10276 goto READTOKEN1;
10277 }
10278 startlinno = ++plinno;
10279 setprompt(doprompt ? 2 : 0);
10280 } else {
10281 const char *p
10282 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10283
10284 if (c!=PEOF) {
10285 if (c=='\n') {
10286 plinno++;
10287 needprompt = doprompt;
10288 }
10289
10290 p = strchr(xxreadtoken_chars, c);
10291 if (p == NULL) {
10292 READTOKEN1:
10293 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10294 }
10295
10296 if (p-xxreadtoken_chars >= xxreadtoken_singles) {
10297 if (pgetc() == *p) { /* double occurrence? */
10298 p += xxreadtoken_doubles + 1;
10299 } else {
10300 pungetc();
10301 }
10302 }
10303 }
10304
10305 return lasttoken = xxreadtoken_tokens[p-xxreadtoken_chars];
10306 }
10307 }
10308 }
10309}
10310
10311
10312#else
Eric Andersen2870d962001-07-02 17:27:21 +000010313#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010314
10315static int
10316xxreadtoken() {
10317 int c;
10318
10319 if (tokpushback) {
10320 tokpushback = 0;
10321 return lasttoken;
10322 }
10323 if (needprompt) {
10324 setprompt(2);
10325 needprompt = 0;
10326 }
10327 startlinno = plinno;
Eric Andersen2870d962001-07-02 17:27:21 +000010328 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010329 c = pgetc_macro();
10330 switch (c) {
10331 case ' ': case '\t':
Eric Andersen3102ac42001-07-06 04:26:23 +000010332#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010333 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010334#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010335 continue;
10336 case '#':
10337 while ((c = pgetc()) != '\n' && c != PEOF);
10338 pungetc();
10339 continue;
10340 case '\\':
10341 if (pgetc() == '\n') {
10342 startlinno = ++plinno;
10343 if (doprompt)
10344 setprompt(2);
10345 else
10346 setprompt(0);
10347 continue;
10348 }
10349 pungetc();
10350 goto breakloop;
10351 case '\n':
10352 plinno++;
10353 needprompt = doprompt;
10354 RETURN(TNL);
10355 case PEOF:
10356 RETURN(TEOF);
10357 case '&':
10358 if (pgetc() == '&')
10359 RETURN(TAND);
10360 pungetc();
10361 RETURN(TBACKGND);
10362 case '|':
10363 if (pgetc() == '|')
10364 RETURN(TOR);
10365 pungetc();
10366 RETURN(TPIPE);
10367 case ';':
10368 if (pgetc() == ';')
10369 RETURN(TENDCASE);
10370 pungetc();
10371 RETURN(TSEMI);
10372 case '(':
10373 RETURN(TLP);
10374 case ')':
10375 RETURN(TRP);
10376 default:
10377 goto breakloop;
10378 }
10379 }
10380breakloop:
10381 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10382#undef RETURN
10383}
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +000010384#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010385
Eric Andersencb57d552001-06-28 07:25:16 +000010386/*
10387 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10388 * is not NULL, read a here document. In the latter case, eofmark is the
10389 * word which marks the end of the document and striptabs is true if
10390 * leading tabs should be stripped from the document. The argument firstc
10391 * is the first character of the input token or document.
10392 *
10393 * Because C does not have internal subroutines, I have simulated them
10394 * using goto's to implement the subroutine linkage. The following macros
10395 * will run code that appears at the end of readtoken1.
10396 */
10397
Eric Andersen2870d962001-07-02 17:27:21 +000010398#define CHECKEND() {goto checkend; checkend_return:;}
10399#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10400#define PARSESUB() {goto parsesub; parsesub_return:;}
10401#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10402#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10403#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010404
10405static int
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010406readtoken1(int firstc, int syntax, const char *eofmark, int striptabs)
10407{
Eric Andersencb57d552001-06-28 07:25:16 +000010408 int c = firstc;
10409 char *out;
10410 int len;
10411 char line[EOFMARKLEN + 1];
10412 struct nodelist *bqlist;
10413 int quotef;
10414 int dblquote;
Eric Andersen2870d962001-07-02 17:27:21 +000010415 int varnest; /* levels of variables expansion */
10416 int arinest; /* levels of arithmetic expansion */
10417 int parenlevel; /* levels of parens in arithmetic */
10418 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +000010419 int oldstyle;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010420 int prevsyntax; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010421#if __GNUC__
10422 /* Avoid longjmp clobbering */
10423 (void) &out;
10424 (void) &quotef;
10425 (void) &dblquote;
10426 (void) &varnest;
10427 (void) &arinest;
10428 (void) &parenlevel;
10429 (void) &dqvarnest;
10430 (void) &oldstyle;
10431 (void) &prevsyntax;
10432 (void) &syntax;
10433#endif
10434
10435 startlinno = plinno;
10436 dblquote = 0;
10437 if (syntax == DQSYNTAX)
10438 dblquote = 1;
10439 quotef = 0;
10440 bqlist = NULL;
10441 varnest = 0;
10442 arinest = 0;
10443 parenlevel = 0;
10444 dqvarnest = 0;
10445
10446 STARTSTACKSTR(out);
Eric Andersen2870d962001-07-02 17:27:21 +000010447 loop: { /* for each line, until end of word */
10448 CHECKEND(); /* set c to PEOF if at end of here document */
10449 for (;;) { /* until end of line or end of word */
10450 CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010451 switch(SIT(c,syntax)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010452 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010453 if (syntax == BASESYNTAX)
Eric Andersen2870d962001-07-02 17:27:21 +000010454 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010455 USTPUTC(c, out);
10456 plinno++;
10457 if (doprompt)
10458 setprompt(2);
10459 else
10460 setprompt(0);
10461 c = pgetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010462 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010463 case CWORD:
10464 USTPUTC(c, out);
10465 break;
10466 case CCTL:
10467 if ((eofmark == NULL || dblquote) &&
10468 dqvarnest == 0)
10469 USTPUTC(CTLESC, out);
10470 USTPUTC(c, out);
10471 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010472 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010473 c = pgetc2();
10474 if (c == PEOF) {
10475 USTPUTC('\\', out);
10476 pungetc();
10477 } else if (c == '\n') {
10478 if (doprompt)
10479 setprompt(2);
10480 else
10481 setprompt(0);
10482 } else {
10483 if (dblquote && c != '\\' && c != '`' && c != '$'
10484 && (c != '"' || eofmark != NULL))
10485 USTPUTC('\\', out);
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010486 if (SIT(c,SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010487 USTPUTC(CTLESC, out);
10488 else if (eofmark == NULL)
10489 USTPUTC(CTLQUOTEMARK, out);
10490 USTPUTC(c, out);
10491 quotef++;
10492 }
10493 break;
10494 case CSQUOTE:
10495 if (eofmark == NULL)
10496 USTPUTC(CTLQUOTEMARK, out);
10497 syntax = SQSYNTAX;
10498 break;
10499 case CDQUOTE:
10500 if (eofmark == NULL)
10501 USTPUTC(CTLQUOTEMARK, out);
10502 syntax = DQSYNTAX;
10503 dblquote = 1;
10504 break;
10505 case CENDQUOTE:
10506 if (eofmark != NULL && arinest == 0 &&
10507 varnest == 0) {
10508 USTPUTC(c, out);
10509 } else {
10510 if (arinest) {
10511 syntax = ARISYNTAX;
10512 dblquote = 0;
10513 } else if (eofmark == NULL &&
10514 dqvarnest == 0) {
10515 syntax = BASESYNTAX;
10516 dblquote = 0;
10517 }
10518 quotef++;
10519 }
10520 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010521 case CVAR: /* '$' */
10522 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010523 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010524 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010525 if (varnest > 0) {
10526 varnest--;
10527 if (dqvarnest > 0) {
10528 dqvarnest--;
10529 }
10530 USTPUTC(CTLENDVAR, out);
10531 } else {
10532 USTPUTC(c, out);
10533 }
10534 break;
10535#ifdef ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +000010536 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010537 parenlevel++;
10538 USTPUTC(c, out);
10539 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010540 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010541 if (parenlevel > 0) {
10542 USTPUTC(c, out);
10543 --parenlevel;
10544 } else {
10545 if (pgetc() == ')') {
10546 if (--arinest == 0) {
10547 USTPUTC(CTLENDARI, out);
10548 syntax = prevsyntax;
10549 if (syntax == DQSYNTAX)
10550 dblquote = 1;
10551 else
10552 dblquote = 0;
10553 } else
10554 USTPUTC(')', out);
10555 } else {
10556 /*
10557 * unbalanced parens
10558 * (don't 2nd guess - no error)
10559 */
10560 pungetc();
10561 USTPUTC(')', out);
10562 }
10563 }
10564 break;
10565#endif
Eric Andersen2870d962001-07-02 17:27:21 +000010566 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010567 PARSEBACKQOLD();
10568 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010569 case CENDFILE:
10570 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010571 case CIGN:
10572 break;
10573 default:
10574 if (varnest == 0)
Eric Andersen2870d962001-07-02 17:27:21 +000010575 goto endword; /* exit outer loop */
Eric Andersen3102ac42001-07-06 04:26:23 +000010576#ifdef ASH_ALIAS
10577 if (c != PEOA)
10578#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010579 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010580
Eric Andersencb57d552001-06-28 07:25:16 +000010581 }
10582 c = pgetc_macro();
10583 }
10584 }
10585endword:
10586 if (syntax == ARISYNTAX)
10587 synerror("Missing '))'");
10588 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10589 synerror("Unterminated quoted string");
10590 if (varnest != 0) {
10591 startlinno = plinno;
10592 synerror("Missing '}'");
10593 }
10594 USTPUTC('\0', out);
10595 len = out - stackblock();
10596 out = stackblock();
10597 if (eofmark == NULL) {
10598 if ((c == '>' || c == '<')
10599 && quotef == 0
10600 && len <= 2
10601 && (*out == '\0' || is_digit(*out))) {
10602 PARSEREDIR();
10603 return lasttoken = TREDIR;
10604 } else {
10605 pungetc();
10606 }
10607 }
10608 quoteflag = quotef;
10609 backquotelist = bqlist;
10610 grabstackblock(len);
10611 wordtext = out;
10612 return lasttoken = TWORD;
10613/* end of readtoken routine */
10614
10615
10616
10617/*
10618 * Check to see whether we are at the end of the here document. When this
10619 * is called, c is set to the first character of the next input line. If
10620 * we are at the end of the here document, this routine sets the c to PEOF.
10621 */
10622
10623checkend: {
10624 if (eofmark) {
Eric Andersen2870d962001-07-02 17:27:21 +000010625#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010626 if (c == PEOA) {
10627 c = pgetc2();
10628 }
Eric Andersen2870d962001-07-02 17:27:21 +000010629#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010630 if (striptabs) {
10631 while (c == '\t') {
10632 c = pgetc2();
10633 }
10634 }
10635 if (c == *eofmark) {
10636 if (pfgets(line, sizeof line) != NULL) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010637 const char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010638
10639 p = line;
10640 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10641 if (*p == '\n' && *q == '\0') {
10642 c = PEOF;
10643 plinno++;
10644 needprompt = doprompt;
10645 } else {
10646 pushstring(line, strlen(line), NULL);
10647 }
10648 }
10649 }
10650 }
10651 goto checkend_return;
10652}
10653
10654
10655/*
10656 * Parse a redirection operator. The variable "out" points to a string
10657 * specifying the fd to be redirected. The variable "c" contains the
10658 * first character of the redirection operator.
10659 */
10660
10661parseredir: {
10662 char fd = *out;
10663 union node *np;
10664
10665 np = (union node *)stalloc(sizeof (struct nfile));
10666 if (c == '>') {
10667 np->nfile.fd = 1;
10668 c = pgetc();
10669 if (c == '>')
10670 np->type = NAPPEND;
10671 else if (c == '&')
10672 np->type = NTOFD;
10673 else if (c == '|')
10674 np->type = NTOOV;
10675 else {
10676 np->type = NTO;
10677 pungetc();
10678 }
Eric Andersen2870d962001-07-02 17:27:21 +000010679 } else { /* c == '<' */
Eric Andersencb57d552001-06-28 07:25:16 +000010680 np->nfile.fd = 0;
10681 switch (c = pgetc()) {
10682 case '<':
10683 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10684 np = (union node *)stalloc(sizeof (struct nhere));
10685 np->nfile.fd = 0;
10686 }
10687 np->type = NHERE;
10688 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10689 heredoc->here = np;
10690 if ((c = pgetc()) == '-') {
10691 heredoc->striptabs = 1;
10692 } else {
10693 heredoc->striptabs = 0;
10694 pungetc();
10695 }
10696 break;
10697
10698 case '&':
10699 np->type = NFROMFD;
10700 break;
10701
10702 case '>':
10703 np->type = NFROMTO;
10704 break;
10705
10706 default:
10707 np->type = NFROM;
10708 pungetc();
10709 break;
10710 }
10711 }
10712 if (fd != '\0')
10713 np->nfile.fd = digit_val(fd);
10714 redirnode = np;
10715 goto parseredir_return;
10716}
10717
10718
10719/*
10720 * Parse a substitution. At this point, we have read the dollar sign
10721 * and nothing else.
10722 */
10723
10724parsesub: {
10725 int subtype;
10726 int typeloc;
10727 int flags;
10728 char *p;
10729 static const char types[] = "}-+?=";
10730
10731 c = pgetc();
10732 if (
10733 c <= PEOA ||
10734 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10735 ) {
10736 USTPUTC('$', out);
10737 pungetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010738 } else if (c == '(') { /* $(command) or $((arith)) */
Eric Andersencb57d552001-06-28 07:25:16 +000010739 if (pgetc() == '(') {
10740 PARSEARITH();
10741 } else {
10742 pungetc();
10743 PARSEBACKQNEW();
10744 }
10745 } else {
10746 USTPUTC(CTLVAR, out);
10747 typeloc = out - stackblock();
10748 USTPUTC(VSNORMAL, out);
10749 subtype = VSNORMAL;
10750 if (c == '{') {
10751 c = pgetc();
10752 if (c == '#') {
10753 if ((c = pgetc()) == '}')
10754 c = '#';
10755 else
10756 subtype = VSLENGTH;
10757 }
10758 else
10759 subtype = 0;
10760 }
10761 if (c > PEOA && is_name(c)) {
10762 do {
10763 STPUTC(c, out);
10764 c = pgetc();
10765 } while (c > PEOA && is_in_name(c));
10766 } else if (is_digit(c)) {
10767 do {
10768 USTPUTC(c, out);
10769 c = pgetc();
10770 } while (is_digit(c));
10771 }
10772 else if (is_special(c)) {
10773 USTPUTC(c, out);
10774 c = pgetc();
10775 }
10776 else
Eric Andersen2870d962001-07-02 17:27:21 +000010777badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010778
10779 STPUTC('=', out);
10780 flags = 0;
10781 if (subtype == 0) {
10782 switch (c) {
10783 case ':':
10784 flags = VSNUL;
10785 c = pgetc();
10786 /*FALLTHROUGH*/
10787 default:
10788 p = strchr(types, c);
10789 if (p == NULL)
10790 goto badsub;
10791 subtype = p - types + VSNORMAL;
10792 break;
10793 case '%':
10794 case '#':
10795 {
10796 int cc = c;
10797 subtype = c == '#' ? VSTRIMLEFT :
10798 VSTRIMRIGHT;
10799 c = pgetc();
10800 if (c == cc)
10801 subtype++;
10802 else
10803 pungetc();
10804 break;
10805 }
10806 }
10807 } else {
10808 pungetc();
10809 }
10810 if (dblquote || arinest)
10811 flags |= VSQUOTE;
10812 *(stackblock() + typeloc) = subtype | flags;
10813 if (subtype != VSNORMAL) {
10814 varnest++;
10815 if (dblquote) {
10816 dqvarnest++;
10817 }
10818 }
10819 }
10820 goto parsesub_return;
10821}
10822
10823
10824/*
10825 * Called to parse command substitutions. Newstyle is set if the command
10826 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10827 * list of commands (passed by reference), and savelen is the number of
10828 * characters on the top of the stack which must be preserved.
10829 */
10830
10831parsebackq: {
10832 struct nodelist **nlpp;
10833 int savepbq;
10834 union node *n;
10835 char *volatile str;
10836 struct jmploc jmploc;
10837 struct jmploc *volatile savehandler;
10838 int savelen;
10839 int saveprompt;
10840#ifdef __GNUC__
10841 (void) &saveprompt;
10842#endif
10843
10844 savepbq = parsebackquote;
10845 if (setjmp(jmploc.loc)) {
10846 if (str)
10847 ckfree(str);
10848 parsebackquote = 0;
10849 handler = savehandler;
10850 longjmp(handler->loc, 1);
10851 }
10852 INTOFF;
10853 str = NULL;
10854 savelen = out - stackblock();
10855 if (savelen > 0) {
10856 str = ckmalloc(savelen);
10857 memcpy(str, stackblock(), savelen);
10858 }
10859 savehandler = handler;
10860 handler = &jmploc;
10861 INTON;
Eric Andersen2870d962001-07-02 17:27:21 +000010862 if (oldstyle) {
10863 /* We must read until the closing backquote, giving special
10864 treatment to some slashes, and then push the string and
10865 reread it as input, interpreting it normally. */
10866 char *pout;
10867 int pc;
10868 int psavelen;
10869 char *pstr;
Eric Andersencb57d552001-06-28 07:25:16 +000010870
10871
Eric Andersen2870d962001-07-02 17:27:21 +000010872 STARTSTACKSTR(pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010873 for (;;) {
10874 if (needprompt) {
10875 setprompt(2);
10876 needprompt = 0;
10877 }
10878 switch (pc = pgetc()) {
10879 case '`':
10880 goto done;
10881
10882 case '\\':
Eric Andersen2870d962001-07-02 17:27:21 +000010883 if ((pc = pgetc()) == '\n') {
Eric Andersencb57d552001-06-28 07:25:16 +000010884 plinno++;
10885 if (doprompt)
10886 setprompt(2);
10887 else
10888 setprompt(0);
10889 /*
10890 * If eating a newline, avoid putting
10891 * the newline into the new character
10892 * stream (via the STPUTC after the
10893 * switch).
10894 */
10895 continue;
10896 }
Eric Andersen2870d962001-07-02 17:27:21 +000010897 if (pc != '\\' && pc != '`' && pc != '$'
10898 && (!dblquote || pc != '"'))
10899 STPUTC('\\', pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010900 if (pc > PEOA) {
10901 break;
10902 }
10903 /* fall through */
10904
10905 case PEOF:
Eric Andersen2870d962001-07-02 17:27:21 +000010906#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010907 case PEOA:
Eric Andersen2870d962001-07-02 17:27:21 +000010908#endif
10909 startlinno = plinno;
Eric Andersencb57d552001-06-28 07:25:16 +000010910 synerror("EOF in backquote substitution");
10911
10912 case '\n':
10913 plinno++;
10914 needprompt = doprompt;
10915 break;
10916
10917 default:
10918 break;
10919 }
10920 STPUTC(pc, pout);
Eric Andersen2870d962001-07-02 17:27:21 +000010921 }
Eric Andersencb57d552001-06-28 07:25:16 +000010922done:
Eric Andersen2870d962001-07-02 17:27:21 +000010923 STPUTC('\0', pout);
10924 psavelen = pout - stackblock();
10925 if (psavelen > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010926 pstr = grabstackstr(pout);
10927 setinputstring(pstr);
Eric Andersen2870d962001-07-02 17:27:21 +000010928 }
10929 }
Eric Andersencb57d552001-06-28 07:25:16 +000010930 nlpp = &bqlist;
10931 while (*nlpp)
10932 nlpp = &(*nlpp)->next;
10933 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10934 (*nlpp)->next = NULL;
10935 parsebackquote = oldstyle;
10936
10937 if (oldstyle) {
10938 saveprompt = doprompt;
10939 doprompt = 0;
10940 }
10941
10942 n = list(0);
10943
10944 if (oldstyle)
10945 doprompt = saveprompt;
10946 else {
10947 if (readtoken() != TRP)
10948 synexpect(TRP);
10949 }
10950
10951 (*nlpp)->n = n;
Eric Andersen2870d962001-07-02 17:27:21 +000010952 if (oldstyle) {
Eric Andersencb57d552001-06-28 07:25:16 +000010953 /*
10954 * Start reading from old file again, ignoring any pushed back
10955 * tokens left from the backquote parsing
10956 */
Eric Andersen2870d962001-07-02 17:27:21 +000010957 popfile();
Eric Andersencb57d552001-06-28 07:25:16 +000010958 tokpushback = 0;
10959 }
10960 while (stackblocksize() <= savelen)
10961 growstackblock();
10962 STARTSTACKSTR(out);
10963 if (str) {
10964 memcpy(out, str, savelen);
10965 STADJUST(savelen, out);
10966 INTOFF;
10967 ckfree(str);
10968 str = NULL;
10969 INTON;
10970 }
10971 parsebackquote = savepbq;
10972 handler = savehandler;
10973 if (arinest || dblquote)
10974 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10975 else
10976 USTPUTC(CTLBACKQ, out);
10977 if (oldstyle)
10978 goto parsebackq_oldreturn;
10979 else
10980 goto parsebackq_newreturn;
10981}
10982
10983/*
10984 * Parse an arithmetic expansion (indicate start of one and set state)
10985 */
10986parsearith: {
10987
10988 if (++arinest == 1) {
10989 prevsyntax = syntax;
10990 syntax = ARISYNTAX;
10991 USTPUTC(CTLARI, out);
10992 if (dblquote)
10993 USTPUTC('"',out);
10994 else
10995 USTPUTC(' ',out);
10996 } else {
10997 /*
10998 * we collapse embedded arithmetic expansion to
10999 * parenthesis, which should be equivalent
11000 */
11001 USTPUTC('(', out);
11002 }
11003 goto parsearith_return;
11004}
11005
11006} /* end of readtoken */
11007
11008
Eric Andersencb57d552001-06-28 07:25:16 +000011009/*
11010 * Returns true if the text contains nothing to expand (no dollar signs
11011 * or backquotes).
11012 */
11013
11014static int
11015noexpand(text)
11016 char *text;
11017 {
11018 char *p;
11019 char c;
11020
11021 p = text;
11022 while ((c = *p++) != '\0') {
11023 if (c == CTLQUOTEMARK)
11024 continue;
11025 if (c == CTLESC)
11026 p++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011027 else if (SIT(c,BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000011028 return 0;
11029 }
11030 return 1;
11031}
11032
11033
11034/*
11035 * Return true if the argument is a legal variable name (a letter or
11036 * underscore followed by zero or more letters, underscores, and digits).
11037 */
11038
11039static int
Eric Andersen2870d962001-07-02 17:27:21 +000011040goodname(const char *name)
11041{
11042 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000011043
11044 p = name;
11045 if (! is_name(*p))
11046 return 0;
11047 while (*++p) {
11048 if (! is_in_name(*p))
11049 return 0;
11050 }
11051 return 1;
11052}
11053
11054
11055/*
11056 * Called when an unexpected token is read during the parse. The argument
11057 * is the token that is expected, or -1 if more than one type of token can
11058 * occur at this point.
11059 */
11060
11061static void
11062synexpect(token)
11063 int token;
11064{
11065 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011066 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000011067
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011068 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
11069 if (token >= 0)
11070 sprintf(msg+l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000011071 synerror(msg);
11072 /* NOTREACHED */
11073}
11074
11075
11076static void
Eric Andersen2870d962001-07-02 17:27:21 +000011077synerror(const char *msg)
11078{
Eric Andersencb57d552001-06-28 07:25:16 +000011079 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +000011080 out2fmt("%s: %d: ", commandname, startlinno);
11081 out2fmt("Syntax error: %s\n", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000011082 error((char *)NULL);
11083 /* NOTREACHED */
11084}
11085
Eric Andersencb57d552001-06-28 07:25:16 +000011086
11087/*
11088 * called by editline -- any expansions to the prompt
11089 * should be added here.
11090 */
Eric Andersen2870d962001-07-02 17:27:21 +000011091static void
Eric Andersen62483552001-07-10 06:09:16 +000011092setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000011093{
Eric Andersen62483552001-07-10 06:09:16 +000011094 char *prompt;
11095 switch (whichprompt) {
11096 case 1:
11097 prompt = ps1val();
11098 break;
11099 case 2:
11100 prompt = ps2val();
11101 break;
11102 default: /* 0 */
11103 prompt = "";
11104 }
11105 putprompt(prompt);
Eric Andersencb57d552001-06-28 07:25:16 +000011106}
11107
Eric Andersencb57d552001-06-28 07:25:16 +000011108
Eric Andersencb57d552001-06-28 07:25:16 +000011109/*
11110 * Code for dealing with input/output redirection.
11111 */
11112
Eric Andersen2870d962001-07-02 17:27:21 +000011113#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000011114#ifndef PIPE_BUF
Eric Andersen2870d962001-07-02 17:27:21 +000011115# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000011116#else
11117# define PIPESIZE PIPE_BUF
11118#endif
11119
11120
Eric Andersen62483552001-07-10 06:09:16 +000011121/*
11122 * Open a file in noclobber mode.
11123 * The code was copied from bash.
11124 */
11125static inline int
11126noclobberopen(const char *fname)
11127{
11128 int r, fd;
11129 struct stat finfo, finfo2;
11130
11131 /*
11132 * If the file exists and is a regular file, return an error
11133 * immediately.
11134 */
11135 r = stat(fname, &finfo);
11136 if (r == 0 && S_ISREG(finfo.st_mode)) {
11137 errno = EEXIST;
11138 return -1;
11139 }
11140
11141 /*
11142 * If the file was not present (r != 0), make sure we open it
11143 * exclusively so that if it is created before we open it, our open
11144 * will fail. Make sure that we do not truncate an existing file.
11145 * Note that we don't turn on O_EXCL unless the stat failed -- if the
11146 * file was not a regular file, we leave O_EXCL off.
11147 */
11148 if (r != 0)
11149 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
11150 fd = open(fname, O_WRONLY|O_CREAT, 0666);
11151
11152 /* If the open failed, return the file descriptor right away. */
11153 if (fd < 0)
11154 return fd;
11155
11156 /*
11157 * OK, the open succeeded, but the file may have been changed from a
11158 * non-regular file to a regular file between the stat and the open.
11159 * We are assuming that the O_EXCL open handles the case where FILENAME
11160 * did not exist and is symlinked to an existing file between the stat
11161 * and open.
11162 */
11163
11164 /*
11165 * If we can open it and fstat the file descriptor, and neither check
11166 * revealed that it was a regular file, and the file has not been
11167 * replaced, return the file descriptor.
11168 */
11169 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
11170 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
11171 return fd;
11172
11173 /* The file has been replaced. badness. */
11174 close(fd);
11175 errno = EEXIST;
11176 return -1;
11177}
Eric Andersencb57d552001-06-28 07:25:16 +000011178
11179/*
Eric Andersen62483552001-07-10 06:09:16 +000011180 * Handle here documents. Normally we fork off a process to write the
11181 * data to a pipe. If the document is short, we can stuff the data in
11182 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000011183 */
11184
Eric Andersen62483552001-07-10 06:09:16 +000011185static inline int
11186openhere(const union node *redir)
11187{
11188 int pip[2];
11189 int len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011190
Eric Andersen62483552001-07-10 06:09:16 +000011191 if (pipe(pip) < 0)
11192 error("Pipe call failed");
11193 if (redir->type == NHERE) {
11194 len = strlen(redir->nhere.doc->narg.text);
11195 if (len <= PIPESIZE) {
11196 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11197 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011198 }
Eric Andersencb57d552001-06-28 07:25:16 +000011199 }
Eric Andersen62483552001-07-10 06:09:16 +000011200 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
11201 close(pip[0]);
11202 signal(SIGINT, SIG_IGN);
11203 signal(SIGQUIT, SIG_IGN);
11204 signal(SIGHUP, SIG_IGN);
11205#ifdef SIGTSTP
11206 signal(SIGTSTP, SIG_IGN);
11207#endif
11208 signal(SIGPIPE, SIG_DFL);
11209 if (redir->type == NHERE)
11210 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11211 else
11212 expandhere(redir->nhere.doc, pip[1]);
11213 _exit(0);
11214 }
11215out:
11216 close(pip[1]);
11217 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000011218}
11219
11220
Eric Andersen62483552001-07-10 06:09:16 +000011221static inline int
11222openredirect(const union node *redir)
11223{
Eric Andersencb57d552001-06-28 07:25:16 +000011224 char *fname;
11225 int f;
11226
11227 switch (redir->nfile.type) {
11228 case NFROM:
11229 fname = redir->nfile.expfname;
11230 if ((f = open(fname, O_RDONLY)) < 0)
11231 goto eopen;
11232 break;
11233 case NFROMTO:
11234 fname = redir->nfile.expfname;
11235 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
11236 goto ecreate;
11237 break;
11238 case NTO:
11239 /* Take care of noclobber mode. */
11240 if (Cflag) {
11241 fname = redir->nfile.expfname;
11242 if ((f = noclobberopen(fname)) < 0)
11243 goto ecreate;
11244 break;
11245 }
11246 case NTOOV:
11247 fname = redir->nfile.expfname;
11248#ifdef O_CREAT
11249 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
11250 goto ecreate;
11251#else
11252 if ((f = creat(fname, 0666)) < 0)
11253 goto ecreate;
11254#endif
11255 break;
11256 case NAPPEND:
11257 fname = redir->nfile.expfname;
11258#ifdef O_APPEND
11259 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
11260 goto ecreate;
11261#else
11262 if ((f = open(fname, O_WRONLY)) < 0
11263 && (f = creat(fname, 0666)) < 0)
11264 goto ecreate;
11265 lseek(f, (off_t)0, 2);
11266#endif
11267 break;
11268 default:
11269#ifdef DEBUG
11270 abort();
11271#endif
11272 /* Fall through to eliminate warning. */
11273 case NTOFD:
11274 case NFROMFD:
11275 f = -1;
11276 break;
11277 case NHERE:
11278 case NXHERE:
11279 f = openhere(redir);
11280 break;
11281 }
11282
11283 return f;
11284ecreate:
11285 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11286eopen:
11287 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11288}
11289
11290
Eric Andersen62483552001-07-10 06:09:16 +000011291/*
11292 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11293 * old file descriptors are stashed away so that the redirection can be
11294 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11295 * standard output, and the standard error if it becomes a duplicate of
11296 * stdout.
11297 */
11298
Eric Andersencb57d552001-06-28 07:25:16 +000011299static void
Eric Andersen62483552001-07-10 06:09:16 +000011300redirect(union node *redir, int flags)
11301{
11302 union node *n;
11303 struct redirtab *sv = NULL;
11304 int i;
11305 int fd;
11306 int newfd;
11307 int try;
11308 int fd1dup = flags & REDIR_BACKQ;; /* stdout `cmd` redir to pipe */
11309
11310 if (flags & REDIR_PUSH) {
11311 sv = ckmalloc(sizeof (struct redirtab));
11312 for (i = 0 ; i < 10 ; i++)
11313 sv->renamed[i] = EMPTY;
11314 sv->next = redirlist;
11315 redirlist = sv;
11316 }
11317 for (n = redir ; n ; n = n->nfile.next) {
11318 fd = n->nfile.fd;
11319 try = 0;
11320 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11321 n->ndup.dupfd == fd)
11322 continue; /* redirect from/to same file descriptor */
11323
11324 INTOFF;
11325 newfd = openredirect(n);
11326 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
11327 if (newfd == fd) {
11328 try++;
11329 } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
11330 switch (errno) {
11331 case EBADF:
11332 if (!try) {
11333 dupredirect(n, newfd, fd1dup);
11334 try++;
11335 break;
11336 }
11337 /* FALLTHROUGH*/
11338 default:
11339 if (newfd >= 0) {
11340 close(newfd);
11341 }
11342 INTON;
11343 error("%d: %m", fd);
11344 /* NOTREACHED */
11345 }
11346 }
11347 if (!try) {
11348 close(fd);
11349 if (flags & REDIR_PUSH) {
11350 sv->renamed[fd] = i;
11351 }
11352 }
11353 } else if (fd != newfd) {
11354 close(fd);
11355 }
11356 if (fd == 0)
11357 fd0_redirected++;
11358 if (!try)
11359 dupredirect(n, newfd, fd1dup);
11360 INTON;
11361 }
11362}
11363
11364
11365static void
11366dupredirect(const union node *redir, int f, int fd1dup)
Eric Andersen2870d962001-07-02 17:27:21 +000011367{
Eric Andersencb57d552001-06-28 07:25:16 +000011368 int fd = redir->nfile.fd;
11369
Eric Andersen62483552001-07-10 06:09:16 +000011370 if(fd==1)
11371 fd1dup = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011372 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Eric Andersen2870d962001-07-02 17:27:21 +000011373 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
Eric Andersen62483552001-07-10 06:09:16 +000011374 if (redir->ndup.dupfd!=1 || fd1dup!=1)
Eric Andersencb57d552001-06-28 07:25:16 +000011375 dup_as_newfd(redir->ndup.dupfd, fd);
11376 }
11377 return;
11378 }
11379
11380 if (f != fd) {
11381 dup_as_newfd(f, fd);
11382 close(f);
11383 }
11384 return;
11385}
11386
11387
Eric Andersencb57d552001-06-28 07:25:16 +000011388
Eric Andersencb57d552001-06-28 07:25:16 +000011389/*
11390 * Undo the effects of the last redirection.
11391 */
11392
11393static void
Eric Andersen2870d962001-07-02 17:27:21 +000011394popredir(void)
11395{
Eric Andersencb57d552001-06-28 07:25:16 +000011396 struct redirtab *rp = redirlist;
11397 int i;
11398
11399 INTOFF;
11400 for (i = 0 ; i < 10 ; i++) {
11401 if (rp->renamed[i] != EMPTY) {
Eric Andersen2870d962001-07-02 17:27:21 +000011402 if (i == 0)
11403 fd0_redirected--;
Eric Andersencb57d552001-06-28 07:25:16 +000011404 close(i);
11405 if (rp->renamed[i] >= 0) {
11406 dup_as_newfd(rp->renamed[i], i);
11407 close(rp->renamed[i]);
11408 }
Eric Andersencb57d552001-06-28 07:25:16 +000011409 }
11410 }
11411 redirlist = rp->next;
11412 ckfree(rp);
11413 INTON;
11414}
11415
11416/*
Eric Andersencb57d552001-06-28 07:25:16 +000011417 * Discard all saved file descriptors.
11418 */
11419
11420static void
Eric Andersen2870d962001-07-02 17:27:21 +000011421clearredir(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000011422 struct redirtab *rp;
11423 int i;
11424
11425 for (rp = redirlist ; rp ; rp = rp->next) {
11426 for (i = 0 ; i < 10 ; i++) {
11427 if (rp->renamed[i] >= 0) {
11428 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011429 }
11430 rp->renamed[i] = EMPTY;
11431 }
11432 }
Eric Andersencb57d552001-06-28 07:25:16 +000011433}
11434
11435
Eric Andersencb57d552001-06-28 07:25:16 +000011436/*
11437 * Copy a file descriptor to be >= to. Returns -1
11438 * if the source file descriptor is closed, EMPTY if there are no unused
11439 * file descriptors left.
11440 */
11441
11442static int
11443dup_as_newfd(from, to)
11444 int from;
11445 int to;
11446{
11447 int newfd;
11448
11449 newfd = fcntl(from, F_DUPFD, to);
11450 if (newfd < 0) {
11451 if (errno == EMFILE)
11452 return EMPTY;
11453 else
Eric Andersen2870d962001-07-02 17:27:21 +000011454 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011455 }
11456 return newfd;
11457}
11458
Eric Andersencb57d552001-06-28 07:25:16 +000011459#ifdef DEBUG
Eric Andersenec074692001-10-31 11:05:49 +000011460/*
11461 * Debugging stuff.
11462 */
Eric Andersen2870d962001-07-02 17:27:21 +000011463static void shtree (union node *, int, char *, FILE*);
11464static void shcmd (union node *, FILE *);
11465static void sharg (union node *, FILE *);
11466static void indent (int, char *, FILE *);
11467static void trstring (char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011468
11469
11470static void
11471showtree(n)
Eric Andersen69a20f02001-10-31 10:40:37 +000011472 unode *n;
Eric Andersencb57d552001-06-28 07:25:16 +000011473{
11474 trputs("showtree called\n");
11475 shtree(n, 1, NULL, stdout);
11476}
11477
11478
11479static void
11480shtree(n, ind, pfx, fp)
11481 union node *n;
11482 int ind;
11483 char *pfx;
11484 FILE *fp;
11485{
11486 struct nodelist *lp;
11487 const char *s;
11488
11489 if (n == NULL)
11490 return;
11491
11492 indent(ind, pfx, fp);
11493 switch(n->type) {
11494 case NSEMI:
11495 s = "; ";
11496 goto binop;
11497 case NAND:
11498 s = " && ";
11499 goto binop;
11500 case NOR:
11501 s = " || ";
11502binop:
11503 shtree(n->nbinary.ch1, ind, NULL, fp);
11504 /* if (ind < 0) */
11505 fputs(s, fp);
11506 shtree(n->nbinary.ch2, ind, NULL, fp);
11507 break;
11508 case NCMD:
11509 shcmd(n, fp);
11510 if (ind >= 0)
11511 putc('\n', fp);
11512 break;
11513 case NPIPE:
11514 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11515 shcmd(lp->n, fp);
11516 if (lp->next)
11517 fputs(" | ", fp);
11518 }
11519 if (n->npipe.backgnd)
11520 fputs(" &", fp);
11521 if (ind >= 0)
11522 putc('\n', fp);
11523 break;
11524 default:
11525 fprintf(fp, "<node type %d>", n->type);
11526 if (ind >= 0)
11527 putc('\n', fp);
11528 break;
11529 }
11530}
11531
11532
11533
11534static void
11535shcmd(cmd, fp)
11536 union node *cmd;
11537 FILE *fp;
11538{
11539 union node *np;
11540 int first;
11541 const char *s;
11542 int dftfd;
11543
11544 first = 1;
11545 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11546 if (! first)
11547 putchar(' ');
11548 sharg(np, fp);
11549 first = 0;
11550 }
11551 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11552 if (! first)
11553 putchar(' ');
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011554#if 1
11555 s = "*error*";
11556 dftfd = 0;
11557 if ((np->nfile.type <= NFROMFD) && (np->nfile.type >= NTO)) {
11558 s = redir_strings[np->nfile.type - NTO];
11559 if (*s == '>') {
11560 dftfd = 1;
11561 }
11562 }
11563#else
Eric Andersencb57d552001-06-28 07:25:16 +000011564 switch (np->nfile.type) {
Eric Andersen2870d962001-07-02 17:27:21 +000011565 case NTO: s = ">"; dftfd = 1; break;
11566 case NAPPEND: s = ">>"; dftfd = 1; break;
11567 case NTOFD: s = ">&"; dftfd = 1; break;
11568 case NTOOV: s = ">|"; dftfd = 1; break;
11569 case NFROM: s = "<"; dftfd = 0; break;
11570 case NFROMFD: s = "<&"; dftfd = 0; break;
11571 case NFROMTO: s = "<>"; dftfd = 0; break;
11572 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011573 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011574#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011575 if (np->nfile.fd != dftfd)
11576 fprintf(fp, "%d", np->nfile.fd);
11577 fputs(s, fp);
11578 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11579 fprintf(fp, "%d", np->ndup.dupfd);
11580 } else {
11581 sharg(np->nfile.fname, fp);
11582 }
11583 first = 0;
11584 }
11585}
11586
Eric Andersencb57d552001-06-28 07:25:16 +000011587static void
11588sharg(arg, fp)
11589 union node *arg;
11590 FILE *fp;
11591 {
11592 char *p;
11593 struct nodelist *bqlist;
11594 int subtype;
11595
11596 if (arg->type != NARG) {
11597 printf("<node type %d>\n", arg->type);
11598 fflush(stdout);
11599 abort();
11600 }
11601 bqlist = arg->narg.backquote;
11602 for (p = arg->narg.text ; *p ; p++) {
11603 switch (*p) {
11604 case CTLESC:
11605 putc(*++p, fp);
11606 break;
11607 case CTLVAR:
11608 putc('$', fp);
11609 putc('{', fp);
11610 subtype = *++p;
11611 if (subtype == VSLENGTH)
11612 putc('#', fp);
11613
11614 while (*p != '=')
11615 putc(*p++, fp);
11616
11617 if (subtype & VSNUL)
11618 putc(':', fp);
11619
11620 switch (subtype & VSTYPE) {
11621 case VSNORMAL:
11622 putc('}', fp);
11623 break;
11624 case VSMINUS:
11625 putc('-', fp);
11626 break;
11627 case VSPLUS:
11628 putc('+', fp);
11629 break;
11630 case VSQUESTION:
11631 putc('?', fp);
11632 break;
11633 case VSASSIGN:
11634 putc('=', fp);
11635 break;
11636 case VSTRIMLEFT:
11637 putc('#', fp);
11638 break;
11639 case VSTRIMLEFTMAX:
11640 putc('#', fp);
11641 putc('#', fp);
11642 break;
11643 case VSTRIMRIGHT:
11644 putc('%', fp);
11645 break;
11646 case VSTRIMRIGHTMAX:
11647 putc('%', fp);
11648 putc('%', fp);
11649 break;
11650 case VSLENGTH:
11651 break;
11652 default:
11653 printf("<subtype %d>", subtype);
11654 }
11655 break;
11656 case CTLENDVAR:
11657 putc('}', fp);
11658 break;
11659 case CTLBACKQ:
11660 case CTLBACKQ|CTLQUOTE:
11661 putc('$', fp);
11662 putc('(', fp);
11663 shtree(bqlist->n, -1, NULL, fp);
11664 putc(')', fp);
11665 break;
11666 default:
11667 putc(*p, fp);
11668 break;
11669 }
11670 }
11671}
11672
11673
11674static void
11675indent(amount, pfx, fp)
11676 int amount;
11677 char *pfx;
11678 FILE *fp;
11679{
11680 int i;
11681
11682 for (i = 0 ; i < amount ; i++) {
11683 if (pfx && i == amount - 1)
11684 fputs(pfx, fp);
11685 putc('\t', fp);
11686 }
11687}
Eric Andersencb57d552001-06-28 07:25:16 +000011688
11689
Eric Andersencb57d552001-06-28 07:25:16 +000011690FILE *tracefile;
11691
11692#if DEBUG == 2
11693static int debug = 1;
11694#else
11695static int debug = 0;
11696#endif
11697
11698
11699static void
11700trputc(c)
11701 int c;
11702{
11703 if (tracefile == NULL)
11704 return;
11705 putc(c, tracefile);
11706 if (c == '\n')
11707 fflush(tracefile);
11708}
11709
11710static void
11711trace(const char *fmt, ...)
11712{
11713 va_list va;
Eric Andersencb57d552001-06-28 07:25:16 +000011714 va_start(va, fmt);
Eric Andersencb57d552001-06-28 07:25:16 +000011715 if (tracefile != NULL) {
11716 (void) vfprintf(tracefile, fmt, va);
11717 if (strchr(fmt, '\n'))
11718 (void) fflush(tracefile);
11719 }
11720 va_end(va);
11721}
11722
11723
11724static void
11725trputs(s)
11726 const char *s;
11727{
11728 if (tracefile == NULL)
11729 return;
11730 fputs(s, tracefile);
11731 if (strchr(s, '\n'))
11732 fflush(tracefile);
11733}
11734
11735
11736static void
11737trstring(s)
11738 char *s;
11739{
11740 char *p;
11741 char c;
11742
11743 if (tracefile == NULL)
11744 return;
11745 putc('"', tracefile);
11746 for (p = s ; *p ; p++) {
11747 switch (*p) {
11748 case '\n': c = 'n'; goto backslash;
11749 case '\t': c = 't'; goto backslash;
11750 case '\r': c = 'r'; goto backslash;
11751 case '"': c = '"'; goto backslash;
11752 case '\\': c = '\\'; goto backslash;
11753 case CTLESC: c = 'e'; goto backslash;
11754 case CTLVAR: c = 'v'; goto backslash;
11755 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11756 case CTLBACKQ: c = 'q'; goto backslash;
11757 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
Eric Andersen2870d962001-07-02 17:27:21 +000011758backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011759 putc(c, tracefile);
11760 break;
11761 default:
11762 if (*p >= ' ' && *p <= '~')
11763 putc(*p, tracefile);
11764 else {
11765 putc('\\', tracefile);
11766 putc(*p >> 6 & 03, tracefile);
11767 putc(*p >> 3 & 07, tracefile);
11768 putc(*p & 07, tracefile);
11769 }
11770 break;
11771 }
11772 }
11773 putc('"', tracefile);
11774}
11775
11776
11777static void
11778trargs(ap)
11779 char **ap;
11780{
11781 if (tracefile == NULL)
11782 return;
11783 while (*ap) {
11784 trstring(*ap++);
11785 if (*ap)
11786 putc(' ', tracefile);
11787 else
11788 putc('\n', tracefile);
11789 }
11790 fflush(tracefile);
11791}
11792
11793
11794static void
11795opentrace() {
11796 char s[100];
11797#ifdef O_APPEND
11798 int flags;
11799#endif
11800
11801 if (!debug)
11802 return;
11803#ifdef not_this_way
11804 {
11805 char *p;
11806 if ((p = getenv("HOME")) == NULL) {
11807 if (geteuid() == 0)
11808 p = "/";
11809 else
11810 p = "/tmp";
11811 }
Eric Andersen2870d962001-07-02 17:27:21 +000011812 strcpy(s, p);
Eric Andersencb57d552001-06-28 07:25:16 +000011813 strcat(s, "/trace");
11814 }
11815#else
Eric Andersen2870d962001-07-02 17:27:21 +000011816 strcpy(s, "./trace");
Eric Andersencb57d552001-06-28 07:25:16 +000011817#endif /* not_this_way */
Matt Kraaia5f09c62001-11-12 16:44:55 +000011818 if ((tracefile = wfopen(s, "a")) == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000011819 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011820#ifdef O_APPEND
11821 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11822 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11823#endif
11824 fputs("\nTracing started.\n", tracefile);
11825 fflush(tracefile);
11826}
11827#endif /* DEBUG */
11828
11829
11830/*
Eric Andersencb57d552001-06-28 07:25:16 +000011831 * The trap builtin.
11832 */
11833
11834static int
11835trapcmd(argc, argv)
11836 int argc;
11837 char **argv;
11838{
11839 char *action;
11840 char **ap;
11841 int signo;
11842
11843 if (argc <= 1) {
11844 for (signo = 0 ; signo < NSIG ; signo++) {
11845 if (trap[signo] != NULL) {
11846 char *p;
Eric Andersen34506362001-08-02 05:02:46 +000011847 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011848
11849 p = single_quote(trap[signo]);
Eric Andersen34506362001-08-02 05:02:46 +000011850 sn = sys_siglist[signo];
11851 if(sn==NULL)
11852 sn = u_signal_names(0, &signo, 0);
11853 if(sn==NULL)
11854 sn = "???";
11855 printf("trap -- %s %s\n", p, sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011856 stunalloc(p);
11857 }
11858 }
11859 return 0;
11860 }
11861 ap = argv + 1;
11862 if (argc == 2)
11863 action = NULL;
11864 else
11865 action = *ap++;
11866 while (*ap) {
11867 if ((signo = decode_signal(*ap, 0)) < 0)
11868 error("%s: bad trap", *ap);
11869 INTOFF;
11870 if (action) {
11871 if (action[0] == '-' && action[1] == '\0')
11872 action = NULL;
11873 else
11874 action = savestr(action);
11875 }
11876 if (trap[signo])
11877 ckfree(trap[signo]);
11878 trap[signo] = action;
11879 if (signo != 0)
11880 setsignal(signo);
11881 INTON;
11882 ap++;
11883 }
11884 return 0;
11885}
11886
11887
11888
Eric Andersencb57d552001-06-28 07:25:16 +000011889
11890
11891
11892/*
11893 * Set the signal handler for the specified signal. The routine figures
11894 * out what it should be set to.
11895 */
11896
11897static void
Eric Andersen2870d962001-07-02 17:27:21 +000011898setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011899{
11900 int action;
11901 char *t;
11902 struct sigaction act;
11903
11904 if ((t = trap[signo]) == NULL)
11905 action = S_DFL;
11906 else if (*t != '\0')
11907 action = S_CATCH;
11908 else
11909 action = S_IGN;
11910 if (rootshell && action == S_DFL) {
11911 switch (signo) {
11912 case SIGINT:
11913 if (iflag || minusc || sflag == 0)
11914 action = S_CATCH;
11915 break;
11916 case SIGQUIT:
11917#ifdef DEBUG
11918 {
Eric Andersencb57d552001-06-28 07:25:16 +000011919
11920 if (debug)
11921 break;
11922 }
11923#endif
11924 /* FALLTHROUGH */
11925 case SIGTERM:
11926 if (iflag)
11927 action = S_IGN;
11928 break;
Eric Andersen2870d962001-07-02 17:27:21 +000011929#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000011930 case SIGTSTP:
11931 case SIGTTOU:
11932 if (mflag)
11933 action = S_IGN;
11934 break;
11935#endif
11936 }
11937 }
11938
11939 t = &sigmode[signo - 1];
11940 if (*t == 0) {
11941 /*
11942 * current setting unknown
11943 */
11944 if (sigaction(signo, 0, &act) == -1) {
11945 /*
11946 * Pretend it worked; maybe we should give a warning
11947 * here, but other shells don't. We don't alter
11948 * sigmode, so that we retry every time.
11949 */
11950 return;
11951 }
11952 if (act.sa_handler == SIG_IGN) {
11953 if (mflag && (signo == SIGTSTP ||
11954 signo == SIGTTIN || signo == SIGTTOU)) {
Eric Andersen2870d962001-07-02 17:27:21 +000011955 *t = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000011956 } else
11957 *t = S_HARD_IGN;
11958 } else {
Eric Andersen2870d962001-07-02 17:27:21 +000011959 *t = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000011960 }
11961 }
11962 if (*t == S_HARD_IGN || *t == action)
11963 return;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011964 act.sa_handler = ((action == S_CATCH) ? onsig
11965 : ((action == S_IGN) ? SIG_IGN : SIG_DFL));
Eric Andersencb57d552001-06-28 07:25:16 +000011966 *t = action;
11967 act.sa_flags = 0;
11968 sigemptyset(&act.sa_mask);
11969 sigaction(signo, &act, 0);
11970}
11971
11972/*
11973 * Ignore a signal.
11974 */
11975
11976static void
11977ignoresig(signo)
11978 int signo;
11979{
11980 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11981 signal(signo, SIG_IGN);
11982 }
11983 sigmode[signo - 1] = S_HARD_IGN;
11984}
11985
11986
Eric Andersencb57d552001-06-28 07:25:16 +000011987/*
11988 * Signal handler.
11989 */
11990
11991static void
Eric Andersen2870d962001-07-02 17:27:21 +000011992onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011993{
11994 if (signo == SIGINT && trap[SIGINT] == NULL) {
11995 onint();
11996 return;
11997 }
11998 gotsig[signo - 1] = 1;
11999 pendingsigs++;
12000}
12001
12002
Eric Andersencb57d552001-06-28 07:25:16 +000012003/*
12004 * Called to execute a trap. Perhaps we should avoid entering new trap
12005 * handlers while we are executing a trap handler.
12006 */
12007
12008static void
Eric Andersen2870d962001-07-02 17:27:21 +000012009dotrap(void)
12010{
Eric Andersencb57d552001-06-28 07:25:16 +000012011 int i;
12012 int savestatus;
12013
12014 for (;;) {
12015 for (i = 1 ; ; i++) {
12016 if (gotsig[i - 1])
12017 break;
12018 if (i >= NSIG - 1)
12019 goto done;
12020 }
12021 gotsig[i - 1] = 0;
12022 savestatus=exitstatus;
12023 evalstring(trap[i], 0);
12024 exitstatus=savestatus;
12025 }
12026done:
12027 pendingsigs = 0;
12028}
12029
Eric Andersencb57d552001-06-28 07:25:16 +000012030/*
12031 * Called to exit the shell.
12032 */
12033
12034static void
Eric Andersen2870d962001-07-02 17:27:21 +000012035exitshell(int status)
Eric Andersencb57d552001-06-28 07:25:16 +000012036{
12037 struct jmploc loc1, loc2;
12038 char *p;
12039
12040 TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
12041 if (setjmp(loc1.loc)) {
12042 goto l1;
12043 }
12044 if (setjmp(loc2.loc)) {
12045 goto l2;
12046 }
12047 handler = &loc1;
12048 if ((p = trap[0]) != NULL && *p != '\0') {
12049 trap[0] = NULL;
12050 evalstring(p, 0);
12051 }
Eric Andersen2870d962001-07-02 17:27:21 +000012052l1: handler = &loc2; /* probably unnecessary */
Eric Andersencb57d552001-06-28 07:25:16 +000012053 flushall();
Eric Andersen2870d962001-07-02 17:27:21 +000012054#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000012055 setjobctl(0);
12056#endif
12057l2: _exit(status);
12058 /* NOTREACHED */
12059}
12060
12061static int decode_signal(const char *string, int minsig)
12062{
12063 int signo;
Eric Andersen34506362001-08-02 05:02:46 +000012064 const char *name = u_signal_names(string, &signo, minsig);
Eric Andersencb57d552001-06-28 07:25:16 +000012065
Eric Andersen34506362001-08-02 05:02:46 +000012066 return name ? signo : -1;
Eric Andersencb57d552001-06-28 07:25:16 +000012067}
Eric Andersen34506362001-08-02 05:02:46 +000012068
Eric Andersen2870d962001-07-02 17:27:21 +000012069static struct var **hashvar (const char *);
12070static void showvars (const char *, int, int);
12071static struct var **findvar (struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000012072
12073/*
12074 * Initialize the varable symbol tables and import the environment
12075 */
12076
Eric Andersencb57d552001-06-28 07:25:16 +000012077/*
12078 * This routine initializes the builtin variables. It is called when the
12079 * shell is initialized and again when a shell procedure is spawned.
12080 */
12081
12082static void
12083initvar() {
12084 const struct varinit *ip;
12085 struct var *vp;
12086 struct var **vpp;
12087
12088 for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
12089 if ((vp->flags & VEXPORT) == 0) {
12090 vpp = hashvar(ip->text);
12091 vp->next = *vpp;
12092 *vpp = vp;
Matt Kraaic8227632001-11-12 16:57:27 +000012093 vp->text = xstrdup(ip->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012094 vp->flags = ip->flags;
12095 vp->func = ip->func;
12096 }
12097 }
12098 /*
12099 * PS1 depends on uid
12100 */
12101 if ((vps1.flags & VEXPORT) == 0) {
12102 vpp = hashvar("PS1=");
12103 vps1.next = *vpp;
12104 *vpp = &vps1;
Matt Kraaic8227632001-11-12 16:57:27 +000012105 vps1.text = xstrdup(geteuid() ? "PS1=$ " : "PS1=# ");
Eric Andersencb57d552001-06-28 07:25:16 +000012106 vps1.flags = VSTRFIXED|VTEXTFIXED;
12107 }
12108}
12109
12110/*
12111 * Set the value of a variable. The flags argument is ored with the
12112 * flags of the variable. If val is NULL, the variable is unset.
12113 */
12114
12115static void
12116setvar(name, val, flags)
12117 const char *name, *val;
12118 int flags;
12119{
12120 const char *p;
12121 int len;
12122 int namelen;
12123 char *nameeq;
12124 int isbad;
12125 int vallen = 0;
12126
12127 isbad = 0;
12128 p = name;
12129 if (! is_name(*p))
12130 isbad = 1;
12131 p++;
12132 for (;;) {
12133 if (! is_in_name(*p)) {
12134 if (*p == '\0' || *p == '=')
12135 break;
12136 isbad = 1;
12137 }
12138 p++;
12139 }
12140 namelen = p - name;
12141 if (isbad)
12142 error("%.*s: bad variable name", namelen, name);
Eric Andersen2870d962001-07-02 17:27:21 +000012143 len = namelen + 2; /* 2 is space for '=' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +000012144 if (val == NULL) {
12145 flags |= VUNSET;
12146 } else {
12147 len += vallen = strlen(val);
12148 }
12149 INTOFF;
12150 nameeq = ckmalloc(len);
12151 memcpy(nameeq, name, namelen);
12152 nameeq[namelen] = '=';
12153 if (val) {
12154 memcpy(nameeq + namelen + 1, val, vallen + 1);
12155 } else {
12156 nameeq[namelen + 1] = '\0';
12157 }
12158 setvareq(nameeq, flags);
12159 INTON;
12160}
12161
12162
12163
12164/*
12165 * Same as setvar except that the variable and value are passed in
12166 * the first argument as name=value. Since the first argument will
12167 * be actually stored in the table, it should not be a string that
12168 * will go away.
12169 */
12170
12171static void
12172setvareq(s, flags)
12173 char *s;
12174 int flags;
12175{
12176 struct var *vp, **vpp;
12177
12178 vpp = hashvar(s);
12179 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
12180 if ((vp = *findvar(vpp, s))) {
12181 if (vp->flags & VREADONLY) {
12182 size_t len = strchr(s, '=') - s;
12183 error("%.*s: is read only", len, s);
12184 }
12185 INTOFF;
12186
12187 if (vp->func && (flags & VNOFUNC) == 0)
12188 (*vp->func)(strchr(s, '=') + 1);
12189
12190 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12191 ckfree(vp->text);
12192
12193 vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
12194 vp->flags |= flags;
12195 vp->text = s;
12196
Eric Andersenec074692001-10-31 11:05:49 +000012197#ifdef ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000012198 /*
12199 * We could roll this to a function, to handle it as
12200 * a regular variable function callback, but why bother?
12201 */
12202 if (iflag && (vp == &vmpath || (vp == &vmail && !mpathset())))
12203 chkmail(1);
Eric Andersenec074692001-10-31 11:05:49 +000012204#endif
Eric Andersencb57d552001-06-28 07:25:16 +000012205 INTON;
12206 return;
12207 }
12208 /* not found */
12209 vp = ckmalloc(sizeof (*vp));
12210 vp->flags = flags;
12211 vp->text = s;
12212 vp->next = *vpp;
12213 vp->func = NULL;
12214 *vpp = vp;
12215}
12216
12217
12218
12219/*
12220 * Process a linked list of variable assignments.
12221 */
12222
12223static void
12224listsetvar(mylist)
12225 struct strlist *mylist;
12226 {
12227 struct strlist *lp;
12228
12229 INTOFF;
12230 for (lp = mylist ; lp ; lp = lp->next) {
12231 setvareq(savestr(lp->text), 0);
12232 }
12233 INTON;
12234}
12235
12236
12237
12238/*
12239 * Find the value of a variable. Returns NULL if not set.
12240 */
12241
Eric Andersen62483552001-07-10 06:09:16 +000012242static const char *
Eric Andersencb57d552001-06-28 07:25:16 +000012243lookupvar(name)
12244 const char *name;
Eric Andersenec074692001-10-31 11:05:49 +000012245{
Eric Andersencb57d552001-06-28 07:25:16 +000012246 struct var *v;
12247
12248 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
12249 return strchr(v->text, '=') + 1;
12250 }
12251 return NULL;
12252}
12253
12254
12255
12256/*
12257 * Search the environment of a builtin command.
12258 */
12259
Eric Andersen62483552001-07-10 06:09:16 +000012260static const char *
12261bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012262{
Eric Andersen62483552001-07-10 06:09:16 +000012263 const struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012264
12265 for (sp = cmdenviron ; sp ; sp = sp->next) {
12266 if (varequal(sp->text, name))
12267 return strchr(sp->text, '=') + 1;
12268 }
12269 return lookupvar(name);
12270}
12271
12272
12273
12274/*
12275 * Generate a list of exported variables. This routine is used to construct
12276 * the third argument to execve when executing a program.
12277 */
12278
12279static char **
12280environment() {
12281 int nenv;
12282 struct var **vpp;
12283 struct var *vp;
12284 char **env;
12285 char **ep;
12286
12287 nenv = 0;
12288 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12289 for (vp = *vpp ; vp ; vp = vp->next)
12290 if (vp->flags & VEXPORT)
12291 nenv++;
12292 }
12293 ep = env = stalloc((nenv + 1) * sizeof *env);
12294 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12295 for (vp = *vpp ; vp ; vp = vp->next)
12296 if (vp->flags & VEXPORT)
12297 *ep++ = vp->text;
12298 }
12299 *ep = NULL;
12300 return env;
12301}
12302
12303
12304/*
12305 * Called when a shell procedure is invoked to clear out nonexported
12306 * variables. It is also necessary to reallocate variables of with
12307 * VSTACK set since these are currently allocated on the stack.
12308 */
12309
Eric Andersencb57d552001-06-28 07:25:16 +000012310static void
Eric Andersen2870d962001-07-02 17:27:21 +000012311shprocvar(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000012312 struct var **vpp;
12313 struct var *vp, **prev;
12314
12315 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12316 for (prev = vpp ; (vp = *prev) != NULL ; ) {
12317 if ((vp->flags & VEXPORT) == 0) {
12318 *prev = vp->next;
12319 if ((vp->flags & VTEXTFIXED) == 0)
12320 ckfree(vp->text);
12321 if ((vp->flags & VSTRFIXED) == 0)
12322 ckfree(vp);
12323 } else {
12324 if (vp->flags & VSTACK) {
12325 vp->text = savestr(vp->text);
12326 vp->flags &=~ VSTACK;
12327 }
12328 prev = &vp->next;
12329 }
12330 }
12331 }
12332 initvar();
12333}
12334
12335
12336
12337/*
12338 * Command to list all variables which are set. Currently this command
12339 * is invoked from the set command when the set command is called without
12340 * any variables.
12341 */
12342
12343static int
12344showvarscmd(argc, argv)
12345 int argc;
12346 char **argv;
12347{
12348 showvars(nullstr, VUNSET, VUNSET);
12349 return 0;
12350}
12351
12352
12353
12354/*
12355 * The export and readonly commands.
12356 */
12357
12358static int
12359exportcmd(argc, argv)
12360 int argc;
12361 char **argv;
12362{
12363 struct var *vp;
12364 char *name;
12365 const char *p;
12366 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12367 int pflag;
12368
12369 listsetvar(cmdenviron);
12370 pflag = (nextopt("p") == 'p');
12371 if (argc > 1 && !pflag) {
12372 while ((name = *argptr++) != NULL) {
12373 if ((p = strchr(name, '=')) != NULL) {
12374 p++;
12375 } else {
12376 if ((vp = *findvar(hashvar(name), name))) {
12377 vp->flags |= flag;
12378 goto found;
12379 }
12380 }
12381 setvar(name, p, flag);
12382found:;
12383 }
12384 } else {
12385 showvars(argv[0], flag, 0);
12386 }
12387 return 0;
12388}
12389
Eric Andersen34506362001-08-02 05:02:46 +000012390
Eric Andersencb57d552001-06-28 07:25:16 +000012391/*
12392 * The "local" command.
12393 */
12394
Eric Andersen2870d962001-07-02 17:27:21 +000012395/* funcnest nonzero if we are currently evaluating a function */
12396
Eric Andersencb57d552001-06-28 07:25:16 +000012397static int
12398localcmd(argc, argv)
12399 int argc;
12400 char **argv;
12401{
12402 char *name;
12403
Eric Andersen2870d962001-07-02 17:27:21 +000012404 if (! funcnest)
Eric Andersencb57d552001-06-28 07:25:16 +000012405 error("Not in a function");
12406 while ((name = *argptr++) != NULL) {
12407 mklocal(name);
12408 }
12409 return 0;
12410}
12411
12412
12413/*
12414 * Make a variable a local variable. When a variable is made local, it's
12415 * value and flags are saved in a localvar structure. The saved values
12416 * will be restored when the shell function returns. We handle the name
12417 * "-" as a special case.
12418 */
12419
12420static void
12421mklocal(name)
12422 char *name;
12423 {
12424 struct localvar *lvp;
12425 struct var **vpp;
12426 struct var *vp;
12427
12428 INTOFF;
12429 lvp = ckmalloc(sizeof (struct localvar));
12430 if (name[0] == '-' && name[1] == '\0') {
12431 char *p;
Eric Andersen2870d962001-07-02 17:27:21 +000012432 p = ckmalloc(sizeof optet_vals);
12433 lvp->text = memcpy(p, optet_vals, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000012434 vp = NULL;
12435 } else {
12436 vpp = hashvar(name);
12437 vp = *findvar(vpp, name);
12438 if (vp == NULL) {
12439 if (strchr(name, '='))
12440 setvareq(savestr(name), VSTRFIXED);
12441 else
12442 setvar(name, NULL, VSTRFIXED);
Eric Andersen2870d962001-07-02 17:27:21 +000012443 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012444 lvp->text = NULL;
12445 lvp->flags = VUNSET;
12446 } else {
12447 lvp->text = vp->text;
12448 lvp->flags = vp->flags;
12449 vp->flags |= VSTRFIXED|VTEXTFIXED;
12450 if (strchr(name, '='))
12451 setvareq(savestr(name), 0);
12452 }
12453 }
12454 lvp->vp = vp;
12455 lvp->next = localvars;
12456 localvars = lvp;
12457 INTON;
12458}
12459
12460
12461/*
12462 * Called after a function returns.
12463 */
12464
12465static void
12466poplocalvars() {
12467 struct localvar *lvp;
12468 struct var *vp;
12469
12470 while ((lvp = localvars) != NULL) {
12471 localvars = lvp->next;
12472 vp = lvp->vp;
Eric Andersen2870d962001-07-02 17:27:21 +000012473 if (vp == NULL) { /* $- saved */
12474 memcpy(optet_vals, lvp->text, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000012475 ckfree(lvp->text);
12476 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12477 (void)unsetvar(vp->text);
12478 } else {
12479 if ((vp->flags & VTEXTFIXED) == 0)
12480 ckfree(vp->text);
12481 vp->flags = lvp->flags;
12482 vp->text = lvp->text;
12483 }
12484 ckfree(lvp);
12485 }
12486}
12487
12488
12489static int
12490setvarcmd(argc, argv)
12491 int argc;
12492 char **argv;
12493{
12494 if (argc <= 2)
12495 return unsetcmd(argc, argv);
12496 else if (argc == 3)
12497 setvar(argv[1], argv[2], 0);
12498 else
12499 error("List assignment not implemented");
12500 return 0;
12501}
12502
12503
12504/*
12505 * The unset builtin command. We unset the function before we unset the
12506 * variable to allow a function to be unset when there is a readonly variable
12507 * with the same name.
12508 */
12509
12510static int
12511unsetcmd(argc, argv)
12512 int argc;
12513 char **argv;
12514{
12515 char **ap;
12516 int i;
12517 int flg_func = 0;
12518 int flg_var = 0;
12519 int ret = 0;
12520
12521 while ((i = nextopt("vf")) != '\0') {
12522 if (i == 'f')
12523 flg_func = 1;
12524 else
12525 flg_var = 1;
12526 }
12527 if (flg_func == 0 && flg_var == 0)
12528 flg_var = 1;
12529
12530 for (ap = argptr; *ap ; ap++) {
12531 if (flg_func)
12532 unsetfunc(*ap);
12533 if (flg_var)
12534 ret |= unsetvar(*ap);
12535 }
12536 return ret;
12537}
12538
12539
12540/*
12541 * Unset the specified variable.
12542 */
12543
12544static int
Eric Andersen62483552001-07-10 06:09:16 +000012545unsetvar(const char *s)
12546{
Eric Andersencb57d552001-06-28 07:25:16 +000012547 struct var **vpp;
12548 struct var *vp;
12549
12550 vpp = findvar(hashvar(s), s);
12551 vp = *vpp;
12552 if (vp) {
12553 if (vp->flags & VREADONLY)
12554 return (1);
12555 INTOFF;
12556 if (*(strchr(vp->text, '=') + 1) != '\0')
12557 setvar(s, nullstr, 0);
12558 vp->flags &= ~VEXPORT;
12559 vp->flags |= VUNSET;
12560 if ((vp->flags & VSTRFIXED) == 0) {
12561 if ((vp->flags & VTEXTFIXED) == 0)
12562 ckfree(vp->text);
12563 *vpp = vp->next;
12564 ckfree(vp);
12565 }
12566 INTON;
12567 return (0);
12568 }
12569
12570 return (0);
12571}
12572
12573
12574
12575/*
12576 * Find the appropriate entry in the hash table from the name.
12577 */
12578
12579static struct var **
Eric Andersen62483552001-07-10 06:09:16 +000012580hashvar(const char *p)
12581{
Eric Andersencb57d552001-06-28 07:25:16 +000012582 unsigned int hashval;
12583
12584 hashval = ((unsigned char) *p) << 4;
12585 while (*p && *p != '=')
12586 hashval += (unsigned char) *p++;
12587 return &vartab[hashval % VTABSIZE];
12588}
12589
12590
12591
12592/*
12593 * Returns true if the two strings specify the same varable. The first
12594 * variable name is terminated by '='; the second may be terminated by
12595 * either '=' or '\0'.
12596 */
12597
12598static int
Eric Andersen62483552001-07-10 06:09:16 +000012599varequal(const char *p, const char *q)
12600{
Eric Andersencb57d552001-06-28 07:25:16 +000012601 while (*p == *q++) {
12602 if (*p++ == '=')
12603 return 1;
12604 }
12605 if (*p == '=' && *(q - 1) == '\0')
12606 return 1;
12607 return 0;
12608}
12609
12610static void
12611showvars(const char *myprefix, int mask, int xor)
12612{
12613 struct var **vpp;
12614 struct var *vp;
12615 const char *sep = myprefix == nullstr ? myprefix : spcstr;
12616
12617 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12618 for (vp = *vpp ; vp ; vp = vp->next) {
12619 if ((vp->flags & mask) ^ xor) {
12620 char *p;
12621 int len;
12622
12623 p = strchr(vp->text, '=') + 1;
12624 len = p - vp->text;
12625 p = single_quote(p);
12626
Eric Andersen62483552001-07-10 06:09:16 +000012627 printf("%s%s%.*s%s\n", myprefix, sep, len,
12628 vp->text, p);
Eric Andersencb57d552001-06-28 07:25:16 +000012629 stunalloc(p);
12630 }
12631 }
12632 }
12633}
12634
12635static struct var **
12636findvar(struct var **vpp, const char *name)
12637{
12638 for (; *vpp; vpp = &(*vpp)->next) {
12639 if (varequal((*vpp)->text, name)) {
12640 break;
12641 }
12642 }
12643 return vpp;
12644}
12645
12646/*
12647 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
12648 * This file contains code for the times builtin.
Matt Kraaic8227632001-11-12 16:57:27 +000012649 * $Id: ash.c,v 1.36 2001/11/12 16:57:26 kraai Exp $
Eric Andersencb57d552001-06-28 07:25:16 +000012650 */
12651static int timescmd (int argc, char **argv)
12652{
12653 struct tms buf;
12654 long int clk_tck = sysconf(_SC_CLK_TCK);
12655
12656 times(&buf);
12657 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
12658 (int) (buf.tms_utime / clk_tck / 60),
12659 ((double) buf.tms_utime) / clk_tck,
12660 (int) (buf.tms_stime / clk_tck / 60),
12661 ((double) buf.tms_stime) / clk_tck,
12662 (int) (buf.tms_cutime / clk_tck / 60),
12663 ((double) buf.tms_cutime) / clk_tck,
12664 (int) (buf.tms_cstime / clk_tck / 60),
12665 ((double) buf.tms_cstime) / clk_tck);
12666 return 0;
12667}
12668
Eric Andersen74bcd162001-07-30 21:41:37 +000012669#ifdef ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012670/* The let builtin. */
12671int letcmd(int argc, char **argv)
Eric Andersen74bcd162001-07-30 21:41:37 +000012672{
Eric Andersen34506362001-08-02 05:02:46 +000012673 int errcode;
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012674 long result=0;
12675 if (argc == 2) {
12676 char *tmp, *expression, p[13];
12677 expression = strchr(argv[1], '=');
12678 if (!expression) {
Eric Andersen34506362001-08-02 05:02:46 +000012679 /* Cannot use 'error()' here, or the return code
12680 * will be incorrect */
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012681 out2fmt("sh: let: syntax error: \"%s\"\n", argv[1]);
12682 return 0;
Eric Andersen74bcd162001-07-30 21:41:37 +000012683 }
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012684 *expression = '\0';
12685 tmp = ++expression;
Eric Andersen34506362001-08-02 05:02:46 +000012686 result = arith(tmp, &errcode);
12687 if (errcode < 0) {
12688 /* Cannot use 'error()' here, or the return code
12689 * will be incorrect */
12690 out2fmt("sh: let: ");
12691 if(errcode == -2)
12692 out2fmt("divide by zero");
12693 else
12694 out2fmt("syntax error: \"%s=%s\"\n", argv[1], expression);
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012695 return 0;
12696 }
12697 snprintf(p, 12, "%ld", result);
12698 setvar(argv[1], savestr(p), 0);
12699 } else if (argc >= 3)
12700 synerror("invalid operand");
12701 return !result;
Eric Andersen74bcd162001-07-30 21:41:37 +000012702}
12703#endif
12704
12705
12706
Eric Andersendf82f612001-06-28 07:46:40 +000012707/*-
12708 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000012709 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000012710 *
12711 * This code is derived from software contributed to Berkeley by
12712 * Kenneth Almquist.
12713 *
12714 * Redistribution and use in source and binary forms, with or without
12715 * modification, are permitted provided that the following conditions
12716 * are met:
12717 * 1. Redistributions of source code must retain the above copyright
12718 * notice, this list of conditions and the following disclaimer.
12719 * 2. Redistributions in binary form must reproduce the above copyright
12720 * notice, this list of conditions and the following disclaimer in the
12721 * documentation and/or other materials provided with the distribution.
12722 *
Eric Andersen2870d962001-07-02 17:27:21 +000012723 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
12724 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000012725 *
12726 * 4. Neither the name of the University nor the names of its contributors
12727 * may be used to endorse or promote products derived from this software
12728 * without specific prior written permission.
12729 *
12730 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
12731 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
12732 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
12733 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
12734 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
12735 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
12736 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
12737 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
12738 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
12739 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
12740 * SUCH DAMAGE.
12741 */