Magellan Linux

Contents of /trunk/mkinitrd-magellan/busybox/shell/ash.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 816 - (show annotations) (download)
Fri Apr 24 18:33:46 2009 UTC (15 years, 1 month ago) by niro
File MIME type: text/plain
File size: 306829 byte(s)
-updated to busybox-1.13.4
1 /* vi: set sw=4 ts=4: */
2 /*
3 * ash shell port for busybox
4 *
5 * Copyright (c) 1989, 1991, 1993, 1994
6 * The Regents of the University of California. All rights reserved.
7 *
8 * Copyright (c) 1997-2005 Herbert Xu <herbert@gondor.apana.org.au>
9 * was re-ported from NetBSD and debianized.
10 *
11 * This code is derived from software contributed to Berkeley by
12 * Kenneth Almquist.
13 *
14 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
15 *
16 * Original BSD copyright notice is retained at the end of this file.
17 */
18
19 /*
20 * rewrite arith.y to micro stack based cryptic algorithm by
21 * Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
22 *
23 * Modified by Paul Mundt <lethal@linux-sh.org> (c) 2004 to support
24 * dynamic variables.
25 *
26 * Modified by Vladimir Oleynik <dzo@simtreas.ru> (c) 2001-2005 to be
27 * used in busybox and size optimizations,
28 * rewrote arith (see notes to this), added locale support,
29 * rewrote dynamic variables.
30 */
31
32 /*
33 * The following should be set to reflect the type of system you have:
34 * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
35 * define SYSV if you are running under System V.
36 * define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
37 * define DEBUG=2 to compile in and turn on debugging.
38 *
39 * When debugging is on, debugging info will be written to ./trace and
40 * a quit signal will generate a core dump.
41 */
42 #define DEBUG 0
43 /* Tweak debug output verbosity here */
44 #define DEBUG_TIME 0
45 #define DEBUG_PID 1
46 #define DEBUG_SIG 1
47
48 #define PROFILE 0
49
50 #define IFS_BROKEN
51
52 #define JOBS ENABLE_ASH_JOB_CONTROL
53
54 #if DEBUG
55 # ifndef _GNU_SOURCE
56 # define _GNU_SOURCE
57 # endif
58 #endif
59
60 #include "busybox.h" /* for applet_names */
61 #include <paths.h>
62 #include <setjmp.h>
63 #include <fnmatch.h>
64 #if JOBS || ENABLE_ASH_READ_NCHARS
65 # include <termios.h>
66 #endif
67
68 #ifndef PIPE_BUF
69 # define PIPE_BUF 4096 /* amount of buffering in a pipe */
70 #endif
71
72 #if defined(__uClinux__)
73 # error "Do not even bother, ash will not run on uClinux"
74 #endif
75
76
77 /* ============ Hash table sizes. Configurable. */
78
79 #define VTABSIZE 39
80 #define ATABSIZE 39
81 #define CMDTABLESIZE 31 /* should be prime */
82
83
84 /* ============ Shell options */
85
86 static const char *const optletters_optnames[] = {
87 "e" "errexit",
88 "f" "noglob",
89 "I" "ignoreeof",
90 "i" "interactive",
91 "m" "monitor",
92 "n" "noexec",
93 "s" "stdin",
94 "x" "xtrace",
95 "v" "verbose",
96 "C" "noclobber",
97 "a" "allexport",
98 "b" "notify",
99 "u" "nounset",
100 "\0" "vi"
101 #if DEBUG
102 ,"\0" "nolog"
103 ,"\0" "debug"
104 #endif
105 };
106
107 #define optletters(n) optletters_optnames[(n)][0]
108 #define optnames(n) (&optletters_optnames[(n)][1])
109
110 enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
111
112
113 /* ============ Misc data */
114
115 static const char homestr[] ALIGN1 = "HOME";
116 static const char snlfmt[] ALIGN1 = "%s\n";
117 static const char illnum[] ALIGN1 = "Illegal number: %s";
118
119 /*
120 * We enclose jmp_buf in a structure so that we can declare pointers to
121 * jump locations. The global variable handler contains the location to
122 * jump to when an exception occurs, and the global variable exception
123 * contains a code identifying the exception. To implement nested
124 * exception handlers, the user should save the value of handler on entry
125 * to an inner scope, set handler to point to a jmploc structure for the
126 * inner scope, and restore handler on exit from the scope.
127 */
128 struct jmploc {
129 jmp_buf loc;
130 };
131
132 struct globals_misc {
133 /* pid of main shell */
134 int rootpid;
135 /* shell level: 0 for the main shell, 1 for its children, and so on */
136 int shlvl;
137 #define rootshell (!shlvl)
138 char *minusc; /* argument to -c option */
139
140 char *curdir; // = nullstr; /* current working directory */
141 char *physdir; // = nullstr; /* physical working directory */
142
143 char *arg0; /* value of $0 */
144
145 struct jmploc *exception_handler;
146
147 // disabled by vda: cannot understand how it was supposed to work -
148 // cannot fix bugs. That's why you have to explain your non-trivial designs!
149 // /* do we generate EXSIG events */
150 // int exsig; /* counter */
151 volatile int suppressint; /* counter */
152 volatile /*sig_atomic_t*/ smallint intpending; /* 1 = got SIGINT */
153 /* last pending signal */
154 volatile /*sig_atomic_t*/ smallint pendingsig;
155 smallint exception; /* kind of exception (0..5) */
156 /* exceptions */
157 #define EXINT 0 /* SIGINT received */
158 #define EXERROR 1 /* a generic error */
159 #define EXSHELLPROC 2 /* execute a shell procedure */
160 #define EXEXEC 3 /* command execution failed */
161 #define EXEXIT 4 /* exit the shell */
162 #define EXSIG 5 /* trapped signal in wait(1) */
163
164 smallint isloginsh;
165 char nullstr[1]; /* zero length string */
166
167 char optlist[NOPTS];
168 #define eflag optlist[0]
169 #define fflag optlist[1]
170 #define Iflag optlist[2]
171 #define iflag optlist[3]
172 #define mflag optlist[4]
173 #define nflag optlist[5]
174 #define sflag optlist[6]
175 #define xflag optlist[7]
176 #define vflag optlist[8]
177 #define Cflag optlist[9]
178 #define aflag optlist[10]
179 #define bflag optlist[11]
180 #define uflag optlist[12]
181 #define viflag optlist[13]
182 #if DEBUG
183 #define nolog optlist[14]
184 #define debug optlist[15]
185 #endif
186
187 /* trap handler commands */
188 /*
189 * Sigmode records the current value of the signal handlers for the various
190 * modes. A value of zero means that the current handler is not known.
191 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
192 */
193 char sigmode[NSIG - 1];
194 #define S_DFL 1 /* default signal handling (SIG_DFL) */
195 #define S_CATCH 2 /* signal is caught */
196 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
197 #define S_HARD_IGN 4 /* signal is ignored permenantly */
198 #define S_RESET 5 /* temporary - to reset a hard ignored sig */
199
200 /* indicates specified signal received */
201 char gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
202 char *trap[NSIG];
203
204 /* Rarely referenced stuff */
205 #if ENABLE_ASH_RANDOM_SUPPORT
206 /* Random number generators */
207 int32_t random_galois_LFSR; /* Galois LFSR (fast but weak). signed! */
208 uint32_t random_LCG; /* LCG (fast but weak) */
209 #endif
210 pid_t backgndpid; /* pid of last background process */
211 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
212 };
213 extern struct globals_misc *const ash_ptr_to_globals_misc;
214 #define G_misc (*ash_ptr_to_globals_misc)
215 #define rootpid (G_misc.rootpid )
216 #define shlvl (G_misc.shlvl )
217 #define minusc (G_misc.minusc )
218 #define curdir (G_misc.curdir )
219 #define physdir (G_misc.physdir )
220 #define arg0 (G_misc.arg0 )
221 #define exception_handler (G_misc.exception_handler)
222 #define exception (G_misc.exception )
223 #define suppressint (G_misc.suppressint )
224 #define intpending (G_misc.intpending )
225 //#define exsig (G_misc.exsig )
226 #define pendingsig (G_misc.pendingsig )
227 #define isloginsh (G_misc.isloginsh )
228 #define nullstr (G_misc.nullstr )
229 #define optlist (G_misc.optlist )
230 #define sigmode (G_misc.sigmode )
231 #define gotsig (G_misc.gotsig )
232 #define trap (G_misc.trap )
233 #define random_galois_LFSR (G_misc.random_galois_LFSR)
234 #define random_LCG (G_misc.random_LCG )
235 #define backgndpid (G_misc.backgndpid )
236 #define job_warning (G_misc.job_warning)
237 #define INIT_G_misc() do { \
238 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
239 barrier(); \
240 curdir = nullstr; \
241 physdir = nullstr; \
242 } while (0)
243
244
245 /* ============ DEBUG */
246 #if DEBUG
247 static void trace_printf(const char *fmt, ...);
248 static void trace_vprintf(const char *fmt, va_list va);
249 # define TRACE(param) trace_printf param
250 # define TRACEV(param) trace_vprintf param
251 # define close(f) do { \
252 int dfd = (f); \
253 if (close(dfd) < 0) \
254 bb_error_msg("bug on %d: closing %d(%x)", \
255 __LINE__, dfd, dfd); \
256 } while (0)
257 #else
258 # define TRACE(param)
259 # define TRACEV(param)
260 #endif
261
262
263 /* ============ Utility functions */
264 #define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0)
265
266 /* C99 say: "char" declaration may be signed or unsigned by default */
267 #define signed_char2int(sc) ((int)(signed char)(sc))
268
269 static int isdigit_str9(const char *str)
270 {
271 int maxlen = 9 + 1; /* max 9 digits: 999999999 */
272 while (--maxlen && isdigit(*str))
273 str++;
274 return (*str == '\0');
275 }
276
277
278 /* ============ Interrupts / exceptions */
279 /*
280 * These macros allow the user to suspend the handling of interrupt signals
281 * over a period of time. This is similar to SIGHOLD or to sigblock, but
282 * much more efficient and portable. (But hacking the kernel is so much
283 * more fun than worrying about efficiency and portability. :-))
284 */
285 #define INT_OFF do { \
286 suppressint++; \
287 xbarrier(); \
288 } while (0)
289
290 /*
291 * Called to raise an exception. Since C doesn't include exceptions, we
292 * just do a longjmp to the exception handler. The type of exception is
293 * stored in the global variable "exception".
294 */
295 static void raise_exception(int) NORETURN;
296 static void
297 raise_exception(int e)
298 {
299 #if DEBUG
300 if (exception_handler == NULL)
301 abort();
302 #endif
303 INT_OFF;
304 exception = e;
305 longjmp(exception_handler->loc, 1);
306 }
307 #if DEBUG
308 #define raise_exception(e) do { \
309 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
310 raise_exception(e); \
311 } while (0)
312 #endif
313
314 /*
315 * Called from trap.c when a SIGINT is received. (If the user specifies
316 * that SIGINT is to be trapped or ignored using the trap builtin, then
317 * this routine is not called.) Suppressint is nonzero when interrupts
318 * are held using the INT_OFF macro. (The test for iflag is just
319 * defensive programming.)
320 */
321 static void raise_interrupt(void) NORETURN;
322 static void
323 raise_interrupt(void)
324 {
325 int i;
326
327 intpending = 0;
328 /* Signal is not automatically unmasked after it is raised,
329 * do it ourself - unmask all signals */
330 sigprocmask_allsigs(SIG_UNBLOCK);
331 /* pendingsig = 0; - now done in onsig() */
332
333 i = EXSIG;
334 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
335 if (!(rootshell && iflag)) {
336 /* Kill ourself with SIGINT */
337 signal(SIGINT, SIG_DFL);
338 raise(SIGINT);
339 }
340 i = EXINT;
341 }
342 raise_exception(i);
343 /* NOTREACHED */
344 }
345 #if DEBUG
346 #define raise_interrupt() do { \
347 TRACE(("raising interrupt on line %d\n", __LINE__)); \
348 raise_interrupt(); \
349 } while (0)
350 #endif
351
352 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
353 static void
354 int_on(void)
355 {
356 if (--suppressint == 0 && intpending) {
357 raise_interrupt();
358 }
359 }
360 #define INT_ON int_on()
361 static void
362 force_int_on(void)
363 {
364 suppressint = 0;
365 if (intpending)
366 raise_interrupt();
367 }
368 #define FORCE_INT_ON force_int_on()
369
370 #else /* !ASH_OPTIMIZE_FOR_SIZE */
371
372 #define INT_ON do { \
373 xbarrier(); \
374 if (--suppressint == 0 && intpending) \
375 raise_interrupt(); \
376 } while (0)
377 #define FORCE_INT_ON do { \
378 xbarrier(); \
379 suppressint = 0; \
380 if (intpending) \
381 raise_interrupt(); \
382 } while (0)
383 #endif /* !ASH_OPTIMIZE_FOR_SIZE */
384
385 #define SAVE_INT(v) ((v) = suppressint)
386
387 #define RESTORE_INT(v) do { \
388 xbarrier(); \
389 suppressint = (v); \
390 if (suppressint == 0 && intpending) \
391 raise_interrupt(); \
392 } while (0)
393
394 /*
395 * Ignore a signal. Only one usage site - in forkchild()
396 */
397 static void
398 ignoresig(int signo)
399 {
400 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
401 signal(signo, SIG_IGN);
402 }
403 sigmode[signo - 1] = S_HARD_IGN;
404 }
405
406 /*
407 * Signal handler. Only one usage site - in setsignal()
408 */
409 static void
410 onsig(int signo)
411 {
412 gotsig[signo - 1] = 1;
413
414 if (/* exsig || */ (signo == SIGINT && !trap[SIGINT])) {
415 if (!suppressint) {
416 pendingsig = 0;
417 raise_interrupt(); /* does not return */
418 }
419 intpending = 1;
420 } else {
421 pendingsig = signo;
422 }
423 }
424
425
426 /* ============ Stdout/stderr output */
427
428 static void
429 outstr(const char *p, FILE *file)
430 {
431 INT_OFF;
432 fputs(p, file);
433 INT_ON;
434 }
435
436 static void
437 flush_stdout_stderr(void)
438 {
439 INT_OFF;
440 fflush(stdout);
441 fflush(stderr);
442 INT_ON;
443 }
444
445 static void
446 flush_stderr(void)
447 {
448 INT_OFF;
449 fflush(stderr);
450 INT_ON;
451 }
452
453 static void
454 outcslow(int c, FILE *dest)
455 {
456 INT_OFF;
457 putc(c, dest);
458 fflush(dest);
459 INT_ON;
460 }
461
462 static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
463 static int
464 out1fmt(const char *fmt, ...)
465 {
466 va_list ap;
467 int r;
468
469 INT_OFF;
470 va_start(ap, fmt);
471 r = vprintf(fmt, ap);
472 va_end(ap);
473 INT_ON;
474 return r;
475 }
476
477 static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
478 static int
479 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
480 {
481 va_list ap;
482 int ret;
483
484 va_start(ap, fmt);
485 INT_OFF;
486 ret = vsnprintf(outbuf, length, fmt, ap);
487 va_end(ap);
488 INT_ON;
489 return ret;
490 }
491
492 static void
493 out1str(const char *p)
494 {
495 outstr(p, stdout);
496 }
497
498 static void
499 out2str(const char *p)
500 {
501 outstr(p, stderr);
502 flush_stderr();
503 }
504
505
506 /* ============ Parser structures */
507
508 /* control characters in argument strings */
509 #define CTLESC '\201' /* escape next character */
510 #define CTLVAR '\202' /* variable defn */
511 #define CTLENDVAR '\203'
512 #define CTLBACKQ '\204'
513 #define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
514 /* CTLBACKQ | CTLQUOTE == '\205' */
515 #define CTLARI '\206' /* arithmetic expression */
516 #define CTLENDARI '\207'
517 #define CTLQUOTEMARK '\210'
518
519 /* variable substitution byte (follows CTLVAR) */
520 #define VSTYPE 0x0f /* type of variable substitution */
521 #define VSNUL 0x10 /* colon--treat the empty string as unset */
522 #define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
523
524 /* values of VSTYPE field */
525 #define VSNORMAL 0x1 /* normal variable: $var or ${var} */
526 #define VSMINUS 0x2 /* ${var-text} */
527 #define VSPLUS 0x3 /* ${var+text} */
528 #define VSQUESTION 0x4 /* ${var?message} */
529 #define VSASSIGN 0x5 /* ${var=text} */
530 #define VSTRIMRIGHT 0x6 /* ${var%pattern} */
531 #define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
532 #define VSTRIMLEFT 0x8 /* ${var#pattern} */
533 #define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
534 #define VSLENGTH 0xa /* ${#var} */
535 #if ENABLE_ASH_BASH_COMPAT
536 #define VSSUBSTR 0xc /* ${var:position:length} */
537 #define VSREPLACE 0xd /* ${var/pattern/replacement} */
538 #define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
539 #endif
540
541 static const char dolatstr[] ALIGN1 = {
542 CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'
543 };
544
545 #define NCMD 0
546 #define NPIPE 1
547 #define NREDIR 2
548 #define NBACKGND 3
549 #define NSUBSHELL 4
550 #define NAND 5
551 #define NOR 6
552 #define NSEMI 7
553 #define NIF 8
554 #define NWHILE 9
555 #define NUNTIL 10
556 #define NFOR 11
557 #define NCASE 12
558 #define NCLIST 13
559 #define NDEFUN 14
560 #define NARG 15
561 #define NTO 16
562 #if ENABLE_ASH_BASH_COMPAT
563 #define NTO2 17
564 #endif
565 #define NCLOBBER 18
566 #define NFROM 19
567 #define NFROMTO 20
568 #define NAPPEND 21
569 #define NTOFD 22
570 #define NFROMFD 23
571 #define NHERE 24
572 #define NXHERE 25
573 #define NNOT 26
574 #define N_NUMBER 27
575
576 union node;
577
578 struct ncmd {
579 smallint type; /* Nxxxx */
580 union node *assign;
581 union node *args;
582 union node *redirect;
583 };
584
585 struct npipe {
586 smallint type;
587 smallint pipe_backgnd;
588 struct nodelist *cmdlist;
589 };
590
591 struct nredir {
592 smallint type;
593 union node *n;
594 union node *redirect;
595 };
596
597 struct nbinary {
598 smallint type;
599 union node *ch1;
600 union node *ch2;
601 };
602
603 struct nif {
604 smallint type;
605 union node *test;
606 union node *ifpart;
607 union node *elsepart;
608 };
609
610 struct nfor {
611 smallint type;
612 union node *args;
613 union node *body;
614 char *var;
615 };
616
617 struct ncase {
618 smallint type;
619 union node *expr;
620 union node *cases;
621 };
622
623 struct nclist {
624 smallint type;
625 union node *next;
626 union node *pattern;
627 union node *body;
628 };
629
630 struct narg {
631 smallint type;
632 union node *next;
633 char *text;
634 struct nodelist *backquote;
635 };
636
637 /* nfile and ndup layout must match!
638 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
639 * that it is actually NTO2 (>&file), and change its type.
640 */
641 struct nfile {
642 smallint type;
643 union node *next;
644 int fd;
645 int _unused_dupfd;
646 union node *fname;
647 char *expfname;
648 };
649
650 struct ndup {
651 smallint type;
652 union node *next;
653 int fd;
654 int dupfd;
655 union node *vname;
656 char *_unused_expfname;
657 };
658
659 struct nhere {
660 smallint type;
661 union node *next;
662 int fd;
663 union node *doc;
664 };
665
666 struct nnot {
667 smallint type;
668 union node *com;
669 };
670
671 union node {
672 smallint type;
673 struct ncmd ncmd;
674 struct npipe npipe;
675 struct nredir nredir;
676 struct nbinary nbinary;
677 struct nif nif;
678 struct nfor nfor;
679 struct ncase ncase;
680 struct nclist nclist;
681 struct narg narg;
682 struct nfile nfile;
683 struct ndup ndup;
684 struct nhere nhere;
685 struct nnot nnot;
686 };
687
688 struct nodelist {
689 struct nodelist *next;
690 union node *n;
691 };
692
693 struct funcnode {
694 int count;
695 union node n;
696 };
697
698 /*
699 * Free a parse tree.
700 */
701 static void
702 freefunc(struct funcnode *f)
703 {
704 if (f && --f->count < 0)
705 free(f);
706 }
707
708
709 /* ============ Debugging output */
710
711 #if DEBUG
712
713 static FILE *tracefile;
714
715 static void
716 trace_printf(const char *fmt, ...)
717 {
718 va_list va;
719
720 if (debug != 1)
721 return;
722 if (DEBUG_TIME)
723 fprintf(tracefile, "%u ", (int) time(NULL));
724 if (DEBUG_PID)
725 fprintf(tracefile, "[%u] ", (int) getpid());
726 if (DEBUG_SIG)
727 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pendingsig, intpending, suppressint);
728 va_start(va, fmt);
729 vfprintf(tracefile, fmt, va);
730 va_end(va);
731 }
732
733 static void
734 trace_vprintf(const char *fmt, va_list va)
735 {
736 if (debug != 1)
737 return;
738 if (DEBUG_TIME)
739 fprintf(tracefile, "%u ", (int) time(NULL));
740 if (DEBUG_PID)
741 fprintf(tracefile, "[%u] ", (int) getpid());
742 if (DEBUG_SIG)
743 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pendingsig, intpending, suppressint);
744 vfprintf(tracefile, fmt, va);
745 }
746
747 static void
748 trace_puts(const char *s)
749 {
750 if (debug != 1)
751 return;
752 fputs(s, tracefile);
753 }
754
755 static void
756 trace_puts_quoted(char *s)
757 {
758 char *p;
759 char c;
760
761 if (debug != 1)
762 return;
763 putc('"', tracefile);
764 for (p = s; *p; p++) {
765 switch (*p) {
766 case '\n': c = 'n'; goto backslash;
767 case '\t': c = 't'; goto backslash;
768 case '\r': c = 'r'; goto backslash;
769 case '"': c = '"'; goto backslash;
770 case '\\': c = '\\'; goto backslash;
771 case CTLESC: c = 'e'; goto backslash;
772 case CTLVAR: c = 'v'; goto backslash;
773 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
774 case CTLBACKQ: c = 'q'; goto backslash;
775 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
776 backslash:
777 putc('\\', tracefile);
778 putc(c, tracefile);
779 break;
780 default:
781 if (*p >= ' ' && *p <= '~')
782 putc(*p, tracefile);
783 else {
784 putc('\\', tracefile);
785 putc(*p >> 6 & 03, tracefile);
786 putc(*p >> 3 & 07, tracefile);
787 putc(*p & 07, tracefile);
788 }
789 break;
790 }
791 }
792 putc('"', tracefile);
793 }
794
795 static void
796 trace_puts_args(char **ap)
797 {
798 if (debug != 1)
799 return;
800 if (!*ap)
801 return;
802 while (1) {
803 trace_puts_quoted(*ap);
804 if (!*++ap) {
805 putc('\n', tracefile);
806 break;
807 }
808 putc(' ', tracefile);
809 }
810 }
811
812 static void
813 opentrace(void)
814 {
815 char s[100];
816 #ifdef O_APPEND
817 int flags;
818 #endif
819
820 if (debug != 1) {
821 if (tracefile)
822 fflush(tracefile);
823 /* leave open because libedit might be using it */
824 return;
825 }
826 strcpy(s, "./trace");
827 if (tracefile) {
828 if (!freopen(s, "a", tracefile)) {
829 fprintf(stderr, "Can't re-open %s\n", s);
830 debug = 0;
831 return;
832 }
833 } else {
834 tracefile = fopen(s, "a");
835 if (tracefile == NULL) {
836 fprintf(stderr, "Can't open %s\n", s);
837 debug = 0;
838 return;
839 }
840 }
841 #ifdef O_APPEND
842 flags = fcntl(fileno(tracefile), F_GETFL);
843 if (flags >= 0)
844 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
845 #endif
846 setlinebuf(tracefile);
847 fputs("\nTracing started.\n", tracefile);
848 }
849
850 static void
851 indent(int amount, char *pfx, FILE *fp)
852 {
853 int i;
854
855 for (i = 0; i < amount; i++) {
856 if (pfx && i == amount - 1)
857 fputs(pfx, fp);
858 putc('\t', fp);
859 }
860 }
861
862 /* little circular references here... */
863 static void shtree(union node *n, int ind, char *pfx, FILE *fp);
864
865 static void
866 sharg(union node *arg, FILE *fp)
867 {
868 char *p;
869 struct nodelist *bqlist;
870 int subtype;
871
872 if (arg->type != NARG) {
873 out1fmt("<node type %d>\n", arg->type);
874 abort();
875 }
876 bqlist = arg->narg.backquote;
877 for (p = arg->narg.text; *p; p++) {
878 switch (*p) {
879 case CTLESC:
880 putc(*++p, fp);
881 break;
882 case CTLVAR:
883 putc('$', fp);
884 putc('{', fp);
885 subtype = *++p;
886 if (subtype == VSLENGTH)
887 putc('#', fp);
888
889 while (*p != '=')
890 putc(*p++, fp);
891
892 if (subtype & VSNUL)
893 putc(':', fp);
894
895 switch (subtype & VSTYPE) {
896 case VSNORMAL:
897 putc('}', fp);
898 break;
899 case VSMINUS:
900 putc('-', fp);
901 break;
902 case VSPLUS:
903 putc('+', fp);
904 break;
905 case VSQUESTION:
906 putc('?', fp);
907 break;
908 case VSASSIGN:
909 putc('=', fp);
910 break;
911 case VSTRIMLEFT:
912 putc('#', fp);
913 break;
914 case VSTRIMLEFTMAX:
915 putc('#', fp);
916 putc('#', fp);
917 break;
918 case VSTRIMRIGHT:
919 putc('%', fp);
920 break;
921 case VSTRIMRIGHTMAX:
922 putc('%', fp);
923 putc('%', fp);
924 break;
925 case VSLENGTH:
926 break;
927 default:
928 out1fmt("<subtype %d>", subtype);
929 }
930 break;
931 case CTLENDVAR:
932 putc('}', fp);
933 break;
934 case CTLBACKQ:
935 case CTLBACKQ|CTLQUOTE:
936 putc('$', fp);
937 putc('(', fp);
938 shtree(bqlist->n, -1, NULL, fp);
939 putc(')', fp);
940 break;
941 default:
942 putc(*p, fp);
943 break;
944 }
945 }
946 }
947
948 static void
949 shcmd(union node *cmd, FILE *fp)
950 {
951 union node *np;
952 int first;
953 const char *s;
954 int dftfd;
955
956 first = 1;
957 for (np = cmd->ncmd.args; np; np = np->narg.next) {
958 if (!first)
959 putc(' ', fp);
960 sharg(np, fp);
961 first = 0;
962 }
963 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
964 if (!first)
965 putc(' ', fp);
966 dftfd = 0;
967 switch (np->nfile.type) {
968 case NTO: s = ">>"+1; dftfd = 1; break;
969 case NCLOBBER: s = ">|"; dftfd = 1; break;
970 case NAPPEND: s = ">>"; dftfd = 1; break;
971 #if ENABLE_ASH_BASH_COMPAT
972 case NTO2:
973 #endif
974 case NTOFD: s = ">&"; dftfd = 1; break;
975 case NFROM: s = "<"; break;
976 case NFROMFD: s = "<&"; break;
977 case NFROMTO: s = "<>"; break;
978 default: s = "*error*"; break;
979 }
980 if (np->nfile.fd != dftfd)
981 fprintf(fp, "%d", np->nfile.fd);
982 fputs(s, fp);
983 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
984 fprintf(fp, "%d", np->ndup.dupfd);
985 } else {
986 sharg(np->nfile.fname, fp);
987 }
988 first = 0;
989 }
990 }
991
992 static void
993 shtree(union node *n, int ind, char *pfx, FILE *fp)
994 {
995 struct nodelist *lp;
996 const char *s;
997
998 if (n == NULL)
999 return;
1000
1001 indent(ind, pfx, fp);
1002 switch (n->type) {
1003 case NSEMI:
1004 s = "; ";
1005 goto binop;
1006 case NAND:
1007 s = " && ";
1008 goto binop;
1009 case NOR:
1010 s = " || ";
1011 binop:
1012 shtree(n->nbinary.ch1, ind, NULL, fp);
1013 /* if (ind < 0) */
1014 fputs(s, fp);
1015 shtree(n->nbinary.ch2, ind, NULL, fp);
1016 break;
1017 case NCMD:
1018 shcmd(n, fp);
1019 if (ind >= 0)
1020 putc('\n', fp);
1021 break;
1022 case NPIPE:
1023 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
1024 shcmd(lp->n, fp);
1025 if (lp->next)
1026 fputs(" | ", fp);
1027 }
1028 if (n->npipe.pipe_backgnd)
1029 fputs(" &", fp);
1030 if (ind >= 0)
1031 putc('\n', fp);
1032 break;
1033 default:
1034 fprintf(fp, "<node type %d>", n->type);
1035 if (ind >= 0)
1036 putc('\n', fp);
1037 break;
1038 }
1039 }
1040
1041 static void
1042 showtree(union node *n)
1043 {
1044 trace_puts("showtree called\n");
1045 shtree(n, 1, NULL, stdout);
1046 }
1047
1048 #endif /* DEBUG */
1049
1050
1051 /* ============ Parser data */
1052
1053 /*
1054 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1055 */
1056 struct strlist {
1057 struct strlist *next;
1058 char *text;
1059 };
1060
1061 struct alias;
1062
1063 struct strpush {
1064 struct strpush *prev; /* preceding string on stack */
1065 char *prevstring;
1066 int prevnleft;
1067 #if ENABLE_ASH_ALIAS
1068 struct alias *ap; /* if push was associated with an alias */
1069 #endif
1070 char *string; /* remember the string since it may change */
1071 };
1072
1073 struct parsefile {
1074 struct parsefile *prev; /* preceding file on stack */
1075 int linno; /* current line */
1076 int fd; /* file descriptor (or -1 if string) */
1077 int nleft; /* number of chars left in this line */
1078 int lleft; /* number of chars left in this buffer */
1079 char *nextc; /* next char in buffer */
1080 char *buf; /* input buffer */
1081 struct strpush *strpush; /* for pushing strings at this level */
1082 struct strpush basestrpush; /* so pushing one is fast */
1083 };
1084
1085 static struct parsefile basepf; /* top level input file */
1086 static struct parsefile *g_parsefile = &basepf; /* current input file */
1087 static int startlinno; /* line # where last token started */
1088 static char *commandname; /* currently executing command */
1089 static struct strlist *cmdenviron; /* environment for builtin command */
1090 static uint8_t exitstatus; /* exit status of last command */
1091
1092
1093 /* ============ Message printing */
1094
1095 static void
1096 ash_vmsg(const char *msg, va_list ap)
1097 {
1098 fprintf(stderr, "%s: ", arg0);
1099 if (commandname) {
1100 if (strcmp(arg0, commandname))
1101 fprintf(stderr, "%s: ", commandname);
1102 if (!iflag || g_parsefile->fd)
1103 fprintf(stderr, "line %d: ", startlinno);
1104 }
1105 vfprintf(stderr, msg, ap);
1106 outcslow('\n', stderr);
1107 }
1108
1109 /*
1110 * Exverror is called to raise the error exception. If the second argument
1111 * is not NULL then error prints an error message using printf style
1112 * formatting. It then raises the error exception.
1113 */
1114 static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
1115 static void
1116 ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
1117 {
1118 #if DEBUG
1119 if (msg) {
1120 TRACE(("ash_vmsg_and_raise(%d, \"", cond));
1121 TRACEV((msg, ap));
1122 TRACE(("\") pid=%d\n", getpid()));
1123 } else
1124 TRACE(("ash_vmsg_and_raise(%d, NULL) pid=%d\n", cond, getpid()));
1125 if (msg)
1126 #endif
1127 ash_vmsg(msg, ap);
1128
1129 flush_stdout_stderr();
1130 raise_exception(cond);
1131 /* NOTREACHED */
1132 }
1133
1134 static void ash_msg_and_raise_error(const char *, ...) NORETURN;
1135 static void
1136 ash_msg_and_raise_error(const char *msg, ...)
1137 {
1138 va_list ap;
1139
1140 va_start(ap, msg);
1141 ash_vmsg_and_raise(EXERROR, msg, ap);
1142 /* NOTREACHED */
1143 va_end(ap);
1144 }
1145
1146 static void ash_msg_and_raise(int, const char *, ...) NORETURN;
1147 static void
1148 ash_msg_and_raise(int cond, const char *msg, ...)
1149 {
1150 va_list ap;
1151
1152 va_start(ap, msg);
1153 ash_vmsg_and_raise(cond, msg, ap);
1154 /* NOTREACHED */
1155 va_end(ap);
1156 }
1157
1158 /*
1159 * error/warning routines for external builtins
1160 */
1161 static void
1162 ash_msg(const char *fmt, ...)
1163 {
1164 va_list ap;
1165
1166 va_start(ap, fmt);
1167 ash_vmsg(fmt, ap);
1168 va_end(ap);
1169 }
1170
1171 /*
1172 * Return a string describing an error. The returned string may be a
1173 * pointer to a static buffer that will be overwritten on the next call.
1174 * Action describes the operation that got the error.
1175 */
1176 static const char *
1177 errmsg(int e, const char *em)
1178 {
1179 if (e == ENOENT || e == ENOTDIR) {
1180 return em;
1181 }
1182 return strerror(e);
1183 }
1184
1185
1186 /* ============ Memory allocation */
1187
1188 /*
1189 * It appears that grabstackstr() will barf with such alignments
1190 * because stalloc() will return a string allocated in a new stackblock.
1191 */
1192 #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1193 enum {
1194 /* Most machines require the value returned from malloc to be aligned
1195 * in some way. The following macro will get this right
1196 * on many machines. */
1197 SHELL_SIZE = sizeof(union {int i; char *cp; double d; }) - 1,
1198 /* Minimum size of a block */
1199 MINSIZE = SHELL_ALIGN(504),
1200 };
1201
1202 struct stack_block {
1203 struct stack_block *prev;
1204 char space[MINSIZE];
1205 };
1206
1207 struct stackmark {
1208 struct stack_block *stackp;
1209 char *stacknxt;
1210 size_t stacknleft;
1211 struct stackmark *marknext;
1212 };
1213
1214
1215 struct globals_memstack {
1216 struct stack_block *g_stackp; // = &stackbase;
1217 struct stackmark *markp;
1218 char *g_stacknxt; // = stackbase.space;
1219 char *sstrend; // = stackbase.space + MINSIZE;
1220 size_t g_stacknleft; // = MINSIZE;
1221 int herefd; // = -1;
1222 struct stack_block stackbase;
1223 };
1224 extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1225 #define G_memstack (*ash_ptr_to_globals_memstack)
1226 #define g_stackp (G_memstack.g_stackp )
1227 #define markp (G_memstack.markp )
1228 #define g_stacknxt (G_memstack.g_stacknxt )
1229 #define sstrend (G_memstack.sstrend )
1230 #define g_stacknleft (G_memstack.g_stacknleft)
1231 #define herefd (G_memstack.herefd )
1232 #define stackbase (G_memstack.stackbase )
1233 #define INIT_G_memstack() do { \
1234 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1235 barrier(); \
1236 g_stackp = &stackbase; \
1237 g_stacknxt = stackbase.space; \
1238 g_stacknleft = MINSIZE; \
1239 sstrend = stackbase.space + MINSIZE; \
1240 herefd = -1; \
1241 } while (0)
1242
1243 #define stackblock() ((void *)g_stacknxt)
1244 #define stackblocksize() g_stacknleft
1245
1246
1247 static void *
1248 ckrealloc(void * p, size_t nbytes)
1249 {
1250 p = realloc(p, nbytes);
1251 if (!p)
1252 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1253 return p;
1254 }
1255
1256 static void *
1257 ckmalloc(size_t nbytes)
1258 {
1259 return ckrealloc(NULL, nbytes);
1260 }
1261
1262 static void *
1263 ckzalloc(size_t nbytes)
1264 {
1265 return memset(ckmalloc(nbytes), 0, nbytes);
1266 }
1267
1268 /*
1269 * Make a copy of a string in safe storage.
1270 */
1271 static char *
1272 ckstrdup(const char *s)
1273 {
1274 char *p = strdup(s);
1275 if (!p)
1276 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1277 return p;
1278 }
1279
1280 /*
1281 * Parse trees for commands are allocated in lifo order, so we use a stack
1282 * to make this more efficient, and also to avoid all sorts of exception
1283 * handling code to handle interrupts in the middle of a parse.
1284 *
1285 * The size 504 was chosen because the Ultrix malloc handles that size
1286 * well.
1287 */
1288 static void *
1289 stalloc(size_t nbytes)
1290 {
1291 char *p;
1292 size_t aligned;
1293
1294 aligned = SHELL_ALIGN(nbytes);
1295 if (aligned > g_stacknleft) {
1296 size_t len;
1297 size_t blocksize;
1298 struct stack_block *sp;
1299
1300 blocksize = aligned;
1301 if (blocksize < MINSIZE)
1302 blocksize = MINSIZE;
1303 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1304 if (len < blocksize)
1305 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1306 INT_OFF;
1307 sp = ckmalloc(len);
1308 sp->prev = g_stackp;
1309 g_stacknxt = sp->space;
1310 g_stacknleft = blocksize;
1311 sstrend = g_stacknxt + blocksize;
1312 g_stackp = sp;
1313 INT_ON;
1314 }
1315 p = g_stacknxt;
1316 g_stacknxt += aligned;
1317 g_stacknleft -= aligned;
1318 return p;
1319 }
1320
1321 static void *
1322 stzalloc(size_t nbytes)
1323 {
1324 return memset(stalloc(nbytes), 0, nbytes);
1325 }
1326
1327 static void
1328 stunalloc(void *p)
1329 {
1330 #if DEBUG
1331 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
1332 write(STDERR_FILENO, "stunalloc\n", 10);
1333 abort();
1334 }
1335 #endif
1336 g_stacknleft += g_stacknxt - (char *)p;
1337 g_stacknxt = p;
1338 }
1339
1340 /*
1341 * Like strdup but works with the ash stack.
1342 */
1343 static char *
1344 ststrdup(const char *p)
1345 {
1346 size_t len = strlen(p) + 1;
1347 return memcpy(stalloc(len), p, len);
1348 }
1349
1350 static void
1351 setstackmark(struct stackmark *mark)
1352 {
1353 mark->stackp = g_stackp;
1354 mark->stacknxt = g_stacknxt;
1355 mark->stacknleft = g_stacknleft;
1356 mark->marknext = markp;
1357 markp = mark;
1358 }
1359
1360 static void
1361 popstackmark(struct stackmark *mark)
1362 {
1363 struct stack_block *sp;
1364
1365 if (!mark->stackp)
1366 return;
1367
1368 INT_OFF;
1369 markp = mark->marknext;
1370 while (g_stackp != mark->stackp) {
1371 sp = g_stackp;
1372 g_stackp = sp->prev;
1373 free(sp);
1374 }
1375 g_stacknxt = mark->stacknxt;
1376 g_stacknleft = mark->stacknleft;
1377 sstrend = mark->stacknxt + mark->stacknleft;
1378 INT_ON;
1379 }
1380
1381 /*
1382 * When the parser reads in a string, it wants to stick the string on the
1383 * stack and only adjust the stack pointer when it knows how big the
1384 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1385 * of space on top of the stack and stackblocklen returns the length of
1386 * this block. Growstackblock will grow this space by at least one byte,
1387 * possibly moving it (like realloc). Grabstackblock actually allocates the
1388 * part of the block that has been used.
1389 */
1390 static void
1391 growstackblock(void)
1392 {
1393 size_t newlen;
1394
1395 newlen = g_stacknleft * 2;
1396 if (newlen < g_stacknleft)
1397 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1398 if (newlen < 128)
1399 newlen += 128;
1400
1401 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
1402 struct stack_block *oldstackp;
1403 struct stackmark *xmark;
1404 struct stack_block *sp;
1405 struct stack_block *prevstackp;
1406 size_t grosslen;
1407
1408 INT_OFF;
1409 oldstackp = g_stackp;
1410 sp = g_stackp;
1411 prevstackp = sp->prev;
1412 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1413 sp = ckrealloc(sp, grosslen);
1414 sp->prev = prevstackp;
1415 g_stackp = sp;
1416 g_stacknxt = sp->space;
1417 g_stacknleft = newlen;
1418 sstrend = sp->space + newlen;
1419
1420 /*
1421 * Stack marks pointing to the start of the old block
1422 * must be relocated to point to the new block
1423 */
1424 xmark = markp;
1425 while (xmark != NULL && xmark->stackp == oldstackp) {
1426 xmark->stackp = g_stackp;
1427 xmark->stacknxt = g_stacknxt;
1428 xmark->stacknleft = g_stacknleft;
1429 xmark = xmark->marknext;
1430 }
1431 INT_ON;
1432 } else {
1433 char *oldspace = g_stacknxt;
1434 size_t oldlen = g_stacknleft;
1435 char *p = stalloc(newlen);
1436
1437 /* free the space we just allocated */
1438 g_stacknxt = memcpy(p, oldspace, oldlen);
1439 g_stacknleft += newlen;
1440 }
1441 }
1442
1443 static void
1444 grabstackblock(size_t len)
1445 {
1446 len = SHELL_ALIGN(len);
1447 g_stacknxt += len;
1448 g_stacknleft -= len;
1449 }
1450
1451 /*
1452 * The following routines are somewhat easier to use than the above.
1453 * The user declares a variable of type STACKSTR, which may be declared
1454 * to be a register. The macro STARTSTACKSTR initializes things. Then
1455 * the user uses the macro STPUTC to add characters to the string. In
1456 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1457 * grown as necessary. When the user is done, she can just leave the
1458 * string there and refer to it using stackblock(). Or she can allocate
1459 * the space for it using grabstackstr(). If it is necessary to allow
1460 * someone else to use the stack temporarily and then continue to grow
1461 * the string, the user should use grabstack to allocate the space, and
1462 * then call ungrabstr(p) to return to the previous mode of operation.
1463 *
1464 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1465 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1466 * is space for at least one character.
1467 */
1468 static void *
1469 growstackstr(void)
1470 {
1471 size_t len = stackblocksize();
1472 if (herefd >= 0 && len >= 1024) {
1473 full_write(herefd, stackblock(), len);
1474 return stackblock();
1475 }
1476 growstackblock();
1477 return (char *)stackblock() + len;
1478 }
1479
1480 /*
1481 * Called from CHECKSTRSPACE.
1482 */
1483 static char *
1484 makestrspace(size_t newlen, char *p)
1485 {
1486 size_t len = p - g_stacknxt;
1487 size_t size = stackblocksize();
1488
1489 for (;;) {
1490 size_t nleft;
1491
1492 size = stackblocksize();
1493 nleft = size - len;
1494 if (nleft >= newlen)
1495 break;
1496 growstackblock();
1497 }
1498 return (char *)stackblock() + len;
1499 }
1500
1501 static char *
1502 stack_nputstr(const char *s, size_t n, char *p)
1503 {
1504 p = makestrspace(n, p);
1505 p = (char *)memcpy(p, s, n) + n;
1506 return p;
1507 }
1508
1509 static char *
1510 stack_putstr(const char *s, char *p)
1511 {
1512 return stack_nputstr(s, strlen(s), p);
1513 }
1514
1515 static char *
1516 _STPUTC(int c, char *p)
1517 {
1518 if (p == sstrend)
1519 p = growstackstr();
1520 *p++ = c;
1521 return p;
1522 }
1523
1524 #define STARTSTACKSTR(p) ((p) = stackblock())
1525 #define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1526 #define CHECKSTRSPACE(n, p) do { \
1527 char *q = (p); \
1528 size_t l = (n); \
1529 size_t m = sstrend - q; \
1530 if (l > m) \
1531 (p) = makestrspace(l, q); \
1532 } while (0)
1533 #define USTPUTC(c, p) (*(p)++ = (c))
1534 #define STACKSTRNUL(p) do { \
1535 if ((p) == sstrend) \
1536 (p) = growstackstr(); \
1537 *(p) = '\0'; \
1538 } while (0)
1539 #define STUNPUTC(p) (--(p))
1540 #define STTOPC(p) ((p)[-1])
1541 #define STADJUST(amount, p) ((p) += (amount))
1542
1543 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1544 #define ungrabstackstr(s, p) stunalloc(s)
1545 #define stackstrend() ((void *)sstrend)
1546
1547
1548 /* ============ String helpers */
1549
1550 /*
1551 * prefix -- see if pfx is a prefix of string.
1552 */
1553 static char *
1554 prefix(const char *string, const char *pfx)
1555 {
1556 while (*pfx) {
1557 if (*pfx++ != *string++)
1558 return NULL;
1559 }
1560 return (char *) string;
1561 }
1562
1563 /*
1564 * Check for a valid number. This should be elsewhere.
1565 */
1566 static int
1567 is_number(const char *p)
1568 {
1569 do {
1570 if (!isdigit(*p))
1571 return 0;
1572 } while (*++p != '\0');
1573 return 1;
1574 }
1575
1576 /*
1577 * Convert a string of digits to an integer, printing an error message on
1578 * failure.
1579 */
1580 static int
1581 number(const char *s)
1582 {
1583 if (!is_number(s))
1584 ash_msg_and_raise_error(illnum, s);
1585 return atoi(s);
1586 }
1587
1588 /*
1589 * Produce a possibly single quoted string suitable as input to the shell.
1590 * The return string is allocated on the stack.
1591 */
1592 static char *
1593 single_quote(const char *s)
1594 {
1595 char *p;
1596
1597 STARTSTACKSTR(p);
1598
1599 do {
1600 char *q;
1601 size_t len;
1602
1603 len = strchrnul(s, '\'') - s;
1604
1605 q = p = makestrspace(len + 3, p);
1606
1607 *q++ = '\'';
1608 q = (char *)memcpy(q, s, len) + len;
1609 *q++ = '\'';
1610 s += len;
1611
1612 STADJUST(q - p, p);
1613
1614 len = strspn(s, "'");
1615 if (!len)
1616 break;
1617
1618 q = p = makestrspace(len + 3, p);
1619
1620 *q++ = '"';
1621 q = (char *)memcpy(q, s, len) + len;
1622 *q++ = '"';
1623 s += len;
1624
1625 STADJUST(q - p, p);
1626 } while (*s);
1627
1628 USTPUTC(0, p);
1629
1630 return stackblock();
1631 }
1632
1633
1634 /* ============ nextopt */
1635
1636 static char **argptr; /* argument list for builtin commands */
1637 static char *optionarg; /* set by nextopt (like getopt) */
1638 static char *optptr; /* used by nextopt */
1639
1640 /*
1641 * XXX - should get rid of. Have all builtins use getopt(3).
1642 * The library getopt must have the BSD extension static variable
1643 * "optreset", otherwise it can't be used within the shell safely.
1644 *
1645 * Standard option processing (a la getopt) for builtin routines.
1646 * The only argument that is passed to nextopt is the option string;
1647 * the other arguments are unnecessary. It returns the character,
1648 * or '\0' on end of input.
1649 */
1650 static int
1651 nextopt(const char *optstring)
1652 {
1653 char *p;
1654 const char *q;
1655 char c;
1656
1657 p = optptr;
1658 if (p == NULL || *p == '\0') {
1659 /* We ate entire "-param", take next one */
1660 p = *argptr;
1661 if (p == NULL)
1662 return '\0';
1663 if (*p != '-')
1664 return '\0';
1665 if (*++p == '\0') /* just "-" ? */
1666 return '\0';
1667 argptr++;
1668 if (LONE_DASH(p)) /* "--" ? */
1669 return '\0';
1670 /* p => next "-param" */
1671 }
1672 /* p => some option char in the middle of a "-param" */
1673 c = *p++;
1674 for (q = optstring; *q != c;) {
1675 if (*q == '\0')
1676 ash_msg_and_raise_error("illegal option -%c", c);
1677 if (*++q == ':')
1678 q++;
1679 }
1680 if (*++q == ':') {
1681 if (*p == '\0') {
1682 p = *argptr++;
1683 if (p == NULL)
1684 ash_msg_and_raise_error("no arg for -%c option", c);
1685 }
1686 optionarg = p;
1687 p = NULL;
1688 }
1689 optptr = p;
1690 return c;
1691 }
1692
1693
1694 /* ============ Shell variables */
1695
1696 /*
1697 * The parsefile structure pointed to by the global variable parsefile
1698 * contains information about the current file being read.
1699 */
1700 struct shparam {
1701 int nparam; /* # of positional parameters (without $0) */
1702 #if ENABLE_ASH_GETOPTS
1703 int optind; /* next parameter to be processed by getopts */
1704 int optoff; /* used by getopts */
1705 #endif
1706 unsigned char malloced; /* if parameter list dynamically allocated */
1707 char **p; /* parameter list */
1708 };
1709
1710 /*
1711 * Free the list of positional parameters.
1712 */
1713 static void
1714 freeparam(volatile struct shparam *param)
1715 {
1716 if (param->malloced) {
1717 char **ap, **ap1;
1718 ap = ap1 = param->p;
1719 while (*ap)
1720 free(*ap++);
1721 free(ap1);
1722 }
1723 }
1724
1725 #if ENABLE_ASH_GETOPTS
1726 static void getoptsreset(const char *value);
1727 #endif
1728
1729 struct var {
1730 struct var *next; /* next entry in hash list */
1731 int flags; /* flags are defined above */
1732 const char *text; /* name=value */
1733 void (*func)(const char *); /* function to be called when */
1734 /* the variable gets set/unset */
1735 };
1736
1737 struct localvar {
1738 struct localvar *next; /* next local variable in list */
1739 struct var *vp; /* the variable that was made local */
1740 int flags; /* saved flags */
1741 const char *text; /* saved text */
1742 };
1743
1744 /* flags */
1745 #define VEXPORT 0x01 /* variable is exported */
1746 #define VREADONLY 0x02 /* variable cannot be modified */
1747 #define VSTRFIXED 0x04 /* variable struct is statically allocated */
1748 #define VTEXTFIXED 0x08 /* text is statically allocated */
1749 #define VSTACK 0x10 /* text is allocated on the stack */
1750 #define VUNSET 0x20 /* the variable is not set */
1751 #define VNOFUNC 0x40 /* don't call the callback function */
1752 #define VNOSET 0x80 /* do not set variable - just readonly test */
1753 #define VNOSAVE 0x100 /* when text is on the heap before setvareq */
1754 #if ENABLE_ASH_RANDOM_SUPPORT
1755 # define VDYNAMIC 0x200 /* dynamic variable */
1756 #else
1757 # define VDYNAMIC 0
1758 #endif
1759
1760 #ifdef IFS_BROKEN
1761 static const char defifsvar[] ALIGN1 = "IFS= \t\n";
1762 #define defifs (defifsvar + 4)
1763 #else
1764 static const char defifs[] ALIGN1 = " \t\n";
1765 #endif
1766
1767
1768 /* Need to be before varinit_data[] */
1769 #if ENABLE_LOCALE_SUPPORT
1770 static void
1771 change_lc_all(const char *value)
1772 {
1773 if (value && *value != '\0')
1774 setlocale(LC_ALL, value);
1775 }
1776 static void
1777 change_lc_ctype(const char *value)
1778 {
1779 if (value && *value != '\0')
1780 setlocale(LC_CTYPE, value);
1781 }
1782 #endif
1783 #if ENABLE_ASH_MAIL
1784 static void chkmail(void);
1785 static void changemail(const char *);
1786 #endif
1787 static void changepath(const char *);
1788 #if ENABLE_ASH_RANDOM_SUPPORT
1789 static void change_random(const char *);
1790 #endif
1791
1792 static const struct {
1793 int flags;
1794 const char *text;
1795 void (*func)(const char *);
1796 } varinit_data[] = {
1797 #ifdef IFS_BROKEN
1798 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
1799 #else
1800 { VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0" , NULL },
1801 #endif
1802 #if ENABLE_ASH_MAIL
1803 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0" , changemail },
1804 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
1805 #endif
1806 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1807 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
1808 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1809 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
1810 #if ENABLE_ASH_GETOPTS
1811 { VSTRFIXED|VTEXTFIXED , "OPTIND=1" , getoptsreset },
1812 #endif
1813 #if ENABLE_ASH_RANDOM_SUPPORT
1814 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
1815 #endif
1816 #if ENABLE_LOCALE_SUPPORT
1817 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL\0" , change_lc_all },
1818 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE\0", change_lc_ctype },
1819 #endif
1820 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
1821 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE\0", NULL },
1822 #endif
1823 };
1824
1825 struct redirtab;
1826
1827 struct globals_var {
1828 struct shparam shellparam; /* $@ current positional parameters */
1829 struct redirtab *redirlist;
1830 int g_nullredirs;
1831 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1832 struct var *vartab[VTABSIZE];
1833 struct var varinit[ARRAY_SIZE(varinit_data)];
1834 };
1835 extern struct globals_var *const ash_ptr_to_globals_var;
1836 #define G_var (*ash_ptr_to_globals_var)
1837 #define shellparam (G_var.shellparam )
1838 //#define redirlist (G_var.redirlist )
1839 #define g_nullredirs (G_var.g_nullredirs )
1840 #define preverrout_fd (G_var.preverrout_fd)
1841 #define vartab (G_var.vartab )
1842 #define varinit (G_var.varinit )
1843 #define INIT_G_var() do { \
1844 unsigned i; \
1845 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1846 barrier(); \
1847 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
1848 varinit[i].flags = varinit_data[i].flags; \
1849 varinit[i].text = varinit_data[i].text; \
1850 varinit[i].func = varinit_data[i].func; \
1851 } \
1852 } while (0)
1853
1854 #define vifs varinit[0]
1855 #if ENABLE_ASH_MAIL
1856 # define vmail (&vifs)[1]
1857 # define vmpath (&vmail)[1]
1858 # define vpath (&vmpath)[1]
1859 #else
1860 # define vpath (&vifs)[1]
1861 #endif
1862 #define vps1 (&vpath)[1]
1863 #define vps2 (&vps1)[1]
1864 #define vps4 (&vps2)[1]
1865 #if ENABLE_ASH_GETOPTS
1866 # define voptind (&vps4)[1]
1867 # if ENABLE_ASH_RANDOM_SUPPORT
1868 # define vrandom (&voptind)[1]
1869 # endif
1870 #else
1871 # if ENABLE_ASH_RANDOM_SUPPORT
1872 # define vrandom (&vps4)[1]
1873 # endif
1874 #endif
1875
1876 /*
1877 * The following macros access the values of the above variables.
1878 * They have to skip over the name. They return the null string
1879 * for unset variables.
1880 */
1881 #define ifsval() (vifs.text + 4)
1882 #define ifsset() ((vifs.flags & VUNSET) == 0)
1883 #if ENABLE_ASH_MAIL
1884 # define mailval() (vmail.text + 5)
1885 # define mpathval() (vmpath.text + 9)
1886 # define mpathset() ((vmpath.flags & VUNSET) == 0)
1887 #endif
1888 #define pathval() (vpath.text + 5)
1889 #define ps1val() (vps1.text + 4)
1890 #define ps2val() (vps2.text + 4)
1891 #define ps4val() (vps4.text + 4)
1892 #if ENABLE_ASH_GETOPTS
1893 # define optindval() (voptind.text + 7)
1894 #endif
1895
1896
1897 #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
1898 #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
1899
1900 #if ENABLE_ASH_GETOPTS
1901 static void
1902 getoptsreset(const char *value)
1903 {
1904 shellparam.optind = number(value);
1905 shellparam.optoff = -1;
1906 }
1907 #endif
1908
1909 /*
1910 * Return of a legal variable name (a letter or underscore followed by zero or
1911 * more letters, underscores, and digits).
1912 */
1913 static char *
1914 endofname(const char *name)
1915 {
1916 char *p;
1917
1918 p = (char *) name;
1919 if (!is_name(*p))
1920 return p;
1921 while (*++p) {
1922 if (!is_in_name(*p))
1923 break;
1924 }
1925 return p;
1926 }
1927
1928 /*
1929 * Compares two strings up to the first = or '\0'. The first
1930 * string must be terminated by '='; the second may be terminated by
1931 * either '=' or '\0'.
1932 */
1933 static int
1934 varcmp(const char *p, const char *q)
1935 {
1936 int c, d;
1937
1938 while ((c = *p) == (d = *q)) {
1939 if (!c || c == '=')
1940 goto out;
1941 p++;
1942 q++;
1943 }
1944 if (c == '=')
1945 c = '\0';
1946 if (d == '=')
1947 d = '\0';
1948 out:
1949 return c - d;
1950 }
1951
1952 static int
1953 varequal(const char *a, const char *b)
1954 {
1955 return !varcmp(a, b);
1956 }
1957
1958 /*
1959 * Find the appropriate entry in the hash table from the name.
1960 */
1961 static struct var **
1962 hashvar(const char *p)
1963 {
1964 unsigned hashval;
1965
1966 hashval = ((unsigned char) *p) << 4;
1967 while (*p && *p != '=')
1968 hashval += (unsigned char) *p++;
1969 return &vartab[hashval % VTABSIZE];
1970 }
1971
1972 static int
1973 vpcmp(const void *a, const void *b)
1974 {
1975 return varcmp(*(const char **)a, *(const char **)b);
1976 }
1977
1978 /*
1979 * This routine initializes the builtin variables.
1980 */
1981 static void
1982 initvar(void)
1983 {
1984 struct var *vp;
1985 struct var *end;
1986 struct var **vpp;
1987
1988 /*
1989 * PS1 depends on uid
1990 */
1991 #if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
1992 vps1.text = "PS1=\\w \\$ ";
1993 #else
1994 if (!geteuid())
1995 vps1.text = "PS1=# ";
1996 #endif
1997 vp = varinit;
1998 end = vp + ARRAY_SIZE(varinit);
1999 do {
2000 vpp = hashvar(vp->text);
2001 vp->next = *vpp;
2002 *vpp = vp;
2003 } while (++vp < end);
2004 }
2005
2006 static struct var **
2007 findvar(struct var **vpp, const char *name)
2008 {
2009 for (; *vpp; vpp = &(*vpp)->next) {
2010 if (varequal((*vpp)->text, name)) {
2011 break;
2012 }
2013 }
2014 return vpp;
2015 }
2016
2017 /*
2018 * Find the value of a variable. Returns NULL if not set.
2019 */
2020 static char *
2021 lookupvar(const char *name)
2022 {
2023 struct var *v;
2024
2025 v = *findvar(hashvar(name), name);
2026 if (v) {
2027 #if ENABLE_ASH_RANDOM_SUPPORT
2028 /*
2029 * Dynamic variables are implemented roughly the same way they are
2030 * in bash. Namely, they're "special" so long as they aren't unset.
2031 * As soon as they're unset, they're no longer dynamic, and dynamic
2032 * lookup will no longer happen at that point. -- PFM.
2033 */
2034 if ((v->flags & VDYNAMIC))
2035 (*v->func)(NULL);
2036 #endif
2037 if (!(v->flags & VUNSET))
2038 return strchrnul(v->text, '=') + 1;
2039 }
2040 return NULL;
2041 }
2042
2043 /*
2044 * Search the environment of a builtin command.
2045 */
2046 static char *
2047 bltinlookup(const char *name)
2048 {
2049 struct strlist *sp;
2050
2051 for (sp = cmdenviron; sp; sp = sp->next) {
2052 if (varequal(sp->text, name))
2053 return strchrnul(sp->text, '=') + 1;
2054 }
2055 return lookupvar(name);
2056 }
2057
2058 /*
2059 * Same as setvar except that the variable and value are passed in
2060 * the first argument as name=value. Since the first argument will
2061 * be actually stored in the table, it should not be a string that
2062 * will go away.
2063 * Called with interrupts off.
2064 */
2065 static void
2066 setvareq(char *s, int flags)
2067 {
2068 struct var *vp, **vpp;
2069
2070 vpp = hashvar(s);
2071 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2072 vp = *findvar(vpp, s);
2073 if (vp) {
2074 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2075 const char *n;
2076
2077 if (flags & VNOSAVE)
2078 free(s);
2079 n = vp->text;
2080 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2081 }
2082
2083 if (flags & VNOSET)
2084 return;
2085
2086 if (vp->func && (flags & VNOFUNC) == 0)
2087 (*vp->func)(strchrnul(s, '=') + 1);
2088
2089 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
2090 free((char*)vp->text);
2091
2092 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2093 } else {
2094 if (flags & VNOSET)
2095 return;
2096 /* not found */
2097 vp = ckzalloc(sizeof(*vp));
2098 vp->next = *vpp;
2099 /*vp->func = NULL; - ckzalloc did it */
2100 *vpp = vp;
2101 }
2102 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2103 s = ckstrdup(s);
2104 vp->text = s;
2105 vp->flags = flags;
2106 }
2107
2108 /*
2109 * Set the value of a variable. The flags argument is ored with the
2110 * flags of the variable. If val is NULL, the variable is unset.
2111 */
2112 static void
2113 setvar(const char *name, const char *val, int flags)
2114 {
2115 char *p, *q;
2116 size_t namelen;
2117 char *nameeq;
2118 size_t vallen;
2119
2120 q = endofname(name);
2121 p = strchrnul(q, '=');
2122 namelen = p - name;
2123 if (!namelen || p != q)
2124 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2125 vallen = 0;
2126 if (val == NULL) {
2127 flags |= VUNSET;
2128 } else {
2129 vallen = strlen(val);
2130 }
2131 INT_OFF;
2132 nameeq = ckmalloc(namelen + vallen + 2);
2133 p = (char *)memcpy(nameeq, name, namelen) + namelen;
2134 if (val) {
2135 *p++ = '=';
2136 p = (char *)memcpy(p, val, vallen) + vallen;
2137 }
2138 *p = '\0';
2139 setvareq(nameeq, flags | VNOSAVE);
2140 INT_ON;
2141 }
2142
2143 #if ENABLE_ASH_GETOPTS
2144 /*
2145 * Safe version of setvar, returns 1 on success 0 on failure.
2146 */
2147 static int
2148 setvarsafe(const char *name, const char *val, int flags)
2149 {
2150 int err;
2151 volatile int saveint;
2152 struct jmploc *volatile savehandler = exception_handler;
2153 struct jmploc jmploc;
2154
2155 SAVE_INT(saveint);
2156 if (setjmp(jmploc.loc))
2157 err = 1;
2158 else {
2159 exception_handler = &jmploc;
2160 setvar(name, val, flags);
2161 err = 0;
2162 }
2163 exception_handler = savehandler;
2164 RESTORE_INT(saveint);
2165 return err;
2166 }
2167 #endif
2168
2169 /*
2170 * Unset the specified variable.
2171 */
2172 static int
2173 unsetvar(const char *s)
2174 {
2175 struct var **vpp;
2176 struct var *vp;
2177 int retval;
2178
2179 vpp = findvar(hashvar(s), s);
2180 vp = *vpp;
2181 retval = 2;
2182 if (vp) {
2183 int flags = vp->flags;
2184
2185 retval = 1;
2186 if (flags & VREADONLY)
2187 goto out;
2188 #if ENABLE_ASH_RANDOM_SUPPORT
2189 vp->flags &= ~VDYNAMIC;
2190 #endif
2191 if (flags & VUNSET)
2192 goto ok;
2193 if ((flags & VSTRFIXED) == 0) {
2194 INT_OFF;
2195 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
2196 free((char*)vp->text);
2197 *vpp = vp->next;
2198 free(vp);
2199 INT_ON;
2200 } else {
2201 setvar(s, 0, 0);
2202 vp->flags &= ~VEXPORT;
2203 }
2204 ok:
2205 retval = 0;
2206 }
2207 out:
2208 return retval;
2209 }
2210
2211 /*
2212 * Process a linked list of variable assignments.
2213 */
2214 static void
2215 listsetvar(struct strlist *list_set_var, int flags)
2216 {
2217 struct strlist *lp = list_set_var;
2218
2219 if (!lp)
2220 return;
2221 INT_OFF;
2222 do {
2223 setvareq(lp->text, flags);
2224 lp = lp->next;
2225 } while (lp);
2226 INT_ON;
2227 }
2228
2229 /*
2230 * Generate a list of variables satisfying the given conditions.
2231 */
2232 static char **
2233 listvars(int on, int off, char ***end)
2234 {
2235 struct var **vpp;
2236 struct var *vp;
2237 char **ep;
2238 int mask;
2239
2240 STARTSTACKSTR(ep);
2241 vpp = vartab;
2242 mask = on | off;
2243 do {
2244 for (vp = *vpp; vp; vp = vp->next) {
2245 if ((vp->flags & mask) == on) {
2246 if (ep == stackstrend())
2247 ep = growstackstr();
2248 *ep++ = (char *) vp->text;
2249 }
2250 }
2251 } while (++vpp < vartab + VTABSIZE);
2252 if (ep == stackstrend())
2253 ep = growstackstr();
2254 if (end)
2255 *end = ep;
2256 *ep++ = NULL;
2257 return grabstackstr(ep);
2258 }
2259
2260
2261 /* ============ Path search helper
2262 *
2263 * The variable path (passed by reference) should be set to the start
2264 * of the path before the first call; padvance will update
2265 * this value as it proceeds. Successive calls to padvance will return
2266 * the possible path expansions in sequence. If an option (indicated by
2267 * a percent sign) appears in the path entry then the global variable
2268 * pathopt will be set to point to it; otherwise pathopt will be set to
2269 * NULL.
2270 */
2271 static const char *pathopt; /* set by padvance */
2272
2273 static char *
2274 padvance(const char **path, const char *name)
2275 {
2276 const char *p;
2277 char *q;
2278 const char *start;
2279 size_t len;
2280
2281 if (*path == NULL)
2282 return NULL;
2283 start = *path;
2284 for (p = start; *p && *p != ':' && *p != '%'; p++)
2285 continue;
2286 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2287 while (stackblocksize() < len)
2288 growstackblock();
2289 q = stackblock();
2290 if (p != start) {
2291 memcpy(q, start, p - start);
2292 q += p - start;
2293 *q++ = '/';
2294 }
2295 strcpy(q, name);
2296 pathopt = NULL;
2297 if (*p == '%') {
2298 pathopt = ++p;
2299 while (*p && *p != ':')
2300 p++;
2301 }
2302 if (*p == ':')
2303 *path = p + 1;
2304 else
2305 *path = NULL;
2306 return stalloc(len);
2307 }
2308
2309
2310 /* ============ Prompt */
2311
2312 static smallint doprompt; /* if set, prompt the user */
2313 static smallint needprompt; /* true if interactive and at start of line */
2314
2315 #if ENABLE_FEATURE_EDITING
2316 static line_input_t *line_input_state;
2317 static const char *cmdedit_prompt;
2318 static void
2319 putprompt(const char *s)
2320 {
2321 if (ENABLE_ASH_EXPAND_PRMT) {
2322 free((char*)cmdedit_prompt);
2323 cmdedit_prompt = ckstrdup(s);
2324 return;
2325 }
2326 cmdedit_prompt = s;
2327 }
2328 #else
2329 static void
2330 putprompt(const char *s)
2331 {
2332 out2str(s);
2333 }
2334 #endif
2335
2336 #if ENABLE_ASH_EXPAND_PRMT
2337 /* expandstr() needs parsing machinery, so it is far away ahead... */
2338 static const char *expandstr(const char *ps);
2339 #else
2340 #define expandstr(s) s
2341 #endif
2342
2343 static void
2344 setprompt(int whichprompt)
2345 {
2346 const char *prompt;
2347 #if ENABLE_ASH_EXPAND_PRMT
2348 struct stackmark smark;
2349 #endif
2350
2351 needprompt = 0;
2352
2353 switch (whichprompt) {
2354 case 1:
2355 prompt = ps1val();
2356 break;
2357 case 2:
2358 prompt = ps2val();
2359 break;
2360 default: /* 0 */
2361 prompt = nullstr;
2362 }
2363 #if ENABLE_ASH_EXPAND_PRMT
2364 setstackmark(&smark);
2365 stalloc(stackblocksize());
2366 #endif
2367 putprompt(expandstr(prompt));
2368 #if ENABLE_ASH_EXPAND_PRMT
2369 popstackmark(&smark);
2370 #endif
2371 }
2372
2373
2374 /* ============ The cd and pwd commands */
2375
2376 #define CD_PHYSICAL 1
2377 #define CD_PRINT 2
2378
2379 static int docd(const char *, int);
2380
2381 static int
2382 cdopt(void)
2383 {
2384 int flags = 0;
2385 int i, j;
2386
2387 j = 'L';
2388 while ((i = nextopt("LP"))) {
2389 if (i != j) {
2390 flags ^= CD_PHYSICAL;
2391 j = i;
2392 }
2393 }
2394
2395 return flags;
2396 }
2397
2398 /*
2399 * Update curdir (the name of the current directory) in response to a
2400 * cd command.
2401 */
2402 static const char *
2403 updatepwd(const char *dir)
2404 {
2405 char *new;
2406 char *p;
2407 char *cdcomppath;
2408 const char *lim;
2409
2410 cdcomppath = ststrdup(dir);
2411 STARTSTACKSTR(new);
2412 if (*dir != '/') {
2413 if (curdir == nullstr)
2414 return 0;
2415 new = stack_putstr(curdir, new);
2416 }
2417 new = makestrspace(strlen(dir) + 2, new);
2418 lim = (char *)stackblock() + 1;
2419 if (*dir != '/') {
2420 if (new[-1] != '/')
2421 USTPUTC('/', new);
2422 if (new > lim && *lim == '/')
2423 lim++;
2424 } else {
2425 USTPUTC('/', new);
2426 cdcomppath++;
2427 if (dir[1] == '/' && dir[2] != '/') {
2428 USTPUTC('/', new);
2429 cdcomppath++;
2430 lim++;
2431 }
2432 }
2433 p = strtok(cdcomppath, "/");
2434 while (p) {
2435 switch (*p) {
2436 case '.':
2437 if (p[1] == '.' && p[2] == '\0') {
2438 while (new > lim) {
2439 STUNPUTC(new);
2440 if (new[-1] == '/')
2441 break;
2442 }
2443 break;
2444 }
2445 if (p[1] == '\0')
2446 break;
2447 /* fall through */
2448 default:
2449 new = stack_putstr(p, new);
2450 USTPUTC('/', new);
2451 }
2452 p = strtok(0, "/");
2453 }
2454 if (new > lim)
2455 STUNPUTC(new);
2456 *new = 0;
2457 return stackblock();
2458 }
2459
2460 /*
2461 * Find out what the current directory is. If we already know the current
2462 * directory, this routine returns immediately.
2463 */
2464 static char *
2465 getpwd(void)
2466 {
2467 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
2468 return dir ? dir : nullstr;
2469 }
2470
2471 static void
2472 setpwd(const char *val, int setold)
2473 {
2474 char *oldcur, *dir;
2475
2476 oldcur = dir = curdir;
2477
2478 if (setold) {
2479 setvar("OLDPWD", oldcur, VEXPORT);
2480 }
2481 INT_OFF;
2482 if (physdir != nullstr) {
2483 if (physdir != oldcur)
2484 free(physdir);
2485 physdir = nullstr;
2486 }
2487 if (oldcur == val || !val) {
2488 char *s = getpwd();
2489 physdir = s;
2490 if (!val)
2491 dir = s;
2492 } else
2493 dir = ckstrdup(val);
2494 if (oldcur != dir && oldcur != nullstr) {
2495 free(oldcur);
2496 }
2497 curdir = dir;
2498 INT_ON;
2499 setvar("PWD", dir, VEXPORT);
2500 }
2501
2502 static void hashcd(void);
2503
2504 /*
2505 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2506 * know that the current directory has changed.
2507 */
2508 static int
2509 docd(const char *dest, int flags)
2510 {
2511 const char *dir = 0;
2512 int err;
2513
2514 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2515
2516 INT_OFF;
2517 if (!(flags & CD_PHYSICAL)) {
2518 dir = updatepwd(dest);
2519 if (dir)
2520 dest = dir;
2521 }
2522 err = chdir(dest);
2523 if (err)
2524 goto out;
2525 setpwd(dir, 1);
2526 hashcd();
2527 out:
2528 INT_ON;
2529 return err;
2530 }
2531
2532 static int
2533 cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2534 {
2535 const char *dest;
2536 const char *path;
2537 const char *p;
2538 char c;
2539 struct stat statb;
2540 int flags;
2541
2542 flags = cdopt();
2543 dest = *argptr;
2544 if (!dest)
2545 dest = bltinlookup(homestr);
2546 else if (LONE_DASH(dest)) {
2547 dest = bltinlookup("OLDPWD");
2548 flags |= CD_PRINT;
2549 }
2550 if (!dest)
2551 dest = nullstr;
2552 if (*dest == '/')
2553 goto step7;
2554 if (*dest == '.') {
2555 c = dest[1];
2556 dotdot:
2557 switch (c) {
2558 case '\0':
2559 case '/':
2560 goto step6;
2561 case '.':
2562 c = dest[2];
2563 if (c != '.')
2564 goto dotdot;
2565 }
2566 }
2567 if (!*dest)
2568 dest = ".";
2569 path = bltinlookup("CDPATH");
2570 if (!path) {
2571 step6:
2572 step7:
2573 p = dest;
2574 goto docd;
2575 }
2576 do {
2577 c = *path;
2578 p = padvance(&path, dest);
2579 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2580 if (c && c != ':')
2581 flags |= CD_PRINT;
2582 docd:
2583 if (!docd(p, flags))
2584 goto out;
2585 break;
2586 }
2587 } while (path);
2588 ash_msg_and_raise_error("can't cd to %s", dest);
2589 /* NOTREACHED */
2590 out:
2591 if (flags & CD_PRINT)
2592 out1fmt(snlfmt, curdir);
2593 return 0;
2594 }
2595
2596 static int
2597 pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2598 {
2599 int flags;
2600 const char *dir = curdir;
2601
2602 flags = cdopt();
2603 if (flags) {
2604 if (physdir == nullstr)
2605 setpwd(dir, 0);
2606 dir = physdir;
2607 }
2608 out1fmt(snlfmt, dir);
2609 return 0;
2610 }
2611
2612
2613 /* ============ ... */
2614
2615
2616 #define IBUFSIZ COMMON_BUFSIZE
2617 /* buffer for top level input file */
2618 #define basebuf bb_common_bufsiz1
2619
2620 /* Syntax classes */
2621 #define CWORD 0 /* character is nothing special */
2622 #define CNL 1 /* newline character */
2623 #define CBACK 2 /* a backslash character */
2624 #define CSQUOTE 3 /* single quote */
2625 #define CDQUOTE 4 /* double quote */
2626 #define CENDQUOTE 5 /* a terminating quote */
2627 #define CBQUOTE 6 /* backwards single quote */
2628 #define CVAR 7 /* a dollar sign */
2629 #define CENDVAR 8 /* a '}' character */
2630 #define CLP 9 /* a left paren in arithmetic */
2631 #define CRP 10 /* a right paren in arithmetic */
2632 #define CENDFILE 11 /* end of file */
2633 #define CCTL 12 /* like CWORD, except it must be escaped */
2634 #define CSPCL 13 /* these terminate a word */
2635 #define CIGN 14 /* character should be ignored */
2636
2637 #if ENABLE_ASH_ALIAS
2638 #define SYNBASE 130
2639 #define PEOF -130
2640 #define PEOA -129
2641 #define PEOA_OR_PEOF PEOA
2642 #else
2643 #define SYNBASE 129
2644 #define PEOF -129
2645 #define PEOA_OR_PEOF PEOF
2646 #endif
2647
2648 /* number syntax index */
2649 #define BASESYNTAX 0 /* not in quotes */
2650 #define DQSYNTAX 1 /* in double quotes */
2651 #define SQSYNTAX 2 /* in single quotes */
2652 #define ARISYNTAX 3 /* in arithmetic */
2653 #define PSSYNTAX 4 /* prompt */
2654
2655 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
2656 #define USE_SIT_FUNCTION
2657 #endif
2658
2659 #if ENABLE_ASH_MATH_SUPPORT
2660 static const char S_I_T[][4] = {
2661 #if ENABLE_ASH_ALIAS
2662 { CSPCL, CIGN, CIGN, CIGN }, /* 0, PEOA */
2663 #endif
2664 { CSPCL, CWORD, CWORD, CWORD }, /* 1, ' ' */
2665 { CNL, CNL, CNL, CNL }, /* 2, \n */
2666 { CWORD, CCTL, CCTL, CWORD }, /* 3, !*-/:=?[]~ */
2667 { CDQUOTE, CENDQUOTE, CWORD, CWORD }, /* 4, '"' */
2668 { CVAR, CVAR, CWORD, CVAR }, /* 5, $ */
2669 { CSQUOTE, CWORD, CENDQUOTE, CWORD }, /* 6, "'" */
2670 { CSPCL, CWORD, CWORD, CLP }, /* 7, ( */
2671 { CSPCL, CWORD, CWORD, CRP }, /* 8, ) */
2672 { CBACK, CBACK, CCTL, CBACK }, /* 9, \ */
2673 { CBQUOTE, CBQUOTE, CWORD, CBQUOTE }, /* 10, ` */
2674 { CENDVAR, CENDVAR, CWORD, CENDVAR }, /* 11, } */
2675 #ifndef USE_SIT_FUNCTION
2676 { CENDFILE, CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */
2677 { CWORD, CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */
2678 { CCTL, CCTL, CCTL, CCTL } /* 14, CTLESC ... */
2679 #endif
2680 };
2681 #else
2682 static const char S_I_T[][3] = {
2683 #if ENABLE_ASH_ALIAS
2684 { CSPCL, CIGN, CIGN }, /* 0, PEOA */
2685 #endif
2686 { CSPCL, CWORD, CWORD }, /* 1, ' ' */
2687 { CNL, CNL, CNL }, /* 2, \n */
2688 { CWORD, CCTL, CCTL }, /* 3, !*-/:=?[]~ */
2689 { CDQUOTE, CENDQUOTE, CWORD }, /* 4, '"' */
2690 { CVAR, CVAR, CWORD }, /* 5, $ */
2691 { CSQUOTE, CWORD, CENDQUOTE }, /* 6, "'" */
2692 { CSPCL, CWORD, CWORD }, /* 7, ( */
2693 { CSPCL, CWORD, CWORD }, /* 8, ) */
2694 { CBACK, CBACK, CCTL }, /* 9, \ */
2695 { CBQUOTE, CBQUOTE, CWORD }, /* 10, ` */
2696 { CENDVAR, CENDVAR, CWORD }, /* 11, } */
2697 #ifndef USE_SIT_FUNCTION
2698 { CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */
2699 { CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */
2700 { CCTL, CCTL, CCTL } /* 14, CTLESC ... */
2701 #endif
2702 };
2703 #endif /* ASH_MATH_SUPPORT */
2704
2705 #ifdef USE_SIT_FUNCTION
2706
2707 static int
2708 SIT(int c, int syntax)
2709 {
2710 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
2711 #if ENABLE_ASH_ALIAS
2712 static const char syntax_index_table[] ALIGN1 = {
2713 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
2714 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
2715 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2716 11, 3 /* "}~" */
2717 };
2718 #else
2719 static const char syntax_index_table[] ALIGN1 = {
2720 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
2721 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
2722 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2723 10, 2 /* "}~" */
2724 };
2725 #endif
2726 const char *s;
2727 int indx;
2728
2729 if (c == PEOF) /* 2^8+2 */
2730 return CENDFILE;
2731 #if ENABLE_ASH_ALIAS
2732 if (c == PEOA) /* 2^8+1 */
2733 indx = 0;
2734 else
2735 #endif
2736
2737 if ((unsigned char)c >= (unsigned char)(CTLESC)
2738 && (unsigned char)c <= (unsigned char)(CTLQUOTEMARK)
2739 ) {
2740 return CCTL;
2741 } else {
2742 s = strchrnul(spec_symbls, c);
2743 if (*s == '\0')
2744 return CWORD;
2745 indx = syntax_index_table[s - spec_symbls];
2746 }
2747 return S_I_T[indx][syntax];
2748 }
2749
2750 #else /* !USE_SIT_FUNCTION */
2751
2752 #if ENABLE_ASH_ALIAS
2753 #define CSPCL_CIGN_CIGN_CIGN 0
2754 #define CSPCL_CWORD_CWORD_CWORD 1
2755 #define CNL_CNL_CNL_CNL 2
2756 #define CWORD_CCTL_CCTL_CWORD 3
2757 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 4
2758 #define CVAR_CVAR_CWORD_CVAR 5
2759 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 6
2760 #define CSPCL_CWORD_CWORD_CLP 7
2761 #define CSPCL_CWORD_CWORD_CRP 8
2762 #define CBACK_CBACK_CCTL_CBACK 9
2763 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
2764 #define CENDVAR_CENDVAR_CWORD_CENDVAR 11
2765 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
2766 #define CWORD_CWORD_CWORD_CWORD 13
2767 #define CCTL_CCTL_CCTL_CCTL 14
2768 #else
2769 #define CSPCL_CWORD_CWORD_CWORD 0
2770 #define CNL_CNL_CNL_CNL 1
2771 #define CWORD_CCTL_CCTL_CWORD 2
2772 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 3
2773 #define CVAR_CVAR_CWORD_CVAR 4
2774 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 5
2775 #define CSPCL_CWORD_CWORD_CLP 6
2776 #define CSPCL_CWORD_CWORD_CRP 7
2777 #define CBACK_CBACK_CCTL_CBACK 8
2778 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9
2779 #define CENDVAR_CENDVAR_CWORD_CENDVAR 10
2780 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11
2781 #define CWORD_CWORD_CWORD_CWORD 12
2782 #define CCTL_CCTL_CCTL_CCTL 13
2783 #endif
2784
2785 static const char syntax_index_table[258] = {
2786 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
2787 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
2788 #if ENABLE_ASH_ALIAS
2789 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,
2790 #endif
2791 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
2792 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,
2793 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
2794 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
2795 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
2796 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
2797 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,
2798 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
2799 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
2800 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
2801 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
2802 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
2803 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
2804 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
2805 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
2806 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
2807 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
2808 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
2809 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
2810 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
2811 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
2812 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
2813 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
2814 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
2815 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
2816 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
2817 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
2818 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
2819 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
2820 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
2821 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
2822 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
2823 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
2824 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
2825 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
2826 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
2827 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
2828 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
2829 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
2830 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
2831 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
2832 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
2833 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
2834 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
2835 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
2836 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
2837 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
2838 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
2839 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
2840 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
2841 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
2842 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
2843 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
2844 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
2845 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
2846 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
2847 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
2848 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
2849 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
2850 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
2851 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
2852 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
2853 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
2854 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
2855 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
2856 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
2857 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
2858 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
2859 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
2860 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
2861 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
2862 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
2863 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
2864 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
2865 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
2866 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
2867 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
2868 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
2869 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
2870 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
2871 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
2872 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
2873 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
2874 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
2875 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
2876 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
2877 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
2878 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
2879 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
2880 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
2881 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
2882 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
2883 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
2884 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
2885 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
2886 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
2887 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
2888 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
2889 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
2890 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
2891 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
2892 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
2893 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
2894 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
2895 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
2896 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
2897 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
2898 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
2899 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
2900 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
2901 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
2902 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
2903 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
2904 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
2905 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
2906 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
2907 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
2908 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
2909 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
2910 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
2911 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
2912 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
2913 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
2914 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
2915 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
2916 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
2917 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
2918 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
2919 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
2920 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
2921 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
2922 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
2923 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
2924 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
2925 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
2926 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
2927 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
2928 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2929 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
2930 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
2931 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
2932 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
2933 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
2934 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
2935 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
2936 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
2937 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
2938 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
2939 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
2940 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
2941 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
2942 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
2943 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
2944 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
2945 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
2946 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
2947 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
2948 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
2949 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
2950 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
2951 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2952 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2953 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2954 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2955 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2956 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2957 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2958 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2959 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2960 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2961 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2962 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
2964 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2965 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
2966 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
2967 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2970 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2971 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2972 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2973 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2974 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2975 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2976 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2977 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2978 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2979 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2980 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2981 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2982 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2983 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2984 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2985 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2986 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2987 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2988 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2989 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2990 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2991 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2992 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2993 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2994 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2995 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2996 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2997 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2998 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2999 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
3000 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
3001 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
3002 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
3003 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
3004 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
3005 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
3006 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
3007 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
3008 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
3009 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
3010 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
3011 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
3012 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
3013 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
3014 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
3015 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
3016 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
3017 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
3018 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
3019 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
3020 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
3021 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
3022 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
3023 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
3024 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
3025 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
3026 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
3027 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
3028 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
3029 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
3030 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
3031 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
3032 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
3033 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
3034 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
3035 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
3036 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
3037 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
3038 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
3039 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
3040 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
3041 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
3042 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
3043 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
3044 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
3045 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
3046 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
3047 };
3048
3049 #define SIT(c, syntax) (S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax])
3050
3051 #endif /* USE_SIT_FUNCTION */
3052
3053
3054 /* ============ Alias handling */
3055
3056 #if ENABLE_ASH_ALIAS
3057
3058 #define ALIASINUSE 1
3059 #define ALIASDEAD 2
3060
3061 struct alias {
3062 struct alias *next;
3063 char *name;
3064 char *val;
3065 int flag;
3066 };
3067
3068
3069 static struct alias **atab; // [ATABSIZE];
3070 #define INIT_G_alias() do { \
3071 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3072 } while (0)
3073
3074
3075 static struct alias **
3076 __lookupalias(const char *name) {
3077 unsigned int hashval;
3078 struct alias **app;
3079 const char *p;
3080 unsigned int ch;
3081
3082 p = name;
3083
3084 ch = (unsigned char)*p;
3085 hashval = ch << 4;
3086 while (ch) {
3087 hashval += ch;
3088 ch = (unsigned char)*++p;
3089 }
3090 app = &atab[hashval % ATABSIZE];
3091
3092 for (; *app; app = &(*app)->next) {
3093 if (strcmp(name, (*app)->name) == 0) {
3094 break;
3095 }
3096 }
3097
3098 return app;
3099 }
3100
3101 static struct alias *
3102 lookupalias(const char *name, int check)
3103 {
3104 struct alias *ap = *__lookupalias(name);
3105
3106 if (check && ap && (ap->flag & ALIASINUSE))
3107 return NULL;
3108 return ap;
3109 }
3110
3111 static struct alias *
3112 freealias(struct alias *ap)
3113 {
3114 struct alias *next;
3115
3116 if (ap->flag & ALIASINUSE) {
3117 ap->flag |= ALIASDEAD;
3118 return ap;
3119 }
3120
3121 next = ap->next;
3122 free(ap->name);
3123 free(ap->val);
3124 free(ap);
3125 return next;
3126 }
3127
3128 static void
3129 setalias(const char *name, const char *val)
3130 {
3131 struct alias *ap, **app;
3132
3133 app = __lookupalias(name);
3134 ap = *app;
3135 INT_OFF;
3136 if (ap) {
3137 if (!(ap->flag & ALIASINUSE)) {
3138 free(ap->val);
3139 }
3140 ap->val = ckstrdup(val);
3141 ap->flag &= ~ALIASDEAD;
3142 } else {
3143 /* not found */
3144 ap = ckzalloc(sizeof(struct alias));
3145 ap->name = ckstrdup(name);
3146 ap->val = ckstrdup(val);
3147 /*ap->flag = 0; - ckzalloc did it */
3148 /*ap->next = NULL;*/
3149 *app = ap;
3150 }
3151 INT_ON;
3152 }
3153
3154 static int
3155 unalias(const char *name)
3156 {
3157 struct alias **app;
3158
3159 app = __lookupalias(name);
3160
3161 if (*app) {
3162 INT_OFF;
3163 *app = freealias(*app);
3164 INT_ON;
3165 return 0;
3166 }
3167
3168 return 1;
3169 }
3170
3171 static void
3172 rmaliases(void)
3173 {
3174 struct alias *ap, **app;
3175 int i;
3176
3177 INT_OFF;
3178 for (i = 0; i < ATABSIZE; i++) {
3179 app = &atab[i];
3180 for (ap = *app; ap; ap = *app) {
3181 *app = freealias(*app);
3182 if (ap == *app) {
3183 app = &ap->next;
3184 }
3185 }
3186 }
3187 INT_ON;
3188 }
3189
3190 static void
3191 printalias(const struct alias *ap)
3192 {
3193 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3194 }
3195
3196 /*
3197 * TODO - sort output
3198 */
3199 static int
3200 aliascmd(int argc UNUSED_PARAM, char **argv)
3201 {
3202 char *n, *v;
3203 int ret = 0;
3204 struct alias *ap;
3205
3206 if (!argv[1]) {
3207 int i;
3208
3209 for (i = 0; i < ATABSIZE; i++) {
3210 for (ap = atab[i]; ap; ap = ap->next) {
3211 printalias(ap);
3212 }
3213 }
3214 return 0;
3215 }
3216 while ((n = *++argv) != NULL) {
3217 v = strchr(n+1, '=');
3218 if (v == NULL) { /* n+1: funny ksh stuff */
3219 ap = *__lookupalias(n);
3220 if (ap == NULL) {
3221 fprintf(stderr, "%s: %s not found\n", "alias", n);
3222 ret = 1;
3223 } else
3224 printalias(ap);
3225 } else {
3226 *v++ = '\0';
3227 setalias(n, v);
3228 }
3229 }
3230
3231 return ret;
3232 }
3233
3234 static int
3235 unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3236 {
3237 int i;
3238
3239 while ((i = nextopt("a")) != '\0') {
3240 if (i == 'a') {
3241 rmaliases();
3242 return 0;
3243 }
3244 }
3245 for (i = 0; *argptr; argptr++) {
3246 if (unalias(*argptr)) {
3247 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
3248 i = 1;
3249 }
3250 }
3251
3252 return i;
3253 }
3254
3255 #endif /* ASH_ALIAS */
3256
3257
3258 /* ============ jobs.c */
3259
3260 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
3261 #define FORK_FG 0
3262 #define FORK_BG 1
3263 #define FORK_NOJOB 2
3264
3265 /* mode flags for showjob(s) */
3266 #define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
3267 #define SHOW_PID 0x04 /* include process pid */
3268 #define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
3269
3270 /*
3271 * A job structure contains information about a job. A job is either a
3272 * single process or a set of processes contained in a pipeline. In the
3273 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3274 * array of pids.
3275 */
3276
3277 struct procstat {
3278 pid_t pid; /* process id */
3279 int status; /* last process status from wait() */
3280 char *cmd; /* text of command being run */
3281 };
3282
3283 struct job {
3284 struct procstat ps0; /* status of process */
3285 struct procstat *ps; /* status or processes when more than one */
3286 #if JOBS
3287 int stopstatus; /* status of a stopped job */
3288 #endif
3289 uint32_t
3290 nprocs: 16, /* number of processes */
3291 state: 8,
3292 #define JOBRUNNING 0 /* at least one proc running */
3293 #define JOBSTOPPED 1 /* all procs are stopped */
3294 #define JOBDONE 2 /* all procs are completed */
3295 #if JOBS
3296 sigint: 1, /* job was killed by SIGINT */
3297 jobctl: 1, /* job running under job control */
3298 #endif
3299 waited: 1, /* true if this entry has been waited for */
3300 used: 1, /* true if this entry is in used */
3301 changed: 1; /* true if status has changed */
3302 struct job *prev_job; /* previous job */
3303 };
3304
3305 static struct job *makejob(/*union node *,*/ int);
3306 #if !JOBS
3307 #define forkshell(job, node, mode) forkshell(job, mode)
3308 #endif
3309 static int forkshell(struct job *, union node *, int);
3310 static int waitforjob(struct job *);
3311
3312 #if !JOBS
3313 enum { doing_jobctl = 0 };
3314 #define setjobctl(on) do {} while (0)
3315 #else
3316 static smallint doing_jobctl; //references:8
3317 static void setjobctl(int);
3318 #endif
3319
3320 /*
3321 * Set the signal handler for the specified signal. The routine figures
3322 * out what it should be set to.
3323 */
3324 static void
3325 setsignal(int signo)
3326 {
3327 int action;
3328 char *t, tsig;
3329 struct sigaction act;
3330
3331 t = trap[signo];
3332 action = S_IGN;
3333 if (t == NULL)
3334 action = S_DFL;
3335 else if (*t != '\0')
3336 action = S_CATCH;
3337 if (rootshell && action == S_DFL) {
3338 switch (signo) {
3339 case SIGINT:
3340 if (iflag || minusc || sflag == 0)
3341 action = S_CATCH;
3342 break;
3343 case SIGQUIT:
3344 #if DEBUG
3345 if (debug)
3346 break;
3347 #endif
3348 /* FALLTHROUGH */
3349 case SIGTERM:
3350 if (iflag)
3351 action = S_IGN;
3352 break;
3353 #if JOBS
3354 case SIGTSTP:
3355 case SIGTTOU:
3356 if (mflag)
3357 action = S_IGN;
3358 break;
3359 #endif
3360 }
3361 }
3362
3363 t = &sigmode[signo - 1];
3364 tsig = *t;
3365 if (tsig == 0) {
3366 /*
3367 * current setting unknown
3368 */
3369 if (sigaction(signo, NULL, &act) == -1) {
3370 /*
3371 * Pretend it worked; maybe we should give a warning
3372 * here, but other shells don't. We don't alter
3373 * sigmode, so that we retry every time.
3374 */
3375 return;
3376 }
3377 tsig = S_RESET; /* force to be set */
3378 if (act.sa_handler == SIG_IGN) {
3379 tsig = S_HARD_IGN;
3380 if (mflag
3381 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3382 ) {
3383 tsig = S_IGN; /* don't hard ignore these */
3384 }
3385 }
3386 }
3387 if (tsig == S_HARD_IGN || tsig == action)
3388 return;
3389 act.sa_handler = SIG_DFL;
3390 switch (action) {
3391 case S_CATCH:
3392 act.sa_handler = onsig;
3393 break;
3394 case S_IGN:
3395 act.sa_handler = SIG_IGN;
3396 break;
3397 }
3398 *t = action;
3399 act.sa_flags = 0;
3400 sigfillset(&act.sa_mask);
3401 sigaction_set(signo, &act);
3402 }
3403
3404 /* mode flags for set_curjob */
3405 #define CUR_DELETE 2
3406 #define CUR_RUNNING 1
3407 #define CUR_STOPPED 0
3408
3409 /* mode flags for dowait */
3410 #define DOWAIT_NONBLOCK WNOHANG
3411 #define DOWAIT_BLOCK 0
3412
3413 #if JOBS
3414 /* pgrp of shell on invocation */
3415 static int initialpgrp; //references:2
3416 static int ttyfd = -1; //5
3417 #endif
3418 /* array of jobs */
3419 static struct job *jobtab; //5
3420 /* size of array */
3421 static unsigned njobs; //4
3422 /* current job */
3423 static struct job *curjob; //lots
3424 /* number of presumed living untracked jobs */
3425 static int jobless; //4
3426
3427 static void
3428 set_curjob(struct job *jp, unsigned mode)
3429 {
3430 struct job *jp1;
3431 struct job **jpp, **curp;
3432
3433 /* first remove from list */
3434 jpp = curp = &curjob;
3435 do {
3436 jp1 = *jpp;
3437 if (jp1 == jp)
3438 break;
3439 jpp = &jp1->prev_job;
3440 } while (1);
3441 *jpp = jp1->prev_job;
3442
3443 /* Then re-insert in correct position */
3444 jpp = curp;
3445 switch (mode) {
3446 default:
3447 #if DEBUG
3448 abort();
3449 #endif
3450 case CUR_DELETE:
3451 /* job being deleted */
3452 break;
3453 case CUR_RUNNING:
3454 /* newly created job or backgrounded job,
3455 put after all stopped jobs. */
3456 do {
3457 jp1 = *jpp;
3458 #if JOBS
3459 if (!jp1 || jp1->state != JOBSTOPPED)
3460 #endif
3461 break;
3462 jpp = &jp1->prev_job;
3463 } while (1);
3464 /* FALLTHROUGH */
3465 #if JOBS
3466 case CUR_STOPPED:
3467 #endif
3468 /* newly stopped job - becomes curjob */
3469 jp->prev_job = *jpp;
3470 *jpp = jp;
3471 break;
3472 }
3473 }
3474
3475 #if JOBS || DEBUG
3476 static int
3477 jobno(const struct job *jp)
3478 {
3479 return jp - jobtab + 1;
3480 }
3481 #endif
3482
3483 /*
3484 * Convert a job name to a job structure.
3485 */
3486 #if !JOBS
3487 #define getjob(name, getctl) getjob(name)
3488 #endif
3489 static struct job *
3490 getjob(const char *name, int getctl)
3491 {
3492 struct job *jp;
3493 struct job *found;
3494 const char *err_msg = "No such job: %s";
3495 unsigned num;
3496 int c;
3497 const char *p;
3498 char *(*match)(const char *, const char *);
3499
3500 jp = curjob;
3501 p = name;
3502 if (!p)
3503 goto currentjob;
3504
3505 if (*p != '%')
3506 goto err;
3507
3508 c = *++p;
3509 if (!c)
3510 goto currentjob;
3511
3512 if (!p[1]) {
3513 if (c == '+' || c == '%') {
3514 currentjob:
3515 err_msg = "No current job";
3516 goto check;
3517 }
3518 if (c == '-') {
3519 if (jp)
3520 jp = jp->prev_job;
3521 err_msg = "No previous job";
3522 check:
3523 if (!jp)
3524 goto err;
3525 goto gotit;
3526 }
3527 }
3528
3529 if (is_number(p)) {
3530 // TODO: number() instead? It does error checking...
3531 num = atoi(p);
3532 if (num < njobs) {
3533 jp = jobtab + num - 1;
3534 if (jp->used)
3535 goto gotit;
3536 goto err;
3537 }
3538 }
3539
3540 match = prefix;
3541 if (*p == '?') {
3542 match = strstr;
3543 p++;
3544 }
3545
3546 found = 0;
3547 while (1) {
3548 if (!jp)
3549 goto err;
3550 if (match(jp->ps[0].cmd, p)) {
3551 if (found)
3552 goto err;
3553 found = jp;
3554 err_msg = "%s: ambiguous";
3555 }
3556 jp = jp->prev_job;
3557 }
3558
3559 gotit:
3560 #if JOBS
3561 err_msg = "job %s not created under job control";
3562 if (getctl && jp->jobctl == 0)
3563 goto err;
3564 #endif
3565 return jp;
3566 err:
3567 ash_msg_and_raise_error(err_msg, name);
3568 }
3569
3570 /*
3571 * Mark a job structure as unused.
3572 */
3573 static void
3574 freejob(struct job *jp)
3575 {
3576 struct procstat *ps;
3577 int i;
3578
3579 INT_OFF;
3580 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
3581 if (ps->cmd != nullstr)
3582 free(ps->cmd);
3583 }
3584 if (jp->ps != &jp->ps0)
3585 free(jp->ps);
3586 jp->used = 0;
3587 set_curjob(jp, CUR_DELETE);
3588 INT_ON;
3589 }
3590
3591 #if JOBS
3592 static void
3593 xtcsetpgrp(int fd, pid_t pgrp)
3594 {
3595 if (tcsetpgrp(fd, pgrp))
3596 ash_msg_and_raise_error("can't set tty process group (%m)");
3597 }
3598
3599 /*
3600 * Turn job control on and off.
3601 *
3602 * Note: This code assumes that the third arg to ioctl is a character
3603 * pointer, which is true on Berkeley systems but not System V. Since
3604 * System V doesn't have job control yet, this isn't a problem now.
3605 *
3606 * Called with interrupts off.
3607 */
3608 static void
3609 setjobctl(int on)
3610 {
3611 int fd;
3612 int pgrp;
3613
3614 if (on == doing_jobctl || rootshell == 0)
3615 return;
3616 if (on) {
3617 int ofd;
3618 ofd = fd = open(_PATH_TTY, O_RDWR);
3619 if (fd < 0) {
3620 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3621 * That sometimes helps to acquire controlling tty.
3622 * Obviously, a workaround for bugs when someone
3623 * failed to provide a controlling tty to bash! :) */
3624 fd = 2;
3625 while (!isatty(fd))
3626 if (--fd < 0)
3627 goto out;
3628 }
3629 fd = fcntl(fd, F_DUPFD, 10);
3630 if (ofd >= 0)
3631 close(ofd);
3632 if (fd < 0)
3633 goto out;
3634 /* fd is a tty at this point */
3635 close_on_exec_on(fd);
3636 do { /* while we are in the background */
3637 pgrp = tcgetpgrp(fd);
3638 if (pgrp < 0) {
3639 out:
3640 ash_msg("can't access tty; job control turned off");
3641 mflag = on = 0;
3642 goto close;
3643 }
3644 if (pgrp == getpgrp())
3645 break;
3646 killpg(0, SIGTTIN);
3647 } while (1);
3648 initialpgrp = pgrp;
3649
3650 setsignal(SIGTSTP);
3651 setsignal(SIGTTOU);
3652 setsignal(SIGTTIN);
3653 pgrp = rootpid;
3654 setpgid(0, pgrp);
3655 xtcsetpgrp(fd, pgrp);
3656 } else {
3657 /* turning job control off */
3658 fd = ttyfd;
3659 pgrp = initialpgrp;
3660 /* was xtcsetpgrp, but this can make exiting ash
3661 * loop forever if pty is already deleted */
3662 tcsetpgrp(fd, pgrp);
3663 setpgid(0, pgrp);
3664 setsignal(SIGTSTP);
3665 setsignal(SIGTTOU);
3666 setsignal(SIGTTIN);
3667 close:
3668 if (fd >= 0)
3669 close(fd);
3670 fd = -1;
3671 }
3672 ttyfd = fd;
3673 doing_jobctl = on;
3674 }
3675
3676 static int
3677 killcmd(int argc, char **argv)
3678 {
3679 int i = 1;
3680 if (argv[1] && strcmp(argv[1], "-l") != 0) {
3681 do {
3682 if (argv[i][0] == '%') {
3683 struct job *jp = getjob(argv[i], 0);
3684 unsigned pid = jp->ps[0].pid;
3685 /* Enough space for ' -NNN<nul>' */
3686 argv[i] = alloca(sizeof(int)*3 + 3);
3687 /* kill_main has matching code to expect
3688 * leading space. Needed to not confuse
3689 * negative pids with "kill -SIGNAL_NO" syntax */
3690 sprintf(argv[i], " -%u", pid);
3691 }
3692 } while (argv[++i]);
3693 }
3694 return kill_main(argc, argv);
3695 }
3696
3697 static void
3698 showpipe(struct job *jp, FILE *out)
3699 {
3700 struct procstat *sp;
3701 struct procstat *spend;
3702
3703 spend = jp->ps + jp->nprocs;
3704 for (sp = jp->ps + 1; sp < spend; sp++)
3705 fprintf(out, " | %s", sp->cmd);
3706 outcslow('\n', out);
3707 flush_stdout_stderr();
3708 }
3709
3710
3711 static int
3712 restartjob(struct job *jp, int mode)
3713 {
3714 struct procstat *ps;
3715 int i;
3716 int status;
3717 pid_t pgid;
3718
3719 INT_OFF;
3720 if (jp->state == JOBDONE)
3721 goto out;
3722 jp->state = JOBRUNNING;
3723 pgid = jp->ps->pid;
3724 if (mode == FORK_FG)
3725 xtcsetpgrp(ttyfd, pgid);
3726 killpg(pgid, SIGCONT);
3727 ps = jp->ps;
3728 i = jp->nprocs;
3729 do {
3730 if (WIFSTOPPED(ps->status)) {
3731 ps->status = -1;
3732 }
3733 ps++;
3734 } while (--i);
3735 out:
3736 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3737 INT_ON;
3738 return status;
3739 }
3740
3741 static int
3742 fg_bgcmd(int argc UNUSED_PARAM, char **argv)
3743 {
3744 struct job *jp;
3745 FILE *out;
3746 int mode;
3747 int retval;
3748
3749 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3750 nextopt(nullstr);
3751 argv = argptr;
3752 out = stdout;
3753 do {
3754 jp = getjob(*argv, 1);
3755 if (mode == FORK_BG) {
3756 set_curjob(jp, CUR_RUNNING);
3757 fprintf(out, "[%d] ", jobno(jp));
3758 }
3759 outstr(jp->ps->cmd, out);
3760 showpipe(jp, out);
3761 retval = restartjob(jp, mode);
3762 } while (*argv && *++argv);
3763 return retval;
3764 }
3765 #endif
3766
3767 static int
3768 sprint_status(char *s, int status, int sigonly)
3769 {
3770 int col;
3771 int st;
3772
3773 col = 0;
3774 if (!WIFEXITED(status)) {
3775 #if JOBS
3776 if (WIFSTOPPED(status))
3777 st = WSTOPSIG(status);
3778 else
3779 #endif
3780 st = WTERMSIG(status);
3781 if (sigonly) {
3782 if (st == SIGINT || st == SIGPIPE)
3783 goto out;
3784 #if JOBS
3785 if (WIFSTOPPED(status))
3786 goto out;
3787 #endif
3788 }
3789 st &= 0x7f;
3790 col = fmtstr(s, 32, strsignal(st));
3791 if (WCOREDUMP(status)) {
3792 col += fmtstr(s + col, 16, " (core dumped)");
3793 }
3794 } else if (!sigonly) {
3795 st = WEXITSTATUS(status);
3796 if (st)
3797 col = fmtstr(s, 16, "Done(%d)", st);
3798 else
3799 col = fmtstr(s, 16, "Done");
3800 }
3801 out:
3802 return col;
3803 }
3804
3805 static int
3806 dowait(int wait_flags, struct job *job)
3807 {
3808 int pid;
3809 int status;
3810 struct job *jp;
3811 struct job *thisjob;
3812 int state;
3813
3814 TRACE(("dowait(0x%x) called\n", wait_flags));
3815
3816 /* Do a wait system call. If job control is compiled in, we accept
3817 * stopped processes. wait_flags may have WNOHANG, preventing blocking.
3818 * NB: _not_ safe_waitpid, we need to detect EINTR */
3819 pid = waitpid(-1, &status,
3820 (doing_jobctl ? (wait_flags | WUNTRACED) : wait_flags));
3821 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", pid, status, errno, strerror(errno)));
3822
3823 if (pid <= 0) {
3824 /* If we were doing blocking wait and (probably) got EINTR,
3825 * check for pending sigs received while waiting.
3826 * (NB: can be moved into callers if needed) */
3827 if (wait_flags == DOWAIT_BLOCK && pendingsig)
3828 raise_exception(EXSIG);
3829 return pid;
3830 }
3831 INT_OFF;
3832 thisjob = NULL;
3833 for (jp = curjob; jp; jp = jp->prev_job) {
3834 struct procstat *sp;
3835 struct procstat *spend;
3836 if (jp->state == JOBDONE)
3837 continue;
3838 state = JOBDONE;
3839 spend = jp->ps + jp->nprocs;
3840 sp = jp->ps;
3841 do {
3842 if (sp->pid == pid) {
3843 TRACE(("Job %d: changing status of proc %d "
3844 "from 0x%x to 0x%x\n",
3845 jobno(jp), pid, sp->status, status));
3846 sp->status = status;
3847 thisjob = jp;
3848 }
3849 if (sp->status == -1)
3850 state = JOBRUNNING;
3851 #if JOBS
3852 if (state == JOBRUNNING)
3853 continue;
3854 if (WIFSTOPPED(sp->status)) {
3855 jp->stopstatus = sp->status;
3856 state = JOBSTOPPED;
3857 }
3858 #endif
3859 } while (++sp < spend);
3860 if (thisjob)
3861 goto gotjob;
3862 }
3863 #if JOBS
3864 if (!WIFSTOPPED(status))
3865 #endif
3866 jobless--;
3867 goto out;
3868
3869 gotjob:
3870 if (state != JOBRUNNING) {
3871 thisjob->changed = 1;
3872
3873 if (thisjob->state != state) {
3874 TRACE(("Job %d: changing state from %d to %d\n",
3875 jobno(thisjob), thisjob->state, state));
3876 thisjob->state = state;
3877 #if JOBS
3878 if (state == JOBSTOPPED) {
3879 set_curjob(thisjob, CUR_STOPPED);
3880 }
3881 #endif
3882 }
3883 }
3884
3885 out:
3886 INT_ON;
3887
3888 if (thisjob && thisjob == job) {
3889 char s[48 + 1];
3890 int len;
3891
3892 len = sprint_status(s, status, 1);
3893 if (len) {
3894 s[len] = '\n';
3895 s[len + 1] = '\0';
3896 out2str(s);
3897 }
3898 }
3899 return pid;
3900 }
3901
3902 #if JOBS
3903 static void
3904 showjob(FILE *out, struct job *jp, int mode)
3905 {
3906 struct procstat *ps;
3907 struct procstat *psend;
3908 int col;
3909 int indent_col;
3910 char s[80];
3911
3912 ps = jp->ps;
3913
3914 if (mode & SHOW_PGID) {
3915 /* just output process (group) id of pipeline */
3916 fprintf(out, "%d\n", ps->pid);
3917 return;
3918 }
3919
3920 col = fmtstr(s, 16, "[%d] ", jobno(jp));
3921 indent_col = col;
3922
3923 if (jp == curjob)
3924 s[col - 2] = '+';
3925 else if (curjob && jp == curjob->prev_job)
3926 s[col - 2] = '-';
3927
3928 if (mode & SHOW_PID)
3929 col += fmtstr(s + col, 16, "%d ", ps->pid);
3930
3931 psend = ps + jp->nprocs;
3932
3933 if (jp->state == JOBRUNNING) {
3934 strcpy(s + col, "Running");
3935 col += sizeof("Running") - 1;
3936 } else {
3937 int status = psend[-1].status;
3938 if (jp->state == JOBSTOPPED)
3939 status = jp->stopstatus;
3940 col += sprint_status(s + col, status, 0);
3941 }
3942
3943 goto start;
3944
3945 do {
3946 /* for each process */
3947 col = fmtstr(s, 48, " |\n%*c%d ", indent_col, ' ', ps->pid) - 3;
3948 start:
3949 fprintf(out, "%s%*c%s",
3950 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
3951 );
3952 if (!(mode & SHOW_PID)) {
3953 showpipe(jp, out);
3954 break;
3955 }
3956 if (++ps == psend) {
3957 outcslow('\n', out);
3958 break;
3959 }
3960 } while (1);
3961
3962 jp->changed = 0;
3963
3964 if (jp->state == JOBDONE) {
3965 TRACE(("showjob: freeing job %d\n", jobno(jp)));
3966 freejob(jp);
3967 }
3968 }
3969
3970 /*
3971 * Print a list of jobs. If "change" is nonzero, only print jobs whose
3972 * statuses have changed since the last call to showjobs.
3973 */
3974 static void
3975 showjobs(FILE *out, int mode)
3976 {
3977 struct job *jp;
3978
3979 TRACE(("showjobs(%x) called\n", mode));
3980
3981 /* If not even one job changed, there is nothing to do */
3982 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
3983 continue;
3984
3985 for (jp = curjob; jp; jp = jp->prev_job) {
3986 if (!(mode & SHOW_CHANGED) || jp->changed) {
3987 showjob(out, jp, mode);
3988 }
3989 }
3990 }
3991
3992 static int
3993 jobscmd(int argc UNUSED_PARAM, char **argv)
3994 {
3995 int mode, m;
3996
3997 mode = 0;
3998 while ((m = nextopt("lp"))) {
3999 if (m == 'l')
4000 mode = SHOW_PID;
4001 else
4002 mode = SHOW_PGID;
4003 }
4004
4005 argv = argptr;
4006 if (*argv) {
4007 do
4008 showjob(stdout, getjob(*argv,0), mode);
4009 while (*++argv);
4010 } else
4011 showjobs(stdout, mode);
4012
4013 return 0;
4014 }
4015 #endif /* JOBS */
4016
4017 static int
4018 getstatus(struct job *job)
4019 {
4020 int status;
4021 int retval;
4022
4023 status = job->ps[job->nprocs - 1].status;
4024 retval = WEXITSTATUS(status);
4025 if (!WIFEXITED(status)) {
4026 #if JOBS
4027 retval = WSTOPSIG(status);
4028 if (!WIFSTOPPED(status))
4029 #endif
4030 {
4031 /* XXX: limits number of signals */
4032 retval = WTERMSIG(status);
4033 #if JOBS
4034 if (retval == SIGINT)
4035 job->sigint = 1;
4036 #endif
4037 }
4038 retval += 128;
4039 }
4040 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
4041 jobno(job), job->nprocs, status, retval));
4042 return retval;
4043 }
4044
4045 static int
4046 waitcmd(int argc UNUSED_PARAM, char **argv)
4047 {
4048 struct job *job;
4049 int retval;
4050 struct job *jp;
4051
4052 // exsig++;
4053 // xbarrier();
4054 if (pendingsig)
4055 raise_exception(EXSIG);
4056
4057 nextopt(nullstr);
4058 retval = 0;
4059
4060 argv = argptr;
4061 if (!*argv) {
4062 /* wait for all jobs */
4063 for (;;) {
4064 jp = curjob;
4065 while (1) {
4066 if (!jp) /* no running procs */
4067 goto ret;
4068 if (jp->state == JOBRUNNING)
4069 break;
4070 jp->waited = 1;
4071 jp = jp->prev_job;
4072 }
4073 dowait(DOWAIT_BLOCK, NULL);
4074 }
4075 }
4076
4077 retval = 127;
4078 do {
4079 if (**argv != '%') {
4080 pid_t pid = number(*argv);
4081 job = curjob;
4082 while (1) {
4083 if (!job)
4084 goto repeat;
4085 if (job->ps[job->nprocs - 1].pid == pid)
4086 break;
4087 job = job->prev_job;
4088 }
4089 } else
4090 job = getjob(*argv, 0);
4091 /* loop until process terminated or stopped */
4092 while (job->state == JOBRUNNING)
4093 dowait(DOWAIT_BLOCK, NULL);
4094 job->waited = 1;
4095 retval = getstatus(job);
4096 repeat:
4097 ;
4098 } while (*++argv);
4099
4100 ret:
4101 return retval;
4102 }
4103
4104 static struct job *
4105 growjobtab(void)
4106 {
4107 size_t len;
4108 ptrdiff_t offset;
4109 struct job *jp, *jq;
4110
4111 len = njobs * sizeof(*jp);
4112 jq = jobtab;
4113 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4114
4115 offset = (char *)jp - (char *)jq;
4116 if (offset) {
4117 /* Relocate pointers */
4118 size_t l = len;
4119
4120 jq = (struct job *)((char *)jq + l);
4121 while (l) {
4122 l -= sizeof(*jp);
4123 jq--;
4124 #define joff(p) ((struct job *)((char *)(p) + l))
4125 #define jmove(p) (p) = (void *)((char *)(p) + offset)
4126 if (joff(jp)->ps == &jq->ps0)
4127 jmove(joff(jp)->ps);
4128 if (joff(jp)->prev_job)
4129 jmove(joff(jp)->prev_job);
4130 }
4131 if (curjob)
4132 jmove(curjob);
4133 #undef joff
4134 #undef jmove
4135 }
4136
4137 njobs += 4;
4138 jobtab = jp;
4139 jp = (struct job *)((char *)jp + len);
4140 jq = jp + 3;
4141 do {
4142 jq->used = 0;
4143 } while (--jq >= jp);
4144 return jp;
4145 }
4146
4147 /*
4148 * Return a new job structure.
4149 * Called with interrupts off.
4150 */
4151 static struct job *
4152 makejob(/*union node *node,*/ int nprocs)
4153 {
4154 int i;
4155 struct job *jp;
4156
4157 for (i = njobs, jp = jobtab; ; jp++) {
4158 if (--i < 0) {
4159 jp = growjobtab();
4160 break;
4161 }
4162 if (jp->used == 0)
4163 break;
4164 if (jp->state != JOBDONE || !jp->waited)
4165 continue;
4166 #if JOBS
4167 if (doing_jobctl)
4168 continue;
4169 #endif
4170 freejob(jp);
4171 break;
4172 }
4173 memset(jp, 0, sizeof(*jp));
4174 #if JOBS
4175 /* jp->jobctl is a bitfield.
4176 * "jp->jobctl |= jobctl" likely to give awful code */
4177 if (doing_jobctl)
4178 jp->jobctl = 1;
4179 #endif
4180 jp->prev_job = curjob;
4181 curjob = jp;
4182 jp->used = 1;
4183 jp->ps = &jp->ps0;
4184 if (nprocs > 1) {
4185 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4186 }
4187 TRACE(("makejob(%d) returns %%%d\n", nprocs,
4188 jobno(jp)));
4189 return jp;
4190 }
4191
4192 #if JOBS
4193 /*
4194 * Return a string identifying a command (to be printed by the
4195 * jobs command).
4196 */
4197 static char *cmdnextc;
4198
4199 static void
4200 cmdputs(const char *s)
4201 {
4202 static const char vstype[VSTYPE + 1][3] = {
4203 "", "}", "-", "+", "?", "=",
4204 "%", "%%", "#", "##"
4205 USE_ASH_BASH_COMPAT(, ":", "/", "//")
4206 };
4207
4208 const char *p, *str;
4209 char c, cc[2] = " ";
4210 char *nextc;
4211 int subtype = 0;
4212 int quoted = 0;
4213
4214 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4215 p = s;
4216 while ((c = *p++) != 0) {
4217 str = NULL;
4218 switch (c) {
4219 case CTLESC:
4220 c = *p++;
4221 break;
4222 case CTLVAR:
4223 subtype = *p++;
4224 if ((subtype & VSTYPE) == VSLENGTH)
4225 str = "${#";
4226 else
4227 str = "${";
4228 if (!(subtype & VSQUOTE) == !(quoted & 1))
4229 goto dostr;
4230 quoted ^= 1;
4231 c = '"';
4232 break;
4233 case CTLENDVAR:
4234 str = "\"}" + !(quoted & 1);
4235 quoted >>= 1;
4236 subtype = 0;
4237 goto dostr;
4238 case CTLBACKQ:
4239 str = "$(...)";
4240 goto dostr;
4241 case CTLBACKQ+CTLQUOTE:
4242 str = "\"$(...)\"";
4243 goto dostr;
4244 #if ENABLE_ASH_MATH_SUPPORT
4245 case CTLARI:
4246 str = "$((";
4247 goto dostr;
4248 case CTLENDARI:
4249 str = "))";
4250 goto dostr;
4251 #endif
4252 case CTLQUOTEMARK:
4253 quoted ^= 1;
4254 c = '"';
4255 break;
4256 case '=':
4257 if (subtype == 0)
4258 break;
4259 if ((subtype & VSTYPE) != VSNORMAL)
4260 quoted <<= 1;
4261 str = vstype[subtype & VSTYPE];
4262 if (subtype & VSNUL)
4263 c = ':';
4264 else
4265 goto checkstr;
4266 break;
4267 case '\'':
4268 case '\\':
4269 case '"':
4270 case '$':
4271 /* These can only happen inside quotes */
4272 cc[0] = c;
4273 str = cc;
4274 c = '\\';
4275 break;
4276 default:
4277 break;
4278 }
4279 USTPUTC(c, nextc);
4280 checkstr:
4281 if (!str)
4282 continue;
4283 dostr:
4284 while ((c = *str++)) {
4285 USTPUTC(c, nextc);
4286 }
4287 }
4288 if (quoted & 1) {
4289 USTPUTC('"', nextc);
4290 }
4291 *nextc = 0;
4292 cmdnextc = nextc;
4293 }
4294
4295 /* cmdtxt() and cmdlist() call each other */
4296 static void cmdtxt(union node *n);
4297
4298 static void
4299 cmdlist(union node *np, int sep)
4300 {
4301 for (; np; np = np->narg.next) {
4302 if (!sep)
4303 cmdputs(" ");
4304 cmdtxt(np);
4305 if (sep && np->narg.next)
4306 cmdputs(" ");
4307 }
4308 }
4309
4310 static void
4311 cmdtxt(union node *n)
4312 {
4313 union node *np;
4314 struct nodelist *lp;
4315 const char *p;
4316
4317 if (!n)
4318 return;
4319 switch (n->type) {
4320 default:
4321 #if DEBUG
4322 abort();
4323 #endif
4324 case NPIPE:
4325 lp = n->npipe.cmdlist;
4326 for (;;) {
4327 cmdtxt(lp->n);
4328 lp = lp->next;
4329 if (!lp)
4330 break;
4331 cmdputs(" | ");
4332 }
4333 break;
4334 case NSEMI:
4335 p = "; ";
4336 goto binop;
4337 case NAND:
4338 p = " && ";
4339 goto binop;
4340 case NOR:
4341 p = " || ";
4342 binop:
4343 cmdtxt(n->nbinary.ch1);
4344 cmdputs(p);
4345 n = n->nbinary.ch2;
4346 goto donode;
4347 case NREDIR:
4348 case NBACKGND:
4349 n = n->nredir.n;
4350 goto donode;
4351 case NNOT:
4352 cmdputs("!");
4353 n = n->nnot.com;
4354 donode:
4355 cmdtxt(n);
4356 break;
4357 case NIF:
4358 cmdputs("if ");
4359 cmdtxt(n->nif.test);
4360 cmdputs("; then ");
4361 n = n->nif.ifpart;
4362 if (n->nif.elsepart) {
4363 cmdtxt(n);
4364 cmdputs("; else ");
4365 n = n->nif.elsepart;
4366 }
4367 p = "; fi";
4368 goto dotail;
4369 case NSUBSHELL:
4370 cmdputs("(");
4371 n = n->nredir.n;
4372 p = ")";
4373 goto dotail;
4374 case NWHILE:
4375 p = "while ";
4376 goto until;
4377 case NUNTIL:
4378 p = "until ";
4379 until:
4380 cmdputs(p);
4381 cmdtxt(n->nbinary.ch1);
4382 n = n->nbinary.ch2;
4383 p = "; done";
4384 dodo:
4385 cmdputs("; do ");
4386 dotail:
4387 cmdtxt(n);
4388 goto dotail2;
4389 case NFOR:
4390 cmdputs("for ");
4391 cmdputs(n->nfor.var);
4392 cmdputs(" in ");
4393 cmdlist(n->nfor.args, 1);
4394 n = n->nfor.body;
4395 p = "; done";
4396 goto dodo;
4397 case NDEFUN:
4398 cmdputs(n->narg.text);
4399 p = "() { ... }";
4400 goto dotail2;
4401 case NCMD:
4402 cmdlist(n->ncmd.args, 1);
4403 cmdlist(n->ncmd.redirect, 0);
4404 break;
4405 case NARG:
4406 p = n->narg.text;
4407 dotail2:
4408 cmdputs(p);
4409 break;
4410 case NHERE:
4411 case NXHERE:
4412 p = "<<...";
4413 goto dotail2;
4414 case NCASE:
4415 cmdputs("case ");
4416 cmdputs(n->ncase.expr->narg.text);
4417 cmdputs(" in ");
4418 for (np = n->ncase.cases; np; np = np->nclist.next) {
4419 cmdtxt(np->nclist.pattern);
4420 cmdputs(") ");
4421 cmdtxt(np->nclist.body);
4422 cmdputs(";; ");
4423 }
4424 p = "esac";
4425 goto dotail2;
4426 case NTO:
4427 p = ">";
4428 goto redir;
4429 case NCLOBBER:
4430 p = ">|";
4431 goto redir;
4432 case NAPPEND:
4433 p = ">>";
4434 goto redir;
4435 #if ENABLE_ASH_BASH_COMPAT
4436 case NTO2:
4437 #endif
4438 case NTOFD:
4439 p = ">&";
4440 goto redir;
4441 case NFROM:
4442 p = "<";
4443 goto redir;
4444 case NFROMFD:
4445 p = "<&";
4446 goto redir;
4447 case NFROMTO:
4448 p = "<>";
4449 redir:
4450 cmdputs(utoa(n->nfile.fd));
4451 cmdputs(p);
4452 if (n->type == NTOFD || n->type == NFROMFD) {
4453 cmdputs(utoa(n->ndup.dupfd));
4454 break;
4455 }
4456 n = n->nfile.fname;
4457 goto donode;
4458 }
4459 }
4460
4461 static char *
4462 commandtext(union node *n)
4463 {
4464 char *name;
4465
4466 STARTSTACKSTR(cmdnextc);
4467 cmdtxt(n);
4468 name = stackblock();
4469 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
4470 name, cmdnextc, cmdnextc));
4471 return ckstrdup(name);
4472 }
4473 #endif /* JOBS */
4474
4475 /*
4476 * Fork off a subshell. If we are doing job control, give the subshell its
4477 * own process group. Jp is a job structure that the job is to be added to.
4478 * N is the command that will be evaluated by the child. Both jp and n may
4479 * be NULL. The mode parameter can be one of the following:
4480 * FORK_FG - Fork off a foreground process.
4481 * FORK_BG - Fork off a background process.
4482 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4483 * process group even if job control is on.
4484 *
4485 * When job control is turned off, background processes have their standard
4486 * input redirected to /dev/null (except for the second and later processes
4487 * in a pipeline).
4488 *
4489 * Called with interrupts off.
4490 */
4491 /*
4492 * Clear traps on a fork.
4493 */
4494 static void
4495 clear_traps(void)
4496 {
4497 char **tp;
4498
4499 for (tp = trap; tp < &trap[NSIG]; tp++) {
4500 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
4501 INT_OFF;
4502 free(*tp);
4503 *tp = NULL;
4504 if (tp != &trap[0])
4505 setsignal(tp - trap);
4506 INT_ON;
4507 }
4508 }
4509 }
4510
4511 /* Lives far away from here, needed for forkchild */
4512 static void closescript(void);
4513
4514 /* Called after fork(), in child */
4515 static void
4516 forkchild(struct job *jp, /*union node *n,*/ int mode)
4517 {
4518 int oldlvl;
4519
4520 TRACE(("Child shell %d\n", getpid()));
4521 oldlvl = shlvl;
4522 shlvl++;
4523
4524 closescript();
4525 clear_traps();
4526 #if JOBS
4527 /* do job control only in root shell */
4528 doing_jobctl = 0;
4529 if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
4530 pid_t pgrp;
4531
4532 if (jp->nprocs == 0)
4533 pgrp = getpid();
4534 else
4535 pgrp = jp->ps[0].pid;
4536 /* This can fail because we are doing it in the parent also */
4537 (void)setpgid(0, pgrp);
4538 if (mode == FORK_FG)
4539 xtcsetpgrp(ttyfd, pgrp);
4540 setsignal(SIGTSTP);
4541 setsignal(SIGTTOU);
4542 } else
4543 #endif
4544 if (mode == FORK_BG) {
4545 ignoresig(SIGINT);
4546 ignoresig(SIGQUIT);
4547 if (jp->nprocs == 0) {
4548 close(0);
4549 if (open(bb_dev_null, O_RDONLY) != 0)
4550 ash_msg_and_raise_error("can't open %s", bb_dev_null);
4551 }
4552 }
4553 if (!oldlvl && iflag) {
4554 setsignal(SIGINT);
4555 setsignal(SIGQUIT);
4556 setsignal(SIGTERM);
4557 }
4558 for (jp = curjob; jp; jp = jp->prev_job)
4559 freejob(jp);
4560 jobless = 0;
4561 }
4562
4563 /* Called after fork(), in parent */
4564 #if !JOBS
4565 #define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4566 #endif
4567 static void
4568 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4569 {
4570 TRACE(("In parent shell: child = %d\n", pid));
4571 if (!jp) {
4572 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4573 continue;
4574 jobless++;
4575 return;
4576 }
4577 #if JOBS
4578 if (mode != FORK_NOJOB && jp->jobctl) {
4579 int pgrp;
4580
4581 if (jp->nprocs == 0)
4582 pgrp = pid;
4583 else
4584 pgrp = jp->ps[0].pid;
4585 /* This can fail because we are doing it in the child also */
4586 setpgid(pid, pgrp);
4587 }
4588 #endif
4589 if (mode == FORK_BG) {
4590 backgndpid = pid; /* set $! */
4591 set_curjob(jp, CUR_RUNNING);
4592 }
4593 if (jp) {
4594 struct procstat *ps = &jp->ps[jp->nprocs++];
4595 ps->pid = pid;
4596 ps->status = -1;
4597 ps->cmd = nullstr;
4598 #if JOBS
4599 if (doing_jobctl && n)
4600 ps->cmd = commandtext(n);
4601 #endif
4602 }
4603 }
4604
4605 static int
4606 forkshell(struct job *jp, union node *n, int mode)
4607 {
4608 int pid;
4609
4610 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4611 pid = fork();
4612 if (pid < 0) {
4613 TRACE(("Fork failed, errno=%d", errno));
4614 if (jp)
4615 freejob(jp);
4616 ash_msg_and_raise_error("can't fork");
4617 }
4618 if (pid == 0)
4619 forkchild(jp, /*n,*/ mode);
4620 else
4621 forkparent(jp, n, mode, pid);
4622 return pid;
4623 }
4624
4625 /*
4626 * Wait for job to finish.
4627 *
4628 * Under job control we have the problem that while a child process is
4629 * running interrupts generated by the user are sent to the child but not
4630 * to the shell. This means that an infinite loop started by an inter-
4631 * active user may be hard to kill. With job control turned off, an
4632 * interactive user may place an interactive program inside a loop. If
4633 * the interactive program catches interrupts, the user doesn't want
4634 * these interrupts to also abort the loop. The approach we take here
4635 * is to have the shell ignore interrupt signals while waiting for a
4636 * foreground process to terminate, and then send itself an interrupt
4637 * signal if the child process was terminated by an interrupt signal.
4638 * Unfortunately, some programs want to do a bit of cleanup and then
4639 * exit on interrupt; unless these processes terminate themselves by
4640 * sending a signal to themselves (instead of calling exit) they will
4641 * confuse this approach.
4642 *
4643 * Called with interrupts off.
4644 */
4645 static int
4646 waitforjob(struct job *jp)
4647 {
4648 int st;
4649
4650 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
4651 while (jp->state == JOBRUNNING) {
4652 dowait(DOWAIT_BLOCK, jp);
4653 }
4654 st = getstatus(jp);
4655 #if JOBS
4656 if (jp->jobctl) {
4657 xtcsetpgrp(ttyfd, rootpid);
4658 /*
4659 * This is truly gross.
4660 * If we're doing job control, then we did a TIOCSPGRP which
4661 * caused us (the shell) to no longer be in the controlling
4662 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
4663 * intuit from the subprocess exit status whether a SIGINT
4664 * occurred, and if so interrupt ourselves. Yuck. - mycroft
4665 */
4666 if (jp->sigint) /* TODO: do the same with all signals */
4667 raise(SIGINT); /* ... by raise(jp->sig) instead? */
4668 }
4669 if (jp->state == JOBDONE)
4670 #endif
4671 freejob(jp);
4672 return st;
4673 }
4674
4675 /*
4676 * return 1 if there are stopped jobs, otherwise 0
4677 */
4678 static int
4679 stoppedjobs(void)
4680 {
4681 struct job *jp;
4682 int retval;
4683
4684 retval = 0;
4685 if (job_warning)
4686 goto out;
4687 jp = curjob;
4688 if (jp && jp->state == JOBSTOPPED) {
4689 out2str("You have stopped jobs.\n");
4690 job_warning = 2;
4691 retval++;
4692 }
4693 out:
4694 return retval;
4695 }
4696
4697
4698 /* ============ redir.c
4699 *
4700 * Code for dealing with input/output redirection.
4701 */
4702
4703 #define EMPTY -2 /* marks an unused slot in redirtab */
4704 #define CLOSED -3 /* marks a slot of previously-closed fd */
4705
4706 /*
4707 * Open a file in noclobber mode.
4708 * The code was copied from bash.
4709 */
4710 static int
4711 noclobberopen(const char *fname)
4712 {
4713 int r, fd;
4714 struct stat finfo, finfo2;
4715
4716 /*
4717 * If the file exists and is a regular file, return an error
4718 * immediately.
4719 */
4720 r = stat(fname, &finfo);
4721 if (r == 0 && S_ISREG(finfo.st_mode)) {
4722 errno = EEXIST;
4723 return -1;
4724 }
4725
4726 /*
4727 * If the file was not present (r != 0), make sure we open it
4728 * exclusively so that if it is created before we open it, our open
4729 * will fail. Make sure that we do not truncate an existing file.
4730 * Note that we don't turn on O_EXCL unless the stat failed -- if the
4731 * file was not a regular file, we leave O_EXCL off.
4732 */
4733 if (r != 0)
4734 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
4735 fd = open(fname, O_WRONLY|O_CREAT, 0666);
4736
4737 /* If the open failed, return the file descriptor right away. */
4738 if (fd < 0)
4739 return fd;
4740
4741 /*
4742 * OK, the open succeeded, but the file may have been changed from a
4743 * non-regular file to a regular file between the stat and the open.
4744 * We are assuming that the O_EXCL open handles the case where FILENAME
4745 * did not exist and is symlinked to an existing file between the stat
4746 * and open.
4747 */
4748
4749 /*
4750 * If we can open it and fstat the file descriptor, and neither check
4751 * revealed that it was a regular file, and the file has not been
4752 * replaced, return the file descriptor.
4753 */
4754 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode)
4755 && finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
4756 return fd;
4757
4758 /* The file has been replaced. badness. */
4759 close(fd);
4760 errno = EEXIST;
4761 return -1;
4762 }
4763
4764 /*
4765 * Handle here documents. Normally we fork off a process to write the
4766 * data to a pipe. If the document is short, we can stuff the data in
4767 * the pipe without forking.
4768 */
4769 /* openhere needs this forward reference */
4770 static void expandhere(union node *arg, int fd);
4771 static int
4772 openhere(union node *redir)
4773 {
4774 int pip[2];
4775 size_t len = 0;
4776
4777 if (pipe(pip) < 0)
4778 ash_msg_and_raise_error("pipe call failed");
4779 if (redir->type == NHERE) {
4780 len = strlen(redir->nhere.doc->narg.text);
4781 if (len <= PIPE_BUF) {
4782 full_write(pip[1], redir->nhere.doc->narg.text, len);
4783 goto out;
4784 }
4785 }
4786 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
4787 /* child */
4788 close(pip[0]);
4789 signal(SIGINT, SIG_IGN);
4790 signal(SIGQUIT, SIG_IGN);
4791 signal(SIGHUP, SIG_IGN);
4792 #ifdef SIGTSTP
4793 signal(SIGTSTP, SIG_IGN);
4794 #endif
4795 signal(SIGPIPE, SIG_DFL);
4796 if (redir->type == NHERE)
4797 full_write(pip[1], redir->nhere.doc->narg.text, len);
4798 else /* NXHERE */
4799 expandhere(redir->nhere.doc, pip[1]);
4800 _exit(EXIT_SUCCESS);
4801 }
4802 out:
4803 close(pip[1]);
4804 return pip[0];
4805 }
4806
4807 static int
4808 openredirect(union node *redir)
4809 {
4810 char *fname;
4811 int f;
4812
4813 switch (redir->nfile.type) {
4814 case NFROM:
4815 fname = redir->nfile.expfname;
4816 f = open(fname, O_RDONLY);
4817 if (f < 0)
4818 goto eopen;
4819 break;
4820 case NFROMTO:
4821 fname = redir->nfile.expfname;
4822 f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666);
4823 if (f < 0)
4824 goto ecreate;
4825 break;
4826 case NTO:
4827 #if ENABLE_ASH_BASH_COMPAT
4828 case NTO2:
4829 #endif
4830 /* Take care of noclobber mode. */
4831 if (Cflag) {
4832 fname = redir->nfile.expfname;
4833 f = noclobberopen(fname);
4834 if (f < 0)
4835 goto ecreate;
4836 break;
4837 }
4838 /* FALLTHROUGH */
4839 case NCLOBBER:
4840 fname = redir->nfile.expfname;
4841 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
4842 if (f < 0)
4843 goto ecreate;
4844 break;
4845 case NAPPEND:
4846 fname = redir->nfile.expfname;
4847 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
4848 if (f < 0)
4849 goto ecreate;
4850 break;
4851 default:
4852 #if DEBUG
4853 abort();
4854 #endif
4855 /* Fall through to eliminate warning. */
4856 /* Our single caller does this itself */
4857 // case NTOFD:
4858 // case NFROMFD:
4859 // f = -1;
4860 // break;
4861 case NHERE:
4862 case NXHERE:
4863 f = openhere(redir);
4864 break;
4865 }
4866
4867 return f;
4868 ecreate:
4869 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
4870 eopen:
4871 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
4872 }
4873
4874 /*
4875 * Copy a file descriptor to be >= to. Returns -1
4876 * if the source file descriptor is closed, EMPTY if there are no unused
4877 * file descriptors left.
4878 */
4879 /* 0x800..00: bit to set in "to" to request dup2 instead of fcntl(F_DUPFD).
4880 * old code was doing close(to) prior to copyfd() to achieve the same */
4881 enum {
4882 COPYFD_EXACT = (int)~(INT_MAX),
4883 COPYFD_RESTORE = (int)((unsigned)COPYFD_EXACT >> 1),
4884 };
4885 static int
4886 copyfd(int from, int to)
4887 {
4888 int newfd;
4889
4890 if (to & COPYFD_EXACT) {
4891 to &= ~COPYFD_EXACT;
4892 /*if (from != to)*/
4893 newfd = dup2(from, to);
4894 } else {
4895 newfd = fcntl(from, F_DUPFD, to);
4896 }
4897 if (newfd < 0) {
4898 if (errno == EMFILE)
4899 return EMPTY;
4900 /* Happens when source fd is not open: try "echo >&99" */
4901 ash_msg_and_raise_error("%d: %m", from);
4902 }
4903 return newfd;
4904 }
4905
4906 /* Struct def and variable are moved down to the first usage site */
4907 struct two_fd_t {
4908 int orig, copy;
4909 };
4910 struct redirtab {
4911 struct redirtab *next;
4912 int nullredirs;
4913 int pair_count;
4914 struct two_fd_t two_fd[0];
4915 };
4916 #define redirlist (G_var.redirlist)
4917
4918 static int need_to_remember(struct redirtab *rp, int fd)
4919 {
4920 int i;
4921
4922 if (!rp) /* remembering was not requested */
4923 return 0;
4924
4925 for (i = 0; i < rp->pair_count; i++) {
4926 if (rp->two_fd[i].orig == fd) {
4927 /* already remembered */
4928 return 0;
4929 }
4930 }
4931 return 1;
4932 }
4933
4934 /* "hidden" fd is a fd used to read scripts, or a copy of such */
4935 static int is_hidden_fd(struct redirtab *rp, int fd)
4936 {
4937 int i;
4938 struct parsefile *pf;
4939
4940 if (fd == -1)
4941 return 0;
4942 pf = g_parsefile;
4943 while (pf) {
4944 if (fd == pf->fd) {
4945 return 1;
4946 }
4947 pf = pf->prev;
4948 }
4949 if (!rp)
4950 return 0;
4951 fd |= COPYFD_RESTORE;
4952 for (i = 0; i < rp->pair_count; i++) {
4953 if (rp->two_fd[i].copy == fd) {
4954 return 1;
4955 }
4956 }
4957 return 0;
4958 }
4959
4960 /*
4961 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
4962 * old file descriptors are stashed away so that the redirection can be
4963 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
4964 * standard output, and the standard error if it becomes a duplicate of
4965 * stdout, is saved in memory.
4966 */
4967 /* flags passed to redirect */
4968 #define REDIR_PUSH 01 /* save previous values of file descriptors */
4969 #define REDIR_SAVEFD2 03 /* set preverrout */
4970 static void
4971 redirect(union node *redir, int flags)
4972 {
4973 struct redirtab *sv;
4974 int sv_pos;
4975 int i;
4976 int fd;
4977 int newfd;
4978 int copied_fd2 = -1;
4979
4980 g_nullredirs++;
4981 if (!redir) {
4982 return;
4983 }
4984
4985 sv = NULL;
4986 sv_pos = 0;
4987 INT_OFF;
4988 if (flags & REDIR_PUSH) {
4989 union node *tmp = redir;
4990 do {
4991 sv_pos++;
4992 #if ENABLE_ASH_BASH_COMPAT
4993 if (redir->nfile.type == NTO2)
4994 sv_pos++;
4995 #endif
4996 tmp = tmp->nfile.next;
4997 } while (tmp);
4998 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
4999 sv->next = redirlist;
5000 sv->pair_count = sv_pos;
5001 redirlist = sv;
5002 sv->nullredirs = g_nullredirs - 1;
5003 g_nullredirs = 0;
5004 while (sv_pos > 0) {
5005 sv_pos--;
5006 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
5007 }
5008 }
5009
5010 do {
5011 fd = redir->nfile.fd;
5012 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
5013 int right_fd = redir->ndup.dupfd;
5014 /* redirect from/to same file descriptor? */
5015 if (right_fd == fd)
5016 continue;
5017 /* echo >&10 and 10 is a fd opened to the sh script? */
5018 if (is_hidden_fd(sv, right_fd)) {
5019 errno = EBADF; /* as if it is closed */
5020 ash_msg_and_raise_error("%d: %m", right_fd);
5021 }
5022 newfd = -1;
5023 } else {
5024 newfd = openredirect(redir); /* always >= 0 */
5025 if (fd == newfd) {
5026 /* Descriptor wasn't open before redirect.
5027 * Mark it for close in the future */
5028 if (need_to_remember(sv, fd)) {
5029 goto remember_to_close;
5030 }
5031 continue;
5032 }
5033 }
5034 #if ENABLE_ASH_BASH_COMPAT
5035 redirect_more:
5036 #endif
5037 if (need_to_remember(sv, fd)) {
5038 /* Copy old descriptor */
5039 i = fcntl(fd, F_DUPFD, 10);
5040 /* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds
5041 * are closed in popredir() in the child, preventing them from leaking
5042 * into child. (popredir() also cleans up the mess in case of failures)
5043 */
5044 if (i == -1) {
5045 i = errno;
5046 if (i != EBADF) {
5047 /* Strange error (e.g. "too many files" EMFILE?) */
5048 if (newfd >= 0)
5049 close(newfd);
5050 errno = i;
5051 ash_msg_and_raise_error("%d: %m", fd);
5052 /* NOTREACHED */
5053 }
5054 /* EBADF: it is not open - good, remember to close it */
5055 remember_to_close:
5056 i = CLOSED;
5057 } else { /* fd is open, save its copy */
5058 /* "exec fd>&-" should not close fds
5059 * which point to script file(s).
5060 * Force them to be restored afterwards */
5061 if (is_hidden_fd(sv, fd))
5062 i |= COPYFD_RESTORE;
5063 }
5064 if (fd == 2)
5065 copied_fd2 = i;
5066 sv->two_fd[sv_pos].orig = fd;
5067 sv->two_fd[sv_pos].copy = i;
5068 sv_pos++;
5069 }
5070 if (newfd < 0) {
5071 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
5072 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
5073 /* Don't want to trigger debugging */
5074 if (fd != -1)
5075 close(fd);
5076 } else {
5077 copyfd(redir->ndup.dupfd, fd | COPYFD_EXACT);
5078 }
5079 } else if (fd != newfd) { /* move newfd to fd */
5080 copyfd(newfd, fd | COPYFD_EXACT);
5081 #if ENABLE_ASH_BASH_COMPAT
5082 if (!(redir->nfile.type == NTO2 && fd == 2))
5083 #endif
5084 close(newfd);
5085 }
5086 #if ENABLE_ASH_BASH_COMPAT
5087 if (redir->nfile.type == NTO2 && fd == 1) {
5088 /* We already redirected it to fd 1, now copy it to 2 */
5089 newfd = 1;
5090 fd = 2;
5091 goto redirect_more;
5092 }
5093 #endif
5094 } while ((redir = redir->nfile.next) != NULL);
5095
5096 INT_ON;
5097 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5098 preverrout_fd = copied_fd2;
5099 }
5100
5101 /*
5102 * Undo the effects of the last redirection.
5103 */
5104 static void
5105 popredir(int drop, int restore)
5106 {
5107 struct redirtab *rp;
5108 int i;
5109
5110 if (--g_nullredirs >= 0)
5111 return;
5112 INT_OFF;
5113 rp = redirlist;
5114 for (i = 0; i < rp->pair_count; i++) {
5115 int fd = rp->two_fd[i].orig;
5116 int copy = rp->two_fd[i].copy;
5117 if (copy == CLOSED) {
5118 if (!drop)
5119 close(fd);
5120 continue;
5121 }
5122 if (copy != EMPTY) {
5123 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
5124 copy &= ~COPYFD_RESTORE;
5125 /*close(fd);*/
5126 copyfd(copy, fd | COPYFD_EXACT);
5127 }
5128 close(copy & ~COPYFD_RESTORE);
5129 }
5130 }
5131 redirlist = rp->next;
5132 g_nullredirs = rp->nullredirs;
5133 free(rp);
5134 INT_ON;
5135 }
5136
5137 /*
5138 * Undo all redirections. Called on error or interrupt.
5139 */
5140
5141 /*
5142 * Discard all saved file descriptors.
5143 */
5144 static void
5145 clearredir(int drop)
5146 {
5147 for (;;) {
5148 g_nullredirs = 0;
5149 if (!redirlist)
5150 break;
5151 popredir(drop, /*restore:*/ 0);
5152 }
5153 }
5154
5155 static int
5156 redirectsafe(union node *redir, int flags)
5157 {
5158 int err;
5159 volatile int saveint;
5160 struct jmploc *volatile savehandler = exception_handler;
5161 struct jmploc jmploc;
5162
5163 SAVE_INT(saveint);
5164 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5165 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
5166 if (!err) {
5167 exception_handler = &jmploc;
5168 redirect(redir, flags);
5169 }
5170 exception_handler = savehandler;
5171 if (err && exception != EXERROR)
5172 longjmp(exception_handler->loc, 1);
5173 RESTORE_INT(saveint);
5174 return err;
5175 }
5176
5177
5178 /* ============ Routines to expand arguments to commands
5179 *
5180 * We have to deal with backquotes, shell variables, and file metacharacters.
5181 */
5182
5183 #if ENABLE_ASH_MATH_SUPPORT_64
5184 typedef int64_t arith_t;
5185 #define arith_t_type long long
5186 #else
5187 typedef long arith_t;
5188 #define arith_t_type long
5189 #endif
5190
5191 #if ENABLE_ASH_MATH_SUPPORT
5192 static arith_t dash_arith(const char *);
5193 static arith_t arith(const char *expr, int *perrcode);
5194 #endif
5195
5196 /*
5197 * expandarg flags
5198 */
5199 #define EXP_FULL 0x1 /* perform word splitting & file globbing */
5200 #define EXP_TILDE 0x2 /* do normal tilde expansion */
5201 #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5202 #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
5203 #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
5204 #define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
5205 #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5206 #define EXP_WORD 0x80 /* expand word in parameter expansion */
5207 #define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
5208 /*
5209 * _rmescape() flags
5210 */
5211 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5212 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
5213 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
5214 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5215 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
5216
5217 /*
5218 * Structure specifying which parts of the string should be searched
5219 * for IFS characters.
5220 */
5221 struct ifsregion {
5222 struct ifsregion *next; /* next region in list */
5223 int begoff; /* offset of start of region */
5224 int endoff; /* offset of end of region */
5225 int nulonly; /* search for nul bytes only */
5226 };
5227
5228 struct arglist {
5229 struct strlist *list;
5230 struct strlist **lastp;
5231 };
5232
5233 /* output of current string */
5234 static char *expdest;
5235 /* list of back quote expressions */
5236 static struct nodelist *argbackq;
5237 /* first struct in list of ifs regions */
5238 static struct ifsregion ifsfirst;
5239 /* last struct in list */
5240 static struct ifsregion *ifslastp;
5241 /* holds expanded arg list */
5242 static struct arglist exparg;
5243
5244 /*
5245 * Our own itoa().
5246 */
5247 static int
5248 cvtnum(arith_t num)
5249 {
5250 int len;
5251
5252 expdest = makestrspace(32, expdest);
5253 #if ENABLE_ASH_MATH_SUPPORT_64
5254 len = fmtstr(expdest, 32, "%lld", (long long) num);
5255 #else
5256 len = fmtstr(expdest, 32, "%ld", num);
5257 #endif
5258 STADJUST(len, expdest);
5259 return len;
5260 }
5261
5262 static size_t
5263 esclen(const char *start, const char *p)
5264 {
5265 size_t esc = 0;
5266
5267 while (p > start && *--p == CTLESC) {
5268 esc++;
5269 }
5270 return esc;
5271 }
5272
5273 /*
5274 * Remove any CTLESC characters from a string.
5275 */
5276 static char *
5277 _rmescapes(char *str, int flag)
5278 {
5279 static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' };
5280
5281 char *p, *q, *r;
5282 unsigned inquotes;
5283 int notescaped;
5284 int globbing;
5285
5286 p = strpbrk(str, qchars);
5287 if (!p) {
5288 return str;
5289 }
5290 q = p;
5291 r = str;
5292 if (flag & RMESCAPE_ALLOC) {
5293 size_t len = p - str;
5294 size_t fulllen = len + strlen(p) + 1;
5295
5296 if (flag & RMESCAPE_GROW) {
5297 r = makestrspace(fulllen, expdest);
5298 } else if (flag & RMESCAPE_HEAP) {
5299 r = ckmalloc(fulllen);
5300 } else {
5301 r = stalloc(fulllen);
5302 }
5303 q = r;
5304 if (len > 0) {
5305 q = (char *)memcpy(q, str, len) + len;
5306 }
5307 }
5308 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5309 globbing = flag & RMESCAPE_GLOB;
5310 notescaped = globbing;
5311 while (*p) {
5312 if (*p == CTLQUOTEMARK) {
5313 inquotes = ~inquotes;
5314 p++;
5315 notescaped = globbing;
5316 continue;
5317 }
5318 if (*p == '\\') {
5319 /* naked back slash */
5320 notescaped = 0;
5321 goto copy;
5322 }
5323 if (*p == CTLESC) {
5324 p++;
5325 if (notescaped && inquotes && *p != '/') {
5326 *q++ = '\\';
5327 }
5328 }
5329 notescaped = globbing;
5330 copy:
5331 *q++ = *p++;
5332 }
5333 *q = '\0';
5334 if (flag & RMESCAPE_GROW) {
5335 expdest = r;
5336 STADJUST(q - r + 1, expdest);
5337 }
5338 return r;
5339 }
5340 #define rmescapes(p) _rmescapes((p), 0)
5341
5342 #define pmatch(a, b) !fnmatch((a), (b), 0)
5343
5344 /*
5345 * Prepare a pattern for a expmeta (internal glob(3)) call.
5346 *
5347 * Returns an stalloced string.
5348 */
5349 static char *
5350 preglob(const char *pattern, int quoted, int flag)
5351 {
5352 flag |= RMESCAPE_GLOB;
5353 if (quoted) {
5354 flag |= RMESCAPE_QUOTED;
5355 }
5356 return _rmescapes((char *)pattern, flag);
5357 }
5358
5359 /*
5360 * Put a string on the stack.
5361 */
5362 static void
5363 memtodest(const char *p, size_t len, int syntax, int quotes)
5364 {
5365 char *q = expdest;
5366
5367 q = makestrspace(len * 2, q);
5368
5369 while (len--) {
5370 int c = signed_char2int(*p++);
5371 if (!c)
5372 continue;
5373 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5374 USTPUTC(CTLESC, q);
5375 USTPUTC(c, q);
5376 }
5377
5378 expdest = q;
5379 }
5380
5381 static void
5382 strtodest(const char *p, int syntax, int quotes)
5383 {
5384 memtodest(p, strlen(p), syntax, quotes);
5385 }
5386
5387 /*
5388 * Record the fact that we have to scan this region of the
5389 * string for IFS characters.
5390 */
5391 static void
5392 recordregion(int start, int end, int nulonly)
5393 {
5394 struct ifsregion *ifsp;
5395
5396 if (ifslastp == NULL) {
5397 ifsp = &ifsfirst;
5398 } else {
5399 INT_OFF;
5400 ifsp = ckzalloc(sizeof(*ifsp));
5401 /*ifsp->next = NULL; - ckzalloc did it */
5402 ifslastp->next = ifsp;
5403 INT_ON;
5404 }
5405 ifslastp = ifsp;
5406 ifslastp->begoff = start;
5407 ifslastp->endoff = end;
5408 ifslastp->nulonly = nulonly;
5409 }
5410
5411 static void
5412 removerecordregions(int endoff)
5413 {
5414 if (ifslastp == NULL)
5415 return;
5416
5417 if (ifsfirst.endoff > endoff) {
5418 while (ifsfirst.next != NULL) {
5419 struct ifsregion *ifsp;
5420 INT_OFF;
5421 ifsp = ifsfirst.next->next;
5422 free(ifsfirst.next);
5423 ifsfirst.next = ifsp;
5424 INT_ON;
5425 }
5426 if (ifsfirst.begoff > endoff)
5427 ifslastp = NULL;
5428 else {
5429 ifslastp = &ifsfirst;
5430 ifsfirst.endoff = endoff;
5431 }
5432 return;
5433 }
5434
5435 ifslastp = &ifsfirst;
5436 while (ifslastp->next && ifslastp->next->begoff < endoff)
5437 ifslastp=ifslastp->next;
5438 while (ifslastp->next != NULL) {
5439 struct ifsregion *ifsp;
5440 INT_OFF;
5441 ifsp = ifslastp->next->next;
5442 free(ifslastp->next);
5443 ifslastp->next = ifsp;
5444 INT_ON;
5445 }
5446 if (ifslastp->endoff > endoff)
5447 ifslastp->endoff = endoff;
5448 }
5449
5450 static char *
5451 exptilde(char *startp, char *p, int flag)
5452 {
5453 char c;
5454 char *name;
5455 struct passwd *pw;
5456 const char *home;
5457 int quotes = flag & (EXP_FULL | EXP_CASE);
5458 int startloc;
5459
5460 name = p + 1;
5461
5462 while ((c = *++p) != '\0') {
5463 switch (c) {
5464 case CTLESC:
5465 return startp;
5466 case CTLQUOTEMARK:
5467 return startp;
5468 case ':':
5469 if (flag & EXP_VARTILDE)
5470 goto done;
5471 break;
5472 case '/':
5473 case CTLENDVAR:
5474 goto done;
5475 }
5476 }
5477 done:
5478 *p = '\0';
5479 if (*name == '\0') {
5480 home = lookupvar(homestr);
5481 } else {
5482 pw = getpwnam(name);
5483 if (pw == NULL)
5484 goto lose;
5485 home = pw->pw_dir;
5486 }
5487 if (!home || !*home)
5488 goto lose;
5489 *p = c;
5490 startloc = expdest - (char *)stackblock();
5491 strtodest(home, SQSYNTAX, quotes);
5492 recordregion(startloc, expdest - (char *)stackblock(), 0);
5493 return p;
5494 lose:
5495 *p = c;
5496 return startp;
5497 }
5498
5499 /*
5500 * Execute a command inside back quotes. If it's a builtin command, we
5501 * want to save its output in a block obtained from malloc. Otherwise
5502 * we fork off a subprocess and get the output of the command via a pipe.
5503 * Should be called with interrupts off.
5504 */
5505 struct backcmd { /* result of evalbackcmd */
5506 int fd; /* file descriptor to read from */
5507 int nleft; /* number of chars in buffer */
5508 char *buf; /* buffer */
5509 struct job *jp; /* job structure for command */
5510 };
5511
5512 /* These forward decls are needed to use "eval" code for backticks handling: */
5513 static uint8_t back_exitstatus; /* exit status of backquoted command */
5514 #define EV_EXIT 01 /* exit after evaluating tree */
5515 static void evaltree(union node *, int);
5516
5517 static void
5518 evalbackcmd(union node *n, struct backcmd *result)
5519 {
5520 int saveherefd;
5521
5522 result->fd = -1;
5523 result->buf = NULL;
5524 result->nleft = 0;
5525 result->jp = NULL;
5526 if (n == NULL) {
5527 goto out;
5528 }
5529
5530 saveherefd = herefd;
5531 herefd = -1;
5532
5533 {
5534 int pip[2];
5535 struct job *jp;
5536
5537 if (pipe(pip) < 0)
5538 ash_msg_and_raise_error("pipe call failed");
5539 jp = makejob(/*n,*/ 1);
5540 if (forkshell(jp, n, FORK_NOJOB) == 0) {
5541 FORCE_INT_ON;
5542 close(pip[0]);
5543 if (pip[1] != 1) {
5544 /*close(1);*/
5545 copyfd(pip[1], 1 | COPYFD_EXACT);
5546 close(pip[1]);
5547 }
5548 eflag = 0;
5549 evaltree(n, EV_EXIT); /* actually evaltreenr... */
5550 /* NOTREACHED */
5551 }
5552 close(pip[1]);
5553 result->fd = pip[0];
5554 result->jp = jp;
5555 }
5556 herefd = saveherefd;
5557 out:
5558 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
5559 result->fd, result->buf, result->nleft, result->jp));
5560 }
5561
5562 /*
5563 * Expand stuff in backwards quotes.
5564 */
5565 static void
5566 expbackq(union node *cmd, int quoted, int quotes)
5567 {
5568 struct backcmd in;
5569 int i;
5570 char buf[128];
5571 char *p;
5572 char *dest;
5573 int startloc;
5574 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
5575 struct stackmark smark;
5576
5577 INT_OFF;
5578 setstackmark(&smark);
5579 dest = expdest;
5580 startloc = dest - (char *)stackblock();
5581 grabstackstr(dest);
5582 evalbackcmd(cmd, &in);
5583 popstackmark(&smark);
5584
5585 p = in.buf;
5586 i = in.nleft;
5587 if (i == 0)
5588 goto read;
5589 for (;;) {
5590 memtodest(p, i, syntax, quotes);
5591 read:
5592 if (in.fd < 0)
5593 break;
5594 i = nonblock_safe_read(in.fd, buf, sizeof(buf));
5595 TRACE(("expbackq: read returns %d\n", i));
5596 if (i <= 0)
5597 break;
5598 p = buf;
5599 }
5600
5601 free(in.buf);
5602 if (in.fd >= 0) {
5603 close(in.fd);
5604 back_exitstatus = waitforjob(in.jp);
5605 }
5606 INT_ON;
5607
5608 /* Eat all trailing newlines */
5609 dest = expdest;
5610 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
5611 STUNPUTC(dest);
5612 expdest = dest;
5613
5614 if (quoted == 0)
5615 recordregion(startloc, dest - (char *)stackblock(), 0);
5616 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
5617 (dest - (char *)stackblock()) - startloc,
5618 (dest - (char *)stackblock()) - startloc,
5619 stackblock() + startloc));
5620 }
5621
5622 #if ENABLE_ASH_MATH_SUPPORT
5623 /*
5624 * Expand arithmetic expression. Backup to start of expression,
5625 * evaluate, place result in (backed up) result, adjust string position.
5626 */
5627 static void
5628 expari(int quotes)
5629 {
5630 char *p, *start;
5631 int begoff;
5632 int flag;
5633 int len;
5634
5635 /* ifsfree(); */
5636
5637 /*
5638 * This routine is slightly over-complicated for
5639 * efficiency. Next we scan backwards looking for the
5640 * start of arithmetic.
5641 */
5642 start = stackblock();
5643 p = expdest - 1;
5644 *p = '\0';
5645 p--;
5646 do {
5647 int esc;
5648
5649 while (*p != CTLARI) {
5650 p--;
5651 #if DEBUG
5652 if (p < start) {
5653 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
5654 }
5655 #endif
5656 }
5657
5658 esc = esclen(start, p);
5659 if (!(esc % 2)) {
5660 break;
5661 }
5662
5663 p -= esc + 1;
5664 } while (1);
5665
5666 begoff = p - start;
5667
5668 removerecordregions(begoff);
5669
5670 flag = p[1];
5671
5672 expdest = p;
5673
5674 if (quotes)
5675 rmescapes(p + 2);
5676
5677 len = cvtnum(dash_arith(p + 2));
5678
5679 if (flag != '"')
5680 recordregion(begoff, begoff + len, 0);
5681 }
5682 #endif
5683
5684 /* argstr needs it */
5685 static char *evalvar(char *p, int flag, struct strlist *var_str_list);
5686
5687 /*
5688 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
5689 * characters to allow for further processing. Otherwise treat
5690 * $@ like $* since no splitting will be performed.
5691 *
5692 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
5693 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
5694 * for correct expansion of "B=$A" word.
5695 */
5696 static void
5697 argstr(char *p, int flag, struct strlist *var_str_list)
5698 {
5699 static const char spclchars[] ALIGN1 = {
5700 '=',
5701 ':',
5702 CTLQUOTEMARK,
5703 CTLENDVAR,
5704 CTLESC,
5705 CTLVAR,
5706 CTLBACKQ,
5707 CTLBACKQ | CTLQUOTE,
5708 #if ENABLE_ASH_MATH_SUPPORT
5709 CTLENDARI,
5710 #endif
5711 0
5712 };
5713 const char *reject = spclchars;
5714 int c;
5715 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
5716 int breakall = flag & EXP_WORD;
5717 int inquotes;
5718 size_t length;
5719 int startloc;
5720
5721 if (!(flag & EXP_VARTILDE)) {
5722 reject += 2;
5723 } else if (flag & EXP_VARTILDE2) {
5724 reject++;
5725 }
5726 inquotes = 0;
5727 length = 0;
5728 if (flag & EXP_TILDE) {
5729 char *q;
5730
5731 flag &= ~EXP_TILDE;
5732 tilde:
5733 q = p;
5734 if (*q == CTLESC && (flag & EXP_QWORD))
5735 q++;
5736 if (*q == '~')
5737 p = exptilde(p, q, flag);
5738 }
5739 start:
5740 startloc = expdest - (char *)stackblock();
5741 for (;;) {
5742 length += strcspn(p + length, reject);
5743 c = p[length];
5744 if (c && (!(c & 0x80)
5745 #if ENABLE_ASH_MATH_SUPPORT
5746 || c == CTLENDARI
5747 #endif
5748 )) {
5749 /* c == '=' || c == ':' || c == CTLENDARI */
5750 length++;
5751 }
5752 if (length > 0) {
5753 int newloc;
5754 expdest = stack_nputstr(p, length, expdest);
5755 newloc = expdest - (char *)stackblock();
5756 if (breakall && !inquotes && newloc > startloc) {
5757 recordregion(startloc, newloc, 0);
5758 }
5759 startloc = newloc;
5760 }
5761 p += length + 1;
5762 length = 0;
5763
5764 switch (c) {
5765 case '\0':
5766 goto breakloop;
5767 case '=':
5768 if (flag & EXP_VARTILDE2) {
5769 p--;
5770 continue;
5771 }
5772 flag |= EXP_VARTILDE2;
5773 reject++;
5774 /* fall through */
5775 case ':':
5776 /*
5777 * sort of a hack - expand tildes in variable
5778 * assignments (after the first '=' and after ':'s).
5779 */
5780 if (*--p == '~') {
5781 goto tilde;
5782 }
5783 continue;
5784 }
5785
5786 switch (c) {
5787 case CTLENDVAR: /* ??? */
5788 goto breakloop;
5789 case CTLQUOTEMARK:
5790 /* "$@" syntax adherence hack */
5791 if (
5792 !inquotes &&
5793 !memcmp(p, dolatstr, 4) &&
5794 (p[4] == CTLQUOTEMARK || (
5795 p[4] == CTLENDVAR &&
5796 p[5] == CTLQUOTEMARK
5797 ))
5798 ) {
5799 p = evalvar(p + 1, flag, /* var_str_list: */ NULL) + 1;
5800 goto start;
5801 }
5802 inquotes = !inquotes;
5803 addquote:
5804 if (quotes) {
5805 p--;
5806 length++;
5807 startloc++;
5808 }
5809 break;
5810 case CTLESC:
5811 startloc++;
5812 length++;
5813 goto addquote;
5814 case CTLVAR:
5815 p = evalvar(p, flag, var_str_list);
5816 goto start;
5817 case CTLBACKQ:
5818 c = 0;
5819 case CTLBACKQ|CTLQUOTE:
5820 expbackq(argbackq->n, c, quotes);
5821 argbackq = argbackq->next;
5822 goto start;
5823 #if ENABLE_ASH_MATH_SUPPORT
5824 case CTLENDARI:
5825 p--;
5826 expari(quotes);
5827 goto start;
5828 #endif
5829 }
5830 }
5831 breakloop:
5832 ;
5833 }
5834
5835 static char *
5836 scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM, char *str, int quotes,
5837 int zero)
5838 {
5839 // This commented out code was added by James Simmons <jsimmons@infradead.org>
5840 // as part of a larger change when he added support for ${var/a/b}.
5841 // However, it broke # and % operators:
5842 //
5843 //var=ababcdcd
5844 // ok bad
5845 //echo ${var#ab} abcdcd abcdcd
5846 //echo ${var##ab} abcdcd abcdcd
5847 //echo ${var#a*b} abcdcd ababcdcd (!)
5848 //echo ${var##a*b} cdcd cdcd
5849 //echo ${var#?} babcdcd ababcdcd (!)
5850 //echo ${var##?} babcdcd babcdcd
5851 //echo ${var#*} ababcdcd babcdcd (!)
5852 //echo ${var##*}
5853 //echo ${var%cd} ababcd ababcd
5854 //echo ${var%%cd} ababcd abab (!)
5855 //echo ${var%c*d} ababcd ababcd
5856 //echo ${var%%c*d} abab ababcdcd (!)
5857 //echo ${var%?} ababcdc ababcdc
5858 //echo ${var%%?} ababcdc ababcdcd (!)
5859 //echo ${var%*} ababcdcd ababcdcd
5860 //echo ${var%%*}
5861 //
5862 // Commenting it back out helped. Remove it completely if it really
5863 // is not needed.
5864
5865 char *loc, *loc2; //, *full;
5866 char c;
5867
5868 loc = startp;
5869 loc2 = rmesc;
5870 do {
5871 int match; // = strlen(str);
5872 const char *s = loc2;
5873
5874 c = *loc2;
5875 if (zero) {
5876 *loc2 = '\0';
5877 s = rmesc;
5878 }
5879 match = pmatch(str, s); // this line was deleted
5880
5881 // // chop off end if its '*'
5882 // full = strrchr(str, '*');
5883 // if (full && full != str)
5884 // match--;
5885 //
5886 // // If str starts with '*' replace with s.
5887 // if ((*str == '*') && strlen(s) >= match) {
5888 // full = xstrdup(s);
5889 // strncpy(full+strlen(s)-match+1, str+1, match-1);
5890 // } else
5891 // full = xstrndup(str, match);
5892 // match = strncmp(s, full, strlen(full));
5893 // free(full);
5894 //
5895 *loc2 = c;
5896 if (match) // if (!match)
5897 return loc;
5898 if (quotes && *loc == CTLESC)
5899 loc++;
5900 loc++;
5901 loc2++;
5902 } while (c);
5903 return 0;
5904 }
5905
5906 static char *
5907 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5908 int zero)
5909 {
5910 int esc = 0;
5911 char *loc;
5912 char *loc2;
5913
5914 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5915 int match;
5916 char c = *loc2;
5917 const char *s = loc2;
5918 if (zero) {
5919 *loc2 = '\0';
5920 s = rmesc;
5921 }
5922 match = pmatch(str, s);
5923 *loc2 = c;
5924 if (match)
5925 return loc;
5926 loc--;
5927 if (quotes) {
5928 if (--esc < 0) {
5929 esc = esclen(startp, loc);
5930 }
5931 if (esc % 2) {
5932 esc--;
5933 loc--;
5934 }
5935 }
5936 }
5937 return 0;
5938 }
5939
5940 static void varunset(const char *, const char *, const char *, int) NORETURN;
5941 static void
5942 varunset(const char *end, const char *var, const char *umsg, int varflags)
5943 {
5944 const char *msg;
5945 const char *tail;
5946
5947 tail = nullstr;
5948 msg = "parameter not set";
5949 if (umsg) {
5950 if (*end == CTLENDVAR) {
5951 if (varflags & VSNUL)
5952 tail = " or null";
5953 } else
5954 msg = umsg;
5955 }
5956 ash_msg_and_raise_error("%.*s: %s%s", end - var - 1, var, msg, tail);
5957 }
5958
5959 #if ENABLE_ASH_BASH_COMPAT
5960 static char *
5961 parse_sub_pattern(char *arg, int inquotes)
5962 {
5963 char *idx, *repl = NULL;
5964 unsigned char c;
5965
5966 idx = arg;
5967 while (1) {
5968 c = *arg;
5969 if (!c)
5970 break;
5971 if (c == '/') {
5972 /* Only the first '/' seen is our separator */
5973 if (!repl) {
5974 repl = idx + 1;
5975 c = '\0';
5976 }
5977 }
5978 *idx++ = c;
5979 if (!inquotes && c == '\\' && arg[1] == '\\')
5980 arg++; /* skip both \\, not just first one */
5981 arg++;
5982 }
5983 *idx = c; /* NUL */
5984
5985 return repl;
5986 }
5987 #endif /* ENABLE_ASH_BASH_COMPAT */
5988
5989 static const char *
5990 subevalvar(char *p, char *str, int strloc, int subtype,
5991 int startloc, int varflags, int quotes, struct strlist *var_str_list)
5992 {
5993 struct nodelist *saveargbackq = argbackq;
5994 char *startp;
5995 char *loc;
5996 char *rmesc, *rmescend;
5997 USE_ASH_BASH_COMPAT(char *repl = NULL;)
5998 USE_ASH_BASH_COMPAT(char null = '\0';)
5999 USE_ASH_BASH_COMPAT(int pos, len, orig_len;)
6000 int saveherefd = herefd;
6001 int amount, workloc, resetloc;
6002 int zero;
6003 char *(*scan)(char*, char*, char*, char*, int, int);
6004
6005 herefd = -1;
6006 argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0,
6007 var_str_list);
6008 STPUTC('\0', expdest);
6009 herefd = saveherefd;
6010 argbackq = saveargbackq;
6011 startp = (char *)stackblock() + startloc;
6012
6013 switch (subtype) {
6014 case VSASSIGN:
6015 setvar(str, startp, 0);
6016 amount = startp - expdest;
6017 STADJUST(amount, expdest);
6018 return startp;
6019
6020 #if ENABLE_ASH_BASH_COMPAT
6021 case VSSUBSTR:
6022 loc = str = stackblock() + strloc;
6023 // TODO: number() instead? It does error checking...
6024 pos = atoi(loc);
6025 len = str - startp - 1;
6026
6027 /* *loc != '\0', guaranteed by parser */
6028 if (quotes) {
6029 char *ptr;
6030
6031 /* We must adjust the length by the number of escapes we find. */
6032 for (ptr = startp; ptr < (str - 1); ptr++) {
6033 if (*ptr == CTLESC) {
6034 len--;
6035 ptr++;
6036 }
6037 }
6038 }
6039 orig_len = len;
6040
6041 if (*loc++ == ':') {
6042 // TODO: number() instead? It does error checking...
6043 len = atoi(loc);
6044 } else {
6045 len = orig_len;
6046 while (*loc && *loc != ':')
6047 loc++;
6048 if (*loc++ == ':')
6049 // TODO: number() instead? It does error checking...
6050 len = atoi(loc);
6051 }
6052 if (pos >= orig_len) {
6053 pos = 0;
6054 len = 0;
6055 }
6056 if (len > (orig_len - pos))
6057 len = orig_len - pos;
6058
6059 for (str = startp; pos; str++, pos--) {
6060 if (quotes && *str == CTLESC)
6061 str++;
6062 }
6063 for (loc = startp; len; len--) {
6064 if (quotes && *str == CTLESC)
6065 *loc++ = *str++;
6066 *loc++ = *str++;
6067 }
6068 *loc = '\0';
6069 amount = loc - expdest;
6070 STADJUST(amount, expdest);
6071 return loc;
6072 #endif
6073
6074 case VSQUESTION:
6075 varunset(p, str, startp, varflags);
6076 /* NOTREACHED */
6077 }
6078 resetloc = expdest - (char *)stackblock();
6079
6080 /* We'll comeback here if we grow the stack while handling
6081 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6082 * stack will need rebasing, and we'll need to remove our work
6083 * areas each time
6084 */
6085 USE_ASH_BASH_COMPAT(restart:)
6086
6087 amount = expdest - ((char *)stackblock() + resetloc);
6088 STADJUST(-amount, expdest);
6089 startp = (char *)stackblock() + startloc;
6090
6091 rmesc = startp;
6092 rmescend = (char *)stackblock() + strloc;
6093 if (quotes) {
6094 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
6095 if (rmesc != startp) {
6096 rmescend = expdest;
6097 startp = (char *)stackblock() + startloc;
6098 }
6099 }
6100 rmescend--;
6101 str = (char *)stackblock() + strloc;
6102 preglob(str, varflags & VSQUOTE, 0);
6103 workloc = expdest - (char *)stackblock();
6104
6105 #if ENABLE_ASH_BASH_COMPAT
6106 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
6107 char *idx, *end, *restart_detect;
6108
6109 if (!repl) {
6110 repl = parse_sub_pattern(str, varflags & VSQUOTE);
6111 if (!repl)
6112 repl = &null;
6113 }
6114
6115 /* If there's no pattern to match, return the expansion unmolested */
6116 if (*str == '\0')
6117 return 0;
6118
6119 len = 0;
6120 idx = startp;
6121 end = str - 1;
6122 while (idx < end) {
6123 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
6124 if (!loc) {
6125 /* No match, advance */
6126 restart_detect = stackblock();
6127 STPUTC(*idx, expdest);
6128 if (quotes && *idx == CTLESC) {
6129 idx++;
6130 len++;
6131 STPUTC(*idx, expdest);
6132 }
6133 if (stackblock() != restart_detect)
6134 goto restart;
6135 idx++;
6136 len++;
6137 rmesc++;
6138 continue;
6139 }
6140
6141 if (subtype == VSREPLACEALL) {
6142 while (idx < loc) {
6143 if (quotes && *idx == CTLESC)
6144 idx++;
6145 idx++;
6146 rmesc++;
6147 }
6148 } else
6149 idx = loc;
6150
6151 for (loc = repl; *loc; loc++) {
6152 restart_detect = stackblock();
6153 STPUTC(*loc, expdest);
6154 if (stackblock() != restart_detect)
6155 goto restart;
6156 len++;
6157 }
6158
6159 if (subtype == VSREPLACE) {
6160 while (*idx) {
6161 restart_detect = stackblock();
6162 STPUTC(*idx, expdest);
6163 if (stackblock() != restart_detect)
6164 goto restart;
6165 len++;
6166 idx++;
6167 }
6168 break;
6169 }
6170 }
6171
6172 /* We've put the replaced text into a buffer at workloc, now
6173 * move it to the right place and adjust the stack.
6174 */
6175 startp = stackblock() + startloc;
6176 STPUTC('\0', expdest);
6177 memmove(startp, stackblock() + workloc, len);
6178 startp[len++] = '\0';
6179 amount = expdest - ((char *)stackblock() + startloc + len - 1);
6180 STADJUST(-amount, expdest);
6181 return startp;
6182 }
6183 #endif /* ENABLE_ASH_BASH_COMPAT */
6184
6185 subtype -= VSTRIMRIGHT;
6186 #if DEBUG
6187 if (subtype < 0 || subtype > 7)
6188 abort();
6189 #endif
6190 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
6191 zero = subtype >> 1;
6192 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6193 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6194
6195 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6196 if (loc) {
6197 if (zero) {
6198 memmove(startp, loc, str - loc);
6199 loc = startp + (str - loc) - 1;
6200 }
6201 *loc = '\0';
6202 amount = loc - expdest;
6203 STADJUST(amount, expdest);
6204 }
6205 return loc;
6206 }
6207
6208 /*
6209 * Add the value of a specialized variable to the stack string.
6210 */
6211 static ssize_t
6212 varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
6213 {
6214 int num;
6215 char *p;
6216 int i;
6217 int sep = 0;
6218 int sepq = 0;
6219 ssize_t len = 0;
6220 char **ap;
6221 int syntax;
6222 int quoted = varflags & VSQUOTE;
6223 int subtype = varflags & VSTYPE;
6224 int quotes = flags & (EXP_FULL | EXP_CASE);
6225
6226 if (quoted && (flags & EXP_FULL))
6227 sep = 1 << CHAR_BIT;
6228
6229 syntax = quoted ? DQSYNTAX : BASESYNTAX;
6230 switch (*name) {
6231 case '$':
6232 num = rootpid;
6233 goto numvar;
6234 case '?':
6235 num = exitstatus;
6236 goto numvar;
6237 case '#':
6238 num = shellparam.nparam;
6239 goto numvar;
6240 case '!':
6241 num = backgndpid;
6242 if (num == 0)
6243 return -1;
6244 numvar:
6245 len = cvtnum(num);
6246 break;
6247 case '-':
6248 p = makestrspace(NOPTS, expdest);
6249 for (i = NOPTS - 1; i >= 0; i--) {
6250 if (optlist[i]) {
6251 USTPUTC(optletters(i), p);
6252 len++;
6253 }
6254 }
6255 expdest = p;
6256 break;
6257 case '@':
6258 if (sep)
6259 goto param;
6260 /* fall through */
6261 case '*':
6262 sep = ifsset() ? signed_char2int(ifsval()[0]) : ' ';
6263 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
6264 sepq = 1;
6265 param:
6266 ap = shellparam.p;
6267 if (!ap)
6268 return -1;
6269 while ((p = *ap++)) {
6270 size_t partlen;
6271
6272 partlen = strlen(p);
6273 len += partlen;
6274
6275 if (!(subtype == VSPLUS || subtype == VSLENGTH))
6276 memtodest(p, partlen, syntax, quotes);
6277
6278 if (*ap && sep) {
6279 char *q;
6280
6281 len++;
6282 if (subtype == VSPLUS || subtype == VSLENGTH) {
6283 continue;
6284 }
6285 q = expdest;
6286 if (sepq)
6287 STPUTC(CTLESC, q);
6288 STPUTC(sep, q);
6289 expdest = q;
6290 }
6291 }
6292 return len;
6293 case '0':
6294 case '1':
6295 case '2':
6296 case '3':
6297 case '4':
6298 case '5':
6299 case '6':
6300 case '7':
6301 case '8':
6302 case '9':
6303 // TODO: number() instead? It does error checking...
6304 num = atoi(name);
6305 if (num < 0 || num > shellparam.nparam)
6306 return -1;
6307 p = num ? shellparam.p[num - 1] : arg0;
6308 goto value;
6309 default:
6310 /* NB: name has form "VAR=..." */
6311
6312 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6313 * which should be considered before we check variables. */
6314 if (var_str_list) {
6315 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6316 p = NULL;
6317 do {
6318 char *str, *eq;
6319 str = var_str_list->text;
6320 eq = strchr(str, '=');
6321 if (!eq) /* stop at first non-assignment */
6322 break;
6323 eq++;
6324 if (name_len == (unsigned)(eq - str)
6325 && strncmp(str, name, name_len) == 0) {
6326 p = eq;
6327 /* goto value; - WRONG! */
6328 /* think "A=1 A=2 B=$A" */
6329 }
6330 var_str_list = var_str_list->next;
6331 } while (var_str_list);
6332 if (p)
6333 goto value;
6334 }
6335 p = lookupvar(name);
6336 value:
6337 if (!p)
6338 return -1;
6339
6340 len = strlen(p);
6341 if (!(subtype == VSPLUS || subtype == VSLENGTH))
6342 memtodest(p, len, syntax, quotes);
6343 return len;
6344 }
6345
6346 if (subtype == VSPLUS || subtype == VSLENGTH)
6347 STADJUST(-len, expdest);
6348 return len;
6349 }
6350
6351 /*
6352 * Expand a variable, and return a pointer to the next character in the
6353 * input string.
6354 */
6355 static char *
6356 evalvar(char *p, int flag, struct strlist *var_str_list)
6357 {
6358 char varflags;
6359 char subtype;
6360 char quoted;
6361 char easy;
6362 char *var;
6363 int patloc;
6364 int startloc;
6365 ssize_t varlen;
6366
6367 varflags = *p++;
6368 subtype = varflags & VSTYPE;
6369 quoted = varflags & VSQUOTE;
6370 var = p;
6371 easy = (!quoted || (*var == '@' && shellparam.nparam));
6372 startloc = expdest - (char *)stackblock();
6373 p = strchr(p, '=') + 1;
6374
6375 again:
6376 varlen = varvalue(var, varflags, flag, var_str_list);
6377 if (varflags & VSNUL)
6378 varlen--;
6379
6380 if (subtype == VSPLUS) {
6381 varlen = -1 - varlen;
6382 goto vsplus;
6383 }
6384
6385 if (subtype == VSMINUS) {
6386 vsplus:
6387 if (varlen < 0) {
6388 argstr(
6389 p, flag | EXP_TILDE |
6390 (quoted ? EXP_QWORD : EXP_WORD),
6391 var_str_list
6392 );
6393 goto end;
6394 }
6395 if (easy)
6396 goto record;
6397 goto end;
6398 }
6399
6400 if (subtype == VSASSIGN || subtype == VSQUESTION) {
6401 if (varlen < 0) {
6402 if (subevalvar(p, var, /* strloc: */ 0,
6403 subtype, startloc, varflags,
6404 /* quotes: */ 0,
6405 var_str_list)
6406 ) {
6407 varflags &= ~VSNUL;
6408 /*
6409 * Remove any recorded regions beyond
6410 * start of variable
6411 */
6412 removerecordregions(startloc);
6413 goto again;
6414 }
6415 goto end;
6416 }
6417 if (easy)
6418 goto record;
6419 goto end;
6420 }
6421
6422 if (varlen < 0 && uflag)
6423 varunset(p, var, 0, 0);
6424
6425 if (subtype == VSLENGTH) {
6426 cvtnum(varlen > 0 ? varlen : 0);
6427 goto record;
6428 }
6429
6430 if (subtype == VSNORMAL) {
6431 if (easy)
6432 goto record;
6433 goto end;
6434 }
6435
6436 #if DEBUG
6437 switch (subtype) {
6438 case VSTRIMLEFT:
6439 case VSTRIMLEFTMAX:
6440 case VSTRIMRIGHT:
6441 case VSTRIMRIGHTMAX:
6442 #if ENABLE_ASH_BASH_COMPAT
6443 case VSSUBSTR:
6444 case VSREPLACE:
6445 case VSREPLACEALL:
6446 #endif
6447 break;
6448 default:
6449 abort();
6450 }
6451 #endif
6452
6453 if (varlen >= 0) {
6454 /*
6455 * Terminate the string and start recording the pattern
6456 * right after it
6457 */
6458 STPUTC('\0', expdest);
6459 patloc = expdest - (char *)stackblock();
6460 if (0 == subevalvar(p, /* str: */ NULL, patloc, subtype,
6461 startloc, varflags,
6462 /* quotes: */ flag & (EXP_FULL | EXP_CASE),
6463 var_str_list)
6464 ) {
6465 int amount = expdest - (
6466 (char *)stackblock() + patloc - 1
6467 );
6468 STADJUST(-amount, expdest);
6469 }
6470 /* Remove any recorded regions beyond start of variable */
6471 removerecordregions(startloc);
6472 record:
6473 recordregion(startloc, expdest - (char *)stackblock(), quoted);
6474 }
6475
6476 end:
6477 if (subtype != VSNORMAL) { /* skip to end of alternative */
6478 int nesting = 1;
6479 for (;;) {
6480 char c = *p++;
6481 if (c == CTLESC)
6482 p++;
6483 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
6484 if (varlen >= 0)
6485 argbackq = argbackq->next;
6486 } else if (c == CTLVAR) {
6487 if ((*p++ & VSTYPE) != VSNORMAL)
6488 nesting++;
6489 } else if (c == CTLENDVAR) {
6490 if (--nesting == 0)
6491 break;
6492 }
6493 }
6494 }
6495 return p;
6496 }
6497
6498 /*
6499 * Break the argument string into pieces based upon IFS and add the
6500 * strings to the argument list. The regions of the string to be
6501 * searched for IFS characters have been stored by recordregion.
6502 */
6503 static void
6504 ifsbreakup(char *string, struct arglist *arglist)
6505 {
6506 struct ifsregion *ifsp;
6507 struct strlist *sp;
6508 char *start;
6509 char *p;
6510 char *q;
6511 const char *ifs, *realifs;
6512 int ifsspc;
6513 int nulonly;
6514
6515 start = string;
6516 if (ifslastp != NULL) {
6517 ifsspc = 0;
6518 nulonly = 0;
6519 realifs = ifsset() ? ifsval() : defifs;
6520 ifsp = &ifsfirst;
6521 do {
6522 p = string + ifsp->begoff;
6523 nulonly = ifsp->nulonly;
6524 ifs = nulonly ? nullstr : realifs;
6525 ifsspc = 0;
6526 while (p < string + ifsp->endoff) {
6527 q = p;
6528 if (*p == CTLESC)
6529 p++;
6530 if (!strchr(ifs, *p)) {
6531 p++;
6532 continue;
6533 }
6534 if (!nulonly)
6535 ifsspc = (strchr(defifs, *p) != NULL);
6536 /* Ignore IFS whitespace at start */
6537 if (q == start && ifsspc) {
6538 p++;
6539 start = p;
6540 continue;
6541 }
6542 *q = '\0';
6543 sp = stzalloc(sizeof(*sp));
6544 sp->text = start;
6545 *arglist->lastp = sp;
6546 arglist->lastp = &sp->next;
6547 p++;
6548 if (!nulonly) {
6549 for (;;) {
6550 if (p >= string + ifsp->endoff) {
6551 break;
6552 }
6553 q = p;
6554 if (*p == CTLESC)
6555 p++;
6556 if (strchr(ifs, *p) == NULL) {
6557 p = q;
6558 break;
6559 }
6560 if (strchr(defifs, *p) == NULL) {
6561 if (ifsspc) {
6562 p++;
6563 ifsspc = 0;
6564 } else {
6565 p = q;
6566 break;
6567 }
6568 } else
6569 p++;
6570 }
6571 }
6572 start = p;
6573 } /* while */
6574 ifsp = ifsp->next;
6575 } while (ifsp != NULL);
6576 if (nulonly)
6577 goto add;
6578 }
6579
6580 if (!*start)
6581 return;
6582
6583 add:
6584 sp = stzalloc(sizeof(*sp));
6585 sp->text = start;
6586 *arglist->lastp = sp;
6587 arglist->lastp = &sp->next;
6588 }
6589
6590 static void
6591 ifsfree(void)
6592 {
6593 struct ifsregion *p;
6594
6595 INT_OFF;
6596 p = ifsfirst.next;
6597 do {
6598 struct ifsregion *ifsp;
6599 ifsp = p->next;
6600 free(p);
6601 p = ifsp;
6602 } while (p);
6603 ifslastp = NULL;
6604 ifsfirst.next = NULL;
6605 INT_ON;
6606 }
6607
6608 /*
6609 * Add a file name to the list.
6610 */
6611 static void
6612 addfname(const char *name)
6613 {
6614 struct strlist *sp;
6615
6616 sp = stzalloc(sizeof(*sp));
6617 sp->text = ststrdup(name);
6618 *exparg.lastp = sp;
6619 exparg.lastp = &sp->next;
6620 }
6621
6622 static char *expdir;
6623
6624 /*
6625 * Do metacharacter (i.e. *, ?, [...]) expansion.
6626 */
6627 static void
6628 expmeta(char *enddir, char *name)
6629 {
6630 char *p;
6631 const char *cp;
6632 char *start;
6633 char *endname;
6634 int metaflag;
6635 struct stat statb;
6636 DIR *dirp;
6637 struct dirent *dp;
6638 int atend;
6639 int matchdot;
6640
6641 metaflag = 0;
6642 start = name;
6643 for (p = name; *p; p++) {
6644 if (*p == '*' || *p == '?')
6645 metaflag = 1;
6646 else if (*p == '[') {
6647 char *q = p + 1;
6648 if (*q == '!')
6649 q++;
6650 for (;;) {
6651 if (*q == '\\')
6652 q++;
6653 if (*q == '/' || *q == '\0')
6654 break;
6655 if (*++q == ']') {
6656 metaflag = 1;
6657 break;
6658 }
6659 }
6660 } else if (*p == '\\')
6661 p++;
6662 else if (*p == '/') {
6663 if (metaflag)
6664 goto out;
6665 start = p + 1;
6666 }
6667 }
6668 out:
6669 if (metaflag == 0) { /* we've reached the end of the file name */
6670 if (enddir != expdir)
6671 metaflag++;
6672 p = name;
6673 do {
6674 if (*p == '\\')
6675 p++;
6676 *enddir++ = *p;
6677 } while (*p++);
6678 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
6679 addfname(expdir);
6680 return;
6681 }
6682 endname = p;
6683 if (name < start) {
6684 p = name;
6685 do {
6686 if (*p == '\\')
6687 p++;
6688 *enddir++ = *p++;
6689 } while (p < start);
6690 }
6691 if (enddir == expdir) {
6692 cp = ".";
6693 } else if (enddir == expdir + 1 && *expdir == '/') {
6694 cp = "/";
6695 } else {
6696 cp = expdir;
6697 enddir[-1] = '\0';
6698 }
6699 dirp = opendir(cp);
6700 if (dirp == NULL)
6701 return;
6702 if (enddir != expdir)
6703 enddir[-1] = '/';
6704 if (*endname == 0) {
6705 atend = 1;
6706 } else {
6707 atend = 0;
6708 *endname++ = '\0';
6709 }
6710 matchdot = 0;
6711 p = start;
6712 if (*p == '\\')
6713 p++;
6714 if (*p == '.')
6715 matchdot++;
6716 while (!intpending && (dp = readdir(dirp)) != NULL) {
6717 if (dp->d_name[0] == '.' && !matchdot)
6718 continue;
6719 if (pmatch(start, dp->d_name)) {
6720 if (atend) {
6721 strcpy(enddir, dp->d_name);
6722 addfname(expdir);
6723 } else {
6724 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
6725 continue;
6726 p[-1] = '/';
6727 expmeta(p, endname);
6728 }
6729 }
6730 }
6731 closedir(dirp);
6732 if (!atend)
6733 endname[-1] = '/';
6734 }
6735
6736 static struct strlist *
6737 msort(struct strlist *list, int len)
6738 {
6739 struct strlist *p, *q = NULL;
6740 struct strlist **lpp;
6741 int half;
6742 int n;
6743
6744 if (len <= 1)
6745 return list;
6746 half = len >> 1;
6747 p = list;
6748 for (n = half; --n >= 0;) {
6749 q = p;
6750 p = p->next;
6751 }
6752 q->next = NULL; /* terminate first half of list */
6753 q = msort(list, half); /* sort first half of list */
6754 p = msort(p, len - half); /* sort second half */
6755 lpp = &list;
6756 for (;;) {
6757 #if ENABLE_LOCALE_SUPPORT
6758 if (strcoll(p->text, q->text) < 0)
6759 #else
6760 if (strcmp(p->text, q->text) < 0)
6761 #endif
6762 {
6763 *lpp = p;
6764 lpp = &p->next;
6765 p = *lpp;
6766 if (p == NULL) {
6767 *lpp = q;
6768 break;
6769 }
6770 } else {
6771 *lpp = q;
6772 lpp = &q->next;
6773 q = *lpp;
6774 if (q == NULL) {
6775 *lpp = p;
6776 break;
6777 }
6778 }
6779 }
6780 return list;
6781 }
6782
6783 /*
6784 * Sort the results of file name expansion. It calculates the number of
6785 * strings to sort and then calls msort (short for merge sort) to do the
6786 * work.
6787 */
6788 static struct strlist *
6789 expsort(struct strlist *str)
6790 {
6791 int len;
6792 struct strlist *sp;
6793
6794 len = 0;
6795 for (sp = str; sp; sp = sp->next)
6796 len++;
6797 return msort(str, len);
6798 }
6799
6800 static void
6801 expandmeta(struct strlist *str /*, int flag*/)
6802 {
6803 static const char metachars[] ALIGN1 = {
6804 '*', '?', '[', 0
6805 };
6806 /* TODO - EXP_REDIR */
6807
6808 while (str) {
6809 struct strlist **savelastp;
6810 struct strlist *sp;
6811 char *p;
6812
6813 if (fflag)
6814 goto nometa;
6815 if (!strpbrk(str->text, metachars))
6816 goto nometa;
6817 savelastp = exparg.lastp;
6818
6819 INT_OFF;
6820 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
6821 {
6822 int i = strlen(str->text);
6823 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
6824 }
6825
6826 expmeta(expdir, p);
6827 free(expdir);
6828 if (p != str->text)
6829 free(p);
6830 INT_ON;
6831 if (exparg.lastp == savelastp) {
6832 /*
6833 * no matches
6834 */
6835 nometa:
6836 *exparg.lastp = str;
6837 rmescapes(str->text);
6838 exparg.lastp = &str->next;
6839 } else {
6840 *exparg.lastp = NULL;
6841 *savelastp = sp = expsort(*savelastp);
6842 while (sp->next != NULL)
6843 sp = sp->next;
6844 exparg.lastp = &sp->next;
6845 }
6846 str = str->next;
6847 }
6848 }
6849
6850 /*
6851 * Perform variable substitution and command substitution on an argument,
6852 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
6853 * perform splitting and file name expansion. When arglist is NULL, perform
6854 * here document expansion.
6855 */
6856 static void
6857 expandarg(union node *arg, struct arglist *arglist, int flag)
6858 {
6859 struct strlist *sp;
6860 char *p;
6861
6862 argbackq = arg->narg.backquote;
6863 STARTSTACKSTR(expdest);
6864 ifsfirst.next = NULL;
6865 ifslastp = NULL;
6866 argstr(arg->narg.text, flag,
6867 /* var_str_list: */ arglist ? arglist->list : NULL);
6868 p = _STPUTC('\0', expdest);
6869 expdest = p - 1;
6870 if (arglist == NULL) {
6871 return; /* here document expanded */
6872 }
6873 p = grabstackstr(p);
6874 exparg.lastp = &exparg.list;
6875 /*
6876 * TODO - EXP_REDIR
6877 */
6878 if (flag & EXP_FULL) {
6879 ifsbreakup(p, &exparg);
6880 *exparg.lastp = NULL;
6881 exparg.lastp = &exparg.list;
6882 expandmeta(exparg.list /*, flag*/);
6883 } else {
6884 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
6885 rmescapes(p);
6886 sp = stzalloc(sizeof(*sp));
6887 sp->text = p;
6888 *exparg.lastp = sp;
6889 exparg.lastp = &sp->next;
6890 }
6891 if (ifsfirst.next)
6892 ifsfree();
6893 *exparg.lastp = NULL;
6894 if (exparg.list) {
6895 *arglist->lastp = exparg.list;
6896 arglist->lastp = exparg.lastp;
6897 }
6898 }
6899
6900 /*
6901 * Expand shell variables and backquotes inside a here document.
6902 */
6903 static void
6904 expandhere(union node *arg, int fd)
6905 {
6906 herefd = fd;
6907 expandarg(arg, (struct arglist *)NULL, 0);
6908 full_write(fd, stackblock(), expdest - (char *)stackblock());
6909 }
6910
6911 /*
6912 * Returns true if the pattern matches the string.
6913 */
6914 static int
6915 patmatch(char *pattern, const char *string)
6916 {
6917 return pmatch(preglob(pattern, 0, 0), string);
6918 }
6919
6920 /*
6921 * See if a pattern matches in a case statement.
6922 */
6923 static int
6924 casematch(union node *pattern, char *val)
6925 {
6926 struct stackmark smark;
6927 int result;
6928
6929 setstackmark(&smark);
6930 argbackq = pattern->narg.backquote;
6931 STARTSTACKSTR(expdest);
6932 ifslastp = NULL;
6933 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
6934 /* var_str_list: */ NULL);
6935 STACKSTRNUL(expdest);
6936 result = patmatch(stackblock(), val);
6937 popstackmark(&smark);
6938 return result;
6939 }
6940
6941
6942 /* ============ find_command */
6943
6944 struct builtincmd {
6945 const char *name;
6946 int (*builtin)(int, char **);
6947 /* unsigned flags; */
6948 };
6949 #define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
6950 /* "regular" builtins always take precedence over commands,
6951 * regardless of PATH=....%builtin... position */
6952 #define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
6953 #define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
6954
6955 struct cmdentry {
6956 smallint cmdtype; /* CMDxxx */
6957 union param {
6958 int index;
6959 /* index >= 0 for commands without path (slashes) */
6960 /* (TODO: what exactly does the value mean? PATH position?) */
6961 /* index == -1 for commands with slashes */
6962 /* index == (-2 - applet_no) for NOFORK applets */
6963 const struct builtincmd *cmd;
6964 struct funcnode *func;
6965 } u;
6966 };
6967 /* values of cmdtype */
6968 #define CMDUNKNOWN -1 /* no entry in table for command */
6969 #define CMDNORMAL 0 /* command is an executable program */
6970 #define CMDFUNCTION 1 /* command is a shell function */
6971 #define CMDBUILTIN 2 /* command is a shell builtin */
6972
6973 /* action to find_command() */
6974 #define DO_ERR 0x01 /* prints errors */
6975 #define DO_ABS 0x02 /* checks absolute paths */
6976 #define DO_NOFUNC 0x04 /* don't return shell functions, for command */
6977 #define DO_ALTPATH 0x08 /* using alternate path */
6978 #define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
6979
6980 static void find_command(char *, struct cmdentry *, int, const char *);
6981
6982
6983 /* ============ Hashing commands */
6984
6985 /*
6986 * When commands are first encountered, they are entered in a hash table.
6987 * This ensures that a full path search will not have to be done for them
6988 * on each invocation.
6989 *
6990 * We should investigate converting to a linear search, even though that
6991 * would make the command name "hash" a misnomer.
6992 */
6993
6994 struct tblentry {
6995 struct tblentry *next; /* next entry in hash chain */
6996 union param param; /* definition of builtin function */
6997 smallint cmdtype; /* CMDxxx */
6998 char rehash; /* if set, cd done since entry created */
6999 char cmdname[1]; /* name of command */
7000 };
7001
7002 static struct tblentry **cmdtable;
7003 #define INIT_G_cmdtable() do { \
7004 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7005 } while (0)
7006
7007 static int builtinloc = -1; /* index in path of %builtin, or -1 */
7008
7009
7010 static void
7011 tryexec(USE_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
7012 {
7013 int repeated = 0;
7014
7015 #if ENABLE_FEATURE_SH_STANDALONE
7016 if (applet_no >= 0) {
7017 if (APPLET_IS_NOEXEC(applet_no)) {
7018 while (*envp)
7019 putenv(*envp++);
7020 run_applet_no_and_exit(applet_no, argv);
7021 }
7022 /* re-exec ourselves with the new arguments */
7023 execve(bb_busybox_exec_path, argv, envp);
7024 /* If they called chroot or otherwise made the binary no longer
7025 * executable, fall through */
7026 }
7027 #endif
7028
7029 repeat:
7030 #ifdef SYSV
7031 do {
7032 execve(cmd, argv, envp);
7033 } while (errno == EINTR);
7034 #else
7035 execve(cmd, argv, envp);
7036 #endif
7037 if (repeated) {
7038 free(argv);
7039 return;
7040 }
7041 if (errno == ENOEXEC) {
7042 char **ap;
7043 char **new;
7044
7045 for (ap = argv; *ap; ap++)
7046 continue;
7047 ap = new = ckmalloc((ap - argv + 2) * sizeof(ap[0]));
7048 ap[1] = cmd;
7049 ap[0] = cmd = (char *)DEFAULT_SHELL;
7050 ap += 2;
7051 argv++;
7052 while ((*ap++ = *argv++) != NULL)
7053 continue;
7054 argv = new;
7055 repeated++;
7056 goto repeat;
7057 }
7058 }
7059
7060 /*
7061 * Exec a program. Never returns. If you change this routine, you may
7062 * have to change the find_command routine as well.
7063 */
7064 static void shellexec(char **, const char *, int) NORETURN;
7065 static void
7066 shellexec(char **argv, const char *path, int idx)
7067 {
7068 char *cmdname;
7069 int e;
7070 char **envp;
7071 int exerrno;
7072 #if ENABLE_FEATURE_SH_STANDALONE
7073 int applet_no = -1;
7074 #endif
7075
7076 clearredir(/*drop:*/ 1);
7077 envp = listvars(VEXPORT, VUNSET, 0);
7078 if (strchr(argv[0], '/') != NULL
7079 #if ENABLE_FEATURE_SH_STANDALONE
7080 || (applet_no = find_applet_by_name(argv[0])) >= 0
7081 #endif
7082 ) {
7083 tryexec(USE_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
7084 e = errno;
7085 } else {
7086 e = ENOENT;
7087 while ((cmdname = padvance(&path, argv[0])) != NULL) {
7088 if (--idx < 0 && pathopt == NULL) {
7089 tryexec(USE_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
7090 if (errno != ENOENT && errno != ENOTDIR)
7091 e = errno;
7092 }
7093 stunalloc(cmdname);
7094 }
7095 }
7096
7097 /* Map to POSIX errors */
7098 switch (e) {
7099 case EACCES:
7100 exerrno = 126;
7101 break;
7102 case ENOENT:
7103 exerrno = 127;
7104 break;
7105 default:
7106 exerrno = 2;
7107 break;
7108 }
7109 exitstatus = exerrno;
7110 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
7111 argv[0], e, suppressint));
7112 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
7113 /* NOTREACHED */
7114 }
7115
7116 static void
7117 printentry(struct tblentry *cmdp)
7118 {
7119 int idx;
7120 const char *path;
7121 char *name;
7122
7123 idx = cmdp->param.index;
7124 path = pathval();
7125 do {
7126 name = padvance(&path, cmdp->cmdname);
7127 stunalloc(name);
7128 } while (--idx >= 0);
7129 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7130 }
7131
7132 /*
7133 * Clear out command entries. The argument specifies the first entry in
7134 * PATH which has changed.
7135 */
7136 static void
7137 clearcmdentry(int firstchange)
7138 {
7139 struct tblentry **tblp;
7140 struct tblentry **pp;
7141 struct tblentry *cmdp;
7142
7143 INT_OFF;
7144 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7145 pp = tblp;
7146 while ((cmdp = *pp) != NULL) {
7147 if ((cmdp->cmdtype == CMDNORMAL &&
7148 cmdp->param.index >= firstchange)
7149 || (cmdp->cmdtype == CMDBUILTIN &&
7150 builtinloc >= firstchange)
7151 ) {
7152 *pp = cmdp->next;
7153 free(cmdp);
7154 } else {
7155 pp = &cmdp->next;
7156 }
7157 }
7158 }
7159 INT_ON;
7160 }
7161
7162 /*
7163 * Locate a command in the command hash table. If "add" is nonzero,
7164 * add the command to the table if it is not already present. The
7165 * variable "lastcmdentry" is set to point to the address of the link
7166 * pointing to the entry, so that delete_cmd_entry can delete the
7167 * entry.
7168 *
7169 * Interrupts must be off if called with add != 0.
7170 */
7171 static struct tblentry **lastcmdentry;
7172
7173 static struct tblentry *
7174 cmdlookup(const char *name, int add)
7175 {
7176 unsigned int hashval;
7177 const char *p;
7178 struct tblentry *cmdp;
7179 struct tblentry **pp;
7180
7181 p = name;
7182 hashval = (unsigned char)*p << 4;
7183 while (*p)
7184 hashval += (unsigned char)*p++;
7185 hashval &= 0x7FFF;
7186 pp = &cmdtable[hashval % CMDTABLESIZE];
7187 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7188 if (strcmp(cmdp->cmdname, name) == 0)
7189 break;
7190 pp = &cmdp->next;
7191 }
7192 if (add && cmdp == NULL) {
7193 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7194 + strlen(name)
7195 /* + 1 - already done because
7196 * tblentry::cmdname is char[1] */);
7197 /*cmdp->next = NULL; - ckzalloc did it */
7198 cmdp->cmdtype = CMDUNKNOWN;
7199 strcpy(cmdp->cmdname, name);
7200 }
7201 lastcmdentry = pp;
7202 return cmdp;
7203 }
7204
7205 /*
7206 * Delete the command entry returned on the last lookup.
7207 */
7208 static void
7209 delete_cmd_entry(void)
7210 {
7211 struct tblentry *cmdp;
7212
7213 INT_OFF;
7214 cmdp = *lastcmdentry;
7215 *lastcmdentry = cmdp->next;
7216 if (cmdp->cmdtype == CMDFUNCTION)
7217 freefunc(cmdp->param.func);
7218 free(cmdp);
7219 INT_ON;
7220 }
7221
7222 /*
7223 * Add a new command entry, replacing any existing command entry for
7224 * the same name - except special builtins.
7225 */
7226 static void
7227 addcmdentry(char *name, struct cmdentry *entry)
7228 {
7229 struct tblentry *cmdp;
7230
7231 cmdp = cmdlookup(name, 1);
7232 if (cmdp->cmdtype == CMDFUNCTION) {
7233 freefunc(cmdp->param.func);
7234 }
7235 cmdp->cmdtype = entry->cmdtype;
7236 cmdp->param = entry->u;
7237 cmdp->rehash = 0;
7238 }
7239
7240 static int
7241 hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
7242 {
7243 struct tblentry **pp;
7244 struct tblentry *cmdp;
7245 int c;
7246 struct cmdentry entry;
7247 char *name;
7248
7249 if (nextopt("r") != '\0') {
7250 clearcmdentry(0);
7251 return 0;
7252 }
7253
7254 if (*argptr == NULL) {
7255 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7256 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7257 if (cmdp->cmdtype == CMDNORMAL)
7258 printentry(cmdp);
7259 }
7260 }
7261 return 0;
7262 }
7263
7264 c = 0;
7265 while ((name = *argptr) != NULL) {
7266 cmdp = cmdlookup(name, 0);
7267 if (cmdp != NULL
7268 && (cmdp->cmdtype == CMDNORMAL
7269 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7270 ) {
7271 delete_cmd_entry();
7272 }
7273 find_command(name, &entry, DO_ERR, pathval());
7274 if (entry.cmdtype == CMDUNKNOWN)
7275 c = 1;
7276 argptr++;
7277 }
7278 return c;
7279 }
7280
7281 /*
7282 * Called when a cd is done. Marks all commands so the next time they
7283 * are executed they will be rehashed.
7284 */
7285 static void
7286 hashcd(void)
7287 {
7288 struct tblentry **pp;
7289 struct tblentry *cmdp;
7290
7291 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7292 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7293 if (cmdp->cmdtype == CMDNORMAL
7294 || (cmdp->cmdtype == CMDBUILTIN
7295 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
7296 && builtinloc > 0)
7297 ) {
7298 cmdp->rehash = 1;
7299 }
7300 }
7301 }
7302 }
7303
7304 /*
7305 * Fix command hash table when PATH changed.
7306 * Called before PATH is changed. The argument is the new value of PATH;
7307 * pathval() still returns the old value at this point.
7308 * Called with interrupts off.
7309 */
7310 static void
7311 changepath(const char *new)
7312 {
7313 const char *old;
7314 int firstchange;
7315 int idx;
7316 int idx_bltin;
7317
7318 old = pathval();
7319 firstchange = 9999; /* assume no change */
7320 idx = 0;
7321 idx_bltin = -1;
7322 for (;;) {
7323 if (*old != *new) {
7324 firstchange = idx;
7325 if ((*old == '\0' && *new == ':')
7326 || (*old == ':' && *new == '\0'))
7327 firstchange++;
7328 old = new; /* ignore subsequent differences */
7329 }
7330 if (*new == '\0')
7331 break;
7332 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7333 idx_bltin = idx;
7334 if (*new == ':')
7335 idx++;
7336 new++, old++;
7337 }
7338 if (builtinloc < 0 && idx_bltin >= 0)
7339 builtinloc = idx_bltin; /* zap builtins */
7340 if (builtinloc >= 0 && idx_bltin < 0)
7341 firstchange = 0;
7342 clearcmdentry(firstchange);
7343 builtinloc = idx_bltin;
7344 }
7345
7346 #define TEOF 0
7347 #define TNL 1
7348 #define TREDIR 2
7349 #define TWORD 3
7350 #define TSEMI 4
7351 #define TBACKGND 5
7352 #define TAND 6
7353 #define TOR 7
7354 #define TPIPE 8
7355 #define TLP 9
7356 #define TRP 10
7357 #define TENDCASE 11
7358 #define TENDBQUOTE 12
7359 #define TNOT 13
7360 #define TCASE 14
7361 #define TDO 15
7362 #define TDONE 16
7363 #define TELIF 17
7364 #define TELSE 18
7365 #define TESAC 19
7366 #define TFI 20
7367 #define TFOR 21
7368 #define TIF 22
7369 #define TIN 23
7370 #define TTHEN 24
7371 #define TUNTIL 25
7372 #define TWHILE 26
7373 #define TBEGIN 27
7374 #define TEND 28
7375 typedef smallint token_id_t;
7376
7377 /* first char is indicating which tokens mark the end of a list */
7378 static const char *const tokname_array[] = {
7379 "\1end of file",
7380 "\0newline",
7381 "\0redirection",
7382 "\0word",
7383 "\0;",
7384 "\0&",
7385 "\0&&",
7386 "\0||",
7387 "\0|",
7388 "\0(",
7389 "\1)",
7390 "\1;;",
7391 "\1`",
7392 #define KWDOFFSET 13
7393 /* the following are keywords */
7394 "\0!",
7395 "\0case",
7396 "\1do",
7397 "\1done",
7398 "\1elif",
7399 "\1else",
7400 "\1esac",
7401 "\1fi",
7402 "\0for",
7403 "\0if",
7404 "\0in",
7405 "\1then",
7406 "\0until",
7407 "\0while",
7408 "\0{",
7409 "\1}",
7410 };
7411
7412 static const char *
7413 tokname(int tok)
7414 {
7415 static char buf[16];
7416
7417 //try this:
7418 //if (tok < TSEMI) return tokname_array[tok] + 1;
7419 //sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
7420 //return buf;
7421
7422 if (tok >= TSEMI)
7423 buf[0] = '"';
7424 sprintf(buf + (tok >= TSEMI), "%s%c",
7425 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
7426 return buf;
7427 }
7428
7429 /* Wrapper around strcmp for qsort/bsearch/... */
7430 static int
7431 pstrcmp(const void *a, const void *b)
7432 {
7433 return strcmp((char*) a, (*(char**) b) + 1);
7434 }
7435
7436 static const char *const *
7437 findkwd(const char *s)
7438 {
7439 return bsearch(s, tokname_array + KWDOFFSET,
7440 ARRAY_SIZE(tokname_array) - KWDOFFSET,
7441 sizeof(tokname_array[0]), pstrcmp);
7442 }
7443
7444 /*
7445 * Locate and print what a word is...
7446 */
7447 static int
7448 describe_command(char *command, int describe_command_verbose)
7449 {
7450 struct cmdentry entry;
7451 struct tblentry *cmdp;
7452 #if ENABLE_ASH_ALIAS
7453 const struct alias *ap;
7454 #endif
7455 const char *path = pathval();
7456
7457 if (describe_command_verbose) {
7458 out1str(command);
7459 }
7460
7461 /* First look at the keywords */
7462 if (findkwd(command)) {
7463 out1str(describe_command_verbose ? " is a shell keyword" : command);
7464 goto out;
7465 }
7466
7467 #if ENABLE_ASH_ALIAS
7468 /* Then look at the aliases */
7469 ap = lookupalias(command, 0);
7470 if (ap != NULL) {
7471 if (!describe_command_verbose) {
7472 out1str("alias ");
7473 printalias(ap);
7474 return 0;
7475 }
7476 out1fmt(" is an alias for %s", ap->val);
7477 goto out;
7478 }
7479 #endif
7480 /* Then check if it is a tracked alias */
7481 cmdp = cmdlookup(command, 0);
7482 if (cmdp != NULL) {
7483 entry.cmdtype = cmdp->cmdtype;
7484 entry.u = cmdp->param;
7485 } else {
7486 /* Finally use brute force */
7487 find_command(command, &entry, DO_ABS, path);
7488 }
7489
7490 switch (entry.cmdtype) {
7491 case CMDNORMAL: {
7492 int j = entry.u.index;
7493 char *p;
7494 if (j < 0) {
7495 p = command;
7496 } else {
7497 do {
7498 p = padvance(&path, command);
7499 stunalloc(p);
7500 } while (--j >= 0);
7501 }
7502 if (describe_command_verbose) {
7503 out1fmt(" is%s %s",
7504 (cmdp ? " a tracked alias for" : nullstr), p
7505 );
7506 } else {
7507 out1str(p);
7508 }
7509 break;
7510 }
7511
7512 case CMDFUNCTION:
7513 if (describe_command_verbose) {
7514 out1str(" is a shell function");
7515 } else {
7516 out1str(command);
7517 }
7518 break;
7519
7520 case CMDBUILTIN:
7521 if (describe_command_verbose) {
7522 out1fmt(" is a %sshell builtin",
7523 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
7524 "special " : nullstr
7525 );
7526 } else {
7527 out1str(command);
7528 }
7529 break;
7530
7531 default:
7532 if (describe_command_verbose) {
7533 out1str(": not found\n");
7534 }
7535 return 127;
7536 }
7537 out:
7538 outstr("\n", stdout);
7539 return 0;
7540 }
7541
7542 static int
7543 typecmd(int argc UNUSED_PARAM, char **argv)
7544 {
7545 int i = 1;
7546 int err = 0;
7547 int verbose = 1;
7548
7549 /* type -p ... ? (we don't bother checking for 'p') */
7550 if (argv[1] && argv[1][0] == '-') {
7551 i++;
7552 verbose = 0;
7553 }
7554 while (argv[i]) {
7555 err |= describe_command(argv[i++], verbose);
7556 }
7557 return err;
7558 }
7559
7560 #if ENABLE_ASH_CMDCMD
7561 static int
7562 commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
7563 {
7564 int c;
7565 enum {
7566 VERIFY_BRIEF = 1,
7567 VERIFY_VERBOSE = 2,
7568 } verify = 0;
7569
7570 while ((c = nextopt("pvV")) != '\0')
7571 if (c == 'V')
7572 verify |= VERIFY_VERBOSE;
7573 else if (c == 'v')
7574 verify |= VERIFY_BRIEF;
7575 #if DEBUG
7576 else if (c != 'p')
7577 abort();
7578 #endif
7579 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
7580 if (verify && (*argptr != NULL)) {
7581 return describe_command(*argptr, verify - VERIFY_BRIEF);
7582 }
7583
7584 return 0;
7585 }
7586 #endif
7587
7588
7589 /* ============ eval.c */
7590
7591 static int funcblocksize; /* size of structures in function */
7592 static int funcstringsize; /* size of strings in node */
7593 static void *funcblock; /* block to allocate function from */
7594 static char *funcstring; /* block to allocate strings from */
7595
7596 /* flags in argument to evaltree */
7597 #define EV_EXIT 01 /* exit after evaluating tree */
7598 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
7599 #define EV_BACKCMD 04 /* command executing within back quotes */
7600
7601 static const short nodesize[N_NUMBER] = {
7602 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
7603 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
7604 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
7605 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
7606 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
7607 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
7608 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
7609 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
7610 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
7611 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
7612 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
7613 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
7614 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
7615 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
7616 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
7617 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
7618 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
7619 #if ENABLE_ASH_BASH_COMPAT
7620 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
7621 #endif
7622 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
7623 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
7624 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
7625 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
7626 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
7627 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
7628 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
7629 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
7630 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
7631 };
7632
7633 static void calcsize(union node *n);
7634
7635 static void
7636 sizenodelist(struct nodelist *lp)
7637 {
7638 while (lp) {
7639 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
7640 calcsize(lp->n);
7641 lp = lp->next;
7642 }
7643 }
7644
7645 static void
7646 calcsize(union node *n)
7647 {
7648 if (n == NULL)
7649 return;
7650 funcblocksize += nodesize[n->type];
7651 switch (n->type) {
7652 case NCMD:
7653 calcsize(n->ncmd.redirect);
7654 calcsize(n->ncmd.args);
7655 calcsize(n->ncmd.assign);
7656 break;
7657 case NPIPE:
7658 sizenodelist(n->npipe.cmdlist);
7659 break;
7660 case NREDIR:
7661 case NBACKGND:
7662 case NSUBSHELL:
7663 calcsize(n->nredir.redirect);
7664 calcsize(n->nredir.n);
7665 break;
7666 case NAND:
7667 case NOR:
7668 case NSEMI:
7669 case NWHILE:
7670 case NUNTIL:
7671 calcsize(n->nbinary.ch2);
7672 calcsize(n->nbinary.ch1);
7673 break;
7674 case NIF:
7675 calcsize(n->nif.elsepart);
7676 calcsize(n->nif.ifpart);
7677 calcsize(n->nif.test);
7678 break;
7679 case NFOR:
7680 funcstringsize += strlen(n->nfor.var) + 1;
7681 calcsize(n->nfor.body);
7682 calcsize(n->nfor.args);
7683 break;
7684 case NCASE:
7685 calcsize(n->ncase.cases);
7686 calcsize(n->ncase.expr);
7687 break;
7688 case NCLIST:
7689 calcsize(n->nclist.body);
7690 calcsize(n->nclist.pattern);
7691 calcsize(n->nclist.next);
7692 break;
7693 case NDEFUN:
7694 case NARG:
7695 sizenodelist(n->narg.backquote);
7696 funcstringsize += strlen(n->narg.text) + 1;
7697 calcsize(n->narg.next);
7698 break;
7699 case NTO:
7700 #if ENABLE_ASH_BASH_COMPAT
7701 case NTO2:
7702 #endif
7703 case NCLOBBER:
7704 case NFROM:
7705 case NFROMTO:
7706 case NAPPEND:
7707 calcsize(n->nfile.fname);
7708 calcsize(n->nfile.next);
7709 break;
7710 case NTOFD:
7711 case NFROMFD:
7712 calcsize(n->ndup.vname);
7713 calcsize(n->ndup.next);
7714 break;
7715 case NHERE:
7716 case NXHERE:
7717 calcsize(n->nhere.doc);
7718 calcsize(n->nhere.next);
7719 break;
7720 case NNOT:
7721 calcsize(n->nnot.com);
7722 break;
7723 };
7724 }
7725
7726 static char *
7727 nodeckstrdup(char *s)
7728 {
7729 char *rtn = funcstring;
7730
7731 strcpy(funcstring, s);
7732 funcstring += strlen(s) + 1;
7733 return rtn;
7734 }
7735
7736 static union node *copynode(union node *);
7737
7738 static struct nodelist *
7739 copynodelist(struct nodelist *lp)
7740 {
7741 struct nodelist *start;
7742 struct nodelist **lpp;
7743
7744 lpp = &start;
7745 while (lp) {
7746 *lpp = funcblock;
7747 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
7748 (*lpp)->n = copynode(lp->n);
7749 lp = lp->next;
7750 lpp = &(*lpp)->next;
7751 }
7752 *lpp = NULL;
7753 return start;
7754 }
7755
7756 static union node *
7757 copynode(union node *n)
7758 {
7759 union node *new;
7760
7761 if (n == NULL)
7762 return NULL;
7763 new = funcblock;
7764 funcblock = (char *) funcblock + nodesize[n->type];
7765
7766 switch (n->type) {
7767 case NCMD:
7768 new->ncmd.redirect = copynode(n->ncmd.redirect);
7769 new->ncmd.args = copynode(n->ncmd.args);
7770 new->ncmd.assign = copynode(n->ncmd.assign);
7771 break;
7772 case NPIPE:
7773 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
7774 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
7775 break;
7776 case NREDIR:
7777 case NBACKGND:
7778 case NSUBSHELL:
7779 new->nredir.redirect = copynode(n->nredir.redirect);
7780 new->nredir.n = copynode(n->nredir.n);
7781 break;
7782 case NAND:
7783 case NOR:
7784 case NSEMI:
7785 case NWHILE:
7786 case NUNTIL:
7787 new->nbinary.ch2 = copynode(n->nbinary.ch2);
7788 new->nbinary.ch1 = copynode(n->nbinary.ch1);
7789 break;
7790 case NIF:
7791 new->nif.elsepart = copynode(n->nif.elsepart);
7792 new->nif.ifpart = copynode(n->nif.ifpart);
7793 new->nif.test = copynode(n->nif.test);
7794 break;
7795 case NFOR:
7796 new->nfor.var = nodeckstrdup(n->nfor.var);
7797 new->nfor.body = copynode(n->nfor.body);
7798 new->nfor.args = copynode(n->nfor.args);
7799 break;
7800 case NCASE:
7801 new->ncase.cases = copynode(n->ncase.cases);
7802 new->ncase.expr = copynode(n->ncase.expr);
7803 break;
7804 case NCLIST:
7805 new->nclist.body = copynode(n->nclist.body);
7806 new->nclist.pattern = copynode(n->nclist.pattern);
7807 new->nclist.next = copynode(n->nclist.next);
7808 break;
7809 case NDEFUN:
7810 case NARG:
7811 new->narg.backquote = copynodelist(n->narg.backquote);
7812 new->narg.text = nodeckstrdup(n->narg.text);
7813 new->narg.next = copynode(n->narg.next);
7814 break;
7815 case NTO:
7816 #if ENABLE_ASH_BASH_COMPAT
7817 case NTO2:
7818 #endif
7819 case NCLOBBER:
7820 case NFROM:
7821 case NFROMTO:
7822 case NAPPEND:
7823 new->nfile.fname = copynode(n->nfile.fname);
7824 new->nfile.fd = n->nfile.fd;
7825 new->nfile.next = copynode(n->nfile.next);
7826 break;
7827 case NTOFD:
7828 case NFROMFD:
7829 new->ndup.vname = copynode(n->ndup.vname);
7830 new->ndup.dupfd = n->ndup.dupfd;
7831 new->ndup.fd = n->ndup.fd;
7832 new->ndup.next = copynode(n->ndup.next);
7833 break;
7834 case NHERE:
7835 case NXHERE:
7836 new->nhere.doc = copynode(n->nhere.doc);
7837 new->nhere.fd = n->nhere.fd;
7838 new->nhere.next = copynode(n->nhere.next);
7839 break;
7840 case NNOT:
7841 new->nnot.com = copynode(n->nnot.com);
7842 break;
7843 };
7844 new->type = n->type;
7845 return new;
7846 }
7847
7848 /*
7849 * Make a copy of a parse tree.
7850 */
7851 static struct funcnode *
7852 copyfunc(union node *n)
7853 {
7854 struct funcnode *f;
7855 size_t blocksize;
7856
7857 funcblocksize = offsetof(struct funcnode, n);
7858 funcstringsize = 0;
7859 calcsize(n);
7860 blocksize = funcblocksize;
7861 f = ckmalloc(blocksize + funcstringsize);
7862 funcblock = (char *) f + offsetof(struct funcnode, n);
7863 funcstring = (char *) f + blocksize;
7864 copynode(n);
7865 f->count = 0;
7866 return f;
7867 }
7868
7869 /*
7870 * Define a shell function.
7871 */
7872 static void
7873 defun(char *name, union node *func)
7874 {
7875 struct cmdentry entry;
7876
7877 INT_OFF;
7878 entry.cmdtype = CMDFUNCTION;
7879 entry.u.func = copyfunc(func);
7880 addcmdentry(name, &entry);
7881 INT_ON;
7882 }
7883
7884 static int evalskip; /* set if we are skipping commands */
7885 /* reasons for skipping commands (see comment on breakcmd routine) */
7886 #define SKIPBREAK (1 << 0)
7887 #define SKIPCONT (1 << 1)
7888 #define SKIPFUNC (1 << 2)
7889 #define SKIPFILE (1 << 3)
7890 #define SKIPEVAL (1 << 4)
7891 static int skipcount; /* number of levels to skip */
7892 static int funcnest; /* depth of function calls */
7893 static int loopnest; /* current loop nesting level */
7894
7895 /* forward decl way out to parsing code - dotrap needs it */
7896 static int evalstring(char *s, int mask);
7897
7898 /*
7899 * Called to execute a trap. Perhaps we should avoid entering new trap
7900 * handlers while we are executing a trap handler.
7901 */
7902 static int
7903 dotrap(void)
7904 {
7905 char *p;
7906 char *q;
7907 int i;
7908 int savestatus;
7909 int skip;
7910
7911 savestatus = exitstatus;
7912 pendingsig = 0;
7913 xbarrier();
7914
7915 TRACE(("dotrap entered\n"));
7916 for (i = 1, q = gotsig; i < NSIG; i++, q++) {
7917 if (!*q)
7918 continue;
7919
7920 p = trap[i];
7921 /* non-trapped SIGINT is handled separately by raise_interrupt,
7922 * don't upset it by resetting gotsig[SIGINT-1] */
7923 if (i == SIGINT && !p)
7924 continue;
7925
7926 TRACE(("sig %d is active, will run handler '%s'\n", i, p));
7927 *q = '\0';
7928 if (!p)
7929 continue;
7930 skip = evalstring(p, SKIPEVAL);
7931 exitstatus = savestatus;
7932 if (skip) {
7933 TRACE(("dotrap returns %d\n", skip));
7934 return skip;
7935 }
7936 }
7937
7938 TRACE(("dotrap returns 0\n"));
7939 return 0;
7940 }
7941
7942 /* forward declarations - evaluation is fairly recursive business... */
7943 static void evalloop(union node *, int);
7944 static void evalfor(union node *, int);
7945 static void evalcase(union node *, int);
7946 static void evalsubshell(union node *, int);
7947 static void expredir(union node *);
7948 static void evalpipe(union node *, int);
7949 static void evalcommand(union node *, int);
7950 static int evalbltin(const struct builtincmd *, int, char **);
7951 static void prehash(union node *);
7952
7953 /*
7954 * Evaluate a parse tree. The value is left in the global variable
7955 * exitstatus.
7956 */
7957 static void
7958 evaltree(union node *n, int flags)
7959 {
7960 struct jmploc *volatile savehandler = exception_handler;
7961 struct jmploc jmploc;
7962 int checkexit = 0;
7963 void (*evalfn)(union node *, int);
7964 int status;
7965 int int_level;
7966
7967 SAVE_INT(int_level);
7968
7969 if (n == NULL) {
7970 TRACE(("evaltree(NULL) called\n"));
7971 goto out1;
7972 }
7973 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
7974
7975 exception_handler = &jmploc;
7976 {
7977 int err = setjmp(jmploc.loc);
7978 if (err) {
7979 /* if it was a signal, check for trap handlers */
7980 if (exception == EXSIG) {
7981 TRACE(("exception %d (EXSIG) in evaltree, err=%d\n", exception, err));
7982 goto out;
7983 }
7984 /* continue on the way out */
7985 TRACE(("exception %d in evaltree, propagating err=%d\n", exception, err));
7986 exception_handler = savehandler;
7987 longjmp(exception_handler->loc, err);
7988 }
7989 }
7990
7991 switch (n->type) {
7992 default:
7993 #if DEBUG
7994 out1fmt("Node type = %d\n", n->type);
7995 fflush(stdout);
7996 break;
7997 #endif
7998 case NNOT:
7999 evaltree(n->nnot.com, EV_TESTED);
8000 status = !exitstatus;
8001 goto setstatus;
8002 case NREDIR:
8003 expredir(n->nredir.redirect);
8004 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8005 if (!status) {
8006 evaltree(n->nredir.n, flags & EV_TESTED);
8007 status = exitstatus;
8008 }
8009 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
8010 goto setstatus;
8011 case NCMD:
8012 evalfn = evalcommand;
8013 checkexit:
8014 if (eflag && !(flags & EV_TESTED))
8015 checkexit = ~0;
8016 goto calleval;
8017 case NFOR:
8018 evalfn = evalfor;
8019 goto calleval;
8020 case NWHILE:
8021 case NUNTIL:
8022 evalfn = evalloop;
8023 goto calleval;
8024 case NSUBSHELL:
8025 case NBACKGND:
8026 evalfn = evalsubshell;
8027 goto calleval;
8028 case NPIPE:
8029 evalfn = evalpipe;
8030 goto checkexit;
8031 case NCASE:
8032 evalfn = evalcase;
8033 goto calleval;
8034 case NAND:
8035 case NOR:
8036 case NSEMI: {
8037
8038 #if NAND + 1 != NOR
8039 #error NAND + 1 != NOR
8040 #endif
8041 #if NOR + 1 != NSEMI
8042 #error NOR + 1 != NSEMI
8043 #endif
8044 unsigned is_or = n->type - NAND;
8045 evaltree(
8046 n->nbinary.ch1,
8047 (flags | ((is_or >> 1) - 1)) & EV_TESTED
8048 );
8049 if (!exitstatus == is_or)
8050 break;
8051 if (!evalskip) {
8052 n = n->nbinary.ch2;
8053 evaln:
8054 evalfn = evaltree;
8055 calleval:
8056 evalfn(n, flags);
8057 break;
8058 }
8059 break;
8060 }
8061 case NIF:
8062 evaltree(n->nif.test, EV_TESTED);
8063 if (evalskip)
8064 break;
8065 if (exitstatus == 0) {
8066 n = n->nif.ifpart;
8067 goto evaln;
8068 }
8069 if (n->nif.elsepart) {
8070 n = n->nif.elsepart;
8071 goto evaln;
8072 }
8073 goto success;
8074 case NDEFUN:
8075 defun(n->narg.text, n->narg.next);
8076 success:
8077 status = 0;
8078 setstatus:
8079 exitstatus = status;
8080 break;
8081 }
8082
8083 out:
8084 exception_handler = savehandler;
8085 out1:
8086 if (checkexit & exitstatus)
8087 evalskip |= SKIPEVAL;
8088 else if (pendingsig && dotrap())
8089 goto exexit;
8090
8091 if (flags & EV_EXIT) {
8092 exexit:
8093 raise_exception(EXEXIT);
8094 }
8095
8096 RESTORE_INT(int_level);
8097 TRACE(("leaving evaltree (no interrupts)\n"));
8098 }
8099
8100 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8101 static
8102 #endif
8103 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
8104
8105 static void
8106 evalloop(union node *n, int flags)
8107 {
8108 int status;
8109
8110 loopnest++;
8111 status = 0;
8112 flags &= EV_TESTED;
8113 for (;;) {
8114 int i;
8115
8116 evaltree(n->nbinary.ch1, EV_TESTED);
8117 if (evalskip) {
8118 skipping:
8119 if (evalskip == SKIPCONT && --skipcount <= 0) {
8120 evalskip = 0;
8121 continue;
8122 }
8123 if (evalskip == SKIPBREAK && --skipcount <= 0)
8124 evalskip = 0;
8125 break;
8126 }
8127 i = exitstatus;
8128 if (n->type != NWHILE)
8129 i = !i;
8130 if (i != 0)
8131 break;
8132 evaltree(n->nbinary.ch2, flags);
8133 status = exitstatus;
8134 if (evalskip)
8135 goto skipping;
8136 }
8137 loopnest--;
8138 exitstatus = status;
8139 }
8140
8141 static void
8142 evalfor(union node *n, int flags)
8143 {
8144 struct arglist arglist;
8145 union node *argp;
8146 struct strlist *sp;
8147 struct stackmark smark;
8148
8149 setstackmark(&smark);
8150 arglist.list = NULL;
8151 arglist.lastp = &arglist.list;
8152 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
8153 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
8154 /* XXX */
8155 if (evalskip)
8156 goto out;
8157 }
8158 *arglist.lastp = NULL;
8159
8160 exitstatus = 0;
8161 loopnest++;
8162 flags &= EV_TESTED;
8163 for (sp = arglist.list; sp; sp = sp->next) {
8164 setvar(n->nfor.var, sp->text, 0);
8165 evaltree(n->nfor.body, flags);
8166 if (evalskip) {
8167 if (evalskip == SKIPCONT && --skipcount <= 0) {
8168 evalskip = 0;
8169 continue;
8170 }
8171 if (evalskip == SKIPBREAK && --skipcount <= 0)
8172 evalskip = 0;
8173 break;
8174 }
8175 }
8176 loopnest--;
8177 out:
8178 popstackmark(&smark);
8179 }
8180
8181 static void
8182 evalcase(union node *n, int flags)
8183 {
8184 union node *cp;
8185 union node *patp;
8186 struct arglist arglist;
8187 struct stackmark smark;
8188
8189 setstackmark(&smark);
8190 arglist.list = NULL;
8191 arglist.lastp = &arglist.list;
8192 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
8193 exitstatus = 0;
8194 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8195 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
8196 if (casematch(patp, arglist.list->text)) {
8197 if (evalskip == 0) {
8198 evaltree(cp->nclist.body, flags);
8199 }
8200 goto out;
8201 }
8202 }
8203 }
8204 out:
8205 popstackmark(&smark);
8206 }
8207
8208 /*
8209 * Kick off a subshell to evaluate a tree.
8210 */
8211 static void
8212 evalsubshell(union node *n, int flags)
8213 {
8214 struct job *jp;
8215 int backgnd = (n->type == NBACKGND);
8216 int status;
8217
8218 expredir(n->nredir.redirect);
8219 if (!backgnd && flags & EV_EXIT && !trap[0])
8220 goto nofork;
8221 INT_OFF;
8222 jp = makejob(/*n,*/ 1);
8223 if (forkshell(jp, n, backgnd) == 0) {
8224 INT_ON;
8225 flags |= EV_EXIT;
8226 if (backgnd)
8227 flags &=~ EV_TESTED;
8228 nofork:
8229 redirect(n->nredir.redirect, 0);
8230 evaltreenr(n->nredir.n, flags);
8231 /* never returns */
8232 }
8233 status = 0;
8234 if (!backgnd)
8235 status = waitforjob(jp);
8236 exitstatus = status;
8237 INT_ON;
8238 }
8239
8240 /*
8241 * Compute the names of the files in a redirection list.
8242 */
8243 static void fixredir(union node *, const char *, int);
8244 static void
8245 expredir(union node *n)
8246 {
8247 union node *redir;
8248
8249 for (redir = n; redir; redir = redir->nfile.next) {
8250 struct arglist fn;
8251
8252 fn.list = NULL;
8253 fn.lastp = &fn.list;
8254 switch (redir->type) {
8255 case NFROMTO:
8256 case NFROM:
8257 case NTO:
8258 #if ENABLE_ASH_BASH_COMPAT
8259 case NTO2:
8260 #endif
8261 case NCLOBBER:
8262 case NAPPEND:
8263 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
8264 #if ENABLE_ASH_BASH_COMPAT
8265 store_expfname:
8266 #endif
8267 redir->nfile.expfname = fn.list->text;
8268 break;
8269 case NFROMFD:
8270 case NTOFD: /* >& */
8271 if (redir->ndup.vname) {
8272 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
8273 if (fn.list == NULL)
8274 ash_msg_and_raise_error("redir error");
8275 #if ENABLE_ASH_BASH_COMPAT
8276 //FIXME: we used expandarg with different args!
8277 if (!isdigit_str9(fn.list->text)) {
8278 /* >&file, not >&fd */
8279 if (redir->nfile.fd != 1) /* 123>&file - BAD */
8280 ash_msg_and_raise_error("redir error");
8281 redir->type = NTO2;
8282 goto store_expfname;
8283 }
8284 #endif
8285 fixredir(redir, fn.list->text, 1);
8286 }
8287 break;
8288 }
8289 }
8290 }
8291
8292 /*
8293 * Evaluate a pipeline. All the processes in the pipeline are children
8294 * of the process creating the pipeline. (This differs from some versions
8295 * of the shell, which make the last process in a pipeline the parent
8296 * of all the rest.)
8297 */
8298 static void
8299 evalpipe(union node *n, int flags)
8300 {
8301 struct job *jp;
8302 struct nodelist *lp;
8303 int pipelen;
8304 int prevfd;
8305 int pip[2];
8306
8307 TRACE(("evalpipe(0x%lx) called\n", (long)n));
8308 pipelen = 0;
8309 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
8310 pipelen++;
8311 flags |= EV_EXIT;
8312 INT_OFF;
8313 jp = makejob(/*n,*/ pipelen);
8314 prevfd = -1;
8315 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
8316 prehash(lp->n);
8317 pip[1] = -1;
8318 if (lp->next) {
8319 if (pipe(pip) < 0) {
8320 close(prevfd);
8321 ash_msg_and_raise_error("pipe call failed");
8322 }
8323 }
8324 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
8325 INT_ON;
8326 if (pip[1] >= 0) {
8327 close(pip[0]);
8328 }
8329 if (prevfd > 0) {
8330 dup2(prevfd, 0);
8331 close(prevfd);
8332 }
8333 if (pip[1] > 1) {
8334 dup2(pip[1], 1);
8335 close(pip[1]);
8336 }
8337 evaltreenr(lp->n, flags);
8338 /* never returns */
8339 }
8340 if (prevfd >= 0)
8341 close(prevfd);
8342 prevfd = pip[0];
8343 /* Don't want to trigger debugging */
8344 if (pip[1] != -1)
8345 close(pip[1]);
8346 }
8347 if (n->npipe.pipe_backgnd == 0) {
8348 exitstatus = waitforjob(jp);
8349 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
8350 }
8351 INT_ON;
8352 }
8353
8354 /*
8355 * Controls whether the shell is interactive or not.
8356 */
8357 static void
8358 setinteractive(int on)
8359 {
8360 static smallint is_interactive;
8361
8362 if (++on == is_interactive)
8363 return;
8364 is_interactive = on;
8365 setsignal(SIGINT);
8366 setsignal(SIGQUIT);
8367 setsignal(SIGTERM);
8368 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8369 if (is_interactive > 1) {
8370 /* Looks like they want an interactive shell */
8371 static smallint did_banner;
8372
8373 if (!did_banner) {
8374 out1fmt(
8375 "\n\n"
8376 "%s built-in shell (ash)\n"
8377 "Enter 'help' for a list of built-in commands."
8378 "\n\n",
8379 bb_banner);
8380 did_banner = 1;
8381 }
8382 }
8383 #endif
8384 }
8385
8386 static void
8387 optschanged(void)
8388 {
8389 #if DEBUG
8390 opentrace();
8391 #endif
8392 setinteractive(iflag);
8393 setjobctl(mflag);
8394 #if ENABLE_FEATURE_EDITING_VI
8395 if (viflag)
8396 line_input_state->flags |= VI_MODE;
8397 else
8398 line_input_state->flags &= ~VI_MODE;
8399 #else
8400 viflag = 0; /* forcibly keep the option off */
8401 #endif
8402 }
8403
8404 static struct localvar *localvars;
8405
8406 /*
8407 * Called after a function returns.
8408 * Interrupts must be off.
8409 */
8410 static void
8411 poplocalvars(void)
8412 {
8413 struct localvar *lvp;
8414 struct var *vp;
8415
8416 while ((lvp = localvars) != NULL) {
8417 localvars = lvp->next;
8418 vp = lvp->vp;
8419 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
8420 if (vp == NULL) { /* $- saved */
8421 memcpy(optlist, lvp->text, sizeof(optlist));
8422 free((char*)lvp->text);
8423 optschanged();
8424 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
8425 unsetvar(vp->text);
8426 } else {
8427 if (vp->func)
8428 (*vp->func)(strchrnul(lvp->text, '=') + 1);
8429 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
8430 free((char*)vp->text);
8431 vp->flags = lvp->flags;
8432 vp->text = lvp->text;
8433 }
8434 free(lvp);
8435 }
8436 }
8437
8438 static int
8439 evalfun(struct funcnode *func, int argc, char **argv, int flags)
8440 {
8441 volatile struct shparam saveparam;
8442 struct localvar *volatile savelocalvars;
8443 struct jmploc *volatile savehandler;
8444 struct jmploc jmploc;
8445 int e;
8446
8447 saveparam = shellparam;
8448 savelocalvars = localvars;
8449 e = setjmp(jmploc.loc);
8450 if (e) {
8451 goto funcdone;
8452 }
8453 INT_OFF;
8454 savehandler = exception_handler;
8455 exception_handler = &jmploc;
8456 localvars = NULL;
8457 shellparam.malloced = 0;
8458 func->count++;
8459 funcnest++;
8460 INT_ON;
8461 shellparam.nparam = argc - 1;
8462 shellparam.p = argv + 1;
8463 #if ENABLE_ASH_GETOPTS
8464 shellparam.optind = 1;
8465 shellparam.optoff = -1;
8466 #endif
8467 evaltree(&func->n, flags & EV_TESTED);
8468 funcdone:
8469 INT_OFF;
8470 funcnest--;
8471 freefunc(func);
8472 poplocalvars();
8473 localvars = savelocalvars;
8474 freeparam(&shellparam);
8475 shellparam = saveparam;
8476 exception_handler = savehandler;
8477 INT_ON;
8478 evalskip &= ~SKIPFUNC;
8479 return e;
8480 }
8481
8482 #if ENABLE_ASH_CMDCMD
8483 static char **
8484 parse_command_args(char **argv, const char **path)
8485 {
8486 char *cp, c;
8487
8488 for (;;) {
8489 cp = *++argv;
8490 if (!cp)
8491 return 0;
8492 if (*cp++ != '-')
8493 break;
8494 c = *cp++;
8495 if (!c)
8496 break;
8497 if (c == '-' && !*cp) {
8498 argv++;
8499 break;
8500 }
8501 do {
8502 switch (c) {
8503 case 'p':
8504 *path = bb_default_path;
8505 break;
8506 default:
8507 /* run 'typecmd' for other options */
8508 return 0;
8509 }
8510 c = *cp++;
8511 } while (c);
8512 }
8513 return argv;
8514 }
8515 #endif
8516
8517 /*
8518 * Make a variable a local variable. When a variable is made local, it's
8519 * value and flags are saved in a localvar structure. The saved values
8520 * will be restored when the shell function returns. We handle the name
8521 * "-" as a special case.
8522 */
8523 static void
8524 mklocal(char *name)
8525 {
8526 struct localvar *lvp;
8527 struct var **vpp;
8528 struct var *vp;
8529
8530 INT_OFF;
8531 lvp = ckzalloc(sizeof(struct localvar));
8532 if (LONE_DASH(name)) {
8533 char *p;
8534 p = ckmalloc(sizeof(optlist));
8535 lvp->text = memcpy(p, optlist, sizeof(optlist));
8536 vp = NULL;
8537 } else {
8538 char *eq;
8539
8540 vpp = hashvar(name);
8541 vp = *findvar(vpp, name);
8542 eq = strchr(name, '=');
8543 if (vp == NULL) {
8544 if (eq)
8545 setvareq(name, VSTRFIXED);
8546 else
8547 setvar(name, NULL, VSTRFIXED);
8548 vp = *vpp; /* the new variable */
8549 lvp->flags = VUNSET;
8550 } else {
8551 lvp->text = vp->text;
8552 lvp->flags = vp->flags;
8553 vp->flags |= VSTRFIXED|VTEXTFIXED;
8554 if (eq)
8555 setvareq(name, 0);
8556 }
8557 }
8558 lvp->vp = vp;
8559 lvp->next = localvars;
8560 localvars = lvp;
8561 INT_ON;
8562 }
8563
8564 /*
8565 * The "local" command.
8566 */
8567 static int
8568 localcmd(int argc UNUSED_PARAM, char **argv)
8569 {
8570 char *name;
8571
8572 argv = argptr;
8573 while ((name = *argv++) != NULL) {
8574 mklocal(name);
8575 }
8576 return 0;
8577 }
8578
8579 static int
8580 falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8581 {
8582 return 1;
8583 }
8584
8585 static int
8586 truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8587 {
8588 return 0;
8589 }
8590
8591 static int
8592 execcmd(int argc UNUSED_PARAM, char **argv)
8593 {
8594 if (argv[1]) {
8595 iflag = 0; /* exit on error */
8596 mflag = 0;
8597 optschanged();
8598 shellexec(argv + 1, pathval(), 0);
8599 }
8600 return 0;
8601 }
8602
8603 /*
8604 * The return command.
8605 */
8606 static int
8607 returncmd(int argc UNUSED_PARAM, char **argv)
8608 {
8609 /*
8610 * If called outside a function, do what ksh does;
8611 * skip the rest of the file.
8612 */
8613 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
8614 return argv[1] ? number(argv[1]) : exitstatus;
8615 }
8616
8617 /* Forward declarations for builtintab[] */
8618 static int breakcmd(int, char **);
8619 static int dotcmd(int, char **);
8620 static int evalcmd(int, char **);
8621 static int exitcmd(int, char **);
8622 static int exportcmd(int, char **);
8623 #if ENABLE_ASH_GETOPTS
8624 static int getoptscmd(int, char **);
8625 #endif
8626 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8627 static int helpcmd(int, char **);
8628 #endif
8629 #if ENABLE_ASH_MATH_SUPPORT
8630 static int letcmd(int, char **);
8631 #endif
8632 static int readcmd(int, char **);
8633 static int setcmd(int, char **);
8634 static int shiftcmd(int, char **);
8635 static int timescmd(int, char **);
8636 static int trapcmd(int, char **);
8637 static int umaskcmd(int, char **);
8638 static int unsetcmd(int, char **);
8639 static int ulimitcmd(int, char **);
8640
8641 #define BUILTIN_NOSPEC "0"
8642 #define BUILTIN_SPECIAL "1"
8643 #define BUILTIN_REGULAR "2"
8644 #define BUILTIN_SPEC_REG "3"
8645 #define BUILTIN_ASSIGN "4"
8646 #define BUILTIN_SPEC_ASSG "5"
8647 #define BUILTIN_REG_ASSG "6"
8648 #define BUILTIN_SPEC_REG_ASSG "7"
8649
8650 /* We do not handle [[ expr ]] bashism bash-compatibly,
8651 * we make it a synonym of [ expr ].
8652 * Basically, word splitting and pathname expansion should NOT be performed
8653 * Examples:
8654 * no word splitting: a="a b"; [[ $a = "a b" ]]; echo $? should print "0"
8655 * no pathname expansion: [[ /bin/m* = "/bin/m*" ]]; echo $? should print "0"
8656 * Additional operators:
8657 * || and && should work as -o and -a
8658 * =~ regexp match
8659 * Apart from the above, [[ expr ]] should work as [ expr ]
8660 */
8661
8662 #define echocmd echo_main
8663 #define printfcmd printf_main
8664 #define testcmd test_main
8665
8666 /* Keep these in proper order since it is searched via bsearch() */
8667 static const struct builtincmd builtintab[] = {
8668 { BUILTIN_SPEC_REG ".", dotcmd },
8669 { BUILTIN_SPEC_REG ":", truecmd },
8670 #if ENABLE_ASH_BUILTIN_TEST
8671 { BUILTIN_REGULAR "[", testcmd },
8672 #if ENABLE_ASH_BASH_COMPAT
8673 { BUILTIN_REGULAR "[[", testcmd },
8674 #endif
8675 #endif
8676 #if ENABLE_ASH_ALIAS
8677 { BUILTIN_REG_ASSG "alias", aliascmd },
8678 #endif
8679 #if JOBS
8680 { BUILTIN_REGULAR "bg", fg_bgcmd },
8681 #endif
8682 { BUILTIN_SPEC_REG "break", breakcmd },
8683 { BUILTIN_REGULAR "cd", cdcmd },
8684 { BUILTIN_NOSPEC "chdir", cdcmd },
8685 #if ENABLE_ASH_CMDCMD
8686 { BUILTIN_REGULAR "command", commandcmd },
8687 #endif
8688 { BUILTIN_SPEC_REG "continue", breakcmd },
8689 #if ENABLE_ASH_BUILTIN_ECHO
8690 { BUILTIN_REGULAR "echo", echocmd },
8691 #endif
8692 { BUILTIN_SPEC_REG "eval", evalcmd },
8693 { BUILTIN_SPEC_REG "exec", execcmd },
8694 { BUILTIN_SPEC_REG "exit", exitcmd },
8695 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
8696 { BUILTIN_REGULAR "false", falsecmd },
8697 #if JOBS
8698 { BUILTIN_REGULAR "fg", fg_bgcmd },
8699 #endif
8700 #if ENABLE_ASH_GETOPTS
8701 { BUILTIN_REGULAR "getopts", getoptscmd },
8702 #endif
8703 { BUILTIN_NOSPEC "hash", hashcmd },
8704 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8705 { BUILTIN_NOSPEC "help", helpcmd },
8706 #endif
8707 #if JOBS
8708 { BUILTIN_REGULAR "jobs", jobscmd },
8709 { BUILTIN_REGULAR "kill", killcmd },
8710 #endif
8711 #if ENABLE_ASH_MATH_SUPPORT
8712 { BUILTIN_NOSPEC "let", letcmd },
8713 #endif
8714 { BUILTIN_ASSIGN "local", localcmd },
8715 #if ENABLE_ASH_BUILTIN_PRINTF
8716 { BUILTIN_REGULAR "printf", printfcmd },
8717 #endif
8718 { BUILTIN_NOSPEC "pwd", pwdcmd },
8719 { BUILTIN_REGULAR "read", readcmd },
8720 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
8721 { BUILTIN_SPEC_REG "return", returncmd },
8722 { BUILTIN_SPEC_REG "set", setcmd },
8723 { BUILTIN_SPEC_REG "shift", shiftcmd },
8724 { BUILTIN_SPEC_REG "source", dotcmd },
8725 #if ENABLE_ASH_BUILTIN_TEST
8726 { BUILTIN_REGULAR "test", testcmd },
8727 #endif
8728 { BUILTIN_SPEC_REG "times", timescmd },
8729 { BUILTIN_SPEC_REG "trap", trapcmd },
8730 { BUILTIN_REGULAR "true", truecmd },
8731 { BUILTIN_NOSPEC "type", typecmd },
8732 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
8733 { BUILTIN_REGULAR "umask", umaskcmd },
8734 #if ENABLE_ASH_ALIAS
8735 { BUILTIN_REGULAR "unalias", unaliascmd },
8736 #endif
8737 { BUILTIN_SPEC_REG "unset", unsetcmd },
8738 { BUILTIN_REGULAR "wait", waitcmd },
8739 };
8740
8741 /* Should match the above table! */
8742 #define COMMANDCMD (builtintab + \
8743 2 + \
8744 1 * ENABLE_ASH_BUILTIN_TEST + \
8745 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
8746 1 * ENABLE_ASH_ALIAS + \
8747 1 * ENABLE_ASH_JOB_CONTROL + \
8748 3)
8749 #define EXECCMD (builtintab + \
8750 2 + \
8751 1 * ENABLE_ASH_BUILTIN_TEST + \
8752 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
8753 1 * ENABLE_ASH_ALIAS + \
8754 1 * ENABLE_ASH_JOB_CONTROL + \
8755 3 + \
8756 1 * ENABLE_ASH_CMDCMD + \
8757 1 + \
8758 ENABLE_ASH_BUILTIN_ECHO + \
8759 1)
8760
8761 /*
8762 * Search the table of builtin commands.
8763 */
8764 static struct builtincmd *
8765 find_builtin(const char *name)
8766 {
8767 struct builtincmd *bp;
8768
8769 bp = bsearch(
8770 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
8771 pstrcmp
8772 );
8773 return bp;
8774 }
8775
8776 /*
8777 * Execute a simple command.
8778 */
8779 static int
8780 isassignment(const char *p)
8781 {
8782 const char *q = endofname(p);
8783 if (p == q)
8784 return 0;
8785 return *q == '=';
8786 }
8787 static int
8788 bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8789 {
8790 /* Preserve exitstatus of a previous possible redirection
8791 * as POSIX mandates */
8792 return back_exitstatus;
8793 }
8794 static void
8795 evalcommand(union node *cmd, int flags)
8796 {
8797 static const struct builtincmd null_bltin = {
8798 "\0\0", bltincmd /* why three NULs? */
8799 };
8800 struct stackmark smark;
8801 union node *argp;
8802 struct arglist arglist;
8803 struct arglist varlist;
8804 char **argv;
8805 int argc;
8806 const struct strlist *sp;
8807 struct cmdentry cmdentry;
8808 struct job *jp;
8809 char *lastarg;
8810 const char *path;
8811 int spclbltin;
8812 int status;
8813 char **nargv;
8814 struct builtincmd *bcmd;
8815 smallint cmd_is_exec;
8816 smallint pseudovarflag = 0;
8817
8818 /* First expand the arguments. */
8819 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
8820 setstackmark(&smark);
8821 back_exitstatus = 0;
8822
8823 cmdentry.cmdtype = CMDBUILTIN;
8824 cmdentry.u.cmd = &null_bltin;
8825 varlist.lastp = &varlist.list;
8826 *varlist.lastp = NULL;
8827 arglist.lastp = &arglist.list;
8828 *arglist.lastp = NULL;
8829
8830 argc = 0;
8831 if (cmd->ncmd.args) {
8832 bcmd = find_builtin(cmd->ncmd.args->narg.text);
8833 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
8834 }
8835
8836 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
8837 struct strlist **spp;
8838
8839 spp = arglist.lastp;
8840 if (pseudovarflag && isassignment(argp->narg.text))
8841 expandarg(argp, &arglist, EXP_VARTILDE);
8842 else
8843 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
8844
8845 for (sp = *spp; sp; sp = sp->next)
8846 argc++;
8847 }
8848
8849 argv = nargv = stalloc(sizeof(char *) * (argc + 1));
8850 for (sp = arglist.list; sp; sp = sp->next) {
8851 TRACE(("evalcommand arg: %s\n", sp->text));
8852 *nargv++ = sp->text;
8853 }
8854 *nargv = NULL;
8855
8856 lastarg = NULL;
8857 if (iflag && funcnest == 0 && argc > 0)
8858 lastarg = nargv[-1];
8859
8860 preverrout_fd = 2;
8861 expredir(cmd->ncmd.redirect);
8862 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
8863
8864 path = vpath.text;
8865 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
8866 struct strlist **spp;
8867 char *p;
8868
8869 spp = varlist.lastp;
8870 expandarg(argp, &varlist, EXP_VARTILDE);
8871
8872 /*
8873 * Modify the command lookup path, if a PATH= assignment
8874 * is present
8875 */
8876 p = (*spp)->text;
8877 if (varequal(p, path))
8878 path = p;
8879 }
8880
8881 /* Print the command if xflag is set. */
8882 if (xflag) {
8883 int n;
8884 const char *p = " %s";
8885
8886 p++;
8887 fdprintf(preverrout_fd, p, expandstr(ps4val()));
8888
8889 sp = varlist.list;
8890 for (n = 0; n < 2; n++) {
8891 while (sp) {
8892 fdprintf(preverrout_fd, p, sp->text);
8893 sp = sp->next;
8894 if (*p == '%') {
8895 p--;
8896 }
8897 }
8898 sp = arglist.list;
8899 }
8900 safe_write(preverrout_fd, "\n", 1);
8901 }
8902
8903 cmd_is_exec = 0;
8904 spclbltin = -1;
8905
8906 /* Now locate the command. */
8907 if (argc) {
8908 const char *oldpath;
8909 int cmd_flag = DO_ERR;
8910
8911 path += 5;
8912 oldpath = path;
8913 for (;;) {
8914 find_command(argv[0], &cmdentry, cmd_flag, path);
8915 if (cmdentry.cmdtype == CMDUNKNOWN) {
8916 flush_stderr();
8917 status = 127;
8918 goto bail;
8919 }
8920
8921 /* implement bltin and command here */
8922 if (cmdentry.cmdtype != CMDBUILTIN)
8923 break;
8924 if (spclbltin < 0)
8925 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
8926 if (cmdentry.u.cmd == EXECCMD)
8927 cmd_is_exec = 1;
8928 #if ENABLE_ASH_CMDCMD
8929 if (cmdentry.u.cmd == COMMANDCMD) {
8930 path = oldpath;
8931 nargv = parse_command_args(argv, &path);
8932 if (!nargv)
8933 break;
8934 argc -= nargv - argv;
8935 argv = nargv;
8936 cmd_flag |= DO_NOFUNC;
8937 } else
8938 #endif
8939 break;
8940 }
8941 }
8942
8943 if (status) {
8944 /* We have a redirection error. */
8945 if (spclbltin > 0)
8946 raise_exception(EXERROR);
8947 bail:
8948 exitstatus = status;
8949 goto out;
8950 }
8951
8952 /* Execute the command. */
8953 switch (cmdentry.cmdtype) {
8954 default:
8955
8956 #if ENABLE_FEATURE_SH_NOFORK
8957 /* Hmmm... shouldn't it happen somewhere in forkshell() instead?
8958 * Why "fork off a child process if necessary" doesn't apply to NOFORK? */
8959 {
8960 /* find_command() encodes applet_no as (-2 - applet_no) */
8961 int applet_no = (- cmdentry.u.index - 2);
8962 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
8963 listsetvar(varlist.list, VEXPORT|VSTACK);
8964 /* run <applet>_main() */
8965 exitstatus = run_nofork_applet(applet_no, argv);
8966 break;
8967 }
8968 }
8969 #endif
8970 /* Fork off a child process if necessary. */
8971 if (!(flags & EV_EXIT) || trap[0]) {
8972 INT_OFF;
8973 jp = makejob(/*cmd,*/ 1);
8974 if (forkshell(jp, cmd, FORK_FG) != 0) {
8975 exitstatus = waitforjob(jp);
8976 INT_ON;
8977 TRACE(("forked child exited with %d\n", exitstatus));
8978 break;
8979 }
8980 FORCE_INT_ON;
8981 }
8982 listsetvar(varlist.list, VEXPORT|VSTACK);
8983 shellexec(argv, path, cmdentry.u.index);
8984 /* NOTREACHED */
8985
8986 case CMDBUILTIN:
8987 cmdenviron = varlist.list;
8988 if (cmdenviron) {
8989 struct strlist *list = cmdenviron;
8990 int i = VNOSET;
8991 if (spclbltin > 0 || argc == 0) {
8992 i = 0;
8993 if (cmd_is_exec && argc > 1)
8994 i = VEXPORT;
8995 }
8996 listsetvar(list, i);
8997 }
8998 /* Tight loop with builtins only:
8999 * "while kill -0 $child; do true; done"
9000 * will never exit even if $child died, unless we do this
9001 * to reap the zombie and make kill detect that it's gone: */
9002 dowait(DOWAIT_NONBLOCK, NULL);
9003
9004 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
9005 int exit_status;
9006 int i = exception;
9007 if (i == EXEXIT)
9008 goto raise;
9009 exit_status = 2;
9010 if (i == EXINT)
9011 exit_status = 128 + SIGINT;
9012 if (i == EXSIG)
9013 exit_status = 128 + pendingsig;
9014 exitstatus = exit_status;
9015 if (i == EXINT || spclbltin > 0) {
9016 raise:
9017 longjmp(exception_handler->loc, 1);
9018 }
9019 FORCE_INT_ON;
9020 }
9021 break;
9022
9023 case CMDFUNCTION:
9024 listsetvar(varlist.list, 0);
9025 /* See above for the rationale */
9026 dowait(DOWAIT_NONBLOCK, NULL);
9027 if (evalfun(cmdentry.u.func, argc, argv, flags))
9028 goto raise;
9029 break;
9030 }
9031
9032 out:
9033 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
9034 if (lastarg) {
9035 /* dsl: I think this is intended to be used to support
9036 * '_' in 'vi' command mode during line editing...
9037 * However I implemented that within libedit itself.
9038 */
9039 setvar("_", lastarg, 0);
9040 }
9041 popstackmark(&smark);
9042 }
9043
9044 static int
9045 evalbltin(const struct builtincmd *cmd, int argc, char **argv)
9046 {
9047 char *volatile savecmdname;
9048 struct jmploc *volatile savehandler;
9049 struct jmploc jmploc;
9050 int i;
9051
9052 savecmdname = commandname;
9053 i = setjmp(jmploc.loc);
9054 if (i)
9055 goto cmddone;
9056 savehandler = exception_handler;
9057 exception_handler = &jmploc;
9058 commandname = argv[0];
9059 argptr = argv + 1;
9060 optptr = NULL; /* initialize nextopt */
9061 exitstatus = (*cmd->builtin)(argc, argv);
9062 flush_stdout_stderr();
9063 cmddone:
9064 exitstatus |= ferror(stdout);
9065 clearerr(stdout);
9066 commandname = savecmdname;
9067 // exsig = 0;
9068 exception_handler = savehandler;
9069
9070 return i;
9071 }
9072
9073 static int
9074 goodname(const char *p)
9075 {
9076 return !*endofname(p);
9077 }
9078
9079
9080 /*
9081 * Search for a command. This is called before we fork so that the
9082 * location of the command will be available in the parent as well as
9083 * the child. The check for "goodname" is an overly conservative
9084 * check that the name will not be subject to expansion.
9085 */
9086 static void
9087 prehash(union node *n)
9088 {
9089 struct cmdentry entry;
9090
9091 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9092 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
9093 }
9094
9095
9096 /* ============ Builtin commands
9097 *
9098 * Builtin commands whose functions are closely tied to evaluation
9099 * are implemented here.
9100 */
9101
9102 /*
9103 * Handle break and continue commands. Break, continue, and return are
9104 * all handled by setting the evalskip flag. The evaluation routines
9105 * above all check this flag, and if it is set they start skipping
9106 * commands rather than executing them. The variable skipcount is
9107 * the number of loops to break/continue, or the number of function
9108 * levels to return. (The latter is always 1.) It should probably
9109 * be an error to break out of more loops than exist, but it isn't
9110 * in the standard shell so we don't make it one here.
9111 */
9112 static int
9113 breakcmd(int argc UNUSED_PARAM, char **argv)
9114 {
9115 int n = argv[1] ? number(argv[1]) : 1;
9116
9117 if (n <= 0)
9118 ash_msg_and_raise_error(illnum, argv[1]);
9119 if (n > loopnest)
9120 n = loopnest;
9121 if (n > 0) {
9122 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
9123 skipcount = n;
9124 }
9125 return 0;
9126 }
9127
9128
9129 /* ============ input.c
9130 *
9131 * This implements the input routines used by the parser.
9132 */
9133
9134 enum {
9135 INPUT_PUSH_FILE = 1,
9136 INPUT_NOFILE_OK = 2,
9137 };
9138
9139 static int plinno = 1; /* input line number */
9140 /* number of characters left in input buffer */
9141 static int parsenleft; /* copy of parsefile->nleft */
9142 static int parselleft; /* copy of parsefile->lleft */
9143 /* next character in input buffer */
9144 static char *parsenextc; /* copy of parsefile->nextc */
9145
9146 static smallint checkkwd;
9147 /* values of checkkwd variable */
9148 #define CHKALIAS 0x1
9149 #define CHKKWD 0x2
9150 #define CHKNL 0x4
9151
9152 static void
9153 popstring(void)
9154 {
9155 struct strpush *sp = g_parsefile->strpush;
9156
9157 INT_OFF;
9158 #if ENABLE_ASH_ALIAS
9159 if (sp->ap) {
9160 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
9161 checkkwd |= CHKALIAS;
9162 }
9163 if (sp->string != sp->ap->val) {
9164 free(sp->string);
9165 }
9166 sp->ap->flag &= ~ALIASINUSE;
9167 if (sp->ap->flag & ALIASDEAD) {
9168 unalias(sp->ap->name);
9169 }
9170 }
9171 #endif
9172 parsenextc = sp->prevstring;
9173 parsenleft = sp->prevnleft;
9174 g_parsefile->strpush = sp->prev;
9175 if (sp != &(g_parsefile->basestrpush))
9176 free(sp);
9177 INT_ON;
9178 }
9179
9180 static int
9181 preadfd(void)
9182 {
9183 int nr;
9184 char *buf = g_parsefile->buf;
9185 parsenextc = buf;
9186
9187 #if ENABLE_FEATURE_EDITING
9188 retry:
9189 if (!iflag || g_parsefile->fd != STDIN_FILENO)
9190 nr = nonblock_safe_read(g_parsefile->fd, buf, BUFSIZ - 1);
9191 else {
9192 #if ENABLE_FEATURE_TAB_COMPLETION
9193 line_input_state->path_lookup = pathval();
9194 #endif
9195 nr = read_line_input(cmdedit_prompt, buf, BUFSIZ, line_input_state);
9196 if (nr == 0) {
9197 /* Ctrl+C pressed */
9198 if (trap[SIGINT]) {
9199 buf[0] = '\n';
9200 buf[1] = '\0';
9201 raise(SIGINT);
9202 return 1;
9203 }
9204 goto retry;
9205 }
9206 if (nr < 0 && errno == 0) {
9207 /* Ctrl+D pressed */
9208 nr = 0;
9209 }
9210 }
9211 #else
9212 nr = nonblock_safe_read(g_parsefile->fd, buf, BUFSIZ - 1);
9213 #endif
9214
9215 #if 0
9216 /* nonblock_safe_read() handles this problem */
9217 if (nr < 0) {
9218 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
9219 int flags = fcntl(0, F_GETFL);
9220 if (flags >= 0 && (flags & O_NONBLOCK)) {
9221 flags &= ~O_NONBLOCK;
9222 if (fcntl(0, F_SETFL, flags) >= 0) {
9223 out2str("sh: turning off NDELAY mode\n");
9224 goto retry;
9225 }
9226 }
9227 }
9228 }
9229 #endif
9230 return nr;
9231 }
9232
9233 /*
9234 * Refill the input buffer and return the next input character:
9235 *
9236 * 1) If a string was pushed back on the input, pop it;
9237 * 2) If an EOF was pushed back (parsenleft < -BIGNUM) or we are reading
9238 * from a string so we can't refill the buffer, return EOF.
9239 * 3) If the is more stuff in this buffer, use it else call read to fill it.
9240 * 4) Process input up to the next newline, deleting nul characters.
9241 */
9242 //#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
9243 #define pgetc_debug(...) ((void)0)
9244 static int
9245 preadbuffer(void)
9246 {
9247 char *q;
9248 int more;
9249
9250 while (g_parsefile->strpush) {
9251 #if ENABLE_ASH_ALIAS
9252 if (parsenleft == -1 && g_parsefile->strpush->ap
9253 && parsenextc[-1] != ' ' && parsenextc[-1] != '\t'
9254 ) {
9255 pgetc_debug("preadbuffer PEOA");
9256 return PEOA;
9257 }
9258 #endif
9259 popstring();
9260 /* try "pgetc" now: */
9261 pgetc_debug("internal pgetc at %d:%p'%s'", parsenleft, parsenextc, parsenextc);
9262 if (--parsenleft >= 0)
9263 return signed_char2int(*parsenextc++);
9264 }
9265 /* on both branches above parsenleft < 0.
9266 * "pgetc" needs refilling.
9267 */
9268
9269 /* -90 is -BIGNUM. Below we use -99 to mark "EOF on read",
9270 * pungetc() may decrement it a few times. -90 is enough.
9271 */
9272 if (parsenleft < -90 || g_parsefile->buf == NULL) {
9273 pgetc_debug("preadbuffer PEOF1");
9274 /* even in failure keep them in lock step,
9275 * for correct pungetc. */
9276 parsenextc++;
9277 return PEOF;
9278 }
9279
9280 more = parselleft;
9281 if (more <= 0) {
9282 flush_stdout_stderr();
9283 again:
9284 more = preadfd();
9285 if (more <= 0) {
9286 parselleft = parsenleft = -99;
9287 pgetc_debug("preadbuffer PEOF2");
9288 parsenextc++;
9289 return PEOF;
9290 }
9291 }
9292
9293 /* Find out where's the end of line.
9294 * Set parsenleft/parselleft acordingly.
9295 * NUL chars are deleted.
9296 */
9297 q = parsenextc;
9298 for (;;) {
9299 char c;
9300
9301 more--;
9302
9303 c = *q;
9304 if (c == '\0') {
9305 memmove(q, q + 1, more);
9306 } else {
9307 q++;
9308 if (c == '\n') {
9309 parsenleft = q - parsenextc - 1;
9310 break;
9311 }
9312 }
9313
9314 if (more <= 0) {
9315 parsenleft = q - parsenextc - 1;
9316 if (parsenleft < 0)
9317 goto again;
9318 break;
9319 }
9320 }
9321 parselleft = more;
9322
9323 if (vflag) {
9324 char save = *q;
9325 *q = '\0';
9326 out2str(parsenextc);
9327 *q = save;
9328 }
9329
9330 pgetc_debug("preadbuffer at %d:%p'%s'", parsenleft, parsenextc, parsenextc);
9331 return signed_char2int(*parsenextc++);
9332 }
9333
9334 #define pgetc_as_macro() (--parsenleft >= 0 ? signed_char2int(*parsenextc++) : preadbuffer())
9335
9336 static int
9337 pgetc(void)
9338 {
9339 pgetc_debug("pgetc at %d:%p'%s'", parsenleft, parsenextc, parsenextc);
9340 return pgetc_as_macro();
9341 }
9342
9343 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
9344 #define pgetc_fast() pgetc()
9345 #else
9346 #define pgetc_fast() pgetc_as_macro()
9347 #endif
9348
9349 /*
9350 * Same as pgetc(), but ignores PEOA.
9351 */
9352 #if ENABLE_ASH_ALIAS
9353 static int
9354 pgetc2(void)
9355 {
9356 int c;
9357 do {
9358 c = pgetc_fast();
9359 } while (c == PEOA);
9360 return c;
9361 }
9362 #else
9363 #define pgetc2() pgetc()
9364 #endif
9365
9366 /*
9367 * Read a line from the script.
9368 */
9369 static char *
9370 pfgets(char *line, int len)
9371 {
9372 char *p = line;
9373 int nleft = len;
9374 int c;
9375
9376 while (--nleft > 0) {
9377 c = pgetc2();
9378 if (c == PEOF) {
9379 if (p == line)
9380 return NULL;
9381 break;
9382 }
9383 *p++ = c;
9384 if (c == '\n')
9385 break;
9386 }
9387 *p = '\0';
9388 return line;
9389 }
9390
9391 /*
9392 * Undo the last call to pgetc. Only one character may be pushed back.
9393 * PEOF may be pushed back.
9394 */
9395 static void
9396 pungetc(void)
9397 {
9398 parsenleft++;
9399 parsenextc--;
9400 pgetc_debug("pushed back to %d:%p'%s'", parsenleft, parsenextc, parsenextc);
9401 }
9402
9403 /*
9404 * Push a string back onto the input at this current parsefile level.
9405 * We handle aliases this way.
9406 */
9407 #if !ENABLE_ASH_ALIAS
9408 #define pushstring(s, ap) pushstring(s)
9409 #endif
9410 static void
9411 pushstring(char *s, struct alias *ap)
9412 {
9413 struct strpush *sp;
9414 int len;
9415
9416 len = strlen(s);
9417 INT_OFF;
9418 if (g_parsefile->strpush) {
9419 sp = ckzalloc(sizeof(*sp));
9420 sp->prev = g_parsefile->strpush;
9421 } else {
9422 sp = &(g_parsefile->basestrpush);
9423 }
9424 g_parsefile->strpush = sp;
9425 sp->prevstring = parsenextc;
9426 sp->prevnleft = parsenleft;
9427 #if ENABLE_ASH_ALIAS
9428 sp->ap = ap;
9429 if (ap) {
9430 ap->flag |= ALIASINUSE;
9431 sp->string = s;
9432 }
9433 #endif
9434 parsenextc = s;
9435 parsenleft = len;
9436 INT_ON;
9437 }
9438
9439 /*
9440 * To handle the "." command, a stack of input files is used. Pushfile
9441 * adds a new entry to the stack and popfile restores the previous level.
9442 */
9443 static void
9444 pushfile(void)
9445 {
9446 struct parsefile *pf;
9447
9448 g_parsefile->nleft = parsenleft;
9449 g_parsefile->lleft = parselleft;
9450 g_parsefile->nextc = parsenextc;
9451 g_parsefile->linno = plinno;
9452 pf = ckzalloc(sizeof(*pf));
9453 pf->prev = g_parsefile;
9454 pf->fd = -1;
9455 /*pf->strpush = NULL; - ckzalloc did it */
9456 /*pf->basestrpush.prev = NULL;*/
9457 g_parsefile = pf;
9458 }
9459
9460 static void
9461 popfile(void)
9462 {
9463 struct parsefile *pf = g_parsefile;
9464
9465 INT_OFF;
9466 if (pf->fd >= 0)
9467 close(pf->fd);
9468 free(pf->buf);
9469 while (pf->strpush)
9470 popstring();
9471 g_parsefile = pf->prev;
9472 free(pf);
9473 parsenleft = g_parsefile->nleft;
9474 parselleft = g_parsefile->lleft;
9475 parsenextc = g_parsefile->nextc;
9476 plinno = g_parsefile->linno;
9477 INT_ON;
9478 }
9479
9480 /*
9481 * Return to top level.
9482 */
9483 static void
9484 popallfiles(void)
9485 {
9486 while (g_parsefile != &basepf)
9487 popfile();
9488 }
9489
9490 /*
9491 * Close the file(s) that the shell is reading commands from. Called
9492 * after a fork is done.
9493 */
9494 static void
9495 closescript(void)
9496 {
9497 popallfiles();
9498 if (g_parsefile->fd > 0) {
9499 close(g_parsefile->fd);
9500 g_parsefile->fd = 0;
9501 }
9502 }
9503
9504 /*
9505 * Like setinputfile, but takes an open file descriptor. Call this with
9506 * interrupts off.
9507 */
9508 static void
9509 setinputfd(int fd, int push)
9510 {
9511 close_on_exec_on(fd);
9512 if (push) {
9513 pushfile();
9514 g_parsefile->buf = NULL;
9515 }
9516 g_parsefile->fd = fd;
9517 if (g_parsefile->buf == NULL)
9518 g_parsefile->buf = ckmalloc(IBUFSIZ);
9519 parselleft = parsenleft = 0;
9520 plinno = 1;
9521 }
9522
9523 /*
9524 * Set the input to take input from a file. If push is set, push the
9525 * old input onto the stack first.
9526 */
9527 static int
9528 setinputfile(const char *fname, int flags)
9529 {
9530 int fd;
9531 int fd2;
9532
9533 INT_OFF;
9534 fd = open(fname, O_RDONLY);
9535 if (fd < 0) {
9536 if (flags & INPUT_NOFILE_OK)
9537 goto out;
9538 ash_msg_and_raise_error("can't open %s", fname);
9539 }
9540 if (fd < 10) {
9541 fd2 = copyfd(fd, 10);
9542 close(fd);
9543 if (fd2 < 0)
9544 ash_msg_and_raise_error("out of file descriptors");
9545 fd = fd2;
9546 }
9547 setinputfd(fd, flags & INPUT_PUSH_FILE);
9548 out:
9549 INT_ON;
9550 return fd;
9551 }
9552
9553 /*
9554 * Like setinputfile, but takes input from a string.
9555 */
9556 static void
9557 setinputstring(char *string)
9558 {
9559 INT_OFF;
9560 pushfile();
9561 parsenextc = string;
9562 parsenleft = strlen(string);
9563 g_parsefile->buf = NULL;
9564 plinno = 1;
9565 INT_ON;
9566 }
9567
9568
9569 /* ============ mail.c
9570 *
9571 * Routines to check for mail.
9572 */
9573
9574 #if ENABLE_ASH_MAIL
9575
9576 #define MAXMBOXES 10
9577
9578 /* times of mailboxes */
9579 static time_t mailtime[MAXMBOXES];
9580 /* Set if MAIL or MAILPATH is changed. */
9581 static smallint mail_var_path_changed;
9582
9583 /*
9584 * Print appropriate message(s) if mail has arrived.
9585 * If mail_var_path_changed is set,
9586 * then the value of MAIL has mail_var_path_changed,
9587 * so we just update the values.
9588 */
9589 static void
9590 chkmail(void)
9591 {
9592 const char *mpath;
9593 char *p;
9594 char *q;
9595 time_t *mtp;
9596 struct stackmark smark;
9597 struct stat statb;
9598
9599 setstackmark(&smark);
9600 mpath = mpathset() ? mpathval() : mailval();
9601 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
9602 p = padvance(&mpath, nullstr);
9603 if (p == NULL)
9604 break;
9605 if (*p == '\0')
9606 continue;
9607 for (q = p; *q; q++)
9608 continue;
9609 #if DEBUG
9610 if (q[-1] != '/')
9611 abort();
9612 #endif
9613 q[-1] = '\0'; /* delete trailing '/' */
9614 if (stat(p, &statb) < 0) {
9615 *mtp = 0;
9616 continue;
9617 }
9618 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
9619 fprintf(
9620 stderr, snlfmt,
9621 pathopt ? pathopt : "you have mail"
9622 );
9623 }
9624 *mtp = statb.st_mtime;
9625 }
9626 mail_var_path_changed = 0;
9627 popstackmark(&smark);
9628 }
9629
9630 static void
9631 changemail(const char *val UNUSED_PARAM)
9632 {
9633 mail_var_path_changed = 1;
9634 }
9635
9636 #endif /* ASH_MAIL */
9637
9638
9639 /* ============ ??? */
9640
9641 /*
9642 * Set the shell parameters.
9643 */
9644 static void
9645 setparam(char **argv)
9646 {
9647 char **newparam;
9648 char **ap;
9649 int nparam;
9650
9651 for (nparam = 0; argv[nparam]; nparam++)
9652 continue;
9653 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
9654 while (*argv) {
9655 *ap++ = ckstrdup(*argv++);
9656 }
9657 *ap = NULL;
9658 freeparam(&shellparam);
9659 shellparam.malloced = 1;
9660 shellparam.nparam = nparam;
9661 shellparam.p = newparam;
9662 #if ENABLE_ASH_GETOPTS
9663 shellparam.optind = 1;
9664 shellparam.optoff = -1;
9665 #endif
9666 }
9667
9668 /*
9669 * Process shell options. The global variable argptr contains a pointer
9670 * to the argument list; we advance it past the options.
9671 *
9672 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
9673 * For a non-interactive shell, an error condition encountered
9674 * by a special built-in ... shall cause the shell to write a diagnostic message
9675 * to standard error and exit as shown in the following table:
9676 * Error Special Built-In
9677 * ...
9678 * Utility syntax error (option or operand error) Shall exit
9679 * ...
9680 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
9681 * we see that bash does not do that (set "finishes" with error code 1 instead,
9682 * and shell continues), and people rely on this behavior!
9683 * Testcase:
9684 * set -o barfoo 2>/dev/null
9685 * echo $?
9686 *
9687 * Oh well. Let's mimic that.
9688 */
9689 static int
9690 plus_minus_o(char *name, int val)
9691 {
9692 int i;
9693
9694 if (name) {
9695 for (i = 0; i < NOPTS; i++) {
9696 if (strcmp(name, optnames(i)) == 0) {
9697 optlist[i] = val;
9698 return 0;
9699 }
9700 }
9701 ash_msg("illegal option %co %s", val ? '-' : '+', name);
9702 return 1;
9703 }
9704 for (i = 0; i < NOPTS; i++) {
9705 if (val) {
9706 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
9707 } else {
9708 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
9709 }
9710 }
9711 return 0;
9712 }
9713 static void
9714 setoption(int flag, int val)
9715 {
9716 int i;
9717
9718 for (i = 0; i < NOPTS; i++) {
9719 if (optletters(i) == flag) {
9720 optlist[i] = val;
9721 return;
9722 }
9723 }
9724 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
9725 /* NOTREACHED */
9726 }
9727 static int
9728 options(int cmdline)
9729 {
9730 char *p;
9731 int val;
9732 int c;
9733
9734 if (cmdline)
9735 minusc = NULL;
9736 while ((p = *argptr) != NULL) {
9737 c = *p++;
9738 if (c != '-' && c != '+')
9739 break;
9740 argptr++;
9741 val = 0; /* val = 0 if c == '+' */
9742 if (c == '-') {
9743 val = 1;
9744 if (p[0] == '\0' || LONE_DASH(p)) {
9745 if (!cmdline) {
9746 /* "-" means turn off -x and -v */
9747 if (p[0] == '\0')
9748 xflag = vflag = 0;
9749 /* "--" means reset params */
9750 else if (*argptr == NULL)
9751 setparam(argptr);
9752 }
9753 break; /* "-" or "--" terminates options */
9754 }
9755 }
9756 /* first char was + or - */
9757 while ((c = *p++) != '\0') {
9758 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
9759 if (c == 'c' && cmdline) {
9760 minusc = p; /* command is after shell args */
9761 } else if (c == 'o') {
9762 if (plus_minus_o(*argptr, val)) {
9763 /* it already printed err message */
9764 return 1; /* error */
9765 }
9766 if (*argptr)
9767 argptr++;
9768 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
9769 isloginsh = 1;
9770 /* bash does not accept +-login, we also won't */
9771 } else if (cmdline && val && (c == '-')) { /* long options */
9772 if (strcmp(p, "login") == 0)
9773 isloginsh = 1;
9774 break;
9775 } else {
9776 setoption(c, val);
9777 }
9778 }
9779 }
9780 return 0;
9781 }
9782
9783 /*
9784 * The shift builtin command.
9785 */
9786 static int
9787 shiftcmd(int argc UNUSED_PARAM, char **argv)
9788 {
9789 int n;
9790 char **ap1, **ap2;
9791
9792 n = 1;
9793 if (argv[1])
9794 n = number(argv[1]);
9795 if (n > shellparam.nparam)
9796 n = 0; /* bash compat, was = shellparam.nparam; */
9797 INT_OFF;
9798 shellparam.nparam -= n;
9799 for (ap1 = shellparam.p; --n >= 0; ap1++) {
9800 if (shellparam.malloced)
9801 free(*ap1);
9802 }
9803 ap2 = shellparam.p;
9804 while ((*ap2++ = *ap1++) != NULL)
9805 continue;
9806 #if ENABLE_ASH_GETOPTS
9807 shellparam.optind = 1;
9808 shellparam.optoff = -1;
9809 #endif
9810 INT_ON;
9811 return 0;
9812 }
9813
9814 /*
9815 * POSIX requires that 'set' (but not export or readonly) output the
9816 * variables in lexicographic order - by the locale's collating order (sigh).
9817 * Maybe we could keep them in an ordered balanced binary tree
9818 * instead of hashed lists.
9819 * For now just roll 'em through qsort for printing...
9820 */
9821 static int
9822 showvars(const char *sep_prefix, int on, int off)
9823 {
9824 const char *sep;
9825 char **ep, **epend;
9826
9827 ep = listvars(on, off, &epend);
9828 qsort(ep, epend - ep, sizeof(char *), vpcmp);
9829
9830 sep = *sep_prefix ? " " : sep_prefix;
9831
9832 for (; ep < epend; ep++) {
9833 const char *p;
9834 const char *q;
9835
9836 p = strchrnul(*ep, '=');
9837 q = nullstr;
9838 if (*p)
9839 q = single_quote(++p);
9840 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
9841 }
9842 return 0;
9843 }
9844
9845 /*
9846 * The set command builtin.
9847 */
9848 static int
9849 setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9850 {
9851 int retval;
9852
9853 if (!argv[1])
9854 return showvars(nullstr, 0, VUNSET);
9855 INT_OFF;
9856 retval = 1;
9857 if (!options(0)) { /* if no parse error... */
9858 retval = 0;
9859 optschanged();
9860 if (*argptr != NULL) {
9861 setparam(argptr);
9862 }
9863 }
9864 INT_ON;
9865 return retval;
9866 }
9867
9868 #if ENABLE_ASH_RANDOM_SUPPORT
9869 static void
9870 change_random(const char *value)
9871 {
9872 /* Galois LFSR parameter */
9873 /* Taps at 32 31 29 1: */
9874 enum { MASK = 0x8000000b };
9875 /* Another example - taps at 32 31 30 10: */
9876 /* MASK = 0x00400007 */
9877
9878 if (value == NULL) {
9879 /* "get", generate */
9880 uint32_t t;
9881
9882 /* LCG has period of 2^32 and alternating lowest bit */
9883 random_LCG = 1664525 * random_LCG + 1013904223;
9884 /* Galois LFSR has period of 2^32-1 = 3 * 5 * 17 * 257 * 65537 */
9885 t = (random_galois_LFSR << 1);
9886 if (random_galois_LFSR < 0) /* if we just shifted 1 out of msb... */
9887 t ^= MASK;
9888 random_galois_LFSR = t;
9889 /* Both are weak, combining them gives better randomness
9890 * and ~2^64 period. & 0x7fff is probably bash compat
9891 * for $RANDOM range. Combining with subtraction is
9892 * just for fun. + and ^ would work equally well. */
9893 t = (t - random_LCG) & 0x7fff;
9894 /* set without recursion */
9895 setvar(vrandom.text, utoa(t), VNOFUNC);
9896 vrandom.flags &= ~VNOFUNC;
9897 } else {
9898 /* set/reset */
9899 random_galois_LFSR = random_LCG = strtoul(value, (char **)NULL, 10);
9900 }
9901 }
9902 #endif
9903
9904 #if ENABLE_ASH_GETOPTS
9905 static int
9906 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
9907 {
9908 char *p, *q;
9909 char c = '?';
9910 int done = 0;
9911 int err = 0;
9912 char s[12];
9913 char **optnext;
9914
9915 if (*param_optind < 1)
9916 return 1;
9917 optnext = optfirst + *param_optind - 1;
9918
9919 if (*param_optind <= 1 || *optoff < 0 || (int)strlen(optnext[-1]) < *optoff)
9920 p = NULL;
9921 else
9922 p = optnext[-1] + *optoff;
9923 if (p == NULL || *p == '\0') {
9924 /* Current word is done, advance */
9925 p = *optnext;
9926 if (p == NULL || *p != '-' || *++p == '\0') {
9927 atend:
9928 p = NULL;
9929 done = 1;
9930 goto out;
9931 }
9932 optnext++;
9933 if (LONE_DASH(p)) /* check for "--" */
9934 goto atend;
9935 }
9936
9937 c = *p++;
9938 for (q = optstr; *q != c;) {
9939 if (*q == '\0') {
9940 if (optstr[0] == ':') {
9941 s[0] = c;
9942 s[1] = '\0';
9943 err |= setvarsafe("OPTARG", s, 0);
9944 } else {
9945 fprintf(stderr, "Illegal option -%c\n", c);
9946 unsetvar("OPTARG");
9947 }
9948 c = '?';
9949 goto out;
9950 }
9951 if (*++q == ':')
9952 q++;
9953 }
9954
9955 if (*++q == ':') {
9956 if (*p == '\0' && (p = *optnext) == NULL) {
9957 if (optstr[0] == ':') {
9958 s[0] = c;
9959 s[1] = '\0';
9960 err |= setvarsafe("OPTARG", s, 0);
9961 c = ':';
9962 } else {
9963 fprintf(stderr, "No arg for -%c option\n", c);
9964 unsetvar("OPTARG");
9965 c = '?';
9966 }
9967 goto out;
9968 }
9969
9970 if (p == *optnext)
9971 optnext++;
9972 err |= setvarsafe("OPTARG", p, 0);
9973 p = NULL;
9974 } else
9975 err |= setvarsafe("OPTARG", nullstr, 0);
9976 out:
9977 *optoff = p ? p - *(optnext - 1) : -1;
9978 *param_optind = optnext - optfirst + 1;
9979 fmtstr(s, sizeof(s), "%d", *param_optind);
9980 err |= setvarsafe("OPTIND", s, VNOFUNC);
9981 s[0] = c;
9982 s[1] = '\0';
9983 err |= setvarsafe(optvar, s, 0);
9984 if (err) {
9985 *param_optind = 1;
9986 *optoff = -1;
9987 flush_stdout_stderr();
9988 raise_exception(EXERROR);
9989 }
9990 return done;
9991 }
9992
9993 /*
9994 * The getopts builtin. Shellparam.optnext points to the next argument
9995 * to be processed. Shellparam.optptr points to the next character to
9996 * be processed in the current argument. If shellparam.optnext is NULL,
9997 * then it's the first time getopts has been called.
9998 */
9999 static int
10000 getoptscmd(int argc, char **argv)
10001 {
10002 char **optbase;
10003
10004 if (argc < 3)
10005 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
10006 if (argc == 3) {
10007 optbase = shellparam.p;
10008 if (shellparam.optind > shellparam.nparam + 1) {
10009 shellparam.optind = 1;
10010 shellparam.optoff = -1;
10011 }
10012 } else {
10013 optbase = &argv[3];
10014 if (shellparam.optind > argc - 2) {
10015 shellparam.optind = 1;
10016 shellparam.optoff = -1;
10017 }
10018 }
10019
10020 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
10021 &shellparam.optoff);
10022 }
10023 #endif /* ASH_GETOPTS */
10024
10025
10026 /* ============ Shell parser */
10027
10028 struct heredoc {
10029 struct heredoc *next; /* next here document in list */
10030 union node *here; /* redirection node */
10031 char *eofmark; /* string indicating end of input */
10032 smallint striptabs; /* if set, strip leading tabs */
10033 };
10034
10035 static smallint tokpushback; /* last token pushed back */
10036 static smallint parsebackquote; /* nonzero if we are inside backquotes */
10037 static smallint quoteflag; /* set if (part of) last token was quoted */
10038 static token_id_t lasttoken; /* last token read (integer id Txxx) */
10039 static struct heredoc *heredoclist; /* list of here documents to read */
10040 static char *wordtext; /* text of last word returned by readtoken */
10041 static struct nodelist *backquotelist;
10042 static union node *redirnode;
10043 static struct heredoc *heredoc;
10044 /*
10045 * NEOF is returned by parsecmd when it encounters an end of file. It
10046 * must be distinct from NULL, so we use the address of a variable that
10047 * happens to be handy.
10048 */
10049 #define NEOF ((union node *)&tokpushback)
10050
10051 static void raise_error_syntax(const char *) NORETURN;
10052 static void
10053 raise_error_syntax(const char *msg)
10054 {
10055 ash_msg_and_raise_error("syntax error: %s", msg);
10056 /* NOTREACHED */
10057 }
10058
10059 /*
10060 * Called when an unexpected token is read during the parse. The argument
10061 * is the token that is expected, or -1 if more than one type of token can
10062 * occur at this point.
10063 */
10064 static void raise_error_unexpected_syntax(int) NORETURN;
10065 static void
10066 raise_error_unexpected_syntax(int token)
10067 {
10068 char msg[64];
10069 int l;
10070
10071 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10072 if (token >= 0)
10073 sprintf(msg + l, " (expecting %s)", tokname(token));
10074 raise_error_syntax(msg);
10075 /* NOTREACHED */
10076 }
10077
10078 #define EOFMARKLEN 79
10079
10080 /* parsing is heavily cross-recursive, need these forward decls */
10081 static union node *andor(void);
10082 static union node *pipeline(void);
10083 static union node *parse_command(void);
10084 static void parseheredoc(void);
10085 static char peektoken(void);
10086 static int readtoken(void);
10087
10088 static union node *
10089 list(int nlflag)
10090 {
10091 union node *n1, *n2, *n3;
10092 int tok;
10093
10094 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10095 if (nlflag == 2 && peektoken())
10096 return NULL;
10097 n1 = NULL;
10098 for (;;) {
10099 n2 = andor();
10100 tok = readtoken();
10101 if (tok == TBACKGND) {
10102 if (n2->type == NPIPE) {
10103 n2->npipe.pipe_backgnd = 1;
10104 } else {
10105 if (n2->type != NREDIR) {
10106 n3 = stzalloc(sizeof(struct nredir));
10107 n3->nredir.n = n2;
10108 /*n3->nredir.redirect = NULL; - stzalloc did it */
10109 n2 = n3;
10110 }
10111 n2->type = NBACKGND;
10112 }
10113 }
10114 if (n1 == NULL) {
10115 n1 = n2;
10116 } else {
10117 n3 = stzalloc(sizeof(struct nbinary));
10118 n3->type = NSEMI;
10119 n3->nbinary.ch1 = n1;
10120 n3->nbinary.ch2 = n2;
10121 n1 = n3;
10122 }
10123 switch (tok) {
10124 case TBACKGND:
10125 case TSEMI:
10126 tok = readtoken();
10127 /* fall through */
10128 case TNL:
10129 if (tok == TNL) {
10130 parseheredoc();
10131 if (nlflag == 1)
10132 return n1;
10133 } else {
10134 tokpushback = 1;
10135 }
10136 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10137 if (peektoken())
10138 return n1;
10139 break;
10140 case TEOF:
10141 if (heredoclist)
10142 parseheredoc();
10143 else
10144 pungetc(); /* push back EOF on input */
10145 return n1;
10146 default:
10147 if (nlflag == 1)
10148 raise_error_unexpected_syntax(-1);
10149 tokpushback = 1;
10150 return n1;
10151 }
10152 }
10153 }
10154
10155 static union node *
10156 andor(void)
10157 {
10158 union node *n1, *n2, *n3;
10159 int t;
10160
10161 n1 = pipeline();
10162 for (;;) {
10163 t = readtoken();
10164 if (t == TAND) {
10165 t = NAND;
10166 } else if (t == TOR) {
10167 t = NOR;
10168 } else {
10169 tokpushback = 1;
10170 return n1;
10171 }
10172 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10173 n2 = pipeline();
10174 n3 = stzalloc(sizeof(struct nbinary));
10175 n3->type = t;
10176 n3->nbinary.ch1 = n1;
10177 n3->nbinary.ch2 = n2;
10178 n1 = n3;
10179 }
10180 }
10181
10182 static union node *
10183 pipeline(void)
10184 {
10185 union node *n1, *n2, *pipenode;
10186 struct nodelist *lp, *prev;
10187 int negate;
10188
10189 negate = 0;
10190 TRACE(("pipeline: entered\n"));
10191 if (readtoken() == TNOT) {
10192 negate = !negate;
10193 checkkwd = CHKKWD | CHKALIAS;
10194 } else
10195 tokpushback = 1;
10196 n1 = parse_command();
10197 if (readtoken() == TPIPE) {
10198 pipenode = stzalloc(sizeof(struct npipe));
10199 pipenode->type = NPIPE;
10200 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
10201 lp = stzalloc(sizeof(struct nodelist));
10202 pipenode->npipe.cmdlist = lp;
10203 lp->n = n1;
10204 do {
10205 prev = lp;
10206 lp = stzalloc(sizeof(struct nodelist));
10207 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10208 lp->n = parse_command();
10209 prev->next = lp;
10210 } while (readtoken() == TPIPE);
10211 lp->next = NULL;
10212 n1 = pipenode;
10213 }
10214 tokpushback = 1;
10215 if (negate) {
10216 n2 = stzalloc(sizeof(struct nnot));
10217 n2->type = NNOT;
10218 n2->nnot.com = n1;
10219 return n2;
10220 }
10221 return n1;
10222 }
10223
10224 static union node *
10225 makename(void)
10226 {
10227 union node *n;
10228
10229 n = stzalloc(sizeof(struct narg));
10230 n->type = NARG;
10231 /*n->narg.next = NULL; - stzalloc did it */
10232 n->narg.text = wordtext;
10233 n->narg.backquote = backquotelist;
10234 return n;
10235 }
10236
10237 static void
10238 fixredir(union node *n, const char *text, int err)
10239 {
10240 int fd;
10241
10242 TRACE(("Fix redir %s %d\n", text, err));
10243 if (!err)
10244 n->ndup.vname = NULL;
10245
10246 fd = bb_strtou(text, NULL, 10);
10247 if (!errno && fd >= 0)
10248 n->ndup.dupfd = fd;
10249 else if (LONE_DASH(text))
10250 n->ndup.dupfd = -1;
10251 else {
10252 if (err)
10253 raise_error_syntax("bad fd number");
10254 n->ndup.vname = makename();
10255 }
10256 }
10257
10258 /*
10259 * Returns true if the text contains nothing to expand (no dollar signs
10260 * or backquotes).
10261 */
10262 static int
10263 noexpand(char *text)
10264 {
10265 char *p;
10266 char c;
10267
10268 p = text;
10269 while ((c = *p++) != '\0') {
10270 if (c == CTLQUOTEMARK)
10271 continue;
10272 if (c == CTLESC)
10273 p++;
10274 else if (SIT(c, BASESYNTAX) == CCTL)
10275 return 0;
10276 }
10277 return 1;
10278 }
10279
10280 static void
10281 parsefname(void)
10282 {
10283 union node *n = redirnode;
10284
10285 if (readtoken() != TWORD)
10286 raise_error_unexpected_syntax(-1);
10287 if (n->type == NHERE) {
10288 struct heredoc *here = heredoc;
10289 struct heredoc *p;
10290 int i;
10291
10292 if (quoteflag == 0)
10293 n->type = NXHERE;
10294 TRACE(("Here document %d\n", n->type));
10295 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
10296 raise_error_syntax("illegal eof marker for << redirection");
10297 rmescapes(wordtext);
10298 here->eofmark = wordtext;
10299 here->next = NULL;
10300 if (heredoclist == NULL)
10301 heredoclist = here;
10302 else {
10303 for (p = heredoclist; p->next; p = p->next)
10304 continue;
10305 p->next = here;
10306 }
10307 } else if (n->type == NTOFD || n->type == NFROMFD) {
10308 fixredir(n, wordtext, 0);
10309 } else {
10310 n->nfile.fname = makename();
10311 }
10312 }
10313
10314 static union node *
10315 simplecmd(void)
10316 {
10317 union node *args, **app;
10318 union node *n = NULL;
10319 union node *vars, **vpp;
10320 union node **rpp, *redir;
10321 int savecheckkwd;
10322 #if ENABLE_ASH_BASH_COMPAT
10323 smallint double_brackets_flag = 0;
10324 #endif
10325
10326 args = NULL;
10327 app = &args;
10328 vars = NULL;
10329 vpp = &vars;
10330 redir = NULL;
10331 rpp = &redir;
10332
10333 savecheckkwd = CHKALIAS;
10334 for (;;) {
10335 int t;
10336 checkkwd = savecheckkwd;
10337 t = readtoken();
10338 switch (t) {
10339 #if ENABLE_ASH_BASH_COMPAT
10340 case TAND: /* "&&" */
10341 case TOR: /* "||" */
10342 if (!double_brackets_flag) {
10343 tokpushback = 1;
10344 goto out;
10345 }
10346 wordtext = (char *) (t == TAND ? "-a" : "-o");
10347 #endif
10348 case TWORD:
10349 n = stzalloc(sizeof(struct narg));
10350 n->type = NARG;
10351 /*n->narg.next = NULL; - stzalloc did it */
10352 n->narg.text = wordtext;
10353 #if ENABLE_ASH_BASH_COMPAT
10354 if (strcmp("[[", wordtext) == 0)
10355 double_brackets_flag = 1;
10356 else if (strcmp("]]", wordtext) == 0)
10357 double_brackets_flag = 0;
10358 #endif
10359 n->narg.backquote = backquotelist;
10360 if (savecheckkwd && isassignment(wordtext)) {
10361 *vpp = n;
10362 vpp = &n->narg.next;
10363 } else {
10364 *app = n;
10365 app = &n->narg.next;
10366 savecheckkwd = 0;
10367 }
10368 break;
10369 case TREDIR:
10370 *rpp = n = redirnode;
10371 rpp = &n->nfile.next;
10372 parsefname(); /* read name of redirection file */
10373 break;
10374 case TLP:
10375 if (args && app == &args->narg.next
10376 && !vars && !redir
10377 ) {
10378 struct builtincmd *bcmd;
10379 const char *name;
10380
10381 /* We have a function */
10382 if (readtoken() != TRP)
10383 raise_error_unexpected_syntax(TRP);
10384 name = n->narg.text;
10385 if (!goodname(name)
10386 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
10387 ) {
10388 raise_error_syntax("bad function name");
10389 }
10390 n->type = NDEFUN;
10391 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10392 n->narg.next = parse_command();
10393 return n;
10394 }
10395 /* fall through */
10396 default:
10397 tokpushback = 1;
10398 goto out;
10399 }
10400 }
10401 out:
10402 *app = NULL;
10403 *vpp = NULL;
10404 *rpp = NULL;
10405 n = stzalloc(sizeof(struct ncmd));
10406 n->type = NCMD;
10407 n->ncmd.args = args;
10408 n->ncmd.assign = vars;
10409 n->ncmd.redirect = redir;
10410 return n;
10411 }
10412
10413 static union node *
10414 parse_command(void)
10415 {
10416 union node *n1, *n2;
10417 union node *ap, **app;
10418 union node *cp, **cpp;
10419 union node *redir, **rpp;
10420 union node **rpp2;
10421 int t;
10422
10423 redir = NULL;
10424 rpp2 = &redir;
10425
10426 switch (readtoken()) {
10427 default:
10428 raise_error_unexpected_syntax(-1);
10429 /* NOTREACHED */
10430 case TIF:
10431 n1 = stzalloc(sizeof(struct nif));
10432 n1->type = NIF;
10433 n1->nif.test = list(0);
10434 if (readtoken() != TTHEN)
10435 raise_error_unexpected_syntax(TTHEN);
10436 n1->nif.ifpart = list(0);
10437 n2 = n1;
10438 while (readtoken() == TELIF) {
10439 n2->nif.elsepart = stzalloc(sizeof(struct nif));
10440 n2 = n2->nif.elsepart;
10441 n2->type = NIF;
10442 n2->nif.test = list(0);
10443 if (readtoken() != TTHEN)
10444 raise_error_unexpected_syntax(TTHEN);
10445 n2->nif.ifpart = list(0);
10446 }
10447 if (lasttoken == TELSE)
10448 n2->nif.elsepart = list(0);
10449 else {
10450 n2->nif.elsepart = NULL;
10451 tokpushback = 1;
10452 }
10453 t = TFI;
10454 break;
10455 case TWHILE:
10456 case TUNTIL: {
10457 int got;
10458 n1 = stzalloc(sizeof(struct nbinary));
10459 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
10460 n1->nbinary.ch1 = list(0);
10461 got = readtoken();
10462 if (got != TDO) {
10463 TRACE(("expecting DO got %s %s\n", tokname(got),
10464 got == TWORD ? wordtext : ""));
10465 raise_error_unexpected_syntax(TDO);
10466 }
10467 n1->nbinary.ch2 = list(0);
10468 t = TDONE;
10469 break;
10470 }
10471 case TFOR:
10472 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
10473 raise_error_syntax("bad for loop variable");
10474 n1 = stzalloc(sizeof(struct nfor));
10475 n1->type = NFOR;
10476 n1->nfor.var = wordtext;
10477 checkkwd = CHKKWD | CHKALIAS;
10478 if (readtoken() == TIN) {
10479 app = &ap;
10480 while (readtoken() == TWORD) {
10481 n2 = stzalloc(sizeof(struct narg));
10482 n2->type = NARG;
10483 /*n2->narg.next = NULL; - stzalloc did it */
10484 n2->narg.text = wordtext;
10485 n2->narg.backquote = backquotelist;
10486 *app = n2;
10487 app = &n2->narg.next;
10488 }
10489 *app = NULL;
10490 n1->nfor.args = ap;
10491 if (lasttoken != TNL && lasttoken != TSEMI)
10492 raise_error_unexpected_syntax(-1);
10493 } else {
10494 n2 = stzalloc(sizeof(struct narg));
10495 n2->type = NARG;
10496 /*n2->narg.next = NULL; - stzalloc did it */
10497 n2->narg.text = (char *)dolatstr;
10498 /*n2->narg.backquote = NULL;*/
10499 n1->nfor.args = n2;
10500 /*
10501 * Newline or semicolon here is optional (but note
10502 * that the original Bourne shell only allowed NL).
10503 */
10504 if (lasttoken != TNL && lasttoken != TSEMI)
10505 tokpushback = 1;
10506 }
10507 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10508 if (readtoken() != TDO)
10509 raise_error_unexpected_syntax(TDO);
10510 n1->nfor.body = list(0);
10511 t = TDONE;
10512 break;
10513 case TCASE:
10514 n1 = stzalloc(sizeof(struct ncase));
10515 n1->type = NCASE;
10516 if (readtoken() != TWORD)
10517 raise_error_unexpected_syntax(TWORD);
10518 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
10519 n2->type = NARG;
10520 /*n2->narg.next = NULL; - stzalloc did it */
10521 n2->narg.text = wordtext;
10522 n2->narg.backquote = backquotelist;
10523 do {
10524 checkkwd = CHKKWD | CHKALIAS;
10525 } while (readtoken() == TNL);
10526 if (lasttoken != TIN)
10527 raise_error_unexpected_syntax(TIN);
10528 cpp = &n1->ncase.cases;
10529 next_case:
10530 checkkwd = CHKNL | CHKKWD;
10531 t = readtoken();
10532 while (t != TESAC) {
10533 if (lasttoken == TLP)
10534 readtoken();
10535 *cpp = cp = stzalloc(sizeof(struct nclist));
10536 cp->type = NCLIST;
10537 app = &cp->nclist.pattern;
10538 for (;;) {
10539 *app = ap = stzalloc(sizeof(struct narg));
10540 ap->type = NARG;
10541 /*ap->narg.next = NULL; - stzalloc did it */
10542 ap->narg.text = wordtext;
10543 ap->narg.backquote = backquotelist;
10544 if (readtoken() != TPIPE)
10545 break;
10546 app = &ap->narg.next;
10547 readtoken();
10548 }
10549 //ap->narg.next = NULL;
10550 if (lasttoken != TRP)
10551 raise_error_unexpected_syntax(TRP);
10552 cp->nclist.body = list(2);
10553
10554 cpp = &cp->nclist.next;
10555
10556 checkkwd = CHKNL | CHKKWD;
10557 t = readtoken();
10558 if (t != TESAC) {
10559 if (t != TENDCASE)
10560 raise_error_unexpected_syntax(TENDCASE);
10561 goto next_case;
10562 }
10563 }
10564 *cpp = NULL;
10565 goto redir;
10566 case TLP:
10567 n1 = stzalloc(sizeof(struct nredir));
10568 n1->type = NSUBSHELL;
10569 n1->nredir.n = list(0);
10570 /*n1->nredir.redirect = NULL; - stzalloc did it */
10571 t = TRP;
10572 break;
10573 case TBEGIN:
10574 n1 = list(0);
10575 t = TEND;
10576 break;
10577 case TWORD:
10578 case TREDIR:
10579 tokpushback = 1;
10580 return simplecmd();
10581 }
10582
10583 if (readtoken() != t)
10584 raise_error_unexpected_syntax(t);
10585
10586 redir:
10587 /* Now check for redirection which may follow command */
10588 checkkwd = CHKKWD | CHKALIAS;
10589 rpp = rpp2;
10590 while (readtoken() == TREDIR) {
10591 *rpp = n2 = redirnode;
10592 rpp = &n2->nfile.next;
10593 parsefname();
10594 }
10595 tokpushback = 1;
10596 *rpp = NULL;
10597 if (redir) {
10598 if (n1->type != NSUBSHELL) {
10599 n2 = stzalloc(sizeof(struct nredir));
10600 n2->type = NREDIR;
10601 n2->nredir.n = n1;
10602 n1 = n2;
10603 }
10604 n1->nredir.redirect = redir;
10605 }
10606 return n1;
10607 }
10608
10609 #if ENABLE_ASH_BASH_COMPAT
10610 static int decode_dollar_squote(void)
10611 {
10612 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
10613 int c, cnt;
10614 char *p;
10615 char buf[4];
10616
10617 c = pgetc();
10618 p = strchr(C_escapes, c);
10619 if (p) {
10620 buf[0] = c;
10621 p = buf;
10622 cnt = 3;
10623 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
10624 do {
10625 c = pgetc();
10626 *++p = c;
10627 } while ((unsigned char)(c - '0') <= 7 && --cnt);
10628 pungetc();
10629 } else if (c == 'x') { /* \xHH */
10630 do {
10631 c = pgetc();
10632 *++p = c;
10633 } while (isxdigit(c) && --cnt);
10634 pungetc();
10635 if (cnt == 3) { /* \x but next char is "bad" */
10636 c = 'x';
10637 goto unrecognized;
10638 }
10639 } else { /* simple seq like \\ or \t */
10640 p++;
10641 }
10642 *p = '\0';
10643 p = buf;
10644 c = bb_process_escape_sequence((void*)&p);
10645 } else { /* unrecognized "\z": print both chars unless ' or " */
10646 if (c != '\'' && c != '"') {
10647 unrecognized:
10648 c |= 0x100; /* "please encode \, then me" */
10649 }
10650 }
10651 return c;
10652 }
10653 #endif
10654
10655 /*
10656 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10657 * is not NULL, read a here document. In the latter case, eofmark is the
10658 * word which marks the end of the document and striptabs is true if
10659 * leading tabs should be stripped from the document. The argument firstc
10660 * is the first character of the input token or document.
10661 *
10662 * Because C does not have internal subroutines, I have simulated them
10663 * using goto's to implement the subroutine linkage. The following macros
10664 * will run code that appears at the end of readtoken1.
10665 */
10666 #define CHECKEND() {goto checkend; checkend_return:;}
10667 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
10668 #define PARSESUB() {goto parsesub; parsesub_return:;}
10669 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10670 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10671 #define PARSEARITH() {goto parsearith; parsearith_return:;}
10672 static int
10673 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10674 {
10675 /* NB: syntax parameter fits into smallint */
10676 int c = firstc;
10677 char *out;
10678 int len;
10679 char line[EOFMARKLEN + 1];
10680 struct nodelist *bqlist;
10681 smallint quotef;
10682 smallint dblquote;
10683 smallint oldstyle;
10684 smallint prevsyntax; /* syntax before arithmetic */
10685 #if ENABLE_ASH_EXPAND_PRMT
10686 smallint pssyntax; /* we are expanding a prompt string */
10687 #endif
10688 int varnest; /* levels of variables expansion */
10689 int arinest; /* levels of arithmetic expansion */
10690 int parenlevel; /* levels of parens in arithmetic */
10691 int dqvarnest; /* levels of variables expansion within double quotes */
10692
10693 USE_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
10694
10695 #if __GNUC__
10696 /* Avoid longjmp clobbering */
10697 (void) &out;
10698 (void) &quotef;
10699 (void) &dblquote;
10700 (void) &varnest;
10701 (void) &arinest;
10702 (void) &parenlevel;
10703 (void) &dqvarnest;
10704 (void) &oldstyle;
10705 (void) &prevsyntax;
10706 (void) &syntax;
10707 #endif
10708 startlinno = plinno;
10709 bqlist = NULL;
10710 quotef = 0;
10711 oldstyle = 0;
10712 prevsyntax = 0;
10713 #if ENABLE_ASH_EXPAND_PRMT
10714 pssyntax = (syntax == PSSYNTAX);
10715 if (pssyntax)
10716 syntax = DQSYNTAX;
10717 #endif
10718 dblquote = (syntax == DQSYNTAX);
10719 varnest = 0;
10720 arinest = 0;
10721 parenlevel = 0;
10722 dqvarnest = 0;
10723
10724 STARTSTACKSTR(out);
10725 loop:
10726 /* For each line, until end of word */
10727 {
10728 CHECKEND(); /* set c to PEOF if at end of here document */
10729 for (;;) { /* until end of line or end of word */
10730 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10731 switch (SIT(c, syntax)) {
10732 case CNL: /* '\n' */
10733 if (syntax == BASESYNTAX)
10734 goto endword; /* exit outer loop */
10735 USTPUTC(c, out);
10736 plinno++;
10737 if (doprompt)
10738 setprompt(2);
10739 c = pgetc();
10740 goto loop; /* continue outer loop */
10741 case CWORD:
10742 USTPUTC(c, out);
10743 break;
10744 case CCTL:
10745 if (eofmark == NULL || dblquote)
10746 USTPUTC(CTLESC, out);
10747 #if ENABLE_ASH_BASH_COMPAT
10748 if (c == '\\' && bash_dollar_squote) {
10749 c = decode_dollar_squote();
10750 if (c & 0x100) {
10751 USTPUTC('\\', out);
10752 c = (unsigned char)c;
10753 }
10754 }
10755 #endif
10756 USTPUTC(c, out);
10757 break;
10758 case CBACK: /* backslash */
10759 c = pgetc2();
10760 if (c == PEOF) {
10761 USTPUTC(CTLESC, out);
10762 USTPUTC('\\', out);
10763 pungetc();
10764 } else if (c == '\n') {
10765 if (doprompt)
10766 setprompt(2);
10767 } else {
10768 #if ENABLE_ASH_EXPAND_PRMT
10769 if (c == '$' && pssyntax) {
10770 USTPUTC(CTLESC, out);
10771 USTPUTC('\\', out);
10772 }
10773 #endif
10774 if (dblquote && c != '\\'
10775 && c != '`' && c != '$'
10776 && (c != '"' || eofmark != NULL)
10777 ) {
10778 USTPUTC(CTLESC, out);
10779 USTPUTC('\\', out);
10780 }
10781 if (SIT(c, SQSYNTAX) == CCTL)
10782 USTPUTC(CTLESC, out);
10783 USTPUTC(c, out);
10784 quotef = 1;
10785 }
10786 break;
10787 case CSQUOTE:
10788 syntax = SQSYNTAX;
10789 quotemark:
10790 if (eofmark == NULL) {
10791 USTPUTC(CTLQUOTEMARK, out);
10792 }
10793 break;
10794 case CDQUOTE:
10795 syntax = DQSYNTAX;
10796 dblquote = 1;
10797 goto quotemark;
10798 case CENDQUOTE:
10799 USE_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
10800 if (eofmark != NULL && arinest == 0
10801 && varnest == 0
10802 ) {
10803 USTPUTC(c, out);
10804 } else {
10805 if (dqvarnest == 0) {
10806 syntax = BASESYNTAX;
10807 dblquote = 0;
10808 }
10809 quotef = 1;
10810 goto quotemark;
10811 }
10812 break;
10813 case CVAR: /* '$' */
10814 PARSESUB(); /* parse substitution */
10815 break;
10816 case CENDVAR: /* '}' */
10817 if (varnest > 0) {
10818 varnest--;
10819 if (dqvarnest > 0) {
10820 dqvarnest--;
10821 }
10822 USTPUTC(CTLENDVAR, out);
10823 } else {
10824 USTPUTC(c, out);
10825 }
10826 break;
10827 #if ENABLE_ASH_MATH_SUPPORT
10828 case CLP: /* '(' in arithmetic */
10829 parenlevel++;
10830 USTPUTC(c, out);
10831 break;
10832 case CRP: /* ')' in arithmetic */
10833 if (parenlevel > 0) {
10834 USTPUTC(c, out);
10835 --parenlevel;
10836 } else {
10837 if (pgetc() == ')') {
10838 if (--arinest == 0) {
10839 USTPUTC(CTLENDARI, out);
10840 syntax = prevsyntax;
10841 dblquote = (syntax == DQSYNTAX);
10842 } else
10843 USTPUTC(')', out);
10844 } else {
10845 /*
10846 * unbalanced parens
10847 * (don't 2nd guess - no error)
10848 */
10849 pungetc();
10850 USTPUTC(')', out);
10851 }
10852 }
10853 break;
10854 #endif
10855 case CBQUOTE: /* '`' */
10856 PARSEBACKQOLD();
10857 break;
10858 case CENDFILE:
10859 goto endword; /* exit outer loop */
10860 case CIGN:
10861 break;
10862 default:
10863 if (varnest == 0) {
10864 #if ENABLE_ASH_BASH_COMPAT
10865 if (c == '&') {
10866 if (pgetc() == '>')
10867 c = 0x100 + '>'; /* flag &> */
10868 pungetc();
10869 }
10870 #endif
10871 goto endword; /* exit outer loop */
10872 }
10873 #if ENABLE_ASH_ALIAS
10874 if (c != PEOA)
10875 #endif
10876 USTPUTC(c, out);
10877
10878 }
10879 c = pgetc_fast();
10880 } /* for (;;) */
10881 }
10882 endword:
10883 #if ENABLE_ASH_MATH_SUPPORT
10884 if (syntax == ARISYNTAX)
10885 raise_error_syntax("missing '))'");
10886 #endif
10887 if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
10888 raise_error_syntax("unterminated quoted string");
10889 if (varnest != 0) {
10890 startlinno = plinno;
10891 /* { */
10892 raise_error_syntax("missing '}'");
10893 }
10894 USTPUTC('\0', out);
10895 len = out - (char *)stackblock();
10896 out = stackblock();
10897 if (eofmark == NULL) {
10898 if ((c == '>' || c == '<' USE_ASH_BASH_COMPAT( || c == 0x100 + '>'))
10899 && quotef == 0
10900 ) {
10901 if (isdigit_str9(out)) {
10902 PARSEREDIR(); /* passed as params: out, c */
10903 lasttoken = TREDIR;
10904 return lasttoken;
10905 }
10906 /* else: non-number X seen, interpret it
10907 * as "NNNX>file" = "NNNX >file" */
10908 }
10909 pungetc();
10910 }
10911 quoteflag = quotef;
10912 backquotelist = bqlist;
10913 grabstackblock(len);
10914 wordtext = out;
10915 lasttoken = TWORD;
10916 return lasttoken;
10917 /* end of readtoken routine */
10918
10919 /*
10920 * Check to see whether we are at the end of the here document. When this
10921 * is called, c is set to the first character of the next input line. If
10922 * we are at the end of the here document, this routine sets the c to PEOF.
10923 */
10924 checkend: {
10925 if (eofmark) {
10926 #if ENABLE_ASH_ALIAS
10927 if (c == PEOA) {
10928 c = pgetc2();
10929 }
10930 #endif
10931 if (striptabs) {
10932 while (c == '\t') {
10933 c = pgetc2();
10934 }
10935 }
10936 if (c == *eofmark) {
10937 if (pfgets(line, sizeof(line)) != NULL) {
10938 char *p, *q;
10939
10940 p = line;
10941 for (q = eofmark + 1; *q && *p == *q; p++, q++)
10942 continue;
10943 if (*p == '\n' && *q == '\0') {
10944 c = PEOF;
10945 plinno++;
10946 needprompt = doprompt;
10947 } else {
10948 pushstring(line, NULL);
10949 }
10950 }
10951 }
10952 }
10953 goto checkend_return;
10954 }
10955
10956 /*
10957 * Parse a redirection operator. The variable "out" points to a string
10958 * specifying the fd to be redirected. The variable "c" contains the
10959 * first character of the redirection operator.
10960 */
10961 parseredir: {
10962 /* out is already checked to be a valid number or "" */
10963 int fd = (*out == '\0' ? -1 : atoi(out));
10964 union node *np;
10965
10966 np = stzalloc(sizeof(struct nfile));
10967 if (c == '>') {
10968 np->nfile.fd = 1;
10969 c = pgetc();
10970 if (c == '>')
10971 np->type = NAPPEND;
10972 else if (c == '|')
10973 np->type = NCLOBBER;
10974 else if (c == '&')
10975 np->type = NTOFD;
10976 /* it also can be NTO2 (>&file), but we can't figure it out yet */
10977 else {
10978 np->type = NTO;
10979 pungetc();
10980 }
10981 }
10982 #if ENABLE_ASH_BASH_COMPAT
10983 else if (c == 0x100 + '>') { /* this flags &> redirection */
10984 np->nfile.fd = 1;
10985 pgetc(); /* this is '>', no need to check */
10986 np->type = NTO2;
10987 }
10988 #endif
10989 else { /* c == '<' */
10990 /*np->nfile.fd = 0; - stzalloc did it */
10991 c = pgetc();
10992 switch (c) {
10993 case '<':
10994 if (sizeof(struct nfile) != sizeof(struct nhere)) {
10995 np = stzalloc(sizeof(struct nhere));
10996 /*np->nfile.fd = 0; - stzalloc did it */
10997 }
10998 np->type = NHERE;
10999 heredoc = stzalloc(sizeof(struct heredoc));
11000 heredoc->here = np;
11001 c = pgetc();
11002 if (c == '-') {
11003 heredoc->striptabs = 1;
11004 } else {
11005 /*heredoc->striptabs = 0; - stzalloc did it */
11006 pungetc();
11007 }
11008 break;
11009
11010 case '&':
11011 np->type = NFROMFD;
11012 break;
11013
11014 case '>':
11015 np->type = NFROMTO;
11016 break;
11017
11018 default:
11019 np->type = NFROM;
11020 pungetc();
11021 break;
11022 }
11023 }
11024 if (fd >= 0)
11025 np->nfile.fd = fd;
11026 redirnode = np;
11027 goto parseredir_return;
11028 }
11029
11030 /*
11031 * Parse a substitution. At this point, we have read the dollar sign
11032 * and nothing else.
11033 */
11034
11035 /* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11036 * (assuming ascii char codes, as the original implementation did) */
11037 #define is_special(c) \
11038 (((unsigned)(c) - 33 < 32) \
11039 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
11040 parsesub: {
11041 int subtype;
11042 int typeloc;
11043 int flags;
11044 char *p;
11045 static const char types[] ALIGN1 = "}-+?=";
11046
11047 c = pgetc();
11048 if (c <= PEOA_OR_PEOF
11049 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
11050 ) {
11051 #if ENABLE_ASH_BASH_COMPAT
11052 if (c == '\'')
11053 bash_dollar_squote = 1;
11054 else
11055 #endif
11056 USTPUTC('$', out);
11057 pungetc();
11058 } else if (c == '(') { /* $(command) or $((arith)) */
11059 if (pgetc() == '(') {
11060 #if ENABLE_ASH_MATH_SUPPORT
11061 PARSEARITH();
11062 #else
11063 raise_error_syntax("you disabled math support for $((arith)) syntax");
11064 #endif
11065 } else {
11066 pungetc();
11067 PARSEBACKQNEW();
11068 }
11069 } else {
11070 USTPUTC(CTLVAR, out);
11071 typeloc = out - (char *)stackblock();
11072 USTPUTC(VSNORMAL, out);
11073 subtype = VSNORMAL;
11074 if (c == '{') {
11075 c = pgetc();
11076 if (c == '#') {
11077 c = pgetc();
11078 if (c == '}')
11079 c = '#';
11080 else
11081 subtype = VSLENGTH;
11082 } else
11083 subtype = 0;
11084 }
11085 if (c > PEOA_OR_PEOF && is_name(c)) {
11086 do {
11087 STPUTC(c, out);
11088 c = pgetc();
11089 } while (c > PEOA_OR_PEOF && is_in_name(c));
11090 } else if (isdigit(c)) {
11091 do {
11092 STPUTC(c, out);
11093 c = pgetc();
11094 } while (isdigit(c));
11095 } else if (is_special(c)) {
11096 USTPUTC(c, out);
11097 c = pgetc();
11098 } else {
11099 badsub:
11100 raise_error_syntax("bad substitution");
11101 }
11102
11103 STPUTC('=', out);
11104 flags = 0;
11105 if (subtype == 0) {
11106 switch (c) {
11107 case ':':
11108 c = pgetc();
11109 #if ENABLE_ASH_BASH_COMPAT
11110 if (c == ':' || c == '$' || isdigit(c)) {
11111 pungetc();
11112 subtype = VSSUBSTR;
11113 break;
11114 }
11115 #endif
11116 flags = VSNUL;
11117 /*FALLTHROUGH*/
11118 default:
11119 p = strchr(types, c);
11120 if (p == NULL)
11121 goto badsub;
11122 subtype = p - types + VSNORMAL;
11123 break;
11124 case '%':
11125 case '#': {
11126 int cc = c;
11127 subtype = c == '#' ? VSTRIMLEFT : VSTRIMRIGHT;
11128 c = pgetc();
11129 if (c == cc)
11130 subtype++;
11131 else
11132 pungetc();
11133 break;
11134 }
11135 #if ENABLE_ASH_BASH_COMPAT
11136 case '/':
11137 subtype = VSREPLACE;
11138 c = pgetc();
11139 if (c == '/')
11140 subtype++; /* VSREPLACEALL */
11141 else
11142 pungetc();
11143 break;
11144 #endif
11145 }
11146 } else {
11147 pungetc();
11148 }
11149 if (dblquote || arinest)
11150 flags |= VSQUOTE;
11151 *((char *)stackblock() + typeloc) = subtype | flags;
11152 if (subtype != VSNORMAL) {
11153 varnest++;
11154 if (dblquote || arinest) {
11155 dqvarnest++;
11156 }
11157 }
11158 }
11159 goto parsesub_return;
11160 }
11161
11162 /*
11163 * Called to parse command substitutions. Newstyle is set if the command
11164 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11165 * list of commands (passed by reference), and savelen is the number of
11166 * characters on the top of the stack which must be preserved.
11167 */
11168 parsebackq: {
11169 struct nodelist **nlpp;
11170 smallint savepbq;
11171 union node *n;
11172 char *volatile str;
11173 struct jmploc jmploc;
11174 struct jmploc *volatile savehandler;
11175 size_t savelen;
11176 smallint saveprompt = 0;
11177
11178 #ifdef __GNUC__
11179 (void) &saveprompt;
11180 #endif
11181 savepbq = parsebackquote;
11182 if (setjmp(jmploc.loc)) {
11183 free(str);
11184 parsebackquote = 0;
11185 exception_handler = savehandler;
11186 longjmp(exception_handler->loc, 1);
11187 }
11188 INT_OFF;
11189 str = NULL;
11190 savelen = out - (char *)stackblock();
11191 if (savelen > 0) {
11192 str = ckmalloc(savelen);
11193 memcpy(str, stackblock(), savelen);
11194 }
11195 savehandler = exception_handler;
11196 exception_handler = &jmploc;
11197 INT_ON;
11198 if (oldstyle) {
11199 /* We must read until the closing backquote, giving special
11200 treatment to some slashes, and then push the string and
11201 reread it as input, interpreting it normally. */
11202 char *pout;
11203 int pc;
11204 size_t psavelen;
11205 char *pstr;
11206
11207
11208 STARTSTACKSTR(pout);
11209 for (;;) {
11210 if (needprompt) {
11211 setprompt(2);
11212 }
11213 pc = pgetc();
11214 switch (pc) {
11215 case '`':
11216 goto done;
11217
11218 case '\\':
11219 pc = pgetc();
11220 if (pc == '\n') {
11221 plinno++;
11222 if (doprompt)
11223 setprompt(2);
11224 /*
11225 * If eating a newline, avoid putting
11226 * the newline into the new character
11227 * stream (via the STPUTC after the
11228 * switch).
11229 */
11230 continue;
11231 }
11232 if (pc != '\\' && pc != '`' && pc != '$'
11233 && (!dblquote || pc != '"'))
11234 STPUTC('\\', pout);
11235 if (pc > PEOA_OR_PEOF) {
11236 break;
11237 }
11238 /* fall through */
11239
11240 case PEOF:
11241 #if ENABLE_ASH_ALIAS
11242 case PEOA:
11243 #endif
11244 startlinno = plinno;
11245 raise_error_syntax("EOF in backquote substitution");
11246
11247 case '\n':
11248 plinno++;
11249 needprompt = doprompt;
11250 break;
11251
11252 default:
11253 break;
11254 }
11255 STPUTC(pc, pout);
11256 }
11257 done:
11258 STPUTC('\0', pout);
11259 psavelen = pout - (char *)stackblock();
11260 if (psavelen > 0) {
11261 pstr = grabstackstr(pout);
11262 setinputstring(pstr);
11263 }
11264 }
11265 nlpp = &bqlist;
11266 while (*nlpp)
11267 nlpp = &(*nlpp)->next;
11268 *nlpp = stzalloc(sizeof(**nlpp));
11269 /* (*nlpp)->next = NULL; - stzalloc did it */
11270 parsebackquote = oldstyle;
11271
11272 if (oldstyle) {
11273 saveprompt = doprompt;
11274 doprompt = 0;
11275 }
11276
11277 n = list(2);
11278
11279 if (oldstyle)
11280 doprompt = saveprompt;
11281 else if (readtoken() != TRP)
11282 raise_error_unexpected_syntax(TRP);
11283
11284 (*nlpp)->n = n;
11285 if (oldstyle) {
11286 /*
11287 * Start reading from old file again, ignoring any pushed back
11288 * tokens left from the backquote parsing
11289 */
11290 popfile();
11291 tokpushback = 0;
11292 }
11293 while (stackblocksize() <= savelen)
11294 growstackblock();
11295 STARTSTACKSTR(out);
11296 if (str) {
11297 memcpy(out, str, savelen);
11298 STADJUST(savelen, out);
11299 INT_OFF;
11300 free(str);
11301 str = NULL;
11302 INT_ON;
11303 }
11304 parsebackquote = savepbq;
11305 exception_handler = savehandler;
11306 if (arinest || dblquote)
11307 USTPUTC(CTLBACKQ | CTLQUOTE, out);
11308 else
11309 USTPUTC(CTLBACKQ, out);
11310 if (oldstyle)
11311 goto parsebackq_oldreturn;
11312 goto parsebackq_newreturn;
11313 }
11314
11315 #if ENABLE_ASH_MATH_SUPPORT
11316 /*
11317 * Parse an arithmetic expansion (indicate start of one and set state)
11318 */
11319 parsearith: {
11320 if (++arinest == 1) {
11321 prevsyntax = syntax;
11322 syntax = ARISYNTAX;
11323 USTPUTC(CTLARI, out);
11324 if (dblquote)
11325 USTPUTC('"', out);
11326 else
11327 USTPUTC(' ', out);
11328 } else {
11329 /*
11330 * we collapse embedded arithmetic expansion to
11331 * parenthesis, which should be equivalent
11332 */
11333 USTPUTC('(', out);
11334 }
11335 goto parsearith_return;
11336 }
11337 #endif
11338
11339 } /* end of readtoken */
11340
11341 /*
11342 * Read the next input token.
11343 * If the token is a word, we set backquotelist to the list of cmds in
11344 * backquotes. We set quoteflag to true if any part of the word was
11345 * quoted.
11346 * If the token is TREDIR, then we set redirnode to a structure containing
11347 * the redirection.
11348 * In all cases, the variable startlinno is set to the number of the line
11349 * on which the token starts.
11350 *
11351 * [Change comment: here documents and internal procedures]
11352 * [Readtoken shouldn't have any arguments. Perhaps we should make the
11353 * word parsing code into a separate routine. In this case, readtoken
11354 * doesn't need to have any internal procedures, but parseword does.
11355 * We could also make parseoperator in essence the main routine, and
11356 * have parseword (readtoken1?) handle both words and redirection.]
11357 */
11358 #define NEW_xxreadtoken
11359 #ifdef NEW_xxreadtoken
11360 /* singles must be first! */
11361 static const char xxreadtoken_chars[7] ALIGN1 = {
11362 '\n', '(', ')', /* singles */
11363 '&', '|', ';', /* doubles */
11364 0
11365 };
11366
11367 #define xxreadtoken_singles 3
11368 #define xxreadtoken_doubles 3
11369
11370 static const char xxreadtoken_tokens[] ALIGN1 = {
11371 TNL, TLP, TRP, /* only single occurrence allowed */
11372 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
11373 TEOF, /* corresponds to trailing nul */
11374 TAND, TOR, TENDCASE /* if double occurrence */
11375 };
11376
11377 static int
11378 xxreadtoken(void)
11379 {
11380 int c;
11381
11382 if (tokpushback) {
11383 tokpushback = 0;
11384 return lasttoken;
11385 }
11386 if (needprompt) {
11387 setprompt(2);
11388 }
11389 startlinno = plinno;
11390 for (;;) { /* until token or start of word found */
11391 c = pgetc_fast();
11392 if (c == ' ' || c == '\t' USE_ASH_ALIAS( || c == PEOA))
11393 continue;
11394
11395 if (c == '#') {
11396 while ((c = pgetc()) != '\n' && c != PEOF)
11397 continue;
11398 pungetc();
11399 } else if (c == '\\') {
11400 if (pgetc() != '\n') {
11401 pungetc();
11402 break; /* return readtoken1(...) */
11403 }
11404 startlinno = ++plinno;
11405 if (doprompt)
11406 setprompt(2);
11407 } else {
11408 const char *p;
11409
11410 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
11411 if (c != PEOF) {
11412 if (c == '\n') {
11413 plinno++;
11414 needprompt = doprompt;
11415 }
11416
11417 p = strchr(xxreadtoken_chars, c);
11418 if (p == NULL)
11419 break; /* return readtoken1(...) */
11420
11421 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
11422 int cc = pgetc();
11423 if (cc == c) { /* double occurrence? */
11424 p += xxreadtoken_doubles + 1;
11425 } else {
11426 pungetc();
11427 #if ENABLE_ASH_BASH_COMPAT
11428 if (c == '&' && cc == '>') /* &> */
11429 break; /* return readtoken1(...) */
11430 #endif
11431 }
11432 }
11433 }
11434 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
11435 return lasttoken;
11436 }
11437 } /* for (;;) */
11438
11439 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
11440 }
11441 #else /* old xxreadtoken */
11442 #define RETURN(token) return lasttoken = token
11443 static int
11444 xxreadtoken(void)
11445 {
11446 int c;
11447
11448 if (tokpushback) {
11449 tokpushback = 0;
11450 return lasttoken;
11451 }
11452 if (needprompt) {
11453 setprompt(2);
11454 }
11455 startlinno = plinno;
11456 for (;;) { /* until token or start of word found */
11457 c = pgetc_fast();
11458 switch (c) {
11459 case ' ': case '\t':
11460 #if ENABLE_ASH_ALIAS
11461 case PEOA:
11462 #endif
11463 continue;
11464 case '#':
11465 while ((c = pgetc()) != '\n' && c != PEOF)
11466 continue;
11467 pungetc();
11468 continue;
11469 case '\\':
11470 if (pgetc() == '\n') {
11471 startlinno = ++plinno;
11472 if (doprompt)
11473 setprompt(2);
11474 continue;
11475 }
11476 pungetc();
11477 goto breakloop;
11478 case '\n':
11479 plinno++;
11480 needprompt = doprompt;
11481 RETURN(TNL);
11482 case PEOF:
11483 RETURN(TEOF);
11484 case '&':
11485 if (pgetc() == '&')
11486 RETURN(TAND);
11487 pungetc();
11488 RETURN(TBACKGND);
11489 case '|':
11490 if (pgetc() == '|')
11491 RETURN(TOR);
11492 pungetc();
11493 RETURN(TPIPE);
11494 case ';':
11495 if (pgetc() == ';')
11496 RETURN(TENDCASE);
11497 pungetc();
11498 RETURN(TSEMI);
11499 case '(':
11500 RETURN(TLP);
11501 case ')':
11502 RETURN(TRP);
11503 default:
11504 goto breakloop;
11505 }
11506 }
11507 breakloop:
11508 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
11509 #undef RETURN
11510 }
11511 #endif /* old xxreadtoken */
11512
11513 static int
11514 readtoken(void)
11515 {
11516 int t;
11517 #if DEBUG
11518 smallint alreadyseen = tokpushback;
11519 #endif
11520
11521 #if ENABLE_ASH_ALIAS
11522 top:
11523 #endif
11524
11525 t = xxreadtoken();
11526
11527 /*
11528 * eat newlines
11529 */
11530 if (checkkwd & CHKNL) {
11531 while (t == TNL) {
11532 parseheredoc();
11533 t = xxreadtoken();
11534 }
11535 }
11536
11537 if (t != TWORD || quoteflag) {
11538 goto out;
11539 }
11540
11541 /*
11542 * check for keywords
11543 */
11544 if (checkkwd & CHKKWD) {
11545 const char *const *pp;
11546
11547 pp = findkwd(wordtext);
11548 if (pp) {
11549 lasttoken = t = pp - tokname_array;
11550 TRACE(("keyword %s recognized\n", tokname(t)));
11551 goto out;
11552 }
11553 }
11554
11555 if (checkkwd & CHKALIAS) {
11556 #if ENABLE_ASH_ALIAS
11557 struct alias *ap;
11558 ap = lookupalias(wordtext, 1);
11559 if (ap != NULL) {
11560 if (*ap->val) {
11561 pushstring(ap->val, ap);
11562 }
11563 goto top;
11564 }
11565 #endif
11566 }
11567 out:
11568 checkkwd = 0;
11569 #if DEBUG
11570 if (!alreadyseen)
11571 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
11572 else
11573 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
11574 #endif
11575 return t;
11576 }
11577
11578 static char
11579 peektoken(void)
11580 {
11581 int t;
11582
11583 t = readtoken();
11584 tokpushback = 1;
11585 return tokname_array[t][0];
11586 }
11587
11588 /*
11589 * Read and parse a command. Returns NEOF on end of file. (NULL is a
11590 * valid parse tree indicating a blank line.)
11591 */
11592 static union node *
11593 parsecmd(int interact)
11594 {
11595 int t;
11596
11597 tokpushback = 0;
11598 doprompt = interact;
11599 if (doprompt)
11600 setprompt(doprompt);
11601 needprompt = 0;
11602 t = readtoken();
11603 if (t == TEOF)
11604 return NEOF;
11605 if (t == TNL)
11606 return NULL;
11607 tokpushback = 1;
11608 return list(1);
11609 }
11610
11611 /*
11612 * Input any here documents.
11613 */
11614 static void
11615 parseheredoc(void)
11616 {
11617 struct heredoc *here;
11618 union node *n;
11619
11620 here = heredoclist;
11621 heredoclist = NULL;
11622
11623 while (here) {
11624 if (needprompt) {
11625 setprompt(2);
11626 }
11627 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
11628 here->eofmark, here->striptabs);
11629 n = stzalloc(sizeof(struct narg));
11630 n->narg.type = NARG;
11631 /*n->narg.next = NULL; - stzalloc did it */
11632 n->narg.text = wordtext;
11633 n->narg.backquote = backquotelist;
11634 here->here->nhere.doc = n;
11635 here = here->next;
11636 }
11637 }
11638
11639
11640 /*
11641 * called by editline -- any expansions to the prompt should be added here.
11642 */
11643 #if ENABLE_ASH_EXPAND_PRMT
11644 static const char *
11645 expandstr(const char *ps)
11646 {
11647 union node n;
11648
11649 /* XXX Fix (char *) cast. */
11650 setinputstring((char *)ps);
11651 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
11652 popfile();
11653
11654 n.narg.type = NARG;
11655 n.narg.next = NULL;
11656 n.narg.text = wordtext;
11657 n.narg.backquote = backquotelist;
11658
11659 expandarg(&n, NULL, 0);
11660 return stackblock();
11661 }
11662 #endif
11663
11664 /*
11665 * Execute a command or commands contained in a string.
11666 */
11667 static int
11668 evalstring(char *s, int mask)
11669 {
11670 union node *n;
11671 struct stackmark smark;
11672 int skip;
11673
11674 setinputstring(s);
11675 setstackmark(&smark);
11676
11677 skip = 0;
11678 while ((n = parsecmd(0)) != NEOF) {
11679 evaltree(n, 0);
11680 popstackmark(&smark);
11681 skip = evalskip;
11682 if (skip)
11683 break;
11684 }
11685 popfile();
11686
11687 skip &= mask;
11688 evalskip = skip;
11689 return skip;
11690 }
11691
11692 /*
11693 * The eval command.
11694 */
11695 static int
11696 evalcmd(int argc UNUSED_PARAM, char **argv)
11697 {
11698 char *p;
11699 char *concat;
11700
11701 if (argv[1]) {
11702 p = argv[1];
11703 argv += 2;
11704 if (argv[0]) {
11705 STARTSTACKSTR(concat);
11706 for (;;) {
11707 concat = stack_putstr(p, concat);
11708 p = *argv++;
11709 if (p == NULL)
11710 break;
11711 STPUTC(' ', concat);
11712 }
11713 STPUTC('\0', concat);
11714 p = grabstackstr(concat);
11715 }
11716 evalstring(p, ~SKIPEVAL);
11717
11718 }
11719 return exitstatus;
11720 }
11721
11722 /*
11723 * Read and execute commands. "Top" is nonzero for the top level command
11724 * loop; it turns on prompting if the shell is interactive.
11725 */
11726 static int
11727 cmdloop(int top)
11728 {
11729 union node *n;
11730 struct stackmark smark;
11731 int inter;
11732 int numeof = 0;
11733
11734 TRACE(("cmdloop(%d) called\n", top));
11735 for (;;) {
11736 int skip;
11737
11738 setstackmark(&smark);
11739 #if JOBS
11740 if (doing_jobctl)
11741 showjobs(stderr, SHOW_CHANGED);
11742 #endif
11743 inter = 0;
11744 if (iflag && top) {
11745 inter++;
11746 #if ENABLE_ASH_MAIL
11747 chkmail();
11748 #endif
11749 }
11750 n = parsecmd(inter);
11751 /* showtree(n); DEBUG */
11752 if (n == NEOF) {
11753 if (!top || numeof >= 50)
11754 break;
11755 if (!stoppedjobs()) {
11756 if (!Iflag)
11757 break;
11758 out2str("\nUse \"exit\" to leave shell.\n");
11759 }
11760 numeof++;
11761 } else if (nflag == 0) {
11762 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
11763 job_warning >>= 1;
11764 numeof = 0;
11765 evaltree(n, 0);
11766 }
11767 popstackmark(&smark);
11768 skip = evalskip;
11769
11770 if (skip) {
11771 evalskip = 0;
11772 return skip & SKIPEVAL;
11773 }
11774 }
11775 return 0;
11776 }
11777
11778 /*
11779 * Take commands from a file. To be compatible we should do a path
11780 * search for the file, which is necessary to find sub-commands.
11781 */
11782 static char *
11783 find_dot_file(char *name)
11784 {
11785 char *fullname;
11786 const char *path = pathval();
11787 struct stat statb;
11788
11789 /* don't try this for absolute or relative paths */
11790 if (strchr(name, '/'))
11791 return name;
11792
11793 while ((fullname = padvance(&path, name)) != NULL) {
11794 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
11795 /*
11796 * Don't bother freeing here, since it will
11797 * be freed by the caller.
11798 */
11799 return fullname;
11800 }
11801 stunalloc(fullname);
11802 }
11803
11804 /* not found in the PATH */
11805 ash_msg_and_raise_error("%s: not found", name);
11806 /* NOTREACHED */
11807 }
11808
11809 static int
11810 dotcmd(int argc, char **argv)
11811 {
11812 struct strlist *sp;
11813 volatile struct shparam saveparam;
11814 int status = 0;
11815
11816 for (sp = cmdenviron; sp; sp = sp->next)
11817 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
11818
11819 if (argv[1]) { /* That's what SVR2 does */
11820 char *fullname = find_dot_file(argv[1]);
11821 argv += 2;
11822 argc -= 2;
11823 if (argc) { /* argc > 0, argv[0] != NULL */
11824 saveparam = shellparam;
11825 shellparam.malloced = 0;
11826 shellparam.nparam = argc;
11827 shellparam.p = argv;
11828 };
11829
11830 setinputfile(fullname, INPUT_PUSH_FILE);
11831 commandname = fullname;
11832 cmdloop(0);
11833 popfile();
11834
11835 if (argc) {
11836 freeparam(&shellparam);
11837 shellparam = saveparam;
11838 };
11839 status = exitstatus;
11840 }
11841 return status;
11842 }
11843
11844 static int
11845 exitcmd(int argc UNUSED_PARAM, char **argv)
11846 {
11847 if (stoppedjobs())
11848 return 0;
11849 if (argv[1])
11850 exitstatus = number(argv[1]);
11851 raise_exception(EXEXIT);
11852 /* NOTREACHED */
11853 }
11854
11855 /*
11856 * Read a file containing shell functions.
11857 */
11858 static void
11859 readcmdfile(char *name)
11860 {
11861 setinputfile(name, INPUT_PUSH_FILE);
11862 cmdloop(0);
11863 popfile();
11864 }
11865
11866
11867 /* ============ find_command inplementation */
11868
11869 /*
11870 * Resolve a command name. If you change this routine, you may have to
11871 * change the shellexec routine as well.
11872 */
11873 static void
11874 find_command(char *name, struct cmdentry *entry, int act, const char *path)
11875 {
11876 struct tblentry *cmdp;
11877 int idx;
11878 int prev;
11879 char *fullname;
11880 struct stat statb;
11881 int e;
11882 int updatetbl;
11883 struct builtincmd *bcmd;
11884
11885 /* If name contains a slash, don't use PATH or hash table */
11886 if (strchr(name, '/') != NULL) {
11887 entry->u.index = -1;
11888 if (act & DO_ABS) {
11889 while (stat(name, &statb) < 0) {
11890 #ifdef SYSV
11891 if (errno == EINTR)
11892 continue;
11893 #endif
11894 entry->cmdtype = CMDUNKNOWN;
11895 return;
11896 }
11897 }
11898 entry->cmdtype = CMDNORMAL;
11899 return;
11900 }
11901
11902 /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
11903
11904 updatetbl = (path == pathval());
11905 if (!updatetbl) {
11906 act |= DO_ALTPATH;
11907 if (strstr(path, "%builtin") != NULL)
11908 act |= DO_ALTBLTIN;
11909 }
11910
11911 /* If name is in the table, check answer will be ok */
11912 cmdp = cmdlookup(name, 0);
11913 if (cmdp != NULL) {
11914 int bit;
11915
11916 switch (cmdp->cmdtype) {
11917 default:
11918 #if DEBUG
11919 abort();
11920 #endif
11921 case CMDNORMAL:
11922 bit = DO_ALTPATH;
11923 break;
11924 case CMDFUNCTION:
11925 bit = DO_NOFUNC;
11926 break;
11927 case CMDBUILTIN:
11928 bit = DO_ALTBLTIN;
11929 break;
11930 }
11931 if (act & bit) {
11932 updatetbl = 0;
11933 cmdp = NULL;
11934 } else if (cmdp->rehash == 0)
11935 /* if not invalidated by cd, we're done */
11936 goto success;
11937 }
11938
11939 /* If %builtin not in path, check for builtin next */
11940 bcmd = find_builtin(name);
11941 if (bcmd) {
11942 if (IS_BUILTIN_REGULAR(bcmd))
11943 goto builtin_success;
11944 if (act & DO_ALTPATH) {
11945 if (!(act & DO_ALTBLTIN))
11946 goto builtin_success;
11947 } else if (builtinloc <= 0) {
11948 goto builtin_success;
11949 }
11950 }
11951
11952 #if ENABLE_FEATURE_SH_STANDALONE
11953 {
11954 int applet_no = find_applet_by_name(name);
11955 if (applet_no >= 0) {
11956 entry->cmdtype = CMDNORMAL;
11957 entry->u.index = -2 - applet_no;
11958 return;
11959 }
11960 }
11961 #endif
11962
11963 /* We have to search path. */
11964 prev = -1; /* where to start */
11965 if (cmdp && cmdp->rehash) { /* doing a rehash */
11966 if (cmdp->cmdtype == CMDBUILTIN)
11967 prev = builtinloc;
11968 else
11969 prev = cmdp->param.index;
11970 }
11971
11972 e = ENOENT;
11973 idx = -1;
11974 loop:
11975 while ((fullname = padvance(&path, name)) != NULL) {
11976 stunalloc(fullname);
11977 /* NB: code below will still use fullname
11978 * despite it being "unallocated" */
11979 idx++;
11980 if (pathopt) {
11981 if (prefix(pathopt, "builtin")) {
11982 if (bcmd)
11983 goto builtin_success;
11984 continue;
11985 }
11986 if ((act & DO_NOFUNC)
11987 || !prefix(pathopt, "func")
11988 ) { /* ignore unimplemented options */
11989 continue;
11990 }
11991 }
11992 /* if rehash, don't redo absolute path names */
11993 if (fullname[0] == '/' && idx <= prev) {
11994 if (idx < prev)
11995 continue;
11996 TRACE(("searchexec \"%s\": no change\n", name));
11997 goto success;
11998 }
11999 while (stat(fullname, &statb) < 0) {
12000 #ifdef SYSV
12001 if (errno == EINTR)
12002 continue;
12003 #endif
12004 if (errno != ENOENT && errno != ENOTDIR)
12005 e = errno;
12006 goto loop;
12007 }
12008 e = EACCES; /* if we fail, this will be the error */
12009 if (!S_ISREG(statb.st_mode))
12010 continue;
12011 if (pathopt) { /* this is a %func directory */
12012 stalloc(strlen(fullname) + 1);
12013 /* NB: stalloc will return space pointed by fullname
12014 * (because we don't have any intervening allocations
12015 * between stunalloc above and this stalloc) */
12016 readcmdfile(fullname);
12017 cmdp = cmdlookup(name, 0);
12018 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
12019 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
12020 stunalloc(fullname);
12021 goto success;
12022 }
12023 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
12024 if (!updatetbl) {
12025 entry->cmdtype = CMDNORMAL;
12026 entry->u.index = idx;
12027 return;
12028 }
12029 INT_OFF;
12030 cmdp = cmdlookup(name, 1);
12031 cmdp->cmdtype = CMDNORMAL;
12032 cmdp->param.index = idx;
12033 INT_ON;
12034 goto success;
12035 }
12036
12037 /* We failed. If there was an entry for this command, delete it */
12038 if (cmdp && updatetbl)
12039 delete_cmd_entry();
12040 if (act & DO_ERR)
12041 ash_msg("%s: %s", name, errmsg(e, "not found"));
12042 entry->cmdtype = CMDUNKNOWN;
12043 return;
12044
12045 builtin_success:
12046 if (!updatetbl) {
12047 entry->cmdtype = CMDBUILTIN;
12048 entry->u.cmd = bcmd;
12049 return;
12050 }
12051 INT_OFF;
12052 cmdp = cmdlookup(name, 1);
12053 cmdp->cmdtype = CMDBUILTIN;
12054 cmdp->param.cmd = bcmd;
12055 INT_ON;
12056 success:
12057 cmdp->rehash = 0;
12058 entry->cmdtype = cmdp->cmdtype;
12059 entry->u = cmdp->param;
12060 }
12061
12062
12063 /* ============ trap.c */
12064
12065 /*
12066 * The trap builtin.
12067 */
12068 static int
12069 trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12070 {
12071 char *action;
12072 char **ap;
12073 int signo;
12074
12075 nextopt(nullstr);
12076 ap = argptr;
12077 if (!*ap) {
12078 for (signo = 0; signo < NSIG; signo++) {
12079 if (trap[signo] != NULL) {
12080 out1fmt("trap -- %s %s\n",
12081 single_quote(trap[signo]),
12082 get_signame(signo));
12083 }
12084 }
12085 return 0;
12086 }
12087 action = NULL;
12088 if (ap[1])
12089 action = *ap++;
12090 while (*ap) {
12091 signo = get_signum(*ap);
12092 if (signo < 0)
12093 ash_msg_and_raise_error("%s: bad trap", *ap);
12094 INT_OFF;
12095 if (action) {
12096 if (LONE_DASH(action))
12097 action = NULL;
12098 else
12099 action = ckstrdup(action);
12100 }
12101 free(trap[signo]);
12102 trap[signo] = action;
12103 if (signo != 0)
12104 setsignal(signo);
12105 INT_ON;
12106 ap++;
12107 }
12108 return 0;
12109 }
12110
12111
12112 /* ============ Builtins */
12113
12114 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
12115 /*
12116 * Lists available builtins
12117 */
12118 static int
12119 helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12120 {
12121 unsigned col;
12122 unsigned i;
12123
12124 out1fmt("\nBuilt-in commands:\n-------------------\n");
12125 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
12126 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
12127 builtintab[i].name + 1);
12128 if (col > 60) {
12129 out1fmt("\n");
12130 col = 0;
12131 }
12132 }
12133 #if ENABLE_FEATURE_SH_STANDALONE
12134 {
12135 const char *a = applet_names;
12136 while (*a) {
12137 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
12138 if (col > 60) {
12139 out1fmt("\n");
12140 col = 0;
12141 }
12142 a += strlen(a) + 1;
12143 }
12144 }
12145 #endif
12146 out1fmt("\n\n");
12147 return EXIT_SUCCESS;
12148 }
12149 #endif /* FEATURE_SH_EXTRA_QUIET */
12150
12151 /*
12152 * The export and readonly commands.
12153 */
12154 static int
12155 exportcmd(int argc UNUSED_PARAM, char **argv)
12156 {
12157 struct var *vp;
12158 char *name;
12159 const char *p;
12160 char **aptr;
12161 int flag = argv[0][0] == 'r' ? VREADONLY : VEXPORT;
12162
12163 if (nextopt("p") != 'p') {
12164 aptr = argptr;
12165 name = *aptr;
12166 if (name) {
12167 do {
12168 p = strchr(name, '=');
12169 if (p != NULL) {
12170 p++;
12171 } else {
12172 vp = *findvar(hashvar(name), name);
12173 if (vp) {
12174 vp->flags |= flag;
12175 continue;
12176 }
12177 }
12178 setvar(name, p, flag);
12179 } while ((name = *++aptr) != NULL);
12180 return 0;
12181 }
12182 }
12183 showvars(argv[0], flag, 0);
12184 return 0;
12185 }
12186
12187 /*
12188 * Delete a function if it exists.
12189 */
12190 static void
12191 unsetfunc(const char *name)
12192 {
12193 struct tblentry *cmdp;
12194
12195 cmdp = cmdlookup(name, 0);
12196 if (cmdp!= NULL && cmdp->cmdtype == CMDFUNCTION)
12197 delete_cmd_entry();
12198 }
12199
12200 /*
12201 * The unset builtin command. We unset the function before we unset the
12202 * variable to allow a function to be unset when there is a readonly variable
12203 * with the same name.
12204 */
12205 static int
12206 unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12207 {
12208 char **ap;
12209 int i;
12210 int flag = 0;
12211 int ret = 0;
12212
12213 while ((i = nextopt("vf")) != '\0') {
12214 flag = i;
12215 }
12216
12217 for (ap = argptr; *ap; ap++) {
12218 if (flag != 'f') {
12219 i = unsetvar(*ap);
12220 ret |= i;
12221 if (!(i & 2))
12222 continue;
12223 }
12224 if (flag != 'v')
12225 unsetfunc(*ap);
12226 }
12227 return ret & 1;
12228 }
12229
12230
12231 /* setmode.c */
12232
12233 #include <sys/times.h>
12234
12235 static const unsigned char timescmd_str[] ALIGN1 = {
12236 ' ', offsetof(struct tms, tms_utime),
12237 '\n', offsetof(struct tms, tms_stime),
12238 ' ', offsetof(struct tms, tms_cutime),
12239 '\n', offsetof(struct tms, tms_cstime),
12240 0
12241 };
12242
12243 static int
12244 timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12245 {
12246 long clk_tck, s, t;
12247 const unsigned char *p;
12248 struct tms buf;
12249
12250 clk_tck = sysconf(_SC_CLK_TCK);
12251 times(&buf);
12252
12253 p = timescmd_str;
12254 do {
12255 t = *(clock_t *)(((char *) &buf) + p[1]);
12256 s = t / clk_tck;
12257 out1fmt("%ldm%ld.%.3lds%c",
12258 s/60, s%60,
12259 ((t - s * clk_tck) * 1000) / clk_tck,
12260 p[0]);
12261 } while (*(p += 2));
12262
12263 return 0;
12264 }
12265
12266 #if ENABLE_ASH_MATH_SUPPORT
12267 static arith_t
12268 dash_arith(const char *s)
12269 {
12270 arith_t result;
12271 int errcode = 0;
12272
12273 INT_OFF;
12274 result = arith(s, &errcode);
12275 if (errcode < 0) {
12276 if (errcode == -3)
12277 ash_msg_and_raise_error("exponent less than 0");
12278 if (errcode == -2)
12279 ash_msg_and_raise_error("divide by zero");
12280 if (errcode == -5)
12281 ash_msg_and_raise_error("expression recursion loop detected");
12282 raise_error_syntax(s);
12283 }
12284 INT_ON;
12285
12286 return result;
12287 }
12288
12289 /*
12290 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12291 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12292 *
12293 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12294 */
12295 static int
12296 letcmd(int argc UNUSED_PARAM, char **argv)
12297 {
12298 arith_t i;
12299
12300 argv++;
12301 if (!*argv)
12302 ash_msg_and_raise_error("expression expected");
12303 do {
12304 i = dash_arith(*argv);
12305 } while (*++argv);
12306
12307 return !i;
12308 }
12309 #endif /* ASH_MATH_SUPPORT */
12310
12311
12312 /* ============ miscbltin.c
12313 *
12314 * Miscellaneous builtins.
12315 */
12316
12317 #undef rflag
12318
12319 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12320 typedef enum __rlimit_resource rlim_t;
12321 #endif
12322
12323 /*
12324 * The read builtin. Options:
12325 * -r Do not interpret '\' specially
12326 * -s Turn off echo (tty only)
12327 * -n NCHARS Read NCHARS max
12328 * -p PROMPT Display PROMPT on stderr (if input is from tty)
12329 * -t SECONDS Timeout after SECONDS (tty or pipe only)
12330 * -u FD Read from given FD instead of fd 0
12331 * This uses unbuffered input, which may be avoidable in some cases.
12332 * TODO: bash also has:
12333 * -a ARRAY Read into array[0],[1],etc
12334 * -d DELIM End on DELIM char, not newline
12335 * -e Use line editing (tty only)
12336 */
12337 static int
12338 readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12339 {
12340 static const char *const arg_REPLY[] = { "REPLY", NULL };
12341
12342 char **ap;
12343 int backslash;
12344 char c;
12345 int rflag;
12346 char *prompt;
12347 const char *ifs;
12348 char *p;
12349 int startword;
12350 int status;
12351 int i;
12352 int fd = 0;
12353 #if ENABLE_ASH_READ_NCHARS
12354 int nchars = 0; /* if != 0, -n is in effect */
12355 int silent = 0;
12356 struct termios tty, old_tty;
12357 #endif
12358 #if ENABLE_ASH_READ_TIMEOUT
12359 unsigned end_ms = 0;
12360 unsigned timeout = 0;
12361 #endif
12362
12363 rflag = 0;
12364 prompt = NULL;
12365 while ((i = nextopt("p:u:r"
12366 USE_ASH_READ_TIMEOUT("t:")
12367 USE_ASH_READ_NCHARS("n:s")
12368 )) != '\0') {
12369 switch (i) {
12370 case 'p':
12371 prompt = optionarg;
12372 break;
12373 #if ENABLE_ASH_READ_NCHARS
12374 case 'n':
12375 nchars = bb_strtou(optionarg, NULL, 10);
12376 if (nchars < 0 || errno)
12377 ash_msg_and_raise_error("invalid count");
12378 /* nchars == 0: off (bash 3.2 does this too) */
12379 break;
12380 case 's':
12381 silent = 1;
12382 break;
12383 #endif
12384 #if ENABLE_ASH_READ_TIMEOUT
12385 case 't':
12386 timeout = bb_strtou(optionarg, NULL, 10);
12387 if (errno || timeout > UINT_MAX / 2048)
12388 ash_msg_and_raise_error("invalid timeout");
12389 timeout *= 1000;
12390 #if 0 /* even bash have no -t N.NNN support */
12391 ts.tv_sec = bb_strtou(optionarg, &p, 10);
12392 ts.tv_usec = 0;
12393 /* EINVAL means number is ok, but not terminated by NUL */
12394 if (*p == '.' && errno == EINVAL) {
12395 char *p2;
12396 if (*++p) {
12397 int scale;
12398 ts.tv_usec = bb_strtou(p, &p2, 10);
12399 if (errno)
12400 ash_msg_and_raise_error("invalid timeout");
12401 scale = p2 - p;
12402 /* normalize to usec */
12403 if (scale > 6)
12404 ash_msg_and_raise_error("invalid timeout");
12405 while (scale++ < 6)
12406 ts.tv_usec *= 10;
12407 }
12408 } else if (ts.tv_sec < 0 || errno) {
12409 ash_msg_and_raise_error("invalid timeout");
12410 }
12411 if (!(ts.tv_sec | ts.tv_usec)) { /* both are 0? */
12412 ash_msg_and_raise_error("invalid timeout");
12413 }
12414 #endif /* if 0 */
12415 break;
12416 #endif
12417 case 'r':
12418 rflag = 1;
12419 break;
12420 case 'u':
12421 fd = bb_strtou(optionarg, NULL, 10);
12422 if (fd < 0 || errno)
12423 ash_msg_and_raise_error("invalid file descriptor");
12424 break;
12425 default:
12426 break;
12427 }
12428 }
12429 if (prompt && isatty(fd)) {
12430 out2str(prompt);
12431 }
12432 ap = argptr;
12433 if (*ap == NULL)
12434 ap = (char**)arg_REPLY;
12435 ifs = bltinlookup("IFS");
12436 if (ifs == NULL)
12437 ifs = defifs;
12438 #if ENABLE_ASH_READ_NCHARS
12439 tcgetattr(fd, &tty);
12440 old_tty = tty;
12441 if (nchars || silent) {
12442 if (nchars) {
12443 tty.c_lflag &= ~ICANON;
12444 tty.c_cc[VMIN] = nchars < 256 ? nchars : 255;
12445 }
12446 if (silent) {
12447 tty.c_lflag &= ~(ECHO | ECHOK | ECHONL);
12448 }
12449 /* if tcgetattr failed, tcsetattr will fail too.
12450 * Ignoring, it's harmless. */
12451 tcsetattr(fd, TCSANOW, &tty);
12452 }
12453 #endif
12454
12455 status = 0;
12456 startword = 2;
12457 backslash = 0;
12458 #if ENABLE_ASH_READ_TIMEOUT
12459 if (timeout) /* NB: ensuring end_ms is nonzero */
12460 end_ms = ((unsigned)(monotonic_us() / 1000) + timeout) | 1;
12461 #endif
12462 STARTSTACKSTR(p);
12463 do {
12464 const char *is_ifs;
12465
12466 #if ENABLE_ASH_READ_TIMEOUT
12467 if (end_ms) {
12468 struct pollfd pfd[1];
12469 pfd[0].fd = fd;
12470 pfd[0].events = POLLIN;
12471 timeout = end_ms - (unsigned)(monotonic_us() / 1000);
12472 if ((int)timeout <= 0 /* already late? */
12473 || safe_poll(pfd, 1, timeout) != 1 /* no? wait... */
12474 ) { /* timed out! */
12475 #if ENABLE_ASH_READ_NCHARS
12476 tcsetattr(fd, TCSANOW, &old_tty);
12477 #endif
12478 return 1;
12479 }
12480 }
12481 #endif
12482 if (nonblock_safe_read(fd, &c, 1) != 1) {
12483 status = 1;
12484 break;
12485 }
12486 if (c == '\0')
12487 continue;
12488 if (backslash) {
12489 backslash = 0;
12490 if (c != '\n')
12491 goto put;
12492 continue;
12493 }
12494 if (!rflag && c == '\\') {
12495 backslash = 1;
12496 continue;
12497 }
12498 if (c == '\n')
12499 break;
12500 is_ifs = strchr(ifs, c);
12501 if (startword && is_ifs) {
12502 if (isspace(c))
12503 continue;
12504 /* non-space ifs char */
12505 startword--;
12506 if (startword == 1) /* first one? */
12507 continue;
12508 }
12509 startword = 0;
12510 if (ap[1] != NULL && is_ifs) {
12511 const char *beg;
12512 STACKSTRNUL(p);
12513 beg = stackblock();
12514 setvar(*ap, beg, 0);
12515 ap++;
12516 /* can we skip one non-space ifs? (2: yes) */
12517 startword = isspace(c) ? 2 : 1;
12518 STARTSTACKSTR(p);
12519 continue;
12520 }
12521 put:
12522 STPUTC(c, p);
12523 }
12524 /* end of do {} while: */
12525 #if ENABLE_ASH_READ_NCHARS
12526 while (--nchars);
12527 #else
12528 while (1);
12529 #endif
12530
12531 #if ENABLE_ASH_READ_NCHARS
12532 tcsetattr(fd, TCSANOW, &old_tty);
12533 #endif
12534
12535 STACKSTRNUL(p);
12536 /* Remove trailing space ifs chars */
12537 while ((char *)stackblock() <= --p && isspace(*p) && strchr(ifs, *p) != NULL)
12538 *p = '\0';
12539 setvar(*ap, stackblock(), 0);
12540 while (*++ap != NULL)
12541 setvar(*ap, nullstr, 0);
12542 return status;
12543 }
12544
12545 static int
12546 umaskcmd(int argc UNUSED_PARAM, char **argv)
12547 {
12548 static const char permuser[3] ALIGN1 = "ugo";
12549 static const char permmode[3] ALIGN1 = "rwx";
12550 static const short permmask[] ALIGN2 = {
12551 S_IRUSR, S_IWUSR, S_IXUSR,
12552 S_IRGRP, S_IWGRP, S_IXGRP,
12553 S_IROTH, S_IWOTH, S_IXOTH
12554 };
12555
12556 char *ap;
12557 mode_t mask;
12558 int i;
12559 int symbolic_mode = 0;
12560
12561 while (nextopt("S") != '\0') {
12562 symbolic_mode = 1;
12563 }
12564
12565 INT_OFF;
12566 mask = umask(0);
12567 umask(mask);
12568 INT_ON;
12569
12570 ap = *argptr;
12571 if (ap == NULL) {
12572 if (symbolic_mode) {
12573 char buf[18];
12574 char *p = buf;
12575
12576 for (i = 0; i < 3; i++) {
12577 int j;
12578
12579 *p++ = permuser[i];
12580 *p++ = '=';
12581 for (j = 0; j < 3; j++) {
12582 if ((mask & permmask[3 * i + j]) == 0) {
12583 *p++ = permmode[j];
12584 }
12585 }
12586 *p++ = ',';
12587 }
12588 *--p = 0;
12589 puts(buf);
12590 } else {
12591 out1fmt("%.4o\n", mask);
12592 }
12593 } else {
12594 if (isdigit((unsigned char) *ap)) {
12595 mask = 0;
12596 do {
12597 if (*ap >= '8' || *ap < '0')
12598 ash_msg_and_raise_error(illnum, argv[1]);
12599 mask = (mask << 3) + (*ap - '0');
12600 } while (*++ap != '\0');
12601 umask(mask);
12602 } else {
12603 mask = ~mask & 0777;
12604 if (!bb_parse_mode(ap, &mask)) {
12605 ash_msg_and_raise_error("illegal mode: %s", ap);
12606 }
12607 umask(~mask & 0777);
12608 }
12609 }
12610 return 0;
12611 }
12612
12613 /*
12614 * ulimit builtin
12615 *
12616 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12617 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12618 * ash by J.T. Conklin.
12619 *
12620 * Public domain.
12621 */
12622
12623 struct limits {
12624 uint8_t cmd; /* RLIMIT_xxx fit into it */
12625 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */
12626 char option;
12627 };
12628
12629 static const struct limits limits_tbl[] = {
12630 #ifdef RLIMIT_CPU
12631 { RLIMIT_CPU, 0, 't' },
12632 #endif
12633 #ifdef RLIMIT_FSIZE
12634 { RLIMIT_FSIZE, 9, 'f' },
12635 #endif
12636 #ifdef RLIMIT_DATA
12637 { RLIMIT_DATA, 10, 'd' },
12638 #endif
12639 #ifdef RLIMIT_STACK
12640 { RLIMIT_STACK, 10, 's' },
12641 #endif
12642 #ifdef RLIMIT_CORE
12643 { RLIMIT_CORE, 9, 'c' },
12644 #endif
12645 #ifdef RLIMIT_RSS
12646 { RLIMIT_RSS, 10, 'm' },
12647 #endif
12648 #ifdef RLIMIT_MEMLOCK
12649 { RLIMIT_MEMLOCK, 10, 'l' },
12650 #endif
12651 #ifdef RLIMIT_NPROC
12652 { RLIMIT_NPROC, 0, 'p' },
12653 #endif
12654 #ifdef RLIMIT_NOFILE
12655 { RLIMIT_NOFILE, 0, 'n' },
12656 #endif
12657 #ifdef RLIMIT_AS
12658 { RLIMIT_AS, 10, 'v' },
12659 #endif
12660 #ifdef RLIMIT_LOCKS
12661 { RLIMIT_LOCKS, 0, 'w' },
12662 #endif
12663 };
12664 static const char limits_name[] =
12665 #ifdef RLIMIT_CPU
12666 "time(seconds)" "\0"
12667 #endif
12668 #ifdef RLIMIT_FSIZE
12669 "file(blocks)" "\0"
12670 #endif
12671 #ifdef RLIMIT_DATA
12672 "data(kb)" "\0"
12673 #endif
12674 #ifdef RLIMIT_STACK
12675 "stack(kb)" "\0"
12676 #endif
12677 #ifdef RLIMIT_CORE
12678 "coredump(blocks)" "\0"
12679 #endif
12680 #ifdef RLIMIT_RSS
12681 "memory(kb)" "\0"
12682 #endif
12683 #ifdef RLIMIT_MEMLOCK
12684 "locked memory(kb)" "\0"
12685 #endif
12686 #ifdef RLIMIT_NPROC
12687 "process" "\0"
12688 #endif
12689 #ifdef RLIMIT_NOFILE
12690 "nofiles" "\0"
12691 #endif
12692 #ifdef RLIMIT_AS
12693 "vmemory(kb)" "\0"
12694 #endif
12695 #ifdef RLIMIT_LOCKS
12696 "locks" "\0"
12697 #endif
12698 ;
12699
12700 enum limtype { SOFT = 0x1, HARD = 0x2 };
12701
12702 static void
12703 printlim(enum limtype how, const struct rlimit *limit,
12704 const struct limits *l)
12705 {
12706 rlim_t val;
12707
12708 val = limit->rlim_max;
12709 if (how & SOFT)
12710 val = limit->rlim_cur;
12711
12712 if (val == RLIM_INFINITY)
12713 out1fmt("unlimited\n");
12714 else {
12715 val >>= l->factor_shift;
12716 out1fmt("%lld\n", (long long) val);
12717 }
12718 }
12719
12720 static int
12721 ulimitcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12722 {
12723 int c;
12724 rlim_t val = 0;
12725 enum limtype how = SOFT | HARD;
12726 const struct limits *l;
12727 int set, all = 0;
12728 int optc, what;
12729 struct rlimit limit;
12730
12731 what = 'f';
12732 while ((optc = nextopt("HSa"
12733 #ifdef RLIMIT_CPU
12734 "t"
12735 #endif
12736 #ifdef RLIMIT_FSIZE
12737 "f"
12738 #endif
12739 #ifdef RLIMIT_DATA
12740 "d"
12741 #endif
12742 #ifdef RLIMIT_STACK
12743 "s"
12744 #endif
12745 #ifdef RLIMIT_CORE
12746 "c"
12747 #endif
12748 #ifdef RLIMIT_RSS
12749 "m"
12750 #endif
12751 #ifdef RLIMIT_MEMLOCK
12752 "l"
12753 #endif
12754 #ifdef RLIMIT_NPROC
12755 "p"
12756 #endif
12757 #ifdef RLIMIT_NOFILE
12758 "n"
12759 #endif
12760 #ifdef RLIMIT_AS
12761 "v"
12762 #endif
12763 #ifdef RLIMIT_LOCKS
12764 "w"
12765 #endif
12766 )) != '\0')
12767 switch (optc) {
12768 case 'H':
12769 how = HARD;
12770 break;
12771 case 'S':
12772 how = SOFT;
12773 break;
12774 case 'a':
12775 all = 1;
12776 break;
12777 default:
12778 what = optc;
12779 }
12780
12781 for (l = limits_tbl; l->option != what; l++)
12782 continue;
12783
12784 set = *argptr ? 1 : 0;
12785 if (set) {
12786 char *p = *argptr;
12787
12788 if (all || argptr[1])
12789 ash_msg_and_raise_error("too many arguments");
12790 if (strncmp(p, "unlimited\n", 9) == 0)
12791 val = RLIM_INFINITY;
12792 else {
12793 val = (rlim_t) 0;
12794
12795 while ((c = *p++) >= '0' && c <= '9') {
12796 val = (val * 10) + (long)(c - '0');
12797 // val is actually 'unsigned long int' and can't get < 0
12798 if (val < (rlim_t) 0)
12799 break;
12800 }
12801 if (c)
12802 ash_msg_and_raise_error("bad number");
12803 val <<= l->factor_shift;
12804 }
12805 }
12806 if (all) {
12807 const char *lname = limits_name;
12808 for (l = limits_tbl; l != &limits_tbl[ARRAY_SIZE(limits_tbl)]; l++) {
12809 getrlimit(l->cmd, &limit);
12810 out1fmt("%-20s ", lname);
12811 lname += strlen(lname) + 1;
12812 printlim(how, &limit, l);
12813 }
12814 return 0;
12815 }
12816
12817 getrlimit(l->cmd, &limit);
12818 if (set) {
12819 if (how & HARD)
12820 limit.rlim_max = val;
12821 if (how & SOFT)
12822 limit.rlim_cur = val;
12823 if (setrlimit(l->cmd, &limit) < 0)
12824 ash_msg_and_raise_error("error setting limit (%m)");
12825 } else {
12826 printlim(how, &limit, l);
12827 }
12828 return 0;
12829 }
12830
12831
12832 /* ============ Math support */
12833
12834 #if ENABLE_ASH_MATH_SUPPORT
12835
12836 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12837
12838 Permission is hereby granted, free of charge, to any person obtaining
12839 a copy of this software and associated documentation files (the
12840 "Software"), to deal in the Software without restriction, including
12841 without limitation the rights to use, copy, modify, merge, publish,
12842 distribute, sublicense, and/or sell copies of the Software, and to
12843 permit persons to whom the Software is furnished to do so, subject to
12844 the following conditions:
12845
12846 The above copyright notice and this permission notice shall be
12847 included in all copies or substantial portions of the Software.
12848
12849 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12850 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12851 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12852 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12853 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12854 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12855 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12856 */
12857
12858 /* This is my infix parser/evaluator. It is optimized for size, intended
12859 * as a replacement for yacc-based parsers. However, it may well be faster
12860 * than a comparable parser written in yacc. The supported operators are
12861 * listed in #defines below. Parens, order of operations, and error handling
12862 * are supported. This code is thread safe. The exact expression format should
12863 * be that which POSIX specifies for shells. */
12864
12865 /* The code uses a simple two-stack algorithm. See
12866 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12867 * for a detailed explanation of the infix-to-postfix algorithm on which
12868 * this is based (this code differs in that it applies operators immediately
12869 * to the stack instead of adding them to a queue to end up with an
12870 * expression). */
12871
12872 /* To use the routine, call it with an expression string and error return
12873 * pointer */
12874
12875 /*
12876 * Aug 24, 2001 Manuel Novoa III
12877 *
12878 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12879 *
12880 * 1) In arith_apply():
12881 * a) Cached values of *numptr and &(numptr[-1]).
12882 * b) Removed redundant test for zero denominator.
12883 *
12884 * 2) In arith():
12885 * a) Eliminated redundant code for processing operator tokens by moving
12886 * to a table-based implementation. Also folded handling of parens
12887 * into the table.
12888 * b) Combined all 3 loops which called arith_apply to reduce generated
12889 * code size at the cost of speed.
12890 *
12891 * 3) The following expressions were treated as valid by the original code:
12892 * 1() , 0! , 1 ( *3 ) .
12893 * These bugs have been fixed by internally enclosing the expression in
12894 * parens and then checking that all binary ops and right parens are
12895 * preceded by a valid expression (NUM_TOKEN).
12896 *
12897 * Note: It may be desirable to replace Aaron's test for whitespace with
12898 * ctype's isspace() if it is used by another busybox applet or if additional
12899 * whitespace chars should be considered. Look below the "#include"s for a
12900 * precompiler test.
12901 */
12902
12903 /*
12904 * Aug 26, 2001 Manuel Novoa III
12905 *
12906 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
12907 *
12908 * Merge in Aaron's comments previously posted to the busybox list,
12909 * modified slightly to take account of my changes to the code.
12910 *
12911 */
12912
12913 /*
12914 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12915 *
12916 * - allow access to variable,
12917 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12918 * - realize assign syntax (VAR=expr, +=, *= etc)
12919 * - realize exponentiation (** operator)
12920 * - realize comma separated - expr, expr
12921 * - realise ++expr --expr expr++ expr--
12922 * - realise expr ? expr : expr (but, second expr calculate always)
12923 * - allow hexadecimal and octal numbers
12924 * - was restored loses XOR operator
12925 * - remove one goto label, added three ;-)
12926 * - protect $((num num)) as true zero expr (Manuel`s error)
12927 * - always use special isspace(), see comment from bash ;-)
12928 */
12929
12930 #define arith_isspace(arithval) \
12931 (arithval == ' ' || arithval == '\n' || arithval == '\t')
12932
12933 typedef unsigned char operator;
12934
12935 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
12936 * precedence, and 3 high bits are an ID unique across operators of that
12937 * precedence. The ID portion is so that multiple operators can have the
12938 * same precedence, ensuring that the leftmost one is evaluated first.
12939 * Consider * and /. */
12940
12941 #define tok_decl(prec,id) (((id)<<5)|(prec))
12942 #define PREC(op) ((op) & 0x1F)
12943
12944 #define TOK_LPAREN tok_decl(0,0)
12945
12946 #define TOK_COMMA tok_decl(1,0)
12947
12948 #define TOK_ASSIGN tok_decl(2,0)
12949 #define TOK_AND_ASSIGN tok_decl(2,1)
12950 #define TOK_OR_ASSIGN tok_decl(2,2)
12951 #define TOK_XOR_ASSIGN tok_decl(2,3)
12952 #define TOK_PLUS_ASSIGN tok_decl(2,4)
12953 #define TOK_MINUS_ASSIGN tok_decl(2,5)
12954 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)
12955 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)
12956
12957 #define TOK_MUL_ASSIGN tok_decl(3,0)
12958 #define TOK_DIV_ASSIGN tok_decl(3,1)
12959 #define TOK_REM_ASSIGN tok_decl(3,2)
12960
12961 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
12962 #define convert_prec_is_assing(prec) do { if (prec == 3) prec = 2; } while (0)
12963
12964 /* conditional is right associativity too */
12965 #define TOK_CONDITIONAL tok_decl(4,0)
12966 #define TOK_CONDITIONAL_SEP tok_decl(4,1)
12967
12968 #define TOK_OR tok_decl(5,0)
12969
12970 #define TOK_AND tok_decl(6,0)
12971
12972 #define TOK_BOR tok_decl(7,0)
12973
12974 #define TOK_BXOR tok_decl(8,0)
12975
12976 #define TOK_BAND tok_decl(9,0)
12977
12978 #define TOK_EQ tok_decl(10,0)
12979 #define TOK_NE tok_decl(10,1)
12980
12981 #define TOK_LT tok_decl(11,0)
12982 #define TOK_GT tok_decl(11,1)
12983 #define TOK_GE tok_decl(11,2)
12984 #define TOK_LE tok_decl(11,3)
12985
12986 #define TOK_LSHIFT tok_decl(12,0)
12987 #define TOK_RSHIFT tok_decl(12,1)
12988
12989 #define TOK_ADD tok_decl(13,0)
12990 #define TOK_SUB tok_decl(13,1)
12991
12992 #define TOK_MUL tok_decl(14,0)
12993 #define TOK_DIV tok_decl(14,1)
12994 #define TOK_REM tok_decl(14,2)
12995
12996 /* exponent is right associativity */
12997 #define TOK_EXPONENT tok_decl(15,1)
12998
12999 /* For now unary operators. */
13000 #define UNARYPREC 16
13001 #define TOK_BNOT tok_decl(UNARYPREC,0)
13002 #define TOK_NOT tok_decl(UNARYPREC,1)
13003
13004 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)
13005 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)
13006
13007 #define PREC_PRE (UNARYPREC+2)
13008
13009 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)
13010 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
13011
13012 #define PREC_POST (UNARYPREC+3)
13013
13014 #define TOK_POST_INC tok_decl(PREC_POST, 0)
13015 #define TOK_POST_DEC tok_decl(PREC_POST, 1)
13016
13017 #define SPEC_PREC (UNARYPREC+4)
13018
13019 #define TOK_NUM tok_decl(SPEC_PREC, 0)
13020 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)
13021
13022 #define NUMPTR (*numstackptr)
13023
13024 static int
13025 tok_have_assign(operator op)
13026 {
13027 operator prec = PREC(op);
13028
13029 convert_prec_is_assing(prec);
13030 return (prec == PREC(TOK_ASSIGN) ||
13031 prec == PREC_PRE || prec == PREC_POST);
13032 }
13033
13034 static int
13035 is_right_associativity(operator prec)
13036 {
13037 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT)
13038 || prec == PREC(TOK_CONDITIONAL));
13039 }
13040
13041 typedef struct {
13042 arith_t val;
13043 arith_t contidional_second_val;
13044 char contidional_second_val_initialized;
13045 char *var; /* if NULL then is regular number,
13046 else is variable name */
13047 } v_n_t;
13048
13049 typedef struct chk_var_recursive_looped_t {
13050 const char *var;
13051 struct chk_var_recursive_looped_t *next;
13052 } chk_var_recursive_looped_t;
13053
13054 static chk_var_recursive_looped_t *prev_chk_var_recursive;
13055
13056 static int
13057 arith_lookup_val(v_n_t *t)
13058 {
13059 if (t->var) {
13060 const char * p = lookupvar(t->var);
13061
13062 if (p) {
13063 int errcode;
13064
13065 /* recursive try as expression */
13066 chk_var_recursive_looped_t *cur;
13067 chk_var_recursive_looped_t cur_save;
13068
13069 for (cur = prev_chk_var_recursive; cur; cur = cur->next) {
13070 if (strcmp(cur->var, t->var) == 0) {
13071 /* expression recursion loop detected */
13072 return -5;
13073 }
13074 }
13075 /* save current lookuped var name */
13076 cur = prev_chk_var_recursive;
13077 cur_save.var = t->var;
13078 cur_save.next = cur;
13079 prev_chk_var_recursive = &cur_save;
13080
13081 t->val = arith (p, &errcode);
13082 /* restore previous ptr after recursiving */
13083 prev_chk_var_recursive = cur;
13084 return errcode;
13085 }
13086 /* allow undefined var as 0 */
13087 t->val = 0;
13088 }
13089 return 0;
13090 }
13091
13092 /* "applying" a token means performing it on the top elements on the integer
13093 * stack. For a unary operator it will only change the top element, but a
13094 * binary operator will pop two arguments and push a result */
13095 static int
13096 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13097 {
13098 v_n_t *numptr_m1;
13099 arith_t numptr_val, rez;
13100 int ret_arith_lookup_val;
13101
13102 /* There is no operator that can work without arguments */
13103 if (NUMPTR == numstack) goto err;
13104 numptr_m1 = NUMPTR - 1;
13105
13106 /* check operand is var with noninteger value */
13107 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13108 if (ret_arith_lookup_val)
13109 return ret_arith_lookup_val;
13110
13111 rez = numptr_m1->val;
13112 if (op == TOK_UMINUS)
13113 rez *= -1;
13114 else if (op == TOK_NOT)
13115 rez = !rez;
13116 else if (op == TOK_BNOT)
13117 rez = ~rez;
13118 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13119 rez++;
13120 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13121 rez--;
13122 else if (op != TOK_UPLUS) {
13123 /* Binary operators */
13124
13125 /* check and binary operators need two arguments */
13126 if (numptr_m1 == numstack) goto err;
13127
13128 /* ... and they pop one */
13129 --NUMPTR;
13130 numptr_val = rez;
13131 if (op == TOK_CONDITIONAL) {
13132 if (!numptr_m1->contidional_second_val_initialized) {
13133 /* protect $((expr1 ? expr2)) without ": expr" */
13134 goto err;
13135 }
13136 rez = numptr_m1->contidional_second_val;
13137 } else if (numptr_m1->contidional_second_val_initialized) {
13138 /* protect $((expr1 : expr2)) without "expr ? " */
13139 goto err;
13140 }
13141 numptr_m1 = NUMPTR - 1;
13142 if (op != TOK_ASSIGN) {
13143 /* check operand is var with noninteger value for not '=' */
13144 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13145 if (ret_arith_lookup_val)
13146 return ret_arith_lookup_val;
13147 }
13148 if (op == TOK_CONDITIONAL) {
13149 numptr_m1->contidional_second_val = rez;
13150 }
13151 rez = numptr_m1->val;
13152 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13153 rez |= numptr_val;
13154 else if (op == TOK_OR)
13155 rez = numptr_val || rez;
13156 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13157 rez &= numptr_val;
13158 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13159 rez ^= numptr_val;
13160 else if (op == TOK_AND)
13161 rez = rez && numptr_val;
13162 else if (op == TOK_EQ)
13163 rez = (rez == numptr_val);
13164 else if (op == TOK_NE)
13165 rez = (rez != numptr_val);
13166 else if (op == TOK_GE)
13167 rez = (rez >= numptr_val);
13168 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13169 rez >>= numptr_val;
13170 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13171 rez <<= numptr_val;
13172 else if (op == TOK_GT)
13173 rez = (rez > numptr_val);
13174 else if (op == TOK_LT)
13175 rez = (rez < numptr_val);
13176 else if (op == TOK_LE)
13177 rez = (rez <= numptr_val);
13178 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13179 rez *= numptr_val;
13180 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13181 rez += numptr_val;
13182 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13183 rez -= numptr_val;
13184 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13185 rez = numptr_val;
13186 else if (op == TOK_CONDITIONAL_SEP) {
13187 if (numptr_m1 == numstack) {
13188 /* protect $((expr : expr)) without "expr ? " */
13189 goto err;
13190 }
13191 numptr_m1->contidional_second_val_initialized = op;
13192 numptr_m1->contidional_second_val = numptr_val;
13193 } else if (op == TOK_CONDITIONAL) {
13194 rez = rez ?
13195 numptr_val : numptr_m1->contidional_second_val;
13196 } else if (op == TOK_EXPONENT) {
13197 if (numptr_val < 0)
13198 return -3; /* exponent less than 0 */
13199 else {
13200 arith_t c = 1;
13201
13202 if (numptr_val)
13203 while (numptr_val--)
13204 c *= rez;
13205 rez = c;
13206 }
13207 } else if (numptr_val==0) /* zero divisor check */
13208 return -2;
13209 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13210 rez /= numptr_val;
13211 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13212 rez %= numptr_val;
13213 }
13214 if (tok_have_assign(op)) {
13215 char buf[sizeof(arith_t_type)*3 + 2];
13216
13217 if (numptr_m1->var == NULL) {
13218 /* Hmm, 1=2 ? */
13219 goto err;
13220 }
13221 /* save to shell variable */
13222 #if ENABLE_ASH_MATH_SUPPORT_64
13223 snprintf(buf, sizeof(buf), "%lld", (arith_t_type) rez);
13224 #else
13225 snprintf(buf, sizeof(buf), "%ld", (arith_t_type) rez);
13226 #endif
13227 setvar(numptr_m1->var, buf, 0);
13228 /* after saving, make previous value for v++ or v-- */
13229 if (op == TOK_POST_INC)
13230 rez--;
13231 else if (op == TOK_POST_DEC)
13232 rez++;
13233 }
13234 numptr_m1->val = rez;
13235 /* protect geting var value, is number now */
13236 numptr_m1->var = NULL;
13237 return 0;
13238 err:
13239 return -1;
13240 }
13241
13242 /* longest must be first */
13243 static const char op_tokens[] ALIGN1 = {
13244 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13245 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13246 '<','<', 0, TOK_LSHIFT,
13247 '>','>', 0, TOK_RSHIFT,
13248 '|','|', 0, TOK_OR,
13249 '&','&', 0, TOK_AND,
13250 '!','=', 0, TOK_NE,
13251 '<','=', 0, TOK_LE,
13252 '>','=', 0, TOK_GE,
13253 '=','=', 0, TOK_EQ,
13254 '|','=', 0, TOK_OR_ASSIGN,
13255 '&','=', 0, TOK_AND_ASSIGN,
13256 '*','=', 0, TOK_MUL_ASSIGN,
13257 '/','=', 0, TOK_DIV_ASSIGN,
13258 '%','=', 0, TOK_REM_ASSIGN,
13259 '+','=', 0, TOK_PLUS_ASSIGN,
13260 '-','=', 0, TOK_MINUS_ASSIGN,
13261 '-','-', 0, TOK_POST_DEC,
13262 '^','=', 0, TOK_XOR_ASSIGN,
13263 '+','+', 0, TOK_POST_INC,
13264 '*','*', 0, TOK_EXPONENT,
13265 '!', 0, TOK_NOT,
13266 '<', 0, TOK_LT,
13267 '>', 0, TOK_GT,
13268 '=', 0, TOK_ASSIGN,
13269 '|', 0, TOK_BOR,
13270 '&', 0, TOK_BAND,
13271 '*', 0, TOK_MUL,
13272 '/', 0, TOK_DIV,
13273 '%', 0, TOK_REM,
13274 '+', 0, TOK_ADD,
13275 '-', 0, TOK_SUB,
13276 '^', 0, TOK_BXOR,
13277 /* uniq */
13278 '~', 0, TOK_BNOT,
13279 ',', 0, TOK_COMMA,
13280 '?', 0, TOK_CONDITIONAL,
13281 ':', 0, TOK_CONDITIONAL_SEP,
13282 ')', 0, TOK_RPAREN,
13283 '(', 0, TOK_LPAREN,
13284 0
13285 };
13286 /* ptr to ")" */
13287 #define endexpression (&op_tokens[sizeof(op_tokens)-7])
13288
13289 static arith_t
13290 arith(const char *expr, int *perrcode)
13291 {
13292 char arithval; /* Current character under analysis */
13293 operator lasttok, op;
13294 operator prec;
13295 operator *stack, *stackptr;
13296 const char *p = endexpression;
13297 int errcode;
13298 v_n_t *numstack, *numstackptr;
13299 unsigned datasizes = strlen(expr) + 2;
13300
13301 /* Stack of integers */
13302 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
13303 * in any given correct or incorrect expression is left as an exercise to
13304 * the reader. */
13305 numstackptr = numstack = alloca((datasizes / 2) * sizeof(numstack[0]));
13306 /* Stack of operator tokens */
13307 stackptr = stack = alloca(datasizes * sizeof(stack[0]));
13308
13309 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13310 *perrcode = errcode = 0;
13311
13312 while (1) {
13313 arithval = *expr;
13314 if (arithval == 0) {
13315 if (p == endexpression) {
13316 /* Null expression. */
13317 return 0;
13318 }
13319
13320 /* This is only reached after all tokens have been extracted from the
13321 * input stream. If there are still tokens on the operator stack, they
13322 * are to be applied in order. At the end, there should be a final
13323 * result on the integer stack */
13324
13325 if (expr != endexpression + 1) {
13326 /* If we haven't done so already, */
13327 /* append a closing right paren */
13328 expr = endexpression;
13329 /* and let the loop process it. */
13330 continue;
13331 }
13332 /* At this point, we're done with the expression. */
13333 if (numstackptr != numstack+1) {
13334 /* ... but if there isn't, it's bad */
13335 err:
13336 *perrcode = -1;
13337 return *perrcode;
13338 }
13339 if (numstack->var) {
13340 /* expression is $((var)) only, lookup now */
13341 errcode = arith_lookup_val(numstack);
13342 }
13343 ret:
13344 *perrcode = errcode;
13345 return numstack->val;
13346 }
13347
13348 /* Continue processing the expression. */
13349 if (arith_isspace(arithval)) {
13350 /* Skip whitespace */
13351 goto prologue;
13352 }
13353 p = endofname(expr);
13354 if (p != expr) {
13355 size_t var_name_size = (p-expr) + 1; /* trailing zero */
13356
13357 numstackptr->var = alloca(var_name_size);
13358 safe_strncpy(numstackptr->var, expr, var_name_size);
13359 expr = p;
13360 num:
13361 numstackptr->contidional_second_val_initialized = 0;
13362 numstackptr++;
13363 lasttok = TOK_NUM;
13364 continue;
13365 }
13366 if (isdigit(arithval)) {
13367 numstackptr->var = NULL;
13368 #if ENABLE_ASH_MATH_SUPPORT_64
13369 numstackptr->val = strtoll(expr, (char **) &expr, 0);
13370 #else
13371 numstackptr->val = strtol(expr, (char **) &expr, 0);
13372 #endif
13373 goto num;
13374 }
13375 for (p = op_tokens; ; p++) {
13376 const char *o;
13377
13378 if (*p == 0) {
13379 /* strange operator not found */
13380 goto err;
13381 }
13382 for (o = expr; *p && *o == *p; p++)
13383 o++;
13384 if (!*p) {
13385 /* found */
13386 expr = o - 1;
13387 break;
13388 }
13389 /* skip tail uncompared token */
13390 while (*p)
13391 p++;
13392 /* skip zero delim */
13393 p++;
13394 }
13395 op = p[1];
13396
13397 /* post grammar: a++ reduce to num */
13398 if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13399 lasttok = TOK_NUM;
13400
13401 /* Plus and minus are binary (not unary) _only_ if the last
13402 * token was as number, or a right paren (which pretends to be
13403 * a number, since it evaluates to one). Think about it.
13404 * It makes sense. */
13405 if (lasttok != TOK_NUM) {
13406 switch (op) {
13407 case TOK_ADD:
13408 op = TOK_UPLUS;
13409 break;
13410 case TOK_SUB:
13411 op = TOK_UMINUS;
13412 break;
13413 case TOK_POST_INC:
13414 op = TOK_PRE_INC;
13415 break;
13416 case TOK_POST_DEC:
13417 op = TOK_PRE_DEC;
13418 break;
13419 }
13420 }
13421 /* We don't want a unary operator to cause recursive descent on the
13422 * stack, because there can be many in a row and it could cause an
13423 * operator to be evaluated before its argument is pushed onto the
13424 * integer stack. */
13425 /* But for binary operators, "apply" everything on the operator
13426 * stack until we find an operator with a lesser priority than the
13427 * one we have just extracted. */
13428 /* Left paren is given the lowest priority so it will never be
13429 * "applied" in this way.
13430 * if associativity is right and priority eq, applied also skip
13431 */
13432 prec = PREC(op);
13433 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13434 /* not left paren or unary */
13435 if (lasttok != TOK_NUM) {
13436 /* binary op must be preceded by a num */
13437 goto err;
13438 }
13439 while (stackptr != stack) {
13440 if (op == TOK_RPAREN) {
13441 /* The algorithm employed here is simple: while we don't
13442 * hit an open paren nor the bottom of the stack, pop
13443 * tokens and apply them */
13444 if (stackptr[-1] == TOK_LPAREN) {
13445 --stackptr;
13446 /* Any operator directly after a */
13447 lasttok = TOK_NUM;
13448 /* close paren should consider itself binary */
13449 goto prologue;
13450 }
13451 } else {
13452 operator prev_prec = PREC(stackptr[-1]);
13453
13454 convert_prec_is_assing(prec);
13455 convert_prec_is_assing(prev_prec);
13456 if (prev_prec < prec)
13457 break;
13458 /* check right assoc */
13459 if (prev_prec == prec && is_right_associativity(prec))
13460 break;
13461 }
13462 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13463 if (errcode) goto ret;
13464 }
13465 if (op == TOK_RPAREN) {
13466 goto err;
13467 }
13468 }
13469
13470 /* Push this operator to the stack and remember it. */
13471 *stackptr++ = lasttok = op;
13472 prologue:
13473 ++expr;
13474 } /* while */
13475 }
13476 #endif /* ASH_MATH_SUPPORT */
13477
13478
13479 /* ============ main() and helpers */
13480
13481 /*
13482 * Called to exit the shell.
13483 */
13484 static void exitshell(void) NORETURN;
13485 static void
13486 exitshell(void)
13487 {
13488 struct jmploc loc;
13489 char *p;
13490 int status;
13491
13492 status = exitstatus;
13493 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13494 if (setjmp(loc.loc)) {
13495 if (exception == EXEXIT)
13496 /* dash bug: it just does _exit(exitstatus) here
13497 * but we have to do setjobctl(0) first!
13498 * (bug is still not fixed in dash-0.5.3 - if you run dash
13499 * under Midnight Commander, on exit from dash MC is backgrounded) */
13500 status = exitstatus;
13501 goto out;
13502 }
13503 exception_handler = &loc;
13504 p = trap[0];
13505 if (p) {
13506 trap[0] = NULL;
13507 evalstring(p, 0);
13508 }
13509 flush_stdout_stderr();
13510 out:
13511 setjobctl(0);
13512 _exit(status);
13513 /* NOTREACHED */
13514 }
13515
13516 static void
13517 init(void)
13518 {
13519 /* from input.c: */
13520 basepf.nextc = basepf.buf = basebuf;
13521
13522 /* from trap.c: */
13523 signal(SIGCHLD, SIG_DFL);
13524
13525 /* from var.c: */
13526 {
13527 char **envp;
13528 char ppid[sizeof(int)*3 + 1];
13529 const char *p;
13530 struct stat st1, st2;
13531
13532 initvar();
13533 for (envp = environ; envp && *envp; envp++) {
13534 if (strchr(*envp, '=')) {
13535 setvareq(*envp, VEXPORT|VTEXTFIXED);
13536 }
13537 }
13538
13539 snprintf(ppid, sizeof(ppid), "%u", (unsigned) getppid());
13540 setvar("PPID", ppid, 0);
13541
13542 p = lookupvar("PWD");
13543 if (p)
13544 if (*p != '/' || stat(p, &st1) || stat(".", &st2)
13545 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
13546 p = '\0';
13547 setpwd(p, 0);
13548 }
13549 }
13550
13551 /*
13552 * Process the shell command line arguments.
13553 */
13554 static void
13555 procargs(char **argv)
13556 {
13557 int i;
13558 const char *xminusc;
13559 char **xargv;
13560
13561 xargv = argv;
13562 arg0 = xargv[0];
13563 /* if (xargv[0]) - mmm, this is always true! */
13564 xargv++;
13565 for (i = 0; i < NOPTS; i++)
13566 optlist[i] = 2;
13567 argptr = xargv;
13568 if (options(1)) {
13569 /* it already printed err message */
13570 raise_exception(EXERROR);
13571 }
13572 xargv = argptr;
13573 xminusc = minusc;
13574 if (*xargv == NULL) {
13575 if (xminusc)
13576 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13577 sflag = 1;
13578 }
13579 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13580 iflag = 1;
13581 if (mflag == 2)
13582 mflag = iflag;
13583 for (i = 0; i < NOPTS; i++)
13584 if (optlist[i] == 2)
13585 optlist[i] = 0;
13586 #if DEBUG == 2
13587 debug = 1;
13588 #endif
13589 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13590 if (xminusc) {
13591 minusc = *xargv++;
13592 if (*xargv)
13593 goto setarg0;
13594 } else if (!sflag) {
13595 setinputfile(*xargv, 0);
13596 setarg0:
13597 arg0 = *xargv++;
13598 commandname = arg0;
13599 }
13600
13601 shellparam.p = xargv;
13602 #if ENABLE_ASH_GETOPTS
13603 shellparam.optind = 1;
13604 shellparam.optoff = -1;
13605 #endif
13606 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
13607 while (*xargv) {
13608 shellparam.nparam++;
13609 xargv++;
13610 }
13611 optschanged();
13612 }
13613
13614 /*
13615 * Read /etc/profile or .profile.
13616 */
13617 static void
13618 read_profile(const char *name)
13619 {
13620 int skip;
13621
13622 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13623 return;
13624 skip = cmdloop(0);
13625 popfile();
13626 if (skip)
13627 exitshell();
13628 }
13629
13630 /*
13631 * This routine is called when an error or an interrupt occurs in an
13632 * interactive shell and control is returned to the main command loop.
13633 */
13634 static void
13635 reset(void)
13636 {
13637 /* from eval.c: */
13638 evalskip = 0;
13639 loopnest = 0;
13640 /* from input.c: */
13641 parselleft = parsenleft = 0; /* clear input buffer */
13642 popallfiles();
13643 /* from parser.c: */
13644 tokpushback = 0;
13645 checkkwd = 0;
13646 /* from redir.c: */
13647 clearredir(/*drop:*/ 0);
13648 }
13649
13650 #if PROFILE
13651 static short profile_buf[16384];
13652 extern int etext();
13653 #endif
13654
13655 /*
13656 * Main routine. We initialize things, parse the arguments, execute
13657 * profiles if we're a login shell, and then call cmdloop to execute
13658 * commands. The setjmp call sets up the location to jump to when an
13659 * exception occurs. When an exception occurs the variable "state"
13660 * is used to figure out how far we had gotten.
13661 */
13662 int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
13663 int ash_main(int argc UNUSED_PARAM, char **argv)
13664 {
13665 char *shinit;
13666 volatile int state;
13667 struct jmploc jmploc;
13668 struct stackmark smark;
13669
13670 /* Initialize global data */
13671 INIT_G_misc();
13672 INIT_G_memstack();
13673 INIT_G_var();
13674 #if ENABLE_ASH_ALIAS
13675 INIT_G_alias();
13676 #endif
13677 INIT_G_cmdtable();
13678
13679 #if PROFILE
13680 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13681 #endif
13682
13683 #if ENABLE_FEATURE_EDITING
13684 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13685 #endif
13686 state = 0;
13687 if (setjmp(jmploc.loc)) {
13688 int e;
13689 int s;
13690
13691 reset();
13692
13693 e = exception;
13694 if (e == EXERROR)
13695 exitstatus = 2;
13696 s = state;
13697 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
13698 exitshell();
13699
13700 if (e == EXINT) {
13701 outcslow('\n', stderr);
13702 }
13703 popstackmark(&smark);
13704 FORCE_INT_ON; /* enable interrupts */
13705 if (s == 1)
13706 goto state1;
13707 if (s == 2)
13708 goto state2;
13709 if (s == 3)
13710 goto state3;
13711 goto state4;
13712 }
13713 exception_handler = &jmploc;
13714 #if DEBUG
13715 opentrace();
13716 TRACE(("Shell args: "));
13717 trace_puts_args(argv);
13718 #endif
13719 rootpid = getpid();
13720
13721 #if ENABLE_ASH_RANDOM_SUPPORT
13722 /* Can use monotonic_ns() for better randomness but for now it is
13723 * not used anywhere else in busybox... so avoid bloat */
13724 random_galois_LFSR = random_LCG = rootpid + monotonic_us();
13725 #endif
13726 init();
13727 setstackmark(&smark);
13728 procargs(argv);
13729
13730 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13731 if (iflag) {
13732 const char *hp = lookupvar("HISTFILE");
13733
13734 if (hp == NULL) {
13735 hp = lookupvar("HOME");
13736 if (hp != NULL) {
13737 char *defhp = concat_path_file(hp, ".ash_history");
13738 setvar("HISTFILE", defhp, 0);
13739 free(defhp);
13740 }
13741 }
13742 }
13743 #endif
13744 if (argv[0] && argv[0][0] == '-')
13745 isloginsh = 1;
13746 if (isloginsh) {
13747 state = 1;
13748 read_profile("/etc/profile");
13749 state1:
13750 state = 2;
13751 read_profile(".profile");
13752 }
13753 state2:
13754 state = 3;
13755 if (
13756 #ifndef linux
13757 getuid() == geteuid() && getgid() == getegid() &&
13758 #endif
13759 iflag
13760 ) {
13761 shinit = lookupvar("ENV");
13762 if (shinit != NULL && *shinit != '\0') {
13763 read_profile(shinit);
13764 }
13765 }
13766 state3:
13767 state = 4;
13768 if (minusc) {
13769 /* evalstring pushes parsefile stack.
13770 * Ensure we don't falsely claim that 0 (stdin)
13771 * is one of stacked source fds */
13772 if (!sflag)
13773 g_parsefile->fd = -1;
13774 evalstring(minusc, 0);
13775 }
13776
13777 if (sflag || minusc == NULL) {
13778 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13779 if (iflag) {
13780 const char *hp = lookupvar("HISTFILE");
13781
13782 if (hp != NULL)
13783 line_input_state->hist_file = hp;
13784 }
13785 #endif
13786 state4: /* XXX ??? - why isn't this before the "if" statement */
13787 cmdloop(1);
13788 }
13789 #if PROFILE
13790 monitor(0);
13791 #endif
13792 #ifdef GPROF
13793 {
13794 extern void _mcleanup(void);
13795 _mcleanup();
13796 }
13797 #endif
13798 exitshell();
13799 /* NOTREACHED */
13800 }
13801
13802
13803 /*-
13804 * Copyright (c) 1989, 1991, 1993, 1994
13805 * The Regents of the University of California. All rights reserved.
13806 *
13807 * This code is derived from software contributed to Berkeley by
13808 * Kenneth Almquist.
13809 *
13810 * Redistribution and use in source and binary forms, with or without
13811 * modification, are permitted provided that the following conditions
13812 * are met:
13813 * 1. Redistributions of source code must retain the above copyright
13814 * notice, this list of conditions and the following disclaimer.
13815 * 2. Redistributions in binary form must reproduce the above copyright
13816 * notice, this list of conditions and the following disclaimer in the
13817 * documentation and/or other materials provided with the distribution.
13818 * 3. Neither the name of the University nor the names of its contributors
13819 * may be used to endorse or promote products derived from this software
13820 * without specific prior written permission.
13821 *
13822 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13823 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13824 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13825 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13826 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13827 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13828 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13829 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13830 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13831 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13832 * SUCH DAMAGE.
13833 */