diff options
author | Ron Yorston <rmy@pobox.com> | 2020-11-12 08:27:51 +0000 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2020-11-12 08:27:51 +0000 |
commit | ead8b92e3d66ab45235e137f85fb3a529dcc64ef (patch) | |
tree | af268270382dad969218063d4a8120fc91a9e631 | |
parent | 567728c22dddea4ed33b8a69641ba2e0c3f1f600 (diff) | |
parent | 64981b4c8e88812c322bee3832f1d421ff670ed5 (diff) | |
download | busybox-w32-ead8b92e3d66ab45235e137f85fb3a529dcc64ef.tar.gz busybox-w32-ead8b92e3d66ab45235e137f85fb3a529dcc64ef.tar.bz2 busybox-w32-ead8b92e3d66ab45235e137f85fb3a529dcc64ef.zip |
Merge branch 'busybox' into merge
90 files changed, 1009 insertions, 487 deletions
diff --git a/archival/libarchive/get_header_tar.c b/archival/libarchive/get_header_tar.c index b3131ff2d..2ab3c04b8 100644 --- a/archival/libarchive/get_header_tar.c +++ b/archival/libarchive/get_header_tar.c | |||
@@ -352,7 +352,7 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) | |||
352 | /* case 0: */ | 352 | /* case 0: */ |
353 | case '0': | 353 | case '0': |
354 | #if ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY | 354 | #if ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY |
355 | if (last_char_is(file_header->name, '/')) { | 355 | if (file_header->name && last_char_is(file_header->name, '/')) { |
356 | goto set_dir; | 356 | goto set_dir; |
357 | } | 357 | } |
358 | #endif | 358 | #endif |
diff --git a/archival/tar.c b/archival/tar.c index c7642a50e..1796d4c60 100644 --- a/archival/tar.c +++ b/archival/tar.c | |||
@@ -299,7 +299,8 @@ static void writeLongname(int fd, int type, const char *name, int dir) | |||
299 | header.typeflag = type; | 299 | header.typeflag = type; |
300 | strcpy(header.name, "././@LongLink"); | 300 | strcpy(header.name, "././@LongLink"); |
301 | /* This sets mode/uid/gid/mtime to "00...00<NUL>" strings */ | 301 | /* This sets mode/uid/gid/mtime to "00...00<NUL>" strings */ |
302 | memset(header.mode, '0', sizeof(struct prefilled)); | 302 | memset((char*)&header + offsetof(struct tar_header_t, mode), /* make gcc-9.x happy */ |
303 | '0', sizeof(struct prefilled)); | ||
303 | header.mode [sizeof(header.mode ) - 1] = '\0'; | 304 | header.mode [sizeof(header.mode ) - 1] = '\0'; |
304 | header.uid [sizeof(header.uid ) - 1] = '\0'; | 305 | header.uid [sizeof(header.uid ) - 1] = '\0'; |
305 | header.gid [sizeof(header.gid ) - 1] = '\0'; | 306 | header.gid [sizeof(header.gid ) - 1] = '\0'; |
@@ -492,10 +493,11 @@ static int exclude_file(const llist_t *excluded_files, const char *file) | |||
492 | # define exclude_file(excluded_files, file) 0 | 493 | # define exclude_file(excluded_files, file) 0 |
493 | # endif | 494 | # endif |
494 | 495 | ||
495 | static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statbuf, | 496 | static int FAST_FUNC writeFileToTarball(struct recursive_state *state, |
496 | void *userData, int depth UNUSED_PARAM) | 497 | const char *fileName, |
498 | struct stat *statbuf) | ||
497 | { | 499 | { |
498 | struct TarBallInfo *tbInfo = (struct TarBallInfo *) userData; | 500 | struct TarBallInfo *tbInfo = (struct TarBallInfo *) state->userData; |
499 | const char *header_name; | 501 | const char *header_name; |
500 | int inputFileFd = -1; | 502 | int inputFileFd = -1; |
501 | 503 | ||
@@ -714,7 +716,7 @@ static NOINLINE int writeTarFile( | |||
714 | /* Read the directory/files and iterate over them one at a time */ | 716 | /* Read the directory/files and iterate over them one at a time */ |
715 | while (filelist) { | 717 | while (filelist) { |
716 | if (!recursive_action(filelist->data, recurseFlags, | 718 | if (!recursive_action(filelist->data, recurseFlags, |
717 | writeFileToTarball, writeFileToTarball, tbInfo, 0) | 719 | writeFileToTarball, writeFileToTarball, tbInfo) |
718 | ) { | 720 | ) { |
719 | errorFlag = TRUE; | 721 | errorFlag = TRUE; |
720 | } | 722 | } |
diff --git a/coreutils/chmod.c b/coreutils/chmod.c index 27e9b6b86..d2988c490 100644 --- a/coreutils/chmod.c +++ b/coreutils/chmod.c | |||
@@ -65,12 +65,14 @@ | |||
65 | * symbolic links encountered during recursive directory traversals. | 65 | * symbolic links encountered during recursive directory traversals. |
66 | */ | 66 | */ |
67 | 67 | ||
68 | static int FAST_FUNC fileAction(const char *fileName, struct stat *statbuf, void* param, int depth) | 68 | static int FAST_FUNC fileAction(struct recursive_state *state, |
69 | const char *fileName, | ||
70 | struct stat *statbuf) | ||
69 | { | 71 | { |
70 | mode_t newmode; | 72 | mode_t newmode; |
71 | 73 | ||
72 | /* match coreutils behavior */ | 74 | /* match coreutils behavior */ |
73 | if (depth == 0) { | 75 | if (state->depth == 0) { |
74 | /* statbuf holds lstat result, but we need stat (follow link) */ | 76 | /* statbuf holds lstat result, but we need stat (follow link) */ |
75 | if (stat(fileName, statbuf)) | 77 | if (stat(fileName, statbuf)) |
76 | goto err; | 78 | goto err; |
@@ -79,9 +81,9 @@ static int FAST_FUNC fileAction(const char *fileName, struct stat *statbuf, void | |||
79 | return TRUE; | 81 | return TRUE; |
80 | } | 82 | } |
81 | 83 | ||
82 | newmode = bb_parse_mode((char *)param, statbuf->st_mode); | 84 | newmode = bb_parse_mode((char *)state->userData, statbuf->st_mode); |
83 | if (newmode == (mode_t)-1) | 85 | if (newmode == (mode_t)-1) |
84 | bb_error_msg_and_die("invalid mode '%s'", (char *)param); | 86 | bb_error_msg_and_die("invalid mode '%s'", (char *)state->userData); |
85 | 87 | ||
86 | if (chmod(fileName, newmode) == 0) { | 88 | if (chmod(fileName, newmode) == 0) { |
87 | if (OPT_VERBOSE | 89 | if (OPT_VERBOSE |
@@ -136,8 +138,7 @@ int chmod_main(int argc UNUSED_PARAM, char **argv) | |||
136 | OPT_RECURSE, // recurse | 138 | OPT_RECURSE, // recurse |
137 | fileAction, // file action | 139 | fileAction, // file action |
138 | fileAction, // dir action | 140 | fileAction, // dir action |
139 | smode, // user data | 141 | smode) // user data |
140 | 0) // depth | ||
141 | ) { | 142 | ) { |
142 | retval = EXIT_FAILURE; | 143 | retval = EXIT_FAILURE; |
143 | } | 144 | } |
diff --git a/coreutils/chown.c b/coreutils/chown.c index a1c5c0224..ffccc6cce 100644 --- a/coreutils/chown.c +++ b/coreutils/chown.c | |||
@@ -97,10 +97,10 @@ struct param_t { | |||
97 | chown_fptr chown_func; | 97 | chown_fptr chown_func; |
98 | }; | 98 | }; |
99 | 99 | ||
100 | static int FAST_FUNC fileAction(const char *fileName, struct stat *statbuf, | 100 | static int FAST_FUNC fileAction(struct recursive_state *state UNUSED_PARAM, |
101 | void *vparam, int depth UNUSED_PARAM) | 101 | const char *fileName, struct stat *statbuf) |
102 | { | 102 | { |
103 | #define param (*(struct param_t*)vparam) | 103 | #define param (*(struct param_t*)state->userData) |
104 | #define opt option_mask32 | 104 | #define opt option_mask32 |
105 | uid_t u = (param.ugid.uid == (uid_t)-1L) ? statbuf->st_uid : param.ugid.uid; | 105 | uid_t u = (param.ugid.uid == (uid_t)-1L) ? statbuf->st_uid : param.ugid.uid; |
106 | gid_t g = (param.ugid.gid == (gid_t)-1L) ? statbuf->st_gid : param.ugid.gid; | 106 | gid_t g = (param.ugid.gid == (gid_t)-1L) ? statbuf->st_gid : param.ugid.gid; |
@@ -159,8 +159,7 @@ int chown_main(int argc UNUSED_PARAM, char **argv) | |||
159 | flags, /* flags */ | 159 | flags, /* flags */ |
160 | fileAction, /* file action */ | 160 | fileAction, /* file action */ |
161 | fileAction, /* dir action */ | 161 | fileAction, /* dir action */ |
162 | ¶m, /* user data */ | 162 | ¶m) /* user data */ |
163 | 0) /* depth */ | ||
164 | ) { | 163 | ) { |
165 | retval = EXIT_FAILURE; | 164 | retval = EXIT_FAILURE; |
166 | } | 165 | } |
diff --git a/coreutils/test.c b/coreutils/test.c index a08986130..ac7b546a3 100644 --- a/coreutils/test.c +++ b/coreutils/test.c | |||
@@ -76,6 +76,8 @@ | |||
76 | //usage: "1\n" | 76 | //usage: "1\n" |
77 | 77 | ||
78 | #include "libbb.h" | 78 | #include "libbb.h" |
79 | #include <regex.h> | ||
80 | #include <fnmatch.h> | ||
79 | 81 | ||
80 | /* This is a NOFORK applet. Be very careful! */ | 82 | /* This is a NOFORK applet. Be very careful! */ |
81 | 83 | ||
@@ -146,6 +148,14 @@ | |||
146 | 148 | ||
147 | #define TEST_DEBUG 0 | 149 | #define TEST_DEBUG 0 |
148 | 150 | ||
151 | #if ENABLE_TEST2 \ | ||
152 | || (ENABLE_ASH_BASH_COMPAT && ENABLE_ASH_TEST) \ | ||
153 | || (ENABLE_HUSH_BASH_COMPAT && ENABLE_HUSH_TEST) | ||
154 | # define BASH_TEST2 1 | ||
155 | #else | ||
156 | # define BASH_TEST2 0 | ||
157 | #endif | ||
158 | |||
149 | enum token { | 159 | enum token { |
150 | EOI, | 160 | EOI, |
151 | 161 | ||
@@ -184,6 +194,10 @@ enum token { | |||
184 | STRLT, | 194 | STRLT, |
185 | STRGT, | 195 | STRGT, |
186 | 196 | ||
197 | #if BASH_TEST2 | ||
198 | REGEX, | ||
199 | #endif | ||
200 | |||
187 | INTEQ, /* int ops */ | 201 | INTEQ, /* int ops */ |
188 | INTNE, | 202 | INTNE, |
189 | INTGE, | 203 | INTGE, |
@@ -257,6 +271,9 @@ static const char *const TOKSTR[] = { | |||
257 | "STRNE", | 271 | "STRNE", |
258 | "STRLT", | 272 | "STRLT", |
259 | "STRGT", | 273 | "STRGT", |
274 | #if BASH_TEST2 | ||
275 | "REGEX", | ||
276 | #endif | ||
260 | "INTEQ", | 277 | "INTEQ", |
261 | "INTNE", | 278 | "INTNE", |
262 | "INTGE", | 279 | "INTGE", |
@@ -320,6 +337,9 @@ static const struct operator_t ops_table[] = { | |||
320 | { /* "!=" */ STRNE , BINOP }, | 337 | { /* "!=" */ STRNE , BINOP }, |
321 | { /* "<" */ STRLT , BINOP }, | 338 | { /* "<" */ STRLT , BINOP }, |
322 | { /* ">" */ STRGT , BINOP }, | 339 | { /* ">" */ STRGT , BINOP }, |
340 | #if BASH_TEST2 | ||
341 | { /* "=~" */ REGEX , BINOP }, | ||
342 | #endif | ||
323 | { /* "-eq"*/ INTEQ , BINOP }, | 343 | { /* "-eq"*/ INTEQ , BINOP }, |
324 | { /* "-ne"*/ INTNE , BINOP }, | 344 | { /* "-ne"*/ INTNE , BINOP }, |
325 | { /* "-ge"*/ INTGE , BINOP }, | 345 | { /* "-ge"*/ INTGE , BINOP }, |
@@ -332,6 +352,10 @@ static const struct operator_t ops_table[] = { | |||
332 | { /* "!" */ UNOT , BUNOP }, | 352 | { /* "!" */ UNOT , BUNOP }, |
333 | { /* "-a" */ BAND , BBINOP }, | 353 | { /* "-a" */ BAND , BBINOP }, |
334 | { /* "-o" */ BOR , BBINOP }, | 354 | { /* "-o" */ BOR , BBINOP }, |
355 | #if BASH_TEST2 | ||
356 | { /* "&&" */ BAND , BBINOP }, | ||
357 | { /* "||" */ BOR , BBINOP }, | ||
358 | #endif | ||
335 | { /* "(" */ LPAREN , PAREN }, | 359 | { /* "(" */ LPAREN , PAREN }, |
336 | { /* ")" */ RPAREN , PAREN }, | 360 | { /* ")" */ RPAREN , PAREN }, |
337 | }; | 361 | }; |
@@ -365,6 +389,9 @@ static const char ops_texts[] ALIGN1 = | |||
365 | "!=" "\0" | 389 | "!=" "\0" |
366 | "<" "\0" | 390 | "<" "\0" |
367 | ">" "\0" | 391 | ">" "\0" |
392 | #if BASH_TEST2 | ||
393 | "=~" "\0" | ||
394 | #endif | ||
368 | "-eq" "\0" | 395 | "-eq" "\0" |
369 | "-ne" "\0" | 396 | "-ne" "\0" |
370 | "-ge" "\0" | 397 | "-ge" "\0" |
@@ -377,6 +404,10 @@ static const char ops_texts[] ALIGN1 = | |||
377 | "!" "\0" | 404 | "!" "\0" |
378 | "-a" "\0" | 405 | "-a" "\0" |
379 | "-o" "\0" | 406 | "-o" "\0" |
407 | #if BASH_TEST2 | ||
408 | "&&" "\0" | ||
409 | "||" "\0" | ||
410 | #endif | ||
380 | "(" "\0" | 411 | "(" "\0" |
381 | ")" "\0" | 412 | ")" "\0" |
382 | ; | 413 | ; |
@@ -397,6 +428,9 @@ struct test_statics { | |||
397 | const struct operator_t *last_operator; | 428 | const struct operator_t *last_operator; |
398 | gid_t *group_array; | 429 | gid_t *group_array; |
399 | int ngroups; | 430 | int ngroups; |
431 | #if BASH_TEST2 | ||
432 | bool bash_test2; | ||
433 | #endif | ||
400 | jmp_buf leaving; | 434 | jmp_buf leaving; |
401 | }; | 435 | }; |
402 | 436 | ||
@@ -408,6 +442,7 @@ extern struct test_statics *const test_ptr_to_statics; | |||
408 | #define last_operator (S.last_operator) | 442 | #define last_operator (S.last_operator) |
409 | #define group_array (S.group_array ) | 443 | #define group_array (S.group_array ) |
410 | #define ngroups (S.ngroups ) | 444 | #define ngroups (S.ngroups ) |
445 | #define bash_test2 (S.bash_test2 ) | ||
411 | #define leaving (S.leaving ) | 446 | #define leaving (S.leaving ) |
412 | 447 | ||
413 | #define INIT_S() do { \ | 448 | #define INIT_S() do { \ |
@@ -501,6 +536,20 @@ static enum token check_operator(const char *s) | |||
501 | n = index_in_strings(ops_texts, s); | 536 | n = index_in_strings(ops_texts, s); |
502 | if (n < 0) | 537 | if (n < 0) |
503 | return OPERAND; | 538 | return OPERAND; |
539 | |||
540 | #if BASH_TEST2 | ||
541 | if (ops_table[n].op_num == REGEX && !bash_test2) { | ||
542 | /* =~ is only for [[ ]] */ | ||
543 | return OPERAND; | ||
544 | } | ||
545 | if (ops_table[n].op_num == BAND || ops_table[n].op_num == BOR) { | ||
546 | /* [ ] accepts -a and -o but not && and || */ | ||
547 | /* [[ ]] accepts && and || but not -a and -o */ | ||
548 | if (bash_test2 == (s[0] == '-')) | ||
549 | return OPERAND; | ||
550 | } | ||
551 | #endif | ||
552 | |||
504 | last_operator = &ops_table[n]; | 553 | last_operator = &ops_table[n]; |
505 | return ops_table[n].op_num; | 554 | return ops_table[n].op_num; |
506 | } | 555 | } |
@@ -536,6 +585,29 @@ static int binop(void) | |||
536 | /*if (op->op_num == INTLT)*/ | 585 | /*if (op->op_num == INTLT)*/ |
537 | return val1 < val2; | 586 | return val1 < val2; |
538 | } | 587 | } |
588 | #if BASH_TEST2 | ||
589 | if (bash_test2) { | ||
590 | if (op->op_num == STREQ) { | ||
591 | val1 = fnmatch(opnd2, opnd1, 0); | ||
592 | return val1 == 0; | ||
593 | } | ||
594 | if (op->op_num == STRNE) { | ||
595 | val1 = fnmatch(opnd2, opnd1, 0); | ||
596 | return val1 != 0; | ||
597 | } | ||
598 | if (op->op_num == REGEX) { | ||
599 | regex_t re_buffer; | ||
600 | memset(&re_buffer, 0, sizeof(re_buffer)); | ||
601 | if (regcomp(&re_buffer, opnd2, REG_EXTENDED)) { // REG_NEWLINE? | ||
602 | /* Bad regex */ | ||
603 | longjmp(leaving, 2); /* [[ a =~ * ]]; echo $? - prints 2 (silently, no error msg) */ | ||
604 | } | ||
605 | val1 = regexec(&re_buffer, opnd1, 0, NULL, 0); | ||
606 | regfree(&re_buffer); | ||
607 | return val1 == 0; | ||
608 | } | ||
609 | } | ||
610 | #endif | ||
539 | if (is_str_op(op->op_num)) { | 611 | if (is_str_op(op->op_num)) { |
540 | val1 = strcmp(opnd1, opnd2); | 612 | val1 = strcmp(opnd1, opnd2); |
541 | if (op->op_num == STREQ) | 613 | if (op->op_num == STREQ) |
@@ -824,6 +896,9 @@ int test_main(int argc, char **argv) | |||
824 | { | 896 | { |
825 | int res; | 897 | int res; |
826 | const char *arg0; | 898 | const char *arg0; |
899 | #if BASH_TEST2 | ||
900 | bool bt2 = 0; | ||
901 | #endif | ||
827 | 902 | ||
828 | arg0 = bb_basename(argv[0]); | 903 | arg0 = bb_basename(argv[0]); |
829 | if ((ENABLE_TEST1 || ENABLE_TEST2 || ENABLE_ASH_TEST || ENABLE_HUSH_TEST) | 904 | if ((ENABLE_TEST1 || ENABLE_TEST2 || ENABLE_ASH_TEST || ENABLE_HUSH_TEST) |
@@ -840,6 +915,9 @@ int test_main(int argc, char **argv) | |||
840 | bb_simple_error_msg("missing ]]"); | 915 | bb_simple_error_msg("missing ]]"); |
841 | return 2; | 916 | return 2; |
842 | } | 917 | } |
918 | #if BASH_TEST2 | ||
919 | bt2 = 1; | ||
920 | #endif | ||
843 | } | 921 | } |
844 | argv[argc] = NULL; | 922 | argv[argc] = NULL; |
845 | } | 923 | } |
@@ -848,6 +926,10 @@ int test_main(int argc, char **argv) | |||
848 | /* We must do DEINIT_S() prior to returning */ | 926 | /* We must do DEINIT_S() prior to returning */ |
849 | INIT_S(); | 927 | INIT_S(); |
850 | 928 | ||
929 | #if BASH_TEST2 | ||
930 | bash_test2 = bt2; | ||
931 | #endif | ||
932 | |||
851 | res = setjmp(leaving); | 933 | res = setjmp(leaving); |
852 | if (res) | 934 | if (res) |
853 | goto ret; | 935 | goto ret; |
diff --git a/coreutils/uudecode.c b/coreutils/uudecode.c index dc8ef5cca..5b2edd649 100644 --- a/coreutils/uudecode.c +++ b/coreutils/uudecode.c | |||
@@ -110,9 +110,7 @@ static void FAST_FUNC read_stduu(FILE *src_stream, FILE *dst_stream, int flags U | |||
110 | } | 110 | } |
111 | bb_simple_error_msg_and_die("short file"); | 111 | bb_simple_error_msg_and_die("short file"); |
112 | } | 112 | } |
113 | #endif | ||
114 | 113 | ||
115 | #if ENABLE_UUDECODE | ||
116 | int uudecode_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 114 | int uudecode_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
117 | int uudecode_main(int argc UNUSED_PARAM, char **argv) | 115 | int uudecode_main(int argc UNUSED_PARAM, char **argv) |
118 | { | 116 | { |
@@ -202,10 +200,10 @@ int base64_main(int argc UNUSED_PARAM, char **argv) | |||
202 | *--argv = (char*)"-"; | 200 | *--argv = (char*)"-"; |
203 | src_stream = xfopen_stdin(argv[0]); | 201 | src_stream = xfopen_stdin(argv[0]); |
204 | if (opts) { | 202 | if (opts) { |
205 | read_base64(src_stream, stdout, /*flags:*/ (char)EOF); | 203 | read_base64(src_stream, stdout, /*flags:*/ (unsigned char)EOF); |
206 | } else { | 204 | } else { |
207 | enum { | 205 | enum { |
208 | SRC_BUF_SIZE = 76/4*3, /* This *MUST* be a multiple of 3 */ | 206 | SRC_BUF_SIZE = 76 / 4 * 3, /* this *MUST* be a multiple of 3 */ |
209 | DST_BUF_SIZE = 4 * ((SRC_BUF_SIZE + 2) / 3), | 207 | DST_BUF_SIZE = 4 * ((SRC_BUF_SIZE + 2) / 3), |
210 | }; | 208 | }; |
211 | char src_buf[SRC_BUF_SIZE]; | 209 | char src_buf[SRC_BUF_SIZE]; |
diff --git a/debianutils/run_parts.c b/debianutils/run_parts.c index c80cc863f..585a4b58f 100644 --- a/debianutils/run_parts.c +++ b/debianutils/run_parts.c | |||
@@ -131,12 +131,13 @@ static int bb_alphasort(const void *p1, const void *p2) | |||
131 | return (option_mask32 & OPT_r) ? -r : r; | 131 | return (option_mask32 & OPT_r) ? -r : r; |
132 | } | 132 | } |
133 | 133 | ||
134 | static int FAST_FUNC act(const char *file, struct stat *statbuf, void *args UNUSED_PARAM, int depth) | 134 | static int FAST_FUNC act(struct recursive_state *state, |
135 | const char *file, struct stat *statbuf) | ||
135 | { | 136 | { |
136 | if (depth == 1) | 137 | if (state->depth == 0) |
137 | return TRUE; | 138 | return TRUE; |
138 | 139 | ||
139 | if (depth == 2 | 140 | if (state->depth == 1 |
140 | && ( !(statbuf->st_mode & (S_IFREG | S_IFLNK)) | 141 | && ( !(statbuf->st_mode & (S_IFREG | S_IFLNK)) |
141 | || invalid_name(file) | 142 | || invalid_name(file) |
142 | || (!(option_mask32 & OPT_l) && access(file, X_OK) != 0)) | 143 | || (!(option_mask32 & OPT_l) && access(file, X_OK) != 0)) |
@@ -199,9 +200,8 @@ int run_parts_main(int argc UNUSED_PARAM, char **argv) | |||
199 | ACTION_RECURSE|ACTION_FOLLOWLINKS, | 200 | ACTION_RECURSE|ACTION_FOLLOWLINKS, |
200 | act, /* file action */ | 201 | act, /* file action */ |
201 | act, /* dir action */ | 202 | act, /* dir action */ |
202 | NULL, /* user data */ | 203 | NULL /* user data */ |
203 | 1 /* depth */ | 204 | ); |
204 | ); | ||
205 | 205 | ||
206 | if (!names) | 206 | if (!names) |
207 | return 0; | 207 | return 0; |
diff --git a/editors/diff.c b/editors/diff.c index 093e7b498..a1c51ebb9 100644 --- a/editors/diff.c +++ b/editors/diff.c | |||
@@ -824,11 +824,11 @@ struct dlist { | |||
824 | }; | 824 | }; |
825 | 825 | ||
826 | /* This function adds a filename to dl, the directory listing. */ | 826 | /* This function adds a filename to dl, the directory listing. */ |
827 | static int FAST_FUNC add_to_dirlist(const char *filename, | 827 | static int FAST_FUNC add_to_dirlist(struct recursive_state *state, |
828 | struct stat *sb UNUSED_PARAM, | 828 | const char *filename, |
829 | void *userdata, int depth UNUSED_PARAM) | 829 | struct stat *sb UNUSED_PARAM) |
830 | { | 830 | { |
831 | struct dlist *const l = userdata; | 831 | struct dlist *const l = state->userData; |
832 | const char *file = filename + l->len; | 832 | const char *file = filename + l->len; |
833 | while (*file == '/') | 833 | while (*file == '/') |
834 | file++; | 834 | file++; |
@@ -841,12 +841,12 @@ static int FAST_FUNC add_to_dirlist(const char *filename, | |||
841 | /* If recursion is not set, this function adds the directory | 841 | /* If recursion is not set, this function adds the directory |
842 | * to the list and prevents recursive_action from recursing into it. | 842 | * to the list and prevents recursive_action from recursing into it. |
843 | */ | 843 | */ |
844 | static int FAST_FUNC skip_dir(const char *filename, | 844 | static int FAST_FUNC skip_dir(struct recursive_state *state, |
845 | struct stat *sb, void *userdata, | 845 | const char *filename, |
846 | int depth) | 846 | struct stat *sb) |
847 | { | 847 | { |
848 | if (!(option_mask32 & FLAG(r)) && depth) { | 848 | if (!(option_mask32 & FLAG(r)) && state->depth) { |
849 | add_to_dirlist(filename, sb, userdata, depth); | 849 | add_to_dirlist(state, filename, sb); |
850 | return SKIP; | 850 | return SKIP; |
851 | } | 851 | } |
852 | if (!(option_mask32 & FLAG(N))) { | 852 | if (!(option_mask32 & FLAG(N))) { |
@@ -854,7 +854,7 @@ static int FAST_FUNC skip_dir(const char *filename, | |||
854 | * which do not exist on the "other side". | 854 | * which do not exist on the "other side". |
855 | * Testcase: diff -r /tmp / | 855 | * Testcase: diff -r /tmp / |
856 | * (it would recurse deep into /proc without this code) */ | 856 | * (it would recurse deep into /proc without this code) */ |
857 | struct dlist *const l = userdata; | 857 | struct dlist *const l = state->userData; |
858 | filename += l->len; | 858 | filename += l->len; |
859 | if (filename[0]) { | 859 | if (filename[0]) { |
860 | struct stat osb; | 860 | struct stat osb; |
@@ -889,7 +889,7 @@ static void diffdir(char *p[2], const char *s_start) | |||
889 | * add_to_dirlist will remove it. */ | 889 | * add_to_dirlist will remove it. */ |
890 | list[i].len = strlen(p[i]); | 890 | list[i].len = strlen(p[i]); |
891 | recursive_action(p[i], ACTION_RECURSE | ACTION_FOLLOWLINKS, | 891 | recursive_action(p[i], ACTION_RECURSE | ACTION_FOLLOWLINKS, |
892 | add_to_dirlist, skip_dir, &list[i], 0); | 892 | add_to_dirlist, skip_dir, &list[i]); |
893 | /* Sort dl alphabetically. | 893 | /* Sort dl alphabetically. |
894 | * GNU diff does this ignoring any number of trailing dots. | 894 | * GNU diff does this ignoring any number of trailing dots. |
895 | * We don't, so for us dotted files almost always are | 895 | * We don't, so for us dotted files almost always are |
diff --git a/findutils/find.c b/findutils/find.c index 121f8fd03..f26c01c1e 100644 --- a/findutils/find.c +++ b/findutils/find.c | |||
@@ -889,10 +889,10 @@ ACTF(links) | |||
889 | } | 889 | } |
890 | #endif | 890 | #endif |
891 | 891 | ||
892 | static int FAST_FUNC fileAction(const char *fileName, | 892 | static int FAST_FUNC fileAction( |
893 | struct stat *statbuf, | 893 | struct recursive_state *state IF_NOT_FEATURE_FIND_MAXDEPTH(UNUSED_PARAM), |
894 | void *userData UNUSED_PARAM, | 894 | const char *fileName, |
895 | int depth IF_NOT_FEATURE_FIND_MAXDEPTH(UNUSED_PARAM)) | 895 | struct stat *statbuf) |
896 | { | 896 | { |
897 | int r; | 897 | int r; |
898 | int same_fs = 1; | 898 | int same_fs = 1; |
@@ -911,12 +911,12 @@ static int FAST_FUNC fileAction(const char *fileName, | |||
911 | #endif | 911 | #endif |
912 | 912 | ||
913 | #if ENABLE_FEATURE_FIND_MAXDEPTH | 913 | #if ENABLE_FEATURE_FIND_MAXDEPTH |
914 | if (depth < G.minmaxdepth[0]) { | 914 | if (state->depth < G.minmaxdepth[0]) { |
915 | if (same_fs) | 915 | if (same_fs) |
916 | return TRUE; /* skip this, continue recursing */ | 916 | return TRUE; /* skip this, continue recursing */ |
917 | return SKIP; /* stop recursing */ | 917 | return SKIP; /* stop recursing */ |
918 | } | 918 | } |
919 | if (depth > G.minmaxdepth[1]) | 919 | if (state->depth > G.minmaxdepth[1]) |
920 | return SKIP; /* stop recursing */ | 920 | return SKIP; /* stop recursing */ |
921 | #endif | 921 | #endif |
922 | 922 | ||
@@ -927,7 +927,7 @@ static int FAST_FUNC fileAction(const char *fileName, | |||
927 | 927 | ||
928 | #if ENABLE_FEATURE_FIND_MAXDEPTH | 928 | #if ENABLE_FEATURE_FIND_MAXDEPTH |
929 | if (S_ISDIR(statbuf->st_mode)) { | 929 | if (S_ISDIR(statbuf->st_mode)) { |
930 | if (depth == G.minmaxdepth[1]) | 930 | if (state->depth == G.minmaxdepth[1]) |
931 | return SKIP; | 931 | return SKIP; |
932 | } | 932 | } |
933 | #endif | 933 | #endif |
@@ -1574,8 +1574,7 @@ int find_main(int argc UNUSED_PARAM, char **argv) | |||
1574 | G.recurse_flags,/* flags */ | 1574 | G.recurse_flags,/* flags */ |
1575 | fileAction, /* file action */ | 1575 | fileAction, /* file action */ |
1576 | fileAction, /* dir action */ | 1576 | fileAction, /* dir action */ |
1577 | NULL, /* user data */ | 1577 | NULL) /* user data */ |
1578 | 0) /* depth */ | ||
1579 | ) { | 1578 | ) { |
1580 | G.exitstatus |= EXIT_FAILURE; | 1579 | G.exitstatus |= EXIT_FAILURE; |
1581 | } | 1580 | } |
diff --git a/findutils/grep.c b/findutils/grep.c index b456ed467..10cca83e7 100644 --- a/findutils/grep.c +++ b/findutils/grep.c | |||
@@ -656,10 +656,9 @@ static void load_pattern_list(llist_t **lst, char *pattern) | |||
656 | llist_add_to(lst, new_grep_list_data(p, 0)); | 656 | llist_add_to(lst, new_grep_list_data(p, 0)); |
657 | } | 657 | } |
658 | 658 | ||
659 | static int FAST_FUNC file_action_grep(const char *filename, | 659 | static int FAST_FUNC file_action_grep(struct recursive_state *state UNUSED_PARAM, |
660 | struct stat *statbuf, | 660 | const char *filename, |
661 | void* matched, | 661 | struct stat *statbuf) |
662 | int depth UNUSED_PARAM) | ||
663 | { | 662 | { |
664 | FILE *file; | 663 | FILE *file; |
665 | 664 | ||
@@ -686,7 +685,7 @@ static int FAST_FUNC file_action_grep(const char *filename, | |||
686 | return 0; | 685 | return 0; |
687 | } | 686 | } |
688 | cur_file = filename; | 687 | cur_file = filename; |
689 | *(int*)matched |= grep_file(file); | 688 | *(int*)state->userData |= grep_file(file); |
690 | fclose(file); | 689 | fclose(file); |
691 | return 1; | 690 | return 1; |
692 | } | 691 | } |
@@ -694,15 +693,16 @@ static int FAST_FUNC file_action_grep(const char *filename, | |||
694 | static int grep_dir(const char *dir) | 693 | static int grep_dir(const char *dir) |
695 | { | 694 | { |
696 | int matched = 0; | 695 | int matched = 0; |
697 | recursive_action(dir, | 696 | recursive_action(dir, 0 |
698 | /* recurse=yes */ ACTION_RECURSE | | 697 | | ACTION_RECURSE |
699 | /* followLinks=always */ ((option_mask32 & OPT_R) ? ACTION_FOLLOWLINKS : 0) | | 698 | | ((option_mask32 & OPT_R) ? ACTION_FOLLOWLINKS : 0) |
700 | /* followLinks=command line only */ ACTION_FOLLOWLINKS_L0 | | 699 | | ACTION_FOLLOWLINKS_L0 /* grep -r ... SYMLINK follows it */ |
701 | /* depthFirst=yes */ ACTION_DEPTHFIRST, | 700 | | ACTION_DEPTHFIRST |
701 | | 0, | ||
702 | /* fileAction= */ file_action_grep, | 702 | /* fileAction= */ file_action_grep, |
703 | /* dirAction= */ NULL, | 703 | /* dirAction= */ NULL, |
704 | /* userData= */ &matched, | 704 | /* userData= */ &matched |
705 | /* depth= */ 0); | 705 | ); |
706 | return matched; | 706 | return matched; |
707 | } | 707 | } |
708 | 708 | ||
diff --git a/findutils/xargs.c b/findutils/xargs.c index 71350d470..1f8d95168 100644 --- a/findutils/xargs.c +++ b/findutils/xargs.c | |||
@@ -83,9 +83,11 @@ | |||
83 | /* This is a NOEXEC applet. Be very careful! */ | 83 | /* This is a NOEXEC applet. Be very careful! */ |
84 | 84 | ||
85 | 85 | ||
86 | //#define dbg_msg(...) bb_error_msg(__VA_ARGS__) | 86 | #if 0 |
87 | #define dbg_msg(...) ((void)0) | 87 | # define dbg_msg(...) bb_error_msg(__VA_ARGS__) |
88 | 88 | #else | |
89 | # define dbg_msg(...) ((void)0) | ||
90 | #endif | ||
89 | 91 | ||
90 | #ifdef TEST | 92 | #ifdef TEST |
91 | # ifndef ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION | 93 | # ifndef ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION |
@@ -539,9 +541,18 @@ static char* FAST_FUNC process_stdin_with_replace(int n_max_chars, int n_max_arg | |||
539 | 541 | ||
540 | while (1) { | 542 | while (1) { |
541 | int c = getchar(); | 543 | int c = getchar(); |
544 | if (p == buf) { | ||
545 | if (c == EOF) | ||
546 | goto ret; /* last line is empty, return "" */ | ||
547 | if (c == G.eol_ch) | ||
548 | continue; /* empty line, ignore */ | ||
549 | /* Skip leading whitespace of each line: try | ||
550 | * echo -e ' \t\v1 2 3 ' | xargs -I% echo '[%]' | ||
551 | */ | ||
552 | if (ISSPACE(c)) | ||
553 | continue; | ||
554 | } | ||
542 | if (c == EOF || c == G.eol_ch) { | 555 | if (c == EOF || c == G.eol_ch) { |
543 | if (p == buf) | ||
544 | goto ret; /* empty line */ | ||
545 | c = '\0'; | 556 | c = '\0'; |
546 | } | 557 | } |
547 | *p++ = c; | 558 | *p++ = c; |
diff --git a/include/dump.h b/include/dump.h index 4c237ef05..9193a6925 100644 --- a/include/dump.h +++ b/include/dump.h | |||
@@ -2,20 +2,6 @@ | |||
2 | 2 | ||
3 | PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN | 3 | PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN |
4 | 4 | ||
5 | #define F_IGNORE 0x01 /* %_A */ | ||
6 | #define F_SETREP 0x02 /* rep count set, not default */ | ||
7 | #define F_ADDRESS 0x001 /* print offset */ | ||
8 | #define F_BPAD 0x002 /* blank pad */ | ||
9 | #define F_C 0x004 /* %_c */ | ||
10 | #define F_CHAR 0x008 /* %c */ | ||
11 | #define F_DBL 0x010 /* %[EefGf] */ | ||
12 | #define F_INT 0x020 /* %[di] */ | ||
13 | #define F_P 0x040 /* %_p */ | ||
14 | #define F_STR 0x080 /* %s */ | ||
15 | #define F_U 0x100 /* %_u */ | ||
16 | #define F_UINT 0x200 /* %[ouXx] */ | ||
17 | #define F_TEXT 0x400 /* no conversions */ | ||
18 | |||
19 | enum dump_vflag_t { ALL, DUP, FIRST, WAIT }; /* -v values */ | 5 | enum dump_vflag_t { ALL, DUP, FIRST, WAIT }; /* -v values */ |
20 | 6 | ||
21 | typedef struct PR { | 7 | typedef struct PR { |
@@ -46,6 +32,7 @@ typedef struct dumper_t { | |||
46 | off_t dump_skip; /* bytes to skip */ | 32 | off_t dump_skip; /* bytes to skip */ |
47 | int dump_length; /* max bytes to read */ | 33 | int dump_length; /* max bytes to read */ |
48 | smallint dump_vflag; /*enum dump_vflag_t*/ | 34 | smallint dump_vflag; /*enum dump_vflag_t*/ |
35 | const char *eofstring; | ||
49 | FS *fshead; | 36 | FS *fshead; |
50 | } dumper_t; | 37 | } dumper_t; |
51 | 38 | ||
diff --git a/include/libbb.h b/include/libbb.h index c09db66eb..eb8b63895 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -357,12 +357,13 @@ struct BUG_off_t_size_is_misdetected { | |||
357 | #endif | 357 | #endif |
358 | #endif | 358 | #endif |
359 | 359 | ||
360 | #if defined(__GLIBC__) | 360 | #if defined(errno) |
361 | /* glibc uses __errno_location() to get a ptr to errno */ | 361 | /* If errno is a define, assume it's "define errno (*__errno_location())" |
362 | /* We can just memorize it once - no multithreading in busybox :) */ | 362 | * and we will cache it's result in this variable */ |
363 | extern int *const bb_errno; | 363 | extern int *const bb_errno; |
364 | #undef errno | 364 | #undef errno |
365 | #define errno (*bb_errno) | 365 | #define errno (*bb_errno) |
366 | #define bb_cached_errno_ptr 1 | ||
366 | #endif | 367 | #endif |
367 | 368 | ||
368 | #if !(ULONG_MAX > 0xffffffff) | 369 | #if !(ULONG_MAX > 0xffffffff) |
@@ -454,15 +455,23 @@ enum { | |||
454 | ACTION_FOLLOWLINKS = (1 << 1), | 455 | ACTION_FOLLOWLINKS = (1 << 1), |
455 | ACTION_FOLLOWLINKS_L0 = (1 << 2), | 456 | ACTION_FOLLOWLINKS_L0 = (1 << 2), |
456 | ACTION_DEPTHFIRST = (1 << 3), | 457 | ACTION_DEPTHFIRST = (1 << 3), |
457 | /*ACTION_REVERSE = (1 << 4), - unused */ | 458 | ACTION_QUIET = (1 << 4), |
458 | ACTION_QUIET = (1 << 5), | 459 | ACTION_DANGLING_OK = (1 << 5), |
459 | ACTION_DANGLING_OK = (1 << 6), | ||
460 | }; | 460 | }; |
461 | typedef uint8_t recurse_flags_t; | 461 | typedef uint8_t recurse_flags_t; |
462 | extern int recursive_action(const char *fileName, unsigned flags, | 462 | typedef struct recursive_state { |
463 | int FAST_FUNC (*fileAction)(const char *fileName, struct stat* statbuf, void* userData, int depth), | 463 | unsigned flags; |
464 | int FAST_FUNC (*dirAction)(const char *fileName, struct stat* statbuf, void* userData, int depth), | 464 | unsigned depth; |
465 | void* userData, unsigned depth) FAST_FUNC; | 465 | void *userData; |
466 | int FAST_FUNC (*fileAction)(struct recursive_state *state, const char *fileName, struct stat* statbuf); | ||
467 | int FAST_FUNC (*dirAction)(struct recursive_state *state, const char *fileName, struct stat* statbuf); | ||
468 | } recursive_state_t; | ||
469 | int recursive_action(const char *fileName, unsigned flags, | ||
470 | int FAST_FUNC (*fileAction)(struct recursive_state *state, const char *fileName, struct stat* statbuf), | ||
471 | int FAST_FUNC (*dirAction)(struct recursive_state *state, const char *fileName, struct stat* statbuf), | ||
472 | void *userData | ||
473 | ) FAST_FUNC; | ||
474 | |||
466 | extern int device_open(const char *device, int mode) FAST_FUNC; | 475 | extern int device_open(const char *device, int mode) FAST_FUNC; |
467 | enum { GETPTY_BUFSIZE = 16 }; /* more than enough for "/dev/ttyXXX" */ | 476 | enum { GETPTY_BUFSIZE = 16 }; /* more than enough for "/dev/ttyXXX" */ |
468 | extern int xgetpty(char *line) FAST_FUNC; | 477 | extern int xgetpty(char *line) FAST_FUNC; |
@@ -856,7 +865,7 @@ ssize_t recv_from_to(int fd, void *buf, size_t len, int flags, | |||
856 | struct sockaddr *to, | 865 | struct sockaddr *to, |
857 | socklen_t sa_size) FAST_FUNC; | 866 | socklen_t sa_size) FAST_FUNC; |
858 | 867 | ||
859 | uint16_t inet_cksum(uint16_t *addr, int len) FAST_FUNC; | 868 | uint16_t inet_cksum(const void *addr, int len) FAST_FUNC; |
860 | int parse_pasv_epsv(char *buf) FAST_FUNC; | 869 | int parse_pasv_epsv(char *buf) FAST_FUNC; |
861 | 870 | ||
862 | /* 0 if argv[0] is NULL: */ | 871 | /* 0 if argv[0] is NULL: */ |
@@ -1558,7 +1567,8 @@ int del_loop(const char *device) FAST_FUNC; | |||
1558 | * malloc and return it in *devname. | 1567 | * malloc and return it in *devname. |
1559 | * return value is the opened fd to the loop device, or < on error | 1568 | * return value is the opened fd to the loop device, or < on error |
1560 | */ | 1569 | */ |
1561 | int set_loop(char **devname, const char *file, unsigned long long offset, unsigned flags) FAST_FUNC; | 1570 | int set_loop(char **devname, const char *file, unsigned long long offset, |
1571 | unsigned long long sizelimit, unsigned flags) FAST_FUNC; | ||
1562 | /* These constants match linux/loop.h (without BB_ prefix): */ | 1572 | /* These constants match linux/loop.h (without BB_ prefix): */ |
1563 | #define BB_LO_FLAGS_READ_ONLY 1 | 1573 | #define BB_LO_FLAGS_READ_ONLY 1 |
1564 | #define BB_LO_FLAGS_AUTOCLEAR 4 | 1574 | #define BB_LO_FLAGS_AUTOCLEAR 4 |
diff --git a/libbb/appletlib.c b/libbb/appletlib.c index 77a9c3b7d..6ed86e12b 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c | |||
@@ -25,6 +25,11 @@ | |||
25 | * | 25 | * |
26 | * FEATURE_INSTALLER or FEATURE_SUID will still link printf routines in. :( | 26 | * FEATURE_INSTALLER or FEATURE_SUID will still link printf routines in. :( |
27 | */ | 27 | */ |
28 | |||
29 | /* Define this accessor before we #define "errno" our way */ | ||
30 | #include <errno.h> | ||
31 | static inline int *get_perrno(void) { return &errno; } | ||
32 | |||
28 | #include "busybox.h" | 33 | #include "busybox.h" |
29 | 34 | ||
30 | #if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \ | 35 | #if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \ |
@@ -318,8 +323,8 @@ void lbb_prepare(const char *applet | |||
318 | void lbb_prepare(const char *applet | 323 | void lbb_prepare(const char *applet |
319 | IF_FEATURE_INDIVIDUAL(, char **argv)) | 324 | IF_FEATURE_INDIVIDUAL(, char **argv)) |
320 | { | 325 | { |
321 | #ifdef __GLIBC__ | 326 | #ifdef bb_cached_errno_ptr |
322 | (*(int **)not_const_pp(&bb_errno)) = __errno_location(); | 327 | (*(int **)not_const_pp(&bb_errno)) = get_perrno(); |
323 | barrier(); | 328 | barrier(); |
324 | #endif | 329 | #endif |
325 | applet_name = applet; | 330 | applet_name = applet; |
diff --git a/libbb/dump.c b/libbb/dump.c index 8029cca0e..1ba1132b3 100644 --- a/libbb/dump.c +++ b/libbb/dump.c | |||
@@ -13,13 +13,19 @@ | |||
13 | #include "libbb.h" | 13 | #include "libbb.h" |
14 | #include "dump.h" | 14 | #include "dump.h" |
15 | 15 | ||
16 | static const char dot_flags_width_chars[] ALIGN1 = ".#-+ 0123456789"; | 16 | #define F_IGNORE 0x01 /* %_A */ |
17 | 17 | #define F_SETREP 0x02 /* rep count set, not default */ | |
18 | static const char size_conv_str[] ALIGN1 = | 18 | #define F_ADDRESS 0x001 /* print offset */ |
19 | "\x1\x4\x4\x4\x4\x4\x4\x8\x8\x8\x8\010cdiouxXeEfgG"; | 19 | #define F_BPAD 0x002 /* blank pad */ |
20 | 20 | #define F_C 0x004 /* %_c */ | |
21 | static const char int_convs[] ALIGN1 = "diouxX"; | 21 | #define F_CHAR 0x008 /* %c */ |
22 | 22 | #define F_DBL 0x010 /* %[EefGf] */ | |
23 | #define F_INT 0x020 /* %[di] */ | ||
24 | #define F_P 0x040 /* %_p */ | ||
25 | #define F_STR 0x080 /* %s */ | ||
26 | #define F_U 0x100 /* %_u */ | ||
27 | #define F_UINT 0x200 /* %[ouXx] */ | ||
28 | #define F_TEXT 0x400 /* no conversions */ | ||
23 | 29 | ||
24 | typedef struct priv_dumper_t { | 30 | typedef struct priv_dumper_t { |
25 | dumper_t pub; | 31 | dumper_t pub; |
@@ -39,6 +45,13 @@ typedef struct priv_dumper_t { | |||
39 | unsigned char *get__savp; | 45 | unsigned char *get__savp; |
40 | } priv_dumper_t; | 46 | } priv_dumper_t; |
41 | 47 | ||
48 | static const char dot_flags_width_chars[] ALIGN1 = ".#-+ 0123456789"; | ||
49 | |||
50 | static const char size_conv_str[] ALIGN1 = | ||
51 | "\x1\x4\x4\x4\x4\x4\x4\x8\x8\x8\x8\010cdiouxXeEfgG"; | ||
52 | |||
53 | static const char int_convs[] ALIGN1 = "diouxX"; | ||
54 | |||
42 | dumper_t* FAST_FUNC alloc_dumper(void) | 55 | dumper_t* FAST_FUNC alloc_dumper(void) |
43 | { | 56 | { |
44 | priv_dumper_t *dumper = xzalloc(sizeof(*dumper)); | 57 | priv_dumper_t *dumper = xzalloc(sizeof(*dumper)); |
@@ -48,7 +61,6 @@ dumper_t* FAST_FUNC alloc_dumper(void) | |||
48 | return &dumper->pub; | 61 | return &dumper->pub; |
49 | } | 62 | } |
50 | 63 | ||
51 | |||
52 | static NOINLINE int bb_dump_size(FS *fs) | 64 | static NOINLINE int bb_dump_size(FS *fs) |
53 | { | 65 | { |
54 | FU *fu; | 66 | FU *fu; |
@@ -284,7 +296,9 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) | |||
284 | * repeat it as necessary. | 296 | * repeat it as necessary. |
285 | * | 297 | * |
286 | * if rep count is greater than 1, no trailing whitespace | 298 | * if rep count is greater than 1, no trailing whitespace |
287 | * gets output from the last iteration of the format unit. | 299 | * gets output from the last iteration of the format unit: |
300 | * 2/1 "%02x " prints "XX XX", not "XX XX " | ||
301 | * 2/1 "%02x\n" prints "XX\nXX", not "XX\nXX\n" | ||
288 | */ | 302 | */ |
289 | for (fu = fs->nextfu; fu; fu = fu->nextfu) { | 303 | for (fu = fs->nextfu; fu; fu = fu->nextfu) { |
290 | if (!fu->nextfu | 304 | if (!fu->nextfu |
@@ -394,7 +408,6 @@ static unsigned char *get(priv_dumper_t *dumper) | |||
394 | if (dumper->pub.dump_vflag != DUP) { | 408 | if (dumper->pub.dump_vflag != DUP) { |
395 | puts("*"); | 409 | puts("*"); |
396 | } | 410 | } |
397 | return NULL; | ||
398 | } | 411 | } |
399 | memset(dumper->get__curp + nread, 0, need); | 412 | memset(dumper->get__curp + nread, 0, need); |
400 | dumper->eaddress = dumper->address + nread; | 413 | dumper->eaddress = dumper->address + nread; |
@@ -453,7 +466,7 @@ static void bpad(PR *pr) | |||
453 | for (p2 = ++p1; *p1 && strchr(" -0+#", *p1); ++p1) | 466 | for (p2 = ++p1; *p1 && strchr(" -0+#", *p1); ++p1) |
454 | if (pr->nospace) | 467 | if (pr->nospace) |
455 | pr->nospace--; | 468 | pr->nospace--; |
456 | while ((*p2++ = *p1++) != 0) | 469 | while ((*p2++ = *p1++) != '\0') |
457 | continue; | 470 | continue; |
458 | } | 471 | } |
459 | 472 | ||
@@ -520,36 +533,43 @@ static void conv_u(PR *pr, unsigned char *p) | |||
520 | 533 | ||
521 | static void display(priv_dumper_t* dumper) | 534 | static void display(priv_dumper_t* dumper) |
522 | { | 535 | { |
523 | FS *fs; | 536 | unsigned char *bp; |
524 | FU *fu; | ||
525 | PR *pr; | ||
526 | int cnt; | ||
527 | unsigned char *bp, *savebp; | ||
528 | off_t saveaddress; | ||
529 | unsigned char savech = '\0'; | 537 | unsigned char savech = '\0'; |
530 | 538 | ||
531 | while ((bp = get(dumper)) != NULL) { | 539 | while ((bp = get(dumper)) != NULL) { |
540 | FS *fs; | ||
541 | unsigned char *savebp; | ||
542 | off_t saveaddress; | ||
543 | |||
532 | fs = dumper->pub.fshead; | 544 | fs = dumper->pub.fshead; |
533 | savebp = bp; | 545 | savebp = bp; |
534 | saveaddress = dumper->address; | 546 | saveaddress = dumper->address; |
535 | for (; fs; fs = fs->nextfs, bp = savebp, dumper->address = saveaddress) { | 547 | for (; fs; fs = fs->nextfs, bp = savebp, dumper->address = saveaddress) { |
548 | FU *fu; | ||
536 | for (fu = fs->nextfu; fu; fu = fu->nextfu) { | 549 | for (fu = fs->nextfu; fu; fu = fu->nextfu) { |
550 | int cnt; | ||
537 | if (fu->flags & F_IGNORE) { | 551 | if (fu->flags & F_IGNORE) { |
538 | break; | 552 | break; |
539 | } | 553 | } |
540 | for (cnt = fu->reps; cnt; --cnt) { | 554 | for (cnt = fu->reps; cnt; --cnt) { |
555 | PR *pr; | ||
541 | for (pr = fu->nextpr; pr; dumper->address += pr->bcnt, | 556 | for (pr = fu->nextpr; pr; dumper->address += pr->bcnt, |
542 | bp += pr->bcnt, pr = pr->nextpr) { | 557 | bp += pr->bcnt, pr = pr->nextpr) { |
543 | if (dumper->eaddress && dumper->address >= dumper->eaddress | 558 | if (dumper->eaddress |
544 | && !(pr->flags & (F_TEXT | F_BPAD)) | 559 | && dumper->address >= dumper->eaddress |
545 | ) { | 560 | ) { |
546 | bpad(pr); | 561 | if (dumper->pub.eofstring) { |
562 | /* xxd support: requested to not pad incomplete blocks */ | ||
563 | fputs(dumper->pub.eofstring, stdout); | ||
564 | return; | ||
565 | } | ||
566 | if (!(pr->flags & (F_TEXT | F_BPAD))) | ||
567 | bpad(pr); | ||
547 | } | 568 | } |
548 | if (cnt == 1 && pr->nospace) { | 569 | if (cnt == 1 && pr->nospace) { |
549 | savech = *pr->nospace; | 570 | savech = *pr->nospace; |
550 | *pr->nospace = '\0'; | 571 | *pr->nospace = '\0'; |
551 | } | 572 | } |
552 | /* PRINT; */ | ||
553 | switch (pr->flags) { | 573 | switch (pr->flags) { |
554 | case F_ADDRESS: | 574 | case F_ADDRESS: |
555 | printf(pr->fmt, (unsigned) dumper->address); | 575 | printf(pr->fmt, (unsigned) dumper->address); |
@@ -638,7 +658,9 @@ static void display(priv_dumper_t* dumper) | |||
638 | } | 658 | } |
639 | } | 659 | } |
640 | } | 660 | } |
661 | |||
641 | if (dumper->endfu) { | 662 | if (dumper->endfu) { |
663 | PR *pr; | ||
642 | /* | 664 | /* |
643 | * if eaddress not set, error or file size was multiple | 665 | * if eaddress not set, error or file size was multiple |
644 | * of blocksize, and no partial block ever found. | 666 | * of blocksize, and no partial block ever found. |
@@ -695,8 +717,7 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt) | |||
695 | { | 717 | { |
696 | const char *p; | 718 | const char *p; |
697 | FS *tfs; | 719 | FS *tfs; |
698 | FU *tfu, **nextfupp; | 720 | FU **nextfupp; |
699 | const char *savep; | ||
700 | 721 | ||
701 | /* start new linked list of format units */ | 722 | /* start new linked list of format units */ |
702 | tfs = xzalloc(sizeof(FS)); /*DBU:[dave@cray.com] start out NULL */ | 723 | tfs = xzalloc(sizeof(FS)); /*DBU:[dave@cray.com] start out NULL */ |
@@ -713,6 +734,9 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt) | |||
713 | /* take the format string and break it up into format units */ | 734 | /* take the format string and break it up into format units */ |
714 | p = fmt; | 735 | p = fmt; |
715 | for (;;) { | 736 | for (;;) { |
737 | FU *tfu; | ||
738 | const char *savep; | ||
739 | |||
716 | p = skip_whitespace(p); | 740 | p = skip_whitespace(p); |
717 | if (*p == '\0') { | 741 | if (*p == '\0') { |
718 | break; | 742 | break; |
diff --git a/libbb/hash_md5_sha.c b/libbb/hash_md5_sha.c index 9db79ea8b..d8f210173 100644 --- a/libbb/hash_md5_sha.c +++ b/libbb/hash_md5_sha.c | |||
@@ -38,35 +38,6 @@ static ALWAYS_INLINE uint64_t rotl64(uint64_t x, unsigned n) | |||
38 | return (x << n) | (x >> (64 - n)); | 38 | return (x << n) | (x >> (64 - n)); |
39 | } | 39 | } |
40 | 40 | ||
41 | /* Feed data through a temporary buffer. | ||
42 | * The internal buffer remembers previous data until it has 64 | ||
43 | * bytes worth to pass on. | ||
44 | */ | ||
45 | static void FAST_FUNC common64_hash(md5_ctx_t *ctx, const void *buffer, size_t len) | ||
46 | { | ||
47 | unsigned bufpos = ctx->total64 & 63; | ||
48 | |||
49 | ctx->total64 += len; | ||
50 | |||
51 | while (1) { | ||
52 | unsigned remaining = 64 - bufpos; | ||
53 | if (remaining > len) | ||
54 | remaining = len; | ||
55 | /* Copy data into aligned buffer */ | ||
56 | memcpy(ctx->wbuffer + bufpos, buffer, remaining); | ||
57 | len -= remaining; | ||
58 | buffer = (const char *)buffer + remaining; | ||
59 | bufpos += remaining; | ||
60 | /* Clever way to do "if (bufpos != N) break; ... ; bufpos = 0;" */ | ||
61 | bufpos -= 64; | ||
62 | if (bufpos != 0) | ||
63 | break; | ||
64 | /* Buffer is filled up, process it */ | ||
65 | ctx->process_block(ctx); | ||
66 | /*bufpos = 0; - already is */ | ||
67 | } | ||
68 | } | ||
69 | |||
70 | /* Process the remaining bytes in the buffer */ | 41 | /* Process the remaining bytes in the buffer */ |
71 | static void FAST_FUNC common64_end(md5_ctx_t *ctx, int swap_needed) | 42 | static void FAST_FUNC common64_end(md5_ctx_t *ctx, int swap_needed) |
72 | { | 43 | { |
@@ -449,7 +420,29 @@ void FAST_FUNC md5_begin(md5_ctx_t *ctx) | |||
449 | /* Used also for sha1 and sha256 */ | 420 | /* Used also for sha1 and sha256 */ |
450 | void FAST_FUNC md5_hash(md5_ctx_t *ctx, const void *buffer, size_t len) | 421 | void FAST_FUNC md5_hash(md5_ctx_t *ctx, const void *buffer, size_t len) |
451 | { | 422 | { |
452 | common64_hash(ctx, buffer, len); | 423 | unsigned bufpos = ctx->total64 & 63; |
424 | |||
425 | ctx->total64 += len; | ||
426 | |||
427 | while (1) { | ||
428 | unsigned remaining = 64 - bufpos; | ||
429 | if (remaining > len) | ||
430 | remaining = len; | ||
431 | /* Copy data into aligned buffer */ | ||
432 | memcpy(ctx->wbuffer + bufpos, buffer, remaining); | ||
433 | len -= remaining; | ||
434 | buffer = (const char *)buffer + remaining; | ||
435 | bufpos += remaining; | ||
436 | |||
437 | /* Clever way to do "if (bufpos != N) break; ... ; bufpos = 0;" */ | ||
438 | bufpos -= 64; | ||
439 | if (bufpos != 0) | ||
440 | break; | ||
441 | |||
442 | /* Buffer is filled up, process it */ | ||
443 | ctx->process_block(ctx); | ||
444 | /*bufpos = 0; - already is */ | ||
445 | } | ||
453 | } | 446 | } |
454 | 447 | ||
455 | /* Process the remaining bytes in the buffer and put result from CTX | 448 | /* Process the remaining bytes in the buffer and put result from CTX |
@@ -816,7 +809,7 @@ void FAST_FUNC sha512_begin(sha512_ctx_t *ctx) | |||
816 | int i; | 809 | int i; |
817 | /* Two extra iterations zero out ctx->total64[2] */ | 810 | /* Two extra iterations zero out ctx->total64[2] */ |
818 | uint64_t *tp = ctx->total64; | 811 | uint64_t *tp = ctx->total64; |
819 | for (i = 0; i < 2+8; i++) | 812 | for (i = 0; i < 8 + 2; i++) |
820 | tp[i] = ((uint64_t)(init256[i]) << 32) + init512_lo[i]; | 813 | tp[i] = ((uint64_t)(init256[i]) << 32) + init512_lo[i]; |
821 | /*ctx->total64[0] = ctx->total64[1] = 0; - already done */ | 814 | /*ctx->total64[0] = ctx->total64[1] = 0; - already done */ |
822 | } | 815 | } |
@@ -832,22 +825,7 @@ void FAST_FUNC sha512_hash(sha512_ctx_t *ctx, const void *buffer, size_t len) | |||
832 | ctx->total64[0] += len; | 825 | ctx->total64[0] += len; |
833 | if (ctx->total64[0] < len) | 826 | if (ctx->total64[0] < len) |
834 | ctx->total64[1]++; | 827 | ctx->total64[1]++; |
835 | # if 0 | ||
836 | remaining = 128 - bufpos; | ||
837 | 828 | ||
838 | /* Hash whole blocks */ | ||
839 | while (len >= remaining) { | ||
840 | memcpy(ctx->wbuffer + bufpos, buffer, remaining); | ||
841 | buffer = (const char *)buffer + remaining; | ||
842 | len -= remaining; | ||
843 | remaining = 128; | ||
844 | bufpos = 0; | ||
845 | sha512_process_block128(ctx); | ||
846 | } | ||
847 | |||
848 | /* Save last, partial blosk */ | ||
849 | memcpy(ctx->wbuffer + bufpos, buffer, len); | ||
850 | # else | ||
851 | while (1) { | 829 | while (1) { |
852 | remaining = 128 - bufpos; | 830 | remaining = 128 - bufpos; |
853 | if (remaining > len) | 831 | if (remaining > len) |
@@ -857,15 +835,16 @@ void FAST_FUNC sha512_hash(sha512_ctx_t *ctx, const void *buffer, size_t len) | |||
857 | len -= remaining; | 835 | len -= remaining; |
858 | buffer = (const char *)buffer + remaining; | 836 | buffer = (const char *)buffer + remaining; |
859 | bufpos += remaining; | 837 | bufpos += remaining; |
838 | |||
860 | /* Clever way to do "if (bufpos != N) break; ... ; bufpos = 0;" */ | 839 | /* Clever way to do "if (bufpos != N) break; ... ; bufpos = 0;" */ |
861 | bufpos -= 128; | 840 | bufpos -= 128; |
862 | if (bufpos != 0) | 841 | if (bufpos != 0) |
863 | break; | 842 | break; |
843 | |||
864 | /* Buffer is filled up, process it */ | 844 | /* Buffer is filled up, process it */ |
865 | sha512_process_block128(ctx); | 845 | sha512_process_block128(ctx); |
866 | /*bufpos = 0; - already is */ | 846 | /*bufpos = 0; - already is */ |
867 | } | 847 | } |
868 | # endif | ||
869 | } | 848 | } |
870 | #endif /* NEED_SHA512 */ | 849 | #endif /* NEED_SHA512 */ |
871 | 850 | ||
@@ -1398,10 +1377,12 @@ void FAST_FUNC sha3_hash(sha3_ctx_t *ctx, const void *buffer, size_t len) | |||
1398 | bufpos++; | 1377 | bufpos++; |
1399 | remaining--; | 1378 | remaining--; |
1400 | } | 1379 | } |
1380 | |||
1401 | /* Clever way to do "if (bufpos != N) break; ... ; bufpos = 0;" */ | 1381 | /* Clever way to do "if (bufpos != N) break; ... ; bufpos = 0;" */ |
1402 | bufpos -= ctx->input_block_bytes; | 1382 | bufpos -= ctx->input_block_bytes; |
1403 | if (bufpos != 0) | 1383 | if (bufpos != 0) |
1404 | break; | 1384 | break; |
1385 | |||
1405 | /* Buffer is filled up, process it */ | 1386 | /* Buffer is filled up, process it */ |
1406 | sha3_process_block72(ctx->state); | 1387 | sha3_process_block72(ctx->state); |
1407 | /*bufpos = 0; - already is */ | 1388 | /*bufpos = 0; - already is */ |
diff --git a/libbb/inet_cksum.c b/libbb/inet_cksum.c index 3d5dc3adf..fee8648f3 100644 --- a/libbb/inet_cksum.c +++ b/libbb/inet_cksum.c | |||
@@ -6,8 +6,10 @@ | |||
6 | 6 | ||
7 | #include "libbb.h" | 7 | #include "libbb.h" |
8 | 8 | ||
9 | uint16_t FAST_FUNC inet_cksum(uint16_t *addr, int nleft) | 9 | uint16_t FAST_FUNC inet_cksum(const void *ptr, int nleft) |
10 | { | 10 | { |
11 | const uint16_t *addr = ptr; | ||
12 | |||
11 | /* | 13 | /* |
12 | * Our algorithm is simple, using a 32 bit accumulator, | 14 | * Our algorithm is simple, using a 32 bit accumulator, |
13 | * we add sequential 16 bit words to it, and at the end, fold | 15 | * we add sequential 16 bit words to it, and at the end, fold |
diff --git a/libbb/kernel_version.c b/libbb/kernel_version.c index 7769a091b..6bb32ce5f 100644 --- a/libbb/kernel_version.c +++ b/libbb/kernel_version.c | |||
@@ -19,15 +19,17 @@ int FAST_FUNC get_linux_version_code(void) | |||
19 | { | 19 | { |
20 | struct utsname name; | 20 | struct utsname name; |
21 | char *t; | 21 | char *t; |
22 | int i, r; | 22 | int r; |
23 | 23 | ||
24 | uname(&name); /* never fails */ | 24 | uname(&name); /* never fails */ |
25 | t = name.release; | 25 | t = name.release - 1; |
26 | r = 0; | 26 | r = 1; |
27 | for (i = 0; i < 3; i++) { | 27 | do { |
28 | t = strtok(t, "."); | 28 | r <<= 8; |
29 | r = r * 256 + (t ? atoi(t) : 0); | 29 | if (t) { |
30 | t = NULL; | 30 | r += atoi(++t); |
31 | } | 31 | t = strchr(t, '.'); |
32 | return r; | 32 | } |
33 | } while (r < 0x1000000); | ||
34 | return r - 0x1000000; | ||
33 | } | 35 | } |
diff --git a/libbb/loop.c b/libbb/loop.c index ada0c7638..85b2724e5 100644 --- a/libbb/loop.c +++ b/libbb/loop.c | |||
@@ -102,7 +102,8 @@ int FAST_FUNC get_free_loop(void) | |||
102 | * search will re-use an existing loop device already bound to that | 102 | * search will re-use an existing loop device already bound to that |
103 | * file/offset if it finds one. | 103 | * file/offset if it finds one. |
104 | */ | 104 | */ |
105 | int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offset, unsigned flags) | 105 | int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offset, |
106 | unsigned long long sizelimit, unsigned flags) | ||
106 | { | 107 | { |
107 | char dev[LOOP_NAMESIZE]; | 108 | char dev[LOOP_NAMESIZE]; |
108 | char *try; | 109 | char *try; |
@@ -185,6 +186,7 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse | |||
185 | memset(&loopinfo, 0, sizeof(loopinfo)); | 186 | memset(&loopinfo, 0, sizeof(loopinfo)); |
186 | safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); | 187 | safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); |
187 | loopinfo.lo_offset = offset; | 188 | loopinfo.lo_offset = offset; |
189 | loopinfo.lo_sizelimit = sizelimit; | ||
188 | /* | 190 | /* |
189 | * Used by mount to set LO_FLAGS_AUTOCLEAR. | 191 | * Used by mount to set LO_FLAGS_AUTOCLEAR. |
190 | * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. | 192 | * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. |
diff --git a/libbb/ptr_to_globals.c b/libbb/ptr_to_globals.c index 8ba9cd154..2232c6864 100644 --- a/libbb/ptr_to_globals.c +++ b/libbb/ptr_to_globals.c | |||
@@ -14,7 +14,7 @@ struct globals; | |||
14 | * but here we make it live in R/W memory */ | 14 | * but here we make it live in R/W memory */ |
15 | struct globals *ptr_to_globals; | 15 | struct globals *ptr_to_globals; |
16 | 16 | ||
17 | #ifdef __GLIBC__ | 17 | #ifdef errno |
18 | int *bb_errno; | 18 | int *bb_errno; |
19 | #endif | 19 | #endif |
20 | 20 | ||
@@ -27,7 +27,7 @@ int *bb_errno; | |||
27 | * on weird architectures, compilers, linkers and so on */ | 27 | * on weird architectures, compilers, linkers and so on */ |
28 | struct globals *const ptr_to_globals __attribute__ ((section (".data"))); | 28 | struct globals *const ptr_to_globals __attribute__ ((section (".data"))); |
29 | 29 | ||
30 | #ifdef __GLIBC__ | 30 | #ifdef errno |
31 | int *const bb_errno __attribute__ ((section (".data"))); | 31 | int *const bb_errno __attribute__ ((section (".data"))); |
32 | #endif | 32 | #endif |
33 | 33 | ||
diff --git a/libbb/recursive_action.c b/libbb/recursive_action.c index 0831ecc3a..b1c4bfad7 100644 --- a/libbb/recursive_action.c +++ b/libbb/recursive_action.c | |||
@@ -21,10 +21,9 @@ | |||
21 | * is so stinking huge. | 21 | * is so stinking huge. |
22 | */ | 22 | */ |
23 | 23 | ||
24 | static int FAST_FUNC true_action(const char *fileName UNUSED_PARAM, | 24 | static int FAST_FUNC true_action(struct recursive_state *state UNUSED_PARAM, |
25 | struct stat *statbuf UNUSED_PARAM, | 25 | const char *fileName UNUSED_PARAM, |
26 | void* userData UNUSED_PARAM, | 26 | struct stat *statbuf UNUSED_PARAM) |
27 | int depth UNUSED_PARAM) | ||
28 | { | 27 | { |
29 | return TRUE; | 28 | return TRUE; |
30 | } | 29 | } |
@@ -65,12 +64,7 @@ static int FAST_FUNC true_action(const char *fileName UNUSED_PARAM, | |||
65 | * 1: stat(statbuf). Calls dirAction and optionally recurse on link to dir. | 64 | * 1: stat(statbuf). Calls dirAction and optionally recurse on link to dir. |
66 | */ | 65 | */ |
67 | 66 | ||
68 | int FAST_FUNC recursive_action(const char *fileName, | 67 | static int recursive_action1(recursive_state_t *state, const char *fileName) |
69 | unsigned flags, | ||
70 | int FAST_FUNC (*fileAction)(const char *fileName, struct stat *statbuf, void* userData, int depth), | ||
71 | int FAST_FUNC (*dirAction)(const char *fileName, struct stat *statbuf, void* userData, int depth), | ||
72 | void* userData, | ||
73 | unsigned depth) | ||
74 | { | 68 | { |
75 | struct stat statbuf; | 69 | struct stat statbuf; |
76 | unsigned follow; | 70 | unsigned follow; |
@@ -78,24 +72,21 @@ int FAST_FUNC recursive_action(const char *fileName, | |||
78 | DIR *dir; | 72 | DIR *dir; |
79 | struct dirent *next; | 73 | struct dirent *next; |
80 | 74 | ||
81 | if (!fileAction) fileAction = true_action; | ||
82 | if (!dirAction) dirAction = true_action; | ||
83 | |||
84 | follow = ACTION_FOLLOWLINKS; | 75 | follow = ACTION_FOLLOWLINKS; |
85 | if (depth == 0) | 76 | if (state->depth == 0) |
86 | follow = ACTION_FOLLOWLINKS | ACTION_FOLLOWLINKS_L0; | 77 | follow = ACTION_FOLLOWLINKS | ACTION_FOLLOWLINKS_L0; |
87 | follow &= flags; | 78 | follow &= state->flags; |
88 | status = (follow ? stat : lstat)(fileName, &statbuf); | 79 | status = (follow ? stat : lstat)(fileName, &statbuf); |
89 | if (status < 0) { | 80 | if (status < 0) { |
90 | #ifdef DEBUG_RECURS_ACTION | 81 | #ifdef DEBUG_RECURS_ACTION |
91 | bb_error_msg("status=%d flags=%x", status, flags); | 82 | bb_error_msg("status=%d flags=%x", status, state->flags); |
92 | #endif | 83 | #endif |
93 | if ((flags & ACTION_DANGLING_OK) | 84 | if ((state->flags & ACTION_DANGLING_OK) |
94 | && errno == ENOENT | 85 | && errno == ENOENT |
95 | && lstat(fileName, &statbuf) == 0 | 86 | && lstat(fileName, &statbuf) == 0 |
96 | ) { | 87 | ) { |
97 | /* Dangling link */ | 88 | /* Dangling link */ |
98 | return fileAction(fileName, &statbuf, userData, depth); | 89 | return state->fileAction(state, fileName, &statbuf); |
99 | } | 90 | } |
100 | goto done_nak_warn; | 91 | goto done_nak_warn; |
101 | } | 92 | } |
@@ -103,20 +94,20 @@ int FAST_FUNC recursive_action(const char *fileName, | |||
103 | /* If S_ISLNK(m), then we know that !S_ISDIR(m). | 94 | /* If S_ISLNK(m), then we know that !S_ISDIR(m). |
104 | * Then we can skip checking first part: if it is true, then | 95 | * Then we can skip checking first part: if it is true, then |
105 | * (!dir) is also true! */ | 96 | * (!dir) is also true! */ |
106 | if ( /* (!(flags & ACTION_FOLLOWLINKS) && S_ISLNK(statbuf.st_mode)) || */ | 97 | if ( /* (!(state->flags & ACTION_FOLLOWLINKS) && S_ISLNK(statbuf.st_mode)) || */ |
107 | !S_ISDIR(statbuf.st_mode) | 98 | !S_ISDIR(statbuf.st_mode) |
108 | ) { | 99 | ) { |
109 | return fileAction(fileName, &statbuf, userData, depth); | 100 | return state->fileAction(state, fileName, &statbuf); |
110 | } | 101 | } |
111 | 102 | ||
112 | /* It's a directory (or a link to one, and followLinks is set) */ | 103 | /* It's a directory (or a link to one, and followLinks is set) */ |
113 | 104 | ||
114 | if (!(flags & ACTION_RECURSE)) { | 105 | if (!(state->flags & ACTION_RECURSE)) { |
115 | return dirAction(fileName, &statbuf, userData, depth); | 106 | return state->dirAction(state, fileName, &statbuf); |
116 | } | 107 | } |
117 | 108 | ||
118 | if (!(flags & ACTION_DEPTHFIRST)) { | 109 | if (!(state->flags & ACTION_DEPTHFIRST)) { |
119 | status = dirAction(fileName, &statbuf, userData, depth); | 110 | status = state->dirAction(state, fileName, &statbuf); |
120 | if (status == FALSE) | 111 | if (status == FALSE) |
121 | goto done_nak_warn; | 112 | goto done_nak_warn; |
122 | if (status == SKIP) | 113 | if (status == SKIP) |
@@ -140,11 +131,13 @@ int FAST_FUNC recursive_action(const char *fileName, | |||
140 | continue; | 131 | continue; |
141 | 132 | ||
142 | /* process every file (NB: ACTION_RECURSE is set in flags) */ | 133 | /* process every file (NB: ACTION_RECURSE is set in flags) */ |
143 | s = recursive_action(nextFile, flags, fileAction, dirAction, | 134 | state->depth++; |
144 | userData, depth + 1); | 135 | s = recursive_action1(state, nextFile); |
145 | if (s == FALSE) | 136 | if (s == FALSE) |
146 | status = FALSE; | 137 | status = FALSE; |
147 | free(nextFile); | 138 | free(nextFile); |
139 | state->depth--; | ||
140 | |||
148 | //#define RECURSE_RESULT_ABORT -1 | 141 | //#define RECURSE_RESULT_ABORT -1 |
149 | // if (s == RECURSE_RESULT_ABORT) { | 142 | // if (s == RECURSE_RESULT_ABORT) { |
150 | // closedir(dir); | 143 | // closedir(dir); |
@@ -153,15 +146,36 @@ int FAST_FUNC recursive_action(const char *fileName, | |||
153 | } | 146 | } |
154 | closedir(dir); | 147 | closedir(dir); |
155 | 148 | ||
156 | if (flags & ACTION_DEPTHFIRST) { | 149 | if (state->flags & ACTION_DEPTHFIRST) { |
157 | if (!dirAction(fileName, &statbuf, userData, depth)) | 150 | if (!state->dirAction(state, fileName, &statbuf)) |
158 | goto done_nak_warn; | 151 | goto done_nak_warn; |
159 | } | 152 | } |
160 | 153 | ||
161 | return status; | 154 | return status; |
162 | 155 | ||
163 | done_nak_warn: | 156 | done_nak_warn: |
164 | if (!(flags & ACTION_QUIET)) | 157 | if (!(state->flags & ACTION_QUIET)) |
165 | bb_simple_perror_msg(fileName); | 158 | bb_simple_perror_msg(fileName); |
166 | return FALSE; | 159 | return FALSE; |
167 | } | 160 | } |
161 | |||
162 | int FAST_FUNC recursive_action(const char *fileName, | ||
163 | unsigned flags, | ||
164 | int FAST_FUNC (*fileAction)(struct recursive_state *state, const char *fileName, struct stat* statbuf), | ||
165 | int FAST_FUNC (*dirAction)(struct recursive_state *state, const char *fileName, struct stat* statbuf), | ||
166 | void *userData) | ||
167 | { | ||
168 | /* Keeping a part of variables of recusive descent in a "state structure" | ||
169 | * instead of passing ALL of them down as parameters of recursive_action1() | ||
170 | * relieves register pressure, both in recursive_action1() | ||
171 | * and in every file/dirAction(). | ||
172 | */ | ||
173 | recursive_state_t state; | ||
174 | state.flags = flags; | ||
175 | state.depth = 0; | ||
176 | state.userData = userData; | ||
177 | state.fileAction = fileAction ? fileAction : true_action; | ||
178 | state.dirAction = dirAction ? dirAction : true_action; | ||
179 | |||
180 | return recursive_action1(&state, fileName); | ||
181 | } | ||
diff --git a/libbb/update_passwd.c b/libbb/update_passwd.c index c605c4c64..7b67f30cd 100644 --- a/libbb/update_passwd.c +++ b/libbb/update_passwd.c | |||
@@ -18,17 +18,20 @@ | |||
18 | #if ENABLE_SELINUX | 18 | #if ENABLE_SELINUX |
19 | static void check_selinux_update_passwd(const char *username) | 19 | static void check_selinux_update_passwd(const char *username) |
20 | { | 20 | { |
21 | security_context_t context; | 21 | security_context_t seuser; |
22 | char *seuser; | 22 | char *p; |
23 | 23 | ||
24 | if (getuid() != (uid_t)0 || is_selinux_enabled() == 0) | 24 | if (getuid() != (uid_t)0 || is_selinux_enabled() == 0) |
25 | return; /* No need to check */ | 25 | return; /* No need to check */ |
26 | 26 | ||
27 | if (getprevcon_raw(&context) < 0) | 27 | if (getprevcon_raw(&seuser) < 0) |
28 | bb_simple_perror_msg_and_die("getprevcon failed"); | 28 | bb_simple_perror_msg_and_die("getprevcon failed"); |
29 | seuser = strtok(context, ":"); | 29 | |
30 | if (!seuser) | 30 | p = strchr(seuser, ':'); |
31 | bb_error_msg_and_die("invalid context '%s'", context); | 31 | if (!p) |
32 | bb_error_msg_and_die("invalid context '%s'", seuser); | ||
33 | *p = '\0'; | ||
34 | |||
32 | if (strcmp(seuser, username) != 0) { | 35 | if (strcmp(seuser, username) != 0) { |
33 | security_class_t tclass; | 36 | security_class_t tclass; |
34 | access_vector_t av; | 37 | access_vector_t av; |
diff --git a/mailutils/reformime.c b/mailutils/reformime.c index 321729e0a..307656a15 100644 --- a/mailutils/reformime.c +++ b/mailutils/reformime.c | |||
@@ -115,6 +115,7 @@ static int parse(const char *boundary, char **argv) | |||
115 | /* Split to tokens */ | 115 | /* Split to tokens */ |
116 | { | 116 | { |
117 | char *s, *p; | 117 | char *s, *p; |
118 | char *tokstate; | ||
118 | unsigned ntokens; | 119 | unsigned ntokens; |
119 | const char *delims = ";=\" \t\n"; | 120 | const char *delims = ";=\" \t\n"; |
120 | 121 | ||
@@ -127,13 +128,13 @@ static int parse(const char *boundary, char **argv) | |||
127 | } | 128 | } |
128 | dbg_error_msg("L:'%s'", p); | 129 | dbg_error_msg("L:'%s'", p); |
129 | ntokens = 0; | 130 | ntokens = 0; |
130 | s = strtok(s, delims); | 131 | s = strtok_r(s, delims, &tokstate); |
131 | while (s) { | 132 | while (s) { |
132 | tokens[ntokens] = s; | 133 | tokens[ntokens] = s; |
133 | if (ntokens < ARRAY_SIZE(tokens) - 1) | 134 | if (ntokens < ARRAY_SIZE(tokens) - 1) |
134 | ntokens++; | 135 | ntokens++; |
135 | dbg_error_msg("L[%d]='%s'", ntokens, s); | 136 | dbg_error_msg("L[%d]='%s'", ntokens, s); |
136 | s = strtok(NULL, delims); | 137 | s = strtok_r(NULL, delims, &tokstate); |
137 | } | 138 | } |
138 | tokens[ntokens] = NULL; | 139 | tokens[ntokens] = NULL; |
139 | dbg_error_msg("EMPTYLINE, ntokens:%d", ntokens); | 140 | dbg_error_msg("EMPTYLINE, ntokens:%d", ntokens); |
diff --git a/modutils/depmod.c b/modutils/depmod.c index 318e7cdc7..bb42bbefe 100644 --- a/modutils/depmod.c +++ b/modutils/depmod.c | |||
@@ -32,10 +32,11 @@ | |||
32 | * for each depends, look through our list of full paths and emit if found | 32 | * for each depends, look through our list of full paths and emit if found |
33 | */ | 33 | */ |
34 | 34 | ||
35 | static int FAST_FUNC parse_module(const char *fname, struct stat *sb UNUSED_PARAM, | 35 | static int FAST_FUNC parse_module(struct recursive_state *state, |
36 | void *data, int depth UNUSED_PARAM) | 36 | const char *fname, |
37 | struct stat *sb UNUSED_PARAM) | ||
37 | { | 38 | { |
38 | module_db *modules = data; | 39 | module_db *modules = state->userData; |
39 | char *image, *ptr; | 40 | char *image, *ptr; |
40 | module_entry *e; | 41 | module_entry *e; |
41 | 42 | ||
@@ -201,11 +202,12 @@ int depmod_main(int argc UNUSED_PARAM, char **argv) | |||
201 | memset(&modules, 0, sizeof(modules)); | 202 | memset(&modules, 0, sizeof(modules)); |
202 | if (*argv) { | 203 | if (*argv) { |
203 | do { | 204 | do { |
204 | parse_module(*argv, /*sb (unused):*/ NULL, &modules, 0); | 205 | recursive_action(*argv, 0 /* no ACTION_RECURSE! */, |
206 | parse_module, NULL, &modules); | ||
205 | } while (*++argv); | 207 | } while (*++argv); |
206 | } else { | 208 | } else { |
207 | recursive_action(".", ACTION_RECURSE, | 209 | recursive_action(".", ACTION_RECURSE, |
208 | parse_module, NULL, &modules, 0); | 210 | parse_module, NULL, &modules); |
209 | } | 211 | } |
210 | 212 | ||
211 | /* Generate dependency and alias files */ | 213 | /* Generate dependency and alias files */ |
diff --git a/modutils/modprobe-small.c b/modutils/modprobe-small.c index a94b0b9a6..18cfac481 100644 --- a/modutils/modprobe-small.c +++ b/modutils/modprobe-small.c | |||
@@ -751,8 +751,7 @@ static int process_module(char *name, const char *cmdline_options) | |||
751 | ACTION_RECURSE, /* flags */ | 751 | ACTION_RECURSE, /* flags */ |
752 | fileAction, /* file action */ | 752 | fileAction, /* file action */ |
753 | NULL, /* dir action */ | 753 | NULL, /* dir action */ |
754 | name, /* user data */ | 754 | name /* user data */ |
755 | 0 /* depth */ | ||
756 | ); | 755 | ); |
757 | dbg1_error_msg("dirscan complete"); | 756 | dbg1_error_msg("dirscan complete"); |
758 | /* Module was not found, or load failed, or is_remove */ | 757 | /* Module was not found, or load failed, or is_remove */ |
diff --git a/modutils/modprobe.c b/modutils/modprobe.c index 70c45903a..eeeff7609 100644 --- a/modutils/modprobe.c +++ b/modutils/modprobe.c | |||
@@ -235,10 +235,9 @@ static void add_probe(const char *name) | |||
235 | } | 235 | } |
236 | } | 236 | } |
237 | 237 | ||
238 | static int FAST_FUNC config_file_action(const char *filename, | 238 | static int FAST_FUNC config_file_action(struct recursive_state *state, |
239 | struct stat *statbuf UNUSED_PARAM, | 239 | const char *filename, |
240 | void *userdata UNUSED_PARAM, | 240 | struct stat *statbuf UNUSED_PARAM) |
241 | int depth) | ||
242 | { | 241 | { |
243 | char *tokens[3]; | 242 | char *tokens[3]; |
244 | parser_t *p; | 243 | parser_t *p; |
@@ -255,7 +254,7 @@ static int FAST_FUNC config_file_action(const char *filename, | |||
255 | * that we shouldn't recurse into /etc/modprobe.d/dir/ | 254 | * that we shouldn't recurse into /etc/modprobe.d/dir/ |
256 | * _subdirectories_: | 255 | * _subdirectories_: |
257 | */ | 256 | */ |
258 | if (depth > 1) | 257 | if (state->depth > 1) |
259 | return SKIP; /* stop recursing */ | 258 | return SKIP; /* stop recursing */ |
260 | //TODO: instead, can use dirAction in recursive_action() to SKIP dirs | 259 | //TODO: instead, can use dirAction in recursive_action() to SKIP dirs |
261 | //on depth == 1 level. But that's more code... | 260 | //on depth == 1 level. But that's more code... |
@@ -264,7 +263,7 @@ static int FAST_FUNC config_file_action(const char *filename, | |||
264 | * depth==0: read_config("modules.{symbols,alias}") must work, | 263 | * depth==0: read_config("modules.{symbols,alias}") must work, |
265 | * "include FILE_NOT_ENDING_IN_CONF" must work too. | 264 | * "include FILE_NOT_ENDING_IN_CONF" must work too. |
266 | */ | 265 | */ |
267 | if (depth != 0) { | 266 | if (state->depth != 0) { |
268 | if (!is_suffixed_with(base, ".conf")) | 267 | if (!is_suffixed_with(base, ".conf")) |
269 | goto error; | 268 | goto error; |
270 | } | 269 | } |
@@ -329,8 +328,7 @@ static int FAST_FUNC config_file_action(const char *filename, | |||
329 | static int read_config(const char *path) | 328 | static int read_config(const char *path) |
330 | { | 329 | { |
331 | return recursive_action(path, ACTION_RECURSE | ACTION_QUIET, | 330 | return recursive_action(path, ACTION_RECURSE | ACTION_QUIET, |
332 | config_file_action, NULL, NULL, | 331 | config_file_action, NULL, NULL); |
333 | /*depth:*/ 0); | ||
334 | } | 332 | } |
335 | 333 | ||
336 | static const char *humanly_readable_name(struct module_entry *m) | 334 | static const char *humanly_readable_name(struct module_entry *m) |
diff --git a/networking/httpd.c b/networking/httpd.c index 7684ca4e7..daa3ca1d0 100644 --- a/networking/httpd.c +++ b/networking/httpd.c | |||
@@ -1038,6 +1038,12 @@ static char *encodeString(const char *string) | |||
1038 | */ | 1038 | */ |
1039 | static void decodeBase64(char *Data) | 1039 | static void decodeBase64(char *Data) |
1040 | { | 1040 | { |
1041 | # if ENABLE_BASE64 || ENABLE_UUDECODE | ||
1042 | /* Call decode_base64() from uuencode.c */ | ||
1043 | char *eptr = Data; | ||
1044 | decode_base64(&eptr, Data); | ||
1045 | *eptr = '\0'; | ||
1046 | # else | ||
1041 | const unsigned char *in = (const unsigned char *)Data; | 1047 | const unsigned char *in = (const unsigned char *)Data; |
1042 | /* The decoded size will be at most 3/4 the size of the encoded */ | 1048 | /* The decoded size will be at most 3/4 the size of the encoded */ |
1043 | unsigned ch = 0; | 1049 | unsigned ch = 0; |
@@ -1071,6 +1077,7 @@ static void decodeBase64(char *Data) | |||
1071 | } | 1077 | } |
1072 | } | 1078 | } |
1073 | *Data = '\0'; | 1079 | *Data = '\0'; |
1080 | # endif | ||
1074 | } | 1081 | } |
1075 | #endif | 1082 | #endif |
1076 | 1083 | ||
diff --git a/networking/ip.c b/networking/ip.c index 7d3faf7f8..33bea5f49 100644 --- a/networking/ip.c +++ b/networking/ip.c | |||
@@ -252,7 +252,7 @@ | |||
252 | //usage:#define iprule_trivial_usage | 252 | //usage:#define iprule_trivial_usage |
253 | //usage: "[list] | add|del SELECTOR ACTION" | 253 | //usage: "[list] | add|del SELECTOR ACTION" |
254 | //usage:#define iprule_full_usage "\n\n" | 254 | //usage:#define iprule_full_usage "\n\n" |
255 | //usage: " SELECTOR := [from PREFIX] [to PREFIX] [tos TOS] [fwmark FWMARK]\n" | 255 | //usage: " SELECTOR := [from PREFIX] [to PREFIX] [tos TOS] [fwmark FWMARK[/MASK]]\n" |
256 | //usage: " [dev IFACE] [pref NUMBER]\n" | 256 | //usage: " [dev IFACE] [pref NUMBER]\n" |
257 | //usage: " ACTION := [table TABLE_ID] [nat ADDR]\n" | 257 | //usage: " ACTION := [table TABLE_ID] [nat ADDR]\n" |
258 | //usage: " [prohibit|reject|unreachable]\n" | 258 | //usage: " [prohibit|reject|unreachable]\n" |
diff --git a/networking/libiproute/iprule.c b/networking/libiproute/iprule.c index 0ce0dfeef..50acfe4e7 100644 --- a/networking/libiproute/iprule.c +++ b/networking/libiproute/iprule.c | |||
@@ -17,8 +17,10 @@ | |||
17 | #include <arpa/inet.h> | 17 | #include <arpa/inet.h> |
18 | 18 | ||
19 | /* from <linux/fib_rules.h>: */ | 19 | /* from <linux/fib_rules.h>: */ |
20 | #define FRA_SUPPRESS_IFGROUP 13 | 20 | #define FRA_FWMARK 10 |
21 | #define FRA_SUPPRESS_PREFIXLEN 14 | 21 | #define FRA_SUPPRESS_IFGROUP 13 |
22 | #define FRA_SUPPRESS_PREFIXLEN 14 | ||
23 | #define FRA_FWMASK 16 | ||
22 | 24 | ||
23 | #include "ip_common.h" /* #include "libbb.h" is inside */ | 25 | #include "ip_common.h" /* #include "libbb.h" is inside */ |
24 | #include "rt_names.h" | 26 | #include "rt_names.h" |
@@ -117,8 +119,18 @@ static int FAST_FUNC print_rule(const struct sockaddr_nl *who UNUSED_PARAM, | |||
117 | if (r->rtm_tos) { | 119 | if (r->rtm_tos) { |
118 | printf("tos %s ", rtnl_dsfield_n2a(r->rtm_tos)); | 120 | printf("tos %s ", rtnl_dsfield_n2a(r->rtm_tos)); |
119 | } | 121 | } |
120 | if (tb[RTA_PROTOINFO]) { | 122 | |
121 | printf("fwmark %#x ", *(uint32_t*)RTA_DATA(tb[RTA_PROTOINFO])); | 123 | if (tb[FRA_FWMARK] || tb[FRA_FWMASK]) { |
124 | uint32_t mark = 0, mask = 0; | ||
125 | |||
126 | if (tb[FRA_FWMARK]) | ||
127 | mark = *(uint32_t*)RTA_DATA(tb[FRA_FWMARK]); | ||
128 | if (tb[FRA_FWMASK] | ||
129 | && (mask = *(uint32_t*)RTA_DATA(tb[FRA_FWMASK])) != 0xFFFFFFFF | ||
130 | ) | ||
131 | printf("fwmark %#x/%#x ", mark, mask); | ||
132 | else | ||
133 | printf("fwmark %#x ", mark); | ||
122 | } | 134 | } |
123 | 135 | ||
124 | if (tb[RTA_IIF]) { | 136 | if (tb[RTA_IIF]) { |
@@ -257,10 +269,18 @@ static int iprule_modify(int cmd, char **argv) | |||
257 | invarg_1_to_2(*argv, "TOS"); | 269 | invarg_1_to_2(*argv, "TOS"); |
258 | req.r.rtm_tos = tos; | 270 | req.r.rtm_tos = tos; |
259 | } else if (key == ARG_fwmark) { | 271 | } else if (key == ARG_fwmark) { |
260 | uint32_t fwmark; | 272 | char *slash; |
273 | uint32_t fwmark, fwmask; | ||
261 | NEXT_ARG(); | 274 | NEXT_ARG(); |
275 | slash = strchr(*argv, '/'); | ||
276 | if (slash) | ||
277 | *slash = '\0'; | ||
262 | fwmark = get_u32(*argv, keyword_fwmark); | 278 | fwmark = get_u32(*argv, keyword_fwmark); |
263 | addattr32(&req.n, sizeof(req), RTA_PROTOINFO, fwmark); | 279 | addattr32(&req.n, sizeof(req), FRA_FWMARK, fwmark); |
280 | if (slash) { | ||
281 | fwmask = get_u32(slash + 1, "fwmask"); | ||
282 | addattr32(&req.n, sizeof(req), FRA_FWMASK, fwmask); | ||
283 | } | ||
264 | } else if (key == ARG_realms) { | 284 | } else if (key == ARG_realms) { |
265 | uint32_t realm; | 285 | uint32_t realm; |
266 | NEXT_ARG(); | 286 | NEXT_ARG(); |
diff --git a/networking/netstat.c b/networking/netstat.c index 936610f89..3ab7b0d21 100644 --- a/networking/netstat.c +++ b/networking/netstat.c | |||
@@ -272,10 +272,9 @@ static long extract_socket_inode(const char *lname) | |||
272 | return inode; | 272 | return inode; |
273 | } | 273 | } |
274 | 274 | ||
275 | static int FAST_FUNC add_to_prg_cache_if_socket(const char *fileName, | 275 | static int FAST_FUNC add_to_prg_cache_if_socket(struct recursive_state *state, |
276 | struct stat *statbuf UNUSED_PARAM, | 276 | const char *fileName, |
277 | void *pid_slash_progname, | 277 | struct stat *statbuf UNUSED_PARAM) |
278 | int depth UNUSED_PARAM) | ||
279 | { | 278 | { |
280 | char *linkname; | 279 | char *linkname; |
281 | long inode; | 280 | long inode; |
@@ -284,16 +283,17 @@ static int FAST_FUNC add_to_prg_cache_if_socket(const char *fileName, | |||
284 | if (linkname != NULL) { | 283 | if (linkname != NULL) { |
285 | inode = extract_socket_inode(linkname); | 284 | inode = extract_socket_inode(linkname); |
286 | free(linkname); | 285 | free(linkname); |
287 | if (inode >= 0) | 286 | if (inode >= 0) { |
288 | prg_cache_add(inode, (char *)pid_slash_progname); | 287 | char *pid_slash_progname = state->userData; |
288 | prg_cache_add(inode, pid_slash_progname); | ||
289 | } | ||
289 | } | 290 | } |
290 | return TRUE; | 291 | return TRUE; |
291 | } | 292 | } |
292 | 293 | ||
293 | static int FAST_FUNC dir_act(const char *fileName, | 294 | static int FAST_FUNC dir_act(struct recursive_state *state, |
294 | struct stat *statbuf UNUSED_PARAM, | 295 | const char *fileName, |
295 | void *userData UNUSED_PARAM, | 296 | struct stat *statbuf UNUSED_PARAM) |
296 | int depth) | ||
297 | { | 297 | { |
298 | const char *pid; | 298 | const char *pid; |
299 | char *pid_slash_progname; | 299 | char *pid_slash_progname; |
@@ -301,7 +301,7 @@ static int FAST_FUNC dir_act(const char *fileName, | |||
301 | char cmdline_buf[512]; | 301 | char cmdline_buf[512]; |
302 | int n, len; | 302 | int n, len; |
303 | 303 | ||
304 | if (depth == 0) /* "/proc" itself */ | 304 | if (state->depth == 0) /* "/proc" itself */ |
305 | return TRUE; /* continue looking one level below /proc */ | 305 | return TRUE; /* continue looking one level below /proc */ |
306 | 306 | ||
307 | pid = fileName + sizeof("/proc/")-1; /* point after "/proc/" */ | 307 | pid = fileName + sizeof("/proc/")-1; /* point after "/proc/" */ |
@@ -321,8 +321,8 @@ static int FAST_FUNC dir_act(const char *fileName, | |||
321 | ACTION_RECURSE | ACTION_QUIET, | 321 | ACTION_RECURSE | ACTION_QUIET, |
322 | add_to_prg_cache_if_socket, | 322 | add_to_prg_cache_if_socket, |
323 | NULL, | 323 | NULL, |
324 | (void *)pid_slash_progname, | 324 | (void *)pid_slash_progname |
325 | 0); | 325 | ); |
326 | free(pid_slash_progname); | 326 | free(pid_slash_progname); |
327 | 327 | ||
328 | if (!n) | 328 | if (!n) |
@@ -337,7 +337,7 @@ static void prg_cache_load(void) | |||
337 | 337 | ||
338 | prg_cache_loaded = 1; | 338 | prg_cache_loaded = 1; |
339 | load_ok = recursive_action("/proc", ACTION_RECURSE | ACTION_QUIET, | 339 | load_ok = recursive_action("/proc", ACTION_RECURSE | ACTION_QUIET, |
340 | NULL, dir_act, NULL, 0); | 340 | NULL, dir_act, NULL); |
341 | if (load_ok) | 341 | if (load_ok) |
342 | return; | 342 | return; |
343 | 343 | ||
diff --git a/networking/nslookup.c b/networking/nslookup.c index c43e60558..759de5c83 100644 --- a/networking/nslookup.c +++ b/networking/nslookup.c | |||
@@ -703,12 +703,13 @@ static void parse_resolvconf(void) | |||
703 | 703 | ||
704 | while (fgets(line, sizeof(line), resolv)) { | 704 | while (fgets(line, sizeof(line), resolv)) { |
705 | char *p, *arg; | 705 | char *p, *arg; |
706 | char *tokstate; | ||
706 | 707 | ||
707 | p = strtok(line, " \t\n"); | 708 | p = strtok_r(line, " \t\n", &tokstate); |
708 | if (!p) | 709 | if (!p) |
709 | continue; | 710 | continue; |
710 | dbg("resolv_key:'%s'\n", p); | 711 | dbg("resolv_key:'%s'\n", p); |
711 | arg = strtok(NULL, "\n"); | 712 | arg = strtok_r(NULL, "\n", &tokstate); |
712 | dbg("resolv_arg:'%s'\n", arg); | 713 | dbg("resolv_arg:'%s'\n", arg); |
713 | if (!arg) | 714 | if (!arg) |
714 | continue; | 715 | continue; |
diff --git a/networking/ntpd.c b/networking/ntpd.c index d721fe80c..44e711232 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c | |||
@@ -2025,6 +2025,15 @@ recv_and_process_peer_pkt(peer_t *p) | |||
2025 | 2025 | ||
2026 | offset = 0; | 2026 | offset = 0; |
2027 | 2027 | ||
2028 | /* The below can happen as follows: | ||
2029 | * = we receive two peer rsponses at once. | ||
2030 | * = recv_and_process_peer_pkt(PEER1) -> update_local_clock() | ||
2031 | * -> step_time() and it closes all other fds, sets all ->fd to -1. | ||
2032 | * = recv_and_process_peer_pkt(PEER2) sees PEER2->fd == -1 | ||
2033 | */ | ||
2034 | if (p->p_fd < 0) | ||
2035 | return; | ||
2036 | |||
2028 | /* We can recvfrom here and check from.IP, but some multihomed | 2037 | /* We can recvfrom here and check from.IP, but some multihomed |
2029 | * ntp servers reply from their *other IP*. | 2038 | * ntp servers reply from their *other IP*. |
2030 | * TODO: maybe we should check at least what we can: from.port == 123? | 2039 | * TODO: maybe we should check at least what we can: from.port == 123? |
diff --git a/networking/ping.c b/networking/ping.c index 47b6ab1b2..5f7e5b9b5 100644 --- a/networking/ping.c +++ b/networking/ping.c | |||
@@ -217,7 +217,7 @@ static void ping4(len_and_sockaddr *lsa) | |||
217 | /*memset(pkt, 0, sizeof(G.packet)); already is */ | 217 | /*memset(pkt, 0, sizeof(G.packet)); already is */ |
218 | pkt->icmp_type = ICMP_ECHO; | 218 | pkt->icmp_type = ICMP_ECHO; |
219 | pkt->icmp_id = G.myid; | 219 | pkt->icmp_id = G.myid; |
220 | pkt->icmp_cksum = inet_cksum((uint16_t *) pkt, sizeof(G.packet)); | 220 | pkt->icmp_cksum = inet_cksum(pkt, sizeof(G.packet)); |
221 | 221 | ||
222 | xsendto(pingsock, G.packet, DEFDATALEN + ICMP_MINLEN, &lsa->u.sa, lsa->len); | 222 | xsendto(pingsock, G.packet, DEFDATALEN + ICMP_MINLEN, &lsa->u.sa, lsa->len); |
223 | 223 | ||
@@ -529,7 +529,7 @@ static void sendping4(int junk UNUSED_PARAM) | |||
529 | /* No hton: we'll read it back on the same machine */ | 529 | /* No hton: we'll read it back on the same machine */ |
530 | *(uint32_t*)&pkt->icmp_dun = G.cur_us = monotonic_us(); | 530 | *(uint32_t*)&pkt->icmp_dun = G.cur_us = monotonic_us(); |
531 | 531 | ||
532 | pkt->icmp_cksum = inet_cksum((uint16_t *) pkt, datalen + ICMP_MINLEN); | 532 | pkt->icmp_cksum = inet_cksum(pkt, datalen + ICMP_MINLEN); |
533 | 533 | ||
534 | sendping_tail(sendping4, ICMP_MINLEN); | 534 | sendping_tail(sendping4, ICMP_MINLEN); |
535 | } | 535 | } |
diff --git a/networking/traceroute.c b/networking/traceroute.c index 5068f654b..1c4dc3e4a 100644 --- a/networking/traceroute.c +++ b/networking/traceroute.c | |||
@@ -468,7 +468,7 @@ send_probe(int seq, int ttl) | |||
468 | /* Always calculate checksum for icmp packets */ | 468 | /* Always calculate checksum for icmp packets */ |
469 | outicmp->icmp_cksum = 0; | 469 | outicmp->icmp_cksum = 0; |
470 | outicmp->icmp_cksum = inet_cksum( | 470 | outicmp->icmp_cksum = inet_cksum( |
471 | (uint16_t *)outicmp, | 471 | outicmp, |
472 | ((char*)outip + packlen) - (char*)outicmp | 472 | ((char*)outip + packlen) - (char*)outicmp |
473 | ); | 473 | ); |
474 | if (outicmp->icmp_cksum == 0) | 474 | if (outicmp->icmp_cksum == 0) |
diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c index 20d843bab..4bc719001 100644 --- a/networking/udhcp/common.c +++ b/networking/udhcp/common.c | |||
@@ -526,7 +526,7 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg, | |||
526 | 526 | ||
527 | /* Cheat, the only *const* str possible is "" */ | 527 | /* Cheat, the only *const* str possible is "" */ |
528 | str = (char *) const_str; | 528 | str = (char *) const_str; |
529 | opt = strtok(str, " \t=:"); | 529 | opt = strtok_r(str, " \t=:", &str); |
530 | if (!opt) | 530 | if (!opt) |
531 | return 0; | 531 | return 0; |
532 | 532 | ||
@@ -550,10 +550,10 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg, | |||
550 | char *val; | 550 | char *val; |
551 | 551 | ||
552 | if (optflag->flags == OPTION_BIN) { | 552 | if (optflag->flags == OPTION_BIN) { |
553 | val = strtok(NULL, ""); /* do not split "'q w e'" */ | 553 | val = strtok_r(NULL, "", &str); /* do not split "'q w e'" */ |
554 | if (val) trim(val); | 554 | if (val) trim(val); |
555 | } else | 555 | } else |
556 | val = strtok(NULL, ", \t"); | 556 | val = strtok_r(NULL, ", \t", &str); |
557 | if (!val) | 557 | if (!val) |
558 | break; | 558 | break; |
559 | 559 | ||
@@ -567,7 +567,7 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg, | |||
567 | break; | 567 | break; |
568 | case OPTION_IP_PAIR: | 568 | case OPTION_IP_PAIR: |
569 | retval = udhcp_str2nip(val, buffer); | 569 | retval = udhcp_str2nip(val, buffer); |
570 | val = strtok(NULL, ", \t/-"); | 570 | val = strtok_r(NULL, ", \t/-", &str); |
571 | if (!val) | 571 | if (!val) |
572 | retval = 0; | 572 | retval = 0; |
573 | if (retval) | 573 | if (retval) |
@@ -631,7 +631,7 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg, | |||
631 | *slash = '\0'; | 631 | *slash = '\0'; |
632 | retval = udhcp_str2nip(val, buffer + 1); | 632 | retval = udhcp_str2nip(val, buffer + 1); |
633 | buffer[0] = mask = bb_strtou(slash + 1, NULL, 10); | 633 | buffer[0] = mask = bb_strtou(slash + 1, NULL, 10); |
634 | val = strtok(NULL, ", \t/-"); | 634 | val = strtok_r(NULL, ", \t/-", &str); |
635 | if (!val || mask > 32 || errno) | 635 | if (!val || mask > 32 || errno) |
636 | retval = 0; | 636 | retval = 0; |
637 | if (retval) { | 637 | if (retval) { |
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h index 81c1dcbdc..3cbd2d3c8 100644 --- a/networking/udhcp/common.h +++ b/networking/udhcp/common.h | |||
@@ -46,7 +46,7 @@ struct dhcp_packet { | |||
46 | uint8_t file[128]; /* boot file name (ASCIZ) */ | 46 | uint8_t file[128]; /* boot file name (ASCIZ) */ |
47 | uint32_t cookie; /* fixed first four option bytes (99,130,83,99 dec) */ | 47 | uint32_t cookie; /* fixed first four option bytes (99,130,83,99 dec) */ |
48 | uint8_t options[DHCP_OPTIONS_BUFSIZE + CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS]; | 48 | uint8_t options[DHCP_OPTIONS_BUFSIZE + CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS]; |
49 | } PACKED; | 49 | }; |
50 | #define DHCP_PKT_SNAME_LEN 64 | 50 | #define DHCP_PKT_SNAME_LEN 64 |
51 | #define DHCP_PKT_FILE_LEN 128 | 51 | #define DHCP_PKT_FILE_LEN 128 |
52 | #define DHCP_PKT_SNAME_LEN_STR "64" | 52 | #define DHCP_PKT_SNAME_LEN_STR "64" |
@@ -56,12 +56,12 @@ struct ip_udp_dhcp_packet { | |||
56 | struct iphdr ip; | 56 | struct iphdr ip; |
57 | struct udphdr udp; | 57 | struct udphdr udp; |
58 | struct dhcp_packet data; | 58 | struct dhcp_packet data; |
59 | } PACKED; | 59 | }; |
60 | 60 | ||
61 | struct udp_dhcp_packet { | 61 | struct udp_dhcp_packet { |
62 | struct udphdr udp; | 62 | struct udphdr udp; |
63 | struct dhcp_packet data; | 63 | struct dhcp_packet data; |
64 | } PACKED; | 64 | }; |
65 | 65 | ||
66 | enum { | 66 | enum { |
67 | IP_UDP_DHCP_SIZE = sizeof(struct ip_udp_dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS, | 67 | IP_UDP_DHCP_SIZE = sizeof(struct ip_udp_dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS, |
diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c index fc2d672b7..ac8af91d3 100644 --- a/networking/udhcp/d6_dhcpc.c +++ b/networking/udhcp/d6_dhcpc.c | |||
@@ -947,7 +947,7 @@ static NOINLINE int d6_recv_raw_packet(struct in6_addr *peer_ipv6, struct d6_pac | |||
947 | // packet.ip.tot_len = packet.udp.len; /* yes, this is needed */ | 947 | // packet.ip.tot_len = packet.udp.len; /* yes, this is needed */ |
948 | // check = packet.udp.check; | 948 | // check = packet.udp.check; |
949 | // packet.udp.check = 0; | 949 | // packet.udp.check = 0; |
950 | // if (check && check != inet_cksum((uint16_t *)&packet, bytes)) { | 950 | // if (check && check != inet_cksum(&packet, bytes)) { |
951 | // log1("packet with bad UDP checksum received, ignoring"); | 951 | // log1("packet with bad UDP checksum received, ignoring"); |
952 | // return -2; | 952 | // return -2; |
953 | // } | 953 | // } |
diff --git a/networking/udhcp/d6_packet.c b/networking/udhcp/d6_packet.c index 446497e15..167a813e3 100644 --- a/networking/udhcp/d6_packet.c +++ b/networking/udhcp/d6_packet.c | |||
@@ -103,7 +103,7 @@ int FAST_FUNC d6_send_raw_packet( | |||
103 | */ | 103 | */ |
104 | packet.ip6.ip6_hlim = IPPROTO_UDP; | 104 | packet.ip6.ip6_hlim = IPPROTO_UDP; |
105 | packet.udp.check = inet_cksum( | 105 | packet.udp.check = inet_cksum( |
106 | (uint16_t *)&packet + 2, | 106 | (uint8_t *)&packet + 4, |
107 | offsetof(struct ip6_udp_d6_packet, data) - 4 + d6_pkt_size | 107 | offsetof(struct ip6_udp_d6_packet, data) - 4 + d6_pkt_size |
108 | ); | 108 | ); |
109 | /* fix 'hop limit' and 'next header' after UDP checksumming */ | 109 | /* fix 'hop limit' and 'next header' after UDP checksumming */ |
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index e13eb3f9f..66aa38c20 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c | |||
@@ -935,7 +935,7 @@ static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) | |||
935 | /* verify IP checksum */ | 935 | /* verify IP checksum */ |
936 | check = packet.ip.check; | 936 | check = packet.ip.check; |
937 | packet.ip.check = 0; | 937 | packet.ip.check = 0; |
938 | if (check != inet_cksum((uint16_t *)&packet.ip, sizeof(packet.ip))) { | 938 | if (check != inet_cksum(&packet.ip, sizeof(packet.ip))) { |
939 | log1s("bad IP header checksum, ignoring"); | 939 | log1s("bad IP header checksum, ignoring"); |
940 | return -2; | 940 | return -2; |
941 | } | 941 | } |
@@ -960,7 +960,7 @@ static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) | |||
960 | packet.ip.tot_len = packet.udp.len; /* yes, this is needed */ | 960 | packet.ip.tot_len = packet.udp.len; /* yes, this is needed */ |
961 | check = packet.udp.check; | 961 | check = packet.udp.check; |
962 | packet.udp.check = 0; | 962 | packet.udp.check = 0; |
963 | if (check && check != inet_cksum((uint16_t *)&packet, bytes)) { | 963 | if (check && check != inet_cksum(&packet, bytes)) { |
964 | log1s("packet with bad UDP checksum received, ignoring"); | 964 | log1s("packet with bad UDP checksum received, ignoring"); |
965 | return -2; | 965 | return -2; |
966 | } | 966 | } |
diff --git a/networking/udhcp/packet.c b/networking/udhcp/packet.c index 6d4375237..51374646d 100644 --- a/networking/udhcp/packet.c +++ b/networking/udhcp/packet.c | |||
@@ -164,14 +164,14 @@ int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt, | |||
164 | packet.udp.len = htons(UDP_DHCP_SIZE - padding); | 164 | packet.udp.len = htons(UDP_DHCP_SIZE - padding); |
165 | /* for UDP checksumming, ip.len is set to UDP packet len */ | 165 | /* for UDP checksumming, ip.len is set to UDP packet len */ |
166 | packet.ip.tot_len = packet.udp.len; | 166 | packet.ip.tot_len = packet.udp.len; |
167 | packet.udp.check = inet_cksum((uint16_t *)&packet, | 167 | packet.udp.check = inet_cksum(&packet, |
168 | IP_UDP_DHCP_SIZE - padding); | 168 | IP_UDP_DHCP_SIZE - padding); |
169 | /* but for sending, it is set to IP packet len */ | 169 | /* but for sending, it is set to IP packet len */ |
170 | packet.ip.tot_len = htons(IP_UDP_DHCP_SIZE - padding); | 170 | packet.ip.tot_len = htons(IP_UDP_DHCP_SIZE - padding); |
171 | packet.ip.ihl = sizeof(packet.ip) >> 2; | 171 | packet.ip.ihl = sizeof(packet.ip) >> 2; |
172 | packet.ip.version = IPVERSION; | 172 | packet.ip.version = IPVERSION; |
173 | packet.ip.ttl = IPDEFTTL; | 173 | packet.ip.ttl = IPDEFTTL; |
174 | packet.ip.check = inet_cksum((uint16_t *)&packet.ip, sizeof(packet.ip)); | 174 | packet.ip.check = inet_cksum(&packet.ip, sizeof(packet.ip)); |
175 | 175 | ||
176 | udhcp_dump_packet(dhcp_pkt); | 176 | udhcp_dump_packet(dhcp_pkt); |
177 | result = sendto(fd, &packet, IP_UDP_DHCP_SIZE - padding, /*flags:*/ 0, | 177 | result = sendto(fd, &packet, IP_UDP_DHCP_SIZE - padding, /*flags:*/ 0, |
diff --git a/procps/mpstat.c b/procps/mpstat.c index 3e07edc5c..883c4d52d 100644 --- a/procps/mpstat.c +++ b/procps/mpstat.c | |||
@@ -923,7 +923,7 @@ int mpstat_main(int argc UNUSED_PARAM, char **argv) | |||
923 | char *t; | 923 | char *t; |
924 | G.p_option = 1; | 924 | G.p_option = 1; |
925 | 925 | ||
926 | for (t = strtok(opt_set_cpu, ","); t; t = strtok(NULL, ",")) { | 926 | for (t = strtok_r(opt_set_cpu, ",", &opt_set_cpu); t; t = strtok_r(NULL, ",", &opt_set_cpu)) { |
927 | if (strcmp(t, "ALL") == 0) { | 927 | if (strcmp(t, "ALL") == 0) { |
928 | /* Select every CPU */ | 928 | /* Select every CPU */ |
929 | memset(G.cpu_bitmap, 0xff, G.cpu_bitmap_len); | 929 | memset(G.cpu_bitmap, 0xff, G.cpu_bitmap_len); |
diff --git a/selinux/chcon.c b/selinux/chcon.c index afe7f713d..9b13679b8 100644 --- a/selinux/chcon.c +++ b/selinux/chcon.c | |||
@@ -62,11 +62,9 @@ static char *type = NULL; | |||
62 | static char *range = NULL; | 62 | static char *range = NULL; |
63 | static char *specified_context = NULL; | 63 | static char *specified_context = NULL; |
64 | 64 | ||
65 | static int FAST_FUNC change_filedir_context( | 65 | static int FAST_FUNC change_filedir_context(struct recursive_state *state UNUSED_PARAM, |
66 | const char *fname, | 66 | const char *fname, |
67 | struct stat *stbuf UNUSED_PARAM, | 67 | struct stat *stbuf UNUSED_PARAM) |
68 | void *userData UNUSED_PARAM, | ||
69 | int depth UNUSED_PARAM) | ||
70 | { | 68 | { |
71 | context_t context = NULL; | 69 | context_t context = NULL; |
72 | security_context_t file_context = NULL; | 70 | security_context_t file_context = NULL; |
@@ -207,7 +205,7 @@ int chcon_main(int argc UNUSED_PARAM, char **argv) | |||
207 | ((option_mask32 & OPT_RECURSIVE) ? ACTION_RECURSE : 0), | 205 | ((option_mask32 & OPT_RECURSIVE) ? ACTION_RECURSE : 0), |
208 | change_filedir_context, | 206 | change_filedir_context, |
209 | change_filedir_context, | 207 | change_filedir_context, |
210 | NULL, 0) != TRUE) | 208 | NULL) != TRUE) |
211 | errors = 1; | 209 | errors = 1; |
212 | } | 210 | } |
213 | return errors; | 211 | return errors; |
diff --git a/selinux/setfiles.c b/selinux/setfiles.c index 55bfb4d02..a617b95d8 100644 --- a/selinux/setfiles.c +++ b/selinux/setfiles.c | |||
@@ -463,11 +463,9 @@ static int restore(const char *file) | |||
463 | * This function is called by recursive_action on each file during | 463 | * This function is called by recursive_action on each file during |
464 | * the directory traversal. | 464 | * the directory traversal. |
465 | */ | 465 | */ |
466 | static int FAST_FUNC apply_spec( | 466 | static int FAST_FUNC apply_spec(struct recursive_state *state UNUSED_PARAM, |
467 | const char *file, | 467 | const char *file, |
468 | struct stat *sb, | 468 | struct stat *sb) |
469 | void *userData UNUSED_PARAM, | ||
470 | int depth UNUSED_PARAM) | ||
471 | { | 469 | { |
472 | if (!follow_mounts) { | 470 | if (!follow_mounts) { |
473 | /* setfiles does not process across different mount points */ | 471 | /* setfiles does not process across different mount points */ |
@@ -535,7 +533,7 @@ static int process_one(char *name) | |||
535 | ACTION_RECURSE, | 533 | ACTION_RECURSE, |
536 | apply_spec, | 534 | apply_spec, |
537 | apply_spec, | 535 | apply_spec, |
538 | NULL, 0) != TRUE | 536 | NULL) != TRUE |
539 | ) { | 537 | ) { |
540 | bb_error_msg("error while labeling %s", name); | 538 | bb_error_msg("error while labeling %s", name); |
541 | goto err; | 539 | goto err; |
diff --git a/shell/ash.c b/shell/ash.c index 1f57c2d7e..b8f75af05 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -240,17 +240,17 @@ | |||
240 | #define IF_BASH_SUBSTR IF_ASH_BASH_COMPAT | 240 | #define IF_BASH_SUBSTR IF_ASH_BASH_COMPAT |
241 | /* BASH_TEST2: [[ EXPR ]] | 241 | /* BASH_TEST2: [[ EXPR ]] |
242 | * Status of [[ support: | 242 | * Status of [[ support: |
243 | * We replace && and || with -a and -o | 243 | * && and || work as they should |
244 | * = is glob match operator, not equality operator: STR = GLOB | ||
245 | * == same as = | ||
246 | * =~ is regex match operator: STR =~ REGEX | ||
244 | * TODO: | 247 | * TODO: |
245 | * singleword+noglob expansion: | 248 | * singleword+noglob expansion: |
246 | * v='a b'; [[ $v = 'a b' ]]; echo 0:$? | 249 | * v='a b'; [[ $v = 'a b' ]]; echo 0:$? |
247 | * [[ /bin/n* ]]; echo 0:$? | 250 | * [[ /bin/n* ]]; echo 0:$? |
248 | * -a/-o are not AND/OR ops! (they are just strings) | ||
249 | * quoting needs to be considered (-f is an operator, "-f" and ""-f are not; etc) | 251 | * quoting needs to be considered (-f is an operator, "-f" and ""-f are not; etc) |
250 | * = is glob match operator, not equality operator: STR = GLOB | 252 | * ( ) < > should not have special meaning (IOW: should not require quoting) |
251 | * (in GLOB, quoting is significant on char-by-char basis: a*cd"*") | 253 | * in word = GLOB, quoting should be significant on char-by-char basis: a*cd"*" |
252 | * == same as = | ||
253 | * add =~ regex match operator: STR =~ REGEX | ||
254 | */ | 254 | */ |
255 | #define BASH_TEST2 (ENABLE_ASH_BASH_COMPAT * ENABLE_ASH_TEST) | 255 | #define BASH_TEST2 (ENABLE_ASH_BASH_COMPAT * ENABLE_ASH_TEST) |
256 | #define BASH_SOURCE ENABLE_ASH_BASH_COMPAT | 256 | #define BASH_SOURCE ENABLE_ASH_BASH_COMPAT |
@@ -3173,7 +3173,7 @@ updatepwd(const char *dir) | |||
3173 | lim++; | 3173 | lim++; |
3174 | } | 3174 | } |
3175 | } | 3175 | } |
3176 | p = strtok(cdcomppath, "/"); | 3176 | p = strtok_r(cdcomppath, "/", &cdcomppath); |
3177 | while (p) { | 3177 | while (p) { |
3178 | switch (*p) { | 3178 | switch (*p) { |
3179 | case '.': | 3179 | case '.': |
@@ -3192,7 +3192,7 @@ updatepwd(const char *dir) | |||
3192 | new = stack_putstr(p, new); | 3192 | new = stack_putstr(p, new); |
3193 | USTPUTC('/', new); | 3193 | USTPUTC('/', new); |
3194 | } | 3194 | } |
3195 | p = strtok(NULL, "/"); | 3195 | p = strtok_r(NULL, "/", &cdcomppath); |
3196 | } | 3196 | } |
3197 | if (new > lim) | 3197 | if (new > lim) |
3198 | STUNPUTC(new); | 3198 | STUNPUTC(new); |
@@ -4780,61 +4780,54 @@ waitpid_child(int *status, int wait_flags) | |||
4780 | return pid; | 4780 | return pid; |
4781 | } | 4781 | } |
4782 | #define waitpid(p, s, f) waitpid_child(s, f) | 4782 | #define waitpid(p, s, f) waitpid_child(s, f) |
4783 | #define wait_block_or_sig(s) waitpid_child(s, 0) | 4783 | #endif |
4784 | 4784 | ||
4785 | #else | 4785 | #define DOWAIT_NONBLOCK 0 |
4786 | #define DOWAIT_BLOCK 1 | ||
4787 | #define DOWAIT_BLOCK_OR_SIG 2 | ||
4788 | #if BASH_WAIT_N | ||
4789 | # define DOWAIT_JOBSTATUS 0x10 /* OR this to get job's exitstatus instead of pid */ | ||
4790 | #endif | ||
4786 | 4791 | ||
4787 | static int | 4792 | static int |
4788 | wait_block_or_sig(int *status) | 4793 | waitproc(int block, int *status) |
4789 | { | 4794 | { |
4790 | int pid; | 4795 | #if !ENABLE_PLATFORM_MINGW32 |
4796 | sigset_t oldmask; | ||
4797 | int flags = block == DOWAIT_BLOCK ? 0 : WNOHANG; | ||
4798 | int err; | ||
4791 | 4799 | ||
4792 | do { | 4800 | #if JOBS |
4793 | sigset_t mask; | 4801 | if (doing_jobctl) |
4802 | flags |= WUNTRACED; | ||
4803 | #endif | ||
4794 | 4804 | ||
4795 | /* Poll all children for changes in their state */ | 4805 | do { |
4796 | got_sigchld = 0; | 4806 | got_sigchld = 0; |
4797 | /* if job control is active, accept stopped processes too */ | 4807 | do |
4798 | pid = waitpid(-1, status, doing_jobctl ? (WNOHANG|WUNTRACED) : WNOHANG); | 4808 | err = waitpid(-1, status, flags); |
4799 | if (pid != 0) | 4809 | while (err < 0 && errno == EINTR); |
4800 | break; /* Error (e.g. EINTR, ECHILD) or pid */ | ||
4801 | 4810 | ||
4802 | /* Children exist, but none are ready. Sleep until interesting signal */ | 4811 | if (err || (err = -!block)) |
4803 | #if 1 | 4812 | break; |
4804 | sigfillset(&mask); | 4813 | |
4805 | sigprocmask2(SIG_SETMASK, &mask); /* mask is updated */ | 4814 | sigfillset(&oldmask); |
4806 | while (!got_sigchld && !pending_sig) { | 4815 | sigprocmask2(SIG_SETMASK, &oldmask); /* mask is updated */ |
4807 | sigsuspend(&mask); | ||
4808 | /* ^^^ add "sigdelset(&mask, SIGCHLD);" before sigsuspend | ||
4809 | * to make sure SIGCHLD is not masked off? | ||
4810 | * It was reported that this: | ||
4811 | * fn() { : | return; } | ||
4812 | * shopt -s lastpipe | ||
4813 | * fn | ||
4814 | * exec ash SCRIPT | ||
4815 | * under bash 4.4.23 runs SCRIPT with SIGCHLD masked, | ||
4816 | * making "wait" commands in SCRIPT block forever. | ||
4817 | */ | ||
4818 | } | ||
4819 | sigprocmask(SIG_SETMASK, &mask, NULL); | ||
4820 | #else /* unsafe: a signal can set pending_sig after check, but before pause() */ | ||
4821 | while (!got_sigchld && !pending_sig) | 4816 | while (!got_sigchld && !pending_sig) |
4822 | pause(); | 4817 | sigsuspend(&oldmask); |
4823 | #endif | 4818 | sigprocmask(SIG_SETMASK, &oldmask, NULL); |
4819 | //simpler, but unsafe: a signal can set pending_sig after check, but before pause(): | ||
4820 | //while (!got_sigchld && !pending_sig) | ||
4821 | // pause(); | ||
4824 | 4822 | ||
4825 | /* If it was SIGCHLD, poll children again */ | ||
4826 | } while (got_sigchld); | 4823 | } while (got_sigchld); |
4827 | 4824 | ||
4828 | return pid; | 4825 | return err; |
4829 | } | 4826 | #else |
4830 | #endif | 4827 | int flags = block == DOWAIT_BLOCK ? 0 : WNOHANG; |
4831 | 4828 | return waitpid(-1, status, flags); | |
4832 | #define DOWAIT_NONBLOCK 0 | ||
4833 | #define DOWAIT_BLOCK 1 | ||
4834 | #define DOWAIT_BLOCK_OR_SIG 2 | ||
4835 | #if BASH_WAIT_N | ||
4836 | # define DOWAIT_JOBSTATUS 0x10 /* OR this to get job's exitstatus instead of pid */ | ||
4837 | #endif | 4829 | #endif |
4830 | } | ||
4838 | 4831 | ||
4839 | static int | 4832 | static int |
4840 | waitone(int block, struct job *job) | 4833 | waitone(int block, struct job *job) |
@@ -4842,7 +4835,7 @@ waitone(int block, struct job *job) | |||
4842 | int pid; | 4835 | int pid; |
4843 | int status; | 4836 | int status; |
4844 | struct job *jp; | 4837 | struct job *jp; |
4845 | struct job *thisjob; | 4838 | struct job *thisjob = NULL; |
4846 | #if BASH_WAIT_N | 4839 | #if BASH_WAIT_N |
4847 | bool want_jobexitstatus = (block & DOWAIT_JOBSTATUS); | 4840 | bool want_jobexitstatus = (block & DOWAIT_JOBSTATUS); |
4848 | block = (block & ~DOWAIT_JOBSTATUS); | 4841 | block = (block & ~DOWAIT_JOBSTATUS); |
@@ -4869,21 +4862,8 @@ waitone(int block, struct job *job) | |||
4869 | * SIG_DFL handler does not wake sigsuspend(). | 4862 | * SIG_DFL handler does not wake sigsuspend(). |
4870 | */ | 4863 | */ |
4871 | INT_OFF; | 4864 | INT_OFF; |
4872 | if (block == DOWAIT_BLOCK_OR_SIG) { | 4865 | pid = waitproc(block, &status); |
4873 | pid = wait_block_or_sig(&status); | 4866 | TRACE(("wait returns pid %d, status=%d\n", pid, status)); |
4874 | } else { | ||
4875 | int wait_flags = 0; | ||
4876 | if (block == DOWAIT_NONBLOCK) | ||
4877 | wait_flags = WNOHANG; | ||
4878 | /* if job control is active, accept stopped processes too */ | ||
4879 | if (doing_jobctl) | ||
4880 | wait_flags |= WUNTRACED; | ||
4881 | /* NB: _not_ safe_waitpid, we need to detect EINTR */ | ||
4882 | pid = waitpid(-1, &status, wait_flags); | ||
4883 | } | ||
4884 | TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", | ||
4885 | pid, status, errno, strerror(errno))); | ||
4886 | thisjob = NULL; | ||
4887 | if (pid <= 0) | 4867 | if (pid <= 0) |
4888 | goto out; | 4868 | goto out; |
4889 | 4869 | ||
@@ -4971,21 +4951,35 @@ static int | |||
4971 | dowait(int block, struct job *jp) | 4951 | dowait(int block, struct job *jp) |
4972 | { | 4952 | { |
4973 | #if !ENABLE_PLATFORM_MINGW32 | 4953 | #if !ENABLE_PLATFORM_MINGW32 |
4974 | int pid = block == DOWAIT_NONBLOCK ? got_sigchld : 1; | 4954 | smallint gotchld = *(volatile smallint *)&got_sigchld; |
4955 | int rpid; | ||
4956 | int pid; | ||
4957 | |||
4958 | if (jp && jp->state != JOBRUNNING) | ||
4959 | block = DOWAIT_NONBLOCK; | ||
4960 | |||
4961 | if (block == DOWAIT_NONBLOCK && !gotchld) | ||
4962 | return 1; | ||
4963 | |||
4964 | rpid = 1; | ||
4975 | 4965 | ||
4976 | while (jp ? jp->state == JOBRUNNING : pid > 0) { | 4966 | do { |
4977 | if (!jp) | ||
4978 | got_sigchld = 0; | ||
4979 | pid = waitone(block, jp); | 4967 | pid = waitone(block, jp); |
4980 | } | 4968 | rpid &= !!pid; |
4969 | |||
4970 | if (!pid || (jp && jp->state != JOBRUNNING)) | ||
4971 | block = DOWAIT_NONBLOCK; | ||
4972 | } while (pid >= 0); | ||
4973 | |||
4974 | return rpid; | ||
4981 | #else | 4975 | #else |
4982 | int pid = 1; | 4976 | int pid = 1; |
4983 | 4977 | ||
4984 | while (jp ? jp->state == JOBRUNNING : pid > 0) | 4978 | while (jp ? jp->state == JOBRUNNING : pid > 0) |
4985 | pid = waitone(block, jp); | 4979 | pid = waitone(block, jp); |
4986 | #endif | ||
4987 | 4980 | ||
4988 | return pid; | 4981 | return pid; |
4982 | #endif | ||
4989 | } | 4983 | } |
4990 | 4984 | ||
4991 | #if JOBS | 4985 | #if JOBS |
@@ -5232,7 +5226,7 @@ waitcmd(int argc UNUSED_PARAM, char **argv) | |||
5232 | job = getjob(*argv, 0); | 5226 | job = getjob(*argv, 0); |
5233 | } | 5227 | } |
5234 | /* loop until process terminated or stopped */ | 5228 | /* loop until process terminated or stopped */ |
5235 | dowait(DOWAIT_BLOCK_OR_SIG, NULL); | 5229 | dowait(DOWAIT_BLOCK_OR_SIG, job); |
5236 | if (pending_sig) | 5230 | if (pending_sig) |
5237 | goto sigout; | 5231 | goto sigout; |
5238 | job->waited = 1; | 5232 | job->waited = 1; |
@@ -12622,7 +12616,8 @@ simplecmd(void) | |||
12622 | tokpushback = 1; | 12616 | tokpushback = 1; |
12623 | goto out; | 12617 | goto out; |
12624 | } | 12618 | } |
12625 | wordtext = (char *) (t == TAND ? "-a" : "-o"); | 12619 | /* pass "&&" or "||" to [[ ]] as literal args */ |
12620 | wordtext = (char *) (t == TAND ? "&&" : "||"); | ||
12626 | #endif | 12621 | #endif |
12627 | case TWORD: | 12622 | case TWORD: |
12628 | n = stzalloc(sizeof(struct narg)); | 12623 | n = stzalloc(sizeof(struct narg)); |
@@ -13600,7 +13595,7 @@ parsebackq: { | |||
13600 | goto done; | 13595 | goto done; |
13601 | 13596 | ||
13602 | case '\\': | 13597 | case '\\': |
13603 | pc = pgetc(); /* or pgetc_eatbnl()? why (example)? */ | 13598 | pc = pgetc(); /* not pgetc_eatbnl! */ |
13604 | if (pc != '\\' && pc != '`' && pc != '$' | 13599 | if (pc != '\\' && pc != '`' && pc != '$' |
13605 | && (!synstack->dblquote || pc != '"') | 13600 | && (!synstack->dblquote || pc != '"') |
13606 | ) { | 13601 | ) { |
diff --git a/shell/ash_test/ash-misc/wait7.right b/shell/ash_test/ash-misc/wait7.right new file mode 100644 index 000000000..4b6445841 --- /dev/null +++ b/shell/ash_test/ash-misc/wait7.right | |||
@@ -0,0 +1,2 @@ | |||
1 | Background1 | ||
2 | Ok:0 | ||
diff --git a/shell/ash_test/ash-misc/wait7.tests b/shell/ash_test/ash-misc/wait7.tests new file mode 100755 index 000000000..a54a778e5 --- /dev/null +++ b/shell/ash_test/ash-misc/wait7.tests | |||
@@ -0,0 +1,7 @@ | |||
1 | sleep 1 && echo "Background1" & | ||
2 | pid=$! | ||
3 | sleep 3 && echo "Background2: BUG!" & | ||
4 | # Shouldn't wait for 2nd bkgd: | ||
5 | wait $pid | ||
6 | kill $! | ||
7 | echo Ok:$? | ||
diff --git a/shell/ash_test/ash-signals/usage.right b/shell/ash_test/ash-signals/usage.right new file mode 100644 index 000000000..c0dbd6c3c --- /dev/null +++ b/shell/ash_test/ash-signals/usage.right | |||
@@ -0,0 +1,14 @@ | |||
1 | ___ | ||
2 | ___ | ||
3 | ___ | ||
4 | trap -- 'a' EXIT | ||
5 | trap -- 'a' INT | ||
6 | trap -- 'a' USR1 | ||
7 | trap -- 'a' USR2 | ||
8 | ___ | ||
9 | ___ | ||
10 | trap -- 'a' USR1 | ||
11 | trap -- 'a' USR2 | ||
12 | ___ | ||
13 | ___ | ||
14 | trap -- 'a' USR2 | ||
diff --git a/shell/ash_test/ash-signals/usage.tests b/shell/ash_test/ash-signals/usage.tests new file mode 100755 index 000000000..d29c6e74a --- /dev/null +++ b/shell/ash_test/ash-signals/usage.tests | |||
@@ -0,0 +1,23 @@ | |||
1 | # no output -- default state | ||
2 | echo ___ | ||
3 | trap | ||
4 | |||
5 | # assign some traps | ||
6 | echo ___ | ||
7 | trap "a" EXIT INT USR1 USR2 | ||
8 | |||
9 | # show them all | ||
10 | echo ___ | ||
11 | trap | ||
12 | |||
13 | # clear one | ||
14 | echo ___ | ||
15 | trap 0 INT | ||
16 | echo ___ | ||
17 | trap | ||
18 | |||
19 | # clear another | ||
20 | echo ___ | ||
21 | trap "-" USR1 | ||
22 | echo ___ | ||
23 | trap | ||
diff --git a/shell/hush.c b/shell/hush.c index e9cec1cc9..ab7263381 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -63,7 +63,6 @@ | |||
63 | * reserved words: function select | 63 | * reserved words: function select |
64 | * advanced test: [[ ]] | 64 | * advanced test: [[ ]] |
65 | * process substitution: <(list) and >(list) | 65 | * process substitution: <(list) and >(list) |
66 | * =~: regex operator | ||
67 | * let EXPR [EXPR...] | 66 | * let EXPR [EXPR...] |
68 | * Each EXPR is an arithmetic expression (ARITHMETIC EVALUATION) | 67 | * Each EXPR is an arithmetic expression (ARITHMETIC EVALUATION) |
69 | * If the last arg evaluates to 0, let returns 1; 0 otherwise. | 68 | * If the last arg evaluates to 0, let returns 1; 0 otherwise. |
@@ -84,13 +83,12 @@ | |||
84 | * [[ args ]] are CMD_SINGLEWORD_NOGLOB: | 83 | * [[ args ]] are CMD_SINGLEWORD_NOGLOB: |
85 | * v='a b'; [[ $v = 'a b' ]]; echo 0:$? | 84 | * v='a b'; [[ $v = 'a b' ]]; echo 0:$? |
86 | * [[ /bin/n* ]]; echo 0:$? | 85 | * [[ /bin/n* ]]; echo 0:$? |
86 | * = is glob match operator, not equality operator: STR = GLOB | ||
87 | * == same as = | ||
88 | * =~ is regex match operator: STR =~ REGEX | ||
87 | * TODO: | 89 | * TODO: |
88 | * &&/|| are AND/OR ops, -a/-o are not | ||
89 | * quoting needs to be considered (-f is an operator, "-f" and ""-f are not; etc) | 90 | * quoting needs to be considered (-f is an operator, "-f" and ""-f are not; etc) |
90 | * = is glob match operator, not equality operator: STR = GLOB | 91 | * in word = GLOB, quoting should be significant on char-by-char basis: a*cd"*" |
91 | * (in GLOB, quoting is significant on char-by-char basis: a*cd"*") | ||
92 | * == same as = | ||
93 | * add =~ regex match operator: STR =~ REGEX | ||
94 | */ | 92 | */ |
95 | //config:config HUSH | 93 | //config:config HUSH |
96 | //config: bool "hush (68 kb)" | 94 | //config: bool "hush (68 kb)" |
@@ -651,14 +649,16 @@ struct command { | |||
651 | smallint cmd_type; /* CMD_xxx */ | 649 | smallint cmd_type; /* CMD_xxx */ |
652 | #define CMD_NORMAL 0 | 650 | #define CMD_NORMAL 0 |
653 | #define CMD_SUBSHELL 1 | 651 | #define CMD_SUBSHELL 1 |
654 | #if BASH_TEST2 || ENABLE_HUSH_LOCAL || ENABLE_HUSH_EXPORT || ENABLE_HUSH_READONLY | 652 | #if BASH_TEST2 |
655 | /* used for "[[ EXPR ]]", and to prevent word splitting and globbing in | 653 | /* used for "[[ EXPR ]]" */ |
656 | * "export v=t*" | 654 | # define CMD_TEST2_SINGLEWORD_NOGLOB 2 |
657 | */ | 655 | #endif |
658 | # define CMD_SINGLEWORD_NOGLOB 2 | 656 | #if ENABLE_HUSH_LOCAL || ENABLE_HUSH_EXPORT || ENABLE_HUSH_READONLY |
657 | /* used to prevent word splitting and globbing in "export v=t*" */ | ||
658 | # define CMD_SINGLEWORD_NOGLOB 3 | ||
659 | #endif | 659 | #endif |
660 | #if ENABLE_HUSH_FUNCTIONS | 660 | #if ENABLE_HUSH_FUNCTIONS |
661 | # define CMD_FUNCDEF 3 | 661 | # define CMD_FUNCDEF 4 |
662 | #endif | 662 | #endif |
663 | 663 | ||
664 | smalluint cmd_exitcode; | 664 | smalluint cmd_exitcode; |
@@ -4112,6 +4112,14 @@ static int done_word(struct parse_context *ctx) | |||
4112 | ctx->ctx_dsemicolon = 0; | 4112 | ctx->ctx_dsemicolon = 0; |
4113 | } else | 4113 | } else |
4114 | # endif | 4114 | # endif |
4115 | # if defined(CMD_TEST2_SINGLEWORD_NOGLOB) | ||
4116 | if (command->cmd_type == CMD_TEST2_SINGLEWORD_NOGLOB | ||
4117 | && strcmp(ctx->word.data, "]]") == 0 | ||
4118 | ) { | ||
4119 | /* allow "[[ ]] >file" etc */ | ||
4120 | command->cmd_type = CMD_SINGLEWORD_NOGLOB; | ||
4121 | } else | ||
4122 | # endif | ||
4115 | if (!command->argv /* if it's the first word... */ | 4123 | if (!command->argv /* if it's the first word... */ |
4116 | # if ENABLE_HUSH_LOOPS | 4124 | # if ENABLE_HUSH_LOOPS |
4117 | && ctx->ctx_res_w != RES_FOR /* ...not after FOR or IN */ | 4125 | && ctx->ctx_res_w != RES_FOR /* ...not after FOR or IN */ |
@@ -4146,11 +4154,13 @@ static int done_word(struct parse_context *ctx) | |||
4146 | (ctx->ctx_res_w == RES_SNTX)); | 4154 | (ctx->ctx_res_w == RES_SNTX)); |
4147 | return (ctx->ctx_res_w == RES_SNTX); | 4155 | return (ctx->ctx_res_w == RES_SNTX); |
4148 | } | 4156 | } |
4157 | # if defined(CMD_TEST2_SINGLEWORD_NOGLOB) | ||
4158 | if (strcmp(ctx->word.data, "[[") == 0) { | ||
4159 | command->cmd_type = CMD_TEST2_SINGLEWORD_NOGLOB; | ||
4160 | } else | ||
4161 | # endif | ||
4149 | # if defined(CMD_SINGLEWORD_NOGLOB) | 4162 | # if defined(CMD_SINGLEWORD_NOGLOB) |
4150 | if (0 | 4163 | if (0 |
4151 | # if BASH_TEST2 | ||
4152 | || strcmp(ctx->word.data, "[[") == 0 | ||
4153 | # endif | ||
4154 | /* In bash, local/export/readonly are special, args | 4164 | /* In bash, local/export/readonly are special, args |
4155 | * are assignments and therefore expansion of them | 4165 | * are assignments and therefore expansion of them |
4156 | * should be "one-word" expansion: | 4166 | * should be "one-word" expansion: |
@@ -4172,7 +4182,8 @@ static int done_word(struct parse_context *ctx) | |||
4172 | ) { | 4182 | ) { |
4173 | command->cmd_type = CMD_SINGLEWORD_NOGLOB; | 4183 | command->cmd_type = CMD_SINGLEWORD_NOGLOB; |
4174 | } | 4184 | } |
4175 | /* fall through */ | 4185 | # else |
4186 | { /* empty block to pair "if ... else" */ } | ||
4176 | # endif | 4187 | # endif |
4177 | } | 4188 | } |
4178 | #endif /* HAS_KEYWORDS */ | 4189 | #endif /* HAS_KEYWORDS */ |
@@ -5354,9 +5365,15 @@ static struct pipe *parse_stream(char **pstring, | |||
5354 | if (ch != '\n') | 5365 | if (ch != '\n') |
5355 | next = i_peek_and_eat_bkslash_nl(input); | 5366 | next = i_peek_and_eat_bkslash_nl(input); |
5356 | 5367 | ||
5357 | is_special = "{}<>;&|()#" /* special outside of "str" */ | 5368 | is_special = "{}<>&|();#" /* special outside of "str" */ |
5358 | "$\"" IF_HUSH_TICK("`") /* always special */ | 5369 | "$\"" IF_HUSH_TICK("`") /* always special */ |
5359 | SPECIAL_VAR_SYMBOL_STR; | 5370 | SPECIAL_VAR_SYMBOL_STR; |
5371 | #if defined(CMD_TEST2_SINGLEWORD_NOGLOB) | ||
5372 | if (ctx.command->cmd_type == CMD_TEST2_SINGLEWORD_NOGLOB) { | ||
5373 | /* In [[ ]], {}<>&|() are not special */ | ||
5374 | is_special += 8; | ||
5375 | } else | ||
5376 | #endif | ||
5360 | /* Are { and } special here? */ | 5377 | /* Are { and } special here? */ |
5361 | if (ctx.command->argv /* word [word]{... - non-special */ | 5378 | if (ctx.command->argv /* word [word]{... - non-special */ |
5362 | || ctx.word.length /* word{... - non-special */ | 5379 | || ctx.word.length /* word{... - non-special */ |
@@ -6953,7 +6970,7 @@ static char **expand_strvec_to_strvec(char **argv) | |||
6953 | return expand_variables(argv, EXP_FLAG_GLOB | EXP_FLAG_ESC_GLOB_CHARS); | 6970 | return expand_variables(argv, EXP_FLAG_GLOB | EXP_FLAG_ESC_GLOB_CHARS); |
6954 | } | 6971 | } |
6955 | 6972 | ||
6956 | #if defined(CMD_SINGLEWORD_NOGLOB) | 6973 | #if defined(CMD_SINGLEWORD_NOGLOB) || defined(CMD_TEST2_SINGLEWORD_NOGLOB) |
6957 | static char **expand_strvec_to_strvec_singleword_noglob(char **argv) | 6974 | static char **expand_strvec_to_strvec_singleword_noglob(char **argv) |
6958 | { | 6975 | { |
6959 | return expand_variables(argv, EXP_FLAG_SINGLEWORD); | 6976 | return expand_variables(argv, EXP_FLAG_SINGLEWORD); |
@@ -8698,9 +8715,15 @@ static int process_wait_result(struct pipe *fg_pipe, pid_t childpid, int status) | |||
8698 | */ | 8715 | */ |
8699 | if (WIFSIGNALED(status)) { | 8716 | if (WIFSIGNALED(status)) { |
8700 | int sig = WTERMSIG(status); | 8717 | int sig = WTERMSIG(status); |
8701 | if (i == fg_pipe->num_cmds-1) | 8718 | if (G.run_list_level == 1 |
8702 | /* TODO: use strsignal() instead for bash compat? but that's bloat... */ | 8719 | /* ^^^^^ Do not print in nested contexts, example: |
8703 | puts(sig == SIGINT || sig == SIGPIPE ? "" : get_signame(sig)); | 8720 | * echo `sleep 1; sh -c 'kill -9 $$'` - prints "137", NOT "Killed 137" |
8721 | */ | ||
8722 | && i == fg_pipe->num_cmds-1 | ||
8723 | ) { | ||
8724 | /* strsignal() is for bash compat. ~600 bloat versus bbox's get_signame() */ | ||
8725 | puts(sig == SIGINT || sig == SIGPIPE ? "" : strsignal(sig)); | ||
8726 | } | ||
8704 | /* TODO: if (WCOREDUMP(status)) + " (core dumped)"; */ | 8727 | /* TODO: if (WCOREDUMP(status)) + " (core dumped)"; */ |
8705 | /* TODO: MIPS has 128 sigs (1..128), what if sig==128 here? | 8728 | /* TODO: MIPS has 128 sigs (1..128), what if sig==128 here? |
8706 | * Maybe we need to use sig | 128? */ | 8729 | * Maybe we need to use sig | 128? */ |
@@ -9127,6 +9150,11 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
9127 | } | 9150 | } |
9128 | 9151 | ||
9129 | /* Expand the rest into (possibly) many strings each */ | 9152 | /* Expand the rest into (possibly) many strings each */ |
9153 | #if defined(CMD_TEST2_SINGLEWORD_NOGLOB) | ||
9154 | if (command->cmd_type == CMD_TEST2_SINGLEWORD_NOGLOB) | ||
9155 | argv_expanded = expand_strvec_to_strvec_singleword_noglob(argv + command->assignment_cnt); | ||
9156 | else | ||
9157 | #endif | ||
9130 | #if defined(CMD_SINGLEWORD_NOGLOB) | 9158 | #if defined(CMD_SINGLEWORD_NOGLOB) |
9131 | if (command->cmd_type == CMD_SINGLEWORD_NOGLOB) | 9159 | if (command->cmd_type == CMD_SINGLEWORD_NOGLOB) |
9132 | argv_expanded = expand_strvec_to_strvec_singleword_noglob(argv + command->assignment_cnt); | 9160 | argv_expanded = expand_strvec_to_strvec_singleword_noglob(argv + command->assignment_cnt); |
diff --git a/shell/hush_test/hush-bugs/strops5_bug.right b/shell/hush_test/hush-bugs/strops5_bug.right new file mode 100644 index 000000000..aba7bb429 --- /dev/null +++ b/shell/hush_test/hush-bugs/strops5_bug.right | |||
@@ -0,0 +1,2 @@ | |||
1 | 4:no:1 | ||
2 | 5:YES:0 | ||
diff --git a/shell/hush_test/hush-bugs/strops5_bug.tests b/shell/hush_test/hush-bugs/strops5_bug.tests new file mode 100755 index 000000000..3e24df768 --- /dev/null +++ b/shell/hush_test/hush-bugs/strops5_bug.tests | |||
@@ -0,0 +1,10 @@ | |||
1 | v='*.z' | ||
2 | |||
3 | # Buggy: | ||
4 | # the problem is that expansion rules of LHS and RHS of ~= | ||
5 | # should not be the same: in RHS, "$v" and "*" should escape metas | ||
6 | # (currently "$v" does not), | ||
7 | # but in LHS, they should _not_ do that | ||
8 | # (currently "*" does). Thus these cases fail: | ||
9 | [[ a.z == "$v" ]]; echo 4:no:$? # BUG: "$v" expands to *.z | ||
10 | [[ "*".z == ?.z ]]; echo 5:YES:$? # BUG: "*" expands to \* | ||
diff --git a/shell/hush_test/hush-misc/sig_exitcode.right b/shell/hush_test/hush-misc/sig_exitcode.right index d5f000a08..7cbc1072d 100644 --- a/shell/hush_test/hush-misc/sig_exitcode.right +++ b/shell/hush_test/hush-misc/sig_exitcode.right | |||
@@ -1,5 +1,5 @@ | |||
1 | KILL | 1 | Killed |
2 | 137:137 | 2 | 137:137 |
3 | KILL | 3 | Killed |
4 | 0:0 | 4 | 0:0 |
5 | Done | 5 | Done |
diff --git a/shell/hush_test/hush-misc/wait7.right b/shell/hush_test/hush-misc/wait7.right new file mode 100644 index 000000000..4b6445841 --- /dev/null +++ b/shell/hush_test/hush-misc/wait7.right | |||
@@ -0,0 +1,2 @@ | |||
1 | Background1 | ||
2 | Ok:0 | ||
diff --git a/shell/hush_test/hush-misc/wait7.tests b/shell/hush_test/hush-misc/wait7.tests new file mode 100755 index 000000000..a54a778e5 --- /dev/null +++ b/shell/hush_test/hush-misc/wait7.tests | |||
@@ -0,0 +1,7 @@ | |||
1 | sleep 1 && echo "Background1" & | ||
2 | pid=$! | ||
3 | sleep 3 && echo "Background2: BUG!" & | ||
4 | # Shouldn't wait for 2nd bkgd: | ||
5 | wait $pid | ||
6 | kill $! | ||
7 | echo Ok:$? | ||
diff --git a/shell/hush_test/hush-psubst/tick6.right b/shell/hush_test/hush-psubst/tick6.right new file mode 100644 index 000000000..065fd3e79 --- /dev/null +++ b/shell/hush_test/hush-psubst/tick6.right | |||
@@ -0,0 +1 @@ | |||
137 | |||
diff --git a/shell/hush_test/hush-psubst/tick6.tests b/shell/hush_test/hush-psubst/tick6.tests new file mode 100755 index 000000000..33dd3630d --- /dev/null +++ b/shell/hush_test/hush-psubst/tick6.tests | |||
@@ -0,0 +1 @@ | |||
true; echo `sh -c 'kill -9 $$'` $? | |||
diff --git a/shell/hush_test/hush-signals/catch.right b/shell/hush_test/hush-signals/catch.right index 80a062c4b..68530c6e7 100644 --- a/shell/hush_test/hush-signals/catch.right +++ b/shell/hush_test/hush-signals/catch.right | |||
@@ -2,4 +2,4 @@ sending USR2 | |||
2 | caught | 2 | caught |
3 | sending USR2 | 3 | sending USR2 |
4 | sending USR2 | 4 | sending USR2 |
5 | USR2 | 5 | User defined signal 2 |
diff --git a/shell/hush_test/hush-signals/signal1.right b/shell/hush_test/hush-signals/signal1.right new file mode 100644 index 000000000..cf403ac62 --- /dev/null +++ b/shell/hush_test/hush-signals/signal1.right | |||
@@ -0,0 +1,20 @@ | |||
1 | got signal | ||
2 | trap -- 'echo got signal' USR1 | ||
3 | sent 1 signal | ||
4 | got signal | ||
5 | wait interrupted | ||
6 | trap -- 'echo got signal' USR1 | ||
7 | sent 2 signal | ||
8 | got signal | ||
9 | wait interrupted | ||
10 | trap -- 'echo got signal' USR1 | ||
11 | sent 3 signal | ||
12 | got signal | ||
13 | wait interrupted | ||
14 | trap -- 'echo got signal' USR1 | ||
15 | sent 4 signal | ||
16 | got signal | ||
17 | wait interrupted | ||
18 | trap -- 'echo got signal' USR1 | ||
19 | sent 5 signal | ||
20 | sleep completed | ||
diff --git a/shell/hush_test/hush-signals/signal1.tests b/shell/hush_test/hush-signals/signal1.tests new file mode 100755 index 000000000..61943467a --- /dev/null +++ b/shell/hush_test/hush-signals/signal1.tests | |||
@@ -0,0 +1,28 @@ | |||
1 | trap "echo got signal" USR1 | ||
2 | |||
3 | for try in 1 2 3 4 5; do | ||
4 | kill -USR1 $$ | ||
5 | sleep 0.2 | ||
6 | echo "sent $try signal" | ||
7 | done & | ||
8 | |||
9 | # Ensure "wait" has something to wait for | ||
10 | sleep 2 & | ||
11 | |||
12 | # Ensure we do not execute "trap" below before "kill -USR1" above | ||
13 | # (was getting failure on loaded machine without this) | ||
14 | sleep 0.1 | ||
15 | |||
16 | sleeping=true | ||
17 | while $sleeping; do | ||
18 | trap | ||
19 | if wait %%; then | ||
20 | echo "sleep completed" | ||
21 | sleeping=false | ||
22 | elif [ $? = 127 ]; then | ||
23 | echo "BUG: no processes to wait for?!" | ||
24 | sleeping=false | ||
25 | else | ||
26 | echo "wait interrupted" | ||
27 | fi | ||
28 | done | ||
diff --git a/shell/hush_test/hush-signals/signal_read2.right b/shell/hush_test/hush-signals/signal_read2.right index 71a6bc16d..87d8da304 100644 --- a/shell/hush_test/hush-signals/signal_read2.right +++ b/shell/hush_test/hush-signals/signal_read2.right | |||
@@ -1,2 +1,2 @@ | |||
1 | HUP | 1 | Hangup |
2 | Done:129 | 2 | Done:129 |
diff --git a/shell/hush_test/hush-signals/subshell.right b/shell/hush_test/hush-signals/subshell.right index f865b932b..248fcc41a 100644 --- a/shell/hush_test/hush-signals/subshell.right +++ b/shell/hush_test/hush-signals/subshell.right | |||
@@ -17,5 +17,5 @@ Ok | |||
17 | trap -- '' HUP | 17 | trap -- '' HUP |
18 | trap -- '' QUIT | 18 | trap -- '' QUIT |
19 | trap -- '' SYS | 19 | trap -- '' SYS |
20 | TERM | 20 | Terminated |
21 | Done | 21 | Done |
diff --git a/shell/hush_test/hush-test2/andor1.right b/shell/hush_test/hush-test2/andor1.right new file mode 100644 index 000000000..038c7a681 --- /dev/null +++ b/shell/hush_test/hush-test2/andor1.right | |||
@@ -0,0 +1,6 @@ | |||
1 | 1:YES | ||
2 | 2:no | ||
3 | 3:YES | ||
4 | 4:YES | ||
5 | 5:no | ||
6 | 6:no | ||
diff --git a/shell/hush_test/hush-test2/andor1.tests b/shell/hush_test/hush-test2/andor1.tests new file mode 100755 index 000000000..c449de7e6 --- /dev/null +++ b/shell/hush_test/hush-test2/andor1.tests | |||
@@ -0,0 +1,7 @@ | |||
1 | e='' | ||
2 | [[ a && b ]] && echo 1:YES | ||
3 | [[ a && '' ]] || echo 2:no | ||
4 | [[ a || b ]] && echo 3:YES | ||
5 | [[ '' || b ]] && echo 4:YES | ||
6 | [[ "" || "$e" ]] || echo 5:no | ||
7 | [[ "" || $e ]] || echo 6:no | ||
diff --git a/shell/hush_test/hush-test2/noglob1.right b/shell/hush_test/hush-test2/noglob1.right new file mode 100644 index 000000000..d0c3f1d8e --- /dev/null +++ b/shell/hush_test/hush-test2/noglob1.right | |||
@@ -0,0 +1,2 @@ | |||
1 | 1:YES:0 | ||
2 | 2:YES:0 | ||
diff --git a/shell/hush_test/hush-test2/noglob1.tests b/shell/hush_test/hush-test2/noglob1.tests new file mode 100755 index 000000000..963bacbd3 --- /dev/null +++ b/shell/hush_test/hush-test2/noglob1.tests | |||
@@ -0,0 +1,3 @@ | |||
1 | v='*.tests' | ||
2 | [[ *.tests ]]; echo 1:YES:$? | ||
3 | [[ $v ]]; echo 2:YES:$? | ||
diff --git a/shell/hush_test/hush-test2/strops1.right b/shell/hush_test/hush-test2/strops1.right new file mode 100644 index 000000000..590496301 --- /dev/null +++ b/shell/hush_test/hush-test2/strops1.right | |||
@@ -0,0 +1,8 @@ | |||
1 | 1:YES:0 | ||
2 | 2:YES:0 | ||
3 | 3:YES:0 | ||
4 | 4:YES:0 | ||
5 | 5:YES:0 | ||
6 | 6:YES:0 | ||
7 | 7:YES:0 | ||
8 | 8:no:1 | ||
diff --git a/shell/hush_test/hush-test2/strops1.tests b/shell/hush_test/hush-test2/strops1.tests new file mode 100755 index 000000000..bb24e2a2f --- /dev/null +++ b/shell/hush_test/hush-test2/strops1.tests | |||
@@ -0,0 +1,15 @@ | |||
1 | v='*.z' | ||
2 | [[ a.z = *.z ]]; echo 1:YES:$? | ||
3 | [[ a.z == $v ]]; echo 2:YES:$? | ||
4 | |||
5 | # wildcards can match a slash | ||
6 | [[ a/b = a*b ]]; echo 3:YES:$? | ||
7 | [[ a/b == a?b ]]; echo 4:YES:$? | ||
8 | |||
9 | # wildcards can match a leading dot | ||
10 | [[ a/.b = a/*b ]]; echo 5:YES:$? | ||
11 | [[ a/.b == a/?b ]]; echo 6:YES:$? | ||
12 | |||
13 | # wildcards can be escaped | ||
14 | [[ abc = a*c ]]; echo 7:YES:$? | ||
15 | [[ abc == a\*c ]]; echo 8:no:$? | ||
diff --git a/shell/hush_test/hush-test2/strops2.right b/shell/hush_test/hush-test2/strops2.right new file mode 100644 index 000000000..8ddb4b0f0 --- /dev/null +++ b/shell/hush_test/hush-test2/strops2.right | |||
@@ -0,0 +1,6 @@ | |||
1 | 1:ERR2:2 | ||
2 | 2:YES:0 | ||
3 | 3:YES:0 | ||
4 | 4:YES:0 | ||
5 | 5:no:1 | ||
6 | 6:YES:0 | ||
diff --git a/shell/hush_test/hush-test2/strops2.tests b/shell/hush_test/hush-test2/strops2.tests new file mode 100755 index 000000000..ab325bc9f --- /dev/null +++ b/shell/hush_test/hush-test2/strops2.tests | |||
@@ -0,0 +1,12 @@ | |||
1 | # malformed regex | ||
2 | [[ a =~ * ]]; echo 1:ERR2:$? | ||
3 | |||
4 | [[ a/b =~ a.b ]]; echo 2:YES:$? | ||
5 | [[ a/b =~ /*b ]]; echo 3:YES:$? | ||
6 | |||
7 | v='[]b.-]' | ||
8 | [[ a/.b] =~ $v ]]; echo 4:YES:$? | ||
9 | |||
10 | v=']b.-' | ||
11 | [[ a/.b] =~ $v ]]; echo 5:no:$? | ||
12 | [[ a/.b] =~ [$v] ]]; echo 6:YES:$? | ||
diff --git a/shell/hush_test/hush-test2/strops3.right b/shell/hush_test/hush-test2/strops3.right new file mode 100644 index 000000000..14cc04fdc --- /dev/null +++ b/shell/hush_test/hush-test2/strops3.right | |||
@@ -0,0 +1,7 @@ | |||
1 | 1:YES:0 | ||
2 | 2:YES:0 | ||
3 | 3:no:1 | ||
4 | 4:YES:0 | ||
5 | 2u:YES:0 | ||
6 | 3u:YES:0 | ||
7 | 4u:YES:0 | ||
diff --git a/shell/hush_test/hush-test2/strops3.tests b/shell/hush_test/hush-test2/strops3.tests new file mode 100755 index 000000000..927476671 --- /dev/null +++ b/shell/hush_test/hush-test2/strops3.tests | |||
@@ -0,0 +1,13 @@ | |||
1 | # regex should accept '+' operator | ||
2 | [[ abcdef =~ a[b-z]+ ]]; echo 1:YES:$? | ||
3 | |||
4 | # newline matches by "match any" patterns | ||
5 | v=' | ||
6 | ' | ||
7 | [[ "$v" =~ . ]]; echo 2:YES:$? | ||
8 | [[ "$v" =~ "[$v]" ]]; echo 3:no:$? # hmm bash does return 1... why? | ||
9 | [[ "$v" =~ [^a] ]]; echo 4:YES:$? | ||
10 | # should work even without quotes: | ||
11 | [[ $v =~ . ]]; echo 2u:YES:$? | ||
12 | [[ $v =~ [$v] ]]; echo 3u:YES:$? | ||
13 | [[ $v =~ [^a] ]]; echo 4u:YES:$? | ||
diff --git a/shell/hush_test/hush-test2/strops4.right b/shell/hush_test/hush-test2/strops4.right new file mode 100644 index 000000000..53a176261 --- /dev/null +++ b/shell/hush_test/hush-test2/strops4.right | |||
@@ -0,0 +1,2 @@ | |||
1 | 1:no:1 | ||
2 | 2:YES:0 | ||
diff --git a/shell/hush_test/hush-test2/strops4.tests b/shell/hush_test/hush-test2/strops4.tests new file mode 100755 index 000000000..bb381426d --- /dev/null +++ b/shell/hush_test/hush-test2/strops4.tests | |||
@@ -0,0 +1,3 @@ | |||
1 | # < > are not redirect operators | ||
2 | [[ a > b ]]; echo 1:no:$? | ||
3 | [[ a < b ]]; echo 2:YES:$? | ||
diff --git a/shell/hush_test/hush-test2/strops5.right b/shell/hush_test/hush-test2/strops5.right new file mode 100644 index 000000000..9ed4d6569 --- /dev/null +++ b/shell/hush_test/hush-test2/strops5.right | |||
@@ -0,0 +1,3 @@ | |||
1 | 1:YES:0 | ||
2 | 2:no:1 | ||
3 | 3:YES:0 | ||
diff --git a/shell/hush_test/hush-test2/strops5.tests b/shell/hush_test/hush-test2/strops5.tests new file mode 100755 index 000000000..ee01e5c30 --- /dev/null +++ b/shell/hush_test/hush-test2/strops5.tests | |||
@@ -0,0 +1,13 @@ | |||
1 | v='*.z' | ||
2 | [[ a.z = *.z ]]; echo 1:YES:$? | ||
3 | [[ a.z = "*".z ]]; echo 2:no:$? | ||
4 | [[ a.z == $v ]]; echo 3:YES:$? | ||
5 | |||
6 | # Buggy: | ||
7 | # the problem is that expansion rules of LHS and RHS of ~= | ||
8 | # should not be the same: in RHS, "$v" and "*" should escape metas | ||
9 | # (currently "$v" does not), | ||
10 | # but in LHS, they should _not_ do that | ||
11 | # (currently "*" does). Thus these cases fail: | ||
12 | #[[ a.z == "$v" ]]; echo 4:no:$? # BUG: "$v" expands to *.z | ||
13 | #[[ "*".z == ?.z ]]; echo 5:YES:$? # BUG: "*" expands to \* | ||
diff --git a/shell/math.c b/shell/math.c index aac5017d0..2942cdd26 100644 --- a/shell/math.c +++ b/shell/math.c | |||
@@ -251,7 +251,7 @@ typedef struct remembered_name { | |||
251 | } remembered_name; | 251 | } remembered_name; |
252 | 252 | ||
253 | 253 | ||
254 | static arith_t FAST_FUNC | 254 | static arith_t |
255 | evaluate_string(arith_state_t *math_state, const char *expr); | 255 | evaluate_string(arith_state_t *math_state, const char *expr); |
256 | 256 | ||
257 | static const char* | 257 | static const char* |
@@ -582,7 +582,7 @@ static arith_t strto_arith_t(const char *nptr, char **endptr) | |||
582 | # endif | 582 | # endif |
583 | #endif | 583 | #endif |
584 | 584 | ||
585 | static arith_t FAST_FUNC | 585 | static arith_t |
586 | evaluate_string(arith_state_t *math_state, const char *expr) | 586 | evaluate_string(arith_state_t *math_state, const char *expr) |
587 | { | 587 | { |
588 | operator lasttok; | 588 | operator lasttok; |
diff --git a/testsuite/hexdump.tests b/testsuite/hexdump.tests index 45a0c1300..cfb20187e 100755 --- a/testsuite/hexdump.tests +++ b/testsuite/hexdump.tests | |||
@@ -15,4 +15,23 @@ testing 'hexdump -C with four NULs' \ | |||
15 | '' \ | 15 | '' \ |
16 | '\0\0\0\0' | 16 | '\0\0\0\0' |
17 | 17 | ||
18 | testing "hexdump does not think last padded block matches any full block" \ | ||
19 | "hexdump -e '1/1 \"%02x|\"1/1 \"%02x!\\n\"'" \ | ||
20 | "\ | ||
21 | 00|00! | ||
22 | * | ||
23 | 00| ! | ||
24 | " \ | ||
25 | '' \ | ||
26 | '\0\0\0\0\0\0\0\0\0\0\0' | ||
27 | |||
28 | testing "hexdump thinks last full block can match" \ | ||
29 | "hexdump -e '1/1 \"%02x|\"1/1 \"%02x!\\n\"'" \ | ||
30 | "\ | ||
31 | 00|00! | ||
32 | * | ||
33 | " \ | ||
34 | '' \ | ||
35 | '\0\0\0\0\0\0\0\0\0\0\0\0' | ||
36 | |||
18 | exit $FAILCOUNT | 37 | exit $FAILCOUNT |
diff --git a/testsuite/xargs.tests b/testsuite/xargs.tests index 159f1ff69..e7c7c4b3d 100755 --- a/testsuite/xargs.tests +++ b/testsuite/xargs.tests | |||
@@ -61,4 +61,12 @@ testing "xargs -n2" \ | |||
61 | 61 | ||
62 | SKIP= | 62 | SKIP= |
63 | 63 | ||
64 | optional FEATURE_XARGS_SUPPORT_QUOTES | ||
65 | testing "xargs -I skips empty lines and leading whitespace" \ | ||
66 | "xargs -I% echo '[%]'" \ | ||
67 | "[2]\n[4]\n[6 6 ]\n[7]\n" \ | ||
68 | "" " \n2\n\n4\n\n 6 6 \n \v \t 7\n\t\n\v\n" | ||
69 | |||
70 | SKIP= | ||
71 | |||
64 | exit $FAILCOUNT | 72 | exit $FAILCOUNT |
diff --git a/testsuite/xxd.tests b/testsuite/xxd.tests new file mode 100755 index 000000000..2e80be5fe --- /dev/null +++ b/testsuite/xxd.tests | |||
@@ -0,0 +1,34 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | # Copyright 2020 by Denys Vlasenko <vda.linux@googlemail.com> | ||
4 | # Licensed under GPLv2, see file LICENSE in this source tree. | ||
5 | |||
6 | . ./testing.sh | ||
7 | |||
8 | # testing "description" "command" "result" "infile" "stdin" | ||
9 | testing 'xxd -p with one NUL' \ | ||
10 | 'xxd -p' \ | ||
11 | "\ | ||
12 | 00 | ||
13 | " \ | ||
14 | '' \ | ||
15 | '\0' | ||
16 | |||
17 | testing 'xxd -p with 30 NULs' \ | ||
18 | 'xxd -p' \ | ||
19 | "\ | ||
20 | 000000000000000000000000000000000000000000000000000000000000 | ||
21 | " \ | ||
22 | '' \ | ||
23 | '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0' | ||
24 | |||
25 | testing 'xxd -p with 31 NULs' \ | ||
26 | 'xxd -p' \ | ||
27 | "\ | ||
28 | 000000000000000000000000000000000000000000000000000000000000 | ||
29 | 00 | ||
30 | " \ | ||
31 | '' \ | ||
32 | '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0' | ||
33 | |||
34 | exit $FAILCOUNT | ||
diff --git a/util-linux/getopt.c b/util-linux/getopt.c index db7db6ff8..1fa402429 100644 --- a/util-linux/getopt.c +++ b/util-linux/getopt.c | |||
@@ -289,12 +289,13 @@ static struct option *add_long_options(struct option *long_options, char *option | |||
289 | { | 289 | { |
290 | int long_nr = 0; | 290 | int long_nr = 0; |
291 | int arg_opt, tlen; | 291 | int arg_opt, tlen; |
292 | char *tokptr = strtok(options, ", \t\n"); | 292 | char *tokptr; |
293 | 293 | ||
294 | if (long_options) | 294 | if (long_options) |
295 | while (long_options[long_nr].name) | 295 | while (long_options[long_nr].name) |
296 | long_nr++; | 296 | long_nr++; |
297 | 297 | ||
298 | tokptr = strtok_r(options, ", \t\n", &options); | ||
298 | while (tokptr) { | 299 | while (tokptr) { |
299 | arg_opt = no_argument; | 300 | arg_opt = no_argument; |
300 | tlen = strlen(tokptr); | 301 | tlen = strlen(tokptr); |
@@ -318,7 +319,7 @@ static struct option *add_long_options(struct option *long_options, char *option | |||
318 | long_nr++; | 319 | long_nr++; |
319 | /*memset(&long_options[long_nr], 0, sizeof(long_options[0])); - xrealloc_vector did it */ | 320 | /*memset(&long_options[long_nr], 0, sizeof(long_options[0])); - xrealloc_vector did it */ |
320 | } | 321 | } |
321 | tokptr = strtok(NULL, ", \t\n"); | 322 | tokptr = strtok_r(NULL, ", \t\n", &options); |
322 | } | 323 | } |
323 | return long_options; | 324 | return long_options; |
324 | } | 325 | } |
diff --git a/util-linux/hexdump.c b/util-linux/hexdump.c index 065b83980..2174c3008 100644 --- a/util-linux/hexdump.c +++ b/util-linux/hexdump.c | |||
@@ -15,16 +15,6 @@ | |||
15 | //config: The hexdump utility is used to display binary data in a readable | 15 | //config: The hexdump utility is used to display binary data in a readable |
16 | //config: way that is comparable to the output from most hex editors. | 16 | //config: way that is comparable to the output from most hex editors. |
17 | //config: | 17 | //config: |
18 | //config:config FEATURE_HEXDUMP_REVERSE | ||
19 | //config: bool "Support -R, reverse of 'hexdump -Cv'" | ||
20 | //config: default y | ||
21 | //config: depends on HEXDUMP | ||
22 | //config: help | ||
23 | //config: The hexdump utility is used to display binary data in an ascii | ||
24 | //config: readable way. This option creates binary data from an ascii input. | ||
25 | //config: NB: this option is non-standard. It's unwise to use it in scripts | ||
26 | //config: aimed to be portable. | ||
27 | //config: | ||
28 | //config:config HD | 18 | //config:config HD |
29 | //config: bool "hd (7.8 kb)" | 19 | //config: bool "hd (7.8 kb)" |
30 | //config: default y | 20 | //config: default y |
@@ -38,7 +28,7 @@ | |||
38 | //kbuild:lib-$(CONFIG_HD) += hexdump.o | 28 | //kbuild:lib-$(CONFIG_HD) += hexdump.o |
39 | 29 | ||
40 | //usage:#define hexdump_trivial_usage | 30 | //usage:#define hexdump_trivial_usage |
41 | //usage: "[-bcCdefnosvx" IF_FEATURE_HEXDUMP_REVERSE("R") "] [FILE]..." | 31 | //usage: "[-bcCdefnosvx] [FILE]..." |
42 | //usage:#define hexdump_full_usage "\n\n" | 32 | //usage:#define hexdump_full_usage "\n\n" |
43 | //usage: "Display FILEs (or stdin) in a user specified format\n" | 33 | //usage: "Display FILEs (or stdin) in a user specified format\n" |
44 | //usage: "\n -b 1-byte octal display" | 34 | //usage: "\n -b 1-byte octal display" |
@@ -53,9 +43,6 @@ | |||
53 | // exactly the same help text lines in hexdump and xxd: | 43 | // exactly the same help text lines in hexdump and xxd: |
54 | //usage: "\n -n LENGTH Show only first LENGTH bytes" | 44 | //usage: "\n -n LENGTH Show only first LENGTH bytes" |
55 | //usage: "\n -s OFFSET Skip OFFSET bytes" | 45 | //usage: "\n -s OFFSET Skip OFFSET bytes" |
56 | //usage: IF_FEATURE_HEXDUMP_REVERSE( | ||
57 | //usage: "\n -R Reverse of 'hexdump -Cv'") | ||
58 | // TODO: NONCOMPAT!!! move -R to xxd -r | ||
59 | //usage: | 46 | //usage: |
60 | //usage:#define hd_trivial_usage | 47 | //usage:#define hd_trivial_usage |
61 | //usage: "FILE..." | 48 | //usage: "FILE..." |
@@ -94,7 +81,7 @@ static const char *const add_strings[] = { | |||
94 | 81 | ||
95 | static const char add_first[] ALIGN1 = "\"%07.7_Ax\n\""; | 82 | static const char add_first[] ALIGN1 = "\"%07.7_Ax\n\""; |
96 | 83 | ||
97 | static const char hexdump_opts[] ALIGN1 = "bcdoxCe:f:n:s:v" IF_FEATURE_HEXDUMP_REVERSE("R"); | 84 | static const char hexdump_opts[] ALIGN1 = "bcdoxCe:f:n:s:v"; |
98 | 85 | ||
99 | int hexdump_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 86 | int hexdump_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
100 | int hexdump_main(int argc, char **argv) | 87 | int hexdump_main(int argc, char **argv) |
@@ -102,10 +89,6 @@ int hexdump_main(int argc, char **argv) | |||
102 | dumper_t *dumper = alloc_dumper(); | 89 | dumper_t *dumper = alloc_dumper(); |
103 | const char *p; | 90 | const char *p; |
104 | int ch; | 91 | int ch; |
105 | #if ENABLE_FEATURE_HEXDUMP_REVERSE | ||
106 | FILE *fp; | ||
107 | smallint rdump = 0; | ||
108 | #endif | ||
109 | 92 | ||
110 | if (ENABLE_HD | 93 | if (ENABLE_HD |
111 | && (!ENABLE_HEXDUMP || !applet_name[2]) | 94 | && (!ENABLE_HEXDUMP || !applet_name[2]) |
@@ -153,11 +136,6 @@ int hexdump_main(int argc, char **argv) | |||
153 | if (ch == 'v') { | 136 | if (ch == 'v') { |
154 | dumper->dump_vflag = ALL; | 137 | dumper->dump_vflag = ALL; |
155 | } | 138 | } |
156 | #if ENABLE_FEATURE_HEXDUMP_REVERSE | ||
157 | if (ch == 'R') { | ||
158 | rdump = 1; | ||
159 | } | ||
160 | #endif | ||
161 | } | 139 | } |
162 | 140 | ||
163 | if (!dumper->fshead) { | 141 | if (!dumper->fshead) { |
@@ -167,40 +145,5 @@ int hexdump_main(int argc, char **argv) | |||
167 | 145 | ||
168 | argv += optind; | 146 | argv += optind; |
169 | 147 | ||
170 | #if !ENABLE_FEATURE_HEXDUMP_REVERSE | ||
171 | return bb_dump_dump(dumper, argv); | 148 | return bb_dump_dump(dumper, argv); |
172 | #else | ||
173 | if (!rdump) { | ||
174 | return bb_dump_dump(dumper, argv); | ||
175 | } | ||
176 | |||
177 | /* -R: reverse of 'hexdump -Cv' */ | ||
178 | fp = stdin; | ||
179 | if (!*argv) { | ||
180 | argv--; | ||
181 | goto jump_in; | ||
182 | } | ||
183 | |||
184 | do { | ||
185 | char *buf; | ||
186 | fp = xfopen_for_read(*argv); | ||
187 | jump_in: | ||
188 | while ((buf = xmalloc_fgetline(fp)) != NULL) { | ||
189 | p = buf; | ||
190 | while (1) { | ||
191 | /* skip address or previous byte */ | ||
192 | while (isxdigit(*p)) p++; | ||
193 | while (*p == ' ') p++; | ||
194 | /* '|' char will break the line */ | ||
195 | if (!isxdigit(*p) || sscanf(p, "%x ", &ch) != 1) | ||
196 | break; | ||
197 | putchar(ch); | ||
198 | } | ||
199 | free(buf); | ||
200 | } | ||
201 | fclose(fp); | ||
202 | } while (*++argv); | ||
203 | |||
204 | fflush_stdout_and_exit(EXIT_SUCCESS); | ||
205 | #endif | ||
206 | } | 149 | } |
diff --git a/util-linux/hexdump_xxd.c b/util-linux/hexdump_xxd.c index 6cf6d0297..d2f4b6ed8 100644 --- a/util-linux/hexdump_xxd.c +++ b/util-linux/hexdump_xxd.c | |||
@@ -50,6 +50,7 @@ | |||
50 | // exactly the same help text lines in hexdump and xxd: | 50 | // exactly the same help text lines in hexdump and xxd: |
51 | //usage: "\n -l LENGTH Show only first LENGTH bytes" | 51 | //usage: "\n -l LENGTH Show only first LENGTH bytes" |
52 | //usage: "\n -s OFFSET Skip OFFSET bytes" | 52 | //usage: "\n -s OFFSET Skip OFFSET bytes" |
53 | //usage: "\n -r Reverse (with -p, assumes no offsets in input)" | ||
53 | // TODO: implement -r (see hexdump -R) | 54 | // TODO: implement -r (see hexdump -R) |
54 | 55 | ||
55 | #include "libbb.h" | 56 | #include "libbb.h" |
@@ -57,6 +58,71 @@ | |||
57 | 58 | ||
58 | /* This is a NOEXEC applet. Be very careful! */ | 59 | /* This is a NOEXEC applet. Be very careful! */ |
59 | 60 | ||
61 | #define OPT_l (1 << 0) | ||
62 | #define OPT_s (1 << 1) | ||
63 | #define OPT_a (1 << 2) | ||
64 | #define OPT_p (1 << 3) | ||
65 | #define OPT_r (1 << 4) | ||
66 | |||
67 | static void reverse(unsigned opt, unsigned cols, const char *filename) | ||
68 | { | ||
69 | FILE *fp; | ||
70 | char *buf; | ||
71 | |||
72 | fp = filename ? xfopen_for_read(filename) : stdin; | ||
73 | |||
74 | while ((buf = xmalloc_fgetline(fp)) != NULL) { | ||
75 | char *p = buf; | ||
76 | unsigned cnt = cols; | ||
77 | |||
78 | if (!(opt & OPT_p)) { | ||
79 | /* skip address */ | ||
80 | while (isxdigit(*p)) p++; | ||
81 | /* NB: for xxd -r, first hex portion is address even without colon */ | ||
82 | /* If it's there, skip it: */ | ||
83 | if (*p == ':') p++; | ||
84 | |||
85 | //TODO: seek (or zero-pad if unseekable) to the address position | ||
86 | //NOTE: -s SEEK value should be added to the address before seeking | ||
87 | } | ||
88 | |||
89 | /* Process hex bytes optionally separated by whitespace */ | ||
90 | do { | ||
91 | uint8_t val, c; | ||
92 | |||
93 | p = skip_whitespace(p); | ||
94 | |||
95 | c = *p++; | ||
96 | if (isdigit(c)) | ||
97 | val = c - '0'; | ||
98 | else if ((c|0x20) >= 'a' && (c|0x20) <= 'f') | ||
99 | val = (c|0x20) - ('a' - 10); | ||
100 | else | ||
101 | break; | ||
102 | val <<= 4; | ||
103 | |||
104 | /* Works the same with xxd V1.10: | ||
105 | * echo "31 09 32 0a" | xxd -r -p | ||
106 | * echo "31 0 9 32 0a" | xxd -r -p | ||
107 | * thus allow whitespace even within the byte: | ||
108 | */ | ||
109 | p = skip_whitespace(p); | ||
110 | |||
111 | c = *p++; | ||
112 | if (isdigit(c)) | ||
113 | val |= c - '0'; | ||
114 | else if ((c|0x20) >= 'a' && (c|0x20) <= 'f') | ||
115 | val |= (c|0x20) - ('a' - 10); | ||
116 | else | ||
117 | break; | ||
118 | putchar(val); | ||
119 | } while (!(opt & OPT_p) || --cnt != 0); | ||
120 | free(buf); | ||
121 | } | ||
122 | //fclose(fp); | ||
123 | fflush_stdout_and_exit(EXIT_SUCCESS); | ||
124 | } | ||
125 | |||
60 | int xxd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 126 | int xxd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
61 | int xxd_main(int argc UNUSED_PARAM, char **argv) | 127 | int xxd_main(int argc UNUSED_PARAM, char **argv) |
62 | { | 128 | { |
@@ -69,11 +135,7 @@ int xxd_main(int argc UNUSED_PARAM, char **argv) | |||
69 | 135 | ||
70 | dumper = alloc_dumper(); | 136 | dumper = alloc_dumper(); |
71 | 137 | ||
72 | #define OPT_l (1 << 0) | 138 | opt = getopt32(argv, "^" "l:s:aprg:+c:+" "\0" "?1" /* 1 argument max */, |
73 | #define OPT_s (1 << 1) | ||
74 | #define OPT_a (1 << 2) | ||
75 | #define OPT_p (1 << 3) | ||
76 | opt = getopt32(argv, "^" "l:s:apg:+c:+" "\0" "?1" /* 1 argument max */, | ||
77 | &opt_l, &opt_s, &bytes, &cols | 139 | &opt_l, &opt_s, &bytes, &cols |
78 | ); | 140 | ); |
79 | argv += optind; | 141 | argv += optind; |
@@ -107,6 +169,10 @@ int xxd_main(int argc UNUSED_PARAM, char **argv) | |||
107 | bb_dump_add(dumper, "\"%08.8_ax: \""); // "address: " | 169 | bb_dump_add(dumper, "\"%08.8_ax: \""); // "address: " |
108 | } | 170 | } |
109 | 171 | ||
172 | if (opt & OPT_r) { | ||
173 | reverse(opt, cols, argv[0]); | ||
174 | } | ||
175 | |||
110 | if (bytes < 1 || bytes >= cols) { | 176 | if (bytes < 1 || bytes >= cols) { |
111 | sprintf(buf, "%u/1 \"%%02x\"", cols); // cols * "xx" | 177 | sprintf(buf, "%u/1 \"%%02x\"", cols); // cols * "xx" |
112 | bb_dump_add(dumper, buf); | 178 | bb_dump_add(dumper, buf); |
@@ -141,6 +207,7 @@ int xxd_main(int argc UNUSED_PARAM, char **argv) | |||
141 | bb_dump_add(dumper, buf); | 207 | bb_dump_add(dumper, buf); |
142 | } else { | 208 | } else { |
143 | bb_dump_add(dumper, "\"\n\""); | 209 | bb_dump_add(dumper, "\"\n\""); |
210 | dumper->eofstring = "\n"; | ||
144 | } | 211 | } |
145 | 212 | ||
146 | return bb_dump_dump(dumper, argv); | 213 | return bb_dump_dump(dumper, argv); |
diff --git a/util-linux/losetup.c b/util-linux/losetup.c index ac8b79502..24f7a2349 100644 --- a/util-linux/losetup.c +++ b/util-linux/losetup.c | |||
@@ -150,7 +150,7 @@ int losetup_main(int argc UNUSED_PARAM, char **argv) | |||
150 | if (opt & OPT_P) { | 150 | if (opt & OPT_P) { |
151 | flags |= BB_LO_FLAGS_PARTSCAN; | 151 | flags |= BB_LO_FLAGS_PARTSCAN; |
152 | } | 152 | } |
153 | if (set_loop(&d, argv[0], offset, flags) < 0) | 153 | if (set_loop(&d, argv[0], offset, 0, flags) < 0) |
154 | bb_simple_perror_msg_and_die(argv[0]); | 154 | bb_simple_perror_msg_and_die(argv[0]); |
155 | return EXIT_SUCCESS; | 155 | return EXIT_SUCCESS; |
156 | } | 156 | } |
diff --git a/util-linux/lspci.c b/util-linux/lspci.c index 2f0b5fab9..c22cbcc1e 100644 --- a/util-linux/lspci.c +++ b/util-linux/lspci.c | |||
@@ -37,11 +37,9 @@ enum { | |||
37 | /* | 37 | /* |
38 | * PCI_SLOT_NAME PCI_CLASS: PCI_VID:PCI_DID [PCI_SUBSYS_VID:PCI_SUBSYS_DID] [DRIVER] | 38 | * PCI_SLOT_NAME PCI_CLASS: PCI_VID:PCI_DID [PCI_SUBSYS_VID:PCI_SUBSYS_DID] [DRIVER] |
39 | */ | 39 | */ |
40 | static int FAST_FUNC fileAction( | 40 | static int FAST_FUNC fileAction(struct recursive_state *state UNUSED_PARAM, |
41 | const char *fileName, | 41 | const char *fileName, |
42 | struct stat *statbuf UNUSED_PARAM, | 42 | struct stat *statbuf UNUSED_PARAM) |
43 | void *userData UNUSED_PARAM, | ||
44 | int depth UNUSED_PARAM) | ||
45 | { | 43 | { |
46 | parser_t *parser; | 44 | parser_t *parser; |
47 | char *tokens[3]; | 45 | char *tokens[3]; |
@@ -117,8 +115,7 @@ int lspci_main(int argc UNUSED_PARAM, char **argv) | |||
117 | ACTION_RECURSE, | 115 | ACTION_RECURSE, |
118 | fileAction, | 116 | fileAction, |
119 | NULL, /* dirAction */ | 117 | NULL, /* dirAction */ |
120 | NULL, /* userData */ | 118 | NULL /* userData */ |
121 | 0 /* depth */); | 119 | ); |
122 | |||
123 | return EXIT_SUCCESS; | 120 | return EXIT_SUCCESS; |
124 | } | 121 | } |
diff --git a/util-linux/lsusb.c b/util-linux/lsusb.c index 64a00eee2..9abb748ce 100644 --- a/util-linux/lsusb.c +++ b/util-linux/lsusb.c | |||
@@ -24,11 +24,9 @@ | |||
24 | 24 | ||
25 | #include "libbb.h" | 25 | #include "libbb.h" |
26 | 26 | ||
27 | static int FAST_FUNC fileAction( | 27 | static int FAST_FUNC fileAction(struct recursive_state *state UNUSED_PARAM, |
28 | const char *fileName, | 28 | const char *fileName, |
29 | struct stat *statbuf UNUSED_PARAM, | 29 | struct stat *statbuf UNUSED_PARAM) |
30 | void *userData UNUSED_PARAM, | ||
31 | int depth UNUSED_PARAM) | ||
32 | { | 30 | { |
33 | parser_t *parser; | 31 | parser_t *parser; |
34 | char *tokens[4]; | 32 | char *tokens[4]; |
@@ -80,8 +78,8 @@ int lsusb_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
80 | ACTION_RECURSE, | 78 | ACTION_RECURSE, |
81 | fileAction, | 79 | fileAction, |
82 | NULL, /* dirAction */ | 80 | NULL, /* dirAction */ |
83 | NULL, /* userData */ | 81 | NULL /* userData */ |
84 | 0 /* depth */); | 82 | ); |
85 | 83 | ||
86 | return EXIT_SUCCESS; | 84 | return EXIT_SUCCESS; |
87 | } | 85 | } |
diff --git a/util-linux/mdev.c b/util-linux/mdev.c index f42bebc20..59dbcf0cd 100644 --- a/util-linux/mdev.c +++ b/util-linux/mdev.c | |||
@@ -845,13 +845,12 @@ static ssize_t readlink2(char *buf, size_t bufsize) | |||
845 | /* File callback for /sys/ traversal. | 845 | /* File callback for /sys/ traversal. |
846 | * We act only on "/sys/.../dev" (pseudo)file | 846 | * We act only on "/sys/.../dev" (pseudo)file |
847 | */ | 847 | */ |
848 | static int FAST_FUNC fileAction(const char *fileName, | 848 | static int FAST_FUNC fileAction(struct recursive_state *state, |
849 | struct stat *statbuf UNUSED_PARAM, | 849 | const char *fileName, |
850 | void *userData, | 850 | struct stat *statbuf UNUSED_PARAM) |
851 | int depth UNUSED_PARAM) | ||
852 | { | 851 | { |
853 | size_t len = strlen(fileName) - 4; /* can't underflow */ | 852 | size_t len = strlen(fileName) - 4; /* can't underflow */ |
854 | char *path = userData; /* char array[PATH_MAX + SCRATCH_SIZE] */ | 853 | char *path = state->userData; /* char array[PATH_MAX + SCRATCH_SIZE] */ |
855 | char subsys[PATH_MAX]; | 854 | char subsys[PATH_MAX]; |
856 | int res; | 855 | int res; |
857 | 856 | ||
@@ -888,12 +887,11 @@ static int FAST_FUNC fileAction(const char *fileName, | |||
888 | } | 887 | } |
889 | 888 | ||
890 | /* Directory callback for /sys/ traversal */ | 889 | /* Directory callback for /sys/ traversal */ |
891 | static int FAST_FUNC dirAction(const char *fileName UNUSED_PARAM, | 890 | static int FAST_FUNC dirAction(struct recursive_state *state, |
892 | struct stat *statbuf UNUSED_PARAM, | 891 | const char *fileName UNUSED_PARAM, |
893 | void *userData UNUSED_PARAM, | 892 | struct stat *statbuf UNUSED_PARAM) |
894 | int depth) | ||
895 | { | 893 | { |
896 | return (depth >= MAX_SYSFS_DEPTH ? SKIP : TRUE); | 894 | return (state->depth >= MAX_SYSFS_DEPTH ? SKIP : TRUE); |
897 | } | 895 | } |
898 | 896 | ||
899 | /* For the full gory details, see linux/Documentation/firmware_class/README | 897 | /* For the full gory details, see linux/Documentation/firmware_class/README |
@@ -1149,7 +1147,7 @@ static void initial_scan(char *temp) | |||
1149 | /* Create all devices from /sys/dev hierarchy */ | 1147 | /* Create all devices from /sys/dev hierarchy */ |
1150 | recursive_action("/sys/dev", | 1148 | recursive_action("/sys/dev", |
1151 | ACTION_RECURSE | ACTION_FOLLOWLINKS, | 1149 | ACTION_RECURSE | ACTION_FOLLOWLINKS, |
1152 | fileAction, dirAction, temp, 0); | 1150 | fileAction, dirAction, temp); |
1153 | } | 1151 | } |
1154 | 1152 | ||
1155 | #if ENABLE_FEATURE_MDEV_DAEMON | 1153 | #if ENABLE_FEATURE_MDEV_DAEMON |
diff --git a/util-linux/mount.c b/util-linux/mount.c index b92e2c297..fc5161d7f 100644 --- a/util-linux/mount.c +++ b/util-linux/mount.c | |||
@@ -1230,6 +1230,7 @@ static NOINLINE int nfsmount(struct mntent *mp, unsigned long vfsflags, char *fi | |||
1230 | * then data pointer is interpreted as a string. */ | 1230 | * then data pointer is interpreted as a string. */ |
1231 | struct nfs_mount_data data; | 1231 | struct nfs_mount_data data; |
1232 | char *opt; | 1232 | char *opt; |
1233 | char *tokstate; | ||
1233 | struct hostent *hp; | 1234 | struct hostent *hp; |
1234 | struct sockaddr_in server_addr; | 1235 | struct sockaddr_in server_addr; |
1235 | struct sockaddr_in mount_server_addr; | 1236 | struct sockaddr_in mount_server_addr; |
@@ -1348,7 +1349,7 @@ static NOINLINE int nfsmount(struct mntent *mp, unsigned long vfsflags, char *fi | |||
1348 | nfsvers = 0; | 1349 | nfsvers = 0; |
1349 | 1350 | ||
1350 | /* parse options */ | 1351 | /* parse options */ |
1351 | if (filteropts) for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) { | 1352 | if (filteropts) for (opt = strtok_r(filteropts, ",", &tokstate); opt; opt = strtok_r(NULL, ",", &tokstate)) { |
1352 | char *opteq = strchr(opt, '='); | 1353 | char *opteq = strchr(opt, '='); |
1353 | if (opteq) { | 1354 | if (opteq) { |
1354 | int val, idx; | 1355 | int val, idx; |
@@ -1886,6 +1887,58 @@ static int nfsmount(struct mntent *mp, unsigned long vfsflags, char *filteropts) | |||
1886 | 1887 | ||
1887 | #endif // !ENABLE_FEATURE_MOUNT_NFS | 1888 | #endif // !ENABLE_FEATURE_MOUNT_NFS |
1888 | 1889 | ||
1890 | // Find "...,NAME=NUM,..." in the option string, remove "NAME=NUM" option | ||
1891 | // and return NUM. | ||
1892 | // Return 0 if not found. | ||
1893 | // All instances must be parsed and removed (for example, since kernel 5.4 | ||
1894 | // squashfs: Unknown parameter 'sizelimit' | ||
1895 | // will result if loopback mount option "sizelimit=NNN" is not removed | ||
1896 | // and squashfs sees it in option string). | ||
1897 | static unsigned long long cut_out_ull_opt(char *opts, const char *name_eq) | ||
1898 | { | ||
1899 | unsigned long long ret = 0; | ||
1900 | |||
1901 | if (!opts) // allow NULL opts (simplifies callers' work) | ||
1902 | return ret; | ||
1903 | |||
1904 | for (;;) { | ||
1905 | char *end; | ||
1906 | char *opt; | ||
1907 | |||
1908 | // Find comma-delimited "NAME=" | ||
1909 | for (;;) { | ||
1910 | opt = strstr(opts, name_eq); | ||
1911 | if (!opt) | ||
1912 | return ret; | ||
1913 | if (opt == opts) | ||
1914 | break; // found it (it's first opt) | ||
1915 | if (opt[-1] == ',') { | ||
1916 | opts = opt - 1; | ||
1917 | break; // found it (it's not a first opt) | ||
1918 | } | ||
1919 | // False positive like "VNAME=", we are at "N". | ||
1920 | // - skip it, loop back to searching | ||
1921 | opts = opt + 1; | ||
1922 | } | ||
1923 | |||
1924 | ret = bb_strtoull(opt + strlen(name_eq), &end, 0); | ||
1925 | if (errno && errno != EINVAL) { | ||
1926 | err: | ||
1927 | bb_error_msg_and_die("bad option '%s'", opt); | ||
1928 | } | ||
1929 | if (*end == '\0') { | ||
1930 | // It is "[,]NAME=NUM\0" - truncate it and return | ||
1931 | *opts = '\0'; | ||
1932 | return ret; | ||
1933 | } | ||
1934 | if (*end != ',') | ||
1935 | goto err; | ||
1936 | // We are at trailing comma | ||
1937 | // Remove "NAME=NUM," and loop back to check for duplicate opts | ||
1938 | overlapping_strcpy(opt, end + 1); | ||
1939 | } | ||
1940 | } | ||
1941 | |||
1889 | // Mount one directory. Handles CIFS, NFS, loopback, autobind, and filesystem | 1942 | // Mount one directory. Handles CIFS, NFS, loopback, autobind, and filesystem |
1890 | // type detection. Returns 0 for success, nonzero for failure. | 1943 | // type detection. Returns 0 for success, nonzero for failure. |
1891 | // NB: mp->xxx fields may be trashed on exit | 1944 | // NB: mp->xxx fields may be trashed on exit |
@@ -2029,9 +2082,16 @@ static int singlemount(struct mntent *mp, int ignore_busy) | |||
2029 | ) { | 2082 | ) { |
2030 | // Do we need to allocate a loopback device for it? | 2083 | // Do we need to allocate a loopback device for it? |
2031 | if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) { | 2084 | if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) { |
2085 | unsigned long long offset; | ||
2086 | unsigned long long sizelimit; | ||
2087 | |||
2032 | loopFile = bb_simplify_path(mp->mnt_fsname); | 2088 | loopFile = bb_simplify_path(mp->mnt_fsname); |
2033 | mp->mnt_fsname = NULL; // will receive malloced loop dev name | 2089 | mp->mnt_fsname = NULL; // will receive malloced loop dev name |
2034 | 2090 | ||
2091 | // Parse and remove loopback options | ||
2092 | offset = cut_out_ull_opt(filteropts, "offset="); | ||
2093 | sizelimit = cut_out_ull_opt(filteropts, "sizelimit="); | ||
2094 | |||
2035 | // mount always creates AUTOCLEARed loopdevs, so that umounting | 2095 | // mount always creates AUTOCLEARed loopdevs, so that umounting |
2036 | // drops them without any code in the userspace. | 2096 | // drops them without any code in the userspace. |
2037 | // This happens since circa linux-2.6.25: | 2097 | // This happens since circa linux-2.6.25: |
@@ -2040,7 +2100,8 @@ static int singlemount(struct mntent *mp, int ignore_busy) | |||
2040 | // Subject: Allow auto-destruction of loop devices | 2100 | // Subject: Allow auto-destruction of loop devices |
2041 | loopfd = set_loop(&mp->mnt_fsname, | 2101 | loopfd = set_loop(&mp->mnt_fsname, |
2042 | loopFile, | 2102 | loopFile, |
2043 | 0, | 2103 | offset, |
2104 | sizelimit, | ||
2044 | ((vfsflags & MS_RDONLY) ? BB_LO_FLAGS_READ_ONLY : 0) | 2105 | ((vfsflags & MS_RDONLY) ? BB_LO_FLAGS_READ_ONLY : 0) |
2045 | | BB_LO_FLAGS_AUTOCLEAR | 2106 | | BB_LO_FLAGS_AUTOCLEAR |
2046 | ); | 2107 | ); |
diff --git a/util-linux/setpriv.c b/util-linux/setpriv.c index 37e8821a1..1e4b201ed 100644 --- a/util-linux/setpriv.c +++ b/util-linux/setpriv.c | |||
@@ -144,10 +144,11 @@ static unsigned parse_cap(const char *cap) | |||
144 | static void set_inh_caps(char *capstring) | 144 | static void set_inh_caps(char *capstring) |
145 | { | 145 | { |
146 | struct caps caps; | 146 | struct caps caps; |
147 | char *string; | ||
147 | 148 | ||
148 | getcaps(&caps); | 149 | getcaps(&caps); |
149 | 150 | ||
150 | capstring = strtok(capstring, ","); | 151 | capstring = strtok_r(capstring, ",", &string); |
151 | while (capstring) { | 152 | while (capstring) { |
152 | unsigned cap; | 153 | unsigned cap; |
153 | 154 | ||
@@ -159,7 +160,7 @@ static void set_inh_caps(char *capstring) | |||
159 | caps.data[CAP_TO_INDEX(cap)].inheritable |= CAP_TO_MASK(cap); | 160 | caps.data[CAP_TO_INDEX(cap)].inheritable |= CAP_TO_MASK(cap); |
160 | else | 161 | else |
161 | caps.data[CAP_TO_INDEX(cap)].inheritable &= ~CAP_TO_MASK(cap); | 162 | caps.data[CAP_TO_INDEX(cap)].inheritable &= ~CAP_TO_MASK(cap); |
162 | capstring = strtok(NULL, ","); | 163 | capstring = strtok_r(NULL, ",", &string); |
163 | } | 164 | } |
164 | 165 | ||
165 | if (capset(&caps.header, caps.data) != 0) | 166 | if (capset(&caps.header, caps.data) != 0) |
@@ -170,7 +171,7 @@ static void set_ambient_caps(char *string) | |||
170 | { | 171 | { |
171 | char *cap; | 172 | char *cap; |
172 | 173 | ||
173 | cap = strtok(string, ","); | 174 | cap = strtok_r(string, ",", &string); |
174 | while (cap) { | 175 | while (cap) { |
175 | unsigned idx; | 176 | unsigned idx; |
176 | 177 | ||
@@ -182,7 +183,7 @@ static void set_ambient_caps(char *string) | |||
182 | if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_LOWER, idx, 0, 0) < 0) | 183 | if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_LOWER, idx, 0, 0) < 0) |
183 | bb_simple_perror_msg("cap_ambient_lower"); | 184 | bb_simple_perror_msg("cap_ambient_lower"); |
184 | } | 185 | } |
185 | cap = strtok(NULL, ","); | 186 | cap = strtok_r(NULL, ",", &string); |
186 | } | 187 | } |
187 | } | 188 | } |
188 | #endif /* FEATURE_SETPRIV_CAPABILITIES */ | 189 | #endif /* FEATURE_SETPRIV_CAPABILITIES */ |
diff --git a/util-linux/switch_root.c b/util-linux/switch_root.c index c65096c27..f2674b5ac 100644 --- a/util-linux/switch_root.c +++ b/util-linux/switch_root.c | |||
@@ -164,7 +164,7 @@ static void drop_capabilities(char *string) | |||
164 | { | 164 | { |
165 | char *cap; | 165 | char *cap; |
166 | 166 | ||
167 | cap = strtok(string, ","); | 167 | cap = strtok_r(string, ",", &string); |
168 | while (cap) { | 168 | while (cap) { |
169 | unsigned cap_idx; | 169 | unsigned cap_idx; |
170 | 170 | ||
@@ -174,7 +174,7 @@ static void drop_capabilities(char *string) | |||
174 | drop_bounding_set(cap_idx); | 174 | drop_bounding_set(cap_idx); |
175 | drop_capset(cap_idx); | 175 | drop_capset(cap_idx); |
176 | bb_error_msg("dropped capability: %s", cap); | 176 | bb_error_msg("dropped capability: %s", cap); |
177 | cap = strtok(NULL, ","); | 177 | cap = strtok_r(NULL, ",", &string); |
178 | } | 178 | } |
179 | } | 179 | } |
180 | #endif | 180 | #endif |
diff --git a/util-linux/volume_id/get_devname.c b/util-linux/volume_id/get_devname.c index 34f5d119f..00cfb2826 100644 --- a/util-linux/volume_id/get_devname.c +++ b/util-linux/volume_id/get_devname.c | |||
@@ -102,10 +102,9 @@ uuidcache_addentry(char *device, /*int major, int minor,*/ char *label, char *uu | |||
102 | * add a cache entry for this device. | 102 | * add a cache entry for this device. |
103 | * If device node does not exist, it will be temporarily created. */ | 103 | * If device node does not exist, it will be temporarily created. */ |
104 | static int FAST_FUNC | 104 | static int FAST_FUNC |
105 | uuidcache_check_device(const char *device, | 105 | uuidcache_check_device(struct recursive_state *state UNUSED_PARAM, |
106 | struct stat *statbuf, | 106 | const char *device, |
107 | void *userData UNUSED_PARAM, | 107 | struct stat *statbuf) |
108 | int depth UNUSED_PARAM) | ||
109 | { | 108 | { |
110 | /* note: this check rejects links to devices, among other nodes */ | 109 | /* note: this check rejects links to devices, among other nodes */ |
111 | if (!S_ISBLK(statbuf->st_mode) | 110 | if (!S_ISBLK(statbuf->st_mode) |
@@ -145,12 +144,13 @@ uuidcache_init(int scan_devices) | |||
145 | * This is unacceptably complex. Let's just scan /dev. | 144 | * This is unacceptably complex. Let's just scan /dev. |
146 | * (Maybe add scanning of /sys/block/XXX/dev for devices | 145 | * (Maybe add scanning of /sys/block/XXX/dev for devices |
147 | * somehow not having their /dev/XXX entries created?) */ | 146 | * somehow not having their /dev/XXX entries created?) */ |
148 | if (scan_devices) | 147 | if (scan_devices) { |
149 | recursive_action("/dev", ACTION_RECURSE, | 148 | recursive_action("/dev", ACTION_RECURSE, |
150 | uuidcache_check_device, /* file_action */ | 149 | uuidcache_check_device, /* file_action */ |
151 | NULL, /* dir_action */ | 150 | NULL, /* dir_action */ |
152 | NULL, /* userData */ | 151 | NULL /* userData */ |
153 | 0 /* depth */); | 152 | ); |
153 | } | ||
154 | 154 | ||
155 | return uuidCache; | 155 | return uuidCache; |
156 | } | 156 | } |