summaryrefslogtreecommitdiff
path: root/shell/ash.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/ash.c')
-rw-r--r--shell/ash.c189
1 files changed, 130 insertions, 59 deletions
diff --git a/shell/ash.c b/shell/ash.c
index d6fd38849..e3f79fcd5 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -30,7 +30,7 @@
30 */ 30 */
31 31
32/* 32/*
33 * The follow should be set to reflect the type of system you have: 33 * The following should be set to reflect the type of system you have:
34 * JOBS -> 1 if you have Berkeley job control, 0 otherwise. 34 * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
35 * define SYSV if you are running under System V. 35 * define SYSV if you are running under System V.
36 * define DEBUG=1 to compile in debugging ('set -o debug' to turn on) 36 * define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
@@ -40,6 +40,11 @@
40 * a quit signal will generate a core dump. 40 * a quit signal will generate a core dump.
41 */ 41 */
42#define DEBUG 0 42#define DEBUG 0
43/* Tweak debug output verbosity here */
44#define DEBUG_TIME 0
45#define DEBUG_PID 1
46#define DEBUG_SIG 1
47
43#define PROFILE 0 48#define PROFILE 0
44 49
45#define IFS_BROKEN 50#define IFS_BROKEN
@@ -47,9 +52,9 @@
47#define JOBS ENABLE_ASH_JOB_CONTROL 52#define JOBS ENABLE_ASH_JOB_CONTROL
48 53
49#if DEBUG 54#if DEBUG
50#ifndef _GNU_SOURCE 55# ifndef _GNU_SOURCE
51#define _GNU_SOURCE 56# define _GNU_SOURCE
52#endif 57# endif
53#endif 58#endif
54 59
55#include "busybox.h" /* for applet_names */ 60#include "busybox.h" /* for applet_names */
@@ -57,15 +62,15 @@
57#include <setjmp.h> 62#include <setjmp.h>
58#include <fnmatch.h> 63#include <fnmatch.h>
59#if JOBS || ENABLE_ASH_READ_NCHARS 64#if JOBS || ENABLE_ASH_READ_NCHARS
60#include <termios.h> 65# include <termios.h>
61#endif 66#endif
62 67
63#ifndef PIPE_BUF 68#ifndef PIPE_BUF
64#define PIPE_BUF 4096 /* amount of buffering in a pipe */ 69# define PIPE_BUF 4096 /* amount of buffering in a pipe */
65#endif 70#endif
66 71
67#if defined(__uClinux__) 72#if defined(__uClinux__)
68#error "Do not even bother, ash will not run on uClinux" 73# error "Do not even bother, ash will not run on uClinux"
69#endif 74#endif
70 75
71 76
@@ -76,14 +81,6 @@
76#define CMDTABLESIZE 31 /* should be prime */ 81#define CMDTABLESIZE 31 /* should be prime */
77 82
78 83
79/* ============ Misc helpers */
80
81#define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0)
82
83/* C99 say: "char" declaration may be signed or unsigned default */
84#define signed_char2int(sc) ((int)((signed char)sc))
85
86
87/* ============ Shell options */ 84/* ============ Shell options */
88 85
89static const char *const optletters_optnames[] = { 86static const char *const optletters_optnames[] = {
@@ -245,7 +242,30 @@ extern struct globals_misc *const ash_ptr_to_globals_misc;
245} while (0) 242} while (0)
246 243
247 244
245/* ============ DEBUG */
246#if DEBUG
247static void trace_printf(const char *fmt, ...);
248static void trace_vprintf(const char *fmt, va_list va);
249# define TRACE(param) trace_printf param
250# define TRACEV(param) trace_vprintf param
251# define close(f) do { \
252 int dfd = (f); \
253 if (close(dfd) < 0) \
254 bb_error_msg("bug on %d: closing %d(%x)", \
255 __LINE__, dfd, dfd); \
256} while (0)
257#else
258# define TRACE(param)
259# define TRACEV(param)
260#endif
261
262
248/* ============ Utility functions */ 263/* ============ Utility functions */
264#define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0)
265
266/* C99 say: "char" declaration may be signed or unsigned by default */
267#define signed_char2int(sc) ((int)(signed char)(sc))
268
249static int isdigit_str9(const char *str) 269static int isdigit_str9(const char *str)
250{ 270{
251 int maxlen = 9 + 1; /* max 9 digits: 999999999 */ 271 int maxlen = 9 + 1; /* max 9 digits: 999999999 */
@@ -284,6 +304,12 @@ raise_exception(int e)
284 exception = e; 304 exception = e;
285 longjmp(exception_handler->loc, 1); 305 longjmp(exception_handler->loc, 1);
286} 306}
307#if DEBUG
308#define raise_exception(e) do { \
309 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
310 raise_exception(e); \
311} while (0)
312#endif
287 313
288/* 314/*
289 * Called from trap.c when a SIGINT is received. (If the user specifies 315 * Called from trap.c when a SIGINT is received. (If the user specifies
@@ -316,6 +342,12 @@ raise_interrupt(void)
316 raise_exception(i); 342 raise_exception(i);
317 /* NOTREACHED */ 343 /* NOTREACHED */
318} 344}
345#if DEBUG
346#define raise_interrupt() do { \
347 TRACE(("raising interrupt on line %d\n", __LINE__)); \
348 raise_interrupt(); \
349} while (0)
350#endif
319 351
320#if ENABLE_ASH_OPTIMIZE_FOR_SIZE 352#if ENABLE_ASH_OPTIMIZE_FOR_SIZE
321static void 353static void
@@ -334,7 +366,9 @@ force_int_on(void)
334 raise_interrupt(); 366 raise_interrupt();
335} 367}
336#define FORCE_INT_ON force_int_on() 368#define FORCE_INT_ON force_int_on()
337#else 369
370#else /* !ASH_OPTIMIZE_FOR_SIZE */
371
338#define INT_ON do { \ 372#define INT_ON do { \
339 xbarrier(); \ 373 xbarrier(); \
340 if (--suppressint == 0 && intpending) \ 374 if (--suppressint == 0 && intpending) \
@@ -346,7 +380,7 @@ force_int_on(void)
346 if (intpending) \ 380 if (intpending) \
347 raise_interrupt(); \ 381 raise_interrupt(); \
348} while (0) 382} while (0)
349#endif /* ASH_OPTIMIZE_FOR_SIZE */ 383#endif /* !ASH_OPTIMIZE_FOR_SIZE */
350 384
351#define SAVE_INT(v) ((v) = suppressint) 385#define SAVE_INT(v) ((v) = suppressint)
352 386
@@ -376,7 +410,6 @@ static void
376onsig(int signo) 410onsig(int signo)
377{ 411{
378 gotsig[signo - 1] = 1; 412 gotsig[signo - 1] = 1;
379 pendingsig = signo;
380 413
381 if (/* exsig || */ (signo == SIGINT && !trap[SIGINT])) { 414 if (/* exsig || */ (signo == SIGINT && !trap[SIGINT])) {
382 if (!suppressint) { 415 if (!suppressint) {
@@ -384,6 +417,8 @@ onsig(int signo)
384 raise_interrupt(); /* does not return */ 417 raise_interrupt(); /* does not return */
385 } 418 }
386 intpending = 1; 419 intpending = 1;
420 } else {
421 pendingsig = signo;
387 } 422 }
388} 423}
389 424
@@ -684,6 +719,12 @@ trace_printf(const char *fmt, ...)
684 719
685 if (debug != 1) 720 if (debug != 1)
686 return; 721 return;
722 if (DEBUG_TIME)
723 fprintf(tracefile, "%u ", (int) time(NULL));
724 if (DEBUG_PID)
725 fprintf(tracefile, "[%u] ", (int) getpid());
726 if (DEBUG_SIG)
727 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pendingsig, intpending, suppressint);
687 va_start(va, fmt); 728 va_start(va, fmt);
688 vfprintf(tracefile, fmt, va); 729 vfprintf(tracefile, fmt, va);
689 va_end(va); 730 va_end(va);
@@ -694,6 +735,12 @@ trace_vprintf(const char *fmt, va_list va)
694{ 735{
695 if (debug != 1) 736 if (debug != 1)
696 return; 737 return;
738 if (DEBUG_TIME)
739 fprintf(tracefile, "%u ", (int) time(NULL));
740 if (DEBUG_PID)
741 fprintf(tracefile, "[%u] ", (int) getpid());
742 if (DEBUG_SIG)
743 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pendingsig, intpending, suppressint);
697 vfprintf(tracefile, fmt, va); 744 vfprintf(tracefile, fmt, va);
698} 745}
699 746
@@ -998,14 +1045,6 @@ showtree(union node *n)
998 shtree(n, 1, NULL, stdout); 1045 shtree(n, 1, NULL, stdout);
999} 1046}
1000 1047
1001#define TRACE(param) trace_printf param
1002#define TRACEV(param) trace_vprintf param
1003
1004#else
1005
1006#define TRACE(param)
1007#define TRACEV(param)
1008
1009#endif /* DEBUG */ 1048#endif /* DEBUG */
1010 1049
1011 1050
@@ -3779,7 +3818,7 @@ dowait(int wait_flags, struct job *job)
3779 * NB: _not_ safe_waitpid, we need to detect EINTR */ 3818 * NB: _not_ safe_waitpid, we need to detect EINTR */
3780 pid = waitpid(-1, &status, 3819 pid = waitpid(-1, &status,
3781 (doing_jobctl ? (wait_flags | WUNTRACED) : wait_flags)); 3820 (doing_jobctl ? (wait_flags | WUNTRACED) : wait_flags));
3782 TRACE(("wait returns pid=%d, status=0x%x\n", pid, status)); 3821 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", pid, status, errno, strerror(errno)));
3783 3822
3784 if (pid <= 0) { 3823 if (pid <= 0) {
3785 /* If we were doing blocking wait and (probably) got EINTR, 3824 /* If we were doing blocking wait and (probably) got EINTR,
@@ -5031,7 +5070,9 @@ redirect(union node *redir, int flags)
5031 if (newfd < 0) { 5070 if (newfd < 0) {
5032 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */ 5071 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
5033 if (redir->ndup.dupfd < 0) { /* "fd>&-" */ 5072 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
5034 close(fd); 5073 /* Don't want to trigger debugging */
5074 if (fd != -1)
5075 close(fd);
5035 } else { 5076 } else {
5036 copyfd(redir->ndup.dupfd, fd | COPYFD_EXACT); 5077 copyfd(redir->ndup.dupfd, fd | COPYFD_EXACT);
5037 } 5078 }
@@ -5084,7 +5125,7 @@ popredir(int drop, int restore)
5084 /*close(fd);*/ 5125 /*close(fd);*/
5085 copyfd(copy, fd | COPYFD_EXACT); 5126 copyfd(copy, fd | COPYFD_EXACT);
5086 } 5127 }
5087 close(copy); 5128 close(copy & ~COPYFD_RESTORE);
5088 } 5129 }
5089 } 5130 }
5090 redirlist = rp->next; 5131 redirlist = rp->next;
@@ -7871,20 +7912,30 @@ dotrap(void)
7871 pendingsig = 0; 7912 pendingsig = 0;
7872 xbarrier(); 7913 xbarrier();
7873 7914
7915 TRACE(("dotrap entered\n"));
7874 for (i = 1, q = gotsig; i < NSIG; i++, q++) { 7916 for (i = 1, q = gotsig; i < NSIG; i++, q++) {
7875 if (!*q) 7917 if (!*q)
7876 continue; 7918 continue;
7877 *q = '\0';
7878 7919
7879 p = trap[i]; 7920 p = trap[i];
7921 /* non-trapped SIGINT is handled separately by raise_interrupt,
7922 * don't upset it by resetting gotsig[SIGINT-1] */
7923 if (i == SIGINT && !p)
7924 continue;
7925
7926 TRACE(("sig %d is active, will run handler '%s'\n", i, p));
7927 *q = '\0';
7880 if (!p) 7928 if (!p)
7881 continue; 7929 continue;
7882 skip = evalstring(p, SKIPEVAL); 7930 skip = evalstring(p, SKIPEVAL);
7883 exitstatus = savestatus; 7931 exitstatus = savestatus;
7884 if (skip) 7932 if (skip) {
7933 TRACE(("dotrap returns %d\n", skip));
7885 return skip; 7934 return skip;
7935 }
7886 } 7936 }
7887 7937
7938 TRACE(("dotrap returns 0\n"));
7888 return 0; 7939 return 0;
7889} 7940}
7890 7941
@@ -7906,28 +7957,32 @@ static void prehash(union node *);
7906static void 7957static void
7907evaltree(union node *n, int flags) 7958evaltree(union node *n, int flags)
7908{ 7959{
7909
7910 struct jmploc *volatile savehandler = exception_handler; 7960 struct jmploc *volatile savehandler = exception_handler;
7911 struct jmploc jmploc; 7961 struct jmploc jmploc;
7912 int checkexit = 0; 7962 int checkexit = 0;
7913 void (*evalfn)(union node *, int); 7963 void (*evalfn)(union node *, int);
7914 int status; 7964 int status;
7965 int int_level;
7966
7967 SAVE_INT(int_level);
7915 7968
7916 if (n == NULL) { 7969 if (n == NULL) {
7917 TRACE(("evaltree(NULL) called\n")); 7970 TRACE(("evaltree(NULL) called\n"));
7918 goto out1; 7971 goto out1;
7919 } 7972 }
7920 TRACE(("pid %d, evaltree(%p: %d, %d) called\n", 7973 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
7921 getpid(), n, n->type, flags));
7922 7974
7923 exception_handler = &jmploc; 7975 exception_handler = &jmploc;
7924 { 7976 {
7925 int err = setjmp(jmploc.loc); 7977 int err = setjmp(jmploc.loc);
7926 if (err) { 7978 if (err) {
7927 /* if it was a signal, check for trap handlers */ 7979 /* if it was a signal, check for trap handlers */
7928 if (exception == EXSIG) 7980 if (exception == EXSIG) {
7981 TRACE(("exception %d (EXSIG) in evaltree, err=%d\n", exception, err));
7929 goto out; 7982 goto out;
7983 }
7930 /* continue on the way out */ 7984 /* continue on the way out */
7985 TRACE(("exception %d in evaltree, propagating err=%d\n", exception, err));
7931 exception_handler = savehandler; 7986 exception_handler = savehandler;
7932 longjmp(exception_handler->loc, err); 7987 longjmp(exception_handler->loc, err);
7933 } 7988 }
@@ -8010,7 +8065,8 @@ evaltree(union node *n, int flags)
8010 if (exitstatus == 0) { 8065 if (exitstatus == 0) {
8011 n = n->nif.ifpart; 8066 n = n->nif.ifpart;
8012 goto evaln; 8067 goto evaln;
8013 } else if (n->nif.elsepart) { 8068 }
8069 if (n->nif.elsepart) {
8014 n = n->nif.elsepart; 8070 n = n->nif.elsepart;
8015 goto evaln; 8071 goto evaln;
8016 } 8072 }
@@ -8036,6 +8092,9 @@ evaltree(union node *n, int flags)
8036 exexit: 8092 exexit:
8037 raise_exception(EXEXIT); 8093 raise_exception(EXEXIT);
8038 } 8094 }
8095
8096 RESTORE_INT(int_level);
8097 TRACE(("leaving evaltree (no interrupts)\n"));
8039} 8098}
8040 8099
8041#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3) 8100#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
@@ -8281,7 +8340,9 @@ evalpipe(union node *n, int flags)
8281 if (prevfd >= 0) 8340 if (prevfd >= 0)
8282 close(prevfd); 8341 close(prevfd);
8283 prevfd = pip[0]; 8342 prevfd = pip[0];
8284 close(pip[1]); 8343 /* Don't want to trigger debugging */
8344 if (pip[1] != -1)
8345 close(pip[1]);
8285 } 8346 }
8286 if (n->npipe.pipe_backgnd == 0) { 8347 if (n->npipe.pipe_backgnd == 0) {
8287 exitstatus = waitforjob(jp); 8348 exitstatus = waitforjob(jp);
@@ -8913,6 +8974,7 @@ evalcommand(union node *cmd, int flags)
8913 if (forkshell(jp, cmd, FORK_FG) != 0) { 8974 if (forkshell(jp, cmd, FORK_FG) != 0) {
8914 exitstatus = waitforjob(jp); 8975 exitstatus = waitforjob(jp);
8915 INT_ON; 8976 INT_ON;
8977 TRACE(("forked child exited with %d\n", exitstatus));
8916 break; 8978 break;
8917 } 8979 }
8918 FORCE_INT_ON; 8980 FORCE_INT_ON;
@@ -12391,7 +12453,7 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12391#endif 12453#endif
12392 12454
12393 status = 0; 12455 status = 0;
12394 startword = 1; 12456 startword = 2;
12395 backslash = 0; 12457 backslash = 0;
12396#if ENABLE_ASH_READ_TIMEOUT 12458#if ENABLE_ASH_READ_TIMEOUT
12397 if (timeout) /* NB: ensuring end_ms is nonzero */ 12459 if (timeout) /* NB: ensuring end_ms is nonzero */
@@ -12399,6 +12461,8 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12399#endif 12461#endif
12400 STARTSTACKSTR(p); 12462 STARTSTACKSTR(p);
12401 do { 12463 do {
12464 const char *is_ifs;
12465
12402#if ENABLE_ASH_READ_TIMEOUT 12466#if ENABLE_ASH_READ_TIMEOUT
12403 if (end_ms) { 12467 if (end_ms) {
12404 struct pollfd pfd[1]; 12468 struct pollfd pfd[1];
@@ -12428,25 +12492,34 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12428 continue; 12492 continue;
12429 } 12493 }
12430 if (!rflag && c == '\\') { 12494 if (!rflag && c == '\\') {
12431 backslash++; 12495 backslash = 1;
12432 continue; 12496 continue;
12433 } 12497 }
12434 if (c == '\n') 12498 if (c == '\n')
12435 break; 12499 break;
12436 if (startword && *ifs == ' ' && strchr(ifs, c)) { 12500 is_ifs = strchr(ifs, c);
12437 continue; 12501 if (startword && is_ifs) {
12502 if (isspace(c))
12503 continue;
12504 /* non-space ifs char */
12505 startword--;
12506 if (startword == 1) /* first one? */
12507 continue;
12438 } 12508 }
12439 startword = 0; 12509 startword = 0;
12440 if (ap[1] != NULL && strchr(ifs, c) != NULL) { 12510 if (ap[1] != NULL && is_ifs) {
12511 const char *beg;
12441 STACKSTRNUL(p); 12512 STACKSTRNUL(p);
12442 setvar(*ap, stackblock(), 0); 12513 beg = stackblock();
12514 setvar(*ap, beg, 0);
12443 ap++; 12515 ap++;
12444 startword = 1; 12516 /* can we skip one non-space ifs? (2: yes) */
12517 startword = isspace(c) ? 2 : 1;
12445 STARTSTACKSTR(p); 12518 STARTSTACKSTR(p);
12446 } else { 12519 continue;
12447 put:
12448 STPUTC(c, p);
12449 } 12520 }
12521 put:
12522 STPUTC(c, p);
12450 } 12523 }
12451/* end of do {} while: */ 12524/* end of do {} while: */
12452#if ENABLE_ASH_READ_NCHARS 12525#if ENABLE_ASH_READ_NCHARS
@@ -12460,8 +12533,8 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12460#endif 12533#endif
12461 12534
12462 STACKSTRNUL(p); 12535 STACKSTRNUL(p);
12463 /* Remove trailing blanks */ 12536 /* Remove trailing space ifs chars */
12464 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL) 12537 while ((char *)stackblock() <= --p && isspace(*p) && strchr(ifs, *p) != NULL)
12465 *p = '\0'; 12538 *p = '\0';
12466 setvar(*ap, stackblock(), 0); 12539 setvar(*ap, stackblock(), 0);
12467 while (*++ap != NULL) 12540 while (*++ap != NULL)
@@ -13640,7 +13713,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
13640 exception_handler = &jmploc; 13713 exception_handler = &jmploc;
13641#if DEBUG 13714#if DEBUG
13642 opentrace(); 13715 opentrace();
13643 trace_puts("Shell args: "); 13716 TRACE(("Shell args: "));
13644 trace_puts_args(argv); 13717 trace_puts_args(argv);
13645#endif 13718#endif
13646 rootpid = getpid(); 13719 rootpid = getpid();
@@ -13692,8 +13765,14 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
13692 } 13765 }
13693 state3: 13766 state3:
13694 state = 4; 13767 state = 4;
13695 if (minusc) 13768 if (minusc) {
13769 /* evalstring pushes parsefile stack.
13770 * Ensure we don't falsely claim that 0 (stdin)
13771 * is one of stacked source fds */
13772 if (!sflag)
13773 g_parsefile->fd = -1;
13696 evalstring(minusc, 0); 13774 evalstring(minusc, 0);
13775 }
13697 13776
13698 if (sflag || minusc == NULL) { 13777 if (sflag || minusc == NULL) {
13699#if ENABLE_FEATURE_EDITING_SAVEHISTORY 13778#if ENABLE_FEATURE_EDITING_SAVEHISTORY
@@ -13720,14 +13799,6 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
13720 /* NOTREACHED */ 13799 /* NOTREACHED */
13721} 13800}
13722 13801
13723#if DEBUG
13724const char *applet_name = "debug stuff usage";
13725int main(int argc, char **argv)
13726{
13727 return ash_main(argc, argv);
13728}
13729#endif
13730
13731 13802
13732/*- 13803/*-
13733 * Copyright (c) 1989, 1991, 1993, 1994 13804 * Copyright (c) 1989, 1991, 1993, 1994