blob: 80da35b59a5f06b1368bb607d0a993244f8a4c4f [file] [log] [blame]
Eric Andersendf82f612001-06-28 07:46:40 +00001/* vi: set sw=4 ts=4: */
2/*
3 * ash shell port for busybox
4 *
5 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +00006 * The Regents of the University of California. All rights reserved.
Eric Andersencb57d552001-06-28 07:25:16 +00007 *
8 * This code is derived from software contributed to Berkeley by
9 * Kenneth Almquist.
10 *
Eric Andersendf82f612001-06-28 07:46:40 +000011 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
Eric Andersencb57d552001-06-28 07:25:16 +000015 *
Eric Andersendf82f612001-06-28 07:46:40 +000016 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
Eric Andersen2870d962001-07-02 17:27:21 +000025 * This version of ash is adapted from the source in Debian's ash 0.3.8-5
26 * package.
Eric Andersendf82f612001-06-28 07:46:40 +000027 *
Eric Andersen2870d962001-07-02 17:27:21 +000028 * Modified by Erik Andersen <andersee@debian.org> and
Eric Andersen7467c8d2001-07-12 20:26:32 +000029 * Vladimir Oleynik <dzo@simtreas.ru> to be used in busybox
Eric Andersen2870d962001-07-02 17:27:21 +000030 *
Eric Andersendf82f612001-06-28 07:46:40 +000031 *
32 * Original copyright notice is retained at the end of this file.
Eric Andersencb57d552001-06-28 07:25:16 +000033 */
34
Eric Andersen2870d962001-07-02 17:27:21 +000035
Eric Andersen2870d962001-07-02 17:27:21 +000036/* Enable this to compile in extra debugging noise. When debugging is
37 * on, debugging info will be written to $HOME/trace and a quit signal
38 * will generate a core dump. */
39#undef DEBUG
40
Eric Andersen2870d962001-07-02 17:27:21 +000041/* These are here to work with glibc -- Don't change these... */
Eric Andersendf82f612001-06-28 07:46:40 +000042#undef FNMATCH_BROKEN
43#undef GLOB_BROKEN
Eric Andersen5bb16772001-09-06 18:00:41 +000044#define IFS_BROKEN
Eric Andersencb57d552001-06-28 07:25:16 +000045
46#include <assert.h>
Manuel Novoa III 16815d42001-08-10 19:36:07 +000047#include <stddef.h>
Eric Andersencb57d552001-06-28 07:25:16 +000048#include <ctype.h>
49#include <dirent.h>
50#include <errno.h>
51#include <fcntl.h>
52#include <limits.h>
53#include <paths.h>
Eric Andersencb57d552001-06-28 07:25:16 +000054#include <setjmp.h>
55#include <signal.h>
56#include <stdarg.h>
Eric Andersencb57d552001-06-28 07:25:16 +000057#include <stdio.h>
58#include <stdlib.h>
59#include <string.h>
60#include <sysexits.h>
61#include <unistd.h>
62#include <sys/stat.h>
63#include <sys/cdefs.h>
64#include <sys/ioctl.h>
65#include <sys/param.h>
66#include <sys/resource.h>
67#include <sys/time.h>
68#include <sys/times.h>
69#include <sys/types.h>
70#include <sys/wait.h>
Robert Grieblea1a63a2002-06-04 20:10:23 +000071#include "busybox.h"
Eric Andersen1a10eec2001-10-24 17:19:38 +000072#include "pwd.h"
Eric Andersencb57d552001-06-28 07:25:16 +000073
74
75#if !defined(FNMATCH_BROKEN)
76#include <fnmatch.h>
77#endif
78#if !defined(GLOB_BROKEN)
79#include <glob.h>
80#endif
81
Eric Andersend35c5df2002-01-09 15:37:36 +000082#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +000083#include <termios.h>
Eric Andersencb57d552001-06-28 07:25:16 +000084#endif
85
Eric Andersen2870d962001-07-02 17:27:21 +000086#include "cmdedit.h"
87
Eric Andersen2870d962001-07-02 17:27:21 +000088/*
89 * This file was generated by the mksyntax program.
90 */
91
92/* Syntax classes */
93#define CWORD 0 /* character is nothing special */
94#define CNL 1 /* newline character */
95#define CBACK 2 /* a backslash character */
96#define CSQUOTE 3 /* single quote */
97#define CDQUOTE 4 /* double quote */
98#define CENDQUOTE 5 /* a terminating quote */
99#define CBQUOTE 6 /* backwards single quote */
100#define CVAR 7 /* a dollar sign */
101#define CENDVAR 8 /* a '}' character */
102#define CLP 9 /* a left paren in arithmetic */
103#define CRP 10 /* a right paren in arithmetic */
104#define CENDFILE 11 /* end of file */
105#define CCTL 12 /* like CWORD, except it must be escaped */
106#define CSPCL 13 /* these terminate a word */
107#define CIGN 14 /* character should be ignored */
108
Eric Andersen2870d962001-07-02 17:27:21 +0000109#define SYNBASE 130
110#define PEOF -130
111
112#define PEOA -129
113
114#define TEOF 0
115#define TNL 1
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000116#define TREDIR 2
117#define TWORD 3
118#define TASSIGN 4
119#define TSEMI 5
120#define TBACKGND 6
121#define TAND 7
122#define TOR 8
123#define TPIPE 9
124#define TLP 10
125#define TRP 11
126#define TENDCASE 12
127#define TENDBQUOTE 13
Eric Andersen2870d962001-07-02 17:27:21 +0000128#define TNOT 14
129#define TCASE 15
130#define TDO 16
131#define TDONE 17
132#define TELIF 18
133#define TELSE 19
134#define TESAC 20
135#define TFI 21
136#define TFOR 22
137#define TIF 23
138#define TIN 24
139#define TTHEN 25
140#define TUNTIL 26
141#define TWHILE 27
142#define TBEGIN 28
143#define TEND 29
144
145
Eric Andersen2870d962001-07-02 17:27:21 +0000146
147/* control characters in argument strings */
148#define CTLESC '\201'
149#define CTLVAR '\202'
150#define CTLENDVAR '\203'
151#define CTLBACKQ '\204'
152#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
153/* CTLBACKQ | CTLQUOTE == '\205' */
154#define CTLARI '\206'
155#define CTLENDARI '\207'
156#define CTLQUOTEMARK '\210'
157
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000158
Eric Andersen62483552001-07-10 06:09:16 +0000159#define is_digit(c) ((c)>='0' && (c)<='9')
Eric Andersen2870d962001-07-02 17:27:21 +0000160#define is_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalpha((unsigned char) (c))))
161#define is_in_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalnum((unsigned char) (c))))
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000162
163/*
164 * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
165 * (assuming ascii char codes, as the original implementation did)
166 */
167#define is_special(c) \
168 ( (((unsigned int)c) - 33 < 32) \
169 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
170
Eric Andersen2870d962001-07-02 17:27:21 +0000171#define digit_val(c) ((c) - '0')
Eric Andersencb57d552001-06-28 07:25:16 +0000172
173
Eric Andersen2870d962001-07-02 17:27:21 +0000174#define S_DFL 1 /* default signal handling (SIG_DFL) */
175#define S_CATCH 2 /* signal is caught */
176#define S_IGN 3 /* signal is ignored (SIG_IGN) */
177#define S_HARD_IGN 4 /* signal is ignored permenantly */
178#define S_RESET 5 /* temporary - to reset a hard ignored sig */
Eric Andersencb57d552001-06-28 07:25:16 +0000179
180
Eric Andersen2870d962001-07-02 17:27:21 +0000181/* variable substitution byte (follows CTLVAR) */
182#define VSTYPE 0x0f /* type of variable substitution */
183#define VSNUL 0x10 /* colon--treat the empty string as unset */
184#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
Eric Andersencb57d552001-06-28 07:25:16 +0000185
Eric Andersen2870d962001-07-02 17:27:21 +0000186/* values of VSTYPE field */
187#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
188#define VSMINUS 0x2 /* ${var-text} */
189#define VSPLUS 0x3 /* ${var+text} */
190#define VSQUESTION 0x4 /* ${var?message} */
191#define VSASSIGN 0x5 /* ${var=text} */
192#define VSTRIMLEFT 0x6 /* ${var#pattern} */
193#define VSTRIMLEFTMAX 0x7 /* ${var##pattern} */
194#define VSTRIMRIGHT 0x8 /* ${var%pattern} */
195#define VSTRIMRIGHTMAX 0x9 /* ${var%%pattern} */
196#define VSLENGTH 0xa /* ${#var} */
Eric Andersencb57d552001-06-28 07:25:16 +0000197
Eric Andersen2870d962001-07-02 17:27:21 +0000198/* flags passed to redirect */
199#define REDIR_PUSH 01 /* save previous values of file descriptors */
Eric Andersen3102ac42001-07-06 04:26:23 +0000200#define REDIR_BACKQ 02 /* save the command output to pipe */
Eric Andersencb57d552001-06-28 07:25:16 +0000201
Eric Andersen2870d962001-07-02 17:27:21 +0000202/*
203 * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
204 * so we use _setjmp instead.
205 */
206
Eric Andersen62483552001-07-10 06:09:16 +0000207#if defined(BSD)
Eric Andersen2870d962001-07-02 17:27:21 +0000208#define setjmp(jmploc) _setjmp(jmploc)
209#define longjmp(jmploc, val) _longjmp(jmploc, val)
210#endif
211
212/*
213 * Most machines require the value returned from malloc to be aligned
214 * in some way. The following macro will get this right on many machines.
215 */
216
217#ifndef ALIGN
218union align {
219 int i;
220 char *cp;
221};
222
223#define ALIGN(nbytes) (((nbytes) + sizeof(union align) - 1) & ~(sizeof(union align) - 1))
224#endif
225
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000226#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +0000227#include <locale.h>
228static void change_lc_all(const char *value);
229static void change_lc_ctype(const char *value);
230#endif
231
232/*
233 * These macros allow the user to suspend the handling of interrupt signals
234 * over a period of time. This is similar to SIGHOLD to or sigblock, but
235 * much more efficient and portable. (But hacking the kernel is so much
236 * more fun than worrying about efficiency and portability. :-))
237 */
238
239static void onint (void);
240static volatile int suppressint;
241static volatile int intpending;
242
243#define INTOFF suppressint++
Eric Andersend35c5df2002-01-09 15:37:36 +0000244#ifndef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Eric Andersen2870d962001-07-02 17:27:21 +0000245#define INTON { if (--suppressint == 0 && intpending) onint(); }
Eric Andersen3102ac42001-07-06 04:26:23 +0000246#define FORCEINTON {suppressint = 0; if (intpending) onint();}
Eric Andersen2870d962001-07-02 17:27:21 +0000247#else
248static void __inton (void);
Eric Andersen3102ac42001-07-06 04:26:23 +0000249static void forceinton (void);
Eric Andersen2870d962001-07-02 17:27:21 +0000250#define INTON __inton()
Eric Andersen3102ac42001-07-06 04:26:23 +0000251#define FORCEINTON forceinton()
Eric Andersen2870d962001-07-02 17:27:21 +0000252#endif
Eric Andersen3102ac42001-07-06 04:26:23 +0000253
Eric Andersen2870d962001-07-02 17:27:21 +0000254#define CLEAR_PENDING_INT intpending = 0
255#define int_pending() intpending
256
257
258typedef void *pointer;
259#ifndef NULL
260#define NULL (void *)0
261#endif
262
Eric Andersen2870d962001-07-02 17:27:21 +0000263static pointer stalloc (int);
264static void stunalloc (pointer);
265static void ungrabstackstr (char *, char *);
266static char * growstackstr(void);
Eric Andersen3102ac42001-07-06 04:26:23 +0000267static char * makestrspace(size_t newlen);
Eric Andersen2870d962001-07-02 17:27:21 +0000268static char *sstrdup (const char *);
269
270/*
271 * Parse trees for commands are allocated in lifo order, so we use a stack
272 * to make this more efficient, and also to avoid all sorts of exception
273 * handling code to handle interrupts in the middle of a parse.
274 *
275 * The size 504 was chosen because the Ultrix malloc handles that size
276 * well.
277 */
278
279#define MINSIZE 504 /* minimum size of a block */
280
281
282struct stack_block {
283 struct stack_block *prev;
284 char space[MINSIZE];
285};
286
287static struct stack_block stackbase;
288static struct stack_block *stackp = &stackbase;
289static struct stackmark *markp;
290static char *stacknxt = stackbase.space;
291static int stacknleft = MINSIZE;
292
293
294#define equal(s1, s2) (strcmp(s1, s2) == 0)
295
296#define stackblock() stacknxt
297#define stackblocksize() stacknleft
298#define STARTSTACKSTR(p) p = stackblock(), sstrnleft = stackblocksize()
Eric Andersen3102ac42001-07-06 04:26:23 +0000299
Eric Andersen2870d962001-07-02 17:27:21 +0000300#define STPUTC(c, p) (--sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(), *p++ = (c)))
301#define CHECKSTRSPACE(n, p) { if (sstrnleft < n) p = makestrspace(n); }
Eric Andersen2870d962001-07-02 17:27:21 +0000302#define STACKSTRNUL(p) (sstrnleft == 0? (p = growstackstr(), *p = '\0') : (*p = '\0'))
Eric Andersen3102ac42001-07-06 04:26:23 +0000303
304
305#define USTPUTC(c, p) (--sstrnleft, *p++ = (c))
Eric Andersen2870d962001-07-02 17:27:21 +0000306#define STUNPUTC(p) (++sstrnleft, --p)
307#define STTOPC(p) p[-1]
308#define STADJUST(amount, p) (p += (amount), sstrnleft -= (amount))
309#define grabstackstr(p) stalloc(stackblocksize() - sstrnleft)
310
311#define ckfree(p) free((pointer)(p))
312
Eric Andersen2870d962001-07-02 17:27:21 +0000313
314#ifdef DEBUG
315#define TRACE(param) trace param
Eric Andersen69a20f02001-10-31 10:40:37 +0000316typedef union node unode;
Eric Andersen2870d962001-07-02 17:27:21 +0000317static void trace (const char *, ...);
318static void trargs (char **);
Eric Andersen69a20f02001-10-31 10:40:37 +0000319static void showtree (unode *);
Eric Andersen2870d962001-07-02 17:27:21 +0000320static void trputc (int);
321static void trputs (const char *);
322static void opentrace (void);
323#else
324#define TRACE(param)
325#endif
326
327#define NSEMI 0
328#define NCMD 1
329#define NPIPE 2
330#define NREDIR 3
331#define NBACKGND 4
332#define NSUBSHELL 5
333#define NAND 6
334#define NOR 7
335#define NIF 8
336#define NWHILE 9
337#define NUNTIL 10
338#define NFOR 11
339#define NCASE 12
340#define NCLIST 13
341#define NDEFUN 14
342#define NARG 15
343#define NTO 16
344#define NFROM 17
345#define NFROMTO 18
346#define NAPPEND 19
347#define NTOOV 20
348#define NTOFD 21
349#define NFROMFD 22
350#define NHERE 23
351#define NXHERE 24
352#define NNOT 25
353
354/*
355 * expandarg() flags
356 */
357#define EXP_FULL 0x1 /* perform word splitting & file globbing */
358#define EXP_TILDE 0x2 /* do normal tilde expansion */
359#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
360#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
361#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
362#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
363
364
365#define NOPTS 16
366
367static char optet_vals[NOPTS];
368
369static const char * const optlist[NOPTS] = {
370 "e" "errexit",
371 "f" "noglob",
372 "I" "ignoreeof",
373 "i" "interactive",
374 "m" "monitor",
375 "n" "noexec",
376 "s" "stdin",
377 "x" "xtrace",
378 "v" "verbose",
379 "V" "vi",
380 "E" "emacs",
381 "C" "noclobber",
382 "a" "allexport",
383 "b" "notify",
384 "u" "nounset",
385 "q" "quietprofile"
386};
387
388#define optent_name(optent) (optent+1)
389#define optent_letter(optent) optent[0]
390#define optent_val(optent) optet_vals[optent]
391
392#define eflag optent_val(0)
393#define fflag optent_val(1)
394#define Iflag optent_val(2)
395#define iflag optent_val(3)
396#define mflag optent_val(4)
397#define nflag optent_val(5)
398#define sflag optent_val(6)
399#define xflag optent_val(7)
400#define vflag optent_val(8)
401#define Vflag optent_val(9)
402#define Eflag optent_val(10)
403#define Cflag optent_val(11)
404#define aflag optent_val(12)
405#define bflag optent_val(13)
406#define uflag optent_val(14)
407#define qflag optent_val(15)
408
409
410/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
411#define FORK_FG 0
412#define FORK_BG 1
413#define FORK_NOJOB 2
414
415
416struct nbinary {
417 int type;
418 union node *ch1;
419 union node *ch2;
420};
421
422
423struct ncmd {
424 int type;
425 int backgnd;
426 union node *assign;
427 union node *args;
428 union node *redirect;
429};
430
431
432struct npipe {
433 int type;
434 int backgnd;
435 struct nodelist *cmdlist;
436};
437
438
439struct nredir {
440 int type;
441 union node *n;
442 union node *redirect;
443};
444
445
446struct nif {
447 int type;
448 union node *test;
449 union node *ifpart;
450 union node *elsepart;
451};
452
453
454struct nfor {
455 int type;
456 union node *args;
457 union node *body;
458 char *var;
459};
460
461
462struct ncase {
463 int type;
464 union node *expr;
465 union node *cases;
466};
467
468
469struct nclist {
470 int type;
471 union node *next;
472 union node *pattern;
473 union node *body;
474};
475
476
477struct narg {
478 int type;
479 union node *next;
480 char *text;
481 struct nodelist *backquote;
482};
483
484
485struct nfile {
486 int type;
487 union node *next;
488 int fd;
489 union node *fname;
490 char *expfname;
491};
492
493
494struct ndup {
495 int type;
496 union node *next;
497 int fd;
498 int dupfd;
499 union node *vname;
500};
501
502
503struct nhere {
504 int type;
505 union node *next;
506 int fd;
507 union node *doc;
508};
509
510
511struct nnot {
512 int type;
513 union node *com;
514};
515
516
517union node {
518 int type;
519 struct nbinary nbinary;
520 struct ncmd ncmd;
521 struct npipe npipe;
522 struct nredir nredir;
523 struct nif nif;
524 struct nfor nfor;
525 struct ncase ncase;
526 struct nclist nclist;
527 struct narg narg;
528 struct nfile nfile;
529 struct ndup ndup;
530 struct nhere nhere;
531 struct nnot nnot;
532};
533
534
535struct nodelist {
536 struct nodelist *next;
537 union node *n;
538};
539
540struct backcmd { /* result of evalbackcmd */
541 int fd; /* file descriptor to read from */
542 char *buf; /* buffer */
543 int nleft; /* number of chars in buffer */
544 struct job *jp; /* job structure for command */
545};
546
547struct cmdentry {
548 int cmdtype;
549 union param {
550 int index;
551 union node *func;
552 const struct builtincmd *cmd;
553 } u;
554};
555
556struct strlist {
557 struct strlist *next;
558 char *text;
559};
560
561
562struct arglist {
563 struct strlist *list;
564 struct strlist **lastp;
565};
566
567struct strpush {
568 struct strpush *prev; /* preceding string on stack */
569 char *prevstring;
570 int prevnleft;
Eric Andersend35c5df2002-01-09 15:37:36 +0000571#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +0000572 struct alias *ap; /* if push was associated with an alias */
573#endif
574 char *string; /* remember the string since it may change */
575};
576
577struct parsefile {
578 struct parsefile *prev; /* preceding file on stack */
579 int linno; /* current line */
580 int fd; /* file descriptor (or -1 if string) */
581 int nleft; /* number of chars left in this line */
582 int lleft; /* number of chars left in this buffer */
583 char *nextc; /* next char in buffer */
584 char *buf; /* input buffer */
585 struct strpush *strpush; /* for pushing strings at this level */
586 struct strpush basestrpush; /* so pushing one is fast */
587};
588
589struct stackmark {
590 struct stack_block *stackp;
591 char *stacknxt;
592 int stacknleft;
593 struct stackmark *marknext;
594};
595
596struct shparam {
597 int nparam; /* # of positional parameters (without $0) */
598 unsigned char malloc; /* if parameter list dynamically allocated */
599 char **p; /* parameter list */
600 int optind; /* next parameter to be processed by getopts */
601 int optoff; /* used by getopts */
602};
603
Eric Andersen62483552001-07-10 06:09:16 +0000604/*
605 * When commands are first encountered, they are entered in a hash table.
606 * This ensures that a full path search will not have to be done for them
607 * on each invocation.
608 *
609 * We should investigate converting to a linear search, even though that
610 * would make the command name "hash" a misnomer.
611 */
612#define CMDTABLESIZE 31 /* should be prime */
613#define ARB 1 /* actual size determined at run time */
614
615
616
617struct tblentry {
618 struct tblentry *next; /* next entry in hash chain */
619 union param param; /* definition of builtin function */
620 short cmdtype; /* index identifying command */
621 char rehash; /* if set, cd done since entry created */
622 char cmdname[ARB]; /* name of command */
623};
624
625
626static struct tblentry *cmdtable[CMDTABLESIZE];
627static int builtinloc = -1; /* index in path of %builtin, or -1 */
628static int exerrno = 0; /* Last exec error */
629
630
631static void tryexec (char *, char **, char **);
632static void printentry (struct tblentry *, int);
633static void clearcmdentry (int);
634static struct tblentry *cmdlookup (const char *, int);
635static void delete_cmd_entry (void);
636static int path_change (const char *, int *);
637
638
Eric Andersen2870d962001-07-02 17:27:21 +0000639static void flushall (void);
Eric Andersen3102ac42001-07-06 04:26:23 +0000640static void out2fmt (const char *, ...)
641 __attribute__((__format__(__printf__,1,2)));
Eric Andersen2870d962001-07-02 17:27:21 +0000642static int xwrite (int, const char *, int);
Eric Andersen2870d962001-07-02 17:27:21 +0000643
Manuel Novoa III c639a352001-08-12 17:32:56 +0000644static inline void outstr (const char *p, FILE *file) { fputs(p, file); }
Eric Andersen3102ac42001-07-06 04:26:23 +0000645static void out1str(const char *p) { outstr(p, stdout); }
646static void out2str(const char *p) { outstr(p, stderr); }
Eric Andersen2870d962001-07-02 17:27:21 +0000647
Eric Andersend35c5df2002-01-09 15:37:36 +0000648#ifndef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Eric Andersen3102ac42001-07-06 04:26:23 +0000649#define out2c(c) putc((c), stderr)
Eric Andersen62483552001-07-10 06:09:16 +0000650#else
651static void out2c(int c) { putc(c, stderr); }
652#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000653
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000654
Eric Andersend35c5df2002-01-09 15:37:36 +0000655#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000656#define USE_SIT_FUNCTION
657#endif
658
659/* number syntax index */
660#define BASESYNTAX 0 /* not in quotes */
661#define DQSYNTAX 1 /* in double quotes */
662#define SQSYNTAX 2 /* in single quotes */
663#define ARISYNTAX 3 /* in arithmetic */
664
665static const char S_I_T[][4] = {
666 /* 0 */ { CSPCL, CIGN, CIGN, CIGN }, /* PEOA */
667 /* 1 */ { CSPCL, CWORD, CWORD, CWORD }, /* ' ' */
668 /* 2 */ { CNL, CNL, CNL, CNL }, /* \n */
669 /* 3 */ { CWORD, CCTL, CCTL, CWORD }, /* !*-/:=?[]~ */
670 /* 4 */ { CDQUOTE, CENDQUOTE, CWORD, CDQUOTE }, /* '"' */
671 /* 5 */ { CVAR, CVAR, CWORD, CVAR }, /* $ */
672 /* 6 */ { CSQUOTE, CWORD, CENDQUOTE, CSQUOTE }, /* "'" */
673 /* 7 */ { CSPCL, CWORD, CWORD, CLP }, /* ( */
674 /* 8 */ { CSPCL, CWORD, CWORD, CRP }, /* ) */
675 /* 9 */ { CBACK, CBACK, CCTL, CBACK }, /* \ */
676 /* 10 */ { CBQUOTE, CBQUOTE, CWORD, CBQUOTE }, /* ` */
677 /* 11 */ { CENDVAR, CENDVAR, CWORD, CENDVAR }, /* } */
678#ifndef USE_SIT_FUNCTION
679 /* 12 */ { CENDFILE, CENDFILE, CENDFILE, CENDFILE }, /* PEOF */
680 /* 13 */ { CWORD, CWORD, CWORD, CWORD }, /* 0-9A-Za-z */
681 /* 14 */ { CCTL, CCTL, CCTL, CCTL } /* CTLESC ... */
682#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000683};
684
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000685#ifdef USE_SIT_FUNCTION
686
687#define U_C(c) ((unsigned char)(c))
688
689static int SIT(int c, int syntax)
690{
691 static const char spec_symbls[]="\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
692 static const char syntax_index_table [] = {
693 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
694 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
695 3, 1, 3, 3, 9, 3,10, 1, /* "=>?[\\]`|" */
696 11,3 }; /* "}~" */
697 const char *s;
698 int indx;
699
700 if(c==PEOF) /* 2^8+2 */
701 return CENDFILE;
702 if(c==PEOA) /* 2^8+1 */
703 indx = 0;
704 else if(U_C(c)>=U_C(CTLESC) && U_C(c)<=U_C(CTLQUOTEMARK))
705 return CCTL;
706 else {
707 s = strchr(spec_symbls, c);
708 if(s==0)
709 return CWORD;
710 indx = syntax_index_table[(s-spec_symbls)];
711 }
712 return S_I_T[indx][syntax];
713}
714
715#else /* USE_SIT_FUNCTION */
716
717#define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
718
719#define CSPCL_CIGN_CIGN_CIGN 0
720#define CSPCL_CWORD_CWORD_CWORD 1
721#define CNL_CNL_CNL_CNL 2
722#define CWORD_CCTL_CCTL_CWORD 3
723#define CDQUOTE_CENDQUOTE_CWORD_CDQUOTE 4
724#define CVAR_CVAR_CWORD_CVAR 5
725#define CSQUOTE_CWORD_CENDQUOTE_CSQUOTE 6
726#define CSPCL_CWORD_CWORD_CLP 7
727#define CSPCL_CWORD_CWORD_CRP 8
728#define CBACK_CBACK_CCTL_CBACK 9
729#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
730#define CENDVAR_CENDVAR_CWORD_CENDVAR 11
731#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
732#define CWORD_CWORD_CWORD_CWORD 13
733#define CCTL_CCTL_CCTL_CCTL 14
734
735static const char syntax_index_table[258] = {
736 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
737 /* 0 -130 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
738 /* 1 -129 PEOA */ CSPCL_CIGN_CIGN_CIGN,
739 /* 2 -128 0xff */ CWORD_CWORD_CWORD_CWORD,
740 /* 3 -127 */ CCTL_CCTL_CCTL_CCTL, /* CTLQUOTEMARK */
741 /* 4 -126 */ CCTL_CCTL_CCTL_CCTL,
742 /* 5 -125 */ CCTL_CCTL_CCTL_CCTL,
743 /* 6 -124 */ CCTL_CCTL_CCTL_CCTL,
744 /* 7 -123 */ CCTL_CCTL_CCTL_CCTL,
745 /* 8 -122 */ CCTL_CCTL_CCTL_CCTL,
746 /* 9 -121 */ CCTL_CCTL_CCTL_CCTL,
747 /* 10 -120 */ CCTL_CCTL_CCTL_CCTL, /* CTLESC */
748 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
749 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
750 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
751 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
752 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
753 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
754 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
755 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
756 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
757 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
758 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
759 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
760 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
761 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
762 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
763 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
764 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
765 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
766 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
767 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
768 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
769 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
770 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
771 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
772 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
773 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
774 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
775 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
776 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
777 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
778 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
779 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
780 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
781 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
782 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
783 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
784 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
785 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
786 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
787 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
788 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
789 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
790 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
791 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
792 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
793 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
794 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
795 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
796 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
797 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
798 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
799 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
800 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
801 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
802 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
803 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
804 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
805 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
806 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
807 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
808 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
809 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
810 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
811 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
812 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
813 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
814 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
815 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
816 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
817 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
818 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
819 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
820 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
821 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
822 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
823 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
824 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
825 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
826 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
827 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
828 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
829 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
830 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
831 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
832 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
833 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
834 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
835 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
836 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
837 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
838 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
839 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
840 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
841 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
842 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
843 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
844 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
845 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
846 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
847 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
848 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
849 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
850 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
851 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
852 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
853 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
854 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
855 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
856 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
857 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
858 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
859 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
860 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
861 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
862 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
863 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
864 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
865 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
866 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
867 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
868 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
869 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
870 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
871 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
872 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
873 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
874 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
875 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
876 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
877 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
878 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
879 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
880 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
881 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
882 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
883 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
884 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
885 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
886 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
887 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
888 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
889 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
890 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
891 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
892 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
893 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
894 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
895 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
896 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
897 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
898 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
899 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
900 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
901 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CDQUOTE,
902 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
903 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
904 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
905 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
906 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CSQUOTE,
907 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
908 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
909 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
910 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
911 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
912 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
913 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
914 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
915 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
916 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
917 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
918 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
919 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
920 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
921 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
922 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
923 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
924 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
925 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
926 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
927 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
928 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
929 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
930 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
931 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
932 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
933 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
934 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
935 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
936 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
937 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
938 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
939 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
940 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
941 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
942 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
943 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
944 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
945 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
946 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
947 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
948 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
949 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
950 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
951 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
952 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
953 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
954 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
955 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
956 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
957 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
958 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
959 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
960 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
961 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
962 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
963 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
964 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
965 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
966 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
967 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
968 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
969 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
970 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
971 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
972 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
973 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
974 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
975 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
976 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
977 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
978 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
979 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
980 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
981 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
982 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
983 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
984 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
985 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
986 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
987 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
988 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
989 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
990 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
991 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
992 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
993 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
994 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
Eric Andersen2870d962001-07-02 17:27:21 +0000995};
996
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000997#endif /* USE_SIT_FUNCTION */
Eric Andersen2870d962001-07-02 17:27:21 +0000998
Eric Andersen2870d962001-07-02 17:27:21 +0000999
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001000/* first char is indicating which tokens mark the end of a list */
1001static const char *const tokname_array[] = {
1002 "\1end of file",
1003 "\0newline",
1004 "\0redirection",
1005 "\0word",
1006 "\0assignment",
1007 "\0;",
1008 "\0&",
1009 "\0&&",
1010 "\0||",
1011 "\0|",
1012 "\0(",
1013 "\1)",
1014 "\1;;",
1015 "\1`",
Eric Andersen2870d962001-07-02 17:27:21 +00001016#define KWDOFFSET 14
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001017 /* the following are keywords */
1018 "\0!",
1019 "\0case",
1020 "\1do",
1021 "\1done",
1022 "\1elif",
1023 "\1else",
1024 "\1esac",
1025 "\1fi",
1026 "\0for",
1027 "\0if",
1028 "\0in",
1029 "\1then",
1030 "\0until",
1031 "\0while",
1032 "\0{",
1033 "\1}",
Eric Andersen2870d962001-07-02 17:27:21 +00001034};
1035
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001036static const char *tokname(int tok)
1037{
1038 static char buf[16];
1039
1040 if(tok>=TSEMI)
1041 buf[0] = '"';
1042 sprintf(buf+(tok>=TSEMI), "%s%c",
1043 tokname_array[tok]+1, (tok>=TSEMI ? '"' : 0));
1044 return buf;
1045}
Eric Andersen2870d962001-07-02 17:27:21 +00001046
1047static int plinno = 1; /* input line number */
1048
1049static int parselleft; /* copy of parsefile->lleft */
1050
1051static struct parsefile basepf; /* top level input file */
1052static char basebuf[BUFSIZ]; /* buffer for top level input file */
1053static struct parsefile *parsefile = &basepf; /* current input file */
1054
1055/*
1056 * NEOF is returned by parsecmd when it encounters an end of file. It
1057 * must be distinct from NULL, so we use the address of a variable that
1058 * happens to be handy.
1059 */
1060
1061static int tokpushback; /* last token pushed back */
1062#define NEOF ((union node *)&tokpushback)
1063static int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */
1064
1065
1066static void error (const char *, ...) __attribute__((__noreturn__));
1067static void exerror (int, const char *, ...) __attribute__((__noreturn__));
1068static void shellexec (char **, char **, const char *, int)
1069 __attribute__((noreturn));
1070static void exitshell (int) __attribute__((noreturn));
1071
1072static int goodname(const char *);
1073static void ignoresig (int);
1074static void onsig (int);
1075static void dotrap (void);
1076static int decode_signal (const char *, int);
1077
1078static void shprocvar(void);
1079static void deletefuncs(void);
1080static void setparam (char **);
1081static void freeparam (volatile struct shparam *);
1082
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001083static void find_command (const char *, struct cmdentry *, int, const char *);
1084
1085static inline void hashcd (void);
1086
Eric Andersen2870d962001-07-02 17:27:21 +00001087/* reasons for skipping commands (see comment on breakcmd routine) */
1088#define SKIPBREAK 1
1089#define SKIPCONT 2
1090#define SKIPFUNC 3
1091#define SKIPFILE 4
1092
1093/* values of cmdtype */
1094#define CMDUNKNOWN -1 /* no entry in table for command */
1095#define CMDNORMAL 0 /* command is an executable program */
1096#define CMDBUILTIN 1 /* command is a shell builtin */
1097#define CMDFUNCTION 2 /* command is a shell function */
1098
1099#define DO_ERR 1 /* find_command prints errors */
1100#define DO_ABS 2 /* find_command checks absolute paths */
1101#define DO_NOFUN 4 /* find_command ignores functions */
1102#define DO_BRUTE 8 /* find_command ignores hash table */
1103
1104/*
1105 * Shell variables.
1106 */
1107
1108/* flags */
1109#define VEXPORT 0x01 /* variable is exported */
1110#define VREADONLY 0x02 /* variable cannot be modified */
1111#define VSTRFIXED 0x04 /* variable struct is staticly allocated */
1112#define VTEXTFIXED 0x08 /* text is staticly allocated */
1113#define VSTACK 0x10 /* text is allocated on the stack */
1114#define VUNSET 0x20 /* the variable is not set */
1115#define VNOFUNC 0x40 /* don't call the callback function */
1116
1117
1118struct var {
1119 struct var *next; /* next entry in hash list */
1120 int flags; /* flags are defined above */
1121 char *text; /* name=value */
1122 void (*func) (const char *);
1123 /* function to be called when */
1124 /* the variable gets set/unset */
1125};
1126
1127struct localvar {
1128 struct localvar *next; /* next local variable in list */
1129 struct var *vp; /* the variable that was made local */
1130 int flags; /* saved flags */
1131 char *text; /* saved text */
1132};
1133
1134
Eric Andersen62483552001-07-10 06:09:16 +00001135#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00001136#define rmescapes(p) _rmescapes((p), 0)
1137static char *_rmescapes (char *, int);
1138#else
1139static void rmescapes (char *);
1140#endif
1141
1142static int casematch (union node *, const char *);
1143static void clearredir(void);
1144static void popstring(void);
1145static void readcmdfile (const char *);
1146
1147static int number (const char *);
1148static int is_number (const char *, int *num);
1149static char *single_quote (const char *);
1150static int nextopt (const char *);
1151
1152static void redirect (union node *, int);
1153static void popredir (void);
1154static int dup_as_newfd (int, int);
1155
1156static void changepath(const char *newval);
1157static void getoptsreset(const char *value);
1158
1159
1160static int parsenleft; /* copy of parsefile->nleft */
1161static char *parsenextc; /* copy of parsefile->nextc */
1162static int rootpid; /* pid of main shell */
1163static int rootshell; /* true if we aren't a child of the main shell */
1164
1165static const char spcstr[] = " ";
1166static const char snlfmt[] = "%s\n";
1167
1168static int sstrnleft;
1169static int herefd = -1;
1170
1171static struct localvar *localvars;
1172
1173static struct var vifs;
1174static struct var vmail;
1175static struct var vmpath;
1176static struct var vpath;
1177static struct var vps1;
1178static struct var vps2;
1179static struct var voptind;
Eric Andersenbdfd0d72001-10-24 05:00:29 +00001180#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00001181static struct var vlc_all;
1182static struct var vlc_ctype;
1183#endif
1184
1185struct varinit {
1186 struct var *var;
1187 int flags;
1188 const char *text;
1189 void (*func) (const char *);
1190};
1191
1192static const char defpathvar[] =
1193 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
1194#define defpath (defpathvar + 5)
1195
1196#ifdef IFS_BROKEN
1197static const char defifsvar[] = "IFS= \t\n";
1198#define defifs (defifsvar + 4)
1199#else
1200static const char defifs[] = " \t\n";
1201#endif
1202
1203static const struct varinit varinit[] = {
1204#ifdef IFS_BROKEN
1205 { &vifs, VSTRFIXED|VTEXTFIXED, defifsvar,
1206#else
1207 { &vifs, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS=",
1208#endif
1209 NULL },
1210 { &vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=",
1211 NULL },
1212 { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=",
1213 NULL },
1214 { &vpath, VSTRFIXED|VTEXTFIXED, defpathvar,
1215 changepath },
Tim Riker497a8852002-04-13 05:37:10 +00001216#if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1217 { &vps1, VSTRFIXED|VTEXTFIXED, "PS1=\\w \\$ ",
1218 NULL },
1219#endif /* else vps1 depends on uid */
Eric Andersen2870d962001-07-02 17:27:21 +00001220 { &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ",
1221 NULL },
1222 { &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1",
1223 getoptsreset },
Eric Andersenbdfd0d72001-10-24 05:00:29 +00001224#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00001225 { &vlc_all, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL=",
1226 change_lc_all },
1227 { &vlc_ctype, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE=",
1228 change_lc_ctype },
1229#endif
1230 { NULL, 0, NULL,
1231 NULL }
1232};
1233
1234#define VTABSIZE 39
1235
1236static struct var *vartab[VTABSIZE];
1237
1238/*
1239 * The following macros access the values of the above variables.
1240 * They have to skip over the name. They return the null string
1241 * for unset variables.
1242 */
1243
1244#define ifsval() (vifs.text + 4)
1245#define ifsset() ((vifs.flags & VUNSET) == 0)
1246#define mailval() (vmail.text + 5)
1247#define mpathval() (vmpath.text + 9)
1248#define pathval() (vpath.text + 5)
1249#define ps1val() (vps1.text + 4)
1250#define ps2val() (vps2.text + 4)
1251#define optindval() (voptind.text + 7)
1252
1253#define mpathset() ((vmpath.flags & VUNSET) == 0)
1254
1255static void initvar (void);
1256static void setvar (const char *, const char *, int);
1257static void setvareq (char *, int);
1258static void listsetvar (struct strlist *);
Eric Andersen62483552001-07-10 06:09:16 +00001259static const char *lookupvar (const char *);
1260static const char *bltinlookup (const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001261static char **environment (void);
1262static int showvarscmd (int, char **);
1263static void mklocal (char *);
1264static void poplocalvars (void);
1265static int unsetvar (const char *);
1266static int varequal (const char *, const char *);
1267
1268
1269static char *arg0; /* value of $0 */
1270static struct shparam shellparam; /* current positional parameters */
1271static char **argptr; /* argument list for builtin commands */
1272static char *optionarg; /* set by nextopt (like getopt) */
1273static char *optptr; /* used by nextopt */
1274static char *minusc; /* argument to -c option */
1275
1276
Eric Andersend35c5df2002-01-09 15:37:36 +00001277#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00001278
1279#define ALIASINUSE 1
1280#define ALIASDEAD 2
1281
Eric Andersen3102ac42001-07-06 04:26:23 +00001282#define ATABSIZE 39
1283
Eric Andersen2870d962001-07-02 17:27:21 +00001284struct alias {
1285 struct alias *next;
1286 char *name;
1287 char *val;
1288 int flag;
1289};
1290
1291static struct alias *atab[ATABSIZE];
1292
1293static void setalias (char *, char *);
1294static struct alias **hashalias (const char *);
1295static struct alias *freealias (struct alias *);
1296static struct alias **__lookupalias (const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00001297
1298static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001299setalias(char *name, char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00001300{
1301 struct alias *ap, **app;
1302
1303 app = __lookupalias(name);
1304 ap = *app;
1305 INTOFF;
1306 if (ap) {
1307 if (!(ap->flag & ALIASINUSE)) {
1308 ckfree(ap->val);
1309 }
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001310 ap->val = xstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00001311 ap->flag &= ~ALIASDEAD;
1312 } else {
1313 /* not found */
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001314 ap = xmalloc(sizeof (struct alias));
1315 ap->name = xstrdup(name);
1316 ap->val = xstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00001317 ap->flag = 0;
1318 ap->next = 0;
1319 *app = ap;
1320 }
1321 INTON;
1322}
1323
1324static int
Eric Andersen2870d962001-07-02 17:27:21 +00001325unalias(char *name)
1326{
Eric Andersencb57d552001-06-28 07:25:16 +00001327 struct alias **app;
1328
1329 app = __lookupalias(name);
1330
1331 if (*app) {
1332 INTOFF;
1333 *app = freealias(*app);
1334 INTON;
1335 return (0);
1336 }
1337
1338 return (1);
1339}
1340
Eric Andersencb57d552001-06-28 07:25:16 +00001341static void
Eric Andersen2870d962001-07-02 17:27:21 +00001342rmaliases(void)
1343{
Eric Andersencb57d552001-06-28 07:25:16 +00001344 struct alias *ap, **app;
1345 int i;
1346
1347 INTOFF;
1348 for (i = 0; i < ATABSIZE; i++) {
1349 app = &atab[i];
1350 for (ap = *app; ap; ap = *app) {
1351 *app = freealias(*app);
1352 if (ap == *app) {
1353 app = &ap->next;
1354 }
1355 }
1356 }
1357 INTON;
1358}
1359
Eric Andersen2870d962001-07-02 17:27:21 +00001360static void
1361printalias(const struct alias *ap) {
1362 char *p;
1363
1364 p = single_quote(ap->val);
Eric Andersen62483552001-07-10 06:09:16 +00001365 printf("alias %s=%s\n", ap->name, p);
Eric Andersen2870d962001-07-02 17:27:21 +00001366 stunalloc(p);
1367}
1368
Eric Andersencb57d552001-06-28 07:25:16 +00001369
1370/*
1371 * TODO - sort output
1372 */
1373static int
Eric Andersen2870d962001-07-02 17:27:21 +00001374aliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001375{
1376 char *n, *v;
1377 int ret = 0;
1378 struct alias *ap;
1379
1380 if (argc == 1) {
1381 int i;
1382
1383 for (i = 0; i < ATABSIZE; i++)
1384 for (ap = atab[i]; ap; ap = ap->next) {
1385 printalias(ap);
1386 }
1387 return (0);
1388 }
1389 while ((n = *++argv) != NULL) {
1390 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
1391 if ((ap = *__lookupalias(n)) == NULL) {
Eric Andersen3102ac42001-07-06 04:26:23 +00001392 out2fmt("%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00001393 ret = 1;
1394 } else
1395 printalias(ap);
1396 }
1397 else {
1398 *v++ = '\0';
1399 setalias(n, v);
1400 }
1401 }
1402
1403 return (ret);
1404}
1405
1406static int
Eric Andersen2870d962001-07-02 17:27:21 +00001407unaliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001408{
1409 int i;
1410
1411 while ((i = nextopt("a")) != '\0') {
1412 if (i == 'a') {
1413 rmaliases();
1414 return (0);
1415 }
1416 }
1417 for (i = 0; *argptr; argptr++) {
1418 if (unalias(*argptr)) {
Eric Andersen3102ac42001-07-06 04:26:23 +00001419 out2fmt("%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00001420 i = 1;
1421 }
1422 }
1423
1424 return (i);
1425}
1426
1427static struct alias **
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001428hashalias(const char *p)
1429{
Eric Andersencb57d552001-06-28 07:25:16 +00001430 unsigned int hashval;
1431
1432 hashval = *p << 4;
1433 while (*p)
1434 hashval+= *p++;
1435 return &atab[hashval % ATABSIZE];
1436}
1437
1438static struct alias *
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001439freealias(struct alias *ap)
1440{
Eric Andersencb57d552001-06-28 07:25:16 +00001441 struct alias *next;
1442
1443 if (ap->flag & ALIASINUSE) {
1444 ap->flag |= ALIASDEAD;
1445 return ap;
1446 }
1447
1448 next = ap->next;
1449 ckfree(ap->name);
1450 ckfree(ap->val);
1451 ckfree(ap);
1452 return next;
1453}
1454
Eric Andersencb57d552001-06-28 07:25:16 +00001455
1456static struct alias **
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001457__lookupalias(const char *name)
1458{
Eric Andersencb57d552001-06-28 07:25:16 +00001459 struct alias **app = hashalias(name);
1460
1461 for (; *app; app = &(*app)->next) {
1462 if (equal(name, (*app)->name)) {
1463 break;
1464 }
1465 }
1466
1467 return app;
1468}
Eric Andersen2870d962001-07-02 17:27:21 +00001469#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001470
Eric Andersend35c5df2002-01-09 15:37:36 +00001471#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersen74bcd162001-07-30 21:41:37 +00001472/* The generated file arith.c has been replaced with a custom hand
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001473 * written implementation written by Aaron Lehmann <aaronl@vitelus.com>.
1474 * This is now part of libbb, so that it can be used by all the shells
Eric Andersen74bcd162001-07-30 21:41:37 +00001475 * in busybox. */
Eric Andersen2870d962001-07-02 17:27:21 +00001476static void expari (int);
Eric Andersencb57d552001-06-28 07:25:16 +00001477#endif
1478
Eric Andersen2870d962001-07-02 17:27:21 +00001479static char *trap[NSIG]; /* trap handler commands */
1480static char sigmode[NSIG - 1]; /* current value of signal */
1481static char gotsig[NSIG - 1]; /* indicates specified signal received */
1482static int pendingsigs; /* indicates some signal received */
1483
Eric Andersencb57d552001-06-28 07:25:16 +00001484/*
1485 * This file was generated by the mkbuiltins program.
1486 */
1487
Eric Andersend35c5df2002-01-09 15:37:36 +00001488#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen2870d962001-07-02 17:27:21 +00001489static int bgcmd (int, char **);
1490static int fgcmd (int, char **);
1491static int killcmd (int, char **);
1492#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001493static int bltincmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001494static int cdcmd (int, char **);
1495static int breakcmd (int, char **);
Eric Andersend35c5df2002-01-09 15:37:36 +00001496#ifdef CONFIG_ASH_CMDCMD
Eric Andersen2870d962001-07-02 17:27:21 +00001497static int commandcmd (int, char **);
1498#endif
1499static int dotcmd (int, char **);
1500static int evalcmd (int, char **);
1501static int execcmd (int, char **);
1502static int exitcmd (int, char **);
1503static int exportcmd (int, char **);
1504static int histcmd (int, char **);
1505static int hashcmd (int, char **);
Eric Andersen1c039232001-07-07 00:05:55 +00001506static int helpcmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001507static int jobscmd (int, char **);
1508static int localcmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001509static int pwdcmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001510static int readcmd (int, char **);
1511static int returncmd (int, char **);
1512static int setcmd (int, char **);
1513static int setvarcmd (int, char **);
1514static int shiftcmd (int, char **);
1515static int trapcmd (int, char **);
1516static int umaskcmd (int, char **);
Eric Andersend35c5df2002-01-09 15:37:36 +00001517#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00001518static int aliascmd (int, char **);
1519static int unaliascmd (int, char **);
1520#endif
1521static int unsetcmd (int, char **);
1522static int waitcmd (int, char **);
1523static int ulimitcmd (int, char **);
1524static int timescmd (int, char **);
Eric Andersend35c5df2002-01-09 15:37:36 +00001525#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +00001526static int letcmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001527#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001528static int typecmd (int, char **);
Eric Andersend35c5df2002-01-09 15:37:36 +00001529#ifdef CONFIG_ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00001530static int getoptscmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001531#endif
1532
Eric Andersen69a20f02001-10-31 10:40:37 +00001533#ifndef CONFIG_TRUE
Eric Andersen2870d962001-07-02 17:27:21 +00001534static int true_main (int, char **);
Eric Andersen69a20f02001-10-31 10:40:37 +00001535#endif
1536#ifndef CONFIG_FALSE
Eric Andersen2870d962001-07-02 17:27:21 +00001537static int false_main (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001538#endif
1539
1540static void setpwd (const char *, int);
1541
1542
1543#define BUILTIN_NOSPEC "0"
1544#define BUILTIN_SPECIAL "1"
1545#define BUILTIN_REGULAR "2"
1546#define BUILTIN_ASSIGN "4"
1547#define BUILTIN_SPEC_ASSG "5"
1548#define BUILTIN_REG_ASSG "6"
1549
1550#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1551#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1552#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
1553
1554struct builtincmd {
1555 const char *name;
1556 int (*const builtinfunc) (int, char **);
1557 //unsigned flags;
1558};
1559
Eric Andersencb57d552001-06-28 07:25:16 +00001560
1561/* It is CRUCIAL that this listing be kept in ascii order, otherwise
1562 * the binary search in find_builtin() will stop working. If you value
1563 * your kneecaps, you'll be sure to *make sure* that any changes made
1564 * to this array result in the listing remaining in ascii order. You
1565 * have been warned.
1566 */
1567static const struct builtincmd builtincmds[] = {
Eric Andersen62483552001-07-10 06:09:16 +00001568 { BUILTIN_SPECIAL ".", dotcmd }, /* first, see declare DOTCMD */
Eric Andersen2870d962001-07-02 17:27:21 +00001569 { BUILTIN_SPECIAL ":", true_main },
Eric Andersend35c5df2002-01-09 15:37:36 +00001570#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00001571 { BUILTIN_REG_ASSG "alias", aliascmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001572#endif
Eric Andersend35c5df2002-01-09 15:37:36 +00001573#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen2870d962001-07-02 17:27:21 +00001574 { BUILTIN_REGULAR "bg", bgcmd },
1575#endif
1576 { BUILTIN_SPECIAL "break", breakcmd },
Eric Andersen3102ac42001-07-06 04:26:23 +00001577 { BUILTIN_SPECIAL "builtin", bltincmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001578 { BUILTIN_REGULAR "cd", cdcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001579 { BUILTIN_NOSPEC "chdir", cdcmd },
Eric Andersend35c5df2002-01-09 15:37:36 +00001580#ifdef CONFIG_ASH_CMDCMD
Eric Andersen2870d962001-07-02 17:27:21 +00001581 { BUILTIN_REGULAR "command", commandcmd },
1582#endif
1583 { BUILTIN_SPECIAL "continue", breakcmd },
1584 { BUILTIN_SPECIAL "eval", evalcmd },
1585 { BUILTIN_SPECIAL "exec", execcmd },
1586 { BUILTIN_SPECIAL "exit", exitcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001587 { BUILTIN_SPEC_ASSG "export", exportcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001588 { BUILTIN_REGULAR "false", false_main },
Eric Andersen2870d962001-07-02 17:27:21 +00001589 { BUILTIN_REGULAR "fc", histcmd },
Eric Andersend35c5df2002-01-09 15:37:36 +00001590#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen2870d962001-07-02 17:27:21 +00001591 { BUILTIN_REGULAR "fg", fgcmd },
1592#endif
Eric Andersend35c5df2002-01-09 15:37:36 +00001593#ifdef CONFIG_ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00001594 { BUILTIN_REGULAR "getopts", getoptscmd },
1595#endif
1596 { BUILTIN_NOSPEC "hash", hashcmd },
Eric Andersen1c039232001-07-07 00:05:55 +00001597 { BUILTIN_NOSPEC "help", helpcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001598 { BUILTIN_REGULAR "jobs", jobscmd },
Eric Andersend35c5df2002-01-09 15:37:36 +00001599#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen2870d962001-07-02 17:27:21 +00001600 { BUILTIN_REGULAR "kill", killcmd },
1601#endif
Eric Andersend35c5df2002-01-09 15:37:36 +00001602#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +00001603 { BUILTIN_REGULAR "let", letcmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001604#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001605 { BUILTIN_ASSIGN "local", localcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001606 { BUILTIN_NOSPEC "pwd", pwdcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001607 { BUILTIN_REGULAR "read", readcmd },
1608 { BUILTIN_SPEC_ASSG "readonly", exportcmd },
1609 { BUILTIN_SPECIAL "return", returncmd },
1610 { BUILTIN_SPECIAL "set", setcmd },
1611 { BUILTIN_NOSPEC "setvar", setvarcmd },
1612 { BUILTIN_SPECIAL "shift", shiftcmd },
1613 { BUILTIN_SPECIAL "times", timescmd },
1614 { BUILTIN_SPECIAL "trap", trapcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001615 { BUILTIN_REGULAR "true", true_main },
Eric Andersen2870d962001-07-02 17:27:21 +00001616 { BUILTIN_NOSPEC "type", typecmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001617 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1618 { BUILTIN_REGULAR "umask", umaskcmd },
Eric Andersend35c5df2002-01-09 15:37:36 +00001619#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00001620 { BUILTIN_REGULAR "unalias", unaliascmd },
1621#endif
1622 { BUILTIN_SPECIAL "unset", unsetcmd },
1623 { BUILTIN_REGULAR "wait", waitcmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001624};
1625#define NUMBUILTINS (sizeof (builtincmds) / sizeof (struct builtincmd) )
1626
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001627#define DOTCMD &builtincmds[0]
Eric Andersen2870d962001-07-02 17:27:21 +00001628static struct builtincmd *BLTINCMD;
1629static struct builtincmd *EXECCMD;
1630static struct builtincmd *EVALCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00001631
Eric Andersen2870d962001-07-02 17:27:21 +00001632/* states */
Eric Andersend35c5df2002-01-09 15:37:36 +00001633#define CONFIG_ASH_JOB_CONTROLTOPPED 1 /* all procs are stopped */
Eric Andersen2870d962001-07-02 17:27:21 +00001634#define JOBDONE 2 /* all procs are completed */
Eric Andersencb57d552001-06-28 07:25:16 +00001635
Eric Andersen2870d962001-07-02 17:27:21 +00001636/*
1637 * A job structure contains information about a job. A job is either a
1638 * single process or a set of processes contained in a pipeline. In the
1639 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1640 * array of pids.
1641 */
Eric Andersencb57d552001-06-28 07:25:16 +00001642
Eric Andersen2870d962001-07-02 17:27:21 +00001643struct procstat {
1644 pid_t pid; /* process id */
1645 int status; /* status flags (defined above) */
1646 char *cmd; /* text of command being run */
1647};
Eric Andersencb57d552001-06-28 07:25:16 +00001648
Eric Andersen2870d962001-07-02 17:27:21 +00001649
1650static int job_warning; /* user was warned about stopped jobs */
1651
Eric Andersend35c5df2002-01-09 15:37:36 +00001652#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen2870d962001-07-02 17:27:21 +00001653static void setjobctl(int enable);
1654#else
1655#define setjobctl(on) /* do nothing */
Eric Andersencb57d552001-06-28 07:25:16 +00001656#endif
1657
Eric Andersen2870d962001-07-02 17:27:21 +00001658
1659struct job {
1660 struct procstat ps0; /* status of process */
1661 struct procstat *ps; /* status or processes when more than one */
1662 short nprocs; /* number of processes */
1663 short pgrp; /* process group of this job */
1664 char state; /* true if job is finished */
1665 char used; /* true if this entry is in used */
1666 char changed; /* true if status has changed */
Eric Andersend35c5df2002-01-09 15:37:36 +00001667#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen2870d962001-07-02 17:27:21 +00001668 char jobctl; /* job running under job control */
1669#endif
1670};
1671
1672static struct job *jobtab; /* array of jobs */
1673static int njobs; /* size of array */
1674static int backgndpid = -1; /* pid of last background process */
Eric Andersend35c5df2002-01-09 15:37:36 +00001675#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen2870d962001-07-02 17:27:21 +00001676static int initialpgrp; /* pgrp of shell on invocation */
1677static int curjob; /* current job */
1678static int jobctl;
1679#endif
1680static int intreceived;
1681
Eric Andersen62483552001-07-10 06:09:16 +00001682static struct job *makejob (const union node *, int);
1683static int forkshell (struct job *, const union node *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00001684static int waitforjob (struct job *);
1685
1686static int docd (char *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00001687static void getpwd (void);
1688
1689static char *padvance (const char **, const char *);
1690
1691static char nullstr[1]; /* zero length string */
1692static char *curdir = nullstr; /* current working directory */
Eric Andersen2870d962001-07-02 17:27:21 +00001693
Eric Andersencb57d552001-06-28 07:25:16 +00001694static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001695cdcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001696{
1697 const char *dest;
1698 const char *path;
1699 char *p;
1700 struct stat statb;
1701 int print = 0;
1702
1703 nextopt(nullstr);
1704 if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME")) == NULL)
1705 error("HOME not set");
1706 if (*dest == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00001707 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001708 if (dest[0] == '-' && dest[1] == '\0') {
1709 dest = bltinlookup("OLDPWD");
1710 if (!dest || !*dest) {
1711 dest = curdir;
1712 }
1713 print = 1;
1714 if (dest)
Eric Andersen2870d962001-07-02 17:27:21 +00001715 print = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00001716 else
Eric Andersen2870d962001-07-02 17:27:21 +00001717 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001718 }
1719 if (*dest == '/' || (path = bltinlookup("CDPATH")) == NULL)
1720 path = nullstr;
1721 while ((p = padvance(&path, dest)) != NULL) {
1722 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
1723 if (!print) {
1724 /*
1725 * XXX - rethink
1726 */
1727 if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
1728 p += 2;
1729 print = strcmp(p, dest);
1730 }
1731 if (docd(p, print) >= 0)
1732 return 0;
1733
1734 }
1735 }
1736 error("can't cd to %s", dest);
1737 /* NOTREACHED */
1738}
1739
1740
1741/*
1742 * Actually do the chdir. In an interactive shell, print the
1743 * directory name if "print" is nonzero.
1744 */
1745
1746static int
Eric Andersena3483db2001-10-24 08:01:06 +00001747docd(char *dest, int print)
Eric Andersencb57d552001-06-28 07:25:16 +00001748{
Eric Andersencb57d552001-06-28 07:25:16 +00001749 TRACE(("docd(\"%s\", %d) called\n", dest, print));
Eric Andersencb57d552001-06-28 07:25:16 +00001750 INTOFF;
1751 if (chdir(dest) < 0) {
1752 INTON;
1753 return -1;
1754 }
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001755 hashcd();
1756 /*
1757 * Update curdir (the name of the current directory) in response to a
1758 * cd command. We also call hashcd to let the routines in exec.c know
1759 * that the current directory has changed.
1760 */
1761 /* If dest is NULL, we don't know the current directory */
1762 if (dest == NULL || curdir == nullstr)
1763 setpwd(0, 1);
1764 else
1765 setpwd(dest, 1);
1766
Eric Andersencb57d552001-06-28 07:25:16 +00001767 INTON;
1768 if (print && iflag)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001769 puts(curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00001770 return 0;
1771}
1772
1773
Eric Andersencb57d552001-06-28 07:25:16 +00001774static int
Eric Andersena3483db2001-10-24 08:01:06 +00001775pwdcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001776{
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001777 puts(curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00001778 return 0;
1779}
Eric Andersencb57d552001-06-28 07:25:16 +00001780
Eric Andersena3483db2001-10-24 08:01:06 +00001781/* Ask system the current directory */
Eric Andersencb57d552001-06-28 07:25:16 +00001782static void
Eric Andersen2870d962001-07-02 17:27:21 +00001783getpwd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00001784{
Eric Andersen2870d962001-07-02 17:27:21 +00001785 curdir = xgetcwd(0);
1786 if(curdir==0)
1787 curdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00001788}
1789
1790static void
1791setpwd(const char *val, int setold)
1792{
Eric Andersena3483db2001-10-24 08:01:06 +00001793 char *cated = NULL;
1794
Eric Andersencb57d552001-06-28 07:25:16 +00001795 if (setold) {
1796 setvar("OLDPWD", curdir, VEXPORT);
1797 }
1798 INTOFF;
1799 if (curdir != nullstr) {
Eric Andersena3483db2001-10-24 08:01:06 +00001800 if(val!=NULL && *val != '/')
1801 val = cated = concat_path_file(curdir, val);
Eric Andersencb57d552001-06-28 07:25:16 +00001802 free(curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00001803 }
Eric Andersena3483db2001-10-24 08:01:06 +00001804 if (!val)
Eric Andersencb57d552001-06-28 07:25:16 +00001805 getpwd();
Eric Andersena3483db2001-10-24 08:01:06 +00001806 else
1807 curdir = simplify_path(val);
1808 free(cated);
Eric Andersencb57d552001-06-28 07:25:16 +00001809 INTON;
1810 setvar("PWD", curdir, VEXPORT);
1811}
1812
Eric Andersencb57d552001-06-28 07:25:16 +00001813/*
1814 * Errors and exceptions.
1815 */
1816
1817/*
1818 * Code to handle exceptions in C.
1819 */
1820
Eric Andersen2870d962001-07-02 17:27:21 +00001821/*
1822 * We enclose jmp_buf in a structure so that we can declare pointers to
1823 * jump locations. The global variable handler contains the location to
1824 * jump to when an exception occurs, and the global variable exception
1825 * contains a code identifying the exeception. To implement nested
1826 * exception handlers, the user should save the value of handler on entry
1827 * to an inner scope, set handler to point to a jmploc structure for the
1828 * inner scope, and restore handler on exit from the scope.
1829 */
1830
1831struct jmploc {
1832 jmp_buf loc;
1833};
1834
1835/* exceptions */
1836#define EXINT 0 /* SIGINT received */
1837#define EXERROR 1 /* a generic error */
1838#define EXSHELLPROC 2 /* execute a shell procedure */
1839#define EXEXEC 3 /* command execution failed */
1840
1841static struct jmploc *handler;
Eric Andersencb57d552001-06-28 07:25:16 +00001842static int exception;
Eric Andersencb57d552001-06-28 07:25:16 +00001843
Eric Andersen2870d962001-07-02 17:27:21 +00001844static void exverror (int, const char *, va_list)
Eric Andersencb57d552001-06-28 07:25:16 +00001845 __attribute__((__noreturn__));
1846
1847/*
1848 * Called to raise an exception. Since C doesn't include exceptions, we
1849 * just do a longjmp to the exception handler. The type of exception is
1850 * stored in the global variable "exception".
1851 */
1852
Eric Andersen2870d962001-07-02 17:27:21 +00001853static void exraise (int) __attribute__((__noreturn__));
1854
Eric Andersencb57d552001-06-28 07:25:16 +00001855static void
Eric Andersen2870d962001-07-02 17:27:21 +00001856exraise(int e)
Eric Andersencb57d552001-06-28 07:25:16 +00001857{
1858#ifdef DEBUG
1859 if (handler == NULL)
1860 abort();
1861#endif
Eric Andersen62483552001-07-10 06:09:16 +00001862 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00001863 exception = e;
1864 longjmp(handler->loc, 1);
1865}
1866
1867
1868/*
1869 * Called from trap.c when a SIGINT is received. (If the user specifies
1870 * that SIGINT is to be trapped or ignored using the trap builtin, then
1871 * this routine is not called.) Suppressint is nonzero when interrupts
1872 * are held using the INTOFF macro. The call to _exit is necessary because
1873 * there is a short period after a fork before the signal handlers are
1874 * set to the appropriate value for the child. (The test for iflag is
1875 * just defensive programming.)
1876 */
1877
1878static void
Eric Andersen2870d962001-07-02 17:27:21 +00001879onint(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00001880 sigset_t mysigset;
1881
1882 if (suppressint) {
1883 intpending++;
1884 return;
1885 }
1886 intpending = 0;
1887 sigemptyset(&mysigset);
1888 sigprocmask(SIG_SETMASK, &mysigset, NULL);
1889 if (rootshell && iflag)
1890 exraise(EXINT);
1891 else {
1892 signal(SIGINT, SIG_DFL);
1893 raise(SIGINT);
1894 }
1895 /* NOTREACHED */
1896}
1897
1898
Eric Andersen2870d962001-07-02 17:27:21 +00001899static char *commandname; /* currently executing command */
1900
Eric Andersencb57d552001-06-28 07:25:16 +00001901/*
1902 * Exverror is called to raise the error exception. If the first argument
1903 * is not NULL then error prints an error message using printf style
1904 * formatting. It then raises the error exception.
1905 */
1906static void
Eric Andersen2870d962001-07-02 17:27:21 +00001907exverror(int cond, const char *msg, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00001908{
1909 CLEAR_PENDING_INT;
1910 INTOFF;
1911
1912#ifdef DEBUG
1913 if (msg)
1914 TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
1915 else
1916 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
1917#endif
1918 if (msg) {
1919 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +00001920 out2fmt("%s: ", commandname);
1921 vfprintf(stderr, msg, ap);
1922 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00001923 }
Eric Andersencb57d552001-06-28 07:25:16 +00001924 exraise(cond);
1925 /* NOTREACHED */
1926}
1927
1928
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001929static void
Eric Andersencb57d552001-06-28 07:25:16 +00001930error(const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00001931{
Eric Andersencb57d552001-06-28 07:25:16 +00001932 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00001933 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00001934 exverror(EXERROR, msg, ap);
1935 /* NOTREACHED */
1936 va_end(ap);
1937}
1938
1939
Eric Andersencb57d552001-06-28 07:25:16 +00001940static void
1941exerror(int cond, const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00001942{
Eric Andersencb57d552001-06-28 07:25:16 +00001943 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00001944 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00001945 exverror(cond, msg, ap);
1946 /* NOTREACHED */
1947 va_end(ap);
1948}
1949
1950
1951
1952/*
1953 * Table of error messages.
1954 */
1955
1956struct errname {
Eric Andersen2870d962001-07-02 17:27:21 +00001957 short errcode; /* error number */
Aaron Lehmann43880332001-12-31 06:16:54 +00001958 short action; /* operation which encountered the error */
Eric Andersencb57d552001-06-28 07:25:16 +00001959};
1960
Eric Andersen2870d962001-07-02 17:27:21 +00001961/*
1962 * Types of operations (passed to the errmsg routine).
1963 */
1964
1965#define E_OPEN 01 /* opening a file */
1966#define E_CREAT 02 /* creating a file */
1967#define E_EXEC 04 /* executing a program */
Eric Andersencb57d552001-06-28 07:25:16 +00001968
1969#define ALL (E_OPEN|E_CREAT|E_EXEC)
1970
1971static const struct errname errormsg[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00001972 { EINTR, ALL },
1973 { EACCES, ALL },
1974 { EIO, ALL },
1975 { ENOENT, E_OPEN },
1976 { ENOENT, E_CREAT },
1977 { ENOENT, E_EXEC },
1978 { ENOTDIR, E_OPEN },
1979 { ENOTDIR, E_CREAT },
1980 { ENOTDIR, E_EXEC },
1981 { EISDIR, ALL },
1982 { EEXIST, E_CREAT },
1983#ifdef EMFILE
1984 { EMFILE, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00001985#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001986 { ENFILE, ALL },
1987 { ENOSPC, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00001988#ifdef EDQUOT
Eric Andersen2870d962001-07-02 17:27:21 +00001989 { EDQUOT, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00001990#endif
1991#ifdef ENOSR
Eric Andersen2870d962001-07-02 17:27:21 +00001992 { ENOSR, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00001993#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001994 { ENXIO, ALL },
1995 { EROFS, ALL },
1996 { ETXTBSY, ALL },
1997#ifdef EAGAIN
1998 { EAGAIN, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00001999#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002000 { ENOMEM, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002001#ifdef ENOLINK
Eric Andersen2870d962001-07-02 17:27:21 +00002002 { ENOLINK, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002003#endif
2004#ifdef EMULTIHOP
Eric Andersen2870d962001-07-02 17:27:21 +00002005 { EMULTIHOP, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002006#endif
2007#ifdef ECOMM
Eric Andersen2870d962001-07-02 17:27:21 +00002008 { ECOMM, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002009#endif
2010#ifdef ESTALE
Eric Andersen2870d962001-07-02 17:27:21 +00002011 { ESTALE, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002012#endif
2013#ifdef ETIMEDOUT
Eric Andersen2870d962001-07-02 17:27:21 +00002014 { ETIMEDOUT, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002015#endif
2016#ifdef ELOOP
Eric Andersen2870d962001-07-02 17:27:21 +00002017 { ELOOP, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002018#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002019 { E2BIG, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002020#ifdef ELIBACC
Eric Andersen2870d962001-07-02 17:27:21 +00002021 { ELIBACC, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002022#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002023};
2024
Eric Andersen2870d962001-07-02 17:27:21 +00002025#define ERRNAME_SIZE (sizeof(errormsg)/sizeof(struct errname))
Eric Andersencb57d552001-06-28 07:25:16 +00002026
2027/*
2028 * Return a string describing an error. The returned string may be a
2029 * pointer to a static buffer that will be overwritten on the next call.
2030 * Action describes the operation that got the error.
2031 */
2032
2033static const char *
Eric Andersen2870d962001-07-02 17:27:21 +00002034errmsg(int e, int action)
Eric Andersencb57d552001-06-28 07:25:16 +00002035{
2036 struct errname const *ep;
2037 static char buf[12];
2038
Eric Andersen2870d962001-07-02 17:27:21 +00002039 for (ep = errormsg ; ep < errormsg+ERRNAME_SIZE; ep++) {
Eric Andersencb57d552001-06-28 07:25:16 +00002040 if (ep->errcode == e && (ep->action & action) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00002041 return strerror(e);
Eric Andersencb57d552001-06-28 07:25:16 +00002042 }
Eric Andersen2870d962001-07-02 17:27:21 +00002043
Eric Andersen3102ac42001-07-06 04:26:23 +00002044 snprintf(buf, sizeof buf, "error %d", e);
Eric Andersencb57d552001-06-28 07:25:16 +00002045 return buf;
2046}
2047
2048
Eric Andersend35c5df2002-01-09 15:37:36 +00002049#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Eric Andersencb57d552001-06-28 07:25:16 +00002050static void
2051__inton() {
2052 if (--suppressint == 0 && intpending) {
2053 onint();
2054 }
2055}
Eric Andersen3102ac42001-07-06 04:26:23 +00002056static void forceinton (void) {
2057 suppressint = 0;
2058 if (intpending)
2059 onint();
2060}
Eric Andersencb57d552001-06-28 07:25:16 +00002061#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002062
2063/* flags in argument to evaltree */
Eric Andersen2870d962001-07-02 17:27:21 +00002064#define EV_EXIT 01 /* exit after evaluating tree */
2065#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2066#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00002067
Eric Andersen2870d962001-07-02 17:27:21 +00002068static int evalskip; /* set if we are skipping commands */
2069static int skipcount; /* number of levels to skip */
2070static int loopnest; /* current loop nesting level */
2071static int funcnest; /* depth of function calls */
Eric Andersencb57d552001-06-28 07:25:16 +00002072
2073
Eric Andersen2870d962001-07-02 17:27:21 +00002074static struct strlist *cmdenviron; /* environment for builtin command */
2075static int exitstatus; /* exit status of last command */
2076static int oexitstatus; /* saved exit status */
Eric Andersencb57d552001-06-28 07:25:16 +00002077
Eric Andersen62483552001-07-10 06:09:16 +00002078static void evalsubshell (const union node *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00002079static void expredir (union node *);
Eric Andersen2870d962001-07-02 17:27:21 +00002080static void eprintlist (struct strlist *);
Eric Andersencb57d552001-06-28 07:25:16 +00002081
Eric Andersen2870d962001-07-02 17:27:21 +00002082static union node *parsecmd(int);
Eric Andersencb57d552001-06-28 07:25:16 +00002083/*
2084 * Called to reset things after an exception.
2085 */
2086
Eric Andersencb57d552001-06-28 07:25:16 +00002087/*
2088 * The eval commmand.
2089 */
Eric Andersen2870d962001-07-02 17:27:21 +00002090static void evalstring (char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00002091
2092static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00002093evalcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002094{
Eric Andersen2870d962001-07-02 17:27:21 +00002095 char *p;
2096 char *concat;
2097 char **ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002098
Eric Andersen2870d962001-07-02 17:27:21 +00002099 if (argc > 1) {
2100 p = argv[1];
2101 if (argc > 2) {
2102 STARTSTACKSTR(concat);
2103 ap = argv + 2;
2104 for (;;) {
2105 while (*p)
2106 STPUTC(*p++, concat);
2107 if ((p = *ap++) == NULL)
2108 break;
2109 STPUTC(' ', concat);
2110 }
2111 STPUTC('\0', concat);
2112 p = grabstackstr(concat);
2113 }
2114 evalstring(p, EV_TESTED);
2115 }
2116 return exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002117}
2118
Eric Andersencb57d552001-06-28 07:25:16 +00002119/*
2120 * Execute a command or commands contained in a string.
2121 */
2122
Eric Andersen2870d962001-07-02 17:27:21 +00002123static void evaltree (union node *, int);
2124static void setinputstring (char *);
2125static void popfile (void);
2126static void setstackmark(struct stackmark *mark);
2127static void popstackmark(struct stackmark *mark);
2128
2129
Eric Andersencb57d552001-06-28 07:25:16 +00002130static void
Eric Andersen2870d962001-07-02 17:27:21 +00002131evalstring(char *s, int flag)
2132{
Eric Andersencb57d552001-06-28 07:25:16 +00002133 union node *n;
2134 struct stackmark smark;
2135
2136 setstackmark(&smark);
2137 setinputstring(s);
2138 while ((n = parsecmd(0)) != NEOF) {
2139 evaltree(n, flag);
2140 popstackmark(&smark);
2141 }
2142 popfile();
2143 popstackmark(&smark);
2144}
2145
Eric Andersen2870d962001-07-02 17:27:21 +00002146static struct builtincmd *find_builtin (const char *);
Eric Andersen62483552001-07-10 06:09:16 +00002147static void expandarg (union node *, struct arglist *, int);
2148static void calcsize (const union node *);
2149static union node *copynode (const union node *);
2150
2151/*
2152 * Make a copy of a parse tree.
2153 */
2154
2155static int funcblocksize; /* size of structures in function */
2156static int funcstringsize; /* size of strings in node */
2157static pointer funcblock; /* block to allocate function from */
2158static char *funcstring; /* block to allocate strings from */
2159
2160
2161static inline union node *
2162copyfunc(union node *n)
2163{
2164 if (n == NULL)
2165 return NULL;
2166 funcblocksize = 0;
2167 funcstringsize = 0;
2168 calcsize(n);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00002169 funcblock = xmalloc(funcblocksize + funcstringsize);
Eric Andersen62483552001-07-10 06:09:16 +00002170 funcstring = (char *) funcblock + funcblocksize;
2171 return copynode(n);
2172}
2173
2174/*
2175 * Free a parse tree.
2176 */
Eric Andersencb57d552001-06-28 07:25:16 +00002177
2178static void
Eric Andersen62483552001-07-10 06:09:16 +00002179freefunc(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00002180{
Eric Andersen62483552001-07-10 06:09:16 +00002181 if (n)
2182 ckfree(n);
Eric Andersencb57d552001-06-28 07:25:16 +00002183}
2184
2185
Eric Andersen62483552001-07-10 06:09:16 +00002186/*
2187 * Add a new command entry, replacing any existing command entry for
2188 * the same name.
2189 */
2190
2191static inline void
2192addcmdentry(char *name, struct cmdentry *entry)
2193{
2194 struct tblentry *cmdp;
2195
2196 INTOFF;
2197 cmdp = cmdlookup(name, 1);
2198 if (cmdp->cmdtype == CMDFUNCTION) {
2199 freefunc(cmdp->param.func);
2200 }
2201 cmdp->cmdtype = entry->cmdtype;
2202 cmdp->param = entry->u;
2203 INTON;
2204}
2205
2206static inline void
2207evalloop(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002208{
2209 int status;
2210
2211 loopnest++;
2212 status = 0;
2213 for (;;) {
2214 evaltree(n->nbinary.ch1, EV_TESTED);
2215 if (evalskip) {
Eric Andersen2870d962001-07-02 17:27:21 +00002216skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002217 evalskip = 0;
2218 continue;
2219 }
2220 if (evalskip == SKIPBREAK && --skipcount <= 0)
2221 evalskip = 0;
2222 break;
2223 }
2224 if (n->type == NWHILE) {
2225 if (exitstatus != 0)
2226 break;
2227 } else {
2228 if (exitstatus == 0)
2229 break;
2230 }
2231 evaltree(n->nbinary.ch2, flags & EV_TESTED);
2232 status = exitstatus;
2233 if (evalskip)
2234 goto skipping;
2235 }
2236 loopnest--;
2237 exitstatus = status;
2238}
2239
Eric Andersencb57d552001-06-28 07:25:16 +00002240static void
Eric Andersen62483552001-07-10 06:09:16 +00002241evalfor(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002242{
2243 struct arglist arglist;
2244 union node *argp;
2245 struct strlist *sp;
2246 struct stackmark smark;
2247
2248 setstackmark(&smark);
2249 arglist.lastp = &arglist.list;
2250 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2251 oexitstatus = exitstatus;
2252 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2253 if (evalskip)
2254 goto out;
2255 }
2256 *arglist.lastp = NULL;
2257
2258 exitstatus = 0;
2259 loopnest++;
2260 for (sp = arglist.list ; sp ; sp = sp->next) {
2261 setvar(n->nfor.var, sp->text, 0);
2262 evaltree(n->nfor.body, flags & EV_TESTED);
2263 if (evalskip) {
2264 if (evalskip == SKIPCONT && --skipcount <= 0) {
2265 evalskip = 0;
2266 continue;
2267 }
2268 if (evalskip == SKIPBREAK && --skipcount <= 0)
2269 evalskip = 0;
2270 break;
2271 }
2272 }
2273 loopnest--;
2274out:
2275 popstackmark(&smark);
2276}
2277
Eric Andersen62483552001-07-10 06:09:16 +00002278static inline void
2279evalcase(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002280{
2281 union node *cp;
2282 union node *patp;
2283 struct arglist arglist;
2284 struct stackmark smark;
2285
2286 setstackmark(&smark);
2287 arglist.lastp = &arglist.list;
2288 oexitstatus = exitstatus;
2289 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2290 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2291 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2292 if (casematch(patp, arglist.list->text)) {
2293 if (evalskip == 0) {
2294 evaltree(cp->nclist.body, flags);
2295 }
2296 goto out;
2297 }
2298 }
2299 }
2300out:
2301 popstackmark(&smark);
2302}
2303
Eric Andersencb57d552001-06-28 07:25:16 +00002304/*
Eric Andersencb57d552001-06-28 07:25:16 +00002305 * Evaluate a pipeline. All the processes in the pipeline are children
2306 * of the process creating the pipeline. (This differs from some versions
2307 * of the shell, which make the last process in a pipeline the parent
2308 * of all the rest.)
2309 */
2310
Eric Andersen74400cc2001-10-18 04:11:39 +00002311static inline void evalpipe(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00002312{
2313 struct job *jp;
2314 struct nodelist *lp;
2315 int pipelen;
2316 int prevfd;
2317 int pip[2];
2318
2319 TRACE(("evalpipe(0x%lx) called\n", (long)n));
2320 pipelen = 0;
2321 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
2322 pipelen++;
2323 INTOFF;
2324 jp = makejob(n, pipelen);
2325 prevfd = -1;
2326 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00002327 /*
2328 * Search for a command. This is called before we fork so that the
2329 * location of the command will be available in the parent as well as
2330 * the child. The check for "goodname" is an overly conservative
2331 * check that the name will not be subject to expansion.
2332 */
2333
2334 struct cmdentry entry;
2335 union node *lpn = lp->n;
2336 if (lpn->type == NCMD && lpn->ncmd.args && goodname(lpn->ncmd.args->narg.text))
2337 find_command(lpn->ncmd.args->narg.text, &entry, 0, pathval());
2338
Eric Andersencb57d552001-06-28 07:25:16 +00002339 pip[1] = -1;
2340 if (lp->next) {
2341 if (pipe(pip) < 0) {
2342 close(prevfd);
2343 error("Pipe call failed");
2344 }
2345 }
2346 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
2347 INTON;
2348 if (prevfd > 0) {
2349 close(0);
2350 dup_as_newfd(prevfd, 0);
2351 close(prevfd);
2352 if (pip[0] == 0) {
2353 pip[0] = -1;
2354 }
2355 }
2356 if (pip[1] >= 0) {
2357 if (pip[0] >= 0) {
2358 close(pip[0]);
2359 }
2360 if (pip[1] != 1) {
2361 close(1);
2362 dup_as_newfd(pip[1], 1);
2363 close(pip[1]);
2364 }
2365 }
2366 evaltree(lp->n, EV_EXIT);
2367 }
2368 if (prevfd >= 0)
2369 close(prevfd);
2370 prevfd = pip[0];
2371 close(pip[1]);
2372 }
2373 INTON;
2374 if (n->npipe.backgnd == 0) {
2375 INTOFF;
2376 exitstatus = waitforjob(jp);
2377 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
2378 INTON;
2379 }
2380}
2381
Eric Andersen2870d962001-07-02 17:27:21 +00002382static int
2383isassignment(const char *word) {
2384 if (!is_name(*word)) {
2385 return 0;
2386 }
2387 do {
2388 word++;
2389 } while (is_in_name(*word));
2390 return *word == '=';
2391}
2392
Eric Andersen62483552001-07-10 06:09:16 +00002393
Eric Andersencb57d552001-06-28 07:25:16 +00002394static void
Eric Andersen3102ac42001-07-06 04:26:23 +00002395evalcommand(union node *cmd, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002396{
2397 struct stackmark smark;
2398 union node *argp;
2399 struct arglist arglist;
2400 struct arglist varlist;
2401 char **argv;
2402 int argc;
2403 char **envp;
2404 struct strlist *sp;
2405 int mode;
Eric Andersencb57d552001-06-28 07:25:16 +00002406 struct cmdentry cmdentry;
2407 struct job *jp;
2408 char *volatile savecmdname;
2409 volatile struct shparam saveparam;
2410 struct localvar *volatile savelocalvars;
2411 volatile int e;
2412 char *lastarg;
2413 const char *path;
2414 const struct builtincmd *firstbltin;
2415 struct jmploc *volatile savehandler;
2416 struct jmploc jmploc;
2417#if __GNUC__
2418 /* Avoid longjmp clobbering */
2419 (void) &argv;
2420 (void) &argc;
2421 (void) &lastarg;
2422 (void) &flags;
2423#endif
2424
2425 /* First expand the arguments. */
2426 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
2427 setstackmark(&smark);
2428 arglist.lastp = &arglist.list;
2429 varlist.lastp = &varlist.list;
2430 arglist.list = 0;
2431 oexitstatus = exitstatus;
2432 exitstatus = 0;
2433 path = pathval();
2434 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
2435 expandarg(argp, &varlist, EXP_VARTILDE);
2436 }
2437 for (
2438 argp = cmd->ncmd.args; argp && !arglist.list;
2439 argp = argp->narg.next
2440 ) {
2441 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2442 }
2443 if (argp) {
2444 struct builtincmd *bcmd;
Eric Andersen62483552001-07-10 06:09:16 +00002445 int pseudovarflag;
Eric Andersencb57d552001-06-28 07:25:16 +00002446 bcmd = find_builtin(arglist.list->text);
Eric Andersen2870d962001-07-02 17:27:21 +00002447 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00002448 for (; argp; argp = argp->narg.next) {
2449 if (pseudovarflag && isassignment(argp->narg.text)) {
2450 expandarg(argp, &arglist, EXP_VARTILDE);
2451 continue;
2452 }
2453 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2454 }
2455 }
2456 *arglist.lastp = NULL;
2457 *varlist.lastp = NULL;
2458 expredir(cmd->ncmd.redirect);
2459 argc = 0;
2460 for (sp = arglist.list ; sp ; sp = sp->next)
2461 argc++;
2462 argv = stalloc(sizeof (char *) * (argc + 1));
2463
2464 for (sp = arglist.list ; sp ; sp = sp->next) {
2465 TRACE(("evalcommand arg: %s\n", sp->text));
2466 *argv++ = sp->text;
2467 }
2468 *argv = NULL;
2469 lastarg = NULL;
2470 if (iflag && funcnest == 0 && argc > 0)
2471 lastarg = argv[-1];
2472 argv -= argc;
2473
2474 /* Print the command if xflag is set. */
2475 if (xflag) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002476 out2c('+');
Eric Andersencb57d552001-06-28 07:25:16 +00002477 eprintlist(varlist.list);
2478 eprintlist(arglist.list);
Eric Andersen3102ac42001-07-06 04:26:23 +00002479 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00002480 }
2481
2482 /* Now locate the command. */
2483 if (argc == 0) {
2484 cmdentry.cmdtype = CMDBUILTIN;
2485 firstbltin = cmdentry.u.cmd = BLTINCMD;
2486 } else {
2487 const char *oldpath;
2488 int findflag = DO_ERR;
2489 int oldfindflag;
2490
2491 /*
2492 * Modify the command lookup path, if a PATH= assignment
2493 * is present
2494 */
2495 for (sp = varlist.list ; sp ; sp = sp->next)
2496 if (varequal(sp->text, defpathvar)) {
2497 path = sp->text + 5;
2498 findflag |= DO_BRUTE;
2499 }
2500 oldpath = path;
2501 oldfindflag = findflag;
2502 firstbltin = 0;
2503 for(;;) {
2504 find_command(argv[0], &cmdentry, findflag, path);
Eric Andersen2870d962001-07-02 17:27:21 +00002505 if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */
Eric Andersencb57d552001-06-28 07:25:16 +00002506 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002507 goto out;
2508 }
2509 /* implement bltin and command here */
2510 if (cmdentry.cmdtype != CMDBUILTIN) {
2511 break;
2512 }
2513 if (!firstbltin) {
2514 firstbltin = cmdentry.u.cmd;
2515 }
2516 if (cmdentry.u.cmd == BLTINCMD) {
2517 for(;;) {
2518 struct builtincmd *bcmd;
2519
2520 argv++;
2521 if (--argc == 0)
2522 goto found;
2523 if (!(bcmd = find_builtin(*argv))) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002524 out2fmt("%s: not found\n", *argv);
Eric Andersencb57d552001-06-28 07:25:16 +00002525 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002526 goto out;
2527 }
2528 cmdentry.u.cmd = bcmd;
2529 if (bcmd != BLTINCMD)
2530 break;
2531 }
2532 }
Eric Andersen2870d962001-07-02 17:27:21 +00002533 if (cmdentry.u.cmd == find_builtin("command")) {
Eric Andersencb57d552001-06-28 07:25:16 +00002534 argv++;
2535 if (--argc == 0) {
2536 goto found;
2537 }
2538 if (*argv[0] == '-') {
2539 if (!equal(argv[0], "-p")) {
2540 argv--;
2541 argc++;
2542 break;
2543 }
2544 argv++;
2545 if (--argc == 0) {
2546 goto found;
2547 }
2548 path = defpath;
2549 findflag |= DO_BRUTE;
2550 } else {
2551 path = oldpath;
2552 findflag = oldfindflag;
2553 }
2554 findflag |= DO_NOFUN;
2555 continue;
2556 }
2557found:
2558 break;
2559 }
2560 }
2561
2562 /* Fork off a child process if necessary. */
2563 if (cmd->ncmd.backgnd
2564 || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00002565 ) {
2566 jp = makejob(cmd, 1);
2567 mode = cmd->ncmd.backgnd;
Eric Andersencb57d552001-06-28 07:25:16 +00002568 if (forkshell(jp, cmd, mode) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00002569 goto parent; /* at end of routine */
Eric Andersencb57d552001-06-28 07:25:16 +00002570 flags |= EV_EXIT;
2571 }
2572
2573 /* This is the child process if a fork occurred. */
2574 /* Execute the command. */
2575 if (cmdentry.cmdtype == CMDFUNCTION) {
2576#ifdef DEBUG
2577 trputs("Shell function: "); trargs(argv);
2578#endif
2579 exitstatus = oexitstatus;
2580 redirect(cmd->ncmd.redirect, REDIR_PUSH);
2581 saveparam = shellparam;
2582 shellparam.malloc = 0;
2583 shellparam.nparam = argc - 1;
2584 shellparam.p = argv + 1;
2585 INTOFF;
2586 savelocalvars = localvars;
2587 localvars = NULL;
2588 INTON;
2589 if (setjmp(jmploc.loc)) {
2590 if (exception == EXSHELLPROC) {
2591 freeparam((volatile struct shparam *)
2592 &saveparam);
2593 } else {
2594 saveparam.optind = shellparam.optind;
2595 saveparam.optoff = shellparam.optoff;
2596 freeparam(&shellparam);
2597 shellparam = saveparam;
2598 }
2599 poplocalvars();
2600 localvars = savelocalvars;
2601 handler = savehandler;
2602 longjmp(handler->loc, 1);
2603 }
2604 savehandler = handler;
2605 handler = &jmploc;
2606 for (sp = varlist.list ; sp ; sp = sp->next)
2607 mklocal(sp->text);
2608 funcnest++;
2609 evaltree(cmdentry.u.func, flags & EV_TESTED);
2610 funcnest--;
2611 INTOFF;
2612 poplocalvars();
2613 localvars = savelocalvars;
2614 saveparam.optind = shellparam.optind;
2615 saveparam.optoff = shellparam.optoff;
2616 freeparam(&shellparam);
2617 shellparam = saveparam;
2618 handler = savehandler;
2619 popredir();
2620 INTON;
2621 if (evalskip == SKIPFUNC) {
2622 evalskip = 0;
2623 skipcount = 0;
2624 }
2625 if (flags & EV_EXIT)
2626 exitshell(exitstatus);
2627 } else if (cmdentry.cmdtype == CMDBUILTIN) {
2628#ifdef DEBUG
2629 trputs("builtin command: "); trargs(argv);
2630#endif
2631 mode = (cmdentry.u.cmd == EXECCMD)? 0 : REDIR_PUSH;
Eric Andersencb57d552001-06-28 07:25:16 +00002632 redirect(cmd->ncmd.redirect, mode);
2633 savecmdname = commandname;
Eric Andersen2870d962001-07-02 17:27:21 +00002634 if (IS_BUILTIN_SPECIAL(firstbltin)) {
Eric Andersencb57d552001-06-28 07:25:16 +00002635 listsetvar(varlist.list);
2636 } else {
2637 cmdenviron = varlist.list;
2638 }
2639 e = -1;
2640 if (setjmp(jmploc.loc)) {
2641 e = exception;
2642 exitstatus = (e == EXINT)? SIGINT+128 : 2;
2643 goto cmddone;
2644 }
2645 savehandler = handler;
2646 handler = &jmploc;
2647 commandname = argv[0];
2648 argptr = argv + 1;
Eric Andersen2870d962001-07-02 17:27:21 +00002649 optptr = NULL; /* initialize nextopt */
Eric Andersencb57d552001-06-28 07:25:16 +00002650 exitstatus = (*cmdentry.u.cmd->builtinfunc)(argc, argv);
2651 flushall();
2652cmddone:
Eric Andersencb57d552001-06-28 07:25:16 +00002653 cmdenviron = NULL;
2654 if (e != EXSHELLPROC) {
2655 commandname = savecmdname;
2656 if (flags & EV_EXIT)
2657 exitshell(exitstatus);
2658 }
2659 handler = savehandler;
2660 if (e != -1) {
2661 if ((e != EXERROR && e != EXEXEC)
2662 || cmdentry.u.cmd == BLTINCMD
2663 || cmdentry.u.cmd == DOTCMD
2664 || cmdentry.u.cmd == EVALCMD
2665 || cmdentry.u.cmd == EXECCMD)
2666 exraise(e);
2667 FORCEINTON;
2668 }
2669 if (cmdentry.u.cmd != EXECCMD)
2670 popredir();
Eric Andersencb57d552001-06-28 07:25:16 +00002671 } else {
2672#ifdef DEBUG
2673 trputs("normal command: "); trargs(argv);
2674#endif
2675 redirect(cmd->ncmd.redirect, 0);
2676 clearredir();
2677 for (sp = varlist.list ; sp ; sp = sp->next)
2678 setvareq(sp->text, VEXPORT|VSTACK);
2679 envp = environment();
2680 shellexec(argv, envp, path, cmdentry.u.index);
2681 }
2682 goto out;
2683
Eric Andersen2870d962001-07-02 17:27:21 +00002684parent: /* parent process gets here (if we forked) */
2685 if (mode == 0) { /* argument to fork */
Eric Andersencb57d552001-06-28 07:25:16 +00002686 INTOFF;
2687 exitstatus = waitforjob(jp);
2688 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00002689 }
2690
2691out:
2692 if (lastarg)
2693 setvar("_", lastarg, 0);
2694 popstackmark(&smark);
2695}
2696
Eric Andersen62483552001-07-10 06:09:16 +00002697/*
2698 * Evaluate a parse tree. The value is left in the global variable
2699 * exitstatus.
2700 */
2701static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00002702evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00002703{
2704 int checkexit = 0;
2705 if (n == NULL) {
2706 TRACE(("evaltree(NULL) called\n"));
2707 goto out;
2708 }
2709 TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
2710 switch (n->type) {
2711 case NSEMI:
2712 evaltree(n->nbinary.ch1, flags & EV_TESTED);
2713 if (evalskip)
2714 goto out;
2715 evaltree(n->nbinary.ch2, flags);
2716 break;
2717 case NAND:
2718 evaltree(n->nbinary.ch1, EV_TESTED);
2719 if (evalskip || exitstatus != 0)
2720 goto out;
2721 evaltree(n->nbinary.ch2, flags);
2722 break;
2723 case NOR:
2724 evaltree(n->nbinary.ch1, EV_TESTED);
2725 if (evalskip || exitstatus == 0)
2726 goto out;
2727 evaltree(n->nbinary.ch2, flags);
2728 break;
2729 case NREDIR:
2730 expredir(n->nredir.redirect);
2731 redirect(n->nredir.redirect, REDIR_PUSH);
2732 evaltree(n->nredir.n, flags);
2733 popredir();
2734 break;
2735 case NSUBSHELL:
2736 evalsubshell(n, flags);
2737 break;
2738 case NBACKGND:
2739 evalsubshell(n, flags);
2740 break;
2741 case NIF: {
2742 evaltree(n->nif.test, EV_TESTED);
2743 if (evalskip)
2744 goto out;
2745 if (exitstatus == 0)
2746 evaltree(n->nif.ifpart, flags);
2747 else if (n->nif.elsepart)
2748 evaltree(n->nif.elsepart, flags);
2749 else
2750 exitstatus = 0;
2751 break;
2752 }
2753 case NWHILE:
2754 case NUNTIL:
2755 evalloop(n, flags);
2756 break;
2757 case NFOR:
2758 evalfor(n, flags);
2759 break;
2760 case NCASE:
2761 evalcase(n, flags);
2762 break;
2763 case NDEFUN: {
2764 struct builtincmd *bcmd;
2765 struct cmdentry entry;
2766 if (
2767 (bcmd = find_builtin(n->narg.text)) &&
2768 IS_BUILTIN_SPECIAL(bcmd)
2769 ) {
2770 out2fmt("%s is a special built-in\n", n->narg.text);
2771 exitstatus = 1;
2772 break;
2773 }
2774 entry.cmdtype = CMDFUNCTION;
2775 entry.u.func = copyfunc(n->narg.next);
2776 addcmdentry(n->narg.text, &entry);
2777 exitstatus = 0;
2778 break;
2779 }
2780 case NNOT:
2781 evaltree(n->nnot.com, EV_TESTED);
2782 exitstatus = !exitstatus;
2783 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002784
Eric Andersen62483552001-07-10 06:09:16 +00002785 case NPIPE:
2786 evalpipe(n);
2787 checkexit = 1;
2788 break;
2789 case NCMD:
2790 evalcommand(n, flags);
2791 checkexit = 1;
2792 break;
2793#ifdef DEBUG
2794 default:
2795 printf("Node type = %d\n", n->type);
2796 break;
2797#endif
2798 }
2799out:
2800 if (pendingsigs)
2801 dotrap();
2802 if (
2803 flags & EV_EXIT ||
2804 (checkexit && eflag && exitstatus && !(flags & EV_TESTED))
2805 )
2806 exitshell(exitstatus);
2807}
2808
2809/*
2810 * Kick off a subshell to evaluate a tree.
2811 */
2812
2813static void
2814evalsubshell(const union node *n, int flags)
2815{
2816 struct job *jp;
2817 int backgnd = (n->type == NBACKGND);
2818
2819 expredir(n->nredir.redirect);
2820 jp = makejob(n, 1);
2821 if (forkshell(jp, n, backgnd) == 0) {
2822 if (backgnd)
2823 flags &=~ EV_TESTED;
2824 redirect(n->nredir.redirect, 0);
2825 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
2826 }
2827 if (! backgnd) {
2828 INTOFF;
2829 exitstatus = waitforjob(jp);
2830 INTON;
2831 }
2832}
2833
2834/*
2835 * Compute the names of the files in a redirection list.
2836 */
2837
2838static void fixredir(union node *n, const char *text, int err);
2839
2840static void
2841expredir(union node *n)
2842{
2843 union node *redir;
2844
2845 for (redir = n ; redir ; redir = redir->nfile.next) {
2846 struct arglist fn;
2847 fn.lastp = &fn.list;
2848 oexitstatus = exitstatus;
2849 switch (redir->type) {
2850 case NFROMTO:
2851 case NFROM:
2852 case NTO:
2853 case NAPPEND:
2854 case NTOOV:
2855 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
2856 redir->nfile.expfname = fn.list->text;
2857 break;
2858 case NFROMFD:
2859 case NTOFD:
2860 if (redir->ndup.vname) {
2861 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
2862 fixredir(redir, fn.list->text, 1);
2863 }
2864 break;
2865 }
2866 }
2867}
2868
2869
2870/*
2871 * Execute a command inside back quotes. If it's a builtin command, we
2872 * want to save its output in a block obtained from malloc. Otherwise
2873 * we fork off a subprocess and get the output of the command via a pipe.
2874 * Should be called with interrupts off.
2875 */
2876
2877static void
2878evalbackcmd(union node *n, struct backcmd *result)
2879{
2880 int pip[2];
2881 struct job *jp;
2882 struct stackmark smark; /* unnecessary */
2883
2884 setstackmark(&smark);
2885 result->fd = -1;
2886 result->buf = NULL;
2887 result->nleft = 0;
2888 result->jp = NULL;
2889 if (n == NULL) {
2890 exitstatus = 0;
2891 goto out;
2892 }
2893 exitstatus = 0;
2894 if (pipe(pip) < 0)
2895 error("Pipe call failed");
2896 jp = makejob(n, 1);
2897 if (forkshell(jp, n, FORK_NOJOB) == 0) {
2898 FORCEINTON;
2899 close(pip[0]);
2900 if (pip[1] != 1) {
2901 close(1);
2902 dup_as_newfd(pip[1], 1);
2903 close(pip[1]);
2904 }
2905 eflag = 0;
2906 evaltree(n, EV_EXIT);
2907 }
2908 close(pip[1]);
2909 result->fd = pip[0];
2910 result->jp = jp;
2911out:
2912 popstackmark(&smark);
2913 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
2914 result->fd, result->buf, result->nleft, result->jp));
2915}
2916
2917
2918/*
2919 * Execute a simple command.
2920 */
Eric Andersencb57d552001-06-28 07:25:16 +00002921
Eric Andersencb57d552001-06-28 07:25:16 +00002922
Eric Andersencb57d552001-06-28 07:25:16 +00002923/*
2924 * Builtin commands. Builtin commands whose functions are closely
2925 * tied to evaluation are implemented here.
2926 */
2927
2928/*
2929 * No command given, or a bltin command with no arguments. Set the
2930 * specified variables.
2931 */
2932
2933int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00002934bltincmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002935{
2936 /*
2937 * Preserve exitstatus of a previous possible redirection
2938 * as POSIX mandates
2939 */
2940 return exitstatus;
2941}
2942
2943
2944/*
2945 * Handle break and continue commands. Break, continue, and return are
2946 * all handled by setting the evalskip flag. The evaluation routines
2947 * above all check this flag, and if it is set they start skipping
2948 * commands rather than executing them. The variable skipcount is
2949 * the number of loops to break/continue, or the number of function
2950 * levels to return. (The latter is always 1.) It should probably
2951 * be an error to break out of more loops than exist, but it isn't
2952 * in the standard shell so we don't make it one here.
2953 */
2954
2955static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00002956breakcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002957{
2958 int n = argc > 1 ? number(argv[1]) : 1;
2959
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00002960 if (n <= 0)
2961 error("Illegal number: %s", argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00002962 if (n > loopnest)
2963 n = loopnest;
2964 if (n > 0) {
2965 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
2966 skipcount = n;
2967 }
2968 return 0;
2969}
2970
2971
2972/*
2973 * The return command.
2974 */
2975
2976static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00002977returncmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002978{
2979 int ret = argc > 1 ? number(argv[1]) : oexitstatus;
2980
2981 if (funcnest) {
2982 evalskip = SKIPFUNC;
2983 skipcount = 1;
2984 return ret;
2985 }
2986 else {
2987 /* Do what ksh does; skip the rest of the file */
2988 evalskip = SKIPFILE;
2989 skipcount = 1;
2990 return ret;
2991 }
2992}
2993
2994
Eric Andersen69a20f02001-10-31 10:40:37 +00002995#ifndef CONFIG_FALSE
Eric Andersencb57d552001-06-28 07:25:16 +00002996static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00002997false_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002998{
2999 return 1;
3000}
Eric Andersen69a20f02001-10-31 10:40:37 +00003001#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003002
Eric Andersen69a20f02001-10-31 10:40:37 +00003003#ifndef CONFIG_TRUE
Eric Andersencb57d552001-06-28 07:25:16 +00003004static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003005true_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003006{
3007 return 0;
3008}
3009#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003010
3011/*
3012 * Controls whether the shell is interactive or not.
3013 */
3014
3015static void setsignal(int signo);
Eric Andersen2870d962001-07-02 17:27:21 +00003016
Eric Andersend35c5df2002-01-09 15:37:36 +00003017#ifdef CONFIG_ASH_MAIL
Eric Andersenec074692001-10-31 11:05:49 +00003018static void chkmail(int silent);
3019#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003020
3021static void
3022setinteractive(int on)
3023{
3024 static int is_interactive;
Eric Andersen1c039232001-07-07 00:05:55 +00003025 static int do_banner=0;
Eric Andersen2870d962001-07-02 17:27:21 +00003026
3027 if (on == is_interactive)
3028 return;
3029 setsignal(SIGINT);
3030 setsignal(SIGQUIT);
3031 setsignal(SIGTERM);
Eric Andersend35c5df2002-01-09 15:37:36 +00003032#ifdef CONFIG_ASH_MAIL
Eric Andersen2870d962001-07-02 17:27:21 +00003033 chkmail(1);
Eric Andersenec074692001-10-31 11:05:49 +00003034#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003035 is_interactive = on;
Eric Andersen1c039232001-07-07 00:05:55 +00003036 if (do_banner==0 && is_interactive) {
3037 /* Looks like they want an interactive shell */
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003038#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
Eric Andersen1c039232001-07-07 00:05:55 +00003039 printf( "\n\n" BB_BANNER " Built-in shell (ash)\n");
3040 printf( "Enter 'help' for a list of built-in commands.\n\n");
Eric Andersend63dee42001-10-19 00:22:23 +00003041#endif
Eric Andersen1c039232001-07-07 00:05:55 +00003042 do_banner=1;
3043 }
Eric Andersen2870d962001-07-02 17:27:21 +00003044}
3045
3046static void
3047optschanged(void)
3048{
3049 setinteractive(iflag);
3050 setjobctl(mflag);
3051}
3052
Eric Andersencb57d552001-06-28 07:25:16 +00003053
3054static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003055execcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003056{
3057 if (argc > 1) {
3058 struct strlist *sp;
3059
Eric Andersen2870d962001-07-02 17:27:21 +00003060 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003061 mflag = 0;
3062 optschanged();
3063 for (sp = cmdenviron; sp ; sp = sp->next)
3064 setvareq(sp->text, VEXPORT|VSTACK);
3065 shellexec(argv + 1, environment(), pathval(), 0);
3066 }
3067 return 0;
3068}
3069
3070static void
3071eprintlist(struct strlist *sp)
3072{
3073 for (; sp; sp = sp->next) {
Eric Andersen3102ac42001-07-06 04:26:23 +00003074 out2fmt(" %s",sp->text);
Eric Andersencb57d552001-06-28 07:25:16 +00003075 }
3076}
Eric Andersencb57d552001-06-28 07:25:16 +00003077
3078/*
3079 * Exec a program. Never returns. If you change this routine, you may
3080 * have to change the find_command routine as well.
3081 */
3082
Eric Andersen2870d962001-07-02 17:27:21 +00003083static const char *pathopt; /* set by padvance */
3084
Eric Andersencb57d552001-06-28 07:25:16 +00003085static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003086shellexec(char **argv, char **envp, const char *path, int idx)
Eric Andersencb57d552001-06-28 07:25:16 +00003087{
3088 char *cmdname;
3089 int e;
3090
3091 if (strchr(argv[0], '/') != NULL) {
3092 tryexec(argv[0], argv, envp);
3093 e = errno;
3094 } else {
3095 e = ENOENT;
3096 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3097 if (--idx < 0 && pathopt == NULL) {
3098 tryexec(cmdname, argv, envp);
3099 if (errno != ENOENT && errno != ENOTDIR)
3100 e = errno;
3101 }
3102 stunalloc(cmdname);
3103 }
3104 }
3105
3106 /* Map to POSIX errors */
3107 switch (e) {
3108 case EACCES:
3109 exerrno = 126;
3110 break;
3111 case ENOENT:
3112 exerrno = 127;
3113 break;
3114 default:
3115 exerrno = 2;
3116 break;
3117 }
3118 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3119 /* NOTREACHED */
3120}
3121
Eric Andersen2870d962001-07-02 17:27:21 +00003122/*
3123 * Clear traps on a fork.
3124 */
3125static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003126clear_traps(void)
3127{
Eric Andersen2870d962001-07-02 17:27:21 +00003128 char **tp;
3129
3130 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
3131 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
3132 INTOFF;
3133 ckfree(*tp);
3134 *tp = NULL;
3135 if (tp != &trap[0])
3136 setsignal(tp - trap);
3137 INTON;
3138 }
3139 }
3140}
3141
3142
3143static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003144initshellproc(void)
3145{
Eric Andersen2870d962001-07-02 17:27:21 +00003146
Eric Andersend35c5df2002-01-09 15:37:36 +00003147#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00003148 /* from alias.c: */
3149 {
3150 rmaliases();
3151 }
3152#endif
3153 /* from eval.c: */
3154 {
3155 exitstatus = 0;
3156 }
3157
3158 /* from exec.c: */
3159 {
3160 deletefuncs();
3161 }
3162
3163 /* from jobs.c: */
3164 {
3165 backgndpid = -1;
Eric Andersend35c5df2002-01-09 15:37:36 +00003166#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen2870d962001-07-02 17:27:21 +00003167 jobctl = 0;
3168#endif
3169 }
3170
3171 /* from options.c: */
3172 {
3173 int i;
3174
3175 for (i = 0; i < NOPTS; i++)
3176 optent_val(i) = 0;
3177 optschanged();
3178
3179 }
3180
3181 /* from redir.c: */
3182 {
3183 clearredir();
3184 }
3185
3186 /* from trap.c: */
3187 {
3188 char *sm;
3189
3190 clear_traps();
3191 for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) {
3192 if (*sm == S_IGN)
3193 *sm = S_HARD_IGN;
3194 }
3195 }
3196
3197 /* from var.c: */
3198 {
3199 shprocvar();
3200 }
3201}
3202
3203static int preadbuffer(void);
3204static void pushfile (void);
Eric Andersen2870d962001-07-02 17:27:21 +00003205
3206/*
3207 * Read a character from the script, returning PEOF on end of file.
3208 * Nul characters in the input are silently discarded.
3209 */
3210
Eric Andersend35c5df2002-01-09 15:37:36 +00003211#ifndef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Eric Andersen2870d962001-07-02 17:27:21 +00003212#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
3213static int
3214pgetc(void)
3215{
3216 return pgetc_macro();
3217}
3218#else
3219static int
3220pgetc_macro(void)
3221{
3222 return --parsenleft >= 0? *parsenextc++ : preadbuffer();
3223}
3224
3225static inline int
3226pgetc(void)
3227{
3228 return pgetc_macro();
3229}
3230#endif
3231
3232
3233/*
3234 * Undo the last call to pgetc. Only one character may be pushed back.
3235 * PEOF may be pushed back.
3236 */
3237
Eric Andersen74400cc2001-10-18 04:11:39 +00003238static void pungetc(void)
3239{
Eric Andersen2870d962001-07-02 17:27:21 +00003240 parsenleft++;
3241 parsenextc--;
3242}
3243
3244
3245static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003246popfile(void)
3247{
Eric Andersen2870d962001-07-02 17:27:21 +00003248 struct parsefile *pf = parsefile;
3249
3250 INTOFF;
3251 if (pf->fd >= 0)
3252 close(pf->fd);
3253 if (pf->buf)
3254 ckfree(pf->buf);
3255 while (pf->strpush)
3256 popstring();
3257 parsefile = pf->prev;
3258 ckfree(pf);
3259 parsenleft = parsefile->nleft;
3260 parselleft = parsefile->lleft;
3261 parsenextc = parsefile->nextc;
3262 plinno = parsefile->linno;
3263 INTON;
3264}
3265
3266
3267/*
3268 * Return to top level.
3269 */
3270
3271static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003272popallfiles(void)
3273{
Eric Andersen2870d962001-07-02 17:27:21 +00003274 while (parsefile != &basepf)
3275 popfile();
3276}
3277
3278/*
3279 * Close the file(s) that the shell is reading commands from. Called
3280 * after a fork is done.
3281 */
3282
Eric Andersen74400cc2001-10-18 04:11:39 +00003283static void closescript(void)
3284{
Eric Andersen2870d962001-07-02 17:27:21 +00003285 popallfiles();
3286 if (parsefile->fd > 0) {
3287 close(parsefile->fd);
3288 parsefile->fd = 0;
3289 }
3290}
3291
3292
3293/*
3294 * Like setinputfile, but takes an open file descriptor. Call this with
3295 * interrupts off.
3296 */
3297
Eric Andersen74400cc2001-10-18 04:11:39 +00003298static void setinputfd(int fd, int push)
Eric Andersen2870d962001-07-02 17:27:21 +00003299{
3300 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
3301 if (push) {
3302 pushfile();
3303 parsefile->buf = 0;
3304 } else {
3305 closescript();
3306 while (parsefile->strpush)
3307 popstring();
3308 }
3309 parsefile->fd = fd;
3310 if (parsefile->buf == NULL)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003311 parsefile->buf = xmalloc(BUFSIZ);
Eric Andersen2870d962001-07-02 17:27:21 +00003312 parselleft = parsenleft = 0;
3313 plinno = 1;
3314}
3315
3316
3317/*
3318 * Set the input to take input from a file. If push is set, push the
3319 * old input onto the stack first.
3320 */
3321
3322static void
3323setinputfile(const char *fname, int push)
3324{
3325 int fd;
3326 int myfileno2;
3327
3328 INTOFF;
3329 if ((fd = open(fname, O_RDONLY)) < 0)
3330 error("Can't open %s", fname);
3331 if (fd < 10) {
3332 myfileno2 = dup_as_newfd(fd, 10);
3333 close(fd);
3334 if (myfileno2 < 0)
3335 error("Out of file descriptors");
3336 fd = myfileno2;
3337 }
3338 setinputfd(fd, push);
3339 INTON;
3340}
3341
Eric Andersencb57d552001-06-28 07:25:16 +00003342
3343static void
Eric Andersen62483552001-07-10 06:09:16 +00003344tryexec(char *cmd, char **argv, char **envp)
3345{
Eric Andersencb57d552001-06-28 07:25:16 +00003346 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003347
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003348#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Eric Andersen3102ac42001-07-06 04:26:23 +00003349 char *name = cmd;
3350 char** argv_l=argv;
3351 int argc_l;
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003352#ifdef CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
Eric Andersen3102ac42001-07-06 04:26:23 +00003353 name = get_last_path_component(name);
3354#endif
3355 argv_l=envp;
3356 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
3357 putenv(*argv_l);
3358 argv_l=argv;
Eric Andersen62483552001-07-10 06:09:16 +00003359 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
Eric Andersen3102ac42001-07-06 04:26:23 +00003360 optind = 1;
3361 run_applet_by_name(name, argc_l, argv);
3362#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003363 execve(cmd, argv, envp);
Eric Andersencb57d552001-06-28 07:25:16 +00003364 e = errno;
3365 if (e == ENOEXEC) {
3366 INTOFF;
3367 initshellproc();
3368 setinputfile(cmd, 0);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003369 commandname = arg0 = xstrdup(argv[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00003370 setparam(argv + 1);
3371 exraise(EXSHELLPROC);
3372 }
3373 errno = e;
3374}
3375
Eric Andersen2870d962001-07-02 17:27:21 +00003376static char *commandtext (const union node *);
Eric Andersencb57d552001-06-28 07:25:16 +00003377
3378/*
3379 * Do a path search. The variable path (passed by reference) should be
3380 * set to the start of the path before the first call; padvance will update
3381 * this value as it proceeds. Successive calls to padvance will return
3382 * the possible path expansions in sequence. If an option (indicated by
3383 * a percent sign) appears in the path entry then the global variable
3384 * pathopt will be set to point to it; otherwise pathopt will be set to
3385 * NULL.
3386 */
3387
3388static const char *pathopt;
3389
Eric Andersen2870d962001-07-02 17:27:21 +00003390static void growstackblock(void);
3391
3392
Eric Andersencb57d552001-06-28 07:25:16 +00003393static char *
Eric Andersen2870d962001-07-02 17:27:21 +00003394padvance(const char **path, const char *name)
3395{
Eric Andersencb57d552001-06-28 07:25:16 +00003396 const char *p;
3397 char *q;
3398 const char *start;
3399 int len;
3400
3401 if (*path == NULL)
3402 return NULL;
3403 start = *path;
3404 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
Eric Andersen2870d962001-07-02 17:27:21 +00003405 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003406 while (stackblocksize() < len)
3407 growstackblock();
3408 q = stackblock();
3409 if (p != start) {
3410 memcpy(q, start, p - start);
3411 q += p - start;
3412 *q++ = '/';
3413 }
3414 strcpy(q, name);
3415 pathopt = NULL;
3416 if (*p == '%') {
3417 pathopt = ++p;
3418 while (*p && *p != ':') p++;
3419 }
3420 if (*p == ':')
3421 *path = p + 1;
3422 else
3423 *path = NULL;
3424 return stalloc(len);
3425}
3426
Eric Andersen62483552001-07-10 06:09:16 +00003427/*
3428 * Wrapper around strcmp for qsort/bsearch/...
3429 */
3430static int
3431pstrcmp(const void *a, const void *b)
3432{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003433 return strcmp((const char *) a, (*(const char *const *) b) + 1);
Eric Andersen62483552001-07-10 06:09:16 +00003434}
3435
3436/*
3437 * Find a keyword is in a sorted array.
3438 */
3439
3440static const char *const *
3441findkwd(const char *s)
3442{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003443 return bsearch(s, tokname_array + KWDOFFSET,
3444 (sizeof(tokname_array)/sizeof(const char *)) - KWDOFFSET,
3445 sizeof(const char *), pstrcmp);
Eric Andersen62483552001-07-10 06:09:16 +00003446}
Eric Andersencb57d552001-06-28 07:25:16 +00003447
3448
3449/*** Command hashing code ***/
3450
3451
3452static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003453hashcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003454{
3455 struct tblentry **pp;
3456 struct tblentry *cmdp;
3457 int c;
3458 int verbose;
3459 struct cmdentry entry;
3460 char *name;
Eric Andersend35c5df2002-01-09 15:37:36 +00003461#ifdef CONFIG_ASH_ALIAS
Eric Andersen62483552001-07-10 06:09:16 +00003462 const struct alias *ap;
3463#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003464
3465 verbose = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003466 while ((c = nextopt("rvV")) != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00003467 if (c == 'r') {
3468 clearcmdentry(0);
3469 return 0;
Eric Andersen62483552001-07-10 06:09:16 +00003470 } else if (c == 'v' || c == 'V') {
3471 verbose = c;
Eric Andersencb57d552001-06-28 07:25:16 +00003472 }
3473 }
3474 if (*argptr == NULL) {
3475 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3476 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3477 if (cmdp->cmdtype != CMDBUILTIN) {
3478 printentry(cmdp, verbose);
3479 }
3480 }
3481 }
3482 return 0;
3483 }
3484 c = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003485 while ((name = *argptr++) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00003486 if ((cmdp = cmdlookup(name, 0)) != NULL
3487 && (cmdp->cmdtype == CMDNORMAL
3488 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3489 delete_cmd_entry();
Eric Andersend35c5df2002-01-09 15:37:36 +00003490#ifdef CONFIG_ASH_ALIAS
Eric Andersen62483552001-07-10 06:09:16 +00003491 /* Then look at the aliases */
Eric Andersenec074692001-10-31 11:05:49 +00003492 if ((ap = *__lookupalias(name)) != NULL) {
Eric Andersen62483552001-07-10 06:09:16 +00003493 if (verbose=='v')
3494 printf("%s is an alias for %s\n", name, ap->val);
3495 else
3496 printalias(ap);
3497 continue;
3498 }
3499#endif
3500 /* First look at the keywords */
3501 if (findkwd(name)!=0) {
3502 if (verbose=='v')
3503 printf("%s is a shell keyword\n", name);
3504 else
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003505 puts(name);
Eric Andersen62483552001-07-10 06:09:16 +00003506 continue;
3507 }
3508
Eric Andersencb57d552001-06-28 07:25:16 +00003509 find_command(name, &entry, DO_ERR, pathval());
3510 if (entry.cmdtype == CMDUNKNOWN) c = 1;
3511 else if (verbose) {
3512 cmdp = cmdlookup(name, 0);
Eric Andersen62483552001-07-10 06:09:16 +00003513 if (cmdp) printentry(cmdp, verbose=='v');
Eric Andersencb57d552001-06-28 07:25:16 +00003514 flushall();
3515 }
Eric Andersencb57d552001-06-28 07:25:16 +00003516 }
3517 return c;
3518}
3519
Eric Andersencb57d552001-06-28 07:25:16 +00003520static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003521printentry(struct tblentry *cmdp, int verbose)
3522{
Eric Andersencb57d552001-06-28 07:25:16 +00003523 int idx;
3524 const char *path;
3525 char *name;
3526
Eric Andersen62483552001-07-10 06:09:16 +00003527 printf("%s%s", cmdp->cmdname, (verbose ? " is " : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00003528 if (cmdp->cmdtype == CMDNORMAL) {
3529 idx = cmdp->param.index;
3530 path = pathval();
3531 do {
3532 name = padvance(&path, cmdp->cmdname);
3533 stunalloc(name);
3534 } while (--idx >= 0);
Eric Andersen62483552001-07-10 06:09:16 +00003535 if(verbose)
3536 out1str(name);
Eric Andersencb57d552001-06-28 07:25:16 +00003537 } else if (cmdp->cmdtype == CMDBUILTIN) {
Eric Andersen62483552001-07-10 06:09:16 +00003538 if(verbose)
3539 out1str("a shell builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00003540 } else if (cmdp->cmdtype == CMDFUNCTION) {
Eric Andersencb57d552001-06-28 07:25:16 +00003541 if (verbose) {
3542 INTOFF;
Eric Andersen62483552001-07-10 06:09:16 +00003543 out1str("a function\n");
Eric Andersencb57d552001-06-28 07:25:16 +00003544 name = commandtext(cmdp->param.func);
Eric Andersen62483552001-07-10 06:09:16 +00003545 printf("%s() {\n %s\n}", cmdp->cmdname, name);
Eric Andersencb57d552001-06-28 07:25:16 +00003546 ckfree(name);
3547 INTON;
3548 }
3549#ifdef DEBUG
3550 } else {
3551 error("internal error: cmdtype %d", cmdp->cmdtype);
3552#endif
3553 }
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003554 puts(cmdp->rehash ? "*" : nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +00003555}
3556
3557
3558
Eric Andersen1c039232001-07-07 00:05:55 +00003559/*** List the available builtins ***/
3560
3561
3562static int helpcmd(int argc, char** argv)
3563{
3564 int col, i;
Eric Andersen1c039232001-07-07 00:05:55 +00003565
Eric Andersen62483552001-07-10 06:09:16 +00003566 printf("\nBuilt-in commands:\n-------------------\n");
3567 for (col=0, i=0; i < NUMBUILTINS; i++) {
3568 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3569 builtincmds[i].name+1);
Eric Andersen1c039232001-07-07 00:05:55 +00003570 if (col > 60) {
3571 printf("\n");
3572 col = 0;
3573 }
3574 }
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003575#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Eric Andersen1c039232001-07-07 00:05:55 +00003576 {
Eric Andersen1c039232001-07-07 00:05:55 +00003577 extern const struct BB_applet applets[];
3578 extern const size_t NUM_APPLETS;
3579
Eric Andersen62483552001-07-10 06:09:16 +00003580 for (i=0; i < NUM_APPLETS; i++) {
3581
3582 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3583 applets[i].name);
Eric Andersen1c039232001-07-07 00:05:55 +00003584 if (col > 60) {
3585 printf("\n");
3586 col = 0;
3587 }
3588 }
3589 }
3590#endif
3591 printf("\n\n");
3592 return EXIT_SUCCESS;
3593}
3594
Eric Andersencb57d552001-06-28 07:25:16 +00003595/*
3596 * Resolve a command name. If you change this routine, you may have to
3597 * change the shellexec routine as well.
3598 */
3599
Eric Andersen2870d962001-07-02 17:27:21 +00003600static int prefix (const char *, const char *);
3601
Eric Andersencb57d552001-06-28 07:25:16 +00003602static void
Eric Andersen2870d962001-07-02 17:27:21 +00003603find_command(const char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003604{
3605 struct tblentry *cmdp;
3606 int idx;
3607 int prev;
3608 char *fullname;
3609 struct stat statb;
3610 int e;
3611 int bltin;
3612 int firstchange;
3613 int updatetbl;
Eric Andersen62483552001-07-10 06:09:16 +00003614 int regular;
Eric Andersencb57d552001-06-28 07:25:16 +00003615 struct builtincmd *bcmd;
3616
3617 /* If name contains a slash, don't use the hash table */
3618 if (strchr(name, '/') != NULL) {
3619 if (act & DO_ABS) {
3620 while (stat(name, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003621 if (errno != ENOENT && errno != ENOTDIR)
3622 e = errno;
3623 entry->cmdtype = CMDUNKNOWN;
3624 entry->u.index = -1;
3625 return;
3626 }
3627 entry->cmdtype = CMDNORMAL;
3628 entry->u.index = -1;
3629 return;
3630 }
3631 entry->cmdtype = CMDNORMAL;
3632 entry->u.index = 0;
3633 return;
3634 }
3635
3636 updatetbl = 1;
3637 if (act & DO_BRUTE) {
3638 firstchange = path_change(path, &bltin);
3639 } else {
3640 bltin = builtinloc;
3641 firstchange = 9999;
3642 }
3643
3644 /* If name is in the table, and not invalidated by cd, we're done */
3645 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
3646 if (cmdp->cmdtype == CMDFUNCTION) {
3647 if (act & DO_NOFUN) {
3648 updatetbl = 0;
3649 } else {
3650 goto success;
3651 }
3652 } else if (act & DO_BRUTE) {
3653 if ((cmdp->cmdtype == CMDNORMAL &&
3654 cmdp->param.index >= firstchange) ||
3655 (cmdp->cmdtype == CMDBUILTIN &&
3656 ((builtinloc < 0 && bltin >= 0) ?
3657 bltin : builtinloc) >= firstchange)) {
3658 /* need to recompute the entry */
3659 } else {
3660 goto success;
3661 }
3662 } else {
3663 goto success;
3664 }
3665 }
3666
3667 bcmd = find_builtin(name);
Eric Andersen2870d962001-07-02 17:27:21 +00003668 regular = bcmd && IS_BUILTIN_REGULAR(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00003669
3670 if (regular) {
3671 if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) {
Eric Andersen2870d962001-07-02 17:27:21 +00003672 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003673 }
3674 } else if (act & DO_BRUTE) {
3675 if (firstchange == 0) {
3676 updatetbl = 0;
3677 }
3678 }
3679
3680 /* If %builtin not in path, check for builtin next */
3681 if (regular || (bltin < 0 && bcmd)) {
3682builtin:
3683 if (!updatetbl) {
3684 entry->cmdtype = CMDBUILTIN;
3685 entry->u.cmd = bcmd;
3686 return;
3687 }
3688 INTOFF;
3689 cmdp = cmdlookup(name, 1);
3690 cmdp->cmdtype = CMDBUILTIN;
3691 cmdp->param.cmd = bcmd;
3692 INTON;
3693 goto success;
3694 }
3695
3696 /* We have to search path. */
Eric Andersen2870d962001-07-02 17:27:21 +00003697 prev = -1; /* where to start */
3698 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00003699 if (cmdp->cmdtype == CMDBUILTIN)
3700 prev = builtinloc;
3701 else
3702 prev = cmdp->param.index;
3703 }
3704
3705 e = ENOENT;
3706 idx = -1;
3707loop:
3708 while ((fullname = padvance(&path, name)) != NULL) {
3709 stunalloc(fullname);
3710 idx++;
3711 if (idx >= firstchange) {
3712 updatetbl = 0;
3713 }
3714 if (pathopt) {
3715 if (prefix("builtin", pathopt)) {
3716 if ((bcmd = find_builtin(name))) {
3717 goto builtin;
3718 }
3719 continue;
3720 } else if (!(act & DO_NOFUN) &&
3721 prefix("func", pathopt)) {
3722 /* handled below */
3723 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00003724 continue; /* ignore unimplemented options */
Eric Andersencb57d552001-06-28 07:25:16 +00003725 }
3726 }
3727 /* if rehash, don't redo absolute path names */
3728 if (fullname[0] == '/' && idx <= prev &&
3729 idx < firstchange) {
3730 if (idx < prev)
3731 continue;
3732 TRACE(("searchexec \"%s\": no change\n", name));
3733 goto success;
3734 }
3735 while (stat(fullname, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003736 if (errno != ENOENT && errno != ENOTDIR)
3737 e = errno;
3738 goto loop;
3739 }
Eric Andersen2870d962001-07-02 17:27:21 +00003740 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00003741 if (!S_ISREG(statb.st_mode))
3742 continue;
Eric Andersen2870d962001-07-02 17:27:21 +00003743 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00003744 stalloc(strlen(fullname) + 1);
3745 readcmdfile(fullname);
3746 if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
3747 error("%s not defined in %s", name, fullname);
3748 stunalloc(fullname);
3749 goto success;
3750 }
Eric Andersencb57d552001-06-28 07:25:16 +00003751 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
3752 /* If we aren't called with DO_BRUTE and cmdp is set, it must
3753 be a function and we're being called with DO_NOFUN */
3754 if (!updatetbl) {
3755 entry->cmdtype = CMDNORMAL;
3756 entry->u.index = idx;
3757 return;
3758 }
3759 INTOFF;
3760 cmdp = cmdlookup(name, 1);
3761 cmdp->cmdtype = CMDNORMAL;
3762 cmdp->param.index = idx;
3763 INTON;
3764 goto success;
3765 }
3766
3767 /* We failed. If there was an entry for this command, delete it */
3768 if (cmdp && updatetbl)
3769 delete_cmd_entry();
3770 if (act & DO_ERR)
Eric Andersen3102ac42001-07-06 04:26:23 +00003771 out2fmt("%s: %s\n", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00003772 entry->cmdtype = CMDUNKNOWN;
3773 return;
3774
3775success:
3776 cmdp->rehash = 0;
3777 entry->cmdtype = cmdp->cmdtype;
3778 entry->u = cmdp->param;
3779}
3780
3781
3782
3783/*
3784 * Search the table of builtin commands.
3785 */
3786
Eric Andersen2870d962001-07-02 17:27:21 +00003787static int
3788bstrcmp(const void *name, const void *b)
3789{
3790 return strcmp((const char *)name, (*(const char *const *) b)+1);
3791}
3792
3793static struct builtincmd *
3794find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00003795{
3796 struct builtincmd *bp;
3797
Eric Andersen2870d962001-07-02 17:27:21 +00003798 bp = bsearch(name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd),
3799 bstrcmp
Eric Andersencb57d552001-06-28 07:25:16 +00003800 );
3801 return bp;
3802}
3803
3804
3805/*
3806 * Called when a cd is done. Marks all commands so the next time they
3807 * are executed they will be rehashed.
3808 */
3809
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003810static inline void
3811hashcd(void)
3812{
Eric Andersencb57d552001-06-28 07:25:16 +00003813 struct tblentry **pp;
3814 struct tblentry *cmdp;
3815
3816 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3817 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3818 if (cmdp->cmdtype == CMDNORMAL
3819 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
3820 cmdp->rehash = 1;
3821 }
3822 }
3823}
3824
3825
3826
3827/*
3828 * Called before PATH is changed. The argument is the new value of PATH;
3829 * pathval() still returns the old value at this point. Called with
3830 * interrupts off.
3831 */
3832
3833static void
Eric Andersen2870d962001-07-02 17:27:21 +00003834changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00003835{
3836 int firstchange;
3837 int bltin;
3838
3839 firstchange = path_change(newval, &bltin);
3840 if (builtinloc < 0 && bltin >= 0)
Eric Andersen2870d962001-07-02 17:27:21 +00003841 builtinloc = bltin; /* zap builtins */
Eric Andersencb57d552001-06-28 07:25:16 +00003842 clearcmdentry(firstchange);
3843 builtinloc = bltin;
Eric Andersen1a923762002-06-06 12:07:28 +00003844 /* Ensure that getenv("PATH") stays current */
3845 setenv("PATH", newval, 1);
Eric Andersencb57d552001-06-28 07:25:16 +00003846}
3847
3848
3849/*
3850 * Clear out command entries. The argument specifies the first entry in
3851 * PATH which has changed.
3852 */
3853
3854static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003855clearcmdentry(int firstchange)
Eric Andersencb57d552001-06-28 07:25:16 +00003856{
3857 struct tblentry **tblp;
3858 struct tblentry **pp;
3859 struct tblentry *cmdp;
3860
3861 INTOFF;
3862 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
3863 pp = tblp;
3864 while ((cmdp = *pp) != NULL) {
3865 if ((cmdp->cmdtype == CMDNORMAL &&
3866 cmdp->param.index >= firstchange)
3867 || (cmdp->cmdtype == CMDBUILTIN &&
3868 builtinloc >= firstchange)) {
3869 *pp = cmdp->next;
3870 ckfree(cmdp);
3871 } else {
3872 pp = &cmdp->next;
3873 }
3874 }
3875 }
3876 INTON;
3877}
3878
3879
3880/*
3881 * Delete all functions.
3882 */
3883
Eric Andersencb57d552001-06-28 07:25:16 +00003884static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003885deletefuncs(void)
3886{
Eric Andersencb57d552001-06-28 07:25:16 +00003887 struct tblentry **tblp;
3888 struct tblentry **pp;
3889 struct tblentry *cmdp;
3890
3891 INTOFF;
3892 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
3893 pp = tblp;
3894 while ((cmdp = *pp) != NULL) {
3895 if (cmdp->cmdtype == CMDFUNCTION) {
3896 *pp = cmdp->next;
3897 freefunc(cmdp->param.func);
3898 ckfree(cmdp);
3899 } else {
3900 pp = &cmdp->next;
3901 }
3902 }
3903 }
3904 INTON;
3905}
3906
3907
3908
3909/*
3910 * Locate a command in the command hash table. If "add" is nonzero,
3911 * add the command to the table if it is not already present. The
3912 * variable "lastcmdentry" is set to point to the address of the link
3913 * pointing to the entry, so that delete_cmd_entry can delete the
3914 * entry.
3915 */
3916
Eric Andersen2870d962001-07-02 17:27:21 +00003917static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00003918
3919static struct tblentry *
Eric Andersen2870d962001-07-02 17:27:21 +00003920cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00003921{
3922 int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00003923 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00003924 struct tblentry *cmdp;
3925 struct tblentry **pp;
3926
3927 p = name;
3928 hashval = *p << 4;
3929 while (*p)
3930 hashval += *p++;
3931 hashval &= 0x7FFF;
3932 pp = &cmdtable[hashval % CMDTABLESIZE];
3933 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3934 if (equal(cmdp->cmdname, name))
3935 break;
3936 pp = &cmdp->next;
3937 }
3938 if (add && cmdp == NULL) {
3939 INTOFF;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003940 cmdp = *pp = xmalloc(sizeof (struct tblentry) - ARB
Eric Andersencb57d552001-06-28 07:25:16 +00003941 + strlen(name) + 1);
3942 cmdp->next = NULL;
3943 cmdp->cmdtype = CMDUNKNOWN;
3944 cmdp->rehash = 0;
3945 strcpy(cmdp->cmdname, name);
3946 INTON;
3947 }
3948 lastcmdentry = pp;
3949 return cmdp;
3950}
3951
3952/*
3953 * Delete the command entry returned on the last lookup.
3954 */
3955
3956static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003957delete_cmd_entry()
3958{
Eric Andersencb57d552001-06-28 07:25:16 +00003959 struct tblentry *cmdp;
3960
3961 INTOFF;
3962 cmdp = *lastcmdentry;
3963 *lastcmdentry = cmdp->next;
3964 ckfree(cmdp);
3965 INTON;
3966}
3967
3968
3969
Eric Andersencb57d552001-06-28 07:25:16 +00003970
3971
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003972static const unsigned char nodesize[26] = {
Eric Andersen62483552001-07-10 06:09:16 +00003973 ALIGN(sizeof (struct nbinary)),
3974 ALIGN(sizeof (struct ncmd)),
3975 ALIGN(sizeof (struct npipe)),
3976 ALIGN(sizeof (struct nredir)),
3977 ALIGN(sizeof (struct nredir)),
3978 ALIGN(sizeof (struct nredir)),
3979 ALIGN(sizeof (struct nbinary)),
3980 ALIGN(sizeof (struct nbinary)),
3981 ALIGN(sizeof (struct nif)),
3982 ALIGN(sizeof (struct nbinary)),
3983 ALIGN(sizeof (struct nbinary)),
3984 ALIGN(sizeof (struct nfor)),
3985 ALIGN(sizeof (struct ncase)),
3986 ALIGN(sizeof (struct nclist)),
3987 ALIGN(sizeof (struct narg)),
3988 ALIGN(sizeof (struct narg)),
3989 ALIGN(sizeof (struct nfile)),
3990 ALIGN(sizeof (struct nfile)),
3991 ALIGN(sizeof (struct nfile)),
3992 ALIGN(sizeof (struct nfile)),
3993 ALIGN(sizeof (struct nfile)),
3994 ALIGN(sizeof (struct ndup)),
3995 ALIGN(sizeof (struct ndup)),
3996 ALIGN(sizeof (struct nhere)),
3997 ALIGN(sizeof (struct nhere)),
3998 ALIGN(sizeof (struct nnot)),
3999};
Eric Andersencb57d552001-06-28 07:25:16 +00004000
Eric Andersencb57d552001-06-28 07:25:16 +00004001
4002
4003/*
4004 * Delete a function if it exists.
4005 */
4006
4007static void
Eric Andersen2870d962001-07-02 17:27:21 +00004008unsetfunc(char *name)
4009{
Eric Andersencb57d552001-06-28 07:25:16 +00004010 struct tblentry *cmdp;
4011
4012 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
4013 freefunc(cmdp->param.func);
4014 delete_cmd_entry();
4015 }
4016}
4017
Eric Andersen2870d962001-07-02 17:27:21 +00004018
4019/*
Eric Andersencb57d552001-06-28 07:25:16 +00004020 * Locate and print what a word is...
4021 */
4022
4023static int
Eric Andersen62483552001-07-10 06:09:16 +00004024typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004025{
4026 int i;
4027 int err = 0;
Eric Andersen62483552001-07-10 06:09:16 +00004028 char *argv_a[2];
4029
4030 argv_a[1] = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004031
4032 for (i = 1; i < argc; i++) {
Eric Andersen62483552001-07-10 06:09:16 +00004033 argv_a[0] = argv[i];
4034 argptr = argv_a;
4035 optptr = "v";
4036 err |= hashcmd(argc, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00004037 }
4038 return err;
4039}
4040
Eric Andersend35c5df2002-01-09 15:37:36 +00004041#ifdef CONFIG_ASH_CMDCMD
Eric Andersencb57d552001-06-28 07:25:16 +00004042static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004043commandcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004044{
4045 int c;
4046 int default_path = 0;
4047 int verify_only = 0;
4048 int verbose_verify_only = 0;
4049
4050 while ((c = nextopt("pvV")) != '\0')
4051 switch (c) {
4052 case 'p':
4053 default_path = 1;
4054 break;
4055 case 'v':
4056 verify_only = 1;
4057 break;
4058 case 'V':
4059 verbose_verify_only = 1;
4060 break;
Eric Andersencb57d552001-06-28 07:25:16 +00004061 }
4062
4063 if (default_path + verify_only + verbose_verify_only > 1 ||
4064 !*argptr) {
Eric Andersen62483552001-07-10 06:09:16 +00004065 out2str(
4066 "command [-p] command [arg ...]\n"
4067 "command {-v|-V} command\n");
Eric Andersencb57d552001-06-28 07:25:16 +00004068 return EX_USAGE;
4069 }
4070
Eric Andersencb57d552001-06-28 07:25:16 +00004071 if (verify_only || verbose_verify_only) {
Eric Andersen62483552001-07-10 06:09:16 +00004072 char *argv_a[2];
4073
4074 argv_a[1] = 0;
4075 argv_a[0] = *argptr;
4076 argptr = argv_a;
4077 optptr = verbose_verify_only ? "v" : "V"; /* reverse special */
4078 return hashcmd(argc, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00004079 }
Eric Andersencb57d552001-06-28 07:25:16 +00004080
4081 return 0;
4082}
Eric Andersen2870d962001-07-02 17:27:21 +00004083#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004084
4085static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004086path_change(const char *newval, int *bltin)
Eric Andersencb57d552001-06-28 07:25:16 +00004087{
4088 const char *old, *new;
4089 int idx;
4090 int firstchange;
4091
4092 old = pathval();
4093 new = newval;
Eric Andersen2870d962001-07-02 17:27:21 +00004094 firstchange = 9999; /* assume no change */
Eric Andersencb57d552001-06-28 07:25:16 +00004095 idx = 0;
4096 *bltin = -1;
4097 for (;;) {
4098 if (*old != *new) {
4099 firstchange = idx;
4100 if ((*old == '\0' && *new == ':')
4101 || (*old == ':' && *new == '\0'))
4102 firstchange++;
Eric Andersen2870d962001-07-02 17:27:21 +00004103 old = new; /* ignore subsequent differences */
Eric Andersencb57d552001-06-28 07:25:16 +00004104 }
4105 if (*new == '\0')
4106 break;
4107 if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1))
4108 *bltin = idx;
4109 if (*new == ':') {
4110 idx++;
4111 }
4112 new++, old++;
4113 }
4114 if (builtinloc >= 0 && *bltin < 0)
4115 firstchange = 0;
4116 return firstchange;
4117}
Eric Andersencb57d552001-06-28 07:25:16 +00004118/*
4119 * Routines to expand arguments to commands. We have to deal with
4120 * backquotes, shell variables, and file metacharacters.
4121 */
4122/*
4123 * _rmescape() flags
4124 */
Eric Andersen2870d962001-07-02 17:27:21 +00004125#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4126#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Eric Andersencb57d552001-06-28 07:25:16 +00004127
4128/*
4129 * Structure specifying which parts of the string should be searched
4130 * for IFS characters.
4131 */
4132
4133struct ifsregion {
Eric Andersen2870d962001-07-02 17:27:21 +00004134 struct ifsregion *next; /* next region in list */
4135 int begoff; /* offset of start of region */
4136 int endoff; /* offset of end of region */
4137 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004138};
4139
4140
Eric Andersen2870d962001-07-02 17:27:21 +00004141static char *expdest; /* output of current string */
4142static struct nodelist *argbackq; /* list of back quote expressions */
4143static struct ifsregion ifsfirst; /* first struct in list of ifs regions */
4144static struct ifsregion *ifslastp; /* last struct in list */
4145static struct arglist exparg; /* holds expanded arg list */
Eric Andersencb57d552001-06-28 07:25:16 +00004146
Eric Andersen2870d962001-07-02 17:27:21 +00004147static void argstr (char *, int);
4148static char *exptilde (char *, int);
4149static void expbackq (union node *, int, int);
4150static int subevalvar (char *, char *, int, int, int, int, int);
Eric Andersen2870d962001-07-02 17:27:21 +00004151static int varisset (char *, int);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004152static void strtodest (const char *, int, int);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004153static inline void varvalue (char *, int, int);
Eric Andersen2870d962001-07-02 17:27:21 +00004154static void recordregion (int, int, int);
4155static void removerecordregions (int);
4156static void ifsbreakup (char *, struct arglist *);
4157static void ifsfree (void);
4158static void expandmeta (struct strlist *, int);
Eric Andersen62483552001-07-10 06:09:16 +00004159#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00004160#define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB)
4161#if !defined(GLOB_BROKEN)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004162static inline void addglob (const glob_t *);
Eric Andersencb57d552001-06-28 07:25:16 +00004163#endif
4164#endif
Eric Andersen62483552001-07-10 06:09:16 +00004165#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersen2870d962001-07-02 17:27:21 +00004166static void expmeta (char *, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004167#endif
Eric Andersen62483552001-07-10 06:09:16 +00004168#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersen2870d962001-07-02 17:27:21 +00004169static struct strlist *expsort (struct strlist *);
4170static struct strlist *msort (struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004171#endif
Eric Andersen2870d962001-07-02 17:27:21 +00004172static int patmatch (char *, char *, int);
Eric Andersen62483552001-07-10 06:09:16 +00004173#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00004174static int patmatch2 (char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004175#else
Eric Andersen2870d962001-07-02 17:27:21 +00004176static int pmatch (char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004177#define patmatch2 patmatch
4178#endif
Eric Andersen2870d962001-07-02 17:27:21 +00004179static char *cvtnum (int, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004180
4181/*
4182 * Expand shell variables and backquotes inside a here document.
4183 */
4184
Eric Andersen2870d962001-07-02 17:27:21 +00004185/* arg: the document, fd: where to write the expanded version */
Eric Andersen62483552001-07-10 06:09:16 +00004186static inline void
Eric Andersen2870d962001-07-02 17:27:21 +00004187expandhere(union node *arg, int fd)
4188{
Eric Andersencb57d552001-06-28 07:25:16 +00004189 herefd = fd;
4190 expandarg(arg, (struct arglist *)NULL, 0);
4191 xwrite(fd, stackblock(), expdest - stackblock());
4192}
4193
4194
4195/*
4196 * Perform variable substitution and command substitution on an argument,
4197 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4198 * perform splitting and file name expansion. When arglist is NULL, perform
4199 * here document expansion.
4200 */
4201
4202static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004203expandarg(union node *arg, struct arglist *arglist, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004204{
4205 struct strlist *sp;
4206 char *p;
4207
4208 argbackq = arg->narg.backquote;
4209 STARTSTACKSTR(expdest);
4210 ifsfirst.next = NULL;
4211 ifslastp = NULL;
4212 argstr(arg->narg.text, flag);
4213 if (arglist == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00004214 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004215 }
4216 STPUTC('\0', expdest);
4217 p = grabstackstr(expdest);
4218 exparg.lastp = &exparg.list;
4219 /*
4220 * TODO - EXP_REDIR
4221 */
4222 if (flag & EXP_FULL) {
4223 ifsbreakup(p, &exparg);
4224 *exparg.lastp = NULL;
4225 exparg.lastp = &exparg.list;
4226 expandmeta(exparg.list, flag);
4227 } else {
4228 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4229 rmescapes(p);
4230 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4231 sp->text = p;
4232 *exparg.lastp = sp;
4233 exparg.lastp = &sp->next;
4234 }
4235 ifsfree();
4236 *exparg.lastp = NULL;
4237 if (exparg.list) {
4238 *arglist->lastp = exparg.list;
4239 arglist->lastp = exparg.lastp;
4240 }
4241}
4242
4243
Eric Andersen62483552001-07-10 06:09:16 +00004244/*
4245 * Expand a variable, and return a pointer to the next character in the
4246 * input string.
4247 */
4248
Eric Andersen74400cc2001-10-18 04:11:39 +00004249static inline char * evalvar(char *p, int flag)
Eric Andersen62483552001-07-10 06:09:16 +00004250{
4251 int subtype;
4252 int varflags;
4253 char *var;
4254 const char *val;
4255 int patloc;
4256 int c;
4257 int set;
4258 int special;
4259 int startloc;
4260 int varlen;
4261 int easy;
4262 int quotes = flag & (EXP_FULL | EXP_CASE);
4263
4264 varflags = *p++;
4265 subtype = varflags & VSTYPE;
4266 var = p;
4267 special = 0;
4268 if (! is_name(*p))
4269 special = 1;
4270 p = strchr(p, '=') + 1;
4271again: /* jump here after setting a variable with ${var=text} */
4272 if (special) {
4273 set = varisset(var, varflags & VSNUL);
4274 val = NULL;
4275 } else {
4276 val = lookupvar(var);
4277 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
4278 val = NULL;
4279 set = 0;
4280 } else
4281 set = 1;
4282 }
4283 varlen = 0;
4284 startloc = expdest - stackblock();
4285 if (set && subtype != VSPLUS) {
4286 /* insert the value of the variable */
4287 if (special) {
4288 varvalue(var, varflags & VSQUOTE, flag);
4289 if (subtype == VSLENGTH) {
4290 varlen = expdest - stackblock() - startloc;
4291 STADJUST(-varlen, expdest);
4292 }
4293 } else {
4294 if (subtype == VSLENGTH) {
4295 varlen = strlen(val);
4296 } else {
4297 strtodest(
4298 val,
4299 varflags & VSQUOTE ?
4300 DQSYNTAX : BASESYNTAX,
4301 quotes
4302 );
4303 }
4304 }
4305 }
4306
4307 if (subtype == VSPLUS)
4308 set = ! set;
4309
4310 easy = ((varflags & VSQUOTE) == 0 ||
4311 (*var == '@' && shellparam.nparam != 1));
4312
4313
4314 switch (subtype) {
4315 case VSLENGTH:
4316 expdest = cvtnum(varlen, expdest);
4317 goto record;
4318
4319 case VSNORMAL:
4320 if (!easy)
4321 break;
4322record:
4323 recordregion(startloc, expdest - stackblock(),
4324 varflags & VSQUOTE);
4325 break;
4326
4327 case VSPLUS:
4328 case VSMINUS:
4329 if (!set) {
4330 argstr(p, flag);
4331 break;
4332 }
4333 if (easy)
4334 goto record;
4335 break;
4336
4337 case VSTRIMLEFT:
4338 case VSTRIMLEFTMAX:
4339 case VSTRIMRIGHT:
4340 case VSTRIMRIGHTMAX:
4341 if (!set)
4342 break;
4343 /*
4344 * Terminate the string and start recording the pattern
4345 * right after it
4346 */
4347 STPUTC('\0', expdest);
4348 patloc = expdest - stackblock();
4349 if (subevalvar(p, NULL, patloc, subtype,
4350 startloc, varflags, quotes) == 0) {
4351 int amount = (expdest - stackblock() - patloc) + 1;
4352 STADJUST(-amount, expdest);
4353 }
4354 /* Remove any recorded regions beyond start of variable */
4355 removerecordregions(startloc);
4356 goto record;
4357
4358 case VSASSIGN:
4359 case VSQUESTION:
4360 if (!set) {
4361 if (subevalvar(p, var, 0, subtype, startloc,
4362 varflags, quotes)) {
4363 varflags &= ~VSNUL;
4364 /*
4365 * Remove any recorded regions beyond
4366 * start of variable
4367 */
4368 removerecordregions(startloc);
4369 goto again;
4370 }
4371 break;
4372 }
4373 if (easy)
4374 goto record;
4375 break;
4376
4377#ifdef DEBUG
4378 default:
4379 abort();
4380#endif
4381 }
4382
4383 if (subtype != VSNORMAL) { /* skip to end of alternative */
4384 int nesting = 1;
4385 for (;;) {
4386 if ((c = *p++) == CTLESC)
4387 p++;
4388 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
4389 if (set)
4390 argbackq = argbackq->next;
4391 } else if (c == CTLVAR) {
4392 if ((*p++ & VSTYPE) != VSNORMAL)
4393 nesting++;
4394 } else if (c == CTLENDVAR) {
4395 if (--nesting == 0)
4396 break;
4397 }
4398 }
4399 }
4400 return p;
4401}
4402
Eric Andersencb57d552001-06-28 07:25:16 +00004403
4404/*
4405 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4406 * characters to allow for further processing. Otherwise treat
4407 * $@ like $* since no splitting will be performed.
4408 */
4409
4410static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004411argstr(char *p, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004412{
4413 char c;
Eric Andersen2870d962001-07-02 17:27:21 +00004414 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
Eric Andersencb57d552001-06-28 07:25:16 +00004415 int firsteq = 1;
4416
4417 if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
4418 p = exptilde(p, flag);
4419 for (;;) {
4420 switch (c = *p++) {
4421 case '\0':
4422 case CTLENDVAR: /* ??? */
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004423 return;
Eric Andersencb57d552001-06-28 07:25:16 +00004424 case CTLQUOTEMARK:
4425 /* "$@" syntax adherence hack */
4426 if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
4427 break;
4428 if ((flag & EXP_FULL) != 0)
4429 STPUTC(c, expdest);
4430 break;
4431 case CTLESC:
4432 if (quotes)
4433 STPUTC(c, expdest);
4434 c = *p++;
4435 STPUTC(c, expdest);
4436 break;
4437 case CTLVAR:
4438 p = evalvar(p, flag);
4439 break;
4440 case CTLBACKQ:
4441 case CTLBACKQ|CTLQUOTE:
4442 expbackq(argbackq->n, c & CTLQUOTE, flag);
4443 argbackq = argbackq->next;
4444 break;
Eric Andersend35c5df2002-01-09 15:37:36 +00004445#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +00004446 case CTLENDARI:
4447 expari(flag);
4448 break;
Eric Andersen2870d962001-07-02 17:27:21 +00004449#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004450 case ':':
4451 case '=':
4452 /*
4453 * sort of a hack - expand tildes in variable
4454 * assignments (after the first '=' and after ':'s).
4455 */
4456 STPUTC(c, expdest);
4457 if (flag & EXP_VARTILDE && *p == '~') {
4458 if (c == '=') {
4459 if (firsteq)
4460 firsteq = 0;
4461 else
4462 break;
4463 }
4464 p = exptilde(p, flag);
4465 }
4466 break;
4467 default:
4468 STPUTC(c, expdest);
4469 }
4470 }
Eric Andersencb57d552001-06-28 07:25:16 +00004471 return;
4472}
4473
4474static char *
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004475exptilde(char *p, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004476{
4477 char c, *startp = p;
4478 struct passwd *pw;
4479 const char *home;
4480 int quotes = flag & (EXP_FULL | EXP_CASE);
4481
4482 while ((c = *p) != '\0') {
4483 switch(c) {
4484 case CTLESC:
4485 return (startp);
4486 case CTLQUOTEMARK:
4487 return (startp);
4488 case ':':
4489 if (flag & EXP_VARTILDE)
4490 goto done;
4491 break;
4492 case '/':
4493 goto done;
4494 }
4495 p++;
4496 }
4497done:
4498 *p = '\0';
4499 if (*(startp+1) == '\0') {
4500 if ((home = lookupvar("HOME")) == NULL)
4501 goto lose;
4502 } else {
4503 if ((pw = getpwnam(startp+1)) == NULL)
4504 goto lose;
4505 home = pw->pw_dir;
4506 }
4507 if (*home == '\0')
4508 goto lose;
4509 *p = c;
4510 strtodest(home, SQSYNTAX, quotes);
4511 return (p);
4512lose:
4513 *p = c;
4514 return (startp);
4515}
4516
4517
Eric Andersen2870d962001-07-02 17:27:21 +00004518static void
4519removerecordregions(int endoff)
Eric Andersencb57d552001-06-28 07:25:16 +00004520{
4521 if (ifslastp == NULL)
4522 return;
4523
4524 if (ifsfirst.endoff > endoff) {
4525 while (ifsfirst.next != NULL) {
4526 struct ifsregion *ifsp;
4527 INTOFF;
4528 ifsp = ifsfirst.next->next;
4529 ckfree(ifsfirst.next);
4530 ifsfirst.next = ifsp;
4531 INTON;
4532 }
4533 if (ifsfirst.begoff > endoff)
4534 ifslastp = NULL;
4535 else {
4536 ifslastp = &ifsfirst;
4537 ifsfirst.endoff = endoff;
4538 }
4539 return;
4540 }
Eric Andersen2870d962001-07-02 17:27:21 +00004541
Eric Andersencb57d552001-06-28 07:25:16 +00004542 ifslastp = &ifsfirst;
4543 while (ifslastp->next && ifslastp->next->begoff < endoff)
4544 ifslastp=ifslastp->next;
4545 while (ifslastp->next != NULL) {
4546 struct ifsregion *ifsp;
4547 INTOFF;
4548 ifsp = ifslastp->next->next;
4549 ckfree(ifslastp->next);
4550 ifslastp->next = ifsp;
4551 INTON;
4552 }
4553 if (ifslastp->endoff > endoff)
4554 ifslastp->endoff = endoff;
4555}
4556
4557
Eric Andersend35c5df2002-01-09 15:37:36 +00004558#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +00004559/*
4560 * Expand arithmetic expression. Backup to start of expression,
4561 * evaluate, place result in (backed up) result, adjust string position.
4562 */
4563static void
Eric Andersen2870d962001-07-02 17:27:21 +00004564expari(int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004565{
4566 char *p, *start;
Eric Andersen34506362001-08-02 05:02:46 +00004567 int errcode;
Eric Andersencb57d552001-06-28 07:25:16 +00004568 int result;
4569 int begoff;
4570 int quotes = flag & (EXP_FULL | EXP_CASE);
4571 int quoted;
4572
Eric Andersen2870d962001-07-02 17:27:21 +00004573 /* ifsfree(); */
Eric Andersencb57d552001-06-28 07:25:16 +00004574
4575 /*
4576 * This routine is slightly over-complicated for
4577 * efficiency. First we make sure there is
4578 * enough space for the result, which may be bigger
4579 * than the expression if we add exponentation. Next we
4580 * scan backwards looking for the start of arithmetic. If the
4581 * next previous character is a CTLESC character, then we
4582 * have to rescan starting from the beginning since CTLESC
4583 * characters have to be processed left to right.
4584 */
4585 CHECKSTRSPACE(10, expdest);
4586 USTPUTC('\0', expdest);
4587 start = stackblock();
4588 p = expdest - 1;
4589 while (*p != CTLARI && p >= start)
4590 --p;
4591 if (*p != CTLARI)
4592 error("missing CTLARI (shouldn't happen)");
4593 if (p > start && *(p-1) == CTLESC)
4594 for (p = start; *p != CTLARI; p++)
4595 if (*p == CTLESC)
4596 p++;
4597
4598 if (p[1] == '"')
4599 quoted=1;
4600 else
4601 quoted=0;
4602 begoff = p - start;
4603 removerecordregions(begoff);
4604 if (quotes)
4605 rmescapes(p+2);
Eric Andersen34506362001-08-02 05:02:46 +00004606 result = arith(p+2, &errcode);
4607 if (errcode < 0) {
4608 if(errcode == -2)
4609 error("divide by zero");
4610 else
4611 error("syntax error: \"%s\"\n", p+2);
4612 }
Eric Andersen3102ac42001-07-06 04:26:23 +00004613 snprintf(p, 12, "%d", result);
Eric Andersencb57d552001-06-28 07:25:16 +00004614
4615 while (*p++)
4616 ;
4617
4618 if (quoted == 0)
4619 recordregion(begoff, p - 1 - start, 0);
4620 result = expdest - p + 1;
4621 STADJUST(-result, expdest);
4622}
Eric Andersen2870d962001-07-02 17:27:21 +00004623#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004624
4625/*
4626 * Expand stuff in backwards quotes.
4627 */
4628
4629static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004630expbackq(union node *cmd, int quoted, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004631{
4632 volatile struct backcmd in;
4633 int i;
4634 char buf[128];
4635 char *p;
4636 char *dest = expdest;
4637 volatile struct ifsregion saveifs;
4638 struct ifsregion *volatile savelastp;
4639 struct nodelist *volatile saveargbackq;
4640 char lastc;
4641 int startloc = dest - stackblock();
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004642 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +00004643 volatile int saveherefd;
4644 int quotes = flag & (EXP_FULL | EXP_CASE);
4645 struct jmploc jmploc;
4646 struct jmploc *volatile savehandler;
4647 int ex;
4648
4649#if __GNUC__
4650 /* Avoid longjmp clobbering */
4651 (void) &dest;
4652 (void) &syntax;
4653#endif
4654
4655 in.fd = -1;
4656 in.buf = 0;
4657 in.jp = 0;
4658
4659 INTOFF;
4660 saveifs = ifsfirst;
4661 savelastp = ifslastp;
4662 saveargbackq = argbackq;
4663 saveherefd = herefd;
4664 herefd = -1;
4665 if ((ex = setjmp(jmploc.loc))) {
4666 goto err1;
4667 }
4668 savehandler = handler;
4669 handler = &jmploc;
4670 INTON;
4671 p = grabstackstr(dest);
4672 evalbackcmd(cmd, (struct backcmd *) &in);
4673 ungrabstackstr(p, dest);
4674err1:
4675 INTOFF;
4676 ifsfirst = saveifs;
4677 ifslastp = savelastp;
4678 argbackq = saveargbackq;
4679 herefd = saveherefd;
4680 if (ex) {
4681 goto err2;
4682 }
4683
4684 p = in.buf;
4685 lastc = '\0';
4686 for (;;) {
4687 if (--in.nleft < 0) {
4688 if (in.fd < 0)
4689 break;
Eric Andersen7467c8d2001-07-12 20:26:32 +00004690 i = safe_read(in.fd, buf, sizeof buf);
Eric Andersencb57d552001-06-28 07:25:16 +00004691 TRACE(("expbackq: read returns %d\n", i));
4692 if (i <= 0)
4693 break;
4694 p = buf;
4695 in.nleft = i - 1;
4696 }
4697 lastc = *p++;
4698 if (lastc != '\0') {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004699 if (quotes && SIT(lastc, syntax) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +00004700 STPUTC(CTLESC, dest);
4701 STPUTC(lastc, dest);
4702 }
4703 }
4704
4705 /* Eat all trailing newlines */
4706 for (; dest > stackblock() && dest[-1] == '\n';)
4707 STUNPUTC(dest);
4708
4709err2:
4710 if (in.fd >= 0)
4711 close(in.fd);
4712 if (in.buf)
4713 ckfree(in.buf);
4714 if (in.jp)
4715 exitstatus = waitforjob(in.jp);
4716 handler = savehandler;
4717 if (ex) {
4718 longjmp(handler->loc, 1);
4719 }
4720 if (quoted == 0)
4721 recordregion(startloc, dest - stackblock(), 0);
4722 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4723 (dest - stackblock()) - startloc,
4724 (dest - stackblock()) - startloc,
4725 stackblock() + startloc));
4726 expdest = dest;
4727 INTON;
4728}
4729
Eric Andersencb57d552001-06-28 07:25:16 +00004730static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004731subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
Eric Andersencb57d552001-06-28 07:25:16 +00004732{
4733 char *startp;
4734 char *loc = NULL;
4735 char *q;
4736 int c = 0;
4737 int saveherefd = herefd;
4738 struct nodelist *saveargbackq = argbackq;
4739 int amount;
4740
4741 herefd = -1;
4742 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
4743 STACKSTRNUL(expdest);
4744 herefd = saveherefd;
4745 argbackq = saveargbackq;
4746 startp = stackblock() + startloc;
4747 if (str == NULL)
4748 str = stackblock() + strloc;
4749
4750 switch (subtype) {
4751 case VSASSIGN:
4752 setvar(str, startp, 0);
4753 amount = startp - expdest;
4754 STADJUST(amount, expdest);
4755 varflags &= ~VSNUL;
4756 if (c != 0)
4757 *loc = c;
4758 return 1;
4759
4760 case VSQUESTION:
4761 if (*p != CTLENDVAR) {
Eric Andersen3102ac42001-07-06 04:26:23 +00004762 out2fmt(snlfmt, startp);
Eric Andersencb57d552001-06-28 07:25:16 +00004763 error((char *)NULL);
4764 }
4765 error("%.*s: parameter %snot set", p - str - 1,
4766 str, (varflags & VSNUL) ? "null or "
4767 : nullstr);
4768 /* NOTREACHED */
4769
4770 case VSTRIMLEFT:
4771 for (loc = startp; loc < str; loc++) {
4772 c = *loc;
4773 *loc = '\0';
4774 if (patmatch2(str, startp, quotes))
4775 goto recordleft;
4776 *loc = c;
4777 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00004778 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00004779 }
4780 return 0;
4781
4782 case VSTRIMLEFTMAX:
4783 for (loc = str - 1; loc >= startp;) {
4784 c = *loc;
4785 *loc = '\0';
4786 if (patmatch2(str, startp, quotes))
4787 goto recordleft;
4788 *loc = c;
4789 loc--;
4790 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
4791 for (q = startp; q < loc; q++)
4792 if (*q == CTLESC)
4793 q++;
4794 if (q > loc)
4795 loc--;
4796 }
4797 }
4798 return 0;
4799
4800 case VSTRIMRIGHT:
Eric Andersen2870d962001-07-02 17:27:21 +00004801 for (loc = str - 1; loc >= startp;) {
Eric Andersencb57d552001-06-28 07:25:16 +00004802 if (patmatch2(str, loc, quotes))
4803 goto recordright;
4804 loc--;
Eric Andersen2870d962001-07-02 17:27:21 +00004805 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
Eric Andersencb57d552001-06-28 07:25:16 +00004806 for (q = startp; q < loc; q++)
4807 if (*q == CTLESC)
4808 q++;
4809 if (q > loc)
4810 loc--;
4811 }
4812 }
4813 return 0;
4814
4815 case VSTRIMRIGHTMAX:
4816 for (loc = startp; loc < str - 1; loc++) {
4817 if (patmatch2(str, loc, quotes))
4818 goto recordright;
4819 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00004820 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00004821 }
4822 return 0;
4823
4824#ifdef DEBUG
4825 default:
4826 abort();
4827#endif
4828 }
4829
4830recordleft:
4831 *loc = c;
4832 amount = ((str - 1) - (loc - startp)) - expdest;
4833 STADJUST(amount, expdest);
4834 while (loc != str - 1)
4835 *startp++ = *loc++;
4836 return 1;
4837
4838recordright:
4839 amount = loc - expdest;
4840 STADJUST(amount, expdest);
4841 STPUTC('\0', expdest);
4842 STADJUST(-1, expdest);
4843 return 1;
4844}
4845
4846
4847/*
Eric Andersencb57d552001-06-28 07:25:16 +00004848 * Test whether a specialized variable is set.
4849 */
4850
4851static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004852varisset(char *name, int nulok)
Eric Andersencb57d552001-06-28 07:25:16 +00004853{
4854 if (*name == '!')
4855 return backgndpid != -1;
4856 else if (*name == '@' || *name == '*') {
4857 if (*shellparam.p == NULL)
4858 return 0;
4859
4860 if (nulok) {
4861 char **av;
4862
4863 for (av = shellparam.p; *av; av++)
4864 if (**av != '\0')
4865 return 1;
4866 return 0;
4867 }
4868 } else if (is_digit(*name)) {
4869 char *ap;
4870 int num = atoi(name);
4871
4872 if (num > shellparam.nparam)
4873 return 0;
4874
4875 if (num == 0)
4876 ap = arg0;
4877 else
4878 ap = shellparam.p[num - 1];
4879
4880 if (nulok && (ap == NULL || *ap == '\0'))
4881 return 0;
4882 }
4883 return 1;
4884}
4885
Eric Andersencb57d552001-06-28 07:25:16 +00004886/*
4887 * Put a string on the stack.
4888 */
4889
4890static void
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004891strtodest(const char *p, int syntax, int quotes)
Eric Andersencb57d552001-06-28 07:25:16 +00004892{
4893 while (*p) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004894 if (quotes && SIT(*p,syntax) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +00004895 STPUTC(CTLESC, expdest);
4896 STPUTC(*p++, expdest);
4897 }
4898}
4899
Eric Andersencb57d552001-06-28 07:25:16 +00004900/*
4901 * Add the value of a specialized variable to the stack string.
4902 */
4903
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004904static inline void
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004905varvalue(char *name, int quoted, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00004906{
4907 int num;
4908 char *p;
4909 int i;
4910 int sep;
4911 int sepq = 0;
4912 char **ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004913 int syntax;
Eric Andersencb57d552001-06-28 07:25:16 +00004914 int allow_split = flags & EXP_FULL;
4915 int quotes = flags & (EXP_FULL | EXP_CASE);
4916
4917 syntax = quoted ? DQSYNTAX : BASESYNTAX;
4918 switch (*name) {
4919 case '$':
4920 num = rootpid;
4921 goto numvar;
4922 case '?':
4923 num = oexitstatus;
4924 goto numvar;
4925 case '#':
4926 num = shellparam.nparam;
4927 goto numvar;
4928 case '!':
4929 num = backgndpid;
4930numvar:
4931 expdest = cvtnum(num, expdest);
4932 break;
4933 case '-':
4934 for (i = 0 ; i < NOPTS ; i++) {
Eric Andersen2870d962001-07-02 17:27:21 +00004935 if (optent_val(i))
4936 STPUTC(optent_letter(optlist[i]), expdest);
Eric Andersencb57d552001-06-28 07:25:16 +00004937 }
4938 break;
4939 case '@':
4940 if (allow_split && quoted) {
4941 sep = 1 << CHAR_BIT;
4942 goto param;
4943 }
4944 /* fall through */
4945 case '*':
4946 sep = ifsset() ? ifsval()[0] : ' ';
4947 if (quotes) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004948 sepq = SIT(sep,syntax) == CCTL;
Eric Andersencb57d552001-06-28 07:25:16 +00004949 }
4950param:
4951 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
4952 strtodest(p, syntax, quotes);
4953 if (*ap && sep) {
4954 if (sepq)
4955 STPUTC(CTLESC, expdest);
4956 STPUTC(sep, expdest);
4957 }
4958 }
4959 break;
4960 case '0':
4961 strtodest(arg0, syntax, quotes);
4962 break;
4963 default:
4964 num = atoi(name);
4965 if (num > 0 && num <= shellparam.nparam) {
4966 strtodest(shellparam.p[num - 1], syntax, quotes);
4967 }
4968 break;
4969 }
4970}
4971
4972
Eric Andersencb57d552001-06-28 07:25:16 +00004973/*
4974 * Record the fact that we have to scan this region of the
4975 * string for IFS characters.
4976 */
4977
4978static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004979recordregion(int start, int end, int nulonly)
Eric Andersencb57d552001-06-28 07:25:16 +00004980{
4981 struct ifsregion *ifsp;
4982
4983 if (ifslastp == NULL) {
4984 ifsp = &ifsfirst;
4985 } else {
4986 INTOFF;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004987 ifsp = (struct ifsregion *)xmalloc(sizeof (struct ifsregion));
Eric Andersencb57d552001-06-28 07:25:16 +00004988 ifsp->next = NULL;
4989 ifslastp->next = ifsp;
4990 INTON;
4991 }
4992 ifslastp = ifsp;
4993 ifslastp->begoff = start;
4994 ifslastp->endoff = end;
4995 ifslastp->nulonly = nulonly;
4996}
4997
4998
4999
5000/*
5001 * Break the argument string into pieces based upon IFS and add the
5002 * strings to the argument list. The regions of the string to be
5003 * searched for IFS characters have been stored by recordregion.
5004 */
5005static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005006ifsbreakup(char *string, struct arglist *arglist)
5007{
Eric Andersencb57d552001-06-28 07:25:16 +00005008 struct ifsregion *ifsp;
5009 struct strlist *sp;
5010 char *start;
5011 char *p;
5012 char *q;
5013 const char *ifs, *realifs;
5014 int ifsspc;
5015 int nulonly;
5016
5017
5018 start = string;
5019 ifsspc = 0;
5020 nulonly = 0;
5021 realifs = ifsset() ? ifsval() : defifs;
5022 if (ifslastp != NULL) {
5023 ifsp = &ifsfirst;
5024 do {
5025 p = string + ifsp->begoff;
5026 nulonly = ifsp->nulonly;
5027 ifs = nulonly ? nullstr : realifs;
5028 ifsspc = 0;
5029 while (p < string + ifsp->endoff) {
5030 q = p;
5031 if (*p == CTLESC)
5032 p++;
5033 if (strchr(ifs, *p)) {
5034 if (!nulonly)
5035 ifsspc = (strchr(defifs, *p) != NULL);
5036 /* Ignore IFS whitespace at start */
5037 if (q == start && ifsspc) {
5038 p++;
5039 start = p;
5040 continue;
5041 }
5042 *q = '\0';
5043 sp = (struct strlist *)stalloc(sizeof *sp);
5044 sp->text = start;
5045 *arglist->lastp = sp;
5046 arglist->lastp = &sp->next;
5047 p++;
5048 if (!nulonly) {
5049 for (;;) {
5050 if (p >= string + ifsp->endoff) {
5051 break;
5052 }
5053 q = p;
5054 if (*p == CTLESC)
5055 p++;
5056 if (strchr(ifs, *p) == NULL ) {
5057 p = q;
5058 break;
5059 } else if (strchr(defifs, *p) == NULL) {
5060 if (ifsspc) {
5061 p++;
5062 ifsspc = 0;
5063 } else {
5064 p = q;
5065 break;
5066 }
5067 } else
5068 p++;
5069 }
5070 }
5071 start = p;
5072 } else
5073 p++;
5074 }
5075 } while ((ifsp = ifsp->next) != NULL);
5076 if (!(*start || (!ifsspc && start > string && nulonly))) {
5077 return;
5078 }
5079 }
5080
5081 sp = (struct strlist *)stalloc(sizeof *sp);
5082 sp->text = start;
5083 *arglist->lastp = sp;
5084 arglist->lastp = &sp->next;
5085}
5086
5087static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005088ifsfree(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005089{
5090 while (ifsfirst.next != NULL) {
5091 struct ifsregion *ifsp;
5092 INTOFF;
5093 ifsp = ifsfirst.next->next;
5094 ckfree(ifsfirst.next);
5095 ifsfirst.next = ifsp;
5096 INTON;
5097 }
5098 ifslastp = NULL;
5099 ifsfirst.next = NULL;
5100}
5101
Eric Andersen2870d962001-07-02 17:27:21 +00005102/*
5103 * Add a file name to the list.
5104 */
Eric Andersencb57d552001-06-28 07:25:16 +00005105
Eric Andersen2870d962001-07-02 17:27:21 +00005106static void
5107addfname(const char *name)
5108{
Eric Andersen2870d962001-07-02 17:27:21 +00005109 struct strlist *sp;
5110
Eric Andersen2870d962001-07-02 17:27:21 +00005111 sp = (struct strlist *)stalloc(sizeof *sp);
Aaron Lehmann95877b62001-12-31 06:00:57 +00005112 sp->text = sstrdup(name);
Eric Andersen2870d962001-07-02 17:27:21 +00005113 *exparg.lastp = sp;
5114 exparg.lastp = &sp->next;
5115}
Eric Andersencb57d552001-06-28 07:25:16 +00005116
5117/*
5118 * Expand shell metacharacters. At this point, the only control characters
5119 * should be escapes. The results are stored in the list exparg.
5120 */
5121
Eric Andersen62483552001-07-10 06:09:16 +00005122#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00005123static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005124expandmeta(struct strlist *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005125{
5126 const char *p;
5127 glob_t pglob;
5128 /* TODO - EXP_REDIR */
5129
5130 while (str) {
5131 if (fflag)
5132 goto nometa;
5133 p = preglob(str->text);
5134 INTOFF;
Eric Andersen34506362001-08-02 05:02:46 +00005135 switch (glob(p, 0, 0, &pglob)) {
Eric Andersencb57d552001-06-28 07:25:16 +00005136 case 0:
Eric Andersen34506362001-08-02 05:02:46 +00005137 if(pglob.gl_pathv[1]==0 && !strcmp(p, pglob.gl_pathv[0]))
Eric Andersencb57d552001-06-28 07:25:16 +00005138 goto nometa2;
5139 addglob(&pglob);
5140 globfree(&pglob);
5141 INTON;
5142 break;
5143 case GLOB_NOMATCH:
5144nometa2:
5145 globfree(&pglob);
5146 INTON;
5147nometa:
5148 *exparg.lastp = str;
5149 rmescapes(str->text);
5150 exparg.lastp = &str->next;
5151 break;
Eric Andersen2870d962001-07-02 17:27:21 +00005152 default: /* GLOB_NOSPACE */
Eric Andersencb57d552001-06-28 07:25:16 +00005153 error("Out of space");
5154 }
5155 str = str->next;
5156 }
5157}
5158
5159
5160/*
5161 * Add the result of glob(3) to the list.
5162 */
5163
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005164static inline void
5165addglob(const glob_t *pglob)
Eric Andersencb57d552001-06-28 07:25:16 +00005166{
5167 char **p = pglob->gl_pathv;
5168
5169 do {
5170 addfname(*p);
5171 } while (*++p);
5172}
5173
5174
Eric Andersen2870d962001-07-02 17:27:21 +00005175#else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005176static char *expdir;
5177
5178
5179static void
Eric Andersenceef50b2001-12-21 11:22:26 +00005180expandmeta(struct strlist *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005181{
5182 char *p;
5183 struct strlist **savelastp;
5184 struct strlist *sp;
5185 char c;
5186 /* TODO - EXP_REDIR */
5187
5188 while (str) {
5189 if (fflag)
5190 goto nometa;
5191 p = str->text;
Eric Andersen2870d962001-07-02 17:27:21 +00005192 for (;;) { /* fast check for meta chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005193 if ((c = *p++) == '\0')
5194 goto nometa;
5195 if (c == '*' || c == '?' || c == '[' || c == '!')
5196 break;
5197 }
5198 savelastp = exparg.lastp;
5199 INTOFF;
5200 if (expdir == NULL) {
5201 int i = strlen(str->text);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005202 expdir = xmalloc(i < 2048 ? 2048 : i); /* XXX */
Eric Andersencb57d552001-06-28 07:25:16 +00005203 }
5204
5205 expmeta(expdir, str->text);
5206 ckfree(expdir);
5207 expdir = NULL;
5208 INTON;
5209 if (exparg.lastp == savelastp) {
5210 /*
5211 * no matches
5212 */
5213nometa:
5214 *exparg.lastp = str;
5215 rmescapes(str->text);
5216 exparg.lastp = &str->next;
5217 } else {
5218 *exparg.lastp = NULL;
5219 *savelastp = sp = expsort(*savelastp);
5220 while (sp->next != NULL)
5221 sp = sp->next;
5222 exparg.lastp = &sp->next;
5223 }
5224 str = str->next;
5225 }
5226}
5227
5228
5229/*
5230 * Do metacharacter (i.e. *, ?, [...]) expansion.
5231 */
5232
5233static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005234expmeta(char *enddir, char *name)
5235{
Eric Andersencb57d552001-06-28 07:25:16 +00005236 char *p;
5237 const char *cp;
5238 char *q;
5239 char *start;
5240 char *endname;
5241 int metaflag;
5242 struct stat statb;
5243 DIR *dirp;
5244 struct dirent *dp;
5245 int atend;
5246 int matchdot;
5247
5248 metaflag = 0;
5249 start = name;
5250 for (p = name ; ; p++) {
5251 if (*p == '*' || *p == '?')
5252 metaflag = 1;
5253 else if (*p == '[') {
5254 q = p + 1;
5255 if (*q == '!')
5256 q++;
5257 for (;;) {
5258 while (*q == CTLQUOTEMARK)
5259 q++;
5260 if (*q == CTLESC)
5261 q++;
5262 if (*q == '/' || *q == '\0')
5263 break;
5264 if (*++q == ']') {
5265 metaflag = 1;
5266 break;
5267 }
5268 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005269 } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) {
Eric Andersencb57d552001-06-28 07:25:16 +00005270 metaflag = 1;
5271 } else if (*p == '\0')
5272 break;
5273 else if (*p == CTLQUOTEMARK)
5274 continue;
5275 else if (*p == CTLESC)
5276 p++;
5277 if (*p == '/') {
5278 if (metaflag)
5279 break;
5280 start = p + 1;
5281 }
5282 }
Eric Andersen2870d962001-07-02 17:27:21 +00005283 if (metaflag == 0) { /* we've reached the end of the file name */
Eric Andersencb57d552001-06-28 07:25:16 +00005284 if (enddir != expdir)
5285 metaflag++;
5286 for (p = name ; ; p++) {
5287 if (*p == CTLQUOTEMARK)
5288 continue;
5289 if (*p == CTLESC)
5290 p++;
5291 *enddir++ = *p;
5292 if (*p == '\0')
5293 break;
5294 }
5295 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5296 addfname(expdir);
5297 return;
5298 }
5299 endname = p;
5300 if (start != name) {
5301 p = name;
5302 while (p < start) {
5303 while (*p == CTLQUOTEMARK)
5304 p++;
5305 if (*p == CTLESC)
5306 p++;
5307 *enddir++ = *p++;
5308 }
5309 }
5310 if (enddir == expdir) {
5311 cp = ".";
5312 } else if (enddir == expdir + 1 && *expdir == '/') {
5313 cp = "/";
5314 } else {
5315 cp = expdir;
5316 enddir[-1] = '\0';
5317 }
5318 if ((dirp = opendir(cp)) == NULL)
5319 return;
5320 if (enddir != expdir)
5321 enddir[-1] = '/';
5322 if (*endname == 0) {
5323 atend = 1;
5324 } else {
5325 atend = 0;
5326 *endname++ = '\0';
5327 }
5328 matchdot = 0;
5329 p = start;
5330 while (*p == CTLQUOTEMARK)
5331 p++;
5332 if (*p == CTLESC)
5333 p++;
5334 if (*p == '.')
5335 matchdot++;
5336 while (! int_pending() && (dp = readdir(dirp)) != NULL) {
5337 if (dp->d_name[0] == '.' && ! matchdot)
5338 continue;
5339 if (patmatch(start, dp->d_name, 0)) {
5340 if (atend) {
Eric Andersen2870d962001-07-02 17:27:21 +00005341 strcpy(enddir, dp->d_name);
Eric Andersencb57d552001-06-28 07:25:16 +00005342 addfname(expdir);
5343 } else {
5344 for (p = enddir, cp = dp->d_name;
5345 (*p++ = *cp++) != '\0';)
5346 continue;
5347 p[-1] = '/';
5348 expmeta(p, endname);
5349 }
5350 }
5351 }
5352 closedir(dirp);
5353 if (! atend)
5354 endname[-1] = '/';
5355}
Eric Andersen2870d962001-07-02 17:27:21 +00005356#endif /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005357
5358
Eric Andersencb57d552001-06-28 07:25:16 +00005359
Eric Andersen62483552001-07-10 06:09:16 +00005360#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersencb57d552001-06-28 07:25:16 +00005361/*
5362 * Sort the results of file name expansion. It calculates the number of
5363 * strings to sort and then calls msort (short for merge sort) to do the
5364 * work.
5365 */
5366
5367static struct strlist *
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005368expsort(struct strlist *str)
5369{
Eric Andersencb57d552001-06-28 07:25:16 +00005370 int len;
5371 struct strlist *sp;
5372
5373 len = 0;
5374 for (sp = str ; sp ; sp = sp->next)
5375 len++;
5376 return msort(str, len);
5377}
5378
5379
5380static struct strlist *
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005381msort(struct strlist *list, int len)
Eric Andersencb57d552001-06-28 07:25:16 +00005382{
5383 struct strlist *p, *q = NULL;
5384 struct strlist **lpp;
5385 int half;
5386 int n;
5387
5388 if (len <= 1)
5389 return list;
5390 half = len >> 1;
5391 p = list;
5392 for (n = half ; --n >= 0 ; ) {
5393 q = p;
5394 p = p->next;
5395 }
Eric Andersen2870d962001-07-02 17:27:21 +00005396 q->next = NULL; /* terminate first half of list */
5397 q = msort(list, half); /* sort first half of list */
5398 p = msort(p, len - half); /* sort second half */
Eric Andersencb57d552001-06-28 07:25:16 +00005399 lpp = &list;
5400 for (;;) {
5401 if (strcmp(p->text, q->text) < 0) {
5402 *lpp = p;
5403 lpp = &p->next;
5404 if ((p = *lpp) == NULL) {
5405 *lpp = q;
5406 break;
5407 }
5408 } else {
5409 *lpp = q;
5410 lpp = &q->next;
5411 if ((q = *lpp) == NULL) {
5412 *lpp = p;
5413 break;
5414 }
5415 }
5416 }
5417 return list;
5418}
5419#endif
5420
5421
5422
5423/*
5424 * Returns true if the pattern matches the string.
5425 */
5426
Eric Andersen62483552001-07-10 06:09:16 +00005427#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00005428/* squoted: string might have quote chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005429static int
Eric Andersen2870d962001-07-02 17:27:21 +00005430patmatch(char *pattern, char *string, int squoted)
5431{
Eric Andersencb57d552001-06-28 07:25:16 +00005432 const char *p;
5433 char *q;
5434
5435 p = preglob(pattern);
5436 q = squoted ? _rmescapes(string, RMESCAPE_ALLOC) : string;
5437
5438 return !fnmatch(p, q, 0);
5439}
5440
5441
5442static int
Eric Andersen2870d962001-07-02 17:27:21 +00005443patmatch2(char *pattern, char *string, int squoted)
5444{
Eric Andersencb57d552001-06-28 07:25:16 +00005445 char *p;
5446 int res;
5447
5448 sstrnleft--;
5449 p = grabstackstr(expdest);
5450 res = patmatch(pattern, string, squoted);
5451 ungrabstackstr(p, expdest);
5452 return res;
5453}
5454#else
5455static int
Eric Andersen2870d962001-07-02 17:27:21 +00005456patmatch(char *pattern, char *string, int squoted) {
5457 return pmatch(pattern, string, squoted);
Eric Andersencb57d552001-06-28 07:25:16 +00005458}
5459
5460
5461static int
Eric Andersen2870d962001-07-02 17:27:21 +00005462pmatch(char *pattern, char *string, int squoted)
5463{
Eric Andersencb57d552001-06-28 07:25:16 +00005464 char *p, *q;
5465 char c;
5466
5467 p = pattern;
5468 q = string;
5469 for (;;) {
5470 switch (c = *p++) {
5471 case '\0':
5472 goto breakloop;
5473 case CTLESC:
5474 if (squoted && *q == CTLESC)
5475 q++;
5476 if (*q++ != *p++)
5477 return 0;
5478 break;
5479 case CTLQUOTEMARK:
5480 continue;
5481 case '?':
5482 if (squoted && *q == CTLESC)
5483 q++;
5484 if (*q++ == '\0')
5485 return 0;
5486 break;
5487 case '*':
5488 c = *p;
5489 while (c == CTLQUOTEMARK || c == '*')
5490 c = *++p;
5491 if (c != CTLESC && c != CTLQUOTEMARK &&
5492 c != '?' && c != '*' && c != '[') {
5493 while (*q != c) {
5494 if (squoted && *q == CTLESC &&
5495 q[1] == c)
5496 break;
5497 if (*q == '\0')
5498 return 0;
5499 if (squoted && *q == CTLESC)
5500 q++;
5501 q++;
5502 }
5503 }
5504 do {
5505 if (pmatch(p, q, squoted))
5506 return 1;
5507 if (squoted && *q == CTLESC)
5508 q++;
5509 } while (*q++ != '\0');
5510 return 0;
5511 case '[': {
5512 char *endp;
5513 int invert, found;
5514 char chr;
5515
5516 endp = p;
5517 if (*endp == '!')
5518 endp++;
5519 for (;;) {
5520 while (*endp == CTLQUOTEMARK)
5521 endp++;
5522 if (*endp == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00005523 goto dft; /* no matching ] */
Eric Andersencb57d552001-06-28 07:25:16 +00005524 if (*endp == CTLESC)
5525 endp++;
5526 if (*++endp == ']')
5527 break;
5528 }
5529 invert = 0;
5530 if (*p == '!') {
5531 invert++;
5532 p++;
5533 }
5534 found = 0;
5535 chr = *q++;
5536 if (squoted && chr == CTLESC)
5537 chr = *q++;
5538 if (chr == '\0')
5539 return 0;
5540 c = *p++;
5541 do {
5542 if (c == CTLQUOTEMARK)
5543 continue;
5544 if (c == CTLESC)
5545 c = *p++;
5546 if (*p == '-' && p[1] != ']') {
5547 p++;
5548 while (*p == CTLQUOTEMARK)
5549 p++;
5550 if (*p == CTLESC)
5551 p++;
5552 if (chr >= c && chr <= *p)
5553 found = 1;
5554 p++;
5555 } else {
5556 if (chr == c)
5557 found = 1;
5558 }
5559 } while ((c = *p++) != ']');
5560 if (found == invert)
5561 return 0;
5562 break;
5563 }
Eric Andersen2870d962001-07-02 17:27:21 +00005564dft: default:
Eric Andersencb57d552001-06-28 07:25:16 +00005565 if (squoted && *q == CTLESC)
5566 q++;
5567 if (*q++ != c)
5568 return 0;
5569 break;
5570 }
5571 }
5572breakloop:
5573 if (*q != '\0')
5574 return 0;
5575 return 1;
5576}
5577#endif
5578
5579
5580
5581/*
5582 * Remove any CTLESC characters from a string.
5583 */
5584
Eric Andersen62483552001-07-10 06:09:16 +00005585#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00005586static char *
Eric Andersen2870d962001-07-02 17:27:21 +00005587_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005588{
5589 char *p, *q, *r;
5590 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5591
5592 p = strpbrk(str, qchars);
5593 if (!p) {
5594 return str;
5595 }
5596 q = p;
5597 r = str;
5598 if (flag & RMESCAPE_ALLOC) {
5599 size_t len = p - str;
5600 q = r = stalloc(strlen(p) + len + 1);
5601 if (len > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00005602 memcpy(q, str, len);
5603 q += len;
Eric Andersencb57d552001-06-28 07:25:16 +00005604 }
5605 }
5606 while (*p) {
5607 if (*p == CTLQUOTEMARK) {
5608 p++;
5609 continue;
5610 }
5611 if (*p == CTLESC) {
5612 p++;
5613 if (flag & RMESCAPE_GLOB && *p != '/') {
5614 *q++ = '\\';
5615 }
5616 }
5617 *q++ = *p++;
5618 }
5619 *q = '\0';
5620 return r;
5621}
5622#else
5623static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005624rmescapes(char *str)
Eric Andersencb57d552001-06-28 07:25:16 +00005625{
5626 char *p, *q;
5627
5628 p = str;
5629 while (*p != CTLESC && *p != CTLQUOTEMARK) {
5630 if (*p++ == '\0')
5631 return;
5632 }
5633 q = p;
5634 while (*p) {
5635 if (*p == CTLQUOTEMARK) {
5636 p++;
5637 continue;
5638 }
5639 if (*p == CTLESC)
5640 p++;
5641 *q++ = *p++;
5642 }
5643 *q = '\0';
5644}
5645#endif
5646
5647
5648
5649/*
5650 * See if a pattern matches in a case statement.
5651 */
5652
5653static int
Eric Andersen2870d962001-07-02 17:27:21 +00005654casematch(union node *pattern, const char *val)
5655{
Eric Andersencb57d552001-06-28 07:25:16 +00005656 struct stackmark smark;
5657 int result;
5658 char *p;
5659
5660 setstackmark(&smark);
5661 argbackq = pattern->narg.backquote;
5662 STARTSTACKSTR(expdest);
5663 ifslastp = NULL;
5664 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5665 STPUTC('\0', expdest);
5666 p = grabstackstr(expdest);
Eric Andersen2870d962001-07-02 17:27:21 +00005667 result = patmatch(p, (char *)val, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00005668 popstackmark(&smark);
5669 return result;
5670}
5671
5672/*
5673 * Our own itoa().
5674 */
5675
5676static char *
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005677cvtnum(int num, char *buf)
5678{
Eric Andersencb57d552001-06-28 07:25:16 +00005679 int len;
5680
5681 CHECKSTRSPACE(32, buf);
5682 len = sprintf(buf, "%d", num);
5683 STADJUST(len, buf);
5684 return buf;
5685}
Eric Andersencb57d552001-06-28 07:25:16 +00005686/*
5687 * Editline and history functions (and glue).
5688 */
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005689static int histcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00005690{
5691 error("not compiled with history support");
5692 /* NOTREACHED */
5693}
5694
5695
Eric Andersencb57d552001-06-28 07:25:16 +00005696struct redirtab {
5697 struct redirtab *next;
Russ Dill4db35642001-07-26 05:58:40 +00005698 short renamed[10]; /* Current ash support only 0-9 descriptors */
Eric Andersen34506362001-08-02 05:02:46 +00005699 /* char on arm (and others) can't be negative */
Eric Andersencb57d552001-06-28 07:25:16 +00005700};
5701
Eric Andersen2870d962001-07-02 17:27:21 +00005702static struct redirtab *redirlist;
Eric Andersencb57d552001-06-28 07:25:16 +00005703
5704extern char **environ;
5705
5706
5707
5708/*
5709 * Initialization code.
5710 */
5711
5712static void
Eric Andersen2870d962001-07-02 17:27:21 +00005713init(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00005714
5715 /* from cd.c: */
5716 {
Eric Andersena3483db2001-10-24 08:01:06 +00005717 curdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00005718 setpwd(0, 0);
5719 }
5720
5721 /* from input.c: */
5722 {
5723 basepf.nextc = basepf.buf = basebuf;
5724 }
5725
Eric Andersencb57d552001-06-28 07:25:16 +00005726 /* from var.c: */
5727 {
5728 char **envp;
5729 char ppid[32];
5730
5731 initvar();
5732 for (envp = environ ; *envp ; envp++) {
5733 if (strchr(*envp, '=')) {
5734 setvareq(*envp, VEXPORT|VTEXTFIXED);
5735 }
5736 }
5737
Eric Andersen3102ac42001-07-06 04:26:23 +00005738 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
Eric Andersencb57d552001-06-28 07:25:16 +00005739 setvar("PPID", ppid, 0);
5740 }
5741}
5742
5743
5744
5745/*
5746 * This routine is called when an error or an interrupt occurs in an
5747 * interactive shell and control is returned to the main command loop.
5748 */
5749
Eric Andersen2870d962001-07-02 17:27:21 +00005750/* 1 == check for aliases, 2 == also check for assignments */
Eric Andersen7467c8d2001-07-12 20:26:32 +00005751static int checkalias; /* also used in no alias mode for check assignments */
Eric Andersen2870d962001-07-02 17:27:21 +00005752
Eric Andersencb57d552001-06-28 07:25:16 +00005753static void
Eric Andersen2870d962001-07-02 17:27:21 +00005754reset(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00005755
5756 /* from eval.c: */
5757 {
5758 evalskip = 0;
5759 loopnest = 0;
5760 funcnest = 0;
5761 }
5762
5763 /* from input.c: */
5764 {
5765 if (exception != EXSHELLPROC)
Eric Andersen2870d962001-07-02 17:27:21 +00005766 parselleft = parsenleft = 0; /* clear input buffer */
Eric Andersencb57d552001-06-28 07:25:16 +00005767 popallfiles();
5768 }
5769
5770 /* from parser.c: */
5771 {
5772 tokpushback = 0;
5773 checkkwd = 0;
5774 checkalias = 0;
5775 }
5776
5777 /* from redir.c: */
5778 {
5779 while (redirlist)
5780 popredir();
5781 }
5782
Eric Andersencb57d552001-06-28 07:25:16 +00005783}
5784
5785
5786
5787/*
Eric Andersencb57d552001-06-28 07:25:16 +00005788 * This file implements the input routines used by the parser.
5789 */
5790
Eric Andersenbdfd0d72001-10-24 05:00:29 +00005791#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersencb57d552001-06-28 07:25:16 +00005792static const char * cmdedit_prompt;
5793static inline void putprompt(const char *s) {
5794 cmdedit_prompt = s;
5795}
5796#else
5797static inline void putprompt(const char *s) {
5798 out2str(s);
5799}
5800#endif
5801
Eric Andersen2870d962001-07-02 17:27:21 +00005802#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
Eric Andersencb57d552001-06-28 07:25:16 +00005803
Eric Andersencb57d552001-06-28 07:25:16 +00005804
Eric Andersencb57d552001-06-28 07:25:16 +00005805
Eric Andersen2870d962001-07-02 17:27:21 +00005806/*
5807 * Same as pgetc(), but ignores PEOA.
5808 */
Eric Andersencb57d552001-06-28 07:25:16 +00005809
Eric Andersend35c5df2002-01-09 15:37:36 +00005810#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00005811static int
Eric Andersen74400cc2001-10-18 04:11:39 +00005812pgetc2(void)
Eric Andersen2870d962001-07-02 17:27:21 +00005813{
5814 int c;
5815 do {
5816 c = pgetc_macro();
5817 } while (c == PEOA);
5818 return c;
Eric Andersencb57d552001-06-28 07:25:16 +00005819}
Eric Andersen2870d962001-07-02 17:27:21 +00005820#else
Eric Andersend35c5df2002-01-09 15:37:36 +00005821static inline int pgetc2(void) { return pgetc_macro(); }
Eric Andersencb57d552001-06-28 07:25:16 +00005822#endif
5823
Eric Andersencb57d552001-06-28 07:25:16 +00005824/*
5825 * Read a line from the script.
5826 */
5827
Eric Andersen62483552001-07-10 06:09:16 +00005828static inline char *
Eric Andersen2870d962001-07-02 17:27:21 +00005829pfgets(char *line, int len)
Eric Andersencb57d552001-06-28 07:25:16 +00005830{
5831 char *p = line;
5832 int nleft = len;
5833 int c;
5834
5835 while (--nleft > 0) {
5836 c = pgetc2();
5837 if (c == PEOF) {
5838 if (p == line)
5839 return NULL;
5840 break;
5841 }
5842 *p++ = c;
5843 if (c == '\n')
5844 break;
5845 }
5846 *p = '\0';
5847 return line;
5848}
5849
Eric Andersen62483552001-07-10 06:09:16 +00005850static inline int
Eric Andersen2870d962001-07-02 17:27:21 +00005851preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005852{
5853 int nr;
5854 char *buf = parsefile->buf;
5855 parsenextc = buf;
5856
5857retry:
Eric Andersenbdfd0d72001-10-24 05:00:29 +00005858#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersencb57d552001-06-28 07:25:16 +00005859 {
Eric Andersen34506362001-08-02 05:02:46 +00005860 if (!iflag || parsefile->fd)
Eric Andersen7467c8d2001-07-12 20:26:32 +00005861 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersen2870d962001-07-02 17:27:21 +00005862 else {
Eric Andersen044228d2001-07-17 01:12:36 +00005863 nr = cmdedit_read_input((char*)cmdedit_prompt, buf);
Eric Andersencb57d552001-06-28 07:25:16 +00005864 }
5865 }
5866#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00005867 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00005868#endif
5869
5870 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00005871 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
5872 int flags = fcntl(0, F_GETFL, 0);
5873 if (flags >= 0 && flags & O_NONBLOCK) {
5874 flags &=~ O_NONBLOCK;
5875 if (fcntl(0, F_SETFL, flags) >= 0) {
5876 out2str("sh: turning off NDELAY mode\n");
5877 goto retry;
5878 }
5879 }
5880 }
5881 }
5882 return nr;
5883}
5884
Eric Andersen2870d962001-07-02 17:27:21 +00005885static void
5886popstring(void)
5887{
5888 struct strpush *sp = parsefile->strpush;
5889
5890 INTOFF;
Eric Andersend35c5df2002-01-09 15:37:36 +00005891#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00005892 if (sp->ap) {
5893 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
5894 if (!checkalias) {
5895 checkalias = 1;
5896 }
5897 }
5898 if (sp->string != sp->ap->val) {
5899 ckfree(sp->string);
5900 }
5901
5902 sp->ap->flag &= ~ALIASINUSE;
5903 if (sp->ap->flag & ALIASDEAD) {
5904 unalias(sp->ap->name);
5905 }
5906 }
5907#endif
5908 parsenextc = sp->prevstring;
5909 parsenleft = sp->prevnleft;
5910/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
5911 parsefile->strpush = sp->prev;
5912 if (sp != &(parsefile->basestrpush))
5913 ckfree(sp);
5914 INTON;
5915}
5916
5917
Eric Andersencb57d552001-06-28 07:25:16 +00005918/*
5919 * Refill the input buffer and return the next input character:
5920 *
5921 * 1) If a string was pushed back on the input, pop it;
5922 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
5923 * from a string so we can't refill the buffer, return EOF.
5924 * 3) If the is more stuff in this buffer, use it else call read to fill it.
5925 * 4) Process input up to the next newline, deleting nul characters.
5926 */
5927
5928static int
Eric Andersen2870d962001-07-02 17:27:21 +00005929preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005930{
5931 char *p, *q;
5932 int more;
5933 char savec;
5934
5935 while (parsefile->strpush) {
Eric Andersend35c5df2002-01-09 15:37:36 +00005936#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00005937 if (parsenleft == -1 && parsefile->strpush->ap &&
5938 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00005939 return PEOA;
5940 }
Eric Andersen2870d962001-07-02 17:27:21 +00005941#endif
Eric Andersencb57d552001-06-28 07:25:16 +00005942 popstring();
5943 if (--parsenleft >= 0)
5944 return (*parsenextc++);
5945 }
5946 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
5947 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00005948 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00005949
5950again:
5951 if (parselleft <= 0) {
5952 if ((parselleft = preadfd()) <= 0) {
5953 parselleft = parsenleft = EOF_NLEFT;
5954 return PEOF;
5955 }
5956 }
5957
5958 q = p = parsenextc;
5959
5960 /* delete nul characters */
5961 for (more = 1; more;) {
5962 switch (*p) {
5963 case '\0':
Eric Andersen2870d962001-07-02 17:27:21 +00005964 p++; /* Skip nul */
Eric Andersencb57d552001-06-28 07:25:16 +00005965 goto check;
5966
5967
5968 case '\n':
5969 parsenleft = q - parsenextc;
5970 more = 0; /* Stop processing here */
5971 break;
5972 }
5973
5974 *q++ = *p++;
5975check:
5976 if (--parselleft <= 0 && more) {
5977 parsenleft = q - parsenextc - 1;
5978 if (parsenleft < 0)
5979 goto again;
5980 more = 0;
5981 }
5982 }
5983
5984 savec = *q;
5985 *q = '\0';
5986
5987 if (vflag) {
5988 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00005989 }
5990
5991 *q = savec;
5992
5993 return *parsenextc++;
5994}
5995
Eric Andersencb57d552001-06-28 07:25:16 +00005996
5997/*
5998 * Push a string back onto the input at this current parsefile level.
5999 * We handle aliases this way.
6000 */
6001static void
Eric Andersen2870d962001-07-02 17:27:21 +00006002pushstring(char *s, int len, void *ap)
6003{
Eric Andersencb57d552001-06-28 07:25:16 +00006004 struct strpush *sp;
6005
6006 INTOFF;
6007/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6008 if (parsefile->strpush) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006009 sp = xmalloc(sizeof (struct strpush));
Eric Andersencb57d552001-06-28 07:25:16 +00006010 sp->prev = parsefile->strpush;
6011 parsefile->strpush = sp;
6012 } else
6013 sp = parsefile->strpush = &(parsefile->basestrpush);
6014 sp->prevstring = parsenextc;
6015 sp->prevnleft = parsenleft;
Eric Andersend35c5df2002-01-09 15:37:36 +00006016#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00006017 sp->ap = (struct alias *)ap;
6018 if (ap) {
6019 ((struct alias *)ap)->flag |= ALIASINUSE;
6020 sp->string = s;
6021 }
Eric Andersen2870d962001-07-02 17:27:21 +00006022#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006023 parsenextc = s;
6024 parsenleft = len;
6025 INTON;
6026}
6027
Eric Andersencb57d552001-06-28 07:25:16 +00006028
Eric Andersencb57d552001-06-28 07:25:16 +00006029/*
6030 * Like setinputfile, but takes input from a string.
6031 */
6032
6033static void
Eric Andersen62483552001-07-10 06:09:16 +00006034setinputstring(char *string)
6035{
Eric Andersencb57d552001-06-28 07:25:16 +00006036 INTOFF;
6037 pushfile();
6038 parsenextc = string;
6039 parsenleft = strlen(string);
6040 parsefile->buf = NULL;
6041 plinno = 1;
6042 INTON;
6043}
6044
6045
6046
6047/*
6048 * To handle the "." command, a stack of input files is used. Pushfile
6049 * adds a new entry to the stack and popfile restores the previous level.
6050 */
6051
6052static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006053pushfile(void)
6054{
Eric Andersencb57d552001-06-28 07:25:16 +00006055 struct parsefile *pf;
6056
6057 parsefile->nleft = parsenleft;
6058 parsefile->lleft = parselleft;
6059 parsefile->nextc = parsenextc;
6060 parsefile->linno = plinno;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006061 pf = (struct parsefile *)xmalloc(sizeof (struct parsefile));
Eric Andersencb57d552001-06-28 07:25:16 +00006062 pf->prev = parsefile;
6063 pf->fd = -1;
6064 pf->strpush = NULL;
6065 pf->basestrpush.prev = NULL;
6066 parsefile = pf;
6067}
6068
Eric Andersend35c5df2002-01-09 15:37:36 +00006069#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen2870d962001-07-02 17:27:21 +00006070static void restartjob (struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00006071#endif
Eric Andersen2870d962001-07-02 17:27:21 +00006072static void freejob (struct job *);
6073static struct job *getjob (const char *);
6074static int dowait (int, struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00006075static void waitonint(int);
6076
6077
Eric Andersen2870d962001-07-02 17:27:21 +00006078/*
6079 * We keep track of whether or not fd0 has been redirected. This is for
6080 * background commands, where we want to redirect fd0 to /dev/null only
6081 * if it hasn't already been redirected.
6082*/
6083static int fd0_redirected = 0;
6084
6085/* Return true if fd 0 has already been redirected at least once. */
6086static inline int
Eric Andersen74400cc2001-10-18 04:11:39 +00006087fd0_redirected_p (void)
6088{
Eric Andersen2870d962001-07-02 17:27:21 +00006089 return fd0_redirected != 0;
6090}
6091
Eric Andersen62483552001-07-10 06:09:16 +00006092static void dupredirect (const union node *, int, int fd1dup);
Eric Andersen2870d962001-07-02 17:27:21 +00006093
Eric Andersend35c5df2002-01-09 15:37:36 +00006094#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006095/*
6096 * Turn job control on and off.
6097 *
6098 * Note: This code assumes that the third arg to ioctl is a character
6099 * pointer, which is true on Berkeley systems but not System V. Since
6100 * System V doesn't have job control yet, this isn't a problem now.
6101 */
6102
Eric Andersen2870d962001-07-02 17:27:21 +00006103
Eric Andersencb57d552001-06-28 07:25:16 +00006104
6105static void setjobctl(int enable)
6106{
6107#ifdef OLD_TTY_DRIVER
6108 int ldisc;
6109#endif
6110
6111 if (enable == jobctl || rootshell == 0)
6112 return;
6113 if (enable) {
6114 do { /* while we are in the background */
6115#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006116 if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006117#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006118 initialpgrp = tcgetpgrp(2);
Eric Andersencb57d552001-06-28 07:25:16 +00006119 if (initialpgrp < 0) {
6120#endif
Eric Andersen8c145dc2001-07-10 16:57:09 +00006121 out2str("sh: can't access tty; job control turned off\n");
Eric Andersencb57d552001-06-28 07:25:16 +00006122 mflag = 0;
6123 return;
6124 }
6125 if (initialpgrp == -1)
6126 initialpgrp = getpgrp();
6127 else if (initialpgrp != getpgrp()) {
6128 killpg(initialpgrp, SIGTTIN);
6129 continue;
6130 }
6131 } while (0);
6132#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006133 if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
Eric Andersen8c145dc2001-07-10 16:57:09 +00006134 out2str("sh: need new tty driver to run job control; job control turned off\n");
Eric Andersencb57d552001-06-28 07:25:16 +00006135 mflag = 0;
6136 return;
6137 }
6138#endif
6139 setsignal(SIGTSTP);
6140 setsignal(SIGTTOU);
6141 setsignal(SIGTTIN);
6142 setpgid(0, rootpid);
6143#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006144 ioctl(2, TIOCSPGRP, (char *)&rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00006145#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006146 tcsetpgrp(2, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00006147#endif
Eric Andersen8c145dc2001-07-10 16:57:09 +00006148 } else { /* turning job control off */
Eric Andersencb57d552001-06-28 07:25:16 +00006149 setpgid(0, initialpgrp);
6150#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006151 ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006152#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006153 tcsetpgrp(2, initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006154#endif
6155 setsignal(SIGTSTP);
6156 setsignal(SIGTTOU);
6157 setsignal(SIGTTIN);
6158 }
6159 jobctl = enable;
6160}
6161#endif
6162
6163
Eric Andersend35c5df2002-01-09 15:37:36 +00006164#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006165static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006166killcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006167{
6168 int signo = -1;
6169 int list = 0;
6170 int i;
6171 pid_t pid;
6172 struct job *jp;
6173
6174 if (argc <= 1) {
6175usage:
6176 error(
6177"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6178"kill -l [exitstatus]"
6179 );
6180 }
6181
6182 if (*argv[1] == '-') {
6183 signo = decode_signal(argv[1] + 1, 1);
6184 if (signo < 0) {
6185 int c;
6186
6187 while ((c = nextopt("ls:")) != '\0')
6188 switch (c) {
6189 case 'l':
6190 list = 1;
6191 break;
6192 case 's':
6193 signo = decode_signal(optionarg, 1);
6194 if (signo < 0) {
6195 error(
6196 "invalid signal number or name: %s",
6197 optionarg
6198 );
6199 }
Eric Andersen2870d962001-07-02 17:27:21 +00006200 break;
Eric Andersencb57d552001-06-28 07:25:16 +00006201#ifdef DEBUG
6202 default:
6203 error(
6204 "nextopt returned character code 0%o", c);
6205#endif
6206 }
6207 } else
6208 argptr++;
6209 }
6210
6211 if (!list && signo < 0)
6212 signo = SIGTERM;
6213
6214 if ((signo < 0 || !*argptr) ^ list) {
6215 goto usage;
6216 }
6217
6218 if (list) {
Eric Andersen34506362001-08-02 05:02:46 +00006219 const char *name;
6220
Eric Andersencb57d552001-06-28 07:25:16 +00006221 if (!*argptr) {
6222 out1str("0\n");
6223 for (i = 1; i < NSIG; i++) {
Eric Andersen34506362001-08-02 05:02:46 +00006224 name = u_signal_names(0, &i, 1);
6225 if(name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006226 puts(name);
Eric Andersencb57d552001-06-28 07:25:16 +00006227 }
6228 return 0;
6229 }
Eric Andersen34506362001-08-02 05:02:46 +00006230 name = u_signal_names(*argptr, &signo, -1);
6231 if (name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006232 puts(name);
Eric Andersencb57d552001-06-28 07:25:16 +00006233 else
6234 error("invalid signal number or exit status: %s",
6235 *argptr);
6236 return 0;
6237 }
6238
6239 do {
6240 if (**argptr == '%') {
6241 jp = getjob(*argptr);
6242 if (jp->jobctl == 0)
6243 error("job %s not created under job control",
6244 *argptr);
6245 pid = -jp->ps[0].pid;
6246 } else
6247 pid = atoi(*argptr);
6248 if (kill(pid, signo) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00006249 error("%s: %m", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006250 } while (*++argptr);
6251
6252 return 0;
6253}
6254
6255static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006256fgcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006257{
6258 struct job *jp;
6259 int pgrp;
6260 int status;
6261
6262 jp = getjob(argv[1]);
6263 if (jp->jobctl == 0)
6264 error("job not created under job control");
6265 pgrp = jp->ps[0].pid;
6266#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006267 ioctl(2, TIOCSPGRP, (char *)&pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006268#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006269 tcsetpgrp(2, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006270#endif
6271 restartjob(jp);
Eric Andersencb57d552001-06-28 07:25:16 +00006272 status = waitforjob(jp);
Eric Andersencb57d552001-06-28 07:25:16 +00006273 return status;
6274}
6275
6276
6277static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006278bgcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006279{
6280 struct job *jp;
6281
6282 do {
6283 jp = getjob(*++argv);
6284 if (jp->jobctl == 0)
6285 error("job not created under job control");
6286 restartjob(jp);
6287 } while (--argc > 1);
6288 return 0;
6289}
6290
6291
6292static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006293restartjob(struct job *jp)
Eric Andersencb57d552001-06-28 07:25:16 +00006294{
6295 struct procstat *ps;
6296 int i;
6297
6298 if (jp->state == JOBDONE)
6299 return;
6300 INTOFF;
6301 killpg(jp->ps[0].pid, SIGCONT);
6302 for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
6303 if (WIFSTOPPED(ps->status)) {
6304 ps->status = -1;
6305 jp->state = 0;
6306 }
6307 }
6308 INTON;
6309}
6310#endif
6311
Eric Andersen2870d962001-07-02 17:27:21 +00006312static void showjobs(int change);
6313
Eric Andersencb57d552001-06-28 07:25:16 +00006314
6315static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006316jobscmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006317{
6318 showjobs(0);
6319 return 0;
6320}
6321
6322
6323/*
6324 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6325 * statuses have changed since the last call to showjobs.
6326 *
6327 * If the shell is interrupted in the process of creating a job, the
6328 * result may be a job structure containing zero processes. Such structures
6329 * will be freed here.
6330 */
6331
6332static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006333showjobs(int change)
Eric Andersencb57d552001-06-28 07:25:16 +00006334{
6335 int jobno;
6336 int procno;
6337 int i;
6338 struct job *jp;
6339 struct procstat *ps;
6340 int col;
6341 char s[64];
6342
6343 TRACE(("showjobs(%d) called\n", change));
6344 while (dowait(0, (struct job *)NULL) > 0);
6345 for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
6346 if (! jp->used)
6347 continue;
6348 if (jp->nprocs == 0) {
6349 freejob(jp);
6350 continue;
6351 }
6352 if (change && ! jp->changed)
6353 continue;
6354 procno = jp->nprocs;
Eric Andersen2870d962001-07-02 17:27:21 +00006355 for (ps = jp->ps ; ; ps++) { /* for each process */
Eric Andersencb57d552001-06-28 07:25:16 +00006356 if (ps == jp->ps)
Eric Andersen3102ac42001-07-06 04:26:23 +00006357 snprintf(s, 64, "[%d] %ld ", jobno,
Eric Andersencb57d552001-06-28 07:25:16 +00006358 (long)ps->pid);
6359 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006360 snprintf(s, 64, " %ld ",
Eric Andersencb57d552001-06-28 07:25:16 +00006361 (long)ps->pid);
6362 out1str(s);
6363 col = strlen(s);
6364 s[0] = '\0';
6365 if (ps->status == -1) {
6366 /* don't print anything */
6367 } else if (WIFEXITED(ps->status)) {
Eric Andersen3102ac42001-07-06 04:26:23 +00006368 snprintf(s, 64, "Exit %d",
Eric Andersencb57d552001-06-28 07:25:16 +00006369 WEXITSTATUS(ps->status));
6370 } else {
Eric Andersend35c5df2002-01-09 15:37:36 +00006371#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen2870d962001-07-02 17:27:21 +00006372 if (WIFSTOPPED(ps->status))
Eric Andersencb57d552001-06-28 07:25:16 +00006373 i = WSTOPSIG(ps->status);
6374 else /* WIFSIGNALED(ps->status) */
6375#endif
6376 i = WTERMSIG(ps->status);
6377 if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
Eric Andersen2870d962001-07-02 17:27:21 +00006378 strcpy(s, sys_siglist[i & 0x7F]);
Eric Andersencb57d552001-06-28 07:25:16 +00006379 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006380 snprintf(s, 64, "Signal %d", i & 0x7F);
Eric Andersencb57d552001-06-28 07:25:16 +00006381 if (WCOREDUMP(ps->status))
6382 strcat(s, " (core dumped)");
6383 }
6384 out1str(s);
6385 col += strlen(s);
Eric Andersen62483552001-07-10 06:09:16 +00006386 printf(
Eric Andersencb57d552001-06-28 07:25:16 +00006387 "%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ',
6388 ps->cmd
6389 );
6390 if (--procno <= 0)
6391 break;
6392 }
6393 jp->changed = 0;
6394 if (jp->state == JOBDONE) {
6395 freejob(jp);
6396 }
6397 }
6398}
6399
6400
6401/*
6402 * Mark a job structure as unused.
6403 */
6404
6405static void
Eric Andersen62483552001-07-10 06:09:16 +00006406freejob(struct job *jp)
6407{
6408 const struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006409 int i;
6410
6411 INTOFF;
6412 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6413 if (ps->cmd != nullstr)
6414 ckfree(ps->cmd);
6415 }
6416 if (jp->ps != &jp->ps0)
6417 ckfree(jp->ps);
6418 jp->used = 0;
Eric Andersend35c5df2002-01-09 15:37:36 +00006419#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006420 if (curjob == jp - jobtab + 1)
6421 curjob = 0;
6422#endif
6423 INTON;
6424}
6425
6426
6427
6428static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006429waitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006430{
6431 struct job *job;
6432 int status, retval;
6433 struct job *jp;
6434
6435 if (--argc > 0) {
6436start:
6437 job = getjob(*++argv);
6438 } else {
6439 job = NULL;
6440 }
Eric Andersen2870d962001-07-02 17:27:21 +00006441 for (;;) { /* loop until process terminated or stopped */
Eric Andersencb57d552001-06-28 07:25:16 +00006442 if (job != NULL) {
6443 if (job->state) {
6444 status = job->ps[job->nprocs - 1].status;
6445 if (! iflag)
6446 freejob(job);
6447 if (--argc) {
6448 goto start;
6449 }
6450 if (WIFEXITED(status))
6451 retval = WEXITSTATUS(status);
Eric Andersend35c5df2002-01-09 15:37:36 +00006452#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006453 else if (WIFSTOPPED(status))
6454 retval = WSTOPSIG(status) + 128;
6455#endif
6456 else {
6457 /* XXX: limits number of signals */
6458 retval = WTERMSIG(status) + 128;
6459 }
6460 return retval;
6461 }
6462 } else {
6463 for (jp = jobtab ; ; jp++) {
Eric Andersen2870d962001-07-02 17:27:21 +00006464 if (jp >= jobtab + njobs) { /* no running procs */
Eric Andersencb57d552001-06-28 07:25:16 +00006465 return 0;
6466 }
6467 if (jp->used && jp->state == 0)
6468 break;
6469 }
6470 }
6471 if (dowait(2, 0) < 0 && errno == EINTR) {
6472 return 129;
6473 }
6474 }
6475}
6476
6477
6478
6479/*
6480 * Convert a job name to a job structure.
6481 */
6482
6483static struct job *
Eric Andersen2870d962001-07-02 17:27:21 +00006484getjob(const char *name)
6485{
Eric Andersencb57d552001-06-28 07:25:16 +00006486 int jobno;
6487 struct job *jp;
6488 int pid;
6489 int i;
6490
6491 if (name == NULL) {
Eric Andersend35c5df2002-01-09 15:37:36 +00006492#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006493currentjob:
6494 if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
6495 error("No current job");
6496 return &jobtab[jobno - 1];
6497#else
6498 error("No current job");
6499#endif
6500 } else if (name[0] == '%') {
6501 if (is_digit(name[1])) {
6502 jobno = number(name + 1);
6503 if (jobno > 0 && jobno <= njobs
6504 && jobtab[jobno - 1].used != 0)
6505 return &jobtab[jobno - 1];
Eric Andersend35c5df2002-01-09 15:37:36 +00006506#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006507 } else if (name[1] == '%' && name[2] == '\0') {
6508 goto currentjob;
6509#endif
6510 } else {
6511 struct job *found = NULL;
6512 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
6513 if (jp->used && jp->nprocs > 0
6514 && prefix(name + 1, jp->ps[0].cmd)) {
6515 if (found)
6516 error("%s: ambiguous", name);
6517 found = jp;
6518 }
6519 }
6520 if (found)
6521 return found;
6522 }
Eric Andersen2870d962001-07-02 17:27:21 +00006523 } else if (is_number(name, &pid)) {
Eric Andersencb57d552001-06-28 07:25:16 +00006524 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
6525 if (jp->used && jp->nprocs > 0
6526 && jp->ps[jp->nprocs - 1].pid == pid)
6527 return jp;
6528 }
6529 }
6530 error("No such job: %s", name);
6531 /* NOTREACHED */
6532}
6533
6534
6535
6536/*
6537 * Return a new job structure,
6538 */
6539
Eric Andersen2870d962001-07-02 17:27:21 +00006540static struct job *
Eric Andersen62483552001-07-10 06:09:16 +00006541makejob(const union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00006542{
6543 int i;
6544 struct job *jp;
6545
6546 for (i = njobs, jp = jobtab ; ; jp++) {
6547 if (--i < 0) {
6548 INTOFF;
6549 if (njobs == 0) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006550 jobtab = xmalloc(4 * sizeof jobtab[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00006551 } else {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006552 jp = xmalloc((njobs + 4) * sizeof jobtab[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00006553 memcpy(jp, jobtab, njobs * sizeof jp[0]);
6554 /* Relocate `ps' pointers */
6555 for (i = 0; i < njobs; i++)
6556 if (jp[i].ps == &jobtab[i].ps0)
6557 jp[i].ps = &jp[i].ps0;
6558 ckfree(jobtab);
6559 jobtab = jp;
6560 }
6561 jp = jobtab + njobs;
6562 for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
6563 INTON;
6564 break;
6565 }
6566 if (jp->used == 0)
6567 break;
6568 }
6569 INTOFF;
6570 jp->state = 0;
6571 jp->used = 1;
6572 jp->changed = 0;
6573 jp->nprocs = 0;
Eric Andersend35c5df2002-01-09 15:37:36 +00006574#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006575 jp->jobctl = jobctl;
6576#endif
6577 if (nprocs > 1) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006578 jp->ps = xmalloc(nprocs * sizeof (struct procstat));
Eric Andersencb57d552001-06-28 07:25:16 +00006579 } else {
6580 jp->ps = &jp->ps0;
6581 }
6582 INTON;
6583 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
6584 jp - jobtab + 1));
6585 return jp;
6586}
6587
6588
6589/*
6590 * Fork of a subshell. If we are doing job control, give the subshell its
6591 * own process group. Jp is a job structure that the job is to be added to.
6592 * N is the command that will be evaluated by the child. Both jp and n may
6593 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00006594 * FORK_FG - Fork off a foreground process.
6595 * FORK_BG - Fork off a background process.
6596 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
6597 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00006598 *
6599 * When job control is turned off, background processes have their standard
6600 * input redirected to /dev/null (except for the second and later processes
6601 * in a pipeline).
6602 */
6603
Eric Andersen2870d962001-07-02 17:27:21 +00006604
6605
Eric Andersencb57d552001-06-28 07:25:16 +00006606static int
Eric Andersen62483552001-07-10 06:09:16 +00006607forkshell(struct job *jp, const union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00006608{
6609 int pid;
Eric Andersend35c5df2002-01-09 15:37:36 +00006610#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006611 int pgrp;
Eric Andersen62483552001-07-10 06:09:16 +00006612#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006613 const char *devnull = _PATH_DEVNULL;
6614 const char *nullerr = "Can't open %s";
6615
6616 TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
6617 mode));
6618 INTOFF;
Eric Andersen72f9a422001-10-28 05:12:20 +00006619#if !defined(__UCLIBC__) || defined(__UCLIBC_HAS_MMU__)
Eric Andersencb57d552001-06-28 07:25:16 +00006620 pid = fork();
Eric Andersen72f9a422001-10-28 05:12:20 +00006621#else
6622 pid = vfork();
6623#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006624 if (pid == -1) {
6625 TRACE(("Fork failed, errno=%d\n", errno));
6626 INTON;
6627 error("Cannot fork");
6628 }
6629 if (pid == 0) {
6630 struct job *p;
6631 int wasroot;
6632 int i;
6633
6634 TRACE(("Child shell %d\n", getpid()));
6635 wasroot = rootshell;
6636 rootshell = 0;
6637 closescript();
6638 INTON;
6639 clear_traps();
Eric Andersend35c5df2002-01-09 15:37:36 +00006640#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen2870d962001-07-02 17:27:21 +00006641 jobctl = 0; /* do job control only in root shell */
Eric Andersencb57d552001-06-28 07:25:16 +00006642 if (wasroot && mode != FORK_NOJOB && mflag) {
6643 if (jp == NULL || jp->nprocs == 0)
6644 pgrp = getpid();
6645 else
6646 pgrp = jp->ps[0].pid;
6647 setpgid(0, pgrp);
6648 if (mode == FORK_FG) {
6649 /*** this causes superfluous TIOCSPGRPS ***/
6650#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006651 if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006652 error("TIOCSPGRP failed, errno=%d", errno);
6653#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006654 if (tcsetpgrp(2, pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006655 error("tcsetpgrp failed, errno=%d", errno);
6656#endif
6657 }
6658 setsignal(SIGTSTP);
6659 setsignal(SIGTTOU);
6660 } else if (mode == FORK_BG) {
Eric Andersencb57d552001-06-28 07:25:16 +00006661#else
6662 if (mode == FORK_BG) {
Aaron Lehmann1a698662001-12-31 06:12:48 +00006663#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006664 ignoresig(SIGINT);
6665 ignoresig(SIGQUIT);
6666 if ((jp == NULL || jp->nprocs == 0) &&
6667 ! fd0_redirected_p ()) {
6668 close(0);
6669 if (open(devnull, O_RDONLY) != 0)
6670 error(nullerr, devnull);
6671 }
6672 }
Eric Andersencb57d552001-06-28 07:25:16 +00006673 for (i = njobs, p = jobtab ; --i >= 0 ; p++)
6674 if (p->used)
6675 freejob(p);
6676 if (wasroot && iflag) {
6677 setsignal(SIGINT);
6678 setsignal(SIGQUIT);
6679 setsignal(SIGTERM);
6680 }
6681 return pid;
6682 }
Eric Andersend35c5df2002-01-09 15:37:36 +00006683#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006684 if (rootshell && mode != FORK_NOJOB && mflag) {
6685 if (jp == NULL || jp->nprocs == 0)
6686 pgrp = pid;
6687 else
6688 pgrp = jp->ps[0].pid;
6689 setpgid(pid, pgrp);
6690 }
Eric Andersen62483552001-07-10 06:09:16 +00006691#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006692 if (mode == FORK_BG)
Eric Andersen2870d962001-07-02 17:27:21 +00006693 backgndpid = pid; /* set $! */
Eric Andersencb57d552001-06-28 07:25:16 +00006694 if (jp) {
6695 struct procstat *ps = &jp->ps[jp->nprocs++];
6696 ps->pid = pid;
6697 ps->status = -1;
6698 ps->cmd = nullstr;
6699 if (iflag && rootshell && n)
6700 ps->cmd = commandtext(n);
6701 }
6702 INTON;
6703 TRACE(("In parent shell: child = %d\n", pid));
6704 return pid;
6705}
6706
6707
6708
6709/*
6710 * Wait for job to finish.
6711 *
6712 * Under job control we have the problem that while a child process is
6713 * running interrupts generated by the user are sent to the child but not
6714 * to the shell. This means that an infinite loop started by an inter-
6715 * active user may be hard to kill. With job control turned off, an
6716 * interactive user may place an interactive program inside a loop. If
6717 * the interactive program catches interrupts, the user doesn't want
6718 * these interrupts to also abort the loop. The approach we take here
6719 * is to have the shell ignore interrupt signals while waiting for a
6720 * forground process to terminate, and then send itself an interrupt
6721 * signal if the child process was terminated by an interrupt signal.
6722 * Unfortunately, some programs want to do a bit of cleanup and then
6723 * exit on interrupt; unless these processes terminate themselves by
6724 * sending a signal to themselves (instead of calling exit) they will
6725 * confuse this approach.
6726 */
6727
6728static int
Eric Andersen62483552001-07-10 06:09:16 +00006729waitforjob(struct job *jp)
6730{
Eric Andersend35c5df2002-01-09 15:37:36 +00006731#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006732 int mypgrp = getpgrp();
6733#endif
6734 int status;
6735 int st;
6736 struct sigaction act, oact;
6737
6738 INTOFF;
6739 intreceived = 0;
Eric Andersend35c5df2002-01-09 15:37:36 +00006740#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006741 if (!jobctl) {
6742#else
6743 if (!iflag) {
6744#endif
6745 sigaction(SIGINT, 0, &act);
6746 act.sa_handler = waitonint;
6747 sigaction(SIGINT, &act, &oact);
6748 }
6749 TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
6750 while (jp->state == 0) {
6751 dowait(1, jp);
6752 }
Eric Andersend35c5df2002-01-09 15:37:36 +00006753#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006754 if (!jobctl) {
6755#else
6756 if (!iflag) {
6757#endif
6758 sigaction(SIGINT, &oact, 0);
Eric Andersen54c14d72002-04-24 23:14:06 +00006759 if (intreceived) kill(getpid(), SIGINT);
Eric Andersencb57d552001-06-28 07:25:16 +00006760 }
Eric Andersend35c5df2002-01-09 15:37:36 +00006761#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006762 if (jp->jobctl) {
6763#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006764 if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006765 error("TIOCSPGRP failed, errno=%d\n", errno);
6766#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006767 if (tcsetpgrp(2, mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006768 error("tcsetpgrp failed, errno=%d\n", errno);
6769#endif
6770 }
Eric Andersend35c5df2002-01-09 15:37:36 +00006771 if (jp->state == CONFIG_ASH_JOB_CONTROLTOPPED)
Eric Andersencb57d552001-06-28 07:25:16 +00006772 curjob = jp - jobtab + 1;
6773#endif
6774 status = jp->ps[jp->nprocs - 1].status;
6775 /* convert to 8 bits */
6776 if (WIFEXITED(status))
6777 st = WEXITSTATUS(status);
Eric Andersend35c5df2002-01-09 15:37:36 +00006778#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006779 else if (WIFSTOPPED(status))
6780 st = WSTOPSIG(status) + 128;
6781#endif
6782 else
6783 st = WTERMSIG(status) + 128;
Eric Andersend35c5df2002-01-09 15:37:36 +00006784#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006785 if (jp->jobctl) {
6786 /*
6787 * This is truly gross.
6788 * If we're doing job control, then we did a TIOCSPGRP which
6789 * caused us (the shell) to no longer be in the controlling
6790 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
6791 * intuit from the subprocess exit status whether a SIGINT
6792 * occured, and if so interrupt ourselves. Yuck. - mycroft
6793 */
6794 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
6795 raise(SIGINT);
6796 }
Eric Andersen2870d962001-07-02 17:27:21 +00006797 if (jp->state == JOBDONE)
6798
Eric Andersencb57d552001-06-28 07:25:16 +00006799#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006800 freejob(jp);
6801 INTON;
6802 return st;
6803}
6804
6805
6806
6807/*
6808 * Wait for a process to terminate.
6809 */
6810
Eric Andersen62483552001-07-10 06:09:16 +00006811/*
6812 * Do a wait system call. If job control is compiled in, we accept
6813 * stopped processes. If block is zero, we return a value of zero
6814 * rather than blocking.
6815 *
6816 * System V doesn't have a non-blocking wait system call. It does
6817 * have a SIGCLD signal that is sent to a process when one of it's
6818 * children dies. The obvious way to use SIGCLD would be to install
6819 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
6820 * was received, and have waitproc bump another counter when it got
6821 * the status of a process. Waitproc would then know that a wait
6822 * system call would not block if the two counters were different.
6823 * This approach doesn't work because if a process has children that
6824 * have not been waited for, System V will send it a SIGCLD when it
6825 * installs a signal handler for SIGCLD. What this means is that when
6826 * a child exits, the shell will be sent SIGCLD signals continuously
6827 * until is runs out of stack space, unless it does a wait call before
6828 * restoring the signal handler. The code below takes advantage of
6829 * this (mis)feature by installing a signal handler for SIGCLD and
6830 * then checking to see whether it was called. If there are any
6831 * children to be waited for, it will be.
6832 *
6833 */
6834
6835static inline int
6836waitproc(int block, int *status)
6837{
6838 int flags;
6839
6840 flags = 0;
Eric Andersend35c5df2002-01-09 15:37:36 +00006841#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersen62483552001-07-10 06:09:16 +00006842 if (jobctl)
6843 flags |= WUNTRACED;
6844#endif
6845 if (block == 0)
6846 flags |= WNOHANG;
6847 return wait3(status, flags, (struct rusage *)NULL);
6848}
6849
Eric Andersencb57d552001-06-28 07:25:16 +00006850static int
Eric Andersen62483552001-07-10 06:09:16 +00006851dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00006852{
6853 int pid;
6854 int status;
6855 struct procstat *sp;
6856 struct job *jp;
6857 struct job *thisjob;
6858 int done;
6859 int stopped;
6860 int core;
6861 int sig;
6862
6863 TRACE(("dowait(%d) called\n", block));
6864 do {
6865 pid = waitproc(block, &status);
6866 TRACE(("wait returns %d, status=%d\n", pid, status));
6867 } while (!(block & 2) && pid == -1 && errno == EINTR);
6868 if (pid <= 0)
6869 return pid;
6870 INTOFF;
6871 thisjob = NULL;
6872 for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
6873 if (jp->used) {
6874 done = 1;
6875 stopped = 1;
6876 for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
6877 if (sp->pid == -1)
6878 continue;
6879 if (sp->pid == pid) {
6880 TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
6881 sp->status = status;
6882 thisjob = jp;
6883 }
6884 if (sp->status == -1)
6885 stopped = 0;
6886 else if (WIFSTOPPED(sp->status))
6887 done = 0;
6888 }
Eric Andersen2870d962001-07-02 17:27:21 +00006889 if (stopped) { /* stopped or done */
Eric Andersend35c5df2002-01-09 15:37:36 +00006890 int state = done? JOBDONE : CONFIG_ASH_JOB_CONTROLTOPPED;
Eric Andersencb57d552001-06-28 07:25:16 +00006891 if (jp->state != state) {
6892 TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
6893 jp->state = state;
Eric Andersend35c5df2002-01-09 15:37:36 +00006894#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006895 if (done && curjob == jp - jobtab + 1)
Eric Andersen2870d962001-07-02 17:27:21 +00006896 curjob = 0; /* no current job */
Eric Andersencb57d552001-06-28 07:25:16 +00006897#endif
6898 }
6899 }
6900 }
6901 }
6902 INTON;
6903 if (! rootshell || ! iflag || (job && thisjob == job)) {
6904 core = WCOREDUMP(status);
Eric Andersend35c5df2002-01-09 15:37:36 +00006905#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006906 if (WIFSTOPPED(status)) sig = WSTOPSIG(status);
6907 else
6908#endif
6909 if (WIFEXITED(status)) sig = 0;
6910 else sig = WTERMSIG(status);
6911
6912 if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
6913 if (thisjob != job)
Eric Andersen3102ac42001-07-06 04:26:23 +00006914 out2fmt("%d: ", pid);
Eric Andersend35c5df2002-01-09 15:37:36 +00006915#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +00006916 if (sig == SIGTSTP && rootshell && iflag)
Eric Andersen3102ac42001-07-06 04:26:23 +00006917 out2fmt("%%%ld ",
Eric Andersencb57d552001-06-28 07:25:16 +00006918 (long)(job - jobtab + 1));
6919#endif
6920 if (sig < NSIG && sys_siglist[sig])
6921 out2str(sys_siglist[sig]);
6922 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006923 out2fmt("Signal %d", sig);
Eric Andersencb57d552001-06-28 07:25:16 +00006924 if (core)
6925 out2str(" - core dumped");
6926 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00006927 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00006928 TRACE(("Not printing status: status=%d, sig=%d\n",
Eric Andersencb57d552001-06-28 07:25:16 +00006929 status, sig));
6930 }
6931 } else {
6932 TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
6933 if (thisjob)
6934 thisjob->changed = 1;
6935 }
6936 return pid;
6937}
6938
6939
6940
Eric Andersencb57d552001-06-28 07:25:16 +00006941
6942/*
6943 * return 1 if there are stopped jobs, otherwise 0
6944 */
Eric Andersencb57d552001-06-28 07:25:16 +00006945static int
Eric Andersen2870d962001-07-02 17:27:21 +00006946stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006947{
6948 int jobno;
6949 struct job *jp;
6950
6951 if (job_warning)
6952 return (0);
6953 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
6954 if (jp->used == 0)
6955 continue;
Eric Andersend35c5df2002-01-09 15:37:36 +00006956 if (jp->state == CONFIG_ASH_JOB_CONTROLTOPPED) {
Eric Andersencb57d552001-06-28 07:25:16 +00006957 out2str("You have stopped jobs.\n");
6958 job_warning = 2;
6959 return (1);
6960 }
6961 }
6962
6963 return (0);
6964}
6965
6966/*
6967 * Return a string identifying a command (to be printed by the
6968 * jobs command.
6969 */
6970
6971static char *cmdnextc;
6972static int cmdnleft;
Eric Andersen2870d962001-07-02 17:27:21 +00006973#define MAXCMDTEXT 200
Eric Andersencb57d552001-06-28 07:25:16 +00006974
Eric Andersen2870d962001-07-02 17:27:21 +00006975static void
6976cmdputs(const char *s)
6977{
6978 const char *p;
6979 char *q;
6980 char c;
6981 int subtype = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00006982
Eric Andersen2870d962001-07-02 17:27:21 +00006983 if (cmdnleft <= 0)
6984 return;
6985 p = s;
6986 q = cmdnextc;
6987 while ((c = *p++) != '\0') {
6988 if (c == CTLESC)
6989 *q++ = *p++;
6990 else if (c == CTLVAR) {
6991 *q++ = '$';
6992 if (--cmdnleft > 0)
6993 *q++ = '{';
6994 subtype = *p++;
6995 } else if (c == '=' && subtype != 0) {
6996 *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
6997 subtype = 0;
6998 } else if (c == CTLENDVAR) {
6999 *q++ = '}';
7000 } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
7001 cmdnleft++; /* ignore it */
7002 else
7003 *q++ = c;
7004 if (--cmdnleft <= 0) {
7005 *q++ = '.';
7006 *q++ = '.';
7007 *q++ = '.';
7008 break;
7009 }
7010 }
7011 cmdnextc = q;
Eric Andersencb57d552001-06-28 07:25:16 +00007012}
7013
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00007014#define CMDTXT_TABLE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007015#ifdef CMDTXT_TABLE
7016/*
7017 * To collect a lot of redundant code in cmdtxt() case statements, we
7018 * implement a mini language here. Each type of node struct has an
7019 * associated instruction sequence that operates on its members via
7020 * their offsets. The instruction are pack in unsigned chars with
7021 * format IIDDDDDE where the bits are
7022 * I : part of the instruction opcode, which are
7023 * 00 : member is a pointer to another node -- process it recursively
7024 * 40 : member is a pointer to a char string -- output it
7025 * 80 : output the string whose index is stored in the data field
7026 * CC : flag signaling that this case needs external processing
7027 * D : data - either the (shifted) index of a fixed string to output or
7028 * the actual offset of the member to operate on in the struct
7029 * (since we assume bit 0 is set, the offset is not shifted)
7030 * E : flag signaling end of instruction sequence
7031 *
7032 * WARNING: In order to handle larger offsets for 64bit archs, this code
7033 * assumes that no offset can be an odd number and stores the
7034 * end-of-instructions flag in bit 0.
7035 */
Eric Andersencb57d552001-06-28 07:25:16 +00007036
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007037#define CMDTXT_NOMORE 0x01 /* NOTE: no offset should be odd */
7038#define CMDTXT_CHARPTR 0x40
7039#define CMDTXT_STRING 0x80
7040#define CMDTXT_SPECIAL 0xC0
7041#define CMDTXT_OFFSETMASK 0x3E
7042
7043static const char * const cmdtxt_strings[] = {
7044 /* 0 1 2 3 4 5 6 7 */
7045 "; ", "(", ")", " && ", " || ", "if ", "; then ", "...",
7046 /* 8 9 10 11 12 13 */
7047 "while ", "; do ", "; done", "until ", "for ", " in ...",
7048 /* 14 15 16 17 */
7049 "case ", "???", "() ...", "<<..."
7050};
7051
7052static const char * const redir_strings[] = {
7053 ">", "<", "<>", ">>", ">|", ">&", "<&"
7054};
7055
7056static const unsigned char cmdtxt_ops[] = {
7057#define CMDTXT_NSEMI 0
7058 offsetof(union node, nbinary.ch1),
7059 0|CMDTXT_STRING,
7060 offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7061#define CMDTXT_NCMD (CMDTXT_NSEMI + 3)
7062#define CMDTXT_NPIPE (CMDTXT_NCMD)
7063#define CMDTXT_NCASE (CMDTXT_NCMD)
7064#define CMDTXT_NTO (CMDTXT_NCMD)
7065#define CMDTXT_NFROM (CMDTXT_NCMD)
7066#define CMDTXT_NFROMTO (CMDTXT_NCMD)
7067#define CMDTXT_NAPPEND (CMDTXT_NCMD)
7068#define CMDTXT_NTOOV (CMDTXT_NCMD)
7069#define CMDTXT_NTOFD (CMDTXT_NCMD)
7070#define CMDTXT_NFROMFD (CMDTXT_NCMD)
7071 CMDTXT_SPECIAL,
7072#define CMDTXT_NREDIR (CMDTXT_NPIPE + 1)
7073#define CMDTXT_NBACKGND (CMDTXT_NREDIR)
7074 offsetof(union node, nredir.n)|CMDTXT_NOMORE,
7075#define CMDTXT_NSUBSHELL (CMDTXT_NBACKGND + 1)
7076 (1*2)|CMDTXT_STRING,
7077 offsetof(union node, nredir.n),
7078 (2*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7079#define CMDTXT_NAND (CMDTXT_NSUBSHELL + 3)
7080 offsetof(union node, nbinary.ch1),
7081 (3*2)|CMDTXT_STRING,
7082 offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7083#define CMDTXT_NOR (CMDTXT_NAND + 3)
7084 offsetof(union node, nbinary.ch1),
7085 (4*2)|CMDTXT_STRING,
7086 offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7087#define CMDTXT_NIF (CMDTXT_NOR + 3)
7088 (5*2)|CMDTXT_STRING,
7089 offsetof(union node, nif.test),
7090 (6*2)|CMDTXT_STRING,
7091 offsetof(union node, nif.ifpart),
7092 (7*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7093#define CMDTXT_NWHILE (CMDTXT_NIF + 5)
7094 (8*2)|CMDTXT_STRING,
7095 offsetof(union node, nbinary.ch1),
7096 (9*2)|CMDTXT_STRING,
7097 offsetof(union node, nbinary.ch2),
7098 (10*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7099#define CMDTXT_NUNTIL (CMDTXT_NWHILE + 5)
7100 (11*2)|CMDTXT_STRING,
7101 offsetof(union node, nbinary.ch1),
7102 (9*2)|CMDTXT_STRING,
7103 offsetof(union node, nbinary.ch2),
7104 (10*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7105#define CMDTXT_NFOR (CMDTXT_NUNTIL + 5)
7106 (12*2)|CMDTXT_STRING,
7107 offsetof(union node, nfor.var)|CMDTXT_CHARPTR,
7108 (13*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7109#define CMDTXT_NCLIST (CMDTXT_NFOR + 3) /* TODO: IS THIS CORRECT??? */
7110#define CMDTXT_NNOT (CMDTXT_NCLIST) /* TODO: IS THIS CORRECT??? */
7111 (15*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7112#define CMDTXT_NDEFUN (CMDTXT_NCLIST + 1)
7113 offsetof(union node, narg.text)|CMDTXT_CHARPTR,
7114 (16*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7115#define CMDTXT_NARG (CMDTXT_NDEFUN + 2)
7116 offsetof(union node, narg.text)|CMDTXT_CHARPTR|CMDTXT_NOMORE,
7117#define CMDTXT_NHERE (CMDTXT_NARG + 1)
7118#define CMDTXT_NXHERE (CMDTXT_NHERE)
7119 (17*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7120};
7121
7122#if CMDTXT_NXHERE != 36
7123#error CMDTXT_NXHERE
7124#endif
7125
7126static const unsigned char cmdtxt_ops_index[26] = {
7127 CMDTXT_NSEMI,
7128 CMDTXT_NCMD,
7129 CMDTXT_NPIPE,
7130 CMDTXT_NREDIR,
7131 CMDTXT_NBACKGND,
7132 CMDTXT_NSUBSHELL,
7133 CMDTXT_NAND,
7134 CMDTXT_NOR,
7135 CMDTXT_NIF,
7136 CMDTXT_NWHILE,
7137 CMDTXT_NUNTIL,
7138 CMDTXT_NFOR,
7139 CMDTXT_NCASE,
7140 CMDTXT_NCLIST,
7141 CMDTXT_NDEFUN,
7142 CMDTXT_NARG,
7143 CMDTXT_NTO,
7144 CMDTXT_NFROM,
7145 CMDTXT_NFROMTO,
7146 CMDTXT_NAPPEND,
7147 CMDTXT_NTOOV,
7148 CMDTXT_NTOFD,
7149 CMDTXT_NFROMFD,
7150 CMDTXT_NHERE,
7151 CMDTXT_NXHERE,
7152 CMDTXT_NNOT,
7153};
7154
7155static void
7156cmdtxt(const union node *n)
7157{
7158 const char *p;
7159
7160 if (n == NULL)
7161 return;
7162
7163 p = cmdtxt_ops + (int) cmdtxt_ops_index[n->type];
7164 if ((*p & CMDTXT_SPECIAL) != CMDTXT_SPECIAL) { /* normal case */
7165 do {
7166 if (*p & CMDTXT_STRING) { /* output fixed string */
7167 cmdputs(cmdtxt_strings[((int)(*p & CMDTXT_OFFSETMASK) >> 1)]);
Manuel Novoa III c639a352001-08-12 17:32:56 +00007168 } else {
7169 const char *pf = ((const char *) n)
7170 + ((int)(*p & CMDTXT_OFFSETMASK));
7171 if (*p & CMDTXT_CHARPTR) { /* output dynamic string */
7172 cmdputs(*((const char **) pf));
7173 } else { /* output field */
7174 cmdtxt(*((const union node **) pf));
7175 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007176 }
7177 } while (!(*p++ & CMDTXT_NOMORE));
7178 } else if (n->type == NCMD) {
7179 union node *np;
7180 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7181 cmdtxt(np);
7182 if (np->narg.next)
7183 cmdputs(spcstr);
7184 }
7185 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7186 cmdputs(spcstr);
7187 cmdtxt(np);
7188 }
7189 } else if (n->type == NPIPE) {
7190 struct nodelist *lp;
7191 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7192 cmdtxt(lp->n);
7193 if (lp->next)
7194 cmdputs(" | ");
7195 }
7196 } else if (n->type == NCASE) {
7197 cmdputs(cmdtxt_strings[14]);
7198 cmdputs(n->ncase.expr->narg.text);
7199 cmdputs(cmdtxt_strings[13]);
7200 } else {
7201#if (NTO != 16) || (NFROM != 17) || (NFROMTO != 18) || (NAPPEND != 19) || (NTOOV != 20) || (NTOFD != 21) || (NFROMFD != 22)
7202#error Assumption violated regarding range and ordering of NTO ... NFROMFD!
7203#endif
7204 char s[2];
7205
7206#ifdef DEBUG
7207 assert((n->type >= NTO) && (n->type <= NFROMFD));
7208#endif
7209
7210 p = redir_strings[n->type - NTO];
7211 if (n->nfile.fd != ('>' == *p)) {
7212 s[0] = n->nfile.fd + '0';
7213 s[1] = '\0';
7214 cmdputs(s);
7215 }
7216 cmdputs(p);
7217 if (n->type >= NTOFD) {
7218 s[0] = n->ndup.dupfd + '0';
7219 s[1] = '\0';
7220 cmdputs(s);
7221 } else {
7222 cmdtxt(n->nfile.fname);
7223 }
7224 }
7225}
7226#else /* CMDTXT_TABLE */
Eric Andersencb57d552001-06-28 07:25:16 +00007227static void
Eric Andersen2870d962001-07-02 17:27:21 +00007228cmdtxt(const union node *n)
7229{
Eric Andersencb57d552001-06-28 07:25:16 +00007230 union node *np;
7231 struct nodelist *lp;
7232 const char *p;
7233 int i;
7234 char s[2];
7235
7236 if (n == NULL)
7237 return;
7238 switch (n->type) {
7239 case NSEMI:
7240 cmdtxt(n->nbinary.ch1);
7241 cmdputs("; ");
7242 cmdtxt(n->nbinary.ch2);
7243 break;
7244 case NAND:
7245 cmdtxt(n->nbinary.ch1);
7246 cmdputs(" && ");
7247 cmdtxt(n->nbinary.ch2);
7248 break;
7249 case NOR:
7250 cmdtxt(n->nbinary.ch1);
7251 cmdputs(" || ");
7252 cmdtxt(n->nbinary.ch2);
7253 break;
7254 case NPIPE:
7255 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7256 cmdtxt(lp->n);
7257 if (lp->next)
7258 cmdputs(" | ");
7259 }
7260 break;
7261 case NSUBSHELL:
7262 cmdputs("(");
7263 cmdtxt(n->nredir.n);
7264 cmdputs(")");
7265 break;
7266 case NREDIR:
7267 case NBACKGND:
7268 cmdtxt(n->nredir.n);
7269 break;
7270 case NIF:
7271 cmdputs("if ");
7272 cmdtxt(n->nif.test);
7273 cmdputs("; then ");
7274 cmdtxt(n->nif.ifpart);
7275 cmdputs("...");
7276 break;
7277 case NWHILE:
7278 cmdputs("while ");
7279 goto until;
7280 case NUNTIL:
7281 cmdputs("until ");
7282until:
7283 cmdtxt(n->nbinary.ch1);
7284 cmdputs("; do ");
7285 cmdtxt(n->nbinary.ch2);
7286 cmdputs("; done");
7287 break;
7288 case NFOR:
7289 cmdputs("for ");
7290 cmdputs(n->nfor.var);
7291 cmdputs(" in ...");
7292 break;
7293 case NCASE:
7294 cmdputs("case ");
7295 cmdputs(n->ncase.expr->narg.text);
7296 cmdputs(" in ...");
7297 break;
7298 case NDEFUN:
7299 cmdputs(n->narg.text);
7300 cmdputs("() ...");
7301 break;
7302 case NCMD:
7303 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7304 cmdtxt(np);
7305 if (np->narg.next)
7306 cmdputs(spcstr);
7307 }
7308 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7309 cmdputs(spcstr);
7310 cmdtxt(np);
7311 }
7312 break;
7313 case NARG:
7314 cmdputs(n->narg.text);
7315 break;
7316 case NTO:
7317 p = ">"; i = 1; goto redir;
7318 case NAPPEND:
7319 p = ">>"; i = 1; goto redir;
7320 case NTOFD:
7321 p = ">&"; i = 1; goto redir;
7322 case NTOOV:
7323 p = ">|"; i = 1; goto redir;
7324 case NFROM:
7325 p = "<"; i = 0; goto redir;
7326 case NFROMFD:
7327 p = "<&"; i = 0; goto redir;
7328 case NFROMTO:
7329 p = "<>"; i = 0; goto redir;
7330redir:
7331 if (n->nfile.fd != i) {
7332 s[0] = n->nfile.fd + '0';
7333 s[1] = '\0';
7334 cmdputs(s);
7335 }
7336 cmdputs(p);
7337 if (n->type == NTOFD || n->type == NFROMFD) {
7338 s[0] = n->ndup.dupfd + '0';
7339 s[1] = '\0';
7340 cmdputs(s);
7341 } else {
7342 cmdtxt(n->nfile.fname);
7343 }
7344 break;
7345 case NHERE:
7346 case NXHERE:
7347 cmdputs("<<...");
7348 break;
7349 default:
7350 cmdputs("???");
7351 break;
7352 }
7353}
Manuel Novoa III c639a352001-08-12 17:32:56 +00007354#endif /* CMDTXT_TABLE */
Eric Andersencb57d552001-06-28 07:25:16 +00007355
Eric Andersen2870d962001-07-02 17:27:21 +00007356static char *
7357commandtext(const union node *n)
7358{
7359 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007360
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007361 cmdnextc = name = xmalloc(MAXCMDTEXT);
Eric Andersen2870d962001-07-02 17:27:21 +00007362 cmdnleft = MAXCMDTEXT - 4;
7363 cmdtxt(n);
7364 *cmdnextc = '\0';
7365 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00007366}
7367
Eric Andersen2870d962001-07-02 17:27:21 +00007368
Eric Andersencb57d552001-06-28 07:25:16 +00007369static void waitonint(int sig) {
7370 intreceived = 1;
7371 return;
7372}
Eric Andersenec074692001-10-31 11:05:49 +00007373
Eric Andersend35c5df2002-01-09 15:37:36 +00007374#ifdef CONFIG_ASH_MAIL
Eric Andersenec074692001-10-31 11:05:49 +00007375
Eric Andersencb57d552001-06-28 07:25:16 +00007376/*
Eric Andersenec074692001-10-31 11:05:49 +00007377 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +00007378 */
7379
7380
7381#define MAXMBOXES 10
7382
7383
Eric Andersen2870d962001-07-02 17:27:21 +00007384static int nmboxes; /* number of mailboxes */
7385static time_t mailtime[MAXMBOXES]; /* times of mailboxes */
Eric Andersencb57d552001-06-28 07:25:16 +00007386
7387
7388
7389/*
7390 * Print appropriate message(s) if mail has arrived. If the argument is
7391 * nozero, then the value of MAIL has changed, so we just update the
7392 * values.
7393 */
7394
7395static void
Eric Andersen2870d962001-07-02 17:27:21 +00007396chkmail(int silent)
Eric Andersencb57d552001-06-28 07:25:16 +00007397{
7398 int i;
7399 const char *mpath;
7400 char *p;
7401 char *q;
7402 struct stackmark smark;
7403 struct stat statb;
7404
7405 if (silent)
7406 nmboxes = 10;
7407 if (nmboxes == 0)
7408 return;
7409 setstackmark(&smark);
7410 mpath = mpathset()? mpathval() : mailval();
7411 for (i = 0 ; i < nmboxes ; i++) {
7412 p = padvance(&mpath, nullstr);
7413 if (p == NULL)
7414 break;
7415 if (*p == '\0')
7416 continue;
7417 for (q = p ; *q ; q++);
7418#ifdef DEBUG
7419 if (q[-1] != '/')
7420 abort();
7421#endif
Eric Andersen2870d962001-07-02 17:27:21 +00007422 q[-1] = '\0'; /* delete trailing '/' */
Eric Andersencb57d552001-06-28 07:25:16 +00007423 if (stat(p, &statb) < 0)
7424 statb.st_size = 0;
7425 if (statb.st_size > mailtime[i] && ! silent) {
Eric Andersen3102ac42001-07-06 04:26:23 +00007426 out2fmt(snlfmt,
7427 pathopt? pathopt : "you have mail");
Eric Andersencb57d552001-06-28 07:25:16 +00007428 }
7429 mailtime[i] = statb.st_size;
Eric Andersencb57d552001-06-28 07:25:16 +00007430 }
7431 nmboxes = i;
7432 popstackmark(&smark);
7433}
Eric Andersencb57d552001-06-28 07:25:16 +00007434
Eric Andersend35c5df2002-01-09 15:37:36 +00007435#endif /* CONFIG_ASH_MAIL */
Eric Andersenec074692001-10-31 11:05:49 +00007436
Eric Andersencb57d552001-06-28 07:25:16 +00007437#define PROFILE 0
7438
Eric Andersencb57d552001-06-28 07:25:16 +00007439#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007440static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007441extern int etext();
7442#endif
7443
Robert Griebl64f70cc2002-05-14 23:22:06 +00007444static int isloginsh = 0;
7445
Eric Andersen2870d962001-07-02 17:27:21 +00007446static void read_profile (const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007447static void cmdloop (int);
7448static void options (int);
Eric Andersen2870d962001-07-02 17:27:21 +00007449static void setoption (int, int);
7450static void procargs (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00007451
Eric Andersen2870d962001-07-02 17:27:21 +00007452
Eric Andersencb57d552001-06-28 07:25:16 +00007453/*
7454 * Main routine. We initialize things, parse the arguments, execute
7455 * profiles if we're a login shell, and then call cmdloop to execute
7456 * commands. The setjmp call sets up the location to jump to when an
7457 * exception occurs. When an exception occurs the variable "state"
7458 * is used to figure out how far we had gotten.
7459 */
7460
7461int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007462ash_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007463{
7464 struct jmploc jmploc;
7465 struct stackmark smark;
7466 volatile int state;
Eric Andersen62483552001-07-10 06:09:16 +00007467 const char *shinit;
Eric Andersencb57d552001-06-28 07:25:16 +00007468
Eric Andersencb57d552001-06-28 07:25:16 +00007469 BLTINCMD = find_builtin("builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00007470 EXECCMD = find_builtin("exec");
7471 EVALCMD = find_builtin("eval");
7472
Eric Andersenbdfd0d72001-10-24 05:00:29 +00007473#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
Eric Andersen1c039232001-07-07 00:05:55 +00007474 unsetenv("PS1");
7475 unsetenv("PS2");
7476#endif
7477
Eric Andersencb57d552001-06-28 07:25:16 +00007478#if PROFILE
7479 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7480#endif
7481#if defined(linux) || defined(__GNU__)
7482 signal(SIGCHLD, SIG_DFL);
7483#endif
7484 state = 0;
7485 if (setjmp(jmploc.loc)) {
7486 INTOFF;
7487 /*
7488 * When a shell procedure is executed, we raise the
7489 * exception EXSHELLPROC to clean up before executing
7490 * the shell procedure.
7491 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007492 if (exception == EXSHELLPROC) {
Eric Andersencb57d552001-06-28 07:25:16 +00007493 rootpid = getpid();
7494 rootshell = 1;
7495 minusc = NULL;
7496 state = 3;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007497 } else {
7498 if (exception == EXEXEC) {
7499 exitstatus = exerrno;
7500 } else if (exception == EXERROR) {
7501 exitstatus = 2;
7502 }
Eric Andersencb57d552001-06-28 07:25:16 +00007503 if (state == 0 || iflag == 0 || ! rootshell)
7504 exitshell(exitstatus);
7505 }
7506 reset();
Eric Andersen2870d962001-07-02 17:27:21 +00007507 if (exception == EXINT) {
Eric Andersencb57d552001-06-28 07:25:16 +00007508 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00007509 }
7510 popstackmark(&smark);
Eric Andersen2870d962001-07-02 17:27:21 +00007511 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007512 if (state == 1)
7513 goto state1;
7514 else if (state == 2)
7515 goto state2;
7516 else if (state == 3)
7517 goto state3;
7518 else
7519 goto state4;
7520 }
7521 handler = &jmploc;
7522#ifdef DEBUG
7523 opentrace();
7524 trputs("Shell args: "); trargs(argv);
7525#endif
7526 rootpid = getpid();
7527 rootshell = 1;
7528 init();
7529 setstackmark(&smark);
7530 procargs(argc, argv);
Robert Griebl64f70cc2002-05-14 23:22:06 +00007531 if (argv[0] && argv[0][0] == '-')
7532 isloginsh = 1;
7533 if (isloginsh) {
Eric Andersencb57d552001-06-28 07:25:16 +00007534 state = 1;
7535 read_profile("/etc/profile");
7536state1:
7537 state = 2;
7538 read_profile(".profile");
7539 }
7540state2:
7541 state = 3;
7542#ifndef linux
7543 if (getuid() == geteuid() && getgid() == getegid()) {
7544#endif
7545 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7546 state = 3;
7547 read_profile(shinit);
7548 }
7549#ifndef linux
7550 }
7551#endif
7552state3:
7553 state = 4;
7554 if (sflag == 0 || minusc) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007555 static const char sigs[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00007556 SIGINT, SIGQUIT, SIGHUP,
Eric Andersencb57d552001-06-28 07:25:16 +00007557#ifdef SIGTSTP
7558 SIGTSTP,
7559#endif
7560 SIGPIPE
7561 };
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007562#define SIGSSIZE ((sizeof(sigs)/sizeof(sigs[0])) - 1) /* trailing nul */
Eric Andersencb57d552001-06-28 07:25:16 +00007563 int i;
7564
7565 for (i = 0; i < SIGSSIZE; i++)
7566 setsignal(sigs[i]);
7567 }
7568
7569 if (minusc)
7570 evalstring(minusc, 0);
7571
7572 if (sflag || minusc == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00007573state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007574 cmdloop(1);
7575 }
7576#if PROFILE
7577 monitor(0);
7578#endif
7579 exitshell(exitstatus);
7580 /* NOTREACHED */
7581}
7582
7583
7584/*
7585 * Read and execute commands. "Top" is nonzero for the top level command
7586 * loop; it turns on prompting if the shell is interactive.
7587 */
7588
7589static void
Eric Andersen2870d962001-07-02 17:27:21 +00007590cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00007591{
7592 union node *n;
7593 struct stackmark smark;
7594 int inter;
7595 int numeof = 0;
7596
7597 TRACE(("cmdloop(%d) called\n", top));
7598 setstackmark(&smark);
7599 for (;;) {
7600 if (pendingsigs)
7601 dotrap();
7602 inter = 0;
7603 if (iflag && top) {
7604 inter++;
7605 showjobs(1);
Eric Andersend35c5df2002-01-09 15:37:36 +00007606#ifdef CONFIG_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +00007607 chkmail(0);
Eric Andersenec074692001-10-31 11:05:49 +00007608#endif
Eric Andersen3102ac42001-07-06 04:26:23 +00007609 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00007610 }
7611 n = parsecmd(inter);
7612 /* showtree(n); DEBUG */
7613 if (n == NEOF) {
7614 if (!top || numeof >= 50)
7615 break;
7616 if (!stoppedjobs()) {
7617 if (!Iflag)
7618 break;
7619 out2str("\nUse \"exit\" to leave shell.\n");
7620 }
7621 numeof++;
7622 } else if (n != NULL && nflag == 0) {
7623 job_warning = (job_warning == 2) ? 1 : 0;
7624 numeof = 0;
7625 evaltree(n, 0);
7626 }
7627 popstackmark(&smark);
7628 setstackmark(&smark);
7629 if (evalskip == SKIPFILE) {
7630 evalskip = 0;
7631 break;
7632 }
7633 }
7634 popstackmark(&smark);
7635}
7636
7637
7638
7639/*
7640 * Read /etc/profile or .profile. Return on error.
7641 */
7642
7643static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007644read_profile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00007645{
7646 int fd;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007647 int xflag_save;
7648 int vflag_save;
Eric Andersencb57d552001-06-28 07:25:16 +00007649
7650 INTOFF;
7651 if ((fd = open(name, O_RDONLY)) >= 0)
7652 setinputfd(fd, 1);
7653 INTON;
7654 if (fd < 0)
7655 return;
7656 /* -q turns off -x and -v just when executing init files */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007657 /* Note: Might do a little redundant work, but reduces code size. */
7658 xflag_save = xflag;
7659 vflag_save = vflag;
Eric Andersencb57d552001-06-28 07:25:16 +00007660 if (qflag) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007661 vflag = xflag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007662 }
7663 cmdloop(0);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007664 xflag = xflag_save;
7665 vflag = vflag_save;
Eric Andersencb57d552001-06-28 07:25:16 +00007666 popfile();
7667}
7668
7669
7670
7671/*
7672 * Read a file containing shell functions.
7673 */
7674
7675static void
Eric Andersen2870d962001-07-02 17:27:21 +00007676readcmdfile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00007677{
7678 int fd;
7679
7680 INTOFF;
7681 if ((fd = open(name, O_RDONLY)) >= 0)
7682 setinputfd(fd, 1);
7683 else
7684 error("Can't open %s", name);
7685 INTON;
7686 cmdloop(0);
7687 popfile();
7688}
7689
7690
7691
7692/*
7693 * Take commands from a file. To be compatable we should do a path
7694 * search for the file, which is necessary to find sub-commands.
7695 */
7696
Eric Andersen62483552001-07-10 06:09:16 +00007697static inline char *
Eric Andersen74400cc2001-10-18 04:11:39 +00007698find_dot_file(char *mybasename)
Eric Andersencb57d552001-06-28 07:25:16 +00007699{
7700 char *fullname;
7701 const char *path = pathval();
7702 struct stat statb;
7703
7704 /* don't try this for absolute or relative paths */
7705 if (strchr(mybasename, '/'))
7706 return mybasename;
7707
7708 while ((fullname = padvance(&path, mybasename)) != NULL) {
7709 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
7710 /*
7711 * Don't bother freeing here, since it will
7712 * be freed by the caller.
7713 */
7714 return fullname;
7715 }
7716 stunalloc(fullname);
7717 }
7718
7719 /* not found in the PATH */
7720 error("%s: not found", mybasename);
7721 /* NOTREACHED */
7722}
7723
7724static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007725dotcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007726{
7727 struct strlist *sp;
Eric Andersen69a20f02001-10-31 10:40:37 +00007728 volatile struct shparam saveparam;
Eric Andersencb57d552001-06-28 07:25:16 +00007729 exitstatus = 0;
7730
7731 for (sp = cmdenviron; sp ; sp = sp->next)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007732 setvareq(xstrdup(sp->text), VSTRFIXED|VTEXTFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +00007733
Eric Andersen2870d962001-07-02 17:27:21 +00007734 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00007735 char *fullname;
7736 struct stackmark smark;
7737
7738 setstackmark(&smark);
7739 fullname = find_dot_file(argv[1]);
Eric Andersen69a20f02001-10-31 10:40:37 +00007740
7741 if (argc>2) {
7742 saveparam = shellparam;
7743 shellparam.malloc = 0;
7744 shellparam.nparam = argc - 2;
7745 shellparam.p = argv + 2;
7746 };
7747
Eric Andersencb57d552001-06-28 07:25:16 +00007748 setinputfile(fullname, 1);
7749 commandname = fullname;
7750 cmdloop(0);
7751 popfile();
Eric Andersen69a20f02001-10-31 10:40:37 +00007752
7753 if (argc>2) {
7754 freeparam(&shellparam);
7755 shellparam = saveparam;
7756 };
7757
Eric Andersencb57d552001-06-28 07:25:16 +00007758 popstackmark(&smark);
7759 }
7760 return exitstatus;
7761}
7762
7763
7764static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007765exitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007766{
7767 if (stoppedjobs())
7768 return 0;
7769 if (argc > 1)
7770 exitstatus = number(argv[1]);
7771 else
7772 exitstatus = oexitstatus;
7773 exitshell(exitstatus);
7774 /* NOTREACHED */
7775}
Eric Andersen62483552001-07-10 06:09:16 +00007776
Eric Andersen2870d962001-07-02 17:27:21 +00007777static pointer
7778stalloc(int nbytes)
Eric Andersencb57d552001-06-28 07:25:16 +00007779{
7780 char *p;
7781
7782 nbytes = ALIGN(nbytes);
7783 if (nbytes > stacknleft) {
7784 int blocksize;
7785 struct stack_block *sp;
7786
7787 blocksize = nbytes;
7788 if (blocksize < MINSIZE)
7789 blocksize = MINSIZE;
7790 INTOFF;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007791 sp = xmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
Eric Andersencb57d552001-06-28 07:25:16 +00007792 sp->prev = stackp;
7793 stacknxt = sp->space;
7794 stacknleft = blocksize;
7795 stackp = sp;
7796 INTON;
7797 }
7798 p = stacknxt;
7799 stacknxt += nbytes;
7800 stacknleft -= nbytes;
7801 return p;
7802}
7803
7804
7805static void
Eric Andersen2870d962001-07-02 17:27:21 +00007806stunalloc(pointer p)
7807{
Eric Andersencb57d552001-06-28 07:25:16 +00007808#ifdef DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +00007809 if (p == NULL) { /*DEBUG */
Eric Andersencb57d552001-06-28 07:25:16 +00007810 write(2, "stunalloc\n", 10);
7811 abort();
7812 }
7813#endif
7814 if (!(stacknxt >= (char *)p && (char *)p >= stackp->space)) {
7815 p = stackp->space;
7816 }
7817 stacknleft += stacknxt - (char *)p;
7818 stacknxt = p;
7819}
7820
7821
Eric Andersencb57d552001-06-28 07:25:16 +00007822static void
Eric Andersen2870d962001-07-02 17:27:21 +00007823setstackmark(struct stackmark *mark)
7824{
Eric Andersencb57d552001-06-28 07:25:16 +00007825 mark->stackp = stackp;
7826 mark->stacknxt = stacknxt;
7827 mark->stacknleft = stacknleft;
7828 mark->marknext = markp;
7829 markp = mark;
7830}
7831
7832
7833static void
Eric Andersen2870d962001-07-02 17:27:21 +00007834popstackmark(struct stackmark *mark)
7835{
Eric Andersencb57d552001-06-28 07:25:16 +00007836 struct stack_block *sp;
7837
7838 INTOFF;
7839 markp = mark->marknext;
7840 while (stackp != mark->stackp) {
7841 sp = stackp;
7842 stackp = sp->prev;
7843 ckfree(sp);
7844 }
7845 stacknxt = mark->stacknxt;
7846 stacknleft = mark->stacknleft;
7847 INTON;
7848}
7849
7850
7851/*
7852 * When the parser reads in a string, it wants to stick the string on the
7853 * stack and only adjust the stack pointer when it knows how big the
7854 * string is. Stackblock (defined in stack.h) returns a pointer to a block
7855 * of space on top of the stack and stackblocklen returns the length of
7856 * this block. Growstackblock will grow this space by at least one byte,
7857 * possibly moving it (like realloc). Grabstackblock actually allocates the
7858 * part of the block that has been used.
7859 */
7860
7861static void
Eric Andersen2870d962001-07-02 17:27:21 +00007862growstackblock(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00007863 char *p;
7864 int newlen = ALIGN(stacknleft * 2 + 100);
7865 char *oldspace = stacknxt;
7866 int oldlen = stacknleft;
7867 struct stack_block *sp;
7868 struct stack_block *oldstackp;
7869
7870 if (stacknxt == stackp->space && stackp != &stackbase) {
7871 INTOFF;
7872 oldstackp = stackp;
7873 sp = stackp;
7874 stackp = sp->prev;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007875 sp = xrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen);
Eric Andersencb57d552001-06-28 07:25:16 +00007876 sp->prev = stackp;
7877 stackp = sp;
7878 stacknxt = sp->space;
7879 stacknleft = newlen;
7880 {
7881 /* Stack marks pointing to the start of the old block
Eric Andersen2870d962001-07-02 17:27:21 +00007882 * must be relocated to point to the new block
Eric Andersencb57d552001-06-28 07:25:16 +00007883 */
7884 struct stackmark *xmark;
7885 xmark = markp;
7886 while (xmark != NULL && xmark->stackp == oldstackp) {
7887 xmark->stackp = stackp;
7888 xmark->stacknxt = stacknxt;
7889 xmark->stacknleft = stacknleft;
7890 xmark = xmark->marknext;
7891 }
7892 }
7893 INTON;
7894 } else {
7895 p = stalloc(newlen);
7896 memcpy(p, oldspace, oldlen);
Eric Andersen2870d962001-07-02 17:27:21 +00007897 stacknxt = p; /* free the space */
7898 stacknleft += newlen; /* we just allocated */
Eric Andersencb57d552001-06-28 07:25:16 +00007899 }
7900}
7901
7902
7903
Eric Andersen2870d962001-07-02 17:27:21 +00007904static inline void
7905grabstackblock(int len)
Eric Andersencb57d552001-06-28 07:25:16 +00007906{
7907 len = ALIGN(len);
7908 stacknxt += len;
7909 stacknleft -= len;
7910}
7911
7912
7913
7914/*
7915 * The following routines are somewhat easier to use that the above.
7916 * The user declares a variable of type STACKSTR, which may be declared
7917 * to be a register. The macro STARTSTACKSTR initializes things. Then
7918 * the user uses the macro STPUTC to add characters to the string. In
7919 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
7920 * grown as necessary. When the user is done, she can just leave the
7921 * string there and refer to it using stackblock(). Or she can allocate
7922 * the space for it using grabstackstr(). If it is necessary to allow
7923 * someone else to use the stack temporarily and then continue to grow
7924 * the string, the user should use grabstack to allocate the space, and
7925 * then call ungrabstr(p) to return to the previous mode of operation.
7926 *
7927 * USTPUTC is like STPUTC except that it doesn't check for overflow.
7928 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
7929 * is space for at least one character.
7930 */
7931
7932
7933static char *
Eric Andersen2870d962001-07-02 17:27:21 +00007934growstackstr(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00007935 int len = stackblocksize();
7936 if (herefd >= 0 && len >= 1024) {
7937 xwrite(herefd, stackblock(), len);
7938 sstrnleft = len - 1;
7939 return stackblock();
7940 }
7941 growstackblock();
7942 sstrnleft = stackblocksize() - len - 1;
7943 return stackblock() + len;
7944}
7945
7946
7947/*
7948 * Called from CHECKSTRSPACE.
7949 */
7950
7951static char *
7952makestrspace(size_t newlen) {
7953 int len = stackblocksize() - sstrnleft;
7954 do {
7955 growstackblock();
7956 sstrnleft = stackblocksize() - len;
7957 } while (sstrnleft < newlen);
7958 return stackblock() + len;
7959}
7960
7961
7962
7963static void
Eric Andersen2870d962001-07-02 17:27:21 +00007964ungrabstackstr(char *s, char *p)
7965{
Eric Andersencb57d552001-06-28 07:25:16 +00007966 stacknleft += stacknxt - s;
7967 stacknxt = s;
7968 sstrnleft = stacknleft - (p - s);
7969}
Eric Andersencb57d552001-06-28 07:25:16 +00007970/*
7971 * Miscelaneous builtins.
7972 */
7973
7974
7975#undef rflag
7976
Eric Andersencb57d552001-06-28 07:25:16 +00007977#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersen62483552001-07-10 06:09:16 +00007978typedef long rlim_t;
Eric Andersencb57d552001-06-28 07:25:16 +00007979#endif
7980
7981
7982
7983/*
7984 * The read builtin. The -e option causes backslashes to escape the
7985 * following character.
7986 *
7987 * This uses unbuffered input, which may be avoidable in some cases.
7988 */
7989
7990static int
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007991readcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007992{
7993 char **ap;
7994 int backslash;
7995 char c;
7996 int rflag;
7997 char *prompt;
7998 const char *ifs;
7999 char *p;
8000 int startword;
8001 int status;
8002 int i;
8003
8004 rflag = 0;
8005 prompt = NULL;
8006 while ((i = nextopt("p:r")) != '\0') {
8007 if (i == 'p')
8008 prompt = optionarg;
8009 else
8010 rflag = 1;
8011 }
8012 if (prompt && isatty(0)) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008013 out2str(prompt); /* read without cmdedit */
Eric Andersencb57d552001-06-28 07:25:16 +00008014 flushall();
8015 }
8016 if (*(ap = argptr) == NULL)
8017 error("arg count");
8018 if ((ifs = bltinlookup("IFS")) == NULL)
8019 ifs = defifs;
8020 status = 0;
8021 startword = 1;
8022 backslash = 0;
8023 STARTSTACKSTR(p);
8024 for (;;) {
8025 if (read(0, &c, 1) != 1) {
8026 status = 1;
8027 break;
8028 }
8029 if (c == '\0')
8030 continue;
8031 if (backslash) {
8032 backslash = 0;
8033 if (c != '\n')
8034 STPUTC(c, p);
8035 continue;
8036 }
8037 if (!rflag && c == '\\') {
8038 backslash++;
8039 continue;
8040 }
8041 if (c == '\n')
8042 break;
8043 if (startword && *ifs == ' ' && strchr(ifs, c)) {
8044 continue;
8045 }
8046 startword = 0;
8047 if (backslash && c == '\\') {
8048 if (read(0, &c, 1) != 1) {
8049 status = 1;
8050 break;
8051 }
8052 STPUTC(c, p);
8053 } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
8054 STACKSTRNUL(p);
8055 setvar(*ap, stackblock(), 0);
8056 ap++;
8057 startword = 1;
8058 STARTSTACKSTR(p);
8059 } else {
8060 STPUTC(c, p);
8061 }
8062 }
8063 STACKSTRNUL(p);
8064 /* Remove trailing blanks */
8065 while (stackblock() <= --p && strchr(ifs, *p) != NULL)
8066 *p = '\0';
8067 setvar(*ap, stackblock(), 0);
8068 while (*++ap != NULL)
8069 setvar(*ap, nullstr, 0);
8070 return status;
8071}
8072
8073
8074
8075static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008076umaskcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008077{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008078 static const char permuser[3] = "ugo";
8079 static const char permmode[3] = "rwx";
8080 static const short int permmask[] = {
8081 S_IRUSR, S_IWUSR, S_IXUSR,
8082 S_IRGRP, S_IWGRP, S_IXGRP,
8083 S_IROTH, S_IWOTH, S_IXOTH
8084 };
8085
Eric Andersencb57d552001-06-28 07:25:16 +00008086 char *ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008087 mode_t mask;
Eric Andersencb57d552001-06-28 07:25:16 +00008088 int i;
8089 int symbolic_mode = 0;
8090
Eric Andersen62483552001-07-10 06:09:16 +00008091 while (nextopt("S") != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00008092 symbolic_mode = 1;
8093 }
8094
8095 INTOFF;
8096 mask = umask(0);
8097 umask(mask);
8098 INTON;
8099
8100 if ((ap = *argptr) == NULL) {
8101 if (symbolic_mode) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008102 char buf[18];
8103 char *p = buf;
8104 for (i=0 ; i<3 ; i++) {
8105 int j;
8106 *p++ = permuser[i];
8107 *p++ = '=';
8108 for (j=0 ; j<3 ; j++) {
8109 if ((mask & permmask[3*i+j]) == 0) {
8110 *p++ = permmode[j];
8111 }
8112 }
8113 *p++ = ',';
8114 }
8115 *--p = 0;
8116 puts(buf);
Eric Andersencb57d552001-06-28 07:25:16 +00008117 } else {
Eric Andersen62483552001-07-10 06:09:16 +00008118 printf("%.4o\n", mask);
Eric Andersencb57d552001-06-28 07:25:16 +00008119 }
8120 } else {
Eric Andersen62483552001-07-10 06:09:16 +00008121 if (is_digit((unsigned char)*ap)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008122 mask = 0;
8123 do {
8124 if (*ap >= '8' || *ap < '0')
8125 error("Illegal number: %s", argv[1]);
8126 mask = (mask << 3) + (*ap - '0');
8127 } while (*++ap != '\0');
8128 umask(mask);
8129 } else {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008130 mask = ~mask & 0777;
Matt Kraai1f0c4362001-12-20 23:13:26 +00008131 if (! parse_mode(ap, &mask)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008132 error("Illegal mode: %s", ap);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008133 }
Eric Andersencb57d552001-06-28 07:25:16 +00008134 umask(~mask & 0777);
8135 }
8136 }
8137 return 0;
8138}
8139
8140/*
8141 * ulimit builtin
8142 *
8143 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
8144 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
8145 * ash by J.T. Conklin.
8146 *
8147 * Public domain.
8148 */
8149
8150struct limits {
8151 const char *name;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008152 short cmd;
8153 short factor; /* multiply by to get rlim_{cur,max} values */
Eric Andersencb57d552001-06-28 07:25:16 +00008154};
8155
8156static const struct limits limits[] = {
8157#ifdef RLIMIT_CPU
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008158 { "time(seconds)", RLIMIT_CPU, 1 },
Eric Andersencb57d552001-06-28 07:25:16 +00008159#endif
8160#ifdef RLIMIT_FSIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008161 { "file(blocks)", RLIMIT_FSIZE, 512 },
Eric Andersencb57d552001-06-28 07:25:16 +00008162#endif
8163#ifdef RLIMIT_DATA
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008164 { "data(kbytes)", RLIMIT_DATA, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008165#endif
8166#ifdef RLIMIT_STACK
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008167 { "stack(kbytes)", RLIMIT_STACK, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008168#endif
8169#ifdef RLIMIT_CORE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008170 { "coredump(blocks)", RLIMIT_CORE, 512 },
Eric Andersencb57d552001-06-28 07:25:16 +00008171#endif
8172#ifdef RLIMIT_RSS
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008173 { "memory(kbytes)", RLIMIT_RSS, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008174#endif
8175#ifdef RLIMIT_MEMLOCK
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008176 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008177#endif
8178#ifdef RLIMIT_NPROC
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008179 { "process(processes)", RLIMIT_NPROC, 1 },
Eric Andersencb57d552001-06-28 07:25:16 +00008180#endif
8181#ifdef RLIMIT_NOFILE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008182 { "nofiles(descriptors)", RLIMIT_NOFILE, 1 },
Eric Andersencb57d552001-06-28 07:25:16 +00008183#endif
8184#ifdef RLIMIT_VMEM
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008185 { "vmemory(kbytes)", RLIMIT_VMEM, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008186#endif
8187#ifdef RLIMIT_SWAP
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008188 { "swap(kbytes)", RLIMIT_SWAP, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008189#endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008190 { NULL, 0, 0 }
Eric Andersencb57d552001-06-28 07:25:16 +00008191};
8192
8193static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008194ulimitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008195{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008196 static const char unlimited_string[] = "unlimited";
Eric Andersen2870d962001-07-02 17:27:21 +00008197 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00008198 rlim_t val = 0;
8199 enum { SOFT = 0x1, HARD = 0x2 }
8200 how = SOFT | HARD;
Eric Andersen2870d962001-07-02 17:27:21 +00008201 const struct limits *l;
8202 int set, all = 0;
8203 int optc, what;
8204 struct rlimit limit;
Eric Andersencb57d552001-06-28 07:25:16 +00008205
8206 what = 'f';
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008207
8208 while ((optc = nextopt("HSa"
8209#ifdef RLIMIT_CPU
8210 "t"
8211#endif
8212#ifdef RLIMIT_FSIZE
8213 "f"
8214#endif
8215#ifdef RLIMIT_DATA
8216 "d"
8217#endif
8218#ifdef RLIMIT_STACK
8219 "s"
8220#endif
8221#ifdef RLIMIT_CORE
8222 "c"
8223#endif
8224#ifdef RLIMIT_RSS
8225 "m"
8226#endif
8227#ifdef RLIMIT_MEMLOCK
8228 "l"
8229#endif
8230#ifdef RLIMIT_NPROC
8231 "p"
8232#endif
8233#ifdef RLIMIT_NOFILE
8234 "n"
8235#endif
8236#ifdef RLIMIT_VMEM
8237 "v"
8238#endif
8239#ifdef RLIMIT_SWAP
8240 "w"
8241#endif
8242 )) != '\0') {
8243 if (optc == 'H') {
Eric Andersencb57d552001-06-28 07:25:16 +00008244 how = HARD;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008245 } else if (optc == 'S') {
Eric Andersencb57d552001-06-28 07:25:16 +00008246 how = SOFT;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008247 } else if (optc == 'a') {
Eric Andersencb57d552001-06-28 07:25:16 +00008248 all = 1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008249 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00008250 what = optc;
8251 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008252 }
Eric Andersencb57d552001-06-28 07:25:16 +00008253
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008254 for (l = limits; l->name; l++) {
8255 if(l->name[0] == what)
8256 break;
8257 if(l->name[1]=='w' && what=='w')
8258 break;
8259 }
Eric Andersencb57d552001-06-28 07:25:16 +00008260
8261 set = *argptr ? 1 : 0;
8262 if (set) {
8263 char *p = *argptr;
8264
8265 if (all || argptr[1])
8266 error("too many arguments");
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008267 if (strcmp(p, unlimited_string) == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00008268 val = RLIM_INFINITY;
8269 else {
8270 val = (rlim_t) 0;
8271
8272 while ((c = *p++) >= '0' && c <= '9')
8273 {
8274 val = (val * 10) + (long)(c - '0');
8275 if (val < (rlim_t) 0)
8276 break;
8277 }
8278 if (c)
8279 error("bad number");
8280 val *= l->factor;
8281 }
8282 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008283
Eric Andersencb57d552001-06-28 07:25:16 +00008284 if (all) {
8285 for (l = limits; l->name; l++) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008286 printf("%-20s ", l->name);
Eric Andersencb57d552001-06-28 07:25:16 +00008287 getrlimit(l->cmd, &limit);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008288 OUTPUT_LIMIT:
Eric Andersencb57d552001-06-28 07:25:16 +00008289 if (how & SOFT)
8290 val = limit.rlim_cur;
8291 else if (how & HARD)
8292 val = limit.rlim_max;
8293
Eric Andersencb57d552001-06-28 07:25:16 +00008294 if (val == RLIM_INFINITY)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008295 puts(unlimited_string);
Eric Andersencb57d552001-06-28 07:25:16 +00008296 else
8297 {
8298 val /= l->factor;
Eric Andersen62483552001-07-10 06:09:16 +00008299 printf("%lld\n", (long long) val);
Eric Andersencb57d552001-06-28 07:25:16 +00008300 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008301 if (!all) {
8302 break;
8303 }
Eric Andersencb57d552001-06-28 07:25:16 +00008304 }
8305 return 0;
8306 }
8307
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008308 if (!set) {
8309 goto OUTPUT_LIMIT;
Eric Andersencb57d552001-06-28 07:25:16 +00008310 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008311
8312 getrlimit(l->cmd, &limit);
8313 if (how & HARD)
8314 limit.rlim_max = val;
8315 if (how & SOFT)
8316 limit.rlim_cur = val;
8317 if (setrlimit(l->cmd, &limit) < 0)
8318 error("error setting limit (%m)");
Eric Andersencb57d552001-06-28 07:25:16 +00008319 return 0;
8320}
Eric Andersencb57d552001-06-28 07:25:16 +00008321/*
8322 * prefix -- see if pfx is a prefix of string.
8323 */
8324
8325static int
Eric Andersen62483552001-07-10 06:09:16 +00008326prefix(char const *pfx, char const *string)
8327{
Eric Andersencb57d552001-06-28 07:25:16 +00008328 while (*pfx) {
8329 if (*pfx++ != *string++)
8330 return 0;
8331 }
8332 return 1;
8333}
8334
Eric Andersen2870d962001-07-02 17:27:21 +00008335/*
8336 * Return true if s is a string of digits, and save munber in intptr
8337 * nagative is bad
8338 */
8339
8340static int
8341is_number(const char *p, int *intptr)
8342{
8343 int ret = 0;
8344
8345 do {
8346 if (! is_digit(*p))
8347 return 0;
8348 ret *= 10;
8349 ret += digit_val(*p);
8350 p++;
8351 } while (*p != '\0');
8352
8353 *intptr = ret;
8354 return 1;
8355}
Eric Andersencb57d552001-06-28 07:25:16 +00008356
8357/*
8358 * Convert a string of digits to an integer, printing an error message on
8359 * failure.
8360 */
8361
8362static int
Eric Andersen2870d962001-07-02 17:27:21 +00008363number(const char *s)
8364{
8365 int i;
8366 if (! is_number(s, &i))
Eric Andersencb57d552001-06-28 07:25:16 +00008367 error("Illegal number: %s", s);
Eric Andersen2870d962001-07-02 17:27:21 +00008368 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00008369}
8370
Eric Andersencb57d552001-06-28 07:25:16 +00008371/*
8372 * Produce a possibly single quoted string suitable as input to the shell.
8373 * The return string is allocated on the stack.
8374 */
8375
8376static char *
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008377single_quote(const char *s)
8378{
Eric Andersencb57d552001-06-28 07:25:16 +00008379 char *p;
8380
8381 STARTSTACKSTR(p);
8382
8383 do {
8384 char *q = p;
8385 size_t len1, len1p, len2, len2p;
8386
8387 len1 = strcspn(s, "'");
8388 len2 = strspn(s + len1, "'");
8389
8390 len1p = len1 ? len1 + 2 : len1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008391 len2p = len2 + ((len2 < 2) ? len2 : 2);
Eric Andersencb57d552001-06-28 07:25:16 +00008392
8393 CHECKSTRSPACE(len1p + len2p + 1, p);
8394
8395 if (len1) {
8396 *p = '\'';
Eric Andersencb57d552001-06-28 07:25:16 +00008397 q = p + 1 + len1;
8398 memcpy(p + 1, s, len1);
Eric Andersencb57d552001-06-28 07:25:16 +00008399 *q++ = '\'';
8400 s += len1;
8401 }
8402
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008403 if (len2 > 1) {
Eric Andersencb57d552001-06-28 07:25:16 +00008404 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008405 q += 1 + len2;
8406 memcpy(q + 1, s, len2);
8407 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008408 s += len2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008409 } else if (len2 == 1) {
8410 *q++ = '\\';
8411 *q = '\'';
8412 s++;
Eric Andersencb57d552001-06-28 07:25:16 +00008413 }
8414
8415 STADJUST(len1p + len2p, p);
8416 } while (*s);
8417
8418 USTPUTC(0, p);
8419
8420 return grabstackstr(p);
8421}
8422
8423/*
8424 * Like strdup but works with the ash stack.
8425 */
8426
8427static char *
8428sstrdup(const char *p)
8429{
8430 size_t len = strlen(p) + 1;
8431 return memcpy(stalloc(len), p, len);
8432}
8433
Eric Andersencb57d552001-06-28 07:25:16 +00008434
8435/*
Eric Andersencb57d552001-06-28 07:25:16 +00008436 * Routine for dealing with parsed shell commands.
8437 */
8438
8439
Eric Andersen62483552001-07-10 06:09:16 +00008440static void sizenodelist (const struct nodelist *);
8441static struct nodelist *copynodelist (const struct nodelist *);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008442static char *nodexstrdup (const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00008443
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00008444#define CALCSIZE_TABLE
8445#define COPYNODE_TABLE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008446#if defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE)
8447/*
8448 * To collect a lot of redundant code in case statements for copynode()
8449 * and calcsize(), we implement a mini language here. Each type of node
8450 * struct has an associated instruction sequence that operates on its
8451 * members via their offsets. The instruction are pack in unsigned chars
8452 * with format IIDDDDDE where the bits are
8453 * I : part of the instruction opcode, which are
8454 * 00 : member is a pointer to another node
8455 * 40 : member is an integer
8456 * 80 : member is a pointer to a nodelist
8457 * CC : member is a pointer to a char string
8458 * D : data - the actual offset of the member to operate on in the struct
8459 * (since we assume bit 0 is set, it is not shifted)
8460 * E : flag signaling end of instruction sequence
8461 *
8462 * WARNING: In order to handle larger offsets for 64bit archs, this code
8463 * assumes that no offset can be an odd number and stores the
8464 * end-of-instructions flag in bit 0.
8465 */
8466
8467#define NODE_INTEGER 0x40
8468#define NODE_NODELIST 0x80
8469#define NODE_CHARPTR 0xC0
8470#define NODE_NOMORE 0x01 /* Note: no offset should be odd (aligned)*/
8471#define NODE_MBRMASK 0xC0
8472#define NODE_OFFSETMASK 0x3E
8473
8474static const unsigned char copynode_ops[35] = {
8475#define COPYNODE_OPS0 0
8476 offsetof(union node, nbinary.ch2),
8477 offsetof(union node, nbinary.ch1)|NODE_NOMORE,
8478#define COPYNODE_OPS1 (COPYNODE_OPS0 + 2)
8479 offsetof(union node, ncmd.redirect),
8480 offsetof(union node, ncmd.args),
8481 offsetof(union node, ncmd.assign),
8482 offsetof(union node, ncmd.backgnd)|NODE_INTEGER|NODE_NOMORE,
8483#define COPYNODE_OPS2 (COPYNODE_OPS1 + 4)
8484 offsetof(union node, npipe.cmdlist)|NODE_NODELIST,
8485 offsetof(union node, npipe.backgnd)|NODE_INTEGER|NODE_NOMORE,
8486#define COPYNODE_OPS3 (COPYNODE_OPS2 + 2)
8487 offsetof(union node, nredir.redirect),
8488 offsetof(union node, nredir.n)|NODE_NOMORE,
8489#define COPYNODE_OPS4 (COPYNODE_OPS3 + 2)
8490 offsetof(union node, nif.elsepart),
8491 offsetof(union node, nif.ifpart),
8492 offsetof(union node, nif.test)|NODE_NOMORE,
8493#define COPYNODE_OPS5 (COPYNODE_OPS4 + 3)
8494 offsetof(union node, nfor.var)|NODE_CHARPTR,
8495 offsetof(union node, nfor.body),
8496 offsetof(union node, nfor.args)|NODE_NOMORE,
8497#define COPYNODE_OPS6 (COPYNODE_OPS5 + 3)
8498 offsetof(union node, ncase.cases),
8499 offsetof(union node, ncase.expr)|NODE_NOMORE,
8500#define COPYNODE_OPS7 (COPYNODE_OPS6 + 2)
8501 offsetof(union node, nclist.body),
8502 offsetof(union node, nclist.pattern),
8503 offsetof(union node, nclist.next)|NODE_NOMORE,
8504#define COPYNODE_OPS8 (COPYNODE_OPS7 + 3)
8505 offsetof(union node, narg.backquote)|NODE_NODELIST,
8506 offsetof(union node, narg.text)|NODE_CHARPTR,
8507 offsetof(union node, narg.next)|NODE_NOMORE,
8508#define COPYNODE_OPS9 (COPYNODE_OPS8 + 3)
8509 offsetof(union node, nfile.fname),
8510 offsetof(union node, nfile.fd)|NODE_INTEGER,
8511 offsetof(union node, nfile.next)|NODE_NOMORE,
8512#define COPYNODE_OPS10 (COPYNODE_OPS9 + 3)
8513 offsetof(union node, ndup.vname),
8514 offsetof(union node, ndup.dupfd)|NODE_INTEGER,
8515 offsetof(union node, ndup.fd)|NODE_INTEGER,
8516 offsetof(union node, ndup.next)|NODE_NOMORE,
8517#define COPYNODE_OPS11 (COPYNODE_OPS10 + 4)
8518 offsetof(union node, nhere.doc),
8519 offsetof(union node, nhere.fd)|NODE_INTEGER,
8520 offsetof(union node, nhere.next)|NODE_NOMORE,
8521#define COPYNODE_OPS12 (COPYNODE_OPS11 + 3)
8522 offsetof(union node, nnot.com)|NODE_NOMORE,
8523};
8524
8525#if COPYNODE_OPS12 != 34
8526#error COPYNODE_OPS12 is incorrect
8527#endif
8528
8529static const unsigned char copynode_ops_index[26] = {
8530 COPYNODE_OPS0, /* NSEMI */
8531 COPYNODE_OPS1, /* NCMD */
8532 COPYNODE_OPS2, /* NPIPE */
8533 COPYNODE_OPS3, /* NREDIR */
8534 COPYNODE_OPS3, /* NBACKGND */
8535 COPYNODE_OPS3, /* NSUBSHELL */
8536 COPYNODE_OPS0, /* NAND */
8537 COPYNODE_OPS0, /* NOR */
8538 COPYNODE_OPS4, /* NIF */
8539 COPYNODE_OPS0, /* NWHILE */
8540 COPYNODE_OPS0, /* NUNTIL */
8541 COPYNODE_OPS5, /* NFOR */
8542 COPYNODE_OPS6, /* NCASE */
8543 COPYNODE_OPS7, /* NCLIST */
8544 COPYNODE_OPS8, /* NDEFUN */
8545 COPYNODE_OPS8, /* NARG */
8546 COPYNODE_OPS9, /* NTO */
8547 COPYNODE_OPS9, /* NFROM */
8548 COPYNODE_OPS9, /* NFROMTO */
8549 COPYNODE_OPS9, /* NAPPEND */
8550 COPYNODE_OPS9, /* NTOOV */
8551 COPYNODE_OPS10, /* NTOFD */
8552 COPYNODE_OPS10, /* NFROMFD */
8553 COPYNODE_OPS11, /* NHERE */
8554 COPYNODE_OPS11, /* NXHERE */
8555 COPYNODE_OPS12, /* NNOT */
8556};
8557
8558#if NODE_CHARPTR != NODE_MBRMASK
8559#error NODE_CHARPTR != NODE_MBRMASK!!!
8560#endif
8561#endif /* defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE) */
8562
8563#ifdef COPYNODE_TABLE
8564static union node *
8565copynode(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008566{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008567 union node *new;
8568 const unsigned char *p;
8569
Manuel Novoa III c639a352001-08-12 17:32:56 +00008570 if (n == NULL) {
8571 return NULL;
8572 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008573 new = funcblock;
8574 new->type = n->type;
8575 funcblock = (char *) funcblock + (int) nodesize[n->type];
8576 p = copynode_ops + (int) copynode_ops_index[n->type];
8577 do {
8578 char *nn = ((char *) new) + ((int)(*p & NODE_OFFSETMASK));
8579 const char *no = ((const char *) n) + ((int)(*p & NODE_OFFSETMASK));
8580
8581 if (!(*p & NODE_MBRMASK)) { /* standard node */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008582 *((union node **)nn) = copynode(*((const union node **) no));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008583 } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008584 *((const char **)nn) = nodexstrdup(*((const char **)no));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008585 } else if (*p & NODE_NODELIST) { /* nodelist */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008586 *((struct nodelist **)nn)
8587 = copynodelist(*((const struct nodelist **) no));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008588 } else { /* integer */
8589 *((int *) nn) = *((int *) no);
8590 }
8591 } while (!(*p++ & NODE_NOMORE));
8592 return new;
Eric Andersencb57d552001-06-28 07:25:16 +00008593}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008594#else /* COPYNODE_TABLE */
Eric Andersencb57d552001-06-28 07:25:16 +00008595static union node *
Eric Andersen62483552001-07-10 06:09:16 +00008596copynode(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008597{
Eric Andersen62483552001-07-10 06:09:16 +00008598 union node *new;
Eric Andersencb57d552001-06-28 07:25:16 +00008599
8600 if (n == NULL)
Manuel Novoa III c639a352001-08-12 17:32:56 +00008601 return NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008602 new = funcblock;
8603 funcblock = (char *) funcblock + nodesize[n->type];
8604 switch (n->type) {
8605 case NSEMI:
8606 case NAND:
8607 case NOR:
8608 case NWHILE:
8609 case NUNTIL:
8610 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8611 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8612 break;
8613 case NCMD:
8614 new->ncmd.redirect = copynode(n->ncmd.redirect);
8615 new->ncmd.args = copynode(n->ncmd.args);
8616 new->ncmd.assign = copynode(n->ncmd.assign);
8617 new->ncmd.backgnd = n->ncmd.backgnd;
8618 break;
8619 case NPIPE:
8620 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8621 new->npipe.backgnd = n->npipe.backgnd;
8622 break;
8623 case NREDIR:
8624 case NBACKGND:
8625 case NSUBSHELL:
8626 new->nredir.redirect = copynode(n->nredir.redirect);
8627 new->nredir.n = copynode(n->nredir.n);
8628 break;
8629 case NIF:
8630 new->nif.elsepart = copynode(n->nif.elsepart);
8631 new->nif.ifpart = copynode(n->nif.ifpart);
8632 new->nif.test = copynode(n->nif.test);
8633 break;
8634 case NFOR:
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008635 new->nfor.var = nodexstrdup(n->nfor.var);
Eric Andersencb57d552001-06-28 07:25:16 +00008636 new->nfor.body = copynode(n->nfor.body);
8637 new->nfor.args = copynode(n->nfor.args);
8638 break;
8639 case NCASE:
8640 new->ncase.cases = copynode(n->ncase.cases);
8641 new->ncase.expr = copynode(n->ncase.expr);
8642 break;
8643 case NCLIST:
8644 new->nclist.body = copynode(n->nclist.body);
8645 new->nclist.pattern = copynode(n->nclist.pattern);
8646 new->nclist.next = copynode(n->nclist.next);
8647 break;
8648 case NDEFUN:
8649 case NARG:
8650 new->narg.backquote = copynodelist(n->narg.backquote);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008651 new->narg.text = nodexstrdup(n->narg.text);
Eric Andersencb57d552001-06-28 07:25:16 +00008652 new->narg.next = copynode(n->narg.next);
8653 break;
8654 case NTO:
8655 case NFROM:
8656 case NFROMTO:
8657 case NAPPEND:
8658 case NTOOV:
8659 new->nfile.fname = copynode(n->nfile.fname);
8660 new->nfile.fd = n->nfile.fd;
8661 new->nfile.next = copynode(n->nfile.next);
8662 break;
8663 case NTOFD:
8664 case NFROMFD:
8665 new->ndup.vname = copynode(n->ndup.vname);
8666 new->ndup.dupfd = n->ndup.dupfd;
8667 new->ndup.fd = n->ndup.fd;
8668 new->ndup.next = copynode(n->ndup.next);
8669 break;
8670 case NHERE:
8671 case NXHERE:
8672 new->nhere.doc = copynode(n->nhere.doc);
8673 new->nhere.fd = n->nhere.fd;
8674 new->nhere.next = copynode(n->nhere.next);
8675 break;
8676 case NNOT:
8677 new->nnot.com = copynode(n->nnot.com);
8678 break;
8679 };
8680 new->type = n->type;
Eric Andersen62483552001-07-10 06:09:16 +00008681 return new;
Eric Andersencb57d552001-06-28 07:25:16 +00008682}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008683#endif /* COPYNODE_TABLE */
8684
8685#ifdef CALCSIZE_TABLE
8686static void
8687calcsize(const union node *n)
8688{
8689 const unsigned char *p;
8690
8691 if (n == NULL)
8692 return;
8693 funcblocksize += (int) nodesize[n->type];
8694
8695 p = copynode_ops + (int) copynode_ops_index[n->type];
8696 do {
8697 const char *no = ((const char *) n) + ((int)(*p & NODE_OFFSETMASK));
8698
8699 if (!(*p & NODE_MBRMASK)) { /* standard node */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008700 calcsize(*((const union node **) no));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008701 } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008702 funcstringsize += strlen(*((const char **)no)) + 1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008703 } else if (*p & NODE_NODELIST) { /* nodelist */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008704 sizenodelist(*((const struct nodelist **) no));
8705 } /* else integer -- ignore */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008706 } while (!(*p++ & NODE_NOMORE));
8707}
8708#else /* CALCSIZE_TABLE */
8709static void
8710calcsize(const union node *n)
8711{
8712 if (n == NULL)
8713 return;
8714 funcblocksize += nodesize[n->type];
8715 switch (n->type) {
8716 case NSEMI:
8717 case NAND:
8718 case NOR:
8719 case NWHILE:
8720 case NUNTIL:
8721 calcsize(n->nbinary.ch2);
8722 calcsize(n->nbinary.ch1);
8723 break;
8724 case NCMD:
8725 calcsize(n->ncmd.redirect);
8726 calcsize(n->ncmd.args);
8727 calcsize(n->ncmd.assign);
8728 break;
8729 case NPIPE:
8730 sizenodelist(n->npipe.cmdlist);
8731 break;
8732 case NREDIR:
8733 case NBACKGND:
8734 case NSUBSHELL:
8735 calcsize(n->nredir.redirect);
8736 calcsize(n->nredir.n);
8737 break;
8738 case NIF:
8739 calcsize(n->nif.elsepart);
8740 calcsize(n->nif.ifpart);
8741 calcsize(n->nif.test);
8742 break;
8743 case NFOR:
8744 funcstringsize += strlen(n->nfor.var) + 1;
8745 calcsize(n->nfor.body);
8746 calcsize(n->nfor.args);
8747 break;
8748 case NCASE:
8749 calcsize(n->ncase.cases);
8750 calcsize(n->ncase.expr);
8751 break;
8752 case NCLIST:
8753 calcsize(n->nclist.body);
8754 calcsize(n->nclist.pattern);
8755 calcsize(n->nclist.next);
8756 break;
8757 case NDEFUN:
8758 case NARG:
8759 sizenodelist(n->narg.backquote);
8760 funcstringsize += strlen(n->narg.text) + 1;
8761 calcsize(n->narg.next);
8762 break;
8763 case NTO:
8764 case NFROM:
8765 case NFROMTO:
8766 case NAPPEND:
8767 case NTOOV:
8768 calcsize(n->nfile.fname);
8769 calcsize(n->nfile.next);
8770 break;
8771 case NTOFD:
8772 case NFROMFD:
8773 calcsize(n->ndup.vname);
8774 calcsize(n->ndup.next);
8775 break;
8776 case NHERE:
8777 case NXHERE:
8778 calcsize(n->nhere.doc);
8779 calcsize(n->nhere.next);
8780 break;
8781 case NNOT:
8782 calcsize(n->nnot.com);
8783 break;
8784 };
8785}
8786#endif /* CALCSIZE_TABLE */
8787
8788static void
8789sizenodelist(const struct nodelist *lp)
8790{
8791 while (lp) {
8792 funcblocksize += ALIGN(sizeof(struct nodelist));
8793 calcsize(lp->n);
8794 lp = lp->next;
8795 }
8796}
Eric Andersencb57d552001-06-28 07:25:16 +00008797
8798
8799static struct nodelist *
Eric Andersen62483552001-07-10 06:09:16 +00008800copynodelist(const struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008801{
8802 struct nodelist *start;
8803 struct nodelist **lpp;
8804
8805 lpp = &start;
8806 while (lp) {
8807 *lpp = funcblock;
8808 funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist));
8809 (*lpp)->n = copynode(lp->n);
8810 lp = lp->next;
8811 lpp = &(*lpp)->next;
8812 }
8813 *lpp = NULL;
8814 return start;
8815}
8816
8817
Eric Andersencb57d552001-06-28 07:25:16 +00008818static char *
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008819nodexstrdup(const char *s)
Eric Andersencb57d552001-06-28 07:25:16 +00008820{
Eric Andersen62483552001-07-10 06:09:16 +00008821 const char *p = s;
8822 char *q = funcstring;
Eric Andersencb57d552001-06-28 07:25:16 +00008823 char *rtn = funcstring;
8824
8825 while ((*q++ = *p++) != '\0')
8826 continue;
8827 funcstring = q;
8828 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00008829}
8830
Eric Andersend35c5df2002-01-09 15:37:36 +00008831#ifdef CONFIG_ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00008832static int getopts (char *, char *, char **, int *, int *);
Eric Andersencb57d552001-06-28 07:25:16 +00008833#endif
8834
Eric Andersencb57d552001-06-28 07:25:16 +00008835/*
8836 * Process the shell command line arguments.
8837 */
8838
8839static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008840procargs(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008841{
8842 int i;
8843
8844 argptr = argv;
8845 if (argc > 0)
8846 argptr++;
8847 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00008848 optent_val(i) = 2;
Eric Andersencb57d552001-06-28 07:25:16 +00008849 options(1);
8850 if (*argptr == NULL && minusc == NULL)
8851 sflag = 1;
8852 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8853 iflag = 1;
8854 if (mflag == 2)
8855 mflag = iflag;
8856 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00008857 if (optent_val(i) == 2)
8858 optent_val(i) = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008859 arg0 = argv[0];
8860 if (sflag == 0 && minusc == NULL) {
8861 commandname = argv[0];
8862 arg0 = *argptr++;
8863 setinputfile(arg0, 0);
8864 commandname = arg0;
8865 }
8866 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8867 if (argptr && minusc && *argptr)
Eric Andersen2870d962001-07-02 17:27:21 +00008868 arg0 = *argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00008869
8870 shellparam.p = argptr;
8871 shellparam.optind = 1;
8872 shellparam.optoff = -1;
8873 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8874 while (*argptr) {
8875 shellparam.nparam++;
8876 argptr++;
8877 }
8878 optschanged();
8879}
8880
8881
Eric Andersencb57d552001-06-28 07:25:16 +00008882
8883/*
8884 * Process shell options. The global variable argptr contains a pointer
8885 * to the argument list; we advance it past the options.
8886 */
8887
Eric Andersen62483552001-07-10 06:09:16 +00008888static inline void
8889minus_o(const char *name, int val)
8890{
8891 int i;
8892
8893 if (name == NULL) {
8894 out1str("Current option settings\n");
8895 for (i = 0; i < NOPTS; i++)
8896 printf("%-16s%s\n", optent_name(optlist[i]),
8897 optent_val(i) ? "on" : "off");
8898 } else {
8899 for (i = 0; i < NOPTS; i++)
8900 if (equal(name, optent_name(optlist[i]))) {
8901 setoption(optent_letter(optlist[i]), val);
8902 return;
8903 }
8904 error("Illegal option -o %s", name);
8905 }
8906}
8907
8908
Eric Andersencb57d552001-06-28 07:25:16 +00008909static void
Eric Andersen62483552001-07-10 06:09:16 +00008910options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00008911{
8912 char *p;
8913 int val;
8914 int c;
8915
8916 if (cmdline)
8917 minusc = NULL;
8918 while ((p = *argptr) != NULL) {
8919 argptr++;
8920 if ((c = *p++) == '-') {
8921 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00008922 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8923 if (!cmdline) {
8924 /* "-" means turn off -x and -v */
8925 if (p[0] == '\0')
8926 xflag = vflag = 0;
8927 /* "--" means reset params */
8928 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00008929 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00008930 }
8931 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00008932 }
8933 } else if (c == '+') {
8934 val = 0;
8935 } else {
8936 argptr--;
8937 break;
8938 }
8939 while ((c = *p++) != '\0') {
8940 if (c == 'c' && cmdline) {
8941 char *q;
Eric Andersen2870d962001-07-02 17:27:21 +00008942#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */
Eric Andersencb57d552001-06-28 07:25:16 +00008943 if (*p == '\0')
8944#endif
8945 q = *argptr++;
8946 if (q == NULL || minusc != NULL)
8947 error("Bad -c option");
8948 minusc = q;
8949#ifdef NOHACK
8950 break;
8951#endif
8952 } else if (c == 'o') {
8953 minus_o(*argptr, val);
8954 if (*argptr)
8955 argptr++;
Robert Griebl64f70cc2002-05-14 23:22:06 +00008956 } else if (cmdline && (c == '-')) { // long options
8957 if ( strcmp ( p, "login" ) == 0 )
8958 isloginsh = 1;
8959 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008960 } else {
8961 setoption(c, val);
8962 }
8963 }
8964 }
8965}
8966
Eric Andersencb57d552001-06-28 07:25:16 +00008967
8968static void
Eric Andersen2870d962001-07-02 17:27:21 +00008969setoption(int flag, int val)
8970{
Eric Andersencb57d552001-06-28 07:25:16 +00008971 int i;
8972
8973 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00008974 if (optent_letter(optlist[i]) == flag) {
8975 optent_val(i) = val;
Eric Andersencb57d552001-06-28 07:25:16 +00008976 if (val) {
8977 /* #%$ hack for ksh semantics */
8978 if (flag == 'V')
8979 Eflag = 0;
8980 else if (flag == 'E')
8981 Vflag = 0;
8982 }
8983 return;
8984 }
8985 error("Illegal option -%c", flag);
8986 /* NOTREACHED */
8987}
8988
8989
8990
Eric Andersencb57d552001-06-28 07:25:16 +00008991/*
8992 * Set the shell parameters.
8993 */
8994
8995static void
Eric Andersen2870d962001-07-02 17:27:21 +00008996setparam(char **argv)
8997{
Eric Andersencb57d552001-06-28 07:25:16 +00008998 char **newparam;
8999 char **ap;
9000 int nparam;
9001
9002 for (nparam = 0 ; argv[nparam] ; nparam++);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00009003 ap = newparam = xmalloc((nparam + 1) * sizeof *ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009004 while (*argv) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00009005 *ap++ = xstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +00009006 }
9007 *ap = NULL;
9008 freeparam(&shellparam);
9009 shellparam.malloc = 1;
9010 shellparam.nparam = nparam;
9011 shellparam.p = newparam;
9012 shellparam.optind = 1;
9013 shellparam.optoff = -1;
9014}
9015
9016
9017/*
9018 * Free the list of positional parameters.
9019 */
9020
9021static void
Eric Andersen2870d962001-07-02 17:27:21 +00009022freeparam(volatile struct shparam *param)
9023{
Eric Andersencb57d552001-06-28 07:25:16 +00009024 char **ap;
9025
9026 if (param->malloc) {
9027 for (ap = param->p ; *ap ; ap++)
9028 ckfree(*ap);
9029 ckfree(param->p);
9030 }
9031}
9032
9033
9034
9035/*
9036 * The shift builtin command.
9037 */
9038
9039static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00009040shiftcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009041{
9042 int n;
9043 char **ap1, **ap2;
9044
9045 n = 1;
9046 if (argc > 1)
9047 n = number(argv[1]);
9048 if (n > shellparam.nparam)
9049 error("can't shift that many");
9050 INTOFF;
9051 shellparam.nparam -= n;
9052 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
9053 if (shellparam.malloc)
9054 ckfree(*ap1);
9055 }
9056 ap2 = shellparam.p;
9057 while ((*ap2++ = *ap1++) != NULL);
9058 shellparam.optind = 1;
9059 shellparam.optoff = -1;
9060 INTON;
9061 return 0;
9062}
9063
9064
9065
9066/*
9067 * The set command builtin.
9068 */
9069
9070static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00009071setcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009072{
9073 if (argc == 1)
9074 return showvarscmd(argc, argv);
9075 INTOFF;
9076 options(0);
9077 optschanged();
9078 if (*argptr != NULL) {
9079 setparam(argptr);
9080 }
9081 INTON;
9082 return 0;
9083}
9084
9085
9086static void
Eric Andersen2870d962001-07-02 17:27:21 +00009087getoptsreset(const char *value)
Eric Andersencb57d552001-06-28 07:25:16 +00009088{
9089 shellparam.optind = number(value);
9090 shellparam.optoff = -1;
9091}
9092
Eric Andersenbdfd0d72001-10-24 05:00:29 +00009093#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00009094static void change_lc_all(const char *value)
9095{
9096 if(value != 0 && *value != 0)
9097 setlocale(LC_ALL, value);
9098}
9099
9100static void change_lc_ctype(const char *value)
9101{
9102 if(value != 0 && *value != 0)
9103 setlocale(LC_CTYPE, value);
9104}
9105
9106#endif
9107
Eric Andersend35c5df2002-01-09 15:37:36 +00009108#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00009109/*
9110 * The getopts builtin. Shellparam.optnext points to the next argument
9111 * to be processed. Shellparam.optptr points to the next character to
9112 * be processed in the current argument. If shellparam.optnext is NULL,
9113 * then it's the first time getopts has been called.
9114 */
9115
9116static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00009117getoptscmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009118{
9119 char **optbase;
9120
9121 if (argc < 3)
9122 error("Usage: getopts optstring var [arg]");
9123 else if (argc == 3) {
9124 optbase = shellparam.p;
9125 if (shellparam.optind > shellparam.nparam + 1) {
9126 shellparam.optind = 1;
9127 shellparam.optoff = -1;
9128 }
9129 }
9130 else {
9131 optbase = &argv[3];
9132 if (shellparam.optind > argc - 2) {
9133 shellparam.optind = 1;
9134 shellparam.optoff = -1;
9135 }
9136 }
9137
9138 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9139 &shellparam.optoff);
9140}
9141
9142/*
9143 * Safe version of setvar, returns 1 on success 0 on failure.
9144 */
9145
9146static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00009147setvarsafe(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009148{
9149 struct jmploc jmploc;
9150 struct jmploc *volatile savehandler = handler;
9151 int err = 0;
9152#ifdef __GNUC__
9153 (void) &err;
9154#endif
9155
9156 if (setjmp(jmploc.loc))
9157 err = 1;
9158 else {
9159 handler = &jmploc;
9160 setvar(name, val, flags);
9161 }
9162 handler = savehandler;
9163 return err;
9164}
9165
9166static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00009167getopts(char *optstr, char *optvar, char **optfirst, int *myoptind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009168{
9169 char *p, *q;
9170 char c = '?';
9171 int done = 0;
9172 int err = 0;
9173 char s[10];
9174 char **optnext = optfirst + *myoptind - 1;
9175
9176 if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
9177 strlen(*(optnext - 1)) < *optoff)
9178 p = NULL;
9179 else
9180 p = *(optnext - 1) + *optoff;
9181 if (p == NULL || *p == '\0') {
9182 /* Current word is done, advance */
9183 if (optnext == NULL)
9184 return 1;
9185 p = *optnext;
9186 if (p == NULL || *p != '-' || *++p == '\0') {
9187atend:
9188 *myoptind = optnext - optfirst + 1;
9189 p = NULL;
9190 done = 1;
9191 goto out;
9192 }
9193 optnext++;
Eric Andersen2870d962001-07-02 17:27:21 +00009194 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009195 goto atend;
9196 }
9197
9198 c = *p++;
9199 for (q = optstr; *q != c; ) {
9200 if (*q == '\0') {
9201 if (optstr[0] == ':') {
9202 s[0] = c;
9203 s[1] = '\0';
9204 err |= setvarsafe("OPTARG", s, 0);
9205 }
9206 else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009207 out2fmt("Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009208 (void) unsetvar("OPTARG");
9209 }
9210 c = '?';
9211 goto bad;
9212 }
9213 if (*++q == ':')
9214 q++;
9215 }
9216
9217 if (*++q == ':') {
9218 if (*p == '\0' && (p = *optnext) == NULL) {
9219 if (optstr[0] == ':') {
9220 s[0] = c;
9221 s[1] = '\0';
9222 err |= setvarsafe("OPTARG", s, 0);
9223 c = ':';
9224 }
9225 else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009226 out2fmt("No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009227 (void) unsetvar("OPTARG");
9228 c = '?';
9229 }
9230 goto bad;
9231 }
9232
9233 if (p == *optnext)
9234 optnext++;
9235 setvarsafe("OPTARG", p, 0);
9236 p = NULL;
9237 }
9238 else
9239 setvarsafe("OPTARG", "", 0);
9240 *myoptind = optnext - optfirst + 1;
9241 goto out;
9242
9243bad:
9244 *myoptind = 1;
9245 p = NULL;
9246out:
9247 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersen3102ac42001-07-06 04:26:23 +00009248 snprintf(s, sizeof(s), "%d", *myoptind);
Eric Andersencb57d552001-06-28 07:25:16 +00009249 err |= setvarsafe("OPTIND", s, VNOFUNC);
9250 s[0] = c;
9251 s[1] = '\0';
9252 err |= setvarsafe(optvar, s, 0);
9253 if (err) {
9254 *myoptind = 1;
9255 *optoff = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00009256 exraise(EXERROR);
9257 }
9258 return done;
9259}
Eric Andersen2870d962001-07-02 17:27:21 +00009260#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009261
9262/*
9263 * XXX - should get rid of. have all builtins use getopt(3). the
9264 * library getopt must have the BSD extension static variable "optreset"
9265 * otherwise it can't be used within the shell safely.
9266 *
9267 * Standard option processing (a la getopt) for builtin routines. The
9268 * only argument that is passed to nextopt is the option string; the
9269 * other arguments are unnecessary. It return the character, or '\0' on
9270 * end of input.
9271 */
9272
9273static int
Eric Andersen62483552001-07-10 06:09:16 +00009274nextopt(const char *optstring)
9275{
Eric Andersencb57d552001-06-28 07:25:16 +00009276 char *p;
9277 const char *q;
9278 char c;
9279
9280 if ((p = optptr) == NULL || *p == '\0') {
9281 p = *argptr;
9282 if (p == NULL || *p != '-' || *++p == '\0')
9283 return '\0';
9284 argptr++;
Eric Andersen2870d962001-07-02 17:27:21 +00009285 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009286 return '\0';
9287 }
9288 c = *p++;
9289 for (q = optstring ; *q != c ; ) {
9290 if (*q == '\0')
9291 error("Illegal option -%c", c);
9292 if (*++q == ':')
9293 q++;
9294 }
9295 if (*++q == ':') {
9296 if (*p == '\0' && (p = *argptr++) == NULL)
9297 error("No arg for -%c option", c);
9298 optionarg = p;
9299 p = NULL;
9300 }
9301 optptr = p;
9302 return c;
9303}
9304
Eric Andersencb57d552001-06-28 07:25:16 +00009305static void
9306flushall() {
Eric Andersencb57d552001-06-28 07:25:16 +00009307 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009308 fflush(stdout);
Eric Andersencb57d552001-06-28 07:25:16 +00009309 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009310}
9311
9312
9313static void
Eric Andersen3102ac42001-07-06 04:26:23 +00009314out2fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009315{
9316 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00009317 va_start(ap, fmt);
Eric Andersen3102ac42001-07-06 04:26:23 +00009318 vfprintf(stderr, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009319 va_end(ap);
9320}
9321
Eric Andersencb57d552001-06-28 07:25:16 +00009322/*
9323 * Version of write which resumes after a signal is caught.
9324 */
9325
9326static int
Eric Andersen2870d962001-07-02 17:27:21 +00009327xwrite(int fd, const char *buf, int nbytes)
9328{
Eric Andersencb57d552001-06-28 07:25:16 +00009329 int ntry;
9330 int i;
9331 int n;
9332
9333 n = nbytes;
9334 ntry = 0;
9335 for (;;) {
9336 i = write(fd, buf, n);
9337 if (i > 0) {
9338 if ((n -= i) <= 0)
9339 return nbytes;
9340 buf += i;
9341 ntry = 0;
9342 } else if (i == 0) {
9343 if (++ntry > 10)
9344 return nbytes - n;
9345 } else if (errno != EINTR) {
9346 return -1;
9347 }
9348 }
9349}
9350
9351
Eric Andersencb57d552001-06-28 07:25:16 +00009352/*
9353 * Shell command parser.
9354 */
9355
9356#define EOFMARKLEN 79
9357
9358
9359
9360struct heredoc {
Eric Andersen2870d962001-07-02 17:27:21 +00009361 struct heredoc *next; /* next here document in list */
9362 union node *here; /* redirection node */
9363 char *eofmark; /* string indicating end of input */
9364 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009365};
9366
Eric Andersen2870d962001-07-02 17:27:21 +00009367static struct heredoc *heredoclist; /* list of here documents to read */
9368static int parsebackquote; /* nonzero if we are inside backquotes */
9369static int doprompt; /* if set, prompt the user */
9370static int needprompt; /* true if interactive and at start of line */
9371static int lasttoken; /* last token read */
Eric Andersencb57d552001-06-28 07:25:16 +00009372
Eric Andersen2870d962001-07-02 17:27:21 +00009373static char *wordtext; /* text of last word returned by readtoken */
Eric Andersencb57d552001-06-28 07:25:16 +00009374
Eric Andersen2870d962001-07-02 17:27:21 +00009375static struct nodelist *backquotelist;
9376static union node *redirnode;
Eric Andersen044228d2001-07-17 01:12:36 +00009377static struct heredoc *heredoc;
Eric Andersen2870d962001-07-02 17:27:21 +00009378static int quoteflag; /* set if (part of) last token was quoted */
9379static int startlinno; /* line # where last token started */
Eric Andersencb57d552001-06-28 07:25:16 +00009380
9381
Eric Andersen2870d962001-07-02 17:27:21 +00009382static union node *list (int);
9383static union node *andor (void);
9384static union node *pipeline (void);
9385static union node *command (void);
Eric Andersena3483db2001-10-24 08:01:06 +00009386static union node *simplecmd(union node **rpp, union node *redir);
Eric Andersen2870d962001-07-02 17:27:21 +00009387static void parsefname (void);
9388static void parseheredoc (void);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009389static char peektoken (void);
Eric Andersen2870d962001-07-02 17:27:21 +00009390static int readtoken (void);
9391static int xxreadtoken (void);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009392static int readtoken1 (int, int, const char *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00009393static int noexpand (char *);
9394static void synexpect (int) __attribute__((noreturn));
9395static void synerror (const char *) __attribute__((noreturn));
9396static void setprompt (int);
Eric Andersencb57d552001-06-28 07:25:16 +00009397
9398
9399/*
9400 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9401 * valid parse tree indicating a blank line.)
9402 */
9403
Eric Andersen2870d962001-07-02 17:27:21 +00009404static union node *
Eric Andersencb57d552001-06-28 07:25:16 +00009405parsecmd(int interact)
9406{
9407 int t;
9408
9409 tokpushback = 0;
9410 doprompt = interact;
9411 if (doprompt)
9412 setprompt(1);
9413 else
9414 setprompt(0);
9415 needprompt = 0;
9416 t = readtoken();
9417 if (t == TEOF)
9418 return NEOF;
9419 if (t == TNL)
9420 return NULL;
9421 tokpushback++;
9422 return list(1);
9423}
9424
9425
9426static union node *
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00009427list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +00009428{
9429 union node *n1, *n2, *n3;
9430 int tok;
9431
9432 checkkwd = 2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009433 if (nlflag == 0 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009434 return NULL;
9435 n1 = NULL;
9436 for (;;) {
9437 n2 = andor();
9438 tok = readtoken();
9439 if (tok == TBACKGND) {
9440 if (n2->type == NCMD || n2->type == NPIPE) {
9441 n2->ncmd.backgnd = 1;
9442 } else if (n2->type == NREDIR) {
9443 n2->type = NBACKGND;
9444 } else {
9445 n3 = (union node *)stalloc(sizeof (struct nredir));
9446 n3->type = NBACKGND;
9447 n3->nredir.n = n2;
9448 n3->nredir.redirect = NULL;
9449 n2 = n3;
9450 }
9451 }
9452 if (n1 == NULL) {
9453 n1 = n2;
9454 }
9455 else {
9456 n3 = (union node *)stalloc(sizeof (struct nbinary));
9457 n3->type = NSEMI;
9458 n3->nbinary.ch1 = n1;
9459 n3->nbinary.ch2 = n2;
9460 n1 = n3;
9461 }
9462 switch (tok) {
9463 case TBACKGND:
9464 case TSEMI:
9465 tok = readtoken();
9466 /* fall through */
9467 case TNL:
9468 if (tok == TNL) {
9469 parseheredoc();
9470 if (nlflag)
9471 return n1;
9472 } else {
9473 tokpushback++;
9474 }
9475 checkkwd = 2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009476 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009477 return n1;
9478 break;
9479 case TEOF:
9480 if (heredoclist)
9481 parseheredoc();
9482 else
Eric Andersen2870d962001-07-02 17:27:21 +00009483 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009484 return n1;
9485 default:
9486 if (nlflag)
9487 synexpect(-1);
9488 tokpushback++;
9489 return n1;
9490 }
9491 }
9492}
9493
9494
9495
9496static union node *
9497andor() {
9498 union node *n1, *n2, *n3;
9499 int t;
9500
9501 checkkwd = 1;
9502 n1 = pipeline();
9503 for (;;) {
9504 if ((t = readtoken()) == TAND) {
9505 t = NAND;
9506 } else if (t == TOR) {
9507 t = NOR;
9508 } else {
9509 tokpushback++;
9510 return n1;
9511 }
9512 checkkwd = 2;
9513 n2 = pipeline();
9514 n3 = (union node *)stalloc(sizeof (struct nbinary));
9515 n3->type = t;
9516 n3->nbinary.ch1 = n1;
9517 n3->nbinary.ch2 = n2;
9518 n1 = n3;
9519 }
9520}
9521
9522
9523
9524static union node *
9525pipeline() {
9526 union node *n1, *n2, *pipenode;
9527 struct nodelist *lp, *prev;
9528 int negate;
9529
9530 negate = 0;
9531 TRACE(("pipeline: entered\n"));
9532 if (readtoken() == TNOT) {
9533 negate = !negate;
9534 checkkwd = 1;
9535 } else
9536 tokpushback++;
9537 n1 = command();
9538 if (readtoken() == TPIPE) {
9539 pipenode = (union node *)stalloc(sizeof (struct npipe));
9540 pipenode->type = NPIPE;
9541 pipenode->npipe.backgnd = 0;
9542 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9543 pipenode->npipe.cmdlist = lp;
9544 lp->n = n1;
9545 do {
9546 prev = lp;
9547 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9548 checkkwd = 2;
9549 lp->n = command();
9550 prev->next = lp;
9551 } while (readtoken() == TPIPE);
9552 lp->next = NULL;
9553 n1 = pipenode;
9554 }
9555 tokpushback++;
9556 if (negate) {
9557 n2 = (union node *)stalloc(sizeof (struct nnot));
9558 n2->type = NNOT;
9559 n2->nnot.com = n1;
9560 return n2;
9561 } else
9562 return n1;
9563}
9564
9565
9566
9567static union node *
Eric Andersena3483db2001-10-24 08:01:06 +00009568command(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009569 union node *n1, *n2;
9570 union node *ap, **app;
9571 union node *cp, **cpp;
9572 union node *redir, **rpp;
9573 int t;
9574
9575 redir = NULL;
9576 n1 = NULL;
9577 rpp = &redir;
9578
Eric Andersen88cec252001-09-06 17:35:20 +00009579 /* Check for redirection which may precede command */
9580 while (readtoken() == TREDIR) {
9581 *rpp = n2 = redirnode;
9582 rpp = &n2->nfile.next;
9583 parsefname();
9584 }
9585 tokpushback++;
9586
Eric Andersencb57d552001-06-28 07:25:16 +00009587 switch (readtoken()) {
9588 case TIF:
9589 n1 = (union node *)stalloc(sizeof (struct nif));
9590 n1->type = NIF;
9591 n1->nif.test = list(0);
9592 if (readtoken() != TTHEN)
9593 synexpect(TTHEN);
9594 n1->nif.ifpart = list(0);
9595 n2 = n1;
9596 while (readtoken() == TELIF) {
9597 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9598 n2 = n2->nif.elsepart;
9599 n2->type = NIF;
9600 n2->nif.test = list(0);
9601 if (readtoken() != TTHEN)
9602 synexpect(TTHEN);
9603 n2->nif.ifpart = list(0);
9604 }
9605 if (lasttoken == TELSE)
9606 n2->nif.elsepart = list(0);
9607 else {
9608 n2->nif.elsepart = NULL;
9609 tokpushback++;
9610 }
9611 if (readtoken() != TFI)
9612 synexpect(TFI);
9613 checkkwd = 1;
9614 break;
9615 case TWHILE:
9616 case TUNTIL: {
9617 int got;
9618 n1 = (union node *)stalloc(sizeof (struct nbinary));
9619 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9620 n1->nbinary.ch1 = list(0);
9621 if ((got=readtoken()) != TDO) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009622TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009623 synexpect(TDO);
9624 }
9625 n1->nbinary.ch2 = list(0);
9626 if (readtoken() != TDONE)
9627 synexpect(TDONE);
9628 checkkwd = 1;
9629 break;
9630 }
9631 case TFOR:
9632 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9633 synerror("Bad for loop variable");
9634 n1 = (union node *)stalloc(sizeof (struct nfor));
9635 n1->type = NFOR;
9636 n1->nfor.var = wordtext;
9637 checkkwd = 1;
9638 if (readtoken() == TIN) {
9639 app = &ap;
9640 while (readtoken() == TWORD) {
9641 n2 = (union node *)stalloc(sizeof (struct narg));
9642 n2->type = NARG;
9643 n2->narg.text = wordtext;
9644 n2->narg.backquote = backquotelist;
9645 *app = n2;
9646 app = &n2->narg.next;
9647 }
9648 *app = NULL;
9649 n1->nfor.args = ap;
9650 if (lasttoken != TNL && lasttoken != TSEMI)
9651 synexpect(-1);
9652 } else {
9653 static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
9654 '@', '=', '\0'};
9655 n2 = (union node *)stalloc(sizeof (struct narg));
9656 n2->type = NARG;
9657 n2->narg.text = argvars;
9658 n2->narg.backquote = NULL;
9659 n2->narg.next = NULL;
9660 n1->nfor.args = n2;
9661 /*
9662 * Newline or semicolon here is optional (but note
9663 * that the original Bourne shell only allowed NL).
9664 */
9665 if (lasttoken != TNL && lasttoken != TSEMI)
9666 tokpushback++;
9667 }
9668 checkkwd = 2;
9669 if (readtoken() != TDO)
9670 synexpect(TDO);
9671 n1->nfor.body = list(0);
9672 if (readtoken() != TDONE)
9673 synexpect(TDONE);
9674 checkkwd = 1;
9675 break;
9676 case TCASE:
9677 n1 = (union node *)stalloc(sizeof (struct ncase));
9678 n1->type = NCASE;
9679 if (readtoken() != TWORD)
9680 synexpect(TWORD);
9681 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9682 n2->type = NARG;
9683 n2->narg.text = wordtext;
9684 n2->narg.backquote = backquotelist;
9685 n2->narg.next = NULL;
9686 do {
9687 checkkwd = 1;
9688 } while (readtoken() == TNL);
9689 if (lasttoken != TIN)
9690 synerror("expecting \"in\"");
9691 cpp = &n1->ncase.cases;
9692 checkkwd = 2, readtoken();
9693 do {
9694 if (lasttoken == TLP)
9695 readtoken();
9696 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9697 cp->type = NCLIST;
9698 app = &cp->nclist.pattern;
9699 for (;;) {
9700 *app = ap = (union node *)stalloc(sizeof (struct narg));
9701 ap->type = NARG;
9702 ap->narg.text = wordtext;
9703 ap->narg.backquote = backquotelist;
9704 if (checkkwd = 2, readtoken() != TPIPE)
9705 break;
9706 app = &ap->narg.next;
9707 readtoken();
9708 }
9709 ap->narg.next = NULL;
9710 if (lasttoken != TRP)
9711 synexpect(TRP);
9712 cp->nclist.body = list(0);
9713
9714 checkkwd = 2;
9715 if ((t = readtoken()) != TESAC) {
9716 if (t != TENDCASE)
9717 synexpect(TENDCASE);
9718 else
9719 checkkwd = 2, readtoken();
9720 }
9721 cpp = &cp->nclist.next;
9722 } while(lasttoken != TESAC);
9723 *cpp = NULL;
9724 checkkwd = 1;
9725 break;
9726 case TLP:
9727 n1 = (union node *)stalloc(sizeof (struct nredir));
9728 n1->type = NSUBSHELL;
9729 n1->nredir.n = list(0);
9730 n1->nredir.redirect = NULL;
9731 if (readtoken() != TRP)
9732 synexpect(TRP);
9733 checkkwd = 1;
9734 break;
9735 case TBEGIN:
9736 n1 = list(0);
9737 if (readtoken() != TEND)
9738 synexpect(TEND);
9739 checkkwd = 1;
9740 break;
9741 /* Handle an empty command like other simple commands. */
9742 case TSEMI:
9743 case TAND:
9744 case TOR:
9745 case TNL:
9746 case TEOF:
9747 case TRP:
9748 case TBACKGND:
9749 /*
9750 * An empty command before a ; doesn't make much sense, and
9751 * should certainly be disallowed in the case of `if ;'.
9752 */
9753 if (!redir)
9754 synexpect(-1);
9755 case TWORD:
Eric Andersencb57d552001-06-28 07:25:16 +00009756 tokpushback++;
Eric Andersena3483db2001-10-24 08:01:06 +00009757 n1 = simplecmd(rpp, redir);
Eric Andersencb57d552001-06-28 07:25:16 +00009758 return n1;
9759 default:
9760 synexpect(-1);
9761 /* NOTREACHED */
9762 }
9763
9764 /* Now check for redirection which may follow command */
9765 while (readtoken() == TREDIR) {
9766 *rpp = n2 = redirnode;
9767 rpp = &n2->nfile.next;
9768 parsefname();
9769 }
9770 tokpushback++;
9771 *rpp = NULL;
9772 if (redir) {
9773 if (n1->type != NSUBSHELL) {
9774 n2 = (union node *)stalloc(sizeof (struct nredir));
9775 n2->type = NREDIR;
9776 n2->nredir.n = n1;
9777 n1 = n2;
9778 }
9779 n1->nredir.redirect = redir;
9780 }
9781
9782 return n1;
9783}
9784
9785
9786static union node *
Eric Andersena3483db2001-10-24 08:01:06 +00009787simplecmd(union node **rpp, union node *redir) {
Eric Andersencb57d552001-06-28 07:25:16 +00009788 union node *args, **app;
9789 union node *n = NULL;
9790 union node *vars, **vpp;
Eric Andersena3483db2001-10-24 08:01:06 +00009791 union node **orig_rpp;
Eric Andersencb57d552001-06-28 07:25:16 +00009792
9793 args = NULL;
9794 app = &args;
9795 vars = NULL;
9796 vpp = &vars;
Eric Andersena3483db2001-10-24 08:01:06 +00009797
9798 /* If we don't have any redirections already, then we must reset
9799 rpp to be the address of the local redir variable. */
9800 if (redir == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00009801 rpp = &redir;
Eric Andersena3483db2001-10-24 08:01:06 +00009802 /* We save the incoming value, because we need this for shell
9803 functions. There can not be a redirect or an argument between
9804 the function name and the open parenthesis. */
9805 orig_rpp = rpp;
Eric Andersencb57d552001-06-28 07:25:16 +00009806
9807 checkalias = 2;
9808 for (;;) {
9809 switch (readtoken()) {
9810 case TWORD:
9811 case TASSIGN:
9812 n = (union node *)stalloc(sizeof (struct narg));
9813 n->type = NARG;
9814 n->narg.text = wordtext;
9815 n->narg.backquote = backquotelist;
9816 if (lasttoken == TWORD) {
9817 *app = n;
9818 app = &n->narg.next;
9819 } else {
9820 *vpp = n;
9821 vpp = &n->narg.next;
9822 }
9823 break;
9824 case TREDIR:
9825 *rpp = n = redirnode;
9826 rpp = &n->nfile.next;
Eric Andersen2870d962001-07-02 17:27:21 +00009827 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +00009828 break;
9829 case TLP:
9830 if (
9831 args && app == &args->narg.next &&
Eric Andersena3483db2001-10-24 08:01:06 +00009832 !vars && rpp == orig_rpp
Eric Andersencb57d552001-06-28 07:25:16 +00009833 ) {
9834 /* We have a function */
9835 if (readtoken() != TRP)
9836 synexpect(TRP);
Eric Andersencb57d552001-06-28 07:25:16 +00009837 n->type = NDEFUN;
9838 checkkwd = 2;
9839 n->narg.next = command();
9840 return n;
9841 }
9842 /* fall through */
9843 default:
9844 tokpushback++;
9845 goto out;
9846 }
9847 }
9848out:
9849 *app = NULL;
9850 *vpp = NULL;
9851 *rpp = NULL;
9852 n = (union node *)stalloc(sizeof (struct ncmd));
9853 n->type = NCMD;
9854 n->ncmd.backgnd = 0;
9855 n->ncmd.args = args;
9856 n->ncmd.assign = vars;
9857 n->ncmd.redirect = redir;
9858 return n;
9859}
9860
9861static union node *
Eric Andersen2870d962001-07-02 17:27:21 +00009862makename(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009863 union node *n;
9864
9865 n = (union node *)stalloc(sizeof (struct narg));
9866 n->type = NARG;
9867 n->narg.next = NULL;
9868 n->narg.text = wordtext;
9869 n->narg.backquote = backquotelist;
9870 return n;
9871}
9872
9873static void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +00009874{
Eric Andersencb57d552001-06-28 07:25:16 +00009875 TRACE(("Fix redir %s %d\n", text, err));
9876 if (!err)
9877 n->ndup.vname = NULL;
9878
9879 if (is_digit(text[0]) && text[1] == '\0')
9880 n->ndup.dupfd = digit_val(text[0]);
9881 else if (text[0] == '-' && text[1] == '\0')
9882 n->ndup.dupfd = -1;
9883 else {
9884
9885 if (err)
9886 synerror("Bad fd number");
9887 else
9888 n->ndup.vname = makename();
9889 }
9890}
9891
9892
9893static void
Eric Andersen2870d962001-07-02 17:27:21 +00009894parsefname(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009895 union node *n = redirnode;
9896
9897 if (readtoken() != TWORD)
9898 synexpect(-1);
9899 if (n->type == NHERE) {
9900 struct heredoc *here = heredoc;
9901 struct heredoc *p;
9902 int i;
9903
9904 if (quoteflag == 0)
9905 n->type = NXHERE;
9906 TRACE(("Here document %d\n", n->type));
9907 if (here->striptabs) {
9908 while (*wordtext == '\t')
9909 wordtext++;
9910 }
9911 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9912 synerror("Illegal eof marker for << redirection");
9913 rmescapes(wordtext);
9914 here->eofmark = wordtext;
9915 here->next = NULL;
9916 if (heredoclist == NULL)
9917 heredoclist = here;
9918 else {
9919 for (p = heredoclist ; p->next ; p = p->next);
9920 p->next = here;
9921 }
9922 } else if (n->type == NTOFD || n->type == NFROMFD) {
9923 fixredir(n, wordtext, 0);
9924 } else {
9925 n->nfile.fname = makename();
9926 }
9927}
9928
9929
9930/*
9931 * Input any here documents.
9932 */
9933
9934static void
9935parseheredoc() {
9936 struct heredoc *here;
9937 union node *n;
9938
9939 while (heredoclist) {
9940 here = heredoclist;
9941 heredoclist = here->next;
9942 if (needprompt) {
9943 setprompt(2);
9944 needprompt = 0;
9945 }
9946 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9947 here->eofmark, here->striptabs);
9948 n = (union node *)stalloc(sizeof (struct narg));
9949 n->narg.type = NARG;
9950 n->narg.next = NULL;
9951 n->narg.text = wordtext;
9952 n->narg.backquote = backquotelist;
9953 here->here->nhere.doc = n;
9954 }
9955}
9956
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009957static char
Eric Andersencb57d552001-06-28 07:25:16 +00009958peektoken() {
9959 int t;
9960
9961 t = readtoken();
9962 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009963 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +00009964}
9965
9966static int
9967readtoken() {
9968 int t;
Eric Andersen7467c8d2001-07-12 20:26:32 +00009969
Eric Andersend35c5df2002-01-09 15:37:36 +00009970#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00009971 int savecheckalias = checkalias;
Eric Andersen7467c8d2001-07-12 20:26:32 +00009972 int savecheckkwd = checkkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009973 struct alias *ap;
Eric Andersen2870d962001-07-02 17:27:21 +00009974#endif
9975
Eric Andersencb57d552001-06-28 07:25:16 +00009976#ifdef DEBUG
9977 int alreadyseen = tokpushback;
9978#endif
9979
Eric Andersend35c5df2002-01-09 15:37:36 +00009980#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00009981top:
Eric Andersen2870d962001-07-02 17:27:21 +00009982#endif
9983
Eric Andersencb57d552001-06-28 07:25:16 +00009984 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +00009985
Eric Andersend35c5df2002-01-09 15:37:36 +00009986#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00009987 checkalias = savecheckalias;
Eric Andersen2870d962001-07-02 17:27:21 +00009988#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009989
9990 if (checkkwd) {
9991 /*
9992 * eat newlines
9993 */
9994 if (checkkwd == 2) {
9995 checkkwd = 0;
9996 while (t == TNL) {
9997 parseheredoc();
9998 t = xxreadtoken();
9999 }
10000 }
10001 checkkwd = 0;
10002 /*
10003 * check for keywords
10004 */
10005 if (t == TWORD && !quoteflag)
10006 {
10007 const char *const *pp;
10008
10009 if ((pp = findkwd(wordtext))) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010010 lasttoken = t = pp - tokname_array;
10011 TRACE(("keyword %s recognized\n", tokname(t)));
Eric Andersencb57d552001-06-28 07:25:16 +000010012 goto out;
10013 }
10014 }
10015 }
10016
Eric Andersen7467c8d2001-07-12 20:26:32 +000010017
Eric Andersencb57d552001-06-28 07:25:16 +000010018 if (t != TWORD) {
10019 if (t != TREDIR) {
10020 checkalias = 0;
10021 }
10022 } else if (checkalias == 2 && isassignment(wordtext)) {
10023 lasttoken = t = TASSIGN;
Eric Andersend35c5df2002-01-09 15:37:36 +000010024#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010025 } else if (checkalias) {
Eric Andersenec074692001-10-31 11:05:49 +000010026 if (!quoteflag && (ap = *__lookupalias(wordtext)) != NULL && !(ap->flag & ALIASINUSE)) {
Eric Andersencb57d552001-06-28 07:25:16 +000010027 if (*ap->val) {
10028 pushstring(ap->val, strlen(ap->val), ap);
10029 }
10030 checkkwd = savecheckkwd;
10031 goto top;
10032 }
10033 checkalias = 0;
Eric Andersen2870d962001-07-02 17:27:21 +000010034#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +000010035 }
Eric Andersencb57d552001-06-28 07:25:16 +000010036out:
10037#ifdef DEBUG
10038 if (!alreadyseen)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010039 TRACE(("token %s %s\n", tokname(t), t == TWORD || t == TASSIGN ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +000010040 else
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010041 TRACE(("reread token %s %s\n", tokname(t), t == TWORD || t == TASSIGN ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +000010042#endif
10043 return (t);
10044}
10045
10046
10047/*
10048 * Read the next input token.
10049 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +000010050 * backquotes. We set quoteflag to true if any part of the word was
10051 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +000010052 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +000010053 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +000010054 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +000010055 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +000010056 *
10057 * [Change comment: here documents and internal procedures]
10058 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10059 * word parsing code into a separate routine. In this case, readtoken
10060 * doesn't need to have any internal procedures, but parseword does.
10061 * We could also make parseoperator in essence the main routine, and
10062 * have parseword (readtoken1?) handle both words and redirection.]
10063 */
10064
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +000010065#define NEW_xxreadtoken
10066#ifdef NEW_xxreadtoken
10067
10068static const char xxreadtoken_chars[] = "\n()&|;"; /* singles must be first! */
10069static const char xxreadtoken_tokens[] = {
10070 TNL, TLP, TRP, /* only single occurrence allowed */
10071 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10072 TEOF, /* corresponds to trailing nul */
10073 TAND, TOR, TENDCASE, /* if double occurrence */
10074};
10075
10076#define xxreadtoken_doubles \
10077 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10078#define xxreadtoken_singles \
10079 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10080
10081static int
10082xxreadtoken() {
10083 int c;
10084
10085 if (tokpushback) {
10086 tokpushback = 0;
10087 return lasttoken;
10088 }
10089 if (needprompt) {
10090 setprompt(2);
10091 needprompt = 0;
10092 }
10093 startlinno = plinno;
10094 for (;;) { /* until token or start of word found */
10095 c = pgetc_macro();
10096
10097 if ((c!=' ') && (c!='\t')
Eric Andersend35c5df2002-01-09 15:37:36 +000010098#ifdef CONFIG_ASH_ALIAS
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +000010099 && (c!=PEOA)
10100#endif
10101 ) {
10102 if (c=='#') {
10103 while ((c = pgetc()) != '\n' && c != PEOF);
10104 pungetc();
10105 } else if (c=='\\') {
10106 if (pgetc() != '\n') {
10107 pungetc();
10108 goto READTOKEN1;
10109 }
10110 startlinno = ++plinno;
10111 setprompt(doprompt ? 2 : 0);
10112 } else {
10113 const char *p
10114 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10115
10116 if (c!=PEOF) {
10117 if (c=='\n') {
10118 plinno++;
10119 needprompt = doprompt;
10120 }
10121
10122 p = strchr(xxreadtoken_chars, c);
10123 if (p == NULL) {
10124 READTOKEN1:
10125 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10126 }
10127
10128 if (p-xxreadtoken_chars >= xxreadtoken_singles) {
10129 if (pgetc() == *p) { /* double occurrence? */
10130 p += xxreadtoken_doubles + 1;
10131 } else {
10132 pungetc();
10133 }
10134 }
10135 }
10136
10137 return lasttoken = xxreadtoken_tokens[p-xxreadtoken_chars];
10138 }
10139 }
10140 }
10141}
10142
10143
10144#else
Eric Andersen2870d962001-07-02 17:27:21 +000010145#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010146
10147static int
10148xxreadtoken() {
10149 int c;
10150
10151 if (tokpushback) {
10152 tokpushback = 0;
10153 return lasttoken;
10154 }
10155 if (needprompt) {
10156 setprompt(2);
10157 needprompt = 0;
10158 }
10159 startlinno = plinno;
Eric Andersen2870d962001-07-02 17:27:21 +000010160 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010161 c = pgetc_macro();
10162 switch (c) {
10163 case ' ': case '\t':
Eric Andersend35c5df2002-01-09 15:37:36 +000010164#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010165 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010166#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010167 continue;
10168 case '#':
10169 while ((c = pgetc()) != '\n' && c != PEOF);
10170 pungetc();
10171 continue;
10172 case '\\':
10173 if (pgetc() == '\n') {
10174 startlinno = ++plinno;
10175 if (doprompt)
10176 setprompt(2);
10177 else
10178 setprompt(0);
10179 continue;
10180 }
10181 pungetc();
10182 goto breakloop;
10183 case '\n':
10184 plinno++;
10185 needprompt = doprompt;
10186 RETURN(TNL);
10187 case PEOF:
10188 RETURN(TEOF);
10189 case '&':
10190 if (pgetc() == '&')
10191 RETURN(TAND);
10192 pungetc();
10193 RETURN(TBACKGND);
10194 case '|':
10195 if (pgetc() == '|')
10196 RETURN(TOR);
10197 pungetc();
10198 RETURN(TPIPE);
10199 case ';':
10200 if (pgetc() == ';')
10201 RETURN(TENDCASE);
10202 pungetc();
10203 RETURN(TSEMI);
10204 case '(':
10205 RETURN(TLP);
10206 case ')':
10207 RETURN(TRP);
10208 default:
10209 goto breakloop;
10210 }
10211 }
10212breakloop:
10213 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10214#undef RETURN
10215}
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +000010216#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010217
Eric Andersencb57d552001-06-28 07:25:16 +000010218/*
10219 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10220 * is not NULL, read a here document. In the latter case, eofmark is the
10221 * word which marks the end of the document and striptabs is true if
10222 * leading tabs should be stripped from the document. The argument firstc
10223 * is the first character of the input token or document.
10224 *
10225 * Because C does not have internal subroutines, I have simulated them
10226 * using goto's to implement the subroutine linkage. The following macros
10227 * will run code that appears at the end of readtoken1.
10228 */
10229
Eric Andersen2870d962001-07-02 17:27:21 +000010230#define CHECKEND() {goto checkend; checkend_return:;}
10231#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10232#define PARSESUB() {goto parsesub; parsesub_return:;}
10233#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10234#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10235#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010236
10237static int
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010238readtoken1(int firstc, int syntax, const char *eofmark, int striptabs)
10239{
Eric Andersencb57d552001-06-28 07:25:16 +000010240 int c = firstc;
10241 char *out;
10242 int len;
10243 char line[EOFMARKLEN + 1];
10244 struct nodelist *bqlist;
10245 int quotef;
10246 int dblquote;
Eric Andersen2870d962001-07-02 17:27:21 +000010247 int varnest; /* levels of variables expansion */
10248 int arinest; /* levels of arithmetic expansion */
10249 int parenlevel; /* levels of parens in arithmetic */
10250 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +000010251 int oldstyle;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010252 int prevsyntax; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010253#if __GNUC__
10254 /* Avoid longjmp clobbering */
10255 (void) &out;
10256 (void) &quotef;
10257 (void) &dblquote;
10258 (void) &varnest;
10259 (void) &arinest;
10260 (void) &parenlevel;
10261 (void) &dqvarnest;
10262 (void) &oldstyle;
10263 (void) &prevsyntax;
10264 (void) &syntax;
10265#endif
10266
10267 startlinno = plinno;
10268 dblquote = 0;
10269 if (syntax == DQSYNTAX)
10270 dblquote = 1;
10271 quotef = 0;
10272 bqlist = NULL;
10273 varnest = 0;
10274 arinest = 0;
10275 parenlevel = 0;
10276 dqvarnest = 0;
10277
10278 STARTSTACKSTR(out);
Eric Andersen2870d962001-07-02 17:27:21 +000010279 loop: { /* for each line, until end of word */
10280 CHECKEND(); /* set c to PEOF if at end of here document */
10281 for (;;) { /* until end of line or end of word */
10282 CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010283 switch(SIT(c,syntax)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010284 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010285 if (syntax == BASESYNTAX)
Eric Andersen2870d962001-07-02 17:27:21 +000010286 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010287 USTPUTC(c, out);
10288 plinno++;
10289 if (doprompt)
10290 setprompt(2);
10291 else
10292 setprompt(0);
10293 c = pgetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010294 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010295 case CWORD:
10296 USTPUTC(c, out);
10297 break;
10298 case CCTL:
10299 if ((eofmark == NULL || dblquote) &&
10300 dqvarnest == 0)
10301 USTPUTC(CTLESC, out);
10302 USTPUTC(c, out);
10303 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010304 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010305 c = pgetc2();
10306 if (c == PEOF) {
10307 USTPUTC('\\', out);
10308 pungetc();
10309 } else if (c == '\n') {
10310 if (doprompt)
10311 setprompt(2);
10312 else
10313 setprompt(0);
10314 } else {
10315 if (dblquote && c != '\\' && c != '`' && c != '$'
10316 && (c != '"' || eofmark != NULL))
10317 USTPUTC('\\', out);
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010318 if (SIT(c,SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010319 USTPUTC(CTLESC, out);
10320 else if (eofmark == NULL)
10321 USTPUTC(CTLQUOTEMARK, out);
10322 USTPUTC(c, out);
10323 quotef++;
10324 }
10325 break;
10326 case CSQUOTE:
10327 if (eofmark == NULL)
10328 USTPUTC(CTLQUOTEMARK, out);
10329 syntax = SQSYNTAX;
10330 break;
10331 case CDQUOTE:
10332 if (eofmark == NULL)
10333 USTPUTC(CTLQUOTEMARK, out);
10334 syntax = DQSYNTAX;
10335 dblquote = 1;
10336 break;
10337 case CENDQUOTE:
10338 if (eofmark != NULL && arinest == 0 &&
10339 varnest == 0) {
10340 USTPUTC(c, out);
10341 } else {
10342 if (arinest) {
10343 syntax = ARISYNTAX;
10344 dblquote = 0;
10345 } else if (eofmark == NULL &&
10346 dqvarnest == 0) {
10347 syntax = BASESYNTAX;
10348 dblquote = 0;
10349 }
10350 quotef++;
10351 }
10352 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010353 case CVAR: /* '$' */
10354 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010355 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010356 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010357 if (varnest > 0) {
10358 varnest--;
10359 if (dqvarnest > 0) {
10360 dqvarnest--;
10361 }
10362 USTPUTC(CTLENDVAR, out);
10363 } else {
10364 USTPUTC(c, out);
10365 }
10366 break;
Eric Andersend35c5df2002-01-09 15:37:36 +000010367#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +000010368 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010369 parenlevel++;
10370 USTPUTC(c, out);
10371 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010372 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010373 if (parenlevel > 0) {
10374 USTPUTC(c, out);
10375 --parenlevel;
10376 } else {
10377 if (pgetc() == ')') {
10378 if (--arinest == 0) {
10379 USTPUTC(CTLENDARI, out);
10380 syntax = prevsyntax;
10381 if (syntax == DQSYNTAX)
10382 dblquote = 1;
10383 else
10384 dblquote = 0;
10385 } else
10386 USTPUTC(')', out);
10387 } else {
10388 /*
10389 * unbalanced parens
10390 * (don't 2nd guess - no error)
10391 */
10392 pungetc();
10393 USTPUTC(')', out);
10394 }
10395 }
10396 break;
10397#endif
Eric Andersen2870d962001-07-02 17:27:21 +000010398 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010399 PARSEBACKQOLD();
10400 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010401 case CENDFILE:
10402 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010403 case CIGN:
10404 break;
10405 default:
10406 if (varnest == 0)
Eric Andersen2870d962001-07-02 17:27:21 +000010407 goto endword; /* exit outer loop */
Eric Andersend35c5df2002-01-09 15:37:36 +000010408#ifdef CONFIG_ASH_ALIAS
Eric Andersen3102ac42001-07-06 04:26:23 +000010409 if (c != PEOA)
10410#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010411 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010412
Eric Andersencb57d552001-06-28 07:25:16 +000010413 }
10414 c = pgetc_macro();
10415 }
10416 }
10417endword:
10418 if (syntax == ARISYNTAX)
10419 synerror("Missing '))'");
10420 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10421 synerror("Unterminated quoted string");
10422 if (varnest != 0) {
10423 startlinno = plinno;
10424 synerror("Missing '}'");
10425 }
10426 USTPUTC('\0', out);
10427 len = out - stackblock();
10428 out = stackblock();
10429 if (eofmark == NULL) {
10430 if ((c == '>' || c == '<')
10431 && quotef == 0
10432 && len <= 2
10433 && (*out == '\0' || is_digit(*out))) {
10434 PARSEREDIR();
10435 return lasttoken = TREDIR;
10436 } else {
10437 pungetc();
10438 }
10439 }
10440 quoteflag = quotef;
10441 backquotelist = bqlist;
10442 grabstackblock(len);
10443 wordtext = out;
10444 return lasttoken = TWORD;
10445/* end of readtoken routine */
10446
10447
10448
10449/*
10450 * Check to see whether we are at the end of the here document. When this
10451 * is called, c is set to the first character of the next input line. If
10452 * we are at the end of the here document, this routine sets the c to PEOF.
10453 */
10454
10455checkend: {
10456 if (eofmark) {
Eric Andersend35c5df2002-01-09 15:37:36 +000010457#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010458 if (c == PEOA) {
10459 c = pgetc2();
10460 }
Eric Andersen2870d962001-07-02 17:27:21 +000010461#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010462 if (striptabs) {
10463 while (c == '\t') {
10464 c = pgetc2();
10465 }
10466 }
10467 if (c == *eofmark) {
10468 if (pfgets(line, sizeof line) != NULL) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010469 const char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010470
10471 p = line;
10472 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10473 if (*p == '\n' && *q == '\0') {
10474 c = PEOF;
10475 plinno++;
10476 needprompt = doprompt;
10477 } else {
10478 pushstring(line, strlen(line), NULL);
10479 }
10480 }
10481 }
10482 }
10483 goto checkend_return;
10484}
10485
10486
10487/*
10488 * Parse a redirection operator. The variable "out" points to a string
10489 * specifying the fd to be redirected. The variable "c" contains the
10490 * first character of the redirection operator.
10491 */
10492
10493parseredir: {
10494 char fd = *out;
10495 union node *np;
10496
10497 np = (union node *)stalloc(sizeof (struct nfile));
10498 if (c == '>') {
10499 np->nfile.fd = 1;
10500 c = pgetc();
10501 if (c == '>')
10502 np->type = NAPPEND;
10503 else if (c == '&')
10504 np->type = NTOFD;
10505 else if (c == '|')
10506 np->type = NTOOV;
10507 else {
10508 np->type = NTO;
10509 pungetc();
10510 }
Eric Andersen2870d962001-07-02 17:27:21 +000010511 } else { /* c == '<' */
Eric Andersencb57d552001-06-28 07:25:16 +000010512 np->nfile.fd = 0;
10513 switch (c = pgetc()) {
10514 case '<':
10515 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10516 np = (union node *)stalloc(sizeof (struct nhere));
10517 np->nfile.fd = 0;
10518 }
10519 np->type = NHERE;
10520 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10521 heredoc->here = np;
10522 if ((c = pgetc()) == '-') {
10523 heredoc->striptabs = 1;
10524 } else {
10525 heredoc->striptabs = 0;
10526 pungetc();
10527 }
10528 break;
10529
10530 case '&':
10531 np->type = NFROMFD;
10532 break;
10533
10534 case '>':
10535 np->type = NFROMTO;
10536 break;
10537
10538 default:
10539 np->type = NFROM;
10540 pungetc();
10541 break;
10542 }
10543 }
10544 if (fd != '\0')
10545 np->nfile.fd = digit_val(fd);
10546 redirnode = np;
10547 goto parseredir_return;
10548}
10549
10550
10551/*
10552 * Parse a substitution. At this point, we have read the dollar sign
10553 * and nothing else.
10554 */
10555
10556parsesub: {
10557 int subtype;
10558 int typeloc;
10559 int flags;
10560 char *p;
10561 static const char types[] = "}-+?=";
10562
10563 c = pgetc();
10564 if (
10565 c <= PEOA ||
10566 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10567 ) {
10568 USTPUTC('$', out);
10569 pungetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010570 } else if (c == '(') { /* $(command) or $((arith)) */
Eric Andersencb57d552001-06-28 07:25:16 +000010571 if (pgetc() == '(') {
10572 PARSEARITH();
10573 } else {
10574 pungetc();
10575 PARSEBACKQNEW();
10576 }
10577 } else {
10578 USTPUTC(CTLVAR, out);
10579 typeloc = out - stackblock();
10580 USTPUTC(VSNORMAL, out);
10581 subtype = VSNORMAL;
10582 if (c == '{') {
10583 c = pgetc();
10584 if (c == '#') {
10585 if ((c = pgetc()) == '}')
10586 c = '#';
10587 else
10588 subtype = VSLENGTH;
10589 }
10590 else
10591 subtype = 0;
10592 }
10593 if (c > PEOA && is_name(c)) {
10594 do {
10595 STPUTC(c, out);
10596 c = pgetc();
10597 } while (c > PEOA && is_in_name(c));
10598 } else if (is_digit(c)) {
10599 do {
10600 USTPUTC(c, out);
10601 c = pgetc();
10602 } while (is_digit(c));
10603 }
10604 else if (is_special(c)) {
10605 USTPUTC(c, out);
10606 c = pgetc();
10607 }
10608 else
Eric Andersen2870d962001-07-02 17:27:21 +000010609badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010610
10611 STPUTC('=', out);
10612 flags = 0;
10613 if (subtype == 0) {
10614 switch (c) {
10615 case ':':
10616 flags = VSNUL;
10617 c = pgetc();
10618 /*FALLTHROUGH*/
10619 default:
10620 p = strchr(types, c);
10621 if (p == NULL)
10622 goto badsub;
10623 subtype = p - types + VSNORMAL;
10624 break;
10625 case '%':
10626 case '#':
10627 {
10628 int cc = c;
10629 subtype = c == '#' ? VSTRIMLEFT :
10630 VSTRIMRIGHT;
10631 c = pgetc();
10632 if (c == cc)
10633 subtype++;
10634 else
10635 pungetc();
10636 break;
10637 }
10638 }
10639 } else {
10640 pungetc();
10641 }
10642 if (dblquote || arinest)
10643 flags |= VSQUOTE;
10644 *(stackblock() + typeloc) = subtype | flags;
10645 if (subtype != VSNORMAL) {
10646 varnest++;
10647 if (dblquote) {
10648 dqvarnest++;
10649 }
10650 }
10651 }
10652 goto parsesub_return;
10653}
10654
10655
10656/*
10657 * Called to parse command substitutions. Newstyle is set if the command
10658 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10659 * list of commands (passed by reference), and savelen is the number of
10660 * characters on the top of the stack which must be preserved.
10661 */
10662
10663parsebackq: {
10664 struct nodelist **nlpp;
10665 int savepbq;
10666 union node *n;
10667 char *volatile str;
10668 struct jmploc jmploc;
10669 struct jmploc *volatile savehandler;
10670 int savelen;
10671 int saveprompt;
10672#ifdef __GNUC__
10673 (void) &saveprompt;
10674#endif
10675
10676 savepbq = parsebackquote;
10677 if (setjmp(jmploc.loc)) {
10678 if (str)
10679 ckfree(str);
10680 parsebackquote = 0;
10681 handler = savehandler;
10682 longjmp(handler->loc, 1);
10683 }
10684 INTOFF;
10685 str = NULL;
10686 savelen = out - stackblock();
10687 if (savelen > 0) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010688 str = xmalloc(savelen);
Eric Andersencb57d552001-06-28 07:25:16 +000010689 memcpy(str, stackblock(), savelen);
10690 }
10691 savehandler = handler;
10692 handler = &jmploc;
10693 INTON;
Eric Andersen2870d962001-07-02 17:27:21 +000010694 if (oldstyle) {
10695 /* We must read until the closing backquote, giving special
10696 treatment to some slashes, and then push the string and
10697 reread it as input, interpreting it normally. */
10698 char *pout;
10699 int pc;
10700 int psavelen;
10701 char *pstr;
Eric Andersencb57d552001-06-28 07:25:16 +000010702
10703
Eric Andersen2870d962001-07-02 17:27:21 +000010704 STARTSTACKSTR(pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010705 for (;;) {
10706 if (needprompt) {
10707 setprompt(2);
10708 needprompt = 0;
10709 }
10710 switch (pc = pgetc()) {
10711 case '`':
10712 goto done;
10713
10714 case '\\':
Eric Andersen2870d962001-07-02 17:27:21 +000010715 if ((pc = pgetc()) == '\n') {
Eric Andersencb57d552001-06-28 07:25:16 +000010716 plinno++;
10717 if (doprompt)
10718 setprompt(2);
10719 else
10720 setprompt(0);
10721 /*
10722 * If eating a newline, avoid putting
10723 * the newline into the new character
10724 * stream (via the STPUTC after the
10725 * switch).
10726 */
10727 continue;
10728 }
Eric Andersen2870d962001-07-02 17:27:21 +000010729 if (pc != '\\' && pc != '`' && pc != '$'
10730 && (!dblquote || pc != '"'))
10731 STPUTC('\\', pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010732 if (pc > PEOA) {
10733 break;
10734 }
10735 /* fall through */
10736
10737 case PEOF:
Eric Andersend35c5df2002-01-09 15:37:36 +000010738#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010739 case PEOA:
Eric Andersen2870d962001-07-02 17:27:21 +000010740#endif
10741 startlinno = plinno;
Eric Andersencb57d552001-06-28 07:25:16 +000010742 synerror("EOF in backquote substitution");
10743
10744 case '\n':
10745 plinno++;
10746 needprompt = doprompt;
10747 break;
10748
10749 default:
10750 break;
10751 }
10752 STPUTC(pc, pout);
Eric Andersen2870d962001-07-02 17:27:21 +000010753 }
Eric Andersencb57d552001-06-28 07:25:16 +000010754done:
Eric Andersen2870d962001-07-02 17:27:21 +000010755 STPUTC('\0', pout);
10756 psavelen = pout - stackblock();
10757 if (psavelen > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010758 pstr = grabstackstr(pout);
10759 setinputstring(pstr);
Eric Andersen2870d962001-07-02 17:27:21 +000010760 }
10761 }
Eric Andersencb57d552001-06-28 07:25:16 +000010762 nlpp = &bqlist;
10763 while (*nlpp)
10764 nlpp = &(*nlpp)->next;
10765 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10766 (*nlpp)->next = NULL;
10767 parsebackquote = oldstyle;
10768
10769 if (oldstyle) {
10770 saveprompt = doprompt;
10771 doprompt = 0;
10772 }
10773
10774 n = list(0);
10775
10776 if (oldstyle)
10777 doprompt = saveprompt;
10778 else {
10779 if (readtoken() != TRP)
10780 synexpect(TRP);
10781 }
10782
10783 (*nlpp)->n = n;
Eric Andersen2870d962001-07-02 17:27:21 +000010784 if (oldstyle) {
Eric Andersencb57d552001-06-28 07:25:16 +000010785 /*
10786 * Start reading from old file again, ignoring any pushed back
10787 * tokens left from the backquote parsing
10788 */
Eric Andersen2870d962001-07-02 17:27:21 +000010789 popfile();
Eric Andersencb57d552001-06-28 07:25:16 +000010790 tokpushback = 0;
10791 }
10792 while (stackblocksize() <= savelen)
10793 growstackblock();
10794 STARTSTACKSTR(out);
10795 if (str) {
10796 memcpy(out, str, savelen);
10797 STADJUST(savelen, out);
10798 INTOFF;
10799 ckfree(str);
10800 str = NULL;
10801 INTON;
10802 }
10803 parsebackquote = savepbq;
10804 handler = savehandler;
10805 if (arinest || dblquote)
10806 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10807 else
10808 USTPUTC(CTLBACKQ, out);
10809 if (oldstyle)
10810 goto parsebackq_oldreturn;
10811 else
10812 goto parsebackq_newreturn;
10813}
10814
10815/*
10816 * Parse an arithmetic expansion (indicate start of one and set state)
10817 */
10818parsearith: {
10819
10820 if (++arinest == 1) {
10821 prevsyntax = syntax;
10822 syntax = ARISYNTAX;
10823 USTPUTC(CTLARI, out);
10824 if (dblquote)
10825 USTPUTC('"',out);
10826 else
10827 USTPUTC(' ',out);
10828 } else {
10829 /*
10830 * we collapse embedded arithmetic expansion to
10831 * parenthesis, which should be equivalent
10832 */
10833 USTPUTC('(', out);
10834 }
10835 goto parsearith_return;
10836}
10837
10838} /* end of readtoken */
10839
10840
Eric Andersencb57d552001-06-28 07:25:16 +000010841/*
10842 * Returns true if the text contains nothing to expand (no dollar signs
10843 * or backquotes).
10844 */
10845
10846static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010847noexpand(char *text)
10848{
Eric Andersencb57d552001-06-28 07:25:16 +000010849 char *p;
10850 char c;
10851
10852 p = text;
10853 while ((c = *p++) != '\0') {
10854 if (c == CTLQUOTEMARK)
10855 continue;
10856 if (c == CTLESC)
10857 p++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010858 else if (SIT(c,BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010859 return 0;
10860 }
10861 return 1;
10862}
10863
10864
10865/*
10866 * Return true if the argument is a legal variable name (a letter or
10867 * underscore followed by zero or more letters, underscores, and digits).
10868 */
10869
10870static int
Eric Andersen2870d962001-07-02 17:27:21 +000010871goodname(const char *name)
10872{
10873 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000010874
10875 p = name;
10876 if (! is_name(*p))
10877 return 0;
10878 while (*++p) {
10879 if (! is_in_name(*p))
10880 return 0;
10881 }
10882 return 1;
10883}
10884
10885
10886/*
10887 * Called when an unexpected token is read during the parse. The argument
10888 * is the token that is expected, or -1 if more than one type of token can
10889 * occur at this point.
10890 */
10891
10892static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010893synexpect(int token)
Eric Andersencb57d552001-06-28 07:25:16 +000010894{
10895 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010896 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000010897
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010898 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10899 if (token >= 0)
10900 sprintf(msg+l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000010901 synerror(msg);
10902 /* NOTREACHED */
10903}
10904
10905
10906static void
Eric Andersen2870d962001-07-02 17:27:21 +000010907synerror(const char *msg)
10908{
Eric Andersencb57d552001-06-28 07:25:16 +000010909 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +000010910 out2fmt("%s: %d: ", commandname, startlinno);
10911 out2fmt("Syntax error: %s\n", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000010912 error((char *)NULL);
10913 /* NOTREACHED */
10914}
10915
Eric Andersencb57d552001-06-28 07:25:16 +000010916
10917/*
10918 * called by editline -- any expansions to the prompt
10919 * should be added here.
10920 */
Eric Andersen2870d962001-07-02 17:27:21 +000010921static void
Eric Andersen62483552001-07-10 06:09:16 +000010922setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000010923{
Eric Andersen62483552001-07-10 06:09:16 +000010924 char *prompt;
10925 switch (whichprompt) {
10926 case 1:
10927 prompt = ps1val();
10928 break;
10929 case 2:
10930 prompt = ps2val();
10931 break;
10932 default: /* 0 */
10933 prompt = "";
10934 }
10935 putprompt(prompt);
Eric Andersencb57d552001-06-28 07:25:16 +000010936}
10937
Eric Andersencb57d552001-06-28 07:25:16 +000010938
Eric Andersencb57d552001-06-28 07:25:16 +000010939/*
10940 * Code for dealing with input/output redirection.
10941 */
10942
Eric Andersen2870d962001-07-02 17:27:21 +000010943#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000010944#ifndef PIPE_BUF
Eric Andersen2870d962001-07-02 17:27:21 +000010945# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000010946#else
10947# define PIPESIZE PIPE_BUF
10948#endif
10949
10950
Eric Andersen62483552001-07-10 06:09:16 +000010951/*
10952 * Open a file in noclobber mode.
10953 * The code was copied from bash.
10954 */
10955static inline int
10956noclobberopen(const char *fname)
10957{
10958 int r, fd;
10959 struct stat finfo, finfo2;
10960
10961 /*
10962 * If the file exists and is a regular file, return an error
10963 * immediately.
10964 */
10965 r = stat(fname, &finfo);
10966 if (r == 0 && S_ISREG(finfo.st_mode)) {
10967 errno = EEXIST;
10968 return -1;
10969 }
10970
10971 /*
10972 * If the file was not present (r != 0), make sure we open it
10973 * exclusively so that if it is created before we open it, our open
10974 * will fail. Make sure that we do not truncate an existing file.
10975 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10976 * file was not a regular file, we leave O_EXCL off.
10977 */
10978 if (r != 0)
10979 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10980 fd = open(fname, O_WRONLY|O_CREAT, 0666);
10981
10982 /* If the open failed, return the file descriptor right away. */
10983 if (fd < 0)
10984 return fd;
10985
10986 /*
10987 * OK, the open succeeded, but the file may have been changed from a
10988 * non-regular file to a regular file between the stat and the open.
10989 * We are assuming that the O_EXCL open handles the case where FILENAME
10990 * did not exist and is symlinked to an existing file between the stat
10991 * and open.
10992 */
10993
10994 /*
10995 * If we can open it and fstat the file descriptor, and neither check
10996 * revealed that it was a regular file, and the file has not been
10997 * replaced, return the file descriptor.
10998 */
10999 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
11000 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
11001 return fd;
11002
11003 /* The file has been replaced. badness. */
11004 close(fd);
11005 errno = EEXIST;
11006 return -1;
11007}
Eric Andersencb57d552001-06-28 07:25:16 +000011008
11009/*
Eric Andersen62483552001-07-10 06:09:16 +000011010 * Handle here documents. Normally we fork off a process to write the
11011 * data to a pipe. If the document is short, we can stuff the data in
11012 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000011013 */
11014
Eric Andersen62483552001-07-10 06:09:16 +000011015static inline int
11016openhere(const union node *redir)
11017{
11018 int pip[2];
11019 int len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011020
Eric Andersen62483552001-07-10 06:09:16 +000011021 if (pipe(pip) < 0)
11022 error("Pipe call failed");
11023 if (redir->type == NHERE) {
11024 len = strlen(redir->nhere.doc->narg.text);
11025 if (len <= PIPESIZE) {
11026 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11027 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011028 }
Eric Andersencb57d552001-06-28 07:25:16 +000011029 }
Eric Andersen62483552001-07-10 06:09:16 +000011030 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
11031 close(pip[0]);
11032 signal(SIGINT, SIG_IGN);
11033 signal(SIGQUIT, SIG_IGN);
11034 signal(SIGHUP, SIG_IGN);
11035#ifdef SIGTSTP
11036 signal(SIGTSTP, SIG_IGN);
11037#endif
11038 signal(SIGPIPE, SIG_DFL);
11039 if (redir->type == NHERE)
11040 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11041 else
11042 expandhere(redir->nhere.doc, pip[1]);
11043 _exit(0);
11044 }
11045out:
11046 close(pip[1]);
11047 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000011048}
11049
11050
Eric Andersen62483552001-07-10 06:09:16 +000011051static inline int
11052openredirect(const union node *redir)
11053{
Eric Andersencb57d552001-06-28 07:25:16 +000011054 char *fname;
11055 int f;
11056
11057 switch (redir->nfile.type) {
11058 case NFROM:
11059 fname = redir->nfile.expfname;
11060 if ((f = open(fname, O_RDONLY)) < 0)
11061 goto eopen;
11062 break;
11063 case NFROMTO:
11064 fname = redir->nfile.expfname;
11065 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
11066 goto ecreate;
11067 break;
11068 case NTO:
11069 /* Take care of noclobber mode. */
11070 if (Cflag) {
11071 fname = redir->nfile.expfname;
11072 if ((f = noclobberopen(fname)) < 0)
11073 goto ecreate;
11074 break;
11075 }
11076 case NTOOV:
11077 fname = redir->nfile.expfname;
11078#ifdef O_CREAT
11079 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
11080 goto ecreate;
11081#else
11082 if ((f = creat(fname, 0666)) < 0)
11083 goto ecreate;
11084#endif
11085 break;
11086 case NAPPEND:
11087 fname = redir->nfile.expfname;
11088#ifdef O_APPEND
11089 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
11090 goto ecreate;
11091#else
11092 if ((f = open(fname, O_WRONLY)) < 0
11093 && (f = creat(fname, 0666)) < 0)
11094 goto ecreate;
11095 lseek(f, (off_t)0, 2);
11096#endif
11097 break;
11098 default:
11099#ifdef DEBUG
11100 abort();
11101#endif
11102 /* Fall through to eliminate warning. */
11103 case NTOFD:
11104 case NFROMFD:
11105 f = -1;
11106 break;
11107 case NHERE:
11108 case NXHERE:
11109 f = openhere(redir);
11110 break;
11111 }
11112
11113 return f;
11114ecreate:
11115 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11116eopen:
11117 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11118}
11119
11120
Eric Andersen62483552001-07-10 06:09:16 +000011121/*
11122 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11123 * old file descriptors are stashed away so that the redirection can be
11124 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11125 * standard output, and the standard error if it becomes a duplicate of
11126 * stdout.
11127 */
11128
Eric Andersencb57d552001-06-28 07:25:16 +000011129static void
Eric Andersen62483552001-07-10 06:09:16 +000011130redirect(union node *redir, int flags)
11131{
11132 union node *n;
11133 struct redirtab *sv = NULL;
11134 int i;
11135 int fd;
11136 int newfd;
11137 int try;
11138 int fd1dup = flags & REDIR_BACKQ;; /* stdout `cmd` redir to pipe */
11139
11140 if (flags & REDIR_PUSH) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011141 sv = xmalloc(sizeof (struct redirtab));
Eric Andersen62483552001-07-10 06:09:16 +000011142 for (i = 0 ; i < 10 ; i++)
11143 sv->renamed[i] = EMPTY;
11144 sv->next = redirlist;
11145 redirlist = sv;
11146 }
11147 for (n = redir ; n ; n = n->nfile.next) {
11148 fd = n->nfile.fd;
11149 try = 0;
11150 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11151 n->ndup.dupfd == fd)
11152 continue; /* redirect from/to same file descriptor */
11153
11154 INTOFF;
11155 newfd = openredirect(n);
11156 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
11157 if (newfd == fd) {
11158 try++;
11159 } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
11160 switch (errno) {
11161 case EBADF:
11162 if (!try) {
11163 dupredirect(n, newfd, fd1dup);
11164 try++;
11165 break;
11166 }
11167 /* FALLTHROUGH*/
11168 default:
11169 if (newfd >= 0) {
11170 close(newfd);
11171 }
11172 INTON;
11173 error("%d: %m", fd);
11174 /* NOTREACHED */
11175 }
11176 }
11177 if (!try) {
11178 close(fd);
11179 if (flags & REDIR_PUSH) {
11180 sv->renamed[fd] = i;
11181 }
11182 }
11183 } else if (fd != newfd) {
11184 close(fd);
11185 }
11186 if (fd == 0)
11187 fd0_redirected++;
11188 if (!try)
11189 dupredirect(n, newfd, fd1dup);
11190 INTON;
11191 }
11192}
11193
11194
11195static void
11196dupredirect(const union node *redir, int f, int fd1dup)
Eric Andersen2870d962001-07-02 17:27:21 +000011197{
Eric Andersencb57d552001-06-28 07:25:16 +000011198 int fd = redir->nfile.fd;
11199
Eric Andersen62483552001-07-10 06:09:16 +000011200 if(fd==1)
11201 fd1dup = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011202 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Eric Andersen2870d962001-07-02 17:27:21 +000011203 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
Eric Andersen62483552001-07-10 06:09:16 +000011204 if (redir->ndup.dupfd!=1 || fd1dup!=1)
Eric Andersencb57d552001-06-28 07:25:16 +000011205 dup_as_newfd(redir->ndup.dupfd, fd);
11206 }
11207 return;
11208 }
11209
11210 if (f != fd) {
11211 dup_as_newfd(f, fd);
11212 close(f);
11213 }
11214 return;
11215}
11216
11217
Eric Andersencb57d552001-06-28 07:25:16 +000011218
Eric Andersencb57d552001-06-28 07:25:16 +000011219/*
11220 * Undo the effects of the last redirection.
11221 */
11222
11223static void
Eric Andersen2870d962001-07-02 17:27:21 +000011224popredir(void)
11225{
Eric Andersencb57d552001-06-28 07:25:16 +000011226 struct redirtab *rp = redirlist;
11227 int i;
11228
11229 INTOFF;
11230 for (i = 0 ; i < 10 ; i++) {
11231 if (rp->renamed[i] != EMPTY) {
Eric Andersen2870d962001-07-02 17:27:21 +000011232 if (i == 0)
11233 fd0_redirected--;
Eric Andersencb57d552001-06-28 07:25:16 +000011234 close(i);
11235 if (rp->renamed[i] >= 0) {
11236 dup_as_newfd(rp->renamed[i], i);
11237 close(rp->renamed[i]);
11238 }
Eric Andersencb57d552001-06-28 07:25:16 +000011239 }
11240 }
11241 redirlist = rp->next;
11242 ckfree(rp);
11243 INTON;
11244}
11245
11246/*
Eric Andersencb57d552001-06-28 07:25:16 +000011247 * Discard all saved file descriptors.
11248 */
11249
11250static void
Eric Andersen2870d962001-07-02 17:27:21 +000011251clearredir(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000011252 struct redirtab *rp;
11253 int i;
11254
11255 for (rp = redirlist ; rp ; rp = rp->next) {
11256 for (i = 0 ; i < 10 ; i++) {
11257 if (rp->renamed[i] >= 0) {
11258 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011259 }
11260 rp->renamed[i] = EMPTY;
11261 }
11262 }
Eric Andersencb57d552001-06-28 07:25:16 +000011263}
11264
11265
Eric Andersencb57d552001-06-28 07:25:16 +000011266/*
11267 * Copy a file descriptor to be >= to. Returns -1
11268 * if the source file descriptor is closed, EMPTY if there are no unused
11269 * file descriptors left.
11270 */
11271
11272static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011273dup_as_newfd(int from, int to)
Eric Andersencb57d552001-06-28 07:25:16 +000011274{
11275 int newfd;
11276
11277 newfd = fcntl(from, F_DUPFD, to);
11278 if (newfd < 0) {
11279 if (errno == EMFILE)
11280 return EMPTY;
11281 else
Eric Andersen2870d962001-07-02 17:27:21 +000011282 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011283 }
11284 return newfd;
11285}
11286
Eric Andersencb57d552001-06-28 07:25:16 +000011287#ifdef DEBUG
Eric Andersenec074692001-10-31 11:05:49 +000011288/*
11289 * Debugging stuff.
11290 */
Eric Andersen2870d962001-07-02 17:27:21 +000011291static void shtree (union node *, int, char *, FILE*);
11292static void shcmd (union node *, FILE *);
11293static void sharg (union node *, FILE *);
11294static void indent (int, char *, FILE *);
11295static void trstring (char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011296
11297
11298static void
11299showtree(n)
Eric Andersen69a20f02001-10-31 10:40:37 +000011300 unode *n;
Eric Andersencb57d552001-06-28 07:25:16 +000011301{
11302 trputs("showtree called\n");
11303 shtree(n, 1, NULL, stdout);
11304}
11305
11306
11307static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011308shtree(union node *n, int ind, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011309{
11310 struct nodelist *lp;
11311 const char *s;
11312
11313 if (n == NULL)
11314 return;
11315
11316 indent(ind, pfx, fp);
11317 switch(n->type) {
11318 case NSEMI:
11319 s = "; ";
11320 goto binop;
11321 case NAND:
11322 s = " && ";
11323 goto binop;
11324 case NOR:
11325 s = " || ";
11326binop:
11327 shtree(n->nbinary.ch1, ind, NULL, fp);
11328 /* if (ind < 0) */
11329 fputs(s, fp);
11330 shtree(n->nbinary.ch2, ind, NULL, fp);
11331 break;
11332 case NCMD:
11333 shcmd(n, fp);
11334 if (ind >= 0)
11335 putc('\n', fp);
11336 break;
11337 case NPIPE:
11338 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11339 shcmd(lp->n, fp);
11340 if (lp->next)
11341 fputs(" | ", fp);
11342 }
11343 if (n->npipe.backgnd)
11344 fputs(" &", fp);
11345 if (ind >= 0)
11346 putc('\n', fp);
11347 break;
11348 default:
11349 fprintf(fp, "<node type %d>", n->type);
11350 if (ind >= 0)
11351 putc('\n', fp);
11352 break;
11353 }
11354}
11355
11356
11357
11358static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011359shcmd(union node *cmd, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011360{
11361 union node *np;
11362 int first;
11363 const char *s;
11364 int dftfd;
11365
11366 first = 1;
11367 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11368 if (! first)
11369 putchar(' ');
11370 sharg(np, fp);
11371 first = 0;
11372 }
11373 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11374 if (! first)
11375 putchar(' ');
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011376#if 1
11377 s = "*error*";
11378 dftfd = 0;
11379 if ((np->nfile.type <= NFROMFD) && (np->nfile.type >= NTO)) {
11380 s = redir_strings[np->nfile.type - NTO];
11381 if (*s == '>') {
11382 dftfd = 1;
11383 }
11384 }
11385#else
Eric Andersencb57d552001-06-28 07:25:16 +000011386 switch (np->nfile.type) {
Eric Andersen2870d962001-07-02 17:27:21 +000011387 case NTO: s = ">"; dftfd = 1; break;
11388 case NAPPEND: s = ">>"; dftfd = 1; break;
11389 case NTOFD: s = ">&"; dftfd = 1; break;
11390 case NTOOV: s = ">|"; dftfd = 1; break;
11391 case NFROM: s = "<"; dftfd = 0; break;
11392 case NFROMFD: s = "<&"; dftfd = 0; break;
11393 case NFROMTO: s = "<>"; dftfd = 0; break;
11394 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011395 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011396#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011397 if (np->nfile.fd != dftfd)
11398 fprintf(fp, "%d", np->nfile.fd);
11399 fputs(s, fp);
11400 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11401 fprintf(fp, "%d", np->ndup.dupfd);
11402 } else {
11403 sharg(np->nfile.fname, fp);
11404 }
11405 first = 0;
11406 }
11407}
11408
Eric Andersencb57d552001-06-28 07:25:16 +000011409static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011410sharg(union node *arg, FILE *fp)
11411{
Eric Andersencb57d552001-06-28 07:25:16 +000011412 char *p;
11413 struct nodelist *bqlist;
11414 int subtype;
11415
11416 if (arg->type != NARG) {
11417 printf("<node type %d>\n", arg->type);
11418 fflush(stdout);
11419 abort();
11420 }
11421 bqlist = arg->narg.backquote;
11422 for (p = arg->narg.text ; *p ; p++) {
11423 switch (*p) {
11424 case CTLESC:
11425 putc(*++p, fp);
11426 break;
11427 case CTLVAR:
11428 putc('$', fp);
11429 putc('{', fp);
11430 subtype = *++p;
11431 if (subtype == VSLENGTH)
11432 putc('#', fp);
11433
11434 while (*p != '=')
11435 putc(*p++, fp);
11436
11437 if (subtype & VSNUL)
11438 putc(':', fp);
11439
11440 switch (subtype & VSTYPE) {
11441 case VSNORMAL:
11442 putc('}', fp);
11443 break;
11444 case VSMINUS:
11445 putc('-', fp);
11446 break;
11447 case VSPLUS:
11448 putc('+', fp);
11449 break;
11450 case VSQUESTION:
11451 putc('?', fp);
11452 break;
11453 case VSASSIGN:
11454 putc('=', fp);
11455 break;
11456 case VSTRIMLEFT:
11457 putc('#', fp);
11458 break;
11459 case VSTRIMLEFTMAX:
11460 putc('#', fp);
11461 putc('#', fp);
11462 break;
11463 case VSTRIMRIGHT:
11464 putc('%', fp);
11465 break;
11466 case VSTRIMRIGHTMAX:
11467 putc('%', fp);
11468 putc('%', fp);
11469 break;
11470 case VSLENGTH:
11471 break;
11472 default:
11473 printf("<subtype %d>", subtype);
11474 }
11475 break;
11476 case CTLENDVAR:
11477 putc('}', fp);
11478 break;
11479 case CTLBACKQ:
11480 case CTLBACKQ|CTLQUOTE:
11481 putc('$', fp);
11482 putc('(', fp);
11483 shtree(bqlist->n, -1, NULL, fp);
11484 putc(')', fp);
11485 break;
11486 default:
11487 putc(*p, fp);
11488 break;
11489 }
11490 }
11491}
11492
11493
11494static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011495indent(int amount, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011496{
11497 int i;
11498
11499 for (i = 0 ; i < amount ; i++) {
11500 if (pfx && i == amount - 1)
11501 fputs(pfx, fp);
11502 putc('\t', fp);
11503 }
11504}
Eric Andersencb57d552001-06-28 07:25:16 +000011505
11506
Eric Andersencb57d552001-06-28 07:25:16 +000011507FILE *tracefile;
11508
11509#if DEBUG == 2
11510static int debug = 1;
11511#else
11512static int debug = 0;
11513#endif
11514
11515
11516static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011517trputc(int c)
Eric Andersencb57d552001-06-28 07:25:16 +000011518{
11519 if (tracefile == NULL)
11520 return;
11521 putc(c, tracefile);
11522 if (c == '\n')
11523 fflush(tracefile);
11524}
11525
11526static void
11527trace(const char *fmt, ...)
11528{
11529 va_list va;
Eric Andersencb57d552001-06-28 07:25:16 +000011530 va_start(va, fmt);
Eric Andersencb57d552001-06-28 07:25:16 +000011531 if (tracefile != NULL) {
11532 (void) vfprintf(tracefile, fmt, va);
11533 if (strchr(fmt, '\n'))
11534 (void) fflush(tracefile);
11535 }
11536 va_end(va);
11537}
11538
11539
11540static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011541trputs(const char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011542{
11543 if (tracefile == NULL)
11544 return;
11545 fputs(s, tracefile);
11546 if (strchr(s, '\n'))
11547 fflush(tracefile);
11548}
11549
11550
11551static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011552trstring(char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011553{
11554 char *p;
11555 char c;
11556
11557 if (tracefile == NULL)
11558 return;
11559 putc('"', tracefile);
11560 for (p = s ; *p ; p++) {
11561 switch (*p) {
11562 case '\n': c = 'n'; goto backslash;
11563 case '\t': c = 't'; goto backslash;
11564 case '\r': c = 'r'; goto backslash;
11565 case '"': c = '"'; goto backslash;
11566 case '\\': c = '\\'; goto backslash;
11567 case CTLESC: c = 'e'; goto backslash;
11568 case CTLVAR: c = 'v'; goto backslash;
11569 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11570 case CTLBACKQ: c = 'q'; goto backslash;
11571 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
Eric Andersen2870d962001-07-02 17:27:21 +000011572backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011573 putc(c, tracefile);
11574 break;
11575 default:
11576 if (*p >= ' ' && *p <= '~')
11577 putc(*p, tracefile);
11578 else {
11579 putc('\\', tracefile);
11580 putc(*p >> 6 & 03, tracefile);
11581 putc(*p >> 3 & 07, tracefile);
11582 putc(*p & 07, tracefile);
11583 }
11584 break;
11585 }
11586 }
11587 putc('"', tracefile);
11588}
11589
11590
11591static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011592trargs(char **ap)
Eric Andersencb57d552001-06-28 07:25:16 +000011593{
11594 if (tracefile == NULL)
11595 return;
11596 while (*ap) {
11597 trstring(*ap++);
11598 if (*ap)
11599 putc(' ', tracefile);
11600 else
11601 putc('\n', tracefile);
11602 }
11603 fflush(tracefile);
11604}
11605
11606
11607static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011608opentrace()
11609{
Eric Andersencb57d552001-06-28 07:25:16 +000011610 char s[100];
11611#ifdef O_APPEND
11612 int flags;
11613#endif
11614
11615 if (!debug)
11616 return;
11617#ifdef not_this_way
11618 {
11619 char *p;
11620 if ((p = getenv("HOME")) == NULL) {
11621 if (geteuid() == 0)
11622 p = "/";
11623 else
11624 p = "/tmp";
11625 }
Eric Andersen2870d962001-07-02 17:27:21 +000011626 strcpy(s, p);
Eric Andersencb57d552001-06-28 07:25:16 +000011627 strcat(s, "/trace");
11628 }
11629#else
Eric Andersen2870d962001-07-02 17:27:21 +000011630 strcpy(s, "./trace");
Eric Andersencb57d552001-06-28 07:25:16 +000011631#endif /* not_this_way */
Matt Kraaia5f09c62001-11-12 16:44:55 +000011632 if ((tracefile = wfopen(s, "a")) == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000011633 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011634#ifdef O_APPEND
11635 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11636 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11637#endif
11638 fputs("\nTracing started.\n", tracefile);
11639 fflush(tracefile);
11640}
11641#endif /* DEBUG */
11642
11643
11644/*
Eric Andersencb57d552001-06-28 07:25:16 +000011645 * The trap builtin.
11646 */
11647
11648static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011649trapcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011650{
11651 char *action;
11652 char **ap;
11653 int signo;
11654
11655 if (argc <= 1) {
11656 for (signo = 0 ; signo < NSIG ; signo++) {
11657 if (trap[signo] != NULL) {
11658 char *p;
Eric Andersen34506362001-08-02 05:02:46 +000011659 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011660
11661 p = single_quote(trap[signo]);
Eric Andersen34506362001-08-02 05:02:46 +000011662 sn = sys_siglist[signo];
11663 if(sn==NULL)
11664 sn = u_signal_names(0, &signo, 0);
11665 if(sn==NULL)
11666 sn = "???";
11667 printf("trap -- %s %s\n", p, sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011668 stunalloc(p);
11669 }
11670 }
11671 return 0;
11672 }
11673 ap = argv + 1;
11674 if (argc == 2)
11675 action = NULL;
11676 else
11677 action = *ap++;
11678 while (*ap) {
11679 if ((signo = decode_signal(*ap, 0)) < 0)
11680 error("%s: bad trap", *ap);
11681 INTOFF;
11682 if (action) {
11683 if (action[0] == '-' && action[1] == '\0')
11684 action = NULL;
11685 else
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011686 action = xstrdup(action);
Eric Andersencb57d552001-06-28 07:25:16 +000011687 }
11688 if (trap[signo])
11689 ckfree(trap[signo]);
11690 trap[signo] = action;
11691 if (signo != 0)
11692 setsignal(signo);
11693 INTON;
11694 ap++;
11695 }
11696 return 0;
11697}
11698
11699
11700
Eric Andersencb57d552001-06-28 07:25:16 +000011701
11702
11703
11704/*
11705 * Set the signal handler for the specified signal. The routine figures
11706 * out what it should be set to.
11707 */
11708
11709static void
Eric Andersen2870d962001-07-02 17:27:21 +000011710setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011711{
11712 int action;
11713 char *t;
11714 struct sigaction act;
11715
11716 if ((t = trap[signo]) == NULL)
11717 action = S_DFL;
11718 else if (*t != '\0')
11719 action = S_CATCH;
11720 else
11721 action = S_IGN;
11722 if (rootshell && action == S_DFL) {
11723 switch (signo) {
11724 case SIGINT:
11725 if (iflag || minusc || sflag == 0)
11726 action = S_CATCH;
11727 break;
11728 case SIGQUIT:
11729#ifdef DEBUG
11730 {
Eric Andersencb57d552001-06-28 07:25:16 +000011731
11732 if (debug)
11733 break;
11734 }
11735#endif
11736 /* FALLTHROUGH */
11737 case SIGTERM:
11738 if (iflag)
11739 action = S_IGN;
11740 break;
Eric Andersend35c5df2002-01-09 15:37:36 +000011741#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +000011742 case SIGTSTP:
11743 case SIGTTOU:
11744 if (mflag)
11745 action = S_IGN;
11746 break;
11747#endif
11748 }
11749 }
11750
11751 t = &sigmode[signo - 1];
11752 if (*t == 0) {
11753 /*
11754 * current setting unknown
11755 */
11756 if (sigaction(signo, 0, &act) == -1) {
11757 /*
11758 * Pretend it worked; maybe we should give a warning
11759 * here, but other shells don't. We don't alter
11760 * sigmode, so that we retry every time.
11761 */
11762 return;
11763 }
11764 if (act.sa_handler == SIG_IGN) {
11765 if (mflag && (signo == SIGTSTP ||
11766 signo == SIGTTIN || signo == SIGTTOU)) {
Eric Andersen2870d962001-07-02 17:27:21 +000011767 *t = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000011768 } else
11769 *t = S_HARD_IGN;
11770 } else {
Eric Andersen2870d962001-07-02 17:27:21 +000011771 *t = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000011772 }
11773 }
11774 if (*t == S_HARD_IGN || *t == action)
11775 return;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011776 act.sa_handler = ((action == S_CATCH) ? onsig
11777 : ((action == S_IGN) ? SIG_IGN : SIG_DFL));
Eric Andersencb57d552001-06-28 07:25:16 +000011778 *t = action;
11779 act.sa_flags = 0;
11780 sigemptyset(&act.sa_mask);
11781 sigaction(signo, &act, 0);
11782}
11783
11784/*
11785 * Ignore a signal.
11786 */
11787
11788static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011789ignoresig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011790{
11791 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11792 signal(signo, SIG_IGN);
11793 }
11794 sigmode[signo - 1] = S_HARD_IGN;
11795}
11796
11797
Eric Andersencb57d552001-06-28 07:25:16 +000011798/*
11799 * Signal handler.
11800 */
11801
11802static void
Eric Andersen2870d962001-07-02 17:27:21 +000011803onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011804{
11805 if (signo == SIGINT && trap[SIGINT] == NULL) {
11806 onint();
11807 return;
11808 }
11809 gotsig[signo - 1] = 1;
11810 pendingsigs++;
11811}
11812
11813
Eric Andersencb57d552001-06-28 07:25:16 +000011814/*
11815 * Called to execute a trap. Perhaps we should avoid entering new trap
11816 * handlers while we are executing a trap handler.
11817 */
11818
11819static void
Eric Andersen2870d962001-07-02 17:27:21 +000011820dotrap(void)
11821{
Eric Andersencb57d552001-06-28 07:25:16 +000011822 int i;
11823 int savestatus;
11824
11825 for (;;) {
11826 for (i = 1 ; ; i++) {
11827 if (gotsig[i - 1])
11828 break;
11829 if (i >= NSIG - 1)
11830 goto done;
11831 }
11832 gotsig[i - 1] = 0;
11833 savestatus=exitstatus;
11834 evalstring(trap[i], 0);
11835 exitstatus=savestatus;
11836 }
11837done:
11838 pendingsigs = 0;
11839}
11840
Eric Andersencb57d552001-06-28 07:25:16 +000011841/*
11842 * Called to exit the shell.
11843 */
11844
11845static void
Eric Andersen2870d962001-07-02 17:27:21 +000011846exitshell(int status)
Eric Andersencb57d552001-06-28 07:25:16 +000011847{
11848 struct jmploc loc1, loc2;
11849 char *p;
11850
11851 TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
11852 if (setjmp(loc1.loc)) {
11853 goto l1;
11854 }
11855 if (setjmp(loc2.loc)) {
11856 goto l2;
11857 }
11858 handler = &loc1;
11859 if ((p = trap[0]) != NULL && *p != '\0') {
11860 trap[0] = NULL;
11861 evalstring(p, 0);
11862 }
Eric Andersen2870d962001-07-02 17:27:21 +000011863l1: handler = &loc2; /* probably unnecessary */
Eric Andersencb57d552001-06-28 07:25:16 +000011864 flushall();
Eric Andersend35c5df2002-01-09 15:37:36 +000011865#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersencb57d552001-06-28 07:25:16 +000011866 setjobctl(0);
11867#endif
11868l2: _exit(status);
11869 /* NOTREACHED */
11870}
11871
11872static int decode_signal(const char *string, int minsig)
11873{
11874 int signo;
Eric Andersen34506362001-08-02 05:02:46 +000011875 const char *name = u_signal_names(string, &signo, minsig);
Eric Andersencb57d552001-06-28 07:25:16 +000011876
Eric Andersen34506362001-08-02 05:02:46 +000011877 return name ? signo : -1;
Eric Andersencb57d552001-06-28 07:25:16 +000011878}
Eric Andersen34506362001-08-02 05:02:46 +000011879
Eric Andersen2870d962001-07-02 17:27:21 +000011880static struct var **hashvar (const char *);
11881static void showvars (const char *, int, int);
11882static struct var **findvar (struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011883
11884/*
11885 * Initialize the varable symbol tables and import the environment
11886 */
11887
Eric Andersencb57d552001-06-28 07:25:16 +000011888/*
11889 * This routine initializes the builtin variables. It is called when the
11890 * shell is initialized and again when a shell procedure is spawned.
11891 */
11892
11893static void
11894initvar() {
11895 const struct varinit *ip;
11896 struct var *vp;
11897 struct var **vpp;
11898
11899 for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
11900 if ((vp->flags & VEXPORT) == 0) {
11901 vpp = hashvar(ip->text);
11902 vp->next = *vpp;
11903 *vpp = vp;
Matt Kraaic8227632001-11-12 16:57:27 +000011904 vp->text = xstrdup(ip->text);
Eric Andersencb57d552001-06-28 07:25:16 +000011905 vp->flags = ip->flags;
11906 vp->func = ip->func;
11907 }
11908 }
Tim Riker497a8852002-04-13 05:37:10 +000011909#if !defined(CONFIG_FEATURE_COMMAND_EDITING) || !defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
Eric Andersencb57d552001-06-28 07:25:16 +000011910 /*
11911 * PS1 depends on uid
11912 */
11913 if ((vps1.flags & VEXPORT) == 0) {
Aaron Lehmann9a218bf2001-12-31 06:13:38 +000011914 vpp = hashvar("PS1=$");
Eric Andersencb57d552001-06-28 07:25:16 +000011915 vps1.next = *vpp;
11916 *vpp = &vps1;
Matt Kraaic8227632001-11-12 16:57:27 +000011917 vps1.text = xstrdup(geteuid() ? "PS1=$ " : "PS1=# ");
Eric Andersencb57d552001-06-28 07:25:16 +000011918 vps1.flags = VSTRFIXED|VTEXTFIXED;
11919 }
Tim Riker497a8852002-04-13 05:37:10 +000011920#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011921}
11922
11923/*
11924 * Set the value of a variable. The flags argument is ored with the
11925 * flags of the variable. If val is NULL, the variable is unset.
11926 */
11927
11928static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011929setvar(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011930{
11931 const char *p;
11932 int len;
11933 int namelen;
11934 char *nameeq;
11935 int isbad;
11936 int vallen = 0;
11937
11938 isbad = 0;
11939 p = name;
11940 if (! is_name(*p))
11941 isbad = 1;
11942 p++;
11943 for (;;) {
11944 if (! is_in_name(*p)) {
11945 if (*p == '\0' || *p == '=')
11946 break;
11947 isbad = 1;
11948 }
11949 p++;
11950 }
11951 namelen = p - name;
11952 if (isbad)
11953 error("%.*s: bad variable name", namelen, name);
Eric Andersen2870d962001-07-02 17:27:21 +000011954 len = namelen + 2; /* 2 is space for '=' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +000011955 if (val == NULL) {
11956 flags |= VUNSET;
11957 } else {
11958 len += vallen = strlen(val);
11959 }
11960 INTOFF;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011961 nameeq = xmalloc(len);
Eric Andersencb57d552001-06-28 07:25:16 +000011962 memcpy(nameeq, name, namelen);
11963 nameeq[namelen] = '=';
11964 if (val) {
11965 memcpy(nameeq + namelen + 1, val, vallen + 1);
11966 } else {
11967 nameeq[namelen + 1] = '\0';
11968 }
11969 setvareq(nameeq, flags);
11970 INTON;
11971}
11972
11973
11974
11975/*
11976 * Same as setvar except that the variable and value are passed in
11977 * the first argument as name=value. Since the first argument will
11978 * be actually stored in the table, it should not be a string that
11979 * will go away.
11980 */
11981
11982static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011983setvareq(char *s, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011984{
11985 struct var *vp, **vpp;
11986
11987 vpp = hashvar(s);
11988 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
11989 if ((vp = *findvar(vpp, s))) {
11990 if (vp->flags & VREADONLY) {
11991 size_t len = strchr(s, '=') - s;
11992 error("%.*s: is read only", len, s);
11993 }
11994 INTOFF;
11995
11996 if (vp->func && (flags & VNOFUNC) == 0)
11997 (*vp->func)(strchr(s, '=') + 1);
11998
11999 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12000 ckfree(vp->text);
12001
12002 vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
12003 vp->flags |= flags;
12004 vp->text = s;
12005
Eric Andersend35c5df2002-01-09 15:37:36 +000012006#ifdef CONFIG_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000012007 /*
12008 * We could roll this to a function, to handle it as
12009 * a regular variable function callback, but why bother?
12010 */
12011 if (iflag && (vp == &vmpath || (vp == &vmail && !mpathset())))
12012 chkmail(1);
Eric Andersenec074692001-10-31 11:05:49 +000012013#endif
Eric Andersencb57d552001-06-28 07:25:16 +000012014 INTON;
12015 return;
12016 }
12017 /* not found */
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012018 vp = xmalloc(sizeof (*vp));
Eric Andersencb57d552001-06-28 07:25:16 +000012019 vp->flags = flags;
12020 vp->text = s;
12021 vp->next = *vpp;
12022 vp->func = NULL;
12023 *vpp = vp;
12024}
12025
12026
12027
12028/*
12029 * Process a linked list of variable assignments.
12030 */
12031
12032static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012033listsetvar(struct strlist *mylist)
12034{
Eric Andersencb57d552001-06-28 07:25:16 +000012035 struct strlist *lp;
12036
12037 INTOFF;
12038 for (lp = mylist ; lp ; lp = lp->next) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012039 setvareq(xstrdup(lp->text), 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012040 }
12041 INTON;
12042}
12043
12044
12045
12046/*
12047 * Find the value of a variable. Returns NULL if not set.
12048 */
12049
Eric Andersen62483552001-07-10 06:09:16 +000012050static const char *
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012051lookupvar(const char *name)
Eric Andersenec074692001-10-31 11:05:49 +000012052{
Eric Andersencb57d552001-06-28 07:25:16 +000012053 struct var *v;
12054
12055 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
12056 return strchr(v->text, '=') + 1;
12057 }
12058 return NULL;
12059}
12060
12061
12062
12063/*
12064 * Search the environment of a builtin command.
12065 */
12066
Eric Andersen62483552001-07-10 06:09:16 +000012067static const char *
12068bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012069{
Eric Andersen62483552001-07-10 06:09:16 +000012070 const struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012071
12072 for (sp = cmdenviron ; sp ; sp = sp->next) {
12073 if (varequal(sp->text, name))
12074 return strchr(sp->text, '=') + 1;
12075 }
12076 return lookupvar(name);
12077}
12078
12079
12080
12081/*
12082 * Generate a list of exported variables. This routine is used to construct
12083 * the third argument to execve when executing a program.
12084 */
12085
12086static char **
12087environment() {
12088 int nenv;
12089 struct var **vpp;
12090 struct var *vp;
12091 char **env;
12092 char **ep;
12093
12094 nenv = 0;
12095 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12096 for (vp = *vpp ; vp ; vp = vp->next)
12097 if (vp->flags & VEXPORT)
12098 nenv++;
12099 }
12100 ep = env = stalloc((nenv + 1) * sizeof *env);
12101 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12102 for (vp = *vpp ; vp ; vp = vp->next)
12103 if (vp->flags & VEXPORT)
12104 *ep++ = vp->text;
12105 }
12106 *ep = NULL;
12107 return env;
12108}
12109
12110
12111/*
12112 * Called when a shell procedure is invoked to clear out nonexported
12113 * variables. It is also necessary to reallocate variables of with
12114 * VSTACK set since these are currently allocated on the stack.
12115 */
12116
Eric Andersencb57d552001-06-28 07:25:16 +000012117static void
Eric Andersen2870d962001-07-02 17:27:21 +000012118shprocvar(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000012119 struct var **vpp;
12120 struct var *vp, **prev;
12121
12122 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12123 for (prev = vpp ; (vp = *prev) != NULL ; ) {
12124 if ((vp->flags & VEXPORT) == 0) {
12125 *prev = vp->next;
12126 if ((vp->flags & VTEXTFIXED) == 0)
12127 ckfree(vp->text);
12128 if ((vp->flags & VSTRFIXED) == 0)
12129 ckfree(vp);
12130 } else {
12131 if (vp->flags & VSTACK) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012132 vp->text = xstrdup(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012133 vp->flags &=~ VSTACK;
12134 }
12135 prev = &vp->next;
12136 }
12137 }
12138 }
12139 initvar();
12140}
12141
12142
12143
12144/*
12145 * Command to list all variables which are set. Currently this command
12146 * is invoked from the set command when the set command is called without
12147 * any variables.
12148 */
12149
12150static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012151showvarscmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012152{
12153 showvars(nullstr, VUNSET, VUNSET);
12154 return 0;
12155}
12156
12157
12158
12159/*
12160 * The export and readonly commands.
12161 */
12162
12163static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012164exportcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012165{
12166 struct var *vp;
12167 char *name;
12168 const char *p;
12169 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12170 int pflag;
12171
12172 listsetvar(cmdenviron);
12173 pflag = (nextopt("p") == 'p');
12174 if (argc > 1 && !pflag) {
12175 while ((name = *argptr++) != NULL) {
12176 if ((p = strchr(name, '=')) != NULL) {
12177 p++;
12178 } else {
12179 if ((vp = *findvar(hashvar(name), name))) {
12180 vp->flags |= flag;
12181 goto found;
12182 }
12183 }
12184 setvar(name, p, flag);
12185found:;
12186 }
12187 } else {
12188 showvars(argv[0], flag, 0);
12189 }
12190 return 0;
12191}
12192
Eric Andersen34506362001-08-02 05:02:46 +000012193
Eric Andersencb57d552001-06-28 07:25:16 +000012194/*
12195 * The "local" command.
12196 */
12197
Eric Andersen2870d962001-07-02 17:27:21 +000012198/* funcnest nonzero if we are currently evaluating a function */
12199
Eric Andersencb57d552001-06-28 07:25:16 +000012200static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012201localcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012202{
12203 char *name;
12204
Eric Andersen2870d962001-07-02 17:27:21 +000012205 if (! funcnest)
Eric Andersencb57d552001-06-28 07:25:16 +000012206 error("Not in a function");
12207 while ((name = *argptr++) != NULL) {
12208 mklocal(name);
12209 }
12210 return 0;
12211}
12212
12213
12214/*
12215 * Make a variable a local variable. When a variable is made local, it's
12216 * value and flags are saved in a localvar structure. The saved values
12217 * will be restored when the shell function returns. We handle the name
12218 * "-" as a special case.
12219 */
12220
12221static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012222mklocal(char *name)
12223{
Eric Andersencb57d552001-06-28 07:25:16 +000012224 struct localvar *lvp;
12225 struct var **vpp;
12226 struct var *vp;
12227
12228 INTOFF;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012229 lvp = xmalloc(sizeof (struct localvar));
Eric Andersencb57d552001-06-28 07:25:16 +000012230 if (name[0] == '-' && name[1] == '\0') {
12231 char *p;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012232 p = xmalloc(sizeof optet_vals);
Eric Andersen2870d962001-07-02 17:27:21 +000012233 lvp->text = memcpy(p, optet_vals, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000012234 vp = NULL;
12235 } else {
12236 vpp = hashvar(name);
12237 vp = *findvar(vpp, name);
12238 if (vp == NULL) {
12239 if (strchr(name, '='))
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012240 setvareq(xstrdup(name), VSTRFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +000012241 else
12242 setvar(name, NULL, VSTRFIXED);
Eric Andersen2870d962001-07-02 17:27:21 +000012243 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012244 lvp->text = NULL;
12245 lvp->flags = VUNSET;
12246 } else {
12247 lvp->text = vp->text;
12248 lvp->flags = vp->flags;
12249 vp->flags |= VSTRFIXED|VTEXTFIXED;
12250 if (strchr(name, '='))
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012251 setvareq(xstrdup(name), 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012252 }
12253 }
12254 lvp->vp = vp;
12255 lvp->next = localvars;
12256 localvars = lvp;
12257 INTON;
12258}
12259
12260
12261/*
12262 * Called after a function returns.
12263 */
12264
12265static void
12266poplocalvars() {
12267 struct localvar *lvp;
12268 struct var *vp;
12269
12270 while ((lvp = localvars) != NULL) {
12271 localvars = lvp->next;
12272 vp = lvp->vp;
Eric Andersen2870d962001-07-02 17:27:21 +000012273 if (vp == NULL) { /* $- saved */
12274 memcpy(optet_vals, lvp->text, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000012275 ckfree(lvp->text);
12276 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12277 (void)unsetvar(vp->text);
12278 } else {
12279 if ((vp->flags & VTEXTFIXED) == 0)
12280 ckfree(vp->text);
12281 vp->flags = lvp->flags;
12282 vp->text = lvp->text;
12283 }
12284 ckfree(lvp);
12285 }
12286}
12287
12288
12289static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012290setvarcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012291{
12292 if (argc <= 2)
12293 return unsetcmd(argc, argv);
12294 else if (argc == 3)
12295 setvar(argv[1], argv[2], 0);
12296 else
12297 error("List assignment not implemented");
12298 return 0;
12299}
12300
12301
12302/*
12303 * The unset builtin command. We unset the function before we unset the
12304 * variable to allow a function to be unset when there is a readonly variable
12305 * with the same name.
12306 */
12307
12308static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012309unsetcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012310{
12311 char **ap;
12312 int i;
12313 int flg_func = 0;
12314 int flg_var = 0;
12315 int ret = 0;
12316
12317 while ((i = nextopt("vf")) != '\0') {
12318 if (i == 'f')
12319 flg_func = 1;
12320 else
12321 flg_var = 1;
12322 }
12323 if (flg_func == 0 && flg_var == 0)
12324 flg_var = 1;
12325
12326 for (ap = argptr; *ap ; ap++) {
12327 if (flg_func)
12328 unsetfunc(*ap);
12329 if (flg_var)
12330 ret |= unsetvar(*ap);
12331 }
12332 return ret;
12333}
12334
12335
12336/*
12337 * Unset the specified variable.
12338 */
12339
12340static int
Eric Andersen62483552001-07-10 06:09:16 +000012341unsetvar(const char *s)
12342{
Eric Andersencb57d552001-06-28 07:25:16 +000012343 struct var **vpp;
12344 struct var *vp;
12345
12346 vpp = findvar(hashvar(s), s);
12347 vp = *vpp;
12348 if (vp) {
12349 if (vp->flags & VREADONLY)
12350 return (1);
12351 INTOFF;
12352 if (*(strchr(vp->text, '=') + 1) != '\0')
12353 setvar(s, nullstr, 0);
12354 vp->flags &= ~VEXPORT;
12355 vp->flags |= VUNSET;
12356 if ((vp->flags & VSTRFIXED) == 0) {
12357 if ((vp->flags & VTEXTFIXED) == 0)
12358 ckfree(vp->text);
12359 *vpp = vp->next;
12360 ckfree(vp);
12361 }
12362 INTON;
12363 return (0);
12364 }
12365
12366 return (0);
12367}
12368
12369
12370
12371/*
12372 * Find the appropriate entry in the hash table from the name.
12373 */
12374
12375static struct var **
Eric Andersen62483552001-07-10 06:09:16 +000012376hashvar(const char *p)
12377{
Eric Andersencb57d552001-06-28 07:25:16 +000012378 unsigned int hashval;
12379
12380 hashval = ((unsigned char) *p) << 4;
12381 while (*p && *p != '=')
12382 hashval += (unsigned char) *p++;
12383 return &vartab[hashval % VTABSIZE];
12384}
12385
12386
12387
12388/*
12389 * Returns true if the two strings specify the same varable. The first
12390 * variable name is terminated by '='; the second may be terminated by
12391 * either '=' or '\0'.
12392 */
12393
12394static int
Eric Andersen62483552001-07-10 06:09:16 +000012395varequal(const char *p, const char *q)
12396{
Eric Andersencb57d552001-06-28 07:25:16 +000012397 while (*p == *q++) {
12398 if (*p++ == '=')
12399 return 1;
12400 }
12401 if (*p == '=' && *(q - 1) == '\0')
12402 return 1;
12403 return 0;
12404}
12405
12406static void
12407showvars(const char *myprefix, int mask, int xor)
12408{
12409 struct var **vpp;
12410 struct var *vp;
12411 const char *sep = myprefix == nullstr ? myprefix : spcstr;
12412
12413 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12414 for (vp = *vpp ; vp ; vp = vp->next) {
12415 if ((vp->flags & mask) ^ xor) {
12416 char *p;
12417 int len;
12418
12419 p = strchr(vp->text, '=') + 1;
12420 len = p - vp->text;
12421 p = single_quote(p);
12422
Eric Andersen62483552001-07-10 06:09:16 +000012423 printf("%s%s%.*s%s\n", myprefix, sep, len,
12424 vp->text, p);
Eric Andersencb57d552001-06-28 07:25:16 +000012425 stunalloc(p);
12426 }
12427 }
12428 }
12429}
12430
12431static struct var **
12432findvar(struct var **vpp, const char *name)
12433{
12434 for (; *vpp; vpp = &(*vpp)->next) {
12435 if (varequal((*vpp)->text, name)) {
12436 break;
12437 }
12438 }
12439 return vpp;
12440}
12441
12442/*
12443 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
12444 * This file contains code for the times builtin.
Eric Andersen1a923762002-06-06 12:07:28 +000012445 * $Id: ash.c,v 1.52 2002/06/06 12:07:28 andersen Exp $
Eric Andersencb57d552001-06-28 07:25:16 +000012446 */
12447static int timescmd (int argc, char **argv)
12448{
12449 struct tms buf;
12450 long int clk_tck = sysconf(_SC_CLK_TCK);
12451
12452 times(&buf);
12453 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
12454 (int) (buf.tms_utime / clk_tck / 60),
12455 ((double) buf.tms_utime) / clk_tck,
12456 (int) (buf.tms_stime / clk_tck / 60),
12457 ((double) buf.tms_stime) / clk_tck,
12458 (int) (buf.tms_cutime / clk_tck / 60),
12459 ((double) buf.tms_cutime) / clk_tck,
12460 (int) (buf.tms_cstime / clk_tck / 60),
12461 ((double) buf.tms_cstime) / clk_tck);
12462 return 0;
12463}
12464
Eric Andersend35c5df2002-01-09 15:37:36 +000012465#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012466/* The let builtin. */
12467int letcmd(int argc, char **argv)
Eric Andersen74bcd162001-07-30 21:41:37 +000012468{
Eric Andersen34506362001-08-02 05:02:46 +000012469 int errcode;
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012470 long result=0;
12471 if (argc == 2) {
12472 char *tmp, *expression, p[13];
12473 expression = strchr(argv[1], '=');
12474 if (!expression) {
Eric Andersen34506362001-08-02 05:02:46 +000012475 /* Cannot use 'error()' here, or the return code
12476 * will be incorrect */
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012477 out2fmt("sh: let: syntax error: \"%s\"\n", argv[1]);
12478 return 0;
Eric Andersen74bcd162001-07-30 21:41:37 +000012479 }
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012480 *expression = '\0';
12481 tmp = ++expression;
Eric Andersen34506362001-08-02 05:02:46 +000012482 result = arith(tmp, &errcode);
12483 if (errcode < 0) {
12484 /* Cannot use 'error()' here, or the return code
12485 * will be incorrect */
12486 out2fmt("sh: let: ");
12487 if(errcode == -2)
12488 out2fmt("divide by zero");
12489 else
12490 out2fmt("syntax error: \"%s=%s\"\n", argv[1], expression);
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012491 return 0;
12492 }
12493 snprintf(p, 12, "%ld", result);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012494 setvar(argv[1], xstrdup(p), 0);
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012495 } else if (argc >= 3)
12496 synerror("invalid operand");
12497 return !result;
Eric Andersen74bcd162001-07-30 21:41:37 +000012498}
12499#endif
12500
12501
12502
Eric Andersendf82f612001-06-28 07:46:40 +000012503/*-
12504 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000012505 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000012506 *
12507 * This code is derived from software contributed to Berkeley by
12508 * Kenneth Almquist.
12509 *
12510 * Redistribution and use in source and binary forms, with or without
12511 * modification, are permitted provided that the following conditions
12512 * are met:
12513 * 1. Redistributions of source code must retain the above copyright
12514 * notice, this list of conditions and the following disclaimer.
12515 * 2. Redistributions in binary form must reproduce the above copyright
12516 * notice, this list of conditions and the following disclaimer in the
12517 * documentation and/or other materials provided with the distribution.
12518 *
Eric Andersen2870d962001-07-02 17:27:21 +000012519 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
12520 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000012521 *
12522 * 4. Neither the name of the University nor the names of its contributors
12523 * may be used to endorse or promote products derived from this software
12524 * without specific prior written permission.
12525 *
12526 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
12527 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
12528 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
12529 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
12530 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
12531 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
12532 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
12533 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
12534 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
12535 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
12536 * SUCH DAMAGE.
12537 */