aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2009-10-08 03:06:04 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2009-10-08 03:06:04 +0200
commit4ac9819263114edb9b5b638ffa6d2e41a4bb46e7 (patch)
treef0c5bc9c7a2bf3a384b85350bfe4c9ca5ec4858f
parent5b807cd5acd1f27b3e7aa36aac2728be27c5907c (diff)
downloadbusybox-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.c11
-rw-r--r--coreutils/uniq.c1
-rw-r--r--editors/sed.c4
-rw-r--r--findutils/find.c68
-rw-r--r--include/libbb.h2
-rw-r--r--libbb/lineedit.c49
-rw-r--r--libbb/procps.c133
-rw-r--r--libbb/recursive_action.c17
-rw-r--r--miscutils/hdparm.c3
-rw-r--r--shell/ash.c418
-rw-r--r--shell/ash_test/ash-redir/redir7.right3
-rwxr-xr-xshell/ash_test/ash-redir/redir7.tests12
-rw-r--r--shell/ash_test/ash-redir/redir8.right3
-rwxr-xr-xshell/ash_test/ash-redir/redir8.tests15
-rw-r--r--shell/ash_test/ash-signals/savetrap.right8
-rwxr-xr-xshell/ash_test/ash-signals/savetrap.tests9
-rw-r--r--shell/hush.c188
-rw-r--r--shell/hush_test/hush-trap/savetrap.right8
-rwxr-xr-xshell/hush_test/hush-trap/savetrap.tests9
-rw-r--r--shell/hush_test/hush-trap/subshell.right6
-rwxr-xr-xshell/hush_test/hush-trap/subshell.tests20
-rw-r--r--util-linux/fdisk.c5
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
65IF_FEATURE_FIND_XDEV(static dev_t *xdev_dev;)
66IF_FEATURE_FIND_XDEV(static int xdev_count;)
67
68typedef int (*action_fp)(const char *fileName, struct stat *statbuf, void *) FAST_FUNC; 65typedef int (*action_fp)(const char *fileName, struct stat *statbuf, void *) FAST_FUNC;
69 66
70typedef struct { 67typedef struct {
@@ -100,9 +97,24 @@ IF_FEATURE_FIND_DELETE( ACTS(delete))
100IF_FEATURE_FIND_EXEC( ACTS(exec, char **exec_argv; unsigned *subst_count; int exec_argc;)) 97IF_FEATURE_FIND_EXEC( ACTS(exec, char **exec_argv; unsigned *subst_count; int exec_argc;))
101IF_FEATURE_FIND_GROUP( ACTS(group, gid_t gid;)) 98IF_FEATURE_FIND_GROUP( ACTS(group, gid_t gid;))
102 99
103static action ***actions; 100struct globals {
104static bool need_print = 1; 101 IF_FEATURE_FIND_XDEV(dev_t *xdev_dev;)
105static 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
108static unsigned count_subst(const char *str) 120static 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};
291typedef uint8_t recurse_flags_t;
290extern int recursive_action(const char *fileName, unsigned flags, 292extern 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
1264static void remember_in_history(char *str) 1264static 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
113static const char homestr[] ALIGN1 = "HOME"; 113static const char homestr[] ALIGN1 = "HOME";
114static const char snlfmt[] ALIGN1 = "%s\n"; 114static const char snlfmt[] ALIGN1 = "%s\n";
115static const char illnum[] ALIGN1 = "Illegal number: %s"; 115static 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
353int_on(void) 348int_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
362force_int_on(void) 357force_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
1556number(const char *s) 1551number(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
2354static int docd(const char *, int);
2355
2356static int 2349static int
2357cdopt(void) 2350cdopt(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
3254struct procstat { 3246struct 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
3918blocking_wait_with_raise_on_sig(struct job *job) 3909blocking_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
4549static void 4547static NOINLINE void
4550forkchild(struct job *jp, union node *n, int mode) 4548forkchild(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 */
5375static char * 5426static char *
5376_rmescapes(char *str, int flag) 5427rmescapes(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
5549static char * 5606static char *
5550exptilde(char *startp, char *p, int flag) 5607exptilde(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 */
5783static char *evalvar(char *p, int flag, struct strlist *var_str_list); 5840static 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 */
5794static void 5851static void
5795argstr(char *p, int flag, struct strlist *var_str_list) 5852argstr(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 */
6454static char * 6517static char *
6455evalvar(char *p, int flag, struct strlist *var_str_list) 6518evalvar(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 @@
1Ok
2Ok
3Done
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
7echo -e 'echo Ok >uni\x81code' >>unicode.sh
8echo -e 'cat uni\x81code' >>unicode.sh
9echo -e 'cat uni?code' >>unicode.sh
10. unicode.sh
11rm uni*code*
12echo 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 @@
1Ok
2Ok
3Done
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
9echo -e 'v=uni\x81code' >>unicode.sh
10echo -e 'echo Ok >"$v"' >>unicode.sh
11echo -e 'cat uni\x81code' >>unicode.sh
12echo -e 'cat uni?code' >>unicode.sh
13. unicode.sh
14rm uni*code*
15echo 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 @@
1trap -- 'echo Exiting' EXIT
2trap -- 'echo WINCH!' WINCH
3trap -- 'echo Exiting' EXIT
4trap -- 'echo WINCH!' WINCH
5trap -- 'echo Exiting' EXIT
6trap -- 'echo WINCH!' WINCH
7Done
8Exiting
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 @@
1trap 'echo Exiting' EXIT
2trap 'echo WINCH!' SIGWINCH
3v=` trap `
4echo "$v"
5v=$( trap )
6echo "$v"
7v=`trap`
8echo "$v"
9echo 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. */
899static char *unbackslash(char *src) 900static 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 */
1114enum { 1120enum {
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
3082static const struct function *find_function(const char *name) 3096static 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
3108static 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 */
3097static struct function *new_function(char *name) 3117static 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
3142static void unset_func(const char *name) 3155static 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 @@
1trap -- 'echo Exiting' EXIT
2trap -- 'echo WINCH!' WINCH
3trap -- 'echo Exiting' EXIT
4trap -- 'echo WINCH!' WINCH
5trap -- 'echo Exiting' EXIT
6trap -- 'echo WINCH!' WINCH
7Done
8Exiting
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 @@
1trap 'echo Exiting' EXIT
2trap 'echo WINCH!' SIGWINCH
3v=` trap `
4echo "$v"
5v=$( trap )
6echo "$v"
7v=`trap`
8echo "$v"
9echo 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 @@
1Ok
2Ok
3Ok
4Ok
5TERM
6Done
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
4trap '' HUP
5# QUIT is always special
6trap '' QUIT
7# SYS is not special
8trap '' SYS
9# WINCH is harmless
10trap 'bad: caught WINCH' WINCH
11# With TERM we'll check whether it is reset
12trap '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)
20echo 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 */