diff options
108 files changed, 1571 insertions, 982 deletions
diff --git a/archival/bbunzip.c b/archival/bbunzip.c index 2beb92763..467996071 100644 --- a/archival/bbunzip.c +++ b/archival/bbunzip.c | |||
@@ -286,7 +286,7 @@ int uncompress_main(int argc UNUSED_PARAM, char **argv) | |||
286 | //usage: "\n -c Write to stdout" | 286 | //usage: "\n -c Write to stdout" |
287 | //usage: "\n -f Force" | 287 | //usage: "\n -f Force" |
288 | //usage: "\n -k Keep input files" | 288 | //usage: "\n -k Keep input files" |
289 | //usage: "\n -t Test file integrity" | 289 | //usage: "\n -t Test integrity" |
290 | //usage: | 290 | //usage: |
291 | //usage:#define gunzip_example_usage | 291 | //usage:#define gunzip_example_usage |
292 | //usage: "$ ls -la /tmp/BusyBox*\n" | 292 | //usage: "$ ls -la /tmp/BusyBox*\n" |
@@ -409,6 +409,8 @@ int gunzip_main(int argc UNUSED_PARAM, char **argv) | |||
409 | //usage: "\n -c Write to stdout" | 409 | //usage: "\n -c Write to stdout" |
410 | //usage: "\n -f Force" | 410 | //usage: "\n -f Force" |
411 | //usage: "\n -k Keep input files" | 411 | //usage: "\n -k Keep input files" |
412 | //usage: "\n -t Test integrity" | ||
413 | //usage: | ||
412 | //usage:#define bzcat_trivial_usage | 414 | //usage:#define bzcat_trivial_usage |
413 | //usage: "[FILE]..." | 415 | //usage: "[FILE]..." |
414 | //usage:#define bzcat_full_usage "\n\n" | 416 | //usage:#define bzcat_full_usage "\n\n" |
@@ -467,6 +469,7 @@ int bunzip2_main(int argc UNUSED_PARAM, char **argv) | |||
467 | //usage: "\n -c Write to stdout" | 469 | //usage: "\n -c Write to stdout" |
468 | //usage: "\n -f Force" | 470 | //usage: "\n -f Force" |
469 | //usage: "\n -k Keep input files" | 471 | //usage: "\n -k Keep input files" |
472 | //usage: "\n -t Test integrity" | ||
470 | //usage: | 473 | //usage: |
471 | //usage:#define lzma_trivial_usage | 474 | //usage:#define lzma_trivial_usage |
472 | //usage: "-d [-cfk] [FILE]..." | 475 | //usage: "-d [-cfk] [FILE]..." |
@@ -476,6 +479,7 @@ int bunzip2_main(int argc UNUSED_PARAM, char **argv) | |||
476 | //usage: "\n -c Write to stdout" | 479 | //usage: "\n -c Write to stdout" |
477 | //usage: "\n -f Force" | 480 | //usage: "\n -f Force" |
478 | //usage: "\n -k Keep input files" | 481 | //usage: "\n -k Keep input files" |
482 | //usage: "\n -t Test integrity" | ||
479 | //usage: | 483 | //usage: |
480 | //usage:#define lzcat_trivial_usage | 484 | //usage:#define lzcat_trivial_usage |
481 | //usage: "[FILE]..." | 485 | //usage: "[FILE]..." |
@@ -538,7 +542,7 @@ int unlzma_main(int argc UNUSED_PARAM, char **argv) | |||
538 | //usage: "\n -c Write to stdout" | 542 | //usage: "\n -c Write to stdout" |
539 | //usage: "\n -f Force" | 543 | //usage: "\n -f Force" |
540 | //usage: "\n -k Keep input files" | 544 | //usage: "\n -k Keep input files" |
541 | //usage: "\n -t Test file integrity" | 545 | //usage: "\n -t Test integrity" |
542 | //usage: | 546 | //usage: |
543 | //usage:#define xz_trivial_usage | 547 | //usage:#define xz_trivial_usage |
544 | //usage: "-d [-cfk] [FILE]..." | 548 | //usage: "-d [-cfk] [FILE]..." |
@@ -548,7 +552,7 @@ int unlzma_main(int argc UNUSED_PARAM, char **argv) | |||
548 | //usage: "\n -c Write to stdout" | 552 | //usage: "\n -c Write to stdout" |
549 | //usage: "\n -f Force" | 553 | //usage: "\n -f Force" |
550 | //usage: "\n -k Keep input files" | 554 | //usage: "\n -k Keep input files" |
551 | //usage: "\n -t Test file integrity" | 555 | //usage: "\n -t Test integrity" |
552 | //usage: | 556 | //usage: |
553 | //usage:#define xzcat_trivial_usage | 557 | //usage:#define xzcat_trivial_usage |
554 | //usage: "[FILE]..." | 558 | //usage: "[FILE]..." |
diff --git a/archival/bzip2.c b/archival/bzip2.c index ac5db0880..bce13cf93 100644 --- a/archival/bzip2.c +++ b/archival/bzip2.c | |||
@@ -56,11 +56,13 @@ | |||
56 | //usage: "\n -1..9 Compression level" | 56 | //usage: "\n -1..9 Compression level" |
57 | //usage: IF_FEATURE_BZIP2_DECOMPRESS( | 57 | //usage: IF_FEATURE_BZIP2_DECOMPRESS( |
58 | //usage: "\n -d Decompress" | 58 | //usage: "\n -d Decompress" |
59 | //usage: "\n -t Test file integrity" | ||
60 | //usage: ) | 59 | //usage: ) |
61 | //usage: "\n -c Write to stdout" | 60 | //usage: "\n -c Write to stdout" |
62 | //usage: "\n -f Force" | 61 | //usage: "\n -f Force" |
63 | //usage: "\n -k Keep input files" | 62 | //usage: "\n -k Keep input files" |
63 | //usage: IF_FEATURE_BZIP2_DECOMPRESS( | ||
64 | //usage: "\n -t Test integrity" | ||
65 | //usage: ) | ||
64 | 66 | ||
65 | #include "libbb.h" | 67 | #include "libbb.h" |
66 | #include "bb_archive.h" | 68 | #include "bb_archive.h" |
diff --git a/archival/gzip.c b/archival/gzip.c index d9c730f13..91bd4d09d 100644 --- a/archival/gzip.c +++ b/archival/gzip.c | |||
@@ -77,11 +77,13 @@ aa: 85.1% -- replaced with aa.gz | |||
77 | //usage: ) | 77 | //usage: ) |
78 | //usage: IF_FEATURE_GZIP_DECOMPRESS( | 78 | //usage: IF_FEATURE_GZIP_DECOMPRESS( |
79 | //usage: "\n -d Decompress" | 79 | //usage: "\n -d Decompress" |
80 | //usage: "\n -t Test file integrity" | ||
81 | //usage: ) | 80 | //usage: ) |
82 | //usage: "\n -c Write to stdout" | 81 | //usage: "\n -c Write to stdout" |
83 | //usage: "\n -f Force" | 82 | //usage: "\n -f Force" |
84 | //usage: "\n -k Keep input files" | 83 | //usage: "\n -k Keep input files" |
84 | //usage: IF_FEATURE_GZIP_DECOMPRESS( | ||
85 | //usage: "\n -t Test integrity" | ||
86 | //usage: ) | ||
85 | //usage: | 87 | //usage: |
86 | //usage:#define gzip_example_usage | 88 | //usage:#define gzip_example_usage |
87 | //usage: "$ ls -la /tmp/busybox*\n" | 89 | //usage: "$ ls -la /tmp/busybox*\n" |
diff --git a/archival/libarchive/decompress_unlzma.c b/archival/libarchive/decompress_unlzma.c index 0744f231a..fb5aac8fe 100644 --- a/archival/libarchive/decompress_unlzma.c +++ b/archival/libarchive/decompress_unlzma.c | |||
@@ -290,8 +290,11 @@ unpack_lzma_stream(transformer_state_t *xstate) | |||
290 | uint32_t pos; | 290 | uint32_t pos; |
291 | 291 | ||
292 | pos = buffer_pos - rep0; | 292 | pos = buffer_pos - rep0; |
293 | if ((int32_t)pos < 0) | 293 | if ((int32_t)pos < 0) { |
294 | pos += header.dict_size; | 294 | pos += header.dict_size; |
295 | if ((int32_t)pos < 0) | ||
296 | goto bad; | ||
297 | } | ||
295 | match_byte = buffer[pos]; | 298 | match_byte = buffer[pos]; |
296 | do { | 299 | do { |
297 | int bit; | 300 | int bit; |
diff --git a/archival/libarchive/get_header_cpio.c b/archival/libarchive/get_header_cpio.c index 4ad174732..9ad0557c2 100644 --- a/archival/libarchive/get_header_cpio.c +++ b/archival/libarchive/get_header_cpio.c | |||
@@ -20,7 +20,7 @@ typedef struct hardlinks_t { | |||
20 | char FAST_FUNC get_header_cpio(archive_handle_t *archive_handle) | 20 | char FAST_FUNC get_header_cpio(archive_handle_t *archive_handle) |
21 | { | 21 | { |
22 | file_header_t *file_header = archive_handle->file_header; | 22 | file_header_t *file_header = archive_handle->file_header; |
23 | char cpio_header[110]; | 23 | char cpio_header[111]; |
24 | int namesize; | 24 | int namesize; |
25 | int major, minor, nlink, mode, inode; | 25 | int major, minor, nlink, mode, inode; |
26 | unsigned size, uid, gid, mtime; | 26 | unsigned size, uid, gid, mtime; |
@@ -43,6 +43,7 @@ char FAST_FUNC get_header_cpio(archive_handle_t *archive_handle) | |||
43 | bb_simple_error_msg_and_die("unsupported cpio format, use newc or crc"); | 43 | bb_simple_error_msg_and_die("unsupported cpio format, use newc or crc"); |
44 | } | 44 | } |
45 | 45 | ||
46 | cpio_header[110] = '\0'; /* sscanf may call strlen which may break without this */ | ||
46 | if (sscanf(cpio_header + 6, | 47 | if (sscanf(cpio_header + 6, |
47 | "%8x" "%8x" "%8x" "%8x" | 48 | "%8x" "%8x" "%8x" "%8x" |
48 | "%8x" "%8x" "%8x" /*maj,min:*/ "%*16c" | 49 | "%8x" "%8x" "%8x" /*maj,min:*/ "%*16c" |
diff --git a/archival/lzop.c b/archival/lzop.c index bdd21598c..74df8ff03 100644 --- a/archival/lzop.c +++ b/archival/lzop.c | |||
@@ -86,6 +86,7 @@ | |||
86 | //usage: "\n -f Force" | 86 | //usage: "\n -f Force" |
87 | //usage: "\n -U Delete input files" | 87 | //usage: "\n -U Delete input files" |
88 | ///////: "\n -k Keep input files" (default, so why bother documenting?) | 88 | ///////: "\n -k Keep input files" (default, so why bother documenting?) |
89 | //usage: "\n -t Test integrity" | ||
89 | //usage: "\n -v Verbose" | 90 | //usage: "\n -v Verbose" |
90 | //usage: "\n -F Don't verify checksum" | 91 | //usage: "\n -F Don't verify checksum" |
91 | 92 | ||
diff --git a/archival/tar.c b/archival/tar.c index 3b8777414..8cd371173 100644 --- a/archival/tar.c +++ b/archival/tar.c | |||
@@ -796,7 +796,7 @@ static llist_t *append_file_list_to_list(llist_t *list) | |||
796 | //usage: IF_FEATURE_TAR_NOPRESERVE_TIME("m") | 796 | //usage: IF_FEATURE_TAR_NOPRESERVE_TIME("m") |
797 | //usage: "vokO] " | 797 | //usage: "vokO] " |
798 | //usage: "[-f TARFILE] [-C DIR] " | 798 | //usage: "[-f TARFILE] [-C DIR] " |
799 | //usage: IF_FEATURE_TAR_FROM("[-T FILE] [-X FILE] "IF_FEATURE_TAR_LONG_OPTIONS("[OPTION]... ")) | 799 | //usage: IF_FEATURE_TAR_FROM("[-T FILE] [-X FILE] "IF_FEATURE_TAR_LONG_OPTIONS("[LONGOPT]... ")) |
800 | //usage: "[FILE]..." | 800 | //usage: "[FILE]..." |
801 | //usage:#define tar_full_usage "\n\n" | 801 | //usage:#define tar_full_usage "\n\n" |
802 | //usage: IF_FEATURE_TAR_CREATE("Create, extract, ") | 802 | //usage: IF_FEATURE_TAR_CREATE("Create, extract, ") |
diff --git a/archival/unzip.c b/archival/unzip.c index e02cf33e3..edfd73652 100644 --- a/archival/unzip.c +++ b/archival/unzip.c | |||
@@ -56,14 +56,14 @@ | |||
56 | //kbuild:lib-$(CONFIG_UNZIP) += unzip.o | 56 | //kbuild:lib-$(CONFIG_UNZIP) += unzip.o |
57 | 57 | ||
58 | //usage:#define unzip_trivial_usage | 58 | //usage:#define unzip_trivial_usage |
59 | //usage: "[-lnojpq] FILE[.zip] [FILE]... [-x FILE...] [-d DIR]" | 59 | //usage: "[-lnojpq] FILE[.zip] [FILE]... [-x FILE]... [-d DIR]" |
60 | //usage:#define unzip_full_usage "\n\n" | 60 | //usage:#define unzip_full_usage "\n\n" |
61 | //usage: "Extract FILEs from ZIP archive\n" | 61 | //usage: "Extract FILEs from ZIP archive\n" |
62 | //usage: "\n -l List contents (with -q for short form)" | 62 | //usage: "\n -l List contents (with -q for short form)" |
63 | //usage: "\n -n Never overwrite files (default: ask)" | 63 | //usage: "\n -n Never overwrite files (default: ask)" |
64 | //usage: "\n -o Overwrite" | 64 | //usage: "\n -o Overwrite" |
65 | //usage: "\n -j Do not restore paths" | 65 | //usage: "\n -j Do not restore paths" |
66 | //usage: "\n -p Print to stdout" | 66 | //usage: "\n -p Write to stdout" |
67 | //usage: "\n -t Test" | 67 | //usage: "\n -t Test" |
68 | //usage: "\n -q Quiet" | 68 | //usage: "\n -q Quiet" |
69 | //usage: "\n -x FILE Exclude FILEs" | 69 | //usage: "\n -x FILE Exclude FILEs" |
diff --git a/console-tools/loadfont.c b/console-tools/loadfont.c index 7533b0aad..81a0e6aa8 100644 --- a/console-tools/loadfont.c +++ b/console-tools/loadfont.c | |||
@@ -399,7 +399,7 @@ setfont [-O font+umap.orig] [-o font.orig] [-om cmap.orig] | |||
399 | -V Version | 399 | -V Version |
400 | */ | 400 | */ |
401 | //usage:#define setfont_trivial_usage | 401 | //usage:#define setfont_trivial_usage |
402 | //usage: "FONT [-m MAPFILE] [-C TTY]" | 402 | //usage: "[-m MAPFILE] [-C TTY] FILE" |
403 | //usage:#define setfont_full_usage "\n\n" | 403 | //usage:#define setfont_full_usage "\n\n" |
404 | //usage: "Load a console font\n" | 404 | //usage: "Load a console font\n" |
405 | //usage: "\n -m MAPFILE Load console screen map" | 405 | //usage: "\n -m MAPFILE Load console screen map" |
diff --git a/coreutils/chgrp.c b/coreutils/chgrp.c index 0c2060981..e6ac316e5 100644 --- a/coreutils/chgrp.c +++ b/coreutils/chgrp.c | |||
@@ -23,13 +23,17 @@ | |||
23 | //usage:#define chgrp_trivial_usage | 23 | //usage:#define chgrp_trivial_usage |
24 | //usage: "[-Rh"IF_DESKTOP("LHPcvf")"]... GROUP FILE..." | 24 | //usage: "[-Rh"IF_DESKTOP("LHPcvf")"]... GROUP FILE..." |
25 | //usage:#define chgrp_full_usage "\n\n" | 25 | //usage:#define chgrp_full_usage "\n\n" |
26 | //usage: "Change the group membership of FILEs to GROUP\n" | 26 | //usage: "Change the group membership of FILEs to GROUP" |
27 | //usage: "\n -R Recurse" | 27 | //usage: "\n" |
28 | //usage: "\n -h Affect symlinks instead of symlink targets" | 28 | //usage: "\n -h Affect symlinks instead of symlink targets" |
29 | //usage: IF_DESKTOP( | 29 | //usage: IF_DESKTOP( |
30 | //usage: "\n -L Traverse all symlinks to directories" | 30 | //usage: "\n -L Traverse all symlinks to directories" |
31 | //usage: "\n -H Traverse symlinks on command line only" | 31 | //usage: "\n -H Traverse symlinks on command line only" |
32 | //usage: "\n -P Don't traverse symlinks (default)" | 32 | //usage: "\n -P Don't traverse symlinks (default)" |
33 | //usage: ) | ||
34 | //next 4 options are the same for chmod/chown/chgrp: | ||
35 | //usage: "\n -R Recurse" | ||
36 | //usage: IF_DESKTOP( | ||
33 | //usage: "\n -c List changed files" | 37 | //usage: "\n -c List changed files" |
34 | //usage: "\n -v Verbose" | 38 | //usage: "\n -v Verbose" |
35 | //usage: "\n -f Hide errors" | 39 | //usage: "\n -f Hide errors" |
diff --git a/coreutils/chmod.c b/coreutils/chmod.c index d2988c490..e260adab2 100644 --- a/coreutils/chmod.c +++ b/coreutils/chmod.c | |||
@@ -26,12 +26,13 @@ | |||
26 | //usage:#define chmod_trivial_usage | 26 | //usage:#define chmod_trivial_usage |
27 | //usage: "[-R"IF_DESKTOP("cvf")"] MODE[,MODE]... FILE..." | 27 | //usage: "[-R"IF_DESKTOP("cvf")"] MODE[,MODE]... FILE..." |
28 | //usage:#define chmod_full_usage "\n\n" | 28 | //usage:#define chmod_full_usage "\n\n" |
29 | //usage: "Each MODE is one or more of the letters ugoa, one of the\n" | 29 | //usage: "MODE is octal number (bit pattern sstrwxrwxrwx) or [ugoa]{+|-|=}[rwxXst]" |
30 | //usage: "symbols +-= and one or more of the letters rwxst\n" | 30 | //usage: "\n" |
31 | //next 4 options are the same for chmod/chown/chgrp: | ||
31 | //usage: "\n -R Recurse" | 32 | //usage: "\n -R Recurse" |
32 | //usage: IF_DESKTOP( | 33 | //usage: IF_DESKTOP( |
33 | //usage: "\n -c List changed files" | 34 | //usage: "\n -c List changed files" |
34 | //usage: "\n -v List all files" | 35 | //usage: "\n -v Verbose" |
35 | //usage: "\n -f Hide errors" | 36 | //usage: "\n -f Hide errors" |
36 | //usage: ) | 37 | //usage: ) |
37 | //usage: | 38 | //usage: |
diff --git a/coreutils/chown.c b/coreutils/chown.c index 170507147..528a2a05a 100644 --- a/coreutils/chown.c +++ b/coreutils/chown.c | |||
@@ -28,15 +28,19 @@ | |||
28 | //usage:#define chown_trivial_usage | 28 | //usage:#define chown_trivial_usage |
29 | //usage: "[-Rh"IF_DESKTOP("LHPcvf")"]... USER[:[GRP]] FILE..." | 29 | //usage: "[-Rh"IF_DESKTOP("LHPcvf")"]... USER[:[GRP]] FILE..." |
30 | //usage:#define chown_full_usage "\n\n" | 30 | //usage:#define chown_full_usage "\n\n" |
31 | //usage: "Change the owner and/or group of FILEs to USER and/or GRP\n" | 31 | //usage: "Change the owner and/or group of FILEs to USER and/or GRP" |
32 | //usage: "\n -R Recurse" | 32 | //usage: "\n" |
33 | //usage: "\n -h Affect symlinks instead of symlink targets" | 33 | //usage: "\n -h Affect symlinks instead of symlink targets" |
34 | //usage: IF_DESKTOP( | 34 | //usage: IF_DESKTOP( |
35 | //usage: "\n -L Traverse all symlinks to directories" | 35 | //usage: "\n -L Traverse all symlinks to directories" |
36 | //usage: "\n -H Traverse symlinks on command line only" | 36 | //usage: "\n -H Traverse symlinks on command line only" |
37 | //usage: "\n -P Don't traverse symlinks (default)" | 37 | //usage: "\n -P Don't traverse symlinks (default)" |
38 | //usage: ) | ||
39 | //next 4 options are the same for chmod/chown/chgrp: | ||
40 | //usage: "\n -R Recurse" | ||
41 | //usage: IF_DESKTOP( | ||
38 | //usage: "\n -c List changed files" | 42 | //usage: "\n -c List changed files" |
39 | //usage: "\n -v List all files" | 43 | //usage: "\n -v Verbose" |
40 | //usage: "\n -f Hide errors" | 44 | //usage: "\n -f Hide errors" |
41 | //usage: ) | 45 | //usage: ) |
42 | //usage: | 46 | //usage: |
diff --git a/coreutils/cksum.c b/coreutils/cksum.c index 633322bc7..83b7e3238 100644 --- a/coreutils/cksum.c +++ b/coreutils/cksum.c | |||
@@ -9,32 +9,40 @@ | |||
9 | //config:config CKSUM | 9 | //config:config CKSUM |
10 | //config: bool "cksum (4.1 kb)" | 10 | //config: bool "cksum (4.1 kb)" |
11 | //config: default y | 11 | //config: default y |
12 | //config: help | 12 | //config: |
13 | //config: cksum is used to calculate the CRC32 checksum of a file. | 13 | //config:config CRC32 |
14 | //config: bool "crc32 (4.1 kb)" | ||
15 | //config: default y | ||
14 | 16 | ||
17 | // APPLET_NOEXEC:name main location suid_type help | ||
15 | //applet:IF_CKSUM(APPLET_NOEXEC(cksum, cksum, BB_DIR_USR_BIN, BB_SUID_DROP, cksum)) | 18 | //applet:IF_CKSUM(APPLET_NOEXEC(cksum, cksum, BB_DIR_USR_BIN, BB_SUID_DROP, cksum)) |
19 | //applet:IF_CRC32(APPLET_NOEXEC(crc32, cksum, BB_DIR_USR_BIN, BB_SUID_DROP, cksum)) | ||
16 | /* bb_common_bufsiz1 usage here is safe wrt NOEXEC: not expecting it to be zeroed. */ | 20 | /* bb_common_bufsiz1 usage here is safe wrt NOEXEC: not expecting it to be zeroed. */ |
17 | 21 | ||
18 | //kbuild:lib-$(CONFIG_CKSUM) += cksum.o | 22 | //kbuild:lib-$(CONFIG_CKSUM) += cksum.o |
23 | //kbuild:lib-$(CONFIG_CRC32) += cksum.o | ||
19 | 24 | ||
20 | //usage:#define cksum_trivial_usage | 25 | //usage:#define cksum_trivial_usage |
21 | //usage: "FILE..." | 26 | //usage: "FILE..." |
22 | //usage:#define cksum_full_usage "\n\n" | 27 | //usage:#define cksum_full_usage "\n\n" |
23 | //usage: "Calculate the CRC32 checksums of FILEs" | 28 | //usage: "Calculate CRC32 checksum of FILEs" |
24 | 29 | ||
25 | #include "libbb.h" | 30 | #include "libbb.h" |
26 | #include "common_bufsiz.h" | 31 | #include "common_bufsiz.h" |
27 | 32 | ||
28 | /* This is a NOEXEC applet. Be very careful! */ | 33 | /* This is a NOEXEC applet. Be very careful! */ |
29 | 34 | ||
35 | #define IS_CKSUM (ENABLE_CKSUM && (!ENABLE_CRC32 || applet_name[1] == 'k')) | ||
36 | #define IS_CRC32 (ENABLE_CRC32 && (!ENABLE_CKSUM || applet_name[1] == 'r')) | ||
37 | |||
30 | int cksum_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 38 | int cksum_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
31 | int cksum_main(int argc UNUSED_PARAM, char **argv) | 39 | int cksum_main(int argc UNUSED_PARAM, char **argv) |
32 | { | 40 | { |
33 | uint32_t *crc32_table = crc32_filltable(NULL, 1); | 41 | uint32_t *crc32_table = crc32_filltable(NULL, IS_CKSUM); |
34 | int exit_code = EXIT_SUCCESS; | 42 | int exit_code = EXIT_SUCCESS; |
35 | 43 | ||
36 | #if ENABLE_DESKTOP | 44 | #if ENABLE_DESKTOP |
37 | getopt32(argv, ""); /* coreutils 6.9 compat */ | 45 | getopt32(argv, ""); /* cksum coreutils 6.9 compat */ |
38 | argv += optind; | 46 | argv += optind; |
39 | #else | 47 | #else |
40 | argv++; | 48 | argv++; |
@@ -43,41 +51,55 @@ int cksum_main(int argc UNUSED_PARAM, char **argv) | |||
43 | setup_common_bufsiz(); | 51 | setup_common_bufsiz(); |
44 | do { | 52 | do { |
45 | uint32_t crc; | 53 | uint32_t crc; |
46 | off_t filesize; | 54 | IF_CKSUM(off_t filesize;) |
47 | int fd = open_or_warn_stdin(*argv ? *argv : bb_msg_standard_input); | 55 | const char *fname = *argv ? *argv : bb_msg_standard_input; |
56 | int fd = open_or_warn_stdin(fname); | ||
48 | 57 | ||
49 | if (fd < 0) { | 58 | if (fd < 0) { |
50 | exit_code = EXIT_FAILURE; | 59 | exit_code = EXIT_FAILURE; |
51 | continue; | 60 | continue; |
52 | } | 61 | } |
53 | 62 | ||
54 | crc = 0; | 63 | crc = IS_CKSUM ? 0 : 0xffffffff; |
55 | filesize = 0; | 64 | IF_CKSUM(filesize = 0;) |
56 | #define read_buf bb_common_bufsiz1 | 65 | #define read_buf bb_common_bufsiz1 |
57 | for (;;) { | 66 | for (;;) { |
58 | uoff_t t; | ||
59 | int bytes_read = safe_read(fd, read_buf, COMMON_BUFSIZE); | 67 | int bytes_read = safe_read(fd, read_buf, COMMON_BUFSIZE); |
68 | if (bytes_read < 0) | ||
69 | bb_simple_perror_msg_and_die(fname); | ||
60 | if (bytes_read > 0) { | 70 | if (bytes_read > 0) { |
61 | filesize += bytes_read; | 71 | IF_CKSUM(filesize += bytes_read;) |
62 | } else { | 72 | } else { |
63 | /* Checksum filesize bytes, LSB first, and exit */ | 73 | IF_CKSUM(uoff_t t;) |
74 | |||
64 | close(fd); | 75 | close(fd); |
76 | if (IS_CRC32) | ||
77 | break; | ||
78 | #if ENABLE_CKSUM | ||
65 | fd = -1; /* break flag */ | 79 | fd = -1; /* break flag */ |
80 | /* Checksum filesize bytes, LSB first */ | ||
66 | t = filesize; | 81 | t = filesize; |
67 | bytes_read = 0; | 82 | /*bytes_read = 0; - already is */ |
68 | while (t != 0) { | 83 | while (t != 0) { |
69 | read_buf[bytes_read++] = (uint8_t)t; | 84 | read_buf[bytes_read++] = (uint8_t)t; |
70 | t >>= 8; | 85 | t >>= 8; |
71 | } | 86 | } |
87 | #endif | ||
72 | } | 88 | } |
73 | crc = crc32_block_endian1(crc, read_buf, bytes_read, crc32_table); | 89 | crc = (IS_CKSUM ? crc32_block_endian1 : crc32_block_endian0)(crc, read_buf, bytes_read, crc32_table); |
74 | if (fd < 0) | 90 | if (ENABLE_CKSUM && fd < 0) |
75 | break; | 91 | break; |
76 | } | 92 | } |
77 | 93 | ||
78 | crc = ~crc; | 94 | crc = ~crc; |
79 | printf((*argv ? "%u %"OFF_FMT"u %s\n" : "%u %"OFF_FMT"u\n"), | 95 | #if ENABLE_CKSUM |
96 | if (IS_CKSUM) | ||
97 | printf((*argv ? "%u %"OFF_FMT"u %s\n" : "%u %"OFF_FMT"u\n"), | ||
80 | (unsigned)crc, filesize, *argv); | 98 | (unsigned)crc, filesize, *argv); |
99 | else | ||
100 | #endif | ||
101 | printf((*argv ? "%08x %s\n" : "%08x\n"), | ||
102 | (unsigned)crc, *argv); | ||
81 | } while (*argv && *++argv); | 103 | } while (*argv && *++argv); |
82 | 104 | ||
83 | fflush_stdout_and_exit(exit_code); | 105 | fflush_stdout_and_exit(exit_code); |
diff --git a/coreutils/cp.c b/coreutils/cp.c index f92ba6886..50ca1ccea 100644 --- a/coreutils/cp.c +++ b/coreutils/cp.c | |||
@@ -37,8 +37,55 @@ | |||
37 | 37 | ||
38 | /* http://www.opengroup.org/onlinepubs/007904975/utilities/cp.html */ | 38 | /* http://www.opengroup.org/onlinepubs/007904975/utilities/cp.html */ |
39 | 39 | ||
40 | // Options of cp from GNU coreutils 6.10: | ||
41 | // -a, --archive | ||
42 | // -f, --force | ||
43 | // -i, --interactive | ||
44 | // -l, --link | ||
45 | // -L, --dereference | ||
46 | // -P, --no-dereference | ||
47 | // -R, -r, --recursive | ||
48 | // -s, --symbolic-link | ||
49 | // -v, --verbose | ||
50 | // -H follow command-line symbolic links in SOURCE | ||
51 | // -d same as --no-dereference --preserve=links | ||
52 | // -p same as --preserve=mode,ownership,timestamps | ||
53 | // -c same as --preserve=context | ||
54 | // -u, --update | ||
55 | // copy only when the SOURCE file is newer than the destination | ||
56 | // file or when the destination file is missing | ||
57 | // --remove-destination | ||
58 | // remove each existing destination file before attempting to open | ||
59 | // --parents | ||
60 | // use full source file name under DIRECTORY | ||
61 | // -T, --no-target-directory | ||
62 | // treat DEST as a normal file | ||
63 | // NOT SUPPORTED IN BBOX: | ||
64 | // --backup[=CONTROL] | ||
65 | // make a backup of each existing destination file | ||
66 | // -b like --backup but does not accept an argument | ||
67 | // --copy-contents | ||
68 | // copy contents of special files when recursive | ||
69 | // --preserve[=ATTR_LIST] | ||
70 | // preserve attributes (default: mode,ownership,timestamps), | ||
71 | // if possible additional attributes: security context,links,all | ||
72 | // --no-preserve=ATTR_LIST | ||
73 | // --sparse=WHEN | ||
74 | // control creation of sparse files | ||
75 | // --strip-trailing-slashes | ||
76 | // remove any trailing slashes from each SOURCE argument | ||
77 | // -S, --suffix=SUFFIX | ||
78 | // override the usual backup suffix | ||
79 | // -t, --target-directory=DIRECTORY | ||
80 | // copy all SOURCE arguments into DIRECTORY | ||
81 | // -x, --one-file-system | ||
82 | // stay on this file system | ||
83 | // -Z, --context=CONTEXT | ||
84 | // (SELinux) set SELinux security context of copy to CONTEXT | ||
85 | |||
40 | //usage:#define cp_trivial_usage | 86 | //usage:#define cp_trivial_usage |
41 | //usage: "[-arPLHpfilsTu] SOURCE... DEST" | 87 | //usage: "[-arPLHpfinlsTu] SOURCE DEST\n" |
88 | //usage: "or: cp [-arPLHpfinlsu] SOURCE... { -t DIRECTORY | DIRECTORY }" | ||
42 | //usage:#define cp_full_usage "\n\n" | 89 | //usage:#define cp_full_usage "\n\n" |
43 | //usage: "Copy SOURCEs to DEST\n" | 90 | //usage: "Copy SOURCEs to DEST\n" |
44 | //usage: "\n -a Same as -dpR" | 91 | //usage: "\n -a Same as -dpR" |
@@ -52,8 +99,10 @@ | |||
52 | //usage: "\n -p Preserve file attributes if possible" | 99 | //usage: "\n -p Preserve file attributes if possible" |
53 | //usage: "\n -f Overwrite" | 100 | //usage: "\n -f Overwrite" |
54 | //usage: "\n -i Prompt before overwrite" | 101 | //usage: "\n -i Prompt before overwrite" |
102 | //usage: "\n -n Don't overwrite" | ||
55 | //usage: "\n -l,-s Create (sym)links" | 103 | //usage: "\n -l,-s Create (sym)links" |
56 | //usage: "\n -T Treat DEST as a normal file" | 104 | //usage: "\n -T Refuse to copy if DEST is a directory" |
105 | //usage: "\n -t DIR Copy all SOURCEs into DIR" | ||
57 | //usage: "\n -u Copy only newer files" | 106 | //usage: "\n -u Copy only newer files" |
58 | 107 | ||
59 | #include "libbb.h" | 108 | #include "libbb.h" |
@@ -73,14 +122,12 @@ int cp_main(int argc, char **argv) | |||
73 | int flags; | 122 | int flags; |
74 | int status; | 123 | int status; |
75 | enum { | 124 | enum { |
76 | FILEUTILS_CP_OPTNUM = sizeof(FILEUTILS_CP_OPTSTR)-1, | ||
77 | #if ENABLE_FEATURE_CP_LONG_OPTIONS | 125 | #if ENABLE_FEATURE_CP_LONG_OPTIONS |
78 | /*OPT_rmdest = FILEUTILS_RMDEST = 1 << FILEUTILS_CP_OPTNUM */ | 126 | /*OPT_rmdest = FILEUTILS_RMDEST = 1 << FILEUTILS_CP_OPTBITS */ |
79 | OPT_parents = 1 << (FILEUTILS_CP_OPTNUM+1), | 127 | OPT_parents = 1 << (FILEUTILS_CP_OPTBITS+1), |
80 | OPT_reflink = 1 << (FILEUTILS_CP_OPTNUM+2), | 128 | OPT_reflink = 1 << (FILEUTILS_CP_OPTBITS+2), |
81 | #endif | 129 | #endif |
82 | }; | 130 | }; |
83 | |||
84 | #if ENABLE_FEATURE_CP_LONG_OPTIONS | 131 | #if ENABLE_FEATURE_CP_LONG_OPTIONS |
85 | # if ENABLE_FEATURE_CP_REFLINK | 132 | # if ENABLE_FEATURE_CP_REFLINK |
86 | char *reflink = NULL; | 133 | char *reflink = NULL; |
@@ -88,28 +135,34 @@ int cp_main(int argc, char **argv) | |||
88 | flags = getopt32long(argv, "^" | 135 | flags = getopt32long(argv, "^" |
89 | FILEUTILS_CP_OPTSTR | 136 | FILEUTILS_CP_OPTSTR |
90 | "\0" | 137 | "\0" |
91 | // Need at least two arguments | 138 | // Need at least one argument. (Usually two+, but -t DIR can have only one) |
92 | // Soft- and hardlinking doesn't mix | 139 | // Soft- and hardlinking doesn't mix |
93 | // -P and -d are the same (-P is POSIX, -d is GNU) | 140 | // -P and -d are the same (-P is POSIX, -d is GNU) |
94 | // -r and -R are the same | 141 | // -r and -R are the same |
95 | // -R (and therefore -r) turns on -d (coreutils does this) | 142 | // -R (and therefore -r) turns on -d (coreutils does this) |
96 | // -a = -pdR | 143 | // -a = -pdR |
97 | "-2:l--s:s--l:Pd:rRd:Rd:apdR", | 144 | // -i overrides -n and vice versa (last wins) |
145 | "-1:l--s:s--l:Pd:rRd:Rd:apdR:i-n:n-i", | ||
98 | "archive\0" No_argument "a" | 146 | "archive\0" No_argument "a" |
99 | "force\0" No_argument "f" | 147 | "force\0" No_argument "f" |
100 | "interactive\0" No_argument "i" | 148 | "interactive\0" No_argument "i" |
149 | "no-clobber\0" No_argument "n" | ||
101 | "link\0" No_argument "l" | 150 | "link\0" No_argument "l" |
102 | "dereference\0" No_argument "L" | 151 | "dereference\0" No_argument "L" |
103 | "no-dereference\0" No_argument "P" | 152 | "no-dereference\0" No_argument "P" |
104 | "recursive\0" No_argument "R" | 153 | "recursive\0" No_argument "R" |
105 | "symbolic-link\0" No_argument "s" | 154 | "symbolic-link\0" No_argument "s" |
106 | "no-target-directory\0" No_argument "T" | 155 | "no-target-directory\0" No_argument "T" |
156 | "target-directory\0" Required_argument "t" | ||
107 | "verbose\0" No_argument "v" | 157 | "verbose\0" No_argument "v" |
108 | "update\0" No_argument "u" | 158 | "update\0" No_argument "u" |
109 | "remove-destination\0" No_argument "\xff" | 159 | "remove-destination\0" No_argument "\xff" |
110 | "parents\0" No_argument "\xfe" | 160 | "parents\0" No_argument "\xfe" |
111 | # if ENABLE_FEATURE_CP_REFLINK | 161 | # if ENABLE_FEATURE_CP_REFLINK |
112 | "reflink\0" Optional_argument "\xfd" | 162 | "reflink\0" Optional_argument "\xfd" |
163 | # endif | ||
164 | , &last | ||
165 | # if ENABLE_FEATURE_CP_REFLINK | ||
113 | , &reflink | 166 | , &reflink |
114 | # endif | 167 | # endif |
115 | ); | 168 | ); |
@@ -128,55 +181,10 @@ int cp_main(int argc, char **argv) | |||
128 | flags = getopt32(argv, "^" | 181 | flags = getopt32(argv, "^" |
129 | FILEUTILS_CP_OPTSTR | 182 | FILEUTILS_CP_OPTSTR |
130 | "\0" | 183 | "\0" |
131 | "-2:l--s:s--l:Pd:rRd:Rd:apdR" | 184 | "-1:l--s:s--l:Pd:rRd:Rd:apdR" |
185 | , &last | ||
132 | ); | 186 | ); |
133 | #endif | 187 | #endif |
134 | /* Options of cp from GNU coreutils 6.10: | ||
135 | * -a, --archive | ||
136 | * -f, --force | ||
137 | * -i, --interactive | ||
138 | * -l, --link | ||
139 | * -L, --dereference | ||
140 | * -P, --no-dereference | ||
141 | * -R, -r, --recursive | ||
142 | * -s, --symbolic-link | ||
143 | * -v, --verbose | ||
144 | * -H follow command-line symbolic links in SOURCE | ||
145 | * -d same as --no-dereference --preserve=links | ||
146 | * -p same as --preserve=mode,ownership,timestamps | ||
147 | * -c same as --preserve=context | ||
148 | * -u, --update | ||
149 | * copy only when the SOURCE file is newer than the destination | ||
150 | * file or when the destination file is missing | ||
151 | * --remove-destination | ||
152 | * remove each existing destination file before attempting to open | ||
153 | * --parents | ||
154 | * use full source file name under DIRECTORY | ||
155 | * -T, --no-target-directory | ||
156 | * treat DEST as a normal file | ||
157 | * NOT SUPPORTED IN BBOX: | ||
158 | * --backup[=CONTROL] | ||
159 | * make a backup of each existing destination file | ||
160 | * -b like --backup but does not accept an argument | ||
161 | * --copy-contents | ||
162 | * copy contents of special files when recursive | ||
163 | * --preserve[=ATTR_LIST] | ||
164 | * preserve attributes (default: mode,ownership,timestamps), | ||
165 | * if possible additional attributes: security context,links,all | ||
166 | * --no-preserve=ATTR_LIST | ||
167 | * --sparse=WHEN | ||
168 | * control creation of sparse files | ||
169 | * --strip-trailing-slashes | ||
170 | * remove any trailing slashes from each SOURCE argument | ||
171 | * -S, --suffix=SUFFIX | ||
172 | * override the usual backup suffix | ||
173 | * -t, --target-directory=DIRECTORY | ||
174 | * copy all SOURCE arguments into DIRECTORY | ||
175 | * -x, --one-file-system | ||
176 | * stay on this file system | ||
177 | * -Z, --context=CONTEXT | ||
178 | * (SELinux) set SELinux security context of copy to CONTEXT | ||
179 | */ | ||
180 | argc -= optind; | 188 | argc -= optind; |
181 | argv += optind; | 189 | argv += optind; |
182 | /* Reverse this bit. If there is -d, bit is not set: */ | 190 | /* Reverse this bit. If there is -d, bit is not set: */ |
@@ -195,49 +203,56 @@ int cp_main(int argc, char **argv) | |||
195 | #endif | 203 | #endif |
196 | 204 | ||
197 | status = EXIT_SUCCESS; | 205 | status = EXIT_SUCCESS; |
198 | last = argv[argc - 1]; | 206 | if (!(flags & FILEUTILS_TARGET_DIR)) { |
199 | /* If there are only two arguments and... */ | 207 | last = argv[argc - 1]; |
200 | if (argc == 2) { | 208 | if (argc < 2) |
201 | s_flags = cp_mv_stat2(*argv, &source_stat, | 209 | bb_show_usage(); |
202 | (flags & FILEUTILS_DEREFERENCE) ? stat : lstat); | 210 | if (argc != 2) { |
203 | if (s_flags < 0) | 211 | if (flags & FILEUTILS_NO_TARGET_DIR) |
204 | return EXIT_FAILURE; | 212 | bb_show_usage(); |
205 | d_flags = cp_mv_stat(last, &dest_stat); | 213 | /* "cp A B C... DIR" - target must be dir */ |
206 | if (d_flags < 0) | 214 | } else /* argc == 2 */ { |
207 | return EXIT_FAILURE; | 215 | /* "cp A B" - only case where target can be not a dir */ |
216 | s_flags = cp_mv_stat2(*argv, &source_stat, | ||
217 | (flags & FILEUTILS_DEREFERENCE) ? stat : lstat); | ||
218 | if (s_flags < 0) /* error other than ENOENT */ | ||
219 | return EXIT_FAILURE; | ||
220 | d_flags = cp_mv_stat(last, &dest_stat); | ||
221 | if (d_flags < 0) /* error other than ENOENT */ | ||
222 | return EXIT_FAILURE; | ||
208 | 223 | ||
209 | if (flags & FILEUTILS_NO_TARGET_DIR) { /* -T */ | 224 | if (flags & FILEUTILS_NO_TARGET_DIR) { /* -T */ |
210 | if (!(s_flags & 2) && (d_flags & 2)) | 225 | if (!(s_flags & 2) && (d_flags & 2)) |
211 | /* cp -T NOTDIR DIR */ | 226 | /* cp -T NOTDIR DIR */ |
212 | bb_error_msg_and_die("'%s' is a directory", last); | 227 | bb_error_msg_and_die("'%s' is a directory", last); |
213 | } | 228 | } |
214 | 229 | ||
215 | #if ENABLE_FEATURE_CP_LONG_OPTIONS | 230 | #if ENABLE_FEATURE_CP_LONG_OPTIONS |
216 | //bb_error_msg("flags:%x FILEUTILS_RMDEST:%x OPT_parents:%x", | 231 | //bb_error_msg("flags:%x FILEUTILS_RMDEST:%x OPT_parents:%x", |
217 | // flags, FILEUTILS_RMDEST, OPT_parents); | 232 | // flags, FILEUTILS_RMDEST, OPT_parents); |
218 | if (flags & OPT_parents) { | 233 | if (flags & OPT_parents) { |
219 | if (!(d_flags & 2)) { | 234 | if (!(d_flags & 2)) { |
220 | bb_simple_error_msg_and_die("with --parents, the destination must be a directory"); | 235 | bb_simple_error_msg_and_die("with --parents, the destination must be a directory"); |
236 | } | ||
237 | } | ||
238 | if (flags & FILEUTILS_RMDEST) { | ||
239 | flags |= FILEUTILS_FORCE; | ||
221 | } | 240 | } |
222 | } | ||
223 | if (flags & FILEUTILS_RMDEST) { | ||
224 | flags |= FILEUTILS_FORCE; | ||
225 | } | ||
226 | #endif | 241 | #endif |
227 | 242 | ||
228 | /* ...if neither is a directory... */ | 243 | /* ...if neither is a directory... */ |
229 | if (!((s_flags | d_flags) & 2) | 244 | if (!((s_flags | d_flags) & 2) |
230 | /* ...or: recursing, the 1st is a directory, and the 2nd doesn't exist... */ | 245 | /* ...or: recursing, the 1st is a directory, and the 2nd doesn't exist... */ |
231 | || ((flags & FILEUTILS_RECUR) && (s_flags & 2) && !d_flags) | 246 | || ((flags & FILEUTILS_RECUR) && (s_flags & 2) && !d_flags) |
232 | || (flags & FILEUTILS_NO_TARGET_DIR) | 247 | || (flags & FILEUTILS_NO_TARGET_DIR) |
233 | ) { | 248 | ) { |
234 | /* Do a simple copy */ | 249 | /* Do a simple copy */ |
235 | dest = last; | 250 | dest = last; |
236 | goto DO_COPY; /* NB: argc==2 -> *++argv==last */ | 251 | goto DO_COPY; /* NB: argc==2 -> *++argv==last */ |
252 | } | ||
237 | } | 253 | } |
238 | } else if (flags & FILEUTILS_NO_TARGET_DIR) { | ||
239 | bb_simple_error_msg_and_die("too many arguments"); | ||
240 | } | 254 | } |
255 | /* else: last is DIR from "-t DIR" */ | ||
241 | 256 | ||
242 | while (1) { | 257 | while (1) { |
243 | #if ENABLE_FEATURE_CP_LONG_OPTIONS | 258 | #if ENABLE_FEATURE_CP_LONG_OPTIONS |
@@ -259,7 +274,7 @@ int cp_main(int argc, char **argv) | |||
259 | if (copy_file(*argv, dest, flags) < 0) { | 274 | if (copy_file(*argv, dest, flags) < 0) { |
260 | status = EXIT_FAILURE; | 275 | status = EXIT_FAILURE; |
261 | } | 276 | } |
262 | if (*++argv == last) { | 277 | if (!*++argv || *argv == last) { |
263 | /* possibly leaking dest... */ | 278 | /* possibly leaking dest... */ |
264 | break; | 279 | break; |
265 | } | 280 | } |
diff --git a/coreutils/cut.c b/coreutils/cut.c index 5897d82b6..cc3c32576 100644 --- a/coreutils/cut.c +++ b/coreutils/cut.c | |||
@@ -29,6 +29,7 @@ | |||
29 | //usage: "\n -s Output only lines containing delimiter" | 29 | //usage: "\n -s Output only lines containing delimiter" |
30 | //usage: "\n -f LIST Print only these fields" | 30 | //usage: "\n -f LIST Print only these fields" |
31 | //usage: "\n -n Ignored" | 31 | //usage: "\n -n Ignored" |
32 | //(manpage:-n with -b: don't split multibyte characters) | ||
32 | //usage: | 33 | //usage: |
33 | //usage:#define cut_example_usage | 34 | //usage:#define cut_example_usage |
34 | //usage: "$ echo \"Hello world\" | cut -f 1 -d ' '\n" | 35 | //usage: "$ echo \"Hello world\" | cut -f 1 -d ' '\n" |
diff --git a/coreutils/df.c b/coreutils/df.c index debb86867..e8d4bc8f2 100644 --- a/coreutils/df.c +++ b/coreutils/df.c | |||
@@ -45,7 +45,7 @@ | |||
45 | //usage: IF_FEATURE_HUMAN_READABLE("mh") | 45 | //usage: IF_FEATURE_HUMAN_READABLE("mh") |
46 | //usage: "T" | 46 | //usage: "T" |
47 | //usage: IF_FEATURE_DF_FANCY("ai] [-B SIZE") | 47 | //usage: IF_FEATURE_DF_FANCY("ai] [-B SIZE") |
48 | //usage: "] [FILESYSTEM]..." | 48 | //usage: "] [-t TYPE] [FILESYSTEM]..." |
49 | //usage:#define df_full_usage "\n\n" | 49 | //usage:#define df_full_usage "\n\n" |
50 | //usage: "Print filesystem usage statistics\n" | 50 | //usage: "Print filesystem usage statistics\n" |
51 | //usage: "\n -P POSIX output format" | 51 | //usage: "\n -P POSIX output format" |
@@ -55,6 +55,7 @@ | |||
55 | //usage: "\n -h Human readable (e.g. 1K 243M 2G)" | 55 | //usage: "\n -h Human readable (e.g. 1K 243M 2G)" |
56 | //usage: ) | 56 | //usage: ) |
57 | //usage: "\n -T Print filesystem type" | 57 | //usage: "\n -T Print filesystem type" |
58 | //usage: "\n -t TYPE Print only mounts of this type" | ||
58 | //usage: IF_FEATURE_DF_FANCY( | 59 | //usage: IF_FEATURE_DF_FANCY( |
59 | //usage: "\n -a Show all filesystems" | 60 | //usage: "\n -a Show all filesystems" |
60 | //usage: "\n -i Inodes" | 61 | //usage: "\n -i Inodes" |
@@ -97,24 +98,31 @@ int df_main(int argc UNUSED_PARAM, char **argv) | |||
97 | FILE *mount_table; | 98 | FILE *mount_table; |
98 | struct mntent *mount_entry; | 99 | struct mntent *mount_entry; |
99 | struct statvfs s; | 100 | struct statvfs s; |
100 | |||
101 | enum { | 101 | enum { |
102 | OPT_KILO = (1 << 0), | 102 | OPT_KILO = (1 << 0), |
103 | OPT_POSIX = (1 << 1), | 103 | OPT_POSIX = (1 << 1), |
104 | OPT_FSTYPE = (1 << 2), | 104 | OPT_FSTYPE = (1 << 2), |
105 | OPT_ALL = (1 << 3) * ENABLE_FEATURE_DF_FANCY, | 105 | OPT_t = (1 << 3), |
106 | OPT_INODE = (1 << 4) * ENABLE_FEATURE_DF_FANCY, | 106 | OPT_ALL = (1 << 4) * ENABLE_FEATURE_DF_FANCY, |
107 | OPT_BSIZE = (1 << 5) * ENABLE_FEATURE_DF_FANCY, | 107 | OPT_INODE = (1 << 5) * ENABLE_FEATURE_DF_FANCY, |
108 | OPT_HUMAN = (1 << (3 + 3*ENABLE_FEATURE_DF_FANCY)) * ENABLE_FEATURE_HUMAN_READABLE, | 108 | OPT_BSIZE = (1 << 6) * ENABLE_FEATURE_DF_FANCY, |
109 | OPT_MEGA = (1 << (4 + 3*ENABLE_FEATURE_DF_FANCY)) * ENABLE_FEATURE_HUMAN_READABLE, | 109 | OPT_HUMAN = (1 << (4 + 3*ENABLE_FEATURE_DF_FANCY)) * ENABLE_FEATURE_HUMAN_READABLE, |
110 | OPT_MEGA = (1 << (5 + 3*ENABLE_FEATURE_DF_FANCY)) * ENABLE_FEATURE_HUMAN_READABLE, | ||
110 | }; | 111 | }; |
111 | const char *disp_units_hdr = NULL; | 112 | const char *disp_units_hdr = NULL; |
112 | char *chp; | 113 | char *chp, *opt_t; |
113 | 114 | ||
114 | init_unicode(); | 115 | init_unicode(); |
115 | 116 | ||
117 | /* From the manpage of df from coreutils-6.10: | ||
118 | * Disk space is shown in 1K blocks by default, unless the environment | ||
119 | * variable POSIXLY_CORRECT is set, in which case 512-byte blocks are used. | ||
120 | */ | ||
121 | if (getenv("POSIXLY_CORRECT")) /* TODO - a new libbb function? */ | ||
122 | df_disp_hr = 512; | ||
123 | |||
116 | opt = getopt32(argv, "^" | 124 | opt = getopt32(argv, "^" |
117 | "kPT" | 125 | "kPTt:" |
118 | IF_FEATURE_DF_FANCY("aiB:") | 126 | IF_FEATURE_DF_FANCY("aiB:") |
119 | IF_FEATURE_HUMAN_READABLE("hm") | 127 | IF_FEATURE_HUMAN_READABLE("hm") |
120 | "\0" | 128 | "\0" |
@@ -123,6 +131,7 @@ int df_main(int argc UNUSED_PARAM, char **argv) | |||
123 | #elif ENABLE_FEATURE_HUMAN_READABLE | 131 | #elif ENABLE_FEATURE_HUMAN_READABLE |
124 | "k-m:m-k" | 132 | "k-m:m-k" |
125 | #endif | 133 | #endif |
134 | , &opt_t | ||
126 | IF_FEATURE_DF_FANCY(, &chp) | 135 | IF_FEATURE_DF_FANCY(, &chp) |
127 | ); | 136 | ); |
128 | if (opt & OPT_MEGA) | 137 | if (opt & OPT_MEGA) |
@@ -142,13 +151,6 @@ int df_main(int argc UNUSED_PARAM, char **argv) | |||
142 | got_it: ; | 151 | got_it: ; |
143 | } | 152 | } |
144 | 153 | ||
145 | /* From the manpage of df from coreutils-6.10: | ||
146 | * Disk space is shown in 1K blocks by default, unless the environment | ||
147 | * variable POSIXLY_CORRECT is set, in which case 512-byte blocks are used. | ||
148 | */ | ||
149 | if (getenv("POSIXLY_CORRECT")) /* TODO - a new libbb function? */ | ||
150 | df_disp_hr = 512; | ||
151 | |||
152 | if (opt & OPT_HUMAN) { | 154 | if (opt & OPT_HUMAN) { |
153 | df_disp_hr = 0; | 155 | df_disp_hr = 0; |
154 | disp_units_hdr = " Size"; | 156 | disp_units_hdr = " Size"; |
@@ -214,6 +216,11 @@ int df_main(int argc UNUSED_PARAM, char **argv) | |||
214 | mount_point = mount_entry->mnt_dir; | 216 | mount_point = mount_entry->mnt_dir; |
215 | fs_type = mount_entry->mnt_type; | 217 | fs_type = mount_entry->mnt_type; |
216 | 218 | ||
219 | if (opt & OPT_t) { | ||
220 | if (strcmp(fs_type, opt_t) != 0) | ||
221 | continue; | ||
222 | } | ||
223 | |||
217 | if (statvfs(mount_point, &s) != 0) { | 224 | if (statvfs(mount_point, &s) != 0) { |
218 | bb_simple_perror_msg(mount_point); | 225 | bb_simple_perror_msg(mount_point); |
219 | goto set_error; | 226 | goto set_error; |
diff --git a/coreutils/du.c b/coreutils/du.c index 247a08c95..092647468 100644 --- a/coreutils/du.c +++ b/coreutils/du.c | |||
@@ -42,6 +42,7 @@ | |||
42 | //usage:#define du_full_usage "\n\n" | 42 | //usage:#define du_full_usage "\n\n" |
43 | //usage: "Summarize disk space used for FILEs (or directories)\n" | 43 | //usage: "Summarize disk space used for FILEs (or directories)\n" |
44 | //usage: "\n -a Show file sizes too" | 44 | //usage: "\n -a Show file sizes too" |
45 | //usage: "\n -b Apparent size (including holes)" | ||
45 | //usage: "\n -L Follow all symlinks" | 46 | //usage: "\n -L Follow all symlinks" |
46 | //usage: "\n -H Follow symlinks on command line" | 47 | //usage: "\n -H Follow symlinks on command line" |
47 | //usage: "\n -d N Limit output to directories (and files with -a) of depth < N" | 48 | //usage: "\n -d N Limit output to directories (and files with -a) of depth < N" |
@@ -84,8 +85,9 @@ enum { | |||
84 | OPT_d_maxdepth = (1 << 6), | 85 | OPT_d_maxdepth = (1 << 6), |
85 | OPT_l_hardlinks = (1 << 7), | 86 | OPT_l_hardlinks = (1 << 7), |
86 | OPT_c_total = (1 << 8), | 87 | OPT_c_total = (1 << 8), |
87 | OPT_h_for_humans = (1 << 9), | 88 | OPT_b = (1 << 9), |
88 | OPT_m_mbytes = (1 << 10), | 89 | OPT_h_for_humans = (1 << 10), |
90 | OPT_m_mbytes = (1 << 11), | ||
89 | }; | 91 | }; |
90 | 92 | ||
91 | struct globals { | 93 | struct globals { |
@@ -109,7 +111,7 @@ static void print(unsigned long long size, const char *filename) | |||
109 | /* TODO - May not want to defer error checking here. */ | 111 | /* TODO - May not want to defer error checking here. */ |
110 | #if ENABLE_FEATURE_HUMAN_READABLE | 112 | #if ENABLE_FEATURE_HUMAN_READABLE |
111 | # if ENABLE_DESKTOP | 113 | # if ENABLE_DESKTOP |
112 | /* ~30 bytes of code for extra comtat: | 114 | /* ~30 bytes of code for extra compat: |
113 | * coreutils' du rounds sizes up: | 115 | * coreutils' du rounds sizes up: |
114 | * for example, 1025k file is shown as "2" by du -m. | 116 | * for example, 1025k file is shown as "2" by du -m. |
115 | * We round to nearest if human-readable [too hard to fix], | 117 | * We round to nearest if human-readable [too hard to fix], |
@@ -124,12 +126,16 @@ static void print(unsigned long long size, const char *filename) | |||
124 | * If G.disp_unit == 0, show one fractional | 126 | * If G.disp_unit == 0, show one fractional |
125 | * and use suffixes | 127 | * and use suffixes |
126 | */ | 128 | */ |
127 | make_human_readable_str(size, 512, G.disp_unit), | 129 | make_human_readable_str(size, (option_mask32 & OPT_b) ? 1 : 512, G.disp_unit), |
128 | filename); | 130 | filename); |
129 | #else | 131 | #else |
130 | if (G.disp_k) { | 132 | if (G.disp_k) { |
131 | size++; | 133 | if (!(option_mask32 & OPT_b)) { |
132 | size >>= 1; | 134 | size++; |
135 | size >>= 1; | ||
136 | } else { | ||
137 | size >>= 10; | ||
138 | } | ||
133 | } | 139 | } |
134 | printf("%"LL_FMT"u\t%s\n", size, filename); | 140 | printf("%"LL_FMT"u\t%s\n", size, filename); |
135 | #endif | 141 | #endif |
@@ -155,7 +161,7 @@ static unsigned long long du(const char *filename) | |||
155 | } | 161 | } |
156 | } | 162 | } |
157 | 163 | ||
158 | sum = statbuf.st_blocks; | 164 | sum = ((option_mask32 & OPT_b) ? statbuf.st_size : statbuf.st_blocks); |
159 | 165 | ||
160 | if (S_ISLNK(statbuf.st_mode)) { | 166 | if (S_ISLNK(statbuf.st_mode)) { |
161 | if (G.slink_depth > G.du_depth) { /* -H or -L */ | 167 | if (G.slink_depth > G.du_depth) { /* -H or -L */ |
@@ -164,7 +170,7 @@ static unsigned long long du(const char *filename) | |||
164 | G.status = EXIT_FAILURE; | 170 | G.status = EXIT_FAILURE; |
165 | return 0; | 171 | return 0; |
166 | } | 172 | } |
167 | sum = statbuf.st_blocks; | 173 | sum = ((option_mask32 & OPT_b) ? statbuf.st_size : statbuf.st_blocks); |
168 | if (G.slink_depth == 1) { | 174 | if (G.slink_depth == 1) { |
169 | /* Convert -H to -L */ | 175 | /* Convert -H to -L */ |
170 | G.slink_depth = INT_MAX; | 176 | G.slink_depth = INT_MAX; |
@@ -241,11 +247,14 @@ int du_main(int argc UNUSED_PARAM, char **argv) | |||
241 | */ | 247 | */ |
242 | #if ENABLE_FEATURE_HUMAN_READABLE | 248 | #if ENABLE_FEATURE_HUMAN_READABLE |
243 | opt = getopt32(argv, "^" | 249 | opt = getopt32(argv, "^" |
244 | "aHkLsxd:+lchm" | 250 | "aHkLsxd:+lcbhm" |
245 | "\0" "h-km:k-hm:m-hk:H-L:L-H:s-d:d-s", | 251 | "\0" "h-km:k-hm:m-hk:H-L:L-H:s-d:d-s", |
246 | &G.max_print_depth | 252 | &G.max_print_depth |
247 | ); | 253 | ); |
248 | argv += optind; | 254 | argv += optind; |
255 | if (opt & OPT_b) { | ||
256 | G.disp_unit = 1; | ||
257 | } | ||
249 | if (opt & OPT_h_for_humans) { | 258 | if (opt & OPT_h_for_humans) { |
250 | G.disp_unit = 0; | 259 | G.disp_unit = 0; |
251 | } | 260 | } |
@@ -257,16 +266,16 @@ int du_main(int argc UNUSED_PARAM, char **argv) | |||
257 | } | 266 | } |
258 | #else | 267 | #else |
259 | opt = getopt32(argv, "^" | 268 | opt = getopt32(argv, "^" |
260 | "aHkLsxd:+lc" | 269 | "aHkLsxd:+lcb" |
261 | "\0" "H-L:L-H:s-d:d-s", | 270 | "\0" "H-L:L-H:s-d:d-s", |
262 | &G.max_print_depth | 271 | &G.max_print_depth |
263 | ); | 272 | ); |
264 | argv += optind; | 273 | argv += optind; |
265 | #if !ENABLE_FEATURE_DU_DEFAULT_BLOCKSIZE_1K | 274 | # if !ENABLE_FEATURE_DU_DEFAULT_BLOCKSIZE_1K |
266 | if (opt & OPT_k_kbytes) { | 275 | if (opt & OPT_k_kbytes) { |
267 | G.disp_k = 1; | 276 | G.disp_k = 1; |
268 | } | 277 | } |
269 | #endif | 278 | # endif |
270 | #endif | 279 | #endif |
271 | if (opt & OPT_H_follow_links) { | 280 | if (opt & OPT_H_follow_links) { |
272 | G.slink_depth = 1; | 281 | G.slink_depth = 1; |
diff --git a/coreutils/echo.c b/coreutils/echo.c index aab177cee..82f0358b6 100644 --- a/coreutils/echo.c +++ b/coreutils/echo.c | |||
@@ -43,10 +43,10 @@ | |||
43 | //usage:#define echo_trivial_usage | 43 | //usage:#define echo_trivial_usage |
44 | //usage: IF_FEATURE_FANCY_ECHO("[-neE] ") "[ARG]..." | 44 | //usage: IF_FEATURE_FANCY_ECHO("[-neE] ") "[ARG]..." |
45 | //usage:#define echo_full_usage "\n\n" | 45 | //usage:#define echo_full_usage "\n\n" |
46 | //usage: "Print the specified ARGs to stdout" | 46 | //usage: "Print ARGs to stdout" |
47 | //usage: IF_FEATURE_FANCY_ECHO( "\n" | 47 | //usage: IF_FEATURE_FANCY_ECHO( "\n" |
48 | //usage: "\n -n Suppress trailing newline" | 48 | //usage: "\n -n No trailing newline" |
49 | //usage: "\n -e Interpret backslash escapes (i.e., \\t=tab)" | 49 | //usage: "\n -e Interpret backslash escapes (\\t=tab etc)" |
50 | //usage: "\n -E Don't interpret backslash escapes (default)" | 50 | //usage: "\n -E Don't interpret backslash escapes (default)" |
51 | //usage: ) | 51 | //usage: ) |
52 | //usage: | 52 | //usage: |
diff --git a/coreutils/env.c b/coreutils/env.c index c37c0c2df..a0ea4dd27 100644 --- a/coreutils/env.c +++ b/coreutils/env.c | |||
@@ -39,12 +39,15 @@ | |||
39 | /* http://www.opengroup.org/onlinepubs/007904975/utilities/env.html */ | 39 | /* http://www.opengroup.org/onlinepubs/007904975/utilities/env.html */ |
40 | 40 | ||
41 | //usage:#define env_trivial_usage | 41 | //usage:#define env_trivial_usage |
42 | //usage: "[-iu] [-] [name=value]... [PROG ARGS]" | 42 | //usage: "[-i0] [-u NAME]... [-] [NAME=VALUE]... [PROG ARGS]" |
43 | // The "-" can occur only once (unlike, say, -i): it terminates option processing, | ||
44 | // so if it is followed by another "-" arg (or any option-looking arg), | ||
45 | // that arg will be taken as PROG (or even as NAME=VALUE, example: "-z=QWE"). | ||
43 | //usage:#define env_full_usage "\n\n" | 46 | //usage:#define env_full_usage "\n\n" |
44 | //usage: "Print the current environment or run PROG after setting up\n" | 47 | //usage: "Print current environment or run PROG after setting up environment\n" |
45 | //usage: "the specified environment\n" | 48 | //usage: "\n -, -i Start with empty environment" |
46 | //usage: "\n -, -i Start with an empty environment" | 49 | //usage: "\n -0 NUL terminated output" |
47 | //usage: "\n -u Remove variable from the environment" | 50 | //usage: "\n -u NAME Remove variable from environment" |
48 | 51 | ||
49 | #include "libbb.h" | 52 | #include "libbb.h" |
50 | 53 | ||
@@ -54,8 +57,9 @@ int env_main(int argc UNUSED_PARAM, char **argv) | |||
54 | unsigned opts; | 57 | unsigned opts; |
55 | llist_t *unset_env = NULL; | 58 | llist_t *unset_env = NULL; |
56 | 59 | ||
57 | opts = getopt32long(argv, "+iu:*", | 60 | opts = getopt32long(argv, "+i0u:*", |
58 | "ignore-environment\0" No_argument "i" | 61 | "ignore-environment\0" No_argument "i" |
62 | "null\0" No_argument "0" | ||
59 | "unset\0" Required_argument "u" | 63 | "unset\0" Required_argument "u" |
60 | , &unset_env | 64 | , &unset_env |
61 | ); | 65 | ); |
@@ -90,8 +94,9 @@ int env_main(int argc UNUSED_PARAM, char **argv) | |||
90 | 94 | ||
91 | if (environ) { /* clearenv() may set environ == NULL! */ | 95 | if (environ) { /* clearenv() may set environ == NULL! */ |
92 | char **ep; | 96 | char **ep; |
97 | opts = (opts & 2) ? 0 : '\n'; | ||
93 | for (ep = environ; *ep; ep++) { | 98 | for (ep = environ; *ep; ep++) { |
94 | puts(*ep); | 99 | printf("%s%c", *ep, opts); |
95 | } | 100 | } |
96 | } | 101 | } |
97 | 102 | ||
diff --git a/coreutils/expr.c b/coreutils/expr.c index c11505d13..b896acd44 100644 --- a/coreutils/expr.c +++ b/coreutils/expr.c | |||
@@ -45,7 +45,7 @@ | |||
45 | //usage:#define expr_trivial_usage | 45 | //usage:#define expr_trivial_usage |
46 | //usage: "EXPRESSION" | 46 | //usage: "EXPRESSION" |
47 | //usage:#define expr_full_usage "\n\n" | 47 | //usage:#define expr_full_usage "\n\n" |
48 | //usage: "Print the value of EXPRESSION to stdout\n" | 48 | //usage: "Print the value of EXPRESSION\n" |
49 | //usage: "\n" | 49 | //usage: "\n" |
50 | //usage: "EXPRESSION may be:\n" | 50 | //usage: "EXPRESSION may be:\n" |
51 | //usage: " ARG1 | ARG2 ARG1 if it is neither null nor 0, otherwise ARG2\n" | 51 | //usage: " ARG1 | ARG2 ARG1 if it is neither null nor 0, otherwise ARG2\n" |
@@ -63,7 +63,7 @@ | |||
63 | //usage: " ARG1 % ARG2\n" | 63 | //usage: " ARG1 % ARG2\n" |
64 | //usage: " STRING : REGEXP Anchored pattern match of REGEXP in STRING\n" | 64 | //usage: " STRING : REGEXP Anchored pattern match of REGEXP in STRING\n" |
65 | //usage: " match STRING REGEXP Same as STRING : REGEXP\n" | 65 | //usage: " match STRING REGEXP Same as STRING : REGEXP\n" |
66 | //usage: " substr STRING POS LENGTH Substring of STRING, POS counted from 1\n" | 66 | //usage: " substr STRING POS LEN Substring of STRING, POS counts from 1\n" |
67 | //usage: " index STRING CHARS Index in STRING where any CHARS is found, or 0\n" | 67 | //usage: " index STRING CHARS Index in STRING where any CHARS is found, or 0\n" |
68 | //usage: " length STRING Length of STRING\n" | 68 | //usage: " length STRING Length of STRING\n" |
69 | //usage: " quote TOKEN Interpret TOKEN as a string, even if\n" | 69 | //usage: " quote TOKEN Interpret TOKEN as a string, even if\n" |
diff --git a/coreutils/id.c b/coreutils/id.c index f453a87ae..18bda3c55 100644 --- a/coreutils/id.c +++ b/coreutils/id.c | |||
@@ -52,7 +52,7 @@ | |||
52 | //usage:#define groups_trivial_usage | 52 | //usage:#define groups_trivial_usage |
53 | //usage: "[USER]" | 53 | //usage: "[USER]" |
54 | //usage:#define groups_full_usage "\n\n" | 54 | //usage:#define groups_full_usage "\n\n" |
55 | //usage: "Print the group memberships of USER or for the current process" | 55 | //usage: "Print the groups USER is in" |
56 | //usage: | 56 | //usage: |
57 | //usage:#define groups_example_usage | 57 | //usage:#define groups_example_usage |
58 | //usage: "$ groups\n" | 58 | //usage: "$ groups\n" |
diff --git a/coreutils/mv.c b/coreutils/mv.c index f5ed9fcfc..fd2422683 100644 --- a/coreutils/mv.c +++ b/coreutils/mv.c | |||
@@ -23,13 +23,15 @@ | |||
23 | //kbuild:lib-$(CONFIG_MV) += mv.o | 23 | //kbuild:lib-$(CONFIG_MV) += mv.o |
24 | 24 | ||
25 | //usage:#define mv_trivial_usage | 25 | //usage:#define mv_trivial_usage |
26 | //usage: "[-fin] SOURCE DEST\n" | 26 | //usage: "[-finT] SOURCE DEST\n" |
27 | //usage: "or: mv [-fin] SOURCE... DIRECTORY" | 27 | //usage: "or: mv [-fin] SOURCE... { -t DIRECTORY | DIRECTORY }" |
28 | //usage:#define mv_full_usage "\n\n" | 28 | //usage:#define mv_full_usage "\n\n" |
29 | //usage: "Rename SOURCE to DEST, or move SOURCEs to DIRECTORY\n" | 29 | //usage: "Rename SOURCE to DEST, or move SOURCEs to DIRECTORY\n" |
30 | //usage: "\n -f Don't prompt before overwriting" | 30 | //usage: "\n -f Don't prompt before overwriting" |
31 | //usage: "\n -i Interactive, prompt before overwrite" | 31 | //usage: "\n -i Interactive, prompt before overwrite" |
32 | //usage: "\n -n Don't overwrite an existing file" | 32 | //usage: "\n -n Don't overwrite an existing file" |
33 | //usage: "\n -T Refuse to move if DEST is a directory" | ||
34 | //usage: "\n -t DIR Move all SOURCEs into DIR" | ||
33 | //usage: | 35 | //usage: |
34 | //usage:#define mv_example_usage | 36 | //usage:#define mv_example_usage |
35 | //usage: "$ mv /tmp/foo /bin/bar\n" | 37 | //usage: "$ mv /tmp/foo /bin/bar\n" |
@@ -40,7 +42,7 @@ | |||
40 | int mv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 42 | int mv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
41 | int mv_main(int argc, char **argv) | 43 | int mv_main(int argc, char **argv) |
42 | { | 44 | { |
43 | struct stat dest_stat; | 45 | struct stat statbuf; |
44 | const char *last; | 46 | const char *last; |
45 | const char *dest; | 47 | const char *dest; |
46 | unsigned flags; | 48 | unsigned flags; |
@@ -51,41 +53,66 @@ int mv_main(int argc, char **argv) | |||
51 | #define OPT_FORCE (1 << 0) | 53 | #define OPT_FORCE (1 << 0) |
52 | #define OPT_INTERACTIVE (1 << 1) | 54 | #define OPT_INTERACTIVE (1 << 1) |
53 | #define OPT_NOCLOBBER (1 << 2) | 55 | #define OPT_NOCLOBBER (1 << 2) |
54 | #define OPT_VERBOSE ((1 << 3) * ENABLE_FEATURE_VERBOSE) | 56 | #define OPT_DESTNOTDIR (1 << 3) |
55 | /* Need at least two arguments. | 57 | #define OPT_DESTDIR (1 << 4) |
56 | * If more than one of -f, -i, -n is specified , only the final one | 58 | #define OPT_VERBOSE ((1 << 5) * ENABLE_FEATURE_VERBOSE) |
57 | * takes effect (it unsets previous options). | ||
58 | */ | ||
59 | flags = getopt32long(argv, "^" | 59 | flags = getopt32long(argv, "^" |
60 | "finv" | 60 | "finTt:v" |
61 | "\0" | 61 | "\0" |
62 | "-2:f-in:i-fn:n-fi", | 62 | /* At least one argument. (Usually two+, but -t DIR can have only one) */ |
63 | "-1" | ||
64 | /* only the final one of -f, -i, -n takes effect */ | ||
65 | ":f-in:i-fn:n-fi" | ||
66 | /* -t and -T don't mix */ | ||
67 | ":t--T:T--t", | ||
63 | "interactive\0" No_argument "i" | 68 | "interactive\0" No_argument "i" |
64 | "force\0" No_argument "f" | 69 | "force\0" No_argument "f" |
65 | "no-clobber\0" No_argument "n" | 70 | "no-clobber\0" No_argument "n" |
71 | "no-target-directory\0" No_argument "T" | ||
72 | "target-directory\0" Required_argument "t" | ||
66 | IF_FEATURE_VERBOSE( | 73 | IF_FEATURE_VERBOSE( |
67 | "verbose\0" No_argument "v" | 74 | "verbose\0" No_argument "v", |
75 | &last | ||
68 | ) | 76 | ) |
69 | ); | 77 | ); |
70 | argc -= optind; | 78 | argc -= optind; |
71 | argv += optind; | 79 | argv += optind; |
72 | last = argv[argc - 1]; | ||
73 | 80 | ||
74 | if (argc == 2) { | 81 | if (!(flags & OPT_DESTDIR)) { |
75 | dest_exists = cp_mv_stat(last, &dest_stat); | 82 | last = argv[argc - 1]; |
76 | if (dest_exists < 0) { | 83 | if (argc < 2) |
77 | return EXIT_FAILURE; | 84 | bb_show_usage(); |
78 | } | 85 | if (argc != 2) { |
79 | 86 | if (flags & OPT_DESTNOTDIR) | |
80 | if (!(dest_exists & 2)) { /* last is not a directory */ | 87 | bb_show_usage(); |
81 | dest = last; | 88 | /* "mv A B C... DIR" - target must be dir */ |
82 | goto DO_MOVE; | 89 | } else /* argc == 2 */ { |
90 | /* "mv A B" - only case where target can be not a dir */ | ||
91 | dest_exists = cp_mv_stat(last, &statbuf); | ||
92 | if (dest_exists < 0) { /* error other than ENOENT */ | ||
93 | return EXIT_FAILURE; | ||
94 | } | ||
95 | if (!(dest_exists & 2)) { | ||
96 | /* last is not a directory */ | ||
97 | dest = last; | ||
98 | goto DO_MOVE; | ||
99 | } | ||
100 | /* last is a directory */ | ||
101 | if (flags & OPT_DESTNOTDIR) { | ||
102 | if (stat(argv[0], &statbuf) == 0 && !S_ISDIR(statbuf.st_mode)) | ||
103 | bb_error_msg_and_die("'%s' is a directory", last); | ||
104 | /* "mv -T DIR1 DIR2" is allowed (renames a dir) */ | ||
105 | dest = last; | ||
106 | goto DO_MOVE; | ||
107 | } | ||
108 | /* else: fall through into "do { move SRC to DIR/SRC } while" loop */ | ||
83 | } | 109 | } |
84 | } | 110 | } |
111 | /* else: last is DIR from "-t DIR" */ | ||
85 | 112 | ||
86 | do { | 113 | do { |
87 | dest = concat_path_file(last, bb_get_last_path_component_strip(*argv)); | 114 | dest = concat_path_file(last, bb_get_last_path_component_strip(*argv)); |
88 | dest_exists = cp_mv_stat(dest, &dest_stat); | 115 | dest_exists = cp_mv_stat(dest, &statbuf); |
89 | if (dest_exists < 0) { | 116 | if (dest_exists < 0) { |
90 | goto RET_1; | 117 | goto RET_1; |
91 | } | 118 | } |
@@ -108,11 +135,10 @@ int mv_main(int argc, char **argv) | |||
108 | } | 135 | } |
109 | 136 | ||
110 | if (rename(*argv, dest) < 0) { | 137 | if (rename(*argv, dest) < 0) { |
111 | struct stat source_stat; | ||
112 | int source_exists; | 138 | int source_exists; |
113 | 139 | ||
114 | if (errno != EXDEV | 140 | if (errno != EXDEV |
115 | || (source_exists = cp_mv_stat2(*argv, &source_stat, lstat)) < 1 | 141 | || (source_exists = cp_mv_stat2(*argv, &statbuf, lstat)) < 1 |
116 | ) { | 142 | ) { |
117 | bb_perror_msg("can't rename '%s'", *argv); | 143 | bb_perror_msg("can't rename '%s'", *argv); |
118 | } else { | 144 | } else { |
@@ -159,7 +185,7 @@ int mv_main(int argc, char **argv) | |||
159 | if (dest != last) { | 185 | if (dest != last) { |
160 | free((void *) dest); | 186 | free((void *) dest); |
161 | } | 187 | } |
162 | } while (*++argv != last); | 188 | } while (*++argv && *argv != last); |
163 | 189 | ||
164 | return status; | 190 | return status; |
165 | } | 191 | } |
diff --git a/coreutils/nproc.c b/coreutils/nproc.c index 7025765c5..b345255a7 100644 --- a/coreutils/nproc.c +++ b/coreutils/nproc.c | |||
@@ -14,7 +14,7 @@ | |||
14 | //kbuild:lib-$(CONFIG_NPROC) += nproc.o | 14 | //kbuild:lib-$(CONFIG_NPROC) += nproc.o |
15 | 15 | ||
16 | //usage:#define nproc_trivial_usage | 16 | //usage:#define nproc_trivial_usage |
17 | //usage: ""IF_LONG_OPTS("--all --ignore=N") | 17 | //usage: ""IF_LONG_OPTS("[--all] [--ignore=N]") |
18 | //usage:#define nproc_full_usage "\n\n" | 18 | //usage:#define nproc_full_usage "\n\n" |
19 | //usage: "Print number of available CPUs" | 19 | //usage: "Print number of available CPUs" |
20 | //usage: IF_LONG_OPTS( | 20 | //usage: IF_LONG_OPTS( |
@@ -49,7 +49,7 @@ int nproc_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
49 | if (cpuid && isdigit(cpuid[strlen(cpuid) - 1])) | 49 | if (cpuid && isdigit(cpuid[strlen(cpuid) - 1])) |
50 | count++; | 50 | count++; |
51 | } | 51 | } |
52 | closedir(cpusd); | 52 | IF_FEATURE_CLEAN_UP(closedir(cpusd);) |
53 | } | 53 | } |
54 | } else | 54 | } else |
55 | #endif | 55 | #endif |
diff --git a/coreutils/shred.c b/coreutils/shred.c index 0b11b9491..794d7b815 100644 --- a/coreutils/shred.c +++ b/coreutils/shred.c | |||
@@ -15,14 +15,15 @@ | |||
15 | //kbuild:lib-$(CONFIG_SHRED) += shred.o | 15 | //kbuild:lib-$(CONFIG_SHRED) += shred.o |
16 | 16 | ||
17 | //usage:#define shred_trivial_usage | 17 | //usage:#define shred_trivial_usage |
18 | //usage: "FILE..." | 18 | //usage: "[-fuz] [-n N] [-s SIZE] FILE..." |
19 | //usage:#define shred_full_usage "\n\n" | 19 | //usage:#define shred_full_usage "\n\n" |
20 | //usage: "Overwrite/delete FILEs\n" | 20 | //usage: "Overwrite/delete FILEs\n" |
21 | //usage: "\n -f Chmod to ensure writability" | 21 | //usage: "\n -f Chmod to ensure writability" |
22 | //usage: "\n -s SIZE Size to write" | ||
22 | //usage: "\n -n N Overwrite N times (default 3)" | 23 | //usage: "\n -n N Overwrite N times (default 3)" |
23 | //usage: "\n -z Final overwrite with zeros" | 24 | //usage: "\n -z Final overwrite with zeros" |
24 | //usage: "\n -u Remove file" | 25 | //usage: "\n -u Remove file" |
25 | //-x and -v are accepted but have no effect | 26 | //-x (exact: don't round up to 4k) and -v (verbose) are accepted but have no effect |
26 | 27 | ||
27 | /* shred (GNU coreutils) 8.25: | 28 | /* shred (GNU coreutils) 8.25: |
28 | -f, --force change permissions to allow writing if necessary | 29 | -f, --force change permissions to allow writing if necessary |
@@ -41,6 +42,7 @@ | |||
41 | int shred_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 42 | int shred_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
42 | int shred_main(int argc UNUSED_PARAM, char **argv) | 43 | int shred_main(int argc UNUSED_PARAM, char **argv) |
43 | { | 44 | { |
45 | char *opt_s; | ||
44 | int rand_fd = rand_fd; /* for compiler */ | 46 | int rand_fd = rand_fd; /* for compiler */ |
45 | int zero_fd; | 47 | int zero_fd; |
46 | unsigned num_iter = 3; | 48 | unsigned num_iter = 3; |
@@ -52,18 +54,16 @@ int shred_main(int argc UNUSED_PARAM, char **argv) | |||
52 | OPT_n = (1 << 3), | 54 | OPT_n = (1 << 3), |
53 | OPT_v = (1 << 4), | 55 | OPT_v = (1 << 4), |
54 | OPT_x = (1 << 5), | 56 | OPT_x = (1 << 5), |
57 | OPT_s = (1 << 6), | ||
55 | }; | 58 | }; |
56 | 59 | ||
57 | opt = getopt32(argv, "fuzn:+vx", &num_iter); | 60 | opt = getopt32(argv, "^" "fuzn:+vxs:" "\0" "-1"/*min 1 arg*/, &num_iter, &opt_s); |
58 | argv += optind; | 61 | argv += optind; |
59 | 62 | ||
60 | zero_fd = MINGW_SPECIAL(xopen)("/dev/zero", O_RDONLY); | 63 | zero_fd = MINGW_SPECIAL(xopen)("/dev/zero", O_RDONLY); |
61 | if (num_iter != 0) | 64 | if (num_iter != 0) |
62 | rand_fd = MINGW_SPECIAL(xopen)("/dev/urandom", O_RDONLY); | 65 | rand_fd = MINGW_SPECIAL(xopen)("/dev/urandom", O_RDONLY); |
63 | 66 | ||
64 | if (!*argv) | ||
65 | bb_show_usage(); | ||
66 | |||
67 | for (;;) { | 67 | for (;;) { |
68 | struct stat sb; | 68 | struct stat sb; |
69 | const char *fname; | 69 | const char *fname; |
@@ -85,6 +85,11 @@ int shred_main(int argc UNUSED_PARAM, char **argv) | |||
85 | if (fstat(fd, &sb) == 0 && sb.st_size > 0) { | 85 | if (fstat(fd, &sb) == 0 && sb.st_size > 0) { |
86 | off_t size = sb.st_size; | 86 | off_t size = sb.st_size; |
87 | 87 | ||
88 | if (opt & OPT_s) { | ||
89 | size = BB_STRTOOFF(opt_s, NULL, 0); /* accepts oct/hex */ | ||
90 | if (errno || size < 0) bb_show_usage(); | ||
91 | } | ||
92 | |||
88 | for (i = 0; i < num_iter; i++) { | 93 | for (i = 0; i < num_iter; i++) { |
89 | bb_copyfd_size(rand_fd, fd, size); | 94 | bb_copyfd_size(rand_fd, fd, size); |
90 | fdatasync(fd); | 95 | fdatasync(fd); |
@@ -94,18 +99,18 @@ int shred_main(int argc UNUSED_PARAM, char **argv) | |||
94 | bb_copyfd_size(zero_fd, fd, size); | 99 | bb_copyfd_size(zero_fd, fd, size); |
95 | fdatasync(fd); | 100 | fdatasync(fd); |
96 | } | 101 | } |
97 | if (opt & OPT_u) { | 102 | } |
98 | ftruncate(fd, 0); | 103 | if (opt & OPT_u) { |
104 | ftruncate(fd, 0); | ||
99 | #if ENABLE_PLATFORM_MINGW32 | 105 | #if ENABLE_PLATFORM_MINGW32 |
100 | xclose(fd); | 106 | xclose(fd); |
101 | #endif | 107 | #endif |
102 | xunlink(fname); | 108 | xunlink(fname); |
103 | } | 109 | } |
104 | #if ENABLE_PLATFORM_MINGW32 | 110 | #if ENABLE_PLATFORM_MINGW32 |
105 | else | 111 | else |
106 | #endif | 112 | #endif |
107 | xclose(fd); | 113 | xclose(fd); |
108 | } | ||
109 | } | 114 | } |
110 | 115 | ||
111 | return EXIT_SUCCESS; | 116 | return EXIT_SUCCESS; |
diff --git a/coreutils/sort.c b/coreutils/sort.c index 6c4e3038c..32a06e40a 100644 --- a/coreutils/sort.c +++ b/coreutils/sort.c | |||
@@ -67,7 +67,7 @@ | |||
67 | //usage: "\n -r Reverse sort order" | 67 | //usage: "\n -r Reverse sort order" |
68 | //usage: "\n -s Stable (don't sort ties alphabetically)" | 68 | //usage: "\n -s Stable (don't sort ties alphabetically)" |
69 | //usage: "\n -u Suppress duplicate lines" | 69 | //usage: "\n -u Suppress duplicate lines" |
70 | //usage: "\n -z Lines are terminated by NUL, not newline" | 70 | //usage: "\n -z NUL terminated input and output" |
71 | ///////: "\n -m Ignored for GNU compatibility" | 71 | ///////: "\n -m Ignored for GNU compatibility" |
72 | ///////: "\n -S BUFSZ Ignored for GNU compatibility" | 72 | ///////: "\n -S BUFSZ Ignored for GNU compatibility" |
73 | ///////: "\n -T TMPDIR Ignored for GNU compatibility" | 73 | ///////: "\n -T TMPDIR Ignored for GNU compatibility" |
diff --git a/coreutils/touch.c b/coreutils/touch.c index 2b225dd16..ec12eb7cf 100644 --- a/coreutils/touch.c +++ b/coreutils/touch.c | |||
@@ -31,7 +31,7 @@ | |||
31 | //kbuild:lib-$(CONFIG_TOUCH) += touch.o | 31 | //kbuild:lib-$(CONFIG_TOUCH) += touch.o |
32 | 32 | ||
33 | //usage:#define touch_trivial_usage | 33 | //usage:#define touch_trivial_usage |
34 | //usage: "[-c" IF_FEATURE_TOUCH_SUSV3("am") "]" | 34 | //usage: "[-ch" IF_FEATURE_TOUCH_SUSV3("am") "]" |
35 | //usage: IF_FEATURE_TOUCH_SUSV3(" [-d DATE] [-t DATE] [-r FILE]") | 35 | //usage: IF_FEATURE_TOUCH_SUSV3(" [-d DATE] [-t DATE] [-r FILE]") |
36 | //usage: " FILE..." | 36 | //usage: " FILE..." |
37 | //usage:#define touch_full_usage "\n\n" | 37 | //usage:#define touch_full_usage "\n\n" |
diff --git a/coreutils/tty.c b/coreutils/tty.c index ff6f2bb3b..e448c27ec 100644 --- a/coreutils/tty.c +++ b/coreutils/tty.c | |||
@@ -21,7 +21,7 @@ | |||
21 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/tty.html */ | 21 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/tty.html */ |
22 | 22 | ||
23 | //usage:#define tty_trivial_usage | 23 | //usage:#define tty_trivial_usage |
24 | //usage: "" | 24 | //usage: "" IF_INCLUDE_SUSv2("[-s]") |
25 | //usage:#define tty_full_usage "\n\n" | 25 | //usage:#define tty_full_usage "\n\n" |
26 | //usage: "Print file name of stdin's terminal" | 26 | //usage: "Print file name of stdin's terminal" |
27 | //usage: IF_INCLUDE_SUSv2( "\n" | 27 | //usage: IF_INCLUDE_SUSv2( "\n" |
diff --git a/coreutils/uname.c b/coreutils/uname.c index 2a1602b4c..da785ab4c 100644 --- a/coreutils/uname.c +++ b/coreutils/uname.c | |||
@@ -79,13 +79,13 @@ | |||
79 | //usage:#define uname_full_usage "\n\n" | 79 | //usage:#define uname_full_usage "\n\n" |
80 | //usage: "Print system information\n" | 80 | //usage: "Print system information\n" |
81 | //usage: "\n -a Print all" | 81 | //usage: "\n -a Print all" |
82 | //usage: "\n -m The machine (hardware) type" | 82 | //usage: "\n -m Machine (hardware) type" |
83 | //usage: "\n -n Hostname" | 83 | //usage: "\n -n Hostname" |
84 | //usage: "\n -r Kernel release" | 84 | //usage: "\n -r Kernel release" |
85 | //usage: "\n -s Kernel name (default)" | 85 | //usage: "\n -s Kernel name (default)" |
86 | //usage: "\n -p Processor type" | 86 | //usage: "\n -p Processor type" |
87 | //usage: "\n -v Kernel version" | 87 | //usage: "\n -v Kernel version" |
88 | //usage: "\n -i The hardware platform" | 88 | //usage: "\n -i Hardware platform" |
89 | //usage: "\n -o OS name" | 89 | //usage: "\n -o OS name" |
90 | //usage: | 90 | //usage: |
91 | //usage:#define uname_example_usage | 91 | //usage:#define uname_example_usage |
diff --git a/coreutils/uniq.c b/coreutils/uniq.c index e1594286f..a3058ac07 100644 --- a/coreutils/uniq.c +++ b/coreutils/uniq.c | |||
@@ -20,13 +20,14 @@ | |||
20 | /* http://www.opengroup.org/onlinepubs/007904975/utilities/uniq.html */ | 20 | /* http://www.opengroup.org/onlinepubs/007904975/utilities/uniq.html */ |
21 | 21 | ||
22 | //usage:#define uniq_trivial_usage | 22 | //usage:#define uniq_trivial_usage |
23 | //usage: "[-cdui] [-f,s,w N] [INPUT [OUTPUT]]" | 23 | //usage: "[-cduiz] [-f,s,w N] [FILE [OUTFILE]]" |
24 | //usage:#define uniq_full_usage "\n\n" | 24 | //usage:#define uniq_full_usage "\n\n" |
25 | //usage: "Discard duplicate lines\n" | 25 | //usage: "Discard duplicate lines\n" |
26 | //usage: "\n -c Prefix lines by the number of occurrences" | 26 | //usage: "\n -c Prefix lines by the number of occurrences" |
27 | //usage: "\n -d Only print duplicate lines" | 27 | //usage: "\n -d Only print duplicate lines" |
28 | //usage: "\n -u Only print unique lines" | 28 | //usage: "\n -u Only print unique lines" |
29 | //usage: "\n -i Ignore case" | 29 | //usage: "\n -i Ignore case" |
30 | //usage: "\n -z NUL terminated output" | ||
30 | //usage: "\n -f N Skip first N fields" | 31 | //usage: "\n -f N Skip first N fields" |
31 | //usage: "\n -s N Skip first N chars (after any skipped fields)" | 32 | //usage: "\n -s N Skip first N chars (after any skipped fields)" |
32 | //usage: "\n -w N Compare N characters in line" | 33 | //usage: "\n -w N Compare N characters in line" |
@@ -45,23 +46,25 @@ int uniq_main(int argc UNUSED_PARAM, char **argv) | |||
45 | const char *input_filename; | 46 | const char *input_filename; |
46 | unsigned skip_fields, skip_chars, max_chars; | 47 | unsigned skip_fields, skip_chars, max_chars; |
47 | unsigned opt; | 48 | unsigned opt; |
49 | char eol; | ||
48 | char *cur_line; | 50 | char *cur_line; |
49 | const char *cur_compare; | 51 | const char *cur_compare; |
50 | 52 | ||
51 | enum { | 53 | enum { |
52 | OPT_c = 0x1, | 54 | OPT_c = 1 << 0, |
53 | OPT_d = 0x2, /* print only dups */ | 55 | OPT_d = 1 << 1, /* print only dups */ |
54 | OPT_u = 0x4, /* print only uniq */ | 56 | OPT_u = 1 << 2, /* print only uniq */ |
55 | OPT_f = 0x8, | 57 | OPT_f = 1 << 3, |
56 | OPT_s = 0x10, | 58 | OPT_s = 1 << 4, |
57 | OPT_w = 0x20, | 59 | OPT_w = 1 << 5, |
58 | OPT_i = 0x40, | 60 | OPT_i = 1 << 6, |
61 | OPT_z = 1 << 7, | ||
59 | }; | 62 | }; |
60 | 63 | ||
61 | skip_fields = skip_chars = 0; | 64 | skip_fields = skip_chars = 0; |
62 | max_chars = INT_MAX; | 65 | max_chars = INT_MAX; |
63 | 66 | ||
64 | opt = getopt32(argv, "cduf:+s:+w:+i", &skip_fields, &skip_chars, &max_chars); | 67 | opt = getopt32(argv, "cduf:+s:+w:+iz", &skip_fields, &skip_chars, &max_chars); |
65 | argv += optind; | 68 | argv += optind; |
66 | 69 | ||
67 | input_filename = argv[0]; | 70 | input_filename = argv[0]; |
@@ -86,6 +89,7 @@ int uniq_main(int argc UNUSED_PARAM, char **argv) | |||
86 | } | 89 | } |
87 | 90 | ||
88 | cur_compare = cur_line = NULL; /* prime the pump */ | 91 | cur_compare = cur_line = NULL; /* prime the pump */ |
92 | eol = (opt & OPT_z) ? 0 : '\n'; | ||
89 | 93 | ||
90 | do { | 94 | do { |
91 | unsigned i; | 95 | unsigned i; |
@@ -127,7 +131,7 @@ int uniq_main(int argc UNUSED_PARAM, char **argv) | |||
127 | /* %7lu matches GNU coreutils 6.9 */ | 131 | /* %7lu matches GNU coreutils 6.9 */ |
128 | printf("%7lu ", dups + 1); | 132 | printf("%7lu ", dups + 1); |
129 | } | 133 | } |
130 | puts(old_line); | 134 | printf("%s%c", old_line, eol); |
131 | } | 135 | } |
132 | free(old_line); | 136 | free(old_line); |
133 | } | 137 | } |
diff --git a/coreutils/uudecode.c b/coreutils/uudecode.c index 02b037276..a607977e9 100644 --- a/coreutils/uudecode.c +++ b/coreutils/uudecode.c | |||
@@ -183,7 +183,7 @@ int uudecode_main(int argc UNUSED_PARAM, char **argv) | |||
183 | //usage:#define base32_trivial_usage | 183 | //usage:#define base32_trivial_usage |
184 | //usage: "[-d] [-w COL] [FILE]" | 184 | //usage: "[-d] [-w COL] [FILE]" |
185 | //usage:#define base32_full_usage "\n\n" | 185 | //usage:#define base32_full_usage "\n\n" |
186 | //usage: "Base32 encode or decode FILE to standard output" | 186 | //usage: "Base32 encode or decode FILE to standard output\n" |
187 | //usage: "\n -d Decode data" | 187 | //usage: "\n -d Decode data" |
188 | //usage: "\n -w COL Wrap lines at COL (default 76, 0 disables)" | 188 | //usage: "\n -w COL Wrap lines at COL (default 76, 0 disables)" |
189 | ////usage: "\n -i When decoding, ignore non-alphabet characters" | 189 | ////usage: "\n -i When decoding, ignore non-alphabet characters" |
@@ -191,10 +191,12 @@ int uudecode_main(int argc UNUSED_PARAM, char **argv) | |||
191 | //usage:#define base64_trivial_usage | 191 | //usage:#define base64_trivial_usage |
192 | //usage: "[-d] [-w COL] [FILE]" | 192 | //usage: "[-d] [-w COL] [FILE]" |
193 | //usage:#define base64_full_usage "\n\n" | 193 | //usage:#define base64_full_usage "\n\n" |
194 | //usage: "Base64 encode or decode FILE to standard output" | 194 | //usage: "Base64 encode or decode FILE to standard output\n" |
195 | //usage: "\n -d Decode data" | 195 | //usage: "\n -d Decode data" |
196 | //usage: "\n -w COL Wrap lines at COL (default 76, 0 disables)" | 196 | //usage: "\n -w COL Wrap lines at COL (default 76, 0 disables)" |
197 | ////usage: "\n -i When decoding, ignore non-alphabet characters" | 197 | ///////: "\n -i When decoding, ignore non-alphabet characters" |
198 | // -i is accepted but has no effect: currently, decode_base32/64() functions | ||
199 | // (called via read_base64()) skip invalid chars unconditionally. | ||
198 | 200 | ||
199 | // APPLET_ODDNAME:name main location suid_type help | 201 | // APPLET_ODDNAME:name main location suid_type help |
200 | //applet:IF_BASE32(APPLET_ODDNAME(base32, baseNUM, BB_DIR_BIN, BB_SUID_DROP, base32)) | 202 | //applet:IF_BASE32(APPLET_ODDNAME(base32, baseNUM, BB_DIR_BIN, BB_SUID_DROP, base32)) |
@@ -272,7 +274,7 @@ int baseNUM_main(int argc UNUSED_PARAM, char **argv) | |||
272 | unsigned opts; | 274 | unsigned opts; |
273 | unsigned col = 76; | 275 | unsigned col = 76; |
274 | 276 | ||
275 | opts = getopt32(argv, "^" "dw:+" "\0" "?1"/* 1 arg max*/, &col); | 277 | opts = getopt32(argv, "^" "diw:+" "\0" "?1"/* 1 arg max*/, &col); |
276 | argv += optind; | 278 | argv += optind; |
277 | 279 | ||
278 | if (!argv[0]) | 280 | if (!argv[0]) |
diff --git a/coreutils/who.c b/coreutils/who.c index be9c3ccca..3725d77f5 100644 --- a/coreutils/who.c +++ b/coreutils/who.c | |||
@@ -78,7 +78,7 @@ | |||
78 | // root pts/1 Mon13 3:24m 1:01 0.01s w | 78 | // root pts/1 Mon13 3:24m 1:01 0.01s w |
79 | 79 | ||
80 | //usage:#define who_trivial_usage | 80 | //usage:#define who_trivial_usage |
81 | //usage: "[-a]" | 81 | //usage: "[-aH]" |
82 | //usage:#define who_full_usage "\n\n" | 82 | //usage:#define who_full_usage "\n\n" |
83 | //usage: "Show who is logged on\n" | 83 | //usage: "Show who is logged on\n" |
84 | //usage: "\n -a Show all" | 84 | //usage: "\n -a Show all" |
diff --git a/coreutils/yes.c b/coreutils/yes.c index 38ffff46c..64dfa500c 100644 --- a/coreutils/yes.c +++ b/coreutils/yes.c | |||
@@ -27,7 +27,7 @@ | |||
27 | //usage:#define yes_trivial_usage | 27 | //usage:#define yes_trivial_usage |
28 | //usage: "[STRING]" | 28 | //usage: "[STRING]" |
29 | //usage:#define yes_full_usage "\n\n" | 29 | //usage:#define yes_full_usage "\n\n" |
30 | //usage: "Repeatedly output a line with STRING, or 'y'" | 30 | //usage: "Repeatedly print a line with STRING, or 'y'" |
31 | 31 | ||
32 | #include "libbb.h" | 32 | #include "libbb.h" |
33 | 33 | ||
diff --git a/docs/busybox_footer.pod b/docs/busybox_footer.pod index 92748eb72..0f4810bd3 100644 --- a/docs/busybox_footer.pod +++ b/docs/busybox_footer.pod | |||
@@ -37,6 +37,7 @@ incorrect, please send in an update. | |||
37 | =for html <br> | 37 | =for html <br> |
38 | 38 | ||
39 | Emanuele Aina <emanuele.aina@tiscali.it> | 39 | Emanuele Aina <emanuele.aina@tiscali.it> |
40 | |||
40 | run-parts | 41 | run-parts |
41 | 42 | ||
42 | =for html <br> | 43 | =for html <br> |
diff --git a/e2fsprogs/chattr.c b/e2fsprogs/chattr.c index e1a798727..c1e90d13f 100644 --- a/e2fsprogs/chattr.c +++ b/e2fsprogs/chattr.c | |||
@@ -21,7 +21,7 @@ | |||
21 | 21 | ||
22 | //usage:#define chattr_trivial_usage | 22 | //usage:#define chattr_trivial_usage |
23 | //usage: IF_NOT_PLATFORM_MINGW32( | 23 | //usage: IF_NOT_PLATFORM_MINGW32( |
24 | //usage: "[-R] [-v VERSION] [-+=AacDdijsStTu] FILE..." | 24 | //usage: "[-R] [-v VERSION] [-p PROJID] [-+=AacDdijsStTu] FILE..." |
25 | //usage: ) | 25 | //usage: ) |
26 | //usage: IF_PLATFORM_MINGW32( | 26 | //usage: IF_PLATFORM_MINGW32( |
27 | //usage: "[-R] [-+rhsatn] FILE..." | 27 | //usage: "[-R] [-+rhsatn] FILE..." |
@@ -35,24 +35,34 @@ | |||
35 | //usage: ) | 35 | //usage: ) |
36 | //usage: "\n -R Recurse" | 36 | //usage: "\n -R Recurse" |
37 | //usage: IF_NOT_PLATFORM_MINGW32( | 37 | //usage: IF_NOT_PLATFORM_MINGW32( |
38 | //usage: "\n -v VER Set version/generation number" | 38 | //usage: "\n -v NUM Set version/generation number" |
39 | //usage: "\n -p NUM Set project number" | ||
39 | //usage: ) | 40 | //usage: ) |
40 | //-V, -f accepted but ignored | 41 | //-V, -f accepted but ignored |
41 | //usage: "\nModifiers:" | 42 | //usage: "\nModifiers:" |
42 | //usage: IF_NOT_PLATFORM_MINGW32( | 43 | //usage: IF_NOT_PLATFORM_MINGW32( |
43 | //usage: "\n -,+,= Remove/add/set attributes" | 44 | //usage: "\n -,+,= Remove/add/set attributes" |
44 | //usage: "\nAttributes:" | 45 | //usage: "\nAttributes:" |
45 | //usage: "\n A Don't track atime" | 46 | //usage: "\n A No atime" |
46 | //usage: "\n a Append mode only" | 47 | //usage: "\n a Append only" |
47 | //usage: "\n c Enable compress" | 48 | //usage: "\n C No copy-on-write" |
48 | //usage: "\n D Write dir contents synchronously" | 49 | //usage: "\n c Compressed" |
50 | //usage: "\n D Synchronous dir updates" | ||
49 | //usage: "\n d Don't backup with dump" | 51 | //usage: "\n d Don't backup with dump" |
50 | //usage: "\n i Cannot be modified (immutable)" | 52 | //usage: "\n E Encrypted" |
51 | //usage: "\n j Write all data to journal first" | 53 | //usage: "\n e File uses extents" |
52 | //usage: "\n s Zero disk storage when deleted" | 54 | //usage: "\n F Case-insensitive dir" |
53 | //usage: "\n S Write synchronously" | 55 | //usage: "\n I Indexed dir" |
54 | //usage: "\n t Disable tail-merging of partial blocks with other files" | 56 | //usage: "\n i Immutable" |
55 | //usage: "\n u Allow file to be undeleted" | 57 | //usage: "\n j Write data to journal first" |
58 | //usage: "\n N File is stored in inode" | ||
59 | //usage: "\n P Hierarchical project ID dir" | ||
60 | //usage: "\n S Synchronous file updates" | ||
61 | //usage: "\n s Zero storage when deleted" | ||
62 | //usage: "\n T Top of dir hierarchy" | ||
63 | //usage: "\n t Don't tail-merge with other files" | ||
64 | //usage: "\n u Allow undelete" | ||
65 | //usage: "\n V Verity" | ||
56 | //usage: ) | 66 | //usage: ) |
57 | //usage: IF_PLATFORM_MINGW32( | 67 | //usage: IF_PLATFORM_MINGW32( |
58 | //usage: "\n -,+ Remove/add attributes" | 68 | //usage: "\n -,+ Remove/add attributes" |
@@ -68,18 +78,22 @@ | |||
68 | #include "libbb.h" | 78 | #include "libbb.h" |
69 | #include "e2fs_lib.h" | 79 | #include "e2fs_lib.h" |
70 | 80 | ||
71 | #define OPT_ADD 1 | 81 | #define OPT_ADD (1 << 0) |
72 | #define OPT_REM 2 | 82 | #define OPT_REM (1 << 1) |
73 | #define OPT_SET 4 | 83 | #define OPT_SET (1 << 2) |
74 | #define OPT_SET_VER 8 | 84 | #define OPT_SET_VER (1 << 3) |
85 | #define OPT_SET_PROJ (1 << 4) | ||
75 | 86 | ||
76 | struct globals { | 87 | struct globals { |
77 | #if !ENABLE_PLATFORM_MINGW32 | 88 | #if !ENABLE_PLATFORM_MINGW32 |
78 | unsigned long version; | 89 | unsigned version; |
79 | #endif | 90 | #endif |
80 | unsigned long af; | 91 | unsigned af; |
81 | unsigned long rf; | 92 | unsigned rf; |
82 | int flags; | 93 | int flags; |
94 | #if !ENABLE_PLATFORM_MINGW32 | ||
95 | uint32_t projid; | ||
96 | #endif | ||
83 | smallint recursive; | 97 | smallint recursive; |
84 | }; | 98 | }; |
85 | 99 | ||
@@ -93,13 +107,15 @@ static unsigned long get_flag(char c) | |||
93 | 107 | ||
94 | static char** decode_arg(char **argv, struct globals *gp) | 108 | static char** decode_arg(char **argv, struct globals *gp) |
95 | { | 109 | { |
96 | unsigned long *fl; | 110 | unsigned *fl; |
97 | const char *arg = *argv; | 111 | const char *arg = *argv; |
98 | char opt = *arg; | 112 | char opt = *arg; |
99 | 113 | ||
100 | fl = &gp->af; | 114 | fl = &gp->af; |
101 | if (opt == '-') { | 115 | if (opt == '-') { |
102 | gp->flags |= OPT_REM; | 116 | /* gp->flags |= OPT_REM; - WRONG, it can be an option */ |
117 | /* testcase: chattr =ae -R FILE should not complain "= is incompatible with - and +" */ | ||
118 | /* (and should not read flags, with =FLAGS they can be just set directly) */ | ||
103 | fl = &gp->rf; | 119 | fl = &gp->rf; |
104 | #if ENABLE_PLATFORM_MINGW32 | 120 | #if ENABLE_PLATFORM_MINGW32 |
105 | } else { /* if (opt == '+') */ | 121 | } else { /* if (opt == '+') */ |
@@ -136,15 +152,22 @@ static char** decode_arg(char **argv, struct globals *gp) | |||
136 | if (*arg == 'v') { | 152 | if (*arg == 'v') { |
137 | if (!*++argv) | 153 | if (!*++argv) |
138 | bb_show_usage(); | 154 | bb_show_usage(); |
139 | gp->version = xatoul(*argv); | 155 | gp->version = xatou(*argv); |
140 | gp->flags |= OPT_SET_VER; | 156 | gp->flags |= OPT_SET_VER; |
141 | continue; | 157 | continue; |
142 | } | 158 | } |
143 | //TODO: "-p PROJECT_NUM" ? | 159 | if (*arg == 'p') { |
160 | if (!*++argv) | ||
161 | bb_show_usage(); | ||
162 | gp->projid = xatou32(*argv); | ||
163 | gp->flags |= OPT_SET_PROJ; | ||
164 | continue; | ||
165 | } | ||
144 | #endif | 166 | #endif |
145 | /* not a known option, try as an attribute */ | 167 | /* not a known option, try as an attribute */ |
168 | gp->flags |= OPT_REM; | ||
146 | } | 169 | } |
147 | *fl |= get_flag(*arg); | 170 | *fl |= get_flag(*arg); /* aborts on bad flag letter */ |
148 | } | 171 | } |
149 | 172 | ||
150 | return argv; | 173 | return argv; |
@@ -154,6 +177,8 @@ static void change_attributes(const char *name, struct globals *gp); | |||
154 | 177 | ||
155 | static int FAST_FUNC chattr_dir_proc(const char *dir_name, struct dirent *de, void *gp) | 178 | static int FAST_FUNC chattr_dir_proc(const char *dir_name, struct dirent *de, void *gp) |
156 | { | 179 | { |
180 | //TODO: use de->d_type (if it's not DT_UNKNOWN) to skip !(REG || DIR || LNK) entries without lstat? | ||
181 | |||
157 | char *path = concat_subpath_file(dir_name, de->d_name); | 182 | char *path = concat_subpath_file(dir_name, de->d_name); |
158 | /* path is NULL if de->d_name is "." or "..", else... */ | 183 | /* path is NULL if de->d_name is "." or "..", else... */ |
159 | if (path) { | 184 | if (path) { |
@@ -165,15 +190,16 @@ static int FAST_FUNC chattr_dir_proc(const char *dir_name, struct dirent *de, vo | |||
165 | 190 | ||
166 | static void change_attributes(const char *name, struct globals *gp) | 191 | static void change_attributes(const char *name, struct globals *gp) |
167 | { | 192 | { |
168 | unsigned long fsflags; | 193 | unsigned fsflags; |
194 | #if !ENABLE_PLATFORM_MINGW32 | ||
195 | int fd; | ||
196 | #endif | ||
169 | struct stat st; | 197 | struct stat st; |
170 | 198 | ||
171 | if (lstat(name, &st) != 0) { | 199 | if (lstat(name, &st) != 0) { |
172 | bb_perror_msg("stat %s", name); | 200 | bb_perror_msg("can't stat '%s'", name); |
173 | return; | 201 | return; |
174 | } | 202 | } |
175 | if (S_ISLNK(st.st_mode) && gp->recursive) | ||
176 | return; | ||
177 | 203 | ||
178 | /* Don't try to open device files, fifos etc. We probably | 204 | /* Don't try to open device files, fifos etc. We probably |
179 | * ought to display an error if the file was explicitly given | 205 | * ought to display an error if the file was explicitly given |
@@ -183,11 +209,58 @@ static void change_attributes(const char *name, struct globals *gp) | |||
183 | return; | 209 | return; |
184 | 210 | ||
185 | #if !ENABLE_PLATFORM_MINGW32 | 211 | #if !ENABLE_PLATFORM_MINGW32 |
186 | if (gp->flags & OPT_SET_VER) | 212 | /* There is no way to run needed ioctls on a symlink. |
187 | if (fsetversion(name, gp->version) != 0) | 213 | * open(O_PATH | O_NOFOLLOW) _can_ be used to get a fd referring to the symlink, |
188 | bb_perror_msg("setting version on %s", name); | 214 | * but ioctls fail on such a fd (tried on 4.12.0 kernel). |
189 | #endif | 215 | * e2fsprogs-1.46.2 uses open(O_NOFOLLOW), it fails on symlinks. |
216 | */ | ||
217 | fd = open_or_warn(name, O_RDONLY | O_NONBLOCK | O_NOCTTY | O_NOFOLLOW); | ||
218 | if (fd >= 0) { | ||
219 | int r; | ||
220 | |||
221 | if (gp->flags & OPT_SET_VER) { | ||
222 | r = ioctl(fd, EXT2_IOC_SETVERSION, &gp->version); | ||
223 | if (r != 0) | ||
224 | bb_perror_msg("setting %s on %s", "version", name); | ||
225 | } | ||
190 | 226 | ||
227 | if (gp->flags & OPT_SET_PROJ) { | ||
228 | struct ext2_fsxattr fsxattr; | ||
229 | r = ioctl(fd, EXT2_IOC_FSGETXATTR, &fsxattr); | ||
230 | /* note: ^^^ may fail in 32-bit userspace on 64-bit kernel (seen on 4.12.0) */ | ||
231 | if (r != 0) { | ||
232 | bb_perror_msg("getting %s on %s", "project ID", name); | ||
233 | } else { | ||
234 | fsxattr.fsx_projid = gp->projid; | ||
235 | r = ioctl(fd, EXT2_IOC_FSSETXATTR, &fsxattr); | ||
236 | if (r != 0) | ||
237 | bb_perror_msg("setting %s on %s", "project ID", name); | ||
238 | } | ||
239 | } | ||
240 | |||
241 | if (gp->flags & OPT_SET) { | ||
242 | fsflags = gp->af; | ||
243 | } else { | ||
244 | r = ioctl(fd, EXT2_IOC_GETFLAGS, &fsflags); | ||
245 | if (r != 0) { | ||
246 | bb_perror_msg("getting %s on %s", "flags", name); | ||
247 | goto skip_setflags; | ||
248 | } | ||
249 | /*if (gp->flags & OPT_REM) - not needed, rf is zero otherwise */ | ||
250 | fsflags &= ~gp->rf; | ||
251 | /*if (gp->flags & OPT_ADD) - not needed, af is zero otherwise */ | ||
252 | fsflags |= gp->af; | ||
253 | // What is this? And why it's not done for SET case? | ||
254 | if (!S_ISDIR(st.st_mode)) | ||
255 | fsflags &= ~EXT2_DIRSYNC_FL; | ||
256 | } | ||
257 | r = ioctl(fd, EXT2_IOC_SETFLAGS, &fsflags); | ||
258 | if (r != 0) | ||
259 | bb_perror_msg("setting %s on %s", "flags", name); | ||
260 | skip_setflags: | ||
261 | close(fd); | ||
262 | } | ||
263 | #else /* ENABLE_PLATFORM_MINGW32 */ | ||
191 | if (gp->flags & OPT_SET) { | 264 | if (gp->flags & OPT_SET) { |
192 | fsflags = gp->af; | 265 | fsflags = gp->af; |
193 | } else { | 266 | } else { |
@@ -199,16 +272,13 @@ static void change_attributes(const char *name, struct globals *gp) | |||
199 | fsflags &= ~gp->rf; | 272 | fsflags &= ~gp->rf; |
200 | /*if (gp->flags & OPT_ADD) - not needed, af is zero otherwise */ | 273 | /*if (gp->flags & OPT_ADD) - not needed, af is zero otherwise */ |
201 | fsflags |= gp->af; | 274 | fsflags |= gp->af; |
202 | #if !ENABLE_PLATFORM_MINGW32 | ||
203 | // What is this? And why it's not done for SET case? | ||
204 | if (!S_ISDIR(st.st_mode)) | ||
205 | fsflags &= ~EXT2_DIRSYNC_FL; | ||
206 | #endif | ||
207 | } | 275 | } |
208 | if (fsetflags(name, fsflags) != 0) | 276 | if (fsetflags(name, fsflags) != 0) |
209 | bb_perror_msg("setting flags on %s", name); | 277 | bb_perror_msg("setting flags on %s", name); |
210 | 278 | ||
211 | skip_setflags: | 279 | skip_setflags: |
280 | #endif | ||
281 | |||
212 | if (gp->recursive && S_ISDIR(st.st_mode)) | 282 | if (gp->recursive && S_ISDIR(st.st_mode)) |
213 | iterate_on_dir(name, chattr_dir_proc, gp); | 283 | iterate_on_dir(name, chattr_dir_proc, gp); |
214 | } | 284 | } |
@@ -245,7 +315,7 @@ int chattr_main(int argc UNUSED_PARAM, char **argv) | |||
245 | #if ENABLE_PLATFORM_MINGW32 | 315 | #if ENABLE_PLATFORM_MINGW32 |
246 | bb_simple_error_msg_and_die("must use - or +"); | 316 | bb_simple_error_msg_and_die("must use - or +"); |
247 | #else | 317 | #else |
248 | bb_simple_error_msg_and_die("must use '-v', =, - or +"); | 318 | bb_simple_error_msg_and_die("must use -v, -p, =, - or +"); |
249 | #endif | 319 | #endif |
250 | 320 | ||
251 | /* now run chattr on all the files passed to us */ | 321 | /* now run chattr on all the files passed to us */ |
diff --git a/e2fsprogs/e2fs_lib.c b/e2fsprogs/e2fs_lib.c index d0cacf14c..48c3b68b5 100644 --- a/e2fsprogs/e2fs_lib.c +++ b/e2fsprogs/e2fs_lib.c | |||
@@ -8,125 +8,7 @@ | |||
8 | #include "libbb.h" | 8 | #include "libbb.h" |
9 | #include "e2fs_lib.h" | 9 | #include "e2fs_lib.h" |
10 | 10 | ||
11 | #if !ENABLE_PLATFORM_MINGW32 | 11 | #if ENABLE_PLATFORM_MINGW32 |
12 | #define HAVE_EXT2_IOCTLS 1 | ||
13 | |||
14 | #if INT_MAX == LONG_MAX | ||
15 | #define IF_LONG_IS_SAME(...) __VA_ARGS__ | ||
16 | #define IF_LONG_IS_WIDER(...) | ||
17 | #else | ||
18 | #define IF_LONG_IS_SAME(...) | ||
19 | #define IF_LONG_IS_WIDER(...) __VA_ARGS__ | ||
20 | #endif | ||
21 | |||
22 | static void close_silently(int fd) | ||
23 | { | ||
24 | int e = errno; | ||
25 | close(fd); | ||
26 | errno = e; | ||
27 | } | ||
28 | #endif | ||
29 | |||
30 | |||
31 | /* Iterate a function on each entry of a directory */ | ||
32 | int iterate_on_dir(const char *dir_name, | ||
33 | int FAST_FUNC (*func)(const char *, struct dirent *, void *), | ||
34 | void *private) | ||
35 | { | ||
36 | DIR *dir; | ||
37 | struct dirent *de; | ||
38 | |||
39 | dir = opendir(dir_name); | ||
40 | if (dir == NULL) { | ||
41 | return -1; | ||
42 | } | ||
43 | while ((de = readdir(dir)) != NULL) { | ||
44 | func(dir_name, de, private); | ||
45 | } | ||
46 | closedir(dir); | ||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | |||
51 | #if !ENABLE_PLATFORM_MINGW32 | ||
52 | /* Get/set a file version on an ext2 file system */ | ||
53 | int fgetsetversion(const char *name, unsigned long *get_version, unsigned long set_version) | ||
54 | { | ||
55 | #if HAVE_EXT2_IOCTLS | ||
56 | int fd, r; | ||
57 | IF_LONG_IS_WIDER(int ver;) | ||
58 | |||
59 | fd = open(name, O_RDONLY | O_NONBLOCK); | ||
60 | if (fd == -1) | ||
61 | return -1; | ||
62 | if (!get_version) { | ||
63 | IF_LONG_IS_WIDER( | ||
64 | ver = (int) set_version; | ||
65 | r = ioctl(fd, EXT2_IOC_SETVERSION, &ver); | ||
66 | ) | ||
67 | IF_LONG_IS_SAME( | ||
68 | r = ioctl(fd, EXT2_IOC_SETVERSION, (void*)&set_version); | ||
69 | ) | ||
70 | } else { | ||
71 | IF_LONG_IS_WIDER( | ||
72 | r = ioctl(fd, EXT2_IOC_GETVERSION, &ver); | ||
73 | *get_version = ver; | ||
74 | ) | ||
75 | IF_LONG_IS_SAME( | ||
76 | r = ioctl(fd, EXT2_IOC_GETVERSION, (void*)get_version); | ||
77 | ) | ||
78 | } | ||
79 | close_silently(fd); | ||
80 | return r; | ||
81 | #else /* ! HAVE_EXT2_IOCTLS */ | ||
82 | errno = EOPNOTSUPP; | ||
83 | return -1; | ||
84 | #endif /* ! HAVE_EXT2_IOCTLS */ | ||
85 | } | ||
86 | |||
87 | /* Get/set a file flags on an ext2 file system */ | ||
88 | int fgetsetflags(const char *name, unsigned long *get_flags, unsigned long set_flags) | ||
89 | { | ||
90 | #if HAVE_EXT2_IOCTLS | ||
91 | struct stat buf; | ||
92 | int fd, r; | ||
93 | IF_LONG_IS_WIDER(int f;) | ||
94 | |||
95 | if (stat(name, &buf) == 0 /* stat is ok */ | ||
96 | && !S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode) | ||
97 | ) { | ||
98 | goto notsupp; | ||
99 | } | ||
100 | fd = open(name, O_RDONLY | O_NONBLOCK); /* neither read nor write asked for */ | ||
101 | if (fd == -1) | ||
102 | return -1; | ||
103 | |||
104 | if (!get_flags) { | ||
105 | IF_LONG_IS_WIDER( | ||
106 | f = (int) set_flags; | ||
107 | r = ioctl(fd, EXT2_IOC_SETFLAGS, &f); | ||
108 | ) | ||
109 | IF_LONG_IS_SAME( | ||
110 | r = ioctl(fd, EXT2_IOC_SETFLAGS, (void*)&set_flags); | ||
111 | ) | ||
112 | } else { | ||
113 | IF_LONG_IS_WIDER( | ||
114 | r = ioctl(fd, EXT2_IOC_GETFLAGS, &f); | ||
115 | *get_flags = f; | ||
116 | ) | ||
117 | IF_LONG_IS_SAME( | ||
118 | r = ioctl(fd, EXT2_IOC_GETFLAGS, (void*)get_flags); | ||
119 | ) | ||
120 | } | ||
121 | |||
122 | close_silently(fd); | ||
123 | return r; | ||
124 | notsupp: | ||
125 | #endif /* HAVE_EXT2_IOCTLS */ | ||
126 | errno = EOPNOTSUPP; | ||
127 | return -1; | ||
128 | } | ||
129 | #else /* ENABLE_PLATFORM_MINGW32 */ | ||
130 | /* Only certain attributes can be set using SetFileAttributes() */ | 12 | /* Only certain attributes can be set using SetFileAttributes() */ |
131 | #define CHATTR_MASK (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | \ | 13 | #define CHATTR_MASK (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | \ |
132 | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE | \ | 14 | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE | \ |
@@ -134,7 +16,7 @@ int fgetsetflags(const char *name, unsigned long *get_flags, unsigned long set_f | |||
134 | FILE_ATTRIBUTE_OFFLINE) | 16 | FILE_ATTRIBUTE_OFFLINE) |
135 | 17 | ||
136 | /* Get/set file attributes on a Windows file system */ | 18 | /* Get/set file attributes on a Windows file system */ |
137 | int fgetsetflags(const char *name, unsigned long *get_flags, unsigned long set_flags) | 19 | int fgetsetflags(const char *name, unsigned *get_flags, unsigned set_flags) |
138 | { | 20 | { |
139 | struct stat buf; | 21 | struct stat buf; |
140 | 22 | ||
@@ -156,7 +38,6 @@ int fgetsetflags(const char *name, unsigned long *get_flags, unsigned long set_f | |||
156 | } | 38 | } |
157 | #endif | 39 | #endif |
158 | 40 | ||
159 | |||
160 | #if !ENABLE_PLATFORM_MINGW32 | 41 | #if !ENABLE_PLATFORM_MINGW32 |
161 | /* Print file attributes on an ext2 file system */ | 42 | /* Print file attributes on an ext2 file system */ |
162 | const uint32_t e2attr_flags_value[] ALIGN4 = { | 43 | const uint32_t e2attr_flags_value[] ALIGN4 = { |
@@ -164,9 +45,7 @@ const uint32_t e2attr_flags_value[] ALIGN4 = { | |||
164 | EXT2_COMPRBLK_FL, | 45 | EXT2_COMPRBLK_FL, |
165 | EXT2_DIRTY_FL, | 46 | EXT2_DIRTY_FL, |
166 | EXT2_NOCOMPR_FL, | 47 | EXT2_NOCOMPR_FL, |
167 | EXT2_ECOMPR_FL, | ||
168 | #endif | 48 | #endif |
169 | EXT2_INDEX_FL, | ||
170 | EXT2_SECRM_FL, | 49 | EXT2_SECRM_FL, |
171 | EXT2_UNRM_FL, | 50 | EXT2_UNRM_FL, |
172 | EXT2_SYNC_FL, | 51 | EXT2_SYNC_FL, |
@@ -176,26 +55,31 @@ const uint32_t e2attr_flags_value[] ALIGN4 = { | |||
176 | EXT2_NODUMP_FL, | 55 | EXT2_NODUMP_FL, |
177 | EXT2_NOATIME_FL, | 56 | EXT2_NOATIME_FL, |
178 | EXT2_COMPR_FL, | 57 | EXT2_COMPR_FL, |
58 | EXT2_ECOMPR_FL, | ||
179 | EXT3_JOURNAL_DATA_FL, | 59 | EXT3_JOURNAL_DATA_FL, |
60 | EXT2_INDEX_FL, | ||
180 | EXT2_NOTAIL_FL, | 61 | EXT2_NOTAIL_FL, |
181 | EXT2_TOPDIR_FL | 62 | EXT2_TOPDIR_FL, |
63 | EXT2_EXTENT_FL, | ||
64 | EXT2_NOCOW_FL, | ||
65 | EXT2_CASEFOLD_FL, | ||
66 | EXT2_INLINE_DATA_FL, | ||
67 | EXT2_PROJINHERIT_FL, | ||
68 | EXT2_VERITY_FL, | ||
182 | }; | 69 | }; |
183 | 70 | ||
184 | const char e2attr_flags_sname[] ALIGN1 = | 71 | const char e2attr_flags_sname[] ALIGN1 = |
185 | #ifdef ENABLE_COMPRESSION | 72 | #ifdef ENABLE_COMPRESSION |
186 | "BZXE" | 73 | "BZX" |
187 | #endif | 74 | #endif |
188 | "I" | 75 | "suSDiadAcEjItTeCFNPV"; |
189 | "suSDiadAcjtT"; | ||
190 | 76 | ||
191 | static const char e2attr_flags_lname[] ALIGN1 = | 77 | static const char e2attr_flags_lname[] ALIGN1 = |
192 | #ifdef ENABLE_COMPRESSION | 78 | #ifdef ENABLE_COMPRESSION |
193 | "Compressed_File" "\0" | 79 | "Compressed_File" "\0" |
194 | "Compressed_Dirty_File" "\0" | 80 | "Compressed_Dirty_File" "\0" |
195 | "Compression_Raw_Access" "\0" | 81 | "Compression_Raw_Access" "\0" |
196 | "Compression_Error" "\0" | ||
197 | #endif | 82 | #endif |
198 | "Indexed_directory" "\0" | ||
199 | "Secure_Deletion" "\0" | 83 | "Secure_Deletion" "\0" |
200 | "Undelete" "\0" | 84 | "Undelete" "\0" |
201 | "Synchronous_Updates" "\0" | 85 | "Synchronous_Updates" "\0" |
@@ -205,9 +89,17 @@ static const char e2attr_flags_lname[] ALIGN1 = | |||
205 | "No_Dump" "\0" | 89 | "No_Dump" "\0" |
206 | "No_Atime" "\0" | 90 | "No_Atime" "\0" |
207 | "Compression_Requested" "\0" | 91 | "Compression_Requested" "\0" |
92 | "Encrypted" "\0" | ||
208 | "Journaled_Data" "\0" | 93 | "Journaled_Data" "\0" |
94 | "Indexed_directory" "\0" | ||
209 | "No_Tailmerging" "\0" | 95 | "No_Tailmerging" "\0" |
210 | "Top_of_Directory_Hierarchies" "\0" | 96 | "Top_of_Directory_Hierarchies" "\0" |
97 | "Extents" "\0" | ||
98 | "No_COW" "\0" | ||
99 | "Casefold" "\0" | ||
100 | "Inline_Data" "\0" | ||
101 | "Project_Hierarchy" "\0" | ||
102 | "Verity" "\0" | ||
211 | /* Another trailing NUL is added by compiler */; | 103 | /* Another trailing NUL is added by compiler */; |
212 | #else /* ENABLE_PLATFORM_MINGW32 */ | 104 | #else /* ENABLE_PLATFORM_MINGW32 */ |
213 | /* Print file attributes on a Windows file system */ | 105 | /* Print file attributes on a Windows file system */ |
@@ -243,36 +135,41 @@ static const char e2attr_flags_lname[] ALIGN1 = | |||
243 | /* Another trailing NUL is added by compiler */; | 135 | /* Another trailing NUL is added by compiler */; |
244 | #endif | 136 | #endif |
245 | 137 | ||
246 | void print_e2flags(FILE *f, unsigned long flags, unsigned options) | 138 | void print_e2flags_long(unsigned flags) |
247 | { | 139 | { |
248 | const uint32_t *fv; | 140 | const uint32_t *fv; |
249 | const char *fn; | 141 | const char *fn; |
142 | int first = 1; | ||
250 | 143 | ||
251 | fv = e2attr_flags_value; | 144 | fv = e2attr_flags_value; |
252 | if (options & PFOPT_LONG) { | 145 | fn = e2attr_flags_lname; |
253 | int first = 1; | 146 | do { |
254 | fn = e2attr_flags_lname; | 147 | if (flags & *fv) { |
255 | do { | 148 | if (!first) |
256 | if (flags & *fv) { | 149 | fputs(", ", stdout); |
257 | if (!first) | 150 | fputs(fn, stdout); |
258 | fputs(", ", f); | 151 | first = 0; |
259 | fputs(fn, f); | 152 | } |
260 | first = 0; | 153 | fv++; |
261 | } | 154 | fn += strlen(fn) + 1; |
262 | fv++; | 155 | } while (*fn); |
263 | fn += strlen(fn) + 1; | 156 | if (first) |
264 | } while (*fn); | 157 | fputs("---", stdout); |
265 | if (first) | 158 | } |
266 | fputs("---", f); | 159 | |
267 | } else { | 160 | void print_e2flags(unsigned flags) |
268 | fn = e2attr_flags_sname; | 161 | { |
269 | do { | 162 | const uint32_t *fv; |
270 | char c = '-'; | 163 | const char *fn; |
271 | if (flags & *fv) | 164 | |
272 | c = *fn; | 165 | fv = e2attr_flags_value; |
273 | fputc(c, f); | 166 | fn = e2attr_flags_sname; |
274 | fv++; | 167 | do { |
275 | fn++; | 168 | char c = '-'; |
276 | } while (*fn); | 169 | if (flags & *fv) |
277 | } | 170 | c = *fn; |
171 | putchar(c); | ||
172 | fv++; | ||
173 | fn++; | ||
174 | } while (*fn); | ||
278 | } | 175 | } |
diff --git a/e2fsprogs/e2fs_lib.h b/e2fsprogs/e2fs_lib.h index 4a4d4cc27..aa92e63af 100644 --- a/e2fsprogs/e2fs_lib.h +++ b/e2fsprogs/e2fs_lib.h | |||
@@ -11,25 +11,16 @@ | |||
11 | 11 | ||
12 | PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN | 12 | PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN |
13 | 13 | ||
14 | /* Iterate a function on each entry of a directory */ | 14 | #if ENABLE_PLATFORM_MINGW32 |
15 | int iterate_on_dir(const char *dir_name, | 15 | /* Get/set a file flags */ |
16 | int FAST_FUNC (*func)(const char *, struct dirent *, void *), | 16 | int fgetsetflags(const char *name, unsigned *get_flags, unsigned set_flags); |
17 | void *private); | ||
18 | |||
19 | /* Get/set a file version on an ext2 file system */ | ||
20 | int fgetsetversion(const char *name, unsigned long *get_version, unsigned long set_version); | ||
21 | #define fgetversion(name, version) fgetsetversion(name, version, 0) | ||
22 | #define fsetversion(name, version) fgetsetversion(name, NULL, version) | ||
23 | |||
24 | /* Get/set a file flags on an ext2 file system */ | ||
25 | int fgetsetflags(const char *name, unsigned long *get_flags, unsigned long set_flags); | ||
26 | #define fgetflags(name, flags) fgetsetflags(name, flags, 0) | 17 | #define fgetflags(name, flags) fgetsetflags(name, flags, 0) |
27 | #define fsetflags(name, flags) fgetsetflags(name, NULL, flags) | 18 | #define fsetflags(name, flags) fgetsetflags(name, NULL, flags) |
19 | #endif | ||
28 | 20 | ||
29 | /* Must be 1 for compatibility with 'int long_format'. */ | ||
30 | #define PFOPT_LONG 1 | ||
31 | /* Print file attributes on an ext2 file system */ | 21 | /* Print file attributes on an ext2 file system */ |
32 | void print_e2flags(FILE *f, unsigned long flags, unsigned options); | 22 | void print_e2flags_long(unsigned flags); |
23 | void print_e2flags(unsigned flags); | ||
33 | 24 | ||
34 | extern const uint32_t e2attr_flags_value[]; | 25 | extern const uint32_t e2attr_flags_value[]; |
35 | extern const char e2attr_flags_sname[]; | 26 | extern const char e2attr_flags_sname[]; |
diff --git a/e2fsprogs/lsattr.c b/e2fsprogs/lsattr.c index ed7b67c6f..d82861e14 100644 --- a/e2fsprogs/lsattr.c +++ b/e2fsprogs/lsattr.c | |||
@@ -22,7 +22,7 @@ | |||
22 | 22 | ||
23 | //usage:#define lsattr_trivial_usage | 23 | //usage:#define lsattr_trivial_usage |
24 | //usage: IF_NOT_PLATFORM_MINGW32( | 24 | //usage: IF_NOT_PLATFORM_MINGW32( |
25 | //usage: "[-Radlv] [FILE]..." | 25 | //usage: "[-Radlpv] [FILE]..." |
26 | //usage: ) | 26 | //usage: ) |
27 | //usage: IF_PLATFORM_MINGW32( | 27 | //usage: IF_PLATFORM_MINGW32( |
28 | //usage: "[-Radl] [FILE]..." | 28 | //usage: "[-Radl] [FILE]..." |
@@ -30,10 +30,12 @@ | |||
30 | //usage:#define lsattr_full_usage "\n\n" | 30 | //usage:#define lsattr_full_usage "\n\n" |
31 | //usage: "List ext2 file attributes\n" | 31 | //usage: "List ext2 file attributes\n" |
32 | //usage: "\n -R Recurse" | 32 | //usage: "\n -R Recurse" |
33 | //usage: "\n -a Don't hide entries starting with ." | 33 | //usage: "\n -a Include names starting with ." |
34 | //usage: "\n -d List directory entries instead of contents" | 34 | //usage: "\n -d List directory names, not contents" |
35 | // -a,-d text should match ls --help | ||
35 | //usage: "\n -l List long flag names" | 36 | //usage: "\n -l List long flag names" |
36 | //usage: IF_NOT_PLATFORM_MINGW32( | 37 | //usage: IF_NOT_PLATFORM_MINGW32( |
38 | //usage: "\n -p List project ID" | ||
37 | //usage: "\n -v List version/generation number" | 39 | //usage: "\n -v List version/generation number" |
38 | //usage: ) | 40 | //usage: ) |
39 | 41 | ||
@@ -41,43 +43,71 @@ | |||
41 | #include "e2fs_lib.h" | 43 | #include "e2fs_lib.h" |
42 | 44 | ||
43 | enum { | 45 | enum { |
44 | OPT_RECUR = 0x1, | 46 | OPT_RECUR = 1 << 0, |
45 | OPT_ALL = 0x2, | 47 | OPT_ALL = 1 << 1, |
46 | OPT_DIRS_OPT = 0x4, | 48 | OPT_DIRS_OPT = 1 << 2, |
47 | OPT_PF_LONG = 0x8, | 49 | OPT_PF_LONG = 1 << 3, |
48 | OPT_GENERATION = 0x10, | 50 | OPT_GENERATION = 1 << 4, |
51 | OPT_PROJID = 1 << 5, | ||
49 | }; | 52 | }; |
50 | 53 | ||
51 | static void list_attributes(const char *name) | 54 | static void list_attributes(const char *name) |
52 | { | 55 | { |
53 | unsigned long fsflags; | 56 | unsigned fsflags; |
54 | #if !ENABLE_PLATFORM_MINGW32 | 57 | #if !ENABLE_PLATFORM_MINGW32 |
55 | unsigned long generation; | 58 | int fd, r; |
56 | #endif | 59 | |
57 | 60 | /* There is no way to run needed ioctls on a symlink. | |
58 | if (fgetflags(name, &fsflags) != 0) | 61 | * open(O_PATH | O_NOFOLLOW) _can_ be used to get a fd referring to the symlink, |
59 | goto read_err; | 62 | * but ioctls fail on such a fd (tried on 4.12.0 kernel). |
63 | * e2fsprogs-1.46.2 uses open(O_NOFOLLOW), it fails on symlinks. | ||
64 | */ | ||
65 | fd = open_or_warn(name, O_RDONLY | O_NONBLOCK | O_NOCTTY | O_NOFOLLOW); | ||
66 | if (fd < 0) | ||
67 | return; | ||
68 | |||
69 | if (option_mask32 & OPT_PROJID) { | ||
70 | struct ext2_fsxattr fsxattr; | ||
71 | r = ioctl(fd, EXT2_IOC_FSGETXATTR, &fsxattr); | ||
72 | /* note: ^^^ may fail in 32-bit userspace on 64-bit kernel (seen on 4.12.0) */ | ||
73 | if (r != 0) | ||
74 | goto read_err; | ||
75 | printf("%5u ", (unsigned)fsxattr.fsx_projid); | ||
76 | } | ||
60 | 77 | ||
61 | #if !ENABLE_PLATFORM_MINGW32 | ||
62 | if (option_mask32 & OPT_GENERATION) { | 78 | if (option_mask32 & OPT_GENERATION) { |
63 | if (fgetversion(name, &generation) != 0) | 79 | unsigned generation; |
80 | r = ioctl(fd, EXT2_IOC_GETVERSION, &generation); | ||
81 | if (r != 0) | ||
64 | goto read_err; | 82 | goto read_err; |
65 | printf("%5lu ", generation); | 83 | printf("%-10u ", generation); |
66 | } | 84 | } |
85 | |||
86 | r = ioctl(fd, EXT2_IOC_GETFLAGS, &fsflags); | ||
87 | if (r != 0) | ||
88 | goto read_err; | ||
89 | |||
90 | close(fd); | ||
91 | #else /* ENABLE_PLATFORM_MINGW32 */ | ||
92 | if (fgetflags(name, &fsflags) != 0) | ||
93 | goto read_err; | ||
67 | #endif | 94 | #endif |
68 | 95 | ||
69 | if (option_mask32 & OPT_PF_LONG) { | 96 | if (option_mask32 & OPT_PF_LONG) { |
70 | printf("%-28s ", name); | 97 | printf("%-28s ", name); |
71 | print_e2flags(stdout, fsflags, PFOPT_LONG); | 98 | print_e2flags_long(fsflags); |
72 | bb_putchar('\n'); | 99 | bb_putchar('\n'); |
73 | } else { | 100 | } else { |
74 | print_e2flags(stdout, fsflags, 0); | 101 | print_e2flags(fsflags); |
75 | printf(" %s\n", name); | 102 | printf(" %s\n", name); |
76 | } | 103 | } |
77 | 104 | ||
78 | return; | 105 | return; |
79 | read_err: | 106 | read_err: |
80 | bb_perror_msg("reading %s", name); | 107 | bb_perror_msg("reading %s", name); |
108 | #if !ENABLE_PLATFORM_MINGW32 | ||
109 | close(fd); | ||
110 | #endif | ||
81 | } | 111 | } |
82 | 112 | ||
83 | static int FAST_FUNC lsattr_dir_proc(const char *dir_name, | 113 | static int FAST_FUNC lsattr_dir_proc(const char *dir_name, |
@@ -90,9 +120,13 @@ static int FAST_FUNC lsattr_dir_proc(const char *dir_name, | |||
90 | path = concat_path_file(dir_name, de->d_name); | 120 | path = concat_path_file(dir_name, de->d_name); |
91 | 121 | ||
92 | if (lstat(path, &st) != 0) | 122 | if (lstat(path, &st) != 0) |
93 | bb_perror_msg("stat %s", path); | 123 | bb_perror_msg("can't stat '%s'", path); |
124 | |||
94 | else if (de->d_name[0] != '.' || (option_mask32 & OPT_ALL)) { | 125 | else if (de->d_name[0] != '.' || (option_mask32 & OPT_ALL)) { |
95 | list_attributes(path); | 126 | /* Don't try to open device files, fifos etc */ |
127 | if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode) || S_ISDIR(st.st_mode)) | ||
128 | list_attributes(path); | ||
129 | |||
96 | if (S_ISDIR(st.st_mode) && (option_mask32 & OPT_RECUR) | 130 | if (S_ISDIR(st.st_mode) && (option_mask32 & OPT_RECUR) |
97 | && !DOT_OR_DOTDOT(de->d_name) | 131 | && !DOT_OR_DOTDOT(de->d_name) |
98 | ) { | 132 | ) { |
@@ -111,7 +145,7 @@ static void lsattr_args(const char *name) | |||
111 | struct stat st; | 145 | struct stat st; |
112 | 146 | ||
113 | if (lstat(name, &st) == -1) { | 147 | if (lstat(name, &st) == -1) { |
114 | bb_perror_msg("stat %s", name); | 148 | bb_perror_msg("can't stat '%s'", name); |
115 | } else if (S_ISDIR(st.st_mode) && !(option_mask32 & OPT_DIRS_OPT)) { | 149 | } else if (S_ISDIR(st.st_mode) && !(option_mask32 & OPT_DIRS_OPT)) { |
116 | iterate_on_dir(name, lsattr_dir_proc, NULL); | 150 | iterate_on_dir(name, lsattr_dir_proc, NULL); |
117 | } else { | 151 | } else { |
@@ -125,7 +159,7 @@ int lsattr_main(int argc UNUSED_PARAM, char **argv) | |||
125 | #if ENABLE_PLATFORM_MINGW32 | 159 | #if ENABLE_PLATFORM_MINGW32 |
126 | getopt32(argv, "Radl"); | 160 | getopt32(argv, "Radl"); |
127 | #else | 161 | #else |
128 | getopt32(argv, "Radlv"); | 162 | getopt32(argv, "Radlvp"); |
129 | #endif | 163 | #endif |
130 | argv += optind; | 164 | argv += optind; |
131 | 165 | ||
diff --git a/editors/awk.c b/editors/awk.c index 41a57ea0c..9b9b202db 100644 --- a/editors/awk.c +++ b/editors/awk.c | |||
@@ -66,6 +66,8 @@ | |||
66 | #endif | 66 | #endif |
67 | #ifndef debug_printf_parse | 67 | #ifndef debug_printf_parse |
68 | # define debug_printf_parse(...) (fprintf(stderr, __VA_ARGS__)) | 68 | # define debug_printf_parse(...) (fprintf(stderr, __VA_ARGS__)) |
69 | #else | ||
70 | # define debug_parse_print_tc(...) ((void)0) | ||
69 | #endif | 71 | #endif |
70 | 72 | ||
71 | 73 | ||
@@ -210,13 +212,13 @@ typedef struct tsplitter_s { | |||
210 | #define TC_SEQTERM (1 << 1) /* ) */ | 212 | #define TC_SEQTERM (1 << 1) /* ) */ |
211 | #define TC_REGEXP (1 << 2) /* /.../ */ | 213 | #define TC_REGEXP (1 << 2) /* /.../ */ |
212 | #define TC_OUTRDR (1 << 3) /* | > >> */ | 214 | #define TC_OUTRDR (1 << 3) /* | > >> */ |
213 | #define TC_UOPPOST (1 << 4) /* unary postfix operator */ | 215 | #define TC_UOPPOST (1 << 4) /* unary postfix operator ++ -- */ |
214 | #define TC_UOPPRE1 (1 << 5) /* unary prefix operator */ | 216 | #define TC_UOPPRE1 (1 << 5) /* unary prefix operator ++ -- $ */ |
215 | #define TC_BINOPX (1 << 6) /* two-opnd operator */ | 217 | #define TC_BINOPX (1 << 6) /* two-opnd operator */ |
216 | #define TC_IN (1 << 7) | 218 | #define TC_IN (1 << 7) |
217 | #define TC_COMMA (1 << 8) | 219 | #define TC_COMMA (1 << 8) |
218 | #define TC_PIPE (1 << 9) /* input redirection pipe */ | 220 | #define TC_PIPE (1 << 9) /* input redirection pipe */ |
219 | #define TC_UOPPRE2 (1 << 10) /* unary prefix operator */ | 221 | #define TC_UOPPRE2 (1 << 10) /* unary prefix operator + - ! */ |
220 | #define TC_ARRTERM (1 << 11) /* ] */ | 222 | #define TC_ARRTERM (1 << 11) /* ] */ |
221 | #define TC_GRPSTART (1 << 12) /* { */ | 223 | #define TC_GRPSTART (1 << 12) /* { */ |
222 | #define TC_GRPTERM (1 << 13) /* } */ | 224 | #define TC_GRPTERM (1 << 13) /* } */ |
@@ -243,14 +245,51 @@ typedef struct tsplitter_s { | |||
243 | #define TC_STRING (1 << 29) | 245 | #define TC_STRING (1 << 29) |
244 | #define TC_NUMBER (1 << 30) | 246 | #define TC_NUMBER (1 << 30) |
245 | 247 | ||
246 | #define TC_UOPPRE (TC_UOPPRE1 | TC_UOPPRE2) | 248 | #ifndef debug_parse_print_tc |
249 | #define debug_parse_print_tc(n) do { \ | ||
250 | if ((n) & TC_SEQSTART) debug_printf_parse(" SEQSTART"); \ | ||
251 | if ((n) & TC_SEQTERM ) debug_printf_parse(" SEQTERM" ); \ | ||
252 | if ((n) & TC_REGEXP ) debug_printf_parse(" REGEXP" ); \ | ||
253 | if ((n) & TC_OUTRDR ) debug_printf_parse(" OUTRDR" ); \ | ||
254 | if ((n) & TC_UOPPOST ) debug_printf_parse(" UOPPOST" ); \ | ||
255 | if ((n) & TC_UOPPRE1 ) debug_printf_parse(" UOPPRE1" ); \ | ||
256 | if ((n) & TC_BINOPX ) debug_printf_parse(" BINOPX" ); \ | ||
257 | if ((n) & TC_IN ) debug_printf_parse(" IN" ); \ | ||
258 | if ((n) & TC_COMMA ) debug_printf_parse(" COMMA" ); \ | ||
259 | if ((n) & TC_PIPE ) debug_printf_parse(" PIPE" ); \ | ||
260 | if ((n) & TC_UOPPRE2 ) debug_printf_parse(" UOPPRE2" ); \ | ||
261 | if ((n) & TC_ARRTERM ) debug_printf_parse(" ARRTERM" ); \ | ||
262 | if ((n) & TC_GRPSTART) debug_printf_parse(" GRPSTART"); \ | ||
263 | if ((n) & TC_GRPTERM ) debug_printf_parse(" GRPTERM" ); \ | ||
264 | if ((n) & TC_SEMICOL ) debug_printf_parse(" SEMICOL" ); \ | ||
265 | if ((n) & TC_NEWLINE ) debug_printf_parse(" NEWLINE" ); \ | ||
266 | if ((n) & TC_STATX ) debug_printf_parse(" STATX" ); \ | ||
267 | if ((n) & TC_WHILE ) debug_printf_parse(" WHILE" ); \ | ||
268 | if ((n) & TC_ELSE ) debug_printf_parse(" ELSE" ); \ | ||
269 | if ((n) & TC_BUILTIN ) debug_printf_parse(" BUILTIN" ); \ | ||
270 | if ((n) & TC_LENGTH ) debug_printf_parse(" LENGTH" ); \ | ||
271 | if ((n) & TC_GETLINE ) debug_printf_parse(" GETLINE" ); \ | ||
272 | if ((n) & TC_FUNCDECL) debug_printf_parse(" FUNCDECL"); \ | ||
273 | if ((n) & TC_BEGIN ) debug_printf_parse(" BEGIN" ); \ | ||
274 | if ((n) & TC_END ) debug_printf_parse(" END" ); \ | ||
275 | if ((n) & TC_EOF ) debug_printf_parse(" EOF" ); \ | ||
276 | if ((n) & TC_VARIABLE) debug_printf_parse(" VARIABLE"); \ | ||
277 | if ((n) & TC_ARRAY ) debug_printf_parse(" ARRAY" ); \ | ||
278 | if ((n) & TC_FUNCTION) debug_printf_parse(" FUNCTION"); \ | ||
279 | if ((n) & TC_STRING ) debug_printf_parse(" STRING" ); \ | ||
280 | if ((n) & TC_NUMBER ) debug_printf_parse(" NUMBER" ); \ | ||
281 | } while (0) | ||
282 | #endif | ||
247 | 283 | ||
248 | /* combined token classes */ | 284 | /* combined token classes */ |
285 | #define TC_UOPPRE (TC_UOPPRE1 | TC_UOPPRE2) | ||
286 | |||
249 | #define TC_BINOP (TC_BINOPX | TC_COMMA | TC_PIPE | TC_IN) | 287 | #define TC_BINOP (TC_BINOPX | TC_COMMA | TC_PIPE | TC_IN) |
250 | //#define TC_UNARYOP (TC_UOPPRE | TC_UOPPOST) | 288 | //#define TC_UNARYOP (TC_UOPPRE | TC_UOPPOST) |
251 | #define TC_OPERAND (TC_VARIABLE | TC_ARRAY | TC_FUNCTION \ | 289 | #define TC_OPERAND (TC_VARIABLE | TC_ARRAY | TC_FUNCTION \ |
252 | | TC_BUILTIN | TC_LENGTH | TC_GETLINE \ | 290 | | TC_BUILTIN | TC_LENGTH | TC_GETLINE \ |
253 | | TC_SEQSTART | TC_STRING | TC_NUMBER) | 291 | | TC_SEQSTART | TC_STRING | TC_NUMBER) |
292 | #define TC_LVALUE (TC_VARIABLE | TC_ARRAY) | ||
254 | 293 | ||
255 | #define TC_STATEMNT (TC_STATX | TC_WHILE) | 294 | #define TC_STATEMNT (TC_STATX | TC_WHILE) |
256 | #define TC_OPTERM (TC_SEMICOL | TC_NEWLINE) | 295 | #define TC_OPTERM (TC_SEMICOL | TC_NEWLINE) |
@@ -284,7 +323,6 @@ typedef struct tsplitter_s { | |||
284 | #define OF_CHECKED 0x200000 | 323 | #define OF_CHECKED 0x200000 |
285 | #define OF_REQUIRED 0x400000 | 324 | #define OF_REQUIRED 0x400000 |
286 | 325 | ||
287 | |||
288 | /* combined operator flags */ | 326 | /* combined operator flags */ |
289 | #define xx 0 | 327 | #define xx 0 |
290 | #define xV OF_RES2 | 328 | #define xV OF_RES2 |
@@ -313,10 +351,8 @@ typedef struct tsplitter_s { | |||
313 | #define PRIMASK2 0x7E000000 | 351 | #define PRIMASK2 0x7E000000 |
314 | 352 | ||
315 | /* Operation classes */ | 353 | /* Operation classes */ |
316 | |||
317 | #define SHIFT_TIL_THIS 0x0600 | 354 | #define SHIFT_TIL_THIS 0x0600 |
318 | #define RECUR_FROM_THIS 0x1000 | 355 | #define RECUR_FROM_THIS 0x1000 |
319 | |||
320 | enum { | 356 | enum { |
321 | OC_DELETE = 0x0100, OC_EXEC = 0x0200, OC_NEWSOURCE = 0x0300, | 357 | OC_DELETE = 0x0100, OC_EXEC = 0x0200, OC_NEWSOURCE = 0x0300, |
322 | OC_PRINT = 0x0400, OC_PRINTF = 0x0500, OC_WALKINIT = 0x0600, | 358 | OC_PRINT = 0x0400, OC_PRINTF = 0x0500, OC_WALKINIT = 0x0600, |
@@ -411,13 +447,16 @@ static const uint32_t tokeninfo[] ALIGN4 = { | |||
411 | OC_REGEXP, | 447 | OC_REGEXP, |
412 | xS|'a', xS|'w', xS|'|', | 448 | xS|'a', xS|'w', xS|'|', |
413 | OC_UNARY|xV|P(9)|'p', OC_UNARY|xV|P(9)|'m', | 449 | OC_UNARY|xV|P(9)|'p', OC_UNARY|xV|P(9)|'m', |
414 | OC_UNARY|xV|P(9)|'P', OC_UNARY|xV|P(9)|'M', OC_FIELD|xV|P(5), | 450 | #define TI_PREINC (OC_UNARY|xV|P(9)|'P') |
451 | #define TI_PREDEC (OC_UNARY|xV|P(9)|'M') | ||
452 | TI_PREINC, TI_PREDEC, OC_FIELD|xV|P(5), | ||
415 | OC_COMPARE|VV|P(39)|5, OC_MOVE|VV|P(74), OC_REPLACE|NV|P(74)|'+', OC_REPLACE|NV|P(74)|'-', | 453 | OC_COMPARE|VV|P(39)|5, OC_MOVE|VV|P(74), OC_REPLACE|NV|P(74)|'+', OC_REPLACE|NV|P(74)|'-', |
416 | OC_REPLACE|NV|P(74)|'*', OC_REPLACE|NV|P(74)|'/', OC_REPLACE|NV|P(74)|'%', OC_REPLACE|NV|P(74)|'&', | 454 | OC_REPLACE|NV|P(74)|'*', OC_REPLACE|NV|P(74)|'/', OC_REPLACE|NV|P(74)|'%', OC_REPLACE|NV|P(74)|'&', |
417 | OC_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-', OC_REPLACE|NV|P(74)|'&', OC_BINARY|NV|P(15)|'&', | 455 | OC_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-', OC_REPLACE|NV|P(74)|'&', OC_BINARY|NV|P(15)|'&', |
418 | OC_BINARY|NV|P(25)|'/', OC_BINARY|NV|P(25)|'%', OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'*', | 456 | OC_BINARY|NV|P(25)|'/', OC_BINARY|NV|P(25)|'%', OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'*', |
419 | OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3, OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1, | 457 | OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3, OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1, |
420 | OC_COMPARE|VV|P(39)|2, OC_MATCH|Sx|P(45)|'!', OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55), | 458 | #define TI_LESS (OC_COMPARE|VV|P(39)|2) |
459 | TI_LESS, OC_MATCH|Sx|P(45)|'!', OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55), | ||
421 | OC_LOR|Vx|P(59), OC_TERNARY|Vx|P(64)|'?', OC_COLON|xx|P(67)|':', | 460 | OC_LOR|Vx|P(59), OC_TERNARY|Vx|P(64)|'?', OC_COLON|xx|P(67)|':', |
422 | OC_IN|SV|P(49), /* TC_IN */ | 461 | OC_IN|SV|P(49), /* TC_IN */ |
423 | OC_COMMA|SS|P(80), | 462 | OC_COMMA|SS|P(80), |
@@ -1074,6 +1113,10 @@ static uint32_t next_token(uint32_t expected) | |||
1074 | uint32_t tc; | 1113 | uint32_t tc; |
1075 | const uint32_t *ti; | 1114 | const uint32_t *ti; |
1076 | 1115 | ||
1116 | debug_printf_parse("%s() expected(%x):", __func__, expected); | ||
1117 | debug_parse_print_tc(expected); | ||
1118 | debug_printf_parse("\n"); | ||
1119 | |||
1077 | if (t_rollback) { | 1120 | if (t_rollback) { |
1078 | debug_printf_parse("%s: using rolled-back token\n", __func__); | 1121 | debug_printf_parse("%s: using rolled-back token\n", __func__); |
1079 | t_rollback = FALSE; | 1122 | t_rollback = FALSE; |
@@ -1178,6 +1221,8 @@ static uint32_t next_token(uint32_t expected) | |||
1178 | if (!isalnum_(*p)) | 1221 | if (!isalnum_(*p)) |
1179 | syntax_error(EMSG_UNEXP_TOKEN); /* no */ | 1222 | syntax_error(EMSG_UNEXP_TOKEN); /* no */ |
1180 | /* yes */ | 1223 | /* yes */ |
1224 | /* "move name one char back" trick: we need a byte for NUL terminator */ | ||
1225 | /* NB: this results in argv[i][-1] being used (!!!) in e.g. "awk -e 'NAME'" case */ | ||
1181 | t_string = --p; | 1226 | t_string = --p; |
1182 | while (isalnum_(*++p)) { | 1227 | while (isalnum_(*++p)) { |
1183 | p[-1] = *p; | 1228 | p[-1] = *p; |
@@ -1230,7 +1275,9 @@ static uint32_t next_token(uint32_t expected) | |||
1230 | EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN); | 1275 | EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN); |
1231 | } | 1276 | } |
1232 | 1277 | ||
1233 | debug_printf_parse("%s: returning, ltclass:%x t_double:%f\n", __func__, ltclass, t_double); | 1278 | debug_printf_parse("%s: returning, t_double:%f ltclass:", __func__, t_double); |
1279 | debug_parse_print_tc(ltclass); | ||
1280 | debug_printf_parse("\n"); | ||
1234 | return ltclass; | 1281 | return ltclass; |
1235 | #undef concat_inserted | 1282 | #undef concat_inserted |
1236 | #undef save_tclass | 1283 | #undef save_tclass |
@@ -1270,7 +1317,7 @@ static node *condition(void) | |||
1270 | 1317 | ||
1271 | /* parse expression terminated by given argument, return ptr | 1318 | /* parse expression terminated by given argument, return ptr |
1272 | * to built subtree. Terminator is eaten by parse_expr */ | 1319 | * to built subtree. Terminator is eaten by parse_expr */ |
1273 | static node *parse_expr(uint32_t iexp) | 1320 | static node *parse_expr(uint32_t term_tc) |
1274 | { | 1321 | { |
1275 | node sn; | 1322 | node sn; |
1276 | node *cn = &sn; | 1323 | node *cn = &sn; |
@@ -1278,15 +1325,17 @@ static node *parse_expr(uint32_t iexp) | |||
1278 | uint32_t tc, xtc; | 1325 | uint32_t tc, xtc; |
1279 | var *v; | 1326 | var *v; |
1280 | 1327 | ||
1281 | debug_printf_parse("%s(%x)\n", __func__, iexp); | 1328 | debug_printf_parse("%s() term_tc(%x):", __func__, term_tc); |
1329 | debug_parse_print_tc(term_tc); | ||
1330 | debug_printf_parse("\n"); | ||
1282 | 1331 | ||
1283 | sn.info = PRIMASK; | 1332 | sn.info = PRIMASK; |
1284 | sn.r.n = sn.a.n = glptr = NULL; | 1333 | sn.r.n = sn.a.n = glptr = NULL; |
1285 | xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp; | 1334 | xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | term_tc; |
1286 | 1335 | ||
1287 | while (!((tc = next_token(xtc)) & iexp)) { | 1336 | while (!((tc = next_token(xtc)) & term_tc)) { |
1288 | 1337 | ||
1289 | if (glptr && (t_info == (OC_COMPARE | VV | P(39) | 2))) { | 1338 | if (glptr && (t_info == TI_LESS)) { |
1290 | /* input redirection (<) attached to glptr node */ | 1339 | /* input redirection (<) attached to glptr node */ |
1291 | debug_printf_parse("%s: input redir\n", __func__); | 1340 | debug_printf_parse("%s: input redir\n", __func__); |
1292 | cn = glptr->l.n = new_node(OC_CONCAT | SS | P(37)); | 1341 | cn = glptr->l.n = new_node(OC_CONCAT | SS | P(37)); |
@@ -1317,25 +1366,28 @@ static node *parse_expr(uint32_t iexp) | |||
1317 | next_token(TC_GETLINE); | 1366 | next_token(TC_GETLINE); |
1318 | /* give maximum priority to this pipe */ | 1367 | /* give maximum priority to this pipe */ |
1319 | cn->info &= ~PRIMASK; | 1368 | cn->info &= ~PRIMASK; |
1320 | xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp; | 1369 | xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | term_tc; |
1321 | } | 1370 | } |
1322 | } else { | 1371 | } else { |
1323 | cn->r.n = vn; | 1372 | cn->r.n = vn; |
1324 | xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp; | 1373 | xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | term_tc; |
1325 | } | 1374 | } |
1326 | vn->a.n = cn; | 1375 | vn->a.n = cn; |
1327 | 1376 | ||
1328 | } else { | 1377 | } else { |
1329 | debug_printf_parse("%s: other\n", __func__); | 1378 | debug_printf_parse("%s: other, t_info:%x\n", __func__, t_info); |
1330 | /* for operands and prefix-unary operators, attach them | 1379 | /* for operands and prefix-unary operators, attach them |
1331 | * to last node */ | 1380 | * to last node */ |
1332 | vn = cn; | 1381 | vn = cn; |
1333 | cn = vn->r.n = new_node(t_info); | 1382 | cn = vn->r.n = new_node(t_info); |
1334 | cn->a.n = vn; | 1383 | cn->a.n = vn; |
1384 | |||
1335 | xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP; | 1385 | xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP; |
1386 | if (t_info == TI_PREINC || t_info == TI_PREDEC) | ||
1387 | xtc = TC_LVALUE | TC_UOPPRE1; | ||
1336 | if (tc & (TC_OPERAND | TC_REGEXP)) { | 1388 | if (tc & (TC_OPERAND | TC_REGEXP)) { |
1337 | debug_printf_parse("%s: TC_OPERAND | TC_REGEXP\n", __func__); | 1389 | debug_printf_parse("%s: TC_OPERAND | TC_REGEXP\n", __func__); |
1338 | xtc = TC_UOPPRE | TC_UOPPOST | TC_BINOP | TC_OPERAND | iexp; | 1390 | xtc = TC_UOPPRE | TC_UOPPOST | TC_BINOP | TC_OPERAND | term_tc; |
1339 | /* one should be very careful with switch on tclass - | 1391 | /* one should be very careful with switch on tclass - |
1340 | * only simple tclasses should be used! */ | 1392 | * only simple tclasses should be used! */ |
1341 | switch (tc) { | 1393 | switch (tc) { |
@@ -1392,7 +1444,7 @@ static node *parse_expr(uint32_t iexp) | |||
1392 | case TC_GETLINE: | 1444 | case TC_GETLINE: |
1393 | debug_printf_parse("%s: TC_GETLINE\n", __func__); | 1445 | debug_printf_parse("%s: TC_GETLINE\n", __func__); |
1394 | glptr = cn; | 1446 | glptr = cn; |
1395 | xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp; | 1447 | xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | term_tc; |
1396 | break; | 1448 | break; |
1397 | 1449 | ||
1398 | case TC_BUILTIN: | 1450 | case TC_BUILTIN: |
@@ -1607,6 +1659,8 @@ static void parse_program(char *p) | |||
1607 | func *f; | 1659 | func *f; |
1608 | var *v; | 1660 | var *v; |
1609 | 1661 | ||
1662 | debug_printf_parse("%s()\n", __func__); | ||
1663 | |||
1610 | g_pos = p; | 1664 | g_pos = p; |
1611 | t_lineno = 1; | 1665 | t_lineno = 1; |
1612 | while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART | | 1666 | while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART | |
@@ -1749,12 +1803,22 @@ static char* qrealloc(char *b, int n, int *size) | |||
1749 | /* resize field storage space */ | 1803 | /* resize field storage space */ |
1750 | static void fsrealloc(int size) | 1804 | static void fsrealloc(int size) |
1751 | { | 1805 | { |
1752 | int i; | 1806 | int i, newsize; |
1753 | 1807 | ||
1754 | if (size >= maxfields) { | 1808 | if (size >= maxfields) { |
1809 | /* Sanity cap, easier than catering for overflows */ | ||
1810 | if (size > 0xffffff) | ||
1811 | bb_die_memory_exhausted(); | ||
1812 | |||
1755 | i = maxfields; | 1813 | i = maxfields; |
1756 | maxfields = size + 16; | 1814 | maxfields = size + 16; |
1757 | Fields = xrealloc(Fields, maxfields * sizeof(Fields[0])); | 1815 | |
1816 | newsize = maxfields * sizeof(Fields[0]); | ||
1817 | debug_printf_eval("fsrealloc: xrealloc(%p, %u)\n", Fields, newsize); | ||
1818 | Fields = xrealloc(Fields, newsize); | ||
1819 | debug_printf_eval("fsrealloc: Fields=%p..%p\n", Fields, (char*)Fields + newsize - 1); | ||
1820 | /* ^^^ did Fields[] move? debug aid for L.v getting "upstaged" by R.v in evaluate() */ | ||
1821 | |||
1758 | for (; i < maxfields; i++) { | 1822 | for (; i < maxfields; i++) { |
1759 | Fields[i].type = VF_SPECIAL; | 1823 | Fields[i].type = VF_SPECIAL; |
1760 | Fields[i].string = NULL; | 1824 | Fields[i].string = NULL; |
@@ -2633,20 +2697,30 @@ static var *evaluate(node *op, var *res) | |||
2633 | /* execute inevitable things */ | 2697 | /* execute inevitable things */ |
2634 | if (opinfo & OF_RES1) | 2698 | if (opinfo & OF_RES1) |
2635 | L.v = evaluate(op1, v1); | 2699 | L.v = evaluate(op1, v1); |
2636 | if (opinfo & OF_RES2) | ||
2637 | R.v = evaluate(op->r.n, v1+1); | ||
2638 | if (opinfo & OF_STR1) { | 2700 | if (opinfo & OF_STR1) { |
2639 | L.s = getvar_s(L.v); | 2701 | L.s = getvar_s(L.v); |
2640 | debug_printf_eval("L.s:'%s'\n", L.s); | 2702 | debug_printf_eval("L.s:'%s'\n", L.s); |
2641 | } | 2703 | } |
2642 | if (opinfo & OF_STR2) { | ||
2643 | R.s = getvar_s(R.v); | ||
2644 | debug_printf_eval("R.s:'%s'\n", R.s); | ||
2645 | } | ||
2646 | if (opinfo & OF_NUM1) { | 2704 | if (opinfo & OF_NUM1) { |
2647 | L_d = getvar_i(L.v); | 2705 | L_d = getvar_i(L.v); |
2648 | debug_printf_eval("L_d:%f\n", L_d); | 2706 | debug_printf_eval("L_d:%f\n", L_d); |
2649 | } | 2707 | } |
2708 | /* NB: Must get string/numeric values of L (done above) | ||
2709 | * _before_ evaluate()'ing R.v: if both L and R are $NNNs, | ||
2710 | * and right one is large, then L.v points to Fields[NNN1], | ||
2711 | * second evaluate() reallocates and moves (!) Fields[], | ||
2712 | * R.v points to Fields[NNN2] but L.v now points to freed mem! | ||
2713 | * (Seen trying to evaluate "$444 $44444") | ||
2714 | */ | ||
2715 | if (opinfo & OF_RES2) { | ||
2716 | R.v = evaluate(op->r.n, v1+1); | ||
2717 | //TODO: L.v may be invalid now, set L.v to NULL to catch bugs? | ||
2718 | //L.v = NULL; | ||
2719 | } | ||
2720 | if (opinfo & OF_STR2) { | ||
2721 | R.s = getvar_s(R.v); | ||
2722 | debug_printf_eval("R.s:'%s'\n", R.s); | ||
2723 | } | ||
2650 | 2724 | ||
2651 | debug_printf_eval("switch(0x%x)\n", XC(opinfo & OPCLSMASK)); | 2725 | debug_printf_eval("switch(0x%x)\n", XC(opinfo & OPCLSMASK)); |
2652 | switch (XC(opinfo & OPCLSMASK)) { | 2726 | switch (XC(opinfo & OPCLSMASK)) { |
@@ -2655,6 +2729,7 @@ static var *evaluate(node *op, var *res) | |||
2655 | 2729 | ||
2656 | /* test pattern */ | 2730 | /* test pattern */ |
2657 | case XC( OC_TEST ): | 2731 | case XC( OC_TEST ): |
2732 | debug_printf_eval("TEST\n"); | ||
2658 | if ((op1->info & OPCLSMASK) == OC_COMMA) { | 2733 | if ((op1->info & OPCLSMASK) == OC_COMMA) { |
2659 | /* it's range pattern */ | 2734 | /* it's range pattern */ |
2660 | if ((opinfo & OF_CHECKED) || ptest(op1->l.n)) { | 2735 | if ((opinfo & OF_CHECKED) || ptest(op1->l.n)) { |
@@ -2672,25 +2747,32 @@ static var *evaluate(node *op, var *res) | |||
2672 | 2747 | ||
2673 | /* just evaluate an expression, also used as unconditional jump */ | 2748 | /* just evaluate an expression, also used as unconditional jump */ |
2674 | case XC( OC_EXEC ): | 2749 | case XC( OC_EXEC ): |
2750 | debug_printf_eval("EXEC\n"); | ||
2675 | break; | 2751 | break; |
2676 | 2752 | ||
2677 | /* branch, used in if-else and various loops */ | 2753 | /* branch, used in if-else and various loops */ |
2678 | case XC( OC_BR ): | 2754 | case XC( OC_BR ): |
2755 | debug_printf_eval("BR\n"); | ||
2679 | op = istrue(L.v) ? op->a.n : op->r.n; | 2756 | op = istrue(L.v) ? op->a.n : op->r.n; |
2680 | break; | 2757 | break; |
2681 | 2758 | ||
2682 | /* initialize for-in loop */ | 2759 | /* initialize for-in loop */ |
2683 | case XC( OC_WALKINIT ): | 2760 | case XC( OC_WALKINIT ): |
2761 | debug_printf_eval("WALKINIT\n"); | ||
2684 | hashwalk_init(L.v, iamarray(R.v)); | 2762 | hashwalk_init(L.v, iamarray(R.v)); |
2685 | break; | 2763 | break; |
2686 | 2764 | ||
2687 | /* get next array item */ | 2765 | /* get next array item */ |
2688 | case XC( OC_WALKNEXT ): | 2766 | case XC( OC_WALKNEXT ): |
2767 | debug_printf_eval("WALKNEXT\n"); | ||
2689 | op = hashwalk_next(L.v) ? op->a.n : op->r.n; | 2768 | op = hashwalk_next(L.v) ? op->a.n : op->r.n; |
2690 | break; | 2769 | break; |
2691 | 2770 | ||
2692 | case XC( OC_PRINT ): | 2771 | case XC( OC_PRINT ): |
2693 | case XC( OC_PRINTF ): { | 2772 | debug_printf_eval("PRINT /\n"); |
2773 | case XC( OC_PRINTF ): | ||
2774 | debug_printf_eval("PRINTF\n"); | ||
2775 | { | ||
2694 | FILE *F = stdout; | 2776 | FILE *F = stdout; |
2695 | IF_FEATURE_AWK_GNU_EXTENSIONS(int len;) | 2777 | IF_FEATURE_AWK_GNU_EXTENSIONS(int len;) |
2696 | 2778 | ||
@@ -2745,22 +2827,28 @@ static var *evaluate(node *op, var *res) | |||
2745 | /* case XC( OC_DELETE ): - moved to happen before arg evaluation */ | 2827 | /* case XC( OC_DELETE ): - moved to happen before arg evaluation */ |
2746 | 2828 | ||
2747 | case XC( OC_NEWSOURCE ): | 2829 | case XC( OC_NEWSOURCE ): |
2830 | debug_printf_eval("NEWSOURCE\n"); | ||
2748 | g_progname = op->l.new_progname; | 2831 | g_progname = op->l.new_progname; |
2749 | break; | 2832 | break; |
2750 | 2833 | ||
2751 | case XC( OC_RETURN ): | 2834 | case XC( OC_RETURN ): |
2835 | debug_printf_eval("RETURN\n"); | ||
2752 | copyvar(res, L.v); | 2836 | copyvar(res, L.v); |
2753 | break; | 2837 | break; |
2754 | 2838 | ||
2755 | case XC( OC_NEXTFILE ): | 2839 | case XC( OC_NEXTFILE ): |
2840 | debug_printf_eval("NEXTFILE\n"); | ||
2756 | nextfile = TRUE; | 2841 | nextfile = TRUE; |
2757 | case XC( OC_NEXT ): | 2842 | case XC( OC_NEXT ): |
2843 | debug_printf_eval("NEXT\n"); | ||
2758 | nextrec = TRUE; | 2844 | nextrec = TRUE; |
2759 | case XC( OC_DONE ): | 2845 | case XC( OC_DONE ): |
2846 | debug_printf_eval("DONE\n"); | ||
2760 | clrvar(res); | 2847 | clrvar(res); |
2761 | break; | 2848 | break; |
2762 | 2849 | ||
2763 | case XC( OC_EXIT ): | 2850 | case XC( OC_EXIT ): |
2851 | debug_printf_eval("EXIT\n"); | ||
2764 | awk_exit(L_d); | 2852 | awk_exit(L_d); |
2765 | 2853 | ||
2766 | /* -- recursive node type -- */ | 2854 | /* -- recursive node type -- */ |
@@ -2780,15 +2868,18 @@ static var *evaluate(node *op, var *res) | |||
2780 | break; | 2868 | break; |
2781 | 2869 | ||
2782 | case XC( OC_IN ): | 2870 | case XC( OC_IN ): |
2871 | debug_printf_eval("IN\n"); | ||
2783 | setvar_i(res, hash_search(iamarray(R.v), L.s) ? 1 : 0); | 2872 | setvar_i(res, hash_search(iamarray(R.v), L.s) ? 1 : 0); |
2784 | break; | 2873 | break; |
2785 | 2874 | ||
2786 | case XC( OC_REGEXP ): | 2875 | case XC( OC_REGEXP ): |
2876 | debug_printf_eval("REGEXP\n"); | ||
2787 | op1 = op; | 2877 | op1 = op; |
2788 | L.s = getvar_s(intvar[F0]); | 2878 | L.s = getvar_s(intvar[F0]); |
2789 | goto re_cont; | 2879 | goto re_cont; |
2790 | 2880 | ||
2791 | case XC( OC_MATCH ): | 2881 | case XC( OC_MATCH ): |
2882 | debug_printf_eval("MATCH\n"); | ||
2792 | op1 = op->r.n; | 2883 | op1 = op->r.n; |
2793 | re_cont: | 2884 | re_cont: |
2794 | { | 2885 | { |
@@ -2814,6 +2905,7 @@ static var *evaluate(node *op, var *res) | |||
2814 | break; | 2905 | break; |
2815 | 2906 | ||
2816 | case XC( OC_TERNARY ): | 2907 | case XC( OC_TERNARY ): |
2908 | debug_printf_eval("TERNARY\n"); | ||
2817 | if ((op->r.n->info & OPCLSMASK) != OC_COLON) | 2909 | if ((op->r.n->info & OPCLSMASK) != OC_COLON) |
2818 | syntax_error(EMSG_POSSIBLE_ERROR); | 2910 | syntax_error(EMSG_POSSIBLE_ERROR); |
2819 | res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res); | 2911 | res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res); |
@@ -2822,6 +2914,7 @@ static var *evaluate(node *op, var *res) | |||
2822 | case XC( OC_FUNC ): { | 2914 | case XC( OC_FUNC ): { |
2823 | var *vbeg, *v; | 2915 | var *vbeg, *v; |
2824 | const char *sv_progname; | 2916 | const char *sv_progname; |
2917 | debug_printf_eval("FUNC\n"); | ||
2825 | 2918 | ||
2826 | /* The body might be empty, still has to eval the args */ | 2919 | /* The body might be empty, still has to eval the args */ |
2827 | if (!op->r.n->info && !op->r.f->body.first) | 2920 | if (!op->r.n->info && !op->r.f->body.first) |
@@ -2851,7 +2944,10 @@ static var *evaluate(node *op, var *res) | |||
2851 | } | 2944 | } |
2852 | 2945 | ||
2853 | case XC( OC_GETLINE ): | 2946 | case XC( OC_GETLINE ): |
2854 | case XC( OC_PGETLINE ): { | 2947 | debug_printf_eval("GETLINE /\n"); |
2948 | case XC( OC_PGETLINE ): | ||
2949 | debug_printf_eval("PGETLINE\n"); | ||
2950 | { | ||
2855 | rstream *rsm; | 2951 | rstream *rsm; |
2856 | int i; | 2952 | int i; |
2857 | 2953 | ||
@@ -2892,6 +2988,7 @@ static var *evaluate(node *op, var *res) | |||
2892 | /* simple builtins */ | 2988 | /* simple builtins */ |
2893 | case XC( OC_FBLTIN ): { | 2989 | case XC( OC_FBLTIN ): { |
2894 | double R_d = R_d; /* for compiler */ | 2990 | double R_d = R_d; /* for compiler */ |
2991 | debug_printf_eval("FBLTIN\n"); | ||
2895 | 2992 | ||
2896 | switch (opn) { | 2993 | switch (opn) { |
2897 | case F_in: | 2994 | case F_in: |
@@ -3005,14 +3102,18 @@ static var *evaluate(node *op, var *res) | |||
3005 | } | 3102 | } |
3006 | 3103 | ||
3007 | case XC( OC_BUILTIN ): | 3104 | case XC( OC_BUILTIN ): |
3105 | debug_printf_eval("BUILTIN\n"); | ||
3008 | res = exec_builtin(op, res); | 3106 | res = exec_builtin(op, res); |
3009 | break; | 3107 | break; |
3010 | 3108 | ||
3011 | case XC( OC_SPRINTF ): | 3109 | case XC( OC_SPRINTF ): |
3110 | debug_printf_eval("SPRINTF\n"); | ||
3012 | setvar_p(res, awk_printf(op1, NULL)); | 3111 | setvar_p(res, awk_printf(op1, NULL)); |
3013 | break; | 3112 | break; |
3014 | 3113 | ||
3015 | case XC( OC_UNARY ): { | 3114 | case XC( OC_UNARY ): |
3115 | debug_printf_eval("UNARY\n"); | ||
3116 | { | ||
3016 | double Ld, R_d; | 3117 | double Ld, R_d; |
3017 | 3118 | ||
3018 | Ld = R_d = getvar_i(R.v); | 3119 | Ld = R_d = getvar_i(R.v); |
@@ -3042,7 +3143,9 @@ static var *evaluate(node *op, var *res) | |||
3042 | break; | 3143 | break; |
3043 | } | 3144 | } |
3044 | 3145 | ||
3045 | case XC( OC_FIELD ): { | 3146 | case XC( OC_FIELD ): |
3147 | debug_printf_eval("FIELD\n"); | ||
3148 | { | ||
3046 | int i = (int)getvar_i(R.v); | 3149 | int i = (int)getvar_i(R.v); |
3047 | if (i < 0) | 3150 | if (i < 0) |
3048 | syntax_error(EMSG_NEGATIVE_FIELD); | 3151 | syntax_error(EMSG_NEGATIVE_FIELD); |
@@ -3059,8 +3162,10 @@ static var *evaluate(node *op, var *res) | |||
3059 | 3162 | ||
3060 | /* concatenation (" ") and index joining (",") */ | 3163 | /* concatenation (" ") and index joining (",") */ |
3061 | case XC( OC_CONCAT ): | 3164 | case XC( OC_CONCAT ): |
3165 | debug_printf_eval("CONCAT /\n"); | ||
3062 | case XC( OC_COMMA ): { | 3166 | case XC( OC_COMMA ): { |
3063 | const char *sep = ""; | 3167 | const char *sep = ""; |
3168 | debug_printf_eval("COMMA\n"); | ||
3064 | if ((opinfo & OPCLSMASK) == OC_COMMA) | 3169 | if ((opinfo & OPCLSMASK) == OC_COMMA) |
3065 | sep = getvar_s(intvar[SUBSEP]); | 3170 | sep = getvar_s(intvar[SUBSEP]); |
3066 | setvar_p(res, xasprintf("%s%s%s", L.s, sep, R.s)); | 3171 | setvar_p(res, xasprintf("%s%s%s", L.s, sep, R.s)); |
@@ -3068,17 +3173,22 @@ static var *evaluate(node *op, var *res) | |||
3068 | } | 3173 | } |
3069 | 3174 | ||
3070 | case XC( OC_LAND ): | 3175 | case XC( OC_LAND ): |
3176 | debug_printf_eval("LAND\n"); | ||
3071 | setvar_i(res, istrue(L.v) ? ptest(op->r.n) : 0); | 3177 | setvar_i(res, istrue(L.v) ? ptest(op->r.n) : 0); |
3072 | break; | 3178 | break; |
3073 | 3179 | ||
3074 | case XC( OC_LOR ): | 3180 | case XC( OC_LOR ): |
3181 | debug_printf_eval("LOR\n"); | ||
3075 | setvar_i(res, istrue(L.v) ? 1 : ptest(op->r.n)); | 3182 | setvar_i(res, istrue(L.v) ? 1 : ptest(op->r.n)); |
3076 | break; | 3183 | break; |
3077 | 3184 | ||
3078 | case XC( OC_BINARY ): | 3185 | case XC( OC_BINARY ): |
3079 | case XC( OC_REPLACE ): { | 3186 | debug_printf_eval("BINARY /\n"); |
3187 | case XC( OC_REPLACE ): | ||
3188 | debug_printf_eval("REPLACE\n"); | ||
3189 | { | ||
3080 | double R_d = getvar_i(R.v); | 3190 | double R_d = getvar_i(R.v); |
3081 | debug_printf_eval("BINARY/REPLACE: R_d:%f opn:%c\n", R_d, opn); | 3191 | debug_printf_eval("R_d:%f opn:%c\n", R_d, opn); |
3082 | switch (opn) { | 3192 | switch (opn) { |
3083 | case '+': | 3193 | case '+': |
3084 | L_d += R_d; | 3194 | L_d += R_d; |
@@ -3114,6 +3224,7 @@ static var *evaluate(node *op, var *res) | |||
3114 | case XC( OC_COMPARE ): { | 3224 | case XC( OC_COMPARE ): { |
3115 | int i = i; /* for compiler */ | 3225 | int i = i; /* for compiler */ |
3116 | double Ld; | 3226 | double Ld; |
3227 | debug_printf_eval("COMPARE\n"); | ||
3117 | 3228 | ||
3118 | if (is_numeric(L.v) && is_numeric(R.v)) { | 3229 | if (is_numeric(L.v) && is_numeric(R.v)) { |
3119 | Ld = getvar_i(L.v) - getvar_i(R.v); | 3230 | Ld = getvar_i(L.v) - getvar_i(R.v); |
@@ -3162,20 +3273,19 @@ static var *evaluate(node *op, var *res) | |||
3162 | 3273 | ||
3163 | static int awk_exit(int r) | 3274 | static int awk_exit(int r) |
3164 | { | 3275 | { |
3165 | var tv; | ||
3166 | unsigned i; | 3276 | unsigned i; |
3167 | hash_item *hi; | ||
3168 | |||
3169 | zero_out_var(&tv); | ||
3170 | 3277 | ||
3171 | if (!exiting) { | 3278 | if (!exiting) { |
3279 | var tv; | ||
3172 | exiting = TRUE; | 3280 | exiting = TRUE; |
3173 | nextrec = FALSE; | 3281 | nextrec = FALSE; |
3282 | zero_out_var(&tv); | ||
3174 | evaluate(endseq.first, &tv); | 3283 | evaluate(endseq.first, &tv); |
3175 | } | 3284 | } |
3176 | 3285 | ||
3177 | /* waiting for children */ | 3286 | /* waiting for children */ |
3178 | for (i = 0; i < fdhash->csize; i++) { | 3287 | for (i = 0; i < fdhash->csize; i++) { |
3288 | hash_item *hi; | ||
3179 | hi = fdhash->items[i]; | 3289 | hi = fdhash->items[i]; |
3180 | while (hi) { | 3290 | while (hi) { |
3181 | if (hi->data.rs.F && hi->data.rs.is_pipe) | 3291 | if (hi->data.rs.F && hi->data.rs.is_pipe) |
@@ -3255,12 +3365,8 @@ int awk_main(int argc UNUSED_PARAM, char **argv) | |||
3255 | #if ENABLE_FEATURE_AWK_GNU_EXTENSIONS | 3365 | #if ENABLE_FEATURE_AWK_GNU_EXTENSIONS |
3256 | llist_t *list_e = NULL; | 3366 | llist_t *list_e = NULL; |
3257 | #endif | 3367 | #endif |
3258 | int i, j; | 3368 | int i; |
3259 | var *v; | ||
3260 | var tv; | 3369 | var tv; |
3261 | char **envp; | ||
3262 | char *vnames = (char *)vNames; /* cheat */ | ||
3263 | char *vvalues = (char *)vValues; | ||
3264 | 3370 | ||
3265 | INIT_G(); | 3371 | INIT_G(); |
3266 | 3372 | ||
@@ -3269,8 +3375,6 @@ int awk_main(int argc UNUSED_PARAM, char **argv) | |||
3269 | if (ENABLE_LOCALE_SUPPORT) | 3375 | if (ENABLE_LOCALE_SUPPORT) |
3270 | setlocale(LC_NUMERIC, "C"); | 3376 | setlocale(LC_NUMERIC, "C"); |
3271 | 3377 | ||
3272 | zero_out_var(&tv); | ||
3273 | |||
3274 | /* allocate global buffer */ | 3378 | /* allocate global buffer */ |
3275 | g_buf = xmalloc(MAXVARFMT + 1); | 3379 | g_buf = xmalloc(MAXVARFMT + 1); |
3276 | 3380 | ||
@@ -3280,16 +3384,21 @@ int awk_main(int argc UNUSED_PARAM, char **argv) | |||
3280 | fnhash = hash_init(); | 3384 | fnhash = hash_init(); |
3281 | 3385 | ||
3282 | /* initialize variables */ | 3386 | /* initialize variables */ |
3283 | for (i = 0; *vnames; i++) { | 3387 | { |
3284 | intvar[i] = v = newvar(nextword(&vnames)); | 3388 | char *vnames = (char *)vNames; /* cheat */ |
3285 | if (*vvalues != '\377') | 3389 | char *vvalues = (char *)vValues; |
3286 | setvar_s(v, nextword(&vvalues)); | 3390 | for (i = 0; *vnames; i++) { |
3287 | else | 3391 | var *v; |
3288 | setvar_i(v, 0); | 3392 | intvar[i] = v = newvar(nextword(&vnames)); |
3289 | 3393 | if (*vvalues != '\377') | |
3290 | if (*vnames == '*') { | 3394 | setvar_s(v, nextword(&vvalues)); |
3291 | v->type |= VF_SPECIAL; | 3395 | else |
3292 | vnames++; | 3396 | setvar_i(v, 0); |
3397 | |||
3398 | if (*vnames == '*') { | ||
3399 | v->type |= VF_SPECIAL; | ||
3400 | vnames++; | ||
3401 | } | ||
3293 | } | 3402 | } |
3294 | } | 3403 | } |
3295 | 3404 | ||
@@ -3301,16 +3410,19 @@ int awk_main(int argc UNUSED_PARAM, char **argv) | |||
3301 | newfile("/dev/stderr")->F = stderr; | 3410 | newfile("/dev/stderr")->F = stderr; |
3302 | 3411 | ||
3303 | /* Huh, people report that sometimes environ is NULL. Oh well. */ | 3412 | /* Huh, people report that sometimes environ is NULL. Oh well. */ |
3304 | if (environ) for (envp = environ; *envp; envp++) { | 3413 | if (environ) { |
3305 | /* environ is writable, thus we don't strdup it needlessly */ | 3414 | char **envp; |
3306 | char *s = *envp; | 3415 | for (envp = environ; *envp; envp++) { |
3307 | char *s1 = strchr(s, '='); | 3416 | /* environ is writable, thus we don't strdup it needlessly */ |
3308 | if (s1) { | 3417 | char *s = *envp; |
3309 | *s1 = '\0'; | 3418 | char *s1 = strchr(s, '='); |
3310 | /* Both findvar and setvar_u take const char* | 3419 | if (s1) { |
3311 | * as 2nd arg -> environment is not trashed */ | 3420 | *s1 = '\0'; |
3312 | setvar_u(findvar(iamarray(intvar[ENVIRON]), s), s1 + 1); | 3421 | /* Both findvar and setvar_u take const char* |
3313 | *s1 = '='; | 3422 | * as 2nd arg -> environment is not trashed */ |
3423 | setvar_u(findvar(iamarray(intvar[ENVIRON]), s), s1 + 1); | ||
3424 | *s1 = '='; | ||
3425 | } | ||
3314 | } | 3426 | } |
3315 | } | 3427 | } |
3316 | opt = getopt32(argv, OPTSTR_AWK, &opt_F, &list_v, &list_f, IF_FEATURE_AWK_GNU_EXTENSIONS(&list_e,) NULL); | 3428 | opt = getopt32(argv, OPTSTR_AWK, &opt_F, &list_v, &list_f, IF_FEATURE_AWK_GNU_EXTENSIONS(&list_e,) NULL); |
@@ -3327,30 +3439,43 @@ int awk_main(int argc UNUSED_PARAM, char **argv) | |||
3327 | bb_show_usage(); | 3439 | bb_show_usage(); |
3328 | } | 3440 | } |
3329 | while (list_f) { | 3441 | while (list_f) { |
3330 | char *s = NULL; | 3442 | int fd; |
3331 | FILE *from_file; | 3443 | char *s; |
3332 | 3444 | ||
3333 | g_progname = llist_pop(&list_f); | 3445 | g_progname = llist_pop(&list_f); |
3334 | from_file = xfopen_stdin(g_progname); | 3446 | fd = xopen_stdin(g_progname); |
3335 | /* one byte is reserved for some trick in next_token */ | 3447 | /* 1st byte is reserved for "move name one char back" trick in next_token */ |
3336 | for (i = j = 1; j > 0; i += j) { | 3448 | i = 1; |
3337 | s = xrealloc(s, i + 4096); | 3449 | s = NULL; |
3338 | j = fread(s + i, 1, 4094, from_file); | 3450 | for (;;) { |
3451 | int sz; | ||
3452 | s = xrealloc(s, i + 1000); | ||
3453 | sz = safe_read(fd, s + i, 1000); | ||
3454 | if (sz <= 0) | ||
3455 | break; | ||
3456 | i += sz; | ||
3339 | } | 3457 | } |
3458 | s = xrealloc(s, i + 1); /* trim unused 999 bytes */ | ||
3340 | s[i] = '\0'; | 3459 | s[i] = '\0'; |
3341 | fclose(from_file); | 3460 | close(fd); |
3342 | parse_program(s + 1); | 3461 | parse_program(s + 1); |
3343 | free(s); | 3462 | free(s); |
3344 | } | 3463 | } |
3345 | g_progname = "cmd. line"; | 3464 | g_progname = "cmd. line"; |
3346 | #if ENABLE_FEATURE_AWK_GNU_EXTENSIONS | 3465 | #if ENABLE_FEATURE_AWK_GNU_EXTENSIONS |
3347 | while (list_e) { | 3466 | while (list_e) { |
3467 | /* NB: "move name one char back" trick in next_token | ||
3468 | * can use argv[i][-1] here. | ||
3469 | */ | ||
3348 | parse_program(llist_pop(&list_e)); | 3470 | parse_program(llist_pop(&list_e)); |
3349 | } | 3471 | } |
3350 | #endif | 3472 | #endif |
3351 | if (!(opt & (OPT_f | OPT_e))) { | 3473 | if (!(opt & (OPT_f | OPT_e))) { |
3352 | if (!*argv) | 3474 | if (!*argv) |
3353 | bb_show_usage(); | 3475 | bb_show_usage(); |
3476 | /* NB: "move name one char back" trick in next_token | ||
3477 | * can use argv[i][-1] here. | ||
3478 | */ | ||
3354 | parse_program(*argv++); | 3479 | parse_program(*argv++); |
3355 | } | 3480 | } |
3356 | 3481 | ||
@@ -3361,6 +3486,7 @@ int awk_main(int argc UNUSED_PARAM, char **argv) | |||
3361 | setari_u(intvar[ARGV], ++i, *argv++); | 3486 | setari_u(intvar[ARGV], ++i, *argv++); |
3362 | setvar_i(intvar[ARGC], i + 1); | 3487 | setvar_i(intvar[ARGC], i + 1); |
3363 | 3488 | ||
3489 | zero_out_var(&tv); | ||
3364 | evaluate(beginseq.first, &tv); | 3490 | evaluate(beginseq.first, &tv); |
3365 | if (!mainseq.first && !endseq.first) | 3491 | if (!mainseq.first && !endseq.first) |
3366 | awk_exit(EXIT_SUCCESS); | 3492 | awk_exit(EXIT_SUCCESS); |
diff --git a/editors/cmp.c b/editors/cmp.c index 6e27a841a..e106d814e 100644 --- a/editors/cmp.c +++ b/editors/cmp.c | |||
@@ -18,7 +18,7 @@ | |||
18 | //kbuild:lib-$(CONFIG_CMP) += cmp.o | 18 | //kbuild:lib-$(CONFIG_CMP) += cmp.o |
19 | 19 | ||
20 | //usage:#define cmp_trivial_usage | 20 | //usage:#define cmp_trivial_usage |
21 | //usage: "[-l] [-s] FILE1 [FILE2" IF_DESKTOP(" [SKIP1 [SKIP2]]") "]" | 21 | //usage: "[-ls] FILE1 [FILE2" IF_DESKTOP(" [SKIP1 [SKIP2]]") "]" |
22 | //usage:#define cmp_full_usage "\n\n" | 22 | //usage:#define cmp_full_usage "\n\n" |
23 | //usage: "Compare FILE1 with FILE2 (or stdin)\n" | 23 | //usage: "Compare FILE1 with FILE2 (or stdin)\n" |
24 | //usage: "\n -l Write the byte numbers (decimal) and values (octal)" | 24 | //usage: "\n -l Write the byte numbers (decimal) and values (octal)" |
diff --git a/editors/sed.c b/editors/sed.c index b269b58d8..523fb8dba 100644 --- a/editors/sed.c +++ b/editors/sed.c | |||
@@ -70,7 +70,7 @@ | |||
70 | //usage:#define sed_full_usage "\n\n" | 70 | //usage:#define sed_full_usage "\n\n" |
71 | //usage: " -e CMD Add CMD to sed commands to be executed" | 71 | //usage: " -e CMD Add CMD to sed commands to be executed" |
72 | //usage: "\n -f FILE Add FILE contents to sed commands to be executed" | 72 | //usage: "\n -f FILE Add FILE contents to sed commands to be executed" |
73 | //usage: "\n -i[SFX] Edit files in-place (otherwise sends to stdout)" | 73 | //usage: "\n -i[SFX] Edit files in-place (otherwise write to stdout)" |
74 | //usage: "\n Optionally back files up, appending SFX" | 74 | //usage: "\n Optionally back files up, appending SFX" |
75 | //usage: "\n -n Suppress automatic printing of pattern space" | 75 | //usage: "\n -n Suppress automatic printing of pattern space" |
76 | //usage: "\n -r,-E Use extended regex syntax" | 76 | //usage: "\n -r,-E Use extended regex syntax" |
diff --git a/editors/vi.c b/editors/vi.c index a4d6b21b4..89c567f10 100644 --- a/editors/vi.c +++ b/editors/vi.c | |||
@@ -181,7 +181,7 @@ | |||
181 | //kbuild:lib-$(CONFIG_VI) += vi.o | 181 | //kbuild:lib-$(CONFIG_VI) += vi.o |
182 | 182 | ||
183 | //usage:#define vi_trivial_usage | 183 | //usage:#define vi_trivial_usage |
184 | //usage: IF_FEATURE_VI_COLON("[-c CMD] ")IF_FEATURE_VI_READONLY("[-R] ")"[FILE]..." | 184 | //usage: IF_FEATURE_VI_COLON("[-c CMD] ")IF_FEATURE_VI_READONLY("[-R] ")"[-H] [FILE]..." |
185 | //usage:#define vi_full_usage "\n\n" | 185 | //usage:#define vi_full_usage "\n\n" |
186 | //usage: "Edit FILE\n" | 186 | //usage: "Edit FILE\n" |
187 | //usage: IF_FEATURE_VI_COLON( | 187 | //usage: IF_FEATURE_VI_COLON( |
@@ -191,6 +191,7 @@ | |||
191 | //usage: "\n -R Read-only" | 191 | //usage: "\n -R Read-only" |
192 | //usage: ) | 192 | //usage: ) |
193 | //usage: "\n -H List available features" | 193 | //usage: "\n -H List available features" |
194 | // note: non-standard, "vim -H" is Hebrew mode (bidi support) | ||
194 | 195 | ||
195 | #include "libbb.h" | 196 | #include "libbb.h" |
196 | // Should be after libbb.h: on some systems regex.h needs sys/types.h: | 197 | // Should be after libbb.h: on some systems regex.h needs sys/types.h: |
@@ -377,6 +378,7 @@ struct globals { | |||
377 | #if ENABLE_FEATURE_VI_SETOPTS | 378 | #if ENABLE_FEATURE_VI_SETOPTS |
378 | int indentcol; // column of recently autoindent, 0 or -1 | 379 | int indentcol; // column of recently autoindent, 0 or -1 |
379 | #endif | 380 | #endif |
381 | smallint cmd_error; | ||
380 | 382 | ||
381 | // former statics | 383 | // former statics |
382 | #if ENABLE_FEATURE_VI_YANKMARK | 384 | #if ENABLE_FEATURE_VI_YANKMARK |
@@ -503,6 +505,7 @@ struct globals { | |||
503 | #define dotcnt (G.dotcnt ) | 505 | #define dotcnt (G.dotcnt ) |
504 | #define last_search_pattern (G.last_search_pattern) | 506 | #define last_search_pattern (G.last_search_pattern) |
505 | #define indentcol (G.indentcol ) | 507 | #define indentcol (G.indentcol ) |
508 | #define cmd_error (G.cmd_error ) | ||
506 | 509 | ||
507 | #define edit_file__cur_line (G.edit_file__cur_line) | 510 | #define edit_file__cur_line (G.edit_file__cur_line) |
508 | #define refresh__old_offset (G.refresh__old_offset) | 511 | #define refresh__old_offset (G.refresh__old_offset) |
@@ -537,6 +540,7 @@ struct globals { | |||
537 | last_modified_count = -1; \ | 540 | last_modified_count = -1; \ |
538 | /* "" but has space for 2 chars: */ \ | 541 | /* "" but has space for 2 chars: */ \ |
539 | IF_FEATURE_VI_SEARCH(last_search_pattern = xzalloc(2);) \ | 542 | IF_FEATURE_VI_SEARCH(last_search_pattern = xzalloc(2);) \ |
543 | tabstop = 8; \ | ||
540 | } while (0) | 544 | } while (0) |
541 | 545 | ||
542 | #if ENABLE_FEATURE_VI_CRASHME | 546 | #if ENABLE_FEATURE_VI_CRASHME |
@@ -1122,6 +1126,7 @@ static void indicate_error(void) | |||
1122 | if (crashme > 0) | 1126 | if (crashme > 0) |
1123 | return; | 1127 | return; |
1124 | #endif | 1128 | #endif |
1129 | cmd_error = TRUE; | ||
1125 | if (!err_method) { | 1130 | if (!err_method) { |
1126 | write1(ESC_BELL); | 1131 | write1(ESC_BELL); |
1127 | } else { | 1132 | } else { |
@@ -2191,13 +2196,13 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p' | |||
2191 | cmdcnt = 0; | 2196 | cmdcnt = 0; |
2192 | end_cmd_q(); // stop adding to q | 2197 | end_cmd_q(); // stop adding to q |
2193 | last_status_cksum = 0; // force status update | 2198 | last_status_cksum = 0; // force status update |
2194 | if ((p[-1] != '\n') && (dot > text)) { | 2199 | if ((dot > text) && (p[-1] != '\n')) { |
2195 | p--; | 2200 | p--; |
2196 | } | 2201 | } |
2197 | #if ENABLE_FEATURE_VI_SETOPTS | 2202 | #if ENABLE_FEATURE_VI_SETOPTS |
2198 | if (autoindent) { | 2203 | if (autoindent) { |
2199 | len = indent_len(bol); | 2204 | len = indent_len(bol); |
2200 | if (len && get_column(bol + len) == indentcol) { | 2205 | if (len && get_column(bol + len) == indentcol && bol[len] == '\n') { |
2201 | // remove autoindent from otherwise empty line | 2206 | // remove autoindent from otherwise empty line |
2202 | text_hole_delete(bol, bol + len - 1, undo); | 2207 | text_hole_delete(bol, bol + len - 1, undo); |
2203 | p = bol; | 2208 | p = bol; |
@@ -2437,9 +2442,7 @@ static char *char_search(char *p, const char *pat, int dir_and_range) | |||
2437 | struct re_pattern_buffer preg; | 2442 | struct re_pattern_buffer preg; |
2438 | const char *err; | 2443 | const char *err; |
2439 | char *q; | 2444 | char *q; |
2440 | int i; | 2445 | int i, size, range, start; |
2441 | int size; | ||
2442 | int range; | ||
2443 | 2446 | ||
2444 | re_syntax_options = RE_SYNTAX_POSIX_EXTENDED; | 2447 | re_syntax_options = RE_SYNTAX_POSIX_EXTENDED; |
2445 | if (ignorecase) | 2448 | if (ignorecase) |
@@ -2464,31 +2467,26 @@ static char *char_search(char *p, const char *pat, int dir_and_range) | |||
2464 | 2467 | ||
2465 | // RANGE could be negative if we are searching backwards | 2468 | // RANGE could be negative if we are searching backwards |
2466 | range = q - p; | 2469 | range = q - p; |
2467 | q = p; | ||
2468 | size = range; | ||
2469 | if (range < 0) { | 2470 | if (range < 0) { |
2470 | size = -size; | 2471 | size = -range; |
2471 | q = p - size; | 2472 | start = size; |
2472 | if (q < text) | 2473 | } else { |
2473 | q = text; | 2474 | size = range; |
2475 | start = 0; | ||
2474 | } | 2476 | } |
2477 | q = p - start; | ||
2478 | if (q < text) | ||
2479 | q = text; | ||
2475 | // search for the compiled pattern, preg, in p[] | 2480 | // search for the compiled pattern, preg, in p[] |
2476 | // range < 0: search backward | 2481 | // range < 0, start == size: search backward |
2477 | // range > 0: search forward | 2482 | // range > 0, start == 0: search forward |
2478 | // 0 < start < size | ||
2479 | // re_search() < 0: not found or error | 2483 | // re_search() < 0: not found or error |
2480 | // re_search() >= 0: index of found pattern | 2484 | // re_search() >= 0: index of found pattern |
2481 | // struct pattern char int int int struct reg | 2485 | // struct pattern char int int int struct reg |
2482 | // re_search(*pattern_buffer, *string, size, start, range, *regs) | 2486 | // re_search(*pattern_buffer, *string, size, start, range, *regs) |
2483 | i = re_search(&preg, q, size, /*start:*/ 0, range, /*struct re_registers*:*/ NULL); | 2487 | i = re_search(&preg, q, size, start, range, /*struct re_registers*:*/ NULL); |
2484 | regfree(&preg); | 2488 | regfree(&preg); |
2485 | if (i < 0) | 2489 | return i < 0 ? NULL : q + i; |
2486 | return NULL; | ||
2487 | if (dir_and_range > 0) // FORWARD? | ||
2488 | p = p + i; | ||
2489 | else | ||
2490 | p = p - i; | ||
2491 | return p; | ||
2492 | } | 2490 | } |
2493 | # else | 2491 | # else |
2494 | # if ENABLE_FEATURE_VI_SETOPTS | 2492 | # if ENABLE_FEATURE_VI_SETOPTS |
@@ -3063,12 +3061,10 @@ static void colon(char *buf) | |||
3063 | status_line_bold("No current filename"); | 3061 | status_line_bold("No current filename"); |
3064 | goto ret; | 3062 | goto ret; |
3065 | } | 3063 | } |
3066 | if (e < 0) { // no addr given- read after current line | 3064 | if (e == 0) { // user said ":0r foo" |
3067 | q = begin_line(dot); | ||
3068 | } else if (e == 0) { // user said ":0r foo" | ||
3069 | q = text; | 3065 | q = text; |
3070 | } else { // addr given- read after that line | 3066 | } else { // read after given line or current line if none given |
3071 | q = next_line(find_line(e)); | 3067 | q = next_line(e > 0 ? find_line(e) : dot); |
3072 | // read after last line | 3068 | // read after last line |
3073 | if (q == end-1) | 3069 | if (q == end-1) |
3074 | ++q; | 3070 | ++q; |
@@ -3170,6 +3166,18 @@ static void colon(char *buf) | |||
3170 | } | 3166 | } |
3171 | len_R = strlen(R); | 3167 | len_R = strlen(R); |
3172 | 3168 | ||
3169 | if (len_F) { // save "find" as last search pattern | ||
3170 | free(last_search_pattern); | ||
3171 | last_search_pattern = xstrdup(F - 1); | ||
3172 | last_search_pattern[0] = '/'; | ||
3173 | } else if (last_search_pattern[1] == '\0') { | ||
3174 | status_line_bold("No previous search"); | ||
3175 | goto ret; | ||
3176 | } else { | ||
3177 | F = last_search_pattern + 1; | ||
3178 | len_F = strlen(F); | ||
3179 | } | ||
3180 | |||
3173 | if (e < 0) { // no addr given | 3181 | if (e < 0) { // no addr given |
3174 | q = begin_line(dot); // start with cur line | 3182 | q = begin_line(dot); // start with cur line |
3175 | r = end_line(dot); | 3183 | r = end_line(dot); |
@@ -3465,8 +3473,11 @@ static int find_range(char **start, char **stop, int cmd) | |||
3465 | #endif | 3473 | #endif |
3466 | // these cmds operate on whole lines | 3474 | // these cmds operate on whole lines |
3467 | buftype = WHOLE; | 3475 | buftype = WHOLE; |
3468 | if (--cmdcnt > 0) | 3476 | if (--cmdcnt > 0) { |
3469 | do_cmd('j'); | 3477 | do_cmd('j'); |
3478 | if (cmd_error) | ||
3479 | buftype = -1; | ||
3480 | } | ||
3470 | } else if (strchr("^%$0bBeEfFtThnN/?|{}\b\177", c)) { | 3481 | } else if (strchr("^%$0bBeEfFtThnN/?|{}\b\177", c)) { |
3471 | // Most operate on char positions within a line. Of those that | 3482 | // Most operate on char positions within a line. Of those that |
3472 | // don't '%' needs no special treatment, search commands are | 3483 | // don't '%' needs no special treatment, search commands are |
@@ -3496,6 +3507,8 @@ static int find_range(char **start, char **stop, int cmd) | |||
3496 | // these operate on whole lines | 3507 | // these operate on whole lines |
3497 | buftype = WHOLE; | 3508 | buftype = WHOLE; |
3498 | do_cmd(c); // execute movement cmd | 3509 | do_cmd(c); // execute movement cmd |
3510 | if (cmd_error) | ||
3511 | buftype = -1; | ||
3499 | } else if (c == ' ' || c == 'l') { | 3512 | } else if (c == ' ' || c == 'l') { |
3500 | // forward motion by character | 3513 | // forward motion by character |
3501 | int tmpcnt = (cmdcnt ?: 1); | 3514 | int tmpcnt = (cmdcnt ?: 1); |
@@ -3581,6 +3594,7 @@ static void do_cmd(int c) | |||
3581 | // p = q = save_dot = buf; // quiet the compiler | 3594 | // p = q = save_dot = buf; // quiet the compiler |
3582 | memset(buf, '\0', sizeof(buf)); | 3595 | memset(buf, '\0', sizeof(buf)); |
3583 | keep_index = FALSE; | 3596 | keep_index = FALSE; |
3597 | cmd_error = FALSE; | ||
3584 | 3598 | ||
3585 | show_status_line(); | 3599 | show_status_line(); |
3586 | 3600 | ||
@@ -3701,24 +3715,30 @@ static void do_cmd(int c) | |||
3701 | case 10: // Newline ^J | 3715 | case 10: // Newline ^J |
3702 | case 'j': // j- goto next line, same col | 3716 | case 'j': // j- goto next line, same col |
3703 | case KEYCODE_DOWN: // cursor key Down | 3717 | case KEYCODE_DOWN: // cursor key Down |
3718 | case 13: // Carriage Return ^M | ||
3719 | case '+': // +- goto next line | ||
3720 | q = dot; | ||
3704 | do { | 3721 | do { |
3705 | dot_next(); // go to next B-o-l | 3722 | p = next_line(q); |
3723 | if (p == end_line(q)) { | ||
3724 | indicate_error(); | ||
3725 | goto dc1; | ||
3726 | } | ||
3727 | q = p; | ||
3706 | } while (--cmdcnt > 0); | 3728 | } while (--cmdcnt > 0); |
3707 | // try to stay in saved column | 3729 | dot = q; |
3708 | dot = cindex == C_END ? end_line(dot) : move_to_col(dot, cindex); | 3730 | if (c == 13 || c == '+') { |
3709 | keep_index = TRUE; | 3731 | dot_skip_over_ws(); |
3732 | } else { | ||
3733 | // try to stay in saved column | ||
3734 | dot = cindex == C_END ? end_line(dot) : move_to_col(dot, cindex); | ||
3735 | keep_index = TRUE; | ||
3736 | } | ||
3710 | break; | 3737 | break; |
3711 | case 12: // ctrl-L force redraw whole screen | 3738 | case 12: // ctrl-L force redraw whole screen |
3712 | case 18: // ctrl-R force redraw | 3739 | case 18: // ctrl-R force redraw |
3713 | redraw(TRUE); // this will redraw the entire display | 3740 | redraw(TRUE); // this will redraw the entire display |
3714 | break; | 3741 | break; |
3715 | case 13: // Carriage Return ^M | ||
3716 | case '+': // +- goto next line | ||
3717 | do { | ||
3718 | dot_next(); | ||
3719 | } while (--cmdcnt > 0); | ||
3720 | dot_skip_over_ws(); | ||
3721 | break; | ||
3722 | case 21: // ctrl-U scroll up half screen | 3742 | case 21: // ctrl-U scroll up half screen |
3723 | dot_scroll((rows - 2) / 2, -1); | 3743 | dot_scroll((rows - 2) / 2, -1); |
3724 | break; | 3744 | break; |
@@ -3759,6 +3779,8 @@ static void do_cmd(int c) | |||
3759 | dot = q; | 3779 | dot = q; |
3760 | dot_begin(); // go to B-o-l | 3780 | dot_begin(); // go to B-o-l |
3761 | dot_skip_over_ws(); | 3781 | dot_skip_over_ws(); |
3782 | } else { | ||
3783 | indicate_error(); | ||
3762 | } | 3784 | } |
3763 | } else if (c1 == '\'') { // goto previous context | 3785 | } else if (c1 == '\'') { // goto previous context |
3764 | dot = swap_context(dot); // swap current and previous context | 3786 | dot = swap_context(dot); // swap current and previous context |
@@ -3884,12 +3906,6 @@ static void do_cmd(int c) | |||
3884 | case ',': // ,- repeat latest search in opposite direction | 3906 | case ',': // ,- repeat latest search in opposite direction |
3885 | dot_to_char(c != ',' ? last_search_cmd : last_search_cmd ^ 0x20); | 3907 | dot_to_char(c != ',' ? last_search_cmd : last_search_cmd ^ 0x20); |
3886 | break; | 3908 | break; |
3887 | case '-': // -- goto prev line | ||
3888 | do { | ||
3889 | dot_prev(); | ||
3890 | } while (--cmdcnt > 0); | ||
3891 | dot_skip_over_ws(); | ||
3892 | break; | ||
3893 | #if ENABLE_FEATURE_VI_DOT_CMD | 3909 | #if ENABLE_FEATURE_VI_DOT_CMD |
3894 | case '.': // .- repeat the last modifying command | 3910 | case '.': // .- repeat the last modifying command |
3895 | // Stuff the last_modifying_cmd back into stdin | 3911 | // Stuff the last_modifying_cmd back into stdin |
@@ -4095,9 +4111,10 @@ static void do_cmd(int c) | |||
4095 | if (cmdcnt > (rows - 1)) { | 4111 | if (cmdcnt > (rows - 1)) { |
4096 | cmdcnt = (rows - 1); | 4112 | cmdcnt = (rows - 1); |
4097 | } | 4113 | } |
4098 | if (--cmdcnt > 0) { | 4114 | while (--cmdcnt > 0) { |
4099 | do_cmd('+'); | 4115 | dot_next(); |
4100 | } | 4116 | } |
4117 | dot_begin(); | ||
4101 | dot_skip_over_ws(); | 4118 | dot_skip_over_ws(); |
4102 | break; | 4119 | break; |
4103 | case 'I': // I- insert before first non-blank | 4120 | case 'I': // I- insert before first non-blank |
@@ -4134,8 +4151,8 @@ static void do_cmd(int c) | |||
4134 | if (cmdcnt > (rows - 1)) { | 4151 | if (cmdcnt > (rows - 1)) { |
4135 | cmdcnt = (rows - 1); | 4152 | cmdcnt = (rows - 1); |
4136 | } | 4153 | } |
4137 | if (--cmdcnt > 0) { | 4154 | while (--cmdcnt > 0) { |
4138 | do_cmd('-'); | 4155 | dot_prev(); |
4139 | } | 4156 | } |
4140 | dot_begin(); | 4157 | dot_begin(); |
4141 | dot_skip_over_ws(); | 4158 | dot_skip_over_ws(); |
@@ -4300,12 +4317,24 @@ static void do_cmd(int c) | |||
4300 | } | 4317 | } |
4301 | case 'k': // k- goto prev line, same col | 4318 | case 'k': // k- goto prev line, same col |
4302 | case KEYCODE_UP: // cursor key Up | 4319 | case KEYCODE_UP: // cursor key Up |
4320 | case '-': // -- goto prev line | ||
4321 | q = dot; | ||
4303 | do { | 4322 | do { |
4304 | dot_prev(); | 4323 | p = prev_line(q); |
4324 | if (p == begin_line(q)) { | ||
4325 | indicate_error(); | ||
4326 | goto dc1; | ||
4327 | } | ||
4328 | q = p; | ||
4305 | } while (--cmdcnt > 0); | 4329 | } while (--cmdcnt > 0); |
4306 | // try to stay in saved column | 4330 | dot = q; |
4307 | dot = cindex == C_END ? end_line(dot) : move_to_col(dot, cindex); | 4331 | if (c == '-') { |
4308 | keep_index = TRUE; | 4332 | dot_skip_over_ws(); |
4333 | } else { | ||
4334 | // try to stay in saved column | ||
4335 | dot = cindex == C_END ? end_line(dot) : move_to_col(dot, cindex); | ||
4336 | keep_index = TRUE; | ||
4337 | } | ||
4309 | break; | 4338 | break; |
4310 | case 'r': // r- replace the current char with user input | 4339 | case 'r': // r- replace the current char with user input |
4311 | c1 = get_one_char(); // get the replacement char | 4340 | c1 = get_one_char(); // get the replacement char |
@@ -4686,7 +4715,6 @@ static void edit_file(char *fn) | |||
4686 | 4715 | ||
4687 | cmd_mode = 0; // 0=command 1=insert 2='R'eplace | 4716 | cmd_mode = 0; // 0=command 1=insert 2='R'eplace |
4688 | cmdcnt = 0; | 4717 | cmdcnt = 0; |
4689 | tabstop = 8; | ||
4690 | offset = 0; // no horizontal offset | 4718 | offset = 0; // no horizontal offset |
4691 | c = '\0'; | 4719 | c = '\0'; |
4692 | #if ENABLE_FEATURE_VI_DOT_CMD | 4720 | #if ENABLE_FEATURE_VI_DOT_CMD |
@@ -4814,7 +4842,11 @@ int vi_main(int argc, char **argv) | |||
4814 | initial_cmds[0] = xstrndup(p, MAX_INPUT_LEN); | 4842 | initial_cmds[0] = xstrndup(p, MAX_INPUT_LEN); |
4815 | } | 4843 | } |
4816 | #endif | 4844 | #endif |
4817 | while ((c = getopt(argc, argv, "hCRH" IF_FEATURE_VI_COLON("c:"))) != -1) { | 4845 | while ((c = getopt(argc, argv, |
4846 | #if ENABLE_FEATURE_VI_CRASHME | ||
4847 | "C" | ||
4848 | #endif | ||
4849 | "RHh" IF_FEATURE_VI_COLON("c:"))) != -1) { | ||
4818 | switch (c) { | 4850 | switch (c) { |
4819 | #if ENABLE_FEATURE_VI_CRASHME | 4851 | #if ENABLE_FEATURE_VI_CRASHME |
4820 | case 'C': | 4852 | case 'C': |
diff --git a/findutils/grep.c b/findutils/grep.c index 10cca83e7..be4362ed0 100644 --- a/findutils/grep.c +++ b/findutils/grep.c | |||
@@ -57,14 +57,12 @@ | |||
57 | #include "common_bufsiz.h" | 57 | #include "common_bufsiz.h" |
58 | #include "xregex.h" | 58 | #include "xregex.h" |
59 | 59 | ||
60 | |||
61 | /* options */ | ||
62 | //usage:#define grep_trivial_usage | 60 | //usage:#define grep_trivial_usage |
63 | //usage: "[-HhnlLoqvsrRiwFE" | 61 | //usage: "[-HhnlLoqvsrRiwFE" |
64 | //usage: IF_EXTRA_COMPAT("z") | 62 | //usage: IF_EXTRA_COMPAT("z") |
65 | //usage: "] [-m N] " | 63 | //usage: "] [-m N] " |
66 | //usage: IF_FEATURE_GREP_CONTEXT("[-A/B/C N] ") | 64 | //usage: IF_FEATURE_GREP_CONTEXT("[-A|B|C N] ") |
67 | //usage: "PATTERN/-e PATTERN.../-f FILE [FILE]..." | 65 | //usage: "{ PATTERN | -e PATTERN... | -f FILE... } [FILE]..." |
68 | //usage:#define grep_full_usage "\n\n" | 66 | //usage:#define grep_full_usage "\n\n" |
69 | //usage: "Search for PATTERN in FILEs (or stdin)\n" | 67 | //usage: "Search for PATTERN in FILEs (or stdin)\n" |
70 | //usage: "\n -H Add 'filename:' prefix" | 68 | //usage: "\n -H Add 'filename:' prefix" |
diff --git a/include/bb_e2fs_defs.h b/include/bb_e2fs_defs.h index 3f5e3c45b..608cbf0b0 100644 --- a/include/bb_e2fs_defs.h +++ b/include/bb_e2fs_defs.h | |||
@@ -182,11 +182,12 @@ struct ext2_dx_countlimit { | |||
182 | #define EXT2_NOTAIL_FL 0x00008000 /* file tail should not be merged */ | 182 | #define EXT2_NOTAIL_FL 0x00008000 /* file tail should not be merged */ |
183 | #define EXT2_DIRSYNC_FL 0x00010000 /* Synchronous directory modifications */ | 183 | #define EXT2_DIRSYNC_FL 0x00010000 /* Synchronous directory modifications */ |
184 | #define EXT2_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ | 184 | #define EXT2_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ |
185 | #define EXT3_EXTENTS_FL 0x00080000 /* Inode uses extents */ | 185 | #define EXT2_EXTENT_FL 0x00080000 /* Extents */ |
186 | #define EXT2_RESERVED_FL 0x80000000 /* reserved for ext2 lib */ | 186 | #define EXT2_VERITY_FL 0x00100000 |
187 | 187 | #define EXT2_NOCOW_FL 0x00800000 /* Do not cow file */ | |
188 | #define EXT2_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */ | 188 | #define EXT2_INLINE_DATA_FL 0x10000000 |
189 | #define EXT2_FL_USER_MODIFIABLE 0x000080FF /* User modifiable flags */ | 189 | #define EXT2_PROJINHERIT_FL 0x20000000 |
190 | #define EXT2_CASEFOLD_FL 0x40000000 | ||
190 | 191 | ||
191 | /* | 192 | /* |
192 | * ioctl commands | 193 | * ioctl commands |
@@ -195,6 +196,18 @@ struct ext2_dx_countlimit { | |||
195 | #define EXT2_IOC_SETFLAGS _IOW('f', 2, long) | 196 | #define EXT2_IOC_SETFLAGS _IOW('f', 2, long) |
196 | #define EXT2_IOC_GETVERSION _IOR('v', 1, long) | 197 | #define EXT2_IOC_GETVERSION _IOR('v', 1, long) |
197 | #define EXT2_IOC_SETVERSION _IOW('v', 2, long) | 198 | #define EXT2_IOC_SETVERSION _IOW('v', 2, long) |
199 | //NB: despite "long" in defs above, these ioctls use an _int_! | ||
200 | //passing them a pointer to long will read/write only int-sized data! | ||
201 | struct ext2_fsxattr { | ||
202 | uint32_t fsx_xflags; /* xflags field value (get/set) */ | ||
203 | uint32_t fsx_extsize; /* extsize field value (get/set)*/ | ||
204 | uint32_t fsx_nextents; /* nextents field value (get) */ | ||
205 | uint32_t fsx_projid; /* project identifier (get/set) */ | ||
206 | uint32_t fsx_cowextsize; /* CoW extsize field value (get/set)*/ | ||
207 | unsigned char fsx_pad[8]; | ||
208 | }; | ||
209 | #define EXT2_IOC_FSGETXATTR _IOR('X', 31, struct ext2_fsxattr) | ||
210 | #define EXT2_IOC_FSSETXATTR _IOW('X', 32, struct ext2_fsxattr) | ||
198 | 211 | ||
199 | /* | 212 | /* |
200 | * Structure of an inode on the disk | 213 | * Structure of an inode on the disk |
diff --git a/include/dump.h b/include/dump.h index 9193a6925..10fc5d900 100644 --- a/include/dump.h +++ b/include/dump.h | |||
@@ -32,8 +32,10 @@ typedef struct dumper_t { | |||
32 | off_t dump_skip; /* bytes to skip */ | 32 | off_t dump_skip; /* bytes to skip */ |
33 | int dump_length; /* max bytes to read */ | 33 | int dump_length; /* max bytes to read */ |
34 | smallint dump_vflag; /*enum dump_vflag_t*/ | 34 | smallint dump_vflag; /*enum dump_vflag_t*/ |
35 | const char *eofstring; | ||
36 | FS *fshead; | 35 | FS *fshead; |
36 | const char *xxd_eofstring; | ||
37 | off_t address; /* address/offset in stream */ | ||
38 | long long xxd_displayoff; | ||
37 | } dumper_t; | 39 | } dumper_t; |
38 | 40 | ||
39 | dumper_t* alloc_dumper(void) FAST_FUNC; | 41 | dumper_t* alloc_dumper(void) FAST_FUNC; |
diff --git a/include/libbb.h b/include/libbb.h index e80ed1e32..7a43967cb 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -469,23 +469,29 @@ enum { /* cp.c, mv.c, install.c depend on these values. CAREFUL when changing th | |||
469 | FILEUTILS_RECUR = 1 << 2, /* -R */ | 469 | FILEUTILS_RECUR = 1 << 2, /* -R */ |
470 | FILEUTILS_FORCE = 1 << 3, /* -f */ | 470 | FILEUTILS_FORCE = 1 << 3, /* -f */ |
471 | FILEUTILS_INTERACTIVE = 1 << 4, /* -i */ | 471 | FILEUTILS_INTERACTIVE = 1 << 4, /* -i */ |
472 | FILEUTILS_MAKE_HARDLINK = 1 << 5, /* -l */ | 472 | FILEUTILS_NO_OVERWRITE = 1 << 5, /* -n */ |
473 | FILEUTILS_MAKE_SOFTLINK = 1 << 6, /* -s */ | 473 | FILEUTILS_MAKE_HARDLINK = 1 << 6, /* -l */ |
474 | FILEUTILS_DEREF_SOFTLINK = 1 << 7, /* -L */ | 474 | FILEUTILS_MAKE_SOFTLINK = 1 << 7, /* -s */ |
475 | FILEUTILS_DEREFERENCE_L0 = 1 << 8, /* -H */ | 475 | FILEUTILS_DEREF_SOFTLINK = 1 << 8, /* -L */ |
476 | FILEUTILS_DEREFERENCE_L0 = 1 << 9, /* -H */ | ||
476 | /* -a = -pdR (mapped in cp.c) */ | 477 | /* -a = -pdR (mapped in cp.c) */ |
477 | /* -r = -dR (mapped in cp.c) */ | 478 | /* -r = -dR (mapped in cp.c) */ |
478 | /* -P = -d (mapped in cp.c) */ | 479 | /* -P = -d (mapped in cp.c) */ |
479 | FILEUTILS_VERBOSE = (1 << 12) * ENABLE_FEATURE_VERBOSE, /* -v */ | 480 | FILEUTILS_VERBOSE = (1 << 13) * ENABLE_FEATURE_VERBOSE, /* -v */ |
480 | FILEUTILS_UPDATE = 1 << 13, /* -u */ | 481 | FILEUTILS_UPDATE = 1 << 14, /* -u */ |
481 | FILEUTILS_NO_TARGET_DIR = 1 << 14, /* -T */ | 482 | FILEUTILS_NO_TARGET_DIR = 1 << 15, /* -T */ |
483 | FILEUTILS_TARGET_DIR = 1 << 16, /* -t DIR */ | ||
482 | #if ENABLE_SELINUX | 484 | #if ENABLE_SELINUX |
483 | FILEUTILS_PRESERVE_SECURITY_CONTEXT = 1 << 15, /* -c */ | 485 | FILEUTILS_PRESERVE_SECURITY_CONTEXT = 1 << 17, /* -c */ |
484 | #endif | 486 | #endif |
485 | FILEUTILS_RMDEST = 1 << (16 - !ENABLE_SELINUX), /* --remove-destination */ | 487 | #define FILEUTILS_CP_OPTSTR "pdRfinlsLHarPvuTt:" IF_SELINUX("c") |
486 | /* bit 17 skipped for "cp --parents" */ | 488 | /* How many bits in FILEUTILS_CP_OPTSTR? */ |
487 | FILEUTILS_REFLINK = 1 << (18 - !ENABLE_SELINUX), /* cp --reflink=auto */ | 489 | FILEUTILS_CP_OPTBITS = 18 - !ENABLE_SELINUX, |
488 | FILEUTILS_REFLINK_ALWAYS = 1 << (19 - !ENABLE_SELINUX), /* cp --reflink[=always] */ | 490 | |
491 | FILEUTILS_RMDEST = 1 << (19 - !ENABLE_SELINUX), /* cp --remove-destination */ | ||
492 | /* bit 18 skipped for "cp --parents" */ | ||
493 | FILEUTILS_REFLINK = 1 << (20 - !ENABLE_SELINUX), /* cp --reflink=auto */ | ||
494 | FILEUTILS_REFLINK_ALWAYS = 1 << (21 - !ENABLE_SELINUX), /* cp --reflink[=always] */ | ||
489 | /* | 495 | /* |
490 | * Hole. cp may have some bits set here, | 496 | * Hole. cp may have some bits set here, |
491 | * they should not affect remove_file()/copy_file() | 497 | * they should not affect remove_file()/copy_file() |
@@ -495,7 +501,7 @@ enum { /* cp.c, mv.c, install.c depend on these values. CAREFUL when changing th | |||
495 | #endif | 501 | #endif |
496 | FILEUTILS_IGNORE_CHMOD_ERR = 1 << 31, | 502 | FILEUTILS_IGNORE_CHMOD_ERR = 1 << 31, |
497 | }; | 503 | }; |
498 | #define FILEUTILS_CP_OPTSTR "pdRfilsLHarPvuT" IF_SELINUX("c") | 504 | |
499 | extern int remove_file(const char *path, int flags) FAST_FUNC; | 505 | extern int remove_file(const char *path, int flags) FAST_FUNC; |
500 | /* NB: without FILEUTILS_RECUR in flags, it will basically "cat" | 506 | /* NB: without FILEUTILS_RECUR in flags, it will basically "cat" |
501 | * the source, not copy (unless "source" is a directory). | 507 | * the source, not copy (unless "source" is a directory). |
@@ -525,6 +531,11 @@ int recursive_action(const char *fileName, unsigned flags, | |||
525 | void *userData | 531 | void *userData |
526 | ) FAST_FUNC; | 532 | ) FAST_FUNC; |
527 | 533 | ||
534 | /* Simpler version: call a function on each dirent in a directory */ | ||
535 | int iterate_on_dir(const char *dir_name, | ||
536 | int FAST_FUNC (*func)(const char *, struct dirent *, void *), | ||
537 | void *private) FAST_FUNC; | ||
538 | |||
528 | extern int device_open(const char *device, int mode) FAST_FUNC; | 539 | extern int device_open(const char *device, int mode) FAST_FUNC; |
529 | enum { GETPTY_BUFSIZE = 16 }; /* more than enough for "/dev/ttyXXX" */ | 540 | enum { GETPTY_BUFSIZE = 16 }; /* more than enough for "/dev/ttyXXX" */ |
530 | extern int xgetpty(char *line) FAST_FUNC; | 541 | extern int xgetpty(char *line) FAST_FUNC; |
@@ -1105,10 +1116,10 @@ char *smart_ulltoa5(unsigned long long ul, char buf[5], const char *scale) FAST_ | |||
1105 | /* If block_size == 0, display size without fractional part, | 1116 | /* If block_size == 0, display size without fractional part, |
1106 | * else display (size * block_size) with one decimal digit. | 1117 | * else display (size * block_size) with one decimal digit. |
1107 | * If display_unit == 0, show value no bigger than 1024 with suffix (K,M,G...), | 1118 | * If display_unit == 0, show value no bigger than 1024 with suffix (K,M,G...), |
1108 | * else divide by display_unit and do not use suffix. */ | 1119 | * else divide by display_unit and do not use suffix. |
1120 | * Returns "auto pointer" */ | ||
1109 | #define HUMAN_READABLE_MAX_WIDTH 7 /* "1024.0G" */ | 1121 | #define HUMAN_READABLE_MAX_WIDTH 7 /* "1024.0G" */ |
1110 | #define HUMAN_READABLE_MAX_WIDTH_STR "7" | 1122 | #define HUMAN_READABLE_MAX_WIDTH_STR "7" |
1111 | //TODO: provide pointer to buf (avoid statics)? | ||
1112 | const char *make_human_readable_str(unsigned long long size, | 1123 | const char *make_human_readable_str(unsigned long long size, |
1113 | unsigned long block_size, unsigned long display_unit) FAST_FUNC; | 1124 | unsigned long block_size, unsigned long display_unit) FAST_FUNC; |
1114 | /* Put a string of hex bytes ("1b2e66fe"...), return advanced pointer */ | 1125 | /* Put a string of hex bytes ("1b2e66fe"...), return advanced pointer */ |
diff --git a/libbb/copy_file.c b/libbb/copy_file.c index 9b10dda1f..c0928a5a8 100644 --- a/libbb/copy_file.c +++ b/libbb/copy_file.c | |||
@@ -117,6 +117,8 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags) | |||
117 | return -1; | 117 | return -1; |
118 | } | 118 | } |
119 | #endif | 119 | #endif |
120 | if (flags & FILEUTILS_NO_OVERWRITE) /* cp -n */ | ||
121 | return 0; | ||
120 | dest_exists = 1; | 122 | dest_exists = 1; |
121 | } | 123 | } |
122 | 124 | ||
diff --git a/libbb/dump.c b/libbb/dump.c index 196ccfe65..ffae04786 100644 --- a/libbb/dump.c +++ b/libbb/dump.c | |||
@@ -34,7 +34,6 @@ typedef struct priv_dumper_t { | |||
34 | FU *endfu; | 34 | FU *endfu; |
35 | off_t savaddress; /* saved address/offset in stream */ | 35 | off_t savaddress; /* saved address/offset in stream */ |
36 | off_t eaddress; /* end address */ | 36 | off_t eaddress; /* end address */ |
37 | off_t address; /* address/offset in stream */ | ||
38 | int blocksize; | 37 | int blocksize; |
39 | smallint exitval; /* final exit value */ | 38 | smallint exitval; /* final exit value */ |
40 | #if ENABLE_PLATFORM_MINGW32 | 39 | #if ENABLE_PLATFORM_MINGW32 |
@@ -217,7 +216,7 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) | |||
217 | pr->bcnt = fu->bcnt; | 216 | pr->bcnt = fu->bcnt; |
218 | if (fu->bcnt == 0) { | 217 | if (fu->bcnt == 0) { |
219 | if (!prec) | 218 | if (!prec) |
220 | bb_simple_error_msg_and_die("%%s needs precision or byte count"); | 219 | bb_simple_error_msg_and_die("%s needs precision or byte count"); |
221 | pr->bcnt = atoi(prec); | 220 | pr->bcnt = atoi(prec); |
222 | } | 221 | } |
223 | } else | 222 | } else |
@@ -234,7 +233,8 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) | |||
234 | if ((p1[2] != 'd') && (p1[2] != 'o') && (p1[2] != 'x')) { | 233 | if ((p1[2] != 'd') && (p1[2] != 'o') && (p1[2] != 'x')) { |
235 | goto DO_BAD_CONV_CHAR; | 234 | goto DO_BAD_CONV_CHAR; |
236 | } | 235 | } |
237 | *p1 = p1[2]; | 236 | *p1++ = 'l'; |
237 | *p1++ = 'l'; | ||
238 | break; | 238 | break; |
239 | case 'c': /* %_c: chars, \ooo, \n \r \t etc */ | 239 | case 'c': /* %_c: chars, \ooo, \n \r \t etc */ |
240 | pr->flags = F_C; | 240 | pr->flags = F_C; |
@@ -344,7 +344,7 @@ static void do_skip(priv_dumper_t *dumper, const char *fname) | |||
344 | ) { | 344 | ) { |
345 | /* If st_size is valid and pub.dump_skip >= st_size */ | 345 | /* If st_size is valid and pub.dump_skip >= st_size */ |
346 | dumper->pub.dump_skip -= sbuf.st_size; | 346 | dumper->pub.dump_skip -= sbuf.st_size; |
347 | dumper->address += sbuf.st_size; | 347 | dumper->pub.address += sbuf.st_size; |
348 | return; | 348 | return; |
349 | } | 349 | } |
350 | #if ENABLE_PLATFORM_MINGW32 | 350 | #if ENABLE_PLATFORM_MINGW32 |
@@ -354,8 +354,8 @@ static void do_skip(priv_dumper_t *dumper, const char *fname) | |||
354 | #endif | 354 | #endif |
355 | bb_simple_perror_msg_and_die(fname); | 355 | bb_simple_perror_msg_and_die(fname); |
356 | } | 356 | } |
357 | dumper->address += dumper->pub.dump_skip; | 357 | dumper->pub.address += dumper->pub.dump_skip; |
358 | dumper->savaddress = dumper->address; | 358 | dumper->savaddress = dumper->pub.address; |
359 | dumper->pub.dump_skip = 0; | 359 | dumper->pub.dump_skip = 0; |
360 | } | 360 | } |
361 | 361 | ||
@@ -375,6 +375,7 @@ static NOINLINE int next(priv_dumper_t *dumper) | |||
375 | #endif | 375 | #endif |
376 | bb_simple_perror_msg(fname); | 376 | bb_simple_perror_msg(fname); |
377 | dumper->exitval = 1; | 377 | dumper->exitval = 1; |
378 | dumper->next__done = 1; | ||
378 | continue; | 379 | continue; |
379 | } | 380 | } |
380 | } | 381 | } |
@@ -403,7 +404,7 @@ static unsigned char *get(priv_dumper_t *dumper) | |||
403 | int blocksize = dumper->blocksize; | 404 | int blocksize = dumper->blocksize; |
404 | 405 | ||
405 | if (!dumper->get__curp) { | 406 | if (!dumper->get__curp) { |
406 | dumper->address = (off_t)0; /*DBU:[dave@cray.com] initialize,initialize..*/ | 407 | dumper->pub.address = (off_t)0; /*DBU:[dave@cray.com] initialize,initialize..*/ |
407 | dumper->get__curp = xmalloc(blocksize); | 408 | dumper->get__curp = xmalloc(blocksize); |
408 | dumper->get__savp = xzalloc(blocksize); /* need to be initialized */ | 409 | dumper->get__savp = xzalloc(blocksize); /* need to be initialized */ |
409 | } else { | 410 | } else { |
@@ -411,7 +412,7 @@ static unsigned char *get(priv_dumper_t *dumper) | |||
411 | dumper->get__curp = dumper->get__savp; | 412 | dumper->get__curp = dumper->get__savp; |
412 | dumper->get__savp = tmp; | 413 | dumper->get__savp = tmp; |
413 | dumper->savaddress += blocksize; | 414 | dumper->savaddress += blocksize; |
414 | dumper->address = dumper->savaddress; | 415 | dumper->pub.address = dumper->savaddress; |
415 | } | 416 | } |
416 | need = blocksize; | 417 | need = blocksize; |
417 | nread = 0; | 418 | nread = 0; |
@@ -434,7 +435,7 @@ static unsigned char *get(priv_dumper_t *dumper) | |||
434 | } | 435 | } |
435 | } | 436 | } |
436 | memset(dumper->get__curp + nread, 0, need); | 437 | memset(dumper->get__curp + nread, 0, need); |
437 | dumper->eaddress = dumper->address + nread; | 438 | dumper->eaddress = dumper->pub.address + nread; |
438 | return dumper->get__curp; | 439 | return dumper->get__curp; |
439 | } | 440 | } |
440 | #if ENABLE_PLATFORM_MINGW32 | 441 | #if ENABLE_PLATFORM_MINGW32 |
@@ -478,7 +479,7 @@ static unsigned char *get(priv_dumper_t *dumper) | |||
478 | } | 479 | } |
479 | dumper->pub.dump_vflag = DUP; | 480 | dumper->pub.dump_vflag = DUP; |
480 | dumper->savaddress += blocksize; | 481 | dumper->savaddress += blocksize; |
481 | dumper->address = dumper->savaddress; | 482 | dumper->pub.address = dumper->savaddress; |
482 | need = blocksize; | 483 | need = blocksize; |
483 | nread = 0; | 484 | nread = 0; |
484 | } else { | 485 | } else { |
@@ -579,8 +580,8 @@ static void display(priv_dumper_t* dumper) | |||
579 | 580 | ||
580 | fs = dumper->pub.fshead; | 581 | fs = dumper->pub.fshead; |
581 | savebp = bp; | 582 | savebp = bp; |
582 | saveaddress = dumper->address; | 583 | saveaddress = dumper->pub.address; |
583 | for (; fs; fs = fs->nextfs, bp = savebp, dumper->address = saveaddress) { | 584 | for (; fs; fs = fs->nextfs, bp = savebp, dumper->pub.address = saveaddress) { |
584 | FU *fu; | 585 | FU *fu; |
585 | for (fu = fs->nextfu; fu; fu = fu->nextfu) { | 586 | for (fu = fs->nextfu; fu; fu = fu->nextfu) { |
586 | int cnt; | 587 | int cnt; |
@@ -589,14 +590,14 @@ static void display(priv_dumper_t* dumper) | |||
589 | } | 590 | } |
590 | for (cnt = fu->reps; cnt; --cnt) { | 591 | for (cnt = fu->reps; cnt; --cnt) { |
591 | PR *pr; | 592 | PR *pr; |
592 | for (pr = fu->nextpr; pr; dumper->address += pr->bcnt, | 593 | for (pr = fu->nextpr; pr; dumper->pub.address += pr->bcnt, |
593 | bp += pr->bcnt, pr = pr->nextpr) { | 594 | bp += pr->bcnt, pr = pr->nextpr) { |
594 | if (dumper->eaddress | 595 | if (dumper->eaddress |
595 | && dumper->address >= dumper->eaddress | 596 | && dumper->pub.address >= dumper->eaddress |
596 | ) { | 597 | ) { |
597 | if (dumper->pub.eofstring) { | 598 | if (dumper->pub.xxd_eofstring) { |
598 | /* xxd support: requested to not pad incomplete blocks */ | 599 | /* xxd support: requested to not pad incomplete blocks */ |
599 | fputs_stdout(dumper->pub.eofstring); | 600 | fputs_stdout(dumper->pub.xxd_eofstring); |
600 | return; | 601 | return; |
601 | } | 602 | } |
602 | if (!(pr->flags & (F_TEXT | F_BPAD))) | 603 | if (!(pr->flags & (F_TEXT | F_BPAD))) |
@@ -608,7 +609,7 @@ static void display(priv_dumper_t* dumper) | |||
608 | } | 609 | } |
609 | switch (pr->flags) { | 610 | switch (pr->flags) { |
610 | case F_ADDRESS: | 611 | case F_ADDRESS: |
611 | printf(pr->fmt, (unsigned) dumper->address); | 612 | printf(pr->fmt, (unsigned long long) dumper->pub.address + dumper->pub.xxd_displayoff); |
612 | break; | 613 | break; |
613 | case F_BPAD: | 614 | case F_BPAD: |
614 | printf(pr->fmt, ""); | 615 | printf(pr->fmt, ""); |
@@ -702,15 +703,15 @@ static void display(priv_dumper_t* dumper) | |||
702 | * of blocksize, and no partial block ever found. | 703 | * of blocksize, and no partial block ever found. |
703 | */ | 704 | */ |
704 | if (!dumper->eaddress) { | 705 | if (!dumper->eaddress) { |
705 | if (!dumper->address) { | 706 | if (!dumper->pub.address) { |
706 | return; | 707 | return; |
707 | } | 708 | } |
708 | dumper->eaddress = dumper->address; | 709 | dumper->eaddress = dumper->pub.address; |
709 | } | 710 | } |
710 | for (pr = dumper->endfu->nextpr; pr; pr = pr->nextpr) { | 711 | for (pr = dumper->endfu->nextpr; pr; pr = pr->nextpr) { |
711 | switch (pr->flags) { | 712 | switch (pr->flags) { |
712 | case F_ADDRESS: | 713 | case F_ADDRESS: |
713 | printf(pr->fmt, (unsigned) dumper->eaddress); | 714 | printf(pr->fmt, (unsigned long long) dumper->eaddress + dumper->pub.xxd_displayoff); |
714 | break; | 715 | break; |
715 | case F_TEXT: | 716 | case F_TEXT: |
716 | printf(pr->fmt); | 717 | printf(pr->fmt); |
diff --git a/libbb/iterate_on_dir.c b/libbb/iterate_on_dir.c new file mode 100644 index 000000000..deef72ebf --- /dev/null +++ b/libbb/iterate_on_dir.c | |||
@@ -0,0 +1,28 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * See README for additional information | ||
4 | * | ||
5 | * Licensed under GPLv2, see file LICENSE in this source tree. | ||
6 | */ | ||
7 | //kbuild:lib-y += iterate_on_dir.o | ||
8 | |||
9 | #include "libbb.h" | ||
10 | |||
11 | /* Iterate a function on each entry of a directory */ | ||
12 | int FAST_FUNC iterate_on_dir(const char *dir_name, | ||
13 | int FAST_FUNC (*func)(const char *, struct dirent *, void *), | ||
14 | void *private) | ||
15 | { | ||
16 | DIR *dir; | ||
17 | struct dirent *de; | ||
18 | |||
19 | dir = opendir(dir_name); | ||
20 | if (dir == NULL) { | ||
21 | return -1; | ||
22 | } | ||
23 | while ((de = readdir(dir)) != NULL) { | ||
24 | func(dir_name, de, private); | ||
25 | } | ||
26 | closedir(dir); | ||
27 | return 0; | ||
28 | } | ||
diff --git a/libbb/remove_file.c b/libbb/remove_file.c index cea5d47e6..1505e6218 100644 --- a/libbb/remove_file.c +++ b/libbb/remove_file.c | |||
@@ -60,11 +60,7 @@ int FAST_FUNC remove_file(const char *path, int flags) | |||
60 | status = -1; | 60 | status = -1; |
61 | free(new_path); | 61 | free(new_path); |
62 | } | 62 | } |
63 | 63 | closedir(dp); | |
64 | if (closedir(dp) < 0) { | ||
65 | bb_perror_msg("can't close '%s'", path); | ||
66 | return -1; | ||
67 | } | ||
68 | 64 | ||
69 | if (flags & FILEUTILS_INTERACTIVE) { | 65 | if (flags & FILEUTILS_INTERACTIVE) { |
70 | fprintf(stderr, "%s: remove directory '%s'? ", | 66 | fprintf(stderr, "%s: remove directory '%s'? ", |
diff --git a/loginutils/su.c b/loginutils/su.c index e46bbf78b..647c97fb1 100644 --- a/loginutils/su.c +++ b/loginutils/su.c | |||
@@ -36,7 +36,7 @@ | |||
36 | //kbuild:lib-$(CONFIG_SU) += su.o | 36 | //kbuild:lib-$(CONFIG_SU) += su.o |
37 | 37 | ||
38 | //usage:#define su_trivial_usage | 38 | //usage:#define su_trivial_usage |
39 | //usage: "[-lmp] [-] [-s SH] [USER [SCRIPT ARGS / -c 'CMD' ARG0 ARGS]]" | 39 | //usage: "[-lmp] [-s SH] [-] [USER [FILE ARGS | -c 'CMD' [ARG0 ARGS]]]" |
40 | //usage:#define su_full_usage "\n\n" | 40 | //usage:#define su_full_usage "\n\n" |
41 | //usage: "Run shell under USER (by default, root)\n" | 41 | //usage: "Run shell under USER (by default, root)\n" |
42 | //usage: "\n -,-l Clear environment, go to home dir, run shell as login shell" | 42 | //usage: "\n -,-l Clear environment, go to home dir, run shell as login shell" |
diff --git a/miscutils/ascii.c b/miscutils/ascii.c new file mode 100644 index 000000000..98c11fa51 --- /dev/null +++ b/miscutils/ascii.c | |||
@@ -0,0 +1,51 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Copyright (C) 2021 Denys Vlasenko <vda.linux@googlemail.com> | ||
4 | * | ||
5 | * Licensed under GPLv2, see file LICENSE in this source tree. | ||
6 | */ | ||
7 | //config:config ASCII | ||
8 | //config: bool "ascii" | ||
9 | //config: default y | ||
10 | //config: help | ||
11 | //config: Print ascii table. | ||
12 | //config: | ||
13 | |||
14 | //applet:IF_ASCII(APPLET(ascii, BB_DIR_USR_BIN, BB_SUID_DROP)) | ||
15 | |||
16 | //kbuild:lib-$(CONFIG_ASCII) += ascii.o | ||
17 | |||
18 | //usage:#define ascii_trivial_usage NOUSAGE_STR | ||
19 | //usage:#define ascii_full_usage "" | ||
20 | |||
21 | #include "libbb.h" | ||
22 | |||
23 | int ascii_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
24 | int ascii_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | ||
25 | { | ||
26 | const char *ctrl = | ||
27 | "NUL""SOH""STX""ETX""EOT""ENQ""ACK""BEL" | ||
28 | "BS ""HT ""NL ""VT ""FF ""CR ""SO ""SI " | ||
29 | "DLE""DC1""DC2""DC3""DC4""NAK""SYN""ETB" | ||
30 | "CAN""EM ""SUB""ESC""FS ""GS ""RS ""US " | ||
31 | ; | ||
32 | //TODO: od has a similar table, can we reuse it? | ||
33 | char last[2]; | ||
34 | unsigned i; | ||
35 | |||
36 | last[1] = '\0'; | ||
37 | printf("Dec Hex Dec Hex Dec Hex Dec Hex Dec Hex Dec Hex Dec Hex Dec Hex\n"); | ||
38 | for (i = 0; i < 16; i++) { | ||
39 | printf("%3u %02x %.3s%4u %02x %.3s%4u %02x %c%4u %02x %c%4u %02x %c%4u %02x %c%5u %02x %c%5u %02x %s\n", | ||
40 | i+0x00, i+0x00, ctrl + i*3, | ||
41 | i+0x10, i+0x10, ctrl + i*3 + 16*3, | ||
42 | i+0x20, i+0x20, i+0x20, | ||
43 | i+0x30, i+0x30, i+0x30, | ||
44 | i+0x40, i+0x40, i+0x40, | ||
45 | i+0x50, i+0x50, i+0x50, | ||
46 | i+0x60, i+0x60, i+0x60, | ||
47 | i+0x70, i+0x70, (i+0x70 == 0x7f ? "DEL" : (last[0] = i+0x70, last)) | ||
48 | ); | ||
49 | } | ||
50 | return EXIT_SUCCESS; | ||
51 | } | ||
diff --git a/miscutils/bc.c b/miscutils/bc.c index d74ab1da2..f931be5cc 100644 --- a/miscutils/bc.c +++ b/miscutils/bc.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * Original code copyright (c) 2018 Gavin D. Howard and contributors. | 5 | * Original code copyright (c) 2018 Gavin D. Howard and contributors. |
6 | */ | 6 | */ |
7 | //TODO: | 7 | //TODO: |
8 | // maybe implement a^b for non-integer b? | 8 | // maybe implement a^b for non-integer b? (see zbc_num_p()) |
9 | 9 | ||
10 | #define DEBUG_LEXER 0 | 10 | #define DEBUG_LEXER 0 |
11 | #define DEBUG_COMPILE 0 | 11 | #define DEBUG_COMPILE 0 |
@@ -108,7 +108,7 @@ | |||
108 | 108 | ||
109 | //See www.gnu.org/software/bc/manual/bc.html | 109 | //See www.gnu.org/software/bc/manual/bc.html |
110 | //usage:#define bc_trivial_usage | 110 | //usage:#define bc_trivial_usage |
111 | //usage: "[-sqlw] [FILE...]" | 111 | //usage: "[-sqlw] [FILE]..." |
112 | //usage: | 112 | //usage: |
113 | //usage:#define bc_full_usage "\n" | 113 | //usage:#define bc_full_usage "\n" |
114 | //usage: "\nArbitrary precision calculator" | 114 | //usage: "\nArbitrary precision calculator" |
@@ -1386,6 +1386,12 @@ static void bc_num_copy(BcNum *d, BcNum *s) | |||
1386 | } | 1386 | } |
1387 | } | 1387 | } |
1388 | 1388 | ||
1389 | static void bc_num_init_and_copy(BcNum *d, BcNum *s) | ||
1390 | { | ||
1391 | bc_num_init(d, s->len); | ||
1392 | bc_num_copy(d, s); | ||
1393 | } | ||
1394 | |||
1389 | static BC_STATUS zbc_num_ulong_abs(BcNum *n, unsigned long *result_p) | 1395 | static BC_STATUS zbc_num_ulong_abs(BcNum *n, unsigned long *result_p) |
1390 | { | 1396 | { |
1391 | size_t i; | 1397 | size_t i; |
@@ -1985,11 +1991,8 @@ static FAST_FUNC BC_STATUS zbc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size | |||
1985 | scale = BC_MIN(a->rdx + b->rdx, scale); | 1991 | scale = BC_MIN(a->rdx + b->rdx, scale); |
1986 | maxrdx = BC_MAX(maxrdx, scale); | 1992 | maxrdx = BC_MAX(maxrdx, scale); |
1987 | 1993 | ||
1988 | bc_num_init(&cpa, a->len); | 1994 | bc_num_init_and_copy(&cpa, a); |
1989 | bc_num_init(&cpb, b->len); | 1995 | bc_num_init_and_copy(&cpb, b); |
1990 | |||
1991 | bc_num_copy(&cpa, a); | ||
1992 | bc_num_copy(&cpb, b); | ||
1993 | cpa.neg = cpb.neg = false; | 1996 | cpa.neg = cpb.neg = false; |
1994 | 1997 | ||
1995 | s = zbc_num_shift(&cpa, maxrdx); | 1998 | s = zbc_num_shift(&cpa, maxrdx); |
@@ -2152,6 +2155,7 @@ static FAST_FUNC BC_STATUS zbc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size | |||
2152 | BcNum copy; | 2155 | BcNum copy; |
2153 | unsigned long pow; | 2156 | unsigned long pow; |
2154 | size_t i, powrdx, resrdx; | 2157 | size_t i, powrdx, resrdx; |
2158 | size_t a_rdx; | ||
2155 | bool neg; | 2159 | bool neg; |
2156 | 2160 | ||
2157 | // GNU bc does not allow 2^2.0 - we do | 2161 | // GNU bc does not allow 2^2.0 - we do |
@@ -2159,6 +2163,9 @@ static FAST_FUNC BC_STATUS zbc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size | |||
2159 | if (b->num[i] != 0) | 2163 | if (b->num[i] != 0) |
2160 | RETURN_STATUS(bc_error("not an integer")); | 2164 | RETURN_STATUS(bc_error("not an integer")); |
2161 | 2165 | ||
2166 | // a^b for non-integer b (for a>0) can be implemented as exp(ln(a)*b). | ||
2167 | // Possibly better precision would be given by a^int(b) * exp(ln(a)*frac(b)). | ||
2168 | |||
2162 | if (b->len == 0) { | 2169 | if (b->len == 0) { |
2163 | bc_num_one(c); | 2170 | bc_num_one(c); |
2164 | RETURN_STATUS(BC_STATUS_SUCCESS); | 2171 | RETURN_STATUS(BC_STATUS_SUCCESS); |
@@ -2180,18 +2187,31 @@ static FAST_FUNC BC_STATUS zbc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size | |||
2180 | if (s) RETURN_STATUS(s); | 2187 | if (s) RETURN_STATUS(s); |
2181 | // b is not used beyond this point | 2188 | // b is not used beyond this point |
2182 | 2189 | ||
2183 | bc_num_init(©, a->len); | 2190 | bc_num_init_and_copy(©, a); |
2184 | bc_num_copy(©, a); | 2191 | a_rdx = a->rdx; // pull it into a CPU register (hopefully) |
2192 | // a is not used beyond this point | ||
2185 | 2193 | ||
2186 | if (!neg) { | 2194 | if (!neg) { |
2187 | if (a->rdx > scale) | 2195 | unsigned long new_scale; |
2188 | scale = a->rdx; | 2196 | if (a_rdx > scale) |
2189 | if (a->rdx * pow < scale) | 2197 | scale = a_rdx; |
2190 | scale = a->rdx * pow; | 2198 | new_scale = a_rdx * pow; |
2191 | } | 2199 | // Don't fall for multiplication overflow. Example: |
2192 | 2200 | // 0.01^2147483648 a_rdx:2 pow:0x80000000, 32bit mul is 0. | |
2193 | 2201 | //not that it matters with current algorithm, it would OOM on such large powers, | |
2194 | for (powrdx = a->rdx; !(pow & 1); pow >>= 1) { | 2202 | //but it can be improved to detect zero results etc. Example: with scale=0, |
2203 | //result of 0.01^N for any N>1 is 0: 0.01^2 = 0.0001 ~= 0.00 (trunc to scale) | ||
2204 | //then this would matter: | ||
2205 | // if a_rdx != 0 and new_scale < pow, we had overflow, | ||
2206 | // correct "new_scale" value is larger than ULONG_MAX, | ||
2207 | // thus larger than any possible current value of "scale", | ||
2208 | // thus "scale = new_scale" should not be done: | ||
2209 | if (a_rdx == 0 || new_scale >= pow) | ||
2210 | if (new_scale < scale) | ||
2211 | scale = new_scale; | ||
2212 | } | ||
2213 | |||
2214 | for (powrdx = a_rdx; !(pow & 1); pow >>= 1) { | ||
2195 | powrdx <<= 1; | 2215 | powrdx <<= 1; |
2196 | s = zbc_num_mul(©, ©, ©, powrdx); | 2216 | s = zbc_num_mul(©, ©, ©, powrdx); |
2197 | if (s) goto err; | 2217 | if (s) goto err; |
@@ -2493,8 +2513,7 @@ static void bc_array_copy(BcVec *d, const BcVec *s) | |||
2493 | dnum = (void*)d->v; | 2513 | dnum = (void*)d->v; |
2494 | snum = (void*)s->v; | 2514 | snum = (void*)s->v; |
2495 | for (i = 0; i < s->len; i++, dnum++, snum++) { | 2515 | for (i = 0; i < s->len; i++, dnum++, snum++) { |
2496 | bc_num_init(dnum, snum->len); | 2516 | bc_num_init_and_copy(dnum, snum); |
2497 | bc_num_copy(dnum, snum); | ||
2498 | } | 2517 | } |
2499 | } | 2518 | } |
2500 | 2519 | ||
@@ -2508,8 +2527,7 @@ static void dc_result_copy(BcResult *d, BcResult *src) | |||
2508 | case XC_RESULT_IBASE: | 2527 | case XC_RESULT_IBASE: |
2509 | case XC_RESULT_SCALE: | 2528 | case XC_RESULT_SCALE: |
2510 | case XC_RESULT_OBASE: | 2529 | case XC_RESULT_OBASE: |
2511 | bc_num_init(&d->d.n, src->d.n.len); | 2530 | bc_num_init_and_copy(&d->d.n, &src->d.n); |
2512 | bc_num_copy(&d->d.n, &src->d.n); | ||
2513 | break; | 2531 | break; |
2514 | case XC_RESULT_VAR: | 2532 | case XC_RESULT_VAR: |
2515 | case XC_RESULT_ARRAY: | 2533 | case XC_RESULT_ARRAY: |
@@ -5611,11 +5629,10 @@ static BC_STATUS zxc_num_printNum(BcNum *n, unsigned base_t, size_t width, BcNum | |||
5611 | } | 5629 | } |
5612 | 5630 | ||
5613 | bc_vec_init(&stack, sizeof(long), NULL); | 5631 | bc_vec_init(&stack, sizeof(long), NULL); |
5614 | bc_num_init(&intp, n->len); | 5632 | bc_num_init_and_copy(&intp, n); |
5615 | bc_num_init(&fracp, n->rdx); | 5633 | bc_num_init(&fracp, n->rdx); |
5616 | bc_num_init(&digit, width); | 5634 | bc_num_init(&digit, width); |
5617 | bc_num_init(&frac_len, BC_NUM_INT(n)); | 5635 | bc_num_init(&frac_len, BC_NUM_INT(n)); |
5618 | bc_num_copy(&intp, n); | ||
5619 | bc_num_one(&frac_len); | 5636 | bc_num_one(&frac_len); |
5620 | base.cap = ARRAY_SIZE(base_digs); | 5637 | base.cap = ARRAY_SIZE(base_digs); |
5621 | base.num = base_digs; | 5638 | base.num = base_digs; |
@@ -5784,8 +5801,7 @@ static BC_STATUS zxc_program_negate(void) | |||
5784 | s = zxc_program_prep(&ptr, &num); | 5801 | s = zxc_program_prep(&ptr, &num); |
5785 | if (s) RETURN_STATUS(s); | 5802 | if (s) RETURN_STATUS(s); |
5786 | 5803 | ||
5787 | bc_num_init(&res.d.n, num->len); | 5804 | bc_num_init_and_copy(&res.d.n, num); |
5788 | bc_num_copy(&res.d.n, num); | ||
5789 | if (res.d.n.len) res.d.n.neg = !res.d.n.neg; | 5805 | if (res.d.n.len) res.d.n.neg = !res.d.n.neg; |
5790 | 5806 | ||
5791 | xc_program_retire(&res, XC_RESULT_TEMP); | 5807 | xc_program_retire(&res, XC_RESULT_TEMP); |
@@ -6024,8 +6040,7 @@ static BC_STATUS zxc_program_assign(char inst) | |||
6024 | s = BC_STATUS_SUCCESS; | 6040 | s = BC_STATUS_SUCCESS; |
6025 | } | 6041 | } |
6026 | 6042 | ||
6027 | bc_num_init(&res.d.n, l->len); | 6043 | bc_num_init_and_copy(&res.d.n, l); |
6028 | bc_num_copy(&res.d.n, l); | ||
6029 | xc_program_binOpRetire(&res); | 6044 | xc_program_binOpRetire(&res); |
6030 | 6045 | ||
6031 | RETURN_STATUS(s); | 6046 | RETURN_STATUS(s); |
@@ -6122,8 +6137,7 @@ static BC_STATUS zbc_program_incdec(char inst) | |||
6122 | 6137 | ||
6123 | if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) { | 6138 | if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) { |
6124 | copy.t = XC_RESULT_TEMP; | 6139 | copy.t = XC_RESULT_TEMP; |
6125 | bc_num_init(©.d.n, num->len); | 6140 | bc_num_init_and_copy(©.d.n, num); |
6126 | bc_num_copy(©.d.n, num); | ||
6127 | } | 6141 | } |
6128 | 6142 | ||
6129 | res.t = BC_RESULT_ONE; | 6143 | res.t = BC_RESULT_ONE; |
@@ -6225,8 +6239,7 @@ static BC_STATUS zbc_program_return(char inst) | |||
6225 | 6239 | ||
6226 | s = zxc_program_num(operand, &num); | 6240 | s = zxc_program_num(operand, &num); |
6227 | if (s) RETURN_STATUS(s); | 6241 | if (s) RETURN_STATUS(s); |
6228 | bc_num_init(&res.d.n, num->len); | 6242 | bc_num_init_and_copy(&res.d.n, num); |
6229 | bc_num_copy(&res.d.n, num); | ||
6230 | bc_vec_pop(&G.prog.results); | 6243 | bc_vec_pop(&G.prog.results); |
6231 | } else { | 6244 | } else { |
6232 | if (f->voidfunc) | 6245 | if (f->voidfunc) |
diff --git a/miscutils/chat.c b/miscutils/chat.c index 86a114df6..f9e12a4ac 100644 --- a/miscutils/chat.c +++ b/miscutils/chat.c | |||
@@ -79,7 +79,7 @@ | |||
79 | //kbuild:lib-$(CONFIG_CHAT) += chat.o | 79 | //kbuild:lib-$(CONFIG_CHAT) += chat.o |
80 | 80 | ||
81 | //usage:#define chat_trivial_usage | 81 | //usage:#define chat_trivial_usage |
82 | //usage: "EXPECT [SEND [EXPECT [SEND...]]]" | 82 | //usage: "EXPECT [SEND [EXPECT [SEND]]...]" |
83 | //usage:#define chat_full_usage "\n\n" | 83 | //usage:#define chat_full_usage "\n\n" |
84 | //usage: "Useful for interacting with a modem connected to stdin/stdout.\n" | 84 | //usage: "Useful for interacting with a modem connected to stdin/stdout.\n" |
85 | //usage: "A script consists of \"expect-send\" argument pairs.\n" | 85 | //usage: "A script consists of \"expect-send\" argument pairs.\n" |
diff --git a/miscutils/flashcp.c b/miscutils/flashcp.c index 1ca9d158d..93c80cc6c 100644 --- a/miscutils/flashcp.c +++ b/miscutils/flashcp.c | |||
@@ -19,9 +19,9 @@ | |||
19 | //kbuild:lib-$(CONFIG_FLASHCP) += flashcp.o | 19 | //kbuild:lib-$(CONFIG_FLASHCP) += flashcp.o |
20 | 20 | ||
21 | //usage:#define flashcp_trivial_usage | 21 | //usage:#define flashcp_trivial_usage |
22 | //usage: "-v FILE MTD_DEVICE" | 22 | //usage: "[-v] FILE MTD_DEVICE" |
23 | //usage:#define flashcp_full_usage "\n\n" | 23 | //usage:#define flashcp_full_usage "\n\n" |
24 | //usage: "Copy an image to MTD device\n" | 24 | //usage: "Copy FILE to MTD device\n" |
25 | //usage: "\n -v Verbose" | 25 | //usage: "\n -v Verbose" |
26 | 26 | ||
27 | #include "libbb.h" | 27 | #include "libbb.h" |
diff --git a/miscutils/i2c_tools.c b/miscutils/i2c_tools.c index 48135921d..b25d49792 100644 --- a/miscutils/i2c_tools.c +++ b/miscutils/i2c_tools.c | |||
@@ -1394,7 +1394,7 @@ static void check_i2c_func(int fd) | |||
1394 | } | 1394 | } |
1395 | 1395 | ||
1396 | //usage:#define i2ctransfer_trivial_usage | 1396 | //usage:#define i2ctransfer_trivial_usage |
1397 | //usage: "[-fay] I2CBUS {rLENGTH[@ADDR] | wLENGTH[@ADDR] DATA...}..." | 1397 | //usage: "[-fay] I2CBUS { rLENGTH[@ADDR] | wLENGTH[@ADDR] DATA...}..." |
1398 | //usage:#define i2ctransfer_full_usage "\n\n" | 1398 | //usage:#define i2ctransfer_full_usage "\n\n" |
1399 | //usage: "Read/write I2C data in one transfer" | 1399 | //usage: "Read/write I2C data in one transfer" |
1400 | //usage: "\n" | 1400 | //usage: "\n" |
diff --git a/miscutils/man.c b/miscutils/man.c index 052b50054..be3b2a000 100644 --- a/miscutils/man.c +++ b/miscutils/man.c | |||
@@ -350,7 +350,7 @@ int man_main(int argc UNUSED_PARAM, char **argv) | |||
350 | 350 | ||
351 | /* is 1st ARG a SECTION? */ | 351 | /* is 1st ARG a SECTION? */ |
352 | sec_list = conf_sec_list; | 352 | sec_list = conf_sec_list; |
353 | if (is_section_name(conf_sec_list, *argv)) { | 353 | if (is_section_name(conf_sec_list, *argv) && argv[1]) { |
354 | /* yes */ | 354 | /* yes */ |
355 | sec_list = *argv++; | 355 | sec_list = *argv++; |
356 | } | 356 | } |
diff --git a/miscutils/microcom.c b/miscutils/microcom.c index 399d4cf7f..97b46342f 100644 --- a/miscutils/microcom.c +++ b/miscutils/microcom.c | |||
@@ -18,14 +18,14 @@ | |||
18 | //kbuild:lib-$(CONFIG_MICROCOM) += microcom.o | 18 | //kbuild:lib-$(CONFIG_MICROCOM) += microcom.o |
19 | 19 | ||
20 | //usage:#define microcom_trivial_usage | 20 | //usage:#define microcom_trivial_usage |
21 | //usage: "[-d DELAY] [-t TIMEOUT] [-s SPEED] [-X] TTY" | 21 | //usage: "[-d DELAY_MS] [-t TIMEOUT_MS ] [-s SPEED] [-X] TTY" |
22 | //usage:#define microcom_full_usage "\n\n" | 22 | //usage:#define microcom_full_usage "\n\n" |
23 | //usage: "Copy bytes for stdin to TTY and from TTY to stdout\n" | 23 | //usage: "Copy bytes from stdin to TTY and from TTY to stdout\n" |
24 | //usage: "\n -d Wait up to DELAY ms for TTY output before sending every" | 24 | //usage: "\n -d DELAY Wait up to DELAY ms for TTY output before sending" |
25 | //usage: "\n next byte to it" | 25 | //usage: "\n every next byte to it" |
26 | //usage: "\n -t Exit if both stdin and TTY are silent for TIMEOUT ms" | 26 | //usage: "\n -t TIMEOUT Exit if both stdin and TTY are silent for TIMEOUT ms" |
27 | //usage: "\n -s Set serial line to SPEED" | 27 | //usage: "\n -s SPEED Set serial line to SPEED" |
28 | //usage: "\n -X Disable special meaning of NUL and Ctrl-X from stdin" | 28 | //usage: "\n -X Disable special meaning of NUL and Ctrl-X from stdin" |
29 | 29 | ||
30 | #include "libbb.h" | 30 | #include "libbb.h" |
31 | #include "common_bufsiz.h" | 31 | #include "common_bufsiz.h" |
diff --git a/miscutils/mt.c b/miscutils/mt.c index 1a4214664..52d5476a1 100644 --- a/miscutils/mt.c +++ b/miscutils/mt.c | |||
@@ -19,7 +19,7 @@ | |||
19 | //usage:#define mt_full_usage "\n\n" | 19 | //usage:#define mt_full_usage "\n\n" |
20 | //usage: "Control magnetic tape drive operation\n" | 20 | //usage: "Control magnetic tape drive operation\n" |
21 | //usage: "\n" | 21 | //usage: "\n" |
22 | //usage: "Available Opcodes:\n" | 22 | //usage: "Opcodes:\n" |
23 | //usage: "\n" | 23 | //usage: "\n" |
24 | //usage: "bsf bsfm bsr bss datacompression drvbuffer eof eom erase\n" | 24 | //usage: "bsf bsfm bsr bss datacompression drvbuffer eof eom erase\n" |
25 | //usage: "fsf fsfm fsr fss load lock mkpart nop offline ras1 ras2\n" | 25 | //usage: "fsf fsfm fsr fss load lock mkpart nop offline ras1 ras2\n" |
diff --git a/miscutils/strings.c b/miscutils/strings.c index e4a68227e..b01884968 100644 --- a/miscutils/strings.c +++ b/miscutils/strings.c | |||
@@ -18,7 +18,7 @@ | |||
18 | //kbuild:lib-$(CONFIG_STRINGS) += strings.o | 18 | //kbuild:lib-$(CONFIG_STRINGS) += strings.o |
19 | 19 | ||
20 | //usage:#define strings_trivial_usage | 20 | //usage:#define strings_trivial_usage |
21 | //usage: "[-fo] [-t o/d/x] [-n LEN] [FILE]..." | 21 | //usage: "[-fo] [-t o|d|x] [-n LEN] [FILE]..." |
22 | //usage:#define strings_full_usage "\n\n" | 22 | //usage:#define strings_full_usage "\n\n" |
23 | //usage: "Display printable strings in a binary file\n" | 23 | //usage: "Display printable strings in a binary file\n" |
24 | //We usually don't bother user with "nop" options. They work, but are not shown: | 24 | //We usually don't bother user with "nop" options. They work, but are not shown: |
@@ -26,7 +26,7 @@ | |||
26 | //unimplemented alternative is -d: Only strings from initialized, loaded data sections | 26 | //unimplemented alternative is -d: Only strings from initialized, loaded data sections |
27 | //usage: "\n -f Precede strings with filenames" | 27 | //usage: "\n -f Precede strings with filenames" |
28 | //usage: "\n -o Precede strings with octal offsets" | 28 | //usage: "\n -o Precede strings with octal offsets" |
29 | //usage: "\n -t o/d/x Precede strings with offsets in base 8/10/16" | 29 | //usage: "\n -t o|d|x Precede strings with offsets in base 8/10/16" |
30 | //usage: "\n -n LEN At least LEN characters form a string (default 4)" | 30 | //usage: "\n -n LEN At least LEN characters form a string (default 4)" |
31 | 31 | ||
32 | #include "libbb.h" | 32 | #include "libbb.h" |
diff --git a/miscutils/ts.c b/miscutils/ts.c index 3eecb7464..af6677fc7 100644 --- a/miscutils/ts.c +++ b/miscutils/ts.c | |||
@@ -13,7 +13,10 @@ | |||
13 | 13 | ||
14 | //usage:#define ts_trivial_usage | 14 | //usage:#define ts_trivial_usage |
15 | //usage: "[-is] [STRFTIME]" | 15 | //usage: "[-is] [STRFTIME]" |
16 | //usage:#define ts_full_usage "" | 16 | //usage:#define ts_full_usage "\n\n" |
17 | //usage: "Pipe stdin to stdout, add timestamp to each line\n" | ||
18 | //usage: "\n -s Time since start" | ||
19 | //usage: "\n -i Time since previous line" | ||
17 | 20 | ||
18 | #include "libbb.h" | 21 | #include "libbb.h" |
19 | #include "common_bufsiz.h" | 22 | #include "common_bufsiz.h" |
diff --git a/miscutils/ubi_tools.c b/miscutils/ubi_tools.c index 69ead7a13..6d49f61d9 100644 --- a/miscutils/ubi_tools.c +++ b/miscutils/ubi_tools.c | |||
@@ -251,7 +251,7 @@ int ubi_tools_main(int argc UNUSED_PARAM, char **argv) | |||
251 | } else | 251 | } else |
252 | 252 | ||
253 | //usage:#define ubirmvol_trivial_usage | 253 | //usage:#define ubirmvol_trivial_usage |
254 | //usage: "-n VOLID / -N VOLNAME UBI_DEVICE" | 254 | //usage: "-n VOLID | -N VOLNAME UBI_DEVICE" |
255 | //usage:#define ubirmvol_full_usage "\n\n" | 255 | //usage:#define ubirmvol_full_usage "\n\n" |
256 | //usage: "Remove UBI volume\n" | 256 | //usage: "Remove UBI volume\n" |
257 | //usage: "\n -n VOLID Volume ID" | 257 | //usage: "\n -n VOLID Volume ID" |
diff --git a/modutils/modinfo.c b/modutils/modinfo.c index d15772f0d..0a86c3296 100644 --- a/modutils/modinfo.c +++ b/modutils/modinfo.c | |||
@@ -131,7 +131,7 @@ static void modinfo(const char *path, const char *version, | |||
131 | //usage: "\n -p Shortcut for '-F parm'" | 131 | //usage: "\n -p Shortcut for '-F parm'" |
132 | ////usage: "\n -n Shortcut for '-F filename'" | 132 | ////usage: "\n -n Shortcut for '-F filename'" |
133 | //usage: "\n -F keyword Keyword to look for" | 133 | //usage: "\n -F keyword Keyword to look for" |
134 | //usage: "\n -0 Separate output with NULs" | 134 | //usage: "\n -0 NUL terminated output" |
135 | //usage:#define modinfo_example_usage | 135 | //usage:#define modinfo_example_usage |
136 | //usage: "$ modinfo -F vermagic loop\n" | 136 | //usage: "$ modinfo -F vermagic loop\n" |
137 | 137 | ||
diff --git a/networking/ftpd.c b/networking/ftpd.c index 6ca231c90..0d6a289c7 100644 --- a/networking/ftpd.c +++ b/networking/ftpd.c | |||
@@ -54,7 +54,7 @@ | |||
54 | //kbuild:lib-$(CONFIG_FTPD) += ftpd.o | 54 | //kbuild:lib-$(CONFIG_FTPD) += ftpd.o |
55 | 55 | ||
56 | //usage:#define ftpd_trivial_usage | 56 | //usage:#define ftpd_trivial_usage |
57 | //usage: "[-wvS]"IF_FEATURE_FTPD_AUTHENTICATION(" [-a USER]")" [-t N] [-T N] [DIR]" | 57 | //usage: "[-wvS]"IF_FEATURE_FTPD_AUTHENTICATION(" [-a USER]")" [-t SEC] [-T SEC] [DIR]" |
58 | //usage:#define ftpd_full_usage "\n\n" | 58 | //usage:#define ftpd_full_usage "\n\n" |
59 | //usage: IF_NOT_FEATURE_FTPD_AUTHENTICATION( | 59 | //usage: IF_NOT_FEATURE_FTPD_AUTHENTICATION( |
60 | //usage: "Anonymous FTP server. Client access occurs under ftpd's UID.\n" | 60 | //usage: "Anonymous FTP server. Client access occurs under ftpd's UID.\n" |
@@ -63,7 +63,7 @@ | |||
63 | //usage: "FTP server. " | 63 | //usage: "FTP server. " |
64 | //usage: ) | 64 | //usage: ) |
65 | //usage: "Chroots to DIR, if this fails (run by non-root), cds to it.\n" | 65 | //usage: "Chroots to DIR, if this fails (run by non-root), cds to it.\n" |
66 | //usage: "Should be used as inetd service, inetd.conf line:\n" | 66 | //usage: "It is an inetd service, inetd.conf line:\n" |
67 | //usage: " 21 stream tcp nowait root ftpd ftpd /files/to/serve\n" | 67 | //usage: " 21 stream tcp nowait root ftpd ftpd /files/to/serve\n" |
68 | //usage: "Can be run from tcpsvd:\n" | 68 | //usage: "Can be run from tcpsvd:\n" |
69 | //usage: " tcpsvd -vE 0.0.0.0 21 ftpd /files/to/serve" | 69 | //usage: " tcpsvd -vE 0.0.0.0 21 ftpd /files/to/serve" |
diff --git a/networking/nameif.c b/networking/nameif.c index 854594c83..66e042688 100644 --- a/networking/nameif.c +++ b/networking/nameif.c | |||
@@ -52,10 +52,10 @@ | |||
52 | //usage:#define nameif_full_usage "\n\n" | 52 | //usage:#define nameif_full_usage "\n\n" |
53 | //usage: "Rename network interface while it in the down state." | 53 | //usage: "Rename network interface while it in the down state." |
54 | //usage: IF_NOT_FEATURE_NAMEIF_EXTENDED( | 54 | //usage: IF_NOT_FEATURE_NAMEIF_EXTENDED( |
55 | //usage: "\nThe device with address HWADDR is renamed to IFACE." | 55 | //usage: "\nThe device with address HWADDR is renamed to IFNAME." |
56 | //usage: ) | 56 | //usage: ) |
57 | //usage: IF_FEATURE_NAMEIF_EXTENDED( | 57 | //usage: IF_FEATURE_NAMEIF_EXTENDED( |
58 | //usage: "\nThe device matched by SELECTOR is renamed to IFACE." | 58 | //usage: "\nThe device matched by SELECTOR is renamed to IFNAME." |
59 | //usage: "\nSELECTOR can be a combination of:" | 59 | //usage: "\nSELECTOR can be a combination of:" |
60 | //usage: "\n driver=STRING" | 60 | //usage: "\n driver=STRING" |
61 | //usage: "\n bus=STRING" | 61 | //usage: "\n bus=STRING" |
diff --git a/networking/telnetd.c b/networking/telnetd.c index 29f805de7..de4d733f9 100644 --- a/networking/telnetd.c +++ b/networking/telnetd.c | |||
@@ -109,6 +109,7 @@ | |||
109 | //usage: "\n -i Inetd mode" | 109 | //usage: "\n -i Inetd mode" |
110 | //usage: IF_FEATURE_TELNETD_INETD_WAIT( | 110 | //usage: IF_FEATURE_TELNETD_INETD_WAIT( |
111 | //usage: "\n -w SEC Inetd 'wait' mode, linger time SEC" | 111 | //usage: "\n -w SEC Inetd 'wait' mode, linger time SEC" |
112 | //usage: "\n inetd.conf line: 23 stream tcp wait root telnetd telnetd -w10" | ||
112 | //usage: "\n -S Log to syslog (implied by -i or without -F and -w)" | 113 | //usage: "\n -S Log to syslog (implied by -i or without -F and -w)" |
113 | //usage: ) | 114 | //usage: ) |
114 | //usage: ) | 115 | //usage: ) |
diff --git a/networking/tftp.c b/networking/tftp.c index 4b86ed9de..f5b4367ca 100644 --- a/networking/tftp.c +++ b/networking/tftp.c | |||
@@ -113,10 +113,9 @@ | |||
113 | //usage:#define tftpd_full_usage "\n\n" | 113 | //usage:#define tftpd_full_usage "\n\n" |
114 | //usage: "Transfer a file on tftp client's request\n" | 114 | //usage: "Transfer a file on tftp client's request\n" |
115 | //usage: "\n" | 115 | //usage: "\n" |
116 | //usage: "tftpd should be used as an inetd service.\n" | 116 | //usage: "tftpd is an inetd service, inetd.conf line:\n" |
117 | //usage: "tftpd's line for inetd.conf:\n" | ||
118 | //usage: " 69 dgram udp nowait root tftpd tftpd -l /files/to/serve\n" | 117 | //usage: " 69 dgram udp nowait root tftpd tftpd -l /files/to/serve\n" |
119 | //usage: "It also can be ran from udpsvd:\n" | 118 | //usage: "Can be run from udpsvd:\n" |
120 | //usage: " udpsvd -vE 0.0.0.0 69 tftpd /files/to/serve\n" | 119 | //usage: " udpsvd -vE 0.0.0.0 69 tftpd /files/to/serve\n" |
121 | //usage: "\n -r Prohibit upload" | 120 | //usage: "\n -r Prohibit upload" |
122 | //usage: "\n -c Allow file creation via upload" | 121 | //usage: "\n -c Allow file creation via upload" |
diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c index 7f288f891..8d11a7539 100644 --- a/networking/udhcp/d6_dhcpc.c +++ b/networking/udhcp/d6_dhcpc.c | |||
@@ -479,15 +479,15 @@ static ALWAYS_INLINE uint32_t random_xid(void) | |||
479 | } | 479 | } |
480 | 480 | ||
481 | /* Initialize the packet with the proper defaults */ | 481 | /* Initialize the packet with the proper defaults */ |
482 | static uint8_t *init_d6_packet(struct d6_packet *packet, char type, uint32_t xid) | 482 | static uint8_t *init_d6_packet(struct d6_packet *packet, char type) |
483 | { | 483 | { |
484 | uint8_t *ptr; | 484 | uint8_t *ptr; |
485 | unsigned secs; | 485 | unsigned secs; |
486 | 486 | ||
487 | memset(packet, 0, sizeof(*packet)); | 487 | memset(packet, 0, sizeof(*packet)); |
488 | 488 | ||
489 | packet->d6_xid32 = xid; | 489 | packet->d6_xid32 = client_data.xid; |
490 | packet->d6_msg_type = type; | 490 | packet->d6_msg_type = type; /* union, overwrites lowest byte of d6_xid32 */ |
491 | 491 | ||
492 | /* ELAPSED_TIME option is required to be present by the RFC, | 492 | /* ELAPSED_TIME option is required to be present by the RFC, |
493 | * and some servers do check for its presense. [which?] | 493 | * and some servers do check for its presense. [which?] |
@@ -585,13 +585,13 @@ static int d6_mcast_from_client_data_ifindex(struct d6_packet *packet, uint8_t * | |||
585 | * about parameter values the client would like to have returned. | 585 | * about parameter values the client would like to have returned. |
586 | */ | 586 | */ |
587 | /* NOINLINE: limit stack usage in caller */ | 587 | /* NOINLINE: limit stack usage in caller */ |
588 | static NOINLINE int send_d6_info_request(uint32_t xid) | 588 | static NOINLINE int send_d6_info_request(void) |
589 | { | 589 | { |
590 | struct d6_packet packet; | 590 | struct d6_packet packet; |
591 | uint8_t *opt_ptr; | 591 | uint8_t *opt_ptr; |
592 | 592 | ||
593 | /* Fill in: msg type */ | 593 | /* Fill in: msg type, xid, ELAPSED_TIME */ |
594 | opt_ptr = init_d6_packet(&packet, D6_MSG_INFORMATION_REQUEST, xid); | 594 | opt_ptr = init_d6_packet(&packet, D6_MSG_INFORMATION_REQUEST); |
595 | 595 | ||
596 | /* Add options: client-id, | 596 | /* Add options: client-id, |
597 | * "param req" option according to -O, options specified with -x | 597 | * "param req" option according to -O, options specified with -x |
@@ -684,14 +684,14 @@ static NOINLINE int send_d6_info_request(uint32_t xid) | |||
684 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 684 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
685 | */ | 685 | */ |
686 | /* NOINLINE: limit stack usage in caller */ | 686 | /* NOINLINE: limit stack usage in caller */ |
687 | static NOINLINE int send_d6_discover(uint32_t xid, struct in6_addr *requested_ipv6) | 687 | static NOINLINE int send_d6_discover(struct in6_addr *requested_ipv6) |
688 | { | 688 | { |
689 | struct d6_packet packet; | 689 | struct d6_packet packet; |
690 | uint8_t *opt_ptr; | 690 | uint8_t *opt_ptr; |
691 | unsigned len; | 691 | unsigned len; |
692 | 692 | ||
693 | /* Fill in: msg type */ | 693 | /* Fill in: msg type, xid, ELAPSED_TIME */ |
694 | opt_ptr = init_d6_packet(&packet, D6_MSG_SOLICIT, xid); | 694 | opt_ptr = init_d6_packet(&packet, D6_MSG_SOLICIT); |
695 | 695 | ||
696 | /* Create new IA_NA, optionally with included IAADDR with requested IP */ | 696 | /* Create new IA_NA, optionally with included IAADDR with requested IP */ |
697 | free(client6_data.ia_na); | 697 | free(client6_data.ia_na); |
@@ -763,13 +763,13 @@ static NOINLINE int send_d6_discover(uint32_t xid, struct in6_addr *requested_ip | |||
763 | * messages from the server. | 763 | * messages from the server. |
764 | */ | 764 | */ |
765 | /* NOINLINE: limit stack usage in caller */ | 765 | /* NOINLINE: limit stack usage in caller */ |
766 | static NOINLINE int send_d6_select(uint32_t xid) | 766 | static NOINLINE int send_d6_select(void) |
767 | { | 767 | { |
768 | struct d6_packet packet; | 768 | struct d6_packet packet; |
769 | uint8_t *opt_ptr; | 769 | uint8_t *opt_ptr; |
770 | 770 | ||
771 | /* Fill in: msg type */ | 771 | /* Fill in: msg type, xid, ELAPSED_TIME */ |
772 | opt_ptr = init_d6_packet(&packet, D6_MSG_REQUEST, xid); | 772 | opt_ptr = init_d6_packet(&packet, D6_MSG_REQUEST); |
773 | 773 | ||
774 | /* server id */ | 774 | /* server id */ |
775 | opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2); | 775 | opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2); |
@@ -836,13 +836,13 @@ static NOINLINE int send_d6_select(uint32_t xid) | |||
836 | * about parameter values the client would like to have returned. | 836 | * about parameter values the client would like to have returned. |
837 | */ | 837 | */ |
838 | /* NOINLINE: limit stack usage in caller */ | 838 | /* NOINLINE: limit stack usage in caller */ |
839 | static NOINLINE int send_d6_renew(uint32_t xid, struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6) | 839 | static NOINLINE int send_d6_renew(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6) |
840 | { | 840 | { |
841 | struct d6_packet packet; | 841 | struct d6_packet packet; |
842 | uint8_t *opt_ptr; | 842 | uint8_t *opt_ptr; |
843 | 843 | ||
844 | /* Fill in: msg type */ | 844 | /* Fill in: msg type, xid, ELAPSED_TIME */ |
845 | opt_ptr = init_d6_packet(&packet, DHCPREQUEST, xid); | 845 | opt_ptr = init_d6_packet(&packet, DHCPREQUEST); |
846 | 846 | ||
847 | /* server id */ | 847 | /* server id */ |
848 | opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2); | 848 | opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2); |
@@ -877,8 +877,8 @@ int send_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6) | |||
877 | uint8_t *opt_ptr; | 877 | uint8_t *opt_ptr; |
878 | struct option_set *ci; | 878 | struct option_set *ci; |
879 | 879 | ||
880 | /* Fill in: msg type, client id */ | 880 | /* Fill in: msg type, xid, ELAPSED_TIME */ |
881 | opt_ptr = init_d6_packet(&packet, D6_MSG_RELEASE, random_xid()); | 881 | opt_ptr = init_d6_packet(&packet, D6_MSG_RELEASE); |
882 | /* server id */ | 882 | /* server id */ |
883 | opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2); | 883 | opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2); |
884 | /* IA NA (contains our current IP) */ | 884 | /* IA NA (contains our current IP) */ |
@@ -1097,6 +1097,7 @@ static void perform_d6_release(struct in6_addr *server_ipv6, struct in6_addr *ou | |||
1097 | || client_data.state == RENEW_REQUESTED | 1097 | || client_data.state == RENEW_REQUESTED |
1098 | ) { | 1098 | ) { |
1099 | bb_simple_info_msg("unicasting a release"); | 1099 | bb_simple_info_msg("unicasting a release"); |
1100 | client_data.xid = random_xid(); //TODO: can omit? | ||
1100 | send_d6_release(server_ipv6, our_cur_ipv6); /* unicast */ | 1101 | send_d6_release(server_ipv6, our_cur_ipv6); /* unicast */ |
1101 | } | 1102 | } |
1102 | bb_simple_info_msg("entering released state"); | 1103 | bb_simple_info_msg("entering released state"); |
@@ -1126,23 +1127,23 @@ static void client_background(void) | |||
1126 | //usage:# define IF_UDHCP_VERBOSE(...) | 1127 | //usage:# define IF_UDHCP_VERBOSE(...) |
1127 | //usage:#endif | 1128 | //usage:#endif |
1128 | //usage:#define udhcpc6_trivial_usage | 1129 | //usage:#define udhcpc6_trivial_usage |
1129 | //usage: "[-fbnq"IF_UDHCP_VERBOSE("v")"odR] [-i IFACE] [-r IPv6] [-s PROG] [-p PIDFILE]\n" | 1130 | //usage: "[-fbq"IF_UDHCP_VERBOSE("v")"R] [-t N] [-T SEC] [-A SEC|-n] [-i IFACE] [-s PROG]\n" |
1130 | //usage: " [-x OPT:VAL]... [-O OPT]..." IF_FEATURE_UDHCP_PORT(" [-P PORT]") | 1131 | //usage: " [-p PIDFILE]"IF_FEATURE_UDHCP_PORT(" [-P PORT]")" [-ldo] [-r IPv6] [-x OPT:VAL]... [-O OPT]..." |
1131 | //usage:#define udhcpc6_full_usage "\n" | 1132 | //usage:#define udhcpc6_full_usage "\n" |
1132 | //usage: "\n -i IFACE Interface to use (default "CONFIG_UDHCPC_DEFAULT_INTERFACE")" | 1133 | //usage: "\n -i IFACE Interface to use (default "CONFIG_UDHCPC_DEFAULT_INTERFACE")" |
1133 | //usage: "\n -p FILE Create pidfile" | 1134 | //usage: "\n -p FILE Create pidfile" |
1134 | //usage: "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")" | 1135 | //usage: "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")" |
1135 | //usage: "\n -B Request broadcast replies" | 1136 | //usage: "\n -B Request broadcast replies" |
1136 | //usage: "\n -t N Send up to N discover packets" | 1137 | //usage: "\n -t N Send up to N discover packets" |
1137 | //usage: "\n -T N Pause between packets (default 3 seconds)" | 1138 | //usage: "\n -T SEC Pause between packets (default 3)" |
1138 | //usage: "\n -A N Wait N seconds (default 20) after failure" | 1139 | //usage: "\n -A SEC Wait if lease is not obtained (default 20)" |
1139 | //usage: "\n -f Run in foreground" | ||
1140 | //usage: USE_FOR_MMU( | 1140 | //usage: USE_FOR_MMU( |
1141 | //usage: "\n -b Background if lease is not obtained" | 1141 | //usage: "\n -b Background if lease is not obtained" |
1142 | //usage: ) | 1142 | //usage: ) |
1143 | //usage: "\n -n Exit if lease is not obtained" | 1143 | //usage: "\n -n Exit if lease is not obtained" |
1144 | //usage: "\n -q Exit after obtaining lease" | 1144 | //usage: "\n -q Exit after obtaining lease" |
1145 | //usage: "\n -R Release IP on exit" | 1145 | //usage: "\n -R Release IP on exit" |
1146 | //usage: "\n -f Run in foreground" | ||
1146 | //usage: "\n -S Log to syslog too" | 1147 | //usage: "\n -S Log to syslog too" |
1147 | //usage: IF_FEATURE_UDHCP_PORT( | 1148 | //usage: IF_FEATURE_UDHCP_PORT( |
1148 | //usage: "\n -P PORT Use PORT (default 546)" | 1149 | //usage: "\n -P PORT Use PORT (default 546)" |
@@ -1150,12 +1151,12 @@ static void client_background(void) | |||
1150 | ////usage: IF_FEATURE_UDHCPC_ARPING( | 1151 | ////usage: IF_FEATURE_UDHCPC_ARPING( |
1151 | ////usage: "\n -a Use arping to validate offered address" | 1152 | ////usage: "\n -a Use arping to validate offered address" |
1152 | ////usage: ) | 1153 | ////usage: ) |
1153 | //usage: "\n -O OPT Request option OPT from server (cumulative)" | ||
1154 | //usage: "\n -o Don't request any options (unless -O is given)" | ||
1155 | //usage: "\n -r IPv6 Request this address ('no' to not request any IP)" | ||
1156 | //usage: "\n -d Request prefix" | ||
1157 | //usage: "\n -l Send 'information request' instead of 'solicit'" | 1154 | //usage: "\n -l Send 'information request' instead of 'solicit'" |
1158 | //usage: "\n (used for servers which do not assign IPv6 addresses)" | 1155 | //usage: "\n (used for servers which do not assign IPv6 addresses)" |
1156 | //usage: "\n -r IPv6 Request this address ('no' to not request any IP)" | ||
1157 | //usage: "\n -d Request prefix" | ||
1158 | //usage: "\n -o Don't request any options (unless -O is given)" | ||
1159 | //usage: "\n -O OPT Request option OPT from server (cumulative)" | ||
1159 | //usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)" | 1160 | //usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)" |
1160 | //usage: "\n Examples of string, numeric, and hex byte opts:" | 1161 | //usage: "\n Examples of string, numeric, and hex byte opts:" |
1161 | //usage: "\n -x hostname:bbox - option 12" | 1162 | //usage: "\n -x hostname:bbox - option 12" |
@@ -1183,7 +1184,6 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1183 | struct in6_addr srv6_buf; | 1184 | struct in6_addr srv6_buf; |
1184 | struct in6_addr ipv6_buf; | 1185 | struct in6_addr ipv6_buf; |
1185 | struct in6_addr *requested_ipv6; | 1186 | struct in6_addr *requested_ipv6; |
1186 | uint32_t xid = 0; | ||
1187 | int packet_num; | 1187 | int packet_num; |
1188 | int timeout; /* must be signed */ | 1188 | int timeout; /* must be signed */ |
1189 | int lease_remaining; /* must be signed */ | 1189 | int lease_remaining; /* must be signed */ |
@@ -1387,13 +1387,13 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1387 | if (!discover_retries || packet_num < discover_retries) { | 1387 | if (!discover_retries || packet_num < discover_retries) { |
1388 | if (packet_num == 0) { | 1388 | if (packet_num == 0) { |
1389 | change_listen_mode(LISTEN_RAW); | 1389 | change_listen_mode(LISTEN_RAW); |
1390 | xid = random_xid(); | 1390 | client_data.xid = random_xid(); |
1391 | } | 1391 | } |
1392 | /* multicast */ | 1392 | /* multicast */ |
1393 | if (opt & OPT_l) | 1393 | if (opt & OPT_l) |
1394 | send_d6_info_request(xid); | 1394 | send_d6_info_request(); |
1395 | else | 1395 | else |
1396 | send_d6_discover(xid, requested_ipv6); | 1396 | send_d6_discover(requested_ipv6); |
1397 | timeout = discover_timeout; | 1397 | timeout = discover_timeout; |
1398 | packet_num++; | 1398 | packet_num++; |
1399 | continue; | 1399 | continue; |
@@ -1427,7 +1427,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1427 | case REQUESTING: | 1427 | case REQUESTING: |
1428 | if (!discover_retries || packet_num < discover_retries) { | 1428 | if (!discover_retries || packet_num < discover_retries) { |
1429 | /* send multicast select packet */ | 1429 | /* send multicast select packet */ |
1430 | send_d6_select(xid); | 1430 | send_d6_select(); |
1431 | timeout = discover_timeout; | 1431 | timeout = discover_timeout; |
1432 | packet_num++; | 1432 | packet_num++; |
1433 | continue; | 1433 | continue; |
@@ -1459,9 +1459,9 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1459 | * into INIT_SELECTING state. | 1459 | * into INIT_SELECTING state. |
1460 | */ | 1460 | */ |
1461 | if (opt & OPT_l) | 1461 | if (opt & OPT_l) |
1462 | send_d6_info_request(xid); | 1462 | send_d6_info_request(); |
1463 | else | 1463 | else |
1464 | send_d6_renew(xid, &srv6_buf, requested_ipv6); | 1464 | send_d6_renew(&srv6_buf, requested_ipv6); |
1465 | timeout = discover_timeout; | 1465 | timeout = discover_timeout; |
1466 | packet_num++; | 1466 | packet_num++; |
1467 | continue; | 1467 | continue; |
@@ -1484,9 +1484,9 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1484 | * try to find DHCP server using broadcast */ | 1484 | * try to find DHCP server using broadcast */ |
1485 | if (lease_remaining > 0 && packet_num < 3) { | 1485 | if (lease_remaining > 0 && packet_num < 3) { |
1486 | if (opt & OPT_l) | 1486 | if (opt & OPT_l) |
1487 | send_d6_info_request(xid); | 1487 | send_d6_info_request(); |
1488 | else /* send a broadcast renew request */ | 1488 | else /* send a broadcast renew request */ |
1489 | send_d6_renew(xid, /*server_ipv6:*/ NULL, requested_ipv6); | 1489 | send_d6_renew(/*server_ipv6:*/ NULL, requested_ipv6); |
1490 | timeout = discover_timeout; | 1490 | timeout = discover_timeout; |
1491 | packet_num++; | 1491 | packet_num++; |
1492 | continue; | 1492 | continue; |
@@ -1581,9 +1581,9 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1581 | packet_end = (uint8_t*)&packet + len; | 1581 | packet_end = (uint8_t*)&packet + len; |
1582 | } | 1582 | } |
1583 | 1583 | ||
1584 | if ((packet.d6_xid32 & htonl(0x00ffffff)) != xid) { | 1584 | if ((packet.d6_xid32 & htonl(0x00ffffff)) != client_data.xid) { |
1585 | log1("xid %x (our is %x)%s", | 1585 | log1("xid %x (our is %x)%s", |
1586 | (unsigned)(packet.d6_xid32 & htonl(0x00ffffff)), (unsigned)xid, | 1586 | (unsigned)(packet.d6_xid32 & htonl(0x00ffffff)), (unsigned)client_data.xid, |
1587 | ", ignoring packet" | 1587 | ", ignoring packet" |
1588 | ); | 1588 | ); |
1589 | continue; | 1589 | continue; |
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index 4e3d8ca5e..331f13a8c 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c | |||
@@ -605,7 +605,7 @@ static void init_packet(struct dhcp_packet *packet, char type) | |||
605 | /* Fill in: op, htype, hlen, cookie fields; message type option: */ | 605 | /* Fill in: op, htype, hlen, cookie fields; message type option: */ |
606 | udhcp_init_header(packet, type); | 606 | udhcp_init_header(packet, type); |
607 | 607 | ||
608 | packet->xid = random_xid(); | 608 | packet->xid = client_data.xid; |
609 | 609 | ||
610 | client_data.last_secs = monotonic_sec(); | 610 | client_data.last_secs = monotonic_sec(); |
611 | if (client_data.first_secs == 0) | 611 | if (client_data.first_secs == 0) |
@@ -663,6 +663,24 @@ static void add_client_options(struct dhcp_packet *packet) | |||
663 | // ...add (DHCP_VENDOR, "udhcp "BB_VER) opt... | 663 | // ...add (DHCP_VENDOR, "udhcp "BB_VER) opt... |
664 | } | 664 | } |
665 | 665 | ||
666 | static void add_serverid_and_clientid_options(struct dhcp_packet *packet, uint32_t server) | ||
667 | { | ||
668 | struct option_set *ci; | ||
669 | |||
670 | udhcp_add_simple_option(packet, DHCP_SERVER_ID, server); | ||
671 | |||
672 | /* RFC 2131 section 2: | ||
673 | * If the client uses a 'client identifier' in one message, | ||
674 | * it MUST use that same identifier in all subsequent messages. | ||
675 | * section 3.1.6: | ||
676 | * If the client used a 'client identifier' when it obtained the lease, | ||
677 | * it MUST use the same 'client identifier' in the DHCPRELEASE message. | ||
678 | */ | ||
679 | ci = udhcp_find_option(client_data.options, DHCP_CLIENT_ID); | ||
680 | if (ci) | ||
681 | udhcp_add_binary_option(packet, ci->data); | ||
682 | } | ||
683 | |||
666 | /* RFC 2131 | 684 | /* RFC 2131 |
667 | * 4.4.4 Use of broadcast and unicast | 685 | * 4.4.4 Use of broadcast and unicast |
668 | * | 686 | * |
@@ -701,17 +719,15 @@ static int bcast_or_ucast(struct dhcp_packet *packet, uint32_t ciaddr, uint32_t | |||
701 | 719 | ||
702 | /* Broadcast a DHCP discover packet to the network, with an optionally requested IP */ | 720 | /* Broadcast a DHCP discover packet to the network, with an optionally requested IP */ |
703 | /* NOINLINE: limit stack usage in caller */ | 721 | /* NOINLINE: limit stack usage in caller */ |
704 | static NOINLINE int send_discover(uint32_t xid, uint32_t requested) | 722 | static NOINLINE int send_discover(uint32_t requested) |
705 | { | 723 | { |
706 | struct dhcp_packet packet; | 724 | struct dhcp_packet packet; |
707 | 725 | ||
708 | /* Fill in: op, htype, hlen, cookie, chaddr fields, | 726 | /* Fill in: op, htype, hlen, cookie, chaddr fields, |
709 | * random xid field (we override it below), | 727 | * xid field, message type option: |
710 | * message type option: | ||
711 | */ | 728 | */ |
712 | init_packet(&packet, DHCPDISCOVER); | 729 | init_packet(&packet, DHCPDISCOVER); |
713 | 730 | ||
714 | packet.xid = xid; | ||
715 | if (requested) | 731 | if (requested) |
716 | udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); | 732 | udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); |
717 | 733 | ||
@@ -729,7 +745,7 @@ static NOINLINE int send_discover(uint32_t xid, uint32_t requested) | |||
729 | * "The client _broadcasts_ a DHCPREQUEST message..." | 745 | * "The client _broadcasts_ a DHCPREQUEST message..." |
730 | */ | 746 | */ |
731 | /* NOINLINE: limit stack usage in caller */ | 747 | /* NOINLINE: limit stack usage in caller */ |
732 | static NOINLINE int send_select(uint32_t xid, uint32_t server, uint32_t requested) | 748 | static NOINLINE int send_select(uint32_t server, uint32_t requested) |
733 | { | 749 | { |
734 | struct dhcp_packet packet; | 750 | struct dhcp_packet packet; |
735 | struct in_addr temp_addr; | 751 | struct in_addr temp_addr; |
@@ -748,18 +764,16 @@ static NOINLINE int send_select(uint32_t xid, uint32_t server, uint32_t requeste | |||
748 | * include that list in all subsequent messages. | 764 | * include that list in all subsequent messages. |
749 | */ | 765 | */ |
750 | /* Fill in: op, htype, hlen, cookie, chaddr fields, | 766 | /* Fill in: op, htype, hlen, cookie, chaddr fields, |
751 | * random xid field (we override it below), | 767 | * xid field, message type option: |
752 | * message type option: | ||
753 | */ | 768 | */ |
754 | init_packet(&packet, DHCPREQUEST); | 769 | init_packet(&packet, DHCPREQUEST); |
755 | 770 | ||
756 | packet.xid = xid; | ||
757 | udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); | 771 | udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); |
758 | 772 | ||
759 | udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); | 773 | udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); |
760 | 774 | ||
761 | /* Add options: maxsize, | 775 | /* Add options: maxsize, |
762 | * "param req" option according to -O, and options specified with -x | 776 | * "param req" option according to -O, options specified with -x |
763 | */ | 777 | */ |
764 | add_client_options(&packet); | 778 | add_client_options(&packet); |
765 | 779 | ||
@@ -775,7 +789,7 @@ static NOINLINE int send_select(uint32_t xid, uint32_t server, uint32_t requeste | |||
775 | 789 | ||
776 | /* Unicast or broadcast a DHCP renew message */ | 790 | /* Unicast or broadcast a DHCP renew message */ |
777 | /* NOINLINE: limit stack usage in caller */ | 791 | /* NOINLINE: limit stack usage in caller */ |
778 | static NOINLINE int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) | 792 | static NOINLINE int send_renew(uint32_t server, uint32_t ciaddr) |
779 | { | 793 | { |
780 | struct dhcp_packet packet; | 794 | struct dhcp_packet packet; |
781 | 795 | ||
@@ -794,16 +808,14 @@ static NOINLINE int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) | |||
794 | * replying to the client. | 808 | * replying to the client. |
795 | */ | 809 | */ |
796 | /* Fill in: op, htype, hlen, cookie, chaddr fields, | 810 | /* Fill in: op, htype, hlen, cookie, chaddr fields, |
797 | * random xid field (we override it below), | 811 | * xid field, message type option: |
798 | * message type option: | ||
799 | */ | 812 | */ |
800 | init_packet(&packet, DHCPREQUEST); | 813 | init_packet(&packet, DHCPREQUEST); |
801 | 814 | ||
802 | packet.xid = xid; | ||
803 | packet.ciaddr = ciaddr; | 815 | packet.ciaddr = ciaddr; |
804 | 816 | ||
805 | /* Add options: maxsize, | 817 | /* Add options: maxsize, |
806 | * "param req" option according to -O, and options specified with -x | 818 | * "param req" option according to -O, options specified with -x |
807 | */ | 819 | */ |
808 | add_client_options(&packet); | 820 | add_client_options(&packet); |
809 | 821 | ||
@@ -821,7 +833,7 @@ static NOINLINE int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) | |||
821 | #if ENABLE_FEATURE_UDHCPC_ARPING | 833 | #if ENABLE_FEATURE_UDHCPC_ARPING |
822 | /* Broadcast a DHCP decline message */ | 834 | /* Broadcast a DHCP decline message */ |
823 | /* NOINLINE: limit stack usage in caller */ | 835 | /* NOINLINE: limit stack usage in caller */ |
824 | static NOINLINE int send_decline(/*uint32_t xid,*/ uint32_t server, uint32_t requested) | 836 | static NOINLINE int send_decline(uint32_t server, uint32_t requested) |
825 | { | 837 | { |
826 | struct dhcp_packet packet; | 838 | struct dhcp_packet packet; |
827 | 839 | ||
@@ -830,20 +842,10 @@ static NOINLINE int send_decline(/*uint32_t xid,*/ uint32_t server, uint32_t req | |||
830 | */ | 842 | */ |
831 | init_packet(&packet, DHCPDECLINE); | 843 | init_packet(&packet, DHCPDECLINE); |
832 | 844 | ||
833 | #if 0 | ||
834 | /* RFC 2131 says DHCPDECLINE's xid is randomly selected by client, | ||
835 | * but in case the server is buggy and wants DHCPDECLINE's xid | ||
836 | * to match the xid which started entire handshake, | ||
837 | * we use the same xid we used in initial DHCPDISCOVER: | ||
838 | */ | ||
839 | packet.xid = xid; | ||
840 | #endif | ||
841 | /* DHCPDECLINE uses "requested ip", not ciaddr, to store offered IP */ | 845 | /* DHCPDECLINE uses "requested ip", not ciaddr, to store offered IP */ |
842 | udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); | 846 | udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); |
843 | 847 | ||
844 | udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); | 848 | add_serverid_and_clientid_options(&packet, server); |
845 | |||
846 | //TODO: add client-id opt? | ||
847 | 849 | ||
848 | bb_simple_info_msg("broadcasting decline"); | 850 | bb_simple_info_msg("broadcasting decline"); |
849 | return raw_bcast_from_client_data_ifindex(&packet, INADDR_ANY); | 851 | return raw_bcast_from_client_data_ifindex(&packet, INADDR_ANY); |
@@ -856,7 +858,6 @@ ALWAYS_INLINE /* one caller, help compiler to use this fact */ | |||
856 | int send_release(uint32_t server, uint32_t ciaddr) | 858 | int send_release(uint32_t server, uint32_t ciaddr) |
857 | { | 859 | { |
858 | struct dhcp_packet packet; | 860 | struct dhcp_packet packet; |
859 | struct option_set *ci; | ||
860 | 861 | ||
861 | /* Fill in: op, htype, hlen, cookie, chaddr, random xid fields, | 862 | /* Fill in: op, htype, hlen, cookie, chaddr, random xid fields, |
862 | * message type option: | 863 | * message type option: |
@@ -866,15 +867,7 @@ int send_release(uint32_t server, uint32_t ciaddr) | |||
866 | /* DHCPRELEASE uses ciaddr, not "requested ip", to store IP being released */ | 867 | /* DHCPRELEASE uses ciaddr, not "requested ip", to store IP being released */ |
867 | packet.ciaddr = ciaddr; | 868 | packet.ciaddr = ciaddr; |
868 | 869 | ||
869 | udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); | 870 | add_serverid_and_clientid_options(&packet, server); |
870 | |||
871 | /* RFC 2131 section 3.1.6: | ||
872 | * If the client used a 'client identifier' when it obtained the lease, | ||
873 | * it MUST use the same 'client identifier' in the DHCPRELEASE message. | ||
874 | */ | ||
875 | ci = udhcp_find_option(client_data.options, DHCP_CLIENT_ID); | ||
876 | if (ci) | ||
877 | udhcp_add_binary_option(&packet, ci->data); | ||
878 | 871 | ||
879 | bb_info_msg("sending %s", "release"); | 872 | bb_info_msg("sending %s", "release"); |
880 | /* Note: normally we unicast here since "server" is not zero. | 873 | /* Note: normally we unicast here since "server" is not zero. |
@@ -1120,7 +1113,7 @@ static void change_listen_mode(int new_mode) | |||
1120 | /* else LISTEN_NONE: client_data.sockfd stays closed */ | 1113 | /* else LISTEN_NONE: client_data.sockfd stays closed */ |
1121 | } | 1114 | } |
1122 | 1115 | ||
1123 | static void perform_release(uint32_t server_addr, uint32_t requested_ip) | 1116 | static void perform_release(uint32_t server_id, uint32_t requested_ip) |
1124 | { | 1117 | { |
1125 | char buffer[sizeof("255.255.255.255")]; | 1118 | char buffer[sizeof("255.255.255.255")]; |
1126 | struct in_addr temp_addr; | 1119 | struct in_addr temp_addr; |
@@ -1133,12 +1126,13 @@ static void perform_release(uint32_t server_addr, uint32_t requested_ip) | |||
1133 | || client_data.state == REBINDING | 1126 | || client_data.state == REBINDING |
1134 | || client_data.state == RENEW_REQUESTED | 1127 | || client_data.state == RENEW_REQUESTED |
1135 | ) { | 1128 | ) { |
1136 | temp_addr.s_addr = server_addr; | 1129 | temp_addr.s_addr = server_id; |
1137 | strcpy(buffer, inet_ntoa(temp_addr)); | 1130 | strcpy(buffer, inet_ntoa(temp_addr)); |
1138 | temp_addr.s_addr = requested_ip; | 1131 | temp_addr.s_addr = requested_ip; |
1139 | bb_info_msg("unicasting a release of %s to %s", | 1132 | bb_info_msg("unicasting a release of %s to %s", |
1140 | inet_ntoa(temp_addr), buffer); | 1133 | inet_ntoa(temp_addr), buffer); |
1141 | send_release(server_addr, requested_ip); /* unicast */ | 1134 | client_data.xid = random_xid(); //TODO: can omit? |
1135 | send_release(server_id, requested_ip); /* unicast */ | ||
1142 | } | 1136 | } |
1143 | bb_simple_info_msg("entering released state"); | 1137 | bb_simple_info_msg("entering released state"); |
1144 | /* | 1138 | /* |
@@ -1167,7 +1161,7 @@ static void client_background(void) | |||
1167 | //usage:# define IF_UDHCP_VERBOSE(...) | 1161 | //usage:# define IF_UDHCP_VERBOSE(...) |
1168 | //usage:#endif | 1162 | //usage:#endif |
1169 | //usage:#define udhcpc_trivial_usage | 1163 | //usage:#define udhcpc_trivial_usage |
1170 | //usage: "[-fbq"IF_UDHCP_VERBOSE("v")"RB]"IF_FEATURE_UDHCPC_ARPING(" [-a[MSEC]]")" [-t N] [-T SEC] [-A SEC/-n]\n" | 1164 | //usage: "[-fbq"IF_UDHCP_VERBOSE("v")"RB]"IF_FEATURE_UDHCPC_ARPING(" [-a[MSEC]]")" [-t N] [-T SEC] [-A SEC|-n]\n" |
1171 | //usage: " [-i IFACE]"IF_FEATURE_UDHCP_PORT(" [-P PORT]")" [-s PROG] [-p PIDFILE]\n" | 1165 | //usage: " [-i IFACE]"IF_FEATURE_UDHCP_PORT(" [-P PORT]")" [-s PROG] [-p PIDFILE]\n" |
1172 | //usage: " [-oC] [-r IP] [-V VENDOR] [-F NAME] [-x OPT:VAL]... [-O OPT]..." | 1166 | //usage: " [-oC] [-r IP] [-V VENDOR] [-F NAME] [-x OPT:VAL]... [-O OPT]..." |
1173 | //usage:#define udhcpc_full_usage "\n" | 1167 | //usage:#define udhcpc_full_usage "\n" |
@@ -1224,9 +1218,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1224 | int tryagain_timeout = 20; | 1218 | int tryagain_timeout = 20; |
1225 | int discover_timeout = 3; | 1219 | int discover_timeout = 3; |
1226 | int discover_retries = 3; | 1220 | int discover_retries = 3; |
1227 | uint32_t server_addr = server_addr; /* for compiler */ | 1221 | uint32_t server_id = server_id; /* for compiler */ |
1228 | uint32_t requested_ip = 0; | 1222 | uint32_t requested_ip = 0; |
1229 | uint32_t xid = xid; /* for compiler */ | ||
1230 | int packet_num; | 1223 | int packet_num; |
1231 | int timeout; /* must be signed */ | 1224 | int timeout; /* must be signed */ |
1232 | int lease_remaining; /* must be signed */ | 1225 | int lease_remaining; /* must be signed */ |
@@ -1291,7 +1284,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1291 | memcpy(p + OPT_DATA + 3, str_F, len); /* do not store NUL byte */ | 1284 | memcpy(p + OPT_DATA + 3, str_F, len); /* do not store NUL byte */ |
1292 | } | 1285 | } |
1293 | if (opt & OPT_r) | 1286 | if (opt & OPT_r) |
1294 | requested_ip = inet_addr(str_r); | 1287 | if (!inet_aton(str_r, (void*)&requested_ip)) |
1288 | bb_show_usage(); | ||
1295 | #if ENABLE_FEATURE_UDHCP_PORT | 1289 | #if ENABLE_FEATURE_UDHCP_PORT |
1296 | if (opt & OPT_P) { | 1290 | if (opt & OPT_P) { |
1297 | CLIENT_PORT = xatou16(str_P); | 1291 | CLIENT_PORT = xatou16(str_P); |
@@ -1451,10 +1445,10 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1451 | if (!discover_retries || packet_num < discover_retries) { | 1445 | if (!discover_retries || packet_num < discover_retries) { |
1452 | if (packet_num == 0) { | 1446 | if (packet_num == 0) { |
1453 | change_listen_mode(LISTEN_RAW); | 1447 | change_listen_mode(LISTEN_RAW); |
1454 | xid = random_xid(); | 1448 | client_data.xid = random_xid(); |
1455 | } | 1449 | } |
1456 | /* broadcast */ | 1450 | /* broadcast */ |
1457 | send_discover(xid, requested_ip); | 1451 | send_discover(requested_ip); |
1458 | timeout = discover_timeout; | 1452 | timeout = discover_timeout; |
1459 | packet_num++; | 1453 | packet_num++; |
1460 | continue; | 1454 | continue; |
@@ -1488,7 +1482,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1488 | case REQUESTING: | 1482 | case REQUESTING: |
1489 | if (packet_num < 3) { | 1483 | if (packet_num < 3) { |
1490 | /* send broadcast select packet */ | 1484 | /* send broadcast select packet */ |
1491 | send_select(xid, server_addr, requested_ip); | 1485 | send_select(server_id, requested_ip); |
1492 | timeout = discover_timeout; | 1486 | timeout = discover_timeout; |
1493 | packet_num++; | 1487 | packet_num++; |
1494 | continue; | 1488 | continue; |
@@ -1519,7 +1513,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1519 | * Anyway, it does recover by eventually failing through | 1513 | * Anyway, it does recover by eventually failing through |
1520 | * into INIT_SELECTING state. | 1514 | * into INIT_SELECTING state. |
1521 | */ | 1515 | */ |
1522 | if (send_renew(xid, server_addr, requested_ip) >= 0) { | 1516 | if (send_renew(server_id, requested_ip) >= 0) { |
1523 | timeout = discover_timeout; | 1517 | timeout = discover_timeout; |
1524 | packet_num++; | 1518 | packet_num++; |
1525 | continue; | 1519 | continue; |
@@ -1548,7 +1542,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1548 | * try to find DHCP server using broadcast */ | 1542 | * try to find DHCP server using broadcast */ |
1549 | if (lease_remaining > 0 && packet_num < 3) { | 1543 | if (lease_remaining > 0 && packet_num < 3) { |
1550 | /* send a broadcast renew request */ | 1544 | /* send a broadcast renew request */ |
1551 | send_renew(xid, 0 /*INADDR_ANY*/, requested_ip); | 1545 | send_renew(0 /*INADDR_ANY*/, requested_ip); |
1552 | timeout = discover_timeout; | 1546 | timeout = discover_timeout; |
1553 | packet_num++; | 1547 | packet_num++; |
1554 | continue; | 1548 | continue; |
@@ -1610,7 +1604,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1610 | timeout = 0; | 1604 | timeout = 0; |
1611 | continue; | 1605 | continue; |
1612 | case SIGUSR2: | 1606 | case SIGUSR2: |
1613 | perform_release(server_addr, requested_ip); | 1607 | perform_release(server_id, requested_ip); |
1614 | /* ^^^ switches to LISTEN_NONE */ | 1608 | /* ^^^ switches to LISTEN_NONE */ |
1615 | timeout = INT_MAX; | 1609 | timeout = INT_MAX; |
1616 | continue; | 1610 | continue; |
@@ -1641,9 +1635,9 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1641 | continue; | 1635 | continue; |
1642 | } | 1636 | } |
1643 | 1637 | ||
1644 | if (packet.xid != xid) { | 1638 | if (packet.xid != client_data.xid) { |
1645 | log1("xid %x (our is %x)%s", | 1639 | log1("xid %x (our is %x)%s", |
1646 | (unsigned)packet.xid, (unsigned)xid, | 1640 | (unsigned)packet.xid, (unsigned)client_data.xid, |
1647 | ", ignoring packet" | 1641 | ", ignoring packet" |
1648 | ); | 1642 | ); |
1649 | continue; | 1643 | continue; |
@@ -1695,13 +1689,13 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1695 | * They either supply DHCP_SERVER_ID of 0.0.0.0 or don't supply it at all. | 1689 | * They either supply DHCP_SERVER_ID of 0.0.0.0 or don't supply it at all. |
1696 | * They say ISC DHCP client supports this case. | 1690 | * They say ISC DHCP client supports this case. |
1697 | */ | 1691 | */ |
1698 | server_addr = 0; | 1692 | server_id = 0; |
1699 | temp = udhcp_get_option32(&packet, DHCP_SERVER_ID); | 1693 | temp = udhcp_get_option32(&packet, DHCP_SERVER_ID); |
1700 | if (!temp) { | 1694 | if (!temp) { |
1701 | bb_simple_info_msg("no server ID, using 0.0.0.0"); | 1695 | bb_simple_info_msg("no server ID, using 0.0.0.0"); |
1702 | } else { | 1696 | } else { |
1703 | /* it IS unaligned sometimes, don't "optimize" */ | 1697 | /* it IS unaligned sometimes, don't "optimize" */ |
1704 | move_from_unaligned32(server_addr, temp); | 1698 | move_from_unaligned32(server_id, temp); |
1705 | } | 1699 | } |
1706 | /*xid = packet.xid; - already is */ | 1700 | /*xid = packet.xid; - already is */ |
1707 | temp_addr.s_addr = requested_ip = packet.yiaddr; | 1701 | temp_addr.s_addr = requested_ip = packet.yiaddr; |
@@ -1725,7 +1719,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1725 | 1719 | ||
1726 | change_listen_mode(LISTEN_NONE); | 1720 | change_listen_mode(LISTEN_NONE); |
1727 | 1721 | ||
1728 | temp_addr.s_addr = server_addr; | 1722 | temp_addr.s_addr = server_id; |
1729 | strcpy(server_str, inet_ntoa(temp_addr)); | 1723 | strcpy(server_str, inet_ntoa(temp_addr)); |
1730 | temp_addr.s_addr = packet.yiaddr; | 1724 | temp_addr.s_addr = packet.yiaddr; |
1731 | 1725 | ||
@@ -1772,7 +1766,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1772 | ) { | 1766 | ) { |
1773 | bb_simple_info_msg("offered address is in use " | 1767 | bb_simple_info_msg("offered address is in use " |
1774 | "(got ARP reply), declining"); | 1768 | "(got ARP reply), declining"); |
1775 | send_decline(/*xid,*/ server_addr, packet.yiaddr); | 1769 | client_data.xid = random_xid(); //TODO: can omit? |
1770 | send_decline(server_id, packet.yiaddr); | ||
1776 | 1771 | ||
1777 | if (client_data.state != REQUESTING) | 1772 | if (client_data.state != REQUESTING) |
1778 | d4_run_script_deconfig(); | 1773 | d4_run_script_deconfig(); |
@@ -1807,7 +1802,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1807 | timeout = (unsigned)lease_remaining / 2; | 1802 | timeout = (unsigned)lease_remaining / 2; |
1808 | client_data.state = BOUND; | 1803 | client_data.state = BOUND; |
1809 | /* make future renew packets use different xid */ | 1804 | /* make future renew packets use different xid */ |
1810 | /* xid = random_xid(); ...but why bother? */ | 1805 | /* client_data.xid = random_xid(); ...but why bother? */ |
1811 | packet_num = 0; | 1806 | packet_num = 0; |
1812 | continue; /* back to main loop */ | 1807 | continue; /* back to main loop */ |
1813 | } | 1808 | } |
@@ -1816,20 +1811,14 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1816 | * "wrong" server can reply first, with a NAK. | 1811 | * "wrong" server can reply first, with a NAK. |
1817 | * Do not interpret it as a NAK from "our" server. | 1812 | * Do not interpret it as a NAK from "our" server. |
1818 | */ | 1813 | */ |
1819 | if (server_addr != 0) { | 1814 | uint32_t svid = 0; /* we treat no server id as 0.0.0.0 */ |
1820 | uint32_t svid; | 1815 | uint8_t *temp = udhcp_get_option32(&packet, DHCP_SERVER_ID); |
1821 | uint8_t *temp; | 1816 | if (temp) |
1822 | |||
1823 | temp = udhcp_get_option32(&packet, DHCP_SERVER_ID); | ||
1824 | if (!temp) { | ||
1825 | non_matching_svid: | ||
1826 | log1("received DHCP NAK with wrong" | ||
1827 | " server ID%s", ", ignoring packet"); | ||
1828 | continue; | ||
1829 | } | ||
1830 | move_from_unaligned32(svid, temp); | 1817 | move_from_unaligned32(svid, temp); |
1831 | if (svid != server_addr) | 1818 | if (svid != server_id) { |
1832 | goto non_matching_svid; | 1819 | log1("received DHCP NAK with wrong" |
1820 | " server ID%s", ", ignoring packet"); | ||
1821 | continue; | ||
1833 | } | 1822 | } |
1834 | /* return to init state */ | 1823 | /* return to init state */ |
1835 | change_listen_mode(LISTEN_NONE); | 1824 | change_listen_mode(LISTEN_NONE); |
@@ -1853,7 +1842,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1853 | 1842 | ||
1854 | ret0: | 1843 | ret0: |
1855 | if (opt & OPT_R) /* release on quit */ | 1844 | if (opt & OPT_R) /* release on quit */ |
1856 | perform_release(server_addr, requested_ip); | 1845 | perform_release(server_id, requested_ip); |
1857 | retval = 0; | 1846 | retval = 0; |
1858 | ret: | 1847 | ret: |
1859 | /*if (client_data.pidfile) - remove_pidfile has its own check */ | 1848 | /*if (client_data.pidfile) - remove_pidfile has its own check */ |
diff --git a/networking/udhcp/dhcpc.h b/networking/udhcp/dhcpc.h index cd9ead6bd..19b054b32 100644 --- a/networking/udhcp/dhcpc.h +++ b/networking/udhcp/dhcpc.h | |||
@@ -11,6 +11,7 @@ struct client_data_t { | |||
11 | uint8_t client_mac[6]; /* Our mac address */ | 11 | uint8_t client_mac[6]; /* Our mac address */ |
12 | IF_FEATURE_UDHCP_PORT(uint16_t port;) | 12 | IF_FEATURE_UDHCP_PORT(uint16_t port;) |
13 | int ifindex; /* Index number of the interface to use */ | 13 | int ifindex; /* Index number of the interface to use */ |
14 | uint32_t xid; | ||
14 | uint8_t opt_mask[256 / 8]; /* Bitmask of options to send (-O option) */ | 15 | uint8_t opt_mask[256 / 8]; /* Bitmask of options to send (-O option) */ |
15 | // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TODO: DHCPv6 has 16-bit option numbers | 16 | // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TODO: DHCPv6 has 16-bit option numbers |
16 | const char *interface; /* The name of the interface to use */ | 17 | const char *interface; /* The name of the interface to use */ |
diff --git a/networking/vconfig.c b/networking/vconfig.c index 4f1fbe280..7e805be9c 100644 --- a/networking/vconfig.c +++ b/networking/vconfig.c | |||
@@ -20,12 +20,12 @@ | |||
20 | //usage: "COMMAND [OPTIONS]" | 20 | //usage: "COMMAND [OPTIONS]" |
21 | //usage:#define vconfig_full_usage "\n\n" | 21 | //usage:#define vconfig_full_usage "\n\n" |
22 | //usage: "Create and remove virtual ethernet devices\n" | 22 | //usage: "Create and remove virtual ethernet devices\n" |
23 | //usage: "\n add IFACE VLAN_ID" | 23 | //usage: "\n add IFACE VLAN_ID" |
24 | //usage: "\n rem VLAN_NAME" | 24 | //usage: "\n rem VLAN_NAME" |
25 | //usage: "\n set_flag IFACE 0|1 VLAN_QOS" | 25 | //usage: "\n set_flag IFACE 0|1 VLAN_QOS" |
26 | //usage: "\n set_egress_map VLAN_NAME SKB_PRIO VLAN_QOS" | 26 | //usage: "\n set_egress_map VLAN_NAME SKB_PRIO VLAN_QOS" |
27 | //usage: "\n set_ingress_map VLAN_NAME SKB_PRIO VLAN_QOS" | 27 | //usage: "\n set_ingress_map VLAN_NAME SKB_PRIO VLAN_QOS" |
28 | //usage: "\n set_name_type NAME_TYPE" | 28 | //usage: "\n set_name_type NAME_TYPE" |
29 | 29 | ||
30 | #include "libbb.h" | 30 | #include "libbb.h" |
31 | #include <net/if.h> | 31 | #include <net/if.h> |
diff --git a/procps/free.c b/procps/free.c index 142786083..f19c38dd5 100644 --- a/procps/free.c +++ b/procps/free.c | |||
@@ -19,9 +19,9 @@ | |||
19 | //kbuild:lib-$(CONFIG_FREE) += free.o | 19 | //kbuild:lib-$(CONFIG_FREE) += free.o |
20 | 20 | ||
21 | //usage:#define free_trivial_usage | 21 | //usage:#define free_trivial_usage |
22 | //usage: "" IF_DESKTOP("[-b/k/m/g]") | 22 | //usage: "" IF_DESKTOP("[-bkmgh]") |
23 | //usage:#define free_full_usage "\n\n" | 23 | //usage:#define free_full_usage "\n\n" |
24 | //usage: "Display the amount of free and used system memory" | 24 | //usage: "Display free and used memory" |
25 | //usage: | 25 | //usage: |
26 | //usage:#define free_example_usage | 26 | //usage:#define free_example_usage |
27 | //usage: "$ free\n" | 27 | //usage: "$ free\n" |
@@ -29,6 +29,27 @@ | |||
29 | //usage: " Mem: 257628 248724 8904 59644 93124\n" | 29 | //usage: " Mem: 257628 248724 8904 59644 93124\n" |
30 | //usage: " Swap: 128516 8404 120112\n" | 30 | //usage: " Swap: 128516 8404 120112\n" |
31 | //usage: "Total: 386144 257128 129016\n" | 31 | //usage: "Total: 386144 257128 129016\n" |
32 | //procps-ng 3.3.15: | ||
33 | // -b, --bytes show output in bytes | ||
34 | // --kilo show output in kilobytes | ||
35 | // --mega show output in megabytes | ||
36 | // --giga show output in gigabytes | ||
37 | // --tera show output in terabytes | ||
38 | // --peta show output in petabytes | ||
39 | // -k, --kibi show output in kibibytes | ||
40 | // -m, --mebi show output in mebibytes | ||
41 | // -g, --gibi show output in gibibytes | ||
42 | // --tebi show output in tebibytes | ||
43 | // --pebi show output in pebibytes | ||
44 | // -h, --human show human-readable output | ||
45 | // --si use powers of 1000 not 1024 | ||
46 | // -l, --lohi show detailed low and high memory statistics | ||
47 | // -t, --total show total for RAM + swap | ||
48 | // -s N, --seconds N repeat printing every N seconds | ||
49 | // -c N, --count N repeat printing N times, then exit | ||
50 | // -w, --wide wide output | ||
51 | // | ||
52 | //NB: if we implement -s or -c, need to stop being NOFORK! | ||
32 | 53 | ||
33 | #include "libbb.h" | 54 | #include "libbb.h" |
34 | #ifdef __linux__ | 55 | #ifdef __linux__ |
@@ -38,18 +59,22 @@ | |||
38 | struct globals { | 59 | struct globals { |
39 | unsigned mem_unit; | 60 | unsigned mem_unit; |
40 | #if ENABLE_DESKTOP | 61 | #if ENABLE_DESKTOP |
41 | uint8_t unit_steps; | 62 | unsigned unit; |
42 | # define G_unit_steps g->unit_steps | 63 | # define G_unit g->unit |
43 | #else | 64 | #else |
44 | # define G_unit_steps 10 | 65 | # define G_unit (1 << 10) |
45 | #endif | 66 | #endif |
46 | unsigned long cached_kb, available_kb, reclaimable_kb; | 67 | unsigned long cached_kb, available_kb, reclaimable_kb; |
47 | }; | 68 | }; |
48 | /* Because of NOFORK, "globals" are not in global data */ | 69 | /* Because of NOFORK, "globals" are not in global data */ |
49 | 70 | ||
50 | static unsigned long long scale(struct globals *g, unsigned long d) | 71 | static const char *scale(struct globals *g, unsigned long d) |
51 | { | 72 | { |
52 | return ((unsigned long long)d * g->mem_unit) >> G_unit_steps; | 73 | /* Display (size * block_size) with one decimal digit. |
74 | * If display_unit == 0, show value no bigger than 1024 with suffix (K,M,G...), | ||
75 | * else divide by display_unit and do not use suffix. | ||
76 | * Returns "auto pointer" */ | ||
77 | return make_human_readable_str(d, g->mem_unit, G_unit); | ||
53 | } | 78 | } |
54 | 79 | ||
55 | #if !ENABLE_PLATFORM_MINGW32 | 80 | #if !ENABLE_PLATFORM_MINGW32 |
@@ -97,20 +122,27 @@ int free_main(int argc UNUSED_PARAM, char **argv IF_NOT_DESKTOP(UNUSED_PARAM)) | |||
97 | int seen_available; | 122 | int seen_available; |
98 | 123 | ||
99 | #if ENABLE_DESKTOP | 124 | #if ENABLE_DESKTOP |
100 | G.unit_steps = 10; | 125 | G.unit = 1 << 10; |
101 | if (argv[1] && argv[1][0] == '-') { | 126 | if (argv[1] && argv[1][0] == '-') { |
102 | switch (argv[1][1]) { | 127 | switch (argv[1][1]) { |
103 | case 'b': | 128 | case 'b': |
104 | G.unit_steps = 0; | 129 | G.unit = 1; |
105 | break; | 130 | break; |
106 | case 'k': /* 2^10 */ | 131 | case 'k': /* 2^10 */ |
107 | /* G.unit_steps = 10; - already is */ | 132 | /* G.unit = 1 << 10; - already is */ |
108 | break; | 133 | break; |
109 | case 'm': /* 2^20 */ | 134 | case 'm': /* 2^20 */ |
110 | G.unit_steps = 20; | 135 | G.unit = 1 << 20; |
111 | break; | 136 | break; |
112 | case 'g': /* 2^30 */ | 137 | case 'g': /* 2^30 */ |
113 | G.unit_steps = 30; | 138 | G.unit = 1 << 30; |
139 | break; | ||
140 | // case 't': | ||
141 | // -- WRONG, -t is not "terabytes" in procps-ng, it's --total | ||
142 | // G.unit = 1 << 40; | ||
143 | // break; | ||
144 | case 'h': | ||
145 | G.unit = 0; /* human readable */ | ||
114 | break; | 146 | break; |
115 | default: | 147 | default: |
116 | bb_show_usage(); | 148 | bb_show_usage(); |
@@ -135,29 +167,13 @@ int free_main(int argc UNUSED_PARAM, char **argv IF_NOT_DESKTOP(UNUSED_PARAM)) | |||
135 | cached += ((unsigned long long) G.reclaimable_kb * 1024) / G.mem_unit; | 167 | cached += ((unsigned long long) G.reclaimable_kb * 1024) / G.mem_unit; |
136 | cached_plus_free = cached + info.freeram; | 168 | cached_plus_free = cached + info.freeram; |
137 | 169 | ||
138 | /* In case (long long * G.mem_unit) can overflow, this can be used to reduce the chances */ | 170 | printf("%12s%12s%12s", |
139 | #if 0 //ENABLE_DESKTOP | ||
140 | while (!(G.mem_unit & 1) && G.unit_steps != 0) { | ||
141 | G.mem_unit >>= 1; | ||
142 | G.unit_steps--; | ||
143 | //bb_error_msg("mem_unit:%d unit_steps:%d", G.mem_unit, G.unit_steps); | ||
144 | } | ||
145 | #endif | ||
146 | |||
147 | #if !ENABLE_PLATFORM_MINGW32 | ||
148 | #define FIELDS_6 "%12llu %11llu %11llu %11llu %11llu %11llu\n" | ||
149 | #define FIELDS_3 (FIELDS_6 + 6 + 7 + 7) | ||
150 | #define FIELDS_2 (FIELDS_6 + 6 + 7 + 7 + 7) | ||
151 | #else | ||
152 | #define FIELDS_6 "%12I64u %11I64u %11I64u %11I64u %11I64u %11I64u\n" | ||
153 | #define FIELDS_3 (FIELDS_6 + 7 + 8 + 8) | ||
154 | #define FIELDS_2 (FIELDS_6 + 8 + 8 + 8 + 8) | ||
155 | #endif | ||
156 | |||
157 | printf(FIELDS_6, | ||
158 | scale(&G, info.totalram), //total | 171 | scale(&G, info.totalram), //total |
159 | scale(&G, info.totalram - cached_plus_free), //used | 172 | scale(&G, info.totalram - cached_plus_free), //used |
160 | scale(&G, info.freeram), //free | 173 | scale(&G, info.freeram) //free |
174 | ); | ||
175 | /* using two printf's: only 4 auto strings are supported, we need 6 */ | ||
176 | printf("%12s%12s%12s\n", | ||
161 | scale(&G, info.sharedram), //shared | 177 | scale(&G, info.sharedram), //shared |
162 | scale(&G, cached), //buff/cache | 178 | scale(&G, cached), //buff/cache |
163 | scale(&G, available) //available | 179 | scale(&G, available) //available |
@@ -167,14 +183,14 @@ int free_main(int argc UNUSED_PARAM, char **argv IF_NOT_DESKTOP(UNUSED_PARAM)) | |||
167 | * buffer cache as free memory. */ | 183 | * buffer cache as free memory. */ |
168 | if (!seen_available) { | 184 | if (!seen_available) { |
169 | printf("-/+ buffers/cache: "); | 185 | printf("-/+ buffers/cache: "); |
170 | printf(FIELDS_2, | 186 | printf("%12s%12s%12s\n" + 4, |
171 | scale(&G, info.totalram - cached_plus_free), //used | 187 | scale(&G, info.totalram - cached_plus_free), //used |
172 | scale(&G, cached_plus_free) //free | 188 | scale(&G, cached_plus_free) //free |
173 | ); | 189 | ); |
174 | } | 190 | } |
175 | #if BB_MMU | 191 | #if BB_MMU |
176 | printf("Swap: "); | 192 | printf("Swap: "); |
177 | printf(FIELDS_3, | 193 | printf("%12s%12s%12s\n", |
178 | scale(&G, info.totalswap), //total | 194 | scale(&G, info.totalswap), //total |
179 | scale(&G, info.totalswap - info.freeswap), //used | 195 | scale(&G, info.totalswap - info.freeswap), //used |
180 | scale(&G, info.freeswap) //free | 196 | scale(&G, info.freeswap) //free |
diff --git a/procps/kill.c b/procps/kill.c index 358d8f42b..8c2bc2b6f 100644 --- a/procps/kill.c +++ b/procps/kill.c | |||
@@ -59,7 +59,7 @@ | |||
59 | //usage: "$ kill 252\n" | 59 | //usage: "$ kill 252\n" |
60 | //usage: | 60 | //usage: |
61 | //usage:#define killall_trivial_usage | 61 | //usage:#define killall_trivial_usage |
62 | //usage: "[-l] [-q] [-SIG] PROCESS_NAME..." | 62 | //usage: "[-lq] [-SIG] PROCESS_NAME..." |
63 | //usage:#define killall_full_usage "\n\n" | 63 | //usage:#define killall_full_usage "\n\n" |
64 | //usage: "Send a signal (default: TERM) to given processes\n" | 64 | //usage: "Send a signal (default: TERM) to given processes\n" |
65 | //usage: "\n -l List all signal names and numbers" | 65 | //usage: "\n -l List all signal names and numbers" |
diff --git a/procps/lsof.c b/procps/lsof.c index 21ac85ed3..9cb8d066c 100644 --- a/procps/lsof.c +++ b/procps/lsof.c | |||
@@ -66,7 +66,7 @@ int lsof_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
66 | 66 | ||
67 | safe_strncpy(name + baseofs, entry->d_name, 10); | 67 | safe_strncpy(name + baseofs, entry->d_name, 10); |
68 | if ((fdlink = xmalloc_readlink(name)) != NULL) { | 68 | if ((fdlink = xmalloc_readlink(name)) != NULL) { |
69 | printf("%d\t%s\t%s\n", proc->pid, proc->exe, fdlink); | 69 | printf("%d\t%s\t%s\t%s\n", proc->pid, proc->exe, entry->d_name, fdlink); |
70 | free(fdlink); | 70 | free(fdlink); |
71 | } | 71 | } |
72 | } | 72 | } |
diff --git a/procps/pgrep.c b/procps/pgrep.c index 495e0ef9d..6d25c247e 100644 --- a/procps/pgrep.c +++ b/procps/pgrep.c | |||
@@ -44,17 +44,17 @@ | |||
44 | //usage: "\n -P Match parent process ID" | 44 | //usage: "\n -P Match parent process ID" |
45 | //usage: | 45 | //usage: |
46 | //usage:#define pkill_trivial_usage | 46 | //usage:#define pkill_trivial_usage |
47 | //usage: "[-l|-SIGNAL] [-fnovx] [-s SID|-P PPID|PATTERN]" | 47 | //usage: "[-l|-SIGNAL] [-xfvno] [-s SID|-P PPID|PATTERN]" |
48 | //usage:#define pkill_full_usage "\n\n" | 48 | //usage:#define pkill_full_usage "\n\n" |
49 | //usage: "Send a signal to process(es) selected by regex PATTERN\n" | 49 | //usage: "Send signal to processes selected by regex PATTERN\n" |
50 | //usage: "\n -l List all signals" | 50 | //usage: "\n -l List all signals" |
51 | //usage: "\n -x Match whole name (not substring)" | ||
51 | //usage: "\n -f Match against entire command line" | 52 | //usage: "\n -f Match against entire command line" |
53 | //usage: "\n -s SID Match session ID (0 for current)" | ||
54 | //usage: "\n -P PPID Match parent process ID" | ||
55 | //usage: "\n -v Negate the match" | ||
52 | //usage: "\n -n Signal the newest process only" | 56 | //usage: "\n -n Signal the newest process only" |
53 | //usage: "\n -o Signal the oldest process only" | 57 | //usage: "\n -o Signal the oldest process only" |
54 | //usage: "\n -v Negate the match" | ||
55 | //usage: "\n -x Match whole name (not substring)" | ||
56 | //usage: "\n -s Match session ID (0 for current)" | ||
57 | //usage: "\n -P Match parent process ID" | ||
58 | 58 | ||
59 | #include "libbb.h" | 59 | #include "libbb.h" |
60 | #include "xregex.h" | 60 | #include "xregex.h" |
diff --git a/procps/sysctl.c b/procps/sysctl.c index e16b119e9..40afa0c90 100644 --- a/procps/sysctl.c +++ b/procps/sysctl.c | |||
@@ -21,16 +21,16 @@ | |||
21 | //kbuild:lib-$(CONFIG_BB_SYSCTL) += sysctl.o | 21 | //kbuild:lib-$(CONFIG_BB_SYSCTL) += sysctl.o |
22 | 22 | ||
23 | //usage:#define sysctl_trivial_usage | 23 | //usage:#define sysctl_trivial_usage |
24 | //usage: "-p [-enq] [FILE...] / [-enqaw] [KEY[=VALUE]]..." | 24 | //usage: "[-enq] { -a | -p [FILE]... | [-w] [KEY[=VALUE]]... }" |
25 | //usage:#define sysctl_full_usage "\n\n" | 25 | //usage:#define sysctl_full_usage "\n\n" |
26 | //usage: "Show/set kernel parameters\n" | 26 | //usage: "Show/set kernel parameters\n" |
27 | //usage: "\n -p Set values from FILEs (default /etc/sysctl.conf)" | ||
28 | //usage: "\n -e Don't warn about unknown keys" | 27 | //usage: "\n -e Don't warn about unknown keys" |
29 | //usage: "\n -n Don't show key names" | 28 | //usage: "\n -n Don't show key names" |
30 | //usage: "\n -q Quiet" | 29 | //usage: "\n -q Quiet" |
31 | //usage: "\n -a Show all values" | 30 | //usage: "\n -a Show all values" |
32 | /* Same as -a, no need to show it */ | 31 | /* Same as -a, no need to show it */ |
33 | /* //usage: "\n -A Show all values in table form" */ | 32 | /* //usage: "\n -A Show all values in table form" */ |
33 | //usage: "\n -p Set values from FILEs (default /etc/sysctl.conf)" | ||
34 | //usage: "\n -w Set values" | 34 | //usage: "\n -w Set values" |
35 | //usage: | 35 | //usage: |
36 | //usage:#define sysctl_example_usage | 36 | //usage:#define sysctl_example_usage |
diff --git a/procps/top.c b/procps/top.c index cadc4ecec..4cd545c69 100644 --- a/procps/top.c +++ b/procps/top.c | |||
@@ -1052,9 +1052,9 @@ static unsigned handle_input(unsigned scan_mask, duration_t interval) | |||
1052 | //usage: "[-b"IF_FEATURE_TOPMEM("m")IF_FEATURE_SHOW_THREADS("H")"]" | 1052 | //usage: "[-b"IF_FEATURE_TOPMEM("m")IF_FEATURE_SHOW_THREADS("H")"]" |
1053 | //usage: " [-n COUNT] [-d SECONDS]" | 1053 | //usage: " [-n COUNT] [-d SECONDS]" |
1054 | //usage:#define top_full_usage "\n\n" | 1054 | //usage:#define top_full_usage "\n\n" |
1055 | //usage: "Provide a view of process activity in real time." | 1055 | //usage: "Show a view of process activity in real time." |
1056 | //usage: "\n""Read the status of all processes from /proc each SECONDS" | 1056 | //usage: "\n""Read the status of all processes from /proc each SECONDS" |
1057 | //usage: "\n""and display a screenful of them." | 1057 | //usage: "\n""and show a screenful of them." |
1058 | //usage: "\n" | 1058 | //usage: "\n" |
1059 | //usage: IF_FEATURE_TOP_INTERACTIVE( | 1059 | //usage: IF_FEATURE_TOP_INTERACTIVE( |
1060 | //usage: "Keys:" | 1060 | //usage: "Keys:" |
diff --git a/procps/watch.c b/procps/watch.c index 059eb1dda..1190b29df 100644 --- a/procps/watch.c +++ b/procps/watch.c | |||
@@ -22,7 +22,7 @@ | |||
22 | //usage: "[-n SEC] [-t] PROG ARGS" | 22 | //usage: "[-n SEC] [-t] PROG ARGS" |
23 | //usage:#define watch_full_usage "\n\n" | 23 | //usage:#define watch_full_usage "\n\n" |
24 | //usage: "Run PROG periodically\n" | 24 | //usage: "Run PROG periodically\n" |
25 | //usage: "\n -n SEC Loop period (default 2)" | 25 | //usage: "\n -n SEC Period (default 2)" |
26 | //usage: "\n -t Don't print header" | 26 | //usage: "\n -t Don't print header" |
27 | //usage: | 27 | //usage: |
28 | //usage:#define watch_example_usage | 28 | //usage:#define watch_example_usage |
diff --git a/runit/svlogd.c b/runit/svlogd.c index 02c305696..f7576f0fa 100644 --- a/runit/svlogd.c +++ b/runit/svlogd.c | |||
@@ -140,12 +140,12 @@ log message, you can use a pattern like this instead | |||
140 | //usage:#define svlogd_full_usage "\n\n" | 140 | //usage:#define svlogd_full_usage "\n\n" |
141 | //usage: "Read log data from stdin and write to rotated log files in DIRs" | 141 | //usage: "Read log data from stdin and write to rotated log files in DIRs" |
142 | //usage: "\n" | 142 | //usage: "\n" |
143 | //usage: "\n""-r C Replace non-printable characters with C" | 143 | //usage: "\n"" -r C Replace non-printable characters with C" |
144 | //usage: "\n""-R CHARS Also replace CHARS with C (default _)" | 144 | //usage: "\n"" -R CHARS Also replace CHARS with C (default _)" |
145 | //usage: "\n""-t Timestamp with @tai64n" | 145 | //usage: "\n"" -t Timestamp with @tai64n" |
146 | //usage: "\n""-tt Timestamp with yyyy-mm-dd_hh:mm:ss.sssss" | 146 | //usage: "\n"" -tt Timestamp with yyyy-mm-dd_hh:mm:ss.sssss" |
147 | //usage: "\n""-ttt Timestamp with yyyy-mm-ddThh:mm:ss.sssss" | 147 | //usage: "\n"" -ttt Timestamp with yyyy-mm-ddThh:mm:ss.sssss" |
148 | //usage: "\n""-v Verbose" | 148 | //usage: "\n"" -v Verbose" |
149 | //usage: "\n" | 149 | //usage: "\n" |
150 | //usage: "\n""DIR/config file modifies behavior:" | 150 | //usage: "\n""DIR/config file modifies behavior:" |
151 | //usage: "\n""sSIZE - when to rotate logs (default 1000000, 0 disables)" | 151 | //usage: "\n""sSIZE - when to rotate logs (default 1000000, 0 disables)" |
diff --git a/shell/ash.c b/shell/ash.c index bab6138da..4ae42595d 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -13572,7 +13572,7 @@ parsesub: { | |||
13572 | do { | 13572 | do { |
13573 | STPUTC(c, out); | 13573 | STPUTC(c, out); |
13574 | c = pgetc_eatbnl(); | 13574 | c = pgetc_eatbnl(); |
13575 | } while (!subtype && isdigit(c)); | 13575 | } while ((subtype == 0 || subtype == VSLENGTH) && isdigit(c)); |
13576 | } else if (c != '}') { | 13576 | } else if (c != '}') { |
13577 | /* $[{[#]]<specialchar>[}] */ | 13577 | /* $[{[#]]<specialchar>[}] */ |
13578 | int cc = c; | 13578 | int cc = c; |
@@ -13602,11 +13602,6 @@ parsesub: { | |||
13602 | } else | 13602 | } else |
13603 | goto badsub; | 13603 | goto badsub; |
13604 | 13604 | ||
13605 | if (c != '}' && subtype == VSLENGTH) { | ||
13606 | /* ${#VAR didn't end with } */ | ||
13607 | goto badsub; | ||
13608 | } | ||
13609 | |||
13610 | if (subtype == 0) { | 13605 | if (subtype == 0) { |
13611 | static const char types[] ALIGN1 = "}-+?="; | 13606 | static const char types[] ALIGN1 = "}-+?="; |
13612 | /* ${VAR...} but not $VAR or ${#VAR} */ | 13607 | /* ${VAR...} but not $VAR or ${#VAR} */ |
@@ -13663,6 +13658,8 @@ parsesub: { | |||
13663 | #endif | 13658 | #endif |
13664 | } | 13659 | } |
13665 | } else { | 13660 | } else { |
13661 | if (subtype == VSLENGTH && c != '}') | ||
13662 | subtype = 0; | ||
13666 | badsub: | 13663 | badsub: |
13667 | pungetc(); | 13664 | pungetc(); |
13668 | } | 13665 | } |
@@ -15358,7 +15355,7 @@ init(void) | |||
15358 | 15355 | ||
15359 | 15356 | ||
15360 | //usage:#define ash_trivial_usage | 15357 | //usage:#define ash_trivial_usage |
15361 | //usage: "[-il] [-/+Cabefmnuvx] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS] / -s [ARGS]]" | 15358 | //usage: "[-il] [-|+Cabefmnuvx] [-|+o OPT]... [-c 'SCRIPT' [ARG0 ARGS] | FILE [ARGS] | -s [ARGS]]" |
15362 | //////// comes from ^^^^^^^^^^optletters | 15359 | //////// comes from ^^^^^^^^^^optletters |
15363 | //usage:#define ash_full_usage "\n\n" | 15360 | //usage:#define ash_full_usage "\n\n" |
15364 | //usage: "Unix shell interpreter" | 15361 | //usage: "Unix shell interpreter" |
diff --git a/shell/ash_test/ash-misc/control_char3.right b/shell/ash_test/ash-misc/control_char3.right new file mode 100644 index 000000000..283e02cbb --- /dev/null +++ b/shell/ash_test/ash-misc/control_char3.right | |||
@@ -0,0 +1 @@ | |||
SHELL: line 1: : not found | |||
diff --git a/shell/ash_test/ash-misc/control_char3.tests b/shell/ash_test/ash-misc/control_char3.tests new file mode 100755 index 000000000..4359db3f3 --- /dev/null +++ b/shell/ash_test/ash-misc/control_char3.tests | |||
@@ -0,0 +1,2 @@ | |||
1 | # (set argv0 to "SHELL" to avoid "/path/to/shell: blah" in error messages) | ||
2 | $THIS_SH -c '\' SHELL | ||
diff --git a/shell/ash_test/ash-misc/control_char4.right b/shell/ash_test/ash-misc/control_char4.right new file mode 100644 index 000000000..2bf18e684 --- /dev/null +++ b/shell/ash_test/ash-misc/control_char4.right | |||
@@ -0,0 +1 @@ | |||
SHELL: line 1: -: not found | |||
diff --git a/shell/ash_test/ash-misc/control_char4.tests b/shell/ash_test/ash-misc/control_char4.tests new file mode 100755 index 000000000..48010f154 --- /dev/null +++ b/shell/ash_test/ash-misc/control_char4.tests | |||
@@ -0,0 +1,2 @@ | |||
1 | # (set argv0 to "SHELL" to avoid "/path/to/shell: blah" in error messages) | ||
2 | $THIS_SH -c '"-"' SHELL | ||
diff --git a/shell/ash_test/ash-parsing/bkslash_newline4.right b/shell/ash_test/ash-parsing/bkslash_newline4.right new file mode 100644 index 000000000..2110716d1 --- /dev/null +++ b/shell/ash_test/ash-parsing/bkslash_newline4.right | |||
@@ -0,0 +1,4 @@ | |||
1 | 1:1 | ||
2 | 22:22 | ||
3 | 3:3 | ||
4 | Ok:0 | ||
diff --git a/shell/ash_test/ash-parsing/bkslash_newline4.tests b/shell/ash_test/ash-parsing/bkslash_newline4.tests new file mode 100755 index 000000000..c8f5037c4 --- /dev/null +++ b/shell/ash_test/ash-parsing/bkslash_newline4.tests | |||
@@ -0,0 +1,14 @@ | |||
1 | set -- 1 22 333 | ||
2 | echo 1:$\ | ||
3 | 1 | ||
4 | echo 22:$\ | ||
5 | {\ | ||
6 | 2\ | ||
7 | } | ||
8 | echo 3:$\ | ||
9 | {\ | ||
10 | #\ | ||
11 | 3\ | ||
12 | } | ||
13 | echo Ok:$\ | ||
14 | ? | ||
diff --git a/shell/hush.c b/shell/hush.c index 77921e11c..1aa0a400d 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -339,7 +339,7 @@ | |||
339 | * therefore we don't show them either. | 339 | * therefore we don't show them either. |
340 | */ | 340 | */ |
341 | //usage:#define hush_trivial_usage | 341 | //usage:#define hush_trivial_usage |
342 | //usage: "[-enxl] [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS] / -s [ARGS]]" | 342 | //usage: "[-enxl] [-c 'SCRIPT' [ARG0 ARGS] | FILE [ARGS] | -s [ARGS]]" |
343 | //usage:#define hush_full_usage "\n\n" | 343 | //usage:#define hush_full_usage "\n\n" |
344 | //usage: "Unix shell interpreter" | 344 | //usage: "Unix shell interpreter" |
345 | 345 | ||
@@ -3696,9 +3696,10 @@ static void debug_print_tree(struct pipe *pi, int lvl) | |||
3696 | 3696 | ||
3697 | pin = 0; | 3697 | pin = 0; |
3698 | while (pi) { | 3698 | while (pi) { |
3699 | fdprintf(2, "%*spipe %d %sres_word=%s followup=%d %s\n", | 3699 | fdprintf(2, "%*spipe %d #cmds:%d %sres_word=%s followup=%d %s\n", |
3700 | lvl*2, "", | 3700 | lvl*2, "", |
3701 | pin, | 3701 | pin, |
3702 | pi->num_cmds, | ||
3702 | (IF_HAS_KEYWORDS(pi->pi_inverted ? "! " :) ""), | 3703 | (IF_HAS_KEYWORDS(pi->pi_inverted ? "! " :) ""), |
3703 | RES[pi->res_word], | 3704 | RES[pi->res_word], |
3704 | pi->followup, PIPE[pi->followup] | 3705 | pi->followup, PIPE[pi->followup] |
@@ -3841,6 +3842,9 @@ static void done_pipe(struct parse_context *ctx, pipe_style type) | |||
3841 | #endif | 3842 | #endif |
3842 | /* Replace all pipes in ctx with one newly created */ | 3843 | /* Replace all pipes in ctx with one newly created */ |
3843 | ctx->list_head = ctx->pipe = pi; | 3844 | ctx->list_head = ctx->pipe = pi; |
3845 | /* for cases like "cmd && &", do not be tricked by last command | ||
3846 | * being null - the entire {...} & is NOT null! */ | ||
3847 | not_null = 1; | ||
3844 | } else { | 3848 | } else { |
3845 | no_conv: | 3849 | no_conv: |
3846 | ctx->pipe->followup = type; | 3850 | ctx->pipe->followup = type; |
@@ -4994,6 +4998,32 @@ static int parse_dollar(o_string *as_string, | |||
4994 | * which check invalid constructs like ${%}. | 4998 | * which check invalid constructs like ${%}. |
4995 | * Oh well... let's check that the var name part is fine... */ | 4999 | * Oh well... let's check that the var name part is fine... */ |
4996 | 5000 | ||
5001 | if (isdigit(len_single_ch) | ||
5002 | || (len_single_ch == '#' && isdigit(i_peek_and_eat_bkslash_nl(input))) | ||
5003 | ) { | ||
5004 | /* Execution engine uses plain xatoi_positive() | ||
5005 | * to interpret ${NNN} and {#NNN}, | ||
5006 | * check syntax here in the parser. | ||
5007 | * (bash does not support expressions in ${#NN}, | ||
5008 | * e.g. ${#$var} and {#1:+WORD} are not supported). | ||
5009 | */ | ||
5010 | unsigned cnt = 9; /* max 9 digits for ${NN} and 8 for {#NN} */ | ||
5011 | while (1) { | ||
5012 | o_addchr(dest, ch); | ||
5013 | debug_printf_parse(": '%c'\n", ch); | ||
5014 | ch = i_getch_and_eat_bkslash_nl(input); | ||
5015 | nommu_addchr(as_string, ch); | ||
5016 | if (ch == '}') | ||
5017 | break; | ||
5018 | if (--cnt == 0) | ||
5019 | goto bad_dollar_syntax; | ||
5020 | if (len_single_ch != '#' && strchr(VAR_SUBST_OPS, ch)) | ||
5021 | /* ${NN<op>...} is valid */ | ||
5022 | goto eat_until_closing; | ||
5023 | if (!isdigit(ch)) | ||
5024 | goto bad_dollar_syntax; | ||
5025 | } | ||
5026 | } else | ||
4997 | while (1) { | 5027 | while (1) { |
4998 | unsigned pos; | 5028 | unsigned pos; |
4999 | 5029 | ||
@@ -5004,7 +5034,6 @@ static int parse_dollar(o_string *as_string, | |||
5004 | nommu_addchr(as_string, ch); | 5034 | nommu_addchr(as_string, ch); |
5005 | if (ch == '}') | 5035 | if (ch == '}') |
5006 | break; | 5036 | break; |
5007 | |||
5008 | if (!isalnum(ch) && ch != '_') { | 5037 | if (!isalnum(ch) && ch != '_') { |
5009 | unsigned end_ch; | 5038 | unsigned end_ch; |
5010 | unsigned char last_ch; | 5039 | unsigned char last_ch; |
@@ -5023,6 +5052,7 @@ static int parse_dollar(o_string *as_string, | |||
5023 | * special var name, e.g. ${#!}. | 5052 | * special var name, e.g. ${#!}. |
5024 | */ | 5053 | */ |
5025 | } | 5054 | } |
5055 | eat_until_closing: | ||
5026 | /* Eat everything until closing '}' (or ':') */ | 5056 | /* Eat everything until closing '}' (or ':') */ |
5027 | end_ch = '}'; | 5057 | end_ch = '}'; |
5028 | if (BASH_SUBSTR | 5058 | if (BASH_SUBSTR |
@@ -5237,6 +5267,11 @@ static int encode_string(o_string *as_string, | |||
5237 | } | 5267 | } |
5238 | #endif | 5268 | #endif |
5239 | o_addQchr(dest, ch); | 5269 | o_addQchr(dest, ch); |
5270 | if (ch == SPECIAL_VAR_SYMBOL) { | ||
5271 | /* Convert "^C" to corresponding special variable reference */ | ||
5272 | o_addchr(dest, SPECIAL_VAR_QUOTED_SVS); | ||
5273 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | ||
5274 | } | ||
5240 | goto again; | 5275 | goto again; |
5241 | #undef as_string | 5276 | #undef as_string |
5242 | } | 5277 | } |
@@ -5348,6 +5383,11 @@ static struct pipe *parse_stream(char **pstring, | |||
5348 | if (ch == '\n') | 5383 | if (ch == '\n') |
5349 | continue; /* drop \<newline>, get next char */ | 5384 | continue; /* drop \<newline>, get next char */ |
5350 | nommu_addchr(&ctx.as_string, '\\'); | 5385 | nommu_addchr(&ctx.as_string, '\\'); |
5386 | if (ch == SPECIAL_VAR_SYMBOL) { | ||
5387 | nommu_addchr(&ctx.as_string, ch); | ||
5388 | /* Convert \^C to corresponding special variable reference */ | ||
5389 | goto case_SPECIAL_VAR_SYMBOL; | ||
5390 | } | ||
5351 | o_addchr(&ctx.word, '\\'); | 5391 | o_addchr(&ctx.word, '\\'); |
5352 | if (ch == EOF) { | 5392 | if (ch == EOF) { |
5353 | /* Testcase: eval 'echo Ok\' */ | 5393 | /* Testcase: eval 'echo Ok\' */ |
@@ -5672,6 +5712,7 @@ static struct pipe *parse_stream(char **pstring, | |||
5672 | /* Note: nommu_addchr(&ctx.as_string, ch) is already done */ | 5712 | /* Note: nommu_addchr(&ctx.as_string, ch) is already done */ |
5673 | 5713 | ||
5674 | switch (ch) { | 5714 | switch (ch) { |
5715 | case_SPECIAL_VAR_SYMBOL: | ||
5675 | case SPECIAL_VAR_SYMBOL: | 5716 | case SPECIAL_VAR_SYMBOL: |
5676 | /* Convert raw ^C to corresponding special variable reference */ | 5717 | /* Convert raw ^C to corresponding special variable reference */ |
5677 | o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL); | 5718 | o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL); |
diff --git a/shell/hush_test/hush-misc/control_char3.right b/shell/hush_test/hush-misc/control_char3.right new file mode 100644 index 000000000..94b4f8699 --- /dev/null +++ b/shell/hush_test/hush-misc/control_char3.right | |||
@@ -0,0 +1 @@ | |||
hush: can't execute '': No such file or directory | |||
diff --git a/shell/hush_test/hush-misc/control_char3.tests b/shell/hush_test/hush-misc/control_char3.tests new file mode 100755 index 000000000..4359db3f3 --- /dev/null +++ b/shell/hush_test/hush-misc/control_char3.tests | |||
@@ -0,0 +1,2 @@ | |||
1 | # (set argv0 to "SHELL" to avoid "/path/to/shell: blah" in error messages) | ||
2 | $THIS_SH -c '\' SHELL | ||
diff --git a/shell/hush_test/hush-misc/control_char4.right b/shell/hush_test/hush-misc/control_char4.right new file mode 100644 index 000000000..698e21427 --- /dev/null +++ b/shell/hush_test/hush-misc/control_char4.right | |||
@@ -0,0 +1 @@ | |||
hush: can't execute '-': No such file or directory | |||
diff --git a/shell/hush_test/hush-misc/control_char4.tests b/shell/hush_test/hush-misc/control_char4.tests new file mode 100755 index 000000000..48010f154 --- /dev/null +++ b/shell/hush_test/hush-misc/control_char4.tests | |||
@@ -0,0 +1,2 @@ | |||
1 | # (set argv0 to "SHELL" to avoid "/path/to/shell: blah" in error messages) | ||
2 | $THIS_SH -c '"-"' SHELL | ||
diff --git a/shell/hush_test/hush-parsing/bkslash_newline4.right b/shell/hush_test/hush-parsing/bkslash_newline4.right new file mode 100644 index 000000000..2110716d1 --- /dev/null +++ b/shell/hush_test/hush-parsing/bkslash_newline4.right | |||
@@ -0,0 +1,4 @@ | |||
1 | 1:1 | ||
2 | 22:22 | ||
3 | 3:3 | ||
4 | Ok:0 | ||
diff --git a/shell/hush_test/hush-parsing/bkslash_newline4.tests b/shell/hush_test/hush-parsing/bkslash_newline4.tests new file mode 100755 index 000000000..c8f5037c4 --- /dev/null +++ b/shell/hush_test/hush-parsing/bkslash_newline4.tests | |||
@@ -0,0 +1,14 @@ | |||
1 | set -- 1 22 333 | ||
2 | echo 1:$\ | ||
3 | 1 | ||
4 | echo 22:$\ | ||
5 | {\ | ||
6 | 2\ | ||
7 | } | ||
8 | echo 3:$\ | ||
9 | {\ | ||
10 | #\ | ||
11 | 3\ | ||
12 | } | ||
13 | echo Ok:$\ | ||
14 | ? | ||
diff --git a/shell/hush_test/hush-vars/var6.right b/shell/hush_test/hush-vars/var6.right index 40e67fdf5..5e28d2fab 100644 --- a/shell/hush_test/hush-vars/var6.right +++ b/shell/hush_test/hush-vars/var6.right | |||
@@ -1,2 +1,2 @@ | |||
1 | hush: invalid number '1q' | 1 | hush: syntax error: unterminated ${name} |
2 | hush: syntax error: unterminated ${name} | 2 | hush: syntax error: unterminated ${name} |
diff --git a/sysklogd/logger.c b/sysklogd/logger.c index 9422b6ea7..04b2c8e3b 100644 --- a/sysklogd/logger.c +++ b/sysklogd/logger.c | |||
@@ -26,7 +26,7 @@ | |||
26 | //usage: "Write MESSAGE (or stdin) to syslog\n" | 26 | //usage: "Write MESSAGE (or stdin) to syslog\n" |
27 | //usage: "\n -s Log to stderr as well as the system log" | 27 | //usage: "\n -s Log to stderr as well as the system log" |
28 | //usage: "\n -t TAG Log using the specified tag (defaults to user name)" | 28 | //usage: "\n -t TAG Log using the specified tag (defaults to user name)" |
29 | //usage: "\n -p PRIO Priority (numeric or facility.level pair)" | 29 | //usage: "\n -p PRIO Priority (number or FACILITY.LEVEL pair)" |
30 | //usage: | 30 | //usage: |
31 | //usage:#define logger_example_usage | 31 | //usage:#define logger_example_usage |
32 | //usage: "$ logger \"hello\"\n" | 32 | //usage: "$ logger \"hello\"\n" |
diff --git a/testsuite/mv/mv-files-to-dir-2 b/testsuite/mv/mv-files-to-dir-2 new file mode 100644 index 000000000..e189ebb6f --- /dev/null +++ b/testsuite/mv/mv-files-to-dir-2 | |||
@@ -0,0 +1,16 @@ | |||
1 | echo file number one > file1 | ||
2 | echo file number two > file2 | ||
3 | ln -s file2 link1 | ||
4 | mkdir dir1 | ||
5 | TZ=UTC0 touch -d '2000-01-30 05:24:08' dir1/file3 | ||
6 | mkdir there | ||
7 | busybox mv -t there file1 file2 link1 dir1 | ||
8 | test -f there/file1 | ||
9 | test -f there/file2 | ||
10 | test -f there/dir1/file3 | ||
11 | test -L there/link1 | ||
12 | test xfile2 = x`readlink there/link1` | ||
13 | test ! -e file1 | ||
14 | test ! -e file2 | ||
15 | test ! -e link1 | ||
16 | test ! -e dir1/file3 | ||
diff --git a/testsuite/unlzma.tests b/testsuite/unlzma.tests index 0e98afe09..fcc6e9441 100755 --- a/testsuite/unlzma.tests +++ b/testsuite/unlzma.tests | |||
@@ -8,14 +8,23 @@ | |||
8 | 8 | ||
9 | # Damaged encrypted streams | 9 | # Damaged encrypted streams |
10 | testing "unlzma (bad archive 1)" \ | 10 | testing "unlzma (bad archive 1)" \ |
11 | "unlzma <unlzma_issue_1.lzma >/dev/null; echo \$?" \ | 11 | "unlzma <unlzma_issue_1.lzma 2>&1 >/dev/null; echo \$?" \ |
12 | "1 | 12 | "unlzma: corrupted data |
13 | 1 | ||
13 | " "" "" | 14 | " "" "" |
14 | 15 | ||
15 | # Damaged encrypted streams | 16 | # Damaged encrypted streams |
16 | testing "unlzma (bad archive 2)" \ | 17 | testing "unlzma (bad archive 2)" \ |
17 | "unlzma <unlzma_issue_2.lzma >/dev/null; echo \$?" \ | 18 | "unlzma <unlzma_issue_2.lzma 2>&1 >/dev/null; echo \$?" \ |
18 | "1 | 19 | "unlzma: corrupted data |
20 | 1 | ||
21 | " "" "" | ||
22 | |||
23 | # Damaged encrypted streams | ||
24 | testing "unlzma (bad archive 3)" \ | ||
25 | "unlzma <unlzma_issue_3.lzma 2>&1 >/dev/null; echo \$?" \ | ||
26 | "unlzma: corrupted data | ||
27 | 1 | ||
19 | " "" "" | 28 | " "" "" |
20 | 29 | ||
21 | exit $FAILCOUNT | 30 | exit $FAILCOUNT |
diff --git a/testsuite/unlzma_issue_3.lzma b/testsuite/unlzma_issue_3.lzma new file mode 100644 index 000000000..cc60f29e4 --- /dev/null +++ b/testsuite/unlzma_issue_3.lzma | |||
Binary files differ | |||
diff --git a/util-linux/blockdev.c b/util-linux/blockdev.c index 20a031377..3b550220a 100644 --- a/util-linux/blockdev.c +++ b/util-linux/blockdev.c | |||
@@ -25,8 +25,11 @@ | |||
25 | //usage: "\n --getbsz Get block size" | 25 | //usage: "\n --getbsz Get block size" |
26 | //usage: "\n --setbsz BYTES Set block size" | 26 | //usage: "\n --setbsz BYTES Set block size" |
27 | //usage: "\n --getsz Get device size in 512-byte sectors" | 27 | //usage: "\n --getsz Get device size in 512-byte sectors" |
28 | /*//usage: "\n --getsize Get device size in sectors (deprecated)"*/ | 28 | ///////: "\n --getsize Get device size in sectors (deprecated)" |
29 | ///////^^^^^ supported, but not shown in help ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
29 | //usage: "\n --getsize64 Get device size in bytes" | 30 | //usage: "\n --getsize64 Get device size in bytes" |
31 | //usage: "\n --getra Get readahead in 512-byte sectors" | ||
32 | //usage: "\n --setra SECTORS Set readahead" | ||
30 | //usage: "\n --flushbufs Flush buffers" | 33 | //usage: "\n --flushbufs Flush buffers" |
31 | //usage: "\n --rereadpt Reread partition table" | 34 | //usage: "\n --rereadpt Reread partition table" |
32 | // util-linux 2.31 also has: | 35 | // util-linux 2.31 also has: |
@@ -57,6 +60,9 @@ static const char bdcmd_names[] ALIGN1 = | |||
57 | "getsz" "\0" | 60 | "getsz" "\0" |
58 | "getsize" "\0" | 61 | "getsize" "\0" |
59 | "getsize64" "\0" | 62 | "getsize64" "\0" |
63 | "getra" "\0" | ||
64 | "setra" "\0" | ||
65 | #define CMD_SETRA 10 | ||
60 | "flushbufs" "\0" | 66 | "flushbufs" "\0" |
61 | "rereadpt" "\0" | 67 | "rereadpt" "\0" |
62 | ; | 68 | ; |
@@ -70,6 +76,8 @@ static const uint32_t bdcmd_ioctl[] ALIGN4 = { | |||
70 | BLKGETSIZE64, //getsz | 76 | BLKGETSIZE64, //getsz |
71 | BLKGETSIZE, //getsize | 77 | BLKGETSIZE, //getsize |
72 | BLKGETSIZE64, //getsize64 | 78 | BLKGETSIZE64, //getsize64 |
79 | BLKRAGET, //getra | ||
80 | BLKRASET, //setra | ||
73 | BLKFLSBUF, //flushbufs | 81 | BLKFLSBUF, //flushbufs |
74 | BLKRRPART, //rereadpt | 82 | BLKRRPART, //rereadpt |
75 | }; | 83 | }; |
@@ -95,6 +103,8 @@ static const uint8_t bdcmd_flags[] ALIGN1 = { | |||
95 | ARG_U64 + FL_SCALE512, //getsz | 103 | ARG_U64 + FL_SCALE512, //getsz |
96 | ARG_ULONG, //getsize | 104 | ARG_ULONG, //getsize |
97 | ARG_U64, //getsize64 | 105 | ARG_U64, //getsize64 |
106 | ARG_ULONG, //getra | ||
107 | ARG_ULONG + FL_NORESULT, //setra | ||
98 | ARG_NONE + FL_NORESULT, //flushbufs | 108 | ARG_NONE + FL_NORESULT, //flushbufs |
99 | ARG_NONE + FL_NORESULT, //rereadpt | 109 | ARG_NONE + FL_NORESULT, //rereadpt |
100 | }; | 110 | }; |
@@ -130,8 +140,9 @@ int blockdev_main(int argc UNUSED_PARAM, char **argv) | |||
130 | /* setrw translates to BLKROSET(0), most other ioctls don't care... */ | 140 | /* setrw translates to BLKROSET(0), most other ioctls don't care... */ |
131 | /* ...setro will do BLKROSET(1) */ | 141 | /* ...setro will do BLKROSET(1) */ |
132 | u64 = (bdcmd == CMD_SETRO); | 142 | u64 = (bdcmd == CMD_SETRO); |
133 | if (bdcmd == CMD_SETBSZ) { | 143 | if (bdcmd == CMD_SETBSZ || bdcmd == CMD_SETRA) { |
134 | /* ...setbsz is BLKBSZSET(bytes) */ | 144 | /* ...setbsz is BLKBSZSET(bytes) */ |
145 | /* ...setra is BLKRASET(512 bytes) */ | ||
135 | u64 = xatoi_positive(*++argv); | 146 | u64 = xatoi_positive(*++argv); |
136 | } | 147 | } |
137 | 148 | ||
@@ -145,8 +156,11 @@ int blockdev_main(int argc UNUSED_PARAM, char **argv) | |||
145 | #if BB_BIG_ENDIAN | 156 | #if BB_BIG_ENDIAN |
146 | /* Store data properly wrt data size. | 157 | /* Store data properly wrt data size. |
147 | * (1) It's no-op for little-endian. | 158 | * (1) It's no-op for little-endian. |
148 | * (2) it's no-op for 0 and -1. Only --setro uses arg != 0 and != -1, | 159 | * (2) it's no-op for 0 and -1. |
149 | * and it is ARG_INT. --setbsz USER_VAL is also ARG_INT. | 160 | * --setro uses arg != 0 and != -1, and it is ARG_INT |
161 | * --setbsz USER_VAL is also ARG_INT | ||
162 | * --setra USER_VAL is ARG_ULONG, but it is passed by value, | ||
163 | * not reference (see below in ioctl call). | ||
150 | * Thus, we don't need to handle ARG_ULONG. | 164 | * Thus, we don't need to handle ARG_ULONG. |
151 | */ | 165 | */ |
152 | switch (flags & ARG_MASK) { | 166 | switch (flags & ARG_MASK) { |
@@ -161,7 +175,11 @@ int blockdev_main(int argc UNUSED_PARAM, char **argv) | |||
161 | } | 175 | } |
162 | #endif | 176 | #endif |
163 | 177 | ||
164 | if (ioctl(fd, bdcmd_ioctl[bdcmd], &ioctl_val_on_stack.u64) == -1) | 178 | if (ioctl(fd, bdcmd_ioctl[bdcmd], |
179 | bdcmd == CMD_SETRA | ||
180 | ? (void*)(uintptr_t)u64 /* BLKRASET passes _value_, not pointer to it */ | ||
181 | : &ioctl_val_on_stack.u64 | ||
182 | ) == -1) | ||
165 | bb_simple_perror_msg_and_die(*argv); | 183 | bb_simple_perror_msg_and_die(*argv); |
166 | 184 | ||
167 | /* Fetch it into register(s) */ | 185 | /* Fetch it into register(s) */ |
diff --git a/util-linux/dmesg.c b/util-linux/dmesg.c index dc4e57169..6670b84de 100644 --- a/util-linux/dmesg.c +++ b/util-linux/dmesg.c | |||
@@ -46,7 +46,7 @@ | |||
46 | //kbuild:lib-$(CONFIG_DMESG) += dmesg.o | 46 | //kbuild:lib-$(CONFIG_DMESG) += dmesg.o |
47 | 47 | ||
48 | //usage:#define dmesg_trivial_usage | 48 | //usage:#define dmesg_trivial_usage |
49 | //usage: "[-c] [-n LEVEL] [-s SIZE]" | 49 | //usage: "[-cr] [-n LEVEL] [-s SIZE]" |
50 | //usage:#define dmesg_full_usage "\n\n" | 50 | //usage:#define dmesg_full_usage "\n\n" |
51 | //usage: "Print or control the kernel ring buffer\n" | 51 | //usage: "Print or control the kernel ring buffer\n" |
52 | //usage: "\n -c Clear ring buffer after printing" | 52 | //usage: "\n -c Clear ring buffer after printing" |
diff --git a/util-linux/fdisk.c b/util-linux/fdisk.c index c50ceead1..1c2a7d683 100644 --- a/util-linux/fdisk.c +++ b/util-linux/fdisk.c | |||
@@ -232,8 +232,8 @@ struct pte { | |||
232 | }; | 232 | }; |
233 | 233 | ||
234 | #define unable_to_open "can't open '%s'" | 234 | #define unable_to_open "can't open '%s'" |
235 | #define unable_to_read "can't read from %s" | 235 | #define unable_to_read "can't read '%s'" |
236 | #define unable_to_seek "can't seek on %s" | 236 | #define unable_to_seek "can't seek '%s'" |
237 | 237 | ||
238 | enum label_type { | 238 | enum label_type { |
239 | LABEL_DOS, LABEL_SUN, LABEL_SGI, LABEL_AIX, LABEL_OSF, LABEL_GPT | 239 | LABEL_DOS, LABEL_SUN, LABEL_SGI, LABEL_AIX, LABEL_OSF, LABEL_GPT |
diff --git a/util-linux/flock.c b/util-linux/flock.c index 12c16013c..1ed752a80 100644 --- a/util-linux/flock.c +++ b/util-linux/flock.c | |||
@@ -14,7 +14,7 @@ | |||
14 | //kbuild:lib-$(CONFIG_FLOCK) += flock.o | 14 | //kbuild:lib-$(CONFIG_FLOCK) += flock.o |
15 | 15 | ||
16 | //usage:#define flock_trivial_usage | 16 | //usage:#define flock_trivial_usage |
17 | //usage: "[-sxun] FD|{FILE [-c] PROG ARGS}" | 17 | //usage: "[-sxun] FD | { FILE [-c] PROG ARGS }" |
18 | //usage:#define flock_full_usage "\n\n" | 18 | //usage:#define flock_full_usage "\n\n" |
19 | //usage: "[Un]lock file descriptor, or lock FILE, run PROG\n" | 19 | //usage: "[Un]lock file descriptor, or lock FILE, run PROG\n" |
20 | //usage: "\n -s Shared lock" | 20 | //usage: "\n -s Shared lock" |
diff --git a/util-linux/hexdump_xxd.c b/util-linux/hexdump_xxd.c index 29bbc6633..fe78f6242 100644 --- a/util-linux/hexdump_xxd.c +++ b/util-linux/hexdump_xxd.c | |||
@@ -41,15 +41,17 @@ | |||
41 | // -u use upper case hex letters. | 41 | // -u use upper case hex letters. |
42 | 42 | ||
43 | //usage:#define xxd_trivial_usage | 43 | //usage:#define xxd_trivial_usage |
44 | //usage: "[-pr] [-g N] [-c N] [-n LEN] [-s OFS] [FILE]" | 44 | //usage: "[-pri] [-g N] [-c N] [-n LEN] [-s OFS] [-o OFS] [FILE]" |
45 | //usage:#define xxd_full_usage "\n\n" | 45 | //usage:#define xxd_full_usage "\n\n" |
46 | //usage: "Hex dump FILE (or stdin)\n" | 46 | //usage: "Hex dump FILE (or stdin)\n" |
47 | //usage: "\n -g N Bytes per group" | 47 | //usage: "\n -g N Bytes per group" |
48 | //usage: "\n -c N Bytes per line" | 48 | //usage: "\n -c N Bytes per line" |
49 | //usage: "\n -p Show only hex bytes, assumes -c30" | 49 | //usage: "\n -p Show only hex bytes, assumes -c30" |
50 | //usage: "\n -i C include file style" | ||
50 | // exactly the same help text lines in hexdump and xxd: | 51 | // exactly the same help text lines in hexdump and xxd: |
51 | //usage: "\n -l LENGTH Show only first LENGTH bytes" | 52 | //usage: "\n -l LENGTH Show only first LENGTH bytes" |
52 | //usage: "\n -s OFFSET Skip OFFSET bytes" | 53 | //usage: "\n -s OFFSET Skip OFFSET bytes" |
54 | //usage: "\n -o OFFSET Add OFFSET to displayed offset" | ||
53 | //usage: "\n -r Reverse (with -p, assumes no offsets in input)" | 55 | //usage: "\n -r Reverse (with -p, assumes no offsets in input)" |
54 | 56 | ||
55 | #include "libbb.h" | 57 | #include "libbb.h" |
@@ -61,7 +63,11 @@ | |||
61 | #define OPT_s (1 << 1) | 63 | #define OPT_s (1 << 1) |
62 | #define OPT_a (1 << 2) | 64 | #define OPT_a (1 << 2) |
63 | #define OPT_p (1 << 3) | 65 | #define OPT_p (1 << 3) |
64 | #define OPT_r (1 << 4) | 66 | #define OPT_i (1 << 4) |
67 | #define OPT_r (1 << 5) | ||
68 | #define OPT_g (1 << 6) | ||
69 | #define OPT_c (1 << 7) | ||
70 | #define OPT_o (1 << 8) | ||
65 | 71 | ||
66 | static void reverse(unsigned opt, unsigned cols, const char *filename) | 72 | static void reverse(unsigned opt, unsigned cols, const char *filename) |
67 | { | 73 | { |
@@ -122,20 +128,30 @@ static void reverse(unsigned opt, unsigned cols, const char *filename) | |||
122 | fflush_stdout_and_exit(EXIT_SUCCESS); | 128 | fflush_stdout_and_exit(EXIT_SUCCESS); |
123 | } | 129 | } |
124 | 130 | ||
131 | static void print_C_style(const char *p, const char *hdr) | ||
132 | { | ||
133 | printf(hdr, isdigit(p[0]) ? "__" : ""); | ||
134 | while (*p) { | ||
135 | bb_putchar(isalnum(*p) ? *p : '_'); | ||
136 | p++; | ||
137 | } | ||
138 | } | ||
139 | |||
125 | int xxd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 140 | int xxd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
126 | int xxd_main(int argc UNUSED_PARAM, char **argv) | 141 | int xxd_main(int argc UNUSED_PARAM, char **argv) |
127 | { | 142 | { |
128 | char buf[80]; | 143 | char buf[80]; |
129 | dumper_t *dumper; | 144 | dumper_t *dumper; |
130 | char *opt_l, *opt_s; | 145 | char *opt_l, *opt_s, *opt_o; |
131 | unsigned bytes = 2; | 146 | unsigned bytes = 2; |
132 | unsigned cols = 0; | 147 | unsigned cols = 0; |
133 | unsigned opt; | 148 | unsigned opt; |
149 | int r; | ||
134 | 150 | ||
135 | dumper = alloc_dumper(); | 151 | dumper = alloc_dumper(); |
136 | 152 | ||
137 | opt = getopt32(argv, "^" "l:s:aprg:+c:+" "\0" "?1" /* 1 argument max */, | 153 | opt = getopt32(argv, "^" "l:s:apirg:+c:+o:" "\0" "?1" /* 1 argument max */, |
138 | &opt_l, &opt_s, &bytes, &cols | 154 | &opt_l, &opt_s, &bytes, &cols, &opt_o |
139 | ); | 155 | ); |
140 | argv += optind; | 156 | argv += optind; |
141 | 157 | ||
@@ -158,14 +174,24 @@ int xxd_main(int argc UNUSED_PARAM, char **argv) | |||
158 | //BUGGY for /proc/version (unseekable?) | 174 | //BUGGY for /proc/version (unseekable?) |
159 | } | 175 | } |
160 | 176 | ||
177 | if (opt & OPT_o) { | ||
178 | /* -o accepts negative numbers too */ | ||
179 | dumper->xxd_displayoff = xstrtoll(opt_o, /*base:*/ 0); | ||
180 | } | ||
181 | |||
161 | if (opt & OPT_p) { | 182 | if (opt & OPT_p) { |
162 | if (cols == 0) | 183 | if (cols == 0) |
163 | cols = 30; | 184 | cols = 30; |
164 | bytes = cols; /* -p ignores -gN */ | 185 | bytes = cols; /* -p ignores -gN */ |
165 | } else { | 186 | } else { |
166 | if (cols == 0) | 187 | if (cols == 0) |
167 | cols = 16; | 188 | cols = (opt & OPT_i) ? 12 : 16; |
168 | bb_dump_add(dumper, "\"%08.8_ax: \""); // "address: " | 189 | if (opt & OPT_i) { |
190 | bytes = 1; // -i ignores -gN | ||
191 | // output is " 0xXX, 0xXX, 0xXX...", add leading space | ||
192 | bb_dump_add(dumper, "\" \""); | ||
193 | } else | ||
194 | bb_dump_add(dumper, "\"%08.8_ax: \""); // "address: " | ||
169 | } | 195 | } |
170 | 196 | ||
171 | if (opt & OPT_r) { | 197 | if (opt & OPT_r) { |
@@ -173,11 +199,15 @@ int xxd_main(int argc UNUSED_PARAM, char **argv) | |||
173 | } | 199 | } |
174 | 200 | ||
175 | if (bytes < 1 || bytes >= cols) { | 201 | if (bytes < 1 || bytes >= cols) { |
176 | sprintf(buf, "%u/1 \"%%02x\"", cols); // cols * "xx" | 202 | sprintf(buf, "%u/1 \"%%02x\"", cols); // cols * "XX" |
177 | bb_dump_add(dumper, buf); | 203 | bb_dump_add(dumper, buf); |
178 | } | 204 | } |
179 | else if (bytes == 1) { | 205 | else if (bytes == 1) { |
180 | sprintf(buf, "%u/1 \"%%02x \"", cols); // cols * "xx " | 206 | if (opt & OPT_i) |
207 | sprintf(buf, "%u/1 \" 0x%%02x,\"", cols); // cols * " 0xXX," | ||
208 | //TODO: compat: omit the last comma after the very last byte | ||
209 | else | ||
210 | sprintf(buf, "%u/1 \"%%02x \"", cols); // cols * "XX " | ||
181 | bb_dump_add(dumper, buf); | 211 | bb_dump_add(dumper, buf); |
182 | } | 212 | } |
183 | else { | 213 | else { |
@@ -201,13 +231,22 @@ int xxd_main(int argc UNUSED_PARAM, char **argv) | |||
201 | free(bigbuf); | 231 | free(bigbuf); |
202 | } | 232 | } |
203 | 233 | ||
204 | if (!(opt & OPT_p)) { | 234 | if (!(opt & (OPT_p|OPT_i))) { |
205 | sprintf(buf, "\" \"%u/1 \"%%_p\"\"\n\"", cols); // " ASCII\n" | 235 | sprintf(buf, "\" \"%u/1 \"%%_p\"\"\n\"", cols); // " ASCII\n" |
206 | bb_dump_add(dumper, buf); | 236 | bb_dump_add(dumper, buf); |
207 | } else { | 237 | } else { |
208 | bb_dump_add(dumper, "\"\n\""); | 238 | bb_dump_add(dumper, "\"\n\""); |
209 | dumper->eofstring = "\n"; | 239 | dumper->xxd_eofstring = "\n"; |
210 | } | 240 | } |
211 | 241 | ||
212 | return bb_dump_dump(dumper, argv); | 242 | if ((opt & OPT_i) && argv[0]) { |
243 | print_C_style(argv[0], "unsigned char %s"); | ||
244 | printf("[] = {\n"); | ||
245 | } | ||
246 | r = bb_dump_dump(dumper, argv); | ||
247 | if (r == 0 && (opt & OPT_i) && argv[0]) { | ||
248 | print_C_style(argv[0], "};\nunsigned int %s"); | ||
249 | printf("_len = %"OFF_FMT"u;\n", dumper->address); | ||
250 | } | ||
251 | return r; | ||
213 | } | 252 | } |
diff --git a/util-linux/ionice.c b/util-linux/ionice.c index c8fb1a777..82bd309d1 100644 --- a/util-linux/ionice.c +++ b/util-linux/ionice.c | |||
@@ -18,11 +18,13 @@ | |||
18 | //kbuild:lib-$(CONFIG_IONICE) += ionice.o | 18 | //kbuild:lib-$(CONFIG_IONICE) += ionice.o |
19 | 19 | ||
20 | //usage:#define ionice_trivial_usage | 20 | //usage:#define ionice_trivial_usage |
21 | //usage: "[-c 1-3] [-n 0-7] [-p PID] [PROG ARGS]" | 21 | //usage: "[-c 1-3] [-n 0-7] [-t] { -p PID | PROG ARGS }" |
22 | //TODO: | -P PGID | -u UID; also -pPu can take _list of_ IDs | ||
22 | //usage:#define ionice_full_usage "\n\n" | 23 | //usage:#define ionice_full_usage "\n\n" |
23 | //usage: "Change I/O priority and class\n" | 24 | //usage: "Change I/O priority and class\n" |
24 | //usage: "\n -c N Class. 1:realtime 2:best-effort 3:idle" | 25 | //usage: "\n -c N Class. 1:realtime 2:best-effort 3:idle" |
25 | //usage: "\n -n N Priority" | 26 | //usage: "\n -n N Priority" |
27 | //usage: "\n -t Ignore errors" | ||
26 | 28 | ||
27 | #include <sys/syscall.h> | 29 | #include <sys/syscall.h> |
28 | #include <asm/unistd.h> | 30 | #include <asm/unistd.h> |
@@ -64,14 +66,15 @@ int ionice_main(int argc UNUSED_PARAM, char **argv) | |||
64 | int pid = 0; /* affect own process */ | 66 | int pid = 0; /* affect own process */ |
65 | int opt; | 67 | int opt; |
66 | enum { | 68 | enum { |
67 | OPT_n = 1, | 69 | OPT_n = 1 << 0, |
68 | OPT_c = 2, | 70 | OPT_c = 1 << 1, |
69 | OPT_p = 4, | 71 | OPT_p = 1 << 2, |
72 | OPT_t = 1 << 3, | ||
70 | }; | 73 | }; |
71 | 74 | ||
72 | /* Numeric params */ | ||
73 | /* '+': stop at first non-option */ | 75 | /* '+': stop at first non-option */ |
74 | opt = getopt32(argv, "+n:+c:+p:+", &pri, &ioclass, &pid); | 76 | /* numeric params for -n -c -p */ |
77 | opt = getopt32(argv, "+""n:+c:+p:+t", &pri, &ioclass, &pid); | ||
75 | argv += optind; | 78 | argv += optind; |
76 | 79 | ||
77 | if (opt & OPT_c) { | 80 | if (opt & OPT_c) { |
@@ -104,7 +107,8 @@ int ionice_main(int argc UNUSED_PARAM, char **argv) | |||
104 | //pri, ioclass, pri | (ioclass << IOPRIO_CLASS_SHIFT)); | 107 | //pri, ioclass, pri | (ioclass << IOPRIO_CLASS_SHIFT)); |
105 | pri |= (ioclass << IOPRIO_CLASS_SHIFT); | 108 | pri |= (ioclass << IOPRIO_CLASS_SHIFT); |
106 | if (ioprio_set(IOPRIO_WHO_PROCESS, pid, pri) == -1) | 109 | if (ioprio_set(IOPRIO_WHO_PROCESS, pid, pri) == -1) |
107 | bb_perror_msg_and_die("ioprio_%cet", 's'); | 110 | if (!(opt & OPT_t)) |
111 | bb_perror_msg_and_die("ioprio_%cet", 's'); | ||
108 | if (argv[0]) { | 112 | if (argv[0]) { |
109 | BB_EXECVP_or_die(argv); | 113 | BB_EXECVP_or_die(argv); |
110 | } | 114 | } |
diff --git a/util-linux/mountpoint.c b/util-linux/mountpoint.c index a44cf6013..28b1e7a54 100644 --- a/util-linux/mountpoint.c +++ b/util-linux/mountpoint.c | |||
@@ -19,13 +19,14 @@ | |||
19 | //kbuild:lib-$(CONFIG_MOUNTPOINT) += mountpoint.o | 19 | //kbuild:lib-$(CONFIG_MOUNTPOINT) += mountpoint.o |
20 | 20 | ||
21 | //usage:#define mountpoint_trivial_usage | 21 | //usage:#define mountpoint_trivial_usage |
22 | //usage: "[-q] <[-dn] DIR | -x DEVICE>" | 22 | //usage: "[-q] { [-dn] DIR | -x DEVICE }" |
23 | //usage:#define mountpoint_full_usage "\n\n" | 23 | //usage:#define mountpoint_full_usage "\n\n" |
24 | //usage: "Check if the directory is a mountpoint\n" | 24 | //usage: "Check if DIR is a mountpoint\n" |
25 | //usage: "\n -q Quiet" | 25 | //usage: "\n -q Quiet" |
26 | //usage: "\n -d Print major/minor device number of the filesystem" | 26 | //usage: "\n -d Print major:minor of the filesystem" |
27 | //usage: "\n -n Print device name of the filesystem" | 27 | //usage: "\n -n Print device name of the filesystem" |
28 | //usage: "\n -x Print major/minor device number of the blockdevice" | 28 | //////// -n is not supported by util-linux-2.36.1 ^^^^^^^^^^^^^^^^^^ |
29 | //usage: "\n -x Print major:minor of DEVICE" | ||
29 | //usage: | 30 | //usage: |
30 | //usage:#define mountpoint_example_usage | 31 | //usage:#define mountpoint_example_usage |
31 | //usage: "$ mountpoint /proc\n" | 32 | //usage: "$ mountpoint /proc\n" |
diff --git a/util-linux/readprofile.c b/util-linux/readprofile.c index 32d9987e7..f11c62292 100644 --- a/util-linux/readprofile.c +++ b/util-linux/readprofile.c | |||
@@ -44,8 +44,8 @@ | |||
44 | //usage:#define readprofile_trivial_usage | 44 | //usage:#define readprofile_trivial_usage |
45 | //usage: "[OPTIONS]" | 45 | //usage: "[OPTIONS]" |
46 | //usage:#define readprofile_full_usage "\n\n" | 46 | //usage:#define readprofile_full_usage "\n\n" |
47 | //usage: " -m mapfile (Default: /boot/System.map)" | 47 | //usage: " -m MAPFILE (Default: /boot/System.map)" |
48 | //usage: "\n -p profile (Default: /proc/profile)" | 48 | //usage: "\n -p PROFILE (Default: /proc/profile)" |
49 | //usage: "\n -M NUM Set the profiling multiplier to NUM" | 49 | //usage: "\n -M NUM Set the profiling multiplier to NUM" |
50 | //usage: "\n -i Print only info about the sampling step" | 50 | //usage: "\n -i Print only info about the sampling step" |
51 | //usage: "\n -v Verbose" | 51 | //usage: "\n -v Verbose" |
diff --git a/util-linux/renice.c b/util-linux/renice.c index a318ffce0..fc72550f4 100644 --- a/util-linux/renice.c +++ b/util-linux/renice.c | |||
@@ -29,7 +29,7 @@ | |||
29 | //kbuild:lib-$(CONFIG_RENICE) += renice.o | 29 | //kbuild:lib-$(CONFIG_RENICE) += renice.o |
30 | 30 | ||
31 | //usage:#define renice_trivial_usage | 31 | //usage:#define renice_trivial_usage |
32 | //usage: "[-n] PRIORITY [[-p | -g | -u] ID...]..." | 32 | //usage: "[-n] PRIORITY [[-p|g|u] ID...]..." |
33 | //usage:#define renice_full_usage "\n\n" | 33 | //usage:#define renice_full_usage "\n\n" |
34 | //usage: "Change scheduling priority of a running process\n" | 34 | //usage: "Change scheduling priority of a running process\n" |
35 | //usage: "\n -n Add PRIORITY to current nice value" | 35 | //usage: "\n -n Add PRIORITY to current nice value" |
diff --git a/util-linux/switch_root.c b/util-linux/switch_root.c index f2674b5ac..901c0b8db 100644 --- a/util-linux/switch_root.c +++ b/util-linux/switch_root.c | |||
@@ -68,11 +68,22 @@ extern int capget(cap_user_header_t header, const cap_user_data_t data); | |||
68 | # define MS_MOVE 8192 | 68 | # define MS_MOVE 8192 |
69 | #endif | 69 | #endif |
70 | 70 | ||
71 | static void delete_contents(const char *directory, dev_t rootdev); | ||
72 | |||
73 | static int FAST_FUNC rmrf(const char *directory, struct dirent *d, void *rootdevp) | ||
74 | { | ||
75 | char *newdir = concat_subpath_file(directory, d->d_name); | ||
76 | if (newdir) { // not . or .. | ||
77 | // Recurse to delete contents | ||
78 | delete_contents(newdir, *(dev_t*)rootdevp); | ||
79 | free(newdir); | ||
80 | } | ||
81 | return 0; | ||
82 | } | ||
83 | |||
71 | // Recursively delete contents of rootfs | 84 | // Recursively delete contents of rootfs |
72 | static void delete_contents(const char *directory, dev_t rootdev) | 85 | static void delete_contents(const char *directory, dev_t rootdev) |
73 | { | 86 | { |
74 | DIR *dir; | ||
75 | struct dirent *d; | ||
76 | struct stat st; | 87 | struct stat st; |
77 | 88 | ||
78 | // Don't descend into other filesystems | 89 | // Don't descend into other filesystems |
@@ -81,25 +92,7 @@ static void delete_contents(const char *directory, dev_t rootdev) | |||
81 | 92 | ||
82 | // Recursively delete the contents of directories | 93 | // Recursively delete the contents of directories |
83 | if (S_ISDIR(st.st_mode)) { | 94 | if (S_ISDIR(st.st_mode)) { |
84 | dir = opendir(directory); | 95 | iterate_on_dir(directory, rmrf, &rootdev); |
85 | if (dir) { | ||
86 | while ((d = readdir(dir))) { | ||
87 | char *newdir = d->d_name; | ||
88 | |||
89 | // Skip . and .. | ||
90 | if (DOT_OR_DOTDOT(newdir)) | ||
91 | continue; | ||
92 | |||
93 | // Recurse to delete contents | ||
94 | newdir = concat_path_file(directory, newdir); | ||
95 | delete_contents(newdir, rootdev); | ||
96 | free(newdir); | ||
97 | } | ||
98 | closedir(dir); | ||
99 | |||
100 | // Directory should now be empty, zap it | ||
101 | rmdir(directory); | ||
102 | } | ||
103 | } else { | 96 | } else { |
104 | // It wasn't a directory, zap it | 97 | // It wasn't a directory, zap it |
105 | unlink(directory); | 98 | unlink(directory); |
diff --git a/util-linux/taskset.c b/util-linux/taskset.c index b542f8c83..afe2f04d2 100644 --- a/util-linux/taskset.c +++ b/util-linux/taskset.c | |||
@@ -34,10 +34,12 @@ | |||
34 | //kbuild:lib-$(CONFIG_TASKSET) += taskset.o | 34 | //kbuild:lib-$(CONFIG_TASKSET) += taskset.o |
35 | 35 | ||
36 | //usage:#define taskset_trivial_usage | 36 | //usage:#define taskset_trivial_usage |
37 | //usage: "[-p] [HEXMASK] PID | PROG ARGS" | 37 | //usage: "[-ap] [HEXMASK"IF_FEATURE_TASKSET_CPULIST(" | -c LIST")"] { PID | PROG ARGS }" |
38 | //usage:#define taskset_full_usage "\n\n" | 38 | //usage:#define taskset_full_usage "\n\n" |
39 | //usage: "Set or get CPU affinity\n" | 39 | //usage: "Set or get CPU affinity\n" |
40 | //usage: "\n -p Operate on an existing PID" | 40 | //usage: "\n -p Operate on PID" |
41 | //usage: "\n -a Operate on all threads" | ||
42 | //usage: "\n -c Affinity is a list, not mask" | ||
41 | //usage: | 43 | //usage: |
42 | //usage:#define taskset_example_usage | 44 | //usage:#define taskset_example_usage |
43 | //usage: "$ taskset 0x7 ./dgemm_test&\n" | 45 | //usage: "$ taskset 0x7 ./dgemm_test&\n" |
@@ -205,42 +207,18 @@ static void print_cpulist(const ul *mask, unsigned mask_size_in_bytes) | |||
205 | } | 207 | } |
206 | #endif | 208 | #endif |
207 | 209 | ||
208 | int taskset_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 210 | enum { |
209 | int taskset_main(int argc UNUSED_PARAM, char **argv) | 211 | OPT_p = 1 << 0, |
212 | OPT_a = 1 << 1, | ||
213 | OPT_c = (1 << 2) * ENABLE_FEATURE_TASKSET_CPULIST, | ||
214 | }; | ||
215 | |||
216 | static int process_pid_str(const char *pid_str, unsigned opts, char *aff) | ||
210 | { | 217 | { |
211 | ul *mask; | 218 | ul *mask; |
212 | unsigned mask_size_in_bytes; | 219 | unsigned mask_size_in_bytes; |
213 | pid_t pid = 0; | ||
214 | const char *current_new; | 220 | const char *current_new; |
215 | char *aff; | 221 | pid_t pid = xatoi_positive(pid_str); |
216 | unsigned opts; | ||
217 | enum { | ||
218 | OPT_p = 1 << 0, | ||
219 | OPT_c = (1 << 1) * ENABLE_FEATURE_TASKSET_CPULIST, | ||
220 | }; | ||
221 | |||
222 | /* NB: we mimic util-linux's taskset: -p does not take | ||
223 | * an argument, i.e., "-pN" is NOT valid, only "-p N"! | ||
224 | * Indeed, util-linux-2.13-pre7 uses: | ||
225 | * getopt_long(argc, argv, "+pchV", ...), not "...p:..." */ | ||
226 | |||
227 | opts = getopt32(argv, "^+" "p"IF_FEATURE_TASKSET_CPULIST("c") | ||
228 | "\0" "-1" /* at least 1 arg */); | ||
229 | argv += optind; | ||
230 | |||
231 | aff = *argv++; | ||
232 | if (opts & OPT_p) { | ||
233 | char *pid_str = aff; | ||
234 | if (*argv) { /* "-p <aff> <pid> ...rest.is.ignored..." */ | ||
235 | pid_str = *argv; /* NB: *argv != NULL in this case */ | ||
236 | } | ||
237 | /* else it was just "-p <pid>", and *argv == NULL */ | ||
238 | pid = xatoul_range(pid_str, 1, ((unsigned)(pid_t)ULONG_MAX) >> 1); | ||
239 | } else { | ||
240 | /* <aff> <cmd...> */ | ||
241 | if (!*argv) | ||
242 | bb_show_usage(); | ||
243 | } | ||
244 | 222 | ||
245 | mask_size_in_bytes = SZOF_UL; | 223 | mask_size_in_bytes = SZOF_UL; |
246 | current_new = "current"; | 224 | current_new = "current"; |
@@ -255,13 +233,12 @@ int taskset_main(int argc UNUSED_PARAM, char **argv) | |||
255 | #endif | 233 | #endif |
256 | printf("pid %d's %s affinity mask: "TASKSET_PRINTF_MASK"\n", | 234 | printf("pid %d's %s affinity mask: "TASKSET_PRINTF_MASK"\n", |
257 | pid, current_new, from_mask(mask, mask_size_in_bytes)); | 235 | pid, current_new, from_mask(mask, mask_size_in_bytes)); |
258 | if (*argv == NULL) { | 236 | if (!aff) { |
259 | /* Either it was just "-p <pid>", | 237 | /* Either it was just "-p <pid>", |
260 | * or it was "-p <aff> <pid>" and we came here | 238 | * or it was "-p <aff> <pid>" and we came here |
261 | * for the second time (see goto below) */ | 239 | * for the second time (see goto below) */ |
262 | return EXIT_SUCCESS; | 240 | return 0; |
263 | } | 241 | } |
264 | *argv = NULL; | ||
265 | current_new = "new"; | 242 | current_new = "new"; |
266 | } | 243 | } |
267 | memset(mask, 0, mask_size_in_bytes); | 244 | memset(mask, 0, mask_size_in_bytes); |
@@ -331,8 +308,61 @@ int taskset_main(int argc UNUSED_PARAM, char **argv) | |||
331 | bb_perror_msg_and_die("can't %cet pid %d's affinity", 's', pid); | 308 | bb_perror_msg_and_die("can't %cet pid %d's affinity", 's', pid); |
332 | //bb_error_msg("set mask[0]:%lx", mask[0]); | 309 | //bb_error_msg("set mask[0]:%lx", mask[0]); |
333 | 310 | ||
334 | if (!argv[0]) /* "-p <aff> <pid> [...ignored...]" */ | 311 | if ((opts & OPT_p) && aff) { /* "-p <aff> <pid> [...ignored...]" */ |
312 | aff = NULL; | ||
335 | goto print_aff; /* print new affinity and exit */ | 313 | goto print_aff; /* print new affinity and exit */ |
314 | } | ||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | static int FAST_FUNC iter(const char *dn UNUSED_PARAM, struct dirent *ent, void *aff) | ||
319 | { | ||
320 | if (isdigit(ent->d_name[0])) | ||
321 | return process_pid_str(ent->d_name, option_mask32, aff); | ||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | int taskset_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
326 | int taskset_main(int argc UNUSED_PARAM, char **argv) | ||
327 | { | ||
328 | const char *pid_str; | ||
329 | char *aff; | ||
330 | unsigned opts; | ||
336 | 331 | ||
337 | BB_EXECVP_or_die(argv); | 332 | /* NB: we mimic util-linux's taskset: -p does not take |
333 | * an argument, i.e., "-pN" is NOT valid, only "-p N"! | ||
334 | * Indeed, util-linux-2.13-pre7 uses: | ||
335 | * getopt_long(argc, argv, "+pchV", ...), not "...p:..." */ | ||
336 | |||
337 | opts = getopt32(argv, "^+" "pa"IF_FEATURE_TASKSET_CPULIST("c") | ||
338 | "\0" "-1" /* at least 1 arg */); | ||
339 | argv += optind; | ||
340 | |||
341 | aff = *argv++; | ||
342 | if (!(opts & OPT_p)) { | ||
343 | /* <aff> <cmd...> */ | ||
344 | if (!*argv) | ||
345 | bb_show_usage(); | ||
346 | process_pid_str("0", opts, aff); | ||
347 | BB_EXECVP_or_die(argv); | ||
348 | } | ||
349 | |||
350 | pid_str = aff; | ||
351 | if (*argv) /* "-p <aff> <pid> ...rest.is.ignored..." */ | ||
352 | pid_str = *argv; | ||
353 | else | ||
354 | aff = NULL; | ||
355 | |||
356 | if (opts & OPT_a) { | ||
357 | char *dn; | ||
358 | int r; | ||
359 | |||
360 | dn = xasprintf("/proc/%s/task", pid_str); | ||
361 | r = iterate_on_dir(dn, iter, aff); | ||
362 | IF_FEATURE_CLEAN_UP(free(dn);) | ||
363 | if (r == 0) | ||
364 | return r; /* EXIT_SUCCESS */ | ||
365 | /* else: no /proc/PID/task, act as if no -a was given */ | ||
366 | } | ||
367 | return process_pid_str(pid_str, opts, aff); | ||
338 | } | 368 | } |