diff options
52 files changed, 1265 insertions, 736 deletions
diff --git a/Makefile.custom b/Makefile.custom index e2f6d1c2f..36170de8a 100644 --- a/Makefile.custom +++ b/Makefile.custom | |||
@@ -156,12 +156,12 @@ docs/busybox.pod: $(srctree)/docs/busybox_header.pod \ | |||
156 | docs/BusyBox.txt: docs/busybox.pod | 156 | docs/BusyBox.txt: docs/busybox.pod |
157 | $(disp_doc) | 157 | $(disp_doc) |
158 | $(Q)-mkdir -p docs | 158 | $(Q)-mkdir -p docs |
159 | $(Q)-pod2text $< > $@ | 159 | $(Q)-pod2text --quotes=none $< > $@ |
160 | 160 | ||
161 | docs/busybox.1: docs/busybox.pod | 161 | docs/busybox.1: docs/busybox.pod |
162 | $(disp_doc) | 162 | $(disp_doc) |
163 | $(Q)-mkdir -p docs | 163 | $(Q)-mkdir -p docs |
164 | $(Q)-pod2man --center=busybox --release="version $(KERNELVERSION)" $< > $@ | 164 | $(Q)-pod2man --quotes=none --center=busybox --release="version $(KERNELVERSION)" $< > $@ |
165 | 165 | ||
166 | docs/BusyBox.html: docs/busybox.net/BusyBox.html | 166 | docs/BusyBox.html: docs/busybox.net/BusyBox.html |
167 | $(disp_doc) | 167 | $(disp_doc) |
diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 055f9fb24..a000de45b 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst | |||
@@ -336,6 +336,7 @@ setuidgid - noexec. spawner | |||
336 | sha1sum - noexec. runner | 336 | sha1sum - noexec. runner |
337 | sha256sum - noexec. runner | 337 | sha256sum - noexec. runner |
338 | sha3sum - noexec. runner | 338 | sha3sum - noexec. runner |
339 | sha384sum - noexec. runner | ||
339 | sha512sum - noexec. runner | 340 | sha512sum - noexec. runner |
340 | showkey - interactive, longterm | 341 | showkey - interactive, longterm |
341 | shred - runner | 342 | shred - runner |
diff --git a/applets/usage_pod.c b/applets/usage_pod.c index 9e6d3f0ee..2c177be90 100644 --- a/applets/usage_pod.c +++ b/applets/usage_pod.c | |||
@@ -67,30 +67,37 @@ int main(void) | |||
67 | } | 67 | } |
68 | if (col == 0) { | 68 | if (col == 0) { |
69 | col = 6; | 69 | col = 6; |
70 | printf("\t"); | ||
71 | } else { | 70 | } else { |
72 | printf(", "); | 71 | printf(", "); |
73 | } | 72 | } |
74 | printf("%s", usage_array[i].aname); | 73 | if (usage_array[i].usage[0] != NOUSAGE_STR[0]) { |
74 | /* | ||
75 | * If the applet usage string will be included in the final document | ||
76 | * optimistically link to its header (which is just the applet name). | ||
77 | */ | ||
78 | printf("L<C<%1$s>|/\"%1$s\">", usage_array[i].aname); | ||
79 | } else { | ||
80 | /* Without a usage string, just output the applet name with no link. */ | ||
81 | printf("C<%s>", usage_array[i].aname); | ||
82 | } | ||
75 | col += len2; | 83 | col += len2; |
76 | } | 84 | } |
77 | printf("\n\n"); | 85 | printf("\n\n"); |
78 | 86 | ||
79 | printf("=head1 COMMAND DESCRIPTIONS\n\n"); | 87 | printf("=head1 COMMAND DESCRIPTIONS\n\n"); |
80 | printf("=over 4\n\n"); | ||
81 | 88 | ||
82 | for (i = 0; i < num_messages; i++) { | 89 | for (i = 0; i < num_messages; i++) { |
83 | if (usage_array[i].aname[0] >= 'a' && usage_array[i].aname[0] <= 'z' | 90 | if (usage_array[i].aname[0] >= 'a' && usage_array[i].aname[0] <= 'z' |
84 | && usage_array[i].usage[0] != NOUSAGE_STR[0] | 91 | && usage_array[i].usage[0] != NOUSAGE_STR[0] |
85 | ) { | 92 | ) { |
86 | printf("=item B<%s>\n\n", usage_array[i].aname); | 93 | /* This is the heading that will be linked from the command list. */ |
94 | printf("=head2 %s\n\n", usage_array[i].aname); | ||
87 | if (usage_array[i].usage[0]) | 95 | if (usage_array[i].usage[0]) |
88 | printf("%s %s\n\n", usage_array[i].aname, usage_array[i].usage); | 96 | printf("%s %s\n\n", usage_array[i].aname, usage_array[i].usage); |
89 | else | 97 | else |
90 | printf("%s\n\n", usage_array[i].aname); | 98 | printf("%s\n\n", usage_array[i].aname); |
91 | } | 99 | } |
92 | } | 100 | } |
93 | printf("=back\n\n"); | ||
94 | 101 | ||
95 | return 0; | 102 | return 0; |
96 | } | 103 | } |
diff --git a/configs/mingw64a_defconfig b/configs/mingw64a_defconfig index f23dab438..d17737721 100644 --- a/configs/mingw64a_defconfig +++ b/configs/mingw64a_defconfig | |||
@@ -121,7 +121,7 @@ CONFIG_FEATURE_BUFFERS_USE_MALLOC=y | |||
121 | # CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set | 121 | # CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set |
122 | # CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set | 122 | # CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set |
123 | CONFIG_PASSWORD_MINLEN=6 | 123 | CONFIG_PASSWORD_MINLEN=6 |
124 | # CONFIG_FEATURE_USE_CNG_API is not set | 124 | CONFIG_FEATURE_USE_CNG_API=y |
125 | CONFIG_MD5_SMALL=1 | 125 | CONFIG_MD5_SMALL=1 |
126 | CONFIG_SHA1_SMALL=3 | 126 | CONFIG_SHA1_SMALL=3 |
127 | # CONFIG_SHA1_HWACCEL is not set | 127 | # CONFIG_SHA1_HWACCEL is not set |
diff --git a/coreutils/date.c b/coreutils/date.c index 3a89b6caf..ef482af1b 100644 --- a/coreutils/date.c +++ b/coreutils/date.c | |||
@@ -289,7 +289,7 @@ int date_main(int argc UNUSED_PARAM, char **argv) | |||
289 | 289 | ||
290 | /* if setting time, set it */ | 290 | /* if setting time, set it */ |
291 | if ((opt & OPT_SET) && clock_settime(CLOCK_REALTIME, &ts) < 0) { | 291 | if ((opt & OPT_SET) && clock_settime(CLOCK_REALTIME, &ts) < 0) { |
292 | bb_simple_perror_msg("can't set date"); | 292 | bb_simple_perror_msg_and_die("can't set date"); |
293 | } | 293 | } |
294 | } | 294 | } |
295 | 295 | ||
diff --git a/coreutils/ls.c b/coreutils/ls.c index 5d2e96a1e..2153554e8 100644 --- a/coreutils/ls.c +++ b/coreutils/ls.c | |||
@@ -129,6 +129,8 @@ | |||
129 | //usage: "\n -F Append indicator (one of */=@|) to names" | 129 | //usage: "\n -F Append indicator (one of */=@|) to names" |
130 | //usage: ) | 130 | //usage: ) |
131 | //usage: "\n -l Long format" | 131 | //usage: "\n -l Long format" |
132 | ////usage: "\n -g Long format without group column" | ||
133 | ////TODO: support -G too ("suppress owner column", GNUism) | ||
132 | //usage: "\n -i List inode numbers" | 134 | //usage: "\n -i List inode numbers" |
133 | //usage: "\n -n List numeric UIDs and GIDs instead of names" | 135 | //usage: "\n -n List numeric UIDs and GIDs instead of names" |
134 | //usage: "\n -s List allocated blocks" | 136 | //usage: "\n -s List allocated blocks" |
@@ -162,6 +164,8 @@ | |||
162 | //usage: IF_FEATURE_LS_WIDTH( | 164 | //usage: IF_FEATURE_LS_WIDTH( |
163 | //usage: "\n -w N Format N columns wide" | 165 | //usage: "\n -w N Format N columns wide" |
164 | //usage: ) | 166 | //usage: ) |
167 | ////usage: "\n -Q Double-quote names" | ||
168 | ////usage: "\n -q Replace unprintable chars with '?'" | ||
165 | //usage: IF_FEATURE_LS_COLOR( | 169 | //usage: IF_FEATURE_LS_COLOR( |
166 | //usage: "\n --color[={always,never,auto}]" | 170 | //usage: "\n --color[={always,never,auto}]" |
167 | //usage: ) | 171 | //usage: ) |
@@ -199,27 +203,47 @@ SPLIT_SUBDIR = 2, | |||
199 | 203 | ||
200 | /* -Cadi1l Std options, busybox always supports */ | 204 | /* -Cadi1l Std options, busybox always supports */ |
201 | /* -gnsxA Std options, busybox always supports */ | 205 | /* -gnsxA Std options, busybox always supports */ |
202 | /* -Q GNU option, busybox always supports */ | 206 | /* -Q GNU option, busybox always supports: */ |
203 | /* -k Std option, busybox always supports (by ignoring) */ | 207 | /* -Q, --quote-name */ |
204 | /* It means "for -s, show sizes in kbytes" */ | 208 | /* enclose entry names in double quotes */ |
205 | /* Seems to only affect "POSIXLY_CORRECT=1 ls -sk" */ | ||
206 | /* since otherwise -s shows kbytes anyway */ | ||
207 | /* -LHRctur Std options, busybox optionally supports */ | 209 | /* -LHRctur Std options, busybox optionally supports */ |
208 | /* -Fp Std options, busybox optionally supports */ | 210 | /* -Fp Std options, busybox optionally supports */ |
209 | /* -SXvhTw GNU options, busybox optionally supports */ | 211 | /* -SXvhTw GNU options, busybox optionally supports */ |
210 | /* -T WIDTH Ignored (we don't use tabs on output) */ | 212 | /* -T WIDTH Ignored (we don't use tabs on output) */ |
211 | /* -Z SELinux mandated option, busybox optionally supports */ | 213 | /* -Z SELinux mandated option, busybox optionally supports */ |
214 | /* -q Std option, busybox always supports: */ | ||
215 | /* https://pubs.opengroup.org/onlinepubs/9699919799/utilities/ls.html: */ | ||
216 | /* Force each instance of non-printable filename characters and */ | ||
217 | /* <tab> characters to be written as the <question-mark> ('?') */ | ||
218 | /* character. Implementations may provide this option by default */ | ||
219 | /* if the output is to a terminal device. */ | ||
220 | /* -k Std option, busybox always supports (by ignoring) */ | ||
221 | /* It means "for -s, show sizes in kbytes" */ | ||
222 | /* Seems to only affect "POSIXLY_CORRECT=1 ls -sk" */ | ||
223 | /* since otherwise -s shows kbytes anyway */ | ||
212 | #define ls_options \ | 224 | #define ls_options \ |
213 | "Cadi1lgnsxAk" /* 12 opts, total 12 */ \ | 225 | "Cadi1lgnsxA" /* 11 opts, total 11 */ \ |
214 | IF_FEATURE_LS_FILETYPES("Fp") /* 2, 14 */ \ | 226 | IF_FEATURE_LS_FILETYPES("Fp") /* 2, 13 */ \ |
215 | IF_FEATURE_LS_RECURSIVE("R") /* 1, 15 */ \ | 227 | IF_FEATURE_LS_RECURSIVE("R") /* 1, 14 */ \ |
216 | IF_SELINUX("Z") /* 1, 16 */ \ | 228 | IF_SELINUX("Z") /* 1, 15 */ \ |
217 | "Q" /* 1, 17 */ \ | 229 | "Q" /* 1, 16 */ \ |
218 | IF_FEATURE_LS_TIMESTAMPS("ctu") /* 3, 20 */ \ | 230 | IF_FEATURE_LS_TIMESTAMPS("ctu") /* 3, 19 */ \ |
219 | IF_FEATURE_LS_SORTFILES("SXrv") /* 4, 24 */ \ | 231 | IF_FEATURE_LS_SORTFILES("SXrv") /* 4, 23 */ \ |
220 | IF_FEATURE_LS_FOLLOWLINKS("LH") /* 2, 26 */ \ | 232 | IF_FEATURE_LS_FOLLOWLINKS("LH") /* 2, 25 */ \ |
221 | IF_FEATURE_HUMAN_READABLE("h") /* 1, 27 */ \ | 233 | IF_FEATURE_HUMAN_READABLE("h") /* 1, 26 */ \ |
222 | IF_FEATURE_LS_WIDTH("T:w:") /* 2, 29 */ | 234 | IF_FEATURE_LS_WIDTH("T:w:") /* 2, 28 */ \ |
235 | IF_LONG_OPTS("\xff") /* 1, 29 */ \ | ||
236 | IF_LONG_OPTS("\xfe") /* 1, 30 */ \ | ||
237 | IF_LONG_OPTS("\xfd") /* 1, 31 */ \ | ||
238 | "qk" /* 2, 33 */ | ||
239 | |||
240 | #if ENABLE_LONG_OPTS | ||
241 | static const char ls_longopts[] ALIGN1 = | ||
242 | "full-time\0" No_argument "\xff" | ||
243 | "group-directories-first\0" No_argument "\xfe" | ||
244 | IF_FEATURE_LS_COLOR("color\0" Optional_argument "\xfd") | ||
245 | ; | ||
246 | #endif | ||
223 | 247 | ||
224 | enum { | 248 | enum { |
225 | OPT_C = (1 << 0), | 249 | OPT_C = (1 << 0), |
@@ -233,29 +257,31 @@ enum { | |||
233 | OPT_s = (1 << 8), | 257 | OPT_s = (1 << 8), |
234 | OPT_x = (1 << 9), | 258 | OPT_x = (1 << 9), |
235 | OPT_A = (1 << 10), | 259 | OPT_A = (1 << 10), |
236 | //OPT_k = (1 << 11), | ||
237 | 260 | ||
238 | OPTBIT_F = 12, | 261 | OPTBIT_F = 11, |
239 | OPTBIT_p, /* 13 */ | 262 | OPTBIT_p, /* 12 */ |
240 | OPTBIT_R = OPTBIT_F + 2 * ENABLE_FEATURE_LS_FILETYPES, | 263 | OPTBIT_R = OPTBIT_F + 2 * ENABLE_FEATURE_LS_FILETYPES, |
241 | OPTBIT_Z = OPTBIT_R + 1 * ENABLE_FEATURE_LS_RECURSIVE, | 264 | OPTBIT_Z = OPTBIT_R + 1 * ENABLE_FEATURE_LS_RECURSIVE, |
242 | OPTBIT_Q = OPTBIT_Z + 1 * ENABLE_SELINUX, | 265 | OPTBIT_Q = OPTBIT_Z + 1 * ENABLE_SELINUX, |
243 | OPTBIT_c, /* 17 */ | 266 | OPTBIT_c, /* 16 */ |
244 | OPTBIT_t, /* 18 */ | 267 | OPTBIT_t, /* 17 */ |
245 | OPTBIT_u, /* 19 */ | 268 | OPTBIT_u, /* 18 */ |
246 | OPTBIT_S = OPTBIT_c + 3 * ENABLE_FEATURE_LS_TIMESTAMPS, | 269 | OPTBIT_S = OPTBIT_c + 3 * ENABLE_FEATURE_LS_TIMESTAMPS, |
247 | OPTBIT_X, /* 21 */ | 270 | OPTBIT_X, /* 20 */ |
248 | OPTBIT_r, /* 22 */ | 271 | OPTBIT_r, /* 21 */ |
249 | OPTBIT_v, /* 23 */ | 272 | OPTBIT_v, /* 22 */ |
250 | OPTBIT_L = OPTBIT_S + 4 * ENABLE_FEATURE_LS_SORTFILES, | 273 | OPTBIT_L = OPTBIT_S + 4 * ENABLE_FEATURE_LS_SORTFILES, |
251 | OPTBIT_H, /* 25 */ | 274 | OPTBIT_H, /* 24 */ |
252 | OPTBIT_h = OPTBIT_L + 2 * ENABLE_FEATURE_LS_FOLLOWLINKS, | 275 | OPTBIT_h = OPTBIT_L + 2 * ENABLE_FEATURE_LS_FOLLOWLINKS, |
253 | OPTBIT_T = OPTBIT_h + 1 * ENABLE_FEATURE_HUMAN_READABLE, | 276 | OPTBIT_T = OPTBIT_h + 1 * ENABLE_FEATURE_HUMAN_READABLE, |
254 | OPTBIT_w, /* 28 */ | 277 | OPTBIT_w, /* 27 */ |
255 | OPTBIT_full_time = OPTBIT_T + 2 * ENABLE_FEATURE_LS_WIDTH, | 278 | OPTBIT_full_time = OPTBIT_T + 2 * ENABLE_FEATURE_LS_WIDTH, |
256 | OPTBIT_dirs_first, | 279 | OPTBIT_dirs_first, |
257 | OPTBIT_color, /* 31 */ | 280 | OPTBIT_color, /* 30 */ |
258 | /* with long opts, we use all 32 bits */ | 281 | OPTBIT_q = OPTBIT_color + 1, /* 31 */ |
282 | OPTBIT_k = OPTBIT_q + 1, /* 32 */ | ||
283 | /* with all options enabled, we use all 32 bits and even one extra bit! */ | ||
284 | /* this works because -k is ignored, and getopt32 allows such "ignore" options past 31th bit */ | ||
259 | 285 | ||
260 | OPT_F = (1 << OPTBIT_F) * ENABLE_FEATURE_LS_FILETYPES, | 286 | OPT_F = (1 << OPTBIT_F) * ENABLE_FEATURE_LS_FILETYPES, |
261 | OPT_p = (1 << OPTBIT_p) * ENABLE_FEATURE_LS_FILETYPES, | 287 | OPT_p = (1 << OPTBIT_p) * ENABLE_FEATURE_LS_FILETYPES, |
@@ -277,6 +303,8 @@ enum { | |||
277 | OPT_full_time = (1 << OPTBIT_full_time ) * ENABLE_LONG_OPTS, | 303 | OPT_full_time = (1 << OPTBIT_full_time ) * ENABLE_LONG_OPTS, |
278 | OPT_dirs_first = (1 << OPTBIT_dirs_first) * ENABLE_LONG_OPTS, | 304 | OPT_dirs_first = (1 << OPTBIT_dirs_first) * ENABLE_LONG_OPTS, |
279 | OPT_color = (1 << OPTBIT_color ) * ENABLE_FEATURE_LS_COLOR, | 305 | OPT_color = (1 << OPTBIT_color ) * ENABLE_FEATURE_LS_COLOR, |
306 | OPT_q = (1 << OPTBIT_q), | ||
307 | //-k is ignored: OPT_k = (1 << OPTBIT_k), | ||
280 | }; | 308 | }; |
281 | 309 | ||
282 | /* | 310 | /* |
@@ -333,6 +361,7 @@ struct globals { | |||
333 | #endif | 361 | #endif |
334 | smallint exit_code; | 362 | smallint exit_code; |
335 | smallint show_dirname; | 363 | smallint show_dirname; |
364 | smallint tty_out; | ||
336 | #if ENABLE_FEATURE_LS_WIDTH | 365 | #if ENABLE_FEATURE_LS_WIDTH |
337 | unsigned terminal_width; | 366 | unsigned terminal_width; |
338 | # define G_terminal_width (G.terminal_width) | 367 | # define G_terminal_width (G.terminal_width) |
@@ -353,16 +382,21 @@ struct globals { | |||
353 | setup_common_bufsiz(); \ | 382 | setup_common_bufsiz(); \ |
354 | /* we have to zero it out because of NOEXEC */ \ | 383 | /* we have to zero it out because of NOEXEC */ \ |
355 | memset(&G, 0, sizeof(G)); \ | 384 | memset(&G, 0, sizeof(G)); \ |
356 | IF_FEATURE_LS_WIDTH(G_terminal_width = TERMINAL_WIDTH;) \ | 385 | IF_FEATURE_LS_WIDTH(G_terminal_width = ~0U;) \ |
357 | IF_FEATURE_LS_TIMESTAMPS(time(&G.current_time_t);) \ | 386 | IF_FEATURE_LS_TIMESTAMPS(time(&G.current_time_t);) \ |
358 | } while (0) | 387 | } while (0) |
359 | 388 | ||
360 | #define ESC "\033" | 389 | #define ESC "\033" |
361 | 390 | ||
391 | static int G_isatty(void) | ||
392 | { | ||
393 | if (!G.tty_out) /* not known yet? */ | ||
394 | G.tty_out = isatty(STDOUT_FILENO) + 1; | ||
395 | return (G.tty_out == 2); | ||
396 | } | ||
362 | 397 | ||
363 | /*** Output code ***/ | 398 | /*** Output code ***/ |
364 | 399 | ||
365 | |||
366 | /* FYI type values: 1:fifo 2:char 4:dir 6:blk 8:file 10:link 12:socket | 400 | /* FYI type values: 1:fifo 2:char 4:dir 6:blk 8:file 10:link 12:socket |
367 | * (various wacky OSes: 13:Sun door 14:BSD whiteout 5:XENIX named file | 401 | * (various wacky OSes: 13:Sun door 14:BSD whiteout 5:XENIX named file |
368 | * 3/7:multiplexed char/block device) | 402 | * 3/7:multiplexed char/block device) |
@@ -425,56 +459,93 @@ static char append_char(mode_t mode) | |||
425 | } | 459 | } |
426 | #endif | 460 | #endif |
427 | 461 | ||
462 | /* Return the number of used columns. | ||
463 | * Note that only columnar output uses return value. | ||
464 | * -l and -1 modes don't care. | ||
465 | * coreutils 7.2 also supports: | ||
466 | * ls -b (--escape) = octal escapes (although it doesn't look like working) | ||
467 | * ls -N (--literal) = not escape at all | ||
468 | */ | ||
428 | static unsigned calc_name_len(const char *name) | 469 | static unsigned calc_name_len(const char *name) |
429 | { | 470 | { |
430 | unsigned len; | 471 | unsigned len; |
431 | uni_stat_t uni_stat; | 472 | uni_stat_t uni_stat; |
432 | 473 | ||
433 | // TODO: quote tab as \t, etc, if -Q | 474 | if (!(option_mask32 & (OPT_q|OPT_Q))) |
434 | name = printable_string2(&uni_stat, name); | 475 | return strlen(name); |
435 | 476 | ||
436 | if (!(option_mask32 & OPT_Q)) { | 477 | if (!(option_mask32 & OPT_Q)) { |
478 | /* the most likely branch: "ls" to tty (it auto-enables -q behavior) */ | ||
479 | printable_string2(&uni_stat, name); | ||
437 | return uni_stat.unicode_width; | 480 | return uni_stat.unicode_width; |
438 | } | 481 | } |
439 | 482 | ||
440 | len = 2 + uni_stat.unicode_width; | 483 | len = 2 + strlen(name); |
441 | while (*name) { | 484 | while (*name) { |
485 | unsigned char ch = (unsigned char)*name; | ||
486 | if (ch < ' ' || ch > 0x7e) { | ||
487 | ch -= 7; | ||
488 | if (ch <= 6) { | ||
489 | /* quote chars 7..13 as \a,b,t,n,v,f,r */ | ||
490 | goto two; | ||
491 | } | ||
492 | /* other chars <32 or >126 as \ooo octal */ | ||
493 | len += 3; | ||
494 | goto next; | ||
495 | } | ||
442 | if (*name == '"' || *name == '\\') { | 496 | if (*name == '"' || *name == '\\') { |
497 | two: | ||
443 | len++; | 498 | len++; |
444 | } | 499 | } |
500 | next: | ||
445 | name++; | 501 | name++; |
446 | } | 502 | } |
447 | return len; | 503 | return len; |
448 | } | 504 | } |
449 | |||
450 | /* Return the number of used columns. | ||
451 | * Note that only columnar output uses return value. | ||
452 | * -l and -1 modes don't care. | ||
453 | * coreutils 7.2 also supports: | ||
454 | * ls -b (--escape) = octal escapes (although it doesn't look like working) | ||
455 | * ls -N (--literal) = not escape at all | ||
456 | */ | ||
457 | static unsigned print_name(const char *name) | 505 | static unsigned print_name(const char *name) |
458 | { | 506 | { |
459 | unsigned len; | 507 | unsigned len; |
460 | uni_stat_t uni_stat; | 508 | uni_stat_t uni_stat; |
461 | 509 | ||
462 | // TODO: quote tab as \t, etc, if -Q | 510 | if (!(option_mask32 & (OPT_q|OPT_Q))) { |
463 | name = printable_string2(&uni_stat, name); | 511 | fputs_stdout(name); |
512 | return strlen(name); | ||
513 | } | ||
464 | 514 | ||
465 | if (!(option_mask32 & OPT_Q)) { | 515 | if (!(option_mask32 & OPT_Q)) { |
516 | /* the most likely branch: "ls" to tty (it auto-enables -q behavior) */ | ||
517 | name = printable_string2(&uni_stat, name); | ||
466 | fputs_stdout(name); | 518 | fputs_stdout(name); |
467 | return uni_stat.unicode_width; | 519 | return uni_stat.unicode_width; |
468 | } | 520 | } |
469 | 521 | ||
470 | len = 2 + uni_stat.unicode_width; | 522 | len = 2 + strlen(name); |
471 | putchar('"'); | 523 | putchar('"'); |
472 | while (*name) { | 524 | while (*name) { |
473 | if (*name == '"' || *name == '\\') { | 525 | unsigned char ch = (unsigned char)*name; |
526 | if (ch < ' ' || ch > 0x7e) { | ||
474 | putchar('\\'); | 527 | putchar('\\'); |
528 | ch -= 7; | ||
529 | if (ch <= 6) { | ||
530 | /* quote chars 7..13 as \a,b,t,n,v,f,r */ | ||
531 | ch = c_escape_conv_str07[1 + 3 * ch]; | ||
532 | goto two; | ||
533 | } | ||
534 | /* other chars <32 or >126 as \ooo octal */ | ||
535 | ch = (unsigned char)*name; | ||
536 | putchar('0' + (ch>>6)); | ||
537 | putchar('0' + ((ch>>3) & 7)); | ||
538 | ch = '0' + (ch & 7); | ||
539 | len += 3; | ||
540 | goto put_ch; | ||
541 | } | ||
542 | if (ch == '"' || ch == '\\') { | ||
543 | putchar('\\'); | ||
544 | two: | ||
475 | len++; | 545 | len++; |
476 | } | 546 | } |
477 | putchar(*name); | 547 | put_ch: |
548 | putchar(ch); | ||
478 | name++; | 549 | name++; |
479 | } | 550 | } |
480 | putchar('"'); | 551 | putchar('"'); |
@@ -660,7 +731,7 @@ static void display_files(struct dnode **dn, unsigned nfiles) | |||
660 | unsigned i, ncols, nrows, row, nc; | 731 | unsigned i, ncols, nrows, row, nc; |
661 | unsigned column; | 732 | unsigned column; |
662 | unsigned nexttab; | 733 | unsigned nexttab; |
663 | unsigned column_width = 0; /* used only by coulmnal output */ | 734 | unsigned column_width = 0; /* used only by columnar output */ |
664 | 735 | ||
665 | if (option_mask32 & (OPT_l|OPT_1)) { | 736 | if (option_mask32 & (OPT_l|OPT_1)) { |
666 | ncols = 1; | 737 | ncols = 1; |
@@ -709,6 +780,11 @@ static void display_files(struct dnode **dn, unsigned nfiles) | |||
709 | } | 780 | } |
710 | nexttab = column + column_width; | 781 | nexttab = column + column_width; |
711 | column += display_single(dn[i]); | 782 | column += display_single(dn[i]); |
783 | } else { | ||
784 | /* if -w999999999, ncols can be very large */ | ||
785 | //bb_error_msg(" col:%u ncol:%u i:%i", nc, ncols, i); sleep1(); | ||
786 | /* without "break", we loop millions of times here */ | ||
787 | break; | ||
712 | } | 788 | } |
713 | } | 789 | } |
714 | putchar('\n'); | 790 | putchar('\n'); |
@@ -1155,25 +1231,11 @@ int ls_main(int argc UNUSED_PARAM, char **argv) | |||
1155 | /* need to initialize since --color has _an optional_ argument */ | 1231 | /* need to initialize since --color has _an optional_ argument */ |
1156 | const char *color_opt = color_str; /* "always" */ | 1232 | const char *color_opt = color_str; /* "always" */ |
1157 | #endif | 1233 | #endif |
1158 | #if ENABLE_LONG_OPTS | ||
1159 | static const char ls_longopts[] ALIGN1 = | ||
1160 | "full-time\0" No_argument "\xff" | ||
1161 | "group-directories-first\0" No_argument "\xfe" | ||
1162 | IF_FEATURE_LS_COLOR("color\0" Optional_argument "\xfd") | ||
1163 | ; | ||
1164 | #endif | ||
1165 | 1234 | ||
1166 | INIT_G(); | 1235 | INIT_G(); |
1167 | 1236 | ||
1168 | init_unicode(); | 1237 | init_unicode(); |
1169 | 1238 | ||
1170 | #if ENABLE_FEATURE_LS_WIDTH | ||
1171 | /* obtain the terminal width */ | ||
1172 | G_terminal_width = get_terminal_width(STDIN_FILENO); | ||
1173 | /* go one less... */ | ||
1174 | G_terminal_width--; | ||
1175 | #endif | ||
1176 | |||
1177 | /* process options */ | 1239 | /* process options */ |
1178 | opt = getopt32long(argv, "^" | 1240 | opt = getopt32long(argv, "^" |
1179 | ls_options | 1241 | ls_options |
@@ -1211,6 +1273,29 @@ int ls_main(int argc UNUSED_PARAM, char **argv) | |||
1211 | exit(0); | 1273 | exit(0); |
1212 | #endif | 1274 | #endif |
1213 | 1275 | ||
1276 | /* ftpd secret backdoor? */ | ||
1277 | if (ENABLE_FTPD && applet_name[0] == 'f') { | ||
1278 | /* dirs first are much nicer */ | ||
1279 | opt = option_mask32 |= OPT_dirs_first; | ||
1280 | /* don't show SEcontext */ | ||
1281 | IF_SELINUX(opt = option_mask32 &= ~OPT_Z;) | ||
1282 | /* do not query stdout about size and tty-ness */ | ||
1283 | IF_FEATURE_LS_WIDTH(G_terminal_width = INT_MAX;) | ||
1284 | G.tty_out = 1; /* not a tty */ | ||
1285 | goto skip_if_ftpd; | ||
1286 | } | ||
1287 | |||
1288 | #if ENABLE_FEATURE_LS_WIDTH | ||
1289 | if ((int)G_terminal_width < 0) { | ||
1290 | /* obtain the terminal width */ | ||
1291 | G_terminal_width = get_terminal_width(STDIN_FILENO); | ||
1292 | /* go one less... */ | ||
1293 | G_terminal_width--; | ||
1294 | } | ||
1295 | if (G_terminal_width == 0) /* -w0 */ | ||
1296 | G_terminal_width = INT_MAX; /* "infinite" */ | ||
1297 | #endif | ||
1298 | |||
1214 | #if ENABLE_SELINUX | 1299 | #if ENABLE_SELINUX |
1215 | if (opt & OPT_Z) { | 1300 | if (opt & OPT_Z) { |
1216 | if (!is_selinux_enabled()) | 1301 | if (!is_selinux_enabled()) |
@@ -1229,7 +1314,7 @@ int ls_main(int argc UNUSED_PARAM, char **argv) | |||
1229 | # endif | 1314 | # endif |
1230 | /* LS_COLORS is unset, or (not empty && not "none") ? */ | 1315 | /* LS_COLORS is unset, or (not empty && not "none") ? */ |
1231 | if (!p || (p[0] && strcmp(p, "none") != 0)) { | 1316 | if (!p || (p[0] && strcmp(p, "none") != 0)) { |
1232 | if (isatty(STDOUT_FILENO)) { | 1317 | if (G_isatty()) { |
1233 | /* check isatty() last because it's expensive (syscall) */ | 1318 | /* check isatty() last because it's expensive (syscall) */ |
1234 | G_show_color = 1; | 1319 | G_show_color = 1; |
1235 | } | 1320 | } |
@@ -1238,23 +1323,28 @@ int ls_main(int argc UNUSED_PARAM, char **argv) | |||
1238 | if (opt & OPT_color) { | 1323 | if (opt & OPT_color) { |
1239 | if (color_opt[0] == 'n') | 1324 | if (color_opt[0] == 'n') |
1240 | G_show_color = 0; | 1325 | G_show_color = 0; |
1241 | else switch (index_in_substrings(color_str, color_opt)) { | 1326 | else if (!G_show_color) { |
1242 | case 3: | 1327 | /* if() is not needed, but avoids extra isatty() if G_show_color is already set */ |
1243 | case 4: | 1328 | /* Check --color=COLOR_OPT and maybe set show_color=1 */ |
1244 | case 5: | 1329 | switch (index_in_substrings(color_str, color_opt)) { |
1245 | if (!is_TERM_dumb() && isatty(STDOUT_FILENO)) { | 1330 | case 3: // auto |
1246 | case 0: | 1331 | case 4: // tty |
1247 | case 1: | 1332 | case 5: // if-tty |
1248 | case 2: | 1333 | if (!is_TERM_dumb() && G_isatty()) { |
1249 | G_show_color = 1; | 1334 | case 0: // always |
1335 | case 1: // yes | ||
1336 | case 2: // force | ||
1337 | G_show_color = 1; | ||
1338 | } | ||
1250 | } | 1339 | } |
1251 | } | 1340 | } |
1252 | } | 1341 | } |
1253 | #endif | 1342 | #endif |
1343 | skip_if_ftpd: | ||
1254 | 1344 | ||
1255 | /* sort out which command line options take precedence */ | 1345 | /* sort out which command line options take precedence */ |
1256 | if (ENABLE_FEATURE_LS_RECURSIVE && (opt & OPT_d)) | 1346 | if (ENABLE_FEATURE_LS_RECURSIVE && (opt & OPT_d)) |
1257 | option_mask32 &= ~OPT_R; /* no recurse if listing only dir */ | 1347 | opt = option_mask32 &= ~OPT_R; /* no recurse if listing only dir */ |
1258 | if (!(opt & OPT_l)) { /* not -l? */ | 1348 | if (!(opt & OPT_l)) { /* not -l? */ |
1259 | if (ENABLE_FEATURE_LS_TIMESTAMPS && ENABLE_FEATURE_LS_SORTFILES) { | 1349 | if (ENABLE_FEATURE_LS_TIMESTAMPS && ENABLE_FEATURE_LS_SORTFILES) { |
1260 | /* when to sort by time? -t[cu] sorts by time even with -l */ | 1350 | /* when to sort by time? -t[cu] sorts by time even with -l */ |
@@ -1262,19 +1352,17 @@ int ls_main(int argc UNUSED_PARAM, char **argv) | |||
1262 | /* without -l, bare -c or -u enable sort too */ | 1352 | /* without -l, bare -c or -u enable sort too */ |
1263 | /* (with -l, bare -c or -u just select which time to show) */ | 1353 | /* (with -l, bare -c or -u just select which time to show) */ |
1264 | if (opt & (OPT_c|OPT_u)) { | 1354 | if (opt & (OPT_c|OPT_u)) { |
1265 | option_mask32 |= OPT_t; | 1355 | opt = option_mask32 |= OPT_t; |
1266 | } | 1356 | } |
1267 | } | 1357 | } |
1268 | } | 1358 | } |
1269 | 1359 | ||
1270 | /* choose a display format if one was not already specified by an option */ | 1360 | /* choose a display format if one was not already specified by an option */ |
1271 | if (!(option_mask32 & (OPT_l|OPT_1|OPT_x|OPT_C))) | 1361 | if (!(opt & (OPT_l|OPT_1|OPT_x|OPT_C))) |
1272 | option_mask32 |= (isatty(STDOUT_FILENO) ? OPT_C : OPT_1); | 1362 | opt = option_mask32 |= (G_isatty() ? OPT_C : OPT_1); |
1273 | 1363 | ||
1274 | if (ENABLE_FTPD && applet_name[0] == 'f') { | 1364 | if (!(opt & OPT_q) && G_isatty()) |
1275 | /* ftpd secret backdoor. dirs first are much nicer */ | 1365 | opt = option_mask32 |= OPT_q; |
1276 | option_mask32 |= OPT_dirs_first; | ||
1277 | } | ||
1278 | 1366 | ||
1279 | #if ENABLE_FEATURE_EXTRA_FILE_DATA | 1367 | #if ENABLE_FEATURE_EXTRA_FILE_DATA |
1280 | /* Enable accurate link counts for directories */ | 1368 | /* Enable accurate link counts for directories */ |
diff --git a/coreutils/md5_sha1_sum.c b/coreutils/md5_sha1_sum.c index 978d328f1..4506aeb56 100644 --- a/coreutils/md5_sha1_sum.c +++ b/coreutils/md5_sha1_sum.c | |||
@@ -23,6 +23,12 @@ | |||
23 | //config: help | 23 | //config: help |
24 | //config: Compute and check SHA256 message digest | 24 | //config: Compute and check SHA256 message digest |
25 | //config: | 25 | //config: |
26 | //config:config SHA384SUM | ||
27 | //config: bool "sha384sum (7.3 kb)" | ||
28 | //config: default y | ||
29 | //config: help | ||
30 | //config: Compute and check SHA384 message digest | ||
31 | //config: | ||
26 | //config:config SHA512SUM | 32 | //config:config SHA512SUM |
27 | //config: bool "sha512sum (7.3 kb)" | 33 | //config: bool "sha512sum (7.3 kb)" |
28 | //config: default y | 34 | //config: default y |
@@ -35,13 +41,13 @@ | |||
35 | //config: help | 41 | //config: help |
36 | //config: Compute and check SHA3 message digest | 42 | //config: Compute and check SHA3 message digest |
37 | //config: | 43 | //config: |
38 | //config:comment "Common options for md5sum, sha1sum, sha256sum, sha512sum, sha3sum" | 44 | //config:comment "Common options for md5sum, sha1sum, sha256sum, ..., sha3sum" |
39 | //config: depends on MD5SUM || SHA1SUM || SHA256SUM || SHA512SUM || SHA3SUM | 45 | //config: depends on MD5SUM || SHA1SUM || SHA256SUM || SHA384SUM || SHA512SUM || SHA3SUM |
40 | //config: | 46 | //config: |
41 | //config:config FEATURE_MD5_SHA1_SUM_CHECK | 47 | //config:config FEATURE_MD5_SHA1_SUM_CHECK |
42 | //config: bool "Enable -c, -s and -w options" | 48 | //config: bool "Enable -c, -s and -w options" |
43 | //config: default y | 49 | //config: default y |
44 | //config: depends on MD5SUM || SHA1SUM || SHA256SUM || SHA512SUM || SHA3SUM | 50 | //config: depends on MD5SUM || SHA1SUM || SHA256SUM || SHA384SUM || SHA512SUM || SHA3SUM |
45 | //config: help | 51 | //config: help |
46 | //config: Enabling the -c options allows files to be checked | 52 | //config: Enabling the -c options allows files to be checked |
47 | //config: against pre-calculated hash values. | 53 | //config: against pre-calculated hash values. |
@@ -51,11 +57,13 @@ | |||
51 | //applet:IF_SHA1SUM(APPLET_NOEXEC(sha1sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, sha1sum)) | 57 | //applet:IF_SHA1SUM(APPLET_NOEXEC(sha1sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, sha1sum)) |
52 | //applet:IF_SHA3SUM(APPLET_NOEXEC(sha3sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, sha3sum)) | 58 | //applet:IF_SHA3SUM(APPLET_NOEXEC(sha3sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, sha3sum)) |
53 | //applet:IF_SHA256SUM(APPLET_NOEXEC(sha256sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, sha256sum)) | 59 | //applet:IF_SHA256SUM(APPLET_NOEXEC(sha256sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, sha256sum)) |
60 | //applet:IF_SHA384SUM(APPLET_NOEXEC(sha384sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, sha384sum)) | ||
54 | //applet:IF_SHA512SUM(APPLET_NOEXEC(sha512sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, sha512sum)) | 61 | //applet:IF_SHA512SUM(APPLET_NOEXEC(sha512sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, sha512sum)) |
55 | 62 | ||
56 | //kbuild:lib-$(CONFIG_MD5SUM) += md5_sha1_sum.o | 63 | //kbuild:lib-$(CONFIG_MD5SUM) += md5_sha1_sum.o |
57 | //kbuild:lib-$(CONFIG_SHA1SUM) += md5_sha1_sum.o | 64 | //kbuild:lib-$(CONFIG_SHA1SUM) += md5_sha1_sum.o |
58 | //kbuild:lib-$(CONFIG_SHA256SUM) += md5_sha1_sum.o | 65 | //kbuild:lib-$(CONFIG_SHA256SUM) += md5_sha1_sum.o |
66 | //kbuild:lib-$(CONFIG_SHA384SUM) += md5_sha1_sum.o | ||
59 | //kbuild:lib-$(CONFIG_SHA512SUM) += md5_sha1_sum.o | 67 | //kbuild:lib-$(CONFIG_SHA512SUM) += md5_sha1_sum.o |
60 | //kbuild:lib-$(CONFIG_SHA3SUM) += md5_sha1_sum.o | 68 | //kbuild:lib-$(CONFIG_SHA3SUM) += md5_sha1_sum.o |
61 | 69 | ||
@@ -99,6 +107,16 @@ | |||
99 | //usage: "\n -w Warn about improperly formatted checksum lines" | 107 | //usage: "\n -w Warn about improperly formatted checksum lines" |
100 | //usage: ) | 108 | //usage: ) |
101 | //usage: | 109 | //usage: |
110 | //usage:#define sha384sum_trivial_usage | ||
111 | //usage: IF_FEATURE_MD5_SHA1_SUM_CHECK("[-c[sw]] ")"[FILE]..." | ||
112 | //usage:#define sha384sum_full_usage "\n\n" | ||
113 | //usage: "Print" IF_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " SHA384 checksums" | ||
114 | //usage: IF_FEATURE_MD5_SHA1_SUM_CHECK( "\n" | ||
115 | //usage: "\n -c Check sums against list in FILEs" | ||
116 | //usage: "\n -s Don't output anything, status code shows success" | ||
117 | //usage: "\n -w Warn about improperly formatted checksum lines" | ||
118 | //usage: ) | ||
119 | //usage: | ||
102 | //usage:#define sha512sum_trivial_usage | 120 | //usage:#define sha512sum_trivial_usage |
103 | //usage: IF_FEATURE_MD5_SHA1_SUM_CHECK("[-c[sw]] ")"[FILE]..." | 121 | //usage: IF_FEATURE_MD5_SHA1_SUM_CHECK("[-c[sw]] ")"[FILE]..." |
104 | //usage:#define sha512sum_full_usage "\n\n" | 122 | //usage:#define sha512sum_full_usage "\n\n" |
@@ -130,11 +148,12 @@ | |||
130 | 148 | ||
131 | enum { | 149 | enum { |
132 | /* 4th letter of applet_name is... */ | 150 | /* 4th letter of applet_name is... */ |
133 | HASH_MD5 = 's', /* "md5>s<um" */ | 151 | HASH_MD5 = 's', /* "md5>s<um" */ |
134 | HASH_SHA1 = '1', | 152 | HASH_SHA1 = '1', |
135 | HASH_SHA256 = '2', | 153 | HASH_SHA256 = '2', |
136 | HASH_SHA3 = '3', | 154 | HASH_SHA3 = '3', |
137 | HASH_SHA512 = '5', | 155 | HASH_SHA512 = '5', |
156 | /* unfortunately, sha384sum has the same '3' as sha3 */ | ||
138 | }; | 157 | }; |
139 | 158 | ||
140 | #define FLAG_SILENT 1 | 159 | #define FLAG_SILENT 1 |
@@ -158,10 +177,11 @@ static unsigned char *hash_bin_to_hex(unsigned char *hash_value, | |||
158 | #endif | 177 | #endif |
159 | static uint8_t *hash_file(unsigned char *in_buf, const char *filename, unsigned sha3_width) | 178 | static uint8_t *hash_file(unsigned char *in_buf, const char *filename, unsigned sha3_width) |
160 | { | 179 | { |
161 | int src_fd, hash_len, count; | 180 | int src_fd, count; |
162 | union _ctx_ { | 181 | union _ctx_ { |
163 | sha3_ctx_t sha3; | 182 | sha3_ctx_t sha3; |
164 | sha512_ctx_t sha512; | 183 | sha512_ctx_t sha512; |
184 | sha384_ctx_t sha384; | ||
165 | sha256_ctx_t sha256; | 185 | sha256_ctx_t sha256; |
166 | sha1_ctx_t sha1; | 186 | sha1_ctx_t sha1; |
167 | md5_ctx_t md5; | 187 | md5_ctx_t md5; |
@@ -183,25 +203,31 @@ static uint8_t *hash_file(unsigned char *in_buf, const char *filename, unsigned | |||
183 | md5_begin(&context.md5); | 203 | md5_begin(&context.md5); |
184 | update = (void*)md5_hash; | 204 | update = (void*)md5_hash; |
185 | final = (void*)md5_end; | 205 | final = (void*)md5_end; |
186 | hash_len = 16; | ||
187 | } | 206 | } |
188 | else if (ENABLE_SHA1SUM && hash_algo == HASH_SHA1) { | 207 | else if (ENABLE_SHA1SUM && hash_algo == HASH_SHA1) { |
189 | sha1_begin(&context.sha1); | 208 | sha1_begin(&context.sha1); |
190 | update = (void*)sha1_hash; | 209 | update = (void*)sha1_hash; |
191 | final = (void*)sha1_end; | 210 | final = (void*)sha1_end; |
192 | hash_len = 20; | ||
193 | } | 211 | } |
194 | else if (ENABLE_SHA256SUM && hash_algo == HASH_SHA256) { | 212 | else if (ENABLE_SHA256SUM && hash_algo == HASH_SHA256) { |
195 | sha256_begin(&context.sha256); | 213 | sha256_begin(&context.sha256); |
196 | update = (void*)sha256_hash; | 214 | update = (void*)sha256_hash; |
197 | final = (void*)sha256_end; | 215 | final = (void*)sha256_end; |
198 | hash_len = 32; | 216 | } |
217 | else if (ENABLE_SHA384SUM | ||
218 | && (ENABLE_SHA3SUM | ||
219 | ? (applet_name[4] == '8') /* check for "sha384", but do not match "sha3" */ | ||
220 | : (hash_algo == '3') /* applet_name = "sha3sum" is not possible */ | ||
221 | ) | ||
222 | ) { | ||
223 | sha384_begin(&context.sha384); | ||
224 | update = (void*)sha384_hash; | ||
225 | final = (void*)sha384_end; | ||
199 | } | 226 | } |
200 | else if (ENABLE_SHA512SUM && hash_algo == HASH_SHA512) { | 227 | else if (ENABLE_SHA512SUM && hash_algo == HASH_SHA512) { |
201 | sha512_begin(&context.sha512); | 228 | sha512_begin(&context.sha512); |
202 | update = (void*)sha512_hash; | 229 | update = (void*)sha512_hash; |
203 | final = (void*)sha512_end; | 230 | final = (void*)sha512_end; |
204 | hash_len = 64; | ||
205 | } | 231 | } |
206 | #if ENABLE_SHA3SUM | 232 | #if ENABLE_SHA3SUM |
207 | else if (ENABLE_SHA3SUM && hash_algo == HASH_SHA3) { | 233 | else if (ENABLE_SHA3SUM && hash_algo == HASH_SHA3) { |
@@ -219,9 +245,7 @@ static uint8_t *hash_file(unsigned char *in_buf, const char *filename, unsigned | |||
219 | ) { | 245 | ) { |
220 | bb_error_msg_and_die("bad -a%u", sha3_width); | 246 | bb_error_msg_and_die("bad -a%u", sha3_width); |
221 | } | 247 | } |
222 | sha3_width /= 4; | 248 | context.sha3.input_block_bytes = 1600/8 - sha3_width/4; |
223 | context.sha3.input_block_bytes = 1600/8 - sha3_width; | ||
224 | hash_len = sha3_width/2; | ||
225 | } | 249 | } |
226 | #endif | 250 | #endif |
227 | else { | 251 | else { |
@@ -236,7 +260,7 @@ static uint8_t *hash_file(unsigned char *in_buf, const char *filename, unsigned | |||
236 | if (count < 0) | 260 | if (count < 0) |
237 | bb_perror_msg("can't read '%s'", filename); | 261 | bb_perror_msg("can't read '%s'", filename); |
238 | else /* count == 0 */ { | 262 | else /* count == 0 */ { |
239 | final(&context, in_buf); | 263 | unsigned hash_len = final(&context, in_buf); |
240 | hash_value = hash_bin_to_hex(in_buf, hash_len); | 264 | hash_value = hash_bin_to_hex(in_buf, hash_len); |
241 | } | 265 | } |
242 | } | 266 | } |
@@ -262,14 +286,14 @@ int md5_sha1_sum_main(int argc UNUSED_PARAM, char **argv) | |||
262 | /* -b "binary", -t "text" are ignored (shaNNNsum compat) */ | 286 | /* -b "binary", -t "text" are ignored (shaNNNsum compat) */ |
263 | /* -s and -w require -c */ | 287 | /* -s and -w require -c */ |
264 | #if ENABLE_SHA3SUM | 288 | #if ENABLE_SHA3SUM |
265 | if (applet_name[3] == HASH_SHA3) | 289 | if (applet_name[3] == HASH_SHA3 && (!ENABLE_SHA384SUM || applet_name[4] != '8')) |
266 | flags = getopt32(argv, "^" "scwbta:+" "\0" "s?c:w?c", &sha3_width); | 290 | flags = getopt32(argv, "^" "scwbta:+" "\0" "s?c:w?c", &sha3_width); |
267 | else | 291 | else |
268 | #endif | 292 | #endif |
269 | flags = getopt32(argv, "^" "scwbt" "\0" "s?c:w?c"); | 293 | flags = getopt32(argv, "^" "scwbt" "\0" "s?c:w?c"); |
270 | } else { | 294 | } else { |
271 | #if ENABLE_SHA3SUM | 295 | #if ENABLE_SHA3SUM |
272 | if (applet_name[3] == HASH_SHA3) | 296 | if (applet_name[3] == HASH_SHA3 && (!ENABLE_SHA384SUM || applet_name[4] != '8')) |
273 | getopt32(argv, "a:+", &sha3_width); | 297 | getopt32(argv, "a:+", &sha3_width); |
274 | else | 298 | else |
275 | #endif | 299 | #endif |
diff --git a/e2fsprogs/fsck.c b/e2fsprogs/fsck.c index fd4ea737c..f7e93497d 100644 --- a/e2fsprogs/fsck.c +++ b/e2fsprogs/fsck.c | |||
@@ -423,13 +423,11 @@ static int wait_one(int flags) | |||
423 | /* if (G.noexecute) { already returned -1; } */ | 423 | /* if (G.noexecute) { already returned -1; } */ |
424 | 424 | ||
425 | while (1) { | 425 | while (1) { |
426 | pid = waitpid(-1, &status, flags); | 426 | pid = safe_waitpid(-1, &status, flags); |
427 | kill_all_if_got_signal(); | 427 | kill_all_if_got_signal(); |
428 | if (pid == 0) /* flags == WNOHANG and no children exited */ | 428 | if (pid == 0) /* flags == WNOHANG and no children exited */ |
429 | return -1; | 429 | return -1; |
430 | if (pid < 0) { | 430 | if (pid < 0) { |
431 | if (errno == EINTR) | ||
432 | continue; | ||
433 | if (errno == ECHILD) { /* paranoia */ | 431 | if (errno == ECHILD) { /* paranoia */ |
434 | bb_simple_error_msg("wait: no more children"); | 432 | bb_simple_error_msg("wait: no more children"); |
435 | return -1; | 433 | return -1; |
diff --git a/include/libbb.h b/include/libbb.h index 8dc4e4992..60037ed3d 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -1224,6 +1224,22 @@ char *bin2hex(char *dst, const char *src, int count) FAST_FUNC; | |||
1224 | /* Reverse */ | 1224 | /* Reverse */ |
1225 | char* hex2bin(char *dst, const char *src, int count) FAST_FUNC; | 1225 | char* hex2bin(char *dst, const char *src, int count) FAST_FUNC; |
1226 | 1226 | ||
1227 | /* Returns strlen as a bonus */ | ||
1228 | //size_t replace_char(char *s, char what, char with) FAST_FUNC; | ||
1229 | static inline size_t replace_char(char *str, char from, char to) | ||
1230 | { | ||
1231 | char *p = str; | ||
1232 | while (*p) { | ||
1233 | if (*p == from) | ||
1234 | *p = to; | ||
1235 | p++; | ||
1236 | } | ||
1237 | return p - str; | ||
1238 | } | ||
1239 | |||
1240 | extern const char c_escape_conv_str00[]; | ||
1241 | #define c_escape_conv_str07 (c_escape_conv_str00+3) | ||
1242 | |||
1227 | void FAST_FUNC xorbuf_3(void *dst, const void *src1, const void *src2, unsigned count); | 1243 | void FAST_FUNC xorbuf_3(void *dst, const void *src1, const void *src2, unsigned count); |
1228 | void FAST_FUNC xorbuf(void* buf, const void* mask, unsigned count); | 1244 | void FAST_FUNC xorbuf(void* buf, const void* mask, unsigned count); |
1229 | void FAST_FUNC xorbuf16_aligned_long(void* buf, const void* mask); | 1245 | void FAST_FUNC xorbuf16_aligned_long(void* buf, const void* mask); |
@@ -2225,33 +2241,6 @@ enum { COMM_LEN = 16 }; | |||
2225 | # endif | 2241 | # endif |
2226 | #endif | 2242 | #endif |
2227 | 2243 | ||
2228 | struct smaprec { | ||
2229 | unsigned long mapped_rw; | ||
2230 | unsigned long mapped_ro; | ||
2231 | unsigned long shared_clean; | ||
2232 | unsigned long shared_dirty; | ||
2233 | unsigned long private_clean; | ||
2234 | unsigned long private_dirty; | ||
2235 | unsigned long stack; | ||
2236 | unsigned long smap_pss, smap_swap; | ||
2237 | unsigned long smap_size; | ||
2238 | // For mixed 32/64 userspace, 32-bit pmap still needs | ||
2239 | // 64-bit field here to correctly show 64-bit processes: | ||
2240 | unsigned long long smap_start; | ||
2241 | // (strictly speaking, other fields need to be wider too, | ||
2242 | // but they are in kbytes, not bytes, and they hold sizes, | ||
2243 | // not start addresses, sizes tend to be less than 4 terabytes) | ||
2244 | char smap_mode[5]; | ||
2245 | char *smap_name; | ||
2246 | }; | ||
2247 | |||
2248 | #if !ENABLE_PMAP | ||
2249 | #define procps_read_smaps(pid, total, cb, data) \ | ||
2250 | procps_read_smaps(pid, total) | ||
2251 | #endif | ||
2252 | int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total, | ||
2253 | void (*cb)(struct smaprec *, void *), void *data); | ||
2254 | |||
2255 | typedef struct procps_status_t { | 2244 | typedef struct procps_status_t { |
2256 | #if !ENABLE_PLATFORM_MINGW32 | 2245 | #if !ENABLE_PLATFORM_MINGW32 |
2257 | DIR *dir; | 2246 | DIR *dir; |
@@ -2287,7 +2276,13 @@ typedef struct procps_status_t { | |||
2287 | #endif | 2276 | #endif |
2288 | unsigned tty_major,tty_minor; | 2277 | unsigned tty_major,tty_minor; |
2289 | #if ENABLE_FEATURE_TOPMEM | 2278 | #if ENABLE_FEATURE_TOPMEM |
2290 | struct smaprec smaps; | 2279 | unsigned long mapped_rw; |
2280 | unsigned long mapped_ro; | ||
2281 | unsigned long shared_clean; | ||
2282 | unsigned long shared_dirty; | ||
2283 | unsigned long private_clean; | ||
2284 | unsigned long private_dirty; | ||
2285 | unsigned long stack; | ||
2291 | #endif | 2286 | #endif |
2292 | char state[4]; | 2287 | char state[4]; |
2293 | /* basename of executable in exec(2), read from /proc/N/stat | 2288 | /* basename of executable in exec(2), read from /proc/N/stat |
@@ -2336,11 +2331,15 @@ void free_procps_scan(procps_status_t* sp) FAST_FUNC; | |||
2336 | procps_status_t* procps_scan(procps_status_t* sp, int flags) FAST_FUNC; | 2331 | procps_status_t* procps_scan(procps_status_t* sp, int flags) FAST_FUNC; |
2337 | /* Format cmdline (up to col chars) into char buf[size] */ | 2332 | /* Format cmdline (up to col chars) into char buf[size] */ |
2338 | /* Puts [comm] if cmdline is empty (-> process is a kernel thread) */ | 2333 | /* Puts [comm] if cmdline is empty (-> process is a kernel thread) */ |
2339 | void read_cmdline(char *buf, int size, unsigned pid, const char *comm) FAST_FUNC; | 2334 | int read_cmdline(char *buf, int size, unsigned pid, const char *comm) FAST_FUNC; |
2340 | pid_t *find_pid_by_name(const char* procName) FAST_FUNC; | 2335 | pid_t *find_pid_by_name(const char* procName) FAST_FUNC; |
2341 | pid_t *pidlist_reverse(pid_t *pidList) FAST_FUNC; | 2336 | pid_t *pidlist_reverse(pid_t *pidList) FAST_FUNC; |
2342 | int starts_with_cpu(const char *str) FAST_FUNC; | 2337 | int starts_with_cpu(const char *str) FAST_FUNC; |
2343 | unsigned get_cpu_count(void) FAST_FUNC; | 2338 | unsigned get_cpu_count(void) FAST_FUNC; |
2339 | /* Some internals reused by pmap: */ | ||
2340 | unsigned long FAST_FUNC fast_strtoul_10(char **endptr); | ||
2341 | unsigned long long FAST_FUNC fast_strtoull_16(char **endptr); | ||
2342 | char* FAST_FUNC skip_fields(char *str, int count); | ||
2344 | 2343 | ||
2345 | 2344 | ||
2346 | /* Use strict=1 if you process input from untrusted source: | 2345 | /* Use strict=1 if you process input from untrusted source: |
@@ -2375,8 +2374,9 @@ enum { | |||
2375 | MD5_OUTSIZE = 16, | 2374 | MD5_OUTSIZE = 16, |
2376 | SHA1_OUTSIZE = 20, | 2375 | SHA1_OUTSIZE = 20, |
2377 | SHA256_OUTSIZE = 32, | 2376 | SHA256_OUTSIZE = 32, |
2377 | SHA384_OUTSIZE = 48, | ||
2378 | SHA512_OUTSIZE = 64, | 2378 | SHA512_OUTSIZE = 64, |
2379 | SHA3_OUTSIZE = 28, | 2379 | //SHA3-224_OUTSIZE = 28, |
2380 | /* size of input block */ | 2380 | /* size of input block */ |
2381 | SHA2_INSIZE = 64, | 2381 | SHA2_INSIZE = 64, |
2382 | }; | 2382 | }; |
@@ -2390,6 +2390,7 @@ struct bcrypt_hash_ctx_t { | |||
2390 | typedef struct bcrypt_hash_ctx_t md5_ctx_t; | 2390 | typedef struct bcrypt_hash_ctx_t md5_ctx_t; |
2391 | typedef struct bcrypt_hash_ctx_t sha1_ctx_t; | 2391 | typedef struct bcrypt_hash_ctx_t sha1_ctx_t; |
2392 | typedef struct bcrypt_hash_ctx_t sha256_ctx_t; | 2392 | typedef struct bcrypt_hash_ctx_t sha256_ctx_t; |
2393 | typedef struct bcrypt_hash_ctx_t sha384_ctx_t; | ||
2393 | typedef struct bcrypt_hash_ctx_t sha512_ctx_t; | 2394 | typedef struct bcrypt_hash_ctx_t sha512_ctx_t; |
2394 | typedef struct sha3_ctx_t { | 2395 | typedef struct sha3_ctx_t { |
2395 | uint64_t state[25]; | 2396 | uint64_t state[25]; |
@@ -2399,16 +2400,19 @@ typedef struct sha3_ctx_t { | |||
2399 | void md5_begin(struct bcrypt_hash_ctx_t *ctx) FAST_FUNC; | 2400 | void md5_begin(struct bcrypt_hash_ctx_t *ctx) FAST_FUNC; |
2400 | void sha1_begin(struct bcrypt_hash_ctx_t *ctx) FAST_FUNC; | 2401 | void sha1_begin(struct bcrypt_hash_ctx_t *ctx) FAST_FUNC; |
2401 | void sha256_begin(struct bcrypt_hash_ctx_t *ctx) FAST_FUNC; | 2402 | void sha256_begin(struct bcrypt_hash_ctx_t *ctx) FAST_FUNC; |
2403 | void sha384_begin(struct bcrypt_hash_ctx_t *ctx) FAST_FUNC; | ||
2402 | void sha512_begin(struct bcrypt_hash_ctx_t *ctx) FAST_FUNC; | 2404 | void sha512_begin(struct bcrypt_hash_ctx_t *ctx) FAST_FUNC; |
2403 | void generic_hash(struct bcrypt_hash_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC; | 2405 | void generic_hash(struct bcrypt_hash_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC; |
2404 | unsigned generic_end(struct bcrypt_hash_ctx_t *ctx, void *resbuf) FAST_FUNC; | 2406 | unsigned generic_end(struct bcrypt_hash_ctx_t *ctx, void *resbuf) FAST_FUNC; |
2405 | # define md5_hash generic_hash | 2407 | # define md5_hash generic_hash |
2406 | # define sha1_hash generic_hash | 2408 | # define sha1_hash generic_hash |
2407 | # define sha256_hash generic_hash | 2409 | # define sha256_hash generic_hash |
2410 | # define sha384_hash generic_hash | ||
2408 | # define sha512_hash generic_hash | 2411 | # define sha512_hash generic_hash |
2409 | # define md5_end generic_end | 2412 | # define md5_end generic_end |
2410 | # define sha1_end generic_end | 2413 | # define sha1_end generic_end |
2411 | # define sha256_end generic_end | 2414 | # define sha256_end generic_end |
2415 | # define sha384_end generic_end | ||
2412 | # define sha512_end generic_end | 2416 | # define sha512_end generic_end |
2413 | #else | 2417 | #else |
2414 | typedef struct md5_ctx_t { | 2418 | typedef struct md5_ctx_t { |
@@ -2424,6 +2428,7 @@ typedef struct sha512_ctx_t { | |||
2424 | uint64_t hash[8]; | 2428 | uint64_t hash[8]; |
2425 | uint8_t wbuffer[128]; /* always correctly aligned for uint64_t */ | 2429 | uint8_t wbuffer[128]; /* always correctly aligned for uint64_t */ |
2426 | } sha512_ctx_t; | 2430 | } sha512_ctx_t; |
2431 | typedef struct sha512_ctx_t sha384_ctx_t; | ||
2427 | typedef struct sha3_ctx_t { | 2432 | typedef struct sha3_ctx_t { |
2428 | uint64_t state[25]; | 2433 | uint64_t state[25]; |
2429 | unsigned bytes_queued; | 2434 | unsigned bytes_queued; |
@@ -2441,6 +2446,9 @@ void sha256_begin(sha256_ctx_t *ctx) FAST_FUNC; | |||
2441 | void sha512_begin(sha512_ctx_t *ctx) FAST_FUNC; | 2446 | void sha512_begin(sha512_ctx_t *ctx) FAST_FUNC; |
2442 | void sha512_hash(sha512_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC; | 2447 | void sha512_hash(sha512_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC; |
2443 | unsigned sha512_end(sha512_ctx_t *ctx, void *resbuf) FAST_FUNC; | 2448 | unsigned sha512_end(sha512_ctx_t *ctx, void *resbuf) FAST_FUNC; |
2449 | void sha384_begin(sha384_ctx_t *ctx) FAST_FUNC; | ||
2450 | #define sha384_hash sha512_hash | ||
2451 | unsigned sha384_end(sha384_ctx_t *ctx, void *resbuf) FAST_FUNC; | ||
2444 | #endif | 2452 | #endif |
2445 | void sha3_begin(sha3_ctx_t *ctx) FAST_FUNC; | 2453 | void sha3_begin(sha3_ctx_t *ctx) FAST_FUNC; |
2446 | void sha3_hash(sha3_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC; | 2454 | void sha3_hash(sha3_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC; |
diff --git a/include/platform.h b/include/platform.h index 5795a0cf3..0b88f990b 100644 --- a/include/platform.h +++ b/include/platform.h | |||
@@ -208,7 +208,7 @@ | |||
208 | #elif defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN | 208 | #elif defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN |
209 | # define BB_BIG_ENDIAN 0 | 209 | # define BB_BIG_ENDIAN 0 |
210 | # define BB_LITTLE_ENDIAN 1 | 210 | # define BB_LITTLE_ENDIAN 1 |
211 | #elif defined(__386__) | 211 | #elif defined(__i386__) |
212 | # define BB_BIG_ENDIAN 0 | 212 | # define BB_BIG_ENDIAN 0 |
213 | # define BB_LITTLE_ENDIAN 1 | 213 | # define BB_LITTLE_ENDIAN 1 |
214 | #else | 214 | #else |
diff --git a/init/init.c b/init/init.c index 797e0a0eb..294be9952 100644 --- a/init/init.c +++ b/init/init.c | |||
@@ -1201,7 +1201,7 @@ int init_main(int argc UNUSED_PARAM, char **argv) | |||
1201 | int status; | 1201 | int status; |
1202 | struct init_action *a; | 1202 | struct init_action *a; |
1203 | 1203 | ||
1204 | wpid = waitpid(-1, &status, WNOHANG); | 1204 | wpid = wait_any_nohang(&status); |
1205 | if (wpid <= 0) | 1205 | if (wpid <= 0) |
1206 | break; | 1206 | break; |
1207 | 1207 | ||
diff --git a/libbb/c_escape.c b/libbb/c_escape.c new file mode 100644 index 000000000..6c109f2e0 --- /dev/null +++ b/libbb/c_escape.c | |||
@@ -0,0 +1,20 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Copyright (C) 2025 by Denys Vlasenko <vda.linux@googlemail.com> | ||
4 | * | ||
5 | * Licensed under GPLv2, see file LICENSE in this source tree. | ||
6 | */ | ||
7 | //kbuild:lib-y += c_escape.o | ||
8 | |||
9 | #include "libbb.h" | ||
10 | |||
11 | const char c_escape_conv_str00[] ALIGN1 = | ||
12 | "\\""0""\0" // [0]:00 | ||
13 | "\\""a""\0" // [1]:07 | ||
14 | "\\""b""\0" // [2]:08 | ||
15 | "\\""t""\0" // [3]:09 | ||
16 | "\\""n""\0" // [4]:0a | ||
17 | "\\""v""\0" // [5]:0b | ||
18 | "\\""f""\0" // [6]:0c | ||
19 | "\\""r" // [7]:0d | ||
20 | ; | ||
diff --git a/libbb/concat_path_file.c b/libbb/concat_path_file.c index 3afb0e3a4..96fcd4a1d 100644 --- a/libbb/concat_path_file.c +++ b/libbb/concat_path_file.c | |||
@@ -17,6 +17,7 @@ | |||
17 | 17 | ||
18 | char* FAST_FUNC concat_path_file(const char *path, const char *filename) | 18 | char* FAST_FUNC concat_path_file(const char *path, const char *filename) |
19 | { | 19 | { |
20 | #if 0 | ||
20 | char *lc; | 21 | char *lc; |
21 | 22 | ||
22 | if (!path) | 23 | if (!path) |
@@ -31,4 +32,78 @@ char* FAST_FUNC concat_path_file(const char *path, const char *filename) | |||
31 | filename++; | 32 | filename++; |
32 | #endif | 33 | #endif |
33 | return xasprintf("%s%s%s", path, (lc==NULL ? "/" : ""), filename); | 34 | return xasprintf("%s%s%s", path, (lc==NULL ? "/" : ""), filename); |
35 | #else | ||
36 | /* ^^^^^^^^^^^ timing of xasprintf-based code above: | ||
37 | * real 7.074s | ||
38 | * user 0.156s <<< | ||
39 | * sys 6.394s | ||
40 | * "rm -rf" of a Linux kernel tree from tmpfs (run time still dominated by in-kernel work, though) | ||
41 | * real 6.989s | ||
42 | * user 0.055s <<< 3 times less CPU used | ||
43 | * sys 6.450s | ||
44 | * vvvvvvvvvvv timing of open-coded malloc+memcpy code below (+59 bytes): | ||
45 | */ | ||
46 | char *buf, *p; | ||
47 | size_t n1, n2, n3; | ||
48 | |||
49 | while (*filename == '/') | ||
50 | filename++; | ||
51 | |||
52 | if (!path || !path[0]) | ||
53 | return xstrdup(filename); | ||
54 | |||
55 | n1 = strlen(path); | ||
56 | n2 = (path[n1 - 1] != '/'); /* 1: "path has no trailing slash" */ | ||
57 | n3 = strlen(filename) + 1; | ||
58 | |||
59 | buf = xmalloc(n1 + n2 + n3); | ||
60 | p = mempcpy(buf, path, n1); | ||
61 | if (n2) | ||
62 | *p++ = '/'; | ||
63 | memcpy(p, filename, n3); | ||
64 | return buf; | ||
65 | #endif | ||
34 | } | 66 | } |
67 | |||
68 | /* If second component comes from struct dirent, | ||
69 | * it's possible to eliminate one strlen() by using name length | ||
70 | * provided by kernel in struct dirent. See below. | ||
71 | * However, the win seems to be insignificant. | ||
72 | */ | ||
73 | |||
74 | #if 0 | ||
75 | |||
76 | /* Extract d_namlen from struct dirent */ | ||
77 | static size_t get_d_namlen(const struct dirent *de) | ||
78 | { | ||
79 | #if defined(_DIRENT_HAVE_D_NAMLEN) | ||
80 | return de->d_namlen; | ||
81 | #elif defined(_DIRENT_HAVE_D_RECLEN) | ||
82 | const size_t prefix_sz = offsetof(struct dirent, d_name); | ||
83 | return de->d_reclen - prefix_sz; | ||
84 | #else | ||
85 | return strlen(de->d_name); | ||
86 | #endif | ||
87 | } | ||
88 | |||
89 | char* FAST_FUNC concat_path_dirent(const char *path, const struct dirent *de) | ||
90 | { | ||
91 | char *buf, *p; | ||
92 | size_t n1, n2, n3; | ||
93 | |||
94 | if (!path || !path[0]) | ||
95 | return xstrdup(de->d_name); | ||
96 | |||
97 | n1 = strlen(path); | ||
98 | n2 = (path[n1 - 1] != '/'); | ||
99 | n3 = get_d_namlen(de) + 1; | ||
100 | |||
101 | buf = xmalloc(n1 + n2 + n3); | ||
102 | p = mempcpy(buf, path, n1); | ||
103 | if (n2) | ||
104 | *p++ = '/'; | ||
105 | memcpy(p, de->d_name, n3); | ||
106 | return buf; | ||
107 | } | ||
108 | |||
109 | #endif | ||
diff --git a/libbb/dump.c b/libbb/dump.c index b2abe85af..3dc53d55f 100644 --- a/libbb/dump.c +++ b/libbb/dump.c | |||
@@ -514,37 +514,52 @@ static void bpad(PR *pr) | |||
514 | continue; | 514 | continue; |
515 | } | 515 | } |
516 | 516 | ||
517 | static const char conv_str[] ALIGN1 = | ||
518 | "\0" "\\""0""\0" | ||
519 | "\007""\\""a""\0" | ||
520 | "\b" "\\""b""\0" | ||
521 | "\f" "\\""f""\0" | ||
522 | "\n" "\\""n""\0" | ||
523 | "\r" "\\""r""\0" | ||
524 | "\t" "\\""t""\0" | ||
525 | "\v" "\\""v""\0" | ||
526 | ; | ||
527 | |||
528 | static void conv_c(PR *pr, unsigned char *p) | 517 | static void conv_c(PR *pr, unsigned char *p) |
529 | { | 518 | { |
530 | const char *str = conv_str; | 519 | const char *str; |
531 | 520 | unsigned char ch; | |
532 | do { | 521 | |
533 | if (*p == *str) { | 522 | ch = *p; |
534 | ++str; | 523 | if (ch == 0 || (ch -= 6, (signed char)ch > 0 && ch <= 7)) { |
535 | goto strpr; /* map e.g. '\n' to "\\n" */ | 524 | /* map chars 0,7..13 to "\0","\{a,b,t,n,v,f,r}" */ |
536 | } | 525 | str = c_escape_conv_str00 + 3 * ch; |
537 | str += 4; | 526 | goto strpr; |
538 | } while (*str); | 527 | } |
539 | 528 | ||
540 | if (isprint_asciionly(*p)) { | 529 | if (isprint_asciionly(*p)) { |
541 | *pr->cchar = 'c'; | 530 | *pr->cchar = 'c'; |
542 | printf(pr->fmt, *p); | 531 | printf(pr->fmt, *p); |
543 | } else { | 532 | } else { |
533 | #if defined(__i386__) || defined(__x86_64__) | ||
534 | /* Abuse partial register operations */ | ||
535 | uint32_t buf; | ||
536 | unsigned n = *p; | ||
537 | asm ( //00000000 00000000 00000000 aabbbccc | ||
538 | "\n shll $10,%%eax" //00000000 000000aa bbbccc00 00000000 | ||
539 | "\n shrw $5,%%ax" //00000000 000000aa 00000bbb ccc00000 | ||
540 | "\n shrb $5,%%al" //00000000 000000aa 00000bbb 00000ccc | ||
541 | "\n shll $8,%%eax" //000000aa 00000bbb 00000ccc 00000000 | ||
542 | "\n bswapl %%eax" //00000000 00000ccc 00000bbb 000000aa | ||
543 | "\n addl $0x303030,%%eax" | ||
544 | "\n" : "=a" (n) | ||
545 | : "0" (n) | ||
546 | ); | ||
547 | buf = n; | ||
548 | str = (void*)&buf; | ||
549 | #elif 1 | ||
544 | char buf[4]; | 550 | char buf[4]; |
545 | /* gcc-8.0.1 needs lots of casts to shut up */ | 551 | /* gcc-8.0.1 needs lots of casts to shut up */ |
546 | sprintf(buf, "%03o", (unsigned)(uint8_t)*p); | 552 | sprintf(buf, "%03o", (unsigned)(uint8_t)*p); |
547 | str = buf; | 553 | str = buf; |
554 | #else // use faster version? +20 bytes of code relative to sprintf() method | ||
555 | char buf[4]; | ||
556 | buf[3] = '\0'; | ||
557 | ch = *p; | ||
558 | buf[2] = '0' + (ch & 7); ch >>= 3; | ||
559 | buf[1] = '0' + (ch & 7); ch >>= 3; | ||
560 | buf[0] = '0' + ch; | ||
561 | str = buf; | ||
562 | #endif | ||
548 | strpr: | 563 | strpr: |
549 | *pr->cchar = 's'; | 564 | *pr->cchar = 's'; |
550 | printf(pr->fmt, str); | 565 | printf(pr->fmt, str); |
diff --git a/libbb/getopt32.c b/libbb/getopt32.c index 76d29d5eb..9247588d9 100644 --- a/libbb/getopt32.c +++ b/libbb/getopt32.c | |||
@@ -530,6 +530,7 @@ vgetopt32(char **argv, const char *applet_opts, const char *applet_long_options, | |||
530 | * "fake" short options, like this one: | 530 | * "fake" short options, like this one: |
531 | * wget $'-\203' "Test: test" http://kernel.org/ | 531 | * wget $'-\203' "Test: test" http://kernel.org/ |
532 | * (supposed to act as --header, but doesn't) */ | 532 | * (supposed to act as --header, but doesn't) */ |
533 | next_opt: | ||
533 | #if ENABLE_LONG_OPTS | 534 | #if ENABLE_LONG_OPTS |
534 | while ((c = getopt_long(argc, argv, applet_opts, | 535 | while ((c = getopt_long(argc, argv, applet_opts, |
535 | long_options, NULL)) != -1) { | 536 | long_options, NULL)) != -1) { |
@@ -544,8 +545,16 @@ vgetopt32(char **argv, const char *applet_opts, const char *applet_long_options, | |||
544 | * but we construct long opts so that flag | 545 | * but we construct long opts so that flag |
545 | * is always NULL (see above) */ | 546 | * is always NULL (see above) */ |
546 | if (on_off->opt_char == '\0' /* && c != '\0' */) { | 547 | if (on_off->opt_char == '\0' /* && c != '\0' */) { |
547 | /* c is probably '?' - "bad option" */ | 548 | /* We reached the end of complementary[] and did not find -c */ |
548 | goto error; | 549 | if (c == '?') /* getopt says: "bad option, or option has no required argument" */ |
550 | goto error; | ||
551 | /* if there were options beyond 32 bits (example: ls), | ||
552 | * they got no complementary[] slot, and no result bit. | ||
553 | * IOW: they must be "accept but ignore" options. | ||
554 | * For them, we end up here. | ||
555 | */ | ||
556 | //bb_error_msg("ignored option '%c', skipping", c); | ||
557 | goto next_opt; | ||
549 | } | 558 | } |
550 | } | 559 | } |
551 | if (flags & on_off->incongruously) | 560 | if (flags & on_off->incongruously) |
diff --git a/libbb/hash_md5_sha.c b/libbb/hash_md5_sha.c index 22dd890bf..fd56d831b 100644 --- a/libbb/hash_md5_sha.c +++ b/libbb/hash_md5_sha.c | |||
@@ -11,7 +11,7 @@ | |||
11 | #define STR1(s) #s | 11 | #define STR1(s) #s |
12 | #define STR(s) STR1(s) | 12 | #define STR(s) STR1(s) |
13 | 13 | ||
14 | #define NEED_SHA512 (ENABLE_SHA512SUM || ENABLE_USE_BB_CRYPT_SHA) | 14 | #define NEED_SHA512 (ENABLE_SHA512SUM || ENABLE_SHA384SUM || ENABLE_USE_BB_CRYPT_SHA) |
15 | 15 | ||
16 | #if ENABLE_FEATURE_USE_CNG_API | 16 | #if ENABLE_FEATURE_USE_CNG_API |
17 | # include <windows.h> | 17 | # include <windows.h> |
@@ -21,6 +21,7 @@ | |||
21 | # define BCRYPT_MD5_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x00000021) | 21 | # define BCRYPT_MD5_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x00000021) |
22 | # define BCRYPT_SHA1_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x00000031) | 22 | # define BCRYPT_SHA1_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x00000031) |
23 | # define BCRYPT_SHA256_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x00000041) | 23 | # define BCRYPT_SHA256_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x00000041) |
24 | # define BCRYPT_SHA384_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x00000051) | ||
24 | # define BCRYPT_SHA512_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x00000061) | 25 | # define BCRYPT_SHA512_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x00000061) |
25 | 26 | ||
26 | /* Initialize structure containing state of computation. | 27 | /* Initialize structure containing state of computation. |
@@ -61,9 +62,18 @@ void FAST_FUNC sha256_begin(sha256_ctx_t *ctx) | |||
61 | generic_init(ctx, BCRYPT_SHA256_ALG_HANDLE); | 62 | generic_init(ctx, BCRYPT_SHA256_ALG_HANDLE); |
62 | } | 63 | } |
63 | 64 | ||
64 | #if NEED_SHA512 | 65 | #if ENABLE_SHA384SUM |
65 | /* Initialize structure containing state of computation. | 66 | /* Initialize structure containing state of computation. |
66 | (FIPS 180-2:5.3.3) */ | 67 | (FIPS 180-2:5.3.3) */ |
68 | void FAST_FUNC sha384_begin(sha384_ctx_t *ctx) | ||
69 | { | ||
70 | generic_init(ctx, BCRYPT_SHA384_ALG_HANDLE); | ||
71 | } | ||
72 | #endif /* ENABLE_SHA384SUM */ | ||
73 | |||
74 | #if NEED_SHA512 | ||
75 | /* Initialize structure containing state of computation. | ||
76 | (FIPS 180-2:5.3.4) */ | ||
67 | void FAST_FUNC sha512_begin(sha512_ctx_t *ctx) | 77 | void FAST_FUNC sha512_begin(sha512_ctx_t *ctx) |
68 | { | 78 | { |
69 | generic_init(ctx, BCRYPT_SHA512_ALG_HANDLE); | 79 | generic_init(ctx, BCRYPT_SHA512_ALG_HANDLE); |
@@ -1109,7 +1119,7 @@ static const sha_K_int sha_K[] ALIGN8 = { | |||
1109 | K(0x84c87814a1f0ab72ULL), K(0x8cc702081a6439ecULL), | 1119 | K(0x84c87814a1f0ab72ULL), K(0x8cc702081a6439ecULL), |
1110 | K(0x90befffa23631e28ULL), K(0xa4506cebde82bde9ULL), | 1120 | K(0x90befffa23631e28ULL), K(0xa4506cebde82bde9ULL), |
1111 | K(0xbef9a3f7b2c67915ULL), K(0xc67178f2e372532bULL), | 1121 | K(0xbef9a3f7b2c67915ULL), K(0xc67178f2e372532bULL), |
1112 | #if NEED_SHA512 /* [64]+ are used for sha512 only */ | 1122 | #if NEED_SHA512 /* [64]+ are used for sha384 and sha512 only */ |
1113 | K(0xca273eceea26619cULL), K(0xd186b8c721c0c207ULL), | 1123 | K(0xca273eceea26619cULL), K(0xd186b8c721c0c207ULL), |
1114 | K(0xeada7dd6cde0eb1eULL), K(0xf57d4f7fee6ed178ULL), | 1124 | K(0xeada7dd6cde0eb1eULL), K(0xf57d4f7fee6ed178ULL), |
1115 | K(0x06f067aa72176fbaULL), K(0x0a637dc5a2c898a6ULL), | 1125 | K(0x06f067aa72176fbaULL), K(0x0a637dc5a2c898a6ULL), |
@@ -1306,11 +1316,20 @@ static const uint32_t init512_lo[] ALIGN4 = { | |||
1306 | 0x137e2179, | 1316 | 0x137e2179, |
1307 | }; | 1317 | }; |
1308 | #endif /* NEED_SHA512 */ | 1318 | #endif /* NEED_SHA512 */ |
1309 | 1319 | #if ENABLE_SHA384SUM | |
1310 | // Note: SHA-384 is identical to SHA-512, except that initial hash values are | 1320 | static const uint64_t init384[] ALIGN8 = { |
1311 | // 0xcbbb9d5dc1059ed8, 0x629a292a367cd507, 0x9159015a3070dd17, 0x152fecd8f70e5939, | 1321 | 0, |
1312 | // 0x67332667ffc00b31, 0x8eb44a8768581511, 0xdb0c2e0d64f98fa7, 0x47b5481dbefa4fa4, | 1322 | 0, |
1313 | // and the output is constructed by omitting last two 64-bit words of it. | 1323 | 0xcbbb9d5dc1059ed8, |
1324 | 0x629a292a367cd507, | ||
1325 | 0x9159015a3070dd17, | ||
1326 | 0x152fecd8f70e5939, | ||
1327 | 0x67332667ffc00b31, | ||
1328 | 0x8eb44a8768581511, | ||
1329 | 0xdb0c2e0d64f98fa7, | ||
1330 | 0x47b5481dbefa4fa4, | ||
1331 | }; | ||
1332 | #endif | ||
1314 | 1333 | ||
1315 | /* Initialize structure containing state of computation. | 1334 | /* Initialize structure containing state of computation. |
1316 | (FIPS 180-2:5.3.2) */ | 1335 | (FIPS 180-2:5.3.2) */ |
@@ -1332,9 +1351,19 @@ void FAST_FUNC sha256_begin(sha256_ctx_t *ctx) | |||
1332 | #endif | 1351 | #endif |
1333 | } | 1352 | } |
1334 | 1353 | ||
1335 | #if NEED_SHA512 | 1354 | #if ENABLE_SHA384SUM |
1336 | /* Initialize structure containing state of computation. | 1355 | /* Initialize structure containing state of computation. |
1337 | (FIPS 180-2:5.3.3) */ | 1356 | (FIPS 180-2:5.3.3) */ |
1357 | void FAST_FUNC sha384_begin(sha512_ctx_t *ctx) | ||
1358 | { | ||
1359 | memcpy(&ctx->total64, init384, sizeof(init384)); | ||
1360 | /*ctx->total64[0] = ctx->total64[1] = 0; - already done */ | ||
1361 | } | ||
1362 | #endif | ||
1363 | |||
1364 | #if NEED_SHA512 | ||
1365 | /* Initialize structure containing state of computation. | ||
1366 | (FIPS 180-2:5.3.4) */ | ||
1338 | void FAST_FUNC sha512_begin(sha512_ctx_t *ctx) | 1367 | void FAST_FUNC sha512_begin(sha512_ctx_t *ctx) |
1339 | { | 1368 | { |
1340 | int i; | 1369 | int i; |
@@ -1409,7 +1438,7 @@ unsigned FAST_FUNC sha1_end(sha1_ctx_t *ctx, void *resbuf) | |||
1409 | } | 1438 | } |
1410 | 1439 | ||
1411 | #if NEED_SHA512 | 1440 | #if NEED_SHA512 |
1412 | unsigned FAST_FUNC sha512_end(sha512_ctx_t *ctx, void *resbuf) | 1441 | static unsigned FAST_FUNC sha512384_end(sha512_ctx_t *ctx, void *resbuf, unsigned outsize) |
1413 | { | 1442 | { |
1414 | unsigned bufpos = ctx->total64[0] & 127; | 1443 | unsigned bufpos = ctx->total64[0] & 127; |
1415 | 1444 | ||
@@ -1440,12 +1469,22 @@ unsigned FAST_FUNC sha512_end(sha512_ctx_t *ctx, void *resbuf) | |||
1440 | for (i = 0; i < ARRAY_SIZE(ctx->hash); ++i) | 1469 | for (i = 0; i < ARRAY_SIZE(ctx->hash); ++i) |
1441 | ctx->hash[i] = SWAP_BE64(ctx->hash[i]); | 1470 | ctx->hash[i] = SWAP_BE64(ctx->hash[i]); |
1442 | } | 1471 | } |
1443 | memcpy(resbuf, ctx->hash, sizeof(ctx->hash)); | 1472 | memcpy(resbuf, ctx->hash, outsize); |
1444 | return sizeof(ctx->hash); | 1473 | return outsize; |
1474 | } | ||
1475 | unsigned FAST_FUNC sha512_end(sha384_ctx_t *ctx, void *resbuf) | ||
1476 | { | ||
1477 | return sha512384_end(ctx, resbuf, SHA512_OUTSIZE); | ||
1445 | } | 1478 | } |
1446 | #endif /* NEED_SHA512 */ | 1479 | #endif /* NEED_SHA512 */ |
1447 | #endif /* !ENABLE_FEATURE_USE_CNG_API */ | ||
1448 | 1480 | ||
1481 | #if ENABLE_SHA384SUM | ||
1482 | unsigned FAST_FUNC sha384_end(sha384_ctx_t *ctx, void *resbuf) | ||
1483 | { | ||
1484 | return sha512384_end(ctx, resbuf, SHA384_OUTSIZE); | ||
1485 | } | ||
1486 | #endif | ||
1487 | #endif /* !ENABLE_FEATURE_USE_CNG_API */ | ||
1449 | 1488 | ||
1450 | /* | 1489 | /* |
1451 | * The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, | 1490 | * The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, |
@@ -1982,6 +2021,8 @@ void FAST_FUNC sha3_hash(sha3_ctx_t *ctx, const void *buffer, size_t len) | |||
1982 | 2021 | ||
1983 | unsigned FAST_FUNC sha3_end(sha3_ctx_t *ctx, void *resbuf) | 2022 | unsigned FAST_FUNC sha3_end(sha3_ctx_t *ctx, void *resbuf) |
1984 | { | 2023 | { |
2024 | unsigned hash_len; | ||
2025 | |||
1985 | /* Padding */ | 2026 | /* Padding */ |
1986 | uint8_t *buf = (uint8_t*)ctx->state; | 2027 | uint8_t *buf = (uint8_t*)ctx->state; |
1987 | /* | 2028 | /* |
@@ -2004,6 +2045,7 @@ unsigned FAST_FUNC sha3_end(sha3_ctx_t *ctx, void *resbuf) | |||
2004 | sha3_process_block72(ctx->state); | 2045 | sha3_process_block72(ctx->state); |
2005 | 2046 | ||
2006 | /* Output */ | 2047 | /* Output */ |
2007 | memcpy(resbuf, ctx->state, 64); | 2048 | hash_len = (1600/8 - ctx->input_block_bytes) / 2; |
2008 | return 64; | 2049 | memcpy(resbuf, ctx->state, hash_len); |
2050 | return hash_len; | ||
2009 | } | 2051 | } |
diff --git a/libbb/lineedit.c b/libbb/lineedit.c index c8a0f37fe..77207a427 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c | |||
@@ -1754,7 +1754,7 @@ void FAST_FUNC save_history(line_input_t *st) | |||
1754 | FILE *fp; | 1754 | FILE *fp; |
1755 | 1755 | ||
1756 | /* bash compat: HISTFILE="" disables history saving */ | 1756 | /* bash compat: HISTFILE="" disables history saving */ |
1757 | if (!st || !st->hist_file || !state->hist_file[0]) | 1757 | if (!st || !st->hist_file || !st->hist_file[0]) |
1758 | return; | 1758 | return; |
1759 | if (st->cnt_history <= st->cnt_history_in_file) | 1759 | if (st->cnt_history <= st->cnt_history_in_file) |
1760 | return; /* no new entries were added */ | 1760 | return; /* no new entries were added */ |
diff --git a/libbb/procps.c b/libbb/procps.c index 8c9cac125..c751100bc 100644 --- a/libbb/procps.c +++ b/libbb/procps.c | |||
@@ -110,7 +110,7 @@ void FAST_FUNC free_procps_scan(procps_status_t* sp) | |||
110 | } | 110 | } |
111 | 111 | ||
112 | #if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP | 112 | #if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP |
113 | static unsigned long long fast_strtoull_16(char **endptr) | 113 | unsigned long long FAST_FUNC fast_strtoull_16(char **endptr) |
114 | { | 114 | { |
115 | unsigned char c; | 115 | unsigned char c; |
116 | char *str = *endptr; | 116 | char *str = *endptr; |
@@ -131,7 +131,7 @@ static unsigned long long fast_strtoull_16(char **endptr) | |||
131 | 131 | ||
132 | #if ENABLE_FEATURE_FAST_TOP || ENABLE_FEATURE_TOPMEM || ENABLE_PMAP | 132 | #if ENABLE_FEATURE_FAST_TOP || ENABLE_FEATURE_TOPMEM || ENABLE_PMAP |
133 | /* We cut a lot of corners here for speed */ | 133 | /* We cut a lot of corners here for speed */ |
134 | static unsigned long fast_strtoul_10(char **endptr) | 134 | unsigned long FAST_FUNC fast_strtoul_10(char **endptr) |
135 | { | 135 | { |
136 | unsigned char c; | 136 | unsigned char c; |
137 | char *str = *endptr; | 137 | char *str = *endptr; |
@@ -144,6 +144,24 @@ static unsigned long fast_strtoul_10(char **endptr) | |||
144 | *endptr = str + 1; /* We skip trailing space! */ | 144 | *endptr = str + 1; /* We skip trailing space! */ |
145 | return n; | 145 | return n; |
146 | } | 146 | } |
147 | # if LONG_MAX < LLONG_MAX | ||
148 | /* For VSZ, which can be very large */ | ||
149 | static unsigned long long fast_strtoull_10(char **endptr) | ||
150 | { | ||
151 | unsigned char c; | ||
152 | char *str = *endptr; | ||
153 | unsigned long long n = *str - '0'; | ||
154 | |||
155 | /* Need to stop on both ' ' and '\n' */ | ||
156 | while ((c = *++str) > ' ') | ||
157 | n = n*10 + (c - '0'); | ||
158 | |||
159 | *endptr = str + 1; /* We skip trailing space! */ | ||
160 | return n; | ||
161 | } | ||
162 | # else | ||
163 | # define fast_strtoull_10(endptr) fast_strtoul_10(endptr) | ||
164 | # endif | ||
147 | 165 | ||
148 | # if ENABLE_FEATURE_FAST_TOP | 166 | # if ENABLE_FEATURE_FAST_TOP |
149 | static long fast_strtol_10(char **endptr) | 167 | static long fast_strtol_10(char **endptr) |
@@ -156,7 +174,7 @@ static long fast_strtol_10(char **endptr) | |||
156 | } | 174 | } |
157 | # endif | 175 | # endif |
158 | 176 | ||
159 | static char *skip_fields(char *str, int count) | 177 | char* FAST_FUNC skip_fields(char *str, int count) |
160 | { | 178 | { |
161 | do { | 179 | do { |
162 | while (*str++ != ' ') | 180 | while (*str++ != ' ') |
@@ -167,35 +185,25 @@ static char *skip_fields(char *str, int count) | |||
167 | } | 185 | } |
168 | #endif | 186 | #endif |
169 | 187 | ||
170 | #if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP | 188 | #if ENABLE_FEATURE_TOPMEM |
171 | static char* skip_whitespace_if_prefixed_with(char *buf, const char *prefix) | 189 | static NOINLINE void procps_read_smaps(pid_t pid, procps_status_t *sp) |
172 | { | 190 | { |
173 | char *tp = is_prefixed_with(buf, prefix); | 191 | // There is A LOT of /proc/PID/smaps data on a big system. |
174 | if (tp) { | 192 | // Optimize this for speed, makes "top -m" faster. |
175 | tp = skip_whitespace(tp); | 193 | //TODO large speedup: |
176 | } | 194 | //read /proc/PID/smaps_rollup (cumulative stats of all mappings, much faster) |
177 | return tp; | 195 | //and /proc/PID/maps to get mapped_ro and mapped_rw (IOW: VSZ,VSZRW) |
178 | } | ||
179 | 196 | ||
180 | int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total, | ||
181 | void (*cb)(struct smaprec *, void *), void *data) | ||
182 | { | ||
183 | FILE *file; | 197 | FILE *file; |
184 | struct smaprec currec; | ||
185 | char filename[sizeof("/proc/%u/smaps") + sizeof(int)*3]; | 198 | char filename[sizeof("/proc/%u/smaps") + sizeof(int)*3]; |
186 | char buf[PROCPS_BUFSIZE]; | 199 | char buf[PROCPS_BUFSIZE]; |
187 | #if !ENABLE_PMAP | ||
188 | void (*cb)(struct smaprec *, void *) = NULL; | ||
189 | void *data = NULL; | ||
190 | #endif | ||
191 | 200 | ||
192 | sprintf(filename, "/proc/%u/smaps", (int)pid); | 201 | sprintf(filename, "/proc/%u/smaps", (int)pid); |
193 | 202 | ||
194 | file = fopen_for_read(filename); | 203 | file = fopen_for_read(filename); |
195 | if (!file) | 204 | if (!file) |
196 | return 1; | 205 | return; |
197 | 206 | ||
198 | memset(&currec, 0, sizeof(currec)); | ||
199 | while (fgets(buf, PROCPS_BUFSIZE, file)) { | 207 | while (fgets(buf, PROCPS_BUFSIZE, file)) { |
200 | // Each mapping datum has this form: | 208 | // Each mapping datum has this form: |
201 | // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME | 209 | // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME |
@@ -203,80 +211,53 @@ int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total, | |||
203 | // Rss: nnn kB | 211 | // Rss: nnn kB |
204 | // ..... | 212 | // ..... |
205 | 213 | ||
206 | char *tp, *p; | 214 | char *tp; |
207 | 215 | ||
216 | if (buf[0] == 'S' || buf[0] == 'P') { | ||
208 | #define SCAN(S, X) \ | 217 | #define SCAN(S, X) \ |
209 | if ((tp = skip_whitespace_if_prefixed_with(buf, S)) != NULL) { \ | 218 | if (memcmp(buf, S, sizeof(S)-1) == 0) { \ |
210 | total->X += currec.X = fast_strtoul_10(&tp); \ | 219 | tp = skip_whitespace(buf + sizeof(S)-1); \ |
211 | continue; \ | 220 | sp->X += fast_strtoul_10(&tp); \ |
212 | } | 221 | continue; \ |
213 | if (cb) { | 222 | } |
214 | SCAN("Pss:" , smap_pss ); | 223 | SCAN("Private_Dirty:", private_dirty) |
215 | SCAN("Swap:" , smap_swap ); | 224 | SCAN("Private_Clean:", private_clean) |
216 | } | 225 | SCAN("Shared_Dirty:" , shared_dirty ) |
217 | SCAN("Private_Dirty:", private_dirty); | 226 | SCAN("Shared_Clean:" , shared_clean ) |
218 | SCAN("Private_Clean:", private_clean); | ||
219 | SCAN("Shared_Dirty:" , shared_dirty ); | ||
220 | SCAN("Shared_Clean:" , shared_clean ); | ||
221 | #undef SCAN | 227 | #undef SCAN |
228 | } | ||
222 | tp = strchr(buf, '-'); | 229 | tp = strchr(buf, '-'); |
223 | if (tp) { | 230 | if (tp) { |
224 | // We reached next mapping - the line of this form: | 231 | // We reached next mapping - the line of this form: |
225 | // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME | 232 | // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME |
226 | 233 | ||
227 | if (cb) { | 234 | char *rwx; |
228 | /* If we have a previous record, there's nothing more | 235 | unsigned long sz; |
229 | * for it, call the callback and clear currec | ||
230 | */ | ||
231 | if (currec.smap_size) | ||
232 | cb(&currec, data); | ||
233 | free(currec.smap_name); | ||
234 | } | ||
235 | memset(&currec, 0, sizeof(currec)); | ||
236 | 236 | ||
237 | *tp = ' '; | 237 | *tp = ' '; |
238 | tp = buf; | 238 | tp = buf; |
239 | currec.smap_start = fast_strtoull_16(&tp); | 239 | sz = fast_strtoull_16(&tp); // start |
240 | currec.smap_size = (fast_strtoull_16(&tp) - currec.smap_start) >> 10; | 240 | sz = (fast_strtoull_16(&tp) - sz) >> 10; // end - start |
241 | 241 | // tp -> "rw-s" string | |
242 | strncpy(currec.smap_mode, tp, sizeof(currec.smap_mode)-1); | 242 | rwx = tp; |
243 | |||
244 | // skipping "rw-s FILEOFS M:m INODE " | 243 | // skipping "rw-s FILEOFS M:m INODE " |
245 | tp = skip_whitespace(skip_fields(tp, 4)); | 244 | tp = skip_whitespace(skip_fields(tp, 4)); |
246 | // filter out /dev/something (something != zero) | 245 | // if not a device memory mapped... |
247 | if (!is_prefixed_with(tp, "/dev/") || strcmp(tp, "/dev/zero\n") == 0) { | 246 | if (memcmp(tp, "/dev/", 5) != 0 // not "/dev/something" |
248 | if (currec.smap_mode[1] == 'w') { | 247 | || strcmp(tp + 5, "zero\n") == 0 // or is "/dev/zero" (which isn't a device) |
249 | currec.mapped_rw = currec.smap_size; | 248 | ) { |
250 | total->mapped_rw += currec.smap_size; | 249 | if (rwx[1] == 'w') |
251 | } else if (currec.smap_mode[1] == '-') { | 250 | sp->mapped_rw += sz; |
252 | currec.mapped_ro = currec.smap_size; | 251 | else if (rwx[0] == 'r' || rwx[2] == 'x') |
253 | total->mapped_ro += currec.smap_size; | 252 | sp->mapped_ro += sz; |
254 | } | 253 | // else: seen "---p" mappings (mmap guard gaps?), |
254 | // do NOT account these as VSZ, they aren't really | ||
255 | } | 255 | } |
256 | |||
257 | if (strcmp(tp, "[stack]\n") == 0) | 256 | if (strcmp(tp, "[stack]\n") == 0) |
258 | total->stack += currec.smap_size; | 257 | sp->stack += sz; |
259 | if (cb) { | ||
260 | p = skip_non_whitespace(tp); | ||
261 | if (p == tp) { | ||
262 | currec.smap_name = xstrdup(" [ anon ]"); | ||
263 | } else { | ||
264 | *p = '\0'; | ||
265 | currec.smap_name = xstrdup(tp); | ||
266 | } | ||
267 | } | ||
268 | total->smap_size += currec.smap_size; | ||
269 | } | 258 | } |
270 | } | 259 | } |
271 | fclose(file); | 260 | fclose(file); |
272 | |||
273 | if (cb) { | ||
274 | if (currec.smap_size) | ||
275 | cb(&currec, data); | ||
276 | free(currec.smap_name); | ||
277 | } | ||
278 | |||
279 | return 0; | ||
280 | } | 261 | } |
281 | #endif | 262 | #endif |
282 | 263 | ||
@@ -371,7 +352,8 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |||
371 | char *cp, *comm1; | 352 | char *cp, *comm1; |
372 | int tty; | 353 | int tty; |
373 | #if !ENABLE_FEATURE_FAST_TOP | 354 | #if !ENABLE_FEATURE_FAST_TOP |
374 | unsigned long vsz, rss; | 355 | unsigned long long vsz; |
356 | unsigned long rss; | ||
375 | #endif | 357 | #endif |
376 | /* see proc(5) for some details on this */ | 358 | /* see proc(5) for some details on this */ |
377 | strcpy(filename_tail, "stat"); | 359 | strcpy(filename_tail, "stat"); |
@@ -397,7 +379,7 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |||
397 | "%ld " /* nice */ | 379 | "%ld " /* nice */ |
398 | "%*s %*s " /* timeout, it_real_value */ | 380 | "%*s %*s " /* timeout, it_real_value */ |
399 | "%lu " /* start_time */ | 381 | "%lu " /* start_time */ |
400 | "%lu " /* vsize */ | 382 | "%llu " /* vsize - can be very large */ |
401 | "%lu " /* rss */ | 383 | "%lu " /* rss */ |
402 | # if ENABLE_FEATURE_TOP_SMP_PROCESS | 384 | # if ENABLE_FEATURE_TOP_SMP_PROCESS |
403 | "%*s %*s %*s %*s %*s %*s " /*rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */ | 385 | "%*s %*s %*s %*s %*s %*s " /*rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */ |
@@ -450,7 +432,7 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |||
450 | cp = skip_fields(cp, 2); /* timeout, it_real_value */ | 432 | cp = skip_fields(cp, 2); /* timeout, it_real_value */ |
451 | sp->start_time = fast_strtoul_10(&cp); | 433 | sp->start_time = fast_strtoul_10(&cp); |
452 | /* vsz is in bytes and we want kb */ | 434 | /* vsz is in bytes and we want kb */ |
453 | sp->vsz = fast_strtoul_10(&cp) >> 10; | 435 | sp->vsz = fast_strtoull_10(&cp) >> 10; |
454 | /* vsz is in bytes but rss is in *PAGES*! Can you believe that? */ | 436 | /* vsz is in bytes but rss is in *PAGES*! Can you believe that? */ |
455 | sp->rss = fast_strtoul_10(&cp) << sp->shift_pages_to_kb; | 437 | sp->rss = fast_strtoul_10(&cp) << sp->shift_pages_to_kb; |
456 | # if ENABLE_FEATURE_TOP_SMP_PROCESS | 438 | # if ENABLE_FEATURE_TOP_SMP_PROCESS |
@@ -484,7 +466,7 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |||
484 | 466 | ||
485 | #if ENABLE_FEATURE_TOPMEM | 467 | #if ENABLE_FEATURE_TOPMEM |
486 | if (flags & PSSCAN_SMAPS) | 468 | if (flags & PSSCAN_SMAPS) |
487 | procps_read_smaps(pid, &sp->smaps, NULL, NULL); | 469 | procps_read_smaps(pid, sp); |
488 | #endif /* TOPMEM */ | 470 | #endif /* TOPMEM */ |
489 | #if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS | 471 | #if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS |
490 | if (flags & PSSCAN_RUIDGID) { | 472 | if (flags & PSSCAN_RUIDGID) { |
@@ -567,36 +549,45 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |||
567 | return sp; | 549 | return sp; |
568 | } | 550 | } |
569 | 551 | ||
570 | void FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm) | 552 | int FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm) |
571 | { | 553 | { |
572 | int sz; | 554 | int sz; |
573 | char filename[sizeof("/proc/%u/cmdline") + sizeof(int)*3]; | 555 | char filename[sizeof("/proc/%u/cmdline") + sizeof(int)*3]; |
574 | 556 | ||
575 | sprintf(filename, "/proc/%u/cmdline", pid); | 557 | sprintf(filename, "/proc/%u/cmdline", pid); |
576 | sz = open_read_close(filename, buf, col - 1); | 558 | sz = open_read_close(filename, buf, col - 1); |
559 | if (sz < 0) | ||
560 | return sz; | ||
577 | if (sz > 0) { | 561 | if (sz > 0) { |
578 | const char *base; | 562 | const char *program_basename; |
579 | int comm_len; | 563 | int comm_len; |
580 | 564 | ||
581 | buf[sz] = '\0'; | 565 | buf[sz] = '\0'; |
582 | while (--sz >= 0 && buf[sz] == '\0') | 566 | while (--sz >= 0 && buf[sz] == '\0') |
583 | continue; | 567 | continue; |
584 | /* Prevent basename("process foo/bar") = "bar" */ | 568 | |
585 | strchrnul(buf, ' ')[0] = '\0'; | 569 | /* Find "program" in "[-][/PATH/TO/]program" */ |
586 | base = bb_basename(buf); /* before we replace argv0's NUL with space */ | 570 | strchrnul(buf, ' ')[0] = '\0'; /* prevent basename("program foo/bar") = "bar" */ |
571 | program_basename = bb_basename(buf[0] == '-' ? buf + 1 : buf); | ||
572 | /* ^^^ note: must do it *before* replacing argv0's NUL with space */ | ||
573 | |||
574 | /* Prevent stuff like this: | ||
575 | * echo 'sleep 999; exit' >`printf '\ec'`; sh ?c | ||
576 | * messing up top and ps output (or worse). | ||
577 | * This also replaces NULs with spaces, converting | ||
578 | * list of NUL-strings into one string. | ||
579 | */ | ||
587 | while (sz >= 0) { | 580 | while (sz >= 0) { |
588 | if ((unsigned char)(buf[sz]) < ' ') | 581 | if ((unsigned char)(buf[sz]) < ' ') |
589 | buf[sz] = ' '; | 582 | buf[sz] = ' '; |
590 | sz--; | 583 | sz--; |
591 | } | 584 | } |
592 | if (base[0] == '-') /* "-sh" (login shell)? */ | ||
593 | base++; | ||
594 | 585 | ||
595 | /* If comm differs from argv0, prepend "{comm} ". | 586 | /* If comm differs from argv0, prepend "{comm} ". |
596 | * It allows to see thread names set by prctl(PR_SET_NAME). | 587 | * It allows to see thread names set by prctl(PR_SET_NAME). |
597 | */ | 588 | */ |
598 | if (!comm) | 589 | if (!comm) |
599 | return; | 590 | return 0; |
600 | comm_len = strlen(comm); | 591 | comm_len = strlen(comm); |
601 | /* Why compare up to comm_len, not COMM_LEN-1? | 592 | /* Why compare up to comm_len, not COMM_LEN-1? |
602 | * Well, some processes rewrite argv, and use _spaces_ there | 593 | * Well, some processes rewrite argv, and use _spaces_ there |
@@ -604,19 +595,20 @@ void FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm) | |||
604 | * I prefer to still treat argv0 "process foo bar" | 595 | * I prefer to still treat argv0 "process foo bar" |
605 | * as 'equal' to comm "process". | 596 | * as 'equal' to comm "process". |
606 | */ | 597 | */ |
607 | if (strncmp(base, comm, comm_len) != 0) { | 598 | if (strncmp(program_basename, comm, comm_len) != 0) { |
608 | comm_len += 3; | 599 | comm_len += 3; |
609 | if (col > comm_len) | 600 | if (col > comm_len) |
610 | memmove(buf + comm_len, buf, col - comm_len); | 601 | memmove(buf + comm_len, buf, col - comm_len); |
611 | snprintf(buf, col, "{%s}", comm); | 602 | snprintf(buf, col, "{%s}", comm); |
612 | if (col <= comm_len) | 603 | if (col <= comm_len) |
613 | return; | 604 | return 0; |
614 | buf[comm_len - 1] = ' '; | 605 | buf[comm_len - 1] = ' '; |
615 | buf[col - 1] = '\0'; | 606 | buf[col - 1] = '\0'; |
616 | } | 607 | } |
617 | } else { | 608 | } else { |
618 | snprintf(buf, col, "[%s]", comm ? comm : "?"); | 609 | snprintf(buf, col, "[%s]", comm ? comm : "?"); |
619 | } | 610 | } |
611 | return 0; | ||
620 | } | 612 | } |
621 | 613 | ||
622 | #endif /* ENABLE_PLATFORM_MINGW32 */ | 614 | #endif /* ENABLE_PLATFORM_MINGW32 */ |
diff --git a/libbb/replace.c b/libbb/replace.c index 6183d3e6f..bc26b04cc 100644 --- a/libbb/replace.c +++ b/libbb/replace.c | |||
@@ -46,3 +46,17 @@ char* FAST_FUNC xmalloc_substitute_string(const char *src, int count, const char | |||
46 | //dbg_msg("subst9:'%s'", buf); | 46 | //dbg_msg("subst9:'%s'", buf); |
47 | return buf; | 47 | return buf; |
48 | } | 48 | } |
49 | |||
50 | #if 0 /* inlined in libbb.h */ | ||
51 | /* Returns strlen as a bonus */ | ||
52 | size_t FAST_FUNC replace_char(char *str, char from, char to) | ||
53 | { | ||
54 | char *p = str; | ||
55 | while (*p) { | ||
56 | if (*p == from) | ||
57 | *p = to; | ||
58 | p++; | ||
59 | } | ||
60 | return p - str; | ||
61 | } | ||
62 | #endif | ||
diff --git a/libbb/yescrypt/alg-sha256.c b/libbb/yescrypt/alg-sha256.c index 20e8d1ee4..dc748c968 100644 --- a/libbb/yescrypt/alg-sha256.c +++ b/libbb/yescrypt/alg-sha256.c | |||
@@ -47,9 +47,12 @@ PBKDF2_SHA256(const uint8_t *passwd, size_t passwdlen, | |||
47 | 47 | ||
48 | /* Iterate through the blocks. */ | 48 | /* Iterate through the blocks. */ |
49 | for (i = 0; dkLen != 0; ) { | 49 | for (i = 0; dkLen != 0; ) { |
50 | uint64_t U[32 / 8]; | 50 | long U[32 / sizeof(long)]; |
51 | uint64_t T[32 / 8]; | 51 | long T[32 / sizeof(long)]; |
52 | uint64_t j; | 52 | // Do not make these ^^ uint64_t[]. Keep them long[]. |
53 | // Even though the XORing loop below is optimized out, | ||
54 | // gcc is not smart enough to realize that 64-bit alignment of the stack | ||
55 | // is no longer useful, and generates ~50 more bytes of code on i386... | ||
53 | uint32_t ivec; | 56 | uint32_t ivec; |
54 | size_t clen; | 57 | size_t clen; |
55 | int k; | 58 | int k; |
@@ -64,13 +67,15 @@ PBKDF2_SHA256(const uint8_t *passwd, size_t passwdlen, | |||
64 | //does libbb need a non-vararg version with just one (buf,len)? | 67 | //does libbb need a non-vararg version with just one (buf,len)? |
65 | 68 | ||
66 | if (c > 1) { | 69 | if (c > 1) { |
70 | //in yescrypt, c is always 1, so this if() branch is optimized out | ||
71 | uint64_t j; | ||
67 | /* T_i = U_1 ... */ | 72 | /* T_i = U_1 ... */ |
68 | memcpy(U, T, 32); | 73 | memcpy(U, T, 32); |
69 | for (j = 2; j <= c; j++) { | 74 | for (j = 2; j <= c; j++) { |
70 | /* Compute U_j. */ | 75 | /* Compute U_j. */ |
71 | hmac_peek_hash(&Phctx, (void*)U, U, 32, NULL); | 76 | hmac_peek_hash(&Phctx, (void*)U, U, 32, NULL); |
72 | /* ... xor U_j ... */ | 77 | /* ... xor U_j ... */ |
73 | for (k = 0; k < 32 / 8; k++) | 78 | for (k = 0; k < 32 / sizeof(long); k++) |
74 | T[k] ^= U[k]; | 79 | T[k] ^= U[k]; |
75 | //TODO: xorbuf32_aligned_long(T, U); | 80 | //TODO: xorbuf32_aligned_long(T, U); |
76 | } | 81 | } |
diff --git a/miscutils/crond.c b/miscutils/crond.c index 96131cae4..6a384fdfb 100644 --- a/miscutils/crond.c +++ b/miscutils/crond.c | |||
@@ -989,7 +989,7 @@ static int check_completions(void) | |||
989 | if (line->cl_pid <= 0) | 989 | if (line->cl_pid <= 0) |
990 | continue; | 990 | continue; |
991 | 991 | ||
992 | r = waitpid(line->cl_pid, NULL, WNOHANG); | 992 | r = safe_waitpid(line->cl_pid, NULL, WNOHANG); |
993 | if (r < 0 || r == line->cl_pid) { | 993 | if (r < 0 || r == line->cl_pid) { |
994 | process_finished_job(file->cf_username, line); | 994 | process_finished_job(file->cf_username, line); |
995 | if (line->cl_pid == 0) { | 995 | if (line->cl_pid == 0) { |
@@ -1001,6 +1001,14 @@ static int check_completions(void) | |||
1001 | /* else: r == 0: "process is still running" */ | 1001 | /* else: r == 0: "process is still running" */ |
1002 | file->cf_has_running = 1; | 1002 | file->cf_has_running = 1; |
1003 | } | 1003 | } |
1004 | |||
1005 | /* Reap any other children we don't actively track. | ||
1006 | * Reportedly, some people run crond as init process! | ||
1007 | * Thus, we need to reap orphans, like init does. | ||
1008 | */ | ||
1009 | while (wait_any_nohang(NULL) > 0) | ||
1010 | continue; | ||
1011 | |||
1004 | //FIXME: if !file->cf_has_running && file->deleted: delete it! | 1012 | //FIXME: if !file->cf_has_running && file->deleted: delete it! |
1005 | //otherwise deleted entries will stay forever, right? | 1013 | //otherwise deleted entries will stay forever, right? |
1006 | num_still_running += file->cf_has_running; | 1014 | num_still_running += file->cf_has_running; |
diff --git a/modutils/modprobe-small.c b/modutils/modprobe-small.c index 77e42e3fb..31a215a29 100644 --- a/modutils/modprobe-small.c +++ b/modutils/modprobe-small.c | |||
@@ -186,15 +186,6 @@ static char* find_keyword(char *ptr, size_t len, const char *word) | |||
186 | return NULL; | 186 | return NULL; |
187 | } | 187 | } |
188 | 188 | ||
189 | static void replace(char *s, char what, char with) | ||
190 | { | ||
191 | while (*s) { | ||
192 | if (what == *s) | ||
193 | *s = with; | ||
194 | ++s; | ||
195 | } | ||
196 | } | ||
197 | |||
198 | static char *filename2modname(const char *filename, char *modname) | 189 | static char *filename2modname(const char *filename, char *modname) |
199 | { | 190 | { |
200 | int i; | 191 | int i; |
@@ -230,7 +221,7 @@ static char* str_2_list(const char *str) | |||
230 | dst[len] = '\0'; | 221 | dst[len] = '\0'; |
231 | memcpy(dst, str, len); | 222 | memcpy(dst, str, len); |
232 | //TODO: protect against 2+ spaces: "word word" | 223 | //TODO: protect against 2+ spaces: "word word" |
233 | replace(dst, ' ', '\0'); | 224 | replace_char(dst, ' ', '\0'); |
234 | return dst; | 225 | return dst; |
235 | } | 226 | } |
236 | 227 | ||
@@ -369,14 +360,14 @@ static int parse_module(module_info *info, const char *pathname) | |||
369 | } | 360 | } |
370 | bksp(); /* remove last ' ' */ | 361 | bksp(); /* remove last ' ' */ |
371 | info->aliases = copy_stringbuf(); | 362 | info->aliases = copy_stringbuf(); |
372 | replace(info->aliases, '-', '_'); | 363 | replace_char(info->aliases, '-', '_'); |
373 | 364 | ||
374 | /* "dependency1 depandency2" */ | 365 | /* "dependency1 depandency2" */ |
375 | reset_stringbuf(); | 366 | reset_stringbuf(); |
376 | ptr = find_keyword(module_image, len, "depends="); | 367 | ptr = find_keyword(module_image, len, "depends="); |
377 | if (ptr && *ptr) { | 368 | if (ptr && *ptr) { |
378 | replace(ptr, ',', ' '); | 369 | replace_char(ptr, ',', ' '); |
379 | replace(ptr, '-', '_'); | 370 | replace_char(ptr, '-', '_'); |
380 | dbg2_error_msg("dep:'%s'", ptr); | 371 | dbg2_error_msg("dep:'%s'", ptr); |
381 | append(ptr); | 372 | append(ptr); |
382 | } | 373 | } |
@@ -707,7 +698,7 @@ static int process_module(char *name, const char *cmdline_options) | |||
707 | 698 | ||
708 | dbg1_error_msg("process_module('%s','%s')", name, cmdline_options); | 699 | dbg1_error_msg("process_module('%s','%s')", name, cmdline_options); |
709 | 700 | ||
710 | replace(name, '-', '_'); | 701 | replace_char(name, '-', '_'); |
711 | 702 | ||
712 | dbg1_error_msg("already_loaded:%d is_remove:%d", already_loaded(name), is_remove); | 703 | dbg1_error_msg("already_loaded:%d is_remove:%d", already_loaded(name), is_remove); |
713 | 704 | ||
@@ -735,7 +726,7 @@ static int process_module(char *name, const char *cmdline_options) | |||
735 | char *opt_filename = xasprintf("/etc/modules/%s", name); | 726 | char *opt_filename = xasprintf("/etc/modules/%s", name); |
736 | options = xmalloc_open_read_close(opt_filename, NULL); | 727 | options = xmalloc_open_read_close(opt_filename, NULL); |
737 | if (options) | 728 | if (options) |
738 | replace(options, '\n', ' '); | 729 | replace_char(options, '\n', ' '); |
739 | #if ENABLE_FEATURE_CMDLINE_MODULE_OPTIONS | 730 | #if ENABLE_FEATURE_CMDLINE_MODULE_OPTIONS |
740 | if (cmdline_options) { | 731 | if (cmdline_options) { |
741 | /* NB: cmdline_options always have one leading ' ' | 732 | /* NB: cmdline_options always have one leading ' ' |
diff --git a/modutils/modprobe.c b/modutils/modprobe.c index 543f53e99..f890abe53 100644 --- a/modutils/modprobe.c +++ b/modutils/modprobe.c | |||
@@ -579,7 +579,7 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) | |||
579 | parser_t *p = config_open2(CONFIG_DEFAULT_DEPMOD_FILE, xfopen_for_read); | 579 | parser_t *p = config_open2(CONFIG_DEFAULT_DEPMOD_FILE, xfopen_for_read); |
580 | 580 | ||
581 | for (i = 0; argv[i]; i++) | 581 | for (i = 0; argv[i]; i++) |
582 | replace(argv[i], '-', '_'); | 582 | replace_char(argv[i], '-', '_'); |
583 | 583 | ||
584 | while (config_read(p, tokens, 2, 1, "# \t", PARSE_NORMAL)) { | 584 | while (config_read(p, tokens, 2, 1, "# \t", PARSE_NORMAL)) { |
585 | colon = last_char_is(tokens[0], ':'); | 585 | colon = last_char_is(tokens[0], ':'); |
diff --git a/modutils/modutils.c b/modutils/modutils.c index cbff20961..862f71f57 100644 --- a/modutils/modutils.c +++ b/modutils/modutils.c | |||
@@ -69,15 +69,6 @@ void FAST_FUNC moddb_free(module_db *db) | |||
69 | } | 69 | } |
70 | } | 70 | } |
71 | 71 | ||
72 | void FAST_FUNC replace(char *s, char what, char with) | ||
73 | { | ||
74 | while (*s) { | ||
75 | if (what == *s) | ||
76 | *s = with; | ||
77 | ++s; | ||
78 | } | ||
79 | } | ||
80 | |||
81 | int FAST_FUNC string_to_llist(char *string, llist_t **llist, const char *delim) | 72 | int FAST_FUNC string_to_llist(char *string, llist_t **llist, const char *delim) |
82 | { | 73 | { |
83 | char *tok; | 74 | char *tok; |
diff --git a/modutils/modutils.h b/modutils/modutils.h index 4a702e97c..9b05116d1 100644 --- a/modutils/modutils.h +++ b/modutils/modutils.h | |||
@@ -47,7 +47,6 @@ module_entry *moddb_get(module_db *db, const char *s) FAST_FUNC; | |||
47 | module_entry *moddb_get_or_create(module_db *db, const char *s) FAST_FUNC; | 47 | module_entry *moddb_get_or_create(module_db *db, const char *s) FAST_FUNC; |
48 | void moddb_free(module_db *db) FAST_FUNC; | 48 | void moddb_free(module_db *db) FAST_FUNC; |
49 | 49 | ||
50 | void replace(char *s, char what, char with) FAST_FUNC; | ||
51 | int string_to_llist(char *string, llist_t **llist, const char *delim) FAST_FUNC; | 50 | int string_to_llist(char *string, llist_t **llist, const char *delim) FAST_FUNC; |
52 | char *filename2modname(const char *filename, char *modname) FAST_FUNC; | 51 | char *filename2modname(const char *filename, char *modname) FAST_FUNC; |
53 | #if ENABLE_FEATURE_CMDLINE_MODULE_OPTIONS | 52 | #if ENABLE_FEATURE_CMDLINE_MODULE_OPTIONS |
diff --git a/networking/ftpd.c b/networking/ftpd.c index 0d6a289c7..c3125410e 100644 --- a/networking/ftpd.c +++ b/networking/ftpd.c | |||
@@ -190,54 +190,39 @@ struct globals { | |||
190 | } while (0) | 190 | } while (0) |
191 | 191 | ||
192 | 192 | ||
193 | /* escape_text("pfx:", str, (0xff << 8) + '\r') | ||
194 | * Duplicate 0xff, append \r ^^^^^^^^^^^^^^^^^^ | ||
195 | */ | ||
193 | static char * | 196 | static char * |
194 | escape_text(const char *prepend, const char *str, unsigned escapee) | 197 | escape_text(const char *prepend, const char *str, unsigned escapee) |
195 | { | 198 | { |
196 | unsigned retlen, remainlen, chunklen; | 199 | char *ret, *p; |
197 | char *ret, *found; | ||
198 | char append; | 200 | char append; |
199 | 201 | ||
200 | append = (char)escapee; | 202 | append = (char)escapee; |
201 | escapee >>= 8; | 203 | escapee >>= 8; |
202 | 204 | ||
203 | remainlen = strlen(str); | 205 | ret = xmalloc(strlen(prepend) + strlen(str) * 2 + 1 + 1); |
204 | retlen = strlen(prepend); | 206 | p = stpcpy(ret, prepend); |
205 | ret = xmalloc(retlen + remainlen * 2 + 1 + 1); | ||
206 | strcpy(ret, prepend); | ||
207 | 207 | ||
208 | for (;;) { | 208 | for (;;) { |
209 | found = strchrnul(str, escapee); | 209 | char *found = strchrnul(str, escapee); |
210 | chunklen = found - str + 1; | ||
211 | 210 | ||
212 | /* Copy chunk up to and including escapee (or NUL) to ret */ | 211 | /* Copy up to and including escapee (or NUL) */ |
213 | memcpy(ret + retlen, str, chunklen); | 212 | p = mempcpy(p, str, found - str + 1); |
214 | retlen += chunklen; | ||
215 | 213 | ||
216 | if (*found == '\0') { | 214 | if (*found == '\0') { |
217 | /* It wasn't escapee, it was NUL! */ | 215 | /* It wasn't escapee, it was NUL! */ |
218 | ret[retlen - 1] = append; /* replace NUL */ | ||
219 | ret[retlen] = '\0'; /* add NUL */ | ||
220 | break; | 216 | break; |
221 | } | 217 | } |
222 | ret[retlen++] = escapee; /* duplicate escapee */ | ||
223 | str = found + 1; | 218 | str = found + 1; |
219 | *p++ = escapee; /* duplicate escapee */ | ||
224 | } | 220 | } |
221 | p[-1] = append; /* replace NUL */ | ||
222 | *p = '\0'; /* add NUL */ | ||
225 | return ret; | 223 | return ret; |
226 | } | 224 | } |
227 | 225 | ||
228 | /* Returns strlen as a bonus */ | ||
229 | static unsigned | ||
230 | replace_char(char *str, char from, char to) | ||
231 | { | ||
232 | char *p = str; | ||
233 | while (*p) { | ||
234 | if (*p == from) | ||
235 | *p = to; | ||
236 | p++; | ||
237 | } | ||
238 | return p - str; | ||
239 | } | ||
240 | |||
241 | static void | 226 | static void |
242 | verbose_log(const char *str) | 227 | verbose_log(const char *str) |
243 | { | 228 | { |
diff --git a/procps/pmap.c b/procps/pmap.c index 49f7688d9..3069856a4 100644 --- a/procps/pmap.c +++ b/procps/pmap.c | |||
@@ -29,10 +29,14 @@ | |||
29 | 29 | ||
30 | #if ULLONG_MAX == 0xffffffff | 30 | #if ULLONG_MAX == 0xffffffff |
31 | # define TABS "\t" | 31 | # define TABS "\t" |
32 | # define SIZEWIDTHx "7" | ||
33 | # define SIZEWIDTH "9" | ||
32 | # define AFMTLL "8" | 34 | # define AFMTLL "8" |
33 | # define DASHES "" | 35 | # define DASHES "" |
34 | #else | 36 | #else |
35 | # define TABS "\t\t" | 37 | # define TABS "\t\t" |
38 | # define SIZEWIDTHx "15" | ||
39 | # define SIZEWIDTH "17" | ||
36 | # define AFMTLL "16" | 40 | # define AFMTLL "16" |
37 | # define DASHES "--------" | 41 | # define DASHES "--------" |
38 | #endif | 42 | #endif |
@@ -42,49 +46,145 @@ enum { | |||
42 | OPT_q = 1 << 1, | 46 | OPT_q = 1 << 1, |
43 | }; | 47 | }; |
44 | 48 | ||
45 | static void print_smaprec(struct smaprec *currec, void *data) | 49 | struct smaprec { |
46 | { | 50 | // For mixed 32/64 userspace, 32-bit pmap still needs |
47 | unsigned opt = (uintptr_t)data; | 51 | // 64-bit field here to correctly show 64-bit processes: |
52 | unsigned long long smap_start; | ||
53 | // Make size wider too: | ||
54 | // I've seen 1203765248 kb large "---p" mapping in a browser, | ||
55 | // this cuts close to 4 terabytes. | ||
56 | unsigned long long smap_size; | ||
57 | // (strictly speaking, other fields need to be wider too, | ||
58 | // but they are in kbytes, not bytes, and they hold sizes, | ||
59 | // not start addresses, sizes tend to be less than 4 terabytes) | ||
60 | unsigned long private_dirty; | ||
61 | unsigned long smap_pss, smap_swap; | ||
62 | char smap_mode[5]; | ||
63 | char *smap_name; | ||
64 | }; | ||
48 | 65 | ||
66 | // How long the filenames and command lines we want to handle? | ||
67 | #define PMAP_BUFSZ 4096 | ||
68 | |||
69 | static void print_smaprec(struct smaprec *currec) | ||
70 | { | ||
49 | printf("%0" AFMTLL "llx ", currec->smap_start); | 71 | printf("%0" AFMTLL "llx ", currec->smap_start); |
50 | 72 | ||
51 | if (opt & OPT_x) | 73 | if (option_mask32 & OPT_x) |
52 | printf("%7lu %7lu %7lu %7lu ", | 74 | printf("%7llu %7lu %7lu %7lu ", |
53 | currec->smap_size, | 75 | currec->smap_size, |
54 | currec->smap_pss, | 76 | currec->smap_pss, |
55 | currec->private_dirty, | 77 | currec->private_dirty, |
56 | currec->smap_swap); | 78 | currec->smap_swap); |
57 | else | 79 | else |
58 | printf("%7luK", currec->smap_size); | 80 | printf("%7lluK", currec->smap_size); |
59 | 81 | ||
60 | printf(" %.4s %s\n", currec->smap_mode, currec->smap_name); | 82 | printf(" %.4s %s\n", currec->smap_mode, currec->smap_name ? : " [ anon ]"); |
83 | } | ||
84 | |||
85 | /* libbb's procps_read_smaps() looks somewhat similar, | ||
86 | * but the collected information is sufficiently different | ||
87 | * that merging them into one function is not a good idea | ||
88 | * (unless you feel masochistic today). | ||
89 | */ | ||
90 | static int read_smaps(pid_t pid, char buf[PMAP_BUFSZ], struct smaprec *total) | ||
91 | { | ||
92 | FILE *file; | ||
93 | struct smaprec currec; | ||
94 | char filename[sizeof("/proc/%u/smaps") + sizeof(int)*3]; | ||
95 | |||
96 | sprintf(filename, "/proc/%u/smaps", (int)pid); | ||
97 | |||
98 | file = fopen_for_read(filename); | ||
99 | if (!file) | ||
100 | return 1; | ||
101 | |||
102 | memset(&currec, 0, sizeof(currec)); | ||
103 | while (fgets(buf, PMAP_BUFSZ, file)) { | ||
104 | // Each mapping datum has this form: | ||
105 | // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME | ||
106 | // Size: nnn kB | ||
107 | // Rss: nnn kB | ||
108 | // ..... | ||
109 | |||
110 | char *tp, *p; | ||
111 | |||
112 | if (buf[0] == 'S' || buf[0] == 'P') { | ||
113 | #define SCAN(S, X) \ | ||
114 | if (memcmp(buf, S, sizeof(S)-1) == 0) { \ | ||
115 | tp = skip_whitespace(buf + sizeof(S)-1); \ | ||
116 | total->X += currec.X = fast_strtoul_10(&tp); \ | ||
117 | continue; \ | ||
118 | } | ||
119 | SCAN("Pss:" , smap_pss ); | ||
120 | SCAN("Swap:" , smap_swap ); | ||
121 | SCAN("Private_Dirty:", private_dirty); | ||
122 | #undef SCAN | ||
123 | } | ||
124 | tp = strchr(buf, '-'); | ||
125 | if (tp) { | ||
126 | // We reached next mapping - the line of this form: | ||
127 | // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME | ||
128 | |||
129 | // If we have a previous record, there's nothing more | ||
130 | // for it, print and clear currec | ||
131 | if (currec.smap_size) | ||
132 | print_smaprec(&currec); | ||
133 | free(currec.smap_name); | ||
134 | memset(&currec, 0, sizeof(currec)); | ||
135 | |||
136 | *tp = ' '; | ||
137 | tp = buf; | ||
138 | currec.smap_start = fast_strtoull_16(&tp); | ||
139 | currec.smap_size = (fast_strtoull_16(&tp) - currec.smap_start) >> 10; | ||
140 | strncpy(currec.smap_mode, tp, sizeof(currec.smap_mode)-1); | ||
141 | |||
142 | // skipping "rw-s FILEOFS M:m INODE " | ||
143 | tp = skip_fields(tp, 4); | ||
144 | tp = skip_whitespace(tp); // there may be many spaces, can't just "tp++" | ||
145 | p = strchrnul(tp, '\n'); | ||
146 | if (p != tp) { | ||
147 | currec.smap_name = xstrndup(tp, p - tp); | ||
148 | } | ||
149 | total->smap_size += currec.smap_size; | ||
150 | } | ||
151 | } // while (got line) | ||
152 | fclose(file); | ||
153 | |||
154 | if (currec.smap_size) | ||
155 | print_smaprec(&currec); | ||
156 | free(currec.smap_name); | ||
157 | |||
158 | return 0; | ||
61 | } | 159 | } |
62 | 160 | ||
63 | static int procps_get_maps(pid_t pid, unsigned opt) | 161 | static int procps_get_maps(pid_t pid, unsigned opt) |
64 | { | 162 | { |
65 | struct smaprec total; | 163 | struct smaprec total; |
66 | int ret; | 164 | int ret; |
67 | char buf[256]; | 165 | char buf[PMAP_BUFSZ]; |
166 | |||
167 | ret = read_cmdline(buf, sizeof(buf), pid, NULL); | ||
168 | if (ret < 0) | ||
169 | return ret; | ||
68 | 170 | ||
69 | read_cmdline(buf, sizeof(buf), pid, NULL); | ||
70 | printf("%u: %s\n", (int)pid, buf); | 171 | printf("%u: %s\n", (int)pid, buf); |
71 | 172 | ||
72 | if (!(opt & OPT_q) && (opt & OPT_x)) | 173 | if (!(opt & OPT_q) && (opt & OPT_x)) |
73 | puts("Address" TABS " Kbytes PSS Dirty Swap Mode Mapping"); | 174 | puts("Address" TABS " Kbytes PSS Dirty Swap Mode Mapping"); |
74 | 175 | ||
75 | memset(&total, 0, sizeof(total)); | 176 | memset(&total, 0, sizeof(total)); |
76 | 177 | ret = read_smaps(pid, buf, &total); | |
77 | ret = procps_read_smaps(pid, &total, print_smaprec, (void*)(uintptr_t)opt); | ||
78 | if (ret) | 178 | if (ret) |
79 | return ret; | 179 | return ret; |
80 | 180 | ||
81 | if (!(opt & OPT_q)) { | 181 | if (!(opt & OPT_q)) { |
82 | if (opt & OPT_x) | 182 | if (opt & OPT_x) |
83 | printf("--------" DASHES " ------ ------ ------ ------\n" | 183 | printf("--------" DASHES " ------ ------ ------ ------\n" |
84 | "total" TABS " %7lu %7lu %7lu %7lu\n", | 184 | "total kB %"SIZEWIDTHx"llu %7lu %7lu %7lu\n", |
85 | total.smap_size, total.smap_pss, total.private_dirty, total.smap_swap); | 185 | total.smap_size, total.smap_pss, total.private_dirty, total.smap_swap); |
86 | else | 186 | else |
87 | printf("mapped: %luK\n", total.smap_size); | 187 | printf(" total %"SIZEWIDTH"lluK\n", total.smap_size); |
88 | } | 188 | } |
89 | 189 | ||
90 | return 0; | 190 | return 0; |
diff --git a/procps/top.c b/procps/top.c index 09d31c673..96b3e2d4e 100644 --- a/procps/top.c +++ b/procps/top.c | |||
@@ -117,10 +117,15 @@ | |||
117 | 117 | ||
118 | #include "libbb.h" | 118 | #include "libbb.h" |
119 | 119 | ||
120 | #define ESC "\033" | 120 | #define ESC "\033" |
121 | #define HOME ESC"[H" | ||
122 | #define CLREOS ESC"[J" | ||
123 | #define CLREOL ESC"[K" | ||
124 | #define REVERSE ESC"[7m" | ||
125 | #define NORMAL ESC"[m" | ||
121 | 126 | ||
122 | typedef struct top_status_t { | 127 | typedef struct top_status_t { |
123 | unsigned long vsz; | 128 | unsigned long memsize; |
124 | #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE | 129 | #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE |
125 | unsigned long ticks; | 130 | unsigned long ticks; |
126 | unsigned pcpu; /* delta of ticks */ | 131 | unsigned pcpu; /* delta of ticks */ |
@@ -161,13 +166,16 @@ struct globals { | |||
161 | top_status_t *top; | 166 | top_status_t *top; |
162 | int ntop; | 167 | int ntop; |
163 | smallint inverted; | 168 | smallint inverted; |
169 | smallint not_first_line; | ||
164 | #if ENABLE_FEATURE_TOPMEM | 170 | #if ENABLE_FEATURE_TOPMEM |
165 | smallint sort_field; | 171 | smallint sort_field; |
166 | #endif | 172 | #endif |
167 | #if ENABLE_FEATURE_TOP_SMP_CPU | 173 | #if ENABLE_FEATURE_TOP_SMP_CPU |
168 | smallint smp_cpu_info; /* one/many cpu info lines? */ | 174 | smallint smp_cpu_info; /* one/many cpu info lines? */ |
169 | #endif | 175 | #endif |
170 | unsigned lines; /* screen height */ | 176 | int lines_remaining; |
177 | unsigned lines; /* screen height */ | ||
178 | unsigned scr_width; /* width, clamped <= LINE_BUF_SIZE-2 */ | ||
171 | #if ENABLE_FEATURE_TOP_INTERACTIVE | 179 | #if ENABLE_FEATURE_TOP_INTERACTIVE |
172 | struct termios initial_settings; | 180 | struct termios initial_settings; |
173 | int scroll_ofs; | 181 | int scroll_ofs; |
@@ -212,7 +220,6 @@ struct globals { | |||
212 | #define cpu_prev_jif (G.cpu_prev_jif ) | 220 | #define cpu_prev_jif (G.cpu_prev_jif ) |
213 | #define num_cpus (G.num_cpus ) | 221 | #define num_cpus (G.num_cpus ) |
214 | #define total_pcpu (G.total_pcpu ) | 222 | #define total_pcpu (G.total_pcpu ) |
215 | #define line_buf (G.line_buf ) | ||
216 | #define INIT_G() do { \ | 223 | #define INIT_G() do { \ |
217 | SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ | 224 | SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ |
218 | BUILD_BUG_ON(LINE_BUF_SIZE <= 80); \ | 225 | BUILD_BUG_ON(LINE_BUF_SIZE <= 80); \ |
@@ -241,8 +248,8 @@ static int pid_sort(top_status_t *P, top_status_t *Q) | |||
241 | static int mem_sort(top_status_t *P, top_status_t *Q) | 248 | static int mem_sort(top_status_t *P, top_status_t *Q) |
242 | { | 249 | { |
243 | /* We want to avoid unsigned->signed and truncation errors */ | 250 | /* We want to avoid unsigned->signed and truncation errors */ |
244 | if (Q->vsz < P->vsz) return -1; | 251 | if (Q->memsize < P->memsize) return -1; |
245 | return Q->vsz != P->vsz; /* 0 if ==, 1 if > */ | 252 | return Q->memsize != P->memsize; /* 0 if ==, 1 if > */ |
246 | } | 253 | } |
247 | 254 | ||
248 | 255 | ||
@@ -283,9 +290,9 @@ static NOINLINE int read_cpu_jiffy(FILE *fp, jiffy_counts_t *p_jif) | |||
283 | #endif | 290 | #endif |
284 | int ret; | 291 | int ret; |
285 | 292 | ||
286 | if (!fgets(line_buf, LINE_BUF_SIZE, fp) || line_buf[0] != 'c' /* not "cpu" */) | 293 | if (!fgets(G.line_buf, LINE_BUF_SIZE, fp) || G.line_buf[0] != 'c' /* not "cpu" */) |
287 | return 0; | 294 | return 0; |
288 | ret = sscanf(line_buf, fmt, | 295 | ret = sscanf(G.line_buf, fmt, |
289 | &p_jif->usr, &p_jif->nic, &p_jif->sys, &p_jif->idle, | 296 | &p_jif->usr, &p_jif->nic, &p_jif->sys, &p_jif->idle, |
290 | &p_jif->iowait, &p_jif->irq, &p_jif->softirq, | 297 | &p_jif->iowait, &p_jif->irq, &p_jif->softirq, |
291 | &p_jif->steal); | 298 | &p_jif->steal); |
@@ -362,7 +369,7 @@ static void do_stats(void) | |||
362 | 369 | ||
363 | get_jiffy_counts(); | 370 | get_jiffy_counts(); |
364 | total_pcpu = 0; | 371 | total_pcpu = 0; |
365 | /* total_vsz = 0; */ | 372 | /* total_memsize = 0; */ |
366 | new_hist = xmalloc(sizeof(new_hist[0]) * ntop); | 373 | new_hist = xmalloc(sizeof(new_hist[0]) * ntop); |
367 | /* | 374 | /* |
368 | * Make a pass through the data to get stats. | 375 | * Make a pass through the data to get stats. |
@@ -394,7 +401,7 @@ static void do_stats(void) | |||
394 | i = (i+1) % prev_hist_count; | 401 | i = (i+1) % prev_hist_count; |
395 | /* hist_iterations++; */ | 402 | /* hist_iterations++; */ |
396 | } while (i != last_i); | 403 | } while (i != last_i); |
397 | /* total_vsz += cur->vsz; */ | 404 | /* total_memsize += cur->memsize; */ |
398 | } | 405 | } |
399 | 406 | ||
400 | /* | 407 | /* |
@@ -407,6 +414,38 @@ static void do_stats(void) | |||
407 | 414 | ||
408 | #endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */ | 415 | #endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */ |
409 | 416 | ||
417 | static void print_line_buf(void) | ||
418 | { | ||
419 | const char *fmt; | ||
420 | |||
421 | G.lines_remaining--; | ||
422 | fmt = OPT_BATCH_MODE ? "\n""%.*s" : "\n""%.*s"CLREOL; | ||
423 | if (!G.not_first_line) { | ||
424 | G.not_first_line = 1; | ||
425 | /* Go to top */ | ||
426 | fmt = OPT_BATCH_MODE ? "%.*s" : HOME"%.*s"CLREOL; | ||
427 | } | ||
428 | printf(fmt, G.scr_width - 1, G.line_buf); | ||
429 | } | ||
430 | |||
431 | static void print_line_bold(void) | ||
432 | { | ||
433 | G.lines_remaining--; | ||
434 | //we never print first line in bold | ||
435 | // if (!G.not_first_line) { | ||
436 | // printf(OPT_BATCH_MODE ? "%.*s" : HOME"%.*s"CLREOL, G.scr_width - 1, G.line_buf); | ||
437 | // G.not_first_line = 1; | ||
438 | // } else { | ||
439 | printf(OPT_BATCH_MODE ? "\n""%.*s" : "\n"REVERSE"%.*s"NORMAL CLREOL, G.scr_width - 1, G.line_buf); | ||
440 | // } | ||
441 | } | ||
442 | |||
443 | static void print_end(void) | ||
444 | { | ||
445 | fputs_stdout(OPT_BATCH_MODE ? "\n" : CLREOS"\r"); | ||
446 | G.not_first_line = 0; /* next print will be "first line" (will clear the screen) */ | ||
447 | } | ||
448 | |||
410 | #if ENABLE_FEATURE_TOP_CPU_GLOBAL_PERCENTS && ENABLE_FEATURE_TOP_DECIMALS | 449 | #if ENABLE_FEATURE_TOP_CPU_GLOBAL_PERCENTS && ENABLE_FEATURE_TOP_DECIMALS |
411 | /* formats 7 char string (8 with terminating NUL) */ | 450 | /* formats 7 char string (8 with terminating NUL) */ |
412 | static char *fmt_100percent_8(char pbuf[8], unsigned value, unsigned total) | 451 | static char *fmt_100percent_8(char pbuf[8], unsigned value, unsigned total) |
@@ -433,7 +472,7 @@ static char *fmt_100percent_8(char pbuf[8], unsigned value, unsigned total) | |||
433 | #endif | 472 | #endif |
434 | 473 | ||
435 | #if ENABLE_FEATURE_TOP_CPU_GLOBAL_PERCENTS | 474 | #if ENABLE_FEATURE_TOP_CPU_GLOBAL_PERCENTS |
436 | static void display_cpus(int scr_width, char *scrbuf, int *lines_rem_p) | 475 | static void display_cpus(void) |
437 | { | 476 | { |
438 | /* | 477 | /* |
439 | * xxx% = (cur_jif.xxx - prev_jif.xxx) / (cur_jif.total - prev_jif.total) * 100% | 478 | * xxx% = (cur_jif.xxx - prev_jif.xxx) / (cur_jif.total - prev_jif.total) * 100% |
@@ -469,8 +508,8 @@ static void display_cpus(int scr_width, char *scrbuf, int *lines_rem_p) | |||
469 | # else | 508 | # else |
470 | /* Loop thru CPU(s) */ | 509 | /* Loop thru CPU(s) */ |
471 | n_cpu_lines = smp_cpu_info ? num_cpus : 1; | 510 | n_cpu_lines = smp_cpu_info ? num_cpus : 1; |
472 | if (n_cpu_lines > *lines_rem_p) | 511 | if (n_cpu_lines > G.lines_remaining) |
473 | n_cpu_lines = *lines_rem_p; | 512 | n_cpu_lines = G.lines_remaining; |
474 | 513 | ||
475 | for (i = 0; i < n_cpu_lines; i++) { | 514 | for (i = 0; i < n_cpu_lines; i++) { |
476 | p_jif = &cpu_jif[i]; | 515 | p_jif = &cpu_jif[i]; |
@@ -488,7 +527,7 @@ static void display_cpus(int scr_width, char *scrbuf, int *lines_rem_p) | |||
488 | CALC_STAT(softirq); | 527 | CALC_STAT(softirq); |
489 | /*CALC_STAT(steal);*/ | 528 | /*CALC_STAT(steal);*/ |
490 | 529 | ||
491 | snprintf(scrbuf, scr_width, | 530 | sprintf(G.line_buf, |
492 | /* Barely fits in 79 chars when in "decimals" mode. */ | 531 | /* Barely fits in 79 chars when in "decimals" mode. */ |
493 | # if ENABLE_FEATURE_TOP_SMP_CPU | 532 | # if ENABLE_FEATURE_TOP_SMP_CPU |
494 | "CPU%s:"FMT"usr"FMT"sys"FMT"nic"FMT"idle"FMT"io"FMT"irq"FMT"sirq", | 533 | "CPU%s:"FMT"usr"FMT"sys"FMT"nic"FMT"idle"FMT"io"FMT"irq"FMT"sirq", |
@@ -501,16 +540,15 @@ static void display_cpus(int scr_width, char *scrbuf, int *lines_rem_p) | |||
501 | /*, SHOW_STAT(steal) - what is this 'steal' thing? */ | 540 | /*, SHOW_STAT(steal) - what is this 'steal' thing? */ |
502 | /* I doubt anyone wants to know it */ | 541 | /* I doubt anyone wants to know it */ |
503 | ); | 542 | ); |
504 | puts(scrbuf); | 543 | print_line_buf(); |
505 | } | 544 | } |
506 | } | 545 | } |
507 | # undef SHOW_STAT | 546 | # undef SHOW_STAT |
508 | # undef CALC_STAT | 547 | # undef CALC_STAT |
509 | # undef FMT | 548 | # undef FMT |
510 | *lines_rem_p -= i; | ||
511 | } | 549 | } |
512 | #else /* !ENABLE_FEATURE_TOP_CPU_GLOBAL_PERCENTS */ | 550 | #else /* !ENABLE_FEATURE_TOP_CPU_GLOBAL_PERCENTS */ |
513 | # define display_cpus(scr_width, scrbuf, lines_rem) ((void)0) | 551 | # define display_cpus() ((void)0) |
514 | #endif | 552 | #endif |
515 | 553 | ||
516 | enum { | 554 | enum { |
@@ -564,52 +602,55 @@ static void parse_meminfo(unsigned long meminfo[MI_MAX]) | |||
564 | fclose(f); | 602 | fclose(f); |
565 | } | 603 | } |
566 | 604 | ||
567 | static unsigned long display_header(int scr_width, int *lines_rem_p) | 605 | static void cmdline_to_line_buf_and_print(unsigned offset, unsigned pid, const char *comm) |
606 | { | ||
607 | int width = G.scr_width - offset; | ||
608 | if (width > 1) /* wider than to fit just the NUL? */ | ||
609 | read_cmdline(G.line_buf + offset, width, pid, comm); | ||
610 | //TODO: read_cmdline() sanitizes control chars, but not chars above 0x7e | ||
611 | print_line_buf(); | ||
612 | } | ||
613 | |||
614 | static unsigned long display_header(void) | ||
568 | { | 615 | { |
569 | char scrbuf[100]; /* [80] was a bit too low on 8Gb ram box */ | ||
570 | char *buf; | 616 | char *buf; |
571 | unsigned long meminfo[MI_MAX]; | 617 | unsigned long meminfo[MI_MAX]; |
572 | 618 | ||
573 | parse_meminfo(meminfo); | 619 | parse_meminfo(meminfo); |
574 | 620 | ||
575 | /* Output memory info */ | 621 | /* Output memory info */ |
576 | if (scr_width > (int)sizeof(scrbuf)) | 622 | sprintf(G.line_buf, |
577 | scr_width = sizeof(scrbuf); | ||
578 | snprintf(scrbuf, scr_width, | ||
579 | "Mem: %luK used, %luK free, %luK shrd, %luK buff, %luK cached", | 623 | "Mem: %luK used, %luK free, %luK shrd, %luK buff, %luK cached", |
580 | meminfo[MI_MEMTOTAL] - meminfo[MI_MEMFREE], | 624 | meminfo[MI_MEMTOTAL] - meminfo[MI_MEMFREE], |
581 | meminfo[MI_MEMFREE], | 625 | meminfo[MI_MEMFREE], |
582 | meminfo[MI_MEMSHARED] + meminfo[MI_SHMEM], | 626 | meminfo[MI_MEMSHARED] + meminfo[MI_SHMEM], |
583 | meminfo[MI_BUFFERS], | 627 | meminfo[MI_BUFFERS], |
584 | meminfo[MI_CACHED]); | 628 | meminfo[MI_CACHED]); |
585 | /* Go to top & clear to the end of screen */ | 629 | print_line_buf(); |
586 | printf(OPT_BATCH_MODE ? "%s\n" : ESC"[H" ESC"[J" "%s\n", scrbuf); | ||
587 | (*lines_rem_p)--; | ||
588 | 630 | ||
589 | /* Display CPU time split as percentage of total time. | 631 | /* Display CPU time split as percentage of total time. |
590 | * This displays either a cumulative line or one line per CPU. | 632 | * This displays either a cumulative line or one line per CPU. |
591 | */ | 633 | */ |
592 | display_cpus(scr_width, scrbuf, lines_rem_p); | 634 | display_cpus(); |
593 | 635 | ||
594 | /* Read load average as a string */ | 636 | /* Read load average as a string */ |
595 | buf = stpcpy(scrbuf, "Load average: "); | 637 | buf = stpcpy(G.line_buf, "Load average: "); |
596 | open_read_close("loadavg", buf, sizeof(scrbuf) - sizeof("Load average: ")); | 638 | open_read_close("loadavg", buf, sizeof(G.line_buf) - sizeof("Load average: ")); |
597 | scrbuf[scr_width - 1] = '\0'; | 639 | G.line_buf[sizeof(G.line_buf) - 1] = '\0'; /* paranoia */ |
598 | strchrnul(buf, '\n')[0] = '\0'; | 640 | strchrnul(buf, '\n')[0] = '\0'; |
599 | puts(scrbuf); | 641 | print_line_buf(); |
600 | (*lines_rem_p)--; | ||
601 | 642 | ||
602 | return meminfo[MI_MEMTOTAL]; | 643 | return meminfo[MI_MEMTOTAL]; |
603 | } | 644 | } |
604 | 645 | ||
605 | static NOINLINE void display_process_list(int lines_rem, int scr_width) | 646 | static NOINLINE void display_process_list(void) |
606 | { | 647 | { |
607 | enum { | 648 | enum { |
608 | BITS_PER_INT = sizeof(int) * 8 | 649 | BITS_PER_INT = sizeof(int) * 8 |
609 | }; | 650 | }; |
610 | 651 | ||
611 | top_status_t *s; | 652 | top_status_t *s; |
612 | unsigned long total_memory = display_header(scr_width, &lines_rem); /* or use total_vsz? */ | 653 | unsigned long total_memory = display_header(); |
613 | /* xxx_shift and xxx_scale variables allow us to replace | 654 | /* xxx_shift and xxx_scale variables allow us to replace |
614 | * expensive divides with multiply and shift */ | 655 | * expensive divides with multiply and shift */ |
615 | unsigned pmem_shift, pmem_scale, pmem_half; | 656 | unsigned pmem_shift, pmem_scale, pmem_half; |
@@ -621,7 +662,7 @@ static NOINLINE void display_process_list(int lines_rem, int scr_width) | |||
621 | 662 | ||
622 | #if ENABLE_FEATURE_TOP_DECIMALS | 663 | #if ENABLE_FEATURE_TOP_DECIMALS |
623 | # define UPSCALE 1000 | 664 | # define UPSCALE 1000 |
624 | typedef struct { unsigned quot, rem; } bb_div_t; | 665 | typedef struct { unsigned quot, rem; } bb_div_t; |
625 | /* Used to have "div_t name = div((val), 10)" here | 666 | /* Used to have "div_t name = div((val), 10)" here |
626 | * (IOW: intended to use libc-compatible way to divide and use | 667 | * (IOW: intended to use libc-compatible way to divide and use |
627 | * both result and remainder, but musl does not inline div()...) | 668 | * both result and remainder, but musl does not inline div()...) |
@@ -629,28 +670,34 @@ typedef struct { unsigned quot, rem; } bb_div_t; | |||
629 | */ | 670 | */ |
630 | # define CALC_STAT(name, val) bb_div_t name = { (val) / 10, (val) % 10 } | 671 | # define CALC_STAT(name, val) bb_div_t name = { (val) / 10, (val) % 10 } |
631 | # define SHOW_STAT(name) name.quot, '0'+name.rem | 672 | # define SHOW_STAT(name) name.quot, '0'+name.rem |
673 | # define SANITIZE(name) if (name.quot > 99) name.quot = 99, name.rem = (unsigned char)('+' - '0') | ||
632 | # define FMT "%3u.%c" | 674 | # define FMT "%3u.%c" |
633 | #else | 675 | #else |
634 | # define UPSCALE 100 | 676 | # define UPSCALE 100 |
635 | # define CALC_STAT(name, val) unsigned name = (val) | 677 | # define CALC_STAT(name, val) unsigned name = (val) |
678 | # define SANITIZE(name) if (name > 99) name = 99 | ||
636 | # define SHOW_STAT(name) name | 679 | # define SHOW_STAT(name) name |
637 | # define FMT "%4u%%" | 680 | # define FMT "%4u%%" |
638 | #endif | 681 | #endif |
639 | 682 | ||
640 | /* what info of the processes is shown */ | 683 | strcpy(G.line_buf, " PID PPID USER STAT RSS %RSS" |
641 | printf(OPT_BATCH_MODE ? "%.*s" : ESC"[7m" "%.*s" ESC"[m", scr_width, | ||
642 | " PID PPID USER STAT VSZ %VSZ" | ||
643 | IF_FEATURE_TOP_SMP_PROCESS(" CPU") | 684 | IF_FEATURE_TOP_SMP_PROCESS(" CPU") |
644 | IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE(" %CPU") | 685 | IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE(" %CPU") |
645 | " COMMAND"); | 686 | " COMMAND"); |
646 | lines_rem--; | 687 | print_line_bold(); |
647 | 688 | ||
648 | /* | 689 | /* %RSS = s->memsize / MemTotal * 100% |
649 | * %VSZ = s->vsz/MemTotal | 690 | * Calculate this with multiply and shift. Example: |
691 | * shift = 12 | ||
692 | * scale = 100 * 0x1000 / total_memory | ||
693 | * percent_mem = (size_mem * scale) >> shift | ||
694 | * ~= (size_mem >> shift) * scale | ||
695 | * ~= (size_mem >> shift) * 100 * (1 << shift) / total_memory | ||
696 | * ~= size_mem * 100 / total_memory | ||
650 | */ | 697 | */ |
651 | pmem_shift = BITS_PER_INT-11; | 698 | pmem_shift = BITS_PER_INT-11; |
652 | pmem_scale = UPSCALE*(1U<<(BITS_PER_INT-11)) / total_memory; | 699 | pmem_scale = UPSCALE*(1U<<(BITS_PER_INT-11)) / total_memory; |
653 | /* s->vsz is in kb. we want (s->vsz * pmem_scale) to never overflow */ | 700 | /* s->memsize is in kb. we want (s->memsize * pmem_scale) to never overflow */ |
654 | while (pmem_scale >= 512) { | 701 | while (pmem_scale >= 512) { |
655 | pmem_scale /= 4; | 702 | pmem_scale /= 4; |
656 | pmem_shift -= 2; | 703 | pmem_shift -= 2; |
@@ -689,25 +736,29 @@ typedef struct { unsigned quot, rem; } bb_div_t; | |||
689 | pcpu_half = (1U << pcpu_shift) / (ENABLE_FEATURE_TOP_DECIMALS ? 20 : 2); | 736 | pcpu_half = (1U << pcpu_shift) / (ENABLE_FEATURE_TOP_DECIMALS ? 20 : 2); |
690 | /* printf(" pmem_scale=%u pcpu_scale=%u ", pmem_scale, pcpu_scale); */ | 737 | /* printf(" pmem_scale=%u pcpu_scale=%u ", pmem_scale, pcpu_scale); */ |
691 | #endif | 738 | #endif |
739 | if (G.lines_remaining > ntop - G_scroll_ofs) | ||
740 | G.lines_remaining = ntop - G_scroll_ofs; | ||
692 | 741 | ||
693 | /* Ok, all preliminary data is ready, go through the list */ | 742 | /* Ok, all preliminary data is ready, go through the list */ |
694 | scr_width += 2; /* account for leading '\n' and trailing NUL */ | ||
695 | if (lines_rem > ntop - G_scroll_ofs) | ||
696 | lines_rem = ntop - G_scroll_ofs; | ||
697 | s = top + G_scroll_ofs; | 743 | s = top + G_scroll_ofs; |
698 | while (--lines_rem >= 0) { | 744 | while (G.lines_remaining > 0) { |
699 | int n; | 745 | int n; |
700 | char *ppu; | 746 | char *ppu; |
701 | char ppubuf[sizeof(int)*3 * 2 + 12]; | 747 | char ppubuf[sizeof(int)*3 * 2 + 12]; |
702 | char vsz_str_buf[8]; | 748 | char memsize_str_buf[8]; |
703 | unsigned col; | 749 | unsigned col; |
704 | 750 | ||
705 | CALC_STAT(pmem, (s->vsz*pmem_scale + pmem_half) >> pmem_shift); | 751 | CALC_STAT(pmem, (s->memsize*pmem_scale + pmem_half) >> pmem_shift); |
706 | #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE | 752 | #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE |
707 | CALC_STAT(pcpu, (s->pcpu*pcpu_scale + pcpu_half) >> pcpu_shift); | 753 | CALC_STAT(pcpu, (s->pcpu*pcpu_scale + pcpu_half) >> pcpu_shift); |
708 | #endif | 754 | #endif |
755 | /* VSZ can be much larger than total memory | ||
756 | * (seen values close to 2Tbyte), don't try to display | ||
757 | * "uses 12345.6% of MemTotal" (won't fit the column) | ||
758 | */ | ||
759 | SANITIZE(pmem); | ||
709 | 760 | ||
710 | smart_ulltoa5(s->vsz, vsz_str_buf, " mgtpezy"); | 761 | smart_ulltoa5(s->memsize, memsize_str_buf, " mgtpezy"); |
711 | /* PID PPID USER STAT VSZ %VSZ [%CPU] COMMAND */ | 762 | /* PID PPID USER STAT VSZ %VSZ [%CPU] COMMAND */ |
712 | n = sprintf(ppubuf, "%5u %5u %-8.8s", s->pid, s->ppid, get_cached_username(s->uid)); | 763 | n = sprintf(ppubuf, "%5u %5u %-8.8s", s->pid, s->ppid, get_cached_username(s->uid)); |
713 | ppu = ppubuf; | 764 | ppu = ppubuf; |
@@ -736,27 +787,23 @@ typedef struct { unsigned quot, rem; } bb_div_t; | |||
736 | ppu[6+6+8] = '\0'; /* truncate USER */ | 787 | ppu[6+6+8] = '\0'; /* truncate USER */ |
737 | } | 788 | } |
738 | shortened: | 789 | shortened: |
739 | col = snprintf(line_buf, scr_width, | 790 | col = sprintf(G.line_buf, |
740 | "\n" "%s %s %.5s" FMT | 791 | "%s %s %.5s" FMT |
741 | IF_FEATURE_TOP_SMP_PROCESS(" %3d") | 792 | IF_FEATURE_TOP_SMP_PROCESS(" %3d") |
742 | IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE(FMT) | 793 | IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE(FMT) |
743 | " ", | 794 | " ", |
744 | ppu, | 795 | ppu, |
745 | s->state, vsz_str_buf, | 796 | s->state, memsize_str_buf, |
746 | SHOW_STAT(pmem) | 797 | SHOW_STAT(pmem) |
747 | IF_FEATURE_TOP_SMP_PROCESS(, s->last_seen_on_cpu) | 798 | IF_FEATURE_TOP_SMP_PROCESS(, s->last_seen_on_cpu) |
748 | IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE(, SHOW_STAT(pcpu)) | 799 | IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE(, SHOW_STAT(pcpu)) |
749 | ); | 800 | ); |
750 | if ((int)(scr_width - col) > 1) | 801 | cmdline_to_line_buf_and_print(col, s->pid, s->comm); |
751 | read_cmdline(line_buf + col, scr_width - col, s->pid, s->comm); | ||
752 | fputs_stdout(line_buf); | ||
753 | /* printf(" %d/%d %lld/%lld", s->pcpu, total_pcpu, | 802 | /* printf(" %d/%d %lld/%lld", s->pcpu, total_pcpu, |
754 | cur_jif.busy - prev_jif.busy, cur_jif.total - prev_jif.total); */ | 803 | cur_jif.busy - prev_jif.busy, cur_jif.total - prev_jif.total); */ |
755 | s++; | 804 | s++; |
756 | } | 805 | } |
757 | /* printf(" %d", hist_iterations); */ | 806 | /* printf(" %d", hist_iterations); */ |
758 | bb_putchar(OPT_BATCH_MODE ? '\n' : '\r'); | ||
759 | fflush_all(); | ||
760 | } | 807 | } |
761 | #undef UPSCALE | 808 | #undef UPSCALE |
762 | #undef SHOW_STAT | 809 | #undef SHOW_STAT |
@@ -828,36 +875,34 @@ static int topmem_sort(char *a, char *b) | |||
828 | } | 875 | } |
829 | 876 | ||
830 | /* display header info (meminfo / loadavg) */ | 877 | /* display header info (meminfo / loadavg) */ |
831 | static void display_topmem_header(int scr_width, int *lines_rem_p) | 878 | static void display_topmem_header(void) |
832 | { | 879 | { |
833 | unsigned long meminfo[MI_MAX]; | 880 | unsigned long meminfo[MI_MAX]; |
834 | 881 | ||
835 | parse_meminfo(meminfo); | 882 | parse_meminfo(meminfo); |
836 | 883 | ||
837 | snprintf(line_buf, LINE_BUF_SIZE, | 884 | sprintf(G.line_buf, |
838 | "Mem total:%lu anon:%lu map:%lu free:%lu", | 885 | "Mem total:%lu anon:%lu map:%lu free:%lu", |
839 | meminfo[MI_MEMTOTAL], | 886 | meminfo[MI_MEMTOTAL], |
840 | meminfo[MI_ANONPAGES], | 887 | meminfo[MI_ANONPAGES], |
841 | meminfo[MI_MAPPED], | 888 | meminfo[MI_MAPPED], |
842 | meminfo[MI_MEMFREE]); | 889 | meminfo[MI_MEMFREE]); |
843 | printf(OPT_BATCH_MODE ? "%.*s\n" : ESC"[H" ESC"[J" "%.*s\n", scr_width, line_buf); | 890 | print_line_buf(); |
844 | 891 | ||
845 | snprintf(line_buf, LINE_BUF_SIZE, | 892 | sprintf(G.line_buf, |
846 | " slab:%lu buf:%lu cache:%lu dirty:%lu write:%lu", | 893 | " slab:%lu buf:%lu cache:%lu dirty:%lu write:%lu", |
847 | meminfo[MI_SLAB], | 894 | meminfo[MI_SLAB], |
848 | meminfo[MI_BUFFERS], | 895 | meminfo[MI_BUFFERS], |
849 | meminfo[MI_CACHED], | 896 | meminfo[MI_CACHED], |
850 | meminfo[MI_DIRTY], | 897 | meminfo[MI_DIRTY], |
851 | meminfo[MI_WRITEBACK]); | 898 | meminfo[MI_WRITEBACK]); |
852 | printf("%.*s\n", scr_width, line_buf); | 899 | print_line_buf(); |
853 | 900 | ||
854 | snprintf(line_buf, LINE_BUF_SIZE, | 901 | sprintf(G.line_buf, |
855 | "Swap total:%lu free:%lu", // TODO: % used? | 902 | "Swap total:%lu free:%lu", // TODO: % used? |
856 | meminfo[MI_SWAPTOTAL], | 903 | meminfo[MI_SWAPTOTAL], |
857 | meminfo[MI_SWAPFREE]); | 904 | meminfo[MI_SWAPFREE]); |
858 | printf("%.*s\n", scr_width, line_buf); | 905 | print_line_buf(); |
859 | |||
860 | (*lines_rem_p) -= 3; | ||
861 | } | 906 | } |
862 | 907 | ||
863 | /* see http://en.wikipedia.org/wiki/Tera */ | 908 | /* see http://en.wikipedia.org/wiki/Tera */ |
@@ -870,75 +915,57 @@ static void ulltoa4_and_space(unsigned long long ul, char buf[5]) | |||
870 | smart_ulltoa4(ul, buf, " mgtpezy")[0] = ' '; | 915 | smart_ulltoa4(ul, buf, " mgtpezy")[0] = ' '; |
871 | } | 916 | } |
872 | 917 | ||
873 | static NOINLINE void display_topmem_process_list(int lines_rem, int scr_width) | 918 | static NOINLINE void display_topmem_process_list(void) |
874 | { | 919 | { |
875 | #define HDR_STR " PID VSZ VSZRW RSS (SHR) DIRTY (SHR) STACK" | ||
876 | #define MIN_WIDTH sizeof(HDR_STR) | ||
877 | const topmem_status_t *s = topmem + G_scroll_ofs; | 920 | const topmem_status_t *s = topmem + G_scroll_ofs; |
878 | char *cp, ch; | 921 | char *cp, ch; |
879 | 922 | ||
880 | display_topmem_header(scr_width, &lines_rem); | 923 | display_topmem_header(); |
881 | 924 | ||
882 | strcpy(line_buf, HDR_STR " COMMAND"); | 925 | strcpy(G.line_buf, " PID VSZ VSZRW RSS (SHR) DIRTY (SHR) STACK COMMAND"); |
883 | /* Mark the ^FIELD^ we sort by */ | 926 | /* Mark the ^FIELD^ we sort by */ |
884 | cp = &line_buf[5 + sort_field * 6]; | 927 | cp = &G.line_buf[5 + sort_field * 6]; |
885 | ch = "^_"[inverted]; | 928 | ch = "^_"[inverted]; |
886 | cp[6] = ch; | 929 | cp[6] = ch; |
887 | do *cp++ = ch; while (*cp == ' '); | 930 | do *cp++ = ch; while (*cp == ' '); |
931 | print_line_bold(); | ||
888 | 932 | ||
889 | printf(OPT_BATCH_MODE ? "%.*s" : ESC"[7m" "%.*s" ESC"[m", scr_width, line_buf); | 933 | if (G.lines_remaining > ntop - G_scroll_ofs) |
890 | lines_rem--; | 934 | G.lines_remaining = ntop - G_scroll_ofs; |
891 | 935 | while (G.lines_remaining > 0) { | |
892 | if (lines_rem > ntop - G_scroll_ofs) | ||
893 | lines_rem = ntop - G_scroll_ofs; | ||
894 | while (--lines_rem >= 0) { | ||
895 | /* PID VSZ VSZRW RSS (SHR) DIRTY (SHR) COMMAND */ | 936 | /* PID VSZ VSZRW RSS (SHR) DIRTY (SHR) COMMAND */ |
896 | int n = sprintf(line_buf, "%5u ", s->pid); | 937 | int n = sprintf(G.line_buf, "%5u ", s->pid); |
897 | if (n > 7) { | 938 | if (n > 7) { |
898 | /* PID is 7 chars long (up to 4194304) */ | 939 | /* PID is 7 chars long (up to 4194304) */ |
899 | ulltoa4_and_space(s->vsz , &line_buf[8]); | 940 | ulltoa4_and_space(s->vsz , &G.line_buf[8]); |
900 | ulltoa4_and_space(s->vszrw, &line_buf[8+5]); | 941 | ulltoa4_and_space(s->vszrw, &G.line_buf[8+5]); |
901 | /* the next field (RSS) starts at 8+10 = 3*6 */ | 942 | /* the next field (RSS) starts at 8+10 = 3*6 */ |
902 | } else { | 943 | } else { |
903 | if (n == 7) /* PID is 6 chars long */ | 944 | if (n == 7) /* PID is 6 chars long */ |
904 | ulltoa4_and_space(s->vsz, &line_buf[7]); | 945 | ulltoa4_and_space(s->vsz, &G.line_buf[7]); |
905 | /* the next field (VSZRW) starts at 7+5 = 2*6 */ | 946 | /* the next field (VSZRW) starts at 7+5 = 2*6 */ |
906 | else /* PID is 5 chars or less */ | 947 | else /* PID is 5 chars or less */ |
907 | ulltoa5_and_space(s->vsz, &line_buf[6]); | 948 | ulltoa5_and_space(s->vsz, &G.line_buf[6]); |
908 | ulltoa5_and_space(s->vszrw, &line_buf[2*6]); | 949 | ulltoa5_and_space(s->vszrw, &G.line_buf[2*6]); |
909 | } | ||
910 | ulltoa5_and_space(s->rss , &line_buf[3*6]); | ||
911 | ulltoa5_and_space(s->rss_sh , &line_buf[4*6]); | ||
912 | ulltoa5_and_space(s->dirty , &line_buf[5*6]); | ||
913 | ulltoa5_and_space(s->dirty_sh, &line_buf[6*6]); | ||
914 | ulltoa5_and_space(s->stack , &line_buf[7*6]); | ||
915 | line_buf[8*6] = '\0'; | ||
916 | if (scr_width > (int)MIN_WIDTH) { | ||
917 | read_cmdline(&line_buf[8*6], scr_width - MIN_WIDTH, s->pid, s->comm); | ||
918 | } | 950 | } |
919 | printf("\n""%.*s", scr_width, line_buf); | 951 | ulltoa5_and_space(s->rss , &G.line_buf[3*6]); |
952 | ulltoa5_and_space(s->rss_sh , &G.line_buf[4*6]); | ||
953 | ulltoa5_and_space(s->dirty , &G.line_buf[5*6]); | ||
954 | ulltoa5_and_space(s->dirty_sh, &G.line_buf[6*6]); | ||
955 | ulltoa5_and_space(s->stack , &G.line_buf[7*6]); | ||
956 | G.line_buf[8*6] = '\0'; | ||
957 | cmdline_to_line_buf_and_print(8*6, s->pid, s->comm); | ||
920 | s++; | 958 | s++; |
921 | } | 959 | } |
922 | bb_putchar(OPT_BATCH_MODE ? '\n' : '\r'); | ||
923 | fflush_all(); | ||
924 | #undef HDR_STR | ||
925 | #undef MIN_WIDTH | ||
926 | } | 960 | } |
927 | 961 | ||
928 | #else | 962 | #endif /* end TOPMEM support */ |
929 | void display_topmem_process_list(int lines_rem, int scr_width); | ||
930 | int topmem_sort(char *a, char *b); | ||
931 | #endif /* TOPMEM */ | ||
932 | |||
933 | /* | ||
934 | * end TOPMEM support | ||
935 | */ | ||
936 | 963 | ||
937 | enum { | 964 | enum { |
938 | TOP_MASK = 0 | 965 | TOP_MASK = 0 |
939 | | PSSCAN_PID | 966 | | PSSCAN_PID |
940 | | PSSCAN_PPID | 967 | | PSSCAN_PPID |
941 | | PSSCAN_VSZ | 968 | | PSSCAN_RSS |
942 | | PSSCAN_STIME | 969 | | PSSCAN_STIME |
943 | | PSSCAN_UTIME | 970 | | PSSCAN_UTIME |
944 | | PSSCAN_STATE | 971 | | PSSCAN_STATE |
@@ -950,7 +977,7 @@ enum { | |||
950 | | PSSCAN_SMAPS | 977 | | PSSCAN_SMAPS |
951 | | PSSCAN_COMM, | 978 | | PSSCAN_COMM, |
952 | EXIT_MASK = 0, | 979 | EXIT_MASK = 0, |
953 | NO_RESCAN_MASK = (unsigned)-1, | 980 | ONLY_REDRAW = (unsigned)-1, |
954 | }; | 981 | }; |
955 | 982 | ||
956 | #if ENABLE_FEATURE_TOP_INTERACTIVE | 983 | #if ENABLE_FEATURE_TOP_INTERACTIVE |
@@ -963,15 +990,22 @@ static unsigned handle_input(unsigned scan_mask, duration_t interval) | |||
963 | } | 990 | } |
964 | 991 | ||
965 | while (1) { | 992 | while (1) { |
966 | int32_t c; | 993 | int32_t c, cc; |
967 | 994 | ||
968 | c = safe_read_key(STDIN_FILENO, G.kbd_input, interval * 1000); | 995 | c = safe_read_key(STDIN_FILENO, G.kbd_input, interval * 1000); |
969 | if (c == -1 && errno != EAGAIN) { | 996 | if (c == -1) { |
970 | /* error/EOF */ | 997 | if (errno != EAGAIN) |
971 | option_mask32 |= OPT_EOF; | 998 | /* error/EOF */ |
999 | option_mask32 |= OPT_EOF; | ||
1000 | /* else: timeout - rescan and refresh */ | ||
972 | break; | 1001 | break; |
973 | } | 1002 | } |
974 | interval = 0; | 1003 | interval = 0; |
1004 | /* "continue" statements below return to do one additional | ||
1005 | * quick attempt to read a key. This prevents | ||
1006 | * long sequence of e.g. "nnnnnnnnnnnnnnnnnnnnnnnnnn" | ||
1007 | * to cause lots of rescans. | ||
1008 | */ | ||
975 | 1009 | ||
976 | if (c == initial_settings.c_cc[VINTR]) | 1010 | if (c == initial_settings.c_cc[VINTR]) |
977 | return EXIT_MASK; | 1011 | return EXIT_MASK; |
@@ -1005,9 +1039,10 @@ static unsigned handle_input(unsigned scan_mask, duration_t interval) | |||
1005 | G_scroll_ofs = ntop - 1; | 1039 | G_scroll_ofs = ntop - 1; |
1006 | if (G_scroll_ofs < 0) | 1040 | if (G_scroll_ofs < 0) |
1007 | G_scroll_ofs = 0; | 1041 | G_scroll_ofs = 0; |
1008 | return NO_RESCAN_MASK; | 1042 | return ONLY_REDRAW; |
1009 | } | 1043 | } |
1010 | 1044 | ||
1045 | cc = c; | ||
1011 | c |= 0x20; /* lowercase */ | 1046 | c |= 0x20; /* lowercase */ |
1012 | if (c == 'q') | 1047 | if (c == 'q') |
1013 | return EXIT_MASK; | 1048 | return EXIT_MASK; |
@@ -1055,9 +1090,17 @@ static unsigned handle_input(unsigned scan_mask, duration_t interval) | |||
1055 | continue; | 1090 | continue; |
1056 | } | 1091 | } |
1057 | # if ENABLE_FEATURE_TOPMEM | 1092 | # if ENABLE_FEATURE_TOPMEM |
1093 | if (cc == 'S') { | ||
1094 | if (--sort_field < 0) | ||
1095 | sort_field = NUM_SORT_FIELD - 1; | ||
1096 | if (--sort_field < 0) | ||
1097 | sort_field = NUM_SORT_FIELD - 1; | ||
1098 | } | ||
1058 | if (c == 's') { | 1099 | if (c == 's') { |
1059 | scan_mask = TOPMEM_MASK; | ||
1060 | sort_field = (sort_field + 1) % NUM_SORT_FIELD; | 1100 | sort_field = (sort_field + 1) % NUM_SORT_FIELD; |
1101 | if (scan_mask == TOPMEM_MASK) | ||
1102 | return ONLY_REDRAW; | ||
1103 | scan_mask = TOPMEM_MASK; | ||
1061 | free(prev_hist); | 1104 | free(prev_hist); |
1062 | prev_hist = NULL; | 1105 | prev_hist = NULL; |
1063 | prev_hist_count = 0; | 1106 | prev_hist_count = 0; |
@@ -1066,7 +1109,7 @@ static unsigned handle_input(unsigned scan_mask, duration_t interval) | |||
1066 | # endif | 1109 | # endif |
1067 | if (c == 'r') { | 1110 | if (c == 'r') { |
1068 | inverted ^= 1; | 1111 | inverted ^= 1; |
1069 | continue; | 1112 | return ONLY_REDRAW; |
1070 | } | 1113 | } |
1071 | # if ENABLE_FEATURE_TOP_SMP_CPU | 1114 | # if ENABLE_FEATURE_TOP_SMP_CPU |
1072 | /* procps-2.0.18 uses 'C', 3.2.7 uses '1' */ | 1115 | /* procps-2.0.18 uses 'C', 3.2.7 uses '1' */ |
@@ -1088,8 +1131,8 @@ static unsigned handle_input(unsigned scan_mask, duration_t interval) | |||
1088 | } | 1131 | } |
1089 | # endif | 1132 | # endif |
1090 | # endif | 1133 | # endif |
1091 | break; /* unknown key -> force refresh */ | 1134 | /* Unknown key. Eat remaining buffered input (if any) */ |
1092 | } | 1135 | } /* while (1) */ |
1093 | 1136 | ||
1094 | return scan_mask; | 1137 | return scan_mask; |
1095 | } | 1138 | } |
@@ -1155,7 +1198,7 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |||
1155 | { | 1198 | { |
1156 | duration_t interval; | 1199 | duration_t interval; |
1157 | int iterations; | 1200 | int iterations; |
1158 | unsigned col; | 1201 | unsigned opt; |
1159 | char *str_interval, *str_iterations; | 1202 | char *str_interval, *str_iterations; |
1160 | unsigned scan_mask = TOP_MASK; | 1203 | unsigned scan_mask = TOP_MASK; |
1161 | 1204 | ||
@@ -1172,13 +1215,13 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |||
1172 | 1215 | ||
1173 | /* all args are options; -n NUM */ | 1216 | /* all args are options; -n NUM */ |
1174 | make_all_argv_opts(argv); /* options can be specified w/o dash */ | 1217 | make_all_argv_opts(argv); /* options can be specified w/o dash */ |
1175 | col = getopt32(argv, "d:n:bHm", &str_interval, &str_iterations); | 1218 | opt = getopt32(argv, "d:n:bHm", &str_interval, &str_iterations); |
1176 | /* NB: -m and -H are accepted even if not configured */ | 1219 | /* NB: -m and -H are accepted even if not configured */ |
1177 | #if ENABLE_FEATURE_TOPMEM | 1220 | #if ENABLE_FEATURE_TOPMEM |
1178 | if (col & OPT_m) /* -m (busybox specific) */ | 1221 | if (opt & OPT_m) /* -m (busybox specific) */ |
1179 | scan_mask = TOPMEM_MASK; | 1222 | scan_mask = TOPMEM_MASK; |
1180 | #endif | 1223 | #endif |
1181 | if (col & OPT_d) { | 1224 | if (opt & OPT_d) { |
1182 | /* work around for "-d 1" -> "-d -1" done by make_all_argv_opts() */ | 1225 | /* work around for "-d 1" -> "-d -1" done by make_all_argv_opts() */ |
1183 | if (str_interval[0] == '-') | 1226 | if (str_interval[0] == '-') |
1184 | str_interval++; | 1227 | str_interval++; |
@@ -1187,18 +1230,17 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |||
1187 | if (interval > INT_MAX / 1000) | 1230 | if (interval > INT_MAX / 1000) |
1188 | interval = INT_MAX / 1000; | 1231 | interval = INT_MAX / 1000; |
1189 | } | 1232 | } |
1190 | if (col & OPT_n) { | 1233 | if (opt & OPT_n) { |
1191 | if (str_iterations[0] == '-') | 1234 | if (str_iterations[0] == '-') |
1192 | str_iterations++; | 1235 | str_iterations++; |
1193 | iterations = xatou(str_iterations); | 1236 | iterations = xatou(str_iterations); |
1194 | } | 1237 | } |
1195 | #if ENABLE_FEATURE_SHOW_THREADS | 1238 | #if ENABLE_FEATURE_SHOW_THREADS |
1196 | if (col & OPT_H) { | 1239 | if (opt & OPT_H) { |
1197 | scan_mask |= PSSCAN_TASKS; | 1240 | scan_mask |= PSSCAN_TASKS; |
1198 | } | 1241 | } |
1199 | #endif | 1242 | #endif |
1200 | 1243 | ||
1201 | /* change to /proc */ | ||
1202 | xchdir("/proc"); | 1244 | xchdir("/proc"); |
1203 | 1245 | ||
1204 | #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE | 1246 | #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE |
@@ -1226,23 +1268,22 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |||
1226 | #endif | 1268 | #endif |
1227 | 1269 | ||
1228 | while (scan_mask != EXIT_MASK) { | 1270 | while (scan_mask != EXIT_MASK) { |
1229 | IF_FEATURE_TOP_INTERACTIVE(unsigned new_mask;) | 1271 | IF_FEATURE_TOP_INTERACTIVE(unsigned new_mask = scan_mask;) |
1230 | procps_status_t *p = NULL; | 1272 | procps_status_t *p = NULL; |
1231 | 1273 | ||
1232 | if (OPT_BATCH_MODE) { | 1274 | G.lines = INT_MAX; |
1233 | G.lines = INT_MAX; | 1275 | G.scr_width = LINE_BUF_SIZE - 2; /* +2 bytes for '\n', NUL */ |
1234 | col = LINE_BUF_SIZE - 2; /* +2 bytes for '\n', NUL */ | 1276 | if (!OPT_BATCH_MODE) { |
1235 | } else { | ||
1236 | G.lines = 24; /* default */ | 1277 | G.lines = 24; /* default */ |
1237 | col = 79; | 1278 | G.scr_width = 80; |
1238 | /* We output to stdout, we need size of stdout (not stdin)! */ | 1279 | /* We output to stdout, we need size of stdout (not stdin)! */ |
1239 | get_terminal_width_height(STDOUT_FILENO, &col, &G.lines); | 1280 | get_terminal_width_height(STDOUT_FILENO, &G.scr_width, &G.lines); |
1240 | if (G.lines < 5 || col < 10) { | 1281 | if (G.lines < 5 || G.scr_width < 10) { |
1241 | sleep_for_duration(interval); | 1282 | sleep_for_duration(interval); |
1242 | continue; | 1283 | continue; |
1243 | } | 1284 | } |
1244 | if (col > LINE_BUF_SIZE - 2) | 1285 | if (G.scr_width > LINE_BUF_SIZE - 2) |
1245 | col = LINE_BUF_SIZE - 2; | 1286 | G.scr_width = LINE_BUF_SIZE - 2; |
1246 | } | 1287 | } |
1247 | 1288 | ||
1248 | /* read process IDs & status for all the processes */ | 1289 | /* read process IDs & status for all the processes */ |
@@ -1255,7 +1296,7 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |||
1255 | top = xrealloc_vector(top, 6, ntop++); | 1296 | top = xrealloc_vector(top, 6, ntop++); |
1256 | top[n].pid = p->pid; | 1297 | top[n].pid = p->pid; |
1257 | top[n].ppid = p->ppid; | 1298 | top[n].ppid = p->ppid; |
1258 | top[n].vsz = p->vsz; | 1299 | top[n].memsize = p->rss; |
1259 | #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE | 1300 | #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE |
1260 | top[n].ticks = p->stime + p->utime; | 1301 | top[n].ticks = p->stime + p->utime; |
1261 | #endif | 1302 | #endif |
@@ -1268,20 +1309,20 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |||
1268 | } | 1309 | } |
1269 | #if ENABLE_FEATURE_TOPMEM | 1310 | #if ENABLE_FEATURE_TOPMEM |
1270 | else { /* TOPMEM */ | 1311 | else { /* TOPMEM */ |
1271 | if (!(p->smaps.mapped_ro | p->smaps.mapped_rw)) | 1312 | if (!(p->mapped_ro | p->mapped_rw)) |
1272 | continue; /* kernel threads are ignored */ | 1313 | continue; /* kernel threads are ignored */ |
1273 | n = ntop; | 1314 | n = ntop; |
1274 | /* No bug here - top and topmem are the same */ | 1315 | /* No bug here - top and topmem are the same */ |
1275 | top = xrealloc_vector(topmem, 6, ntop++); | 1316 | top = xrealloc_vector(topmem, 6, ntop++); |
1276 | strcpy(topmem[n].comm, p->comm); | 1317 | strcpy(topmem[n].comm, p->comm); |
1277 | topmem[n].pid = p->pid; | 1318 | topmem[n].pid = p->pid; |
1278 | topmem[n].vsz = p->smaps.mapped_rw + p->smaps.mapped_ro; | 1319 | topmem[n].vsz = p->mapped_rw + p->mapped_ro; |
1279 | topmem[n].vszrw = p->smaps.mapped_rw; | 1320 | topmem[n].vszrw = p->mapped_rw; |
1280 | topmem[n].rss_sh = p->smaps.shared_clean + p->smaps.shared_dirty; | 1321 | topmem[n].rss_sh = p->shared_clean + p->shared_dirty; |
1281 | topmem[n].rss = p->smaps.private_clean + p->smaps.private_dirty + topmem[n].rss_sh; | 1322 | topmem[n].rss = p->private_clean + p->private_dirty + topmem[n].rss_sh; |
1282 | topmem[n].dirty = p->smaps.private_dirty + p->smaps.shared_dirty; | 1323 | topmem[n].dirty = p->private_dirty + p->shared_dirty; |
1283 | topmem[n].dirty_sh = p->smaps.shared_dirty; | 1324 | topmem[n].dirty_sh = p->shared_dirty; |
1284 | topmem[n].stack = p->smaps.stack; | 1325 | topmem[n].stack = p->stack; |
1285 | } | 1326 | } |
1286 | #endif | 1327 | #endif |
1287 | } /* end of "while we read /proc" */ | 1328 | } /* end of "while we read /proc" */ |
@@ -1310,30 +1351,40 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |||
1310 | qsort(topmem, ntop, sizeof(topmem_status_t), (void*)topmem_sort); | 1351 | qsort(topmem, ntop, sizeof(topmem_status_t), (void*)topmem_sort); |
1311 | } | 1352 | } |
1312 | #endif | 1353 | #endif |
1313 | IF_FEATURE_TOP_INTERACTIVE(display:) | 1354 | IF_FEATURE_TOP_INTERACTIVE(redraw:) |
1355 | G.lines_remaining = G.lines; | ||
1314 | IF_FEATURE_TOPMEM(if (scan_mask != TOPMEM_MASK)) { | 1356 | IF_FEATURE_TOPMEM(if (scan_mask != TOPMEM_MASK)) { |
1315 | display_process_list(G.lines, col); | 1357 | display_process_list(); |
1316 | } | 1358 | } |
1317 | #if ENABLE_FEATURE_TOPMEM | 1359 | #if ENABLE_FEATURE_TOPMEM |
1318 | else { /* TOPMEM */ | 1360 | else { /* TOPMEM */ |
1319 | display_topmem_process_list(G.lines, col); | 1361 | display_topmem_process_list(); |
1320 | } | 1362 | } |
1321 | #endif | 1363 | #endif |
1364 | print_end(); | ||
1365 | fflush_all(); | ||
1322 | if (iterations >= 0 && !--iterations) | 1366 | if (iterations >= 0 && !--iterations) |
1323 | break; | 1367 | break; |
1324 | #if !ENABLE_FEATURE_TOP_INTERACTIVE | 1368 | #if !ENABLE_FEATURE_TOP_INTERACTIVE |
1325 | clearmems(); | 1369 | clearmems(); |
1326 | sleep_for_duration(interval); | 1370 | sleep_for_duration(interval); |
1327 | #else | 1371 | #else |
1328 | new_mask = handle_input(scan_mask, interval); | 1372 | new_mask = handle_input(scan_mask, |
1329 | if (new_mask == NO_RESCAN_MASK) | 1373 | /* After "redraw with no rescan", have one |
1330 | goto display; | 1374 | * key timeout shorter that normal |
1375 | * (IOW: rescan sooner): | ||
1376 | */ | ||
1377 | (new_mask == ONLY_REDRAW ? 1 : interval) | ||
1378 | ); | ||
1379 | if (new_mask == ONLY_REDRAW) | ||
1380 | goto redraw; | ||
1331 | scan_mask = new_mask; | 1381 | scan_mask = new_mask; |
1332 | clearmems(); | 1382 | clearmems(); |
1333 | #endif | 1383 | #endif |
1334 | } /* end of "while (not Q)" */ | 1384 | } /* end of "while (not Q)" */ |
1335 | 1385 | ||
1336 | bb_putchar('\n'); | 1386 | if (!OPT_BATCH_MODE) |
1387 | bb_putchar('\n'); | ||
1337 | #if ENABLE_FEATURE_TOP_INTERACTIVE | 1388 | #if ENABLE_FEATURE_TOP_INTERACTIVE |
1338 | reset_term(); | 1389 | reset_term(); |
1339 | #endif | 1390 | #endif |
diff --git a/shell/ash.c b/shell/ash.c index 0038aa1e9..605215e41 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -461,7 +461,7 @@ static void forkshell_print(FILE *fp0, struct forkshell *fs, const char **notes) | |||
461 | 461 | ||
462 | /* ============ Shell options */ | 462 | /* ============ Shell options */ |
463 | 463 | ||
464 | /* If you add/change options hare, update --help text too */ | 464 | /* If you add/change options here, update --help text too */ |
465 | static const char *const optletters_optnames[] ALIGN_PTR = { | 465 | static const char *const optletters_optnames[] ALIGN_PTR = { |
466 | "e" "errexit", | 466 | "e" "errexit", |
467 | "f" "noglob", | 467 | "f" "noglob", |
@@ -1822,7 +1822,6 @@ struct stackmark { | |||
1822 | size_t stacknleft; | 1822 | size_t stacknleft; |
1823 | }; | 1823 | }; |
1824 | 1824 | ||
1825 | |||
1826 | struct globals_memstack { | 1825 | struct globals_memstack { |
1827 | struct stack_block *g_stackp; // = &stackbase; | 1826 | struct stack_block *g_stackp; // = &stackbase; |
1828 | char *g_stacknxt; // = stackbase.space; | 1827 | char *g_stacknxt; // = stackbase.space; |
@@ -1845,7 +1844,6 @@ extern struct globals_memstack *BB_GLOBAL_CONST ash_ptr_to_globals_memstack; | |||
1845 | sstrend = stackbase.space + MINSIZE; \ | 1844 | sstrend = stackbase.space + MINSIZE; \ |
1846 | } while (0) | 1845 | } while (0) |
1847 | 1846 | ||
1848 | |||
1849 | #define stackblock() ((void *)g_stacknxt) | 1847 | #define stackblock() ((void *)g_stacknxt) |
1850 | #define stackblocksize() g_stacknleft | 1848 | #define stackblocksize() g_stacknleft |
1851 | 1849 | ||
@@ -2362,7 +2360,6 @@ struct localvar { | |||
2362 | # define VIMPORT 0x400 /* variable was imported from environment */ | 2360 | # define VIMPORT 0x400 /* variable was imported from environment */ |
2363 | #endif | 2361 | #endif |
2364 | 2362 | ||
2365 | |||
2366 | /* Need to be before varinit_data[] */ | 2363 | /* Need to be before varinit_data[] */ |
2367 | #if ENABLE_LOCALE_SUPPORT | 2364 | #if ENABLE_LOCALE_SUPPORT |
2368 | static void FAST_FUNC | 2365 | static void FAST_FUNC |
@@ -3582,7 +3579,6 @@ pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
3582 | 3579 | ||
3583 | /* ============ ... */ | 3580 | /* ============ ... */ |
3584 | 3581 | ||
3585 | |||
3586 | #define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024) | 3582 | #define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024) |
3587 | 3583 | ||
3588 | /* Syntax classes */ | 3584 | /* Syntax classes */ |
@@ -3989,13 +3985,11 @@ struct alias { | |||
3989 | int flag; | 3985 | int flag; |
3990 | }; | 3986 | }; |
3991 | 3987 | ||
3992 | |||
3993 | static struct alias **atab; // [ATABSIZE]; | 3988 | static struct alias **atab; // [ATABSIZE]; |
3994 | #define INIT_G_alias() do { \ | 3989 | #define INIT_G_alias() do { \ |
3995 | atab = xzalloc(ATABSIZE * sizeof(atab[0])); \ | 3990 | atab = xzalloc(ATABSIZE * sizeof(atab[0])); \ |
3996 | } while (0) | 3991 | } while (0) |
3997 | 3992 | ||
3998 | |||
3999 | static struct alias ** | 3993 | static struct alias ** |
4000 | __lookupalias(const char *name) | 3994 | __lookupalias(const char *name) |
4001 | { | 3995 | { |
@@ -4177,7 +4171,6 @@ unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
4177 | 4171 | ||
4178 | #endif /* ASH_ALIAS */ | 4172 | #endif /* ASH_ALIAS */ |
4179 | 4173 | ||
4180 | |||
4181 | /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */ | 4174 | /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */ |
4182 | #define FORK_FG 0 | 4175 | #define FORK_FG 0 |
4183 | #define FORK_BG 1 | 4176 | #define FORK_BG 1 |
@@ -6194,7 +6187,6 @@ stoppedjobs(void) | |||
6194 | } | 6187 | } |
6195 | #endif | 6188 | #endif |
6196 | 6189 | ||
6197 | |||
6198 | /* | 6190 | /* |
6199 | * Code for dealing with input/output redirection. | 6191 | * Code for dealing with input/output redirection. |
6200 | */ | 6192 | */ |
@@ -9904,7 +9896,6 @@ commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
9904 | } | 9896 | } |
9905 | #endif | 9897 | #endif |
9906 | 9898 | ||
9907 | |||
9908 | /*static int funcblocksize; // size of structures in function */ | 9899 | /*static int funcblocksize; // size of structures in function */ |
9909 | /*static int funcstringsize; // size of strings in node */ | 9900 | /*static int funcstringsize; // size of strings in node */ |
9910 | static void *funcblock; /* block to allocate function from */ | 9901 | static void *funcblock; /* block to allocate function from */ |
@@ -11920,7 +11911,6 @@ goodname(const char *p) | |||
11920 | return endofname(p)[0] == '\0'; | 11911 | return endofname(p)[0] == '\0'; |
11921 | } | 11912 | } |
11922 | 11913 | ||
11923 | |||
11924 | /* | 11914 | /* |
11925 | * Search for a command. This is called before we fork so that the | 11915 | * Search for a command. This is called before we fork so that the |
11926 | * location of the command will be available in the parent as well as | 11916 | * location of the command will be available in the parent as well as |
@@ -14773,7 +14763,6 @@ parseheredoc(void) | |||
14773 | } | 14763 | } |
14774 | } | 14764 | } |
14775 | 14765 | ||
14776 | |||
14777 | static const char * | 14766 | static const char * |
14778 | expandstr(const char *ps, int syntax_type) | 14767 | expandstr(const char *ps, int syntax_type) |
14779 | { | 14768 | { |
@@ -15403,7 +15392,6 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
15403 | entry->u = cmdp->param; | 15392 | entry->u = cmdp->param; |
15404 | } | 15393 | } |
15405 | 15394 | ||
15406 | |||
15407 | /* | 15395 | /* |
15408 | * The trap builtin. | 15396 | * The trap builtin. |
15409 | */ | 15397 | */ |
@@ -16170,7 +16158,6 @@ init(void) | |||
16170 | } | 16158 | } |
16171 | } | 16159 | } |
16172 | 16160 | ||
16173 | |||
16174 | //usage:#define ash_trivial_usage | 16161 | //usage:#define ash_trivial_usage |
16175 | //usage: "[-il] [-|+Cabefmnuvx] [-|+o OPT]... [-c 'SCRIPT' [ARG0 ARGS] | FILE ARGS | -s ARGS]" | 16162 | //usage: "[-il] [-|+Cabefmnuvx] [-|+o OPT]... [-c 'SCRIPT' [ARG0 ARGS] | FILE ARGS | -s ARGS]" |
16176 | //////// comes from ^^^^^^^^^^optletters | 16163 | //////// comes from ^^^^^^^^^^optletters |
diff --git a/shell/hush.c b/shell/hush.c index d1f687f9d..09ab6ebc0 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -392,6 +392,8 @@ | |||
392 | 392 | ||
393 | /* Build knobs */ | 393 | /* Build knobs */ |
394 | #define LEAK_HUNTING 0 | 394 | #define LEAK_HUNTING 0 |
395 | #define LEAK_PRINTF(...) fdprintf(__VA_ARGS__) | ||
396 | //#define LEAK_PRINTF(...) do { if (ptr_to_globals && G.root_pid == getpid()) fdprintf(__VA_ARGS__); } while (0) | ||
395 | #define BUILD_AS_NOMMU 0 | 397 | #define BUILD_AS_NOMMU 0 |
396 | /* Enable/disable sanity checks. Ok to enable in production, | 398 | /* Enable/disable sanity checks. Ok to enable in production, |
397 | * only adds a bit of bloat. Set to >1 to get non-production level verbosity. | 399 | * only adds a bit of bloat. Set to >1 to get non-production level verbosity. |
@@ -930,6 +932,12 @@ struct globals { | |||
930 | # define G_flag_return_in_progress 0 | 932 | # define G_flag_return_in_progress 0 |
931 | #endif | 933 | #endif |
932 | smallint exiting; /* used to prevent EXIT trap recursion */ | 934 | smallint exiting; /* used to prevent EXIT trap recursion */ |
935 | #if !BB_MMU | ||
936 | smallint reexeced_on_NOMMU; | ||
937 | # define G_reexeced_on_NOMMU (G.reexeced_on_NOMMU) | ||
938 | #else | ||
939 | # define G_reexeced_on_NOMMU 0 | ||
940 | #endif | ||
933 | /* These support $? */ | 941 | /* These support $? */ |
934 | smalluint last_exitcode; | 942 | smalluint last_exitcode; |
935 | smalluint expand_exitcode; | 943 | smalluint expand_exitcode; |
@@ -1352,30 +1360,67 @@ static void debug_print_strings(const char *prefix, char **vv) | |||
1352 | static void *xxmalloc(int lineno, size_t size) | 1360 | static void *xxmalloc(int lineno, size_t size) |
1353 | { | 1361 | { |
1354 | void *ptr = xmalloc((size + 0xff) & ~0xff); | 1362 | void *ptr = xmalloc((size + 0xff) & ~0xff); |
1355 | fdprintf(2, "line %d: malloc %p\n", lineno, ptr); | 1363 | LEAK_PRINTF(2, "line %d: malloc %p\n", lineno, ptr); |
1364 | return ptr; | ||
1365 | } | ||
1366 | static void *xxzalloc(int lineno, size_t size) | ||
1367 | { | ||
1368 | void *ptr = xzalloc((size + 0xff) & ~0xff); | ||
1369 | LEAK_PRINTF(2, "line %d: zalloc %p\n", lineno, ptr); | ||
1356 | return ptr; | 1370 | return ptr; |
1357 | } | 1371 | } |
1358 | static void *xxrealloc(int lineno, void *ptr, size_t size) | 1372 | static void *xxrealloc(int lineno, void *ptr, size_t size) |
1359 | { | 1373 | { |
1374 | char *p = ptr; | ||
1360 | ptr = xrealloc(ptr, (size + 0xff) & ~0xff); | 1375 | ptr = xrealloc(ptr, (size + 0xff) & ~0xff); |
1361 | fdprintf(2, "line %d: realloc %p\n", lineno, ptr); | 1376 | if (p != ptr) |
1377 | LEAK_PRINTF(2, "line %d: realloc %p\n", lineno, ptr); | ||
1378 | return ptr; | ||
1379 | } | ||
1380 | static void *xxrealloc_getcwd_or_warn(int lineno, char *ptr) | ||
1381 | { | ||
1382 | char *p = ptr; | ||
1383 | ptr = xrealloc_getcwd_or_warn(ptr); | ||
1384 | if (p != ptr) | ||
1385 | LEAK_PRINTF(2, "line %d: xrealloc_getcwd_or_warn %p\n", lineno, ptr); | ||
1362 | return ptr; | 1386 | return ptr; |
1363 | } | 1387 | } |
1364 | static char *xxstrdup(int lineno, const char *str) | 1388 | static char *xxstrdup(int lineno, const char *str) |
1365 | { | 1389 | { |
1366 | char *ptr = xstrdup(str); | 1390 | char *ptr = xstrdup(str); |
1367 | fdprintf(2, "line %d: strdup %p\n", lineno, ptr); | 1391 | LEAK_PRINTF(2, "line %d: strdup %p\n", lineno, ptr); |
1392 | return ptr; | ||
1393 | } | ||
1394 | static char *xxstrndup(int lineno, const char *str, size_t n) | ||
1395 | { | ||
1396 | char *ptr = xstrndup(str, n); | ||
1397 | LEAK_PRINTF(2, "line %d: strndup %p\n", lineno, ptr); | ||
1398 | return ptr; | ||
1399 | } | ||
1400 | static char *xxasprintf(int lineno, const char *f, ...) | ||
1401 | { | ||
1402 | char *ptr; | ||
1403 | va_list args; | ||
1404 | va_start(args, f); | ||
1405 | if (vasprintf(&ptr, f, args) < 0) | ||
1406 | bb_die_memory_exhausted(); | ||
1407 | va_end(args); | ||
1408 | LEAK_PRINTF(2, "line %d: xasprintf %p\n", lineno, ptr); | ||
1368 | return ptr; | 1409 | return ptr; |
1369 | } | 1410 | } |
1370 | static void xxfree(void *ptr) | 1411 | static void xxfree(void *ptr) |
1371 | { | 1412 | { |
1372 | fdprintf(2, "free %p\n", ptr); | 1413 | LEAK_PRINTF(2, "free %p\n", ptr); |
1373 | free(ptr); | 1414 | free(ptr); |
1374 | } | 1415 | } |
1375 | # define xmalloc(s) xxmalloc(__LINE__, s) | 1416 | # define xmalloc(s) xxmalloc(__LINE__, s) |
1376 | # define xrealloc(p, s) xxrealloc(__LINE__, p, s) | 1417 | # define xzalloc(s) xxzalloc(__LINE__, s) |
1377 | # define xstrdup(s) xxstrdup(__LINE__, s) | 1418 | # define xrealloc(p, s) xxrealloc(__LINE__, p, s) |
1378 | # define free(p) xxfree(p) | 1419 | # define xrealloc_getcwd_or_warn(p) xxrealloc_getcwd_or_warn(__LINE__, p) |
1420 | # define xstrdup(s) xxstrdup(__LINE__, s) | ||
1421 | # define xstrndup(s, n) xxstrndup(__LINE__, s, n) | ||
1422 | # define xasprintf(f, ...) xxasprintf(__LINE__, f, __VA_ARGS__) | ||
1423 | # define free(p) xxfree(p) | ||
1379 | #endif | 1424 | #endif |
1380 | 1425 | ||
1381 | /* | 1426 | /* |
@@ -1929,7 +1974,7 @@ static void restore_G_args(save_arg_t *sv, char **argv) | |||
1929 | * "trap - SIGxxx": | 1974 | * "trap - SIGxxx": |
1930 | * if sig is in special_sig_mask, set handler back to: | 1975 | * if sig is in special_sig_mask, set handler back to: |
1931 | * record_pending_signo, or to IGN if it's a tty stop signal | 1976 | * record_pending_signo, or to IGN if it's a tty stop signal |
1932 | * if sig is in fatal_sig_mask, set handler back to sigexit. | 1977 | * if sig is in fatal_sig_mask, set handler back to restore_ttypgrp_and_killsig_or__exit. |
1933 | * else: set handler back to SIG_DFL | 1978 | * else: set handler back to SIG_DFL |
1934 | * "trap 'cmd' SIGxxx": | 1979 | * "trap 'cmd' SIGxxx": |
1935 | * set handler to record_pending_signo. | 1980 | * set handler to record_pending_signo. |
@@ -2002,19 +2047,6 @@ static sighandler_t install_sighandler(int sig, sighandler_t handler) | |||
2002 | return old_sa.sa_handler; | 2047 | return old_sa.sa_handler; |
2003 | } | 2048 | } |
2004 | 2049 | ||
2005 | static void hush_exit(int exitcode) NORETURN; | ||
2006 | |||
2007 | static void restore_ttypgrp_and__exit(void) NORETURN; | ||
2008 | static void restore_ttypgrp_and__exit(void) | ||
2009 | { | ||
2010 | /* xfunc has failed! die die die */ | ||
2011 | /* no EXIT traps, this is an escape hatch! */ | ||
2012 | G.exiting = 1; | ||
2013 | hush_exit(xfunc_error_retval); | ||
2014 | } | ||
2015 | |||
2016 | #if ENABLE_HUSH_JOB | ||
2017 | |||
2018 | /* Needed only on some libc: | 2050 | /* Needed only on some libc: |
2019 | * It was observed that on exit(), fgetc'ed buffered data | 2051 | * It was observed that on exit(), fgetc'ed buffered data |
2020 | * gets "unwound" via lseek(fd, -NUM, SEEK_CUR). | 2052 | * gets "unwound" via lseek(fd, -NUM, SEEK_CUR). |
@@ -2028,26 +2060,20 @@ static void restore_ttypgrp_and__exit(void) | |||
2028 | * and in `cmd` handling. | 2060 | * and in `cmd` handling. |
2029 | * If set as die_func(), this makes xfunc_die() exit via _exit(), not exit(): | 2061 | * If set as die_func(), this makes xfunc_die() exit via _exit(), not exit(): |
2030 | */ | 2062 | */ |
2031 | static void fflush_and__exit(void) NORETURN; | 2063 | static NORETURN void fflush_and__exit(void) |
2032 | static void fflush_and__exit(void) | ||
2033 | { | 2064 | { |
2034 | fflush_all(); | 2065 | fflush_all(); |
2035 | _exit(xfunc_error_retval); | 2066 | _exit(xfunc_error_retval); |
2036 | } | 2067 | } |
2037 | 2068 | ||
2038 | /* After [v]fork, in child: do not restore tty pgrp on xfunc death */ | 2069 | #if ENABLE_HUSH_JOB |
2039 | # define disable_restore_tty_pgrp_on_exit() (die_func = fflush_and__exit) | ||
2040 | /* After [v]fork, in parent: restore tty pgrp on xfunc death */ | ||
2041 | # define enable_restore_tty_pgrp_on_exit() (die_func = restore_ttypgrp_and__exit) | ||
2042 | |||
2043 | /* Restores tty foreground process group, and exits. | 2070 | /* Restores tty foreground process group, and exits. |
2044 | * May be called as signal handler for fatal signal | 2071 | * May be called as signal handler for fatal signal |
2045 | * (will resend signal to itself, producing correct exit state) | 2072 | * (will resend signal to itself, producing correct exit state) |
2046 | * or called directly with -EXITCODE. | 2073 | * or called directly with -EXITCODE. |
2047 | * We also call it if xfunc is exiting. | 2074 | * We also call it if xfunc is exiting. |
2048 | */ | 2075 | */ |
2049 | static void sigexit(int sig) NORETURN; | 2076 | static NORETURN void restore_ttypgrp_and_killsig_or__exit(int sig) |
2050 | static void sigexit(int sig) | ||
2051 | { | 2077 | { |
2052 | /* Careful: we can end up here after [v]fork. Do not restore | 2078 | /* Careful: we can end up here after [v]fork. Do not restore |
2053 | * tty pgrp then, only top-level shell process does that */ | 2079 | * tty pgrp then, only top-level shell process does that */ |
@@ -2065,6 +2091,19 @@ static void sigexit(int sig) | |||
2065 | 2091 | ||
2066 | kill_myself_with_sig(sig); /* does not return */ | 2092 | kill_myself_with_sig(sig); /* does not return */ |
2067 | } | 2093 | } |
2094 | |||
2095 | static NORETURN void fflush_restore_ttypgrp_and__exit(void) | ||
2096 | { | ||
2097 | /* xfunc has failed! die die die */ | ||
2098 | fflush_all(); | ||
2099 | restore_ttypgrp_and_killsig_or__exit(- xfunc_error_retval); | ||
2100 | } | ||
2101 | |||
2102 | /* After [v]fork, in child: do not restore tty pgrp on xfunc death */ | ||
2103 | # define disable_restore_tty_pgrp_on_exit() (die_func = fflush_and__exit) | ||
2104 | /* After [v]fork, in parent: restore tty pgrp on xfunc death */ | ||
2105 | # define enable_restore_tty_pgrp_on_exit() (die_func = fflush_restore_ttypgrp_and__exit) | ||
2106 | |||
2068 | #else | 2107 | #else |
2069 | 2108 | ||
2070 | # define disable_restore_tty_pgrp_on_exit() ((void)0) | 2109 | # define disable_restore_tty_pgrp_on_exit() ((void)0) |
@@ -2081,7 +2120,7 @@ static sighandler_t pick_sighandler(unsigned sig) | |||
2081 | #if ENABLE_HUSH_JOB | 2120 | #if ENABLE_HUSH_JOB |
2082 | /* is sig fatal? */ | 2121 | /* is sig fatal? */ |
2083 | if (G_fatal_sig_mask & sigmask) | 2122 | if (G_fatal_sig_mask & sigmask) |
2084 | handler = sigexit; | 2123 | handler = restore_ttypgrp_and_killsig_or__exit; |
2085 | else | 2124 | else |
2086 | #endif | 2125 | #endif |
2087 | /* sig has special handling? */ | 2126 | /* sig has special handling? */ |
@@ -2101,11 +2140,15 @@ static sighandler_t pick_sighandler(unsigned sig) | |||
2101 | 2140 | ||
2102 | static const char* FAST_FUNC get_local_var_value(const char *name); | 2141 | static const char* FAST_FUNC get_local_var_value(const char *name); |
2103 | 2142 | ||
2104 | /* Restores tty foreground process group, and exits. */ | 2143 | /* Self-explanatory. |
2105 | static void hush_exit(int exitcode) | 2144 | * Restores tty foreground process group too. |
2145 | */ | ||
2146 | static NORETURN void save_history_run_exit_trap_and_exit(int exitcode) | ||
2106 | { | 2147 | { |
2107 | #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT | 2148 | #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT |
2108 | if (G.line_input_state) { | 2149 | if (G.line_input_state |
2150 | && getpid() == G.root_pid /* exits in subshells do not save history */ | ||
2151 | ) { | ||
2109 | const char *hp; | 2152 | const char *hp; |
2110 | # if ENABLE_FEATURE_SH_HISTFILESIZE | 2153 | # if ENABLE_FEATURE_SH_HISTFILESIZE |
2111 | // in bash: | 2154 | // in bash: |
@@ -2155,7 +2198,7 @@ static void hush_exit(int exitcode) | |||
2155 | 2198 | ||
2156 | fflush_all(); | 2199 | fflush_all(); |
2157 | #if ENABLE_HUSH_JOB | 2200 | #if ENABLE_HUSH_JOB |
2158 | sigexit(- (exitcode & 0xff)); | 2201 | restore_ttypgrp_and_killsig_or__exit(- (exitcode & 0xff)); |
2159 | #else | 2202 | #else |
2160 | _exit(exitcode); | 2203 | _exit(exitcode); |
2161 | #endif | 2204 | #endif |
@@ -2240,7 +2283,7 @@ static int check_and_run_traps(void) | |||
2240 | } | 2283 | } |
2241 | } | 2284 | } |
2242 | /* this restores tty pgrp, then kills us with SIGHUP */ | 2285 | /* this restores tty pgrp, then kills us with SIGHUP */ |
2243 | sigexit(SIGHUP); | 2286 | restore_ttypgrp_and_killsig_or__exit(SIGHUP); |
2244 | } | 2287 | } |
2245 | #endif | 2288 | #endif |
2246 | #if ENABLE_HUSH_FAST | 2289 | #if ENABLE_HUSH_FAST |
@@ -7389,11 +7432,6 @@ static void switch_off_special_sigs(unsigned mask) | |||
7389 | } | 7432 | } |
7390 | 7433 | ||
7391 | #if BB_MMU | 7434 | #if BB_MMU |
7392 | /* never called */ | ||
7393 | void re_execute_shell(char ***to_free, const char *s, | ||
7394 | char *g_argv0, char **g_argv, | ||
7395 | char **builtin_argv) NORETURN; | ||
7396 | |||
7397 | static void reset_traps_to_defaults(void) | 7435 | static void reset_traps_to_defaults(void) |
7398 | { | 7436 | { |
7399 | /* This function is always called in a child shell | 7437 | /* This function is always called in a child shell |
@@ -7443,10 +7481,8 @@ static void reset_traps_to_defaults(void) | |||
7443 | 7481 | ||
7444 | #else /* !BB_MMU */ | 7482 | #else /* !BB_MMU */ |
7445 | 7483 | ||
7446 | static void re_execute_shell(char ***to_free, const char *s, | 7484 | static NORETURN void re_execute_shell( |
7447 | char *g_argv0, char **g_argv, | 7485 | char * *volatile * to_free, const char *s, |
7448 | char **builtin_argv) NORETURN; | ||
7449 | static void re_execute_shell(char ***to_free, const char *s, | ||
7450 | char *g_argv0, char **g_argv, | 7486 | char *g_argv0, char **g_argv, |
7451 | char **builtin_argv) | 7487 | char **builtin_argv) |
7452 | { | 7488 | { |
@@ -7676,7 +7712,13 @@ static int generate_stream_from_string(const char *s, pid_t *pid_p) | |||
7676 | pid_t pid; | 7712 | pid_t pid; |
7677 | int channel[2]; | 7713 | int channel[2]; |
7678 | # if !BB_MMU | 7714 | # if !BB_MMU |
7679 | char **to_free = NULL; | 7715 | /* _volatile_ pointer to "char*". |
7716 | * Or else compiler can peek from inside re_execute_shell() | ||
7717 | * and see that this pointer is a local var (i.e. not globally visible), | ||
7718 | * and decide to optimize out the store to it. Yes, | ||
7719 | * it was seen in the wild. | ||
7720 | */ | ||
7721 | char * *volatile to_free = NULL; | ||
7680 | # endif | 7722 | # endif |
7681 | 7723 | ||
7682 | xpipe(channel); | 7724 | xpipe(channel); |
@@ -7823,7 +7865,7 @@ static void setup_heredoc(struct redir_struct *redir) | |||
7823 | const char *heredoc = redir->rd_filename; | 7865 | const char *heredoc = redir->rd_filename; |
7824 | char *expanded; | 7866 | char *expanded; |
7825 | #if !BB_MMU | 7867 | #if !BB_MMU |
7826 | char **to_free; | 7868 | char * *volatile to_free; |
7827 | #endif | 7869 | #endif |
7828 | 7870 | ||
7829 | expanded = NULL; | 7871 | expanded = NULL; |
@@ -8298,7 +8340,7 @@ static const struct built_in_command *find_builtin(const char *name) | |||
8298 | return find_builtin_helper(name, bltins2, &bltins2[ARRAY_SIZE(bltins2)]); | 8340 | return find_builtin_helper(name, bltins2, &bltins2[ARRAY_SIZE(bltins2)]); |
8299 | } | 8341 | } |
8300 | 8342 | ||
8301 | #if ENABLE_HUSH_JOB && ENABLE_FEATURE_TAB_COMPLETION | 8343 | #if ENABLE_HUSH_INTERACTIVE && ENABLE_FEATURE_TAB_COMPLETION |
8302 | static const char * FAST_FUNC hush_command_name(int i) | 8344 | static const char * FAST_FUNC hush_command_name(int i) |
8303 | { | 8345 | { |
8304 | if (/*i >= 0 && */ i < ARRAY_SIZE(bltins1)) { | 8346 | if (/*i >= 0 && */ i < ARRAY_SIZE(bltins1)) { |
@@ -8464,10 +8506,8 @@ static void unset_func(const char *name) | |||
8464 | #define exec_function(to_free, funcp, argv) \ | 8506 | #define exec_function(to_free, funcp, argv) \ |
8465 | exec_function(funcp, argv) | 8507 | exec_function(funcp, argv) |
8466 | # endif | 8508 | # endif |
8467 | static void exec_function(char ***to_free, | 8509 | static NORETURN void exec_function( |
8468 | const struct function *funcp, | 8510 | char * *volatile *to_free, |
8469 | char **argv) NORETURN; | ||
8470 | static void exec_function(char ***to_free, | ||
8471 | const struct function *funcp, | 8511 | const struct function *funcp, |
8472 | char **argv) | 8512 | char **argv) |
8473 | { | 8513 | { |
@@ -8563,10 +8603,8 @@ static int run_function(const struct function *funcp, char **argv) | |||
8563 | #define exec_builtin(to_free, x, argv) \ | 8603 | #define exec_builtin(to_free, x, argv) \ |
8564 | exec_builtin(to_free, argv) | 8604 | exec_builtin(to_free, argv) |
8565 | #endif | 8605 | #endif |
8566 | static void exec_builtin(char ***to_free, | 8606 | static NORETURN void exec_builtin( |
8567 | const struct built_in_command *x, | 8607 | char * *volatile *to_free, |
8568 | char **argv) NORETURN; | ||
8569 | static void exec_builtin(char ***to_free, | ||
8570 | const struct built_in_command *x, | 8608 | const struct built_in_command *x, |
8571 | char **argv) | 8609 | char **argv) |
8572 | { | 8610 | { |
@@ -8589,8 +8627,7 @@ static void exec_builtin(char ***to_free, | |||
8589 | #endif | 8627 | #endif |
8590 | } | 8628 | } |
8591 | 8629 | ||
8592 | static void execvp_or_die(char **argv) NORETURN; | 8630 | static NORETURN void execvp_or_die(char **argv) |
8593 | static void execvp_or_die(char **argv) | ||
8594 | { | 8631 | { |
8595 | int e; | 8632 | int e; |
8596 | debug_printf_exec("execing '%s'\n", argv[0]); | 8633 | debug_printf_exec("execing '%s'\n", argv[0]); |
@@ -8711,10 +8748,8 @@ static void if_command_vV_print_and_exit(char opt_vV, char *cmd, const char *exp | |||
8711 | * The at_exit handlers apparently confuse the calling process, | 8748 | * The at_exit handlers apparently confuse the calling process, |
8712 | * in particular stdin handling. Not sure why? -- because of vfork! (vda) | 8749 | * in particular stdin handling. Not sure why? -- because of vfork! (vda) |
8713 | */ | 8750 | */ |
8714 | static void pseudo_exec_argv(nommu_save_t *nommu_save, | 8751 | static NORETURN NOINLINE void pseudo_exec_argv( |
8715 | char **argv, int assignment_cnt, | 8752 | volatile nommu_save_t *nommu_save, |
8716 | char **argv_expanded) NORETURN; | ||
8717 | static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, | ||
8718 | char **argv, int assignment_cnt, | 8753 | char **argv, int assignment_cnt, |
8719 | char **argv_expanded) | 8754 | char **argv_expanded) |
8720 | { | 8755 | { |
@@ -8740,7 +8775,8 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, | |||
8740 | #if BB_MMU | 8775 | #if BB_MMU |
8741 | G.shadowed_vars_pp = NULL; /* "don't save, free them instead" */ | 8776 | G.shadowed_vars_pp = NULL; /* "don't save, free them instead" */ |
8742 | #else | 8777 | #else |
8743 | G.shadowed_vars_pp = &nommu_save->old_vars; | 8778 | /* cast away volatility */ |
8779 | G.shadowed_vars_pp = (struct variable **)&nommu_save->old_vars; | ||
8744 | G.var_nest_level++; | 8780 | G.var_nest_level++; |
8745 | #endif | 8781 | #endif |
8746 | set_vars_and_save_old(new_env); | 8782 | set_vars_and_save_old(new_env); |
@@ -8867,10 +8903,8 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, | |||
8867 | 8903 | ||
8868 | /* Called after [v]fork() in run_pipe | 8904 | /* Called after [v]fork() in run_pipe |
8869 | */ | 8905 | */ |
8870 | static void pseudo_exec(nommu_save_t *nommu_save, | 8906 | static NORETURN void pseudo_exec( |
8871 | struct command *command, | 8907 | volatile nommu_save_t *nommu_save, |
8872 | char **argv_expanded) NORETURN; | ||
8873 | static void pseudo_exec(nommu_save_t *nommu_save, | ||
8874 | struct command *command, | 8908 | struct command *command, |
8875 | char **argv_expanded) | 8909 | char **argv_expanded) |
8876 | { | 8910 | { |
@@ -9755,8 +9789,7 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
9755 | 9789 | ||
9756 | /* Stores to nommu_save list of env vars putenv'ed | 9790 | /* Stores to nommu_save list of env vars putenv'ed |
9757 | * (NOMMU, on MMU we don't need that) */ | 9791 | * (NOMMU, on MMU we don't need that) */ |
9758 | /* cast away volatility... */ | 9792 | pseudo_exec(&nommu_save, command, argv_expanded); |
9759 | pseudo_exec((nommu_save_t*) &nommu_save, command, argv_expanded); | ||
9760 | /* pseudo_exec() does not return */ | 9793 | /* pseudo_exec() does not return */ |
9761 | } | 9794 | } |
9762 | 9795 | ||
@@ -10144,7 +10177,7 @@ static int run_list(struct pipe *pi) | |||
10144 | if (rcode != 0 && G.o_opt[OPT_O_ERREXIT]) { | 10177 | if (rcode != 0 && G.o_opt[OPT_O_ERREXIT]) { |
10145 | debug_printf_exec("ERREXIT:1 errexit_depth:%d\n", G.errexit_depth); | 10178 | debug_printf_exec("ERREXIT:1 errexit_depth:%d\n", G.errexit_depth); |
10146 | if (G.errexit_depth == 0) | 10179 | if (G.errexit_depth == 0) |
10147 | hush_exit(rcode); | 10180 | save_history_run_exit_trap_and_exit(rcode); |
10148 | } | 10181 | } |
10149 | G.errexit_depth = sv_errexit_depth; | 10182 | G.errexit_depth = sv_errexit_depth; |
10150 | 10183 | ||
@@ -10218,6 +10251,53 @@ static int run_and_free_list(struct pipe *pi) | |||
10218 | /* | 10251 | /* |
10219 | * Initialization and main | 10252 | * Initialization and main |
10220 | */ | 10253 | */ |
10254 | #if ENABLE_HUSH_INTERACTIVE && ENABLE_FEATURE_EDITING | ||
10255 | static void init_line_editing(void) | ||
10256 | { | ||
10257 | G.line_input_state = new_line_input_t(FOR_SHELL); | ||
10258 | # if ENABLE_FEATURE_TAB_COMPLETION | ||
10259 | G.line_input_state->get_exe_name = hush_command_name; | ||
10260 | # endif | ||
10261 | # if EDITING_HAS_sh_get_var | ||
10262 | G.line_input_state->sh_get_var = get_local_var_value; | ||
10263 | # endif | ||
10264 | # if ENABLE_HUSH_SAVEHISTORY && MAX_HISTORY > 0 | ||
10265 | { | ||
10266 | const char *hp = get_local_var_value("HISTFILE"); | ||
10267 | if (!hp) { | ||
10268 | hp = get_local_var_value("HOME"); | ||
10269 | if (hp) { | ||
10270 | hp = concat_path_file(hp, ".hush_history"); | ||
10271 | /* Make HISTFILE set on exit (else history won't be saved) */ | ||
10272 | set_local_var_from_halves("HISTFILE", hp); | ||
10273 | } | ||
10274 | } else { | ||
10275 | hp = xstrdup(hp); | ||
10276 | } | ||
10277 | if (hp) { | ||
10278 | G.line_input_state->hist_file = hp; | ||
10279 | } | ||
10280 | # if ENABLE_FEATURE_SH_HISTFILESIZE | ||
10281 | hp = get_local_var_value("HISTSIZE"); | ||
10282 | /* Using HISTFILESIZE above to limit max_history would be WRONG: | ||
10283 | * users may set HISTFILESIZE=0 in their profile scripts | ||
10284 | * to prevent _saving_ of history files, but still want to have | ||
10285 | * non-zero history limit for in-memory list. | ||
10286 | */ | ||
10287 | // in bash, runtime history size is controlled by HISTSIZE (0=no history), | ||
10288 | // HISTFILESIZE controls on-disk history file size (in lines, 0=no history): | ||
10289 | G.line_input_state->max_history = size_from_HISTFILESIZE(hp); | ||
10290 | // HISTFILESIZE: "The shell sets the default value to the value of HISTSIZE after reading any startup files." | ||
10291 | // HISTSIZE: "The shell sets the default value to 500 after reading any startup files." | ||
10292 | // (meaning: if the value wasn't set after startup files, the default value is set as described above) | ||
10293 | # endif | ||
10294 | } | ||
10295 | # endif | ||
10296 | } | ||
10297 | #else | ||
10298 | # define init_line_editing() ((void)0) | ||
10299 | #endif | ||
10300 | |||
10221 | static void install_sighandlers(unsigned mask) | 10301 | static void install_sighandlers(unsigned mask) |
10222 | { | 10302 | { |
10223 | sighandler_t old_handler; | 10303 | sighandler_t old_handler; |
@@ -10356,7 +10436,6 @@ static int set_mode(int state, char mode, const char *o_opt) | |||
10356 | int hush_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 10436 | int hush_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
10357 | int hush_main(int argc, char **argv) | 10437 | int hush_main(int argc, char **argv) |
10358 | { | 10438 | { |
10359 | pid_t cached_getpid; | ||
10360 | enum { | 10439 | enum { |
10361 | OPT_login = (1 << 0), | 10440 | OPT_login = (1 << 0), |
10362 | }; | 10441 | }; |
@@ -10369,6 +10448,11 @@ int hush_main(int argc, char **argv) | |||
10369 | struct variable *shell_ver; | 10448 | struct variable *shell_ver; |
10370 | 10449 | ||
10371 | INIT_G(); | 10450 | INIT_G(); |
10451 | #if ENABLE_HUSH_JOB | ||
10452 | die_func = fflush_restore_ttypgrp_and__exit; | ||
10453 | #else | ||
10454 | die_func = fflush_and__exit; | ||
10455 | #endif | ||
10372 | if (EXIT_SUCCESS != 0) /* if EXIT_SUCCESS == 0, it is already done */ | 10456 | if (EXIT_SUCCESS != 0) /* if EXIT_SUCCESS == 0, it is already done */ |
10373 | G.last_exitcode = EXIT_SUCCESS; | 10457 | G.last_exitcode = EXIT_SUCCESS; |
10374 | #if !BB_MMU | 10458 | #if !BB_MMU |
@@ -10384,9 +10468,6 @@ int hush_main(int argc, char **argv) | |||
10384 | _exit(0); | 10468 | _exit(0); |
10385 | } | 10469 | } |
10386 | G.argv0_for_re_execing = argv[0]; | 10470 | G.argv0_for_re_execing = argv[0]; |
10387 | if (G.argv0_for_re_execing[0] == '-') | ||
10388 | /* reexeced hush should never be a login shell */ | ||
10389 | G.argv0_for_re_execing++; | ||
10390 | #endif | 10471 | #endif |
10391 | #if ENABLE_HUSH_TRAP | 10472 | #if ENABLE_HUSH_TRAP |
10392 | # if ENABLE_HUSH_FUNCTIONS | 10473 | # if ENABLE_HUSH_FUNCTIONS |
@@ -10399,9 +10480,8 @@ int hush_main(int argc, char **argv) | |||
10399 | G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */ | 10480 | G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */ |
10400 | #endif | 10481 | #endif |
10401 | 10482 | ||
10402 | cached_getpid = getpid(); /* for tcsetpgrp() during init */ | 10483 | G.root_pid = getpid(); /* for $PID (NOMMU can override via -$HEXPID:HEXPPID:...) */ |
10403 | G.root_pid = cached_getpid; /* for $PID (NOMMU can override via -$HEXPID:HEXPPID:...) */ | 10484 | G.root_ppid = getppid(); /* for $PPID (NOMMU can override) */ |
10404 | G.root_ppid = getppid(); /* for $PPID (NOMMU can override) */ | ||
10405 | 10485 | ||
10406 | /* Deal with HUSH_VERSION */ | 10486 | /* Deal with HUSH_VERSION */ |
10407 | debug_printf_env("unsetenv '%s'\n", "HUSH_VERSION"); | 10487 | debug_printf_env("unsetenv '%s'\n", "HUSH_VERSION"); |
@@ -10484,27 +10564,24 @@ int hush_main(int argc, char **argv) | |||
10484 | * PS4='+ ' | 10564 | * PS4='+ ' |
10485 | */ | 10565 | */ |
10486 | 10566 | ||
10567 | /* Shell is non-interactive at first. We need to call | ||
10568 | * install_special_sighandlers() if we are going to execute "sh <script>", | ||
10569 | * "sh -c <cmds>" or login shell's /etc/profile and friends. | ||
10570 | * If we later decide that we are interactive, we run | ||
10571 | * install_special_sighandlers() in order to intercept more signals. | ||
10572 | */ | ||
10573 | install_special_sighandlers(); | ||
10574 | |||
10487 | #if NUM_SCRIPTS > 0 | 10575 | #if NUM_SCRIPTS > 0 |
10488 | if (argc < 0) { | 10576 | if (argc < 0) { |
10489 | char *script = get_script_content(-argc - 1); | 10577 | char *script = get_script_content(-argc - 1); |
10490 | G.global_argv = argv; | 10578 | G.global_argv = argv; |
10491 | G.global_argc = string_array_len(argv); | 10579 | G.global_argc = string_array_len(argv); |
10492 | //install_special_sighandlers(); - needed? | ||
10493 | parse_and_run_string(script); | 10580 | parse_and_run_string(script); |
10494 | goto final_return; | 10581 | goto final_return; |
10495 | } | 10582 | } |
10496 | #endif | 10583 | #endif |
10497 | 10584 | ||
10498 | /* Initialize some more globals to non-zero values */ | ||
10499 | die_func = restore_ttypgrp_and__exit; | ||
10500 | |||
10501 | /* Shell is non-interactive at first. We need to call | ||
10502 | * install_special_sighandlers() if we are going to execute "sh <script>", | ||
10503 | * "sh -c <cmds>" or login shell's /etc/profile and friends. | ||
10504 | * If we later decide that we are interactive, we run install_special_sighandlers() | ||
10505 | * in order to intercept (more) signals. | ||
10506 | */ | ||
10507 | |||
10508 | /* Parse options */ | 10585 | /* Parse options */ |
10509 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html */ | 10586 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html */ |
10510 | flags = (argv[0] && argv[0][0] == '-') ? OPT_login : 0; | 10587 | flags = (argv[0] && argv[0][0] == '-') ? OPT_login : 0; |
@@ -10568,6 +10645,7 @@ int hush_main(int argc, char **argv) | |||
10568 | case '$': { | 10645 | case '$': { |
10569 | unsigned long long empty_trap_mask; | 10646 | unsigned long long empty_trap_mask; |
10570 | 10647 | ||
10648 | G.reexeced_on_NOMMU = 1; | ||
10571 | G.root_pid = bb_strtou(optarg, &optarg, 16); | 10649 | G.root_pid = bb_strtou(optarg, &optarg, 16); |
10572 | optarg++; | 10650 | optarg++; |
10573 | G.root_ppid = bb_strtou(optarg, &optarg, 16); | 10651 | G.root_ppid = bb_strtou(optarg, &optarg, 16); |
@@ -10581,7 +10659,6 @@ int hush_main(int argc, char **argv) | |||
10581 | empty_trap_mask = bb_strtoull(optarg, &optarg, 16); | 10659 | empty_trap_mask = bb_strtoull(optarg, &optarg, 16); |
10582 | if (empty_trap_mask != 0) { | 10660 | if (empty_trap_mask != 0) { |
10583 | IF_HUSH_TRAP(int sig;) | 10661 | IF_HUSH_TRAP(int sig;) |
10584 | install_special_sighandlers(); | ||
10585 | # if ENABLE_HUSH_TRAP | 10662 | # if ENABLE_HUSH_TRAP |
10586 | G_traps = xzalloc(sizeof(G_traps[0]) * NSIG); | 10663 | G_traps = xzalloc(sizeof(G_traps[0]) * NSIG); |
10587 | for (sig = 1; sig < NSIG; sig++) { | 10664 | for (sig = 1; sig < NSIG; sig++) { |
@@ -10647,7 +10724,9 @@ int hush_main(int argc, char **argv) | |||
10647 | G.global_argv[0] = argv[0]; | 10724 | G.global_argv[0] = argv[0]; |
10648 | 10725 | ||
10649 | /* If we are login shell... */ | 10726 | /* If we are login shell... */ |
10650 | if (flags & OPT_login) { | 10727 | if (!G_reexeced_on_NOMMU /* reexeced hush should never be a login shell */ |
10728 | && (flags & OPT_login) | ||
10729 | ) { | ||
10651 | const char *hp = NULL; | 10730 | const char *hp = NULL; |
10652 | HFILE *input; | 10731 | HFILE *input; |
10653 | 10732 | ||
@@ -10655,7 +10734,6 @@ int hush_main(int argc, char **argv) | |||
10655 | input = hfopen("/etc/profile"); | 10734 | input = hfopen("/etc/profile"); |
10656 | run_profile: | 10735 | run_profile: |
10657 | if (input != NULL) { | 10736 | if (input != NULL) { |
10658 | install_special_sighandlers(); | ||
10659 | parse_and_run_file(input); | 10737 | parse_and_run_file(input); |
10660 | hfclose(input); | 10738 | hfclose(input); |
10661 | } | 10739 | } |
@@ -10692,8 +10770,6 @@ int hush_main(int argc, char **argv) | |||
10692 | */ | 10770 | */ |
10693 | char *script; | 10771 | char *script; |
10694 | 10772 | ||
10695 | install_special_sighandlers(); | ||
10696 | |||
10697 | G.global_argc--; | 10773 | G.global_argc--; |
10698 | G.global_argv++; | 10774 | G.global_argv++; |
10699 | #if !BB_MMU | 10775 | #if !BB_MMU |
@@ -10744,7 +10820,6 @@ int hush_main(int argc, char **argv) | |||
10744 | bb_simple_perror_msg_and_die(G.global_argv[0]); | 10820 | bb_simple_perror_msg_and_die(G.global_argv[0]); |
10745 | } | 10821 | } |
10746 | xfunc_error_retval = 1; | 10822 | xfunc_error_retval = 1; |
10747 | install_special_sighandlers(); | ||
10748 | parse_and_run_file(input); | 10823 | parse_and_run_file(input); |
10749 | #if ENABLE_FEATURE_CLEAN_UP | 10824 | #if ENABLE_FEATURE_CLEAN_UP |
10750 | hfclose(input); | 10825 | hfclose(input); |
@@ -10760,138 +10835,86 @@ int hush_main(int argc, char **argv) | |||
10760 | 10835 | ||
10761 | /* A shell is interactive if the '-i' flag was given, | 10836 | /* A shell is interactive if the '-i' flag was given, |
10762 | * or if all of the following conditions are met: | 10837 | * or if all of the following conditions are met: |
10763 | * no -c command | 10838 | * not -c 'CMD' |
10764 | * no arguments remaining or the -s flag given | 10839 | * not running a script (no arguments remaining, or -s flag given) |
10765 | * standard input is a terminal | 10840 | * standard input is a terminal |
10766 | * standard output is a terminal | 10841 | * standard output is a terminal |
10767 | * Refer to Posix.2, the description of the 'sh' utility. | 10842 | * Refer to Posix.2, the description of the 'sh' utility. |
10768 | */ | 10843 | */ |
10769 | #if ENABLE_HUSH_JOB | 10844 | #if ENABLE_HUSH_INTERACTIVE |
10770 | if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) { | 10845 | if (!G_reexeced_on_NOMMU |
10771 | G_saved_tty_pgrp = tcgetpgrp(STDIN_FILENO); | 10846 | && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO) |
10772 | debug_printf("saved_tty_pgrp:%d\n", G_saved_tty_pgrp); | 10847 | ) { |
10773 | if (G_saved_tty_pgrp < 0) | 10848 | /* Try to dup stdin to high fd#, >= 255 */ |
10774 | G_saved_tty_pgrp = 0; | ||
10775 | |||
10776 | /* try to dup stdin to high fd#, >= 255 */ | ||
10777 | G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, 254); | 10849 | G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, 254); |
10778 | if (G_interactive_fd < 0) { | 10850 | if (G_interactive_fd < 0) { |
10779 | /* try to dup to any fd */ | 10851 | /* Try to dup to any fd */ |
10780 | G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, -1); | 10852 | G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, -1); |
10781 | if (G_interactive_fd < 0) { | 10853 | if (G_interactive_fd < 0) |
10782 | /* give up */ | 10854 | /* Give up */ |
10783 | G_interactive_fd = 0; | 10855 | G_interactive_fd = 0; |
10784 | G_saved_tty_pgrp = 0; | ||
10785 | } | ||
10786 | } | 10856 | } |
10787 | } | 10857 | debug_printf("interactive_fd:%d\n", G_interactive_fd); |
10788 | debug_printf("interactive_fd:%d\n", G_interactive_fd); | 10858 | if (G_interactive_fd) { |
10789 | if (G_interactive_fd) { | 10859 | // TODO? bash: |
10790 | if (G_saved_tty_pgrp) { | 10860 | // if interactive but not a login shell, sources ~/.bashrc |
10791 | /* If we were run as 'hush &', sleep until we are | 10861 | // (--norc turns this off, --rcfile <file> overrides) |
10792 | * in the foreground (tty pgrp == our pgrp). | 10862 | # if ENABLE_HUSH_JOB |
10793 | * If we get started under a job aware app (like bash), | 10863 | /* Can we do job control? */ |
10794 | * make sure we are now in charge so we don't fight over | 10864 | G_saved_tty_pgrp = tcgetpgrp(G_interactive_fd); |
10795 | * who gets the foreground */ | 10865 | debug_printf("saved_tty_pgrp:%d\n", G_saved_tty_pgrp); |
10796 | while (1) { | 10866 | if (G_saved_tty_pgrp < 0) |
10797 | pid_t shell_pgrp = getpgrp(); | 10867 | G_saved_tty_pgrp = 0; /* no */ |
10798 | G_saved_tty_pgrp = tcgetpgrp(G_interactive_fd); | 10868 | if (G_saved_tty_pgrp) { |
10799 | if (G_saved_tty_pgrp == shell_pgrp) | 10869 | /* If we were run as 'hush &', sleep until we are |
10800 | break; | 10870 | * in the foreground (tty pgrp == our pgrp). |
10801 | /* send TTIN to ourself (should stop us) */ | 10871 | * If we get started under a job aware app (like bash), |
10802 | kill(- shell_pgrp, SIGTTIN); | 10872 | * make sure we are now in charge so we don't fight over |
10873 | * who gets the foreground */ | ||
10874 | while (1) { | ||
10875 | pid_t shell_pgrp = getpgrp(); | ||
10876 | if (G_saved_tty_pgrp == shell_pgrp) { | ||
10877 | /* Often both pgrps here are set to our pid - but not always! | ||
10878 | * Example: sh -c 'echo $$; hush; echo FIN' | ||
10879 | * Here, the parent shell is not interactive, so it does NOT set up | ||
10880 | * a separate process group for its children, and we (hush) initially | ||
10881 | * run in parent's process group (until we set up our own a few lines down). | ||
10882 | */ | ||
10883 | //bb_error_msg("process groups tty:%d hush:%d", G_saved_tty_pgrp, shell_pgrp); | ||
10884 | break; | ||
10885 | } | ||
10886 | /* Send TTIN to ourself (should stop us) */ | ||
10887 | kill(- shell_pgrp, SIGTTIN); | ||
10888 | G_saved_tty_pgrp = tcgetpgrp(G_interactive_fd); | ||
10889 | } | ||
10803 | } | 10890 | } |
10804 | } | ||
10805 | |||
10806 | /* Install more signal handlers */ | ||
10807 | install_special_sighandlers(); | ||
10808 | |||
10809 | if (G_saved_tty_pgrp) { | ||
10810 | /* Set other signals to restore saved_tty_pgrp */ | ||
10811 | install_fatal_sighandlers(); | ||
10812 | /* Put ourselves in our own process group | ||
10813 | * (bash, too, does this only if ctty is available) */ | ||
10814 | bb_setpgrp(); /* is the same as setpgid(our_pid, our_pid); */ | ||
10815 | /* Grab control of the terminal */ | ||
10816 | tcsetpgrp(G_interactive_fd, cached_getpid); | ||
10817 | } | ||
10818 | enable_restore_tty_pgrp_on_exit(); | ||
10819 | |||
10820 | # if ENABLE_FEATURE_EDITING | ||
10821 | G.line_input_state = new_line_input_t(FOR_SHELL); | ||
10822 | # if ENABLE_FEATURE_TAB_COMPLETION | ||
10823 | G.line_input_state->get_exe_name = hush_command_name; | ||
10824 | # endif | ||
10825 | # if EDITING_HAS_sh_get_var | ||
10826 | G.line_input_state->sh_get_var = get_local_var_value; | ||
10827 | # endif | ||
10828 | # endif | 10891 | # endif |
10829 | # if ENABLE_HUSH_SAVEHISTORY && MAX_HISTORY > 0 | 10892 | /* Install more signal handlers */ |
10830 | { | 10893 | install_special_sighandlers(); |
10831 | const char *hp = get_local_var_value("HISTFILE"); | 10894 | # if ENABLE_HUSH_JOB |
10832 | if (!hp) { | 10895 | if (G_saved_tty_pgrp) { |
10833 | hp = get_local_var_value("HOME"); | 10896 | /* Set fatal signals to restore saved_tty_pgrp */ |
10834 | if (hp) { | 10897 | install_fatal_sighandlers(); |
10835 | hp = concat_path_file(hp, ".hush_history"); | 10898 | /* (The if() is an optimization: can avoid two redundant syscalls) */ |
10836 | /* Make HISTFILE set on exit (else history won't be saved) */ | 10899 | if (G_saved_tty_pgrp != G.root_pid) { |
10837 | set_local_var_from_halves("HISTFILE", hp); | 10900 | /* Put ourselves in our own process group |
10901 | * (bash, too, does this only if ctty is available) */ | ||
10902 | bb_setpgrp(); /* is the same as setpgid(our_pid, our_pid); */ | ||
10903 | /* Grab control of the terminal */ | ||
10904 | tcsetpgrp(G_interactive_fd, G.root_pid); | ||
10838 | } | 10905 | } |
10839 | } else { | ||
10840 | hp = xstrdup(hp); | ||
10841 | } | 10906 | } |
10842 | if (hp) { | ||
10843 | G.line_input_state->hist_file = hp; | ||
10844 | } | ||
10845 | # if ENABLE_FEATURE_SH_HISTFILESIZE | ||
10846 | hp = get_local_var_value("HISTSIZE"); | ||
10847 | /* Using HISTFILESIZE above to limit max_history would be WRONG: | ||
10848 | * users may set HISTFILESIZE=0 in their profile scripts | ||
10849 | * to prevent _saving_ of history files, but still want to have | ||
10850 | * non-zero history limit for in-memory list. | ||
10851 | */ | ||
10852 | // in bash, runtime history size is controlled by HISTSIZE (0=no history), | ||
10853 | // HISTFILESIZE controls on-disk history file size (in lines, 0=no history): | ||
10854 | G.line_input_state->max_history = size_from_HISTFILESIZE(hp); | ||
10855 | // HISTFILESIZE: "The shell sets the default value to the value of HISTSIZE after reading any startup files." | ||
10856 | // HISTSIZE: "The shell sets the default value to 500 after reading any startup files." | ||
10857 | // (meaning: if the value wasn't set after startup files, the default value is set as described above) | ||
10858 | # endif | ||
10859 | } | ||
10860 | # endif | 10907 | # endif |
10861 | } else { | 10908 | # if ENABLE_FEATURE_EDITING_FANCY_PROMPT |
10862 | install_special_sighandlers(); | 10909 | /* Set (but not export) PS1/2 unless already set */ |
10863 | } | 10910 | if (!get_local_var_value("PS1")) |
10864 | #elif ENABLE_HUSH_INTERACTIVE | 10911 | set_local_var_from_halves("PS1", "\\w \\$ "); |
10865 | /* No job control compiled in, only prompt/line editing */ | 10912 | if (!get_local_var_value("PS2")) |
10866 | if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) { | 10913 | set_local_var_from_halves("PS2", "> "); |
10867 | G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, 254); | 10914 | # endif |
10868 | if (G_interactive_fd < 0) { | 10915 | init_line_editing(); |
10869 | /* try to dup to any fd */ | ||
10870 | G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, -1); | ||
10871 | if (G_interactive_fd < 0) | ||
10872 | /* give up */ | ||
10873 | G_interactive_fd = 0; | ||
10874 | } | ||
10875 | } | ||
10876 | install_special_sighandlers(); | ||
10877 | #else | ||
10878 | /* We have interactiveness code disabled */ | ||
10879 | install_special_sighandlers(); | ||
10880 | #endif | ||
10881 | /* bash: | ||
10882 | * if interactive but not a login shell, sources ~/.bashrc | ||
10883 | * (--norc turns this off, --rcfile <file> overrides) | ||
10884 | */ | ||
10885 | 10916 | ||
10886 | if (G_interactive_fd) { | 10917 | # if !ENABLE_FEATURE_SH_EXTRA_QUIET |
10887 | #if ENABLE_HUSH_INTERACTIVE && ENABLE_FEATURE_EDITING_FANCY_PROMPT | ||
10888 | /* Set (but not export) PS1/2 unless already set */ | ||
10889 | if (!get_local_var_value("PS1")) | ||
10890 | set_local_var_from_halves("PS1", "\\w \\$ "); | ||
10891 | if (!get_local_var_value("PS2")) | ||
10892 | set_local_var_from_halves("PS2", "> "); | ||
10893 | #endif | ||
10894 | if (!ENABLE_FEATURE_SH_EXTRA_QUIET) { | ||
10895 | /* note: ash and hush share this string */ | 10918 | /* note: ash and hush share this string */ |
10896 | printf("\n\n%s %s\n" | 10919 | printf("\n\n%s %s\n" |
10897 | IF_HUSH_HELP("Enter 'help' for a list of built-in commands.\n") | 10920 | IF_HUSH_HELP("Enter 'help' for a list of built-in commands.\n") |
@@ -10899,13 +10922,15 @@ int hush_main(int argc, char **argv) | |||
10899 | bb_banner, | 10922 | bb_banner, |
10900 | "hush - the humble shell" | 10923 | "hush - the humble shell" |
10901 | ); | 10924 | ); |
10902 | } | 10925 | # endif |
10903 | } | 10926 | } /* if become interactive */ |
10927 | } /* if on tty */ | ||
10928 | #endif /* if INTERACTIVE is allowed by build config */ | ||
10904 | 10929 | ||
10905 | parse_and_run_file(hfopen(NULL)); /* stdin */ | 10930 | parse_and_run_file(hfopen(NULL)); /* stdin */ |
10906 | 10931 | ||
10907 | final_return: | 10932 | final_return: |
10908 | hush_exit(G.last_exitcode); | 10933 | save_history_run_exit_trap_and_exit(G.last_exitcode); |
10909 | } | 10934 | } |
10910 | 10935 | ||
10911 | /* | 10936 | /* |
@@ -11091,19 +11116,19 @@ static int FAST_FUNC builtin_exit(char **argv) | |||
11091 | * TODO: we can use G.exiting = -1 as indicator "last cmd was exit" | 11116 | * TODO: we can use G.exiting = -1 as indicator "last cmd was exit" |
11092 | */ | 11117 | */ |
11093 | 11118 | ||
11094 | /* note: EXIT trap is run by hush_exit */ | 11119 | /* note: EXIT trap is run by save_history_run_exit_trap_and_exit */ |
11095 | argv = skip_dash_dash(argv); | 11120 | argv = skip_dash_dash(argv); |
11096 | if (argv[0] == NULL) { | 11121 | if (argv[0] == NULL) { |
11097 | #if ENABLE_HUSH_TRAP | 11122 | #if ENABLE_HUSH_TRAP |
11098 | if (G.pre_trap_exitcode >= 0) /* "exit" in trap uses $? from before the trap */ | 11123 | if (G.pre_trap_exitcode >= 0) /* "exit" in trap uses $? from before the trap */ |
11099 | hush_exit(G.pre_trap_exitcode); | 11124 | save_history_run_exit_trap_and_exit(G.pre_trap_exitcode); |
11100 | #endif | 11125 | #endif |
11101 | hush_exit(G.last_exitcode); | 11126 | save_history_run_exit_trap_and_exit(G.last_exitcode); |
11102 | } | 11127 | } |
11103 | /* mimic bash: exit 123abc == exit 255 + error msg */ | 11128 | /* mimic bash: exit 123abc == exit 255 + error msg */ |
11104 | xfunc_error_retval = 255; | 11129 | xfunc_error_retval = 255; |
11105 | /* bash: exit -2 == exit 254, no error msg */ | 11130 | /* bash: exit -2 == exit 254, no error msg */ |
11106 | hush_exit(xatoi(argv[0]) & 0xff); | 11131 | save_history_run_exit_trap_and_exit(xatoi(argv[0]) & 0xff); |
11107 | } | 11132 | } |
11108 | 11133 | ||
11109 | #if ENABLE_HUSH_TYPE | 11134 | #if ENABLE_HUSH_TYPE |
diff --git a/shell/hush_leaktool.sh b/shell/hush_leaktool.sh index ca35ec144..3edd3df61 100755 --- a/shell/hush_leaktool.sh +++ b/shell/hush_leaktool.sh | |||
@@ -7,7 +7,7 @@ freelist=`grep 'free 0x' "$output" | cut -d' ' -f2 | sort | uniq | xargs` | |||
7 | 7 | ||
8 | grep -v free "$output" >"$output.leaked" | 8 | grep -v free "$output" >"$output.leaked" |
9 | 9 | ||
10 | i=8 | 10 | i=16 |
11 | list= | 11 | list= |
12 | for freed in $freelist; do | 12 | for freed in $freelist; do |
13 | list="$list -e $freed" | 13 | list="$list -e $freed" |
@@ -15,7 +15,7 @@ for freed in $freelist; do | |||
15 | echo Dropping $list | 15 | echo Dropping $list |
16 | grep -F -v $list <"$output.leaked" >"$output.temp" | 16 | grep -F -v $list <"$output.leaked" >"$output.temp" |
17 | mv "$output.temp" "$output.leaked" | 17 | mv "$output.temp" "$output.leaked" |
18 | i=8 | 18 | i=16 |
19 | list= | 19 | list= |
20 | done | 20 | done |
21 | if test "$list"; then | 21 | if test "$list"; then |
@@ -23,3 +23,17 @@ if test "$list"; then | |||
23 | grep -F -v $list <"$output.leaked" >"$output.temp" | 23 | grep -F -v $list <"$output.leaked" >"$output.temp" |
24 | mv "$output.temp" "$output.leaked" | 24 | mv "$output.temp" "$output.leaked" |
25 | fi | 25 | fi |
26 | |||
27 | # All remaining allocations are on addresses which were never freed. | ||
28 | # * Sort them by line, grouping together allocations which allocated the same address. | ||
29 | # A leaky allocation will give many different addresses (because it's never freed, | ||
30 | # the address can not be reused). | ||
31 | # * Remove the address (field #4). | ||
32 | # * Count the allocations per every unique source line and alloc type. | ||
33 | # * Show largest counts on top. | ||
34 | cat output.leaked \ | ||
35 | | sort -u \ | ||
36 | | cut -d' ' -f1-3 \ | ||
37 | | uniq -c \ | ||
38 | | sort -rn \ | ||
39 | >output.leaked.counted_uniq_alloc_address | ||
diff --git a/shell/hush_test/hush-misc/sig_exitcode.tests b/shell/hush_test/hush-misc/sig_exitcode.tests index 7879dc854..67b4500f4 100755 --- a/shell/hush_test/hush-misc/sig_exitcode.tests +++ b/shell/hush_test/hush-misc/sig_exitcode.tests | |||
@@ -1,3 +1,6 @@ | |||
1 | # If job control is disabled, skip the test | ||
2 | test "`type jobs`" = "jobs is a shell builtin" || exit 77 | ||
3 | |||
1 | exec 2>&1 | 4 | exec 2>&1 |
2 | 5 | ||
3 | $THIS_SH -c 'kill -9 $$' | 6 | $THIS_SH -c 'kill -9 $$' |
diff --git a/shell/hush_test/hush-misc/wait1.tests b/shell/hush_test/hush-misc/wait1.tests index f9cf6d48c..54120319b 100755 --- a/shell/hush_test/hush-misc/wait1.tests +++ b/shell/hush_test/hush-misc/wait1.tests | |||
@@ -1,3 +1,6 @@ | |||
1 | # If job control is disabled, skip the test | ||
2 | test "`type jobs`" = "jobs is a shell builtin" || exit 77 | ||
3 | |||
1 | sleep 2 & sleep 1 & wait $! | 4 | sleep 2 & sleep 1 & wait $! |
2 | echo $? | 5 | echo $? |
3 | jobs | 6 | jobs |
diff --git a/shell/hush_test/hush-misc/wait2.tests b/shell/hush_test/hush-misc/wait2.tests index be20f95a5..60f382c9f 100755 --- a/shell/hush_test/hush-misc/wait2.tests +++ b/shell/hush_test/hush-misc/wait2.tests | |||
@@ -1,3 +1,6 @@ | |||
1 | # If job control is disabled, skip the test | ||
2 | test "`type jobs`" = "jobs is a shell builtin" || exit 77 | ||
3 | |||
1 | sleep 3 & sleep 2 & sleep 1 | 4 | sleep 3 & sleep 2 & sleep 1 |
2 | wait $! | 5 | wait $! |
3 | echo $? | 6 | echo $? |
diff --git a/shell/hush_test/hush-misc/wait3.tests b/shell/hush_test/hush-misc/wait3.tests index ac541c3fc..aceed1126 100755 --- a/shell/hush_test/hush-misc/wait3.tests +++ b/shell/hush_test/hush-misc/wait3.tests | |||
@@ -1,3 +1,6 @@ | |||
1 | # If job control is disabled, skip the test | ||
2 | test "`type jobs`" = "jobs is a shell builtin" || exit 77 | ||
3 | |||
1 | sleep 2 & (sleep 1;exit 3) & wait $! | 4 | sleep 2 & (sleep 1;exit 3) & wait $! |
2 | echo $? | 5 | echo $? |
3 | jobs | 6 | jobs |
diff --git a/shell/hush_test/hush-misc/wait4.tests b/shell/hush_test/hush-misc/wait4.tests index cc34059ac..c979a38b6 100755 --- a/shell/hush_test/hush-misc/wait4.tests +++ b/shell/hush_test/hush-misc/wait4.tests | |||
@@ -1,2 +1,5 @@ | |||
1 | # If job control is disabled, skip the test | ||
2 | test "`type jobs`" = "jobs is a shell builtin" || exit 77 | ||
3 | |||
1 | sleep 1 | (sleep 1;exit 3) & wait %1 | 4 | sleep 1 | (sleep 1;exit 3) & wait %1 |
2 | echo Three:$? | 5 | echo Three:$? |
diff --git a/shell/hush_test/hush-misc/wait5.tests b/shell/hush_test/hush-misc/wait5.tests index 1b4762d89..e0ac8c251 100755 --- a/shell/hush_test/hush-misc/wait5.tests +++ b/shell/hush_test/hush-misc/wait5.tests | |||
@@ -1,3 +1,6 @@ | |||
1 | # If job control is disabled, skip the test | ||
2 | test "`type jobs`" = "jobs is a shell builtin" || exit 77 | ||
3 | |||
1 | sleep 0 | (sleep 0;exit 3) & | 4 | sleep 0 | (sleep 0;exit 3) & |
2 | sleep 1 | 5 | sleep 1 |
3 | echo Zero:$? | 6 | echo Zero:$? |
diff --git a/shell/hush_test/hush-misc/wait6.tests b/shell/hush_test/hush-misc/wait6.tests index c23713199..c09002ab0 100755 --- a/shell/hush_test/hush-misc/wait6.tests +++ b/shell/hush_test/hush-misc/wait6.tests | |||
@@ -1,3 +1,6 @@ | |||
1 | # If job control is disabled, skip the test | ||
2 | test "`type jobs`" = "jobs is a shell builtin" || exit 77 | ||
3 | |||
1 | # In bash, "wait $!" extracts correct exitcode even if bg task has already exited | 4 | # In bash, "wait $!" extracts correct exitcode even if bg task has already exited |
2 | # It prints 0, then 3: | 5 | # It prints 0, then 3: |
3 | (sleep 0; exit 3) & sleep 1 | 6 | (sleep 0; exit 3) & sleep 1 |
diff --git a/shell/hush_test/hush-signals/catch.tests b/shell/hush_test/hush-signals/catch.tests index d2a21d17e..4b1a08e8f 100755 --- a/shell/hush_test/hush-signals/catch.tests +++ b/shell/hush_test/hush-signals/catch.tests | |||
@@ -1,3 +1,6 @@ | |||
1 | # If job control is disabled, skip the test ("User defined signal 2" text not emitted) | ||
2 | test "`type jobs`" = "jobs is a shell builtin" || exit 77 | ||
3 | |||
1 | # avoid ugly warnings about signals not being caught | 4 | # avoid ugly warnings about signals not being caught |
2 | trap ":" USR1 USR2 | 5 | trap ":" USR1 USR2 |
3 | 6 | ||
diff --git a/shell/hush_test/hush-signals/signal1.tests b/shell/hush_test/hush-signals/signal1.tests index 61943467a..c83fa1254 100755 --- a/shell/hush_test/hush-signals/signal1.tests +++ b/shell/hush_test/hush-signals/signal1.tests | |||
@@ -1,3 +1,6 @@ | |||
1 | # If job control is disabled, skip the test | ||
2 | test "`type jobs`" = "jobs is a shell builtin" || exit 77 | ||
3 | |||
1 | trap "echo got signal" USR1 | 4 | trap "echo got signal" USR1 |
2 | 5 | ||
3 | for try in 1 2 3 4 5; do | 6 | for try in 1 2 3 4 5; do |
diff --git a/shell/hush_test/hush-signals/signal8.tests b/shell/hush_test/hush-signals/signal8.tests index 731af7477..cd5790164 100755 --- a/shell/hush_test/hush-signals/signal8.tests +++ b/shell/hush_test/hush-signals/signal8.tests | |||
@@ -1,3 +1,6 @@ | |||
1 | # If job control is disabled, skip the test | ||
2 | test "`type jobs`" = "jobs is a shell builtin" || exit 77 | ||
3 | |||
1 | "$THIS_SH" -c ' | 4 | "$THIS_SH" -c ' |
2 | exit_func() { | 5 | exit_func() { |
3 | echo "Removing traps" | 6 | echo "Removing traps" |
diff --git a/shell/hush_test/hush-signals/signal_read2.tests b/shell/hush_test/hush-signals/signal_read2.tests index eab5b9b5b..11accd5ab 100755 --- a/shell/hush_test/hush-signals/signal_read2.tests +++ b/shell/hush_test/hush-signals/signal_read2.tests | |||
@@ -1,3 +1,6 @@ | |||
1 | # If job control is disabled, skip the test ("Hangup" not emitted) | ||
2 | test "`type jobs`" = "jobs is a shell builtin" || exit 77 | ||
3 | |||
1 | $THIS_SH -c ' | 4 | $THIS_SH -c ' |
2 | (sleep 1; kill -HUP $$) & | 5 | (sleep 1; kill -HUP $$) & |
3 | while true; do | 6 | while true; do |
diff --git a/shell/hush_test/hush-signals/subshell.tests b/shell/hush_test/hush-signals/subshell.tests index d877f2b82..856c922d3 100755 --- a/shell/hush_test/hush-signals/subshell.tests +++ b/shell/hush_test/hush-signals/subshell.tests | |||
@@ -1,5 +1,8 @@ | |||
1 | # Non-empty traps should be reset in subshell | 1 | # Non-empty traps should be reset in subshell |
2 | 2 | ||
3 | # If job control is disabled, skip the test ("Terminated" text not emitted) | ||
4 | test "`type jobs`" = "jobs is a shell builtin" || exit 77 | ||
5 | |||
3 | # HUP is special in interactive shells | 6 | # HUP is special in interactive shells |
4 | trap '' HUP | 7 | trap '' HUP |
5 | # QUIT is always special | 8 | # QUIT is always special |
diff --git a/shell/hush_test/run-all b/shell/hush_test/run-all index 7345fee43..ff29ca0b1 100755 --- a/shell/hush_test/run-all +++ b/shell/hush_test/run-all | |||
@@ -67,9 +67,12 @@ do_test() | |||
67 | # echo Running test: "$x" | 67 | # echo Running test: "$x" |
68 | echo -n "$1/$x:" | 68 | echo -n "$1/$x:" |
69 | ( | 69 | ( |
70 | "$THIS_SH" "./$x" 2>&1 | \ | 70 | "$THIS_SH" "./$x" >"$name.xx" 2>&1 |
71 | grep -va "^hush: using fallback suid method$" >"$name.xx" | ||
72 | r=$? | 71 | r=$? |
72 | # filter !FEATURE_SUID_CONFIG_QUIET message | ||
73 | sed -i \ | ||
74 | -e "/^hush: using fallback suid method$/d" \ | ||
75 | "$name.xx" | ||
73 | # filter C library differences | 76 | # filter C library differences |
74 | sed -i \ | 77 | sed -i \ |
75 | -e "/: invalid option /s:'::g" \ | 78 | -e "/: invalid option /s:'::g" \ |
diff --git a/testsuite/hexdump.tests b/testsuite/hexdump.tests index b2f6a2201..d2c0a5dc8 100755 --- a/testsuite/hexdump.tests +++ b/testsuite/hexdump.tests | |||
@@ -56,6 +56,16 @@ testing "hexdump -e %3_u" \ | |||
56 | " \ | 56 | " \ |
57 | "" "$input" | 57 | "" "$input" |
58 | 58 | ||
59 | testing "hexdump -e %3_c" \ | ||
60 | "hexdump -e '16/1 \" %3_c\" \"\n\"'" \ | ||
61 | ' \\0 001 002 003 004 005 006 \\a \\b \\t \\n \\v \\f \\r 016 017 | ||
62 | 020 021 022 023 024 025 026 027 030 031 032 033 034 035 036 037 | ||
63 | p q r s t u v w x y z { | } ~ 177 | ||
64 | 200 201 202 203 204 205 206 207 210 211 212 213 214 215 216 217 | ||
65 | 360 361 362 363 364 365 366 367 370 371 372 373 374 375 376 377 | ||
66 | ' \ | ||
67 | "" "$input" | ||
68 | |||
59 | testing "hexdump -e /1 %d" \ | 69 | testing "hexdump -e /1 %d" \ |
60 | "hexdump -e '16/1 \" %4d\" \"\n\"'" \ | 70 | "hexdump -e '16/1 \" %4d\" \"\n\"'" \ |
61 | "\ | 71 | "\ |
diff --git a/testsuite/ls.tests b/testsuite/ls.tests index 9309d366b..a95911034 100755 --- a/testsuite/ls.tests +++ b/testsuite/ls.tests | |||
@@ -19,7 +19,7 @@ test x"$CONFIG_UNICODE_SUPPORT" = x"y" \ | |||
19 | && test x"$CONFIG_LAST_SUPPORTED_WCHAR" = x"767" \ | 19 | && test x"$CONFIG_LAST_SUPPORTED_WCHAR" = x"767" \ |
20 | && test x"$CONFIG_FEATURE_LS_SORTFILES" = x"y" \ | 20 | && test x"$CONFIG_FEATURE_LS_SORTFILES" = x"y" \ |
21 | && testing "ls unicode test with codepoints limited to 767" \ | 21 | && testing "ls unicode test with codepoints limited to 767" \ |
22 | "(cd ls.testdir && sh ../ls.mk_uni_tests) && ls -1 ls.testdir" \ | 22 | "(cd ls.testdir && sh ../ls.mk_uni_tests) && ls -1q ls.testdir" \ |
23 | '0001_1__Some_correct_UTF-8_text___________________________________________| | 23 | '0001_1__Some_correct_UTF-8_text___________________________________________| |
24 | 0002_2__Boundary_condition_test_cases_____________________________________| | 24 | 0002_2__Boundary_condition_test_cases_____________________________________| |
25 | 0003_2.1__First_possible_sequence_of_a_certain_length_____________________| | 25 | 0003_2.1__First_possible_sequence_of_a_certain_length_____________________| |
@@ -138,7 +138,7 @@ test x"$CONFIG_UNICODE_SUPPORT" = x"y" \ | |||
138 | && test x"$CONFIG_SUBST_WCHAR" = x"63" \ | 138 | && test x"$CONFIG_SUBST_WCHAR" = x"63" \ |
139 | && test x"$CONFIG_LAST_SUPPORTED_WCHAR" = x"0" \ | 139 | && test x"$CONFIG_LAST_SUPPORTED_WCHAR" = x"0" \ |
140 | && testing "ls unicode test with unlimited codepoints" \ | 140 | && testing "ls unicode test with unlimited codepoints" \ |
141 | "(cd ls.testdir && sh ../ls.mk_uni_tests) && ls -1 ls.testdir" \ | 141 | "(cd ls.testdir && sh ../ls.mk_uni_tests) && ls -1q ls.testdir" \ |
142 | '0001_1__Some_correct_UTF-8_text___________________________________________| | 142 | '0001_1__Some_correct_UTF-8_text___________________________________________| |
143 | 0002_2__Boundary_condition_test_cases_____________________________________| | 143 | 0002_2__Boundary_condition_test_cases_____________________________________| |
144 | 0003_2.1__First_possible_sequence_of_a_certain_length_____________________| | 144 | 0003_2.1__First_possible_sequence_of_a_certain_length_____________________| |
@@ -262,6 +262,28 @@ test x"$CONFIG_FEATURE_LS_SORTFILES" = x"y" \ | |||
262 | "A\nB\nA\nB\nA\nB\n" \ | 262 | "A\nB\nA\nB\nA\nB\n" \ |
263 | "" "" | 263 | "" "" |
264 | 264 | ||
265 | rm -rf ls.testdir 2>/dev/null | ||
266 | mkdir ls.testdir || exit 1 | ||
267 | touch "`printf "ls.testdir/\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f_\x7f\x80\xfe\xff_\x22_\x27_\x5c"`" | ||
268 | |||
269 | sq="'" | ||
270 | |||
271 | # testing "test name" "command" "expected result" "file input" "stdin" | ||
272 | testing "ls -q" \ | ||
273 | 'ls -q ls.testdir' \ | ||
274 | '???????????????????????????????_????_"_'$sq'_\\''\n' \ | ||
275 | "" "" | ||
276 | |||
277 | testing "ls -Q" \ | ||
278 | 'ls -Q ls.testdir' \ | ||
279 | '"\\001\\002\\003\\004\\005\\006\\a\\b\\t\\n\\v\\f\\r\\016\\017\\020\\021\\022\\023\\024\\025\\026\\027\\030\\031\\032\\033\\034\\035\\036\\037_\\177\\200\\376\\377_\\"_'$sq'_\\\\"\n' \ | ||
280 | "" "" | ||
281 | |||
282 | testing "ls -qQ" \ | ||
283 | 'ls -qQ ls.testdir' \ | ||
284 | '"\\001\\002\\003\\004\\005\\006\\a\\b\\t\\n\\v\\f\\r\\016\\017\\020\\021\\022\\023\\024\\025\\026\\027\\030\\031\\032\\033\\034\\035\\036\\037_\\177\\200\\376\\377_\\"_'$sq'_\\\\"\n' \ | ||
285 | "" "" | ||
286 | |||
265 | # Clean up | 287 | # Clean up |
266 | rm -rf ls.testdir 2>/dev/null | 288 | rm -rf ls.testdir 2>/dev/null |
267 | 289 | ||
diff --git a/testsuite/md5sum.tests b/testsuite/md5sum.tests index cca26dc64..a6d2b7ffb 100755 --- a/testsuite/md5sum.tests +++ b/testsuite/md5sum.tests | |||
@@ -9,6 +9,7 @@ | |||
9 | # efe30c482e0b687e0cca0612f42ca29b | 9 | # efe30c482e0b687e0cca0612f42ca29b |
10 | # d41337e834377140ae7f98460d71d908598ef04f | 10 | # d41337e834377140ae7f98460d71d908598ef04f |
11 | # 8e1d3ed57ebc130f0f72508446559eeae06451ae6d61b1e8ce46370cfb8963c3 | 11 | # 8e1d3ed57ebc130f0f72508446559eeae06451ae6d61b1e8ce46370cfb8963c3 |
12 | # c01420bb6613d4bd00396a82033e59e81486cbb045ae0dd2b4c3332e581b3ce09fb1946d6e283acec685778ff205d485 | ||
12 | # fe413e0f177324d1353893ca0772ceba83fd41512ba63895a0eebb703ef9feac2fb4e92b2cb430b3bda41b46b0cb4ea8307190a5cc795157cfb680a9cd635d0f | 13 | # fe413e0f177324d1353893ca0772ceba83fd41512ba63895a0eebb703ef9feac2fb4e92b2cb430b3bda41b46b0cb4ea8307190a5cc795157cfb680a9cd635d0f |
13 | 14 | ||
14 | if ! test "$1"; then | 15 | if ! test "$1"; then |
@@ -31,9 +32,9 @@ text=`yes "$text" | head -c 9999` | |||
31 | result=`( | 32 | result=`( |
32 | n=0 | 33 | n=0 |
33 | while test $n -le 999; do | 34 | while test $n -le 999; do |
34 | echo "$text" | head -c $n | "$sum" | 35 | echo "$text" | head -c $n | $sum |
35 | n=$(($n+1)) | 36 | n=$(($n+1)) |
36 | done | "$sum" | 37 | done | $sum |
37 | )` | 38 | )` |
38 | if test x"$result" != x"$expected -"; then | 39 | if test x"$result" != x"$expected -"; then |
39 | echo "FAIL: $sum (r:$result exp:$expected)" | 40 | echo "FAIL: $sum (r:$result exp:$expected)" |
@@ -44,7 +45,7 @@ fi | |||
44 | 45 | ||
45 | # GNU compat: -c EMPTY must fail (exitcode 1)! | 46 | # GNU compat: -c EMPTY must fail (exitcode 1)! |
46 | >EMPTY | 47 | >EMPTY |
47 | if "$sum" -c EMPTY 2>/dev/null; then | 48 | if $sum -c EMPTY 2>/dev/null; then |
48 | echo "FAIL: $sum -c EMPTY" | 49 | echo "FAIL: $sum -c EMPTY" |
49 | : $((FAILCOUNT++)) | 50 | : $((FAILCOUNT++)) |
50 | else | 51 | else |
diff --git a/testsuite/sha384sum.tests b/testsuite/sha384sum.tests new file mode 100755 index 000000000..f1449d195 --- /dev/null +++ b/testsuite/sha384sum.tests | |||
@@ -0,0 +1,3 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | . ./md5sum.tests sha384sum c01420bb6613d4bd00396a82033e59e81486cbb045ae0dd2b4c3332e581b3ce09fb1946d6e283acec685778ff205d485 | ||
diff --git a/testsuite/sha3sum.tests b/testsuite/sha3sum.tests index 2cd8e3bf2..631141735 100755 --- a/testsuite/sha3sum.tests +++ b/testsuite/sha3sum.tests | |||
@@ -1,3 +1,7 @@ | |||
1 | #!/bin/sh | 1 | #!/bin/sh |
2 | 2 | ||
3 | . ./md5sum.tests sha3sum 11659f09370139f8ef384f4a6260947fafa6e4fcd87a1ef3f35410e9 | 3 | (. ./md5sum.tests sha3sum 11659f09370139f8ef384f4a6260947fafa6e4fcd87a1ef3f35410e9) \ |
4 | && (. ./md5sum.tests "sha3sum -a224" 11659f09370139f8ef384f4a6260947fafa6e4fcd87a1ef3f35410e9) \ | ||
5 | && (. ./md5sum.tests "sha3sum -a256" 6f69c8d36a9a579a943d878dab38c179d2a9dde12b244aa8840002c0f3d5bb73) \ | ||
6 | && (. ./md5sum.tests "sha3sum -a384" 303913449042257996a869e0378323193b4f58d90eea801b12186a3d65640bd3403d3404c63527424ec43dff842c0cd0) \ | ||
7 | && (. ./md5sum.tests "sha3sum -a512" e14814dccc2fef967af74eb6710885b35dfe660a362c0609b642404987d24a13dac66ad037e6affa5c42631110231655fcf4c972b1457ac49fb83af8113fc51f) | ||
diff --git a/util-linux/lspci.c b/util-linux/lspci.c index b38b46be3..25be23a01 100644 --- a/util-linux/lspci.c +++ b/util-linux/lspci.c | |||
@@ -47,7 +47,7 @@ static int FAST_FUNC fileAction(struct recursive_state *state UNUSED_PARAM, | |||
47 | int pci_class = 0, pci_vid = 0, pci_did = 0; | 47 | int pci_class = 0, pci_vid = 0, pci_did = 0; |
48 | int pci_subsys_vid = 0, pci_subsys_did = 0; | 48 | int pci_subsys_vid = 0, pci_subsys_did = 0; |
49 | 49 | ||
50 | char *uevent_filename = concat_path_file(fileName, "/uevent"); | 50 | char *uevent_filename = concat_path_file(fileName, "uevent"); |
51 | parser = config_open2(uevent_filename, fopen_for_read); | 51 | parser = config_open2(uevent_filename, fopen_for_read); |
52 | free(uevent_filename); | 52 | free(uevent_filename); |
53 | 53 | ||
diff --git a/util-linux/lsusb.c b/util-linux/lsusb.c index 0a9e505f4..f7d0de32d 100644 --- a/util-linux/lsusb.c +++ b/util-linux/lsusb.c | |||
@@ -50,7 +50,7 @@ static int FAST_FUNC fileAction(struct recursive_state *state UNUSED_PARAM, | |||
50 | char *tokens[4]; | 50 | char *tokens[4]; |
51 | char *busnum = NULL, *devnum = NULL; | 51 | char *busnum = NULL, *devnum = NULL; |
52 | int product_vid = 0, product_did = 0; | 52 | int product_vid = 0, product_did = 0; |
53 | char *uevent_filename = concat_path_file(fileName, "/uevent"); | 53 | char *uevent_filename = concat_path_file(fileName, "uevent"); |
54 | 54 | ||
55 | parser = config_open2(uevent_filename, fopen_for_read); | 55 | parser = config_open2(uevent_filename, fopen_for_read); |
56 | free(uevent_filename); | 56 | free(uevent_filename); |
diff --git a/win32/process.c b/win32/process.c index 33f45ee42..0d120936e 100644 --- a/win32/process.c +++ b/win32/process.c | |||
@@ -795,7 +795,7 @@ UNUSED_PARAM | |||
795 | return sp; | 795 | return sp; |
796 | } | 796 | } |
797 | 797 | ||
798 | void FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm) | 798 | int FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm) |
799 | { | 799 | { |
800 | const char *str, *cmdline; | 800 | const char *str, *cmdline; |
801 | 801 | ||
@@ -807,6 +807,7 @@ void FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm) | |||
807 | else | 807 | else |
808 | cmdline = comm; | 808 | cmdline = comm; |
809 | safe_strncpy(buf, cmdline, col); | 809 | safe_strncpy(buf, cmdline, col); |
810 | return 0; | ||
810 | } | 811 | } |
811 | 812 | ||
812 | /** | 813 | /** |