diff options
146 files changed, 6249 insertions, 1620 deletions
@@ -566,6 +566,15 @@ config OVERRIDE_APPLETS | |||
566 | environment variable. BB_OVERRIDE_APPLETS is checked first, if it | 566 | environment variable. BB_OVERRIDE_APPLETS is checked first, if it |
567 | allows the applet and this list is non-empty it is checked too. | 567 | allows the applet and this list is non-empty it is checked too. |
568 | 568 | ||
569 | config UNWIND_TABLES | ||
570 | bool "Include stack unwind tables in the binary" | ||
571 | default y | ||
572 | depends on PLATFORM_MINGW32 | ||
573 | help | ||
574 | Binaries can include support for stack unwinding. This isn't | ||
575 | normally required in BusyBox, but Windows' Control Flow Guard | ||
576 | needs it. Disabling this reduces the size of the binaries. | ||
577 | |||
569 | comment 'Build Options' | 578 | comment 'Build Options' |
570 | 579 | ||
571 | config STATIC | 580 | config STATIC |
@@ -551,6 +551,7 @@ libs-y := \ | |||
551 | findutils/ \ | 551 | findutils/ \ |
552 | init/ \ | 552 | init/ \ |
553 | libbb/ \ | 553 | libbb/ \ |
554 | libbb/yescrypt/ \ | ||
554 | libpwdgrp/ \ | 555 | libpwdgrp/ \ |
555 | loginutils/ \ | 556 | loginutils/ \ |
556 | mailutils/ \ | 557 | mailutils/ \ |
@@ -688,8 +689,12 @@ quiet_cmd_busybox__ ?= LINK $@ | |||
688 | "$(core-y)" \ | 689 | "$(core-y)" \ |
689 | "$(libs-y)" \ | 690 | "$(libs-y)" \ |
690 | "$(LDLIBS)" \ | 691 | "$(LDLIBS)" \ |
691 | "$(CONFIG_EXTRA_LDLIBS)" \ | 692 | $(CONFIG_EXTRA_LDLIBS) \ |
692 | && $(srctree)/scripts/generate_BUFSIZ.sh --post include/common_bufsiz.h | 693 | && $(srctree)/scripts/generate_BUFSIZ.sh --post include/common_bufsiz.h |
694 | # ^^^ note: CONFIG_xyz strings already have double quotes: their value | ||
695 | # is '"LIB LIB2"', therefore $(CONFIG_EXTRA_LDLIBS) above must NOT be written | ||
696 | # as "$(CONFIG_EXTRA_LDLIBS)", it would be passed as ""LIB LIB2"", | ||
697 | # and LIB2 would end up in $9, not $8 (and lost or misinterpreted). | ||
693 | 698 | ||
694 | # Generate System.map | 699 | # Generate System.map |
695 | quiet_cmd_sysmap = SYSMAP | 700 | quiet_cmd_sysmap = SYSMAP |
diff --git a/Makefile.flags b/Makefile.flags index f24fd9475..29fabcfb5 100644 --- a/Makefile.flags +++ b/Makefile.flags | |||
@@ -73,8 +73,13 @@ CFLAGS += $(call cc-option,-falign-jumps=1 -falign-labels=1 -falign-loops=1,) | |||
73 | endif | 73 | endif |
74 | 74 | ||
75 | # Defeat .eh_frame bloat (gcc 4.6.3 x86-32 defconfig: 20% smaller busybox binary): | 75 | # Defeat .eh_frame bloat (gcc 4.6.3 x86-32 defconfig: 20% smaller busybox binary): |
76 | ifneq ($(CONFIG_UNWIND_TABLES),y) | ||
76 | CFLAGS += $(call cc-option,-fno-unwind-tables,) | 77 | CFLAGS += $(call cc-option,-fno-unwind-tables,) |
77 | CFLAGS += $(call cc-option,-fno-asynchronous-unwind-tables,) | 78 | CFLAGS += $(call cc-option,-fno-asynchronous-unwind-tables,) |
79 | else | ||
80 | CFLAGS += $(call cc-option,-funwind-tables,) | ||
81 | CFLAGS += $(call cc-option,-fasynchronous-unwind-tables,) | ||
82 | endif | ||
78 | # No automatic printf->puts,putchar conversions | 83 | # No automatic printf->puts,putchar conversions |
79 | # (try disabling this and comparing assembly, it's instructive) | 84 | # (try disabling this and comparing assembly, it's instructive) |
80 | CFLAGS += $(call cc-option,-fno-builtin-printf,) | 85 | CFLAGS += $(call cc-option,-fno-builtin-printf,) |
@@ -151,11 +156,15 @@ ifeq ($(CONFIG_PLATFORM_MINGW32),y) | |||
151 | CFLAGS += -Iwin32 -DHAVE_STRING_H=1 -DHAVE_CONFIG_H=0 -fno-builtin-stpcpy -fno-builtin-stpncpy -fno-ident -fno-builtin-strndup | 156 | CFLAGS += -Iwin32 -DHAVE_STRING_H=1 -DHAVE_CONFIG_H=0 -fno-builtin-stpcpy -fno-builtin-stpncpy -fno-ident -fno-builtin-strndup |
152 | # this seems to be necessary for setjmp/longjmp to work with clang | 157 | # this seems to be necessary for setjmp/longjmp to work with clang |
153 | ifeq ($(lastword $(subst -, ,$(CC))),clang) | 158 | ifeq ($(lastword $(subst -, ,$(CC))),clang) |
159 | ifeq ($(CONFIG_UNWIND_TABLES),y) | ||
160 | CFLAGS += $(call cc-option,-fexceptions,) | ||
161 | else | ||
154 | CFLAGS += $(call cc-option,-fsjlj-exceptions,) | 162 | CFLAGS += $(call cc-option,-fsjlj-exceptions,) |
155 | endif | 163 | endif |
164 | endif | ||
156 | 165 | ||
157 | EXEEXT = .exe | 166 | EXEEXT = .exe |
158 | LDLIBS += ws2_32 | 167 | LDLIBS += ws2_32 bcrypt secur32 |
159 | endif | 168 | endif |
160 | 169 | ||
161 | ifneq ($(CONFIG_PLATFORM_MINGW32),y) | 170 | ifneq ($(CONFIG_PLATFORM_MINGW32),y) |
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 fb5deb0ce..1f1f28b61 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 167931bdb..38d826a3c 100644 --- a/archival/cpio.c +++ b/archival/cpio.c | |||
@@ -354,6 +354,12 @@ static NOINLINE int cpio_o(void) | |||
354 | #endif | 354 | #endif |
355 | #endif | 355 | #endif |
356 | 356 | ||
357 | if (sizeof(st.st_size) > 4 | ||
358 | && st.st_size > (off_t)0xffffffff | ||
359 | ) { | ||
360 | bb_error_msg_and_die("error: file '%s' is larger than 4GB", name); | ||
361 | } | ||
362 | |||
357 | bytes += printf("070701" | 363 | bytes += printf("070701" |
358 | "%08X%08X%08X%08X%08X%08X%08X" | 364 | "%08X%08X%08X%08X%08X%08X%08X" |
359 | "%08X%08X%08X%08X" /* GNU cpio uses uppercase hex */ | 365 | "%08X%08X%08X%08X" /* GNU cpio uses uppercase hex */ |
@@ -425,6 +431,7 @@ int cpio_main(int argc UNUSED_PARAM, char **argv) | |||
425 | #endif | 431 | #endif |
426 | #endif | 432 | #endif |
427 | "owner\0" Required_argument "R" | 433 | "owner\0" Required_argument "R" |
434 | "file\0" Required_argument "F" | ||
428 | "verbose\0" No_argument "v" | 435 | "verbose\0" No_argument "v" |
429 | "null\0" No_argument "0" | 436 | "null\0" No_argument "0" |
430 | "quiet\0" No_argument "\xff" | 437 | "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 3d202ad26..a949c4509 100644 --- a/archival/libarchive/open_transformer.c +++ b/archival/libarchive/open_transformer.c | |||
@@ -164,7 +164,7 @@ void FAST_FUNC fork_transformer(int fd, const char *transform_prog) | |||
164 | /* Used by e.g. rpm which gives us a fd without filename, | 164 | /* Used by e.g. rpm which gives us a fd without filename, |
165 | * thus we can't guess the format from filename's extension. | 165 | * thus we can't guess the format from filename's extension. |
166 | */ | 166 | */ |
167 | static transformer_state_t *setup_transformer_on_fd(int fd, int fail_if_not_compressed) | 167 | static transformer_state_t *setup_transformer_on_fd(int fd, int die_if_not_compressed) |
168 | { | 168 | { |
169 | transformer_state_t *xstate; | 169 | transformer_state_t *xstate; |
170 | 170 | ||
@@ -211,7 +211,7 @@ static transformer_state_t *setup_transformer_on_fd(int fd, int fail_if_not_comp | |||
211 | } | 211 | } |
212 | 212 | ||
213 | /* No known magic seen */ | 213 | /* No known magic seen */ |
214 | if (fail_if_not_compressed) | 214 | if (die_if_not_compressed) |
215 | bb_simple_error_msg_and_die("no gzip" | 215 | bb_simple_error_msg_and_die("no gzip" |
216 | IF_FEATURE_SEAMLESS_BZ2("/bzip2") | 216 | IF_FEATURE_SEAMLESS_BZ2("/bzip2") |
217 | IF_FEATURE_SEAMLESS_XZ("/xz") | 217 | IF_FEATURE_SEAMLESS_XZ("/xz") |
@@ -247,13 +247,15 @@ static void fork_transformer_and_free(transformer_state_t *xstate) | |||
247 | /* Used by e.g. rpm which gives us a fd without filename, | 247 | /* Used by e.g. rpm which gives us a fd without filename, |
248 | * thus we can't guess the format from filename's extension. | 248 | * thus we can't guess the format from filename's extension. |
249 | */ | 249 | */ |
250 | int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_compressed) | 250 | int FAST_FUNC setup_unzip_on_fd(int fd, int die_if_not_compressed) |
251 | { | 251 | { |
252 | transformer_state_t *xstate = setup_transformer_on_fd(fd, fail_if_not_compressed); | 252 | transformer_state_t *xstate = setup_transformer_on_fd(fd, die_if_not_compressed); |
253 | 253 | ||
254 | if (!xstate->xformer) { | 254 | if (!xstate->xformer) { |
255 | /* Not compressed */ | ||
256 | int retval = xstate->signature_skipped; /* never zero */ | ||
255 | free(xstate); | 257 | free(xstate); |
256 | return 1; | 258 | return retval; |
257 | } | 259 | } |
258 | 260 | ||
259 | fork_transformer_and_free(xstate); | 261 | fork_transformer_and_free(xstate); |
@@ -271,7 +273,7 @@ void FAST_FUNC setup_lzma_on_fd(int fd) | |||
271 | } | 273 | } |
272 | #endif | 274 | #endif |
273 | 275 | ||
274 | static transformer_state_t *open_transformer(const char *fname, int fail_if_not_compressed) | 276 | static transformer_state_t *open_transformer(const char *fname, int die_if_not_compressed) |
275 | { | 277 | { |
276 | transformer_state_t *xstate; | 278 | transformer_state_t *xstate; |
277 | int fd; | 279 | int fd; |
@@ -291,18 +293,18 @@ static transformer_state_t *open_transformer(const char *fname, int fail_if_not_ | |||
291 | } | 293 | } |
292 | } | 294 | } |
293 | 295 | ||
294 | xstate = setup_transformer_on_fd(fd, fail_if_not_compressed); | 296 | xstate = setup_transformer_on_fd(fd, die_if_not_compressed); |
295 | 297 | ||
296 | return xstate; | 298 | return xstate; |
297 | } | 299 | } |
298 | 300 | ||
299 | int FAST_FUNC open_zipped(const char *fname, int fail_if_not_compressed) | 301 | int FAST_FUNC open_zipped(const char *fname, int die_if_not_compressed) |
300 | { | 302 | { |
301 | int fd; | 303 | int fd; |
302 | transformer_state_t *xstate; | 304 | transformer_state_t *xstate; |
303 | 305 | ||
304 | xstate = open_transformer(fname, fail_if_not_compressed); | 306 | xstate = open_transformer(fname, die_if_not_compressed); |
305 | if (!xstate) | 307 | if (!xstate) /* open error */ |
306 | return -1; | 308 | return -1; |
307 | 309 | ||
308 | fd = xstate->src_fd; | 310 | fd = xstate->src_fd; |
@@ -333,7 +335,7 @@ void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_ | |||
333 | transformer_state_t *xstate; | 335 | transformer_state_t *xstate; |
334 | char *image; | 336 | char *image; |
335 | 337 | ||
336 | xstate = open_transformer(fname, /*fail_if_not_compressed:*/ 0); | 338 | xstate = open_transformer(fname, /*die_if_not_compressed:*/ 0); |
337 | if (!xstate) /* file open error */ | 339 | if (!xstate) /* file open error */ |
338 | return NULL; | 340 | return NULL; |
339 | 341 | ||
@@ -378,7 +380,7 @@ void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_ | |||
378 | int fd; | 380 | int fd; |
379 | char *image; | 381 | char *image; |
380 | 382 | ||
381 | fd = open_zipped(fname, /*fail_if_not_compressed:*/ 0); | 383 | fd = open_zipped(fname, /*die_if_not_compressed:*/ 0); |
382 | if (fd < 0) | 384 | if (fd < 0) |
383 | return NULL; | 385 | return NULL; |
384 | 386 | ||
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 d83c33137..c2f0550ff 100644 --- a/archival/rpm.c +++ b/archival/rpm.c | |||
@@ -330,7 +330,7 @@ static void extract_cpio(int fd, const char *source_rpm) | |||
330 | archive_handle->src_fd = fd; | 330 | archive_handle->src_fd = fd; |
331 | /*archive_handle->offset = 0; - init_handle() did it */ | 331 | /*archive_handle->offset = 0; - init_handle() did it */ |
332 | 332 | ||
333 | setup_unzip_on_fd(archive_handle->src_fd, /*fail_if_not_compressed:*/ 1); | 333 | setup_unzip_on_fd(archive_handle->src_fd, /*die_if_not_compressed:*/ 1); |
334 | while (get_header_cpio(archive_handle) == EXIT_SUCCESS) | 334 | while (get_header_cpio(archive_handle) == EXIT_SUCCESS) |
335 | continue; | 335 | continue; |
336 | } | 336 | } |
@@ -549,6 +549,7 @@ int rpm2cpio_main(int argc UNUSED_PARAM, char **argv) | |||
549 | // /* We need to know whether child (gzip/bzip/etc) exits abnormally */ | 549 | // /* We need to know whether child (gzip/bzip/etc) exits abnormally */ |
550 | // signal(SIGCHLD, check_errors_in_children); | 550 | // signal(SIGCHLD, check_errors_in_children); |
551 | 551 | ||
552 | str = NULL; | ||
552 | if (ENABLE_FEATURE_SEAMLESS_LZMA | 553 | if (ENABLE_FEATURE_SEAMLESS_LZMA |
553 | && (str = rpm_getstr0(TAG_PAYLOADCOMPRESSOR)) != NULL | 554 | && (str = rpm_getstr0(TAG_PAYLOADCOMPRESSOR)) != NULL |
554 | && strcmp(str, "lzma") == 0 | 555 | && strcmp(str, "lzma") == 0 |
@@ -557,7 +558,11 @@ int rpm2cpio_main(int argc UNUSED_PARAM, char **argv) | |||
557 | // set up decompressor without detection | 558 | // set up decompressor without detection |
558 | setup_lzma_on_fd(rpm_fd); | 559 | setup_lzma_on_fd(rpm_fd); |
559 | } else { | 560 | } else { |
560 | setup_unzip_on_fd(rpm_fd, /*fail_if_not_compressed:*/ 1); | 561 | int signature_bytes = setup_unzip_on_fd(rpm_fd, /*die_if_not_compressed:*/ 0); |
562 | if (signature_bytes != 0) { | ||
563 | xlseek(rpm_fd, - signature_bytes, SEEK_CUR); | ||
564 | bb_error_msg("warning, unknown compression '%s'", str); | ||
565 | } | ||
561 | } | 566 | } |
562 | 567 | ||
563 | if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0) | 568 | if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0) |
diff --git a/archival/tar.c b/archival/tar.c index 23ea02b5d..fd20d6ce7 100644 --- a/archival/tar.c +++ b/archival/tar.c | |||
@@ -1188,7 +1188,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv) | |||
1188 | * on e.g. tarball with 1st file named "BZh5". | 1188 | * on e.g. tarball with 1st file named "BZh5". |
1189 | */ | 1189 | */ |
1190 | ) { | 1190 | ) { |
1191 | tar_handle->src_fd = open_zipped(tar_filename, /*fail_if_not_compressed:*/ 0); | 1191 | tar_handle->src_fd = open_zipped(tar_filename, /*die_if_not_compressed:*/ 0); |
1192 | if (tar_handle->src_fd < 0) | 1192 | if (tar_handle->src_fd < 0) |
1193 | bb_perror_msg_and_die("can't open '%s'", tar_filename); | 1193 | bb_perror_msg_and_die("can't open '%s'", tar_filename); |
1194 | } else { | 1194 | } else { |
diff --git a/configs/mingw32_defconfig b/configs/mingw32_defconfig index 6f6bdb14b..6e8f1d5e4 100644 --- a/configs/mingw32_defconfig +++ b/configs/mingw32_defconfig | |||
@@ -1,7 +1,7 @@ | |||
1 | # | 1 | # |
2 | # Automatically generated make config: don't edit | 2 | # Automatically generated make config: don't edit |
3 | # Busybox version: 1.37.0.git | 3 | # Busybox version: 1.38.0.git |
4 | # Fri Jun 14 12:24:50 2024 | 4 | # Fri Aug 8 08:27:35 2025 |
5 | # | 5 | # |
6 | CONFIG_HAVE_DOT_CONFIG=y | 6 | CONFIG_HAVE_DOT_CONFIG=y |
7 | # CONFIG_PLATFORM_POSIX is not set | 7 | # CONFIG_PLATFORM_POSIX is not set |
@@ -62,6 +62,7 @@ CONFIG_TERMINAL_MODE=5 | |||
62 | CONFIG_FEATURE_IMPROVED_COLOUR_MAPPING=y | 62 | CONFIG_FEATURE_IMPROVED_COLOUR_MAPPING=y |
63 | CONFIG_FEATURE_EXTRA_FILE_DATA=y | 63 | CONFIG_FEATURE_EXTRA_FILE_DATA=y |
64 | CONFIG_OVERRIDE_APPLETS="" | 64 | CONFIG_OVERRIDE_APPLETS="" |
65 | CONFIG_UNWIND_TABLES=y | ||
65 | 66 | ||
66 | # | 67 | # |
67 | # Build Options | 68 | # Build Options |
@@ -120,6 +121,7 @@ CONFIG_FEATURE_BUFFERS_USE_MALLOC=y | |||
120 | # CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set | 121 | # CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set |
121 | # CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set | 122 | # CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set |
122 | CONFIG_PASSWORD_MINLEN=6 | 123 | CONFIG_PASSWORD_MINLEN=6 |
124 | # CONFIG_FEATURE_USE_CNG_API is not set | ||
123 | CONFIG_MD5_SMALL=1 | 125 | CONFIG_MD5_SMALL=1 |
124 | CONFIG_SHA1_SMALL=3 | 126 | CONFIG_SHA1_SMALL=3 |
125 | # CONFIG_SHA1_HWACCEL is not set | 127 | # CONFIG_SHA1_HWACCEL is not set |
@@ -225,6 +227,7 @@ CONFIG_FEATURE_UNZIP_BZIP2=y | |||
225 | CONFIG_FEATURE_UNZIP_LZMA=y | 227 | CONFIG_FEATURE_UNZIP_LZMA=y |
226 | CONFIG_FEATURE_UNZIP_XZ=y | 228 | CONFIG_FEATURE_UNZIP_XZ=y |
227 | CONFIG_FEATURE_LZMA_FAST=y | 229 | CONFIG_FEATURE_LZMA_FAST=y |
230 | # CONFIG_FEATURE_PATH_TRAVERSAL_PROTECTION is not set | ||
228 | 231 | ||
229 | # | 232 | # |
230 | # Coreutils | 233 | # Coreutils |
@@ -272,7 +275,7 @@ CONFIG_DD=y | |||
272 | CONFIG_FEATURE_DD_IBS_OBS=y | 275 | CONFIG_FEATURE_DD_IBS_OBS=y |
273 | CONFIG_FEATURE_DD_STATUS=y | 276 | CONFIG_FEATURE_DD_STATUS=y |
274 | CONFIG_DF=y | 277 | CONFIG_DF=y |
275 | # CONFIG_FEATURE_DF_FANCY is not set | 278 | CONFIG_FEATURE_DF_FANCY=y |
276 | # CONFIG_FEATURE_SKIP_ROOTFS is not set | 279 | # CONFIG_FEATURE_SKIP_ROOTFS is not set |
277 | CONFIG_DIRNAME=y | 280 | CONFIG_DIRNAME=y |
278 | CONFIG_DOS2UNIX=y | 281 | CONFIG_DOS2UNIX=y |
@@ -351,7 +354,7 @@ CONFIG_FEATURE_SPLIT_FANCY=y | |||
351 | CONFIG_STAT=y | 354 | CONFIG_STAT=y |
352 | CONFIG_FEATURE_STAT_FORMAT=y | 355 | CONFIG_FEATURE_STAT_FORMAT=y |
353 | CONFIG_FEATURE_STAT_FILESYSTEM=y | 356 | CONFIG_FEATURE_STAT_FILESYSTEM=y |
354 | # CONFIG_STTY is not set | 357 | CONFIG_STTY=y |
355 | CONFIG_SUM=y | 358 | CONFIG_SUM=y |
356 | CONFIG_SYNC=y | 359 | CONFIG_SYNC=y |
357 | # CONFIG_FEATURE_SYNC_FANCY is not set | 360 | # CONFIG_FEATURE_SYNC_FANCY is not set |
@@ -898,7 +901,10 @@ CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y | |||
898 | # CONFIG_FEATURE_ETC_NETWORKS is not set | 901 | # CONFIG_FEATURE_ETC_NETWORKS is not set |
899 | # CONFIG_FEATURE_ETC_SERVICES is not set | 902 | # CONFIG_FEATURE_ETC_SERVICES is not set |
900 | # CONFIG_FEATURE_HWIB is not set | 903 | # CONFIG_FEATURE_HWIB is not set |
904 | CONFIG_FEATURE_TLS_INTERNAL=y | ||
905 | # CONFIG_FEATURE_TLS_SCHANNEL is not set | ||
901 | # CONFIG_FEATURE_TLS_SHA1 is not set | 906 | # CONFIG_FEATURE_TLS_SHA1 is not set |
907 | # CONFIG_FEATURE_TLS_SCHANNEL_1_3 is not set | ||
902 | # CONFIG_ARP is not set | 908 | # CONFIG_ARP is not set |
903 | # CONFIG_ARPING is not set | 909 | # CONFIG_ARPING is not set |
904 | # CONFIG_BRCTL is not set | 910 | # CONFIG_BRCTL is not set |
@@ -964,6 +970,7 @@ CONFIG_IFUPDOWN_IFSTATE_PATH="" | |||
964 | # CONFIG_IPNEIGH is not set | 970 | # CONFIG_IPNEIGH is not set |
965 | # CONFIG_FEATURE_IP_ADDRESS is not set | 971 | # CONFIG_FEATURE_IP_ADDRESS is not set |
966 | # CONFIG_FEATURE_IP_LINK is not set | 972 | # CONFIG_FEATURE_IP_LINK is not set |
973 | CONFIG_FEATURE_IP_LINK_CAN=y | ||
967 | # CONFIG_FEATURE_IP_ROUTE is not set | 974 | # CONFIG_FEATURE_IP_ROUTE is not set |
968 | CONFIG_FEATURE_IP_ROUTE_DIR="" | 975 | CONFIG_FEATURE_IP_ROUTE_DIR="" |
969 | # CONFIG_FEATURE_IP_TUNNEL is not set | 976 | # CONFIG_FEATURE_IP_TUNNEL is not set |
diff --git a/configs/mingw64_defconfig b/configs/mingw64_defconfig index fbd2bc6e3..3a5d1248a 100644 --- a/configs/mingw64_defconfig +++ b/configs/mingw64_defconfig | |||
@@ -1,7 +1,7 @@ | |||
1 | # | 1 | # |
2 | # Automatically generated make config: don't edit | 2 | # Automatically generated make config: don't edit |
3 | # Busybox version: 1.37.0.git | 3 | # Busybox version: 1.38.0.git |
4 | # Fri Jun 14 12:24:50 2024 | 4 | # Fri Aug 8 08:27:35 2025 |
5 | # | 5 | # |
6 | CONFIG_HAVE_DOT_CONFIG=y | 6 | CONFIG_HAVE_DOT_CONFIG=y |
7 | # CONFIG_PLATFORM_POSIX is not set | 7 | # CONFIG_PLATFORM_POSIX is not set |
@@ -62,6 +62,7 @@ CONFIG_TERMINAL_MODE=5 | |||
62 | CONFIG_FEATURE_IMPROVED_COLOUR_MAPPING=y | 62 | CONFIG_FEATURE_IMPROVED_COLOUR_MAPPING=y |
63 | CONFIG_FEATURE_EXTRA_FILE_DATA=y | 63 | CONFIG_FEATURE_EXTRA_FILE_DATA=y |
64 | CONFIG_OVERRIDE_APPLETS="" | 64 | CONFIG_OVERRIDE_APPLETS="" |
65 | CONFIG_UNWIND_TABLES=y | ||
65 | 66 | ||
66 | # | 67 | # |
67 | # Build Options | 68 | # Build Options |
@@ -120,6 +121,7 @@ CONFIG_FEATURE_BUFFERS_USE_MALLOC=y | |||
120 | # CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set | 121 | # CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set |
121 | # CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set | 122 | # CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set |
122 | CONFIG_PASSWORD_MINLEN=6 | 123 | CONFIG_PASSWORD_MINLEN=6 |
124 | # CONFIG_FEATURE_USE_CNG_API is not set | ||
123 | CONFIG_MD5_SMALL=1 | 125 | CONFIG_MD5_SMALL=1 |
124 | CONFIG_SHA1_SMALL=3 | 126 | CONFIG_SHA1_SMALL=3 |
125 | # CONFIG_SHA1_HWACCEL is not set | 127 | # CONFIG_SHA1_HWACCEL is not set |
@@ -225,6 +227,7 @@ CONFIG_FEATURE_UNZIP_BZIP2=y | |||
225 | CONFIG_FEATURE_UNZIP_LZMA=y | 227 | CONFIG_FEATURE_UNZIP_LZMA=y |
226 | CONFIG_FEATURE_UNZIP_XZ=y | 228 | CONFIG_FEATURE_UNZIP_XZ=y |
227 | CONFIG_FEATURE_LZMA_FAST=y | 229 | CONFIG_FEATURE_LZMA_FAST=y |
230 | # CONFIG_FEATURE_PATH_TRAVERSAL_PROTECTION is not set | ||
228 | 231 | ||
229 | # | 232 | # |
230 | # Coreutils | 233 | # Coreutils |
@@ -272,7 +275,7 @@ CONFIG_DD=y | |||
272 | CONFIG_FEATURE_DD_IBS_OBS=y | 275 | CONFIG_FEATURE_DD_IBS_OBS=y |
273 | CONFIG_FEATURE_DD_STATUS=y | 276 | CONFIG_FEATURE_DD_STATUS=y |
274 | CONFIG_DF=y | 277 | CONFIG_DF=y |
275 | # CONFIG_FEATURE_DF_FANCY is not set | 278 | CONFIG_FEATURE_DF_FANCY=y |
276 | # CONFIG_FEATURE_SKIP_ROOTFS is not set | 279 | # CONFIG_FEATURE_SKIP_ROOTFS is not set |
277 | CONFIG_DIRNAME=y | 280 | CONFIG_DIRNAME=y |
278 | CONFIG_DOS2UNIX=y | 281 | CONFIG_DOS2UNIX=y |
@@ -351,7 +354,7 @@ CONFIG_FEATURE_SPLIT_FANCY=y | |||
351 | CONFIG_STAT=y | 354 | CONFIG_STAT=y |
352 | CONFIG_FEATURE_STAT_FORMAT=y | 355 | CONFIG_FEATURE_STAT_FORMAT=y |
353 | CONFIG_FEATURE_STAT_FILESYSTEM=y | 356 | CONFIG_FEATURE_STAT_FILESYSTEM=y |
354 | # CONFIG_STTY is not set | 357 | CONFIG_STTY=y |
355 | CONFIG_SUM=y | 358 | CONFIG_SUM=y |
356 | CONFIG_SYNC=y | 359 | CONFIG_SYNC=y |
357 | # CONFIG_FEATURE_SYNC_FANCY is not set | 360 | # CONFIG_FEATURE_SYNC_FANCY is not set |
@@ -898,7 +901,10 @@ CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y | |||
898 | # CONFIG_FEATURE_ETC_NETWORKS is not set | 901 | # CONFIG_FEATURE_ETC_NETWORKS is not set |
899 | # CONFIG_FEATURE_ETC_SERVICES is not set | 902 | # CONFIG_FEATURE_ETC_SERVICES is not set |
900 | # CONFIG_FEATURE_HWIB is not set | 903 | # CONFIG_FEATURE_HWIB is not set |
904 | CONFIG_FEATURE_TLS_INTERNAL=y | ||
905 | # CONFIG_FEATURE_TLS_SCHANNEL is not set | ||
901 | # CONFIG_FEATURE_TLS_SHA1 is not set | 906 | # CONFIG_FEATURE_TLS_SHA1 is not set |
907 | # CONFIG_FEATURE_TLS_SCHANNEL_1_3 is not set | ||
902 | # CONFIG_ARP is not set | 908 | # CONFIG_ARP is not set |
903 | # CONFIG_ARPING is not set | 909 | # CONFIG_ARPING is not set |
904 | # CONFIG_BRCTL is not set | 910 | # CONFIG_BRCTL is not set |
@@ -964,6 +970,7 @@ CONFIG_IFUPDOWN_IFSTATE_PATH="" | |||
964 | # CONFIG_IPNEIGH is not set | 970 | # CONFIG_IPNEIGH is not set |
965 | # CONFIG_FEATURE_IP_ADDRESS is not set | 971 | # CONFIG_FEATURE_IP_ADDRESS is not set |
966 | # CONFIG_FEATURE_IP_LINK is not set | 972 | # CONFIG_FEATURE_IP_LINK is not set |
973 | CONFIG_FEATURE_IP_LINK_CAN=y | ||
967 | # CONFIG_FEATURE_IP_ROUTE is not set | 974 | # CONFIG_FEATURE_IP_ROUTE is not set |
968 | CONFIG_FEATURE_IP_ROUTE_DIR="" | 975 | CONFIG_FEATURE_IP_ROUTE_DIR="" |
969 | # CONFIG_FEATURE_IP_TUNNEL is not set | 976 | # CONFIG_FEATURE_IP_TUNNEL is not set |
diff --git a/configs/mingw64a_defconfig b/configs/mingw64a_defconfig index e9a88bf62..d17737721 100644 --- a/configs/mingw64a_defconfig +++ b/configs/mingw64a_defconfig | |||
@@ -1,7 +1,7 @@ | |||
1 | # | 1 | # |
2 | # Automatically generated make config: don't edit | 2 | # Automatically generated make config: don't edit |
3 | # Busybox version: 1.37.0.git | 3 | # Busybox version: 1.38.0.git |
4 | # Fri Jun 14 12:24:50 2024 | 4 | # Fri Aug 8 08:27:35 2025 |
5 | # | 5 | # |
6 | CONFIG_HAVE_DOT_CONFIG=y | 6 | CONFIG_HAVE_DOT_CONFIG=y |
7 | # CONFIG_PLATFORM_POSIX is not set | 7 | # CONFIG_PLATFORM_POSIX is not set |
@@ -62,6 +62,7 @@ CONFIG_TERMINAL_MODE=5 | |||
62 | CONFIG_FEATURE_IMPROVED_COLOUR_MAPPING=y | 62 | CONFIG_FEATURE_IMPROVED_COLOUR_MAPPING=y |
63 | CONFIG_FEATURE_EXTRA_FILE_DATA=y | 63 | CONFIG_FEATURE_EXTRA_FILE_DATA=y |
64 | CONFIG_OVERRIDE_APPLETS="" | 64 | CONFIG_OVERRIDE_APPLETS="" |
65 | CONFIG_UNWIND_TABLES=y | ||
65 | 66 | ||
66 | # | 67 | # |
67 | # Build Options | 68 | # Build Options |
@@ -120,6 +121,7 @@ CONFIG_FEATURE_BUFFERS_USE_MALLOC=y | |||
120 | # CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set | 121 | # CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set |
121 | # CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set | 122 | # CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set |
122 | CONFIG_PASSWORD_MINLEN=6 | 123 | CONFIG_PASSWORD_MINLEN=6 |
124 | CONFIG_FEATURE_USE_CNG_API=y | ||
123 | CONFIG_MD5_SMALL=1 | 125 | CONFIG_MD5_SMALL=1 |
124 | CONFIG_SHA1_SMALL=3 | 126 | CONFIG_SHA1_SMALL=3 |
125 | # CONFIG_SHA1_HWACCEL is not set | 127 | # CONFIG_SHA1_HWACCEL is not set |
@@ -225,6 +227,7 @@ CONFIG_FEATURE_UNZIP_BZIP2=y | |||
225 | CONFIG_FEATURE_UNZIP_LZMA=y | 227 | CONFIG_FEATURE_UNZIP_LZMA=y |
226 | CONFIG_FEATURE_UNZIP_XZ=y | 228 | CONFIG_FEATURE_UNZIP_XZ=y |
227 | CONFIG_FEATURE_LZMA_FAST=y | 229 | CONFIG_FEATURE_LZMA_FAST=y |
230 | # CONFIG_FEATURE_PATH_TRAVERSAL_PROTECTION is not set | ||
228 | 231 | ||
229 | # | 232 | # |
230 | # Coreutils | 233 | # Coreutils |
@@ -272,7 +275,7 @@ CONFIG_DD=y | |||
272 | CONFIG_FEATURE_DD_IBS_OBS=y | 275 | CONFIG_FEATURE_DD_IBS_OBS=y |
273 | CONFIG_FEATURE_DD_STATUS=y | 276 | CONFIG_FEATURE_DD_STATUS=y |
274 | CONFIG_DF=y | 277 | CONFIG_DF=y |
275 | # CONFIG_FEATURE_DF_FANCY is not set | 278 | CONFIG_FEATURE_DF_FANCY=y |
276 | # CONFIG_FEATURE_SKIP_ROOTFS is not set | 279 | # CONFIG_FEATURE_SKIP_ROOTFS is not set |
277 | CONFIG_DIRNAME=y | 280 | CONFIG_DIRNAME=y |
278 | CONFIG_DOS2UNIX=y | 281 | CONFIG_DOS2UNIX=y |
@@ -351,7 +354,7 @@ CONFIG_FEATURE_SPLIT_FANCY=y | |||
351 | CONFIG_STAT=y | 354 | CONFIG_STAT=y |
352 | CONFIG_FEATURE_STAT_FORMAT=y | 355 | CONFIG_FEATURE_STAT_FORMAT=y |
353 | CONFIG_FEATURE_STAT_FILESYSTEM=y | 356 | CONFIG_FEATURE_STAT_FILESYSTEM=y |
354 | # CONFIG_STTY is not set | 357 | CONFIG_STTY=y |
355 | CONFIG_SUM=y | 358 | CONFIG_SUM=y |
356 | CONFIG_SYNC=y | 359 | CONFIG_SYNC=y |
357 | # CONFIG_FEATURE_SYNC_FANCY is not set | 360 | # CONFIG_FEATURE_SYNC_FANCY is not set |
@@ -898,7 +901,10 @@ CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y | |||
898 | # CONFIG_FEATURE_ETC_NETWORKS is not set | 901 | # CONFIG_FEATURE_ETC_NETWORKS is not set |
899 | # CONFIG_FEATURE_ETC_SERVICES is not set | 902 | # CONFIG_FEATURE_ETC_SERVICES is not set |
900 | # CONFIG_FEATURE_HWIB is not set | 903 | # CONFIG_FEATURE_HWIB is not set |
904 | # CONFIG_FEATURE_TLS_INTERNAL is not set | ||
905 | CONFIG_FEATURE_TLS_SCHANNEL=y | ||
901 | # CONFIG_FEATURE_TLS_SHA1 is not set | 906 | # CONFIG_FEATURE_TLS_SHA1 is not set |
907 | # CONFIG_FEATURE_TLS_SCHANNEL_1_3 is not set | ||
902 | # CONFIG_ARP is not set | 908 | # CONFIG_ARP is not set |
903 | # CONFIG_ARPING is not set | 909 | # CONFIG_ARPING is not set |
904 | # CONFIG_BRCTL is not set | 910 | # CONFIG_BRCTL is not set |
@@ -964,6 +970,7 @@ CONFIG_IFUPDOWN_IFSTATE_PATH="" | |||
964 | # CONFIG_IPNEIGH is not set | 970 | # CONFIG_IPNEIGH is not set |
965 | # CONFIG_FEATURE_IP_ADDRESS is not set | 971 | # CONFIG_FEATURE_IP_ADDRESS is not set |
966 | # CONFIG_FEATURE_IP_LINK is not set | 972 | # CONFIG_FEATURE_IP_LINK is not set |
973 | CONFIG_FEATURE_IP_LINK_CAN=y | ||
967 | # CONFIG_FEATURE_IP_ROUTE is not set | 974 | # CONFIG_FEATURE_IP_ROUTE is not set |
968 | CONFIG_FEATURE_IP_ROUTE_DIR="" | 975 | CONFIG_FEATURE_IP_ROUTE_DIR="" |
969 | # CONFIG_FEATURE_IP_TUNNEL is not set | 976 | # CONFIG_FEATURE_IP_TUNNEL is not set |
diff --git a/configs/mingw64u_defconfig b/configs/mingw64u_defconfig index 61753699d..adb1552f2 100644 --- a/configs/mingw64u_defconfig +++ b/configs/mingw64u_defconfig | |||
@@ -1,7 +1,7 @@ | |||
1 | # | 1 | # |
2 | # Automatically generated make config: don't edit | 2 | # Automatically generated make config: don't edit |
3 | # Busybox version: 1.37.0.git | 3 | # Busybox version: 1.38.0.git |
4 | # Fri Jun 14 12:24:50 2024 | 4 | # Fri Aug 8 08:27:35 2025 |
5 | # | 5 | # |
6 | CONFIG_HAVE_DOT_CONFIG=y | 6 | CONFIG_HAVE_DOT_CONFIG=y |
7 | # CONFIG_PLATFORM_POSIX is not set | 7 | # CONFIG_PLATFORM_POSIX is not set |
@@ -62,6 +62,7 @@ CONFIG_TERMINAL_MODE=5 | |||
62 | CONFIG_FEATURE_IMPROVED_COLOUR_MAPPING=y | 62 | CONFIG_FEATURE_IMPROVED_COLOUR_MAPPING=y |
63 | CONFIG_FEATURE_EXTRA_FILE_DATA=y | 63 | CONFIG_FEATURE_EXTRA_FILE_DATA=y |
64 | CONFIG_OVERRIDE_APPLETS="" | 64 | CONFIG_OVERRIDE_APPLETS="" |
65 | CONFIG_UNWIND_TABLES=y | ||
65 | 66 | ||
66 | # | 67 | # |
67 | # Build Options | 68 | # Build Options |
@@ -120,6 +121,7 @@ CONFIG_FEATURE_BUFFERS_USE_MALLOC=y | |||
120 | # CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set | 121 | # CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set |
121 | # CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set | 122 | # CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set |
122 | CONFIG_PASSWORD_MINLEN=6 | 123 | CONFIG_PASSWORD_MINLEN=6 |
124 | CONFIG_FEATURE_USE_CNG_API=y | ||
123 | CONFIG_MD5_SMALL=1 | 125 | CONFIG_MD5_SMALL=1 |
124 | CONFIG_SHA1_SMALL=3 | 126 | CONFIG_SHA1_SMALL=3 |
125 | # CONFIG_SHA1_HWACCEL is not set | 127 | # CONFIG_SHA1_HWACCEL is not set |
@@ -225,6 +227,7 @@ CONFIG_FEATURE_UNZIP_BZIP2=y | |||
225 | CONFIG_FEATURE_UNZIP_LZMA=y | 227 | CONFIG_FEATURE_UNZIP_LZMA=y |
226 | CONFIG_FEATURE_UNZIP_XZ=y | 228 | CONFIG_FEATURE_UNZIP_XZ=y |
227 | CONFIG_FEATURE_LZMA_FAST=y | 229 | CONFIG_FEATURE_LZMA_FAST=y |
230 | # CONFIG_FEATURE_PATH_TRAVERSAL_PROTECTION is not set | ||
228 | 231 | ||
229 | # | 232 | # |
230 | # Coreutils | 233 | # Coreutils |
@@ -272,7 +275,7 @@ CONFIG_DD=y | |||
272 | CONFIG_FEATURE_DD_IBS_OBS=y | 275 | CONFIG_FEATURE_DD_IBS_OBS=y |
273 | CONFIG_FEATURE_DD_STATUS=y | 276 | CONFIG_FEATURE_DD_STATUS=y |
274 | CONFIG_DF=y | 277 | CONFIG_DF=y |
275 | # CONFIG_FEATURE_DF_FANCY is not set | 278 | CONFIG_FEATURE_DF_FANCY=y |
276 | # CONFIG_FEATURE_SKIP_ROOTFS is not set | 279 | # CONFIG_FEATURE_SKIP_ROOTFS is not set |
277 | CONFIG_DIRNAME=y | 280 | CONFIG_DIRNAME=y |
278 | CONFIG_DOS2UNIX=y | 281 | CONFIG_DOS2UNIX=y |
@@ -351,7 +354,7 @@ CONFIG_FEATURE_SPLIT_FANCY=y | |||
351 | CONFIG_STAT=y | 354 | CONFIG_STAT=y |
352 | CONFIG_FEATURE_STAT_FORMAT=y | 355 | CONFIG_FEATURE_STAT_FORMAT=y |
353 | CONFIG_FEATURE_STAT_FILESYSTEM=y | 356 | CONFIG_FEATURE_STAT_FILESYSTEM=y |
354 | # CONFIG_STTY is not set | 357 | CONFIG_STTY=y |
355 | CONFIG_SUM=y | 358 | CONFIG_SUM=y |
356 | CONFIG_SYNC=y | 359 | CONFIG_SYNC=y |
357 | # CONFIG_FEATURE_SYNC_FANCY is not set | 360 | # CONFIG_FEATURE_SYNC_FANCY is not set |
@@ -898,7 +901,10 @@ CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y | |||
898 | # CONFIG_FEATURE_ETC_NETWORKS is not set | 901 | # CONFIG_FEATURE_ETC_NETWORKS is not set |
899 | # CONFIG_FEATURE_ETC_SERVICES is not set | 902 | # CONFIG_FEATURE_ETC_SERVICES is not set |
900 | # CONFIG_FEATURE_HWIB is not set | 903 | # CONFIG_FEATURE_HWIB is not set |
904 | # CONFIG_FEATURE_TLS_INTERNAL is not set | ||
905 | CONFIG_FEATURE_TLS_SCHANNEL=y | ||
901 | # CONFIG_FEATURE_TLS_SHA1 is not set | 906 | # CONFIG_FEATURE_TLS_SHA1 is not set |
907 | # CONFIG_FEATURE_TLS_SCHANNEL_1_3 is not set | ||
902 | # CONFIG_ARP is not set | 908 | # CONFIG_ARP is not set |
903 | # CONFIG_ARPING is not set | 909 | # CONFIG_ARPING is not set |
904 | # CONFIG_BRCTL is not set | 910 | # CONFIG_BRCTL is not set |
@@ -964,6 +970,7 @@ CONFIG_IFUPDOWN_IFSTATE_PATH="" | |||
964 | # CONFIG_IPNEIGH is not set | 970 | # CONFIG_IPNEIGH is not set |
965 | # CONFIG_FEATURE_IP_ADDRESS is not set | 971 | # CONFIG_FEATURE_IP_ADDRESS is not set |
966 | # CONFIG_FEATURE_IP_LINK is not set | 972 | # CONFIG_FEATURE_IP_LINK is not set |
973 | CONFIG_FEATURE_IP_LINK_CAN=y | ||
967 | # CONFIG_FEATURE_IP_ROUTE is not set | 974 | # CONFIG_FEATURE_IP_ROUTE is not set |
968 | CONFIG_FEATURE_IP_ROUTE_DIR="" | 975 | CONFIG_FEATURE_IP_ROUTE_DIR="" |
969 | # CONFIG_FEATURE_IP_TUNNEL is not set | 976 | # CONFIG_FEATURE_IP_TUNNEL is not set |
diff --git a/coreutils/cut.c b/coreutils/cut.c index f7b501a46..d81f36bcd 100644 --- a/coreutils/cut.c +++ b/coreutils/cut.c | |||
@@ -27,21 +27,34 @@ | |||
27 | //kbuild:lib-$(CONFIG_CUT) += cut.o | 27 | //kbuild:lib-$(CONFIG_CUT) += cut.o |
28 | 28 | ||
29 | //usage:#define cut_trivial_usage | 29 | //usage:#define cut_trivial_usage |
30 | //usage: "[OPTIONS] [FILE]..." | 30 | //usage: "{-b|c LIST | -f"IF_FEATURE_CUT_REGEX("|F")" LIST [-d SEP] [-s]} [-D] [-O SEP] [FILE]..." |
31 | // --output-delimiter SEP is too long to fit into 80 char-wide help ----------------^^^^^^^^ | ||
31 | //usage:#define cut_full_usage "\n\n" | 32 | //usage:#define cut_full_usage "\n\n" |
32 | //usage: "Print selected fields from FILEs to stdout\n" | 33 | //usage: "Print selected fields from FILEs to stdout\n" |
33 | //usage: "\n -b LIST Output only bytes from LIST" | 34 | //usage: "\n -b LIST Output only bytes from LIST" |
34 | //usage: "\n -c LIST Output only characters from LIST" | 35 | //usage: "\n -c LIST Output only characters from LIST" |
35 | //usage: "\n -d SEP Field delimiter for input (default -f TAB, -F run of whitespace)" | 36 | //usage: IF_FEATURE_CUT_REGEX( |
36 | //usage: "\n -O SEP Field delimeter for output (default = -d for -f, one space for -F)" | 37 | //usage: "\n -d SEP Input field delimiter (default -f TAB, -F run of whitespace)" |
37 | //usage: "\n -D Don't sort/collate sections or match -fF lines without delimeter" | 38 | //usage: ) IF_NOT_FEATURE_CUT_REGEX( |
39 | //usage: "\n -d SEP Input field delimiter (default TAB)" | ||
40 | //usage: ) | ||
38 | //usage: "\n -f LIST Print only these fields (-d is single char)" | 41 | //usage: "\n -f LIST Print only these fields (-d is single char)" |
39 | //usage: IF_FEATURE_CUT_REGEX( | 42 | //usage: IF_FEATURE_CUT_REGEX( |
40 | //usage: "\n -F LIST Print only these fields (-d is regex)" | 43 | //usage: "\n -F LIST Print only these fields (-d is regex)" |
41 | //usage: ) | 44 | //usage: ) |
42 | //usage: "\n -s Output only lines containing delimiter" | 45 | //usage: "\n -s Drop lines with no delimiter (else print them in full)" |
46 | //usage: "\n -D Don't sort ranges; line without delimiters has one field" | ||
47 | //usage: IF_LONG_OPTS( | ||
48 | //usage: "\n --output-delimiter SEP Output field delimeter" | ||
49 | //usage: ) IF_NOT_LONG_OPTS( | ||
50 | //usage: IF_FEATURE_CUT_REGEX( | ||
51 | //usage: "\n -O SEP Output field delimeter (default = -d for -f, one space for -F)" | ||
52 | //usage: ) IF_NOT_FEATURE_CUT_REGEX( | ||
53 | //usage: "\n -O SEP Output field delimeter (default = -d)" | ||
54 | //usage: ) | ||
55 | //usage: ) | ||
43 | //usage: "\n -n Ignored" | 56 | //usage: "\n -n Ignored" |
44 | //(manpage:-n with -b: don't split multibyte characters) | 57 | //(manpage:-n with -b: don't split multibyte characters) |
45 | //usage: | 58 | //usage: |
46 | //usage:#define cut_example_usage | 59 | //usage:#define cut_example_usage |
47 | //usage: "$ echo \"Hello world\" | cut -f 1 -d ' '\n" | 60 | //usage: "$ echo \"Hello world\" | cut -f 1 -d ' '\n" |
@@ -53,11 +66,6 @@ | |||
53 | 66 | ||
54 | #if ENABLE_FEATURE_CUT_REGEX | 67 | #if ENABLE_FEATURE_CUT_REGEX |
55 | #include "xregex.h" | 68 | #include "xregex.h" |
56 | #else | ||
57 | #define regex_t int | ||
58 | typedef struct { int rm_eo, rm_so; } regmatch_t; | ||
59 | #define xregcomp(x, ...) *(x) = 0 | ||
60 | #define regexec(...) 0 | ||
61 | #endif | 69 | #endif |
62 | 70 | ||
63 | /* This is a NOEXEC applet. Be very careful! */ | 71 | /* This is a NOEXEC applet. Be very careful! */ |
@@ -65,265 +73,346 @@ typedef struct { int rm_eo, rm_so; } regmatch_t; | |||
65 | 73 | ||
66 | /* option vars */ | 74 | /* option vars */ |
67 | #define OPT_STR "b:c:f:d:O:sD"IF_FEATURE_CUT_REGEX("F:")"n" | 75 | #define OPT_STR "b:c:f:d:O:sD"IF_FEATURE_CUT_REGEX("F:")"n" |
68 | #define CUT_OPT_BYTE_FLGS (1 << 0) | 76 | #define OPT_BYTE (1 << 0) |
69 | #define CUT_OPT_CHAR_FLGS (1 << 1) | 77 | #define OPT_CHAR (1 << 1) |
70 | #define CUT_OPT_FIELDS_FLGS (1 << 2) | 78 | #define OPT_FIELDS (1 << 2) |
71 | #define CUT_OPT_DELIM_FLGS (1 << 3) | 79 | #define OPT_DELIM (1 << 3) |
72 | #define CUT_OPT_ODELIM_FLGS (1 << 4) | 80 | #define OPT_ODELIM (1 << 4) |
73 | #define CUT_OPT_SUPPRESS_FLGS (1 << 5) | 81 | #define OPT_SUPPRESS (1 << 5) |
74 | #define CUT_OPT_NOSORT_FLGS (1 << 6) | 82 | #define OPT_NOSORT (1 << 6) |
75 | #define CUT_OPT_REGEX_FLGS ((1 << 7) * ENABLE_FEATURE_CUT_REGEX) | 83 | #define OPT_REGEX ((1 << 7) * ENABLE_FEATURE_CUT_REGEX) |
76 | 84 | ||
77 | struct cut_list { | 85 | #define opt_REGEX (option_mask32 & OPT_REGEX) |
78 | int startpos; | 86 | |
79 | int endpos; | 87 | struct cut_range { |
88 | unsigned startpos; | ||
89 | unsigned endpos; | ||
80 | }; | 90 | }; |
81 | 91 | ||
82 | static int cmpfunc(const void *a, const void *b) | 92 | static int cmpfunc(const void *a, const void *b) |
83 | { | 93 | { |
84 | return (((struct cut_list *) a)->startpos - | 94 | const struct cut_range *aa = a; |
85 | ((struct cut_list *) b)->startpos); | 95 | const struct cut_range *bb = b; |
96 | return aa->startpos - bb->startpos; | ||
86 | } | 97 | } |
87 | 98 | ||
99 | #define END_OF_LIST(list_elem) ((list_elem).startpos == UINT_MAX) | ||
100 | #define NOT_END_OF_LIST(list_elem) ((list_elem).startpos != UINT_MAX) | ||
101 | |||
88 | static void cut_file(FILE *file, const char *delim, const char *odelim, | 102 | static void cut_file(FILE *file, const char *delim, const char *odelim, |
89 | const struct cut_list *cut_lists, unsigned nlists) | 103 | const struct cut_range *cut_list) |
90 | { | 104 | { |
91 | char *line; | 105 | char *line; |
92 | unsigned linenum = 0; /* keep these zero-based to be consistent */ | 106 | unsigned linenum = 0; /* keep these zero-based to be consistent */ |
93 | regex_t reg; | 107 | int first_print = 1; |
94 | int spos, shoe = option_mask32 & CUT_OPT_REGEX_FLGS; | ||
95 | |||
96 | if (shoe) xregcomp(®, delim, REG_EXTENDED); | ||
97 | 108 | ||
98 | /* go through every line in the file */ | 109 | /* go through every line in the file */ |
99 | while ((line = xmalloc_fgetline(file)) != NULL) { | 110 | while ((line = xmalloc_fgetline(file)) != NULL) { |
100 | 111 | ||
101 | /* set up a list so we can keep track of what's been printed */ | 112 | /* set up a list so we can keep track of what's been printed */ |
102 | int linelen = strlen(line); | 113 | unsigned linelen = strlen(line); |
103 | char *printed = xzalloc(linelen + 1); | ||
104 | char *orig_line = line; | ||
105 | unsigned cl_pos = 0; | 114 | unsigned cl_pos = 0; |
106 | 115 | ||
107 | /* cut based on chars/bytes XXX: only works when sizeof(char) == byte */ | 116 | /* Cut based on chars/bytes XXX: only works when sizeof(char) == byte */ |
108 | if (option_mask32 & (CUT_OPT_CHAR_FLGS | CUT_OPT_BYTE_FLGS)) { | 117 | if (option_mask32 & (OPT_CHAR | OPT_BYTE)) { |
118 | char *printed = xzalloc(linelen + 1); | ||
119 | int need_odelim = 0; | ||
120 | |||
109 | /* print the chars specified in each cut list */ | 121 | /* print the chars specified in each cut list */ |
110 | for (; cl_pos < nlists; cl_pos++) { | 122 | for (; NOT_END_OF_LIST(cut_list[cl_pos]); cl_pos++) { |
111 | for (spos = cut_lists[cl_pos].startpos; spos < linelen;) { | 123 | unsigned spos = cut_list[cl_pos].startpos; |
124 | while (spos < linelen) { | ||
112 | if (!printed[spos]) { | 125 | if (!printed[spos]) { |
113 | printed[spos] = 'X'; | 126 | printed[spos] = 'X'; |
127 | if (need_odelim && spos != 0 && !printed[spos-1]) { | ||
128 | need_odelim = 0; | ||
129 | fputs_stdout(odelim); | ||
130 | } | ||
114 | putchar(line[spos]); | 131 | putchar(line[spos]); |
115 | } | 132 | } |
116 | if (++spos > cut_lists[cl_pos].endpos) { | 133 | spos++; |
134 | if (spos > cut_list[cl_pos].endpos) { | ||
135 | /* will print OSEP (if not empty) */ | ||
136 | need_odelim = (odelim && odelim[0]); | ||
117 | break; | 137 | break; |
118 | } | 138 | } |
119 | } | 139 | } |
120 | } | 140 | } |
121 | } else if (*delim == '\n') { /* cut by lines */ | 141 | free(printed); |
122 | spos = cut_lists[cl_pos].startpos; | 142 | /* Cut by lines */ |
143 | } else if (!opt_REGEX && *delim == '\n') { | ||
144 | unsigned spos = cut_list[cl_pos].startpos; | ||
123 | 145 | ||
124 | /* get out if we have no more lists to process or if the lines | 146 | linenum++; |
147 | /* get out if we have no more ranges to process or if the lines | ||
125 | * are lower than what we're interested in */ | 148 | * are lower than what we're interested in */ |
126 | if (((int)linenum < spos) || (cl_pos >= nlists)) | 149 | if (linenum <= spos || END_OF_LIST(cut_list[cl_pos])) |
127 | goto next_line; | 150 | goto next_line; |
128 | 151 | ||
129 | /* 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 |
130 | * passed, it means we displayed it already, so move on */ | 153 | * passed, it means we displayed it already, so move on */ |
131 | while (spos < (int)linenum) { | 154 | while (++spos < linenum) { |
132 | spos++; | ||
133 | /* 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 */ |
134 | if (spos > cut_lists[cl_pos].endpos) { | 156 | if (spos > cut_list[cl_pos].endpos) { |
135 | cl_pos++; | 157 | cl_pos++; |
136 | /* get out if there's no more lists to process */ | 158 | /* get out if there's no more ranges to process */ |
137 | if (cl_pos >= nlists) | 159 | if (END_OF_LIST(cut_list[cl_pos])) |
138 | goto next_line; | 160 | goto next_line; |
139 | spos = cut_lists[cl_pos].startpos; | 161 | spos = cut_list[cl_pos].startpos; |
140 | /* get out if the current line is lower than the one | 162 | /* get out if the current line is lower than the one |
141 | * we just became interested in */ | 163 | * we just became interested in */ |
142 | if ((int)linenum < spos) | 164 | if (linenum <= spos) |
143 | goto next_line; | 165 | goto next_line; |
144 | } | 166 | } |
145 | } | 167 | } |
146 | 168 | ||
147 | /* If we made it here, it means we've found the line we're | 169 | /* If we made it here, it means we've found the line we're |
148 | * looking for, so print it */ | 170 | * looking for, so print it */ |
149 | puts(line); | 171 | if (first_print) { |
172 | first_print = 0; | ||
173 | fputs_stdout(line); | ||
174 | } else | ||
175 | printf("%s%s", odelim, line); | ||
150 | goto next_line; | 176 | goto next_line; |
151 | } else { /* cut by fields */ | 177 | /* Cut by fields */ |
152 | unsigned uu = 0, start = 0, end = 0, out = 0; | 178 | } else { |
153 | int dcount = 0; | 179 | unsigned next = 0, start = 0, end = 0; |
180 | unsigned dcount = 0; /* we saw Nth delimiter (0 - didn't see any yet) */ | ||
181 | |||
182 | /* Blank line? Check -s (later check for -s does not catch empty lines) */ | ||
183 | if (linelen == 0) { | ||
184 | if (option_mask32 & OPT_SUPPRESS) | ||
185 | goto next_line; | ||
186 | } | ||
187 | |||
188 | if (!odelim) | ||
189 | odelim = "\t"; | ||
190 | first_print = 1; | ||
154 | 191 | ||
155 | #if ENABLE_PLATFORM_MINGW32 | ||
156 | /* An empty line can't contain a delimiter */ | ||
157 | if (linelen == 0 && (option_mask32 & CUT_OPT_SUPPRESS_FLGS)) | ||
158 | goto next_line; | ||
159 | #endif | ||
160 | /* Loop through bytes, finding next delimiter */ | 192 | /* Loop through bytes, finding next delimiter */ |
161 | for (;;) { | 193 | for (;;) { |
162 | /* End of current range? */ | 194 | /* End of current range? */ |
163 | if (end == linelen || dcount > cut_lists[cl_pos].endpos) { | 195 | if (end == linelen || dcount > cut_list[cl_pos].endpos) { |
164 | if (++cl_pos >= nlists) break; | 196 | end_of_range: |
165 | if (option_mask32 & CUT_OPT_NOSORT_FLGS) | 197 | cl_pos++; |
166 | start = dcount = uu = 0; | 198 | if (END_OF_LIST(cut_list[cl_pos])) |
167 | end = 0; | 199 | break; |
200 | if (option_mask32 & OPT_NOSORT) | ||
201 | start = dcount = next = 0; | ||
202 | end = 0; /* (why?) */ | ||
203 | //bb_error_msg("End of current range"); | ||
168 | } | 204 | } |
169 | /* End of current line? */ | 205 | /* End of current line? */ |
170 | if (uu == linelen) { | 206 | if (next == linelen) { |
171 | /* If we've seen no delimiters, check -s */ | 207 | end = linelen; /* print up to end */ |
172 | if (!cl_pos && !dcount && !shoe) { | 208 | /* If we've seen no delimiters, and no -D, check -s */ |
173 | if (option_mask32 & CUT_OPT_SUPPRESS_FLGS) | 209 | if (!(option_mask32 & OPT_NOSORT) && cl_pos == 0 && dcount == 0) { |
210 | if (option_mask32 & OPT_SUPPRESS) | ||
174 | goto next_line; | 211 | goto next_line; |
175 | } else if (dcount < cut_lists[cl_pos].startpos) | 212 | /* else: will print entire line */ |
176 | start = linelen; | 213 | } else if (dcount < cut_list[cl_pos].startpos) { |
177 | end = linelen; | 214 | /* echo 1.2 | cut -d. -f1,3: prints "1", not "1." */ |
215 | //break; | ||
216 | /* ^^^ this fails a case with -D: | ||
217 | * echo 1 2 | cut -DF 1,3,2: | ||
218 | * do not end line processing when didn't find field#3 | ||
219 | */ | ||
220 | //if (option_mask32 & OPT_NOSORT) - no, just do it always | ||
221 | goto end_of_range; | ||
222 | } | ||
223 | //bb_error_msg("End of current line: s:%d e:%d", start, end); | ||
178 | } else { | 224 | } else { |
179 | /* Find next delimiter */ | 225 | /* Find next delimiter */ |
180 | if (shoe) { | 226 | #if ENABLE_FEATURE_CUT_REGEX |
181 | regmatch_t rr = {-1, -1}; | 227 | if (opt_REGEX) { |
182 | 228 | regmatch_t rr; | |
183 | if (!regexec(®, line+uu, 1, &rr, REG_NOTBOL|REG_NOTEOL)) { | 229 | regex_t *reg = (void*) delim; |
184 | end = uu + rr.rm_so; | 230 | |
185 | uu += rr.rm_eo; | 231 | if (regexec(reg, line + next, 1, &rr, REG_NOTBOL|REG_NOTEOL) != 0) { |
186 | } else { | 232 | /* not found, go to "end of line" logic */ |
187 | uu = linelen; | 233 | next = linelen; |
188 | continue; | 234 | continue; |
189 | } | 235 | } |
190 | } else if (line[end = uu++] != *delim) | 236 | end = next + rr.rm_so; |
191 | continue; | 237 | next += (rr.rm_eo ? rr.rm_eo : 1); |
192 | 238 | /* ^^^ advancing by at least 1 prevents infinite loops */ | |
193 | /* Got delimiter. Loop if not yet within range. */ | 239 | /* testcase: echo "no at sign" | cut -d'@*' -F 1- */ |
194 | if (dcount++ < cut_lists[cl_pos].startpos) { | 240 | } else |
195 | start = uu; | 241 | #endif |
242 | { | ||
243 | end = next++; | ||
244 | if (line[end] != *delim) | ||
245 | continue; | ||
246 | } | ||
247 | /* Got delimiter */ | ||
248 | dcount++; | ||
249 | if (dcount <= cut_list[cl_pos].startpos) { | ||
250 | /* Not yet within range - loop */ | ||
251 | start = next; | ||
196 | continue; | 252 | continue; |
197 | } | 253 | } |
254 | /* -F N-M preserves intermediate delimiters: */ | ||
255 | //printf "1 2 3 4 5 6 7\n" | toybox cut -O: -F2,4-6,7 | ||
256 | //2:4 5 6:7 | ||
257 | if (opt_REGEX && dcount <= cut_list[cl_pos].endpos) | ||
258 | continue; | ||
259 | // NB: toybox does the above for -f too, but it's a compatibility bug: | ||
260 | //printf "1 2 3 4 5 6 7 8\n" | toybox cut -d' ' -O: -f2,4-6,7 | ||
261 | //2:4 5 6:7 // WRONG! | ||
262 | //printf "1 2 3 4 5 6 7 8\n" | cut -d' ' --output-delimiter=: -f2,4-6,7 | ||
263 | //2:4:5:6:7 // GNU coreutils 9.1 | ||
198 | } | 264 | } |
199 | if (end != start || !shoe) | 265 | #if ENABLE_FEATURE_CUT_REGEX |
200 | printf("%s%.*s", out++ ? odelim : "", end-start, line + start); | 266 | if (end != start || !opt_REGEX) |
201 | start = uu; | 267 | #endif |
202 | if (!dcount) | 268 | { |
203 | break; | 269 | if (first_print) { |
204 | } | 270 | first_print = 0; |
271 | printf("%.*s", end - start, line + start); | ||
272 | } else | ||
273 | printf("%s%.*s", odelim, end - start, line + start); | ||
274 | } | ||
275 | start = next; | ||
276 | //if (dcount == 0) | ||
277 | // break; - why? | ||
278 | } /* byte loop */ | ||
205 | } | 279 | } |
206 | /* if we printed anything, finish with newline */ | 280 | /* if we printed anything, finish with newline */ |
207 | putchar('\n'); | 281 | putchar('\n'); |
208 | next_line: | 282 | next_line: |
209 | linenum++; | 283 | free(line); |
210 | free(printed); | 284 | } /* while (got line) */ |
211 | free(orig_line); | 285 | |
212 | } | 286 | /* For -d$'\n' --output-delimiter=^, the overall output is still terminated with \n, not ^ */ |
287 | if (!opt_REGEX && *delim == '\n' && !first_print) | ||
288 | putchar('\n'); | ||
213 | } | 289 | } |
214 | 290 | ||
215 | int cut_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 291 | int cut_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
216 | int cut_main(int argc UNUSED_PARAM, char **argv) | 292 | int cut_main(int argc UNUSED_PARAM, char **argv) |
217 | { | 293 | { |
218 | /* growable array holding a series of lists */ | 294 | /* growable array holding a series of ranges */ |
219 | struct cut_list *cut_lists = NULL; | 295 | struct cut_range *cut_list = NULL; |
220 | unsigned nlists = 0; /* number of elements in above list */ | 296 | unsigned nranges = 0; /* number of elements in above list */ |
221 | char *sopt, *ltok; | 297 | char *LIST, *ltok; |
222 | const char *delim = NULL; | 298 | const char *delim = NULL; |
223 | const char *odelim = NULL; | 299 | const char *odelim = NULL; |
224 | unsigned opt; | 300 | unsigned opt; |
301 | #if ENABLE_FEATURE_CUT_REGEX | ||
302 | regex_t reg; | ||
303 | #endif | ||
304 | #if ENABLE_LONG_OPTS | ||
305 | static const char cut_longopts[] ALIGN1 = | ||
306 | "output-delimiter\0" Required_argument "O" | ||
307 | ; | ||
308 | #endif | ||
225 | 309 | ||
226 | #define ARG "bcf"IF_FEATURE_CUT_REGEX("F") | 310 | #define ARG "bcf"IF_FEATURE_CUT_REGEX("F") |
227 | opt = getopt32(argv, "^" | 311 | #if ENABLE_LONG_OPTS |
312 | opt = getopt32long | ||
313 | #else | ||
314 | opt = getopt32 | ||
315 | #endif | ||
316 | (argv, "^" | ||
228 | OPT_STR // = "b:c:f:d:O:sD"IF_FEATURE_CUT_REGEX("F:")"n" | 317 | OPT_STR // = "b:c:f:d:O:sD"IF_FEATURE_CUT_REGEX("F:")"n" |
229 | "\0" "b--"ARG":c--"ARG":f--"ARG IF_FEATURE_CUT_REGEX("F--"ARG), | 318 | "\0" "b:c:f:" IF_FEATURE_CUT_REGEX("F:") /* one of -bcfF is required */ |
230 | &sopt, &sopt, &sopt, &delim, &odelim IF_FEATURE_CUT_REGEX(, &sopt) | 319 | "b--"ARG":c--"ARG":f--"ARG IF_FEATURE_CUT_REGEX(":F--"ARG), /* they are mutually exclusive */ |
231 | ); | 320 | IF_LONG_OPTS(cut_longopts,) |
232 | if (!delim || !*delim) | 321 | &LIST, &LIST, &LIST, &delim, &odelim IF_FEATURE_CUT_REGEX(, &LIST) |
233 | delim = (opt & CUT_OPT_REGEX_FLGS) ? "[[:space:]]+" : "\t"; | 322 | ); |
234 | if (!odelim) odelim = (opt & CUT_OPT_REGEX_FLGS) ? " " : delim; | 323 | if (!odelim) |
324 | odelim = (opt & OPT_REGEX) ? " " : delim; | ||
325 | if (!delim) | ||
326 | delim = (opt & OPT_REGEX) ? "[[:space:]]+" : "\t"; | ||
235 | 327 | ||
236 | // argc -= optind; | 328 | // argc -= optind; |
237 | argv += optind; | 329 | argv += optind; |
238 | if (!(opt & (CUT_OPT_BYTE_FLGS | CUT_OPT_CHAR_FLGS | CUT_OPT_FIELDS_FLGS | CUT_OPT_REGEX_FLGS))) | 330 | //if (!(opt & (OPT_BYTE | OPT_CHAR | OPT_FIELDS | OPT_REGEX))) |
239 | bb_simple_error_msg_and_die("expected a list of bytes, characters, or fields"); | 331 | // bb_simple_error_msg_and_die("expected a list of bytes, characters, or fields"); |
240 | 332 | //^^^ handled by getopt32 | |
241 | /* non-field (char or byte) cutting has some special handling */ | 333 | |
242 | if (!(opt & (CUT_OPT_FIELDS_FLGS|CUT_OPT_REGEX_FLGS))) { | 334 | /* non-field (char or byte) cutting has some special handling */ |
243 | static const char _op_on_field[] ALIGN1 = " only when operating on fields"; | 335 | if (!(opt & (OPT_FIELDS|OPT_REGEX))) { |
244 | 336 | static const char requires_f[] ALIGN1 = " requires -f" | |
245 | if (opt & CUT_OPT_SUPPRESS_FLGS) { | 337 | IF_FEATURE_CUT_REGEX(" or -F"); |
246 | bb_error_msg_and_die | 338 | if (opt & OPT_SUPPRESS) |
247 | ("suppressing non-delimited lines makes sense%s", _op_on_field); | 339 | bb_error_msg_and_die("-s%s", requires_f); |
248 | } | 340 | if (opt & OPT_DELIM) |
249 | if (opt & CUT_OPT_DELIM_FLGS) { | 341 | bb_error_msg_and_die("-d DELIM%s", requires_f); |
250 | bb_error_msg_and_die | ||
251 | ("a delimiter may be specified%s", _op_on_field); | ||
252 | } | ||
253 | } | 342 | } |
254 | 343 | ||
255 | /* | 344 | /* |
256 | * parse list and put values into startpos and endpos. | 345 | * parse list and put values into startpos and endpos. |
257 | * valid list formats: N, N-, N-M, -M | 346 | * valid range formats: N, N-, N-M, -M |
258 | * more than one list can be separated by commas | 347 | * more than one range can be separated by commas |
259 | */ | 348 | */ |
260 | { | 349 | /* take apart the ranges, one by one (separated with commas) */ |
350 | while ((ltok = strsep(&LIST, ",")) != NULL) { | ||
261 | char *ntok; | 351 | char *ntok; |
262 | int s = 0, e = 0; | 352 | int s, e; |
263 | 353 | ||
264 | /* take apart the lists, one by one (they are separated with commas) */ | 354 | /* it's actually legal to pass an empty list */ |
265 | while ((ltok = strsep(&sopt, ",")) != NULL) { | 355 | //if (!ltok[0]) |
356 | // continue; | ||
357 | //^^^ testcase? | ||
358 | |||
359 | /* get the start pos */ | ||
360 | ntok = strsep(<ok, "-"); | ||
361 | if (!ntok[0]) { | ||
362 | if (!ltok) /* testcase: -f '' */ | ||
363 | bb_show_usage(); | ||
364 | if (!ltok[0]) /* testcase: -f - */ | ||
365 | bb_show_usage(); | ||
366 | s = 0; /* "-M" means "1-M" */ | ||
367 | } else { | ||
368 | /* "N" or "N-[M]" */ | ||
369 | /* arrays are zero based, while the user expects | ||
370 | * the first field/char on the line to be char #1 */ | ||
371 | s = xatoi_positive(ntok) - 1; | ||
372 | } | ||
266 | 373 | ||
267 | /* it's actually legal to pass an empty list */ | 374 | /* get the end pos */ |
268 | if (!ltok[0]) | 375 | if (!ltok) { |
269 | continue; | 376 | e = s; /* "N" means "N-N" */ |
377 | } else if (!ltok[0]) { | ||
378 | /* "N-" means "until the end of the line" */ | ||
379 | e = INT_MAX; | ||
380 | } else { | ||
381 | /* again, arrays are zero based, fields are 1 based */ | ||
382 | e = xatoi_positive(ltok) - 1; | ||
383 | } | ||
270 | 384 | ||
271 | /* get the start pos */ | 385 | if (s < 0 || e < s) |
272 | ntok = strsep(<ok, "-"); | 386 | bb_error_msg_and_die("invalid range %s-%s", ntok, ltok ?: ntok); |
273 | if (!ntok[0]) { | ||
274 | s = 0; | ||
275 | } else { | ||
276 | s = xatoi_positive(ntok); | ||
277 | /* account for the fact that arrays are zero based, while | ||
278 | * the user expects the first char on the line to be char #1 */ | ||
279 | #if !ENABLE_PLATFORM_MINGW32 | ||
280 | if (s != 0) | ||
281 | s--; | ||
282 | #else | ||
283 | s--; | ||
284 | #endif | ||
285 | } | ||
286 | 387 | ||
287 | /* get the end pos */ | 388 | /* add the new range */ |
288 | if (ltok == NULL) { | 389 | cut_list = xrealloc_vector(cut_list, 4, nranges); |
289 | e = s; | 390 | /* NB: s is always >= 0 */ |
290 | } else if (!ltok[0]) { | 391 | cut_list[nranges].startpos = s; |
291 | e = INT_MAX; | 392 | cut_list[nranges].endpos = e; |
292 | } else { | 393 | nranges++; |
293 | e = xatoi_positive(ltok); | 394 | } |
294 | /* if the user specified no end position, | 395 | cut_list[nranges].startpos = UINT_MAX; /* end indicator */ |
295 | * that means "til the end of the line" */ | ||
296 | #if !ENABLE_PLATFORM_MINGW32 | ||
297 | if (!*ltok) | ||
298 | e = INT_MAX; | ||
299 | else if (e < s) | ||
300 | bb_error_msg_and_die("%d<%d", e, s); | ||
301 | #endif | ||
302 | e--; /* again, arrays are zero based, lines are 1 based */ | ||
303 | } | ||
304 | #if ENABLE_PLATFORM_MINGW32 | ||
305 | if (s < 0 || e < s) | ||
306 | bb_error_msg_and_die("invalid range %s-%s", ntok, ltok ?: ntok); | ||
307 | #endif | ||
308 | 396 | ||
309 | /* add the new list */ | 397 | /* make sure we got some cut positions out of all that */ |
310 | cut_lists = xrealloc_vector(cut_lists, 4, nlists); | 398 | //if (nranges == 0) |
311 | /* NB: startpos is always >= 0 */ | 399 | // bb_simple_error_msg_and_die("missing list of positions"); |
312 | cut_lists[nlists].startpos = s; | 400 | //^^^ this is impossible since one of -bcfF is required, |
313 | cut_lists[nlists].endpos = e; | 401 | // they populate LIST with non-NULL string and when it is parsed, |
314 | nlists++; | 402 | // cut_list[] gets at least one element. |
315 | } | ||
316 | 403 | ||
317 | /* make sure we got some cut positions out of all that */ | 404 | /* now that the lists are parsed, we need to sort them to make life |
318 | if (nlists == 0) | 405 | * easier on us when it comes time to print the chars / fields / lines |
319 | bb_simple_error_msg_and_die("missing list of positions"); | 406 | */ |
407 | if (!(opt & OPT_NOSORT)) | ||
408 | qsort(cut_list, nranges, sizeof(cut_list[0]), cmpfunc); | ||
320 | 409 | ||
321 | /* now that the lists are parsed, we need to sort them to make life | 410 | #if ENABLE_FEATURE_CUT_REGEX |
322 | * easier on us when it comes time to print the chars / fields / lines | 411 | if (opt & OPT_REGEX) { |
323 | */ | 412 | xregcomp(®, delim, REG_EXTENDED); |
324 | if (!(opt & CUT_OPT_NOSORT_FLGS)) | 413 | delim = (void*) ® |
325 | qsort(cut_lists, nlists, sizeof(cut_lists[0]), cmpfunc); | ||
326 | } | 414 | } |
415 | #endif | ||
327 | 416 | ||
328 | { | 417 | { |
329 | exitcode_t retval = EXIT_SUCCESS; | 418 | exitcode_t retval = EXIT_SUCCESS; |
@@ -337,12 +426,12 @@ int cut_main(int argc UNUSED_PARAM, char **argv) | |||
337 | retval = EXIT_FAILURE; | 426 | retval = EXIT_FAILURE; |
338 | continue; | 427 | continue; |
339 | } | 428 | } |
340 | cut_file(file, delim, odelim, cut_lists, nlists); | 429 | cut_file(file, delim, odelim, cut_list); |
341 | fclose_if_not_stdin(file); | 430 | fclose_if_not_stdin(file); |
342 | } while (*++argv); | 431 | } while (*++argv); |
343 | 432 | ||
344 | if (ENABLE_FEATURE_CLEAN_UP) | 433 | if (ENABLE_FEATURE_CLEAN_UP) |
345 | free(cut_lists); | 434 | free(cut_list); |
346 | fflush_stdout_and_exit(retval); | 435 | fflush_stdout_and_exit(retval); |
347 | } | 436 | } |
348 | } | 437 | } |
diff --git a/coreutils/df.c b/coreutils/df.c index 03aa78148..01c41db38 100644 --- a/coreutils/df.c +++ b/coreutils/df.c | |||
@@ -64,7 +64,9 @@ | |||
64 | //usage: "[-Pk" | 64 | //usage: "[-Pk" |
65 | //usage: IF_FEATURE_HUMAN_READABLE("mh") | 65 | //usage: IF_FEATURE_HUMAN_READABLE("mh") |
66 | //usage: "T" | 66 | //usage: "T" |
67 | //usage: IF_FEATURE_DF_FANCY("ai] [-B SIZE") | 67 | //usage: IF_FEATURE_DF_FANCY("a" |
68 | //usage: IF_PLATFORM_POSIX("i") | ||
69 | //usage: "] [-B SIZE") | ||
68 | //usage: "] [-t TYPE] [FILESYSTEM]..." | 70 | //usage: "] [-t TYPE] [FILESYSTEM]..." |
69 | //usage:#define df_full_usage "\n\n" | 71 | //usage:#define df_full_usage "\n\n" |
70 | //usage: "Print filesystem usage statistics\n" | 72 | //usage: "Print filesystem usage statistics\n" |
@@ -78,7 +80,9 @@ | |||
78 | //usage: "\n -t TYPE Print only mounts of this type" | 80 | //usage: "\n -t TYPE Print only mounts of this type" |
79 | //usage: IF_FEATURE_DF_FANCY( | 81 | //usage: IF_FEATURE_DF_FANCY( |
80 | //usage: "\n -a Show all filesystems" | 82 | //usage: "\n -a Show all filesystems" |
83 | //usage: IF_PLATFORM_POSIX( | ||
81 | //usage: "\n -i Inodes" | 84 | //usage: "\n -i Inodes" |
85 | //usage: ) | ||
82 | //usage: "\n -B SIZE Blocksize" | 86 | //usage: "\n -B SIZE Blocksize" |
83 | //usage: ) | 87 | //usage: ) |
84 | //usage: | 88 | //usage: |
@@ -109,6 +113,12 @@ static unsigned long kscale(unsigned long b, unsigned long bs) | |||
109 | } | 113 | } |
110 | #endif | 114 | #endif |
111 | 115 | ||
116 | #if ENABLE_PLATFORM_MINGW32 | ||
117 | # define ENABLE_FEATURE_DF_FANCY_POSIX 0 | ||
118 | #else | ||
119 | # define ENABLE_FEATURE_DF_FANCY_POSIX ENABLE_FEATURE_DF_FANCY | ||
120 | #endif | ||
121 | |||
112 | int df_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 122 | int df_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
113 | int df_main(int argc UNUSED_PARAM, char **argv) | 123 | int df_main(int argc UNUSED_PARAM, char **argv) |
114 | { | 124 | { |
@@ -124,11 +134,11 @@ int df_main(int argc UNUSED_PARAM, char **argv) | |||
124 | OPT_FSTYPE = (1 << 2), | 134 | OPT_FSTYPE = (1 << 2), |
125 | OPT_t = (1 << 3), | 135 | OPT_t = (1 << 3), |
126 | OPT_ALL = (1 << 4) * ENABLE_FEATURE_DF_FANCY, | 136 | OPT_ALL = (1 << 4) * ENABLE_FEATURE_DF_FANCY, |
127 | OPT_INODE = (1 << 5) * ENABLE_FEATURE_DF_FANCY, | 137 | OPT_INODE = (1 << 5) * ENABLE_FEATURE_DF_FANCY_POSIX, |
128 | OPT_BSIZE = (1 << 6) * ENABLE_FEATURE_DF_FANCY, | 138 | OPT_BSIZE = (1 << (5 + ENABLE_FEATURE_DF_FANCY_POSIX)) * ENABLE_FEATURE_DF_FANCY, |
129 | OPT_HUMAN = (1 << (4 + 3*ENABLE_FEATURE_DF_FANCY)) * ENABLE_FEATURE_HUMAN_READABLE, | 139 | OPT_HUMAN = (1 << (4 + 2*ENABLE_FEATURE_DF_FANCY + ENABLE_FEATURE_DF_FANCY_POSIX)) * ENABLE_FEATURE_HUMAN_READABLE, |
130 | OPT_HUMANDEC = (1 << (5 + 3*ENABLE_FEATURE_DF_FANCY)) * ENABLE_FEATURE_HUMAN_READABLE, | 140 | OPT_HUMANDEC = (1 << (5 + 2*ENABLE_FEATURE_DF_FANCY + ENABLE_FEATURE_DF_FANCY_POSIX)) * ENABLE_FEATURE_HUMAN_READABLE, |
131 | OPT_MEGA = (1 << (6 + 3*ENABLE_FEATURE_DF_FANCY)) * ENABLE_FEATURE_HUMAN_READABLE, | 141 | OPT_MEGA = (1 << (6 + 2*ENABLE_FEATURE_DF_FANCY + ENABLE_FEATURE_DF_FANCY_POSIX)) * ENABLE_FEATURE_HUMAN_READABLE, |
132 | }; | 142 | }; |
133 | const char *disp_units_hdr = NULL; | 143 | const char *disp_units_hdr = NULL; |
134 | char *chp, *opt_t; | 144 | char *chp, *opt_t; |
@@ -144,7 +154,11 @@ int df_main(int argc UNUSED_PARAM, char **argv) | |||
144 | 154 | ||
145 | opt = getopt32(argv, "^" | 155 | opt = getopt32(argv, "^" |
146 | "kPTt:" | 156 | "kPTt:" |
157 | #if ENABLE_PLATFORM_POSIX | ||
147 | IF_FEATURE_DF_FANCY("aiB:") | 158 | IF_FEATURE_DF_FANCY("aiB:") |
159 | #else | ||
160 | IF_FEATURE_DF_FANCY("aB:") | ||
161 | #endif | ||
148 | IF_FEATURE_HUMAN_READABLE("hHm") | 162 | IF_FEATURE_HUMAN_READABLE("hHm") |
149 | "\0" | 163 | "\0" |
150 | #if ENABLE_FEATURE_HUMAN_READABLE && ENABLE_FEATURE_DF_FANCY | 164 | #if ENABLE_FEATURE_HUMAN_READABLE && ENABLE_FEATURE_DF_FANCY |
@@ -155,6 +169,9 @@ int df_main(int argc UNUSED_PARAM, char **argv) | |||
155 | , &opt_t | 169 | , &opt_t |
156 | IF_FEATURE_DF_FANCY(, &chp) | 170 | IF_FEATURE_DF_FANCY(, &chp) |
157 | ); | 171 | ); |
172 | /* -k overrides $POSIXLY_CORRECT: */ | ||
173 | if (opt & OPT_KILO) | ||
174 | df_disp_hr = 1024; | ||
158 | if (opt & OPT_MEGA) | 175 | if (opt & OPT_MEGA) |
159 | df_disp_hr = 1024*1024; | 176 | df_disp_hr = 1024*1024; |
160 | 177 | ||
@@ -185,8 +202,8 @@ int df_main(int argc UNUSED_PARAM, char **argv) | |||
185 | if (disp_units_hdr == NULL) { | 202 | if (disp_units_hdr == NULL) { |
186 | #if ENABLE_FEATURE_HUMAN_READABLE | 203 | #if ENABLE_FEATURE_HUMAN_READABLE |
187 | disp_units_hdr = xasprintf("%s-blocks", | 204 | disp_units_hdr = xasprintf("%s-blocks", |
188 | /* print df_disp_hr, show no fractionals, | 205 | /* print df_disp_hr; show no fractionals; |
189 | * use suffixes if OPT_POSIX is set in opt */ | 206 | * if -P, unit=1 (print it in full, no KMG suffixes) */ |
190 | make_human_readable_str(df_disp_hr, 0, !!(opt & OPT_POSIX)) | 207 | make_human_readable_str(df_disp_hr, 0, !!(opt & OPT_POSIX)) |
191 | ); | 208 | ); |
192 | #else | 209 | #else |
diff --git a/coreutils/expr.c b/coreutils/expr.c index 3f7e21871..c00559e4c 100644 --- a/coreutils/expr.c +++ b/coreutils/expr.c | |||
@@ -97,6 +97,10 @@ typedef long arith_t; | |||
97 | 97 | ||
98 | /* TODO: use bb_strtol[l]? It's easier to check for errors... */ | 98 | /* TODO: use bb_strtol[l]? It's easier to check for errors... */ |
99 | 99 | ||
100 | #if ENABLE_PLATFORM_MINGW32 | ||
101 | # define STRING BB_STRING | ||
102 | #endif | ||
103 | |||
100 | /* The kinds of value we can have. */ | 104 | /* The kinds of value we can have. */ |
101 | enum { | 105 | enum { |
102 | INTEGER, | 106 | INTEGER, |
diff --git a/coreutils/stty.c b/coreutils/stty.c index c88ef07f4..92d5838c0 100644 --- a/coreutils/stty.c +++ b/coreutils/stty.c | |||
@@ -20,14 +20,30 @@ | |||
20 | //kbuild:lib-$(CONFIG_STTY) += stty.o | 20 | //kbuild:lib-$(CONFIG_STTY) += stty.o |
21 | 21 | ||
22 | //usage:#define stty_trivial_usage | 22 | //usage:#define stty_trivial_usage |
23 | //usage: IF_NOT_PLATFORM_MINGW32( | ||
23 | //usage: "[-a|g] [-F DEVICE] [SETTING]..." | 24 | //usage: "[-a|g] [-F DEVICE] [SETTING]..." |
25 | //usage: ) | ||
26 | //usage: IF_PLATFORM_MINGW32( | ||
27 | //usage: "[-a] [SETTING]..." | ||
28 | //usage: ) | ||
24 | //usage:#define stty_full_usage "\n\n" | 29 | //usage:#define stty_full_usage "\n\n" |
30 | //usage: IF_NOT_PLATFORM_MINGW32( | ||
25 | //usage: "Without arguments, prints baud rate, line discipline,\n" | 31 | //usage: "Without arguments, prints baud rate, line discipline,\n" |
26 | //usage: "and deviations from stty sane\n" | 32 | //usage: "and deviations from stty sane\n" |
27 | //usage: "\n -F DEVICE Open device instead of stdin" | 33 | //usage: "\n -F DEVICE Open device instead of stdin" |
34 | //usage: ) | ||
35 | //usage: IF_PLATFORM_MINGW32( | ||
36 | //usage: "Without arguments, prints deviations from stty sane\n" | ||
37 | //usage: ) | ||
28 | //usage: "\n -a Print all current settings in human-readable form" | 38 | //usage: "\n -a Print all current settings in human-readable form" |
39 | //usage: IF_NOT_PLATFORM_MINGW32( | ||
29 | //usage: "\n -g Print in stty-readable form" | 40 | //usage: "\n -g Print in stty-readable form" |
30 | //usage: "\n [SETTING] See manpage" | 41 | //usage: "\n [SETTING] See manpage" |
42 | //usage: ) | ||
43 | //usage: IF_PLATFORM_MINGW32( | ||
44 | //usage: "\n [SETTING] [-]echo [-]cooked [-]raw sane" | ||
45 | //usage: "\n cols N rows N size" | ||
46 | //usage: ) | ||
31 | 47 | ||
32 | /* If no args are given, write to stdout the baud rate and settings that | 48 | /* If no args are given, write to stdout the baud rate and settings that |
33 | * have been changed from their defaults. Mode reading and changes | 49 | * have been changed from their defaults. Mode reading and changes |
@@ -294,6 +310,7 @@ struct mode_info { | |||
294 | const tcflag_t bits; /* Bits to set for this mode */ | 310 | const tcflag_t bits; /* Bits to set for this mode */ |
295 | }; | 311 | }; |
296 | 312 | ||
313 | #if !ENABLE_PLATFORM_MINGW32 | ||
297 | enum { | 314 | enum { |
298 | /* Must match mode_name[] and mode_info[] order! */ | 315 | /* Must match mode_name[] and mode_info[] order! */ |
299 | IDX_evenp = 0, | 316 | IDX_evenp = 0, |
@@ -320,19 +337,30 @@ enum { | |||
320 | IDX_LCASE, | 337 | IDX_LCASE, |
321 | #endif | 338 | #endif |
322 | }; | 339 | }; |
340 | #else | ||
341 | enum { | ||
342 | /* Must match mode_name[] and mode_info[] order! */ | ||
343 | IDX_sane = 0, | ||
344 | IDX_cooked, | ||
345 | IDX_raw, | ||
346 | }; | ||
347 | #endif | ||
323 | 348 | ||
324 | #define MI_ENTRY(N,T,F,B,M) N "\0" | 349 | #define MI_ENTRY(N,T,F,B,M) N "\0" |
325 | 350 | ||
326 | /* Mode names given on command line */ | 351 | /* Mode names given on command line */ |
327 | static const char mode_name[] ALIGN1 = | 352 | static const char mode_name[] ALIGN1 = |
353 | #if !ENABLE_PLATFORM_MINGW32 | ||
328 | MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 ) | 354 | MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 ) |
329 | MI_ENTRY("parity", combination, REV | OMIT, 0, 0 ) | 355 | MI_ENTRY("parity", combination, REV | OMIT, 0, 0 ) |
330 | MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 ) | 356 | MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 ) |
331 | MI_ENTRY("nl", combination, REV | OMIT, 0, 0 ) | 357 | MI_ENTRY("nl", combination, REV | OMIT, 0, 0 ) |
332 | MI_ENTRY("ek", combination, OMIT, 0, 0 ) | 358 | MI_ENTRY("ek", combination, OMIT, 0, 0 ) |
359 | #endif | ||
333 | MI_ENTRY("sane", combination, OMIT, 0, 0 ) | 360 | MI_ENTRY("sane", combination, OMIT, 0, 0 ) |
334 | MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 ) | 361 | MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 ) |
335 | MI_ENTRY("raw", combination, REV | OMIT, 0, 0 ) | 362 | MI_ENTRY("raw", combination, REV | OMIT, 0, 0 ) |
363 | #if !ENABLE_PLATFORM_MINGW32 | ||
336 | MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 ) | 364 | MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 ) |
337 | MI_ENTRY("litout", combination, REV | OMIT, 0, 0 ) | 365 | MI_ENTRY("litout", combination, REV | OMIT, 0, 0 ) |
338 | MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 ) | 366 | MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 ) |
@@ -454,7 +482,9 @@ static const char mode_name[] ALIGN1 = | |||
454 | #if IEXTEN | 482 | #if IEXTEN |
455 | MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 ) | 483 | MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 ) |
456 | #endif | 484 | #endif |
485 | #endif /* !ENABLE_PLATFORM_MINGW32 */ | ||
457 | MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 ) | 486 | MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 ) |
487 | #if !ENABLE_PLATFORM_MINGW32 | ||
458 | MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 ) | 488 | MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 ) |
459 | MI_ENTRY("crterase", local, OMIT | REV, ECHOE, 0 ) | 489 | MI_ENTRY("crterase", local, OMIT | REV, ECHOE, 0 ) |
460 | MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 ) | 490 | MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 ) |
@@ -482,6 +512,7 @@ static const char mode_name[] ALIGN1 = | |||
482 | #ifdef EXTPROC | 512 | #ifdef EXTPROC |
483 | MI_ENTRY("extproc", local, SANE_UNSET | REV, EXTPROC, 0 ) | 513 | MI_ENTRY("extproc", local, SANE_UNSET | REV, EXTPROC, 0 ) |
484 | #endif | 514 | #endif |
515 | #endif /* !ENABLE_PLATFORM_MINGW32 */ | ||
485 | ; | 516 | ; |
486 | 517 | ||
487 | #undef MI_ENTRY | 518 | #undef MI_ENTRY |
@@ -489,14 +520,17 @@ static const char mode_name[] ALIGN1 = | |||
489 | 520 | ||
490 | static const struct mode_info mode_info[] ALIGN4 = { | 521 | static const struct mode_info mode_info[] ALIGN4 = { |
491 | /* This should be verbatim cut-n-paste copy of the above MI_ENTRYs */ | 522 | /* This should be verbatim cut-n-paste copy of the above MI_ENTRYs */ |
523 | #if !ENABLE_PLATFORM_MINGW32 | ||
492 | MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 ) | 524 | MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 ) |
493 | MI_ENTRY("parity", combination, REV | OMIT, 0, 0 ) | 525 | MI_ENTRY("parity", combination, REV | OMIT, 0, 0 ) |
494 | MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 ) | 526 | MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 ) |
495 | MI_ENTRY("nl", combination, REV | OMIT, 0, 0 ) | 527 | MI_ENTRY("nl", combination, REV | OMIT, 0, 0 ) |
496 | MI_ENTRY("ek", combination, OMIT, 0, 0 ) | 528 | MI_ENTRY("ek", combination, OMIT, 0, 0 ) |
529 | #endif | ||
497 | MI_ENTRY("sane", combination, OMIT, 0, 0 ) | 530 | MI_ENTRY("sane", combination, OMIT, 0, 0 ) |
498 | MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 ) | 531 | MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 ) |
499 | MI_ENTRY("raw", combination, REV | OMIT, 0, 0 ) | 532 | MI_ENTRY("raw", combination, REV | OMIT, 0, 0 ) |
533 | #if !ENABLE_PLATFORM_MINGW32 | ||
500 | MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 ) | 534 | MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 ) |
501 | MI_ENTRY("litout", combination, REV | OMIT, 0, 0 ) | 535 | MI_ENTRY("litout", combination, REV | OMIT, 0, 0 ) |
502 | MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 ) | 536 | MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 ) |
@@ -618,7 +652,9 @@ static const struct mode_info mode_info[] ALIGN4 = { | |||
618 | #if IEXTEN | 652 | #if IEXTEN |
619 | MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 ) | 653 | MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 ) |
620 | #endif | 654 | #endif |
655 | #endif /* !ENABLE_PLATFORM_MINGW32 */ | ||
621 | MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 ) | 656 | MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 ) |
657 | #if !ENABLE_PLATFORM_MINGW32 | ||
622 | MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 ) | 658 | MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 ) |
623 | MI_ENTRY("crterase", local, OMIT | REV, ECHOE, 0 ) | 659 | MI_ENTRY("crterase", local, OMIT | REV, ECHOE, 0 ) |
624 | MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 ) | 660 | MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 ) |
@@ -646,6 +682,7 @@ static const struct mode_info mode_info[] ALIGN4 = { | |||
646 | #ifdef EXTPROC | 682 | #ifdef EXTPROC |
647 | MI_ENTRY("extproc", local, SANE_UNSET | REV, EXTPROC, 0 ) | 683 | MI_ENTRY("extproc", local, SANE_UNSET | REV, EXTPROC, 0 ) |
648 | #endif | 684 | #endif |
685 | #endif /* !ENABLE_PLATFORM_MINGW32 */ | ||
649 | }; | 686 | }; |
650 | 687 | ||
651 | enum { | 688 | enum { |
@@ -653,6 +690,7 @@ enum { | |||
653 | }; | 690 | }; |
654 | 691 | ||
655 | 692 | ||
693 | #if !ENABLE_PLATFORM_MINGW32 | ||
656 | /* Control characters */ | 694 | /* Control characters */ |
657 | struct control_info { | 695 | struct control_info { |
658 | const uint8_t saneval; /* Value to set for 'stty sane' */ | 696 | const uint8_t saneval; /* Value to set for 'stty sane' */ |
@@ -786,6 +824,7 @@ static const struct control_info control_info[] ALIGN2 = { | |||
786 | enum { | 824 | enum { |
787 | NUM_control_info = ARRAY_SIZE(control_info) | 825 | NUM_control_info = ARRAY_SIZE(control_info) |
788 | }; | 826 | }; |
827 | #endif | ||
789 | 828 | ||
790 | 829 | ||
791 | struct globals { | 830 | struct globals { |
@@ -803,6 +842,7 @@ struct globals { | |||
803 | G.current_col = 0; /* we are noexec, must clear */ \ | 842 | G.current_col = 0; /* we are noexec, must clear */ \ |
804 | } while (0) | 843 | } while (0) |
805 | 844 | ||
845 | #if !ENABLE_PLATFORM_MINGW32 | ||
806 | static void set_speed_or_die(enum speed_setting type, const char *arg, | 846 | static void set_speed_or_die(enum speed_setting type, const char *arg, |
807 | struct termios *mode) | 847 | struct termios *mode) |
808 | { | 848 | { |
@@ -817,6 +857,7 @@ static void set_speed_or_die(enum speed_setting type, const char *arg, | |||
817 | cfsetospeed(mode, baud); | 857 | cfsetospeed(mode, baud); |
818 | } | 858 | } |
819 | } | 859 | } |
860 | #endif | ||
820 | 861 | ||
821 | static NORETURN void perror_on_device_and_die(const char *fmt) | 862 | static NORETURN void perror_on_device_and_die(const char *fmt) |
822 | { | 863 | { |
@@ -918,6 +959,7 @@ static const struct mode_info *find_mode(const char *name) | |||
918 | return i >= 0 ? &mode_info[i] : NULL; | 959 | return i >= 0 ? &mode_info[i] : NULL; |
919 | } | 960 | } |
920 | 961 | ||
962 | #if !ENABLE_PLATFORM_MINGW32 | ||
921 | static const struct control_info *find_control(const char *name) | 963 | static const struct control_info *find_control(const char *name) |
922 | { | 964 | { |
923 | int i = index_in_strings(control_name, name); | 965 | int i = index_in_strings(control_name, name); |
@@ -954,7 +996,32 @@ static int find_param(const char *name) | |||
954 | i |= 0x80; | 996 | i |= 0x80; |
955 | return i; | 997 | return i; |
956 | } | 998 | } |
999 | #else | ||
1000 | enum { | ||
1001 | param_need_arg = 0x80, | ||
1002 | param_rows = 1 | 0x80, | ||
1003 | param_cols = 2 | 0x80, | ||
1004 | param_columns = 3 | 0x80, | ||
1005 | param_size = 4, | ||
1006 | }; | ||
957 | 1007 | ||
1008 | static int find_param(const char *name) | ||
1009 | { | ||
1010 | static const char params[] ALIGN1 = | ||
1011 | "rows\0" /* 1 */ | ||
1012 | "cols\0" /* 2 */ | ||
1013 | "columns\0" /* 3 */ | ||
1014 | "size\0"; /* 4 */ | ||
1015 | int i = index_in_strings(params, name) + 1; | ||
1016 | if (i == 0) | ||
1017 | return 0; | ||
1018 | if (i != 4) | ||
1019 | i |= 0x80; | ||
1020 | return i; | ||
1021 | } | ||
1022 | #endif | ||
1023 | |||
1024 | #if !ENABLE_PLATFORM_MINGW32 | ||
958 | static int recover_mode(const char *arg, struct termios *mode) | 1025 | static int recover_mode(const char *arg, struct termios *mode) |
959 | { | 1026 | { |
960 | int i, n; | 1027 | int i, n; |
@@ -1013,6 +1080,9 @@ static void display_speed(const struct termios *mode, int fancy) | |||
1013 | if (fancy) fmt_str += 9; | 1080 | if (fancy) fmt_str += 9; |
1014 | wrapf(fmt_str, tty_baud_to_value(ispeed), tty_baud_to_value(ospeed)); | 1081 | wrapf(fmt_str, tty_baud_to_value(ispeed), tty_baud_to_value(ospeed)); |
1015 | } | 1082 | } |
1083 | #else | ||
1084 | # define display_speed(m, f) ((void)0) | ||
1085 | #endif | ||
1016 | 1086 | ||
1017 | static void do_display(const struct termios *mode, int all) | 1087 | static void do_display(const struct termios *mode, int all) |
1018 | { | 1088 | { |
@@ -1030,6 +1100,7 @@ static void do_display(const struct termios *mode, int all) | |||
1030 | newline(); | 1100 | newline(); |
1031 | #endif | 1101 | #endif |
1032 | 1102 | ||
1103 | #if !ENABLE_PLATFORM_MINGW32 | ||
1033 | for (i = 0; i != CIDX_min; ++i) { | 1104 | for (i = 0; i != CIDX_min; ++i) { |
1034 | char ch; | 1105 | char ch; |
1035 | char buf10[10]; | 1106 | char buf10[10]; |
@@ -1059,6 +1130,7 @@ static void do_display(const struct termios *mode, int all) | |||
1059 | #endif | 1130 | #endif |
1060 | wrapf("min = %u; time = %u;", mode->c_cc[VMIN], mode->c_cc[VTIME]); | 1131 | wrapf("min = %u; time = %u;", mode->c_cc[VMIN], mode->c_cc[VTIME]); |
1061 | newline(); | 1132 | newline(); |
1133 | #endif | ||
1062 | 1134 | ||
1063 | for (i = 0; i < NUM_mode_info; ++i) { | 1135 | for (i = 0; i < NUM_mode_info; ++i) { |
1064 | if (mode_info[i].flags & OMIT) | 1136 | if (mode_info[i].flags & OMIT) |
@@ -1086,6 +1158,7 @@ static void do_display(const struct termios *mode, int all) | |||
1086 | 1158 | ||
1087 | static void sane_mode(struct termios *mode) | 1159 | static void sane_mode(struct termios *mode) |
1088 | { | 1160 | { |
1161 | #if !ENABLE_PLATFORM_MINGW32 | ||
1089 | int i; | 1162 | int i; |
1090 | 1163 | ||
1091 | for (i = 0; i < NUM_control_info; ++i) { | 1164 | for (i = 0; i < NUM_control_info; ++i) { |
@@ -1110,6 +1183,11 @@ static void sane_mode(struct termios *mode) | |||
1110 | *bitsp = val & ~mode_info[i].bits; | 1183 | *bitsp = val & ~mode_info[i].bits; |
1111 | } | 1184 | } |
1112 | } | 1185 | } |
1186 | #else | ||
1187 | mode->c_lflag |= ECHO; | ||
1188 | mode->w_mode |= ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | | ||
1189 | ENABLE_PROCESSED_INPUT; | ||
1190 | #endif | ||
1113 | } | 1191 | } |
1114 | 1192 | ||
1115 | static void set_mode(const struct mode_info *info, int reversed, | 1193 | static void set_mode(const struct mode_info *info, int reversed, |
@@ -1129,6 +1207,7 @@ static void set_mode(const struct mode_info *info, int reversed, | |||
1129 | } | 1207 | } |
1130 | 1208 | ||
1131 | /* !bitsp - it's a "combination" mode */ | 1209 | /* !bitsp - it's a "combination" mode */ |
1210 | #if !ENABLE_PLATFORM_MINGW32 | ||
1132 | if (info == &mode_info[IDX_evenp] || info == &mode_info[IDX_parity]) { | 1211 | if (info == &mode_info[IDX_evenp] || info == &mode_info[IDX_parity]) { |
1133 | if (reversed) | 1212 | if (reversed) |
1134 | mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8; | 1213 | mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8; |
@@ -1150,9 +1229,14 @@ static void set_mode(const struct mode_info *info, int reversed, | |||
1150 | } else if (info == &mode_info[IDX_ek]) { | 1229 | } else if (info == &mode_info[IDX_ek]) { |
1151 | mode->c_cc[VERASE] = CERASE; | 1230 | mode->c_cc[VERASE] = CERASE; |
1152 | mode->c_cc[VKILL] = CKILL; | 1231 | mode->c_cc[VKILL] = CKILL; |
1153 | } else if (info == &mode_info[IDX_sane]) { | 1232 | } |
1233 | else | ||
1234 | #endif /* !ENABLE_PLATFORM_MINGW32 */ | ||
1235 | if (info == &mode_info[IDX_sane]) { | ||
1154 | sane_mode(mode); | 1236 | sane_mode(mode); |
1155 | } else if (info == &mode_info[IDX_cbreak]) { | 1237 | } |
1238 | #if !ENABLE_PLATFORM_MINGW32 | ||
1239 | else if (info == &mode_info[IDX_cbreak]) { | ||
1156 | if (reversed) | 1240 | if (reversed) |
1157 | mode->c_lflag |= ICANON; | 1241 | mode->c_lflag |= ICANON; |
1158 | else | 1242 | else |
@@ -1175,11 +1259,14 @@ static void set_mode(const struct mode_info *info, int reversed, | |||
1175 | mode->c_iflag &= ~ISTRIP; | 1259 | mode->c_iflag &= ~ISTRIP; |
1176 | mode->c_oflag &= ~OPOST; | 1260 | mode->c_oflag &= ~OPOST; |
1177 | } | 1261 | } |
1178 | } else if (info == &mode_info[IDX_raw] || info == &mode_info[IDX_cooked]) { | 1262 | } |
1263 | #endif /* !ENABLE_PLATFORM_MINGW32 */ | ||
1264 | else if (info == &mode_info[IDX_raw] || info == &mode_info[IDX_cooked]) { | ||
1179 | if ((info == &mode_info[IDX_raw] && reversed) | 1265 | if ((info == &mode_info[IDX_raw] && reversed) |
1180 | || (info == &mode_info[IDX_cooked] && !reversed) | 1266 | || (info == &mode_info[IDX_cooked] && !reversed) |
1181 | ) { | 1267 | ) { |
1182 | /* Cooked mode */ | 1268 | /* Cooked mode */ |
1269 | #if !ENABLE_PLATFORM_MINGW32 | ||
1183 | mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON; | 1270 | mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON; |
1184 | mode->c_oflag |= OPOST; | 1271 | mode->c_oflag |= OPOST; |
1185 | mode->c_lflag |= ISIG | ICANON; | 1272 | mode->c_lflag |= ISIG | ICANON; |
@@ -1189,15 +1276,23 @@ static void set_mode(const struct mode_info *info, int reversed, | |||
1189 | #if VTIME == VEOL | 1276 | #if VTIME == VEOL |
1190 | mode->c_cc[VEOL] = CEOL; | 1277 | mode->c_cc[VEOL] = CEOL; |
1191 | #endif | 1278 | #endif |
1279 | #else | ||
1280 | mode->w_mode |= ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT; | ||
1281 | #endif | ||
1192 | } else { | 1282 | } else { |
1193 | /* Raw mode */ | 1283 | /* Raw mode */ |
1284 | #if !ENABLE_PLATFORM_MINGW32 | ||
1194 | mode->c_iflag = 0; | 1285 | mode->c_iflag = 0; |
1195 | mode->c_oflag &= ~OPOST; | 1286 | mode->c_oflag &= ~OPOST; |
1196 | mode->c_lflag &= ~(ISIG | ICANON | XCASE); | 1287 | mode->c_lflag &= ~(ISIG | ICANON | XCASE); |
1197 | mode->c_cc[VMIN] = 1; | 1288 | mode->c_cc[VMIN] = 1; |
1198 | mode->c_cc[VTIME] = 0; | 1289 | mode->c_cc[VTIME] = 0; |
1290 | #else | ||
1291 | mode->w_mode &= ~(ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT); | ||
1292 | #endif | ||
1199 | } | 1293 | } |
1200 | } | 1294 | } |
1295 | #if !ENABLE_PLATFORM_MINGW32 | ||
1201 | #if IXANY | 1296 | #if IXANY |
1202 | else if (info == &mode_info[IDX_decctlq]) { | 1297 | else if (info == &mode_info[IDX_decctlq]) { |
1203 | if (reversed) | 1298 | if (reversed) |
@@ -1244,8 +1339,10 @@ static void set_mode(const struct mode_info *info, int reversed, | |||
1244 | mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE; | 1339 | mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE; |
1245 | if (IXANY) mode->c_iflag &= ~IXANY; | 1340 | if (IXANY) mode->c_iflag &= ~IXANY; |
1246 | } | 1341 | } |
1342 | #endif /*!ENABLE_PLATFORM_MINGW32 */ | ||
1247 | } | 1343 | } |
1248 | 1344 | ||
1345 | #if !ENABLE_PLATFORM_MINGW32 | ||
1249 | static void set_control_char_or_die(const struct control_info *info, | 1346 | static void set_control_char_or_die(const struct control_info *info, |
1250 | const char *arg, struct termios *mode) | 1347 | const char *arg, struct termios *mode) |
1251 | { | 1348 | { |
@@ -1265,6 +1362,7 @@ static void set_control_char_or_die(const struct control_info *info, | |||
1265 | value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes); | 1362 | value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes); |
1266 | mode->c_cc[info->offset] = value; | 1363 | mode->c_cc[info->offset] = value; |
1267 | } | 1364 | } |
1365 | #endif | ||
1268 | 1366 | ||
1269 | #define STTY_require_set_attr (1 << 0) | 1367 | #define STTY_require_set_attr (1 << 0) |
1270 | #define STTY_speed_was_set (1 << 1) | 1368 | #define STTY_speed_was_set (1 << 1) |
@@ -1277,7 +1375,9 @@ int stty_main(int argc UNUSED_PARAM, char **argv) | |||
1277 | { | 1375 | { |
1278 | struct termios mode; | 1376 | struct termios mode; |
1279 | void (*output_func)(const struct termios *, int); | 1377 | void (*output_func)(const struct termios *, int); |
1378 | #if !ENABLE_PLATFORM_MINGW32 | ||
1280 | const char *file_name = NULL; | 1379 | const char *file_name = NULL; |
1380 | #endif | ||
1281 | int display_all = 0; | 1381 | int display_all = 0; |
1282 | int stty_state; | 1382 | int stty_state; |
1283 | int k; | 1383 | int k; |
@@ -1291,7 +1391,9 @@ int stty_main(int argc UNUSED_PARAM, char **argv) | |||
1291 | k = 0; | 1391 | k = 0; |
1292 | while (argv[++k]) { | 1392 | while (argv[++k]) { |
1293 | const struct mode_info *mp; | 1393 | const struct mode_info *mp; |
1394 | #if !ENABLE_PLATFORM_MINGW32 | ||
1294 | const struct control_info *cp; | 1395 | const struct control_info *cp; |
1396 | #endif | ||
1295 | const char *arg = argv[k]; | 1397 | const char *arg = argv[k]; |
1296 | const char *argnext = argv[k+1]; | 1398 | const char *argnext = argv[k+1]; |
1297 | int param; | 1399 | int param; |
@@ -1314,6 +1416,7 @@ int stty_main(int argc UNUSED_PARAM, char **argv) | |||
1314 | output_func = do_display; | 1416 | output_func = do_display; |
1315 | display_all = 1; | 1417 | display_all = 1; |
1316 | break; | 1418 | break; |
1419 | #if !ENABLE_PLATFORM_MINGW32 | ||
1317 | case 'g': | 1420 | case 'g': |
1318 | stty_state |= STTY_recoverable_output; | 1421 | stty_state |= STTY_recoverable_output; |
1319 | output_func = display_recoverable; | 1422 | output_func = display_recoverable; |
@@ -1334,11 +1437,14 @@ int stty_main(int argc UNUSED_PARAM, char **argv) | |||
1334 | } | 1437 | } |
1335 | } | 1438 | } |
1336 | goto end_option; | 1439 | goto end_option; |
1440 | #endif | ||
1337 | default: | 1441 | default: |
1338 | goto invalid_argument; | 1442 | goto invalid_argument; |
1339 | } | 1443 | } |
1340 | } | 1444 | } |
1445 | #if !ENABLE_PLATFORM_MINGW32 | ||
1341 | end_option: | 1446 | end_option: |
1447 | #endif | ||
1342 | continue; | 1448 | continue; |
1343 | } | 1449 | } |
1344 | 1450 | ||
@@ -1348,6 +1454,7 @@ int stty_main(int argc UNUSED_PARAM, char **argv) | |||
1348 | continue; | 1454 | continue; |
1349 | } | 1455 | } |
1350 | 1456 | ||
1457 | #if !ENABLE_PLATFORM_MINGW32 | ||
1351 | cp = find_control(arg); | 1458 | cp = find_control(arg); |
1352 | if (cp) { | 1459 | if (cp) { |
1353 | if (!argnext) | 1460 | if (!argnext) |
@@ -1358,6 +1465,7 @@ int stty_main(int argc UNUSED_PARAM, char **argv) | |||
1358 | ++k; | 1465 | ++k; |
1359 | continue; | 1466 | continue; |
1360 | } | 1467 | } |
1468 | #endif | ||
1361 | 1469 | ||
1362 | param = find_param(arg); | 1470 | param = find_param(arg); |
1363 | if (param & param_need_arg) { | 1471 | if (param & param_need_arg) { |
@@ -1381,7 +1489,11 @@ int stty_main(int argc UNUSED_PARAM, char **argv) | |||
1381 | xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes); | 1489 | xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes); |
1382 | break; | 1490 | break; |
1383 | case param_size: | 1491 | case param_size: |
1492 | # if ENABLE_PLATFORM_MINGW32 | ||
1493 | break; | ||
1494 | # endif | ||
1384 | #endif | 1495 | #endif |
1496 | #if !ENABLE_PLATFORM_MINGW32 | ||
1385 | case param_speed: | 1497 | case param_speed: |
1386 | break; | 1498 | break; |
1387 | case param_ispeed: | 1499 | case param_ispeed: |
@@ -1392,15 +1504,19 @@ int stty_main(int argc UNUSED_PARAM, char **argv) | |||
1392 | /* called for the side effect of xfunc death only */ | 1504 | /* called for the side effect of xfunc death only */ |
1393 | set_speed_or_die(output_speed, argnext, &mode); | 1505 | set_speed_or_die(output_speed, argnext, &mode); |
1394 | break; | 1506 | break; |
1507 | #endif | ||
1395 | default: | 1508 | default: |
1509 | #if !ENABLE_PLATFORM_MINGW32 | ||
1396 | if (recover_mode(arg, &mode) == 1) break; | 1510 | if (recover_mode(arg, &mode) == 1) break; |
1397 | if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) break; | 1511 | if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) break; |
1512 | #endif | ||
1398 | invalid_argument: | 1513 | invalid_argument: |
1399 | bb_error_msg_and_die("invalid argument '%s'", arg); | 1514 | bb_error_msg_and_die("invalid argument '%s'", arg); |
1400 | } | 1515 | } |
1401 | stty_state &= ~STTY_noargs; | 1516 | stty_state &= ~STTY_noargs; |
1402 | } | 1517 | } |
1403 | 1518 | ||
1519 | #if !ENABLE_PLATFORM_MINGW32 | ||
1404 | /* Specifying both -a and -g is an error */ | 1520 | /* Specifying both -a and -g is an error */ |
1405 | if ((stty_state & (STTY_verbose_output | STTY_recoverable_output)) == | 1521 | if ((stty_state & (STTY_verbose_output | STTY_recoverable_output)) == |
1406 | (STTY_verbose_output | STTY_recoverable_output) | 1522 | (STTY_verbose_output | STTY_recoverable_output) |
@@ -1413,13 +1529,22 @@ int stty_main(int argc UNUSED_PARAM, char **argv) | |||
1413 | ) { | 1529 | ) { |
1414 | bb_simple_error_msg_and_die("modes may not be set when -a or -g is used"); | 1530 | bb_simple_error_msg_and_die("modes may not be set when -a or -g is used"); |
1415 | } | 1531 | } |
1532 | #else | ||
1533 | /* Specifying -a with non-options is an error */ | ||
1534 | if ((stty_state & STTY_verbose_output) && !(stty_state & STTY_noargs) | ||
1535 | ) { | ||
1536 | bb_simple_error_msg_and_die("modes may not be set when -a is used"); | ||
1537 | } | ||
1538 | #endif | ||
1416 | 1539 | ||
1540 | #if !ENABLE_PLATFORM_MINGW32 | ||
1417 | /* Now it is safe to start doing things */ | 1541 | /* Now it is safe to start doing things */ |
1418 | if (file_name) { | 1542 | if (file_name) { |
1419 | G.device_name = file_name; | 1543 | G.device_name = file_name; |
1420 | xmove_fd(xopen_nonblocking(G.device_name), STDIN_FILENO); | 1544 | xmove_fd(xopen_nonblocking(G.device_name), STDIN_FILENO); |
1421 | ndelay_off(STDIN_FILENO); | 1545 | ndelay_off(STDIN_FILENO); |
1422 | } | 1546 | } |
1547 | #endif | ||
1423 | 1548 | ||
1424 | /* Initialize to all zeroes so there is no risk memcmp will report a | 1549 | /* Initialize to all zeroes so there is no risk memcmp will report a |
1425 | spurious difference in an uninitialized portion of the structure */ | 1550 | spurious difference in an uninitialized portion of the structure */ |
@@ -1437,7 +1562,9 @@ int stty_main(int argc UNUSED_PARAM, char **argv) | |||
1437 | k = 0; | 1562 | k = 0; |
1438 | while (argv[++k]) { | 1563 | while (argv[++k]) { |
1439 | const struct mode_info *mp; | 1564 | const struct mode_info *mp; |
1565 | #if !ENABLE_PLATFORM_MINGW32 | ||
1440 | const struct control_info *cp; | 1566 | const struct control_info *cp; |
1567 | #endif | ||
1441 | const char *arg = argv[k]; | 1568 | const char *arg = argv[k]; |
1442 | const char *argnext = argv[k+1]; | 1569 | const char *argnext = argv[k+1]; |
1443 | int param; | 1570 | int param; |
@@ -1459,6 +1586,7 @@ int stty_main(int argc UNUSED_PARAM, char **argv) | |||
1459 | continue; | 1586 | continue; |
1460 | } | 1587 | } |
1461 | 1588 | ||
1589 | #if !ENABLE_PLATFORM_MINGW32 | ||
1462 | cp = find_control(arg); | 1590 | cp = find_control(arg); |
1463 | if (cp) { | 1591 | if (cp) { |
1464 | ++k; | 1592 | ++k; |
@@ -1466,6 +1594,7 @@ int stty_main(int argc UNUSED_PARAM, char **argv) | |||
1466 | stty_state |= STTY_require_set_attr; | 1594 | stty_state |= STTY_require_set_attr; |
1467 | continue; | 1595 | continue; |
1468 | } | 1596 | } |
1597 | #endif | ||
1469 | 1598 | ||
1470 | param = find_param(arg); | 1599 | param = find_param(arg); |
1471 | if (param & param_need_arg) { | 1600 | if (param & param_need_arg) { |
@@ -1491,6 +1620,7 @@ int stty_main(int argc UNUSED_PARAM, char **argv) | |||
1491 | set_window_size(xatoul_sfx(argnext, stty_suffixes), -1); | 1620 | set_window_size(xatoul_sfx(argnext, stty_suffixes), -1); |
1492 | break; | 1621 | break; |
1493 | #endif | 1622 | #endif |
1623 | #if !ENABLE_PLATFORM_MINGW32 | ||
1494 | case param_speed: | 1624 | case param_speed: |
1495 | display_speed(&mode, 0); | 1625 | display_speed(&mode, 0); |
1496 | break; | 1626 | break; |
@@ -1502,7 +1632,9 @@ int stty_main(int argc UNUSED_PARAM, char **argv) | |||
1502 | set_speed_or_die(output_speed, argnext, &mode); | 1632 | set_speed_or_die(output_speed, argnext, &mode); |
1503 | stty_state |= (STTY_require_set_attr | STTY_speed_was_set); | 1633 | stty_state |= (STTY_require_set_attr | STTY_speed_was_set); |
1504 | break; | 1634 | break; |
1635 | #endif | ||
1505 | default: | 1636 | default: |
1637 | #if !ENABLE_PLATFORM_MINGW32 | ||
1506 | if (recover_mode(arg, &mode) == 1) | 1638 | if (recover_mode(arg, &mode) == 1) |
1507 | stty_state |= STTY_require_set_attr; | 1639 | stty_state |= STTY_require_set_attr; |
1508 | else /* true: if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) */{ | 1640 | else /* true: if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) */{ |
@@ -1510,15 +1642,24 @@ int stty_main(int argc UNUSED_PARAM, char **argv) | |||
1510 | stty_state |= (STTY_require_set_attr | STTY_speed_was_set); | 1642 | stty_state |= (STTY_require_set_attr | STTY_speed_was_set); |
1511 | } /* else - impossible (caught in the first pass): | 1643 | } /* else - impossible (caught in the first pass): |
1512 | bb_error_msg_and_die("invalid argument '%s'", arg); */ | 1644 | bb_error_msg_and_die("invalid argument '%s'", arg); */ |
1645 | #endif | ||
1513 | } | 1646 | } |
1514 | } | 1647 | } |
1515 | 1648 | ||
1516 | if (stty_state & STTY_require_set_attr) { | 1649 | if (stty_state & STTY_require_set_attr) { |
1650 | #if !ENABLE_PLATFORM_MINGW32 | ||
1517 | struct termios new_mode; | 1651 | struct termios new_mode; |
1652 | #else | ||
1653 | if (mode.c_lflag & ECHO) | ||
1654 | mode.w_mode |= ENABLE_ECHO_INPUT; | ||
1655 | else | ||
1656 | mode.w_mode &= ~ENABLE_ECHO_INPUT; | ||
1657 | #endif | ||
1518 | 1658 | ||
1519 | if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode)) | 1659 | if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode)) |
1520 | perror_on_device_and_die("%s"); | 1660 | perror_on_device_and_die("%s"); |
1521 | 1661 | ||
1662 | #if !ENABLE_PLATFORM_MINGW32 | ||
1522 | /* POSIX (according to Zlotnick's book) tcsetattr returns zero if | 1663 | /* POSIX (according to Zlotnick's book) tcsetattr returns zero if |
1523 | it performs *any* of the requested operations. This means it | 1664 | it performs *any* of the requested operations. This means it |
1524 | can report 'success' when it has actually failed to perform | 1665 | can report 'success' when it has actually failed to perform |
@@ -1554,6 +1695,7 @@ int stty_main(int argc UNUSED_PARAM, char **argv) | |||
1554 | #endif | 1695 | #endif |
1555 | perror_on_device_and_die("%s: cannot perform all requested operations"); | 1696 | perror_on_device_and_die("%s: cannot perform all requested operations"); |
1556 | } | 1697 | } |
1698 | #endif | ||
1557 | } | 1699 | } |
1558 | 1700 | ||
1559 | return EXIT_SUCCESS; | 1701 | return EXIT_SUCCESS; |
diff --git a/coreutils/truncate.c b/coreutils/truncate.c index 8826e6b4c..87a47bb09 100644 --- a/coreutils/truncate.c +++ b/coreutils/truncate.c | |||
@@ -73,6 +73,12 @@ int truncate_main(int argc UNUSED_PARAM, char **argv) | |||
73 | * do not report error, exitcode is also 0. | 73 | * do not report error, exitcode is also 0. |
74 | */ | 74 | */ |
75 | } else { | 75 | } else { |
76 | #if ENABLE_PLATFORM_MINGW32 | ||
77 | struct stat st; | ||
78 | |||
79 | if (fstat(fd, &st) == 0 && size > st.st_size) | ||
80 | make_sparse(fd, st.st_size, size); | ||
81 | #endif | ||
76 | if (ftruncate(fd, size) == -1) { | 82 | if (ftruncate(fd, size) == -1) { |
77 | bb_perror_msg("%s: truncate", *argv); | 83 | bb_perror_msg("%s: truncate", *argv); |
78 | ret = EXIT_FAILURE; | 84 | ret = EXIT_FAILURE; |
diff --git a/editors/diff.c b/editors/diff.c index b324feaa5..8911859cd 100644 --- a/editors/diff.c +++ b/editors/diff.c | |||
@@ -773,7 +773,7 @@ static int diffreg(char *file[2]) | |||
773 | fd = fd_tmp; | 773 | fd = fd_tmp; |
774 | xlseek(fd, 0, SEEK_SET); | 774 | xlseek(fd, 0, SEEK_SET); |
775 | } | 775 | } |
776 | fp[i] = fdopen(fd, "r"); | 776 | fp[i] = xfdopen_for_read(fd); |
777 | } | 777 | } |
778 | 778 | ||
779 | setup_common_bufsiz(); | 779 | setup_common_bufsiz(); |
diff --git a/editors/sed.c b/editors/sed.c index 107e664a0..204417108 100644 --- a/editors/sed.c +++ b/editors/sed.c | |||
@@ -257,7 +257,12 @@ static FILE *sed_xfopen_w(const char *fname) | |||
257 | 257 | ||
258 | static void cleanup_outname(void) | 258 | static void cleanup_outname(void) |
259 | { | 259 | { |
260 | if (G.outname) unlink(G.outname); | 260 | if (G.outname) { |
261 | #if ENABLE_PLATFORM_MINGW32 | ||
262 | fclose(G.nonstdout); | ||
263 | #endif | ||
264 | unlink(G.outname); | ||
265 | } | ||
261 | } | 266 | } |
262 | 267 | ||
263 | /* strcpy, replacing "\from" with 'to'. If to is NUL, replacing "\any" with 'any' */ | 268 | /* strcpy, replacing "\from" with 'to'. If to is NUL, replacing "\any" with 'any' */ |
diff --git a/findutils/xargs.c b/findutils/xargs.c index f0abf1a23..83af75521 100644 --- a/findutils/xargs.c +++ b/findutils/xargs.c | |||
@@ -846,11 +846,11 @@ int xargs_main(int argc UNUSED_PARAM, char **argv) | |||
846 | * arguments, but not if the command is a NOFORK applet. If the rules | 846 | * arguments, but not if the command is a NOFORK applet. If the rules |
847 | * to detect this situation change xargs_exec() above will also need | 847 | * to detect this situation change xargs_exec() above will also need |
848 | * to be updated. */ | 848 | * to be updated. */ |
849 | # if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL | 849 | # if ENABLE_FEATURE_PREFER_APPLETS && (NUM_APPLETS > 1) |
850 | # if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL | ||
850 | if (G.max_procs == 1) | 851 | if (G.max_procs == 1) |
851 | # endif | 852 | # endif |
852 | { | 853 | { |
853 | # if ENABLE_FEATURE_PREFER_APPLETS && (NUM_APPLETS > 1) | ||
854 | int applet = find_applet_by_name(argv[0]); | 854 | int applet = find_applet_by_name(argv[0]); |
855 | if (applet >= 0 && APPLET_IS_NOFORK(applet)) { | 855 | if (applet >= 0 && APPLET_IS_NOFORK(applet)) { |
856 | quote = FALSE; | 856 | quote = FALSE; |
diff --git a/include/libbb.h b/include/libbb.h index bc1453e12..8dc4e4992 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -281,6 +281,26 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN | |||
281 | # endif | 281 | # endif |
282 | #endif | 282 | #endif |
283 | 283 | ||
284 | #if ENABLE_FEATURE_TLS_SCHANNEL || ENABLE_FEATURE_USE_CNG_API | ||
285 | # define SECURITY_WIN32 | ||
286 | # include <windows.h> | ||
287 | # include <security.h> | ||
288 | #endif | ||
289 | |||
290 | #if ENABLE_FEATURE_USE_CNG_API | ||
291 | # include <bcrypt.h> | ||
292 | |||
293 | // these work on Windows >= 10 | ||
294 | # define BCRYPT_HMAC_SHA1_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x000000a1) | ||
295 | # define BCRYPT_HMAC_SHA256_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x000000b1) | ||
296 | # define sha1_begin_hmac BCRYPT_HMAC_SHA1_ALG_HANDLE | ||
297 | # define sha256_begin_hmac BCRYPT_HMAC_SHA256_ALG_HANDLE | ||
298 | #else | ||
299 | # define sha1_begin_hmac sha1_begin | ||
300 | # define sha256_begin_hmac sha256_begin | ||
301 | # define hmac_uninit(...) ((void)0) | ||
302 | #endif | ||
303 | |||
284 | /* Tested to work correctly with all int types (IIRC :]) */ | 304 | /* Tested to work correctly with all int types (IIRC :]) */ |
285 | #define MAXINT(T) (T)( \ | 305 | #define MAXINT(T) (T)( \ |
286 | ((T)-1) > 0 \ | 306 | ((T)-1) > 0 \ |
@@ -899,7 +919,36 @@ struct hostent *xgethostbyname(const char *name) FAST_FUNC; | |||
899 | // Also mount.c and inetd.c are using gethostbyname(), | 919 | // Also mount.c and inetd.c are using gethostbyname(), |
900 | // + inet_common.c has additional IPv4-only stuff | 920 | // + inet_common.c has additional IPv4-only stuff |
901 | 921 | ||
922 | #if defined CONFIG_FEATURE_TLS_SCHANNEL | ||
923 | typedef struct tls_state { | ||
924 | int ofd; | ||
925 | int ifd; | ||
926 | |||
927 | // handles | ||
928 | CredHandle cred_handle; | ||
929 | CtxtHandle ctx_handle; | ||
930 | |||
931 | // buffers | ||
932 | char in_buffer[16384 + 256]; // input buffer (to read from server) | ||
933 | unsigned long in_buffer_size; // amount of data currently in input buffer | ||
934 | |||
935 | char *out_buffer; // output buffer (for decrypted data), this is essentially the same as input buffer as data is decrypted in place | ||
936 | unsigned long out_buffer_size; // amount of data currently in output buffer | ||
937 | unsigned long out_buffer_used; // amount of extra data currently in output buffer | ||
938 | |||
939 | // data | ||
940 | char *hostname; | ||
941 | SecPkgContext_StreamSizes stream_sizes; | ||
942 | |||
943 | // booleans | ||
902 | 944 | ||
945 | // context initialized | ||
946 | int initialized; | ||
947 | |||
948 | // closed by remote peer | ||
949 | int closed; | ||
950 | } tls_state_t; | ||
951 | #else | ||
903 | struct tls_aes { | 952 | struct tls_aes { |
904 | uint32_t key[60]; | 953 | uint32_t key[60]; |
905 | unsigned rounds; | 954 | unsigned rounds; |
@@ -956,12 +1005,14 @@ typedef struct tls_state { | |||
956 | struct tls_aes aes_decrypt; | 1005 | struct tls_aes aes_decrypt; |
957 | uint8_t H[16]; //used by AES_GCM | 1006 | uint8_t H[16]; //used by AES_GCM |
958 | } tls_state_t; | 1007 | } tls_state_t; |
1008 | #endif | ||
959 | 1009 | ||
960 | static inline tls_state_t *new_tls_state(void) | 1010 | static inline tls_state_t *new_tls_state(void) |
961 | { | 1011 | { |
962 | tls_state_t *tls = xzalloc(sizeof(*tls)); | 1012 | tls_state_t *tls = xzalloc(sizeof(*tls)); |
963 | return tls; | 1013 | return tls; |
964 | } | 1014 | } |
1015 | |||
965 | void tls_handshake(tls_state_t *tls, const char *sni) FAST_FUNC; | 1016 | void tls_handshake(tls_state_t *tls, const char *sni) FAST_FUNC; |
966 | #define TLSLOOP_EXIT_ON_LOCAL_EOF (1 << 0) | 1017 | #define TLSLOOP_EXIT_ON_LOCAL_EOF (1 << 0) |
967 | void tls_run_copy_loop(tls_state_t *tls, unsigned flags) FAST_FUNC; | 1018 | void tls_run_copy_loop(tls_state_t *tls, unsigned flags) FAST_FUNC; |
@@ -1071,13 +1122,13 @@ unsigned bb_clk_tck(void) FAST_FUNC; | |||
1071 | 1122 | ||
1072 | #if SEAMLESS_COMPRESSION | 1123 | #if SEAMLESS_COMPRESSION |
1073 | /* Autodetects gzip/bzip2 formats. fd may be in the middle of the file! */ | 1124 | /* Autodetects gzip/bzip2 formats. fd may be in the middle of the file! */ |
1074 | int setup_unzip_on_fd(int fd, int fail_if_not_compressed) FAST_FUNC; | 1125 | int setup_unzip_on_fd(int fd, int die_if_not_compressed) FAST_FUNC; |
1075 | /* Autodetects .gz etc */ | 1126 | /* Autodetects .gz etc */ |
1076 | extern int open_zipped(const char *fname, int fail_if_not_compressed) FAST_FUNC; | 1127 | extern int open_zipped(const char *fname, int die_if_not_compressed) FAST_FUNC; |
1077 | extern void *xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; | 1128 | extern void *xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; |
1078 | #else | 1129 | #else |
1079 | # define setup_unzip_on_fd(...) (0) | 1130 | # define setup_unzip_on_fd(...) (0) |
1080 | # define open_zipped(fname, fail_if_not_compressed) open((fname), O_RDONLY); | 1131 | # define open_zipped(fname, die_if_not_compressed) open((fname), O_RDONLY); |
1081 | # define xmalloc_open_zipped_read_close(fname, maxsz_p) xmalloc_open_read_close((fname), (maxsz_p)) | 1132 | # define xmalloc_open_zipped_read_close(fname, maxsz_p) xmalloc_open_read_close((fname), (maxsz_p)) |
1082 | #endif | 1133 | #endif |
1083 | /* lzma has no signature, need a little helper. NB: exist only for ENABLE_FEATURE_SEAMLESS_LZMA=y */ | 1134 | /* lzma has no signature, need a little helper. NB: exist only for ENABLE_FEATURE_SEAMLESS_LZMA=y */ |
@@ -1173,6 +1224,16 @@ char *bin2hex(char *dst, const char *src, int count) FAST_FUNC; | |||
1173 | /* Reverse */ | 1224 | /* Reverse */ |
1174 | char* hex2bin(char *dst, const char *src, int count) FAST_FUNC; | 1225 | char* hex2bin(char *dst, const char *src, int count) FAST_FUNC; |
1175 | 1226 | ||
1227 | void FAST_FUNC xorbuf_3(void *dst, const void *src1, const void *src2, unsigned count); | ||
1228 | void FAST_FUNC xorbuf(void* buf, const void* mask, unsigned count); | ||
1229 | void FAST_FUNC xorbuf16_aligned_long(void* buf, const void* mask); | ||
1230 | void FAST_FUNC xorbuf64_3_aligned64(void *dst, const void *src1, const void *src2); | ||
1231 | #if BB_UNALIGNED_MEMACCESS_OK | ||
1232 | # define xorbuf16(buf,mask) xorbuf16_aligned_long(buf,mask) | ||
1233 | #else | ||
1234 | void FAST_FUNC xorbuf16(void* buf, const void* mask); | ||
1235 | #endif | ||
1236 | |||
1176 | /* Generate a UUID */ | 1237 | /* Generate a UUID */ |
1177 | void generate_uuid(uint8_t *buf) FAST_FUNC; | 1238 | void generate_uuid(uint8_t *buf) FAST_FUNC; |
1178 | 1239 | ||
@@ -1887,18 +1948,25 @@ extern char *pw_encrypt(const char *clear, const char *salt, int cleanup) FAST_F | |||
1887 | extern int obscure(const char *old, const char *newval, const struct passwd *pwdp) FAST_FUNC; | 1948 | extern int obscure(const char *old, const char *newval, const struct passwd *pwdp) FAST_FUNC; |
1888 | /* | 1949 | /* |
1889 | * rnd is additional random input. New one is returned. | 1950 | * rnd is additional random input. New one is returned. |
1890 | * Useful if you call crypt_make_salt many times in a row: | 1951 | * Useful if you call crypt_make_rand64encoded many times in a row: |
1891 | * rnd = crypt_make_salt(buf1, 4, 0); | 1952 | * rnd = crypt_make_rand64encoded(buf1, 4, 0); |
1892 | * rnd = crypt_make_salt(buf2, 4, rnd); | 1953 | * rnd = crypt_make_rand64encoded(buf2, 4, rnd); |
1893 | * rnd = crypt_make_salt(buf3, 4, rnd); | 1954 | * rnd = crypt_make_rand64encoded(buf3, 4, rnd); |
1894 | * (otherwise we risk having same salt generated) | 1955 | * (otherwise we risk having same salt generated) |
1895 | */ | 1956 | */ |
1896 | extern int crypt_make_salt(char *p, int cnt /*, int rnd*/) FAST_FUNC; | 1957 | extern int crypt_make_rand64encoded(char *p, int cnt /*, int rnd*/) FAST_FUNC; |
1897 | /* "$N$" + sha_salt_16_bytes + NUL */ | 1958 | /* Size of char salt[] to hold randomly-generated salt string |
1898 | #define MAX_PW_SALT_LEN (3 + 16 + 1) | 1959 | * sha256/512: |
1960 | * "$5$" ["rounds=999999999$"] "<sha_salt_16_chars><NUL>" | ||
1961 | * "$6$" ["rounds=999999999$"] "<sha_salt_16_chars><NUL>" | ||
1962 | * #define MAX_PW_SALT_LEN (3 + sizeof("rounds=999999999$")-1 + 16 + 1) | ||
1963 | * yescrypt: | ||
1964 | * "$y$" <up to 8 params of up to 6 chars each> "$" <up to 86 chars salt><NUL> | ||
1965 | * (86 chars are ascii64-encoded 64 binary bytes) | ||
1966 | */ | ||
1967 | #define MAX_PW_SALT_LEN (3 + 8*6 + 1 + 86 + 1) | ||
1899 | extern char* crypt_make_pw_salt(char p[MAX_PW_SALT_LEN], const char *algo) FAST_FUNC; | 1968 | extern char* crypt_make_pw_salt(char p[MAX_PW_SALT_LEN], const char *algo) FAST_FUNC; |
1900 | 1969 | ||
1901 | |||
1902 | /* Returns number of lines changed, or -1 on error */ | 1970 | /* Returns number of lines changed, or -1 on error */ |
1903 | #if !(ENABLE_FEATURE_ADDUSER_TO_GROUP || ENABLE_FEATURE_DEL_USER_FROM_GROUP) | 1971 | #if !(ENABLE_FEATURE_ADDUSER_TO_GROUP || ENABLE_FEATURE_DEL_USER_FROM_GROUP) |
1904 | #define update_passwd(filename, username, data, member) \ | 1972 | #define update_passwd(filename, username, data, member) \ |
@@ -2041,6 +2109,10 @@ int64_t windows_read_key(int fd, char *buffer, int timeout) FAST_FUNC; | |||
2041 | int64_t safe_read_key(int fd, char *buffer, int timeout) FAST_FUNC; | 2109 | int64_t safe_read_key(int fd, char *buffer, int timeout) FAST_FUNC; |
2042 | void read_key_ungets(char *buffer, const char *str, unsigned len) FAST_FUNC; | 2110 | void read_key_ungets(char *buffer, const char *str, unsigned len) FAST_FUNC; |
2043 | 2111 | ||
2112 | int check_got_signal_and_poll(struct pollfd pfd[1], int timeout) FAST_FUNC; | ||
2113 | #if ENABLE_PLATFORM_MINGW32 | ||
2114 | # define check_got_signal_and_poll(p, t) poll(p, 1, t) | ||
2115 | #endif | ||
2044 | 2116 | ||
2045 | #if ENABLE_FEATURE_EDITING | 2117 | #if ENABLE_FEATURE_EDITING |
2046 | /* It's NOT just ENABLEd or disabled. It's a number: */ | 2118 | /* It's NOT just ENABLEd or disabled. It's a number: */ |
@@ -2087,7 +2159,7 @@ typedef struct line_input_t { | |||
2087 | # if MAX_HISTORY | 2159 | # if MAX_HISTORY |
2088 | int cnt_history; | 2160 | int cnt_history; |
2089 | int cur_history; | 2161 | int cur_history; |
2090 | int max_history; /* must never be <= 0 */ | 2162 | int max_history; /* must never be < 0 */ |
2091 | # if ENABLE_FEATURE_EDITING_SAVEHISTORY | 2163 | # if ENABLE_FEATURE_EDITING_SAVEHISTORY |
2092 | /* meaning of this field depends on FEATURE_EDITING_SAVE_ON_EXIT: | 2164 | /* meaning of this field depends on FEATURE_EDITING_SAVE_ON_EXIT: |
2093 | * if !FEATURE_EDITING_SAVE_ON_EXIT: "how many lines are | 2165 | * if !FEATURE_EDITING_SAVE_ON_EXIT: "how many lines are |
@@ -2294,6 +2366,51 @@ char *decode_base64(char *dst, const char **pp_src) FAST_FUNC; | |||
2294 | char *decode_base32(char *dst, const char **pp_src) FAST_FUNC; | 2366 | char *decode_base32(char *dst, const char **pp_src) FAST_FUNC; |
2295 | void read_base64(FILE *src_stream, FILE *dst_stream, int flags) FAST_FUNC; | 2367 | void read_base64(FILE *src_stream, FILE *dst_stream, int flags) FAST_FUNC; |
2296 | 2368 | ||
2369 | int FAST_FUNC i2a64(int i); | ||
2370 | int FAST_FUNC a2i64(char c); | ||
2371 | char* FAST_FUNC num2str64_lsb_first(char *s, unsigned v, int n); | ||
2372 | |||
2373 | enum { | ||
2374 | /* how many bytes XYZ_end() fills */ | ||
2375 | MD5_OUTSIZE = 16, | ||
2376 | SHA1_OUTSIZE = 20, | ||
2377 | SHA256_OUTSIZE = 32, | ||
2378 | SHA512_OUTSIZE = 64, | ||
2379 | SHA3_OUTSIZE = 28, | ||
2380 | /* size of input block */ | ||
2381 | SHA2_INSIZE = 64, | ||
2382 | }; | ||
2383 | |||
2384 | #if defined CONFIG_FEATURE_USE_CNG_API | ||
2385 | struct bcrypt_hash_ctx_t { | ||
2386 | void *handle; | ||
2387 | void *hash_obj; | ||
2388 | unsigned int output_size; | ||
2389 | }; | ||
2390 | typedef struct bcrypt_hash_ctx_t md5_ctx_t; | ||
2391 | typedef struct bcrypt_hash_ctx_t sha1_ctx_t; | ||
2392 | typedef struct bcrypt_hash_ctx_t sha256_ctx_t; | ||
2393 | typedef struct bcrypt_hash_ctx_t sha512_ctx_t; | ||
2394 | typedef struct sha3_ctx_t { | ||
2395 | uint64_t state[25]; | ||
2396 | unsigned bytes_queued; | ||
2397 | unsigned input_block_bytes; | ||
2398 | } sha3_ctx_t; | ||
2399 | void md5_begin(struct bcrypt_hash_ctx_t *ctx) FAST_FUNC; | ||
2400 | void sha1_begin(struct bcrypt_hash_ctx_t *ctx) FAST_FUNC; | ||
2401 | void sha256_begin(struct bcrypt_hash_ctx_t *ctx) FAST_FUNC; | ||
2402 | void sha512_begin(struct bcrypt_hash_ctx_t *ctx) FAST_FUNC; | ||
2403 | void generic_hash(struct bcrypt_hash_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC; | ||
2404 | unsigned generic_end(struct bcrypt_hash_ctx_t *ctx, void *resbuf) FAST_FUNC; | ||
2405 | # define md5_hash generic_hash | ||
2406 | # define sha1_hash generic_hash | ||
2407 | # define sha256_hash generic_hash | ||
2408 | # define sha512_hash generic_hash | ||
2409 | # define md5_end generic_end | ||
2410 | # define sha1_end generic_end | ||
2411 | # define sha256_end generic_end | ||
2412 | # define sha512_end generic_end | ||
2413 | #else | ||
2297 | typedef struct md5_ctx_t { | 2414 | typedef struct md5_ctx_t { |
2298 | uint8_t wbuffer[64]; /* always correctly aligned for uint64_t */ | 2415 | uint8_t wbuffer[64]; /* always correctly aligned for uint64_t */ |
2299 | void (*process_block)(struct md5_ctx_t*) FAST_FUNC; | 2416 | void (*process_block)(struct md5_ctx_t*) FAST_FUNC; |
@@ -2324,20 +2441,66 @@ void sha256_begin(sha256_ctx_t *ctx) FAST_FUNC; | |||
2324 | void sha512_begin(sha512_ctx_t *ctx) FAST_FUNC; | 2441 | void sha512_begin(sha512_ctx_t *ctx) FAST_FUNC; |
2325 | void sha512_hash(sha512_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC; | 2442 | void sha512_hash(sha512_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC; |
2326 | unsigned sha512_end(sha512_ctx_t *ctx, void *resbuf) FAST_FUNC; | 2443 | unsigned sha512_end(sha512_ctx_t *ctx, void *resbuf) FAST_FUNC; |
2444 | #endif | ||
2327 | void sha3_begin(sha3_ctx_t *ctx) FAST_FUNC; | 2445 | void sha3_begin(sha3_ctx_t *ctx) FAST_FUNC; |
2328 | void sha3_hash(sha3_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC; | 2446 | void sha3_hash(sha3_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC; |
2329 | unsigned sha3_end(sha3_ctx_t *ctx, void *resbuf) FAST_FUNC; | 2447 | unsigned sha3_end(sha3_ctx_t *ctx, void *resbuf) FAST_FUNC; |
2448 | void FAST_FUNC sha256_block(const void *in, size_t len, uint8_t hash[32]); | ||
2330 | /* TLS benefits from knowing that sha1 and sha256 share these. Give them "agnostic" names too */ | 2449 | /* TLS benefits from knowing that sha1 and sha256 share these. Give them "agnostic" names too */ |
2450 | #if defined CONFIG_FEATURE_USE_CNG_API | ||
2451 | typedef struct bcrypt_hash_ctx_t md5sha_ctx_t; | ||
2452 | #define md5sha_hash generic_hash | ||
2453 | #define sha_end generic_end | ||
2454 | #else | ||
2331 | typedef struct md5_ctx_t md5sha_ctx_t; | 2455 | typedef struct md5_ctx_t md5sha_ctx_t; |
2332 | #define md5sha_hash md5_hash | 2456 | #define md5sha_hash md5_hash |
2333 | #define sha_end sha1_end | 2457 | #define sha_end sha1_end |
2334 | enum { | 2458 | #endif |
2335 | MD5_OUTSIZE = 16, | 2459 | |
2336 | SHA1_OUTSIZE = 20, | 2460 | /* RFC 2104 HMAC (hash-based message authentication code) */ |
2337 | SHA256_OUTSIZE = 32, | 2461 | #if !ENABLE_FEATURE_USE_CNG_API |
2338 | SHA512_OUTSIZE = 64, | 2462 | typedef struct hmac_ctx { |
2339 | SHA3_OUTSIZE = 28, | 2463 | md5sha_ctx_t hashed_key_xor_ipad; |
2340 | }; | 2464 | md5sha_ctx_t hashed_key_xor_opad; |
2465 | } hmac_ctx_t; | ||
2466 | #else | ||
2467 | typedef struct bcrypt_hash_ctx_t hmac_ctx_t; | ||
2468 | #endif | ||
2469 | #define HMAC_ONLY_SHA256 (!ENABLE_FEATURE_TLS_SHA1) | ||
2470 | typedef void md5sha_begin_func(md5sha_ctx_t *ctx) FAST_FUNC; | ||
2471 | #if !ENABLE_FEATURE_USE_CNG_API | ||
2472 | #if HMAC_ONLY_SHA256 | ||
2473 | #define hmac_begin(ctx,key,key_size,begin) \ | ||
2474 | hmac_begin(ctx,key,key_size) | ||
2475 | #endif | ||
2476 | void FAST_FUNC hmac_begin(hmac_ctx_t *ctx, const uint8_t *key, unsigned key_size, md5sha_begin_func *begin); | ||
2477 | static ALWAYS_INLINE void hmac_hash(hmac_ctx_t *ctx, const void *in, size_t len) | ||
2478 | { | ||
2479 | md5sha_hash(&ctx->hashed_key_xor_ipad, in, len); | ||
2480 | } | ||
2481 | #else | ||
2482 | # if HMAC_ONLY_SHA256 | ||
2483 | # define hmac_begin(pre,key,key_size,begin) \ | ||
2484 | _hmac_begin(pre, key, key_size, sha256_begin_hmac) | ||
2485 | # else | ||
2486 | # define hmac_begin _hmac_begin | ||
2487 | # endif | ||
2488 | void _hmac_begin(hmac_ctx_t *pre, uint8_t *key, unsigned key_size, | ||
2489 | BCRYPT_ALG_HANDLE alg_handle); | ||
2490 | void hmac_uninit(hmac_ctx_t *pre); | ||
2491 | #endif | ||
2492 | unsigned FAST_FUNC hmac_end(hmac_ctx_t *ctx, uint8_t *out); | ||
2493 | #if HMAC_ONLY_SHA256 | ||
2494 | #define hmac_block(key,key_size,begin,in,sz,out) \ | ||
2495 | hmac_block(key,key_size,in,sz,out) | ||
2496 | #endif | ||
2497 | unsigned FAST_FUNC hmac_block(const uint8_t *key, unsigned key_size, | ||
2498 | md5sha_begin_func *begin, | ||
2499 | const void *in, unsigned sz, | ||
2500 | uint8_t *out); | ||
2501 | /* HMAC helpers for TLS: */ | ||
2502 | void FAST_FUNC hmac_hash_v(hmac_ctx_t *ctx, va_list va); | ||
2503 | unsigned hmac_peek_hash(hmac_ctx_t *ctx, uint8_t *out, ...); | ||
2341 | 2504 | ||
2342 | extern uint32_t *global_crc32_table; | 2505 | extern uint32_t *global_crc32_table; |
2343 | uint32_t *crc32_filltable(uint32_t *tbl256, int endian) FAST_FUNC; | 2506 | uint32_t *crc32_filltable(uint32_t *tbl256, int endian) FAST_FUNC; |
@@ -2473,31 +2636,10 @@ extern struct globals *BB_GLOBAL_CONST ptr_to_globals; | |||
2473 | #define barrier() asm volatile ("":::"memory") | 2636 | #define barrier() asm volatile ("":::"memory") |
2474 | 2637 | ||
2475 | #if defined(__clang_major__) && __clang_major__ >= 9 | 2638 | #if defined(__clang_major__) && __clang_major__ >= 9 |
2476 | /* Clang/llvm drops assignment to "constant" storage. Silently. | 2639 | /* {ASSIGN,XZALLOC}_CONST_PTR() are out-of-line functions |
2477 | * Needs serious convincing to not eliminate the store. | 2640 | * to prevent clang from reading pointer before it is assigned. |
2478 | */ | ||
2479 | static ALWAYS_INLINE void* not_const_pp(const void *p) | ||
2480 | { | ||
2481 | void *pp; | ||
2482 | asm volatile ( | ||
2483 | "# forget that p points to const" | ||
2484 | : /*outputs*/ "=r" (pp) | ||
2485 | : /*inputs*/ "0" (p) | ||
2486 | ); | ||
2487 | return pp; | ||
2488 | } | ||
2489 | # if !ENABLE_PLATFORM_MINGW32 | ||
2490 | # define ASSIGN_CONST_PTR(pptr, v) do { \ | ||
2491 | *(void**)not_const_pp(pptr) = (void*)(v); \ | ||
2492 | barrier(); \ | ||
2493 | } while (0) | ||
2494 | #else | ||
2495 | /* On Windows it seems necessary for this to be a function too. */ | ||
2496 | void ASSIGN_CONST_PTR(const void *pptr, const void *ptr) FAST_FUNC; | ||
2497 | #endif | ||
2498 | /* XZALLOC_CONST_PTR() is an out-of-line function to prevent | ||
2499 | * clang from reading pointer before it is assigned. | ||
2500 | */ | 2641 | */ |
2642 | void ASSIGN_CONST_PTR(const void *pptr, void *v) FAST_FUNC; | ||
2501 | void XZALLOC_CONST_PTR(const void *pptr, size_t size) FAST_FUNC; | 2643 | void XZALLOC_CONST_PTR(const void *pptr, size_t size) FAST_FUNC; |
2502 | #else | 2644 | #else |
2503 | # define ASSIGN_CONST_PTR(pptr, v) do { \ | 2645 | # define ASSIGN_CONST_PTR(pptr, v) do { \ |
diff --git a/include/mingw.h b/include/mingw.h index c41c0f91e..276e40659 100644 --- a/include/mingw.h +++ b/include/mingw.h | |||
@@ -259,6 +259,7 @@ int ffs(int i); | |||
259 | */ | 259 | */ |
260 | 260 | ||
261 | #define TIOCGWINSZ 0x5413 | 261 | #define TIOCGWINSZ 0x5413 |
262 | #define TIOCSWINSZ 0x5414 | ||
262 | 263 | ||
263 | int ioctl(int fd, int code, ...); | 264 | int ioctl(int fd, int code, ...); |
264 | 265 | ||
@@ -669,3 +670,5 @@ enum { | |||
669 | }; | 670 | }; |
670 | int elevation_state(void); | 671 | int elevation_state(void); |
671 | void set_interp(int i) FAST_FUNC; | 672 | void set_interp(int i) FAST_FUNC; |
673 | int mingw_shell_execute(SHELLEXECUTEINFO *info); | ||
674 | void mingw_die_if_error(NTSTATUS status, const char *function_name); | ||
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..797e0a0eb 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 = waitpid(-1, &status, WNOHANG); |
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 61b4601d6..eff327c2a 100644 --- a/libbb/Config.src +++ b/libbb/Config.src | |||
@@ -37,6 +37,14 @@ config PASSWORD_MINLEN | |||
37 | help | 37 | help |
38 | Minimum allowable password length. | 38 | Minimum allowable password length. |
39 | 39 | ||
40 | config FEATURE_USE_CNG_API | ||
41 | bool "Use the Windows CNG API for checksums (Windows 10+ only)" | ||
42 | default n | ||
43 | depends on PLATFORM_MINGW32 | ||
44 | help | ||
45 | Use the in-built Windows CNG API for checksums. | ||
46 | This reduces code size, but is only supported on Windows 10+. | ||
47 | |||
40 | config MD5_SMALL | 48 | config MD5_SMALL |
41 | int "MD5: Trade bytes for speed (0:fast, 3:slow)" | 49 | int "MD5: Trade bytes for speed (0:fast, 3:slow)" |
42 | default 1 # all "fast or small" options default to small | 50 | default 1 # all "fast or small" options default to small |
@@ -67,6 +75,7 @@ config SHA1_SMALL | |||
67 | config SHA1_HWACCEL | 75 | config SHA1_HWACCEL |
68 | bool "SHA1: Use hardware accelerated instructions if possible" | 76 | bool "SHA1: Use hardware accelerated instructions if possible" |
69 | default y | 77 | default y |
78 | depends on !FEATURE_USE_CNG_API | ||
70 | help | 79 | help |
71 | On x86, this adds ~590 bytes of code. Throughput | 80 | On x86, this adds ~590 bytes of code. Throughput |
72 | is about twice as fast as fully-unrolled generic code. | 81 | is about twice as fast as fully-unrolled generic code. |
@@ -74,6 +83,7 @@ config SHA1_HWACCEL | |||
74 | config SHA256_HWACCEL | 83 | config SHA256_HWACCEL |
75 | bool "SHA256: Use hardware accelerated instructions if possible" | 84 | bool "SHA256: Use hardware accelerated instructions if possible" |
76 | default y | 85 | default y |
86 | depends on !FEATURE_USE_CNG_API | ||
77 | help | 87 | help |
78 | On x86, this adds ~1k bytes of code. | 88 | On x86, this adds ~1k bytes of code. |
79 | 89 | ||
@@ -182,8 +192,8 @@ config FEATURE_EDITING_VI | |||
182 | config FEATURE_EDITING_HISTORY | 192 | config FEATURE_EDITING_HISTORY |
183 | int "History size" | 193 | int "History size" |
184 | # Don't allow way too big values here, code uses fixed "char *history[N]" struct member | 194 | # Don't allow way too big values here, code uses fixed "char *history[N]" struct member |
185 | range 0 9999 | 195 | range 0 2000 |
186 | default 255 | 196 | default 200 |
187 | depends on FEATURE_EDITING | 197 | depends on FEATURE_EDITING |
188 | help | 198 | help |
189 | Specify command history size (0 - disable). | 199 | Specify command history size (0 - disable). |
diff --git a/libbb/appletlib.c b/libbb/appletlib.c index d6e042775..b1064d10a 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c | |||
@@ -933,7 +933,7 @@ int busybox_main(int argc UNUSED_PARAM, char **argv) | |||
933 | full_write1_str(" multi-call binary.\n"); /* reuse */ | 933 | full_write1_str(" multi-call binary.\n"); /* reuse */ |
934 | #endif | 934 | #endif |
935 | full_write1_str( | 935 | full_write1_str( |
936 | "BusyBox is copyrighted by many authors between 1998-2024.\n" | 936 | "BusyBox is copyrighted by many authors between 1998-2025.\n" |
937 | "Licensed under GPLv2. See source distribution for detailed\n" | 937 | "Licensed under GPLv2. See source distribution for detailed\n" |
938 | "copyright notices.\n" | 938 | "copyright notices.\n" |
939 | "\n" | 939 | "\n" |
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/const_hack.c b/libbb/const_hack.c index 75163fede..1d175481b 100644 --- a/libbb/const_hack.c +++ b/libbb/const_hack.c | |||
@@ -9,18 +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 | void FAST_FUNC XZALLOC_CONST_PTR(const void *pptr, size_t size) | 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) | ||
13 | { | 16 | { |
14 | ASSIGN_CONST_PTR(pptr, xzalloc(size)); | 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; | ||
15 | } | 24 | } |
16 | 25 | void FAST_FUNC ASSIGN_CONST_PTR(const void *pptr, void *v) | |
17 | # if ENABLE_PLATFORM_MINGW32 | 26 | { |
18 | void FAST_FUNC ASSIGN_CONST_PTR(const void *pptr, const void *v) | 27 | *(void**)not_const_pp(pptr) = v; |
28 | barrier(); | ||
29 | } | ||
30 | void FAST_FUNC XZALLOC_CONST_PTR(const void *pptr, size_t size) | ||
19 | { | 31 | { |
20 | do { | 32 | *(void**)not_const_pp(pptr) = xzalloc(size); |
21 | *(void**)not_const_pp(pptr) = (void*)(v); | 33 | barrier(); |
22 | barrier(); | ||
23 | } while (0); | ||
24 | } | 34 | } |
25 | # endif | ||
26 | #endif | 35 | #endif |
diff --git a/libbb/dump.c b/libbb/dump.c index ffc46f6a7..b2abe85af 100644 --- a/libbb/dump.c +++ b/libbb/dump.c | |||
@@ -204,9 +204,11 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) | |||
204 | if (!e) | 204 | if (!e) |
205 | goto DO_BAD_CONV_CHAR; | 205 | goto DO_BAD_CONV_CHAR; |
206 | pr->flags = F_INT; | 206 | pr->flags = F_INT; |
207 | if (e > int_convs + 1) /* not d or i? */ | ||
208 | pr->flags = F_UINT; | ||
209 | byte_count_str = "\010\004\002\001"; | 207 | byte_count_str = "\010\004\002\001"; |
208 | if (e > int_convs + 1) { /* not d or i? */ | ||
209 | pr->flags = F_UINT; | ||
210 | byte_count_str++; | ||
211 | } | ||
210 | goto DO_BYTE_COUNT; | 212 | goto DO_BYTE_COUNT; |
211 | } else | 213 | } else |
212 | if (strchr(int_convs, *p1)) { /* %d etc */ | 214 | if (strchr(int_convs, *p1)) { /* %d etc */ |
@@ -701,15 +703,21 @@ static NOINLINE void display(priv_dumper_t* dumper) | |||
701 | conv_u(pr, bp); | 703 | conv_u(pr, bp); |
702 | break; | 704 | break; |
703 | case F_UINT: { | 705 | case F_UINT: { |
706 | union { | ||
707 | uint16_t uval16; | ||
708 | uint32_t uval32; | ||
709 | } u; | ||
704 | unsigned value = (unsigned char)*bp; | 710 | unsigned value = (unsigned char)*bp; |
705 | switch (pr->bcnt) { | 711 | switch (pr->bcnt) { |
706 | case 1: | 712 | case 1: |
707 | break; | 713 | break; |
708 | case 2: | 714 | case 2: |
709 | move_from_unaligned16(value, bp); | 715 | move_from_unaligned16(u.uval16, bp); |
716 | value = u.uval16; | ||
710 | break; | 717 | break; |
711 | case 4: | 718 | case 4: |
712 | move_from_unaligned32(value, bp); | 719 | move_from_unaligned32(u.uval32, bp); |
720 | value = u.uval32; | ||
713 | break; | 721 | break; |
714 | /* case 8: no users yet */ | 722 | /* case 8: no users yet */ |
715 | } | 723 | } |
diff --git a/libbb/getopt32.c b/libbb/getopt32.c index 56040e150..76d29d5eb 100644 --- a/libbb/getopt32.c +++ b/libbb/getopt32.c | |||
@@ -93,7 +93,7 @@ getopt32(char **argv, const char *applet_opts, ...) | |||
93 | 93 | ||
94 | "!" If the first character in the applet_opts string is a '!', | 94 | "!" If the first character in the applet_opts string is a '!', |
95 | report bad options, missing required options, | 95 | report bad options, missing required options, |
96 | inconsistent options with all-ones return value (instead of abort. | 96 | inconsistent options with all-ones return value instead of aborting. |
97 | 97 | ||
98 | "+" If the first character in the applet_opts string is a plus, | 98 | "+" If the first character in the applet_opts string is a plus, |
99 | then option processing will stop as soon as a non-option is | 99 | then option processing will stop as soon as a non-option is |
@@ -265,7 +265,7 @@ Special characters: | |||
265 | for "long options only" cases, such as tar --exclude=PATTERN, | 265 | for "long options only" cases, such as tar --exclude=PATTERN, |
266 | wget --header=HDR cases. | 266 | wget --header=HDR cases. |
267 | 267 | ||
268 | "a?b" A "?" between an option and a group of options means that | 268 | "a?bc" A "?" between an option and a group of options means that |
269 | at least one of them is required to occur if the first option | 269 | at least one of them is required to occur if the first option |
270 | occurs in preceding command line arguments. | 270 | occurs in preceding command line arguments. |
271 | 271 | ||
@@ -348,9 +348,6 @@ vgetopt32(char **argv, const char *applet_opts, const char *applet_long_options, | |||
348 | unsigned trigger; | 348 | unsigned trigger; |
349 | int min_arg = 0; | 349 | int min_arg = 0; |
350 | int max_arg = -1; | 350 | int max_arg = -1; |
351 | int spec_flgs = 0; | ||
352 | |||
353 | #define SHOW_USAGE_IF_ERROR 1 | ||
354 | 351 | ||
355 | on_off = complementary; | 352 | on_off = complementary; |
356 | memset(on_off, 0, sizeof(complementary)); | 353 | memset(on_off, 0, sizeof(complementary)); |
@@ -449,9 +446,7 @@ vgetopt32(char **argv, const char *applet_opts, const char *applet_long_options, | |||
449 | continue; | 446 | continue; |
450 | c = s[1]; | 447 | c = s[1]; |
451 | if (*s == '?') { | 448 | if (*s == '?') { |
452 | if (c < '0' || c > '9') { | 449 | if (c >= '0' && c <= '9') { |
453 | spec_flgs |= SHOW_USAGE_IF_ERROR; | ||
454 | } else { | ||
455 | max_arg = c - '0'; | 450 | max_arg = c - '0'; |
456 | s++; | 451 | s++; |
457 | } | 452 | } |
@@ -465,8 +460,10 @@ vgetopt32(char **argv, const char *applet_opts, const char *applet_long_options, | |||
465 | continue; | 460 | continue; |
466 | } | 461 | } |
467 | if (*s == '=') { | 462 | if (*s == '=') { |
468 | min_arg = max_arg = c - '0'; | 463 | if (c >= '0' && c <= '9') { |
469 | s++; | 464 | min_arg = max_arg = c - '0'; |
465 | s++; | ||
466 | } | ||
470 | continue; | 467 | continue; |
471 | } | 468 | } |
472 | for (on_off = complementary; on_off->opt_char; on_off++) | 469 | for (on_off = complementary; on_off->opt_char; on_off++) |
diff --git a/libbb/hash_hmac.c b/libbb/hash_hmac.c new file mode 100644 index 000000000..b3138029f --- /dev/null +++ b/libbb/hash_hmac.c | |||
@@ -0,0 +1,154 @@ | |||
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 | #if !ENABLE_FEATURE_USE_CNG_API | ||
22 | void FAST_FUNC hmac_begin(hmac_ctx_t *ctx, const uint8_t *key, unsigned key_size, md5sha_begin_func *begin) | ||
23 | { | ||
24 | #if HMAC_ONLY_SHA256 | ||
25 | #define begin sha256_begin | ||
26 | #endif | ||
27 | uint8_t key_xor_ipad[SHA2_INSIZE]; | ||
28 | uint8_t key_xor_opad[SHA2_INSIZE]; | ||
29 | unsigned i; | ||
30 | |||
31 | // "The authentication key can be of any length up to INSIZE, the | ||
32 | // block length of the hash function. Applications that use keys longer | ||
33 | // than INSIZE bytes will first hash the key using H and then use the | ||
34 | // resultant OUTSIZE byte string as the actual key to HMAC." | ||
35 | if (key_size > SHA2_INSIZE) { | ||
36 | uint8_t tempkey[SHA1_OUTSIZE < SHA256_OUTSIZE ? SHA256_OUTSIZE : SHA1_OUTSIZE]; | ||
37 | /* use ctx->hashed_key_xor_ipad as scratch ctx */ | ||
38 | begin(&ctx->hashed_key_xor_ipad); | ||
39 | md5sha_hash(&ctx->hashed_key_xor_ipad, key, key_size); | ||
40 | key_size = sha_end(&ctx->hashed_key_xor_ipad, tempkey); | ||
41 | key = tempkey; | ||
42 | } | ||
43 | |||
44 | for (i = 0; i < key_size; i++) { | ||
45 | key_xor_ipad[i] = key[i] ^ 0x36; | ||
46 | key_xor_opad[i] = key[i] ^ 0x5c; | ||
47 | } | ||
48 | for (; i < SHA2_INSIZE; i++) { | ||
49 | key_xor_ipad[i] = 0x36; | ||
50 | key_xor_opad[i] = 0x5c; | ||
51 | } | ||
52 | |||
53 | begin(&ctx->hashed_key_xor_ipad); | ||
54 | begin(&ctx->hashed_key_xor_opad); | ||
55 | md5sha_hash(&ctx->hashed_key_xor_ipad, key_xor_ipad, SHA2_INSIZE); | ||
56 | md5sha_hash(&ctx->hashed_key_xor_opad, key_xor_opad, SHA2_INSIZE); | ||
57 | } | ||
58 | #undef begin | ||
59 | |||
60 | unsigned FAST_FUNC hmac_end(hmac_ctx_t *ctx, uint8_t *out) | ||
61 | { | ||
62 | unsigned len = sha_end(&ctx->hashed_key_xor_ipad, out); | ||
63 | /* out = H((key XOR opad) + out) */ | ||
64 | md5sha_hash(&ctx->hashed_key_xor_opad, out, len); | ||
65 | return sha_end(&ctx->hashed_key_xor_opad, out); | ||
66 | } | ||
67 | |||
68 | unsigned FAST_FUNC hmac_block(const uint8_t *key, unsigned key_size, md5sha_begin_func *begin, const void *in, unsigned sz, uint8_t *out) | ||
69 | { | ||
70 | hmac_ctx_t ctx; | ||
71 | hmac_begin(&ctx, key, key_size, begin); | ||
72 | hmac_hash(&ctx, in, sz); | ||
73 | return hmac_end(&ctx, out); | ||
74 | } | ||
75 | |||
76 | /* TLS helpers */ | ||
77 | |||
78 | void FAST_FUNC hmac_hash_v( | ||
79 | hmac_ctx_t *ctx, | ||
80 | va_list va) | ||
81 | { | ||
82 | uint8_t *in; | ||
83 | |||
84 | /* ctx->hashed_key_xor_ipad contains unclosed "H((key XOR ipad) +" state */ | ||
85 | /* ctx->hashed_key_xor_opad contains unclosed "H((key XOR opad) +" state */ | ||
86 | |||
87 | /* calculate out = H((key XOR ipad) + text) */ | ||
88 | while ((in = va_arg(va, uint8_t*)) != NULL) { | ||
89 | unsigned size = va_arg(va, unsigned); | ||
90 | md5sha_hash(&ctx->hashed_key_xor_ipad, in, size); | ||
91 | } | ||
92 | } | ||
93 | #else | ||
94 | void _hmac_begin(hmac_ctx_t *ctx, uint8_t *key, unsigned key_size, | ||
95 | BCRYPT_ALG_HANDLE alg_handle) { | ||
96 | DWORD hash_object_length = 0; | ||
97 | ULONG _unused; | ||
98 | NTSTATUS status; | ||
99 | |||
100 | status = BCryptGetProperty(alg_handle, BCRYPT_OBJECT_LENGTH, | ||
101 | (PUCHAR)&hash_object_length, sizeof(DWORD), &_unused, 0); | ||
102 | mingw_die_if_error(status, "BCryptGetProperty"); | ||
103 | status = BCryptGetProperty(alg_handle, BCRYPT_HASH_LENGTH, | ||
104 | (PUCHAR)&ctx->output_size, sizeof(DWORD), &_unused, 0); | ||
105 | mingw_die_if_error(status, "BCryptGetProperty"); | ||
106 | |||
107 | ctx->hash_obj = xmalloc(hash_object_length); | ||
108 | |||
109 | status = BCryptCreateHash(alg_handle, &ctx->handle, ctx->hash_obj, | ||
110 | hash_object_length, key, key_size, BCRYPT_HASH_REUSABLE_FLAG); | ||
111 | mingw_die_if_error(status, "BCryptCreateHash"); | ||
112 | } | ||
113 | |||
114 | unsigned FAST_FUNC hmac_end(hmac_ctx_t *ctx, uint8_t *out) | ||
115 | { | ||
116 | NTSTATUS status; | ||
117 | |||
118 | status = BCryptFinishHash(ctx->handle, out, ctx->output_size, 0); | ||
119 | mingw_die_if_error(status, "BCryptFinishHash"); | ||
120 | |||
121 | return ctx->output_size; | ||
122 | } | ||
123 | |||
124 | void FAST_FUNC hmac_hash_v(hmac_ctx_t *ctx, va_list va) | ||
125 | { | ||
126 | uint8_t *in; | ||
127 | |||
128 | while ((in = va_arg(va, uint8_t*)) != NULL) { | ||
129 | unsigned size = va_arg(va, unsigned); | ||
130 | BCryptHashData(ctx->handle, in, size, 0); | ||
131 | } | ||
132 | } | ||
133 | |||
134 | void hmac_uninit(hmac_ctx_t *ctx) { | ||
135 | BCryptDestroyHash(ctx->handle); | ||
136 | free(ctx->hash_obj); | ||
137 | } | ||
138 | #endif | ||
139 | |||
140 | /* Using HMAC state, make a copy of it (IOW: without affecting this state!) | ||
141 | * hash in the list of (ptr,size) blocks, and finish the HMAC to out[] buffer. | ||
142 | * This function is useful for TLS PRF. | ||
143 | */ | ||
144 | unsigned hmac_peek_hash(hmac_ctx_t *ctx, uint8_t *out, ...) | ||
145 | { | ||
146 | hmac_ctx_t tmpctx = *ctx; /* struct copy */ | ||
147 | va_list va; | ||
148 | |||
149 | va_start(va, out); | ||
150 | hmac_hash_v(&tmpctx, va); | ||
151 | va_end(va); | ||
152 | |||
153 | return hmac_end(&tmpctx, out); | ||
154 | } | ||
diff --git a/libbb/hash_md5_sha.c b/libbb/hash_md5_sha.c index 75a61c32c..22dd890bf 100644 --- a/libbb/hash_md5_sha.c +++ b/libbb/hash_md5_sha.c | |||
@@ -13,6 +13,82 @@ | |||
13 | 13 | ||
14 | #define NEED_SHA512 (ENABLE_SHA512SUM || ENABLE_USE_BB_CRYPT_SHA) | 14 | #define NEED_SHA512 (ENABLE_SHA512SUM || ENABLE_USE_BB_CRYPT_SHA) |
15 | 15 | ||
16 | #if ENABLE_FEATURE_USE_CNG_API | ||
17 | # include <windows.h> | ||
18 | # include <bcrypt.h> | ||
19 | |||
20 | // these work on Windows >= 10 | ||
21 | # define BCRYPT_MD5_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x00000021) | ||
22 | # define BCRYPT_SHA1_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x00000031) | ||
23 | # define BCRYPT_SHA256_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x00000041) | ||
24 | # define BCRYPT_SHA512_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x00000061) | ||
25 | |||
26 | /* Initialize structure containing state of computation. | ||
27 | * (RFC 1321, 3.3: Step 3) | ||
28 | */ | ||
29 | |||
30 | static void generic_init(struct bcrypt_hash_ctx_t *ctx, BCRYPT_ALG_HANDLE alg_handle) { | ||
31 | DWORD hash_object_length = 0; | ||
32 | ULONG _unused; | ||
33 | NTSTATUS status; | ||
34 | |||
35 | status = BCryptGetProperty(alg_handle, BCRYPT_OBJECT_LENGTH, (PUCHAR)&hash_object_length, sizeof(DWORD), &_unused, 0); | ||
36 | mingw_die_if_error(status, "BCryptGetProperty"); | ||
37 | status = BCryptGetProperty(alg_handle, BCRYPT_HASH_LENGTH, (PUCHAR)&ctx->output_size, sizeof(DWORD), &_unused, 0); | ||
38 | mingw_die_if_error(status, "BCryptGetProperty"); | ||
39 | |||
40 | |||
41 | ctx->hash_obj = xmalloc(hash_object_length); | ||
42 | |||
43 | status = BCryptCreateHash(alg_handle, &ctx->handle, ctx->hash_obj, hash_object_length, NULL, 0, 0); | ||
44 | mingw_die_if_error(status, "BCryptCreateHash"); | ||
45 | } | ||
46 | |||
47 | void FAST_FUNC md5_begin(md5_ctx_t *ctx) | ||
48 | { | ||
49 | generic_init(ctx, BCRYPT_MD5_ALG_HANDLE); | ||
50 | } | ||
51 | |||
52 | void FAST_FUNC sha1_begin(sha1_ctx_t *ctx) | ||
53 | { | ||
54 | generic_init(ctx, BCRYPT_SHA1_ALG_HANDLE); | ||
55 | } | ||
56 | |||
57 | /* Initialize structure containing state of computation. | ||
58 | (FIPS 180-2:5.3.2) */ | ||
59 | void FAST_FUNC sha256_begin(sha256_ctx_t *ctx) | ||
60 | { | ||
61 | generic_init(ctx, BCRYPT_SHA256_ALG_HANDLE); | ||
62 | } | ||
63 | |||
64 | #if NEED_SHA512 | ||
65 | /* Initialize structure containing state of computation. | ||
66 | (FIPS 180-2:5.3.3) */ | ||
67 | void FAST_FUNC sha512_begin(sha512_ctx_t *ctx) | ||
68 | { | ||
69 | generic_init(ctx, BCRYPT_SHA512_ALG_HANDLE); | ||
70 | } | ||
71 | #endif /* NEED_SHA512 */ | ||
72 | |||
73 | void FAST_FUNC generic_hash(struct bcrypt_hash_ctx_t *ctx, const void *buffer, size_t len) | ||
74 | { | ||
75 | /* | ||
76 | for perf, no error checking here | ||
77 | */ | ||
78 | /*NTSTATUS status = */ BCryptHashData(ctx->handle, (const PUCHAR)buffer, len, 0); | ||
79 | // mingw_die_if_error(status, "BCryptHashData"); | ||
80 | } | ||
81 | |||
82 | unsigned FAST_FUNC generic_end(struct bcrypt_hash_ctx_t *ctx, void *resbuf) | ||
83 | { | ||
84 | NTSTATUS status = BCryptFinishHash(ctx->handle, resbuf, ctx->output_size, 0); | ||
85 | mingw_die_if_error(status, "BCryptFinishHash"); | ||
86 | BCryptDestroyHash(ctx->handle); | ||
87 | free(ctx->hash_obj); | ||
88 | return ctx->output_size; | ||
89 | } | ||
90 | #endif /* !ENABLE_FEATURE_USE_CNG_API */ | ||
91 | |||
16 | #if ENABLE_SHA1_HWACCEL || ENABLE_SHA256_HWACCEL | 92 | #if ENABLE_SHA1_HWACCEL || ENABLE_SHA256_HWACCEL |
17 | # if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) | 93 | # if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) |
18 | static void cpuid_eax_ebx_ecx(unsigned *eax, unsigned *ebx, unsigned *ecx, unsigned *edx) | 94 | static void cpuid_eax_ebx_ecx(unsigned *eax, unsigned *ebx, unsigned *ecx, unsigned *edx) |
@@ -80,6 +156,7 @@ static ALWAYS_INLINE uint64_t rotl64(uint64_t x, unsigned n) | |||
80 | return (x << n) | (x >> (64 - n)); | 156 | return (x << n) | (x >> (64 - n)); |
81 | } | 157 | } |
82 | 158 | ||
159 | #if !ENABLE_FEATURE_USE_CNG_API | ||
83 | /* Process the remaining bytes in the buffer */ | 160 | /* Process the remaining bytes in the buffer */ |
84 | static void FAST_FUNC common64_end(md5_ctx_t *ctx, int swap_needed) | 161 | static void FAST_FUNC common64_end(md5_ctx_t *ctx, int swap_needed) |
85 | { | 162 | { |
@@ -1367,6 +1444,7 @@ unsigned FAST_FUNC sha512_end(sha512_ctx_t *ctx, void *resbuf) | |||
1367 | return sizeof(ctx->hash); | 1444 | return sizeof(ctx->hash); |
1368 | } | 1445 | } |
1369 | #endif /* NEED_SHA512 */ | 1446 | #endif /* NEED_SHA512 */ |
1447 | #endif /* !ENABLE_FEATURE_USE_CNG_API */ | ||
1370 | 1448 | ||
1371 | 1449 | ||
1372 | /* | 1450 | /* |
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 8e2b37853..c8a0f37fe 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c | |||
@@ -457,7 +457,7 @@ static void put_cur_glyph_and_inc_cursor(void) | |||
457 | * have automargin (IOW: it is moving cursor to next line | 457 | * have automargin (IOW: it is moving cursor to next line |
458 | * by itself (which is wrong for VT-10x terminals)), | 458 | * by itself (which is wrong for VT-10x terminals)), |
459 | * this will break things: there will be one extra empty line */ | 459 | * this will break things: there will be one extra empty line */ |
460 | puts("\r"); /* + implicit '\n' */ | 460 | fputs("\r\n", stderr); |
461 | #else | 461 | #else |
462 | /* VT-10x terminals don't wrap cursor to next line when last char | 462 | /* VT-10x terminals don't wrap cursor to next line when last char |
463 | * on the line is printed - cursor stays "over" this char. | 463 | * on the line is printed - cursor stays "over" this char. |
@@ -1302,9 +1302,10 @@ static void showfiles(void) | |||
1302 | ); | 1302 | ); |
1303 | } | 1303 | } |
1304 | if (ENABLE_UNICODE_SUPPORT) | 1304 | if (ENABLE_UNICODE_SUPPORT) |
1305 | puts(printable_string(matches[n])); | 1305 | fputs(printable_string(matches[n]), stderr); |
1306 | else | 1306 | else |
1307 | puts(matches[n]); | 1307 | fputs(matches[n], stderr); |
1308 | bb_putchar_stderr('\n'); | ||
1308 | } | 1309 | } |
1309 | } | 1310 | } |
1310 | 1311 | ||
@@ -1595,8 +1596,8 @@ unsigned FAST_FUNC size_from_HISTFILESIZE(const char *hp) | |||
1595 | # endif | 1596 | # endif |
1596 | if (hp) { | 1597 | if (hp) { |
1597 | size = atoi(hp); | 1598 | size = atoi(hp); |
1598 | if (size <= 0) | 1599 | if (size < 0) |
1599 | return 1; | 1600 | return 0; |
1600 | if (size > MAX_HISTORY) | 1601 | if (size > MAX_HISTORY) |
1601 | return MAX_HISTORY; | 1602 | return MAX_HISTORY; |
1602 | } | 1603 | } |
@@ -1690,18 +1691,21 @@ static void load_history(line_input_t *st_parm) | |||
1690 | /* NB: do not trash old history if file can't be opened */ | 1691 | /* NB: do not trash old history if file can't be opened */ |
1691 | 1692 | ||
1692 | fp = fopen_for_read(st_parm->hist_file); | 1693 | fp = fopen_for_read(st_parm->hist_file); |
1693 | if (fp) { | 1694 | if (!fp) |
1694 | /* clean up old history */ | 1695 | return; |
1695 | for (idx = st_parm->cnt_history; idx > 0;) { | 1696 | |
1696 | idx--; | 1697 | /* clean up old history */ |
1697 | free(st_parm->history[idx]); | 1698 | for (idx = st_parm->cnt_history; idx > 0;) { |
1698 | st_parm->history[idx] = NULL; | 1699 | idx--; |
1699 | } | 1700 | free(st_parm->history[idx]); |
1701 | st_parm->history[idx] = NULL; | ||
1702 | } | ||
1700 | 1703 | ||
1701 | /* fill temp_h[], retaining only last MAX_HISTORY lines */ | 1704 | /* fill temp_h[], retaining only last max_history lines */ |
1702 | memset(temp_h, 0, sizeof(temp_h)); | 1705 | memset(temp_h, 0, sizeof(temp_h)); |
1703 | idx = 0; | 1706 | idx = 0; |
1704 | st_parm->cnt_history_in_file = 0; | 1707 | st_parm->cnt_history_in_file = 0; |
1708 | if (st_parm->max_history != 0) { | ||
1705 | while ((line = xmalloc_fgetline(fp)) != NULL) { | 1709 | while ((line = xmalloc_fgetline(fp)) != NULL) { |
1706 | if (line[0] == '\0') { | 1710 | if (line[0] == '\0') { |
1707 | free(line); | 1711 | free(line); |
@@ -1714,34 +1718,34 @@ static void load_history(line_input_t *st_parm) | |||
1714 | if (idx == st_parm->max_history) | 1718 | if (idx == st_parm->max_history) |
1715 | idx = 0; | 1719 | idx = 0; |
1716 | } | 1720 | } |
1717 | fclose(fp); | 1721 | } |
1718 | 1722 | fclose(fp); | |
1719 | /* find first non-NULL temp_h[], if any */ | ||
1720 | if (st_parm->cnt_history_in_file) { | ||
1721 | while (temp_h[idx] == NULL) { | ||
1722 | idx++; | ||
1723 | if (idx == st_parm->max_history) | ||
1724 | idx = 0; | ||
1725 | } | ||
1726 | } | ||
1727 | 1723 | ||
1728 | /* copy temp_h[] to st_parm->history[] */ | 1724 | /* find first non-NULL temp_h[], if any */ |
1729 | for (i = 0; i < st_parm->max_history;) { | 1725 | if (st_parm->cnt_history_in_file != 0) { |
1730 | line = temp_h[idx]; | 1726 | while (temp_h[idx] == NULL) { |
1731 | if (!line) | ||
1732 | break; | ||
1733 | idx++; | 1727 | idx++; |
1734 | if (idx == st_parm->max_history) | 1728 | if (idx == st_parm->max_history) |
1735 | idx = 0; | 1729 | idx = 0; |
1736 | line_len = strlen(line); | ||
1737 | if (line_len >= MAX_LINELEN) | ||
1738 | line[MAX_LINELEN-1] = '\0'; | ||
1739 | st_parm->history[i++] = line; | ||
1740 | } | 1730 | } |
1741 | st_parm->cnt_history = i; | ||
1742 | if (ENABLE_FEATURE_EDITING_SAVE_ON_EXIT) | ||
1743 | st_parm->cnt_history_in_file = i; | ||
1744 | } | 1731 | } |
1732 | |||
1733 | /* copy temp_h[] to st_parm->history[] */ | ||
1734 | for (i = 0; i < st_parm->max_history;) { | ||
1735 | line = temp_h[idx]; | ||
1736 | if (!line) | ||
1737 | break; | ||
1738 | idx++; | ||
1739 | if (idx == st_parm->max_history) | ||
1740 | idx = 0; | ||
1741 | line_len = strlen(line); | ||
1742 | if (line_len >= MAX_LINELEN) | ||
1743 | line[MAX_LINELEN-1] = '\0'; | ||
1744 | st_parm->history[i++] = line; | ||
1745 | } | ||
1746 | st_parm->cnt_history = i; | ||
1747 | if (ENABLE_FEATURE_EDITING_SAVE_ON_EXIT) | ||
1748 | st_parm->cnt_history_in_file = i; | ||
1745 | } | 1749 | } |
1746 | 1750 | ||
1747 | # if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT | 1751 | # if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT |
@@ -1749,17 +1753,27 @@ void FAST_FUNC save_history(line_input_t *st) | |||
1749 | { | 1753 | { |
1750 | FILE *fp; | 1754 | FILE *fp; |
1751 | 1755 | ||
1752 | if (!st || !st->hist_file) | 1756 | /* bash compat: HISTFILE="" disables history saving */ |
1757 | if (!st || !st->hist_file || !state->hist_file[0]) | ||
1753 | return; | 1758 | return; |
1754 | if (st->cnt_history <= st->cnt_history_in_file) | 1759 | if (st->cnt_history <= st->cnt_history_in_file) |
1755 | return; | 1760 | return; /* no new entries were added */ |
1761 | /* note: if st->max_history is 0, we do not abort: we truncate the history to 0 lines */ | ||
1756 | 1762 | ||
1757 | fp = fopen(st->hist_file, "a"); | 1763 | fp = fopen(st->hist_file, (st->max_history == 0 ? "w" : "a")); |
1758 | if (fp) { | 1764 | if (fp) { |
1759 | int i, fd; | 1765 | int i, fd; |
1760 | char *new_name; | 1766 | char *new_name; |
1761 | line_input_t *st_temp; | 1767 | line_input_t *st_temp; |
1762 | 1768 | ||
1769 | /* max_history==0 needs special-casing in general code, | ||
1770 | * just handle it in a simpler way: */ | ||
1771 | if (st->max_history == 0) { | ||
1772 | /* fopen("w") already truncated it */ | ||
1773 | fclose(fp); | ||
1774 | return; | ||
1775 | } | ||
1776 | |||
1763 | for (i = st->cnt_history_in_file; i < st->cnt_history; i++) | 1777 | for (i = st->cnt_history_in_file; i < st->cnt_history; i++) |
1764 | fprintf(fp, "%s\n", st->history[i]); | 1778 | fprintf(fp, "%s\n", st->history[i]); |
1765 | fclose(fp); | 1779 | fclose(fp); |
@@ -1769,6 +1783,8 @@ void FAST_FUNC save_history(line_input_t *st) | |||
1769 | st_temp = new_line_input_t(st->flags); | 1783 | st_temp = new_line_input_t(st->flags); |
1770 | st_temp->hist_file = st->hist_file; | 1784 | st_temp->hist_file = st->hist_file; |
1771 | st_temp->max_history = st->max_history; | 1785 | st_temp->max_history = st->max_history; |
1786 | /* load no more than max_history last lines */ | ||
1787 | /* (in unlikely case that file disappeared, st_temp gets empty history) */ | ||
1772 | load_history(st_temp); | 1788 | load_history(st_temp); |
1773 | 1789 | ||
1774 | /* write out temp file and replace hist_file atomically */ | 1790 | /* write out temp file and replace hist_file atomically */ |
@@ -1792,13 +1808,13 @@ static void save_history(char *str) | |||
1792 | int fd; | 1808 | int fd; |
1793 | int len, len2; | 1809 | int len, len2; |
1794 | 1810 | ||
1795 | if (!state->hist_file) | 1811 | /* bash compat: HISTFILE="" disables history saving */ |
1812 | if (!state->hist_file || !state->hist_file[0]) | ||
1796 | return; | 1813 | return; |
1797 | 1814 | ||
1798 | fd = open(state->hist_file, O_WRONLY | O_CREAT | O_APPEND, 0600); | 1815 | fd = open(state->hist_file, O_WRONLY | O_CREAT | O_APPEND, 0600); |
1799 | if (fd < 0) | 1816 | if (fd < 0) |
1800 | return; | 1817 | return; |
1801 | xlseek(fd, 0, SEEK_END); /* paranoia */ | ||
1802 | len = strlen(str); | 1818 | len = strlen(str); |
1803 | str[len] = '\n'; /* we (try to) do atomic write */ | 1819 | str[len] = '\n'; /* we (try to) do atomic write */ |
1804 | len2 = full_write(fd, str, len + 1); | 1820 | len2 = full_write(fd, str, len + 1); |
@@ -1853,13 +1869,10 @@ static void remember_in_history(char *str) | |||
1853 | if (str[0] == '\0') | 1869 | if (str[0] == '\0') |
1854 | return; | 1870 | return; |
1855 | i = state->cnt_history; | 1871 | i = state->cnt_history; |
1856 | /* Don't save dupes */ | 1872 | /* Don't save dups */ |
1857 | if (i && strcmp(state->history[i-1], str) == 0) | 1873 | if (i != 0 && strcmp(state->history[i-1], str) == 0) |
1858 | return; | 1874 | return; |
1859 | 1875 | ||
1860 | free(state->history[state->max_history]); /* redundant, paranoia */ | ||
1861 | state->history[state->max_history] = NULL; /* redundant, paranoia */ | ||
1862 | |||
1863 | /* If history[] is full, remove the oldest command */ | 1876 | /* If history[] is full, remove the oldest command */ |
1864 | /* we need to keep history[state->max_history] empty, hence >=, not > */ | 1877 | /* we need to keep history[state->max_history] empty, hence >=, not > */ |
1865 | if (i >= state->max_history) { | 1878 | if (i >= state->max_history) { |
@@ -1872,7 +1885,7 @@ static void remember_in_history(char *str) | |||
1872 | state->cnt_history_in_file--; | 1885 | state->cnt_history_in_file--; |
1873 | # endif | 1886 | # endif |
1874 | } | 1887 | } |
1875 | /* i <= state->max_history-1 */ | 1888 | /* i < state->max_history */ |
1876 | state->history[i++] = xstrdup(str); | 1889 | state->history[i++] = xstrdup(str); |
1877 | /* i <= state->max_history */ | 1890 | /* i <= state->max_history */ |
1878 | state->cur_history = i; | 1891 | state->cur_history = i; |
@@ -2388,7 +2401,6 @@ static int lineedit_read_key(char *read_key_buffer, int timeout) | |||
2388 | errno = EINTR; | 2401 | errno = EINTR; |
2389 | return -1; | 2402 | return -1; |
2390 | } | 2403 | } |
2391 | //FIXME: still races here with signals, but small window to poll() inside read_key | ||
2392 | IF_FEATURE_EDITING_WINCH(S.ok_to_redraw = 1;) | 2404 | IF_FEATURE_EDITING_WINCH(S.ok_to_redraw = 1;) |
2393 | /* errno = 0; - read_key does this itself */ | 2405 | /* errno = 0; - read_key does this itself */ |
2394 | ic = read_key(STDIN_FILENO, read_key_buffer, timeout); | 2406 | 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..d3c005418 --- /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-$(CONFIG_PLATFORM_POSIX) += 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/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 54886cc9c..2414105ee 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 | ||
@@ -117,8 +117,8 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout) | |||
117 | return windows_read_key(fd, buffer, timeout); | 117 | return windows_read_key(fd, buffer, timeout); |
118 | #endif | 118 | #endif |
119 | 119 | ||
120 | pfd.fd = fd; | 120 | pfd->fd = fd; |
121 | pfd.events = POLLIN; | 121 | pfd->events = POLLIN; |
122 | 122 | ||
123 | buffer++; /* saved chars counter is in buffer[-1] now */ | 123 | buffer++; /* saved chars counter is in buffer[-1] now */ |
124 | 124 | ||
@@ -126,12 +126,16 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout) | |||
126 | errno = 0; | 126 | errno = 0; |
127 | n = (unsigned char)buffer[-1]; | 127 | n = (unsigned char)buffer[-1]; |
128 | if (n == 0) { | 128 | if (n == 0) { |
129 | /* If no data, wait for input. | 129 | /* No data. Wait for input. */ |
130 | * If requested, wait TIMEOUT ms. TIMEOUT = -1 is useful | 130 | |
131 | * if fd can be in non-blocking mode. | 131 | /* timeout == -2 means "do not poll". Else: */ |
132 | */ | ||
133 | if (timeout >= -1) { | 132 | if (timeout >= -1) { |
134 | n = poll(&pfd, 1, timeout); | 133 | /* We must poll even if timeout == -1: |
134 | * we want to be interrupted if signal arrives, | ||
135 | * regardless of SA_RESTART-ness of that signal! | ||
136 | */ | ||
137 | /* test bb_got_signal, then poll(), atomically wrt signals */ | ||
138 | n = check_got_signal_and_poll(pfd, timeout); | ||
135 | if (n < 0 && errno == EINTR) | 139 | if (n < 0 && errno == EINTR) |
136 | return n; | 140 | return n; |
137 | if (n == 0) { | 141 | if (n == 0) { |
@@ -140,6 +144,7 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout) | |||
140 | return -1; | 144 | return -1; |
141 | } | 145 | } |
142 | } | 146 | } |
147 | |||
143 | /* It is tempting to read more than one byte here, | 148 | /* It is tempting to read more than one byte here, |
144 | * but it breaks pasting. Example: at shell prompt, | 149 | * but it breaks pasting. Example: at shell prompt, |
145 | * user presses "c","a","t" and then pastes "\nline\n". | 150 | * user presses "c","a","t" and then pastes "\nline\n". |
@@ -178,7 +183,7 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout) | |||
178 | * so if we block for long it's not really an escape sequence. | 183 | * so if we block for long it's not really an escape sequence. |
179 | * Timeout is needed to reconnect escape sequences | 184 | * Timeout is needed to reconnect escape sequences |
180 | * split up by transmission over a serial console. */ | 185 | * split up by transmission over a serial console. */ |
181 | if (safe_poll(&pfd, 1, 50) == 0) { | 186 | if (safe_poll(pfd, 1, 50) == 0) { |
182 | /* No more data! | 187 | /* No more data! |
183 | * Array is sorted from shortest to longest, | 188 | * Array is sorted from shortest to longest, |
184 | * we can't match anything later in array - | 189 | * we can't match anything later in array - |
@@ -227,7 +232,7 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout) | |||
227 | * n = bytes read. Try to read more until we time out. | 232 | * n = bytes read. Try to read more until we time out. |
228 | */ | 233 | */ |
229 | while (n < KEYCODE_BUFFER_SIZE-1) { /* 1 for count byte at buffer[-1] */ | 234 | while (n < KEYCODE_BUFFER_SIZE-1) { /* 1 for count byte at buffer[-1] */ |
230 | if (safe_poll(&pfd, 1, 50) == 0) { | 235 | if (safe_poll(pfd, 1, 50) == 0) { |
231 | /* No more data! */ | 236 | /* No more data! */ |
232 | break; | 237 | break; |
233 | } | 238 | } |
diff --git a/libbb/u_signal_names.c b/libbb/u_signal_names.c index ef2b6f891..e233849c5 100644 --- a/libbb/u_signal_names.c +++ b/libbb/u_signal_names.c | |||
@@ -27,10 +27,6 @@ | |||
27 | 27 | ||
28 | #include "libbb.h" | 28 | #include "libbb.h" |
29 | 29 | ||
30 | #if ENABLE_PLATFORM_MINGW32 | ||
31 | # undef SIGPIPE | ||
32 | #endif | ||
33 | |||
34 | #if ENABLE_PLATFORM_POSIX || defined(SIGSTKFLT) || defined(SIGVTALRM) | 30 | #if ENABLE_PLATFORM_POSIX || defined(SIGSTKFLT) || defined(SIGVTALRM) |
35 | # define SIGLEN 7 | 31 | # define SIGLEN 7 |
36 | #elif defined(SIGWINCH) || (ENABLE_FEATURE_RTMINMAX && \ | 32 | #elif defined(SIGWINCH) || (ENABLE_FEATURE_RTMINMAX && \ |
diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c index 7df1a4cd3..5609858d1 100644 --- a/libbb/xfuncs.c +++ b/libbb/xfuncs.c | |||
@@ -333,7 +333,7 @@ int FAST_FUNC get_termios_and_make_raw(int fd, struct termios *newterm, struct t | |||
333 | *newterm = *oldterm; | 333 | *newterm = *oldterm; |
334 | 334 | ||
335 | #if ENABLE_PLATFORM_MINGW32 | 335 | #if ENABLE_PLATFORM_MINGW32 |
336 | newterm->imode &= | 336 | newterm->w_mode &= |
337 | ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT); | 337 | ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT); |
338 | #else | 338 | #else |
339 | /* Turn off buffered input (ICANON) | 339 | /* Turn off buffered input (ICANON) |
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..20e8d1ee4 --- /dev/null +++ b/libbb/yescrypt/alg-sha256.c | |||
@@ -0,0 +1,86 @@ | |||
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 | uint64_t U[32 / 8]; | ||
51 | uint64_t T[32 / 8]; | ||
52 | uint64_t j; | ||
53 | uint32_t ivec; | ||
54 | size_t clen; | ||
55 | int k; | ||
56 | |||
57 | /* Generate INT(i). */ | ||
58 | i++; | ||
59 | ivec = SWAP_BE32(i); | ||
60 | |||
61 | /* Compute U_1 = PRF(P, S || INT(i)). */ | ||
62 | hmac_peek_hash(&PShctx, (void*)T, &ivec, 4, NULL); | ||
63 | //TODO: the above is a vararg function, might incur some ABI pain | ||
64 | //does libbb need a non-vararg version with just one (buf,len)? | ||
65 | |||
66 | if (c > 1) { | ||
67 | /* T_i = U_1 ... */ | ||
68 | memcpy(U, T, 32); | ||
69 | for (j = 2; j <= c; j++) { | ||
70 | /* Compute U_j. */ | ||
71 | hmac_peek_hash(&Phctx, (void*)U, U, 32, NULL); | ||
72 | /* ... xor U_j ... */ | ||
73 | for (k = 0; k < 32 / 8; k++) | ||
74 | T[k] ^= U[k]; | ||
75 | //TODO: xorbuf32_aligned_long(T, U); | ||
76 | } | ||
77 | } | ||
78 | |||
79 | /* Copy as many bytes as necessary into buf. */ | ||
80 | clen = dkLen; | ||
81 | if (clen > 32) | ||
82 | clen = 32; | ||
83 | buf = mempcpy(buf, T, clen); | ||
84 | dkLen -= clen; | ||
85 | } | ||
86 | } | ||
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/loginutils/suw32.c b/loginutils/suw32.c index b3976dcfd..77c038582 100644 --- a/loginutils/suw32.c +++ b/loginutils/suw32.c | |||
@@ -48,8 +48,8 @@ int suw32_main(int argc UNUSED_PARAM, char **argv) | |||
48 | char *opt_command = NULL; | 48 | char *opt_command = NULL; |
49 | char *opt_shell = NULL; | 49 | char *opt_shell = NULL; |
50 | SHELLEXECUTEINFO info; | 50 | SHELLEXECUTEINFO info; |
51 | char *bb_path, *cwd, *realcwd, *q, *args; | 51 | const char *bb_path; |
52 | DECLARE_PROC_ADDR(BOOL, ShellExecuteExA, SHELLEXECUTEINFOA *); | 52 | char *cwd, *realcwd, *q, *args; |
53 | 53 | ||
54 | opt = getopt32(argv, "^c:s:tNW" "\0" "s--N:N--s", &opt_command, &opt_shell); | 54 | opt = getopt32(argv, "^c:s:tNW" "\0" "s--N:N--s", &opt_command, &opt_shell); |
55 | argv += optind; | 55 | argv += optind; |
@@ -70,19 +70,17 @@ int suw32_main(int argc UNUSED_PARAM, char **argv) | |||
70 | } | 70 | } |
71 | #endif | 71 | #endif |
72 | 72 | ||
73 | /* ShellExecuteEx() needs backslash as separator in UNC paths. */ | ||
74 | if (opt_shell) { | 73 | if (opt_shell) { |
75 | bb_path = file_is_win32_exe(opt_shell); | 74 | bb_path = file_is_win32_exe(opt_shell); |
76 | if (!bb_path) | 75 | if (!bb_path) |
77 | bb_error_msg_and_die("%s: Not found", opt_shell); | 76 | bb_error_msg_and_die("%s: Not found", opt_shell); |
78 | args = NULL; | 77 | args = NULL; |
79 | } else { | 78 | } else { |
80 | bb_path = xstrdup(bb_busybox_exec_path); | 79 | bb_path = bb_busybox_exec_path; |
81 | args = xstrdup("--busybox ash"); | 80 | args = xstrdup("--busybox ash"); |
82 | if (!test_mode) | 81 | if (!test_mode) |
83 | args = xappendword(args, "-t \"BusyBox ash (Admin)\""); | 82 | args = xappendword(args, "-t \"BusyBox ash (Admin)\""); |
84 | } | 83 | } |
85 | slash_to_bs(bb_path); | ||
86 | 84 | ||
87 | memset(&info, 0, sizeof(SHELLEXECUTEINFO)); | 85 | memset(&info, 0, sizeof(SHELLEXECUTEINFO)); |
88 | info.cbSize = sizeof(SHELLEXECUTEINFO); | 86 | info.cbSize = sizeof(SHELLEXECUTEINFO); |
@@ -137,12 +135,7 @@ int suw32_main(int argc UNUSED_PARAM, char **argv) | |||
137 | /* info.lpDirectory = NULL; */ | 135 | /* info.lpDirectory = NULL; */ |
138 | info.nShow = SW_SHOWNORMAL; | 136 | info.nShow = SW_SHOWNORMAL; |
139 | 137 | ||
140 | if (!INIT_PROC_ADDR(shell32.dll, ShellExecuteExA)) { | 138 | if (!mingw_shell_execute(&info)) { |
141 | ret = -1; | ||
142 | goto end; | ||
143 | } | ||
144 | |||
145 | if (!ShellExecuteExA(&info)) { | ||
146 | ret = 1; | 139 | ret = 1; |
147 | goto end; | 140 | goto end; |
148 | } | 141 | } |
@@ -159,7 +152,8 @@ int suw32_main(int argc UNUSED_PARAM, char **argv) | |||
159 | } | 152 | } |
160 | end: | 153 | end: |
161 | if (ENABLE_FEATURE_CLEAN_UP) { | 154 | if (ENABLE_FEATURE_CLEAN_UP) { |
162 | free(bb_path); | 155 | if (bb_path != bb_busybox_exec_path) |
156 | free((void *)bb_path); | ||
163 | free(cwd); | 157 | free(cwd); |
164 | free(realcwd); | 158 | free(realcwd); |
165 | free(args); | 159 | free(args); |
diff --git a/miscutils/crond.c b/miscutils/crond.c index b3762d327..96131cae4 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). |
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 467c76e2a..5a8fc5a74 100644 --- a/miscutils/less.c +++ b/miscutils/less.c | |||
@@ -1178,7 +1178,7 @@ static int64_t getch_nowait(void) | |||
1178 | 1178 | ||
1179 | /* We have kbd_fd in O_NONBLOCK mode, read inside safe_read_key() | 1179 | /* We have kbd_fd in O_NONBLOCK mode, read inside safe_read_key() |
1180 | * would not block even if there is no input available */ | 1180 | * would not block even if there is no input available */ |
1181 | key64 = safe_read_key(kbd_fd, kbd_input, /*timeout off:*/ -2); | 1181 | key64 = safe_read_key(kbd_fd, kbd_input, /*do not poll:*/ -2); |
1182 | if ((int)key64 == -1) { | 1182 | if ((int)key64 == -1) { |
1183 | if (errno == EAGAIN) { | 1183 | if (errno == EAGAIN) { |
1184 | /* No keyboard input available. Since poll() did return, | 1184 | /* No keyboard input available. Since poll() did return, |
diff --git a/miscutils/make.c b/miscutils/make.c index 7316408bf..a165274aa 100644 --- a/miscutils/make.c +++ b/miscutils/make.c | |||
@@ -257,6 +257,11 @@ enum { | |||
257 | #define MAKE_FAILURE 0x01 | 257 | #define MAKE_FAILURE 0x01 |
258 | #define MAKE_DIDSOMETHING 0x02 | 258 | #define MAKE_DIDSOMETHING 0x02 |
259 | 259 | ||
260 | // Return TRUE if c is allowed in a POSIX 2017 macro or target name | ||
261 | #define ispname(c) (isalpha(c) || isdigit(c) || c == '.' || c == '_') | ||
262 | // Return TRUE if c is in the POSIX 'portable filename character set' | ||
263 | #define isfname(c) (ispname(c) || c == '-') | ||
264 | |||
260 | #define HTABSIZE 39 | 265 | #define HTABSIZE 39 |
261 | 266 | ||
262 | struct globals { | 267 | struct globals { |
@@ -320,11 +325,8 @@ struct globals { | |||
320 | #endif | 325 | #endif |
321 | 326 | ||
322 | static int make(struct name *np, int level); | 327 | static int make(struct name *np, int level); |
323 | 328 | static struct name *dyndep(struct name *np, struct rule *infrule, | |
324 | // Return TRUE if c is allowed in a POSIX 2017 macro or target name | 329 | const char **ptsuff); |
325 | #define ispname(c) (isalpha(c) || isdigit(c) || c == '.' || c == '_') | ||
326 | // Return TRUE if c is in the POSIX 'portable filename character set' | ||
327 | #define isfname(c) (ispname(c) || c == '-') | ||
328 | 330 | ||
329 | /* | 331 | /* |
330 | * Utility functions. | 332 | * Utility functions. |
@@ -469,8 +471,7 @@ newcmd(struct cmd **cphead, char *str) | |||
469 | /*(*cphead)->c_next = NULL; - xzalloc did it */ | 471 | /*(*cphead)->c_next = NULL; - xzalloc did it */ |
470 | (*cphead)->c_cmd = xstrdup(str); | 472 | (*cphead)->c_cmd = xstrdup(str); |
471 | /*(*cphead)->c_refcnt = 0; */ | 473 | /*(*cphead)->c_refcnt = 0; */ |
472 | if (makefile) | 474 | (*cphead)->c_makefile = xstrdup(makefile); |
473 | (*cphead)->c_makefile = xstrdup(makefile); | ||
474 | (*cphead)->c_dispno = dispno; | 475 | (*cphead)->c_dispno = dispno; |
475 | } | 476 | } |
476 | 477 | ||
@@ -993,38 +994,27 @@ suffix(const char *name) | |||
993 | } | 994 | } |
994 | 995 | ||
995 | /* | 996 | /* |
996 | * Dynamic dependency. This routine applies the suffix rules | 997 | * Search for an inference rule to convert some suffix ('psuff') |
997 | * to try and find a source and a set of rules for a missing | 998 | * to the target suffix 'tsuff'. The basename of the prerequisite |
998 | * target. NULL is returned on failure. On success the name of | 999 | * is 'base'. |
999 | * the implicit prerequisite is returned and the details are | ||
1000 | * placed in the imprule structure provided by the caller. | ||
1001 | */ | 1000 | */ |
1002 | static struct name * | 1001 | static struct name * |
1003 | dyndep(struct name *np, struct rule *imprule) | 1002 | dyndep0(char *base, const char *tsuff, struct rule *infrule) |
1004 | { | 1003 | { |
1005 | char *suff, *newsuff; | 1004 | char *psuff; |
1006 | char *base, *name, *member; | ||
1007 | struct name *xp; // Suffixes | 1005 | struct name *xp; // Suffixes |
1008 | struct name *sp; // Suffix rule | 1006 | struct name *sp; // Suffix rule |
1009 | struct name *pp = NULL; // Implicit prerequisite | ||
1010 | struct rule *rp; | 1007 | struct rule *rp; |
1011 | struct depend *dp; | 1008 | struct depend *dp; |
1012 | bool chain = FALSE; | 1009 | bool chain = FALSE; |
1013 | 1010 | ||
1014 | member = NULL; | ||
1015 | name = splitlib(np->n_name, &member); | ||
1016 | |||
1017 | suff = xstrdup(suffix(name)); | ||
1018 | base = member ? member : name; | ||
1019 | *suffix(base) = '\0'; | ||
1020 | |||
1021 | xp = newname(".SUFFIXES"); | 1011 | xp = newname(".SUFFIXES"); |
1022 | retry: | 1012 | retry: |
1023 | for (rp = xp->n_rule; rp; rp = rp->r_next) { | 1013 | for (rp = xp->n_rule; rp; rp = rp->r_next) { |
1024 | for (dp = rp->r_dep; dp; dp = dp->d_next) { | 1014 | for (dp = rp->r_dep; dp; dp = dp->d_next) { |
1025 | // Generate new suffix rule to try | 1015 | // Generate new suffix rule to try |
1026 | newsuff = dp->d_name->n_name; | 1016 | psuff = dp->d_name->n_name; |
1027 | sp = findname(auto_concat(newsuff, suff)); | 1017 | sp = findname(auto_concat(psuff, tsuff)); |
1028 | if (sp && sp->n_rule) { | 1018 | if (sp && sp->n_rule) { |
1029 | struct name *ip; | 1019 | struct name *ip; |
1030 | int got_ip; | 1020 | int got_ip; |
@@ -1032,9 +1022,8 @@ dyndep(struct name *np, struct rule *imprule) | |||
1032 | // Has rule already been used in this chain? | 1022 | // Has rule already been used in this chain? |
1033 | if ((sp->n_flag & N_MARK)) | 1023 | if ((sp->n_flag & N_MARK)) |
1034 | continue; | 1024 | continue; |
1035 | |||
1036 | // Generate a name for an implicit prerequisite | 1025 | // Generate a name for an implicit prerequisite |
1037 | ip = newname(auto_concat(base, newsuff)); | 1026 | ip = newname(auto_concat(base, psuff)); |
1038 | if ((ip->n_flag & N_DOING)) | 1027 | if ((ip->n_flag & N_DOING)) |
1039 | continue; | 1028 | continue; |
1040 | 1029 | ||
@@ -1045,20 +1034,19 @@ dyndep(struct name *np, struct rule *imprule) | |||
1045 | got_ip = ip->n_tim.tv_sec || (ip->n_flag & N_TARGET); | 1034 | got_ip = ip->n_tim.tv_sec || (ip->n_flag & N_TARGET); |
1046 | } else { | 1035 | } else { |
1047 | sp->n_flag |= N_MARK; | 1036 | sp->n_flag |= N_MARK; |
1048 | got_ip = dyndep(ip, NULL) != NULL; | 1037 | got_ip = dyndep(ip, NULL, NULL) != NULL; |
1049 | sp->n_flag &= ~N_MARK; | 1038 | sp->n_flag &= ~N_MARK; |
1050 | } | 1039 | } |
1051 | 1040 | ||
1052 | if (got_ip) { | 1041 | if (got_ip) { |
1053 | // Prerequisite exists or we know how to make it | 1042 | // Prerequisite exists or we know how to make it |
1054 | if (imprule) { | 1043 | if (infrule) { |
1055 | dp = NULL; | 1044 | dp = NULL; |
1056 | newdep(&dp, ip); | 1045 | newdep(&dp, ip); |
1057 | imprule->r_dep = dp; | 1046 | infrule->r_dep = dp; |
1058 | imprule->r_cmd = sp->n_rule->r_cmd; | 1047 | infrule->r_cmd = sp->n_rule->r_cmd; |
1059 | } | 1048 | } |
1060 | pp = ip; | 1049 | return ip; |
1061 | goto finish; | ||
1062 | } | 1050 | } |
1063 | } | 1051 | } |
1064 | } | 1052 | } |
@@ -1069,9 +1057,87 @@ dyndep(struct name *np, struct rule *imprule) | |||
1069 | chain = TRUE; | 1057 | chain = TRUE; |
1070 | goto retry; | 1058 | goto retry; |
1071 | } | 1059 | } |
1072 | finish: | 1060 | return NULL; |
1073 | free(suff); | 1061 | } |
1062 | |||
1063 | /* | ||
1064 | * If 'name' ends with 'suffix' return an allocated string containing | ||
1065 | * the name with the suffix removed, else return NULL. | ||
1066 | */ | ||
1067 | static char * | ||
1068 | has_suffix(const char *name, const char *suffix) | ||
1069 | { | ||
1070 | ssize_t delta = strlen(name) - strlen(suffix); | ||
1071 | char *base = NULL; | ||
1072 | |||
1073 | if (delta > 0 && strcmp(name + delta, suffix) == 0) { | ||
1074 | base = xstrdup(name); | ||
1075 | base[delta] = '\0'; | ||
1076 | } | ||
1077 | |||
1078 | return base; | ||
1079 | } | ||
1080 | |||
1081 | /* | ||
1082 | * Dynamic dependency. This routine applies the suffix rules | ||
1083 | * to try and find a source and a set of rules for a missing | ||
1084 | * target. NULL is returned on failure. On success the name of | ||
1085 | * the implicit prerequisite is returned and the rule used is | ||
1086 | * placed in the infrule structure provided by the caller. | ||
1087 | */ | ||
1088 | static struct name * | ||
1089 | dyndep(struct name *np, struct rule *infrule, const char **ptsuff) | ||
1090 | { | ||
1091 | const char *tsuff; | ||
1092 | char *base, *name, *member; | ||
1093 | struct name *pp = NULL; // Implicit prerequisite | ||
1094 | |||
1095 | member = NULL; | ||
1096 | name = splitlib(np->n_name, &member); | ||
1097 | |||
1098 | // POSIX only allows inference rules with one or two periods. | ||
1099 | // As an extension this restriction is lifted, but not for | ||
1100 | // targets of the form lib.a(member.o). | ||
1101 | if (!posix && member == NULL) { | ||
1102 | struct name *xp = newname(".SUFFIXES"); | ||
1103 | int found_suffix = FALSE; | ||
1104 | |||
1105 | for (struct rule *rp = xp->n_rule; rp; rp = rp->r_next) { | ||
1106 | for (struct depend *dp = rp->r_dep; dp; dp = dp->d_next) { | ||
1107 | tsuff = dp->d_name->n_name; | ||
1108 | base = has_suffix(name, tsuff); | ||
1109 | if (base) { | ||
1110 | found_suffix = TRUE; | ||
1111 | pp = dyndep0(base, tsuff, infrule); | ||
1112 | free(base); | ||
1113 | if (pp) { | ||
1114 | goto done; | ||
1115 | } | ||
1116 | } | ||
1117 | } | ||
1118 | } | ||
1119 | |||
1120 | if (!found_suffix) { | ||
1121 | // The name didn't have a known suffix. Try single-suffix rule. | ||
1122 | tsuff = ""; | ||
1123 | pp = dyndep0(name, tsuff, infrule); | ||
1124 | if (pp) { | ||
1125 | done: | ||
1126 | if (ptsuff) { | ||
1127 | *ptsuff = tsuff; | ||
1128 | } | ||
1129 | } | ||
1130 | } | ||
1131 | } else { | ||
1132 | tsuff = xstrdup(suffix(name)); | ||
1133 | base = member ? member : name; | ||
1134 | *suffix(base) = '\0'; | ||
1135 | |||
1136 | pp = dyndep0(base, tsuff, infrule); | ||
1137 | free((void *)tsuff); | ||
1138 | } | ||
1074 | free(name); | 1139 | free(name); |
1140 | |||
1075 | return pp; | 1141 | return pp; |
1076 | } | 1142 | } |
1077 | 1143 | ||
@@ -1789,9 +1855,10 @@ readline(FILE *fd, int want_command) | |||
1789 | } | 1855 | } |
1790 | 1856 | ||
1791 | /* | 1857 | /* |
1792 | * Return TRUE if the argument is a known suffix. | 1858 | * Return a pointer to the suffix name if the argument is a known suffix |
1859 | * or NULL if it isn't. | ||
1793 | */ | 1860 | */ |
1794 | static int | 1861 | static const char * |
1795 | is_suffix(const char *s) | 1862 | is_suffix(const char *s) |
1796 | { | 1863 | { |
1797 | struct name *np; | 1864 | struct name *np; |
@@ -1802,7 +1869,39 @@ is_suffix(const char *s) | |||
1802 | for (rp = np->n_rule; rp; rp = rp->r_next) { | 1869 | for (rp = np->n_rule; rp; rp = rp->r_next) { |
1803 | for (dp = rp->r_dep; dp; dp = dp->d_next) { | 1870 | for (dp = rp->r_dep; dp; dp = dp->d_next) { |
1804 | if (strcmp(s, dp->d_name->n_name) == 0) { | 1871 | if (strcmp(s, dp->d_name->n_name) == 0) { |
1805 | return TRUE; | 1872 | return dp->d_name->n_name; |
1873 | } | ||
1874 | } | ||
1875 | } | ||
1876 | return NULL; | ||
1877 | } | ||
1878 | |||
1879 | /* | ||
1880 | * Return TRUE if the argument is formed by concatenating two | ||
1881 | * known suffixes. | ||
1882 | */ | ||
1883 | static int | ||
1884 | is_inference_target(const char *s) | ||
1885 | { | ||
1886 | struct name *np; | ||
1887 | struct rule *rp1, *rp2; | ||
1888 | struct depend *dp1, *dp2; | ||
1889 | |||
1890 | np = newname(".SUFFIXES"); | ||
1891 | for (rp1 = np->n_rule; rp1; rp1 = rp1->r_next) { | ||
1892 | for (dp1 = rp1->r_dep; dp1; dp1 = dp1->d_next) { | ||
1893 | const char *suff1 = dp1->d_name->n_name; | ||
1894 | size_t len = strlen(suff1); | ||
1895 | |||
1896 | if (strncmp(s, suff1, len) == 0) { | ||
1897 | for (rp2 = np->n_rule; rp2; rp2 = rp2->r_next) { | ||
1898 | for (dp2 = rp2->r_dep; dp2; dp2 = dp2->d_next) { | ||
1899 | const char *suff2 = dp2->d_name->n_name; | ||
1900 | if (strcmp(s + len, suff2) == 0) { | ||
1901 | return TRUE; | ||
1902 | } | ||
1903 | } | ||
1904 | } | ||
1806 | } | 1905 | } |
1807 | } | 1906 | } |
1808 | } | 1907 | } |
@@ -1824,7 +1923,6 @@ enum { | |||
1824 | static int | 1923 | static int |
1825 | target_type(char *s) | 1924 | target_type(char *s) |
1826 | { | 1925 | { |
1827 | char *sfx; | ||
1828 | int ret; | 1926 | int ret; |
1829 | static const char *s_name = | 1927 | static const char *s_name = |
1830 | ".DEFAULT\0" | 1928 | ".DEFAULT\0" |
@@ -1854,9 +1952,6 @@ target_type(char *s) | |||
1854 | T_SPECIAL, | 1952 | T_SPECIAL, |
1855 | }; | 1953 | }; |
1856 | 1954 | ||
1857 | if (*s != '.') | ||
1858 | return T_NORMAL; | ||
1859 | |||
1860 | // Check for one of the known special targets | 1955 | // Check for one of the known special targets |
1861 | ret = index_in_strings(s_name, s); | 1956 | ret = index_in_strings(s_name, s); |
1862 | if (ret >= 0) | 1957 | if (ret >= 0) |
@@ -1864,16 +1959,23 @@ target_type(char *s) | |||
1864 | 1959 | ||
1865 | // Check for an inference rule | 1960 | // Check for an inference rule |
1866 | ret = T_NORMAL; | 1961 | ret = T_NORMAL; |
1867 | sfx = suffix(s); | 1962 | if (!posix) { |
1868 | if (is_suffix(sfx)) { | 1963 | if (is_suffix(s) || is_inference_target(s)) { |
1869 | if (s == sfx) { // Single suffix rule | ||
1870 | ret = T_INFERENCE | T_NOPREREQ | T_COMMAND; | 1964 | ret = T_INFERENCE | T_NOPREREQ | T_COMMAND; |
1871 | } else { | 1965 | } |
1872 | // Suffix is valid, check that prefix is too | 1966 | } else { |
1873 | *sfx = '\0'; | 1967 | // In POSIX inference rule targets must contain one or two dots |
1874 | if (is_suffix(s)) | 1968 | char *sfx = suffix(s); |
1969 | if (*s == '.' && is_suffix(sfx)) { | ||
1970 | if (s == sfx) { // Single suffix rule | ||
1875 | ret = T_INFERENCE | T_NOPREREQ | T_COMMAND; | 1971 | ret = T_INFERENCE | T_NOPREREQ | T_COMMAND; |
1876 | *sfx = '.'; | 1972 | } else { |
1973 | // Suffix is valid, check that prefix is too | ||
1974 | *sfx = '\0'; | ||
1975 | if (is_suffix(s)) | ||
1976 | ret = T_INFERENCE | T_NOPREREQ | T_COMMAND; | ||
1977 | *sfx = '.'; | ||
1978 | } | ||
1877 | } | 1979 | } |
1878 | } | 1980 | } |
1879 | return ret; | 1981 | return ret; |
@@ -2069,6 +2171,20 @@ pragmas_from_env(void) | |||
2069 | #endif | 2171 | #endif |
2070 | 2172 | ||
2071 | /* | 2173 | /* |
2174 | * Determine if a line is a target rule with an inline command. | ||
2175 | * Return a pointer to the semicolon separator if it is, else NULL. | ||
2176 | */ | ||
2177 | static char * | ||
2178 | inline_command(char *line) | ||
2179 | { | ||
2180 | char *p = find_char(line, ':'); | ||
2181 | |||
2182 | if (p) | ||
2183 | p = strchr(p, ';'); | ||
2184 | return p; | ||
2185 | } | ||
2186 | |||
2187 | /* | ||
2072 | * Parse input from the makefile and construct a tree structure of it. | 2188 | * Parse input from the makefile and construct a tree structure of it. |
2073 | */ | 2189 | */ |
2074 | static void | 2190 | static void |
@@ -2287,9 +2403,9 @@ input(FILE *fd, int ilevel) | |||
2287 | cp = NULL; | 2403 | cp = NULL; |
2288 | s = strchr(q, ';'); | 2404 | s = strchr(q, ';'); |
2289 | if (s) { | 2405 | if (s) { |
2290 | // Retrieve command from expanded copy of line | 2406 | // Retrieve command from original or expanded copy of line |
2291 | char *copy3 = expand_macros(copy, FALSE); | 2407 | char *copy3 = expand_macros(copy, FALSE); |
2292 | if ((p = find_colon(copy3)) && (p = strchr(p, ';'))) | 2408 | if ((p = inline_command(copy)) || (p = inline_command(copy3))) |
2293 | newcmd(&cp, process_command(p + 1)); | 2409 | newcmd(&cp, process_command(p + 1)); |
2294 | free(copy3); | 2410 | free(copy3); |
2295 | *s = '\0'; | 2411 | *s = '\0'; |
@@ -2585,9 +2701,34 @@ docmds(struct name *np, struct cmd *cp) | |||
2585 | return estat; | 2701 | return estat; |
2586 | } | 2702 | } |
2587 | 2703 | ||
2704 | /* | ||
2705 | * Remove the suffix from a name, either the one provided in 'tsuff' | ||
2706 | * or, if 'tsuff' is NULL, one of the known suffixes. | ||
2707 | */ | ||
2708 | static char * | ||
2709 | remove_suffix(const char *name, const char *tsuff) | ||
2710 | { | ||
2711 | char *base = NULL; | ||
2712 | |||
2713 | if (tsuff != NULL) { | ||
2714 | base = has_suffix(name, tsuff); | ||
2715 | } else { | ||
2716 | struct name *xp = newname(".SUFFIXES"); | ||
2717 | for (struct rule *rp = xp->n_rule; rp; rp = rp->r_next) { | ||
2718 | for (struct depend *dp = rp->r_dep; dp; dp = dp->d_next) { | ||
2719 | base = has_suffix(name, dp->d_name->n_name); | ||
2720 | if (base) { | ||
2721 | return base; | ||
2722 | } | ||
2723 | } | ||
2724 | } | ||
2725 | } | ||
2726 | return base; | ||
2727 | } | ||
2728 | |||
2588 | static int | 2729 | static int |
2589 | make1(struct name *np, struct cmd *cp, char *oodate, char *allsrc, | 2730 | make1(struct name *np, struct cmd *cp, char *oodate, char *allsrc, |
2590 | char *dedup, struct name *implicit) | 2731 | char *dedup, struct name *implicit, const char *tsuff) |
2591 | { | 2732 | { |
2592 | char *name, *member = NULL, *base = NULL, *prereq = NULL; | 2733 | char *name, *member = NULL, *base = NULL, *prereq = NULL; |
2593 | 2734 | ||
@@ -2603,7 +2744,7 @@ make1(struct name *np, struct cmd *cp, char *oodate, char *allsrc, | |||
2603 | char *s; | 2744 | char *s; |
2604 | 2745 | ||
2605 | // As an extension, if we're not dealing with an implicit | 2746 | // As an extension, if we're not dealing with an implicit |
2606 | // rule set $< to the first out-of-date prerequisite. | 2747 | // prerequisite set $< to the first out-of-date prerequisite. |
2607 | if (implicit == NULL) { | 2748 | if (implicit == NULL) { |
2608 | if (oodate) { | 2749 | if (oodate) { |
2609 | s = strchr(oodate, ' '); | 2750 | s = strchr(oodate, ' '); |
@@ -2614,15 +2755,26 @@ make1(struct name *np, struct cmd *cp, char *oodate, char *allsrc, | |||
2614 | } else | 2755 | } else |
2615 | prereq = implicit->n_name; | 2756 | prereq = implicit->n_name; |
2616 | 2757 | ||
2617 | base = member ? member : name; | 2758 | if (!posix && member == NULL) { |
2618 | s = suffix(base); | 2759 | // As an extension remove a suffix that doesn't necessarily |
2619 | // As an extension, if we're not dealing with an implicit | 2760 | // start with a period from a target, but not for targets |
2620 | // rule and the target ends with a known suffix, remove it | 2761 | // of the form lib.a(member.o). |
2621 | // and set $* to the stem, else to an empty string. | 2762 | base = remove_suffix(name, tsuff); |
2622 | if (implicit == NULL && !is_suffix(s)) | 2763 | if (base) { |
2623 | base = NULL; | 2764 | free(name); |
2624 | else | 2765 | name = base; |
2625 | *s = '\0'; | 2766 | } |
2767 | } else { | ||
2768 | base = member ? member : name; | ||
2769 | s = suffix(base); | ||
2770 | // As an extension, if we're not dealing with an implicit | ||
2771 | // prerequisite and the target ends with a known suffix, | ||
2772 | // remove it and set $* to the stem, else to an empty string. | ||
2773 | if (implicit == NULL && !is_suffix(s)) | ||
2774 | base = NULL; | ||
2775 | else | ||
2776 | *s = '\0'; | ||
2777 | } | ||
2626 | } | 2778 | } |
2627 | setmacro("<", prereq, 0 | M_VALID); | 2779 | setmacro("<", prereq, 0 | M_VALID); |
2628 | setmacro("*", base, 0 | M_VALID); | 2780 | setmacro("*", base, 0 | M_VALID); |
@@ -2667,11 +2819,12 @@ make(struct name *np, int level) | |||
2667 | struct depend *dp; | 2819 | struct depend *dp; |
2668 | struct rule *rp; | 2820 | struct rule *rp; |
2669 | struct name *impdep = NULL; // implicit prerequisite | 2821 | struct name *impdep = NULL; // implicit prerequisite |
2670 | struct rule imprule; | 2822 | struct rule infrule; |
2671 | struct cmd *sc_cmd = NULL; // commands for single-colon rule | 2823 | struct cmd *sc_cmd = NULL; // commands for single-colon rule |
2672 | char *oodate = NULL; | 2824 | char *oodate = NULL; |
2673 | char *allsrc = NULL; | 2825 | char *allsrc = NULL; |
2674 | char *dedup = NULL; | 2826 | char *dedup = NULL; |
2827 | const char *tsuff = NULL; | ||
2675 | struct timespec dtim = {1, 0}; | 2828 | struct timespec dtim = {1, 0}; |
2676 | int estat = 0; | 2829 | int estat = 0; |
2677 | 2830 | ||
@@ -2690,10 +2843,10 @@ make(struct name *np, int level) | |||
2690 | // as an extension, not for phony targets) | 2843 | // as an extension, not for phony targets) |
2691 | sc_cmd = getcmd(np); | 2844 | sc_cmd = getcmd(np); |
2692 | if (!sc_cmd && (posix || !(np->n_flag & N_PHONY))) { | 2845 | if (!sc_cmd && (posix || !(np->n_flag & N_PHONY))) { |
2693 | impdep = dyndep(np, &imprule); | 2846 | impdep = dyndep(np, &infrule, &tsuff); |
2694 | if (impdep) { | 2847 | if (impdep) { |
2695 | sc_cmd = imprule.r_cmd; | 2848 | sc_cmd = infrule.r_cmd; |
2696 | addrule(np, imprule.r_dep, NULL, FALSE); | 2849 | addrule(np, infrule.r_dep, NULL, FALSE); |
2697 | } | 2850 | } |
2698 | } | 2851 | } |
2699 | 2852 | ||
@@ -2708,14 +2861,15 @@ make(struct name *np, int level) | |||
2708 | } | 2861 | } |
2709 | impdep = np; | 2862 | impdep = np; |
2710 | } | 2863 | } |
2711 | } | 2864 | } else { |
2712 | else { | ||
2713 | // If any double-colon rule has no commands we need | 2865 | // If any double-colon rule has no commands we need |
2714 | // an inference rule (but, as an extension, not for phony targets) | 2866 | // an inference rule. |
2715 | for (rp = np->n_rule; rp; rp = rp->r_next) { | 2867 | for (rp = np->n_rule; rp; rp = rp->r_next) { |
2716 | if (!rp->r_cmd) { | 2868 | if (!rp->r_cmd) { |
2717 | if (posix || !(np->n_flag & N_PHONY)) | 2869 | // Phony targets don't need an inference rule. |
2718 | impdep = dyndep(np, &imprule); | 2870 | if (!posix && (np->n_flag & N_PHONY)) |
2871 | continue; | ||
2872 | impdep = dyndep(np, &infrule, &tsuff); | ||
2719 | if (!impdep) { | 2873 | if (!impdep) { |
2720 | if (doinclude) | 2874 | if (doinclude) |
2721 | return 1; | 2875 | return 1; |
@@ -2741,11 +2895,14 @@ make(struct name *np, int level) | |||
2741 | // Each double-colon rule is handled separately. | 2895 | // Each double-colon rule is handled separately. |
2742 | if ((np->n_flag & N_DOUBLE)) { | 2896 | if ((np->n_flag & N_DOUBLE)) { |
2743 | // If the rule has no commands use the inference rule. | 2897 | // If the rule has no commands use the inference rule. |
2898 | // Unless there isn't one, as allowed for phony targets. | ||
2744 | if (!rp->r_cmd) { | 2899 | if (!rp->r_cmd) { |
2745 | locdep = impdep; | 2900 | if (impdep) { |
2746 | imprule.r_dep->d_next = rp->r_dep; | 2901 | locdep = impdep; |
2747 | rp->r_dep = imprule.r_dep; | 2902 | infrule.r_dep->d_next = rp->r_dep; |
2748 | rp->r_cmd = imprule.r_cmd; | 2903 | rp->r_dep = infrule.r_dep; |
2904 | rp->r_cmd = infrule.r_cmd; | ||
2905 | } | ||
2749 | } | 2906 | } |
2750 | // A rule with no prerequisities is executed unconditionally. | 2907 | // A rule with no prerequisities is executed unconditionally. |
2751 | if (!rp->r_dep) | 2908 | if (!rp->r_dep) |
@@ -2776,7 +2933,7 @@ make(struct name *np, int level) | |||
2776 | if (((np->n_flag & N_PHONY) || timespec_le(&np->n_tim, &dtim))) { | 2933 | if (((np->n_flag & N_PHONY) || timespec_le(&np->n_tim, &dtim))) { |
2777 | if (!(estat & MAKE_FAILURE)) { | 2934 | if (!(estat & MAKE_FAILURE)) { |
2778 | estat |= make1(np, rp->r_cmd, oodate, allsrc, | 2935 | estat |= make1(np, rp->r_cmd, oodate, allsrc, |
2779 | dedup, locdep); | 2936 | dedup, locdep, tsuff); |
2780 | dtim = (struct timespec){1, 0}; | 2937 | dtim = (struct timespec){1, 0}; |
2781 | } | 2938 | } |
2782 | free(oodate); | 2939 | free(oodate); |
@@ -2792,7 +2949,7 @@ make(struct name *np, int level) | |||
2792 | } | 2949 | } |
2793 | } | 2950 | } |
2794 | if ((np->n_flag & N_DOUBLE) && impdep) | 2951 | if ((np->n_flag & N_DOUBLE) && impdep) |
2795 | free(imprule.r_dep); | 2952 | free(infrule.r_dep); |
2796 | 2953 | ||
2797 | np->n_flag |= N_DONE; | 2954 | np->n_flag |= N_DONE; |
2798 | np->n_flag &= ~N_DOING; | 2955 | np->n_flag &= ~N_DOING; |
@@ -2801,7 +2958,8 @@ make(struct name *np, int level) | |||
2801 | ((np->n_flag & N_PHONY) || (timespec_le(&np->n_tim, &dtim)))) { | 2958 | ((np->n_flag & N_PHONY) || (timespec_le(&np->n_tim, &dtim)))) { |
2802 | if (!(estat & MAKE_FAILURE)) { | 2959 | if (!(estat & MAKE_FAILURE)) { |
2803 | if (sc_cmd) | 2960 | if (sc_cmd) |
2804 | estat |= make1(np, sc_cmd, oodate, allsrc, dedup, impdep); | 2961 | estat |= make1(np, sc_cmd, oodate, allsrc, dedup, |
2962 | impdep, tsuff); | ||
2805 | else if (!doinclude && level == 0 && !(estat & MAKE_DIDSOMETHING)) | 2963 | else if (!doinclude && level == 0 && !(estat & MAKE_DIDSOMETHING)) |
2806 | warning("nothing to be done for %s", np->n_name); | 2964 | warning("nothing to be done for %s", np->n_name); |
2807 | } else if (!doinclude && !quest) { | 2965 | } else if (!doinclude && !quest) { |
diff --git a/miscutils/man.c b/miscutils/man.c index 3954455b4..38c1b9aa3 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/networking/Config.src b/networking/Config.src index 0942645c3..aa0806a18 100644 --- a/networking/Config.src +++ b/networking/Config.src | |||
@@ -72,9 +72,28 @@ config FEATURE_HWIB | |||
72 | help | 72 | help |
73 | Support for printing infiniband addresses in network applets. | 73 | Support for printing infiniband addresses in network applets. |
74 | 74 | ||
75 | choice | ||
76 | prompt "TLS implementation" | ||
77 | default FEATURE_TLS_INTERNAL | ||
78 | |||
79 | config FEATURE_TLS_INTERNAL | ||
80 | bool "Internal" | ||
81 | depends on TLS | ||
82 | help | ||
83 | Use the BusyBox default internal TLS implementation. | ||
84 | |||
85 | config FEATURE_TLS_SCHANNEL | ||
86 | bool "Schannel SSP" | ||
87 | depends on TLS && PLATFORM_MINGW32 | ||
88 | help | ||
89 | Use the Schannel SSP to provide TLS support. | ||
90 | Reduces code size and enables certificate checking. | ||
91 | |||
92 | endchoice | ||
93 | |||
75 | config FEATURE_TLS_SHA1 | 94 | config FEATURE_TLS_SHA1 |
76 | bool "In TLS code, support ciphers which use deprecated SHA1" | 95 | bool "In TLS code, support ciphers which use deprecated SHA1" |
77 | depends on TLS | 96 | depends on FEATURE_TLS_INTERNAL |
78 | default n | 97 | default n |
79 | help | 98 | help |
80 | Selecting this option increases interoperability with very old | 99 | Selecting this option increases interoperability with very old |
@@ -83,6 +102,15 @@ config FEATURE_TLS_SHA1 | |||
83 | Most TLS servers support SHA256 today (2018), since SHA1 is | 102 | Most TLS servers support SHA256 today (2018), since SHA1 is |
84 | considered possibly insecure (although not yet definitely broken). | 103 | considered possibly insecure (although not yet definitely broken). |
85 | 104 | ||
105 | config FEATURE_TLS_SCHANNEL_1_3 | ||
106 | bool "Enable TLS 1.3 support for Schannel" | ||
107 | depends on FEATURE_TLS_SCHANNEL | ||
108 | default n | ||
109 | help | ||
110 | Enable TLS 1.3 support for Schannel. | ||
111 | This only works on Windows 11/Server 2022 | ||
112 | and up. | ||
113 | |||
86 | INSERT | 114 | INSERT |
87 | 115 | ||
88 | source networking/udhcp/Config.in | 116 | source networking/udhcp/Config.in |
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 1dae602ee..50595104c 100644 --- a/networking/httpd.c +++ b/networking/httpd.c | |||
@@ -3074,7 +3074,7 @@ int httpd_main(int argc UNUSED_PARAM, char **argv) | |||
3074 | salt[0] = '$'; | 3074 | salt[0] = '$'; |
3075 | salt[1] = '1'; | 3075 | salt[1] = '1'; |
3076 | salt[2] = '$'; | 3076 | salt[2] = '$'; |
3077 | crypt_make_salt(salt + 3, 4); | 3077 | crypt_make_rand64encoded(salt + 3, 8 / 2); /* 8 chars */ |
3078 | puts(pw_encrypt(pass, salt, /*cleanup:*/ 0)); | 3078 | puts(pw_encrypt(pass, salt, /*cleanup:*/ 0)); |
3079 | return 0; | 3079 | return 0; |
3080 | } | 3080 | } |
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 9f1dd67ec..9c05364ea 100644 --- a/networking/tls.c +++ b/networking/tls.c | |||
@@ -10,18 +10,19 @@ | |||
10 | //Config.src also defines FEATURE_TLS_SHA1 option | 10 | //Config.src also defines FEATURE_TLS_SHA1 option |
11 | 11 | ||
12 | //kbuild:lib-$(CONFIG_TLS) += tls.o | 12 | //kbuild:lib-$(CONFIG_TLS) += tls.o |
13 | //kbuild:lib-$(CONFIG_TLS) += tls_pstm.o | 13 | //kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_pstm.o |
14 | //kbuild:lib-$(CONFIG_TLS) += tls_pstm_montgomery_reduce.o | 14 | //kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_pstm_montgomery_reduce.o |
15 | //kbuild:lib-$(CONFIG_TLS) += tls_pstm_mul_comba.o | 15 | //kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_pstm_mul_comba.o |
16 | //kbuild:lib-$(CONFIG_TLS) += tls_pstm_sqr_comba.o | 16 | //kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_pstm_sqr_comba.o |
17 | //kbuild:lib-$(CONFIG_TLS) += tls_aes.o | 17 | //kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_aes.o |
18 | //kbuild:lib-$(CONFIG_TLS) += tls_aesgcm.o | 18 | //kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_aesgcm.o |
19 | //kbuild:lib-$(CONFIG_TLS) += tls_rsa.o | 19 | //kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_rsa.o |
20 | //kbuild:lib-$(CONFIG_TLS) += tls_fe.o | 20 | //kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_fe.o |
21 | //kbuild:lib-$(CONFIG_TLS) += tls_sp_c32.o | 21 | //kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_sp_c32.o |
22 | 22 | ||
23 | #include "tls.h" | 23 | #include "tls.h" |
24 | 24 | ||
25 | #if !ENABLE_FEATURE_TLS_SCHANNEL | ||
25 | // Usually enabled. You can disable some of them to force only | 26 | // Usually enabled. You can disable some of them to force only |
26 | // specific ciphers to be advertized to server. | 27 | // specific ciphers to be advertized to server. |
27 | // (this would not exclude code to handle disabled ciphers, no code size win) | 28 | // (this would not exclude code to handle disabled ciphers, no code size win) |
@@ -188,8 +189,6 @@ | |||
188 | #define TLS_MAX_OUTBUF (1 << 14) | 189 | #define TLS_MAX_OUTBUF (1 << 14) |
189 | 190 | ||
190 | enum { | 191 | enum { |
191 | SHA_INSIZE = 64, | ||
192 | |||
193 | AES128_KEYSIZE = 16, | 192 | AES128_KEYSIZE = 16, |
194 | AES256_KEYSIZE = 32, | 193 | AES256_KEYSIZE = 32, |
195 | 194 | ||
@@ -335,34 +334,6 @@ void FAST_FUNC tls_get_random(void *buf, unsigned len) | |||
335 | xfunc_die(); | 334 | xfunc_die(); |
336 | } | 335 | } |
337 | 336 | ||
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 | 337 | #if !TLS_DEBUG_HASH |
367 | # define hash_handshake(tls, fmt, buffer, len) \ | 338 | # define hash_handshake(tls, fmt, buffer, len) \ |
368 | hash_handshake(tls, buffer, len) | 339 | hash_handshake(tls, buffer, len) |
@@ -393,128 +364,6 @@ static void hash_handshake(tls_state_t *tls, const char *fmt, const void *buffer | |||
393 | # define TLS_MAC_SIZE(tls) (tls)->MAC_size | 364 | # define TLS_MAC_SIZE(tls) (tls)->MAC_size |
394 | #endif | 365 | #endif |
395 | 366 | ||
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: | 367 | // RFC 5246: |
519 | // 5. HMAC and the Pseudorandom Function | 368 | // 5. HMAC and the Pseudorandom Function |
520 | //... | 369 | //... |
@@ -559,7 +408,7 @@ static void prf_hmac_sha256(/*tls_state_t *tls,*/ | |||
559 | const char *label, | 408 | const char *label, |
560 | uint8_t *seed, unsigned seed_size) | 409 | uint8_t *seed, unsigned seed_size) |
561 | { | 410 | { |
562 | hmac_precomputed_t pre; | 411 | hmac_ctx_t ctx; |
563 | uint8_t a[TLS_MAX_MAC_SIZE]; | 412 | uint8_t a[TLS_MAX_MAC_SIZE]; |
564 | uint8_t *out_p = outbuf; | 413 | uint8_t *out_p = outbuf; |
565 | unsigned label_size = strlen(label); | 414 | unsigned label_size = strlen(label); |
@@ -569,26 +418,27 @@ static void prf_hmac_sha256(/*tls_state_t *tls,*/ | |||
569 | #define SEED label, label_size, seed, seed_size | 418 | #define SEED label, label_size, seed, seed_size |
570 | #define A a, MAC_size | 419 | #define A a, MAC_size |
571 | 420 | ||
572 | hmac_begin(&pre, secret, secret_size, sha256_begin); | 421 | hmac_begin(&ctx, secret, secret_size, sha256_begin_hmac); |
573 | 422 | ||
574 | /* A(1) = HMAC_hash(secret, seed) */ | 423 | /* A(1) = HMAC_hash(secret, seed) */ |
575 | hmac_sha_precomputed(&pre, a, SEED, NULL); | 424 | hmac_peek_hash(&ctx, a, SEED, NULL); |
576 | 425 | ||
577 | for (;;) { | 426 | for (;;) { |
578 | /* HMAC_hash(secret, A(1) + seed) */ | 427 | /* HMAC_hash(secret, A(1) + seed) */ |
579 | if (outbuf_size <= MAC_size) { | 428 | if (outbuf_size <= MAC_size) { |
580 | /* Last, possibly incomplete, block */ | 429 | /* Last, possibly incomplete, block */ |
581 | /* (use a[] as temp buffer) */ | 430 | /* (use a[] as temp buffer) */ |
582 | hmac_sha_precomputed(&pre, a, A, SEED, NULL); | 431 | hmac_peek_hash(&ctx, a, A, SEED, NULL); |
583 | memcpy(out_p, a, outbuf_size); | 432 | memcpy(out_p, a, outbuf_size); |
433 | hmac_uninit(&ctx); | ||
584 | return; | 434 | return; |
585 | } | 435 | } |
586 | /* Not last block. Store directly to result buffer */ | 436 | /* Not last block. Store directly to result buffer */ |
587 | hmac_sha_precomputed(&pre, out_p, A, SEED, NULL); | 437 | hmac_peek_hash(&ctx, out_p, A, SEED, NULL); |
588 | out_p += MAC_size; | 438 | out_p += MAC_size; |
589 | outbuf_size -= MAC_size; | 439 | outbuf_size -= MAC_size; |
590 | /* A(2) = HMAC_hash(secret, A(1)) */ | 440 | /* A(2) = HMAC_hash(secret, A(1)) */ |
591 | hmac_sha_precomputed(&pre, a, A, NULL); | 441 | hmac_peek_hash(&ctx, a, A, NULL); |
592 | } | 442 | } |
593 | #undef A | 443 | #undef A |
594 | #undef SECRET | 444 | #undef SECRET |
@@ -655,6 +505,32 @@ static void *tls_get_zeroed_outbuf(tls_state_t *tls, int len) | |||
655 | return record; | 505 | return record; |
656 | } | 506 | } |
657 | 507 | ||
508 | /* Calculate the HMAC over the list of blocks */ | ||
509 | #if !ENABLE_FEATURE_TLS_SHA1 | ||
510 | #define hmac_blocks(tls,out,key,key_size,...) \ | ||
511 | hmac_blocks(out,key,key_size, __VA_ARGS__) | ||
512 | #endif | ||
513 | static unsigned hmac_blocks(tls_state_t *tls, uint8_t *out, uint8_t *key, unsigned key_size, ...) | ||
514 | { | ||
515 | hmac_ctx_t ctx; | ||
516 | va_list va; | ||
517 | unsigned len; | ||
518 | |||
519 | hmac_begin(&ctx, key, key_size, | ||
520 | (ENABLE_FEATURE_TLS_SHA1 && tls->MAC_size == SHA1_OUTSIZE) | ||
521 | ? sha1_begin_hmac | ||
522 | : sha256_begin_hmac | ||
523 | ); | ||
524 | |||
525 | va_start(va, key_size); | ||
526 | hmac_hash_v(&ctx, va); | ||
527 | va_end(va); | ||
528 | |||
529 | len = hmac_end(&ctx, out); | ||
530 | hmac_uninit(&ctx); | ||
531 | return len; | ||
532 | } | ||
533 | |||
658 | static void xwrite_encrypted_and_hmac_signed(tls_state_t *tls, unsigned size, unsigned type) | 534 | static void xwrite_encrypted_and_hmac_signed(tls_state_t *tls, unsigned size, unsigned type) |
659 | { | 535 | { |
660 | uint8_t *buf = tls->outbuf + OUTBUF_PFX; | 536 | uint8_t *buf = tls->outbuf + OUTBUF_PFX; |
@@ -676,7 +552,7 @@ static void xwrite_encrypted_and_hmac_signed(tls_state_t *tls, unsigned size, un | |||
676 | xhdr->len16_lo = size & 0xff; | 552 | xhdr->len16_lo = size & 0xff; |
677 | 553 | ||
678 | /* Calculate MAC signature */ | 554 | /* Calculate MAC signature */ |
679 | hmac(tls, buf + size, /* result */ | 555 | hmac_blocks(tls, buf + size, /* result */ |
680 | tls->client_write_MAC_key, TLS_MAC_SIZE(tls), | 556 | tls->client_write_MAC_key, TLS_MAC_SIZE(tls), |
681 | &tls->write_seq64_be, sizeof(tls->write_seq64_be), | 557 | &tls->write_seq64_be, sizeof(tls->write_seq64_be), |
682 | xhdr, RECHDR_LEN, | 558 | xhdr, RECHDR_LEN, |
@@ -865,8 +741,13 @@ static void xwrite_encrypted_aesgcm(tls_state_t *tls, unsigned size, unsigned ty | |||
865 | cnt++; | 741 | cnt++; |
866 | COUNTER(nonce) = htonl(cnt); /* yes, first cnt here is 2 (!) */ | 742 | COUNTER(nonce) = htonl(cnt); /* yes, first cnt here is 2 (!) */ |
867 | aes_encrypt_one_block(&tls->aes_encrypt, nonce, scratch); | 743 | aes_encrypt_one_block(&tls->aes_encrypt, nonce, scratch); |
868 | n = remaining > AES_BLOCK_SIZE ? AES_BLOCK_SIZE : remaining; | 744 | if (remaining >= AES_BLOCK_SIZE) { |
869 | xorbuf(buf, scratch, n); | 745 | n = AES_BLOCK_SIZE; |
746 | xorbuf_AES_BLOCK_SIZE(buf, scratch); | ||
747 | } else { | ||
748 | n = remaining; | ||
749 | xorbuf(buf, scratch, n); | ||
750 | } | ||
870 | buf += n; | 751 | buf += n; |
871 | remaining -= n; | 752 | remaining -= n; |
872 | } | 753 | } |
@@ -1024,7 +905,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 (!) */ | 905 | COUNTER(nonce) = htonl(cnt); /* yes, first cnt here is 2 (!) */ |
1025 | aes_encrypt_one_block(&tls->aes_decrypt, nonce, scratch); | 906 | aes_encrypt_one_block(&tls->aes_decrypt, nonce, scratch); |
1026 | n = remaining > AES_BLOCK_SIZE ? AES_BLOCK_SIZE : remaining; | 907 | n = remaining > AES_BLOCK_SIZE ? AES_BLOCK_SIZE : remaining; |
1027 | xorbuf3(buf, scratch, buf + 8, n); | 908 | xorbuf_3(buf, scratch, buf + 8, n); |
1028 | buf += n; | 909 | buf += n; |
1029 | remaining -= n; | 910 | remaining -= n; |
1030 | } | 911 | } |
@@ -2481,3 +2362,549 @@ void FAST_FUNC tls_run_copy_loop(tls_state_t *tls, unsigned flags) | |||
2481 | } | 2362 | } |
2482 | } | 2363 | } |
2483 | } | 2364 | } |
2365 | #else | ||
2366 | |||
2367 | #if ENABLE_FEATURE_TLS_SCHANNEL_1_3 | ||
2368 | #include <subauth.h> | ||
2369 | #endif | ||
2370 | |||
2371 | #define SCHANNEL_USE_BLACKLISTS | ||
2372 | |||
2373 | #include <security.h> | ||
2374 | #include <schannel.h> | ||
2375 | |||
2376 | |||
2377 | #define BB_SCHANNEL_ISC_FLAGS \ | ||
2378 | (ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_CONFIDENTIALITY | ISC_REQ_INTEGRITY | ISC_REQ_REPLAY_DETECT | \ | ||
2379 | ISC_REQ_SEQUENCE_DETECT | ISC_REQ_STREAM | ISC_REQ_USE_SUPPLIED_CREDS) | ||
2380 | |||
2381 | static char *hresult_to_error_string(HRESULT result) { | ||
2382 | char *output = NULL; | ||
2383 | |||
2384 | FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | ||
2385 | | FORMAT_MESSAGE_IGNORE_INSERTS | | ||
2386 | FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, result, | ||
2387 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | ||
2388 | (char *) &output, 0, NULL); | ||
2389 | return output; | ||
2390 | } | ||
2391 | |||
2392 | static ssize_t tls_read(struct tls_state *state, char *buf, ssize_t len) { | ||
2393 | ssize_t amount_read = 0; | ||
2394 | |||
2395 | if (state->closed) { | ||
2396 | return 0; | ||
2397 | } | ||
2398 | |||
2399 | while (len > 0) { | ||
2400 | if (state->out_buffer && (state->out_buffer_size > 0)) { | ||
2401 | unsigned long copy_amount = | ||
2402 | min(len, (ssize_t) state->out_buffer_size); | ||
2403 | memcpy(buf, state->out_buffer, copy_amount); | ||
2404 | |||
2405 | amount_read += copy_amount; | ||
2406 | buf += copy_amount; | ||
2407 | len -= copy_amount; | ||
2408 | |||
2409 | if (copy_amount == state->out_buffer_size) { | ||
2410 | // We've used all the decrypted data | ||
2411 | // Move extra data to the front | ||
2412 | memmove(state->in_buffer, | ||
2413 | state->in_buffer + state->out_buffer_used, | ||
2414 | state->in_buffer_size - state->out_buffer_used); | ||
2415 | state->in_buffer_size -= state->out_buffer_used; | ||
2416 | |||
2417 | state->out_buffer = NULL; | ||
2418 | state->out_buffer_used = 0; | ||
2419 | state->out_buffer_size = 0; | ||
2420 | } else { | ||
2421 | state->out_buffer_size -= copy_amount; | ||
2422 | state->out_buffer += copy_amount; | ||
2423 | } | ||
2424 | } else { | ||
2425 | SECURITY_STATUS status; | ||
2426 | |||
2427 | int received; | ||
2428 | |||
2429 | SecBuffer buffers[4]; | ||
2430 | |||
2431 | SecBufferDesc desc; | ||
2432 | |||
2433 | buffers[0].BufferType = SECBUFFER_DATA; | ||
2434 | buffers[0].pvBuffer = state->in_buffer; | ||
2435 | buffers[0].cbBuffer = state->in_buffer_size; | ||
2436 | |||
2437 | buffers[1].BufferType = SECBUFFER_EMPTY; | ||
2438 | buffers[1].pvBuffer = NULL; | ||
2439 | buffers[1].cbBuffer = 0; | ||
2440 | |||
2441 | buffers[2].BufferType = SECBUFFER_EMPTY; | ||
2442 | buffers[2].pvBuffer = NULL; | ||
2443 | buffers[2].cbBuffer = 0; | ||
2444 | |||
2445 | buffers[3].BufferType = SECBUFFER_EMPTY; | ||
2446 | buffers[3].pvBuffer = NULL; | ||
2447 | buffers[3].cbBuffer = 0; | ||
2448 | |||
2449 | desc.ulVersion = SECBUFFER_VERSION; | ||
2450 | desc.pBuffers = buffers; | ||
2451 | desc.cBuffers = _countof(buffers); | ||
2452 | |||
2453 | status = DecryptMessage(&state->ctx_handle, &desc, 0, NULL); | ||
2454 | |||
2455 | switch (status) { | ||
2456 | case SEC_E_OK:{ | ||
2457 | state->out_buffer = buffers[1].pvBuffer; | ||
2458 | state->out_buffer_size = buffers[1].cbBuffer; | ||
2459 | |||
2460 | state->out_buffer_used = state->in_buffer_size; | ||
2461 | if (buffers[3].BufferType == SECBUFFER_EXTRA) { | ||
2462 | state->out_buffer_used -= buffers[3].cbBuffer; | ||
2463 | } | ||
2464 | |||
2465 | continue; | ||
2466 | } | ||
2467 | case SEC_I_CONTEXT_EXPIRED:{ | ||
2468 | state->closed = 1; | ||
2469 | goto Success; | ||
2470 | } | ||
2471 | case SEC_I_RENEGOTIATE:{ | ||
2472 | // Renegotiate the TLS connection. | ||
2473 | // Microsoft repurposed this flag | ||
2474 | // for TLS 1.3 support. | ||
2475 | int i; | ||
2476 | |||
2477 | DWORD flags; | ||
2478 | |||
2479 | SecBuffer in_buffers[2]; | ||
2480 | |||
2481 | SecBuffer out_buffers[2]; | ||
2482 | |||
2483 | SecBufferDesc in_desc; | ||
2484 | |||
2485 | SecBufferDesc out_desc; | ||
2486 | |||
2487 | |||
2488 | for (i = 0; i < 4; i++) { | ||
2489 | if (buffers[i].BufferType == SECBUFFER_EXTRA) | ||
2490 | break; | ||
2491 | } | ||
2492 | |||
2493 | flags = BB_SCHANNEL_ISC_FLAGS; | ||
2494 | |||
2495 | in_buffers[0].BufferType = SECBUFFER_TOKEN; | ||
2496 | in_buffers[0].pvBuffer = buffers[i].pvBuffer; | ||
2497 | in_buffers[0].cbBuffer = buffers[i].cbBuffer; | ||
2498 | |||
2499 | in_buffers[1].BufferType = SECBUFFER_EMPTY; | ||
2500 | in_buffers[1].pvBuffer = NULL; | ||
2501 | in_buffers[1].cbBuffer = 0; | ||
2502 | |||
2503 | out_buffers[0].BufferType = SECBUFFER_TOKEN; | ||
2504 | out_buffers[0].pvBuffer = NULL; | ||
2505 | out_buffers[0].cbBuffer = 0; | ||
2506 | |||
2507 | out_buffers[1].BufferType = SECBUFFER_ALERT; | ||
2508 | out_buffers[1].pvBuffer = NULL; | ||
2509 | out_buffers[1].cbBuffer = 0; | ||
2510 | |||
2511 | in_desc.ulVersion = SECBUFFER_VERSION; | ||
2512 | in_desc.pBuffers = in_buffers; | ||
2513 | in_desc.cBuffers = _countof(in_buffers); | ||
2514 | |||
2515 | out_desc.ulVersion = SECBUFFER_VERSION; | ||
2516 | out_desc.pBuffers = out_buffers; | ||
2517 | out_desc.cBuffers = _countof(out_buffers); | ||
2518 | |||
2519 | status = InitializeSecurityContext(&state->cred_handle, | ||
2520 | state->initialized ? | ||
2521 | &state->ctx_handle : NULL, | ||
2522 | state->initialized ? NULL : | ||
2523 | state->hostname, flags, 0, | ||
2524 | 0, | ||
2525 | state->initialized ? | ||
2526 | &in_desc : NULL, 0, | ||
2527 | state->initialized ? NULL : | ||
2528 | &state->ctx_handle, | ||
2529 | &out_desc, &flags, 0); | ||
2530 | |||
2531 | if (status != SEC_E_OK) { | ||
2532 | bb_error_msg_and_die("schannel: renegotiate failed: (0x%08lx): %s", | ||
2533 | status, hresult_to_error_string(status)); | ||
2534 | } | ||
2535 | |||
2536 | if (in_buffers[1].BufferType == SECBUFFER_EXTRA) { | ||
2537 | memmove(state->in_buffer, | ||
2538 | state->in_buffer + (state->in_buffer_size - | ||
2539 | in_buffers[1].cbBuffer), | ||
2540 | in_buffers[1].cbBuffer); | ||
2541 | } | ||
2542 | |||
2543 | state->out_buffer_used = | ||
2544 | state->in_buffer_size - in_buffers[1].cbBuffer; | ||
2545 | state->in_buffer_size = in_buffers[1].cbBuffer; | ||
2546 | |||
2547 | continue; | ||
2548 | } | ||
2549 | case SEC_E_INCOMPLETE_MESSAGE:{ | ||
2550 | break; | ||
2551 | } | ||
2552 | default:{ | ||
2553 | bb_error_msg_and_die("schannel: DecryptMessage failed: (0x%08lx): %s", status, | ||
2554 | hresult_to_error_string(status)); | ||
2555 | } | ||
2556 | } | ||
2557 | |||
2558 | received = | ||
2559 | safe_read(state->ifd, | ||
2560 | state->in_buffer + state->in_buffer_size, | ||
2561 | sizeof(state->in_buffer) - state->in_buffer_size); | ||
2562 | if (received == 0) { | ||
2563 | state->closed = 1; | ||
2564 | goto Success; | ||
2565 | } else if (received < 0) { | ||
2566 | bb_error_msg_and_die("schannel: read() failed"); | ||
2567 | } | ||
2568 | |||
2569 | state->in_buffer_size += received; | ||
2570 | } | ||
2571 | } | ||
2572 | |||
2573 | Success: | ||
2574 | return amount_read; | ||
2575 | } | ||
2576 | |||
2577 | static void tls_write(struct tls_state *state, char *buf, size_t len) { | ||
2578 | if (state->closed) { | ||
2579 | bb_error_msg_and_die("schannel: attempted to write to a closed connection"); | ||
2580 | } | ||
2581 | |||
2582 | while (len > 0) { | ||
2583 | unsigned long copy_amount = | ||
2584 | min(len, (size_t) state->stream_sizes.cbMaximumMessage); | ||
2585 | char *write_buffer = _alloca(sizeof(state->in_buffer)); | ||
2586 | |||
2587 | SECURITY_STATUS status; | ||
2588 | |||
2589 | SecBuffer buffers[4]; | ||
2590 | |||
2591 | SecBufferDesc desc; | ||
2592 | |||
2593 | buffers[0].BufferType = SECBUFFER_STREAM_HEADER; | ||
2594 | buffers[0].pvBuffer = write_buffer; | ||
2595 | buffers[0].cbBuffer = state->stream_sizes.cbHeader; | ||
2596 | |||
2597 | buffers[1].BufferType = SECBUFFER_DATA; | ||
2598 | buffers[1].pvBuffer = write_buffer + state->stream_sizes.cbHeader; | ||
2599 | buffers[1].cbBuffer = copy_amount; | ||
2600 | |||
2601 | buffers[2].BufferType = SECBUFFER_STREAM_TRAILER; | ||
2602 | buffers[2].pvBuffer = | ||
2603 | write_buffer + state->stream_sizes.cbHeader + copy_amount; | ||
2604 | buffers[2].cbBuffer = state->stream_sizes.cbTrailer; | ||
2605 | |||
2606 | buffers[3].BufferType = SECBUFFER_EMPTY; | ||
2607 | buffers[3].pvBuffer = NULL; | ||
2608 | buffers[3].cbBuffer = 0; | ||
2609 | |||
2610 | memcpy(buffers[1].pvBuffer, buf, copy_amount); | ||
2611 | |||
2612 | desc.ulVersion = SECBUFFER_VERSION; | ||
2613 | desc.pBuffers = buffers; | ||
2614 | desc.cBuffers = _countof(buffers); | ||
2615 | |||
2616 | status = EncryptMessage(&state->ctx_handle, 0, &desc, 0); | ||
2617 | if (status != SEC_E_OK) { | ||
2618 | bb_error_msg_and_die("schannel: EncryptMessage failed: (0x%08lx): %s", status, | ||
2619 | hresult_to_error_string(status)); | ||
2620 | } | ||
2621 | |||
2622 | xwrite(state->ofd, write_buffer, | ||
2623 | buffers[0].cbBuffer + buffers[1].cbBuffer + | ||
2624 | buffers[2].cbBuffer); | ||
2625 | |||
2626 | len -= copy_amount; | ||
2627 | } | ||
2628 | } | ||
2629 | |||
2630 | static void tls_disconnect(tls_state_t * state) { | ||
2631 | SECURITY_STATUS status; | ||
2632 | DWORD token = SCHANNEL_SHUTDOWN; | ||
2633 | DWORD flags = BB_SCHANNEL_ISC_FLAGS; | ||
2634 | |||
2635 | SecBuffer buf_token; | ||
2636 | |||
2637 | SecBufferDesc buf_token_desc; | ||
2638 | |||
2639 | SecBuffer in_buffers[2]; | ||
2640 | SecBuffer out_buffers[2]; | ||
2641 | |||
2642 | SecBufferDesc in_desc; | ||
2643 | SecBufferDesc out_desc; | ||
2644 | |||
2645 | buf_token.BufferType = SECBUFFER_TOKEN; | ||
2646 | buf_token.pvBuffer = &token; | ||
2647 | buf_token.cbBuffer = sizeof(token); | ||
2648 | |||
2649 | buf_token_desc.ulVersion = SECBUFFER_VERSION; | ||
2650 | buf_token_desc.pBuffers = &buf_token; | ||
2651 | buf_token_desc.cBuffers = 1; | ||
2652 | |||
2653 | ApplyControlToken(&state->ctx_handle, &buf_token_desc); | ||
2654 | |||
2655 | // attempt to send any final data | ||
2656 | |||
2657 | in_buffers[0].BufferType = SECBUFFER_TOKEN; | ||
2658 | in_buffers[0].pvBuffer = state->in_buffer; | ||
2659 | in_buffers[0].cbBuffer = state->in_buffer_size; | ||
2660 | |||
2661 | in_buffers[1].BufferType = SECBUFFER_EMPTY; | ||
2662 | in_buffers[1].pvBuffer = NULL; | ||
2663 | in_buffers[1].cbBuffer = 0; | ||
2664 | |||
2665 | out_buffers[0].BufferType = SECBUFFER_TOKEN; | ||
2666 | out_buffers[0].pvBuffer = NULL; | ||
2667 | out_buffers[0].cbBuffer = 0; | ||
2668 | |||
2669 | out_buffers[1].BufferType = SECBUFFER_ALERT; | ||
2670 | out_buffers[1].pvBuffer = NULL; | ||
2671 | out_buffers[1].cbBuffer = 0; | ||
2672 | |||
2673 | in_desc.ulVersion = SECBUFFER_VERSION; | ||
2674 | in_desc.pBuffers = in_buffers; | ||
2675 | in_desc.cBuffers = _countof(in_buffers); | ||
2676 | |||
2677 | out_desc.ulVersion = SECBUFFER_VERSION; | ||
2678 | out_desc.pBuffers = out_buffers; | ||
2679 | out_desc.cBuffers = _countof(out_buffers); | ||
2680 | |||
2681 | status = InitializeSecurityContext(&state->cred_handle, | ||
2682 | state-> | ||
2683 | initialized ? &state->ctx_handle : | ||
2684 | NULL, | ||
2685 | state-> | ||
2686 | initialized ? NULL : state->hostname, | ||
2687 | flags, 0, 0, | ||
2688 | state->initialized ? &in_desc : NULL, | ||
2689 | 0, | ||
2690 | state-> | ||
2691 | initialized ? NULL : | ||
2692 | &state->ctx_handle, &out_desc, &flags, | ||
2693 | 0); | ||
2694 | |||
2695 | if (status == SEC_E_OK) { | ||
2696 | // attempt to write any extra data | ||
2697 | write(state->ofd, out_buffers[0].pvBuffer, out_buffers[0].cbBuffer); | ||
2698 | } | ||
2699 | |||
2700 | DeleteSecurityContext(&state->ctx_handle); | ||
2701 | FreeCredentialsHandle(&state->cred_handle); | ||
2702 | free(state->hostname); | ||
2703 | } | ||
2704 | |||
2705 | |||
2706 | void FAST_FUNC tls_handshake(tls_state_t * state, const char *hostname) { | ||
2707 | SECURITY_STATUS status; | ||
2708 | int received; | ||
2709 | |||
2710 | #if ENABLE_FEATURE_TLS_SCHANNEL_1_3 | ||
2711 | SCH_CREDENTIALS credential = {.dwVersion = SCH_CREDENTIALS_VERSION, | ||
2712 | .dwCredFormat = 0, | ||
2713 | .cCreds = 0, | ||
2714 | .paCred = NULL, | ||
2715 | .hRootStore = NULL, | ||
2716 | .cMappers = 0, | ||
2717 | .aphMappers = NULL, | ||
2718 | .dwSessionLifespan = 0, | ||
2719 | .dwFlags = | ||
2720 | SCH_CRED_AUTO_CRED_VALIDATION | SCH_CRED_NO_DEFAULT_CREDS | | ||
2721 | SCH_USE_STRONG_CRYPTO, | ||
2722 | .cTlsParameters = 0, | ||
2723 | .pTlsParameters = NULL | ||
2724 | }; | ||
2725 | #else | ||
2726 | SCHANNEL_CRED credential = {.dwVersion = SCHANNEL_CRED_VERSION, | ||
2727 | .cCreds = 0, | ||
2728 | .paCred = NULL, | ||
2729 | .hRootStore = NULL, | ||
2730 | .cMappers = 0, | ||
2731 | .aphMappers = NULL, | ||
2732 | .cSupportedAlgs = 0, | ||
2733 | .palgSupportedAlgs = NULL, | ||
2734 | .grbitEnabledProtocols = | ||
2735 | SP_PROT_TLS1_0_CLIENT | SP_PROT_TLS1_1_CLIENT | | ||
2736 | SP_PROT_TLS1_2_CLIENT, | ||
2737 | .dwMinimumCipherStrength = 0, | ||
2738 | .dwMaximumCipherStrength = 0, | ||
2739 | .dwSessionLifespan = 0, | ||
2740 | .dwFlags = | ||
2741 | SCH_CRED_AUTO_CRED_VALIDATION | SCH_CRED_NO_DEFAULT_CREDS | | ||
2742 | SCH_USE_STRONG_CRYPTO, | ||
2743 | .dwCredFormat = 0 | ||
2744 | }; | ||
2745 | #endif | ||
2746 | |||
2747 | if ((status = AcquireCredentialsHandleA(NULL, (SEC_CHAR *) UNISP_NAME_A, | ||
2748 | SECPKG_CRED_OUTBOUND, NULL, | ||
2749 | &credential, | ||
2750 | NULL, NULL, &state->cred_handle, | ||
2751 | NULL)) != SEC_E_OK) { | ||
2752 | bb_error_msg_and_die("schannel: AcquireCredentialsHandleA failed: (0x%08lx): %s", | ||
2753 | status, hresult_to_error_string(status)); | ||
2754 | } | ||
2755 | |||
2756 | state->in_buffer_size = 0; | ||
2757 | state->out_buffer_size = 0; | ||
2758 | state->out_buffer_used = 0; | ||
2759 | |||
2760 | state->out_buffer = NULL; | ||
2761 | |||
2762 | state->hostname = strdup(hostname); | ||
2763 | |||
2764 | state->initialized = 0; | ||
2765 | state->closed = 0; | ||
2766 | |||
2767 | while (1) { | ||
2768 | DWORD flags = BB_SCHANNEL_ISC_FLAGS; | ||
2769 | |||
2770 | SecBuffer in_buffers[2]; | ||
2771 | SecBuffer out_buffers[2]; | ||
2772 | |||
2773 | SecBufferDesc in_desc; | ||
2774 | SecBufferDesc out_desc; | ||
2775 | |||
2776 | in_buffers[0].BufferType = SECBUFFER_TOKEN; | ||
2777 | in_buffers[0].pvBuffer = state->in_buffer; | ||
2778 | in_buffers[0].cbBuffer = state->in_buffer_size; | ||
2779 | |||
2780 | in_buffers[1].BufferType = SECBUFFER_EMPTY; | ||
2781 | in_buffers[1].pvBuffer = NULL; | ||
2782 | in_buffers[1].cbBuffer = 0; | ||
2783 | |||
2784 | out_buffers[0].BufferType = SECBUFFER_TOKEN; | ||
2785 | out_buffers[0].pvBuffer = NULL; | ||
2786 | out_buffers[0].cbBuffer = 0; | ||
2787 | |||
2788 | out_buffers[1].BufferType = SECBUFFER_ALERT; | ||
2789 | out_buffers[1].pvBuffer = NULL; | ||
2790 | out_buffers[1].cbBuffer = 0; | ||
2791 | |||
2792 | in_desc.ulVersion = SECBUFFER_VERSION; | ||
2793 | in_desc.pBuffers = in_buffers; | ||
2794 | in_desc.cBuffers = _countof(in_buffers); | ||
2795 | |||
2796 | out_desc.ulVersion = SECBUFFER_VERSION; | ||
2797 | out_desc.pBuffers = out_buffers; | ||
2798 | out_desc.cBuffers = _countof(out_buffers); | ||
2799 | |||
2800 | status = InitializeSecurityContext(&state->cred_handle, | ||
2801 | state-> | ||
2802 | initialized ? &state->ctx_handle : | ||
2803 | NULL, | ||
2804 | state-> | ||
2805 | initialized ? NULL : | ||
2806 | state->hostname, flags, 0, 0, | ||
2807 | state->initialized ? &in_desc : | ||
2808 | NULL, 0, | ||
2809 | state->initialized ? NULL : | ||
2810 | &state->ctx_handle, &out_desc, | ||
2811 | &flags, 0); | ||
2812 | |||
2813 | state->initialized = 1; | ||
2814 | |||
2815 | if (in_buffers[1].BufferType == SECBUFFER_EXTRA) { | ||
2816 | memmove(state->in_buffer, | ||
2817 | state->in_buffer + (state->in_buffer_size - | ||
2818 | in_buffers[1].cbBuffer), | ||
2819 | in_buffers[1].cbBuffer); | ||
2820 | state->in_buffer_size = in_buffers[1].cbBuffer; | ||
2821 | } else if (status != SEC_E_INCOMPLETE_MESSAGE) { | ||
2822 | state->in_buffer_size = 0; | ||
2823 | } | ||
2824 | |||
2825 | switch (status) { | ||
2826 | case SEC_E_OK:{ | ||
2827 | if (out_buffers[0].cbBuffer > 0) { | ||
2828 | xwrite(state->ofd, out_buffers[0].pvBuffer, | ||
2829 | out_buffers[0].cbBuffer); | ||
2830 | FreeContextBuffer(out_buffers[0].pvBuffer); | ||
2831 | } | ||
2832 | goto Success; | ||
2833 | } | ||
2834 | case SEC_I_CONTINUE_NEEDED:{ | ||
2835 | xwrite(state->ofd, out_buffers[0].pvBuffer, | ||
2836 | out_buffers[0].cbBuffer); | ||
2837 | FreeContextBuffer(out_buffers[0].pvBuffer); | ||
2838 | break; | ||
2839 | } | ||
2840 | case SEC_I_INCOMPLETE_CREDENTIALS:{ | ||
2841 | // we don't support this | ||
2842 | bb_error_msg_and_die("schannel: client certificates not supported"); | ||
2843 | } | ||
2844 | case SEC_E_INCOMPLETE_MESSAGE:{ | ||
2845 | break; | ||
2846 | } | ||
2847 | default:{ | ||
2848 | bb_error_msg_and_die("schannel: handshake failed: (0x%08lx): %s", | ||
2849 | status, hresult_to_error_string(status)); | ||
2850 | } | ||
2851 | } | ||
2852 | |||
2853 | received = | ||
2854 | safe_read(state->ifd, state->in_buffer + state->in_buffer_size, | ||
2855 | sizeof(state->in_buffer) - state->in_buffer_size); | ||
2856 | if (received <= 0) { | ||
2857 | bb_error_msg_and_die("schannel: handshake read() failed"); | ||
2858 | } | ||
2859 | state->in_buffer_size += received; | ||
2860 | } | ||
2861 | |||
2862 | Success: | ||
2863 | QueryContextAttributes(&state->ctx_handle, SECPKG_ATTR_STREAM_SIZES, | ||
2864 | &state->stream_sizes); | ||
2865 | |||
2866 | //SecPkgContext_ConnectionInfo info; | ||
2867 | //QueryContextAttributes(&state->ctx_handle, SECPKG_ATTR_CONNECTION_INFO, | ||
2868 | // &info); | ||
2869 | // | ||
2870 | //fprintf(stderr, "TLS 1.%d\n", (((uint32_t)(8 * sizeof(unsigned long long) - __builtin_clzll((info.dwProtocol)) - 1)) - 7)/2); | ||
2871 | } | ||
2872 | |||
2873 | void FAST_FUNC tls_run_copy_loop(tls_state_t * tls, unsigned flags) { | ||
2874 | char buffer[65536]; | ||
2875 | |||
2876 | struct pollfd pfds[2]; | ||
2877 | |||
2878 | pfds[0].fd = STDIN_FILENO; | ||
2879 | pfds[0].events = POLLIN; | ||
2880 | pfds[1].fd = tls->ifd; | ||
2881 | pfds[1].events = POLLIN; | ||
2882 | |||
2883 | for (;;) { | ||
2884 | int nread; | ||
2885 | |||
2886 | if (safe_poll(pfds, 2, -1) < 0) | ||
2887 | bb_simple_perror_msg_and_die("poll"); | ||
2888 | |||
2889 | if (pfds[0].revents) { | ||
2890 | nread = safe_read(STDIN_FILENO, buffer, sizeof(buffer)); | ||
2891 | if (nread < 1) { | ||
2892 | pfds[0].fd = -1; | ||
2893 | tls_disconnect(tls); | ||
2894 | if (flags & TLSLOOP_EXIT_ON_LOCAL_EOF) | ||
2895 | break; | ||
2896 | } else { | ||
2897 | tls_write(tls, buffer, nread); | ||
2898 | } | ||
2899 | } | ||
2900 | if (pfds[1].revents) { | ||
2901 | nread = tls_read(tls, buffer, sizeof(buffer)); | ||
2902 | if (nread < 1) { | ||
2903 | tls_disconnect(tls); | ||
2904 | break; | ||
2905 | } | ||
2906 | xwrite(STDOUT_FILENO, buffer, nread); | ||
2907 | } | ||
2908 | } | ||
2909 | } | ||
2910 | #endif | ||
diff --git a/networking/tls.h b/networking/tls.h index 0173b87b2..eee5a7617 100644 --- a/networking/tls.h +++ b/networking/tls.h | |||
@@ -11,6 +11,7 @@ | |||
11 | #include "libbb.h" | 11 | #include "libbb.h" |
12 | 12 | ||
13 | 13 | ||
14 | #if !ENABLE_FEATURE_TLS_SCHANNEL | ||
14 | /* Config tweaks */ | 15 | /* Config tweaks */ |
15 | #define HAVE_NATIVE_INT64 | 16 | #define HAVE_NATIVE_INT64 |
16 | #undef USE_1024_KEY_SPEED_OPTIMIZATIONS | 17 | #undef USE_1024_KEY_SPEED_OPTIMIZATIONS |
@@ -82,10 +83,9 @@ typedef int16_t int16; | |||
82 | 83 | ||
83 | void tls_get_random(void *buf, unsigned len) FAST_FUNC; | 84 | void tls_get_random(void *buf, unsigned len) FAST_FUNC; |
84 | 85 | ||
85 | void xorbuf(void* buf, const void* mask, unsigned count) FAST_FUNC; | ||
86 | |||
87 | #define ALIGNED_long ALIGNED(sizeof(long)) | 86 | #define ALIGNED_long ALIGNED(sizeof(long)) |
88 | void xorbuf_aligned_AES_BLOCK_SIZE(void* buf, const void* mask) FAST_FUNC; | 87 | #define xorbuf_aligned_AES_BLOCK_SIZE(dst,src) xorbuf16_aligned_long(dst,src) |
88 | #define xorbuf_AES_BLOCK_SIZE(dst,src) xorbuf16(dst,src) | ||
89 | 89 | ||
90 | #define matrixCryptoGetPrngData(buf, len, userPtr) (tls_get_random(buf, len), PS_SUCCESS) | 90 | #define matrixCryptoGetPrngData(buf, len, userPtr) (tls_get_random(buf, len), PS_SUCCESS) |
91 | 91 | ||
@@ -120,3 +120,4 @@ void curve_P256_compute_pubkey_and_premaster( | |||
120 | void curve_P256_compute_pubkey_and_premaster_NEW( | 120 | void curve_P256_compute_pubkey_and_premaster_NEW( |
121 | uint8_t *pubkey2x32, uint8_t *premaster32, | 121 | uint8_t *pubkey2x32, uint8_t *premaster32, |
122 | const uint8_t *peerkey2x32) FAST_FUNC; | 122 | const uint8_t *peerkey2x32) FAST_FUNC; |
123 | #endif | ||
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/runit/chpst.c b/runit/chpst.c index 2be1a5775..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)" |
@@ -466,7 +467,8 @@ int chpst_main(int argc UNUSED_PARAM, char **argv) | |||
466 | /* nice should be done before xsetuid */ | 467 | /* nice should be done before xsetuid */ |
467 | if (opt & OPT_n) { | 468 | if (opt & OPT_n) { |
468 | errno = 0; | 469 | errno = 0; |
469 | if (nice(xatoi(nicestr)) == -1) | 470 | nice(xatoi(nicestr)); |
471 | if (errno) | ||
470 | bb_simple_perror_msg_and_die("nice"); | 472 | bb_simple_perror_msg_and_die("nice"); |
471 | } | 473 | } |
472 | 474 | ||
diff --git a/scripts/kconfig/libcurses/addch.c b/scripts/kconfig/libcurses/addch.c index f3c25d389..3d1f9c04b 100644 --- a/scripts/kconfig/libcurses/addch.c +++ b/scripts/kconfig/libcurses/addch.c | |||
@@ -90,23 +90,25 @@ addch | |||
90 | All functions return OK on success and ERR on error. | 90 | All functions return OK on success and ERR on error. |
91 | 91 | ||
92 | ### Portability | 92 | ### Portability |
93 | X/Open ncurses NetBSD | 93 | |
94 | addch Y Y Y | 94 | Function | X/Open | ncurses | NetBSD |
95 | waddch Y Y Y | 95 | :---------------------|:------:|:-------:|:------: |
96 | mvaddch Y Y Y | 96 | addch | Y | Y | Y |
97 | mvwaddch Y Y Y | 97 | waddch | Y | Y | Y |
98 | echochar Y Y Y | 98 | mvaddch | Y | Y | Y |
99 | wechochar Y Y Y | 99 | mvwaddch | Y | Y | Y |
100 | add_wch Y Y Y | 100 | echochar | Y | Y | Y |
101 | wadd_wch Y Y Y | 101 | wechochar | Y | Y | Y |
102 | mvadd_wch Y Y Y | 102 | add_wch | Y | Y | Y |
103 | mvwadd_wch Y Y Y | 103 | wadd_wch | Y | Y | Y |
104 | echo_wchar Y Y Y | 104 | mvadd_wch | Y | Y | Y |
105 | wecho_wchar Y Y Y | 105 | mvwadd_wch | Y | Y | Y |
106 | addrawch - - - | 106 | echo_wchar | Y | Y | Y |
107 | waddrawch - - - | 107 | wecho_wchar | Y | Y | Y |
108 | mvaddrawch - - - | 108 | addrawch | - | - | - |
109 | mvwaddrawch - - - | 109 | waddrawch | - | - | - |
110 | mvaddrawch | - | - | - | ||
111 | mvwaddrawch | - | - | - | ||
110 | 112 | ||
111 | **man-end****************************************************************/ | 113 | **man-end****************************************************************/ |
112 | 114 | ||
diff --git a/scripts/kconfig/libcurses/addstr.c b/scripts/kconfig/libcurses/addstr.c index 47f8f4e10..bc286d4b5 100644 --- a/scripts/kconfig/libcurses/addstr.c +++ b/scripts/kconfig/libcurses/addstr.c | |||
@@ -43,23 +43,25 @@ addstr | |||
43 | All functions return OK or ERR. | 43 | All functions return OK or ERR. |
44 | 44 | ||
45 | ### Portability | 45 | ### Portability |
46 | X/Open ncurses NetBSD | 46 | |
47 | addstr Y Y Y | 47 | Function | X/Open | ncurses | NetBSD |
48 | waddstr Y Y Y | 48 | :---------------------|:------:|:-------:|:------: |
49 | mvaddstr Y Y Y | 49 | addstr | Y | Y | Y |
50 | mvwaddstr Y Y Y | 50 | waddstr | Y | Y | Y |
51 | addnstr Y Y Y | 51 | mvaddstr | Y | Y | Y |
52 | waddnstr Y Y Y | 52 | mvwaddstr | Y | Y | Y |
53 | mvaddnstr Y Y Y | 53 | addnstr | Y | Y | Y |
54 | mvwaddnstr Y Y Y | 54 | waddnstr | Y | Y | Y |
55 | addwstr Y Y Y | 55 | mvaddnstr | Y | Y | Y |
56 | waddwstr Y Y Y | 56 | mvwaddnstr | Y | Y | Y |
57 | mvaddwstr Y Y Y | 57 | addwstr | Y | Y | Y |
58 | mvwaddwstr Y Y Y | 58 | waddwstr | Y | Y | Y |
59 | addnwstr Y Y Y | 59 | mvaddwstr | Y | Y | Y |
60 | waddnwstr Y Y Y | 60 | mvwaddwstr | Y | Y | Y |
61 | mvaddnwstr Y Y Y | 61 | addnwstr | Y | Y | Y |
62 | mvwaddnwstr Y Y Y | 62 | waddnwstr | Y | Y | Y |
63 | mvaddnwstr | Y | Y | Y | ||
64 | mvwaddnwstr | Y | Y | Y | ||
63 | 65 | ||
64 | **man-end****************************************************************/ | 66 | **man-end****************************************************************/ |
65 | 67 | ||
diff --git a/scripts/kconfig/libcurses/attr.c b/scripts/kconfig/libcurses/attr.c index 3ab5a5637..d7bc36c73 100644 --- a/scripts/kconfig/libcurses/attr.c +++ b/scripts/kconfig/libcurses/attr.c | |||
@@ -96,36 +96,38 @@ attr | |||
96 | All functions return OK on success and ERR on error. | 96 | All functions return OK on success and ERR on error. |
97 | 97 | ||
98 | ### Portability | 98 | ### Portability |
99 | X/Open ncurses NetBSD | 99 | |
100 | attroff Y Y Y | 100 | Function | X/Open | ncurses | NetBSD |
101 | wattroff Y Y Y | 101 | :---------------------|:------:|:-------:|:------: |
102 | attron Y Y Y | 102 | attroff | Y | Y | Y |
103 | wattron Y Y Y | 103 | wattroff | Y | Y | Y |
104 | attrset Y Y Y | 104 | attron | Y | Y | Y |
105 | wattrset Y Y Y | 105 | wattron | Y | Y | Y |
106 | standend Y Y Y | 106 | attrset | Y | Y | Y |
107 | wstandend Y Y Y | 107 | wattrset | Y | Y | Y |
108 | standout Y Y Y | 108 | standend | Y | Y | Y |
109 | wstandout Y Y Y | 109 | wstandend | Y | Y | Y |
110 | color_set Y Y Y | 110 | standout | Y | Y | Y |
111 | wcolor_set Y Y Y | 111 | wstandout | Y | Y | Y |
112 | attr_get Y Y Y | 112 | color_set | Y | Y | Y |
113 | wattr_get Y Y Y | 113 | wcolor_set | Y | Y | Y |
114 | attr_on Y Y Y | 114 | attr_get | Y | Y | Y |
115 | wattr_on Y Y Y | 115 | wattr_get | Y | Y | Y |
116 | attr_off Y Y Y | 116 | attr_on | Y | Y | Y |
117 | wattr_off Y Y Y | 117 | wattr_on | Y | Y | Y |
118 | attr_set Y Y Y | 118 | attr_off | Y | Y | Y |
119 | wattr_set Y Y Y | 119 | wattr_off | Y | Y | Y |
120 | chgat Y Y Y | 120 | attr_set | Y | Y | Y |
121 | wchgat Y Y Y | 121 | wattr_set | Y | Y | Y |
122 | mvchgat Y Y Y | 122 | chgat | Y | Y | Y |
123 | mvwchgat Y Y Y | 123 | wchgat | Y | Y | Y |
124 | getattrs - Y Y | 124 | mvchgat | Y | Y | Y |
125 | underend - - Y | 125 | mvwchgat | Y | Y | Y |
126 | wunderend - - Y | 126 | getattrs | - | Y | Y |
127 | underscore - - Y | 127 | underend | - | - | Y |
128 | wunderscore - - Y | 128 | wunderend | - | - | Y |
129 | underscore | - | - | Y | ||
130 | wunderscore | - | - | Y | ||
129 | 131 | ||
130 | **man-end****************************************************************/ | 132 | **man-end****************************************************************/ |
131 | 133 | ||
diff --git a/scripts/kconfig/libcurses/beep.c b/scripts/kconfig/libcurses/beep.c index 0b97137fd..b679eed3c 100644 --- a/scripts/kconfig/libcurses/beep.c +++ b/scripts/kconfig/libcurses/beep.c | |||
@@ -26,9 +26,11 @@ beep | |||
26 | These functions return ERR if called before initscr(), otherwise OK. | 26 | These functions return ERR if called before initscr(), otherwise OK. |
27 | 27 | ||
28 | ### Portability | 28 | ### Portability |
29 | X/Open ncurses NetBSD | 29 | |
30 | beep Y Y Y | 30 | Function | X/Open | ncurses | NetBSD |
31 | flash Y Y Y | 31 | :---------------------|:------:|:-------:|:------: |
32 | beep | Y | Y | Y | ||
33 | flash | Y | Y | Y | ||
32 | 34 | ||
33 | **man-end****************************************************************/ | 35 | **man-end****************************************************************/ |
34 | 36 | ||
diff --git a/scripts/kconfig/libcurses/bkgd.c b/scripts/kconfig/libcurses/bkgd.c index af2d0e054..c92df28be 100644 --- a/scripts/kconfig/libcurses/bkgd.c +++ b/scripts/kconfig/libcurses/bkgd.c | |||
@@ -48,18 +48,20 @@ bkgd | |||
48 | case they return ERR. | 48 | case they return ERR. |
49 | 49 | ||
50 | ### Portability | 50 | ### Portability |
51 | X/Open ncurses NetBSD | 51 | |
52 | bkgd Y Y Y | 52 | Function | X/Open | ncurses | NetBSD |
53 | bkgdset Y Y Y | 53 | :---------------------|:------:|:-------:|:------: |
54 | getbkgd Y Y Y | 54 | bkgd | Y | Y | Y |
55 | wbkgd Y Y Y | 55 | bkgdset | Y | Y | Y |
56 | wbkgdset Y Y Y | 56 | getbkgd | Y | Y | Y |
57 | bkgrnd Y Y Y | 57 | wbkgd | Y | Y | Y |
58 | bkgrndset Y Y Y | 58 | wbkgdset | Y | Y | Y |
59 | getbkgrnd Y Y Y | 59 | bkgrnd | Y | Y | Y |
60 | wbkgrnd Y Y Y | 60 | bkgrndset | Y | Y | Y |
61 | wbkgrndset Y Y Y | 61 | getbkgrnd | Y | Y | Y |
62 | wgetbkgrnd Y Y Y | 62 | wbkgrnd | Y | Y | Y |
63 | wbkgrndset | Y | Y | Y | ||
64 | wgetbkgrnd | Y | Y | Y | ||
63 | 65 | ||
64 | **man-end****************************************************************/ | 66 | **man-end****************************************************************/ |
65 | 67 | ||
diff --git a/scripts/kconfig/libcurses/border.c b/scripts/kconfig/libcurses/border.c index 302c46ea2..409f2351a 100644 --- a/scripts/kconfig/libcurses/border.c +++ b/scripts/kconfig/libcurses/border.c | |||
@@ -46,14 +46,16 @@ border | |||
46 | border(), wborder(), and box() draw a border around the edge of the | 46 | border(), wborder(), and box() draw a border around the edge of the |
47 | window. If any argument is zero, an appropriate default is used: | 47 | window. If any argument is zero, an appropriate default is used: |
48 | 48 | ||
49 | ls left side of border ACS_VLINE | 49 | Name | Element | Default |
50 | rs right side of border ACS_VLINE | 50 | :----|:------------------------------|:------------ |
51 | ts top side of border ACS_HLINE | 51 | ls | left side of border | ACS_VLINE |
52 | bs bottom side of border ACS_HLINE | 52 | rs | right side of border | ACS_VLINE |
53 | tl top left corner of border ACS_ULCORNER | 53 | ts | top side of border | ACS_HLINE |
54 | tr top right corner of border ACS_URCORNER | 54 | bs | bottom side of border | ACS_HLINE |
55 | bl bottom left corner of border ACS_LLCORNER | 55 | tl | top left corner of border | ACS_ULCORNER |
56 | br bottom right corner of border ACS_LRCORNER | 56 | tr | top right corner of border | ACS_URCORNER |
57 | bl | bottom left corner of border | ACS_LLCORNER | ||
58 | br | bottom right corner of border | ACS_LRCORNER | ||
57 | 59 | ||
58 | hline() and whline() draw a horizontal line, using ch, starting from | 60 | hline() and whline() draw a horizontal line, using ch, starting from |
59 | the current cursor position. The cursor position does not change. The | 61 | the current cursor position. The cursor position does not change. The |
@@ -74,29 +76,31 @@ border | |||
74 | These functions return OK on success and ERR on error. | 76 | These functions return OK on success and ERR on error. |
75 | 77 | ||
76 | ### Portability | 78 | ### Portability |
77 | X/Open ncurses NetBSD | 79 | |
78 | border Y Y Y | 80 | Function | X/Open | ncurses | NetBSD |
79 | wborder Y Y Y | 81 | :---------------------|:------:|:-------:|:------: |
80 | box Y Y Y | 82 | border | Y | Y | Y |
81 | hline Y Y Y | 83 | wborder | Y | Y | Y |
82 | vline Y Y Y | 84 | box | Y | Y | Y |
83 | whline Y Y Y | 85 | hline | Y | Y | Y |
84 | wvline Y Y Y | 86 | vline | Y | Y | Y |
85 | mvhline Y Y Y | 87 | whline | Y | Y | Y |
86 | mvvline Y Y Y | 88 | wvline | Y | Y | Y |
87 | mvwhline Y Y Y | 89 | mvhline | Y | Y | Y |
88 | mvwvline Y Y Y | 90 | mvvline | Y | Y | Y |
89 | border_set Y Y Y | 91 | mvwhline | Y | Y | Y |
90 | wborder_set Y Y Y | 92 | mvwvline | Y | Y | Y |
91 | box_set Y Y Y | 93 | border_set | Y | Y | Y |
92 | hline_set Y Y Y | 94 | wborder_set | Y | Y | Y |
93 | vline_set Y Y Y | 95 | box_set | Y | Y | Y |
94 | whline_set Y Y Y | 96 | hline_set | Y | Y | Y |
95 | wvline_set Y Y Y | 97 | vline_set | Y | Y | Y |
96 | mvhline_set Y Y Y | 98 | whline_set | Y | Y | Y |
97 | mvvline_set Y Y Y | 99 | wvline_set | Y | Y | Y |
98 | mvwhline_set Y Y Y | 100 | mvhline_set | Y | Y | Y |
99 | mvwvline_set Y Y Y | 101 | mvvline_set | Y | Y | Y |
102 | mvwhline_set | Y | Y | Y | ||
103 | mvwvline_set | Y | Y | Y | ||
100 | 104 | ||
101 | **man-end****************************************************************/ | 105 | **man-end****************************************************************/ |
102 | 106 | ||
diff --git a/scripts/kconfig/libcurses/clear.c b/scripts/kconfig/libcurses/clear.c index acb8edf81..e10b321c3 100644 --- a/scripts/kconfig/libcurses/clear.c +++ b/scripts/kconfig/libcurses/clear.c | |||
@@ -38,15 +38,17 @@ clear | |||
38 | All functions return OK on success and ERR on error. | 38 | All functions return OK on success and ERR on error. |
39 | 39 | ||
40 | ### Portability | 40 | ### Portability |
41 | X/Open ncurses NetBSD | 41 | |
42 | clear Y Y Y | 42 | Function | X/Open | ncurses | NetBSD |
43 | wclear Y Y Y | 43 | :---------------------|:------:|:-------:|:------: |
44 | erase Y Y Y | 44 | clear | Y | Y | Y |
45 | werase Y Y Y | 45 | wclear | Y | Y | Y |
46 | clrtobot Y Y Y | 46 | erase | Y | Y | Y |
47 | wclrtobot Y Y Y | 47 | werase | Y | Y | Y |
48 | clrtoeol Y Y Y | 48 | clrtobot | Y | Y | Y |
49 | wclrtoeol Y Y Y | 49 | wclrtobot | Y | Y | Y |
50 | clrtoeol | Y | Y | Y | ||
51 | wclrtoeol | Y | Y | Y | ||
50 | 52 | ||
51 | **man-end****************************************************************/ | 53 | **man-end****************************************************************/ |
52 | 54 | ||
diff --git a/scripts/kconfig/libcurses/color.c b/scripts/kconfig/libcurses/color.c index 3335ae082..372dad948 100644 --- a/scripts/kconfig/libcurses/color.c +++ b/scripts/kconfig/libcurses/color.c | |||
@@ -92,20 +92,22 @@ color | |||
92 | find_pair() return a pair number, or -1 on error. | 92 | find_pair() return a pair number, or -1 on error. |
93 | 93 | ||
94 | ### Portability | 94 | ### Portability |
95 | X/Open ncurses NetBSD | 95 | |
96 | has_colors Y Y Y | 96 | Function | X/Open | ncurses | NetBSD |
97 | start_color Y Y Y | 97 | :---------------------|:------:|:-------:|:------: |
98 | init_pair Y Y Y | 98 | has_colors | Y | Y | Y |
99 | pair_content Y Y Y | 99 | start_color | Y | Y | Y |
100 | can_change_color Y Y Y | 100 | init_pair | Y | Y | Y |
101 | init_color Y Y Y | 101 | pair_content | Y | Y | Y |
102 | color_content Y Y Y | 102 | can_change_color | Y | Y | Y |
103 | alloc_pair - Y - | 103 | init_color | Y | Y | Y |
104 | assume_default_colors - Y Y | 104 | color_content | Y | Y | Y |
105 | find_pair - Y - | 105 | alloc_pair | - | Y | - |
106 | free_pair - Y - | 106 | assume_default_colors | - | Y | Y |
107 | use_default_colors - Y Y | 107 | find_pair | - | Y | - |
108 | PDC_set_line_color - - - | 108 | free_pair | - | Y | - |
109 | use_default_colors | - | Y | Y | ||
110 | PDC_set_line_color | - | - | - | ||
109 | 111 | ||
110 | **man-end****************************************************************/ | 112 | **man-end****************************************************************/ |
111 | 113 | ||
diff --git a/scripts/kconfig/libcurses/curses.h b/scripts/kconfig/libcurses/curses.h index e4ba3776a..f58fe66df 100644 --- a/scripts/kconfig/libcurses/curses.h +++ b/scripts/kconfig/libcurses/curses.h | |||
@@ -9,26 +9,28 @@ | |||
9 | 9 | ||
10 | Define before inclusion (only those needed): | 10 | Define before inclusion (only those needed): |
11 | 11 | ||
12 | XCURSES if building / built for X11 | 12 | Macro | Meaning / value |
13 | PDC_RGB if you want to use RGB color definitions | 13 | :-------------|------------------------------------------------- |
14 | (Red = 1, Green = 2, Blue = 4) instead of BGR | 14 | XCURSES | if building / built for X11 |
15 | PDC_WIDE if building / built with wide-character support | 15 | PDC_RGB | RGB color (Red = 1, Green = 2, Blue = 4) vs. BGR |
16 | PDC_DLL_BUILD if building / built as a Windows DLL | 16 | PDC_WIDE | if building / built with wide-character support |
17 | PDC_NCMOUSE to use the ncurses mouse API instead | 17 | PDC_DLL_BUILD | if building / built as a Windows DLL |
18 | of PDCurses' traditional mouse API | 18 | PDC_NCMOUSE | use ncurses mouse API vs. traditional PDCurses |
19 | 19 | ||
20 | Defined by this header: | 20 | Defined by this header: |
21 | 21 | ||
22 | PDCURSES PDCurses-only features are available | 22 | Macro | Meaning / value |
23 | PDC_BUILD API build version | 23 | :-------------|------------------------------------------------- |
24 | PDC_VER_MAJOR major version number | 24 | PDCURSES | PDCurses-only features are available |
25 | PDC_VER_MINOR minor version number | 25 | PDC_BUILD | API build version |
26 | PDC_VERDOT version string | 26 | PDC_VER_MAJOR | major version number |
27 | PDC_VER_MINOR | minor version number | ||
28 | PDC_VERDOT | version string | ||
27 | 29 | ||
28 | **man-end****************************************************************/ | 30 | **man-end****************************************************************/ |
29 | 31 | ||
30 | #define PDCURSES 1 | 32 | #define PDCURSES 1 |
31 | #define PDC_BUILD 3907 | 33 | #define PDC_BUILD 3908 |
32 | #define PDC_VER_MAJOR 3 | 34 | #define PDC_VER_MAJOR 3 |
33 | #define PDC_VER_MINOR 9 | 35 | #define PDC_VER_MINOR 9 |
34 | #define PDC_VERDOT "3.9" | 36 | #define PDC_VERDOT "3.9" |
@@ -420,10 +422,9 @@ Text Attributes | |||
420 | 422 | ||
421 | PDCurses uses a 32-bit integer for its chtype: | 423 | PDCurses uses a 32-bit integer for its chtype: |
422 | 424 | ||
423 | +--------------------------------------------------------------------+ | 425 | color pair | modifiers | character eg 'a' |
424 | |31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16|15|14|13|..| 2| 1| 0| | 426 | -----------------------|-----------------------|-------------------- |
425 | +--------------------------------------------------------------------+ | 427 | 31 30 29 28 27 26 25 24|23 22 21 20 19 18 17 16|15 14 13 .. 2 1 0 |
426 | color pair | modifiers | character eg 'a' | ||
427 | 428 | ||
428 | There are 256 color pairs (8 bits), 8 bits for modifiers, and 16 bits | 429 | There are 256 color pairs (8 bits), 8 bits for modifiers, and 16 bits |
429 | for character data. The modifiers are bold, underline, right-line, | 430 | for character data. The modifiers are bold, underline, right-line, |
diff --git a/scripts/kconfig/libcurses/getch.c b/scripts/kconfig/libcurses/getch.c index 8719ca39c..9d771ec0e 100644 --- a/scripts/kconfig/libcurses/getch.c +++ b/scripts/kconfig/libcurses/getch.c | |||
@@ -75,19 +75,21 @@ getch | |||
75 | character or function key token. | 75 | character or function key token. |
76 | 76 | ||
77 | ### Portability | 77 | ### Portability |
78 | X/Open ncurses NetBSD | 78 | |
79 | getch Y Y Y | 79 | Function | X/Open | ncurses | NetBSD |
80 | wgetch Y Y Y | 80 | :---------------------|:------:|:-------:|:------: |
81 | mvgetch Y Y Y | 81 | getch | Y | Y | Y |
82 | mvwgetch Y Y Y | 82 | wgetch | Y | Y | Y |
83 | ungetch Y Y Y | 83 | mvgetch | Y | Y | Y |
84 | flushinp Y Y Y | 84 | mvwgetch | Y | Y | Y |
85 | get_wch Y Y Y | 85 | ungetch | Y | Y | Y |
86 | wget_wch Y Y Y | 86 | flushinp | Y | Y | Y |
87 | mvget_wch Y Y Y | 87 | get_wch | Y | Y | Y |
88 | mvwget_wch Y Y Y | 88 | wget_wch | Y | Y | Y |
89 | unget_wch Y Y Y | 89 | mvget_wch | Y | Y | Y |
90 | PDC_get_key_modifiers - - - | 90 | mvwget_wch | Y | Y | Y |
91 | unget_wch | Y | Y | Y | ||
92 | PDC_get_key_modifiers | - | - | - | ||
91 | 93 | ||
92 | **man-end****************************************************************/ | 94 | **man-end****************************************************************/ |
93 | 95 | ||
diff --git a/scripts/kconfig/libcurses/getyx.c b/scripts/kconfig/libcurses/getyx.c index 5f104df99..6aa894ed0 100644 --- a/scripts/kconfig/libcurses/getyx.c +++ b/scripts/kconfig/libcurses/getyx.c | |||
@@ -54,21 +54,23 @@ getyx | |||
54 | values, or ERR in the case of a NULL window. | 54 | values, or ERR in the case of a NULL window. |
55 | 55 | ||
56 | ### Portability | 56 | ### Portability |
57 | X/Open ncurses NetBSD | 57 | |
58 | getyx Y Y Y | 58 | Function | X/Open | ncurses | NetBSD |
59 | getparyx Y Y Y | 59 | :---------------------|:------:|:-------:|:------: |
60 | getbegyx Y Y Y | 60 | getyx | Y | Y | Y |
61 | getmaxyx Y Y Y | 61 | getparyx | Y | Y | Y |
62 | getsyx - Y Y | 62 | getbegyx | Y | Y | Y |
63 | setsyx - Y Y | 63 | getmaxyx | Y | Y | Y |
64 | getbegy - Y Y | 64 | getsyx | - | Y | Y |
65 | getbegx - Y Y | 65 | setsyx | - | Y | Y |
66 | getcury - Y Y | 66 | getbegy | - | Y | Y |
67 | getcurx - Y Y | 67 | getbegx | - | Y | Y |
68 | getpary - Y Y | 68 | getcury | - | Y | Y |
69 | getparx - Y Y | 69 | getcurx | - | Y | Y |
70 | getmaxy - Y Y | 70 | getpary | - | Y | Y |
71 | getmaxx - Y Y | 71 | getparx | - | Y | Y |
72 | getmaxy | - | Y | Y | ||
73 | getmaxx | - | Y | Y | ||
72 | 74 | ||
73 | **man-end****************************************************************/ | 75 | **man-end****************************************************************/ |
74 | 76 | ||
diff --git a/scripts/kconfig/libcurses/inch.c b/scripts/kconfig/libcurses/inch.c index 2bd4430f6..28b57e222 100644 --- a/scripts/kconfig/libcurses/inch.c +++ b/scripts/kconfig/libcurses/inch.c | |||
@@ -31,15 +31,17 @@ inch | |||
31 | returned.) Note that in PDCurses, chtype and cchar_t are the same. | 31 | returned.) Note that in PDCurses, chtype and cchar_t are the same. |
32 | 32 | ||
33 | ### Portability | 33 | ### Portability |
34 | X/Open ncurses NetBSD | 34 | |
35 | inch Y Y Y | 35 | Function | X/Open | ncurses | NetBSD |
36 | winch Y Y Y | 36 | :---------------------|:------:|:-------:|:------: |
37 | mvinch Y Y Y | 37 | inch | Y | Y | Y |
38 | mvwinch Y Y Y | 38 | winch | Y | Y | Y |
39 | in_wch Y Y Y | 39 | mvinch | Y | Y | Y |
40 | win_wch Y Y Y | 40 | mvwinch | Y | Y | Y |
41 | mvin_wch Y Y Y | 41 | in_wch | Y | Y | Y |
42 | mvwin_wch Y Y Y | 42 | win_wch | Y | Y | Y |
43 | mvin_wch | Y | Y | Y | ||
44 | mvwin_wch | Y | Y | Y | ||
43 | 45 | ||
44 | **man-end****************************************************************/ | 46 | **man-end****************************************************************/ |
45 | 47 | ||
diff --git a/scripts/kconfig/libcurses/initscr.c b/scripts/kconfig/libcurses/initscr.c index 66940a3cf..a4208642a 100644 --- a/scripts/kconfig/libcurses/initscr.c +++ b/scripts/kconfig/libcurses/initscr.c | |||
@@ -83,17 +83,19 @@ initscr | |||
83 | returns OK, and resize_term(), which returns either OK or ERR. | 83 | returns OK, and resize_term(), which returns either OK or ERR. |
84 | 84 | ||
85 | ### Portability | 85 | ### Portability |
86 | X/Open ncurses NetBSD | 86 | |
87 | initscr Y Y Y | 87 | Function | X/Open | ncurses | NetBSD |
88 | endwin Y Y Y | 88 | :---------------------|:------:|:-------:|:------: |
89 | isendwin Y Y Y | 89 | initscr | Y | Y | Y |
90 | newterm Y Y Y | 90 | endwin | Y | Y | Y |
91 | set_term Y Y Y | 91 | isendwin | Y | Y | Y |
92 | delscreen Y Y Y | 92 | newterm | Y | Y | Y |
93 | resize_term - Y Y | 93 | set_term | Y | Y | Y |
94 | set_tabsize - Y Y | 94 | delscreen | Y | Y | Y |
95 | curses_version - Y - | 95 | resize_term | - | Y | Y |
96 | is_termresized - - - | 96 | set_tabsize | - | Y | Y |
97 | curses_version | - | Y | - | ||
98 | is_termresized | - | - | - | ||
97 | 99 | ||
98 | **man-end****************************************************************/ | 100 | **man-end****************************************************************/ |
99 | 101 | ||
diff --git a/scripts/kconfig/libcurses/inopts.c b/scripts/kconfig/libcurses/inopts.c index 30e18f611..a1c4b49f8 100644 --- a/scripts/kconfig/libcurses/inopts.c +++ b/scripts/kconfig/libcurses/inopts.c | |||
@@ -106,32 +106,34 @@ inopts | |||
106 | always returns FALSE. All others return OK on success and ERR on error. | 106 | always returns FALSE. All others return OK on success and ERR on error. |
107 | 107 | ||
108 | ### Portability | 108 | ### Portability |
109 | X/Open ncurses NetBSD | 109 | |
110 | cbreak Y Y Y | 110 | Function | X/Open | ncurses | NetBSD |
111 | nocbreak Y Y Y | 111 | :---------------------|:------:|:-------:|:------: |
112 | echo Y Y Y | 112 | cbreak | Y | Y | Y |
113 | noecho Y Y Y | 113 | nocbreak | Y | Y | Y |
114 | halfdelay Y Y Y | 114 | echo | Y | Y | Y |
115 | intrflush Y Y Y | 115 | noecho | Y | Y | Y |
116 | keypad Y Y Y | 116 | halfdelay | Y | Y | Y |
117 | meta Y Y Y | 117 | intrflush | Y | Y | Y |
118 | nl Y Y Y | 118 | keypad | Y | Y | Y |
119 | nonl Y Y Y | 119 | meta | Y | Y | Y |
120 | nodelay Y Y Y | 120 | nl | Y | Y | Y |
121 | notimeout Y Y Y | 121 | nonl | Y | Y | Y |
122 | raw Y Y Y | 122 | nodelay | Y | Y | Y |
123 | noraw Y Y Y | 123 | notimeout | Y | Y | Y |
124 | noqiflush Y Y Y | 124 | raw | Y | Y | Y |
125 | qiflush Y Y Y | 125 | noraw | Y | Y | Y |
126 | timeout Y Y Y | 126 | noqiflush | Y | Y | Y |
127 | wtimeout Y Y Y | 127 | qiflush | Y | Y | Y |
128 | wgetdelay - Y - | 128 | timeout | Y | Y | Y |
129 | typeahead Y Y Y | 129 | wtimeout | Y | Y | Y |
130 | crmode Y Y Y | 130 | wgetdelay | - | Y | - |
131 | nocrmode Y Y Y | 131 | typeahead | Y | Y | Y |
132 | is_keypad - Y Y | 132 | crmode | Y | Y | Y |
133 | is_nodelay - Y - | 133 | nocrmode | Y | Y | Y |
134 | is_notimeout - Y - | 134 | is_keypad | - | Y | Y |
135 | is_nodelay | - | Y | - | ||
136 | is_notimeout | - | Y | - | ||
135 | 137 | ||
136 | **man-end****************************************************************/ | 138 | **man-end****************************************************************/ |
137 | 139 | ||
diff --git a/scripts/kconfig/libcurses/kernel.c b/scripts/kconfig/libcurses/kernel.c index afb2d0661..0f5a73c21 100644 --- a/scripts/kconfig/libcurses/kernel.c +++ b/scripts/kconfig/libcurses/kernel.c | |||
@@ -71,20 +71,22 @@ kernel | |||
71 | curs_set(), which returns the previous visibility. | 71 | curs_set(), which returns the previous visibility. |
72 | 72 | ||
73 | ### Portability | 73 | ### Portability |
74 | X/Open ncurses NetBSD | 74 | |
75 | def_prog_mode Y Y Y | 75 | Function | X/Open | ncurses | NetBSD |
76 | def_shell_mode Y Y Y | 76 | :---------------------|:------:|:-------:|:------: |
77 | reset_prog_mode Y Y Y | 77 | def_prog_mode | Y | Y | Y |
78 | reset_shell_mode Y Y Y | 78 | def_shell_mode | Y | Y | Y |
79 | resetty Y Y Y | 79 | reset_prog_mode | Y | Y | Y |
80 | savetty Y Y Y | 80 | reset_shell_mode | Y | Y | Y |
81 | ripoffline Y Y Y | 81 | resetty | Y | Y | Y |
82 | curs_set Y Y Y | 82 | savetty | Y | Y | Y |
83 | napms Y Y Y | 83 | ripoffline | Y | Y | Y |
84 | fixterm - Y - | 84 | curs_set | Y | Y | Y |
85 | resetterm - Y - | 85 | napms | Y | Y | Y |
86 | saveterm - Y - | 86 | fixterm | - | Y | - |
87 | draino - - - | 87 | resetterm | - | Y | - |
88 | saveterm | - | Y | - | ||
89 | draino | - | - | - | ||
88 | 90 | ||
89 | **man-end****************************************************************/ | 91 | **man-end****************************************************************/ |
90 | 92 | ||
diff --git a/scripts/kconfig/libcurses/move.c b/scripts/kconfig/libcurses/move.c index 96496445e..38db1d19a 100644 --- a/scripts/kconfig/libcurses/move.c +++ b/scripts/kconfig/libcurses/move.c | |||
@@ -28,10 +28,12 @@ move | |||
28 | All functions return OK on success and ERR on error. | 28 | All functions return OK on success and ERR on error. |
29 | 29 | ||
30 | ### Portability | 30 | ### Portability |
31 | X/Open ncurses NetBSD | 31 | |
32 | move Y Y Y | 32 | Function | X/Open | ncurses | NetBSD |
33 | mvcur Y Y Y | 33 | :---------------------|:------:|:-------:|:------: |
34 | wmove Y Y Y | 34 | move | Y | Y | Y |
35 | mvcur | Y | Y | Y | ||
36 | wmove | Y | Y | Y | ||
35 | 37 | ||
36 | **man-end****************************************************************/ | 38 | **man-end****************************************************************/ |
37 | 39 | ||
diff --git a/scripts/kconfig/libcurses/outopts.c b/scripts/kconfig/libcurses/outopts.c index e0a55e437..4c8950959 100644 --- a/scripts/kconfig/libcurses/outopts.c +++ b/scripts/kconfig/libcurses/outopts.c | |||
@@ -75,23 +75,25 @@ outopts | |||
75 | return OK on success and ERR on error. | 75 | return OK on success and ERR on error. |
76 | 76 | ||
77 | ### Portability | 77 | ### Portability |
78 | X/Open ncurses NetBSD | 78 | |
79 | clearok Y Y Y | 79 | Function | X/Open | ncurses | NetBSD |
80 | idlok Y Y Y | 80 | :---------------------|:------:|:-------:|:------: |
81 | idcok Y Y Y | 81 | clearok | Y | Y | Y |
82 | immedok Y Y Y | 82 | idlok | Y | Y | Y |
83 | leaveok Y Y Y | 83 | idcok | Y | Y | Y |
84 | setscrreg Y Y Y | 84 | immedok | Y | Y | Y |
85 | wsetscrreg Y Y Y | 85 | leaveok | Y | Y | Y |
86 | wgetscrreg - Y - | 86 | setscrreg | Y | Y | Y |
87 | scrollok Y Y Y | 87 | wsetscrreg | Y | Y | Y |
88 | is_cleared - Y - | 88 | wgetscrreg | - | Y | - |
89 | is_idlok - Y - | 89 | scrollok | Y | Y | Y |
90 | is_idcok - Y - | 90 | is_cleared | - | Y | - |
91 | is_immedok - Y - | 91 | is_idlok | - | Y | - |
92 | is_leaveok - Y Y | 92 | is_idcok | - | Y | - |
93 | is_scrollok - Y - | 93 | is_immedok | - | Y | - |
94 | raw_output - - - | 94 | is_leaveok | - | Y | Y |
95 | is_scrollok | - | Y | - | ||
96 | raw_output | - | - | - | ||
95 | 97 | ||
96 | **man-end****************************************************************/ | 98 | **man-end****************************************************************/ |
97 | 99 | ||
diff --git a/scripts/kconfig/libcurses/overlay.c b/scripts/kconfig/libcurses/overlay.c index ae1903da8..75a93d83c 100644 --- a/scripts/kconfig/libcurses/overlay.c +++ b/scripts/kconfig/libcurses/overlay.c | |||
@@ -39,10 +39,12 @@ overlay | |||
39 | All functions return OK on success and ERR on error. | 39 | All functions return OK on success and ERR on error. |
40 | 40 | ||
41 | ### Portability | 41 | ### Portability |
42 | X/Open ncurses NetBSD | 42 | |
43 | overlay Y Y Y | 43 | Function | X/Open | ncurses | NetBSD |
44 | overwrite Y Y Y | 44 | :---------------------|:------:|:-------:|:------: |
45 | copywin Y Y Y | 45 | overlay | Y | Y | Y |
46 | overwrite | Y | Y | Y | ||
47 | copywin | Y | Y | Y | ||
46 | 48 | ||
47 | **man-end****************************************************************/ | 49 | **man-end****************************************************************/ |
48 | 50 | ||
diff --git a/scripts/kconfig/libcurses/pad.c b/scripts/kconfig/libcurses/pad.c index 3dfdfe5d6..8b44dabd4 100644 --- a/scripts/kconfig/libcurses/pad.c +++ b/scripts/kconfig/libcurses/pad.c | |||
@@ -62,14 +62,16 @@ pad | |||
62 | All functions except is_pad() return OK on success and ERR on error. | 62 | All functions except is_pad() return OK on success and ERR on error. |
63 | 63 | ||
64 | ### Portability | 64 | ### Portability |
65 | X/Open ncurses NetBSD | 65 | |
66 | newpad Y Y Y | 66 | Function | X/Open | ncurses | NetBSD |
67 | subpad Y Y Y | 67 | :---------------------|:------:|:-------:|:------: |
68 | prefresh Y Y Y | 68 | newpad | Y | Y | Y |
69 | pnoutrefresh Y Y Y | 69 | subpad | Y | Y | Y |
70 | pechochar Y Y Y | 70 | prefresh | Y | Y | Y |
71 | pecho_wchar Y Y Y | 71 | pnoutrefresh | Y | Y | Y |
72 | is_pad - Y Y | 72 | pechochar | Y | Y | Y |
73 | pecho_wchar | Y | Y | Y | ||
74 | is_pad | - | Y | Y | ||
73 | 75 | ||
74 | **man-end****************************************************************/ | 76 | **man-end****************************************************************/ |
75 | 77 | ||
diff --git a/scripts/kconfig/libcurses/pdcclip.c b/scripts/kconfig/libcurses/pdcclip.c index 740221280..6184ad2d9 100644 --- a/scripts/kconfig/libcurses/pdcclip.c +++ b/scripts/kconfig/libcurses/pdcclip.c | |||
@@ -24,26 +24,27 @@ clipboard | |||
24 | memory returned, via PDC_freeclipboard(). The length of the clipboard | 24 | memory returned, via PDC_freeclipboard(). The length of the clipboard |
25 | contents is returned in the length argument. | 25 | contents is returned in the length argument. |
26 | 26 | ||
27 | PDC_setclipboard copies the supplied text into the system's | 27 | PDC_setclipboard() copies the supplied text into the system's |
28 | clipboard, emptying the clipboard prior to the copy. | 28 | clipboard, emptying the clipboard prior to the copy. |
29 | 29 | ||
30 | PDC_clearclipboard() clears the internal clipboard. | 30 | PDC_clearclipboard() clears the internal clipboard. |
31 | 31 | ||
32 | ### Return Values | 32 | ### Return Values |
33 | 33 | ||
34 | indicator of success/failure of call. | 34 | PDC_CLIP_SUCCESS the call was successful |
35 | PDC_CLIP_SUCCESS the call was successful | 35 | PDC_CLIP_MEMORY_ERROR unable to allocate sufficient memory for |
36 | PDC_CLIP_MEMORY_ERROR unable to allocate sufficient memory for | 36 | the clipboard contents |
37 | the clipboard contents | 37 | PDC_CLIP_EMPTY the clipboard contains no text |
38 | PDC_CLIP_EMPTY the clipboard contains no text | 38 | PDC_CLIP_ACCESS_ERROR no clipboard support |
39 | PDC_CLIP_ACCESS_ERROR no clipboard support | ||
40 | 39 | ||
41 | ### Portability | 40 | ### Portability |
42 | X/Open ncurses NetBSD | 41 | |
43 | PDC_getclipboard - - - | 42 | Function | X/Open | ncurses | NetBSD |
44 | PDC_setclipboard - - - | 43 | :---------------------|:------:|:-------:|:------: |
45 | PDC_freeclipboard - - - | 44 | PDC_getclipboard | - | - | - |
46 | PDC_clearclipboard - - - | 45 | PDC_setclipboard | - | - | - |
46 | PDC_freeclipboard | - | - | - | ||
47 | PDC_clearclipboard | - | - | - | ||
47 | 48 | ||
48 | **man-end****************************************************************/ | 49 | **man-end****************************************************************/ |
49 | 50 | ||
@@ -143,7 +144,12 @@ int PDC_clearclipboard(void) | |||
143 | { | 144 | { |
144 | PDC_LOG(("PDC_clearclipboard() - called\n")); | 145 | PDC_LOG(("PDC_clearclipboard() - called\n")); |
145 | 146 | ||
146 | EmptyClipboard(); | 147 | if (OpenClipboard(NULL)) |
148 | if (EmptyClipboard()) | ||
149 | { | ||
150 | CloseClipboard(); | ||
151 | return PDC_CLIP_SUCCESS; | ||
152 | } | ||
147 | 153 | ||
148 | return PDC_CLIP_SUCCESS; | 154 | return PDC_CLIP_ACCESS_ERROR; |
149 | } | 155 | } |
diff --git a/scripts/kconfig/libcurses/pdcsetsc.c b/scripts/kconfig/libcurses/pdcsetsc.c index a2d1b6dc3..1e9fc9b0d 100644 --- a/scripts/kconfig/libcurses/pdcsetsc.c +++ b/scripts/kconfig/libcurses/pdcsetsc.c | |||
@@ -31,9 +31,12 @@ pdcsetsc | |||
31 | platforms. | 31 | platforms. |
32 | 32 | ||
33 | ### Portability | 33 | ### Portability |
34 | X/Open ncurses NetBSD | 34 | |
35 | PDC_set_blink - - - | 35 | Function | X/Open | ncurses | NetBSD |
36 | PDC_set_title - - - | 36 | :---------------------|:------:|:-------:|:------: |
37 | PDC_set_blink | - | - | - | ||
38 | PDC_set_bold | - | - | - | ||
39 | PDC_set_title | - | - | - | ||
37 | 40 | ||
38 | **man-end****************************************************************/ | 41 | **man-end****************************************************************/ |
39 | 42 | ||
diff --git a/scripts/kconfig/libcurses/printw.c b/scripts/kconfig/libcurses/printw.c index 38e7fd112..a753638a5 100644 --- a/scripts/kconfig/libcurses/printw.c +++ b/scripts/kconfig/libcurses/printw.c | |||
@@ -32,13 +32,15 @@ printw | |||
32 | error. | 32 | error. |
33 | 33 | ||
34 | ### Portability | 34 | ### Portability |
35 | X/Open ncurses NetBSD | 35 | |
36 | printw Y Y Y | 36 | Function | X/Open | ncurses | NetBSD |
37 | wprintw Y Y Y | 37 | :---------------------|:------:|:-------:|:------: |
38 | mvprintw Y Y Y | 38 | printw | Y | Y | Y |
39 | mvwprintw Y Y Y | 39 | wprintw | Y | Y | Y |
40 | vwprintw Y Y Y | 40 | mvprintw | Y | Y | Y |
41 | vw_printw Y Y Y | 41 | mvwprintw | Y | Y | Y |
42 | vwprintw | Y | Y | Y | ||
43 | vw_printw | Y | Y | Y | ||
42 | 44 | ||
43 | **man-end****************************************************************/ | 45 | **man-end****************************************************************/ |
44 | 46 | ||
diff --git a/scripts/kconfig/libcurses/refresh.c b/scripts/kconfig/libcurses/refresh.c index 306f4efb3..1dce414e5 100644 --- a/scripts/kconfig/libcurses/refresh.c +++ b/scripts/kconfig/libcurses/refresh.c | |||
@@ -45,13 +45,15 @@ refresh | |||
45 | All functions return OK on success and ERR on error. | 45 | All functions return OK on success and ERR on error. |
46 | 46 | ||
47 | ### Portability | 47 | ### Portability |
48 | X/Open ncurses NetBSD | 48 | |
49 | refresh Y Y Y | 49 | Function | X/Open | ncurses | NetBSD |
50 | wrefresh Y Y Y | 50 | :---------------------|:------:|:-------:|:------: |
51 | wnoutrefresh Y Y Y | 51 | refresh | Y | Y | Y |
52 | doupdate Y Y Y | 52 | wrefresh | Y | Y | Y |
53 | redrawwin Y Y Y | 53 | wnoutrefresh | Y | Y | Y |
54 | wredrawln Y Y Y | 54 | doupdate | Y | Y | Y |
55 | redrawwin | Y | Y | Y | ||
56 | wredrawln | Y | Y | Y | ||
55 | 57 | ||
56 | **man-end****************************************************************/ | 58 | **man-end****************************************************************/ |
57 | 59 | ||
diff --git a/scripts/kconfig/libcurses/scroll.c b/scripts/kconfig/libcurses/scroll.c index d2f3d1704..a53d71bad 100644 --- a/scripts/kconfig/libcurses/scroll.c +++ b/scripts/kconfig/libcurses/scroll.c | |||
@@ -31,10 +31,12 @@ scroll | |||
31 | All functions return OK on success and ERR on error. | 31 | All functions return OK on success and ERR on error. |
32 | 32 | ||
33 | ### Portability | 33 | ### Portability |
34 | X/Open ncurses NetBSD | 34 | |
35 | scroll Y Y Y | 35 | Function | X/Open | ncurses | NetBSD |
36 | scrl Y Y Y | 36 | :---------------------|:------:|:-------:|:------: |
37 | wscrl Y Y Y | 37 | scroll | Y | Y | Y |
38 | scrl | Y | Y | Y | ||
39 | wscrl | Y | Y | Y | ||
38 | 40 | ||
39 | **man-end****************************************************************/ | 41 | **man-end****************************************************************/ |
40 | 42 | ||
diff --git a/scripts/kconfig/libcurses/slk.c b/scripts/kconfig/libcurses/slk.c index a9fca13d3..e8dde752c 100644 --- a/scripts/kconfig/libcurses/slk.c +++ b/scripts/kconfig/libcurses/slk.c | |||
@@ -46,12 +46,12 @@ slk | |||
46 | slk_init() requires a single parameter which describes the format of | 46 | slk_init() requires a single parameter which describes the format of |
47 | the SLKs as follows: | 47 | the SLKs as follows: |
48 | 48 | ||
49 | 0 3-2-3 format | 49 | 0 3-2-3 format |
50 | 1 4-4 format | 50 | 1 4-4 format |
51 | 2 4-4-4 format (ncurses extension) | 51 | 2 4-4-4 format (ncurses extension) |
52 | 3 4-4-4 format with index line (ncurses extension) | 52 | 3 4-4-4 format with index line (ncurses extension) |
53 | 2 lines used | 53 | 2 lines used |
54 | 55 5-5 format (pdcurses format) | 54 | 55 5-5 format (pdcurses format) |
55 | 55 | ||
56 | slk_refresh(), slk_noutrefresh() and slk_touch() are analogous to | 56 | slk_refresh(), slk_noutrefresh() and slk_touch() are analogous to |
57 | refresh(), noutrefresh() and touch(). | 57 | refresh(), noutrefresh() and touch(). |
@@ -61,26 +61,28 @@ slk | |||
61 | All functions return OK on success and ERR on error. | 61 | All functions return OK on success and ERR on error. |
62 | 62 | ||
63 | ### Portability | 63 | ### Portability |
64 | X/Open ncurses NetBSD | 64 | |
65 | slk_init Y Y Y | 65 | Function | X/Open | ncurses | NetBSD |
66 | slk_set Y Y Y | 66 | :---------------------|:------:|:-------:|:------: |
67 | slk_refresh Y Y Y | 67 | slk_init | Y | Y | Y |
68 | slk_noutrefresh Y Y Y | 68 | slk_set | Y | Y | Y |
69 | slk_label Y Y Y | 69 | slk_refresh | Y | Y | Y |
70 | slk_clear Y Y Y | 70 | slk_noutrefresh | Y | Y | Y |
71 | slk_restore Y Y Y | 71 | slk_label | Y | Y | Y |
72 | slk_touch Y Y Y | 72 | slk_clear | Y | Y | Y |
73 | slk_attron Y Y Y | 73 | slk_restore | Y | Y | Y |
74 | slk_attrset Y Y Y | 74 | slk_touch | Y | Y | Y |
75 | slk_attroff Y Y Y | 75 | slk_attron | Y | Y | Y |
76 | slk_attr_on Y Y Y | 76 | slk_attrset | Y | Y | Y |
77 | slk_attr_set Y Y Y | 77 | slk_attroff | Y | Y | Y |
78 | slk_attr_off Y Y Y | 78 | slk_attr_on | Y | Y | Y |
79 | slk_wset Y Y Y | 79 | slk_attr_set | Y | Y | Y |
80 | PDC_mouse_in_slk - - - | 80 | slk_attr_off | Y | Y | Y |
81 | PDC_slk_free - - - | 81 | slk_wset | Y | Y | Y |
82 | PDC_slk_initialize - - - | 82 | PDC_mouse_in_slk | - | - | - |
83 | slk_wlabel - - - | 83 | PDC_slk_free | - | - | - |
84 | PDC_slk_initialize | - | - | - | ||
85 | slk_wlabel | - | - | - | ||
84 | 86 | ||
85 | **man-end****************************************************************/ | 87 | **man-end****************************************************************/ |
86 | 88 | ||
diff --git a/scripts/kconfig/libcurses/touch.c b/scripts/kconfig/libcurses/touch.c index 2fd03cce5..7ea0b64b2 100644 --- a/scripts/kconfig/libcurses/touch.c +++ b/scripts/kconfig/libcurses/touch.c | |||
@@ -49,14 +49,16 @@ touch | |||
49 | is_wintouched() and is_linetouched(). | 49 | is_wintouched() and is_linetouched(). |
50 | 50 | ||
51 | ### Portability | 51 | ### Portability |
52 | X/Open ncurses NetBSD | 52 | |
53 | touchwin Y Y Y | 53 | Function | X/Open | ncurses | NetBSD |
54 | touchline Y Y Y | 54 | :---------------------|:------:|:-------:|:------: |
55 | untouchwin Y Y Y | 55 | touchwin | Y | Y | Y |
56 | wtouchln Y Y Y | 56 | touchline | Y | Y | Y |
57 | is_linetouched Y Y Y | 57 | untouchwin | Y | Y | Y |
58 | is_wintouched Y Y Y | 58 | wtouchln | Y | Y | Y |
59 | touchoverlap - - Y | 59 | is_linetouched | Y | Y | Y |
60 | is_wintouched | Y | Y | Y | ||
61 | touchoverlap | - | - | Y | ||
60 | 62 | ||
61 | **man-end****************************************************************/ | 63 | **man-end****************************************************************/ |
62 | 64 | ||
diff --git a/scripts/kconfig/libcurses/window.c b/scripts/kconfig/libcurses/window.c index 4ae5b0861..891d0c05b 100644 --- a/scripts/kconfig/libcurses/window.c +++ b/scripts/kconfig/libcurses/window.c | |||
@@ -124,26 +124,28 @@ window | |||
124 | NOT cancelled for those windows. | 124 | NOT cancelled for those windows. |
125 | 125 | ||
126 | ### Portability | 126 | ### Portability |
127 | X/Open ncurses NetBSD | 127 | |
128 | newwin Y Y Y | 128 | Function | X/Open | ncurses | NetBSD |
129 | delwin Y Y Y | 129 | :---------------------|:------:|:-------:|:------: |
130 | mvwin Y Y Y | 130 | newwin | Y | Y | Y |
131 | subwin Y Y Y | 131 | delwin | Y | Y | Y |
132 | derwin Y Y Y | 132 | mvwin | Y | Y | Y |
133 | mvderwin Y Y Y | 133 | subwin | Y | Y | Y |
134 | dupwin Y Y Y | 134 | derwin | Y | Y | Y |
135 | wgetparent - Y - | 135 | mvderwin | Y | Y | Y |
136 | wsyncup Y Y Y | 136 | dupwin | Y | Y | Y |
137 | syncok Y Y Y | 137 | wgetparent | - | Y | - |
138 | is_subwin - Y - | 138 | wsyncup | Y | Y | Y |
139 | is_syncok - Y - | 139 | syncok | Y | Y | Y |
140 | wcursyncup Y Y Y | 140 | is_subwin | - | Y | - |
141 | wsyncdown Y Y Y | 141 | is_syncok | - | Y | - |
142 | wresize - Y Y | 142 | wcursyncup | Y | Y | Y |
143 | resize_window - - - | 143 | wsyncdown | Y | Y | Y |
144 | PDC_makelines - - - | 144 | wresize | - | Y | Y |
145 | PDC_makenew - - - | 145 | resize_window | - | - | - |
146 | PDC_sync - - - | 146 | PDC_makelines | - | - | - |
147 | PDC_makenew | - | - | - | ||
148 | PDC_sync | - | - | - | ||
147 | 149 | ||
148 | **man-end****************************************************************/ | 150 | **man-end****************************************************************/ |
149 | 151 | ||
diff --git a/scripts/kconfig/lxdialog/check-lxdialog.sh b/scripts/kconfig/lxdialog/check-lxdialog.sh index a608d4c5e..885586865 100755 --- a/scripts/kconfig/lxdialog/check-lxdialog.sh +++ b/scripts/kconfig/lxdialog/check-lxdialog.sh | |||
@@ -53,7 +53,7 @@ trap "rm -f $tmp" 0 1 2 3 15 | |||
53 | check() { | 53 | check() { |
54 | $cc -x c - -o $tmp 2>/dev/null <<'EOF' | 54 | $cc -x c - -o $tmp 2>/dev/null <<'EOF' |
55 | #include CURSES_LOC | 55 | #include CURSES_LOC |
56 | int main() {} | 56 | int main() { return 0; } |
57 | EOF | 57 | EOF |
58 | if [ $? != 0 ]; then | 58 | if [ $? != 0 ]; then |
59 | echo " *** Unable to find the ncurses libraries or the" 1>&2 | 59 | echo " *** Unable to find the ncurses libraries or the" 1>&2 |
diff --git a/scripts/mk_mingw64u_defconfig b/scripts/mk_mingw64u_defconfig index 19124d735..5561a0900 100755 --- a/scripts/mk_mingw64u_defconfig +++ b/scripts/mk_mingw64u_defconfig | |||
@@ -32,6 +32,7 @@ set_build_opts \ | |||
32 | CONFIG_LAST_SUPPORTED_WCHAR=1114111 \ | 32 | CONFIG_LAST_SUPPORTED_WCHAR=1114111 \ |
33 | CONFIG_UNICODE_COMBINING_WCHARS=y \ | 33 | CONFIG_UNICODE_COMBINING_WCHARS=y \ |
34 | CONFIG_UNICODE_WIDE_WCHARS=y \ | 34 | CONFIG_UNICODE_WIDE_WCHARS=y \ |
35 | CONFIG_FEATURE_USE_CNG_API=y \ | ||
35 | < "$configs"/mingw64_defconfig \ | 36 | < "$configs"/mingw64_defconfig \ |
36 | > "$configs"/mingw64u_defconfig | 37 | > "$configs"/mingw64u_defconfig |
37 | 38 | ||
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 3919118f0..0038aa1e9 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -929,6 +929,7 @@ raise_interrupt(void) | |||
929 | raise(SIGINT); | 929 | raise(SIGINT); |
930 | #else | 930 | #else |
931 | fflush_all(); | 931 | fflush_all(); |
932 | kill(-getpid(), SIGINT); | ||
932 | _exit(SIGINT << 24); | 933 | _exit(SIGINT << 24); |
933 | #endif | 934 | #endif |
934 | } | 935 | } |
@@ -4274,7 +4275,7 @@ signal_handler(int signo) | |||
4274 | return; | 4275 | return; |
4275 | } | 4276 | } |
4276 | #if ENABLE_FEATURE_EDITING | 4277 | #if ENABLE_FEATURE_EDITING |
4277 | bb_got_signal = signo; /* for read_line_input: "we got a signal" */ | 4278 | bb_got_signal = signo; /* for read_line_input / read builtin: "we got a signal" */ |
4278 | #endif | 4279 | #endif |
4279 | gotsig[signo - 1] = 1; | 4280 | gotsig[signo - 1] = 1; |
4280 | pending_sig = signo; | 4281 | pending_sig = signo; |
@@ -15812,6 +15813,7 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
15812 | r = shell_builtin_read(¶ms); | 15813 | r = shell_builtin_read(¶ms); |
15813 | INT_ON; | 15814 | INT_ON; |
15814 | 15815 | ||
15816 | #if !ENABLE_PLATFORM_MINGW32 | ||
15815 | if ((uintptr_t)r == 1 && errno == EINTR) { | 15817 | if ((uintptr_t)r == 1 && errno == EINTR) { |
15816 | /* To get SIGCHLD: sleep 1 & read x; echo $x | 15818 | /* To get SIGCHLD: sleep 1 & read x; echo $x |
15817 | * Correct behavior is to not exit "read" | 15819 | * Correct behavior is to not exit "read" |
@@ -15820,8 +15822,15 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
15820 | goto again; | 15822 | goto again; |
15821 | } | 15823 | } |
15822 | 15824 | ||
15823 | #if ENABLE_PLATFORM_MINGW32 | 15825 | if ((uintptr_t)r == 2) /* -t SEC timeout? */ |
15826 | /* bash: "The exit status is greater than 128 if the timeout is exceeded." */ | ||
15827 | /* The actual value observed with bash 5.2.15: */ | ||
15828 | return 128 + SIGALRM; | ||
15829 | #else /* ENABLE_PLATFORM_MINGW32 */ | ||
15824 | if ((uintptr_t)r == 2) { | 15830 | if ((uintptr_t)r == 2) { |
15831 | /* Timeout, return 128 + SIGALRM */ | ||
15832 | return 142; | ||
15833 | } else if ((uintptr_t)r == 3) { | ||
15825 | /* ^C pressed, propagate event */ | 15834 | /* ^C pressed, propagate event */ |
15826 | if (trap[SIGINT]) { | 15835 | if (trap[SIGINT]) { |
15827 | write(STDOUT_FILENO, "^C", 2); | 15836 | write(STDOUT_FILENO, "^C", 2); |
@@ -15969,8 +15978,25 @@ exitshell(void) | |||
15969 | char *p; | 15978 | char *p; |
15970 | 15979 | ||
15971 | #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT | 15980 | #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT |
15972 | save_history(line_input_state); /* may be NULL */ | 15981 | if (line_input_state) { |
15982 | const char *hp; | ||
15983 | # if ENABLE_FEATURE_SH_HISTFILESIZE | ||
15984 | // in bash: | ||
15985 | // HISTFILESIZE controls the on-disk history file size (in lines, 0=no history): | ||
15986 | // "When this variable is assigned a value, the history file is truncated, if necessary" | ||
15987 | // but we do it only at exit, not on assignment: | ||
15988 | /* Use HISTFILESIZE to limit file size */ | ||
15989 | hp = lookupvar("HISTFILESIZE"); | ||
15990 | if (hp) | ||
15991 | line_input_state->max_history = size_from_HISTFILESIZE(hp); | ||
15992 | # endif | ||
15993 | /* HISTFILE: "If unset, the command history is not saved when a shell exits." */ | ||
15994 | hp = lookupvar("HISTFILE"); | ||
15995 | line_input_state->hist_file = hp; | ||
15996 | save_history(line_input_state); /* no-op if hist_file is NULL or "" */ | ||
15997 | } | ||
15973 | #endif | 15998 | #endif |
15999 | |||
15974 | savestatus = exitstatus; | 16000 | savestatus = exitstatus; |
15975 | TRACE(("pid %d, exitshell(%d)\n", getpid(), savestatus)); | 16001 | TRACE(("pid %d, exitshell(%d)\n", getpid(), savestatus)); |
15976 | if (setjmp(loc.loc)) | 16002 | if (setjmp(loc.loc)) |
@@ -16474,7 +16500,12 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
16474 | if (hp) | 16500 | if (hp) |
16475 | line_input_state->hist_file = xstrdup(hp); | 16501 | line_input_state->hist_file = xstrdup(hp); |
16476 | # if ENABLE_FEATURE_SH_HISTFILESIZE | 16502 | # if ENABLE_FEATURE_SH_HISTFILESIZE |
16477 | hp = lookupvar("HISTFILESIZE"); | 16503 | hp = lookupvar("HISTSIZE"); |
16504 | /* Using HISTFILESIZE above to limit max_history would be WRONG: | ||
16505 | * users may set HISTFILESIZE=0 in their profile scripts | ||
16506 | * to prevent _saving_ of history files, but still want to have | ||
16507 | * non-zero history limit for in-memory list. | ||
16508 | */ | ||
16478 | line_input_state->max_history = size_from_HISTFILESIZE(hp); | 16509 | line_input_state->max_history = size_from_HISTFILESIZE(hp); |
16479 | # endif | 16510 | # endif |
16480 | } | 16511 | } |
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 04dda0734..d1f687f9d 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -1973,7 +1973,7 @@ static void record_pending_signo(int sig) | |||
1973 | || (G_traps && G_traps[SIGCHLD] && G_traps[SIGCHLD][0]) | 1973 | || (G_traps && G_traps[SIGCHLD] && G_traps[SIGCHLD][0]) |
1974 | /* ^^^ if SIGCHLD, interrupt line reading only if it has a trap */ | 1974 | /* ^^^ if SIGCHLD, interrupt line reading only if it has a trap */ |
1975 | ) { | 1975 | ) { |
1976 | bb_got_signal = sig; /* for read_line_input: "we got a signal" */ | 1976 | bb_got_signal = sig; /* for read_line_input / read builtin: "we got a signal" */ |
1977 | } | 1977 | } |
1978 | #endif | 1978 | #endif |
1979 | #if ENABLE_HUSH_FAST | 1979 | #if ENABLE_HUSH_FAST |
@@ -2099,11 +2099,29 @@ static sighandler_t pick_sighandler(unsigned sig) | |||
2099 | return handler; | 2099 | return handler; |
2100 | } | 2100 | } |
2101 | 2101 | ||
2102 | static const char* FAST_FUNC get_local_var_value(const char *name); | ||
2103 | |||
2102 | /* Restores tty foreground process group, and exits. */ | 2104 | /* Restores tty foreground process group, and exits. */ |
2103 | static void hush_exit(int exitcode) | 2105 | static void hush_exit(int exitcode) |
2104 | { | 2106 | { |
2105 | #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT | 2107 | #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT |
2106 | save_history(G.line_input_state); /* may be NULL */ | 2108 | if (G.line_input_state) { |
2109 | const char *hp; | ||
2110 | # if ENABLE_FEATURE_SH_HISTFILESIZE | ||
2111 | // in bash: | ||
2112 | // HISTFILESIZE controls the on-disk history file size (in lines, 0=no history): | ||
2113 | // "When this variable is assigned a value, the history file is truncated, if necessary" | ||
2114 | // but we do it only at exit, not on every assignment: | ||
2115 | /* Use HISTFILESIZE to limit file size */ | ||
2116 | hp = get_local_var_value("HISTFILESIZE"); | ||
2117 | if (hp) | ||
2118 | G.line_input_state->max_history = size_from_HISTFILESIZE(hp); | ||
2119 | # endif | ||
2120 | /* HISTFILE: "If unset, the command history is not saved when a shell exits." */ | ||
2121 | hp = get_local_var_value("HISTFILE"); | ||
2122 | G.line_input_state->hist_file = hp; | ||
2123 | save_history(G.line_input_state); /* no-op if hist_file is NULL or "" */ | ||
2124 | } | ||
2107 | #endif | 2125 | #endif |
2108 | 2126 | ||
2109 | fflush_all(); | 2127 | fflush_all(); |
@@ -4607,6 +4625,11 @@ static int fetch_heredocs(o_string *as_string, struct pipe *pi, int heredoc_cnt, | |||
4607 | 4625 | ||
4608 | redir->rd_type = REDIRECT_HEREDOC2; | 4626 | redir->rd_type = REDIRECT_HEREDOC2; |
4609 | /* redir->rd_dup is (ab)used to indicate <<- */ | 4627 | /* redir->rd_dup is (ab)used to indicate <<- */ |
4628 | if (!redir->rd_filename) { | ||
4629 | /* examples: "echo <<", "echo <<<", "echo <<>" */ | ||
4630 | syntax_error("missing here document terminator"); | ||
4631 | return -1; | ||
4632 | } | ||
4610 | p = fetch_till_str(as_string, input, | 4633 | p = fetch_till_str(as_string, input, |
4611 | redir->rd_filename, redir->rd_dup); | 4634 | redir->rd_filename, redir->rd_dup); |
4612 | if (!p) { | 4635 | if (!p) { |
@@ -10361,6 +10384,9 @@ int hush_main(int argc, char **argv) | |||
10361 | _exit(0); | 10384 | _exit(0); |
10362 | } | 10385 | } |
10363 | G.argv0_for_re_execing = argv[0]; | 10386 | G.argv0_for_re_execing = argv[0]; |
10387 | if (G.argv0_for_re_execing[0] == '-') | ||
10388 | /* reexeced hush should never be a login shell */ | ||
10389 | G.argv0_for_re_execing++; | ||
10364 | #endif | 10390 | #endif |
10365 | #if ENABLE_HUSH_TRAP | 10391 | #if ENABLE_HUSH_TRAP |
10366 | # if ENABLE_HUSH_FUNCTIONS | 10392 | # if ENABLE_HUSH_FUNCTIONS |
@@ -10424,7 +10450,7 @@ int hush_main(int argc, char **argv) | |||
10424 | if (!get_local_var_value("PATH")) | 10450 | if (!get_local_var_value("PATH")) |
10425 | set_local_var_from_halves("PATH", bb_default_root_path); | 10451 | set_local_var_from_halves("PATH", bb_default_root_path); |
10426 | 10452 | ||
10427 | /* PS1/PS2 are set later, if we determine that we are interactive */ | 10453 | /* PS1/PS2/HISTFILE are set later, if we determine that we are interactive */ |
10428 | 10454 | ||
10429 | /* bash also exports SHLVL and _, | 10455 | /* bash also exports SHLVL and _, |
10430 | * and sets (but doesn't export) the following variables: | 10456 | * and sets (but doesn't export) the following variables: |
@@ -10446,7 +10472,6 @@ int hush_main(int argc, char **argv) | |||
10446 | * BASH_SOURCE=() | 10472 | * BASH_SOURCE=() |
10447 | * DIRSTACK=() | 10473 | * DIRSTACK=() |
10448 | * PIPESTATUS=([0]="0") | 10474 | * PIPESTATUS=([0]="0") |
10449 | * HISTFILE=/<xxx>/.bash_history | ||
10450 | * HISTFILESIZE=500 | 10475 | * HISTFILESIZE=500 |
10451 | * HISTSIZE=500 | 10476 | * HISTSIZE=500 |
10452 | * MAILCHECK=60 | 10477 | * MAILCHECK=60 |
@@ -10806,18 +10831,30 @@ int hush_main(int argc, char **argv) | |||
10806 | const char *hp = get_local_var_value("HISTFILE"); | 10831 | const char *hp = get_local_var_value("HISTFILE"); |
10807 | if (!hp) { | 10832 | if (!hp) { |
10808 | hp = get_local_var_value("HOME"); | 10833 | hp = get_local_var_value("HOME"); |
10809 | if (hp) | 10834 | if (hp) { |
10810 | hp = concat_path_file(hp, ".hush_history"); | 10835 | hp = concat_path_file(hp, ".hush_history"); |
10836 | /* Make HISTFILE set on exit (else history won't be saved) */ | ||
10837 | set_local_var_from_halves("HISTFILE", hp); | ||
10838 | } | ||
10811 | } else { | 10839 | } else { |
10812 | hp = xstrdup(hp); | 10840 | hp = xstrdup(hp); |
10813 | } | 10841 | } |
10814 | if (hp) { | 10842 | if (hp) { |
10815 | G.line_input_state->hist_file = hp; | 10843 | G.line_input_state->hist_file = hp; |
10816 | //set_local_var(xasprintf("HISTFILE=%s", ...)); | ||
10817 | } | 10844 | } |
10818 | # if ENABLE_FEATURE_SH_HISTFILESIZE | 10845 | # if ENABLE_FEATURE_SH_HISTFILESIZE |
10819 | hp = get_local_var_value("HISTFILESIZE"); | 10846 | hp = get_local_var_value("HISTSIZE"); |
10847 | /* Using HISTFILESIZE above to limit max_history would be WRONG: | ||
10848 | * users may set HISTFILESIZE=0 in their profile scripts | ||
10849 | * to prevent _saving_ of history files, but still want to have | ||
10850 | * non-zero history limit for in-memory list. | ||
10851 | */ | ||
10852 | // in bash, runtime history size is controlled by HISTSIZE (0=no history), | ||
10853 | // HISTFILESIZE controls on-disk history file size (in lines, 0=no history): | ||
10820 | G.line_input_state->max_history = size_from_HISTFILESIZE(hp); | 10854 | G.line_input_state->max_history = size_from_HISTFILESIZE(hp); |
10855 | // HISTFILESIZE: "The shell sets the default value to the value of HISTSIZE after reading any startup files." | ||
10856 | // HISTSIZE: "The shell sets the default value to 500 after reading any startup files." | ||
10857 | // (meaning: if the value wasn't set after startup files, the default value is set as described above) | ||
10821 | # endif | 10858 | # endif |
10822 | } | 10859 | } |
10823 | # endif | 10860 | # endif |
@@ -11172,6 +11209,11 @@ static int FAST_FUNC builtin_read(char **argv) | |||
11172 | goto again; | 11209 | goto again; |
11173 | } | 11210 | } |
11174 | 11211 | ||
11212 | if ((uintptr_t)r == 2) /* -t SEC timeout? */ | ||
11213 | /* bash: "The exit status is greater than 128 if the timeout is exceeded." */ | ||
11214 | /* The actual value observed with bash 5.2.15: */ | ||
11215 | return 128 + SIGALRM; | ||
11216 | |||
11175 | if ((uintptr_t)r > 1) { | 11217 | if ((uintptr_t)r > 1) { |
11176 | bb_simple_error_msg(r); | 11218 | bb_simple_error_msg(r); |
11177 | r = (char*)(uintptr_t)1; | 11219 | r = (char*)(uintptr_t)1; |
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-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/shell_common.c b/shell/shell_common.c index 7fb5f8c58..657f0df8f 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 */ |
@@ -144,7 +144,7 @@ shell_builtin_read(struct builtin_read_params *params) | |||
144 | * bash seems to ignore -p PROMPT for this use case. | 144 | * bash seems to ignore -p PROMPT for this use case. |
145 | */ | 145 | */ |
146 | int r; | 146 | int r; |
147 | pfd[0].events = POLLIN; | 147 | pfd->events = POLLIN; |
148 | r = poll(pfd, 1, /*timeout:*/ 0); | 148 | r = poll(pfd, 1, /*timeout:*/ 0); |
149 | /* Return 0 only if poll returns 1 ("one fd ready"), else return 1: */ | 149 | /* Return 0 only if poll returns 1 ("one fd ready"), else return 1: */ |
150 | return (const char *)(uintptr_t)(r <= 0); | 150 | return (const char *)(uintptr_t)(r <= 0); |
@@ -209,8 +209,8 @@ shell_builtin_read(struct builtin_read_params *params) | |||
209 | * 32-bit unix time wrapped (year 2038+). | 209 | * 32-bit unix time wrapped (year 2038+). |
210 | */ | 210 | */ |
211 | if (timeout <= 0) { /* already late? */ | 211 | if (timeout <= 0) { /* already late? */ |
212 | retval = (const char *)(uintptr_t)1; | 212 | retval = (const char *)(uintptr_t)2; |
213 | goto ret; | 213 | break; |
214 | } | 214 | } |
215 | } | 215 | } |
216 | 216 | ||
@@ -219,15 +219,23 @@ shell_builtin_read(struct builtin_read_params *params) | |||
219 | * regardless of SA_RESTART-ness of that signal! | 219 | * regardless of SA_RESTART-ness of that signal! |
220 | */ | 220 | */ |
221 | errno = 0; | 221 | errno = 0; |
222 | pfd[0].events = POLLIN; | 222 | pfd->events = POLLIN; |
223 | //TODO race with a signal arriving just before the poll! | 223 | |
224 | #if ENABLE_PLATFORM_MINGW32 | 224 | #if ENABLE_PLATFORM_MINGW32 |
225 | /* Don't poll if timeout is -1, it hurts performance. */ | 225 | /* Don't poll if timeout is -1, it hurts performance. The |
226 | * caution above about interrupts isn't relevant on Windows | ||
227 | * where Ctrl-C causes an event, not a signal. | ||
228 | */ | ||
226 | if (timeout >= 0) | 229 | if (timeout >= 0) |
227 | #endif | 230 | #endif |
228 | if (poll(pfd, 1, timeout) <= 0) { | 231 | /* test bb_got_signal, then poll(), atomically wrt signals */ |
229 | /* timed out, or EINTR */ | 232 | if (check_got_signal_and_poll(pfd, timeout) <= 0) { |
233 | /* timed out, or some error */ | ||
230 | err = errno; | 234 | err = errno; |
235 | if (!err) { /* timed out */ | ||
236 | retval = (const char *)(uintptr_t)2; | ||
237 | break; | ||
238 | } | ||
231 | retval = (const char *)(uintptr_t)1; | 239 | retval = (const char *)(uintptr_t)1; |
232 | goto ret; | 240 | goto ret; |
233 | } | 241 | } |
@@ -238,15 +246,18 @@ shell_builtin_read(struct builtin_read_params *params) | |||
238 | key = windows_read_key(fd, NULL, timeout); | 246 | key = windows_read_key(fd, NULL, timeout); |
239 | if (key == 0x03) { | 247 | if (key == 0x03) { |
240 | /* ^C pressed */ | 248 | /* ^C pressed */ |
241 | retval = (const char *)(uintptr_t)2; | 249 | retval = (const char *)(uintptr_t)3; |
242 | goto ret; | 250 | goto ret; |
243 | } | 251 | } |
244 | else if (key == -1 || (key == 0x1a && bufpos == 0)) { | 252 | else if (key == -1) { |
245 | /* timeout or ^Z at start of buffer */ | 253 | /* timeout */ |
254 | retval = (const char *)(uintptr_t)2; | ||
255 | break; | ||
256 | } else if (key == 0x1a && bufpos == 0) { | ||
257 | /* ^Z at start of buffer */ | ||
246 | retval = (const char *)(uintptr_t)1; | 258 | retval = (const char *)(uintptr_t)1; |
247 | goto ret; | 259 | break; |
248 | } | 260 | } else if (key == '\b') { |
249 | else if (key == '\b') { | ||
250 | if (bufpos > 0) { | 261 | if (bufpos > 0) { |
251 | --bufpos; | 262 | --bufpos; |
252 | ++nchars; | 263 | ++nchars; |
@@ -278,7 +289,7 @@ shell_builtin_read(struct builtin_read_params *params) | |||
278 | * and exit BS context. | 289 | * and exit BS context. |
279 | * - CR LF not in BS context: replace CR with LF */ | 290 | * - CR LF not in BS context: replace CR with LF */ |
280 | buffer[--bufpos] = c; | 291 | buffer[--bufpos] = c; |
281 | ++nchars; | 292 | nchars += 1 + (backslash == 2); |
282 | } | 293 | } |
283 | } else if (backslash == 2) { | 294 | } else if (backslash == 2) { |
284 | /* We saw BS CR ??, keep escaped CR, exit BS context, | 295 | /* We saw BS CR ??, keep escaped CR, exit BS context, |
@@ -298,6 +309,9 @@ shell_builtin_read(struct builtin_read_params *params) | |||
298 | backslash = 0; | 309 | backslash = 0; |
299 | if (c != '\n') | 310 | if (c != '\n') |
300 | goto put; | 311 | goto put; |
312 | #if ENABLE_PLATFORM_MINGW32 | ||
313 | ++nchars; | ||
314 | #endif | ||
301 | continue; | 315 | continue; |
302 | } | 316 | } |
303 | if (c == '\\') { | 317 | if (c == '\\') { |
@@ -338,7 +352,7 @@ shell_builtin_read(struct builtin_read_params *params) | |||
338 | } | 352 | } |
339 | put: | 353 | put: |
340 | bufpos++; | 354 | bufpos++; |
341 | } while (--nchars); | 355 | } while (IF_PLATFORM_MINGW32(backslash ||) --nchars); |
342 | 356 | ||
343 | if (argv[0]) { | 357 | if (argv[0]) { |
344 | /* Remove trailing space $IFS chars */ | 358 | /* Remove trailing space $IFS chars */ |
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/cut.tests b/testsuite/cut.tests index a31f41f7f..21cfea809 100755 --- a/testsuite/cut.tests +++ b/testsuite/cut.tests | |||
@@ -23,14 +23,30 @@ the quick brown fox jumps over the lazy dog | |||
23 | 23 | ||
24 | testing "cut -b a,a,a" "cut -b 3,3,3 input" "e\np\ne\n" "$abc" "" | 24 | testing "cut -b a,a,a" "cut -b 3,3,3 input" "e\np\ne\n" "$abc" "" |
25 | 25 | ||
26 | testing "cut -b overlaps" "cut -b 1-3,2-5,7-9,9-10 input" \ | 26 | testing "cut -b overlaps" \ |
27 | "one:to:th\nalphabeta\nthe qick \n" "$abc" "" | 27 | "cut -b 1-3,2-5,7-9,9-10 input" \ |
28 | testing "-b encapsulated" "cut -b 3-8,4-6 input" "e:two:\npha:be\ne quic\n" \ | 28 | "\ |
29 | "$abc" "" | 29 | one:to:th |
30 | # --output-delimiter not implemnted (yet?) | 30 | alphabeta |
31 | #testing "cut -bO overlaps" \ | 31 | the qick \n" \ |
32 | # "cut --output-delimiter ' ' -b 1-3,2-5,7-9,9-10 input" \ | 32 | "$abc" "" |
33 | # "one:t o:th\nalpha beta\nthe q ick \n" "$abc" "" | 33 | testing "-b encapsulated" \ |
34 | "cut -b 3-8,4-6 input" \ | ||
35 | "\ | ||
36 | e:two: | ||
37 | pha:be | ||
38 | e quic\n" \ | ||
39 | "$abc" "" | ||
40 | optional LONG_OPTS | ||
41 | testing "cut -b --output-delimiter overlaps" \ | ||
42 | "cut --output-delimiter='^' -b 1-3,2-5,7-9,9-10 input" \ | ||
43 | "\ | ||
44 | one:t^o:th | ||
45 | alpha^beta | ||
46 | the q^ick \n" \ | ||
47 | "$abc" "" | ||
48 | SKIP= | ||
49 | |||
34 | testing "cut high-low error" "cut -b 8-3 input 2>/dev/null || echo err" "err\n" \ | 50 | testing "cut high-low error" "cut -b 8-3 input 2>/dev/null || echo err" "err\n" \ |
35 | "$abc" "" | 51 | "$abc" "" |
36 | 52 | ||
@@ -68,10 +84,27 @@ testing "cut with -d -f( ) -s" "cut -d' ' -f3 -s input && echo yes" "yes\n" "$in | |||
68 | testing "cut with -d -f(a) -s" "cut -da -f3 -s input" "n\nsium:Jim\n\ncion:Ed\n" "$input" "" | 84 | testing "cut with -d -f(a) -s" "cut -da -f3 -s input" "n\nsium:Jim\n\ncion:Ed\n" "$input" "" |
69 | testing "cut with -d -f(a) -s -n" "cut -da -f3 -s -n input" "n\nsium:Jim\n\ncion:Ed\n" "$input" "" | 85 | testing "cut with -d -f(a) -s -n" "cut -da -f3 -s -n input" "n\nsium:Jim\n\ncion:Ed\n" "$input" "" |
70 | 86 | ||
87 | input="\ | ||
88 | |||
89 | foo bar baz | ||
90 | |||
91 | bing bong boop | ||
92 | |||
93 | " | ||
94 | testing "cut with -d -s omits blank lines" "cut -d' ' -f2 -s input" "bar\nbong\n" "$input" "" | ||
95 | |||
71 | # substitute for awk | 96 | # substitute for awk |
72 | optional FEATURE_CUT_REGEX | 97 | optional FEATURE_CUT_REGEX |
73 | testing "cut -DF" "cut -DF 2,7,5" \ | 98 | testing "cut -DF unordered" "cut -DF 2,7,5" \ |
74 | "said and your\nare\nis demand. supply\nforecast :\nyou you better,\n\nEm: Took hate\n" "" \ | 99 | "\ |
100 | said and your | ||
101 | are | ||
102 | is demand. supply | ||
103 | forecast : | ||
104 | you you better, | ||
105 | |||
106 | Em: Took hate | ||
107 | " "" \ | ||
75 | "Bother, said Pooh. It's your husband, and he has a gun. | 108 | "Bother, said Pooh. It's your husband, and he has a gun. |
76 | Cheerios are donut seeds. | 109 | Cheerios are donut seeds. |
77 | Talk is cheap because supply exceeds demand. | 110 | Talk is cheap because supply exceeds demand. |
@@ -79,9 +112,92 @@ Weather forecast for tonight : dark. | |||
79 | Apple: you can buy better, but you can't pay more. | 112 | Apple: you can buy better, but you can't pay more. |
80 | Subcalifragilisticexpialidocious. | 113 | Subcalifragilisticexpialidocious. |
81 | Auntie Em: Hate you, hate Kansas. Took the dog. Dorothy." | 114 | Auntie Em: Hate you, hate Kansas. Took the dog. Dorothy." |
115 | |||
116 | # No delimiter found: print entire line regardless of -F RANGES | ||
117 | testing "cut -F1" "cut -d: -F1" \ | ||
118 | "the_only_field\n" "" \ | ||
119 | "the_only_field\n" | ||
120 | testing "cut -F2" "cut -d: -F2" \ | ||
121 | "the_only_field\n" "" \ | ||
122 | "the_only_field\n" | ||
123 | # No delimiter found and -s: skip entire line | ||
124 | testing "cut -sF1" "cut -d: -sF1" \ | ||
125 | "" "" \ | ||
126 | "the_only_field\n" | ||
127 | #^^^ the above is probably mishandled by toybox, it prints the line | ||
128 | testing "cut -sF2" "cut -d: -sF2" \ | ||
129 | "" "" \ | ||
130 | "the_only_field\n" | ||
131 | # -D disables special handling of lines with no delimiters, the line is treated as the 1st field | ||
132 | testing "cut -DF1" "cut -d: -DF1" \ | ||
133 | "the_only_field\n" "" \ | ||
134 | "the_only_field\n" | ||
135 | testing "cut -DF2" "cut -d: -DF2" \ | ||
136 | "\n" "" \ | ||
137 | "the_only_field\n" | ||
138 | |||
139 | optional FEATURE_CUT_REGEX LONG_OPTS | ||
140 | testing "cut -F preserves intermediate delimiters" \ | ||
141 | "cut --output-delimiter=: -F2,4-6,7" \ | ||
142 | "2:4 5 6:7\n" \ | ||
143 | "" "1 2 3 4\t\t5 6 7 8\n" | ||
144 | SKIP= | ||
145 | |||
146 | optional LONG_OPTS | ||
147 | testing "cut -f does not preserve intermediate delimiters" \ | ||
148 | "cut --output-delimiter=: -d' ' -f2,4-6,7" \ | ||
149 | "2:4:5:6:7\n" \ | ||
150 | "" "1 2 3 4 5 6 7 8\n" | ||
151 | SKIP= | ||
152 | |||
153 | testing "cut empty field" "cut -d ':' -f 1-3" \ | ||
154 | "a::b\n" \ | ||
155 | "" "a::b\n" | ||
156 | testing "cut empty field 2" "cut -d ':' -f 3-5" \ | ||
157 | "b::c\n" \ | ||
158 | "" "a::b::c:d\n" | ||
159 | testing "cut non-existing field" "cut -d ':' -f1,3" \ | ||
160 | "1\n" \ | ||
161 | "" "1:\n" | ||
162 | |||
163 | # cut -d$'\n' has a special meaning: "select input lines". | ||
164 | # I didn't find any documentation for this feature. | ||
165 | testing "cut -dNEWLINE" \ | ||
166 | "cut -d' | ||
167 | ' -f4,2,6-8" \ | ||
168 | "2\n4\n6\n7\n" \ | ||
169 | "" "1\n2\n3\n4\n5\n6\n7" | ||
170 | |||
171 | optional LONG_OPTS | ||
172 | testing "cut -dNEWLINE --output-delimiter" \ | ||
173 | "cut -d' | ||
174 | ' --output-delimiter=@@ -f4,2,6-8" \ | ||
175 | "2@@4@@6@@7\n" \ | ||
176 | "" "1\n2\n3\n4\n5\n6\n7" | ||
177 | |||
178 | testing "cut -dNEWLINE --output-delimiter 2" \ | ||
179 | "cut -d' | ||
180 | ' --output-delimiter=@@ -f4,2,6-8" \ | ||
181 | "2@@4@@6@@7\n" \ | ||
182 | "" "1\n2\n3\n4\n5\n6\n7\n" | ||
183 | |||
184 | testing "cut -dNEWLINE --output-delimiter EMPTY_INPUT" \ | ||
185 | "cut -d' | ||
186 | ' --output-delimiter=@@ -f4,2,6-8" \ | ||
187 | "" \ | ||
188 | "" "" | ||
82 | SKIP= | 189 | SKIP= |
83 | 190 | ||
84 | testing "cut empty field" "cut -d ':' -f 1-3" "a::b\n" "" "a::b\n" | 191 | # This seems to work as if delimiter is never found. |
85 | testing "cut empty field 2" "cut -d ':' -f 3-5" "b::c\n" "" "a::b::c:d\n" | 192 | # We test here that -d '' does *not* operate as if there was no -d |
193 | # and delimiter has defaulted to TAB: | ||
194 | testing "cut -d EMPTY" \ | ||
195 | "cut -d '' -f2-" \ | ||
196 | "1 2\t3 4 5\n" \ | ||
197 | "" "1 2\t3 4 5\n" | ||
198 | testing "cut -d EMPTY -s" \ | ||
199 | "cut -d '' -f2- -s" \ | ||
200 | "" \ | ||
201 | "" "1 2\t3 4 5\n" | ||
86 | 202 | ||
87 | exit $FAILCOUNT | 203 | exit $FAILCOUNT |
diff --git a/testsuite/hexdump.tests b/testsuite/hexdump.tests index be0379cfc..b2f6a2201 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,7 @@ 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"\ | ||
48 | "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"\ | ||
49 | "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"\ | ||
50 | "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"\ | ||
51 | "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"\ | ||
52 | 58 | ||
53 | testing "hexdump -e /1 %d" \ | 59 | testing "hexdump -e /1 %d" \ |
54 | "hexdump -e '16/1 \" %4d\" \"\n\"'" \ | 60 | "hexdump -e '16/1 \" %4d\" \"\n\"'" \ |
@@ -59,27 +65,74 @@ testing "hexdump -e /1 %d" \ | |||
59 | -128 -127 -126 -125 -124 -123 -122 -121 -120 -119 -118 -117 -116 -115 -114 -113 | 65 | -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 | 66 | -16 -15 -14 -13 -12 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 |
61 | " \ | 67 | " \ |
62 | "" \ | 68 | "" "$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 | 69 | ||
69 | testing "hexdump -e /2 %d" \ | 70 | $little_endian || SKIP=1 |
70 | "hexdump -e '8/2 \" %6d\" \"\n\"'" \ | 71 | testing "hexdump -e /2 %d (little endian)" \ |
71 | "\ | 72 | "hexdump -e '8/2 \" %6d\" \"\n\"'" \ |
73 | "\ | ||
72 | 256 770 1284 1798 2312 2826 3340 3854 | 74 | 256 770 1284 1798 2312 2826 3340 3854 |
73 | 4368 4882 5396 5910 6424 6938 7452 7966 | 75 | 4368 4882 5396 5910 6424 6938 7452 7966 |
74 | 29040 29554 30068 30582 31096 31610 32124 32638 | 76 | 29040 29554 30068 30582 31096 31610 32124 32638 |
75 | -32384 -31870 -31356 -30842 -30328 -29814 -29300 -28786 | 77 | -32384 -31870 -31356 -30842 -30328 -29814 -29300 -28786 |
76 | -3600 -3086 -2572 -2058 -1544 -1030 -516 -2 | 78 | -3600 -3086 -2572 -2058 -1544 -1030 -516 -2 |
77 | " \ | 79 | " \ |
80 | "" "$input" | ||
81 | SKIP= | ||
82 | |||
83 | $little_endian && SKIP=1 | ||
84 | testing "hexdump -e /2 %d (big endian)" \ | ||
85 | "hexdump -e '8/2 \" %6d\" \"\n\"'" \ | ||
86 | "\ | ||
87 | 1 515 1029 1543 2057 2571 3085 3599 | ||
88 | 4113 4627 5141 5655 6169 6683 7197 7711 | ||
89 | 28785 29299 29813 30327 30841 31355 31869 32383 | ||
90 | -32639 -32125 -31611 -31097 -30583 -30069 -29555 -29041 | ||
91 | -3855 -3341 -2827 -2313 -1799 -1285 -771 -257 | ||
92 | " \ | ||
93 | "" "$input" | ||
94 | SKIP= | ||
95 | |||
96 | $little_endian || SKIP=1 | ||
97 | testing "hexdump -e /2 %x (little endian)" \ | ||
98 | "hexdump -e '8/2 \" %6x\" \"\n\"'" \ | ||
99 | "\ | ||
100 | 100 302 504 706 908 b0a d0c f0e | ||
101 | 1110 1312 1514 1716 1918 1b1a 1d1c 1f1e | ||
102 | 7170 7372 7574 7776 7978 7b7a 7d7c 7f7e | ||
103 | 8180 8382 8584 8786 8988 8b8a 8d8c 8f8e | ||
104 | f1f0 f3f2 f5f4 f7f6 f9f8 fbfa fdfc fffe | ||
105 | " \ | ||
106 | "" "$input" | ||
107 | SKIP= | ||
108 | |||
109 | $little_endian && SKIP=1 | ||
110 | testing "hexdump -e /2 %x (big endian)" \ | ||
111 | "hexdump -e '8/2 \" %6x\" \"\n\"'" \ | ||
112 | "\ | ||
113 | 1 203 405 607 809 a0b c0d e0f | ||
114 | 1011 1213 1415 1617 1819 1a1b 1c1d 1e1f | ||
115 | 7071 7273 7475 7677 7879 7a7b 7c7d 7e7f | ||
116 | 8081 8283 8485 8687 8889 8a8b 8c8d 8e8f | ||
117 | f0f1 f2f3 f4f5 f6f7 f8f9 fafb fcfd feff | ||
118 | " \ | ||
119 | "" "$input" | ||
120 | SKIP= | ||
121 | |||
122 | $little_endian || SKIP=1 | ||
123 | testing "hexdump -n4 -e '\"%u\"' (little endian)" \ | ||
124 | "hexdump -n4 -e '\"%u\"'" \ | ||
125 | "12345678" \ | ||
78 | "" \ | 126 | "" \ |
79 | "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"\ | 127 | "\x4e\x61\xbc\x00AAAA" |
80 | "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"\ | 128 | SKIP= |
81 | "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"\ | 129 | |
82 | "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"\ | 130 | $little_endian && SKIP=1 |
83 | "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"\ | 131 | testing "hexdump -n4 -e '\"%u\"' (big endian)" \ |
132 | "hexdump -n4 -e '\"%u\"'" \ | ||
133 | "1315027968" \ | ||
134 | "" \ | ||
135 | "\x4e\x61\xbc\x00AAAA" | ||
136 | SKIP= | ||
84 | 137 | ||
85 | exit $FAILCOUNT | 138 | exit $FAILCOUNT |
diff --git a/testsuite/make.tests b/testsuite/make.tests index 376bdcc15..fabdbe45c 100755 --- a/testsuite/make.tests +++ b/testsuite/make.tests | |||
@@ -86,6 +86,16 @@ test.k: | |||
86 | ' | 86 | ' |
87 | cd .. || exit 1; rm -rf make.tempdir 2>/dev/null | 87 | cd .. || exit 1; rm -rf make.tempdir 2>/dev/null |
88 | 88 | ||
89 | # Check that single-suffix inference rules work. | ||
90 | mkdir make.tempdir && cd make.tempdir || exit 1 | ||
91 | touch test.sh | ||
92 | testing "make single-suffix inference rule works" \ | ||
93 | "make -f - -s; echo $?" \ | ||
94 | "0\n" "" ' | ||
95 | test: | ||
96 | ' | ||
97 | cd .. || exit 1; rm -rf make.tempdir 2>/dev/null | ||
98 | |||
89 | # There was a bug where the failure of a build command didn't result | 99 | # There was a bug where the failure of a build command didn't result |
90 | # in make returning a non-zero exit status. | 100 | # in make returning a non-zero exit status. |
91 | testing "make return error if command fails" \ | 101 | testing "make return error if command fails" \ |
@@ -541,6 +551,36 @@ testing "make chained inference rules" \ | |||
541 | ' | 551 | ' |
542 | cd .. || exit 1; rm -rf make.tempdir 2>/dev/null | 552 | cd .. || exit 1; rm -rf make.tempdir 2>/dev/null |
543 | 553 | ||
554 | # Suffixes with multiple periods are supported | ||
555 | mkdir make.tempdir && cd make.tempdir || exit 1 | ||
556 | touch x.c.c | ||
557 | testing "make support multi-period suffixes" \ | ||
558 | "make -f -" "cat x.c.c >x.o.o\nx\n" "" ' | ||
559 | .SUFFIXES: .c.c .o.o | ||
560 | x.o.o: | ||
561 | .c.c.o.o: | ||
562 | cat $< >$@ | ||
563 | @echo $* | ||
564 | ' | ||
565 | cd .. || exit 1; rm -rf make.tempdir 2>/dev/null | ||
566 | |||
567 | # Suffixes with no periods are supported | ||
568 | mkdir make.tempdir && cd make.tempdir || exit 1 | ||
569 | touch filex | ||
570 | testing "make support suffixes without any periods" \ | ||
571 | "make -f -" "cp filex fileh\nfile\ncp filex filez\nfile\n" "" ' | ||
572 | .SUFFIXES: x h z | ||
573 | all: fileh filez | ||
574 | fileh: | ||
575 | filez: filex | ||
576 | cp filex filez | ||
577 | @echo $* | ||
578 | xh: | ||
579 | cp $< $@ | ||
580 | @echo $* | ||
581 | ' | ||
582 | cd .. || exit 1; rm -rf make.tempdir 2>/dev/null | ||
583 | |||
544 | # make supports *, ? and [] wildcards in targets and prerequisites | 584 | # make supports *, ? and [] wildcards in targets and prerequisites |
545 | mkdir make.tempdir && cd make.tempdir || exit 1 | 585 | mkdir make.tempdir && cd make.tempdir || exit 1 |
546 | touch -t 202206171201 t1a t2aa t3b | 586 | touch -t 202206171201 t1a t2aa t3b |
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/wget/wget-handles-https b/testsuite/wget/wget-handles-https new file mode 100644 index 000000000..11915f42f --- /dev/null +++ b/testsuite/wget/wget-handles-https | |||
@@ -0,0 +1,4 @@ | |||
1 | test x"$SKIP_INTERNET_TESTS" != x"" && exit | ||
2 | |||
3 | busybox wget -q -O foo https://www.google.com/ | ||
4 | test -s foo | ||
diff --git a/win32/dirent.c b/win32/dirent.c index 795fc779c..f0e8deae2 100644 --- a/win32/dirent.c +++ b/win32/dirent.c | |||
@@ -3,7 +3,9 @@ | |||
3 | struct DIR { | 3 | struct DIR { |
4 | struct dirent dd_dir; | 4 | struct dirent dd_dir; |
5 | HANDLE dd_handle; /* FindFirstFile handle */ | 5 | HANDLE dd_handle; /* FindFirstFile handle */ |
6 | int dd_stat; /* 0-based index */ | 6 | int not_first; |
7 | int got_dot; | ||
8 | int got_dotdot; | ||
7 | }; | 9 | }; |
8 | 10 | ||
9 | static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata) | 11 | static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata) |
@@ -59,9 +61,11 @@ DIR *opendir(const char *name) | |||
59 | } | 61 | } |
60 | 62 | ||
61 | /* initialize DIR structure and copy first dir entry */ | 63 | /* initialize DIR structure and copy first dir entry */ |
62 | dir = xmalloc(sizeof(DIR)); | 64 | dir = xzalloc(sizeof(DIR)); |
63 | dir->dd_handle = h; | 65 | dir->dd_handle = h; |
64 | dir->dd_stat = 0; | 66 | /* dir->not_first = 0; */ |
67 | /* dir->got_dot = 0; */ | ||
68 | /* dir->got_dotdot = 0; */ | ||
65 | finddata2dirent(&dir->dd_dir, &fdata); | 69 | finddata2dirent(&dir->dd_dir, &fdata); |
66 | return dir; | 70 | return dir; |
67 | } | 71 | } |
@@ -74,11 +78,17 @@ struct dirent *readdir(DIR *dir) | |||
74 | } | 78 | } |
75 | 79 | ||
76 | /* if first entry, dirent has already been set up by opendir */ | 80 | /* if first entry, dirent has already been set up by opendir */ |
77 | if (dir->dd_stat) { | 81 | if (dir->not_first) { |
78 | /* get next entry and convert from WIN32_FIND_DATA to dirent */ | 82 | /* get next entry and convert from WIN32_FIND_DATA to dirent */ |
79 | WIN32_FIND_DATAA fdata; | 83 | WIN32_FIND_DATAA fdata; |
80 | if (FindNextFileA(dir->dd_handle, &fdata)) { | 84 | if (FindNextFileA(dir->dd_handle, &fdata)) { |
81 | finddata2dirent(&dir->dd_dir, &fdata); | 85 | finddata2dirent(&dir->dd_dir, &fdata); |
86 | } else if (!dir->got_dot) { | ||
87 | strcpy(dir->dd_dir.d_name, "."); | ||
88 | dir->dd_dir.d_type = DT_DIR; | ||
89 | } else if (!dir->got_dotdot) { | ||
90 | strcpy(dir->dd_dir.d_name, ".."); | ||
91 | dir->dd_dir.d_type = DT_DIR; | ||
82 | } else { | 92 | } else { |
83 | DWORD lasterr = GetLastError(); | 93 | DWORD lasterr = GetLastError(); |
84 | /* POSIX says you shouldn't set errno when readdir can't | 94 | /* POSIX says you shouldn't set errno when readdir can't |
@@ -89,7 +99,15 @@ struct dirent *readdir(DIR *dir) | |||
89 | } | 99 | } |
90 | } | 100 | } |
91 | 101 | ||
92 | ++dir->dd_stat; | 102 | /* Have we seen '.' or '..'? */ |
103 | if (dir->dd_dir.d_name[0] == '.') { | ||
104 | if (dir->dd_dir.d_name[1] == '\0') | ||
105 | dir->got_dot = TRUE; | ||
106 | else if (dir->dd_dir.d_name[1] == '.' && dir->dd_dir.d_name[2] == '\0') | ||
107 | dir->got_dotdot = TRUE; | ||
108 | } | ||
109 | |||
110 | dir->not_first = TRUE; | ||
93 | return &dir->dd_dir; | 111 | return &dir->dd_dir; |
94 | } | 112 | } |
95 | 113 | ||
diff --git a/win32/glob.c b/win32/glob.c index 1cc6483e7..35a1e9a65 100644 --- a/win32/glob.c +++ b/win32/glob.c | |||
@@ -298,7 +298,7 @@ int glob(const char *restrict pat, int flags, int (*errfunc)(const char *path, i | |||
298 | if (append(&tail, pat, strlen(pat), 0)) | 298 | if (append(&tail, pat, strlen(pat), 0)) |
299 | return GLOB_NOSPACE; | 299 | return GLOB_NOSPACE; |
300 | cnt++; | 300 | cnt++; |
301 | } else | 301 | } else if (!error) |
302 | return GLOB_NOMATCH; | 302 | return GLOB_NOMATCH; |
303 | } | 303 | } |
304 | 304 | ||
diff --git a/win32/inet_pton.c b/win32/inet_pton.c index f229a9355..eec8bd2fe 100644 --- a/win32/inet_pton.c +++ b/win32/inet_pton.c | |||
@@ -78,6 +78,7 @@ int inet_pton(int af, const char *restrict s, void *restrict a0) | |||
78 | if (s[j]!='.' || (i<6 && brk<0)) return 0; | 78 | if (s[j]!='.' || (i<6 && brk<0)) return 0; |
79 | need_v4=1; | 79 | need_v4=1; |
80 | i++; | 80 | i++; |
81 | ip[i&7]=0; | ||
81 | break; | 82 | break; |
82 | } | 83 | } |
83 | s += j+1; | 84 | s += j+1; |
diff --git a/win32/ioctl.c b/win32/ioctl.c index 93f9f504d..d0ed68d61 100644 --- a/win32/ioctl.c +++ b/win32/ioctl.c | |||
@@ -1,5 +1,7 @@ | |||
1 | #include "libbb.h" | 1 | #include "libbb.h" |
2 | #include "lazyload.h" | ||
2 | 3 | ||
4 | #if ENABLE_STTY || ENABLE_TTYSIZE | ||
3 | static int mingw_get_terminal_width_height(struct winsize *win) | 5 | static int mingw_get_terminal_width_height(struct winsize *win) |
4 | { | 6 | { |
5 | int fd; | 7 | int fd; |
@@ -21,6 +23,45 @@ static int mingw_get_terminal_width_height(struct winsize *win) | |||
21 | 23 | ||
22 | return -1; | 24 | return -1; |
23 | } | 25 | } |
26 | #endif | ||
27 | |||
28 | #if ENABLE_STTY | ||
29 | static int mingw_set_terminal_width_height(struct winsize *win) | ||
30 | { | ||
31 | BOOL ret; | ||
32 | DECLARE_PROC_ADDR(BOOL, GetConsoleScreenBufferInfoEx, HANDLE, | ||
33 | PCONSOLE_SCREEN_BUFFER_INFOEX); | ||
34 | DECLARE_PROC_ADDR(BOOL, SetConsoleScreenBufferInfoEx, HANDLE, | ||
35 | PCONSOLE_SCREEN_BUFFER_INFOEX); | ||
36 | |||
37 | if (!INIT_PROC_ADDR(kernel32.dll, GetConsoleScreenBufferInfoEx)) | ||
38 | return -1; | ||
39 | if (!INIT_PROC_ADDR(kernel32.dll, SetConsoleScreenBufferInfoEx)) | ||
40 | return -1; | ||
41 | |||
42 | for (int fd = STDOUT_FILENO; fd <= STDERR_FILENO; ++fd) { | ||
43 | CONSOLE_SCREEN_BUFFER_INFOEX sbi; | ||
44 | HANDLE handle = (HANDLE)_get_osfhandle(fd); | ||
45 | |||
46 | sbi.cbSize = sizeof(sbi); | ||
47 | if (handle != INVALID_HANDLE_VALUE && | ||
48 | (ret=GetConsoleScreenBufferInfoEx(handle, &sbi)) != 0) { | ||
49 | if (sbi.dwSize.X != win->ws_col) { | ||
50 | sbi.dwSize.X = win->ws_col; | ||
51 | } | ||
52 | if (sbi.dwSize.Y < win->ws_row) { | ||
53 | sbi.dwSize.Y = win->ws_row; | ||
54 | } | ||
55 | sbi.srWindow.Bottom = sbi.srWindow.Top + win->ws_row; | ||
56 | sbi.srWindow.Right = sbi.srWindow.Left + win->ws_col; | ||
57 | ret = SetConsoleScreenBufferInfoEx(handle, &sbi); | ||
58 | break; | ||
59 | } | ||
60 | } | ||
61 | |||
62 | return ret ? 0 : -1; | ||
63 | } | ||
64 | #endif | ||
24 | 65 | ||
25 | int ioctl(int fd UNUSED_PARAM, int code, ...) | 66 | int ioctl(int fd UNUSED_PARAM, int code, ...) |
26 | { | 67 | { |
@@ -31,10 +72,18 @@ int ioctl(int fd UNUSED_PARAM, int code, ...) | |||
31 | va_start(ap, code); | 72 | va_start(ap, code); |
32 | 73 | ||
33 | switch (code) { | 74 | switch (code) { |
75 | #if ENABLE_STTY || ENABLE_TTYSIZE | ||
34 | case TIOCGWINSZ: | 76 | case TIOCGWINSZ: |
35 | arg = va_arg(ap, void *); | 77 | arg = va_arg(ap, void *); |
36 | ret = mingw_get_terminal_width_height((struct winsize *)arg); | 78 | ret = mingw_get_terminal_width_height((struct winsize *)arg); |
37 | break; | 79 | break; |
80 | #endif | ||
81 | #if ENABLE_STTY | ||
82 | case TIOCSWINSZ: | ||
83 | arg = va_arg(ap, void *); | ||
84 | ret = mingw_set_terminal_width_height((struct winsize *)arg); | ||
85 | break; | ||
86 | #endif | ||
38 | default: | 87 | default: |
39 | ret = -1; | 88 | ret = -1; |
40 | errno = EINVAL; | 89 | errno = EINVAL; |
diff --git a/win32/mingw.c b/win32/mingw.c index 7a5198ccf..061e7bac6 100644 --- a/win32/mingw.c +++ b/win32/mingw.c | |||
@@ -2538,3 +2538,34 @@ char * FAST_FUNC exe_relative_path(const char *tail) | |||
2538 | free(exepath); | 2538 | free(exepath); |
2539 | return relpath; | 2539 | return relpath; |
2540 | } | 2540 | } |
2541 | |||
2542 | int mingw_shell_execute(SHELLEXECUTEINFO *info) | ||
2543 | { | ||
2544 | DECLARE_PROC_ADDR(BOOL, ShellExecuteExA, SHELLEXECUTEINFOA *); | ||
2545 | char *lpath; | ||
2546 | int ret; | ||
2547 | |||
2548 | if (!INIT_PROC_ADDR(shell32.dll, ShellExecuteExA)) { | ||
2549 | errno = ENOSYS; | ||
2550 | return FALSE; | ||
2551 | } | ||
2552 | |||
2553 | // ShellExecuteEx() needs backslash as separator in UNC paths. | ||
2554 | lpath = xstrdup(info->lpFile); | ||
2555 | slash_to_bs(lpath); | ||
2556 | info->lpFile = lpath; | ||
2557 | |||
2558 | ret = ShellExecuteExA(info); | ||
2559 | |||
2560 | free(lpath); | ||
2561 | return ret; | ||
2562 | } | ||
2563 | |||
2564 | #if ENABLE_FEATURE_USE_CNG_API | ||
2565 | void mingw_die_if_error(NTSTATUS status, const char *function_name) { | ||
2566 | if (!NT_SUCCESS(status)) { | ||
2567 | bb_error_msg_and_die("call to %s failed: 0x%08lX", | ||
2568 | function_name, (unsigned long)status); | ||
2569 | } | ||
2570 | } | ||
2571 | #endif | ||
diff --git a/win32/process.c b/win32/process.c index e7c9ca187..33f45ee42 100644 --- a/win32/process.c +++ b/win32/process.c | |||
@@ -331,7 +331,9 @@ mingw_spawn_interpreter(int mode, const char *prog, char *const *argv, | |||
331 | } else { | 331 | } else { |
332 | errno = ENOENT; | 332 | errno = ENOENT; |
333 | } | 333 | } |
334 | #if ENABLE_FEATURE_PREFER_APPLETS && NUM_APPLETS > 1 | ||
334 | done: | 335 | done: |
336 | #endif | ||
335 | free(path); | 337 | free(path); |
336 | free(new_argv); | 338 | free(new_argv); |
337 | return ret; | 339 | return ret; |
@@ -499,6 +501,38 @@ static NORETURN void wait_for_child(HANDLE child, const char *cmd) | |||
499 | exit((int)code); | 501 | exit((int)code); |
500 | } | 502 | } |
501 | 503 | ||
504 | static intptr_t | ||
505 | shell_execute(const char *path, char *const *argv) | ||
506 | { | ||
507 | SHELLEXECUTEINFO info; | ||
508 | char *args; | ||
509 | |||
510 | memset(&info, 0, sizeof(SHELLEXECUTEINFO)); | ||
511 | info.cbSize = sizeof(SHELLEXECUTEINFO); | ||
512 | info.fMask = SEE_MASK_NOCLOSEPROCESS; | ||
513 | /* info.hwnd = NULL; */ | ||
514 | info.lpVerb = "runas"; | ||
515 | info.lpFile = path; | ||
516 | |||
517 | args = NULL; | ||
518 | if (*argv++) { | ||
519 | while (*argv) { | ||
520 | char *q = quote_arg(*argv++); | ||
521 | args = xappendword(args, q); | ||
522 | free(q); | ||
523 | } | ||
524 | } | ||
525 | |||
526 | info.lpParameters = args; | ||
527 | /* info.lpDirectory = NULL; */ | ||
528 | info.nShow = SW_SHOWNORMAL; | ||
529 | |||
530 | mingw_shell_execute(&info); | ||
531 | |||
532 | free(args); | ||
533 | return info.hProcess ? (intptr_t)info.hProcess : -1; | ||
534 | } | ||
535 | |||
502 | int | 536 | int |
503 | mingw_execvp(const char *cmd, char *const *argv) | 537 | mingw_execvp(const char *cmd, char *const *argv) |
504 | { | 538 | { |
@@ -512,6 +546,16 @@ int | |||
512 | mingw_execve(const char *cmd, char *const *argv, char *const *envp) | 546 | mingw_execve(const char *cmd, char *const *argv, char *const *envp) |
513 | { | 547 | { |
514 | intptr_t ret = mingw_spawn_interpreter(P_NOWAIT, cmd, argv, envp, 0); | 548 | intptr_t ret = mingw_spawn_interpreter(P_NOWAIT, cmd, argv, envp, 0); |
549 | |||
550 | if (ret == -1 && GetLastError() == ERROR_ELEVATION_REQUIRED) { | ||
551 | // Command exists but failed because it wants elevated privileges. | ||
552 | // Try again using ShellExecuteEx(). | ||
553 | SetLastError(0); | ||
554 | ret = shell_execute(cmd, argv); | ||
555 | if (GetLastError()) | ||
556 | exit(1); | ||
557 | } | ||
558 | |||
515 | if (ret != -1) | 559 | if (ret != -1) |
516 | wait_for_child((HANDLE)ret, cmd); | 560 | wait_for_child((HANDLE)ret, cmd); |
517 | return ret; | 561 | return ret; |
diff --git a/win32/select.c b/win32/select.c index 2be221ac8..46a051cfc 100644 --- a/win32/select.c +++ b/win32/select.c | |||
@@ -273,8 +273,11 @@ mingw_select (int nfds, fd_set *rfds, fd_set *wfds, fd_set *xfds, | |||
273 | int i, fd, rc; | 273 | int i, fd, rc; |
274 | clock_t tend = 0; | 274 | clock_t tend = 0; |
275 | 275 | ||
276 | if (nfds > FD_SETSIZE) | 276 | if (nfds < 0 || nfds > FD_SETSIZE) |
277 | nfds = FD_SETSIZE; | 277 | { |
278 | errno = EINVAL; | ||
279 | return -1; | ||
280 | } | ||
278 | 281 | ||
279 | if (!timeout) | 282 | if (!timeout) |
280 | wait_timeout = INFINITE; | 283 | wait_timeout = INFINITE; |
diff --git a/win32/strptime.c b/win32/strptime.c index 3205b95a2..c12e96202 100644 --- a/win32/strptime.c +++ b/win32/strptime.c | |||
@@ -1,23 +1,23 @@ | |||
1 | /* Copyright (C) 2002, 2004-2005, 2007, 2009-2020 Free Software Foundation, | 1 | /* Copyright (C) 2002, 2004-2005, 2007, 2009-2024 Free Software Foundation, |
2 | Inc. | 2 | Inc. |
3 | This file is part of the GNU C Library. | 3 | This file is part of the GNU C Library. |
4 | 4 | ||
5 | This program is free software; you can redistribute it and/or modify | 5 | This file is free software: you can redistribute it and/or modify |
6 | it under the terms of the GNU General Public License as published by | 6 | it under the terms of the GNU Lesser General Public License as |
7 | the Free Software Foundation; either version 2, or (at your option) | 7 | published by the Free Software Foundation; either version 2.1 of the |
8 | any later version. | 8 | License, or (at your option) any later version. |
9 | 9 | ||
10 | This program is distributed in the hope that it will be useful, | 10 | This file is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | GNU General Public License for more details. | 13 | GNU Lesser General Public License for more details. |
14 | 14 | ||
15 | You should have received a copy of the GNU General Public License along | 15 | You should have received a copy of the GNU Lesser General Public License |
16 | with this program; if not, see <https://www.gnu.org/licenses/>. */ | 16 | along with this program. If not, see <https://www.gnu.org/licenses/>. */ |
17 | 17 | ||
18 | /* | 18 | /* |
19 | * File from gnulib (https://www.gnu.org/software/gnulib/), processed with | 19 | * File from gnulib (https://www.gnu.org/software/gnulib/), processed with |
20 | * coan source -U_LIBC -U_NL_CURRENT -UHAVE_TM_GMTOFF strptime.c | 20 | * coan source -U_LIBC -U_NL_CURRENT -UHAVE_STRUCT_TM_TM_GMTOFF strptime.c |
21 | * and lightly edited. | 21 | * and lightly edited. |
22 | * | 22 | * |
23 | * A form of support for tm_gmtoff was later restored. | 23 | * A form of support for tm_gmtoff was later restored. |
@@ -30,7 +30,7 @@ | |||
30 | #include <ctype.h> | 30 | #include <ctype.h> |
31 | #include <limits.h> | 31 | #include <limits.h> |
32 | #include <string.h> | 32 | #include <string.h> |
33 | #include <stdbool.h> | 33 | #include <strings.h> |
34 | 34 | ||
35 | 35 | ||
36 | enum ptime_locale_status { not, loc, raw }; | 36 | enum ptime_locale_status { not, loc, raw }; |
@@ -543,23 +543,23 @@ __strptime_internal (const char *rp, const char *fmt, struct tm *tm, | |||
543 | 543 | ||
544 | if ((have_uweek || have_wweek) && have_wday) | 544 | if ((have_uweek || have_wweek) && have_wday) |
545 | { | 545 | { |
546 | int save_wday = tm->tm_wday; | 546 | int saved_wday = tm->tm_wday; |
547 | int save_mday = tm->tm_mday; | 547 | int saved_mday = tm->tm_mday; |
548 | int save_mon = tm->tm_mon; | 548 | int saved_mon = tm->tm_mon; |
549 | int w_offset = have_uweek ? 0 : 1; | 549 | int w_offset = have_uweek ? 0 : 1; |
550 | 550 | ||
551 | tm->tm_mday = 1; | 551 | tm->tm_mday = 1; |
552 | tm->tm_mon = 0; | 552 | tm->tm_mon = 0; |
553 | day_of_the_week (tm); | 553 | day_of_the_week (tm); |
554 | if (have_mday) | 554 | if (have_mday) |
555 | tm->tm_mday = save_mday; | 555 | tm->tm_mday = saved_mday; |
556 | if (have_mon) | 556 | if (have_mon) |
557 | tm->tm_mon = save_mon; | 557 | tm->tm_mon = saved_mon; |
558 | 558 | ||
559 | if (!have_yday) | 559 | if (!have_yday) |
560 | tm->tm_yday = ((7 - (tm->tm_wday - w_offset)) % 7 | 560 | tm->tm_yday = ((7 - (tm->tm_wday - w_offset)) % 7 |
561 | + (week_no - 1) *7 | 561 | + (week_no - 1) *7 |
562 | + save_wday - w_offset); | 562 | + saved_wday - w_offset); |
563 | 563 | ||
564 | if (!have_mday || !have_mon) | 564 | if (!have_mday || !have_mon) |
565 | { | 565 | { |
@@ -575,7 +575,7 @@ __strptime_internal (const char *rp, const char *fmt, struct tm *tm, | |||
575 | - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1); | 575 | - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1); |
576 | } | 576 | } |
577 | 577 | ||
578 | tm->tm_wday = save_wday; | 578 | tm->tm_wday = saved_wday; |
579 | } | 579 | } |
580 | 580 | ||
581 | return (char *) rp; | 581 | return (char *) rp; |
diff --git a/win32/termios.c b/win32/termios.c index f18ff7c3b..b94f68f59 100644 --- a/win32/termios.c +++ b/win32/termios.c | |||
@@ -2,12 +2,10 @@ | |||
2 | 2 | ||
3 | int tcsetattr(int fd, int mode UNUSED_PARAM, const struct termios *t) | 3 | int tcsetattr(int fd, int mode UNUSED_PARAM, const struct termios *t) |
4 | { | 4 | { |
5 | if (terminal_mode(FALSE) & VT_INPUT) { | 5 | HANDLE h = (HANDLE)_get_osfhandle(fd); |
6 | HANDLE h = (HANDLE)_get_osfhandle(fd); | 6 | if (!SetConsoleMode(h, t->w_mode)) { |
7 | if (!SetConsoleMode(h, t->imode)) { | 7 | errno = err_win_to_posix(); |
8 | errno = err_win_to_posix(); | 8 | return -1; |
9 | return -1; | ||
10 | } | ||
11 | } | 9 | } |
12 | 10 | ||
13 | return 0; | 11 | return 0; |
@@ -15,16 +13,20 @@ int tcsetattr(int fd, int mode UNUSED_PARAM, const struct termios *t) | |||
15 | 13 | ||
16 | int tcgetattr(int fd, struct termios *t) | 14 | int tcgetattr(int fd, struct termios *t) |
17 | { | 15 | { |
18 | if (terminal_mode(FALSE) & VT_INPUT) { | 16 | HANDLE h = (HANDLE)_get_osfhandle(fd); |
19 | HANDLE h = (HANDLE)_get_osfhandle(fd); | 17 | if (!GetConsoleMode(h, &t->w_mode)) { |
20 | if (!GetConsoleMode(h, &t->imode)) { | 18 | errno = err_win_to_posix(); |
21 | errno = err_win_to_posix(); | 19 | return -1; |
22 | return -1; | ||
23 | } | ||
24 | } | 20 | } |
21 | |||
25 | t->c_cc[VINTR] = 3; // ctrl-c | 22 | t->c_cc[VINTR] = 3; // ctrl-c |
26 | t->c_cc[VEOF] = 4; // ctrl-d | 23 | t->c_cc[VEOF] = 4; // ctrl-d |
27 | 24 | ||
25 | if (t->w_mode & ENABLE_ECHO_INPUT) | ||
26 | t->c_lflag |= ECHO; | ||
27 | else | ||
28 | t->c_lflag &= ~ECHO; | ||
29 | |||
28 | return 0; | 30 | return 0; |
29 | } | 31 | } |
30 | 32 | ||
diff --git a/win32/termios.h b/win32/termios.h index 8408aa3e3..60c51119b 100644 --- a/win32/termios.h +++ b/win32/termios.h | |||
@@ -1,23 +1,32 @@ | |||
1 | #ifndef TERMIOS_H | 1 | #ifndef TERMIOS_H |
2 | #define TERMIOS_H | 2 | #define TERMIOS_H |
3 | 3 | ||
4 | #define VINTR 0 | 4 | #define ECHO 0x0004 |
5 | #define VEOF 1 | ||
6 | 5 | ||
7 | #define TCIFLUSH 0 | 6 | #define VINTR 0 |
8 | #define TCSAFLUSH 1 | 7 | #define VEOF 1 |
9 | #define TCSANOW 2 | 8 | |
10 | #define TCSADRAIN 3 | 9 | #define TCIFLUSH 0 |
11 | #define TCSADFLUSH 4 | 10 | #define TCSAFLUSH 1 |
11 | #define TCSANOW 2 | ||
12 | #define TCSADRAIN 3 | ||
13 | #define TCSADFLUSH 4 | ||
14 | |||
15 | #define CSIZE 0 | ||
12 | 16 | ||
13 | typedef unsigned char cc_t; | 17 | typedef unsigned char cc_t; |
18 | typedef unsigned int tcflag_t; | ||
14 | typedef unsigned int speed_t; | 19 | typedef unsigned int speed_t; |
15 | 20 | ||
16 | #define NCCS 2 | 21 | #define NCCS 18 |
17 | struct termios { | 22 | struct termios { |
23 | tcflag_t c_iflag; | ||
24 | tcflag_t c_oflag; | ||
25 | tcflag_t c_cflag; | ||
26 | tcflag_t c_lflag; | ||
27 | char c_line; | ||
18 | cc_t c_cc[NCCS]; | 28 | cc_t c_cc[NCCS]; |
19 | unsigned long imode; | 29 | unsigned long w_mode; |
20 | unsigned long omode; | ||
21 | }; | 30 | }; |
22 | 31 | ||
23 | struct winsize { | 32 | struct winsize { |
diff --git a/win32/winansi.c b/win32/winansi.c index c7529c453..9736f0568 100644 --- a/win32/winansi.c +++ b/win32/winansi.c | |||
@@ -160,7 +160,7 @@ int FAST_FUNC terminal_mode(int reset) | |||
160 | mode |= VT_INPUT; | 160 | mode |= VT_INPUT; |
161 | } | 161 | } |
162 | 162 | ||
163 | if (newmode != oldmode) { | 163 | if (reset && newmode != oldmode) { |
164 | if (!SetConsoleMode(h, newmode)) { | 164 | if (!SetConsoleMode(h, newmode)) { |
165 | if (mode >= 4) | 165 | if (mode >= 4) |
166 | mode &= ~VT_INPUT; | 166 | mode &= ~VT_INPUT; |