Submitted By: Jim Gifford (jim at cross-lfs dot org) Date: 03-28-2009 Initial Package Version: 1.13.3 Origin: Upstream Upstream Status: Applied Description: This is a branch update for busybox-1.13.3, and should be rechecked periodically. diff -Naur busybox-1.13.3.orig/coreutils/tail.c busybox-1.13.3/coreutils/tail.c --- busybox-1.13.3.orig/coreutils/tail.c 2009-02-26 03:47:02.000000000 -0800 +++ busybox-1.13.3/coreutils/tail.c 2009-03-28 08:25:12.762859338 -0700 @@ -104,7 +104,7 @@ if (argv[1] && (argv[1][0] == '+' || argv[1][0] == '-') && isdigit(argv[1][1]) ) { - count = eat_num(&argv[1][1]); + count = eat_num(argv[1]); argv++; argc--; } diff -Naur busybox-1.13.3.orig/shell/ash.c busybox-1.13.3/shell/ash.c --- busybox-1.13.3.orig/shell/ash.c 2009-02-26 03:46:55.000000000 -0800 +++ busybox-1.13.3/shell/ash.c 2009-03-28 08:25:12.198825534 -0700 @@ -30,7 +30,7 @@ */ /* - * The follow should be set to reflect the type of system you have: + * The following should be set to reflect the type of system you have: * JOBS -> 1 if you have Berkeley job control, 0 otherwise. * define SYSV if you are running under System V. * define DEBUG=1 to compile in debugging ('set -o debug' to turn on) @@ -40,6 +40,11 @@ * a quit signal will generate a core dump. */ #define DEBUG 0 +/* Tweak debug output verbosity here */ +#define DEBUG_TIME 0 +#define DEBUG_PID 1 +#define DEBUG_SIG 1 + #define PROFILE 0 #define IFS_BROKEN @@ -47,9 +52,9 @@ #define JOBS ENABLE_ASH_JOB_CONTROL #if DEBUG -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif +# ifndef _GNU_SOURCE +# define _GNU_SOURCE +# endif #endif #include "busybox.h" /* for applet_names */ @@ -57,15 +62,15 @@ #include #include #if JOBS || ENABLE_ASH_READ_NCHARS -#include +# include #endif #ifndef PIPE_BUF -#define PIPE_BUF 4096 /* amount of buffering in a pipe */ +# define PIPE_BUF 4096 /* amount of buffering in a pipe */ #endif #if defined(__uClinux__) -#error "Do not even bother, ash will not run on uClinux" +# error "Do not even bother, ash will not run on uClinux" #endif @@ -76,14 +81,6 @@ #define CMDTABLESIZE 31 /* should be prime */ -/* ============ Misc helpers */ - -#define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0) - -/* C99 say: "char" declaration may be signed or unsigned default */ -#define signed_char2int(sc) ((int)((signed char)sc)) - - /* ============ Shell options */ static const char *const optletters_optnames[] = { @@ -245,7 +242,30 @@ } while (0) +/* ============ DEBUG */ +#if DEBUG +static void trace_printf(const char *fmt, ...); +static void trace_vprintf(const char *fmt, va_list va); +# define TRACE(param) trace_printf param +# define TRACEV(param) trace_vprintf param +# define close(f) do { \ + int dfd = (f); \ + if (close(dfd) < 0) \ + bb_error_msg("bug on %d: closing %d(%x)", \ + __LINE__, dfd, dfd); \ +} while (0) +#else +# define TRACE(param) +# define TRACEV(param) +#endif + + /* ============ Utility functions */ +#define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0) + +/* C99 say: "char" declaration may be signed or unsigned by default */ +#define signed_char2int(sc) ((int)(signed char)(sc)) + static int isdigit_str9(const char *str) { int maxlen = 9 + 1; /* max 9 digits: 999999999 */ @@ -284,6 +304,12 @@ exception = e; longjmp(exception_handler->loc, 1); } +#if DEBUG +#define raise_exception(e) do { \ + TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \ + raise_exception(e); \ +} while (0) +#endif /* * Called from trap.c when a SIGINT is received. (If the user specifies @@ -316,6 +342,12 @@ raise_exception(i); /* NOTREACHED */ } +#if DEBUG +#define raise_interrupt() do { \ + TRACE(("raising interrupt on line %d\n", __LINE__)); \ + raise_interrupt(); \ +} while (0) +#endif #if ENABLE_ASH_OPTIMIZE_FOR_SIZE static void @@ -334,7 +366,9 @@ raise_interrupt(); } #define FORCE_INT_ON force_int_on() -#else + +#else /* !ASH_OPTIMIZE_FOR_SIZE */ + #define INT_ON do { \ xbarrier(); \ if (--suppressint == 0 && intpending) \ @@ -346,7 +380,7 @@ if (intpending) \ raise_interrupt(); \ } while (0) -#endif /* ASH_OPTIMIZE_FOR_SIZE */ +#endif /* !ASH_OPTIMIZE_FOR_SIZE */ #define SAVE_INT(v) ((v) = suppressint) @@ -376,7 +410,6 @@ onsig(int signo) { gotsig[signo - 1] = 1; - pendingsig = signo; if (/* exsig || */ (signo == SIGINT && !trap[SIGINT])) { if (!suppressint) { @@ -384,6 +417,8 @@ raise_interrupt(); /* does not return */ } intpending = 1; + } else { + pendingsig = signo; } } @@ -684,6 +719,12 @@ if (debug != 1) return; + if (DEBUG_TIME) + fprintf(tracefile, "%u ", (int) time(NULL)); + if (DEBUG_PID) + fprintf(tracefile, "[%u] ", (int) getpid()); + if (DEBUG_SIG) + fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pendingsig, intpending, suppressint); va_start(va, fmt); vfprintf(tracefile, fmt, va); va_end(va); @@ -694,6 +735,12 @@ { if (debug != 1) return; + if (DEBUG_TIME) + fprintf(tracefile, "%u ", (int) time(NULL)); + if (DEBUG_PID) + fprintf(tracefile, "[%u] ", (int) getpid()); + if (DEBUG_SIG) + fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pendingsig, intpending, suppressint); vfprintf(tracefile, fmt, va); } @@ -998,14 +1045,6 @@ shtree(n, 1, NULL, stdout); } -#define TRACE(param) trace_printf param -#define TRACEV(param) trace_vprintf param - -#else - -#define TRACE(param) -#define TRACEV(param) - #endif /* DEBUG */ @@ -3779,7 +3818,7 @@ * NB: _not_ safe_waitpid, we need to detect EINTR */ pid = waitpid(-1, &status, (doing_jobctl ? (wait_flags | WUNTRACED) : wait_flags)); - TRACE(("wait returns pid=%d, status=0x%x\n", pid, status)); + TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", pid, status, errno, strerror(errno))); if (pid <= 0) { /* If we were doing blocking wait and (probably) got EINTR, @@ -5031,7 +5070,9 @@ if (newfd < 0) { /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */ if (redir->ndup.dupfd < 0) { /* "fd>&-" */ - close(fd); + /* Don't want to trigger debugging */ + if (fd != -1) + close(fd); } else { copyfd(redir->ndup.dupfd, fd | COPYFD_EXACT); } @@ -5084,7 +5125,7 @@ /*close(fd);*/ copyfd(copy, fd | COPYFD_EXACT); } - close(copy); + close(copy & ~COPYFD_RESTORE); } } redirlist = rp->next; @@ -7871,20 +7912,30 @@ pendingsig = 0; xbarrier(); + TRACE(("dotrap entered\n")); for (i = 1, q = gotsig; i < NSIG; i++, q++) { if (!*q) continue; - *q = '\0'; p = trap[i]; + /* non-trapped SIGINT is handled separately by raise_interrupt, + * don't upset it by resetting gotsig[SIGINT-1] */ + if (i == SIGINT && !p) + continue; + + TRACE(("sig %d is active, will run handler '%s'\n", i, p)); + *q = '\0'; if (!p) continue; skip = evalstring(p, SKIPEVAL); exitstatus = savestatus; - if (skip) + if (skip) { + TRACE(("dotrap returns %d\n", skip)); return skip; + } } + TRACE(("dotrap returns 0\n")); return 0; } @@ -7906,28 +7957,32 @@ static void evaltree(union node *n, int flags) { - struct jmploc *volatile savehandler = exception_handler; struct jmploc jmploc; int checkexit = 0; void (*evalfn)(union node *, int); int status; + int int_level; + + SAVE_INT(int_level); if (n == NULL) { TRACE(("evaltree(NULL) called\n")); goto out1; } - TRACE(("pid %d, evaltree(%p: %d, %d) called\n", - getpid(), n, n->type, flags)); + TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags)); exception_handler = &jmploc; { int err = setjmp(jmploc.loc); if (err) { /* if it was a signal, check for trap handlers */ - if (exception == EXSIG) + if (exception == EXSIG) { + TRACE(("exception %d (EXSIG) in evaltree, err=%d\n", exception, err)); goto out; + } /* continue on the way out */ + TRACE(("exception %d in evaltree, propagating err=%d\n", exception, err)); exception_handler = savehandler; longjmp(exception_handler->loc, err); } @@ -8010,7 +8065,8 @@ if (exitstatus == 0) { n = n->nif.ifpart; goto evaln; - } else if (n->nif.elsepart) { + } + if (n->nif.elsepart) { n = n->nif.elsepart; goto evaln; } @@ -8036,6 +8092,9 @@ exexit: raise_exception(EXEXIT); } + + RESTORE_INT(int_level); + TRACE(("leaving evaltree (no interrupts)\n")); } #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3) @@ -8281,7 +8340,9 @@ if (prevfd >= 0) close(prevfd); prevfd = pip[0]; - close(pip[1]); + /* Don't want to trigger debugging */ + if (pip[1] != -1) + close(pip[1]); } if (n->npipe.pipe_backgnd == 0) { exitstatus = waitforjob(jp); @@ -8913,6 +8974,7 @@ if (forkshell(jp, cmd, FORK_FG) != 0) { exitstatus = waitforjob(jp); INT_ON; + TRACE(("forked child exited with %d\n", exitstatus)); break; } FORCE_INT_ON; @@ -13640,7 +13702,7 @@ exception_handler = &jmploc; #if DEBUG opentrace(); - trace_puts("Shell args: "); + TRACE(("Shell args: ")); trace_puts_args(argv); #endif rootpid = getpid(); @@ -13692,8 +13754,14 @@ } state3: state = 4; - if (minusc) + if (minusc) { + /* evalstring pushes parsefile stack. + * Ensure we don't falsely claim that 0 (stdin) + * is one of stacked source fds */ + if (!sflag) + g_parsefile->fd = -1; evalstring(minusc, 0); + } if (sflag || minusc == NULL) { #if ENABLE_FEATURE_EDITING_SAVEHISTORY @@ -13720,14 +13788,6 @@ /* NOTREACHED */ } -#if DEBUG -const char *applet_name = "debug stuff usage"; -int main(int argc, char **argv) -{ - return ash_main(argc, argv); -} -#endif - /*- * Copyright (c) 1989, 1991, 1993, 1994 diff -Naur busybox-1.13.3.orig/shell/hush.c busybox-1.13.3/shell/hush.c --- busybox-1.13.3.orig/shell/hush.c 2009-02-26 03:46:55.000000000 -0800 +++ busybox-1.13.3/shell/hush.c 2009-03-28 08:25:12.522843973 -0700 @@ -458,8 +458,11 @@ smallint fake_mode; /* these three support $?, $#, and $1 */ smalluint last_return_code; - char **global_argv; + /* is global_argv and global_argv[1..n] malloced? (note: not [0]) */ + smalluint global_args_malloced; + /* how many non-NULL argv's we have. NB: $# + 1 */ int global_argc; + char **global_argv; #if ENABLE_HUSH_LOOPS unsigned depth_break_continue; unsigned depth_of_loop; @@ -633,7 +636,7 @@ return dst; } -static char **add_strings_to_strings(char **strings, char **add) +static char **add_strings_to_strings(char **strings, char **add, int need_to_dup) { int i; unsigned count1; @@ -658,7 +661,7 @@ v[count1 + count2] = NULL; i = count2; while (--i >= 0) - v[count1 + i] = add[i]; + v[count1 + i] = (need_to_dup ? xstrdup(add[i]) : add[i]); return v; } @@ -667,7 +670,7 @@ char *v[2]; v[0] = add; v[1] = NULL; - return add_strings_to_strings(strings, v); + return add_strings_to_strings(strings, v, /*dup:*/ 0); } static void putenv_all(char **strings) @@ -1213,8 +1216,13 @@ * Otherwise, just finish current list[] and start new */ static int o_save_ptr(o_string *o, int n) { - if (o->o_glob) - return o_glob(o, n); /* o_save_ptr_helper is inside */ + if (o->o_glob) { /* if globbing is requested */ + /* If o->has_empty_slot, list[n] was already globbed + * (if it was requested back then when it was filled) + * so don't do that again! */ + if (!o->has_empty_slot) + return o_glob(o, n); /* o_save_ptr_helper is inside */ + } return o_save_ptr_helper(o, n); } @@ -4279,6 +4287,11 @@ switch (opt) { case 'c': G.global_argv = argv + optind; + if (!argv[optind]) { + /* -c 'script' (no params): prevent empty $0 */ + *--G.global_argv = argv[0]; + optind--; + } /* else -c 'script' PAR0 PAR1: $0 is PAR0 */ G.global_argc = argc - optind; opt = parse_and_run_string(optarg, 0 /* parse_flag */); goto final_return; @@ -4639,17 +4652,68 @@ return set_local_var(string, 0); } -/* built-in 'set [VAR=value]' handler */ +/* built-in 'set' handler + * SUSv3 says: + * set [-abCefmnuvx] [-h] [-o option] [argument...] + * set [+abCefmnuvx] [+h] [+o option] [argument...] + * set -- [argument...] + * set -o + * set +o + * Implementations shall support the options in both their hyphen and + * plus-sign forms. These options can also be specified as options to sh. + * Examples: + * Write out all variables and their values: set + * Set $1, $2, and $3 and set "$#" to 3: set c a b + * Turn on the -x and -v options: set -xv + * Unset all positional parameters: set -- + * Set $1 to the value of x, even if it begins with '-' or '+': set -- "$x" + * Set the positional parameters to the expansion of x, even if x expands + * with a leading '-' or '+': set -- $x + * + * So far, we only support "set -- [argument...]" by ignoring all options + * (also, "-o option" will be mishandled by taking "option" as parameter #1). + */ static int builtin_set(char **argv) { - char *temp = argv[1]; struct variable *e; + char **pp; + char *arg = *++argv; - if (temp == NULL) + if (arg == NULL) { for (e = G.top_var; e; e = e->next) puts(e->varstr); - else - set_local_var(xstrdup(temp), 0); + } else { + /* NB: G.global_argv[0] ($0) is never freed/changed */ + + if (G.global_args_malloced) { + pp = G.global_argv; + while (*++pp) + free(*pp); + G.global_argv[1] = NULL; + } else { + G.global_args_malloced = 1; + pp = xzalloc(sizeof(pp[0]) * 2); + pp[0] = G.global_argv[0]; /* retain $0 */ + G.global_argv = pp; + } + do { + if (arg[0] == '+') + continue; + if (arg[0] != '-') + break; + if (arg[1] == '-' && arg[2] == '\0') { + argv++; + break; + } + } while ((arg = *++argv) != NULL); + /* Now argv[0] is 1st argument */ + + /* This realloc's G.global_argv */ + G.global_argv = pp = add_strings_to_strings(G.global_argv, argv, /*dup:*/ 1); + G.global_argc = 1; + while (*++pp) + G.global_argc++; + } return EXIT_SUCCESS; } @@ -4661,9 +4725,14 @@ n = atoi(argv[1]); } if (n >= 0 && n < G.global_argc) { - G.global_argv[n] = G.global_argv[0]; + if (G.global_args_malloced) { + int m = 1; + while (m <= n) + free(G.global_argv[m++]); + } G.global_argc -= n; - G.global_argv += n; + memmove(&G.global_argv[1], &G.global_argv[n+1], + G.global_argc * sizeof(G.global_argv[0])); return EXIT_SUCCESS; } return EXIT_FAILURE; diff -Naur busybox-1.13.3.orig/shell/hush_test/hush-parsing/starquoted2.right busybox-1.13.3/shell/hush_test/hush-parsing/starquoted2.right --- busybox-1.13.3.orig/shell/hush_test/hush-parsing/starquoted2.right 2009-02-26 03:46:52.000000000 -0800 +++ busybox-1.13.3/shell/hush_test/hush-parsing/starquoted2.right 2009-03-28 08:25:12.526845928 -0700 @@ -1,2 +1,3 @@ Should be printed Should be printed +Empty: diff -Naur busybox-1.13.3.orig/shell/hush_test/hush-parsing/starquoted2.tests busybox-1.13.3/shell/hush_test/hush-parsing/starquoted2.tests --- busybox-1.13.3.orig/shell/hush_test/hush-parsing/starquoted2.tests 2009-02-26 03:46:52.000000000 -0800 +++ busybox-1.13.3/shell/hush_test/hush-parsing/starquoted2.tests 2009-03-28 08:25:12.526845928 -0700 @@ -12,3 +12,6 @@ for a in """$@"; do echo Should not be printed; done for a in """$@"''"$@"''; do echo Should not be printed; done for a in ""; do echo Should be printed; done + +# Bug 207: "$@" expands to nothing, and we erroneously glob "%s\\n" twice: +printf "Empty:%s\\n" "$@"