diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2009-10-08 03:06:04 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2009-10-08 03:06:04 +0200 |
commit | 4ac9819263114edb9b5b638ffa6d2e41a4bb46e7 (patch) | |
tree | f0c5bc9c7a2bf3a384b85350bfe4c9ca5ec4858f | |
parent | 5b807cd5acd1f27b3e7aa36aac2728be27c5907c (diff) | |
download | busybox-w32-4ac9819263114edb9b5b638ffa6d2e41a4bb46e7.tar.gz busybox-w32-4ac9819263114edb9b5b638ffa6d2e41a4bb46e7.tar.bz2 busybox-w32-4ac9819263114edb9b5b638ffa6d2e41a4bb46e7.zip |
apply post-1.15.1 fixes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | coreutils/dd.c | 11 | ||||
-rw-r--r-- | coreutils/uniq.c | 1 | ||||
-rw-r--r-- | editors/sed.c | 4 | ||||
-rw-r--r-- | findutils/find.c | 68 | ||||
-rw-r--r-- | include/libbb.h | 2 | ||||
-rw-r--r-- | libbb/lineedit.c | 49 | ||||
-rw-r--r-- | libbb/procps.c | 133 | ||||
-rw-r--r-- | libbb/recursive_action.c | 17 | ||||
-rw-r--r-- | miscutils/hdparm.c | 3 | ||||
-rw-r--r-- | shell/ash.c | 418 | ||||
-rw-r--r-- | shell/ash_test/ash-redir/redir7.right | 3 | ||||
-rwxr-xr-x | shell/ash_test/ash-redir/redir7.tests | 12 | ||||
-rw-r--r-- | shell/ash_test/ash-redir/redir8.right | 3 | ||||
-rwxr-xr-x | shell/ash_test/ash-redir/redir8.tests | 15 | ||||
-rw-r--r-- | shell/ash_test/ash-signals/savetrap.right | 8 | ||||
-rwxr-xr-x | shell/ash_test/ash-signals/savetrap.tests | 9 | ||||
-rw-r--r-- | shell/hush.c | 188 | ||||
-rw-r--r-- | shell/hush_test/hush-trap/savetrap.right | 8 | ||||
-rwxr-xr-x | shell/hush_test/hush-trap/savetrap.tests | 9 | ||||
-rw-r--r-- | shell/hush_test/hush-trap/subshell.right | 6 | ||||
-rwxr-xr-x | shell/hush_test/hush-trap/subshell.tests | 20 | ||||
-rw-r--r-- | util-linux/fdisk.c | 5 |
22 files changed, 636 insertions, 356 deletions
diff --git a/coreutils/dd.c b/coreutils/dd.c index 5281d8118..381f60075 100644 --- a/coreutils/dd.c +++ b/coreutils/dd.c | |||
@@ -286,25 +286,26 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
286 | } | 286 | } |
287 | 287 | ||
288 | while (!(flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) { | 288 | while (!(flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) { |
289 | if (flags & FLAG_NOERROR) /* Pre-zero the buffer if conv=noerror */ | ||
290 | memset(ibuf, 0, ibs); | ||
291 | n = safe_read(ifd, ibuf, ibs); | 289 | n = safe_read(ifd, ibuf, ibs); |
292 | if (n == 0) | 290 | if (n == 0) |
293 | break; | 291 | break; |
294 | if (n < 0) { | 292 | if (n < 0) { |
293 | /* "Bad block" */ | ||
295 | if (!(flags & FLAG_NOERROR)) | 294 | if (!(flags & FLAG_NOERROR)) |
296 | goto die_infile; | 295 | goto die_infile; |
297 | n = ibs; | ||
298 | bb_simple_perror_msg(infile); | 296 | bb_simple_perror_msg(infile); |
299 | /* GNU dd with conv=noerror skips over "bad blocks" */ | 297 | /* GNU dd with conv=noerror skips over bad blocks */ |
300 | xlseek(ifd, ibs, SEEK_CUR); | 298 | xlseek(ifd, ibs, SEEK_CUR); |
299 | /* conv=noerror,sync writes NULs, | ||
300 | * conv=noerror just ignores input bad blocks */ | ||
301 | n = 0; | ||
301 | } | 302 | } |
302 | if ((size_t)n == ibs) | 303 | if ((size_t)n == ibs) |
303 | G.in_full++; | 304 | G.in_full++; |
304 | else { | 305 | else { |
305 | G.in_part++; | 306 | G.in_part++; |
306 | if (flags & FLAG_SYNC) { | 307 | if (flags & FLAG_SYNC) { |
307 | memset(ibuf + n, '\0', ibs - n); | 308 | memset(ibuf + n, 0, ibs - n); |
308 | n = ibs; | 309 | n = ibs; |
309 | } | 310 | } |
310 | } | 311 | } |
diff --git a/coreutils/uniq.c b/coreutils/uniq.c index 126eaeef9..e703659c6 100644 --- a/coreutils/uniq.c +++ b/coreutils/uniq.c | |||
@@ -84,6 +84,7 @@ int uniq_main(int argc UNUSED_PARAM, char **argv) | |||
84 | break; | 84 | break; |
85 | } | 85 | } |
86 | 86 | ||
87 | free((char*)s1); | ||
87 | ++dups; /* note: testing for overflow seems excessive. */ | 88 | ++dups; /* note: testing for overflow seems excessive. */ |
88 | } | 89 | } |
89 | 90 | ||
diff --git a/editors/sed.c b/editors/sed.c index 8b4f60a8c..3f044caef 100644 --- a/editors/sed.c +++ b/editors/sed.c | |||
@@ -690,10 +690,8 @@ static int do_subst_command(sed_cmd_t *sed_cmd, char **line_p) | |||
690 | if (sed_cmd->which_match) | 690 | if (sed_cmd->which_match) |
691 | break; | 691 | break; |
692 | 692 | ||
693 | if (*line == '\0') | ||
694 | break; | ||
695 | //maybe (G.regmatch[0].rm_eo ? REG_NOTBOL : 0) instead of unconditional REG_NOTBOL? | 693 | //maybe (G.regmatch[0].rm_eo ? REG_NOTBOL : 0) instead of unconditional REG_NOTBOL? |
696 | } while (regexec(current_regex, line, 10, G.regmatch, REG_NOTBOL) != REG_NOMATCH); | 694 | } while (*line && regexec(current_regex, line, 10, G.regmatch, REG_NOTBOL) != REG_NOMATCH); |
697 | 695 | ||
698 | /* Copy rest of string into output pipeline */ | 696 | /* Copy rest of string into output pipeline */ |
699 | while (1) { | 697 | while (1) { |
diff --git a/findutils/find.c b/findutils/find.c index 5e8193ffa..ff239dbdd 100644 --- a/findutils/find.c +++ b/findutils/find.c | |||
@@ -62,9 +62,6 @@ | |||
62 | /* This is a NOEXEC applet. Be very careful! */ | 62 | /* This is a NOEXEC applet. Be very careful! */ |
63 | 63 | ||
64 | 64 | ||
65 | IF_FEATURE_FIND_XDEV(static dev_t *xdev_dev;) | ||
66 | IF_FEATURE_FIND_XDEV(static int xdev_count;) | ||
67 | |||
68 | typedef int (*action_fp)(const char *fileName, struct stat *statbuf, void *) FAST_FUNC; | 65 | typedef int (*action_fp)(const char *fileName, struct stat *statbuf, void *) FAST_FUNC; |
69 | 66 | ||
70 | typedef struct { | 67 | typedef struct { |
@@ -100,9 +97,24 @@ IF_FEATURE_FIND_DELETE( ACTS(delete)) | |||
100 | IF_FEATURE_FIND_EXEC( ACTS(exec, char **exec_argv; unsigned *subst_count; int exec_argc;)) | 97 | IF_FEATURE_FIND_EXEC( ACTS(exec, char **exec_argv; unsigned *subst_count; int exec_argc;)) |
101 | IF_FEATURE_FIND_GROUP( ACTS(group, gid_t gid;)) | 98 | IF_FEATURE_FIND_GROUP( ACTS(group, gid_t gid;)) |
102 | 99 | ||
103 | static action ***actions; | 100 | struct globals { |
104 | static bool need_print = 1; | 101 | IF_FEATURE_FIND_XDEV(dev_t *xdev_dev;) |
105 | static int recurse_flags = ACTION_RECURSE; | 102 | IF_FEATURE_FIND_XDEV(int xdev_count;) |
103 | action ***actions; | ||
104 | bool need_print; | ||
105 | recurse_flags_t recurse_flags; | ||
106 | }; | ||
107 | #define G (*(struct globals*)&bb_common_bufsiz1) | ||
108 | #define INIT_G() do { \ | ||
109 | struct G_sizecheck { \ | ||
110 | char G_sizecheck[sizeof(G) > COMMON_BUFSIZE ? -1 : 1]; \ | ||
111 | }; \ | ||
112 | IF_FEATURE_FIND_XDEV(G.xdev_dev = NULL;) \ | ||
113 | IF_FEATURE_FIND_XDEV(G.xdev_count = 0;) \ | ||
114 | G.actions = NULL; \ | ||
115 | G.need_print = 1; \ | ||
116 | G.recurse_flags = ACTION_RECURSE; \ | ||
117 | } while (0) | ||
106 | 118 | ||
107 | #if ENABLE_FEATURE_FIND_EXEC | 119 | #if ENABLE_FEATURE_FIND_EXEC |
108 | static unsigned count_subst(const char *str) | 120 | static unsigned count_subst(const char *str) |
@@ -363,7 +375,7 @@ ACTF(context) | |||
363 | security_context_t con; | 375 | security_context_t con; |
364 | int rc; | 376 | int rc; |
365 | 377 | ||
366 | if (recurse_flags & ACTION_FOLLOWLINKS) { | 378 | if (G.recurse_flags & ACTION_FOLLOWLINKS) { |
367 | rc = getfilecon(fileName, &con); | 379 | rc = getfilecon(fileName, &con); |
368 | } else { | 380 | } else { |
369 | rc = lgetfilecon(fileName, &con); | 381 | rc = lgetfilecon(fileName, &con); |
@@ -392,18 +404,18 @@ static int FAST_FUNC fileAction(const char *fileName, | |||
392 | #endif | 404 | #endif |
393 | 405 | ||
394 | #if ENABLE_FEATURE_FIND_XDEV | 406 | #if ENABLE_FEATURE_FIND_XDEV |
395 | if (S_ISDIR(statbuf->st_mode) && xdev_count) { | 407 | if (S_ISDIR(statbuf->st_mode) && G.xdev_count) { |
396 | for (i = 0; i < xdev_count; i++) { | 408 | for (i = 0; i < G.xdev_count; i++) { |
397 | if (xdev_dev[i] == statbuf->st_dev) | 409 | if (G.xdev_dev[i] == statbuf->st_dev) |
398 | break; | 410 | break; |
399 | } | 411 | } |
400 | if (i == xdev_count) | 412 | if (i == G.xdev_count) |
401 | return SKIP; | 413 | return SKIP; |
402 | } | 414 | } |
403 | #endif | 415 | #endif |
404 | i = exec_actions(actions, fileName, statbuf); | 416 | i = exec_actions(G.actions, fileName, statbuf); |
405 | /* Had no explicit -print[0] or -exec? then print */ | 417 | /* Had no explicit -print[0] or -exec? then print */ |
406 | if ((i & TRUE) && need_print) | 418 | if ((i & TRUE) && G.need_print) |
407 | puts(fileName); | 419 | puts(fileName); |
408 | /* Cannot return 0: our caller, recursive_action(), | 420 | /* Cannot return 0: our caller, recursive_action(), |
409 | * will perror() and skip dirs (if called on dir) */ | 421 | * will perror() and skip dirs (if called on dir) */ |
@@ -431,7 +443,7 @@ static int find_type(const char *type) | |||
431 | else if (*type == 's') | 443 | else if (*type == 's') |
432 | mask = S_IFSOCK; | 444 | mask = S_IFSOCK; |
433 | 445 | ||
434 | if (mask == 0 || *(type + 1) != '\0') | 446 | if (mask == 0 || type[1] != '\0') |
435 | bb_error_msg_and_die(bb_msg_invalid_arg, type, "-type"); | 447 | bb_error_msg_and_die(bb_msg_invalid_arg, type, "-type"); |
436 | 448 | ||
437 | return mask; | 449 | return mask; |
@@ -592,21 +604,21 @@ static action*** parse_params(char **argv) | |||
592 | 604 | ||
593 | /* --- Tests and actions --- */ | 605 | /* --- Tests and actions --- */ |
594 | else if (parm == PARM_print) { | 606 | else if (parm == PARM_print) { |
595 | need_print = 0; | 607 | G.need_print = 0; |
596 | /* GNU find ignores '!' here: "find ! -print" */ | 608 | /* GNU find ignores '!' here: "find ! -print" */ |
597 | IF_FEATURE_FIND_NOT( invert_flag = 0; ) | 609 | IF_FEATURE_FIND_NOT( invert_flag = 0; ) |
598 | (void) ALLOC_ACTION(print); | 610 | (void) ALLOC_ACTION(print); |
599 | } | 611 | } |
600 | #if ENABLE_FEATURE_FIND_PRINT0 | 612 | #if ENABLE_FEATURE_FIND_PRINT0 |
601 | else if (parm == PARM_print0) { | 613 | else if (parm == PARM_print0) { |
602 | need_print = 0; | 614 | G.need_print = 0; |
603 | IF_FEATURE_FIND_NOT( invert_flag = 0; ) | 615 | IF_FEATURE_FIND_NOT( invert_flag = 0; ) |
604 | (void) ALLOC_ACTION(print0); | 616 | (void) ALLOC_ACTION(print0); |
605 | } | 617 | } |
606 | #endif | 618 | #endif |
607 | #if ENABLE_FEATURE_FIND_DEPTH | 619 | #if ENABLE_FEATURE_FIND_DEPTH |
608 | else if (parm == PARM_depth) { | 620 | else if (parm == PARM_depth) { |
609 | recurse_flags |= ACTION_DEPTHFIRST; | 621 | G.recurse_flags |= ACTION_DEPTHFIRST; |
610 | } | 622 | } |
611 | #endif | 623 | #endif |
612 | #if ENABLE_FEATURE_FIND_PRUNE | 624 | #if ENABLE_FEATURE_FIND_PRUNE |
@@ -617,8 +629,8 @@ static action*** parse_params(char **argv) | |||
617 | #endif | 629 | #endif |
618 | #if ENABLE_FEATURE_FIND_DELETE | 630 | #if ENABLE_FEATURE_FIND_DELETE |
619 | else if (parm == PARM_delete) { | 631 | else if (parm == PARM_delete) { |
620 | need_print = 0; | 632 | G.need_print = 0; |
621 | recurse_flags |= ACTION_DEPTHFIRST; | 633 | G.recurse_flags |= ACTION_DEPTHFIRST; |
622 | (void) ALLOC_ACTION(delete); | 634 | (void) ALLOC_ACTION(delete); |
623 | } | 635 | } |
624 | #endif | 636 | #endif |
@@ -626,7 +638,7 @@ static action*** parse_params(char **argv) | |||
626 | else if (parm == PARM_exec) { | 638 | else if (parm == PARM_exec) { |
627 | int i; | 639 | int i; |
628 | action_exec *ap; | 640 | action_exec *ap; |
629 | need_print = 0; | 641 | G.need_print = 0; |
630 | IF_FEATURE_FIND_NOT( invert_flag = 0; ) | 642 | IF_FEATURE_FIND_NOT( invert_flag = 0; ) |
631 | ap = ALLOC_ACTION(exec); | 643 | ap = ALLOC_ACTION(exec); |
632 | ap->exec_argv = ++argv; /* first arg after -exec */ | 644 | ap->exec_argv = ++argv; /* first arg after -exec */ |
@@ -834,6 +846,8 @@ IF_FEATURE_FIND_MAXDEPTH(OPT_MINDEPTH,) | |||
834 | #define minmaxdepth NULL | 846 | #define minmaxdepth NULL |
835 | #endif | 847 | #endif |
836 | 848 | ||
849 | INIT_G(); | ||
850 | |||
837 | for (firstopt = 1; firstopt < argc; firstopt++) { | 851 | for (firstopt = 1; firstopt < argc; firstopt++) { |
838 | if (argv[firstopt][0] == '-') | 852 | if (argv[firstopt][0] == '-') |
839 | break; | 853 | break; |
@@ -861,21 +875,21 @@ IF_FEATURE_FIND_MAXDEPTH(OPT_MINDEPTH,) | |||
861 | while ((arg = argp[0])) { | 875 | while ((arg = argp[0])) { |
862 | int opt = index_in_strings(options, arg); | 876 | int opt = index_in_strings(options, arg); |
863 | if (opt == OPT_FOLLOW) { | 877 | if (opt == OPT_FOLLOW) { |
864 | recurse_flags |= ACTION_FOLLOWLINKS; | 878 | G.recurse_flags |= ACTION_FOLLOWLINKS | ACTION_DANGLING_OK; |
865 | argp[0] = (char*)"-a"; | 879 | argp[0] = (char*)"-a"; |
866 | } | 880 | } |
867 | #if ENABLE_FEATURE_FIND_XDEV | 881 | #if ENABLE_FEATURE_FIND_XDEV |
868 | if (opt == OPT_XDEV) { | 882 | if (opt == OPT_XDEV) { |
869 | struct stat stbuf; | 883 | struct stat stbuf; |
870 | if (!xdev_count) { | 884 | if (!G.xdev_count) { |
871 | xdev_count = firstopt - 1; | 885 | G.xdev_count = firstopt - 1; |
872 | xdev_dev = xmalloc(xdev_count * sizeof(dev_t)); | 886 | G.xdev_dev = xmalloc(G.xdev_count * sizeof(dev_t)); |
873 | for (i = 1; i < firstopt; i++) { | 887 | for (i = 1; i < firstopt; i++) { |
874 | /* not xstat(): shouldn't bomb out on | 888 | /* not xstat(): shouldn't bomb out on |
875 | * "find not_exist exist -xdev" */ | 889 | * "find not_exist exist -xdev" */ |
876 | if (stat(argv[i], &stbuf)) | 890 | if (stat(argv[i], &stbuf)) |
877 | stbuf.st_dev = -1L; | 891 | stbuf.st_dev = -1L; |
878 | xdev_dev[i-1] = stbuf.st_dev; | 892 | G.xdev_dev[i-1] = stbuf.st_dev; |
879 | } | 893 | } |
880 | } | 894 | } |
881 | argp[0] = (char*)"-a"; | 895 | argp[0] = (char*)"-a"; |
@@ -894,11 +908,11 @@ IF_FEATURE_FIND_MAXDEPTH(OPT_MINDEPTH,) | |||
894 | argp++; | 908 | argp++; |
895 | } | 909 | } |
896 | 910 | ||
897 | actions = parse_params(&argv[firstopt]); | 911 | G.actions = parse_params(&argv[firstopt]); |
898 | 912 | ||
899 | for (i = 1; i < firstopt; i++) { | 913 | for (i = 1; i < firstopt; i++) { |
900 | if (!recursive_action(argv[i], | 914 | if (!recursive_action(argv[i], |
901 | recurse_flags, /* flags */ | 915 | G.recurse_flags,/* flags */ |
902 | fileAction, /* file action */ | 916 | fileAction, /* file action */ |
903 | fileAction, /* dir action */ | 917 | fileAction, /* dir action */ |
904 | #if ENABLE_FEATURE_FIND_MAXDEPTH | 918 | #if ENABLE_FEATURE_FIND_MAXDEPTH |
diff --git a/include/libbb.h b/include/libbb.h index c795e6aad..104a39904 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -286,7 +286,9 @@ enum { | |||
286 | ACTION_DEPTHFIRST = (1 << 3), | 286 | ACTION_DEPTHFIRST = (1 << 3), |
287 | /*ACTION_REVERSE = (1 << 4), - unused */ | 287 | /*ACTION_REVERSE = (1 << 4), - unused */ |
288 | ACTION_QUIET = (1 << 5), | 288 | ACTION_QUIET = (1 << 5), |
289 | ACTION_DANGLING_OK = (1 << 6), | ||
289 | }; | 290 | }; |
291 | typedef uint8_t recurse_flags_t; | ||
290 | extern int recursive_action(const char *fileName, unsigned flags, | 292 | extern int recursive_action(const char *fileName, unsigned flags, |
291 | int FAST_FUNC (*fileAction)(const char *fileName, struct stat* statbuf, void* userData, int depth), | 293 | int FAST_FUNC (*fileAction)(const char *fileName, struct stat* statbuf, void* userData, int depth), |
292 | int FAST_FUNC (*dirAction)(const char *fileName, struct stat* statbuf, void* userData, int depth), | 294 | int FAST_FUNC (*dirAction)(const char *fileName, struct stat* statbuf, void* userData, int depth), |
diff --git a/libbb/lineedit.c b/libbb/lineedit.c index 9a773b4b8..071fc5bce 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c | |||
@@ -114,8 +114,8 @@ struct lineedit_statics { | |||
114 | unsigned cmdedit_prmt_len; /* length of prompt (without colors etc) */ | 114 | unsigned cmdedit_prmt_len; /* length of prompt (without colors etc) */ |
115 | 115 | ||
116 | unsigned cursor; | 116 | unsigned cursor; |
117 | unsigned command_len; | 117 | int command_len; /* must be signed (^D returns -1 len) */ |
118 | /* *int* maxsize: we want x in "if (x > S.maxsize)" | 118 | /* signed maxsize: we want x in "if (x > S.maxsize)" |
119 | * to _not_ be promoted to unsigned */ | 119 | * to _not_ be promoted to unsigned */ |
120 | int maxsize; | 120 | int maxsize; |
121 | CHAR_T *command_ps; | 121 | CHAR_T *command_ps; |
@@ -1095,15 +1095,15 @@ static void save_command_ps_at_cur_history(void) | |||
1095 | int cur = state->cur_history; | 1095 | int cur = state->cur_history; |
1096 | free(state->history[cur]); | 1096 | free(state->history[cur]); |
1097 | 1097 | ||
1098 | #if ENABLE_FEATURE_ASSUME_UNICODE | 1098 | # if ENABLE_FEATURE_ASSUME_UNICODE |
1099 | { | 1099 | { |
1100 | char tbuf[MAX_LINELEN]; | 1100 | char tbuf[MAX_LINELEN]; |
1101 | save_string(tbuf, sizeof(tbuf)); | 1101 | save_string(tbuf, sizeof(tbuf)); |
1102 | state->history[cur] = xstrdup(tbuf); | 1102 | state->history[cur] = xstrdup(tbuf); |
1103 | } | 1103 | } |
1104 | #else | 1104 | # else |
1105 | state->history[cur] = xstrdup(command_ps); | 1105 | state->history[cur] = xstrdup(command_ps); |
1106 | #endif | 1106 | # endif |
1107 | } | 1107 | } |
1108 | } | 1108 | } |
1109 | 1109 | ||
@@ -1131,7 +1131,7 @@ static int get_next_history(void) | |||
1131 | return 0; | 1131 | return 0; |
1132 | } | 1132 | } |
1133 | 1133 | ||
1134 | #if ENABLE_FEATURE_EDITING_SAVEHISTORY | 1134 | # if ENABLE_FEATURE_EDITING_SAVEHISTORY |
1135 | /* We try to ensure that concurrent additions to the history | 1135 | /* We try to ensure that concurrent additions to the history |
1136 | * do not overwrite each other. | 1136 | * do not overwrite each other. |
1137 | * Otherwise shell users get unhappy. | 1137 | * Otherwise shell users get unhappy. |
@@ -1256,10 +1256,10 @@ static void save_history(char *str) | |||
1256 | free_line_input_t(st_temp); | 1256 | free_line_input_t(st_temp); |
1257 | } | 1257 | } |
1258 | } | 1258 | } |
1259 | #else | 1259 | # else |
1260 | #define load_history(a) ((void)0) | 1260 | # define load_history(a) ((void)0) |
1261 | #define save_history(a) ((void)0) | 1261 | # define save_history(a) ((void)0) |
1262 | #endif /* FEATURE_COMMAND_SAVEHISTORY */ | 1262 | # endif /* FEATURE_COMMAND_SAVEHISTORY */ |
1263 | 1263 | ||
1264 | static void remember_in_history(char *str) | 1264 | static void remember_in_history(char *str) |
1265 | { | 1265 | { |
@@ -1290,15 +1290,15 @@ static void remember_in_history(char *str) | |||
1290 | /* i <= MAX_HISTORY */ | 1290 | /* i <= MAX_HISTORY */ |
1291 | state->cur_history = i; | 1291 | state->cur_history = i; |
1292 | state->cnt_history = i; | 1292 | state->cnt_history = i; |
1293 | #if ENABLE_FEATURE_EDITING_SAVEHISTORY | 1293 | # if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY |
1294 | if ((state->flags & SAVE_HISTORY) && state->hist_file) | 1294 | if ((state->flags & SAVE_HISTORY) && state->hist_file) |
1295 | save_history(str); | 1295 | save_history(str); |
1296 | #endif | 1296 | # endif |
1297 | IF_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines++;) | 1297 | IF_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines++;) |
1298 | } | 1298 | } |
1299 | 1299 | ||
1300 | #else /* MAX_HISTORY == 0 */ | 1300 | #else /* MAX_HISTORY == 0 */ |
1301 | #define remember_in_history(a) ((void)0) | 1301 | # define remember_in_history(a) ((void)0) |
1302 | #endif /* MAX_HISTORY */ | 1302 | #endif /* MAX_HISTORY */ |
1303 | 1303 | ||
1304 | 1304 | ||
@@ -1476,11 +1476,11 @@ static void parse_and_put_prompt(const char *prmt_ptr) | |||
1476 | c = *prmt_ptr++; | 1476 | c = *prmt_ptr++; |
1477 | 1477 | ||
1478 | switch (c) { | 1478 | switch (c) { |
1479 | #if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR | 1479 | # if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR |
1480 | case 'u': | 1480 | case 'u': |
1481 | pbuf = user_buf ? user_buf : (char*)""; | 1481 | pbuf = user_buf ? user_buf : (char*)""; |
1482 | break; | 1482 | break; |
1483 | #endif | 1483 | # endif |
1484 | case 'h': | 1484 | case 'h': |
1485 | pbuf = free_me = safe_gethostname(); | 1485 | pbuf = free_me = safe_gethostname(); |
1486 | *strchrnul(pbuf, '.') = '\0'; | 1486 | *strchrnul(pbuf, '.') = '\0'; |
@@ -1488,7 +1488,7 @@ static void parse_and_put_prompt(const char *prmt_ptr) | |||
1488 | case '$': | 1488 | case '$': |
1489 | c = (geteuid() == 0 ? '#' : '$'); | 1489 | c = (geteuid() == 0 ? '#' : '$'); |
1490 | break; | 1490 | break; |
1491 | #if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR | 1491 | # if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR |
1492 | case 'w': | 1492 | case 'w': |
1493 | /* /home/user[/something] -> ~[/something] */ | 1493 | /* /home/user[/something] -> ~[/something] */ |
1494 | pbuf = cwd_buf; | 1494 | pbuf = cwd_buf; |
@@ -1501,7 +1501,7 @@ static void parse_and_put_prompt(const char *prmt_ptr) | |||
1501 | pbuf = free_me = xasprintf("~%s", cwd_buf + l); | 1501 | pbuf = free_me = xasprintf("~%s", cwd_buf + l); |
1502 | } | 1502 | } |
1503 | break; | 1503 | break; |
1504 | #endif | 1504 | # endif |
1505 | case 'W': | 1505 | case 'W': |
1506 | pbuf = cwd_buf; | 1506 | pbuf = cwd_buf; |
1507 | cp = strrchr(pbuf, '/'); | 1507 | cp = strrchr(pbuf, '/'); |
@@ -1688,13 +1688,15 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li | |||
1688 | 1688 | ||
1689 | /* With null flags, no other fields are ever used */ | 1689 | /* With null flags, no other fields are ever used */ |
1690 | state = st ? st : (line_input_t*) &const_int_0; | 1690 | state = st ? st : (line_input_t*) &const_int_0; |
1691 | #if ENABLE_FEATURE_EDITING_SAVEHISTORY | 1691 | #if MAX_HISTORY > 0 |
1692 | # if ENABLE_FEATURE_EDITING_SAVEHISTORY | ||
1692 | if ((state->flags & SAVE_HISTORY) && state->hist_file) | 1693 | if ((state->flags & SAVE_HISTORY) && state->hist_file) |
1693 | if (state->cnt_history == 0) | 1694 | if (state->cnt_history == 0) |
1694 | load_history(state); | 1695 | load_history(state); |
1695 | #endif | 1696 | # endif |
1696 | if (state->flags & DO_HISTORY) | 1697 | if (state->flags & DO_HISTORY) |
1697 | state->cur_history = state->cnt_history; | 1698 | state->cur_history = state->cnt_history; |
1699 | #endif | ||
1698 | 1700 | ||
1699 | /* prepare before init handlers */ | 1701 | /* prepare before init handlers */ |
1700 | cmdedit_y = 0; /* quasireal y, not true if line > xt*yt */ | 1702 | cmdedit_y = 0; /* quasireal y, not true if line > xt*yt */ |
@@ -1716,7 +1718,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li | |||
1716 | new_settings.c_cc[VTIME] = 0; | 1718 | new_settings.c_cc[VTIME] = 0; |
1717 | /* Turn off CTRL-C, so we can trap it */ | 1719 | /* Turn off CTRL-C, so we can trap it */ |
1718 | #ifndef _POSIX_VDISABLE | 1720 | #ifndef _POSIX_VDISABLE |
1719 | #define _POSIX_VDISABLE '\0' | 1721 | # define _POSIX_VDISABLE '\0' |
1720 | #endif | 1722 | #endif |
1721 | new_settings.c_cc[VINTR] = _POSIX_VDISABLE; | 1723 | new_settings.c_cc[VINTR] = _POSIX_VDISABLE; |
1722 | tcsetattr_stdin_TCSANOW(&new_settings); | 1724 | tcsetattr_stdin_TCSANOW(&new_settings); |
@@ -2037,7 +2039,8 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li | |||
2037 | rewrite_line: | 2039 | rewrite_line: |
2038 | /* Rewrite the line with the selected history item */ | 2040 | /* Rewrite the line with the selected history item */ |
2039 | /* change command */ | 2041 | /* change command */ |
2040 | command_len = load_string(state->history[state->cur_history] ? : "", maxsize); | 2042 | command_len = load_string(state->history[state->cur_history] ? |
2043 | state->history[state->cur_history] : "", maxsize); | ||
2041 | /* redraw and go to eol (bol, in vi) */ | 2044 | /* redraw and go to eol (bol, in vi) */ |
2042 | redraw(cmdedit_y, (state->flags & VI_MODE) ? 9999 : 0); | 2045 | redraw(cmdedit_y, (state->flags & VI_MODE) ? 9999 : 0); |
2043 | break; | 2046 | break; |
@@ -2121,7 +2124,9 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li | |||
2121 | #undef command | 2124 | #undef command |
2122 | 2125 | ||
2123 | #if ENABLE_FEATURE_ASSUME_UNICODE | 2126 | #if ENABLE_FEATURE_ASSUME_UNICODE |
2124 | command_len = save_string(command, maxsize - 1); | 2127 | command[0] = '\0'; |
2128 | if (command_len > 0) | ||
2129 | command_len = save_string(command, maxsize - 1); | ||
2125 | free(command_ps); | 2130 | free(command_ps); |
2126 | #endif | 2131 | #endif |
2127 | 2132 | ||
diff --git a/libbb/procps.c b/libbb/procps.c index 307d8d622..7276f60ef 100644 --- a/libbb/procps.c +++ b/libbb/procps.c | |||
@@ -134,8 +134,8 @@ static unsigned long fast_strtoul_16(char **endptr) | |||
134 | return n; | 134 | return n; |
135 | } | 135 | } |
136 | /* TOPMEM uses fast_strtoul_10, so... */ | 136 | /* TOPMEM uses fast_strtoul_10, so... */ |
137 | #undef ENABLE_FEATURE_FAST_TOP | 137 | # undef ENABLE_FEATURE_FAST_TOP |
138 | #define ENABLE_FEATURE_FAST_TOP 1 | 138 | # define ENABLE_FEATURE_FAST_TOP 1 |
139 | #endif | 139 | #endif |
140 | 140 | ||
141 | #if ENABLE_FEATURE_FAST_TOP | 141 | #if ENABLE_FEATURE_FAST_TOP |
@@ -198,14 +198,16 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |||
198 | if (errno) | 198 | if (errno) |
199 | continue; | 199 | continue; |
200 | 200 | ||
201 | /* After this point we have to break, not continue | 201 | /* After this point we can: |
202 | * ("continue" would mean that current /proc/NNN | 202 | * "break": stop parsing, return the data |
203 | * is not a valid process info) */ | 203 | * "continue": try next /proc/XXX |
204 | */ | ||
204 | 205 | ||
205 | memset(&sp->vsz, 0, sizeof(*sp) - offsetof(procps_status_t, vsz)); | 206 | memset(&sp->vsz, 0, sizeof(*sp) - offsetof(procps_status_t, vsz)); |
206 | 207 | ||
207 | sp->pid = pid; | 208 | sp->pid = pid; |
208 | if (!(flags & ~PSSCAN_PID)) break; | 209 | if (!(flags & ~PSSCAN_PID)) |
210 | break; /* we needed only pid, we got it */ | ||
209 | 211 | ||
210 | #if ENABLE_SELINUX | 212 | #if ENABLE_SELINUX |
211 | if (flags & PSSCAN_CONTEXT) { | 213 | if (flags & PSSCAN_CONTEXT) { |
@@ -218,7 +220,7 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |||
218 | 220 | ||
219 | if (flags & PSSCAN_UIDGID) { | 221 | if (flags & PSSCAN_UIDGID) { |
220 | if (stat(filename, &sb)) | 222 | if (stat(filename, &sb)) |
221 | break; | 223 | continue; /* process probably exited */ |
222 | /* Effective UID/GID, not real */ | 224 | /* Effective UID/GID, not real */ |
223 | sp->uid = sb.st_uid; | 225 | sp->uid = sb.st_uid; |
224 | sp->gid = sb.st_gid; | 226 | sp->gid = sb.st_gid; |
@@ -234,10 +236,10 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |||
234 | strcpy(filename_tail, "stat"); | 236 | strcpy(filename_tail, "stat"); |
235 | n = read_to_buf(filename, buf); | 237 | n = read_to_buf(filename, buf); |
236 | if (n < 0) | 238 | if (n < 0) |
237 | break; | 239 | continue; /* process probably exited */ |
238 | cp = strrchr(buf, ')'); /* split into "PID (cmd" and "<rest>" */ | 240 | cp = strrchr(buf, ')'); /* split into "PID (cmd" and "<rest>" */ |
239 | /*if (!cp || cp[1] != ' ') | 241 | /*if (!cp || cp[1] != ' ') |
240 | break;*/ | 242 | continue;*/ |
241 | cp[0] = '\0'; | 243 | cp[0] = '\0'; |
242 | if (sizeof(sp->comm) < 16) | 244 | if (sizeof(sp->comm) < 16) |
243 | BUG_comm_size(); | 245 | BUG_comm_size(); |
@@ -257,12 +259,12 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |||
257 | "%lu " /* start_time */ | 259 | "%lu " /* start_time */ |
258 | "%lu " /* vsize */ | 260 | "%lu " /* vsize */ |
259 | "%lu " /* rss */ | 261 | "%lu " /* rss */ |
260 | #if ENABLE_FEATURE_TOP_SMP_PROCESS | 262 | # if ENABLE_FEATURE_TOP_SMP_PROCESS |
261 | "%*s %*s %*s %*s %*s %*s " /*rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */ | 263 | "%*s %*s %*s %*s %*s %*s " /*rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */ |
262 | "%*s %*s %*s %*s " /*signal, blocked, sigignore, sigcatch */ | 264 | "%*s %*s %*s %*s " /*signal, blocked, sigignore, sigcatch */ |
263 | "%*s %*s %*s %*s " /*wchan, nswap, cnswap, exit_signal */ | 265 | "%*s %*s %*s %*s " /*wchan, nswap, cnswap, exit_signal */ |
264 | "%d" /*cpu last seen on*/ | 266 | "%d" /*cpu last seen on*/ |
265 | #endif | 267 | # endif |
266 | , | 268 | , |
267 | sp->state, &sp->ppid, | 269 | sp->state, &sp->ppid, |
268 | &sp->pgid, &sp->sid, &tty, | 270 | &sp->pgid, &sp->sid, &tty, |
@@ -271,17 +273,17 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |||
271 | &sp->start_time, | 273 | &sp->start_time, |
272 | &vsz, | 274 | &vsz, |
273 | &rss | 275 | &rss |
274 | #if ENABLE_FEATURE_TOP_SMP_PROCESS | 276 | # if ENABLE_FEATURE_TOP_SMP_PROCESS |
275 | , &sp->last_seen_on_cpu | 277 | , &sp->last_seen_on_cpu |
276 | #endif | 278 | # endif |
277 | ); | 279 | ); |
278 | 280 | ||
279 | if (n < 11) | 281 | if (n < 11) |
280 | break; | 282 | continue; /* bogus data, get next /proc/XXX */ |
281 | #if ENABLE_FEATURE_TOP_SMP_PROCESS | 283 | # if ENABLE_FEATURE_TOP_SMP_PROCESS |
282 | if (n < 11+15) | 284 | if (n < 11+15) |
283 | sp->last_seen_on_cpu = 0; | 285 | sp->last_seen_on_cpu = 0; |
284 | #endif | 286 | # endif |
285 | 287 | ||
286 | /* vsz is in bytes and we want kb */ | 288 | /* vsz is in bytes and we want kb */ |
287 | sp->vsz = vsz >> 10; | 289 | sp->vsz = vsz >> 10; |
@@ -311,14 +313,14 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |||
311 | sp->vsz = fast_strtoul_10(&cp) >> 10; | 313 | sp->vsz = fast_strtoul_10(&cp) >> 10; |
312 | /* vsz is in bytes but rss is in *PAGES*! Can you believe that? */ | 314 | /* vsz is in bytes but rss is in *PAGES*! Can you believe that? */ |
313 | sp->rss = fast_strtoul_10(&cp) << sp->shift_pages_to_kb; | 315 | sp->rss = fast_strtoul_10(&cp) << sp->shift_pages_to_kb; |
314 | #if ENABLE_FEATURE_TOP_SMP_PROCESS | 316 | # if ENABLE_FEATURE_TOP_SMP_PROCESS |
315 | /* (6): rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */ | 317 | /* (6): rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */ |
316 | /* (4): signal, blocked, sigignore, sigcatch */ | 318 | /* (4): signal, blocked, sigignore, sigcatch */ |
317 | /* (4): wchan, nswap, cnswap, exit_signal */ | 319 | /* (4): wchan, nswap, cnswap, exit_signal */ |
318 | cp = skip_fields(cp, 14); | 320 | cp = skip_fields(cp, 14); |
319 | //FIXME: is it safe to assume this field exists? | 321 | //FIXME: is it safe to assume this field exists? |
320 | sp->last_seen_on_cpu = fast_strtoul_10(&cp); | 322 | sp->last_seen_on_cpu = fast_strtoul_10(&cp); |
321 | #endif | 323 | # endif |
322 | #endif /* end of !ENABLE_FEATURE_TOP_SMP_PROCESS */ | 324 | #endif /* end of !ENABLE_FEATURE_TOP_SMP_PROCESS */ |
323 | 325 | ||
324 | #if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS | 326 | #if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS |
@@ -343,48 +345,48 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |||
343 | 345 | ||
344 | strcpy(filename_tail, "smaps"); | 346 | strcpy(filename_tail, "smaps"); |
345 | file = fopen_for_read(filename); | 347 | file = fopen_for_read(filename); |
346 | if (!file) | 348 | if (file) { |
347 | break; | 349 | while (fgets(buf, sizeof(buf), file)) { |
348 | while (fgets(buf, sizeof(buf), file)) { | 350 | unsigned long sz; |
349 | unsigned long sz; | 351 | char *tp; |
350 | char *tp; | 352 | char w; |
351 | char w; | ||
352 | #define SCAN(str, name) \ | 353 | #define SCAN(str, name) \ |
353 | if (strncmp(buf, str, sizeof(str)-1) == 0) { \ | 354 | if (strncmp(buf, str, sizeof(str)-1) == 0) { \ |
354 | tp = skip_whitespace(buf + sizeof(str)-1); \ | 355 | tp = skip_whitespace(buf + sizeof(str)-1); \ |
355 | sp->name += fast_strtoul_10(&tp); \ | 356 | sp->name += fast_strtoul_10(&tp); \ |
356 | continue; \ | 357 | continue; \ |
357 | } | 358 | } |
358 | SCAN("Shared_Clean:" , shared_clean ); | 359 | SCAN("Shared_Clean:" , shared_clean ); |
359 | SCAN("Shared_Dirty:" , shared_dirty ); | 360 | SCAN("Shared_Dirty:" , shared_dirty ); |
360 | SCAN("Private_Clean:", private_clean); | 361 | SCAN("Private_Clean:", private_clean); |
361 | SCAN("Private_Dirty:", private_dirty); | 362 | SCAN("Private_Dirty:", private_dirty); |
362 | #undef SCAN | 363 | #undef SCAN |
363 | // f7d29000-f7d39000 rw-s ADR M:m OFS FILE | 364 | // f7d29000-f7d39000 rw-s ADR M:m OFS FILE |
364 | tp = strchr(buf, '-'); | 365 | tp = strchr(buf, '-'); |
365 | if (tp) { | 366 | if (tp) { |
366 | *tp = ' '; | 367 | *tp = ' '; |
367 | tp = buf; | 368 | tp = buf; |
368 | sz = fast_strtoul_16(&tp); /* start */ | 369 | sz = fast_strtoul_16(&tp); /* start */ |
369 | sz = (fast_strtoul_16(&tp) - sz) >> 10; /* end - start */ | 370 | sz = (fast_strtoul_16(&tp) - sz) >> 10; /* end - start */ |
370 | // tp -> "rw-s" string | 371 | // tp -> "rw-s" string |
371 | w = tp[1]; | 372 | w = tp[1]; |
372 | // skipping "rw-s ADR M:m OFS " | 373 | // skipping "rw-s ADR M:m OFS " |
373 | tp = skip_whitespace(skip_fields(tp, 4)); | 374 | tp = skip_whitespace(skip_fields(tp, 4)); |
374 | // filter out /dev/something (something != zero) | 375 | // filter out /dev/something (something != zero) |
375 | if (strncmp(tp, "/dev/", 5) != 0 || strcmp(tp, "/dev/zero\n") == 0) { | 376 | if (strncmp(tp, "/dev/", 5) != 0 || strcmp(tp, "/dev/zero\n") == 0) { |
376 | if (w == 'w') { | 377 | if (w == 'w') { |
377 | sp->mapped_rw += sz; | 378 | sp->mapped_rw += sz; |
378 | } else if (w == '-') { | 379 | } else if (w == '-') { |
379 | sp->mapped_ro += sz; | 380 | sp->mapped_ro += sz; |
381 | } | ||
380 | } | 382 | } |
381 | } | ||
382 | //else printf("DROPPING %s (%s)\n", buf, tp); | 383 | //else printf("DROPPING %s (%s)\n", buf, tp); |
383 | if (strcmp(tp, "[stack]\n") == 0) | 384 | if (strcmp(tp, "[stack]\n") == 0) |
384 | sp->stack += sz; | 385 | sp->stack += sz; |
386 | } | ||
385 | } | 387 | } |
388 | fclose(file); | ||
386 | } | 389 | } |
387 | fclose(file); | ||
388 | } | 390 | } |
389 | #endif /* TOPMEM */ | 391 | #endif /* TOPMEM */ |
390 | #if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS | 392 | #if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS |
@@ -393,23 +395,34 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |||
393 | 395 | ||
394 | strcpy(filename_tail, "status"); | 396 | strcpy(filename_tail, "status"); |
395 | file = fopen_for_read(filename); | 397 | file = fopen_for_read(filename); |
396 | if (!file) | 398 | if (file) { |
397 | break; | 399 | while (fgets(buf, sizeof(buf), file)) { |
398 | while (fgets(buf, sizeof(buf), file)) { | 400 | char *tp; |
399 | char *tp; | ||
400 | #define SCAN_TWO(str, name, statement) \ | 401 | #define SCAN_TWO(str, name, statement) \ |
401 | if (strncmp(buf, str, sizeof(str)-1) == 0) { \ | 402 | if (strncmp(buf, str, sizeof(str)-1) == 0) { \ |
402 | tp = skip_whitespace(buf + sizeof(str)-1); \ | 403 | tp = skip_whitespace(buf + sizeof(str)-1); \ |
403 | sscanf(tp, "%u", &sp->name); \ | 404 | sscanf(tp, "%u", &sp->name); \ |
404 | statement; \ | 405 | statement; \ |
405 | } | 406 | } |
406 | SCAN_TWO("Uid:", ruid, continue); | 407 | SCAN_TWO("Uid:", ruid, continue); |
407 | SCAN_TWO("Gid:", rgid, break); | 408 | SCAN_TWO("Gid:", rgid, break); |
408 | #undef SCAN_TWO | 409 | #undef SCAN_TWO |
410 | } | ||
411 | fclose(file); | ||
409 | } | 412 | } |
410 | fclose(file); | ||
411 | } | 413 | } |
412 | #endif /* PS_ADDITIONAL_COLUMNS */ | 414 | #endif /* PS_ADDITIONAL_COLUMNS */ |
415 | if (flags & PSSCAN_EXE) { | ||
416 | strcpy(filename_tail, "exe"); | ||
417 | free(sp->exe); | ||
418 | sp->exe = xmalloc_readlink(filename); | ||
419 | } | ||
420 | /* Note: if /proc/PID/cmdline is empty, | ||
421 | * code below "breaks". Therefore it must be | ||
422 | * the last code to parse /proc/PID/xxx data | ||
423 | * (we used to have /proc/PID/exe parsing after it | ||
424 | * and were getting stale sp->exe). | ||
425 | */ | ||
413 | #if 0 /* PSSCAN_CMD is not used */ | 426 | #if 0 /* PSSCAN_CMD is not used */ |
414 | if (flags & (PSSCAN_CMD|PSSCAN_ARGV0)) { | 427 | if (flags & (PSSCAN_CMD|PSSCAN_ARGV0)) { |
415 | free(sp->argv0); | 428 | free(sp->argv0); |
@@ -452,13 +465,9 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |||
452 | } | 465 | } |
453 | } | 466 | } |
454 | #endif | 467 | #endif |
455 | if (flags & PSSCAN_EXE) { | ||
456 | strcpy(filename_tail, "exe"); | ||
457 | free(sp->exe); | ||
458 | sp->exe = xmalloc_readlink(filename); | ||
459 | } | ||
460 | break; | 468 | break; |
461 | } | 469 | } /* for (;;) */ |
470 | |||
462 | return sp; | 471 | return sp; |
463 | } | 472 | } |
464 | 473 | ||
diff --git a/libbb/recursive_action.c b/libbb/recursive_action.c index 3ec596a35..3a4eb28db 100644 --- a/libbb/recursive_action.c +++ b/libbb/recursive_action.c | |||
@@ -61,6 +61,7 @@ int FAST_FUNC recursive_action(const char *fileName, | |||
61 | unsigned depth) | 61 | unsigned depth) |
62 | { | 62 | { |
63 | struct stat statbuf; | 63 | struct stat statbuf; |
64 | unsigned follow; | ||
64 | int status; | 65 | int status; |
65 | DIR *dir; | 66 | DIR *dir; |
66 | struct dirent *next; | 67 | struct dirent *next; |
@@ -68,14 +69,22 @@ int FAST_FUNC recursive_action(const char *fileName, | |||
68 | if (!fileAction) fileAction = true_action; | 69 | if (!fileAction) fileAction = true_action; |
69 | if (!dirAction) dirAction = true_action; | 70 | if (!dirAction) dirAction = true_action; |
70 | 71 | ||
71 | status = ACTION_FOLLOWLINKS; /* hijack a variable for bitmask... */ | 72 | follow = ACTION_FOLLOWLINKS; |
72 | if (!depth) | 73 | if (depth == 0) |
73 | status = ACTION_FOLLOWLINKS | ACTION_FOLLOWLINKS_L0; | 74 | follow = ACTION_FOLLOWLINKS | ACTION_FOLLOWLINKS_L0; |
74 | status = ((flags & status) ? stat : lstat)(fileName, &statbuf); | 75 | follow &= flags; |
76 | status = (follow ? stat : lstat)(fileName, &statbuf); | ||
75 | if (status < 0) { | 77 | if (status < 0) { |
76 | #ifdef DEBUG_RECURS_ACTION | 78 | #ifdef DEBUG_RECURS_ACTION |
77 | bb_error_msg("status=%d flags=%x", status, flags); | 79 | bb_error_msg("status=%d flags=%x", status, flags); |
78 | #endif | 80 | #endif |
81 | if ((flags & ACTION_DANGLING_OK) | ||
82 | && errno == ENOENT | ||
83 | && lstat(fileName, &statbuf) == 0 | ||
84 | ) { | ||
85 | /* Dangling link */ | ||
86 | return fileAction(fileName, &statbuf, userData, depth); | ||
87 | } | ||
79 | goto done_nak_warn; | 88 | goto done_nak_warn; |
80 | } | 89 | } |
81 | 90 | ||
diff --git a/miscutils/hdparm.c b/miscutils/hdparm.c index 60682231a..0917b4175 100644 --- a/miscutils/hdparm.c +++ b/miscutils/hdparm.c | |||
@@ -15,6 +15,9 @@ | |||
15 | /* must be _after_ libbb.h: */ | 15 | /* must be _after_ libbb.h: */ |
16 | #include <linux/hdreg.h> | 16 | #include <linux/hdreg.h> |
17 | #include <sys/mount.h> | 17 | #include <sys/mount.h> |
18 | #if !defined(BLKGETSIZE64) | ||
19 | # define BLKGETSIZE64 _IOR(0x12,114,size_t) | ||
20 | #endif | ||
18 | 21 | ||
19 | /* device types */ | 22 | /* device types */ |
20 | /* ------------ */ | 23 | /* ------------ */ |
diff --git a/shell/ash.c b/shell/ash.c index 4a163ffbc..952961373 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -112,7 +112,7 @@ enum { NOPTS = ARRAY_SIZE(optletters_optnames) }; | |||
112 | 112 | ||
113 | static const char homestr[] ALIGN1 = "HOME"; | 113 | static const char homestr[] ALIGN1 = "HOME"; |
114 | static const char snlfmt[] ALIGN1 = "%s\n"; | 114 | static const char snlfmt[] ALIGN1 = "%s\n"; |
115 | static const char illnum[] ALIGN1 = "Illegal number: %s"; | 115 | static const char msg_illnum[] ALIGN1 = "Illegal number: %s"; |
116 | 116 | ||
117 | /* | 117 | /* |
118 | * We enclose jmp_buf in a structure so that we can declare pointers to | 118 | * We enclose jmp_buf in a structure so that we can declare pointers to |
@@ -142,17 +142,10 @@ struct globals_misc { | |||
142 | 142 | ||
143 | struct jmploc *exception_handler; | 143 | struct jmploc *exception_handler; |
144 | 144 | ||
145 | // disabled by vda: cannot understand how it was supposed to work - | 145 | volatile int suppress_int; /* counter */ |
146 | // cannot fix bugs. That's why you have to explain your non-trivial designs! | 146 | volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */ |
147 | // /* do we generate EXSIG events */ | ||
148 | // int exsig; /* counter */ | ||
149 | volatile int suppressint; /* counter */ | ||
150 | // TODO: rename | ||
151 | // pendingsig -> pending_sig | ||
152 | // intpending -> pending_int | ||
153 | volatile /*sig_atomic_t*/ smallint intpending; /* 1 = got SIGINT */ | ||
154 | /* last pending signal */ | 147 | /* last pending signal */ |
155 | volatile /*sig_atomic_t*/ smallint pendingsig; | 148 | volatile /*sig_atomic_t*/ smallint pending_sig; |
156 | smallint exception_type; /* kind of exception (0..5) */ | 149 | smallint exception_type; /* kind of exception (0..5) */ |
157 | /* exceptions */ | 150 | /* exceptions */ |
158 | #define EXINT 0 /* SIGINT received */ | 151 | #define EXINT 0 /* SIGINT received */ |
@@ -200,6 +193,7 @@ struct globals_misc { | |||
200 | /* indicates specified signal received */ | 193 | /* indicates specified signal received */ |
201 | uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */ | 194 | uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */ |
202 | char *trap[NSIG]; | 195 | char *trap[NSIG]; |
196 | char **trap_ptr; /* used only by "trap hack" */ | ||
203 | 197 | ||
204 | /* Rarely referenced stuff */ | 198 | /* Rarely referenced stuff */ |
205 | #if ENABLE_ASH_RANDOM_SUPPORT | 199 | #if ENABLE_ASH_RANDOM_SUPPORT |
@@ -220,16 +214,16 @@ extern struct globals_misc *const ash_ptr_to_globals_misc; | |||
220 | #define arg0 (G_misc.arg0 ) | 214 | #define arg0 (G_misc.arg0 ) |
221 | #define exception_handler (G_misc.exception_handler) | 215 | #define exception_handler (G_misc.exception_handler) |
222 | #define exception_type (G_misc.exception_type ) | 216 | #define exception_type (G_misc.exception_type ) |
223 | #define suppressint (G_misc.suppressint ) | 217 | #define suppress_int (G_misc.suppress_int ) |
224 | #define intpending (G_misc.intpending ) | 218 | #define pending_int (G_misc.pending_int ) |
225 | //#define exsig (G_misc.exsig ) | 219 | #define pending_sig (G_misc.pending_sig ) |
226 | #define pendingsig (G_misc.pendingsig ) | ||
227 | #define isloginsh (G_misc.isloginsh ) | 220 | #define isloginsh (G_misc.isloginsh ) |
228 | #define nullstr (G_misc.nullstr ) | 221 | #define nullstr (G_misc.nullstr ) |
229 | #define optlist (G_misc.optlist ) | 222 | #define optlist (G_misc.optlist ) |
230 | #define sigmode (G_misc.sigmode ) | 223 | #define sigmode (G_misc.sigmode ) |
231 | #define gotsig (G_misc.gotsig ) | 224 | #define gotsig (G_misc.gotsig ) |
232 | #define trap (G_misc.trap ) | 225 | #define trap (G_misc.trap ) |
226 | #define trap_ptr (G_misc.trap_ptr ) | ||
233 | #define random_galois_LFSR (G_misc.random_galois_LFSR) | 227 | #define random_galois_LFSR (G_misc.random_galois_LFSR) |
234 | #define random_LCG (G_misc.random_LCG ) | 228 | #define random_LCG (G_misc.random_LCG ) |
235 | #define backgndpid (G_misc.backgndpid ) | 229 | #define backgndpid (G_misc.backgndpid ) |
@@ -239,6 +233,7 @@ extern struct globals_misc *const ash_ptr_to_globals_misc; | |||
239 | barrier(); \ | 233 | barrier(); \ |
240 | curdir = nullstr; \ | 234 | curdir = nullstr; \ |
241 | physdir = nullstr; \ | 235 | physdir = nullstr; \ |
236 | trap_ptr = trap; \ | ||
242 | } while (0) | 237 | } while (0) |
243 | 238 | ||
244 | 239 | ||
@@ -283,7 +278,7 @@ static int isdigit_str9(const char *str) | |||
283 | * more fun than worrying about efficiency and portability. :-)) | 278 | * more fun than worrying about efficiency and portability. :-)) |
284 | */ | 279 | */ |
285 | #define INT_OFF do { \ | 280 | #define INT_OFF do { \ |
286 | suppressint++; \ | 281 | suppress_int++; \ |
287 | xbarrier(); \ | 282 | xbarrier(); \ |
288 | } while (0) | 283 | } while (0) |
289 | 284 | ||
@@ -324,11 +319,11 @@ raise_interrupt(void) | |||
324 | { | 319 | { |
325 | int ex_type; | 320 | int ex_type; |
326 | 321 | ||
327 | intpending = 0; | 322 | pending_int = 0; |
328 | /* Signal is not automatically unmasked after it is raised, | 323 | /* Signal is not automatically unmasked after it is raised, |
329 | * do it ourself - unmask all signals */ | 324 | * do it ourself - unmask all signals */ |
330 | sigprocmask_allsigs(SIG_UNBLOCK); | 325 | sigprocmask_allsigs(SIG_UNBLOCK); |
331 | /* pendingsig = 0; - now done in onsig() */ | 326 | /* pending_sig = 0; - now done in onsig() */ |
332 | 327 | ||
333 | ex_type = EXSIG; | 328 | ex_type = EXSIG; |
334 | if (gotsig[SIGINT - 1] && !trap[SIGINT]) { | 329 | if (gotsig[SIGINT - 1] && !trap[SIGINT]) { |
@@ -353,7 +348,7 @@ static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void | |||
353 | int_on(void) | 348 | int_on(void) |
354 | { | 349 | { |
355 | xbarrier(); | 350 | xbarrier(); |
356 | if (--suppressint == 0 && intpending) { | 351 | if (--suppress_int == 0 && pending_int) { |
357 | raise_interrupt(); | 352 | raise_interrupt(); |
358 | } | 353 | } |
359 | } | 354 | } |
@@ -362,18 +357,18 @@ static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void | |||
362 | force_int_on(void) | 357 | force_int_on(void) |
363 | { | 358 | { |
364 | xbarrier(); | 359 | xbarrier(); |
365 | suppressint = 0; | 360 | suppress_int = 0; |
366 | if (intpending) | 361 | if (pending_int) |
367 | raise_interrupt(); | 362 | raise_interrupt(); |
368 | } | 363 | } |
369 | #define FORCE_INT_ON force_int_on() | 364 | #define FORCE_INT_ON force_int_on() |
370 | 365 | ||
371 | #define SAVE_INT(v) ((v) = suppressint) | 366 | #define SAVE_INT(v) ((v) = suppress_int) |
372 | 367 | ||
373 | #define RESTORE_INT(v) do { \ | 368 | #define RESTORE_INT(v) do { \ |
374 | xbarrier(); \ | 369 | xbarrier(); \ |
375 | suppressint = (v); \ | 370 | suppress_int = (v); \ |
376 | if (suppressint == 0 && intpending) \ | 371 | if (suppress_int == 0 && pending_int) \ |
377 | raise_interrupt(); \ | 372 | raise_interrupt(); \ |
378 | } while (0) | 373 | } while (0) |
379 | 374 | ||
@@ -461,15 +456,15 @@ out2str(const char *p) | |||
461 | /* ============ Parser structures */ | 456 | /* ============ Parser structures */ |
462 | 457 | ||
463 | /* control characters in argument strings */ | 458 | /* control characters in argument strings */ |
464 | #define CTLESC '\201' /* escape next character */ | 459 | #define CTLESC ((unsigned char)'\201') /* escape next character */ |
465 | #define CTLVAR '\202' /* variable defn */ | 460 | #define CTLVAR ((unsigned char)'\202') /* variable defn */ |
466 | #define CTLENDVAR '\203' | 461 | #define CTLENDVAR ((unsigned char)'\203') |
467 | #define CTLBACKQ '\204' | 462 | #define CTLBACKQ ((unsigned char)'\204') |
468 | #define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */ | 463 | #define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */ |
469 | /* CTLBACKQ | CTLQUOTE == '\205' */ | 464 | /* CTLBACKQ | CTLQUOTE == '\205' */ |
470 | #define CTLARI '\206' /* arithmetic expression */ | 465 | #define CTLARI ((unsigned char)'\206') /* arithmetic expression */ |
471 | #define CTLENDARI '\207' | 466 | #define CTLENDARI ((unsigned char)'\207') |
472 | #define CTLQUOTEMARK '\210' | 467 | #define CTLQUOTEMARK ((unsigned char)'\210') |
473 | 468 | ||
474 | /* variable substitution byte (follows CTLVAR) */ | 469 | /* variable substitution byte (follows CTLVAR) */ |
475 | #define VSTYPE 0x0f /* type of variable substitution */ | 470 | #define VSTYPE 0x0f /* type of variable substitution */ |
@@ -685,7 +680,7 @@ trace_printf(const char *fmt, ...) | |||
685 | if (DEBUG_PID) | 680 | if (DEBUG_PID) |
686 | fprintf(tracefile, "[%u] ", (int) getpid()); | 681 | fprintf(tracefile, "[%u] ", (int) getpid()); |
687 | if (DEBUG_SIG) | 682 | if (DEBUG_SIG) |
688 | fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pendingsig, intpending, suppressint); | 683 | fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int); |
689 | va_start(va, fmt); | 684 | va_start(va, fmt); |
690 | vfprintf(tracefile, fmt, va); | 685 | vfprintf(tracefile, fmt, va); |
691 | va_end(va); | 686 | va_end(va); |
@@ -701,7 +696,7 @@ trace_vprintf(const char *fmt, va_list va) | |||
701 | if (DEBUG_PID) | 696 | if (DEBUG_PID) |
702 | fprintf(tracefile, "[%u] ", (int) getpid()); | 697 | fprintf(tracefile, "[%u] ", (int) getpid()); |
703 | if (DEBUG_SIG) | 698 | if (DEBUG_SIG) |
704 | fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pendingsig, intpending, suppressint); | 699 | fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int); |
705 | vfprintf(tracefile, fmt, va); | 700 | vfprintf(tracefile, fmt, va); |
706 | } | 701 | } |
707 | 702 | ||
@@ -1556,7 +1551,7 @@ static int | |||
1556 | number(const char *s) | 1551 | number(const char *s) |
1557 | { | 1552 | { |
1558 | if (!is_number(s)) | 1553 | if (!is_number(s)) |
1559 | ash_msg_and_raise_error(illnum, s); | 1554 | ash_msg_and_raise_error(msg_illnum, s); |
1560 | return atoi(s); | 1555 | return atoi(s); |
1561 | } | 1556 | } |
1562 | 1557 | ||
@@ -2351,8 +2346,6 @@ setprompt(int whichprompt) | |||
2351 | #define CD_PHYSICAL 1 | 2346 | #define CD_PHYSICAL 1 |
2352 | #define CD_PRINT 2 | 2347 | #define CD_PRINT 2 |
2353 | 2348 | ||
2354 | static int docd(const char *, int); | ||
2355 | |||
2356 | static int | 2349 | static int |
2357 | cdopt(void) | 2350 | cdopt(void) |
2358 | { | 2351 | { |
@@ -2360,7 +2353,7 @@ cdopt(void) | |||
2360 | int i, j; | 2353 | int i, j; |
2361 | 2354 | ||
2362 | j = 'L'; | 2355 | j = 'L'; |
2363 | while ((i = nextopt("LP"))) { | 2356 | while ((i = nextopt("LP")) != '\0') { |
2364 | if (i != j) { | 2357 | if (i != j) { |
2365 | flags ^= CD_PHYSICAL; | 2358 | flags ^= CD_PHYSICAL; |
2366 | j = i; | 2359 | j = i; |
@@ -2710,8 +2703,8 @@ SIT(int c, int syntax) | |||
2710 | } else | 2703 | } else |
2711 | #endif | 2704 | #endif |
2712 | { | 2705 | { |
2713 | if ((unsigned char)c >= (unsigned char)(CTLESC) | 2706 | if ((unsigned char)c >= CTLESC |
2714 | && (unsigned char)c <= (unsigned char)(CTLQUOTEMARK) | 2707 | && (unsigned char)c <= CTLQUOTEMARK |
2715 | ) { | 2708 | ) { |
2716 | return CCTL; | 2709 | return CCTL; |
2717 | } | 2710 | } |
@@ -3240,9 +3233,9 @@ unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
3240 | #define FORK_NOJOB 2 | 3233 | #define FORK_NOJOB 2 |
3241 | 3234 | ||
3242 | /* mode flags for showjob(s) */ | 3235 | /* mode flags for showjob(s) */ |
3243 | #define SHOW_PGID 0x01 /* only show pgid - for jobs -p */ | 3236 | #define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */ |
3244 | #define SHOW_PID 0x04 /* include process pid */ | 3237 | #define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */ |
3245 | #define SHOW_CHANGED 0x08 /* only jobs whose state has changed */ | 3238 | #define SHOW_CHANGED 0x04 /* only jobs whose state has changed */ |
3246 | 3239 | ||
3247 | /* | 3240 | /* |
3248 | * A job structure contains information about a job. A job is either a | 3241 | * A job structure contains information about a job. A job is either a |
@@ -3250,7 +3243,6 @@ unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
3250 | * latter case, pidlist will be non-NULL, and will point to a -1 terminated | 3243 | * latter case, pidlist will be non-NULL, and will point to a -1 terminated |
3251 | * array of pids. | 3244 | * array of pids. |
3252 | */ | 3245 | */ |
3253 | |||
3254 | struct procstat { | 3246 | struct procstat { |
3255 | pid_t pid; /* process id */ | 3247 | pid_t pid; /* process id */ |
3256 | int status; /* last process status from wait() */ | 3248 | int status; /* last process status from wait() */ |
@@ -3316,14 +3308,14 @@ onsig(int signo) | |||
3316 | { | 3308 | { |
3317 | gotsig[signo - 1] = 1; | 3309 | gotsig[signo - 1] = 1; |
3318 | 3310 | ||
3319 | if (/* exsig || */ (signo == SIGINT && !trap[SIGINT])) { | 3311 | if (signo == SIGINT && !trap[SIGINT]) { |
3320 | if (!suppressint) { | 3312 | if (!suppress_int) { |
3321 | pendingsig = 0; | 3313 | pending_sig = 0; |
3322 | raise_interrupt(); /* does not return */ | 3314 | raise_interrupt(); /* does not return */ |
3323 | } | 3315 | } |
3324 | intpending = 1; | 3316 | pending_int = 1; |
3325 | } else { | 3317 | } else { |
3326 | pendingsig = signo; | 3318 | pending_sig = signo; |
3327 | } | 3319 | } |
3328 | } | 3320 | } |
3329 | 3321 | ||
@@ -3546,7 +3538,6 @@ getjob(const char *name, int getctl) | |||
3546 | } | 3538 | } |
3547 | 3539 | ||
3548 | if (is_number(p)) { | 3540 | if (is_number(p)) { |
3549 | // TODO: number() instead? It does error checking... | ||
3550 | num = atoi(p); | 3541 | num = atoi(p); |
3551 | if (num < njobs) { | 3542 | if (num < njobs) { |
3552 | jp = jobtab + num - 1; | 3543 | jp = jobtab + num - 1; |
@@ -3918,7 +3909,7 @@ static int | |||
3918 | blocking_wait_with_raise_on_sig(struct job *job) | 3909 | blocking_wait_with_raise_on_sig(struct job *job) |
3919 | { | 3910 | { |
3920 | pid_t pid = dowait(DOWAIT_BLOCK, job); | 3911 | pid_t pid = dowait(DOWAIT_BLOCK, job); |
3921 | if (pid <= 0 && pendingsig) | 3912 | if (pid <= 0 && pending_sig) |
3922 | raise_exception(EXSIG); | 3913 | raise_exception(EXSIG); |
3923 | return pid; | 3914 | return pid; |
3924 | } | 3915 | } |
@@ -3935,7 +3926,7 @@ showjob(FILE *out, struct job *jp, int mode) | |||
3935 | 3926 | ||
3936 | ps = jp->ps; | 3927 | ps = jp->ps; |
3937 | 3928 | ||
3938 | if (mode & SHOW_PGID) { | 3929 | if (mode & SHOW_ONLY_PGID) { /* jobs -p */ |
3939 | /* just output process (group) id of pipeline */ | 3930 | /* just output process (group) id of pipeline */ |
3940 | fprintf(out, "%d\n", ps->pid); | 3931 | fprintf(out, "%d\n", ps->pid); |
3941 | return; | 3932 | return; |
@@ -3945,11 +3936,11 @@ showjob(FILE *out, struct job *jp, int mode) | |||
3945 | indent_col = col; | 3936 | indent_col = col; |
3946 | 3937 | ||
3947 | if (jp == curjob) | 3938 | if (jp == curjob) |
3948 | s[col - 2] = '+'; | 3939 | s[col - 3] = '+'; |
3949 | else if (curjob && jp == curjob->prev_job) | 3940 | else if (curjob && jp == curjob->prev_job) |
3950 | s[col - 2] = '-'; | 3941 | s[col - 3] = '-'; |
3951 | 3942 | ||
3952 | if (mode & SHOW_PID) | 3943 | if (mode & SHOW_PIDS) |
3953 | col += fmtstr(s + col, 16, "%d ", ps->pid); | 3944 | col += fmtstr(s + col, 16, "%d ", ps->pid); |
3954 | 3945 | ||
3955 | psend = ps + jp->nprocs; | 3946 | psend = ps + jp->nprocs; |
@@ -3963,25 +3954,32 @@ showjob(FILE *out, struct job *jp, int mode) | |||
3963 | status = jp->stopstatus; | 3954 | status = jp->stopstatus; |
3964 | col += sprint_status(s + col, status, 0); | 3955 | col += sprint_status(s + col, status, 0); |
3965 | } | 3956 | } |
3957 | /* By now, "[JOBID]* [maybe PID] STATUS" is printed */ | ||
3966 | 3958 | ||
3959 | /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line | ||
3960 | * or prints several "PID | <cmdN>" lines, | ||
3961 | * depending on SHOW_PIDS bit. | ||
3962 | * We do not print status of individual processes | ||
3963 | * between PID and <cmdN>. bash does it, but not very well: | ||
3964 | * first line shows overall job status, not process status, | ||
3965 | * making it impossible to know 1st process status. | ||
3966 | */ | ||
3967 | goto start; | 3967 | goto start; |
3968 | 3968 | while (1) { | |
3969 | do { | ||
3970 | /* for each process */ | 3969 | /* for each process */ |
3971 | col = fmtstr(s, 48, " |\n%*c%d ", indent_col, ' ', ps->pid) - 3; | 3970 | s[0] = '\0'; |
3971 | col = 33; | ||
3972 | if (mode & SHOW_PIDS) | ||
3973 | col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->pid) - 1; | ||
3972 | start: | 3974 | start: |
3973 | fprintf(out, "%s%*c%s", | 3975 | fprintf(out, "%s%*c", s, 33 - col >= 0 ? 33 - col : 0, ' '); |
3974 | s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd | 3976 | if (ps != jp->ps) |
3975 | ); | 3977 | fprintf(out, "| "); |
3976 | if (!(mode & SHOW_PID)) { | 3978 | fprintf(out, "%s", ps->cmd); |
3977 | showpipe(jp, out); | 3979 | if (++ps == psend) |
3978 | break; | ||
3979 | } | ||
3980 | if (++ps == psend) { | ||
3981 | outcslow('\n', out); | ||
3982 | break; | 3980 | break; |
3983 | } | 3981 | } |
3984 | } while (1); | 3982 | outcslow('\n', out); |
3985 | 3983 | ||
3986 | jp->changed = 0; | 3984 | jp->changed = 0; |
3987 | 3985 | ||
@@ -4019,17 +4017,17 @@ jobscmd(int argc UNUSED_PARAM, char **argv) | |||
4019 | int mode, m; | 4017 | int mode, m; |
4020 | 4018 | ||
4021 | mode = 0; | 4019 | mode = 0; |
4022 | while ((m = nextopt("lp"))) { | 4020 | while ((m = nextopt("lp")) != '\0') { |
4023 | if (m == 'l') | 4021 | if (m == 'l') |
4024 | mode = SHOW_PID; | 4022 | mode |= SHOW_PIDS; |
4025 | else | 4023 | else |
4026 | mode = SHOW_PGID; | 4024 | mode |= SHOW_ONLY_PGID; |
4027 | } | 4025 | } |
4028 | 4026 | ||
4029 | argv = argptr; | 4027 | argv = argptr; |
4030 | if (*argv) { | 4028 | if (*argv) { |
4031 | do | 4029 | do |
4032 | showjob(stdout, getjob(*argv,0), mode); | 4030 | showjob(stdout, getjob(*argv, 0), mode); |
4033 | while (*++argv); | 4031 | while (*++argv); |
4034 | } else | 4032 | } else |
4035 | showjobs(stdout, mode); | 4033 | showjobs(stdout, mode); |
@@ -4073,9 +4071,7 @@ waitcmd(int argc UNUSED_PARAM, char **argv) | |||
4073 | int retval; | 4071 | int retval; |
4074 | struct job *jp; | 4072 | struct job *jp; |
4075 | 4073 | ||
4076 | // exsig++; | 4074 | if (pending_sig) |
4077 | // xbarrier(); | ||
4078 | if (pendingsig) | ||
4079 | raise_exception(EXSIG); | 4075 | raise_exception(EXSIG); |
4080 | 4076 | ||
4081 | nextopt(nullstr); | 4077 | nextopt(nullstr); |
@@ -4311,7 +4307,7 @@ cmdputs(const char *s) | |||
4311 | if (!str) | 4307 | if (!str) |
4312 | continue; | 4308 | continue; |
4313 | dostr: | 4309 | dostr: |
4314 | while ((c = *str++)) { | 4310 | while ((c = *str++) != '\0') { |
4315 | USTPUTC(c, nextc); | 4311 | USTPUTC(c, nextc); |
4316 | } | 4312 | } |
4317 | } | 4313 | } |
@@ -4530,9 +4526,11 @@ clear_traps(void) | |||
4530 | for (tp = trap; tp < &trap[NSIG]; tp++) { | 4526 | for (tp = trap; tp < &trap[NSIG]; tp++) { |
4531 | if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */ | 4527 | if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */ |
4532 | INT_OFF; | 4528 | INT_OFF; |
4533 | free(*tp); | 4529 | if (trap_ptr == trap) |
4530 | free(*tp); | ||
4531 | /* else: it "belongs" to trap_ptr vector, don't free */ | ||
4534 | *tp = NULL; | 4532 | *tp = NULL; |
4535 | if (tp != &trap[0]) | 4533 | if ((tp - trap) != 0) |
4536 | setsignal(tp - trap); | 4534 | setsignal(tp - trap); |
4537 | INT_ON; | 4535 | INT_ON; |
4538 | } | 4536 | } |
@@ -4546,7 +4544,7 @@ static void closescript(void); | |||
4546 | #if !JOBS | 4544 | #if !JOBS |
4547 | # define forkchild(jp, n, mode) forkchild(jp, mode) | 4545 | # define forkchild(jp, n, mode) forkchild(jp, mode) |
4548 | #endif | 4546 | #endif |
4549 | static void | 4547 | static NOINLINE void |
4550 | forkchild(struct job *jp, union node *n, int mode) | 4548 | forkchild(struct job *jp, union node *n, int mode) |
4551 | { | 4549 | { |
4552 | int oldlvl; | 4550 | int oldlvl; |
@@ -4560,6 +4558,53 @@ forkchild(struct job *jp, union node *n, int mode) | |||
4560 | * Do we do it correctly? */ | 4558 | * Do we do it correctly? */ |
4561 | 4559 | ||
4562 | closescript(); | 4560 | closescript(); |
4561 | |||
4562 | if (mode == FORK_NOJOB /* is it `xxx` ? */ | ||
4563 | && n && n->type == NCMD /* is it single cmd? */ | ||
4564 | /* && n->ncmd.args->type == NARG - always true? */ | ||
4565 | && strcmp(n->ncmd.args->narg.text, "trap") == 0 | ||
4566 | && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */ | ||
4567 | /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */ | ||
4568 | ) { | ||
4569 | TRACE(("Trap hack\n")); | ||
4570 | /* Awful hack for `trap` or $(trap). | ||
4571 | * | ||
4572 | * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html | ||
4573 | * contains an example where "trap" is executed in a subshell: | ||
4574 | * | ||
4575 | * save_traps=$(trap) | ||
4576 | * ... | ||
4577 | * eval "$save_traps" | ||
4578 | * | ||
4579 | * Standard does not say that "trap" in subshell shall print | ||
4580 | * parent shell's traps. It only says that its output | ||
4581 | * must have suitable form, but then, in the above example | ||
4582 | * (which is not supposed to be normative), it implies that. | ||
4583 | * | ||
4584 | * bash (and probably other shell) does implement it | ||
4585 | * (traps are reset to defaults, but "trap" still shows them), | ||
4586 | * but as a result, "trap" logic is hopelessly messed up: | ||
4587 | * | ||
4588 | * # trap | ||
4589 | * trap -- 'echo Ho' SIGWINCH <--- we have a handler | ||
4590 | * # (trap) <--- trap is in subshell - no output (correct, traps are reset) | ||
4591 | * # true | trap <--- trap is in subshell - no output (ditto) | ||
4592 | * # echo `true | trap` <--- in subshell - output (but traps are reset!) | ||
4593 | * trap -- 'echo Ho' SIGWINCH | ||
4594 | * # echo `(trap)` <--- in subshell in subshell - output | ||
4595 | * trap -- 'echo Ho' SIGWINCH | ||
4596 | * # echo `true | (trap)` <--- in subshell in subshell in subshell - output! | ||
4597 | * trap -- 'echo Ho' SIGWINCH | ||
4598 | * | ||
4599 | * The rules when to forget and when to not forget traps | ||
4600 | * get really complex and nonsensical. | ||
4601 | * | ||
4602 | * Our solution: ONLY bare $(trap) or `trap` is special. | ||
4603 | */ | ||
4604 | /* Save trap handler strings for trap builtin to print */ | ||
4605 | trap_ptr = memcpy(xmalloc(sizeof(trap)), trap, sizeof(trap)); | ||
4606 | /* Fall through into clearing traps */ | ||
4607 | } | ||
4563 | clear_traps(); | 4608 | clear_traps(); |
4564 | #if JOBS | 4609 | #if JOBS |
4565 | /* do job control only in root shell */ | 4610 | /* do job control only in root shell */ |
@@ -4604,8 +4649,14 @@ forkchild(struct job *jp, union node *n, int mode) | |||
4604 | setsignal(SIGQUIT); | 4649 | setsignal(SIGQUIT); |
4605 | } | 4650 | } |
4606 | #if JOBS | 4651 | #if JOBS |
4607 | if (n && n->type == NCMD && strcmp(n->ncmd.args->narg.text, "jobs") == 0) { | 4652 | if (n && n->type == NCMD |
4653 | && strcmp(n->ncmd.args->narg.text, "jobs") == 0 | ||
4654 | ) { | ||
4608 | TRACE(("Job hack\n")); | 4655 | TRACE(("Job hack\n")); |
4656 | /* "jobs": we do not want to clear job list for it, | ||
4657 | * instead we remove only _its_ own_ job from job list. | ||
4658 | * This makes "jobs .... | cat" more useful. | ||
4659 | */ | ||
4609 | freejob(curjob); | 4660 | freejob(curjob); |
4610 | return; | 4661 | return; |
4611 | } | 4662 | } |
@@ -4998,7 +5049,7 @@ struct redirtab { | |||
4998 | struct redirtab *next; | 5049 | struct redirtab *next; |
4999 | int nullredirs; | 5050 | int nullredirs; |
5000 | int pair_count; | 5051 | int pair_count; |
5001 | struct two_fd_t two_fd[0]; | 5052 | struct two_fd_t two_fd[]; |
5002 | }; | 5053 | }; |
5003 | #define redirlist (G_var.redirlist) | 5054 | #define redirlist (G_var.redirlist) |
5004 | 5055 | ||
@@ -5309,7 +5360,7 @@ ash_arith(const char *s) | |||
5309 | #define EXP_WORD 0x80 /* expand word in parameter expansion */ | 5360 | #define EXP_WORD 0x80 /* expand word in parameter expansion */ |
5310 | #define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */ | 5361 | #define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */ |
5311 | /* | 5362 | /* |
5312 | * _rmescape() flags | 5363 | * rmescape() flags |
5313 | */ | 5364 | */ |
5314 | #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */ | 5365 | #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */ |
5315 | #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */ | 5366 | #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */ |
@@ -5363,7 +5414,7 @@ esclen(const char *start, const char *p) | |||
5363 | { | 5414 | { |
5364 | size_t esc = 0; | 5415 | size_t esc = 0; |
5365 | 5416 | ||
5366 | while (p > start && *--p == CTLESC) { | 5417 | while (p > start && (unsigned char)*--p == CTLESC) { |
5367 | esc++; | 5418 | esc++; |
5368 | } | 5419 | } |
5369 | return esc; | 5420 | return esc; |
@@ -5373,19 +5424,19 @@ esclen(const char *start, const char *p) | |||
5373 | * Remove any CTLESC characters from a string. | 5424 | * Remove any CTLESC characters from a string. |
5374 | */ | 5425 | */ |
5375 | static char * | 5426 | static char * |
5376 | _rmescapes(char *str, int flag) | 5427 | rmescapes(char *str, int flag) |
5377 | { | 5428 | { |
5378 | static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' }; | 5429 | static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' }; |
5379 | 5430 | ||
5380 | char *p, *q, *r; | 5431 | char *p, *q, *r; |
5381 | unsigned inquotes; | 5432 | unsigned inquotes; |
5382 | int notescaped; | 5433 | unsigned protect_against_glob; |
5383 | int globbing; | 5434 | unsigned globbing; |
5384 | 5435 | ||
5385 | p = strpbrk(str, qchars); | 5436 | p = strpbrk(str, qchars); |
5386 | if (!p) { | 5437 | if (!p) |
5387 | return str; | 5438 | return str; |
5388 | } | 5439 | |
5389 | q = p; | 5440 | q = p; |
5390 | r = str; | 5441 | r = str; |
5391 | if (flag & RMESCAPE_ALLOC) { | 5442 | if (flag & RMESCAPE_ALLOC) { |
@@ -5404,28 +5455,33 @@ _rmescapes(char *str, int flag) | |||
5404 | q = (char *)memcpy(q, str, len) + len; | 5455 | q = (char *)memcpy(q, str, len) + len; |
5405 | } | 5456 | } |
5406 | } | 5457 | } |
5458 | |||
5407 | inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED; | 5459 | inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED; |
5408 | globbing = flag & RMESCAPE_GLOB; | 5460 | globbing = flag & RMESCAPE_GLOB; |
5409 | notescaped = globbing; | 5461 | protect_against_glob = globbing; |
5410 | while (*p) { | 5462 | while (*p) { |
5411 | if (*p == CTLQUOTEMARK) { | 5463 | if (*p == CTLQUOTEMARK) { |
5464 | // TODO: if no RMESCAPE_QUOTED in flags, inquotes never becomes 0 | ||
5465 | // (alternates between RMESCAPE_QUOTED and ~RMESCAPE_QUOTED). Is it ok? | ||
5466 | // Note: both inquotes and protect_against_glob only affect whether | ||
5467 | // CTLESC,<ch> gets converted to <ch> or to \<ch> | ||
5412 | inquotes = ~inquotes; | 5468 | inquotes = ~inquotes; |
5413 | p++; | 5469 | p++; |
5414 | notescaped = globbing; | 5470 | protect_against_glob = globbing; |
5415 | continue; | 5471 | continue; |
5416 | } | 5472 | } |
5417 | if (*p == '\\') { | 5473 | if (*p == '\\') { |
5418 | /* naked back slash */ | 5474 | /* naked back slash */ |
5419 | notescaped = 0; | 5475 | protect_against_glob = 0; |
5420 | goto copy; | 5476 | goto copy; |
5421 | } | 5477 | } |
5422 | if (*p == CTLESC) { | 5478 | if (*p == CTLESC) { |
5423 | p++; | 5479 | p++; |
5424 | if (notescaped && inquotes && *p != '/') { | 5480 | if (protect_against_glob && inquotes && *p != '/') { |
5425 | *q++ = '\\'; | 5481 | *q++ = '\\'; |
5426 | } | 5482 | } |
5427 | } | 5483 | } |
5428 | notescaped = globbing; | 5484 | protect_against_glob = globbing; |
5429 | copy: | 5485 | copy: |
5430 | *q++ = *p++; | 5486 | *q++ = *p++; |
5431 | } | 5487 | } |
@@ -5436,8 +5492,6 @@ _rmescapes(char *str, int flag) | |||
5436 | } | 5492 | } |
5437 | return r; | 5493 | return r; |
5438 | } | 5494 | } |
5439 | #define rmescapes(p) _rmescapes((p), 0) | ||
5440 | |||
5441 | #define pmatch(a, b) !fnmatch((a), (b), 0) | 5495 | #define pmatch(a, b) !fnmatch((a), (b), 0) |
5442 | 5496 | ||
5443 | /* | 5497 | /* |
@@ -5452,7 +5506,7 @@ preglob(const char *pattern, int quoted, int flag) | |||
5452 | if (quoted) { | 5506 | if (quoted) { |
5453 | flag |= RMESCAPE_QUOTED; | 5507 | flag |= RMESCAPE_QUOTED; |
5454 | } | 5508 | } |
5455 | return _rmescapes((char *)pattern, flag); | 5509 | return rmescapes((char *)pattern, flag); |
5456 | } | 5510 | } |
5457 | 5511 | ||
5458 | /* | 5512 | /* |
@@ -5463,14 +5517,17 @@ memtodest(const char *p, size_t len, int syntax, int quotes) | |||
5463 | { | 5517 | { |
5464 | char *q = expdest; | 5518 | char *q = expdest; |
5465 | 5519 | ||
5466 | q = makestrspace(len * 2, q); | 5520 | q = makestrspace(quotes ? len * 2 : len, q); |
5467 | 5521 | ||
5468 | while (len--) { | 5522 | while (len--) { |
5469 | int c = signed_char2int(*p++); | 5523 | int c = signed_char2int(*p++); |
5470 | if (!c) | 5524 | if (!c) |
5471 | continue; | 5525 | continue; |
5472 | if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK)) | 5526 | if (quotes) { |
5473 | USTPUTC(CTLESC, q); | 5527 | int n = SIT(c, syntax); |
5528 | if (n == CCTL || n == CBACK) | ||
5529 | USTPUTC(CTLESC, q); | ||
5530 | } | ||
5474 | USTPUTC(c, q); | 5531 | USTPUTC(c, q); |
5475 | } | 5532 | } |
5476 | 5533 | ||
@@ -5547,13 +5604,13 @@ removerecordregions(int endoff) | |||
5547 | } | 5604 | } |
5548 | 5605 | ||
5549 | static char * | 5606 | static char * |
5550 | exptilde(char *startp, char *p, int flag) | 5607 | exptilde(char *startp, char *p, int flags) |
5551 | { | 5608 | { |
5552 | char c; | 5609 | char c; |
5553 | char *name; | 5610 | char *name; |
5554 | struct passwd *pw; | 5611 | struct passwd *pw; |
5555 | const char *home; | 5612 | const char *home; |
5556 | int quotes = flag & (EXP_FULL | EXP_CASE); | 5613 | int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR); |
5557 | int startloc; | 5614 | int startloc; |
5558 | 5615 | ||
5559 | name = p + 1; | 5616 | name = p + 1; |
@@ -5565,7 +5622,7 @@ exptilde(char *startp, char *p, int flag) | |||
5565 | case CTLQUOTEMARK: | 5622 | case CTLQUOTEMARK: |
5566 | return startp; | 5623 | return startp; |
5567 | case ':': | 5624 | case ':': |
5568 | if (flag & EXP_VARTILDE) | 5625 | if (flags & EXP_VARTILDE) |
5569 | goto done; | 5626 | goto done; |
5570 | break; | 5627 | break; |
5571 | case '/': | 5628 | case '/': |
@@ -5770,7 +5827,7 @@ expari(int quotes) | |||
5770 | expdest = p; | 5827 | expdest = p; |
5771 | 5828 | ||
5772 | if (quotes) | 5829 | if (quotes) |
5773 | rmescapes(p + 2); | 5830 | rmescapes(p + 2, 0); |
5774 | 5831 | ||
5775 | len = cvtnum(ash_arith(p + 2)); | 5832 | len = cvtnum(ash_arith(p + 2)); |
5776 | 5833 | ||
@@ -5780,7 +5837,7 @@ expari(int quotes) | |||
5780 | #endif | 5837 | #endif |
5781 | 5838 | ||
5782 | /* argstr needs it */ | 5839 | /* argstr needs it */ |
5783 | static char *evalvar(char *p, int flag, struct strlist *var_str_list); | 5840 | static char *evalvar(char *p, int flags, struct strlist *var_str_list); |
5784 | 5841 | ||
5785 | /* | 5842 | /* |
5786 | * Perform variable and command substitution. If EXP_FULL is set, output CTLESC | 5843 | * Perform variable and command substitution. If EXP_FULL is set, output CTLESC |
@@ -5792,7 +5849,7 @@ static char *evalvar(char *p, int flag, struct strlist *var_str_list); | |||
5792 | * for correct expansion of "B=$A" word. | 5849 | * for correct expansion of "B=$A" word. |
5793 | */ | 5850 | */ |
5794 | static void | 5851 | static void |
5795 | argstr(char *p, int flag, struct strlist *var_str_list) | 5852 | argstr(char *p, int flags, struct strlist *var_str_list) |
5796 | { | 5853 | { |
5797 | static const char spclchars[] ALIGN1 = { | 5854 | static const char spclchars[] ALIGN1 = { |
5798 | '=', | 5855 | '=', |
@@ -5810,42 +5867,44 @@ argstr(char *p, int flag, struct strlist *var_str_list) | |||
5810 | }; | 5867 | }; |
5811 | const char *reject = spclchars; | 5868 | const char *reject = spclchars; |
5812 | int c; | 5869 | int c; |
5813 | int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR); /* do CTLESC */ | 5870 | int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR); /* do CTLESC */ |
5814 | int breakall = flag & EXP_WORD; | 5871 | int breakall = flags & EXP_WORD; |
5815 | int inquotes; | 5872 | int inquotes; |
5816 | size_t length; | 5873 | size_t length; |
5817 | int startloc; | 5874 | int startloc; |
5818 | 5875 | ||
5819 | if (!(flag & EXP_VARTILDE)) { | 5876 | if (!(flags & EXP_VARTILDE)) { |
5820 | reject += 2; | 5877 | reject += 2; |
5821 | } else if (flag & EXP_VARTILDE2) { | 5878 | } else if (flags & EXP_VARTILDE2) { |
5822 | reject++; | 5879 | reject++; |
5823 | } | 5880 | } |
5824 | inquotes = 0; | 5881 | inquotes = 0; |
5825 | length = 0; | 5882 | length = 0; |
5826 | if (flag & EXP_TILDE) { | 5883 | if (flags & EXP_TILDE) { |
5827 | char *q; | 5884 | char *q; |
5828 | 5885 | ||
5829 | flag &= ~EXP_TILDE; | 5886 | flags &= ~EXP_TILDE; |
5830 | tilde: | 5887 | tilde: |
5831 | q = p; | 5888 | q = p; |
5832 | if (*q == CTLESC && (flag & EXP_QWORD)) | 5889 | if (*q == CTLESC && (flags & EXP_QWORD)) |
5833 | q++; | 5890 | q++; |
5834 | if (*q == '~') | 5891 | if (*q == '~') |
5835 | p = exptilde(p, q, flag); | 5892 | p = exptilde(p, q, flags); |
5836 | } | 5893 | } |
5837 | start: | 5894 | start: |
5838 | startloc = expdest - (char *)stackblock(); | 5895 | startloc = expdest - (char *)stackblock(); |
5839 | for (;;) { | 5896 | for (;;) { |
5840 | length += strcspn(p + length, reject); | 5897 | length += strcspn(p + length, reject); |
5841 | c = p[length]; | 5898 | c = (unsigned char) p[length]; |
5842 | if (c && (!(c & 0x80) | 5899 | if (c) { |
5900 | if (!(c & 0x80) | ||
5843 | #if ENABLE_SH_MATH_SUPPORT | 5901 | #if ENABLE_SH_MATH_SUPPORT |
5844 | || c == CTLENDARI | 5902 | || c == CTLENDARI |
5845 | #endif | 5903 | #endif |
5846 | )) { | 5904 | ) { |
5847 | /* c == '=' || c == ':' || c == CTLENDARI */ | 5905 | /* c == '=' || c == ':' || c == CTLENDARI */ |
5848 | length++; | 5906 | length++; |
5907 | } | ||
5849 | } | 5908 | } |
5850 | if (length > 0) { | 5909 | if (length > 0) { |
5851 | int newloc; | 5910 | int newloc; |
@@ -5863,11 +5922,11 @@ argstr(char *p, int flag, struct strlist *var_str_list) | |||
5863 | case '\0': | 5922 | case '\0': |
5864 | goto breakloop; | 5923 | goto breakloop; |
5865 | case '=': | 5924 | case '=': |
5866 | if (flag & EXP_VARTILDE2) { | 5925 | if (flags & EXP_VARTILDE2) { |
5867 | p--; | 5926 | p--; |
5868 | continue; | 5927 | continue; |
5869 | } | 5928 | } |
5870 | flag |= EXP_VARTILDE2; | 5929 | flags |= EXP_VARTILDE2; |
5871 | reject++; | 5930 | reject++; |
5872 | /* fall through */ | 5931 | /* fall through */ |
5873 | case ':': | 5932 | case ':': |
@@ -5886,15 +5945,13 @@ argstr(char *p, int flag, struct strlist *var_str_list) | |||
5886 | goto breakloop; | 5945 | goto breakloop; |
5887 | case CTLQUOTEMARK: | 5946 | case CTLQUOTEMARK: |
5888 | /* "$@" syntax adherence hack */ | 5947 | /* "$@" syntax adherence hack */ |
5889 | if ( | 5948 | if (!inquotes |
5890 | !inquotes && | 5949 | && memcmp(p, dolatstr, 4) == 0 |
5891 | !memcmp(p, dolatstr, 4) && | 5950 | && ( p[4] == CTLQUOTEMARK |
5892 | (p[4] == CTLQUOTEMARK || ( | 5951 | || (p[4] == CTLENDVAR && p[5] == CTLQUOTEMARK) |
5893 | p[4] == CTLENDVAR && | 5952 | ) |
5894 | p[5] == CTLQUOTEMARK | ||
5895 | )) | ||
5896 | ) { | 5953 | ) { |
5897 | p = evalvar(p + 1, flag, /* var_str_list: */ NULL) + 1; | 5954 | p = evalvar(p + 1, flags, /* var_str_list: */ NULL) + 1; |
5898 | goto start; | 5955 | goto start; |
5899 | } | 5956 | } |
5900 | inquotes = !inquotes; | 5957 | inquotes = !inquotes; |
@@ -5910,10 +5967,10 @@ argstr(char *p, int flag, struct strlist *var_str_list) | |||
5910 | length++; | 5967 | length++; |
5911 | goto addquote; | 5968 | goto addquote; |
5912 | case CTLVAR: | 5969 | case CTLVAR: |
5913 | p = evalvar(p, flag, var_str_list); | 5970 | p = evalvar(p, flags, var_str_list); |
5914 | goto start; | 5971 | goto start; |
5915 | case CTLBACKQ: | 5972 | case CTLBACKQ: |
5916 | c = 0; | 5973 | c = '\0'; |
5917 | case CTLBACKQ|CTLQUOTE: | 5974 | case CTLBACKQ|CTLQUOTE: |
5918 | expbackq(argbackq->n, c, quotes); | 5975 | expbackq(argbackq->n, c, quotes); |
5919 | argbackq = argbackq->next; | 5976 | argbackq = argbackq->next; |
@@ -6119,15 +6176,15 @@ subevalvar(char *p, char *str, int strloc, int subtype, | |||
6119 | #if ENABLE_ASH_BASH_COMPAT | 6176 | #if ENABLE_ASH_BASH_COMPAT |
6120 | case VSSUBSTR: | 6177 | case VSSUBSTR: |
6121 | loc = str = stackblock() + strloc; | 6178 | loc = str = stackblock() + strloc; |
6122 | // TODO: number() instead? It does error checking... | 6179 | /* Read POS in ${var:POS:LEN} */ |
6123 | pos = atoi(loc); | 6180 | pos = atoi(loc); /* number(loc) errors out on "1:4" */ |
6124 | len = str - startp - 1; | 6181 | len = str - startp - 1; |
6125 | 6182 | ||
6126 | /* *loc != '\0', guaranteed by parser */ | 6183 | /* *loc != '\0', guaranteed by parser */ |
6127 | if (quotes) { | 6184 | if (quotes) { |
6128 | char *ptr; | 6185 | char *ptr; |
6129 | 6186 | ||
6130 | /* We must adjust the length by the number of escapes we find. */ | 6187 | /* Adjust the length by the number of escapes */ |
6131 | for (ptr = startp; ptr < (str - 1); ptr++) { | 6188 | for (ptr = startp; ptr < (str - 1); ptr++) { |
6132 | if (*ptr == CTLESC) { | 6189 | if (*ptr == CTLESC) { |
6133 | len--; | 6190 | len--; |
@@ -6138,15 +6195,22 @@ subevalvar(char *p, char *str, int strloc, int subtype, | |||
6138 | orig_len = len; | 6195 | orig_len = len; |
6139 | 6196 | ||
6140 | if (*loc++ == ':') { | 6197 | if (*loc++ == ':') { |
6141 | // TODO: number() instead? It does error checking... | 6198 | /* ${var::LEN} */ |
6142 | len = atoi(loc); | 6199 | len = number(loc); |
6143 | } else { | 6200 | } else { |
6201 | /* Skip POS in ${var:POS:LEN} */ | ||
6144 | len = orig_len; | 6202 | len = orig_len; |
6145 | while (*loc && *loc != ':') | 6203 | while (*loc && *loc != ':') { |
6204 | /* TODO? | ||
6205 | * bash complains on: var=qwe; echo ${var:1a:123} | ||
6206 | if (!isdigit(*loc)) | ||
6207 | ash_msg_and_raise_error(msg_illnum, str); | ||
6208 | */ | ||
6146 | loc++; | 6209 | loc++; |
6147 | if (*loc++ == ':') | 6210 | } |
6148 | // TODO: number() instead? It does error checking... | 6211 | if (*loc++ == ':') { |
6149 | len = atoi(loc); | 6212 | len = number(loc); |
6213 | } | ||
6150 | } | 6214 | } |
6151 | if (pos >= orig_len) { | 6215 | if (pos >= orig_len) { |
6152 | pos = 0; | 6216 | pos = 0; |
@@ -6190,7 +6254,7 @@ subevalvar(char *p, char *str, int strloc, int subtype, | |||
6190 | rmesc = startp; | 6254 | rmesc = startp; |
6191 | rmescend = (char *)stackblock() + strloc; | 6255 | rmescend = (char *)stackblock() + strloc; |
6192 | if (quotes) { | 6256 | if (quotes) { |
6193 | rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW); | 6257 | rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW); |
6194 | if (rmesc != startp) { | 6258 | if (rmesc != startp) { |
6195 | rmescend = expdest; | 6259 | rmescend = expdest; |
6196 | startp = (char *)stackblock() + startloc; | 6260 | startp = (char *)stackblock() + startloc; |
@@ -6321,7 +6385,7 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list) | |||
6321 | int syntax; | 6385 | int syntax; |
6322 | int quoted = varflags & VSQUOTE; | 6386 | int quoted = varflags & VSQUOTE; |
6323 | int subtype = varflags & VSTYPE; | 6387 | int subtype = varflags & VSTYPE; |
6324 | int quotes = flags & (EXP_FULL | EXP_CASE); | 6388 | int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR); |
6325 | 6389 | ||
6326 | if (quoted && (flags & EXP_FULL)) | 6390 | if (quoted && (flags & EXP_FULL)) |
6327 | sep = 1 << CHAR_BIT; | 6391 | sep = 1 << CHAR_BIT; |
@@ -6365,7 +6429,7 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list) | |||
6365 | ap = shellparam.p; | 6429 | ap = shellparam.p; |
6366 | if (!ap) | 6430 | if (!ap) |
6367 | return -1; | 6431 | return -1; |
6368 | while ((p = *ap++)) { | 6432 | while ((p = *ap++) != NULL) { |
6369 | size_t partlen; | 6433 | size_t partlen; |
6370 | 6434 | ||
6371 | partlen = strlen(p); | 6435 | partlen = strlen(p); |
@@ -6399,8 +6463,7 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list) | |||
6399 | case '7': | 6463 | case '7': |
6400 | case '8': | 6464 | case '8': |
6401 | case '9': | 6465 | case '9': |
6402 | // TODO: number() instead? It does error checking... | 6466 | num = atoi(name); /* number(name) fails on ${N#str} etc */ |
6403 | num = atoi(name); | ||
6404 | if (num < 0 || num > shellparam.nparam) | 6467 | if (num < 0 || num > shellparam.nparam) |
6405 | return -1; | 6468 | return -1; |
6406 | p = num ? shellparam.p[num - 1] : arg0; | 6469 | p = num ? shellparam.p[num - 1] : arg0; |
@@ -6452,7 +6515,7 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list) | |||
6452 | * input string. | 6515 | * input string. |
6453 | */ | 6516 | */ |
6454 | static char * | 6517 | static char * |
6455 | evalvar(char *p, int flag, struct strlist *var_str_list) | 6518 | evalvar(char *p, int flags, struct strlist *var_str_list) |
6456 | { | 6519 | { |
6457 | char varflags; | 6520 | char varflags; |
6458 | char subtype; | 6521 | char subtype; |
@@ -6463,7 +6526,7 @@ evalvar(char *p, int flag, struct strlist *var_str_list) | |||
6463 | int startloc; | 6526 | int startloc; |
6464 | ssize_t varlen; | 6527 | ssize_t varlen; |
6465 | 6528 | ||
6466 | varflags = *p++; | 6529 | varflags = (unsigned char) *p++; |
6467 | subtype = varflags & VSTYPE; | 6530 | subtype = varflags & VSTYPE; |
6468 | quoted = varflags & VSQUOTE; | 6531 | quoted = varflags & VSQUOTE; |
6469 | var = p; | 6532 | var = p; |
@@ -6472,7 +6535,7 @@ evalvar(char *p, int flag, struct strlist *var_str_list) | |||
6472 | p = strchr(p, '=') + 1; | 6535 | p = strchr(p, '=') + 1; |
6473 | 6536 | ||
6474 | again: | 6537 | again: |
6475 | varlen = varvalue(var, varflags, flag, var_str_list); | 6538 | varlen = varvalue(var, varflags, flags, var_str_list); |
6476 | if (varflags & VSNUL) | 6539 | if (varflags & VSNUL) |
6477 | varlen--; | 6540 | varlen--; |
6478 | 6541 | ||
@@ -6485,8 +6548,8 @@ evalvar(char *p, int flag, struct strlist *var_str_list) | |||
6485 | vsplus: | 6548 | vsplus: |
6486 | if (varlen < 0) { | 6549 | if (varlen < 0) { |
6487 | argstr( | 6550 | argstr( |
6488 | p, flag | EXP_TILDE | | 6551 | p, flags | EXP_TILDE | |
6489 | (quoted ? EXP_QWORD : EXP_WORD), | 6552 | (quoted ? EXP_QWORD : EXP_WORD), |
6490 | var_str_list | 6553 | var_str_list |
6491 | ); | 6554 | ); |
6492 | goto end; | 6555 | goto end; |
@@ -6558,7 +6621,8 @@ evalvar(char *p, int flag, struct strlist *var_str_list) | |||
6558 | patloc = expdest - (char *)stackblock(); | 6621 | patloc = expdest - (char *)stackblock(); |
6559 | if (0 == subevalvar(p, /* str: */ NULL, patloc, subtype, | 6622 | if (0 == subevalvar(p, /* str: */ NULL, patloc, subtype, |
6560 | startloc, varflags, | 6623 | startloc, varflags, |
6561 | /* quotes: */ flag & (EXP_FULL | EXP_CASE), | 6624 | //TODO: | EXP_REDIR too? All other such places do it too |
6625 | /* quotes: */ flags & (EXP_FULL | EXP_CASE), | ||
6562 | var_str_list) | 6626 | var_str_list) |
6563 | ) { | 6627 | ) { |
6564 | int amount = expdest - ( | 6628 | int amount = expdest - ( |
@@ -6812,7 +6876,7 @@ expmeta(char *enddir, char *name) | |||
6812 | p++; | 6876 | p++; |
6813 | if (*p == '.') | 6877 | if (*p == '.') |
6814 | matchdot++; | 6878 | matchdot++; |
6815 | while (!intpending && (dp = readdir(dirp)) != NULL) { | 6879 | while (!pending_int && (dp = readdir(dirp)) != NULL) { |
6816 | if (dp->d_name[0] == '.' && !matchdot) | 6880 | if (dp->d_name[0] == '.' && !matchdot) |
6817 | continue; | 6881 | continue; |
6818 | if (pmatch(start, dp->d_name)) { | 6882 | if (pmatch(start, dp->d_name)) { |
@@ -6933,7 +6997,7 @@ expandmeta(struct strlist *str /*, int flag*/) | |||
6933 | */ | 6997 | */ |
6934 | nometa: | 6998 | nometa: |
6935 | *exparg.lastp = str; | 6999 | *exparg.lastp = str; |
6936 | rmescapes(str->text); | 7000 | rmescapes(str->text, 0); |
6937 | exparg.lastp = &str->next; | 7001 | exparg.lastp = &str->next; |
6938 | } else { | 7002 | } else { |
6939 | *exparg.lastp = NULL; | 7003 | *exparg.lastp = NULL; |
@@ -6981,7 +7045,7 @@ expandarg(union node *arg, struct arglist *arglist, int flag) | |||
6981 | expandmeta(exparg.list /*, flag*/); | 7045 | expandmeta(exparg.list /*, flag*/); |
6982 | } else { | 7046 | } else { |
6983 | if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */ | 7047 | if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */ |
6984 | rmescapes(p); | 7048 | rmescapes(p, 0); |
6985 | sp = stzalloc(sizeof(*sp)); | 7049 | sp = stzalloc(sizeof(*sp)); |
6986 | sp->text = p; | 7050 | sp->text = p; |
6987 | *exparg.lastp = sp; | 7051 | *exparg.lastp = sp; |
@@ -7206,8 +7270,8 @@ shellexec(char **argv, const char *path, int idx) | |||
7206 | break; | 7270 | break; |
7207 | } | 7271 | } |
7208 | exitstatus = exerrno; | 7272 | exitstatus = exerrno; |
7209 | TRACE(("shellexec failed for %s, errno %d, suppressint %d\n", | 7273 | TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n", |
7210 | argv[0], e, suppressint)); | 7274 | argv[0], e, suppress_int)); |
7211 | ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found")); | 7275 | ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found")); |
7212 | /* NOTREACHED */ | 7276 | /* NOTREACHED */ |
7213 | } | 7277 | } |
@@ -8009,7 +8073,7 @@ dotrap(void) | |||
8009 | uint8_t savestatus; | 8073 | uint8_t savestatus; |
8010 | 8074 | ||
8011 | savestatus = exitstatus; | 8075 | savestatus = exitstatus; |
8012 | pendingsig = 0; | 8076 | pending_sig = 0; |
8013 | xbarrier(); | 8077 | xbarrier(); |
8014 | 8078 | ||
8015 | TRACE(("dotrap entered\n")); | 8079 | TRACE(("dotrap entered\n")); |
@@ -8189,7 +8253,7 @@ evaltree(union node *n, int flags) | |||
8189 | out1: | 8253 | out1: |
8190 | if (checkexit & exitstatus) | 8254 | if (checkexit & exitstatus) |
8191 | evalskip |= SKIPEVAL; | 8255 | evalskip |= SKIPEVAL; |
8192 | else if (pendingsig && dotrap()) | 8256 | else if (pending_sig && dotrap()) |
8193 | goto exexit; | 8257 | goto exexit; |
8194 | 8258 | ||
8195 | if (flags & EV_EXIT) { | 8259 | if (flags & EV_EXIT) { |
@@ -9109,7 +9173,7 @@ evalcommand(union node *cmd, int flags) | |||
9109 | if (i == EXINT) | 9173 | if (i == EXINT) |
9110 | exit_status = 128 + SIGINT; | 9174 | exit_status = 128 + SIGINT; |
9111 | if (i == EXSIG) | 9175 | if (i == EXSIG) |
9112 | exit_status = 128 + pendingsig; | 9176 | exit_status = 128 + pending_sig; |
9113 | exitstatus = exit_status; | 9177 | exitstatus = exit_status; |
9114 | if (i == EXINT || spclbltin > 0) { | 9178 | if (i == EXINT || spclbltin > 0) { |
9115 | raise: | 9179 | raise: |
@@ -9163,7 +9227,6 @@ evalbltin(const struct builtincmd *cmd, int argc, char **argv) | |||
9163 | exitstatus |= ferror(stdout); | 9227 | exitstatus |= ferror(stdout); |
9164 | clearerr(stdout); | 9228 | clearerr(stdout); |
9165 | commandname = savecmdname; | 9229 | commandname = savecmdname; |
9166 | // exsig = 0; | ||
9167 | exception_handler = savehandler; | 9230 | exception_handler = savehandler; |
9168 | 9231 | ||
9169 | return i; | 9232 | return i; |
@@ -9214,7 +9277,7 @@ breakcmd(int argc UNUSED_PARAM, char **argv) | |||
9214 | int n = argv[1] ? number(argv[1]) : 1; | 9277 | int n = argv[1] ? number(argv[1]) : 1; |
9215 | 9278 | ||
9216 | if (n <= 0) | 9279 | if (n <= 0) |
9217 | ash_msg_and_raise_error(illnum, argv[1]); | 9280 | ash_msg_and_raise_error(msg_illnum, argv[1]); |
9218 | if (n > loopnest) | 9281 | if (n > loopnest) |
9219 | n = loopnest; | 9282 | n = loopnest; |
9220 | if (n > 0) { | 9283 | if (n > 0) { |
@@ -10022,7 +10085,7 @@ change_random(const char *value) | |||
10022 | vrandom.flags &= ~VNOFUNC; | 10085 | vrandom.flags &= ~VNOFUNC; |
10023 | } else { | 10086 | } else { |
10024 | /* set/reset */ | 10087 | /* set/reset */ |
10025 | random_galois_LFSR = random_LCG = strtoul(value, (char **)NULL, 10); | 10088 | random_galois_LFSR = random_LCG = strtoul(value, NULL, 10); |
10026 | } | 10089 | } |
10027 | } | 10090 | } |
10028 | #endif | 10091 | #endif |
@@ -10406,7 +10469,7 @@ parsefname(void) | |||
10406 | TRACE(("Here document %d\n", n->type)); | 10469 | TRACE(("Here document %d\n", n->type)); |
10407 | if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN) | 10470 | if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN) |
10408 | raise_error_syntax("illegal eof marker for << redirection"); | 10471 | raise_error_syntax("illegal eof marker for << redirection"); |
10409 | rmescapes(wordtext); | 10472 | rmescapes(wordtext, 0); |
10410 | here->eofmark = wordtext; | 10473 | here->eofmark = wordtext; |
10411 | here->next = NULL; | 10474 | here->next = NULL; |
10412 | if (heredoclist == NULL) | 10475 | if (heredoclist == NULL) |
@@ -12202,14 +12265,30 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
12202 | ap = argptr; | 12265 | ap = argptr; |
12203 | if (!*ap) { | 12266 | if (!*ap) { |
12204 | for (signo = 0; signo < NSIG; signo++) { | 12267 | for (signo = 0; signo < NSIG; signo++) { |
12205 | if (trap[signo] != NULL) { | 12268 | char *tr = trap_ptr[signo]; |
12269 | if (tr) { | ||
12270 | /* note: bash adds "SIG", but only if invoked | ||
12271 | * as "bash". If called as "sh", or if set -o posix, | ||
12272 | * then it prints short signal names. | ||
12273 | * We are printing short names: */ | ||
12206 | out1fmt("trap -- %s %s\n", | 12274 | out1fmt("trap -- %s %s\n", |
12207 | single_quote(trap[signo]), | 12275 | single_quote(tr), |
12208 | get_signame(signo)); | 12276 | get_signame(signo)); |
12277 | /* trap_ptr != trap only if we are in special-cased `trap` code. | ||
12278 | * In this case, we will exit very soon, no need to free(). */ | ||
12279 | /* if (trap_ptr != trap && tp[0]) */ | ||
12280 | /* free(tr); */ | ||
12209 | } | 12281 | } |
12210 | } | 12282 | } |
12283 | /* | ||
12284 | if (trap_ptr != trap) { | ||
12285 | free(trap_ptr); | ||
12286 | trap_ptr = trap; | ||
12287 | } | ||
12288 | */ | ||
12211 | return 0; | 12289 | return 0; |
12212 | } | 12290 | } |
12291 | |||
12213 | action = NULL; | 12292 | action = NULL; |
12214 | if (ap[1]) | 12293 | if (ap[1]) |
12215 | action = *ap++; | 12294 | action = *ap++; |
@@ -12705,7 +12784,7 @@ umaskcmd(int argc UNUSED_PARAM, char **argv) | |||
12705 | mask = 0; | 12784 | mask = 0; |
12706 | do { | 12785 | do { |
12707 | if (*ap >= '8' || *ap < '0') | 12786 | if (*ap >= '8' || *ap < '0') |
12708 | ash_msg_and_raise_error(illnum, argv[1]); | 12787 | ash_msg_and_raise_error(msg_illnum, argv[1]); |
12709 | mask = (mask << 3) + (*ap - '0'); | 12788 | mask = (mask << 3) + (*ap - '0'); |
12710 | } while (*++ap != '\0'); | 12789 | } while (*++ap != '\0'); |
12711 | umask(mask); | 12790 | umask(mask); |
@@ -12966,6 +13045,7 @@ exitshell(void) | |||
12966 | if (p) { | 13045 | if (p) { |
12967 | trap[0] = NULL; | 13046 | trap[0] = NULL; |
12968 | evalstring(p, 0); | 13047 | evalstring(p, 0); |
13048 | free(p); | ||
12969 | } | 13049 | } |
12970 | flush_stdout_stderr(); | 13050 | flush_stdout_stderr(); |
12971 | out: | 13051 | out: |
@@ -12986,7 +13066,7 @@ init(void) | |||
12986 | /* from var.c: */ | 13066 | /* from var.c: */ |
12987 | { | 13067 | { |
12988 | char **envp; | 13068 | char **envp; |
12989 | char ppid[sizeof(int)*3 + 1]; | 13069 | char ppid[sizeof(int)*3 + 2]; |
12990 | const char *p; | 13070 | const char *p; |
12991 | struct stat st1, st2; | 13071 | struct stat st1, st2; |
12992 | 13072 | ||
@@ -12997,7 +13077,7 @@ init(void) | |||
12997 | } | 13077 | } |
12998 | } | 13078 | } |
12999 | 13079 | ||
13000 | snprintf(ppid, sizeof(ppid), "%u", (unsigned) getppid()); | 13080 | sprintf(ppid, "%u", (unsigned) getppid()); |
13001 | setvar("PPID", ppid, 0); | 13081 | setvar("PPID", ppid, 0); |
13002 | 13082 | ||
13003 | p = lookupvar("PWD"); | 13083 | p = lookupvar("PWD"); |
@@ -13237,7 +13317,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
13237 | } | 13317 | } |
13238 | 13318 | ||
13239 | if (sflag || minusc == NULL) { | 13319 | if (sflag || minusc == NULL) { |
13240 | #if ENABLE_FEATURE_EDITING_SAVEHISTORY | 13320 | #if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY |
13241 | if (iflag) { | 13321 | if (iflag) { |
13242 | const char *hp = lookupvar("HISTFILE"); | 13322 | const char *hp = lookupvar("HISTFILE"); |
13243 | if (hp) | 13323 | if (hp) |
diff --git a/shell/ash_test/ash-redir/redir7.right b/shell/ash_test/ash-redir/redir7.right new file mode 100644 index 000000000..6430b0211 --- /dev/null +++ b/shell/ash_test/ash-redir/redir7.right | |||
@@ -0,0 +1,3 @@ | |||
1 | Ok | ||
2 | Ok | ||
3 | Done | ||
diff --git a/shell/ash_test/ash-redir/redir7.tests b/shell/ash_test/ash-redir/redir7.tests new file mode 100755 index 000000000..17d1040e0 --- /dev/null +++ b/shell/ash_test/ash-redir/redir7.tests | |||
@@ -0,0 +1,12 @@ | |||
1 | # Chars above 0x7f are used as special codes. | ||
2 | # 0x81 is CTLESC (see ash.c). | ||
3 | # The bug was that quoting and unquoting of them | ||
4 | # was out of sync for redirect filenames. | ||
5 | |||
6 | >unicode.sh | ||
7 | echo -e 'echo Ok >uni\x81code' >>unicode.sh | ||
8 | echo -e 'cat uni\x81code' >>unicode.sh | ||
9 | echo -e 'cat uni?code' >>unicode.sh | ||
10 | . unicode.sh | ||
11 | rm uni*code* | ||
12 | echo Done | ||
diff --git a/shell/ash_test/ash-redir/redir8.right b/shell/ash_test/ash-redir/redir8.right new file mode 100644 index 000000000..6430b0211 --- /dev/null +++ b/shell/ash_test/ash-redir/redir8.right | |||
@@ -0,0 +1,3 @@ | |||
1 | Ok | ||
2 | Ok | ||
3 | Done | ||
diff --git a/shell/ash_test/ash-redir/redir8.tests b/shell/ash_test/ash-redir/redir8.tests new file mode 100755 index 000000000..32ab607b8 --- /dev/null +++ b/shell/ash_test/ash-redir/redir8.tests | |||
@@ -0,0 +1,15 @@ | |||
1 | # Chars above 0x7f are used as special codes. | ||
2 | # 0x81 is CTLESC (see ash.c). | ||
3 | # The bug was that quoting and unquoting of them | ||
4 | # was out of sync for redirect filenames. | ||
5 | |||
6 | # Subcase when redirect filename is specified in a variable. | ||
7 | |||
8 | >unicode.sh | ||
9 | echo -e 'v=uni\x81code' >>unicode.sh | ||
10 | echo -e 'echo Ok >"$v"' >>unicode.sh | ||
11 | echo -e 'cat uni\x81code' >>unicode.sh | ||
12 | echo -e 'cat uni?code' >>unicode.sh | ||
13 | . unicode.sh | ||
14 | rm uni*code* | ||
15 | echo Done | ||
diff --git a/shell/ash_test/ash-signals/savetrap.right b/shell/ash_test/ash-signals/savetrap.right new file mode 100644 index 000000000..a59225be3 --- /dev/null +++ b/shell/ash_test/ash-signals/savetrap.right | |||
@@ -0,0 +1,8 @@ | |||
1 | trap -- 'echo Exiting' EXIT | ||
2 | trap -- 'echo WINCH!' WINCH | ||
3 | trap -- 'echo Exiting' EXIT | ||
4 | trap -- 'echo WINCH!' WINCH | ||
5 | trap -- 'echo Exiting' EXIT | ||
6 | trap -- 'echo WINCH!' WINCH | ||
7 | Done | ||
8 | Exiting | ||
diff --git a/shell/ash_test/ash-signals/savetrap.tests b/shell/ash_test/ash-signals/savetrap.tests new file mode 100755 index 000000000..c2b312fb8 --- /dev/null +++ b/shell/ash_test/ash-signals/savetrap.tests | |||
@@ -0,0 +1,9 @@ | |||
1 | trap 'echo Exiting' EXIT | ||
2 | trap 'echo WINCH!' SIGWINCH | ||
3 | v=` trap ` | ||
4 | echo "$v" | ||
5 | v=$( trap ) | ||
6 | echo "$v" | ||
7 | v=`trap` | ||
8 | echo "$v" | ||
9 | echo Done | ||
diff --git a/shell/hush.c b/shell/hush.c index 5794b1ddf..b515eabd2 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -78,6 +78,7 @@ | |||
78 | * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. | 78 | * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. |
79 | */ | 79 | */ |
80 | #include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */ | 80 | #include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */ |
81 | #include <malloc.h> /* for malloc_trim */ | ||
81 | #include <glob.h> | 82 | #include <glob.h> |
82 | /* #include <dmalloc.h> */ | 83 | /* #include <dmalloc.h> */ |
83 | #if ENABLE_HUSH_CASE | 84 | #if ENABLE_HUSH_CASE |
@@ -786,7 +787,7 @@ static void xxfree(void *ptr) | |||
786 | * HUSH_DEBUG >= 2 prints line number in this file where it was detected. | 787 | * HUSH_DEBUG >= 2 prints line number in this file where it was detected. |
787 | */ | 788 | */ |
788 | #if HUSH_DEBUG < 2 | 789 | #if HUSH_DEBUG < 2 |
789 | # define die_if_script(lineno, fmt...) die_if_script(fmt) | 790 | # define die_if_script(lineno, ...) die_if_script(__VA_ARGS__) |
790 | # define syntax_error(lineno, msg) syntax_error(msg) | 791 | # define syntax_error(lineno, msg) syntax_error(msg) |
791 | # define syntax_error_at(lineno, msg) syntax_error_at(msg) | 792 | # define syntax_error_at(lineno, msg) syntax_error_at(msg) |
792 | # define syntax_error_unterm_ch(lineno, ch) syntax_error_unterm_ch(ch) | 793 | # define syntax_error_unterm_ch(lineno, ch) syntax_error_unterm_ch(ch) |
@@ -855,7 +856,7 @@ static void syntax_error_unexpected_ch(unsigned lineno, int ch) | |||
855 | # undef syntax_error_unterm_str | 856 | # undef syntax_error_unterm_str |
856 | # undef syntax_error_unexpected_ch | 857 | # undef syntax_error_unexpected_ch |
857 | #else | 858 | #else |
858 | # define die_if_script(fmt...) die_if_script(__LINE__, fmt) | 859 | # define die_if_script(...) die_if_script(__LINE__, __VA_ARGS__) |
859 | # define syntax_error(msg) syntax_error(__LINE__, msg) | 860 | # define syntax_error(msg) syntax_error(__LINE__, msg) |
860 | # define syntax_error_at(msg) syntax_error_at(__LINE__, msg) | 861 | # define syntax_error_at(msg) syntax_error_at(__LINE__, msg) |
861 | # define syntax_error_unterm_ch(ch) syntax_error_unterm_ch(__LINE__, ch) | 862 | # define syntax_error_unterm_ch(ch) syntax_error_unterm_ch(__LINE__, ch) |
@@ -898,7 +899,7 @@ static int is_well_formed_var_name(const char *s, char terminator) | |||
898 | /* Replace each \x with x in place, return ptr past NUL. */ | 899 | /* Replace each \x with x in place, return ptr past NUL. */ |
899 | static char *unbackslash(char *src) | 900 | static char *unbackslash(char *src) |
900 | { | 901 | { |
901 | char *dst = src; | 902 | char *dst = src = strchrnul(src, '\\'); |
902 | while (1) { | 903 | while (1) { |
903 | if (*src == '\\') | 904 | if (*src == '\\') |
904 | src++; | 905 | src++; |
@@ -1037,7 +1038,7 @@ static void restore_G_args(save_arg_t *sv, char **argv) | |||
1037 | * is finished or backgrounded. It is the same in interactive and | 1038 | * is finished or backgrounded. It is the same in interactive and |
1038 | * non-interactive shells, and is the same regardless of whether | 1039 | * non-interactive shells, and is the same regardless of whether |
1039 | * a user trap handler is installed or a shell special one is in effect. | 1040 | * a user trap handler is installed or a shell special one is in effect. |
1040 | * ^C or ^Z from keyboard seem to execute "at once" because it usually | 1041 | * ^C or ^Z from keyboard seems to execute "at once" because it usually |
1041 | * backgrounds (i.e. stops) or kills all members of currently running | 1042 | * backgrounds (i.e. stops) or kills all members of currently running |
1042 | * pipe. | 1043 | * pipe. |
1043 | * | 1044 | * |
@@ -1104,12 +1105,17 @@ static void restore_G_args(save_arg_t *sv, char **argv) | |||
1104 | * (child shell is not interactive), | 1105 | * (child shell is not interactive), |
1105 | * unset all traps (note: regardless of child shell's type - {}, (), etc) | 1106 | * unset all traps (note: regardless of child shell's type - {}, (), etc) |
1106 | * after [v]fork, if we plan to exec: | 1107 | * after [v]fork, if we plan to exec: |
1107 | * POSIX says pending signal mask is cleared in child - no need to clear it. | 1108 | * POSIX says fork clears pending signal mask in child - no need to clear it. |
1108 | * Restore blocked signal set to one inherited by shell just prior to exec. | 1109 | * Restore blocked signal set to one inherited by shell just prior to exec. |
1109 | * | 1110 | * |
1110 | * Note: as a result, we do not use signal handlers much. The only uses | 1111 | * Note: as a result, we do not use signal handlers much. The only uses |
1111 | * are to count SIGCHLDs | 1112 | * are to count SIGCHLDs |
1112 | * and to restore tty pgrp on signal-induced exit. | 1113 | * and to restore tty pgrp on signal-induced exit. |
1114 | * | ||
1115 | * Note 2 (compat): | ||
1116 | * Standard says "When a subshell is entered, traps that are not being ignored | ||
1117 | * are set to the default actions". bash interprets it so that traps which | ||
1118 | * are set to "" (ignore) are NOT reset to defaults. We do the same. | ||
1113 | */ | 1119 | */ |
1114 | enum { | 1120 | enum { |
1115 | SPECIAL_INTERACTIVE_SIGS = 0 | 1121 | SPECIAL_INTERACTIVE_SIGS = 0 |
@@ -2596,43 +2602,51 @@ static void reset_traps_to_defaults(void) | |||
2596 | { | 2602 | { |
2597 | /* This function is always called in a child shell | 2603 | /* This function is always called in a child shell |
2598 | * after fork (not vfork, NOMMU doesn't use this function). | 2604 | * after fork (not vfork, NOMMU doesn't use this function). |
2599 | * Child shells are not interactive. | ||
2600 | * SIGTTIN/SIGTTOU/SIGTSTP should not have special handling. | ||
2601 | * Testcase: (while :; do :; done) + ^Z should background. | ||
2602 | * Same goes for SIGTERM, SIGHUP, SIGINT. | ||
2603 | */ | 2605 | */ |
2604 | unsigned sig; | 2606 | unsigned sig; |
2605 | unsigned mask; | 2607 | unsigned mask; |
2606 | 2608 | ||
2609 | /* Child shells are not interactive. | ||
2610 | * SIGTTIN/SIGTTOU/SIGTSTP should not have special handling. | ||
2611 | * Testcase: (while :; do :; done) + ^Z should background. | ||
2612 | * Same goes for SIGTERM, SIGHUP, SIGINT. | ||
2613 | */ | ||
2607 | if (!G.traps && !(G.non_DFL_mask & SPECIAL_INTERACTIVE_SIGS)) | 2614 | if (!G.traps && !(G.non_DFL_mask & SPECIAL_INTERACTIVE_SIGS)) |
2608 | return; | 2615 | return; /* already no traps and no SPECIAL_INTERACTIVE_SIGS */ |
2609 | 2616 | ||
2610 | /* Stupid. It can be done with *single* &= op, but we can't use | 2617 | /* Switching off SPECIAL_INTERACTIVE_SIGS. |
2611 | * the fact that G.blocked_set is implemented as a bitmask... */ | 2618 | * Stupid. It can be done with *single* &= op, but we can't use |
2619 | * the fact that G.blocked_set is implemented as a bitmask | ||
2620 | * in libc... */ | ||
2612 | mask = (SPECIAL_INTERACTIVE_SIGS >> 1); | 2621 | mask = (SPECIAL_INTERACTIVE_SIGS >> 1); |
2613 | sig = 1; | 2622 | sig = 1; |
2614 | while (1) { | 2623 | while (1) { |
2615 | if (mask & 1) | 2624 | if (mask & 1) { |
2616 | sigdelset(&G.blocked_set, sig); | 2625 | /* Careful. Only if no trap or trap is not "" */ |
2626 | if (!G.traps || !G.traps[sig] || G.traps[sig][0]) | ||
2627 | sigdelset(&G.blocked_set, sig); | ||
2628 | } | ||
2617 | mask >>= 1; | 2629 | mask >>= 1; |
2618 | if (!mask) | 2630 | if (!mask) |
2619 | break; | 2631 | break; |
2620 | sig++; | 2632 | sig++; |
2621 | } | 2633 | } |
2622 | 2634 | /* Our homegrown sig mask is saner to work with :) */ | |
2623 | G.non_DFL_mask &= ~SPECIAL_INTERACTIVE_SIGS; | 2635 | G.non_DFL_mask &= ~SPECIAL_INTERACTIVE_SIGS; |
2636 | |||
2637 | /* Resetting all traps to default except empty ones */ | ||
2624 | mask = G.non_DFL_mask; | 2638 | mask = G.non_DFL_mask; |
2625 | if (G.traps) for (sig = 0; sig < NSIG; sig++, mask >>= 1) { | 2639 | if (G.traps) for (sig = 0; sig < NSIG; sig++, mask >>= 1) { |
2626 | if (!G.traps[sig]) | 2640 | if (!G.traps[sig] || !G.traps[sig][0]) |
2627 | continue; | 2641 | continue; |
2628 | free(G.traps[sig]); | 2642 | free(G.traps[sig]); |
2629 | G.traps[sig] = NULL; | 2643 | G.traps[sig] = NULL; |
2630 | /* There is no signal for 0 (EXIT) */ | 2644 | /* There is no signal for 0 (EXIT) */ |
2631 | if (sig == 0) | 2645 | if (sig == 0) |
2632 | continue; | 2646 | continue; |
2633 | /* There was a trap handler, we are removing it. | 2647 | /* There was a trap handler, we just removed it. |
2634 | * But if sig still has non-DFL handling, | 2648 | * But if sig still has non-DFL handling, |
2635 | * we should not unblock it. */ | 2649 | * we should not unblock the sig. */ |
2636 | if (mask & 1) | 2650 | if (mask & 1) |
2637 | continue; | 2651 | continue; |
2638 | sigdelset(&G.blocked_set, sig); | 2652 | sigdelset(&G.blocked_set, sig); |
@@ -3079,15 +3093,21 @@ static const struct built_in_command* find_builtin(const char *name) | |||
3079 | } | 3093 | } |
3080 | 3094 | ||
3081 | #if ENABLE_HUSH_FUNCTIONS | 3095 | #if ENABLE_HUSH_FUNCTIONS |
3082 | static const struct function *find_function(const char *name) | 3096 | static struct function **find_function_slot(const char *name) |
3083 | { | 3097 | { |
3084 | const struct function *funcp = G.top_func; | 3098 | struct function **funcpp = &G.top_func; |
3085 | while (funcp) { | 3099 | while (*funcpp) { |
3086 | if (strcmp(name, funcp->name) == 0) { | 3100 | if (strcmp(name, (*funcpp)->name) == 0) { |
3087 | break; | 3101 | break; |
3088 | } | 3102 | } |
3089 | funcp = funcp->next; | 3103 | funcpp = &(*funcpp)->next; |
3090 | } | 3104 | } |
3105 | return funcpp; | ||
3106 | } | ||
3107 | |||
3108 | static const struct function *find_function(const char *name) | ||
3109 | { | ||
3110 | const struct function *funcp = *find_function_slot(name); | ||
3091 | if (funcp) | 3111 | if (funcp) |
3092 | debug_printf_exec("found function '%s'\n", name); | 3112 | debug_printf_exec("found function '%s'\n", name); |
3093 | return funcp; | 3113 | return funcp; |
@@ -3096,18 +3116,11 @@ static const struct function *find_function(const char *name) | |||
3096 | /* Note: takes ownership on name ptr */ | 3116 | /* Note: takes ownership on name ptr */ |
3097 | static struct function *new_function(char *name) | 3117 | static struct function *new_function(char *name) |
3098 | { | 3118 | { |
3099 | struct function *funcp; | 3119 | struct function **funcpp = find_function_slot(name); |
3100 | struct function **funcpp = &G.top_func; | 3120 | struct function *funcp = *funcpp; |
3101 | 3121 | ||
3102 | while ((funcp = *funcpp) != NULL) { | 3122 | if (funcp != NULL) { |
3103 | struct command *cmd; | 3123 | struct command *cmd = funcp->parent_cmd; |
3104 | |||
3105 | if (strcmp(funcp->name, name) != 0) { | ||
3106 | funcpp = &funcp->next; | ||
3107 | continue; | ||
3108 | } | ||
3109 | |||
3110 | cmd = funcp->parent_cmd; | ||
3111 | debug_printf_exec("func %p parent_cmd %p\n", funcp, cmd); | 3124 | debug_printf_exec("func %p parent_cmd %p\n", funcp, cmd); |
3112 | if (!cmd) { | 3125 | if (!cmd) { |
3113 | debug_printf_exec("freeing & replacing function '%s'\n", funcp->name); | 3126 | debug_printf_exec("freeing & replacing function '%s'\n", funcp->name); |
@@ -3129,39 +3142,36 @@ static struct function *new_function(char *name) | |||
3129 | cmd->group_as_string = funcp->body_as_string; | 3142 | cmd->group_as_string = funcp->body_as_string; |
3130 | # endif | 3143 | # endif |
3131 | } | 3144 | } |
3132 | goto skip; | 3145 | } else { |
3146 | debug_printf_exec("remembering new function '%s'\n", name); | ||
3147 | funcp = *funcpp = xzalloc(sizeof(*funcp)); | ||
3148 | /*funcp->next = NULL;*/ | ||
3133 | } | 3149 | } |
3134 | debug_printf_exec("remembering new function '%s'\n", name); | 3150 | |
3135 | funcp = *funcpp = xzalloc(sizeof(*funcp)); | ||
3136 | /*funcp->next = NULL;*/ | ||
3137 | skip: | ||
3138 | funcp->name = name; | 3151 | funcp->name = name; |
3139 | return funcp; | 3152 | return funcp; |
3140 | } | 3153 | } |
3141 | 3154 | ||
3142 | static void unset_func(const char *name) | 3155 | static void unset_func(const char *name) |
3143 | { | 3156 | { |
3144 | struct function *funcp; | 3157 | struct function **funcpp = find_function_slot(name); |
3145 | struct function **funcpp = &G.top_func; | 3158 | struct function *funcp = *funcpp; |
3146 | 3159 | ||
3147 | while ((funcp = *funcpp) != NULL) { | 3160 | if (funcp != NULL) { |
3148 | if (strcmp(funcp->name, name) == 0) { | 3161 | debug_printf_exec("freeing function '%s'\n", funcp->name); |
3149 | *funcpp = funcp->next; | 3162 | *funcpp = funcp->next; |
3150 | /* funcp is unlinked now, deleting it. | 3163 | /* funcp is unlinked now, deleting it. |
3151 | * Note: if !funcp->body, the function was created by | 3164 | * Note: if !funcp->body, the function was created by |
3152 | * "-F name body", do not free ->body_as_string | 3165 | * "-F name body", do not free ->body_as_string |
3153 | * and ->name as they were not malloced. */ | 3166 | * and ->name as they were not malloced. */ |
3154 | if (funcp->body) { | 3167 | if (funcp->body) { |
3155 | free_pipe_list(funcp->body); | 3168 | free_pipe_list(funcp->body); |
3156 | free(funcp->name); | 3169 | free(funcp->name); |
3157 | # if !BB_MMU | 3170 | # if !BB_MMU |
3158 | free(funcp->body_as_string); | 3171 | free(funcp->body_as_string); |
3159 | # endif | 3172 | # endif |
3160 | } | ||
3161 | free(funcp); | ||
3162 | break; | ||
3163 | } | 3173 | } |
3164 | funcpp = &funcp->next; | 3174 | free(funcp); |
3165 | } | 3175 | } |
3166 | } | 3176 | } |
3167 | 3177 | ||
@@ -3628,9 +3638,9 @@ static int checkjobs(struct pipe* fg_pipe) | |||
3628 | /* Note: is WIFSIGNALED, WEXITSTATUS = sig + 128 */ | 3638 | /* Note: is WIFSIGNALED, WEXITSTATUS = sig + 128 */ |
3629 | rcode = WEXITSTATUS(status); | 3639 | rcode = WEXITSTATUS(status); |
3630 | IF_HAS_KEYWORDS(if (fg_pipe->pi_inverted) rcode = !rcode;) | 3640 | IF_HAS_KEYWORDS(if (fg_pipe->pi_inverted) rcode = !rcode;) |
3631 | /* bash prints killing signal's name for *last* | 3641 | /* bash prints killer signal's name for *last* |
3632 | * process in pipe (prints just newline for SIGINT). | 3642 | * process in pipe (prints just newline for SIGINT). |
3633 | * Mimic this. Example: "sleep 5" + ^\ | 3643 | * Mimic this. Example: "sleep 5" + (^\ or kill -QUIT) |
3634 | */ | 3644 | */ |
3635 | if (WIFSIGNALED(status)) { | 3645 | if (WIFSIGNALED(status)) { |
3636 | int sig = WTERMSIG(status); | 3646 | int sig = WTERMSIG(status); |
@@ -5183,6 +5193,47 @@ static FILE *generate_stream_from_string(const char *s) | |||
5183 | xmove_fd(channel[1], 1); | 5193 | xmove_fd(channel[1], 1); |
5184 | /* Prevent it from trying to handle ctrl-z etc */ | 5194 | /* Prevent it from trying to handle ctrl-z etc */ |
5185 | IF_HUSH_JOB(G.run_list_level = 1;) | 5195 | IF_HUSH_JOB(G.run_list_level = 1;) |
5196 | /* Awful hack for `trap` or $(trap). | ||
5197 | * | ||
5198 | * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html | ||
5199 | * contains an example where "trap" is executed in a subshell: | ||
5200 | * | ||
5201 | * save_traps=$(trap) | ||
5202 | * ... | ||
5203 | * eval "$save_traps" | ||
5204 | * | ||
5205 | * Standard does not say that "trap" in subshell shall print | ||
5206 | * parent shell's traps. It only says that its output | ||
5207 | * must have suitable form, but then, in the above example | ||
5208 | * (which is not supposed to be normative), it implies that. | ||
5209 | * | ||
5210 | * bash (and probably other shell) does implement it | ||
5211 | * (traps are reset to defaults, but "trap" still shows them), | ||
5212 | * but as a result, "trap" logic is hopelessly messed up: | ||
5213 | * | ||
5214 | * # trap | ||
5215 | * trap -- 'echo Ho' SIGWINCH <--- we have a handler | ||
5216 | * # (trap) <--- trap is in subshell - no output (correct, traps are reset) | ||
5217 | * # true | trap <--- trap is in subshell - no output (ditto) | ||
5218 | * # echo `true | trap` <--- in subshell - output (but traps are reset!) | ||
5219 | * trap -- 'echo Ho' SIGWINCH | ||
5220 | * # echo `(trap)` <--- in subshell in subshell - output | ||
5221 | * trap -- 'echo Ho' SIGWINCH | ||
5222 | * # echo `true | (trap)` <--- in subshell in subshell in subshell - output! | ||
5223 | * trap -- 'echo Ho' SIGWINCH | ||
5224 | * | ||
5225 | * The rules when to forget and when to not forget traps | ||
5226 | * get really complex and nonsensical. | ||
5227 | * | ||
5228 | * Our solution: ONLY bare $(trap) or `trap` is special. | ||
5229 | */ | ||
5230 | s = skip_whitespace(s); | ||
5231 | if (strncmp(s, "trap", 4) == 0 && (*skip_whitespace(s + 4) == '\0')) | ||
5232 | { | ||
5233 | static const char *const argv[] = { NULL, NULL }; | ||
5234 | builtin_trap((char**)argv); | ||
5235 | exit(0); /* not _exit() - we need to fflush */ | ||
5236 | } | ||
5186 | #if BB_MMU | 5237 | #if BB_MMU |
5187 | reset_traps_to_defaults(); | 5238 | reset_traps_to_defaults(); |
5188 | parse_and_run_string(s); | 5239 | parse_and_run_string(s); |
@@ -5676,8 +5727,10 @@ static int handle_dollar(o_string *as_string, | |||
5676 | goto make_var; | 5727 | goto make_var; |
5677 | } | 5728 | } |
5678 | /* else: it's $_ */ | 5729 | /* else: it's $_ */ |
5679 | /* TODO: */ | 5730 | /* TODO: $_ and $-: */ |
5680 | /* $_ Shell or shell script name; or last cmd name */ | 5731 | /* $_ Shell or shell script name; or last argument of last command |
5732 | * (if last command wasn't a pipe; if it was, bash sets $_ to ""); | ||
5733 | * but in command's env, set to full pathname used to invoke it */ | ||
5681 | /* $- Option flags set by set builtin or shell options (-i etc) */ | 5734 | /* $- Option flags set by set builtin or shell options (-i etc) */ |
5682 | default: | 5735 | default: |
5683 | o_addQchr(dest, '$'); | 5736 | o_addQchr(dest, '$'); |
@@ -5794,7 +5847,7 @@ static struct pipe *parse_stream(char **pstring, | |||
5794 | * found. When recursing, quote state is passed in via dest->o_escape. | 5847 | * found. When recursing, quote state is passed in via dest->o_escape. |
5795 | */ | 5848 | */ |
5796 | debug_printf_parse("parse_stream entered, end_trigger='%c'\n", | 5849 | debug_printf_parse("parse_stream entered, end_trigger='%c'\n", |
5797 | end_trigger ? : 'X'); | 5850 | end_trigger ? end_trigger : 'X'); |
5798 | debug_enter(); | 5851 | debug_enter(); |
5799 | 5852 | ||
5800 | G.ifs = get_local_var_value("IFS"); | 5853 | G.ifs = get_local_var_value("IFS"); |
@@ -6860,7 +6913,8 @@ static int FAST_FUNC builtin_cd(char **argv) | |||
6860 | * bash says "bash: cd: HOME not set" and does nothing | 6913 | * bash says "bash: cd: HOME not set" and does nothing |
6861 | * (exitcode 1) | 6914 | * (exitcode 1) |
6862 | */ | 6915 | */ |
6863 | newdir = get_local_var_value("HOME") ? : "/"; | 6916 | const char *home = get_local_var_value("HOME"); |
6917 | newdir = home ? home : "/"; | ||
6864 | } | 6918 | } |
6865 | if (chdir(newdir)) { | 6919 | if (chdir(newdir)) { |
6866 | /* Mimic bash message exactly */ | 6920 | /* Mimic bash message exactly */ |
@@ -7057,6 +7111,10 @@ static int FAST_FUNC builtin_trap(char **argv) | |||
7057 | if (G.traps[i]) { | 7111 | if (G.traps[i]) { |
7058 | printf("trap -- "); | 7112 | printf("trap -- "); |
7059 | print_escaped(G.traps[i]); | 7113 | print_escaped(G.traps[i]); |
7114 | /* note: bash adds "SIG", but only if invoked | ||
7115 | * as "bash". If called as "sh", or if set -o posix, | ||
7116 | * then it prints short signal names. | ||
7117 | * We are printing short names: */ | ||
7060 | printf(" %s\n", get_signame(i)); | 7118 | printf(" %s\n", get_signame(i)); |
7061 | } | 7119 | } |
7062 | } | 7120 | } |
@@ -7268,6 +7326,10 @@ static int FAST_FUNC builtin_memleak(char **argv UNUSED_PARAM) | |||
7268 | void *p; | 7326 | void *p; |
7269 | unsigned long l; | 7327 | unsigned long l; |
7270 | 7328 | ||
7329 | #ifdef M_TRIM_THRESHOLD | ||
7330 | /* Optional. Reduces probability of false positives */ | ||
7331 | malloc_trim(0); | ||
7332 | #endif | ||
7271 | /* Crude attempt to find where "free memory" starts, | 7333 | /* Crude attempt to find where "free memory" starts, |
7272 | * sans fragmentation. */ | 7334 | * sans fragmentation. */ |
7273 | p = malloc(240); | 7335 | p = malloc(240); |
diff --git a/shell/hush_test/hush-trap/savetrap.right b/shell/hush_test/hush-trap/savetrap.right new file mode 100644 index 000000000..a59225be3 --- /dev/null +++ b/shell/hush_test/hush-trap/savetrap.right | |||
@@ -0,0 +1,8 @@ | |||
1 | trap -- 'echo Exiting' EXIT | ||
2 | trap -- 'echo WINCH!' WINCH | ||
3 | trap -- 'echo Exiting' EXIT | ||
4 | trap -- 'echo WINCH!' WINCH | ||
5 | trap -- 'echo Exiting' EXIT | ||
6 | trap -- 'echo WINCH!' WINCH | ||
7 | Done | ||
8 | Exiting | ||
diff --git a/shell/hush_test/hush-trap/savetrap.tests b/shell/hush_test/hush-trap/savetrap.tests new file mode 100755 index 000000000..c2b312fb8 --- /dev/null +++ b/shell/hush_test/hush-trap/savetrap.tests | |||
@@ -0,0 +1,9 @@ | |||
1 | trap 'echo Exiting' EXIT | ||
2 | trap 'echo WINCH!' SIGWINCH | ||
3 | v=` trap ` | ||
4 | echo "$v" | ||
5 | v=$( trap ) | ||
6 | echo "$v" | ||
7 | v=`trap` | ||
8 | echo "$v" | ||
9 | echo Done | ||
diff --git a/shell/hush_test/hush-trap/subshell.right b/shell/hush_test/hush-trap/subshell.right new file mode 100644 index 000000000..0d20ed4e9 --- /dev/null +++ b/shell/hush_test/hush-trap/subshell.right | |||
@@ -0,0 +1,6 @@ | |||
1 | Ok | ||
2 | Ok | ||
3 | Ok | ||
4 | Ok | ||
5 | TERM | ||
6 | Done | ||
diff --git a/shell/hush_test/hush-trap/subshell.tests b/shell/hush_test/hush-trap/subshell.tests new file mode 100755 index 000000000..4564c2ee2 --- /dev/null +++ b/shell/hush_test/hush-trap/subshell.tests | |||
@@ -0,0 +1,20 @@ | |||
1 | # Non-empty traps should be reset in subshell | ||
2 | |||
3 | # HUP is special in interactive shells | ||
4 | trap '' HUP | ||
5 | # QUIT is always special | ||
6 | trap '' QUIT | ||
7 | # SYS is not special | ||
8 | trap '' SYS | ||
9 | # WINCH is harmless | ||
10 | trap 'bad: caught WINCH' WINCH | ||
11 | # With TERM we'll check whether it is reset | ||
12 | trap 'bad: caught TERM' TERM | ||
13 | |||
14 | # using bash, because we don't have $PPID (yet) | ||
15 | (bash -c 'kill -HUP $PPID'; echo Ok) | ||
16 | (bash -c 'kill -QUIT $PPID'; echo Ok) | ||
17 | (bash -c 'kill -SYS $PPID'; echo Ok) | ||
18 | (bash -c 'kill -WINCH $PPID'; echo Ok) | ||
19 | (bash -c 'kill -TERM $PPID'; echo Bad: TERM is not reset) | ||
20 | echo Done | ||
diff --git a/util-linux/fdisk.c b/util-linux/fdisk.c index 441640831..9f766ecd3 100644 --- a/util-linux/fdisk.c +++ b/util-linux/fdisk.c | |||
@@ -9,13 +9,16 @@ | |||
9 | 9 | ||
10 | #ifndef _LARGEFILE64_SOURCE | 10 | #ifndef _LARGEFILE64_SOURCE |
11 | /* For lseek64 */ | 11 | /* For lseek64 */ |
12 | #define _LARGEFILE64_SOURCE | 12 | # define _LARGEFILE64_SOURCE |
13 | #endif | 13 | #endif |
14 | #include <assert.h> /* assert */ | 14 | #include <assert.h> /* assert */ |
15 | #include <sys/mount.h> | 15 | #include <sys/mount.h> |
16 | #if !defined(BLKSSZGET) | 16 | #if !defined(BLKSSZGET) |
17 | # define BLKSSZGET _IO(0x12, 104) | 17 | # define BLKSSZGET _IO(0x12, 104) |
18 | #endif | 18 | #endif |
19 | #if !defined(BLKGETSIZE64) | ||
20 | # define BLKGETSIZE64 _IOR(0x12,114,size_t) | ||
21 | #endif | ||
19 | #include "libbb.h" | 22 | #include "libbb.h" |
20 | 23 | ||
21 | /* Looks like someone forgot to add this to config system */ | 24 | /* Looks like someone forgot to add this to config system */ |