diff options
author | Ron Yorston <rmy@pobox.com> | 2013-03-19 11:18:39 +0000 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2013-03-19 11:18:39 +0000 |
commit | 63d2c5fead323df5f4250ed544d0bc03527c8936 (patch) | |
tree | 660979b139a4bc4b143c08843cb7efbc69bdcb4d | |
parent | 27fc2d535588728ac3ca69337271471fb6fe3ee9 (diff) | |
parent | a42f530e034b673726a91ea5d8202254e677f066 (diff) | |
download | busybox-w32-63d2c5fead323df5f4250ed544d0bc03527c8936.tar.gz busybox-w32-63d2c5fead323df5f4250ed544d0bc03527c8936.tar.bz2 busybox-w32-63d2c5fead323df5f4250ed544d0bc03527c8936.zip |
Merge branch 'busybox' into merge
59 files changed, 1260 insertions, 718 deletions
diff --git a/archival/bbunzip.c b/archival/bbunzip.c index 66a046052..f77ac8383 100644 --- a/archival/bbunzip.c +++ b/archival/bbunzip.c | |||
@@ -7,13 +7,16 @@ | |||
7 | #include "libbb.h" | 7 | #include "libbb.h" |
8 | #include "bb_archive.h" | 8 | #include "bb_archive.h" |
9 | 9 | ||
10 | /* Note: must be kept in sync with archival/lzop.c */ | ||
10 | enum { | 11 | enum { |
11 | OPT_STDOUT = 1 << 0, | 12 | OPT_STDOUT = 1 << 0, |
12 | OPT_FORCE = 1 << 1, | 13 | OPT_FORCE = 1 << 1, |
13 | /* only some decompressors: */ | 14 | /* only some decompressors: */ |
14 | OPT_VERBOSE = 1 << 2, | 15 | OPT_VERBOSE = 1 << 2, |
15 | OPT_DECOMPRESS = 1 << 3, | 16 | OPT_QUIET = 1 << 3, |
16 | OPT_TEST = 1 << 4, | 17 | OPT_DECOMPRESS = 1 << 4, |
18 | OPT_TEST = 1 << 5, | ||
19 | SEAMLESS_MAGIC = (1 << 31) * SEAMLESS_COMPRESSION, | ||
17 | }; | 20 | }; |
18 | 21 | ||
19 | static | 22 | static |
@@ -39,7 +42,7 @@ int FAST_FUNC bbunpack(char **argv, | |||
39 | ) | 42 | ) |
40 | { | 43 | { |
41 | struct stat stat_buf; | 44 | struct stat stat_buf; |
42 | IF_DESKTOP(long long) int status; | 45 | IF_DESKTOP(long long) int status = 0; |
43 | char *filename, *new_name; | 46 | char *filename, *new_name; |
44 | smallint exitcode = 0; | 47 | smallint exitcode = 0; |
45 | transformer_aux_data_t aux; | 48 | transformer_aux_data_t aux; |
@@ -54,13 +57,27 @@ int FAST_FUNC bbunpack(char **argv, | |||
54 | 57 | ||
55 | /* Open src */ | 58 | /* Open src */ |
56 | if (filename) { | 59 | if (filename) { |
57 | if (stat(filename, &stat_buf) != 0) { | 60 | if (!(option_mask32 & SEAMLESS_MAGIC)) { |
58 | bb_simple_perror_msg(filename); | 61 | if (stat(filename, &stat_buf) != 0) { |
62 | err_name: | ||
63 | bb_simple_perror_msg(filename); | ||
59 | err: | 64 | err: |
60 | exitcode = 1; | 65 | exitcode = 1; |
61 | goto free_name; | 66 | goto free_name; |
67 | } | ||
68 | if (open_to_or_warn(STDIN_FILENO, filename, O_RDONLY, 0)) | ||
69 | goto err; | ||
70 | } else { | ||
71 | /* "clever zcat" with FILE */ | ||
72 | int fd = open_zipped(filename); | ||
73 | if (fd < 0) | ||
74 | goto err_name; | ||
75 | xmove_fd(fd, STDIN_FILENO); | ||
62 | } | 76 | } |
63 | if (open_to_or_warn(STDIN_FILENO, filename, O_RDONLY, 0)) | 77 | } else |
78 | if (option_mask32 & SEAMLESS_MAGIC) { | ||
79 | /* "clever zcat" on stdin */ | ||
80 | if (setup_unzip_on_fd(STDIN_FILENO, /*fail_if_not_detected*/ 0)) | ||
64 | goto err; | 81 | goto err; |
65 | } | 82 | } |
66 | 83 | ||
@@ -68,7 +85,7 @@ int FAST_FUNC bbunpack(char **argv, | |||
68 | if (option_mask32 & (OPT_STDOUT|OPT_TEST)) { | 85 | if (option_mask32 & (OPT_STDOUT|OPT_TEST)) { |
69 | if (option_mask32 & OPT_TEST) | 86 | if (option_mask32 & OPT_TEST) |
70 | if (open_to_or_warn(STDOUT_FILENO, bb_dev_null, O_WRONLY, 0)) | 87 | if (open_to_or_warn(STDOUT_FILENO, bb_dev_null, O_WRONLY, 0)) |
71 | goto err; | 88 | xfunc_die(); |
72 | filename = NULL; | 89 | filename = NULL; |
73 | } | 90 | } |
74 | 91 | ||
@@ -93,16 +110,22 @@ int FAST_FUNC bbunpack(char **argv, | |||
93 | } | 110 | } |
94 | 111 | ||
95 | /* Check that the input is sane */ | 112 | /* Check that the input is sane */ |
96 | if (isatty(STDIN_FILENO) && (option_mask32 & OPT_FORCE) == 0) { | 113 | if (!(option_mask32 & OPT_FORCE) && isatty(STDIN_FILENO)) { |
97 | bb_error_msg_and_die("compressed data not read from terminal, " | 114 | bb_error_msg_and_die("compressed data not read from terminal, " |
98 | "use -f to force it"); | 115 | "use -f to force it"); |
99 | } | 116 | } |
100 | 117 | ||
101 | init_transformer_aux_data(&aux); | 118 | if (!(option_mask32 & SEAMLESS_MAGIC)) { |
102 | aux.check_signature = 1; | 119 | init_transformer_aux_data(&aux); |
103 | status = unpacker(&aux); | 120 | aux.check_signature = 1; |
104 | if (status < 0) | 121 | status = unpacker(&aux); |
105 | exitcode = 1; | 122 | if (status < 0) |
123 | exitcode = 1; | ||
124 | } else { | ||
125 | if (bb_copyfd_eof(STDIN_FILENO, STDOUT_FILENO) < 0) | ||
126 | /* Disk full, tty closed, etc. No point in continuing */ | ||
127 | xfunc_die(); | ||
128 | } | ||
106 | 129 | ||
107 | if (!(option_mask32 & OPT_STDOUT)) | 130 | if (!(option_mask32 & OPT_STDOUT)) |
108 | xclose(STDOUT_FILENO); /* with error check! */ | 131 | xclose(STDOUT_FILENO); /* with error check! */ |
@@ -243,7 +266,7 @@ int uncompress_main(int argc UNUSED_PARAM, char **argv) | |||
243 | //usage: "-rw-rw-r-- 1 andersen andersen 1761280 Apr 14 17:47 /tmp/BusyBox-0.43.tar\n" | 266 | //usage: "-rw-rw-r-- 1 andersen andersen 1761280 Apr 14 17:47 /tmp/BusyBox-0.43.tar\n" |
244 | //usage: | 267 | //usage: |
245 | //usage:#define zcat_trivial_usage | 268 | //usage:#define zcat_trivial_usage |
246 | //usage: "FILE" | 269 | //usage: "[FILE]..." |
247 | //usage:#define zcat_full_usage "\n\n" | 270 | //usage:#define zcat_full_usage "\n\n" |
248 | //usage: "Decompress to stdout" | 271 | //usage: "Decompress to stdout" |
249 | 272 | ||
@@ -294,11 +317,15 @@ IF_DESKTOP(long long) int FAST_FUNC unpack_gunzip(transformer_aux_data_t *aux) | |||
294 | int gunzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 317 | int gunzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
295 | int gunzip_main(int argc UNUSED_PARAM, char **argv) | 318 | int gunzip_main(int argc UNUSED_PARAM, char **argv) |
296 | { | 319 | { |
297 | getopt32(argv, "cfvdtn"); | 320 | getopt32(argv, "cfvqdtn"); |
298 | argv += optind; | 321 | argv += optind; |
299 | /* if called as zcat */ | 322 | |
323 | /* If called as zcat... | ||
324 | * Normally, "zcat" is just "gunzip -c". | ||
325 | * But if seamless magic is enabled, then we are much more clever. | ||
326 | */ | ||
300 | if (applet_name[1] == 'c') | 327 | if (applet_name[1] == 'c') |
301 | option_mask32 |= OPT_STDOUT; | 328 | option_mask32 |= OPT_STDOUT | SEAMLESS_MAGIC; |
302 | 329 | ||
303 | return bbunpack(argv, unpack_gunzip, make_new_name_gunzip, /*unused:*/ NULL); | 330 | return bbunpack(argv, unpack_gunzip, make_new_name_gunzip, /*unused:*/ NULL); |
304 | } | 331 | } |
@@ -318,7 +345,7 @@ int gunzip_main(int argc UNUSED_PARAM, char **argv) | |||
318 | //usage: "\n -c Write to stdout" | 345 | //usage: "\n -c Write to stdout" |
319 | //usage: "\n -f Force" | 346 | //usage: "\n -f Force" |
320 | //usage:#define bzcat_trivial_usage | 347 | //usage:#define bzcat_trivial_usage |
321 | //usage: "FILE" | 348 | //usage: "[FILE]..." |
322 | //usage:#define bzcat_full_usage "\n\n" | 349 | //usage:#define bzcat_full_usage "\n\n" |
323 | //usage: "Decompress to stdout" | 350 | //usage: "Decompress to stdout" |
324 | //applet:IF_BUNZIP2(APPLET(bunzip2, BB_DIR_USR_BIN, BB_SUID_DROP)) | 351 | //applet:IF_BUNZIP2(APPLET(bunzip2, BB_DIR_USR_BIN, BB_SUID_DROP)) |
@@ -332,7 +359,7 @@ IF_DESKTOP(long long) int FAST_FUNC unpack_bunzip2(transformer_aux_data_t *aux) | |||
332 | int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 359 | int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
333 | int bunzip2_main(int argc UNUSED_PARAM, char **argv) | 360 | int bunzip2_main(int argc UNUSED_PARAM, char **argv) |
334 | { | 361 | { |
335 | getopt32(argv, "cfvdt"); | 362 | getopt32(argv, "cfvqdt"); |
336 | argv += optind; | 363 | argv += optind; |
337 | if (applet_name[2] == 'c') /* bzcat */ | 364 | if (applet_name[2] == 'c') /* bzcat */ |
338 | option_mask32 |= OPT_STDOUT; | 365 | option_mask32 |= OPT_STDOUT; |
@@ -367,7 +394,7 @@ int bunzip2_main(int argc UNUSED_PARAM, char **argv) | |||
367 | //usage: "\n -f Force" | 394 | //usage: "\n -f Force" |
368 | //usage: | 395 | //usage: |
369 | //usage:#define lzcat_trivial_usage | 396 | //usage:#define lzcat_trivial_usage |
370 | //usage: "FILE" | 397 | //usage: "[FILE]..." |
371 | //usage:#define lzcat_full_usage "\n\n" | 398 | //usage:#define lzcat_full_usage "\n\n" |
372 | //usage: "Decompress to stdout" | 399 | //usage: "Decompress to stdout" |
373 | //usage: | 400 | //usage: |
@@ -387,7 +414,7 @@ int bunzip2_main(int argc UNUSED_PARAM, char **argv) | |||
387 | //usage: "\n -f Force" | 414 | //usage: "\n -f Force" |
388 | //usage: | 415 | //usage: |
389 | //usage:#define xzcat_trivial_usage | 416 | //usage:#define xzcat_trivial_usage |
390 | //usage: "FILE" | 417 | //usage: "[FILE]..." |
391 | //usage:#define xzcat_full_usage "\n\n" | 418 | //usage:#define xzcat_full_usage "\n\n" |
392 | //usage: "Decompress to stdout" | 419 | //usage: "Decompress to stdout" |
393 | 420 | ||
@@ -400,7 +427,7 @@ IF_DESKTOP(long long) int FAST_FUNC unpack_unlzma(transformer_aux_data_t *aux) | |||
400 | int unlzma_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 427 | int unlzma_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
401 | int unlzma_main(int argc UNUSED_PARAM, char **argv) | 428 | int unlzma_main(int argc UNUSED_PARAM, char **argv) |
402 | { | 429 | { |
403 | IF_LZMA(int opts =) getopt32(argv, "cfvdt"); | 430 | IF_LZMA(int opts =) getopt32(argv, "cfvqdt"); |
404 | # if ENABLE_LZMA | 431 | # if ENABLE_LZMA |
405 | /* lzma without -d or -t? */ | 432 | /* lzma without -d or -t? */ |
406 | if (applet_name[2] == 'm' && !(opts & (OPT_DECOMPRESS|OPT_TEST))) | 433 | if (applet_name[2] == 'm' && !(opts & (OPT_DECOMPRESS|OPT_TEST))) |
@@ -425,7 +452,7 @@ IF_DESKTOP(long long) int FAST_FUNC unpack_unxz(transformer_aux_data_t *aux) | |||
425 | int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 452 | int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
426 | int unxz_main(int argc UNUSED_PARAM, char **argv) | 453 | int unxz_main(int argc UNUSED_PARAM, char **argv) |
427 | { | 454 | { |
428 | IF_XZ(int opts =) getopt32(argv, "cfvdt"); | 455 | IF_XZ(int opts =) getopt32(argv, "cfvqdt"); |
429 | # if ENABLE_XZ | 456 | # if ENABLE_XZ |
430 | /* xz without -d or -t? */ | 457 | /* xz without -d or -t? */ |
431 | if (applet_name[2] == '\0' && !(opts & (OPT_DECOMPRESS|OPT_TEST))) | 458 | if (applet_name[2] == '\0' && !(opts & (OPT_DECOMPRESS|OPT_TEST))) |
diff --git a/archival/libarchive/data_extract_all.c b/archival/libarchive/data_extract_all.c index 3f67b835f..45776dcbe 100644 --- a/archival/libarchive/data_extract_all.c +++ b/archival/libarchive/data_extract_all.c | |||
@@ -106,15 +106,28 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) | |||
106 | switch (file_header->mode & S_IFMT) { | 106 | switch (file_header->mode & S_IFMT) { |
107 | case S_IFREG: { | 107 | case S_IFREG: { |
108 | /* Regular file */ | 108 | /* Regular file */ |
109 | char *dst_name; | ||
109 | int flags = O_WRONLY | O_CREAT | O_EXCL; | 110 | int flags = O_WRONLY | O_CREAT | O_EXCL; |
110 | if (archive_handle->ah_flags & ARCHIVE_O_TRUNC) | 111 | if (archive_handle->ah_flags & ARCHIVE_O_TRUNC) |
111 | flags = O_WRONLY | O_CREAT | O_TRUNC; | 112 | flags = O_WRONLY | O_CREAT | O_TRUNC; |
112 | dst_fd = xopen3(file_header->name, | 113 | dst_name = file_header->name; |
114 | #ifdef ARCHIVE_REPLACE_VIA_RENAME | ||
115 | if (archive_handle->ah_flags & ARCHIVE_REPLACE_VIA_RENAME) | ||
116 | /* rpm-style temp file name */ | ||
117 | dst_name = xasprintf("%s;%x", dst_name, (int)getpid()); | ||
118 | #endif | ||
119 | dst_fd = xopen3(dst_name, | ||
113 | flags, | 120 | flags, |
114 | file_header->mode | 121 | file_header->mode |
115 | ); | 122 | ); |
116 | bb_copyfd_exact_size(archive_handle->src_fd, dst_fd, file_header->size); | 123 | bb_copyfd_exact_size(archive_handle->src_fd, dst_fd, file_header->size); |
117 | close(dst_fd); | 124 | close(dst_fd); |
125 | #ifdef ARCHIVE_REPLACE_VIA_RENAME | ||
126 | if (archive_handle->ah_flags & ARCHIVE_REPLACE_VIA_RENAME) { | ||
127 | xrename(dst_name, file_header->name); | ||
128 | free(dst_name); | ||
129 | } | ||
130 | #endif | ||
118 | break; | 131 | break; |
119 | } | 132 | } |
120 | case S_IFDIR: | 133 | case S_IFDIR: |
diff --git a/archival/libarchive/decompress_unlzma.c b/archival/libarchive/decompress_unlzma.c index cfde8ea56..ca32bd82c 100644 --- a/archival/libarchive/decompress_unlzma.c +++ b/archival/libarchive/decompress_unlzma.c | |||
@@ -45,16 +45,16 @@ typedef struct { | |||
45 | #define RC_MODEL_TOTAL_BITS 11 | 45 | #define RC_MODEL_TOTAL_BITS 11 |
46 | 46 | ||
47 | 47 | ||
48 | /* Called twice: once at startup (LZMA_FAST only) and once in rc_normalize() */ | 48 | /* Called once in rc_do_normalize() */ |
49 | static size_inline void rc_read(rc_t *rc) | 49 | static void rc_read(rc_t *rc) |
50 | { | 50 | { |
51 | int buffer_size = safe_read(rc->fd, RC_BUFFER, RC_BUFFER_SIZE); | 51 | int buffer_size = safe_read(rc->fd, RC_BUFFER, RC_BUFFER_SIZE); |
52 | //TODO: return -1 instead | 52 | //TODO: return -1 instead |
53 | //This will make unlzma delete broken unpacked file on unpack errors | 53 | //This will make unlzma delete broken unpacked file on unpack errors |
54 | if (buffer_size <= 0) | 54 | if (buffer_size <= 0) |
55 | bb_error_msg_and_die("unexpected EOF"); | 55 | bb_error_msg_and_die("unexpected EOF"); |
56 | rc->ptr = RC_BUFFER; | ||
57 | rc->buffer_end = RC_BUFFER + buffer_size; | 56 | rc->buffer_end = RC_BUFFER + buffer_size; |
57 | rc->ptr = RC_BUFFER; | ||
58 | } | 58 | } |
59 | 59 | ||
60 | /* Called twice, but one callsite is in speed_inline'd rc_is_bit_1() */ | 60 | /* Called twice, but one callsite is in speed_inline'd rc_is_bit_1() */ |
@@ -65,6 +65,12 @@ static void rc_do_normalize(rc_t *rc) | |||
65 | rc->range <<= 8; | 65 | rc->range <<= 8; |
66 | rc->code = (rc->code << 8) | *rc->ptr++; | 66 | rc->code = (rc->code << 8) | *rc->ptr++; |
67 | } | 67 | } |
68 | static ALWAYS_INLINE void rc_normalize(rc_t *rc) | ||
69 | { | ||
70 | if (rc->range < (1 << RC_TOP_BITS)) { | ||
71 | rc_do_normalize(rc); | ||
72 | } | ||
73 | } | ||
68 | 74 | ||
69 | /* Called once */ | 75 | /* Called once */ |
70 | static ALWAYS_INLINE rc_t* rc_init(int fd) /*, int buffer_size) */ | 76 | static ALWAYS_INLINE rc_t* rc_init(int fd) /*, int buffer_size) */ |
@@ -78,15 +84,9 @@ static ALWAYS_INLINE rc_t* rc_init(int fd) /*, int buffer_size) */ | |||
78 | /* rc->ptr = rc->buffer_end; */ | 84 | /* rc->ptr = rc->buffer_end; */ |
79 | 85 | ||
80 | for (i = 0; i < 5; i++) { | 86 | for (i = 0; i < 5; i++) { |
81 | #if ENABLE_FEATURE_LZMA_FAST | ||
82 | if (rc->ptr >= rc->buffer_end) | ||
83 | rc_read(rc); | ||
84 | rc->code = (rc->code << 8) | *rc->ptr++; | ||
85 | #else | ||
86 | rc_do_normalize(rc); | 87 | rc_do_normalize(rc); |
87 | #endif | ||
88 | } | 88 | } |
89 | rc->range = 0xFFFFFFFF; | 89 | rc->range = 0xffffffff; |
90 | return rc; | 90 | return rc; |
91 | } | 91 | } |
92 | 92 | ||
@@ -96,13 +96,6 @@ static ALWAYS_INLINE void rc_free(rc_t *rc) | |||
96 | free(rc); | 96 | free(rc); |
97 | } | 97 | } |
98 | 98 | ||
99 | static ALWAYS_INLINE void rc_normalize(rc_t *rc) | ||
100 | { | ||
101 | if (rc->range < (1 << RC_TOP_BITS)) { | ||
102 | rc_do_normalize(rc); | ||
103 | } | ||
104 | } | ||
105 | |||
106 | /* rc_is_bit_1 is called 9 times */ | 99 | /* rc_is_bit_1 is called 9 times */ |
107 | static speed_inline int rc_is_bit_1(rc_t *rc, uint16_t *p) | 100 | static speed_inline int rc_is_bit_1(rc_t *rc, uint16_t *p) |
108 | { | 101 | { |
@@ -120,7 +113,7 @@ static speed_inline int rc_is_bit_1(rc_t *rc, uint16_t *p) | |||
120 | } | 113 | } |
121 | 114 | ||
122 | /* Called 4 times in unlzma loop */ | 115 | /* Called 4 times in unlzma loop */ |
123 | static speed_inline int rc_get_bit(rc_t *rc, uint16_t *p, int *symbol) | 116 | static ALWAYS_INLINE int rc_get_bit(rc_t *rc, uint16_t *p, int *symbol) |
124 | { | 117 | { |
125 | int ret = rc_is_bit_1(rc, p); | 118 | int ret = rc_is_bit_1(rc, p); |
126 | *symbol = *symbol * 2 + ret; | 119 | *symbol = *symbol * 2 + ret; |
diff --git a/archival/libarchive/decompress_unxz.c b/archival/libarchive/decompress_unxz.c index 79b48a152..986b7b191 100644 --- a/archival/libarchive/decompress_unxz.c +++ b/archival/libarchive/decompress_unxz.c | |||
@@ -30,8 +30,8 @@ static uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc) | |||
30 | /* We use arch-optimized unaligned accessors */ | 30 | /* We use arch-optimized unaligned accessors */ |
31 | #define get_unaligned_le32(buf) ({ uint32_t v; move_from_unaligned32(v, buf); SWAP_LE32(v); }) | 31 | #define get_unaligned_le32(buf) ({ uint32_t v; move_from_unaligned32(v, buf); SWAP_LE32(v); }) |
32 | #define get_unaligned_be32(buf) ({ uint32_t v; move_from_unaligned32(v, buf); SWAP_BE32(v); }) | 32 | #define get_unaligned_be32(buf) ({ uint32_t v; move_from_unaligned32(v, buf); SWAP_BE32(v); }) |
33 | #define put_unaligned_le32(val, buf) move_to_unaligned16(buf, SWAP_LE32(val)) | 33 | #define put_unaligned_le32(val, buf) move_to_unaligned32(buf, SWAP_LE32(val)) |
34 | #define put_unaligned_be32(val, buf) move_to_unaligned16(buf, SWAP_BE32(val)) | 34 | #define put_unaligned_be32(val, buf) move_to_unaligned32(buf, SWAP_BE32(val)) |
35 | 35 | ||
36 | #include "unxz/xz_dec_bcj.c" | 36 | #include "unxz/xz_dec_bcj.c" |
37 | #include "unxz/xz_dec_lzma2.c" | 37 | #include "unxz/xz_dec_lzma2.c" |
@@ -40,6 +40,7 @@ static uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc) | |||
40 | IF_DESKTOP(long long) int FAST_FUNC | 40 | IF_DESKTOP(long long) int FAST_FUNC |
41 | unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) | 41 | unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) |
42 | { | 42 | { |
43 | enum xz_ret xz_result; | ||
43 | struct xz_buf iobuf; | 44 | struct xz_buf iobuf; |
44 | struct xz_dec *state; | 45 | struct xz_dec *state; |
45 | unsigned char *membuf; | 46 | unsigned char *membuf; |
@@ -63,9 +64,8 @@ unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) | |||
63 | /* Limit memory usage to about 64 MiB. */ | 64 | /* Limit memory usage to about 64 MiB. */ |
64 | state = xz_dec_init(XZ_DYNALLOC, 64*1024*1024); | 65 | state = xz_dec_init(XZ_DYNALLOC, 64*1024*1024); |
65 | 66 | ||
67 | xz_result = X_OK; | ||
66 | while (1) { | 68 | while (1) { |
67 | enum xz_ret r; | ||
68 | |||
69 | if (iobuf.in_pos == iobuf.in_size) { | 69 | if (iobuf.in_pos == iobuf.in_size) { |
70 | int rd = safe_read(src_fd, membuf, BUFSIZ); | 70 | int rd = safe_read(src_fd, membuf, BUFSIZ); |
71 | if (rd < 0) { | 71 | if (rd < 0) { |
@@ -73,28 +73,57 @@ unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) | |||
73 | total = -1; | 73 | total = -1; |
74 | break; | 74 | break; |
75 | } | 75 | } |
76 | if (rd == 0 && xz_result == XZ_STREAM_END) | ||
77 | break; | ||
76 | iobuf.in_size = rd; | 78 | iobuf.in_size = rd; |
77 | iobuf.in_pos = 0; | 79 | iobuf.in_pos = 0; |
78 | } | 80 | } |
81 | if (xz_result == XZ_STREAM_END) { | ||
82 | /* | ||
83 | * Try to start decoding next concatenated stream. | ||
84 | * Stream padding must always be a multiple of four | ||
85 | * bytes to preserve four-byte alignment. To keep the | ||
86 | * code slightly smaller, we aren't as strict here as | ||
87 | * the .xz spec requires. We just skip all zero-bytes | ||
88 | * without checking the alignment and thus can accept | ||
89 | * files that aren't valid, e.g. the XZ utils test | ||
90 | * files bad-0pad-empty.xz and bad-0catpad-empty.xz. | ||
91 | */ | ||
92 | do { | ||
93 | if (membuf[iobuf.in_pos] != 0) { | ||
94 | xz_dec_reset(state); | ||
95 | goto do_run; | ||
96 | } | ||
97 | iobuf.in_pos++; | ||
98 | } while (iobuf.in_pos < iobuf.in_size); | ||
99 | } | ||
100 | do_run: | ||
79 | // bb_error_msg(">in pos:%d size:%d out pos:%d size:%d", | 101 | // bb_error_msg(">in pos:%d size:%d out pos:%d size:%d", |
80 | // iobuf.in_pos, iobuf.in_size, iobuf.out_pos, iobuf.out_size); | 102 | // iobuf.in_pos, iobuf.in_size, iobuf.out_pos, iobuf.out_size); |
81 | r = xz_dec_run(state, &iobuf); | 103 | xz_result = xz_dec_run(state, &iobuf); |
82 | // bb_error_msg("<in pos:%d size:%d out pos:%d size:%d r:%d", | 104 | // bb_error_msg("<in pos:%d size:%d out pos:%d size:%d r:%d", |
83 | // iobuf.in_pos, iobuf.in_size, iobuf.out_pos, iobuf.out_size, r); | 105 | // iobuf.in_pos, iobuf.in_size, iobuf.out_pos, iobuf.out_size, xz_result); |
84 | if (iobuf.out_pos) { | 106 | if (iobuf.out_pos) { |
85 | xwrite(dst_fd, iobuf.out, iobuf.out_pos); | 107 | xwrite(dst_fd, iobuf.out, iobuf.out_pos); |
86 | IF_DESKTOP(total += iobuf.out_pos;) | 108 | IF_DESKTOP(total += iobuf.out_pos;) |
87 | iobuf.out_pos = 0; | 109 | iobuf.out_pos = 0; |
88 | } | 110 | } |
89 | if (r == XZ_STREAM_END) { | 111 | if (xz_result == XZ_STREAM_END) { |
90 | break; | 112 | /* |
113 | * Can just "break;" here, if not for concatenated | ||
114 | * .xz streams. | ||
115 | * Checking for padding may require buffer | ||
116 | * replenishment. Can't do it here. | ||
117 | */ | ||
118 | continue; | ||
91 | } | 119 | } |
92 | if (r != XZ_OK && r != XZ_UNSUPPORTED_CHECK) { | 120 | if (xz_result != XZ_OK && xz_result != XZ_UNSUPPORTED_CHECK) { |
93 | bb_error_msg("corrupted data"); | 121 | bb_error_msg("corrupted data"); |
94 | total = -1; | 122 | total = -1; |
95 | break; | 123 | break; |
96 | } | 124 | } |
97 | } | 125 | } |
126 | |||
98 | xz_dec_end(state); | 127 | xz_dec_end(state); |
99 | free(membuf); | 128 | free(membuf); |
100 | 129 | ||
diff --git a/archival/libarchive/open_transformer.c b/archival/libarchive/open_transformer.c index f2edc2a2b..841e9dce9 100644 --- a/archival/libarchive/open_transformer.c +++ b/archival/libarchive/open_transformer.c | |||
@@ -35,6 +35,7 @@ void check_errors_in_children(int signo) | |||
35 | if (!signo) { | 35 | if (!signo) { |
36 | /* block waiting for any child */ | 36 | /* block waiting for any child */ |
37 | if (wait(&status) < 0) | 37 | if (wait(&status) < 0) |
38 | //FIXME: check EINTR? | ||
38 | return; /* probably there are no children */ | 39 | return; /* probably there are no children */ |
39 | goto check_status; | 40 | goto check_status; |
40 | } | 41 | } |
@@ -42,14 +43,18 @@ void check_errors_in_children(int signo) | |||
42 | /* Wait for any child without blocking */ | 43 | /* Wait for any child without blocking */ |
43 | for (;;) { | 44 | for (;;) { |
44 | if (wait_any_nohang(&status) < 0) | 45 | if (wait_any_nohang(&status) < 0) |
46 | //FIXME: check EINTR? | ||
45 | /* wait failed?! I'm confused... */ | 47 | /* wait failed?! I'm confused... */ |
46 | return; | 48 | return; |
47 | check_status: | 49 | check_status: |
48 | if (WIFEXITED(status) && WEXITSTATUS(status) == 0) | 50 | /*if (WIFEXITED(status) && WEXITSTATUS(status) == 0)*/ |
51 | /* On Linux, the above can be checked simply as: */ | ||
52 | if (status == 0) | ||
49 | /* this child exited with 0 */ | 53 | /* this child exited with 0 */ |
50 | continue; | 54 | continue; |
51 | /* Cannot happen? | 55 | /* Cannot happen: |
52 | if (!WIFSIGNALED(status) && !WIFEXITED(status)) ???; */ | 56 | if (!WIFSIGNALED(status) && !WIFEXITED(status)) ???; |
57 | */ | ||
53 | bb_got_signal = 1; | 58 | bb_got_signal = 1; |
54 | } | 59 | } |
55 | } | 60 | } |
diff --git a/archival/libarchive/unxz/README b/archival/libarchive/unxz/README index c5972f6b8..a84912035 100644 --- a/archival/libarchive/unxz/README +++ b/archival/libarchive/unxz/README | |||
@@ -7,7 +7,7 @@ XZ Embedded | |||
7 | 7 | ||
8 | XZ Embedded was written for use in the Linux kernel, but the code can | 8 | XZ Embedded was written for use in the Linux kernel, but the code can |
9 | be easily used in other environments too, including regular userspace | 9 | be easily used in other environments too, including regular userspace |
10 | applications. | 10 | applications. See userspace/xzminidec.c for an example program. |
11 | 11 | ||
12 | This README contains information that is useful only when the copy | 12 | This README contains information that is useful only when the copy |
13 | of XZ Embedded isn't part of the Linux kernel tree. You should also | 13 | of XZ Embedded isn't part of the Linux kernel tree. You should also |
@@ -55,7 +55,7 @@ Compiler requirements | |||
55 | code is modified not to support large files, which needs some more | 55 | code is modified not to support large files, which needs some more |
56 | care than just using 32-bit integer instead of 64-bit). | 56 | care than just using 32-bit integer instead of 64-bit). |
57 | 57 | ||
58 | If you use GCC, try to use a recent version. For example, on x86, | 58 | If you use GCC, try to use a recent version. For example, on x86-32, |
59 | xz_dec_lzma2.c compiled with GCC 3.3.6 is 15-25 % slower than when | 59 | xz_dec_lzma2.c compiled with GCC 3.3.6 is 15-25 % slower than when |
60 | compiled with GCC 4.3.3. | 60 | compiled with GCC 4.3.3. |
61 | 61 | ||
@@ -93,7 +93,7 @@ BCJ filter support | |||
93 | them always #defined doesn't hurt either. | 93 | them always #defined doesn't hurt either. |
94 | 94 | ||
95 | #define Instruction set BCJ filter endianness | 95 | #define Instruction set BCJ filter endianness |
96 | XZ_DEC_X86 x86 or x86-64 Little endian only | 96 | XZ_DEC_X86 x86-32 or x86-64 Little endian only |
97 | XZ_DEC_POWERPC PowerPC Big endian only | 97 | XZ_DEC_POWERPC PowerPC Big endian only |
98 | XZ_DEC_IA64 Itanium (IA-64) Big or little endian | 98 | XZ_DEC_IA64 Itanium (IA-64) Big or little endian |
99 | XZ_DEC_ARM ARM Little endian only | 99 | XZ_DEC_ARM ARM Little endian only |
diff --git a/archival/libarchive/unxz/xz.h b/archival/libarchive/unxz/xz.h index c6c071c4a..e0b22db56 100644 --- a/archival/libarchive/unxz/xz.h +++ b/archival/libarchive/unxz/xz.h | |||
@@ -19,6 +19,10 @@ | |||
19 | # include <stdint.h> | 19 | # include <stdint.h> |
20 | #endif | 20 | #endif |
21 | 21 | ||
22 | #ifdef __cplusplus | ||
23 | extern "C" { | ||
24 | #endif | ||
25 | |||
22 | /* In Linux, this is used to make extern functions static when needed. */ | 26 | /* In Linux, this is used to make extern functions static when needed. */ |
23 | #ifndef XZ_EXTERN | 27 | #ifndef XZ_EXTERN |
24 | # define XZ_EXTERN extern | 28 | # define XZ_EXTERN extern |
@@ -70,7 +74,7 @@ enum xz_mode { | |||
70 | * @XZ_UNSUPPORTED_CHECK: Integrity check type is not supported. Decoding | 74 | * @XZ_UNSUPPORTED_CHECK: Integrity check type is not supported. Decoding |
71 | * is still possible in multi-call mode by simply | 75 | * is still possible in multi-call mode by simply |
72 | * calling xz_dec_run() again. | 76 | * calling xz_dec_run() again. |
73 | * NOTE: This return value is used only if | 77 | * Note that this return value is used only if |
74 | * XZ_DEC_ANY_CHECK was defined at build time, | 78 | * XZ_DEC_ANY_CHECK was defined at build time, |
75 | * which is not used in the kernel. Unsupported | 79 | * which is not used in the kernel. Unsupported |
76 | * check types return XZ_OPTIONS_ERROR if | 80 | * check types return XZ_OPTIONS_ERROR if |
@@ -105,7 +109,7 @@ enum xz_mode { | |||
105 | * stream that is truncated or otherwise corrupt. | 109 | * stream that is truncated or otherwise corrupt. |
106 | * | 110 | * |
107 | * In single-call mode, XZ_BUF_ERROR is returned only when the output buffer | 111 | * In single-call mode, XZ_BUF_ERROR is returned only when the output buffer |
108 | * is too small, or the compressed input is corrupt in a way that makes the | 112 | * is too small or the compressed input is corrupt in a way that makes the |
109 | * decoder produce more output than the caller expected. When it is | 113 | * decoder produce more output than the caller expected. When it is |
110 | * (relatively) clear that the compressed input is truncated, XZ_DATA_ERROR | 114 | * (relatively) clear that the compressed input is truncated, XZ_DATA_ERROR |
111 | * is used instead of XZ_BUF_ERROR. | 115 | * is used instead of XZ_BUF_ERROR. |
@@ -207,8 +211,8 @@ XZ_EXTERN struct xz_dec * XZ_FUNC xz_dec_init( | |||
207 | * The possible return values depend on build options and operation mode. | 211 | * The possible return values depend on build options and operation mode. |
208 | * See enum xz_ret for details. | 212 | * See enum xz_ret for details. |
209 | * | 213 | * |
210 | * NOTE: If an error occurs in single-call mode (return value is not | 214 | * Note that if an error occurs in single-call mode (return value is not |
211 | * XZ_STREAM_END), b->in_pos and b->out_pos are not modified, and the | 215 | * XZ_STREAM_END), b->in_pos and b->out_pos are not modified and the |
212 | * contents of the output buffer from b->out[b->out_pos] onward are | 216 | * contents of the output buffer from b->out[b->out_pos] onward are |
213 | * undefined. This is true even after XZ_BUF_ERROR, because with some filter | 217 | * undefined. This is true even after XZ_BUF_ERROR, because with some filter |
214 | * chains, there may be a second pass over the output buffer, and this pass | 218 | * chains, there may be a second pass over the output buffer, and this pass |
@@ -268,4 +272,9 @@ XZ_EXTERN void XZ_FUNC xz_crc32_init(void); | |||
268 | XZ_EXTERN uint32_t XZ_FUNC xz_crc32( | 272 | XZ_EXTERN uint32_t XZ_FUNC xz_crc32( |
269 | const uint8_t *buf, size_t size, uint32_t crc); | 273 | const uint8_t *buf, size_t size, uint32_t crc); |
270 | #endif | 274 | #endif |
275 | |||
276 | #ifdef __cplusplus | ||
277 | } | ||
278 | #endif | ||
279 | |||
271 | #endif | 280 | #endif |
diff --git a/archival/libarchive/unxz/xz_dec_bcj.c b/archival/libarchive/unxz/xz_dec_bcj.c index 09162b51f..e0f913a94 100644 --- a/archival/libarchive/unxz/xz_dec_bcj.c +++ b/archival/libarchive/unxz/xz_dec_bcj.c | |||
@@ -77,10 +77,13 @@ struct xz_dec_bcj { | |||
77 | 77 | ||
78 | #ifdef XZ_DEC_X86 | 78 | #ifdef XZ_DEC_X86 |
79 | /* | 79 | /* |
80 | * This is macro used to test the most significant byte of a memory address | 80 | * This is used to test the most significant byte of a memory address |
81 | * in an x86 instruction. | 81 | * in an x86 instruction. |
82 | */ | 82 | */ |
83 | #define bcj_x86_test_msbyte(b) ((b) == 0x00 || (b) == 0xFF) | 83 | static inline int bcj_x86_test_msbyte(uint8_t b) |
84 | { | ||
85 | return b == 0x00 || b == 0xFF; | ||
86 | } | ||
84 | 87 | ||
85 | static noinline_for_stack size_t XZ_FUNC bcj_x86( | 88 | static noinline_for_stack size_t XZ_FUNC bcj_x86( |
86 | struct xz_dec_bcj *s, uint8_t *buf, size_t size) | 89 | struct xz_dec_bcj *s, uint8_t *buf, size_t size) |
@@ -443,8 +446,12 @@ XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_run(struct xz_dec_bcj *s, | |||
443 | * next filter in the chain. Apply the BCJ filter on the new data | 446 | * next filter in the chain. Apply the BCJ filter on the new data |
444 | * in the output buffer. If everything cannot be filtered, copy it | 447 | * in the output buffer. If everything cannot be filtered, copy it |
445 | * to temp and rewind the output buffer position accordingly. | 448 | * to temp and rewind the output buffer position accordingly. |
449 | * | ||
450 | * This needs to be always run when temp.size == 0 to handle a special | ||
451 | * case where the output buffer is full and the next filter has no | ||
452 | * more output coming but hasn't returned XZ_STREAM_END yet. | ||
446 | */ | 453 | */ |
447 | if (s->temp.size < b->out_size - b->out_pos) { | 454 | if (s->temp.size < b->out_size - b->out_pos || s->temp.size == 0) { |
448 | out_start = b->out_pos; | 455 | out_start = b->out_pos; |
449 | memcpy(b->out + b->out_pos, s->temp.buf, s->temp.size); | 456 | memcpy(b->out + b->out_pos, s->temp.buf, s->temp.size); |
450 | b->out_pos += s->temp.size; | 457 | b->out_pos += s->temp.size; |
@@ -467,16 +474,25 @@ XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_run(struct xz_dec_bcj *s, | |||
467 | s->temp.size = b->out_pos - out_start; | 474 | s->temp.size = b->out_pos - out_start; |
468 | b->out_pos -= s->temp.size; | 475 | b->out_pos -= s->temp.size; |
469 | memcpy(s->temp.buf, b->out + b->out_pos, s->temp.size); | 476 | memcpy(s->temp.buf, b->out + b->out_pos, s->temp.size); |
477 | |||
478 | /* | ||
479 | * If there wasn't enough input to the next filter to fill | ||
480 | * the output buffer with unfiltered data, there's no point | ||
481 | * to try decoding more data to temp. | ||
482 | */ | ||
483 | if (b->out_pos + s->temp.size < b->out_size) | ||
484 | return XZ_OK; | ||
470 | } | 485 | } |
471 | 486 | ||
472 | /* | 487 | /* |
473 | * If we have unfiltered data in temp, try to fill by decoding more | 488 | * We have unfiltered data in temp. If the output buffer isn't full |
474 | * data from the next filter. Apply the BCJ filter on temp. Then we | 489 | * yet, try to fill the temp buffer by decoding more data from the |
475 | * hopefully can fill the actual output buffer by copying filtered | 490 | * next filter. Apply the BCJ filter on temp. Then we hopefully can |
476 | * data from temp. A mix of filtered and unfiltered data may be left | 491 | * fill the actual output buffer by copying filtered data from temp. |
477 | * in temp; it will be taken care on the next call to this function. | 492 | * A mix of filtered and unfiltered data may be left in temp; it will |
493 | * be taken care on the next call to this function. | ||
478 | */ | 494 | */ |
479 | if (s->temp.size > 0) { | 495 | if (b->out_pos < b->out_size) { |
480 | /* Make b->out{,_pos,_size} temporarily point to s->temp. */ | 496 | /* Make b->out{,_pos,_size} temporarily point to s->temp. */ |
481 | s->out = b->out; | 497 | s->out = b->out; |
482 | s->out_pos = b->out_pos; | 498 | s->out_pos = b->out_pos; |
diff --git a/archival/libarchive/unxz/xz_dec_lzma2.c b/archival/libarchive/unxz/xz_dec_lzma2.c index da71cb4d4..3c2dc88b7 100644 --- a/archival/libarchive/unxz/xz_dec_lzma2.c +++ b/archival/libarchive/unxz/xz_dec_lzma2.c | |||
@@ -407,7 +407,6 @@ static void XZ_FUNC dict_uncompressed( | |||
407 | 407 | ||
408 | b->out_pos += copy_size; | 408 | b->out_pos += copy_size; |
409 | b->in_pos += copy_size; | 409 | b->in_pos += copy_size; |
410 | |||
411 | } | 410 | } |
412 | } | 411 | } |
413 | 412 | ||
@@ -972,6 +971,9 @@ XZ_EXTERN NOINLINE enum xz_ret XZ_FUNC xz_dec_lzma2_run( | |||
972 | */ | 971 | */ |
973 | tmp = b->in[b->in_pos++]; | 972 | tmp = b->in[b->in_pos++]; |
974 | 973 | ||
974 | if (tmp == 0x00) | ||
975 | return XZ_STREAM_END; | ||
976 | |||
975 | if (tmp >= 0xE0 || tmp == 0x01) { | 977 | if (tmp >= 0xE0 || tmp == 0x01) { |
976 | s->lzma2.need_props = true; | 978 | s->lzma2.need_props = true; |
977 | s->lzma2.need_dict_reset = false; | 979 | s->lzma2.need_dict_reset = false; |
@@ -1004,9 +1006,6 @@ XZ_EXTERN NOINLINE enum xz_ret XZ_FUNC xz_dec_lzma2_run( | |||
1004 | lzma_reset(s); | 1006 | lzma_reset(s); |
1005 | } | 1007 | } |
1006 | } else { | 1008 | } else { |
1007 | if (tmp == 0x00) | ||
1008 | return XZ_STREAM_END; | ||
1009 | |||
1010 | if (tmp > 0x02) | 1009 | if (tmp > 0x02) |
1011 | return XZ_DATA_ERROR; | 1010 | return XZ_DATA_ERROR; |
1012 | 1011 | ||
diff --git a/archival/libarchive/unxz/xz_stream.h b/archival/libarchive/unxz/xz_stream.h index 36f2a7cbf..66cb5a705 100644 --- a/archival/libarchive/unxz/xz_stream.h +++ b/archival/libarchive/unxz/xz_stream.h | |||
@@ -25,15 +25,20 @@ | |||
25 | 25 | ||
26 | #define STREAM_HEADER_SIZE 12 | 26 | #define STREAM_HEADER_SIZE 12 |
27 | 27 | ||
28 | #define HEADER_MAGIC "\3757zXZ\0" | 28 | #define HEADER_MAGIC "\3757zXZ" |
29 | #define HEADER_MAGIC_SIZE 6 | 29 | #define HEADER_MAGIC_SIZE 6 |
30 | 30 | ||
31 | #define FOOTER_MAGIC "YZ" | 31 | #define FOOTER_MAGIC "YZ" |
32 | #define FOOTER_MAGIC_SIZE 2 | 32 | #define FOOTER_MAGIC_SIZE 2 |
33 | 33 | ||
34 | /* | 34 | /* |
35 | * Variable-length integer can hold a 63-bit unsigned integer, or a special | 35 | * Variable-length integer can hold a 63-bit unsigned integer or a special |
36 | * value to indicate that the value is unknown. | 36 | * value indicating that the value is unknown. |
37 | * | ||
38 | * Experimental: vli_type can be defined to uint32_t to save a few bytes | ||
39 | * in code size (no effect on speed). Doing so limits the uncompressed and | ||
40 | * compressed size of the file to less than 256 MiB and may also weaken | ||
41 | * error detection slightly. | ||
37 | */ | 42 | */ |
38 | typedef uint64_t vli_type; | 43 | typedef uint64_t vli_type; |
39 | 44 | ||
diff --git a/archival/lzop.c b/archival/lzop.c index 56003d421..9b42e5fd3 100644 --- a/archival/lzop.c +++ b/archival/lzop.c | |||
@@ -436,25 +436,27 @@ struct globals { | |||
436 | //#define LZOP_VERSION_STRING "1.01" | 436 | //#define LZOP_VERSION_STRING "1.01" |
437 | //#define LZOP_VERSION_DATE "Apr 27th 2003" | 437 | //#define LZOP_VERSION_DATE "Apr 27th 2003" |
438 | 438 | ||
439 | #define OPTION_STRING "cfvdt123456789CF" | 439 | #define OPTION_STRING "cfvqdt123456789CF" |
440 | 440 | ||
441 | /* Note: must be kept in sync with archival/bbunzip.c */ | ||
441 | enum { | 442 | enum { |
442 | OPT_STDOUT = (1 << 0), | 443 | OPT_STDOUT = (1 << 0), |
443 | OPT_FORCE = (1 << 1), | 444 | OPT_FORCE = (1 << 1), |
444 | OPT_VERBOSE = (1 << 2), | 445 | OPT_VERBOSE = (1 << 2), |
445 | OPT_DECOMPRESS = (1 << 3), | 446 | OPT_QUIET = (1 << 3), |
446 | OPT_TEST = (1 << 4), | 447 | OPT_DECOMPRESS = (1 << 4), |
447 | OPT_1 = (1 << 5), | 448 | OPT_TEST = (1 << 5), |
448 | OPT_2 = (1 << 6), | 449 | OPT_1 = (1 << 6), |
449 | OPT_3 = (1 << 7), | 450 | OPT_2 = (1 << 7), |
450 | OPT_4 = (1 << 8), | 451 | OPT_3 = (1 << 8), |
451 | OPT_5 = (1 << 9), | 452 | OPT_4 = (1 << 9), |
452 | OPT_6 = (1 << 10), | 453 | OPT_5 = (1 << 10), |
453 | OPT_789 = (7 << 11), | 454 | OPT_6 = (1 << 11), |
454 | OPT_7 = (1 << 11), | 455 | OPT_789 = (7 << 12), |
455 | OPT_8 = (1 << 12), | 456 | OPT_7 = (1 << 13), |
456 | OPT_C = (1 << 14), | 457 | OPT_8 = (1 << 14), |
457 | OPT_F = (1 << 15), | 458 | OPT_C = (1 << 15), |
459 | OPT_F = (1 << 16), | ||
458 | }; | 460 | }; |
459 | 461 | ||
460 | /**********************************************************************/ | 462 | /**********************************************************************/ |
@@ -1093,7 +1095,7 @@ int lzop_main(int argc UNUSED_PARAM, char **argv) | |||
1093 | if (applet_name[4] == 'c') | 1095 | if (applet_name[4] == 'c') |
1094 | option_mask32 |= (OPT_STDOUT | OPT_DECOMPRESS); | 1096 | option_mask32 |= (OPT_STDOUT | OPT_DECOMPRESS); |
1095 | /* unlzop? */ | 1097 | /* unlzop? */ |
1096 | if (applet_name[0] == 'u') | 1098 | if (applet_name[4] == 'o') |
1097 | option_mask32 |= OPT_DECOMPRESS; | 1099 | option_mask32 |= OPT_DECOMPRESS; |
1098 | 1100 | ||
1099 | global_crc32_table = crc32_filltable(NULL, 0); | 1101 | global_crc32_table = crc32_filltable(NULL, 0); |
diff --git a/archival/rpm.c b/archival/rpm.c index 6757a6ceb..86ba4dca4 100644 --- a/archival/rpm.c +++ b/archival/rpm.c | |||
@@ -14,10 +14,10 @@ | |||
14 | //usage: "\nCommands:" | 14 | //usage: "\nCommands:" |
15 | //usage: "\n -i Install package" | 15 | //usage: "\n -i Install package" |
16 | //usage: "\n -qp Query package" | 16 | //usage: "\n -qp Query package" |
17 | //usage: "\n -i Show information" | 17 | //usage: "\n -qpi Show information" |
18 | //usage: "\n -l List contents" | 18 | //usage: "\n -qpl List contents" |
19 | //usage: "\n -d List documents" | 19 | //usage: "\n -qpd List documents" |
20 | //usage: "\n -c List config files" | 20 | //usage: "\n -qpc List config files" |
21 | 21 | ||
22 | #include "libbb.h" | 22 | #include "libbb.h" |
23 | #include "bb_archive.h" | 23 | #include "bb_archive.h" |
@@ -79,136 +79,13 @@ typedef struct { | |||
79 | uint32_t count; /* 4 byte count */ | 79 | uint32_t count; /* 4 byte count */ |
80 | } rpm_index; | 80 | } rpm_index; |
81 | 81 | ||
82 | static void *map; | 82 | struct globals { |
83 | static rpm_index **mytags; | 83 | void *map; |
84 | static int tagcount; | 84 | rpm_index **mytags; |
85 | 85 | int tagcount; | |
86 | static void extract_cpio(int fd, const char *source_rpm); | 86 | } FIX_ALIASING; |
87 | static rpm_index **rpm_gettags(int fd, int *num_tags); | 87 | #define G (*(struct globals*)&bb_common_bufsiz1) |
88 | static int bsearch_rpmtag(const void *key, const void *item); | 88 | #define INIT_G() do { } while (0) |
89 | static char *rpm_getstr(int tag, int itemindex); | ||
90 | static int rpm_getint(int tag, int itemindex); | ||
91 | static int rpm_getcount(int tag); | ||
92 | static void fileaction_dobackup(char *filename, int fileref); | ||
93 | static void fileaction_setowngrp(char *filename, int fileref); | ||
94 | static void loop_through_files(int filetag, void (*fileaction)(char *filename, int fileref)); | ||
95 | |||
96 | int rpm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
97 | int rpm_main(int argc, char **argv) | ||
98 | { | ||
99 | int opt = 0, func = 0, rpm_fd, offset; | ||
100 | const int pagesize = getpagesize(); | ||
101 | |||
102 | while ((opt = getopt(argc, argv, "iqpldc")) != -1) { | ||
103 | switch (opt) { | ||
104 | case 'i': /* First arg: Install mode, with q: Information */ | ||
105 | if (!func) func = rpm_install; | ||
106 | else func |= rpm_query_info; | ||
107 | break; | ||
108 | case 'q': /* First arg: Query mode */ | ||
109 | if (func) bb_show_usage(); | ||
110 | func = rpm_query; | ||
111 | break; | ||
112 | case 'p': /* Query a package */ | ||
113 | func |= rpm_query_package; | ||
114 | break; | ||
115 | case 'l': /* List files in a package */ | ||
116 | func |= rpm_query_list; | ||
117 | break; | ||
118 | case 'd': /* List doc files in a package (implies list) */ | ||
119 | func |= rpm_query_list; | ||
120 | func |= rpm_query_list_doc; | ||
121 | break; | ||
122 | case 'c': /* List config files in a package (implies list) */ | ||
123 | func |= rpm_query_list; | ||
124 | func |= rpm_query_list_config; | ||
125 | break; | ||
126 | default: | ||
127 | bb_show_usage(); | ||
128 | } | ||
129 | } | ||
130 | argv += optind; | ||
131 | //argc -= optind; | ||
132 | if (!argv[0]) { | ||
133 | bb_show_usage(); | ||
134 | } | ||
135 | |||
136 | while (*argv) { | ||
137 | const char *source_rpm; | ||
138 | |||
139 | rpm_fd = xopen(*argv++, O_RDONLY); | ||
140 | mytags = rpm_gettags(rpm_fd, &tagcount); | ||
141 | if (!mytags) | ||
142 | bb_error_msg_and_die("error reading rpm header"); | ||
143 | offset = xlseek(rpm_fd, 0, SEEK_CUR); | ||
144 | /* Mimimum is one page */ | ||
145 | map = mmap(0, offset > pagesize ? (offset + offset % pagesize) : pagesize, PROT_READ, MAP_PRIVATE, rpm_fd, 0); | ||
146 | |||
147 | source_rpm = rpm_getstr(TAG_SOURCERPM, 0); | ||
148 | |||
149 | if (func & rpm_install) { | ||
150 | /* Backup any config files */ | ||
151 | loop_through_files(TAG_BASENAMES, fileaction_dobackup); | ||
152 | /* Extact the archive */ | ||
153 | extract_cpio(rpm_fd, source_rpm); | ||
154 | /* Set the correct file uid/gid's */ | ||
155 | loop_through_files(TAG_BASENAMES, fileaction_setowngrp); | ||
156 | } | ||
157 | else if ((func & (rpm_query|rpm_query_package)) == (rpm_query|rpm_query_package)) { | ||
158 | if (!(func & (rpm_query_info|rpm_query_list))) { | ||
159 | /* If just a straight query, just give package name */ | ||
160 | printf("%s-%s-%s\n", rpm_getstr(TAG_NAME, 0), rpm_getstr(TAG_VERSION, 0), rpm_getstr(TAG_RELEASE, 0)); | ||
161 | } | ||
162 | if (func & rpm_query_info) { | ||
163 | /* Do the nice printout */ | ||
164 | time_t bdate_time; | ||
165 | struct tm *bdate_ptm; | ||
166 | char bdatestring[50]; | ||
167 | const char *p; | ||
168 | |||
169 | p = rpm_getstr(TAG_PREFIXS, 0); | ||
170 | if (!p) p = "(not relocateable)"; | ||
171 | printf("Name : %-29sRelocations: %s\n", rpm_getstr(TAG_NAME, 0), p); | ||
172 | p = rpm_getstr(TAG_VENDOR, 0); | ||
173 | if (!p) p = "(none)"; | ||
174 | printf("Version : %-34sVendor: %s\n", rpm_getstr(TAG_VERSION, 0), p); | ||
175 | bdate_time = rpm_getint(TAG_BUILDTIME, 0); | ||
176 | bdate_ptm = localtime(&bdate_time); | ||
177 | strftime(bdatestring, 50, "%a %d %b %Y %T %Z", bdate_ptm); | ||
178 | printf("Release : %-30sBuild Date: %s\n", rpm_getstr(TAG_RELEASE, 0), bdatestring); | ||
179 | printf("Install date: %-30sBuild Host: %s\n", "(not installed)", rpm_getstr(TAG_BUILDHOST, 0)); | ||
180 | printf("Group : %-30sSource RPM: %s\n", rpm_getstr(TAG_GROUP, 0), source_rpm); | ||
181 | printf("Size : %-33dLicense: %s\n", rpm_getint(TAG_SIZE, 0), rpm_getstr(TAG_LICENSE, 0)); | ||
182 | printf("URL : %s\n", rpm_getstr(TAG_URL, 0)); | ||
183 | printf("Summary : %s\n", rpm_getstr(TAG_SUMMARY, 0)); | ||
184 | printf("Description :\n%s\n", rpm_getstr(TAG_DESCRIPTION, 0)); | ||
185 | } | ||
186 | if (func & rpm_query_list) { | ||
187 | int count, it, flags; | ||
188 | count = rpm_getcount(TAG_BASENAMES); | ||
189 | for (it = 0; it < count; it++) { | ||
190 | flags = rpm_getint(TAG_FILEFLAGS, it); | ||
191 | switch (func & (rpm_query_list_doc|rpm_query_list_config)) { | ||
192 | case rpm_query_list_doc: | ||
193 | if (!(flags & RPMFILE_DOC)) continue; | ||
194 | break; | ||
195 | case rpm_query_list_config: | ||
196 | if (!(flags & RPMFILE_CONFIG)) continue; | ||
197 | break; | ||
198 | case rpm_query_list_doc|rpm_query_list_config: | ||
199 | if (!(flags & (RPMFILE_CONFIG|RPMFILE_DOC))) continue; | ||
200 | break; | ||
201 | } | ||
202 | printf("%s%s\n", | ||
203 | rpm_getstr(TAG_DIRNAMES, rpm_getint(TAG_DIRINDEXES, it)), | ||
204 | rpm_getstr(TAG_BASENAMES, it)); | ||
205 | } | ||
206 | } | ||
207 | } | ||
208 | free(mytags); | ||
209 | } | ||
210 | return 0; | ||
211 | } | ||
212 | 89 | ||
213 | static void extract_cpio(int fd, const char *source_rpm) | 90 | static void extract_cpio(int fd, const char *source_rpm) |
214 | { | 91 | { |
@@ -231,8 +108,8 @@ static void extract_cpio(int fd, const char *source_rpm) | |||
231 | /* compat: overwrite existing files. | 108 | /* compat: overwrite existing files. |
232 | * try "rpm -i foo.src.rpm" few times in a row - | 109 | * try "rpm -i foo.src.rpm" few times in a row - |
233 | * standard rpm will not complain. | 110 | * standard rpm will not complain. |
234 | * (TODO? real rpm creates "file;1234" and then renames it) */ | 111 | */ |
235 | | ARCHIVE_UNLINK_OLD; | 112 | | ARCHIVE_REPLACE_VIA_RENAME; |
236 | archive_handle->src_fd = fd; | 113 | archive_handle->src_fd = fd; |
237 | /*archive_handle->offset = 0; - init_handle() did it */ | 114 | /*archive_handle->offset = 0; - init_handle() did it */ |
238 | 115 | ||
@@ -294,7 +171,7 @@ static int bsearch_rpmtag(const void *key, const void *item) | |||
294 | static int rpm_getcount(int tag) | 171 | static int rpm_getcount(int tag) |
295 | { | 172 | { |
296 | rpm_index **found; | 173 | rpm_index **found; |
297 | found = bsearch(&tag, mytags, tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); | 174 | found = bsearch(&tag, G.mytags, G.tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); |
298 | if (!found) | 175 | if (!found) |
299 | return 0; | 176 | return 0; |
300 | return found[0]->count; | 177 | return found[0]->count; |
@@ -303,7 +180,7 @@ static int rpm_getcount(int tag) | |||
303 | static char *rpm_getstr(int tag, int itemindex) | 180 | static char *rpm_getstr(int tag, int itemindex) |
304 | { | 181 | { |
305 | rpm_index **found; | 182 | rpm_index **found; |
306 | found = bsearch(&tag, mytags, tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); | 183 | found = bsearch(&tag, G.mytags, G.tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); |
307 | if (!found || itemindex >= found[0]->count) | 184 | if (!found || itemindex >= found[0]->count) |
308 | return NULL; | 185 | return NULL; |
309 | if (found[0]->type == RPM_STRING_TYPE | 186 | if (found[0]->type == RPM_STRING_TYPE |
@@ -311,7 +188,7 @@ static char *rpm_getstr(int tag, int itemindex) | |||
311 | || found[0]->type == RPM_STRING_ARRAY_TYPE | 188 | || found[0]->type == RPM_STRING_ARRAY_TYPE |
312 | ) { | 189 | ) { |
313 | int n; | 190 | int n; |
314 | char *tmpstr = (char *) map + found[0]->offset; | 191 | char *tmpstr = (char *) G.map + found[0]->offset; |
315 | for (n = 0; n < itemindex; n++) | 192 | for (n = 0; n < itemindex; n++) |
316 | tmpstr = tmpstr + strlen(tmpstr) + 1; | 193 | tmpstr = tmpstr + strlen(tmpstr) + 1; |
317 | return tmpstr; | 194 | return tmpstr; |
@@ -322,32 +199,25 @@ static char *rpm_getstr(int tag, int itemindex) | |||
322 | static int rpm_getint(int tag, int itemindex) | 199 | static int rpm_getint(int tag, int itemindex) |
323 | { | 200 | { |
324 | rpm_index **found; | 201 | rpm_index **found; |
325 | int *tmpint; /* NB: using int8_t* would be easier to code */ | 202 | char *tmpint; |
326 | 203 | ||
327 | /* gcc throws warnings here when sizeof(void*)!=sizeof(int) ... | 204 | /* gcc throws warnings here when sizeof(void*)!=sizeof(int) ... |
328 | * it's ok to ignore it because tag won't be used as a pointer */ | 205 | * it's ok to ignore it because tag won't be used as a pointer */ |
329 | found = bsearch(&tag, mytags, tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); | 206 | found = bsearch(&tag, G.mytags, G.tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); |
330 | if (!found || itemindex >= found[0]->count) | 207 | if (!found || itemindex >= found[0]->count) |
331 | return -1; | 208 | return -1; |
332 | 209 | ||
333 | tmpint = (int *) ((char *) map + found[0]->offset); | 210 | tmpint = (char *) G.map + found[0]->offset; |
334 | |||
335 | if (found[0]->type == RPM_INT32_TYPE) { | 211 | if (found[0]->type == RPM_INT32_TYPE) { |
336 | tmpint = (int *) ((char *) tmpint + itemindex*4); | 212 | tmpint += itemindex*4; |
337 | /*return ntohl(*tmpint);*/ | ||
338 | /* int can be != int32_t */ | ||
339 | return ntohl(*(int32_t*)tmpint); | 213 | return ntohl(*(int32_t*)tmpint); |
340 | } | 214 | } |
341 | if (found[0]->type == RPM_INT16_TYPE) { | 215 | if (found[0]->type == RPM_INT16_TYPE) { |
342 | tmpint = (int *) ((char *) tmpint + itemindex*2); | 216 | tmpint += itemindex*2; |
343 | /* ??? read int, and THEN ntohs() it?? */ | ||
344 | /*return ntohs(*tmpint);*/ | ||
345 | return ntohs(*(int16_t*)tmpint); | 217 | return ntohs(*(int16_t*)tmpint); |
346 | } | 218 | } |
347 | if (found[0]->type == RPM_INT8_TYPE) { | 219 | if (found[0]->type == RPM_INT8_TYPE) { |
348 | tmpint = (int *) ((char *) tmpint + itemindex); | 220 | tmpint += itemindex; |
349 | /* ??? why we don't read byte here??? */ | ||
350 | /*return ntohs(*tmpint);*/ | ||
351 | return *(int8_t*)tmpint; | 221 | return *(int8_t*)tmpint; |
352 | } | 222 | } |
353 | return -1; | 223 | return -1; |
@@ -392,3 +262,134 @@ static void loop_through_files(int filetag, void (*fileaction)(char *filename, i | |||
392 | free(filename); | 262 | free(filename); |
393 | } | 263 | } |
394 | } | 264 | } |
265 | |||
266 | int rpm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
267 | int rpm_main(int argc, char **argv) | ||
268 | { | ||
269 | int opt, func = 0; | ||
270 | const unsigned pagesize = getpagesize(); | ||
271 | |||
272 | while ((opt = getopt(argc, argv, "iqpldc")) != -1) { | ||
273 | switch (opt) { | ||
274 | case 'i': /* First arg: Install mode, with q: Information */ | ||
275 | if (!func) func = rpm_install; | ||
276 | else func |= rpm_query_info; | ||
277 | break; | ||
278 | case 'q': /* First arg: Query mode */ | ||
279 | if (func) bb_show_usage(); | ||
280 | func = rpm_query; | ||
281 | break; | ||
282 | case 'p': /* Query a package */ | ||
283 | func |= rpm_query_package; | ||
284 | break; | ||
285 | case 'l': /* List files in a package */ | ||
286 | func |= rpm_query_list; | ||
287 | break; | ||
288 | case 'd': /* List doc files in a package (implies list) */ | ||
289 | func |= rpm_query_list; | ||
290 | func |= rpm_query_list_doc; | ||
291 | break; | ||
292 | case 'c': /* List config files in a package (implies list) */ | ||
293 | func |= rpm_query_list; | ||
294 | func |= rpm_query_list_config; | ||
295 | break; | ||
296 | default: | ||
297 | bb_show_usage(); | ||
298 | } | ||
299 | } | ||
300 | argv += optind; | ||
301 | //argc -= optind; | ||
302 | if (!argv[0]) { | ||
303 | bb_show_usage(); | ||
304 | } | ||
305 | |||
306 | while (*argv) { | ||
307 | int rpm_fd; | ||
308 | unsigned mapsize; | ||
309 | const char *source_rpm; | ||
310 | |||
311 | rpm_fd = xopen(*argv++, O_RDONLY); | ||
312 | G.mytags = rpm_gettags(rpm_fd, &G.tagcount); | ||
313 | if (!G.mytags) | ||
314 | bb_error_msg_and_die("error reading rpm header"); | ||
315 | mapsize = xlseek(rpm_fd, 0, SEEK_CUR); | ||
316 | mapsize = (mapsize + pagesize) & -(int)pagesize; | ||
317 | /* Some NOMMU systems prefer MAP_PRIVATE over MAP_SHARED */ | ||
318 | G.map = mmap(0, mapsize, PROT_READ, MAP_PRIVATE, rpm_fd, 0); | ||
319 | //FIXME: error check? | ||
320 | |||
321 | source_rpm = rpm_getstr(TAG_SOURCERPM, 0); | ||
322 | |||
323 | if (func & rpm_install) { | ||
324 | /* Backup any config files */ | ||
325 | loop_through_files(TAG_BASENAMES, fileaction_dobackup); | ||
326 | /* Extact the archive */ | ||
327 | extract_cpio(rpm_fd, source_rpm); | ||
328 | /* Set the correct file uid/gid's */ | ||
329 | loop_through_files(TAG_BASENAMES, fileaction_setowngrp); | ||
330 | } | ||
331 | else if ((func & (rpm_query|rpm_query_package)) == (rpm_query|rpm_query_package)) { | ||
332 | if (!(func & (rpm_query_info|rpm_query_list))) { | ||
333 | /* If just a straight query, just give package name */ | ||
334 | printf("%s-%s-%s\n", rpm_getstr(TAG_NAME, 0), rpm_getstr(TAG_VERSION, 0), rpm_getstr(TAG_RELEASE, 0)); | ||
335 | } | ||
336 | if (func & rpm_query_info) { | ||
337 | /* Do the nice printout */ | ||
338 | time_t bdate_time; | ||
339 | struct tm *bdate_ptm; | ||
340 | char bdatestring[50]; | ||
341 | const char *p; | ||
342 | |||
343 | printf("%-12s: %s\n", "Name" , rpm_getstr(TAG_NAME, 0)); | ||
344 | /* TODO compat: add "Epoch" here */ | ||
345 | printf("%-12s: %s\n", "Version" , rpm_getstr(TAG_VERSION, 0)); | ||
346 | printf("%-12s: %s\n", "Release" , rpm_getstr(TAG_RELEASE, 0)); | ||
347 | /* add "Architecture" */ | ||
348 | printf("%-12s: %s\n", "Install Date", "(not installed)"); | ||
349 | printf("%-12s: %s\n", "Group" , rpm_getstr(TAG_GROUP, 0)); | ||
350 | printf("%-12s: %d\n", "Size" , rpm_getint(TAG_SIZE, 0)); | ||
351 | printf("%-12s: %s\n", "License" , rpm_getstr(TAG_LICENSE, 0)); | ||
352 | /* add "Signature" */ | ||
353 | printf("%-12s: %s\n", "Source RPM" , source_rpm ? source_rpm : "(none)"); | ||
354 | bdate_time = rpm_getint(TAG_BUILDTIME, 0); | ||
355 | bdate_ptm = localtime(&bdate_time); | ||
356 | strftime(bdatestring, 50, "%a %d %b %Y %T %Z", bdate_ptm); | ||
357 | printf("%-12s: %s\n", "Build Date" , bdatestring); | ||
358 | printf("%-12s: %s\n", "Build Host" , rpm_getstr(TAG_BUILDHOST, 0)); | ||
359 | p = rpm_getstr(TAG_PREFIXS, 0); | ||
360 | printf("%-12s: %s\n", "Relocations" , p ? p : "(not relocatable)"); | ||
361 | /* add "Packager" */ | ||
362 | p = rpm_getstr(TAG_VENDOR, 0); | ||
363 | printf("%-12s: %s\n", "Vendor" , p ? p : "(none)"); | ||
364 | printf("%-12s: %s\n", "URL" , rpm_getstr(TAG_URL, 0)); | ||
365 | printf("%-12s: %s\n", "Summary" , rpm_getstr(TAG_SUMMARY, 0)); | ||
366 | printf("Description :\n%s\n", rpm_getstr(TAG_DESCRIPTION, 0)); | ||
367 | } | ||
368 | if (func & rpm_query_list) { | ||
369 | int count, it, flags; | ||
370 | count = rpm_getcount(TAG_BASENAMES); | ||
371 | for (it = 0; it < count; it++) { | ||
372 | flags = rpm_getint(TAG_FILEFLAGS, it); | ||
373 | switch (func & (rpm_query_list_doc|rpm_query_list_config)) { | ||
374 | case rpm_query_list_doc: | ||
375 | if (!(flags & RPMFILE_DOC)) continue; | ||
376 | break; | ||
377 | case rpm_query_list_config: | ||
378 | if (!(flags & RPMFILE_CONFIG)) continue; | ||
379 | break; | ||
380 | case rpm_query_list_doc|rpm_query_list_config: | ||
381 | if (!(flags & (RPMFILE_CONFIG|RPMFILE_DOC))) continue; | ||
382 | break; | ||
383 | } | ||
384 | printf("%s%s\n", | ||
385 | rpm_getstr(TAG_DIRNAMES, rpm_getint(TAG_DIRINDEXES, it)), | ||
386 | rpm_getstr(TAG_BASENAMES, it)); | ||
387 | } | ||
388 | } | ||
389 | } | ||
390 | munmap(G.map, mapsize); | ||
391 | free(G.mytags); | ||
392 | close(rpm_fd); | ||
393 | } | ||
394 | return 0; | ||
395 | } | ||
diff --git a/coreutils/Kbuild.src b/coreutils/Kbuild.src index b715b9c47..ec4ef7df2 100644 --- a/coreutils/Kbuild.src +++ b/coreutils/Kbuild.src | |||
@@ -35,7 +35,6 @@ lib-$(CONFIG_EXPAND) += expand.o | |||
35 | lib-$(CONFIG_FALSE) += false.o | 35 | lib-$(CONFIG_FALSE) += false.o |
36 | lib-$(CONFIG_FOLD) += fold.o | 36 | lib-$(CONFIG_FOLD) += fold.o |
37 | lib-$(CONFIG_FSYNC) += fsync.o | 37 | lib-$(CONFIG_FSYNC) += fsync.o |
38 | lib-$(CONFIG_HEAD) += head.o | ||
39 | lib-$(CONFIG_INSTALL) += install.o | 38 | lib-$(CONFIG_INSTALL) += install.o |
40 | #lib-$(CONFIG_LENGTH) += length.o | 39 | #lib-$(CONFIG_LENGTH) += length.o |
41 | lib-$(CONFIG_LN) += ln.o | 40 | lib-$(CONFIG_LN) += ln.o |
@@ -71,7 +70,6 @@ lib-$(CONFIG_STTY) += stty.o | |||
71 | lib-$(CONFIG_SUM) += sum.o | 70 | lib-$(CONFIG_SUM) += sum.o |
72 | lib-$(CONFIG_SYNC) += sync.o | 71 | lib-$(CONFIG_SYNC) += sync.o |
73 | lib-$(CONFIG_TAC) += tac.o | 72 | lib-$(CONFIG_TAC) += tac.o |
74 | lib-$(CONFIG_TAIL) += tail.o | ||
75 | lib-$(CONFIG_TEE) += tee.o | 73 | lib-$(CONFIG_TEE) += tee.o |
76 | lib-$(CONFIG_TRUE) += true.o | 74 | lib-$(CONFIG_TRUE) += true.o |
77 | lib-$(CONFIG_TTY) += tty.o | 75 | lib-$(CONFIG_TTY) += tty.o |
diff --git a/coreutils/head.c b/coreutils/head.c index ec4512765..291e1ce37 100644 --- a/coreutils/head.c +++ b/coreutils/head.c | |||
@@ -11,6 +11,9 @@ | |||
11 | /* BB_AUDIT GNU compatible -c, -q, and -v options in 'fancy' configuration. */ | 11 | /* BB_AUDIT GNU compatible -c, -q, and -v options in 'fancy' configuration. */ |
12 | /* http://www.opengroup.org/onlinepubs/007904975/utilities/head.html */ | 12 | /* http://www.opengroup.org/onlinepubs/007904975/utilities/head.html */ |
13 | 13 | ||
14 | //kbuild:lib-$(CONFIG_HEAD) += head.o | ||
15 | //kbuild:lib-$(CONFIG_HEAD) += head_tail.o | ||
16 | |||
14 | //usage:#define head_trivial_usage | 17 | //usage:#define head_trivial_usage |
15 | //usage: "[OPTIONS] [FILE]..." | 18 | //usage: "[OPTIONS] [FILE]..." |
16 | //usage:#define head_full_usage "\n\n" | 19 | //usage:#define head_full_usage "\n\n" |
@@ -18,7 +21,8 @@ | |||
18 | //usage: "With more than one FILE, precede each with a filename header.\n" | 21 | //usage: "With more than one FILE, precede each with a filename header.\n" |
19 | //usage: "\n -n N[kbm] Print first N lines" | 22 | //usage: "\n -n N[kbm] Print first N lines" |
20 | //usage: IF_FEATURE_FANCY_HEAD( | 23 | //usage: IF_FEATURE_FANCY_HEAD( |
21 | //usage: "\n -c N[kbm] Print first N bytes" | 24 | //usage: "\n -n -N[kbm] Print all except N last lines" |
25 | //usage: "\n -c [-]N[kbm] Print first N bytes" | ||
22 | //usage: "\n -q Never print headers" | 26 | //usage: "\n -q Never print headers" |
23 | //usage: "\n -v Always print headers" | 27 | //usage: "\n -v Always print headers" |
24 | //usage: ) | 28 | //usage: ) |
@@ -31,9 +35,114 @@ | |||
31 | //usage: "daemon:x:1:1:daemon:/usr/sbin:/bin/sh\n" | 35 | //usage: "daemon:x:1:1:daemon:/usr/sbin:/bin/sh\n" |
32 | 36 | ||
33 | #include "libbb.h" | 37 | #include "libbb.h" |
38 | #include "head_tail.h" | ||
34 | 39 | ||
35 | /* This is a NOEXEC applet. Be very careful! */ | 40 | /* This is a NOEXEC applet. Be very careful! */ |
36 | 41 | ||
42 | #if !ENABLE_FEATURE_FANCY_HEAD | ||
43 | # define print_first_N(fp,count,bytes) print_first_N(fp,count) | ||
44 | #endif | ||
45 | static void | ||
46 | print_first_N(FILE *fp, unsigned long count, bool count_bytes) | ||
47 | { | ||
48 | #if !ENABLE_FEATURE_FANCY_HEAD | ||
49 | const int count_bytes = 0; | ||
50 | #endif | ||
51 | while (count) { | ||
52 | int c = getc(fp); | ||
53 | if (c == EOF) | ||
54 | break; | ||
55 | if (count_bytes || (c == '\n')) | ||
56 | --count; | ||
57 | putchar(c); | ||
58 | } | ||
59 | } | ||
60 | |||
61 | #if ENABLE_FEATURE_FANCY_HEAD | ||
62 | static void | ||
63 | print_except_N_last_bytes(FILE *fp, unsigned count) | ||
64 | { | ||
65 | unsigned char *circle = xmalloc(++count); | ||
66 | unsigned head = 0; | ||
67 | for(;;) { | ||
68 | int c; | ||
69 | c = getc(fp); | ||
70 | if (c == EOF) | ||
71 | goto ret; | ||
72 | circle[head++] = c; | ||
73 | if (head == count) | ||
74 | break; | ||
75 | } | ||
76 | for (;;) { | ||
77 | int c; | ||
78 | if (head == count) | ||
79 | head = 0; | ||
80 | putchar(circle[head]); | ||
81 | c = getc(fp); | ||
82 | if (c == EOF) | ||
83 | goto ret; | ||
84 | circle[head] = c; | ||
85 | head++; | ||
86 | } | ||
87 | ret: | ||
88 | free(circle); | ||
89 | } | ||
90 | |||
91 | static void | ||
92 | print_except_N_last_lines(FILE *fp, unsigned count) | ||
93 | { | ||
94 | char **circle = xzalloc((++count) * sizeof(circle[0])); | ||
95 | unsigned head = 0; | ||
96 | for(;;) { | ||
97 | char *c; | ||
98 | c = xmalloc_fgets(fp); | ||
99 | if (!c) | ||
100 | goto ret; | ||
101 | circle[head++] = c; | ||
102 | if (head == count) | ||
103 | break; | ||
104 | } | ||
105 | for (;;) { | ||
106 | char *c; | ||
107 | if (head == count) | ||
108 | head = 0; | ||
109 | fputs(circle[head], stdout); | ||
110 | c = xmalloc_fgets(fp); | ||
111 | if (!c) | ||
112 | goto ret; | ||
113 | free(circle[head]); | ||
114 | circle[head++] = c; | ||
115 | } | ||
116 | ret: | ||
117 | head = 0; | ||
118 | for(;;) { | ||
119 | free(circle[head++]); | ||
120 | if (head == count) | ||
121 | break; | ||
122 | } | ||
123 | free(circle); | ||
124 | } | ||
125 | #else | ||
126 | /* Must never be called */ | ||
127 | void print_except_N_last_bytes(FILE *fp, unsigned count); | ||
128 | void print_except_N_last_lines(FILE *fp, unsigned count); | ||
129 | #endif | ||
130 | |||
131 | #if !ENABLE_FEATURE_FANCY_HEAD | ||
132 | # define eat_num(negative_N,p) eat_num(p) | ||
133 | #endif | ||
134 | static unsigned long | ||
135 | eat_num(bool *negative_N, const char *p) | ||
136 | { | ||
137 | #if ENABLE_FEATURE_FANCY_HEAD | ||
138 | if (*p == '-') { | ||
139 | *negative_N = 1; | ||
140 | p++; | ||
141 | } | ||
142 | #endif | ||
143 | return xatoul_sfx(p, head_tail_suffixes); | ||
144 | } | ||
145 | |||
37 | static const char head_opts[] ALIGN1 = | 146 | static const char head_opts[] ALIGN1 = |
38 | "n:" | 147 | "n:" |
39 | #if ENABLE_FEATURE_FANCY_HEAD | 148 | #if ENABLE_FEATURE_FANCY_HEAD |
@@ -41,29 +150,25 @@ static const char head_opts[] ALIGN1 = | |||
41 | #endif | 150 | #endif |
42 | ; | 151 | ; |
43 | 152 | ||
44 | static const struct suffix_mult head_suffixes[] = { | ||
45 | { "b", 512 }, | ||
46 | { "k", 1024 }, | ||
47 | { "m", 1024*1024 }, | ||
48 | { "", 0 } | ||
49 | }; | ||
50 | |||
51 | #define header_fmt_str "\n==> %s <==\n" | 153 | #define header_fmt_str "\n==> %s <==\n" |
52 | 154 | ||
53 | int head_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 155 | int head_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
54 | int head_main(int argc, char **argv) | 156 | int head_main(int argc, char **argv) |
55 | { | 157 | { |
56 | unsigned long count = 10; | 158 | unsigned long count = 10; |
57 | unsigned long i; | ||
58 | #if ENABLE_FEATURE_FANCY_HEAD | 159 | #if ENABLE_FEATURE_FANCY_HEAD |
59 | int count_bytes = 0; | ||
60 | int header_threshhold = 1; | 160 | int header_threshhold = 1; |
161 | bool count_bytes = 0; | ||
162 | bool negative_N = 0; | ||
163 | #else | ||
164 | # define header_threshhold 1 | ||
165 | # define count_bytes 0 | ||
166 | # define negative_N 0 | ||
61 | #endif | 167 | #endif |
62 | FILE *fp; | 168 | FILE *fp; |
63 | const char *fmt; | 169 | const char *fmt; |
64 | char *p; | 170 | char *p; |
65 | int opt; | 171 | int opt; |
66 | int c; | ||
67 | int retval = EXIT_SUCCESS; | 172 | int retval = EXIT_SUCCESS; |
68 | 173 | ||
69 | #if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_HEAD | 174 | #if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_HEAD |
@@ -73,7 +178,7 @@ int head_main(int argc, char **argv) | |||
73 | ) { | 178 | ) { |
74 | --argc; | 179 | --argc; |
75 | ++argv; | 180 | ++argv; |
76 | p = (*argv) + 1; | 181 | p = argv[0] + 1; |
77 | goto GET_COUNT; | 182 | goto GET_COUNT; |
78 | } | 183 | } |
79 | #endif | 184 | #endif |
@@ -97,7 +202,7 @@ int head_main(int argc, char **argv) | |||
97 | #if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_HEAD | 202 | #if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_HEAD |
98 | GET_COUNT: | 203 | GET_COUNT: |
99 | #endif | 204 | #endif |
100 | count = xatoul_sfx(p, head_suffixes); | 205 | count = eat_num(&negative_N, p); |
101 | break; | 206 | break; |
102 | default: | 207 | default: |
103 | bb_show_usage(); | 208 | bb_show_usage(); |
@@ -110,19 +215,17 @@ int head_main(int argc, char **argv) | |||
110 | *--argv = (char*)"-"; | 215 | *--argv = (char*)"-"; |
111 | 216 | ||
112 | fmt = header_fmt_str + 1; | 217 | fmt = header_fmt_str + 1; |
113 | #if ENABLE_FEATURE_FANCY_HEAD | ||
114 | if (argc <= header_threshhold) { | 218 | if (argc <= header_threshhold) { |
219 | #if ENABLE_FEATURE_FANCY_HEAD | ||
115 | header_threshhold = 0; | 220 | header_threshhold = 0; |
116 | } | ||
117 | #else | 221 | #else |
118 | if (argc <= 1) { | ||
119 | fmt += 11; /* "" */ | 222 | fmt += 11; /* "" */ |
120 | } | ||
121 | /* Now define some things here to avoid #ifdefs in the code below. | ||
122 | * These should optimize out of the if conditions below. */ | ||
123 | #define header_threshhold 1 | ||
124 | #define count_bytes 0 | ||
125 | #endif | 223 | #endif |
224 | } | ||
225 | if (negative_N) { | ||
226 | if (count >= INT_MAX / sizeof(char*)) | ||
227 | bb_error_msg("count is too big: %lu", count); | ||
228 | } | ||
126 | 229 | ||
127 | do { | 230 | do { |
128 | fp = fopen_or_warn_stdin(*argv); | 231 | fp = fopen_or_warn_stdin(*argv); |
@@ -133,18 +236,20 @@ int head_main(int argc, char **argv) | |||
133 | if (header_threshhold) { | 236 | if (header_threshhold) { |
134 | printf(fmt, *argv); | 237 | printf(fmt, *argv); |
135 | } | 238 | } |
136 | i = count; | 239 | if (negative_N) { |
137 | while (i && ((c = getc(fp)) != EOF)) { | 240 | if (count_bytes) { |
138 | if (count_bytes || (c == '\n')) { | 241 | print_except_N_last_bytes(fp, count); |
139 | --i; | 242 | } else { |
243 | print_except_N_last_lines(fp, count); | ||
140 | } | 244 | } |
141 | putchar(c); | 245 | } else { |
246 | print_first_N(fp, count, count_bytes); | ||
142 | } | 247 | } |
248 | die_if_ferror_stdout(); | ||
143 | if (fclose_if_not_stdin(fp)) { | 249 | if (fclose_if_not_stdin(fp)) { |
144 | bb_simple_perror_msg(*argv); | 250 | bb_simple_perror_msg(*argv); |
145 | retval = EXIT_FAILURE; | 251 | retval = EXIT_FAILURE; |
146 | } | 252 | } |
147 | die_if_ferror_stdout(); | ||
148 | } else { | 253 | } else { |
149 | retval = EXIT_FAILURE; | 254 | retval = EXIT_FAILURE; |
150 | } | 255 | } |
diff --git a/coreutils/head_tail.c b/coreutils/head_tail.c new file mode 100644 index 000000000..1658c0d1b --- /dev/null +++ b/coreutils/head_tail.c | |||
@@ -0,0 +1,14 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2013 Denys Vlasenko | ||
3 | * | ||
4 | * Licensed under GPLv2, see file LICENSE in this source tree. | ||
5 | */ | ||
6 | #include "libbb.h" | ||
7 | #include "head_tail.h" | ||
8 | |||
9 | const struct suffix_mult head_tail_suffixes[] = { | ||
10 | { "b", 512 }, | ||
11 | { "k", 1024 }, | ||
12 | { "m", 1024*1024 }, | ||
13 | { "", 0 } | ||
14 | }; | ||
diff --git a/coreutils/head_tail.h b/coreutils/head_tail.h new file mode 100644 index 000000000..df19e41e0 --- /dev/null +++ b/coreutils/head_tail.h | |||
@@ -0,0 +1,6 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2013 Denys Vlasenko | ||
3 | * | ||
4 | * Licensed under GPLv2, see file LICENSE in this source tree. | ||
5 | */ | ||
6 | extern const struct suffix_mult head_tail_suffixes[]; | ||
diff --git a/coreutils/hostid.c b/coreutils/hostid.c index 5c1a4e086..e5b1f5188 100644 --- a/coreutils/hostid.c +++ b/coreutils/hostid.c | |||
@@ -36,7 +36,8 @@ int hostid_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
36 | bb_show_usage(); | 36 | bb_show_usage(); |
37 | } | 37 | } |
38 | 38 | ||
39 | printf("%08lx\n", gethostid()); | 39 | /* POSIX says gethostid returns a "32-bit identifier" */ |
40 | printf("%08x\n", (unsigned)(uint32_t)gethostid()); | ||
40 | 41 | ||
41 | return fflush_all(); | 42 | return fflush_all(); |
42 | } | 43 | } |
diff --git a/coreutils/id.c b/coreutils/id.c index 1f20b755e..1f3e1c4c2 100644 --- a/coreutils/id.c +++ b/coreutils/id.c | |||
@@ -64,12 +64,10 @@ | |||
64 | /* This is a NOEXEC applet. Be very careful! */ | 64 | /* This is a NOEXEC applet. Be very careful! */ |
65 | 65 | ||
66 | #if !ENABLE_USE_BB_PWD_GRP | 66 | #if !ENABLE_USE_BB_PWD_GRP |
67 | #if defined(__UCLIBC_MAJOR__) && (__UCLIBC_MAJOR__ == 0) | 67 | #if defined(__UCLIBC__) && UCLIBC_VERSION < KERNEL_VERSION(0, 9, 30) |
68 | #if (__UCLIBC_MINOR__ < 9) || (__UCLIBC_MINOR__ == 9 && __UCLIBC_SUBLEVEL__ < 30) | ||
69 | #error "Sorry, you need at least uClibc version 0.9.30 for id applet to build" | 68 | #error "Sorry, you need at least uClibc version 0.9.30 for id applet to build" |
70 | #endif | 69 | #endif |
71 | #endif | 70 | #endif |
72 | #endif | ||
73 | 71 | ||
74 | enum { | 72 | enum { |
75 | PRINT_REAL = (1 << 0), | 73 | PRINT_REAL = (1 << 0), |
diff --git a/coreutils/readlink.c b/coreutils/readlink.c index f7ad791ec..d73ef4ddb 100644 --- a/coreutils/readlink.c +++ b/coreutils/readlink.c | |||
@@ -39,7 +39,10 @@ | |||
39 | * -q, --quiet, -s, --silent suppress most error messages | 39 | * -q, --quiet, -s, --silent suppress most error messages |
40 | * -v, --verbose report error messages | 40 | * -v, --verbose report error messages |
41 | * | 41 | * |
42 | * bbox supports: -f -n -v (fully), -q -s (accepts but ignores) | 42 | * bbox supports: -f (partially) -n -v (fully), -q -s (accepts but ignores) |
43 | * Note: we export the -f flag, but our -f behaves like coreutils' -e. | ||
44 | * Unfortunately, there isn't a C lib function we can leverage to get this | ||
45 | * behavior which means we'd have to implement the full stack ourselves :(. | ||
43 | */ | 46 | */ |
44 | 47 | ||
45 | int readlink_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 48 | int readlink_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
diff --git a/coreutils/tail.c b/coreutils/tail.c index b376ec863..19fd8f695 100644 --- a/coreutils/tail.c +++ b/coreutils/tail.c | |||
@@ -24,6 +24,9 @@ | |||
24 | * 7) lseek attempted when count==0 even if arg was +0 (from top) | 24 | * 7) lseek attempted when count==0 even if arg was +0 (from top) |
25 | */ | 25 | */ |
26 | 26 | ||
27 | //kbuild:lib-$(CONFIG_TAIL) += tail.o | ||
28 | //kbuild:lib-$(CONFIG_TAIL) += head_tail.o | ||
29 | |||
27 | //usage:#define tail_trivial_usage | 30 | //usage:#define tail_trivial_usage |
28 | //usage: "[OPTIONS] [FILE]..." | 31 | //usage: "[OPTIONS] [FILE]..." |
29 | //usage:#define tail_full_usage "\n\n" | 32 | //usage:#define tail_full_usage "\n\n" |
@@ -34,14 +37,13 @@ | |||
34 | //usage: "\n -s SECONDS Wait SECONDS between reads with -f" | 37 | //usage: "\n -s SECONDS Wait SECONDS between reads with -f" |
35 | //usage: ) | 38 | //usage: ) |
36 | //usage: "\n -n N[kbm] Print last N lines" | 39 | //usage: "\n -n N[kbm] Print last N lines" |
40 | //usage: "\n -n +N[kbm] Start on Nth line and print the rest" | ||
37 | //usage: IF_FEATURE_FANCY_TAIL( | 41 | //usage: IF_FEATURE_FANCY_TAIL( |
38 | //usage: "\n -c N[kbm] Print last N bytes" | 42 | //usage: "\n -c [+]N[kbm] Print last N bytes" |
39 | //usage: "\n -q Never print headers" | 43 | //usage: "\n -q Never print headers" |
40 | //usage: "\n -v Always print headers" | 44 | //usage: "\n -v Always print headers" |
41 | //usage: "\n" | 45 | //usage: "\n" |
42 | //usage: "\nN may be suffixed by k (x1024), b (x512), or m (x1024^2)." | 46 | //usage: "\nN may be suffixed by k (x1024), b (x512), or m (x1024^2)." |
43 | //usage: "\nIf N starts with a '+', output begins with the Nth item from the start" | ||
44 | //usage: "\nof each file, not from the end." | ||
45 | //usage: ) | 47 | //usage: ) |
46 | //usage: | 48 | //usage: |
47 | //usage:#define tail_example_usage | 49 | //usage:#define tail_example_usage |
@@ -49,13 +51,7 @@ | |||
49 | //usage: "nameserver 10.0.0.1\n" | 51 | //usage: "nameserver 10.0.0.1\n" |
50 | 52 | ||
51 | #include "libbb.h" | 53 | #include "libbb.h" |
52 | 54 | #include "head_tail.h" | |
53 | static const struct suffix_mult tail_suffixes[] = { | ||
54 | { "b", 512 }, | ||
55 | { "k", 1024 }, | ||
56 | { "m", 1024*1024 }, | ||
57 | { "", 0 } | ||
58 | }; | ||
59 | 55 | ||
60 | struct globals { | 56 | struct globals { |
61 | bool from_top; | 57 | bool from_top; |
@@ -102,7 +98,7 @@ static unsigned eat_num(const char *p) | |||
102 | p++; | 98 | p++; |
103 | G.from_top = 1; | 99 | G.from_top = 1; |
104 | } | 100 | } |
105 | return xatou_sfx(p, tail_suffixes); | 101 | return xatou_sfx(p, head_tail_suffixes); |
106 | } | 102 | } |
107 | 103 | ||
108 | int tail_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 104 | int tail_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
diff --git a/debianutils/run_parts.c b/debianutils/run_parts.c index 005b30420..2c2b032be 100644 --- a/debianutils/run_parts.c +++ b/debianutils/run_parts.c | |||
@@ -21,24 +21,24 @@ | |||
21 | * taken from debian-utils. I've only removed the long options and the | 21 | * taken from debian-utils. I've only removed the long options and the |
22 | * report mode. As the original run-parts support only long options, I've | 22 | * report mode. As the original run-parts support only long options, I've |
23 | * broken compatibility because the BusyBox policy doesn't allow them. | 23 | * broken compatibility because the BusyBox policy doesn't allow them. |
24 | * The supported options are: | ||
25 | * -t test. Print the name of the files to be executed, without | ||
26 | * execute them. | ||
27 | * -a ARG argument. Pass ARG as an argument the program executed. It can | ||
28 | * be repeated to pass multiple arguments. | ||
29 | * -u MASK umask. Set the umask of the program executed to MASK. | ||
30 | */ | 24 | */ |
31 | 25 | ||
32 | //usage:#define run_parts_trivial_usage | 26 | //usage:#define run_parts_trivial_usage |
33 | //usage: "[-t"IF_FEATURE_RUN_PARTS_FANCY("l")"] [-a ARG]... [-u MASK] DIRECTORY" | 27 | //usage: "[-a ARG]... [-u UMASK] " |
28 | //usage: IF_FEATURE_RUN_PARTS_LONG_OPTIONS("[--reverse] [--test] [--exit-on-error] "IF_FEATURE_RUN_PARTS_FANCY("[--list] ")) | ||
29 | //usage: "DIRECTORY" | ||
34 | //usage:#define run_parts_full_usage "\n\n" | 30 | //usage:#define run_parts_full_usage "\n\n" |
35 | //usage: "Run a bunch of scripts in DIRECTORY\n" | 31 | //usage: "Run a bunch of scripts in DIRECTORY\n" |
36 | //usage: "\n -t Dry run" | 32 | //usage: "\n -a ARG Pass ARG as argument to scripts" |
33 | //usage: "\n -u UMASK Set UMASK before running scripts" | ||
34 | //usage: IF_FEATURE_RUN_PARTS_LONG_OPTIONS( | ||
35 | //usage: "\n --reverse Reverse execution order" | ||
36 | //usage: "\n --test Dry run" | ||
37 | //usage: "\n --exit-on-error Exit if a script exits with non-zero" | ||
37 | //usage: IF_FEATURE_RUN_PARTS_FANCY( | 38 | //usage: IF_FEATURE_RUN_PARTS_FANCY( |
38 | //usage: "\n -l Print names of matching files even if they are not executable" | 39 | //usage: "\n --list Print names of matching files even if they are not executable" |
40 | //usage: ) | ||
39 | //usage: ) | 41 | //usage: ) |
40 | //usage: "\n -a ARG Pass ARG as argument to programs" | ||
41 | //usage: "\n -u MASK Set umask to MASK before running programs" | ||
42 | //usage: | 42 | //usage: |
43 | //usage:#define run_parts_example_usage | 43 | //usage:#define run_parts_example_usage |
44 | //usage: "$ run-parts -a start /etc/init.d\n" | 44 | //usage: "$ run-parts -a start /etc/init.d\n" |
@@ -70,19 +70,15 @@ struct globals { | |||
70 | enum { NUM_CMD = (COMMON_BUFSIZE - sizeof(G)) / sizeof(cmd[0]) - 1 }; | 70 | enum { NUM_CMD = (COMMON_BUFSIZE - sizeof(G)) / sizeof(cmd[0]) - 1 }; |
71 | 71 | ||
72 | enum { | 72 | enum { |
73 | OPT_r = (1 << 0), | 73 | OPT_a = (1 << 0), |
74 | OPT_a = (1 << 1), | 74 | OPT_u = (1 << 1), |
75 | OPT_u = (1 << 2), | 75 | OPT_r = (1 << 2) * ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS, |
76 | OPT_t = (1 << 3), | 76 | OPT_t = (1 << 3) * ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS, |
77 | OPT_l = (1 << 4) * ENABLE_FEATURE_RUN_PARTS_FANCY, | 77 | OPT_e = (1 << 4) * ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS, |
78 | OPT_l = (1 << 5) * ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS | ||
79 | * ENABLE_FEATURE_RUN_PARTS_FANCY, | ||
78 | }; | 80 | }; |
79 | 81 | ||
80 | #if ENABLE_FEATURE_RUN_PARTS_FANCY | ||
81 | #define list_mode (option_mask32 & OPT_l) | ||
82 | #else | ||
83 | #define list_mode 0 | ||
84 | #endif | ||
85 | |||
86 | /* Is this a valid filename (upper/lower alpha, digits, | 82 | /* Is this a valid filename (upper/lower alpha, digits, |
87 | * underscores, and hyphens only?) | 83 | * underscores, and hyphens only?) |
88 | */ | 84 | */ |
@@ -110,7 +106,7 @@ static int FAST_FUNC act(const char *file, struct stat *statbuf, void *args UNUS | |||
110 | if (depth == 2 | 106 | if (depth == 2 |
111 | && ( !(statbuf->st_mode & (S_IFREG | S_IFLNK)) | 107 | && ( !(statbuf->st_mode & (S_IFREG | S_IFLNK)) |
112 | || invalid_name(file) | 108 | || invalid_name(file) |
113 | || (!list_mode && access(file, X_OK) != 0)) | 109 | || (!(option_mask32 & OPT_l) && access(file, X_OK) != 0)) |
114 | ) { | 110 | ) { |
115 | return SKIP; | 111 | return SKIP; |
116 | } | 112 | } |
@@ -126,11 +122,12 @@ static int FAST_FUNC act(const char *file, struct stat *statbuf, void *args UNUS | |||
126 | static const char runparts_longopts[] ALIGN1 = | 122 | static const char runparts_longopts[] ALIGN1 = |
127 | "arg\0" Required_argument "a" | 123 | "arg\0" Required_argument "a" |
128 | "umask\0" Required_argument "u" | 124 | "umask\0" Required_argument "u" |
129 | "test\0" No_argument "t" | ||
130 | #if ENABLE_FEATURE_RUN_PARTS_FANCY | ||
131 | "list\0" No_argument "l" | ||
132 | "reverse\0" No_argument "r" | ||
133 | //TODO: "verbose\0" No_argument "v" | 125 | //TODO: "verbose\0" No_argument "v" |
126 | "reverse\0" No_argument "\xf0" | ||
127 | "test\0" No_argument "\xf1" | ||
128 | "exit-on-error\0" No_argument "\xf2" | ||
129 | #if ENABLE_FEATURE_RUN_PARTS_FANCY | ||
130 | "list\0" No_argument "\xf3" | ||
134 | #endif | 131 | #endif |
135 | ; | 132 | ; |
136 | #endif | 133 | #endif |
@@ -150,7 +147,7 @@ int run_parts_main(int argc UNUSED_PARAM, char **argv) | |||
150 | #endif | 147 | #endif |
151 | /* We require exactly one argument: the directory name */ | 148 | /* We require exactly one argument: the directory name */ |
152 | opt_complementary = "=1:a::"; | 149 | opt_complementary = "=1:a::"; |
153 | getopt32(argv, "ra:u:t"IF_FEATURE_RUN_PARTS_FANCY("l"), &arg_list, &umask_p); | 150 | getopt32(argv, "a:u:", &arg_list, &umask_p); |
154 | 151 | ||
155 | umask(xstrtou_range(umask_p, 8, 0, 07777)); | 152 | umask(xstrtou_range(umask_p, 8, 0, 07777)); |
156 | 153 | ||
@@ -193,6 +190,9 @@ int run_parts_main(int argc UNUSED_PARAM, char **argv) | |||
193 | bb_perror_msg("can't execute '%s'", name); | 190 | bb_perror_msg("can't execute '%s'", name); |
194 | else /* ret > 0 */ | 191 | else /* ret > 0 */ |
195 | bb_error_msg("%s exited with code %d", name, ret & 0xff); | 192 | bb_error_msg("%s exited with code %d", name, ret & 0xff); |
193 | |||
194 | if (option_mask32 & OPT_e) | ||
195 | xfunc_die(); | ||
196 | } | 196 | } |
197 | 197 | ||
198 | return n; | 198 | return n; |
diff --git a/docs/mdev.txt b/docs/mdev.txt index 61f93c9df..b24025f7b 100644 --- a/docs/mdev.txt +++ b/docs/mdev.txt | |||
@@ -51,9 +51,9 @@ device nodes if your system needs something more than the default root/root | |||
51 | 660 permissions. | 51 | 660 permissions. |
52 | 52 | ||
53 | The file has the format: | 53 | The file has the format: |
54 | [-]<device regex> <uid>:<gid> <permissions> | 54 | [-][envmatch]<device regex> <uid>:<gid> <permissions> |
55 | or | 55 | or |
56 | @<maj[,min1[-min2]]> <uid>:<gid> <permissions> | 56 | [envmatch]@<maj[,min1[-min2]]> <uid>:<gid> <permissions> |
57 | or | 57 | or |
58 | $envvar=<regex> <uid>:<gid> <permissions> | 58 | $envvar=<regex> <uid>:<gid> <permissions> |
59 | 59 | ||
diff --git a/editors/awk.c b/editors/awk.c index 3224788c0..0b573a065 100644 --- a/editors/awk.c +++ b/editors/awk.c | |||
@@ -2661,7 +2661,8 @@ static var *evaluate(node *op, var *res) | |||
2661 | var *vbeg, *v; | 2661 | var *vbeg, *v; |
2662 | const char *sv_progname; | 2662 | const char *sv_progname; |
2663 | 2663 | ||
2664 | if (!op->r.f->body.first) | 2664 | /* The body might be empty, still has to eval the args */ |
2665 | if (!op->r.n->info) | ||
2665 | syntax_error(EMSG_UNDEF_FUNC); | 2666 | syntax_error(EMSG_UNDEF_FUNC); |
2666 | 2667 | ||
2667 | vbeg = v = nvalloc(op->r.f->nargs + 1); | 2668 | vbeg = v = nvalloc(op->r.f->nargs + 1); |
diff --git a/editors/vi.c b/editors/vi.c index 1fc66b931..63b984ea6 100644 --- a/editors/vi.c +++ b/editors/vi.c | |||
@@ -478,6 +478,7 @@ static void flash(int); // flash the terminal screen | |||
478 | static void show_status_line(void); // put a message on the bottom line | 478 | static void show_status_line(void); // put a message on the bottom line |
479 | static void status_line(const char *, ...); // print to status buf | 479 | static void status_line(const char *, ...); // print to status buf |
480 | static void status_line_bold(const char *, ...); | 480 | static void status_line_bold(const char *, ...); |
481 | static void status_line_bold_errno(const char *fn); | ||
481 | static void not_implemented(const char *); // display "Not implemented" message | 482 | static void not_implemented(const char *); // display "Not implemented" message |
482 | static int format_edit_status(void); // format file status on status line | 483 | static int format_edit_status(void); // format file status on status line |
483 | static void redraw(int); // force a full screen refresh | 484 | static void redraw(int); // force a full screen refresh |
@@ -1321,7 +1322,7 @@ static void colon(char *buf) | |||
1321 | } | 1322 | } |
1322 | if (l < 0) { | 1323 | if (l < 0) { |
1323 | if (l == -1) | 1324 | if (l == -1) |
1324 | status_line_bold("'%s' %s", fn, strerror(errno)); | 1325 | status_line_bold_errno(fn); |
1325 | } else { | 1326 | } else { |
1326 | status_line("'%s' %dL, %dC", fn, li, l); | 1327 | status_line("'%s' %dL, %dC", fn, li, l); |
1327 | if (q == text && r == end - 1 && l == ch) { | 1328 | if (q == text && r == end - 1 && l == ch) { |
@@ -2512,7 +2513,7 @@ static int file_insert(const char *fn, char *p, int update_ro_status) | |||
2512 | 2513 | ||
2513 | /* Validate file */ | 2514 | /* Validate file */ |
2514 | if (stat(fn, &statbuf) < 0) { | 2515 | if (stat(fn, &statbuf) < 0) { |
2515 | status_line_bold("'%s' %s", fn, strerror(errno)); | 2516 | status_line_bold_errno(fn); |
2516 | goto fi0; | 2517 | goto fi0; |
2517 | } | 2518 | } |
2518 | if (!S_ISREG(statbuf.st_mode)) { | 2519 | if (!S_ISREG(statbuf.st_mode)) { |
@@ -2528,18 +2529,18 @@ static int file_insert(const char *fn, char *p, int update_ro_status) | |||
2528 | // read file to buffer | 2529 | // read file to buffer |
2529 | fd = open(fn, O_RDONLY); | 2530 | fd = open(fn, O_RDONLY); |
2530 | if (fd < 0) { | 2531 | if (fd < 0) { |
2531 | status_line_bold("'%s' %s", fn, strerror(errno)); | 2532 | status_line_bold_errno(fn); |
2532 | goto fi0; | 2533 | goto fi0; |
2533 | } | 2534 | } |
2534 | size = (statbuf.st_size < INT_MAX ? (int)statbuf.st_size : INT_MAX); | 2535 | size = (statbuf.st_size < INT_MAX ? (int)statbuf.st_size : INT_MAX); |
2535 | p += text_hole_make(p, size); | 2536 | p += text_hole_make(p, size); |
2536 | cnt = safe_read(fd, p, size); | 2537 | cnt = safe_read(fd, p, size); |
2537 | if (cnt < 0) { | 2538 | if (cnt < 0) { |
2538 | status_line_bold("'%s' %s", fn, strerror(errno)); | 2539 | status_line_bold_errno(fn); |
2539 | p = text_hole_delete(p, p + size - 1); // un-do buffer insert | 2540 | p = text_hole_delete(p, p + size - 1); // un-do buffer insert |
2540 | } else if (cnt < size) { | 2541 | } else if (cnt < size) { |
2541 | // There was a partial read, shrink unused space text[] | 2542 | // There was a partial read, shrink unused space text[] |
2542 | p = text_hole_delete(p + cnt, p + (size - cnt) - 1); // un-do buffer insert | 2543 | p = text_hole_delete(p + cnt, p + size - 1); // un-do buffer insert |
2543 | status_line_bold("can't read '%s'", fn); | 2544 | status_line_bold("can't read '%s'", fn); |
2544 | } | 2545 | } |
2545 | if (cnt >= size) | 2546 | if (cnt >= size) |
@@ -2726,6 +2727,11 @@ static void status_line_bold(const char *format, ...) | |||
2726 | have_status_msg = 1 + sizeof(ESC_BOLD_TEXT) + sizeof(ESC_NORM_TEXT) - 2; | 2727 | have_status_msg = 1 + sizeof(ESC_BOLD_TEXT) + sizeof(ESC_NORM_TEXT) - 2; |
2727 | } | 2728 | } |
2728 | 2729 | ||
2730 | static void status_line_bold_errno(const char *fn) | ||
2731 | { | ||
2732 | status_line_bold("'%s' %s", fn, strerror(errno)); | ||
2733 | } | ||
2734 | |||
2729 | // format status buffer | 2735 | // format status buffer |
2730 | static void status_line(const char *format, ...) | 2736 | static void status_line(const char *format, ...) |
2731 | { | 2737 | { |
diff --git a/examples/mdev_fat.conf b/examples/mdev_fat.conf index ceba3a797..bceddb2d7 100644 --- a/examples/mdev_fat.conf +++ b/examples/mdev_fat.conf | |||
@@ -7,9 +7,9 @@ | |||
7 | # instead of the default 0:0 660. | 7 | # instead of the default 0:0 660. |
8 | # | 8 | # |
9 | # Syntax: | 9 | # Syntax: |
10 | # [-]devicename_regex user:group mode [=path]|[>path]|[!] [@|$|*cmd args...] | 10 | # [-][ENVVAR=regex;]...devicename_regex user:group mode [=path]|[>path]|[!] [@|$|*cmd args...] |
11 | # [-]$ENVVAR=regex user:group mode [=path]|[>path]|[!] [@|$|*cmd args...] | 11 | # [-][ENVVAR=regex;]...@maj,min[-min2] user:group mode [=path]|[>path]|[!] [@|$|*cmd args...] |
12 | # [-]@maj,min[-min2] user:group mode [=path]|[>path]|[!] [@|$|*cmd args...] | 12 | # [-]$ENVVAR=regex user:group mode [=path]|[>path]|[!] [@|$|*cmd args...] |
13 | # | 13 | # |
14 | # [-]: do not stop on this match, continue reading mdev.conf | 14 | # [-]: do not stop on this match, continue reading mdev.conf |
15 | # =: move, >: move and create a symlink | 15 | # =: move, >: move and create a symlink |
@@ -53,6 +53,7 @@ sr[0-9]* root:cdrom 660 @ln -sf $MDEV cdrom | |||
53 | fd[0-9]* root:floppy 660 | 53 | fd[0-9]* root:floppy 660 |
54 | 54 | ||
55 | # net devices | 55 | # net devices |
56 | SUBSYSTEM=net;.* root:root 600 @nameif | ||
56 | tun[0-9]* root:root 600 =net/ | 57 | tun[0-9]* root:root 600 =net/ |
57 | tap[0-9]* root:root 600 =net/ | 58 | tap[0-9]* root:root 600 =net/ |
58 | 59 | ||
diff --git a/examples/udhcp/simple.script b/examples/udhcp/simple.script index 40ee73822..2a917eb6c 100755 --- a/examples/udhcp/simple.script +++ b/examples/udhcp/simple.script | |||
@@ -29,18 +29,23 @@ case "$1" in | |||
29 | metric=0 | 29 | metric=0 |
30 | for i in $router ; do | 30 | for i in $router ; do |
31 | echo "Adding router $i" | 31 | echo "Adding router $i" |
32 | route add default gw $i dev $interface metric $((metric++)) | 32 | route add default gw $i dev $interface metric $metric |
33 | : $(( metric += 1 )) | ||
33 | done | 34 | done |
34 | fi | 35 | fi |
35 | 36 | ||
36 | echo "Recreating $RESOLV_CONF" | 37 | echo "Recreating $RESOLV_CONF" |
37 | echo -n > $RESOLV_CONF-$$ | 38 | # If the file is a symlink somewhere (like /etc/resolv.conf |
38 | [ -n "$domain" ] && echo "search $domain" >> $RESOLV_CONF-$$ | 39 | # pointing to /run/resolv.conf), make sure things work. |
40 | realconf=$(readlink -f "$RESOLV_CONF" 2>/dev/null || echo "$RESOLV_CONF") | ||
41 | tmpfile="$realconf-$$" | ||
42 | > "$tmpfile" | ||
43 | [ -n "$domain" ] && echo "search $domain" >> "$tmpfile" | ||
39 | for i in $dns ; do | 44 | for i in $dns ; do |
40 | echo " Adding DNS server $i" | 45 | echo " Adding DNS server $i" |
41 | echo "nameserver $i" >> $RESOLV_CONF-$$ | 46 | echo "nameserver $i" >> "$tmpfile" |
42 | done | 47 | done |
43 | mv $RESOLV_CONF-$$ $RESOLV_CONF | 48 | mv "$tmpfile" "$realconf" |
44 | ;; | 49 | ;; |
45 | esac | 50 | esac |
46 | 51 | ||
diff --git a/include/bb_archive.h b/include/bb_archive.h index a7a2a1135..b82cfd83c 100644 --- a/include/bb_archive.h +++ b/include/bb_archive.h | |||
@@ -122,6 +122,9 @@ typedef struct archive_handle_t { | |||
122 | #define ARCHIVE_NUMERIC_OWNER (1 << 7) | 122 | #define ARCHIVE_NUMERIC_OWNER (1 << 7) |
123 | #define ARCHIVE_O_TRUNC (1 << 8) | 123 | #define ARCHIVE_O_TRUNC (1 << 8) |
124 | #define ARCHIVE_REMEMBER_NAMES (1 << 9) | 124 | #define ARCHIVE_REMEMBER_NAMES (1 << 9) |
125 | #if ENABLE_RPM | ||
126 | #define ARCHIVE_REPLACE_VIA_RENAME (1 << 10) | ||
127 | #endif | ||
125 | 128 | ||
126 | 129 | ||
127 | /* POSIX tar Header Block, from POSIX 1003.1-1990 */ | 130 | /* POSIX tar Header Block, from POSIX 1003.1-1990 */ |
diff --git a/include/libbb.h b/include/libbb.h index c5ff51398..15a5a6623 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -399,6 +399,7 @@ char *bb_get_last_path_component_nostrip(const char *path) FAST_FUNC; | |||
399 | const char *bb_basename(const char *name) FAST_FUNC; | 399 | const char *bb_basename(const char *name) FAST_FUNC; |
400 | /* NB: can violate const-ness (similarly to strchr) */ | 400 | /* NB: can violate const-ness (similarly to strchr) */ |
401 | char *last_char_is(const char *s, int c) FAST_FUNC; | 401 | char *last_char_is(const char *s, int c) FAST_FUNC; |
402 | const char* endofname(const char *name) FAST_FUNC; | ||
402 | 403 | ||
403 | void ndelay_on(int fd) FAST_FUNC; | 404 | void ndelay_on(int fd) FAST_FUNC; |
404 | void ndelay_off(int fd) FAST_FUNC; | 405 | void ndelay_off(int fd) FAST_FUNC; |
diff --git a/include/platform.h b/include/platform.h index b3eee55ee..fa4267b4b 100644 --- a/include/platform.h +++ b/include/platform.h | |||
@@ -245,7 +245,7 @@ typedef uint32_t bb__aliased_uint32_t FIX_ALIASING; | |||
245 | # define move_from_unaligned32(v, u32p) (memcpy(&(v), (u32p), 4)) | 245 | # define move_from_unaligned32(v, u32p) (memcpy(&(v), (u32p), 4)) |
246 | # define move_to_unaligned16(u16p, v) do { \ | 246 | # define move_to_unaligned16(u16p, v) do { \ |
247 | uint16_t __t = (v); \ | 247 | uint16_t __t = (v); \ |
248 | memcpy((u16p), &__t, 4); \ | 248 | memcpy((u16p), &__t, 2); \ |
249 | } while (0) | 249 | } while (0) |
250 | # define move_to_unaligned32(u32p, v) do { \ | 250 | # define move_to_unaligned32(u32p, v) do { \ |
251 | uint32_t __t = (v); \ | 251 | uint32_t __t = (v); \ |
@@ -280,6 +280,12 @@ typedef unsigned smalluint; | |||
280 | 280 | ||
281 | #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) | 281 | #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) |
282 | 282 | ||
283 | #ifdef __UCLIBC__ | ||
284 | # define UCLIBC_VERSION KERNEL_VERSION(__UCLIBC_MAJOR__, __UCLIBC_MINOR__, __UCLIBC_SUBLEVEL__) | ||
285 | #else | ||
286 | # define UCLIBC_VERSION 0 | ||
287 | #endif | ||
288 | |||
283 | 289 | ||
284 | /* ---- Miscellaneous --------------------------------------- */ | 290 | /* ---- Miscellaneous --------------------------------------- */ |
285 | 291 | ||
@@ -322,8 +328,9 @@ typedef unsigned smalluint; | |||
322 | * for a mmu-less system. | 328 | * for a mmu-less system. |
323 | */ | 329 | */ |
324 | #if ENABLE_NOMMU || \ | 330 | #if ENABLE_NOMMU || \ |
325 | (defined __UCLIBC__ && __UCLIBC_MAJOR__ >= 0 && __UCLIBC_MINOR__ >= 9 && \ | 331 | (defined __UCLIBC__ && \ |
326 | __UCLIBC_SUBLEVEL__ > 28 && !defined __ARCH_USE_MMU__) | 332 | UCLIBC_VERSION > KERNEL_VERSION(0, 9, 28) && \ |
333 | !defined __ARCH_USE_MMU__) | ||
327 | # define BB_MMU 0 | 334 | # define BB_MMU 0 |
328 | # define USE_FOR_NOMMU(...) __VA_ARGS__ | 335 | # define USE_FOR_NOMMU(...) __VA_ARGS__ |
329 | # define USE_FOR_MMU(...) | 336 | # define USE_FOR_MMU(...) |
@@ -390,13 +397,8 @@ typedef unsigned smalluint; | |||
390 | #define HAVE_NET_ETHERNET_H 1 | 397 | #define HAVE_NET_ETHERNET_H 1 |
391 | #define HAVE_SYS_STATFS_H 1 | 398 | #define HAVE_SYS_STATFS_H 1 |
392 | 399 | ||
393 | #if defined(__UCLIBC_MAJOR__) | 400 | #if defined(__UCLIBC__) && UCLIBC_VERSION < KERNEL_VERSION(0, 9, 32) |
394 | # if __UCLIBC_MAJOR__ == 0 \ | 401 | # undef HAVE_STRVERSCMP |
395 | && ( __UCLIBC_MINOR__ < 9 \ | ||
396 | || (__UCLIBC_MINOR__ == 9 && __UCLIBC_SUBLEVEL__ < 32) \ | ||
397 | ) | ||
398 | # undef HAVE_STRVERSCMP | ||
399 | # endif | ||
400 | #endif | 402 | #endif |
401 | 403 | ||
402 | #if defined(__dietlibc__) | 404 | #if defined(__dietlibc__) |
diff --git a/libbb/appletlib.c b/libbb/appletlib.c index fb06ab9a5..f0df4e080 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c | |||
@@ -752,7 +752,7 @@ void FAST_FUNC run_applet_no_and_exit(int applet_no, char **argv) | |||
752 | //TODO: just compare applet_no with APPLET_NO_test | 752 | //TODO: just compare applet_no with APPLET_NO_test |
753 | if (!ENABLE_TEST || strcmp(applet_name, "test") != 0) { | 753 | if (!ENABLE_TEST || strcmp(applet_name, "test") != 0) { |
754 | /* If you want "foo --help" to return 0: */ | 754 | /* If you want "foo --help" to return 0: */ |
755 | /*xfunc_error_retval = 0;*/ | 755 | xfunc_error_retval = 0; |
756 | bb_show_usage(); | 756 | bb_show_usage(); |
757 | } | 757 | } |
758 | } | 758 | } |
diff --git a/libbb/endofname.c b/libbb/endofname.c new file mode 100644 index 000000000..305f0932b --- /dev/null +++ b/libbb/endofname.c | |||
@@ -0,0 +1,26 @@ | |||
1 | /* | ||
2 | * Utility routines. | ||
3 | * | ||
4 | * Copyright (C) 2013 Denys Vlasenko | ||
5 | * | ||
6 | * Licensed under GPLv2, see file LICENSE in this source tree. | ||
7 | */ | ||
8 | |||
9 | //kbuild:lib-y += endofname.o | ||
10 | |||
11 | #include "libbb.h" | ||
12 | |||
13 | #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) | ||
14 | #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) | ||
15 | |||
16 | const char* FAST_FUNC | ||
17 | endofname(const char *name) | ||
18 | { | ||
19 | if (!is_name(*name)) | ||
20 | return name; | ||
21 | while (*++name) { | ||
22 | if (!is_in_name(*name)) | ||
23 | break; | ||
24 | } | ||
25 | return name; | ||
26 | } | ||
diff --git a/libbb/lineedit.c b/libbb/lineedit.c index 8a276d941..09e203159 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c | |||
@@ -187,6 +187,7 @@ extern struct lineedit_statics *const lineedit_ptr_to_statics; | |||
187 | cmdedit_termw = 80; \ | 187 | cmdedit_termw = 80; \ |
188 | IF_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines = 1;) \ | 188 | IF_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines = 1;) \ |
189 | IF_USERNAME_OR_HOMEDIR(home_pwd_buf = (char*)null_str;) \ | 189 | IF_USERNAME_OR_HOMEDIR(home_pwd_buf = (char*)null_str;) \ |
190 | IF_FEATURE_EDITING_VI(delptr = delbuf;) \ | ||
190 | } while (0) | 191 | } while (0) |
191 | 192 | ||
192 | static void deinit_S(void) | 193 | static void deinit_S(void) |
diff --git a/libbb/platform.c b/libbb/platform.c index 2bf34f5bc..19734517b 100644 --- a/libbb/platform.c +++ b/libbb/platform.c | |||
@@ -28,14 +28,16 @@ int FAST_FUNC vasprintf(char **string_ptr, const char *format, va_list p) | |||
28 | r = vsnprintf(buf, 128, format, p); | 28 | r = vsnprintf(buf, 128, format, p); |
29 | va_end(p); | 29 | va_end(p); |
30 | 30 | ||
31 | /* Note: can't use xstrdup/xmalloc, they call vasprintf (us) on failure! */ | ||
32 | |||
31 | if (r < 128) { | 33 | if (r < 128) { |
32 | va_end(p2); | 34 | va_end(p2); |
33 | *string_ptr = xstrdup(buf); | 35 | *string_ptr = strdup(buf); |
34 | return r; | 36 | return (*string_ptr ? r : -1); |
35 | } | 37 | } |
36 | 38 | ||
37 | *string_ptr = xmalloc(r+1); | 39 | *string_ptr = malloc(r+1); |
38 | r = vsnprintf(*string_ptr, r+1, format, p2); | 40 | r = (*string_ptr ? vsnprintf(*string_ptr, r+1, format, p2) : -1); |
39 | va_end(p2); | 41 | va_end(p2); |
40 | 42 | ||
41 | return r; | 43 | return r; |
diff --git a/libbb/xreadlink.c b/libbb/xreadlink.c index f2faa6d7a..bc1d0e665 100644 --- a/libbb/xreadlink.c +++ b/libbb/xreadlink.c | |||
@@ -102,7 +102,8 @@ char* FAST_FUNC xmalloc_readlink_or_warn(const char *path) | |||
102 | 102 | ||
103 | char* FAST_FUNC xmalloc_realpath(const char *path) | 103 | char* FAST_FUNC xmalloc_realpath(const char *path) |
104 | { | 104 | { |
105 | #if defined(__GLIBC__) && !defined(__UCLIBC__) | 105 | #if defined(__GLIBC__) || \ |
106 | (defined(__UCLIBC__) && UCLIBC_VERSION >= KERNEL_VERSION(0, 9, 31)) | ||
106 | /* glibc provides a non-standard extension */ | 107 | /* glibc provides a non-standard extension */ |
107 | /* new: POSIX.1-2008 specifies this behavior as well */ | 108 | /* new: POSIX.1-2008 specifies this behavior as well */ |
108 | return realpath(path, NULL); | 109 | return realpath(path, NULL); |
diff --git a/mailutils/sendmail.c b/mailutils/sendmail.c index c426e9d85..b5aa1d17b 100644 --- a/mailutils/sendmail.c +++ b/mailutils/sendmail.c | |||
@@ -92,25 +92,73 @@ static int smtp_check(const char *fmt, int code) | |||
92 | // strip argument of bad chars | 92 | // strip argument of bad chars |
93 | static char *sane_address(char *str) | 93 | static char *sane_address(char *str) |
94 | { | 94 | { |
95 | char *s = str; | 95 | char *s; |
96 | char *p = s; | 96 | |
97 | trim(str); | ||
98 | s = str; | ||
97 | while (*s) { | 99 | while (*s) { |
98 | if (isalnum(*s) || '_' == *s || '-' == *s || '.' == *s || '@' == *s) { | 100 | if (!isalnum(*s) && !strchr("_-.@", *s)) { |
99 | *p++ = *s; | 101 | bb_error_msg("bad address '%s'", str); |
102 | /* returning "": */ | ||
103 | str[0] = '\0'; | ||
104 | return str; | ||
100 | } | 105 | } |
101 | s++; | 106 | s++; |
102 | } | 107 | } |
103 | *p = '\0'; | ||
104 | return str; | 108 | return str; |
105 | } | 109 | } |
106 | 110 | ||
111 | // check for an address inside angle brackets, if not found fall back to normal | ||
112 | static char *angle_address(char *str) | ||
113 | { | ||
114 | char *s, *e; | ||
115 | |||
116 | trim(str); | ||
117 | e = last_char_is(str, '>'); | ||
118 | if (e) { | ||
119 | s = strrchr(str, '<'); | ||
120 | if (s) { | ||
121 | *e = '\0'; | ||
122 | str = s + 1; | ||
123 | } | ||
124 | } | ||
125 | return sane_address(str); | ||
126 | } | ||
127 | |||
107 | static void rcptto(const char *s) | 128 | static void rcptto(const char *s) |
108 | { | 129 | { |
130 | if (!*s) | ||
131 | return; | ||
109 | // N.B. we don't die if recipient is rejected, for the other recipients may be accepted | 132 | // N.B. we don't die if recipient is rejected, for the other recipients may be accepted |
110 | if (250 != smtp_checkp("RCPT TO:<%s>", s, -1)) | 133 | if (250 != smtp_checkp("RCPT TO:<%s>", s, -1)) |
111 | bb_error_msg("Bad recipient: <%s>", s); | 134 | bb_error_msg("Bad recipient: <%s>", s); |
112 | } | 135 | } |
113 | 136 | ||
137 | // send to a list of comma separated addresses | ||
138 | static void rcptto_list(const char *list) | ||
139 | { | ||
140 | char *str = xstrdup(list); | ||
141 | char *s = str; | ||
142 | char prev = 0; | ||
143 | int in_quote = 0; | ||
144 | |||
145 | while (*s) { | ||
146 | char ch = *s++; | ||
147 | |||
148 | if (ch == '"' && prev != '\\') { | ||
149 | in_quote = !in_quote; | ||
150 | } else if (!in_quote && ch == ',') { | ||
151 | s[-1] = '\0'; | ||
152 | rcptto(angle_address(str)); | ||
153 | str = s; | ||
154 | } | ||
155 | prev = ch; | ||
156 | } | ||
157 | if (prev != ',') | ||
158 | rcptto(angle_address(str)); | ||
159 | free(str); | ||
160 | } | ||
161 | |||
114 | int sendmail_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 162 | int sendmail_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
115 | int sendmail_main(int argc UNUSED_PARAM, char **argv) | 163 | int sendmail_main(int argc UNUSED_PARAM, char **argv) |
116 | { | 164 | { |
@@ -121,6 +169,13 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) | |||
121 | char *host = sane_address(safe_gethostname()); | 169 | char *host = sane_address(safe_gethostname()); |
122 | unsigned nheaders = 0; | 170 | unsigned nheaders = 0; |
123 | int code; | 171 | int code; |
172 | enum { | ||
173 | HDR_OTHER = 0, | ||
174 | HDR_TOCC, | ||
175 | HDR_BCC, | ||
176 | } last_hdr = 0; | ||
177 | int check_hdr; | ||
178 | int has_to = 0; | ||
124 | 179 | ||
125 | enum { | 180 | enum { |
126 | //--- standard options | 181 | //--- standard options |
@@ -282,23 +337,36 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) | |||
282 | 337 | ||
283 | // analyze headers | 338 | // analyze headers |
284 | // To: or Cc: headers add recipients | 339 | // To: or Cc: headers add recipients |
340 | check_hdr = (0 == strncasecmp("To:", s, 3)); | ||
341 | has_to |= check_hdr; | ||
285 | if (opts & OPT_t) { | 342 | if (opts & OPT_t) { |
286 | if (0 == strncasecmp("To:", s, 3) || 0 == strncasecmp("Bcc:" + 1, s, 3)) { | 343 | if (check_hdr || 0 == strncasecmp("Bcc:" + 1, s, 3)) { |
287 | rcptto(sane_address(s+3)); | 344 | rcptto_list(s+3); |
345 | last_hdr = HDR_TOCC; | ||
288 | goto addheader; | 346 | goto addheader; |
289 | } | 347 | } |
290 | // Bcc: header adds blind copy (hidden) recipient | 348 | // Bcc: header adds blind copy (hidden) recipient |
291 | if (0 == strncasecmp("Bcc:", s, 4)) { | 349 | if (0 == strncasecmp("Bcc:", s, 4)) { |
292 | rcptto(sane_address(s+4)); | 350 | rcptto_list(s+4); |
293 | free(s); | 351 | free(s); |
352 | last_hdr = HDR_BCC; | ||
294 | continue; // N.B. Bcc: vanishes from headers! | 353 | continue; // N.B. Bcc: vanishes from headers! |
295 | } | 354 | } |
296 | } | 355 | } |
297 | if (strchr(s, ':') || (list && isspace(s[0]))) { | 356 | check_hdr = (list && isspace(s[0])); |
357 | if (strchr(s, ':') || check_hdr) { | ||
298 | // other headers go verbatim | 358 | // other headers go verbatim |
299 | // N.B. RFC2822 2.2.3 "Long Header Fields" allows for headers to occupy several lines. | 359 | // N.B. RFC2822 2.2.3 "Long Header Fields" allows for headers to occupy several lines. |
300 | // Continuation is denoted by prefixing additional lines with whitespace(s). | 360 | // Continuation is denoted by prefixing additional lines with whitespace(s). |
301 | // Thanks (stefan.seyfried at googlemail.com) for pointing this out. | 361 | // Thanks (stefan.seyfried at googlemail.com) for pointing this out. |
362 | if (check_hdr && last_hdr != HDR_OTHER) { | ||
363 | rcptto_list(s+1); | ||
364 | if (last_hdr == HDR_BCC) | ||
365 | continue; | ||
366 | // N.B. Bcc: vanishes from headers! | ||
367 | } else { | ||
368 | last_hdr = HDR_OTHER; | ||
369 | } | ||
302 | addheader: | 370 | addheader: |
303 | // N.B. we allow MAX_HEADERS generic headers at most to prevent attacks | 371 | // N.B. we allow MAX_HEADERS generic headers at most to prevent attacks |
304 | if (MAX_HEADERS && ++nheaders >= MAX_HEADERS) | 372 | if (MAX_HEADERS && ++nheaders >= MAX_HEADERS) |
@@ -309,12 +377,27 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) | |||
309 | // so stop "analyze headers" mode | 377 | // so stop "analyze headers" mode |
310 | reenter: | 378 | reenter: |
311 | // put recipients specified on cmdline | 379 | // put recipients specified on cmdline |
380 | check_hdr = 1; | ||
312 | while (*argv) { | 381 | while (*argv) { |
313 | char *t = sane_address(*argv); | 382 | char *t = sane_address(*argv); |
314 | rcptto(t); | 383 | rcptto(t); |
315 | //if (MAX_HEADERS && ++nheaders >= MAX_HEADERS) | 384 | //if (MAX_HEADERS && ++nheaders >= MAX_HEADERS) |
316 | // goto bail; | 385 | // goto bail; |
317 | llist_add_to_end(&list, xasprintf("To: %s", t)); | 386 | if (!has_to) { |
387 | const char *hdr; | ||
388 | |||
389 | if (check_hdr && argv[1]) | ||
390 | hdr = "To: %s,"; | ||
391 | else if (check_hdr) | ||
392 | hdr = "To: %s"; | ||
393 | else if (argv[1]) | ||
394 | hdr = "To: %s," + 3; | ||
395 | else | ||
396 | hdr = "To: %s" + 3; | ||
397 | llist_add_to_end(&list, | ||
398 | xasprintf(hdr, t)); | ||
399 | check_hdr = 0; | ||
400 | } | ||
318 | argv++; | 401 | argv++; |
319 | } | 402 | } |
320 | // enter "put message" mode | 403 | // enter "put message" mode |
diff --git a/miscutils/flash_eraseall.c b/miscutils/flash_eraseall.c index 0598371d5..bf9b739a1 100644 --- a/miscutils/flash_eraseall.c +++ b/miscutils/flash_eraseall.c | |||
@@ -11,10 +11,11 @@ | |||
11 | */ | 11 | */ |
12 | 12 | ||
13 | //usage:#define flash_eraseall_trivial_usage | 13 | //usage:#define flash_eraseall_trivial_usage |
14 | //usage: "[-jq] MTD_DEVICE" | 14 | //usage: "[-jNq] MTD_DEVICE" |
15 | //usage:#define flash_eraseall_full_usage "\n\n" | 15 | //usage:#define flash_eraseall_full_usage "\n\n" |
16 | //usage: "Erase an MTD device\n" | 16 | //usage: "Erase an MTD device\n" |
17 | //usage: "\n -j Format the device for jffs2" | 17 | //usage: "\n -j Format the device for jffs2" |
18 | //usage: "\n -N Don't skip bad blocks" | ||
18 | //usage: "\n -q Don't display progress messages" | 19 | //usage: "\n -q Don't display progress messages" |
19 | 20 | ||
20 | #include "libbb.h" | 21 | #include "libbb.h" |
@@ -22,9 +23,9 @@ | |||
22 | #include <linux/jffs2.h> | 23 | #include <linux/jffs2.h> |
23 | 24 | ||
24 | #define OPTION_J (1 << 0) | 25 | #define OPTION_J (1 << 0) |
25 | #define OPTION_Q (1 << 1) | 26 | #define OPTION_N (1 << 1) |
26 | #define IS_NAND (1 << 2) | 27 | #define OPTION_Q (1 << 2) |
27 | #define BBTEST (1 << 3) | 28 | #define IS_NAND (1 << 3) |
28 | 29 | ||
29 | /* mtd/jffs2-user.h used to have this atrocity: | 30 | /* mtd/jffs2-user.h used to have this atrocity: |
30 | extern int target_endian; | 31 | extern int target_endian; |
@@ -71,7 +72,7 @@ int flash_eraseall_main(int argc UNUSED_PARAM, char **argv) | |||
71 | char *mtd_name; | 72 | char *mtd_name; |
72 | 73 | ||
73 | opt_complementary = "=1"; | 74 | opt_complementary = "=1"; |
74 | flags = BBTEST | getopt32(argv, "jq"); | 75 | flags = getopt32(argv, "jNq"); |
75 | 76 | ||
76 | mtd_name = argv[optind]; | 77 | mtd_name = argv[optind]; |
77 | fd = xopen(mtd_name, O_RDWR); | 78 | fd = xopen(mtd_name, O_RDWR); |
@@ -139,7 +140,7 @@ int flash_eraseall_main(int argc UNUSED_PARAM, char **argv) | |||
139 | 140 | ||
140 | for (erase.start = 0; erase.start < meminfo.size; | 141 | for (erase.start = 0; erase.start < meminfo.size; |
141 | erase.start += meminfo.erasesize) { | 142 | erase.start += meminfo.erasesize) { |
142 | if (flags & BBTEST) { | 143 | if (!(flags & OPTION_N)) { |
143 | int ret; | 144 | int ret; |
144 | loff_t offset = erase.start; | 145 | loff_t offset = erase.start; |
145 | 146 | ||
@@ -154,7 +155,7 @@ int flash_eraseall_main(int argc UNUSED_PARAM, char **argv) | |||
154 | * types e.g. NOR | 155 | * types e.g. NOR |
155 | */ | 156 | */ |
156 | if (errno == EOPNOTSUPP) { | 157 | if (errno == EOPNOTSUPP) { |
157 | flags &= ~BBTEST; | 158 | flags |= OPTION_N; |
158 | if (flags & IS_NAND) | 159 | if (flags & IS_NAND) |
159 | bb_error_msg_and_die("bad block check not available"); | 160 | bb_error_msg_and_die("bad block check not available"); |
160 | } else { | 161 | } else { |
diff --git a/miscutils/nandwrite.c b/miscutils/nandwrite.c index 5908ac773..e3f9b565d 100644 --- a/miscutils/nandwrite.c +++ b/miscutils/nandwrite.c | |||
@@ -23,7 +23,7 @@ | |||
23 | //config: Dump the content of raw NAND chip | 23 | //config: Dump the content of raw NAND chip |
24 | 24 | ||
25 | //applet:IF_NANDWRITE(APPLET(nandwrite, BB_DIR_USR_SBIN, BB_SUID_DROP)) | 25 | //applet:IF_NANDWRITE(APPLET(nandwrite, BB_DIR_USR_SBIN, BB_SUID_DROP)) |
26 | //applet:IF_NANDWRITE(APPLET_ODDNAME(nanddump, nandwrite, BB_DIR_USR_SBIN, BB_SUID_DROP, nanddump)) | 26 | //applet:IF_NANDDUMP(APPLET_ODDNAME(nanddump, nandwrite, BB_DIR_USR_SBIN, BB_SUID_DROP, nanddump)) |
27 | 27 | ||
28 | //kbuild:lib-$(CONFIG_NANDWRITE) += nandwrite.o | 28 | //kbuild:lib-$(CONFIG_NANDWRITE) += nandwrite.o |
29 | //kbuild:lib-$(CONFIG_NANDDUMP) += nandwrite.o | 29 | //kbuild:lib-$(CONFIG_NANDDUMP) += nandwrite.o |
@@ -31,14 +31,14 @@ | |||
31 | //usage:#define nandwrite_trivial_usage | 31 | //usage:#define nandwrite_trivial_usage |
32 | //usage: "[-p] [-s ADDR] MTD_DEVICE [FILE]" | 32 | //usage: "[-p] [-s ADDR] MTD_DEVICE [FILE]" |
33 | //usage:#define nandwrite_full_usage "\n\n" | 33 | //usage:#define nandwrite_full_usage "\n\n" |
34 | //usage: "Write to the specified MTD device\n" | 34 | //usage: "Write to MTD_DEVICE\n" |
35 | //usage: "\n -p Pad to page size" | 35 | //usage: "\n -p Pad to page size" |
36 | //usage: "\n -s ADDR Start address" | 36 | //usage: "\n -s ADDR Start address" |
37 | 37 | ||
38 | //usage:#define nanddump_trivial_usage | 38 | //usage:#define nanddump_trivial_usage |
39 | //usage: "[-o] [-b] [-s ADDR] [-f FILE] MTD_DEVICE" | 39 | //usage: "[-o] [-b] [-s ADDR] [-l LEN] [-f FILE] MTD_DEVICE" |
40 | //usage:#define nanddump_full_usage "\n\n" | 40 | //usage:#define nanddump_full_usage "\n\n" |
41 | //usage: "Dump the specified MTD device\n" | 41 | //usage: "Dump MTD_DEVICE\n" |
42 | //usage: "\n -o Dump oob data" | 42 | //usage: "\n -o Dump oob data" |
43 | //usage: "\n -b Omit bad block from the dump" | 43 | //usage: "\n -b Omit bad block from the dump" |
44 | //usage: "\n -s ADDR Start address" | 44 | //usage: "\n -s ADDR Start address" |
diff --git a/networking/ether-wake.c b/networking/ether-wake.c index bf09cd529..2d389ea30 100644 --- a/networking/ether-wake.c +++ b/networking/ether-wake.c | |||
@@ -121,10 +121,7 @@ static void get_dest_addr(const char *hostid, struct ether_addr *eaddr) | |||
121 | eap = ether_aton_r(hostid, eaddr); | 121 | eap = ether_aton_r(hostid, eaddr); |
122 | if (eap) { | 122 | if (eap) { |
123 | bb_debug_msg("The target station address is %s\n\n", ether_ntoa(eap)); | 123 | bb_debug_msg("The target station address is %s\n\n", ether_ntoa(eap)); |
124 | #if !defined(__UCLIBC_MAJOR__) \ | 124 | #if !defined(__UCLIBC__) || UCLIBC_VERSION >= KERNEL_VERSION(0, 9, 30) |
125 | || __UCLIBC_MAJOR__ > 0 \ | ||
126 | || __UCLIBC_MINOR__ > 9 \ | ||
127 | || (__UCLIBC_MINOR__ == 9 && __UCLIBC_SUBLEVEL__ >= 30) | ||
128 | } else if (ether_hostton(hostid, eaddr) == 0) { | 125 | } else if (ether_hostton(hostid, eaddr) == 0) { |
129 | bb_debug_msg("Station address for hostname %s is %s\n\n", hostid, ether_ntoa(eaddr)); | 126 | bb_debug_msg("Station address for hostname %s is %s\n\n", hostid, ether_ntoa(eaddr)); |
130 | #endif | 127 | #endif |
diff --git a/networking/ifplugd.c b/networking/ifplugd.c index 86586f0fe..3cdc2c9d2 100644 --- a/networking/ifplugd.c +++ b/networking/ifplugd.c | |||
@@ -556,7 +556,8 @@ int ifplugd_main(int argc UNUSED_PARAM, char **argv) | |||
556 | 556 | ||
557 | if (opts & FLAG_KILL) { | 557 | if (opts & FLAG_KILL) { |
558 | if (pid_from_pidfile > 0) | 558 | if (pid_from_pidfile > 0) |
559 | kill(pid_from_pidfile, SIGQUIT); | 559 | /* Upstream tool use SIGINT for -k */ |
560 | kill(pid_from_pidfile, SIGINT); | ||
560 | return EXIT_SUCCESS; | 561 | return EXIT_SUCCESS; |
561 | } | 562 | } |
562 | 563 | ||
diff --git a/networking/ifupdown.c b/networking/ifupdown.c index 818048284..0f0857cb4 100644 --- a/networking/ifupdown.c +++ b/networking/ifupdown.c | |||
@@ -743,7 +743,7 @@ static const struct method_t *get_method(const struct address_family_t *af, char | |||
743 | return NULL; | 743 | return NULL; |
744 | } | 744 | } |
745 | 745 | ||
746 | static struct interfaces_file_t *read_interfaces(const char *filename) | 746 | static struct interfaces_file_t *read_interfaces(const char *filename, struct interfaces_file_t *defn) |
747 | { | 747 | { |
748 | /* Let's try to be compatible. | 748 | /* Let's try to be compatible. |
749 | * | 749 | * |
@@ -758,19 +758,25 @@ static struct interfaces_file_t *read_interfaces(const char *filename) | |||
758 | * be ignored. Blank lines are ignored. Lines may be indented freely. | 758 | * be ignored. Blank lines are ignored. Lines may be indented freely. |
759 | * A "\" character at the very end of the line indicates the next line | 759 | * A "\" character at the very end of the line indicates the next line |
760 | * should be treated as a continuation of the current one. | 760 | * should be treated as a continuation of the current one. |
761 | * | ||
762 | * Lines beginning with "source" are used to include stanzas from | ||
763 | * other files, so configuration can be split into many files. | ||
764 | * The word "source" is followed by the path of file to be sourced. | ||
761 | */ | 765 | */ |
762 | #if ENABLE_FEATURE_IFUPDOWN_MAPPING | 766 | #if ENABLE_FEATURE_IFUPDOWN_MAPPING |
763 | struct mapping_defn_t *currmap = NULL; | 767 | struct mapping_defn_t *currmap = NULL; |
764 | #endif | 768 | #endif |
765 | struct interface_defn_t *currif = NULL; | 769 | struct interface_defn_t *currif = NULL; |
766 | struct interfaces_file_t *defn; | ||
767 | FILE *f; | 770 | FILE *f; |
768 | char *buf; | 771 | char *buf; |
769 | char *first_word; | 772 | char *first_word; |
770 | char *rest_of_line; | 773 | char *rest_of_line; |
771 | enum { NONE, IFACE, MAPPING } currently_processing = NONE; | 774 | enum { NONE, IFACE, MAPPING } currently_processing = NONE; |
772 | 775 | ||
773 | defn = xzalloc(sizeof(*defn)); | 776 | if (!defn) |
777 | defn = xzalloc(sizeof(*defn)); | ||
778 | |||
779 | debug_noise("reading %s file:\n", filename); | ||
774 | f = xfopen_for_read(filename); | 780 | f = xfopen_for_read(filename); |
775 | 781 | ||
776 | while ((buf = xmalloc_fgetline(f)) != NULL) { | 782 | while ((buf = xmalloc_fgetline(f)) != NULL) { |
@@ -881,6 +887,8 @@ static struct interfaces_file_t *read_interfaces(const char *filename) | |||
881 | debug_noise("\nauto %s\n", first_word); | 887 | debug_noise("\nauto %s\n", first_word); |
882 | } | 888 | } |
883 | currently_processing = NONE; | 889 | currently_processing = NONE; |
890 | } else if (strcmp(first_word, "source") == 0) { | ||
891 | read_interfaces(next_word(&rest_of_line), defn); | ||
884 | } else { | 892 | } else { |
885 | switch (currently_processing) { | 893 | switch (currently_processing) { |
886 | case IFACE: | 894 | case IFACE: |
@@ -934,6 +942,7 @@ static struct interfaces_file_t *read_interfaces(const char *filename) | |||
934 | bb_error_msg_and_die("%s: I/O error", filename); | 942 | bb_error_msg_and_die("%s: I/O error", filename); |
935 | } | 943 | } |
936 | fclose(f); | 944 | fclose(f); |
945 | debug_noise("\ndone reading %s\n\n", filename); | ||
937 | 946 | ||
938 | return defn; | 947 | return defn; |
939 | } | 948 | } |
@@ -1199,9 +1208,7 @@ int ifupdown_main(int argc UNUSED_PARAM, char **argv) | |||
1199 | if (!DO_ALL) bb_show_usage(); | 1208 | if (!DO_ALL) bb_show_usage(); |
1200 | } | 1209 | } |
1201 | 1210 | ||
1202 | debug_noise("reading %s file:\n", interfaces); | 1211 | defn = read_interfaces(interfaces, NULL); |
1203 | defn = read_interfaces(interfaces); | ||
1204 | debug_noise("\ndone reading %s\n\n", interfaces); | ||
1205 | 1212 | ||
1206 | /* Create a list of interfaces to work on */ | 1213 | /* Create a list of interfaces to work on */ |
1207 | if (DO_ALL) { | 1214 | if (DO_ALL) { |
diff --git a/networking/nameif.c b/networking/nameif.c index 5d7e8f9a4..9a8846dc0 100644 --- a/networking/nameif.c +++ b/networking/nameif.c | |||
@@ -292,12 +292,11 @@ int nameif_main(int argc UNUSED_PARAM, char **argv) | |||
292 | if (ch->mac && memcmp(ch->mac, ifr.ifr_hwaddr.sa_data, ETH_ALEN) != 0) | 292 | if (ch->mac && memcmp(ch->mac, ifr.ifr_hwaddr.sa_data, ETH_ALEN) != 0) |
293 | continue; | 293 | continue; |
294 | /* if we came here, all selectors have matched */ | 294 | /* if we came here, all selectors have matched */ |
295 | break; | 295 | goto found; |
296 | } | 296 | } |
297 | /* Nothing found for current interface */ | 297 | /* Nothing found for current interface */ |
298 | if (!ch) | 298 | continue; |
299 | continue; | 299 | found: |
300 | |||
301 | if (strcmp(ifr.ifr_name, ch->ifname) != 0) { | 300 | if (strcmp(ifr.ifr_name, ch->ifname) != 0) { |
302 | strcpy(ifr.ifr_newname, ch->ifname); | 301 | strcpy(ifr.ifr_newname, ch->ifname); |
303 | ioctl_or_perror_and_die(ctl_sk, SIOCSIFNAME, &ifr, | 302 | ioctl_or_perror_and_die(ctl_sk, SIOCSIFNAME, &ifr, |
@@ -313,10 +312,14 @@ int nameif_main(int argc UNUSED_PARAM, char **argv) | |||
313 | ch->next->prev = ch->prev; | 312 | ch->next->prev = ch->prev; |
314 | if (ENABLE_FEATURE_CLEAN_UP) | 313 | if (ENABLE_FEATURE_CLEAN_UP) |
315 | delete_eth_table(ch); | 314 | delete_eth_table(ch); |
316 | } | 315 | } /* while */ |
316 | |||
317 | if (ENABLE_FEATURE_CLEAN_UP) { | 317 | if (ENABLE_FEATURE_CLEAN_UP) { |
318 | for (ch = clist; ch; ch = ch->next) | 318 | ethtable_t *next; |
319 | for (ch = clist; ch; ch = next) { | ||
320 | next = ch->next; | ||
319 | delete_eth_table(ch); | 321 | delete_eth_table(ch); |
322 | } | ||
320 | config_close(parser); | 323 | config_close(parser); |
321 | }; | 324 | }; |
322 | 325 | ||
diff --git a/networking/nc.c b/networking/nc.c index 0c843a686..126bec906 100644 --- a/networking/nc.c +++ b/networking/nc.c | |||
@@ -24,7 +24,7 @@ | |||
24 | //config: Allow netcat to act as a server. | 24 | //config: Allow netcat to act as a server. |
25 | //config: | 25 | //config: |
26 | //config:config NC_EXTRA | 26 | //config:config NC_EXTRA |
27 | //config: bool "Netcat extensions (-eiw and filename)" | 27 | //config: bool "Netcat extensions (-eiw and -f FILE)" |
28 | //config: default y | 28 | //config: default y |
29 | //config: depends on NC | 29 | //config: depends on NC |
30 | //config: help | 30 | //config: help |
@@ -40,7 +40,7 @@ | |||
40 | //config: This option makes nc closely follow original nc-1.10. | 40 | //config: This option makes nc closely follow original nc-1.10. |
41 | //config: The code is about 2.5k bigger. It enables | 41 | //config: The code is about 2.5k bigger. It enables |
42 | //config: -s ADDR, -n, -u, -v, -o FILE, -z options, but loses | 42 | //config: -s ADDR, -n, -u, -v, -o FILE, -z options, but loses |
43 | //config: busybox-specific extensions: -f FILE and -ll. | 43 | //config: busybox-specific extensions: -f FILE. |
44 | 44 | ||
45 | #if ENABLE_NC_110_COMPAT | 45 | #if ENABLE_NC_110_COMPAT |
46 | # include "nc_bloaty.c" | 46 | # include "nc_bloaty.c" |
@@ -60,17 +60,18 @@ | |||
60 | //usage:#define nc_full_usage "\n\n" | 60 | //usage:#define nc_full_usage "\n\n" |
61 | //usage: "Open a pipe to IP:PORT" IF_NC_EXTRA(" or FILE") | 61 | //usage: "Open a pipe to IP:PORT" IF_NC_EXTRA(" or FILE") |
62 | //usage: NC_OPTIONS_STR | 62 | //usage: NC_OPTIONS_STR |
63 | //usage: IF_NC_EXTRA( | ||
64 | //usage: "\n -e PROG Run PROG after connect" | ||
65 | //usage: IF_NC_SERVER( | 63 | //usage: IF_NC_SERVER( |
66 | //usage: "\n -l Listen mode, for inbound connects" | 64 | //usage: "\n -l Listen mode, for inbound connects" |
67 | //usage: IF_NC_EXTRA( | 65 | //usage: IF_NC_EXTRA( |
68 | //usage: "\n (use -l twice with -e for persistent server)") | 66 | //usage: "\n (use -ll with -e for persistent server)" |
67 | //usage: ) | ||
69 | //usage: "\n -p PORT Local port" | 68 | //usage: "\n -p PORT Local port" |
70 | //usage: ) | 69 | //usage: ) |
71 | //usage: "\n -w SEC Timeout for connect" | 70 | //usage: IF_NC_EXTRA( |
71 | //usage: "\n -w SEC Connect timeout" | ||
72 | //usage: "\n -i SEC Delay interval for lines sent" | 72 | //usage: "\n -i SEC Delay interval for lines sent" |
73 | //usage: "\n -f FILE Use file (ala /dev/ttyS0) instead of network" | 73 | //usage: "\n -f FILE Use file (ala /dev/ttyS0) instead of network" |
74 | //usage: "\n -e PROG Run PROG after connect" | ||
74 | //usage: ) | 75 | //usage: ) |
75 | //usage: | 76 | //usage: |
76 | //usage:#define nc_notes_usage "" | 77 | //usage:#define nc_notes_usage "" |
@@ -147,7 +148,7 @@ int nc_main(int argc, char **argv) | |||
147 | *p++ = argv[optind++]; | 148 | *p++ = argv[optind++]; |
148 | } | 149 | } |
149 | ) | 150 | ) |
150 | /* optind points to argv[arvc] (NULL) now. | 151 | /* optind points to argv[argc] (NULL) now. |
151 | ** FIXME: we assume that getopt will not count options | 152 | ** FIXME: we assume that getopt will not count options |
152 | ** possibly present on "-e PROG ARGS" and will not | 153 | ** possibly present on "-e PROG ARGS" and will not |
153 | ** include them into final value of optind | 154 | ** include them into final value of optind |
@@ -226,10 +227,9 @@ int nc_main(int argc, char **argv) | |||
226 | /* child, or main thread if only one -l */ | 227 | /* child, or main thread if only one -l */ |
227 | xmove_fd(cfd, 0); | 228 | xmove_fd(cfd, 0); |
228 | xdup2(0, 1); | 229 | xdup2(0, 1); |
229 | xdup2(0, 2); | 230 | /*xdup2(0, 2); - original nc 1.10 does this, we don't */ |
230 | IF_NC_EXTRA(BB_EXECVP(execparam[0], execparam);) | 231 | IF_NC_EXTRA(BB_EXECVP(execparam[0], execparam);) |
231 | /* Don't print stuff or it will go over the wire... */ | 232 | IF_NC_EXTRA(bb_perror_msg_and_die("can't execute '%s'", execparam[0]);) |
232 | _exit(127); | ||
233 | } | 233 | } |
234 | 234 | ||
235 | /* Select loop copying stdin to cfd, and cfd to stdout */ | 235 | /* Select loop copying stdin to cfd, and cfd to stdout */ |
diff --git a/networking/nc_bloaty.c b/networking/nc_bloaty.c index 62a025116..00ba6f114 100644 --- a/networking/nc_bloaty.c +++ b/networking/nc_bloaty.c | |||
@@ -63,6 +63,12 @@ | |||
63 | //usage: " -e PROG Run PROG after connect (must be last)" | 63 | //usage: " -e PROG Run PROG after connect (must be last)" |
64 | //usage: IF_NC_SERVER( | 64 | //usage: IF_NC_SERVER( |
65 | //usage: "\n -l Listen mode, for inbound connects" | 65 | //usage: "\n -l Listen mode, for inbound connects" |
66 | //usage: "\n -lk With -e, provides persistent server" | ||
67 | /* -ll does the same as -lk, but its our extension, while -k is BSD'd, | ||
68 | * presumably more widely known. Therefore we advertise it, not -ll. | ||
69 | * I would like to drop -ll support, but our "small" nc supports it, | ||
70 | * and Rob uses it. | ||
71 | */ | ||
66 | //usage: ) | 72 | //usage: ) |
67 | //usage: "\n -p PORT Local port" | 73 | //usage: "\n -p PORT Local port" |
68 | //usage: "\n -s ADDR Local address" | 74 | //usage: "\n -s ADDR Local address" |
@@ -166,18 +172,14 @@ enum { | |||
166 | OPT_v = (1 << 4), | 172 | OPT_v = (1 << 4), |
167 | OPT_w = (1 << 5), | 173 | OPT_w = (1 << 5), |
168 | OPT_l = (1 << 6) * ENABLE_NC_SERVER, | 174 | OPT_l = (1 << 6) * ENABLE_NC_SERVER, |
169 | OPT_i = (1 << (6+ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, | 175 | OPT_k = (1 << 7) * ENABLE_NC_SERVER, |
170 | OPT_o = (1 << (7+ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, | 176 | OPT_i = (1 << (7+2*ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, |
171 | OPT_z = (1 << (8+ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, | 177 | OPT_o = (1 << (8+2*ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, |
178 | OPT_z = (1 << (9+2*ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, | ||
172 | }; | 179 | }; |
173 | 180 | ||
174 | #define o_nflag (option_mask32 & OPT_n) | 181 | #define o_nflag (option_mask32 & OPT_n) |
175 | #define o_udpmode (option_mask32 & OPT_u) | 182 | #define o_udpmode (option_mask32 & OPT_u) |
176 | #if ENABLE_NC_SERVER | ||
177 | #define o_listen (option_mask32 & OPT_l) | ||
178 | #else | ||
179 | #define o_listen 0 | ||
180 | #endif | ||
181 | #if ENABLE_NC_EXTRA | 183 | #if ENABLE_NC_EXTRA |
182 | #define o_ofile (option_mask32 & OPT_o) | 184 | #define o_ofile (option_mask32 & OPT_o) |
183 | #define o_zero (option_mask32 & OPT_z) | 185 | #define o_zero (option_mask32 & OPT_z) |
@@ -298,7 +300,7 @@ static int connect_w_timeout(int fd) | |||
298 | incoming and returns an open connection *from* someplace. If we were | 300 | incoming and returns an open connection *from* someplace. If we were |
299 | given host/port args, any connections from elsewhere are rejected. This | 301 | given host/port args, any connections from elsewhere are rejected. This |
300 | in conjunction with local-address binding should limit things nicely... */ | 302 | in conjunction with local-address binding should limit things nicely... */ |
301 | static void dolisten(void) | 303 | static void dolisten(int is_persistent, char **proggie) |
302 | { | 304 | { |
303 | int rr; | 305 | int rr; |
304 | 306 | ||
@@ -371,6 +373,7 @@ create new one, and bind() it. TODO */ | |||
371 | xconnect(netfd, &remend.u.sa, ouraddr->len); | 373 | xconnect(netfd, &remend.u.sa, ouraddr->len); |
372 | } else { | 374 | } else { |
373 | /* TCP */ | 375 | /* TCP */ |
376 | another: | ||
374 | arm(o_wait); /* wrap this in a timer, too; 0 = forever */ | 377 | arm(o_wait); /* wrap this in a timer, too; 0 = forever */ |
375 | if (setjmp(jbuf) == 0) { | 378 | if (setjmp(jbuf) == 0) { |
376 | again: | 379 | again: |
@@ -405,6 +408,19 @@ create new one, and bind() it. TODO */ | |||
405 | unarm(); | 408 | unarm(); |
406 | } else | 409 | } else |
407 | bb_error_msg_and_die("timeout"); | 410 | bb_error_msg_and_die("timeout"); |
411 | |||
412 | if (is_persistent && proggie) { | ||
413 | /* -l -k -e PROG */ | ||
414 | signal(SIGCHLD, SIG_IGN); /* no zombies please */ | ||
415 | if (xvfork() != 0) { | ||
416 | /* parent: go back and accept more connections */ | ||
417 | close(rr); | ||
418 | goto another; | ||
419 | } | ||
420 | /* child */ | ||
421 | signal(SIGCHLD, SIG_DFL); | ||
422 | } | ||
423 | |||
408 | xmove_fd(rr, netfd); /* dump the old socket, here's our new one */ | 424 | xmove_fd(rr, netfd); /* dump the old socket, here's our new one */ |
409 | /* find out what address the connection was *to* on our end, in case we're | 425 | /* find out what address the connection was *to* on our end, in case we're |
410 | doing a listen-on-any on a multihomed machine. This allows one to | 426 | doing a listen-on-any on a multihomed machine. This allows one to |
@@ -454,6 +470,9 @@ create new one, and bind() it. TODO */ | |||
454 | if (!o_nflag) | 470 | if (!o_nflag) |
455 | free(remhostname); | 471 | free(remhostname); |
456 | } | 472 | } |
473 | |||
474 | if (proggie) | ||
475 | doexec(proggie); | ||
457 | } | 476 | } |
458 | 477 | ||
459 | /* udptest: | 478 | /* udptest: |
@@ -730,6 +749,7 @@ int nc_main(int argc UNUSED_PARAM, char **argv) | |||
730 | char *themdotted = themdotted; /* for compiler */ | 749 | char *themdotted = themdotted; /* for compiler */ |
731 | char **proggie; | 750 | char **proggie; |
732 | int x; | 751 | int x; |
752 | unsigned cnt_l = 0; | ||
733 | unsigned o_lport = 0; | 753 | unsigned o_lport = 0; |
734 | 754 | ||
735 | INIT_G(); | 755 | INIT_G(); |
@@ -760,7 +780,7 @@ int nc_main(int argc UNUSED_PARAM, char **argv) | |||
760 | if (proggie[0][0] == '-') { | 780 | if (proggie[0][0] == '-') { |
761 | char *optpos = *proggie + 1; | 781 | char *optpos = *proggie + 1; |
762 | /* Skip all valid opts w/o params */ | 782 | /* Skip all valid opts w/o params */ |
763 | optpos = optpos + strspn(optpos, "nuv"IF_NC_SERVER("l")IF_NC_EXTRA("z")); | 783 | optpos = optpos + strspn(optpos, "nuv"IF_NC_SERVER("lk")IF_NC_EXTRA("z")); |
764 | if (*optpos == 'e' && !optpos[1]) { | 784 | if (*optpos == 'e' && !optpos[1]) { |
765 | *optpos = '\0'; | 785 | *optpos = '\0'; |
766 | proggie++; | 786 | proggie++; |
@@ -774,17 +794,21 @@ int nc_main(int argc UNUSED_PARAM, char **argv) | |||
774 | e_found: | 794 | e_found: |
775 | 795 | ||
776 | // -g -G -t -r deleted, unimplemented -a deleted too | 796 | // -g -G -t -r deleted, unimplemented -a deleted too |
777 | opt_complementary = "?2:vv:w+"; /* max 2 params; -v is a counter; -w N */ | 797 | opt_complementary = "?2:vv:ll:w+"; /* max 2 params; -v and -l are counters; -w N */ |
778 | getopt32(argv, "np:s:uvw:" IF_NC_SERVER("l") | 798 | getopt32(argv, "np:s:uvw:" IF_NC_SERVER("lk") |
779 | IF_NC_EXTRA("i:o:z"), | 799 | IF_NC_EXTRA("i:o:z"), |
780 | &str_p, &str_s, &o_wait | 800 | &str_p, &str_s, &o_wait |
781 | IF_NC_EXTRA(, &str_i, &str_o), &o_verbose); | 801 | IF_NC_EXTRA(, &str_i, &str_o), &o_verbose IF_NC_SERVER(, &cnt_l)); |
782 | argv += optind; | 802 | argv += optind; |
783 | #if ENABLE_NC_EXTRA | 803 | #if ENABLE_NC_EXTRA |
784 | if (option_mask32 & OPT_i) /* line-interval time */ | 804 | if (option_mask32 & OPT_i) /* line-interval time */ |
785 | o_interval = xatou_range(str_i, 1, 0xffff); | 805 | o_interval = xatou_range(str_i, 1, 0xffff); |
786 | #endif | 806 | #endif |
807 | #if ENABLE_NC_SERVER | ||
787 | //if (option_mask32 & OPT_l) /* listen mode */ | 808 | //if (option_mask32 & OPT_l) /* listen mode */ |
809 | if (option_mask32 & OPT_k) /* persistent server mode */ | ||
810 | cnt_l = 2; | ||
811 | #endif | ||
788 | //if (option_mask32 & OPT_n) /* numeric-only, no DNS lookups */ | 812 | //if (option_mask32 & OPT_n) /* numeric-only, no DNS lookups */ |
789 | //if (option_mask32 & OPT_o) /* hexdump log */ | 813 | //if (option_mask32 & OPT_o) /* hexdump log */ |
790 | if (option_mask32 & OPT_p) { /* local source port */ | 814 | if (option_mask32 & OPT_p) { /* local source port */ |
@@ -833,7 +857,7 @@ int nc_main(int argc UNUSED_PARAM, char **argv) | |||
833 | if (o_udpmode) | 857 | if (o_udpmode) |
834 | socket_want_pktinfo(netfd); | 858 | socket_want_pktinfo(netfd); |
835 | if (!ENABLE_FEATURE_UNIX_LOCAL | 859 | if (!ENABLE_FEATURE_UNIX_LOCAL |
836 | || o_listen | 860 | || cnt_l != 0 /* listen */ |
837 | || ouraddr->u.sa.sa_family != AF_UNIX | 861 | || ouraddr->u.sa.sa_family != AF_UNIX |
838 | ) { | 862 | ) { |
839 | xbind(netfd, &ouraddr->u.sa, ouraddr->len); | 863 | xbind(netfd, &ouraddr->u.sa, ouraddr->len); |
@@ -862,11 +886,9 @@ int nc_main(int argc UNUSED_PARAM, char **argv) | |||
862 | xmove_fd(xopen(str_o, O_WRONLY|O_CREAT|O_TRUNC), ofd); | 886 | xmove_fd(xopen(str_o, O_WRONLY|O_CREAT|O_TRUNC), ofd); |
863 | #endif | 887 | #endif |
864 | 888 | ||
865 | if (o_listen) { | 889 | if (cnt_l != 0) { |
866 | dolisten(); | 890 | dolisten((cnt_l - 1), proggie); |
867 | /* dolisten does its own connect reporting */ | 891 | /* dolisten does its own connect reporting */ |
868 | if (proggie) /* -e given? */ | ||
869 | doexec(proggie); | ||
870 | x = readwrite(); /* it even works with UDP! */ | 892 | x = readwrite(); /* it even works with UDP! */ |
871 | } else { | 893 | } else { |
872 | /* Outbound connects. Now we're more picky about args... */ | 894 | /* Outbound connects. Now we're more picky about args... */ |
diff --git a/networking/ping.c b/networking/ping.c index 3df67f5c3..e919b3a09 100644 --- a/networking/ping.c +++ b/networking/ping.c | |||
@@ -89,7 +89,9 @@ | |||
89 | //usage: "[OPTIONS] HOST" | 89 | //usage: "[OPTIONS] HOST" |
90 | //usage:# define ping_full_usage "\n\n" | 90 | //usage:# define ping_full_usage "\n\n" |
91 | //usage: "Send ICMP ECHO_REQUEST packets to network hosts\n" | 91 | //usage: "Send ICMP ECHO_REQUEST packets to network hosts\n" |
92 | //usage: IF_PING6( | ||
92 | //usage: "\n -4,-6 Force IP or IPv6 name resolution" | 93 | //usage: "\n -4,-6 Force IP or IPv6 name resolution" |
94 | //usage: ) | ||
93 | //usage: "\n -c CNT Send only CNT pings" | 95 | //usage: "\n -c CNT Send only CNT pings" |
94 | //usage: "\n -s SIZE Send SIZE data bytes in packets (default:56)" | 96 | //usage: "\n -s SIZE Send SIZE data bytes in packets (default:56)" |
95 | //usage: "\n -t TTL Set TTL" | 97 | //usage: "\n -t TTL Set TTL" |
@@ -299,7 +301,7 @@ static int common_ping_main(sa_family_t af, char **argv) | |||
299 | 301 | ||
300 | /* Full(er) version */ | 302 | /* Full(er) version */ |
301 | 303 | ||
302 | #define OPT_STRING ("qvc:s:t:w:W:I:4" IF_PING6("6")) | 304 | #define OPT_STRING ("qvc:s:t:w:W:I:n4" IF_PING6("6")) |
303 | enum { | 305 | enum { |
304 | OPT_QUIET = 1 << 0, | 306 | OPT_QUIET = 1 << 0, |
305 | OPT_VERBOSE = 1 << 1, | 307 | OPT_VERBOSE = 1 << 1, |
@@ -309,8 +311,9 @@ enum { | |||
309 | OPT_w = 1 << 5, | 311 | OPT_w = 1 << 5, |
310 | OPT_W = 1 << 6, | 312 | OPT_W = 1 << 6, |
311 | OPT_I = 1 << 7, | 313 | OPT_I = 1 << 7, |
312 | OPT_IPV4 = 1 << 8, | 314 | /*OPT_n = 1 << 8, - ignored */ |
313 | OPT_IPV6 = (1 << 9) * ENABLE_PING6, | 315 | OPT_IPV4 = 1 << 9, |
316 | OPT_IPV6 = (1 << 10) * ENABLE_PING6, | ||
314 | }; | 317 | }; |
315 | 318 | ||
316 | 319 | ||
@@ -349,9 +352,6 @@ struct globals { | |||
349 | #define source_lsa (G.source_lsa ) | 352 | #define source_lsa (G.source_lsa ) |
350 | #define str_I (G.str_I ) | 353 | #define str_I (G.str_I ) |
351 | #define datalen (G.datalen ) | 354 | #define datalen (G.datalen ) |
352 | #define ntransmitted (G.ntransmitted) | ||
353 | #define nreceived (G.nreceived ) | ||
354 | #define nrepeats (G.nrepeats ) | ||
355 | #define pingcount (G.pingcount ) | 355 | #define pingcount (G.pingcount ) |
356 | #define opt_ttl (G.opt_ttl ) | 356 | #define opt_ttl (G.opt_ttl ) |
357 | #define myid (G.myid ) | 357 | #define myid (G.myid ) |
@@ -387,33 +387,40 @@ void BUG_ping_globals_too_big(void); | |||
387 | static void print_stats_and_exit(int junk) NORETURN; | 387 | static void print_stats_and_exit(int junk) NORETURN; |
388 | static void print_stats_and_exit(int junk UNUSED_PARAM) | 388 | static void print_stats_and_exit(int junk UNUSED_PARAM) |
389 | { | 389 | { |
390 | unsigned long ul; | ||
391 | unsigned long nrecv; | ||
392 | |||
390 | signal(SIGINT, SIG_IGN); | 393 | signal(SIGINT, SIG_IGN); |
391 | 394 | ||
392 | printf("\n--- %s ping statistics ---\n", hostname); | 395 | nrecv = G.nreceived; |
393 | printf("%lu packets transmitted, ", ntransmitted); | 396 | printf("\n--- %s ping statistics ---\n" |
394 | printf("%lu packets received, ", nreceived); | 397 | "%lu packets transmitted, " |
395 | if (nrepeats) | 398 | "%lu packets received, ", |
396 | printf("%lu duplicates, ", nrepeats); | 399 | hostname, G.ntransmitted, nrecv |
397 | if (ntransmitted) | 400 | ); |
398 | ntransmitted = (ntransmitted - nreceived) * 100 / ntransmitted; | 401 | if (G.nrepeats) |
399 | printf("%lu%% packet loss\n", ntransmitted); | 402 | printf("%lu duplicates, ", G.nrepeats); |
403 | ul = G.ntransmitted; | ||
404 | if (ul != 0) | ||
405 | ul = (ul - nrecv) * 100 / ul; | ||
406 | printf("%lu%% packet loss\n", ul); | ||
400 | if (tmin != UINT_MAX) { | 407 | if (tmin != UINT_MAX) { |
401 | unsigned tavg = tsum / (nreceived + nrepeats); | 408 | unsigned tavg = tsum / (nrecv + G.nrepeats); |
402 | printf("round-trip min/avg/max = %u.%03u/%u.%03u/%u.%03u ms\n", | 409 | printf("round-trip min/avg/max = %u.%03u/%u.%03u/%u.%03u ms\n", |
403 | tmin / 1000, tmin % 1000, | 410 | tmin / 1000, tmin % 1000, |
404 | tavg / 1000, tavg % 1000, | 411 | tavg / 1000, tavg % 1000, |
405 | tmax / 1000, tmax % 1000); | 412 | tmax / 1000, tmax % 1000); |
406 | } | 413 | } |
407 | /* if condition is true, exit with 1 -- 'failure' */ | 414 | /* if condition is true, exit with 1 -- 'failure' */ |
408 | exit(nreceived == 0 || (deadline && nreceived < pingcount)); | 415 | exit(nrecv == 0 || (deadline && nrecv < pingcount)); |
409 | } | 416 | } |
410 | 417 | ||
411 | static void sendping_tail(void (*sp)(int), int size_pkt) | 418 | static void sendping_tail(void (*sp)(int), int size_pkt) |
412 | { | 419 | { |
413 | int sz; | 420 | int sz; |
414 | 421 | ||
415 | CLR((uint16_t)ntransmitted % MAX_DUP_CHK); | 422 | CLR((uint16_t)G.ntransmitted % MAX_DUP_CHK); |
416 | ntransmitted++; | 423 | G.ntransmitted++; |
417 | 424 | ||
418 | size_pkt += datalen; | 425 | size_pkt += datalen; |
419 | 426 | ||
@@ -423,7 +430,7 @@ static void sendping_tail(void (*sp)(int), int size_pkt) | |||
423 | if (sz != size_pkt) | 430 | if (sz != size_pkt) |
424 | bb_error_msg_and_die(bb_msg_write_error); | 431 | bb_error_msg_and_die(bb_msg_write_error); |
425 | 432 | ||
426 | if (pingcount == 0 || deadline || ntransmitted < pingcount) { | 433 | if (pingcount == 0 || deadline || G.ntransmitted < pingcount) { |
427 | /* Didn't send all pings yet - schedule next in 1s */ | 434 | /* Didn't send all pings yet - schedule next in 1s */ |
428 | signal(SIGALRM, sp); | 435 | signal(SIGALRM, sp); |
429 | if (deadline) { | 436 | if (deadline) { |
@@ -439,7 +446,7 @@ static void sendping_tail(void (*sp)(int), int size_pkt) | |||
439 | * otherwise ping waits for two RTTs. */ | 446 | * otherwise ping waits for two RTTs. */ |
440 | unsigned expire = timeout; | 447 | unsigned expire = timeout; |
441 | 448 | ||
442 | if (nreceived) { | 449 | if (G.nreceived) { |
443 | /* approx. 2*tmax, in seconds (2 RTT) */ | 450 | /* approx. 2*tmax, in seconds (2 RTT) */ |
444 | expire = tmax / (512*1024); | 451 | expire = tmax / (512*1024); |
445 | if (expire == 0) | 452 | if (expire == 0) |
@@ -458,7 +465,7 @@ static void sendping4(int junk UNUSED_PARAM) | |||
458 | pkt->icmp_type = ICMP_ECHO; | 465 | pkt->icmp_type = ICMP_ECHO; |
459 | /*pkt->icmp_code = 0;*/ | 466 | /*pkt->icmp_code = 0;*/ |
460 | pkt->icmp_cksum = 0; /* cksum is calculated with this field set to 0 */ | 467 | pkt->icmp_cksum = 0; /* cksum is calculated with this field set to 0 */ |
461 | pkt->icmp_seq = htons(ntransmitted); /* don't ++ here, it can be a macro */ | 468 | pkt->icmp_seq = htons(G.ntransmitted); /* don't ++ here, it can be a macro */ |
462 | pkt->icmp_id = myid; | 469 | pkt->icmp_id = myid; |
463 | 470 | ||
464 | /* If datalen < 4, we store timestamp _past_ the packet, | 471 | /* If datalen < 4, we store timestamp _past_ the packet, |
@@ -481,7 +488,7 @@ static void sendping6(int junk UNUSED_PARAM) | |||
481 | pkt->icmp6_type = ICMP6_ECHO_REQUEST; | 488 | pkt->icmp6_type = ICMP6_ECHO_REQUEST; |
482 | /*pkt->icmp6_code = 0;*/ | 489 | /*pkt->icmp6_code = 0;*/ |
483 | /*pkt->icmp6_cksum = 0;*/ | 490 | /*pkt->icmp6_cksum = 0;*/ |
484 | pkt->icmp6_seq = htons(ntransmitted); /* don't ++ here, it can be a macro */ | 491 | pkt->icmp6_seq = htons(G.ntransmitted); /* don't ++ here, it can be a macro */ |
485 | pkt->icmp6_id = myid; | 492 | pkt->icmp6_id = myid; |
486 | 493 | ||
487 | /*if (datalen >= 4)*/ | 494 | /*if (datalen >= 4)*/ |
@@ -548,7 +555,7 @@ static void unpack_tail(int sz, uint32_t *tp, | |||
548 | const char *dupmsg = " (DUP!)"; | 555 | const char *dupmsg = " (DUP!)"; |
549 | unsigned triptime = triptime; /* for gcc */ | 556 | unsigned triptime = triptime; /* for gcc */ |
550 | 557 | ||
551 | ++nreceived; | 558 | ++G.nreceived; |
552 | 559 | ||
553 | if (tp) { | 560 | if (tp) { |
554 | /* (int32_t) cast is for hypothetical 64-bit unsigned */ | 561 | /* (int32_t) cast is for hypothetical 64-bit unsigned */ |
@@ -562,8 +569,8 @@ static void unpack_tail(int sz, uint32_t *tp, | |||
562 | } | 569 | } |
563 | 570 | ||
564 | if (TST(recv_seq % MAX_DUP_CHK)) { | 571 | if (TST(recv_seq % MAX_DUP_CHK)) { |
565 | ++nrepeats; | 572 | ++G.nrepeats; |
566 | --nreceived; | 573 | --G.nreceived; |
567 | } else { | 574 | } else { |
568 | SET(recv_seq % MAX_DUP_CHK); | 575 | SET(recv_seq % MAX_DUP_CHK); |
569 | dupmsg += 7; | 576 | dupmsg += 7; |
@@ -692,7 +699,7 @@ static void ping4(len_and_sockaddr *lsa) | |||
692 | continue; | 699 | continue; |
693 | } | 700 | } |
694 | unpack4(G.rcv_packet, c, &from); | 701 | unpack4(G.rcv_packet, c, &from); |
695 | if (pingcount && nreceived >= pingcount) | 702 | if (pingcount && G.nreceived >= pingcount) |
696 | break; | 703 | break; |
697 | } | 704 | } |
698 | } | 705 | } |
@@ -784,7 +791,7 @@ static void ping6(len_and_sockaddr *lsa) | |||
784 | } | 791 | } |
785 | } | 792 | } |
786 | unpack6(G.rcv_packet, c, &from, hoplimit); | 793 | unpack6(G.rcv_packet, c, &from, hoplimit); |
787 | if (pingcount && nreceived >= pingcount) | 794 | if (pingcount && G.nreceived >= pingcount) |
788 | break; | 795 | break; |
789 | } | 796 | } |
790 | } | 797 | } |
diff --git a/networking/traceroute.c b/networking/traceroute.c index 6b7b2ebdd..0c18d6c0c 100644 --- a/networking/traceroute.c +++ b/networking/traceroute.c | |||
@@ -805,6 +805,7 @@ common_traceroute_main(int op, char **argv) | |||
805 | char *waittime_str; | 805 | char *waittime_str; |
806 | char *pausemsecs_str; | 806 | char *pausemsecs_str; |
807 | char *first_ttl_str; | 807 | char *first_ttl_str; |
808 | char *dest_str; | ||
808 | #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE | 809 | #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE |
809 | llist_t *source_route_list = NULL; | 810 | llist_t *source_route_list = NULL; |
810 | int lsrr = 0; | 811 | int lsrr = 0; |
@@ -1059,8 +1060,12 @@ common_traceroute_main(int op, char **argv) | |||
1059 | xsetgid(getgid()); | 1060 | xsetgid(getgid()); |
1060 | xsetuid(getuid()); | 1061 | xsetuid(getuid()); |
1061 | 1062 | ||
1062 | printf("traceroute to %s (%s)", argv[0], | 1063 | dest_str = xmalloc_sockaddr2dotted_noport(&dest_lsa->u.sa); |
1063 | xmalloc_sockaddr2dotted_noport(&dest_lsa->u.sa)); | 1064 | printf("traceroute to %s (%s)", argv[0], dest_str); |
1065 | if (ENABLE_FEATURE_CLEAN_UP) { | ||
1066 | free(dest_str); | ||
1067 | } | ||
1068 | |||
1064 | if (op & OPT_SOURCE) | 1069 | if (op & OPT_SOURCE) |
1065 | printf(" from %s", source); | 1070 | printf(" from %s", source); |
1066 | printf(", %d hops max, %d byte packets\n", max_ttl, packlen); | 1071 | printf(", %d hops max, %d byte packets\n", max_ttl, packlen); |
@@ -1216,6 +1221,12 @@ common_traceroute_main(int op, char **argv) | |||
1216 | } | 1221 | } |
1217 | } | 1222 | } |
1218 | 1223 | ||
1224 | if (ENABLE_FEATURE_CLEAN_UP) { | ||
1225 | free(to); | ||
1226 | free(lastaddr); | ||
1227 | free(from_lsa); | ||
1228 | } | ||
1229 | |||
1219 | return 0; | 1230 | return 0; |
1220 | } | 1231 | } |
1221 | 1232 | ||
diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c index 9ad95954d..a1a7f6b57 100644 --- a/networking/udhcp/dhcpd.c +++ b/networking/udhcp/dhcpd.c | |||
@@ -22,11 +22,12 @@ | |||
22 | */ | 22 | */ |
23 | 23 | ||
24 | //usage:#define udhcpd_trivial_usage | 24 | //usage:#define udhcpd_trivial_usage |
25 | //usage: "[-fS]" IF_FEATURE_UDHCP_PORT(" [-P N]") " [CONFFILE]" | 25 | //usage: "[-fS] [-I ADDR]" IF_FEATURE_UDHCP_PORT(" [-P N]") " [CONFFILE]" |
26 | //usage:#define udhcpd_full_usage "\n\n" | 26 | //usage:#define udhcpd_full_usage "\n\n" |
27 | //usage: "DHCP server\n" | 27 | //usage: "DHCP server\n" |
28 | //usage: "\n -f Run in foreground" | 28 | //usage: "\n -f Run in foreground" |
29 | //usage: "\n -S Log to syslog too" | 29 | //usage: "\n -S Log to syslog too" |
30 | //usage: "\n -I ADDR Local address" | ||
30 | //usage: IF_FEATURE_UDHCP_PORT( | 31 | //usage: IF_FEATURE_UDHCP_PORT( |
31 | //usage: "\n -P N Use port N (default 67)" | 32 | //usage: "\n -P N Use port N (default 67)" |
32 | //usage: ) | 33 | //usage: ) |
@@ -302,6 +303,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) | |||
302 | unsigned num_ips; | 303 | unsigned num_ips; |
303 | unsigned opt; | 304 | unsigned opt; |
304 | struct option_set *option; | 305 | struct option_set *option; |
306 | char *str_I = str_I; | ||
305 | IF_FEATURE_UDHCP_PORT(char *str_P;) | 307 | IF_FEATURE_UDHCP_PORT(char *str_P;) |
306 | 308 | ||
307 | #if ENABLE_FEATURE_UDHCP_PORT | 309 | #if ENABLE_FEATURE_UDHCP_PORT |
@@ -312,8 +314,10 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) | |||
312 | #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 | 314 | #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 |
313 | opt_complementary = "vv"; | 315 | opt_complementary = "vv"; |
314 | #endif | 316 | #endif |
315 | opt = getopt32(argv, "fSv" | 317 | opt = getopt32(argv, "fSI:v" |
316 | IF_FEATURE_UDHCP_PORT("P:", &str_P) | 318 | IF_FEATURE_UDHCP_PORT("P:") |
319 | , &str_I | ||
320 | IF_FEATURE_UDHCP_PORT(, &str_P) | ||
317 | IF_UDHCP_VERBOSE(, &dhcp_verbose) | 321 | IF_UDHCP_VERBOSE(, &dhcp_verbose) |
318 | ); | 322 | ); |
319 | if (!(opt & 1)) { /* no -f */ | 323 | if (!(opt & 1)) { /* no -f */ |
@@ -326,8 +330,13 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) | |||
326 | openlog(applet_name, LOG_PID, LOG_DAEMON); | 330 | openlog(applet_name, LOG_PID, LOG_DAEMON); |
327 | logmode |= LOGMODE_SYSLOG; | 331 | logmode |= LOGMODE_SYSLOG; |
328 | } | 332 | } |
333 | if (opt & 4) { /* -I */ | ||
334 | len_and_sockaddr *lsa = xhost_and_af2sockaddr(str_I, 0, AF_INET); | ||
335 | server_config.server_nip = lsa->u.sin.sin_addr.s_addr; | ||
336 | free(lsa); | ||
337 | } | ||
329 | #if ENABLE_FEATURE_UDHCP_PORT | 338 | #if ENABLE_FEATURE_UDHCP_PORT |
330 | if (opt & 8) { /* -P */ | 339 | if (opt & 16) { /* -P */ |
331 | SERVER_PORT = xatou16(str_P); | 340 | SERVER_PORT = xatou16(str_P); |
332 | CLIENT_PORT = SERVER_PORT + 1; | 341 | CLIENT_PORT = SERVER_PORT + 1; |
333 | } | 342 | } |
@@ -367,7 +376,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) | |||
367 | 376 | ||
368 | if (udhcp_read_interface(server_config.interface, | 377 | if (udhcp_read_interface(server_config.interface, |
369 | &server_config.ifindex, | 378 | &server_config.ifindex, |
370 | &server_config.server_nip, | 379 | (server_config.server_nip == 0 ? &server_config.server_nip : NULL), |
371 | server_config.server_mac) | 380 | server_config.server_mac) |
372 | ) { | 381 | ) { |
373 | retval = 1; | 382 | retval = 1; |
diff --git a/procps/pgrep.c b/procps/pgrep.c index dc7ffff48..8daf5b28a 100644 --- a/procps/pgrep.c +++ b/procps/pgrep.c | |||
@@ -128,7 +128,7 @@ int pgrep_main(int argc UNUSED_PARAM, char **argv) | |||
128 | bb_show_usage(); | 128 | bb_show_usage(); |
129 | 129 | ||
130 | if (argv[0]) | 130 | if (argv[0]) |
131 | xregcomp(&re_buffer, argv[0], REG_EXTENDED | REG_NOSUB); | 131 | xregcomp(&re_buffer, argv[0], OPT_ANCHOR ? REG_EXTENDED : (REG_EXTENDED|REG_NOSUB)); |
132 | 132 | ||
133 | matched_pid = 0; | 133 | matched_pid = 0; |
134 | cmd_last = NULL; | 134 | cmd_last = NULL; |
diff --git a/shell/ash.c b/shell/ash.c index 75c01ec14..962fc2609 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -441,6 +441,9 @@ static void trace_vprintf(const char *fmt, va_list va); | |||
441 | /* ============ Utility functions */ | 441 | /* ============ Utility functions */ |
442 | #define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0) | 442 | #define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0) |
443 | 443 | ||
444 | #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) | ||
445 | #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) | ||
446 | |||
444 | static int isdigit_str9(const char *str) | 447 | static int isdigit_str9(const char *str) |
445 | { | 448 | { |
446 | int maxlen = 9 + 1; /* max 9 digits: 999999999 */ | 449 | int maxlen = 9 + 1; /* max 9 digits: 999999999 */ |
@@ -2064,27 +2067,6 @@ getoptsreset(const char *value) | |||
2064 | } | 2067 | } |
2065 | #endif | 2068 | #endif |
2066 | 2069 | ||
2067 | /* math.h has these, otherwise define our private copies */ | ||
2068 | #if !ENABLE_SH_MATH_SUPPORT | ||
2069 | #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) | ||
2070 | #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) | ||
2071 | /* | ||
2072 | * Return the pointer to the first char which is not part of a legal variable name | ||
2073 | * (a letter or underscore followed by letters, underscores, and digits). | ||
2074 | */ | ||
2075 | static const char* | ||
2076 | endofname(const char *name) | ||
2077 | { | ||
2078 | if (!is_name(*name)) | ||
2079 | return name; | ||
2080 | while (*++name) { | ||
2081 | if (!is_in_name(*name)) | ||
2082 | break; | ||
2083 | } | ||
2084 | return name; | ||
2085 | } | ||
2086 | #endif | ||
2087 | |||
2088 | /* | 2070 | /* |
2089 | * Compares two strings up to the first = or '\0'. The first | 2071 | * Compares two strings up to the first = or '\0'. The first |
2090 | * string must be terminated by '='; the second may be terminated by | 2072 | * string must be terminated by '='; the second may be terminated by |
@@ -12774,6 +12756,9 @@ dotcmd(int argc, char **argv) | |||
12774 | /* "false; . empty_file; echo $?" should print 0, not 1: */ | 12756 | /* "false; . empty_file; echo $?" should print 0, not 1: */ |
12775 | exitstatus = 0; | 12757 | exitstatus = 0; |
12776 | 12758 | ||
12759 | /* This aborts if file isn't found, which is POSIXly correct. | ||
12760 | * bash returns exitcode 1 instead. | ||
12761 | */ | ||
12777 | fullname = find_dot_file(argv[1]); | 12762 | fullname = find_dot_file(argv[1]); |
12778 | 12763 | ||
12779 | argv += 2; | 12764 | argv += 2; |
@@ -12785,6 +12770,9 @@ dotcmd(int argc, char **argv) | |||
12785 | shellparam.p = argv; | 12770 | shellparam.p = argv; |
12786 | }; | 12771 | }; |
12787 | 12772 | ||
12773 | /* This aborts if file can't be opened, which is POSIXly correct. | ||
12774 | * bash returns exitcode 1 instead. | ||
12775 | */ | ||
12788 | setinputfile(fullname, INPUT_PUSH_FILE); | 12776 | setinputfile(fullname, INPUT_PUSH_FILE); |
12789 | commandname = fullname; | 12777 | commandname = fullname; |
12790 | cmdloop(0); | 12778 | cmdloop(0); |
@@ -13832,27 +13820,21 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
13832 | #endif | 13820 | #endif |
13833 | procargs(argv); | 13821 | procargs(argv); |
13834 | 13822 | ||
13835 | #if ENABLE_FEATURE_EDITING_SAVEHISTORY | ||
13836 | if (iflag) { | ||
13837 | const char *hp = lookupvar("HISTFILE"); | ||
13838 | if (!hp) { | ||
13839 | hp = lookupvar("HOME"); | ||
13840 | if (hp) { | ||
13841 | char *defhp = concat_path_file(hp, ".ash_history"); | ||
13842 | setvar("HISTFILE", defhp, 0); | ||
13843 | free(defhp); | ||
13844 | } | ||
13845 | } | ||
13846 | } | ||
13847 | #endif | ||
13848 | if (argv[0] && argv[0][0] == '-') | 13823 | if (argv[0] && argv[0][0] == '-') |
13849 | isloginsh = 1; | 13824 | isloginsh = 1; |
13850 | if (isloginsh) { | 13825 | if (isloginsh) { |
13826 | const char *hp; | ||
13827 | |||
13851 | state = 1; | 13828 | state = 1; |
13852 | read_profile("/etc/profile"); | 13829 | read_profile("/etc/profile"); |
13853 | state1: | 13830 | state1: |
13854 | state = 2; | 13831 | state = 2; |
13855 | read_profile(".profile"); | 13832 | hp = lookupvar("HOME"); |
13833 | if (hp) { | ||
13834 | hp = concat_path_file(hp, ".profile"); | ||
13835 | read_profile(hp); | ||
13836 | free((char*)hp); | ||
13837 | } | ||
13856 | } | 13838 | } |
13857 | state2: | 13839 | state2: |
13858 | state = 3; | 13840 | state = 3; |
@@ -13884,6 +13866,15 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
13884 | #if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY | 13866 | #if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY |
13885 | if (iflag) { | 13867 | if (iflag) { |
13886 | const char *hp = lookupvar("HISTFILE"); | 13868 | const char *hp = lookupvar("HISTFILE"); |
13869 | if (!hp) { | ||
13870 | hp = lookupvar("HOME"); | ||
13871 | if (hp) { | ||
13872 | hp = concat_path_file(hp, ".ash_history"); | ||
13873 | setvar("HISTFILE", hp, 0); | ||
13874 | free((char*)hp); | ||
13875 | hp = lookupvar("HISTFILE"); | ||
13876 | } | ||
13877 | } | ||
13887 | if (hp) | 13878 | if (hp) |
13888 | line_input_state->hist_file = hp; | 13879 | line_input_state->hist_file = hp; |
13889 | # if ENABLE_FEATURE_SH_HISTFILESIZE | 13880 | # if ENABLE_FEATURE_SH_HISTFILESIZE |
diff --git a/shell/hush.c b/shell/hush.c index e2dc1e2d0..b23325725 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -8880,6 +8880,9 @@ static int FAST_FUNC builtin_source(char **argv) | |||
8880 | free(arg_path); | 8880 | free(arg_path); |
8881 | if (!input) { | 8881 | if (!input) { |
8882 | /* bb_perror_msg("%s", *argv); - done by fopen_or_warn */ | 8882 | /* bb_perror_msg("%s", *argv); - done by fopen_or_warn */ |
8883 | /* POSIX: non-interactive shell should abort here, | ||
8884 | * not merely fail. So far no one complained :) | ||
8885 | */ | ||
8883 | return EXIT_FAILURE; | 8886 | return EXIT_FAILURE; |
8884 | } | 8887 | } |
8885 | close_on_exec_on(fileno(input)); | 8888 | close_on_exec_on(fileno(input)); |
@@ -8889,12 +8892,14 @@ static int FAST_FUNC builtin_source(char **argv) | |||
8889 | /* "we are inside sourced file, ok to use return" */ | 8892 | /* "we are inside sourced file, ok to use return" */ |
8890 | G.flag_return_in_progress = -1; | 8893 | G.flag_return_in_progress = -1; |
8891 | #endif | 8894 | #endif |
8892 | save_and_replace_G_args(&sv, argv); | 8895 | if (argv[1]) |
8896 | save_and_replace_G_args(&sv, argv); | ||
8893 | 8897 | ||
8894 | parse_and_run_file(input); | 8898 | parse_and_run_file(input); |
8895 | fclose(input); | 8899 | fclose(input); |
8896 | 8900 | ||
8897 | restore_G_args(&sv, argv); | 8901 | if (argv[1]) |
8902 | restore_G_args(&sv, argv); | ||
8898 | #if ENABLE_HUSH_FUNCTIONS | 8903 | #if ENABLE_HUSH_FUNCTIONS |
8899 | G.flag_return_in_progress = sv_flg; | 8904 | G.flag_return_in_progress = sv_flg; |
8900 | #endif | 8905 | #endif |
diff --git a/shell/hush_test/hush-misc/source2.right b/shell/hush_test/hush-misc/source2.right new file mode 100644 index 000000000..0587bad67 --- /dev/null +++ b/shell/hush_test/hush-misc/source2.right | |||
@@ -0,0 +1,4 @@ | |||
1 | 0:arg0 1:arg1 2:arg2 | ||
2 | Ok1:0 | ||
3 | 0:arg0 1:q 2:w | ||
4 | Ok2:0 | ||
diff --git a/shell/hush_test/hush-misc/source2.tests b/shell/hush_test/hush-misc/source2.tests new file mode 100755 index 000000000..40b6b83cd --- /dev/null +++ b/shell/hush_test/hush-misc/source2.tests | |||
@@ -0,0 +1,8 @@ | |||
1 | echo 'echo "0:$0 1:$1 2:$2"' >sourced1 | ||
2 | set -- 1 2 3 | ||
3 | "$THIS_SH" -c '. ./sourced1' arg0 arg1 arg2 | ||
4 | echo Ok1:$? | ||
5 | "$THIS_SH" -c '. ./sourced1 q w e' arg0 arg1 arg2 | ||
6 | echo Ok2:$? | ||
7 | |||
8 | rm sourced1 | ||
diff --git a/shell/math.c b/shell/math.c index 15c003965..3da151137 100644 --- a/shell/math.c +++ b/shell/math.c | |||
@@ -494,18 +494,6 @@ static const char op_tokens[] ALIGN1 = { | |||
494 | }; | 494 | }; |
495 | #define ptr_to_rparen (&op_tokens[sizeof(op_tokens)-7]) | 495 | #define ptr_to_rparen (&op_tokens[sizeof(op_tokens)-7]) |
496 | 496 | ||
497 | const char* FAST_FUNC | ||
498 | endofname(const char *name) | ||
499 | { | ||
500 | if (!is_name(*name)) | ||
501 | return name; | ||
502 | while (*++name) { | ||
503 | if (!is_in_name(*name)) | ||
504 | break; | ||
505 | } | ||
506 | return name; | ||
507 | } | ||
508 | |||
509 | static arith_t FAST_FUNC | 497 | static arith_t FAST_FUNC |
510 | evaluate_string(arith_state_t *math_state, const char *expr) | 498 | evaluate_string(arith_state_t *math_state, const char *expr) |
511 | { | 499 | { |
diff --git a/shell/math.h b/shell/math.h index 2d305eb12..864bee691 100644 --- a/shell/math.h +++ b/shell/math.h | |||
@@ -73,11 +73,6 @@ typedef long arith_t; | |||
73 | #define strto_arith_t strtoul | 73 | #define strto_arith_t strtoul |
74 | #endif | 74 | #endif |
75 | 75 | ||
76 | /* ash's and hush's endofname is the same, so... */ | ||
77 | # define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) | ||
78 | # define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) | ||
79 | const char* FAST_FUNC endofname(const char *name); | ||
80 | |||
81 | typedef const char* FAST_FUNC (*arith_var_lookup_t)(const char *name); | 76 | typedef const char* FAST_FUNC (*arith_var_lookup_t)(const char *name); |
82 | typedef void FAST_FUNC (*arith_var_set_t)(const char *name, const char *val); | 77 | typedef void FAST_FUNC (*arith_var_set_t)(const char *name, const char *val); |
83 | //typedef const char* FAST_FUNC (*arith_var_endofname_t)(const char *name); | 78 | //typedef const char* FAST_FUNC (*arith_var_endofname_t)(const char *name); |
diff --git a/sysklogd/syslogd.c b/sysklogd/syslogd.c index 3fe3f5348..4f45b4f7f 100644 --- a/sysklogd/syslogd.c +++ b/sysklogd/syslogd.c | |||
@@ -29,7 +29,7 @@ | |||
29 | //usage: "\n -b N N rotated logs to keep (default:1, max=99, 0=purge)" | 29 | //usage: "\n -b N N rotated logs to keep (default:1, max=99, 0=purge)" |
30 | //usage: ) | 30 | //usage: ) |
31 | //usage: IF_FEATURE_REMOTE_LOG( | 31 | //usage: IF_FEATURE_REMOTE_LOG( |
32 | //usage: "\n -R HOST[:PORT] Log to IP or hostname on PORT (default PORT=514/UDP)" | 32 | //usage: "\n -R HOST[:PORT] Log to HOST:PORT (default PORT:514)" |
33 | //usage: "\n -L Log locally and via network (default is network only if -R)" | 33 | //usage: "\n -L Log locally and via network (default is network only if -R)" |
34 | //usage: ) | 34 | //usage: ) |
35 | //usage: IF_FEATURE_SYSLOGD_DUP( | 35 | //usage: IF_FEATURE_SYSLOGD_DUP( |
diff --git a/testsuite/awk.tests b/testsuite/awk.tests index f9c3b6b4d..dad49c3f5 100755 --- a/testsuite/awk.tests +++ b/testsuite/awk.tests | |||
@@ -25,6 +25,25 @@ testing "awk if string == " "awk 'BEGIN{if(\"a\"==\"ab\") print \"bar\"}'" "" | |||
25 | 25 | ||
26 | # 4294967295 = 0xffffffff | 26 | # 4294967295 = 0xffffffff |
27 | testing "awk bitwise op" "awk '{ print or(4294967295,1) }'" "4.29497e+09\n" "" "\n" | 27 | testing "awk bitwise op" "awk '{ print or(4294967295,1) }'" "4.29497e+09\n" "" "\n" |
28 | |||
29 | # we were testing for a non-empty body when deciding if a function was | ||
30 | # defined or not. The testcase below caused: | ||
31 | # awk: cmd. line:8: Call to undefined function | ||
32 | prg=' | ||
33 | function empty_fun(count) { | ||
34 | # empty | ||
35 | } | ||
36 | END { | ||
37 | i=1 | ||
38 | print "L" i "\n" | ||
39 | empty_fun(i + i + ++i) | ||
40 | print "L" i "\n" | ||
41 | }' | ||
42 | testing "awk handles empty function f(arg){}" \ | ||
43 | "awk '$prg'" \ | ||
44 | "L1\n\nL2\n\n" \ | ||
45 | "" "" | ||
46 | |||
28 | optional DESKTOP | 47 | optional DESKTOP |
29 | testing "awk hex const 1" "awk '{ print or(0xffffffff,1) }'" "4.29497e+09\n" "" "\n" | 48 | testing "awk hex const 1" "awk '{ print or(0xffffffff,1) }'" "4.29497e+09\n" "" "\n" |
30 | testing "awk hex const 2" "awk '{ print or(0x80000000,1) }'" "2.14748e+09\n" "" "\n" | 49 | testing "awk hex const 2" "awk '{ print or(0x80000000,1) }'" "2.14748e+09\n" "" "\n" |
diff --git a/util-linux/fdisk_sun.c b/util-linux/fdisk_sun.c index e7fcc067c..e32740dea 100644 --- a/util-linux/fdisk_sun.c +++ b/util-linux/fdisk_sun.c | |||
@@ -348,6 +348,7 @@ create_sunlabel(void) | |||
348 | 348 | ||
349 | set_all_unchanged(); | 349 | set_all_unchanged(); |
350 | set_changed(0); | 350 | set_changed(0); |
351 | check_sun_label(); | ||
351 | get_boot(CREATE_EMPTY_SUN); | 352 | get_boot(CREATE_EMPTY_SUN); |
352 | } | 353 | } |
353 | 354 | ||
@@ -497,11 +498,14 @@ add_sun_partition(int n, int sys) | |||
497 | else | 498 | else |
498 | first = read_int(scround(start), scround(stop)+1, | 499 | first = read_int(scround(start), scround(stop)+1, |
499 | scround(stop), 0, mesg); | 500 | scround(stop), 0, mesg); |
500 | if (display_in_cyl_units) | 501 | if (display_in_cyl_units) { |
501 | first *= units_per_sector; | 502 | first *= units_per_sector; |
502 | else | 503 | } else { |
503 | /* Starting sector has to be properly aligned */ | 504 | /* Starting sector has to be properly aligned */ |
504 | first = (first + g_heads * g_sectors - 1) / (g_heads * g_sectors); | 505 | first = (first + g_heads * g_sectors - 1) / |
506 | (g_heads * g_sectors); | ||
507 | first *= g_heads * g_sectors; | ||
508 | } | ||
505 | if (n == 2 && first != 0) | 509 | if (n == 2 && first != 0) |
506 | printf("\ | 510 | printf("\ |
507 | It is highly recommended that the third partition covers the whole disk\n\ | 511 | It is highly recommended that the third partition covers the whole disk\n\ |
diff --git a/util-linux/losetup.c b/util-linux/losetup.c index 21108d0bf..c69763335 100644 --- a/util-linux/losetup.c +++ b/util-linux/losetup.c | |||
@@ -8,16 +8,16 @@ | |||
8 | */ | 8 | */ |
9 | 9 | ||
10 | //usage:#define losetup_trivial_usage | 10 | //usage:#define losetup_trivial_usage |
11 | //usage: "[-r] [-o OFS] LOOPDEV FILE - associate loop devices\n" | 11 | //usage: "[-r] [-o OFS] {-f|LOOPDEV} FILE - associate loop devices\n" |
12 | //usage: " losetup -d LOOPDEV - disassociate\n" | 12 | //usage: " losetup -d LOOPDEV - disassociate\n" |
13 | //usage: " losetup [-f] - show" | 13 | //usage: " losetup -a - show status of all\n" |
14 | //usage: " losetup -f - show next available" | ||
14 | //usage:#define losetup_full_usage "\n\n" | 15 | //usage:#define losetup_full_usage "\n\n" |
15 | //usage: " -o OFS Start OFS bytes into FILE" | 16 | //usage: " -o OFS Start OFS bytes into FILE" |
16 | //usage: "\n -r Read-only" | 17 | //usage: "\n -r Read-only" |
17 | //usage: "\n -f Show first free loop device" | 18 | //usage: "\n -f Show/find first free loop device" |
18 | //usage: | 19 | //usage: |
19 | //usage:#define losetup_notes_usage | 20 | //usage:#define losetup_notes_usage |
20 | //usage: "No arguments will display all current associations.\n" | ||
21 | //usage: "One argument (losetup /dev/loop1) will display the current association\n" | 21 | //usage: "One argument (losetup /dev/loop1) will display the current association\n" |
22 | //usage: "(if any), or disassociate it (with -d). The display shows the offset\n" | 22 | //usage: "(if any), or disassociate it (with -d). The display shows the offset\n" |
23 | //usage: "and filename of the file the loop device is currently bound to.\n\n" | 23 | //usage: "and filename of the file the loop device is currently bound to.\n\n" |
@@ -31,77 +31,91 @@ int losetup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | |||
31 | int losetup_main(int argc UNUSED_PARAM, char **argv) | 31 | int losetup_main(int argc UNUSED_PARAM, char **argv) |
32 | { | 32 | { |
33 | unsigned opt; | 33 | unsigned opt; |
34 | int n; | ||
35 | char *opt_o; | 34 | char *opt_o; |
36 | unsigned long long offset = 0; | 35 | char dev[LOOP_NAMESIZE]; |
37 | enum { | 36 | enum { |
38 | OPT_d = (1 << 0), | 37 | OPT_d = (1 << 0), |
39 | OPT_o = (1 << 1), | 38 | OPT_o = (1 << 1), |
40 | OPT_f = (1 << 2), | 39 | OPT_f = (1 << 2), |
41 | OPT_r = (1 << 3), /* must be last */ | 40 | OPT_a = (1 << 3), |
41 | OPT_r = (1 << 4), /* must be last */ | ||
42 | }; | 42 | }; |
43 | 43 | ||
44 | /* max 2 args, -d,-o,-f opts are mutually exclusive */ | 44 | opt_complementary = "?2:d--ofar:a--ofr"; |
45 | opt_complementary = "?2:d--of:o--df:f--do"; | 45 | opt = getopt32(argv, "do:far", &opt_o); |
46 | opt = getopt32(argv, "do:fr", &opt_o); | ||
47 | argv += optind; | 46 | argv += optind; |
48 | 47 | ||
49 | if (opt == OPT_o) | 48 | /* LOOPDEV */ |
50 | offset = xatoull(opt_o); | 49 | if (!opt && argv[0] && !argv[1]) { |
50 | char *s; | ||
51 | 51 | ||
52 | s = query_loop(argv[0]); | ||
53 | if (!s) | ||
54 | bb_simple_perror_msg_and_die(argv[0]); | ||
55 | printf("%s: %s\n", argv[0], s); | ||
56 | if (ENABLE_FEATURE_CLEAN_UP) | ||
57 | free(s); | ||
58 | return EXIT_SUCCESS; | ||
59 | } | ||
60 | |||
61 | /* -d LOOPDEV */ | ||
52 | if (opt == OPT_d) { | 62 | if (opt == OPT_d) { |
53 | /* -d BLOCKDEV */ | ||
54 | if (!argv[0] || argv[1]) | ||
55 | bb_show_usage(); | ||
56 | if (del_loop(argv[0])) | 63 | if (del_loop(argv[0])) |
57 | bb_simple_perror_msg_and_die(argv[0]); | 64 | bb_simple_perror_msg_and_die(argv[0]); |
58 | return EXIT_SUCCESS; | 65 | return EXIT_SUCCESS; |
59 | } | 66 | } |
60 | 67 | ||
61 | if (argv[0]) { | 68 | /* -a */ |
62 | char *s; | 69 | if (opt == OPT_a) { |
63 | 70 | int n; | |
64 | if (opt == OPT_f) /* -f should not have arguments */ | 71 | for (n = 0; n < 10; n++) { |
65 | bb_show_usage(); | 72 | char *s; |
66 | 73 | ||
67 | if (argv[1]) { | 74 | sprintf(dev, LOOP_FORMAT, n); |
68 | /* [-r] [-o OFS] BLOCKDEV FILE */ | 75 | s = query_loop(dev); |
69 | if (set_loop(&argv[0], argv[1], offset, (opt / OPT_r)) < 0) | 76 | if (s) { |
70 | bb_simple_perror_msg_and_die(argv[0]); | 77 | printf("%s: %s\n", dev, s); |
71 | return EXIT_SUCCESS; | 78 | if (ENABLE_FEATURE_CLEAN_UP) |
79 | free(s); | ||
80 | } | ||
72 | } | 81 | } |
73 | /* [-r] [-o OFS] BLOCKDEV */ | ||
74 | s = query_loop(argv[0]); | ||
75 | if (!s) | ||
76 | bb_simple_perror_msg_and_die(argv[0]); | ||
77 | printf("%s: %s\n", argv[0], s); | ||
78 | if (ENABLE_FEATURE_CLEAN_UP) | ||
79 | free(s); | ||
80 | return EXIT_SUCCESS; | 82 | return EXIT_SUCCESS; |
81 | } | 83 | } |
82 | 84 | ||
83 | /* [-r] [-o OFS|-f] with no params */ | 85 | /* contains -f */ |
84 | n = 0; | 86 | if (opt & OPT_f) { |
85 | while (1) { | ||
86 | char *s; | 87 | char *s; |
87 | char dev[LOOP_NAMESIZE]; | 88 | int n = 0; |
88 | 89 | ||
89 | sprintf(dev, LOOP_FORMAT, n); | 90 | do { |
90 | s = query_loop(dev); | 91 | sprintf(dev, LOOP_FORMAT, n); |
91 | n++; | 92 | s = query_loop(dev); |
92 | if (!s) { | 93 | if (s && ENABLE_FEATURE_CLEAN_UP) |
93 | if (n > 9 && errno && errno != ENXIO) | ||
94 | return EXIT_SUCCESS; | ||
95 | if (opt == OPT_f) { | ||
96 | puts(dev); | ||
97 | return EXIT_SUCCESS; | ||
98 | } | ||
99 | } else { | ||
100 | if (opt != OPT_f) | ||
101 | printf("%s: %s\n", dev, s); | ||
102 | if (ENABLE_FEATURE_CLEAN_UP) | ||
103 | free(s); | 94 | free(s); |
95 | } while (s); | ||
96 | if ((opt == OPT_f) && !argv[0]) { | ||
97 | puts(dev); | ||
98 | return EXIT_SUCCESS; | ||
104 | } | 99 | } |
105 | } | 100 | } |
106 | return EXIT_SUCCESS; | 101 | |
102 | /* [-r] [-o OFS] {-f|LOOPDEV} FILE */ | ||
103 | if (argv[0] && ((opt & OPT_f) || argv[1])) { | ||
104 | unsigned long long offset = 0; | ||
105 | char *d = dev; | ||
106 | |||
107 | if (opt == OPT_o) | ||
108 | offset = xatoull(opt_o); | ||
109 | if (opt != OPT_f) | ||
110 | d = *(argv++); | ||
111 | |||
112 | if (argv[0]) { | ||
113 | if (set_loop(&d, argv[0], offset, (opt / OPT_r)) < 0) | ||
114 | bb_simple_perror_msg_and_die(argv[0]); | ||
115 | return EXIT_SUCCESS; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | bb_show_usage(); | ||
120 | return EXIT_FAILURE; | ||
107 | } | 121 | } |
diff --git a/util-linux/mdev.c b/util-linux/mdev.c index c592ef687..5fe6bbbde 100644 --- a/util-linux/mdev.c +++ b/util-linux/mdev.c | |||
@@ -80,7 +80,7 @@ | |||
80 | //usage: IF_FEATURE_MDEV_CONF( | 80 | //usage: IF_FEATURE_MDEV_CONF( |
81 | //usage: "\n" | 81 | //usage: "\n" |
82 | //usage: "It uses /etc/mdev.conf with lines\n" | 82 | //usage: "It uses /etc/mdev.conf with lines\n" |
83 | //usage: " [-]DEVNAME UID:GID PERM" | 83 | //usage: " [-][ENV=regex;]...DEVNAME UID:GID PERM" |
84 | //usage: IF_FEATURE_MDEV_RENAME(" [>|=PATH]|[!]") | 84 | //usage: IF_FEATURE_MDEV_RENAME(" [>|=PATH]|[!]") |
85 | //usage: IF_FEATURE_MDEV_EXEC(" [@|$|*PROG]") | 85 | //usage: IF_FEATURE_MDEV_EXEC(" [@|$|*PROG]") |
86 | //usage: "\n" | 86 | //usage: "\n" |
@@ -230,9 +230,34 @@ | |||
230 | * SUBSYSTEM=block | 230 | * SUBSYSTEM=block |
231 | */ | 231 | */ |
232 | 232 | ||
233 | static const char keywords[] ALIGN1 = "add\0remove\0change\0"; | 233 | #define DEBUG_LVL 2 |
234 | |||
235 | #if DEBUG_LVL >= 1 | ||
236 | # define dbg1(...) do { if (G.verbose) bb_error_msg(__VA_ARGS__); } while(0) | ||
237 | #else | ||
238 | # define dbg1(...) ((void)0) | ||
239 | #endif | ||
240 | #if DEBUG_LVL >= 2 | ||
241 | # define dbg2(...) do { if (G.verbose >= 2) bb_error_msg(__VA_ARGS__); } while(0) | ||
242 | #else | ||
243 | # define dbg2(...) ((void)0) | ||
244 | #endif | ||
245 | #if DEBUG_LVL >= 3 | ||
246 | # define dbg3(...) do { if (G.verbose >= 3) bb_error_msg(__VA_ARGS__); } while(0) | ||
247 | #else | ||
248 | # define dbg3(...) ((void)0) | ||
249 | #endif | ||
250 | |||
251 | |||
252 | static const char keywords[] ALIGN1 = "add\0remove\0"; // "change\0" | ||
234 | enum { OP_add, OP_remove }; | 253 | enum { OP_add, OP_remove }; |
235 | 254 | ||
255 | struct envmatch { | ||
256 | struct envmatch *next; | ||
257 | char *envname; | ||
258 | regex_t match; | ||
259 | }; | ||
260 | |||
236 | struct rule { | 261 | struct rule { |
237 | bool keep_matching; | 262 | bool keep_matching; |
238 | bool regex_compiled; | 263 | bool regex_compiled; |
@@ -243,12 +268,14 @@ struct rule { | |||
243 | char *ren_mov; | 268 | char *ren_mov; |
244 | IF_FEATURE_MDEV_EXEC(char *r_cmd;) | 269 | IF_FEATURE_MDEV_EXEC(char *r_cmd;) |
245 | regex_t match; | 270 | regex_t match; |
271 | struct envmatch *envmatch; | ||
246 | }; | 272 | }; |
247 | 273 | ||
248 | struct globals { | 274 | struct globals { |
249 | int root_major, root_minor; | 275 | int root_major, root_minor; |
250 | smallint verbose; | 276 | smallint verbose; |
251 | char *subsystem; | 277 | char *subsystem; |
278 | char *subsys_env; /* for putenv("SUBSYSTEM=subsystem") */ | ||
252 | #if ENABLE_FEATURE_MDEV_CONF | 279 | #if ENABLE_FEATURE_MDEV_CONF |
253 | const char *filename; | 280 | const char *filename; |
254 | parser_t *parser; | 281 | parser_t *parser; |
@@ -256,6 +283,7 @@ struct globals { | |||
256 | unsigned rule_idx; | 283 | unsigned rule_idx; |
257 | #endif | 284 | #endif |
258 | struct rule cur_rule; | 285 | struct rule cur_rule; |
286 | char timestr[sizeof("60.123456")]; | ||
259 | } FIX_ALIASING; | 287 | } FIX_ALIASING; |
260 | #define G (*(struct globals*)&bb_common_bufsiz1) | 288 | #define G (*(struct globals*)&bb_common_bufsiz1) |
261 | #define INIT_G() do { \ | 289 | #define INIT_G() do { \ |
@@ -270,13 +298,6 @@ struct globals { | |||
270 | /* We use additional 64+ bytes in make_device() */ | 298 | /* We use additional 64+ bytes in make_device() */ |
271 | #define SCRATCH_SIZE 80 | 299 | #define SCRATCH_SIZE 80 |
272 | 300 | ||
273 | #if 0 | ||
274 | # define dbg(...) bb_error_msg(__VA_ARGS__) | ||
275 | #else | ||
276 | # define dbg(...) ((void)0) | ||
277 | #endif | ||
278 | |||
279 | |||
280 | #if ENABLE_FEATURE_MDEV_CONF | 301 | #if ENABLE_FEATURE_MDEV_CONF |
281 | 302 | ||
282 | static void make_default_cur_rule(void) | 303 | static void make_default_cur_rule(void) |
@@ -288,14 +309,48 @@ static void make_default_cur_rule(void) | |||
288 | 309 | ||
289 | static void clean_up_cur_rule(void) | 310 | static void clean_up_cur_rule(void) |
290 | { | 311 | { |
312 | struct envmatch *e; | ||
313 | |||
291 | free(G.cur_rule.envvar); | 314 | free(G.cur_rule.envvar); |
315 | free(G.cur_rule.ren_mov); | ||
292 | if (G.cur_rule.regex_compiled) | 316 | if (G.cur_rule.regex_compiled) |
293 | regfree(&G.cur_rule.match); | 317 | regfree(&G.cur_rule.match); |
294 | free(G.cur_rule.ren_mov); | ||
295 | IF_FEATURE_MDEV_EXEC(free(G.cur_rule.r_cmd);) | 318 | IF_FEATURE_MDEV_EXEC(free(G.cur_rule.r_cmd);) |
319 | e = G.cur_rule.envmatch; | ||
320 | while (e) { | ||
321 | free(e->envname); | ||
322 | regfree(&e->match); | ||
323 | e = e->next; | ||
324 | } | ||
296 | make_default_cur_rule(); | 325 | make_default_cur_rule(); |
297 | } | 326 | } |
298 | 327 | ||
328 | static char *parse_envmatch_pfx(char *val) | ||
329 | { | ||
330 | struct envmatch **nextp = &G.cur_rule.envmatch; | ||
331 | |||
332 | for (;;) { | ||
333 | struct envmatch *e; | ||
334 | char *semicolon; | ||
335 | char *eq = strchr(val, '='); | ||
336 | if (!eq /* || eq == val? */) | ||
337 | return val; | ||
338 | if (endofname(val) != eq) | ||
339 | return val; | ||
340 | semicolon = strchr(eq, ';'); | ||
341 | if (!semicolon) | ||
342 | return val; | ||
343 | /* ENVVAR=regex;... */ | ||
344 | *nextp = e = xzalloc(sizeof(*e)); | ||
345 | nextp = &e->next; | ||
346 | e->envname = xstrndup(val, eq - val); | ||
347 | *semicolon = '\0'; | ||
348 | xregcomp(&e->match, eq + 1, REG_EXTENDED); | ||
349 | *semicolon = ';'; | ||
350 | val = semicolon + 1; | ||
351 | } | ||
352 | } | ||
353 | |||
299 | static void parse_next_rule(void) | 354 | static void parse_next_rule(void) |
300 | { | 355 | { |
301 | /* Note: on entry, G.cur_rule is set to default */ | 356 | /* Note: on entry, G.cur_rule is set to default */ |
@@ -308,12 +363,13 @@ static void parse_next_rule(void) | |||
308 | break; | 363 | break; |
309 | 364 | ||
310 | /* Fields: [-]regex uid:gid mode [alias] [cmd] */ | 365 | /* Fields: [-]regex uid:gid mode [alias] [cmd] */ |
311 | dbg("token1:'%s'", tokens[1]); | 366 | dbg3("token1:'%s'", tokens[1]); |
312 | 367 | ||
313 | /* 1st field */ | 368 | /* 1st field */ |
314 | val = tokens[0]; | 369 | val = tokens[0]; |
315 | G.cur_rule.keep_matching = ('-' == val[0]); | 370 | G.cur_rule.keep_matching = ('-' == val[0]); |
316 | val += G.cur_rule.keep_matching; /* swallow leading dash */ | 371 | val += G.cur_rule.keep_matching; /* swallow leading dash */ |
372 | val = parse_envmatch_pfx(val); | ||
317 | if (val[0] == '@') { | 373 | if (val[0] == '@') { |
318 | /* @major,minor[-minor2] */ | 374 | /* @major,minor[-minor2] */ |
319 | /* (useful when name is ambiguous: | 375 | /* (useful when name is ambiguous: |
@@ -328,8 +384,10 @@ static void parse_next_rule(void) | |||
328 | if (sc == 2) | 384 | if (sc == 2) |
329 | G.cur_rule.min1 = G.cur_rule.min0; | 385 | G.cur_rule.min1 = G.cur_rule.min0; |
330 | } else { | 386 | } else { |
387 | char *eq = strchr(val, '='); | ||
331 | if (val[0] == '$') { | 388 | if (val[0] == '$') { |
332 | char *eq = strchr(++val, '='); | 389 | /* $ENVVAR=regex ... */ |
390 | val++; | ||
333 | if (!eq) { | 391 | if (!eq) { |
334 | bb_error_msg("bad $envvar=regex on line %d", G.parser->lineno); | 392 | bb_error_msg("bad $envvar=regex on line %d", G.parser->lineno); |
335 | goto next_rule; | 393 | goto next_rule; |
@@ -373,7 +431,7 @@ static void parse_next_rule(void) | |||
373 | clean_up_cur_rule(); | 431 | clean_up_cur_rule(); |
374 | } /* while (config_read) */ | 432 | } /* while (config_read) */ |
375 | 433 | ||
376 | dbg("config_close(G.parser)"); | 434 | dbg3("config_close(G.parser)"); |
377 | config_close(G.parser); | 435 | config_close(G.parser); |
378 | G.parser = NULL; | 436 | G.parser = NULL; |
379 | 437 | ||
@@ -390,7 +448,7 @@ static const struct rule *next_rule(void) | |||
390 | 448 | ||
391 | /* Open conf file if we didn't do it yet */ | 449 | /* Open conf file if we didn't do it yet */ |
392 | if (!G.parser && G.filename) { | 450 | if (!G.parser && G.filename) { |
393 | dbg("config_open('%s')", G.filename); | 451 | dbg3("config_open('%s')", G.filename); |
394 | G.parser = config_open2(G.filename, fopen_for_read); | 452 | G.parser = config_open2(G.filename, fopen_for_read); |
395 | G.filename = NULL; | 453 | G.filename = NULL; |
396 | } | 454 | } |
@@ -399,7 +457,7 @@ static const struct rule *next_rule(void) | |||
399 | /* mdev -s */ | 457 | /* mdev -s */ |
400 | /* Do we have rule parsed already? */ | 458 | /* Do we have rule parsed already? */ |
401 | if (G.rule_vec[G.rule_idx]) { | 459 | if (G.rule_vec[G.rule_idx]) { |
402 | dbg("< G.rule_vec[G.rule_idx:%d]=%p", G.rule_idx, G.rule_vec[G.rule_idx]); | 460 | dbg3("< G.rule_vec[G.rule_idx:%d]=%p", G.rule_idx, G.rule_vec[G.rule_idx]); |
403 | return G.rule_vec[G.rule_idx++]; | 461 | return G.rule_vec[G.rule_idx++]; |
404 | } | 462 | } |
405 | make_default_cur_rule(); | 463 | make_default_cur_rule(); |
@@ -416,13 +474,28 @@ static const struct rule *next_rule(void) | |||
416 | rule = memcpy(xmalloc(sizeof(G.cur_rule)), &G.cur_rule, sizeof(G.cur_rule)); | 474 | rule = memcpy(xmalloc(sizeof(G.cur_rule)), &G.cur_rule, sizeof(G.cur_rule)); |
417 | G.rule_vec = xrealloc_vector(G.rule_vec, 4, G.rule_idx); | 475 | G.rule_vec = xrealloc_vector(G.rule_vec, 4, G.rule_idx); |
418 | G.rule_vec[G.rule_idx++] = rule; | 476 | G.rule_vec[G.rule_idx++] = rule; |
419 | dbg("> G.rule_vec[G.rule_idx:%d]=%p", G.rule_idx, G.rule_vec[G.rule_idx]); | 477 | dbg3("> G.rule_vec[G.rule_idx:%d]=%p", G.rule_idx, G.rule_vec[G.rule_idx]); |
420 | } | 478 | } |
421 | } | 479 | } |
422 | 480 | ||
423 | return rule; | 481 | return rule; |
424 | } | 482 | } |
425 | 483 | ||
484 | static int env_matches(struct envmatch *e) | ||
485 | { | ||
486 | while (e) { | ||
487 | int r; | ||
488 | char *val = getenv(e->envname); | ||
489 | if (!val) | ||
490 | return 0; | ||
491 | r = regexec(&e->match, val, /*size*/ 0, /*range[]*/ NULL, /*eflags*/ 0); | ||
492 | if (r != 0) /* no match */ | ||
493 | return 0; | ||
494 | e = e->next; | ||
495 | } | ||
496 | return 1; | ||
497 | } | ||
498 | |||
426 | #else | 499 | #else |
427 | 500 | ||
428 | # define next_rule() (&G.cur_rule) | 501 | # define next_rule() (&G.cur_rule) |
@@ -479,9 +552,6 @@ static void make_device(char *device_name, char *path, int operation) | |||
479 | { | 552 | { |
480 | int major, minor, type, len; | 553 | int major, minor, type, len; |
481 | 554 | ||
482 | if (G.verbose) | ||
483 | bb_error_msg("device: %s, %s", device_name, path); | ||
484 | |||
485 | /* Try to read major/minor string. Note that the kernel puts \n after | 555 | /* Try to read major/minor string. Note that the kernel puts \n after |
486 | * the data, so we don't need to worry about null terminating the string | 556 | * the data, so we don't need to worry about null terminating the string |
487 | * because sscanf() will stop at the first nondigit, which \n is. | 557 | * because sscanf() will stop at the first nondigit, which \n is. |
@@ -500,8 +570,7 @@ static void make_device(char *device_name, char *path, int operation) | |||
500 | /* no "dev" file, but we can still run scripts | 570 | /* no "dev" file, but we can still run scripts |
501 | * based on device name */ | 571 | * based on device name */ |
502 | } else if (sscanf(++dev_maj_min, "%u:%u", &major, &minor) == 2) { | 572 | } else if (sscanf(++dev_maj_min, "%u:%u", &major, &minor) == 2) { |
503 | if (G.verbose) | 573 | dbg1("dev %u,%u", major, minor); |
504 | bb_error_msg("maj,min: %u,%u", major, minor); | ||
505 | } else { | 574 | } else { |
506 | major = -1; | 575 | major = -1; |
507 | } | 576 | } |
@@ -511,7 +580,8 @@ static void make_device(char *device_name, char *path, int operation) | |||
511 | /* Determine device name, type, major and minor */ | 580 | /* Determine device name, type, major and minor */ |
512 | if (!device_name) | 581 | if (!device_name) |
513 | device_name = (char*) bb_basename(path); | 582 | device_name = (char*) bb_basename(path); |
514 | /* http://kernel.org/doc/pending/hotplug.txt says that only | 583 | /* |
584 | * http://kernel.org/doc/pending/hotplug.txt says that only | ||
515 | * "/sys/block/..." is for block devices. "/sys/bus" etc is not. | 585 | * "/sys/block/..." is for block devices. "/sys/bus" etc is not. |
516 | * But since 2.6.25 block devices are also in /sys/class/block. | 586 | * But since 2.6.25 block devices are also in /sys/class/block. |
517 | * We use strstr("/block/") to forestall future surprises. | 587 | * We use strstr("/block/") to forestall future surprises. |
@@ -537,6 +607,8 @@ static void make_device(char *device_name, char *path, int operation) | |||
537 | rule = next_rule(); | 607 | rule = next_rule(); |
538 | 608 | ||
539 | #if ENABLE_FEATURE_MDEV_CONF | 609 | #if ENABLE_FEATURE_MDEV_CONF |
610 | if (!env_matches(rule->envmatch)) | ||
611 | continue; | ||
540 | if (rule->maj >= 0) { /* @maj,min rule */ | 612 | if (rule->maj >= 0) { /* @maj,min rule */ |
541 | if (major != rule->maj) | 613 | if (major != rule->maj) |
542 | continue; | 614 | continue; |
@@ -547,7 +619,7 @@ static void make_device(char *device_name, char *path, int operation) | |||
547 | } | 619 | } |
548 | if (rule->envvar) { /* $envvar=regex rule */ | 620 | if (rule->envvar) { /* $envvar=regex rule */ |
549 | str_to_match = getenv(rule->envvar); | 621 | str_to_match = getenv(rule->envvar); |
550 | dbg("getenv('%s'):'%s'", rule->envvar, str_to_match); | 622 | dbg3("getenv('%s'):'%s'", rule->envvar, str_to_match); |
551 | if (!str_to_match) | 623 | if (!str_to_match) |
552 | continue; | 624 | continue; |
553 | } | 625 | } |
@@ -555,7 +627,7 @@ static void make_device(char *device_name, char *path, int operation) | |||
555 | 627 | ||
556 | if (rule->regex_compiled) { | 628 | if (rule->regex_compiled) { |
557 | int regex_match = regexec(&rule->match, str_to_match, ARRAY_SIZE(off), off, 0); | 629 | int regex_match = regexec(&rule->match, str_to_match, ARRAY_SIZE(off), off, 0); |
558 | dbg("regex_match for '%s':%d", str_to_match, regex_match); | 630 | dbg3("regex_match for '%s':%d", str_to_match, regex_match); |
559 | //bb_error_msg("matches:"); | 631 | //bb_error_msg("matches:"); |
560 | //for (int i = 0; i < ARRAY_SIZE(off); i++) { | 632 | //for (int i = 0; i < ARRAY_SIZE(off); i++) { |
561 | // if (off[i].rm_so < 0) continue; | 633 | // if (off[i].rm_so < 0) continue; |
@@ -574,9 +646,8 @@ static void make_device(char *device_name, char *path, int operation) | |||
574 | } | 646 | } |
575 | /* else: it's final implicit "match-all" rule */ | 647 | /* else: it's final implicit "match-all" rule */ |
576 | rule_matches: | 648 | rule_matches: |
649 | dbg2("rule matched, line %d", G.parser ? G.parser->lineno : -1); | ||
577 | #endif | 650 | #endif |
578 | dbg("rule matched"); | ||
579 | |||
580 | /* Build alias name */ | 651 | /* Build alias name */ |
581 | alias = NULL; | 652 | alias = NULL; |
582 | if (ENABLE_FEATURE_MDEV_RENAME && rule->ren_mov) { | 653 | if (ENABLE_FEATURE_MDEV_RENAME && rule->ren_mov) { |
@@ -619,34 +690,30 @@ static void make_device(char *device_name, char *path, int operation) | |||
619 | } | 690 | } |
620 | } | 691 | } |
621 | } | 692 | } |
622 | dbg("alias:'%s'", alias); | 693 | dbg3("alias:'%s'", alias); |
623 | 694 | ||
624 | command = NULL; | 695 | command = NULL; |
625 | IF_FEATURE_MDEV_EXEC(command = rule->r_cmd;) | 696 | IF_FEATURE_MDEV_EXEC(command = rule->r_cmd;) |
626 | if (command) { | 697 | if (command) { |
627 | const char *s = "$@*"; | ||
628 | const char *s2 = strchr(s, command[0]); | ||
629 | |||
630 | /* Are we running this command now? | 698 | /* Are we running this command now? |
631 | * Run $cmd on delete, @cmd on create, *cmd on both | 699 | * Run @cmd on create, $cmd on delete, *cmd on any |
632 | */ | 700 | */ |
633 | if (s2 - s != (operation == OP_remove) || *s2 == '*') { | 701 | if ((command[0] == '@' && operation == OP_add) |
634 | /* We are here if: '*', | 702 | || (command[0] == '$' && operation == OP_remove) |
635 | * or: '@' and delete = 0, | 703 | || (command[0] == '*') |
636 | * or: '$' and delete = 1 | 704 | ) { |
637 | */ | ||
638 | command++; | 705 | command++; |
639 | } else { | 706 | } else { |
640 | command = NULL; | 707 | command = NULL; |
641 | } | 708 | } |
642 | } | 709 | } |
643 | dbg("command:'%s'", command); | 710 | dbg3("command:'%s'", command); |
644 | 711 | ||
645 | /* "Execute" the line we found */ | 712 | /* "Execute" the line we found */ |
646 | node_name = device_name; | 713 | node_name = device_name; |
647 | if (ENABLE_FEATURE_MDEV_RENAME && alias) { | 714 | if (ENABLE_FEATURE_MDEV_RENAME && alias) { |
648 | node_name = alias = build_alias(alias, device_name); | 715 | node_name = alias = build_alias(alias, device_name); |
649 | dbg("alias2:'%s'", alias); | 716 | dbg3("alias2:'%s'", alias); |
650 | } | 717 | } |
651 | 718 | ||
652 | if (operation == OP_add && major >= 0) { | 719 | if (operation == OP_add && major >= 0) { |
@@ -656,13 +723,20 @@ static void make_device(char *device_name, char *path, int operation) | |||
656 | mkdir_recursive(node_name); | 723 | mkdir_recursive(node_name); |
657 | *slash = '/'; | 724 | *slash = '/'; |
658 | } | 725 | } |
659 | if (G.verbose) | 726 | if (ENABLE_FEATURE_MDEV_CONF) { |
660 | bb_error_msg("mknod: %s (%d,%d) %o", node_name, major, minor, rule->mode | type); | 727 | dbg1("mknod %s (%d,%d) %o" |
728 | " %u:%u", | ||
729 | node_name, major, minor, rule->mode | type, | ||
730 | rule->ugid.uid, rule->ugid.gid | ||
731 | ); | ||
732 | } else { | ||
733 | dbg1("mknod %s (%d,%d) %o", | ||
734 | node_name, major, minor, rule->mode | type | ||
735 | ); | ||
736 | } | ||
661 | if (mknod(node_name, rule->mode | type, makedev(major, minor)) && errno != EEXIST) | 737 | if (mknod(node_name, rule->mode | type, makedev(major, minor)) && errno != EEXIST) |
662 | bb_perror_msg("can't create '%s'", node_name); | 738 | bb_perror_msg("can't create '%s'", node_name); |
663 | if (ENABLE_FEATURE_MDEV_CONF) { | 739 | if (ENABLE_FEATURE_MDEV_CONF) { |
664 | if (G.verbose) | ||
665 | bb_error_msg("chmod: %o chown: %u:%u", rule->mode, rule->ugid.uid, rule->ugid.gid); | ||
666 | chmod(node_name, rule->mode); | 740 | chmod(node_name, rule->mode); |
667 | chown(node_name, rule->ugid.uid, rule->ugid.gid); | 741 | chown(node_name, rule->ugid.uid, rule->ugid.gid); |
668 | } | 742 | } |
@@ -673,8 +747,7 @@ static void make_device(char *device_name, char *path, int operation) | |||
673 | //TODO: on devtmpfs, device_name already exists and symlink() fails. | 747 | //TODO: on devtmpfs, device_name already exists and symlink() fails. |
674 | //End result is that instead of symlink, we have two nodes. | 748 | //End result is that instead of symlink, we have two nodes. |
675 | //What should be done? | 749 | //What should be done? |
676 | if (G.verbose) | 750 | dbg1("symlink: %s", device_name); |
677 | bb_error_msg("symlink: %s", device_name); | ||
678 | symlink(node_name, device_name); | 751 | symlink(node_name, device_name); |
679 | } | 752 | } |
680 | } | 753 | } |
@@ -683,27 +756,21 @@ static void make_device(char *device_name, char *path, int operation) | |||
683 | if (ENABLE_FEATURE_MDEV_EXEC && command) { | 756 | if (ENABLE_FEATURE_MDEV_EXEC && command) { |
684 | /* setenv will leak memory, use putenv/unsetenv/free */ | 757 | /* setenv will leak memory, use putenv/unsetenv/free */ |
685 | char *s = xasprintf("%s=%s", "MDEV", node_name); | 758 | char *s = xasprintf("%s=%s", "MDEV", node_name); |
686 | char *s1 = xasprintf("%s=%s", "SUBSYSTEM", G.subsystem); | ||
687 | putenv(s); | 759 | putenv(s); |
688 | putenv(s1); | 760 | dbg1("running: %s", command); |
689 | if (G.verbose) | ||
690 | bb_error_msg("running: %s", command); | ||
691 | if (system(command) == -1) | 761 | if (system(command) == -1) |
692 | bb_perror_msg("can't run '%s'", command); | 762 | bb_perror_msg("can't run '%s'", command); |
693 | bb_unsetenv_and_free(s1); | ||
694 | bb_unsetenv_and_free(s); | 763 | bb_unsetenv_and_free(s); |
695 | } | 764 | } |
696 | 765 | ||
697 | if (operation == OP_remove && major >= -1) { | 766 | if (operation == OP_remove && major >= -1) { |
698 | if (ENABLE_FEATURE_MDEV_RENAME && alias) { | 767 | if (ENABLE_FEATURE_MDEV_RENAME && alias) { |
699 | if (aliaslink == '>') { | 768 | if (aliaslink == '>') { |
700 | if (G.verbose) | 769 | dbg1("unlink: %s", device_name); |
701 | bb_error_msg("unlink: %s", device_name); | ||
702 | unlink(device_name); | 770 | unlink(device_name); |
703 | } | 771 | } |
704 | } | 772 | } |
705 | if (G.verbose) | 773 | dbg1("unlink: %s", node_name); |
706 | bb_error_msg("unlink: %s", node_name); | ||
707 | unlink(node_name); | 774 | unlink(node_name); |
708 | } | 775 | } |
709 | 776 | ||
@@ -748,9 +815,16 @@ static int FAST_FUNC dirAction(const char *fileName UNUSED_PARAM, | |||
748 | * under /sys/class/ */ | 815 | * under /sys/class/ */ |
749 | if (1 == depth) { | 816 | if (1 == depth) { |
750 | free(G.subsystem); | 817 | free(G.subsystem); |
818 | if (G.subsys_env) { | ||
819 | bb_unsetenv_and_free(G.subsys_env); | ||
820 | G.subsys_env = NULL; | ||
821 | } | ||
751 | G.subsystem = strrchr(fileName, '/'); | 822 | G.subsystem = strrchr(fileName, '/'); |
752 | if (G.subsystem) | 823 | if (G.subsystem) { |
753 | G.subsystem = xstrdup(G.subsystem + 1); | 824 | G.subsystem = xstrdup(G.subsystem + 1); |
825 | G.subsys_env = xasprintf("%s=%s", "SUBSYSTEM", G.subsystem); | ||
826 | putenv(G.subsys_env); | ||
827 | } | ||
754 | } | 828 | } |
755 | 829 | ||
756 | return (depth >= MAX_SYSFS_DEPTH ? SKIP : TRUE); | 830 | return (depth >= MAX_SYSFS_DEPTH ? SKIP : TRUE); |
@@ -822,6 +896,100 @@ static void load_firmware(const char *firmware, const char *sysfs_path) | |||
822 | } | 896 | } |
823 | } | 897 | } |
824 | 898 | ||
899 | static char *curtime(void) | ||
900 | { | ||
901 | struct timeval tv; | ||
902 | gettimeofday(&tv, NULL); | ||
903 | sprintf(G.timestr, "%u.%06u", (unsigned)tv.tv_sec % 60, (unsigned)tv.tv_usec); | ||
904 | return G.timestr; | ||
905 | } | ||
906 | |||
907 | static void open_mdev_log(const char *seq, unsigned my_pid) | ||
908 | { | ||
909 | int logfd = open("mdev.log", O_WRONLY | O_APPEND); | ||
910 | if (logfd >= 0) { | ||
911 | xmove_fd(logfd, STDERR_FILENO); | ||
912 | G.verbose = 2; | ||
913 | applet_name = xasprintf("%s[%s]", applet_name, seq ? seq : utoa(my_pid)); | ||
914 | } | ||
915 | } | ||
916 | |||
917 | /* If it exists, does /dev/mdev.seq match $SEQNUM? | ||
918 | * If it does not match, earlier mdev is running | ||
919 | * in parallel, and we need to wait. | ||
920 | * Active mdev pokes us with SIGCHLD to check the new file. | ||
921 | */ | ||
922 | static int | ||
923 | wait_for_seqfile(const char *seq) | ||
924 | { | ||
925 | /* We time out after 2 sec */ | ||
926 | static const struct timespec ts = { 0, 32*1000*1000 }; | ||
927 | int timeout = 2000 / 32; | ||
928 | int seq_fd = -1; | ||
929 | int do_once = 1; | ||
930 | sigset_t set_CHLD; | ||
931 | |||
932 | sigemptyset(&set_CHLD); | ||
933 | sigaddset(&set_CHLD, SIGCHLD); | ||
934 | sigprocmask(SIG_BLOCK, &set_CHLD, NULL); | ||
935 | |||
936 | for (;;) { | ||
937 | int seqlen; | ||
938 | char seqbuf[sizeof(int)*3 + 2]; | ||
939 | |||
940 | if (seq_fd < 0) { | ||
941 | seq_fd = open("mdev.seq", O_RDWR); | ||
942 | if (seq_fd < 0) | ||
943 | break; | ||
944 | } | ||
945 | seqlen = pread(seq_fd, seqbuf, sizeof(seqbuf) - 1, 0); | ||
946 | if (seqlen < 0) { | ||
947 | close(seq_fd); | ||
948 | seq_fd = -1; | ||
949 | break; | ||
950 | } | ||
951 | seqbuf[seqlen] = '\0'; | ||
952 | if (seqbuf[0] == '\n') { | ||
953 | /* seed file: write out seq ASAP */ | ||
954 | xwrite_str(seq_fd, seq); | ||
955 | xlseek(seq_fd, 0, SEEK_SET); | ||
956 | dbg2("first seq written"); | ||
957 | break; | ||
958 | } | ||
959 | if (strcmp(seq, seqbuf) == 0) { | ||
960 | /* correct idx */ | ||
961 | break; | ||
962 | } | ||
963 | if (do_once) { | ||
964 | dbg2("%s waiting for '%s'", curtime(), seqbuf); | ||
965 | do_once = 0; | ||
966 | } | ||
967 | if (sigtimedwait(&set_CHLD, NULL, &ts) >= 0) { | ||
968 | dbg3("woken up"); | ||
969 | continue; /* don't decrement timeout! */ | ||
970 | } | ||
971 | if (--timeout == 0) { | ||
972 | dbg1("%s waiting for '%s'", "timed out", seqbuf); | ||
973 | break; | ||
974 | } | ||
975 | } | ||
976 | sigprocmask(SIG_UNBLOCK, &set_CHLD, NULL); | ||
977 | return seq_fd; | ||
978 | } | ||
979 | |||
980 | static void signal_mdevs(unsigned my_pid) | ||
981 | { | ||
982 | procps_status_t* p = NULL; | ||
983 | while ((p = procps_scan(p, PSSCAN_ARGV0)) != NULL) { | ||
984 | if (p->pid != my_pid | ||
985 | && p->argv0 | ||
986 | && strcmp(bb_basename(p->argv0), "mdev") == 0 | ||
987 | ) { | ||
988 | kill(p->pid, SIGCHLD); | ||
989 | } | ||
990 | } | ||
991 | } | ||
992 | |||
825 | int mdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 993 | int mdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
826 | int mdev_main(int argc UNUSED_PARAM, char **argv) | 994 | int mdev_main(int argc UNUSED_PARAM, char **argv) |
827 | { | 995 | { |
@@ -843,8 +1011,8 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) | |||
843 | xchdir("/dev"); | 1011 | xchdir("/dev"); |
844 | 1012 | ||
845 | if (argv[1] && strcmp(argv[1], "-s") == 0) { | 1013 | if (argv[1] && strcmp(argv[1], "-s") == 0) { |
846 | /* Scan: | 1014 | /* |
847 | * mdev -s | 1015 | * Scan: mdev -s |
848 | */ | 1016 | */ |
849 | struct stat st; | 1017 | struct stat st; |
850 | 1018 | ||
@@ -856,6 +1024,8 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) | |||
856 | G.root_major = major(st.st_dev); | 1024 | G.root_major = major(st.st_dev); |
857 | G.root_minor = minor(st.st_dev); | 1025 | G.root_minor = minor(st.st_dev); |
858 | 1026 | ||
1027 | putenv((char*)"ACTION=add"); | ||
1028 | |||
859 | /* ACTION_FOLLOWLINKS is needed since in newer kernels | 1029 | /* ACTION_FOLLOWLINKS is needed since in newer kernels |
860 | * /sys/block/loop* (for example) are symlinks to dirs, | 1030 | * /sys/block/loop* (for example) are symlinks to dirs, |
861 | * not real directories. | 1031 | * not real directories. |
@@ -881,11 +1051,13 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) | |||
881 | char *action; | 1051 | char *action; |
882 | char *env_devname; | 1052 | char *env_devname; |
883 | char *env_devpath; | 1053 | char *env_devpath; |
1054 | unsigned my_pid; | ||
1055 | int seq_fd; | ||
884 | smalluint op; | 1056 | smalluint op; |
885 | 1057 | ||
886 | /* Hotplug: | 1058 | /* Hotplug: |
887 | * env ACTION=... DEVPATH=... SUBSYSTEM=... [SEQNUM=...] mdev | 1059 | * env ACTION=... DEVPATH=... SUBSYSTEM=... [SEQNUM=...] mdev |
888 | * ACTION can be "add" or "remove" | 1060 | * ACTION can be "add", "remove", "change" |
889 | * DEVPATH is like "/block/sda" or "/class/input/mice" | 1061 | * DEVPATH is like "/block/sda" or "/class/input/mice" |
890 | */ | 1062 | */ |
891 | action = getenv("ACTION"); | 1063 | action = getenv("ACTION"); |
@@ -896,41 +1068,20 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) | |||
896 | if (!action || !env_devpath /*|| !G.subsystem*/) | 1068 | if (!action || !env_devpath /*|| !G.subsystem*/) |
897 | bb_show_usage(); | 1069 | bb_show_usage(); |
898 | fw = getenv("FIRMWARE"); | 1070 | fw = getenv("FIRMWARE"); |
899 | /* If it exists, does /dev/mdev.seq match $SEQNUM? | ||
900 | * If it does not match, earlier mdev is running | ||
901 | * in parallel, and we need to wait */ | ||
902 | seq = getenv("SEQNUM"); | 1071 | seq = getenv("SEQNUM"); |
903 | if (seq) { | ||
904 | int timeout = 2000 / 32; /* 2000 msec */ | ||
905 | do { | ||
906 | int seqlen; | ||
907 | char seqbuf[sizeof(int)*3 + 2]; | ||
908 | |||
909 | seqlen = open_read_close("mdev.seq", seqbuf, sizeof(seqbuf) - 1); | ||
910 | if (seqlen < 0) { | ||
911 | seq = NULL; | ||
912 | break; | ||
913 | } | ||
914 | seqbuf[seqlen] = '\0'; | ||
915 | if (seqbuf[0] == '\n' /* seed file? */ | ||
916 | || strcmp(seq, seqbuf) == 0 /* correct idx? */ | ||
917 | ) { | ||
918 | break; | ||
919 | } | ||
920 | usleep(32*1000); | ||
921 | } while (--timeout); | ||
922 | } | ||
923 | 1072 | ||
924 | { | 1073 | my_pid = getpid(); |
925 | int logfd = open("mdev.log", O_WRONLY | O_APPEND); | 1074 | open_mdev_log(seq, my_pid); |
926 | if (logfd >= 0) { | 1075 | |
927 | xmove_fd(logfd, STDERR_FILENO); | 1076 | seq_fd = seq ? wait_for_seqfile(seq) : -1; |
928 | G.verbose = 1; | 1077 | |
929 | if (seq) | 1078 | dbg1("%s " |
930 | applet_name = xasprintf("%s[%s]", applet_name, seq); | 1079 | "ACTION:%s SUBSYSTEM:%s DEVNAME:%s DEVPATH:%s" |
931 | bb_error_msg("action: %s", action); | 1080 | "%s%s", |
932 | } | 1081 | curtime(), |
933 | } | 1082 | action, G.subsystem, env_devname, env_devpath, |
1083 | fw ? " FW:" : "", fw ? fw : "" | ||
1084 | ); | ||
934 | 1085 | ||
935 | snprintf(temp, PATH_MAX, "/sys%s", env_devpath); | 1086 | snprintf(temp, PATH_MAX, "/sys%s", env_devpath); |
936 | if (op == OP_remove) { | 1087 | if (op == OP_remove) { |
@@ -940,16 +1091,18 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) | |||
940 | if (!fw) | 1091 | if (!fw) |
941 | make_device(env_devname, temp, op); | 1092 | make_device(env_devname, temp, op); |
942 | } | 1093 | } |
943 | else if (op == OP_add) { | 1094 | else { |
944 | make_device(env_devname, temp, op); | 1095 | make_device(env_devname, temp, op); |
945 | if (ENABLE_FEATURE_MDEV_LOAD_FIRMWARE) { | 1096 | if (ENABLE_FEATURE_MDEV_LOAD_FIRMWARE) { |
946 | if (fw) | 1097 | if (op == OP_add && fw) |
947 | load_firmware(fw, temp); | 1098 | load_firmware(fw, temp); |
948 | } | 1099 | } |
949 | } | 1100 | } |
950 | 1101 | ||
951 | if (seq) { | 1102 | dbg1("%s exiting", curtime()); |
952 | xopen_xwrite_close("mdev.seq", utoa(xatou(seq) + 1)); | 1103 | if (seq_fd >= 0) { |
1104 | xwrite_str(seq_fd, utoa(xatou(seq) + 1)); | ||
1105 | signal_mdevs(my_pid); | ||
953 | } | 1106 | } |
954 | } | 1107 | } |
955 | 1108 | ||
diff --git a/util-linux/mkfs_minix.c b/util-linux/mkfs_minix.c index 59d7d23d4..49afd1176 100644 --- a/util-linux/mkfs_minix.c +++ b/util-linux/mkfs_minix.c | |||
@@ -196,54 +196,6 @@ static void minix_clrbit(char *a, unsigned i) | |||
196 | # define BLKGETSIZE _IO(0x12,96) /* return device size */ | 196 | # define BLKGETSIZE _IO(0x12,96) /* return device size */ |
197 | #endif | 197 | #endif |
198 | 198 | ||
199 | |||
200 | static long valid_offset(int fd, int offset) | ||
201 | { | ||
202 | char ch; | ||
203 | |||
204 | if (lseek(fd, offset, SEEK_SET) < 0) | ||
205 | return 0; | ||
206 | if (read(fd, &ch, 1) < 1) | ||
207 | return 0; | ||
208 | return 1; | ||
209 | } | ||
210 | |||
211 | static int count_blocks(int fd) | ||
212 | { | ||
213 | int high, low; | ||
214 | |||
215 | low = 0; | ||
216 | for (high = 1; valid_offset(fd, high); high *= 2) | ||
217 | low = high; | ||
218 | |||
219 | while (low < high - 1) { | ||
220 | const int mid = (low + high) / 2; | ||
221 | |||
222 | if (valid_offset(fd, mid)) | ||
223 | low = mid; | ||
224 | else | ||
225 | high = mid; | ||
226 | } | ||
227 | valid_offset(fd, 0); | ||
228 | return (low + 1); | ||
229 | } | ||
230 | |||
231 | static int get_size(const char *file) | ||
232 | { | ||
233 | int fd; | ||
234 | long size; | ||
235 | |||
236 | fd = xopen(file, O_RDWR); | ||
237 | if (ioctl(fd, BLKGETSIZE, &size) >= 0) { | ||
238 | close(fd); | ||
239 | return (size * 512); | ||
240 | } | ||
241 | |||
242 | size = count_blocks(fd); | ||
243 | close(fd); | ||
244 | return size; | ||
245 | } | ||
246 | |||
247 | static void write_tables(void) | 199 | static void write_tables(void) |
248 | { | 200 | { |
249 | /* Mark the superblock valid. */ | 201 | /* Mark the superblock valid. */ |
@@ -636,7 +588,6 @@ int mkfs_minix_main(int argc UNUSED_PARAM, char **argv) | |||
636 | { | 588 | { |
637 | unsigned opt; | 589 | unsigned opt; |
638 | char *tmp; | 590 | char *tmp; |
639 | struct stat statbuf; | ||
640 | char *str_i; | 591 | char *str_i; |
641 | char *listfile = NULL; | 592 | char *listfile = NULL; |
642 | 593 | ||
@@ -673,13 +624,17 @@ int mkfs_minix_main(int argc UNUSED_PARAM, char **argv) | |||
673 | #endif | 624 | #endif |
674 | } | 625 | } |
675 | 626 | ||
676 | G.device_name = *argv++; | 627 | G.device_name = argv[0]; |
677 | if (!G.device_name) | 628 | if (!G.device_name) |
678 | bb_show_usage(); | 629 | bb_show_usage(); |
679 | if (*argv) | 630 | |
680 | G.total_blocks = xatou32(*argv); | 631 | /* Check if it is mounted */ |
681 | else | 632 | if (find_mount_point(G.device_name, 0)) |
682 | G.total_blocks = get_size(G.device_name) / 1024; | 633 | bb_error_msg_and_die("can't format mounted filesystem"); |
634 | |||
635 | xmove_fd(xopen(G.device_name, O_RDWR), dev_fd); | ||
636 | |||
637 | G.total_blocks = get_volume_size_in_bytes(dev_fd, argv[1], 1024, /*extend:*/ 1) / 1024; | ||
683 | 638 | ||
684 | if (G.total_blocks < 10) | 639 | if (G.total_blocks < 10) |
685 | bb_error_msg_and_die("must have at least 10 blocks"); | 640 | bb_error_msg_and_die("must have at least 10 blocks"); |
@@ -690,25 +645,21 @@ int mkfs_minix_main(int argc UNUSED_PARAM, char **argv) | |||
690 | G.magic = MINIX2_SUPER_MAGIC; | 645 | G.magic = MINIX2_SUPER_MAGIC; |
691 | } else if (G.total_blocks > 65535) | 646 | } else if (G.total_blocks > 65535) |
692 | G.total_blocks = 65535; | 647 | G.total_blocks = 65535; |
693 | 648 | #if 0 | |
694 | /* Check if it is mounted */ | 649 | struct stat statbuf; |
695 | if (find_mount_point(G.device_name, 0)) | ||
696 | bb_error_msg_and_die("can't format mounted filesystem"); | ||
697 | |||
698 | xmove_fd(xopen(G.device_name, O_RDWR), dev_fd); | ||
699 | xfstat(dev_fd, &statbuf, G.device_name); | 650 | xfstat(dev_fd, &statbuf, G.device_name); |
651 | /* why? */ | ||
700 | if (!S_ISBLK(statbuf.st_mode)) | 652 | if (!S_ISBLK(statbuf.st_mode)) |
701 | opt &= ~1; // clear -c (check) | 653 | opt &= ~1; // clear -c (check) |
702 | 654 | #if 0 | |
703 | /* I don't know why someone has special code to prevent mkfs.minix | 655 | /* I don't know why someone has special code to prevent mkfs.minix |
704 | * on IDE devices. Why IDE but not SCSI, etc?... */ | 656 | * on IDE devices. Why IDE but not SCSI, etc?... */ |
705 | #if 0 | ||
706 | else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340) | 657 | else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340) |
707 | /* what is this? */ | 658 | /* what is this? */ |
708 | bb_error_msg_and_die("will not try " | 659 | bb_error_msg_and_die("will not try " |
709 | "to make filesystem on '%s'", G.device_name); | 660 | "to make filesystem on '%s'", G.device_name); |
710 | #endif | 661 | #endif |
711 | 662 | #endif | |
712 | tmp = G.root_block; | 663 | tmp = G.root_block; |
713 | *(short *) tmp = 1; | 664 | *(short *) tmp = 1; |
714 | strcpy(tmp + 2, "."); | 665 | strcpy(tmp + 2, "."); |