diff options
Diffstat (limited to '')
125 files changed, 5036 insertions, 1561 deletions
@@ -476,6 +476,7 @@ libs-y := \ | |||
476 | findutils/ \ | 476 | findutils/ \ |
477 | init/ \ | 477 | init/ \ |
478 | libbb/ \ | 478 | libbb/ \ |
479 | libbb/yescrypt/ \ | ||
479 | libpwdgrp/ \ | 480 | libpwdgrp/ \ |
480 | loginutils/ \ | 481 | loginutils/ \ |
481 | mailutils/ \ | 482 | mailutils/ \ |
@@ -612,8 +613,12 @@ quiet_cmd_busybox__ ?= LINK $@ | |||
612 | "$(core-y)" \ | 613 | "$(core-y)" \ |
613 | "$(libs-y)" \ | 614 | "$(libs-y)" \ |
614 | "$(LDLIBS)" \ | 615 | "$(LDLIBS)" \ |
615 | "$(CONFIG_EXTRA_LDLIBS)" \ | 616 | $(CONFIG_EXTRA_LDLIBS) \ |
616 | && $(srctree)/scripts/generate_BUFSIZ.sh --post include/common_bufsiz.h | 617 | && $(srctree)/scripts/generate_BUFSIZ.sh --post include/common_bufsiz.h |
618 | # ^^^ note: CONFIG_xyz strings already have double quotes: their value | ||
619 | # is '"LIB LIB2"', therefore $(CONFIG_EXTRA_LDLIBS) above must NOT be written | ||
620 | # as "$(CONFIG_EXTRA_LDLIBS)", it would be passed as ""LIB LIB2"", | ||
621 | # and LIB2 would end up in $9, not $8 (and lost or misinterpreted). | ||
617 | 622 | ||
618 | # Generate System.map | 623 | # Generate System.map |
619 | quiet_cmd_sysmap = SYSMAP | 624 | quiet_cmd_sysmap = SYSMAP |
diff --git a/Makefile.custom b/Makefile.custom index 6f679c4e1..ea5edb1a8 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/archival/Config.src b/archival/Config.src index 6f4f30c43..cbcd7217c 100644 --- a/archival/Config.src +++ b/archival/Config.src | |||
@@ -35,4 +35,15 @@ config FEATURE_LZMA_FAST | |||
35 | This option reduces decompression time by about 25% at the cost of | 35 | This option reduces decompression time by about 25% at the cost of |
36 | a 1K bigger binary. | 36 | a 1K bigger binary. |
37 | 37 | ||
38 | config FEATURE_PATH_TRAVERSAL_PROTECTION | ||
39 | bool "Prevent extraction of filenames with /../ path component" | ||
40 | default n | ||
41 | help | ||
42 | busybox tar and unzip remove "PREFIX/../" (if it exists) | ||
43 | from extracted names. | ||
44 | This option enables this behavior for all other unpacking applets, | ||
45 | such as cpio, ar, rpm. | ||
46 | GNU cpio 2.15 has NO such sanity check. | ||
47 | # try other archivers and document their behavior? | ||
48 | |||
38 | endmenu | 49 | endmenu |
diff --git a/archival/bbunzip.c b/archival/bbunzip.c index b7944a62a..42b4baf88 100644 --- a/archival/bbunzip.c +++ b/archival/bbunzip.c | |||
@@ -71,8 +71,8 @@ int FAST_FUNC bbunpack(char **argv, | |||
71 | goto err; | 71 | goto err; |
72 | } else { | 72 | } else { |
73 | /* "clever zcat" with FILE */ | 73 | /* "clever zcat" with FILE */ |
74 | /* fail_if_not_compressed because zcat refuses uncompressed input */ | 74 | /* die_if_not_compressed because zcat refuses uncompressed input */ |
75 | int fd = open_zipped(filename, /*fail_if_not_compressed:*/ 1); | 75 | int fd = open_zipped(filename, /*die_if_not_compressed:*/ 1); |
76 | if (fd < 0) | 76 | if (fd < 0) |
77 | goto err_name; | 77 | goto err_name; |
78 | xmove_fd(fd, STDIN_FILENO); | 78 | xmove_fd(fd, STDIN_FILENO); |
@@ -80,7 +80,7 @@ int FAST_FUNC bbunpack(char **argv, | |||
80 | } else | 80 | } else |
81 | if (option_mask32 & BBUNPK_SEAMLESS_MAGIC) { | 81 | if (option_mask32 & BBUNPK_SEAMLESS_MAGIC) { |
82 | /* "clever zcat" on stdin */ | 82 | /* "clever zcat" on stdin */ |
83 | if (setup_unzip_on_fd(STDIN_FILENO, /*fail_if_not_compressed*/ 1)) | 83 | if (setup_unzip_on_fd(STDIN_FILENO, /*die_if_not_compressed*/ 1)) |
84 | goto err; | 84 | goto err; |
85 | } | 85 | } |
86 | 86 | ||
diff --git a/archival/cpio.c b/archival/cpio.c index f0d990048..b033b3733 100644 --- a/archival/cpio.c +++ b/archival/cpio.c | |||
@@ -350,6 +350,12 @@ static NOINLINE int cpio_o(void) | |||
350 | st.st_dev = st.st_rdev = 0; | 350 | st.st_dev = st.st_rdev = 0; |
351 | #endif | 351 | #endif |
352 | 352 | ||
353 | if (sizeof(st.st_size) > 4 | ||
354 | && st.st_size > (off_t)0xffffffff | ||
355 | ) { | ||
356 | bb_error_msg_and_die("error: file '%s' is larger than 4GB", name); | ||
357 | } | ||
358 | |||
353 | bytes += printf("070701" | 359 | bytes += printf("070701" |
354 | "%08X%08X%08X%08X%08X%08X%08X" | 360 | "%08X%08X%08X%08X%08X%08X%08X" |
355 | "%08X%08X%08X%08X" /* GNU cpio uses uppercase hex */ | 361 | "%08X%08X%08X%08X" /* GNU cpio uses uppercase hex */ |
@@ -421,6 +427,7 @@ int cpio_main(int argc UNUSED_PARAM, char **argv) | |||
421 | #endif | 427 | #endif |
422 | #endif | 428 | #endif |
423 | "owner\0" Required_argument "R" | 429 | "owner\0" Required_argument "R" |
430 | "file\0" Required_argument "F" | ||
424 | "verbose\0" No_argument "v" | 431 | "verbose\0" No_argument "v" |
425 | "null\0" No_argument "0" | 432 | "null\0" No_argument "0" |
426 | "quiet\0" No_argument "\xff" | 433 | "quiet\0" No_argument "\xff" |
diff --git a/archival/libarchive/data_extract_all.c b/archival/libarchive/data_extract_all.c index 049c2c156..8a69711c1 100644 --- a/archival/libarchive/data_extract_all.c +++ b/archival/libarchive/data_extract_all.c | |||
@@ -65,6 +65,14 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) | |||
65 | } while (--n != 0); | 65 | } while (--n != 0); |
66 | } | 66 | } |
67 | #endif | 67 | #endif |
68 | #if ENABLE_FEATURE_PATH_TRAVERSAL_PROTECTION | ||
69 | /* Strip leading "/" and up to last "/../" path component */ | ||
70 | dst_name = (char *)strip_unsafe_prefix(dst_name); | ||
71 | #endif | ||
72 | // ^^^ This may be a problem if some applets do need to extract absolute names. | ||
73 | // (Probably will need to invent ARCHIVE_ALLOW_UNSAFE_NAME flag). | ||
74 | // You might think that rpm needs it, but in my tests rpm's internal cpio | ||
75 | // archive has names like "./usr/bin/FOO", not "/usr/bin/FOO". | ||
68 | 76 | ||
69 | if (archive_handle->ah_flags & ARCHIVE_CREATE_LEADING_DIRS) { | 77 | if (archive_handle->ah_flags & ARCHIVE_CREATE_LEADING_DIRS) { |
70 | char *slash = strrchr(dst_name, '/'); | 78 | char *slash = strrchr(dst_name, '/'); |
diff --git a/archival/libarchive/open_transformer.c b/archival/libarchive/open_transformer.c index 44715ef25..353f68217 100644 --- a/archival/libarchive/open_transformer.c +++ b/archival/libarchive/open_transformer.c | |||
@@ -157,7 +157,7 @@ void FAST_FUNC fork_transformer(int fd, const char *transform_prog) | |||
157 | /* Used by e.g. rpm which gives us a fd without filename, | 157 | /* Used by e.g. rpm which gives us a fd without filename, |
158 | * thus we can't guess the format from filename's extension. | 158 | * thus we can't guess the format from filename's extension. |
159 | */ | 159 | */ |
160 | static transformer_state_t *setup_transformer_on_fd(int fd, int fail_if_not_compressed) | 160 | static transformer_state_t *setup_transformer_on_fd(int fd, int die_if_not_compressed) |
161 | { | 161 | { |
162 | transformer_state_t *xstate; | 162 | transformer_state_t *xstate; |
163 | 163 | ||
@@ -204,7 +204,7 @@ static transformer_state_t *setup_transformer_on_fd(int fd, int fail_if_not_comp | |||
204 | } | 204 | } |
205 | 205 | ||
206 | /* No known magic seen */ | 206 | /* No known magic seen */ |
207 | if (fail_if_not_compressed) | 207 | if (die_if_not_compressed) |
208 | bb_simple_error_msg_and_die("no gzip" | 208 | bb_simple_error_msg_and_die("no gzip" |
209 | IF_FEATURE_SEAMLESS_BZ2("/bzip2") | 209 | IF_FEATURE_SEAMLESS_BZ2("/bzip2") |
210 | IF_FEATURE_SEAMLESS_XZ("/xz") | 210 | IF_FEATURE_SEAMLESS_XZ("/xz") |
@@ -240,13 +240,15 @@ static void fork_transformer_and_free(transformer_state_t *xstate) | |||
240 | /* Used by e.g. rpm which gives us a fd without filename, | 240 | /* Used by e.g. rpm which gives us a fd without filename, |
241 | * thus we can't guess the format from filename's extension. | 241 | * thus we can't guess the format from filename's extension. |
242 | */ | 242 | */ |
243 | int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_compressed) | 243 | int FAST_FUNC setup_unzip_on_fd(int fd, int die_if_not_compressed) |
244 | { | 244 | { |
245 | transformer_state_t *xstate = setup_transformer_on_fd(fd, fail_if_not_compressed); | 245 | transformer_state_t *xstate = setup_transformer_on_fd(fd, die_if_not_compressed); |
246 | 246 | ||
247 | if (!xstate->xformer) { | 247 | if (!xstate->xformer) { |
248 | /* Not compressed */ | ||
249 | int retval = xstate->signature_skipped; /* never zero */ | ||
248 | free(xstate); | 250 | free(xstate); |
249 | return 1; | 251 | return retval; |
250 | } | 252 | } |
251 | 253 | ||
252 | fork_transformer_and_free(xstate); | 254 | fork_transformer_and_free(xstate); |
@@ -264,7 +266,7 @@ void FAST_FUNC setup_lzma_on_fd(int fd) | |||
264 | } | 266 | } |
265 | #endif | 267 | #endif |
266 | 268 | ||
267 | static transformer_state_t *open_transformer(const char *fname, int fail_if_not_compressed) | 269 | static transformer_state_t *open_transformer(const char *fname, int die_if_not_compressed) |
268 | { | 270 | { |
269 | transformer_state_t *xstate; | 271 | transformer_state_t *xstate; |
270 | int fd; | 272 | int fd; |
@@ -284,18 +286,18 @@ static transformer_state_t *open_transformer(const char *fname, int fail_if_not_ | |||
284 | } | 286 | } |
285 | } | 287 | } |
286 | 288 | ||
287 | xstate = setup_transformer_on_fd(fd, fail_if_not_compressed); | 289 | xstate = setup_transformer_on_fd(fd, die_if_not_compressed); |
288 | 290 | ||
289 | return xstate; | 291 | return xstate; |
290 | } | 292 | } |
291 | 293 | ||
292 | int FAST_FUNC open_zipped(const char *fname, int fail_if_not_compressed) | 294 | int FAST_FUNC open_zipped(const char *fname, int die_if_not_compressed) |
293 | { | 295 | { |
294 | int fd; | 296 | int fd; |
295 | transformer_state_t *xstate; | 297 | transformer_state_t *xstate; |
296 | 298 | ||
297 | xstate = open_transformer(fname, fail_if_not_compressed); | 299 | xstate = open_transformer(fname, die_if_not_compressed); |
298 | if (!xstate) | 300 | if (!xstate) /* open error */ |
299 | return -1; | 301 | return -1; |
300 | 302 | ||
301 | fd = xstate->src_fd; | 303 | fd = xstate->src_fd; |
@@ -326,7 +328,7 @@ void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_ | |||
326 | transformer_state_t *xstate; | 328 | transformer_state_t *xstate; |
327 | char *image; | 329 | char *image; |
328 | 330 | ||
329 | xstate = open_transformer(fname, /*fail_if_not_compressed:*/ 0); | 331 | xstate = open_transformer(fname, /*die_if_not_compressed:*/ 0); |
330 | if (!xstate) /* file open error */ | 332 | if (!xstate) /* file open error */ |
331 | return NULL; | 333 | return NULL; |
332 | 334 | ||
@@ -371,7 +373,7 @@ void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_ | |||
371 | int fd; | 373 | int fd; |
372 | char *image; | 374 | char *image; |
373 | 375 | ||
374 | fd = open_zipped(fname, /*fail_if_not_compressed:*/ 0); | 376 | fd = open_zipped(fname, /*die_if_not_compressed:*/ 0); |
375 | if (fd < 0) | 377 | if (fd < 0) |
376 | return NULL; | 378 | return NULL; |
377 | 379 | ||
diff --git a/archival/libarchive/unsafe_prefix.c b/archival/libarchive/unsafe_prefix.c index 33e487bf9..667081195 100644 --- a/archival/libarchive/unsafe_prefix.c +++ b/archival/libarchive/unsafe_prefix.c | |||
@@ -14,7 +14,11 @@ const char* FAST_FUNC strip_unsafe_prefix(const char *str) | |||
14 | cp++; | 14 | cp++; |
15 | continue; | 15 | continue; |
16 | } | 16 | } |
17 | if (is_prefixed_with(cp, "/../"+1)) { | 17 | /* We are called lots of times. |
18 | * is_prefixed_with(cp, "../") is slower than open-coding it, | ||
19 | * with minimal code growth (~few bytes). | ||
20 | */ | ||
21 | if (cp[0] == '.' && cp[1] == '.' && cp[2] == '/') { | ||
18 | cp += 3; | 22 | cp += 3; |
19 | continue; | 23 | continue; |
20 | } | 24 | } |
diff --git a/archival/rpm.c b/archival/rpm.c index af8db99a6..95a8c79b6 100644 --- a/archival/rpm.c +++ b/archival/rpm.c | |||
@@ -316,7 +316,7 @@ static void extract_cpio(int fd, const char *source_rpm) | |||
316 | archive_handle->src_fd = fd; | 316 | archive_handle->src_fd = fd; |
317 | /*archive_handle->offset = 0; - init_handle() did it */ | 317 | /*archive_handle->offset = 0; - init_handle() did it */ |
318 | 318 | ||
319 | setup_unzip_on_fd(archive_handle->src_fd, /*fail_if_not_compressed:*/ 1); | 319 | setup_unzip_on_fd(archive_handle->src_fd, /*die_if_not_compressed:*/ 1); |
320 | while (get_header_cpio(archive_handle) == EXIT_SUCCESS) | 320 | while (get_header_cpio(archive_handle) == EXIT_SUCCESS) |
321 | continue; | 321 | continue; |
322 | } | 322 | } |
@@ -533,6 +533,7 @@ int rpm2cpio_main(int argc UNUSED_PARAM, char **argv) | |||
533 | // /* We need to know whether child (gzip/bzip/etc) exits abnormally */ | 533 | // /* We need to know whether child (gzip/bzip/etc) exits abnormally */ |
534 | // signal(SIGCHLD, check_errors_in_children); | 534 | // signal(SIGCHLD, check_errors_in_children); |
535 | 535 | ||
536 | str = NULL; | ||
536 | if (ENABLE_FEATURE_SEAMLESS_LZMA | 537 | if (ENABLE_FEATURE_SEAMLESS_LZMA |
537 | && (str = rpm_getstr0(TAG_PAYLOADCOMPRESSOR)) != NULL | 538 | && (str = rpm_getstr0(TAG_PAYLOADCOMPRESSOR)) != NULL |
538 | && strcmp(str, "lzma") == 0 | 539 | && strcmp(str, "lzma") == 0 |
@@ -541,7 +542,11 @@ int rpm2cpio_main(int argc UNUSED_PARAM, char **argv) | |||
541 | // set up decompressor without detection | 542 | // set up decompressor without detection |
542 | setup_lzma_on_fd(rpm_fd); | 543 | setup_lzma_on_fd(rpm_fd); |
543 | } else { | 544 | } else { |
544 | setup_unzip_on_fd(rpm_fd, /*fail_if_not_compressed:*/ 1); | 545 | int signature_bytes = setup_unzip_on_fd(rpm_fd, /*die_if_not_compressed:*/ 0); |
546 | if (signature_bytes != 0) { | ||
547 | xlseek(rpm_fd, - signature_bytes, SEEK_CUR); | ||
548 | bb_error_msg("warning, unknown compression '%s'", str); | ||
549 | } | ||
545 | } | 550 | } |
546 | 551 | ||
547 | if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0) | 552 | if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0) |
diff --git a/archival/tar.c b/archival/tar.c index d6ca6c1e0..38906ba02 100644 --- a/archival/tar.c +++ b/archival/tar.c | |||
@@ -1164,7 +1164,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv) | |||
1164 | * on e.g. tarball with 1st file named "BZh5". | 1164 | * on e.g. tarball with 1st file named "BZh5". |
1165 | */ | 1165 | */ |
1166 | ) { | 1166 | ) { |
1167 | tar_handle->src_fd = open_zipped(tar_filename, /*fail_if_not_compressed:*/ 0); | 1167 | tar_handle->src_fd = open_zipped(tar_filename, /*die_if_not_compressed:*/ 0); |
1168 | if (tar_handle->src_fd < 0) | 1168 | if (tar_handle->src_fd < 0) |
1169 | bb_perror_msg_and_die("can't open '%s'", tar_filename); | 1169 | bb_perror_msg_and_die("can't open '%s'", tar_filename); |
1170 | } else { | 1170 | } else { |
diff --git a/coreutils/cut.c b/coreutils/cut.c index 93b58b493..d81f36bcd 100644 --- a/coreutils/cut.c +++ b/coreutils/cut.c | |||
@@ -143,15 +143,15 @@ static void cut_file(FILE *file, const char *delim, const char *odelim, | |||
143 | } else if (!opt_REGEX && *delim == '\n') { | 143 | } else if (!opt_REGEX && *delim == '\n') { |
144 | unsigned spos = cut_list[cl_pos].startpos; | 144 | unsigned spos = cut_list[cl_pos].startpos; |
145 | 145 | ||
146 | linenum++; | ||
146 | /* get out if we have no more ranges to process or if the lines | 147 | /* get out if we have no more ranges to process or if the lines |
147 | * are lower than what we're interested in */ | 148 | * are lower than what we're interested in */ |
148 | if ((linenum < spos) || END_OF_LIST(cut_list[cl_pos])) | 149 | if (linenum <= spos || END_OF_LIST(cut_list[cl_pos])) |
149 | goto next_line; | 150 | goto next_line; |
150 | 151 | ||
151 | /* if the line we're looking for is lower than the one we were | 152 | /* if the line we're looking for is lower than the one we were |
152 | * passed, it means we displayed it already, so move on */ | 153 | * passed, it means we displayed it already, so move on */ |
153 | while (spos < linenum) { | 154 | while (++spos < linenum) { |
154 | spos++; | ||
155 | /* go to the next list if we're at the end of this one */ | 155 | /* go to the next list if we're at the end of this one */ |
156 | if (spos > cut_list[cl_pos].endpos) { | 156 | if (spos > cut_list[cl_pos].endpos) { |
157 | cl_pos++; | 157 | cl_pos++; |
@@ -161,7 +161,7 @@ static void cut_file(FILE *file, const char *delim, const char *odelim, | |||
161 | spos = cut_list[cl_pos].startpos; | 161 | spos = cut_list[cl_pos].startpos; |
162 | /* get out if the current line is lower than the one | 162 | /* get out if the current line is lower than the one |
163 | * we just became interested in */ | 163 | * we just became interested in */ |
164 | if (linenum < spos) | 164 | if (linenum <= spos) |
165 | goto next_line; | 165 | goto next_line; |
166 | } | 166 | } |
167 | } | 167 | } |
@@ -280,7 +280,6 @@ static void cut_file(FILE *file, const char *delim, const char *odelim, | |||
280 | /* if we printed anything, finish with newline */ | 280 | /* if we printed anything, finish with newline */ |
281 | putchar('\n'); | 281 | putchar('\n'); |
282 | next_line: | 282 | next_line: |
283 | linenum++; | ||
284 | free(line); | 283 | free(line); |
285 | } /* while (got line) */ | 284 | } /* while (got line) */ |
286 | 285 | ||
@@ -399,7 +398,7 @@ int cut_main(int argc UNUSED_PARAM, char **argv) | |||
399 | //if (nranges == 0) | 398 | //if (nranges == 0) |
400 | // bb_simple_error_msg_and_die("missing list of positions"); | 399 | // bb_simple_error_msg_and_die("missing list of positions"); |
401 | //^^^ this is impossible since one of -bcfF is required, | 400 | //^^^ this is impossible since one of -bcfF is required, |
402 | // they populate LIST with non-empty string and when it is parsed, | 401 | // they populate LIST with non-NULL string and when it is parsed, |
403 | // cut_list[] gets at least one element. | 402 | // cut_list[] gets at least one element. |
404 | 403 | ||
405 | /* now that the lists are parsed, we need to sort them to make life | 404 | /* now that the lists are parsed, we need to sort them to make life |
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/df.c b/coreutils/df.c index 03aa78148..fba23246f 100644 --- a/coreutils/df.c +++ b/coreutils/df.c | |||
@@ -155,6 +155,9 @@ int df_main(int argc UNUSED_PARAM, char **argv) | |||
155 | , &opt_t | 155 | , &opt_t |
156 | IF_FEATURE_DF_FANCY(, &chp) | 156 | IF_FEATURE_DF_FANCY(, &chp) |
157 | ); | 157 | ); |
158 | /* -k overrides $POSIXLY_CORRECT: */ | ||
159 | if (opt & OPT_KILO) | ||
160 | df_disp_hr = 1024; | ||
158 | if (opt & OPT_MEGA) | 161 | if (opt & OPT_MEGA) |
159 | df_disp_hr = 1024*1024; | 162 | df_disp_hr = 1024*1024; |
160 | 163 | ||
@@ -185,8 +188,8 @@ int df_main(int argc UNUSED_PARAM, char **argv) | |||
185 | if (disp_units_hdr == NULL) { | 188 | if (disp_units_hdr == NULL) { |
186 | #if ENABLE_FEATURE_HUMAN_READABLE | 189 | #if ENABLE_FEATURE_HUMAN_READABLE |
187 | disp_units_hdr = xasprintf("%s-blocks", | 190 | disp_units_hdr = xasprintf("%s-blocks", |
188 | /* print df_disp_hr, show no fractionals, | 191 | /* print df_disp_hr; show no fractionals; |
189 | * use suffixes if OPT_POSIX is set in opt */ | 192 | * if -P, unit=1 (print it in full, no KMG suffixes) */ |
190 | make_human_readable_str(df_disp_hr, 0, !!(opt & OPT_POSIX)) | 193 | make_human_readable_str(df_disp_hr, 0, !!(opt & OPT_POSIX)) |
191 | ); | 194 | ); |
192 | #else | 195 | #else |
diff --git a/coreutils/ls.c b/coreutils/ls.c index cc809b797..c24561576 100644 --- a/coreutils/ls.c +++ b/coreutils/ls.c | |||
@@ -126,6 +126,8 @@ | |||
126 | //usage: "\n -F Append indicator (one of */=@|) to names" | 126 | //usage: "\n -F Append indicator (one of */=@|) to names" |
127 | //usage: ) | 127 | //usage: ) |
128 | //usage: "\n -l Long format" | 128 | //usage: "\n -l Long format" |
129 | ////usage: "\n -g Long format without group column" | ||
130 | ////TODO: support -G too ("suppress owner column", GNUism) | ||
129 | //usage: "\n -i List inode numbers" | 131 | //usage: "\n -i List inode numbers" |
130 | //usage: "\n -n List numeric UIDs and GIDs instead of names" | 132 | //usage: "\n -n List numeric UIDs and GIDs instead of names" |
131 | //usage: "\n -s List allocated blocks" | 133 | //usage: "\n -s List allocated blocks" |
@@ -159,6 +161,8 @@ | |||
159 | //usage: IF_FEATURE_LS_WIDTH( | 161 | //usage: IF_FEATURE_LS_WIDTH( |
160 | //usage: "\n -w N Format N columns wide" | 162 | //usage: "\n -w N Format N columns wide" |
161 | //usage: ) | 163 | //usage: ) |
164 | ////usage: "\n -Q Double-quote names" | ||
165 | ////usage: "\n -q Replace unprintable chars with '?'" | ||
162 | //usage: IF_FEATURE_LS_COLOR( | 166 | //usage: IF_FEATURE_LS_COLOR( |
163 | //usage: "\n --color[={always,never,auto}]" | 167 | //usage: "\n --color[={always,never,auto}]" |
164 | //usage: ) | 168 | //usage: ) |
@@ -196,27 +200,47 @@ SPLIT_SUBDIR = 2, | |||
196 | 200 | ||
197 | /* -Cadi1l Std options, busybox always supports */ | 201 | /* -Cadi1l Std options, busybox always supports */ |
198 | /* -gnsxA Std options, busybox always supports */ | 202 | /* -gnsxA Std options, busybox always supports */ |
199 | /* -Q GNU option, busybox always supports */ | 203 | /* -Q GNU option, busybox always supports: */ |
200 | /* -k Std option, busybox always supports (by ignoring) */ | 204 | /* -Q, --quote-name */ |
201 | /* It means "for -s, show sizes in kbytes" */ | 205 | /* enclose entry names in double quotes */ |
202 | /* Seems to only affect "POSIXLY_CORRECT=1 ls -sk" */ | ||
203 | /* since otherwise -s shows kbytes anyway */ | ||
204 | /* -LHRctur Std options, busybox optionally supports */ | 206 | /* -LHRctur Std options, busybox optionally supports */ |
205 | /* -Fp Std options, busybox optionally supports */ | 207 | /* -Fp Std options, busybox optionally supports */ |
206 | /* -SXvhTw GNU options, busybox optionally supports */ | 208 | /* -SXvhTw GNU options, busybox optionally supports */ |
207 | /* -T WIDTH Ignored (we don't use tabs on output) */ | 209 | /* -T WIDTH Ignored (we don't use tabs on output) */ |
208 | /* -Z SELinux mandated option, busybox optionally supports */ | 210 | /* -Z SELinux mandated option, busybox optionally supports */ |
211 | /* -q Std option, busybox always supports: */ | ||
212 | /* https://pubs.opengroup.org/onlinepubs/9699919799/utilities/ls.html: */ | ||
213 | /* Force each instance of non-printable filename characters and */ | ||
214 | /* <tab> characters to be written as the <question-mark> ('?') */ | ||
215 | /* character. Implementations may provide this option by default */ | ||
216 | /* if the output is to a terminal device. */ | ||
217 | /* -k Std option, busybox always supports (by ignoring) */ | ||
218 | /* It means "for -s, show sizes in kbytes" */ | ||
219 | /* Seems to only affect "POSIXLY_CORRECT=1 ls -sk" */ | ||
220 | /* since otherwise -s shows kbytes anyway */ | ||
209 | #define ls_options \ | 221 | #define ls_options \ |
210 | "Cadi1lgnsxAk" /* 12 opts, total 12 */ \ | 222 | "Cadi1lgnsxA" /* 11 opts, total 11 */ \ |
211 | IF_FEATURE_LS_FILETYPES("Fp") /* 2, 14 */ \ | 223 | IF_FEATURE_LS_FILETYPES("Fp") /* 2, 13 */ \ |
212 | IF_FEATURE_LS_RECURSIVE("R") /* 1, 15 */ \ | 224 | IF_FEATURE_LS_RECURSIVE("R") /* 1, 14 */ \ |
213 | IF_SELINUX("Z") /* 1, 16 */ \ | 225 | IF_SELINUX("Z") /* 1, 15 */ \ |
214 | "Q" /* 1, 17 */ \ | 226 | "Q" /* 1, 16 */ \ |
215 | IF_FEATURE_LS_TIMESTAMPS("ctu") /* 3, 20 */ \ | 227 | IF_FEATURE_LS_TIMESTAMPS("ctu") /* 3, 19 */ \ |
216 | IF_FEATURE_LS_SORTFILES("SXrv") /* 4, 24 */ \ | 228 | IF_FEATURE_LS_SORTFILES("SXrv") /* 4, 23 */ \ |
217 | IF_FEATURE_LS_FOLLOWLINKS("LH") /* 2, 26 */ \ | 229 | IF_FEATURE_LS_FOLLOWLINKS("LH") /* 2, 25 */ \ |
218 | IF_FEATURE_HUMAN_READABLE("h") /* 1, 27 */ \ | 230 | IF_FEATURE_HUMAN_READABLE("h") /* 1, 26 */ \ |
219 | IF_FEATURE_LS_WIDTH("T:w:") /* 2, 29 */ | 231 | IF_FEATURE_LS_WIDTH("T:w:") /* 2, 28 */ \ |
232 | IF_LONG_OPTS("\xff") /* 1, 29 */ \ | ||
233 | IF_LONG_OPTS("\xfe") /* 1, 30 */ \ | ||
234 | IF_LONG_OPTS("\xfd") /* 1, 31 */ \ | ||
235 | "qk" /* 2, 33 */ | ||
236 | |||
237 | #if ENABLE_LONG_OPTS | ||
238 | static const char ls_longopts[] ALIGN1 = | ||
239 | "full-time\0" No_argument "\xff" | ||
240 | "group-directories-first\0" No_argument "\xfe" | ||
241 | IF_FEATURE_LS_COLOR("color\0" Optional_argument "\xfd") | ||
242 | ; | ||
243 | #endif | ||
220 | 244 | ||
221 | enum { | 245 | enum { |
222 | OPT_C = (1 << 0), | 246 | OPT_C = (1 << 0), |
@@ -230,29 +254,31 @@ enum { | |||
230 | OPT_s = (1 << 8), | 254 | OPT_s = (1 << 8), |
231 | OPT_x = (1 << 9), | 255 | OPT_x = (1 << 9), |
232 | OPT_A = (1 << 10), | 256 | OPT_A = (1 << 10), |
233 | //OPT_k = (1 << 11), | ||
234 | 257 | ||
235 | OPTBIT_F = 12, | 258 | OPTBIT_F = 11, |
236 | OPTBIT_p, /* 13 */ | 259 | OPTBIT_p, /* 12 */ |
237 | OPTBIT_R = OPTBIT_F + 2 * ENABLE_FEATURE_LS_FILETYPES, | 260 | OPTBIT_R = OPTBIT_F + 2 * ENABLE_FEATURE_LS_FILETYPES, |
238 | OPTBIT_Z = OPTBIT_R + 1 * ENABLE_FEATURE_LS_RECURSIVE, | 261 | OPTBIT_Z = OPTBIT_R + 1 * ENABLE_FEATURE_LS_RECURSIVE, |
239 | OPTBIT_Q = OPTBIT_Z + 1 * ENABLE_SELINUX, | 262 | OPTBIT_Q = OPTBIT_Z + 1 * ENABLE_SELINUX, |
240 | OPTBIT_c, /* 17 */ | 263 | OPTBIT_c, /* 16 */ |
241 | OPTBIT_t, /* 18 */ | 264 | OPTBIT_t, /* 17 */ |
242 | OPTBIT_u, /* 19 */ | 265 | OPTBIT_u, /* 18 */ |
243 | OPTBIT_S = OPTBIT_c + 3 * ENABLE_FEATURE_LS_TIMESTAMPS, | 266 | OPTBIT_S = OPTBIT_c + 3 * ENABLE_FEATURE_LS_TIMESTAMPS, |
244 | OPTBIT_X, /* 21 */ | 267 | OPTBIT_X, /* 20 */ |
245 | OPTBIT_r, /* 22 */ | 268 | OPTBIT_r, /* 21 */ |
246 | OPTBIT_v, /* 23 */ | 269 | OPTBIT_v, /* 22 */ |
247 | OPTBIT_L = OPTBIT_S + 4 * ENABLE_FEATURE_LS_SORTFILES, | 270 | OPTBIT_L = OPTBIT_S + 4 * ENABLE_FEATURE_LS_SORTFILES, |
248 | OPTBIT_H, /* 25 */ | 271 | OPTBIT_H, /* 24 */ |
249 | OPTBIT_h = OPTBIT_L + 2 * ENABLE_FEATURE_LS_FOLLOWLINKS, | 272 | OPTBIT_h = OPTBIT_L + 2 * ENABLE_FEATURE_LS_FOLLOWLINKS, |
250 | OPTBIT_T = OPTBIT_h + 1 * ENABLE_FEATURE_HUMAN_READABLE, | 273 | OPTBIT_T = OPTBIT_h + 1 * ENABLE_FEATURE_HUMAN_READABLE, |
251 | OPTBIT_w, /* 28 */ | 274 | OPTBIT_w, /* 27 */ |
252 | OPTBIT_full_time = OPTBIT_T + 2 * ENABLE_FEATURE_LS_WIDTH, | 275 | OPTBIT_full_time = OPTBIT_T + 2 * ENABLE_FEATURE_LS_WIDTH, |
253 | OPTBIT_dirs_first, | 276 | OPTBIT_dirs_first, |
254 | OPTBIT_color, /* 31 */ | 277 | OPTBIT_color, /* 30 */ |
255 | /* with long opts, we use all 32 bits */ | 278 | OPTBIT_q = OPTBIT_color + 1, /* 31 */ |
279 | OPTBIT_k = OPTBIT_q + 1, /* 32 */ | ||
280 | /* with all options enabled, we use all 32 bits and even one extra bit! */ | ||
281 | /* this works because -k is ignored, and getopt32 allows such "ignore" options past 31th bit */ | ||
256 | 282 | ||
257 | OPT_F = (1 << OPTBIT_F) * ENABLE_FEATURE_LS_FILETYPES, | 283 | OPT_F = (1 << OPTBIT_F) * ENABLE_FEATURE_LS_FILETYPES, |
258 | OPT_p = (1 << OPTBIT_p) * ENABLE_FEATURE_LS_FILETYPES, | 284 | OPT_p = (1 << OPTBIT_p) * ENABLE_FEATURE_LS_FILETYPES, |
@@ -274,6 +300,8 @@ enum { | |||
274 | OPT_full_time = (1 << OPTBIT_full_time ) * ENABLE_LONG_OPTS, | 300 | OPT_full_time = (1 << OPTBIT_full_time ) * ENABLE_LONG_OPTS, |
275 | OPT_dirs_first = (1 << OPTBIT_dirs_first) * ENABLE_LONG_OPTS, | 301 | OPT_dirs_first = (1 << OPTBIT_dirs_first) * ENABLE_LONG_OPTS, |
276 | OPT_color = (1 << OPTBIT_color ) * ENABLE_FEATURE_LS_COLOR, | 302 | OPT_color = (1 << OPTBIT_color ) * ENABLE_FEATURE_LS_COLOR, |
303 | OPT_q = (1 << OPTBIT_q), | ||
304 | //-k is ignored: OPT_k = (1 << OPTBIT_k), | ||
277 | }; | 305 | }; |
278 | 306 | ||
279 | /* | 307 | /* |
@@ -327,6 +355,7 @@ struct globals { | |||
327 | #endif | 355 | #endif |
328 | smallint exit_code; | 356 | smallint exit_code; |
329 | smallint show_dirname; | 357 | smallint show_dirname; |
358 | smallint tty_out; | ||
330 | #if ENABLE_FEATURE_LS_WIDTH | 359 | #if ENABLE_FEATURE_LS_WIDTH |
331 | unsigned terminal_width; | 360 | unsigned terminal_width; |
332 | # define G_terminal_width (G.terminal_width) | 361 | # define G_terminal_width (G.terminal_width) |
@@ -343,16 +372,21 @@ struct globals { | |||
343 | setup_common_bufsiz(); \ | 372 | setup_common_bufsiz(); \ |
344 | /* we have to zero it out because of NOEXEC */ \ | 373 | /* we have to zero it out because of NOEXEC */ \ |
345 | memset(&G, 0, sizeof(G)); \ | 374 | memset(&G, 0, sizeof(G)); \ |
346 | IF_FEATURE_LS_WIDTH(G_terminal_width = TERMINAL_WIDTH;) \ | 375 | IF_FEATURE_LS_WIDTH(G_terminal_width = ~0U;) \ |
347 | IF_FEATURE_LS_TIMESTAMPS(time(&G.current_time_t);) \ | 376 | IF_FEATURE_LS_TIMESTAMPS(time(&G.current_time_t);) \ |
348 | } while (0) | 377 | } while (0) |
349 | 378 | ||
350 | #define ESC "\033" | 379 | #define ESC "\033" |
351 | 380 | ||
381 | static int G_isatty(void) | ||
382 | { | ||
383 | if (!G.tty_out) /* not known yet? */ | ||
384 | G.tty_out = isatty(STDOUT_FILENO) + 1; | ||
385 | return (G.tty_out == 2); | ||
386 | } | ||
352 | 387 | ||
353 | /*** Output code ***/ | 388 | /*** Output code ***/ |
354 | 389 | ||
355 | |||
356 | /* FYI type values: 1:fifo 2:char 4:dir 6:blk 8:file 10:link 12:socket | 390 | /* FYI type values: 1:fifo 2:char 4:dir 6:blk 8:file 10:link 12:socket |
357 | * (various wacky OSes: 13:Sun door 14:BSD whiteout 5:XENIX named file | 391 | * (various wacky OSes: 13:Sun door 14:BSD whiteout 5:XENIX named file |
358 | * 3/7:multiplexed char/block device) | 392 | * 3/7:multiplexed char/block device) |
@@ -415,56 +449,93 @@ static char append_char(mode_t mode) | |||
415 | } | 449 | } |
416 | #endif | 450 | #endif |
417 | 451 | ||
452 | /* Return the number of used columns. | ||
453 | * Note that only columnar output uses return value. | ||
454 | * -l and -1 modes don't care. | ||
455 | * coreutils 7.2 also supports: | ||
456 | * ls -b (--escape) = octal escapes (although it doesn't look like working) | ||
457 | * ls -N (--literal) = not escape at all | ||
458 | */ | ||
418 | static unsigned calc_name_len(const char *name) | 459 | static unsigned calc_name_len(const char *name) |
419 | { | 460 | { |
420 | unsigned len; | 461 | unsigned len; |
421 | uni_stat_t uni_stat; | 462 | uni_stat_t uni_stat; |
422 | 463 | ||
423 | // TODO: quote tab as \t, etc, if -Q | 464 | if (!(option_mask32 & (OPT_q|OPT_Q))) |
424 | name = printable_string2(&uni_stat, name); | 465 | return strlen(name); |
425 | 466 | ||
426 | if (!(option_mask32 & OPT_Q)) { | 467 | if (!(option_mask32 & OPT_Q)) { |
468 | /* the most likely branch: "ls" to tty (it auto-enables -q behavior) */ | ||
469 | printable_string2(&uni_stat, name); | ||
427 | return uni_stat.unicode_width; | 470 | return uni_stat.unicode_width; |
428 | } | 471 | } |
429 | 472 | ||
430 | len = 2 + uni_stat.unicode_width; | 473 | len = 2 + strlen(name); |
431 | while (*name) { | 474 | while (*name) { |
475 | unsigned char ch = (unsigned char)*name; | ||
476 | if (ch < ' ' || ch > 0x7e) { | ||
477 | ch -= 7; | ||
478 | if (ch <= 6) { | ||
479 | /* quote chars 7..13 as \a,b,t,n,v,f,r */ | ||
480 | goto two; | ||
481 | } | ||
482 | /* other chars <32 or >126 as \ooo octal */ | ||
483 | len += 3; | ||
484 | goto next; | ||
485 | } | ||
432 | if (*name == '"' || *name == '\\') { | 486 | if (*name == '"' || *name == '\\') { |
487 | two: | ||
433 | len++; | 488 | len++; |
434 | } | 489 | } |
490 | next: | ||
435 | name++; | 491 | name++; |
436 | } | 492 | } |
437 | return len; | 493 | return len; |
438 | } | 494 | } |
439 | |||
440 | /* Return the number of used columns. | ||
441 | * Note that only columnar output uses return value. | ||
442 | * -l and -1 modes don't care. | ||
443 | * coreutils 7.2 also supports: | ||
444 | * ls -b (--escape) = octal escapes (although it doesn't look like working) | ||
445 | * ls -N (--literal) = not escape at all | ||
446 | */ | ||
447 | static unsigned print_name(const char *name) | 495 | static unsigned print_name(const char *name) |
448 | { | 496 | { |
449 | unsigned len; | 497 | unsigned len; |
450 | uni_stat_t uni_stat; | 498 | uni_stat_t uni_stat; |
451 | 499 | ||
452 | // TODO: quote tab as \t, etc, if -Q | 500 | if (!(option_mask32 & (OPT_q|OPT_Q))) { |
453 | name = printable_string2(&uni_stat, name); | 501 | fputs_stdout(name); |
502 | return strlen(name); | ||
503 | } | ||
454 | 504 | ||
455 | if (!(option_mask32 & OPT_Q)) { | 505 | if (!(option_mask32 & OPT_Q)) { |
506 | /* the most likely branch: "ls" to tty (it auto-enables -q behavior) */ | ||
507 | name = printable_string2(&uni_stat, name); | ||
456 | fputs_stdout(name); | 508 | fputs_stdout(name); |
457 | return uni_stat.unicode_width; | 509 | return uni_stat.unicode_width; |
458 | } | 510 | } |
459 | 511 | ||
460 | len = 2 + uni_stat.unicode_width; | 512 | len = 2 + strlen(name); |
461 | putchar('"'); | 513 | putchar('"'); |
462 | while (*name) { | 514 | while (*name) { |
463 | if (*name == '"' || *name == '\\') { | 515 | unsigned char ch = (unsigned char)*name; |
516 | if (ch < ' ' || ch > 0x7e) { | ||
464 | putchar('\\'); | 517 | putchar('\\'); |
518 | ch -= 7; | ||
519 | if (ch <= 6) { | ||
520 | /* quote chars 7..13 as \a,b,t,n,v,f,r */ | ||
521 | ch = c_escape_conv_str07[1 + 3 * ch]; | ||
522 | goto two; | ||
523 | } | ||
524 | /* other chars <32 or >126 as \ooo octal */ | ||
525 | ch = (unsigned char)*name; | ||
526 | putchar('0' + (ch>>6)); | ||
527 | putchar('0' + ((ch>>3) & 7)); | ||
528 | ch = '0' + (ch & 7); | ||
529 | len += 3; | ||
530 | goto put_ch; | ||
531 | } | ||
532 | if (ch == '"' || ch == '\\') { | ||
533 | putchar('\\'); | ||
534 | two: | ||
465 | len++; | 535 | len++; |
466 | } | 536 | } |
467 | putchar(*name); | 537 | put_ch: |
538 | putchar(ch); | ||
468 | name++; | 539 | name++; |
469 | } | 540 | } |
470 | putchar('"'); | 541 | putchar('"'); |
@@ -646,7 +717,7 @@ static void display_files(struct dnode **dn, unsigned nfiles) | |||
646 | unsigned i, ncols, nrows, row, nc; | 717 | unsigned i, ncols, nrows, row, nc; |
647 | unsigned column; | 718 | unsigned column; |
648 | unsigned nexttab; | 719 | unsigned nexttab; |
649 | unsigned column_width = 0; /* used only by coulmnal output */ | 720 | unsigned column_width = 0; /* used only by columnar output */ |
650 | 721 | ||
651 | if (option_mask32 & (OPT_l|OPT_1)) { | 722 | if (option_mask32 & (OPT_l|OPT_1)) { |
652 | ncols = 1; | 723 | ncols = 1; |
@@ -691,6 +762,11 @@ static void display_files(struct dnode **dn, unsigned nfiles) | |||
691 | } | 762 | } |
692 | nexttab = column + column_width; | 763 | nexttab = column + column_width; |
693 | column += display_single(dn[i]); | 764 | column += display_single(dn[i]); |
765 | } else { | ||
766 | /* if -w999999999, ncols can be very large */ | ||
767 | //bb_error_msg(" col:%u ncol:%u i:%i", nc, ncols, i); sleep1(); | ||
768 | /* without "break", we loop millions of times here */ | ||
769 | break; | ||
694 | } | 770 | } |
695 | } | 771 | } |
696 | putchar('\n'); | 772 | putchar('\n'); |
@@ -1090,25 +1166,11 @@ int ls_main(int argc UNUSED_PARAM, char **argv) | |||
1090 | /* need to initialize since --color has _an optional_ argument */ | 1166 | /* need to initialize since --color has _an optional_ argument */ |
1091 | const char *color_opt = color_str; /* "always" */ | 1167 | const char *color_opt = color_str; /* "always" */ |
1092 | #endif | 1168 | #endif |
1093 | #if ENABLE_LONG_OPTS | ||
1094 | static const char ls_longopts[] ALIGN1 = | ||
1095 | "full-time\0" No_argument "\xff" | ||
1096 | "group-directories-first\0" No_argument "\xfe" | ||
1097 | IF_FEATURE_LS_COLOR("color\0" Optional_argument "\xfd") | ||
1098 | ; | ||
1099 | #endif | ||
1100 | 1169 | ||
1101 | INIT_G(); | 1170 | INIT_G(); |
1102 | 1171 | ||
1103 | init_unicode(); | 1172 | init_unicode(); |
1104 | 1173 | ||
1105 | #if ENABLE_FEATURE_LS_WIDTH | ||
1106 | /* obtain the terminal width */ | ||
1107 | G_terminal_width = get_terminal_width(STDIN_FILENO); | ||
1108 | /* go one less... */ | ||
1109 | G_terminal_width--; | ||
1110 | #endif | ||
1111 | |||
1112 | /* process options */ | 1174 | /* process options */ |
1113 | opt = getopt32long(argv, "^" | 1175 | opt = getopt32long(argv, "^" |
1114 | ls_options | 1176 | ls_options |
@@ -1144,6 +1206,29 @@ int ls_main(int argc UNUSED_PARAM, char **argv) | |||
1144 | exit(0); | 1206 | exit(0); |
1145 | #endif | 1207 | #endif |
1146 | 1208 | ||
1209 | /* ftpd secret backdoor? */ | ||
1210 | if (ENABLE_FTPD && applet_name[0] == 'f') { | ||
1211 | /* dirs first are much nicer */ | ||
1212 | opt = option_mask32 |= OPT_dirs_first; | ||
1213 | /* don't show SEcontext */ | ||
1214 | IF_SELINUX(opt = option_mask32 &= ~OPT_Z;) | ||
1215 | /* do not query stdout about size and tty-ness */ | ||
1216 | IF_FEATURE_LS_WIDTH(G_terminal_width = INT_MAX;) | ||
1217 | G.tty_out = 1; /* not a tty */ | ||
1218 | goto skip_if_ftpd; | ||
1219 | } | ||
1220 | |||
1221 | #if ENABLE_FEATURE_LS_WIDTH | ||
1222 | if ((int)G_terminal_width < 0) { | ||
1223 | /* obtain the terminal width */ | ||
1224 | G_terminal_width = get_terminal_width(STDIN_FILENO); | ||
1225 | /* go one less... */ | ||
1226 | G_terminal_width--; | ||
1227 | } | ||
1228 | if (G_terminal_width == 0) /* -w0 */ | ||
1229 | G_terminal_width = INT_MAX; /* "infinite" */ | ||
1230 | #endif | ||
1231 | |||
1147 | #if ENABLE_SELINUX | 1232 | #if ENABLE_SELINUX |
1148 | if (opt & OPT_Z) { | 1233 | if (opt & OPT_Z) { |
1149 | if (!is_selinux_enabled()) | 1234 | if (!is_selinux_enabled()) |
@@ -1157,7 +1242,7 @@ int ls_main(int argc UNUSED_PARAM, char **argv) | |||
1157 | char *p = getenv("LS_COLORS"); | 1242 | char *p = getenv("LS_COLORS"); |
1158 | /* LS_COLORS is unset, or (not empty && not "none") ? */ | 1243 | /* LS_COLORS is unset, or (not empty && not "none") ? */ |
1159 | if (!p || (p[0] && strcmp(p, "none") != 0)) { | 1244 | if (!p || (p[0] && strcmp(p, "none") != 0)) { |
1160 | if (isatty(STDOUT_FILENO)) { | 1245 | if (G_isatty()) { |
1161 | /* check isatty() last because it's expensive (syscall) */ | 1246 | /* check isatty() last because it's expensive (syscall) */ |
1162 | G_show_color = 1; | 1247 | G_show_color = 1; |
1163 | } | 1248 | } |
@@ -1166,23 +1251,28 @@ int ls_main(int argc UNUSED_PARAM, char **argv) | |||
1166 | if (opt & OPT_color) { | 1251 | if (opt & OPT_color) { |
1167 | if (color_opt[0] == 'n') | 1252 | if (color_opt[0] == 'n') |
1168 | G_show_color = 0; | 1253 | G_show_color = 0; |
1169 | else switch (index_in_substrings(color_str, color_opt)) { | 1254 | else if (!G_show_color) { |
1170 | case 3: | 1255 | /* if() is not needed, but avoids extra isatty() if G_show_color is already set */ |
1171 | case 4: | 1256 | /* Check --color=COLOR_OPT and maybe set show_color=1 */ |
1172 | case 5: | 1257 | switch (index_in_substrings(color_str, color_opt)) { |
1173 | if (!is_TERM_dumb() && isatty(STDOUT_FILENO)) { | 1258 | case 3: // auto |
1174 | case 0: | 1259 | case 4: // tty |
1175 | case 1: | 1260 | case 5: // if-tty |
1176 | case 2: | 1261 | if (!is_TERM_dumb() && G_isatty()) { |
1177 | G_show_color = 1; | 1262 | case 0: // always |
1263 | case 1: // yes | ||
1264 | case 2: // force | ||
1265 | G_show_color = 1; | ||
1266 | } | ||
1178 | } | 1267 | } |
1179 | } | 1268 | } |
1180 | } | 1269 | } |
1181 | #endif | 1270 | #endif |
1271 | skip_if_ftpd: | ||
1182 | 1272 | ||
1183 | /* sort out which command line options take precedence */ | 1273 | /* sort out which command line options take precedence */ |
1184 | if (ENABLE_FEATURE_LS_RECURSIVE && (opt & OPT_d)) | 1274 | if (ENABLE_FEATURE_LS_RECURSIVE && (opt & OPT_d)) |
1185 | option_mask32 &= ~OPT_R; /* no recurse if listing only dir */ | 1275 | opt = option_mask32 &= ~OPT_R; /* no recurse if listing only dir */ |
1186 | if (!(opt & OPT_l)) { /* not -l? */ | 1276 | if (!(opt & OPT_l)) { /* not -l? */ |
1187 | if (ENABLE_FEATURE_LS_TIMESTAMPS && ENABLE_FEATURE_LS_SORTFILES) { | 1277 | if (ENABLE_FEATURE_LS_TIMESTAMPS && ENABLE_FEATURE_LS_SORTFILES) { |
1188 | /* when to sort by time? -t[cu] sorts by time even with -l */ | 1278 | /* when to sort by time? -t[cu] sorts by time even with -l */ |
@@ -1190,19 +1280,17 @@ int ls_main(int argc UNUSED_PARAM, char **argv) | |||
1190 | /* without -l, bare -c or -u enable sort too */ | 1280 | /* without -l, bare -c or -u enable sort too */ |
1191 | /* (with -l, bare -c or -u just select which time to show) */ | 1281 | /* (with -l, bare -c or -u just select which time to show) */ |
1192 | if (opt & (OPT_c|OPT_u)) { | 1282 | if (opt & (OPT_c|OPT_u)) { |
1193 | option_mask32 |= OPT_t; | 1283 | opt = option_mask32 |= OPT_t; |
1194 | } | 1284 | } |
1195 | } | 1285 | } |
1196 | } | 1286 | } |
1197 | 1287 | ||
1198 | /* choose a display format if one was not already specified by an option */ | 1288 | /* choose a display format if one was not already specified by an option */ |
1199 | if (!(option_mask32 & (OPT_l|OPT_1|OPT_x|OPT_C))) | 1289 | if (!(opt & (OPT_l|OPT_1|OPT_x|OPT_C))) |
1200 | option_mask32 |= (isatty(STDOUT_FILENO) ? OPT_C : OPT_1); | 1290 | opt = option_mask32 |= (G_isatty() ? OPT_C : OPT_1); |
1201 | 1291 | ||
1202 | if (ENABLE_FTPD && applet_name[0] == 'f') { | 1292 | if (!(opt & OPT_q) && G_isatty()) |
1203 | /* ftpd secret backdoor. dirs first are much nicer */ | 1293 | opt = option_mask32 |= OPT_q; |
1204 | option_mask32 |= OPT_dirs_first; | ||
1205 | } | ||
1206 | 1294 | ||
1207 | argv += optind; | 1295 | argv += optind; |
1208 | if (!argv[0]) | 1296 | if (!argv[0]) |
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/editors/diff.c b/editors/diff.c index 1adc4cbc7..6f4ed9712 100644 --- a/editors/diff.c +++ b/editors/diff.c | |||
@@ -741,7 +741,7 @@ static int diffreg(char *file[2]) | |||
741 | fd = fd_tmp; | 741 | fd = fd_tmp; |
742 | xlseek(fd, 0, SEEK_SET); | 742 | xlseek(fd, 0, SEEK_SET); |
743 | } | 743 | } |
744 | fp[i] = fdopen(fd, "r"); | 744 | fp[i] = xfdopen_for_read(fd); |
745 | } | 745 | } |
746 | 746 | ||
747 | setup_common_bufsiz(); | 747 | setup_common_bufsiz(); |
diff --git a/include/libbb.h b/include/libbb.h index 4d6193795..fba898943 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -1011,13 +1011,13 @@ unsigned bb_clk_tck(void) FAST_FUNC; | |||
1011 | 1011 | ||
1012 | #if SEAMLESS_COMPRESSION | 1012 | #if SEAMLESS_COMPRESSION |
1013 | /* Autodetects gzip/bzip2 formats. fd may be in the middle of the file! */ | 1013 | /* Autodetects gzip/bzip2 formats. fd may be in the middle of the file! */ |
1014 | int setup_unzip_on_fd(int fd, int fail_if_not_compressed) FAST_FUNC; | 1014 | int setup_unzip_on_fd(int fd, int die_if_not_compressed) FAST_FUNC; |
1015 | /* Autodetects .gz etc */ | 1015 | /* Autodetects .gz etc */ |
1016 | extern int open_zipped(const char *fname, int fail_if_not_compressed) FAST_FUNC; | 1016 | extern int open_zipped(const char *fname, int die_if_not_compressed) FAST_FUNC; |
1017 | extern void *xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; | 1017 | extern void *xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; |
1018 | #else | 1018 | #else |
1019 | # define setup_unzip_on_fd(...) (0) | 1019 | # define setup_unzip_on_fd(...) (0) |
1020 | # define open_zipped(fname, fail_if_not_compressed) open((fname), O_RDONLY); | 1020 | # define open_zipped(fname, die_if_not_compressed) open((fname), O_RDONLY); |
1021 | # define xmalloc_open_zipped_read_close(fname, maxsz_p) xmalloc_open_read_close((fname), (maxsz_p)) | 1021 | # define xmalloc_open_zipped_read_close(fname, maxsz_p) xmalloc_open_read_close((fname), (maxsz_p)) |
1022 | #endif | 1022 | #endif |
1023 | /* lzma has no signature, need a little helper. NB: exist only for ENABLE_FEATURE_SEAMLESS_LZMA=y */ | 1023 | /* lzma has no signature, need a little helper. NB: exist only for ENABLE_FEATURE_SEAMLESS_LZMA=y */ |
@@ -1113,6 +1113,32 @@ char *bin2hex(char *dst, const char *src, int count) FAST_FUNC; | |||
1113 | /* Reverse */ | 1113 | /* Reverse */ |
1114 | char* hex2bin(char *dst, const char *src, int count) FAST_FUNC; | 1114 | char* hex2bin(char *dst, const char *src, int count) FAST_FUNC; |
1115 | 1115 | ||
1116 | /* Returns strlen as a bonus */ | ||
1117 | //size_t replace_char(char *s, char what, char with) FAST_FUNC; | ||
1118 | static inline size_t replace_char(char *str, char from, char to) | ||
1119 | { | ||
1120 | char *p = str; | ||
1121 | while (*p) { | ||
1122 | if (*p == from) | ||
1123 | *p = to; | ||
1124 | p++; | ||
1125 | } | ||
1126 | return p - str; | ||
1127 | } | ||
1128 | |||
1129 | extern const char c_escape_conv_str00[]; | ||
1130 | #define c_escape_conv_str07 (c_escape_conv_str00+3) | ||
1131 | |||
1132 | void FAST_FUNC xorbuf_3(void *dst, const void *src1, const void *src2, unsigned count); | ||
1133 | void FAST_FUNC xorbuf(void* buf, const void* mask, unsigned count); | ||
1134 | void FAST_FUNC xorbuf16_aligned_long(void* buf, const void* mask); | ||
1135 | void FAST_FUNC xorbuf64_3_aligned64(void *dst, const void *src1, const void *src2); | ||
1136 | #if BB_UNALIGNED_MEMACCESS_OK | ||
1137 | # define xorbuf16(buf,mask) xorbuf16_aligned_long(buf,mask) | ||
1138 | #else | ||
1139 | void FAST_FUNC xorbuf16(void* buf, const void* mask); | ||
1140 | #endif | ||
1141 | |||
1116 | /* Generate a UUID */ | 1142 | /* Generate a UUID */ |
1117 | void generate_uuid(uint8_t *buf) FAST_FUNC; | 1143 | void generate_uuid(uint8_t *buf) FAST_FUNC; |
1118 | 1144 | ||
@@ -1806,18 +1832,25 @@ extern char *pw_encrypt(const char *clear, const char *salt, int cleanup) FAST_F | |||
1806 | extern int obscure(const char *old, const char *newval, const struct passwd *pwdp) FAST_FUNC; | 1832 | extern int obscure(const char *old, const char *newval, const struct passwd *pwdp) FAST_FUNC; |
1807 | /* | 1833 | /* |
1808 | * rnd is additional random input. New one is returned. | 1834 | * rnd is additional random input. New one is returned. |
1809 | * Useful if you call crypt_make_salt many times in a row: | 1835 | * Useful if you call crypt_make_rand64encoded many times in a row: |
1810 | * rnd = crypt_make_salt(buf1, 4, 0); | 1836 | * rnd = crypt_make_rand64encoded(buf1, 4, 0); |
1811 | * rnd = crypt_make_salt(buf2, 4, rnd); | 1837 | * rnd = crypt_make_rand64encoded(buf2, 4, rnd); |
1812 | * rnd = crypt_make_salt(buf3, 4, rnd); | 1838 | * rnd = crypt_make_rand64encoded(buf3, 4, rnd); |
1813 | * (otherwise we risk having same salt generated) | 1839 | * (otherwise we risk having same salt generated) |
1814 | */ | 1840 | */ |
1815 | extern int crypt_make_salt(char *p, int cnt /*, int rnd*/) FAST_FUNC; | 1841 | extern int crypt_make_rand64encoded(char *p, int cnt /*, int rnd*/) FAST_FUNC; |
1816 | /* "$N$" + sha_salt_16_bytes + NUL */ | 1842 | /* Size of char salt[] to hold randomly-generated salt string |
1817 | #define MAX_PW_SALT_LEN (3 + 16 + 1) | 1843 | * sha256/512: |
1844 | * "$5$" ["rounds=999999999$"] "<sha_salt_16_chars><NUL>" | ||
1845 | * "$6$" ["rounds=999999999$"] "<sha_salt_16_chars><NUL>" | ||
1846 | * #define MAX_PW_SALT_LEN (3 + sizeof("rounds=999999999$")-1 + 16 + 1) | ||
1847 | * yescrypt: | ||
1848 | * "$y$" <up to 8 params of up to 6 chars each> "$" <up to 86 chars salt><NUL> | ||
1849 | * (86 chars are ascii64-encoded 64 binary bytes) | ||
1850 | */ | ||
1851 | #define MAX_PW_SALT_LEN (3 + 8*6 + 1 + 86 + 1) | ||
1818 | extern char* crypt_make_pw_salt(char p[MAX_PW_SALT_LEN], const char *algo) FAST_FUNC; | 1852 | extern char* crypt_make_pw_salt(char p[MAX_PW_SALT_LEN], const char *algo) FAST_FUNC; |
1819 | 1853 | ||
1820 | |||
1821 | /* Returns number of lines changed, or -1 on error */ | 1854 | /* Returns number of lines changed, or -1 on error */ |
1822 | #if !(ENABLE_FEATURE_ADDUSER_TO_GROUP || ENABLE_FEATURE_DEL_USER_FROM_GROUP) | 1855 | #if !(ENABLE_FEATURE_ADDUSER_TO_GROUP || ENABLE_FEATURE_DEL_USER_FROM_GROUP) |
1823 | #define update_passwd(filename, username, data, member) \ | 1856 | #define update_passwd(filename, username, data, member) \ |
@@ -1951,6 +1984,7 @@ int64_t read_key(int fd, char *buffer, int timeout) FAST_FUNC; | |||
1951 | int64_t safe_read_key(int fd, char *buffer, int timeout) FAST_FUNC; | 1984 | int64_t safe_read_key(int fd, char *buffer, int timeout) FAST_FUNC; |
1952 | void read_key_ungets(char *buffer, const char *str, unsigned len) FAST_FUNC; | 1985 | void read_key_ungets(char *buffer, const char *str, unsigned len) FAST_FUNC; |
1953 | 1986 | ||
1987 | int check_got_signal_and_poll(struct pollfd pfd[1], int timeout) FAST_FUNC; | ||
1954 | 1988 | ||
1955 | #if ENABLE_FEATURE_EDITING | 1989 | #if ENABLE_FEATURE_EDITING |
1956 | /* It's NOT just ENABLEd or disabled. It's a number: */ | 1990 | /* It's NOT just ENABLEd or disabled. It's a number: */ |
@@ -1988,7 +2022,7 @@ typedef struct line_input_t { | |||
1988 | # if MAX_HISTORY | 2022 | # if MAX_HISTORY |
1989 | int cnt_history; | 2023 | int cnt_history; |
1990 | int cur_history; | 2024 | int cur_history; |
1991 | int max_history; /* must never be <= 0 */ | 2025 | int max_history; /* must never be < 0 */ |
1992 | # if ENABLE_FEATURE_EDITING_SAVEHISTORY | 2026 | # if ENABLE_FEATURE_EDITING_SAVEHISTORY |
1993 | /* meaning of this field depends on FEATURE_EDITING_SAVE_ON_EXIT: | 2027 | /* meaning of this field depends on FEATURE_EDITING_SAVE_ON_EXIT: |
1994 | * if !FEATURE_EDITING_SAVE_ON_EXIT: "how many lines are | 2028 | * if !FEATURE_EDITING_SAVE_ON_EXIT: "how many lines are |
@@ -2047,33 +2081,6 @@ enum { COMM_LEN = 16 }; | |||
2047 | # endif | 2081 | # endif |
2048 | #endif | 2082 | #endif |
2049 | 2083 | ||
2050 | struct smaprec { | ||
2051 | unsigned long mapped_rw; | ||
2052 | unsigned long mapped_ro; | ||
2053 | unsigned long shared_clean; | ||
2054 | unsigned long shared_dirty; | ||
2055 | unsigned long private_clean; | ||
2056 | unsigned long private_dirty; | ||
2057 | unsigned long stack; | ||
2058 | unsigned long smap_pss, smap_swap; | ||
2059 | unsigned long smap_size; | ||
2060 | // For mixed 32/64 userspace, 32-bit pmap still needs | ||
2061 | // 64-bit field here to correctly show 64-bit processes: | ||
2062 | unsigned long long smap_start; | ||
2063 | // (strictly speaking, other fields need to be wider too, | ||
2064 | // but they are in kbytes, not bytes, and they hold sizes, | ||
2065 | // not start addresses, sizes tend to be less than 4 terabytes) | ||
2066 | char smap_mode[5]; | ||
2067 | char *smap_name; | ||
2068 | }; | ||
2069 | |||
2070 | #if !ENABLE_PMAP | ||
2071 | #define procps_read_smaps(pid, total, cb, data) \ | ||
2072 | procps_read_smaps(pid, total) | ||
2073 | #endif | ||
2074 | int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total, | ||
2075 | void (*cb)(struct smaprec *, void *), void *data); | ||
2076 | |||
2077 | typedef struct procps_status_t { | 2084 | typedef struct procps_status_t { |
2078 | DIR *dir; | 2085 | DIR *dir; |
2079 | IF_FEATURE_SHOW_THREADS(DIR *task_dir;) | 2086 | IF_FEATURE_SHOW_THREADS(DIR *task_dir;) |
@@ -2103,7 +2110,13 @@ typedef struct procps_status_t { | |||
2103 | #endif | 2110 | #endif |
2104 | unsigned tty_major,tty_minor; | 2111 | unsigned tty_major,tty_minor; |
2105 | #if ENABLE_FEATURE_TOPMEM | 2112 | #if ENABLE_FEATURE_TOPMEM |
2106 | struct smaprec smaps; | 2113 | unsigned long mapped_rw; |
2114 | unsigned long mapped_ro; | ||
2115 | unsigned long shared_clean; | ||
2116 | unsigned long shared_dirty; | ||
2117 | unsigned long private_clean; | ||
2118 | unsigned long private_dirty; | ||
2119 | unsigned long stack; | ||
2107 | #endif | 2120 | #endif |
2108 | char state[4]; | 2121 | char state[4]; |
2109 | /* basename of executable in exec(2), read from /proc/N/stat | 2122 | /* basename of executable in exec(2), read from /proc/N/stat |
@@ -2152,11 +2165,15 @@ void free_procps_scan(procps_status_t* sp) FAST_FUNC; | |||
2152 | procps_status_t* procps_scan(procps_status_t* sp, int flags) FAST_FUNC; | 2165 | procps_status_t* procps_scan(procps_status_t* sp, int flags) FAST_FUNC; |
2153 | /* Format cmdline (up to col chars) into char buf[size] */ | 2166 | /* Format cmdline (up to col chars) into char buf[size] */ |
2154 | /* Puts [comm] if cmdline is empty (-> process is a kernel thread) */ | 2167 | /* Puts [comm] if cmdline is empty (-> process is a kernel thread) */ |
2155 | void read_cmdline(char *buf, int size, unsigned pid, const char *comm) FAST_FUNC; | 2168 | int read_cmdline(char *buf, int size, unsigned pid, const char *comm) FAST_FUNC; |
2156 | pid_t *find_pid_by_name(const char* procName) FAST_FUNC; | 2169 | pid_t *find_pid_by_name(const char* procName) FAST_FUNC; |
2157 | pid_t *pidlist_reverse(pid_t *pidList) FAST_FUNC; | 2170 | pid_t *pidlist_reverse(pid_t *pidList) FAST_FUNC; |
2158 | int starts_with_cpu(const char *str) FAST_FUNC; | 2171 | int starts_with_cpu(const char *str) FAST_FUNC; |
2159 | unsigned get_cpu_count(void) FAST_FUNC; | 2172 | unsigned get_cpu_count(void) FAST_FUNC; |
2173 | /* Some internals reused by pmap: */ | ||
2174 | unsigned long FAST_FUNC fast_strtoul_10(char **endptr); | ||
2175 | unsigned long long FAST_FUNC fast_strtoull_16(char **endptr); | ||
2176 | char* FAST_FUNC skip_fields(char *str, int count); | ||
2160 | 2177 | ||
2161 | 2178 | ||
2162 | /* Use strict=1 if you process input from untrusted source: | 2179 | /* Use strict=1 if you process input from untrusted source: |
@@ -2182,6 +2199,21 @@ char *decode_base64(char *dst, const char **pp_src) FAST_FUNC; | |||
2182 | char *decode_base32(char *dst, const char **pp_src) FAST_FUNC; | 2199 | char *decode_base32(char *dst, const char **pp_src) FAST_FUNC; |
2183 | void read_base64(FILE *src_stream, FILE *dst_stream, int flags) FAST_FUNC; | 2200 | void read_base64(FILE *src_stream, FILE *dst_stream, int flags) FAST_FUNC; |
2184 | 2201 | ||
2202 | int FAST_FUNC i2a64(int i); | ||
2203 | int FAST_FUNC a2i64(char c); | ||
2204 | char* FAST_FUNC num2str64_lsb_first(char *s, unsigned v, int n); | ||
2205 | |||
2206 | enum { | ||
2207 | /* how many bytes XYZ_end() fills */ | ||
2208 | MD5_OUTSIZE = 16, | ||
2209 | SHA1_OUTSIZE = 20, | ||
2210 | SHA256_OUTSIZE = 32, | ||
2211 | SHA384_OUTSIZE = 48, | ||
2212 | SHA512_OUTSIZE = 64, | ||
2213 | //SHA3-224_OUTSIZE = 28, | ||
2214 | /* size of input block */ | ||
2215 | SHA2_INSIZE = 64, | ||
2216 | }; | ||
2185 | typedef struct md5_ctx_t { | 2217 | typedef struct md5_ctx_t { |
2186 | uint8_t wbuffer[64]; /* always correctly aligned for uint64_t */ | 2218 | uint8_t wbuffer[64]; /* always correctly aligned for uint64_t */ |
2187 | void (*process_block)(struct md5_ctx_t*) FAST_FUNC; | 2219 | void (*process_block)(struct md5_ctx_t*) FAST_FUNC; |
@@ -2195,6 +2227,7 @@ typedef struct sha512_ctx_t { | |||
2195 | uint64_t hash[8]; | 2227 | uint64_t hash[8]; |
2196 | uint8_t wbuffer[128]; /* always correctly aligned for uint64_t */ | 2228 | uint8_t wbuffer[128]; /* always correctly aligned for uint64_t */ |
2197 | } sha512_ctx_t; | 2229 | } sha512_ctx_t; |
2230 | typedef struct sha512_ctx_t sha384_ctx_t; | ||
2198 | typedef struct sha3_ctx_t { | 2231 | typedef struct sha3_ctx_t { |
2199 | uint64_t state[25]; | 2232 | uint64_t state[25]; |
2200 | unsigned bytes_queued; | 2233 | unsigned bytes_queued; |
@@ -2212,20 +2245,46 @@ void sha256_begin(sha256_ctx_t *ctx) FAST_FUNC; | |||
2212 | void sha512_begin(sha512_ctx_t *ctx) FAST_FUNC; | 2245 | void sha512_begin(sha512_ctx_t *ctx) FAST_FUNC; |
2213 | void sha512_hash(sha512_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC; | 2246 | void sha512_hash(sha512_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC; |
2214 | unsigned sha512_end(sha512_ctx_t *ctx, void *resbuf) FAST_FUNC; | 2247 | unsigned sha512_end(sha512_ctx_t *ctx, void *resbuf) FAST_FUNC; |
2248 | void sha384_begin(sha384_ctx_t *ctx) FAST_FUNC; | ||
2249 | #define sha384_hash sha512_hash | ||
2250 | unsigned sha384_end(sha384_ctx_t *ctx, void *resbuf) FAST_FUNC; | ||
2215 | void sha3_begin(sha3_ctx_t *ctx) FAST_FUNC; | 2251 | void sha3_begin(sha3_ctx_t *ctx) FAST_FUNC; |
2216 | void sha3_hash(sha3_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC; | 2252 | void sha3_hash(sha3_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC; |
2217 | unsigned sha3_end(sha3_ctx_t *ctx, void *resbuf) FAST_FUNC; | 2253 | unsigned sha3_end(sha3_ctx_t *ctx, void *resbuf) FAST_FUNC; |
2254 | void FAST_FUNC sha256_block(const void *in, size_t len, uint8_t hash[32]); | ||
2218 | /* TLS benefits from knowing that sha1 and sha256 share these. Give them "agnostic" names too */ | 2255 | /* TLS benefits from knowing that sha1 and sha256 share these. Give them "agnostic" names too */ |
2219 | typedef struct md5_ctx_t md5sha_ctx_t; | 2256 | typedef struct md5_ctx_t md5sha_ctx_t; |
2220 | #define md5sha_hash md5_hash | 2257 | #define md5sha_hash md5_hash |
2221 | #define sha_end sha1_end | 2258 | #define sha_end sha1_end |
2222 | enum { | 2259 | |
2223 | MD5_OUTSIZE = 16, | 2260 | /* RFC 2104 HMAC (hash-based message authentication code) */ |
2224 | SHA1_OUTSIZE = 20, | 2261 | typedef struct hmac_ctx { |
2225 | SHA256_OUTSIZE = 32, | 2262 | md5sha_ctx_t hashed_key_xor_ipad; |
2226 | SHA512_OUTSIZE = 64, | 2263 | md5sha_ctx_t hashed_key_xor_opad; |
2227 | SHA3_OUTSIZE = 28, | 2264 | } hmac_ctx_t; |
2228 | }; | 2265 | #define HMAC_ONLY_SHA256 (!ENABLE_FEATURE_TLS_SHA1) |
2266 | typedef void md5sha_begin_func(md5sha_ctx_t *ctx) FAST_FUNC; | ||
2267 | #if HMAC_ONLY_SHA256 | ||
2268 | #define hmac_begin(ctx,key,key_size,begin) \ | ||
2269 | hmac_begin(ctx,key,key_size) | ||
2270 | #endif | ||
2271 | void FAST_FUNC hmac_begin(hmac_ctx_t *ctx, const uint8_t *key, unsigned key_size, md5sha_begin_func *begin); | ||
2272 | static ALWAYS_INLINE void hmac_hash(hmac_ctx_t *ctx, const void *in, size_t len) | ||
2273 | { | ||
2274 | md5sha_hash(&ctx->hashed_key_xor_ipad, in, len); | ||
2275 | } | ||
2276 | unsigned FAST_FUNC hmac_end(hmac_ctx_t *ctx, uint8_t *out); | ||
2277 | #if HMAC_ONLY_SHA256 | ||
2278 | #define hmac_block(key,key_size,begin,in,sz,out) \ | ||
2279 | hmac_block(key,key_size,in,sz,out) | ||
2280 | #endif | ||
2281 | unsigned FAST_FUNC hmac_block(const uint8_t *key, unsigned key_size, | ||
2282 | md5sha_begin_func *begin, | ||
2283 | const void *in, unsigned sz, | ||
2284 | uint8_t *out); | ||
2285 | /* HMAC helpers for TLS: */ | ||
2286 | void FAST_FUNC hmac_hash_v(hmac_ctx_t *ctx, va_list va); | ||
2287 | unsigned FAST_FUNC hmac_peek_hash(hmac_ctx_t *ctx, uint8_t *out, ...); | ||
2229 | 2288 | ||
2230 | extern uint32_t *global_crc32_table; | 2289 | extern uint32_t *global_crc32_table; |
2231 | uint32_t *crc32_filltable(uint32_t *tbl256, int endian) FAST_FUNC; | 2290 | uint32_t *crc32_filltable(uint32_t *tbl256, int endian) FAST_FUNC; |
@@ -2337,26 +2396,10 @@ extern struct globals *BB_GLOBAL_CONST ptr_to_globals; | |||
2337 | #define barrier() asm volatile ("":::"memory") | 2396 | #define barrier() asm volatile ("":::"memory") |
2338 | 2397 | ||
2339 | #if defined(__clang_major__) && __clang_major__ >= 9 | 2398 | #if defined(__clang_major__) && __clang_major__ >= 9 |
2340 | /* Clang/llvm drops assignment to "constant" storage. Silently. | 2399 | /* {ASSIGN,XZALLOC}_CONST_PTR() are out-of-line functions |
2341 | * Needs serious convincing to not eliminate the store. | 2400 | * to prevent clang from reading pointer before it is assigned. |
2342 | */ | ||
2343 | static ALWAYS_INLINE void* not_const_pp(const void *p) | ||
2344 | { | ||
2345 | void *pp; | ||
2346 | asm volatile ( | ||
2347 | "# forget that p points to const" | ||
2348 | : /*outputs*/ "=r" (pp) | ||
2349 | : /*inputs*/ "0" (p) | ||
2350 | ); | ||
2351 | return pp; | ||
2352 | } | ||
2353 | # define ASSIGN_CONST_PTR(pptr, v) do { \ | ||
2354 | *(void**)not_const_pp(pptr) = (void*)(v); \ | ||
2355 | barrier(); \ | ||
2356 | } while (0) | ||
2357 | /* XZALLOC_CONST_PTR() is an out-of-line function to prevent | ||
2358 | * clang from reading pointer before it is assigned. | ||
2359 | */ | 2401 | */ |
2402 | void ASSIGN_CONST_PTR(const void *pptr, void *v) FAST_FUNC; | ||
2360 | void XZALLOC_CONST_PTR(const void *pptr, size_t size) FAST_FUNC; | 2403 | void XZALLOC_CONST_PTR(const void *pptr, size_t size) FAST_FUNC; |
2361 | #else | 2404 | #else |
2362 | # define ASSIGN_CONST_PTR(pptr, v) do { \ | 2405 | # define ASSIGN_CONST_PTR(pptr, v) do { \ |
diff --git a/include/platform.h b/include/platform.h index ea0512f36..e10c5b558 100644 --- a/include/platform.h +++ b/include/platform.h | |||
@@ -187,7 +187,7 @@ | |||
187 | #elif defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN | 187 | #elif defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN |
188 | # define BB_BIG_ENDIAN 0 | 188 | # define BB_BIG_ENDIAN 0 |
189 | # define BB_LITTLE_ENDIAN 1 | 189 | # define BB_LITTLE_ENDIAN 1 |
190 | #elif defined(__386__) | 190 | #elif defined(__i386__) |
191 | # define BB_BIG_ENDIAN 0 | 191 | # define BB_BIG_ENDIAN 0 |
192 | # define BB_LITTLE_ENDIAN 1 | 192 | # define BB_LITTLE_ENDIAN 1 |
193 | #else | 193 | #else |
diff --git a/include/usage.src.h b/include/usage.src.h index 5d2038834..0881337f8 100644 --- a/include/usage.src.h +++ b/include/usage.src.h | |||
@@ -17,11 +17,11 @@ | |||
17 | #define scripted_trivial_usage NOUSAGE_STR | 17 | #define scripted_trivial_usage NOUSAGE_STR |
18 | #define scripted_full_usage "" | 18 | #define scripted_full_usage "" |
19 | 19 | ||
20 | #if !ENABLE_USE_BB_CRYPT || ENABLE_USE_BB_CRYPT_SHA | 20 | #if !ENABLE_USE_BB_CRYPT |
21 | # define CRYPT_METHODS_HELP_STR "des,md5,sha256/512" \ | 21 | # define CRYPT_METHODS_HELP_STR "des,md5,sha256/512,yescrypt" \ |
22 | " (default "CONFIG_FEATURE_DEFAULT_PASSWD_ALGO")" | 22 | " (default "CONFIG_FEATURE_DEFAULT_PASSWD_ALGO")" |
23 | #else | 23 | #else |
24 | # define CRYPT_METHODS_HELP_STR "des,md5" \ | 24 | # define CRYPT_METHODS_HELP_STR "des,md5"IF_USE_BB_CRYPT_SHA(",sha256/512")IF_USE_BB_CRYPT_YES(",yescrypt") \ |
25 | " (default "CONFIG_FEATURE_DEFAULT_PASSWD_ALGO")" | 25 | " (default "CONFIG_FEATURE_DEFAULT_PASSWD_ALGO")" |
26 | #endif | 26 | #endif |
27 | 27 | ||
diff --git a/init/bootchartd.c b/init/bootchartd.c index 0929890a3..a5447c6ad 100644 --- a/init/bootchartd.c +++ b/init/bootchartd.c | |||
@@ -133,7 +133,7 @@ static void dump_file(FILE *fp, const char *filename) | |||
133 | static int dump_procs(FILE *fp, int look_for_login_process) | 133 | static int dump_procs(FILE *fp, int look_for_login_process) |
134 | { | 134 | { |
135 | struct dirent *entry; | 135 | struct dirent *entry; |
136 | DIR *dir = opendir("/proc"); | 136 | DIR *dir = xopendir("/proc"); |
137 | int found_login_process = 0; | 137 | int found_login_process = 0; |
138 | 138 | ||
139 | fputs(G.jiffy_line, fp); | 139 | fputs(G.jiffy_line, fp); |
diff --git a/init/init.c b/init/init.c index 2ee1e4cde..294be9952 100644 --- a/init/init.c +++ b/init/init.c | |||
@@ -1198,17 +1198,29 @@ int init_main(int argc UNUSED_PARAM, char **argv) | |||
1198 | /* Wait for any child process(es) to exit */ | 1198 | /* Wait for any child process(es) to exit */ |
1199 | while (1) { | 1199 | while (1) { |
1200 | pid_t wpid; | 1200 | pid_t wpid; |
1201 | int status; | ||
1201 | struct init_action *a; | 1202 | struct init_action *a; |
1202 | 1203 | ||
1203 | wpid = waitpid(-1, NULL, WNOHANG); | 1204 | wpid = wait_any_nohang(&status); |
1204 | if (wpid <= 0) | 1205 | if (wpid <= 0) |
1205 | break; | 1206 | break; |
1206 | 1207 | ||
1207 | a = mark_terminated(wpid); | 1208 | a = mark_terminated(wpid); |
1208 | if (a) { | 1209 | if (a) { |
1209 | message(L_LOG, "process '%s' (pid %u) exited. " | 1210 | const char *s = "killed, signal"; |
1211 | int ex = WTERMSIG(status); | ||
1212 | /* "if (!WIFSIGNALED(status))" generates more code: | ||
1213 | * on linux, WIFEXITED(status) is "WTERMSIG(status) == 0" | ||
1214 | * and WTERMSIG(status) is known, so compiler optimizes. | ||
1215 | */ | ||
1216 | if (WIFEXITED(status)) { | ||
1217 | s = "exited, exitcode"; | ||
1218 | ex = WEXITSTATUS(status); | ||
1219 | } | ||
1220 | message(L_LOG, "process '%s' (pid %u) %s:%d. " | ||
1210 | "Scheduling for restart.", | 1221 | "Scheduling for restart.", |
1211 | a->command, (unsigned)wpid); | 1222 | a->command, (unsigned)wpid, |
1223 | s, ex); | ||
1212 | } | 1224 | } |
1213 | } | 1225 | } |
1214 | 1226 | ||
diff --git a/libbb/Config.src b/libbb/Config.src index b980f19a9..55e670dcd 100644 --- a/libbb/Config.src +++ b/libbb/Config.src | |||
@@ -182,8 +182,8 @@ config FEATURE_EDITING_VI | |||
182 | config FEATURE_EDITING_HISTORY | 182 | config FEATURE_EDITING_HISTORY |
183 | int "History size" | 183 | int "History size" |
184 | # Don't allow way too big values here, code uses fixed "char *history[N]" struct member | 184 | # Don't allow way too big values here, code uses fixed "char *history[N]" struct member |
185 | range 0 9999 | 185 | range 0 2000 |
186 | default 255 | 186 | default 200 |
187 | depends on FEATURE_EDITING | 187 | depends on FEATURE_EDITING |
188 | help | 188 | help |
189 | Specify command history size (0 - disable). | 189 | Specify command history size (0 - disable). |
diff --git a/libbb/bitops.c b/libbb/bitops.c new file mode 100644 index 000000000..467e1a2d9 --- /dev/null +++ b/libbb/bitops.c | |||
@@ -0,0 +1,128 @@ | |||
1 | /* | ||
2 | * Utility routines. | ||
3 | * | ||
4 | * Copyright (C) 2025 by Denys Vlasenko <vda.linux@googlemail.com> | ||
5 | * | ||
6 | * Licensed under GPLv2, see file LICENSE in this source tree. | ||
7 | */ | ||
8 | //kbuild:lib-y += bitops.o | ||
9 | |||
10 | #include "libbb.h" | ||
11 | |||
12 | void FAST_FUNC xorbuf_3(void *dst, const void *src1, const void *src2, unsigned count) | ||
13 | { | ||
14 | uint8_t *d = dst; | ||
15 | const uint8_t *s1 = src1; | ||
16 | const uint8_t *s2 = src2; | ||
17 | #if BB_UNALIGNED_MEMACCESS_OK | ||
18 | while (count >= sizeof(long)) { | ||
19 | *(long*)d = *(long*)s1 ^ *(long*)s2; | ||
20 | count -= sizeof(long); | ||
21 | d += sizeof(long); | ||
22 | s1 += sizeof(long); | ||
23 | s2 += sizeof(long); | ||
24 | } | ||
25 | #endif | ||
26 | while (count--) | ||
27 | *d++ = *s1++ ^ *s2++; | ||
28 | } | ||
29 | |||
30 | void FAST_FUNC xorbuf(void *dst, const void *src, unsigned count) | ||
31 | { | ||
32 | xorbuf_3(dst, dst, src, count); | ||
33 | } | ||
34 | |||
35 | void FAST_FUNC xorbuf16_aligned_long(void *dst, const void *src) | ||
36 | { | ||
37 | #if defined(__SSE__) /* any x86_64 has it */ | ||
38 | asm volatile( | ||
39 | "\n movups (%0),%%xmm0" | ||
40 | "\n movups (%1),%%xmm1" // can't just xorps(%1),%%xmm0: | ||
41 | "\n xorps %%xmm1,%%xmm0" // SSE requires 16-byte alignment | ||
42 | "\n movups %%xmm0,(%0)" | ||
43 | "\n" | ||
44 | : "=r" (dst), "=r" (src) | ||
45 | : "0" (dst), "1" (src) | ||
46 | : "xmm0", "xmm1", "memory" | ||
47 | ); | ||
48 | #else | ||
49 | unsigned long *d = dst; | ||
50 | const unsigned long *s = src; | ||
51 | d[0] ^= s[0]; | ||
52 | # if LONG_MAX <= 0x7fffffffffffffff | ||
53 | d[1] ^= s[1]; | ||
54 | # if LONG_MAX == 0x7fffffff | ||
55 | d[2] ^= s[2]; | ||
56 | d[3] ^= s[3]; | ||
57 | # endif | ||
58 | # endif | ||
59 | #endif | ||
60 | } | ||
61 | // The above can be inlined in libbb.h, in a way where compiler | ||
62 | // is even free to use better addressing modes than (%reg), and | ||
63 | // to keep the result in a register | ||
64 | // (to not store it to memory after each XOR): | ||
65 | //#if defined(__SSE__) | ||
66 | //#include <xmmintrin.h> | ||
67 | //^^^ or just: typedef float __m128_u attribute((__vector_size__(16),__may_alias__,__aligned__(1))); | ||
68 | //static ALWAYS_INLINE void xorbuf16_aligned_long(void *dst, const void *src) | ||
69 | //{ | ||
70 | // __m128_u xmm0, xmm1; | ||
71 | // asm volatile( | ||
72 | //"\n xorps %1,%0" | ||
73 | // : "=x" (xmm0), "=x" (xmm1) | ||
74 | // : "0" (*(__m128_u*)dst), "1" (*(__m128_u*)src) | ||
75 | // ); | ||
76 | // *(__m128_u*)dst = xmm0; // this store may be optimized out! | ||
77 | //} | ||
78 | //#endif | ||
79 | // but I don't trust gcc optimizer enough to not generate some monstrosity. | ||
80 | // See GMULT() function in TLS code as an example. | ||
81 | |||
82 | void FAST_FUNC xorbuf64_3_aligned64(void *dst, const void *src1, const void *src2) | ||
83 | { | ||
84 | #if defined(__SSE__) /* any x86_64 has it */ | ||
85 | asm volatile( | ||
86 | "\n movups 0*16(%1),%%xmm0" | ||
87 | "\n movups 0*16(%2),%%xmm1" // can't just xorps(%2),%%xmm0: | ||
88 | "\n xorps %%xmm1,%%xmm0" // SSE requires 16-byte alignment, we have only 8-byte | ||
89 | "\n movups %%xmm0,0*16(%0)" | ||
90 | "\n movups 1*16(%1),%%xmm0" | ||
91 | "\n movups 1*16(%2),%%xmm1" | ||
92 | "\n xorps %%xmm1,%%xmm0" | ||
93 | "\n movups %%xmm0,1*16(%0)" | ||
94 | "\n movups 2*16(%1),%%xmm0" | ||
95 | "\n movups 2*16(%2),%%xmm1" | ||
96 | "\n xorps %%xmm1,%%xmm0" | ||
97 | "\n movups %%xmm0,2*16(%0)" | ||
98 | "\n movups 3*16(%1),%%xmm0" | ||
99 | "\n movups 3*16(%2),%%xmm1" | ||
100 | "\n xorps %%xmm1,%%xmm0" | ||
101 | "\n movups %%xmm0,3*16(%0)" | ||
102 | "\n" | ||
103 | : "=r" (dst), "=r" (src1), "=r" (src2) | ||
104 | : "0" (dst), "1" (src1), "2" (src2) | ||
105 | : "xmm0", "xmm1", "memory" | ||
106 | ); | ||
107 | #else | ||
108 | long *d = dst; | ||
109 | const long *s1 = src1; | ||
110 | const long *s2 = src2; | ||
111 | unsigned count = 64 / sizeof(long); | ||
112 | do { | ||
113 | *d++ = *s1++ ^ *s2++; | ||
114 | } while (--count != 0); | ||
115 | #endif | ||
116 | } | ||
117 | |||
118 | #if !BB_UNALIGNED_MEMACCESS_OK | ||
119 | void FAST_FUNC xorbuf16(void *dst, const void *src) | ||
120 | { | ||
121 | #define p_aligned(a) (((uintptr_t)(a) & (sizeof(long)-1)) == 0) | ||
122 | if (p_aligned(src) && p_aligned(dst)) { | ||
123 | xorbuf16_aligned_long(dst, src); | ||
124 | return; | ||
125 | } | ||
126 | xorbuf_3(dst, dst, src, 16); | ||
127 | } | ||
128 | #endif | ||
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 5b4b7f113..aefb84f45 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) |
@@ -25,4 +26,78 @@ char* FAST_FUNC concat_path_file(const char *path, const char *filename) | |||
25 | while (*filename == '/') | 26 | while (*filename == '/') |
26 | filename++; | 27 | filename++; |
27 | return xasprintf("%s%s%s", path, (lc==NULL ? "/" : ""), filename); | 28 | return xasprintf("%s%s%s", path, (lc==NULL ? "/" : ""), filename); |
29 | #else | ||
30 | /* ^^^^^^^^^^^ timing of xasprintf-based code above: | ||
31 | * real 7.074s | ||
32 | * user 0.156s <<< | ||
33 | * sys 6.394s | ||
34 | * "rm -rf" of a Linux kernel tree from tmpfs (run time still dominated by in-kernel work, though) | ||
35 | * real 6.989s | ||
36 | * user 0.055s <<< 3 times less CPU used | ||
37 | * sys 6.450s | ||
38 | * vvvvvvvvvvv timing of open-coded malloc+memcpy code below (+59 bytes): | ||
39 | */ | ||
40 | char *buf, *p; | ||
41 | size_t n1, n2, n3; | ||
42 | |||
43 | while (*filename == '/') | ||
44 | filename++; | ||
45 | |||
46 | if (!path || !path[0]) | ||
47 | return xstrdup(filename); | ||
48 | |||
49 | n1 = strlen(path); | ||
50 | n2 = (path[n1 - 1] != '/'); /* 1: "path has no trailing slash" */ | ||
51 | n3 = strlen(filename) + 1; | ||
52 | |||
53 | buf = xmalloc(n1 + n2 + n3); | ||
54 | p = mempcpy(buf, path, n1); | ||
55 | if (n2) | ||
56 | *p++ = '/'; | ||
57 | memcpy(p, filename, n3); | ||
58 | return buf; | ||
59 | #endif | ||
60 | } | ||
61 | |||
62 | /* If second component comes from struct dirent, | ||
63 | * it's possible to eliminate one strlen() by using name length | ||
64 | * provided by kernel in struct dirent. See below. | ||
65 | * However, the win seems to be insignificant. | ||
66 | */ | ||
67 | |||
68 | #if 0 | ||
69 | |||
70 | /* Extract d_namlen from struct dirent */ | ||
71 | static size_t get_d_namlen(const struct dirent *de) | ||
72 | { | ||
73 | #if defined(_DIRENT_HAVE_D_NAMLEN) | ||
74 | return de->d_namlen; | ||
75 | #elif defined(_DIRENT_HAVE_D_RECLEN) | ||
76 | const size_t prefix_sz = offsetof(struct dirent, d_name); | ||
77 | return de->d_reclen - prefix_sz; | ||
78 | #else | ||
79 | return strlen(de->d_name); | ||
80 | #endif | ||
81 | } | ||
82 | |||
83 | char* FAST_FUNC concat_path_dirent(const char *path, const struct dirent *de) | ||
84 | { | ||
85 | char *buf, *p; | ||
86 | size_t n1, n2, n3; | ||
87 | |||
88 | if (!path || !path[0]) | ||
89 | return xstrdup(de->d_name); | ||
90 | |||
91 | n1 = strlen(path); | ||
92 | n2 = (path[n1 - 1] != '/'); | ||
93 | n3 = get_d_namlen(de) + 1; | ||
94 | |||
95 | buf = xmalloc(n1 + n2 + n3); | ||
96 | p = mempcpy(buf, path, n1); | ||
97 | if (n2) | ||
98 | *p++ = '/'; | ||
99 | memcpy(p, de->d_name, n3); | ||
100 | return buf; | ||
28 | } | 101 | } |
102 | |||
103 | #endif | ||
diff --git a/libbb/const_hack.c b/libbb/const_hack.c index 9575e6d67..1d175481b 100644 --- a/libbb/const_hack.c +++ b/libbb/const_hack.c | |||
@@ -9,8 +9,27 @@ | |||
9 | #include "libbb.h" | 9 | #include "libbb.h" |
10 | 10 | ||
11 | #if defined(__clang_major__) && __clang_major__ >= 9 | 11 | #if defined(__clang_major__) && __clang_major__ >= 9 |
12 | /* Clang/llvm drops assignment to "constant" storage. Silently. | ||
13 | * Needs serious convincing to not eliminate the store. | ||
14 | */ | ||
15 | static ALWAYS_INLINE void* not_const_pp(const void *p) | ||
16 | { | ||
17 | void *pp; | ||
18 | asm volatile ( | ||
19 | "# forget that p points to const" | ||
20 | : /*outputs*/ "=r" (pp) | ||
21 | : /*inputs*/ "0" (p) | ||
22 | ); | ||
23 | return pp; | ||
24 | } | ||
25 | void FAST_FUNC ASSIGN_CONST_PTR(const void *pptr, void *v) | ||
26 | { | ||
27 | *(void**)not_const_pp(pptr) = v; | ||
28 | barrier(); | ||
29 | } | ||
12 | void FAST_FUNC XZALLOC_CONST_PTR(const void *pptr, size_t size) | 30 | void FAST_FUNC XZALLOC_CONST_PTR(const void *pptr, size_t size) |
13 | { | 31 | { |
14 | ASSIGN_CONST_PTR(pptr, xzalloc(size)); | 32 | *(void**)not_const_pp(pptr) = xzalloc(size); |
33 | barrier(); | ||
15 | } | 34 | } |
16 | #endif | 35 | #endif |
diff --git a/libbb/dump.c b/libbb/dump.c index 2ca9919da..d34094576 100644 --- a/libbb/dump.c +++ b/libbb/dump.c | |||
@@ -478,37 +478,52 @@ static void bpad(PR *pr) | |||
478 | continue; | 478 | continue; |
479 | } | 479 | } |
480 | 480 | ||
481 | static const char conv_str[] ALIGN1 = | ||
482 | "\0" "\\""0""\0" | ||
483 | "\007""\\""a""\0" | ||
484 | "\b" "\\""b""\0" | ||
485 | "\f" "\\""f""\0" | ||
486 | "\n" "\\""n""\0" | ||
487 | "\r" "\\""r""\0" | ||
488 | "\t" "\\""t""\0" | ||
489 | "\v" "\\""v""\0" | ||
490 | ; | ||
491 | |||
492 | static void conv_c(PR *pr, unsigned char *p) | 481 | static void conv_c(PR *pr, unsigned char *p) |
493 | { | 482 | { |
494 | const char *str = conv_str; | 483 | const char *str; |
495 | 484 | unsigned char ch; | |
496 | do { | 485 | |
497 | if (*p == *str) { | 486 | ch = *p; |
498 | ++str; | 487 | if (ch == 0 || (ch -= 6, (signed char)ch > 0 && ch <= 7)) { |
499 | goto strpr; /* map e.g. '\n' to "\\n" */ | 488 | /* map chars 0,7..13 to "\0","\{a,b,t,n,v,f,r}" */ |
500 | } | 489 | str = c_escape_conv_str00 + 3 * ch; |
501 | str += 4; | 490 | goto strpr; |
502 | } while (*str); | 491 | } |
503 | 492 | ||
504 | if (isprint_asciionly(*p)) { | 493 | if (isprint_asciionly(*p)) { |
505 | *pr->cchar = 'c'; | 494 | *pr->cchar = 'c'; |
506 | printf(pr->fmt, *p); | 495 | printf(pr->fmt, *p); |
507 | } else { | 496 | } else { |
497 | #if defined(__i386__) || defined(__x86_64__) | ||
498 | /* Abuse partial register operations */ | ||
499 | uint32_t buf; | ||
500 | unsigned n = *p; | ||
501 | asm ( //00000000 00000000 00000000 aabbbccc | ||
502 | "\n shll $10,%%eax" //00000000 000000aa bbbccc00 00000000 | ||
503 | "\n shrw $5,%%ax" //00000000 000000aa 00000bbb ccc00000 | ||
504 | "\n shrb $5,%%al" //00000000 000000aa 00000bbb 00000ccc | ||
505 | "\n shll $8,%%eax" //000000aa 00000bbb 00000ccc 00000000 | ||
506 | "\n bswapl %%eax" //00000000 00000ccc 00000bbb 000000aa | ||
507 | "\n addl $0x303030,%%eax" | ||
508 | "\n" : "=a" (n) | ||
509 | : "0" (n) | ||
510 | ); | ||
511 | buf = n; | ||
512 | str = (void*)&buf; | ||
513 | #elif 1 | ||
508 | char buf[4]; | 514 | char buf[4]; |
509 | /* gcc-8.0.1 needs lots of casts to shut up */ | 515 | /* gcc-8.0.1 needs lots of casts to shut up */ |
510 | sprintf(buf, "%03o", (unsigned)(uint8_t)*p); | 516 | sprintf(buf, "%03o", (unsigned)(uint8_t)*p); |
511 | str = buf; | 517 | str = buf; |
518 | #else // use faster version? +20 bytes of code relative to sprintf() method | ||
519 | char buf[4]; | ||
520 | buf[3] = '\0'; | ||
521 | ch = *p; | ||
522 | buf[2] = '0' + (ch & 7); ch >>= 3; | ||
523 | buf[1] = '0' + (ch & 7); ch >>= 3; | ||
524 | buf[0] = '0' + ch; | ||
525 | str = buf; | ||
526 | #endif | ||
512 | strpr: | 527 | strpr: |
513 | *pr->cchar = 's'; | 528 | *pr->cchar = 's'; |
514 | printf(pr->fmt, str); | 529 | printf(pr->fmt, str); |
@@ -667,15 +682,21 @@ static NOINLINE void display(priv_dumper_t* dumper) | |||
667 | conv_u(pr, bp); | 682 | conv_u(pr, bp); |
668 | break; | 683 | break; |
669 | case F_UINT: { | 684 | case F_UINT: { |
685 | union { | ||
686 | uint16_t uval16; | ||
687 | uint32_t uval32; | ||
688 | } u; | ||
670 | unsigned value = (unsigned char)*bp; | 689 | unsigned value = (unsigned char)*bp; |
671 | switch (pr->bcnt) { | 690 | switch (pr->bcnt) { |
672 | case 1: | 691 | case 1: |
673 | break; | 692 | break; |
674 | case 2: | 693 | case 2: |
675 | move_from_unaligned16(value, bp); | 694 | move_from_unaligned16(u.uval16, bp); |
695 | value = u.uval16; | ||
676 | break; | 696 | break; |
677 | case 4: | 697 | case 4: |
678 | move_from_unaligned32(value, bp); | 698 | move_from_unaligned32(u.uval32, bp); |
699 | value = u.uval32; | ||
679 | break; | 700 | break; |
680 | /* case 8: no users yet */ | 701 | /* case 8: no users yet */ |
681 | } | 702 | } |
diff --git a/libbb/getopt32.c b/libbb/getopt32.c index b5efa19ac..4c05dcb97 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_hmac.c b/libbb/hash_hmac.c new file mode 100644 index 000000000..9e48e0f51 --- /dev/null +++ b/libbb/hash_hmac.c | |||
@@ -0,0 +1,107 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2025 Denys Vlasenko | ||
3 | * | ||
4 | * Licensed under GPLv2, see file LICENSE in this source tree. | ||
5 | */ | ||
6 | //kbuild:lib-$(CONFIG_TLS) += hash_hmac.o | ||
7 | //kbuild:lib-$(CONFIG_USE_BB_CRYPT_YES) += hash_hmac.o | ||
8 | |||
9 | #include "libbb.h" | ||
10 | |||
11 | // RFC 2104: | ||
12 | // HMAC(key, text) based on a hash H (say, sha256) is: | ||
13 | // ipad = [0x36 x INSIZE] | ||
14 | // opad = [0x5c x INSIZE] | ||
15 | // HMAC(key, text) = H((key XOR opad) + H((key XOR ipad) + text)) | ||
16 | // | ||
17 | // H(key XOR opad) and H(key XOR ipad) can be precomputed | ||
18 | // if we often need HMAC hmac with the same key. | ||
19 | // | ||
20 | // text is often given in disjoint pieces. | ||
21 | void FAST_FUNC hmac_begin(hmac_ctx_t *ctx, const uint8_t *key, unsigned key_size, md5sha_begin_func *begin) | ||
22 | { | ||
23 | #if HMAC_ONLY_SHA256 | ||
24 | #define begin sha256_begin | ||
25 | #endif | ||
26 | uint8_t key_xor_ipad[SHA2_INSIZE]; | ||
27 | uint8_t key_xor_opad[SHA2_INSIZE]; | ||
28 | unsigned i; | ||
29 | |||
30 | // "The authentication key can be of any length up to INSIZE, the | ||
31 | // block length of the hash function. Applications that use keys longer | ||
32 | // than INSIZE bytes will first hash the key using H and then use the | ||
33 | // resultant OUTSIZE byte string as the actual key to HMAC." | ||
34 | if (key_size > SHA2_INSIZE) { | ||
35 | uint8_t tempkey[SHA1_OUTSIZE < SHA256_OUTSIZE ? SHA256_OUTSIZE : SHA1_OUTSIZE]; | ||
36 | /* use ctx->hashed_key_xor_ipad as scratch ctx */ | ||
37 | begin(&ctx->hashed_key_xor_ipad); | ||
38 | md5sha_hash(&ctx->hashed_key_xor_ipad, key, key_size); | ||
39 | key_size = sha_end(&ctx->hashed_key_xor_ipad, tempkey); | ||
40 | key = tempkey; | ||
41 | } | ||
42 | |||
43 | for (i = 0; i < key_size; i++) { | ||
44 | key_xor_ipad[i] = key[i] ^ 0x36; | ||
45 | key_xor_opad[i] = key[i] ^ 0x5c; | ||
46 | } | ||
47 | for (; i < SHA2_INSIZE; i++) { | ||
48 | key_xor_ipad[i] = 0x36; | ||
49 | key_xor_opad[i] = 0x5c; | ||
50 | } | ||
51 | |||
52 | begin(&ctx->hashed_key_xor_ipad); | ||
53 | begin(&ctx->hashed_key_xor_opad); | ||
54 | md5sha_hash(&ctx->hashed_key_xor_ipad, key_xor_ipad, SHA2_INSIZE); | ||
55 | md5sha_hash(&ctx->hashed_key_xor_opad, key_xor_opad, SHA2_INSIZE); | ||
56 | } | ||
57 | #undef begin | ||
58 | |||
59 | unsigned FAST_FUNC hmac_end(hmac_ctx_t *ctx, uint8_t *out) | ||
60 | { | ||
61 | unsigned len = sha_end(&ctx->hashed_key_xor_ipad, out); | ||
62 | /* out = H((key XOR opad) + out) */ | ||
63 | md5sha_hash(&ctx->hashed_key_xor_opad, out, len); | ||
64 | return sha_end(&ctx->hashed_key_xor_opad, out); | ||
65 | } | ||
66 | |||
67 | unsigned FAST_FUNC hmac_block(const uint8_t *key, unsigned key_size, md5sha_begin_func *begin, const void *in, unsigned sz, uint8_t *out) | ||
68 | { | ||
69 | hmac_ctx_t ctx; | ||
70 | hmac_begin(&ctx, key, key_size, begin); | ||
71 | hmac_hash(&ctx, in, sz); | ||
72 | return hmac_end(&ctx, out); | ||
73 | } | ||
74 | |||
75 | /* TLS helpers */ | ||
76 | |||
77 | void FAST_FUNC hmac_hash_v( | ||
78 | hmac_ctx_t *ctx, | ||
79 | va_list va) | ||
80 | { | ||
81 | uint8_t *in; | ||
82 | |||
83 | /* ctx->hashed_key_xor_ipad contains unclosed "H((key XOR ipad) +" state */ | ||
84 | /* ctx->hashed_key_xor_opad contains unclosed "H((key XOR opad) +" state */ | ||
85 | |||
86 | /* calculate out = H((key XOR ipad) + text) */ | ||
87 | while ((in = va_arg(va, uint8_t*)) != NULL) { | ||
88 | unsigned size = va_arg(va, unsigned); | ||
89 | md5sha_hash(&ctx->hashed_key_xor_ipad, in, size); | ||
90 | } | ||
91 | } | ||
92 | |||
93 | /* Using HMAC state, make a copy of it (IOW: without affecting this state!) | ||
94 | * hash in the list of (ptr,size) blocks, and finish the HMAC to out[] buffer. | ||
95 | * This function is useful for TLS PRF. | ||
96 | */ | ||
97 | unsigned FAST_FUNC hmac_peek_hash(hmac_ctx_t *ctx, uint8_t *out, ...) | ||
98 | { | ||
99 | hmac_ctx_t tmpctx = *ctx; /* struct copy */ | ||
100 | va_list va; | ||
101 | |||
102 | va_start(va, out); | ||
103 | hmac_hash_v(&tmpctx, va); | ||
104 | va_end(va); | ||
105 | |||
106 | return hmac_end(&tmpctx, out); | ||
107 | } | ||
diff --git a/libbb/hash_md5_sha.c b/libbb/hash_md5_sha.c index 75a61c32c..9ebda232a 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_SHA1_HWACCEL || ENABLE_SHA256_HWACCEL | 16 | #if ENABLE_SHA1_HWACCEL || ENABLE_SHA256_HWACCEL |
17 | # if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) | 17 | # if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) |
@@ -1032,7 +1032,7 @@ static const sha_K_int sha_K[] ALIGN8 = { | |||
1032 | K(0x84c87814a1f0ab72ULL), K(0x8cc702081a6439ecULL), | 1032 | K(0x84c87814a1f0ab72ULL), K(0x8cc702081a6439ecULL), |
1033 | K(0x90befffa23631e28ULL), K(0xa4506cebde82bde9ULL), | 1033 | K(0x90befffa23631e28ULL), K(0xa4506cebde82bde9ULL), |
1034 | K(0xbef9a3f7b2c67915ULL), K(0xc67178f2e372532bULL), | 1034 | K(0xbef9a3f7b2c67915ULL), K(0xc67178f2e372532bULL), |
1035 | #if NEED_SHA512 /* [64]+ are used for sha512 only */ | 1035 | #if NEED_SHA512 /* [64]+ are used for sha384 and sha512 only */ |
1036 | K(0xca273eceea26619cULL), K(0xd186b8c721c0c207ULL), | 1036 | K(0xca273eceea26619cULL), K(0xd186b8c721c0c207ULL), |
1037 | K(0xeada7dd6cde0eb1eULL), K(0xf57d4f7fee6ed178ULL), | 1037 | K(0xeada7dd6cde0eb1eULL), K(0xf57d4f7fee6ed178ULL), |
1038 | K(0x06f067aa72176fbaULL), K(0x0a637dc5a2c898a6ULL), | 1038 | K(0x06f067aa72176fbaULL), K(0x0a637dc5a2c898a6ULL), |
@@ -1229,11 +1229,20 @@ static const uint32_t init512_lo[] ALIGN4 = { | |||
1229 | 0x137e2179, | 1229 | 0x137e2179, |
1230 | }; | 1230 | }; |
1231 | #endif /* NEED_SHA512 */ | 1231 | #endif /* NEED_SHA512 */ |
1232 | 1232 | #if ENABLE_SHA384SUM | |
1233 | // Note: SHA-384 is identical to SHA-512, except that initial hash values are | 1233 | static const uint64_t init384[] ALIGN8 = { |
1234 | // 0xcbbb9d5dc1059ed8, 0x629a292a367cd507, 0x9159015a3070dd17, 0x152fecd8f70e5939, | 1234 | 0, |
1235 | // 0x67332667ffc00b31, 0x8eb44a8768581511, 0xdb0c2e0d64f98fa7, 0x47b5481dbefa4fa4, | 1235 | 0, |
1236 | // and the output is constructed by omitting last two 64-bit words of it. | 1236 | 0xcbbb9d5dc1059ed8, |
1237 | 0x629a292a367cd507, | ||
1238 | 0x9159015a3070dd17, | ||
1239 | 0x152fecd8f70e5939, | ||
1240 | 0x67332667ffc00b31, | ||
1241 | 0x8eb44a8768581511, | ||
1242 | 0xdb0c2e0d64f98fa7, | ||
1243 | 0x47b5481dbefa4fa4, | ||
1244 | }; | ||
1245 | #endif | ||
1237 | 1246 | ||
1238 | /* Initialize structure containing state of computation. | 1247 | /* Initialize structure containing state of computation. |
1239 | (FIPS 180-2:5.3.2) */ | 1248 | (FIPS 180-2:5.3.2) */ |
@@ -1255,9 +1264,19 @@ void FAST_FUNC sha256_begin(sha256_ctx_t *ctx) | |||
1255 | #endif | 1264 | #endif |
1256 | } | 1265 | } |
1257 | 1266 | ||
1258 | #if NEED_SHA512 | 1267 | #if ENABLE_SHA384SUM |
1259 | /* Initialize structure containing state of computation. | 1268 | /* Initialize structure containing state of computation. |
1260 | (FIPS 180-2:5.3.3) */ | 1269 | (FIPS 180-2:5.3.3) */ |
1270 | void FAST_FUNC sha384_begin(sha512_ctx_t *ctx) | ||
1271 | { | ||
1272 | memcpy(&ctx->total64, init384, sizeof(init384)); | ||
1273 | /*ctx->total64[0] = ctx->total64[1] = 0; - already done */ | ||
1274 | } | ||
1275 | #endif | ||
1276 | |||
1277 | #if NEED_SHA512 | ||
1278 | /* Initialize structure containing state of computation. | ||
1279 | (FIPS 180-2:5.3.4) */ | ||
1261 | void FAST_FUNC sha512_begin(sha512_ctx_t *ctx) | 1280 | void FAST_FUNC sha512_begin(sha512_ctx_t *ctx) |
1262 | { | 1281 | { |
1263 | int i; | 1282 | int i; |
@@ -1332,7 +1351,7 @@ unsigned FAST_FUNC sha1_end(sha1_ctx_t *ctx, void *resbuf) | |||
1332 | } | 1351 | } |
1333 | 1352 | ||
1334 | #if NEED_SHA512 | 1353 | #if NEED_SHA512 |
1335 | unsigned FAST_FUNC sha512_end(sha512_ctx_t *ctx, void *resbuf) | 1354 | static unsigned FAST_FUNC sha512384_end(sha512_ctx_t *ctx, void *resbuf, unsigned outsize) |
1336 | { | 1355 | { |
1337 | unsigned bufpos = ctx->total64[0] & 127; | 1356 | unsigned bufpos = ctx->total64[0] & 127; |
1338 | 1357 | ||
@@ -1363,11 +1382,21 @@ unsigned FAST_FUNC sha512_end(sha512_ctx_t *ctx, void *resbuf) | |||
1363 | for (i = 0; i < ARRAY_SIZE(ctx->hash); ++i) | 1382 | for (i = 0; i < ARRAY_SIZE(ctx->hash); ++i) |
1364 | ctx->hash[i] = SWAP_BE64(ctx->hash[i]); | 1383 | ctx->hash[i] = SWAP_BE64(ctx->hash[i]); |
1365 | } | 1384 | } |
1366 | memcpy(resbuf, ctx->hash, sizeof(ctx->hash)); | 1385 | memcpy(resbuf, ctx->hash, outsize); |
1367 | return sizeof(ctx->hash); | 1386 | return outsize; |
1387 | } | ||
1388 | unsigned FAST_FUNC sha512_end(sha384_ctx_t *ctx, void *resbuf) | ||
1389 | { | ||
1390 | return sha512384_end(ctx, resbuf, SHA512_OUTSIZE); | ||
1368 | } | 1391 | } |
1369 | #endif /* NEED_SHA512 */ | 1392 | #endif /* NEED_SHA512 */ |
1370 | 1393 | ||
1394 | #if ENABLE_SHA384SUM | ||
1395 | unsigned FAST_FUNC sha384_end(sha384_ctx_t *ctx, void *resbuf) | ||
1396 | { | ||
1397 | return sha512384_end(ctx, resbuf, SHA384_OUTSIZE); | ||
1398 | } | ||
1399 | #endif | ||
1371 | 1400 | ||
1372 | /* | 1401 | /* |
1373 | * The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, | 1402 | * The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, |
@@ -1904,6 +1933,8 @@ void FAST_FUNC sha3_hash(sha3_ctx_t *ctx, const void *buffer, size_t len) | |||
1904 | 1933 | ||
1905 | unsigned FAST_FUNC sha3_end(sha3_ctx_t *ctx, void *resbuf) | 1934 | unsigned FAST_FUNC sha3_end(sha3_ctx_t *ctx, void *resbuf) |
1906 | { | 1935 | { |
1936 | unsigned hash_len; | ||
1937 | |||
1907 | /* Padding */ | 1938 | /* Padding */ |
1908 | uint8_t *buf = (uint8_t*)ctx->state; | 1939 | uint8_t *buf = (uint8_t*)ctx->state; |
1909 | /* | 1940 | /* |
@@ -1926,6 +1957,7 @@ unsigned FAST_FUNC sha3_end(sha3_ctx_t *ctx, void *resbuf) | |||
1926 | sha3_process_block72(ctx->state); | 1957 | sha3_process_block72(ctx->state); |
1927 | 1958 | ||
1928 | /* Output */ | 1959 | /* Output */ |
1929 | memcpy(resbuf, ctx->state, 64); | 1960 | hash_len = (1600/8 - ctx->input_block_bytes) / 2; |
1930 | return 64; | 1961 | memcpy(resbuf, ctx->state, hash_len); |
1962 | return hash_len; | ||
1931 | } | 1963 | } |
diff --git a/libbb/hash_sha256_block.c b/libbb/hash_sha256_block.c new file mode 100644 index 000000000..3c4366321 --- /dev/null +++ b/libbb/hash_sha256_block.c | |||
@@ -0,0 +1,19 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Utility routines. | ||
4 | * | ||
5 | * Copyright (C) 2025 Denys Vlasenko | ||
6 | * | ||
7 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. | ||
8 | */ | ||
9 | //kbuild:lib-y += hash_sha256_block.o | ||
10 | #include "libbb.h" | ||
11 | |||
12 | void FAST_FUNC | ||
13 | sha256_block(const void *in, size_t len, uint8_t hash[32]) | ||
14 | { | ||
15 | sha256_ctx_t ctx; | ||
16 | sha256_begin(&ctx); | ||
17 | sha256_hash(&ctx, in, len); | ||
18 | sha256_end(&ctx, hash); | ||
19 | } | ||
diff --git a/libbb/hash_sha256_hwaccel_x86-32.S b/libbb/hash_sha256_hwaccel_x86-32.S index a0e4a571a..8d84055e8 100644 --- a/libbb/hash_sha256_hwaccel_x86-32.S +++ b/libbb/hash_sha256_hwaccel_x86-32.S | |||
@@ -34,21 +34,21 @@ | |||
34 | #define MSG %xmm0 | 34 | #define MSG %xmm0 |
35 | #define STATE0 %xmm1 | 35 | #define STATE0 %xmm1 |
36 | #define STATE1 %xmm2 | 36 | #define STATE1 %xmm2 |
37 | #define MSGTMP0 %xmm3 | 37 | #define MSG0 %xmm3 |
38 | #define MSGTMP1 %xmm4 | 38 | #define MSG1 %xmm4 |
39 | #define MSGTMP2 %xmm5 | 39 | #define MSG2 %xmm5 |
40 | #define MSGTMP3 %xmm6 | 40 | #define MSG3 %xmm6 |
41 | 41 | ||
42 | #define XMMTMP %xmm7 | 42 | #define XMMTMP %xmm7 |
43 | 43 | ||
44 | #define SHUF(a,b,c,d) $(a+(b<<2)+(c<<4)+(d<<6)) | 44 | #define SHUF(a,b,c,d) $((a)+((b)<<2)+((c)<<4)+((d)<<6)) |
45 | 45 | ||
46 | .balign 8 # allow decoders to fetch at least 2 first insns | 46 | .balign 8 # allow decoders to fetch at least 2 first insns |
47 | sha256_process_block64_shaNI: | 47 | sha256_process_block64_shaNI: |
48 | 48 | ||
49 | movu128 76+0*16(%eax), XMMTMP /* ABCD (little-endian dword order) */ | 49 | movu128 76+0*16(%eax), XMMTMP /* ABCD (shown least-significant-dword-first) */ |
50 | movu128 76+1*16(%eax), STATE1 /* EFGH */ | 50 | movu128 76+1*16(%eax), STATE1 /* EFGH */ |
51 | /* shufps takes dwords 0,1 from *2nd* operand, and dwords 2,3 from 1st one */ | 51 | /* shufps: dwords 0,1 of the result are selected from *2nd* operand, and dwords 2,3 from 1st operand */ |
52 | mova128 STATE1, STATE0 | 52 | mova128 STATE1, STATE0 |
53 | /* --- -------------- ABCD -- EFGH */ | 53 | /* --- -------------- ABCD -- EFGH */ |
54 | shufps SHUF(1,0,1,0), XMMTMP, STATE0 /* FEBA */ | 54 | shufps SHUF(1,0,1,0), XMMTMP, STATE0 /* FEBA */ |
@@ -58,190 +58,208 @@ sha256_process_block64_shaNI: | |||
58 | mova128 PSHUFFLE_BSWAP32_FLIP_MASK, XMMTMP | 58 | mova128 PSHUFFLE_BSWAP32_FLIP_MASK, XMMTMP |
59 | movl $K256+8*16, SHA256CONSTANTS | 59 | movl $K256+8*16, SHA256CONSTANTS |
60 | 60 | ||
61 | // sha256rnds2 instruction uses only lower 64 bits of MSG. | ||
62 | // The code below needs to move upper 64 bits to lower 64 bits | ||
63 | // for the second sha256rnds2 invocation | ||
64 | // (what remains in upper bits does not matter). | ||
65 | // There are several ways to do it: | ||
66 | // movhlps MSG, MSG // abcd -> cdcd (3 bytes of code) | ||
67 | // shuf128_32 SHUF(2,3,n,n), MSG, MSG // abcd -> cdXX (4 bytes) | ||
68 | // punpckhqdq MSG, MSG // abcd -> cdcd (4 bytes) | ||
69 | // unpckhpd MSG, MSG // abcd -> cdcd (4 bytes) | ||
70 | // psrldq $8, MSG // abcd -> cd00 (5 bytes) | ||
71 | // palignr $8, MSG, MSG // abcd -> cdab (6 bytes, SSSE3 insn) | ||
72 | #define MOVE_UPPER64_DOWN(reg) movhlps reg, reg | ||
73 | //#define MOVE_UPPER64_DOWN(reg) shuf128_32 SHUF(2,3,0,0), reg, reg | ||
74 | //#define MOVE_UPPER64_DOWN(reg) punpckhqdq reg, reg | ||
75 | //#define MOVE_UPPER64_DOWN(reg) unpckhpd reg, reg | ||
76 | //#define MOVE_UPPER64_DOWN(reg) psrldq $8, reg | ||
77 | //#define MOVE_UPPER64_DOWN(reg) palignr $8, reg, reg | ||
78 | |||
61 | /* Rounds 0-3 */ | 79 | /* Rounds 0-3 */ |
62 | movu128 0*16(DATA_PTR), MSG | 80 | movu128 0*16(DATA_PTR), MSG |
63 | pshufb XMMTMP, MSG | 81 | pshufb XMMTMP, MSG |
64 | mova128 MSG, MSGTMP0 | 82 | mova128 MSG, MSG0 |
65 | paddd 0*16-8*16(SHA256CONSTANTS), MSG | 83 | paddd 0*16-8*16(SHA256CONSTANTS), MSG |
66 | sha256rnds2 MSG, STATE0, STATE1 | 84 | sha256rnds2 MSG, STATE0, STATE1 |
67 | shuf128_32 $0x0E, MSG, MSG | 85 | MOVE_UPPER64_DOWN(MSG) |
68 | sha256rnds2 MSG, STATE1, STATE0 | 86 | sha256rnds2 MSG, STATE1, STATE0 |
69 | 87 | ||
70 | /* Rounds 4-7 */ | 88 | /* Rounds 4-7 */ |
71 | movu128 1*16(DATA_PTR), MSG | 89 | movu128 1*16(DATA_PTR), MSG |
72 | pshufb XMMTMP, MSG | 90 | pshufb XMMTMP, MSG |
73 | mova128 MSG, MSGTMP1 | 91 | mova128 MSG, MSG1 |
74 | paddd 1*16-8*16(SHA256CONSTANTS), MSG | 92 | paddd 1*16-8*16(SHA256CONSTANTS), MSG |
75 | sha256rnds2 MSG, STATE0, STATE1 | 93 | sha256rnds2 MSG, STATE0, STATE1 |
76 | shuf128_32 $0x0E, MSG, MSG | 94 | MOVE_UPPER64_DOWN(MSG) |
77 | sha256rnds2 MSG, STATE1, STATE0 | 95 | sha256rnds2 MSG, STATE1, STATE0 |
78 | sha256msg1 MSGTMP1, MSGTMP0 | 96 | sha256msg1 MSG1, MSG0 |
79 | 97 | ||
80 | /* Rounds 8-11 */ | 98 | /* Rounds 8-11 */ |
81 | movu128 2*16(DATA_PTR), MSG | 99 | movu128 2*16(DATA_PTR), MSG |
82 | pshufb XMMTMP, MSG | 100 | pshufb XMMTMP, MSG |
83 | mova128 MSG, MSGTMP2 | 101 | mova128 MSG, MSG2 |
84 | paddd 2*16-8*16(SHA256CONSTANTS), MSG | 102 | paddd 2*16-8*16(SHA256CONSTANTS), MSG |
85 | sha256rnds2 MSG, STATE0, STATE1 | 103 | sha256rnds2 MSG, STATE0, STATE1 |
86 | shuf128_32 $0x0E, MSG, MSG | 104 | MOVE_UPPER64_DOWN(MSG) |
87 | sha256rnds2 MSG, STATE1, STATE0 | 105 | sha256rnds2 MSG, STATE1, STATE0 |
88 | sha256msg1 MSGTMP2, MSGTMP1 | 106 | sha256msg1 MSG2, MSG1 |
89 | 107 | ||
90 | /* Rounds 12-15 */ | 108 | /* Rounds 12-15 */ |
91 | movu128 3*16(DATA_PTR), MSG | 109 | movu128 3*16(DATA_PTR), MSG |
92 | pshufb XMMTMP, MSG | 110 | pshufb XMMTMP, MSG |
93 | /* ...to here */ | 111 | /* ...to here */ |
94 | mova128 MSG, MSGTMP3 | 112 | mova128 MSG, MSG3 |
95 | paddd 3*16-8*16(SHA256CONSTANTS), MSG | 113 | paddd 3*16-8*16(SHA256CONSTANTS), MSG |
96 | sha256rnds2 MSG, STATE0, STATE1 | 114 | sha256rnds2 MSG, STATE0, STATE1 |
97 | mova128 MSGTMP3, XMMTMP | 115 | mova128 MSG3, XMMTMP |
98 | palignr $4, MSGTMP2, XMMTMP | 116 | palignr $4, MSG2, XMMTMP |
99 | paddd XMMTMP, MSGTMP0 | 117 | paddd XMMTMP, MSG0 |
100 | sha256msg2 MSGTMP3, MSGTMP0 | 118 | sha256msg2 MSG3, MSG0 |
101 | shuf128_32 $0x0E, MSG, MSG | 119 | MOVE_UPPER64_DOWN(MSG) |
102 | sha256rnds2 MSG, STATE1, STATE0 | 120 | sha256rnds2 MSG, STATE1, STATE0 |
103 | sha256msg1 MSGTMP3, MSGTMP2 | 121 | sha256msg1 MSG3, MSG2 |
104 | 122 | ||
105 | /* Rounds 16-19 */ | 123 | /* Rounds 16-19 */ |
106 | mova128 MSGTMP0, MSG | 124 | mova128 MSG0, MSG |
107 | paddd 4*16-8*16(SHA256CONSTANTS), MSG | 125 | paddd 4*16-8*16(SHA256CONSTANTS), MSG |
108 | sha256rnds2 MSG, STATE0, STATE1 | 126 | sha256rnds2 MSG, STATE0, STATE1 |
109 | mova128 MSGTMP0, XMMTMP | 127 | mova128 MSG0, XMMTMP |
110 | palignr $4, MSGTMP3, XMMTMP | 128 | palignr $4, MSG3, XMMTMP |
111 | paddd XMMTMP, MSGTMP1 | 129 | paddd XMMTMP, MSG1 |
112 | sha256msg2 MSGTMP0, MSGTMP1 | 130 | sha256msg2 MSG0, MSG1 |
113 | shuf128_32 $0x0E, MSG, MSG | 131 | MOVE_UPPER64_DOWN(MSG) |
114 | sha256rnds2 MSG, STATE1, STATE0 | 132 | sha256rnds2 MSG, STATE1, STATE0 |
115 | sha256msg1 MSGTMP0, MSGTMP3 | 133 | sha256msg1 MSG0, MSG3 |
116 | 134 | ||
117 | /* Rounds 20-23 */ | 135 | /* Rounds 20-23 */ |
118 | mova128 MSGTMP1, MSG | 136 | mova128 MSG1, MSG |
119 | paddd 5*16-8*16(SHA256CONSTANTS), MSG | 137 | paddd 5*16-8*16(SHA256CONSTANTS), MSG |
120 | sha256rnds2 MSG, STATE0, STATE1 | 138 | sha256rnds2 MSG, STATE0, STATE1 |
121 | mova128 MSGTMP1, XMMTMP | 139 | mova128 MSG1, XMMTMP |
122 | palignr $4, MSGTMP0, XMMTMP | 140 | palignr $4, MSG0, XMMTMP |
123 | paddd XMMTMP, MSGTMP2 | 141 | paddd XMMTMP, MSG2 |
124 | sha256msg2 MSGTMP1, MSGTMP2 | 142 | sha256msg2 MSG1, MSG2 |
125 | shuf128_32 $0x0E, MSG, MSG | 143 | MOVE_UPPER64_DOWN(MSG) |
126 | sha256rnds2 MSG, STATE1, STATE0 | 144 | sha256rnds2 MSG, STATE1, STATE0 |
127 | sha256msg1 MSGTMP1, MSGTMP0 | 145 | sha256msg1 MSG1, MSG0 |
128 | 146 | ||
129 | /* Rounds 24-27 */ | 147 | /* Rounds 24-27 */ |
130 | mova128 MSGTMP2, MSG | 148 | mova128 MSG2, MSG |
131 | paddd 6*16-8*16(SHA256CONSTANTS), MSG | 149 | paddd 6*16-8*16(SHA256CONSTANTS), MSG |
132 | sha256rnds2 MSG, STATE0, STATE1 | 150 | sha256rnds2 MSG, STATE0, STATE1 |
133 | mova128 MSGTMP2, XMMTMP | 151 | mova128 MSG2, XMMTMP |
134 | palignr $4, MSGTMP1, XMMTMP | 152 | palignr $4, MSG1, XMMTMP |
135 | paddd XMMTMP, MSGTMP3 | 153 | paddd XMMTMP, MSG3 |
136 | sha256msg2 MSGTMP2, MSGTMP3 | 154 | sha256msg2 MSG2, MSG3 |
137 | shuf128_32 $0x0E, MSG, MSG | 155 | MOVE_UPPER64_DOWN(MSG) |
138 | sha256rnds2 MSG, STATE1, STATE0 | 156 | sha256rnds2 MSG, STATE1, STATE0 |
139 | sha256msg1 MSGTMP2, MSGTMP1 | 157 | sha256msg1 MSG2, MSG1 |
140 | 158 | ||
141 | /* Rounds 28-31 */ | 159 | /* Rounds 28-31 */ |
142 | mova128 MSGTMP3, MSG | 160 | mova128 MSG3, MSG |
143 | paddd 7*16-8*16(SHA256CONSTANTS), MSG | 161 | paddd 7*16-8*16(SHA256CONSTANTS), MSG |
144 | sha256rnds2 MSG, STATE0, STATE1 | 162 | sha256rnds2 MSG, STATE0, STATE1 |
145 | mova128 MSGTMP3, XMMTMP | 163 | mova128 MSG3, XMMTMP |
146 | palignr $4, MSGTMP2, XMMTMP | 164 | palignr $4, MSG2, XMMTMP |
147 | paddd XMMTMP, MSGTMP0 | 165 | paddd XMMTMP, MSG0 |
148 | sha256msg2 MSGTMP3, MSGTMP0 | 166 | sha256msg2 MSG3, MSG0 |
149 | shuf128_32 $0x0E, MSG, MSG | 167 | MOVE_UPPER64_DOWN(MSG) |
150 | sha256rnds2 MSG, STATE1, STATE0 | 168 | sha256rnds2 MSG, STATE1, STATE0 |
151 | sha256msg1 MSGTMP3, MSGTMP2 | 169 | sha256msg1 MSG3, MSG2 |
152 | 170 | ||
153 | /* Rounds 32-35 */ | 171 | /* Rounds 32-35 */ |
154 | mova128 MSGTMP0, MSG | 172 | mova128 MSG0, MSG |
155 | paddd 8*16-8*16(SHA256CONSTANTS), MSG | 173 | paddd 8*16-8*16(SHA256CONSTANTS), MSG |
156 | sha256rnds2 MSG, STATE0, STATE1 | 174 | sha256rnds2 MSG, STATE0, STATE1 |
157 | mova128 MSGTMP0, XMMTMP | 175 | mova128 MSG0, XMMTMP |
158 | palignr $4, MSGTMP3, XMMTMP | 176 | palignr $4, MSG3, XMMTMP |
159 | paddd XMMTMP, MSGTMP1 | 177 | paddd XMMTMP, MSG1 |
160 | sha256msg2 MSGTMP0, MSGTMP1 | 178 | sha256msg2 MSG0, MSG1 |
161 | shuf128_32 $0x0E, MSG, MSG | 179 | MOVE_UPPER64_DOWN(MSG) |
162 | sha256rnds2 MSG, STATE1, STATE0 | 180 | sha256rnds2 MSG, STATE1, STATE0 |
163 | sha256msg1 MSGTMP0, MSGTMP3 | 181 | sha256msg1 MSG0, MSG3 |
164 | 182 | ||
165 | /* Rounds 36-39 */ | 183 | /* Rounds 36-39 */ |
166 | mova128 MSGTMP1, MSG | 184 | mova128 MSG1, MSG |
167 | paddd 9*16-8*16(SHA256CONSTANTS), MSG | 185 | paddd 9*16-8*16(SHA256CONSTANTS), MSG |
168 | sha256rnds2 MSG, STATE0, STATE1 | 186 | sha256rnds2 MSG, STATE0, STATE1 |
169 | mova128 MSGTMP1, XMMTMP | 187 | mova128 MSG1, XMMTMP |
170 | palignr $4, MSGTMP0, XMMTMP | 188 | palignr $4, MSG0, XMMTMP |
171 | paddd XMMTMP, MSGTMP2 | 189 | paddd XMMTMP, MSG2 |
172 | sha256msg2 MSGTMP1, MSGTMP2 | 190 | sha256msg2 MSG1, MSG2 |
173 | shuf128_32 $0x0E, MSG, MSG | 191 | MOVE_UPPER64_DOWN(MSG) |
174 | sha256rnds2 MSG, STATE1, STATE0 | 192 | sha256rnds2 MSG, STATE1, STATE0 |
175 | sha256msg1 MSGTMP1, MSGTMP0 | 193 | sha256msg1 MSG1, MSG0 |
176 | 194 | ||
177 | /* Rounds 40-43 */ | 195 | /* Rounds 40-43 */ |
178 | mova128 MSGTMP2, MSG | 196 | mova128 MSG2, MSG |
179 | paddd 10*16-8*16(SHA256CONSTANTS), MSG | 197 | paddd 10*16-8*16(SHA256CONSTANTS), MSG |
180 | sha256rnds2 MSG, STATE0, STATE1 | 198 | sha256rnds2 MSG, STATE0, STATE1 |
181 | mova128 MSGTMP2, XMMTMP | 199 | mova128 MSG2, XMMTMP |
182 | palignr $4, MSGTMP1, XMMTMP | 200 | palignr $4, MSG1, XMMTMP |
183 | paddd XMMTMP, MSGTMP3 | 201 | paddd XMMTMP, MSG3 |
184 | sha256msg2 MSGTMP2, MSGTMP3 | 202 | sha256msg2 MSG2, MSG3 |
185 | shuf128_32 $0x0E, MSG, MSG | 203 | MOVE_UPPER64_DOWN(MSG) |
186 | sha256rnds2 MSG, STATE1, STATE0 | 204 | sha256rnds2 MSG, STATE1, STATE0 |
187 | sha256msg1 MSGTMP2, MSGTMP1 | 205 | sha256msg1 MSG2, MSG1 |
188 | 206 | ||
189 | /* Rounds 44-47 */ | 207 | /* Rounds 44-47 */ |
190 | mova128 MSGTMP3, MSG | 208 | mova128 MSG3, MSG |
191 | paddd 11*16-8*16(SHA256CONSTANTS), MSG | 209 | paddd 11*16-8*16(SHA256CONSTANTS), MSG |
192 | sha256rnds2 MSG, STATE0, STATE1 | 210 | sha256rnds2 MSG, STATE0, STATE1 |
193 | mova128 MSGTMP3, XMMTMP | 211 | mova128 MSG3, XMMTMP |
194 | palignr $4, MSGTMP2, XMMTMP | 212 | palignr $4, MSG2, XMMTMP |
195 | paddd XMMTMP, MSGTMP0 | 213 | paddd XMMTMP, MSG0 |
196 | sha256msg2 MSGTMP3, MSGTMP0 | 214 | sha256msg2 MSG3, MSG0 |
197 | shuf128_32 $0x0E, MSG, MSG | 215 | MOVE_UPPER64_DOWN(MSG) |
198 | sha256rnds2 MSG, STATE1, STATE0 | 216 | sha256rnds2 MSG, STATE1, STATE0 |
199 | sha256msg1 MSGTMP3, MSGTMP2 | 217 | sha256msg1 MSG3, MSG2 |
200 | 218 | ||
201 | /* Rounds 48-51 */ | 219 | /* Rounds 48-51 */ |
202 | mova128 MSGTMP0, MSG | 220 | mova128 MSG0, MSG |
203 | paddd 12*16-8*16(SHA256CONSTANTS), MSG | 221 | paddd 12*16-8*16(SHA256CONSTANTS), MSG |
204 | sha256rnds2 MSG, STATE0, STATE1 | 222 | sha256rnds2 MSG, STATE0, STATE1 |
205 | mova128 MSGTMP0, XMMTMP | 223 | mova128 MSG0, XMMTMP |
206 | palignr $4, MSGTMP3, XMMTMP | 224 | palignr $4, MSG3, XMMTMP |
207 | paddd XMMTMP, MSGTMP1 | 225 | paddd XMMTMP, MSG1 |
208 | sha256msg2 MSGTMP0, MSGTMP1 | 226 | sha256msg2 MSG0, MSG1 |
209 | shuf128_32 $0x0E, MSG, MSG | 227 | MOVE_UPPER64_DOWN(MSG) |
210 | sha256rnds2 MSG, STATE1, STATE0 | 228 | sha256rnds2 MSG, STATE1, STATE0 |
211 | sha256msg1 MSGTMP0, MSGTMP3 | 229 | sha256msg1 MSG0, MSG3 |
212 | 230 | ||
213 | /* Rounds 52-55 */ | 231 | /* Rounds 52-55 */ |
214 | mova128 MSGTMP1, MSG | 232 | mova128 MSG1, MSG |
215 | paddd 13*16-8*16(SHA256CONSTANTS), MSG | 233 | paddd 13*16-8*16(SHA256CONSTANTS), MSG |
216 | sha256rnds2 MSG, STATE0, STATE1 | 234 | sha256rnds2 MSG, STATE0, STATE1 |
217 | mova128 MSGTMP1, XMMTMP | 235 | mova128 MSG1, XMMTMP |
218 | palignr $4, MSGTMP0, XMMTMP | 236 | palignr $4, MSG0, XMMTMP |
219 | paddd XMMTMP, MSGTMP2 | 237 | paddd XMMTMP, MSG2 |
220 | sha256msg2 MSGTMP1, MSGTMP2 | 238 | sha256msg2 MSG1, MSG2 |
221 | shuf128_32 $0x0E, MSG, MSG | 239 | MOVE_UPPER64_DOWN(MSG) |
222 | sha256rnds2 MSG, STATE1, STATE0 | 240 | sha256rnds2 MSG, STATE1, STATE0 |
223 | 241 | ||
224 | /* Rounds 56-59 */ | 242 | /* Rounds 56-59 */ |
225 | mova128 MSGTMP2, MSG | 243 | mova128 MSG2, MSG |
226 | paddd 14*16-8*16(SHA256CONSTANTS), MSG | 244 | paddd 14*16-8*16(SHA256CONSTANTS), MSG |
227 | sha256rnds2 MSG, STATE0, STATE1 | 245 | sha256rnds2 MSG, STATE0, STATE1 |
228 | mova128 MSGTMP2, XMMTMP | 246 | mova128 MSG2, XMMTMP |
229 | palignr $4, MSGTMP1, XMMTMP | 247 | palignr $4, MSG1, XMMTMP |
230 | paddd XMMTMP, MSGTMP3 | 248 | paddd XMMTMP, MSG3 |
231 | sha256msg2 MSGTMP2, MSGTMP3 | 249 | sha256msg2 MSG2, MSG3 |
232 | shuf128_32 $0x0E, MSG, MSG | 250 | MOVE_UPPER64_DOWN(MSG) |
233 | sha256rnds2 MSG, STATE1, STATE0 | 251 | sha256rnds2 MSG, STATE1, STATE0 |
234 | 252 | ||
235 | /* Rounds 60-63 */ | 253 | /* Rounds 60-63 */ |
236 | mova128 MSGTMP3, MSG | 254 | mova128 MSG3, MSG |
237 | paddd 15*16-8*16(SHA256CONSTANTS), MSG | 255 | paddd 15*16-8*16(SHA256CONSTANTS), MSG |
238 | sha256rnds2 MSG, STATE0, STATE1 | 256 | sha256rnds2 MSG, STATE0, STATE1 |
239 | shuf128_32 $0x0E, MSG, MSG | 257 | MOVE_UPPER64_DOWN(MSG) |
240 | sha256rnds2 MSG, STATE1, STATE0 | 258 | sha256rnds2 MSG, STATE1, STATE0 |
241 | 259 | ||
242 | /* Write hash values back in the correct order */ | 260 | /* Write hash values back in the correct order */ |
243 | mova128 STATE0, XMMTMP | 261 | mova128 STATE0, XMMTMP |
244 | /* shufps takes dwords 0,1 from *2nd* operand, and dwords 2,3 from 1st one */ | 262 | /* shufps: dwords 0,1 of the result are selected from *2nd* operand, and dwords 2,3 from 1st operand */ |
245 | /* --- -------------- HGDC -- FEBA */ | 263 | /* --- -------------- HGDC -- FEBA */ |
246 | shufps SHUF(3,2,3,2), STATE1, STATE0 /* ABCD */ | 264 | shufps SHUF(3,2,3,2), STATE1, STATE0 /* ABCD */ |
247 | shufps SHUF(1,0,1,0), STATE1, XMMTMP /* EFGH */ | 265 | shufps SHUF(1,0,1,0), STATE1, XMMTMP /* EFGH */ |
diff --git a/libbb/hash_sha256_hwaccel_x86-64.S b/libbb/hash_sha256_hwaccel_x86-64.S index 172c2eae2..ee3abbd1f 100644 --- a/libbb/hash_sha256_hwaccel_x86-64.S +++ b/libbb/hash_sha256_hwaccel_x86-64.S | |||
@@ -34,24 +34,24 @@ | |||
34 | #define MSG %xmm0 | 34 | #define MSG %xmm0 |
35 | #define STATE0 %xmm1 | 35 | #define STATE0 %xmm1 |
36 | #define STATE1 %xmm2 | 36 | #define STATE1 %xmm2 |
37 | #define MSGTMP0 %xmm3 | 37 | #define MSG0 %xmm3 |
38 | #define MSGTMP1 %xmm4 | 38 | #define MSG1 %xmm4 |
39 | #define MSGTMP2 %xmm5 | 39 | #define MSG2 %xmm5 |
40 | #define MSGTMP3 %xmm6 | 40 | #define MSG3 %xmm6 |
41 | 41 | ||
42 | #define XMMTMP %xmm7 | 42 | #define XMMTMP %xmm7 |
43 | 43 | ||
44 | #define SAVE0 %xmm8 | 44 | #define SAVE0 %xmm8 |
45 | #define SAVE1 %xmm9 | 45 | #define SAVE1 %xmm9 |
46 | 46 | ||
47 | #define SHUF(a,b,c,d) $(a+(b<<2)+(c<<4)+(d<<6)) | 47 | #define SHUF(a,b,c,d) $((a)+((b)<<2)+((c)<<4)+((d)<<6)) |
48 | 48 | ||
49 | .balign 8 # allow decoders to fetch at least 2 first insns | 49 | .balign 8 # allow decoders to fetch at least 2 first insns |
50 | sha256_process_block64_shaNI: | 50 | sha256_process_block64_shaNI: |
51 | 51 | ||
52 | movu128 80+0*16(%rdi), XMMTMP /* ABCD (little-endian dword order) */ | 52 | movu128 80+0*16(%rdi), XMMTMP /* ABCD (shown least-significant-dword-first) */ |
53 | movu128 80+1*16(%rdi), STATE1 /* EFGH */ | 53 | movu128 80+1*16(%rdi), STATE1 /* EFGH */ |
54 | /* shufps takes dwords 0,1 from *2nd* operand, and dwords 2,3 from 1st one */ | 54 | /* shufps: dwords 0,1 of the result are selected from *2nd* operand, and dwords 2,3 from 1st operand */ |
55 | mova128 STATE1, STATE0 | 55 | mova128 STATE1, STATE0 |
56 | /* --- -------------- ABCD -- EFGH */ | 56 | /* --- -------------- ABCD -- EFGH */ |
57 | shufps SHUF(1,0,1,0), XMMTMP, STATE0 /* FEBA */ | 57 | shufps SHUF(1,0,1,0), XMMTMP, STATE0 /* FEBA */ |
@@ -65,185 +65,203 @@ sha256_process_block64_shaNI: | |||
65 | mova128 STATE0, SAVE0 | 65 | mova128 STATE0, SAVE0 |
66 | mova128 STATE1, SAVE1 | 66 | mova128 STATE1, SAVE1 |
67 | 67 | ||
68 | // sha256rnds2 instruction uses only lower 64 bits of MSG. | ||
69 | // The code below needs to move upper 64 bits to lower 64 bits | ||
70 | // for the second sha256rnds2 invocation | ||
71 | // (what remains in upper bits does not matter). | ||
72 | // There are several ways to do it: | ||
73 | // movhlps MSG, MSG // abcd -> cdcd (3 bytes of code) | ||
74 | // shuf128_32 SHUF(2,3,n,n), MSG, MSG // abcd -> cdXX (4 bytes) | ||
75 | // punpckhqdq MSG, MSG // abcd -> cdcd (4 bytes) | ||
76 | // unpckhpd MSG, MSG // abcd -> cdcd (4 bytes) | ||
77 | // psrldq $8, MSG // abcd -> cd00 (5 bytes) | ||
78 | // palignr $8, MSG, MSG // abcd -> cdab (6 bytes, SSSE3 insn) | ||
79 | #define MOVE_UPPER64_DOWN(reg) movhlps reg, reg | ||
80 | //#define MOVE_UPPER64_DOWN(reg) shuf128_32 SHUF(2,3,0,0), reg, reg | ||
81 | //#define MOVE_UPPER64_DOWN(reg) punpckhqdq reg, reg | ||
82 | //#define MOVE_UPPER64_DOWN(reg) unpckhpd reg, reg | ||
83 | //#define MOVE_UPPER64_DOWN(reg) psrldq $8, reg | ||
84 | //#define MOVE_UPPER64_DOWN(reg) palignr $8, reg, reg | ||
85 | |||
68 | /* Rounds 0-3 */ | 86 | /* Rounds 0-3 */ |
69 | movu128 0*16(DATA_PTR), MSG | 87 | movu128 0*16(DATA_PTR), MSG |
70 | pshufb XMMTMP, MSG | 88 | pshufb XMMTMP, MSG |
71 | mova128 MSG, MSGTMP0 | 89 | mova128 MSG, MSG0 |
72 | paddd 0*16-8*16(SHA256CONSTANTS), MSG | 90 | paddd 0*16-8*16(SHA256CONSTANTS), MSG |
73 | sha256rnds2 MSG, STATE0, STATE1 | 91 | sha256rnds2 MSG, STATE0, STATE1 |
74 | shuf128_32 $0x0E, MSG, MSG | 92 | MOVE_UPPER64_DOWN(MSG) |
75 | sha256rnds2 MSG, STATE1, STATE0 | 93 | sha256rnds2 MSG, STATE1, STATE0 |
76 | 94 | ||
77 | /* Rounds 4-7 */ | 95 | /* Rounds 4-7 */ |
78 | movu128 1*16(DATA_PTR), MSG | 96 | movu128 1*16(DATA_PTR), MSG |
79 | pshufb XMMTMP, MSG | 97 | pshufb XMMTMP, MSG |
80 | mova128 MSG, MSGTMP1 | 98 | mova128 MSG, MSG1 |
81 | paddd 1*16-8*16(SHA256CONSTANTS), MSG | 99 | paddd 1*16-8*16(SHA256CONSTANTS), MSG |
82 | sha256rnds2 MSG, STATE0, STATE1 | 100 | sha256rnds2 MSG, STATE0, STATE1 |
83 | shuf128_32 $0x0E, MSG, MSG | 101 | MOVE_UPPER64_DOWN(MSG) |
84 | sha256rnds2 MSG, STATE1, STATE0 | 102 | sha256rnds2 MSG, STATE1, STATE0 |
85 | sha256msg1 MSGTMP1, MSGTMP0 | 103 | sha256msg1 MSG1, MSG0 |
86 | 104 | ||
87 | /* Rounds 8-11 */ | 105 | /* Rounds 8-11 */ |
88 | movu128 2*16(DATA_PTR), MSG | 106 | movu128 2*16(DATA_PTR), MSG |
89 | pshufb XMMTMP, MSG | 107 | pshufb XMMTMP, MSG |
90 | mova128 MSG, MSGTMP2 | 108 | mova128 MSG, MSG2 |
91 | paddd 2*16-8*16(SHA256CONSTANTS), MSG | 109 | paddd 2*16-8*16(SHA256CONSTANTS), MSG |
92 | sha256rnds2 MSG, STATE0, STATE1 | 110 | sha256rnds2 MSG, STATE0, STATE1 |
93 | shuf128_32 $0x0E, MSG, MSG | 111 | MOVE_UPPER64_DOWN(MSG) |
94 | sha256rnds2 MSG, STATE1, STATE0 | 112 | sha256rnds2 MSG, STATE1, STATE0 |
95 | sha256msg1 MSGTMP2, MSGTMP1 | 113 | sha256msg1 MSG2, MSG1 |
96 | 114 | ||
97 | /* Rounds 12-15 */ | 115 | /* Rounds 12-15 */ |
98 | movu128 3*16(DATA_PTR), MSG | 116 | movu128 3*16(DATA_PTR), MSG |
99 | pshufb XMMTMP, MSG | 117 | pshufb XMMTMP, MSG |
100 | /* ...to here */ | 118 | /* ...to here */ |
101 | mova128 MSG, MSGTMP3 | 119 | mova128 MSG, MSG3 |
102 | paddd 3*16-8*16(SHA256CONSTANTS), MSG | 120 | paddd 3*16-8*16(SHA256CONSTANTS), MSG |
103 | sha256rnds2 MSG, STATE0, STATE1 | 121 | sha256rnds2 MSG, STATE0, STATE1 |
104 | mova128 MSGTMP3, XMMTMP | 122 | mova128 MSG3, XMMTMP |
105 | palignr $4, MSGTMP2, XMMTMP | 123 | palignr $4, MSG2, XMMTMP |
106 | paddd XMMTMP, MSGTMP0 | 124 | paddd XMMTMP, MSG0 |
107 | sha256msg2 MSGTMP3, MSGTMP0 | 125 | sha256msg2 MSG3, MSG0 |
108 | shuf128_32 $0x0E, MSG, MSG | 126 | MOVE_UPPER64_DOWN(MSG) |
109 | sha256rnds2 MSG, STATE1, STATE0 | 127 | sha256rnds2 MSG, STATE1, STATE0 |
110 | sha256msg1 MSGTMP3, MSGTMP2 | 128 | sha256msg1 MSG3, MSG2 |
111 | 129 | ||
112 | /* Rounds 16-19 */ | 130 | /* Rounds 16-19 */ |
113 | mova128 MSGTMP0, MSG | 131 | mova128 MSG0, MSG |
114 | paddd 4*16-8*16(SHA256CONSTANTS), MSG | 132 | paddd 4*16-8*16(SHA256CONSTANTS), MSG |
115 | sha256rnds2 MSG, STATE0, STATE1 | 133 | sha256rnds2 MSG, STATE0, STATE1 |
116 | mova128 MSGTMP0, XMMTMP | 134 | mova128 MSG0, XMMTMP |
117 | palignr $4, MSGTMP3, XMMTMP | 135 | palignr $4, MSG3, XMMTMP |
118 | paddd XMMTMP, MSGTMP1 | 136 | paddd XMMTMP, MSG1 |
119 | sha256msg2 MSGTMP0, MSGTMP1 | 137 | sha256msg2 MSG0, MSG1 |
120 | shuf128_32 $0x0E, MSG, MSG | 138 | MOVE_UPPER64_DOWN(MSG) |
121 | sha256rnds2 MSG, STATE1, STATE0 | 139 | sha256rnds2 MSG, STATE1, STATE0 |
122 | sha256msg1 MSGTMP0, MSGTMP3 | 140 | sha256msg1 MSG0, MSG3 |
123 | 141 | ||
124 | /* Rounds 20-23 */ | 142 | /* Rounds 20-23 */ |
125 | mova128 MSGTMP1, MSG | 143 | mova128 MSG1, MSG |
126 | paddd 5*16-8*16(SHA256CONSTANTS), MSG | 144 | paddd 5*16-8*16(SHA256CONSTANTS), MSG |
127 | sha256rnds2 MSG, STATE0, STATE1 | 145 | sha256rnds2 MSG, STATE0, STATE1 |
128 | mova128 MSGTMP1, XMMTMP | 146 | mova128 MSG1, XMMTMP |
129 | palignr $4, MSGTMP0, XMMTMP | 147 | palignr $4, MSG0, XMMTMP |
130 | paddd XMMTMP, MSGTMP2 | 148 | paddd XMMTMP, MSG2 |
131 | sha256msg2 MSGTMP1, MSGTMP2 | 149 | sha256msg2 MSG1, MSG2 |
132 | shuf128_32 $0x0E, MSG, MSG | 150 | MOVE_UPPER64_DOWN(MSG) |
133 | sha256rnds2 MSG, STATE1, STATE0 | 151 | sha256rnds2 MSG, STATE1, STATE0 |
134 | sha256msg1 MSGTMP1, MSGTMP0 | 152 | sha256msg1 MSG1, MSG0 |
135 | 153 | ||
136 | /* Rounds 24-27 */ | 154 | /* Rounds 24-27 */ |
137 | mova128 MSGTMP2, MSG | 155 | mova128 MSG2, MSG |
138 | paddd 6*16-8*16(SHA256CONSTANTS), MSG | 156 | paddd 6*16-8*16(SHA256CONSTANTS), MSG |
139 | sha256rnds2 MSG, STATE0, STATE1 | 157 | sha256rnds2 MSG, STATE0, STATE1 |
140 | mova128 MSGTMP2, XMMTMP | 158 | mova128 MSG2, XMMTMP |
141 | palignr $4, MSGTMP1, XMMTMP | 159 | palignr $4, MSG1, XMMTMP |
142 | paddd XMMTMP, MSGTMP3 | 160 | paddd XMMTMP, MSG3 |
143 | sha256msg2 MSGTMP2, MSGTMP3 | 161 | sha256msg2 MSG2, MSG3 |
144 | shuf128_32 $0x0E, MSG, MSG | 162 | MOVE_UPPER64_DOWN(MSG) |
145 | sha256rnds2 MSG, STATE1, STATE0 | 163 | sha256rnds2 MSG, STATE1, STATE0 |
146 | sha256msg1 MSGTMP2, MSGTMP1 | 164 | sha256msg1 MSG2, MSG1 |
147 | 165 | ||
148 | /* Rounds 28-31 */ | 166 | /* Rounds 28-31 */ |
149 | mova128 MSGTMP3, MSG | 167 | mova128 MSG3, MSG |
150 | paddd 7*16-8*16(SHA256CONSTANTS), MSG | 168 | paddd 7*16-8*16(SHA256CONSTANTS), MSG |
151 | sha256rnds2 MSG, STATE0, STATE1 | 169 | sha256rnds2 MSG, STATE0, STATE1 |
152 | mova128 MSGTMP3, XMMTMP | 170 | mova128 MSG3, XMMTMP |
153 | palignr $4, MSGTMP2, XMMTMP | 171 | palignr $4, MSG2, XMMTMP |
154 | paddd XMMTMP, MSGTMP0 | 172 | paddd XMMTMP, MSG0 |
155 | sha256msg2 MSGTMP3, MSGTMP0 | 173 | sha256msg2 MSG3, MSG0 |
156 | shuf128_32 $0x0E, MSG, MSG | 174 | MOVE_UPPER64_DOWN(MSG) |
157 | sha256rnds2 MSG, STATE1, STATE0 | 175 | sha256rnds2 MSG, STATE1, STATE0 |
158 | sha256msg1 MSGTMP3, MSGTMP2 | 176 | sha256msg1 MSG3, MSG2 |
159 | 177 | ||
160 | /* Rounds 32-35 */ | 178 | /* Rounds 32-35 */ |
161 | mova128 MSGTMP0, MSG | 179 | mova128 MSG0, MSG |
162 | paddd 8*16-8*16(SHA256CONSTANTS), MSG | 180 | paddd 8*16-8*16(SHA256CONSTANTS), MSG |
163 | sha256rnds2 MSG, STATE0, STATE1 | 181 | sha256rnds2 MSG, STATE0, STATE1 |
164 | mova128 MSGTMP0, XMMTMP | 182 | mova128 MSG0, XMMTMP |
165 | palignr $4, MSGTMP3, XMMTMP | 183 | palignr $4, MSG3, XMMTMP |
166 | paddd XMMTMP, MSGTMP1 | 184 | paddd XMMTMP, MSG1 |
167 | sha256msg2 MSGTMP0, MSGTMP1 | 185 | sha256msg2 MSG0, MSG1 |
168 | shuf128_32 $0x0E, MSG, MSG | 186 | MOVE_UPPER64_DOWN(MSG) |
169 | sha256rnds2 MSG, STATE1, STATE0 | 187 | sha256rnds2 MSG, STATE1, STATE0 |
170 | sha256msg1 MSGTMP0, MSGTMP3 | 188 | sha256msg1 MSG0, MSG3 |
171 | 189 | ||
172 | /* Rounds 36-39 */ | 190 | /* Rounds 36-39 */ |
173 | mova128 MSGTMP1, MSG | 191 | mova128 MSG1, MSG |
174 | paddd 9*16-8*16(SHA256CONSTANTS), MSG | 192 | paddd 9*16-8*16(SHA256CONSTANTS), MSG |
175 | sha256rnds2 MSG, STATE0, STATE1 | 193 | sha256rnds2 MSG, STATE0, STATE1 |
176 | mova128 MSGTMP1, XMMTMP | 194 | mova128 MSG1, XMMTMP |
177 | palignr $4, MSGTMP0, XMMTMP | 195 | palignr $4, MSG0, XMMTMP |
178 | paddd XMMTMP, MSGTMP2 | 196 | paddd XMMTMP, MSG2 |
179 | sha256msg2 MSGTMP1, MSGTMP2 | 197 | sha256msg2 MSG1, MSG2 |
180 | shuf128_32 $0x0E, MSG, MSG | 198 | MOVE_UPPER64_DOWN(MSG) |
181 | sha256rnds2 MSG, STATE1, STATE0 | 199 | sha256rnds2 MSG, STATE1, STATE0 |
182 | sha256msg1 MSGTMP1, MSGTMP0 | 200 | sha256msg1 MSG1, MSG0 |
183 | 201 | ||
184 | /* Rounds 40-43 */ | 202 | /* Rounds 40-43 */ |
185 | mova128 MSGTMP2, MSG | 203 | mova128 MSG2, MSG |
186 | paddd 10*16-8*16(SHA256CONSTANTS), MSG | 204 | paddd 10*16-8*16(SHA256CONSTANTS), MSG |
187 | sha256rnds2 MSG, STATE0, STATE1 | 205 | sha256rnds2 MSG, STATE0, STATE1 |
188 | mova128 MSGTMP2, XMMTMP | 206 | mova128 MSG2, XMMTMP |
189 | palignr $4, MSGTMP1, XMMTMP | 207 | palignr $4, MSG1, XMMTMP |
190 | paddd XMMTMP, MSGTMP3 | 208 | paddd XMMTMP, MSG3 |
191 | sha256msg2 MSGTMP2, MSGTMP3 | 209 | sha256msg2 MSG2, MSG3 |
192 | shuf128_32 $0x0E, MSG, MSG | 210 | MOVE_UPPER64_DOWN(MSG) |
193 | sha256rnds2 MSG, STATE1, STATE0 | 211 | sha256rnds2 MSG, STATE1, STATE0 |
194 | sha256msg1 MSGTMP2, MSGTMP1 | 212 | sha256msg1 MSG2, MSG1 |
195 | 213 | ||
196 | /* Rounds 44-47 */ | 214 | /* Rounds 44-47 */ |
197 | mova128 MSGTMP3, MSG | 215 | mova128 MSG3, MSG |
198 | paddd 11*16-8*16(SHA256CONSTANTS), MSG | 216 | paddd 11*16-8*16(SHA256CONSTANTS), MSG |
199 | sha256rnds2 MSG, STATE0, STATE1 | 217 | sha256rnds2 MSG, STATE0, STATE1 |
200 | mova128 MSGTMP3, XMMTMP | 218 | mova128 MSG3, XMMTMP |
201 | palignr $4, MSGTMP2, XMMTMP | 219 | palignr $4, MSG2, XMMTMP |
202 | paddd XMMTMP, MSGTMP0 | 220 | paddd XMMTMP, MSG0 |
203 | sha256msg2 MSGTMP3, MSGTMP0 | 221 | sha256msg2 MSG3, MSG0 |
204 | shuf128_32 $0x0E, MSG, MSG | 222 | MOVE_UPPER64_DOWN(MSG) |
205 | sha256rnds2 MSG, STATE1, STATE0 | 223 | sha256rnds2 MSG, STATE1, STATE0 |
206 | sha256msg1 MSGTMP3, MSGTMP2 | 224 | sha256msg1 MSG3, MSG2 |
207 | 225 | ||
208 | /* Rounds 48-51 */ | 226 | /* Rounds 48-51 */ |
209 | mova128 MSGTMP0, MSG | 227 | mova128 MSG0, MSG |
210 | paddd 12*16-8*16(SHA256CONSTANTS), MSG | 228 | paddd 12*16-8*16(SHA256CONSTANTS), MSG |
211 | sha256rnds2 MSG, STATE0, STATE1 | 229 | sha256rnds2 MSG, STATE0, STATE1 |
212 | mova128 MSGTMP0, XMMTMP | 230 | mova128 MSG0, XMMTMP |
213 | palignr $4, MSGTMP3, XMMTMP | 231 | palignr $4, MSG3, XMMTMP |
214 | paddd XMMTMP, MSGTMP1 | 232 | paddd XMMTMP, MSG1 |
215 | sha256msg2 MSGTMP0, MSGTMP1 | 233 | sha256msg2 MSG0, MSG1 |
216 | shuf128_32 $0x0E, MSG, MSG | 234 | MOVE_UPPER64_DOWN(MSG) |
217 | sha256rnds2 MSG, STATE1, STATE0 | 235 | sha256rnds2 MSG, STATE1, STATE0 |
218 | sha256msg1 MSGTMP0, MSGTMP3 | 236 | sha256msg1 MSG0, MSG3 |
219 | 237 | ||
220 | /* Rounds 52-55 */ | 238 | /* Rounds 52-55 */ |
221 | mova128 MSGTMP1, MSG | 239 | mova128 MSG1, MSG |
222 | paddd 13*16-8*16(SHA256CONSTANTS), MSG | 240 | paddd 13*16-8*16(SHA256CONSTANTS), MSG |
223 | sha256rnds2 MSG, STATE0, STATE1 | 241 | sha256rnds2 MSG, STATE0, STATE1 |
224 | mova128 MSGTMP1, XMMTMP | 242 | mova128 MSG1, XMMTMP |
225 | palignr $4, MSGTMP0, XMMTMP | 243 | palignr $4, MSG0, XMMTMP |
226 | paddd XMMTMP, MSGTMP2 | 244 | paddd XMMTMP, MSG2 |
227 | sha256msg2 MSGTMP1, MSGTMP2 | 245 | sha256msg2 MSG1, MSG2 |
228 | shuf128_32 $0x0E, MSG, MSG | 246 | MOVE_UPPER64_DOWN(MSG) |
229 | sha256rnds2 MSG, STATE1, STATE0 | 247 | sha256rnds2 MSG, STATE1, STATE0 |
230 | 248 | ||
231 | /* Rounds 56-59 */ | 249 | /* Rounds 56-59 */ |
232 | mova128 MSGTMP2, MSG | 250 | mova128 MSG2, MSG |
233 | paddd 14*16-8*16(SHA256CONSTANTS), MSG | 251 | paddd 14*16-8*16(SHA256CONSTANTS), MSG |
234 | sha256rnds2 MSG, STATE0, STATE1 | 252 | sha256rnds2 MSG, STATE0, STATE1 |
235 | mova128 MSGTMP2, XMMTMP | 253 | mova128 MSG2, XMMTMP |
236 | palignr $4, MSGTMP1, XMMTMP | 254 | palignr $4, MSG1, XMMTMP |
237 | paddd XMMTMP, MSGTMP3 | 255 | paddd XMMTMP, MSG3 |
238 | sha256msg2 MSGTMP2, MSGTMP3 | 256 | sha256msg2 MSG2, MSG3 |
239 | shuf128_32 $0x0E, MSG, MSG | 257 | MOVE_UPPER64_DOWN(MSG) |
240 | sha256rnds2 MSG, STATE1, STATE0 | 258 | sha256rnds2 MSG, STATE1, STATE0 |
241 | 259 | ||
242 | /* Rounds 60-63 */ | 260 | /* Rounds 60-63 */ |
243 | mova128 MSGTMP3, MSG | 261 | mova128 MSG3, MSG |
244 | paddd 15*16-8*16(SHA256CONSTANTS), MSG | 262 | paddd 15*16-8*16(SHA256CONSTANTS), MSG |
245 | sha256rnds2 MSG, STATE0, STATE1 | 263 | sha256rnds2 MSG, STATE0, STATE1 |
246 | shuf128_32 $0x0E, MSG, MSG | 264 | MOVE_UPPER64_DOWN(MSG) |
247 | sha256rnds2 MSG, STATE1, STATE0 | 265 | sha256rnds2 MSG, STATE1, STATE0 |
248 | 266 | ||
249 | /* Add current hash values with previously saved */ | 267 | /* Add current hash values with previously saved */ |
@@ -252,7 +270,7 @@ sha256_process_block64_shaNI: | |||
252 | 270 | ||
253 | /* Write hash values back in the correct order */ | 271 | /* Write hash values back in the correct order */ |
254 | mova128 STATE0, XMMTMP | 272 | mova128 STATE0, XMMTMP |
255 | /* shufps takes dwords 0,1 from *2nd* operand, and dwords 2,3 from 1st one */ | 273 | /* shufps: dwords 0,1 of the result are selected from *2nd* operand, and dwords 2,3 from 1st operand */ |
256 | /* --- -------------- HGDC -- FEBA */ | 274 | /* --- -------------- HGDC -- FEBA */ |
257 | shufps SHUF(3,2,3,2), STATE1, STATE0 /* ABCD */ | 275 | shufps SHUF(3,2,3,2), STATE1, STATE0 /* ABCD */ |
258 | shufps SHUF(1,0,1,0), STATE1, XMMTMP /* EFGH */ | 276 | shufps SHUF(1,0,1,0), STATE1, XMMTMP /* EFGH */ |
diff --git a/libbb/lineedit.c b/libbb/lineedit.c index 151208c1c..10cc0433b 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c | |||
@@ -451,7 +451,7 @@ static void put_cur_glyph_and_inc_cursor(void) | |||
451 | * have automargin (IOW: it is moving cursor to next line | 451 | * have automargin (IOW: it is moving cursor to next line |
452 | * by itself (which is wrong for VT-10x terminals)), | 452 | * by itself (which is wrong for VT-10x terminals)), |
453 | * this will break things: there will be one extra empty line */ | 453 | * this will break things: there will be one extra empty line */ |
454 | puts("\r"); /* + implicit '\n' */ | 454 | fputs("\r\n", stderr); |
455 | #else | 455 | #else |
456 | /* VT-10x terminals don't wrap cursor to next line when last char | 456 | /* VT-10x terminals don't wrap cursor to next line when last char |
457 | * on the line is printed - cursor stays "over" this char. | 457 | * on the line is printed - cursor stays "over" this char. |
@@ -1170,9 +1170,10 @@ static void showfiles(void) | |||
1170 | ); | 1170 | ); |
1171 | } | 1171 | } |
1172 | if (ENABLE_UNICODE_SUPPORT) | 1172 | if (ENABLE_UNICODE_SUPPORT) |
1173 | puts(printable_string(matches[n])); | 1173 | fputs(printable_string(matches[n]), stderr); |
1174 | else | 1174 | else |
1175 | puts(matches[n]); | 1175 | fputs(matches[n], stderr); |
1176 | bb_putchar_stderr('\n'); | ||
1176 | } | 1177 | } |
1177 | } | 1178 | } |
1178 | 1179 | ||
@@ -1405,8 +1406,8 @@ unsigned FAST_FUNC size_from_HISTFILESIZE(const char *hp) | |||
1405 | int size = MAX_HISTORY; | 1406 | int size = MAX_HISTORY; |
1406 | if (hp) { | 1407 | if (hp) { |
1407 | size = atoi(hp); | 1408 | size = atoi(hp); |
1408 | if (size <= 0) | 1409 | if (size < 0) |
1409 | return 1; | 1410 | return 0; |
1410 | if (size > MAX_HISTORY) | 1411 | if (size > MAX_HISTORY) |
1411 | return MAX_HISTORY; | 1412 | return MAX_HISTORY; |
1412 | } | 1413 | } |
@@ -1500,18 +1501,21 @@ static void load_history(line_input_t *st_parm) | |||
1500 | /* NB: do not trash old history if file can't be opened */ | 1501 | /* NB: do not trash old history if file can't be opened */ |
1501 | 1502 | ||
1502 | fp = fopen_for_read(st_parm->hist_file); | 1503 | fp = fopen_for_read(st_parm->hist_file); |
1503 | if (fp) { | 1504 | if (!fp) |
1504 | /* clean up old history */ | 1505 | return; |
1505 | for (idx = st_parm->cnt_history; idx > 0;) { | 1506 | |
1506 | idx--; | 1507 | /* clean up old history */ |
1507 | free(st_parm->history[idx]); | 1508 | for (idx = st_parm->cnt_history; idx > 0;) { |
1508 | st_parm->history[idx] = NULL; | 1509 | idx--; |
1509 | } | 1510 | free(st_parm->history[idx]); |
1511 | st_parm->history[idx] = NULL; | ||
1512 | } | ||
1510 | 1513 | ||
1511 | /* fill temp_h[], retaining only last MAX_HISTORY lines */ | 1514 | /* fill temp_h[], retaining only last max_history lines */ |
1512 | memset(temp_h, 0, sizeof(temp_h)); | 1515 | memset(temp_h, 0, sizeof(temp_h)); |
1513 | idx = 0; | 1516 | idx = 0; |
1514 | st_parm->cnt_history_in_file = 0; | 1517 | st_parm->cnt_history_in_file = 0; |
1518 | if (st_parm->max_history != 0) { | ||
1515 | while ((line = xmalloc_fgetline(fp)) != NULL) { | 1519 | while ((line = xmalloc_fgetline(fp)) != NULL) { |
1516 | if (line[0] == '\0') { | 1520 | if (line[0] == '\0') { |
1517 | free(line); | 1521 | free(line); |
@@ -1524,34 +1528,34 @@ static void load_history(line_input_t *st_parm) | |||
1524 | if (idx == st_parm->max_history) | 1528 | if (idx == st_parm->max_history) |
1525 | idx = 0; | 1529 | idx = 0; |
1526 | } | 1530 | } |
1527 | fclose(fp); | 1531 | } |
1528 | 1532 | fclose(fp); | |
1529 | /* find first non-NULL temp_h[], if any */ | ||
1530 | if (st_parm->cnt_history_in_file) { | ||
1531 | while (temp_h[idx] == NULL) { | ||
1532 | idx++; | ||
1533 | if (idx == st_parm->max_history) | ||
1534 | idx = 0; | ||
1535 | } | ||
1536 | } | ||
1537 | 1533 | ||
1538 | /* copy temp_h[] to st_parm->history[] */ | 1534 | /* find first non-NULL temp_h[], if any */ |
1539 | for (i = 0; i < st_parm->max_history;) { | 1535 | if (st_parm->cnt_history_in_file != 0) { |
1540 | line = temp_h[idx]; | 1536 | while (temp_h[idx] == NULL) { |
1541 | if (!line) | ||
1542 | break; | ||
1543 | idx++; | 1537 | idx++; |
1544 | if (idx == st_parm->max_history) | 1538 | if (idx == st_parm->max_history) |
1545 | idx = 0; | 1539 | idx = 0; |
1546 | line_len = strlen(line); | ||
1547 | if (line_len >= MAX_LINELEN) | ||
1548 | line[MAX_LINELEN-1] = '\0'; | ||
1549 | st_parm->history[i++] = line; | ||
1550 | } | 1540 | } |
1551 | st_parm->cnt_history = i; | ||
1552 | if (ENABLE_FEATURE_EDITING_SAVE_ON_EXIT) | ||
1553 | st_parm->cnt_history_in_file = i; | ||
1554 | } | 1541 | } |
1542 | |||
1543 | /* copy temp_h[] to st_parm->history[] */ | ||
1544 | for (i = 0; i < st_parm->max_history;) { | ||
1545 | line = temp_h[idx]; | ||
1546 | if (!line) | ||
1547 | break; | ||
1548 | idx++; | ||
1549 | if (idx == st_parm->max_history) | ||
1550 | idx = 0; | ||
1551 | line_len = strlen(line); | ||
1552 | if (line_len >= MAX_LINELEN) | ||
1553 | line[MAX_LINELEN-1] = '\0'; | ||
1554 | st_parm->history[i++] = line; | ||
1555 | } | ||
1556 | st_parm->cnt_history = i; | ||
1557 | if (ENABLE_FEATURE_EDITING_SAVE_ON_EXIT) | ||
1558 | st_parm->cnt_history_in_file = i; | ||
1555 | } | 1559 | } |
1556 | 1560 | ||
1557 | # if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT | 1561 | # if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT |
@@ -1559,17 +1563,27 @@ void FAST_FUNC save_history(line_input_t *st) | |||
1559 | { | 1563 | { |
1560 | FILE *fp; | 1564 | FILE *fp; |
1561 | 1565 | ||
1562 | if (!st || !st->hist_file) | 1566 | /* bash compat: HISTFILE="" disables history saving */ |
1567 | if (!st || !st->hist_file || !st->hist_file[0]) | ||
1563 | return; | 1568 | return; |
1564 | if (st->cnt_history <= st->cnt_history_in_file) | 1569 | if (st->cnt_history <= st->cnt_history_in_file) |
1565 | return; | 1570 | return; /* no new entries were added */ |
1571 | /* note: if st->max_history is 0, we do not abort: we truncate the history to 0 lines */ | ||
1566 | 1572 | ||
1567 | fp = fopen(st->hist_file, "a"); | 1573 | fp = fopen(st->hist_file, (st->max_history == 0 ? "w" : "a")); |
1568 | if (fp) { | 1574 | if (fp) { |
1569 | int i, fd; | 1575 | int i, fd; |
1570 | char *new_name; | 1576 | char *new_name; |
1571 | line_input_t *st_temp; | 1577 | line_input_t *st_temp; |
1572 | 1578 | ||
1579 | /* max_history==0 needs special-casing in general code, | ||
1580 | * just handle it in a simpler way: */ | ||
1581 | if (st->max_history == 0) { | ||
1582 | /* fopen("w") already truncated it */ | ||
1583 | fclose(fp); | ||
1584 | return; | ||
1585 | } | ||
1586 | |||
1573 | for (i = st->cnt_history_in_file; i < st->cnt_history; i++) | 1587 | for (i = st->cnt_history_in_file; i < st->cnt_history; i++) |
1574 | fprintf(fp, "%s\n", st->history[i]); | 1588 | fprintf(fp, "%s\n", st->history[i]); |
1575 | fclose(fp); | 1589 | fclose(fp); |
@@ -1579,6 +1593,8 @@ void FAST_FUNC save_history(line_input_t *st) | |||
1579 | st_temp = new_line_input_t(st->flags); | 1593 | st_temp = new_line_input_t(st->flags); |
1580 | st_temp->hist_file = st->hist_file; | 1594 | st_temp->hist_file = st->hist_file; |
1581 | st_temp->max_history = st->max_history; | 1595 | st_temp->max_history = st->max_history; |
1596 | /* load no more than max_history last lines */ | ||
1597 | /* (in unlikely case that file disappeared, st_temp gets empty history) */ | ||
1582 | load_history(st_temp); | 1598 | load_history(st_temp); |
1583 | 1599 | ||
1584 | /* write out temp file and replace hist_file atomically */ | 1600 | /* write out temp file and replace hist_file atomically */ |
@@ -1602,13 +1618,13 @@ static void save_history(char *str) | |||
1602 | int fd; | 1618 | int fd; |
1603 | int len, len2; | 1619 | int len, len2; |
1604 | 1620 | ||
1605 | if (!state->hist_file) | 1621 | /* bash compat: HISTFILE="" disables history saving */ |
1622 | if (!state->hist_file || !state->hist_file[0]) | ||
1606 | return; | 1623 | return; |
1607 | 1624 | ||
1608 | fd = open(state->hist_file, O_WRONLY | O_CREAT | O_APPEND, 0600); | 1625 | fd = open(state->hist_file, O_WRONLY | O_CREAT | O_APPEND, 0600); |
1609 | if (fd < 0) | 1626 | if (fd < 0) |
1610 | return; | 1627 | return; |
1611 | xlseek(fd, 0, SEEK_END); /* paranoia */ | ||
1612 | len = strlen(str); | 1628 | len = strlen(str); |
1613 | str[len] = '\n'; /* we (try to) do atomic write */ | 1629 | str[len] = '\n'; /* we (try to) do atomic write */ |
1614 | len2 = full_write(fd, str, len + 1); | 1630 | len2 = full_write(fd, str, len + 1); |
@@ -1663,13 +1679,10 @@ static void remember_in_history(char *str) | |||
1663 | if (str[0] == '\0') | 1679 | if (str[0] == '\0') |
1664 | return; | 1680 | return; |
1665 | i = state->cnt_history; | 1681 | i = state->cnt_history; |
1666 | /* Don't save dupes */ | 1682 | /* Don't save dups */ |
1667 | if (i && strcmp(state->history[i-1], str) == 0) | 1683 | if (i != 0 && strcmp(state->history[i-1], str) == 0) |
1668 | return; | 1684 | return; |
1669 | 1685 | ||
1670 | free(state->history[state->max_history]); /* redundant, paranoia */ | ||
1671 | state->history[state->max_history] = NULL; /* redundant, paranoia */ | ||
1672 | |||
1673 | /* If history[] is full, remove the oldest command */ | 1686 | /* If history[] is full, remove the oldest command */ |
1674 | /* we need to keep history[state->max_history] empty, hence >=, not > */ | 1687 | /* we need to keep history[state->max_history] empty, hence >=, not > */ |
1675 | if (i >= state->max_history) { | 1688 | if (i >= state->max_history) { |
@@ -1682,7 +1695,7 @@ static void remember_in_history(char *str) | |||
1682 | state->cnt_history_in_file--; | 1695 | state->cnt_history_in_file--; |
1683 | # endif | 1696 | # endif |
1684 | } | 1697 | } |
1685 | /* i <= state->max_history-1 */ | 1698 | /* i < state->max_history */ |
1686 | state->history[i++] = xstrdup(str); | 1699 | state->history[i++] = xstrdup(str); |
1687 | /* i <= state->max_history */ | 1700 | /* i <= state->max_history */ |
1688 | state->cur_history = i; | 1701 | state->cur_history = i; |
@@ -2194,7 +2207,6 @@ static int lineedit_read_key(char *read_key_buffer, int timeout) | |||
2194 | errno = EINTR; | 2207 | errno = EINTR; |
2195 | return -1; | 2208 | return -1; |
2196 | } | 2209 | } |
2197 | //FIXME: still races here with signals, but small window to poll() inside read_key | ||
2198 | IF_FEATURE_EDITING_WINCH(S.ok_to_redraw = 1;) | 2210 | IF_FEATURE_EDITING_WINCH(S.ok_to_redraw = 1;) |
2199 | /* errno = 0; - read_key does this itself */ | 2211 | /* errno = 0; - read_key does this itself */ |
2200 | ic = read_key(STDIN_FILENO, read_key_buffer, timeout); | 2212 | ic = read_key(STDIN_FILENO, read_key_buffer, timeout); |
diff --git a/libbb/poll_with_signals.c b/libbb/poll_with_signals.c new file mode 100644 index 000000000..47419f240 --- /dev/null +++ b/libbb/poll_with_signals.c | |||
@@ -0,0 +1,48 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Utility routines. | ||
4 | * | ||
5 | * Copyright (C) 2025 Denys Vlasenko <vda.linux@googlemail.com> | ||
6 | * | ||
7 | * Licensed under GPLv2, see file LICENSE in this source tree. | ||
8 | */ | ||
9 | //kbuild:lib-y += poll_with_signals.o | ||
10 | |||
11 | #include "libbb.h" | ||
12 | |||
13 | /* Shells, for example, need their line input and "read" builtin | ||
14 | * to be interruptible, and the naive handling of it a-la: | ||
15 | * if (bb_got_signal) { | ||
16 | * errno = EINTR; | ||
17 | * return -1; | ||
18 | * } | ||
19 | * poll(pfd, 1, -1); // signal here would set EINTR | ||
20 | * is racy. | ||
21 | * This is a bit heavy-handed, but safe wrt races: | ||
22 | */ | ||
23 | int FAST_FUNC check_got_signal_and_poll(struct pollfd pfd[1], int timeout) | ||
24 | { | ||
25 | int n; | ||
26 | struct timespec tv; | ||
27 | sigset_t orig_mask; | ||
28 | |||
29 | if (bb_got_signal) /* optimization */ | ||
30 | goto eintr; | ||
31 | |||
32 | if (timeout >= 0) { | ||
33 | tv.tv_sec = timeout / 1000; | ||
34 | tv.tv_nsec = (timeout % 1000) * 1000000; | ||
35 | } | ||
36 | /* test bb_got_signal, then poll(), atomically wrt signals */ | ||
37 | sigfillset(&orig_mask); | ||
38 | sigprocmask2(SIG_BLOCK, &orig_mask); | ||
39 | if (bb_got_signal) { | ||
40 | sigprocmask2(SIG_SETMASK, &orig_mask); | ||
41 | eintr: | ||
42 | errno = EINTR; /* inform the caller that we got a signal */ | ||
43 | return -1; | ||
44 | } | ||
45 | n = ppoll(pfd, 1, timeout >= 0 ? &tv : NULL, &orig_mask); | ||
46 | sigprocmask2(SIG_SETMASK, &orig_mask); | ||
47 | return n; | ||
48 | } | ||
diff --git a/libbb/procps.c b/libbb/procps.c index f56b71b21..fc31c075d 100644 --- a/libbb/procps.c +++ b/libbb/procps.c | |||
@@ -109,7 +109,7 @@ void FAST_FUNC free_procps_scan(procps_status_t* sp) | |||
109 | } | 109 | } |
110 | 110 | ||
111 | #if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP | 111 | #if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP |
112 | static unsigned long long fast_strtoull_16(char **endptr) | 112 | unsigned long long FAST_FUNC fast_strtoull_16(char **endptr) |
113 | { | 113 | { |
114 | unsigned char c; | 114 | unsigned char c; |
115 | char *str = *endptr; | 115 | char *str = *endptr; |
@@ -130,7 +130,7 @@ static unsigned long long fast_strtoull_16(char **endptr) | |||
130 | 130 | ||
131 | #if ENABLE_FEATURE_FAST_TOP || ENABLE_FEATURE_TOPMEM || ENABLE_PMAP | 131 | #if ENABLE_FEATURE_FAST_TOP || ENABLE_FEATURE_TOPMEM || ENABLE_PMAP |
132 | /* We cut a lot of corners here for speed */ | 132 | /* We cut a lot of corners here for speed */ |
133 | static unsigned long fast_strtoul_10(char **endptr) | 133 | unsigned long FAST_FUNC fast_strtoul_10(char **endptr) |
134 | { | 134 | { |
135 | unsigned char c; | 135 | unsigned char c; |
136 | char *str = *endptr; | 136 | char *str = *endptr; |
@@ -143,6 +143,24 @@ static unsigned long fast_strtoul_10(char **endptr) | |||
143 | *endptr = str + 1; /* We skip trailing space! */ | 143 | *endptr = str + 1; /* We skip trailing space! */ |
144 | return n; | 144 | return n; |
145 | } | 145 | } |
146 | # if LONG_MAX < LLONG_MAX | ||
147 | /* For VSZ, which can be very large */ | ||
148 | static unsigned long long fast_strtoull_10(char **endptr) | ||
149 | { | ||
150 | unsigned char c; | ||
151 | char *str = *endptr; | ||
152 | unsigned long long n = *str - '0'; | ||
153 | |||
154 | /* Need to stop on both ' ' and '\n' */ | ||
155 | while ((c = *++str) > ' ') | ||
156 | n = n*10 + (c - '0'); | ||
157 | |||
158 | *endptr = str + 1; /* We skip trailing space! */ | ||
159 | return n; | ||
160 | } | ||
161 | # else | ||
162 | # define fast_strtoull_10(endptr) fast_strtoul_10(endptr) | ||
163 | # endif | ||
146 | 164 | ||
147 | # if ENABLE_FEATURE_FAST_TOP | 165 | # if ENABLE_FEATURE_FAST_TOP |
148 | static long fast_strtol_10(char **endptr) | 166 | static long fast_strtol_10(char **endptr) |
@@ -155,7 +173,7 @@ static long fast_strtol_10(char **endptr) | |||
155 | } | 173 | } |
156 | # endif | 174 | # endif |
157 | 175 | ||
158 | static char *skip_fields(char *str, int count) | 176 | char* FAST_FUNC skip_fields(char *str, int count) |
159 | { | 177 | { |
160 | do { | 178 | do { |
161 | while (*str++ != ' ') | 179 | while (*str++ != ' ') |
@@ -166,35 +184,25 @@ static char *skip_fields(char *str, int count) | |||
166 | } | 184 | } |
167 | #endif | 185 | #endif |
168 | 186 | ||
169 | #if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP | 187 | #if ENABLE_FEATURE_TOPMEM |
170 | static char* skip_whitespace_if_prefixed_with(char *buf, const char *prefix) | 188 | static NOINLINE void procps_read_smaps(pid_t pid, procps_status_t *sp) |
171 | { | 189 | { |
172 | char *tp = is_prefixed_with(buf, prefix); | 190 | // There is A LOT of /proc/PID/smaps data on a big system. |
173 | if (tp) { | 191 | // Optimize this for speed, makes "top -m" faster. |
174 | tp = skip_whitespace(tp); | 192 | //TODO large speedup: |
175 | } | 193 | //read /proc/PID/smaps_rollup (cumulative stats of all mappings, much faster) |
176 | return tp; | 194 | //and /proc/PID/maps to get mapped_ro and mapped_rw (IOW: VSZ,VSZRW) |
177 | } | ||
178 | 195 | ||
179 | int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total, | ||
180 | void (*cb)(struct smaprec *, void *), void *data) | ||
181 | { | ||
182 | FILE *file; | 196 | FILE *file; |
183 | struct smaprec currec; | ||
184 | char filename[sizeof("/proc/%u/smaps") + sizeof(int)*3]; | 197 | char filename[sizeof("/proc/%u/smaps") + sizeof(int)*3]; |
185 | char buf[PROCPS_BUFSIZE]; | 198 | char buf[PROCPS_BUFSIZE]; |
186 | #if !ENABLE_PMAP | ||
187 | void (*cb)(struct smaprec *, void *) = NULL; | ||
188 | void *data = NULL; | ||
189 | #endif | ||
190 | 199 | ||
191 | sprintf(filename, "/proc/%u/smaps", (int)pid); | 200 | sprintf(filename, "/proc/%u/smaps", (int)pid); |
192 | 201 | ||
193 | file = fopen_for_read(filename); | 202 | file = fopen_for_read(filename); |
194 | if (!file) | 203 | if (!file) |
195 | return 1; | 204 | return; |
196 | 205 | ||
197 | memset(&currec, 0, sizeof(currec)); | ||
198 | while (fgets(buf, PROCPS_BUFSIZE, file)) { | 206 | while (fgets(buf, PROCPS_BUFSIZE, file)) { |
199 | // Each mapping datum has this form: | 207 | // Each mapping datum has this form: |
200 | // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME | 208 | // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME |
@@ -202,80 +210,53 @@ int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total, | |||
202 | // Rss: nnn kB | 210 | // Rss: nnn kB |
203 | // ..... | 211 | // ..... |
204 | 212 | ||
205 | char *tp, *p; | 213 | char *tp; |
206 | 214 | ||
215 | if (buf[0] == 'S' || buf[0] == 'P') { | ||
207 | #define SCAN(S, X) \ | 216 | #define SCAN(S, X) \ |
208 | if ((tp = skip_whitespace_if_prefixed_with(buf, S)) != NULL) { \ | 217 | if (memcmp(buf, S, sizeof(S)-1) == 0) { \ |
209 | total->X += currec.X = fast_strtoul_10(&tp); \ | 218 | tp = skip_whitespace(buf + sizeof(S)-1); \ |
210 | continue; \ | 219 | sp->X += fast_strtoul_10(&tp); \ |
211 | } | 220 | continue; \ |
212 | if (cb) { | 221 | } |
213 | SCAN("Pss:" , smap_pss ); | 222 | SCAN("Private_Dirty:", private_dirty) |
214 | SCAN("Swap:" , smap_swap ); | 223 | SCAN("Private_Clean:", private_clean) |
215 | } | 224 | SCAN("Shared_Dirty:" , shared_dirty ) |
216 | SCAN("Private_Dirty:", private_dirty); | 225 | SCAN("Shared_Clean:" , shared_clean ) |
217 | SCAN("Private_Clean:", private_clean); | ||
218 | SCAN("Shared_Dirty:" , shared_dirty ); | ||
219 | SCAN("Shared_Clean:" , shared_clean ); | ||
220 | #undef SCAN | 226 | #undef SCAN |
227 | } | ||
221 | tp = strchr(buf, '-'); | 228 | tp = strchr(buf, '-'); |
222 | if (tp) { | 229 | if (tp) { |
223 | // We reached next mapping - the line of this form: | 230 | // We reached next mapping - the line of this form: |
224 | // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME | 231 | // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME |
225 | 232 | ||
226 | if (cb) { | 233 | char *rwx; |
227 | /* If we have a previous record, there's nothing more | 234 | unsigned long sz; |
228 | * for it, call the callback and clear currec | ||
229 | */ | ||
230 | if (currec.smap_size) | ||
231 | cb(&currec, data); | ||
232 | free(currec.smap_name); | ||
233 | } | ||
234 | memset(&currec, 0, sizeof(currec)); | ||
235 | 235 | ||
236 | *tp = ' '; | 236 | *tp = ' '; |
237 | tp = buf; | 237 | tp = buf; |
238 | currec.smap_start = fast_strtoull_16(&tp); | 238 | sz = fast_strtoull_16(&tp); // start |
239 | currec.smap_size = (fast_strtoull_16(&tp) - currec.smap_start) >> 10; | 239 | sz = (fast_strtoull_16(&tp) - sz) >> 10; // end - start |
240 | 240 | // tp -> "rw-s" string | |
241 | strncpy(currec.smap_mode, tp, sizeof(currec.smap_mode)-1); | 241 | rwx = tp; |
242 | |||
243 | // skipping "rw-s FILEOFS M:m INODE " | 242 | // skipping "rw-s FILEOFS M:m INODE " |
244 | tp = skip_whitespace(skip_fields(tp, 4)); | 243 | tp = skip_whitespace(skip_fields(tp, 4)); |
245 | // filter out /dev/something (something != zero) | 244 | // if not a device memory mapped... |
246 | if (!is_prefixed_with(tp, "/dev/") || strcmp(tp, "/dev/zero\n") == 0) { | 245 | if (memcmp(tp, "/dev/", 5) != 0 // not "/dev/something" |
247 | if (currec.smap_mode[1] == 'w') { | 246 | || strcmp(tp + 5, "zero\n") == 0 // or is "/dev/zero" (which isn't a device) |
248 | currec.mapped_rw = currec.smap_size; | 247 | ) { |
249 | total->mapped_rw += currec.smap_size; | 248 | if (rwx[1] == 'w') |
250 | } else if (currec.smap_mode[1] == '-') { | 249 | sp->mapped_rw += sz; |
251 | currec.mapped_ro = currec.smap_size; | 250 | else if (rwx[0] == 'r' || rwx[2] == 'x') |
252 | total->mapped_ro += currec.smap_size; | 251 | sp->mapped_ro += sz; |
253 | } | 252 | // else: seen "---p" mappings (mmap guard gaps?), |
253 | // do NOT account these as VSZ, they aren't really | ||
254 | } | 254 | } |
255 | |||
256 | if (strcmp(tp, "[stack]\n") == 0) | 255 | if (strcmp(tp, "[stack]\n") == 0) |
257 | total->stack += currec.smap_size; | 256 | sp->stack += sz; |
258 | if (cb) { | ||
259 | p = skip_non_whitespace(tp); | ||
260 | if (p == tp) { | ||
261 | currec.smap_name = xstrdup(" [ anon ]"); | ||
262 | } else { | ||
263 | *p = '\0'; | ||
264 | currec.smap_name = xstrdup(tp); | ||
265 | } | ||
266 | } | ||
267 | total->smap_size += currec.smap_size; | ||
268 | } | 257 | } |
269 | } | 258 | } |
270 | fclose(file); | 259 | fclose(file); |
271 | |||
272 | if (cb) { | ||
273 | if (currec.smap_size) | ||
274 | cb(&currec, data); | ||
275 | free(currec.smap_name); | ||
276 | } | ||
277 | |||
278 | return 0; | ||
279 | } | 260 | } |
280 | #endif | 261 | #endif |
281 | 262 | ||
@@ -370,7 +351,8 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |||
370 | char *cp, *comm1; | 351 | char *cp, *comm1; |
371 | int tty; | 352 | int tty; |
372 | #if !ENABLE_FEATURE_FAST_TOP | 353 | #if !ENABLE_FEATURE_FAST_TOP |
373 | unsigned long vsz, rss; | 354 | unsigned long long vsz; |
355 | unsigned long rss; | ||
374 | #endif | 356 | #endif |
375 | /* see proc(5) for some details on this */ | 357 | /* see proc(5) for some details on this */ |
376 | strcpy(filename_tail, "stat"); | 358 | strcpy(filename_tail, "stat"); |
@@ -396,7 +378,7 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |||
396 | "%ld " /* nice */ | 378 | "%ld " /* nice */ |
397 | "%*s %*s " /* timeout, it_real_value */ | 379 | "%*s %*s " /* timeout, it_real_value */ |
398 | "%lu " /* start_time */ | 380 | "%lu " /* start_time */ |
399 | "%lu " /* vsize */ | 381 | "%llu " /* vsize - can be very large */ |
400 | "%lu " /* rss */ | 382 | "%lu " /* rss */ |
401 | # if ENABLE_FEATURE_TOP_SMP_PROCESS | 383 | # if ENABLE_FEATURE_TOP_SMP_PROCESS |
402 | "%*s %*s %*s %*s %*s %*s " /*rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */ | 384 | "%*s %*s %*s %*s %*s %*s " /*rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */ |
@@ -449,7 +431,7 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |||
449 | cp = skip_fields(cp, 2); /* timeout, it_real_value */ | 431 | cp = skip_fields(cp, 2); /* timeout, it_real_value */ |
450 | sp->start_time = fast_strtoul_10(&cp); | 432 | sp->start_time = fast_strtoul_10(&cp); |
451 | /* vsz is in bytes and we want kb */ | 433 | /* vsz is in bytes and we want kb */ |
452 | sp->vsz = fast_strtoul_10(&cp) >> 10; | 434 | sp->vsz = fast_strtoull_10(&cp) >> 10; |
453 | /* vsz is in bytes but rss is in *PAGES*! Can you believe that? */ | 435 | /* vsz is in bytes but rss is in *PAGES*! Can you believe that? */ |
454 | sp->rss = fast_strtoul_10(&cp) << sp->shift_pages_to_kb; | 436 | sp->rss = fast_strtoul_10(&cp) << sp->shift_pages_to_kb; |
455 | # if ENABLE_FEATURE_TOP_SMP_PROCESS | 437 | # if ENABLE_FEATURE_TOP_SMP_PROCESS |
@@ -483,7 +465,7 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |||
483 | 465 | ||
484 | #if ENABLE_FEATURE_TOPMEM | 466 | #if ENABLE_FEATURE_TOPMEM |
485 | if (flags & PSSCAN_SMAPS) | 467 | if (flags & PSSCAN_SMAPS) |
486 | procps_read_smaps(pid, &sp->smaps, NULL, NULL); | 468 | procps_read_smaps(pid, sp); |
487 | #endif /* TOPMEM */ | 469 | #endif /* TOPMEM */ |
488 | #if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS | 470 | #if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS |
489 | if (flags & PSSCAN_RUIDGID) { | 471 | if (flags & PSSCAN_RUIDGID) { |
@@ -566,36 +548,45 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |||
566 | return sp; | 548 | return sp; |
567 | } | 549 | } |
568 | 550 | ||
569 | void FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm) | 551 | int FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm) |
570 | { | 552 | { |
571 | int sz; | 553 | int sz; |
572 | char filename[sizeof("/proc/%u/cmdline") + sizeof(int)*3]; | 554 | char filename[sizeof("/proc/%u/cmdline") + sizeof(int)*3]; |
573 | 555 | ||
574 | sprintf(filename, "/proc/%u/cmdline", pid); | 556 | sprintf(filename, "/proc/%u/cmdline", pid); |
575 | sz = open_read_close(filename, buf, col - 1); | 557 | sz = open_read_close(filename, buf, col - 1); |
558 | if (sz < 0) | ||
559 | return sz; | ||
576 | if (sz > 0) { | 560 | if (sz > 0) { |
577 | const char *base; | 561 | const char *program_basename; |
578 | int comm_len; | 562 | int comm_len; |
579 | 563 | ||
580 | buf[sz] = '\0'; | 564 | buf[sz] = '\0'; |
581 | while (--sz >= 0 && buf[sz] == '\0') | 565 | while (--sz >= 0 && buf[sz] == '\0') |
582 | continue; | 566 | continue; |
583 | /* Prevent basename("process foo/bar") = "bar" */ | 567 | |
584 | strchrnul(buf, ' ')[0] = '\0'; | 568 | /* Find "program" in "[-][/PATH/TO/]program" */ |
585 | base = bb_basename(buf); /* before we replace argv0's NUL with space */ | 569 | strchrnul(buf, ' ')[0] = '\0'; /* prevent basename("program foo/bar") = "bar" */ |
570 | program_basename = bb_basename(buf[0] == '-' ? buf + 1 : buf); | ||
571 | /* ^^^ note: must do it *before* replacing argv0's NUL with space */ | ||
572 | |||
573 | /* Prevent stuff like this: | ||
574 | * echo 'sleep 999; exit' >`printf '\ec'`; sh ?c | ||
575 | * messing up top and ps output (or worse). | ||
576 | * This also replaces NULs with spaces, converting | ||
577 | * list of NUL-strings into one string. | ||
578 | */ | ||
586 | while (sz >= 0) { | 579 | while (sz >= 0) { |
587 | if ((unsigned char)(buf[sz]) < ' ') | 580 | if ((unsigned char)(buf[sz]) < ' ') |
588 | buf[sz] = ' '; | 581 | buf[sz] = ' '; |
589 | sz--; | 582 | sz--; |
590 | } | 583 | } |
591 | if (base[0] == '-') /* "-sh" (login shell)? */ | ||
592 | base++; | ||
593 | 584 | ||
594 | /* If comm differs from argv0, prepend "{comm} ". | 585 | /* If comm differs from argv0, prepend "{comm} ". |
595 | * It allows to see thread names set by prctl(PR_SET_NAME). | 586 | * It allows to see thread names set by prctl(PR_SET_NAME). |
596 | */ | 587 | */ |
597 | if (!comm) | 588 | if (!comm) |
598 | return; | 589 | return 0; |
599 | comm_len = strlen(comm); | 590 | comm_len = strlen(comm); |
600 | /* Why compare up to comm_len, not COMM_LEN-1? | 591 | /* Why compare up to comm_len, not COMM_LEN-1? |
601 | * Well, some processes rewrite argv, and use _spaces_ there | 592 | * Well, some processes rewrite argv, and use _spaces_ there |
@@ -603,19 +594,20 @@ void FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm) | |||
603 | * I prefer to still treat argv0 "process foo bar" | 594 | * I prefer to still treat argv0 "process foo bar" |
604 | * as 'equal' to comm "process". | 595 | * as 'equal' to comm "process". |
605 | */ | 596 | */ |
606 | if (strncmp(base, comm, comm_len) != 0) { | 597 | if (strncmp(program_basename, comm, comm_len) != 0) { |
607 | comm_len += 3; | 598 | comm_len += 3; |
608 | if (col > comm_len) | 599 | if (col > comm_len) |
609 | memmove(buf + comm_len, buf, col - comm_len); | 600 | memmove(buf + comm_len, buf, col - comm_len); |
610 | snprintf(buf, col, "{%s}", comm); | 601 | snprintf(buf, col, "{%s}", comm); |
611 | if (col <= comm_len) | 602 | if (col <= comm_len) |
612 | return; | 603 | return 0; |
613 | buf[comm_len - 1] = ' '; | 604 | buf[comm_len - 1] = ' '; |
614 | buf[col - 1] = '\0'; | 605 | buf[col - 1] = '\0'; |
615 | } | 606 | } |
616 | } else { | 607 | } else { |
617 | snprintf(buf, col, "[%s]", comm ? comm : "?"); | 608 | snprintf(buf, col, "[%s]", comm ? comm : "?"); |
618 | } | 609 | } |
610 | return 0; | ||
619 | } | 611 | } |
620 | 612 | ||
621 | /* from kernel: | 613 | /* from kernel: |
diff --git a/libbb/pw_ascii64.c b/libbb/pw_ascii64.c new file mode 100644 index 000000000..3993932ca --- /dev/null +++ b/libbb/pw_ascii64.c | |||
@@ -0,0 +1,91 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Utility routines. | ||
4 | * | ||
5 | * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> | ||
6 | * | ||
7 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. | ||
8 | */ | ||
9 | |||
10 | /* Returns >=64 for invalid chars */ | ||
11 | int FAST_FUNC a2i64(char c) | ||
12 | { | ||
13 | unsigned char ch = c; | ||
14 | if (ch >= 'a') | ||
15 | /* "a..z" to 38..63 */ | ||
16 | /* anything after "z": positive int >= 64 */ | ||
17 | return (ch - 'a' + 38); | ||
18 | |||
19 | if (ch > 'Z') | ||
20 | /* after "Z" but before "a": positive byte >= 64 */ | ||
21 | return ch; | ||
22 | |||
23 | if (ch >= 'A') | ||
24 | /* "A..Z" to 12..37 */ | ||
25 | return (ch - 'A' + 12); | ||
26 | |||
27 | if (ch > '9') | ||
28 | return 64; | ||
29 | |||
30 | /* "./0123456789" to 0,1,2..11 */ | ||
31 | /* anything before "." becomes positive byte >= 64 */ | ||
32 | return (unsigned char)(ch - '.'); | ||
33 | } | ||
34 | |||
35 | /* 0..63 -> | ||
36 | * "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; | ||
37 | */ | ||
38 | int FAST_FUNC i2a64(int i) | ||
39 | { | ||
40 | i &= 0x3f; | ||
41 | |||
42 | i += '.'; | ||
43 | /* the above maps 0..11 to "./0123456789": | ||
44 | * ACSII codes of "./" are ('0'-2) and ('0'-1) */ | ||
45 | |||
46 | if (i > '9') | ||
47 | i += ('A' - '9' - 1); | ||
48 | if (i > 'Z') | ||
49 | i += ('a' - 'Z' - 1); | ||
50 | return i; | ||
51 | } | ||
52 | |||
53 | char* FAST_FUNC | ||
54 | num2str64_lsb_first(char *s, unsigned v, int n) | ||
55 | { | ||
56 | while (--n >= 0) { | ||
57 | *s++ = i2a64(v); | ||
58 | v >>= 6; | ||
59 | } | ||
60 | return s; | ||
61 | } | ||
62 | |||
63 | static void | ||
64 | num2str64_4chars_msb_first(char *s, unsigned v) | ||
65 | { | ||
66 | *s++ = i2a64(v >> 18); /* bits 23..18 */ | ||
67 | *s++ = i2a64(v >> 12); /* bits 17..12 */ | ||
68 | *s++ = i2a64(v >> 6); /* bits 11..6 */ | ||
69 | *s = i2a64(v); /* bits 5..0 */ | ||
70 | } | ||
71 | |||
72 | int FAST_FUNC crypt_make_rand64encoded(char *p, int cnt /*, int x */) | ||
73 | { | ||
74 | /* was: x += ... */ | ||
75 | unsigned x = getpid() + monotonic_us(); | ||
76 | do { | ||
77 | /* x = (x*1664525 + 1013904223) % 2^32 generator is lame | ||
78 | * (low-order bit is not "random", etc...), | ||
79 | * but for our purposes it is good enough */ | ||
80 | x = x*1664525 + 1013904223; | ||
81 | /* BTW, Park and Miller's "minimal standard generator" is | ||
82 | * x = x*16807 % ((2^31)-1) | ||
83 | * It has no problem with visibly alternating lowest bit | ||
84 | * but is also weak in cryptographic sense + needs div, | ||
85 | * which needs more code (and slower) on many CPUs */ | ||
86 | *p++ = i2a64(x >> 16); | ||
87 | *p++ = i2a64(x >> 22); | ||
88 | } while (--cnt); | ||
89 | *p = '\0'; | ||
90 | return x; | ||
91 | } | ||
diff --git a/libbb/pw_encrypt.c b/libbb/pw_encrypt.c index 3463fd95b..93653de9f 100644 --- a/libbb/pw_encrypt.c +++ b/libbb/pw_encrypt.c | |||
@@ -13,48 +13,11 @@ | |||
13 | #endif | 13 | #endif |
14 | #include "libbb.h" | 14 | #include "libbb.h" |
15 | 15 | ||
16 | /* static const uint8_t ascii64[] ALIGN1 = | 16 | #include "pw_ascii64.c" |
17 | * "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; | ||
18 | */ | ||
19 | |||
20 | static int i64c(int i) | ||
21 | { | ||
22 | i &= 0x3f; | ||
23 | if (i == 0) | ||
24 | return '.'; | ||
25 | if (i == 1) | ||
26 | return '/'; | ||
27 | if (i < 12) | ||
28 | return ('0' - 2 + i); | ||
29 | if (i < 38) | ||
30 | return ('A' - 12 + i); | ||
31 | return ('a' - 38 + i); | ||
32 | } | ||
33 | |||
34 | int FAST_FUNC crypt_make_salt(char *p, int cnt /*, int x */) | ||
35 | { | ||
36 | /* was: x += ... */ | ||
37 | unsigned x = getpid() + monotonic_us(); | ||
38 | do { | ||
39 | /* x = (x*1664525 + 1013904223) % 2^32 generator is lame | ||
40 | * (low-order bit is not "random", etc...), | ||
41 | * but for our purposes it is good enough */ | ||
42 | x = x*1664525 + 1013904223; | ||
43 | /* BTW, Park and Miller's "minimal standard generator" is | ||
44 | * x = x*16807 % ((2^31)-1) | ||
45 | * It has no problem with visibly alternating lowest bit | ||
46 | * but is also weak in cryptographic sense + needs div, | ||
47 | * which needs more code (and slower) on many CPUs */ | ||
48 | *p++ = i64c(x >> 16); | ||
49 | *p++ = i64c(x >> 22); | ||
50 | } while (--cnt); | ||
51 | *p = '\0'; | ||
52 | return x; | ||
53 | } | ||
54 | 17 | ||
55 | char* FAST_FUNC crypt_make_pw_salt(char salt[MAX_PW_SALT_LEN], const char *algo) | 18 | char* FAST_FUNC crypt_make_pw_salt(char salt[MAX_PW_SALT_LEN], const char *algo) |
56 | { | 19 | { |
57 | int len = 2/2; | 20 | int len = 2 / 2; |
58 | char *salt_ptr = salt; | 21 | char *salt_ptr = salt; |
59 | 22 | ||
60 | /* Standard chpasswd uses uppercase algos ("MD5", not "md5"). | 23 | /* Standard chpasswd uses uppercase algos ("MD5", not "md5"). |
@@ -67,28 +30,61 @@ char* FAST_FUNC crypt_make_pw_salt(char salt[MAX_PW_SALT_LEN], const char *algo) | |||
67 | *salt_ptr++ = '$'; | 30 | *salt_ptr++ = '$'; |
68 | #if !ENABLE_USE_BB_CRYPT || ENABLE_USE_BB_CRYPT_SHA | 31 | #if !ENABLE_USE_BB_CRYPT || ENABLE_USE_BB_CRYPT_SHA |
69 | if ((algo[0]|0x20) == 's') { /* sha */ | 32 | if ((algo[0]|0x20) == 's') { /* sha */ |
70 | salt[1] = '5' + (strcasecmp(algo, "sha512") == 0); | 33 | salt[1] = '5' + (strncasecmp(algo, "sha512", 6) == 0); |
71 | len = 16/2; | 34 | len = 16 / 2; |
35 | } | ||
36 | #endif | ||
37 | #if !ENABLE_USE_BB_CRYPT || ENABLE_USE_BB_CRYPT_YES | ||
38 | if ((algo[0]|0x20) == 'y') { /* yescrypt */ | ||
39 | int rnd; | ||
40 | salt[1] = 'y'; | ||
41 | // The "j9T$" below is the default "yescrypt parameters" encoded by yescrypt_encode_params_r(): | ||
42 | //shadow-4.17.4/src/passwd.c | ||
43 | // salt = crypt_make_salt(NULL, NULL); | ||
44 | //shadow-4.17.4/lib/salt.c | ||
45 | //const char *crypt_make_salt(const char *meth, void *arg) | ||
46 | // if (streq(method, "YESCRYPT")) { | ||
47 | // MAGNUM(result, 'y'); | ||
48 | // salt_len = YESCRYPT_SALT_SIZE; // 24 | ||
49 | // rounds = YESCRYPT_get_salt_cost(arg); // always Y_COST_DEFAULT == 5 for NULL arg | ||
50 | // YESCRYPT_salt_cost_to_buf(result, rounds); // always "j9T$" | ||
51 | // char *retval = crypt_gensalt(result, rounds, NULL, 0); | ||
52 | //libxcrypt-4.4.38/lib/crypt-yescrypt.c | ||
53 | //void gensalt_yescrypt_rn (unsigned long count, | ||
54 | // const uint8_t *rbytes, size_t nrbytes, | ||
55 | // uint8_t *output, size_t o_size) | ||
56 | // yescrypt_params_t params = { | ||
57 | // .flags = YESCRYPT_DEFAULTS, | ||
58 | // .p = 1, | ||
59 | // }; | ||
60 | // if (count < 3) ... else | ||
61 | // params.r = 32; // N in 4KiB | ||
62 | // params.N = 1ULL << (count + 7); // 3 -> 1024, 4 -> 2048, ... 11 -> 262144 | ||
63 | // yescrypt_encode_params_r(¶ms, rbytes, nrbytes, outbuf, o_size) // always "$y$j9T$<random>" | ||
64 | len = 22 / 2; | ||
65 | salt_ptr = stpcpy(salt_ptr, "j9T$"); | ||
66 | /* append 2*len random chars */ | ||
67 | rnd = crypt_make_rand64encoded(salt_ptr, len); | ||
68 | /* fix up last char: it must be in 0..3 range (encoded as one of "./01"). | ||
69 | * IOW: salt_ptr[20..21] encode 16th random byte, must not be > 0xff. | ||
70 | * Without this, we can generate salts which are rejected | ||
71 | * by implementations with more strict salt length check. | ||
72 | */ | ||
73 | salt_ptr[21] = i2a64(rnd & 3); | ||
74 | /* For "mkpasswd -m yescrypt PASS j9T$<salt>" use case, | ||
75 | * "j9T$" is considered part of salt, | ||
76 | * need to return pointer to 'j'. Without -4, | ||
77 | * we'd end up using "j9T$j9T$<salt>" as salt. | ||
78 | */ | ||
79 | return salt_ptr - 4; | ||
72 | } | 80 | } |
73 | #endif | 81 | #endif |
74 | } | 82 | } |
75 | crypt_make_salt(salt_ptr, len); | 83 | crypt_make_rand64encoded(salt_ptr, len); /* appends 2*len random chars */ |
76 | return salt_ptr; | 84 | return salt_ptr; |
77 | } | 85 | } |
78 | 86 | ||
79 | #if ENABLE_USE_BB_CRYPT | 87 | #if ENABLE_USE_BB_CRYPT |
80 | |||
81 | static char* | ||
82 | to64(char *s, unsigned v, int n) | ||
83 | { | ||
84 | while (--n >= 0) { | ||
85 | /* *s++ = ascii64[v & 0x3f]; */ | ||
86 | *s++ = i64c(v); | ||
87 | v >>= 6; | ||
88 | } | ||
89 | return s; | ||
90 | } | ||
91 | |||
92 | /* | 88 | /* |
93 | * DES and MD5 crypt implementations are taken from uclibc. | 89 | * DES and MD5 crypt implementations are taken from uclibc. |
94 | * They were modified to not use static buffers. | 90 | * They were modified to not use static buffers. |
@@ -99,6 +95,9 @@ to64(char *s, unsigned v, int n) | |||
99 | #if ENABLE_USE_BB_CRYPT_SHA | 95 | #if ENABLE_USE_BB_CRYPT_SHA |
100 | #include "pw_encrypt_sha.c" | 96 | #include "pw_encrypt_sha.c" |
101 | #endif | 97 | #endif |
98 | #if ENABLE_USE_BB_CRYPT_YES | ||
99 | #include "pw_encrypt_yes.c" | ||
100 | #endif | ||
102 | 101 | ||
103 | /* Other advanced crypt ids (TODO?): */ | 102 | /* Other advanced crypt ids (TODO?): */ |
104 | /* $2$ or $2a$: Blowfish */ | 103 | /* $2$ or $2a$: Blowfish */ |
@@ -109,7 +108,7 @@ static struct des_ctx *des_ctx; | |||
109 | /* my_crypt returns malloc'ed data */ | 108 | /* my_crypt returns malloc'ed data */ |
110 | static char *my_crypt(const char *key, const char *salt) | 109 | static char *my_crypt(const char *key, const char *salt) |
111 | { | 110 | { |
112 | /* MD5 or SHA? */ | 111 | /* "$x$...." string? */ |
113 | if (salt[0] == '$' && salt[1] && salt[2] == '$') { | 112 | if (salt[0] == '$' && salt[1] && salt[2] == '$') { |
114 | if (salt[1] == '1') | 113 | if (salt[1] == '1') |
115 | return md5_crypt(xzalloc(MD5_OUT_BUFSIZE), (unsigned char*)key, (unsigned char*)salt); | 114 | return md5_crypt(xzalloc(MD5_OUT_BUFSIZE), (unsigned char*)key, (unsigned char*)salt); |
@@ -117,6 +116,10 @@ static char *my_crypt(const char *key, const char *salt) | |||
117 | if (salt[1] == '5' || salt[1] == '6') | 116 | if (salt[1] == '5' || salt[1] == '6') |
118 | return sha_crypt((char*)key, (char*)salt); | 117 | return sha_crypt((char*)key, (char*)salt); |
119 | #endif | 118 | #endif |
119 | #if ENABLE_USE_BB_CRYPT_YES | ||
120 | if (salt[1] == 'y') | ||
121 | return yes_crypt(key, salt); | ||
122 | #endif | ||
120 | } | 123 | } |
121 | 124 | ||
122 | if (!des_cctx) | 125 | if (!des_cctx) |
diff --git a/libbb/pw_encrypt_des.c b/libbb/pw_encrypt_des.c index fe8237cfe..ca8aa9bcc 100644 --- a/libbb/pw_encrypt_des.c +++ b/libbb/pw_encrypt_des.c | |||
@@ -186,39 +186,9 @@ static const uint8_t pbox[32] ALIGN1 = { | |||
186 | 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25 | 186 | 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25 |
187 | }; | 187 | }; |
188 | 188 | ||
189 | static const uint32_t bits32[32] ALIGN4 = { | ||
190 | 0x80000000, 0x40000000, 0x20000000, 0x10000000, | ||
191 | 0x08000000, 0x04000000, 0x02000000, 0x01000000, | ||
192 | 0x00800000, 0x00400000, 0x00200000, 0x00100000, | ||
193 | 0x00080000, 0x00040000, 0x00020000, 0x00010000, | ||
194 | 0x00008000, 0x00004000, 0x00002000, 0x00001000, | ||
195 | 0x00000800, 0x00000400, 0x00000200, 0x00000100, | ||
196 | 0x00000080, 0x00000040, 0x00000020, 0x00000010, | ||
197 | 0x00000008, 0x00000004, 0x00000002, 0x00000001 | ||
198 | }; | ||
199 | |||
200 | static const uint8_t bits8[8] ALIGN1 = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; | 189 | static const uint8_t bits8[8] ALIGN1 = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; |
201 | 190 | ||
202 | 191 | ||
203 | static int | ||
204 | ascii_to_bin(char ch) | ||
205 | { | ||
206 | if (ch > 'z') | ||
207 | return 0; | ||
208 | if (ch >= 'a') | ||
209 | return (ch - 'a' + 38); | ||
210 | if (ch > 'Z') | ||
211 | return 0; | ||
212 | if (ch >= 'A') | ||
213 | return (ch - 'A' + 12); | ||
214 | if (ch > '9') | ||
215 | return 0; | ||
216 | if (ch >= '.') | ||
217 | return (ch - '.'); | ||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | |||
222 | /* Static stuff that stays resident and doesn't change after | 192 | /* Static stuff that stays resident and doesn't change after |
223 | * being initialized, and therefore doesn't need to be made | 193 | * being initialized, and therefore doesn't need to be made |
224 | * reentrant. */ | 194 | * reentrant. */ |
@@ -354,11 +324,18 @@ des_init(struct des_ctx *ctx, const struct const_des_ctx *cctx) | |||
354 | int i, j, b, k, inbit, obit; | 324 | int i, j, b, k, inbit, obit; |
355 | uint32_t p; | 325 | uint32_t p; |
356 | const uint32_t *bits28, *bits24; | 326 | const uint32_t *bits28, *bits24; |
327 | uint32_t bits32[32]; | ||
357 | 328 | ||
358 | if (!ctx) | 329 | if (!ctx) |
359 | ctx = xmalloc(sizeof(*ctx)); | 330 | ctx = xmalloc(sizeof(*ctx)); |
360 | const_ctx = cctx; | 331 | const_ctx = cctx; |
361 | 332 | ||
333 | p = 0x80000000U; | ||
334 | for (i = 0; p; i++) { | ||
335 | bits32[i] = p; | ||
336 | p >>= 1; | ||
337 | } | ||
338 | |||
362 | #if USE_REPETITIVE_SPEEDUP | 339 | #if USE_REPETITIVE_SPEEDUP |
363 | old_rawkey0 = old_rawkey1 = 0; | 340 | old_rawkey0 = old_rawkey1 = 0; |
364 | old_salt = 0; | 341 | old_salt = 0; |
@@ -694,21 +671,6 @@ do_des(struct des_ctx *ctx, /*uint32_t l_in, uint32_t r_in,*/ uint32_t *l_out, u | |||
694 | 671 | ||
695 | #define DES_OUT_BUFSIZE 21 | 672 | #define DES_OUT_BUFSIZE 21 |
696 | 673 | ||
697 | static void | ||
698 | to64_msb_first(char *s, unsigned v) | ||
699 | { | ||
700 | #if 0 | ||
701 | *s++ = ascii64[(v >> 18) & 0x3f]; /* bits 23..18 */ | ||
702 | *s++ = ascii64[(v >> 12) & 0x3f]; /* bits 17..12 */ | ||
703 | *s++ = ascii64[(v >> 6) & 0x3f]; /* bits 11..6 */ | ||
704 | *s = ascii64[v & 0x3f]; /* bits 5..0 */ | ||
705 | #endif | ||
706 | *s++ = i64c(v >> 18); /* bits 23..18 */ | ||
707 | *s++ = i64c(v >> 12); /* bits 17..12 */ | ||
708 | *s++ = i64c(v >> 6); /* bits 11..6 */ | ||
709 | *s = i64c(v); /* bits 5..0 */ | ||
710 | } | ||
711 | |||
712 | static char * | 674 | static char * |
713 | NOINLINE | 675 | NOINLINE |
714 | des_crypt(struct des_ctx *ctx, char output[DES_OUT_BUFSIZE], | 676 | des_crypt(struct des_ctx *ctx, char output[DES_OUT_BUFSIZE], |
@@ -740,44 +702,28 @@ des_crypt(struct des_ctx *ctx, char output[DES_OUT_BUFSIZE], | |||
740 | */ | 702 | */ |
741 | output[0] = salt_str[0]; | 703 | output[0] = salt_str[0]; |
742 | output[1] = salt_str[1]; | 704 | output[1] = salt_str[1]; |
743 | salt = (ascii_to_bin(salt_str[1]) << 6) | 705 | |
744 | | ascii_to_bin(salt_str[0]); | 706 | salt = a2i64(salt_str[0]); |
707 | if (salt >= 64) | ||
708 | return NULL; /* bad salt char */ | ||
709 | salt |= (a2i64(salt_str[1]) << 6); | ||
710 | if (salt >= (64 << 6)) | ||
711 | return NULL; /* bad salt char */ | ||
745 | setup_salt(ctx, salt); /* set ctx->saltbits for do_des() */ | 712 | setup_salt(ctx, salt); /* set ctx->saltbits for do_des() */ |
746 | 713 | ||
747 | /* Do it. */ | 714 | /* Do it. */ |
748 | do_des(ctx, /*0, 0,*/ &r0, &r1, 25 /* count */); | 715 | do_des(ctx, /*0, 0,*/ &r0, &r1, 25 /* count */); |
749 | 716 | ||
750 | /* Now encode the result. */ | 717 | /* Now encode the result. */ |
751 | #if 0 | ||
752 | { | ||
753 | uint32_t l = (r0 >> 8); | ||
754 | q = (uint8_t *)output + 2; | ||
755 | *q++ = ascii64[(l >> 18) & 0x3f]; /* bits 31..26 of r0 */ | ||
756 | *q++ = ascii64[(l >> 12) & 0x3f]; /* bits 25..20 of r0 */ | ||
757 | *q++ = ascii64[(l >> 6) & 0x3f]; /* bits 19..14 of r0 */ | ||
758 | *q++ = ascii64[l & 0x3f]; /* bits 13..8 of r0 */ | ||
759 | l = ((r0 << 16) | (r1 >> 16)); | ||
760 | *q++ = ascii64[(l >> 18) & 0x3f]; /* bits 7..2 of r0 */ | ||
761 | *q++ = ascii64[(l >> 12) & 0x3f]; /* bits 1..2 of r0 and 31..28 of r1 */ | ||
762 | *q++ = ascii64[(l >> 6) & 0x3f]; /* bits 27..22 of r1 */ | ||
763 | *q++ = ascii64[l & 0x3f]; /* bits 21..16 of r1 */ | ||
764 | l = r1 << 2; | ||
765 | *q++ = ascii64[(l >> 12) & 0x3f]; /* bits 15..10 of r1 */ | ||
766 | *q++ = ascii64[(l >> 6) & 0x3f]; /* bits 9..4 of r1 */ | ||
767 | *q++ = ascii64[l & 0x3f]; /* bits 3..0 of r1 + 00 */ | ||
768 | *q = 0; | ||
769 | } | ||
770 | #else | ||
771 | /* Each call takes low-order 24 bits and stores 4 chars */ | 718 | /* Each call takes low-order 24 bits and stores 4 chars */ |
772 | /* bits 31..8 of r0 */ | 719 | /* bits 31..8 of r0 */ |
773 | to64_msb_first(output + 2, (r0 >> 8)); | 720 | num2str64_4chars_msb_first(output + 2, (r0 >> 8)); |
774 | /* bits 7..0 of r0 and 31..16 of r1 */ | 721 | /* bits 7..0 of r0 and 31..16 of r1 */ |
775 | to64_msb_first(output + 6, (r0 << 16) | (r1 >> 16)); | 722 | num2str64_4chars_msb_first(output + 6, (r0 << 16) | (r1 >> 16)); |
776 | /* bits 15..0 of r1 and two zero bits (plus extra zero byte) */ | 723 | /* bits 15..0 of r1 and two zero bits (plus extra zero byte) */ |
777 | to64_msb_first(output + 10, (r1 << 8)); | 724 | num2str64_4chars_msb_first(output + 10, (r1 << 8)); |
778 | /* extra zero byte is encoded as '.', fixing it */ | 725 | /* extra zero byte is encoded as '.', fixing it */ |
779 | output[13] = '\0'; | 726 | output[13] = '\0'; |
780 | #endif | ||
781 | 727 | ||
782 | return output; | 728 | return output; |
783 | } | 729 | } |
diff --git a/libbb/pw_encrypt_md5.c b/libbb/pw_encrypt_md5.c index 1e52ecaea..92d039f96 100644 --- a/libbb/pw_encrypt_md5.c +++ b/libbb/pw_encrypt_md5.c | |||
@@ -149,9 +149,9 @@ md5_crypt(char result[MD5_OUT_BUFSIZE], const unsigned char *pw, const unsigned | |||
149 | final[16] = final[5]; | 149 | final[16] = final[5]; |
150 | for (i = 0; i < 5; i++) { | 150 | for (i = 0; i < 5; i++) { |
151 | unsigned l = (final[i] << 16) | (final[i+6] << 8) | final[i+12]; | 151 | unsigned l = (final[i] << 16) | (final[i+6] << 8) | final[i+12]; |
152 | p = to64(p, l, 4); | 152 | p = num2str64_lsb_first(p, l, 4); |
153 | } | 153 | } |
154 | p = to64(p, final[11], 2); | 154 | p = num2str64_lsb_first(p, final[11], 2); |
155 | *p = '\0'; | 155 | *p = '\0'; |
156 | 156 | ||
157 | /* Don't leave anything around in vm they could use. */ | 157 | /* Don't leave anything around in vm they could use. */ |
diff --git a/libbb/pw_encrypt_sha.c b/libbb/pw_encrypt_sha.c index 5457d7ab6..695a5c07f 100644 --- a/libbb/pw_encrypt_sha.c +++ b/libbb/pw_encrypt_sha.c | |||
@@ -84,8 +84,7 @@ sha_crypt(/*const*/ char *key_data, /*const*/ char *salt_data) | |||
84 | as a scratch space later. */ | 84 | as a scratch space later. */ |
85 | salt_data = xstrndup(salt_data, salt_len); | 85 | salt_data = xstrndup(salt_data, salt_len); |
86 | /* add "salt$" to result */ | 86 | /* add "salt$" to result */ |
87 | strcpy(resptr, salt_data); | 87 | resptr = stpcpy(resptr, salt_data); |
88 | resptr += salt_len; | ||
89 | *resptr++ = '$'; | 88 | *resptr++ = '$'; |
90 | /* key data doesn't need much processing */ | 89 | /* key data doesn't need much processing */ |
91 | key_len = strlen(key_data); | 90 | key_len = strlen(key_data); |
@@ -198,7 +197,7 @@ sha_crypt(/*const*/ char *key_data, /*const*/ char *salt_data) | |||
198 | #define b64_from_24bit(B2, B1, B0, N) \ | 197 | #define b64_from_24bit(B2, B1, B0, N) \ |
199 | do { \ | 198 | do { \ |
200 | unsigned w = ((B2) << 16) | ((B1) << 8) | (B0); \ | 199 | unsigned w = ((B2) << 16) | ((B1) << 8) | (B0); \ |
201 | resptr = to64(resptr, w, N); \ | 200 | resptr = num2str64_lsb_first(resptr, w, N); \ |
202 | } while (0) | 201 | } while (0) |
203 | if (_32or64 == 32) { /* sha256 */ | 202 | if (_32or64 == 32) { /* sha256 */ |
204 | unsigned i = 0; | 203 | unsigned i = 0; |
diff --git a/libbb/pw_encrypt_yes.c b/libbb/pw_encrypt_yes.c new file mode 100644 index 000000000..50bd06418 --- /dev/null +++ b/libbb/pw_encrypt_yes.c | |||
@@ -0,0 +1,24 @@ | |||
1 | /* | ||
2 | * Utility routines. | ||
3 | * | ||
4 | * Copyright (C) 2025 by Denys Vlasenko <vda.linux@googlemail.com> | ||
5 | * | ||
6 | * Licensed under GPLv2, see file LICENSE in this source tree. | ||
7 | */ | ||
8 | #include "yescrypt/alg-yescrypt.h" | ||
9 | |||
10 | static char * | ||
11 | yes_crypt(const char *passwd, const char *salt_data) | ||
12 | { | ||
13 | /* prefix, '$', hash, NUL */ | ||
14 | char buf[YESCRYPT_PREFIX_LEN + 1 + YESCRYPT_HASH_LEN + 1]; | ||
15 | char *retval; | ||
16 | |||
17 | retval = yescrypt_r( | ||
18 | (const uint8_t *)passwd, strlen(passwd), | ||
19 | (const uint8_t *)salt_data, | ||
20 | buf, sizeof(buf)); | ||
21 | /* The returned value is either buf[], or NULL on error */ | ||
22 | |||
23 | return xstrdup(retval); | ||
24 | } | ||
diff --git a/libbb/read_key.c b/libbb/read_key.c index cf8ed411e..3df9769f7 100644 --- a/libbb/read_key.c +++ b/libbb/read_key.c | |||
@@ -11,7 +11,7 @@ | |||
11 | 11 | ||
12 | int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout) | 12 | int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout) |
13 | { | 13 | { |
14 | struct pollfd pfd; | 14 | struct pollfd pfd[1]; |
15 | const char *seq; | 15 | const char *seq; |
16 | int n; | 16 | int n; |
17 | 17 | ||
@@ -112,8 +112,8 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout) | |||
112 | 0 | 112 | 0 |
113 | }; | 113 | }; |
114 | 114 | ||
115 | pfd.fd = fd; | 115 | pfd->fd = fd; |
116 | pfd.events = POLLIN; | 116 | pfd->events = POLLIN; |
117 | 117 | ||
118 | buffer++; /* saved chars counter is in buffer[-1] now */ | 118 | buffer++; /* saved chars counter is in buffer[-1] now */ |
119 | 119 | ||
@@ -121,12 +121,16 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout) | |||
121 | errno = 0; | 121 | errno = 0; |
122 | n = (unsigned char)buffer[-1]; | 122 | n = (unsigned char)buffer[-1]; |
123 | if (n == 0) { | 123 | if (n == 0) { |
124 | /* If no data, wait for input. | 124 | /* No data. Wait for input. */ |
125 | * If requested, wait TIMEOUT ms. TIMEOUT = -1 is useful | 125 | |
126 | * if fd can be in non-blocking mode. | 126 | /* timeout == -2 means "do not poll". Else: */ |
127 | */ | ||
128 | if (timeout >= -1) { | 127 | if (timeout >= -1) { |
129 | n = poll(&pfd, 1, timeout); | 128 | /* We must poll even if timeout == -1: |
129 | * we want to be interrupted if signal arrives, | ||
130 | * regardless of SA_RESTART-ness of that signal! | ||
131 | */ | ||
132 | /* test bb_got_signal, then poll(), atomically wrt signals */ | ||
133 | n = check_got_signal_and_poll(pfd, timeout); | ||
130 | if (n < 0 && errno == EINTR) | 134 | if (n < 0 && errno == EINTR) |
131 | return n; | 135 | return n; |
132 | if (n == 0) { | 136 | if (n == 0) { |
@@ -135,6 +139,7 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout) | |||
135 | return -1; | 139 | return -1; |
136 | } | 140 | } |
137 | } | 141 | } |
142 | |||
138 | /* It is tempting to read more than one byte here, | 143 | /* It is tempting to read more than one byte here, |
139 | * but it breaks pasting. Example: at shell prompt, | 144 | * but it breaks pasting. Example: at shell prompt, |
140 | * user presses "c","a","t" and then pastes "\nline\n". | 145 | * user presses "c","a","t" and then pastes "\nline\n". |
@@ -173,7 +178,7 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout) | |||
173 | * so if we block for long it's not really an escape sequence. | 178 | * so if we block for long it's not really an escape sequence. |
174 | * Timeout is needed to reconnect escape sequences | 179 | * Timeout is needed to reconnect escape sequences |
175 | * split up by transmission over a serial console. */ | 180 | * split up by transmission over a serial console. */ |
176 | if (safe_poll(&pfd, 1, 50) == 0) { | 181 | if (safe_poll(pfd, 1, 50) == 0) { |
177 | /* No more data! | 182 | /* No more data! |
178 | * Array is sorted from shortest to longest, | 183 | * Array is sorted from shortest to longest, |
179 | * we can't match anything later in array - | 184 | * we can't match anything later in array - |
@@ -222,7 +227,7 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout) | |||
222 | * n = bytes read. Try to read more until we time out. | 227 | * n = bytes read. Try to read more until we time out. |
223 | */ | 228 | */ |
224 | while (n < KEYCODE_BUFFER_SIZE-1) { /* 1 for count byte at buffer[-1] */ | 229 | while (n < KEYCODE_BUFFER_SIZE-1) { /* 1 for count byte at buffer[-1] */ |
225 | if (safe_poll(&pfd, 1, 50) == 0) { | 230 | if (safe_poll(pfd, 1, 50) == 0) { |
226 | /* No more data! */ | 231 | /* No more data! */ |
227 | break; | 232 | break; |
228 | } | 233 | } |
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/Kbuild.src b/libbb/yescrypt/Kbuild.src new file mode 100644 index 000000000..a61211a29 --- /dev/null +++ b/libbb/yescrypt/Kbuild.src | |||
@@ -0,0 +1,9 @@ | |||
1 | # Makefile for busybox | ||
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 | lib-y:= | ||
8 | |||
9 | INSERT | ||
diff --git a/libbb/yescrypt/PARAMETERS b/libbb/yescrypt/PARAMETERS new file mode 100644 index 000000000..d9f5d24e6 --- /dev/null +++ b/libbb/yescrypt/PARAMETERS | |||
@@ -0,0 +1,196 @@ | |||
1 | Optimal yescrypt configuration. | ||
2 | |||
3 | yescrypt is very flexible, but configuring it optimally is complicated. | ||
4 | Here are some guidelines to simplify near-optimal configuration. We | ||
5 | start by listing the parameters and their typical values, and then give | ||
6 | currently recommended parameter sets by use case. | ||
7 | |||
8 | |||
9 | Parameters and their typical values. | ||
10 | |||
11 | Set flags (yescrypt flavor) to YESCRYPT_DEFAULTS to use the currently | ||
12 | recommended flavor. (Other flags values exist for compatibility and for | ||
13 | specialized cases where you think you know what you're doing.) | ||
14 | |||
15 | Set N (block count) based on target memory usage and running time, as | ||
16 | well as on the value of r (block size in 128 byte units). N must be a | ||
17 | power of two. | ||
18 | |||
19 | Set r (block size) to 8 (so that N is in KiB, which is convenient) or to | ||
20 | another small value (if more optimal or for fine-tuning of the total | ||
21 | size and/or running time). Reasonable values for r are from 8 to 96. | ||
22 | |||
23 | Set p (parallelism) to 1 meaning no thread-level parallelism within one | ||
24 | computation of yescrypt. (Use of thread-level parallelism within | ||
25 | yescrypt makes sense for ROM initialization and for key derivation at | ||
26 | high memory usage, but usually not for password hashing where | ||
27 | parallelism is available through concurrent authentication attempts. | ||
28 | Don't use p > 1 unnecessarily.) | ||
29 | |||
30 | Set t (time) to 0 to use the optimal running time for a given memory | ||
31 | usage. This will allow you to maximize the memory usage (the value of | ||
32 | N*r) while staying within your running time constraints. (Non-zero t | ||
33 | makes sense in specialized cases where you can't afford higher memory | ||
34 | usage but can afford more time.) | ||
35 | |||
36 | Set g (upgrades) to 0 because there have been no hash upgrades yet. | ||
37 | |||
38 | Set NROM (block count of ROM) to 0 unless you use a ROM (see below). | ||
39 | NROM must be a power of two. | ||
40 | |||
41 | |||
42 | Password hashing for user authentication, no ROM. | ||
43 | |||
44 | Small and fast (memory usage 2 MiB, performance like bcrypt cost 2^5 - | ||
45 | latency 2-3 ms and throughput 10,000+ per second on a 16-core server): | ||
46 | |||
47 | flags = YESCRYPT_DEFAULTS, N = 2048, r = 8, p = 1, t = 0, g = 0, NROM = 0 | ||
48 | |||
49 | Large and slow (memory usage 16 MiB, performance like bcrypt cost 2^8 - | ||
50 | latency 10-30 ms and throughput 1000+ per second on a 16-core server): | ||
51 | |||
52 | flags = YESCRYPT_DEFAULTS, N = 4096, r = 32, p = 1, t = 0, g = 0, NROM = 0 | ||
53 | |||
54 | Of course, even heavier and slower settings are possible, if affordable. | ||
55 | Simply double the value of N as many times as needed. Since N must be a | ||
56 | power of two, you may use r (in the range of 8 to 32) or/and t (in the | ||
57 | range of 0 to 2) for fine-tuning the running time, but first bring N to | ||
58 | the maximum you can afford. If this feels too complicated, just use one | ||
59 | of the two parameter sets given above (preferably the second) as-is. | ||
60 | |||
61 | |||
62 | Password hashing for user authentication, with ROM. | ||
63 | |||
64 | It's similar to the above, except that you need to adjust r, set NROM, | ||
65 | and initialize the ROM. | ||
66 | |||
67 | First decide on a ROM size, such as making it a large portion of your | ||
68 | dedicated authentication servers' RAM sizes. Since NROM (block count) | ||
69 | must be a power of two, you might need to choose r (block size) based on | ||
70 | how your desired ROM size corresponds to a power of two. Also tuning | ||
71 | for performance on current hardware, you'll likely end up with r in the | ||
72 | range from slightly below 16 to 32. For example, to use 15/16 of a | ||
73 | server's 256 GiB RAM as ROM (thus, making it 240 GiB), you could use | ||
74 | r=15 or r=30. To use 23/24 of a server's 384 GiB RAM as ROM (thus, | ||
75 | making it 368 GiB), you'd use r=23. Then set NROM to your desired ROM | ||
76 | size in KiB divided by 128*r. Note that these examples might (or might | ||
77 | not) be too extreme, leaving little memory for the rest of the system. | ||
78 | You could as well opt for 7/8 with r=14 or 11/12 with r=11 or r=22. | ||
79 | |||
80 | Note that higher r may make placing of ROM in e.g. NVMe flash memory | ||
81 | instead of in RAM more reasonable (or less unreasonable) than it would | ||
82 | have been with a lower r. If this is a concern as it relates to | ||
83 | possible attacks and you do not intend to ever do it defensively, you | ||
84 | might want to keep r lower (e.g., prefer r=15 over r=30 in the example | ||
85 | above, even if 30 performs slightly faster). | ||
86 | |||
87 | Your adjustments to r, if you deviate from powers of two, will also | ||
88 | result in weirder memory usage per hash. Like 1.75 MiB at r=14 instead | ||
89 | of 2 MiB at r=8 that you would have used without a ROM. That's OK. | ||
90 | |||
91 | For ROM initialization, which you do with yescrypt_init_shared(), use | ||
92 | the same r and NROM that you'd later use for password hashing, choose p | ||
93 | based on your servers' physical and/or logical CPU count (maybe | ||
94 | considering eventual upgrades as you won't be able to change this later, | ||
95 | but without going unnecessarily high - e.g., p=28, p=56, or p=112 make | ||
96 | sense on servers that currently have 28 physical / 56 logical CPUs), and | ||
97 | set the rest of the parameters to: | ||
98 | |||
99 | flags = YESCRYPT_DEFAULTS, N = 0, t = 0, g = 0 | ||
100 | |||
101 | N is set to 0 because it isn't relevant during ROM initialization (you | ||
102 | can use different values of N for hashing passwords with the same ROM). | ||
103 | |||
104 | To keep the ROM in e.g. SysV shared memory and reuse it across your | ||
105 | authentication service restarts, you'd need to allocate the memory and | ||
106 | set the flags to "YESCRYPT_DEFAULTS | YESCRYPT_SHARED_PREALLOCATED". | ||
107 | |||
108 | For actual password hashing, you'd use your chosen values for N, r, | ||
109 | NROM, and set the rest of the parameters to: | ||
110 | |||
111 | flags = YESCRYPT_DEFAULTS, p = 1, t = 0, g = 0 | ||
112 | |||
113 | Note that although you'd use a large p for ROM initialization, you | ||
114 | should use p=1 for actual password hashing like you would without a ROM. | ||
115 | |||
116 | Do not forget to pass the ROM into the actual password hashing (and keep | ||
117 | r and NROM set accordingly). | ||
118 | |||
119 | Since N must be a power of two and r is dependent on ROM size, you may | ||
120 | use t (in the range of 0 to 2) for fine-tuning the running time, but | ||
121 | first bring N to the maximum you can afford. | ||
122 | |||
123 | If this feels too complicated, or even if it doesn't, please consider | ||
124 | engaging Openwall for your yescrypt deployment. We'd be happy to help. | ||
125 | |||
126 | |||
127 | Password-based key derivation. | ||
128 | |||
129 | (Or rather passphrase-based.) | ||
130 | |||
131 | Use settings similar to those for password hashing without a ROM, but | ||
132 | adjusted for higher memory usage and running time, and optionally with | ||
133 | thread-level parallelism. | ||
134 | |||
135 | Small and fast (memory usage 128 MiB, running time under 100 ms on a | ||
136 | fast desktop): | ||
137 | |||
138 | flags = YESCRYPT_DEFAULTS, N = 32768, r = 32, p = 1, t = 0, g = 0, NROM = 0 | ||
139 | |||
140 | Large and fast (memory usage 1 GiB, running time under 200 ms on a fast | ||
141 | quad-core desktop not including memory allocation overhead, under 250 ms | ||
142 | with the overhead included), but requires build with OpenMP support (or | ||
143 | otherwise will run as slow as yet be weaker than its p=1 alternative): | ||
144 | |||
145 | flags = YESCRYPT_DEFAULTS, N = 262144, r = 32, p = 4, t = 0, g = 0, NROM = 0 | ||
146 | |||
147 | Large and slower (memory usage 1 GiB, running time under 300 ms on a | ||
148 | fast quad-core desktop not including memory allocation overhead, under | ||
149 | 350 ms with the overhead included), also requires build with OpenMP | ||
150 | support (or otherwise will run slower than the p=1 alternative below): | ||
151 | |||
152 | flags = YESCRYPT_DEFAULTS, N = 262144, r = 32, p = 4, t = 2, g = 0, NROM = 0 | ||
153 | |||
154 | Large and slow (memory usage 1 GiB, running time under 600 ms on a fast | ||
155 | desktop not including memory allocation overhead, under 650 ms with the | ||
156 | overhead included): | ||
157 | |||
158 | flags = YESCRYPT_DEFAULTS, N = 262144, r = 32, p = 1, t = 0, g = 0, NROM = 0 | ||
159 | |||
160 | Just like with password hashing, even heavier and slower settings are | ||
161 | possible, if affordable, and you achieve them by adjusting N, r, t in | ||
162 | the same way and in the same preferred ranges (please see the section on | ||
163 | password hashing without a ROM, above). Unlike with password hashing, | ||
164 | it makes some sense to go above t=2 if you expect that your users might | ||
165 | not be able to afford more memory but can afford more time. However, | ||
166 | increasing the memory usage provides better protection, and we don't | ||
167 | recommend forcing your users to wait for more than 1 second as they | ||
168 | could as well type more characters in that time. If this feels too | ||
169 | complicated, just use one of the above parameter sets as-is. | ||
170 | |||
171 | |||
172 | Amortization of memory allocation overhead. | ||
173 | |||
174 | It takes a significant fraction of yescrypt's total running time to | ||
175 | allocate memory from the operating system, especially considering that | ||
176 | the kernel zeroizes the memory before handing it over to your program. | ||
177 | |||
178 | Unless you naturally need to compute yescrypt just once per process, you | ||
179 | may achieve greater efficiency by fully using advanced yescrypt APIs | ||
180 | that let you preserve and reuse the memory allocation across yescrypt | ||
181 | invocations. This is done by reusing the structure pointed to by the | ||
182 | "yescrypt_local_t *local" argument of yescrypt_r() or yescrypt_kdf() | ||
183 | without calling yescrypt_free_local() inbetween the repeated invocations | ||
184 | of yescrypt. | ||
185 | |||
186 | |||
187 | YESCRYPT_DEFAULTS macro. | ||
188 | |||
189 | Please note that the value of the YESCRYPT_DEFAULTS macro might change | ||
190 | later, so if you use the macro like it's recommended here then for | ||
191 | results reproducible across versions you might need to store its value | ||
192 | somewhere along with the hashes or the encrypted data. | ||
193 | |||
194 | If you use yescrypt's standard hash string encoding, then yescrypt | ||
195 | already encodes and decodes this value for you, so you don't need to | ||
196 | worry about this. | ||
diff --git a/libbb/yescrypt/README b/libbb/yescrypt/README new file mode 100644 index 000000000..c1011c56a --- /dev/null +++ b/libbb/yescrypt/README | |||
@@ -0,0 +1,4 @@ | |||
1 | The yescrypt code in this directory is adapted from libxcrypt-4.4.38 | ||
2 | with minimal edits, hopefully making it easier to track | ||
3 | backports by resetting the tree to the commit which created this file, | ||
4 | then comparing changes in upstream libxcrypt to the tree. | ||
diff --git a/libbb/yescrypt/alg-sha256.c b/libbb/yescrypt/alg-sha256.c new file mode 100644 index 000000000..dc748c968 --- /dev/null +++ b/libbb/yescrypt/alg-sha256.c | |||
@@ -0,0 +1,91 @@ | |||
1 | /*- | ||
2 | * Copyright 2005-2016 Colin Percival | ||
3 | * Copyright 2016-2018,2021 Alexander Peslyak | ||
4 | * All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * 1. Redistributions of source code must retain the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer. | ||
11 | * 2. Redistributions in binary form must reproduce the above copyright | ||
12 | * notice, this list of conditions and the following disclaimer in the | ||
13 | * documentation and/or other materials provided with the distribution. | ||
14 | * | ||
15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | ||
16 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | ||
19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
23 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
24 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
25 | * SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | /** | ||
29 | * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): | ||
30 | * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and | ||
31 | * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). | ||
32 | */ | ||
33 | static void | ||
34 | PBKDF2_SHA256(const uint8_t *passwd, size_t passwdlen, | ||
35 | const uint8_t *salt, size_t saltlen, | ||
36 | uint64_t c, uint8_t *buf, size_t dkLen) | ||
37 | { | ||
38 | hmac_ctx_t Phctx, PShctx; | ||
39 | uint32_t i; | ||
40 | |||
41 | /* Compute HMAC state after processing P. */ | ||
42 | hmac_begin(&Phctx, passwd, passwdlen, sha256_begin); | ||
43 | |||
44 | /* Compute HMAC state after processing P and S. */ | ||
45 | PShctx = Phctx; | ||
46 | hmac_hash(&PShctx, salt, saltlen); | ||
47 | |||
48 | /* Iterate through the blocks. */ | ||
49 | for (i = 0; dkLen != 0; ) { | ||
50 | long U[32 / sizeof(long)]; | ||
51 | long T[32 / sizeof(long)]; | ||
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... | ||
56 | uint32_t ivec; | ||
57 | size_t clen; | ||
58 | int k; | ||
59 | |||
60 | /* Generate INT(i). */ | ||
61 | i++; | ||
62 | ivec = SWAP_BE32(i); | ||
63 | |||
64 | /* Compute U_1 = PRF(P, S || INT(i)). */ | ||
65 | hmac_peek_hash(&PShctx, (void*)T, &ivec, 4, NULL); | ||
66 | //TODO: the above is a vararg function, might incur some ABI pain | ||
67 | //does libbb need a non-vararg version with just one (buf,len)? | ||
68 | |||
69 | if (c > 1) { | ||
70 | //in yescrypt, c is always 1, so this if() branch is optimized out | ||
71 | uint64_t j; | ||
72 | /* T_i = U_1 ... */ | ||
73 | memcpy(U, T, 32); | ||
74 | for (j = 2; j <= c; j++) { | ||
75 | /* Compute U_j. */ | ||
76 | hmac_peek_hash(&Phctx, (void*)U, U, 32, NULL); | ||
77 | /* ... xor U_j ... */ | ||
78 | for (k = 0; k < 32 / sizeof(long); k++) | ||
79 | T[k] ^= U[k]; | ||
80 | //TODO: xorbuf32_aligned_long(T, U); | ||
81 | } | ||
82 | } | ||
83 | |||
84 | /* Copy as many bytes as necessary into buf. */ | ||
85 | clen = dkLen; | ||
86 | if (clen > 32) | ||
87 | clen = 32; | ||
88 | buf = mempcpy(buf, T, clen); | ||
89 | dkLen -= clen; | ||
90 | } | ||
91 | } | ||
diff --git a/libbb/yescrypt/alg-yescrypt-common.c b/libbb/yescrypt/alg-yescrypt-common.c new file mode 100644 index 000000000..c51823787 --- /dev/null +++ b/libbb/yescrypt/alg-yescrypt-common.c | |||
@@ -0,0 +1,408 @@ | |||
1 | /*- | ||
2 | * Copyright 2013-2018 Alexander Peslyak | ||
3 | * All rights reserved. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted. | ||
7 | * | ||
8 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | ||
9 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
10 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
11 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | ||
12 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
13 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
14 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
15 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
16 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
17 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
18 | * SUCH DAMAGE. | ||
19 | */ | ||
20 | |||
21 | #if RESTRICTED_PARAMS | ||
22 | |||
23 | #define decode64_uint32(dst, src, min) \ | ||
24 | ({ \ | ||
25 | uint32_t d32 = a2i64(*(src)); \ | ||
26 | if (d32 > 47) \ | ||
27 | goto fail; \ | ||
28 | *(dst) = d32 + (min); \ | ||
29 | ++src; \ | ||
30 | }) | ||
31 | #define test_decode64_uint32() ((void)0) | ||
32 | #define FULL_PARAMS(...) | ||
33 | |||
34 | #else | ||
35 | |||
36 | #define FULL_PARAMS(...) __VA_ARGS__ | ||
37 | |||
38 | /* Not inlining: | ||
39 | * de/encode64 functions are only used to read | ||
40 | * yescrypt_params_t field, and convert salt to binary - | ||
41 | * both of these are negligible compared to main hashing operation | ||
42 | */ | ||
43 | static NOINLINE const uint8_t *decode64_uint32( | ||
44 | uint32_t *dst, | ||
45 | const uint8_t *src, uint32_t val) | ||
46 | { | ||
47 | uint32_t start = 0, end = 47, bits = 0; | ||
48 | uint32_t c; | ||
49 | |||
50 | if (!src) /* previous decode failed already? */ | ||
51 | goto fail; | ||
52 | |||
53 | c = a2i64(*src++); | ||
54 | if (c > 63) | ||
55 | goto fail; | ||
56 | |||
57 | // The encoding of number N: | ||
58 | // start = 0 end = 47 | ||
59 | // If N < 48, it is encoded verbatim, else | ||
60 | // N -= 48 | ||
61 | // start = end+1 = 48 | ||
62 | // end += (64-end)/2 = 55 | ||
63 | // If N < (end+1-start)<<6 = 8<<6, it is encoded as 48+(N>>6)|low6bits (that is, 48...55|<6bit>), else | ||
64 | // N -= 8<<6 | ||
65 | // start = end+1 = 56 | ||
66 | // end += (64-end)/2 = 59 | ||
67 | // If N < (end+1-start)<<2*6 = 4<<12, it is encoded as 56+(N>>2*6)|low12bits (that is, 56...59|<6bit>|<6bit>), else | ||
68 | // ...same for 60..61|<6bit>|<6bit>|<6bit> | ||
69 | // .......same for 62|<6bit>|<6bit>|<6bit>|<6bit> | ||
70 | // .......same for 63|<6bit>|<6bit>|<6bit>|<6bit>|<6bit> | ||
71 | dbg_dec64("c:%d val:0x%08x", (int)c, (unsigned)val); | ||
72 | while (c > end) { | ||
73 | dbg_dec64("c:%d > end:%d", (int)c, (int)end); | ||
74 | val += (end + 1 - start) << bits; | ||
75 | dbg_dec64("val+=0x%08x", (int)((end + 1 - start) << bits)); | ||
76 | dbg_dec64(" val:0x%08x", (unsigned)val); | ||
77 | start = end + 1; | ||
78 | end += (64 - end) / 2; | ||
79 | bits += 6; | ||
80 | dbg_dec64("start=%d", (int)start); | ||
81 | dbg_dec64("end=%d", (int)end); | ||
82 | dbg_dec64("bits=%d", (int)bits); | ||
83 | } | ||
84 | |||
85 | val += (c - start) << bits; | ||
86 | dbg_dec64("final val+=0x%08x", (int)((c - start) << bits)); | ||
87 | dbg_dec64(" val:0x%08x", (unsigned)val); | ||
88 | |||
89 | while (bits != 0) { | ||
90 | c = a2i64(*src++); | ||
91 | if (c > 63) | ||
92 | goto fail; | ||
93 | bits -= 6; | ||
94 | val += c << bits; | ||
95 | dbg_dec64("low bits val+=0x%08x", (int)(c << bits)); | ||
96 | dbg_dec64(" val:0x%08x", (unsigned)val); | ||
97 | } | ||
98 | ret: | ||
99 | *dst = val; | ||
100 | return src; | ||
101 | fail: | ||
102 | val = 0; | ||
103 | src = NULL; | ||
104 | goto ret; | ||
105 | } | ||
106 | |||
107 | #if TEST_DECODE64 | ||
108 | static void test_decode64_uint32(void) | ||
109 | { | ||
110 | const uint8_t *src, *end; | ||
111 | uint32_t u32; | ||
112 | int a = 48; | ||
113 | int b = 8<<6; // 0x0200 | ||
114 | int c = 4<<12; // 0x04000 | ||
115 | int d = 2<<18; // 0x080000 | ||
116 | int e = 1<<24; // 0x1000000 | ||
117 | |||
118 | src = (void*)"wzzz"; | ||
119 | end = decode64_uint32(&u32, src, 0); | ||
120 | if (u32 != 0x0003ffff+c+b+a) bb_error_msg_and_die("Incorrect decode '%s':0x%08x", src, (unsigned)u32); | ||
121 | if (end != src + 4) bb_error_msg_and_die("Incorrect decode '%s': %p end:%p", src, src, end); | ||
122 | src = (void*)"xzzz"; | ||
123 | end = decode64_uint32(&u32, src, 0); | ||
124 | if (u32 != 0x0007ffff+c+b+a) bb_error_msg_and_die("Incorrect decode '%s':0x%08x", src, (unsigned)u32); | ||
125 | if (end != src + 4) bb_error_msg_and_die("Incorrect decode '%s': %p end:%p", src, src, end); | ||
126 | // Note how the last representable "x---" encoding, 0x7ffff, is exactly d-1! | ||
127 | // And if we now increment it, we get: | ||
128 | src = (void*)"y...."; | ||
129 | end = decode64_uint32(&u32, src, 0); | ||
130 | if (u32 != 0x00000000+d+c+b+a) bb_error_msg_and_die("Incorrect decode '%s':0x%08x", src, (unsigned)u32); | ||
131 | if (end != src + 5) bb_error_msg_and_die("Incorrect decode '%s': %p end:%p", src, src, end); | ||
132 | src = (void*)"yzzzz"; | ||
133 | end = decode64_uint32(&u32, src, 0); | ||
134 | if (u32 != 0x00ffffff+d+c+b+a) bb_error_msg_and_die("Incorrect decode '%s':0x%08x", src, (unsigned)u32); | ||
135 | if (end != src + 5) bb_error_msg_and_die("Incorrect decode '%s': %p end:%p", src, src, end); | ||
136 | |||
137 | src = (void*)"zzzzzz"; | ||
138 | end = decode64_uint32(&u32, src, 0); | ||
139 | if (u32 != 0x3fffffff+e+d+c+b+a) bb_error_msg_and_die("Incorrect decode '%s':0x%08x", src, (unsigned)u32); | ||
140 | if (end != src + 6) bb_error_msg_and_die("Incorrect decode '%s': %p end:%p", src, src, end); | ||
141 | |||
142 | bb_error_msg("test_decode64_uint32() OK"); | ||
143 | } | ||
144 | #else | ||
145 | # define test_decode64_uint32() ((void)0) | ||
146 | #endif | ||
147 | |||
148 | #endif /* !RESTRICTED_PARAMS */ | ||
149 | |||
150 | #if 1 | ||
151 | static const uint8_t *decode64( | ||
152 | uint8_t *dst, size_t *dstlen, | ||
153 | const uint8_t *src) | ||
154 | { | ||
155 | unsigned dstpos = 0; | ||
156 | |||
157 | dbg_dec64("src:'%s'", src); | ||
158 | for (;;) { | ||
159 | uint32_t c, value = 0; | ||
160 | int bits = 0; | ||
161 | while (*src != '\0' && *src != '$') { | ||
162 | c = a2i64(*src); | ||
163 | if (c > 63) { /* bad ascii64 char, stop decoding at it */ | ||
164 | break; | ||
165 | } | ||
166 | src++; | ||
167 | value |= c << bits; | ||
168 | bits += 6; | ||
169 | if (bits == 24) /* got 4 chars */ | ||
170 | goto store; | ||
171 | } | ||
172 | /* we read entire src, or met a non-ascii64 char (such as "$") */ | ||
173 | if (bits == 0) | ||
174 | break; | ||
175 | /* else: we got last, partial bit block - store it */ | ||
176 | store: | ||
177 | dbg_dec64(" storing bits:%d dstpos:%u v:%08x", bits, dstpos, (int)SWAP_BE32(value)); //BE to see lsb first | ||
178 | for (;;) { | ||
179 | if ((*src == '\0' || *src == '$') | ||
180 | && value == 0 && bits < 8 | ||
181 | ) { | ||
182 | /* Example: mkpasswd PWD '$y$j9T$123': | ||
183 | * the "123" is bits:18 value:03,51,00 | ||
184 | * is considered to be 2 bytes, not 3! | ||
185 | * | ||
186 | * '$y$j9T$zzz' in upstream fails outright (3rd byte isn't zero). | ||
187 | * IOW: for upstream, validity of salt depends on VALUE, | ||
188 | * not just size of salt. Which is a bug. | ||
189 | * The '$y$j9T$zzz.' salt is the same | ||
190 | * (it adds 6 zero msbits) but upstream works with it, | ||
191 | * thus '$y$j9T$zzz' should work too and give the same result. | ||
192 | */ | ||
193 | goto end; | ||
194 | } | ||
195 | if (dstpos >= *dstlen) { | ||
196 | dbg_dec64(" ERR: bits:%d dstpos:%u dst[] is too small", bits, dstpos); | ||
197 | goto fail; | ||
198 | } | ||
199 | *dst++ = value; | ||
200 | dstpos++; | ||
201 | value >>= 8; | ||
202 | bits -= 8; | ||
203 | if (bits <= 0) /* can get negative, if we e.g. had 6 bits */ | ||
204 | break; | ||
205 | } | ||
206 | if (*src == '\0' || *src == '$') | ||
207 | break; | ||
208 | } | ||
209 | end: | ||
210 | *dstlen = dstpos; | ||
211 | dbg_dec64("dec64: OK, dst[%d]", (int)dstpos); | ||
212 | return src; | ||
213 | fail: | ||
214 | /* *dstlen = 0; - not needed, caller detects error by seeing NULL */ | ||
215 | return NULL; | ||
216 | } | ||
217 | #else | ||
218 | /* Buggy (and larger) original code */ | ||
219 | static const uint8_t *decode64( | ||
220 | uint8_t *dst, size_t *dstlen, | ||
221 | const uint8_t *src, size_t srclen) | ||
222 | { | ||
223 | size_t dstpos = 0; | ||
224 | |||
225 | while (dstpos <= *dstlen && srclen) { | ||
226 | uint32_t value = 0, bits = 0; | ||
227 | while (srclen--) { | ||
228 | uint32_t c = a2i64(*src); | ||
229 | if (c > 63) { | ||
230 | srclen = 0; | ||
231 | break; | ||
232 | } | ||
233 | src++; | ||
234 | value |= c << bits; | ||
235 | bits += 6; | ||
236 | if (bits >= 24) | ||
237 | break; | ||
238 | } | ||
239 | if (!bits) | ||
240 | break; | ||
241 | if (bits < 12) /* must have at least one full byte */ | ||
242 | goto fail; | ||
243 | dbg_dec64(" storing bits:%d v:%08x", (int)bits, (int)SWAP_BE32(value)); //BE to see lsb first | ||
244 | while (dstpos++ < *dstlen) { | ||
245 | *dst++ = value; | ||
246 | value >>= 8; | ||
247 | bits -= 8; | ||
248 | if (bits < 8) { /* 2 or 4 */ | ||
249 | if (value) /* must be 0 */ | ||
250 | goto fail; | ||
251 | bits = 0; | ||
252 | break; | ||
253 | } | ||
254 | } | ||
255 | if (bits) | ||
256 | goto fail; | ||
257 | } | ||
258 | |||
259 | if (!srclen && dstpos <= *dstlen) { | ||
260 | *dstlen = dstpos; | ||
261 | dbg_dec64("dec64: OK, dst[%d]", (int)dstpos); | ||
262 | return src; | ||
263 | } | ||
264 | fail: | ||
265 | /* *dstlen = 0; - not needed, caller detects error by seeing NULL */ | ||
266 | return NULL; | ||
267 | } | ||
268 | #endif | ||
269 | |||
270 | static char *encode64( | ||
271 | char *dst, size_t dstlen, | ||
272 | const uint8_t *src, size_t srclen) | ||
273 | { | ||
274 | while (srclen) { | ||
275 | uint32_t value = 0, b = 0; | ||
276 | do { | ||
277 | value |= (uint32_t)(*src++ << b); | ||
278 | b += 8; | ||
279 | srclen--; | ||
280 | } while (srclen && b < 24); | ||
281 | |||
282 | b >>= 3; /* number of bits to number of bytes */ | ||
283 | b++; /* 1, 2 or 3 bytes will become 2, 3 or 4 ascii64 chars */ | ||
284 | dstlen -= b; | ||
285 | if ((ssize_t)dstlen <= 0) | ||
286 | return NULL; | ||
287 | dst = num2str64_lsb_first(dst, value, b); | ||
288 | } | ||
289 | *dst = '\0'; | ||
290 | return dst; | ||
291 | } | ||
292 | |||
293 | char *yescrypt_r( | ||
294 | const uint8_t *passwd, size_t passwdlen, | ||
295 | const uint8_t *setting, | ||
296 | char *buf, size_t buflen) | ||
297 | { | ||
298 | struct { | ||
299 | yescrypt_ctx_t yctx[1]; | ||
300 | unsigned char hashbin32[32]; | ||
301 | } u; | ||
302 | #define yctx u.yctx | ||
303 | #define hashbin32 u.hashbin32 | ||
304 | char *dst; | ||
305 | const uint8_t *src, *saltend; | ||
306 | size_t need, prefixlen; | ||
307 | uint32_t u32; | ||
308 | |||
309 | test_decode64_uint32(); | ||
310 | |||
311 | memset(yctx, 0, sizeof(yctx)); | ||
312 | FULL_PARAMS(yctx->param.p = 1;) | ||
313 | |||
314 | /* we assume setting starts with "$y$" (caller must ensure this) */ | ||
315 | src = setting + 3; | ||
316 | |||
317 | src = decode64_uint32(&yctx->param.flags, src, 0); | ||
318 | /* "j9T" returns: 0x2f */ | ||
319 | //if (!src) | ||
320 | // goto fail; | ||
321 | |||
322 | if (yctx->param.flags < YESCRYPT_RW) { | ||
323 | dbg("yctx->param.flags=0x%x", (unsigned)yctx->param.flags); | ||
324 | goto fail; // bbox: we don't support scrypt - only yescrypt | ||
325 | } else if (yctx->param.flags <= YESCRYPT_RW + (YESCRYPT_RW_FLAVOR_MASK >> 2)) { | ||
326 | /* "j9T" sets flags to 0xb6 */ | ||
327 | yctx->param.flags = YESCRYPT_RW + ((yctx->param.flags - YESCRYPT_RW) << 2); | ||
328 | dbg("yctx->param.flags=0x%x", (unsigned)yctx->param.flags); | ||
329 | dbg(" YESCRYPT_RW:%u", !!(yctx->param.flags & YESCRYPT_RW)); | ||
330 | dbg((yctx->param.flags & YESCRYPT_RW_FLAVOR_MASK) == | ||
331 | (YESCRYPT_ROUNDS_6 | YESCRYPT_GATHER_4 | YESCRYPT_SIMPLE_2 | YESCRYPT_SBOX_12K) | ||
332 | ? " YESCRYPT_ROUNDS_6 | YESCRYPT_GATHER_4 | YESCRYPT_SIMPLE_2 | YESCRYPT_SBOX_12K" | ||
333 | : " flags are not standard" | ||
334 | ); | ||
335 | } else { | ||
336 | goto fail; | ||
337 | } | ||
338 | |||
339 | src = decode64_uint32(&u32, src, 1); | ||
340 | if (/*!src ||*/ u32 > 63) | ||
341 | goto fail; | ||
342 | yctx->param.N = (uint64_t)1 << u32; | ||
343 | /* "j9T" sets to 4096 (1<<12) */ | ||
344 | dbg("yctx->param.N=%llu (1<<%u)", (unsigned long long)yctx->param.N, (unsigned)u32); | ||
345 | |||
346 | src = decode64_uint32(&yctx->param.r, src, 1); | ||
347 | /* "j9T" sets to 32 */ | ||
348 | dbg("yctx->param.r=%u", yctx->param.r); | ||
349 | |||
350 | if (!src) | ||
351 | goto fail; | ||
352 | if (*src != '$') { | ||
353 | #if RESTRICTED_PARAMS | ||
354 | goto fail; | ||
355 | #else | ||
356 | src = decode64_uint32(&u32, src, 1); | ||
357 | dbg("yescrypt has extended params:0x%x", (unsigned)u32); | ||
358 | if (u32 & 1) | ||
359 | src = decode64_uint32(&yctx->param.p, src, 2); | ||
360 | if (u32 & 2) | ||
361 | src = decode64_uint32(&yctx->param.t, src, 1); | ||
362 | if (u32 & 4) | ||
363 | src = decode64_uint32(&yctx->param.g, src, 1); | ||
364 | if (u32 & 8) { | ||
365 | src = decode64_uint32(&u32, src, 1); | ||
366 | if (/*!src ||*/ u32 > 63) | ||
367 | goto fail; | ||
368 | yctx->param.NROM = (uint64_t)1 << u32; | ||
369 | } | ||
370 | if (!src) | ||
371 | goto fail; | ||
372 | if (*src != '$') | ||
373 | goto fail; | ||
374 | #endif | ||
375 | } | ||
376 | |||
377 | yctx->saltlen = sizeof(yctx->salt); | ||
378 | src++; /* now points to salt */ | ||
379 | saltend = decode64(yctx->salt, &yctx->saltlen, src); | ||
380 | if (!saltend || (*saltend != '\0' && *saltend != '$')) | ||
381 | goto fail; /* salt[] is too small, or bad char during decode */ | ||
382 | dbg_dec64("salt is %d ascii64 chars -> %d bytes (in binary)", (int)(saltend - src), (int)yctx->saltlen); | ||
383 | |||
384 | prefixlen = saltend - setting; | ||
385 | need = prefixlen + 1 + YESCRYPT_HASH_LEN + 1; | ||
386 | if (need > buflen /*overflow is quite unlikely: || need < prefixlen*/) | ||
387 | goto fail; | ||
388 | |||
389 | if (yescrypt_kdf32(yctx, passwd, passwdlen, hashbin32)) { | ||
390 | dbg("error in yescrypt_kdf32"); | ||
391 | goto fail; | ||
392 | } | ||
393 | |||
394 | dst = mempcpy(buf, setting, prefixlen); | ||
395 | *dst++ = '$'; | ||
396 | dst = encode64(dst, buflen - (dst - buf), hashbin32, sizeof(hashbin32)); | ||
397 | if (!dst) | ||
398 | goto fail; | ||
399 | ret: | ||
400 | free_region(yctx->local); | ||
401 | explicit_bzero(&u, sizeof(u)); | ||
402 | return buf; | ||
403 | fail: | ||
404 | buf = NULL; | ||
405 | goto ret; | ||
406 | #undef yctx | ||
407 | #undef hashbin32 | ||
408 | } | ||
diff --git a/libbb/yescrypt/alg-yescrypt-kdf.c b/libbb/yescrypt/alg-yescrypt-kdf.c new file mode 100644 index 000000000..a9a1bd591 --- /dev/null +++ b/libbb/yescrypt/alg-yescrypt-kdf.c | |||
@@ -0,0 +1,1212 @@ | |||
1 | /*- | ||
2 | * Copyright 2009 Colin Percival | ||
3 | * Copyright 2012-2018 Alexander Peslyak | ||
4 | * All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * 1. Redistributions of source code must retain the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer. | ||
11 | * 2. Redistributions in binary form must reproduce the above copyright | ||
12 | * notice, this list of conditions and the following disclaimer in the | ||
13 | * documentation and/or other materials provided with the distribution. | ||
14 | * | ||
15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | ||
16 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | ||
19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
23 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
24 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
25 | * SUCH DAMAGE. | ||
26 | * | ||
27 | * This file was originally written by Colin Percival as part of the Tarsnap | ||
28 | * online backup system. | ||
29 | */ | ||
30 | |||
31 | #if __STDC_VERSION__ >= 199901L | ||
32 | /* Have restrict */ | ||
33 | #elif defined(__GNUC__) | ||
34 | #define restrict __restrict | ||
35 | #else | ||
36 | #define restrict | ||
37 | #endif | ||
38 | |||
39 | #ifdef __GNUC__ | ||
40 | #define unlikely(exp) __builtin_expect(exp, 0) | ||
41 | #else | ||
42 | #define unlikely(exp) (exp) | ||
43 | #endif | ||
44 | |||
45 | typedef union { | ||
46 | uint32_t w[16]; | ||
47 | uint64_t d[8]; | ||
48 | } salsa20_blk_t; | ||
49 | |||
50 | static void salsa20_simd_shuffle( | ||
51 | const salsa20_blk_t *Bin, | ||
52 | salsa20_blk_t *Bout) | ||
53 | { | ||
54 | #define COMBINE(out, in1, in2) \ | ||
55 | do { \ | ||
56 | Bout->d[out] = Bin->w[in1 * 2] | ((uint64_t)Bin->w[in2 * 2 + 1] << 32); \ | ||
57 | } while (0) | ||
58 | COMBINE(0, 0, 2); | ||
59 | COMBINE(1, 5, 7); | ||
60 | COMBINE(2, 2, 4); | ||
61 | COMBINE(3, 7, 1); | ||
62 | COMBINE(4, 4, 6); | ||
63 | COMBINE(5, 1, 3); | ||
64 | COMBINE(6, 6, 0); | ||
65 | COMBINE(7, 3, 5); | ||
66 | #undef COMBINE | ||
67 | } | ||
68 | |||
69 | static void salsa20_simd_unshuffle( | ||
70 | const salsa20_blk_t *Bin, | ||
71 | salsa20_blk_t *Bout) | ||
72 | { | ||
73 | #define UNCOMBINE(out, in1, in2) \ | ||
74 | do { \ | ||
75 | Bout->w[out * 2] = Bin->d[in1]; \ | ||
76 | Bout->w[out * 2 + 1] = Bin->d[in2] >> 32; \ | ||
77 | } while (0) | ||
78 | UNCOMBINE(0, 0, 6); | ||
79 | UNCOMBINE(1, 5, 3); | ||
80 | UNCOMBINE(2, 2, 0); | ||
81 | UNCOMBINE(3, 7, 5); | ||
82 | UNCOMBINE(4, 4, 2); | ||
83 | UNCOMBINE(5, 1, 7); | ||
84 | UNCOMBINE(6, 6, 4); | ||
85 | UNCOMBINE(7, 3, 1); | ||
86 | #undef UNCOMBINE | ||
87 | } | ||
88 | |||
89 | #define DECL_X \ | ||
90 | salsa20_blk_t X | ||
91 | #define DECL_Y \ | ||
92 | salsa20_blk_t Y | ||
93 | |||
94 | #if KDF_UNROLL_COPY | ||
95 | #define COPY(out, in) \ | ||
96 | do { \ | ||
97 | (out).d[0] = (in).d[0]; \ | ||
98 | (out).d[1] = (in).d[1]; \ | ||
99 | (out).d[2] = (in).d[2]; \ | ||
100 | (out).d[3] = (in).d[3]; \ | ||
101 | (out).d[4] = (in).d[4]; \ | ||
102 | (out).d[5] = (in).d[5]; \ | ||
103 | (out).d[6] = (in).d[6]; \ | ||
104 | (out).d[7] = (in).d[7]; \ | ||
105 | } while (0) | ||
106 | #else | ||
107 | #define COPY(out, in) \ | ||
108 | do { \ | ||
109 | memcpy((out).d, (in).d, sizeof((in).d)); \ | ||
110 | } while (0) | ||
111 | #endif | ||
112 | |||
113 | #define READ_X(in) COPY(X, in) | ||
114 | #define WRITE_X(out) COPY(out, X) | ||
115 | |||
116 | /** | ||
117 | * salsa20(B): | ||
118 | * Apply the Salsa20 core to the provided block. | ||
119 | */ | ||
120 | static void salsa20(salsa20_blk_t *restrict B, | ||
121 | salsa20_blk_t *restrict Bout, | ||
122 | uint32_t doublerounds) | ||
123 | { | ||
124 | salsa20_blk_t X; | ||
125 | #define x X.w | ||
126 | |||
127 | salsa20_simd_unshuffle(B, &X); | ||
128 | |||
129 | do { | ||
130 | #define R(a,b) (((a) << (b)) | ((a) >> (32 - (b)))) | ||
131 | /* Operate on columns */ | ||
132 | #if KDF_UNROLL_SALSA20 | ||
133 | x[ 4] ^= R(x[ 0]+x[12], 7); // x[j] ^= R(x[k]+x[l], CONST) | ||
134 | x[ 8] ^= R(x[ 4]+x[ 0], 9); | ||
135 | x[12] ^= R(x[ 8]+x[ 4],13); | ||
136 | x[ 0] ^= R(x[12]+x[ 8],18); | ||
137 | |||
138 | x[ 9] ^= R(x[ 5]+x[ 1], 7); | ||
139 | x[13] ^= R(x[ 9]+x[ 5], 9); | ||
140 | x[ 1] ^= R(x[13]+x[ 9],13); | ||
141 | x[ 5] ^= R(x[ 1]+x[13],18); | ||
142 | |||
143 | x[14] ^= R(x[10]+x[ 6], 7); | ||
144 | x[ 2] ^= R(x[14]+x[10], 9); | ||
145 | x[ 6] ^= R(x[ 2]+x[14],13); | ||
146 | x[10] ^= R(x[ 6]+x[ 2],18); | ||
147 | |||
148 | x[ 3] ^= R(x[15]+x[11], 7); | ||
149 | x[ 7] ^= R(x[ 3]+x[15], 9); | ||
150 | x[11] ^= R(x[ 7]+x[ 3],13); | ||
151 | x[15] ^= R(x[11]+x[ 7],18); | ||
152 | #else | ||
153 | { | ||
154 | unsigned j, k, l; | ||
155 | j = 4; k = 0; l = 12; | ||
156 | for (;;) { | ||
157 | uint32_t t; | ||
158 | x[j] ^= ({ t = x[k] + x[l]; R(t, 7); }); l = k; k = j; j = (j+4) & 0xf; | ||
159 | x[j] ^= ({ t = x[k] + x[l]; R(t, 9); }); l = k; k = j; j = (j+4) & 0xf; | ||
160 | x[j] ^= ({ t = x[k] + x[l]; R(t,13); }); l = k; k = j; j = (j+4) & 0xf; | ||
161 | x[j] ^= ({ t = x[k] + x[l]; R(t,18); }); | ||
162 | if (j == 15) break; | ||
163 | l = j + 1; k = j + 5; j = (j+9) & 0xf; | ||
164 | } | ||
165 | } | ||
166 | #endif | ||
167 | /* Operate on rows */ | ||
168 | #if KDF_UNROLL_SALSA20 | ||
169 | // i=0 n=0 | ||
170 | x[ 1] ^= R(x[ 0]+x[ 3], 7); // [i + (n+1)&3] [i + (n+0)&3] [i + (n+3)&3] | ||
171 | x[ 2] ^= R(x[ 1]+x[ 0], 9); // [i + (n+2)&3] [i + (n+1)&3] [i + (n+0)&3] | ||
172 | x[ 3] ^= R(x[ 2]+x[ 1],13); // [i + (n+3)&3] [i + (n+2)&3] [i + (n+1)&3] | ||
173 | x[ 0] ^= R(x[ 3]+x[ 2],18); // [i + (n+0)&3] [i + (n+3)&3] [i + (n+2)&3] | ||
174 | // i=4 n=1 ^^^j^^^ ^^^k^^^ ^^^l^^^ | ||
175 | x[ 6] ^= R(x[ 5]+x[ 4], 7); // [i + (n+1)&3] [i + (n+0)&3] [i + (n+3)&3] | ||
176 | x[ 7] ^= R(x[ 6]+x[ 5], 9); // [i + (n+2)&3] [i + (n+1)&3] [i + (n+0)&3] | ||
177 | x[ 4] ^= R(x[ 7]+x[ 6],13); // [i + (n+3)&3] [i + (n+2)&3] [i + (n+1)&3] | ||
178 | x[ 5] ^= R(x[ 4]+x[ 7],18); // [i + (n+0)&3] [i + (n+3)&3] [i + (n+2)&3] | ||
179 | // i=8 n=2 | ||
180 | x[11] ^= R(x[10]+x[ 9], 7); // [i + (n+1)&3] [i + (n+0)&3] [i + (n+3)&3] | ||
181 | x[ 8] ^= R(x[11]+x[10], 9); // [i + (n+2)&3] [i + (n+1)&3] [i + (n+0)&3] | ||
182 | x[ 9] ^= R(x[ 8]+x[11],13); // [i + (n+3)&3] [i + (n+2)&3] [i + (n+1)&3] | ||
183 | x[10] ^= R(x[ 9]+x[ 8],18); // [i + (n+0)&3] [i + (n+3)&3] [i + (n+2)&3] | ||
184 | // i=12 n=3 | ||
185 | x[12] ^= R(x[15]+x[14], 7); // [i + (n+1)&3] [i + (n+0)&3] [i + (n+3)&3] | ||
186 | x[13] ^= R(x[12]+x[15], 9); // [i + (n+2)&3] [i + (n+1)&3] [i + (n+0)&3] | ||
187 | x[14] ^= R(x[13]+x[12],13); // [i + (n+3)&3] [i + (n+2)&3] [i + (n+1)&3] | ||
188 | x[15] ^= R(x[14]+x[13],18); // [i + (n+0)&3] [i + (n+3)&3] [i + (n+2)&3] | ||
189 | #else | ||
190 | { | ||
191 | unsigned j, k, l; | ||
192 | uint32_t *xrow; | ||
193 | j = 1; k = 0; l = 3; | ||
194 | xrow = &x[0]; | ||
195 | for (;;) { | ||
196 | uint32_t t; | ||
197 | xrow[j] ^= ({ t = xrow[k] + xrow[l]; R(t, 7); }); l = k; k = j; j = (j+1) & 3; | ||
198 | xrow[j] ^= ({ t = xrow[k] + xrow[l]; R(t, 9); }); l = k; k = j; j = (j+1) & 3; | ||
199 | xrow[j] ^= ({ t = xrow[k] + xrow[l]; R(t,13); }); l = k; k = j; j = (j+1) & 3; | ||
200 | xrow[j] ^= ({ t = xrow[k] + xrow[l]; R(t,18); }); | ||
201 | if (j == 3) break; | ||
202 | l = j; k = j + 1; j = (j+2) & 3; | ||
203 | xrow += 4; | ||
204 | } | ||
205 | } | ||
206 | #endif | ||
207 | |||
208 | #undef R | ||
209 | } while (--doublerounds); | ||
210 | #undef x | ||
211 | |||
212 | { | ||
213 | uint32_t i; | ||
214 | salsa20_simd_shuffle(&X, Bout); | ||
215 | for (i = 0; i < 16; i++) { | ||
216 | // bbox: note: was unrolled x4 | ||
217 | B->w[i] = Bout->w[i] += B->w[i]; | ||
218 | } | ||
219 | } | ||
220 | #if 0 | ||
221 | /* Too expensive */ | ||
222 | explicit_bzero(&X, sizeof(X)); | ||
223 | #endif | ||
224 | } | ||
225 | |||
226 | /** | ||
227 | * Apply the Salsa20/2 core to the block provided in X. | ||
228 | */ | ||
229 | #define SALSA20_2(out) \ | ||
230 | salsa20(&X, &out, 1) | ||
231 | |||
232 | #if 0 | ||
233 | #define XOR(out, in1, in2) \ | ||
234 | do { \ | ||
235 | (out).d[0] = (in1).d[0] ^ (in2).d[0]; \ | ||
236 | (out).d[1] = (in1).d[1] ^ (in2).d[1]; \ | ||
237 | (out).d[2] = (in1).d[2] ^ (in2).d[2]; \ | ||
238 | (out).d[3] = (in1).d[3] ^ (in2).d[3]; \ | ||
239 | (out).d[4] = (in1).d[4] ^ (in2).d[4]; \ | ||
240 | (out).d[5] = (in1).d[5] ^ (in2).d[5]; \ | ||
241 | (out).d[6] = (in1).d[6] ^ (in2).d[6]; \ | ||
242 | (out).d[7] = (in1).d[7] ^ (in2).d[7]; \ | ||
243 | } while (0) | ||
244 | #else | ||
245 | #define XOR(out, in1, in2) \ | ||
246 | do { \ | ||
247 | xorbuf64_3_aligned64(&(out).d, &(in1).d, &(in2).d); \ | ||
248 | } while (0) | ||
249 | #endif | ||
250 | |||
251 | #define XOR_X(in) XOR(X, X, in) | ||
252 | #define XOR_X_2(in1, in2) XOR(X, in1, in2) | ||
253 | #define XOR_X_WRITE_XOR_Y_2(out, in) \ | ||
254 | do { \ | ||
255 | XOR(Y, out, in); \ | ||
256 | COPY(out, Y); \ | ||
257 | XOR(X, X, Y); \ | ||
258 | } while (0) | ||
259 | |||
260 | /** | ||
261 | * Apply the Salsa20/8 core to the block provided in X ^ in. | ||
262 | */ | ||
263 | #define SALSA20_8_XOR_MEM(in, out) \ | ||
264 | do { \ | ||
265 | XOR_X(in); \ | ||
266 | salsa20(&X, &out, 4); \ | ||
267 | } while (0) | ||
268 | |||
269 | #define INTEGERIFY ((uint32_t)X.d[0]) | ||
270 | |||
271 | /** | ||
272 | * blockmix_salsa8(Bin, Bout, r): | ||
273 | * Compute Bout = BlockMix_{salsa20/8, r}(Bin). The input Bin must be 128r | ||
274 | * bytes in length; the output Bout must also be the same size. | ||
275 | */ | ||
276 | static void blockmix_salsa8( | ||
277 | const salsa20_blk_t *restrict Bin, | ||
278 | salsa20_blk_t *restrict Bout, | ||
279 | size_t r) | ||
280 | { | ||
281 | size_t i; | ||
282 | DECL_X; | ||
283 | |||
284 | READ_X(Bin[r * 2 - 1]); | ||
285 | for (i = 0; i < r; i++) { | ||
286 | SALSA20_8_XOR_MEM(Bin[i * 2], Bout[i]); | ||
287 | SALSA20_8_XOR_MEM(Bin[i * 2 + 1], Bout[r + i]); | ||
288 | } | ||
289 | } | ||
290 | |||
291 | static uint32_t blockmix_salsa8_xor( | ||
292 | const salsa20_blk_t *restrict Bin1, | ||
293 | const salsa20_blk_t *restrict Bin2, | ||
294 | salsa20_blk_t *restrict Bout, | ||
295 | size_t r) | ||
296 | { | ||
297 | size_t i; | ||
298 | DECL_X; | ||
299 | |||
300 | XOR_X_2(Bin1[r * 2 - 1], Bin2[r * 2 - 1]); | ||
301 | for (i = 0; i < r; i++) { | ||
302 | XOR_X(Bin1[i * 2]); | ||
303 | SALSA20_8_XOR_MEM(Bin2[i * 2], Bout[i]); | ||
304 | XOR_X(Bin1[i * 2 + 1]); | ||
305 | SALSA20_8_XOR_MEM(Bin2[i * 2 + 1], Bout[r + i]); | ||
306 | } | ||
307 | |||
308 | return INTEGERIFY; | ||
309 | } | ||
310 | |||
311 | /* This is tunable */ | ||
312 | #define Swidth 8 | ||
313 | |||
314 | /* Not tunable in this implementation, hard-coded in a few places */ | ||
315 | #define PWXsimple 2 | ||
316 | #define PWXgather 4 | ||
317 | |||
318 | /* Derived values. Not tunable except via Swidth above. */ | ||
319 | #define PWXbytes (PWXgather * PWXsimple * 8) | ||
320 | #define Sbytes (3 * (1 << Swidth) * PWXsimple * 8) | ||
321 | #define Smask (((1 << Swidth) - 1) * PWXsimple * 8) | ||
322 | #define Smask2 (((uint64_t)Smask << 32) | Smask) | ||
323 | |||
324 | #define DECL_SMASK2REG do {} while (0) | ||
325 | #define FORCE_REGALLOC_3 do {} while (0) | ||
326 | #define MAYBE_MEMORY_BARRIER do {} while (0) | ||
327 | |||
328 | #define PWXFORM_SIMD(x0, x1) \ | ||
329 | do { \ | ||
330 | uint64_t x = x0 & Smask2; \ | ||
331 | uint64_t *p0 = (uint64_t *)(S0 + (uint32_t)x); \ | ||
332 | uint64_t *p1 = (uint64_t *)(S1 + (x >> 32)); \ | ||
333 | x0 = ((x0 >> 32) * (uint32_t)x0 + p0[0]) ^ p1[0]; \ | ||
334 | x1 = ((x1 >> 32) * (uint32_t)x1 + p0[1]) ^ p1[1]; \ | ||
335 | } while (0) | ||
336 | |||
337 | #if KDF_UNROLL_PWXFORM_ROUND | ||
338 | #define PWXFORM_ROUND \ | ||
339 | do { \ | ||
340 | PWXFORM_SIMD(X.d[0], X.d[1]); \ | ||
341 | PWXFORM_SIMD(X.d[2], X.d[3]); \ | ||
342 | PWXFORM_SIMD(X.d[4], X.d[5]); \ | ||
343 | PWXFORM_SIMD(X.d[6], X.d[7]); \ | ||
344 | } while (0) | ||
345 | #else | ||
346 | #define PWXFORM_ROUND \ | ||
347 | do { \ | ||
348 | for (int pwxi=0; pwxi<8; pwxi+=2) \ | ||
349 | PWXFORM_SIMD(X.d[pwxi], X.d[pwxi + 1]); \ | ||
350 | } while (0) | ||
351 | #endif | ||
352 | |||
353 | /* | ||
354 | * This offset helps address the 256-byte write block via the single-byte | ||
355 | * displacements encodable in x86(-64) instructions. It is needed because the | ||
356 | * displacements are signed. Without it, we'd get 4-byte displacements for | ||
357 | * half of the writes. Setting it to 0x80 instead of 0x7c would avoid needing | ||
358 | * a displacement for one of the writes, but then the LEA instruction would | ||
359 | * need a 4-byte displacement. | ||
360 | */ | ||
361 | #define PWXFORM_WRITE_OFFSET 0x7c | ||
362 | |||
363 | #define PWXFORM_WRITE \ | ||
364 | do { \ | ||
365 | WRITE_X(*(salsa20_blk_t *)(Sw - PWXFORM_WRITE_OFFSET)); \ | ||
366 | Sw += 64; \ | ||
367 | } while (0) | ||
368 | |||
369 | #if KDF_UNROLL_PWXFORM | ||
370 | #define PWXFORM \ | ||
371 | do { \ | ||
372 | uint8_t *Sw = S2 + w + PWXFORM_WRITE_OFFSET; \ | ||
373 | FORCE_REGALLOC_3; \ | ||
374 | MAYBE_MEMORY_BARRIER; \ | ||
375 | PWXFORM_ROUND; \ | ||
376 | PWXFORM_ROUND; PWXFORM_WRITE; \ | ||
377 | PWXFORM_ROUND; PWXFORM_WRITE; \ | ||
378 | PWXFORM_ROUND; PWXFORM_WRITE; \ | ||
379 | PWXFORM_ROUND; PWXFORM_WRITE; \ | ||
380 | PWXFORM_ROUND; \ | ||
381 | w = (w + 64 * 4) & Smask2; \ | ||
382 | { \ | ||
383 | uint8_t *Stmp = S2; \ | ||
384 | S2 = S1; \ | ||
385 | S1 = S0; \ | ||
386 | S0 = Stmp; \ | ||
387 | } \ | ||
388 | } while (0) | ||
389 | #else | ||
390 | #define PWXFORM \ | ||
391 | do { \ | ||
392 | uint8_t *Sw = S2 + w + PWXFORM_WRITE_OFFSET; \ | ||
393 | FORCE_REGALLOC_3; \ | ||
394 | MAYBE_MEMORY_BARRIER; \ | ||
395 | PWXFORM_ROUND; \ | ||
396 | for (int pwxj=0; pwxj<4; pwxj++) {\ | ||
397 | PWXFORM_ROUND; PWXFORM_WRITE; \ | ||
398 | } \ | ||
399 | PWXFORM_ROUND; \ | ||
400 | w = (w + 64 * 4) & Smask2; \ | ||
401 | { \ | ||
402 | uint8_t *Stmp = S2; \ | ||
403 | S2 = S1; \ | ||
404 | S1 = S0; \ | ||
405 | S0 = Stmp; \ | ||
406 | } \ | ||
407 | } while (0) | ||
408 | #endif | ||
409 | |||
410 | typedef struct { | ||
411 | uint8_t *S0, *S1, *S2; | ||
412 | size_t w; | ||
413 | } pwxform_ctx_t; | ||
414 | |||
415 | #define Salloc (Sbytes + ((sizeof(pwxform_ctx_t) + 63) & ~63U)) | ||
416 | |||
417 | /** | ||
418 | * blockmix_pwxform(Bin, Bout, r, S): | ||
419 | * Compute Bout = BlockMix_pwxform{salsa20/2, r, S}(Bin). The input Bin must | ||
420 | * be 128r bytes in length; the output Bout must also be the same size. | ||
421 | */ | ||
422 | static void blockmix( | ||
423 | const salsa20_blk_t *restrict Bin, | ||
424 | salsa20_blk_t *restrict Bout, | ||
425 | size_t r, | ||
426 | pwxform_ctx_t *restrict ctx) | ||
427 | { | ||
428 | uint8_t *S0 = ctx->S0, *S1 = ctx->S1, *S2 = ctx->S2; | ||
429 | size_t w = ctx->w; | ||
430 | size_t i; | ||
431 | DECL_X; | ||
432 | |||
433 | /* Convert count of 128-byte blocks to max index of 64-byte block */ | ||
434 | r = r * 2 - 1; | ||
435 | |||
436 | READ_X(Bin[r]); | ||
437 | |||
438 | DECL_SMASK2REG; | ||
439 | |||
440 | i = 0; | ||
441 | for (;;) { | ||
442 | XOR_X(Bin[i]); | ||
443 | PWXFORM; | ||
444 | if (unlikely(i >= r)) | ||
445 | break; | ||
446 | WRITE_X(Bout[i]); | ||
447 | i++; | ||
448 | } | ||
449 | |||
450 | ctx->S0 = S0; | ||
451 | ctx->S1 = S1; | ||
452 | ctx->S2 = S2; | ||
453 | ctx->w = w; | ||
454 | |||
455 | SALSA20_2(Bout[i]); | ||
456 | } | ||
457 | |||
458 | static uint32_t blockmix_xor( | ||
459 | const salsa20_blk_t *Bin1, | ||
460 | const salsa20_blk_t *restrict Bin2, | ||
461 | salsa20_blk_t *Bout, | ||
462 | size_t r, | ||
463 | pwxform_ctx_t *restrict ctx) | ||
464 | { | ||
465 | uint8_t *S0 = ctx->S0, *S1 = ctx->S1, *S2 = ctx->S2; | ||
466 | size_t w = ctx->w; | ||
467 | size_t i; | ||
468 | DECL_X; | ||
469 | |||
470 | /* Convert count of 128-byte blocks to max index of 64-byte block */ | ||
471 | r = r * 2 - 1; | ||
472 | |||
473 | XOR_X_2(Bin1[r], Bin2[r]); | ||
474 | |||
475 | DECL_SMASK2REG; | ||
476 | |||
477 | i = 0; | ||
478 | r--; | ||
479 | for (;;) { | ||
480 | XOR_X(Bin1[i]); | ||
481 | XOR_X(Bin2[i]); | ||
482 | PWXFORM; | ||
483 | if (unlikely(i > r)) | ||
484 | break; | ||
485 | WRITE_X(Bout[i]); | ||
486 | i++; | ||
487 | } | ||
488 | |||
489 | ctx->S0 = S0; | ||
490 | ctx->S1 = S1; | ||
491 | ctx->S2 = S2; | ||
492 | ctx->w = w; | ||
493 | |||
494 | SALSA20_2(Bout[i]); | ||
495 | |||
496 | return INTEGERIFY; | ||
497 | } | ||
498 | |||
499 | static uint32_t blockmix_xor_save( | ||
500 | salsa20_blk_t *restrict Bin1out, | ||
501 | salsa20_blk_t *restrict Bin2, | ||
502 | size_t r, | ||
503 | pwxform_ctx_t *restrict ctx) | ||
504 | { | ||
505 | uint8_t *S0 = ctx->S0, *S1 = ctx->S1, *S2 = ctx->S2; | ||
506 | size_t w = ctx->w; | ||
507 | size_t i; | ||
508 | DECL_X; | ||
509 | DECL_Y; | ||
510 | |||
511 | /* Convert count of 128-byte blocks to max index of 64-byte block */ | ||
512 | r = r * 2 - 1; | ||
513 | |||
514 | XOR_X_2(Bin1out[r], Bin2[r]); | ||
515 | |||
516 | DECL_SMASK2REG; | ||
517 | |||
518 | i = 0; | ||
519 | r--; | ||
520 | for (;;) { | ||
521 | XOR_X_WRITE_XOR_Y_2(Bin2[i], Bin1out[i]); | ||
522 | PWXFORM; | ||
523 | if (unlikely(i > r)) | ||
524 | break; | ||
525 | WRITE_X(Bin1out[i]); | ||
526 | i++; | ||
527 | } | ||
528 | |||
529 | ctx->S0 = S0; | ||
530 | ctx->S1 = S1; | ||
531 | ctx->S2 = S2; | ||
532 | ctx->w = w; | ||
533 | |||
534 | SALSA20_2(Bin1out[i]); | ||
535 | |||
536 | return INTEGERIFY; | ||
537 | } | ||
538 | |||
539 | /** | ||
540 | * integerify(B, r): | ||
541 | * Return the result of parsing B_{2r-1} as a little-endian integer. | ||
542 | */ | ||
543 | static inline uint32_t integerify(const salsa20_blk_t *B, size_t r) | ||
544 | { | ||
545 | /* | ||
546 | * Our 64-bit words are in host byte order, which is why we don't just read | ||
547 | * w[0] here (would be wrong on big-endian). Also, our 32-bit words are | ||
548 | * SIMD-shuffled (so the next 32 bits would be part of d[6]), but currently | ||
549 | * this does not matter as we only care about the least significant 32 bits. | ||
550 | */ | ||
551 | return (uint32_t)B[2 * r - 1].d[0]; | ||
552 | } | ||
553 | |||
554 | /** | ||
555 | * smix1(B, r, N, flags, V, NROM, VROM, XY, ctx): | ||
556 | * Compute first loop of B = SMix_r(B, N). The input B must be 128r bytes in | ||
557 | * length; the temporary storage V must be 128rN bytes in length; the temporary | ||
558 | * storage XY must be 128r+64 bytes in length. N must be even and at least 4. | ||
559 | * The array V must be aligned to a multiple of 64 bytes, and arrays B and XY | ||
560 | * to a multiple of at least 16 bytes. | ||
561 | */ | ||
562 | #if DISABLE_NROM_CODE | ||
563 | #define smix1(B,r,N,flags,V,NROM,VROM,XY,ctx) \ | ||
564 | smix1(B,r,N,flags,V,XY,ctx) | ||
565 | #endif | ||
566 | static void smix1(uint8_t *B, size_t r, uint32_t N, | ||
567 | uint32_t flags, | ||
568 | salsa20_blk_t *V, | ||
569 | uint32_t NROM, const salsa20_blk_t *VROM, | ||
570 | salsa20_blk_t *XY, | ||
571 | pwxform_ctx_t *ctx) | ||
572 | { | ||
573 | #if DISABLE_NROM_CODE | ||
574 | uint32_t NROM = 0; | ||
575 | const salsa20_blk_t *VROM = NULL; | ||
576 | #endif | ||
577 | size_t s = 2 * r; | ||
578 | salsa20_blk_t *X = V, *Y = &V[s]; | ||
579 | uint32_t i, j; | ||
580 | |||
581 | for (i = 0; i < 2 * r; i++) { | ||
582 | const salsa20_blk_t *src = (salsa20_blk_t *)&B[i * 64]; | ||
583 | salsa20_blk_t *tmp = Y; | ||
584 | salsa20_blk_t *dst = &X[i]; | ||
585 | size_t k; | ||
586 | for (k = 0; k < 16; k++) | ||
587 | tmp->w[k] = SWAP_LE32(src->w[k]); | ||
588 | salsa20_simd_shuffle(tmp, dst); | ||
589 | } | ||
590 | |||
591 | if (VROM) { | ||
592 | uint32_t n; | ||
593 | const salsa20_blk_t *V_j; | ||
594 | |||
595 | V_j = &VROM[(NROM - 1) * s]; | ||
596 | j = blockmix_xor(X, V_j, Y, r, ctx) & (NROM - 1); | ||
597 | V_j = &VROM[j * s]; | ||
598 | X = Y + s; | ||
599 | j = blockmix_xor(Y, V_j, X, r, ctx); | ||
600 | |||
601 | for (n = 2; n < N; n <<= 1) { | ||
602 | uint32_t m = (n < N / 2) ? n : (N - 1 - n); | ||
603 | for (i = 1; i < m; i += 2) { | ||
604 | j &= n - 1; | ||
605 | j += i - 1; | ||
606 | V_j = &V[j * s]; | ||
607 | Y = X + s; | ||
608 | j = blockmix_xor(X, V_j, Y, r, ctx) & (NROM - 1); | ||
609 | V_j = &VROM[j * s]; | ||
610 | X = Y + s; | ||
611 | j = blockmix_xor(Y, V_j, X, r, ctx); | ||
612 | } | ||
613 | } | ||
614 | n >>= 1; | ||
615 | |||
616 | j &= n - 1; | ||
617 | j += N - 2 - n; | ||
618 | V_j = &V[j * s]; | ||
619 | Y = X + s; | ||
620 | j = blockmix_xor(X, V_j, Y, r, ctx) & (NROM - 1); | ||
621 | V_j = &VROM[j * s]; | ||
622 | blockmix_xor(Y, V_j, XY, r, ctx); | ||
623 | } else if (flags & YESCRYPT_RW) { | ||
624 | //can't use flags___YESCRYPT_RW, smix1() may be called with flags = 0 | ||
625 | uint32_t n; | ||
626 | salsa20_blk_t *V_j; | ||
627 | |||
628 | blockmix(X, Y, r, ctx); | ||
629 | X = Y + s; | ||
630 | blockmix(Y, X, r, ctx); | ||
631 | j = integerify(X, r); | ||
632 | |||
633 | for (n = 2; n < N; n <<= 1) { | ||
634 | uint32_t m = (n < N / 2) ? n : (N - 1 - n); | ||
635 | for (i = 1; i < m; i += 2) { | ||
636 | Y = X + s; | ||
637 | j &= n - 1; | ||
638 | j += i - 1; | ||
639 | V_j = &V[j * s]; | ||
640 | j = blockmix_xor(X, V_j, Y, r, ctx); | ||
641 | j &= n - 1; | ||
642 | j += i; | ||
643 | V_j = &V[j * s]; | ||
644 | X = Y + s; | ||
645 | j = blockmix_xor(Y, V_j, X, r, ctx); | ||
646 | } | ||
647 | } | ||
648 | n >>= 1; | ||
649 | |||
650 | j &= n - 1; | ||
651 | j += N - 2 - n; | ||
652 | V_j = &V[j * s]; | ||
653 | Y = X + s; | ||
654 | j = blockmix_xor(X, V_j, Y, r, ctx); | ||
655 | j &= n - 1; | ||
656 | j += N - 1 - n; | ||
657 | V_j = &V[j * s]; | ||
658 | blockmix_xor(Y, V_j, XY, r, ctx); | ||
659 | } else { | ||
660 | N -= 2; | ||
661 | do { | ||
662 | blockmix_salsa8(X, Y, r); | ||
663 | X = Y + s; | ||
664 | blockmix_salsa8(Y, X, r); | ||
665 | Y = X + s; | ||
666 | } while ((N -= 2)); | ||
667 | |||
668 | blockmix_salsa8(X, Y, r); | ||
669 | blockmix_salsa8(Y, XY, r); | ||
670 | } | ||
671 | |||
672 | for (i = 0; i < 2 * r; i++) { | ||
673 | const salsa20_blk_t *src = &XY[i]; | ||
674 | salsa20_blk_t *tmp = &XY[s]; | ||
675 | salsa20_blk_t *dst = (salsa20_blk_t *)&B[i * 64]; | ||
676 | size_t k; | ||
677 | for (k = 0; k < 16; k++) | ||
678 | tmp->w[k] = SWAP_LE32(src->w[k]); | ||
679 | salsa20_simd_unshuffle(tmp, dst); | ||
680 | } | ||
681 | } | ||
682 | |||
683 | /** | ||
684 | * smix2(B, r, N, Nloop, flags, V, NROM, VROM, XY, ctx): | ||
685 | * Compute second loop of B = SMix_r(B, N). The input B must be 128r bytes in | ||
686 | * length; the temporary storage V must be 128rN bytes in length; the temporary | ||
687 | * storage XY must be 256r bytes in length. N must be a power of 2 and at | ||
688 | * least 2. Nloop must be even. The array V must be aligned to a multiple of | ||
689 | * 64 bytes, and arrays B and XY to a multiple of at least 16 bytes. | ||
690 | */ | ||
691 | #if DISABLE_NROM_CODE | ||
692 | #define smix2(B,r,N,Nloop,flags,V,NROM,VROM,XY,ctx) \ | ||
693 | smix2(B,r,N,Nloop,flags,V,XY,ctx) | ||
694 | #endif | ||
695 | static void smix2(uint8_t *B, size_t r, uint32_t N, uint64_t Nloop, | ||
696 | uint32_t flags, | ||
697 | salsa20_blk_t *V, | ||
698 | uint32_t NROM, const salsa20_blk_t *VROM, | ||
699 | salsa20_blk_t *XY, | ||
700 | pwxform_ctx_t *ctx) | ||
701 | { | ||
702 | #if DISABLE_NROM_CODE | ||
703 | uint32_t NROM = 0; | ||
704 | const salsa20_blk_t *VROM = NULL; | ||
705 | #endif | ||
706 | size_t s = 2 * r; | ||
707 | salsa20_blk_t *X = XY, *Y = &XY[s]; | ||
708 | uint32_t i, j; | ||
709 | |||
710 | if (Nloop == 0) | ||
711 | return; | ||
712 | |||
713 | for (i = 0; i < 2 * r; i++) { | ||
714 | const salsa20_blk_t *src = (salsa20_blk_t *)&B[i * 64]; | ||
715 | salsa20_blk_t *tmp = Y; | ||
716 | salsa20_blk_t *dst = &X[i]; | ||
717 | size_t k; | ||
718 | for (k = 0; k < 16; k++) | ||
719 | tmp->w[k] = SWAP_LE32(src->w[k]); | ||
720 | salsa20_simd_shuffle(tmp, dst); | ||
721 | } | ||
722 | |||
723 | j = integerify(X, r) & (N - 1); | ||
724 | |||
725 | /* | ||
726 | * Normally, VROM implies YESCRYPT_RW, but we check for these separately | ||
727 | * because our SMix resets YESCRYPT_RW for the smix2() calls operating on the | ||
728 | * entire V when p > 1. | ||
729 | */ | ||
730 | //and this is why bbox can't use flags___YESCRYPT_RW in this function | ||
731 | if (VROM && (flags & YESCRYPT_RW)) { | ||
732 | do { | ||
733 | salsa20_blk_t *V_j = &V[j * s]; | ||
734 | const salsa20_blk_t *VROM_j; | ||
735 | j = blockmix_xor_save(X, V_j, r, ctx) & (NROM - 1); | ||
736 | VROM_j = &VROM[j * s]; | ||
737 | j = blockmix_xor(X, VROM_j, X, r, ctx) & (N - 1); | ||
738 | } while (Nloop -= 2); | ||
739 | } else if (VROM) { | ||
740 | do { | ||
741 | const salsa20_blk_t *V_j = &V[j * s]; | ||
742 | j = blockmix_xor(X, V_j, X, r, ctx) & (NROM - 1); | ||
743 | V_j = &VROM[j * s]; | ||
744 | j = blockmix_xor(X, V_j, X, r, ctx) & (N - 1); | ||
745 | } while (Nloop -= 2); | ||
746 | } else if (flags & YESCRYPT_RW) { | ||
747 | do { | ||
748 | salsa20_blk_t *V_j = &V[j * s]; | ||
749 | j = blockmix_xor_save(X, V_j, r, ctx) & (N - 1); | ||
750 | V_j = &V[j * s]; | ||
751 | j = blockmix_xor_save(X, V_j, r, ctx) & (N - 1); | ||
752 | } while (Nloop -= 2); | ||
753 | } else if (ctx) { | ||
754 | do { | ||
755 | const salsa20_blk_t *V_j = &V[j * s]; | ||
756 | j = blockmix_xor(X, V_j, X, r, ctx) & (N - 1); | ||
757 | V_j = &V[j * s]; | ||
758 | j = blockmix_xor(X, V_j, X, r, ctx) & (N - 1); | ||
759 | } while (Nloop -= 2); | ||
760 | } else { | ||
761 | do { | ||
762 | const salsa20_blk_t *V_j = &V[j * s]; | ||
763 | j = blockmix_salsa8_xor(X, V_j, Y, r) & (N - 1); | ||
764 | V_j = &V[j * s]; | ||
765 | j = blockmix_salsa8_xor(Y, V_j, X, r) & (N - 1); | ||
766 | } while (Nloop -= 2); | ||
767 | } | ||
768 | |||
769 | for (i = 0; i < 2 * r; i++) { | ||
770 | const salsa20_blk_t *src = &X[i]; | ||
771 | salsa20_blk_t *tmp = Y; | ||
772 | salsa20_blk_t *dst = (salsa20_blk_t *)&B[i * 64]; | ||
773 | size_t k; | ||
774 | for (k = 0; k < 16; k++) | ||
775 | tmp->w[k] = SWAP_LE32(src->w[k]); | ||
776 | salsa20_simd_unshuffle(tmp, dst); | ||
777 | } | ||
778 | } | ||
779 | |||
780 | /** | ||
781 | * p2floor(x): | ||
782 | * Largest power of 2 not greater than argument. | ||
783 | */ | ||
784 | static uint64_t p2floor(uint64_t x) | ||
785 | { | ||
786 | uint64_t y; | ||
787 | while ((y = x & (x - 1))) | ||
788 | x = y; | ||
789 | return x; | ||
790 | } | ||
791 | |||
792 | /** | ||
793 | * smix(B, r, N, p, t, flags, V, NROM, VROM, XY, S, passwd): | ||
794 | * Compute B = SMix_r(B, N). The input B must be 128rp bytes in length; the | ||
795 | * temporary storage V must be 128rN bytes in length; the temporary storage | ||
796 | * XY must be 256r or 256rp bytes in length (the larger size is required with | ||
797 | * OpenMP-enabled builds). N must be a power of 2 and at least 4. The array V | ||
798 | * must be aligned to a multiple of 64 bytes, and arrays B and XY to a multiple | ||
799 | * of at least 16 bytes (aligning them to 64 bytes as well saves cache lines | ||
800 | * and helps avoid false sharing in OpenMP-enabled builds when p > 1, but it | ||
801 | * might also result in cache bank conflicts). | ||
802 | */ | ||
803 | #if DISABLE_NROM_CODE | ||
804 | #define smix(B,r,N,p,t,flags,V,NROM,VROM,XY,S,passwd) \ | ||
805 | smix(B,r,N,p,t,flags,V,XY,S,passwd) | ||
806 | #endif | ||
807 | static void smix(uint8_t *B, size_t r, uint32_t N, uint32_t p, uint32_t t, | ||
808 | uint32_t flags, | ||
809 | salsa20_blk_t *V, | ||
810 | uint32_t NROM, const salsa20_blk_t *VROM, | ||
811 | salsa20_blk_t *XY, | ||
812 | uint8_t *S, uint8_t *passwd) | ||
813 | { | ||
814 | size_t s = 2 * r; | ||
815 | uint32_t Nchunk; | ||
816 | uint64_t Nloop_all, Nloop_rw; | ||
817 | uint32_t i; | ||
818 | |||
819 | Nchunk = N / p; | ||
820 | Nloop_all = Nchunk; | ||
821 | if (flags___YESCRYPT_RW) { | ||
822 | if (t <= 1) { | ||
823 | if (t) | ||
824 | Nloop_all *= 2; /* 2/3 */ | ||
825 | Nloop_all = (Nloop_all + 2) / 3; /* 1/3, round up */ | ||
826 | } else { | ||
827 | Nloop_all *= t - 1; | ||
828 | } | ||
829 | } else if (t) { | ||
830 | if (t == 1) | ||
831 | Nloop_all += (Nloop_all + 1) / 2; /* 1.5, round up */ | ||
832 | Nloop_all *= t; | ||
833 | } | ||
834 | |||
835 | Nloop_rw = 0; | ||
836 | if (flags___YESCRYPT_RW) | ||
837 | Nloop_rw = Nloop_all / p; | ||
838 | |||
839 | Nchunk &= ~(uint32_t)1; /* round down to even */ | ||
840 | Nloop_all++; Nloop_all &= ~(uint64_t)1; /* round up to even */ | ||
841 | Nloop_rw++; Nloop_rw &= ~(uint64_t)1; /* round up to even */ | ||
842 | |||
843 | for (i = 0; i < p; i++) { | ||
844 | uint32_t Vchunk = i * Nchunk; | ||
845 | uint32_t Np = (i < p - 1) ? Nchunk : (N - Vchunk); | ||
846 | uint8_t *Bp = &B[128 * r * i]; | ||
847 | salsa20_blk_t *Vp = &V[Vchunk * s]; | ||
848 | salsa20_blk_t *XYp = XY; | ||
849 | pwxform_ctx_t *ctx_i = NULL; | ||
850 | if (flags___YESCRYPT_RW) { | ||
851 | uint8_t *Si = S + i * Salloc; | ||
852 | smix1(Bp, 1, Sbytes / 128, 0 /* no flags */, | ||
853 | (salsa20_blk_t *)Si, 0, NULL, XYp, NULL); | ||
854 | ctx_i = (pwxform_ctx_t *)(Si + Sbytes); | ||
855 | ctx_i->S2 = Si; | ||
856 | ctx_i->S1 = Si + Sbytes / 3; | ||
857 | ctx_i->S0 = Si + Sbytes / 3 * 2; | ||
858 | ctx_i->w = 0; | ||
859 | if (i == 0) | ||
860 | hmac_block( | ||
861 | /* key,len: */ Bp + (128 * r - 64), 64, | ||
862 | /* hash fn: */ sha256_begin, | ||
863 | /* in,len: */ passwd, 32, | ||
864 | /* outbuf: */ passwd | ||
865 | ); | ||
866 | } | ||
867 | smix1(Bp, r, Np, flags, Vp, NROM, VROM, XYp, ctx_i); | ||
868 | smix2(Bp, r, p2floor(Np), Nloop_rw, flags, Vp, | ||
869 | NROM, VROM, XYp, ctx_i); | ||
870 | } | ||
871 | |||
872 | if (Nloop_all > Nloop_rw) { | ||
873 | for (i = 0; i < p; i++) { | ||
874 | uint8_t *Bp = &B[128 * r * i]; | ||
875 | salsa20_blk_t *XYp = XY; | ||
876 | pwxform_ctx_t *ctx_i = NULL; | ||
877 | if (flags___YESCRYPT_RW) { | ||
878 | uint8_t *Si = S + i * Salloc; | ||
879 | ctx_i = (pwxform_ctx_t *)(Si + Sbytes); | ||
880 | } | ||
881 | smix2(Bp, r, N, Nloop_all - Nloop_rw, | ||
882 | flags & (uint32_t)~YESCRYPT_RW, | ||
883 | V, NROM, VROM, XYp, ctx_i); | ||
884 | } | ||
885 | } | ||
886 | } | ||
887 | |||
888 | /* Allocator code */ | ||
889 | |||
890 | static void alloc_region(yescrypt_region_t *region, size_t size) | ||
891 | { | ||
892 | uint8_t *base; | ||
893 | int flags = | ||
894 | # ifdef MAP_NOCORE /* huh? */ | ||
895 | MAP_NOCORE | | ||
896 | # endif | ||
897 | MAP_ANON | MAP_PRIVATE; | ||
898 | |||
899 | base = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0); | ||
900 | if (base == MAP_FAILED) | ||
901 | bb_die_memory_exhausted(); | ||
902 | |||
903 | #if defined(MADV_HUGEPAGE) | ||
904 | /* Reduces mkpasswd qweRTY123@-+ '$y$jHT$123' | ||
905 | * (which allocates 4 Gbytes) | ||
906 | * run time from 10.543s to 5.635s | ||
907 | * Seen on linux-5.18.0. | ||
908 | */ | ||
909 | madvise(base, size, MADV_HUGEPAGE); | ||
910 | #endif | ||
911 | //region->base = base; | ||
912 | //region->base_size = size; | ||
913 | region->aligned = base; | ||
914 | region->aligned_size = size; | ||
915 | } | ||
916 | |||
917 | static void free_region(yescrypt_region_t *region) | ||
918 | { | ||
919 | if (region->aligned) | ||
920 | munmap(region->aligned, region->aligned_size); | ||
921 | //region->base = NULL; | ||
922 | //region->base_size = 0; | ||
923 | region->aligned = NULL; | ||
924 | region->aligned_size = 0; | ||
925 | } | ||
926 | /** | ||
927 | * yescrypt_kdf_body(shared, local, passwd, passwdlen, salt, saltlen, | ||
928 | * flags, N, r, p, t, NROM, buf, buflen): | ||
929 | * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, | ||
930 | * p, buflen), or a revision of scrypt as requested by flags and shared, and | ||
931 | * write the result into buf. | ||
932 | * | ||
933 | * shared and flags may request special modes as described in yescrypt.h. | ||
934 | * | ||
935 | * local is the thread-local data structure, allowing to preserve and reuse a | ||
936 | * memory allocation across calls, thereby reducing its overhead. | ||
937 | * | ||
938 | * t controls computation time while not affecting peak memory usage. | ||
939 | * | ||
940 | * Return 0 on success; or -1 on error. | ||
941 | * | ||
942 | * This optimized implementation currently limits N to the range from 4 to | ||
943 | * 2^31, but other implementations might not. | ||
944 | */ | ||
945 | static int yescrypt_kdf32_body( | ||
946 | yescrypt_ctx_t *yctx, | ||
947 | const uint8_t *passwd, size_t passwdlen, | ||
948 | uint32_t flags, uint64_t N, uint32_t t, | ||
949 | uint8_t *buf32) | ||
950 | { | ||
951 | #if !DISABLE_NROM_CODE | ||
952 | const salsa20_blk_t *VROM; | ||
953 | #endif | ||
954 | size_t B_size, V_size, XY_size, need; | ||
955 | uint8_t *B, *S; | ||
956 | salsa20_blk_t *V, *XY; | ||
957 | struct { | ||
958 | uint8_t sha256[32]; | ||
959 | uint8_t dk[32]; | ||
960 | } u; | ||
961 | #define sha256 u.sha256 | ||
962 | #define dk u.dk | ||
963 | uint8_t *dkp = buf32; | ||
964 | uint32_t r, p; | ||
965 | |||
966 | /* Sanity-check parameters */ | ||
967 | switch (flags___YESCRYPT_MODE_MASK) { | ||
968 | case 0: /* classic scrypt - can't have anything non-standard */ | ||
969 | if (flags || t || YCTX_param_NROM) | ||
970 | goto out_EINVAL; | ||
971 | break; | ||
972 | case YESCRYPT_WORM: | ||
973 | if (flags != YESCRYPT_WORM || YCTX_param_NROM) | ||
974 | goto out_EINVAL; | ||
975 | break; | ||
976 | case YESCRYPT_RW: | ||
977 | if (flags != (flags & YESCRYPT_KNOWN_FLAGS)) | ||
978 | goto out_EINVAL; | ||
979 | #if PWXsimple == 2 && PWXgather == 4 && Sbytes == 12288 | ||
980 | if ((flags & YESCRYPT_RW_FLAVOR_MASK) == | ||
981 | (YESCRYPT_ROUNDS_6 | YESCRYPT_GATHER_4 | | ||
982 | YESCRYPT_SIMPLE_2 | YESCRYPT_SBOX_12K)) | ||
983 | break; | ||
984 | #else | ||
985 | #error "Unsupported pwxform settings" | ||
986 | #endif | ||
987 | /* FALLTHRU */ | ||
988 | default: | ||
989 | goto out_EINVAL; | ||
990 | } | ||
991 | |||
992 | r = YCTX_param_r; | ||
993 | p = YCTX_param_p; | ||
994 | if ((uint64_t)r * (uint64_t)p >= 1 << 30) { | ||
995 | dbg("r * n >= 2^30"); | ||
996 | goto out_EINVAL; | ||
997 | } | ||
998 | if (N > UINT32_MAX) { | ||
999 | dbg("N > 0x%lx", (long)UINT32_MAX); | ||
1000 | goto out_EINVAL; | ||
1001 | } | ||
1002 | if (N <= 3 | ||
1003 | || r < 1 | ||
1004 | || p < 1 | ||
1005 | ) { | ||
1006 | dbg("bad N, r or p"); | ||
1007 | goto out_EINVAL; | ||
1008 | } | ||
1009 | if (r > SIZE_MAX / 256 / p | ||
1010 | || N > SIZE_MAX / 128 / r | ||
1011 | ) { | ||
1012 | /* 32-bit testcase: mkpasswd qweRTY123@-+ '$y$jHT$123' | ||
1013 | * (works on 64-bit, needs buffer > 4Gbytes) | ||
1014 | */ | ||
1015 | dbg("r > SIZE_MAX / 256 / p? %c", "NY"[r > SIZE_MAX / 256 / p]); | ||
1016 | dbg("N > SIZE_MAX / 128 / r? %c", "NY"[N > SIZE_MAX / 128 / r]); | ||
1017 | goto out_EINVAL; | ||
1018 | } | ||
1019 | if (flags___YESCRYPT_RW) { | ||
1020 | /* p cannot be greater than SIZE_MAX/Salloc on 64-bit systems, | ||
1021 | but it can on 32-bit systems. */ | ||
1022 | #pragma GCC diagnostic push | ||
1023 | #pragma GCC diagnostic ignored "-Wtype-limits" | ||
1024 | if (N / p <= 3 || p > SIZE_MAX / Salloc) { | ||
1025 | dbg("bad p:%ld", (long)p); | ||
1026 | goto out_EINVAL; | ||
1027 | } | ||
1028 | #pragma GCC diagnostic pop | ||
1029 | } | ||
1030 | |||
1031 | #if !DISABLE_NROM_CODE | ||
1032 | VROM = NULL; | ||
1033 | if (YCTX_param_NROM) | ||
1034 | goto out_EINVAL; | ||
1035 | #endif | ||
1036 | |||
1037 | /* Allocate memory */ | ||
1038 | V = NULL; | ||
1039 | V_size = (size_t)128 * r * N; | ||
1040 | need = V_size; | ||
1041 | B_size = (size_t)128 * r * p; | ||
1042 | need += B_size; | ||
1043 | if (need < B_size) { | ||
1044 | dbg("integer overflow at += B_size(%lu)", (long)B_size); | ||
1045 | goto out_EINVAL; | ||
1046 | } | ||
1047 | XY_size = (size_t)256 * r; | ||
1048 | need += XY_size; | ||
1049 | if (need < XY_size) { | ||
1050 | dbg("integer overflow at += XY_size(%lu)", (long)XY_size); | ||
1051 | goto out_EINVAL; | ||
1052 | } | ||
1053 | if (flags___YESCRYPT_RW) { | ||
1054 | size_t S_size = (size_t)Salloc * p; | ||
1055 | need += S_size; | ||
1056 | if (need < S_size) { | ||
1057 | dbg("integer overflow at += S_size(%lu)", (long)S_size); | ||
1058 | goto out_EINVAL; | ||
1059 | } | ||
1060 | } | ||
1061 | if (yctx->local->aligned_size < need) { | ||
1062 | free_region(yctx->local); | ||
1063 | alloc_region(yctx->local, need); | ||
1064 | dbg("allocated local:%lu 0x%lx", (long)need, (long)need); | ||
1065 | /* standard "j9T" params allocate 16Mbytes here */ | ||
1066 | } | ||
1067 | if (flags & YESCRYPT_ALLOC_ONLY) | ||
1068 | return -3; /* expected "failure" */ | ||
1069 | B = (uint8_t *)yctx->local->aligned; | ||
1070 | V = (salsa20_blk_t *)((uint8_t *)B + B_size); | ||
1071 | XY = (salsa20_blk_t *)((uint8_t *)V + V_size); | ||
1072 | S = NULL; | ||
1073 | if (flags___YESCRYPT_RW) | ||
1074 | S = (uint8_t *)XY + XY_size; | ||
1075 | |||
1076 | if (flags) { | ||
1077 | hmac_block( | ||
1078 | /* key,len: */ (const void*)"yescrypt-prehash", (flags & YESCRYPT_PREHASH) ? 16 : 8, | ||
1079 | /* hash fn: */ sha256_begin, | ||
1080 | /* in,len: */ passwd, passwdlen, | ||
1081 | /* outbuf: */ sha256 | ||
1082 | ); | ||
1083 | passwd = sha256; | ||
1084 | passwdlen = sizeof(sha256); | ||
1085 | } | ||
1086 | |||
1087 | PBKDF2_SHA256(passwd, passwdlen, yctx->salt, yctx->saltlen, 1, B, B_size); | ||
1088 | |||
1089 | if (flags) | ||
1090 | memcpy(sha256, B, sizeof(sha256)); | ||
1091 | |||
1092 | if (p == 1 || (flags___YESCRYPT_RW)) { | ||
1093 | smix(B, r, N, p, t, flags, V, YCTX_param_NROM, VROM, XY, S, sha256); | ||
1094 | } else { | ||
1095 | uint32_t i; | ||
1096 | for (i = 0; i < p; i++) { | ||
1097 | smix(&B[(size_t)128 * r * i], r, N, 1, t, flags, V, | ||
1098 | YCTX_param_NROM, VROM, XY, NULL, NULL); | ||
1099 | } | ||
1100 | } | ||
1101 | |||
1102 | dkp = buf32; | ||
1103 | if (flags && /*buflen:*/32 < sizeof(dk)) { | ||
1104 | PBKDF2_SHA256(passwd, passwdlen, B, B_size, 1, dk, sizeof(dk)); | ||
1105 | dkp = dk; | ||
1106 | } | ||
1107 | |||
1108 | PBKDF2_SHA256(passwd, passwdlen, B, B_size, 1, buf32, /*buflen:*/32); | ||
1109 | |||
1110 | /* | ||
1111 | * Except when computing classic scrypt, allow all computation so far | ||
1112 | * to be performed on the client. The final steps below match those of | ||
1113 | * SCRAM (RFC 5802), so that an extension of SCRAM (with the steps so | ||
1114 | * far in place of SCRAM's use of PBKDF2 and with SHA-256 in place of | ||
1115 | * SCRAM's use of SHA-1) would be usable with yescrypt hashes. | ||
1116 | */ | ||
1117 | if (flags && !(flags & YESCRYPT_PREHASH)) { | ||
1118 | /* Compute ClientKey */ | ||
1119 | hmac_block( | ||
1120 | /* key,len: */ dkp, sizeof(dk), | ||
1121 | /* hash fn: */ sha256_begin, | ||
1122 | /* in,len: */ "Client Key", 10, | ||
1123 | /* outbuf: */ sha256 | ||
1124 | ); | ||
1125 | /* Compute StoredKey */ | ||
1126 | { | ||
1127 | size_t clen = /*buflen:*/32; | ||
1128 | if (clen > sizeof(dk)) | ||
1129 | clen = sizeof(dk); | ||
1130 | if (sizeof(dk) != 32) { /* not true, optimize it out */ | ||
1131 | sha256_block(sha256, sizeof(sha256), dk); | ||
1132 | memcpy(buf32, dk, clen); | ||
1133 | } else { | ||
1134 | sha256_block(sha256, sizeof(sha256), buf32); | ||
1135 | } | ||
1136 | } | ||
1137 | } | ||
1138 | |||
1139 | explicit_bzero(&u, sizeof(u)); | ||
1140 | |||
1141 | /* Success! */ | ||
1142 | return 0; | ||
1143 | |||
1144 | out_EINVAL: | ||
1145 | //bbox does not need this: errno = EINVAL; | ||
1146 | return -1; | ||
1147 | #undef sha256 | ||
1148 | #undef dk | ||
1149 | } | ||
1150 | |||
1151 | /** | ||
1152 | * yescrypt_kdf(shared, local, passwd, passwdlen, salt, saltlen, params, | ||
1153 | * buf, buflen): | ||
1154 | * Compute scrypt or its revision as requested by the parameters. The inputs | ||
1155 | * to this function are the same as those for yescrypt_kdf_body() above, with | ||
1156 | * the addition of g, which controls hash upgrades (0 for no upgrades so far). | ||
1157 | */ | ||
1158 | static | ||
1159 | int yescrypt_kdf32( | ||
1160 | yescrypt_ctx_t *yctx, | ||
1161 | const uint8_t *passwd, size_t passwdlen, | ||
1162 | uint8_t *buf32) | ||
1163 | { | ||
1164 | uint32_t flags = YCTX_param_flags; | ||
1165 | uint64_t N = YCTX_param_N; | ||
1166 | uint32_t r = YCTX_param_r; | ||
1167 | uint32_t p = YCTX_param_p; | ||
1168 | uint32_t t = YCTX_param_t; | ||
1169 | uint32_t g = YCTX_param_g; | ||
1170 | uint8_t dk32[32]; | ||
1171 | int retval; | ||
1172 | |||
1173 | /* Support for hash upgrades has been temporarily removed */ | ||
1174 | if (g) { | ||
1175 | //bbox does not need this: errno = EINVAL; | ||
1176 | return -1; | ||
1177 | } | ||
1178 | |||
1179 | if ((flags___YESCRYPT_RW) | ||
1180 | && p >= 1 | ||
1181 | && N / p >= 0x100 | ||
1182 | && N / p * r >= 0x20000 | ||
1183 | ) { | ||
1184 | if (yescrypt_kdf32_body(yctx, | ||
1185 | passwd, passwdlen, | ||
1186 | flags | YESCRYPT_ALLOC_ONLY, N, t, | ||
1187 | buf32) != -3 | ||
1188 | ) { | ||
1189 | dbg("yescrypt_kdf32_body: not -3"); | ||
1190 | return -1; | ||
1191 | } | ||
1192 | retval = yescrypt_kdf32_body(yctx, | ||
1193 | passwd, passwdlen, | ||
1194 | flags | YESCRYPT_PREHASH, N >> 6, 0, | ||
1195 | dk32); | ||
1196 | if (retval) { | ||
1197 | dbg("yescrypt_kdf32_body(PREHASH):%d", retval); | ||
1198 | return retval; | ||
1199 | } | ||
1200 | passwd = dk32; | ||
1201 | passwdlen = sizeof(dk32); | ||
1202 | } | ||
1203 | |||
1204 | retval = yescrypt_kdf32_body(yctx, | ||
1205 | passwd, passwdlen, | ||
1206 | flags, N, t, buf32); | ||
1207 | |||
1208 | explicit_bzero(dk32, sizeof(dk32)); | ||
1209 | |||
1210 | dbg("yescrypt_kdf32_body:%d", retval); | ||
1211 | return retval; | ||
1212 | } | ||
diff --git a/libbb/yescrypt/alg-yescrypt.h b/libbb/yescrypt/alg-yescrypt.h new file mode 100644 index 000000000..b69843f5d --- /dev/null +++ b/libbb/yescrypt/alg-yescrypt.h | |||
@@ -0,0 +1,247 @@ | |||
1 | /*- | ||
2 | * Copyright 2009 Colin Percival | ||
3 | * Copyright 2013-2018 Alexander Peslyak | ||
4 | * All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * 1. Redistributions of source code must retain the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer. | ||
11 | * 2. Redistributions in binary form must reproduce the above copyright | ||
12 | * notice, this list of conditions and the following disclaimer in the | ||
13 | * documentation and/or other materials provided with the distribution. | ||
14 | * | ||
15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | ||
16 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | ||
19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
23 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
24 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
25 | * SUCH DAMAGE. | ||
26 | * | ||
27 | * This file was originally written by Colin Percival as part of the Tarsnap | ||
28 | * online backup system. | ||
29 | */ | ||
30 | |||
31 | // busybox debug and size-reduction configuration | ||
32 | |||
33 | #ifdef YESCRYPT_INTERNAL | ||
34 | # if 1 | ||
35 | # define dbg(...) ((void)0) | ||
36 | # else | ||
37 | # define dbg(...) bb_error_msg(__VA_ARGS__) | ||
38 | # endif | ||
39 | # if 1 | ||
40 | # define dbg_dec64(...) ((void)0) | ||
41 | # else | ||
42 | # define dbg_dec64(...) bb_error_msg(__VA_ARGS__) | ||
43 | # endif | ||
44 | # define TEST_DECODE64 0 | ||
45 | #endif | ||
46 | |||
47 | // Only accept one-char parameters in salt, and only first three? | ||
48 | // Almost any reasonable yescrypt hashes in /etc/shadow should | ||
49 | // only ever use "jXY" parameters which set N and r. | ||
50 | // Fancy multi-byte-encoded wide integers are not needed for that. | ||
51 | #define RESTRICTED_PARAMS 1 | ||
52 | // Note: if you enable the above, please also enable | ||
53 | // YCTX_param_p, YCTX_param_t, YCTX_param_g, YCTX_param_NROM | ||
54 | // optimizations, and DISABLE_NROM_CODE. | ||
55 | |||
56 | #define DISABLE_NROM_CODE 1 | ||
57 | |||
58 | // How much we save by forcing "standard" value by commenting the next line: | ||
59 | // 160 bytes | ||
60 | //#define YCTX_param_flags yctx->param.flags | ||
61 | // 260 bytes | ||
62 | //#define flags___YESCRYPT_RW (flags & YESCRYPT_RW) | ||
63 | // 140 bytes | ||
64 | //#define flags___YESCRYPT_MODE_MASK (flags & YESCRYPT_MODE_MASK) | ||
65 | // ^^^^ forcing the above since the code already requires (checks for) this | ||
66 | // 50 bytes | ||
67 | #define YCTX_param_N yctx->param.N | ||
68 | // -100 bytes (negative!!!) | ||
69 | #define YCTX_param_r yctx->param.r | ||
70 | // 400 bytes | ||
71 | //#define YCTX_param_p yctx->param.p | ||
72 | // 130 bytes | ||
73 | //#define YCTX_param_t yctx->param.t | ||
74 | // 2 bytes | ||
75 | //#define YCTX_param_g yctx->param.g | ||
76 | // 1 bytes | ||
77 | // ^^^^ this looks wrong, compiler should be able to constant-propagate the fact that NROM code is dead | ||
78 | //#define YCTX_param_NROM yctx->param.NROM | ||
79 | |||
80 | #ifndef YCTX_param_flags | ||
81 | #define YCTX_param_flags (YESCRYPT_RW | YESCRYPT_ROUNDS_6 | YESCRYPT_GATHER_4 | YESCRYPT_SIMPLE_2 | YESCRYPT_SBOX_12K) | ||
82 | #endif | ||
83 | #ifndef flags___YESCRYPT_RW | ||
84 | #define flags___YESCRYPT_RW ((void)flags, YESCRYPT_RW) | ||
85 | #endif | ||
86 | #ifndef flags___YESCRYPT_MODE_MASK | ||
87 | #define flags___YESCRYPT_MODE_MASK ((void)flags, YESCRYPT_RW) | ||
88 | #endif | ||
89 | // standard ("j9T") values: | ||
90 | #ifndef YCTX_param_N | ||
91 | #define YCTX_param_N 4096 | ||
92 | #endif | ||
93 | #ifndef YCTX_param_r | ||
94 | #define YCTX_param_r 32 | ||
95 | #endif | ||
96 | #ifndef YCTX_param_p | ||
97 | #define YCTX_param_p 1 | ||
98 | #endif | ||
99 | #ifndef YCTX_param_t | ||
100 | #define YCTX_param_t 0 | ||
101 | #endif | ||
102 | #ifndef YCTX_param_g | ||
103 | #define YCTX_param_g 0 | ||
104 | #endif | ||
105 | #ifndef YCTX_param_NROM | ||
106 | #define YCTX_param_NROM 0 | ||
107 | #endif | ||
108 | |||
109 | // "Faster/smaller code" knobs: | ||
110 | // -941 bytes: | ||
111 | #define KDF_UNROLL_COPY 0 | ||
112 | // -5324 bytes if 0: | ||
113 | #define KDF_UNROLL_PWXFORM_ROUND 0 | ||
114 | // -4864 bytes if 0: | ||
115 | #define KDF_UNROLL_PWXFORM 0 | ||
116 | // if both this ^^^^^^^^^^ and PWXFORM_ROUND set to 0: -7666 bytes | ||
117 | // -464 bytes: | ||
118 | #define KDF_UNROLL_SALSA20 0 | ||
119 | |||
120 | /** | ||
121 | * Type and possible values for the flags argument of yescrypt_kdf(), | ||
122 | * yescrypt_encode_params_r(), yescrypt_encode_params(). Most of these may be | ||
123 | * OR'ed together, except that YESCRYPT_WORM stands on its own. | ||
124 | * Please refer to the description of yescrypt_kdf() below for the meaning of | ||
125 | * these flags. | ||
126 | */ | ||
127 | /* yescrypt flags: | ||
128 | * bits pos: 7654321076543210 | ||
129 | * ss r w | ||
130 | * sbox gg y | ||
131 | */ | ||
132 | /* Public */ | ||
133 | #define YESCRYPT_WORM 1 | ||
134 | #define YESCRYPT_RW 0x002 | ||
135 | #define YESCRYPT_ROUNDS_3 0x000 //r=0 | ||
136 | #define YESCRYPT_ROUNDS_6 0x004 //r=1 | ||
137 | #define YESCRYPT_GATHER_1 0x000 //gg=00 | ||
138 | #define YESCRYPT_GATHER_2 0x008 //gg=01 | ||
139 | #define YESCRYPT_GATHER_4 0x010 //gg=10 | ||
140 | #define YESCRYPT_GATHER_8 0x018 //gg=11 | ||
141 | #define YESCRYPT_SIMPLE_1 0x000 //ss=00 | ||
142 | #define YESCRYPT_SIMPLE_2 0x020 //ss=01 | ||
143 | #define YESCRYPT_SIMPLE_4 0x040 //ss=10 | ||
144 | #define YESCRYPT_SIMPLE_8 0x060 //ss=11 | ||
145 | #define YESCRYPT_SBOX_6K 0x000 //sbox=0000 | ||
146 | #define YESCRYPT_SBOX_12K 0x080 //sbox=0001 | ||
147 | #define YESCRYPT_SBOX_24K 0x100 //sbox=0010 | ||
148 | #define YESCRYPT_SBOX_48K 0x180 //sbox=0011 | ||
149 | #define YESCRYPT_SBOX_96K 0x200 //sbox=0100 | ||
150 | #define YESCRYPT_SBOX_192K 0x280 //sbox=0101 | ||
151 | #define YESCRYPT_SBOX_384K 0x300 //sbox=0110 | ||
152 | #define YESCRYPT_SBOX_768K 0x380 //sbox=0111 | ||
153 | |||
154 | #ifdef YESCRYPT_INTERNAL | ||
155 | /* Private */ | ||
156 | #define YESCRYPT_MODE_MASK 0x003 | ||
157 | #define YESCRYPT_RW_FLAVOR_MASK 0x3fc | ||
158 | #define YESCRYPT_ALLOC_ONLY 0x08000000 | ||
159 | #define YESCRYPT_PREHASH 0x10000000 | ||
160 | #endif | ||
161 | |||
162 | #define YESCRYPT_RW_DEFAULTS \ | ||
163 | (YESCRYPT_RW | \ | ||
164 | YESCRYPT_ROUNDS_6 | YESCRYPT_GATHER_4 | YESCRYPT_SIMPLE_2 | \ | ||
165 | YESCRYPT_SBOX_12K) | ||
166 | |||
167 | #define YESCRYPT_DEFAULTS YESCRYPT_RW_DEFAULTS | ||
168 | |||
169 | #ifdef YESCRYPT_INTERNAL | ||
170 | #define YESCRYPT_KNOWN_FLAGS \ | ||
171 | (YESCRYPT_MODE_MASK | YESCRYPT_RW_FLAVOR_MASK | \ | ||
172 | YESCRYPT_ALLOC_ONLY | YESCRYPT_PREHASH) | ||
173 | #endif | ||
174 | |||
175 | /* How many chars base-64 encoded bytes require? */ | ||
176 | #define YESCRYPT_BYTES2CHARS(bytes) ((((bytes) * 8) + 5) / 6) | ||
177 | /* The /etc/passwd-style hash is "<prefix>$<hash><NUL>" */ | ||
178 | /* | ||
179 | * "$y$", up to 8 params of up to 6 chars each, '$', salt | ||
180 | * Alternatively, but that's smaller: | ||
181 | * "$7$", 3 params encoded as 1+5+5 chars, salt | ||
182 | */ | ||
183 | #define YESCRYPT_PREFIX_LEN (3 + 8 * 6 + 1 + YESCRYPT_BYTES2CHARS(32)) | ||
184 | |||
185 | #define YESCRYPT_HASH_SIZE 32 | ||
186 | #define YESCRYPT_HASH_LEN YESCRYPT_BYTES2CHARS(YESCRYPT_HASH_SIZE) | ||
187 | |||
188 | /** | ||
189 | * Internal type used by the memory allocator. Please do not use it directly. | ||
190 | * Use yescrypt_shared_t and yescrypt_local_t as appropriate instead, since | ||
191 | * they might differ from each other in a future version. | ||
192 | */ | ||
193 | typedef struct { | ||
194 | // void *base; | ||
195 | void *aligned; | ||
196 | // size_t base_size; | ||
197 | size_t aligned_size; | ||
198 | } yescrypt_region_t; | ||
199 | |||
200 | /** | ||
201 | * yescrypt parameters combined into one struct. N, r, p are the same as in | ||
202 | * classic scrypt, except that the meaning of p changes when YESCRYPT_RW is | ||
203 | * set. flags, t, g, NROM are special to yescrypt. | ||
204 | */ | ||
205 | typedef struct { | ||
206 | uint32_t flags; | ||
207 | uint32_t r; | ||
208 | uint64_t N; | ||
209 | #if !RESTRICTED_PARAMS | ||
210 | uint32_t p, t, g; | ||
211 | uint64_t NROM; | ||
212 | #endif | ||
213 | } yescrypt_params_t; | ||
214 | |||
215 | typedef struct { | ||
216 | yescrypt_params_t param; | ||
217 | |||
218 | /* salt in binary form */ | ||
219 | /* stored here to cut down on the amount of function paramaters */ | ||
220 | unsigned char salt[64]; | ||
221 | size_t saltlen; | ||
222 | |||
223 | /* used by the memory allocator */ | ||
224 | //yescrypt_region_t shared[1]; | ||
225 | yescrypt_region_t local[1]; | ||
226 | } yescrypt_ctx_t; | ||
227 | |||
228 | /** | ||
229 | * yescrypt_r(shared, local, passwd, passwdlen, setting, key, buf, buflen): | ||
230 | * Compute and encode an scrypt or enhanced scrypt hash of passwd given the | ||
231 | * parameters and salt value encoded in setting. If shared is not NULL, a ROM | ||
232 | * is used and YESCRYPT_RW is required. Otherwise, whether to compute classic | ||
233 | * scrypt, YESCRYPT_WORM (a slight deviation from classic scrypt), or | ||
234 | * YESCRYPT_RW (time-memory tradeoff discouraging modification) is determined | ||
235 | * by the setting string. shared (if not NULL) and local must be initialized | ||
236 | * as described above for yescrypt_kdf(). buf must be large enough (as | ||
237 | * indicated by buflen) to hold the encoded hash string. | ||
238 | * | ||
239 | * Return the encoded hash string on success; or NULL on error. | ||
240 | * | ||
241 | * MT-safe as long as local and buf are local to the thread. | ||
242 | */ | ||
243 | extern char *yescrypt_r( | ||
244 | const uint8_t *passwd, size_t passwdlen, | ||
245 | const uint8_t *setting, | ||
246 | char *buf, size_t buflen | ||
247 | ); | ||
diff --git a/libbb/yescrypt/y.c b/libbb/yescrypt/y.c new file mode 100644 index 000000000..d5ab8903f --- /dev/null +++ b/libbb/yescrypt/y.c | |||
@@ -0,0 +1,16 @@ | |||
1 | /* | ||
2 | * The compilation unit for yescrypt-related code. | ||
3 | * | ||
4 | * Copyright (C) 2025 by Denys Vlasenko <vda.linux@googlemail.com> | ||
5 | * | ||
6 | * Licensed under GPLv2, see file LICENSE in this source tree. | ||
7 | */ | ||
8 | //kbuild:lib-$(CONFIG_USE_BB_CRYPT_YES) += y.o | ||
9 | |||
10 | #include "libbb.h" | ||
11 | |||
12 | #define YESCRYPT_INTERNAL | ||
13 | #include "alg-yescrypt.h" | ||
14 | #include "alg-sha256.c" | ||
15 | #include "alg-yescrypt-kdf.c" | ||
16 | #include "alg-yescrypt-common.c" | ||
diff --git a/loginutils/Config.src b/loginutils/Config.src index cbb09646b..a7812bd32 100644 --- a/loginutils/Config.src +++ b/loginutils/Config.src | |||
@@ -91,6 +91,17 @@ config USE_BB_CRYPT_SHA | |||
91 | With this option off, login will fail password check for any | 91 | With this option off, login will fail password check for any |
92 | user which has password encrypted with these algorithms. | 92 | user which has password encrypted with these algorithms. |
93 | 93 | ||
94 | config USE_BB_CRYPT_YES | ||
95 | bool "Enable yescrypt functions" | ||
96 | default y | ||
97 | depends on USE_BB_CRYPT | ||
98 | help | ||
99 | Enable this if you have passwords starting with "$y$" or | ||
100 | in your /etc/passwd or /etc/shadow files. These passwords | ||
101 | are hashed using yescrypt algorithms. | ||
102 | With this option off, login will fail password check for any | ||
103 | user which has password encrypted with these algorithms. | ||
104 | |||
94 | INSERT | 105 | INSERT |
95 | 106 | ||
96 | endmenu | 107 | endmenu |
diff --git a/loginutils/chpasswd.c b/loginutils/chpasswd.c index 65530b614..353f19961 100644 --- a/loginutils/chpasswd.c +++ b/loginutils/chpasswd.c | |||
@@ -17,7 +17,7 @@ | |||
17 | //config: default "des" | 17 | //config: default "des" |
18 | //config: depends on PASSWD || CRYPTPW || CHPASSWD | 18 | //config: depends on PASSWD || CRYPTPW || CHPASSWD |
19 | //config: help | 19 | //config: help |
20 | //config: Possible choices are "d[es]", "m[d5]", "s[ha256]" or "sha512". | 20 | //config: Possible choices: "d[es]", "m[d5]", "s[ha256]", "sha512", "yescrypt" |
21 | 21 | ||
22 | //applet:IF_CHPASSWD(APPLET(chpasswd, BB_DIR_USR_SBIN, BB_SUID_DROP)) | 22 | //applet:IF_CHPASSWD(APPLET(chpasswd, BB_DIR_USR_SBIN, BB_SUID_DROP)) |
23 | 23 | ||
diff --git a/loginutils/cryptpw.c b/loginutils/cryptpw.c index 1c338540f..666deff0b 100644 --- a/loginutils/cryptpw.c +++ b/loginutils/cryptpw.c | |||
@@ -84,8 +84,7 @@ to cryptpw. -a option (alias for -m) came from cryptpw. | |||
84 | int cryptpw_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 84 | int cryptpw_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
85 | int cryptpw_main(int argc UNUSED_PARAM, char **argv) | 85 | int cryptpw_main(int argc UNUSED_PARAM, char **argv) |
86 | { | 86 | { |
87 | /* Supports: cryptpw -m sha256 PASS 'rounds=999999999$SALT' */ | 87 | char salt[MAX_PW_SALT_LEN]; |
88 | char salt[MAX_PW_SALT_LEN + sizeof("rounds=999999999$")]; | ||
89 | char *salt_ptr; | 88 | char *salt_ptr; |
90 | char *password; | 89 | char *password; |
91 | const char *opt_m, *opt_S; | 90 | const char *opt_m, *opt_S; |
@@ -100,7 +99,7 @@ int cryptpw_main(int argc UNUSED_PARAM, char **argv) | |||
100 | ; | 99 | ; |
101 | #endif | 100 | #endif |
102 | fd = STDIN_FILENO; | 101 | fd = STDIN_FILENO; |
103 | opt_m = CONFIG_FEATURE_DEFAULT_PASSWD_ALGO; | 102 | opt_m = NULL; |
104 | opt_S = NULL; | 103 | opt_S = NULL; |
105 | /* at most two non-option arguments; -P NUM */ | 104 | /* at most two non-option arguments; -P NUM */ |
106 | getopt32long(argv, "^" "sP:+S:m:a:" "\0" "?2", | 105 | getopt32long(argv, "^" "sP:+S:m:a:" "\0" "?2", |
@@ -114,10 +113,34 @@ int cryptpw_main(int argc UNUSED_PARAM, char **argv) | |||
114 | if (argv[0] && !opt_S) | 113 | if (argv[0] && !opt_S) |
115 | opt_S = argv[1]; | 114 | opt_S = argv[1]; |
116 | 115 | ||
117 | salt_ptr = crypt_make_pw_salt(salt, opt_m); | 116 | if (opt_S && !opt_S[0]) { |
118 | if (opt_S) | 117 | /* mkpasswd 5.6.2 compat: SALT of "" |
119 | /* put user's data after the "$N$" prefix */ | 118 | * is treated as not specified |
120 | safe_strncpy(salt_ptr, opt_S, sizeof(salt) - (sizeof("$N$")-1)); | 119 | * (both forms: -S "" and argv[1] of "") |
120 | */ | ||
121 | opt_S = NULL; | ||
122 | } | ||
123 | |||
124 | if (opt_m) { | ||
125 | /* "cryptpw -m ALGO PASSWORD [SALT]" */ | ||
126 | /* generate "$x$" algo prefix + random salt */ | ||
127 | salt_ptr = crypt_make_pw_salt(salt, opt_m); | ||
128 | if (opt_S) { | ||
129 | /* "cryptpw -m ALGO PASSWORD SALT" */ | ||
130 | /* put SALT data after the "$x$" prefix */ | ||
131 | safe_strncpy(salt_ptr, opt_S, sizeof(salt) - (sizeof("$N$")-1)); | ||
132 | } | ||
133 | } else { | ||
134 | if (!opt_S) { | ||
135 | /* "cryptpw PASSWORD" */ | ||
136 | /* generate random salt with default algo */ | ||
137 | crypt_make_pw_salt(salt, CONFIG_FEATURE_DEFAULT_PASSWD_ALGO); | ||
138 | } else { | ||
139 | /* "cryptpw PASSWORD '$x$SALT'" */ | ||
140 | /* use given salt; algo will be detected by pw_encrypt() */ | ||
141 | safe_strncpy(salt, opt_S, sizeof(salt)); | ||
142 | } | ||
143 | } | ||
121 | 144 | ||
122 | xmove_fd(fd, STDIN_FILENO); | 145 | xmove_fd(fd, STDIN_FILENO); |
123 | 146 | ||
diff --git a/loginutils/sulogin.c b/loginutils/sulogin.c index 9c927ed79..984889915 100644 --- a/loginutils/sulogin.c +++ b/loginutils/sulogin.c | |||
@@ -79,7 +79,7 @@ int sulogin_main(int argc UNUSED_PARAM, char **argv) | |||
79 | break; | 79 | break; |
80 | } | 80 | } |
81 | pause_after_failed_login(); | 81 | pause_after_failed_login(); |
82 | bb_simple_info_msg("Login incorrect"); | 82 | bb_simple_error_msg("Login incorrect"); |
83 | } | 83 | } |
84 | 84 | ||
85 | /* util-linux 2.36.1 compat: no message */ | 85 | /* util-linux 2.36.1 compat: no message */ |
@@ -119,9 +119,12 @@ int sulogin_main(int argc UNUSED_PARAM, char **argv) | |||
119 | } | 119 | } |
120 | 120 | ||
121 | /* | 121 | /* |
122 | * Note: login does this (should we do it too?): | 122 | * Note: login does this. util-linux's sulogin does NOT. |
123 | * But it's rather unpleasant to have non-functioning ^C in a shell, | ||
124 | * and surprisingly, there is no easy way to remove SIG_IGN from ^C | ||
125 | * in the shell. So, we are doing it: | ||
123 | */ | 126 | */ |
124 | /*signal(SIGINT, SIG_DFL);*/ | 127 | signal(SIGINT, SIG_DFL); |
125 | 128 | ||
126 | /* Exec shell with no additional parameters. Never returns. */ | 129 | /* Exec shell with no additional parameters. Never returns. */ |
127 | exec_shell(shell, /* -p? then shell is login:*/(opts & 1), NULL); | 130 | exec_shell(shell, /* -p? then shell is login:*/(opts & 1), NULL); |
diff --git a/miscutils/crond.c b/miscutils/crond.c index b3762d327..6a384fdfb 100644 --- a/miscutils/crond.c +++ b/miscutils/crond.c | |||
@@ -177,7 +177,7 @@ static void crondlog(unsigned level, const char *msg, va_list va) | |||
177 | { | 177 | { |
178 | if (level >= G.log_level) { | 178 | if (level >= G.log_level) { |
179 | /* | 179 | /* |
180 | * We are called only for info meesages. | 180 | * We are called only for info messages. |
181 | * Warnings/errors use plain bb_[p]error_msg's, which | 181 | * Warnings/errors use plain bb_[p]error_msg's, which |
182 | * need not touch syslog_level | 182 | * need not touch syslog_level |
183 | * (they are ok with LOG_ERR default). | 183 | * (they are ok with LOG_ERR default). |
@@ -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/miscutils/fbsplash.c b/miscutils/fbsplash.c index 2934d8eb7..912a501a3 100644 --- a/miscutils/fbsplash.c +++ b/miscutils/fbsplash.c | |||
@@ -382,7 +382,7 @@ static void fb_drawimage(void) | |||
382 | if (LONE_DASH(G.image_filename)) { | 382 | if (LONE_DASH(G.image_filename)) { |
383 | theme_file = stdin; | 383 | theme_file = stdin; |
384 | } else { | 384 | } else { |
385 | int fd = open_zipped(G.image_filename, /*fail_if_not_compressed:*/ 0); | 385 | int fd = open_zipped(G.image_filename, /*die_if_not_compressed:*/ 0); |
386 | if (fd < 0) | 386 | if (fd < 0) |
387 | bb_simple_perror_msg_and_die(G.image_filename); | 387 | bb_simple_perror_msg_and_die(G.image_filename); |
388 | theme_file = xfdopen_for_read(fd); | 388 | theme_file = xfdopen_for_read(fd); |
diff --git a/miscutils/less.c b/miscutils/less.c index 8a0525cb7..2204b1cec 100644 --- a/miscutils/less.c +++ b/miscutils/less.c | |||
@@ -1139,7 +1139,7 @@ static int64_t getch_nowait(void) | |||
1139 | 1139 | ||
1140 | /* We have kbd_fd in O_NONBLOCK mode, read inside safe_read_key() | 1140 | /* We have kbd_fd in O_NONBLOCK mode, read inside safe_read_key() |
1141 | * would not block even if there is no input available */ | 1141 | * would not block even if there is no input available */ |
1142 | key64 = safe_read_key(kbd_fd, kbd_input, /*timeout off:*/ -2); | 1142 | key64 = safe_read_key(kbd_fd, kbd_input, /*do not poll:*/ -2); |
1143 | if ((int)key64 == -1) { | 1143 | if ((int)key64 == -1) { |
1144 | if (errno == EAGAIN) { | 1144 | if (errno == EAGAIN) { |
1145 | /* No keyboard input available. Since poll() did return, | 1145 | /* No keyboard input available. Since poll() did return, |
diff --git a/miscutils/man.c b/miscutils/man.c index deaf9e5ab..6fa1fbfdc 100644 --- a/miscutils/man.c +++ b/miscutils/man.c | |||
@@ -143,7 +143,7 @@ static int run_pipe(char *man_filename, int man, int level) | |||
143 | 143 | ||
144 | ordinary_manpage: | 144 | ordinary_manpage: |
145 | close(STDIN_FILENO); | 145 | close(STDIN_FILENO); |
146 | open_zipped(man_filename, /*fail_if_not_compressed:*/ 0); /* guaranteed to use fd 0 (STDIN_FILENO) */ | 146 | open_zipped(man_filename, /*die_if_not_compressed:*/ 0); /* guaranteed to use fd 0 (STDIN_FILENO) */ |
147 | if (man) { | 147 | if (man) { |
148 | int w = get_terminal_width(-1); | 148 | int w = get_terminal_width(-1); |
149 | if (w > 10) | 149 | if (w > 10) |
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/networking/hostname.c b/networking/hostname.c index 36cb70866..101b89e77 100644 --- a/networking/hostname.c +++ b/networking/hostname.c | |||
@@ -25,8 +25,8 @@ | |||
25 | //applet:IF_DNSDOMAINNAME(APPLET_NOEXEC(dnsdomainname, hostname, BB_DIR_BIN, BB_SUID_DROP, dnsdomainname)) | 25 | //applet:IF_DNSDOMAINNAME(APPLET_NOEXEC(dnsdomainname, hostname, BB_DIR_BIN, BB_SUID_DROP, dnsdomainname)) |
26 | //applet:IF_HOSTNAME( APPLET_NOEXEC(hostname, hostname, BB_DIR_BIN, BB_SUID_DROP, hostname )) | 26 | //applet:IF_HOSTNAME( APPLET_NOEXEC(hostname, hostname, BB_DIR_BIN, BB_SUID_DROP, hostname )) |
27 | 27 | ||
28 | //kbuild: lib-$(CONFIG_HOSTNAME) += hostname.o | 28 | //kbuild:lib-$(CONFIG_HOSTNAME) += hostname.o |
29 | //kbuild: lib-$(CONFIG_DNSDOMAINNAME) += hostname.o | 29 | //kbuild:lib-$(CONFIG_DNSDOMAINNAME) += hostname.o |
30 | 30 | ||
31 | //usage:#define hostname_trivial_usage | 31 | //usage:#define hostname_trivial_usage |
32 | //usage: "[-sidf] [HOSTNAME | -F FILE]" | 32 | //usage: "[-sidf] [HOSTNAME | -F FILE]" |
diff --git a/networking/httpd.c b/networking/httpd.c index ddcb03bca..e1a447fa1 100644 --- a/networking/httpd.c +++ b/networking/httpd.c | |||
@@ -2826,7 +2826,7 @@ int httpd_main(int argc UNUSED_PARAM, char **argv) | |||
2826 | salt[0] = '$'; | 2826 | salt[0] = '$'; |
2827 | salt[1] = '1'; | 2827 | salt[1] = '1'; |
2828 | salt[2] = '$'; | 2828 | salt[2] = '$'; |
2829 | crypt_make_salt(salt + 3, 4); | 2829 | crypt_make_rand64encoded(salt + 3, 8 / 2); /* 8 chars */ |
2830 | puts(pw_encrypt(pass, salt, /*cleanup:*/ 0)); | 2830 | puts(pw_encrypt(pass, salt, /*cleanup:*/ 0)); |
2831 | return 0; | 2831 | return 0; |
2832 | } | 2832 | } |
diff --git a/networking/libiproute/iproute.c b/networking/libiproute/iproute.c index cd77f642f..a30f070eb 100644 --- a/networking/libiproute/iproute.c +++ b/networking/libiproute/iproute.c | |||
@@ -302,24 +302,22 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM, | |||
302 | printf("notify "); | 302 | printf("notify "); |
303 | } | 303 | } |
304 | 304 | ||
305 | if (r->rtm_family == AF_INET6) { | 305 | if (r->rtm_family == AF_INET || r->rtm_family == AF_INET6) { |
306 | struct rta_cacheinfo *ci = NULL; | 306 | if (r->rtm_family == AF_INET) { |
307 | if (tb[RTA_CACHEINFO]) { | ||
308 | ci = RTA_DATA(tb[RTA_CACHEINFO]); | ||
309 | } | ||
310 | if ((r->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) { | ||
311 | if (r->rtm_flags & RTM_F_CLONED) { | 307 | if (r->rtm_flags & RTM_F_CLONED) { |
312 | printf("%c cache ", _SL_); | 308 | printf("%c cache ", _SL_); |
309 | /* upstream: print_cache_flags() prints more here */ | ||
313 | } | 310 | } |
311 | } | ||
312 | if (tb[RTA_CACHEINFO]) { | ||
313 | struct rta_cacheinfo *ci = RTA_DATA(tb[RTA_CACHEINFO]); | ||
314 | if (ci->rta_expires) { | 314 | if (ci->rta_expires) { |
315 | printf(" expires %dsec", ci->rta_expires / get_hz()); | 315 | printf(" expires %dsec", ci->rta_expires / get_hz()); |
316 | } | 316 | } |
317 | if (ci->rta_error != 0) { | 317 | if (ci->rta_error != 0) { |
318 | printf(" error %d", ci->rta_error); | 318 | printf(" error %d", ci->rta_error); |
319 | } | 319 | } |
320 | } else if (ci) { | 320 | /* upstream: print_rta_cacheinfo() prints more here */ |
321 | if (ci->rta_error != 0) | ||
322 | printf(" error %d", ci->rta_error); | ||
323 | } | 321 | } |
324 | } | 322 | } |
325 | if (tb[RTA_IIF] && G_filter.iif == 0) { | 323 | if (tb[RTA_IIF] && G_filter.iif == 0) { |
diff --git a/networking/ntpd.c b/networking/ntpd.c index dcbdb8e60..dd0a9c91f 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c | |||
@@ -205,7 +205,7 @@ | |||
205 | #define MINDISP 0.01 /* minimum dispersion (sec) */ | 205 | #define MINDISP 0.01 /* minimum dispersion (sec) */ |
206 | #define MAXDISP 16 /* maximum dispersion (sec) */ | 206 | #define MAXDISP 16 /* maximum dispersion (sec) */ |
207 | #define MAXSTRAT 16 /* maximum stratum (infinity metric) */ | 207 | #define MAXSTRAT 16 /* maximum stratum (infinity metric) */ |
208 | #define MAXDIST 1 /* distance threshold (sec) */ | 208 | #define MAXDIST 3 /* distance threshold (sec): do not use peers who are farther away */ |
209 | #define MIN_SELECTED 1 /* minimum intersection survivors */ | 209 | #define MIN_SELECTED 1 /* minimum intersection survivors */ |
210 | #define MIN_CLUSTERED 3 /* minimum cluster survivors */ | 210 | #define MIN_CLUSTERED 3 /* minimum cluster survivors */ |
211 | 211 | ||
@@ -1057,7 +1057,7 @@ step_time(double offset) | |||
1057 | } | 1057 | } |
1058 | tval = tvn.tv_sec; | 1058 | tval = tvn.tv_sec; |
1059 | strftime_YYYYMMDDHHMMSS(buf, sizeof(buf), &tval); | 1059 | strftime_YYYYMMDDHHMMSS(buf, sizeof(buf), &tval); |
1060 | bb_info_msg("setting time to %s.%06u (offset %+fs)", buf, (unsigned)tvn.tv_usec, offset); | 1060 | bb_error_msg("setting time to %s.%06u (offset %+fs)", buf, (unsigned)tvn.tv_usec, offset); |
1061 | //maybe? G.FREQHOLD_cnt = 0; | 1061 | //maybe? G.FREQHOLD_cnt = 0; |
1062 | 1062 | ||
1063 | /* Correct various fields which contain time-relative values: */ | 1063 | /* Correct various fields which contain time-relative values: */ |
@@ -1976,7 +1976,7 @@ recv_and_process_peer_pkt(peer_t *p) | |||
1976 | 1976 | ||
1977 | p->reachable_bits |= 1; | 1977 | p->reachable_bits |= 1; |
1978 | if ((MAX_VERBOSE && G.verbose) || (option_mask32 & OPT_w)) { | 1978 | if ((MAX_VERBOSE && G.verbose) || (option_mask32 & OPT_w)) { |
1979 | bb_info_msg("reply from %s: offset:%+f delay:%f status:0x%02x strat:%d refid:0x%08x rootdelay:%f reach:0x%02x", | 1979 | bb_error_msg("reply from %s: offset:%+f delay:%f status:0x%02x strat:%d refid:0x%08x rootdelay:%f reach:0x%02x", |
1980 | p->p_dotted, | 1980 | p->p_dotted, |
1981 | offset, | 1981 | offset, |
1982 | p->p_raw_delay, | 1982 | p->p_raw_delay, |
diff --git a/networking/telnetd.c b/networking/telnetd.c index bfeea1400..a5a783047 100644 --- a/networking/telnetd.c +++ b/networking/telnetd.c | |||
@@ -104,8 +104,8 @@ | |||
104 | //usage:#define telnetd_full_usage "\n\n" | 104 | //usage:#define telnetd_full_usage "\n\n" |
105 | //usage: "Handle incoming telnet connections" | 105 | //usage: "Handle incoming telnet connections" |
106 | //usage: IF_NOT_FEATURE_TELNETD_STANDALONE(" via inetd") "\n" | 106 | //usage: IF_NOT_FEATURE_TELNETD_STANDALONE(" via inetd") "\n" |
107 | //usage: "\n -l LOGIN Exec LOGIN on connect" | 107 | //usage: "\n -l LOGIN Exec LOGIN on connect (default /bin/login)" |
108 | //usage: "\n -f ISSUE_FILE Display ISSUE_FILE instead of /etc/issue" | 108 | //usage: "\n -f ISSUE_FILE Display ISSUE_FILE instead of /etc/issue.net" |
109 | //usage: "\n -K Close connection as soon as login exits" | 109 | //usage: "\n -K Close connection as soon as login exits" |
110 | //usage: "\n (normally wait until all programs close slave pty)" | 110 | //usage: "\n (normally wait until all programs close slave pty)" |
111 | //usage: IF_FEATURE_TELNETD_STANDALONE( | 111 | //usage: IF_FEATURE_TELNETD_STANDALONE( |
diff --git a/networking/tftp.c b/networking/tftp.c index f5b4367ca..b698a9288 100644 --- a/networking/tftp.c +++ b/networking/tftp.c | |||
@@ -250,7 +250,7 @@ static int tftp_blksize_check(const char *blksize_str, int maxsize) | |||
250 | return -1; | 250 | return -1; |
251 | } | 251 | } |
252 | # if ENABLE_TFTP_DEBUG | 252 | # if ENABLE_TFTP_DEBUG |
253 | bb_info_msg("using blksize %u", blksize); | 253 | bb_error_msg("using blksize %u", blksize); |
254 | # endif | 254 | # endif |
255 | return blksize; | 255 | return blksize; |
256 | } | 256 | } |
diff --git a/networking/tls.c b/networking/tls.c index 8d074c058..ac6f0767f 100644 --- a/networking/tls.c +++ b/networking/tls.c | |||
@@ -188,8 +188,6 @@ | |||
188 | #define TLS_MAX_OUTBUF (1 << 14) | 188 | #define TLS_MAX_OUTBUF (1 << 14) |
189 | 189 | ||
190 | enum { | 190 | enum { |
191 | SHA_INSIZE = 64, | ||
192 | |||
193 | AES128_KEYSIZE = 16, | 191 | AES128_KEYSIZE = 16, |
194 | AES256_KEYSIZE = 32, | 192 | AES256_KEYSIZE = 32, |
195 | 193 | ||
@@ -335,34 +333,6 @@ void FAST_FUNC tls_get_random(void *buf, unsigned len) | |||
335 | xfunc_die(); | 333 | xfunc_die(); |
336 | } | 334 | } |
337 | 335 | ||
338 | static void xorbuf3(void *dst, const void *src1, const void *src2, unsigned count) | ||
339 | { | ||
340 | uint8_t *d = dst; | ||
341 | const uint8_t *s1 = src1; | ||
342 | const uint8_t* s2 = src2; | ||
343 | while (count--) | ||
344 | *d++ = *s1++ ^ *s2++; | ||
345 | } | ||
346 | |||
347 | void FAST_FUNC xorbuf(void *dst, const void *src, unsigned count) | ||
348 | { | ||
349 | xorbuf3(dst, dst, src, count); | ||
350 | } | ||
351 | |||
352 | void FAST_FUNC xorbuf_aligned_AES_BLOCK_SIZE(void *dst, const void *src) | ||
353 | { | ||
354 | unsigned long *d = dst; | ||
355 | const unsigned long *s = src; | ||
356 | d[0] ^= s[0]; | ||
357 | #if ULONG_MAX <= 0xffffffffffffffff | ||
358 | d[1] ^= s[1]; | ||
359 | #if ULONG_MAX == 0xffffffff | ||
360 | d[2] ^= s[2]; | ||
361 | d[3] ^= s[3]; | ||
362 | #endif | ||
363 | #endif | ||
364 | } | ||
365 | |||
366 | #if !TLS_DEBUG_HASH | 336 | #if !TLS_DEBUG_HASH |
367 | # define hash_handshake(tls, fmt, buffer, len) \ | 337 | # define hash_handshake(tls, fmt, buffer, len) \ |
368 | hash_handshake(tls, buffer, len) | 338 | hash_handshake(tls, buffer, len) |
@@ -393,128 +363,6 @@ static void hash_handshake(tls_state_t *tls, const char *fmt, const void *buffer | |||
393 | # define TLS_MAC_SIZE(tls) (tls)->MAC_size | 363 | # define TLS_MAC_SIZE(tls) (tls)->MAC_size |
394 | #endif | 364 | #endif |
395 | 365 | ||
396 | // RFC 2104: | ||
397 | // HMAC(key, text) based on a hash H (say, sha256) is: | ||
398 | // ipad = [0x36 x INSIZE] | ||
399 | // opad = [0x5c x INSIZE] | ||
400 | // HMAC(key, text) = H((key XOR opad) + H((key XOR ipad) + text)) | ||
401 | // | ||
402 | // H(key XOR opad) and H(key XOR ipad) can be precomputed | ||
403 | // if we often need HMAC hmac with the same key. | ||
404 | // | ||
405 | // text is often given in disjoint pieces. | ||
406 | typedef struct hmac_precomputed { | ||
407 | md5sha_ctx_t hashed_key_xor_ipad; | ||
408 | md5sha_ctx_t hashed_key_xor_opad; | ||
409 | } hmac_precomputed_t; | ||
410 | |||
411 | typedef void md5sha_begin_func(md5sha_ctx_t *ctx) FAST_FUNC; | ||
412 | #if !ENABLE_FEATURE_TLS_SHA1 | ||
413 | #define hmac_begin(pre,key,key_size,begin) \ | ||
414 | hmac_begin(pre,key,key_size) | ||
415 | #define begin sha256_begin | ||
416 | #endif | ||
417 | static void hmac_begin(hmac_precomputed_t *pre, uint8_t *key, unsigned key_size, md5sha_begin_func *begin) | ||
418 | { | ||
419 | uint8_t key_xor_ipad[SHA_INSIZE]; | ||
420 | uint8_t key_xor_opad[SHA_INSIZE]; | ||
421 | // uint8_t tempkey[SHA1_OUTSIZE < SHA256_OUTSIZE ? SHA256_OUTSIZE : SHA1_OUTSIZE]; | ||
422 | unsigned i; | ||
423 | |||
424 | // "The authentication key can be of any length up to INSIZE, the | ||
425 | // block length of the hash function. Applications that use keys longer | ||
426 | // than INSIZE bytes will first hash the key using H and then use the | ||
427 | // resultant OUTSIZE byte string as the actual key to HMAC." | ||
428 | if (key_size > SHA_INSIZE) { | ||
429 | bb_simple_error_msg_and_die("HMAC key>64"); //does not happen (yet?) | ||
430 | // md5sha_ctx_t ctx; | ||
431 | // begin(&ctx); | ||
432 | // md5sha_hash(&ctx, key, key_size); | ||
433 | // key_size = sha_end(&ctx, tempkey); | ||
434 | // //key = tempkey; - right? RIGHT? why does it work without this? | ||
435 | // // because SHA_INSIZE is 64, but hmac() is always called with | ||
436 | // // key_size = tls->MAC_size = SHA1/256_OUTSIZE (20 or 32), | ||
437 | // // and prf_hmac_sha256() -> hmac_sha256() key sizes are: | ||
438 | // // - RSA_PREMASTER_SIZE is 48 | ||
439 | // // - CURVE25519_KEYSIZE is 32 | ||
440 | // // - master_secret[] is 48 | ||
441 | } | ||
442 | |||
443 | for (i = 0; i < key_size; i++) { | ||
444 | key_xor_ipad[i] = key[i] ^ 0x36; | ||
445 | key_xor_opad[i] = key[i] ^ 0x5c; | ||
446 | } | ||
447 | for (; i < SHA_INSIZE; i++) { | ||
448 | key_xor_ipad[i] = 0x36; | ||
449 | key_xor_opad[i] = 0x5c; | ||
450 | } | ||
451 | |||
452 | begin(&pre->hashed_key_xor_ipad); | ||
453 | begin(&pre->hashed_key_xor_opad); | ||
454 | md5sha_hash(&pre->hashed_key_xor_ipad, key_xor_ipad, SHA_INSIZE); | ||
455 | md5sha_hash(&pre->hashed_key_xor_opad, key_xor_opad, SHA_INSIZE); | ||
456 | } | ||
457 | #undef begin | ||
458 | |||
459 | static unsigned hmac_sha_precomputed_v( | ||
460 | hmac_precomputed_t *pre, | ||
461 | uint8_t *out, | ||
462 | va_list va) | ||
463 | { | ||
464 | uint8_t *text; | ||
465 | unsigned len; | ||
466 | |||
467 | /* pre->hashed_key_xor_ipad contains unclosed "H((key XOR ipad) +" state */ | ||
468 | /* pre->hashed_key_xor_opad contains unclosed "H((key XOR opad) +" state */ | ||
469 | |||
470 | /* calculate out = H((key XOR ipad) + text) */ | ||
471 | while ((text = va_arg(va, uint8_t*)) != NULL) { | ||
472 | unsigned text_size = va_arg(va, unsigned); | ||
473 | md5sha_hash(&pre->hashed_key_xor_ipad, text, text_size); | ||
474 | } | ||
475 | len = sha_end(&pre->hashed_key_xor_ipad, out); | ||
476 | |||
477 | /* out = H((key XOR opad) + out) */ | ||
478 | md5sha_hash(&pre->hashed_key_xor_opad, out, len); | ||
479 | return sha_end(&pre->hashed_key_xor_opad, out); | ||
480 | } | ||
481 | |||
482 | static unsigned hmac_sha_precomputed(hmac_precomputed_t *pre_init, uint8_t *out, ...) | ||
483 | { | ||
484 | hmac_precomputed_t pre; | ||
485 | va_list va; | ||
486 | unsigned len; | ||
487 | |||
488 | va_start(va, out); | ||
489 | pre = *pre_init; /* struct copy */ | ||
490 | len = hmac_sha_precomputed_v(&pre, out, va); | ||
491 | va_end(va); | ||
492 | return len; | ||
493 | } | ||
494 | |||
495 | #if !ENABLE_FEATURE_TLS_SHA1 | ||
496 | #define hmac(tls,out,key,key_size,...) \ | ||
497 | hmac(out,key,key_size, __VA_ARGS__) | ||
498 | #endif | ||
499 | static unsigned hmac(tls_state_t *tls, uint8_t *out, uint8_t *key, unsigned key_size, ...) | ||
500 | { | ||
501 | hmac_precomputed_t pre; | ||
502 | va_list va; | ||
503 | unsigned len; | ||
504 | |||
505 | va_start(va, key_size); | ||
506 | |||
507 | hmac_begin(&pre, key, key_size, | ||
508 | (ENABLE_FEATURE_TLS_SHA1 && tls->MAC_size == SHA1_OUTSIZE) | ||
509 | ? sha1_begin | ||
510 | : sha256_begin | ||
511 | ); | ||
512 | len = hmac_sha_precomputed_v(&pre, out, va); | ||
513 | |||
514 | va_end(va); | ||
515 | return len; | ||
516 | } | ||
517 | |||
518 | // RFC 5246: | 366 | // RFC 5246: |
519 | // 5. HMAC and the Pseudorandom Function | 367 | // 5. HMAC and the Pseudorandom Function |
520 | //... | 368 | //... |
@@ -559,7 +407,7 @@ static void prf_hmac_sha256(/*tls_state_t *tls,*/ | |||
559 | const char *label, | 407 | const char *label, |
560 | uint8_t *seed, unsigned seed_size) | 408 | uint8_t *seed, unsigned seed_size) |
561 | { | 409 | { |
562 | hmac_precomputed_t pre; | 410 | hmac_ctx_t ctx; |
563 | uint8_t a[TLS_MAX_MAC_SIZE]; | 411 | uint8_t a[TLS_MAX_MAC_SIZE]; |
564 | uint8_t *out_p = outbuf; | 412 | uint8_t *out_p = outbuf; |
565 | unsigned label_size = strlen(label); | 413 | unsigned label_size = strlen(label); |
@@ -569,26 +417,26 @@ static void prf_hmac_sha256(/*tls_state_t *tls,*/ | |||
569 | #define SEED label, label_size, seed, seed_size | 417 | #define SEED label, label_size, seed, seed_size |
570 | #define A a, MAC_size | 418 | #define A a, MAC_size |
571 | 419 | ||
572 | hmac_begin(&pre, secret, secret_size, sha256_begin); | 420 | hmac_begin(&ctx, secret, secret_size, sha256_begin); |
573 | 421 | ||
574 | /* A(1) = HMAC_hash(secret, seed) */ | 422 | /* A(1) = HMAC_hash(secret, seed) */ |
575 | hmac_sha_precomputed(&pre, a, SEED, NULL); | 423 | hmac_peek_hash(&ctx, a, SEED, NULL); |
576 | 424 | ||
577 | for (;;) { | 425 | for (;;) { |
578 | /* HMAC_hash(secret, A(1) + seed) */ | 426 | /* HMAC_hash(secret, A(1) + seed) */ |
579 | if (outbuf_size <= MAC_size) { | 427 | if (outbuf_size <= MAC_size) { |
580 | /* Last, possibly incomplete, block */ | 428 | /* Last, possibly incomplete, block */ |
581 | /* (use a[] as temp buffer) */ | 429 | /* (use a[] as temp buffer) */ |
582 | hmac_sha_precomputed(&pre, a, A, SEED, NULL); | 430 | hmac_peek_hash(&ctx, a, A, SEED, NULL); |
583 | memcpy(out_p, a, outbuf_size); | 431 | memcpy(out_p, a, outbuf_size); |
584 | return; | 432 | return; |
585 | } | 433 | } |
586 | /* Not last block. Store directly to result buffer */ | 434 | /* Not last block. Store directly to result buffer */ |
587 | hmac_sha_precomputed(&pre, out_p, A, SEED, NULL); | 435 | hmac_peek_hash(&ctx, out_p, A, SEED, NULL); |
588 | out_p += MAC_size; | 436 | out_p += MAC_size; |
589 | outbuf_size -= MAC_size; | 437 | outbuf_size -= MAC_size; |
590 | /* A(2) = HMAC_hash(secret, A(1)) */ | 438 | /* A(2) = HMAC_hash(secret, A(1)) */ |
591 | hmac_sha_precomputed(&pre, a, A, NULL); | 439 | hmac_peek_hash(&ctx, a, A, NULL); |
592 | } | 440 | } |
593 | #undef A | 441 | #undef A |
594 | #undef SECRET | 442 | #undef SECRET |
@@ -655,6 +503,29 @@ static void *tls_get_zeroed_outbuf(tls_state_t *tls, int len) | |||
655 | return record; | 503 | return record; |
656 | } | 504 | } |
657 | 505 | ||
506 | /* Calculate the HMAC over the list of blocks */ | ||
507 | #if !ENABLE_FEATURE_TLS_SHA1 | ||
508 | #define hmac_blocks(tls,out,key,key_size,...) \ | ||
509 | hmac_blocks(out,key,key_size, __VA_ARGS__) | ||
510 | #endif | ||
511 | static unsigned hmac_blocks(tls_state_t *tls, uint8_t *out, uint8_t *key, unsigned key_size, ...) | ||
512 | { | ||
513 | hmac_ctx_t ctx; | ||
514 | va_list va; | ||
515 | |||
516 | hmac_begin(&ctx, key, key_size, | ||
517 | (ENABLE_FEATURE_TLS_SHA1 && tls->MAC_size == SHA1_OUTSIZE) | ||
518 | ? sha1_begin | ||
519 | : sha256_begin | ||
520 | ); | ||
521 | |||
522 | va_start(va, key_size); | ||
523 | hmac_hash_v(&ctx, va); | ||
524 | va_end(va); | ||
525 | |||
526 | return hmac_end(&ctx, out); | ||
527 | } | ||
528 | |||
658 | static void xwrite_encrypted_and_hmac_signed(tls_state_t *tls, unsigned size, unsigned type) | 529 | static void xwrite_encrypted_and_hmac_signed(tls_state_t *tls, unsigned size, unsigned type) |
659 | { | 530 | { |
660 | uint8_t *buf = tls->outbuf + OUTBUF_PFX; | 531 | uint8_t *buf = tls->outbuf + OUTBUF_PFX; |
@@ -676,7 +547,7 @@ static void xwrite_encrypted_and_hmac_signed(tls_state_t *tls, unsigned size, un | |||
676 | xhdr->len16_lo = size & 0xff; | 547 | xhdr->len16_lo = size & 0xff; |
677 | 548 | ||
678 | /* Calculate MAC signature */ | 549 | /* Calculate MAC signature */ |
679 | hmac(tls, buf + size, /* result */ | 550 | hmac_blocks(tls, buf + size, /* result */ |
680 | tls->client_write_MAC_key, TLS_MAC_SIZE(tls), | 551 | tls->client_write_MAC_key, TLS_MAC_SIZE(tls), |
681 | &tls->write_seq64_be, sizeof(tls->write_seq64_be), | 552 | &tls->write_seq64_be, sizeof(tls->write_seq64_be), |
682 | xhdr, RECHDR_LEN, | 553 | xhdr, RECHDR_LEN, |
@@ -865,8 +736,13 @@ static void xwrite_encrypted_aesgcm(tls_state_t *tls, unsigned size, unsigned ty | |||
865 | cnt++; | 736 | cnt++; |
866 | COUNTER(nonce) = htonl(cnt); /* yes, first cnt here is 2 (!) */ | 737 | COUNTER(nonce) = htonl(cnt); /* yes, first cnt here is 2 (!) */ |
867 | aes_encrypt_one_block(&tls->aes_encrypt, nonce, scratch); | 738 | aes_encrypt_one_block(&tls->aes_encrypt, nonce, scratch); |
868 | n = remaining > AES_BLOCK_SIZE ? AES_BLOCK_SIZE : remaining; | 739 | if (remaining >= AES_BLOCK_SIZE) { |
869 | xorbuf(buf, scratch, n); | 740 | n = AES_BLOCK_SIZE; |
741 | xorbuf_AES_BLOCK_SIZE(buf, scratch); | ||
742 | } else { | ||
743 | n = remaining; | ||
744 | xorbuf(buf, scratch, n); | ||
745 | } | ||
870 | buf += n; | 746 | buf += n; |
871 | remaining -= n; | 747 | remaining -= n; |
872 | } | 748 | } |
@@ -1024,7 +900,7 @@ static void tls_aesgcm_decrypt(tls_state_t *tls, uint8_t *buf, int size) | |||
1024 | COUNTER(nonce) = htonl(cnt); /* yes, first cnt here is 2 (!) */ | 900 | COUNTER(nonce) = htonl(cnt); /* yes, first cnt here is 2 (!) */ |
1025 | aes_encrypt_one_block(&tls->aes_decrypt, nonce, scratch); | 901 | aes_encrypt_one_block(&tls->aes_decrypt, nonce, scratch); |
1026 | n = remaining > AES_BLOCK_SIZE ? AES_BLOCK_SIZE : remaining; | 902 | n = remaining > AES_BLOCK_SIZE ? AES_BLOCK_SIZE : remaining; |
1027 | xorbuf3(buf, scratch, buf + 8, n); | 903 | xorbuf_3(buf, scratch, buf + 8, n); |
1028 | buf += n; | 904 | buf += n; |
1029 | remaining -= n; | 905 | remaining -= n; |
1030 | } | 906 | } |
diff --git a/networking/tls.h b/networking/tls.h index 0173b87b2..9751d30ff 100644 --- a/networking/tls.h +++ b/networking/tls.h | |||
@@ -82,10 +82,9 @@ typedef int16_t int16; | |||
82 | 82 | ||
83 | void tls_get_random(void *buf, unsigned len) FAST_FUNC; | 83 | void tls_get_random(void *buf, unsigned len) FAST_FUNC; |
84 | 84 | ||
85 | void xorbuf(void* buf, const void* mask, unsigned count) FAST_FUNC; | ||
86 | |||
87 | #define ALIGNED_long ALIGNED(sizeof(long)) | 85 | #define ALIGNED_long ALIGNED(sizeof(long)) |
88 | void xorbuf_aligned_AES_BLOCK_SIZE(void* buf, const void* mask) FAST_FUNC; | 86 | #define xorbuf_aligned_AES_BLOCK_SIZE(dst,src) xorbuf16_aligned_long(dst,src) |
87 | #define xorbuf_AES_BLOCK_SIZE(dst,src) xorbuf16(dst,src) | ||
89 | 88 | ||
90 | #define matrixCryptoGetPrngData(buf, len, userPtr) (tls_get_random(buf, len), PS_SUCCESS) | 89 | #define matrixCryptoGetPrngData(buf, len, userPtr) (tls_get_random(buf, len), PS_SUCCESS) |
91 | 90 | ||
diff --git a/networking/tls_aesgcm.c b/networking/tls_aesgcm.c index 5ddcdd2ad..9c2381a57 100644 --- a/networking/tls_aesgcm.c +++ b/networking/tls_aesgcm.c | |||
@@ -167,10 +167,7 @@ void FAST_FUNC aesgcm_GHASH(byte* h, | |||
167 | blocks = cSz / AES_BLOCK_SIZE; | 167 | blocks = cSz / AES_BLOCK_SIZE; |
168 | partial = cSz % AES_BLOCK_SIZE; | 168 | partial = cSz % AES_BLOCK_SIZE; |
169 | while (blocks--) { | 169 | while (blocks--) { |
170 | if (BB_UNALIGNED_MEMACCESS_OK) // c is not guaranteed to be aligned | 170 | xorbuf_AES_BLOCK_SIZE(x, c); |
171 | xorbuf_aligned_AES_BLOCK_SIZE(x, c); | ||
172 | else | ||
173 | xorbuf(x, c, AES_BLOCK_SIZE); | ||
174 | GMULT(x, h); | 171 | GMULT(x, h); |
175 | c += AES_BLOCK_SIZE; | 172 | c += AES_BLOCK_SIZE; |
176 | } | 173 | } |
diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c index 79cef1999..19c961d5c 100644 --- a/networking/udhcp/d6_dhcpc.c +++ b/networking/udhcp/d6_dhcpc.c | |||
@@ -148,10 +148,11 @@ enum { | |||
148 | OPT_o = 1 << 12, | 148 | OPT_o = 1 << 12, |
149 | OPT_x = 1 << 13, | 149 | OPT_x = 1 << 13, |
150 | OPT_f = 1 << 14, | 150 | OPT_f = 1 << 14, |
151 | OPT_l = 1 << 15, | 151 | OPT_m = 1 << 15, |
152 | OPT_d = 1 << 16, | 152 | OPT_l = 1 << 16, |
153 | OPT_d = 1 << 17, | ||
153 | /* The rest has variable bit positions, need to be clever */ | 154 | /* The rest has variable bit positions, need to be clever */ |
154 | OPTBIT_d = 16, | 155 | OPTBIT_d = 17, |
155 | USE_FOR_MMU( OPTBIT_b,) | 156 | USE_FOR_MMU( OPTBIT_b,) |
156 | ///IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,) | 157 | ///IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,) |
157 | IF_FEATURE_UDHCP_PORT( OPTBIT_P,) | 158 | IF_FEATURE_UDHCP_PORT( OPTBIT_P,) |
@@ -268,6 +269,23 @@ static void option_to_env(const uint8_t *option, const uint8_t *option_end) | |||
268 | //case D6_OPT_SERVERID: | 269 | //case D6_OPT_SERVERID: |
269 | case D6_OPT_IA_NA: | 270 | case D6_OPT_IA_NA: |
270 | case D6_OPT_IA_PD: | 271 | case D6_OPT_IA_PD: |
272 | /* 0 1 2 3 | ||
273 | * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 | ||
274 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
275 | * | OPTION_IA_PD | option-length | | ||
276 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
277 | * | IAID (4 octets) | | ||
278 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
279 | * | T1 | | ||
280 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
281 | * | T2 | | ||
282 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
283 | * . . | ||
284 | * . IA_PD-options . | ||
285 | * . . | ||
286 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
287 | */ | ||
288 | /* recurse to handle "IA_PD-options" field */ | ||
271 | option_to_env(option + 16, option + 4 + option[3]); | 289 | option_to_env(option + 16, option + 4 + option[3]); |
272 | break; | 290 | break; |
273 | //case D6_OPT_IA_TA: | 291 | //case D6_OPT_IA_TA: |
@@ -604,6 +622,31 @@ static NOINLINE int send_d6_info_request(void) | |||
604 | return d6_mcast_from_client_data_ifindex(&packet, opt_ptr); | 622 | return d6_mcast_from_client_data_ifindex(&packet, opt_ptr); |
605 | } | 623 | } |
606 | 624 | ||
625 | /* | ||
626 | * RFC 3315 10. Identity Association | ||
627 | * | ||
628 | * An "identity-association" (IA) is a construct through which a server | ||
629 | * and a client can identify, group, and manage a set of related IPv6 | ||
630 | * addresses. Each IA consists of an IAID and associated configuration | ||
631 | * information. | ||
632 | * | ||
633 | * A client must associate at least one distinct IA with each of its | ||
634 | * network interfaces for which it is to request the assignment of IPv6 | ||
635 | * addresses from a DHCP server. The client uses the IAs assigned to an | ||
636 | * interface to obtain configuration information from a server for that | ||
637 | * interface. Each IA must be associated with exactly one interface. | ||
638 | * | ||
639 | * The IAID uniquely identifies the IA and must be chosen to be unique | ||
640 | * among the IAIDs on the client. The IAID is chosen by the client. | ||
641 | * For any given use of an IA by the client, the IAID for that IA MUST | ||
642 | * be consistent across restarts of the DHCP client... | ||
643 | */ | ||
644 | /* Generate IAID. We base it on our MAC address' last 4 bytes */ | ||
645 | static void generate_iaid(uint8_t *iaid) | ||
646 | { | ||
647 | memcpy(iaid, &client_data.client_mac[2], 4); | ||
648 | } | ||
649 | |||
607 | /* Multicast a DHCPv6 Solicit packet to the network, with an optionally requested IP. | 650 | /* Multicast a DHCPv6 Solicit packet to the network, with an optionally requested IP. |
608 | * | 651 | * |
609 | * RFC 3315 17.1.1. Creation of Solicit Messages | 652 | * RFC 3315 17.1.1. Creation of Solicit Messages |
@@ -703,7 +746,7 @@ static NOINLINE int send_d6_discover(struct in6_addr *requested_ipv6) | |||
703 | client6_data.ia_na = xzalloc(len); | 746 | client6_data.ia_na = xzalloc(len); |
704 | client6_data.ia_na->code = D6_OPT_IA_NA; | 747 | client6_data.ia_na->code = D6_OPT_IA_NA; |
705 | client6_data.ia_na->len = len - 4; | 748 | client6_data.ia_na->len = len - 4; |
706 | *(bb__aliased_uint32_t*)client6_data.ia_na->data = rand(); /* IAID */ | 749 | generate_iaid(client6_data.ia_na->data); /* IAID */ |
707 | if (requested_ipv6) { | 750 | if (requested_ipv6) { |
708 | struct d6_option *iaaddr = (void*)(client6_data.ia_na->data + 4+4+4); | 751 | struct d6_option *iaaddr = (void*)(client6_data.ia_na->data + 4+4+4); |
709 | iaaddr->code = D6_OPT_IAADDR; | 752 | iaaddr->code = D6_OPT_IAADDR; |
@@ -721,7 +764,7 @@ static NOINLINE int send_d6_discover(struct in6_addr *requested_ipv6) | |||
721 | client6_data.ia_pd = xzalloc(len); | 764 | client6_data.ia_pd = xzalloc(len); |
722 | client6_data.ia_pd->code = D6_OPT_IA_PD; | 765 | client6_data.ia_pd->code = D6_OPT_IA_PD; |
723 | client6_data.ia_pd->len = len - 4; | 766 | client6_data.ia_pd->len = len - 4; |
724 | *(bb__aliased_uint32_t*)client6_data.ia_pd->data = rand(); /* IAID */ | 767 | generate_iaid(client6_data.ia_pd->data); /* IAID */ |
725 | opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, len); | 768 | opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, len); |
726 | } | 769 | } |
727 | 770 | ||
@@ -1131,12 +1174,11 @@ static void client_background(void) | |||
1131 | //usage:#endif | 1174 | //usage:#endif |
1132 | //usage:#define udhcpc6_trivial_usage | 1175 | //usage:#define udhcpc6_trivial_usage |
1133 | //usage: "[-fbq"IF_UDHCP_VERBOSE("v")"R] [-t N] [-T SEC] [-A SEC|-n] [-i IFACE] [-s PROG]\n" | 1176 | //usage: "[-fbq"IF_UDHCP_VERBOSE("v")"R] [-t N] [-T SEC] [-A SEC|-n] [-i IFACE] [-s PROG]\n" |
1134 | //usage: " [-p PIDFILE]"IF_FEATURE_UDHCP_PORT(" [-P PORT]")" [-ldo] [-r IPv6] [-x OPT:VAL]... [-O OPT]..." | 1177 | //usage: " [-p PIDFILE]"IF_FEATURE_UDHCP_PORT(" [-P PORT]")" [-mldo] [-r IPv6] [-x OPT:VAL]... [-O OPT]..." |
1135 | //usage:#define udhcpc6_full_usage "\n" | 1178 | //usage:#define udhcpc6_full_usage "\n" |
1136 | //usage: "\n -i IFACE Interface to use (default "CONFIG_UDHCPC_DEFAULT_INTERFACE")" | 1179 | //usage: "\n -i IFACE Interface to use (default "CONFIG_UDHCPC_DEFAULT_INTERFACE")" |
1137 | //usage: "\n -p FILE Create pidfile" | 1180 | //usage: "\n -p FILE Create pidfile" |
1138 | //usage: "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC6_DEFAULT_SCRIPT")" | 1181 | //usage: "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC6_DEFAULT_SCRIPT")" |
1139 | //usage: "\n -B Request broadcast replies" | ||
1140 | //usage: "\n -t N Send up to N discover packets" | 1182 | //usage: "\n -t N Send up to N discover packets" |
1141 | //usage: "\n -T SEC Pause between packets (default 3)" | 1183 | //usage: "\n -T SEC Pause between packets (default 3)" |
1142 | //usage: "\n -A SEC Wait if lease is not obtained (default 20)" | 1184 | //usage: "\n -A SEC Wait if lease is not obtained (default 20)" |
@@ -1154,6 +1196,7 @@ static void client_background(void) | |||
1154 | ////usage: IF_FEATURE_UDHCPC_ARPING( | 1196 | ////usage: IF_FEATURE_UDHCPC_ARPING( |
1155 | ////usage: "\n -a Use arping to validate offered address" | 1197 | ////usage: "\n -a Use arping to validate offered address" |
1156 | ////usage: ) | 1198 | ////usage: ) |
1199 | //usage: "\n -m Send multicast renew requests rather than unicast ones" | ||
1157 | //usage: "\n -l Send 'information request' instead of 'solicit'" | 1200 | //usage: "\n -l Send 'information request' instead of 'solicit'" |
1158 | //usage: "\n (used for servers which do not assign IPv6 addresses)" | 1201 | //usage: "\n (used for servers which do not assign IPv6 addresses)" |
1159 | //usage: "\n -r IPv6 Request this address ('no' to not request any IP)" | 1202 | //usage: "\n -r IPv6 Request this address ('no' to not request any IP)" |
@@ -1211,7 +1254,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1211 | /* Parse command line */ | 1254 | /* Parse command line */ |
1212 | opt = getopt32long(argv, "^" | 1255 | opt = getopt32long(argv, "^" |
1213 | /* O,x: list; -T,-t,-A take numeric param */ | 1256 | /* O,x: list; -T,-t,-A take numeric param */ |
1214 | "i:np:qRr:s:T:+t:+SA:+O:*ox:*fld" | 1257 | "i:np:qRr:s:T:+t:+SA:+O:*ox:*fmld" |
1215 | USE_FOR_MMU("b") | 1258 | USE_FOR_MMU("b") |
1216 | ///IF_FEATURE_UDHCPC_ARPING("a") | 1259 | ///IF_FEATURE_UDHCPC_ARPING("a") |
1217 | IF_FEATURE_UDHCP_PORT("P:") | 1260 | IF_FEATURE_UDHCP_PORT("P:") |
@@ -1464,7 +1507,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1464 | if (opt & OPT_l) | 1507 | if (opt & OPT_l) |
1465 | send_d6_info_request(); | 1508 | send_d6_info_request(); |
1466 | else | 1509 | else |
1467 | send_d6_renew(&srv6_buf, requested_ipv6); | 1510 | send_d6_renew(OPT_m ? NULL : &srv6_buf, requested_ipv6); |
1468 | timeout = discover_timeout; | 1511 | timeout = discover_timeout; |
1469 | packet_num++; | 1512 | packet_num++; |
1470 | continue; | 1513 | continue; |
@@ -1606,62 +1649,6 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1606 | case RENEW_REQUESTED: | 1649 | case RENEW_REQUESTED: |
1607 | case REBINDING: | 1650 | case REBINDING: |
1608 | if (packet.d6_msg_type == D6_MSG_REPLY) { | 1651 | if (packet.d6_msg_type == D6_MSG_REPLY) { |
1609 | unsigned start; | ||
1610 | uint32_t lease_seconds; | ||
1611 | struct d6_option *option; | ||
1612 | unsigned address_timeout; | ||
1613 | unsigned prefix_timeout; | ||
1614 | type_is_ok: | ||
1615 | change_listen_mode(LISTEN_NONE); | ||
1616 | |||
1617 | address_timeout = 0; | ||
1618 | prefix_timeout = 0; | ||
1619 | option = d6_find_option(packet.d6_options, packet_end, D6_OPT_STATUS_CODE); | ||
1620 | if (option && (option->data[0] | option->data[1]) != 0) { | ||
1621 | ///FIXME: | ||
1622 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
1623 | // | OPTION_STATUS_CODE | option-len | | ||
1624 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
1625 | // | status-code | | | ||
1626 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | ||
1627 | // . status-message . | ||
1628 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
1629 | // so why do we think it's NAK if data[0] is zero but data[1] is not? That's wrong... | ||
1630 | // we should also check that option->len is ok (i.e. not 0), right? | ||
1631 | /* return to init state */ | ||
1632 | bb_info_msg("received DHCP NAK (%u)", option->data[4]); | ||
1633 | d6_run_script(packet.d6_options, | ||
1634 | packet_end, "nak"); | ||
1635 | if (client_data.state != REQUESTING) | ||
1636 | d6_run_script_no_option("deconfig"); | ||
1637 | sleep(3); /* avoid excessive network traffic */ | ||
1638 | client_data.state = INIT_SELECTING; | ||
1639 | client_data.first_secs = 0; /* make secs field count from 0 */ | ||
1640 | requested_ipv6 = NULL; | ||
1641 | timeout = 0; | ||
1642 | packet_num = 0; | ||
1643 | continue; | ||
1644 | } | ||
1645 | option = d6_copy_option(packet.d6_options, packet_end, D6_OPT_SERVERID); | ||
1646 | if (!option) { | ||
1647 | bb_simple_info_msg("no server ID, ignoring packet"); | ||
1648 | continue; | ||
1649 | /* still selecting - this server looks bad */ | ||
1650 | } | ||
1651 | //Note: we do not bother comparing server IDs in Advertise and Reply msgs. | ||
1652 | //server_id variable is used solely for creation of proper server_id option | ||
1653 | //in outgoing packets. (why DHCPv6 even introduced it is a mystery). | ||
1654 | free(client6_data.server_id); | ||
1655 | client6_data.server_id = option; | ||
1656 | if (packet.d6_msg_type == D6_MSG_ADVERTISE) { | ||
1657 | /* enter requesting state */ | ||
1658 | change_listen_mode(LISTEN_RAW); | ||
1659 | client_data.state = REQUESTING; | ||
1660 | timeout = 0; | ||
1661 | packet_num = 0; | ||
1662 | continue; | ||
1663 | } | ||
1664 | /* It's a D6_MSG_REPLY */ | ||
1665 | /* | 1652 | /* |
1666 | * RFC 3315 18.1.8. Receipt of Reply Messages | 1653 | * RFC 3315 18.1.8. Receipt of Reply Messages |
1667 | * | 1654 | * |
@@ -1747,6 +1734,67 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1747 | * . . | 1734 | * . . |
1748 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 1735 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
1749 | */ | 1736 | */ |
1737 | unsigned start; | ||
1738 | uint32_t lease_seconds; | ||
1739 | struct d6_option *option; | ||
1740 | unsigned address_timeout; | ||
1741 | unsigned prefix_timeout; | ||
1742 | type_is_ok: | ||
1743 | change_listen_mode(LISTEN_NONE); | ||
1744 | |||
1745 | address_timeout = 0; | ||
1746 | prefix_timeout = 0; | ||
1747 | option = d6_find_option(packet.d6_options, packet_end, D6_OPT_STATUS_CODE); | ||
1748 | if (option) { | ||
1749 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
1750 | // | OPTION_STATUS_CODE | option-len | | ||
1751 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
1752 | // | status-code | | | ||
1753 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | ||
1754 | // . status-message . | ||
1755 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
1756 | unsigned len, status; | ||
1757 | len = ((unsigned)option->len_hi << 8) + option->len; | ||
1758 | if (len < 2) { | ||
1759 | bb_simple_error_msg("invalid OPTION_STATUS_CODE, ignoring packet"); | ||
1760 | continue; | ||
1761 | } | ||
1762 | status = ((unsigned)option->data[0] << 8) + option->data[1]; | ||
1763 | if (status != 0) { | ||
1764 | //TODO: handle status == 5 (UseMulticast)? | ||
1765 | /* return to init state */ | ||
1766 | bb_info_msg("received DHCP NAK: %u '%.*s'", status, len - 2, option->data + 2); | ||
1767 | d6_run_script(packet.d6_options, packet_end, "nak"); | ||
1768 | if (client_data.state != REQUESTING) | ||
1769 | d6_run_script_no_option("deconfig"); | ||
1770 | sleep(3); /* avoid excessive network traffic */ | ||
1771 | client_data.state = INIT_SELECTING; | ||
1772 | client_data.first_secs = 0; /* make secs field count from 0 */ | ||
1773 | requested_ipv6 = NULL; | ||
1774 | timeout = 0; | ||
1775 | packet_num = 0; | ||
1776 | continue; | ||
1777 | } | ||
1778 | } | ||
1779 | option = d6_copy_option(packet.d6_options, packet_end, D6_OPT_SERVERID); | ||
1780 | if (!option) { | ||
1781 | bb_simple_info_msg("no server ID, ignoring packet"); | ||
1782 | continue; | ||
1783 | /* still selecting - this server looks bad */ | ||
1784 | } | ||
1785 | //Note: we do not bother comparing server IDs in Advertise and Reply msgs. | ||
1786 | //server_id variable is used solely for creation of proper server_id option | ||
1787 | //in outgoing packets. (why DHCPv6 even introduced it is a mystery). | ||
1788 | free(client6_data.server_id); | ||
1789 | client6_data.server_id = option; | ||
1790 | if (packet.d6_msg_type == D6_MSG_ADVERTISE) { | ||
1791 | /* enter requesting state */ | ||
1792 | change_listen_mode(LISTEN_RAW); | ||
1793 | client_data.state = REQUESTING; | ||
1794 | timeout = 0; | ||
1795 | packet_num = 0; | ||
1796 | continue; | ||
1797 | } | ||
1750 | if (option_mask32 & OPT_r) { | 1798 | if (option_mask32 & OPT_r) { |
1751 | struct d6_option *iaaddr; | 1799 | struct d6_option *iaaddr; |
1752 | 1800 | ||
@@ -1790,6 +1838,21 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1790 | 1838 | ||
1791 | free(client6_data.ia_pd); | 1839 | free(client6_data.ia_pd); |
1792 | client6_data.ia_pd = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_PD); | 1840 | client6_data.ia_pd = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_PD); |
1841 | // 0 1 2 3 | ||
1842 | // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 | ||
1843 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
1844 | // | OPTION_IA_PD | option-length | | ||
1845 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
1846 | // | IAID (4 octets) | | ||
1847 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
1848 | // | T1 | | ||
1849 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
1850 | // | T2 | | ||
1851 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
1852 | // . . | ||
1853 | // . IA_PD-options . | ||
1854 | // . . | ||
1855 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
1793 | if (!client6_data.ia_pd) { | 1856 | if (!client6_data.ia_pd) { |
1794 | bb_info_msg("no %s option%s", "IA_PD", ", ignoring packet"); | 1857 | bb_info_msg("no %s option%s", "IA_PD", ", ignoring packet"); |
1795 | continue; | 1858 | continue; |
diff --git a/networking/udhcp/d6_packet.c b/networking/udhcp/d6_packet.c index 142de9b43..1d7541948 100644 --- a/networking/udhcp/d6_packet.c +++ b/networking/udhcp/d6_packet.c | |||
@@ -153,13 +153,15 @@ int FAST_FUNC d6_send_kernel_packet_from_client_data_ifindex( | |||
153 | } | 153 | } |
154 | setsockopt_reuseaddr(fd); | 154 | setsockopt_reuseaddr(fd); |
155 | 155 | ||
156 | memset(&sa, 0, sizeof(sa)); | 156 | if (src_ipv6) { |
157 | sa.sin6_family = AF_INET6; | 157 | memset(&sa, 0, sizeof(sa)); |
158 | sa.sin6_port = htons(source_port); | 158 | sa.sin6_family = AF_INET6; |
159 | sa.sin6_addr = *src_ipv6; /* struct copy */ | 159 | sa.sin6_port = htons(source_port); |
160 | if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) { | 160 | sa.sin6_addr = *src_ipv6; /* struct copy */ |
161 | msg = "bind(%s)"; | 161 | if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) { |
162 | goto ret_close; | 162 | msg = "bind(%s)"; |
163 | goto ret_close; | ||
164 | } | ||
163 | } | 165 | } |
164 | 166 | ||
165 | memset(&sa, 0, sizeof(sa)); | 167 | memset(&sa, 0, sizeof(sa)); |
diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c index 2904119e5..b9cbd6464 100644 --- a/networking/udhcp/dhcpd.c +++ b/networking/udhcp/dhcpd.c | |||
@@ -575,29 +575,51 @@ static void send_packet_to_client(struct dhcp_packet *dhcp_pkt, int force_broadc | |||
575 | const uint8_t *chaddr; | 575 | const uint8_t *chaddr; |
576 | uint32_t ciaddr; | 576 | uint32_t ciaddr; |
577 | 577 | ||
578 | // Was: | 578 | // Logic: |
579 | //if (force_broadcast) { /* broadcast */ } | 579 | //if (force_broadcast) { /* broadcast */ } |
580 | //else if (dhcp_pkt->ciaddr) { /* unicast to dhcp_pkt->ciaddr */ } | 580 | //else if (dhcp_pkt->ciaddr) { /* unicast to dhcp_pkt->ciaddr */ } |
581 | // ^^^ dhcp_pkt->ciaddr comes from client's request packet. | ||
582 | // We expect such clients to have an UDP socket listening on that IP. | ||
581 | //else if (dhcp_pkt->flags & htons(BROADCAST_FLAG)) { /* broadcast */ } | 583 | //else if (dhcp_pkt->flags & htons(BROADCAST_FLAG)) { /* broadcast */ } |
582 | //else { /* unicast to dhcp_pkt->yiaddr */ } | 584 | //else { /* unicast to dhcp_pkt->yiaddr */ } |
583 | // But this is wrong: yiaddr is _our_ idea what client's IP is | 585 | // ^^^ The last case is confusing, but *should* work. |
584 | // (for example, from lease file). Client may not know that, | 586 | // It's a case where client have sent a DISCOVER |
585 | // and may not have UDP socket listening on that IP! | 587 | // and does not have a kernel UDP socket listening on the IP |
586 | // We should never unicast to dhcp_pkt->yiaddr! | 588 | // we are offering in yiaddr (it does not know the IP yet)! |
587 | // dhcp_pkt->ciaddr, OTOH, comes from client's request packet, | 589 | // This *should* work because client *should* listen on a raw socket |
588 | // and can be used. | 590 | // instead at this time (IOW: it should examine ALL IPv4 packets |
589 | 591 | // "by hand", not relying on kernel's UDP stack.) | |
590 | if (force_broadcast | 592 | |
591 | || (dhcp_pkt->flags & htons(BROADCAST_FLAG)) | 593 | chaddr = dhcp_pkt->chaddr; |
592 | || dhcp_pkt->ciaddr == 0 | 594 | |
595 | if (dhcp_pkt->ciaddr == 0 | ||
596 | || force_broadcast /* sending DHCPNAK pkt? */ | ||
593 | ) { | 597 | ) { |
594 | log1s("broadcasting packet to client"); | 598 | if (dhcp_pkt->flags & htons(BROADCAST_FLAG) |
595 | ciaddr = INADDR_BROADCAST; | 599 | || force_broadcast /* sending DHCPNAK pkt? */ |
596 | chaddr = MAC_BCAST_ADDR; | 600 | ) { |
601 | // RFC 2131: | ||
602 | // If 'giaddr' is zero and 'ciaddr' is zero, and the broadcast bit is | ||
603 | // set, then the server broadcasts DHCPOFFER and DHCPACK messages to | ||
604 | // 0xffffffff. ... | ||
605 | // In all cases, when 'giaddr' is zero, the server broadcasts any DHCPNAK | ||
606 | // messages to 0xffffffff. | ||
607 | ciaddr = INADDR_BROADCAST; | ||
608 | chaddr = MAC_BCAST_ADDR; | ||
609 | log1s("broadcasting packet to client"); | ||
610 | } else { | ||
611 | // If the broadcast bit is not set and 'giaddr' is zero and | ||
612 | // 'ciaddr' is zero, then the server unicasts DHCPOFFER and DHCPACK | ||
613 | // messages to the client's hardware address and 'yiaddr' address. | ||
614 | ciaddr = dhcp_pkt->yiaddr; | ||
615 | log1("unicasting packet to client %ciaddr", 'y'); | ||
616 | } | ||
597 | } else { | 617 | } else { |
598 | log1s("unicasting packet to client ciaddr"); | 618 | // If the 'giaddr' |
619 | // field is zero and the 'ciaddr' field is nonzero, then the server | ||
620 | // unicasts DHCPOFFER and DHCPACK messages to the address in 'ciaddr'. | ||
599 | ciaddr = dhcp_pkt->ciaddr; | 621 | ciaddr = dhcp_pkt->ciaddr; |
600 | chaddr = dhcp_pkt->chaddr; | 622 | log1("unicasting packet to client %ciaddr", 'c'); |
601 | } | 623 | } |
602 | 624 | ||
603 | udhcp_send_raw_packet(dhcp_pkt, | 625 | udhcp_send_raw_packet(dhcp_pkt, |
@@ -624,6 +646,10 @@ static void send_packet_to_relay(struct dhcp_packet *dhcp_pkt) | |||
624 | static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast) | 646 | static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast) |
625 | { | 647 | { |
626 | if (dhcp_pkt->gateway_nip) | 648 | if (dhcp_pkt->gateway_nip) |
649 | // RFC 2131: | ||
650 | // If the 'giaddr' field in a DHCP message from a client is non-zero, | ||
651 | // the server sends any return messages to the 'DHCP server' port on the | ||
652 | // BOOTP relay agent whose address appears in 'giaddr'. | ||
627 | send_packet_to_relay(dhcp_pkt); | 653 | send_packet_to_relay(dhcp_pkt); |
628 | else | 654 | else |
629 | send_packet_to_client(dhcp_pkt, force_broadcast); | 655 | send_packet_to_client(dhcp_pkt, force_broadcast); |
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/runit/chpst.c b/runit/chpst.c index 4e3d613b7..3d04ee50d 100644 --- a/runit/chpst.c +++ b/runit/chpst.c | |||
@@ -38,7 +38,8 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
38 | //config: bool "setuidgid (4.2 kb)" | 38 | //config: bool "setuidgid (4.2 kb)" |
39 | //config: default y | 39 | //config: default y |
40 | //config: help | 40 | //config: help |
41 | //config: Sets soft resource limits as specified by options | 41 | //config: Sets UID and GID to those of the given account, and execs |
42 | //config: specified program. | ||
42 | //config: | 43 | //config: |
43 | //config:config ENVUIDGID | 44 | //config:config ENVUIDGID |
44 | //config: bool "envuidgid (4.1 kb)" | 45 | //config: bool "envuidgid (4.1 kb)" |
diff --git a/scripts/kconfig/lxdialog/check-lxdialog.sh b/scripts/kconfig/lxdialog/check-lxdialog.sh index 5075ebf2d..910ca1f7c 100755 --- a/scripts/kconfig/lxdialog/check-lxdialog.sh +++ b/scripts/kconfig/lxdialog/check-lxdialog.sh | |||
@@ -47,7 +47,7 @@ trap "rm -f $tmp" 0 1 2 3 15 | |||
47 | check() { | 47 | check() { |
48 | $cc -x c - -o $tmp 2>/dev/null <<'EOF' | 48 | $cc -x c - -o $tmp 2>/dev/null <<'EOF' |
49 | #include CURSES_LOC | 49 | #include CURSES_LOC |
50 | main() {} | 50 | int main() { return 0; } |
51 | EOF | 51 | EOF |
52 | if [ $? != 0 ]; then | 52 | if [ $? != 0 ]; then |
53 | echo " *** Unable to find the ncurses libraries or the" 1>&2 | 53 | echo " *** Unable to find the ncurses libraries or the" 1>&2 |
diff --git a/shell/Config.src b/shell/Config.src index 5efbf9995..5b3fe08f3 100644 --- a/shell/Config.src +++ b/shell/Config.src | |||
@@ -166,9 +166,10 @@ config FEATURE_SH_HISTFILESIZE | |||
166 | default y | 166 | default y |
167 | depends on SHELL_ASH || SHELL_HUSH | 167 | depends on SHELL_ASH || SHELL_HUSH |
168 | help | 168 | help |
169 | This option makes busybox shells to use $HISTFILESIZE variable | 169 | This option makes busybox shells to use $HISTSIZE and |
170 | to set shell history size. Note that its max value is capped | 170 | $HISTFILESIZE variables to set shell history size. |
171 | by "History size" setting in library tuning section. | 171 | Note that its max value is capped by "History size" setting |
172 | in library tuning section. | ||
172 | 173 | ||
173 | config FEATURE_SH_EMBEDDED_SCRIPTS | 174 | config FEATURE_SH_EMBEDDED_SCRIPTS |
174 | bool "Embed scripts in the binary" | 175 | bool "Embed scripts in the binary" |
diff --git a/shell/ash.c b/shell/ash.c index 9173b8608..9cacdff64 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -329,7 +329,7 @@ typedef long arith_t; | |||
329 | 329 | ||
330 | /* ============ Shell options */ | 330 | /* ============ Shell options */ |
331 | 331 | ||
332 | /* If you add/change options hare, update --help text too */ | 332 | /* If you add/change options here, update --help text too */ |
333 | static const char *const optletters_optnames[] ALIGN_PTR = { | 333 | static const char *const optletters_optnames[] ALIGN_PTR = { |
334 | "e" "errexit", | 334 | "e" "errexit", |
335 | "f" "noglob", | 335 | "f" "noglob", |
@@ -1596,7 +1596,6 @@ struct stackmark { | |||
1596 | size_t stacknleft; | 1596 | size_t stacknleft; |
1597 | }; | 1597 | }; |
1598 | 1598 | ||
1599 | |||
1600 | struct globals_memstack { | 1599 | struct globals_memstack { |
1601 | struct stack_block *g_stackp; // = &stackbase; | 1600 | struct stack_block *g_stackp; // = &stackbase; |
1602 | char *g_stacknxt; // = stackbase.space; | 1601 | char *g_stacknxt; // = stackbase.space; |
@@ -1619,7 +1618,6 @@ extern struct globals_memstack *BB_GLOBAL_CONST ash_ptr_to_globals_memstack; | |||
1619 | sstrend = stackbase.space + MINSIZE; \ | 1618 | sstrend = stackbase.space + MINSIZE; \ |
1620 | } while (0) | 1619 | } while (0) |
1621 | 1620 | ||
1622 | |||
1623 | #define stackblock() ((void *)g_stacknxt) | 1621 | #define stackblock() ((void *)g_stacknxt) |
1624 | #define stackblocksize() g_stacknleft | 1622 | #define stackblocksize() g_stacknleft |
1625 | 1623 | ||
@@ -2121,7 +2119,6 @@ struct localvar { | |||
2121 | # define VDYNAMIC 0 | 2119 | # define VDYNAMIC 0 |
2122 | #endif | 2120 | #endif |
2123 | 2121 | ||
2124 | |||
2125 | /* Need to be before varinit_data[] */ | 2122 | /* Need to be before varinit_data[] */ |
2126 | #if ENABLE_LOCALE_SUPPORT | 2123 | #if ENABLE_LOCALE_SUPPORT |
2127 | static void FAST_FUNC | 2124 | static void FAST_FUNC |
@@ -3007,7 +3004,6 @@ pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
3007 | 3004 | ||
3008 | /* ============ ... */ | 3005 | /* ============ ... */ |
3009 | 3006 | ||
3010 | |||
3011 | #define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024) | 3007 | #define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024) |
3012 | 3008 | ||
3013 | /* Syntax classes */ | 3009 | /* Syntax classes */ |
@@ -3414,13 +3410,11 @@ struct alias { | |||
3414 | int flag; | 3410 | int flag; |
3415 | }; | 3411 | }; |
3416 | 3412 | ||
3417 | |||
3418 | static struct alias **atab; // [ATABSIZE]; | 3413 | static struct alias **atab; // [ATABSIZE]; |
3419 | #define INIT_G_alias() do { \ | 3414 | #define INIT_G_alias() do { \ |
3420 | atab = xzalloc(ATABSIZE * sizeof(atab[0])); \ | 3415 | atab = xzalloc(ATABSIZE * sizeof(atab[0])); \ |
3421 | } while (0) | 3416 | } while (0) |
3422 | 3417 | ||
3423 | |||
3424 | static struct alias ** | 3418 | static struct alias ** |
3425 | __lookupalias(const char *name) | 3419 | __lookupalias(const char *name) |
3426 | { | 3420 | { |
@@ -3602,7 +3596,6 @@ unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
3602 | 3596 | ||
3603 | #endif /* ASH_ALIAS */ | 3597 | #endif /* ASH_ALIAS */ |
3604 | 3598 | ||
3605 | |||
3606 | /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */ | 3599 | /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */ |
3607 | #define FORK_FG 0 | 3600 | #define FORK_FG 0 |
3608 | #define FORK_BG 1 | 3601 | #define FORK_BG 1 |
@@ -3687,7 +3680,7 @@ signal_handler(int signo) | |||
3687 | return; | 3680 | return; |
3688 | } | 3681 | } |
3689 | #if ENABLE_FEATURE_EDITING | 3682 | #if ENABLE_FEATURE_EDITING |
3690 | bb_got_signal = signo; /* for read_line_input: "we got a signal" */ | 3683 | bb_got_signal = signo; /* for read_line_input / read builtin: "we got a signal" */ |
3691 | #endif | 3684 | #endif |
3692 | gotsig[signo - 1] = 1; | 3685 | gotsig[signo - 1] = 1; |
3693 | pending_sig = signo; | 3686 | pending_sig = signo; |
@@ -5462,7 +5455,6 @@ stoppedjobs(void) | |||
5462 | return retval; | 5455 | return retval; |
5463 | } | 5456 | } |
5464 | 5457 | ||
5465 | |||
5466 | /* | 5458 | /* |
5467 | * Code for dealing with input/output redirection. | 5459 | * Code for dealing with input/output redirection. |
5468 | */ | 5460 | */ |
@@ -8935,7 +8927,6 @@ commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
8935 | } | 8927 | } |
8936 | #endif | 8928 | #endif |
8937 | 8929 | ||
8938 | |||
8939 | /*static int funcblocksize; // size of structures in function */ | 8930 | /*static int funcblocksize; // size of structures in function */ |
8940 | /*static int funcstringsize; // size of strings in node */ | 8931 | /*static int funcstringsize; // size of strings in node */ |
8941 | static void *funcblock; /* block to allocate function from */ | 8932 | static void *funcblock; /* block to allocate function from */ |
@@ -10698,7 +10689,6 @@ goodname(const char *p) | |||
10698 | return endofname(p)[0] == '\0'; | 10689 | return endofname(p)[0] == '\0'; |
10699 | } | 10690 | } |
10700 | 10691 | ||
10701 | |||
10702 | /* | 10692 | /* |
10703 | * Search for a command. This is called before we fork so that the | 10693 | * Search for a command. This is called before we fork so that the |
10704 | * location of the command will be available in the parent as well as | 10694 | * location of the command will be available in the parent as well as |
@@ -13448,7 +13438,6 @@ parseheredoc(void) | |||
13448 | } | 13438 | } |
13449 | } | 13439 | } |
13450 | 13440 | ||
13451 | |||
13452 | static const char * | 13441 | static const char * |
13453 | expandstr(const char *ps, int syntax_type) | 13442 | expandstr(const char *ps, int syntax_type) |
13454 | { | 13443 | { |
@@ -14037,7 +14026,6 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
14037 | entry->u = cmdp->param; | 14026 | entry->u = cmdp->param; |
14038 | } | 14027 | } |
14039 | 14028 | ||
14040 | |||
14041 | /* | 14029 | /* |
14042 | * The trap builtin. | 14030 | * The trap builtin. |
14043 | */ | 14031 | */ |
@@ -14395,6 +14383,11 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
14395 | goto again; | 14383 | goto again; |
14396 | } | 14384 | } |
14397 | 14385 | ||
14386 | if ((uintptr_t)r == 2) /* -t SEC timeout? */ | ||
14387 | /* bash: "The exit status is greater than 128 if the timeout is exceeded." */ | ||
14388 | /* The actual value observed with bash 5.2.15: */ | ||
14389 | return 128 + SIGALRM; | ||
14390 | |||
14398 | if ((uintptr_t)r > 1) | 14391 | if ((uintptr_t)r > 1) |
14399 | ash_msg_and_raise_error(r); | 14392 | ash_msg_and_raise_error(r); |
14400 | 14393 | ||
@@ -14520,8 +14513,25 @@ exitshell(void) | |||
14520 | char *p; | 14513 | char *p; |
14521 | 14514 | ||
14522 | #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT | 14515 | #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT |
14523 | save_history(line_input_state); /* may be NULL */ | 14516 | if (line_input_state) { |
14517 | const char *hp; | ||
14518 | # if ENABLE_FEATURE_SH_HISTFILESIZE | ||
14519 | // in bash: | ||
14520 | // HISTFILESIZE controls the on-disk history file size (in lines, 0=no history): | ||
14521 | // "When this variable is assigned a value, the history file is truncated, if necessary" | ||
14522 | // but we do it only at exit, not on assignment: | ||
14523 | /* Use HISTFILESIZE to limit file size */ | ||
14524 | hp = lookupvar("HISTFILESIZE"); | ||
14525 | if (hp) | ||
14526 | line_input_state->max_history = size_from_HISTFILESIZE(hp); | ||
14527 | # endif | ||
14528 | /* HISTFILE: "If unset, the command history is not saved when a shell exits." */ | ||
14529 | hp = lookupvar("HISTFILE"); | ||
14530 | line_input_state->hist_file = hp; | ||
14531 | save_history(line_input_state); /* no-op if hist_file is NULL or "" */ | ||
14532 | } | ||
14524 | #endif | 14533 | #endif |
14534 | |||
14525 | savestatus = exitstatus; | 14535 | savestatus = exitstatus; |
14526 | TRACE(("pid %d, exitshell(%d)\n", getpid(), savestatus)); | 14536 | TRACE(("pid %d, exitshell(%d)\n", getpid(), savestatus)); |
14527 | if (setjmp(loc.loc)) | 14537 | if (setjmp(loc.loc)) |
@@ -14609,7 +14619,6 @@ init(void) | |||
14609 | } | 14619 | } |
14610 | } | 14620 | } |
14611 | 14621 | ||
14612 | |||
14613 | //usage:#define ash_trivial_usage | 14622 | //usage:#define ash_trivial_usage |
14614 | //usage: "[-il] [-|+Cabefmnuvx] [-|+o OPT]... [-c 'SCRIPT' [ARG0 ARGS] | FILE ARGS | -s ARGS]" | 14623 | //usage: "[-il] [-|+Cabefmnuvx] [-|+o OPT]... [-c 'SCRIPT' [ARG0 ARGS] | FILE ARGS | -s ARGS]" |
14615 | //////// comes from ^^^^^^^^^^optletters | 14624 | //////// comes from ^^^^^^^^^^optletters |
@@ -14862,7 +14871,12 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
14862 | if (hp) | 14871 | if (hp) |
14863 | line_input_state->hist_file = xstrdup(hp); | 14872 | line_input_state->hist_file = xstrdup(hp); |
14864 | # if ENABLE_FEATURE_SH_HISTFILESIZE | 14873 | # if ENABLE_FEATURE_SH_HISTFILESIZE |
14865 | hp = lookupvar("HISTFILESIZE"); | 14874 | hp = lookupvar("HISTSIZE"); |
14875 | /* Using HISTFILESIZE above to limit max_history would be WRONG: | ||
14876 | * users may set HISTFILESIZE=0 in their profile scripts | ||
14877 | * to prevent _saving_ of history files, but still want to have | ||
14878 | * non-zero history limit for in-memory list. | ||
14879 | */ | ||
14866 | line_input_state->max_history = size_from_HISTFILESIZE(hp); | 14880 | line_input_state->max_history = size_from_HISTFILESIZE(hp); |
14867 | # endif | 14881 | # endif |
14868 | } | 14882 | } |
@@ -14884,7 +14898,6 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
14884 | /* NOTREACHED */ | 14898 | /* NOTREACHED */ |
14885 | } | 14899 | } |
14886 | 14900 | ||
14887 | |||
14888 | /*- | 14901 | /*- |
14889 | * Copyright (c) 1989, 1991, 1993, 1994 | 14902 | * Copyright (c) 1989, 1991, 1993, 1994 |
14890 | * The Regents of the University of California. All rights reserved. | 14903 | * The Regents of the University of California. All rights reserved. |
diff --git a/shell/ash_test/ash-read/read_ifs2.right b/shell/ash_test/ash-read/read_ifs2.right new file mode 100644 index 000000000..797137dae --- /dev/null +++ b/shell/ash_test/ash-read/read_ifs2.right | |||
@@ -0,0 +1,9 @@ | |||
1 | |X|Y:Z:| | ||
2 | |X|Y:Z| | ||
3 | |X|Y| | ||
4 | |X|Y| | ||
5 | |X|| | ||
6 | |X|| | ||
7 | ||| | ||
8 | Whitespace should be trimmed too: | ||
9 | |X|Y| | ||
diff --git a/shell/ash_test/ash-read/read_ifs2.tests b/shell/ash_test/ash-read/read_ifs2.tests new file mode 100755 index 000000000..f01a68978 --- /dev/null +++ b/shell/ash_test/ash-read/read_ifs2.tests | |||
@@ -0,0 +1,9 @@ | |||
1 | echo "X:Y:Z:" | (IFS=": " read x y; echo "|$x|$y|") | ||
2 | echo "X:Y:Z" | (IFS=": " read x y; echo "|$x|$y|") | ||
3 | echo "X:Y:" | (IFS=": " read x y; echo "|$x|$y|") | ||
4 | echo "X:Y" | (IFS=": " read x y; echo "|$x|$y|") | ||
5 | echo "X:" | (IFS=": " read x y; echo "|$x|$y|") | ||
6 | echo "X" | (IFS=": " read x y; echo "|$x|$y|") | ||
7 | echo "" | (IFS=": " read x y; echo "|$x|$y|") | ||
8 | echo Whitespace should be trimmed too: | ||
9 | echo "X:Y : " | (IFS=": " read x y; echo "|$x|$y|") | ||
diff --git a/shell/ash_test/ash-read/read_t.right b/shell/ash_test/ash-read/read_t.right index 04126cbe6..3eedae275 100644 --- a/shell/ash_test/ash-read/read_t.right +++ b/shell/ash_test/ash-read/read_t.right | |||
@@ -1,4 +1,4 @@ | |||
1 | >< | 1 | >te:142< |
2 | >< | 2 | >:142< |
3 | >test< | 3 | >test:0< |
4 | >test< | 4 | >test:0< |
diff --git a/shell/ash_test/ash-read/read_t.tests b/shell/ash_test/ash-read/read_t.tests index d65f1aeaa..9fbeec517 100755 --- a/shell/ash_test/ash-read/read_t.tests +++ b/shell/ash_test/ash-read/read_t.tests | |||
@@ -1,10 +1,10 @@ | |||
1 | # bash 3.2 outputs: | 1 | # bash 5.2 outputs: |
2 | 2 | ||
3 | # >< | 3 | # >te:142< |
4 | { echo -n 'te'; sleep 2; echo 'st'; } | (read -t 1 reply; echo ">$reply<") | 4 | { echo -n 'te'; sleep 2; echo 'st'; } | (read -t 1 reply; echo ">$reply:$?<") |
5 | # >< | 5 | # >:142< |
6 | { sleep 2; echo 'test'; } | (read -t 1 reply; echo ">$reply<") | 6 | { sleep 2; echo 'test'; } | (read -t 1 reply; echo ">$reply:$?<") |
7 | # >test< | 7 | # >test:0< |
8 | { echo -n 'te'; sleep 1; echo 'st'; } | (read -t 2 reply; echo ">$reply<") | 8 | { echo -n 'te'; sleep 1; echo 'st'; } | (read -t 2 reply; echo ">$reply:$?<") |
9 | # >test< | 9 | # >test:0< |
10 | { sleep 1; echo 'test'; } | (read -t 2 reply; echo ">$reply<") | 10 | { sleep 1; echo 'test'; } | (read -t 2 reply; echo ">$reply:$?<") |
diff --git a/shell/ash_test/printenv.c b/shell/ash_test/printenv.c index c86308d3b..f0f41984d 100644 --- a/shell/ash_test/printenv.c +++ b/shell/ash_test/printenv.c | |||
@@ -31,9 +31,7 @@ | |||
31 | extern char **environ; | 31 | extern char **environ; |
32 | 32 | ||
33 | int | 33 | int |
34 | main (argc, argv) | 34 | main (int argc, char **argv) |
35 | int argc; | ||
36 | char **argv; | ||
37 | { | 35 | { |
38 | register char **envp, *eval; | 36 | register char **envp, *eval; |
39 | int len; | 37 | int len; |
diff --git a/shell/ash_test/recho.c b/shell/ash_test/recho.c index 42a5feafd..7e96b14cc 100644 --- a/shell/ash_test/recho.c +++ b/shell/ash_test/recho.c | |||
@@ -27,7 +27,7 @@ | |||
27 | #include <stdio.h> | 27 | #include <stdio.h> |
28 | #include <stdlib.h> | 28 | #include <stdlib.h> |
29 | 29 | ||
30 | void strprint(); | 30 | void strprint(char *); |
31 | 31 | ||
32 | int main(int argc, char **argv) | 32 | int main(int argc, char **argv) |
33 | { | 33 | { |
diff --git a/shell/hush.c b/shell/hush.c index 4a97293cc..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. |
@@ -1973,7 +2018,7 @@ static void record_pending_signo(int sig) | |||
1973 | || (G_traps && G_traps[SIGCHLD] && G_traps[SIGCHLD][0]) | 2018 | || (G_traps && G_traps[SIGCHLD] && G_traps[SIGCHLD][0]) |
1974 | /* ^^^ if SIGCHLD, interrupt line reading only if it has a trap */ | 2019 | /* ^^^ if SIGCHLD, interrupt line reading only if it has a trap */ |
1975 | ) { | 2020 | ) { |
1976 | bb_got_signal = sig; /* for read_line_input: "we got a signal" */ | 2021 | bb_got_signal = sig; /* for read_line_input / read builtin: "we got a signal" */ |
1977 | } | 2022 | } |
1978 | #endif | 2023 | #endif |
1979 | #if ENABLE_HUSH_FAST | 2024 | #if ENABLE_HUSH_FAST |
@@ -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? */ |
@@ -2099,11 +2138,33 @@ static sighandler_t pick_sighandler(unsigned sig) | |||
2099 | return handler; | 2138 | return handler; |
2100 | } | 2139 | } |
2101 | 2140 | ||
2102 | /* Restores tty foreground process group, and exits. */ | 2141 | static const char* FAST_FUNC get_local_var_value(const char *name); |
2103 | static void hush_exit(int exitcode) | 2142 | |
2143 | /* Self-explanatory. | ||
2144 | * Restores tty foreground process group too. | ||
2145 | */ | ||
2146 | static NORETURN void save_history_run_exit_trap_and_exit(int exitcode) | ||
2104 | { | 2147 | { |
2105 | #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT | 2148 | #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT |
2106 | save_history(G.line_input_state); /* may be NULL */ | 2149 | if (G.line_input_state |
2150 | && getpid() == G.root_pid /* exits in subshells do not save history */ | ||
2151 | ) { | ||
2152 | const char *hp; | ||
2153 | # if ENABLE_FEATURE_SH_HISTFILESIZE | ||
2154 | // in bash: | ||
2155 | // HISTFILESIZE controls the on-disk history file size (in lines, 0=no history): | ||
2156 | // "When this variable is assigned a value, the history file is truncated, if necessary" | ||
2157 | // but we do it only at exit, not on every assignment: | ||
2158 | /* Use HISTFILESIZE to limit file size */ | ||
2159 | hp = get_local_var_value("HISTFILESIZE"); | ||
2160 | if (hp) | ||
2161 | G.line_input_state->max_history = size_from_HISTFILESIZE(hp); | ||
2162 | # endif | ||
2163 | /* HISTFILE: "If unset, the command history is not saved when a shell exits." */ | ||
2164 | hp = get_local_var_value("HISTFILE"); | ||
2165 | G.line_input_state->hist_file = hp; | ||
2166 | save_history(G.line_input_state); /* no-op if hist_file is NULL or "" */ | ||
2167 | } | ||
2107 | #endif | 2168 | #endif |
2108 | 2169 | ||
2109 | fflush_all(); | 2170 | fflush_all(); |
@@ -2137,7 +2198,7 @@ static void hush_exit(int exitcode) | |||
2137 | 2198 | ||
2138 | fflush_all(); | 2199 | fflush_all(); |
2139 | #if ENABLE_HUSH_JOB | 2200 | #if ENABLE_HUSH_JOB |
2140 | sigexit(- (exitcode & 0xff)); | 2201 | restore_ttypgrp_and_killsig_or__exit(- (exitcode & 0xff)); |
2141 | #else | 2202 | #else |
2142 | _exit(exitcode); | 2203 | _exit(exitcode); |
2143 | #endif | 2204 | #endif |
@@ -2222,7 +2283,7 @@ static int check_and_run_traps(void) | |||
2222 | } | 2283 | } |
2223 | } | 2284 | } |
2224 | /* this restores tty pgrp, then kills us with SIGHUP */ | 2285 | /* this restores tty pgrp, then kills us with SIGHUP */ |
2225 | sigexit(SIGHUP); | 2286 | restore_ttypgrp_and_killsig_or__exit(SIGHUP); |
2226 | } | 2287 | } |
2227 | #endif | 2288 | #endif |
2228 | #if ENABLE_HUSH_FAST | 2289 | #if ENABLE_HUSH_FAST |
@@ -4607,6 +4668,11 @@ static int fetch_heredocs(o_string *as_string, struct pipe *pi, int heredoc_cnt, | |||
4607 | 4668 | ||
4608 | redir->rd_type = REDIRECT_HEREDOC2; | 4669 | redir->rd_type = REDIRECT_HEREDOC2; |
4609 | /* redir->rd_dup is (ab)used to indicate <<- */ | 4670 | /* redir->rd_dup is (ab)used to indicate <<- */ |
4671 | if (!redir->rd_filename) { | ||
4672 | /* examples: "echo <<", "echo <<<", "echo <<>" */ | ||
4673 | syntax_error("missing here document terminator"); | ||
4674 | return -1; | ||
4675 | } | ||
4610 | p = fetch_till_str(as_string, input, | 4676 | p = fetch_till_str(as_string, input, |
4611 | redir->rd_filename, redir->rd_dup); | 4677 | redir->rd_filename, redir->rd_dup); |
4612 | if (!p) { | 4678 | if (!p) { |
@@ -7366,11 +7432,6 @@ static void switch_off_special_sigs(unsigned mask) | |||
7366 | } | 7432 | } |
7367 | 7433 | ||
7368 | #if BB_MMU | 7434 | #if BB_MMU |
7369 | /* never called */ | ||
7370 | void re_execute_shell(char ***to_free, const char *s, | ||
7371 | char *g_argv0, char **g_argv, | ||
7372 | char **builtin_argv) NORETURN; | ||
7373 | |||
7374 | static void reset_traps_to_defaults(void) | 7435 | static void reset_traps_to_defaults(void) |
7375 | { | 7436 | { |
7376 | /* This function is always called in a child shell | 7437 | /* This function is always called in a child shell |
@@ -7420,10 +7481,8 @@ static void reset_traps_to_defaults(void) | |||
7420 | 7481 | ||
7421 | #else /* !BB_MMU */ | 7482 | #else /* !BB_MMU */ |
7422 | 7483 | ||
7423 | static void re_execute_shell(char ***to_free, const char *s, | 7484 | static NORETURN void re_execute_shell( |
7424 | char *g_argv0, char **g_argv, | 7485 | char * *volatile * to_free, const char *s, |
7425 | char **builtin_argv) NORETURN; | ||
7426 | static void re_execute_shell(char ***to_free, const char *s, | ||
7427 | char *g_argv0, char **g_argv, | 7486 | char *g_argv0, char **g_argv, |
7428 | char **builtin_argv) | 7487 | char **builtin_argv) |
7429 | { | 7488 | { |
@@ -7653,7 +7712,13 @@ static int generate_stream_from_string(const char *s, pid_t *pid_p) | |||
7653 | pid_t pid; | 7712 | pid_t pid; |
7654 | int channel[2]; | 7713 | int channel[2]; |
7655 | # if !BB_MMU | 7714 | # if !BB_MMU |
7656 | 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; | ||
7657 | # endif | 7722 | # endif |
7658 | 7723 | ||
7659 | xpipe(channel); | 7724 | xpipe(channel); |
@@ -7800,7 +7865,7 @@ static void setup_heredoc(struct redir_struct *redir) | |||
7800 | const char *heredoc = redir->rd_filename; | 7865 | const char *heredoc = redir->rd_filename; |
7801 | char *expanded; | 7866 | char *expanded; |
7802 | #if !BB_MMU | 7867 | #if !BB_MMU |
7803 | char **to_free; | 7868 | char * *volatile to_free; |
7804 | #endif | 7869 | #endif |
7805 | 7870 | ||
7806 | expanded = NULL; | 7871 | expanded = NULL; |
@@ -8275,7 +8340,7 @@ static const struct built_in_command *find_builtin(const char *name) | |||
8275 | return find_builtin_helper(name, bltins2, &bltins2[ARRAY_SIZE(bltins2)]); | 8340 | return find_builtin_helper(name, bltins2, &bltins2[ARRAY_SIZE(bltins2)]); |
8276 | } | 8341 | } |
8277 | 8342 | ||
8278 | #if ENABLE_HUSH_JOB && ENABLE_FEATURE_TAB_COMPLETION | 8343 | #if ENABLE_HUSH_INTERACTIVE && ENABLE_FEATURE_TAB_COMPLETION |
8279 | static const char * FAST_FUNC hush_command_name(int i) | 8344 | static const char * FAST_FUNC hush_command_name(int i) |
8280 | { | 8345 | { |
8281 | if (/*i >= 0 && */ i < ARRAY_SIZE(bltins1)) { | 8346 | if (/*i >= 0 && */ i < ARRAY_SIZE(bltins1)) { |
@@ -8441,10 +8506,8 @@ static void unset_func(const char *name) | |||
8441 | #define exec_function(to_free, funcp, argv) \ | 8506 | #define exec_function(to_free, funcp, argv) \ |
8442 | exec_function(funcp, argv) | 8507 | exec_function(funcp, argv) |
8443 | # endif | 8508 | # endif |
8444 | static void exec_function(char ***to_free, | 8509 | static NORETURN void exec_function( |
8445 | const struct function *funcp, | 8510 | char * *volatile *to_free, |
8446 | char **argv) NORETURN; | ||
8447 | static void exec_function(char ***to_free, | ||
8448 | const struct function *funcp, | 8511 | const struct function *funcp, |
8449 | char **argv) | 8512 | char **argv) |
8450 | { | 8513 | { |
@@ -8540,10 +8603,8 @@ static int run_function(const struct function *funcp, char **argv) | |||
8540 | #define exec_builtin(to_free, x, argv) \ | 8603 | #define exec_builtin(to_free, x, argv) \ |
8541 | exec_builtin(to_free, argv) | 8604 | exec_builtin(to_free, argv) |
8542 | #endif | 8605 | #endif |
8543 | static void exec_builtin(char ***to_free, | 8606 | static NORETURN void exec_builtin( |
8544 | const struct built_in_command *x, | 8607 | char * *volatile *to_free, |
8545 | char **argv) NORETURN; | ||
8546 | static void exec_builtin(char ***to_free, | ||
8547 | const struct built_in_command *x, | 8608 | const struct built_in_command *x, |
8548 | char **argv) | 8609 | char **argv) |
8549 | { | 8610 | { |
@@ -8566,8 +8627,7 @@ static void exec_builtin(char ***to_free, | |||
8566 | #endif | 8627 | #endif |
8567 | } | 8628 | } |
8568 | 8629 | ||
8569 | static void execvp_or_die(char **argv) NORETURN; | 8630 | static NORETURN void execvp_or_die(char **argv) |
8570 | static void execvp_or_die(char **argv) | ||
8571 | { | 8631 | { |
8572 | int e; | 8632 | int e; |
8573 | debug_printf_exec("execing '%s'\n", argv[0]); | 8633 | debug_printf_exec("execing '%s'\n", argv[0]); |
@@ -8688,10 +8748,8 @@ static void if_command_vV_print_and_exit(char opt_vV, char *cmd, const char *exp | |||
8688 | * The at_exit handlers apparently confuse the calling process, | 8748 | * The at_exit handlers apparently confuse the calling process, |
8689 | * in particular stdin handling. Not sure why? -- because of vfork! (vda) | 8749 | * in particular stdin handling. Not sure why? -- because of vfork! (vda) |
8690 | */ | 8750 | */ |
8691 | static void pseudo_exec_argv(nommu_save_t *nommu_save, | 8751 | static NORETURN NOINLINE void pseudo_exec_argv( |
8692 | char **argv, int assignment_cnt, | 8752 | volatile nommu_save_t *nommu_save, |
8693 | char **argv_expanded) NORETURN; | ||
8694 | static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, | ||
8695 | char **argv, int assignment_cnt, | 8753 | char **argv, int assignment_cnt, |
8696 | char **argv_expanded) | 8754 | char **argv_expanded) |
8697 | { | 8755 | { |
@@ -8717,7 +8775,8 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, | |||
8717 | #if BB_MMU | 8775 | #if BB_MMU |
8718 | G.shadowed_vars_pp = NULL; /* "don't save, free them instead" */ | 8776 | G.shadowed_vars_pp = NULL; /* "don't save, free them instead" */ |
8719 | #else | 8777 | #else |
8720 | G.shadowed_vars_pp = &nommu_save->old_vars; | 8778 | /* cast away volatility */ |
8779 | G.shadowed_vars_pp = (struct variable **)&nommu_save->old_vars; | ||
8721 | G.var_nest_level++; | 8780 | G.var_nest_level++; |
8722 | #endif | 8781 | #endif |
8723 | set_vars_and_save_old(new_env); | 8782 | set_vars_and_save_old(new_env); |
@@ -8844,10 +8903,8 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, | |||
8844 | 8903 | ||
8845 | /* Called after [v]fork() in run_pipe | 8904 | /* Called after [v]fork() in run_pipe |
8846 | */ | 8905 | */ |
8847 | static void pseudo_exec(nommu_save_t *nommu_save, | 8906 | static NORETURN void pseudo_exec( |
8848 | struct command *command, | 8907 | volatile nommu_save_t *nommu_save, |
8849 | char **argv_expanded) NORETURN; | ||
8850 | static void pseudo_exec(nommu_save_t *nommu_save, | ||
8851 | struct command *command, | 8908 | struct command *command, |
8852 | char **argv_expanded) | 8909 | char **argv_expanded) |
8853 | { | 8910 | { |
@@ -9732,8 +9789,7 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
9732 | 9789 | ||
9733 | /* Stores to nommu_save list of env vars putenv'ed | 9790 | /* Stores to nommu_save list of env vars putenv'ed |
9734 | * (NOMMU, on MMU we don't need that) */ | 9791 | * (NOMMU, on MMU we don't need that) */ |
9735 | /* cast away volatility... */ | 9792 | pseudo_exec(&nommu_save, command, argv_expanded); |
9736 | pseudo_exec((nommu_save_t*) &nommu_save, command, argv_expanded); | ||
9737 | /* pseudo_exec() does not return */ | 9793 | /* pseudo_exec() does not return */ |
9738 | } | 9794 | } |
9739 | 9795 | ||
@@ -10121,7 +10177,7 @@ static int run_list(struct pipe *pi) | |||
10121 | if (rcode != 0 && G.o_opt[OPT_O_ERREXIT]) { | 10177 | if (rcode != 0 && G.o_opt[OPT_O_ERREXIT]) { |
10122 | 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); |
10123 | if (G.errexit_depth == 0) | 10179 | if (G.errexit_depth == 0) |
10124 | hush_exit(rcode); | 10180 | save_history_run_exit_trap_and_exit(rcode); |
10125 | } | 10181 | } |
10126 | G.errexit_depth = sv_errexit_depth; | 10182 | G.errexit_depth = sv_errexit_depth; |
10127 | 10183 | ||
@@ -10195,6 +10251,53 @@ static int run_and_free_list(struct pipe *pi) | |||
10195 | /* | 10251 | /* |
10196 | * Initialization and main | 10252 | * Initialization and main |
10197 | */ | 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 | |||
10198 | static void install_sighandlers(unsigned mask) | 10301 | static void install_sighandlers(unsigned mask) |
10199 | { | 10302 | { |
10200 | sighandler_t old_handler; | 10303 | sighandler_t old_handler; |
@@ -10333,7 +10436,6 @@ static int set_mode(int state, char mode, const char *o_opt) | |||
10333 | int hush_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 10436 | int hush_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
10334 | int hush_main(int argc, char **argv) | 10437 | int hush_main(int argc, char **argv) |
10335 | { | 10438 | { |
10336 | pid_t cached_getpid; | ||
10337 | enum { | 10439 | enum { |
10338 | OPT_login = (1 << 0), | 10440 | OPT_login = (1 << 0), |
10339 | }; | 10441 | }; |
@@ -10346,6 +10448,11 @@ int hush_main(int argc, char **argv) | |||
10346 | struct variable *shell_ver; | 10448 | struct variable *shell_ver; |
10347 | 10449 | ||
10348 | 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 | ||
10349 | 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 */ |
10350 | G.last_exitcode = EXIT_SUCCESS; | 10457 | G.last_exitcode = EXIT_SUCCESS; |
10351 | #if !BB_MMU | 10458 | #if !BB_MMU |
@@ -10361,9 +10468,6 @@ int hush_main(int argc, char **argv) | |||
10361 | _exit(0); | 10468 | _exit(0); |
10362 | } | 10469 | } |
10363 | G.argv0_for_re_execing = argv[0]; | 10470 | G.argv0_for_re_execing = argv[0]; |
10364 | if (G.argv0_for_re_execing[0] == '-') | ||
10365 | /* reexeced hush should never be a login shell */ | ||
10366 | G.argv0_for_re_execing++; | ||
10367 | #endif | 10471 | #endif |
10368 | #if ENABLE_HUSH_TRAP | 10472 | #if ENABLE_HUSH_TRAP |
10369 | # if ENABLE_HUSH_FUNCTIONS | 10473 | # if ENABLE_HUSH_FUNCTIONS |
@@ -10376,9 +10480,8 @@ int hush_main(int argc, char **argv) | |||
10376 | G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */ | 10480 | G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */ |
10377 | #endif | 10481 | #endif |
10378 | 10482 | ||
10379 | cached_getpid = getpid(); /* for tcsetpgrp() during init */ | 10483 | G.root_pid = getpid(); /* for $PID (NOMMU can override via -$HEXPID:HEXPPID:...) */ |
10380 | G.root_pid = cached_getpid; /* for $PID (NOMMU can override via -$HEXPID:HEXPPID:...) */ | 10484 | G.root_ppid = getppid(); /* for $PPID (NOMMU can override) */ |
10381 | G.root_ppid = getppid(); /* for $PPID (NOMMU can override) */ | ||
10382 | 10485 | ||
10383 | /* Deal with HUSH_VERSION */ | 10486 | /* Deal with HUSH_VERSION */ |
10384 | debug_printf_env("unsetenv '%s'\n", "HUSH_VERSION"); | 10487 | debug_printf_env("unsetenv '%s'\n", "HUSH_VERSION"); |
@@ -10427,7 +10530,7 @@ int hush_main(int argc, char **argv) | |||
10427 | if (!get_local_var_value("PATH")) | 10530 | if (!get_local_var_value("PATH")) |
10428 | set_local_var_from_halves("PATH", bb_default_root_path); | 10531 | set_local_var_from_halves("PATH", bb_default_root_path); |
10429 | 10532 | ||
10430 | /* PS1/PS2 are set later, if we determine that we are interactive */ | 10533 | /* PS1/PS2/HISTFILE are set later, if we determine that we are interactive */ |
10431 | 10534 | ||
10432 | /* bash also exports SHLVL and _, | 10535 | /* bash also exports SHLVL and _, |
10433 | * and sets (but doesn't export) the following variables: | 10536 | * and sets (but doesn't export) the following variables: |
@@ -10449,7 +10552,6 @@ int hush_main(int argc, char **argv) | |||
10449 | * BASH_SOURCE=() | 10552 | * BASH_SOURCE=() |
10450 | * DIRSTACK=() | 10553 | * DIRSTACK=() |
10451 | * PIPESTATUS=([0]="0") | 10554 | * PIPESTATUS=([0]="0") |
10452 | * HISTFILE=/<xxx>/.bash_history | ||
10453 | * HISTFILESIZE=500 | 10555 | * HISTFILESIZE=500 |
10454 | * HISTSIZE=500 | 10556 | * HISTSIZE=500 |
10455 | * MAILCHECK=60 | 10557 | * MAILCHECK=60 |
@@ -10462,27 +10564,24 @@ int hush_main(int argc, char **argv) | |||
10462 | * PS4='+ ' | 10564 | * PS4='+ ' |
10463 | */ | 10565 | */ |
10464 | 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 | |||
10465 | #if NUM_SCRIPTS > 0 | 10575 | #if NUM_SCRIPTS > 0 |
10466 | if (argc < 0) { | 10576 | if (argc < 0) { |
10467 | char *script = get_script_content(-argc - 1); | 10577 | char *script = get_script_content(-argc - 1); |
10468 | G.global_argv = argv; | 10578 | G.global_argv = argv; |
10469 | G.global_argc = string_array_len(argv); | 10579 | G.global_argc = string_array_len(argv); |
10470 | //install_special_sighandlers(); - needed? | ||
10471 | parse_and_run_string(script); | 10580 | parse_and_run_string(script); |
10472 | goto final_return; | 10581 | goto final_return; |
10473 | } | 10582 | } |
10474 | #endif | 10583 | #endif |
10475 | 10584 | ||
10476 | /* Initialize some more globals to non-zero values */ | ||
10477 | die_func = restore_ttypgrp_and__exit; | ||
10478 | |||
10479 | /* Shell is non-interactive at first. We need to call | ||
10480 | * install_special_sighandlers() if we are going to execute "sh <script>", | ||
10481 | * "sh -c <cmds>" or login shell's /etc/profile and friends. | ||
10482 | * If we later decide that we are interactive, we run install_special_sighandlers() | ||
10483 | * in order to intercept (more) signals. | ||
10484 | */ | ||
10485 | |||
10486 | /* Parse options */ | 10585 | /* Parse options */ |
10487 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html */ | 10586 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html */ |
10488 | flags = (argv[0] && argv[0][0] == '-') ? OPT_login : 0; | 10587 | flags = (argv[0] && argv[0][0] == '-') ? OPT_login : 0; |
@@ -10546,6 +10645,7 @@ int hush_main(int argc, char **argv) | |||
10546 | case '$': { | 10645 | case '$': { |
10547 | unsigned long long empty_trap_mask; | 10646 | unsigned long long empty_trap_mask; |
10548 | 10647 | ||
10648 | G.reexeced_on_NOMMU = 1; | ||
10549 | G.root_pid = bb_strtou(optarg, &optarg, 16); | 10649 | G.root_pid = bb_strtou(optarg, &optarg, 16); |
10550 | optarg++; | 10650 | optarg++; |
10551 | G.root_ppid = bb_strtou(optarg, &optarg, 16); | 10651 | G.root_ppid = bb_strtou(optarg, &optarg, 16); |
@@ -10559,7 +10659,6 @@ int hush_main(int argc, char **argv) | |||
10559 | empty_trap_mask = bb_strtoull(optarg, &optarg, 16); | 10659 | empty_trap_mask = bb_strtoull(optarg, &optarg, 16); |
10560 | if (empty_trap_mask != 0) { | 10660 | if (empty_trap_mask != 0) { |
10561 | IF_HUSH_TRAP(int sig;) | 10661 | IF_HUSH_TRAP(int sig;) |
10562 | install_special_sighandlers(); | ||
10563 | # if ENABLE_HUSH_TRAP | 10662 | # if ENABLE_HUSH_TRAP |
10564 | G_traps = xzalloc(sizeof(G_traps[0]) * NSIG); | 10663 | G_traps = xzalloc(sizeof(G_traps[0]) * NSIG); |
10565 | for (sig = 1; sig < NSIG; sig++) { | 10664 | for (sig = 1; sig < NSIG; sig++) { |
@@ -10625,7 +10724,9 @@ int hush_main(int argc, char **argv) | |||
10625 | G.global_argv[0] = argv[0]; | 10724 | G.global_argv[0] = argv[0]; |
10626 | 10725 | ||
10627 | /* If we are login shell... */ | 10726 | /* If we are login shell... */ |
10628 | if (flags & OPT_login) { | 10727 | if (!G_reexeced_on_NOMMU /* reexeced hush should never be a login shell */ |
10728 | && (flags & OPT_login) | ||
10729 | ) { | ||
10629 | const char *hp = NULL; | 10730 | const char *hp = NULL; |
10630 | HFILE *input; | 10731 | HFILE *input; |
10631 | 10732 | ||
@@ -10633,7 +10734,6 @@ int hush_main(int argc, char **argv) | |||
10633 | input = hfopen("/etc/profile"); | 10734 | input = hfopen("/etc/profile"); |
10634 | run_profile: | 10735 | run_profile: |
10635 | if (input != NULL) { | 10736 | if (input != NULL) { |
10636 | install_special_sighandlers(); | ||
10637 | parse_and_run_file(input); | 10737 | parse_and_run_file(input); |
10638 | hfclose(input); | 10738 | hfclose(input); |
10639 | } | 10739 | } |
@@ -10670,8 +10770,6 @@ int hush_main(int argc, char **argv) | |||
10670 | */ | 10770 | */ |
10671 | char *script; | 10771 | char *script; |
10672 | 10772 | ||
10673 | install_special_sighandlers(); | ||
10674 | |||
10675 | G.global_argc--; | 10773 | G.global_argc--; |
10676 | G.global_argv++; | 10774 | G.global_argv++; |
10677 | #if !BB_MMU | 10775 | #if !BB_MMU |
@@ -10722,7 +10820,6 @@ int hush_main(int argc, char **argv) | |||
10722 | bb_simple_perror_msg_and_die(G.global_argv[0]); | 10820 | bb_simple_perror_msg_and_die(G.global_argv[0]); |
10723 | } | 10821 | } |
10724 | xfunc_error_retval = 1; | 10822 | xfunc_error_retval = 1; |
10725 | install_special_sighandlers(); | ||
10726 | parse_and_run_file(input); | 10823 | parse_and_run_file(input); |
10727 | #if ENABLE_FEATURE_CLEAN_UP | 10824 | #if ENABLE_FEATURE_CLEAN_UP |
10728 | hfclose(input); | 10825 | hfclose(input); |
@@ -10738,126 +10835,86 @@ int hush_main(int argc, char **argv) | |||
10738 | 10835 | ||
10739 | /* A shell is interactive if the '-i' flag was given, | 10836 | /* A shell is interactive if the '-i' flag was given, |
10740 | * or if all of the following conditions are met: | 10837 | * or if all of the following conditions are met: |
10741 | * no -c command | 10838 | * not -c 'CMD' |
10742 | * no arguments remaining or the -s flag given | 10839 | * not running a script (no arguments remaining, or -s flag given) |
10743 | * standard input is a terminal | 10840 | * standard input is a terminal |
10744 | * standard output is a terminal | 10841 | * standard output is a terminal |
10745 | * Refer to Posix.2, the description of the 'sh' utility. | 10842 | * Refer to Posix.2, the description of the 'sh' utility. |
10746 | */ | 10843 | */ |
10747 | #if ENABLE_HUSH_JOB | 10844 | #if ENABLE_HUSH_INTERACTIVE |
10748 | if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) { | 10845 | if (!G_reexeced_on_NOMMU |
10749 | G_saved_tty_pgrp = tcgetpgrp(STDIN_FILENO); | 10846 | && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO) |
10750 | debug_printf("saved_tty_pgrp:%d\n", G_saved_tty_pgrp); | 10847 | ) { |
10751 | if (G_saved_tty_pgrp < 0) | 10848 | /* Try to dup stdin to high fd#, >= 255 */ |
10752 | G_saved_tty_pgrp = 0; | ||
10753 | |||
10754 | /* try to dup stdin to high fd#, >= 255 */ | ||
10755 | G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, 254); | 10849 | G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, 254); |
10756 | if (G_interactive_fd < 0) { | 10850 | if (G_interactive_fd < 0) { |
10757 | /* try to dup to any fd */ | 10851 | /* Try to dup to any fd */ |
10758 | G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, -1); | 10852 | G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, -1); |
10759 | if (G_interactive_fd < 0) { | 10853 | if (G_interactive_fd < 0) |
10760 | /* give up */ | 10854 | /* Give up */ |
10761 | G_interactive_fd = 0; | 10855 | G_interactive_fd = 0; |
10762 | G_saved_tty_pgrp = 0; | ||
10763 | } | ||
10764 | } | 10856 | } |
10765 | } | 10857 | debug_printf("interactive_fd:%d\n", G_interactive_fd); |
10766 | debug_printf("interactive_fd:%d\n", G_interactive_fd); | 10858 | if (G_interactive_fd) { |
10767 | if (G_interactive_fd) { | 10859 | // TODO? bash: |
10768 | if (G_saved_tty_pgrp) { | 10860 | // if interactive but not a login shell, sources ~/.bashrc |
10769 | /* If we were run as 'hush &', sleep until we are | 10861 | // (--norc turns this off, --rcfile <file> overrides) |
10770 | * in the foreground (tty pgrp == our pgrp). | 10862 | # if ENABLE_HUSH_JOB |
10771 | * If we get started under a job aware app (like bash), | 10863 | /* Can we do job control? */ |
10772 | * make sure we are now in charge so we don't fight over | 10864 | G_saved_tty_pgrp = tcgetpgrp(G_interactive_fd); |
10773 | * who gets the foreground */ | 10865 | debug_printf("saved_tty_pgrp:%d\n", G_saved_tty_pgrp); |
10774 | while (1) { | 10866 | if (G_saved_tty_pgrp < 0) |
10775 | pid_t shell_pgrp = getpgrp(); | 10867 | G_saved_tty_pgrp = 0; /* no */ |
10776 | G_saved_tty_pgrp = tcgetpgrp(G_interactive_fd); | 10868 | if (G_saved_tty_pgrp) { |
10777 | if (G_saved_tty_pgrp == shell_pgrp) | 10869 | /* If we were run as 'hush &', sleep until we are |
10778 | break; | 10870 | * in the foreground (tty pgrp == our pgrp). |
10779 | /* send TTIN to ourself (should stop us) */ | 10871 | * If we get started under a job aware app (like bash), |
10780 | 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 | } | ||
10781 | } | 10890 | } |
10782 | } | ||
10783 | |||
10784 | /* Install more signal handlers */ | ||
10785 | install_special_sighandlers(); | ||
10786 | |||
10787 | if (G_saved_tty_pgrp) { | ||
10788 | /* Set other signals to restore saved_tty_pgrp */ | ||
10789 | install_fatal_sighandlers(); | ||
10790 | /* Put ourselves in our own process group | ||
10791 | * (bash, too, does this only if ctty is available) */ | ||
10792 | bb_setpgrp(); /* is the same as setpgid(our_pid, our_pid); */ | ||
10793 | /* Grab control of the terminal */ | ||
10794 | tcsetpgrp(G_interactive_fd, cached_getpid); | ||
10795 | } | ||
10796 | enable_restore_tty_pgrp_on_exit(); | ||
10797 | |||
10798 | # if ENABLE_FEATURE_EDITING | ||
10799 | G.line_input_state = new_line_input_t(FOR_SHELL); | ||
10800 | # if ENABLE_FEATURE_TAB_COMPLETION | ||
10801 | G.line_input_state->get_exe_name = hush_command_name; | ||
10802 | # endif | ||
10803 | # if EDITING_HAS_sh_get_var | ||
10804 | G.line_input_state->sh_get_var = get_local_var_value; | ||
10805 | # endif | ||
10806 | # endif | 10891 | # endif |
10807 | # if ENABLE_HUSH_SAVEHISTORY && MAX_HISTORY > 0 | 10892 | /* Install more signal handlers */ |
10808 | { | 10893 | install_special_sighandlers(); |
10809 | const char *hp = get_local_var_value("HISTFILE"); | 10894 | # if ENABLE_HUSH_JOB |
10810 | if (!hp) { | 10895 | if (G_saved_tty_pgrp) { |
10811 | hp = get_local_var_value("HOME"); | 10896 | /* Set fatal signals to restore saved_tty_pgrp */ |
10812 | if (hp) | 10897 | install_fatal_sighandlers(); |
10813 | hp = concat_path_file(hp, ".hush_history"); | 10898 | /* (The if() is an optimization: can avoid two redundant syscalls) */ |
10814 | } else { | 10899 | if (G_saved_tty_pgrp != G.root_pid) { |
10815 | hp = xstrdup(hp); | 10900 | /* Put ourselves in our own process group |
10816 | } | 10901 | * (bash, too, does this only if ctty is available) */ |
10817 | if (hp) { | 10902 | bb_setpgrp(); /* is the same as setpgid(our_pid, our_pid); */ |
10818 | G.line_input_state->hist_file = hp; | 10903 | /* Grab control of the terminal */ |
10819 | //set_local_var(xasprintf("HISTFILE=%s", ...)); | 10904 | tcsetpgrp(G_interactive_fd, G.root_pid); |
10905 | } | ||
10820 | } | 10906 | } |
10821 | # if ENABLE_FEATURE_SH_HISTFILESIZE | ||
10822 | hp = get_local_var_value("HISTFILESIZE"); | ||
10823 | G.line_input_state->max_history = size_from_HISTFILESIZE(hp); | ||
10824 | # endif | ||
10825 | } | ||
10826 | # endif | 10907 | # endif |
10827 | } else { | 10908 | # if ENABLE_FEATURE_EDITING_FANCY_PROMPT |
10828 | install_special_sighandlers(); | 10909 | /* Set (but not export) PS1/2 unless already set */ |
10829 | } | 10910 | if (!get_local_var_value("PS1")) |
10830 | #elif ENABLE_HUSH_INTERACTIVE | 10911 | set_local_var_from_halves("PS1", "\\w \\$ "); |
10831 | /* No job control compiled in, only prompt/line editing */ | 10912 | if (!get_local_var_value("PS2")) |
10832 | if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) { | 10913 | set_local_var_from_halves("PS2", "> "); |
10833 | G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, 254); | 10914 | # endif |
10834 | if (G_interactive_fd < 0) { | 10915 | init_line_editing(); |
10835 | /* try to dup to any fd */ | ||
10836 | G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, -1); | ||
10837 | if (G_interactive_fd < 0) | ||
10838 | /* give up */ | ||
10839 | G_interactive_fd = 0; | ||
10840 | } | ||
10841 | } | ||
10842 | install_special_sighandlers(); | ||
10843 | #else | ||
10844 | /* We have interactiveness code disabled */ | ||
10845 | install_special_sighandlers(); | ||
10846 | #endif | ||
10847 | /* bash: | ||
10848 | * if interactive but not a login shell, sources ~/.bashrc | ||
10849 | * (--norc turns this off, --rcfile <file> overrides) | ||
10850 | */ | ||
10851 | 10916 | ||
10852 | if (G_interactive_fd) { | 10917 | # if !ENABLE_FEATURE_SH_EXTRA_QUIET |
10853 | #if ENABLE_HUSH_INTERACTIVE && ENABLE_FEATURE_EDITING_FANCY_PROMPT | ||
10854 | /* Set (but not export) PS1/2 unless already set */ | ||
10855 | if (!get_local_var_value("PS1")) | ||
10856 | set_local_var_from_halves("PS1", "\\w \\$ "); | ||
10857 | if (!get_local_var_value("PS2")) | ||
10858 | set_local_var_from_halves("PS2", "> "); | ||
10859 | #endif | ||
10860 | if (!ENABLE_FEATURE_SH_EXTRA_QUIET) { | ||
10861 | /* note: ash and hush share this string */ | 10918 | /* note: ash and hush share this string */ |
10862 | printf("\n\n%s %s\n" | 10919 | printf("\n\n%s %s\n" |
10863 | 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") |
@@ -10865,13 +10922,15 @@ int hush_main(int argc, char **argv) | |||
10865 | bb_banner, | 10922 | bb_banner, |
10866 | "hush - the humble shell" | 10923 | "hush - the humble shell" |
10867 | ); | 10924 | ); |
10868 | } | 10925 | # endif |
10869 | } | 10926 | } /* if become interactive */ |
10927 | } /* if on tty */ | ||
10928 | #endif /* if INTERACTIVE is allowed by build config */ | ||
10870 | 10929 | ||
10871 | parse_and_run_file(hfopen(NULL)); /* stdin */ | 10930 | parse_and_run_file(hfopen(NULL)); /* stdin */ |
10872 | 10931 | ||
10873 | final_return: | 10932 | final_return: |
10874 | hush_exit(G.last_exitcode); | 10933 | save_history_run_exit_trap_and_exit(G.last_exitcode); |
10875 | } | 10934 | } |
10876 | 10935 | ||
10877 | /* | 10936 | /* |
@@ -11057,19 +11116,19 @@ static int FAST_FUNC builtin_exit(char **argv) | |||
11057 | * 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" |
11058 | */ | 11117 | */ |
11059 | 11118 | ||
11060 | /* note: EXIT trap is run by hush_exit */ | 11119 | /* note: EXIT trap is run by save_history_run_exit_trap_and_exit */ |
11061 | argv = skip_dash_dash(argv); | 11120 | argv = skip_dash_dash(argv); |
11062 | if (argv[0] == NULL) { | 11121 | if (argv[0] == NULL) { |
11063 | #if ENABLE_HUSH_TRAP | 11122 | #if ENABLE_HUSH_TRAP |
11064 | 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 */ |
11065 | hush_exit(G.pre_trap_exitcode); | 11124 | save_history_run_exit_trap_and_exit(G.pre_trap_exitcode); |
11066 | #endif | 11125 | #endif |
11067 | hush_exit(G.last_exitcode); | 11126 | save_history_run_exit_trap_and_exit(G.last_exitcode); |
11068 | } | 11127 | } |
11069 | /* mimic bash: exit 123abc == exit 255 + error msg */ | 11128 | /* mimic bash: exit 123abc == exit 255 + error msg */ |
11070 | xfunc_error_retval = 255; | 11129 | xfunc_error_retval = 255; |
11071 | /* bash: exit -2 == exit 254, no error msg */ | 11130 | /* bash: exit -2 == exit 254, no error msg */ |
11072 | hush_exit(xatoi(argv[0]) & 0xff); | 11131 | save_history_run_exit_trap_and_exit(xatoi(argv[0]) & 0xff); |
11073 | } | 11132 | } |
11074 | 11133 | ||
11075 | #if ENABLE_HUSH_TYPE | 11134 | #if ENABLE_HUSH_TYPE |
@@ -11175,6 +11234,11 @@ static int FAST_FUNC builtin_read(char **argv) | |||
11175 | goto again; | 11234 | goto again; |
11176 | } | 11235 | } |
11177 | 11236 | ||
11237 | if ((uintptr_t)r == 2) /* -t SEC timeout? */ | ||
11238 | /* bash: "The exit status is greater than 128 if the timeout is exceeded." */ | ||
11239 | /* The actual value observed with bash 5.2.15: */ | ||
11240 | return 128 + SIGALRM; | ||
11241 | |||
11178 | if ((uintptr_t)r > 1) { | 11242 | if ((uintptr_t)r > 1) { |
11179 | bb_simple_error_msg(r); | 11243 | bb_simple_error_msg(r); |
11180 | r = (char*)(uintptr_t)1; | 11244 | r = (char*)(uintptr_t)1; |
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-heredoc/heredoc_syntax_err_no_EOF1.right b/shell/hush_test/hush-heredoc/heredoc_syntax_err_no_EOF1.right new file mode 100644 index 000000000..7af73557a --- /dev/null +++ b/shell/hush_test/hush-heredoc/heredoc_syntax_err_no_EOF1.right | |||
@@ -0,0 +1 @@ | |||
hush: syntax error: missing here document terminator | |||
diff --git a/shell/hush_test/hush-heredoc/heredoc_syntax_err_no_EOF1.tests b/shell/hush_test/hush-heredoc/heredoc_syntax_err_no_EOF1.tests new file mode 100755 index 000000000..33ccde26b --- /dev/null +++ b/shell/hush_test/hush-heredoc/heredoc_syntax_err_no_EOF1.tests | |||
@@ -0,0 +1,2 @@ | |||
1 | echo << | ||
2 | echo Done: | ||
diff --git a/shell/hush_test/hush-heredoc/heredoc_syntax_err_no_EOF2.right b/shell/hush_test/hush-heredoc/heredoc_syntax_err_no_EOF2.right new file mode 100644 index 000000000..7af73557a --- /dev/null +++ b/shell/hush_test/hush-heredoc/heredoc_syntax_err_no_EOF2.right | |||
@@ -0,0 +1 @@ | |||
hush: syntax error: missing here document terminator | |||
diff --git a/shell/hush_test/hush-heredoc/heredoc_syntax_err_no_EOF2.tests b/shell/hush_test/hush-heredoc/heredoc_syntax_err_no_EOF2.tests new file mode 100755 index 000000000..fcda11045 --- /dev/null +++ b/shell/hush_test/hush-heredoc/heredoc_syntax_err_no_EOF2.tests | |||
@@ -0,0 +1,2 @@ | |||
1 | echo << > | ||
2 | echo Done: | ||
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-read/read_t.right b/shell/hush_test/hush-read/read_t.right index 04126cbe6..3eedae275 100644 --- a/shell/hush_test/hush-read/read_t.right +++ b/shell/hush_test/hush-read/read_t.right | |||
@@ -1,4 +1,4 @@ | |||
1 | >< | 1 | >te:142< |
2 | >< | 2 | >:142< |
3 | >test< | 3 | >test:0< |
4 | >test< | 4 | >test:0< |
diff --git a/shell/hush_test/hush-read/read_t.tests b/shell/hush_test/hush-read/read_t.tests index d65f1aeaa..9fbeec517 100755 --- a/shell/hush_test/hush-read/read_t.tests +++ b/shell/hush_test/hush-read/read_t.tests | |||
@@ -1,10 +1,10 @@ | |||
1 | # bash 3.2 outputs: | 1 | # bash 5.2 outputs: |
2 | 2 | ||
3 | # >< | 3 | # >te:142< |
4 | { echo -n 'te'; sleep 2; echo 'st'; } | (read -t 1 reply; echo ">$reply<") | 4 | { echo -n 'te'; sleep 2; echo 'st'; } | (read -t 1 reply; echo ">$reply:$?<") |
5 | # >< | 5 | # >:142< |
6 | { sleep 2; echo 'test'; } | (read -t 1 reply; echo ">$reply<") | 6 | { sleep 2; echo 'test'; } | (read -t 1 reply; echo ">$reply:$?<") |
7 | # >test< | 7 | # >test:0< |
8 | { echo -n 'te'; sleep 1; echo 'st'; } | (read -t 2 reply; echo ">$reply<") | 8 | { echo -n 'te'; sleep 1; echo 'st'; } | (read -t 2 reply; echo ">$reply:$?<") |
9 | # >test< | 9 | # >test:0< |
10 | { sleep 1; echo 'test'; } | (read -t 2 reply; echo ">$reply<") | 10 | { sleep 1; echo 'test'; } | (read -t 2 reply; echo ">$reply:$?<") |
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/shell/shell_common.c b/shell/shell_common.c index e5c2cefb3..754fef34b 100644 --- a/shell/shell_common.c +++ b/shell/shell_common.c | |||
@@ -55,7 +55,7 @@ const char* FAST_FUNC | |||
55 | shell_builtin_read(struct builtin_read_params *params) | 55 | shell_builtin_read(struct builtin_read_params *params) |
56 | { | 56 | { |
57 | struct pollfd pfd[1]; | 57 | struct pollfd pfd[1]; |
58 | #define fd (pfd[0].fd) /* -u FD */ | 58 | #define fd (pfd->fd) /* -u FD */ |
59 | unsigned err; | 59 | unsigned err; |
60 | unsigned end_ms; /* -t TIMEOUT */ | 60 | unsigned end_ms; /* -t TIMEOUT */ |
61 | int nchars; /* -n NUM */ | 61 | int nchars; /* -n NUM */ |
@@ -142,7 +142,7 @@ shell_builtin_read(struct builtin_read_params *params) | |||
142 | * bash seems to ignore -p PROMPT for this use case. | 142 | * bash seems to ignore -p PROMPT for this use case. |
143 | */ | 143 | */ |
144 | int r; | 144 | int r; |
145 | pfd[0].events = POLLIN; | 145 | pfd->events = POLLIN; |
146 | r = poll(pfd, 1, /*timeout:*/ 0); | 146 | r = poll(pfd, 1, /*timeout:*/ 0); |
147 | /* Return 0 only if poll returns 1 ("one fd ready"), else return 1: */ | 147 | /* Return 0 only if poll returns 1 ("one fd ready"), else return 1: */ |
148 | return (const char *)(uintptr_t)(r <= 0); | 148 | return (const char *)(uintptr_t)(r <= 0); |
@@ -204,8 +204,8 @@ shell_builtin_read(struct builtin_read_params *params) | |||
204 | * 32-bit unix time wrapped (year 2038+). | 204 | * 32-bit unix time wrapped (year 2038+). |
205 | */ | 205 | */ |
206 | if (timeout <= 0) { /* already late? */ | 206 | if (timeout <= 0) { /* already late? */ |
207 | retval = (const char *)(uintptr_t)1; | 207 | retval = (const char *)(uintptr_t)2; |
208 | goto ret; | 208 | break; |
209 | } | 209 | } |
210 | } | 210 | } |
211 | 211 | ||
@@ -214,11 +214,16 @@ shell_builtin_read(struct builtin_read_params *params) | |||
214 | * regardless of SA_RESTART-ness of that signal! | 214 | * regardless of SA_RESTART-ness of that signal! |
215 | */ | 215 | */ |
216 | errno = 0; | 216 | errno = 0; |
217 | pfd[0].events = POLLIN; | 217 | pfd->events = POLLIN; |
218 | //TODO race with a signal arriving just before the poll! | 218 | |
219 | if (poll(pfd, 1, timeout) <= 0) { | 219 | /* test bb_got_signal, then poll(), atomically wrt signals */ |
220 | /* timed out, or EINTR */ | 220 | if (check_got_signal_and_poll(pfd, timeout) <= 0) { |
221 | /* timed out, or some error */ | ||
221 | err = errno; | 222 | err = errno; |
223 | if (!err) { /* timed out */ | ||
224 | retval = (const char *)(uintptr_t)2; | ||
225 | break; | ||
226 | } | ||
222 | retval = (const char *)(uintptr_t)1; | 227 | retval = (const char *)(uintptr_t)1; |
223 | goto ret; | 228 | goto ret; |
224 | } | 229 | } |
diff --git a/sysklogd/syslogd.c b/sysklogd/syslogd.c index 7558051f0..2cbb22b6d 100644 --- a/sysklogd/syslogd.c +++ b/sysklogd/syslogd.c | |||
@@ -1045,7 +1045,7 @@ static int NOINLINE syslogd_init(char **argv) | |||
1045 | #endif | 1045 | #endif |
1046 | /* If they have not specified remote logging, then log locally */ | 1046 | /* If they have not specified remote logging, then log locally */ |
1047 | if (ENABLE_FEATURE_REMOTE_LOG && !(opts & OPT_remotelog)) // -R | 1047 | if (ENABLE_FEATURE_REMOTE_LOG && !(opts & OPT_remotelog)) // -R |
1048 | option_mask32 |= OPT_locallog; | 1048 | option_mask32 = (opts |= OPT_locallog); |
1049 | #if ENABLE_FEATURE_SYSLOGD_CFG | 1049 | #if ENABLE_FEATURE_SYSLOGD_CFG |
1050 | parse_syslogdcfg(opt_f); | 1050 | parse_syslogdcfg(opt_f); |
1051 | #endif | 1051 | #endif |
diff --git a/testsuite/cpio.tests b/testsuite/cpio.tests index 85e746589..a4462c53e 100755 --- a/testsuite/cpio.tests +++ b/testsuite/cpio.tests | |||
@@ -154,6 +154,29 @@ testing "cpio -R with extract" \ | |||
154 | " "" "" | 154 | " "" "" |
155 | SKIP= | 155 | SKIP= |
156 | 156 | ||
157 | # Create an archive containing a file with "../dont_write" filename. | ||
158 | # See that it will not be allowed to unpack. | ||
159 | # NB: GNU cpio 2.15 DOES NOT do such checks. | ||
160 | optional FEATURE_PATH_TRAVERSAL_PROTECTION | ||
161 | rm -rf cpio.testdir | ||
162 | mkdir -p cpio.testdir/prepare/inner | ||
163 | echo "file outside of destination was written" > cpio.testdir/prepare/dont_write | ||
164 | echo "data" > cpio.testdir/prepare/inner/to_extract | ||
165 | mkdir -p cpio.testdir/extract | ||
166 | testing "cpio extract file outside of destination" "\ | ||
167 | (cd cpio.testdir/prepare/inner && echo -e '../dont_write\nto_extract' | cpio -o -H newc) | (cd cpio.testdir/extract && cpio -vi 2>&1) | ||
168 | echo \$? | ||
169 | ls cpio.testdir/dont_write 2>&1" \ | ||
170 | "\ | ||
171 | cpio: removing leading '../' from member names | ||
172 | ../dont_write | ||
173 | to_extract | ||
174 | 1 blocks | ||
175 | 0 | ||
176 | ls: cpio.testdir/dont_write: No such file or directory | ||
177 | " "" "" | ||
178 | SKIP= | ||
179 | |||
157 | # Clean up | 180 | # Clean up |
158 | rm -rf cpio.testdir cpio.testdir2 2>/dev/null | 181 | rm -rf cpio.testdir cpio.testdir2 2>/dev/null |
159 | 182 | ||
diff --git a/testsuite/cryptpw.tests b/testsuite/cryptpw.tests index 0dd91fe15..83bfde521 100755 --- a/testsuite/cryptpw.tests +++ b/testsuite/cryptpw.tests | |||
@@ -22,21 +22,93 @@ testing "cryptpw des zz" \ | |||
22 | #SKIP= | 22 | #SKIP= |
23 | 23 | ||
24 | optional USE_BB_CRYPT_SHA | 24 | optional USE_BB_CRYPT_SHA |
25 | testing "cryptpw sha256" \ | 25 | # Note: mkpasswd-5.6.2 won't accept "-m sha256", wants "-m sha256crypt" |
26 | "cryptpw -m sha256 QWErty '123456789012345678901234567890'" \ | 26 | testing 'cryptpw sha256' \ |
27 | '$5$1234567890123456$5DxfOCmU4vRhtzfsbdK.6wSGMwwVbac7ZkWwusb8Si7\n' "" "" | 27 | 'cryptpw -m sha256 QWErty 1234567890123456' \ |
28 | '$5$1234567890123456$5DxfOCmU4vRhtzfsbdK.6wSGMwwVbac7ZkWwusb8Si7\n' \ | ||
29 | '' '' | ||
30 | # mkpasswd-5.6.2 does not allow overlong salts, we truncate (at 16 chars for sha256) | ||
31 | testing 'cryptpw sha256 overlong' \ | ||
32 | 'cryptpw -m sha256 QWErty 123456789012345678901234567890' \ | ||
33 | '$5$1234567890123456$5DxfOCmU4vRhtzfsbdK.6wSGMwwVbac7ZkWwusb8Si7\n' \ | ||
34 | '' '' | ||
35 | testing 'cryptpw sha256 implicit' \ | ||
36 | 'cryptpw QWErty \$5\$1234567890123456' \ | ||
37 | '$5$1234567890123456$5DxfOCmU4vRhtzfsbdK.6wSGMwwVbac7ZkWwusb8Si7\n' \ | ||
38 | '' '' | ||
39 | testing 'cryptpw sha256 rounds=99999' \ | ||
40 | 'cryptpw -m sha256 QWErty rounds=99999\$123456789012345678901234567890' \ | ||
41 | '$5$rounds=99999$1234567890123456$aYellycJGZM6AKyVzaQsSrDBdTixubtMnM6J.MN0xM8\n' \ | ||
42 | '' '' | ||
43 | testing 'cryptpw sha256 rounds=99999 implicit' \ | ||
44 | 'cryptpw QWErty \$5\$rounds=99999\$123456789012345678901234567890' \ | ||
45 | '$5$rounds=99999$1234567890123456$aYellycJGZM6AKyVzaQsSrDBdTixubtMnM6J.MN0xM8\n' \ | ||
46 | '' '' | ||
28 | 47 | ||
29 | testing "cryptpw sha256 rounds=99999" \ | 48 | testing 'cryptpw sha512' \ |
30 | "cryptpw -m sha256 QWErty 'rounds=99999\$123456789012345678901234567890'" \ | 49 | 'cryptpw -m sha512 QWErty 123456789012345678901234567890' \ |
31 | '$5$rounds=99999$1234567890123456$aYellycJGZM6AKyVzaQsSrDBdTixubtMnM6J.MN0xM8\n' "" "" | 50 | '$6$1234567890123456$KB7QqxFyqmJSWyQYcCuGeFukgz1bPQoipWZf7.9L7z3k8UNTXa6UikbKcUGDc2ANn7DOGmDaroxDgpK16w/RE0\n' \ |
32 | 51 | '' '' | |
33 | testing "cryptpw sha512" \ | 52 | testing 'cryptpw sha512crypt' \ |
34 | "cryptpw -m sha512 QWErty '123456789012345678901234567890'" \ | 53 | 'cryptpw -m sha512crypt QWErty 123456789012345678901234567890' \ |
35 | '$6$1234567890123456$KB7QqxFyqmJSWyQYcCuGeFukgz1bPQoipWZf7.9L7z3k8UNTXa6UikbKcUGDc2ANn7DOGmDaroxDgpK16w/RE0\n' "" "" | 54 | '$6$1234567890123456$KB7QqxFyqmJSWyQYcCuGeFukgz1bPQoipWZf7.9L7z3k8UNTXa6UikbKcUGDc2ANn7DOGmDaroxDgpK16w/RE0\n' \ |
55 | '' '' | ||
56 | testing 'cryptpw sha512 rounds=99999' \ | ||
57 | 'cryptpw -m sha512 QWErty rounds=99999\$123456789012345678901234567890' \ | ||
58 | '$6$rounds=99999$1234567890123456$BfF6gD6ZjUmwawH5QaAglYAxtU./yvsz0fcQ464l49aMI2DZW3j5ri28CrxK7riPWNpLuUpfaIdY751SBYKUH.\n' \ | ||
59 | '' '' | ||
60 | SKIP= | ||
36 | 61 | ||
37 | testing "cryptpw sha512 rounds=99999" \ | 62 | optional USE_BB_CRYPT_YES |
38 | "cryptpw -m sha512 QWErty 'rounds=99999\$123456789012345678901234567890'" \ | 63 | testing 'cryptpw yescrypt' \ |
39 | '$6$rounds=99999$1234567890123456$BfF6gD6ZjUmwawH5QaAglYAxtU./yvsz0fcQ464l49aMI2DZW3j5ri28CrxK7riPWNpLuUpfaIdY751SBYKUH.\n' "" "" | 64 | 'cryptpw -m yescrypt qweRTY123@-+ j9T\$123456789012345678901234' \ |
65 | '$y$j9T$123456789012345678901234$AKxw5OX/T4jD.v./IW.5tE/j7izNjw06fg3OvH1LsN9\n' \ | ||
66 | '' '' | ||
67 | testing 'cryptpw yescrypt with non-standard N=2048 instead of 4096 (j8T instead of j9T)' \ | ||
68 | 'cryptpw -m yescrypt qweRTY123@-+ j8T\$123456789012345678901234' \ | ||
69 | '$y$j8T$123456789012345678901234$JQUUfopCxlfZNE8f.THJwbOkhy.XtB3GIjo9HUVioWB\n' \ | ||
70 | '' '' | ||
71 | # mkpasswd-5.6.2 allows short salts for yescrypt | ||
72 | # ...but there is a catch. Not all of them. | ||
73 | # The "partial" (not fitting in whole bytes) ascii64-encoded salt | ||
74 | # is a special case. For example, "$zzz" would not even work in upstream. | ||
75 | testing 'cryptpw yescrypt with empty salt' \ | ||
76 | 'cryptpw -m yescrypt qweRTY123@-+ j9T\$' \ | ||
77 | '$y$j9T$$hpeksL94GXNRwnA00L3c8WFy0khFAUbCpBSak.N3Bp.\n' \ | ||
78 | '' '' | ||
79 | testing 'cryptpw yescrypt with 3-char salt' \ | ||
80 | 'cryptpw -m yescrypt qweRTY123@-+ j9T\$123' \ | ||
81 | '$y$j9T$123$A34DMIGUbUIo3bjx66Wtk2IFoREMIw6d49it25KQh2D\n' \ | ||
82 | '' '' | ||
83 | # "." is not allowed in mkpasswd-5.6.2 | ||
84 | # .................................... | ||
85 | # ".." is decoded into one zero byte (not two) | ||
86 | testing 'cryptpw yescrypt with 2-char salt ".."' \ | ||
87 | 'cryptpw -m yescrypt qweRTY123@-+ j9T\$..' \ | ||
88 | '$y$j9T$..$yVHeOayxOGg6cHL3.dg10u7T.qSgySfLN3uhSVSLNn/\n' \ | ||
89 | '' '' | ||
90 | # "..." is decoded into two zero bytes (not three, not one) | ||
91 | testing 'cryptpw yescrypt with 3-char salt "..."' \ | ||
92 | 'cryptpw -m yescrypt qweRTY123@-+ j9T\$...' \ | ||
93 | '$y$j9T$...$xHvJ5USZ7hFyXYbOijtEOMfZRS23cWIxu2eIBXRymA5\n' \ | ||
94 | '' '' | ||
95 | # "...." is decoded into three zero bytes (no surprises here) | ||
96 | testing 'cryptpw yescrypt with 4-char salt "...."' \ | ||
97 | 'cryptpw -m yescrypt qweRTY123@-+ j9T\$....' \ | ||
98 | '$y$j9T$....$wOnauYL2/NEtr6YQi9pi8AtV7L57sEbVOAnWJIcP9q2\n' \ | ||
99 | '' '' | ||
100 | # 84 chars = 21 4-char blocks which decode into 21*3 = 63 bytes. | ||
101 | # The last byte of the maximum allowed salt size has to come from an incomplete | ||
102 | # char block. E.g. "z/" encodes byte 0x7f. "z1" is 0xff. | ||
103 | # Anything larger (e.g. "z2") is an error (it encodes 0x13f). | ||
104 | testing 'cryptpw yescrypt with 86-char salt (max size)' \ | ||
105 | 'cryptpw -m yescrypt qweRTY123@-+ j9T\$123456789012345678901234567890123456789012345678901234567890123456789012345678901234z/' \ | ||
106 | '$y$j9T$123456789012345678901234567890123456789012345678901234567890123456789012345678901234z/$Exxe8IoPXiddFsqj7iqCanRf8FyquAoB0/uceLmLjG.\n' \ | ||
107 | '' '' | ||
108 | testing 'cryptpw yescrypt implicit' \ | ||
109 | 'cryptpw qweRTY123@-+ \$y\$j9T\$123456789012345678901234' \ | ||
110 | '$y$j9T$123456789012345678901234$AKxw5OX/T4jD.v./IW.5tE/j7izNjw06fg3OvH1LsN9\n' \ | ||
111 | '' '' | ||
40 | SKIP= | 112 | SKIP= |
41 | 113 | ||
42 | exit $FAILCOUNT | 114 | exit $FAILCOUNT |
diff --git a/testsuite/hexdump.tests b/testsuite/hexdump.tests index 517ec508b..d2c0a5dc8 100755 --- a/testsuite/hexdump.tests +++ b/testsuite/hexdump.tests | |||
@@ -5,6 +5,17 @@ | |||
5 | 5 | ||
6 | . ./testing.sh | 6 | . ./testing.sh |
7 | 7 | ||
8 | input=\ | ||
9 | "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"\ | ||
10 | "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"\ | ||
11 | "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"\ | ||
12 | "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"\ | ||
13 | "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" | ||
14 | |||
15 | little_endian=false | ||
16 | { printf '\0\1' | hexdump -d | grep -q 256; } && little_endian=true | ||
17 | readonly little_endian | ||
18 | |||
8 | # testing "description" "command" "result" "infile" "stdin" | 19 | # testing "description" "command" "result" "infile" "stdin" |
9 | testing 'hexdump -C with four NULs' \ | 20 | testing 'hexdump -C with four NULs' \ |
10 | 'hexdump -C' \ | 21 | 'hexdump -C' \ |
@@ -43,12 +54,17 @@ testing "hexdump -e %3_u" \ | |||
43 | 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f | 54 | 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f |
44 | f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff | 55 | f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff |
45 | " \ | 56 | " \ |
46 | "" \ | 57 | "" "$input" |
47 | "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"\ | 58 | |
48 | "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"\ | 59 | testing "hexdump -e %3_c" \ |
49 | "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"\ | 60 | "hexdump -e '16/1 \" %3_c\" \"\n\"'" \ |
50 | "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"\ | 61 | ' \\0 001 002 003 004 005 006 \\a \\b \\t \\n \\v \\f \\r 016 017 |
51 | "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"\ | 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" | ||
52 | 68 | ||
53 | testing "hexdump -e /1 %d" \ | 69 | testing "hexdump -e /1 %d" \ |
54 | "hexdump -e '16/1 \" %4d\" \"\n\"'" \ | 70 | "hexdump -e '16/1 \" %4d\" \"\n\"'" \ |
@@ -59,33 +75,74 @@ testing "hexdump -e /1 %d" \ | |||
59 | -128 -127 -126 -125 -124 -123 -122 -121 -120 -119 -118 -117 -116 -115 -114 -113 | 75 | -128 -127 -126 -125 -124 -123 -122 -121 -120 -119 -118 -117 -116 -115 -114 -113 |
60 | -16 -15 -14 -13 -12 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 | 76 | -16 -15 -14 -13 -12 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 |
61 | " \ | 77 | " \ |
62 | "" \ | 78 | "" "$input" |
63 | "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"\ | ||
64 | "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"\ | ||
65 | "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"\ | ||
66 | "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"\ | ||
67 | "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"\ | ||
68 | 79 | ||
69 | testing "hexdump -e /2 %d" \ | 80 | $little_endian || SKIP=1 |
70 | "hexdump -e '8/2 \" %6d\" \"\n\"'" \ | 81 | testing "hexdump -e /2 %d (little endian)" \ |
71 | "\ | 82 | "hexdump -e '8/2 \" %6d\" \"\n\"'" \ |
83 | "\ | ||
72 | 256 770 1284 1798 2312 2826 3340 3854 | 84 | 256 770 1284 1798 2312 2826 3340 3854 |
73 | 4368 4882 5396 5910 6424 6938 7452 7966 | 85 | 4368 4882 5396 5910 6424 6938 7452 7966 |
74 | 29040 29554 30068 30582 31096 31610 32124 32638 | 86 | 29040 29554 30068 30582 31096 31610 32124 32638 |
75 | -32384 -31870 -31356 -30842 -30328 -29814 -29300 -28786 | 87 | -32384 -31870 -31356 -30842 -30328 -29814 -29300 -28786 |
76 | -3600 -3086 -2572 -2058 -1544 -1030 -516 -2 | 88 | -3600 -3086 -2572 -2058 -1544 -1030 -516 -2 |
77 | " \ | 89 | " \ |
78 | "" \ | 90 | "" "$input" |
79 | "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"\ | 91 | SKIP= |
80 | "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"\ | 92 | |
81 | "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"\ | 93 | $little_endian && SKIP=1 |
82 | "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"\ | 94 | testing "hexdump -e /2 %d (big endian)" \ |
83 | "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"\ | 95 | "hexdump -e '8/2 \" %6d\" \"\n\"'" \ |
96 | "\ | ||
97 | 1 515 1029 1543 2057 2571 3085 3599 | ||
98 | 4113 4627 5141 5655 6169 6683 7197 7711 | ||
99 | 28785 29299 29813 30327 30841 31355 31869 32383 | ||
100 | -32639 -32125 -31611 -31097 -30583 -30069 -29555 -29041 | ||
101 | -3855 -3341 -2827 -2313 -1799 -1285 -771 -257 | ||
102 | " \ | ||
103 | "" "$input" | ||
104 | SKIP= | ||
84 | 105 | ||
85 | testing "hexdump -n4 -e '\"%u\"'" \ | 106 | $little_endian || SKIP=1 |
107 | testing "hexdump -e /2 %x (little endian)" \ | ||
108 | "hexdump -e '8/2 \" %6x\" \"\n\"'" \ | ||
109 | "\ | ||
110 | 100 302 504 706 908 b0a d0c f0e | ||
111 | 1110 1312 1514 1716 1918 1b1a 1d1c 1f1e | ||
112 | 7170 7372 7574 7776 7978 7b7a 7d7c 7f7e | ||
113 | 8180 8382 8584 8786 8988 8b8a 8d8c 8f8e | ||
114 | f1f0 f3f2 f5f4 f7f6 f9f8 fbfa fdfc fffe | ||
115 | " \ | ||
116 | "" "$input" | ||
117 | SKIP= | ||
118 | |||
119 | $little_endian && SKIP=1 | ||
120 | testing "hexdump -e /2 %x (big endian)" \ | ||
121 | "hexdump -e '8/2 \" %6x\" \"\n\"'" \ | ||
122 | "\ | ||
123 | 1 203 405 607 809 a0b c0d e0f | ||
124 | 1011 1213 1415 1617 1819 1a1b 1c1d 1e1f | ||
125 | 7071 7273 7475 7677 7879 7a7b 7c7d 7e7f | ||
126 | 8081 8283 8485 8687 8889 8a8b 8c8d 8e8f | ||
127 | f0f1 f2f3 f4f5 f6f7 f8f9 fafb fcfd feff | ||
128 | " \ | ||
129 | "" "$input" | ||
130 | SKIP= | ||
131 | |||
132 | $little_endian || SKIP=1 | ||
133 | testing "hexdump -n4 -e '\"%u\"' (little endian)" \ | ||
86 | "hexdump -n4 -e '\"%u\"'" \ | 134 | "hexdump -n4 -e '\"%u\"'" \ |
87 | "12345678" \ | 135 | "12345678" \ |
88 | "" \ | 136 | "" \ |
89 | "\x4e\x61\xbc\x00AAAA" | 137 | "\x4e\x61\xbc\x00AAAA" |
138 | SKIP= | ||
139 | |||
140 | $little_endian && SKIP=1 | ||
141 | testing "hexdump -n4 -e '\"%u\"' (big endian)" \ | ||
142 | "hexdump -n4 -e '\"%u\"'" \ | ||
143 | "1315027968" \ | ||
144 | "" \ | ||
145 | "\x4e\x61\xbc\x00AAAA" | ||
146 | SKIP= | ||
90 | 147 | ||
91 | exit $FAILCOUNT | 148 | exit $FAILCOUNT |
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/od.tests b/testsuite/od.tests index 4f245a7e8..c863bf2e8 100755 --- a/testsuite/od.tests +++ b/testsuite/od.tests | |||
@@ -61,7 +61,8 @@ testing "od -a (DESKTOP)" \ | |||
61 | "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" | 61 | "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" |
62 | SKIP= | 62 | SKIP= |
63 | 63 | ||
64 | testing "od -B" \ | 64 | $little_endian || SKIP=1 |
65 | testing "od -B (little-endian)" \ | ||
65 | "od -B" \ | 66 | "od -B" \ |
66 | "\ | 67 | "\ |
67 | 0000000 001001 005003 041101 177103 | 68 | 0000000 001001 005003 041101 177103 |
@@ -70,6 +71,16 @@ testing "od -B" \ | |||
70 | "" "$input" | 71 | "" "$input" |
71 | SKIP= | 72 | SKIP= |
72 | 73 | ||
74 | $little_endian && SKIP=1 | ||
75 | testing "od -B (big-endian)" \ | ||
76 | "od -B" \ | ||
77 | "\ | ||
78 | 0000000 000402 001412 040502 041776 | ||
79 | 0000010 | ||
80 | " \ | ||
81 | "" "$input" | ||
82 | SKIP= | ||
83 | |||
73 | $little_endian || SKIP=1 | 84 | $little_endian || SKIP=1 |
74 | testing "od -o (little-endian)" \ | 85 | testing "od -o (little-endian)" \ |
75 | "od -o" \ | 86 | "od -o" \ |
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); |