From fdd7b566ecdc174907f38d9389b28ba842d2b4bf Mon Sep 17 00:00:00 2001 From: Dan Fandrich Date: Fri, 18 Jun 2010 22:37:42 -0700 Subject: A few minor portability improvements Signed-off-by: Dan Fandrich Signed-off-by: Denys Vlasenko --- shell/hush.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'shell') diff --git a/shell/hush.c b/shell/hush.c index 4832e2c48..e64c923b4 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -1217,7 +1217,7 @@ static void hush_exit(int exitcode) static int check_and_run_traps(int sig) { - static const struct timespec zero_timespec = { 0, 0 }; + static const struct timespec zero_timespec; smalluint save_rcode; int last_sig = 0; -- cgit v1.2.3-55-g6feb From da75f4484469ca0122b80de69bf3b75a6be71efc Mon Sep 17 00:00:00 2001 From: Andreas Bühmann Date: Thu, 24 Jun 2010 04:32:37 +0200 Subject: ash: <> redir should not truncate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andreas Bühmann Signed-off-by: Denys Vlasenko --- shell/ash.c | 2 +- shell/ash_test/ash-redir/redir9.right | 2 ++ shell/ash_test/ash-redir/redir9.tests | 4 ++++ 3 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 shell/ash_test/ash-redir/redir9.right create mode 100644 shell/ash_test/ash-redir/redir9.tests (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index f581b5bdf..1f8f90a09 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -4938,7 +4938,7 @@ openredirect(union node *redir) break; case NFROMTO: fname = redir->nfile.expfname; - f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666); + f = open(fname, O_RDWR|O_CREAT, 0666); if (f < 0) goto ecreate; break; diff --git a/shell/ash_test/ash-redir/redir9.right b/shell/ash_test/ash-redir/redir9.right new file mode 100644 index 000000000..34c2512e4 --- /dev/null +++ b/shell/ash_test/ash-redir/redir9.right @@ -0,0 +1,2 @@ +Ok +Done:0 diff --git a/shell/ash_test/ash-redir/redir9.tests b/shell/ash_test/ash-redir/redir9.tests new file mode 100644 index 000000000..8befa611c --- /dev/null +++ b/shell/ash_test/ash-redir/redir9.tests @@ -0,0 +1,4 @@ +echo Ok >file.tmp +cat 0<>file.tmp +echo Done:$? +rm file.tmp -- cgit v1.2.3-55-g6feb From 1fcbff2fac490f5665fc1ed13ddad766a8879f3b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 26 Jun 2010 02:40:08 +0200 Subject: build system: do not rebuild ash and hush on any change to any .c file Signed-off-by: Denys Vlasenko --- applets/Kbuild.src | 2 +- applets/applet_tables.c | 24 ++++++++++++++++++++++-- libbb/appletlib.c | 2 +- shell/ash.c | 4 +--- shell/hush.c | 4 +--- 5 files changed, 26 insertions(+), 10 deletions(-) (limited to 'shell') diff --git a/applets/Kbuild.src b/applets/Kbuild.src index e3bac9681..31fee8d1e 100644 --- a/applets/Kbuild.src +++ b/applets/Kbuild.src @@ -38,7 +38,7 @@ include/usage_compressed.h: applets/usage $(srctree_slash)applets/usage_compress $(call cmd,gen_usage_compressed) quiet_cmd_gen_applet_tables = GEN include/applet_tables.h - cmd_gen_applet_tables = applets/applet_tables include/applet_tables.h + cmd_gen_applet_tables = applets/applet_tables include/applet_tables.h include/NUM_APPLETS.h include/applet_tables.h: applets/applet_tables $(call cmd,gen_applet_tables) diff --git a/applets/applet_tables.c b/applets/applet_tables.c index e48be4682..338dc20f9 100644 --- a/applets/applet_tables.c +++ b/applets/applet_tables.c @@ -79,7 +79,7 @@ int main(int argc, char **argv) } printf("\n"); - printf("#ifndef SKIP_definitions\n"); + //printf("#ifndef SKIP_definitions\n"); printf("const char applet_names[] ALIGN1 = \"\"\n"); for (i = 0; i < NUM_APPLETS; i++) { printf("\"%s\" \"\\0\"\n", applets[i].name); @@ -123,9 +123,29 @@ int main(int argc, char **argv) } printf("};\n"); #endif - printf("#endif /* SKIP_definitions */\n"); + //printf("#endif /* SKIP_definitions */\n"); printf("\n"); printf("#define MAX_APPLET_NAME_LEN %u\n", MAX_APPLET_NAME_LEN); + if (argv[2]) { + char line_old[80]; + char line_new[80]; + FILE *fp; + + line_old[0] = 0; + fp = fopen(argv[2], "r"); + if (fp) { + fgets(line_old, sizeof(line_old), fp); + fclose(fp); + } + sprintf(line_new, "#define NUM_APPLETS %u\n", NUM_APPLETS); + if (strcmp(line_old, line_new) != 0) { + fp = fopen(argv[2], "w"); + if (!fp) + return 1; + fputs(line_new, fp); + } + } + return 0; } diff --git a/libbb/appletlib.c b/libbb/appletlib.c index f3d530184..58f1a9490 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -61,7 +61,7 @@ static const char usage_messages[] ALIGN1 = UNPACKED_USAGE; #else # define usage_messages 0 -#endif /* SHOW_USAGE */ +#endif #if ENABLE_FEATURE_COMPRESS_USAGE diff --git a/shell/ash.c b/shell/ash.c index 1f8f90a09..cfd8154ef 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -50,9 +50,7 @@ # define CLEAR_RANDOM_T(rnd) ((void)0) #endif -#define SKIP_definitions 1 -#include "applet_tables.h" -#undef SKIP_definitions +#include "NUM_APPLETS.h" #if NUM_APPLETS == 1 /* STANDALONE does not make sense, and won't compile */ # undef CONFIG_FEATURE_SH_STANDALONE diff --git a/shell/hush.c b/shell/hush.c index e64c923b4..29ff3c442 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -128,9 +128,7 @@ # define USE_FOR_MMU(...) #endif -#define SKIP_definitions 1 -#include "applet_tables.h" -#undef SKIP_definitions +#include "NUM_APPLETS.h" #if NUM_APPLETS == 1 /* STANDALONE does not make sense, and won't compile */ # undef CONFIG_FEATURE_SH_STANDALONE -- cgit v1.2.3-55-g6feb From fd33e17a2bf4c09bb12ac09a645cfd0f0f914fec Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 26 Jun 2010 22:55:44 +0200 Subject: ash: fix obscure case of replacing + globbing + backslashes function old new delta subevalvar 1152 1178 +26 readtoken1 3267 3275 +8 redirect 1284 1286 +2 expandarg 957 958 +1 expdir 4 - -4 evalcommand 1219 1209 -10 expmeta 481 469 -12 ------------------------------------------------------------------------------ (add/remove: 0/1 grow/shrink: 4/2 up/down: 37/-26) Total: 11 bytes Signed-off-by: Denys Vlasenko --- shell/ash.c | 42 +++++++++++----------- .../ash-quoting/dollar_repl_slash_bash1.right | 10 ++++++ .../ash-quoting/dollar_repl_slash_bash1.tests | 21 +++++++++++ 3 files changed, 52 insertions(+), 21 deletions(-) create mode 100644 shell/ash_test/ash-quoting/dollar_repl_slash_bash1.right create mode 100755 shell/ash_test/ash-quoting/dollar_repl_slash_bash1.tests (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index cfd8154ef..0337a5535 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -6184,8 +6184,7 @@ subevalvar(char *p, char *str, int strloc, int subtype, char *startp; char *loc; char *rmesc, *rmescend; - IF_ASH_BASH_COMPAT(char *repl = NULL;) - IF_ASH_BASH_COMPAT(char null = '\0';) + IF_ASH_BASH_COMPAT(const char *repl = NULL;) IF_ASH_BASH_COMPAT(int pos, len, orig_len;) int saveherefd = herefd; int amount, workloc, resetloc; @@ -6306,7 +6305,7 @@ subevalvar(char *p, char *str, int strloc, int subtype, if (!repl) { repl = parse_sub_pattern(str, varflags & VSQUOTE); if (!repl) - repl = &null; + repl = nullstr; } /* If there's no pattern to match, return the expansion unmolested */ @@ -6357,8 +6356,12 @@ subevalvar(char *p, char *str, int strloc, int subtype, idx = loc; } - for (loc = repl; *loc; loc++) { + for (loc = (char*)repl; *loc; loc++) { char *restart_detect = stackblock(); + if (quotes && *loc == '\\') { + STPUTC(CTLESC, expdest); + len++; + } STPUTC(*loc, expdest); if (stackblock() != restart_detect) goto restart; @@ -6368,6 +6371,10 @@ subevalvar(char *p, char *str, int strloc, int subtype, if (subtype == VSREPLACE) { while (*idx) { char *restart_detect = stackblock(); + if (quotes && *idx == '\\') { + STPUTC(CTLESC, expdest); + len++; + } STPUTC(*idx, expdest); if (stackblock() != restart_detect) goto restart; @@ -6381,11 +6388,10 @@ subevalvar(char *p, char *str, int strloc, int subtype, /* We've put the replaced text into a buffer at workloc, now * move it to the right place and adjust the stack. */ - startp = stackblock() + startloc; STPUTC('\0', expdest); - memmove(startp, stackblock() + workloc, len); - startp[len++] = '\0'; - amount = expdest - ((char *)stackblock() + startloc + len - 1); + startp = (char *)stackblock() + startloc; + memmove(startp, (char *)stackblock() + workloc, len + 1); + amount = expdest - (startp + len); STADJUST(-amount, expdest); return startp; } @@ -6685,7 +6691,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list) */ STPUTC('\0', expdest); patloc = expdest - (char *)stackblock(); - if (0 == subevalvar(p, /* str: */ NULL, patloc, subtype, + if (NULL == subevalvar(p, /* str: */ NULL, patloc, subtype, startloc, varflags, //TODO: | EXP_REDIR too? All other such places do it too /* quotes: */ flags & (EXP_FULL | EXP_CASE), @@ -6848,13 +6854,11 @@ addfname(const char *name) exparg.lastp = &sp->next; } -static char *expdir; - /* * Do metacharacter (i.e. *, ?, [...]) expansion. */ static void -expmeta(char *enddir, char *name) +expmeta(char *expdir, char *enddir, char *name) { char *p; const char *cp; @@ -6953,7 +6957,7 @@ expmeta(char *enddir, char *name) for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';) continue; p[-1] = '/'; - expmeta(p, endname); + expmeta(expdir, p, endname); } } } @@ -7035,6 +7039,7 @@ expandmeta(struct strlist *str /*, int flag*/) /* TODO - EXP_REDIR */ while (str) { + char *expdir; struct strlist **savelastp; struct strlist *sp; char *p; @@ -7051,8 +7056,7 @@ expandmeta(struct strlist *str /*, int flag*/) int i = strlen(str->text); expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ } - - expmeta(expdir, p); + expmeta(expdir, expdir, p); free(expdir); if (p != str->text) free(p); @@ -9101,19 +9105,15 @@ evalcommand(union node *cmd, int flags) /* Print the command if xflag is set. */ if (xflag) { int n; - const char *p = " %s"; + const char *p = " %s" + 1; - p++; fdprintf(preverrout_fd, p, expandstr(ps4val())); - sp = varlist.list; for (n = 0; n < 2; n++) { while (sp) { fdprintf(preverrout_fd, p, sp->text); sp = sp->next; - if (*p == '%') { - p--; - } + p = " %s"; } sp = arglist.list; } diff --git a/shell/ash_test/ash-quoting/dollar_repl_slash_bash1.right b/shell/ash_test/ash-quoting/dollar_repl_slash_bash1.right new file mode 100644 index 000000000..b212c246c --- /dev/null +++ b/shell/ash_test/ash-quoting/dollar_repl_slash_bash1.right @@ -0,0 +1,10 @@ +192\.168\.0\.1 +192\.168\.0\.1[ +192\.168\.0\.1[ +192\\.168\\.0\\.1[ +192\.168\.0\.1[ +192\.168\.0\.1 +192\.168\.0\.1[ +192\.168\.0\.1[ +192\\.168\\.0\\.1[ +192\.168\.0\.1[ diff --git a/shell/ash_test/ash-quoting/dollar_repl_slash_bash1.tests b/shell/ash_test/ash-quoting/dollar_repl_slash_bash1.tests new file mode 100755 index 000000000..3fa2f186d --- /dev/null +++ b/shell/ash_test/ash-quoting/dollar_repl_slash_bash1.tests @@ -0,0 +1,21 @@ +# The bug here was triggered by: +# * performin pathname expansion because we see [ +# * replace operator did not escape \ in replace string + +IP=192.168.0.1 + +rm -f '192.168.0.1[' +echo "${IP//./\\.}" +echo "${IP//./\\.}"'[' # bug was here +echo "${IP//./\\.}[" # bug was here +echo "${IP//./\\\\.}[" # bug was here +echo "192\.168\.0\.1[" + +echo >'192.168.0.1[' +echo "${IP//./\\.}" +echo "${IP//./\\.}"'[' # bug was here +echo "${IP//./\\.}[" # bug was here +echo "${IP//./\\\\.}[" # bug was here +echo "192\.168\.0\.1[" + +rm -f '192.168.0.1[' -- cgit v1.2.3-55-g6feb From 21e8e8da6483c80a6054b06e48341968a7dccdd5 Mon Sep 17 00:00:00 2001 From: Pascal Bellard Date: Sun, 4 Jul 2010 00:57:03 +0200 Subject: libbb: introduce and use BB_EXECVP_or_die() function old new delta BB_EXECVP_or_die - 47 +47 time_main 1042 1043 +1 chrt_main 371 364 -7 ionice_main 292 282 -10 setsid_main 69 56 -13 nohup_main 236 223 -13 cttyhack_main 266 253 -13 chroot_main 94 81 -13 chpst_main 746 733 -13 timeout_main 297 279 -18 taskset_main 541 522 -19 vfork_child 67 45 -22 parse 975 953 -22 lpd_main 770 748 -22 launch_helper 192 170 -22 tcpudpsvd_main 1810 1782 -28 nice_main 190 156 -34 env_main 242 206 -36 run_command 221 174 -47 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 1/17 up/down: 48/-352) Total: -304 bytes Signed-off-by: Pascal Bellard Signed-off-by: Denys Vlasenko --- console-tools/openvt.c | 3 +-- coreutils/chroot.c | 3 +-- coreutils/env.c | 5 +---- coreutils/nice.c | 5 +---- coreutils/nohup.c | 3 +-- include/libbb.h | 1 + libbb/execable.c | 8 ++++++++ libbb/vfork_daemon_rexec.c | 34 ---------------------------------- libbb/xfuncs.c | 34 ++++++++++++++++++++++++++++++++++ mailutils/mail.c | 3 +-- mailutils/mime.c | 3 +-- miscutils/chrt.c | 3 +-- miscutils/ionice.c | 3 +-- miscutils/setsid.c | 3 +-- miscutils/taskset.c | 3 +-- miscutils/time.c | 15 ++++++--------- miscutils/timeout.c | 3 +-- networking/ifupdown.c | 3 +-- networking/tcpudp.c | 4 ++-- printutils/lpd.c | 3 +-- runit/chpst.c | 3 +-- shell/cttyhack.c | 3 +-- 22 files changed, 67 insertions(+), 81 deletions(-) (limited to 'shell') diff --git a/console-tools/openvt.c b/console-tools/openvt.c index 6f58916e7..e3ea71bc5 100644 --- a/console-tools/openvt.c +++ b/console-tools/openvt.c @@ -97,8 +97,7 @@ static NOINLINE void vfork_child(char **argv) //bb_error_msg("our pgrp %d", getpgrp()); //bb_error_msg("VT's sid %d", tcgetsid(0)); //bb_error_msg("VT's pgrp %d", tcgetpgrp(0)); - BB_EXECVP(argv[0], argv); - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + BB_EXECVP_or_die(argv); } } diff --git a/coreutils/chroot.c b/coreutils/chroot.c index bc0b1f82c..046c2fabf 100644 --- a/coreutils/chroot.c +++ b/coreutils/chroot.c @@ -30,6 +30,5 @@ int chroot_main(int argc UNUSED_PARAM, char **argv) argv[1] = (char *) "-i"; } - BB_EXECVP(argv[0], argv); - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + BB_EXECVP_or_die(argv); } diff --git a/coreutils/env.c b/coreutils/env.c index c6ba04d35..d4eab191b 100644 --- a/coreutils/env.c +++ b/coreutils/env.c @@ -77,10 +77,7 @@ int env_main(int argc UNUSED_PARAM, char **argv) } if (argv[0]) { - BB_EXECVP(argv[0], argv); - /* SUSv3-mandated exit codes. */ - xfunc_error_retval = (errno == ENOENT) ? 127 : 126; - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + BB_EXECVP_or_die(argv); } if (environ) { /* clearenv() may set environ == NULL! */ diff --git a/coreutils/nice.c b/coreutils/nice.c index 0f70f1079..ff3eb1140 100644 --- a/coreutils/nice.c +++ b/coreutils/nice.c @@ -47,8 +47,5 @@ int nice_main(int argc, char **argv) } } - BB_EXECVP(argv[0], argv); - /* The exec failed... */ - xfunc_error_retval = (errno == ENOENT) ? 127 : 126; /* SUSv3 */ - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + BB_EXECVP_or_die(argv); } diff --git a/coreutils/nohup.c b/coreutils/nohup.c index 1027ada1c..3dc531409 100644 --- a/coreutils/nohup.c +++ b/coreutils/nohup.c @@ -76,6 +76,5 @@ int nohup_main(int argc UNUSED_PARAM, char **argv) signal(SIGHUP, SIG_IGN); argv++; - BB_EXECVP(argv[0], argv); - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + BB_EXECVP_or_die(argv); } diff --git a/include/libbb.h b/include/libbb.h index e26001705..4b6699f2f 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -839,6 +839,7 @@ int bb_execvp(const char *file, char *const argv[]) FAST_FUNC; #define BB_EXECVP(prog,cmd) execvp(prog,cmd) #define BB_EXECLP(prog,cmd,...) execlp(prog,cmd, __VA_ARGS__) #endif +int BB_EXECVP_or_die(char **argv) NORETURN FAST_FUNC; /* NOMMU friendy fork+exec: */ pid_t spawn(char **argv) FAST_FUNC; diff --git a/libbb/execable.c b/libbb/execable.c index 5c7ac16a2..82241cd81 100644 --- a/libbb/execable.c +++ b/libbb/execable.c @@ -76,3 +76,11 @@ int FAST_FUNC bb_execvp(const char *file, char *const argv[]) argv); } #endif + +int FAST_FUNC BB_EXECVP_or_die(char **argv) +{ + BB_EXECVP(argv[0], argv); + /* SUSv3-mandated exit codes */ + xfunc_error_retval = (errno == ENOENT) ? 127 : 126; + bb_perror_msg_and_die("can't execute '%s'", argv[0]); +} diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index 082f0f63e..8102ea2dc 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -67,40 +67,6 @@ pid_t FAST_FUNC xspawn(char **argv) return pid; } -pid_t FAST_FUNC safe_waitpid(pid_t pid, int *wstat, int options) -{ - pid_t r; - - do - r = waitpid(pid, wstat, options); - while ((r == -1) && (errno == EINTR)); - return r; -} - -pid_t FAST_FUNC wait_any_nohang(int *wstat) -{ - return safe_waitpid(-1, wstat, WNOHANG); -} - -// Wait for the specified child PID to exit, returning child's error return. -int FAST_FUNC wait4pid(pid_t pid) -{ - int status; - - if (pid <= 0) { - /*errno = ECHILD; -- wrong. */ - /* we expect errno to be already set from failed [v]fork/exec */ - return -1; - } - if (safe_waitpid(pid, &status, 0) == -1) - return -1; - if (WIFEXITED(status)) - return WEXITSTATUS(status); - if (WIFSIGNALED(status)) - return WTERMSIG(status) + 0x180; - return 0; -} - #if ENABLE_FEATURE_PREFER_APPLETS void FAST_FUNC save_nofork_data(struct nofork_save_area *save) { diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c index 65437211d..275dd4b62 100644 --- a/libbb/xfuncs.c +++ b/libbb/xfuncs.c @@ -268,3 +268,37 @@ int FAST_FUNC tcsetattr_stdin_TCSANOW(const struct termios *tp) { return tcsetattr(STDIN_FILENO, TCSANOW, tp); } + +pid_t FAST_FUNC safe_waitpid(pid_t pid, int *wstat, int options) +{ + pid_t r; + + do + r = waitpid(pid, wstat, options); + while ((r == -1) && (errno == EINTR)); + return r; +} + +pid_t FAST_FUNC wait_any_nohang(int *wstat) +{ + return safe_waitpid(-1, wstat, WNOHANG); +} + +// Wait for the specified child PID to exit, returning child's error return. +int FAST_FUNC wait4pid(pid_t pid) +{ + int status; + + if (pid <= 0) { + /*errno = ECHILD; -- wrong. */ + /* we expect errno to be already set from failed [v]fork/exec */ + return -1; + } + if (safe_waitpid(pid, &status, 0) == -1) + return -1; + if (WIFEXITED(status)) + return WEXITSTATUS(status); + if (WIFSIGNALED(status)) + return WTERMSIG(status) + 0x180; + return 0; +} diff --git a/mailutils/mail.c b/mailutils/mail.c index 49e72c32b..5eb99e13d 100644 --- a/mailutils/mail.c +++ b/mailutils/mail.c @@ -67,8 +67,7 @@ void FAST_FUNC launch_helper(const char **argv) if (!G.helper_pid) { // child: try to execute connection helper // NB: SIGCHLD & SIGALRM revert to SIG_DFL on exec - BB_EXECVP(argv[0], (char **)argv); - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + BB_EXECVP_or_die((char**)argv); } // parent diff --git a/mailutils/mime.c b/mailutils/mime.c index 654b8731c..5eb8ef6f2 100644 --- a/mailutils/mime.c +++ b/mailutils/mime.c @@ -288,8 +288,7 @@ static int parse(const char *boundary, char **argv) xsetenv("CHARSET", charset); xsetenv("ENCODING", encoding); xsetenv("FILENAME", filename); - BB_EXECVP(argv[0], argv); - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + BB_EXECVP_or_die(argv); } // parent dumps to fd[1] close(fd[0]); diff --git a/miscutils/chrt.c b/miscutils/chrt.c index 3d0da58ca..d5f87c4d7 100644 --- a/miscutils/chrt.c +++ b/miscutils/chrt.c @@ -120,6 +120,5 @@ int chrt_main(int argc UNUSED_PARAM, char **argv) if (!argv[0]) /* "-p [...]" */ goto print_rt_info; - BB_EXECVP(argv[0], argv); - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + BB_EXECVP_or_die(argv); } diff --git a/miscutils/ionice.c b/miscutils/ionice.c index 8393cd8b2..52e51b908 100644 --- a/miscutils/ionice.c +++ b/miscutils/ionice.c @@ -90,8 +90,7 @@ int ionice_main(int argc UNUSED_PARAM, char **argv) if (ioprio_set(IOPRIO_WHO_PROCESS, pid, pri) == -1) bb_perror_msg_and_die("ioprio_%cet", 's'); if (argv[0]) { - BB_EXECVP(argv[0], argv); - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + BB_EXECVP_or_die(argv); } } diff --git a/miscutils/setsid.c b/miscutils/setsid.c index 60ee062e3..c573fae34 100644 --- a/miscutils/setsid.c +++ b/miscutils/setsid.c @@ -45,6 +45,5 @@ int setsid_main(int argc UNUSED_PARAM, char **argv) } argv++; - BB_EXECVP(argv[0], argv); - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + BB_EXECVP_or_die(argv); } diff --git a/miscutils/taskset.c b/miscutils/taskset.c index 2891003df..08198d5d4 100644 --- a/miscutils/taskset.c +++ b/miscutils/taskset.c @@ -132,6 +132,5 @@ int taskset_main(int argc UNUSED_PARAM, char **argv) if (!argv[0]) /* "-p [...ignored...]" */ goto print_aff; /* print new affinity and exit */ - BB_EXECVP(argv[0], argv); - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + BB_EXECVP_or_die(argv); } diff --git a/miscutils/time.c b/miscutils/time.c index f5d1e15fb..5cfbcef8e 100644 --- a/miscutils/time.c +++ b/miscutils/time.c @@ -367,20 +367,17 @@ static void summarize(const char *fmt, char **command, resource_t *resp) Put the statistics in *RESP. */ static void run_command(char *const *cmd, resource_t *resp) { - pid_t pid; /* Pid of child. */ + pid_t pid; void (*interrupt_signal)(int); void (*quit_signal)(int); resp->elapsed_ms = monotonic_ms(); - pid = vfork(); /* Run CMD as child process. */ + pid = vfork(); if (pid < 0) - bb_perror_msg_and_die("fork"); - if (pid == 0) { /* If child. */ - /* Don't cast execvp arguments; that causes errors on some systems, - versus merely warnings if the cast is left off. */ - BB_EXECVP(cmd[0], cmd); - xfunc_error_retval = (errno == ENOENT ? 127 : 126); - bb_perror_msg_and_die("can't execute '%s'", cmd[0]); + bb_perror_msg_and_die("vfork"); + if (pid == 0) { + /* Child */ + BB_EXECVP_or_die((char**)cmd); } /* Have signals kill the child but not self (if possible). */ diff --git a/miscutils/timeout.c b/miscutils/timeout.c index 273d26953..f6e655acc 100644 --- a/miscutils/timeout.c +++ b/miscutils/timeout.c @@ -110,6 +110,5 @@ int timeout_main(int argc UNUSED_PARAM, char **argv) argv[0] = sv1; argv[1] = sv2; #endif - BB_EXECVP(argv[0], argv); - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + BB_EXECVP_or_die(argv); } diff --git a/networking/ifupdown.c b/networking/ifupdown.c index 714d2a107..1bab2c5cb 100644 --- a/networking/ifupdown.c +++ b/networking/ifupdown.c @@ -1052,8 +1052,7 @@ static int popen2(FILE **in, FILE **out, char *command, char *param) close(outfd.rd); xmove_fd(infd.rd, 0); xmove_fd(outfd.wr, 1); - BB_EXECVP(command, argv); - bb_perror_msg_and_die("can't execute '%s'", command); + BB_EXECVP_or_die(argv); } /* parent */ close(infd.rd); diff --git a/networking/tcpudp.c b/networking/tcpudp.c index 4e4756738..53e622b56 100644 --- a/networking/tcpudp.c +++ b/networking/tcpudp.c @@ -501,10 +501,10 @@ int tcpudpsvd_main(int argc UNUSED_PARAM, char **argv) #ifdef SSLSVD strcpy(id, utoa(pid)); ssl_io(0, argv); + bb_perror_msg_and_die("can't execute '%s'", argv[0]); #else - BB_EXECVP(argv[0], argv); + BB_EXECVP_or_die(argv); #endif - bb_perror_msg_and_die("can't execute '%s'", argv[0]); } /* diff --git a/printutils/lpd.c b/printutils/lpd.c index 15f1ba20b..d91491f1b 100644 --- a/printutils/lpd.c +++ b/printutils/lpd.c @@ -181,8 +181,7 @@ int lpd_main(int argc UNUSED_PARAM, char *argv[]) // this call reopens stdio fds to "/dev/null" // (no daemonization is done) bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO | DAEMON_ONLY_SANITIZE, NULL); - BB_EXECVP(argv[0], argv); - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + BB_EXECVP_or_die(argv); } // validate input. diff --git a/runit/chpst.c b/runit/chpst.c index 028a28d6c..ad0811294 100644 --- a/runit/chpst.c +++ b/runit/chpst.c @@ -382,6 +382,5 @@ int chpst_main(int argc UNUSED_PARAM, char **argv) if (opt & OPT_2) close(STDERR_FILENO); - BB_EXECVP(argv[0], argv); - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + BB_EXECVP_or_die(argv); } diff --git a/shell/cttyhack.c b/shell/cttyhack.c index bde2acdc9..67736ad62 100644 --- a/shell/cttyhack.c +++ b/shell/cttyhack.c @@ -81,6 +81,5 @@ int cttyhack_main(int argc UNUSED_PARAM, char **argv) } } - BB_EXECVP(argv[0], argv); - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + BB_EXECVP_or_die(argv); } -- cgit v1.2.3-55-g6feb From 926031b7640bf5aad2ffcd54b096911743a47d97 Mon Sep 17 00:00:00 2001 From: Pascal Bellard Date: Sun, 4 Jul 2010 15:32:38 +0200 Subject: *: introduce and use xfork() and xvfork() function old new delta launch_helper 170 169 -1 setup_heredoc 312 302 -10 handle_dir_common 367 354 -13 expand_vars_to_list 2456 2443 -13 open_transformer 89 74 -15 data_extract_to_command 439 423 -16 do_ipaddr 1406 1389 -17 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/7 up/down: 0/-85) Total: -85 bytes Signed-off-by: Pascal Bellard Signed-off-by: Denys Vlasenko --- archival/libunarchive/data_extract_to_command.c | 7 ++----- archival/libunarchive/open_transformer.c | 14 ++------------ archival/tar.c | 4 +--- debianutils/start_stop_daemon.c | 4 +--- e2fsprogs/old_e2fsprogs/fsck.c | 2 +- include/libbb.h | 21 +++++++++++++++++---- init/bootchartd.c | 4 +--- libbb/vfork_daemon_rexec.c | 16 +--------------- libbb/xfuncs_printf.c | 11 +++++++++++ mailutils/mail.c | 4 +--- miscutils/conspy.c | 5 +---- miscutils/crontab.c | 8 ++------ miscutils/time.c | 4 +--- miscutils/timeout.c | 4 +--- networking/ftpd.c | 5 +---- networking/ifupdown.c | 8 +++----- networking/inetd.c | 2 +- networking/nc.c | 6 ++---- scripts/basic/docproc.c | 2 +- shell/hush.c | 15 ++++----------- util-linux/script.c | 5 +---- 21 files changed, 56 insertions(+), 95 deletions(-) (limited to 'shell') diff --git a/archival/libunarchive/data_extract_to_command.c b/archival/libunarchive/data_extract_to_command.c index eb09439bc..95f5bc864 100644 --- a/archival/libunarchive/data_extract_to_command.c +++ b/archival/libunarchive/data_extract_to_command.c @@ -82,11 +82,8 @@ void FAST_FUNC data_extract_to_command(archive_handle_t *archive_handle) memset(tar_env, 0, sizeof(tar_env)); xpipe(p); - pid = BB_MMU ? fork() : vfork(); - switch (pid) { - case -1: - bb_perror_msg_and_die(BB_MMU ? "fork" : "vfork"); - case 0: + pid = BB_MMU ? xfork() : xvfork(); + if (pid == 0) { /* Child */ /* str2env(tar_env, TAR_FILETYPE, "f"); - parent should do it once */ oct2env(tar_env, TAR_MODE, file_header->mode); diff --git a/archival/libunarchive/open_transformer.c b/archival/libunarchive/open_transformer.c index 47c13e6f4..cba049f1f 100644 --- a/archival/libunarchive/open_transformer.c +++ b/archival/libunarchive/open_transformer.c @@ -19,19 +19,9 @@ void FAST_FUNC open_transformer(int fd, int pid; xpiped_pair(fd_pipe); - -#if BB_MMU - pid = fork(); - if (pid == -1) - bb_perror_msg_and_die("vfork" + 1); -#else - pid = vfork(); - if (pid == -1) - bb_perror_msg_and_die("vfork"); -#endif - + pid = BB_MMU ? xfork() : xvfork(); if (pid == 0) { - /* child process */ + /* Child */ close(fd_pipe.rd); /* we don't want to read from the parent */ // FIXME: error check? #if BB_MMU diff --git a/archival/tar.c b/archival/tar.c index f49fb129e..9dd74536e 100644 --- a/archival/tar.c +++ b/archival/tar.c @@ -514,9 +514,7 @@ static void NOINLINE vfork_compressor(int tar_fd, int gzip) (void) &zip_exec; # endif - gzipPid = vfork(); - if (gzipPid < 0) - bb_perror_msg_and_die("vfork"); + gzipPid = xvfork(); if (gzipPid == 0) { /* child */ diff --git a/debianutils/start_stop_daemon.c b/debianutils/start_stop_daemon.c index 3ded758bf..665f38fbd 100644 --- a/debianutils/start_stop_daemon.c +++ b/debianutils/start_stop_daemon.c @@ -409,9 +409,7 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) /* DAEMON_DEVNULL_STDIO is superfluous - * it's always done by bb_daemonize() */ #else - pid_t pid = vfork(); - if (pid < 0) /* error */ - bb_perror_msg_and_die("vfork"); + pid_t pid = xvfork(); if (pid != 0) { /* parent */ /* why _exit? the child may have changed the stack, diff --git a/e2fsprogs/old_e2fsprogs/fsck.c b/e2fsprogs/old_e2fsprogs/fsck.c index dc029b65a..2a66d728a 100644 --- a/e2fsprogs/old_e2fsprogs/fsck.c +++ b/e2fsprogs/old_e2fsprogs/fsck.c @@ -612,7 +612,7 @@ static int execute(const char *type, const char *device, const char *mntpt, if (noexecute) pid = -1; else if ((pid = fork()) < 0) { - perror("fork"); + perror("vfork"+1); return errno; } else if (pid == 0) { if (!interactive) diff --git a/include/libbb.h b/include/libbb.h index 4b6699f2f..e2a8322b8 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -841,6 +841,19 @@ int bb_execvp(const char *file, char *const argv[]) FAST_FUNC; #endif int BB_EXECVP_or_die(char **argv) NORETURN FAST_FUNC; +/* xvfork() can't be a _function_, return after vfork mangles stack + * in the parent. It must be a macro. */ +#define xvfork() \ +({ \ + pid_t bb__xvfork_pid = vfork(); \ + if (bb__xvfork_pid < 0) \ + bb_perror_msg_and_die("vfork"); \ + bb__xvfork_pid; \ +}) +#if BB_MMU +pid_t xfork(void) FAST_FUNC; +#endif + /* NOMMU friendy fork+exec: */ pid_t spawn(char **argv) FAST_FUNC; pid_t xspawn(char **argv) FAST_FUNC; @@ -886,7 +899,7 @@ int run_nofork_applet_prime(struct nofork_save_area *old, int applet_no, char ** * Both of the above will redirect fd 0,1,2 to /dev/null and drop ctty * (will do setsid()). * - * fork_or_rexec(argv) = bare-bones "fork" on MMU, + * fork_or_rexec(argv) = bare-bones fork on MMU, * "vfork + re-exec ourself" on NOMMU. No fd redirection, no setsid(). * On MMU ignores argv. * @@ -902,19 +915,19 @@ enum { DAEMON_ONLY_SANITIZE = 8, /* internal use */ }; #if BB_MMU - pid_t fork_or_rexec(void) FAST_FUNC; enum { re_execed = 0 }; -# define fork_or_rexec(argv) fork_or_rexec() +# define fork_or_rexec(argv) xfork() # define bb_daemonize_or_rexec(flags, argv) bb_daemonize_or_rexec(flags) # define bb_daemonize(flags) bb_daemonize_or_rexec(flags, bogus) #else + extern bool re_execed; void re_exec(char **argv) NORETURN FAST_FUNC; pid_t fork_or_rexec(char **argv) FAST_FUNC; - extern bool re_execed; int BUG_fork_is_unavailable_on_nommu(void) FAST_FUNC; int BUG_daemon_is_unavailable_on_nommu(void) FAST_FUNC; void BUG_bb_daemonize_is_unavailable_on_nommu(void) FAST_FUNC; # define fork() BUG_fork_is_unavailable_on_nommu() +# define xfork() BUG_fork_is_unavailable_on_nommu() # define daemon(a,b) BUG_daemon_is_unavailable_on_nommu() # define bb_daemonize(a) BUG_bb_daemonize_is_unavailable_on_nommu() #endif diff --git a/init/bootchartd.c b/init/bootchartd.c index 42b98c827..b3e08af92 100644 --- a/init/bootchartd.c +++ b/init/bootchartd.c @@ -427,9 +427,7 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv) } if (cmd == CMD_START && argv[2]) { /* "start PROG ARGS" */ - pid_t pid = vfork(); - if (pid < 0) - bb_perror_msg_and_die("vfork"); + pid_t pid = xvfork(); if (pid == 0) { /* child */ argv += 2; execvp(argv[0], argv); diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index 8102ea2dc..5c2c529c9 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -224,26 +224,12 @@ pid_t FAST_FUNC fork_or_rexec(char **argv) /* Maybe we are already re-execed and come here again? */ if (re_execed) return 0; - pid = vfork(); - if (pid < 0) /* wtf? */ - bb_perror_msg_and_die("vfork"); + pid = xvfork(); if (pid) /* parent */ return pid; /* child - re-exec ourself */ re_exec(argv); } -#else -/* Dance around (void)...*/ -#undef fork_or_rexec -pid_t FAST_FUNC fork_or_rexec(void) -{ - pid_t pid; - pid = fork(); - if (pid < 0) /* wtf? */ - bb_perror_msg_and_die("fork"); - return pid; -} -#define fork_or_rexec(argv) fork_or_rexec() #endif /* Due to a #define in libbb.h on MMU systems we actually have 1 argument - diff --git a/libbb/xfuncs_printf.c b/libbb/xfuncs_printf.c index f021493b1..7069a7c8e 100644 --- a/libbb/xfuncs_printf.c +++ b/libbb/xfuncs_printf.c @@ -589,3 +589,14 @@ void FAST_FUNC generate_uuid(uint8_t *buf) /* variant = 10x */ buf[4 + 2 + 2] = (buf[4 + 2 + 2] & 0x3f) | 0x80; } + +#if BB_MMU +pid_t FAST_FUNC xfork(void) +{ + pid_t pid; + pid = fork(); + if (pid < 0) /* wtf? */ + bb_perror_msg_and_die("vfork"+1); + return pid; +} +#endif diff --git a/mailutils/mail.c b/mailutils/mail.c index 5eb99e13d..bcd358302 100644 --- a/mailutils/mail.c +++ b/mailutils/mail.c @@ -54,9 +54,7 @@ void FAST_FUNC launch_helper(const char **argv) + (1 << SIGALRM) , signal_handler); - G.helper_pid = vfork(); - if (G.helper_pid < 0) - bb_perror_msg_and_die("vfork"); + G.helper_pid = xvfork(); i = (!G.helper_pid) * 2; // for parent:0, for child:2 close(pipes[i + 1]); // 1 or 3 - closing one write end diff --git a/miscutils/conspy.c b/miscutils/conspy.c index 3f341ce18..509a0f271 100644 --- a/miscutils/conspy.c +++ b/miscutils/conspy.c @@ -309,10 +309,7 @@ static void create_cdev_if_doesnt_exist(const char* name, dev_t dev) static NOINLINE void start_shell_in_child(const char* tty_name) { - int pid = vfork(); - if (pid < 0) { - bb_perror_msg_and_die("vfork"); - } + int pid = xvfork(); if (pid == 0) { struct termios termchild; char *shell = getenv("SHELL"); diff --git a/miscutils/crontab.c b/miscutils/crontab.c index 5557bc491..b8a5abc64 100644 --- a/miscutils/crontab.c +++ b/miscutils/crontab.c @@ -20,10 +20,8 @@ static void edit_file(const struct passwd *pas, const char *file) { const char *ptr; - int pid = vfork(); + int pid = xvfork(); - if (pid < 0) /* failure */ - bb_perror_msg_and_die("vfork"); if (pid) { /* parent */ wait4pid(pid); return; @@ -51,9 +49,7 @@ static int open_as_user(const struct passwd *pas, const char *file) pid_t pid; char c; - pid = vfork(); - if (pid < 0) /* ERROR */ - bb_perror_msg_and_die("vfork"); + pid = xvfork(); if (pid) { /* PARENT */ if (wait4pid(pid) == 0) { /* exitcode 0: child says it can read */ diff --git a/miscutils/time.c b/miscutils/time.c index 5cfbcef8e..9facc3657 100644 --- a/miscutils/time.c +++ b/miscutils/time.c @@ -372,9 +372,7 @@ static void run_command(char *const *cmd, resource_t *resp) void (*quit_signal)(int); resp->elapsed_ms = monotonic_ms(); - pid = vfork(); - if (pid < 0) - bb_perror_msg_and_die("vfork"); + pid = xvfork(); if (pid == 0) { /* Child */ BB_EXECVP_or_die((char**)cmd); diff --git a/miscutils/timeout.c b/miscutils/timeout.c index f6e655acc..48b8d8fc0 100644 --- a/miscutils/timeout.c +++ b/miscutils/timeout.c @@ -71,9 +71,7 @@ int timeout_main(int argc UNUSED_PARAM, char **argv) sv1 = argv[optind]; sv2 = argv[optind + 1]; #endif - pid = vfork(); - if (pid < 0) - bb_perror_msg_and_die("vfork"); + pid = xvfork(); if (pid == 0) { /* Child: spawn grandchild and exit */ parent = getppid(); diff --git a/networking/ftpd.c b/networking/ftpd.c index c63b9319e..e8cae0a36 100644 --- a/networking/ftpd.c +++ b/networking/ftpd.c @@ -632,10 +632,7 @@ popen_ls(const char *opt) xpiped_pair(outfd); /*fflush_all(); - so far we dont use stdio on output */ - pid = BB_MMU ? fork() : vfork(); - if (pid < 0) - bb_perror_msg_and_die(BB_MMU ? "fork" : "vfork"); - + pid = BB_MMU ? xfork() : xvfork(); if (pid == 0) { /* child */ #if !BB_MMU diff --git a/networking/ifupdown.c b/networking/ifupdown.c index 1bab2c5cb..69c56e879 100644 --- a/networking/ifupdown.c +++ b/networking/ifupdown.c @@ -1041,12 +1041,10 @@ static int popen2(FILE **in, FILE **out, char *command, char *param) xpiped_pair(outfd); fflush_all(); - pid = vfork(); + pid = xvfork(); - switch (pid) { - case -1: /* failure */ - bb_perror_msg_and_die("vfork"); - case 0: /* child */ + if (pid == 0) { + /* Child */ /* NB: close _first_, then move fds! */ close(infd.wr); close(outfd.rd); diff --git a/networking/inetd.c b/networking/inetd.c index 2b0e0069e..7030062b6 100644 --- a/networking/inetd.c +++ b/networking/inetd.c @@ -1271,7 +1271,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) pid = vfork(); if (pid < 0) { /* fork error */ - bb_perror_msg("fork"); + bb_perror_msg("vfork"+1); sleep(1); restore_sigmask(&omask); maybe_close(accepted_fd); diff --git a/networking/nc.c b/networking/nc.c index 5fd8bd759..0dacaf117 100644 --- a/networking/nc.c +++ b/networking/nc.c @@ -216,10 +216,8 @@ int nc_main(int argc, char **argv) if (execparam) { pid_t pid; /* With more than one -l, repeatedly act as server */ - if (do_listen > 1 && (pid = vfork()) != 0) { - /* parent or error */ - if (pid < 0) - bb_perror_msg_and_die("vfork"); + if (do_listen > 1 && (pid = xvfork()) != 0) { + /* parent */ /* prevent zombies */ signal(SIGCHLD, SIG_IGN); close(cfd); diff --git a/scripts/basic/docproc.c b/scripts/basic/docproc.c index ef5181226..50ef37157 100644 --- a/scripts/basic/docproc.c +++ b/scripts/basic/docproc.c @@ -86,7 +86,7 @@ void exec_kernel_doc(char **svec) fflush(stdout); switch(pid=fork()) { case -1: - perror("fork"); + perror("vfork"+1); exit(1); case 0: rflen = strlen(getenv("SRCTREE")); diff --git a/shell/hush.c b/shell/hush.c index 29ff3c442..831443e2e 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -3208,15 +3208,11 @@ static void setup_heredoc(struct redir_struct *redir) #if !BB_MMU to_free = NULL; #endif - pid = vfork(); - if (pid < 0) - bb_perror_msg_and_die("vfork"); + pid = xvfork(); if (pid == 0) { /* child */ disable_restore_tty_pgrp_on_exit(); - pid = BB_MMU ? fork() : vfork(); - if (pid < 0) - bb_perror_msg_and_die(BB_MMU ? "fork" : "vfork"); + pid = BB_MMU ? xfork() : xvfork(); if (pid != 0) _exit(0); /* grandchild */ @@ -4450,7 +4446,7 @@ static NOINLINE int run_pipe(struct pipe *pi) argv_expanded = NULL; if (command->pid < 0) { /* [v]fork failed */ /* Clearly indicate, was it fork or vfork */ - bb_perror_msg(BB_MMU ? "fork" : "vfork"); + bb_perror_msg(BB_MMU ? "vfork"+1 : "vfork"); } else { pi->alive_cmds++; #if ENABLE_HUSH_JOB @@ -5586,10 +5582,7 @@ static FILE *generate_stream_from_string(const char *s, pid_t *pid_p) # endif xpipe(channel); - pid = BB_MMU ? fork() : vfork(); - if (pid < 0) - bb_perror_msg_and_die(BB_MMU ? "fork" : "vfork"); - + pid = BB_MMU ? xfork() : xvfork(); if (pid == 0) { /* child */ disable_restore_tty_pgrp_on_exit(); /* Process substitution is not considered to be usual diff --git a/util-linux/script.c b/util-linux/script.c index d9a62fbfe..c23117cf3 100644 --- a/util-linux/script.c +++ b/util-linux/script.c @@ -88,10 +88,7 @@ int script_main(int argc UNUSED_PARAM, char **argv) /* TODO: SIGWINCH? pass window size changes down to slave? */ - child_pid = vfork(); - if (child_pid < 0) { - bb_perror_msg_and_die("vfork"); - } + child_pid = xvfork(); if (child_pid) { /* parent */ -- cgit v1.2.3-55-g6feb From 9297dbc9d285e823af59c443e0123cb99577569a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 5 Jul 2010 21:37:12 +0200 Subject: randomconfig fixes Signed-off-by: Denys Vlasenko --- applets/applets.c | 2 -- archival/bbunzip.c | 2 +- archival/libunarchive/Kbuild.src | 1 + libbb/appletlib.c | 6 +++++- shell/hush.c | 18 +++++++++++++----- testsuite/ash.tests | 1 - testsuite/cal.tests | 1 - testsuite/cpio.tests | 2 +- testsuite/date/date-works-1 | 2 ++ testsuite/expand.tests | 7 ++++--- testsuite/fold.tests | 7 ++++--- testsuite/ls.tests | 8 ++++---- testsuite/mount.tests | 1 - testsuite/unexpand.tests | 6 ++++-- 14 files changed, 39 insertions(+), 25 deletions(-) (limited to 'shell') diff --git a/applets/applets.c b/applets/applets.c index 133a21575..6a3996272 100644 --- a/applets/applets.c +++ b/applets/applets.c @@ -6,8 +6,6 @@ * * Licensed under GPLv2, see file License in this tarball for details. */ - -#include #include "busybox.h" #if ENABLE_BUILD_LIBBUSYBOX diff --git a/archival/bbunzip.c b/archival/bbunzip.c index 832a7bbf3..c1259ac46 100644 --- a/archival/bbunzip.c +++ b/archival/bbunzip.c @@ -387,7 +387,7 @@ IF_DESKTOP(long long) int FAST_FUNC unpack_unxz(unpack_info_t *info UNUSED_PARAM int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int unxz_main(int argc UNUSED_PARAM, char **argv) { - int opts = getopt32(argv, "cfvdt"); + IF_XZ(int opts =) getopt32(argv, "cfvdt"); # if ENABLE_XZ /* xz without -d or -t? */ if (applet_name[2] == '\0' && !(opts & (OPT_DECOMPRESS|OPT_TEST))) diff --git a/archival/libunarchive/Kbuild.src b/archival/libunarchive/Kbuild.src index 6ad1d7a65..a8549570e 100644 --- a/archival/libunarchive/Kbuild.src +++ b/archival/libunarchive/Kbuild.src @@ -38,6 +38,7 @@ INSERT lib-$(CONFIG_AR) += get_header_ar.o unpack_ar_archive.o lib-$(CONFIG_BUNZIP2) += decompress_bunzip2.o lib-$(CONFIG_UNLZMA) += decompress_unlzma.o +lib-$(CONFIG_UNXZ) += decompress_unxz.o lib-$(CONFIG_CPIO) += get_header_cpio.o lib-$(CONFIG_DPKG) += $(DPKG_FILES) lib-$(CONFIG_DPKG_DEB) += $(DPKG_FILES) diff --git a/libbb/appletlib.c b/libbb/appletlib.c index 6f058bcc8..4924a97c1 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -195,7 +195,11 @@ void lbb_prepare(const char *applet #if ENABLE_FEATURE_INDIVIDUAL /* Redundant for busybox (run_applet_and_exit covers that case) * but needed for "individual applet" mode */ - if (argv[1] && !argv[2] && strcmp(argv[1], "--help") == 0) { + if (argv[1] + && !argv[2] + && strcmp(argv[1], "--help") == 0 + && strncmp(applet, "busybox", 7) != 0 + ) { /* Special case. POSIX says "test --help" * should be no different from e.g. "test --foo". */ if (!ENABLE_TEST || strcmp(applet_name, "test") != 0) diff --git a/shell/hush.c b/shell/hush.c index 831443e2e..31ca22a2e 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -117,6 +117,10 @@ * and therefore waitpid will return the same result as last time) */ #define ENABLE_HUSH_FAST 0 +/* TODO: implement simplified code for users which do not need ${var%...} ops + * So far ${var%...} ops are always enabled: + */ +#define ENABLE_HUSH_DOLLAR_OPS 1 #if BUILD_AS_NOMMU @@ -2681,7 +2685,7 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg, char } } } else if (exp_op == ':') { -#if ENABLE_HUSH_BASH_COMPAT +#if ENABLE_HUSH_BASH_COMPAT && ENABLE_SH_MATH_SUPPORT /* It's ${var:N[:M]} bashism. * Note that in encoded form it has TWO parts: * var:NM @@ -5820,7 +5824,7 @@ static int parse_group(o_string *dest, struct parse_context *ctx, /* command remains "open", available for possible redirects */ } -#if ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT +#if ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT || ENABLE_HUSH_DOLLAR_OPS /* Subroutines for copying $(...) and `...` things */ static void add_till_backquote(o_string *dest, struct in_str *input); /* '...' */ @@ -5921,9 +5925,9 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign { int ch; char dbl = end_ch & DOUBLE_CLOSE_CHAR_FLAG; -#if ENABLE_HUSH_BASH_COMPAT +# if ENABLE_HUSH_BASH_COMPAT char end_char2 = end_ch >> 8; -#endif +# endif end_ch &= (DOUBLE_CLOSE_CHAR_FLAG - 1); while (1) { @@ -5976,7 +5980,7 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign } return ch; } -#endif /* ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT */ +#endif /* ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT || ENABLE_HUSH_DOLLAR_OPS */ /* Return code: 0 for OK, 1 for syntax error */ #if BB_MMU @@ -6082,7 +6086,11 @@ static int parse_dollar(o_string *as_string, again: if (!BB_MMU) pos = dest->length; +#if ENABLE_HUSH_DOLLAR_OPS last_ch = add_till_closing_bracket(dest, input, end_ch); +#else +#error Simple code to only allow ${var} is not implemented +#endif if (as_string) { o_addstr(as_string, dest->data + pos); o_addchr(as_string, last_ch); diff --git a/testsuite/ash.tests b/testsuite/ash.tests index dd626e6d1..2eeb746e4 100755 --- a/testsuite/ash.tests +++ b/testsuite/ash.tests @@ -6,7 +6,6 @@ # Licensed under GPL v2, see file LICENSE for details. . ./testing.sh - test -f "$bindir/.config" && . "$bindir/.config" test x"CONFIG_SCRIPT" = x"y" || exit 0 diff --git a/testsuite/cal.tests b/testsuite/cal.tests index 30985688b..db693ee59 100755 --- a/testsuite/cal.tests +++ b/testsuite/cal.tests @@ -3,7 +3,6 @@ # Licensed under GPL v2, see file LICENSE for details. . ./testing.sh - test -f "$bindir/.config" && . "$bindir/.config" # testing "test name" "command" "expected result" "file input" "stdin" diff --git a/testsuite/cpio.tests b/testsuite/cpio.tests index 5b397b01c..7aee774a1 100755 --- a/testsuite/cpio.tests +++ b/testsuite/cpio.tests @@ -99,7 +99,7 @@ SKIP= # chown on a link was affecting file, dropping its suid/sgid bits rm -rf cpio.testdir -optional FEATURE_CPIO_O +optional FEATURE_CPIO_O FEATURE_STAT_FORMAT mkdir cpio.testdir touch cpio.testdir/file chmod 6755 cpio.testdir/file # sets suid/sgid bits diff --git a/testsuite/date/date-works-1 b/testsuite/date/date-works-1 index 1b3e47ab0..e745d3841 100644 --- a/testsuite/date/date-works-1 +++ b/testsuite/date/date-works-1 @@ -1,3 +1,5 @@ +unset LANG + dt=`busybox date -d 1:2 +%T` test x"$dt" = x"01:02:00" diff --git a/testsuite/expand.tests b/testsuite/expand.tests index 357a9ad6b..2d92344d4 100755 --- a/testsuite/expand.tests +++ b/testsuite/expand.tests @@ -3,6 +3,7 @@ # Licensed under GPL v2, see file LICENSE for details. . ./testing.sh +test -f "$bindir/.config" && . "$bindir/.config" # testing "test name" "options" "expected result" "file input" "stdin" @@ -12,13 +13,13 @@ testing "expand" \ "" \ "\t12345678\t12345678\n" -optional UNICODE_SUPPORT +test x"$CONFIG_UNICODE_SUPPORT" = x"y" \ +&& test x"$CONFIG_UNICODE_USING_LOCALE" != x"y" \ +&& test "$CONFIG_LAST_SUPPORTED_WCHAR" -gt "916" \ testing "expand with unicode characher 0x394" \ "expand" \ "Δ 12345ΔΔΔ 12345678\n" \ "" \ "Δ\t12345ΔΔΔ\t12345678\n" -SKIP= - exit $FAILCOUNT diff --git a/testsuite/fold.tests b/testsuite/fold.tests index 0197d024d..e5700cc2b 100755 --- a/testsuite/fold.tests +++ b/testsuite/fold.tests @@ -3,6 +3,7 @@ # Licensed under GPL v2, see file LICENSE for details. . ./testing.sh +test -f "$bindir/.config" && . "$bindir/.config" # testing "test name" "options" "expected result" "file input" "stdin" @@ -28,9 +29,10 @@ be preserved is here:>\0< - they must be preserved " \ -optional UNICODE_SUPPORT # The text was taken from English and Ukrainian wikipedia pages -testing "fold -sw66 with unicode input" "fold -sw66" \ +test x"$CONFIG_UNICODE_SUPPORT" = x"y" \ +&& test x"$CONFIG_UNICODE_USING_LOCALE" != x"y" \ +&& testing "fold -sw66 with unicode input" "fold -sw66" \ "\ The Andromeda Galaxy (pronounced /ænˈdrɒmədə/, also known as \n\ Messier 31, M31, or NGC224; often referred to as the Great \n\ @@ -56,6 +58,5 @@ Way. спіральна галактика, що знаходиться на відстані приблизно у 2,5 \ мільйони світлових років від нашої планети у сузір'ї Андромеди. \ На початку ХХІ ст. в центрі галактики виявлено чорну дірку." -SKIP= exit $FAILCOUNT diff --git a/testsuite/ls.tests b/testsuite/ls.tests index 0680762fc..dc842123d 100755 --- a/testsuite/ls.tests +++ b/testsuite/ls.tests @@ -3,10 +3,9 @@ # Licensed under GPL v2, see file LICENSE for details. . ./testing.sh - test -f "$bindir/.config" && . "$bindir/.config" -rm -rf ls.testdir >/dev/null +rm -rf ls.testdir 2>/dev/null mkdir ls.testdir || exit 1 # testing "test name" "command" "expected result" "file input" "stdin" @@ -15,9 +14,10 @@ mkdir ls.testdir || exit 1 # I suspect we might fail to skip exactly correct number of bytes # over broked unicode sequences. test x"$CONFIG_UNICODE_SUPPORT" = x"y" \ -&& test x"$CONFIG_LOCALE_SUPPORT" != x"y" \ +&& test x"$CONFIG_UNICODE_USING_LOCALE" != x"y" \ && test x"$CONFIG_SUBST_WCHAR" = x"63" \ && test x"$CONFIG_LAST_SUPPORTED_WCHAR" = x"767" \ +&& test x"$CONFIG_FEATURE_LS_SORTFILES" = x"y" \ && testing "ls unicode test with codepoints limited to 767" \ "(cd ls.testdir && sh ../ls.mk_uni_tests) && ls -1 ls.testdir" \ '0001_1__Some_correct_UTF-8_text___________________________________________| @@ -134,7 +134,7 @@ test x"$CONFIG_UNICODE_SUPPORT" = x"y" \ # Currently fails on "0080_4.2.2__U-000007FF_=_e0_9f_bf" line test x"$CONFIG_UNICODE_SUPPORT" = x"y" \ -&& test x"$CONFIG_LOCALE_SUPPORT" != x"y" \ +&& test x"$CONFIG_UNICODE_USING_LOCALE" != x"y" \ && test x"$CONFIG_SUBST_WCHAR" = x"63" \ && test x"$CONFIG_LAST_SUPPORTED_WCHAR" = x"0" \ && testing "ls unicode test with unlimited codepoints" \ diff --git a/testsuite/mount.tests b/testsuite/mount.tests index 3c7405fbd..ce1a6006b 100755 --- a/testsuite/mount.tests +++ b/testsuite/mount.tests @@ -3,7 +3,6 @@ # Licensed under GPL v2, see file LICENSE for details. . ./testing.sh - test -f "$bindir/.config" && . "$bindir/.config" test "`id -u`" = 0 || { diff --git a/testsuite/unexpand.tests b/testsuite/unexpand.tests index a48e3214e..0727884f7 100755 --- a/testsuite/unexpand.tests +++ b/testsuite/unexpand.tests @@ -3,6 +3,7 @@ # Licensed under GPL v2, see file LICENSE for details. . ./testing.sh +test -f "$bindir/.config" && . "$bindir/.config" # testing "test name" "options" "expected result" "file input" "stdin" @@ -30,9 +31,10 @@ testing "unexpand case 7" "unexpand" \ testing "unexpand case 8" "unexpand" \ "a b\n" "" "a b\n" \ -optional UNICODE_SUPPORT +test x"$CONFIG_UNICODE_SUPPORT" = x"y" \ +&& test x"$CONFIG_UNICODE_USING_LOCALE" != x"y" \ +&& test "$CONFIG_LAST_SUPPORTED_WCHAR" -gt "916" \ testing "unexpand with unicode characher 0x394" "unexpand" \ "1ΔΔΔ5\t99999\n" "" "1ΔΔΔ5 99999\n" -SKIP= exit $FAILCOUNT -- cgit v1.2.3-55-g6feb From 889550b36b057fb8ad5c825c7a17e46fde4ebbf6 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 14 Jul 2010 19:01:25 +0200 Subject: hush: make pun_pipe loop clearer; fix "cmd | var=`cmd` | cmd" handling function old new delta free_strings - 38 +38 pseudo_exec_argv 161 171 +10 free_pipe 227 205 -22 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 1/1 up/down: 48/-22) Total: 26 bytes Signed-off-by: Denys Vlasenko --- shell/hush.c | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) (limited to 'shell') diff --git a/shell/hush.c b/shell/hush.c index 31ca22a2e..8a467be80 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -3713,11 +3713,17 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, { char **new_env; - /* Case when we are here: ... | var=val | ... */ - if (!argv[assignment_cnt]) + new_env = expand_assignments(argv, assignment_cnt); + + if (!argv[assignment_cnt]) { + /* Case when we are here: ... | var=val | ... + * (note that we do not exit early, i.e., do not optimize out + * expand_assignments(): think about ... | var=`sleep 1` | ... + */ + free_strings(new_env); _exit(EXIT_SUCCESS); + } - new_env = expand_assignments(argv, assignment_cnt); #if BB_MMU set_vars_and_save_old(new_env); free(new_env); /* optional */ @@ -3727,6 +3733,7 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, nommu_save->new_env = new_env; nommu_save->old_vars = set_vars_and_save_old(new_env); #endif + if (argv_expanded) { argv = argv_expanded; } else { @@ -4145,8 +4152,9 @@ static int checkjobs_and_fg_shell(struct pipe* fg_pipe) static NOINLINE int run_pipe(struct pipe *pi) { static const char *const null_ptr = NULL; - int i; - int nextin; + + int cmd_no; + int next_infd; struct command *command; char **argv_expanded; char **argv; @@ -4160,7 +4168,7 @@ static NOINLINE int run_pipe(struct pipe *pi) IF_HUSH_JOB(pi->pgrp = -1;) pi->stopped_cmds = 0; - command = &(pi->cmds[0]); + command = &pi->cmds[0]; argv_expanded = NULL; if (pi->num_cmds != 1 @@ -4358,9 +4366,10 @@ static NOINLINE int run_pipe(struct pipe *pi) /* Going to fork a child per each pipe member */ pi->alive_cmds = 0; - nextin = 0; + next_infd = 0; - for (i = 0; i < pi->num_cmds; i++) { + cmd_no = 0; + while (cmd_no < pi->num_cmds) { struct fd_pair pipefds; #if !BB_MMU volatile nommu_save_t nommu_save; @@ -4369,7 +4378,8 @@ static NOINLINE int run_pipe(struct pipe *pi) nommu_save.argv = NULL; nommu_save.argv_from_re_execing = NULL; #endif - command = &(pi->cmds[i]); + command = &pi->cmds[cmd_no]; + cmd_no++; if (command->argv) { debug_printf_exec(": pipe member '%s' '%s'...\n", command->argv[0], command->argv[1]); @@ -4380,7 +4390,7 @@ static NOINLINE int run_pipe(struct pipe *pi) /* pipes are inserted between pairs of commands */ pipefds.rd = 0; pipefds.wr = 1; - if ((i + 1) < pi->num_cmds) + if (cmd_no < pi->num_cmds) xpiped_pair(pipefds); command->pid = BB_MMU ? fork() : vfork(); @@ -4413,7 +4423,7 @@ static NOINLINE int run_pipe(struct pipe *pi) if (open(bb_dev_null, O_RDONLY)) xopen("/", O_RDONLY); } else { - xmove_fd(nextin, 0); + xmove_fd(next_infd, 0); } xmove_fd(pipefds.wr, 1); if (pipefds.rd > 1) @@ -4460,12 +4470,12 @@ static NOINLINE int run_pipe(struct pipe *pi) #endif } - if (i) - close(nextin); - if ((i + 1) < pi->num_cmds) + if (cmd_no > 1) + close(next_infd); + if (cmd_no < pi->num_cmds) close(pipefds.wr); /* Pass read (output) pipe end to next iteration */ - nextin = pipefds.rd; + next_infd = pipefds.rd; } if (!pi->alive_cmds) { @@ -7153,7 +7163,7 @@ int hush_main(int argc, char **argv) #endif case 'n': case 'x': - if (!set_mode('-', opt)) + if (set_mode('-', opt) == 0) /* no error */ break; default: #ifndef BB_VER -- cgit v1.2.3-55-g6feb From 8fa1f5d543266816967949812b65790fbe7cdcd4 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 15 Jul 2010 08:18:46 +0200 Subject: hush: fix faloout from previous commit Signed-off-by: Denys Vlasenko --- include/busybox.h | 13 ++++++++----- shell/hush.c | 26 ++++++++++++-------------- 2 files changed, 20 insertions(+), 19 deletions(-) (limited to 'shell') diff --git a/include/busybox.h b/include/busybox.h index 48ce856ea..48fc0b4c8 100644 --- a/include/busybox.h +++ b/include/busybox.h @@ -35,18 +35,21 @@ extern const uint16_t applet_nameofs[]; extern const uint8_t applet_install_loc[]; #if ENABLE_FEATURE_SUID || ENABLE_FEATURE_PREFER_APPLETS -#define APPLET_NAME(i) (applet_names + (applet_nameofs[i] & 0x0fff)) +# define APPLET_NAME(i) (applet_names + (applet_nameofs[i] & 0x0fff)) #else -#define APPLET_NAME(i) (applet_names + applet_nameofs[i]) +# define APPLET_NAME(i) (applet_names + applet_nameofs[i]) #endif #if ENABLE_FEATURE_PREFER_APPLETS -#define APPLET_IS_NOFORK(i) (applet_nameofs[i] & (1 << 12)) -#define APPLET_IS_NOEXEC(i) (applet_nameofs[i] & (1 << 13)) +# define APPLET_IS_NOFORK(i) (applet_nameofs[i] & (1 << 12)) +# define APPLET_IS_NOEXEC(i) (applet_nameofs[i] & (1 << 13)) +#else +# define APPLET_IS_NOFORK(i) 0 +# define APPLET_IS_NOEXEC(i) 0 #endif #if ENABLE_FEATURE_SUID -#define APPLET_SUID(i) ((applet_nameofs[i] >> 14) & 0x3) +# define APPLET_SUID(i) ((applet_nameofs[i] >> 14) & 0x3) #endif #if ENABLE_FEATURE_INSTALLER diff --git a/shell/hush.c b/shell/hush.c index 8a467be80..7dacfa0b1 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -4328,9 +4328,7 @@ static NOINLINE int run_pipe(struct pipe *pi) } #endif } -#if ENABLE_FEATURE_SH_STANDALONE clean_up_and_ret: -#endif restore_redirects(squirrel); unset_vars(new_env); add_vars(old_vars); @@ -4342,20 +4340,20 @@ static NOINLINE int run_pipe(struct pipe *pi) return rcode; } -#if ENABLE_FEATURE_SH_STANDALONE - i = find_applet_by_name(argv_expanded[0]); - if (i >= 0 && APPLET_IS_NOFORK(i)) { - rcode = setup_redirects(command, squirrel); - if (rcode == 0) { - new_env = expand_assignments(argv, command->assignment_cnt); - old_vars = set_vars_and_save_old(new_env); - debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", - argv_expanded[0], argv_expanded[1]); - rcode = run_nofork_applet(i, argv_expanded); + if (ENABLE_FEATURE_SH_STANDALONE) { + int n = find_applet_by_name(argv_expanded[0]); + if (n >= 0 && APPLET_IS_NOFORK(n)) { + rcode = setup_redirects(command, squirrel); + if (rcode == 0) { + new_env = expand_assignments(argv, command->assignment_cnt); + old_vars = set_vars_and_save_old(new_env); + debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", + argv_expanded[0], argv_expanded[1]); + rcode = run_nofork_applet(n, argv_expanded); + } + goto clean_up_and_ret; } - goto clean_up_and_ret; } -#endif /* It is neither builtin nor applet. We must fork. */ } -- cgit v1.2.3-55-g6feb From b3389de04b1fe398e5f88446dd23a7826139da7d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 15 Jul 2010 12:33:37 +0200 Subject: hush: fix typo in comment Signed-off-by: Denys Vlasenko --- shell/hush.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'shell') diff --git a/shell/hush.c b/shell/hush.c index 7dacfa0b1..14f8f2422 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -4246,7 +4246,7 @@ static NOINLINE int run_pipe(struct pipe *pi) set_local_var(p, /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ 0); argv++; } - /* Redirect error sets $? to 1. Othervise, + /* Redirect error sets $? to 1. Otherwise, * if evaluating assignment value set $?, retain it. * Try "false; q=`exit 2`; echo $?" - should print 2: */ if (rcode == 0) -- cgit v1.2.3-55-g6feb From 3f5fae07725b0cc24587c7965f17ac57e5610bfb Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 16 Jul 2010 12:35:35 +0200 Subject: hush: add support for set -x function old new delta run_pipe 1442 1568 +126 dump_cmd_in_x_mode - 126 +126 builtin_trap 441 462 +21 pseudo_exec_argv 171 187 +16 reset_traps_to_defaults 214 229 +15 check_and_run_traps 227 232 +5 hush_exit 98 101 +3 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 6/0 up/down: 312/0) Total: 312 bytes Signed-off-by: Denys Vlasenko --- shell/hush.c | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) (limited to 'shell') diff --git a/shell/hush.c b/shell/hush.c index 14f8f2422..7640bd6ba 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -532,6 +532,7 @@ struct globals { smallint flag_return_in_progress; #endif smallint fake_mode; + smallint x_mode; smallint exiting; /* used to prevent EXIT trap recursion */ /* These four support $?, $#, and $1 */ smalluint last_exitcode; @@ -3692,6 +3693,31 @@ static void execvp_or_die(char **argv) _exit(127); /* bash compat */ } +static void dump_cmd_in_x_mode(char **argv) +{ + if (G.x_mode && argv) { + /* We want to output the line in one write op */ + char *buf, *p; + int len; + int n; + + len = 3; + n = 0; + while (argv[n]) + len += strlen(argv[n++]) + 1; + buf = xmalloc(len); + buf[0] = '+'; + p = buf + 1; + n = 0; + while (argv[n]) + p += sprintf(p, " %s", argv[n++]); + *p++ = '\n'; + *p = '\0'; + fputs(buf, stderr); + free(buf); + } +} + #if BB_MMU #define pseudo_exec_argv(nommu_save, argv, assignment_cnt, argv_expanded) \ pseudo_exec_argv(argv, assignment_cnt, argv_expanded) @@ -3714,6 +3740,7 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, char **new_env; new_env = expand_assignments(argv, assignment_cnt); + dump_cmd_in_x_mode(new_env); if (!argv[assignment_cnt]) { /* Case when we are here: ... | var=val | ... @@ -3742,6 +3769,7 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, nommu_save->argv = argv; #endif } + dump_cmd_in_x_mode(argv); #if ENABLE_FEATURE_SH_STANDALONE || BB_MMU if (strchr(argv[0], '/') != NULL) @@ -4239,13 +4267,19 @@ static NOINLINE int run_pipe(struct pipe *pi) rcode = setup_redirects(command, squirrel); restore_redirects(squirrel); /* Set shell variables */ + if (G.x_mode) + bb_putchar_stderr('+'); while (*argv) { p = expand_string_to_string(*argv); + if (G.x_mode) + fprintf(stderr, " %s", p); debug_printf_exec("set shell var:'%s'->'%s'\n", *argv, p); set_local_var(p, /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ 0); argv++; } + if (G.x_mode) + bb_putchar_stderr('\n'); /* Redirect error sets $? to 1. Otherwise, * if evaluating assignment value set $?, retain it. * Try "false; q=`exit 2`; echo $?" - should print 2: */ @@ -4305,6 +4339,8 @@ static NOINLINE int run_pipe(struct pipe *pi) rcode = setup_redirects(command, squirrel); if (rcode == 0) { new_env = expand_assignments(argv, command->assignment_cnt); + dump_cmd_in_x_mode(new_env); + dump_cmd_in_x_mode(argv_expanded); old_vars = set_vars_and_save_old(new_env); if (!funcp) { debug_printf_exec(": builtin '%s' '%s'...\n", @@ -4346,6 +4382,8 @@ static NOINLINE int run_pipe(struct pipe *pi) rcode = setup_redirects(command, squirrel); if (rcode == 0) { new_env = expand_assignments(argv, command->assignment_cnt); + dump_cmd_in_x_mode(new_env); + dump_cmd_in_x_mode(argv_expanded); old_vars = set_vars_and_save_old(new_env); debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv_expanded[0], argv_expanded[1]); @@ -6932,7 +6970,7 @@ static int set_mode(const char cstate, const char mode) int state = (cstate == '-' ? 1 : 0); switch (mode) { case 'n': G.fake_mode = state; break; - case 'x': /*G.debug_mode = state;*/ break; + case 'x': G.x_mode = state; break; default: return EXIT_FAILURE; } return EXIT_SUCCESS; -- cgit v1.2.3-55-g6feb From 202a2d121905a6245cdf7441c9f83ff213b5502e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 16 Jul 2010 12:36:14 +0200 Subject: hush: make set -x support optional Signed-off-by: Denys Vlasenko --- include/applets.src.h | 5 -- include/usage.src.h | 6 -- shell/Config.src | 106 ---------------------------------- shell/Kbuild.src | 2 - shell/hush.c | 155 +++++++++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 147 insertions(+), 127 deletions(-) (limited to 'shell') diff --git a/include/applets.src.h b/include/applets.src.h index 9162b66c7..5d84597b0 100644 --- a/include/applets.src.h +++ b/include/applets.src.h @@ -76,7 +76,6 @@ IF_ASH(APPLET(ash, _BB_DIR_BIN, _BB_SUID_DROP)) IF_AWK(APPLET_NOEXEC(awk, awk, _BB_DIR_USR_BIN, _BB_SUID_DROP, awk)) IF_BASENAME(APPLET_NOFORK(basename, basename, _BB_DIR_USR_BIN, _BB_SUID_DROP, basename)) IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, _BB_DIR_BIN, _BB_SUID_DROP, bash)) -IF_FEATURE_BASH_IS_HUSH(APPLET_ODDNAME(bash, hush, _BB_DIR_BIN, _BB_SUID_DROP, bash)) IF_BBCONFIG(APPLET(bbconfig, _BB_DIR_BIN, _BB_SUID_DROP)) //IF_BBSH(APPLET(bbsh, _BB_DIR_BIN, _BB_SUID_DROP)) IF_BEEP(APPLET(beep, _BB_DIR_USR_BIN, _BB_SUID_DROP)) @@ -183,7 +182,6 @@ IF_HEXDUMP(APPLET_NOEXEC(hexdump, hexdump, _BB_DIR_USR_BIN, _BB_SUID_DROP, hexdu IF_HOSTID(APPLET_NOFORK(hostid, hostid, _BB_DIR_USR_BIN, _BB_SUID_DROP, hostid)) IF_HOSTNAME(APPLET(hostname, _BB_DIR_BIN, _BB_SUID_DROP)) IF_HTTPD(APPLET(httpd, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_HUSH(APPLET(hush, _BB_DIR_BIN, _BB_SUID_DROP)) IF_HWCLOCK(APPLET(hwclock, _BB_DIR_SBIN, _BB_SUID_DROP)) IF_ID(APPLET(id, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_IFCONFIG(APPLET(ifconfig, _BB_DIR_SBIN, _BB_SUID_DROP)) @@ -218,7 +216,6 @@ IF_KILL(APPLET(kill, _BB_DIR_BIN, _BB_SUID_DROP)) IF_KILLALL(APPLET_ODDNAME(killall, kill, _BB_DIR_USR_BIN, _BB_SUID_DROP, killall)) IF_KILLALL5(APPLET_ODDNAME(killall5, kill, _BB_DIR_USR_BIN, _BB_SUID_DROP, killall5)) IF_KLOGD(APPLET(klogd, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_LASH(APPLET(lash, _BB_DIR_BIN, _BB_SUID_DROP)) IF_LAST(APPLET(last, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_LENGTH(APPLET_NOFORK(length, length, _BB_DIR_USR_BIN, _BB_SUID_DROP, length)) IF_LESS(APPLET(less, _BB_DIR_USR_BIN, _BB_SUID_DROP)) @@ -273,7 +270,6 @@ IF_MODPROBE_SMALL(APPLET(modprobe, _BB_DIR_SBIN, _BB_SUID_DROP)) IF_MORE(APPLET(more, _BB_DIR_BIN, _BB_SUID_DROP)) IF_MOUNT(APPLET(mount, _BB_DIR_BIN, IF_DESKTOP(_BB_SUID_MAYBE) IF_NOT_DESKTOP(_BB_SUID_DROP))) IF_MOUNTPOINT(APPLET(mountpoint, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_MSH(APPLET(msh, _BB_DIR_BIN, _BB_SUID_DROP)) IF_MT(APPLET(mt, _BB_DIR_BIN, _BB_SUID_DROP)) IF_MV(APPLET(mv, _BB_DIR_BIN, _BB_SUID_DROP)) IF_NAMEIF(APPLET(nameif, _BB_DIR_SBIN, _BB_SUID_DROP)) @@ -349,7 +345,6 @@ IF_SETSEBOOL(APPLET(setsebool, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) IF_SETSID(APPLET(setsid, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_SETUIDGID(APPLET_ODDNAME(setuidgid, chpst, _BB_DIR_USR_BIN, _BB_SUID_DROP, setuidgid)) IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, _BB_DIR_BIN, _BB_SUID_DROP, sh)) -IF_FEATURE_SH_IS_HUSH(APPLET_ODDNAME(sh, hush, _BB_DIR_BIN, _BB_SUID_DROP, sh)) IF_SHA1SUM(APPLET_ODDNAME(sha1sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DROP, sha1sum)) IF_SHA256SUM(APPLET_ODDNAME(sha256sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DROP, sha256sum)) IF_SHA512SUM(APPLET_ODDNAME(sha512sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DROP, sha512sum)) diff --git a/include/usage.src.h b/include/usage.src.h index 94a3256b1..b3396006f 100644 --- a/include/usage.src.h +++ b/include/usage.src.h @@ -119,12 +119,6 @@ INSERT #define sh_full_usage "" #define ash_trivial_usage NOUSAGE_STR #define ash_full_usage "" -#define hush_trivial_usage NOUSAGE_STR -#define hush_full_usage "" -#define lash_trivial_usage NOUSAGE_STR -#define lash_full_usage "" -#define msh_trivial_usage NOUSAGE_STR -#define msh_full_usage "" #define bash_trivial_usage NOUSAGE_STR #define bash_full_usage "" diff --git a/shell/Config.src b/shell/Config.src index 800911966..f415a5fa6 100644 --- a/shell/Config.src +++ b/shell/Config.src @@ -110,112 +110,6 @@ config ASH_EXPAND_PRMT This option recreates the prompt string from the environment variable each time it is displayed. -config HUSH - bool "hush" - default y - help - hush is a small shell (22k). It handles the normal flow control - constructs such as if/then/elif/else/fi, for/in/do/done, while loops, - case/esac. Redirections, here documents, $((arithmetic)) - and functions are supported. - - It will compile and work on no-mmu systems. - - It does not handle select, aliases, brace expansion, - tilde expansion, &>file and >&file redirection of stdout+stderr. - -config HUSH_BASH_COMPAT - bool "bash-compatible extensions" - default y - depends on HUSH - help - Enable bash-compatible extensions. - -config HUSH_HELP - bool "help builtin" - default y - depends on HUSH - help - Enable help builtin in hush. Code size + ~1 kbyte. - -config HUSH_INTERACTIVE - bool "Interactive mode" - default y - depends on HUSH - help - Enable interactive mode (prompt and command editing). - Without this, hush simply reads and executes commands - from stdin just like a shell script from a file. - No prompt, no PS1/PS2 magic shell variables. - -config HUSH_JOB - bool "Job control" - default y - depends on HUSH_INTERACTIVE - help - Enable job control: Ctrl-Z backgrounds, Ctrl-C interrupts current - command (not entire shell), fg/bg builtins work. Without this option, - "cmd &" still works by simply spawning a process and immediately - prompting for next command (or executing next command in a script), - but no separate process group is formed. - -config HUSH_TICK - bool "Process substitution" - default y - depends on HUSH - help - Enable process substitution `command` and $(command) in hush. - -config HUSH_IF - bool "Support if/then/elif/else/fi" - default y - depends on HUSH - help - Enable if/then/elif/else/fi in hush. - -config HUSH_LOOPS - bool "Support for, while and until loops" - default y - depends on HUSH - help - Enable for, while and until loops in hush. - -config HUSH_CASE - bool "Support case ... esac statement" - default y - depends on HUSH - help - Enable case ... esac statement in hush. +400 bytes. - -config HUSH_FUNCTIONS - bool "Support funcname() { commands; } syntax" - default y - depends on HUSH - help - Enable support for shell functions in hush. +800 bytes. - -config HUSH_LOCAL - bool "Support local builtin" - default y - depends on HUSH_FUNCTIONS - help - Enable support for local variables in functions. - -config HUSH_EXPORT_N - bool "Support export '-n' option" - default y - depends on HUSH - help - Enable support for export '-n' option in hush. It is a bash extension. - -config HUSH_RANDOM_SUPPORT - bool "Pseudorandom generator and $RANDOM variable" - default y - depends on HUSH - help - Enable pseudorandom generator and dynamic variable "$RANDOM". - Each read of "$RANDOM" will generate a new pseudorandom value. - choice prompt "Choose which shell is aliased to 'sh' name" diff --git a/shell/Kbuild.src b/shell/Kbuild.src index d76b35386..c7eb5b61a 100644 --- a/shell/Kbuild.src +++ b/shell/Kbuild.src @@ -9,9 +9,7 @@ lib-y:= INSERT lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o -lib-$(CONFIG_HUSH) += hush.o match.o shell_common.o lib-$(CONFIG_CTTYHACK) += cttyhack.o lib-$(CONFIG_SH_MATH_SUPPORT) += math.o lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o -lib-$(CONFIG_HUSH_RANDOM_SUPPORT) += random.o diff --git a/shell/hush.c b/shell/hush.c index 7640bd6ba..c67aebdd7 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -101,6 +101,136 @@ # define PIPE_BUF 4096 /* amount of buffering in a pipe */ #endif +//applet:IF_HUSH(APPLET(hush, _BB_DIR_BIN, _BB_SUID_DROP)) +//applet:IF_MSH(APPLET(msh, _BB_DIR_BIN, _BB_SUID_DROP)) +//applet:IF_LASH(APPLET(lash, _BB_DIR_BIN, _BB_SUID_DROP)) +//applet:IF_FEATURE_SH_IS_HUSH(APPLET_ODDNAME(sh, hush, _BB_DIR_BIN, _BB_SUID_DROP, sh)) +//applet:IF_FEATURE_BASH_IS_HUSH(APPLET_ODDNAME(bash, hush, _BB_DIR_BIN, _BB_SUID_DROP, bash)) + +//kbuild:lib-$(CONFIG_HUSH) += hush.o match.o shell_common.o +//kbuild:lib-$(CONFIG_HUSH_RANDOM_SUPPORT) += random.o + +//config:config HUSH +//config: bool "hush" +//config: default y +//config: help +//config: hush is a small shell (22k). It handles the normal flow control +//config: constructs such as if/then/elif/else/fi, for/in/do/done, while loops, +//config: case/esac. Redirections, here documents, $((arithmetic)) +//config: and functions are supported. +//config: +//config: It will compile and work on no-mmu systems. +//config: +//config: It does not handle select, aliases, brace expansion, +//config: tilde expansion, &>file and >&file redirection of stdout+stderr. +//config: +//config:config HUSH_BASH_COMPAT +//config: bool "bash-compatible extensions" +//config: default y +//config: depends on HUSH +//config: help +//config: Enable bash-compatible extensions. +//config: +//config:config HUSH_HELP +//config: bool "help builtin" +//config: default y +//config: depends on HUSH +//config: help +//config: Enable help builtin in hush. Code size + ~1 kbyte. +//config: +//config:config HUSH_INTERACTIVE +//config: bool "Interactive mode" +//config: default y +//config: depends on HUSH +//config: help +//config: Enable interactive mode (prompt and command editing). +//config: Without this, hush simply reads and executes commands +//config: from stdin just like a shell script from a file. +//config: No prompt, no PS1/PS2 magic shell variables. +//config: +//config:config HUSH_JOB +//config: bool "Job control" +//config: default y +//config: depends on HUSH_INTERACTIVE +//config: help +//config: Enable job control: Ctrl-Z backgrounds, Ctrl-C interrupts current +//config: command (not entire shell), fg/bg builtins work. Without this option, +//config: "cmd &" still works by simply spawning a process and immediately +//config: prompting for next command (or executing next command in a script), +//config: but no separate process group is formed. +//config: +//config:config HUSH_TICK +//config: bool "Process substitution" +//config: default y +//config: depends on HUSH +//config: help +//config: Enable process substitution `command` and $(command) in hush. +//config: +//config:config HUSH_IF +//config: bool "Support if/then/elif/else/fi" +//config: default y +//config: depends on HUSH +//config: help +//config: Enable if/then/elif/else/fi in hush. +//config: +//config:config HUSH_LOOPS +//config: bool "Support for, while and until loops" +//config: default y +//config: depends on HUSH +//config: help +//config: Enable for, while and until loops in hush. +//config: +//config:config HUSH_CASE +//config: bool "Support case ... esac statement" +//config: default y +//config: depends on HUSH +//config: help +//config: Enable case ... esac statement in hush. +400 bytes. +//config: +//config:config HUSH_FUNCTIONS +//config: bool "Support funcname() { commands; } syntax" +//config: default y +//config: depends on HUSH +//config: help +//config: Enable support for shell functions in hush. +800 bytes. +//config: +//config:config HUSH_LOCAL +//config: bool "Support local builtin" +//config: default y +//config: depends on HUSH_FUNCTIONS +//config: help +//config: Enable support for local variables in functions. +//config: +//config:config HUSH_RANDOM_SUPPORT +//config: bool "Pseudorandom generator and $RANDOM variable" +//config: default y +//config: depends on HUSH +//config: help +//config: Enable pseudorandom generator and dynamic variable "$RANDOM". +//config: Each read of "$RANDOM" will generate a new pseudorandom value. +//config: +//config:config HUSH_EXPORT_N +//config: bool "Support 'export -n' option" +//config: default y +//config: depends on HUSH +//config: help +//config: export -n unexports variables. It is a bash extension. +//config: +//config:config HUSH_MODE_X +//config: bool "Support 'hush -x' option and 'set -x' command" +//config: default y +//config: depends on HUSH +//config: help +//config: This instructs hush to print commands before execution. Adds ~300 bytes. +//config: + +//usage:#define hush_trivial_usage NOUSAGE_STR +//usage:#define hush_full_usage "" +//usage:#define lash_trivial_usage NOUSAGE_STR +//usage:#define lash_full_usage "" +//usage:#define msh_trivial_usage NOUSAGE_STR +//usage:#define msh_full_usage "" + /* Build knobs */ #define LEAK_HUNTING 0 @@ -531,8 +661,13 @@ struct globals { */ smallint flag_return_in_progress; #endif - smallint fake_mode; + smallint n_mode; +#if ENABLE_HUSH_MODE_X smallint x_mode; +# define G_x_mode G.x_mode +#else +# define G_x_mode 0 +#endif smallint exiting; /* used to prevent EXIT trap recursion */ /* These four support $?, $#, and $1 */ smalluint last_exitcode; @@ -3693,9 +3828,10 @@ static void execvp_or_die(char **argv) _exit(127); /* bash compat */ } +#if ENABLE_HUSH_MODE_X static void dump_cmd_in_x_mode(char **argv) { - if (G.x_mode && argv) { + if (G_x_mode && argv) { /* We want to output the line in one write op */ char *buf, *p; int len; @@ -3717,6 +3853,9 @@ static void dump_cmd_in_x_mode(char **argv) free(buf); } } +#else +# define dump_cmd_in_x_mode(argv) ((void)0) +#endif #if BB_MMU #define pseudo_exec_argv(nommu_save, argv, assignment_cnt, argv_expanded) \ @@ -4267,18 +4406,18 @@ static NOINLINE int run_pipe(struct pipe *pi) rcode = setup_redirects(command, squirrel); restore_redirects(squirrel); /* Set shell variables */ - if (G.x_mode) + if (G_x_mode) bb_putchar_stderr('+'); while (*argv) { p = expand_string_to_string(*argv); - if (G.x_mode) + if (G_x_mode) fprintf(stderr, " %s", p); debug_printf_exec("set shell var:'%s'->'%s'\n", *argv, p); set_local_var(p, /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ 0); argv++; } - if (G.x_mode) + if (G_x_mode) bb_putchar_stderr('\n'); /* Redirect error sets $? to 1. Otherwise, * if evaluating assignment value set $?, retain it. @@ -4943,7 +5082,7 @@ static int run_and_free_list(struct pipe *pi) { int rcode = 0; debug_printf_exec("run_and_free_list entered\n"); - if (!G.fake_mode) { + if (!G.n_mode) { debug_printf_exec(": run_list: 1st pipe with %d cmds\n", pi->num_cmds); rcode = run_list(pi); } @@ -6969,8 +7108,8 @@ static int set_mode(const char cstate, const char mode) { int state = (cstate == '-' ? 1 : 0); switch (mode) { - case 'n': G.fake_mode = state; break; - case 'x': G.x_mode = state; break; + case 'n': G.n_mode = state; break; + case 'x': IF_HUSH_MODE_X(G_x_mode = state;) break; default: return EXIT_FAILURE; } return EXIT_SUCCESS; -- cgit v1.2.3-55-g6feb From 29082231d0cb1a5b327de5d515b16f332d4dbdaf Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 16 Jul 2010 13:52:32 +0200 Subject: hush: fix multimple dependent variable expansion cases function old new delta get_local_var_value 100 171 +71 expand_assignments 46 76 +30 reset_traps_to_defaults 229 238 +9 maybe_set_to_sigexit 47 50 +3 init_sigmasks 211 214 +3 builtin_trap 462 465 +3 expand_vars_to_list 2412 2408 -4 run_pipe 1568 1533 -35 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 6/2 up/down: 119/-39) Total: 80 bytes Signed-off-by: Denys Vlasenko --- shell/hush.c | 108 +++++++++++++++++++++-------- shell/hush_test/hush-vars/var_serial.right | 5 ++ shell/hush_test/hush-vars/var_serial.tests | 22 ++++++ 3 files changed, 107 insertions(+), 28 deletions(-) create mode 100644 shell/hush_test/hush-vars/var_serial.right create mode 100755 shell/hush_test/hush-vars/var_serial.tests (limited to 'shell') diff --git a/shell/hush.c b/shell/hush.c index c67aebdd7..c5a8ea617 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -221,7 +221,8 @@ //config: default y //config: depends on HUSH //config: help -//config: This instructs hush to print commands before execution. Adds ~300 bytes. +//config: This instructs hush to print commands before execution. +//config: Adds ~300 bytes. //config: //usage:#define hush_trivial_usage NOUSAGE_STR @@ -664,7 +665,7 @@ struct globals { smallint n_mode; #if ENABLE_HUSH_MODE_X smallint x_mode; -# define G_x_mode G.x_mode +# define G_x_mode (G.x_mode) #else # define G_x_mode 0 #endif @@ -688,6 +689,7 @@ struct globals { const char *cwd; struct variable *top_var; /* = &G.shell_ver (set in main()) */ struct variable shell_ver; + char **expanded_assignments; #if ENABLE_HUSH_FUNCTIONS struct function *top_func; # if ENABLE_HUSH_LOCAL @@ -1459,9 +1461,23 @@ static struct variable *get_local_var(const char *name) static const char* FAST_FUNC get_local_var_value(const char *name) { - struct variable **pp = get_ptr_to_local_var(name); - if (pp) - return strchr((*pp)->varstr, '=') + 1; + struct variable **vpp; + + if (G.expanded_assignments) { + char **cpp = G.expanded_assignments; + int len = strlen(name); + while (*cpp) { + char *cp = *cpp; + if (strncmp(cp, name, len) == 0 && cp[len] == '=') + return cp + len + 1; + cpp++; + } + } + + vpp = get_ptr_to_local_var(name); + if (vpp) + return strchr((*vpp)->varstr, '=') + 1; + if (strcmp(name, "PPID") == 0) return utoa(G.root_ppid); // bash compat: UID? EUID? @@ -3090,11 +3106,14 @@ static char* expand_strvec_to_string(char **argv) static char **expand_assignments(char **argv, int count) { int i; - char **p = NULL; + char **p; + + G.expanded_assignments = p = NULL; /* Expand assignments into one string each */ for (i = 0; i < count; i++) { - p = add_string_to_strings(p, expand_string_to_string(argv[i])); + G.expanded_assignments = p = add_string_to_strings(p, expand_string_to_string(argv[i])); } + G.expanded_assignments = NULL; return p; } @@ -4316,6 +4335,27 @@ static int checkjobs_and_fg_shell(struct pipe* fg_pipe) * backgrounded: cmd & { list } & * subshell: ( list ) [&] */ +#if !ENABLE_HUSH_MODE_X +#define redirect_and_varexp_helper(new_env_p, old_vars_p, command, squirrel, char argv_expanded) \ + redirect_and_varexp_helper(new_env_p, old_vars_p, command, squirrel) +#endif +static int redirect_and_varexp_helper(char ***new_env_p, struct variable **old_vars_p, struct command *command, int squirrel[3], char **argv_expanded) +{ + /* setup_redirects acts on file descriptors, not FILEs. + * This is perfect for work that comes after exec(). + * Is it really safe for inline use? Experimentally, + * things seem to work. */ + int rcode = setup_redirects(command, squirrel); + if (rcode == 0) { + char **new_env = expand_assignments(command->argv, command->assignment_cnt); + *new_env_p = new_env; + dump_cmd_in_x_mode(new_env); + dump_cmd_in_x_mode(argv_expanded); + if (old_vars_p) + *old_vars_p = set_vars_and_save_old(new_env); + } + return rcode; +} static NOINLINE int run_pipe(struct pipe *pi) { static const char *const null_ptr = NULL; @@ -4325,7 +4365,6 @@ static NOINLINE int run_pipe(struct pipe *pi) struct command *command; char **argv_expanded; char **argv; - char *p; /* it is not always needed, but we aim to smaller code */ int squirrel[] = { -1, -1, -1 }; int rcode; @@ -4402,19 +4441,45 @@ static NOINLINE int run_pipe(struct pipe *pi) if (argv[command->assignment_cnt] == NULL) { /* Assignments, but no command */ /* Ensure redirects take effect (that is, create files). - * Try "a=t >file": */ + * Try "a=t >file" */ +#if 0 /* A few cases in testsuite fail with this code. FIXME */ + rcode = redirect_and_varexp_helper(&new_env, /*old_vars:*/ NULL, command, squirrel, /*argv_expanded:*/ NULL); + /* Set shell variables */ + if (new_env) { + argv = new_env; + while (*argv) { + set_local_var(*argv, /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ 0); + /* Do we need to flag set_local_var() errors? + * "assignment to readonly var" and "putenv error" + */ + argv++; + } + } + /* Redirect error sets $? to 1. Otherwise, + * if evaluating assignment value set $?, retain it. + * Try "false; q=`exit 2`; echo $?" - should print 2: */ + if (rcode == 0) + rcode = G.last_exitcode; + /* Exit, _skipping_ variable restoring code: */ + goto clean_up_and_ret0; + +#else /* Older, bigger, but more correct code */ + rcode = setup_redirects(command, squirrel); restore_redirects(squirrel); /* Set shell variables */ if (G_x_mode) bb_putchar_stderr('+'); while (*argv) { - p = expand_string_to_string(*argv); + char *p = expand_string_to_string(*argv); if (G_x_mode) fprintf(stderr, " %s", p); debug_printf_exec("set shell var:'%s'->'%s'\n", *argv, p); set_local_var(p, /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ 0); + /* Do we need to flag set_local_var() errors? + * "assignment to readonly var" and "putenv error" + */ argv++; } if (G_x_mode) @@ -4424,13 +4489,11 @@ static NOINLINE int run_pipe(struct pipe *pi) * Try "false; q=`exit 2`; echo $?" - should print 2: */ if (rcode == 0) rcode = G.last_exitcode; - /* Do we need to flag set_local_var() errors? - * "assignment to readonly var" and "putenv error" - */ IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;) debug_leave(); debug_printf_exec("run_pipe: return %d\n", rcode); return rcode; +#endif } /* Expand the rest into (possibly) many strings each */ @@ -4471,16 +4534,8 @@ static NOINLINE int run_pipe(struct pipe *pi) goto clean_up_and_ret1; } } - /* setup_redirects acts on file descriptors, not FILEs. - * This is perfect for work that comes after exec(). - * Is it really safe for inline use? Experimentally, - * things seem to work. */ - rcode = setup_redirects(command, squirrel); + rcode = redirect_and_varexp_helper(&new_env, &old_vars, command, squirrel, argv_expanded); if (rcode == 0) { - new_env = expand_assignments(argv, command->assignment_cnt); - dump_cmd_in_x_mode(new_env); - dump_cmd_in_x_mode(argv_expanded); - old_vars = set_vars_and_save_old(new_env); if (!funcp) { debug_printf_exec(": builtin '%s' '%s'...\n", x->b_cmd, argv_expanded[1]); @@ -4504,9 +4559,10 @@ static NOINLINE int run_pipe(struct pipe *pi) #endif } clean_up_and_ret: - restore_redirects(squirrel); unset_vars(new_env); add_vars(old_vars); +/* clean_up_and_ret0: */ + restore_redirects(squirrel); clean_up_and_ret1: free(argv_expanded); IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;) @@ -4518,12 +4574,8 @@ static NOINLINE int run_pipe(struct pipe *pi) if (ENABLE_FEATURE_SH_STANDALONE) { int n = find_applet_by_name(argv_expanded[0]); if (n >= 0 && APPLET_IS_NOFORK(n)) { - rcode = setup_redirects(command, squirrel); + rcode = redirect_and_varexp_helper(&new_env, &old_vars, command, squirrel, argv_expanded); if (rcode == 0) { - new_env = expand_assignments(argv, command->assignment_cnt); - dump_cmd_in_x_mode(new_env); - dump_cmd_in_x_mode(argv_expanded); - old_vars = set_vars_and_save_old(new_env); debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv_expanded[0], argv_expanded[1]); rcode = run_nofork_applet(n, argv_expanded); diff --git a/shell/hush_test/hush-vars/var_serial.right b/shell/hush_test/hush-vars/var_serial.right new file mode 100644 index 000000000..42aa33057 --- /dev/null +++ b/shell/hush_test/hush-vars/var_serial.right @@ -0,0 +1,5 @@ +Assignments only: c=a +Assignments and a command: c=a +Assignments and a builtin: c=a +Assignments and a function: c=a +Done diff --git a/shell/hush_test/hush-vars/var_serial.tests b/shell/hush_test/hush-vars/var_serial.tests new file mode 100755 index 000000000..6b4a4cdf7 --- /dev/null +++ b/shell/hush_test/hush-vars/var_serial.tests @@ -0,0 +1,22 @@ +a=a + +b=b +c=c +# Second assignment depends on the first: +b=$a c=$b +echo Assignments only: c=$c + +b=b +c=c +b=$a c=$b "$THIS_SH" -c 'echo Assignments and a command: c=$c' + +b=b +c=c +b=$a c=$b eval 'echo Assignments and a builtin: c=$c' + +b=b +c=c +f() { echo Assignments and a function: c=$c; } +b=$a c=$b f + +echo Done -- cgit v1.2.3-55-g6feb