Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 532 - (show annotations) (download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 8 months ago) by niro
File MIME type: text/plain
File size: 288464 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd

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