blob: 16c5ec0f2518c86e455702c54360aadd75ee6788 [file] [log] [blame]
Eric Andersendf82f612001-06-28 07:46:40 +00001/* vi: set sw=4 ts=4: */
2/*
3 * ash shell port for busybox
4 *
5 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +00006 * The Regents of the University of California. All rights reserved.
Eric Andersencb57d552001-06-28 07:25:16 +00007 *
8 * This code is derived from software contributed to Berkeley by
9 * Kenneth Almquist.
10 *
Eric Andersendf82f612001-06-28 07:46:40 +000011 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
Eric Andersencb57d552001-06-28 07:25:16 +000015 *
Eric Andersendf82f612001-06-28 07:46:40 +000016 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
Eric Andersen2870d962001-07-02 17:27:21 +000025 * This version of ash is adapted from the source in Debian's ash 0.3.8-5
26 * package.
Eric Andersendf82f612001-06-28 07:46:40 +000027 *
Eric Andersen2870d962001-07-02 17:27:21 +000028 * Modified by Erik Andersen <andersee@debian.org> and
Eric Andersen7467c8d2001-07-12 20:26:32 +000029 * Vladimir Oleynik <dzo@simtreas.ru> to be used in busybox
Eric Andersen2870d962001-07-02 17:27:21 +000030 *
Eric Andersendf82f612001-06-28 07:46:40 +000031 *
32 * Original copyright notice is retained at the end of this file.
Eric Andersencb57d552001-06-28 07:25:16 +000033 */
34
Eric Andersen2870d962001-07-02 17:27:21 +000035
36/* These defines allow you to adjust the feature set to be compiled
37 * into the ash shell. As a rule, enabling these options will make
38 * ash get bigger... With all of these options off, ash adds about
Eric Andersen62483552001-07-10 06:09:16 +000039 * 60k to busybox on an x86 system.*/
Eric Andersen2870d962001-07-02 17:27:21 +000040
41
42/* Enable job control. This allows you to run jobs in the background,
43 * which is great when ash is being used as an interactive shell, but
Eric Andersen3102ac42001-07-06 04:26:23 +000044 * it completely useless for is all you are doing is running scripts.
Eric Andersen2870d962001-07-02 17:27:21 +000045 * This adds about 2.5k on an x86 system. */
Eric Andersen62483552001-07-10 06:09:16 +000046#undef JOBS
Eric Andersen2870d962001-07-02 17:27:21 +000047
48/* This enables alias support in ash. If you want to support things
49 * like "alias ls='ls -l'" with ash, enable this. This is only useful
50 * when ash is used as an intractive shell. This adds about 1.5k */
51#define ASH_ALIAS
52
53/* If you need ash to act as a full Posix shell, with full math
Eric Andersen74bcd162001-07-30 21:41:37 +000054 * support, enable this. This adds a bit over 2k an x86 system. */
Eric Andersen34506362001-08-02 05:02:46 +000055//#undef ASH_MATH_SUPPORT
Eric Andersen74bcd162001-07-30 21:41:37 +000056#define ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +000057
Eric Andersen2870d962001-07-02 17:27:21 +000058/* Getopts is used by shell procedures to parse positional parameters.
59 * You probably want to leave this disabled, and use the busybox getopt
60 * applet if you want to do this sort of thing. There are some scripts
Manuel Novoa III 16815d42001-08-10 19:36:07 +000061 * out there that use it, so it you need it, enable. Most people will
Eric Andersen2870d962001-07-02 17:27:21 +000062 * leave this disabled. This adds 1k on an x86 system. */
63#undef ASH_GETOPTS
64
65/* This allows you to override shell builtins and use whatever is on
66 * the filesystem. This is most useful when ash is acting as a
Eric Andersen62483552001-07-10 06:09:16 +000067 * standalone shell. Adds about 272 bytes. */
Eric Andersen2870d962001-07-02 17:27:21 +000068#undef ASH_CMDCMD
69
Eric Andersenec074692001-10-31 11:05:49 +000070/* Check for new mail on interactive shells? */
71#undef ASH_MAIL
Eric Andersen2870d962001-07-02 17:27:21 +000072
Eric Andersen3102ac42001-07-06 04:26:23 +000073/* Optimize size vs speed as size */
74#define ASH_OPTIMIZE_FOR_SIZE
75
Eric Andersen2870d962001-07-02 17:27:21 +000076/* Enable this to compile in extra debugging noise. When debugging is
77 * on, debugging info will be written to $HOME/trace and a quit signal
78 * will generate a core dump. */
79#undef DEBUG
80
Eric Andersen2870d962001-07-02 17:27:21 +000081/* These are here to work with glibc -- Don't change these... */
Eric Andersendf82f612001-06-28 07:46:40 +000082#undef FNMATCH_BROKEN
83#undef GLOB_BROKEN
Eric Andersen5bb16772001-09-06 18:00:41 +000084#define IFS_BROKEN
Eric Andersencb57d552001-06-28 07:25:16 +000085
86#include <assert.h>
Manuel Novoa III 16815d42001-08-10 19:36:07 +000087#include <stddef.h>
Eric Andersencb57d552001-06-28 07:25:16 +000088#include <ctype.h>
89#include <dirent.h>
90#include <errno.h>
91#include <fcntl.h>
92#include <limits.h>
93#include <paths.h>
Eric Andersencb57d552001-06-28 07:25:16 +000094#include <setjmp.h>
95#include <signal.h>
96#include <stdarg.h>
Eric Andersencb57d552001-06-28 07:25:16 +000097#include <stdio.h>
98#include <stdlib.h>
99#include <string.h>
100#include <sysexits.h>
101#include <unistd.h>
102#include <sys/stat.h>
103#include <sys/cdefs.h>
104#include <sys/ioctl.h>
105#include <sys/param.h>
106#include <sys/resource.h>
107#include <sys/time.h>
108#include <sys/times.h>
109#include <sys/types.h>
110#include <sys/wait.h>
Eric Andersen1a10eec2001-10-24 17:19:38 +0000111#include "pwd.h"
Eric Andersencb57d552001-06-28 07:25:16 +0000112
113
114#if !defined(FNMATCH_BROKEN)
115#include <fnmatch.h>
116#endif
117#if !defined(GLOB_BROKEN)
118#include <glob.h>
119#endif
120
Eric Andersen2870d962001-07-02 17:27:21 +0000121#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +0000122#include <termios.h>
Eric Andersencb57d552001-06-28 07:25:16 +0000123#endif
124
Eric Andersencb57d552001-06-28 07:25:16 +0000125#include "busybox.h"
Eric Andersen2870d962001-07-02 17:27:21 +0000126#include "cmdedit.h"
127
Eric Andersen2870d962001-07-02 17:27:21 +0000128/*
129 * This file was generated by the mksyntax program.
130 */
131
132/* Syntax classes */
133#define CWORD 0 /* character is nothing special */
134#define CNL 1 /* newline character */
135#define CBACK 2 /* a backslash character */
136#define CSQUOTE 3 /* single quote */
137#define CDQUOTE 4 /* double quote */
138#define CENDQUOTE 5 /* a terminating quote */
139#define CBQUOTE 6 /* backwards single quote */
140#define CVAR 7 /* a dollar sign */
141#define CENDVAR 8 /* a '}' character */
142#define CLP 9 /* a left paren in arithmetic */
143#define CRP 10 /* a right paren in arithmetic */
144#define CENDFILE 11 /* end of file */
145#define CCTL 12 /* like CWORD, except it must be escaped */
146#define CSPCL 13 /* these terminate a word */
147#define CIGN 14 /* character should be ignored */
148
Eric Andersen2870d962001-07-02 17:27:21 +0000149#define SYNBASE 130
150#define PEOF -130
151
152#define PEOA -129
153
154#define TEOF 0
155#define TNL 1
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000156#define TREDIR 2
157#define TWORD 3
158#define TASSIGN 4
159#define TSEMI 5
160#define TBACKGND 6
161#define TAND 7
162#define TOR 8
163#define TPIPE 9
164#define TLP 10
165#define TRP 11
166#define TENDCASE 12
167#define TENDBQUOTE 13
Eric Andersen2870d962001-07-02 17:27:21 +0000168#define TNOT 14
169#define TCASE 15
170#define TDO 16
171#define TDONE 17
172#define TELIF 18
173#define TELSE 19
174#define TESAC 20
175#define TFI 21
176#define TFOR 22
177#define TIF 23
178#define TIN 24
179#define TTHEN 25
180#define TUNTIL 26
181#define TWHILE 27
182#define TBEGIN 28
183#define TEND 29
184
185
Eric Andersen2870d962001-07-02 17:27:21 +0000186
187/* control characters in argument strings */
188#define CTLESC '\201'
189#define CTLVAR '\202'
190#define CTLENDVAR '\203'
191#define CTLBACKQ '\204'
192#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
193/* CTLBACKQ | CTLQUOTE == '\205' */
194#define CTLARI '\206'
195#define CTLENDARI '\207'
196#define CTLQUOTEMARK '\210'
197
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000198
Eric Andersen62483552001-07-10 06:09:16 +0000199#define is_digit(c) ((c)>='0' && (c)<='9')
Eric Andersen2870d962001-07-02 17:27:21 +0000200#define is_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalpha((unsigned char) (c))))
201#define is_in_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalnum((unsigned char) (c))))
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000202
203/*
204 * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
205 * (assuming ascii char codes, as the original implementation did)
206 */
207#define is_special(c) \
208 ( (((unsigned int)c) - 33 < 32) \
209 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
210
Eric Andersen2870d962001-07-02 17:27:21 +0000211#define digit_val(c) ((c) - '0')
Eric Andersencb57d552001-06-28 07:25:16 +0000212
213
Eric Andersen2870d962001-07-02 17:27:21 +0000214#define S_DFL 1 /* default signal handling (SIG_DFL) */
215#define S_CATCH 2 /* signal is caught */
216#define S_IGN 3 /* signal is ignored (SIG_IGN) */
217#define S_HARD_IGN 4 /* signal is ignored permenantly */
218#define S_RESET 5 /* temporary - to reset a hard ignored sig */
Eric Andersencb57d552001-06-28 07:25:16 +0000219
220
Eric Andersen2870d962001-07-02 17:27:21 +0000221/* variable substitution byte (follows CTLVAR) */
222#define VSTYPE 0x0f /* type of variable substitution */
223#define VSNUL 0x10 /* colon--treat the empty string as unset */
224#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
Eric Andersencb57d552001-06-28 07:25:16 +0000225
Eric Andersen2870d962001-07-02 17:27:21 +0000226/* values of VSTYPE field */
227#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
228#define VSMINUS 0x2 /* ${var-text} */
229#define VSPLUS 0x3 /* ${var+text} */
230#define VSQUESTION 0x4 /* ${var?message} */
231#define VSASSIGN 0x5 /* ${var=text} */
232#define VSTRIMLEFT 0x6 /* ${var#pattern} */
233#define VSTRIMLEFTMAX 0x7 /* ${var##pattern} */
234#define VSTRIMRIGHT 0x8 /* ${var%pattern} */
235#define VSTRIMRIGHTMAX 0x9 /* ${var%%pattern} */
236#define VSLENGTH 0xa /* ${#var} */
Eric Andersencb57d552001-06-28 07:25:16 +0000237
Eric Andersen2870d962001-07-02 17:27:21 +0000238/* flags passed to redirect */
239#define REDIR_PUSH 01 /* save previous values of file descriptors */
Eric Andersen3102ac42001-07-06 04:26:23 +0000240#define REDIR_BACKQ 02 /* save the command output to pipe */
Eric Andersencb57d552001-06-28 07:25:16 +0000241
Eric Andersen2870d962001-07-02 17:27:21 +0000242/*
243 * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
244 * so we use _setjmp instead.
245 */
246
Eric Andersen62483552001-07-10 06:09:16 +0000247#if defined(BSD)
Eric Andersen2870d962001-07-02 17:27:21 +0000248#define setjmp(jmploc) _setjmp(jmploc)
249#define longjmp(jmploc, val) _longjmp(jmploc, val)
250#endif
251
252/*
253 * Most machines require the value returned from malloc to be aligned
254 * in some way. The following macro will get this right on many machines.
255 */
256
257#ifndef ALIGN
258union align {
259 int i;
260 char *cp;
261};
262
263#define ALIGN(nbytes) (((nbytes) + sizeof(union align) - 1) & ~(sizeof(union align) - 1))
264#endif
265
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000266#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +0000267#include <locale.h>
268static void change_lc_all(const char *value);
269static void change_lc_ctype(const char *value);
270#endif
271
272/*
273 * These macros allow the user to suspend the handling of interrupt signals
274 * over a period of time. This is similar to SIGHOLD to or sigblock, but
275 * much more efficient and portable. (But hacking the kernel is so much
276 * more fun than worrying about efficiency and portability. :-))
277 */
278
279static void onint (void);
280static volatile int suppressint;
281static volatile int intpending;
282
283#define INTOFF suppressint++
Eric Andersen3102ac42001-07-06 04:26:23 +0000284#ifndef ASH_OPTIMIZE_FOR_SIZE
Eric Andersen2870d962001-07-02 17:27:21 +0000285#define INTON { if (--suppressint == 0 && intpending) onint(); }
Eric Andersen3102ac42001-07-06 04:26:23 +0000286#define FORCEINTON {suppressint = 0; if (intpending) onint();}
Eric Andersen2870d962001-07-02 17:27:21 +0000287#else
288static void __inton (void);
Eric Andersen3102ac42001-07-06 04:26:23 +0000289static void forceinton (void);
Eric Andersen2870d962001-07-02 17:27:21 +0000290#define INTON __inton()
Eric Andersen3102ac42001-07-06 04:26:23 +0000291#define FORCEINTON forceinton()
Eric Andersen2870d962001-07-02 17:27:21 +0000292#endif
Eric Andersen3102ac42001-07-06 04:26:23 +0000293
Eric Andersen2870d962001-07-02 17:27:21 +0000294#define CLEAR_PENDING_INT intpending = 0
295#define int_pending() intpending
296
297
298typedef void *pointer;
299#ifndef NULL
300#define NULL (void *)0
301#endif
302
Eric Andersen2870d962001-07-02 17:27:21 +0000303static pointer stalloc (int);
304static void stunalloc (pointer);
305static void ungrabstackstr (char *, char *);
306static char * growstackstr(void);
Eric Andersen3102ac42001-07-06 04:26:23 +0000307static char * makestrspace(size_t newlen);
Eric Andersen2870d962001-07-02 17:27:21 +0000308static char *sstrdup (const char *);
309
310/*
311 * Parse trees for commands are allocated in lifo order, so we use a stack
312 * to make this more efficient, and also to avoid all sorts of exception
313 * handling code to handle interrupts in the middle of a parse.
314 *
315 * The size 504 was chosen because the Ultrix malloc handles that size
316 * well.
317 */
318
319#define MINSIZE 504 /* minimum size of a block */
320
321
322struct stack_block {
323 struct stack_block *prev;
324 char space[MINSIZE];
325};
326
327static struct stack_block stackbase;
328static struct stack_block *stackp = &stackbase;
329static struct stackmark *markp;
330static char *stacknxt = stackbase.space;
331static int stacknleft = MINSIZE;
332
333
334#define equal(s1, s2) (strcmp(s1, s2) == 0)
335
336#define stackblock() stacknxt
337#define stackblocksize() stacknleft
338#define STARTSTACKSTR(p) p = stackblock(), sstrnleft = stackblocksize()
Eric Andersen3102ac42001-07-06 04:26:23 +0000339
Eric Andersen2870d962001-07-02 17:27:21 +0000340#define STPUTC(c, p) (--sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(), *p++ = (c)))
341#define CHECKSTRSPACE(n, p) { if (sstrnleft < n) p = makestrspace(n); }
Eric Andersen2870d962001-07-02 17:27:21 +0000342#define STACKSTRNUL(p) (sstrnleft == 0? (p = growstackstr(), *p = '\0') : (*p = '\0'))
Eric Andersen3102ac42001-07-06 04:26:23 +0000343
344
345#define USTPUTC(c, p) (--sstrnleft, *p++ = (c))
Eric Andersen2870d962001-07-02 17:27:21 +0000346#define STUNPUTC(p) (++sstrnleft, --p)
347#define STTOPC(p) p[-1]
348#define STADJUST(amount, p) (p += (amount), sstrnleft -= (amount))
349#define grabstackstr(p) stalloc(stackblocksize() - sstrnleft)
350
351#define ckfree(p) free((pointer)(p))
352
Eric Andersen2870d962001-07-02 17:27:21 +0000353
354#ifdef DEBUG
355#define TRACE(param) trace param
Eric Andersen69a20f02001-10-31 10:40:37 +0000356typedef union node unode;
Eric Andersen2870d962001-07-02 17:27:21 +0000357static void trace (const char *, ...);
358static void trargs (char **);
Eric Andersen69a20f02001-10-31 10:40:37 +0000359static void showtree (unode *);
Eric Andersen2870d962001-07-02 17:27:21 +0000360static void trputc (int);
361static void trputs (const char *);
362static void opentrace (void);
363#else
364#define TRACE(param)
365#endif
366
367#define NSEMI 0
368#define NCMD 1
369#define NPIPE 2
370#define NREDIR 3
371#define NBACKGND 4
372#define NSUBSHELL 5
373#define NAND 6
374#define NOR 7
375#define NIF 8
376#define NWHILE 9
377#define NUNTIL 10
378#define NFOR 11
379#define NCASE 12
380#define NCLIST 13
381#define NDEFUN 14
382#define NARG 15
383#define NTO 16
384#define NFROM 17
385#define NFROMTO 18
386#define NAPPEND 19
387#define NTOOV 20
388#define NTOFD 21
389#define NFROMFD 22
390#define NHERE 23
391#define NXHERE 24
392#define NNOT 25
393
394/*
395 * expandarg() flags
396 */
397#define EXP_FULL 0x1 /* perform word splitting & file globbing */
398#define EXP_TILDE 0x2 /* do normal tilde expansion */
399#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
400#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
401#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
402#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
403
404
405#define NOPTS 16
406
407static char optet_vals[NOPTS];
408
409static const char * const optlist[NOPTS] = {
410 "e" "errexit",
411 "f" "noglob",
412 "I" "ignoreeof",
413 "i" "interactive",
414 "m" "monitor",
415 "n" "noexec",
416 "s" "stdin",
417 "x" "xtrace",
418 "v" "verbose",
419 "V" "vi",
420 "E" "emacs",
421 "C" "noclobber",
422 "a" "allexport",
423 "b" "notify",
424 "u" "nounset",
425 "q" "quietprofile"
426};
427
428#define optent_name(optent) (optent+1)
429#define optent_letter(optent) optent[0]
430#define optent_val(optent) optet_vals[optent]
431
432#define eflag optent_val(0)
433#define fflag optent_val(1)
434#define Iflag optent_val(2)
435#define iflag optent_val(3)
436#define mflag optent_val(4)
437#define nflag optent_val(5)
438#define sflag optent_val(6)
439#define xflag optent_val(7)
440#define vflag optent_val(8)
441#define Vflag optent_val(9)
442#define Eflag optent_val(10)
443#define Cflag optent_val(11)
444#define aflag optent_val(12)
445#define bflag optent_val(13)
446#define uflag optent_val(14)
447#define qflag optent_val(15)
448
449
450/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
451#define FORK_FG 0
452#define FORK_BG 1
453#define FORK_NOJOB 2
454
455
456struct nbinary {
457 int type;
458 union node *ch1;
459 union node *ch2;
460};
461
462
463struct ncmd {
464 int type;
465 int backgnd;
466 union node *assign;
467 union node *args;
468 union node *redirect;
469};
470
471
472struct npipe {
473 int type;
474 int backgnd;
475 struct nodelist *cmdlist;
476};
477
478
479struct nredir {
480 int type;
481 union node *n;
482 union node *redirect;
483};
484
485
486struct nif {
487 int type;
488 union node *test;
489 union node *ifpart;
490 union node *elsepart;
491};
492
493
494struct nfor {
495 int type;
496 union node *args;
497 union node *body;
498 char *var;
499};
500
501
502struct ncase {
503 int type;
504 union node *expr;
505 union node *cases;
506};
507
508
509struct nclist {
510 int type;
511 union node *next;
512 union node *pattern;
513 union node *body;
514};
515
516
517struct narg {
518 int type;
519 union node *next;
520 char *text;
521 struct nodelist *backquote;
522};
523
524
525struct nfile {
526 int type;
527 union node *next;
528 int fd;
529 union node *fname;
530 char *expfname;
531};
532
533
534struct ndup {
535 int type;
536 union node *next;
537 int fd;
538 int dupfd;
539 union node *vname;
540};
541
542
543struct nhere {
544 int type;
545 union node *next;
546 int fd;
547 union node *doc;
548};
549
550
551struct nnot {
552 int type;
553 union node *com;
554};
555
556
557union node {
558 int type;
559 struct nbinary nbinary;
560 struct ncmd ncmd;
561 struct npipe npipe;
562 struct nredir nredir;
563 struct nif nif;
564 struct nfor nfor;
565 struct ncase ncase;
566 struct nclist nclist;
567 struct narg narg;
568 struct nfile nfile;
569 struct ndup ndup;
570 struct nhere nhere;
571 struct nnot nnot;
572};
573
574
575struct nodelist {
576 struct nodelist *next;
577 union node *n;
578};
579
580struct backcmd { /* result of evalbackcmd */
581 int fd; /* file descriptor to read from */
582 char *buf; /* buffer */
583 int nleft; /* number of chars in buffer */
584 struct job *jp; /* job structure for command */
585};
586
587struct cmdentry {
588 int cmdtype;
589 union param {
590 int index;
591 union node *func;
592 const struct builtincmd *cmd;
593 } u;
594};
595
596struct strlist {
597 struct strlist *next;
598 char *text;
599};
600
601
602struct arglist {
603 struct strlist *list;
604 struct strlist **lastp;
605};
606
607struct strpush {
608 struct strpush *prev; /* preceding string on stack */
609 char *prevstring;
610 int prevnleft;
611#ifdef ASH_ALIAS
612 struct alias *ap; /* if push was associated with an alias */
613#endif
614 char *string; /* remember the string since it may change */
615};
616
617struct parsefile {
618 struct parsefile *prev; /* preceding file on stack */
619 int linno; /* current line */
620 int fd; /* file descriptor (or -1 if string) */
621 int nleft; /* number of chars left in this line */
622 int lleft; /* number of chars left in this buffer */
623 char *nextc; /* next char in buffer */
624 char *buf; /* input buffer */
625 struct strpush *strpush; /* for pushing strings at this level */
626 struct strpush basestrpush; /* so pushing one is fast */
627};
628
629struct stackmark {
630 struct stack_block *stackp;
631 char *stacknxt;
632 int stacknleft;
633 struct stackmark *marknext;
634};
635
636struct shparam {
637 int nparam; /* # of positional parameters (without $0) */
638 unsigned char malloc; /* if parameter list dynamically allocated */
639 char **p; /* parameter list */
640 int optind; /* next parameter to be processed by getopts */
641 int optoff; /* used by getopts */
642};
643
Eric Andersen62483552001-07-10 06:09:16 +0000644/*
645 * When commands are first encountered, they are entered in a hash table.
646 * This ensures that a full path search will not have to be done for them
647 * on each invocation.
648 *
649 * We should investigate converting to a linear search, even though that
650 * would make the command name "hash" a misnomer.
651 */
652#define CMDTABLESIZE 31 /* should be prime */
653#define ARB 1 /* actual size determined at run time */
654
655
656
657struct tblentry {
658 struct tblentry *next; /* next entry in hash chain */
659 union param param; /* definition of builtin function */
660 short cmdtype; /* index identifying command */
661 char rehash; /* if set, cd done since entry created */
662 char cmdname[ARB]; /* name of command */
663};
664
665
666static struct tblentry *cmdtable[CMDTABLESIZE];
667static int builtinloc = -1; /* index in path of %builtin, or -1 */
668static int exerrno = 0; /* Last exec error */
669
670
671static void tryexec (char *, char **, char **);
672static void printentry (struct tblentry *, int);
673static void clearcmdentry (int);
674static struct tblentry *cmdlookup (const char *, int);
675static void delete_cmd_entry (void);
676static int path_change (const char *, int *);
677
678
Eric Andersen2870d962001-07-02 17:27:21 +0000679static void flushall (void);
Eric Andersen3102ac42001-07-06 04:26:23 +0000680static void out2fmt (const char *, ...)
681 __attribute__((__format__(__printf__,1,2)));
Eric Andersen2870d962001-07-02 17:27:21 +0000682static int xwrite (int, const char *, int);
Eric Andersen2870d962001-07-02 17:27:21 +0000683
Manuel Novoa III c639a352001-08-12 17:32:56 +0000684static inline void outstr (const char *p, FILE *file) { fputs(p, file); }
Eric Andersen3102ac42001-07-06 04:26:23 +0000685static void out1str(const char *p) { outstr(p, stdout); }
686static void out2str(const char *p) { outstr(p, stderr); }
Eric Andersen2870d962001-07-02 17:27:21 +0000687
Eric Andersen62483552001-07-10 06:09:16 +0000688#ifndef ASH_OPTIMIZE_FOR_SIZE
Eric Andersen3102ac42001-07-06 04:26:23 +0000689#define out2c(c) putc((c), stderr)
Eric Andersen62483552001-07-10 06:09:16 +0000690#else
691static void out2c(int c) { putc(c, stderr); }
692#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000693
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000694
695#ifdef ASH_OPTIMIZE_FOR_SIZE
696#define USE_SIT_FUNCTION
697#endif
698
699/* number syntax index */
700#define BASESYNTAX 0 /* not in quotes */
701#define DQSYNTAX 1 /* in double quotes */
702#define SQSYNTAX 2 /* in single quotes */
703#define ARISYNTAX 3 /* in arithmetic */
704
705static const char S_I_T[][4] = {
706 /* 0 */ { CSPCL, CIGN, CIGN, CIGN }, /* PEOA */
707 /* 1 */ { CSPCL, CWORD, CWORD, CWORD }, /* ' ' */
708 /* 2 */ { CNL, CNL, CNL, CNL }, /* \n */
709 /* 3 */ { CWORD, CCTL, CCTL, CWORD }, /* !*-/:=?[]~ */
710 /* 4 */ { CDQUOTE, CENDQUOTE, CWORD, CDQUOTE }, /* '"' */
711 /* 5 */ { CVAR, CVAR, CWORD, CVAR }, /* $ */
712 /* 6 */ { CSQUOTE, CWORD, CENDQUOTE, CSQUOTE }, /* "'" */
713 /* 7 */ { CSPCL, CWORD, CWORD, CLP }, /* ( */
714 /* 8 */ { CSPCL, CWORD, CWORD, CRP }, /* ) */
715 /* 9 */ { CBACK, CBACK, CCTL, CBACK }, /* \ */
716 /* 10 */ { CBQUOTE, CBQUOTE, CWORD, CBQUOTE }, /* ` */
717 /* 11 */ { CENDVAR, CENDVAR, CWORD, CENDVAR }, /* } */
718#ifndef USE_SIT_FUNCTION
719 /* 12 */ { CENDFILE, CENDFILE, CENDFILE, CENDFILE }, /* PEOF */
720 /* 13 */ { CWORD, CWORD, CWORD, CWORD }, /* 0-9A-Za-z */
721 /* 14 */ { CCTL, CCTL, CCTL, CCTL } /* CTLESC ... */
722#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000723};
724
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000725#ifdef USE_SIT_FUNCTION
726
727#define U_C(c) ((unsigned char)(c))
728
729static int SIT(int c, int syntax)
730{
731 static const char spec_symbls[]="\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
732 static const char syntax_index_table [] = {
733 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
734 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
735 3, 1, 3, 3, 9, 3,10, 1, /* "=>?[\\]`|" */
736 11,3 }; /* "}~" */
737 const char *s;
738 int indx;
739
740 if(c==PEOF) /* 2^8+2 */
741 return CENDFILE;
742 if(c==PEOA) /* 2^8+1 */
743 indx = 0;
744 else if(U_C(c)>=U_C(CTLESC) && U_C(c)<=U_C(CTLQUOTEMARK))
745 return CCTL;
746 else {
747 s = strchr(spec_symbls, c);
748 if(s==0)
749 return CWORD;
750 indx = syntax_index_table[(s-spec_symbls)];
751 }
752 return S_I_T[indx][syntax];
753}
754
755#else /* USE_SIT_FUNCTION */
756
757#define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
758
759#define CSPCL_CIGN_CIGN_CIGN 0
760#define CSPCL_CWORD_CWORD_CWORD 1
761#define CNL_CNL_CNL_CNL 2
762#define CWORD_CCTL_CCTL_CWORD 3
763#define CDQUOTE_CENDQUOTE_CWORD_CDQUOTE 4
764#define CVAR_CVAR_CWORD_CVAR 5
765#define CSQUOTE_CWORD_CENDQUOTE_CSQUOTE 6
766#define CSPCL_CWORD_CWORD_CLP 7
767#define CSPCL_CWORD_CWORD_CRP 8
768#define CBACK_CBACK_CCTL_CBACK 9
769#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
770#define CENDVAR_CENDVAR_CWORD_CENDVAR 11
771#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
772#define CWORD_CWORD_CWORD_CWORD 13
773#define CCTL_CCTL_CCTL_CCTL 14
774
775static const char syntax_index_table[258] = {
776 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
777 /* 0 -130 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
778 /* 1 -129 PEOA */ CSPCL_CIGN_CIGN_CIGN,
779 /* 2 -128 0xff */ CWORD_CWORD_CWORD_CWORD,
780 /* 3 -127 */ CCTL_CCTL_CCTL_CCTL, /* CTLQUOTEMARK */
781 /* 4 -126 */ CCTL_CCTL_CCTL_CCTL,
782 /* 5 -125 */ CCTL_CCTL_CCTL_CCTL,
783 /* 6 -124 */ CCTL_CCTL_CCTL_CCTL,
784 /* 7 -123 */ CCTL_CCTL_CCTL_CCTL,
785 /* 8 -122 */ CCTL_CCTL_CCTL_CCTL,
786 /* 9 -121 */ CCTL_CCTL_CCTL_CCTL,
787 /* 10 -120 */ CCTL_CCTL_CCTL_CCTL, /* CTLESC */
788 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
789 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
790 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
791 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
792 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
793 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
794 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
795 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
796 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
797 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
798 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
799 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
800 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
801 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
802 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
803 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
804 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
805 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
806 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
807 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
808 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
809 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
810 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
811 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
812 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
813 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
814 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
815 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
816 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
817 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
818 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
819 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
820 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
821 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
822 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
823 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
824 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
825 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
826 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
827 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
828 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
829 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
830 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
831 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
832 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
833 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
834 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
835 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
836 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
837 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
838 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
839 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
840 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
841 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
842 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
843 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
844 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
845 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
846 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
847 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
848 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
849 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
850 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
851 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
852 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
853 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
854 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
855 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
856 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
857 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
858 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
859 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
860 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
861 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
862 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
863 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
864 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
865 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
866 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
867 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
868 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
869 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
870 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
871 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
872 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
873 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
874 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
875 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
876 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
877 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
878 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
879 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
880 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
881 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
882 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
883 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
884 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
885 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
886 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
887 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
888 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
889 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
890 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
891 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
892 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
893 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
894 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
895 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
896 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
897 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
898 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
899 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
900 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
901 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
902 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
903 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
904 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
905 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
906 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
907 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
908 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
909 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
910 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
911 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
912 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
913 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
914 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
915 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
916 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
917 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
918 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
919 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
920 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
921 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
922 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
923 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
924 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
925 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
926 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
927 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
928 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
929 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
930 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
931 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
932 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
933 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
934 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
935 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
936 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
937 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
938 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
939 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
940 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
941 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CDQUOTE,
942 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
943 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
944 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
945 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
946 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CSQUOTE,
947 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
948 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
949 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
950 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
951 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
952 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
953 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
954 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
955 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
956 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
957 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
958 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
959 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
960 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
961 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
962 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
963 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
964 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
965 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
966 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
967 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
968 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
969 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
970 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
971 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
972 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
973 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
974 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
975 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
976 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
977 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
978 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
979 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
980 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
981 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
982 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
983 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
984 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
985 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
986 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
987 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
988 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
989 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
990 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
991 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
992 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
993 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
994 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
995 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
996 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
997 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
998 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
999 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
1000 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
1001 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
1002 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
1003 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
1004 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
1005 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
1006 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
1007 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
1008 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
1009 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
1010 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
1011 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
1012 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
1013 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
1014 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
1015 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
1016 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
1017 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
1018 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
1019 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
1020 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
1021 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
1022 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
1023 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
1024 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
1025 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
1026 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
1027 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
1028 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
1029 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
1030 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
1031 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
1032 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
1033 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
1034 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
Eric Andersen2870d962001-07-02 17:27:21 +00001035};
1036
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001037#endif /* USE_SIT_FUNCTION */
Eric Andersen2870d962001-07-02 17:27:21 +00001038
Eric Andersen2870d962001-07-02 17:27:21 +00001039
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001040/* first char is indicating which tokens mark the end of a list */
1041static const char *const tokname_array[] = {
1042 "\1end of file",
1043 "\0newline",
1044 "\0redirection",
1045 "\0word",
1046 "\0assignment",
1047 "\0;",
1048 "\0&",
1049 "\0&&",
1050 "\0||",
1051 "\0|",
1052 "\0(",
1053 "\1)",
1054 "\1;;",
1055 "\1`",
Eric Andersen2870d962001-07-02 17:27:21 +00001056#define KWDOFFSET 14
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001057 /* the following are keywords */
1058 "\0!",
1059 "\0case",
1060 "\1do",
1061 "\1done",
1062 "\1elif",
1063 "\1else",
1064 "\1esac",
1065 "\1fi",
1066 "\0for",
1067 "\0if",
1068 "\0in",
1069 "\1then",
1070 "\0until",
1071 "\0while",
1072 "\0{",
1073 "\1}",
Eric Andersen2870d962001-07-02 17:27:21 +00001074};
1075
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001076static const char *tokname(int tok)
1077{
1078 static char buf[16];
1079
1080 if(tok>=TSEMI)
1081 buf[0] = '"';
1082 sprintf(buf+(tok>=TSEMI), "%s%c",
1083 tokname_array[tok]+1, (tok>=TSEMI ? '"' : 0));
1084 return buf;
1085}
Eric Andersen2870d962001-07-02 17:27:21 +00001086
1087static int plinno = 1; /* input line number */
1088
1089static int parselleft; /* copy of parsefile->lleft */
1090
1091static struct parsefile basepf; /* top level input file */
1092static char basebuf[BUFSIZ]; /* buffer for top level input file */
1093static struct parsefile *parsefile = &basepf; /* current input file */
1094
1095/*
1096 * NEOF is returned by parsecmd when it encounters an end of file. It
1097 * must be distinct from NULL, so we use the address of a variable that
1098 * happens to be handy.
1099 */
1100
1101static int tokpushback; /* last token pushed back */
1102#define NEOF ((union node *)&tokpushback)
1103static int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */
1104
1105
1106static void error (const char *, ...) __attribute__((__noreturn__));
1107static void exerror (int, const char *, ...) __attribute__((__noreturn__));
1108static void shellexec (char **, char **, const char *, int)
1109 __attribute__((noreturn));
1110static void exitshell (int) __attribute__((noreturn));
1111
1112static int goodname(const char *);
1113static void ignoresig (int);
1114static void onsig (int);
1115static void dotrap (void);
1116static int decode_signal (const char *, int);
1117
1118static void shprocvar(void);
1119static void deletefuncs(void);
1120static void setparam (char **);
1121static void freeparam (volatile struct shparam *);
1122
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001123static void find_command (const char *, struct cmdentry *, int, const char *);
1124
1125static inline void hashcd (void);
1126
Eric Andersen2870d962001-07-02 17:27:21 +00001127/* reasons for skipping commands (see comment on breakcmd routine) */
1128#define SKIPBREAK 1
1129#define SKIPCONT 2
1130#define SKIPFUNC 3
1131#define SKIPFILE 4
1132
1133/* values of cmdtype */
1134#define CMDUNKNOWN -1 /* no entry in table for command */
1135#define CMDNORMAL 0 /* command is an executable program */
1136#define CMDBUILTIN 1 /* command is a shell builtin */
1137#define CMDFUNCTION 2 /* command is a shell function */
1138
1139#define DO_ERR 1 /* find_command prints errors */
1140#define DO_ABS 2 /* find_command checks absolute paths */
1141#define DO_NOFUN 4 /* find_command ignores functions */
1142#define DO_BRUTE 8 /* find_command ignores hash table */
1143
1144/*
1145 * Shell variables.
1146 */
1147
1148/* flags */
1149#define VEXPORT 0x01 /* variable is exported */
1150#define VREADONLY 0x02 /* variable cannot be modified */
1151#define VSTRFIXED 0x04 /* variable struct is staticly allocated */
1152#define VTEXTFIXED 0x08 /* text is staticly allocated */
1153#define VSTACK 0x10 /* text is allocated on the stack */
1154#define VUNSET 0x20 /* the variable is not set */
1155#define VNOFUNC 0x40 /* don't call the callback function */
1156
1157
1158struct var {
1159 struct var *next; /* next entry in hash list */
1160 int flags; /* flags are defined above */
1161 char *text; /* name=value */
1162 void (*func) (const char *);
1163 /* function to be called when */
1164 /* the variable gets set/unset */
1165};
1166
1167struct localvar {
1168 struct localvar *next; /* next local variable in list */
1169 struct var *vp; /* the variable that was made local */
1170 int flags; /* saved flags */
1171 char *text; /* saved text */
1172};
1173
1174
Eric Andersen62483552001-07-10 06:09:16 +00001175#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00001176#define rmescapes(p) _rmescapes((p), 0)
1177static char *_rmescapes (char *, int);
1178#else
1179static void rmescapes (char *);
1180#endif
1181
1182static int casematch (union node *, const char *);
1183static void clearredir(void);
1184static void popstring(void);
1185static void readcmdfile (const char *);
1186
1187static int number (const char *);
1188static int is_number (const char *, int *num);
1189static char *single_quote (const char *);
1190static int nextopt (const char *);
1191
1192static void redirect (union node *, int);
1193static void popredir (void);
1194static int dup_as_newfd (int, int);
1195
1196static void changepath(const char *newval);
1197static void getoptsreset(const char *value);
1198
1199
1200static int parsenleft; /* copy of parsefile->nleft */
1201static char *parsenextc; /* copy of parsefile->nextc */
1202static int rootpid; /* pid of main shell */
1203static int rootshell; /* true if we aren't a child of the main shell */
1204
1205static const char spcstr[] = " ";
1206static const char snlfmt[] = "%s\n";
1207
1208static int sstrnleft;
1209static int herefd = -1;
1210
1211static struct localvar *localvars;
1212
1213static struct var vifs;
1214static struct var vmail;
1215static struct var vmpath;
1216static struct var vpath;
1217static struct var vps1;
1218static struct var vps2;
1219static struct var voptind;
Eric Andersenbdfd0d72001-10-24 05:00:29 +00001220#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00001221static struct var vlc_all;
1222static struct var vlc_ctype;
1223#endif
1224
1225struct varinit {
1226 struct var *var;
1227 int flags;
1228 const char *text;
1229 void (*func) (const char *);
1230};
1231
1232static const char defpathvar[] =
1233 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
1234#define defpath (defpathvar + 5)
1235
1236#ifdef IFS_BROKEN
1237static const char defifsvar[] = "IFS= \t\n";
1238#define defifs (defifsvar + 4)
1239#else
1240static const char defifs[] = " \t\n";
1241#endif
1242
1243static const struct varinit varinit[] = {
1244#ifdef IFS_BROKEN
1245 { &vifs, VSTRFIXED|VTEXTFIXED, defifsvar,
1246#else
1247 { &vifs, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS=",
1248#endif
1249 NULL },
1250 { &vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=",
1251 NULL },
1252 { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=",
1253 NULL },
1254 { &vpath, VSTRFIXED|VTEXTFIXED, defpathvar,
1255 changepath },
1256 /*
1257 * vps1 depends on uid
1258 */
1259 { &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ",
1260 NULL },
1261 { &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1",
1262 getoptsreset },
Eric Andersenbdfd0d72001-10-24 05:00:29 +00001263#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00001264 { &vlc_all, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL=",
1265 change_lc_all },
1266 { &vlc_ctype, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE=",
1267 change_lc_ctype },
1268#endif
1269 { NULL, 0, NULL,
1270 NULL }
1271};
1272
1273#define VTABSIZE 39
1274
1275static struct var *vartab[VTABSIZE];
1276
1277/*
1278 * The following macros access the values of the above variables.
1279 * They have to skip over the name. They return the null string
1280 * for unset variables.
1281 */
1282
1283#define ifsval() (vifs.text + 4)
1284#define ifsset() ((vifs.flags & VUNSET) == 0)
1285#define mailval() (vmail.text + 5)
1286#define mpathval() (vmpath.text + 9)
1287#define pathval() (vpath.text + 5)
1288#define ps1val() (vps1.text + 4)
1289#define ps2val() (vps2.text + 4)
1290#define optindval() (voptind.text + 7)
1291
1292#define mpathset() ((vmpath.flags & VUNSET) == 0)
1293
1294static void initvar (void);
1295static void setvar (const char *, const char *, int);
1296static void setvareq (char *, int);
1297static void listsetvar (struct strlist *);
Eric Andersen62483552001-07-10 06:09:16 +00001298static const char *lookupvar (const char *);
1299static const char *bltinlookup (const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001300static char **environment (void);
1301static int showvarscmd (int, char **);
1302static void mklocal (char *);
1303static void poplocalvars (void);
1304static int unsetvar (const char *);
1305static int varequal (const char *, const char *);
1306
1307
1308static char *arg0; /* value of $0 */
1309static struct shparam shellparam; /* current positional parameters */
1310static char **argptr; /* argument list for builtin commands */
1311static char *optionarg; /* set by nextopt (like getopt) */
1312static char *optptr; /* used by nextopt */
1313static char *minusc; /* argument to -c option */
1314
1315
1316#ifdef ASH_ALIAS
1317
1318#define ALIASINUSE 1
1319#define ALIASDEAD 2
1320
Eric Andersen3102ac42001-07-06 04:26:23 +00001321#define ATABSIZE 39
1322
Eric Andersen2870d962001-07-02 17:27:21 +00001323struct alias {
1324 struct alias *next;
1325 char *name;
1326 char *val;
1327 int flag;
1328};
1329
1330static struct alias *atab[ATABSIZE];
1331
1332static void setalias (char *, char *);
1333static struct alias **hashalias (const char *);
1334static struct alias *freealias (struct alias *);
1335static struct alias **__lookupalias (const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00001336
1337static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001338setalias(char *name, char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00001339{
1340 struct alias *ap, **app;
1341
1342 app = __lookupalias(name);
1343 ap = *app;
1344 INTOFF;
1345 if (ap) {
1346 if (!(ap->flag & ALIASINUSE)) {
1347 ckfree(ap->val);
1348 }
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001349 ap->val = xstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00001350 ap->flag &= ~ALIASDEAD;
1351 } else {
1352 /* not found */
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001353 ap = xmalloc(sizeof (struct alias));
1354 ap->name = xstrdup(name);
1355 ap->val = xstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00001356 ap->flag = 0;
1357 ap->next = 0;
1358 *app = ap;
1359 }
1360 INTON;
1361}
1362
1363static int
Eric Andersen2870d962001-07-02 17:27:21 +00001364unalias(char *name)
1365{
Eric Andersencb57d552001-06-28 07:25:16 +00001366 struct alias **app;
1367
1368 app = __lookupalias(name);
1369
1370 if (*app) {
1371 INTOFF;
1372 *app = freealias(*app);
1373 INTON;
1374 return (0);
1375 }
1376
1377 return (1);
1378}
1379
Eric Andersencb57d552001-06-28 07:25:16 +00001380static void
Eric Andersen2870d962001-07-02 17:27:21 +00001381rmaliases(void)
1382{
Eric Andersencb57d552001-06-28 07:25:16 +00001383 struct alias *ap, **app;
1384 int i;
1385
1386 INTOFF;
1387 for (i = 0; i < ATABSIZE; i++) {
1388 app = &atab[i];
1389 for (ap = *app; ap; ap = *app) {
1390 *app = freealias(*app);
1391 if (ap == *app) {
1392 app = &ap->next;
1393 }
1394 }
1395 }
1396 INTON;
1397}
1398
Eric Andersen2870d962001-07-02 17:27:21 +00001399static void
1400printalias(const struct alias *ap) {
1401 char *p;
1402
1403 p = single_quote(ap->val);
Eric Andersen62483552001-07-10 06:09:16 +00001404 printf("alias %s=%s\n", ap->name, p);
Eric Andersen2870d962001-07-02 17:27:21 +00001405 stunalloc(p);
1406}
1407
Eric Andersencb57d552001-06-28 07:25:16 +00001408
1409/*
1410 * TODO - sort output
1411 */
1412static int
Eric Andersen2870d962001-07-02 17:27:21 +00001413aliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001414{
1415 char *n, *v;
1416 int ret = 0;
1417 struct alias *ap;
1418
1419 if (argc == 1) {
1420 int i;
1421
1422 for (i = 0; i < ATABSIZE; i++)
1423 for (ap = atab[i]; ap; ap = ap->next) {
1424 printalias(ap);
1425 }
1426 return (0);
1427 }
1428 while ((n = *++argv) != NULL) {
1429 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
1430 if ((ap = *__lookupalias(n)) == NULL) {
Eric Andersen3102ac42001-07-06 04:26:23 +00001431 out2fmt("%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00001432 ret = 1;
1433 } else
1434 printalias(ap);
1435 }
1436 else {
1437 *v++ = '\0';
1438 setalias(n, v);
1439 }
1440 }
1441
1442 return (ret);
1443}
1444
1445static int
Eric Andersen2870d962001-07-02 17:27:21 +00001446unaliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001447{
1448 int i;
1449
1450 while ((i = nextopt("a")) != '\0') {
1451 if (i == 'a') {
1452 rmaliases();
1453 return (0);
1454 }
1455 }
1456 for (i = 0; *argptr; argptr++) {
1457 if (unalias(*argptr)) {
Eric Andersen3102ac42001-07-06 04:26:23 +00001458 out2fmt("%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00001459 i = 1;
1460 }
1461 }
1462
1463 return (i);
1464}
1465
1466static struct alias **
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001467hashalias(const char *p)
1468{
Eric Andersencb57d552001-06-28 07:25:16 +00001469 unsigned int hashval;
1470
1471 hashval = *p << 4;
1472 while (*p)
1473 hashval+= *p++;
1474 return &atab[hashval % ATABSIZE];
1475}
1476
1477static struct alias *
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001478freealias(struct alias *ap)
1479{
Eric Andersencb57d552001-06-28 07:25:16 +00001480 struct alias *next;
1481
1482 if (ap->flag & ALIASINUSE) {
1483 ap->flag |= ALIASDEAD;
1484 return ap;
1485 }
1486
1487 next = ap->next;
1488 ckfree(ap->name);
1489 ckfree(ap->val);
1490 ckfree(ap);
1491 return next;
1492}
1493
Eric Andersencb57d552001-06-28 07:25:16 +00001494
1495static struct alias **
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001496__lookupalias(const char *name)
1497{
Eric Andersencb57d552001-06-28 07:25:16 +00001498 struct alias **app = hashalias(name);
1499
1500 for (; *app; app = &(*app)->next) {
1501 if (equal(name, (*app)->name)) {
1502 break;
1503 }
1504 }
1505
1506 return app;
1507}
Eric Andersen2870d962001-07-02 17:27:21 +00001508#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001509
1510#ifdef ASH_MATH_SUPPORT
Eric Andersen74bcd162001-07-30 21:41:37 +00001511/* The generated file arith.c has been replaced with a custom hand
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001512 * written implementation written by Aaron Lehmann <aaronl@vitelus.com>.
1513 * This is now part of libbb, so that it can be used by all the shells
Eric Andersen74bcd162001-07-30 21:41:37 +00001514 * in busybox. */
Eric Andersen2870d962001-07-02 17:27:21 +00001515static void expari (int);
Eric Andersencb57d552001-06-28 07:25:16 +00001516#endif
1517
Eric Andersen2870d962001-07-02 17:27:21 +00001518static char *trap[NSIG]; /* trap handler commands */
1519static char sigmode[NSIG - 1]; /* current value of signal */
1520static char gotsig[NSIG - 1]; /* indicates specified signal received */
1521static int pendingsigs; /* indicates some signal received */
1522
Eric Andersencb57d552001-06-28 07:25:16 +00001523/*
1524 * This file was generated by the mkbuiltins program.
1525 */
1526
Eric Andersen2870d962001-07-02 17:27:21 +00001527#ifdef JOBS
1528static int bgcmd (int, char **);
1529static int fgcmd (int, char **);
1530static int killcmd (int, char **);
1531#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001532static int bltincmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001533static int cdcmd (int, char **);
1534static int breakcmd (int, char **);
1535#ifdef ASH_CMDCMD
1536static int commandcmd (int, char **);
1537#endif
1538static int dotcmd (int, char **);
1539static int evalcmd (int, char **);
1540static int execcmd (int, char **);
1541static int exitcmd (int, char **);
1542static int exportcmd (int, char **);
1543static int histcmd (int, char **);
1544static int hashcmd (int, char **);
Eric Andersen1c039232001-07-07 00:05:55 +00001545static int helpcmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001546static int jobscmd (int, char **);
1547static int localcmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001548static int pwdcmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001549static int readcmd (int, char **);
1550static int returncmd (int, char **);
1551static int setcmd (int, char **);
1552static int setvarcmd (int, char **);
1553static int shiftcmd (int, char **);
1554static int trapcmd (int, char **);
1555static int umaskcmd (int, char **);
1556#ifdef ASH_ALIAS
1557static int aliascmd (int, char **);
1558static int unaliascmd (int, char **);
1559#endif
1560static int unsetcmd (int, char **);
1561static int waitcmd (int, char **);
1562static int ulimitcmd (int, char **);
1563static int timescmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001564#ifdef ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +00001565static int letcmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001566#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001567static int typecmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001568#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00001569static int getoptscmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001570#endif
1571
Eric Andersen69a20f02001-10-31 10:40:37 +00001572#ifndef CONFIG_TRUE
Eric Andersen2870d962001-07-02 17:27:21 +00001573static int true_main (int, char **);
Eric Andersen69a20f02001-10-31 10:40:37 +00001574#endif
1575#ifndef CONFIG_FALSE
Eric Andersen2870d962001-07-02 17:27:21 +00001576static int false_main (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001577#endif
1578
1579static void setpwd (const char *, int);
1580
1581
1582#define BUILTIN_NOSPEC "0"
1583#define BUILTIN_SPECIAL "1"
1584#define BUILTIN_REGULAR "2"
1585#define BUILTIN_ASSIGN "4"
1586#define BUILTIN_SPEC_ASSG "5"
1587#define BUILTIN_REG_ASSG "6"
1588
1589#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1590#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1591#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
1592
1593struct builtincmd {
1594 const char *name;
1595 int (*const builtinfunc) (int, char **);
1596 //unsigned flags;
1597};
1598
Eric Andersencb57d552001-06-28 07:25:16 +00001599
1600/* It is CRUCIAL that this listing be kept in ascii order, otherwise
1601 * the binary search in find_builtin() will stop working. If you value
1602 * your kneecaps, you'll be sure to *make sure* that any changes made
1603 * to this array result in the listing remaining in ascii order. You
1604 * have been warned.
1605 */
1606static const struct builtincmd builtincmds[] = {
Eric Andersen62483552001-07-10 06:09:16 +00001607 { BUILTIN_SPECIAL ".", dotcmd }, /* first, see declare DOTCMD */
Eric Andersen2870d962001-07-02 17:27:21 +00001608 { BUILTIN_SPECIAL ":", true_main },
1609#ifdef ASH_ALIAS
1610 { BUILTIN_REG_ASSG "alias", aliascmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001611#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001612#ifdef JOBS
1613 { BUILTIN_REGULAR "bg", bgcmd },
1614#endif
1615 { BUILTIN_SPECIAL "break", breakcmd },
Eric Andersen3102ac42001-07-06 04:26:23 +00001616 { BUILTIN_SPECIAL "builtin", bltincmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001617 { BUILTIN_REGULAR "cd", cdcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001618 { BUILTIN_NOSPEC "chdir", cdcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001619#ifdef ASH_CMDCMD
1620 { BUILTIN_REGULAR "command", commandcmd },
1621#endif
1622 { BUILTIN_SPECIAL "continue", breakcmd },
1623 { BUILTIN_SPECIAL "eval", evalcmd },
1624 { BUILTIN_SPECIAL "exec", execcmd },
1625 { BUILTIN_SPECIAL "exit", exitcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001626 { BUILTIN_SPEC_ASSG "export", exportcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001627 { BUILTIN_REGULAR "false", false_main },
Eric Andersen2870d962001-07-02 17:27:21 +00001628 { BUILTIN_REGULAR "fc", histcmd },
1629#ifdef JOBS
1630 { BUILTIN_REGULAR "fg", fgcmd },
1631#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001632#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00001633 { BUILTIN_REGULAR "getopts", getoptscmd },
1634#endif
1635 { BUILTIN_NOSPEC "hash", hashcmd },
Eric Andersen1c039232001-07-07 00:05:55 +00001636 { BUILTIN_NOSPEC "help", helpcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001637 { BUILTIN_REGULAR "jobs", jobscmd },
1638#ifdef JOBS
1639 { BUILTIN_REGULAR "kill", killcmd },
1640#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001641#ifdef ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +00001642 { BUILTIN_REGULAR "let", letcmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001643#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001644 { BUILTIN_ASSIGN "local", localcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001645 { BUILTIN_NOSPEC "pwd", pwdcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001646 { BUILTIN_REGULAR "read", readcmd },
1647 { BUILTIN_SPEC_ASSG "readonly", exportcmd },
1648 { BUILTIN_SPECIAL "return", returncmd },
1649 { BUILTIN_SPECIAL "set", setcmd },
1650 { BUILTIN_NOSPEC "setvar", setvarcmd },
1651 { BUILTIN_SPECIAL "shift", shiftcmd },
1652 { BUILTIN_SPECIAL "times", timescmd },
1653 { BUILTIN_SPECIAL "trap", trapcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001654 { BUILTIN_REGULAR "true", true_main },
Eric Andersen2870d962001-07-02 17:27:21 +00001655 { BUILTIN_NOSPEC "type", typecmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001656 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1657 { BUILTIN_REGULAR "umask", umaskcmd },
1658#ifdef ASH_ALIAS
1659 { BUILTIN_REGULAR "unalias", unaliascmd },
1660#endif
1661 { BUILTIN_SPECIAL "unset", unsetcmd },
1662 { BUILTIN_REGULAR "wait", waitcmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001663};
1664#define NUMBUILTINS (sizeof (builtincmds) / sizeof (struct builtincmd) )
1665
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001666#define DOTCMD &builtincmds[0]
Eric Andersen2870d962001-07-02 17:27:21 +00001667static struct builtincmd *BLTINCMD;
1668static struct builtincmd *EXECCMD;
1669static struct builtincmd *EVALCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00001670
Eric Andersen2870d962001-07-02 17:27:21 +00001671/* states */
1672#define JOBSTOPPED 1 /* all procs are stopped */
1673#define JOBDONE 2 /* all procs are completed */
Eric Andersencb57d552001-06-28 07:25:16 +00001674
Eric Andersen2870d962001-07-02 17:27:21 +00001675/*
1676 * A job structure contains information about a job. A job is either a
1677 * single process or a set of processes contained in a pipeline. In the
1678 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1679 * array of pids.
1680 */
Eric Andersencb57d552001-06-28 07:25:16 +00001681
Eric Andersen2870d962001-07-02 17:27:21 +00001682struct procstat {
1683 pid_t pid; /* process id */
1684 int status; /* status flags (defined above) */
1685 char *cmd; /* text of command being run */
1686};
Eric Andersencb57d552001-06-28 07:25:16 +00001687
Eric Andersen2870d962001-07-02 17:27:21 +00001688
1689static int job_warning; /* user was warned about stopped jobs */
1690
1691#ifdef JOBS
1692static void setjobctl(int enable);
1693#else
1694#define setjobctl(on) /* do nothing */
Eric Andersencb57d552001-06-28 07:25:16 +00001695#endif
1696
Eric Andersen2870d962001-07-02 17:27:21 +00001697
1698struct job {
1699 struct procstat ps0; /* status of process */
1700 struct procstat *ps; /* status or processes when more than one */
1701 short nprocs; /* number of processes */
1702 short pgrp; /* process group of this job */
1703 char state; /* true if job is finished */
1704 char used; /* true if this entry is in used */
1705 char changed; /* true if status has changed */
1706#ifdef JOBS
1707 char jobctl; /* job running under job control */
1708#endif
1709};
1710
1711static struct job *jobtab; /* array of jobs */
1712static int njobs; /* size of array */
1713static int backgndpid = -1; /* pid of last background process */
1714#ifdef JOBS
1715static int initialpgrp; /* pgrp of shell on invocation */
1716static int curjob; /* current job */
1717static int jobctl;
1718#endif
1719static int intreceived;
1720
Eric Andersen62483552001-07-10 06:09:16 +00001721static struct job *makejob (const union node *, int);
1722static int forkshell (struct job *, const union node *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00001723static int waitforjob (struct job *);
1724
1725static int docd (char *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00001726static void getpwd (void);
1727
1728static char *padvance (const char **, const char *);
1729
1730static char nullstr[1]; /* zero length string */
1731static char *curdir = nullstr; /* current working directory */
Eric Andersen2870d962001-07-02 17:27:21 +00001732
Eric Andersencb57d552001-06-28 07:25:16 +00001733static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001734cdcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001735{
1736 const char *dest;
1737 const char *path;
1738 char *p;
1739 struct stat statb;
1740 int print = 0;
1741
1742 nextopt(nullstr);
1743 if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME")) == NULL)
1744 error("HOME not set");
1745 if (*dest == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00001746 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001747 if (dest[0] == '-' && dest[1] == '\0') {
1748 dest = bltinlookup("OLDPWD");
1749 if (!dest || !*dest) {
1750 dest = curdir;
1751 }
1752 print = 1;
1753 if (dest)
Eric Andersen2870d962001-07-02 17:27:21 +00001754 print = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00001755 else
Eric Andersen2870d962001-07-02 17:27:21 +00001756 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001757 }
1758 if (*dest == '/' || (path = bltinlookup("CDPATH")) == NULL)
1759 path = nullstr;
1760 while ((p = padvance(&path, dest)) != NULL) {
1761 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
1762 if (!print) {
1763 /*
1764 * XXX - rethink
1765 */
1766 if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
1767 p += 2;
1768 print = strcmp(p, dest);
1769 }
1770 if (docd(p, print) >= 0)
1771 return 0;
1772
1773 }
1774 }
1775 error("can't cd to %s", dest);
1776 /* NOTREACHED */
1777}
1778
1779
1780/*
1781 * Actually do the chdir. In an interactive shell, print the
1782 * directory name if "print" is nonzero.
1783 */
1784
1785static int
Eric Andersena3483db2001-10-24 08:01:06 +00001786docd(char *dest, int print)
Eric Andersencb57d552001-06-28 07:25:16 +00001787{
Eric Andersencb57d552001-06-28 07:25:16 +00001788 TRACE(("docd(\"%s\", %d) called\n", dest, print));
Eric Andersencb57d552001-06-28 07:25:16 +00001789 INTOFF;
1790 if (chdir(dest) < 0) {
1791 INTON;
1792 return -1;
1793 }
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001794 hashcd();
1795 /*
1796 * Update curdir (the name of the current directory) in response to a
1797 * cd command. We also call hashcd to let the routines in exec.c know
1798 * that the current directory has changed.
1799 */
1800 /* If dest is NULL, we don't know the current directory */
1801 if (dest == NULL || curdir == nullstr)
1802 setpwd(0, 1);
1803 else
1804 setpwd(dest, 1);
1805
Eric Andersencb57d552001-06-28 07:25:16 +00001806 INTON;
1807 if (print && iflag)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001808 puts(curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00001809 return 0;
1810}
1811
1812
Eric Andersencb57d552001-06-28 07:25:16 +00001813static int
Eric Andersena3483db2001-10-24 08:01:06 +00001814pwdcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001815{
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00001816 puts(curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00001817 return 0;
1818}
Eric Andersencb57d552001-06-28 07:25:16 +00001819
Eric Andersena3483db2001-10-24 08:01:06 +00001820/* Ask system the current directory */
Eric Andersencb57d552001-06-28 07:25:16 +00001821static void
Eric Andersen2870d962001-07-02 17:27:21 +00001822getpwd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00001823{
Eric Andersen2870d962001-07-02 17:27:21 +00001824 curdir = xgetcwd(0);
1825 if(curdir==0)
1826 curdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00001827}
1828
1829static void
1830setpwd(const char *val, int setold)
1831{
Eric Andersena3483db2001-10-24 08:01:06 +00001832 char *cated = NULL;
1833
Eric Andersencb57d552001-06-28 07:25:16 +00001834 if (setold) {
1835 setvar("OLDPWD", curdir, VEXPORT);
1836 }
1837 INTOFF;
1838 if (curdir != nullstr) {
Eric Andersena3483db2001-10-24 08:01:06 +00001839 if(val!=NULL && *val != '/')
1840 val = cated = concat_path_file(curdir, val);
Eric Andersencb57d552001-06-28 07:25:16 +00001841 free(curdir);
Eric Andersencb57d552001-06-28 07:25:16 +00001842 }
Eric Andersena3483db2001-10-24 08:01:06 +00001843 if (!val)
Eric Andersencb57d552001-06-28 07:25:16 +00001844 getpwd();
Eric Andersena3483db2001-10-24 08:01:06 +00001845 else
1846 curdir = simplify_path(val);
1847 free(cated);
Eric Andersencb57d552001-06-28 07:25:16 +00001848 INTON;
1849 setvar("PWD", curdir, VEXPORT);
1850}
1851
Eric Andersencb57d552001-06-28 07:25:16 +00001852/*
1853 * Errors and exceptions.
1854 */
1855
1856/*
1857 * Code to handle exceptions in C.
1858 */
1859
Eric Andersen2870d962001-07-02 17:27:21 +00001860/*
1861 * We enclose jmp_buf in a structure so that we can declare pointers to
1862 * jump locations. The global variable handler contains the location to
1863 * jump to when an exception occurs, and the global variable exception
1864 * contains a code identifying the exeception. To implement nested
1865 * exception handlers, the user should save the value of handler on entry
1866 * to an inner scope, set handler to point to a jmploc structure for the
1867 * inner scope, and restore handler on exit from the scope.
1868 */
1869
1870struct jmploc {
1871 jmp_buf loc;
1872};
1873
1874/* exceptions */
1875#define EXINT 0 /* SIGINT received */
1876#define EXERROR 1 /* a generic error */
1877#define EXSHELLPROC 2 /* execute a shell procedure */
1878#define EXEXEC 3 /* command execution failed */
1879
1880static struct jmploc *handler;
Eric Andersencb57d552001-06-28 07:25:16 +00001881static int exception;
Eric Andersencb57d552001-06-28 07:25:16 +00001882
Eric Andersen2870d962001-07-02 17:27:21 +00001883static void exverror (int, const char *, va_list)
Eric Andersencb57d552001-06-28 07:25:16 +00001884 __attribute__((__noreturn__));
1885
1886/*
1887 * Called to raise an exception. Since C doesn't include exceptions, we
1888 * just do a longjmp to the exception handler. The type of exception is
1889 * stored in the global variable "exception".
1890 */
1891
Eric Andersen2870d962001-07-02 17:27:21 +00001892static void exraise (int) __attribute__((__noreturn__));
1893
Eric Andersencb57d552001-06-28 07:25:16 +00001894static void
Eric Andersen2870d962001-07-02 17:27:21 +00001895exraise(int e)
Eric Andersencb57d552001-06-28 07:25:16 +00001896{
1897#ifdef DEBUG
1898 if (handler == NULL)
1899 abort();
1900#endif
Eric Andersen62483552001-07-10 06:09:16 +00001901 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00001902 exception = e;
1903 longjmp(handler->loc, 1);
1904}
1905
1906
1907/*
1908 * Called from trap.c when a SIGINT is received. (If the user specifies
1909 * that SIGINT is to be trapped or ignored using the trap builtin, then
1910 * this routine is not called.) Suppressint is nonzero when interrupts
1911 * are held using the INTOFF macro. The call to _exit is necessary because
1912 * there is a short period after a fork before the signal handlers are
1913 * set to the appropriate value for the child. (The test for iflag is
1914 * just defensive programming.)
1915 */
1916
1917static void
Eric Andersen2870d962001-07-02 17:27:21 +00001918onint(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00001919 sigset_t mysigset;
1920
1921 if (suppressint) {
1922 intpending++;
1923 return;
1924 }
1925 intpending = 0;
1926 sigemptyset(&mysigset);
1927 sigprocmask(SIG_SETMASK, &mysigset, NULL);
1928 if (rootshell && iflag)
1929 exraise(EXINT);
1930 else {
1931 signal(SIGINT, SIG_DFL);
1932 raise(SIGINT);
1933 }
1934 /* NOTREACHED */
1935}
1936
1937
Eric Andersen2870d962001-07-02 17:27:21 +00001938static char *commandname; /* currently executing command */
1939
Eric Andersencb57d552001-06-28 07:25:16 +00001940/*
1941 * Exverror is called to raise the error exception. If the first argument
1942 * is not NULL then error prints an error message using printf style
1943 * formatting. It then raises the error exception.
1944 */
1945static void
Eric Andersen2870d962001-07-02 17:27:21 +00001946exverror(int cond, const char *msg, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00001947{
1948 CLEAR_PENDING_INT;
1949 INTOFF;
1950
1951#ifdef DEBUG
1952 if (msg)
1953 TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
1954 else
1955 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
1956#endif
1957 if (msg) {
1958 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +00001959 out2fmt("%s: ", commandname);
1960 vfprintf(stderr, msg, ap);
1961 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00001962 }
Eric Andersencb57d552001-06-28 07:25:16 +00001963 exraise(cond);
1964 /* NOTREACHED */
1965}
1966
1967
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001968static void
Eric Andersencb57d552001-06-28 07:25:16 +00001969error(const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00001970{
Eric Andersencb57d552001-06-28 07:25:16 +00001971 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00001972 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00001973 exverror(EXERROR, msg, ap);
1974 /* NOTREACHED */
1975 va_end(ap);
1976}
1977
1978
Eric Andersencb57d552001-06-28 07:25:16 +00001979static void
1980exerror(int cond, const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00001981{
Eric Andersencb57d552001-06-28 07:25:16 +00001982 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00001983 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00001984 exverror(cond, msg, ap);
1985 /* NOTREACHED */
1986 va_end(ap);
1987}
1988
1989
1990
1991/*
1992 * Table of error messages.
1993 */
1994
1995struct errname {
Eric Andersen2870d962001-07-02 17:27:21 +00001996 short errcode; /* error number */
Eric Andersen62483552001-07-10 06:09:16 +00001997 char action; /* operation which encountered the error */
Eric Andersencb57d552001-06-28 07:25:16 +00001998};
1999
Eric Andersen2870d962001-07-02 17:27:21 +00002000/*
2001 * Types of operations (passed to the errmsg routine).
2002 */
2003
2004#define E_OPEN 01 /* opening a file */
2005#define E_CREAT 02 /* creating a file */
2006#define E_EXEC 04 /* executing a program */
Eric Andersencb57d552001-06-28 07:25:16 +00002007
2008#define ALL (E_OPEN|E_CREAT|E_EXEC)
2009
2010static const struct errname errormsg[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00002011 { EINTR, ALL },
2012 { EACCES, ALL },
2013 { EIO, ALL },
2014 { ENOENT, E_OPEN },
2015 { ENOENT, E_CREAT },
2016 { ENOENT, E_EXEC },
2017 { ENOTDIR, E_OPEN },
2018 { ENOTDIR, E_CREAT },
2019 { ENOTDIR, E_EXEC },
2020 { EISDIR, ALL },
2021 { EEXIST, E_CREAT },
2022#ifdef EMFILE
2023 { EMFILE, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002024#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002025 { ENFILE, ALL },
2026 { ENOSPC, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002027#ifdef EDQUOT
Eric Andersen2870d962001-07-02 17:27:21 +00002028 { EDQUOT, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002029#endif
2030#ifdef ENOSR
Eric Andersen2870d962001-07-02 17:27:21 +00002031 { ENOSR, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002032#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002033 { ENXIO, ALL },
2034 { EROFS, ALL },
2035 { ETXTBSY, ALL },
2036#ifdef EAGAIN
2037 { EAGAIN, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002038#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002039 { ENOMEM, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002040#ifdef ENOLINK
Eric Andersen2870d962001-07-02 17:27:21 +00002041 { ENOLINK, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002042#endif
2043#ifdef EMULTIHOP
Eric Andersen2870d962001-07-02 17:27:21 +00002044 { EMULTIHOP, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002045#endif
2046#ifdef ECOMM
Eric Andersen2870d962001-07-02 17:27:21 +00002047 { ECOMM, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002048#endif
2049#ifdef ESTALE
Eric Andersen2870d962001-07-02 17:27:21 +00002050 { ESTALE, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002051#endif
2052#ifdef ETIMEDOUT
Eric Andersen2870d962001-07-02 17:27:21 +00002053 { ETIMEDOUT, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002054#endif
2055#ifdef ELOOP
Eric Andersen2870d962001-07-02 17:27:21 +00002056 { ELOOP, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002057#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002058 { E2BIG, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002059#ifdef ELIBACC
Eric Andersen2870d962001-07-02 17:27:21 +00002060 { ELIBACC, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002061#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002062};
2063
Eric Andersen2870d962001-07-02 17:27:21 +00002064#define ERRNAME_SIZE (sizeof(errormsg)/sizeof(struct errname))
Eric Andersencb57d552001-06-28 07:25:16 +00002065
2066/*
2067 * Return a string describing an error. The returned string may be a
2068 * pointer to a static buffer that will be overwritten on the next call.
2069 * Action describes the operation that got the error.
2070 */
2071
2072static const char *
Eric Andersen2870d962001-07-02 17:27:21 +00002073errmsg(int e, int action)
Eric Andersencb57d552001-06-28 07:25:16 +00002074{
2075 struct errname const *ep;
2076 static char buf[12];
2077
Eric Andersen2870d962001-07-02 17:27:21 +00002078 for (ep = errormsg ; ep < errormsg+ERRNAME_SIZE; ep++) {
Eric Andersencb57d552001-06-28 07:25:16 +00002079 if (ep->errcode == e && (ep->action & action) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00002080 return strerror(e);
Eric Andersencb57d552001-06-28 07:25:16 +00002081 }
Eric Andersen2870d962001-07-02 17:27:21 +00002082
Eric Andersen3102ac42001-07-06 04:26:23 +00002083 snprintf(buf, sizeof buf, "error %d", e);
Eric Andersencb57d552001-06-28 07:25:16 +00002084 return buf;
2085}
2086
2087
Eric Andersen3102ac42001-07-06 04:26:23 +00002088#ifdef ASH_OPTIMIZE_FOR_SIZE
Eric Andersencb57d552001-06-28 07:25:16 +00002089static void
2090__inton() {
2091 if (--suppressint == 0 && intpending) {
2092 onint();
2093 }
2094}
Eric Andersen3102ac42001-07-06 04:26:23 +00002095static void forceinton (void) {
2096 suppressint = 0;
2097 if (intpending)
2098 onint();
2099}
Eric Andersencb57d552001-06-28 07:25:16 +00002100#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002101
2102/* flags in argument to evaltree */
Eric Andersen2870d962001-07-02 17:27:21 +00002103#define EV_EXIT 01 /* exit after evaluating tree */
2104#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2105#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00002106
Eric Andersen2870d962001-07-02 17:27:21 +00002107static int evalskip; /* set if we are skipping commands */
2108static int skipcount; /* number of levels to skip */
2109static int loopnest; /* current loop nesting level */
2110static int funcnest; /* depth of function calls */
Eric Andersencb57d552001-06-28 07:25:16 +00002111
2112
Eric Andersen2870d962001-07-02 17:27:21 +00002113static struct strlist *cmdenviron; /* environment for builtin command */
2114static int exitstatus; /* exit status of last command */
2115static int oexitstatus; /* saved exit status */
Eric Andersencb57d552001-06-28 07:25:16 +00002116
Eric Andersen62483552001-07-10 06:09:16 +00002117static void evalsubshell (const union node *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00002118static void expredir (union node *);
Eric Andersen2870d962001-07-02 17:27:21 +00002119static void eprintlist (struct strlist *);
Eric Andersencb57d552001-06-28 07:25:16 +00002120
Eric Andersen2870d962001-07-02 17:27:21 +00002121static union node *parsecmd(int);
Eric Andersencb57d552001-06-28 07:25:16 +00002122/*
2123 * Called to reset things after an exception.
2124 */
2125
Eric Andersencb57d552001-06-28 07:25:16 +00002126/*
2127 * The eval commmand.
2128 */
Eric Andersen2870d962001-07-02 17:27:21 +00002129static void evalstring (char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00002130
2131static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00002132evalcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002133{
Eric Andersen2870d962001-07-02 17:27:21 +00002134 char *p;
2135 char *concat;
2136 char **ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002137
Eric Andersen2870d962001-07-02 17:27:21 +00002138 if (argc > 1) {
2139 p = argv[1];
2140 if (argc > 2) {
2141 STARTSTACKSTR(concat);
2142 ap = argv + 2;
2143 for (;;) {
2144 while (*p)
2145 STPUTC(*p++, concat);
2146 if ((p = *ap++) == NULL)
2147 break;
2148 STPUTC(' ', concat);
2149 }
2150 STPUTC('\0', concat);
2151 p = grabstackstr(concat);
2152 }
2153 evalstring(p, EV_TESTED);
2154 }
2155 return exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002156}
2157
Eric Andersencb57d552001-06-28 07:25:16 +00002158/*
2159 * Execute a command or commands contained in a string.
2160 */
2161
Eric Andersen2870d962001-07-02 17:27:21 +00002162static void evaltree (union node *, int);
2163static void setinputstring (char *);
2164static void popfile (void);
2165static void setstackmark(struct stackmark *mark);
2166static void popstackmark(struct stackmark *mark);
2167
2168
Eric Andersencb57d552001-06-28 07:25:16 +00002169static void
Eric Andersen2870d962001-07-02 17:27:21 +00002170evalstring(char *s, int flag)
2171{
Eric Andersencb57d552001-06-28 07:25:16 +00002172 union node *n;
2173 struct stackmark smark;
2174
2175 setstackmark(&smark);
2176 setinputstring(s);
2177 while ((n = parsecmd(0)) != NEOF) {
2178 evaltree(n, flag);
2179 popstackmark(&smark);
2180 }
2181 popfile();
2182 popstackmark(&smark);
2183}
2184
Eric Andersen2870d962001-07-02 17:27:21 +00002185static struct builtincmd *find_builtin (const char *);
Eric Andersen62483552001-07-10 06:09:16 +00002186static void expandarg (union node *, struct arglist *, int);
2187static void calcsize (const union node *);
2188static union node *copynode (const union node *);
2189
2190/*
2191 * Make a copy of a parse tree.
2192 */
2193
2194static int funcblocksize; /* size of structures in function */
2195static int funcstringsize; /* size of strings in node */
2196static pointer funcblock; /* block to allocate function from */
2197static char *funcstring; /* block to allocate strings from */
2198
2199
2200static inline union node *
2201copyfunc(union node *n)
2202{
2203 if (n == NULL)
2204 return NULL;
2205 funcblocksize = 0;
2206 funcstringsize = 0;
2207 calcsize(n);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00002208 funcblock = xmalloc(funcblocksize + funcstringsize);
Eric Andersen62483552001-07-10 06:09:16 +00002209 funcstring = (char *) funcblock + funcblocksize;
2210 return copynode(n);
2211}
2212
2213/*
2214 * Free a parse tree.
2215 */
Eric Andersencb57d552001-06-28 07:25:16 +00002216
2217static void
Eric Andersen62483552001-07-10 06:09:16 +00002218freefunc(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00002219{
Eric Andersen62483552001-07-10 06:09:16 +00002220 if (n)
2221 ckfree(n);
Eric Andersencb57d552001-06-28 07:25:16 +00002222}
2223
2224
Eric Andersen62483552001-07-10 06:09:16 +00002225/*
2226 * Add a new command entry, replacing any existing command entry for
2227 * the same name.
2228 */
2229
2230static inline void
2231addcmdentry(char *name, struct cmdentry *entry)
2232{
2233 struct tblentry *cmdp;
2234
2235 INTOFF;
2236 cmdp = cmdlookup(name, 1);
2237 if (cmdp->cmdtype == CMDFUNCTION) {
2238 freefunc(cmdp->param.func);
2239 }
2240 cmdp->cmdtype = entry->cmdtype;
2241 cmdp->param = entry->u;
2242 INTON;
2243}
2244
2245static inline void
2246evalloop(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002247{
2248 int status;
2249
2250 loopnest++;
2251 status = 0;
2252 for (;;) {
2253 evaltree(n->nbinary.ch1, EV_TESTED);
2254 if (evalskip) {
Eric Andersen2870d962001-07-02 17:27:21 +00002255skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002256 evalskip = 0;
2257 continue;
2258 }
2259 if (evalskip == SKIPBREAK && --skipcount <= 0)
2260 evalskip = 0;
2261 break;
2262 }
2263 if (n->type == NWHILE) {
2264 if (exitstatus != 0)
2265 break;
2266 } else {
2267 if (exitstatus == 0)
2268 break;
2269 }
2270 evaltree(n->nbinary.ch2, flags & EV_TESTED);
2271 status = exitstatus;
2272 if (evalskip)
2273 goto skipping;
2274 }
2275 loopnest--;
2276 exitstatus = status;
2277}
2278
Eric Andersencb57d552001-06-28 07:25:16 +00002279static void
Eric Andersen62483552001-07-10 06:09:16 +00002280evalfor(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002281{
2282 struct arglist arglist;
2283 union node *argp;
2284 struct strlist *sp;
2285 struct stackmark smark;
2286
2287 setstackmark(&smark);
2288 arglist.lastp = &arglist.list;
2289 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2290 oexitstatus = exitstatus;
2291 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2292 if (evalskip)
2293 goto out;
2294 }
2295 *arglist.lastp = NULL;
2296
2297 exitstatus = 0;
2298 loopnest++;
2299 for (sp = arglist.list ; sp ; sp = sp->next) {
2300 setvar(n->nfor.var, sp->text, 0);
2301 evaltree(n->nfor.body, flags & EV_TESTED);
2302 if (evalskip) {
2303 if (evalskip == SKIPCONT && --skipcount <= 0) {
2304 evalskip = 0;
2305 continue;
2306 }
2307 if (evalskip == SKIPBREAK && --skipcount <= 0)
2308 evalskip = 0;
2309 break;
2310 }
2311 }
2312 loopnest--;
2313out:
2314 popstackmark(&smark);
2315}
2316
Eric Andersen62483552001-07-10 06:09:16 +00002317static inline void
2318evalcase(const union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002319{
2320 union node *cp;
2321 union node *patp;
2322 struct arglist arglist;
2323 struct stackmark smark;
2324
2325 setstackmark(&smark);
2326 arglist.lastp = &arglist.list;
2327 oexitstatus = exitstatus;
2328 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2329 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2330 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2331 if (casematch(patp, arglist.list->text)) {
2332 if (evalskip == 0) {
2333 evaltree(cp->nclist.body, flags);
2334 }
2335 goto out;
2336 }
2337 }
2338 }
2339out:
2340 popstackmark(&smark);
2341}
2342
Eric Andersencb57d552001-06-28 07:25:16 +00002343/*
Eric Andersencb57d552001-06-28 07:25:16 +00002344 * Evaluate a pipeline. All the processes in the pipeline are children
2345 * of the process creating the pipeline. (This differs from some versions
2346 * of the shell, which make the last process in a pipeline the parent
2347 * of all the rest.)
2348 */
2349
Eric Andersen74400cc2001-10-18 04:11:39 +00002350static inline void evalpipe(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00002351{
2352 struct job *jp;
2353 struct nodelist *lp;
2354 int pipelen;
2355 int prevfd;
2356 int pip[2];
2357
2358 TRACE(("evalpipe(0x%lx) called\n", (long)n));
2359 pipelen = 0;
2360 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
2361 pipelen++;
2362 INTOFF;
2363 jp = makejob(n, pipelen);
2364 prevfd = -1;
2365 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00002366 /*
2367 * Search for a command. This is called before we fork so that the
2368 * location of the command will be available in the parent as well as
2369 * the child. The check for "goodname" is an overly conservative
2370 * check that the name will not be subject to expansion.
2371 */
2372
2373 struct cmdentry entry;
2374 union node *lpn = lp->n;
2375 if (lpn->type == NCMD && lpn->ncmd.args && goodname(lpn->ncmd.args->narg.text))
2376 find_command(lpn->ncmd.args->narg.text, &entry, 0, pathval());
2377
Eric Andersencb57d552001-06-28 07:25:16 +00002378 pip[1] = -1;
2379 if (lp->next) {
2380 if (pipe(pip) < 0) {
2381 close(prevfd);
2382 error("Pipe call failed");
2383 }
2384 }
2385 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
2386 INTON;
2387 if (prevfd > 0) {
2388 close(0);
2389 dup_as_newfd(prevfd, 0);
2390 close(prevfd);
2391 if (pip[0] == 0) {
2392 pip[0] = -1;
2393 }
2394 }
2395 if (pip[1] >= 0) {
2396 if (pip[0] >= 0) {
2397 close(pip[0]);
2398 }
2399 if (pip[1] != 1) {
2400 close(1);
2401 dup_as_newfd(pip[1], 1);
2402 close(pip[1]);
2403 }
2404 }
2405 evaltree(lp->n, EV_EXIT);
2406 }
2407 if (prevfd >= 0)
2408 close(prevfd);
2409 prevfd = pip[0];
2410 close(pip[1]);
2411 }
2412 INTON;
2413 if (n->npipe.backgnd == 0) {
2414 INTOFF;
2415 exitstatus = waitforjob(jp);
2416 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
2417 INTON;
2418 }
2419}
2420
Eric Andersen2870d962001-07-02 17:27:21 +00002421static int
2422isassignment(const char *word) {
2423 if (!is_name(*word)) {
2424 return 0;
2425 }
2426 do {
2427 word++;
2428 } while (is_in_name(*word));
2429 return *word == '=';
2430}
2431
Eric Andersen62483552001-07-10 06:09:16 +00002432
Eric Andersencb57d552001-06-28 07:25:16 +00002433static void
Eric Andersen3102ac42001-07-06 04:26:23 +00002434evalcommand(union node *cmd, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002435{
2436 struct stackmark smark;
2437 union node *argp;
2438 struct arglist arglist;
2439 struct arglist varlist;
2440 char **argv;
2441 int argc;
2442 char **envp;
2443 struct strlist *sp;
2444 int mode;
Eric Andersencb57d552001-06-28 07:25:16 +00002445 struct cmdentry cmdentry;
2446 struct job *jp;
2447 char *volatile savecmdname;
2448 volatile struct shparam saveparam;
2449 struct localvar *volatile savelocalvars;
2450 volatile int e;
2451 char *lastarg;
2452 const char *path;
2453 const struct builtincmd *firstbltin;
2454 struct jmploc *volatile savehandler;
2455 struct jmploc jmploc;
2456#if __GNUC__
2457 /* Avoid longjmp clobbering */
2458 (void) &argv;
2459 (void) &argc;
2460 (void) &lastarg;
2461 (void) &flags;
2462#endif
2463
2464 /* First expand the arguments. */
2465 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
2466 setstackmark(&smark);
2467 arglist.lastp = &arglist.list;
2468 varlist.lastp = &varlist.list;
2469 arglist.list = 0;
2470 oexitstatus = exitstatus;
2471 exitstatus = 0;
2472 path = pathval();
2473 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
2474 expandarg(argp, &varlist, EXP_VARTILDE);
2475 }
2476 for (
2477 argp = cmd->ncmd.args; argp && !arglist.list;
2478 argp = argp->narg.next
2479 ) {
2480 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2481 }
2482 if (argp) {
2483 struct builtincmd *bcmd;
Eric Andersen62483552001-07-10 06:09:16 +00002484 int pseudovarflag;
Eric Andersencb57d552001-06-28 07:25:16 +00002485 bcmd = find_builtin(arglist.list->text);
Eric Andersen2870d962001-07-02 17:27:21 +00002486 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00002487 for (; argp; argp = argp->narg.next) {
2488 if (pseudovarflag && isassignment(argp->narg.text)) {
2489 expandarg(argp, &arglist, EXP_VARTILDE);
2490 continue;
2491 }
2492 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2493 }
2494 }
2495 *arglist.lastp = NULL;
2496 *varlist.lastp = NULL;
2497 expredir(cmd->ncmd.redirect);
2498 argc = 0;
2499 for (sp = arglist.list ; sp ; sp = sp->next)
2500 argc++;
2501 argv = stalloc(sizeof (char *) * (argc + 1));
2502
2503 for (sp = arglist.list ; sp ; sp = sp->next) {
2504 TRACE(("evalcommand arg: %s\n", sp->text));
2505 *argv++ = sp->text;
2506 }
2507 *argv = NULL;
2508 lastarg = NULL;
2509 if (iflag && funcnest == 0 && argc > 0)
2510 lastarg = argv[-1];
2511 argv -= argc;
2512
2513 /* Print the command if xflag is set. */
2514 if (xflag) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002515 out2c('+');
Eric Andersencb57d552001-06-28 07:25:16 +00002516 eprintlist(varlist.list);
2517 eprintlist(arglist.list);
Eric Andersen3102ac42001-07-06 04:26:23 +00002518 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00002519 }
2520
2521 /* Now locate the command. */
2522 if (argc == 0) {
2523 cmdentry.cmdtype = CMDBUILTIN;
2524 firstbltin = cmdentry.u.cmd = BLTINCMD;
2525 } else {
2526 const char *oldpath;
2527 int findflag = DO_ERR;
2528 int oldfindflag;
2529
2530 /*
2531 * Modify the command lookup path, if a PATH= assignment
2532 * is present
2533 */
2534 for (sp = varlist.list ; sp ; sp = sp->next)
2535 if (varequal(sp->text, defpathvar)) {
2536 path = sp->text + 5;
2537 findflag |= DO_BRUTE;
2538 }
2539 oldpath = path;
2540 oldfindflag = findflag;
2541 firstbltin = 0;
2542 for(;;) {
2543 find_command(argv[0], &cmdentry, findflag, path);
Eric Andersen2870d962001-07-02 17:27:21 +00002544 if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */
Eric Andersencb57d552001-06-28 07:25:16 +00002545 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002546 goto out;
2547 }
2548 /* implement bltin and command here */
2549 if (cmdentry.cmdtype != CMDBUILTIN) {
2550 break;
2551 }
2552 if (!firstbltin) {
2553 firstbltin = cmdentry.u.cmd;
2554 }
2555 if (cmdentry.u.cmd == BLTINCMD) {
2556 for(;;) {
2557 struct builtincmd *bcmd;
2558
2559 argv++;
2560 if (--argc == 0)
2561 goto found;
2562 if (!(bcmd = find_builtin(*argv))) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002563 out2fmt("%s: not found\n", *argv);
Eric Andersencb57d552001-06-28 07:25:16 +00002564 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002565 goto out;
2566 }
2567 cmdentry.u.cmd = bcmd;
2568 if (bcmd != BLTINCMD)
2569 break;
2570 }
2571 }
Eric Andersen2870d962001-07-02 17:27:21 +00002572 if (cmdentry.u.cmd == find_builtin("command")) {
Eric Andersencb57d552001-06-28 07:25:16 +00002573 argv++;
2574 if (--argc == 0) {
2575 goto found;
2576 }
2577 if (*argv[0] == '-') {
2578 if (!equal(argv[0], "-p")) {
2579 argv--;
2580 argc++;
2581 break;
2582 }
2583 argv++;
2584 if (--argc == 0) {
2585 goto found;
2586 }
2587 path = defpath;
2588 findflag |= DO_BRUTE;
2589 } else {
2590 path = oldpath;
2591 findflag = oldfindflag;
2592 }
2593 findflag |= DO_NOFUN;
2594 continue;
2595 }
2596found:
2597 break;
2598 }
2599 }
2600
2601 /* Fork off a child process if necessary. */
2602 if (cmd->ncmd.backgnd
2603 || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00002604 ) {
2605 jp = makejob(cmd, 1);
2606 mode = cmd->ncmd.backgnd;
Eric Andersencb57d552001-06-28 07:25:16 +00002607 if (forkshell(jp, cmd, mode) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00002608 goto parent; /* at end of routine */
Eric Andersencb57d552001-06-28 07:25:16 +00002609 flags |= EV_EXIT;
2610 }
2611
2612 /* This is the child process if a fork occurred. */
2613 /* Execute the command. */
2614 if (cmdentry.cmdtype == CMDFUNCTION) {
2615#ifdef DEBUG
2616 trputs("Shell function: "); trargs(argv);
2617#endif
2618 exitstatus = oexitstatus;
2619 redirect(cmd->ncmd.redirect, REDIR_PUSH);
2620 saveparam = shellparam;
2621 shellparam.malloc = 0;
2622 shellparam.nparam = argc - 1;
2623 shellparam.p = argv + 1;
2624 INTOFF;
2625 savelocalvars = localvars;
2626 localvars = NULL;
2627 INTON;
2628 if (setjmp(jmploc.loc)) {
2629 if (exception == EXSHELLPROC) {
2630 freeparam((volatile struct shparam *)
2631 &saveparam);
2632 } else {
2633 saveparam.optind = shellparam.optind;
2634 saveparam.optoff = shellparam.optoff;
2635 freeparam(&shellparam);
2636 shellparam = saveparam;
2637 }
2638 poplocalvars();
2639 localvars = savelocalvars;
2640 handler = savehandler;
2641 longjmp(handler->loc, 1);
2642 }
2643 savehandler = handler;
2644 handler = &jmploc;
2645 for (sp = varlist.list ; sp ; sp = sp->next)
2646 mklocal(sp->text);
2647 funcnest++;
2648 evaltree(cmdentry.u.func, flags & EV_TESTED);
2649 funcnest--;
2650 INTOFF;
2651 poplocalvars();
2652 localvars = savelocalvars;
2653 saveparam.optind = shellparam.optind;
2654 saveparam.optoff = shellparam.optoff;
2655 freeparam(&shellparam);
2656 shellparam = saveparam;
2657 handler = savehandler;
2658 popredir();
2659 INTON;
2660 if (evalskip == SKIPFUNC) {
2661 evalskip = 0;
2662 skipcount = 0;
2663 }
2664 if (flags & EV_EXIT)
2665 exitshell(exitstatus);
2666 } else if (cmdentry.cmdtype == CMDBUILTIN) {
2667#ifdef DEBUG
2668 trputs("builtin command: "); trargs(argv);
2669#endif
2670 mode = (cmdentry.u.cmd == EXECCMD)? 0 : REDIR_PUSH;
Eric Andersencb57d552001-06-28 07:25:16 +00002671 redirect(cmd->ncmd.redirect, mode);
2672 savecmdname = commandname;
Eric Andersen2870d962001-07-02 17:27:21 +00002673 if (IS_BUILTIN_SPECIAL(firstbltin)) {
Eric Andersencb57d552001-06-28 07:25:16 +00002674 listsetvar(varlist.list);
2675 } else {
2676 cmdenviron = varlist.list;
2677 }
2678 e = -1;
2679 if (setjmp(jmploc.loc)) {
2680 e = exception;
2681 exitstatus = (e == EXINT)? SIGINT+128 : 2;
2682 goto cmddone;
2683 }
2684 savehandler = handler;
2685 handler = &jmploc;
2686 commandname = argv[0];
2687 argptr = argv + 1;
Eric Andersen2870d962001-07-02 17:27:21 +00002688 optptr = NULL; /* initialize nextopt */
Eric Andersencb57d552001-06-28 07:25:16 +00002689 exitstatus = (*cmdentry.u.cmd->builtinfunc)(argc, argv);
2690 flushall();
2691cmddone:
Eric Andersencb57d552001-06-28 07:25:16 +00002692 cmdenviron = NULL;
2693 if (e != EXSHELLPROC) {
2694 commandname = savecmdname;
2695 if (flags & EV_EXIT)
2696 exitshell(exitstatus);
2697 }
2698 handler = savehandler;
2699 if (e != -1) {
2700 if ((e != EXERROR && e != EXEXEC)
2701 || cmdentry.u.cmd == BLTINCMD
2702 || cmdentry.u.cmd == DOTCMD
2703 || cmdentry.u.cmd == EVALCMD
2704 || cmdentry.u.cmd == EXECCMD)
2705 exraise(e);
2706 FORCEINTON;
2707 }
2708 if (cmdentry.u.cmd != EXECCMD)
2709 popredir();
Eric Andersencb57d552001-06-28 07:25:16 +00002710 } else {
2711#ifdef DEBUG
2712 trputs("normal command: "); trargs(argv);
2713#endif
2714 redirect(cmd->ncmd.redirect, 0);
2715 clearredir();
2716 for (sp = varlist.list ; sp ; sp = sp->next)
2717 setvareq(sp->text, VEXPORT|VSTACK);
2718 envp = environment();
2719 shellexec(argv, envp, path, cmdentry.u.index);
2720 }
2721 goto out;
2722
Eric Andersen2870d962001-07-02 17:27:21 +00002723parent: /* parent process gets here (if we forked) */
2724 if (mode == 0) { /* argument to fork */
Eric Andersencb57d552001-06-28 07:25:16 +00002725 INTOFF;
2726 exitstatus = waitforjob(jp);
2727 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00002728 }
2729
2730out:
2731 if (lastarg)
2732 setvar("_", lastarg, 0);
2733 popstackmark(&smark);
2734}
2735
Eric Andersen62483552001-07-10 06:09:16 +00002736/*
2737 * Evaluate a parse tree. The value is left in the global variable
2738 * exitstatus.
2739 */
2740static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00002741evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00002742{
2743 int checkexit = 0;
2744 if (n == NULL) {
2745 TRACE(("evaltree(NULL) called\n"));
2746 goto out;
2747 }
2748 TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
2749 switch (n->type) {
2750 case NSEMI:
2751 evaltree(n->nbinary.ch1, flags & EV_TESTED);
2752 if (evalskip)
2753 goto out;
2754 evaltree(n->nbinary.ch2, flags);
2755 break;
2756 case NAND:
2757 evaltree(n->nbinary.ch1, EV_TESTED);
2758 if (evalskip || exitstatus != 0)
2759 goto out;
2760 evaltree(n->nbinary.ch2, flags);
2761 break;
2762 case NOR:
2763 evaltree(n->nbinary.ch1, EV_TESTED);
2764 if (evalskip || exitstatus == 0)
2765 goto out;
2766 evaltree(n->nbinary.ch2, flags);
2767 break;
2768 case NREDIR:
2769 expredir(n->nredir.redirect);
2770 redirect(n->nredir.redirect, REDIR_PUSH);
2771 evaltree(n->nredir.n, flags);
2772 popredir();
2773 break;
2774 case NSUBSHELL:
2775 evalsubshell(n, flags);
2776 break;
2777 case NBACKGND:
2778 evalsubshell(n, flags);
2779 break;
2780 case NIF: {
2781 evaltree(n->nif.test, EV_TESTED);
2782 if (evalskip)
2783 goto out;
2784 if (exitstatus == 0)
2785 evaltree(n->nif.ifpart, flags);
2786 else if (n->nif.elsepart)
2787 evaltree(n->nif.elsepart, flags);
2788 else
2789 exitstatus = 0;
2790 break;
2791 }
2792 case NWHILE:
2793 case NUNTIL:
2794 evalloop(n, flags);
2795 break;
2796 case NFOR:
2797 evalfor(n, flags);
2798 break;
2799 case NCASE:
2800 evalcase(n, flags);
2801 break;
2802 case NDEFUN: {
2803 struct builtincmd *bcmd;
2804 struct cmdentry entry;
2805 if (
2806 (bcmd = find_builtin(n->narg.text)) &&
2807 IS_BUILTIN_SPECIAL(bcmd)
2808 ) {
2809 out2fmt("%s is a special built-in\n", n->narg.text);
2810 exitstatus = 1;
2811 break;
2812 }
2813 entry.cmdtype = CMDFUNCTION;
2814 entry.u.func = copyfunc(n->narg.next);
2815 addcmdentry(n->narg.text, &entry);
2816 exitstatus = 0;
2817 break;
2818 }
2819 case NNOT:
2820 evaltree(n->nnot.com, EV_TESTED);
2821 exitstatus = !exitstatus;
2822 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002823
Eric Andersen62483552001-07-10 06:09:16 +00002824 case NPIPE:
2825 evalpipe(n);
2826 checkexit = 1;
2827 break;
2828 case NCMD:
2829 evalcommand(n, flags);
2830 checkexit = 1;
2831 break;
2832#ifdef DEBUG
2833 default:
2834 printf("Node type = %d\n", n->type);
2835 break;
2836#endif
2837 }
2838out:
2839 if (pendingsigs)
2840 dotrap();
2841 if (
2842 flags & EV_EXIT ||
2843 (checkexit && eflag && exitstatus && !(flags & EV_TESTED))
2844 )
2845 exitshell(exitstatus);
2846}
2847
2848/*
2849 * Kick off a subshell to evaluate a tree.
2850 */
2851
2852static void
2853evalsubshell(const union node *n, int flags)
2854{
2855 struct job *jp;
2856 int backgnd = (n->type == NBACKGND);
2857
2858 expredir(n->nredir.redirect);
2859 jp = makejob(n, 1);
2860 if (forkshell(jp, n, backgnd) == 0) {
2861 if (backgnd)
2862 flags &=~ EV_TESTED;
2863 redirect(n->nredir.redirect, 0);
2864 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
2865 }
2866 if (! backgnd) {
2867 INTOFF;
2868 exitstatus = waitforjob(jp);
2869 INTON;
2870 }
2871}
2872
2873/*
2874 * Compute the names of the files in a redirection list.
2875 */
2876
2877static void fixredir(union node *n, const char *text, int err);
2878
2879static void
2880expredir(union node *n)
2881{
2882 union node *redir;
2883
2884 for (redir = n ; redir ; redir = redir->nfile.next) {
2885 struct arglist fn;
2886 fn.lastp = &fn.list;
2887 oexitstatus = exitstatus;
2888 switch (redir->type) {
2889 case NFROMTO:
2890 case NFROM:
2891 case NTO:
2892 case NAPPEND:
2893 case NTOOV:
2894 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
2895 redir->nfile.expfname = fn.list->text;
2896 break;
2897 case NFROMFD:
2898 case NTOFD:
2899 if (redir->ndup.vname) {
2900 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
2901 fixredir(redir, fn.list->text, 1);
2902 }
2903 break;
2904 }
2905 }
2906}
2907
2908
2909/*
2910 * Execute a command inside back quotes. If it's a builtin command, we
2911 * want to save its output in a block obtained from malloc. Otherwise
2912 * we fork off a subprocess and get the output of the command via a pipe.
2913 * Should be called with interrupts off.
2914 */
2915
2916static void
2917evalbackcmd(union node *n, struct backcmd *result)
2918{
2919 int pip[2];
2920 struct job *jp;
2921 struct stackmark smark; /* unnecessary */
2922
2923 setstackmark(&smark);
2924 result->fd = -1;
2925 result->buf = NULL;
2926 result->nleft = 0;
2927 result->jp = NULL;
2928 if (n == NULL) {
2929 exitstatus = 0;
2930 goto out;
2931 }
2932 exitstatus = 0;
2933 if (pipe(pip) < 0)
2934 error("Pipe call failed");
2935 jp = makejob(n, 1);
2936 if (forkshell(jp, n, FORK_NOJOB) == 0) {
2937 FORCEINTON;
2938 close(pip[0]);
2939 if (pip[1] != 1) {
2940 close(1);
2941 dup_as_newfd(pip[1], 1);
2942 close(pip[1]);
2943 }
2944 eflag = 0;
2945 evaltree(n, EV_EXIT);
2946 }
2947 close(pip[1]);
2948 result->fd = pip[0];
2949 result->jp = jp;
2950out:
2951 popstackmark(&smark);
2952 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
2953 result->fd, result->buf, result->nleft, result->jp));
2954}
2955
2956
2957/*
2958 * Execute a simple command.
2959 */
Eric Andersencb57d552001-06-28 07:25:16 +00002960
Eric Andersencb57d552001-06-28 07:25:16 +00002961
Eric Andersencb57d552001-06-28 07:25:16 +00002962/*
2963 * Builtin commands. Builtin commands whose functions are closely
2964 * tied to evaluation are implemented here.
2965 */
2966
2967/*
2968 * No command given, or a bltin command with no arguments. Set the
2969 * specified variables.
2970 */
2971
2972int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00002973bltincmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002974{
2975 /*
2976 * Preserve exitstatus of a previous possible redirection
2977 * as POSIX mandates
2978 */
2979 return exitstatus;
2980}
2981
2982
2983/*
2984 * Handle break and continue commands. Break, continue, and return are
2985 * all handled by setting the evalskip flag. The evaluation routines
2986 * above all check this flag, and if it is set they start skipping
2987 * commands rather than executing them. The variable skipcount is
2988 * the number of loops to break/continue, or the number of function
2989 * levels to return. (The latter is always 1.) It should probably
2990 * be an error to break out of more loops than exist, but it isn't
2991 * in the standard shell so we don't make it one here.
2992 */
2993
2994static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00002995breakcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002996{
2997 int n = argc > 1 ? number(argv[1]) : 1;
2998
2999 if (n > loopnest)
3000 n = loopnest;
3001 if (n > 0) {
3002 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
3003 skipcount = n;
3004 }
3005 return 0;
3006}
3007
3008
3009/*
3010 * The return command.
3011 */
3012
3013static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003014returncmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003015{
3016 int ret = argc > 1 ? number(argv[1]) : oexitstatus;
3017
3018 if (funcnest) {
3019 evalskip = SKIPFUNC;
3020 skipcount = 1;
3021 return ret;
3022 }
3023 else {
3024 /* Do what ksh does; skip the rest of the file */
3025 evalskip = SKIPFILE;
3026 skipcount = 1;
3027 return ret;
3028 }
3029}
3030
3031
Eric Andersen69a20f02001-10-31 10:40:37 +00003032#ifndef CONFIG_FALSE
Eric Andersencb57d552001-06-28 07:25:16 +00003033static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003034false_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003035{
3036 return 1;
3037}
Eric Andersen69a20f02001-10-31 10:40:37 +00003038#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003039
Eric Andersen69a20f02001-10-31 10:40:37 +00003040#ifndef CONFIG_TRUE
Eric Andersencb57d552001-06-28 07:25:16 +00003041static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003042true_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003043{
3044 return 0;
3045}
3046#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003047
3048/*
3049 * Controls whether the shell is interactive or not.
3050 */
3051
3052static void setsignal(int signo);
Eric Andersen2870d962001-07-02 17:27:21 +00003053
Eric Andersenec074692001-10-31 11:05:49 +00003054#ifdef ASH_MAIL
3055static void chkmail(int silent);
3056#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003057
3058static void
3059setinteractive(int on)
3060{
3061 static int is_interactive;
Eric Andersen1c039232001-07-07 00:05:55 +00003062 static int do_banner=0;
Eric Andersen2870d962001-07-02 17:27:21 +00003063
3064 if (on == is_interactive)
3065 return;
3066 setsignal(SIGINT);
3067 setsignal(SIGQUIT);
3068 setsignal(SIGTERM);
Eric Andersenec074692001-10-31 11:05:49 +00003069#ifdef ASH_MAIL
Eric Andersen2870d962001-07-02 17:27:21 +00003070 chkmail(1);
Eric Andersenec074692001-10-31 11:05:49 +00003071#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003072 is_interactive = on;
Eric Andersen1c039232001-07-07 00:05:55 +00003073 if (do_banner==0 && is_interactive) {
3074 /* Looks like they want an interactive shell */
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003075#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
Eric Andersen1c039232001-07-07 00:05:55 +00003076 printf( "\n\n" BB_BANNER " Built-in shell (ash)\n");
3077 printf( "Enter 'help' for a list of built-in commands.\n\n");
Eric Andersend63dee42001-10-19 00:22:23 +00003078#endif
Eric Andersen1c039232001-07-07 00:05:55 +00003079 do_banner=1;
3080 }
Eric Andersen2870d962001-07-02 17:27:21 +00003081}
3082
3083static void
3084optschanged(void)
3085{
3086 setinteractive(iflag);
3087 setjobctl(mflag);
3088}
3089
Eric Andersencb57d552001-06-28 07:25:16 +00003090
3091static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003092execcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003093{
3094 if (argc > 1) {
3095 struct strlist *sp;
3096
Eric Andersen2870d962001-07-02 17:27:21 +00003097 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003098 mflag = 0;
3099 optschanged();
3100 for (sp = cmdenviron; sp ; sp = sp->next)
3101 setvareq(sp->text, VEXPORT|VSTACK);
3102 shellexec(argv + 1, environment(), pathval(), 0);
3103 }
3104 return 0;
3105}
3106
3107static void
3108eprintlist(struct strlist *sp)
3109{
3110 for (; sp; sp = sp->next) {
Eric Andersen3102ac42001-07-06 04:26:23 +00003111 out2fmt(" %s",sp->text);
Eric Andersencb57d552001-06-28 07:25:16 +00003112 }
3113}
Eric Andersencb57d552001-06-28 07:25:16 +00003114
3115/*
3116 * Exec a program. Never returns. If you change this routine, you may
3117 * have to change the find_command routine as well.
3118 */
3119
Eric Andersen2870d962001-07-02 17:27:21 +00003120static const char *pathopt; /* set by padvance */
3121
Eric Andersencb57d552001-06-28 07:25:16 +00003122static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003123shellexec(char **argv, char **envp, const char *path, int idx)
Eric Andersencb57d552001-06-28 07:25:16 +00003124{
3125 char *cmdname;
3126 int e;
3127
3128 if (strchr(argv[0], '/') != NULL) {
3129 tryexec(argv[0], argv, envp);
3130 e = errno;
3131 } else {
3132 e = ENOENT;
3133 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3134 if (--idx < 0 && pathopt == NULL) {
3135 tryexec(cmdname, argv, envp);
3136 if (errno != ENOENT && errno != ENOTDIR)
3137 e = errno;
3138 }
3139 stunalloc(cmdname);
3140 }
3141 }
3142
3143 /* Map to POSIX errors */
3144 switch (e) {
3145 case EACCES:
3146 exerrno = 126;
3147 break;
3148 case ENOENT:
3149 exerrno = 127;
3150 break;
3151 default:
3152 exerrno = 2;
3153 break;
3154 }
3155 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3156 /* NOTREACHED */
3157}
3158
Eric Andersen2870d962001-07-02 17:27:21 +00003159/*
3160 * Clear traps on a fork.
3161 */
3162static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003163clear_traps(void)
3164{
Eric Andersen2870d962001-07-02 17:27:21 +00003165 char **tp;
3166
3167 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
3168 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
3169 INTOFF;
3170 ckfree(*tp);
3171 *tp = NULL;
3172 if (tp != &trap[0])
3173 setsignal(tp - trap);
3174 INTON;
3175 }
3176 }
3177}
3178
3179
3180static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003181initshellproc(void)
3182{
Eric Andersen2870d962001-07-02 17:27:21 +00003183
3184#ifdef ASH_ALIAS
3185 /* from alias.c: */
3186 {
3187 rmaliases();
3188 }
3189#endif
3190 /* from eval.c: */
3191 {
3192 exitstatus = 0;
3193 }
3194
3195 /* from exec.c: */
3196 {
3197 deletefuncs();
3198 }
3199
3200 /* from jobs.c: */
3201 {
3202 backgndpid = -1;
3203#ifdef JOBS
3204 jobctl = 0;
3205#endif
3206 }
3207
3208 /* from options.c: */
3209 {
3210 int i;
3211
3212 for (i = 0; i < NOPTS; i++)
3213 optent_val(i) = 0;
3214 optschanged();
3215
3216 }
3217
3218 /* from redir.c: */
3219 {
3220 clearredir();
3221 }
3222
3223 /* from trap.c: */
3224 {
3225 char *sm;
3226
3227 clear_traps();
3228 for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) {
3229 if (*sm == S_IGN)
3230 *sm = S_HARD_IGN;
3231 }
3232 }
3233
3234 /* from var.c: */
3235 {
3236 shprocvar();
3237 }
3238}
3239
3240static int preadbuffer(void);
3241static void pushfile (void);
Eric Andersen2870d962001-07-02 17:27:21 +00003242
3243/*
3244 * Read a character from the script, returning PEOF on end of file.
3245 * Nul characters in the input are silently discarded.
3246 */
3247
Eric Andersen3102ac42001-07-06 04:26:23 +00003248#ifndef ASH_OPTIMIZE_FOR_SIZE
Eric Andersen2870d962001-07-02 17:27:21 +00003249#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
3250static int
3251pgetc(void)
3252{
3253 return pgetc_macro();
3254}
3255#else
3256static int
3257pgetc_macro(void)
3258{
3259 return --parsenleft >= 0? *parsenextc++ : preadbuffer();
3260}
3261
3262static inline int
3263pgetc(void)
3264{
3265 return pgetc_macro();
3266}
3267#endif
3268
3269
3270/*
3271 * Undo the last call to pgetc. Only one character may be pushed back.
3272 * PEOF may be pushed back.
3273 */
3274
Eric Andersen74400cc2001-10-18 04:11:39 +00003275static void pungetc(void)
3276{
Eric Andersen2870d962001-07-02 17:27:21 +00003277 parsenleft++;
3278 parsenextc--;
3279}
3280
3281
3282static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003283popfile(void)
3284{
Eric Andersen2870d962001-07-02 17:27:21 +00003285 struct parsefile *pf = parsefile;
3286
3287 INTOFF;
3288 if (pf->fd >= 0)
3289 close(pf->fd);
3290 if (pf->buf)
3291 ckfree(pf->buf);
3292 while (pf->strpush)
3293 popstring();
3294 parsefile = pf->prev;
3295 ckfree(pf);
3296 parsenleft = parsefile->nleft;
3297 parselleft = parsefile->lleft;
3298 parsenextc = parsefile->nextc;
3299 plinno = parsefile->linno;
3300 INTON;
3301}
3302
3303
3304/*
3305 * Return to top level.
3306 */
3307
3308static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003309popallfiles(void)
3310{
Eric Andersen2870d962001-07-02 17:27:21 +00003311 while (parsefile != &basepf)
3312 popfile();
3313}
3314
3315/*
3316 * Close the file(s) that the shell is reading commands from. Called
3317 * after a fork is done.
3318 */
3319
Eric Andersen74400cc2001-10-18 04:11:39 +00003320static void closescript(void)
3321{
Eric Andersen2870d962001-07-02 17:27:21 +00003322 popallfiles();
3323 if (parsefile->fd > 0) {
3324 close(parsefile->fd);
3325 parsefile->fd = 0;
3326 }
3327}
3328
3329
3330/*
3331 * Like setinputfile, but takes an open file descriptor. Call this with
3332 * interrupts off.
3333 */
3334
Eric Andersen74400cc2001-10-18 04:11:39 +00003335static void setinputfd(int fd, int push)
Eric Andersen2870d962001-07-02 17:27:21 +00003336{
3337 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
3338 if (push) {
3339 pushfile();
3340 parsefile->buf = 0;
3341 } else {
3342 closescript();
3343 while (parsefile->strpush)
3344 popstring();
3345 }
3346 parsefile->fd = fd;
3347 if (parsefile->buf == NULL)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003348 parsefile->buf = xmalloc(BUFSIZ);
Eric Andersen2870d962001-07-02 17:27:21 +00003349 parselleft = parsenleft = 0;
3350 plinno = 1;
3351}
3352
3353
3354/*
3355 * Set the input to take input from a file. If push is set, push the
3356 * old input onto the stack first.
3357 */
3358
3359static void
3360setinputfile(const char *fname, int push)
3361{
3362 int fd;
3363 int myfileno2;
3364
3365 INTOFF;
3366 if ((fd = open(fname, O_RDONLY)) < 0)
3367 error("Can't open %s", fname);
3368 if (fd < 10) {
3369 myfileno2 = dup_as_newfd(fd, 10);
3370 close(fd);
3371 if (myfileno2 < 0)
3372 error("Out of file descriptors");
3373 fd = myfileno2;
3374 }
3375 setinputfd(fd, push);
3376 INTON;
3377}
3378
Eric Andersencb57d552001-06-28 07:25:16 +00003379
3380static void
Eric Andersen62483552001-07-10 06:09:16 +00003381tryexec(char *cmd, char **argv, char **envp)
3382{
Eric Andersencb57d552001-06-28 07:25:16 +00003383 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003384
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003385#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Eric Andersen3102ac42001-07-06 04:26:23 +00003386 char *name = cmd;
3387 char** argv_l=argv;
3388 int argc_l;
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003389#ifdef CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
Eric Andersen3102ac42001-07-06 04:26:23 +00003390 name = get_last_path_component(name);
3391#endif
3392 argv_l=envp;
3393 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
3394 putenv(*argv_l);
3395 argv_l=argv;
Eric Andersen62483552001-07-10 06:09:16 +00003396 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
Eric Andersen3102ac42001-07-06 04:26:23 +00003397 optind = 1;
3398 run_applet_by_name(name, argc_l, argv);
3399#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003400 execve(cmd, argv, envp);
Eric Andersencb57d552001-06-28 07:25:16 +00003401 e = errno;
3402 if (e == ENOEXEC) {
3403 INTOFF;
3404 initshellproc();
3405 setinputfile(cmd, 0);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003406 commandname = arg0 = xstrdup(argv[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00003407 setparam(argv + 1);
3408 exraise(EXSHELLPROC);
3409 }
3410 errno = e;
3411}
3412
Eric Andersen2870d962001-07-02 17:27:21 +00003413static char *commandtext (const union node *);
Eric Andersencb57d552001-06-28 07:25:16 +00003414
3415/*
3416 * Do a path search. The variable path (passed by reference) should be
3417 * set to the start of the path before the first call; padvance will update
3418 * this value as it proceeds. Successive calls to padvance will return
3419 * the possible path expansions in sequence. If an option (indicated by
3420 * a percent sign) appears in the path entry then the global variable
3421 * pathopt will be set to point to it; otherwise pathopt will be set to
3422 * NULL.
3423 */
3424
3425static const char *pathopt;
3426
Eric Andersen2870d962001-07-02 17:27:21 +00003427static void growstackblock(void);
3428
3429
Eric Andersencb57d552001-06-28 07:25:16 +00003430static char *
Eric Andersen2870d962001-07-02 17:27:21 +00003431padvance(const char **path, const char *name)
3432{
Eric Andersencb57d552001-06-28 07:25:16 +00003433 const char *p;
3434 char *q;
3435 const char *start;
3436 int len;
3437
3438 if (*path == NULL)
3439 return NULL;
3440 start = *path;
3441 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
Eric Andersen2870d962001-07-02 17:27:21 +00003442 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003443 while (stackblocksize() < len)
3444 growstackblock();
3445 q = stackblock();
3446 if (p != start) {
3447 memcpy(q, start, p - start);
3448 q += p - start;
3449 *q++ = '/';
3450 }
3451 strcpy(q, name);
3452 pathopt = NULL;
3453 if (*p == '%') {
3454 pathopt = ++p;
3455 while (*p && *p != ':') p++;
3456 }
3457 if (*p == ':')
3458 *path = p + 1;
3459 else
3460 *path = NULL;
3461 return stalloc(len);
3462}
3463
Eric Andersen62483552001-07-10 06:09:16 +00003464/*
3465 * Wrapper around strcmp for qsort/bsearch/...
3466 */
3467static int
3468pstrcmp(const void *a, const void *b)
3469{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003470 return strcmp((const char *) a, (*(const char *const *) b) + 1);
Eric Andersen62483552001-07-10 06:09:16 +00003471}
3472
3473/*
3474 * Find a keyword is in a sorted array.
3475 */
3476
3477static const char *const *
3478findkwd(const char *s)
3479{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003480 return bsearch(s, tokname_array + KWDOFFSET,
3481 (sizeof(tokname_array)/sizeof(const char *)) - KWDOFFSET,
3482 sizeof(const char *), pstrcmp);
Eric Andersen62483552001-07-10 06:09:16 +00003483}
Eric Andersencb57d552001-06-28 07:25:16 +00003484
3485
3486/*** Command hashing code ***/
3487
3488
3489static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003490hashcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003491{
3492 struct tblentry **pp;
3493 struct tblentry *cmdp;
3494 int c;
3495 int verbose;
3496 struct cmdentry entry;
3497 char *name;
Eric Andersen62483552001-07-10 06:09:16 +00003498#ifdef ASH_ALIAS
3499 const struct alias *ap;
3500#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003501
3502 verbose = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003503 while ((c = nextopt("rvV")) != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00003504 if (c == 'r') {
3505 clearcmdentry(0);
3506 return 0;
Eric Andersen62483552001-07-10 06:09:16 +00003507 } else if (c == 'v' || c == 'V') {
3508 verbose = c;
Eric Andersencb57d552001-06-28 07:25:16 +00003509 }
3510 }
3511 if (*argptr == NULL) {
3512 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3513 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3514 if (cmdp->cmdtype != CMDBUILTIN) {
3515 printentry(cmdp, verbose);
3516 }
3517 }
3518 }
3519 return 0;
3520 }
3521 c = 0;
Eric Andersen62483552001-07-10 06:09:16 +00003522 while ((name = *argptr++) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00003523 if ((cmdp = cmdlookup(name, 0)) != NULL
3524 && (cmdp->cmdtype == CMDNORMAL
3525 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3526 delete_cmd_entry();
Eric Andersen62483552001-07-10 06:09:16 +00003527#ifdef ASH_ALIAS
3528 /* Then look at the aliases */
Eric Andersenec074692001-10-31 11:05:49 +00003529 if ((ap = *__lookupalias(name)) != NULL) {
Eric Andersen62483552001-07-10 06:09:16 +00003530 if (verbose=='v')
3531 printf("%s is an alias for %s\n", name, ap->val);
3532 else
3533 printalias(ap);
3534 continue;
3535 }
3536#endif
3537 /* First look at the keywords */
3538 if (findkwd(name)!=0) {
3539 if (verbose=='v')
3540 printf("%s is a shell keyword\n", name);
3541 else
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003542 puts(name);
Eric Andersen62483552001-07-10 06:09:16 +00003543 continue;
3544 }
3545
Eric Andersencb57d552001-06-28 07:25:16 +00003546 find_command(name, &entry, DO_ERR, pathval());
3547 if (entry.cmdtype == CMDUNKNOWN) c = 1;
3548 else if (verbose) {
3549 cmdp = cmdlookup(name, 0);
Eric Andersen62483552001-07-10 06:09:16 +00003550 if (cmdp) printentry(cmdp, verbose=='v');
Eric Andersencb57d552001-06-28 07:25:16 +00003551 flushall();
3552 }
Eric Andersencb57d552001-06-28 07:25:16 +00003553 }
3554 return c;
3555}
3556
Eric Andersencb57d552001-06-28 07:25:16 +00003557static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003558printentry(struct tblentry *cmdp, int verbose)
3559{
Eric Andersencb57d552001-06-28 07:25:16 +00003560 int idx;
3561 const char *path;
3562 char *name;
3563
Eric Andersen62483552001-07-10 06:09:16 +00003564 printf("%s%s", cmdp->cmdname, (verbose ? " is " : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00003565 if (cmdp->cmdtype == CMDNORMAL) {
3566 idx = cmdp->param.index;
3567 path = pathval();
3568 do {
3569 name = padvance(&path, cmdp->cmdname);
3570 stunalloc(name);
3571 } while (--idx >= 0);
Eric Andersen62483552001-07-10 06:09:16 +00003572 if(verbose)
3573 out1str(name);
Eric Andersencb57d552001-06-28 07:25:16 +00003574 } else if (cmdp->cmdtype == CMDBUILTIN) {
Eric Andersen62483552001-07-10 06:09:16 +00003575 if(verbose)
3576 out1str("a shell builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00003577 } else if (cmdp->cmdtype == CMDFUNCTION) {
Eric Andersencb57d552001-06-28 07:25:16 +00003578 if (verbose) {
3579 INTOFF;
Eric Andersen62483552001-07-10 06:09:16 +00003580 out1str("a function\n");
Eric Andersencb57d552001-06-28 07:25:16 +00003581 name = commandtext(cmdp->param.func);
Eric Andersen62483552001-07-10 06:09:16 +00003582 printf("%s() {\n %s\n}", cmdp->cmdname, name);
Eric Andersencb57d552001-06-28 07:25:16 +00003583 ckfree(name);
3584 INTON;
3585 }
3586#ifdef DEBUG
3587 } else {
3588 error("internal error: cmdtype %d", cmdp->cmdtype);
3589#endif
3590 }
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003591 puts(cmdp->rehash ? "*" : nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +00003592}
3593
3594
3595
Eric Andersen1c039232001-07-07 00:05:55 +00003596/*** List the available builtins ***/
3597
3598
3599static int helpcmd(int argc, char** argv)
3600{
3601 int col, i;
Eric Andersen1c039232001-07-07 00:05:55 +00003602
Eric Andersen62483552001-07-10 06:09:16 +00003603 printf("\nBuilt-in commands:\n-------------------\n");
3604 for (col=0, i=0; i < NUMBUILTINS; i++) {
3605 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3606 builtincmds[i].name+1);
Eric Andersen1c039232001-07-07 00:05:55 +00003607 if (col > 60) {
3608 printf("\n");
3609 col = 0;
3610 }
3611 }
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003612#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Eric Andersen1c039232001-07-07 00:05:55 +00003613 {
Eric Andersen1c039232001-07-07 00:05:55 +00003614 extern const struct BB_applet applets[];
3615 extern const size_t NUM_APPLETS;
3616
Eric Andersen62483552001-07-10 06:09:16 +00003617 for (i=0; i < NUM_APPLETS; i++) {
3618
3619 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3620 applets[i].name);
Eric Andersen1c039232001-07-07 00:05:55 +00003621 if (col > 60) {
3622 printf("\n");
3623 col = 0;
3624 }
3625 }
3626 }
3627#endif
3628 printf("\n\n");
3629 return EXIT_SUCCESS;
3630}
3631
Eric Andersencb57d552001-06-28 07:25:16 +00003632/*
3633 * Resolve a command name. If you change this routine, you may have to
3634 * change the shellexec routine as well.
3635 */
3636
Eric Andersen2870d962001-07-02 17:27:21 +00003637static int prefix (const char *, const char *);
3638
Eric Andersencb57d552001-06-28 07:25:16 +00003639static void
Eric Andersen2870d962001-07-02 17:27:21 +00003640find_command(const char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003641{
3642 struct tblentry *cmdp;
3643 int idx;
3644 int prev;
3645 char *fullname;
3646 struct stat statb;
3647 int e;
3648 int bltin;
3649 int firstchange;
3650 int updatetbl;
Eric Andersen62483552001-07-10 06:09:16 +00003651 int regular;
Eric Andersencb57d552001-06-28 07:25:16 +00003652 struct builtincmd *bcmd;
3653
3654 /* If name contains a slash, don't use the hash table */
3655 if (strchr(name, '/') != NULL) {
3656 if (act & DO_ABS) {
3657 while (stat(name, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003658 if (errno != ENOENT && errno != ENOTDIR)
3659 e = errno;
3660 entry->cmdtype = CMDUNKNOWN;
3661 entry->u.index = -1;
3662 return;
3663 }
3664 entry->cmdtype = CMDNORMAL;
3665 entry->u.index = -1;
3666 return;
3667 }
3668 entry->cmdtype = CMDNORMAL;
3669 entry->u.index = 0;
3670 return;
3671 }
3672
3673 updatetbl = 1;
3674 if (act & DO_BRUTE) {
3675 firstchange = path_change(path, &bltin);
3676 } else {
3677 bltin = builtinloc;
3678 firstchange = 9999;
3679 }
3680
3681 /* If name is in the table, and not invalidated by cd, we're done */
3682 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
3683 if (cmdp->cmdtype == CMDFUNCTION) {
3684 if (act & DO_NOFUN) {
3685 updatetbl = 0;
3686 } else {
3687 goto success;
3688 }
3689 } else if (act & DO_BRUTE) {
3690 if ((cmdp->cmdtype == CMDNORMAL &&
3691 cmdp->param.index >= firstchange) ||
3692 (cmdp->cmdtype == CMDBUILTIN &&
3693 ((builtinloc < 0 && bltin >= 0) ?
3694 bltin : builtinloc) >= firstchange)) {
3695 /* need to recompute the entry */
3696 } else {
3697 goto success;
3698 }
3699 } else {
3700 goto success;
3701 }
3702 }
3703
3704 bcmd = find_builtin(name);
Eric Andersen2870d962001-07-02 17:27:21 +00003705 regular = bcmd && IS_BUILTIN_REGULAR(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00003706
3707 if (regular) {
3708 if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) {
Eric Andersen2870d962001-07-02 17:27:21 +00003709 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003710 }
3711 } else if (act & DO_BRUTE) {
3712 if (firstchange == 0) {
3713 updatetbl = 0;
3714 }
3715 }
3716
3717 /* If %builtin not in path, check for builtin next */
3718 if (regular || (bltin < 0 && bcmd)) {
3719builtin:
3720 if (!updatetbl) {
3721 entry->cmdtype = CMDBUILTIN;
3722 entry->u.cmd = bcmd;
3723 return;
3724 }
3725 INTOFF;
3726 cmdp = cmdlookup(name, 1);
3727 cmdp->cmdtype = CMDBUILTIN;
3728 cmdp->param.cmd = bcmd;
3729 INTON;
3730 goto success;
3731 }
3732
3733 /* We have to search path. */
Eric Andersen2870d962001-07-02 17:27:21 +00003734 prev = -1; /* where to start */
3735 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00003736 if (cmdp->cmdtype == CMDBUILTIN)
3737 prev = builtinloc;
3738 else
3739 prev = cmdp->param.index;
3740 }
3741
3742 e = ENOENT;
3743 idx = -1;
3744loop:
3745 while ((fullname = padvance(&path, name)) != NULL) {
3746 stunalloc(fullname);
3747 idx++;
3748 if (idx >= firstchange) {
3749 updatetbl = 0;
3750 }
3751 if (pathopt) {
3752 if (prefix("builtin", pathopt)) {
3753 if ((bcmd = find_builtin(name))) {
3754 goto builtin;
3755 }
3756 continue;
3757 } else if (!(act & DO_NOFUN) &&
3758 prefix("func", pathopt)) {
3759 /* handled below */
3760 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00003761 continue; /* ignore unimplemented options */
Eric Andersencb57d552001-06-28 07:25:16 +00003762 }
3763 }
3764 /* if rehash, don't redo absolute path names */
3765 if (fullname[0] == '/' && idx <= prev &&
3766 idx < firstchange) {
3767 if (idx < prev)
3768 continue;
3769 TRACE(("searchexec \"%s\": no change\n", name));
3770 goto success;
3771 }
3772 while (stat(fullname, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003773 if (errno != ENOENT && errno != ENOTDIR)
3774 e = errno;
3775 goto loop;
3776 }
Eric Andersen2870d962001-07-02 17:27:21 +00003777 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00003778 if (!S_ISREG(statb.st_mode))
3779 continue;
Eric Andersen2870d962001-07-02 17:27:21 +00003780 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00003781 stalloc(strlen(fullname) + 1);
3782 readcmdfile(fullname);
3783 if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
3784 error("%s not defined in %s", name, fullname);
3785 stunalloc(fullname);
3786 goto success;
3787 }
Eric Andersencb57d552001-06-28 07:25:16 +00003788 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
3789 /* If we aren't called with DO_BRUTE and cmdp is set, it must
3790 be a function and we're being called with DO_NOFUN */
3791 if (!updatetbl) {
3792 entry->cmdtype = CMDNORMAL;
3793 entry->u.index = idx;
3794 return;
3795 }
3796 INTOFF;
3797 cmdp = cmdlookup(name, 1);
3798 cmdp->cmdtype = CMDNORMAL;
3799 cmdp->param.index = idx;
3800 INTON;
3801 goto success;
3802 }
3803
3804 /* We failed. If there was an entry for this command, delete it */
3805 if (cmdp && updatetbl)
3806 delete_cmd_entry();
3807 if (act & DO_ERR)
Eric Andersen3102ac42001-07-06 04:26:23 +00003808 out2fmt("%s: %s\n", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00003809 entry->cmdtype = CMDUNKNOWN;
3810 return;
3811
3812success:
3813 cmdp->rehash = 0;
3814 entry->cmdtype = cmdp->cmdtype;
3815 entry->u = cmdp->param;
3816}
3817
3818
3819
3820/*
3821 * Search the table of builtin commands.
3822 */
3823
Eric Andersen2870d962001-07-02 17:27:21 +00003824static int
3825bstrcmp(const void *name, const void *b)
3826{
3827 return strcmp((const char *)name, (*(const char *const *) b)+1);
3828}
3829
3830static struct builtincmd *
3831find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00003832{
3833 struct builtincmd *bp;
3834
Eric Andersen2870d962001-07-02 17:27:21 +00003835 bp = bsearch(name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd),
3836 bstrcmp
Eric Andersencb57d552001-06-28 07:25:16 +00003837 );
3838 return bp;
3839}
3840
3841
3842/*
3843 * Called when a cd is done. Marks all commands so the next time they
3844 * are executed they will be rehashed.
3845 */
3846
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003847static inline void
3848hashcd(void)
3849{
Eric Andersencb57d552001-06-28 07:25:16 +00003850 struct tblentry **pp;
3851 struct tblentry *cmdp;
3852
3853 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3854 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3855 if (cmdp->cmdtype == CMDNORMAL
3856 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
3857 cmdp->rehash = 1;
3858 }
3859 }
3860}
3861
3862
3863
3864/*
3865 * Called before PATH is changed. The argument is the new value of PATH;
3866 * pathval() still returns the old value at this point. Called with
3867 * interrupts off.
3868 */
3869
3870static void
Eric Andersen2870d962001-07-02 17:27:21 +00003871changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00003872{
3873 int firstchange;
3874 int bltin;
3875
3876 firstchange = path_change(newval, &bltin);
3877 if (builtinloc < 0 && bltin >= 0)
Eric Andersen2870d962001-07-02 17:27:21 +00003878 builtinloc = bltin; /* zap builtins */
Eric Andersencb57d552001-06-28 07:25:16 +00003879 clearcmdentry(firstchange);
3880 builtinloc = bltin;
3881}
3882
3883
3884/*
3885 * Clear out command entries. The argument specifies the first entry in
3886 * PATH which has changed.
3887 */
3888
3889static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003890clearcmdentry(int firstchange)
Eric Andersencb57d552001-06-28 07:25:16 +00003891{
3892 struct tblentry **tblp;
3893 struct tblentry **pp;
3894 struct tblentry *cmdp;
3895
3896 INTOFF;
3897 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
3898 pp = tblp;
3899 while ((cmdp = *pp) != NULL) {
3900 if ((cmdp->cmdtype == CMDNORMAL &&
3901 cmdp->param.index >= firstchange)
3902 || (cmdp->cmdtype == CMDBUILTIN &&
3903 builtinloc >= firstchange)) {
3904 *pp = cmdp->next;
3905 ckfree(cmdp);
3906 } else {
3907 pp = &cmdp->next;
3908 }
3909 }
3910 }
3911 INTON;
3912}
3913
3914
3915/*
3916 * Delete all functions.
3917 */
3918
Eric Andersencb57d552001-06-28 07:25:16 +00003919static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003920deletefuncs(void)
3921{
Eric Andersencb57d552001-06-28 07:25:16 +00003922 struct tblentry **tblp;
3923 struct tblentry **pp;
3924 struct tblentry *cmdp;
3925
3926 INTOFF;
3927 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
3928 pp = tblp;
3929 while ((cmdp = *pp) != NULL) {
3930 if (cmdp->cmdtype == CMDFUNCTION) {
3931 *pp = cmdp->next;
3932 freefunc(cmdp->param.func);
3933 ckfree(cmdp);
3934 } else {
3935 pp = &cmdp->next;
3936 }
3937 }
3938 }
3939 INTON;
3940}
3941
3942
3943
3944/*
3945 * Locate a command in the command hash table. If "add" is nonzero,
3946 * add the command to the table if it is not already present. The
3947 * variable "lastcmdentry" is set to point to the address of the link
3948 * pointing to the entry, so that delete_cmd_entry can delete the
3949 * entry.
3950 */
3951
Eric Andersen2870d962001-07-02 17:27:21 +00003952static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00003953
3954static struct tblentry *
Eric Andersen2870d962001-07-02 17:27:21 +00003955cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00003956{
3957 int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00003958 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00003959 struct tblentry *cmdp;
3960 struct tblentry **pp;
3961
3962 p = name;
3963 hashval = *p << 4;
3964 while (*p)
3965 hashval += *p++;
3966 hashval &= 0x7FFF;
3967 pp = &cmdtable[hashval % CMDTABLESIZE];
3968 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3969 if (equal(cmdp->cmdname, name))
3970 break;
3971 pp = &cmdp->next;
3972 }
3973 if (add && cmdp == NULL) {
3974 INTOFF;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003975 cmdp = *pp = xmalloc(sizeof (struct tblentry) - ARB
Eric Andersencb57d552001-06-28 07:25:16 +00003976 + strlen(name) + 1);
3977 cmdp->next = NULL;
3978 cmdp->cmdtype = CMDUNKNOWN;
3979 cmdp->rehash = 0;
3980 strcpy(cmdp->cmdname, name);
3981 INTON;
3982 }
3983 lastcmdentry = pp;
3984 return cmdp;
3985}
3986
3987/*
3988 * Delete the command entry returned on the last lookup.
3989 */
3990
3991static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003992delete_cmd_entry()
3993{
Eric Andersencb57d552001-06-28 07:25:16 +00003994 struct tblentry *cmdp;
3995
3996 INTOFF;
3997 cmdp = *lastcmdentry;
3998 *lastcmdentry = cmdp->next;
3999 ckfree(cmdp);
4000 INTON;
4001}
4002
4003
4004
Eric Andersencb57d552001-06-28 07:25:16 +00004005
4006
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004007static const unsigned char nodesize[26] = {
Eric Andersen62483552001-07-10 06:09:16 +00004008 ALIGN(sizeof (struct nbinary)),
4009 ALIGN(sizeof (struct ncmd)),
4010 ALIGN(sizeof (struct npipe)),
4011 ALIGN(sizeof (struct nredir)),
4012 ALIGN(sizeof (struct nredir)),
4013 ALIGN(sizeof (struct nredir)),
4014 ALIGN(sizeof (struct nbinary)),
4015 ALIGN(sizeof (struct nbinary)),
4016 ALIGN(sizeof (struct nif)),
4017 ALIGN(sizeof (struct nbinary)),
4018 ALIGN(sizeof (struct nbinary)),
4019 ALIGN(sizeof (struct nfor)),
4020 ALIGN(sizeof (struct ncase)),
4021 ALIGN(sizeof (struct nclist)),
4022 ALIGN(sizeof (struct narg)),
4023 ALIGN(sizeof (struct narg)),
4024 ALIGN(sizeof (struct nfile)),
4025 ALIGN(sizeof (struct nfile)),
4026 ALIGN(sizeof (struct nfile)),
4027 ALIGN(sizeof (struct nfile)),
4028 ALIGN(sizeof (struct nfile)),
4029 ALIGN(sizeof (struct ndup)),
4030 ALIGN(sizeof (struct ndup)),
4031 ALIGN(sizeof (struct nhere)),
4032 ALIGN(sizeof (struct nhere)),
4033 ALIGN(sizeof (struct nnot)),
4034};
Eric Andersencb57d552001-06-28 07:25:16 +00004035
Eric Andersencb57d552001-06-28 07:25:16 +00004036
4037
4038/*
4039 * Delete a function if it exists.
4040 */
4041
4042static void
Eric Andersen2870d962001-07-02 17:27:21 +00004043unsetfunc(char *name)
4044{
Eric Andersencb57d552001-06-28 07:25:16 +00004045 struct tblentry *cmdp;
4046
4047 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
4048 freefunc(cmdp->param.func);
4049 delete_cmd_entry();
4050 }
4051}
4052
Eric Andersen2870d962001-07-02 17:27:21 +00004053
4054/*
Eric Andersencb57d552001-06-28 07:25:16 +00004055 * Locate and print what a word is...
4056 */
4057
4058static int
Eric Andersen62483552001-07-10 06:09:16 +00004059typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004060{
4061 int i;
4062 int err = 0;
Eric Andersen62483552001-07-10 06:09:16 +00004063 char *argv_a[2];
4064
4065 argv_a[1] = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004066
4067 for (i = 1; i < argc; i++) {
Eric Andersen62483552001-07-10 06:09:16 +00004068 argv_a[0] = argv[i];
4069 argptr = argv_a;
4070 optptr = "v";
4071 err |= hashcmd(argc, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00004072 }
4073 return err;
4074}
4075
Eric Andersen2870d962001-07-02 17:27:21 +00004076#ifdef ASH_CMDCMD
Eric Andersencb57d552001-06-28 07:25:16 +00004077static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004078commandcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004079{
4080 int c;
4081 int default_path = 0;
4082 int verify_only = 0;
4083 int verbose_verify_only = 0;
4084
4085 while ((c = nextopt("pvV")) != '\0')
4086 switch (c) {
4087 case 'p':
4088 default_path = 1;
4089 break;
4090 case 'v':
4091 verify_only = 1;
4092 break;
4093 case 'V':
4094 verbose_verify_only = 1;
4095 break;
Eric Andersencb57d552001-06-28 07:25:16 +00004096 }
4097
4098 if (default_path + verify_only + verbose_verify_only > 1 ||
4099 !*argptr) {
Eric Andersen62483552001-07-10 06:09:16 +00004100 out2str(
4101 "command [-p] command [arg ...]\n"
4102 "command {-v|-V} command\n");
Eric Andersencb57d552001-06-28 07:25:16 +00004103 return EX_USAGE;
4104 }
4105
Eric Andersencb57d552001-06-28 07:25:16 +00004106 if (verify_only || verbose_verify_only) {
Eric Andersen62483552001-07-10 06:09:16 +00004107 char *argv_a[2];
4108
4109 argv_a[1] = 0;
4110 argv_a[0] = *argptr;
4111 argptr = argv_a;
4112 optptr = verbose_verify_only ? "v" : "V"; /* reverse special */
4113 return hashcmd(argc, argv);
Eric Andersencb57d552001-06-28 07:25:16 +00004114 }
Eric Andersencb57d552001-06-28 07:25:16 +00004115
4116 return 0;
4117}
Eric Andersen2870d962001-07-02 17:27:21 +00004118#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004119
4120static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004121path_change(const char *newval, int *bltin)
Eric Andersencb57d552001-06-28 07:25:16 +00004122{
4123 const char *old, *new;
4124 int idx;
4125 int firstchange;
4126
4127 old = pathval();
4128 new = newval;
Eric Andersen2870d962001-07-02 17:27:21 +00004129 firstchange = 9999; /* assume no change */
Eric Andersencb57d552001-06-28 07:25:16 +00004130 idx = 0;
4131 *bltin = -1;
4132 for (;;) {
4133 if (*old != *new) {
4134 firstchange = idx;
4135 if ((*old == '\0' && *new == ':')
4136 || (*old == ':' && *new == '\0'))
4137 firstchange++;
Eric Andersen2870d962001-07-02 17:27:21 +00004138 old = new; /* ignore subsequent differences */
Eric Andersencb57d552001-06-28 07:25:16 +00004139 }
4140 if (*new == '\0')
4141 break;
4142 if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1))
4143 *bltin = idx;
4144 if (*new == ':') {
4145 idx++;
4146 }
4147 new++, old++;
4148 }
4149 if (builtinloc >= 0 && *bltin < 0)
4150 firstchange = 0;
4151 return firstchange;
4152}
Eric Andersencb57d552001-06-28 07:25:16 +00004153/*
4154 * Routines to expand arguments to commands. We have to deal with
4155 * backquotes, shell variables, and file metacharacters.
4156 */
4157/*
4158 * _rmescape() flags
4159 */
Eric Andersen2870d962001-07-02 17:27:21 +00004160#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4161#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Eric Andersencb57d552001-06-28 07:25:16 +00004162
4163/*
4164 * Structure specifying which parts of the string should be searched
4165 * for IFS characters.
4166 */
4167
4168struct ifsregion {
Eric Andersen2870d962001-07-02 17:27:21 +00004169 struct ifsregion *next; /* next region in list */
4170 int begoff; /* offset of start of region */
4171 int endoff; /* offset of end of region */
4172 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004173};
4174
4175
Eric Andersen2870d962001-07-02 17:27:21 +00004176static char *expdest; /* output of current string */
4177static struct nodelist *argbackq; /* list of back quote expressions */
4178static struct ifsregion ifsfirst; /* first struct in list of ifs regions */
4179static struct ifsregion *ifslastp; /* last struct in list */
4180static struct arglist exparg; /* holds expanded arg list */
Eric Andersencb57d552001-06-28 07:25:16 +00004181
Eric Andersen2870d962001-07-02 17:27:21 +00004182static void argstr (char *, int);
4183static char *exptilde (char *, int);
4184static void expbackq (union node *, int, int);
4185static int subevalvar (char *, char *, int, int, int, int, int);
Eric Andersen2870d962001-07-02 17:27:21 +00004186static int varisset (char *, int);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004187static void strtodest (const char *, int, int);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004188static inline void varvalue (char *, int, int);
Eric Andersen2870d962001-07-02 17:27:21 +00004189static void recordregion (int, int, int);
4190static void removerecordregions (int);
4191static void ifsbreakup (char *, struct arglist *);
4192static void ifsfree (void);
4193static void expandmeta (struct strlist *, int);
Eric Andersen62483552001-07-10 06:09:16 +00004194#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00004195#define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB)
4196#if !defined(GLOB_BROKEN)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004197static inline void addglob (const glob_t *);
Eric Andersencb57d552001-06-28 07:25:16 +00004198#endif
4199#endif
Eric Andersen62483552001-07-10 06:09:16 +00004200#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersen2870d962001-07-02 17:27:21 +00004201static void expmeta (char *, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004202#endif
Eric Andersen62483552001-07-10 06:09:16 +00004203#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersen2870d962001-07-02 17:27:21 +00004204static struct strlist *expsort (struct strlist *);
4205static struct strlist *msort (struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004206#endif
Eric Andersen2870d962001-07-02 17:27:21 +00004207static int patmatch (char *, char *, int);
Eric Andersen62483552001-07-10 06:09:16 +00004208#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00004209static int patmatch2 (char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004210#else
Eric Andersen2870d962001-07-02 17:27:21 +00004211static int pmatch (char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004212#define patmatch2 patmatch
4213#endif
Eric Andersen2870d962001-07-02 17:27:21 +00004214static char *cvtnum (int, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004215
4216/*
4217 * Expand shell variables and backquotes inside a here document.
4218 */
4219
Eric Andersen2870d962001-07-02 17:27:21 +00004220/* arg: the document, fd: where to write the expanded version */
Eric Andersen62483552001-07-10 06:09:16 +00004221static inline void
Eric Andersen2870d962001-07-02 17:27:21 +00004222expandhere(union node *arg, int fd)
4223{
Eric Andersencb57d552001-06-28 07:25:16 +00004224 herefd = fd;
4225 expandarg(arg, (struct arglist *)NULL, 0);
4226 xwrite(fd, stackblock(), expdest - stackblock());
4227}
4228
4229
4230/*
4231 * Perform variable substitution and command substitution on an argument,
4232 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4233 * perform splitting and file name expansion. When arglist is NULL, perform
4234 * here document expansion.
4235 */
4236
4237static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004238expandarg(union node *arg, struct arglist *arglist, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004239{
4240 struct strlist *sp;
4241 char *p;
4242
4243 argbackq = arg->narg.backquote;
4244 STARTSTACKSTR(expdest);
4245 ifsfirst.next = NULL;
4246 ifslastp = NULL;
4247 argstr(arg->narg.text, flag);
4248 if (arglist == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00004249 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004250 }
4251 STPUTC('\0', expdest);
4252 p = grabstackstr(expdest);
4253 exparg.lastp = &exparg.list;
4254 /*
4255 * TODO - EXP_REDIR
4256 */
4257 if (flag & EXP_FULL) {
4258 ifsbreakup(p, &exparg);
4259 *exparg.lastp = NULL;
4260 exparg.lastp = &exparg.list;
4261 expandmeta(exparg.list, flag);
4262 } else {
4263 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4264 rmescapes(p);
4265 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4266 sp->text = p;
4267 *exparg.lastp = sp;
4268 exparg.lastp = &sp->next;
4269 }
4270 ifsfree();
4271 *exparg.lastp = NULL;
4272 if (exparg.list) {
4273 *arglist->lastp = exparg.list;
4274 arglist->lastp = exparg.lastp;
4275 }
4276}
4277
4278
Eric Andersen62483552001-07-10 06:09:16 +00004279/*
4280 * Expand a variable, and return a pointer to the next character in the
4281 * input string.
4282 */
4283
Eric Andersen74400cc2001-10-18 04:11:39 +00004284static inline char * evalvar(char *p, int flag)
Eric Andersen62483552001-07-10 06:09:16 +00004285{
4286 int subtype;
4287 int varflags;
4288 char *var;
4289 const char *val;
4290 int patloc;
4291 int c;
4292 int set;
4293 int special;
4294 int startloc;
4295 int varlen;
4296 int easy;
4297 int quotes = flag & (EXP_FULL | EXP_CASE);
4298
4299 varflags = *p++;
4300 subtype = varflags & VSTYPE;
4301 var = p;
4302 special = 0;
4303 if (! is_name(*p))
4304 special = 1;
4305 p = strchr(p, '=') + 1;
4306again: /* jump here after setting a variable with ${var=text} */
4307 if (special) {
4308 set = varisset(var, varflags & VSNUL);
4309 val = NULL;
4310 } else {
4311 val = lookupvar(var);
4312 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
4313 val = NULL;
4314 set = 0;
4315 } else
4316 set = 1;
4317 }
4318 varlen = 0;
4319 startloc = expdest - stackblock();
4320 if (set && subtype != VSPLUS) {
4321 /* insert the value of the variable */
4322 if (special) {
4323 varvalue(var, varflags & VSQUOTE, flag);
4324 if (subtype == VSLENGTH) {
4325 varlen = expdest - stackblock() - startloc;
4326 STADJUST(-varlen, expdest);
4327 }
4328 } else {
4329 if (subtype == VSLENGTH) {
4330 varlen = strlen(val);
4331 } else {
4332 strtodest(
4333 val,
4334 varflags & VSQUOTE ?
4335 DQSYNTAX : BASESYNTAX,
4336 quotes
4337 );
4338 }
4339 }
4340 }
4341
4342 if (subtype == VSPLUS)
4343 set = ! set;
4344
4345 easy = ((varflags & VSQUOTE) == 0 ||
4346 (*var == '@' && shellparam.nparam != 1));
4347
4348
4349 switch (subtype) {
4350 case VSLENGTH:
4351 expdest = cvtnum(varlen, expdest);
4352 goto record;
4353
4354 case VSNORMAL:
4355 if (!easy)
4356 break;
4357record:
4358 recordregion(startloc, expdest - stackblock(),
4359 varflags & VSQUOTE);
4360 break;
4361
4362 case VSPLUS:
4363 case VSMINUS:
4364 if (!set) {
4365 argstr(p, flag);
4366 break;
4367 }
4368 if (easy)
4369 goto record;
4370 break;
4371
4372 case VSTRIMLEFT:
4373 case VSTRIMLEFTMAX:
4374 case VSTRIMRIGHT:
4375 case VSTRIMRIGHTMAX:
4376 if (!set)
4377 break;
4378 /*
4379 * Terminate the string and start recording the pattern
4380 * right after it
4381 */
4382 STPUTC('\0', expdest);
4383 patloc = expdest - stackblock();
4384 if (subevalvar(p, NULL, patloc, subtype,
4385 startloc, varflags, quotes) == 0) {
4386 int amount = (expdest - stackblock() - patloc) + 1;
4387 STADJUST(-amount, expdest);
4388 }
4389 /* Remove any recorded regions beyond start of variable */
4390 removerecordregions(startloc);
4391 goto record;
4392
4393 case VSASSIGN:
4394 case VSQUESTION:
4395 if (!set) {
4396 if (subevalvar(p, var, 0, subtype, startloc,
4397 varflags, quotes)) {
4398 varflags &= ~VSNUL;
4399 /*
4400 * Remove any recorded regions beyond
4401 * start of variable
4402 */
4403 removerecordregions(startloc);
4404 goto again;
4405 }
4406 break;
4407 }
4408 if (easy)
4409 goto record;
4410 break;
4411
4412#ifdef DEBUG
4413 default:
4414 abort();
4415#endif
4416 }
4417
4418 if (subtype != VSNORMAL) { /* skip to end of alternative */
4419 int nesting = 1;
4420 for (;;) {
4421 if ((c = *p++) == CTLESC)
4422 p++;
4423 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
4424 if (set)
4425 argbackq = argbackq->next;
4426 } else if (c == CTLVAR) {
4427 if ((*p++ & VSTYPE) != VSNORMAL)
4428 nesting++;
4429 } else if (c == CTLENDVAR) {
4430 if (--nesting == 0)
4431 break;
4432 }
4433 }
4434 }
4435 return p;
4436}
4437
Eric Andersencb57d552001-06-28 07:25:16 +00004438
4439/*
4440 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4441 * characters to allow for further processing. Otherwise treat
4442 * $@ like $* since no splitting will be performed.
4443 */
4444
4445static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004446argstr(char *p, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004447{
4448 char c;
Eric Andersen2870d962001-07-02 17:27:21 +00004449 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
Eric Andersencb57d552001-06-28 07:25:16 +00004450 int firsteq = 1;
4451
4452 if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
4453 p = exptilde(p, flag);
4454 for (;;) {
4455 switch (c = *p++) {
4456 case '\0':
4457 case CTLENDVAR: /* ??? */
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004458 return;
Eric Andersencb57d552001-06-28 07:25:16 +00004459 case CTLQUOTEMARK:
4460 /* "$@" syntax adherence hack */
4461 if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
4462 break;
4463 if ((flag & EXP_FULL) != 0)
4464 STPUTC(c, expdest);
4465 break;
4466 case CTLESC:
4467 if (quotes)
4468 STPUTC(c, expdest);
4469 c = *p++;
4470 STPUTC(c, expdest);
4471 break;
4472 case CTLVAR:
4473 p = evalvar(p, flag);
4474 break;
4475 case CTLBACKQ:
4476 case CTLBACKQ|CTLQUOTE:
4477 expbackq(argbackq->n, c & CTLQUOTE, flag);
4478 argbackq = argbackq->next;
4479 break;
4480#ifdef ASH_MATH_SUPPORT
4481 case CTLENDARI:
4482 expari(flag);
4483 break;
Eric Andersen2870d962001-07-02 17:27:21 +00004484#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004485 case ':':
4486 case '=':
4487 /*
4488 * sort of a hack - expand tildes in variable
4489 * assignments (after the first '=' and after ':'s).
4490 */
4491 STPUTC(c, expdest);
4492 if (flag & EXP_VARTILDE && *p == '~') {
4493 if (c == '=') {
4494 if (firsteq)
4495 firsteq = 0;
4496 else
4497 break;
4498 }
4499 p = exptilde(p, flag);
4500 }
4501 break;
4502 default:
4503 STPUTC(c, expdest);
4504 }
4505 }
Eric Andersencb57d552001-06-28 07:25:16 +00004506 return;
4507}
4508
4509static char *
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004510exptilde(char *p, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004511{
4512 char c, *startp = p;
4513 struct passwd *pw;
4514 const char *home;
4515 int quotes = flag & (EXP_FULL | EXP_CASE);
4516
4517 while ((c = *p) != '\0') {
4518 switch(c) {
4519 case CTLESC:
4520 return (startp);
4521 case CTLQUOTEMARK:
4522 return (startp);
4523 case ':':
4524 if (flag & EXP_VARTILDE)
4525 goto done;
4526 break;
4527 case '/':
4528 goto done;
4529 }
4530 p++;
4531 }
4532done:
4533 *p = '\0';
4534 if (*(startp+1) == '\0') {
4535 if ((home = lookupvar("HOME")) == NULL)
4536 goto lose;
4537 } else {
4538 if ((pw = getpwnam(startp+1)) == NULL)
4539 goto lose;
4540 home = pw->pw_dir;
4541 }
4542 if (*home == '\0')
4543 goto lose;
4544 *p = c;
4545 strtodest(home, SQSYNTAX, quotes);
4546 return (p);
4547lose:
4548 *p = c;
4549 return (startp);
4550}
4551
4552
Eric Andersen2870d962001-07-02 17:27:21 +00004553static void
4554removerecordregions(int endoff)
Eric Andersencb57d552001-06-28 07:25:16 +00004555{
4556 if (ifslastp == NULL)
4557 return;
4558
4559 if (ifsfirst.endoff > endoff) {
4560 while (ifsfirst.next != NULL) {
4561 struct ifsregion *ifsp;
4562 INTOFF;
4563 ifsp = ifsfirst.next->next;
4564 ckfree(ifsfirst.next);
4565 ifsfirst.next = ifsp;
4566 INTON;
4567 }
4568 if (ifsfirst.begoff > endoff)
4569 ifslastp = NULL;
4570 else {
4571 ifslastp = &ifsfirst;
4572 ifsfirst.endoff = endoff;
4573 }
4574 return;
4575 }
Eric Andersen2870d962001-07-02 17:27:21 +00004576
Eric Andersencb57d552001-06-28 07:25:16 +00004577 ifslastp = &ifsfirst;
4578 while (ifslastp->next && ifslastp->next->begoff < endoff)
4579 ifslastp=ifslastp->next;
4580 while (ifslastp->next != NULL) {
4581 struct ifsregion *ifsp;
4582 INTOFF;
4583 ifsp = ifslastp->next->next;
4584 ckfree(ifslastp->next);
4585 ifslastp->next = ifsp;
4586 INTON;
4587 }
4588 if (ifslastp->endoff > endoff)
4589 ifslastp->endoff = endoff;
4590}
4591
4592
4593#ifdef ASH_MATH_SUPPORT
4594/*
4595 * Expand arithmetic expression. Backup to start of expression,
4596 * evaluate, place result in (backed up) result, adjust string position.
4597 */
4598static void
Eric Andersen2870d962001-07-02 17:27:21 +00004599expari(int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004600{
4601 char *p, *start;
Eric Andersen34506362001-08-02 05:02:46 +00004602 int errcode;
Eric Andersencb57d552001-06-28 07:25:16 +00004603 int result;
4604 int begoff;
4605 int quotes = flag & (EXP_FULL | EXP_CASE);
4606 int quoted;
4607
Eric Andersen2870d962001-07-02 17:27:21 +00004608 /* ifsfree(); */
Eric Andersencb57d552001-06-28 07:25:16 +00004609
4610 /*
4611 * This routine is slightly over-complicated for
4612 * efficiency. First we make sure there is
4613 * enough space for the result, which may be bigger
4614 * than the expression if we add exponentation. Next we
4615 * scan backwards looking for the start of arithmetic. If the
4616 * next previous character is a CTLESC character, then we
4617 * have to rescan starting from the beginning since CTLESC
4618 * characters have to be processed left to right.
4619 */
4620 CHECKSTRSPACE(10, expdest);
4621 USTPUTC('\0', expdest);
4622 start = stackblock();
4623 p = expdest - 1;
4624 while (*p != CTLARI && p >= start)
4625 --p;
4626 if (*p != CTLARI)
4627 error("missing CTLARI (shouldn't happen)");
4628 if (p > start && *(p-1) == CTLESC)
4629 for (p = start; *p != CTLARI; p++)
4630 if (*p == CTLESC)
4631 p++;
4632
4633 if (p[1] == '"')
4634 quoted=1;
4635 else
4636 quoted=0;
4637 begoff = p - start;
4638 removerecordregions(begoff);
4639 if (quotes)
4640 rmescapes(p+2);
Eric Andersen34506362001-08-02 05:02:46 +00004641 result = arith(p+2, &errcode);
4642 if (errcode < 0) {
4643 if(errcode == -2)
4644 error("divide by zero");
4645 else
4646 error("syntax error: \"%s\"\n", p+2);
4647 }
Eric Andersen3102ac42001-07-06 04:26:23 +00004648 snprintf(p, 12, "%d", result);
Eric Andersencb57d552001-06-28 07:25:16 +00004649
4650 while (*p++)
4651 ;
4652
4653 if (quoted == 0)
4654 recordregion(begoff, p - 1 - start, 0);
4655 result = expdest - p + 1;
4656 STADJUST(-result, expdest);
4657}
Eric Andersen2870d962001-07-02 17:27:21 +00004658#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004659
4660/*
4661 * Expand stuff in backwards quotes.
4662 */
4663
4664static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004665expbackq(union node *cmd, int quoted, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004666{
4667 volatile struct backcmd in;
4668 int i;
4669 char buf[128];
4670 char *p;
4671 char *dest = expdest;
4672 volatile struct ifsregion saveifs;
4673 struct ifsregion *volatile savelastp;
4674 struct nodelist *volatile saveargbackq;
4675 char lastc;
4676 int startloc = dest - stackblock();
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004677 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +00004678 volatile int saveherefd;
4679 int quotes = flag & (EXP_FULL | EXP_CASE);
4680 struct jmploc jmploc;
4681 struct jmploc *volatile savehandler;
4682 int ex;
4683
4684#if __GNUC__
4685 /* Avoid longjmp clobbering */
4686 (void) &dest;
4687 (void) &syntax;
4688#endif
4689
4690 in.fd = -1;
4691 in.buf = 0;
4692 in.jp = 0;
4693
4694 INTOFF;
4695 saveifs = ifsfirst;
4696 savelastp = ifslastp;
4697 saveargbackq = argbackq;
4698 saveherefd = herefd;
4699 herefd = -1;
4700 if ((ex = setjmp(jmploc.loc))) {
4701 goto err1;
4702 }
4703 savehandler = handler;
4704 handler = &jmploc;
4705 INTON;
4706 p = grabstackstr(dest);
4707 evalbackcmd(cmd, (struct backcmd *) &in);
4708 ungrabstackstr(p, dest);
4709err1:
4710 INTOFF;
4711 ifsfirst = saveifs;
4712 ifslastp = savelastp;
4713 argbackq = saveargbackq;
4714 herefd = saveherefd;
4715 if (ex) {
4716 goto err2;
4717 }
4718
4719 p = in.buf;
4720 lastc = '\0';
4721 for (;;) {
4722 if (--in.nleft < 0) {
4723 if (in.fd < 0)
4724 break;
Eric Andersen7467c8d2001-07-12 20:26:32 +00004725 i = safe_read(in.fd, buf, sizeof buf);
Eric Andersencb57d552001-06-28 07:25:16 +00004726 TRACE(("expbackq: read returns %d\n", i));
4727 if (i <= 0)
4728 break;
4729 p = buf;
4730 in.nleft = i - 1;
4731 }
4732 lastc = *p++;
4733 if (lastc != '\0') {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004734 if (quotes && SIT(lastc, syntax) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +00004735 STPUTC(CTLESC, dest);
4736 STPUTC(lastc, dest);
4737 }
4738 }
4739
4740 /* Eat all trailing newlines */
4741 for (; dest > stackblock() && dest[-1] == '\n';)
4742 STUNPUTC(dest);
4743
4744err2:
4745 if (in.fd >= 0)
4746 close(in.fd);
4747 if (in.buf)
4748 ckfree(in.buf);
4749 if (in.jp)
4750 exitstatus = waitforjob(in.jp);
4751 handler = savehandler;
4752 if (ex) {
4753 longjmp(handler->loc, 1);
4754 }
4755 if (quoted == 0)
4756 recordregion(startloc, dest - stackblock(), 0);
4757 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4758 (dest - stackblock()) - startloc,
4759 (dest - stackblock()) - startloc,
4760 stackblock() + startloc));
4761 expdest = dest;
4762 INTON;
4763}
4764
Eric Andersencb57d552001-06-28 07:25:16 +00004765static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004766subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
Eric Andersencb57d552001-06-28 07:25:16 +00004767{
4768 char *startp;
4769 char *loc = NULL;
4770 char *q;
4771 int c = 0;
4772 int saveherefd = herefd;
4773 struct nodelist *saveargbackq = argbackq;
4774 int amount;
4775
4776 herefd = -1;
4777 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
4778 STACKSTRNUL(expdest);
4779 herefd = saveherefd;
4780 argbackq = saveargbackq;
4781 startp = stackblock() + startloc;
4782 if (str == NULL)
4783 str = stackblock() + strloc;
4784
4785 switch (subtype) {
4786 case VSASSIGN:
4787 setvar(str, startp, 0);
4788 amount = startp - expdest;
4789 STADJUST(amount, expdest);
4790 varflags &= ~VSNUL;
4791 if (c != 0)
4792 *loc = c;
4793 return 1;
4794
4795 case VSQUESTION:
4796 if (*p != CTLENDVAR) {
Eric Andersen3102ac42001-07-06 04:26:23 +00004797 out2fmt(snlfmt, startp);
Eric Andersencb57d552001-06-28 07:25:16 +00004798 error((char *)NULL);
4799 }
4800 error("%.*s: parameter %snot set", p - str - 1,
4801 str, (varflags & VSNUL) ? "null or "
4802 : nullstr);
4803 /* NOTREACHED */
4804
4805 case VSTRIMLEFT:
4806 for (loc = startp; loc < str; loc++) {
4807 c = *loc;
4808 *loc = '\0';
4809 if (patmatch2(str, startp, quotes))
4810 goto recordleft;
4811 *loc = c;
4812 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00004813 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00004814 }
4815 return 0;
4816
4817 case VSTRIMLEFTMAX:
4818 for (loc = str - 1; loc >= startp;) {
4819 c = *loc;
4820 *loc = '\0';
4821 if (patmatch2(str, startp, quotes))
4822 goto recordleft;
4823 *loc = c;
4824 loc--;
4825 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
4826 for (q = startp; q < loc; q++)
4827 if (*q == CTLESC)
4828 q++;
4829 if (q > loc)
4830 loc--;
4831 }
4832 }
4833 return 0;
4834
4835 case VSTRIMRIGHT:
Eric Andersen2870d962001-07-02 17:27:21 +00004836 for (loc = str - 1; loc >= startp;) {
Eric Andersencb57d552001-06-28 07:25:16 +00004837 if (patmatch2(str, loc, quotes))
4838 goto recordright;
4839 loc--;
Eric Andersen2870d962001-07-02 17:27:21 +00004840 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
Eric Andersencb57d552001-06-28 07:25:16 +00004841 for (q = startp; q < loc; q++)
4842 if (*q == CTLESC)
4843 q++;
4844 if (q > loc)
4845 loc--;
4846 }
4847 }
4848 return 0;
4849
4850 case VSTRIMRIGHTMAX:
4851 for (loc = startp; loc < str - 1; loc++) {
4852 if (patmatch2(str, loc, quotes))
4853 goto recordright;
4854 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00004855 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00004856 }
4857 return 0;
4858
4859#ifdef DEBUG
4860 default:
4861 abort();
4862#endif
4863 }
4864
4865recordleft:
4866 *loc = c;
4867 amount = ((str - 1) - (loc - startp)) - expdest;
4868 STADJUST(amount, expdest);
4869 while (loc != str - 1)
4870 *startp++ = *loc++;
4871 return 1;
4872
4873recordright:
4874 amount = loc - expdest;
4875 STADJUST(amount, expdest);
4876 STPUTC('\0', expdest);
4877 STADJUST(-1, expdest);
4878 return 1;
4879}
4880
4881
4882/*
Eric Andersencb57d552001-06-28 07:25:16 +00004883 * Test whether a specialized variable is set.
4884 */
4885
4886static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004887varisset(char *name, int nulok)
Eric Andersencb57d552001-06-28 07:25:16 +00004888{
4889 if (*name == '!')
4890 return backgndpid != -1;
4891 else if (*name == '@' || *name == '*') {
4892 if (*shellparam.p == NULL)
4893 return 0;
4894
4895 if (nulok) {
4896 char **av;
4897
4898 for (av = shellparam.p; *av; av++)
4899 if (**av != '\0')
4900 return 1;
4901 return 0;
4902 }
4903 } else if (is_digit(*name)) {
4904 char *ap;
4905 int num = atoi(name);
4906
4907 if (num > shellparam.nparam)
4908 return 0;
4909
4910 if (num == 0)
4911 ap = arg0;
4912 else
4913 ap = shellparam.p[num - 1];
4914
4915 if (nulok && (ap == NULL || *ap == '\0'))
4916 return 0;
4917 }
4918 return 1;
4919}
4920
Eric Andersencb57d552001-06-28 07:25:16 +00004921/*
4922 * Put a string on the stack.
4923 */
4924
4925static void
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004926strtodest(const char *p, int syntax, int quotes)
Eric Andersencb57d552001-06-28 07:25:16 +00004927{
4928 while (*p) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004929 if (quotes && SIT(*p,syntax) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +00004930 STPUTC(CTLESC, expdest);
4931 STPUTC(*p++, expdest);
4932 }
4933}
4934
Eric Andersencb57d552001-06-28 07:25:16 +00004935/*
4936 * Add the value of a specialized variable to the stack string.
4937 */
4938
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004939static inline void
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004940varvalue(char *name, int quoted, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00004941{
4942 int num;
4943 char *p;
4944 int i;
4945 int sep;
4946 int sepq = 0;
4947 char **ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004948 int syntax;
Eric Andersencb57d552001-06-28 07:25:16 +00004949 int allow_split = flags & EXP_FULL;
4950 int quotes = flags & (EXP_FULL | EXP_CASE);
4951
4952 syntax = quoted ? DQSYNTAX : BASESYNTAX;
4953 switch (*name) {
4954 case '$':
4955 num = rootpid;
4956 goto numvar;
4957 case '?':
4958 num = oexitstatus;
4959 goto numvar;
4960 case '#':
4961 num = shellparam.nparam;
4962 goto numvar;
4963 case '!':
4964 num = backgndpid;
4965numvar:
4966 expdest = cvtnum(num, expdest);
4967 break;
4968 case '-':
4969 for (i = 0 ; i < NOPTS ; i++) {
Eric Andersen2870d962001-07-02 17:27:21 +00004970 if (optent_val(i))
4971 STPUTC(optent_letter(optlist[i]), expdest);
Eric Andersencb57d552001-06-28 07:25:16 +00004972 }
4973 break;
4974 case '@':
4975 if (allow_split && quoted) {
4976 sep = 1 << CHAR_BIT;
4977 goto param;
4978 }
4979 /* fall through */
4980 case '*':
4981 sep = ifsset() ? ifsval()[0] : ' ';
4982 if (quotes) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00004983 sepq = SIT(sep,syntax) == CCTL;
Eric Andersencb57d552001-06-28 07:25:16 +00004984 }
4985param:
4986 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
4987 strtodest(p, syntax, quotes);
4988 if (*ap && sep) {
4989 if (sepq)
4990 STPUTC(CTLESC, expdest);
4991 STPUTC(sep, expdest);
4992 }
4993 }
4994 break;
4995 case '0':
4996 strtodest(arg0, syntax, quotes);
4997 break;
4998 default:
4999 num = atoi(name);
5000 if (num > 0 && num <= shellparam.nparam) {
5001 strtodest(shellparam.p[num - 1], syntax, quotes);
5002 }
5003 break;
5004 }
5005}
5006
5007
Eric Andersencb57d552001-06-28 07:25:16 +00005008/*
5009 * Record the fact that we have to scan this region of the
5010 * string for IFS characters.
5011 */
5012
5013static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005014recordregion(int start, int end, int nulonly)
Eric Andersencb57d552001-06-28 07:25:16 +00005015{
5016 struct ifsregion *ifsp;
5017
5018 if (ifslastp == NULL) {
5019 ifsp = &ifsfirst;
5020 } else {
5021 INTOFF;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005022 ifsp = (struct ifsregion *)xmalloc(sizeof (struct ifsregion));
Eric Andersencb57d552001-06-28 07:25:16 +00005023 ifsp->next = NULL;
5024 ifslastp->next = ifsp;
5025 INTON;
5026 }
5027 ifslastp = ifsp;
5028 ifslastp->begoff = start;
5029 ifslastp->endoff = end;
5030 ifslastp->nulonly = nulonly;
5031}
5032
5033
5034
5035/*
5036 * Break the argument string into pieces based upon IFS and add the
5037 * strings to the argument list. The regions of the string to be
5038 * searched for IFS characters have been stored by recordregion.
5039 */
5040static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005041ifsbreakup(char *string, struct arglist *arglist)
5042{
Eric Andersencb57d552001-06-28 07:25:16 +00005043 struct ifsregion *ifsp;
5044 struct strlist *sp;
5045 char *start;
5046 char *p;
5047 char *q;
5048 const char *ifs, *realifs;
5049 int ifsspc;
5050 int nulonly;
5051
5052
5053 start = string;
5054 ifsspc = 0;
5055 nulonly = 0;
5056 realifs = ifsset() ? ifsval() : defifs;
5057 if (ifslastp != NULL) {
5058 ifsp = &ifsfirst;
5059 do {
5060 p = string + ifsp->begoff;
5061 nulonly = ifsp->nulonly;
5062 ifs = nulonly ? nullstr : realifs;
5063 ifsspc = 0;
5064 while (p < string + ifsp->endoff) {
5065 q = p;
5066 if (*p == CTLESC)
5067 p++;
5068 if (strchr(ifs, *p)) {
5069 if (!nulonly)
5070 ifsspc = (strchr(defifs, *p) != NULL);
5071 /* Ignore IFS whitespace at start */
5072 if (q == start && ifsspc) {
5073 p++;
5074 start = p;
5075 continue;
5076 }
5077 *q = '\0';
5078 sp = (struct strlist *)stalloc(sizeof *sp);
5079 sp->text = start;
5080 *arglist->lastp = sp;
5081 arglist->lastp = &sp->next;
5082 p++;
5083 if (!nulonly) {
5084 for (;;) {
5085 if (p >= string + ifsp->endoff) {
5086 break;
5087 }
5088 q = p;
5089 if (*p == CTLESC)
5090 p++;
5091 if (strchr(ifs, *p) == NULL ) {
5092 p = q;
5093 break;
5094 } else if (strchr(defifs, *p) == NULL) {
5095 if (ifsspc) {
5096 p++;
5097 ifsspc = 0;
5098 } else {
5099 p = q;
5100 break;
5101 }
5102 } else
5103 p++;
5104 }
5105 }
5106 start = p;
5107 } else
5108 p++;
5109 }
5110 } while ((ifsp = ifsp->next) != NULL);
5111 if (!(*start || (!ifsspc && start > string && nulonly))) {
5112 return;
5113 }
5114 }
5115
5116 sp = (struct strlist *)stalloc(sizeof *sp);
5117 sp->text = start;
5118 *arglist->lastp = sp;
5119 arglist->lastp = &sp->next;
5120}
5121
5122static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005123ifsfree(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005124{
5125 while (ifsfirst.next != NULL) {
5126 struct ifsregion *ifsp;
5127 INTOFF;
5128 ifsp = ifsfirst.next->next;
5129 ckfree(ifsfirst.next);
5130 ifsfirst.next = ifsp;
5131 INTON;
5132 }
5133 ifslastp = NULL;
5134 ifsfirst.next = NULL;
5135}
5136
Eric Andersen2870d962001-07-02 17:27:21 +00005137/*
5138 * Add a file name to the list.
5139 */
Eric Andersencb57d552001-06-28 07:25:16 +00005140
Eric Andersen2870d962001-07-02 17:27:21 +00005141static void
5142addfname(const char *name)
5143{
5144 char *p;
5145 struct strlist *sp;
5146
5147 p = sstrdup(name);
5148 sp = (struct strlist *)stalloc(sizeof *sp);
5149 sp->text = p;
5150 *exparg.lastp = sp;
5151 exparg.lastp = &sp->next;
5152}
Eric Andersencb57d552001-06-28 07:25:16 +00005153
5154/*
5155 * Expand shell metacharacters. At this point, the only control characters
5156 * should be escapes. The results are stored in the list exparg.
5157 */
5158
Eric Andersen62483552001-07-10 06:09:16 +00005159#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00005160static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005161expandmeta(struct strlist *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005162{
5163 const char *p;
5164 glob_t pglob;
5165 /* TODO - EXP_REDIR */
5166
5167 while (str) {
5168 if (fflag)
5169 goto nometa;
5170 p = preglob(str->text);
5171 INTOFF;
Eric Andersen34506362001-08-02 05:02:46 +00005172 switch (glob(p, 0, 0, &pglob)) {
Eric Andersencb57d552001-06-28 07:25:16 +00005173 case 0:
Eric Andersen34506362001-08-02 05:02:46 +00005174 if(pglob.gl_pathv[1]==0 && !strcmp(p, pglob.gl_pathv[0]))
Eric Andersencb57d552001-06-28 07:25:16 +00005175 goto nometa2;
5176 addglob(&pglob);
5177 globfree(&pglob);
5178 INTON;
5179 break;
5180 case GLOB_NOMATCH:
5181nometa2:
5182 globfree(&pglob);
5183 INTON;
5184nometa:
5185 *exparg.lastp = str;
5186 rmescapes(str->text);
5187 exparg.lastp = &str->next;
5188 break;
Eric Andersen2870d962001-07-02 17:27:21 +00005189 default: /* GLOB_NOSPACE */
Eric Andersencb57d552001-06-28 07:25:16 +00005190 error("Out of space");
5191 }
5192 str = str->next;
5193 }
5194}
5195
5196
5197/*
5198 * Add the result of glob(3) to the list.
5199 */
5200
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005201static inline void
5202addglob(const glob_t *pglob)
Eric Andersencb57d552001-06-28 07:25:16 +00005203{
5204 char **p = pglob->gl_pathv;
5205
5206 do {
5207 addfname(*p);
5208 } while (*++p);
5209}
5210
5211
Eric Andersen2870d962001-07-02 17:27:21 +00005212#else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005213static char *expdir;
5214
5215
5216static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005217expandmeta(struct strlist str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005218{
5219 char *p;
5220 struct strlist **savelastp;
5221 struct strlist *sp;
5222 char c;
5223 /* TODO - EXP_REDIR */
5224
5225 while (str) {
5226 if (fflag)
5227 goto nometa;
5228 p = str->text;
Eric Andersen2870d962001-07-02 17:27:21 +00005229 for (;;) { /* fast check for meta chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005230 if ((c = *p++) == '\0')
5231 goto nometa;
5232 if (c == '*' || c == '?' || c == '[' || c == '!')
5233 break;
5234 }
5235 savelastp = exparg.lastp;
5236 INTOFF;
5237 if (expdir == NULL) {
5238 int i = strlen(str->text);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005239 expdir = xmalloc(i < 2048 ? 2048 : i); /* XXX */
Eric Andersencb57d552001-06-28 07:25:16 +00005240 }
5241
5242 expmeta(expdir, str->text);
5243 ckfree(expdir);
5244 expdir = NULL;
5245 INTON;
5246 if (exparg.lastp == savelastp) {
5247 /*
5248 * no matches
5249 */
5250nometa:
5251 *exparg.lastp = str;
5252 rmescapes(str->text);
5253 exparg.lastp = &str->next;
5254 } else {
5255 *exparg.lastp = NULL;
5256 *savelastp = sp = expsort(*savelastp);
5257 while (sp->next != NULL)
5258 sp = sp->next;
5259 exparg.lastp = &sp->next;
5260 }
5261 str = str->next;
5262 }
5263}
5264
5265
5266/*
5267 * Do metacharacter (i.e. *, ?, [...]) expansion.
5268 */
5269
5270static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005271expmeta(char *enddir, char *name)
5272{
Eric Andersencb57d552001-06-28 07:25:16 +00005273 char *p;
5274 const char *cp;
5275 char *q;
5276 char *start;
5277 char *endname;
5278 int metaflag;
5279 struct stat statb;
5280 DIR *dirp;
5281 struct dirent *dp;
5282 int atend;
5283 int matchdot;
5284
5285 metaflag = 0;
5286 start = name;
5287 for (p = name ; ; p++) {
5288 if (*p == '*' || *p == '?')
5289 metaflag = 1;
5290 else if (*p == '[') {
5291 q = p + 1;
5292 if (*q == '!')
5293 q++;
5294 for (;;) {
5295 while (*q == CTLQUOTEMARK)
5296 q++;
5297 if (*q == CTLESC)
5298 q++;
5299 if (*q == '/' || *q == '\0')
5300 break;
5301 if (*++q == ']') {
5302 metaflag = 1;
5303 break;
5304 }
5305 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005306 } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) {
Eric Andersencb57d552001-06-28 07:25:16 +00005307 metaflag = 1;
5308 } else if (*p == '\0')
5309 break;
5310 else if (*p == CTLQUOTEMARK)
5311 continue;
5312 else if (*p == CTLESC)
5313 p++;
5314 if (*p == '/') {
5315 if (metaflag)
5316 break;
5317 start = p + 1;
5318 }
5319 }
Eric Andersen2870d962001-07-02 17:27:21 +00005320 if (metaflag == 0) { /* we've reached the end of the file name */
Eric Andersencb57d552001-06-28 07:25:16 +00005321 if (enddir != expdir)
5322 metaflag++;
5323 for (p = name ; ; p++) {
5324 if (*p == CTLQUOTEMARK)
5325 continue;
5326 if (*p == CTLESC)
5327 p++;
5328 *enddir++ = *p;
5329 if (*p == '\0')
5330 break;
5331 }
5332 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5333 addfname(expdir);
5334 return;
5335 }
5336 endname = p;
5337 if (start != name) {
5338 p = name;
5339 while (p < start) {
5340 while (*p == CTLQUOTEMARK)
5341 p++;
5342 if (*p == CTLESC)
5343 p++;
5344 *enddir++ = *p++;
5345 }
5346 }
5347 if (enddir == expdir) {
5348 cp = ".";
5349 } else if (enddir == expdir + 1 && *expdir == '/') {
5350 cp = "/";
5351 } else {
5352 cp = expdir;
5353 enddir[-1] = '\0';
5354 }
5355 if ((dirp = opendir(cp)) == NULL)
5356 return;
5357 if (enddir != expdir)
5358 enddir[-1] = '/';
5359 if (*endname == 0) {
5360 atend = 1;
5361 } else {
5362 atend = 0;
5363 *endname++ = '\0';
5364 }
5365 matchdot = 0;
5366 p = start;
5367 while (*p == CTLQUOTEMARK)
5368 p++;
5369 if (*p == CTLESC)
5370 p++;
5371 if (*p == '.')
5372 matchdot++;
5373 while (! int_pending() && (dp = readdir(dirp)) != NULL) {
5374 if (dp->d_name[0] == '.' && ! matchdot)
5375 continue;
5376 if (patmatch(start, dp->d_name, 0)) {
5377 if (atend) {
Eric Andersen2870d962001-07-02 17:27:21 +00005378 strcpy(enddir, dp->d_name);
Eric Andersencb57d552001-06-28 07:25:16 +00005379 addfname(expdir);
5380 } else {
5381 for (p = enddir, cp = dp->d_name;
5382 (*p++ = *cp++) != '\0';)
5383 continue;
5384 p[-1] = '/';
5385 expmeta(p, endname);
5386 }
5387 }
5388 }
5389 closedir(dirp);
5390 if (! atend)
5391 endname[-1] = '/';
5392}
Eric Andersen2870d962001-07-02 17:27:21 +00005393#endif /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005394
5395
Eric Andersencb57d552001-06-28 07:25:16 +00005396
Eric Andersen62483552001-07-10 06:09:16 +00005397#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersencb57d552001-06-28 07:25:16 +00005398/*
5399 * Sort the results of file name expansion. It calculates the number of
5400 * strings to sort and then calls msort (short for merge sort) to do the
5401 * work.
5402 */
5403
5404static struct strlist *
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005405expsort(struct strlist *str)
5406{
Eric Andersencb57d552001-06-28 07:25:16 +00005407 int len;
5408 struct strlist *sp;
5409
5410 len = 0;
5411 for (sp = str ; sp ; sp = sp->next)
5412 len++;
5413 return msort(str, len);
5414}
5415
5416
5417static struct strlist *
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005418msort(struct strlist *list, int len)
Eric Andersencb57d552001-06-28 07:25:16 +00005419{
5420 struct strlist *p, *q = NULL;
5421 struct strlist **lpp;
5422 int half;
5423 int n;
5424
5425 if (len <= 1)
5426 return list;
5427 half = len >> 1;
5428 p = list;
5429 for (n = half ; --n >= 0 ; ) {
5430 q = p;
5431 p = p->next;
5432 }
Eric Andersen2870d962001-07-02 17:27:21 +00005433 q->next = NULL; /* terminate first half of list */
5434 q = msort(list, half); /* sort first half of list */
5435 p = msort(p, len - half); /* sort second half */
Eric Andersencb57d552001-06-28 07:25:16 +00005436 lpp = &list;
5437 for (;;) {
5438 if (strcmp(p->text, q->text) < 0) {
5439 *lpp = p;
5440 lpp = &p->next;
5441 if ((p = *lpp) == NULL) {
5442 *lpp = q;
5443 break;
5444 }
5445 } else {
5446 *lpp = q;
5447 lpp = &q->next;
5448 if ((q = *lpp) == NULL) {
5449 *lpp = p;
5450 break;
5451 }
5452 }
5453 }
5454 return list;
5455}
5456#endif
5457
5458
5459
5460/*
5461 * Returns true if the pattern matches the string.
5462 */
5463
Eric Andersen62483552001-07-10 06:09:16 +00005464#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00005465/* squoted: string might have quote chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005466static int
Eric Andersen2870d962001-07-02 17:27:21 +00005467patmatch(char *pattern, char *string, int squoted)
5468{
Eric Andersencb57d552001-06-28 07:25:16 +00005469 const char *p;
5470 char *q;
5471
5472 p = preglob(pattern);
5473 q = squoted ? _rmescapes(string, RMESCAPE_ALLOC) : string;
5474
5475 return !fnmatch(p, q, 0);
5476}
5477
5478
5479static int
Eric Andersen2870d962001-07-02 17:27:21 +00005480patmatch2(char *pattern, char *string, int squoted)
5481{
Eric Andersencb57d552001-06-28 07:25:16 +00005482 char *p;
5483 int res;
5484
5485 sstrnleft--;
5486 p = grabstackstr(expdest);
5487 res = patmatch(pattern, string, squoted);
5488 ungrabstackstr(p, expdest);
5489 return res;
5490}
5491#else
5492static int
Eric Andersen2870d962001-07-02 17:27:21 +00005493patmatch(char *pattern, char *string, int squoted) {
5494 return pmatch(pattern, string, squoted);
Eric Andersencb57d552001-06-28 07:25:16 +00005495}
5496
5497
5498static int
Eric Andersen2870d962001-07-02 17:27:21 +00005499pmatch(char *pattern, char *string, int squoted)
5500{
Eric Andersencb57d552001-06-28 07:25:16 +00005501 char *p, *q;
5502 char c;
5503
5504 p = pattern;
5505 q = string;
5506 for (;;) {
5507 switch (c = *p++) {
5508 case '\0':
5509 goto breakloop;
5510 case CTLESC:
5511 if (squoted && *q == CTLESC)
5512 q++;
5513 if (*q++ != *p++)
5514 return 0;
5515 break;
5516 case CTLQUOTEMARK:
5517 continue;
5518 case '?':
5519 if (squoted && *q == CTLESC)
5520 q++;
5521 if (*q++ == '\0')
5522 return 0;
5523 break;
5524 case '*':
5525 c = *p;
5526 while (c == CTLQUOTEMARK || c == '*')
5527 c = *++p;
5528 if (c != CTLESC && c != CTLQUOTEMARK &&
5529 c != '?' && c != '*' && c != '[') {
5530 while (*q != c) {
5531 if (squoted && *q == CTLESC &&
5532 q[1] == c)
5533 break;
5534 if (*q == '\0')
5535 return 0;
5536 if (squoted && *q == CTLESC)
5537 q++;
5538 q++;
5539 }
5540 }
5541 do {
5542 if (pmatch(p, q, squoted))
5543 return 1;
5544 if (squoted && *q == CTLESC)
5545 q++;
5546 } while (*q++ != '\0');
5547 return 0;
5548 case '[': {
5549 char *endp;
5550 int invert, found;
5551 char chr;
5552
5553 endp = p;
5554 if (*endp == '!')
5555 endp++;
5556 for (;;) {
5557 while (*endp == CTLQUOTEMARK)
5558 endp++;
5559 if (*endp == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00005560 goto dft; /* no matching ] */
Eric Andersencb57d552001-06-28 07:25:16 +00005561 if (*endp == CTLESC)
5562 endp++;
5563 if (*++endp == ']')
5564 break;
5565 }
5566 invert = 0;
5567 if (*p == '!') {
5568 invert++;
5569 p++;
5570 }
5571 found = 0;
5572 chr = *q++;
5573 if (squoted && chr == CTLESC)
5574 chr = *q++;
5575 if (chr == '\0')
5576 return 0;
5577 c = *p++;
5578 do {
5579 if (c == CTLQUOTEMARK)
5580 continue;
5581 if (c == CTLESC)
5582 c = *p++;
5583 if (*p == '-' && p[1] != ']') {
5584 p++;
5585 while (*p == CTLQUOTEMARK)
5586 p++;
5587 if (*p == CTLESC)
5588 p++;
5589 if (chr >= c && chr <= *p)
5590 found = 1;
5591 p++;
5592 } else {
5593 if (chr == c)
5594 found = 1;
5595 }
5596 } while ((c = *p++) != ']');
5597 if (found == invert)
5598 return 0;
5599 break;
5600 }
Eric Andersen2870d962001-07-02 17:27:21 +00005601dft: default:
Eric Andersencb57d552001-06-28 07:25:16 +00005602 if (squoted && *q == CTLESC)
5603 q++;
5604 if (*q++ != c)
5605 return 0;
5606 break;
5607 }
5608 }
5609breakloop:
5610 if (*q != '\0')
5611 return 0;
5612 return 1;
5613}
5614#endif
5615
5616
5617
5618/*
5619 * Remove any CTLESC characters from a string.
5620 */
5621
Eric Andersen62483552001-07-10 06:09:16 +00005622#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
Eric Andersencb57d552001-06-28 07:25:16 +00005623static char *
Eric Andersen2870d962001-07-02 17:27:21 +00005624_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005625{
5626 char *p, *q, *r;
5627 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5628
5629 p = strpbrk(str, qchars);
5630 if (!p) {
5631 return str;
5632 }
5633 q = p;
5634 r = str;
5635 if (flag & RMESCAPE_ALLOC) {
5636 size_t len = p - str;
5637 q = r = stalloc(strlen(p) + len + 1);
5638 if (len > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00005639 memcpy(q, str, len);
5640 q += len;
Eric Andersencb57d552001-06-28 07:25:16 +00005641 }
5642 }
5643 while (*p) {
5644 if (*p == CTLQUOTEMARK) {
5645 p++;
5646 continue;
5647 }
5648 if (*p == CTLESC) {
5649 p++;
5650 if (flag & RMESCAPE_GLOB && *p != '/') {
5651 *q++ = '\\';
5652 }
5653 }
5654 *q++ = *p++;
5655 }
5656 *q = '\0';
5657 return r;
5658}
5659#else
5660static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005661rmescapes(char *str)
Eric Andersencb57d552001-06-28 07:25:16 +00005662{
5663 char *p, *q;
5664
5665 p = str;
5666 while (*p != CTLESC && *p != CTLQUOTEMARK) {
5667 if (*p++ == '\0')
5668 return;
5669 }
5670 q = p;
5671 while (*p) {
5672 if (*p == CTLQUOTEMARK) {
5673 p++;
5674 continue;
5675 }
5676 if (*p == CTLESC)
5677 p++;
5678 *q++ = *p++;
5679 }
5680 *q = '\0';
5681}
5682#endif
5683
5684
5685
5686/*
5687 * See if a pattern matches in a case statement.
5688 */
5689
5690static int
Eric Andersen2870d962001-07-02 17:27:21 +00005691casematch(union node *pattern, const char *val)
5692{
Eric Andersencb57d552001-06-28 07:25:16 +00005693 struct stackmark smark;
5694 int result;
5695 char *p;
5696
5697 setstackmark(&smark);
5698 argbackq = pattern->narg.backquote;
5699 STARTSTACKSTR(expdest);
5700 ifslastp = NULL;
5701 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5702 STPUTC('\0', expdest);
5703 p = grabstackstr(expdest);
Eric Andersen2870d962001-07-02 17:27:21 +00005704 result = patmatch(p, (char *)val, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00005705 popstackmark(&smark);
5706 return result;
5707}
5708
5709/*
5710 * Our own itoa().
5711 */
5712
5713static char *
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005714cvtnum(int num, char *buf)
5715{
Eric Andersencb57d552001-06-28 07:25:16 +00005716 int len;
5717
5718 CHECKSTRSPACE(32, buf);
5719 len = sprintf(buf, "%d", num);
5720 STADJUST(len, buf);
5721 return buf;
5722}
Eric Andersencb57d552001-06-28 07:25:16 +00005723/*
5724 * Editline and history functions (and glue).
5725 */
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005726static int histcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00005727{
5728 error("not compiled with history support");
5729 /* NOTREACHED */
5730}
5731
5732
Eric Andersencb57d552001-06-28 07:25:16 +00005733struct redirtab {
5734 struct redirtab *next;
Russ Dill4db35642001-07-26 05:58:40 +00005735 short renamed[10]; /* Current ash support only 0-9 descriptors */
Eric Andersen34506362001-08-02 05:02:46 +00005736 /* char on arm (and others) can't be negative */
Eric Andersencb57d552001-06-28 07:25:16 +00005737};
5738
Eric Andersen2870d962001-07-02 17:27:21 +00005739static struct redirtab *redirlist;
Eric Andersencb57d552001-06-28 07:25:16 +00005740
5741extern char **environ;
5742
5743
5744
5745/*
5746 * Initialization code.
5747 */
5748
5749static void
Eric Andersen2870d962001-07-02 17:27:21 +00005750init(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00005751
5752 /* from cd.c: */
5753 {
Eric Andersena3483db2001-10-24 08:01:06 +00005754 curdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00005755 setpwd(0, 0);
5756 }
5757
5758 /* from input.c: */
5759 {
5760 basepf.nextc = basepf.buf = basebuf;
5761 }
5762
Eric Andersencb57d552001-06-28 07:25:16 +00005763 /* from var.c: */
5764 {
5765 char **envp;
5766 char ppid[32];
5767
5768 initvar();
5769 for (envp = environ ; *envp ; envp++) {
5770 if (strchr(*envp, '=')) {
5771 setvareq(*envp, VEXPORT|VTEXTFIXED);
5772 }
5773 }
5774
Eric Andersen3102ac42001-07-06 04:26:23 +00005775 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
Eric Andersencb57d552001-06-28 07:25:16 +00005776 setvar("PPID", ppid, 0);
5777 }
5778}
5779
5780
5781
5782/*
5783 * This routine is called when an error or an interrupt occurs in an
5784 * interactive shell and control is returned to the main command loop.
5785 */
5786
Eric Andersen2870d962001-07-02 17:27:21 +00005787/* 1 == check for aliases, 2 == also check for assignments */
Eric Andersen7467c8d2001-07-12 20:26:32 +00005788static int checkalias; /* also used in no alias mode for check assignments */
Eric Andersen2870d962001-07-02 17:27:21 +00005789
Eric Andersencb57d552001-06-28 07:25:16 +00005790static void
Eric Andersen2870d962001-07-02 17:27:21 +00005791reset(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00005792
5793 /* from eval.c: */
5794 {
5795 evalskip = 0;
5796 loopnest = 0;
5797 funcnest = 0;
5798 }
5799
5800 /* from input.c: */
5801 {
5802 if (exception != EXSHELLPROC)
Eric Andersen2870d962001-07-02 17:27:21 +00005803 parselleft = parsenleft = 0; /* clear input buffer */
Eric Andersencb57d552001-06-28 07:25:16 +00005804 popallfiles();
5805 }
5806
5807 /* from parser.c: */
5808 {
5809 tokpushback = 0;
5810 checkkwd = 0;
5811 checkalias = 0;
5812 }
5813
5814 /* from redir.c: */
5815 {
5816 while (redirlist)
5817 popredir();
5818 }
5819
Eric Andersencb57d552001-06-28 07:25:16 +00005820}
5821
5822
5823
5824/*
Eric Andersencb57d552001-06-28 07:25:16 +00005825 * This file implements the input routines used by the parser.
5826 */
5827
Eric Andersenbdfd0d72001-10-24 05:00:29 +00005828#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersencb57d552001-06-28 07:25:16 +00005829static const char * cmdedit_prompt;
5830static inline void putprompt(const char *s) {
5831 cmdedit_prompt = s;
5832}
5833#else
5834static inline void putprompt(const char *s) {
5835 out2str(s);
5836}
5837#endif
5838
Eric Andersen2870d962001-07-02 17:27:21 +00005839#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
Eric Andersencb57d552001-06-28 07:25:16 +00005840
Eric Andersencb57d552001-06-28 07:25:16 +00005841
Eric Andersencb57d552001-06-28 07:25:16 +00005842
Eric Andersen2870d962001-07-02 17:27:21 +00005843/*
5844 * Same as pgetc(), but ignores PEOA.
5845 */
Eric Andersencb57d552001-06-28 07:25:16 +00005846
Eric Andersen2870d962001-07-02 17:27:21 +00005847#ifdef ASH_ALIAS
5848static int
Eric Andersen74400cc2001-10-18 04:11:39 +00005849pgetc2(void)
Eric Andersen2870d962001-07-02 17:27:21 +00005850{
5851 int c;
5852 do {
5853 c = pgetc_macro();
5854 } while (c == PEOA);
5855 return c;
Eric Andersencb57d552001-06-28 07:25:16 +00005856}
Eric Andersen2870d962001-07-02 17:27:21 +00005857#else
5858static inline int pgetc2() { return pgetc_macro(); }
Eric Andersencb57d552001-06-28 07:25:16 +00005859#endif
5860
Eric Andersencb57d552001-06-28 07:25:16 +00005861/*
5862 * Read a line from the script.
5863 */
5864
Eric Andersen62483552001-07-10 06:09:16 +00005865static inline char *
Eric Andersen2870d962001-07-02 17:27:21 +00005866pfgets(char *line, int len)
Eric Andersencb57d552001-06-28 07:25:16 +00005867{
5868 char *p = line;
5869 int nleft = len;
5870 int c;
5871
5872 while (--nleft > 0) {
5873 c = pgetc2();
5874 if (c == PEOF) {
5875 if (p == line)
5876 return NULL;
5877 break;
5878 }
5879 *p++ = c;
5880 if (c == '\n')
5881 break;
5882 }
5883 *p = '\0';
5884 return line;
5885}
5886
Eric Andersen62483552001-07-10 06:09:16 +00005887static inline int
Eric Andersen2870d962001-07-02 17:27:21 +00005888preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005889{
5890 int nr;
5891 char *buf = parsefile->buf;
5892 parsenextc = buf;
5893
5894retry:
Eric Andersenbdfd0d72001-10-24 05:00:29 +00005895#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersencb57d552001-06-28 07:25:16 +00005896 {
Eric Andersen34506362001-08-02 05:02:46 +00005897 if (!iflag || parsefile->fd)
Eric Andersen7467c8d2001-07-12 20:26:32 +00005898 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersen2870d962001-07-02 17:27:21 +00005899 else {
Eric Andersen044228d2001-07-17 01:12:36 +00005900 nr = cmdedit_read_input((char*)cmdedit_prompt, buf);
Eric Andersencb57d552001-06-28 07:25:16 +00005901 }
5902 }
5903#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00005904 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00005905#endif
5906
5907 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00005908 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
5909 int flags = fcntl(0, F_GETFL, 0);
5910 if (flags >= 0 && flags & O_NONBLOCK) {
5911 flags &=~ O_NONBLOCK;
5912 if (fcntl(0, F_SETFL, flags) >= 0) {
5913 out2str("sh: turning off NDELAY mode\n");
5914 goto retry;
5915 }
5916 }
5917 }
5918 }
5919 return nr;
5920}
5921
Eric Andersen2870d962001-07-02 17:27:21 +00005922static void
5923popstring(void)
5924{
5925 struct strpush *sp = parsefile->strpush;
5926
5927 INTOFF;
5928#ifdef ASH_ALIAS
5929 if (sp->ap) {
5930 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
5931 if (!checkalias) {
5932 checkalias = 1;
5933 }
5934 }
5935 if (sp->string != sp->ap->val) {
5936 ckfree(sp->string);
5937 }
5938
5939 sp->ap->flag &= ~ALIASINUSE;
5940 if (sp->ap->flag & ALIASDEAD) {
5941 unalias(sp->ap->name);
5942 }
5943 }
5944#endif
5945 parsenextc = sp->prevstring;
5946 parsenleft = sp->prevnleft;
5947/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
5948 parsefile->strpush = sp->prev;
5949 if (sp != &(parsefile->basestrpush))
5950 ckfree(sp);
5951 INTON;
5952}
5953
5954
Eric Andersencb57d552001-06-28 07:25:16 +00005955/*
5956 * Refill the input buffer and return the next input character:
5957 *
5958 * 1) If a string was pushed back on the input, pop it;
5959 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
5960 * from a string so we can't refill the buffer, return EOF.
5961 * 3) If the is more stuff in this buffer, use it else call read to fill it.
5962 * 4) Process input up to the next newline, deleting nul characters.
5963 */
5964
5965static int
Eric Andersen2870d962001-07-02 17:27:21 +00005966preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005967{
5968 char *p, *q;
5969 int more;
5970 char savec;
5971
5972 while (parsefile->strpush) {
Eric Andersen2870d962001-07-02 17:27:21 +00005973#ifdef ASH_ALIAS
5974 if (parsenleft == -1 && parsefile->strpush->ap &&
5975 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00005976 return PEOA;
5977 }
Eric Andersen2870d962001-07-02 17:27:21 +00005978#endif
Eric Andersencb57d552001-06-28 07:25:16 +00005979 popstring();
5980 if (--parsenleft >= 0)
5981 return (*parsenextc++);
5982 }
5983 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
5984 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00005985 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00005986
5987again:
5988 if (parselleft <= 0) {
5989 if ((parselleft = preadfd()) <= 0) {
5990 parselleft = parsenleft = EOF_NLEFT;
5991 return PEOF;
5992 }
5993 }
5994
5995 q = p = parsenextc;
5996
5997 /* delete nul characters */
5998 for (more = 1; more;) {
5999 switch (*p) {
6000 case '\0':
Eric Andersen2870d962001-07-02 17:27:21 +00006001 p++; /* Skip nul */
Eric Andersencb57d552001-06-28 07:25:16 +00006002 goto check;
6003
6004
6005 case '\n':
6006 parsenleft = q - parsenextc;
6007 more = 0; /* Stop processing here */
6008 break;
6009 }
6010
6011 *q++ = *p++;
6012check:
6013 if (--parselleft <= 0 && more) {
6014 parsenleft = q - parsenextc - 1;
6015 if (parsenleft < 0)
6016 goto again;
6017 more = 0;
6018 }
6019 }
6020
6021 savec = *q;
6022 *q = '\0';
6023
6024 if (vflag) {
6025 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00006026 }
6027
6028 *q = savec;
6029
6030 return *parsenextc++;
6031}
6032
Eric Andersencb57d552001-06-28 07:25:16 +00006033
6034/*
6035 * Push a string back onto the input at this current parsefile level.
6036 * We handle aliases this way.
6037 */
6038static void
Eric Andersen2870d962001-07-02 17:27:21 +00006039pushstring(char *s, int len, void *ap)
6040{
Eric Andersencb57d552001-06-28 07:25:16 +00006041 struct strpush *sp;
6042
6043 INTOFF;
6044/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6045 if (parsefile->strpush) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006046 sp = xmalloc(sizeof (struct strpush));
Eric Andersencb57d552001-06-28 07:25:16 +00006047 sp->prev = parsefile->strpush;
6048 parsefile->strpush = sp;
6049 } else
6050 sp = parsefile->strpush = &(parsefile->basestrpush);
6051 sp->prevstring = parsenextc;
6052 sp->prevnleft = parsenleft;
Eric Andersen2870d962001-07-02 17:27:21 +00006053#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00006054 sp->ap = (struct alias *)ap;
6055 if (ap) {
6056 ((struct alias *)ap)->flag |= ALIASINUSE;
6057 sp->string = s;
6058 }
Eric Andersen2870d962001-07-02 17:27:21 +00006059#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006060 parsenextc = s;
6061 parsenleft = len;
6062 INTON;
6063}
6064
Eric Andersencb57d552001-06-28 07:25:16 +00006065
Eric Andersencb57d552001-06-28 07:25:16 +00006066/*
6067 * Like setinputfile, but takes input from a string.
6068 */
6069
6070static void
Eric Andersen62483552001-07-10 06:09:16 +00006071setinputstring(char *string)
6072{
Eric Andersencb57d552001-06-28 07:25:16 +00006073 INTOFF;
6074 pushfile();
6075 parsenextc = string;
6076 parsenleft = strlen(string);
6077 parsefile->buf = NULL;
6078 plinno = 1;
6079 INTON;
6080}
6081
6082
6083
6084/*
6085 * To handle the "." command, a stack of input files is used. Pushfile
6086 * adds a new entry to the stack and popfile restores the previous level.
6087 */
6088
6089static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006090pushfile(void)
6091{
Eric Andersencb57d552001-06-28 07:25:16 +00006092 struct parsefile *pf;
6093
6094 parsefile->nleft = parsenleft;
6095 parsefile->lleft = parselleft;
6096 parsefile->nextc = parsenextc;
6097 parsefile->linno = plinno;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006098 pf = (struct parsefile *)xmalloc(sizeof (struct parsefile));
Eric Andersencb57d552001-06-28 07:25:16 +00006099 pf->prev = parsefile;
6100 pf->fd = -1;
6101 pf->strpush = NULL;
6102 pf->basestrpush.prev = NULL;
6103 parsefile = pf;
6104}
6105
Eric Andersen2870d962001-07-02 17:27:21 +00006106#ifdef JOBS
6107static void restartjob (struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00006108#endif
Eric Andersen2870d962001-07-02 17:27:21 +00006109static void freejob (struct job *);
6110static struct job *getjob (const char *);
6111static int dowait (int, struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00006112static void waitonint(int);
6113
6114
Eric Andersen2870d962001-07-02 17:27:21 +00006115/*
6116 * We keep track of whether or not fd0 has been redirected. This is for
6117 * background commands, where we want to redirect fd0 to /dev/null only
6118 * if it hasn't already been redirected.
6119*/
6120static int fd0_redirected = 0;
6121
6122/* Return true if fd 0 has already been redirected at least once. */
6123static inline int
Eric Andersen74400cc2001-10-18 04:11:39 +00006124fd0_redirected_p (void)
6125{
Eric Andersen2870d962001-07-02 17:27:21 +00006126 return fd0_redirected != 0;
6127}
6128
Eric Andersen62483552001-07-10 06:09:16 +00006129static void dupredirect (const union node *, int, int fd1dup);
Eric Andersen2870d962001-07-02 17:27:21 +00006130
6131#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006132/*
6133 * Turn job control on and off.
6134 *
6135 * Note: This code assumes that the third arg to ioctl is a character
6136 * pointer, which is true on Berkeley systems but not System V. Since
6137 * System V doesn't have job control yet, this isn't a problem now.
6138 */
6139
Eric Andersen2870d962001-07-02 17:27:21 +00006140
Eric Andersencb57d552001-06-28 07:25:16 +00006141
6142static void setjobctl(int enable)
6143{
6144#ifdef OLD_TTY_DRIVER
6145 int ldisc;
6146#endif
6147
6148 if (enable == jobctl || rootshell == 0)
6149 return;
6150 if (enable) {
6151 do { /* while we are in the background */
6152#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006153 if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006154#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006155 initialpgrp = tcgetpgrp(2);
Eric Andersencb57d552001-06-28 07:25:16 +00006156 if (initialpgrp < 0) {
6157#endif
Eric Andersen8c145dc2001-07-10 16:57:09 +00006158 out2str("sh: can't access tty; job control turned off\n");
Eric Andersencb57d552001-06-28 07:25:16 +00006159 mflag = 0;
6160 return;
6161 }
6162 if (initialpgrp == -1)
6163 initialpgrp = getpgrp();
6164 else if (initialpgrp != getpgrp()) {
6165 killpg(initialpgrp, SIGTTIN);
6166 continue;
6167 }
6168 } while (0);
6169#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006170 if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
Eric Andersen8c145dc2001-07-10 16:57:09 +00006171 out2str("sh: need new tty driver to run job control; job control turned off\n");
Eric Andersencb57d552001-06-28 07:25:16 +00006172 mflag = 0;
6173 return;
6174 }
6175#endif
6176 setsignal(SIGTSTP);
6177 setsignal(SIGTTOU);
6178 setsignal(SIGTTIN);
6179 setpgid(0, rootpid);
6180#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006181 ioctl(2, TIOCSPGRP, (char *)&rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00006182#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006183 tcsetpgrp(2, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00006184#endif
Eric Andersen8c145dc2001-07-10 16:57:09 +00006185 } else { /* turning job control off */
Eric Andersencb57d552001-06-28 07:25:16 +00006186 setpgid(0, initialpgrp);
6187#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006188 ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006189#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006190 tcsetpgrp(2, initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006191#endif
6192 setsignal(SIGTSTP);
6193 setsignal(SIGTTOU);
6194 setsignal(SIGTTIN);
6195 }
6196 jobctl = enable;
6197}
6198#endif
6199
6200
Eric Andersen2870d962001-07-02 17:27:21 +00006201#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006202static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006203killcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006204{
6205 int signo = -1;
6206 int list = 0;
6207 int i;
6208 pid_t pid;
6209 struct job *jp;
6210
6211 if (argc <= 1) {
6212usage:
6213 error(
6214"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6215"kill -l [exitstatus]"
6216 );
6217 }
6218
6219 if (*argv[1] == '-') {
6220 signo = decode_signal(argv[1] + 1, 1);
6221 if (signo < 0) {
6222 int c;
6223
6224 while ((c = nextopt("ls:")) != '\0')
6225 switch (c) {
6226 case 'l':
6227 list = 1;
6228 break;
6229 case 's':
6230 signo = decode_signal(optionarg, 1);
6231 if (signo < 0) {
6232 error(
6233 "invalid signal number or name: %s",
6234 optionarg
6235 );
6236 }
Eric Andersen2870d962001-07-02 17:27:21 +00006237 break;
Eric Andersencb57d552001-06-28 07:25:16 +00006238#ifdef DEBUG
6239 default:
6240 error(
6241 "nextopt returned character code 0%o", c);
6242#endif
6243 }
6244 } else
6245 argptr++;
6246 }
6247
6248 if (!list && signo < 0)
6249 signo = SIGTERM;
6250
6251 if ((signo < 0 || !*argptr) ^ list) {
6252 goto usage;
6253 }
6254
6255 if (list) {
Eric Andersen34506362001-08-02 05:02:46 +00006256 const char *name;
6257
Eric Andersencb57d552001-06-28 07:25:16 +00006258 if (!*argptr) {
6259 out1str("0\n");
6260 for (i = 1; i < NSIG; i++) {
Eric Andersen34506362001-08-02 05:02:46 +00006261 name = u_signal_names(0, &i, 1);
6262 if(name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006263 puts(name);
Eric Andersencb57d552001-06-28 07:25:16 +00006264 }
6265 return 0;
6266 }
Eric Andersen34506362001-08-02 05:02:46 +00006267 name = u_signal_names(*argptr, &signo, -1);
6268 if (name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006269 puts(name);
Eric Andersencb57d552001-06-28 07:25:16 +00006270 else
6271 error("invalid signal number or exit status: %s",
6272 *argptr);
6273 return 0;
6274 }
6275
6276 do {
6277 if (**argptr == '%') {
6278 jp = getjob(*argptr);
6279 if (jp->jobctl == 0)
6280 error("job %s not created under job control",
6281 *argptr);
6282 pid = -jp->ps[0].pid;
6283 } else
6284 pid = atoi(*argptr);
6285 if (kill(pid, signo) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00006286 error("%s: %m", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006287 } while (*++argptr);
6288
6289 return 0;
6290}
6291
6292static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006293fgcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006294{
6295 struct job *jp;
6296 int pgrp;
6297 int status;
6298
6299 jp = getjob(argv[1]);
6300 if (jp->jobctl == 0)
6301 error("job not created under job control");
6302 pgrp = jp->ps[0].pid;
6303#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006304 ioctl(2, TIOCSPGRP, (char *)&pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006305#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006306 tcsetpgrp(2, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006307#endif
6308 restartjob(jp);
6309 INTOFF;
6310 status = waitforjob(jp);
6311 INTON;
6312 return status;
6313}
6314
6315
6316static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006317bgcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006318{
6319 struct job *jp;
6320
6321 do {
6322 jp = getjob(*++argv);
6323 if (jp->jobctl == 0)
6324 error("job not created under job control");
6325 restartjob(jp);
6326 } while (--argc > 1);
6327 return 0;
6328}
6329
6330
6331static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006332restartjob(struct job *jp)
Eric Andersencb57d552001-06-28 07:25:16 +00006333{
6334 struct procstat *ps;
6335 int i;
6336
6337 if (jp->state == JOBDONE)
6338 return;
6339 INTOFF;
6340 killpg(jp->ps[0].pid, SIGCONT);
6341 for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
6342 if (WIFSTOPPED(ps->status)) {
6343 ps->status = -1;
6344 jp->state = 0;
6345 }
6346 }
6347 INTON;
6348}
6349#endif
6350
Eric Andersen2870d962001-07-02 17:27:21 +00006351static void showjobs(int change);
6352
Eric Andersencb57d552001-06-28 07:25:16 +00006353
6354static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006355jobscmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006356{
6357 showjobs(0);
6358 return 0;
6359}
6360
6361
6362/*
6363 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6364 * statuses have changed since the last call to showjobs.
6365 *
6366 * If the shell is interrupted in the process of creating a job, the
6367 * result may be a job structure containing zero processes. Such structures
6368 * will be freed here.
6369 */
6370
6371static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006372showjobs(int change)
Eric Andersencb57d552001-06-28 07:25:16 +00006373{
6374 int jobno;
6375 int procno;
6376 int i;
6377 struct job *jp;
6378 struct procstat *ps;
6379 int col;
6380 char s[64];
6381
6382 TRACE(("showjobs(%d) called\n", change));
6383 while (dowait(0, (struct job *)NULL) > 0);
6384 for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
6385 if (! jp->used)
6386 continue;
6387 if (jp->nprocs == 0) {
6388 freejob(jp);
6389 continue;
6390 }
6391 if (change && ! jp->changed)
6392 continue;
6393 procno = jp->nprocs;
Eric Andersen2870d962001-07-02 17:27:21 +00006394 for (ps = jp->ps ; ; ps++) { /* for each process */
Eric Andersencb57d552001-06-28 07:25:16 +00006395 if (ps == jp->ps)
Eric Andersen3102ac42001-07-06 04:26:23 +00006396 snprintf(s, 64, "[%d] %ld ", jobno,
Eric Andersencb57d552001-06-28 07:25:16 +00006397 (long)ps->pid);
6398 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006399 snprintf(s, 64, " %ld ",
Eric Andersencb57d552001-06-28 07:25:16 +00006400 (long)ps->pid);
6401 out1str(s);
6402 col = strlen(s);
6403 s[0] = '\0';
6404 if (ps->status == -1) {
6405 /* don't print anything */
6406 } else if (WIFEXITED(ps->status)) {
Eric Andersen3102ac42001-07-06 04:26:23 +00006407 snprintf(s, 64, "Exit %d",
Eric Andersencb57d552001-06-28 07:25:16 +00006408 WEXITSTATUS(ps->status));
6409 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00006410#ifdef JOBS
6411 if (WIFSTOPPED(ps->status))
Eric Andersencb57d552001-06-28 07:25:16 +00006412 i = WSTOPSIG(ps->status);
6413 else /* WIFSIGNALED(ps->status) */
6414#endif
6415 i = WTERMSIG(ps->status);
6416 if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
Eric Andersen2870d962001-07-02 17:27:21 +00006417 strcpy(s, sys_siglist[i & 0x7F]);
Eric Andersencb57d552001-06-28 07:25:16 +00006418 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006419 snprintf(s, 64, "Signal %d", i & 0x7F);
Eric Andersencb57d552001-06-28 07:25:16 +00006420 if (WCOREDUMP(ps->status))
6421 strcat(s, " (core dumped)");
6422 }
6423 out1str(s);
6424 col += strlen(s);
Eric Andersen62483552001-07-10 06:09:16 +00006425 printf(
Eric Andersencb57d552001-06-28 07:25:16 +00006426 "%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ',
6427 ps->cmd
6428 );
6429 if (--procno <= 0)
6430 break;
6431 }
6432 jp->changed = 0;
6433 if (jp->state == JOBDONE) {
6434 freejob(jp);
6435 }
6436 }
6437}
6438
6439
6440/*
6441 * Mark a job structure as unused.
6442 */
6443
6444static void
Eric Andersen62483552001-07-10 06:09:16 +00006445freejob(struct job *jp)
6446{
6447 const struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006448 int i;
6449
6450 INTOFF;
6451 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6452 if (ps->cmd != nullstr)
6453 ckfree(ps->cmd);
6454 }
6455 if (jp->ps != &jp->ps0)
6456 ckfree(jp->ps);
6457 jp->used = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006458#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006459 if (curjob == jp - jobtab + 1)
6460 curjob = 0;
6461#endif
6462 INTON;
6463}
6464
6465
6466
6467static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006468waitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006469{
6470 struct job *job;
6471 int status, retval;
6472 struct job *jp;
6473
6474 if (--argc > 0) {
6475start:
6476 job = getjob(*++argv);
6477 } else {
6478 job = NULL;
6479 }
Eric Andersen2870d962001-07-02 17:27:21 +00006480 for (;;) { /* loop until process terminated or stopped */
Eric Andersencb57d552001-06-28 07:25:16 +00006481 if (job != NULL) {
6482 if (job->state) {
6483 status = job->ps[job->nprocs - 1].status;
6484 if (! iflag)
6485 freejob(job);
6486 if (--argc) {
6487 goto start;
6488 }
6489 if (WIFEXITED(status))
6490 retval = WEXITSTATUS(status);
Eric Andersen2870d962001-07-02 17:27:21 +00006491#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006492 else if (WIFSTOPPED(status))
6493 retval = WSTOPSIG(status) + 128;
6494#endif
6495 else {
6496 /* XXX: limits number of signals */
6497 retval = WTERMSIG(status) + 128;
6498 }
6499 return retval;
6500 }
6501 } else {
6502 for (jp = jobtab ; ; jp++) {
Eric Andersen2870d962001-07-02 17:27:21 +00006503 if (jp >= jobtab + njobs) { /* no running procs */
Eric Andersencb57d552001-06-28 07:25:16 +00006504 return 0;
6505 }
6506 if (jp->used && jp->state == 0)
6507 break;
6508 }
6509 }
6510 if (dowait(2, 0) < 0 && errno == EINTR) {
6511 return 129;
6512 }
6513 }
6514}
6515
6516
6517
6518/*
6519 * Convert a job name to a job structure.
6520 */
6521
6522static struct job *
Eric Andersen2870d962001-07-02 17:27:21 +00006523getjob(const char *name)
6524{
Eric Andersencb57d552001-06-28 07:25:16 +00006525 int jobno;
6526 struct job *jp;
6527 int pid;
6528 int i;
6529
6530 if (name == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00006531#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006532currentjob:
6533 if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
6534 error("No current job");
6535 return &jobtab[jobno - 1];
6536#else
6537 error("No current job");
6538#endif
6539 } else if (name[0] == '%') {
6540 if (is_digit(name[1])) {
6541 jobno = number(name + 1);
6542 if (jobno > 0 && jobno <= njobs
6543 && jobtab[jobno - 1].used != 0)
6544 return &jobtab[jobno - 1];
Eric Andersen2870d962001-07-02 17:27:21 +00006545#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006546 } else if (name[1] == '%' && name[2] == '\0') {
6547 goto currentjob;
6548#endif
6549 } else {
6550 struct job *found = NULL;
6551 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
6552 if (jp->used && jp->nprocs > 0
6553 && prefix(name + 1, jp->ps[0].cmd)) {
6554 if (found)
6555 error("%s: ambiguous", name);
6556 found = jp;
6557 }
6558 }
6559 if (found)
6560 return found;
6561 }
Eric Andersen2870d962001-07-02 17:27:21 +00006562 } else if (is_number(name, &pid)) {
Eric Andersencb57d552001-06-28 07:25:16 +00006563 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
6564 if (jp->used && jp->nprocs > 0
6565 && jp->ps[jp->nprocs - 1].pid == pid)
6566 return jp;
6567 }
6568 }
6569 error("No such job: %s", name);
6570 /* NOTREACHED */
6571}
6572
6573
6574
6575/*
6576 * Return a new job structure,
6577 */
6578
Eric Andersen2870d962001-07-02 17:27:21 +00006579static struct job *
Eric Andersen62483552001-07-10 06:09:16 +00006580makejob(const union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00006581{
6582 int i;
6583 struct job *jp;
6584
6585 for (i = njobs, jp = jobtab ; ; jp++) {
6586 if (--i < 0) {
6587 INTOFF;
6588 if (njobs == 0) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006589 jobtab = xmalloc(4 * sizeof jobtab[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00006590 } else {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006591 jp = xmalloc((njobs + 4) * sizeof jobtab[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00006592 memcpy(jp, jobtab, njobs * sizeof jp[0]);
6593 /* Relocate `ps' pointers */
6594 for (i = 0; i < njobs; i++)
6595 if (jp[i].ps == &jobtab[i].ps0)
6596 jp[i].ps = &jp[i].ps0;
6597 ckfree(jobtab);
6598 jobtab = jp;
6599 }
6600 jp = jobtab + njobs;
6601 for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
6602 INTON;
6603 break;
6604 }
6605 if (jp->used == 0)
6606 break;
6607 }
6608 INTOFF;
6609 jp->state = 0;
6610 jp->used = 1;
6611 jp->changed = 0;
6612 jp->nprocs = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006613#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006614 jp->jobctl = jobctl;
6615#endif
6616 if (nprocs > 1) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006617 jp->ps = xmalloc(nprocs * sizeof (struct procstat));
Eric Andersencb57d552001-06-28 07:25:16 +00006618 } else {
6619 jp->ps = &jp->ps0;
6620 }
6621 INTON;
6622 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
6623 jp - jobtab + 1));
6624 return jp;
6625}
6626
6627
6628/*
6629 * Fork of a subshell. If we are doing job control, give the subshell its
6630 * own process group. Jp is a job structure that the job is to be added to.
6631 * N is the command that will be evaluated by the child. Both jp and n may
6632 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00006633 * FORK_FG - Fork off a foreground process.
6634 * FORK_BG - Fork off a background process.
6635 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
6636 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00006637 *
6638 * When job control is turned off, background processes have their standard
6639 * input redirected to /dev/null (except for the second and later processes
6640 * in a pipeline).
6641 */
6642
Eric Andersen2870d962001-07-02 17:27:21 +00006643
6644
Eric Andersencb57d552001-06-28 07:25:16 +00006645static int
Eric Andersen62483552001-07-10 06:09:16 +00006646forkshell(struct job *jp, const union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00006647{
6648 int pid;
Eric Andersen62483552001-07-10 06:09:16 +00006649#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006650 int pgrp;
Eric Andersen62483552001-07-10 06:09:16 +00006651#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006652 const char *devnull = _PATH_DEVNULL;
6653 const char *nullerr = "Can't open %s";
6654
6655 TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
6656 mode));
6657 INTOFF;
Eric Andersen72f9a422001-10-28 05:12:20 +00006658#if !defined(__UCLIBC__) || defined(__UCLIBC_HAS_MMU__)
Eric Andersencb57d552001-06-28 07:25:16 +00006659 pid = fork();
Eric Andersen72f9a422001-10-28 05:12:20 +00006660#else
6661 pid = vfork();
6662#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006663 if (pid == -1) {
6664 TRACE(("Fork failed, errno=%d\n", errno));
6665 INTON;
6666 error("Cannot fork");
6667 }
6668 if (pid == 0) {
6669 struct job *p;
6670 int wasroot;
6671 int i;
6672
6673 TRACE(("Child shell %d\n", getpid()));
6674 wasroot = rootshell;
6675 rootshell = 0;
6676 closescript();
6677 INTON;
6678 clear_traps();
Eric Andersen2870d962001-07-02 17:27:21 +00006679#ifdef JOBS
6680 jobctl = 0; /* do job control only in root shell */
Eric Andersencb57d552001-06-28 07:25:16 +00006681 if (wasroot && mode != FORK_NOJOB && mflag) {
6682 if (jp == NULL || jp->nprocs == 0)
6683 pgrp = getpid();
6684 else
6685 pgrp = jp->ps[0].pid;
6686 setpgid(0, pgrp);
6687 if (mode == FORK_FG) {
6688 /*** this causes superfluous TIOCSPGRPS ***/
6689#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006690 if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006691 error("TIOCSPGRP failed, errno=%d", errno);
6692#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006693 if (tcsetpgrp(2, pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006694 error("tcsetpgrp failed, errno=%d", errno);
6695#endif
6696 }
6697 setsignal(SIGTSTP);
6698 setsignal(SIGTTOU);
6699 } else if (mode == FORK_BG) {
6700 ignoresig(SIGINT);
6701 ignoresig(SIGQUIT);
6702 if ((jp == NULL || jp->nprocs == 0) &&
6703 ! fd0_redirected_p ()) {
6704 close(0);
6705 if (open(devnull, O_RDONLY) != 0)
6706 error(nullerr, devnull);
6707 }
6708 }
6709#else
6710 if (mode == FORK_BG) {
6711 ignoresig(SIGINT);
6712 ignoresig(SIGQUIT);
6713 if ((jp == NULL || jp->nprocs == 0) &&
6714 ! fd0_redirected_p ()) {
6715 close(0);
6716 if (open(devnull, O_RDONLY) != 0)
6717 error(nullerr, devnull);
6718 }
6719 }
6720#endif
6721 for (i = njobs, p = jobtab ; --i >= 0 ; p++)
6722 if (p->used)
6723 freejob(p);
6724 if (wasroot && iflag) {
6725 setsignal(SIGINT);
6726 setsignal(SIGQUIT);
6727 setsignal(SIGTERM);
6728 }
6729 return pid;
6730 }
Eric Andersen62483552001-07-10 06:09:16 +00006731#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006732 if (rootshell && mode != FORK_NOJOB && mflag) {
6733 if (jp == NULL || jp->nprocs == 0)
6734 pgrp = pid;
6735 else
6736 pgrp = jp->ps[0].pid;
6737 setpgid(pid, pgrp);
6738 }
Eric Andersen62483552001-07-10 06:09:16 +00006739#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006740 if (mode == FORK_BG)
Eric Andersen2870d962001-07-02 17:27:21 +00006741 backgndpid = pid; /* set $! */
Eric Andersencb57d552001-06-28 07:25:16 +00006742 if (jp) {
6743 struct procstat *ps = &jp->ps[jp->nprocs++];
6744 ps->pid = pid;
6745 ps->status = -1;
6746 ps->cmd = nullstr;
6747 if (iflag && rootshell && n)
6748 ps->cmd = commandtext(n);
6749 }
6750 INTON;
6751 TRACE(("In parent shell: child = %d\n", pid));
6752 return pid;
6753}
6754
6755
6756
6757/*
6758 * Wait for job to finish.
6759 *
6760 * Under job control we have the problem that while a child process is
6761 * running interrupts generated by the user are sent to the child but not
6762 * to the shell. This means that an infinite loop started by an inter-
6763 * active user may be hard to kill. With job control turned off, an
6764 * interactive user may place an interactive program inside a loop. If
6765 * the interactive program catches interrupts, the user doesn't want
6766 * these interrupts to also abort the loop. The approach we take here
6767 * is to have the shell ignore interrupt signals while waiting for a
6768 * forground process to terminate, and then send itself an interrupt
6769 * signal if the child process was terminated by an interrupt signal.
6770 * Unfortunately, some programs want to do a bit of cleanup and then
6771 * exit on interrupt; unless these processes terminate themselves by
6772 * sending a signal to themselves (instead of calling exit) they will
6773 * confuse this approach.
6774 */
6775
6776static int
Eric Andersen62483552001-07-10 06:09:16 +00006777waitforjob(struct job *jp)
6778{
Eric Andersen2870d962001-07-02 17:27:21 +00006779#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006780 int mypgrp = getpgrp();
6781#endif
6782 int status;
6783 int st;
6784 struct sigaction act, oact;
6785
6786 INTOFF;
6787 intreceived = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006788#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006789 if (!jobctl) {
6790#else
6791 if (!iflag) {
6792#endif
6793 sigaction(SIGINT, 0, &act);
6794 act.sa_handler = waitonint;
6795 sigaction(SIGINT, &act, &oact);
6796 }
6797 TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
6798 while (jp->state == 0) {
6799 dowait(1, jp);
6800 }
Eric Andersen2870d962001-07-02 17:27:21 +00006801#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006802 if (!jobctl) {
6803#else
6804 if (!iflag) {
6805#endif
6806 sigaction(SIGINT, &oact, 0);
6807 if (intreceived && trap[SIGINT]) kill(getpid(), SIGINT);
6808 }
Eric Andersen2870d962001-07-02 17:27:21 +00006809#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006810 if (jp->jobctl) {
6811#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006812 if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006813 error("TIOCSPGRP failed, errno=%d\n", errno);
6814#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006815 if (tcsetpgrp(2, mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006816 error("tcsetpgrp failed, errno=%d\n", errno);
6817#endif
6818 }
6819 if (jp->state == JOBSTOPPED)
6820 curjob = jp - jobtab + 1;
6821#endif
6822 status = jp->ps[jp->nprocs - 1].status;
6823 /* convert to 8 bits */
6824 if (WIFEXITED(status))
6825 st = WEXITSTATUS(status);
Eric Andersen2870d962001-07-02 17:27:21 +00006826#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006827 else if (WIFSTOPPED(status))
6828 st = WSTOPSIG(status) + 128;
6829#endif
6830 else
6831 st = WTERMSIG(status) + 128;
Eric Andersen2870d962001-07-02 17:27:21 +00006832#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006833 if (jp->jobctl) {
6834 /*
6835 * This is truly gross.
6836 * If we're doing job control, then we did a TIOCSPGRP which
6837 * caused us (the shell) to no longer be in the controlling
6838 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
6839 * intuit from the subprocess exit status whether a SIGINT
6840 * occured, and if so interrupt ourselves. Yuck. - mycroft
6841 */
6842 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
6843 raise(SIGINT);
6844 }
Eric Andersen2870d962001-07-02 17:27:21 +00006845 if (jp->state == JOBDONE)
6846
Eric Andersencb57d552001-06-28 07:25:16 +00006847#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006848 freejob(jp);
6849 INTON;
6850 return st;
6851}
6852
6853
6854
6855/*
6856 * Wait for a process to terminate.
6857 */
6858
Eric Andersen62483552001-07-10 06:09:16 +00006859/*
6860 * Do a wait system call. If job control is compiled in, we accept
6861 * stopped processes. If block is zero, we return a value of zero
6862 * rather than blocking.
6863 *
6864 * System V doesn't have a non-blocking wait system call. It does
6865 * have a SIGCLD signal that is sent to a process when one of it's
6866 * children dies. The obvious way to use SIGCLD would be to install
6867 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
6868 * was received, and have waitproc bump another counter when it got
6869 * the status of a process. Waitproc would then know that a wait
6870 * system call would not block if the two counters were different.
6871 * This approach doesn't work because if a process has children that
6872 * have not been waited for, System V will send it a SIGCLD when it
6873 * installs a signal handler for SIGCLD. What this means is that when
6874 * a child exits, the shell will be sent SIGCLD signals continuously
6875 * until is runs out of stack space, unless it does a wait call before
6876 * restoring the signal handler. The code below takes advantage of
6877 * this (mis)feature by installing a signal handler for SIGCLD and
6878 * then checking to see whether it was called. If there are any
6879 * children to be waited for, it will be.
6880 *
6881 */
6882
6883static inline int
6884waitproc(int block, int *status)
6885{
6886 int flags;
6887
6888 flags = 0;
6889#ifdef JOBS
6890 if (jobctl)
6891 flags |= WUNTRACED;
6892#endif
6893 if (block == 0)
6894 flags |= WNOHANG;
6895 return wait3(status, flags, (struct rusage *)NULL);
6896}
6897
Eric Andersencb57d552001-06-28 07:25:16 +00006898static int
Eric Andersen62483552001-07-10 06:09:16 +00006899dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00006900{
6901 int pid;
6902 int status;
6903 struct procstat *sp;
6904 struct job *jp;
6905 struct job *thisjob;
6906 int done;
6907 int stopped;
6908 int core;
6909 int sig;
6910
6911 TRACE(("dowait(%d) called\n", block));
6912 do {
6913 pid = waitproc(block, &status);
6914 TRACE(("wait returns %d, status=%d\n", pid, status));
6915 } while (!(block & 2) && pid == -1 && errno == EINTR);
6916 if (pid <= 0)
6917 return pid;
6918 INTOFF;
6919 thisjob = NULL;
6920 for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
6921 if (jp->used) {
6922 done = 1;
6923 stopped = 1;
6924 for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
6925 if (sp->pid == -1)
6926 continue;
6927 if (sp->pid == pid) {
6928 TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
6929 sp->status = status;
6930 thisjob = jp;
6931 }
6932 if (sp->status == -1)
6933 stopped = 0;
6934 else if (WIFSTOPPED(sp->status))
6935 done = 0;
6936 }
Eric Andersen2870d962001-07-02 17:27:21 +00006937 if (stopped) { /* stopped or done */
Eric Andersencb57d552001-06-28 07:25:16 +00006938 int state = done? JOBDONE : JOBSTOPPED;
6939 if (jp->state != state) {
6940 TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
6941 jp->state = state;
Eric Andersen2870d962001-07-02 17:27:21 +00006942#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006943 if (done && curjob == jp - jobtab + 1)
Eric Andersen2870d962001-07-02 17:27:21 +00006944 curjob = 0; /* no current job */
Eric Andersencb57d552001-06-28 07:25:16 +00006945#endif
6946 }
6947 }
6948 }
6949 }
6950 INTON;
6951 if (! rootshell || ! iflag || (job && thisjob == job)) {
6952 core = WCOREDUMP(status);
Eric Andersen2870d962001-07-02 17:27:21 +00006953#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006954 if (WIFSTOPPED(status)) sig = WSTOPSIG(status);
6955 else
6956#endif
6957 if (WIFEXITED(status)) sig = 0;
6958 else sig = WTERMSIG(status);
6959
6960 if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
6961 if (thisjob != job)
Eric Andersen3102ac42001-07-06 04:26:23 +00006962 out2fmt("%d: ", pid);
Eric Andersen2870d962001-07-02 17:27:21 +00006963#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006964 if (sig == SIGTSTP && rootshell && iflag)
Eric Andersen3102ac42001-07-06 04:26:23 +00006965 out2fmt("%%%ld ",
Eric Andersencb57d552001-06-28 07:25:16 +00006966 (long)(job - jobtab + 1));
6967#endif
6968 if (sig < NSIG && sys_siglist[sig])
6969 out2str(sys_siglist[sig]);
6970 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006971 out2fmt("Signal %d", sig);
Eric Andersencb57d552001-06-28 07:25:16 +00006972 if (core)
6973 out2str(" - core dumped");
6974 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00006975 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00006976 TRACE(("Not printing status: status=%d, sig=%d\n",
Eric Andersencb57d552001-06-28 07:25:16 +00006977 status, sig));
6978 }
6979 } else {
6980 TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
6981 if (thisjob)
6982 thisjob->changed = 1;
6983 }
6984 return pid;
6985}
6986
6987
6988
Eric Andersencb57d552001-06-28 07:25:16 +00006989
6990/*
6991 * return 1 if there are stopped jobs, otherwise 0
6992 */
Eric Andersencb57d552001-06-28 07:25:16 +00006993static int
Eric Andersen2870d962001-07-02 17:27:21 +00006994stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006995{
6996 int jobno;
6997 struct job *jp;
6998
6999 if (job_warning)
7000 return (0);
7001 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
7002 if (jp->used == 0)
7003 continue;
7004 if (jp->state == JOBSTOPPED) {
7005 out2str("You have stopped jobs.\n");
7006 job_warning = 2;
7007 return (1);
7008 }
7009 }
7010
7011 return (0);
7012}
7013
7014/*
7015 * Return a string identifying a command (to be printed by the
7016 * jobs command.
7017 */
7018
7019static char *cmdnextc;
7020static int cmdnleft;
Eric Andersen2870d962001-07-02 17:27:21 +00007021#define MAXCMDTEXT 200
Eric Andersencb57d552001-06-28 07:25:16 +00007022
Eric Andersen2870d962001-07-02 17:27:21 +00007023static void
7024cmdputs(const char *s)
7025{
7026 const char *p;
7027 char *q;
7028 char c;
7029 int subtype = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007030
Eric Andersen2870d962001-07-02 17:27:21 +00007031 if (cmdnleft <= 0)
7032 return;
7033 p = s;
7034 q = cmdnextc;
7035 while ((c = *p++) != '\0') {
7036 if (c == CTLESC)
7037 *q++ = *p++;
7038 else if (c == CTLVAR) {
7039 *q++ = '$';
7040 if (--cmdnleft > 0)
7041 *q++ = '{';
7042 subtype = *p++;
7043 } else if (c == '=' && subtype != 0) {
7044 *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
7045 subtype = 0;
7046 } else if (c == CTLENDVAR) {
7047 *q++ = '}';
7048 } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
7049 cmdnleft++; /* ignore it */
7050 else
7051 *q++ = c;
7052 if (--cmdnleft <= 0) {
7053 *q++ = '.';
7054 *q++ = '.';
7055 *q++ = '.';
7056 break;
7057 }
7058 }
7059 cmdnextc = q;
Eric Andersencb57d552001-06-28 07:25:16 +00007060}
7061
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00007062#define CMDTXT_TABLE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007063#ifdef CMDTXT_TABLE
7064/*
7065 * To collect a lot of redundant code in cmdtxt() case statements, we
7066 * implement a mini language here. Each type of node struct has an
7067 * associated instruction sequence that operates on its members via
7068 * their offsets. The instruction are pack in unsigned chars with
7069 * format IIDDDDDE where the bits are
7070 * I : part of the instruction opcode, which are
7071 * 00 : member is a pointer to another node -- process it recursively
7072 * 40 : member is a pointer to a char string -- output it
7073 * 80 : output the string whose index is stored in the data field
7074 * CC : flag signaling that this case needs external processing
7075 * D : data - either the (shifted) index of a fixed string to output or
7076 * the actual offset of the member to operate on in the struct
7077 * (since we assume bit 0 is set, the offset is not shifted)
7078 * E : flag signaling end of instruction sequence
7079 *
7080 * WARNING: In order to handle larger offsets for 64bit archs, this code
7081 * assumes that no offset can be an odd number and stores the
7082 * end-of-instructions flag in bit 0.
7083 */
Eric Andersencb57d552001-06-28 07:25:16 +00007084
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007085#define CMDTXT_NOMORE 0x01 /* NOTE: no offset should be odd */
7086#define CMDTXT_CHARPTR 0x40
7087#define CMDTXT_STRING 0x80
7088#define CMDTXT_SPECIAL 0xC0
7089#define CMDTXT_OFFSETMASK 0x3E
7090
7091static const char * const cmdtxt_strings[] = {
7092 /* 0 1 2 3 4 5 6 7 */
7093 "; ", "(", ")", " && ", " || ", "if ", "; then ", "...",
7094 /* 8 9 10 11 12 13 */
7095 "while ", "; do ", "; done", "until ", "for ", " in ...",
7096 /* 14 15 16 17 */
7097 "case ", "???", "() ...", "<<..."
7098};
7099
7100static const char * const redir_strings[] = {
7101 ">", "<", "<>", ">>", ">|", ">&", "<&"
7102};
7103
7104static const unsigned char cmdtxt_ops[] = {
7105#define CMDTXT_NSEMI 0
7106 offsetof(union node, nbinary.ch1),
7107 0|CMDTXT_STRING,
7108 offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7109#define CMDTXT_NCMD (CMDTXT_NSEMI + 3)
7110#define CMDTXT_NPIPE (CMDTXT_NCMD)
7111#define CMDTXT_NCASE (CMDTXT_NCMD)
7112#define CMDTXT_NTO (CMDTXT_NCMD)
7113#define CMDTXT_NFROM (CMDTXT_NCMD)
7114#define CMDTXT_NFROMTO (CMDTXT_NCMD)
7115#define CMDTXT_NAPPEND (CMDTXT_NCMD)
7116#define CMDTXT_NTOOV (CMDTXT_NCMD)
7117#define CMDTXT_NTOFD (CMDTXT_NCMD)
7118#define CMDTXT_NFROMFD (CMDTXT_NCMD)
7119 CMDTXT_SPECIAL,
7120#define CMDTXT_NREDIR (CMDTXT_NPIPE + 1)
7121#define CMDTXT_NBACKGND (CMDTXT_NREDIR)
7122 offsetof(union node, nredir.n)|CMDTXT_NOMORE,
7123#define CMDTXT_NSUBSHELL (CMDTXT_NBACKGND + 1)
7124 (1*2)|CMDTXT_STRING,
7125 offsetof(union node, nredir.n),
7126 (2*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7127#define CMDTXT_NAND (CMDTXT_NSUBSHELL + 3)
7128 offsetof(union node, nbinary.ch1),
7129 (3*2)|CMDTXT_STRING,
7130 offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7131#define CMDTXT_NOR (CMDTXT_NAND + 3)
7132 offsetof(union node, nbinary.ch1),
7133 (4*2)|CMDTXT_STRING,
7134 offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7135#define CMDTXT_NIF (CMDTXT_NOR + 3)
7136 (5*2)|CMDTXT_STRING,
7137 offsetof(union node, nif.test),
7138 (6*2)|CMDTXT_STRING,
7139 offsetof(union node, nif.ifpart),
7140 (7*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7141#define CMDTXT_NWHILE (CMDTXT_NIF + 5)
7142 (8*2)|CMDTXT_STRING,
7143 offsetof(union node, nbinary.ch1),
7144 (9*2)|CMDTXT_STRING,
7145 offsetof(union node, nbinary.ch2),
7146 (10*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7147#define CMDTXT_NUNTIL (CMDTXT_NWHILE + 5)
7148 (11*2)|CMDTXT_STRING,
7149 offsetof(union node, nbinary.ch1),
7150 (9*2)|CMDTXT_STRING,
7151 offsetof(union node, nbinary.ch2),
7152 (10*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7153#define CMDTXT_NFOR (CMDTXT_NUNTIL + 5)
7154 (12*2)|CMDTXT_STRING,
7155 offsetof(union node, nfor.var)|CMDTXT_CHARPTR,
7156 (13*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7157#define CMDTXT_NCLIST (CMDTXT_NFOR + 3) /* TODO: IS THIS CORRECT??? */
7158#define CMDTXT_NNOT (CMDTXT_NCLIST) /* TODO: IS THIS CORRECT??? */
7159 (15*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7160#define CMDTXT_NDEFUN (CMDTXT_NCLIST + 1)
7161 offsetof(union node, narg.text)|CMDTXT_CHARPTR,
7162 (16*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7163#define CMDTXT_NARG (CMDTXT_NDEFUN + 2)
7164 offsetof(union node, narg.text)|CMDTXT_CHARPTR|CMDTXT_NOMORE,
7165#define CMDTXT_NHERE (CMDTXT_NARG + 1)
7166#define CMDTXT_NXHERE (CMDTXT_NHERE)
7167 (17*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7168};
7169
7170#if CMDTXT_NXHERE != 36
7171#error CMDTXT_NXHERE
7172#endif
7173
7174static const unsigned char cmdtxt_ops_index[26] = {
7175 CMDTXT_NSEMI,
7176 CMDTXT_NCMD,
7177 CMDTXT_NPIPE,
7178 CMDTXT_NREDIR,
7179 CMDTXT_NBACKGND,
7180 CMDTXT_NSUBSHELL,
7181 CMDTXT_NAND,
7182 CMDTXT_NOR,
7183 CMDTXT_NIF,
7184 CMDTXT_NWHILE,
7185 CMDTXT_NUNTIL,
7186 CMDTXT_NFOR,
7187 CMDTXT_NCASE,
7188 CMDTXT_NCLIST,
7189 CMDTXT_NDEFUN,
7190 CMDTXT_NARG,
7191 CMDTXT_NTO,
7192 CMDTXT_NFROM,
7193 CMDTXT_NFROMTO,
7194 CMDTXT_NAPPEND,
7195 CMDTXT_NTOOV,
7196 CMDTXT_NTOFD,
7197 CMDTXT_NFROMFD,
7198 CMDTXT_NHERE,
7199 CMDTXT_NXHERE,
7200 CMDTXT_NNOT,
7201};
7202
7203static void
7204cmdtxt(const union node *n)
7205{
7206 const char *p;
7207
7208 if (n == NULL)
7209 return;
7210
7211 p = cmdtxt_ops + (int) cmdtxt_ops_index[n->type];
7212 if ((*p & CMDTXT_SPECIAL) != CMDTXT_SPECIAL) { /* normal case */
7213 do {
7214 if (*p & CMDTXT_STRING) { /* output fixed string */
7215 cmdputs(cmdtxt_strings[((int)(*p & CMDTXT_OFFSETMASK) >> 1)]);
Manuel Novoa III c639a352001-08-12 17:32:56 +00007216 } else {
7217 const char *pf = ((const char *) n)
7218 + ((int)(*p & CMDTXT_OFFSETMASK));
7219 if (*p & CMDTXT_CHARPTR) { /* output dynamic string */
7220 cmdputs(*((const char **) pf));
7221 } else { /* output field */
7222 cmdtxt(*((const union node **) pf));
7223 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007224 }
7225 } while (!(*p++ & CMDTXT_NOMORE));
7226 } else if (n->type == NCMD) {
7227 union node *np;
7228 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7229 cmdtxt(np);
7230 if (np->narg.next)
7231 cmdputs(spcstr);
7232 }
7233 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7234 cmdputs(spcstr);
7235 cmdtxt(np);
7236 }
7237 } else if (n->type == NPIPE) {
7238 struct nodelist *lp;
7239 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7240 cmdtxt(lp->n);
7241 if (lp->next)
7242 cmdputs(" | ");
7243 }
7244 } else if (n->type == NCASE) {
7245 cmdputs(cmdtxt_strings[14]);
7246 cmdputs(n->ncase.expr->narg.text);
7247 cmdputs(cmdtxt_strings[13]);
7248 } else {
7249#if (NTO != 16) || (NFROM != 17) || (NFROMTO != 18) || (NAPPEND != 19) || (NTOOV != 20) || (NTOFD != 21) || (NFROMFD != 22)
7250#error Assumption violated regarding range and ordering of NTO ... NFROMFD!
7251#endif
7252 char s[2];
7253
7254#ifdef DEBUG
7255 assert((n->type >= NTO) && (n->type <= NFROMFD));
7256#endif
7257
7258 p = redir_strings[n->type - NTO];
7259 if (n->nfile.fd != ('>' == *p)) {
7260 s[0] = n->nfile.fd + '0';
7261 s[1] = '\0';
7262 cmdputs(s);
7263 }
7264 cmdputs(p);
7265 if (n->type >= NTOFD) {
7266 s[0] = n->ndup.dupfd + '0';
7267 s[1] = '\0';
7268 cmdputs(s);
7269 } else {
7270 cmdtxt(n->nfile.fname);
7271 }
7272 }
7273}
7274#else /* CMDTXT_TABLE */
Eric Andersencb57d552001-06-28 07:25:16 +00007275static void
Eric Andersen2870d962001-07-02 17:27:21 +00007276cmdtxt(const union node *n)
7277{
Eric Andersencb57d552001-06-28 07:25:16 +00007278 union node *np;
7279 struct nodelist *lp;
7280 const char *p;
7281 int i;
7282 char s[2];
7283
7284 if (n == NULL)
7285 return;
7286 switch (n->type) {
7287 case NSEMI:
7288 cmdtxt(n->nbinary.ch1);
7289 cmdputs("; ");
7290 cmdtxt(n->nbinary.ch2);
7291 break;
7292 case NAND:
7293 cmdtxt(n->nbinary.ch1);
7294 cmdputs(" && ");
7295 cmdtxt(n->nbinary.ch2);
7296 break;
7297 case NOR:
7298 cmdtxt(n->nbinary.ch1);
7299 cmdputs(" || ");
7300 cmdtxt(n->nbinary.ch2);
7301 break;
7302 case NPIPE:
7303 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7304 cmdtxt(lp->n);
7305 if (lp->next)
7306 cmdputs(" | ");
7307 }
7308 break;
7309 case NSUBSHELL:
7310 cmdputs("(");
7311 cmdtxt(n->nredir.n);
7312 cmdputs(")");
7313 break;
7314 case NREDIR:
7315 case NBACKGND:
7316 cmdtxt(n->nredir.n);
7317 break;
7318 case NIF:
7319 cmdputs("if ");
7320 cmdtxt(n->nif.test);
7321 cmdputs("; then ");
7322 cmdtxt(n->nif.ifpart);
7323 cmdputs("...");
7324 break;
7325 case NWHILE:
7326 cmdputs("while ");
7327 goto until;
7328 case NUNTIL:
7329 cmdputs("until ");
7330until:
7331 cmdtxt(n->nbinary.ch1);
7332 cmdputs("; do ");
7333 cmdtxt(n->nbinary.ch2);
7334 cmdputs("; done");
7335 break;
7336 case NFOR:
7337 cmdputs("for ");
7338 cmdputs(n->nfor.var);
7339 cmdputs(" in ...");
7340 break;
7341 case NCASE:
7342 cmdputs("case ");
7343 cmdputs(n->ncase.expr->narg.text);
7344 cmdputs(" in ...");
7345 break;
7346 case NDEFUN:
7347 cmdputs(n->narg.text);
7348 cmdputs("() ...");
7349 break;
7350 case NCMD:
7351 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7352 cmdtxt(np);
7353 if (np->narg.next)
7354 cmdputs(spcstr);
7355 }
7356 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7357 cmdputs(spcstr);
7358 cmdtxt(np);
7359 }
7360 break;
7361 case NARG:
7362 cmdputs(n->narg.text);
7363 break;
7364 case NTO:
7365 p = ">"; i = 1; goto redir;
7366 case NAPPEND:
7367 p = ">>"; i = 1; goto redir;
7368 case NTOFD:
7369 p = ">&"; i = 1; goto redir;
7370 case NTOOV:
7371 p = ">|"; i = 1; goto redir;
7372 case NFROM:
7373 p = "<"; i = 0; goto redir;
7374 case NFROMFD:
7375 p = "<&"; i = 0; goto redir;
7376 case NFROMTO:
7377 p = "<>"; i = 0; goto redir;
7378redir:
7379 if (n->nfile.fd != i) {
7380 s[0] = n->nfile.fd + '0';
7381 s[1] = '\0';
7382 cmdputs(s);
7383 }
7384 cmdputs(p);
7385 if (n->type == NTOFD || n->type == NFROMFD) {
7386 s[0] = n->ndup.dupfd + '0';
7387 s[1] = '\0';
7388 cmdputs(s);
7389 } else {
7390 cmdtxt(n->nfile.fname);
7391 }
7392 break;
7393 case NHERE:
7394 case NXHERE:
7395 cmdputs("<<...");
7396 break;
7397 default:
7398 cmdputs("???");
7399 break;
7400 }
7401}
Manuel Novoa III c639a352001-08-12 17:32:56 +00007402#endif /* CMDTXT_TABLE */
Eric Andersencb57d552001-06-28 07:25:16 +00007403
Eric Andersen2870d962001-07-02 17:27:21 +00007404static char *
7405commandtext(const union node *n)
7406{
7407 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007408
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007409 cmdnextc = name = xmalloc(MAXCMDTEXT);
Eric Andersen2870d962001-07-02 17:27:21 +00007410 cmdnleft = MAXCMDTEXT - 4;
7411 cmdtxt(n);
7412 *cmdnextc = '\0';
7413 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00007414}
7415
Eric Andersen2870d962001-07-02 17:27:21 +00007416
Eric Andersencb57d552001-06-28 07:25:16 +00007417static void waitonint(int sig) {
7418 intreceived = 1;
7419 return;
7420}
Eric Andersenec074692001-10-31 11:05:49 +00007421
7422#ifdef ASH_MAIL
7423
Eric Andersencb57d552001-06-28 07:25:16 +00007424/*
Eric Andersenec074692001-10-31 11:05:49 +00007425 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +00007426 */
7427
7428
7429#define MAXMBOXES 10
7430
7431
Eric Andersen2870d962001-07-02 17:27:21 +00007432static int nmboxes; /* number of mailboxes */
7433static time_t mailtime[MAXMBOXES]; /* times of mailboxes */
Eric Andersencb57d552001-06-28 07:25:16 +00007434
7435
7436
7437/*
7438 * Print appropriate message(s) if mail has arrived. If the argument is
7439 * nozero, then the value of MAIL has changed, so we just update the
7440 * values.
7441 */
7442
7443static void
Eric Andersen2870d962001-07-02 17:27:21 +00007444chkmail(int silent)
Eric Andersencb57d552001-06-28 07:25:16 +00007445{
7446 int i;
7447 const char *mpath;
7448 char *p;
7449 char *q;
7450 struct stackmark smark;
7451 struct stat statb;
7452
7453 if (silent)
7454 nmboxes = 10;
7455 if (nmboxes == 0)
7456 return;
7457 setstackmark(&smark);
7458 mpath = mpathset()? mpathval() : mailval();
7459 for (i = 0 ; i < nmboxes ; i++) {
7460 p = padvance(&mpath, nullstr);
7461 if (p == NULL)
7462 break;
7463 if (*p == '\0')
7464 continue;
7465 for (q = p ; *q ; q++);
7466#ifdef DEBUG
7467 if (q[-1] != '/')
7468 abort();
7469#endif
Eric Andersen2870d962001-07-02 17:27:21 +00007470 q[-1] = '\0'; /* delete trailing '/' */
Eric Andersencb57d552001-06-28 07:25:16 +00007471 if (stat(p, &statb) < 0)
7472 statb.st_size = 0;
7473 if (statb.st_size > mailtime[i] && ! silent) {
Eric Andersen3102ac42001-07-06 04:26:23 +00007474 out2fmt(snlfmt,
7475 pathopt? pathopt : "you have mail");
Eric Andersencb57d552001-06-28 07:25:16 +00007476 }
7477 mailtime[i] = statb.st_size;
Eric Andersencb57d552001-06-28 07:25:16 +00007478 }
7479 nmboxes = i;
7480 popstackmark(&smark);
7481}
Eric Andersencb57d552001-06-28 07:25:16 +00007482
Eric Andersenec074692001-10-31 11:05:49 +00007483#endif /* ASH_MAIL */
7484
Eric Andersencb57d552001-06-28 07:25:16 +00007485#define PROFILE 0
7486
Eric Andersencb57d552001-06-28 07:25:16 +00007487#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007488static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007489extern int etext();
7490#endif
7491
Eric Andersen2870d962001-07-02 17:27:21 +00007492static void read_profile (const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007493static void cmdloop (int);
7494static void options (int);
Eric Andersen2870d962001-07-02 17:27:21 +00007495static void setoption (int, int);
7496static void procargs (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00007497
Eric Andersen2870d962001-07-02 17:27:21 +00007498
Eric Andersencb57d552001-06-28 07:25:16 +00007499/*
7500 * Main routine. We initialize things, parse the arguments, execute
7501 * profiles if we're a login shell, and then call cmdloop to execute
7502 * commands. The setjmp call sets up the location to jump to when an
7503 * exception occurs. When an exception occurs the variable "state"
7504 * is used to figure out how far we had gotten.
7505 */
7506
7507int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007508ash_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007509{
7510 struct jmploc jmploc;
7511 struct stackmark smark;
7512 volatile int state;
Eric Andersen62483552001-07-10 06:09:16 +00007513 const char *shinit;
Eric Andersencb57d552001-06-28 07:25:16 +00007514
Eric Andersencb57d552001-06-28 07:25:16 +00007515 BLTINCMD = find_builtin("builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00007516 EXECCMD = find_builtin("exec");
7517 EVALCMD = find_builtin("eval");
7518
Eric Andersenbdfd0d72001-10-24 05:00:29 +00007519#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
Eric Andersen1c039232001-07-07 00:05:55 +00007520 unsetenv("PS1");
7521 unsetenv("PS2");
7522#endif
7523
Eric Andersencb57d552001-06-28 07:25:16 +00007524#if PROFILE
7525 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7526#endif
7527#if defined(linux) || defined(__GNU__)
7528 signal(SIGCHLD, SIG_DFL);
7529#endif
7530 state = 0;
7531 if (setjmp(jmploc.loc)) {
7532 INTOFF;
7533 /*
7534 * When a shell procedure is executed, we raise the
7535 * exception EXSHELLPROC to clean up before executing
7536 * the shell procedure.
7537 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007538 if (exception == EXSHELLPROC) {
Eric Andersencb57d552001-06-28 07:25:16 +00007539 rootpid = getpid();
7540 rootshell = 1;
7541 minusc = NULL;
7542 state = 3;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007543 } else {
7544 if (exception == EXEXEC) {
7545 exitstatus = exerrno;
7546 } else if (exception == EXERROR) {
7547 exitstatus = 2;
7548 }
Eric Andersencb57d552001-06-28 07:25:16 +00007549 if (state == 0 || iflag == 0 || ! rootshell)
7550 exitshell(exitstatus);
7551 }
7552 reset();
Eric Andersen2870d962001-07-02 17:27:21 +00007553 if (exception == EXINT) {
Eric Andersencb57d552001-06-28 07:25:16 +00007554 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00007555 }
7556 popstackmark(&smark);
Eric Andersen2870d962001-07-02 17:27:21 +00007557 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007558 if (state == 1)
7559 goto state1;
7560 else if (state == 2)
7561 goto state2;
7562 else if (state == 3)
7563 goto state3;
7564 else
7565 goto state4;
7566 }
7567 handler = &jmploc;
7568#ifdef DEBUG
7569 opentrace();
7570 trputs("Shell args: "); trargs(argv);
7571#endif
7572 rootpid = getpid();
7573 rootshell = 1;
7574 init();
7575 setstackmark(&smark);
7576 procargs(argc, argv);
7577 if (argv[0] && argv[0][0] == '-') {
7578 state = 1;
7579 read_profile("/etc/profile");
7580state1:
7581 state = 2;
7582 read_profile(".profile");
7583 }
7584state2:
7585 state = 3;
7586#ifndef linux
7587 if (getuid() == geteuid() && getgid() == getegid()) {
7588#endif
7589 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7590 state = 3;
7591 read_profile(shinit);
7592 }
7593#ifndef linux
7594 }
7595#endif
7596state3:
7597 state = 4;
7598 if (sflag == 0 || minusc) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007599 static const char sigs[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00007600 SIGINT, SIGQUIT, SIGHUP,
Eric Andersencb57d552001-06-28 07:25:16 +00007601#ifdef SIGTSTP
7602 SIGTSTP,
7603#endif
7604 SIGPIPE
7605 };
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007606#define SIGSSIZE ((sizeof(sigs)/sizeof(sigs[0])) - 1) /* trailing nul */
Eric Andersencb57d552001-06-28 07:25:16 +00007607 int i;
7608
7609 for (i = 0; i < SIGSSIZE; i++)
7610 setsignal(sigs[i]);
7611 }
7612
7613 if (minusc)
7614 evalstring(minusc, 0);
7615
7616 if (sflag || minusc == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00007617state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007618 cmdloop(1);
7619 }
7620#if PROFILE
7621 monitor(0);
7622#endif
7623 exitshell(exitstatus);
7624 /* NOTREACHED */
7625}
7626
7627
7628/*
7629 * Read and execute commands. "Top" is nonzero for the top level command
7630 * loop; it turns on prompting if the shell is interactive.
7631 */
7632
7633static void
Eric Andersen2870d962001-07-02 17:27:21 +00007634cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00007635{
7636 union node *n;
7637 struct stackmark smark;
7638 int inter;
7639 int numeof = 0;
7640
7641 TRACE(("cmdloop(%d) called\n", top));
7642 setstackmark(&smark);
7643 for (;;) {
7644 if (pendingsigs)
7645 dotrap();
7646 inter = 0;
7647 if (iflag && top) {
7648 inter++;
7649 showjobs(1);
Eric Andersenec074692001-10-31 11:05:49 +00007650#ifdef ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +00007651 chkmail(0);
Eric Andersenec074692001-10-31 11:05:49 +00007652#endif
Eric Andersen3102ac42001-07-06 04:26:23 +00007653 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00007654 }
7655 n = parsecmd(inter);
7656 /* showtree(n); DEBUG */
7657 if (n == NEOF) {
7658 if (!top || numeof >= 50)
7659 break;
7660 if (!stoppedjobs()) {
7661 if (!Iflag)
7662 break;
7663 out2str("\nUse \"exit\" to leave shell.\n");
7664 }
7665 numeof++;
7666 } else if (n != NULL && nflag == 0) {
7667 job_warning = (job_warning == 2) ? 1 : 0;
7668 numeof = 0;
7669 evaltree(n, 0);
7670 }
7671 popstackmark(&smark);
7672 setstackmark(&smark);
7673 if (evalskip == SKIPFILE) {
7674 evalskip = 0;
7675 break;
7676 }
7677 }
7678 popstackmark(&smark);
7679}
7680
7681
7682
7683/*
7684 * Read /etc/profile or .profile. Return on error.
7685 */
7686
7687static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007688read_profile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00007689{
7690 int fd;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007691 int xflag_save;
7692 int vflag_save;
Eric Andersencb57d552001-06-28 07:25:16 +00007693
7694 INTOFF;
7695 if ((fd = open(name, O_RDONLY)) >= 0)
7696 setinputfd(fd, 1);
7697 INTON;
7698 if (fd < 0)
7699 return;
7700 /* -q turns off -x and -v just when executing init files */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007701 /* Note: Might do a little redundant work, but reduces code size. */
7702 xflag_save = xflag;
7703 vflag_save = vflag;
Eric Andersencb57d552001-06-28 07:25:16 +00007704 if (qflag) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007705 vflag = xflag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007706 }
7707 cmdloop(0);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00007708 xflag = xflag_save;
7709 vflag = vflag_save;
Eric Andersencb57d552001-06-28 07:25:16 +00007710 popfile();
7711}
7712
7713
7714
7715/*
7716 * Read a file containing shell functions.
7717 */
7718
7719static void
Eric Andersen2870d962001-07-02 17:27:21 +00007720readcmdfile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00007721{
7722 int fd;
7723
7724 INTOFF;
7725 if ((fd = open(name, O_RDONLY)) >= 0)
7726 setinputfd(fd, 1);
7727 else
7728 error("Can't open %s", name);
7729 INTON;
7730 cmdloop(0);
7731 popfile();
7732}
7733
7734
7735
7736/*
7737 * Take commands from a file. To be compatable we should do a path
7738 * search for the file, which is necessary to find sub-commands.
7739 */
7740
Eric Andersen62483552001-07-10 06:09:16 +00007741static inline char *
Eric Andersen74400cc2001-10-18 04:11:39 +00007742find_dot_file(char *mybasename)
Eric Andersencb57d552001-06-28 07:25:16 +00007743{
7744 char *fullname;
7745 const char *path = pathval();
7746 struct stat statb;
7747
7748 /* don't try this for absolute or relative paths */
7749 if (strchr(mybasename, '/'))
7750 return mybasename;
7751
7752 while ((fullname = padvance(&path, mybasename)) != NULL) {
7753 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
7754 /*
7755 * Don't bother freeing here, since it will
7756 * be freed by the caller.
7757 */
7758 return fullname;
7759 }
7760 stunalloc(fullname);
7761 }
7762
7763 /* not found in the PATH */
7764 error("%s: not found", mybasename);
7765 /* NOTREACHED */
7766}
7767
7768static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007769dotcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007770{
7771 struct strlist *sp;
Eric Andersen69a20f02001-10-31 10:40:37 +00007772 volatile struct shparam saveparam;
Eric Andersencb57d552001-06-28 07:25:16 +00007773 exitstatus = 0;
7774
7775 for (sp = cmdenviron; sp ; sp = sp->next)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007776 setvareq(xstrdup(sp->text), VSTRFIXED|VTEXTFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +00007777
Eric Andersen2870d962001-07-02 17:27:21 +00007778 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00007779 char *fullname;
7780 struct stackmark smark;
7781
7782 setstackmark(&smark);
7783 fullname = find_dot_file(argv[1]);
Eric Andersen69a20f02001-10-31 10:40:37 +00007784
7785 if (argc>2) {
7786 saveparam = shellparam;
7787 shellparam.malloc = 0;
7788 shellparam.nparam = argc - 2;
7789 shellparam.p = argv + 2;
7790 };
7791
Eric Andersencb57d552001-06-28 07:25:16 +00007792 setinputfile(fullname, 1);
7793 commandname = fullname;
7794 cmdloop(0);
7795 popfile();
Eric Andersen69a20f02001-10-31 10:40:37 +00007796
7797 if (argc>2) {
7798 freeparam(&shellparam);
7799 shellparam = saveparam;
7800 };
7801
Eric Andersencb57d552001-06-28 07:25:16 +00007802 popstackmark(&smark);
7803 }
7804 return exitstatus;
7805}
7806
7807
7808static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007809exitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007810{
7811 if (stoppedjobs())
7812 return 0;
7813 if (argc > 1)
7814 exitstatus = number(argv[1]);
7815 else
7816 exitstatus = oexitstatus;
7817 exitshell(exitstatus);
7818 /* NOTREACHED */
7819}
Eric Andersen62483552001-07-10 06:09:16 +00007820
Eric Andersen2870d962001-07-02 17:27:21 +00007821static pointer
7822stalloc(int nbytes)
Eric Andersencb57d552001-06-28 07:25:16 +00007823{
7824 char *p;
7825
7826 nbytes = ALIGN(nbytes);
7827 if (nbytes > stacknleft) {
7828 int blocksize;
7829 struct stack_block *sp;
7830
7831 blocksize = nbytes;
7832 if (blocksize < MINSIZE)
7833 blocksize = MINSIZE;
7834 INTOFF;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007835 sp = xmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
Eric Andersencb57d552001-06-28 07:25:16 +00007836 sp->prev = stackp;
7837 stacknxt = sp->space;
7838 stacknleft = blocksize;
7839 stackp = sp;
7840 INTON;
7841 }
7842 p = stacknxt;
7843 stacknxt += nbytes;
7844 stacknleft -= nbytes;
7845 return p;
7846}
7847
7848
7849static void
Eric Andersen2870d962001-07-02 17:27:21 +00007850stunalloc(pointer p)
7851{
Eric Andersencb57d552001-06-28 07:25:16 +00007852#ifdef DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +00007853 if (p == NULL) { /*DEBUG */
Eric Andersencb57d552001-06-28 07:25:16 +00007854 write(2, "stunalloc\n", 10);
7855 abort();
7856 }
7857#endif
7858 if (!(stacknxt >= (char *)p && (char *)p >= stackp->space)) {
7859 p = stackp->space;
7860 }
7861 stacknleft += stacknxt - (char *)p;
7862 stacknxt = p;
7863}
7864
7865
Eric Andersencb57d552001-06-28 07:25:16 +00007866static void
Eric Andersen2870d962001-07-02 17:27:21 +00007867setstackmark(struct stackmark *mark)
7868{
Eric Andersencb57d552001-06-28 07:25:16 +00007869 mark->stackp = stackp;
7870 mark->stacknxt = stacknxt;
7871 mark->stacknleft = stacknleft;
7872 mark->marknext = markp;
7873 markp = mark;
7874}
7875
7876
7877static void
Eric Andersen2870d962001-07-02 17:27:21 +00007878popstackmark(struct stackmark *mark)
7879{
Eric Andersencb57d552001-06-28 07:25:16 +00007880 struct stack_block *sp;
7881
7882 INTOFF;
7883 markp = mark->marknext;
7884 while (stackp != mark->stackp) {
7885 sp = stackp;
7886 stackp = sp->prev;
7887 ckfree(sp);
7888 }
7889 stacknxt = mark->stacknxt;
7890 stacknleft = mark->stacknleft;
7891 INTON;
7892}
7893
7894
7895/*
7896 * When the parser reads in a string, it wants to stick the string on the
7897 * stack and only adjust the stack pointer when it knows how big the
7898 * string is. Stackblock (defined in stack.h) returns a pointer to a block
7899 * of space on top of the stack and stackblocklen returns the length of
7900 * this block. Growstackblock will grow this space by at least one byte,
7901 * possibly moving it (like realloc). Grabstackblock actually allocates the
7902 * part of the block that has been used.
7903 */
7904
7905static void
Eric Andersen2870d962001-07-02 17:27:21 +00007906growstackblock(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00007907 char *p;
7908 int newlen = ALIGN(stacknleft * 2 + 100);
7909 char *oldspace = stacknxt;
7910 int oldlen = stacknleft;
7911 struct stack_block *sp;
7912 struct stack_block *oldstackp;
7913
7914 if (stacknxt == stackp->space && stackp != &stackbase) {
7915 INTOFF;
7916 oldstackp = stackp;
7917 sp = stackp;
7918 stackp = sp->prev;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00007919 sp = xrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen);
Eric Andersencb57d552001-06-28 07:25:16 +00007920 sp->prev = stackp;
7921 stackp = sp;
7922 stacknxt = sp->space;
7923 stacknleft = newlen;
7924 {
7925 /* Stack marks pointing to the start of the old block
Eric Andersen2870d962001-07-02 17:27:21 +00007926 * must be relocated to point to the new block
Eric Andersencb57d552001-06-28 07:25:16 +00007927 */
7928 struct stackmark *xmark;
7929 xmark = markp;
7930 while (xmark != NULL && xmark->stackp == oldstackp) {
7931 xmark->stackp = stackp;
7932 xmark->stacknxt = stacknxt;
7933 xmark->stacknleft = stacknleft;
7934 xmark = xmark->marknext;
7935 }
7936 }
7937 INTON;
7938 } else {
7939 p = stalloc(newlen);
7940 memcpy(p, oldspace, oldlen);
Eric Andersen2870d962001-07-02 17:27:21 +00007941 stacknxt = p; /* free the space */
7942 stacknleft += newlen; /* we just allocated */
Eric Andersencb57d552001-06-28 07:25:16 +00007943 }
7944}
7945
7946
7947
Eric Andersen2870d962001-07-02 17:27:21 +00007948static inline void
7949grabstackblock(int len)
Eric Andersencb57d552001-06-28 07:25:16 +00007950{
7951 len = ALIGN(len);
7952 stacknxt += len;
7953 stacknleft -= len;
7954}
7955
7956
7957
7958/*
7959 * The following routines are somewhat easier to use that the above.
7960 * The user declares a variable of type STACKSTR, which may be declared
7961 * to be a register. The macro STARTSTACKSTR initializes things. Then
7962 * the user uses the macro STPUTC to add characters to the string. In
7963 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
7964 * grown as necessary. When the user is done, she can just leave the
7965 * string there and refer to it using stackblock(). Or she can allocate
7966 * the space for it using grabstackstr(). If it is necessary to allow
7967 * someone else to use the stack temporarily and then continue to grow
7968 * the string, the user should use grabstack to allocate the space, and
7969 * then call ungrabstr(p) to return to the previous mode of operation.
7970 *
7971 * USTPUTC is like STPUTC except that it doesn't check for overflow.
7972 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
7973 * is space for at least one character.
7974 */
7975
7976
7977static char *
Eric Andersen2870d962001-07-02 17:27:21 +00007978growstackstr(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00007979 int len = stackblocksize();
7980 if (herefd >= 0 && len >= 1024) {
7981 xwrite(herefd, stackblock(), len);
7982 sstrnleft = len - 1;
7983 return stackblock();
7984 }
7985 growstackblock();
7986 sstrnleft = stackblocksize() - len - 1;
7987 return stackblock() + len;
7988}
7989
7990
7991/*
7992 * Called from CHECKSTRSPACE.
7993 */
7994
7995static char *
7996makestrspace(size_t newlen) {
7997 int len = stackblocksize() - sstrnleft;
7998 do {
7999 growstackblock();
8000 sstrnleft = stackblocksize() - len;
8001 } while (sstrnleft < newlen);
8002 return stackblock() + len;
8003}
8004
8005
8006
8007static void
Eric Andersen2870d962001-07-02 17:27:21 +00008008ungrabstackstr(char *s, char *p)
8009{
Eric Andersencb57d552001-06-28 07:25:16 +00008010 stacknleft += stacknxt - s;
8011 stacknxt = s;
8012 sstrnleft = stacknleft - (p - s);
8013}
Eric Andersencb57d552001-06-28 07:25:16 +00008014/*
8015 * Miscelaneous builtins.
8016 */
8017
8018
8019#undef rflag
8020
Eric Andersencb57d552001-06-28 07:25:16 +00008021#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersen62483552001-07-10 06:09:16 +00008022typedef long rlim_t;
Eric Andersencb57d552001-06-28 07:25:16 +00008023#endif
8024
8025
8026
8027/*
8028 * The read builtin. The -e option causes backslashes to escape the
8029 * following character.
8030 *
8031 * This uses unbuffered input, which may be avoidable in some cases.
8032 */
8033
8034static int
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008035readcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008036{
8037 char **ap;
8038 int backslash;
8039 char c;
8040 int rflag;
8041 char *prompt;
8042 const char *ifs;
8043 char *p;
8044 int startword;
8045 int status;
8046 int i;
8047
8048 rflag = 0;
8049 prompt = NULL;
8050 while ((i = nextopt("p:r")) != '\0') {
8051 if (i == 'p')
8052 prompt = optionarg;
8053 else
8054 rflag = 1;
8055 }
8056 if (prompt && isatty(0)) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008057 out2str(prompt); /* read without cmdedit */
Eric Andersencb57d552001-06-28 07:25:16 +00008058 flushall();
8059 }
8060 if (*(ap = argptr) == NULL)
8061 error("arg count");
8062 if ((ifs = bltinlookup("IFS")) == NULL)
8063 ifs = defifs;
8064 status = 0;
8065 startword = 1;
8066 backslash = 0;
8067 STARTSTACKSTR(p);
8068 for (;;) {
8069 if (read(0, &c, 1) != 1) {
8070 status = 1;
8071 break;
8072 }
8073 if (c == '\0')
8074 continue;
8075 if (backslash) {
8076 backslash = 0;
8077 if (c != '\n')
8078 STPUTC(c, p);
8079 continue;
8080 }
8081 if (!rflag && c == '\\') {
8082 backslash++;
8083 continue;
8084 }
8085 if (c == '\n')
8086 break;
8087 if (startword && *ifs == ' ' && strchr(ifs, c)) {
8088 continue;
8089 }
8090 startword = 0;
8091 if (backslash && c == '\\') {
8092 if (read(0, &c, 1) != 1) {
8093 status = 1;
8094 break;
8095 }
8096 STPUTC(c, p);
8097 } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
8098 STACKSTRNUL(p);
8099 setvar(*ap, stackblock(), 0);
8100 ap++;
8101 startword = 1;
8102 STARTSTACKSTR(p);
8103 } else {
8104 STPUTC(c, p);
8105 }
8106 }
8107 STACKSTRNUL(p);
8108 /* Remove trailing blanks */
8109 while (stackblock() <= --p && strchr(ifs, *p) != NULL)
8110 *p = '\0';
8111 setvar(*ap, stackblock(), 0);
8112 while (*++ap != NULL)
8113 setvar(*ap, nullstr, 0);
8114 return status;
8115}
8116
8117
8118
8119static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008120umaskcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008121{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008122 static const char permuser[3] = "ugo";
8123 static const char permmode[3] = "rwx";
8124 static const short int permmask[] = {
8125 S_IRUSR, S_IWUSR, S_IXUSR,
8126 S_IRGRP, S_IWGRP, S_IXGRP,
8127 S_IROTH, S_IWOTH, S_IXOTH
8128 };
8129
Eric Andersencb57d552001-06-28 07:25:16 +00008130 char *ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008131 mode_t mask;
Eric Andersencb57d552001-06-28 07:25:16 +00008132 int i;
8133 int symbolic_mode = 0;
8134
Eric Andersen62483552001-07-10 06:09:16 +00008135 while (nextopt("S") != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00008136 symbolic_mode = 1;
8137 }
8138
8139 INTOFF;
8140 mask = umask(0);
8141 umask(mask);
8142 INTON;
8143
8144 if ((ap = *argptr) == NULL) {
8145 if (symbolic_mode) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008146 char buf[18];
8147 char *p = buf;
8148 for (i=0 ; i<3 ; i++) {
8149 int j;
8150 *p++ = permuser[i];
8151 *p++ = '=';
8152 for (j=0 ; j<3 ; j++) {
8153 if ((mask & permmask[3*i+j]) == 0) {
8154 *p++ = permmode[j];
8155 }
8156 }
8157 *p++ = ',';
8158 }
8159 *--p = 0;
8160 puts(buf);
Eric Andersencb57d552001-06-28 07:25:16 +00008161 } else {
Eric Andersen62483552001-07-10 06:09:16 +00008162 printf("%.4o\n", mask);
Eric Andersencb57d552001-06-28 07:25:16 +00008163 }
8164 } else {
Eric Andersen62483552001-07-10 06:09:16 +00008165 if (is_digit((unsigned char)*ap)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008166 mask = 0;
8167 do {
8168 if (*ap >= '8' || *ap < '0')
8169 error("Illegal number: %s", argv[1]);
8170 mask = (mask << 3) + (*ap - '0');
8171 } while (*++ap != '\0');
8172 umask(mask);
8173 } else {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008174 mask = ~mask & 0777;
8175 if (parse_mode(ap, &mask) == FALSE) {
Eric Andersencb57d552001-06-28 07:25:16 +00008176 error("Illegal mode: %s", ap);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008177 }
Eric Andersencb57d552001-06-28 07:25:16 +00008178 umask(~mask & 0777);
8179 }
8180 }
8181 return 0;
8182}
8183
8184/*
8185 * ulimit builtin
8186 *
8187 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
8188 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
8189 * ash by J.T. Conklin.
8190 *
8191 * Public domain.
8192 */
8193
8194struct limits {
8195 const char *name;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008196 short cmd;
8197 short factor; /* multiply by to get rlim_{cur,max} values */
Eric Andersencb57d552001-06-28 07:25:16 +00008198};
8199
8200static const struct limits limits[] = {
8201#ifdef RLIMIT_CPU
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008202 { "time(seconds)", RLIMIT_CPU, 1 },
Eric Andersencb57d552001-06-28 07:25:16 +00008203#endif
8204#ifdef RLIMIT_FSIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008205 { "file(blocks)", RLIMIT_FSIZE, 512 },
Eric Andersencb57d552001-06-28 07:25:16 +00008206#endif
8207#ifdef RLIMIT_DATA
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008208 { "data(kbytes)", RLIMIT_DATA, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008209#endif
8210#ifdef RLIMIT_STACK
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008211 { "stack(kbytes)", RLIMIT_STACK, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008212#endif
8213#ifdef RLIMIT_CORE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008214 { "coredump(blocks)", RLIMIT_CORE, 512 },
Eric Andersencb57d552001-06-28 07:25:16 +00008215#endif
8216#ifdef RLIMIT_RSS
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008217 { "memory(kbytes)", RLIMIT_RSS, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008218#endif
8219#ifdef RLIMIT_MEMLOCK
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008220 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008221#endif
8222#ifdef RLIMIT_NPROC
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008223 { "process(processes)", RLIMIT_NPROC, 1 },
Eric Andersencb57d552001-06-28 07:25:16 +00008224#endif
8225#ifdef RLIMIT_NOFILE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008226 { "nofiles(descriptors)", RLIMIT_NOFILE, 1 },
Eric Andersencb57d552001-06-28 07:25:16 +00008227#endif
8228#ifdef RLIMIT_VMEM
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008229 { "vmemory(kbytes)", RLIMIT_VMEM, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008230#endif
8231#ifdef RLIMIT_SWAP
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008232 { "swap(kbytes)", RLIMIT_SWAP, 1024 },
Eric Andersencb57d552001-06-28 07:25:16 +00008233#endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008234 { NULL, 0, 0 }
Eric Andersencb57d552001-06-28 07:25:16 +00008235};
8236
8237static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008238ulimitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008239{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008240 static const char unlimited_string[] = "unlimited";
Eric Andersen2870d962001-07-02 17:27:21 +00008241 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00008242 rlim_t val = 0;
8243 enum { SOFT = 0x1, HARD = 0x2 }
8244 how = SOFT | HARD;
Eric Andersen2870d962001-07-02 17:27:21 +00008245 const struct limits *l;
8246 int set, all = 0;
8247 int optc, what;
8248 struct rlimit limit;
Eric Andersencb57d552001-06-28 07:25:16 +00008249
8250 what = 'f';
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008251
8252 while ((optc = nextopt("HSa"
8253#ifdef RLIMIT_CPU
8254 "t"
8255#endif
8256#ifdef RLIMIT_FSIZE
8257 "f"
8258#endif
8259#ifdef RLIMIT_DATA
8260 "d"
8261#endif
8262#ifdef RLIMIT_STACK
8263 "s"
8264#endif
8265#ifdef RLIMIT_CORE
8266 "c"
8267#endif
8268#ifdef RLIMIT_RSS
8269 "m"
8270#endif
8271#ifdef RLIMIT_MEMLOCK
8272 "l"
8273#endif
8274#ifdef RLIMIT_NPROC
8275 "p"
8276#endif
8277#ifdef RLIMIT_NOFILE
8278 "n"
8279#endif
8280#ifdef RLIMIT_VMEM
8281 "v"
8282#endif
8283#ifdef RLIMIT_SWAP
8284 "w"
8285#endif
8286 )) != '\0') {
8287 if (optc == 'H') {
Eric Andersencb57d552001-06-28 07:25:16 +00008288 how = HARD;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008289 } else if (optc == 'S') {
Eric Andersencb57d552001-06-28 07:25:16 +00008290 how = SOFT;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008291 } else if (optc == 'a') {
Eric Andersencb57d552001-06-28 07:25:16 +00008292 all = 1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008293 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00008294 what = optc;
8295 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008296 }
Eric Andersencb57d552001-06-28 07:25:16 +00008297
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008298 for (l = limits; l->name; l++) {
8299 if(l->name[0] == what)
8300 break;
8301 if(l->name[1]=='w' && what=='w')
8302 break;
8303 }
Eric Andersencb57d552001-06-28 07:25:16 +00008304
8305 set = *argptr ? 1 : 0;
8306 if (set) {
8307 char *p = *argptr;
8308
8309 if (all || argptr[1])
8310 error("too many arguments");
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008311 if (strcmp(p, unlimited_string) == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00008312 val = RLIM_INFINITY;
8313 else {
8314 val = (rlim_t) 0;
8315
8316 while ((c = *p++) >= '0' && c <= '9')
8317 {
8318 val = (val * 10) + (long)(c - '0');
8319 if (val < (rlim_t) 0)
8320 break;
8321 }
8322 if (c)
8323 error("bad number");
8324 val *= l->factor;
8325 }
8326 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008327
Eric Andersencb57d552001-06-28 07:25:16 +00008328 if (all) {
8329 for (l = limits; l->name; l++) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008330 printf("%-20s ", l->name);
Eric Andersencb57d552001-06-28 07:25:16 +00008331 getrlimit(l->cmd, &limit);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008332 OUTPUT_LIMIT:
Eric Andersencb57d552001-06-28 07:25:16 +00008333 if (how & SOFT)
8334 val = limit.rlim_cur;
8335 else if (how & HARD)
8336 val = limit.rlim_max;
8337
Eric Andersencb57d552001-06-28 07:25:16 +00008338 if (val == RLIM_INFINITY)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008339 puts(unlimited_string);
Eric Andersencb57d552001-06-28 07:25:16 +00008340 else
8341 {
8342 val /= l->factor;
Eric Andersen62483552001-07-10 06:09:16 +00008343 printf("%lld\n", (long long) val);
Eric Andersencb57d552001-06-28 07:25:16 +00008344 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008345 if (!all) {
8346 break;
8347 }
Eric Andersencb57d552001-06-28 07:25:16 +00008348 }
8349 return 0;
8350 }
8351
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008352 if (!set) {
8353 goto OUTPUT_LIMIT;
Eric Andersencb57d552001-06-28 07:25:16 +00008354 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008355
8356 getrlimit(l->cmd, &limit);
8357 if (how & HARD)
8358 limit.rlim_max = val;
8359 if (how & SOFT)
8360 limit.rlim_cur = val;
8361 if (setrlimit(l->cmd, &limit) < 0)
8362 error("error setting limit (%m)");
Eric Andersencb57d552001-06-28 07:25:16 +00008363 return 0;
8364}
Eric Andersencb57d552001-06-28 07:25:16 +00008365/*
8366 * prefix -- see if pfx is a prefix of string.
8367 */
8368
8369static int
Eric Andersen62483552001-07-10 06:09:16 +00008370prefix(char const *pfx, char const *string)
8371{
Eric Andersencb57d552001-06-28 07:25:16 +00008372 while (*pfx) {
8373 if (*pfx++ != *string++)
8374 return 0;
8375 }
8376 return 1;
8377}
8378
Eric Andersen2870d962001-07-02 17:27:21 +00008379/*
8380 * Return true if s is a string of digits, and save munber in intptr
8381 * nagative is bad
8382 */
8383
8384static int
8385is_number(const char *p, int *intptr)
8386{
8387 int ret = 0;
8388
8389 do {
8390 if (! is_digit(*p))
8391 return 0;
8392 ret *= 10;
8393 ret += digit_val(*p);
8394 p++;
8395 } while (*p != '\0');
8396
8397 *intptr = ret;
8398 return 1;
8399}
Eric Andersencb57d552001-06-28 07:25:16 +00008400
8401/*
8402 * Convert a string of digits to an integer, printing an error message on
8403 * failure.
8404 */
8405
8406static int
Eric Andersen2870d962001-07-02 17:27:21 +00008407number(const char *s)
8408{
8409 int i;
8410 if (! is_number(s, &i))
Eric Andersencb57d552001-06-28 07:25:16 +00008411 error("Illegal number: %s", s);
Eric Andersen2870d962001-07-02 17:27:21 +00008412 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00008413}
8414
Eric Andersencb57d552001-06-28 07:25:16 +00008415/*
8416 * Produce a possibly single quoted string suitable as input to the shell.
8417 * The return string is allocated on the stack.
8418 */
8419
8420static char *
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008421single_quote(const char *s)
8422{
Eric Andersencb57d552001-06-28 07:25:16 +00008423 char *p;
8424
8425 STARTSTACKSTR(p);
8426
8427 do {
8428 char *q = p;
8429 size_t len1, len1p, len2, len2p;
8430
8431 len1 = strcspn(s, "'");
8432 len2 = strspn(s + len1, "'");
8433
8434 len1p = len1 ? len1 + 2 : len1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008435 len2p = len2 + ((len2 < 2) ? len2 : 2);
Eric Andersencb57d552001-06-28 07:25:16 +00008436
8437 CHECKSTRSPACE(len1p + len2p + 1, p);
8438
8439 if (len1) {
8440 *p = '\'';
Eric Andersencb57d552001-06-28 07:25:16 +00008441 q = p + 1 + len1;
8442 memcpy(p + 1, s, len1);
Eric Andersencb57d552001-06-28 07:25:16 +00008443 *q++ = '\'';
8444 s += len1;
8445 }
8446
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008447 if (len2 > 1) {
Eric Andersencb57d552001-06-28 07:25:16 +00008448 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008449 q += 1 + len2;
8450 memcpy(q + 1, s, len2);
8451 *q = '"';
Eric Andersencb57d552001-06-28 07:25:16 +00008452 s += len2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008453 } else if (len2 == 1) {
8454 *q++ = '\\';
8455 *q = '\'';
8456 s++;
Eric Andersencb57d552001-06-28 07:25:16 +00008457 }
8458
8459 STADJUST(len1p + len2p, p);
8460 } while (*s);
8461
8462 USTPUTC(0, p);
8463
8464 return grabstackstr(p);
8465}
8466
8467/*
8468 * Like strdup but works with the ash stack.
8469 */
8470
8471static char *
8472sstrdup(const char *p)
8473{
8474 size_t len = strlen(p) + 1;
8475 return memcpy(stalloc(len), p, len);
8476}
8477
Eric Andersencb57d552001-06-28 07:25:16 +00008478
8479/*
Eric Andersencb57d552001-06-28 07:25:16 +00008480 * Routine for dealing with parsed shell commands.
8481 */
8482
8483
Eric Andersen62483552001-07-10 06:09:16 +00008484static void sizenodelist (const struct nodelist *);
8485static struct nodelist *copynodelist (const struct nodelist *);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008486static char *nodexstrdup (const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00008487
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +00008488#define CALCSIZE_TABLE
8489#define COPYNODE_TABLE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008490#if defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE)
8491/*
8492 * To collect a lot of redundant code in case statements for copynode()
8493 * and calcsize(), we implement a mini language here. Each type of node
8494 * struct has an associated instruction sequence that operates on its
8495 * members via their offsets. The instruction are pack in unsigned chars
8496 * with format IIDDDDDE where the bits are
8497 * I : part of the instruction opcode, which are
8498 * 00 : member is a pointer to another node
8499 * 40 : member is an integer
8500 * 80 : member is a pointer to a nodelist
8501 * CC : member is a pointer to a char string
8502 * D : data - the actual offset of the member to operate on in the struct
8503 * (since we assume bit 0 is set, it is not shifted)
8504 * E : flag signaling end of instruction sequence
8505 *
8506 * WARNING: In order to handle larger offsets for 64bit archs, this code
8507 * assumes that no offset can be an odd number and stores the
8508 * end-of-instructions flag in bit 0.
8509 */
8510
8511#define NODE_INTEGER 0x40
8512#define NODE_NODELIST 0x80
8513#define NODE_CHARPTR 0xC0
8514#define NODE_NOMORE 0x01 /* Note: no offset should be odd (aligned)*/
8515#define NODE_MBRMASK 0xC0
8516#define NODE_OFFSETMASK 0x3E
8517
8518static const unsigned char copynode_ops[35] = {
8519#define COPYNODE_OPS0 0
8520 offsetof(union node, nbinary.ch2),
8521 offsetof(union node, nbinary.ch1)|NODE_NOMORE,
8522#define COPYNODE_OPS1 (COPYNODE_OPS0 + 2)
8523 offsetof(union node, ncmd.redirect),
8524 offsetof(union node, ncmd.args),
8525 offsetof(union node, ncmd.assign),
8526 offsetof(union node, ncmd.backgnd)|NODE_INTEGER|NODE_NOMORE,
8527#define COPYNODE_OPS2 (COPYNODE_OPS1 + 4)
8528 offsetof(union node, npipe.cmdlist)|NODE_NODELIST,
8529 offsetof(union node, npipe.backgnd)|NODE_INTEGER|NODE_NOMORE,
8530#define COPYNODE_OPS3 (COPYNODE_OPS2 + 2)
8531 offsetof(union node, nredir.redirect),
8532 offsetof(union node, nredir.n)|NODE_NOMORE,
8533#define COPYNODE_OPS4 (COPYNODE_OPS3 + 2)
8534 offsetof(union node, nif.elsepart),
8535 offsetof(union node, nif.ifpart),
8536 offsetof(union node, nif.test)|NODE_NOMORE,
8537#define COPYNODE_OPS5 (COPYNODE_OPS4 + 3)
8538 offsetof(union node, nfor.var)|NODE_CHARPTR,
8539 offsetof(union node, nfor.body),
8540 offsetof(union node, nfor.args)|NODE_NOMORE,
8541#define COPYNODE_OPS6 (COPYNODE_OPS5 + 3)
8542 offsetof(union node, ncase.cases),
8543 offsetof(union node, ncase.expr)|NODE_NOMORE,
8544#define COPYNODE_OPS7 (COPYNODE_OPS6 + 2)
8545 offsetof(union node, nclist.body),
8546 offsetof(union node, nclist.pattern),
8547 offsetof(union node, nclist.next)|NODE_NOMORE,
8548#define COPYNODE_OPS8 (COPYNODE_OPS7 + 3)
8549 offsetof(union node, narg.backquote)|NODE_NODELIST,
8550 offsetof(union node, narg.text)|NODE_CHARPTR,
8551 offsetof(union node, narg.next)|NODE_NOMORE,
8552#define COPYNODE_OPS9 (COPYNODE_OPS8 + 3)
8553 offsetof(union node, nfile.fname),
8554 offsetof(union node, nfile.fd)|NODE_INTEGER,
8555 offsetof(union node, nfile.next)|NODE_NOMORE,
8556#define COPYNODE_OPS10 (COPYNODE_OPS9 + 3)
8557 offsetof(union node, ndup.vname),
8558 offsetof(union node, ndup.dupfd)|NODE_INTEGER,
8559 offsetof(union node, ndup.fd)|NODE_INTEGER,
8560 offsetof(union node, ndup.next)|NODE_NOMORE,
8561#define COPYNODE_OPS11 (COPYNODE_OPS10 + 4)
8562 offsetof(union node, nhere.doc),
8563 offsetof(union node, nhere.fd)|NODE_INTEGER,
8564 offsetof(union node, nhere.next)|NODE_NOMORE,
8565#define COPYNODE_OPS12 (COPYNODE_OPS11 + 3)
8566 offsetof(union node, nnot.com)|NODE_NOMORE,
8567};
8568
8569#if COPYNODE_OPS12 != 34
8570#error COPYNODE_OPS12 is incorrect
8571#endif
8572
8573static const unsigned char copynode_ops_index[26] = {
8574 COPYNODE_OPS0, /* NSEMI */
8575 COPYNODE_OPS1, /* NCMD */
8576 COPYNODE_OPS2, /* NPIPE */
8577 COPYNODE_OPS3, /* NREDIR */
8578 COPYNODE_OPS3, /* NBACKGND */
8579 COPYNODE_OPS3, /* NSUBSHELL */
8580 COPYNODE_OPS0, /* NAND */
8581 COPYNODE_OPS0, /* NOR */
8582 COPYNODE_OPS4, /* NIF */
8583 COPYNODE_OPS0, /* NWHILE */
8584 COPYNODE_OPS0, /* NUNTIL */
8585 COPYNODE_OPS5, /* NFOR */
8586 COPYNODE_OPS6, /* NCASE */
8587 COPYNODE_OPS7, /* NCLIST */
8588 COPYNODE_OPS8, /* NDEFUN */
8589 COPYNODE_OPS8, /* NARG */
8590 COPYNODE_OPS9, /* NTO */
8591 COPYNODE_OPS9, /* NFROM */
8592 COPYNODE_OPS9, /* NFROMTO */
8593 COPYNODE_OPS9, /* NAPPEND */
8594 COPYNODE_OPS9, /* NTOOV */
8595 COPYNODE_OPS10, /* NTOFD */
8596 COPYNODE_OPS10, /* NFROMFD */
8597 COPYNODE_OPS11, /* NHERE */
8598 COPYNODE_OPS11, /* NXHERE */
8599 COPYNODE_OPS12, /* NNOT */
8600};
8601
8602#if NODE_CHARPTR != NODE_MBRMASK
8603#error NODE_CHARPTR != NODE_MBRMASK!!!
8604#endif
8605#endif /* defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE) */
8606
8607#ifdef COPYNODE_TABLE
8608static union node *
8609copynode(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008610{
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008611 union node *new;
8612 const unsigned char *p;
8613
Manuel Novoa III c639a352001-08-12 17:32:56 +00008614 if (n == NULL) {
8615 return NULL;
8616 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008617 new = funcblock;
8618 new->type = n->type;
8619 funcblock = (char *) funcblock + (int) nodesize[n->type];
8620 p = copynode_ops + (int) copynode_ops_index[n->type];
8621 do {
8622 char *nn = ((char *) new) + ((int)(*p & NODE_OFFSETMASK));
8623 const char *no = ((const char *) n) + ((int)(*p & NODE_OFFSETMASK));
8624
8625 if (!(*p & NODE_MBRMASK)) { /* standard node */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008626 *((union node **)nn) = copynode(*((const union node **) no));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008627 } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008628 *((const char **)nn) = nodexstrdup(*((const char **)no));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008629 } else if (*p & NODE_NODELIST) { /* nodelist */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008630 *((struct nodelist **)nn)
8631 = copynodelist(*((const struct nodelist **) no));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008632 } else { /* integer */
8633 *((int *) nn) = *((int *) no);
8634 }
8635 } while (!(*p++ & NODE_NOMORE));
8636 return new;
Eric Andersencb57d552001-06-28 07:25:16 +00008637}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008638#else /* COPYNODE_TABLE */
Eric Andersencb57d552001-06-28 07:25:16 +00008639static union node *
Eric Andersen62483552001-07-10 06:09:16 +00008640copynode(const union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008641{
Eric Andersen62483552001-07-10 06:09:16 +00008642 union node *new;
Eric Andersencb57d552001-06-28 07:25:16 +00008643
8644 if (n == NULL)
Manuel Novoa III c639a352001-08-12 17:32:56 +00008645 return NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008646 new = funcblock;
8647 funcblock = (char *) funcblock + nodesize[n->type];
8648 switch (n->type) {
8649 case NSEMI:
8650 case NAND:
8651 case NOR:
8652 case NWHILE:
8653 case NUNTIL:
8654 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8655 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8656 break;
8657 case NCMD:
8658 new->ncmd.redirect = copynode(n->ncmd.redirect);
8659 new->ncmd.args = copynode(n->ncmd.args);
8660 new->ncmd.assign = copynode(n->ncmd.assign);
8661 new->ncmd.backgnd = n->ncmd.backgnd;
8662 break;
8663 case NPIPE:
8664 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8665 new->npipe.backgnd = n->npipe.backgnd;
8666 break;
8667 case NREDIR:
8668 case NBACKGND:
8669 case NSUBSHELL:
8670 new->nredir.redirect = copynode(n->nredir.redirect);
8671 new->nredir.n = copynode(n->nredir.n);
8672 break;
8673 case NIF:
8674 new->nif.elsepart = copynode(n->nif.elsepart);
8675 new->nif.ifpart = copynode(n->nif.ifpart);
8676 new->nif.test = copynode(n->nif.test);
8677 break;
8678 case NFOR:
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008679 new->nfor.var = nodexstrdup(n->nfor.var);
Eric Andersencb57d552001-06-28 07:25:16 +00008680 new->nfor.body = copynode(n->nfor.body);
8681 new->nfor.args = copynode(n->nfor.args);
8682 break;
8683 case NCASE:
8684 new->ncase.cases = copynode(n->ncase.cases);
8685 new->ncase.expr = copynode(n->ncase.expr);
8686 break;
8687 case NCLIST:
8688 new->nclist.body = copynode(n->nclist.body);
8689 new->nclist.pattern = copynode(n->nclist.pattern);
8690 new->nclist.next = copynode(n->nclist.next);
8691 break;
8692 case NDEFUN:
8693 case NARG:
8694 new->narg.backquote = copynodelist(n->narg.backquote);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008695 new->narg.text = nodexstrdup(n->narg.text);
Eric Andersencb57d552001-06-28 07:25:16 +00008696 new->narg.next = copynode(n->narg.next);
8697 break;
8698 case NTO:
8699 case NFROM:
8700 case NFROMTO:
8701 case NAPPEND:
8702 case NTOOV:
8703 new->nfile.fname = copynode(n->nfile.fname);
8704 new->nfile.fd = n->nfile.fd;
8705 new->nfile.next = copynode(n->nfile.next);
8706 break;
8707 case NTOFD:
8708 case NFROMFD:
8709 new->ndup.vname = copynode(n->ndup.vname);
8710 new->ndup.dupfd = n->ndup.dupfd;
8711 new->ndup.fd = n->ndup.fd;
8712 new->ndup.next = copynode(n->ndup.next);
8713 break;
8714 case NHERE:
8715 case NXHERE:
8716 new->nhere.doc = copynode(n->nhere.doc);
8717 new->nhere.fd = n->nhere.fd;
8718 new->nhere.next = copynode(n->nhere.next);
8719 break;
8720 case NNOT:
8721 new->nnot.com = copynode(n->nnot.com);
8722 break;
8723 };
8724 new->type = n->type;
Eric Andersen62483552001-07-10 06:09:16 +00008725 return new;
Eric Andersencb57d552001-06-28 07:25:16 +00008726}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008727#endif /* COPYNODE_TABLE */
8728
8729#ifdef CALCSIZE_TABLE
8730static void
8731calcsize(const union node *n)
8732{
8733 const unsigned char *p;
8734
8735 if (n == NULL)
8736 return;
8737 funcblocksize += (int) nodesize[n->type];
8738
8739 p = copynode_ops + (int) copynode_ops_index[n->type];
8740 do {
8741 const char *no = ((const char *) n) + ((int)(*p & NODE_OFFSETMASK));
8742
8743 if (!(*p & NODE_MBRMASK)) { /* standard node */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008744 calcsize(*((const union node **) no));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008745 } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008746 funcstringsize += strlen(*((const char **)no)) + 1;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008747 } else if (*p & NODE_NODELIST) { /* nodelist */
Manuel Novoa III c639a352001-08-12 17:32:56 +00008748 sizenodelist(*((const struct nodelist **) no));
8749 } /* else integer -- ignore */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008750 } while (!(*p++ & NODE_NOMORE));
8751}
8752#else /* CALCSIZE_TABLE */
8753static void
8754calcsize(const union node *n)
8755{
8756 if (n == NULL)
8757 return;
8758 funcblocksize += nodesize[n->type];
8759 switch (n->type) {
8760 case NSEMI:
8761 case NAND:
8762 case NOR:
8763 case NWHILE:
8764 case NUNTIL:
8765 calcsize(n->nbinary.ch2);
8766 calcsize(n->nbinary.ch1);
8767 break;
8768 case NCMD:
8769 calcsize(n->ncmd.redirect);
8770 calcsize(n->ncmd.args);
8771 calcsize(n->ncmd.assign);
8772 break;
8773 case NPIPE:
8774 sizenodelist(n->npipe.cmdlist);
8775 break;
8776 case NREDIR:
8777 case NBACKGND:
8778 case NSUBSHELL:
8779 calcsize(n->nredir.redirect);
8780 calcsize(n->nredir.n);
8781 break;
8782 case NIF:
8783 calcsize(n->nif.elsepart);
8784 calcsize(n->nif.ifpart);
8785 calcsize(n->nif.test);
8786 break;
8787 case NFOR:
8788 funcstringsize += strlen(n->nfor.var) + 1;
8789 calcsize(n->nfor.body);
8790 calcsize(n->nfor.args);
8791 break;
8792 case NCASE:
8793 calcsize(n->ncase.cases);
8794 calcsize(n->ncase.expr);
8795 break;
8796 case NCLIST:
8797 calcsize(n->nclist.body);
8798 calcsize(n->nclist.pattern);
8799 calcsize(n->nclist.next);
8800 break;
8801 case NDEFUN:
8802 case NARG:
8803 sizenodelist(n->narg.backquote);
8804 funcstringsize += strlen(n->narg.text) + 1;
8805 calcsize(n->narg.next);
8806 break;
8807 case NTO:
8808 case NFROM:
8809 case NFROMTO:
8810 case NAPPEND:
8811 case NTOOV:
8812 calcsize(n->nfile.fname);
8813 calcsize(n->nfile.next);
8814 break;
8815 case NTOFD:
8816 case NFROMFD:
8817 calcsize(n->ndup.vname);
8818 calcsize(n->ndup.next);
8819 break;
8820 case NHERE:
8821 case NXHERE:
8822 calcsize(n->nhere.doc);
8823 calcsize(n->nhere.next);
8824 break;
8825 case NNOT:
8826 calcsize(n->nnot.com);
8827 break;
8828 };
8829}
8830#endif /* CALCSIZE_TABLE */
8831
8832static void
8833sizenodelist(const struct nodelist *lp)
8834{
8835 while (lp) {
8836 funcblocksize += ALIGN(sizeof(struct nodelist));
8837 calcsize(lp->n);
8838 lp = lp->next;
8839 }
8840}
Eric Andersencb57d552001-06-28 07:25:16 +00008841
8842
8843static struct nodelist *
Eric Andersen62483552001-07-10 06:09:16 +00008844copynodelist(const struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008845{
8846 struct nodelist *start;
8847 struct nodelist **lpp;
8848
8849 lpp = &start;
8850 while (lp) {
8851 *lpp = funcblock;
8852 funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist));
8853 (*lpp)->n = copynode(lp->n);
8854 lp = lp->next;
8855 lpp = &(*lpp)->next;
8856 }
8857 *lpp = NULL;
8858 return start;
8859}
8860
8861
Eric Andersencb57d552001-06-28 07:25:16 +00008862static char *
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008863nodexstrdup(const char *s)
Eric Andersencb57d552001-06-28 07:25:16 +00008864{
Eric Andersen62483552001-07-10 06:09:16 +00008865 const char *p = s;
8866 char *q = funcstring;
Eric Andersencb57d552001-06-28 07:25:16 +00008867 char *rtn = funcstring;
8868
8869 while ((*q++ = *p++) != '\0')
8870 continue;
8871 funcstring = q;
8872 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00008873}
8874
Eric Andersencb57d552001-06-28 07:25:16 +00008875#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00008876static int getopts (char *, char *, char **, int *, int *);
Eric Andersencb57d552001-06-28 07:25:16 +00008877#endif
8878
8879
8880/*
8881 * Process the shell command line arguments.
8882 */
8883
8884static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00008885procargs(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008886{
8887 int i;
8888
8889 argptr = argv;
8890 if (argc > 0)
8891 argptr++;
8892 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00008893 optent_val(i) = 2;
Eric Andersencb57d552001-06-28 07:25:16 +00008894 options(1);
8895 if (*argptr == NULL && minusc == NULL)
8896 sflag = 1;
8897 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8898 iflag = 1;
8899 if (mflag == 2)
8900 mflag = iflag;
8901 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00008902 if (optent_val(i) == 2)
8903 optent_val(i) = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008904 arg0 = argv[0];
8905 if (sflag == 0 && minusc == NULL) {
8906 commandname = argv[0];
8907 arg0 = *argptr++;
8908 setinputfile(arg0, 0);
8909 commandname = arg0;
8910 }
8911 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8912 if (argptr && minusc && *argptr)
Eric Andersen2870d962001-07-02 17:27:21 +00008913 arg0 = *argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00008914
8915 shellparam.p = argptr;
8916 shellparam.optind = 1;
8917 shellparam.optoff = -1;
8918 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8919 while (*argptr) {
8920 shellparam.nparam++;
8921 argptr++;
8922 }
8923 optschanged();
8924}
8925
8926
Eric Andersencb57d552001-06-28 07:25:16 +00008927
8928/*
8929 * Process shell options. The global variable argptr contains a pointer
8930 * to the argument list; we advance it past the options.
8931 */
8932
Eric Andersen62483552001-07-10 06:09:16 +00008933static inline void
8934minus_o(const char *name, int val)
8935{
8936 int i;
8937
8938 if (name == NULL) {
8939 out1str("Current option settings\n");
8940 for (i = 0; i < NOPTS; i++)
8941 printf("%-16s%s\n", optent_name(optlist[i]),
8942 optent_val(i) ? "on" : "off");
8943 } else {
8944 for (i = 0; i < NOPTS; i++)
8945 if (equal(name, optent_name(optlist[i]))) {
8946 setoption(optent_letter(optlist[i]), val);
8947 return;
8948 }
8949 error("Illegal option -o %s", name);
8950 }
8951}
8952
8953
Eric Andersencb57d552001-06-28 07:25:16 +00008954static void
Eric Andersen62483552001-07-10 06:09:16 +00008955options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00008956{
8957 char *p;
8958 int val;
8959 int c;
8960
8961 if (cmdline)
8962 minusc = NULL;
8963 while ((p = *argptr) != NULL) {
8964 argptr++;
8965 if ((c = *p++) == '-') {
8966 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00008967 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8968 if (!cmdline) {
8969 /* "-" means turn off -x and -v */
8970 if (p[0] == '\0')
8971 xflag = vflag = 0;
8972 /* "--" means reset params */
8973 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00008974 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00008975 }
8976 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00008977 }
8978 } else if (c == '+') {
8979 val = 0;
8980 } else {
8981 argptr--;
8982 break;
8983 }
8984 while ((c = *p++) != '\0') {
8985 if (c == 'c' && cmdline) {
8986 char *q;
Eric Andersen2870d962001-07-02 17:27:21 +00008987#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */
Eric Andersencb57d552001-06-28 07:25:16 +00008988 if (*p == '\0')
8989#endif
8990 q = *argptr++;
8991 if (q == NULL || minusc != NULL)
8992 error("Bad -c option");
8993 minusc = q;
8994#ifdef NOHACK
8995 break;
8996#endif
8997 } else if (c == 'o') {
8998 minus_o(*argptr, val);
8999 if (*argptr)
9000 argptr++;
9001 } else {
9002 setoption(c, val);
9003 }
9004 }
9005 }
9006}
9007
Eric Andersencb57d552001-06-28 07:25:16 +00009008
9009static void
Eric Andersen2870d962001-07-02 17:27:21 +00009010setoption(int flag, int val)
9011{
Eric Andersencb57d552001-06-28 07:25:16 +00009012 int i;
9013
9014 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009015 if (optent_letter(optlist[i]) == flag) {
9016 optent_val(i) = val;
Eric Andersencb57d552001-06-28 07:25:16 +00009017 if (val) {
9018 /* #%$ hack for ksh semantics */
9019 if (flag == 'V')
9020 Eflag = 0;
9021 else if (flag == 'E')
9022 Vflag = 0;
9023 }
9024 return;
9025 }
9026 error("Illegal option -%c", flag);
9027 /* NOTREACHED */
9028}
9029
9030
9031
Eric Andersencb57d552001-06-28 07:25:16 +00009032/*
9033 * Set the shell parameters.
9034 */
9035
9036static void
Eric Andersen2870d962001-07-02 17:27:21 +00009037setparam(char **argv)
9038{
Eric Andersencb57d552001-06-28 07:25:16 +00009039 char **newparam;
9040 char **ap;
9041 int nparam;
9042
9043 for (nparam = 0 ; argv[nparam] ; nparam++);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00009044 ap = newparam = xmalloc((nparam + 1) * sizeof *ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009045 while (*argv) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00009046 *ap++ = xstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +00009047 }
9048 *ap = NULL;
9049 freeparam(&shellparam);
9050 shellparam.malloc = 1;
9051 shellparam.nparam = nparam;
9052 shellparam.p = newparam;
9053 shellparam.optind = 1;
9054 shellparam.optoff = -1;
9055}
9056
9057
9058/*
9059 * Free the list of positional parameters.
9060 */
9061
9062static void
Eric Andersen2870d962001-07-02 17:27:21 +00009063freeparam(volatile struct shparam *param)
9064{
Eric Andersencb57d552001-06-28 07:25:16 +00009065 char **ap;
9066
9067 if (param->malloc) {
9068 for (ap = param->p ; *ap ; ap++)
9069 ckfree(*ap);
9070 ckfree(param->p);
9071 }
9072}
9073
9074
9075
9076/*
9077 * The shift builtin command.
9078 */
9079
9080static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00009081shiftcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009082{
9083 int n;
9084 char **ap1, **ap2;
9085
9086 n = 1;
9087 if (argc > 1)
9088 n = number(argv[1]);
9089 if (n > shellparam.nparam)
9090 error("can't shift that many");
9091 INTOFF;
9092 shellparam.nparam -= n;
9093 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
9094 if (shellparam.malloc)
9095 ckfree(*ap1);
9096 }
9097 ap2 = shellparam.p;
9098 while ((*ap2++ = *ap1++) != NULL);
9099 shellparam.optind = 1;
9100 shellparam.optoff = -1;
9101 INTON;
9102 return 0;
9103}
9104
9105
9106
9107/*
9108 * The set command builtin.
9109 */
9110
9111static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00009112setcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009113{
9114 if (argc == 1)
9115 return showvarscmd(argc, argv);
9116 INTOFF;
9117 options(0);
9118 optschanged();
9119 if (*argptr != NULL) {
9120 setparam(argptr);
9121 }
9122 INTON;
9123 return 0;
9124}
9125
9126
9127static void
Eric Andersen2870d962001-07-02 17:27:21 +00009128getoptsreset(const char *value)
Eric Andersencb57d552001-06-28 07:25:16 +00009129{
9130 shellparam.optind = number(value);
9131 shellparam.optoff = -1;
9132}
9133
Eric Andersenbdfd0d72001-10-24 05:00:29 +00009134#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00009135static void change_lc_all(const char *value)
9136{
9137 if(value != 0 && *value != 0)
9138 setlocale(LC_ALL, value);
9139}
9140
9141static void change_lc_ctype(const char *value)
9142{
9143 if(value != 0 && *value != 0)
9144 setlocale(LC_CTYPE, value);
9145}
9146
9147#endif
9148
Eric Andersencb57d552001-06-28 07:25:16 +00009149#ifdef ASH_GETOPTS
9150/*
9151 * The getopts builtin. Shellparam.optnext points to the next argument
9152 * to be processed. Shellparam.optptr points to the next character to
9153 * be processed in the current argument. If shellparam.optnext is NULL,
9154 * then it's the first time getopts has been called.
9155 */
9156
9157static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00009158getoptscmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009159{
9160 char **optbase;
9161
9162 if (argc < 3)
9163 error("Usage: getopts optstring var [arg]");
9164 else if (argc == 3) {
9165 optbase = shellparam.p;
9166 if (shellparam.optind > shellparam.nparam + 1) {
9167 shellparam.optind = 1;
9168 shellparam.optoff = -1;
9169 }
9170 }
9171 else {
9172 optbase = &argv[3];
9173 if (shellparam.optind > argc - 2) {
9174 shellparam.optind = 1;
9175 shellparam.optoff = -1;
9176 }
9177 }
9178
9179 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9180 &shellparam.optoff);
9181}
9182
9183/*
9184 * Safe version of setvar, returns 1 on success 0 on failure.
9185 */
9186
9187static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00009188setvarsafe(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009189{
9190 struct jmploc jmploc;
9191 struct jmploc *volatile savehandler = handler;
9192 int err = 0;
9193#ifdef __GNUC__
9194 (void) &err;
9195#endif
9196
9197 if (setjmp(jmploc.loc))
9198 err = 1;
9199 else {
9200 handler = &jmploc;
9201 setvar(name, val, flags);
9202 }
9203 handler = savehandler;
9204 return err;
9205}
9206
9207static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00009208getopts(char *optstr, char *optvar, char **optfirst, int *myoptind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009209{
9210 char *p, *q;
9211 char c = '?';
9212 int done = 0;
9213 int err = 0;
9214 char s[10];
9215 char **optnext = optfirst + *myoptind - 1;
9216
9217 if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
9218 strlen(*(optnext - 1)) < *optoff)
9219 p = NULL;
9220 else
9221 p = *(optnext - 1) + *optoff;
9222 if (p == NULL || *p == '\0') {
9223 /* Current word is done, advance */
9224 if (optnext == NULL)
9225 return 1;
9226 p = *optnext;
9227 if (p == NULL || *p != '-' || *++p == '\0') {
9228atend:
9229 *myoptind = optnext - optfirst + 1;
9230 p = NULL;
9231 done = 1;
9232 goto out;
9233 }
9234 optnext++;
Eric Andersen2870d962001-07-02 17:27:21 +00009235 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009236 goto atend;
9237 }
9238
9239 c = *p++;
9240 for (q = optstr; *q != c; ) {
9241 if (*q == '\0') {
9242 if (optstr[0] == ':') {
9243 s[0] = c;
9244 s[1] = '\0';
9245 err |= setvarsafe("OPTARG", s, 0);
9246 }
9247 else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009248 out2fmt("Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009249 (void) unsetvar("OPTARG");
9250 }
9251 c = '?';
9252 goto bad;
9253 }
9254 if (*++q == ':')
9255 q++;
9256 }
9257
9258 if (*++q == ':') {
9259 if (*p == '\0' && (p = *optnext) == NULL) {
9260 if (optstr[0] == ':') {
9261 s[0] = c;
9262 s[1] = '\0';
9263 err |= setvarsafe("OPTARG", s, 0);
9264 c = ':';
9265 }
9266 else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009267 out2fmt("No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009268 (void) unsetvar("OPTARG");
9269 c = '?';
9270 }
9271 goto bad;
9272 }
9273
9274 if (p == *optnext)
9275 optnext++;
9276 setvarsafe("OPTARG", p, 0);
9277 p = NULL;
9278 }
9279 else
9280 setvarsafe("OPTARG", "", 0);
9281 *myoptind = optnext - optfirst + 1;
9282 goto out;
9283
9284bad:
9285 *myoptind = 1;
9286 p = NULL;
9287out:
9288 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersen3102ac42001-07-06 04:26:23 +00009289 snprintf(s, sizeof(s), "%d", *myoptind);
Eric Andersencb57d552001-06-28 07:25:16 +00009290 err |= setvarsafe("OPTIND", s, VNOFUNC);
9291 s[0] = c;
9292 s[1] = '\0';
9293 err |= setvarsafe(optvar, s, 0);
9294 if (err) {
9295 *myoptind = 1;
9296 *optoff = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00009297 exraise(EXERROR);
9298 }
9299 return done;
9300}
Eric Andersen2870d962001-07-02 17:27:21 +00009301#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009302
9303/*
9304 * XXX - should get rid of. have all builtins use getopt(3). the
9305 * library getopt must have the BSD extension static variable "optreset"
9306 * otherwise it can't be used within the shell safely.
9307 *
9308 * Standard option processing (a la getopt) for builtin routines. The
9309 * only argument that is passed to nextopt is the option string; the
9310 * other arguments are unnecessary. It return the character, or '\0' on
9311 * end of input.
9312 */
9313
9314static int
Eric Andersen62483552001-07-10 06:09:16 +00009315nextopt(const char *optstring)
9316{
Eric Andersencb57d552001-06-28 07:25:16 +00009317 char *p;
9318 const char *q;
9319 char c;
9320
9321 if ((p = optptr) == NULL || *p == '\0') {
9322 p = *argptr;
9323 if (p == NULL || *p != '-' || *++p == '\0')
9324 return '\0';
9325 argptr++;
Eric Andersen2870d962001-07-02 17:27:21 +00009326 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009327 return '\0';
9328 }
9329 c = *p++;
9330 for (q = optstring ; *q != c ; ) {
9331 if (*q == '\0')
9332 error("Illegal option -%c", c);
9333 if (*++q == ':')
9334 q++;
9335 }
9336 if (*++q == ':') {
9337 if (*p == '\0' && (p = *argptr++) == NULL)
9338 error("No arg for -%c option", c);
9339 optionarg = p;
9340 p = NULL;
9341 }
9342 optptr = p;
9343 return c;
9344}
9345
Eric Andersencb57d552001-06-28 07:25:16 +00009346static void
9347flushall() {
Eric Andersencb57d552001-06-28 07:25:16 +00009348 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009349 fflush(stdout);
Eric Andersencb57d552001-06-28 07:25:16 +00009350 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009351}
9352
9353
9354static void
Eric Andersen3102ac42001-07-06 04:26:23 +00009355out2fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009356{
9357 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00009358 va_start(ap, fmt);
Eric Andersen3102ac42001-07-06 04:26:23 +00009359 vfprintf(stderr, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009360 va_end(ap);
9361}
9362
Eric Andersencb57d552001-06-28 07:25:16 +00009363/*
9364 * Version of write which resumes after a signal is caught.
9365 */
9366
9367static int
Eric Andersen2870d962001-07-02 17:27:21 +00009368xwrite(int fd, const char *buf, int nbytes)
9369{
Eric Andersencb57d552001-06-28 07:25:16 +00009370 int ntry;
9371 int i;
9372 int n;
9373
9374 n = nbytes;
9375 ntry = 0;
9376 for (;;) {
9377 i = write(fd, buf, n);
9378 if (i > 0) {
9379 if ((n -= i) <= 0)
9380 return nbytes;
9381 buf += i;
9382 ntry = 0;
9383 } else if (i == 0) {
9384 if (++ntry > 10)
9385 return nbytes - n;
9386 } else if (errno != EINTR) {
9387 return -1;
9388 }
9389 }
9390}
9391
9392
Eric Andersencb57d552001-06-28 07:25:16 +00009393/*
9394 * Shell command parser.
9395 */
9396
9397#define EOFMARKLEN 79
9398
9399
9400
9401struct heredoc {
Eric Andersen2870d962001-07-02 17:27:21 +00009402 struct heredoc *next; /* next here document in list */
9403 union node *here; /* redirection node */
9404 char *eofmark; /* string indicating end of input */
9405 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009406};
9407
Eric Andersen2870d962001-07-02 17:27:21 +00009408static struct heredoc *heredoclist; /* list of here documents to read */
9409static int parsebackquote; /* nonzero if we are inside backquotes */
9410static int doprompt; /* if set, prompt the user */
9411static int needprompt; /* true if interactive and at start of line */
9412static int lasttoken; /* last token read */
Eric Andersencb57d552001-06-28 07:25:16 +00009413
Eric Andersen2870d962001-07-02 17:27:21 +00009414static char *wordtext; /* text of last word returned by readtoken */
Eric Andersencb57d552001-06-28 07:25:16 +00009415
Eric Andersen2870d962001-07-02 17:27:21 +00009416static struct nodelist *backquotelist;
9417static union node *redirnode;
Eric Andersen044228d2001-07-17 01:12:36 +00009418static struct heredoc *heredoc;
Eric Andersen2870d962001-07-02 17:27:21 +00009419static int quoteflag; /* set if (part of) last token was quoted */
9420static int startlinno; /* line # where last token started */
Eric Andersencb57d552001-06-28 07:25:16 +00009421
9422
Eric Andersen2870d962001-07-02 17:27:21 +00009423static union node *list (int);
9424static union node *andor (void);
9425static union node *pipeline (void);
9426static union node *command (void);
Eric Andersena3483db2001-10-24 08:01:06 +00009427static union node *simplecmd(union node **rpp, union node *redir);
Eric Andersen2870d962001-07-02 17:27:21 +00009428static void parsefname (void);
9429static void parseheredoc (void);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009430static char peektoken (void);
Eric Andersen2870d962001-07-02 17:27:21 +00009431static int readtoken (void);
9432static int xxreadtoken (void);
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009433static int readtoken1 (int, int, const char *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00009434static int noexpand (char *);
9435static void synexpect (int) __attribute__((noreturn));
9436static void synerror (const char *) __attribute__((noreturn));
9437static void setprompt (int);
Eric Andersencb57d552001-06-28 07:25:16 +00009438
9439
9440/*
9441 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9442 * valid parse tree indicating a blank line.)
9443 */
9444
Eric Andersen2870d962001-07-02 17:27:21 +00009445static union node *
Eric Andersencb57d552001-06-28 07:25:16 +00009446parsecmd(int interact)
9447{
9448 int t;
9449
9450 tokpushback = 0;
9451 doprompt = interact;
9452 if (doprompt)
9453 setprompt(1);
9454 else
9455 setprompt(0);
9456 needprompt = 0;
9457 t = readtoken();
9458 if (t == TEOF)
9459 return NEOF;
9460 if (t == TNL)
9461 return NULL;
9462 tokpushback++;
9463 return list(1);
9464}
9465
9466
9467static union node *
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00009468list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +00009469{
9470 union node *n1, *n2, *n3;
9471 int tok;
9472
9473 checkkwd = 2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009474 if (nlflag == 0 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009475 return NULL;
9476 n1 = NULL;
9477 for (;;) {
9478 n2 = andor();
9479 tok = readtoken();
9480 if (tok == TBACKGND) {
9481 if (n2->type == NCMD || n2->type == NPIPE) {
9482 n2->ncmd.backgnd = 1;
9483 } else if (n2->type == NREDIR) {
9484 n2->type = NBACKGND;
9485 } else {
9486 n3 = (union node *)stalloc(sizeof (struct nredir));
9487 n3->type = NBACKGND;
9488 n3->nredir.n = n2;
9489 n3->nredir.redirect = NULL;
9490 n2 = n3;
9491 }
9492 }
9493 if (n1 == NULL) {
9494 n1 = n2;
9495 }
9496 else {
9497 n3 = (union node *)stalloc(sizeof (struct nbinary));
9498 n3->type = NSEMI;
9499 n3->nbinary.ch1 = n1;
9500 n3->nbinary.ch2 = n2;
9501 n1 = n3;
9502 }
9503 switch (tok) {
9504 case TBACKGND:
9505 case TSEMI:
9506 tok = readtoken();
9507 /* fall through */
9508 case TNL:
9509 if (tok == TNL) {
9510 parseheredoc();
9511 if (nlflag)
9512 return n1;
9513 } else {
9514 tokpushback++;
9515 }
9516 checkkwd = 2;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009517 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009518 return n1;
9519 break;
9520 case TEOF:
9521 if (heredoclist)
9522 parseheredoc();
9523 else
Eric Andersen2870d962001-07-02 17:27:21 +00009524 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009525 return n1;
9526 default:
9527 if (nlflag)
9528 synexpect(-1);
9529 tokpushback++;
9530 return n1;
9531 }
9532 }
9533}
9534
9535
9536
9537static union node *
9538andor() {
9539 union node *n1, *n2, *n3;
9540 int t;
9541
9542 checkkwd = 1;
9543 n1 = pipeline();
9544 for (;;) {
9545 if ((t = readtoken()) == TAND) {
9546 t = NAND;
9547 } else if (t == TOR) {
9548 t = NOR;
9549 } else {
9550 tokpushback++;
9551 return n1;
9552 }
9553 checkkwd = 2;
9554 n2 = pipeline();
9555 n3 = (union node *)stalloc(sizeof (struct nbinary));
9556 n3->type = t;
9557 n3->nbinary.ch1 = n1;
9558 n3->nbinary.ch2 = n2;
9559 n1 = n3;
9560 }
9561}
9562
9563
9564
9565static union node *
9566pipeline() {
9567 union node *n1, *n2, *pipenode;
9568 struct nodelist *lp, *prev;
9569 int negate;
9570
9571 negate = 0;
9572 TRACE(("pipeline: entered\n"));
9573 if (readtoken() == TNOT) {
9574 negate = !negate;
9575 checkkwd = 1;
9576 } else
9577 tokpushback++;
9578 n1 = command();
9579 if (readtoken() == TPIPE) {
9580 pipenode = (union node *)stalloc(sizeof (struct npipe));
9581 pipenode->type = NPIPE;
9582 pipenode->npipe.backgnd = 0;
9583 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9584 pipenode->npipe.cmdlist = lp;
9585 lp->n = n1;
9586 do {
9587 prev = lp;
9588 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9589 checkkwd = 2;
9590 lp->n = command();
9591 prev->next = lp;
9592 } while (readtoken() == TPIPE);
9593 lp->next = NULL;
9594 n1 = pipenode;
9595 }
9596 tokpushback++;
9597 if (negate) {
9598 n2 = (union node *)stalloc(sizeof (struct nnot));
9599 n2->type = NNOT;
9600 n2->nnot.com = n1;
9601 return n2;
9602 } else
9603 return n1;
9604}
9605
9606
9607
9608static union node *
Eric Andersena3483db2001-10-24 08:01:06 +00009609command(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009610 union node *n1, *n2;
9611 union node *ap, **app;
9612 union node *cp, **cpp;
9613 union node *redir, **rpp;
9614 int t;
9615
9616 redir = NULL;
9617 n1 = NULL;
9618 rpp = &redir;
9619
Eric Andersen88cec252001-09-06 17:35:20 +00009620 /* Check for redirection which may precede command */
9621 while (readtoken() == TREDIR) {
9622 *rpp = n2 = redirnode;
9623 rpp = &n2->nfile.next;
9624 parsefname();
9625 }
9626 tokpushback++;
9627
Eric Andersencb57d552001-06-28 07:25:16 +00009628 switch (readtoken()) {
9629 case TIF:
9630 n1 = (union node *)stalloc(sizeof (struct nif));
9631 n1->type = NIF;
9632 n1->nif.test = list(0);
9633 if (readtoken() != TTHEN)
9634 synexpect(TTHEN);
9635 n1->nif.ifpart = list(0);
9636 n2 = n1;
9637 while (readtoken() == TELIF) {
9638 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9639 n2 = n2->nif.elsepart;
9640 n2->type = NIF;
9641 n2->nif.test = list(0);
9642 if (readtoken() != TTHEN)
9643 synexpect(TTHEN);
9644 n2->nif.ifpart = list(0);
9645 }
9646 if (lasttoken == TELSE)
9647 n2->nif.elsepart = list(0);
9648 else {
9649 n2->nif.elsepart = NULL;
9650 tokpushback++;
9651 }
9652 if (readtoken() != TFI)
9653 synexpect(TFI);
9654 checkkwd = 1;
9655 break;
9656 case TWHILE:
9657 case TUNTIL: {
9658 int got;
9659 n1 = (union node *)stalloc(sizeof (struct nbinary));
9660 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9661 n1->nbinary.ch1 = list(0);
9662 if ((got=readtoken()) != TDO) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009663TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009664 synexpect(TDO);
9665 }
9666 n1->nbinary.ch2 = list(0);
9667 if (readtoken() != TDONE)
9668 synexpect(TDONE);
9669 checkkwd = 1;
9670 break;
9671 }
9672 case TFOR:
9673 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9674 synerror("Bad for loop variable");
9675 n1 = (union node *)stalloc(sizeof (struct nfor));
9676 n1->type = NFOR;
9677 n1->nfor.var = wordtext;
9678 checkkwd = 1;
9679 if (readtoken() == TIN) {
9680 app = &ap;
9681 while (readtoken() == TWORD) {
9682 n2 = (union node *)stalloc(sizeof (struct narg));
9683 n2->type = NARG;
9684 n2->narg.text = wordtext;
9685 n2->narg.backquote = backquotelist;
9686 *app = n2;
9687 app = &n2->narg.next;
9688 }
9689 *app = NULL;
9690 n1->nfor.args = ap;
9691 if (lasttoken != TNL && lasttoken != TSEMI)
9692 synexpect(-1);
9693 } else {
9694 static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
9695 '@', '=', '\0'};
9696 n2 = (union node *)stalloc(sizeof (struct narg));
9697 n2->type = NARG;
9698 n2->narg.text = argvars;
9699 n2->narg.backquote = NULL;
9700 n2->narg.next = NULL;
9701 n1->nfor.args = n2;
9702 /*
9703 * Newline or semicolon here is optional (but note
9704 * that the original Bourne shell only allowed NL).
9705 */
9706 if (lasttoken != TNL && lasttoken != TSEMI)
9707 tokpushback++;
9708 }
9709 checkkwd = 2;
9710 if (readtoken() != TDO)
9711 synexpect(TDO);
9712 n1->nfor.body = list(0);
9713 if (readtoken() != TDONE)
9714 synexpect(TDONE);
9715 checkkwd = 1;
9716 break;
9717 case TCASE:
9718 n1 = (union node *)stalloc(sizeof (struct ncase));
9719 n1->type = NCASE;
9720 if (readtoken() != TWORD)
9721 synexpect(TWORD);
9722 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9723 n2->type = NARG;
9724 n2->narg.text = wordtext;
9725 n2->narg.backquote = backquotelist;
9726 n2->narg.next = NULL;
9727 do {
9728 checkkwd = 1;
9729 } while (readtoken() == TNL);
9730 if (lasttoken != TIN)
9731 synerror("expecting \"in\"");
9732 cpp = &n1->ncase.cases;
9733 checkkwd = 2, readtoken();
9734 do {
9735 if (lasttoken == TLP)
9736 readtoken();
9737 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9738 cp->type = NCLIST;
9739 app = &cp->nclist.pattern;
9740 for (;;) {
9741 *app = ap = (union node *)stalloc(sizeof (struct narg));
9742 ap->type = NARG;
9743 ap->narg.text = wordtext;
9744 ap->narg.backquote = backquotelist;
9745 if (checkkwd = 2, readtoken() != TPIPE)
9746 break;
9747 app = &ap->narg.next;
9748 readtoken();
9749 }
9750 ap->narg.next = NULL;
9751 if (lasttoken != TRP)
9752 synexpect(TRP);
9753 cp->nclist.body = list(0);
9754
9755 checkkwd = 2;
9756 if ((t = readtoken()) != TESAC) {
9757 if (t != TENDCASE)
9758 synexpect(TENDCASE);
9759 else
9760 checkkwd = 2, readtoken();
9761 }
9762 cpp = &cp->nclist.next;
9763 } while(lasttoken != TESAC);
9764 *cpp = NULL;
9765 checkkwd = 1;
9766 break;
9767 case TLP:
9768 n1 = (union node *)stalloc(sizeof (struct nredir));
9769 n1->type = NSUBSHELL;
9770 n1->nredir.n = list(0);
9771 n1->nredir.redirect = NULL;
9772 if (readtoken() != TRP)
9773 synexpect(TRP);
9774 checkkwd = 1;
9775 break;
9776 case TBEGIN:
9777 n1 = list(0);
9778 if (readtoken() != TEND)
9779 synexpect(TEND);
9780 checkkwd = 1;
9781 break;
9782 /* Handle an empty command like other simple commands. */
9783 case TSEMI:
9784 case TAND:
9785 case TOR:
9786 case TNL:
9787 case TEOF:
9788 case TRP:
9789 case TBACKGND:
9790 /*
9791 * An empty command before a ; doesn't make much sense, and
9792 * should certainly be disallowed in the case of `if ;'.
9793 */
9794 if (!redir)
9795 synexpect(-1);
9796 case TWORD:
Eric Andersencb57d552001-06-28 07:25:16 +00009797 tokpushback++;
Eric Andersena3483db2001-10-24 08:01:06 +00009798 n1 = simplecmd(rpp, redir);
Eric Andersencb57d552001-06-28 07:25:16 +00009799 return n1;
9800 default:
9801 synexpect(-1);
9802 /* NOTREACHED */
9803 }
9804
9805 /* Now check for redirection which may follow command */
9806 while (readtoken() == TREDIR) {
9807 *rpp = n2 = redirnode;
9808 rpp = &n2->nfile.next;
9809 parsefname();
9810 }
9811 tokpushback++;
9812 *rpp = NULL;
9813 if (redir) {
9814 if (n1->type != NSUBSHELL) {
9815 n2 = (union node *)stalloc(sizeof (struct nredir));
9816 n2->type = NREDIR;
9817 n2->nredir.n = n1;
9818 n1 = n2;
9819 }
9820 n1->nredir.redirect = redir;
9821 }
9822
9823 return n1;
9824}
9825
9826
9827static union node *
Eric Andersena3483db2001-10-24 08:01:06 +00009828simplecmd(union node **rpp, union node *redir) {
Eric Andersencb57d552001-06-28 07:25:16 +00009829 union node *args, **app;
9830 union node *n = NULL;
9831 union node *vars, **vpp;
Eric Andersena3483db2001-10-24 08:01:06 +00009832 union node **orig_rpp;
Eric Andersencb57d552001-06-28 07:25:16 +00009833
9834 args = NULL;
9835 app = &args;
9836 vars = NULL;
9837 vpp = &vars;
Eric Andersena3483db2001-10-24 08:01:06 +00009838
9839 /* If we don't have any redirections already, then we must reset
9840 rpp to be the address of the local redir variable. */
9841 if (redir == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00009842 rpp = &redir;
Eric Andersena3483db2001-10-24 08:01:06 +00009843 /* We save the incoming value, because we need this for shell
9844 functions. There can not be a redirect or an argument between
9845 the function name and the open parenthesis. */
9846 orig_rpp = rpp;
Eric Andersencb57d552001-06-28 07:25:16 +00009847
9848 checkalias = 2;
9849 for (;;) {
9850 switch (readtoken()) {
9851 case TWORD:
9852 case TASSIGN:
9853 n = (union node *)stalloc(sizeof (struct narg));
9854 n->type = NARG;
9855 n->narg.text = wordtext;
9856 n->narg.backquote = backquotelist;
9857 if (lasttoken == TWORD) {
9858 *app = n;
9859 app = &n->narg.next;
9860 } else {
9861 *vpp = n;
9862 vpp = &n->narg.next;
9863 }
9864 break;
9865 case TREDIR:
9866 *rpp = n = redirnode;
9867 rpp = &n->nfile.next;
Eric Andersen2870d962001-07-02 17:27:21 +00009868 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +00009869 break;
9870 case TLP:
9871 if (
9872 args && app == &args->narg.next &&
Eric Andersena3483db2001-10-24 08:01:06 +00009873 !vars && rpp == orig_rpp
Eric Andersencb57d552001-06-28 07:25:16 +00009874 ) {
9875 /* We have a function */
9876 if (readtoken() != TRP)
9877 synexpect(TRP);
Eric Andersencb57d552001-06-28 07:25:16 +00009878 n->type = NDEFUN;
9879 checkkwd = 2;
9880 n->narg.next = command();
9881 return n;
9882 }
9883 /* fall through */
9884 default:
9885 tokpushback++;
9886 goto out;
9887 }
9888 }
9889out:
9890 *app = NULL;
9891 *vpp = NULL;
9892 *rpp = NULL;
9893 n = (union node *)stalloc(sizeof (struct ncmd));
9894 n->type = NCMD;
9895 n->ncmd.backgnd = 0;
9896 n->ncmd.args = args;
9897 n->ncmd.assign = vars;
9898 n->ncmd.redirect = redir;
9899 return n;
9900}
9901
9902static union node *
Eric Andersen2870d962001-07-02 17:27:21 +00009903makename(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009904 union node *n;
9905
9906 n = (union node *)stalloc(sizeof (struct narg));
9907 n->type = NARG;
9908 n->narg.next = NULL;
9909 n->narg.text = wordtext;
9910 n->narg.backquote = backquotelist;
9911 return n;
9912}
9913
9914static void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +00009915{
Eric Andersencb57d552001-06-28 07:25:16 +00009916 TRACE(("Fix redir %s %d\n", text, err));
9917 if (!err)
9918 n->ndup.vname = NULL;
9919
9920 if (is_digit(text[0]) && text[1] == '\0')
9921 n->ndup.dupfd = digit_val(text[0]);
9922 else if (text[0] == '-' && text[1] == '\0')
9923 n->ndup.dupfd = -1;
9924 else {
9925
9926 if (err)
9927 synerror("Bad fd number");
9928 else
9929 n->ndup.vname = makename();
9930 }
9931}
9932
9933
9934static void
Eric Andersen2870d962001-07-02 17:27:21 +00009935parsefname(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009936 union node *n = redirnode;
9937
9938 if (readtoken() != TWORD)
9939 synexpect(-1);
9940 if (n->type == NHERE) {
9941 struct heredoc *here = heredoc;
9942 struct heredoc *p;
9943 int i;
9944
9945 if (quoteflag == 0)
9946 n->type = NXHERE;
9947 TRACE(("Here document %d\n", n->type));
9948 if (here->striptabs) {
9949 while (*wordtext == '\t')
9950 wordtext++;
9951 }
9952 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9953 synerror("Illegal eof marker for << redirection");
9954 rmescapes(wordtext);
9955 here->eofmark = wordtext;
9956 here->next = NULL;
9957 if (heredoclist == NULL)
9958 heredoclist = here;
9959 else {
9960 for (p = heredoclist ; p->next ; p = p->next);
9961 p->next = here;
9962 }
9963 } else if (n->type == NTOFD || n->type == NFROMFD) {
9964 fixredir(n, wordtext, 0);
9965 } else {
9966 n->nfile.fname = makename();
9967 }
9968}
9969
9970
9971/*
9972 * Input any here documents.
9973 */
9974
9975static void
9976parseheredoc() {
9977 struct heredoc *here;
9978 union node *n;
9979
9980 while (heredoclist) {
9981 here = heredoclist;
9982 heredoclist = here->next;
9983 if (needprompt) {
9984 setprompt(2);
9985 needprompt = 0;
9986 }
9987 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9988 here->eofmark, here->striptabs);
9989 n = (union node *)stalloc(sizeof (struct narg));
9990 n->narg.type = NARG;
9991 n->narg.next = NULL;
9992 n->narg.text = wordtext;
9993 n->narg.backquote = backquotelist;
9994 here->here->nhere.doc = n;
9995 }
9996}
9997
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009998static char
Eric Andersencb57d552001-06-28 07:25:16 +00009999peektoken() {
10000 int t;
10001
10002 t = readtoken();
10003 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010004 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +000010005}
10006
10007static int
10008readtoken() {
10009 int t;
Eric Andersen7467c8d2001-07-12 20:26:32 +000010010
Eric Andersen2870d962001-07-02 17:27:21 +000010011#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010012 int savecheckalias = checkalias;
Eric Andersen7467c8d2001-07-12 20:26:32 +000010013 int savecheckkwd = checkkwd;
Eric Andersencb57d552001-06-28 07:25:16 +000010014 struct alias *ap;
Eric Andersen2870d962001-07-02 17:27:21 +000010015#endif
10016
Eric Andersencb57d552001-06-28 07:25:16 +000010017#ifdef DEBUG
10018 int alreadyseen = tokpushback;
10019#endif
10020
Eric Andersen2870d962001-07-02 17:27:21 +000010021#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010022top:
Eric Andersen2870d962001-07-02 17:27:21 +000010023#endif
10024
Eric Andersencb57d552001-06-28 07:25:16 +000010025 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +000010026
10027#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010028 checkalias = savecheckalias;
Eric Andersen2870d962001-07-02 17:27:21 +000010029#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010030
10031 if (checkkwd) {
10032 /*
10033 * eat newlines
10034 */
10035 if (checkkwd == 2) {
10036 checkkwd = 0;
10037 while (t == TNL) {
10038 parseheredoc();
10039 t = xxreadtoken();
10040 }
10041 }
10042 checkkwd = 0;
10043 /*
10044 * check for keywords
10045 */
10046 if (t == TWORD && !quoteflag)
10047 {
10048 const char *const *pp;
10049
10050 if ((pp = findkwd(wordtext))) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010051 lasttoken = t = pp - tokname_array;
10052 TRACE(("keyword %s recognized\n", tokname(t)));
Eric Andersencb57d552001-06-28 07:25:16 +000010053 goto out;
10054 }
10055 }
10056 }
10057
Eric Andersen7467c8d2001-07-12 20:26:32 +000010058
Eric Andersencb57d552001-06-28 07:25:16 +000010059 if (t != TWORD) {
10060 if (t != TREDIR) {
10061 checkalias = 0;
10062 }
10063 } else if (checkalias == 2 && isassignment(wordtext)) {
10064 lasttoken = t = TASSIGN;
Eric Andersen7467c8d2001-07-12 20:26:32 +000010065#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010066 } else if (checkalias) {
Eric Andersenec074692001-10-31 11:05:49 +000010067 if (!quoteflag && (ap = *__lookupalias(wordtext)) != NULL && !(ap->flag & ALIASINUSE)) {
Eric Andersencb57d552001-06-28 07:25:16 +000010068 if (*ap->val) {
10069 pushstring(ap->val, strlen(ap->val), ap);
10070 }
10071 checkkwd = savecheckkwd;
10072 goto top;
10073 }
10074 checkalias = 0;
Eric Andersen2870d962001-07-02 17:27:21 +000010075#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +000010076 }
Eric Andersencb57d552001-06-28 07:25:16 +000010077out:
10078#ifdef DEBUG
10079 if (!alreadyseen)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010080 TRACE(("token %s %s\n", tokname(t), t == TWORD || t == TASSIGN ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +000010081 else
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010082 TRACE(("reread token %s %s\n", tokname(t), t == TWORD || t == TASSIGN ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +000010083#endif
10084 return (t);
10085}
10086
10087
10088/*
10089 * Read the next input token.
10090 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +000010091 * backquotes. We set quoteflag to true if any part of the word was
10092 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +000010093 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +000010094 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +000010095 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +000010096 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +000010097 *
10098 * [Change comment: here documents and internal procedures]
10099 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10100 * word parsing code into a separate routine. In this case, readtoken
10101 * doesn't need to have any internal procedures, but parseword does.
10102 * We could also make parseoperator in essence the main routine, and
10103 * have parseword (readtoken1?) handle both words and redirection.]
10104 */
10105
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +000010106#define NEW_xxreadtoken
10107#ifdef NEW_xxreadtoken
10108
10109static const char xxreadtoken_chars[] = "\n()&|;"; /* singles must be first! */
10110static const char xxreadtoken_tokens[] = {
10111 TNL, TLP, TRP, /* only single occurrence allowed */
10112 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10113 TEOF, /* corresponds to trailing nul */
10114 TAND, TOR, TENDCASE, /* if double occurrence */
10115};
10116
10117#define xxreadtoken_doubles \
10118 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10119#define xxreadtoken_singles \
10120 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10121
10122static int
10123xxreadtoken() {
10124 int c;
10125
10126 if (tokpushback) {
10127 tokpushback = 0;
10128 return lasttoken;
10129 }
10130 if (needprompt) {
10131 setprompt(2);
10132 needprompt = 0;
10133 }
10134 startlinno = plinno;
10135 for (;;) { /* until token or start of word found */
10136 c = pgetc_macro();
10137
10138 if ((c!=' ') && (c!='\t')
10139#ifdef ASH_ALIAS
10140 && (c!=PEOA)
10141#endif
10142 ) {
10143 if (c=='#') {
10144 while ((c = pgetc()) != '\n' && c != PEOF);
10145 pungetc();
10146 } else if (c=='\\') {
10147 if (pgetc() != '\n') {
10148 pungetc();
10149 goto READTOKEN1;
10150 }
10151 startlinno = ++plinno;
10152 setprompt(doprompt ? 2 : 0);
10153 } else {
10154 const char *p
10155 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10156
10157 if (c!=PEOF) {
10158 if (c=='\n') {
10159 plinno++;
10160 needprompt = doprompt;
10161 }
10162
10163 p = strchr(xxreadtoken_chars, c);
10164 if (p == NULL) {
10165 READTOKEN1:
10166 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10167 }
10168
10169 if (p-xxreadtoken_chars >= xxreadtoken_singles) {
10170 if (pgetc() == *p) { /* double occurrence? */
10171 p += xxreadtoken_doubles + 1;
10172 } else {
10173 pungetc();
10174 }
10175 }
10176 }
10177
10178 return lasttoken = xxreadtoken_tokens[p-xxreadtoken_chars];
10179 }
10180 }
10181 }
10182}
10183
10184
10185#else
Eric Andersen2870d962001-07-02 17:27:21 +000010186#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010187
10188static int
10189xxreadtoken() {
10190 int c;
10191
10192 if (tokpushback) {
10193 tokpushback = 0;
10194 return lasttoken;
10195 }
10196 if (needprompt) {
10197 setprompt(2);
10198 needprompt = 0;
10199 }
10200 startlinno = plinno;
Eric Andersen2870d962001-07-02 17:27:21 +000010201 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010202 c = pgetc_macro();
10203 switch (c) {
10204 case ' ': case '\t':
Eric Andersen3102ac42001-07-06 04:26:23 +000010205#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010206 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010207#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010208 continue;
10209 case '#':
10210 while ((c = pgetc()) != '\n' && c != PEOF);
10211 pungetc();
10212 continue;
10213 case '\\':
10214 if (pgetc() == '\n') {
10215 startlinno = ++plinno;
10216 if (doprompt)
10217 setprompt(2);
10218 else
10219 setprompt(0);
10220 continue;
10221 }
10222 pungetc();
10223 goto breakloop;
10224 case '\n':
10225 plinno++;
10226 needprompt = doprompt;
10227 RETURN(TNL);
10228 case PEOF:
10229 RETURN(TEOF);
10230 case '&':
10231 if (pgetc() == '&')
10232 RETURN(TAND);
10233 pungetc();
10234 RETURN(TBACKGND);
10235 case '|':
10236 if (pgetc() == '|')
10237 RETURN(TOR);
10238 pungetc();
10239 RETURN(TPIPE);
10240 case ';':
10241 if (pgetc() == ';')
10242 RETURN(TENDCASE);
10243 pungetc();
10244 RETURN(TSEMI);
10245 case '(':
10246 RETURN(TLP);
10247 case ')':
10248 RETURN(TRP);
10249 default:
10250 goto breakloop;
10251 }
10252 }
10253breakloop:
10254 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10255#undef RETURN
10256}
Manuel Novoa III 8d0afde2001-09-11 01:14:02 +000010257#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010258
Eric Andersencb57d552001-06-28 07:25:16 +000010259/*
10260 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10261 * is not NULL, read a here document. In the latter case, eofmark is the
10262 * word which marks the end of the document and striptabs is true if
10263 * leading tabs should be stripped from the document. The argument firstc
10264 * is the first character of the input token or document.
10265 *
10266 * Because C does not have internal subroutines, I have simulated them
10267 * using goto's to implement the subroutine linkage. The following macros
10268 * will run code that appears at the end of readtoken1.
10269 */
10270
Eric Andersen2870d962001-07-02 17:27:21 +000010271#define CHECKEND() {goto checkend; checkend_return:;}
10272#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10273#define PARSESUB() {goto parsesub; parsesub_return:;}
10274#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10275#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10276#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010277
10278static int
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010279readtoken1(int firstc, int syntax, const char *eofmark, int striptabs)
10280{
Eric Andersencb57d552001-06-28 07:25:16 +000010281 int c = firstc;
10282 char *out;
10283 int len;
10284 char line[EOFMARKLEN + 1];
10285 struct nodelist *bqlist;
10286 int quotef;
10287 int dblquote;
Eric Andersen2870d962001-07-02 17:27:21 +000010288 int varnest; /* levels of variables expansion */
10289 int arinest; /* levels of arithmetic expansion */
10290 int parenlevel; /* levels of parens in arithmetic */
10291 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +000010292 int oldstyle;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010293 int prevsyntax; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010294#if __GNUC__
10295 /* Avoid longjmp clobbering */
10296 (void) &out;
10297 (void) &quotef;
10298 (void) &dblquote;
10299 (void) &varnest;
10300 (void) &arinest;
10301 (void) &parenlevel;
10302 (void) &dqvarnest;
10303 (void) &oldstyle;
10304 (void) &prevsyntax;
10305 (void) &syntax;
10306#endif
10307
10308 startlinno = plinno;
10309 dblquote = 0;
10310 if (syntax == DQSYNTAX)
10311 dblquote = 1;
10312 quotef = 0;
10313 bqlist = NULL;
10314 varnest = 0;
10315 arinest = 0;
10316 parenlevel = 0;
10317 dqvarnest = 0;
10318
10319 STARTSTACKSTR(out);
Eric Andersen2870d962001-07-02 17:27:21 +000010320 loop: { /* for each line, until end of word */
10321 CHECKEND(); /* set c to PEOF if at end of here document */
10322 for (;;) { /* until end of line or end of word */
10323 CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010324 switch(SIT(c,syntax)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010325 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010326 if (syntax == BASESYNTAX)
Eric Andersen2870d962001-07-02 17:27:21 +000010327 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010328 USTPUTC(c, out);
10329 plinno++;
10330 if (doprompt)
10331 setprompt(2);
10332 else
10333 setprompt(0);
10334 c = pgetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010335 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010336 case CWORD:
10337 USTPUTC(c, out);
10338 break;
10339 case CCTL:
10340 if ((eofmark == NULL || dblquote) &&
10341 dqvarnest == 0)
10342 USTPUTC(CTLESC, out);
10343 USTPUTC(c, out);
10344 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010345 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010346 c = pgetc2();
10347 if (c == PEOF) {
10348 USTPUTC('\\', out);
10349 pungetc();
10350 } else if (c == '\n') {
10351 if (doprompt)
10352 setprompt(2);
10353 else
10354 setprompt(0);
10355 } else {
10356 if (dblquote && c != '\\' && c != '`' && c != '$'
10357 && (c != '"' || eofmark != NULL))
10358 USTPUTC('\\', out);
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010359 if (SIT(c,SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010360 USTPUTC(CTLESC, out);
10361 else if (eofmark == NULL)
10362 USTPUTC(CTLQUOTEMARK, out);
10363 USTPUTC(c, out);
10364 quotef++;
10365 }
10366 break;
10367 case CSQUOTE:
10368 if (eofmark == NULL)
10369 USTPUTC(CTLQUOTEMARK, out);
10370 syntax = SQSYNTAX;
10371 break;
10372 case CDQUOTE:
10373 if (eofmark == NULL)
10374 USTPUTC(CTLQUOTEMARK, out);
10375 syntax = DQSYNTAX;
10376 dblquote = 1;
10377 break;
10378 case CENDQUOTE:
10379 if (eofmark != NULL && arinest == 0 &&
10380 varnest == 0) {
10381 USTPUTC(c, out);
10382 } else {
10383 if (arinest) {
10384 syntax = ARISYNTAX;
10385 dblquote = 0;
10386 } else if (eofmark == NULL &&
10387 dqvarnest == 0) {
10388 syntax = BASESYNTAX;
10389 dblquote = 0;
10390 }
10391 quotef++;
10392 }
10393 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010394 case CVAR: /* '$' */
10395 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010396 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010397 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010398 if (varnest > 0) {
10399 varnest--;
10400 if (dqvarnest > 0) {
10401 dqvarnest--;
10402 }
10403 USTPUTC(CTLENDVAR, out);
10404 } else {
10405 USTPUTC(c, out);
10406 }
10407 break;
10408#ifdef ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +000010409 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010410 parenlevel++;
10411 USTPUTC(c, out);
10412 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010413 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010414 if (parenlevel > 0) {
10415 USTPUTC(c, out);
10416 --parenlevel;
10417 } else {
10418 if (pgetc() == ')') {
10419 if (--arinest == 0) {
10420 USTPUTC(CTLENDARI, out);
10421 syntax = prevsyntax;
10422 if (syntax == DQSYNTAX)
10423 dblquote = 1;
10424 else
10425 dblquote = 0;
10426 } else
10427 USTPUTC(')', out);
10428 } else {
10429 /*
10430 * unbalanced parens
10431 * (don't 2nd guess - no error)
10432 */
10433 pungetc();
10434 USTPUTC(')', out);
10435 }
10436 }
10437 break;
10438#endif
Eric Andersen2870d962001-07-02 17:27:21 +000010439 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010440 PARSEBACKQOLD();
10441 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010442 case CENDFILE:
10443 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010444 case CIGN:
10445 break;
10446 default:
10447 if (varnest == 0)
Eric Andersen2870d962001-07-02 17:27:21 +000010448 goto endword; /* exit outer loop */
Eric Andersen3102ac42001-07-06 04:26:23 +000010449#ifdef ASH_ALIAS
10450 if (c != PEOA)
10451#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010452 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010453
Eric Andersencb57d552001-06-28 07:25:16 +000010454 }
10455 c = pgetc_macro();
10456 }
10457 }
10458endword:
10459 if (syntax == ARISYNTAX)
10460 synerror("Missing '))'");
10461 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10462 synerror("Unterminated quoted string");
10463 if (varnest != 0) {
10464 startlinno = plinno;
10465 synerror("Missing '}'");
10466 }
10467 USTPUTC('\0', out);
10468 len = out - stackblock();
10469 out = stackblock();
10470 if (eofmark == NULL) {
10471 if ((c == '>' || c == '<')
10472 && quotef == 0
10473 && len <= 2
10474 && (*out == '\0' || is_digit(*out))) {
10475 PARSEREDIR();
10476 return lasttoken = TREDIR;
10477 } else {
10478 pungetc();
10479 }
10480 }
10481 quoteflag = quotef;
10482 backquotelist = bqlist;
10483 grabstackblock(len);
10484 wordtext = out;
10485 return lasttoken = TWORD;
10486/* end of readtoken routine */
10487
10488
10489
10490/*
10491 * Check to see whether we are at the end of the here document. When this
10492 * is called, c is set to the first character of the next input line. If
10493 * we are at the end of the here document, this routine sets the c to PEOF.
10494 */
10495
10496checkend: {
10497 if (eofmark) {
Eric Andersen2870d962001-07-02 17:27:21 +000010498#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010499 if (c == PEOA) {
10500 c = pgetc2();
10501 }
Eric Andersen2870d962001-07-02 17:27:21 +000010502#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010503 if (striptabs) {
10504 while (c == '\t') {
10505 c = pgetc2();
10506 }
10507 }
10508 if (c == *eofmark) {
10509 if (pfgets(line, sizeof line) != NULL) {
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010510 const char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010511
10512 p = line;
10513 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10514 if (*p == '\n' && *q == '\0') {
10515 c = PEOF;
10516 plinno++;
10517 needprompt = doprompt;
10518 } else {
10519 pushstring(line, strlen(line), NULL);
10520 }
10521 }
10522 }
10523 }
10524 goto checkend_return;
10525}
10526
10527
10528/*
10529 * Parse a redirection operator. The variable "out" points to a string
10530 * specifying the fd to be redirected. The variable "c" contains the
10531 * first character of the redirection operator.
10532 */
10533
10534parseredir: {
10535 char fd = *out;
10536 union node *np;
10537
10538 np = (union node *)stalloc(sizeof (struct nfile));
10539 if (c == '>') {
10540 np->nfile.fd = 1;
10541 c = pgetc();
10542 if (c == '>')
10543 np->type = NAPPEND;
10544 else if (c == '&')
10545 np->type = NTOFD;
10546 else if (c == '|')
10547 np->type = NTOOV;
10548 else {
10549 np->type = NTO;
10550 pungetc();
10551 }
Eric Andersen2870d962001-07-02 17:27:21 +000010552 } else { /* c == '<' */
Eric Andersencb57d552001-06-28 07:25:16 +000010553 np->nfile.fd = 0;
10554 switch (c = pgetc()) {
10555 case '<':
10556 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10557 np = (union node *)stalloc(sizeof (struct nhere));
10558 np->nfile.fd = 0;
10559 }
10560 np->type = NHERE;
10561 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10562 heredoc->here = np;
10563 if ((c = pgetc()) == '-') {
10564 heredoc->striptabs = 1;
10565 } else {
10566 heredoc->striptabs = 0;
10567 pungetc();
10568 }
10569 break;
10570
10571 case '&':
10572 np->type = NFROMFD;
10573 break;
10574
10575 case '>':
10576 np->type = NFROMTO;
10577 break;
10578
10579 default:
10580 np->type = NFROM;
10581 pungetc();
10582 break;
10583 }
10584 }
10585 if (fd != '\0')
10586 np->nfile.fd = digit_val(fd);
10587 redirnode = np;
10588 goto parseredir_return;
10589}
10590
10591
10592/*
10593 * Parse a substitution. At this point, we have read the dollar sign
10594 * and nothing else.
10595 */
10596
10597parsesub: {
10598 int subtype;
10599 int typeloc;
10600 int flags;
10601 char *p;
10602 static const char types[] = "}-+?=";
10603
10604 c = pgetc();
10605 if (
10606 c <= PEOA ||
10607 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10608 ) {
10609 USTPUTC('$', out);
10610 pungetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010611 } else if (c == '(') { /* $(command) or $((arith)) */
Eric Andersencb57d552001-06-28 07:25:16 +000010612 if (pgetc() == '(') {
10613 PARSEARITH();
10614 } else {
10615 pungetc();
10616 PARSEBACKQNEW();
10617 }
10618 } else {
10619 USTPUTC(CTLVAR, out);
10620 typeloc = out - stackblock();
10621 USTPUTC(VSNORMAL, out);
10622 subtype = VSNORMAL;
10623 if (c == '{') {
10624 c = pgetc();
10625 if (c == '#') {
10626 if ((c = pgetc()) == '}')
10627 c = '#';
10628 else
10629 subtype = VSLENGTH;
10630 }
10631 else
10632 subtype = 0;
10633 }
10634 if (c > PEOA && is_name(c)) {
10635 do {
10636 STPUTC(c, out);
10637 c = pgetc();
10638 } while (c > PEOA && is_in_name(c));
10639 } else if (is_digit(c)) {
10640 do {
10641 USTPUTC(c, out);
10642 c = pgetc();
10643 } while (is_digit(c));
10644 }
10645 else if (is_special(c)) {
10646 USTPUTC(c, out);
10647 c = pgetc();
10648 }
10649 else
Eric Andersen2870d962001-07-02 17:27:21 +000010650badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010651
10652 STPUTC('=', out);
10653 flags = 0;
10654 if (subtype == 0) {
10655 switch (c) {
10656 case ':':
10657 flags = VSNUL;
10658 c = pgetc();
10659 /*FALLTHROUGH*/
10660 default:
10661 p = strchr(types, c);
10662 if (p == NULL)
10663 goto badsub;
10664 subtype = p - types + VSNORMAL;
10665 break;
10666 case '%':
10667 case '#':
10668 {
10669 int cc = c;
10670 subtype = c == '#' ? VSTRIMLEFT :
10671 VSTRIMRIGHT;
10672 c = pgetc();
10673 if (c == cc)
10674 subtype++;
10675 else
10676 pungetc();
10677 break;
10678 }
10679 }
10680 } else {
10681 pungetc();
10682 }
10683 if (dblquote || arinest)
10684 flags |= VSQUOTE;
10685 *(stackblock() + typeloc) = subtype | flags;
10686 if (subtype != VSNORMAL) {
10687 varnest++;
10688 if (dblquote) {
10689 dqvarnest++;
10690 }
10691 }
10692 }
10693 goto parsesub_return;
10694}
10695
10696
10697/*
10698 * Called to parse command substitutions. Newstyle is set if the command
10699 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10700 * list of commands (passed by reference), and savelen is the number of
10701 * characters on the top of the stack which must be preserved.
10702 */
10703
10704parsebackq: {
10705 struct nodelist **nlpp;
10706 int savepbq;
10707 union node *n;
10708 char *volatile str;
10709 struct jmploc jmploc;
10710 struct jmploc *volatile savehandler;
10711 int savelen;
10712 int saveprompt;
10713#ifdef __GNUC__
10714 (void) &saveprompt;
10715#endif
10716
10717 savepbq = parsebackquote;
10718 if (setjmp(jmploc.loc)) {
10719 if (str)
10720 ckfree(str);
10721 parsebackquote = 0;
10722 handler = savehandler;
10723 longjmp(handler->loc, 1);
10724 }
10725 INTOFF;
10726 str = NULL;
10727 savelen = out - stackblock();
10728 if (savelen > 0) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010729 str = xmalloc(savelen);
Eric Andersencb57d552001-06-28 07:25:16 +000010730 memcpy(str, stackblock(), savelen);
10731 }
10732 savehandler = handler;
10733 handler = &jmploc;
10734 INTON;
Eric Andersen2870d962001-07-02 17:27:21 +000010735 if (oldstyle) {
10736 /* We must read until the closing backquote, giving special
10737 treatment to some slashes, and then push the string and
10738 reread it as input, interpreting it normally. */
10739 char *pout;
10740 int pc;
10741 int psavelen;
10742 char *pstr;
Eric Andersencb57d552001-06-28 07:25:16 +000010743
10744
Eric Andersen2870d962001-07-02 17:27:21 +000010745 STARTSTACKSTR(pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010746 for (;;) {
10747 if (needprompt) {
10748 setprompt(2);
10749 needprompt = 0;
10750 }
10751 switch (pc = pgetc()) {
10752 case '`':
10753 goto done;
10754
10755 case '\\':
Eric Andersen2870d962001-07-02 17:27:21 +000010756 if ((pc = pgetc()) == '\n') {
Eric Andersencb57d552001-06-28 07:25:16 +000010757 plinno++;
10758 if (doprompt)
10759 setprompt(2);
10760 else
10761 setprompt(0);
10762 /*
10763 * If eating a newline, avoid putting
10764 * the newline into the new character
10765 * stream (via the STPUTC after the
10766 * switch).
10767 */
10768 continue;
10769 }
Eric Andersen2870d962001-07-02 17:27:21 +000010770 if (pc != '\\' && pc != '`' && pc != '$'
10771 && (!dblquote || pc != '"'))
10772 STPUTC('\\', pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010773 if (pc > PEOA) {
10774 break;
10775 }
10776 /* fall through */
10777
10778 case PEOF:
Eric Andersen2870d962001-07-02 17:27:21 +000010779#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010780 case PEOA:
Eric Andersen2870d962001-07-02 17:27:21 +000010781#endif
10782 startlinno = plinno;
Eric Andersencb57d552001-06-28 07:25:16 +000010783 synerror("EOF in backquote substitution");
10784
10785 case '\n':
10786 plinno++;
10787 needprompt = doprompt;
10788 break;
10789
10790 default:
10791 break;
10792 }
10793 STPUTC(pc, pout);
Eric Andersen2870d962001-07-02 17:27:21 +000010794 }
Eric Andersencb57d552001-06-28 07:25:16 +000010795done:
Eric Andersen2870d962001-07-02 17:27:21 +000010796 STPUTC('\0', pout);
10797 psavelen = pout - stackblock();
10798 if (psavelen > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010799 pstr = grabstackstr(pout);
10800 setinputstring(pstr);
Eric Andersen2870d962001-07-02 17:27:21 +000010801 }
10802 }
Eric Andersencb57d552001-06-28 07:25:16 +000010803 nlpp = &bqlist;
10804 while (*nlpp)
10805 nlpp = &(*nlpp)->next;
10806 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10807 (*nlpp)->next = NULL;
10808 parsebackquote = oldstyle;
10809
10810 if (oldstyle) {
10811 saveprompt = doprompt;
10812 doprompt = 0;
10813 }
10814
10815 n = list(0);
10816
10817 if (oldstyle)
10818 doprompt = saveprompt;
10819 else {
10820 if (readtoken() != TRP)
10821 synexpect(TRP);
10822 }
10823
10824 (*nlpp)->n = n;
Eric Andersen2870d962001-07-02 17:27:21 +000010825 if (oldstyle) {
Eric Andersencb57d552001-06-28 07:25:16 +000010826 /*
10827 * Start reading from old file again, ignoring any pushed back
10828 * tokens left from the backquote parsing
10829 */
Eric Andersen2870d962001-07-02 17:27:21 +000010830 popfile();
Eric Andersencb57d552001-06-28 07:25:16 +000010831 tokpushback = 0;
10832 }
10833 while (stackblocksize() <= savelen)
10834 growstackblock();
10835 STARTSTACKSTR(out);
10836 if (str) {
10837 memcpy(out, str, savelen);
10838 STADJUST(savelen, out);
10839 INTOFF;
10840 ckfree(str);
10841 str = NULL;
10842 INTON;
10843 }
10844 parsebackquote = savepbq;
10845 handler = savehandler;
10846 if (arinest || dblquote)
10847 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10848 else
10849 USTPUTC(CTLBACKQ, out);
10850 if (oldstyle)
10851 goto parsebackq_oldreturn;
10852 else
10853 goto parsebackq_newreturn;
10854}
10855
10856/*
10857 * Parse an arithmetic expansion (indicate start of one and set state)
10858 */
10859parsearith: {
10860
10861 if (++arinest == 1) {
10862 prevsyntax = syntax;
10863 syntax = ARISYNTAX;
10864 USTPUTC(CTLARI, out);
10865 if (dblquote)
10866 USTPUTC('"',out);
10867 else
10868 USTPUTC(' ',out);
10869 } else {
10870 /*
10871 * we collapse embedded arithmetic expansion to
10872 * parenthesis, which should be equivalent
10873 */
10874 USTPUTC('(', out);
10875 }
10876 goto parsearith_return;
10877}
10878
10879} /* end of readtoken */
10880
10881
Eric Andersencb57d552001-06-28 07:25:16 +000010882/*
10883 * Returns true if the text contains nothing to expand (no dollar signs
10884 * or backquotes).
10885 */
10886
10887static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010888noexpand(char *text)
10889{
Eric Andersencb57d552001-06-28 07:25:16 +000010890 char *p;
10891 char c;
10892
10893 p = text;
10894 while ((c = *p++) != '\0') {
10895 if (c == CTLQUOTEMARK)
10896 continue;
10897 if (c == CTLESC)
10898 p++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010899 else if (SIT(c,BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010900 return 0;
10901 }
10902 return 1;
10903}
10904
10905
10906/*
10907 * Return true if the argument is a legal variable name (a letter or
10908 * underscore followed by zero or more letters, underscores, and digits).
10909 */
10910
10911static int
Eric Andersen2870d962001-07-02 17:27:21 +000010912goodname(const char *name)
10913{
10914 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000010915
10916 p = name;
10917 if (! is_name(*p))
10918 return 0;
10919 while (*++p) {
10920 if (! is_in_name(*p))
10921 return 0;
10922 }
10923 return 1;
10924}
10925
10926
10927/*
10928 * Called when an unexpected token is read during the parse. The argument
10929 * is the token that is expected, or -1 if more than one type of token can
10930 * occur at this point.
10931 */
10932
10933static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010934synexpect(int token)
Eric Andersencb57d552001-06-28 07:25:16 +000010935{
10936 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010937 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000010938
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010939 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10940 if (token >= 0)
10941 sprintf(msg+l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000010942 synerror(msg);
10943 /* NOTREACHED */
10944}
10945
10946
10947static void
Eric Andersen2870d962001-07-02 17:27:21 +000010948synerror(const char *msg)
10949{
Eric Andersencb57d552001-06-28 07:25:16 +000010950 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +000010951 out2fmt("%s: %d: ", commandname, startlinno);
10952 out2fmt("Syntax error: %s\n", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000010953 error((char *)NULL);
10954 /* NOTREACHED */
10955}
10956
Eric Andersencb57d552001-06-28 07:25:16 +000010957
10958/*
10959 * called by editline -- any expansions to the prompt
10960 * should be added here.
10961 */
Eric Andersen2870d962001-07-02 17:27:21 +000010962static void
Eric Andersen62483552001-07-10 06:09:16 +000010963setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000010964{
Eric Andersen62483552001-07-10 06:09:16 +000010965 char *prompt;
10966 switch (whichprompt) {
10967 case 1:
10968 prompt = ps1val();
10969 break;
10970 case 2:
10971 prompt = ps2val();
10972 break;
10973 default: /* 0 */
10974 prompt = "";
10975 }
10976 putprompt(prompt);
Eric Andersencb57d552001-06-28 07:25:16 +000010977}
10978
Eric Andersencb57d552001-06-28 07:25:16 +000010979
Eric Andersencb57d552001-06-28 07:25:16 +000010980/*
10981 * Code for dealing with input/output redirection.
10982 */
10983
Eric Andersen2870d962001-07-02 17:27:21 +000010984#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000010985#ifndef PIPE_BUF
Eric Andersen2870d962001-07-02 17:27:21 +000010986# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000010987#else
10988# define PIPESIZE PIPE_BUF
10989#endif
10990
10991
Eric Andersen62483552001-07-10 06:09:16 +000010992/*
10993 * Open a file in noclobber mode.
10994 * The code was copied from bash.
10995 */
10996static inline int
10997noclobberopen(const char *fname)
10998{
10999 int r, fd;
11000 struct stat finfo, finfo2;
11001
11002 /*
11003 * If the file exists and is a regular file, return an error
11004 * immediately.
11005 */
11006 r = stat(fname, &finfo);
11007 if (r == 0 && S_ISREG(finfo.st_mode)) {
11008 errno = EEXIST;
11009 return -1;
11010 }
11011
11012 /*
11013 * If the file was not present (r != 0), make sure we open it
11014 * exclusively so that if it is created before we open it, our open
11015 * will fail. Make sure that we do not truncate an existing file.
11016 * Note that we don't turn on O_EXCL unless the stat failed -- if the
11017 * file was not a regular file, we leave O_EXCL off.
11018 */
11019 if (r != 0)
11020 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
11021 fd = open(fname, O_WRONLY|O_CREAT, 0666);
11022
11023 /* If the open failed, return the file descriptor right away. */
11024 if (fd < 0)
11025 return fd;
11026
11027 /*
11028 * OK, the open succeeded, but the file may have been changed from a
11029 * non-regular file to a regular file between the stat and the open.
11030 * We are assuming that the O_EXCL open handles the case where FILENAME
11031 * did not exist and is symlinked to an existing file between the stat
11032 * and open.
11033 */
11034
11035 /*
11036 * If we can open it and fstat the file descriptor, and neither check
11037 * revealed that it was a regular file, and the file has not been
11038 * replaced, return the file descriptor.
11039 */
11040 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
11041 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
11042 return fd;
11043
11044 /* The file has been replaced. badness. */
11045 close(fd);
11046 errno = EEXIST;
11047 return -1;
11048}
Eric Andersencb57d552001-06-28 07:25:16 +000011049
11050/*
Eric Andersen62483552001-07-10 06:09:16 +000011051 * Handle here documents. Normally we fork off a process to write the
11052 * data to a pipe. If the document is short, we can stuff the data in
11053 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000011054 */
11055
Eric Andersen62483552001-07-10 06:09:16 +000011056static inline int
11057openhere(const union node *redir)
11058{
11059 int pip[2];
11060 int len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011061
Eric Andersen62483552001-07-10 06:09:16 +000011062 if (pipe(pip) < 0)
11063 error("Pipe call failed");
11064 if (redir->type == NHERE) {
11065 len = strlen(redir->nhere.doc->narg.text);
11066 if (len <= PIPESIZE) {
11067 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11068 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011069 }
Eric Andersencb57d552001-06-28 07:25:16 +000011070 }
Eric Andersen62483552001-07-10 06:09:16 +000011071 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
11072 close(pip[0]);
11073 signal(SIGINT, SIG_IGN);
11074 signal(SIGQUIT, SIG_IGN);
11075 signal(SIGHUP, SIG_IGN);
11076#ifdef SIGTSTP
11077 signal(SIGTSTP, SIG_IGN);
11078#endif
11079 signal(SIGPIPE, SIG_DFL);
11080 if (redir->type == NHERE)
11081 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11082 else
11083 expandhere(redir->nhere.doc, pip[1]);
11084 _exit(0);
11085 }
11086out:
11087 close(pip[1]);
11088 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000011089}
11090
11091
Eric Andersen62483552001-07-10 06:09:16 +000011092static inline int
11093openredirect(const union node *redir)
11094{
Eric Andersencb57d552001-06-28 07:25:16 +000011095 char *fname;
11096 int f;
11097
11098 switch (redir->nfile.type) {
11099 case NFROM:
11100 fname = redir->nfile.expfname;
11101 if ((f = open(fname, O_RDONLY)) < 0)
11102 goto eopen;
11103 break;
11104 case NFROMTO:
11105 fname = redir->nfile.expfname;
11106 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
11107 goto ecreate;
11108 break;
11109 case NTO:
11110 /* Take care of noclobber mode. */
11111 if (Cflag) {
11112 fname = redir->nfile.expfname;
11113 if ((f = noclobberopen(fname)) < 0)
11114 goto ecreate;
11115 break;
11116 }
11117 case NTOOV:
11118 fname = redir->nfile.expfname;
11119#ifdef O_CREAT
11120 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
11121 goto ecreate;
11122#else
11123 if ((f = creat(fname, 0666)) < 0)
11124 goto ecreate;
11125#endif
11126 break;
11127 case NAPPEND:
11128 fname = redir->nfile.expfname;
11129#ifdef O_APPEND
11130 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
11131 goto ecreate;
11132#else
11133 if ((f = open(fname, O_WRONLY)) < 0
11134 && (f = creat(fname, 0666)) < 0)
11135 goto ecreate;
11136 lseek(f, (off_t)0, 2);
11137#endif
11138 break;
11139 default:
11140#ifdef DEBUG
11141 abort();
11142#endif
11143 /* Fall through to eliminate warning. */
11144 case NTOFD:
11145 case NFROMFD:
11146 f = -1;
11147 break;
11148 case NHERE:
11149 case NXHERE:
11150 f = openhere(redir);
11151 break;
11152 }
11153
11154 return f;
11155ecreate:
11156 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11157eopen:
11158 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11159}
11160
11161
Eric Andersen62483552001-07-10 06:09:16 +000011162/*
11163 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11164 * old file descriptors are stashed away so that the redirection can be
11165 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11166 * standard output, and the standard error if it becomes a duplicate of
11167 * stdout.
11168 */
11169
Eric Andersencb57d552001-06-28 07:25:16 +000011170static void
Eric Andersen62483552001-07-10 06:09:16 +000011171redirect(union node *redir, int flags)
11172{
11173 union node *n;
11174 struct redirtab *sv = NULL;
11175 int i;
11176 int fd;
11177 int newfd;
11178 int try;
11179 int fd1dup = flags & REDIR_BACKQ;; /* stdout `cmd` redir to pipe */
11180
11181 if (flags & REDIR_PUSH) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011182 sv = xmalloc(sizeof (struct redirtab));
Eric Andersen62483552001-07-10 06:09:16 +000011183 for (i = 0 ; i < 10 ; i++)
11184 sv->renamed[i] = EMPTY;
11185 sv->next = redirlist;
11186 redirlist = sv;
11187 }
11188 for (n = redir ; n ; n = n->nfile.next) {
11189 fd = n->nfile.fd;
11190 try = 0;
11191 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11192 n->ndup.dupfd == fd)
11193 continue; /* redirect from/to same file descriptor */
11194
11195 INTOFF;
11196 newfd = openredirect(n);
11197 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
11198 if (newfd == fd) {
11199 try++;
11200 } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
11201 switch (errno) {
11202 case EBADF:
11203 if (!try) {
11204 dupredirect(n, newfd, fd1dup);
11205 try++;
11206 break;
11207 }
11208 /* FALLTHROUGH*/
11209 default:
11210 if (newfd >= 0) {
11211 close(newfd);
11212 }
11213 INTON;
11214 error("%d: %m", fd);
11215 /* NOTREACHED */
11216 }
11217 }
11218 if (!try) {
11219 close(fd);
11220 if (flags & REDIR_PUSH) {
11221 sv->renamed[fd] = i;
11222 }
11223 }
11224 } else if (fd != newfd) {
11225 close(fd);
11226 }
11227 if (fd == 0)
11228 fd0_redirected++;
11229 if (!try)
11230 dupredirect(n, newfd, fd1dup);
11231 INTON;
11232 }
11233}
11234
11235
11236static void
11237dupredirect(const union node *redir, int f, int fd1dup)
Eric Andersen2870d962001-07-02 17:27:21 +000011238{
Eric Andersencb57d552001-06-28 07:25:16 +000011239 int fd = redir->nfile.fd;
11240
Eric Andersen62483552001-07-10 06:09:16 +000011241 if(fd==1)
11242 fd1dup = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011243 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Eric Andersen2870d962001-07-02 17:27:21 +000011244 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
Eric Andersen62483552001-07-10 06:09:16 +000011245 if (redir->ndup.dupfd!=1 || fd1dup!=1)
Eric Andersencb57d552001-06-28 07:25:16 +000011246 dup_as_newfd(redir->ndup.dupfd, fd);
11247 }
11248 return;
11249 }
11250
11251 if (f != fd) {
11252 dup_as_newfd(f, fd);
11253 close(f);
11254 }
11255 return;
11256}
11257
11258
Eric Andersencb57d552001-06-28 07:25:16 +000011259
Eric Andersencb57d552001-06-28 07:25:16 +000011260/*
11261 * Undo the effects of the last redirection.
11262 */
11263
11264static void
Eric Andersen2870d962001-07-02 17:27:21 +000011265popredir(void)
11266{
Eric Andersencb57d552001-06-28 07:25:16 +000011267 struct redirtab *rp = redirlist;
11268 int i;
11269
11270 INTOFF;
11271 for (i = 0 ; i < 10 ; i++) {
11272 if (rp->renamed[i] != EMPTY) {
Eric Andersen2870d962001-07-02 17:27:21 +000011273 if (i == 0)
11274 fd0_redirected--;
Eric Andersencb57d552001-06-28 07:25:16 +000011275 close(i);
11276 if (rp->renamed[i] >= 0) {
11277 dup_as_newfd(rp->renamed[i], i);
11278 close(rp->renamed[i]);
11279 }
Eric Andersencb57d552001-06-28 07:25:16 +000011280 }
11281 }
11282 redirlist = rp->next;
11283 ckfree(rp);
11284 INTON;
11285}
11286
11287/*
Eric Andersencb57d552001-06-28 07:25:16 +000011288 * Discard all saved file descriptors.
11289 */
11290
11291static void
Eric Andersen2870d962001-07-02 17:27:21 +000011292clearredir(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000011293 struct redirtab *rp;
11294 int i;
11295
11296 for (rp = redirlist ; rp ; rp = rp->next) {
11297 for (i = 0 ; i < 10 ; i++) {
11298 if (rp->renamed[i] >= 0) {
11299 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011300 }
11301 rp->renamed[i] = EMPTY;
11302 }
11303 }
Eric Andersencb57d552001-06-28 07:25:16 +000011304}
11305
11306
Eric Andersencb57d552001-06-28 07:25:16 +000011307/*
11308 * Copy a file descriptor to be >= to. Returns -1
11309 * if the source file descriptor is closed, EMPTY if there are no unused
11310 * file descriptors left.
11311 */
11312
11313static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011314dup_as_newfd(int from, int to)
Eric Andersencb57d552001-06-28 07:25:16 +000011315{
11316 int newfd;
11317
11318 newfd = fcntl(from, F_DUPFD, to);
11319 if (newfd < 0) {
11320 if (errno == EMFILE)
11321 return EMPTY;
11322 else
Eric Andersen2870d962001-07-02 17:27:21 +000011323 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011324 }
11325 return newfd;
11326}
11327
Eric Andersencb57d552001-06-28 07:25:16 +000011328#ifdef DEBUG
Eric Andersenec074692001-10-31 11:05:49 +000011329/*
11330 * Debugging stuff.
11331 */
Eric Andersen2870d962001-07-02 17:27:21 +000011332static void shtree (union node *, int, char *, FILE*);
11333static void shcmd (union node *, FILE *);
11334static void sharg (union node *, FILE *);
11335static void indent (int, char *, FILE *);
11336static void trstring (char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011337
11338
11339static void
11340showtree(n)
Eric Andersen69a20f02001-10-31 10:40:37 +000011341 unode *n;
Eric Andersencb57d552001-06-28 07:25:16 +000011342{
11343 trputs("showtree called\n");
11344 shtree(n, 1, NULL, stdout);
11345}
11346
11347
11348static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011349shtree(union node *n, int ind, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011350{
11351 struct nodelist *lp;
11352 const char *s;
11353
11354 if (n == NULL)
11355 return;
11356
11357 indent(ind, pfx, fp);
11358 switch(n->type) {
11359 case NSEMI:
11360 s = "; ";
11361 goto binop;
11362 case NAND:
11363 s = " && ";
11364 goto binop;
11365 case NOR:
11366 s = " || ";
11367binop:
11368 shtree(n->nbinary.ch1, ind, NULL, fp);
11369 /* if (ind < 0) */
11370 fputs(s, fp);
11371 shtree(n->nbinary.ch2, ind, NULL, fp);
11372 break;
11373 case NCMD:
11374 shcmd(n, fp);
11375 if (ind >= 0)
11376 putc('\n', fp);
11377 break;
11378 case NPIPE:
11379 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11380 shcmd(lp->n, fp);
11381 if (lp->next)
11382 fputs(" | ", fp);
11383 }
11384 if (n->npipe.backgnd)
11385 fputs(" &", fp);
11386 if (ind >= 0)
11387 putc('\n', fp);
11388 break;
11389 default:
11390 fprintf(fp, "<node type %d>", n->type);
11391 if (ind >= 0)
11392 putc('\n', fp);
11393 break;
11394 }
11395}
11396
11397
11398
11399static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011400shcmd(union node *cmd, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011401{
11402 union node *np;
11403 int first;
11404 const char *s;
11405 int dftfd;
11406
11407 first = 1;
11408 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11409 if (! first)
11410 putchar(' ');
11411 sharg(np, fp);
11412 first = 0;
11413 }
11414 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11415 if (! first)
11416 putchar(' ');
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011417#if 1
11418 s = "*error*";
11419 dftfd = 0;
11420 if ((np->nfile.type <= NFROMFD) && (np->nfile.type >= NTO)) {
11421 s = redir_strings[np->nfile.type - NTO];
11422 if (*s == '>') {
11423 dftfd = 1;
11424 }
11425 }
11426#else
Eric Andersencb57d552001-06-28 07:25:16 +000011427 switch (np->nfile.type) {
Eric Andersen2870d962001-07-02 17:27:21 +000011428 case NTO: s = ">"; dftfd = 1; break;
11429 case NAPPEND: s = ">>"; dftfd = 1; break;
11430 case NTOFD: s = ">&"; dftfd = 1; break;
11431 case NTOOV: s = ">|"; dftfd = 1; break;
11432 case NFROM: s = "<"; dftfd = 0; break;
11433 case NFROMFD: s = "<&"; dftfd = 0; break;
11434 case NFROMTO: s = "<>"; dftfd = 0; break;
11435 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011436 }
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011437#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011438 if (np->nfile.fd != dftfd)
11439 fprintf(fp, "%d", np->nfile.fd);
11440 fputs(s, fp);
11441 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11442 fprintf(fp, "%d", np->ndup.dupfd);
11443 } else {
11444 sharg(np->nfile.fname, fp);
11445 }
11446 first = 0;
11447 }
11448}
11449
Eric Andersencb57d552001-06-28 07:25:16 +000011450static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011451sharg(union node *arg, FILE *fp)
11452{
Eric Andersencb57d552001-06-28 07:25:16 +000011453 char *p;
11454 struct nodelist *bqlist;
11455 int subtype;
11456
11457 if (arg->type != NARG) {
11458 printf("<node type %d>\n", arg->type);
11459 fflush(stdout);
11460 abort();
11461 }
11462 bqlist = arg->narg.backquote;
11463 for (p = arg->narg.text ; *p ; p++) {
11464 switch (*p) {
11465 case CTLESC:
11466 putc(*++p, fp);
11467 break;
11468 case CTLVAR:
11469 putc('$', fp);
11470 putc('{', fp);
11471 subtype = *++p;
11472 if (subtype == VSLENGTH)
11473 putc('#', fp);
11474
11475 while (*p != '=')
11476 putc(*p++, fp);
11477
11478 if (subtype & VSNUL)
11479 putc(':', fp);
11480
11481 switch (subtype & VSTYPE) {
11482 case VSNORMAL:
11483 putc('}', fp);
11484 break;
11485 case VSMINUS:
11486 putc('-', fp);
11487 break;
11488 case VSPLUS:
11489 putc('+', fp);
11490 break;
11491 case VSQUESTION:
11492 putc('?', fp);
11493 break;
11494 case VSASSIGN:
11495 putc('=', fp);
11496 break;
11497 case VSTRIMLEFT:
11498 putc('#', fp);
11499 break;
11500 case VSTRIMLEFTMAX:
11501 putc('#', fp);
11502 putc('#', fp);
11503 break;
11504 case VSTRIMRIGHT:
11505 putc('%', fp);
11506 break;
11507 case VSTRIMRIGHTMAX:
11508 putc('%', fp);
11509 putc('%', fp);
11510 break;
11511 case VSLENGTH:
11512 break;
11513 default:
11514 printf("<subtype %d>", subtype);
11515 }
11516 break;
11517 case CTLENDVAR:
11518 putc('}', fp);
11519 break;
11520 case CTLBACKQ:
11521 case CTLBACKQ|CTLQUOTE:
11522 putc('$', fp);
11523 putc('(', fp);
11524 shtree(bqlist->n, -1, NULL, fp);
11525 putc(')', fp);
11526 break;
11527 default:
11528 putc(*p, fp);
11529 break;
11530 }
11531 }
11532}
11533
11534
11535static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011536indent(int amount, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011537{
11538 int i;
11539
11540 for (i = 0 ; i < amount ; i++) {
11541 if (pfx && i == amount - 1)
11542 fputs(pfx, fp);
11543 putc('\t', fp);
11544 }
11545}
Eric Andersencb57d552001-06-28 07:25:16 +000011546
11547
Eric Andersencb57d552001-06-28 07:25:16 +000011548FILE *tracefile;
11549
11550#if DEBUG == 2
11551static int debug = 1;
11552#else
11553static int debug = 0;
11554#endif
11555
11556
11557static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011558trputc(int c)
Eric Andersencb57d552001-06-28 07:25:16 +000011559{
11560 if (tracefile == NULL)
11561 return;
11562 putc(c, tracefile);
11563 if (c == '\n')
11564 fflush(tracefile);
11565}
11566
11567static void
11568trace(const char *fmt, ...)
11569{
11570 va_list va;
Eric Andersencb57d552001-06-28 07:25:16 +000011571 va_start(va, fmt);
Eric Andersencb57d552001-06-28 07:25:16 +000011572 if (tracefile != NULL) {
11573 (void) vfprintf(tracefile, fmt, va);
11574 if (strchr(fmt, '\n'))
11575 (void) fflush(tracefile);
11576 }
11577 va_end(va);
11578}
11579
11580
11581static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011582trputs(const char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011583{
11584 if (tracefile == NULL)
11585 return;
11586 fputs(s, tracefile);
11587 if (strchr(s, '\n'))
11588 fflush(tracefile);
11589}
11590
11591
11592static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011593trstring(char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011594{
11595 char *p;
11596 char c;
11597
11598 if (tracefile == NULL)
11599 return;
11600 putc('"', tracefile);
11601 for (p = s ; *p ; p++) {
11602 switch (*p) {
11603 case '\n': c = 'n'; goto backslash;
11604 case '\t': c = 't'; goto backslash;
11605 case '\r': c = 'r'; goto backslash;
11606 case '"': c = '"'; goto backslash;
11607 case '\\': c = '\\'; goto backslash;
11608 case CTLESC: c = 'e'; goto backslash;
11609 case CTLVAR: c = 'v'; goto backslash;
11610 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11611 case CTLBACKQ: c = 'q'; goto backslash;
11612 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
Eric Andersen2870d962001-07-02 17:27:21 +000011613backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011614 putc(c, tracefile);
11615 break;
11616 default:
11617 if (*p >= ' ' && *p <= '~')
11618 putc(*p, tracefile);
11619 else {
11620 putc('\\', tracefile);
11621 putc(*p >> 6 & 03, tracefile);
11622 putc(*p >> 3 & 07, tracefile);
11623 putc(*p & 07, tracefile);
11624 }
11625 break;
11626 }
11627 }
11628 putc('"', tracefile);
11629}
11630
11631
11632static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011633trargs(char **ap)
Eric Andersencb57d552001-06-28 07:25:16 +000011634{
11635 if (tracefile == NULL)
11636 return;
11637 while (*ap) {
11638 trstring(*ap++);
11639 if (*ap)
11640 putc(' ', tracefile);
11641 else
11642 putc('\n', tracefile);
11643 }
11644 fflush(tracefile);
11645}
11646
11647
11648static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011649opentrace()
11650{
Eric Andersencb57d552001-06-28 07:25:16 +000011651 char s[100];
11652#ifdef O_APPEND
11653 int flags;
11654#endif
11655
11656 if (!debug)
11657 return;
11658#ifdef not_this_way
11659 {
11660 char *p;
11661 if ((p = getenv("HOME")) == NULL) {
11662 if (geteuid() == 0)
11663 p = "/";
11664 else
11665 p = "/tmp";
11666 }
Eric Andersen2870d962001-07-02 17:27:21 +000011667 strcpy(s, p);
Eric Andersencb57d552001-06-28 07:25:16 +000011668 strcat(s, "/trace");
11669 }
11670#else
Eric Andersen2870d962001-07-02 17:27:21 +000011671 strcpy(s, "./trace");
Eric Andersencb57d552001-06-28 07:25:16 +000011672#endif /* not_this_way */
Matt Kraaia5f09c62001-11-12 16:44:55 +000011673 if ((tracefile = wfopen(s, "a")) == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000011674 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011675#ifdef O_APPEND
11676 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11677 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11678#endif
11679 fputs("\nTracing started.\n", tracefile);
11680 fflush(tracefile);
11681}
11682#endif /* DEBUG */
11683
11684
11685/*
Eric Andersencb57d552001-06-28 07:25:16 +000011686 * The trap builtin.
11687 */
11688
11689static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011690trapcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011691{
11692 char *action;
11693 char **ap;
11694 int signo;
11695
11696 if (argc <= 1) {
11697 for (signo = 0 ; signo < NSIG ; signo++) {
11698 if (trap[signo] != NULL) {
11699 char *p;
Eric Andersen34506362001-08-02 05:02:46 +000011700 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011701
11702 p = single_quote(trap[signo]);
Eric Andersen34506362001-08-02 05:02:46 +000011703 sn = sys_siglist[signo];
11704 if(sn==NULL)
11705 sn = u_signal_names(0, &signo, 0);
11706 if(sn==NULL)
11707 sn = "???";
11708 printf("trap -- %s %s\n", p, sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011709 stunalloc(p);
11710 }
11711 }
11712 return 0;
11713 }
11714 ap = argv + 1;
11715 if (argc == 2)
11716 action = NULL;
11717 else
11718 action = *ap++;
11719 while (*ap) {
11720 if ((signo = decode_signal(*ap, 0)) < 0)
11721 error("%s: bad trap", *ap);
11722 INTOFF;
11723 if (action) {
11724 if (action[0] == '-' && action[1] == '\0')
11725 action = NULL;
11726 else
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011727 action = xstrdup(action);
Eric Andersencb57d552001-06-28 07:25:16 +000011728 }
11729 if (trap[signo])
11730 ckfree(trap[signo]);
11731 trap[signo] = action;
11732 if (signo != 0)
11733 setsignal(signo);
11734 INTON;
11735 ap++;
11736 }
11737 return 0;
11738}
11739
11740
11741
Eric Andersencb57d552001-06-28 07:25:16 +000011742
11743
11744
11745/*
11746 * Set the signal handler for the specified signal. The routine figures
11747 * out what it should be set to.
11748 */
11749
11750static void
Eric Andersen2870d962001-07-02 17:27:21 +000011751setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011752{
11753 int action;
11754 char *t;
11755 struct sigaction act;
11756
11757 if ((t = trap[signo]) == NULL)
11758 action = S_DFL;
11759 else if (*t != '\0')
11760 action = S_CATCH;
11761 else
11762 action = S_IGN;
11763 if (rootshell && action == S_DFL) {
11764 switch (signo) {
11765 case SIGINT:
11766 if (iflag || minusc || sflag == 0)
11767 action = S_CATCH;
11768 break;
11769 case SIGQUIT:
11770#ifdef DEBUG
11771 {
Eric Andersencb57d552001-06-28 07:25:16 +000011772
11773 if (debug)
11774 break;
11775 }
11776#endif
11777 /* FALLTHROUGH */
11778 case SIGTERM:
11779 if (iflag)
11780 action = S_IGN;
11781 break;
Eric Andersen2870d962001-07-02 17:27:21 +000011782#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000011783 case SIGTSTP:
11784 case SIGTTOU:
11785 if (mflag)
11786 action = S_IGN;
11787 break;
11788#endif
11789 }
11790 }
11791
11792 t = &sigmode[signo - 1];
11793 if (*t == 0) {
11794 /*
11795 * current setting unknown
11796 */
11797 if (sigaction(signo, 0, &act) == -1) {
11798 /*
11799 * Pretend it worked; maybe we should give a warning
11800 * here, but other shells don't. We don't alter
11801 * sigmode, so that we retry every time.
11802 */
11803 return;
11804 }
11805 if (act.sa_handler == SIG_IGN) {
11806 if (mflag && (signo == SIGTSTP ||
11807 signo == SIGTTIN || signo == SIGTTOU)) {
Eric Andersen2870d962001-07-02 17:27:21 +000011808 *t = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000011809 } else
11810 *t = S_HARD_IGN;
11811 } else {
Eric Andersen2870d962001-07-02 17:27:21 +000011812 *t = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000011813 }
11814 }
11815 if (*t == S_HARD_IGN || *t == action)
11816 return;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011817 act.sa_handler = ((action == S_CATCH) ? onsig
11818 : ((action == S_IGN) ? SIG_IGN : SIG_DFL));
Eric Andersencb57d552001-06-28 07:25:16 +000011819 *t = action;
11820 act.sa_flags = 0;
11821 sigemptyset(&act.sa_mask);
11822 sigaction(signo, &act, 0);
11823}
11824
11825/*
11826 * Ignore a signal.
11827 */
11828
11829static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011830ignoresig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011831{
11832 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11833 signal(signo, SIG_IGN);
11834 }
11835 sigmode[signo - 1] = S_HARD_IGN;
11836}
11837
11838
Eric Andersencb57d552001-06-28 07:25:16 +000011839/*
11840 * Signal handler.
11841 */
11842
11843static void
Eric Andersen2870d962001-07-02 17:27:21 +000011844onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011845{
11846 if (signo == SIGINT && trap[SIGINT] == NULL) {
11847 onint();
11848 return;
11849 }
11850 gotsig[signo - 1] = 1;
11851 pendingsigs++;
11852}
11853
11854
Eric Andersencb57d552001-06-28 07:25:16 +000011855/*
11856 * Called to execute a trap. Perhaps we should avoid entering new trap
11857 * handlers while we are executing a trap handler.
11858 */
11859
11860static void
Eric Andersen2870d962001-07-02 17:27:21 +000011861dotrap(void)
11862{
Eric Andersencb57d552001-06-28 07:25:16 +000011863 int i;
11864 int savestatus;
11865
11866 for (;;) {
11867 for (i = 1 ; ; i++) {
11868 if (gotsig[i - 1])
11869 break;
11870 if (i >= NSIG - 1)
11871 goto done;
11872 }
11873 gotsig[i - 1] = 0;
11874 savestatus=exitstatus;
11875 evalstring(trap[i], 0);
11876 exitstatus=savestatus;
11877 }
11878done:
11879 pendingsigs = 0;
11880}
11881
Eric Andersencb57d552001-06-28 07:25:16 +000011882/*
11883 * Called to exit the shell.
11884 */
11885
11886static void
Eric Andersen2870d962001-07-02 17:27:21 +000011887exitshell(int status)
Eric Andersencb57d552001-06-28 07:25:16 +000011888{
11889 struct jmploc loc1, loc2;
11890 char *p;
11891
11892 TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
11893 if (setjmp(loc1.loc)) {
11894 goto l1;
11895 }
11896 if (setjmp(loc2.loc)) {
11897 goto l2;
11898 }
11899 handler = &loc1;
11900 if ((p = trap[0]) != NULL && *p != '\0') {
11901 trap[0] = NULL;
11902 evalstring(p, 0);
11903 }
Eric Andersen2870d962001-07-02 17:27:21 +000011904l1: handler = &loc2; /* probably unnecessary */
Eric Andersencb57d552001-06-28 07:25:16 +000011905 flushall();
Eric Andersen2870d962001-07-02 17:27:21 +000011906#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000011907 setjobctl(0);
11908#endif
11909l2: _exit(status);
11910 /* NOTREACHED */
11911}
11912
11913static int decode_signal(const char *string, int minsig)
11914{
11915 int signo;
Eric Andersen34506362001-08-02 05:02:46 +000011916 const char *name = u_signal_names(string, &signo, minsig);
Eric Andersencb57d552001-06-28 07:25:16 +000011917
Eric Andersen34506362001-08-02 05:02:46 +000011918 return name ? signo : -1;
Eric Andersencb57d552001-06-28 07:25:16 +000011919}
Eric Andersen34506362001-08-02 05:02:46 +000011920
Eric Andersen2870d962001-07-02 17:27:21 +000011921static struct var **hashvar (const char *);
11922static void showvars (const char *, int, int);
11923static struct var **findvar (struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011924
11925/*
11926 * Initialize the varable symbol tables and import the environment
11927 */
11928
Eric Andersencb57d552001-06-28 07:25:16 +000011929/*
11930 * This routine initializes the builtin variables. It is called when the
11931 * shell is initialized and again when a shell procedure is spawned.
11932 */
11933
11934static void
11935initvar() {
11936 const struct varinit *ip;
11937 struct var *vp;
11938 struct var **vpp;
11939
11940 for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
11941 if ((vp->flags & VEXPORT) == 0) {
11942 vpp = hashvar(ip->text);
11943 vp->next = *vpp;
11944 *vpp = vp;
Matt Kraaic8227632001-11-12 16:57:27 +000011945 vp->text = xstrdup(ip->text);
Eric Andersencb57d552001-06-28 07:25:16 +000011946 vp->flags = ip->flags;
11947 vp->func = ip->func;
11948 }
11949 }
11950 /*
11951 * PS1 depends on uid
11952 */
11953 if ((vps1.flags & VEXPORT) == 0) {
11954 vpp = hashvar("PS1=");
11955 vps1.next = *vpp;
11956 *vpp = &vps1;
Matt Kraaic8227632001-11-12 16:57:27 +000011957 vps1.text = xstrdup(geteuid() ? "PS1=$ " : "PS1=# ");
Eric Andersencb57d552001-06-28 07:25:16 +000011958 vps1.flags = VSTRFIXED|VTEXTFIXED;
11959 }
11960}
11961
11962/*
11963 * Set the value of a variable. The flags argument is ored with the
11964 * flags of the variable. If val is NULL, the variable is unset.
11965 */
11966
11967static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011968setvar(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011969{
11970 const char *p;
11971 int len;
11972 int namelen;
11973 char *nameeq;
11974 int isbad;
11975 int vallen = 0;
11976
11977 isbad = 0;
11978 p = name;
11979 if (! is_name(*p))
11980 isbad = 1;
11981 p++;
11982 for (;;) {
11983 if (! is_in_name(*p)) {
11984 if (*p == '\0' || *p == '=')
11985 break;
11986 isbad = 1;
11987 }
11988 p++;
11989 }
11990 namelen = p - name;
11991 if (isbad)
11992 error("%.*s: bad variable name", namelen, name);
Eric Andersen2870d962001-07-02 17:27:21 +000011993 len = namelen + 2; /* 2 is space for '=' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +000011994 if (val == NULL) {
11995 flags |= VUNSET;
11996 } else {
11997 len += vallen = strlen(val);
11998 }
11999 INTOFF;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012000 nameeq = xmalloc(len);
Eric Andersencb57d552001-06-28 07:25:16 +000012001 memcpy(nameeq, name, namelen);
12002 nameeq[namelen] = '=';
12003 if (val) {
12004 memcpy(nameeq + namelen + 1, val, vallen + 1);
12005 } else {
12006 nameeq[namelen + 1] = '\0';
12007 }
12008 setvareq(nameeq, flags);
12009 INTON;
12010}
12011
12012
12013
12014/*
12015 * Same as setvar except that the variable and value are passed in
12016 * the first argument as name=value. Since the first argument will
12017 * be actually stored in the table, it should not be a string that
12018 * will go away.
12019 */
12020
12021static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012022setvareq(char *s, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000012023{
12024 struct var *vp, **vpp;
12025
12026 vpp = hashvar(s);
12027 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
12028 if ((vp = *findvar(vpp, s))) {
12029 if (vp->flags & VREADONLY) {
12030 size_t len = strchr(s, '=') - s;
12031 error("%.*s: is read only", len, s);
12032 }
12033 INTOFF;
12034
12035 if (vp->func && (flags & VNOFUNC) == 0)
12036 (*vp->func)(strchr(s, '=') + 1);
12037
12038 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12039 ckfree(vp->text);
12040
12041 vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
12042 vp->flags |= flags;
12043 vp->text = s;
12044
Eric Andersenec074692001-10-31 11:05:49 +000012045#ifdef ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000012046 /*
12047 * We could roll this to a function, to handle it as
12048 * a regular variable function callback, but why bother?
12049 */
12050 if (iflag && (vp == &vmpath || (vp == &vmail && !mpathset())))
12051 chkmail(1);
Eric Andersenec074692001-10-31 11:05:49 +000012052#endif
Eric Andersencb57d552001-06-28 07:25:16 +000012053 INTON;
12054 return;
12055 }
12056 /* not found */
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012057 vp = xmalloc(sizeof (*vp));
Eric Andersencb57d552001-06-28 07:25:16 +000012058 vp->flags = flags;
12059 vp->text = s;
12060 vp->next = *vpp;
12061 vp->func = NULL;
12062 *vpp = vp;
12063}
12064
12065
12066
12067/*
12068 * Process a linked list of variable assignments.
12069 */
12070
12071static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012072listsetvar(struct strlist *mylist)
12073{
Eric Andersencb57d552001-06-28 07:25:16 +000012074 struct strlist *lp;
12075
12076 INTOFF;
12077 for (lp = mylist ; lp ; lp = lp->next) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012078 setvareq(xstrdup(lp->text), 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012079 }
12080 INTON;
12081}
12082
12083
12084
12085/*
12086 * Find the value of a variable. Returns NULL if not set.
12087 */
12088
Eric Andersen62483552001-07-10 06:09:16 +000012089static const char *
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012090lookupvar(const char *name)
Eric Andersenec074692001-10-31 11:05:49 +000012091{
Eric Andersencb57d552001-06-28 07:25:16 +000012092 struct var *v;
12093
12094 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
12095 return strchr(v->text, '=') + 1;
12096 }
12097 return NULL;
12098}
12099
12100
12101
12102/*
12103 * Search the environment of a builtin command.
12104 */
12105
Eric Andersen62483552001-07-10 06:09:16 +000012106static const char *
12107bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012108{
Eric Andersen62483552001-07-10 06:09:16 +000012109 const struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012110
12111 for (sp = cmdenviron ; sp ; sp = sp->next) {
12112 if (varequal(sp->text, name))
12113 return strchr(sp->text, '=') + 1;
12114 }
12115 return lookupvar(name);
12116}
12117
12118
12119
12120/*
12121 * Generate a list of exported variables. This routine is used to construct
12122 * the third argument to execve when executing a program.
12123 */
12124
12125static char **
12126environment() {
12127 int nenv;
12128 struct var **vpp;
12129 struct var *vp;
12130 char **env;
12131 char **ep;
12132
12133 nenv = 0;
12134 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12135 for (vp = *vpp ; vp ; vp = vp->next)
12136 if (vp->flags & VEXPORT)
12137 nenv++;
12138 }
12139 ep = env = stalloc((nenv + 1) * sizeof *env);
12140 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12141 for (vp = *vpp ; vp ; vp = vp->next)
12142 if (vp->flags & VEXPORT)
12143 *ep++ = vp->text;
12144 }
12145 *ep = NULL;
12146 return env;
12147}
12148
12149
12150/*
12151 * Called when a shell procedure is invoked to clear out nonexported
12152 * variables. It is also necessary to reallocate variables of with
12153 * VSTACK set since these are currently allocated on the stack.
12154 */
12155
Eric Andersencb57d552001-06-28 07:25:16 +000012156static void
Eric Andersen2870d962001-07-02 17:27:21 +000012157shprocvar(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000012158 struct var **vpp;
12159 struct var *vp, **prev;
12160
12161 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12162 for (prev = vpp ; (vp = *prev) != NULL ; ) {
12163 if ((vp->flags & VEXPORT) == 0) {
12164 *prev = vp->next;
12165 if ((vp->flags & VTEXTFIXED) == 0)
12166 ckfree(vp->text);
12167 if ((vp->flags & VSTRFIXED) == 0)
12168 ckfree(vp);
12169 } else {
12170 if (vp->flags & VSTACK) {
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012171 vp->text = xstrdup(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012172 vp->flags &=~ VSTACK;
12173 }
12174 prev = &vp->next;
12175 }
12176 }
12177 }
12178 initvar();
12179}
12180
12181
12182
12183/*
12184 * Command to list all variables which are set. Currently this command
12185 * is invoked from the set command when the set command is called without
12186 * any variables.
12187 */
12188
12189static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012190showvarscmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012191{
12192 showvars(nullstr, VUNSET, VUNSET);
12193 return 0;
12194}
12195
12196
12197
12198/*
12199 * The export and readonly commands.
12200 */
12201
12202static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012203exportcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012204{
12205 struct var *vp;
12206 char *name;
12207 const char *p;
12208 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12209 int pflag;
12210
12211 listsetvar(cmdenviron);
12212 pflag = (nextopt("p") == 'p');
12213 if (argc > 1 && !pflag) {
12214 while ((name = *argptr++) != NULL) {
12215 if ((p = strchr(name, '=')) != NULL) {
12216 p++;
12217 } else {
12218 if ((vp = *findvar(hashvar(name), name))) {
12219 vp->flags |= flag;
12220 goto found;
12221 }
12222 }
12223 setvar(name, p, flag);
12224found:;
12225 }
12226 } else {
12227 showvars(argv[0], flag, 0);
12228 }
12229 return 0;
12230}
12231
Eric Andersen34506362001-08-02 05:02:46 +000012232
Eric Andersencb57d552001-06-28 07:25:16 +000012233/*
12234 * The "local" command.
12235 */
12236
Eric Andersen2870d962001-07-02 17:27:21 +000012237/* funcnest nonzero if we are currently evaluating a function */
12238
Eric Andersencb57d552001-06-28 07:25:16 +000012239static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012240localcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012241{
12242 char *name;
12243
Eric Andersen2870d962001-07-02 17:27:21 +000012244 if (! funcnest)
Eric Andersencb57d552001-06-28 07:25:16 +000012245 error("Not in a function");
12246 while ((name = *argptr++) != NULL) {
12247 mklocal(name);
12248 }
12249 return 0;
12250}
12251
12252
12253/*
12254 * Make a variable a local variable. When a variable is made local, it's
12255 * value and flags are saved in a localvar structure. The saved values
12256 * will be restored when the shell function returns. We handle the name
12257 * "-" as a special case.
12258 */
12259
12260static void
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012261mklocal(char *name)
12262{
Eric Andersencb57d552001-06-28 07:25:16 +000012263 struct localvar *lvp;
12264 struct var **vpp;
12265 struct var *vp;
12266
12267 INTOFF;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012268 lvp = xmalloc(sizeof (struct localvar));
Eric Andersencb57d552001-06-28 07:25:16 +000012269 if (name[0] == '-' && name[1] == '\0') {
12270 char *p;
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012271 p = xmalloc(sizeof optet_vals);
Eric Andersen2870d962001-07-02 17:27:21 +000012272 lvp->text = memcpy(p, optet_vals, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000012273 vp = NULL;
12274 } else {
12275 vpp = hashvar(name);
12276 vp = *findvar(vpp, name);
12277 if (vp == NULL) {
12278 if (strchr(name, '='))
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012279 setvareq(xstrdup(name), VSTRFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +000012280 else
12281 setvar(name, NULL, VSTRFIXED);
Eric Andersen2870d962001-07-02 17:27:21 +000012282 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012283 lvp->text = NULL;
12284 lvp->flags = VUNSET;
12285 } else {
12286 lvp->text = vp->text;
12287 lvp->flags = vp->flags;
12288 vp->flags |= VSTRFIXED|VTEXTFIXED;
12289 if (strchr(name, '='))
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012290 setvareq(xstrdup(name), 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012291 }
12292 }
12293 lvp->vp = vp;
12294 lvp->next = localvars;
12295 localvars = lvp;
12296 INTON;
12297}
12298
12299
12300/*
12301 * Called after a function returns.
12302 */
12303
12304static void
12305poplocalvars() {
12306 struct localvar *lvp;
12307 struct var *vp;
12308
12309 while ((lvp = localvars) != NULL) {
12310 localvars = lvp->next;
12311 vp = lvp->vp;
Eric Andersen2870d962001-07-02 17:27:21 +000012312 if (vp == NULL) { /* $- saved */
12313 memcpy(optet_vals, lvp->text, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000012314 ckfree(lvp->text);
12315 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12316 (void)unsetvar(vp->text);
12317 } else {
12318 if ((vp->flags & VTEXTFIXED) == 0)
12319 ckfree(vp->text);
12320 vp->flags = lvp->flags;
12321 vp->text = lvp->text;
12322 }
12323 ckfree(lvp);
12324 }
12325}
12326
12327
12328static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012329setvarcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012330{
12331 if (argc <= 2)
12332 return unsetcmd(argc, argv);
12333 else if (argc == 3)
12334 setvar(argv[1], argv[2], 0);
12335 else
12336 error("List assignment not implemented");
12337 return 0;
12338}
12339
12340
12341/*
12342 * The unset builtin command. We unset the function before we unset the
12343 * variable to allow a function to be unset when there is a readonly variable
12344 * with the same name.
12345 */
12346
12347static int
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012348unsetcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012349{
12350 char **ap;
12351 int i;
12352 int flg_func = 0;
12353 int flg_var = 0;
12354 int ret = 0;
12355
12356 while ((i = nextopt("vf")) != '\0') {
12357 if (i == 'f')
12358 flg_func = 1;
12359 else
12360 flg_var = 1;
12361 }
12362 if (flg_func == 0 && flg_var == 0)
12363 flg_var = 1;
12364
12365 for (ap = argptr; *ap ; ap++) {
12366 if (flg_func)
12367 unsetfunc(*ap);
12368 if (flg_var)
12369 ret |= unsetvar(*ap);
12370 }
12371 return ret;
12372}
12373
12374
12375/*
12376 * Unset the specified variable.
12377 */
12378
12379static int
Eric Andersen62483552001-07-10 06:09:16 +000012380unsetvar(const char *s)
12381{
Eric Andersencb57d552001-06-28 07:25:16 +000012382 struct var **vpp;
12383 struct var *vp;
12384
12385 vpp = findvar(hashvar(s), s);
12386 vp = *vpp;
12387 if (vp) {
12388 if (vp->flags & VREADONLY)
12389 return (1);
12390 INTOFF;
12391 if (*(strchr(vp->text, '=') + 1) != '\0')
12392 setvar(s, nullstr, 0);
12393 vp->flags &= ~VEXPORT;
12394 vp->flags |= VUNSET;
12395 if ((vp->flags & VSTRFIXED) == 0) {
12396 if ((vp->flags & VTEXTFIXED) == 0)
12397 ckfree(vp->text);
12398 *vpp = vp->next;
12399 ckfree(vp);
12400 }
12401 INTON;
12402 return (0);
12403 }
12404
12405 return (0);
12406}
12407
12408
12409
12410/*
12411 * Find the appropriate entry in the hash table from the name.
12412 */
12413
12414static struct var **
Eric Andersen62483552001-07-10 06:09:16 +000012415hashvar(const char *p)
12416{
Eric Andersencb57d552001-06-28 07:25:16 +000012417 unsigned int hashval;
12418
12419 hashval = ((unsigned char) *p) << 4;
12420 while (*p && *p != '=')
12421 hashval += (unsigned char) *p++;
12422 return &vartab[hashval % VTABSIZE];
12423}
12424
12425
12426
12427/*
12428 * Returns true if the two strings specify the same varable. The first
12429 * variable name is terminated by '='; the second may be terminated by
12430 * either '=' or '\0'.
12431 */
12432
12433static int
Eric Andersen62483552001-07-10 06:09:16 +000012434varequal(const char *p, const char *q)
12435{
Eric Andersencb57d552001-06-28 07:25:16 +000012436 while (*p == *q++) {
12437 if (*p++ == '=')
12438 return 1;
12439 }
12440 if (*p == '=' && *(q - 1) == '\0')
12441 return 1;
12442 return 0;
12443}
12444
12445static void
12446showvars(const char *myprefix, int mask, int xor)
12447{
12448 struct var **vpp;
12449 struct var *vp;
12450 const char *sep = myprefix == nullstr ? myprefix : spcstr;
12451
12452 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12453 for (vp = *vpp ; vp ; vp = vp->next) {
12454 if ((vp->flags & mask) ^ xor) {
12455 char *p;
12456 int len;
12457
12458 p = strchr(vp->text, '=') + 1;
12459 len = p - vp->text;
12460 p = single_quote(p);
12461
Eric Andersen62483552001-07-10 06:09:16 +000012462 printf("%s%s%.*s%s\n", myprefix, sep, len,
12463 vp->text, p);
Eric Andersencb57d552001-06-28 07:25:16 +000012464 stunalloc(p);
12465 }
12466 }
12467 }
12468}
12469
12470static struct var **
12471findvar(struct var **vpp, const char *name)
12472{
12473 for (; *vpp; vpp = &(*vpp)->next) {
12474 if (varequal((*vpp)->text, name)) {
12475 break;
12476 }
12477 }
12478 return vpp;
12479}
12480
12481/*
12482 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
12483 * This file contains code for the times builtin.
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012484 * $Id: ash.c,v 1.37 2001/12/06 03:37:38 aaronl Exp $
Eric Andersencb57d552001-06-28 07:25:16 +000012485 */
12486static int timescmd (int argc, char **argv)
12487{
12488 struct tms buf;
12489 long int clk_tck = sysconf(_SC_CLK_TCK);
12490
12491 times(&buf);
12492 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
12493 (int) (buf.tms_utime / clk_tck / 60),
12494 ((double) buf.tms_utime) / clk_tck,
12495 (int) (buf.tms_stime / clk_tck / 60),
12496 ((double) buf.tms_stime) / clk_tck,
12497 (int) (buf.tms_cutime / clk_tck / 60),
12498 ((double) buf.tms_cutime) / clk_tck,
12499 (int) (buf.tms_cstime / clk_tck / 60),
12500 ((double) buf.tms_cstime) / clk_tck);
12501 return 0;
12502}
12503
Eric Andersen74bcd162001-07-30 21:41:37 +000012504#ifdef ASH_MATH_SUPPORT
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012505/* The let builtin. */
12506int letcmd(int argc, char **argv)
Eric Andersen74bcd162001-07-30 21:41:37 +000012507{
Eric Andersen34506362001-08-02 05:02:46 +000012508 int errcode;
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012509 long result=0;
12510 if (argc == 2) {
12511 char *tmp, *expression, p[13];
12512 expression = strchr(argv[1], '=');
12513 if (!expression) {
Eric Andersen34506362001-08-02 05:02:46 +000012514 /* Cannot use 'error()' here, or the return code
12515 * will be incorrect */
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012516 out2fmt("sh: let: syntax error: \"%s\"\n", argv[1]);
12517 return 0;
Eric Andersen74bcd162001-07-30 21:41:37 +000012518 }
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012519 *expression = '\0';
12520 tmp = ++expression;
Eric Andersen34506362001-08-02 05:02:46 +000012521 result = arith(tmp, &errcode);
12522 if (errcode < 0) {
12523 /* Cannot use 'error()' here, or the return code
12524 * will be incorrect */
12525 out2fmt("sh: let: ");
12526 if(errcode == -2)
12527 out2fmt("divide by zero");
12528 else
12529 out2fmt("syntax error: \"%s=%s\"\n", argv[1], expression);
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012530 return 0;
12531 }
12532 snprintf(p, 12, "%ld", result);
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012533 setvar(argv[1], xstrdup(p), 0);
Eric Andersenfa1c5aa2001-07-31 21:38:23 +000012534 } else if (argc >= 3)
12535 synerror("invalid operand");
12536 return !result;
Eric Andersen74bcd162001-07-30 21:41:37 +000012537}
12538#endif
12539
12540
12541
Eric Andersendf82f612001-06-28 07:46:40 +000012542/*-
12543 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000012544 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000012545 *
12546 * This code is derived from software contributed to Berkeley by
12547 * Kenneth Almquist.
12548 *
12549 * Redistribution and use in source and binary forms, with or without
12550 * modification, are permitted provided that the following conditions
12551 * are met:
12552 * 1. Redistributions of source code must retain the above copyright
12553 * notice, this list of conditions and the following disclaimer.
12554 * 2. Redistributions in binary form must reproduce the above copyright
12555 * notice, this list of conditions and the following disclaimer in the
12556 * documentation and/or other materials provided with the distribution.
12557 *
Eric Andersen2870d962001-07-02 17:27:21 +000012558 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
12559 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000012560 *
12561 * 4. Neither the name of the University nor the names of its contributors
12562 * may be used to endorse or promote products derived from this software
12563 * without specific prior written permission.
12564 *
12565 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
12566 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
12567 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
12568 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
12569 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
12570 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
12571 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
12572 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
12573 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
12574 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
12575 * SUCH DAMAGE.
12576 */